diff --git a/redis.c b/redis.c index 5b4dcf5f87ef..fff590d22d6f 100644 --- a/redis.c +++ b/redis.c @@ -705,6 +705,7 @@ static void substrCommand(redisClient *c); static void zrankCommand(redisClient *c); static void zrevrankCommand(redisClient *c); static void hsetCommand(redisClient *c); +static void hsetnxCommand(redisClient *c); static void hgetCommand(redisClient *c); static void hmsetCommand(redisClient *c); static void hmgetCommand(redisClient *c); @@ -783,6 +784,7 @@ static struct redisCommand cmdTable[] = { {"zrank",zrankCommand,3,REDIS_CMD_BULK,NULL,1,1,1}, {"zrevrank",zrevrankCommand,3,REDIS_CMD_BULK,NULL,1,1,1}, {"hset",hsetCommand,4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1}, + {"hsetnx",hsetnxCommand,4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1}, {"hget",hgetCommand,3,REDIS_CMD_BULK,NULL,1,1,1}, {"hmset",hmsetCommand,-4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1}, {"hmget",hmgetCommand,-3,REDIS_CMD_BULK,NULL,1,1,1}, @@ -6247,6 +6249,20 @@ static void hsetCommand(redisClient *c) { server.dirty++; } +static void hsetnxCommand(redisClient *c) { + robj *o; + if ((o = hashLookupWriteOrCreate(c,c->argv[1])) == NULL) return; + hashTryConversion(o,c->argv,2,3); + + if (hashExists(o, c->argv[2])) { + addReply(c, shared.czero); + } else { + hashReplace(o,c->argv[2],c->argv[3]); + addReply(c, shared.cone); + server.dirty++; + } +} + static void hmsetCommand(redisClient *c) { int i; robj *o; diff --git a/redis.tcl b/redis.tcl index b4a8ae22e870..c76166ef0df0 100644 --- a/redis.tcl +++ b/redis.tcl @@ -46,7 +46,7 @@ foreach redis_bulk_cmd { # Flag commands requiring last argument as a bulk write operation foreach redis_multibulk_cmd { - mset msetnx hset hmset hmget + mset msetnx hset hsetnx hmset hmget } { set ::redis::multibulkarg($redis_multibulk_cmd) {} } diff --git a/test-redis.tcl b/test-redis.tcl index 8ba1ff85838e..800a93eac218 100644 --- a/test-redis.tcl +++ b/test-redis.tcl @@ -1652,6 +1652,30 @@ proc main {} { set _ $rv } {0 newval1 1 0 newval2 1 1 1} + test {HSETNX target key missing - small hash} { + $r hsetnx smallhash __123123123__ foo + $r hget smallhash __123123123__ + } {foo} + + test {HSETNX target key exists - small hash} { + $r hsetnx smallhash __123123123__ bar + set result [$r hget smallhash __123123123__] + $r hdel smallhash __123123123__ + set _ $result + } {foo} + + test {HSETNX target key missing - big hash} { + $r hsetnx bighash __123123123__ foo + $r hget bighash __123123123__ + } {foo} + + test {HSETNX target key exists - big hash} { + $r hsetnx bighash __123123123__ bar + set result [$r hget bighash __123123123__] + $r hdel bighash __123123123__ + set _ $result + } {foo} + test {HMSET wrong number of args} { catch {$r hmset smallhash key1 val1 key2} err format $err