diff --git a/src/module.c b/src/module.c index 53ba70f77c..7fe5a39a50 100644 --- a/src/module.c +++ b/src/module.c @@ -803,6 +803,7 @@ int64_t commandFlagsFromString(char *s) { else if (!strcasecmp(t,"may-replicate")) flags |= CMD_MAY_REPLICATE; else if (!strcasecmp(t,"getkeys-api")) flags |= CMD_MODULE_GETKEYS; else if (!strcasecmp(t,"no-cluster")) flags |= CMD_MODULE_NO_CLUSTER; + else if (!strcasecmp(t,"no-mandatory-keys")) flags |= CMD_NO_MANDATORY_KEYS; else break; } sdsfreesplitres(tokens,count); @@ -891,6 +892,7 @@ RedisModuleCommandProxy *moduleCreateCommandProxy(RedisModuleCtx *ctx, const cha * to authenticate a client. * * **"may-replicate"**: This command may generate replication traffic, even * though it's not a write command. + * * **"no-mandatory-keys"**: All the keys this command may take are optional * * The last three parameters specify which arguments of the new command are * Redis keys. See https://redis.io/commands/command for more information. diff --git a/src/server.c b/src/server.c index fc6606b691..9740475ca6 100644 --- a/src/server.c +++ b/src/server.c @@ -175,6 +175,8 @@ struct redisServer server; /* Server global state */ * * sentinel-only: This command is present only when in sentinel mode. * + * no-mandatory-keys: This key arguments for this command are optional. + * * The following additional flags are only used in order to put commands * in a specific ACL category. Commands can have multiple ACL categories. * See redis.conf for the exact meaning of each. @@ -1751,28 +1753,28 @@ struct redisCommand redisCommandTable[] = { * as opposed to after. */ {"eval",evalCommand,-3, - "no-script no-monitor may-replicate @scripting", + "no-script no-monitor may-replicate no-mandatory-keys @scripting", {{"read write", /* We pass both read and write because these flag are worst-case-scenario */ KSPEC_BS_INDEX,.bs.index={2}, KSPEC_FK_KEYNUM,.fk.keynum={0,1,1}}}, evalGetKeys}, {"eval_ro",evalRoCommand,-3, - "no-script no-monitor @scripting", + "no-script no-monitor no-mandatory-keys @scripting", {{"read", KSPEC_BS_INDEX,.bs.index={2}, KSPEC_FK_KEYNUM,.fk.keynum={0,1,1}}}, evalGetKeys}, {"evalsha",evalShaCommand,-3, - "no-script no-monitor may-replicate @scripting", + "no-script no-monitor may-replicate no-mandatory-keys @scripting", {{"read write", /* We pass both read and write because these flag are worst-case-scenario */ KSPEC_BS_INDEX,.bs.index={2}, KSPEC_FK_KEYNUM,.fk.keynum={0,1,1}}}, evalGetKeys}, {"evalsha_ro",evalShaRoCommand,-3, - "no-script no-monitor @scripting", + "no-script no-monitor no-mandatory-keys @scripting", {{"read", KSPEC_BS_INDEX,.bs.index={2}, KSPEC_FK_KEYNUM,.fk.keynum={0,1,1}}}, @@ -4510,6 +4512,8 @@ void parseCommandFlags(struct redisCommand *c, char *strflags) { } else if (!strcasecmp(flag,"only-sentinel")) { c->flags |= CMD_SENTINEL; /* Obviously it's s sentinel command */ c->flags |= CMD_ONLY_SENTINEL; + } else if (!strcasecmp(flag,"no-mandatory-keys")) { + c->flags |= CMD_NO_MANDATORY_KEYS; } else { /* Parse ACL categories here if the flag name starts with @. */ uint64_t catflag; @@ -5906,7 +5910,11 @@ void getKeysSubcommand(client *c) { } if (!getKeysFromCommand(cmd,c->argv+2,c->argc-2,&result)) { - addReplyError(c,"Invalid arguments specified for command"); + if (cmd->flags & CMD_NO_MANDATORY_KEYS) { + addReplyArrayLen(c,0); + } else { + addReplyError(c,"Invalid arguments specified for command"); + } } else { addReplyArrayLen(c,result.numkeys); for (j = 0; j < result.numkeys; j++) addReplyBulk(c,c->argv[result.keys[j]+2]); diff --git a/src/server.h b/src/server.h index 9eca982307..f5b00e8b99 100644 --- a/src/server.h +++ b/src/server.h @@ -236,6 +236,7 @@ extern int configOOMScoreAdjValuesDefaults[CONFIG_OOM_COUNT]; #define CMD_SENTINEL (1ULL<<40) /* "sentinel" flag */ #define CMD_ONLY_SENTINEL (1ULL<<41) /* "only-sentinel" flag */ +#define CMD_NO_MANDATORY_KEYS (1ULL<<42) /* "no-mandatory-keys" flag */ /* AOF states */ #define AOF_OFF 0 /* AOF is off */ diff --git a/tests/unit/introspection-2.tcl b/tests/unit/introspection-2.tcl index 478631c3f4..e09b2147b9 100644 --- a/tests/unit/introspection-2.tcl +++ b/tests/unit/introspection-2.tcl @@ -89,6 +89,14 @@ start_server {tags {"introspection"}} { assert_equal {key} [r command getkeys xgroup create key groupname $] } + test {COMMAND GETKEYS EVAL with keys} { + assert_equal {key} [r command getkeys eval "return 1" 1 key] + } + + test {COMMAND GETKEYS EVAL without keys} { + assert_equal {} [r command getkeys eval "return 1" 0] + } + test "COMMAND LIST FILTERBY ACLCAT" { set reply [r command list filterby aclcat hyperloglog] assert_equal [lsort $reply] {pfadd pfcount pfdebug pfmerge pfselftest}