Unverified Commit 39b0f0dd authored by Fabian Eichinger's avatar Fabian Eichinger Committed by GitHub
Browse files

Add support for combining NX and GET flags on SET command (#8906)

Till now GET and NX were mutually exclusive.
This change make their combination mean a "Get or Set" command.

If the key exists it returns the old value and avoids setting,
and if it does't exist it returns nil and sets it to the new value (possibly with expiry time)
parent eaa7a7bb
...@@ -81,17 +81,19 @@ void setGenericCommand(client *c, int flags, robj *key, robj *val, robj *expire, ...@@ -81,17 +81,19 @@ void setGenericCommand(client *c, int flags, robj *key, robj *val, robj *expire,
return; return;
} }
if (flags & OBJ_SET_GET) {
if (getGenericCommand(c) == C_ERR) return;
}
if ((flags & OBJ_SET_NX && lookupKeyWrite(c->db,key) != NULL) || if ((flags & OBJ_SET_NX && lookupKeyWrite(c->db,key) != NULL) ||
(flags & OBJ_SET_XX && lookupKeyWrite(c->db,key) == NULL)) (flags & OBJ_SET_XX && lookupKeyWrite(c->db,key) == NULL))
{ {
addReply(c, abort_reply ? abort_reply : shared.null[c->resp]); if (!(flags & OBJ_SET_GET)) {
addReply(c, abort_reply ? abort_reply : shared.null[c->resp]);
}
return; return;
} }
if (flags & OBJ_SET_GET) {
if (getGenericCommand(c) == C_ERR) return;
}
genericSetKey(c,c->db,key, val,flags & OBJ_KEEPTTL,1); genericSetKey(c,c->db,key, val,flags & OBJ_KEEPTTL,1);
server.dirty++; server.dirty++;
notifyKeyspaceEvent(NOTIFY_STRING,"set",key,c->db->id); notifyKeyspaceEvent(NOTIFY_STRING,"set",key,c->db->id);
...@@ -196,7 +198,7 @@ int parseExtendedStringArgumentsOrReply(client *c, int *flags, int *unit, robj * ...@@ -196,7 +198,7 @@ int parseExtendedStringArgumentsOrReply(client *c, int *flags, int *unit, robj *
if ((opt[0] == 'n' || opt[0] == 'N') && if ((opt[0] == 'n' || opt[0] == 'N') &&
(opt[1] == 'x' || opt[1] == 'X') && opt[2] == '\0' && (opt[1] == 'x' || opt[1] == 'X') && opt[2] == '\0' &&
!(*flags & OBJ_SET_XX) && !(*flags & OBJ_SET_GET) && (command_type == COMMAND_SET)) !(*flags & OBJ_SET_XX) && (command_type == COMMAND_SET))
{ {
*flags |= OBJ_SET_NX; *flags |= OBJ_SET_NX;
} else if ((opt[0] == 'x' || opt[0] == 'X') && } else if ((opt[0] == 'x' || opt[0] == 'X') &&
...@@ -207,7 +209,7 @@ int parseExtendedStringArgumentsOrReply(client *c, int *flags, int *unit, robj * ...@@ -207,7 +209,7 @@ int parseExtendedStringArgumentsOrReply(client *c, int *flags, int *unit, robj *
} else if ((opt[0] == 'g' || opt[0] == 'G') && } else if ((opt[0] == 'g' || opt[0] == 'G') &&
(opt[1] == 'e' || opt[1] == 'E') && (opt[1] == 'e' || opt[1] == 'E') &&
(opt[2] == 't' || opt[2] == 'T') && opt[3] == '\0' && (opt[2] == 't' || opt[2] == 'T') && opt[3] == '\0' &&
!(*flags & OBJ_SET_NX) && (command_type == COMMAND_SET)) (command_type == COMMAND_SET))
{ {
*flags |= OBJ_SET_GET; *flags |= OBJ_SET_GET;
} else if (!strcasecmp(opt, "KEEPTTL") && !(*flags & OBJ_PERSIST) && } else if (!strcasecmp(opt, "KEEPTTL") && !(*flags & OBJ_PERSIST) &&
......
...@@ -494,11 +494,35 @@ start_server {tags {"string"}} { ...@@ -494,11 +494,35 @@ start_server {tags {"string"}} {
list $old_value $new_value list $old_value $new_value
} {{} bar} } {{} bar}
test {Extended SET GET with NX option should result in syntax err} { test {Extended SET GET option with XX} {
catch {r set foo bar NX GET} err1 r del foo
catch {r set foo bar NX GET} err2 r set foo bar
list $err1 $err2 set old_value [r set foo baz GET XX]
} {*syntax err* *syntax err*} set new_value [r get foo]
list $old_value $new_value
} {bar baz}
test {Extended SET GET option with XX and no previous value} {
r del foo
set old_value [r set foo bar GET XX]
set new_value [r get foo]
list $old_value $new_value
} {{} {}}
test {Extended SET GET option with NX} {
r del foo
set old_value [r set foo bar GET NX]
set new_value [r get foo]
list $old_value $new_value
} {{} bar}
test {Extended SET GET option with NX and previous value} {
r del foo
r set foo bar
set old_value [r set foo baz GET NX]
set new_value [r get foo]
list $old_value $new_value
} {bar bar}
test {Extended SET GET with incorrect type should result in wrong type error} { test {Extended SET GET with incorrect type should result in wrong type error} {
r del foo r del foo
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment