diff --git a/src/redis.c b/src/redis.c index b13db8b8735..51791dd7f65 100644 --- a/src/redis.c +++ b/src/redis.c @@ -138,6 +138,7 @@ struct redisCommand readonlyCommandTable[] = { {"hsetnx",hsetnxCommand,4,REDIS_CMD_DENYOOM,NULL,1,1,1}, {"hget",hgetCommand,3,0,NULL,1,1,1}, {"hmset",hmsetCommand,-4,REDIS_CMD_DENYOOM,NULL,1,1,1}, + {"hmsetnx",hmsetnxCommand,-4,REDIS_CMD_DENYOOM,NULL,1,1,1}, {"hmget",hmgetCommand,-3,0,NULL,1,1,1}, {"hincrby",hincrbyCommand,4,REDIS_CMD_DENYOOM,NULL,1,1,1}, {"hdel",hdelCommand,-3,0,NULL,1,1,1}, diff --git a/src/redis.h b/src/redis.h index 86e78cac62b..2c264f40c4c 100644 --- a/src/redis.h +++ b/src/redis.h @@ -1050,6 +1050,7 @@ void hsetCommand(redisClient *c); void hsetnxCommand(redisClient *c); void hgetCommand(redisClient *c); void hmsetCommand(redisClient *c); +void hmsetnxCommand(redisClient *c); void hmgetCommand(redisClient *c); void hdelCommand(redisClient *c); void hlenCommand(redisClient *c); diff --git a/src/t_hash.c b/src/t_hash.c index 3feb9dac931..b16d6673216 100644 --- a/src/t_hash.c +++ b/src/t_hash.c @@ -319,6 +319,39 @@ void hmsetCommand(redisClient *c) { server.dirty++; } +void hmsetnxCommand(redisClient *c) { + int i, busykeys = 0; + robj *o; + + if ((c->argc % 2) == 1) { + addReplyError(c,"wrong number of arguments for HMSETNX"); + return; + } + + if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return; + hashTypeTryConversion(o,c->argv,2,c->argc-1); + + /* Handle the NX flag. The HMSETNX semantic is to return zero and don't + * set nothing at all if at least one already key exists. */ + for (i = 2; i < c->argc; i += 2) { + if (hashTypeExists(o, c->argv[i])) { + busykeys++; + } + if (busykeys) { + addReply(c, shared.czero); + return; + } + } + + for (i = 2; i < c->argc; i += 2) { + hashTypeTryObjectEncoding(o,&c->argv[i], &c->argv[i+1]); + hashTypeSet(o,c->argv[i],c->argv[i+1]); + } + addReply(c, shared.cone); + signalModifiedKey(c->db,c->argv[1]); + server.dirty++; +} + void hincrbyCommand(redisClient *c) { long long value, incr, oldvalue; robj *o, *current, *new;