diff --git a/commands.json b/commands.json index ff2cdfb859..bd86fa6841 100644 --- a/commands.json +++ b/commands.json @@ -582,7 +582,8 @@ }, "RW": true, "access": true, - "update": true + "update": true, + "variable_flags": true } ], "arguments": [ @@ -2854,6 +2855,21 @@ "stale" ] }, + "COMMAND GETKEYSANDFLAGS": { + "summary": "Extract keys given a full Redis command", + "since": "7.0.0", + "group": "server", + "complexity": "O(N) where N is the number of arguments to the command", + "acl_categories": [ + "@slow", + "@connection" + ], + "arity": -4, + "command_flags": [ + "loading", + "stale" + ] + }, "COMMAND HELP": { "summary": "Show helpful text about the different subcommands", "since": "5.0.0", @@ -4244,7 +4260,7 @@ "arity": 3, "arguments": [ { - "name": "function-name", + "name": "library-name", "type": "string" } ], @@ -11111,7 +11127,8 @@ }, "RW": true, "access": true, - "update": true + "update": true, + "variable_flags": true } ], "arguments": [ diff --git a/commands/command-getkeys.md b/commands/command-getkeys.md index d734271553..6b8f300253 100644 --- a/commands/command-getkeys.md +++ b/commands/command-getkeys.md @@ -3,10 +3,9 @@ Returns @array-reply of keys from a full Redis command. `COMMAND GETKEYS` is a helper command to let you find the keys from a full Redis command. -`COMMAND` shows some commands as having movablekeys meaning -the entire command must be parsed to discover storage or retrieval -keys. You can use `COMMAND GETKEYS` to discover key positions -directly from how Redis parses the commands. +`COMMAND` provides information on how to find the key names of each command (see `firstkey`, [key specifications](/topics/key-specs#logical-operation-flags), and `movablekeys`), +but in some cases it's not possible to find keys of certain commands and then the entire command must be parsed to discover some / all key names. +You can use `COMMAND GETKEYS` or `COMMAND GETKEYSANDFLAGS` to discover key names directly from how Redis parses the commands. @return diff --git a/commands/command-getkeysandflags.md b/commands/command-getkeysandflags.md new file mode 100644 index 0000000000..5e452a8486 --- /dev/null +++ b/commands/command-getkeysandflags.md @@ -0,0 +1,22 @@ +Returns @array-reply of keys from a full Redis command and their usage flags. + +`COMMAND GETKEYSANDFLAGS` is a helper command to let you find the keys from a full Redis command together with flags indicating what each key is used for. + +`COMMAND` provides information on how to find the key names of each command (see `firstkey`, [key specifications](/topics/key-specs#logical-operation-flags), and `movablekeys`), +but in some cases it's not possible to find keys of certain commands and then the entire command must be parsed to discover some / all key names. +You can use `COMMAND GETKEYS` or `COMMAND GETKEYSANDFLAGS` to discover key names directly from how Redis parses the commands. + +Refer to [key specifications](/topics/key-specs#logical-operation-flags) for information about the meaning of the key flags. + +@return + +@array-reply: list of keys from your command. +Each element of the array is an array containing key name in the first entry, and flags in the second. + +@examples + +```cli +COMMAND GETKEYS MSET a b c d e f +COMMAND GETKEYS EVAL "not consulted" 3 key1 key2 key3 arg1 arg2 arg3 argN +COMMAND GETKEYSANDFLAGS LMOST mylist1 mylist2 left left +``` diff --git a/topics/key-specs.md b/topics/key-specs.md index e408906223..adba3efba9 100644 --- a/topics/key-specs.md +++ b/topics/key-specs.md @@ -156,7 +156,8 @@ Key specifications may have the following flags: * **channel:** this flag indicates that the specification isn't about keys at all. Instead, the specification relates to the name of a sharded Pub/Sub channel. Please refer to the `SPUBLISH` command for further details about sharded Pub/Sub. -* **incomplete:** this flag is explained in the following section. +* **incomplete:** this flag is explained below. +* **variable_flags:** this flag is explained below. ### incomplete @@ -180,6 +181,13 @@ The difficulty arises, for example, because the string _"STORE"_ is both a keywo the only commands with _incomplete_ key specifications are `SORT` and `MIGRATE`. We don't expect the addition of such commands in the future. +### variable_flags + +In some commands, the flags for the same key name argument can depend on other arguments. +For example, consider the `SET` command and its optional _GET_ argument. +Without the _GET_ argument, `SET` is write-only, but it becomes a read and write command with it. +When this flag is present, it means that the key specification flags cover all possible options, but the effective flags depend on other arguments. + ## Examples ### `SET`'s key specifications diff --git a/topics/modules-api-ref.md b/topics/modules-api-ref.md index 3d49506570..5c9d45dead 100644 --- a/topics/modules-api-ref.md +++ b/topics/modules-api-ref.md @@ -152,28 +152,42 @@ Return non-zero if a module command, that was declared with the flag "getkeys-api", is called in a special way to get the keys positions and not to get executed. Otherwise zero is returned. - + -### `RedisModule_KeyAtPos` +### `RedisModule_KeyAtPosWithFlags` - void RedisModule_KeyAtPos(RedisModuleCtx *ctx, int pos); - -**Available since:** 4.0.0 + void RedisModule_KeyAtPosWithFlags(RedisModuleCtx *ctx, int pos, int flags); When a module command is called in order to obtain the position of keys, since it was flagged as "getkeys-api" during the registration, the command implementation checks for this special call using the [`RedisModule_IsKeysPositionRequest()`](#RedisModule_IsKeysPositionRequest) API and uses this function in -order to report keys, like in the following example: +order to report keys. + +The supported flags are the ones used by [`RedisModule_SetCommandInfo`](#RedisModule_SetCommandInfo), see `REDISMODULE_CMD_KEY_`*. + + +The following is an example of how it could be used: if (RedisModule_IsKeysPositionRequest(ctx)) { - RedisModule_KeyAtPos(ctx,1); - RedisModule_KeyAtPos(ctx,2); + RedisModule_KeyAtPosWithFlags(ctx, 2, REDISMODULE_CMD_KEY_RO | REDISMODULE_CMD_KEY_ACCESS); + RedisModule_KeyAtPosWithFlags(ctx, 1, REDISMODULE_CMD_KEY_RW | REDISMODULE_CMD_KEY_UPDATE | REDISMODULE_CMD_KEY_ACCESS); } - Note: in the example below the get keys API would not be needed since - keys are at fixed positions. This interface is only used for commands - with a more complex structure. + Note: in the example above the get keys API could have been handled by key-specs (preferred). + Implementing the getkeys-api is required only when is it not possible to declare key-specs that cover all keys. + + + +### `RedisModule_KeyAtPos` + + void RedisModule_KeyAtPos(RedisModuleCtx *ctx, int pos); + +**Available since:** 4.0.0 + +This API existed before [`RedisModule_KeyAtPosWithFlags`](#RedisModule_KeyAtPosWithFlags) was added, now deprecated and +can be used for compatibility with older versions, before key-specs and flags +were introduced. @@ -408,8 +422,9 @@ All fields except `version` are optional. Explanation of the fields: versions where RM_SetCommandInfo is not available. Note that key-specs don't fully replace the "getkeys-api" (see - RM_CreateCommand, RM_IsKeysPositionRequest and RM_KeyAtPos) so it may be - a good idea to supply both key-specs and a implement the getkeys-api. + RM_CreateCommand, RM_IsKeysPositionRequest and RM_KeyAtPosWithFlags) so + it may be a good idea to supply both key-specs and implement the + getkeys-api. A key-spec has the following structure: @@ -6472,21 +6487,24 @@ such as: If `old_value` is non-NULL, the old value is returned by reference. - - -### `RedisModule_GetCommandKeys` + - int *RedisModule_GetCommandKeys(RedisModuleCtx *ctx, - RedisModuleString **argv, - int argc, - int *num_keys); +### `RedisModule_GetCommandKeysWithFlags` -**Available since:** 6.0.9 + int *RedisModule_GetCommandKeysWithFlags(RedisModuleCtx *ctx, + RedisModuleString **argv, + int argc, + int *num_keys, + int **out_flags); For a specified command, parse its arguments and return an array that contains the indexes of all key name arguments. This function is essentially a more efficient way to do `COMMAND GETKEYS`. +The `out_flags` argument is optional, and can be set to NULL. +When provided it is filled with `REDISMODULE_CMD_KEY_` flags in matching +indexes with the key indexes of the returned array. + A NULL return value indicates the specified command has no keys, or an error condition. Error conditions are indicated by setting errno as follows: @@ -6496,7 +6514,21 @@ as follows: NOTE: The returned array is not a Redis Module object so it does not get automatically freed even when auto-memory is used. The caller -must explicitly call [`RedisModule_Free()`](#RedisModule_Free) to free it. +must explicitly call [`RedisModule_Free()`](#RedisModule_Free) to free it, same as the `out_flags` pointer if +used. + + + +### `RedisModule_GetCommandKeys` + + int *RedisModule_GetCommandKeys(RedisModuleCtx *ctx, + RedisModuleString **argv, + int argc, + int *num_keys); + +**Available since:** 6.0.9 + +Identinal to [`RedisModule_GetCommandKeysWithFlags`](#RedisModule_GetCommandKeysWithFlags) when flags are not needed. @@ -6762,6 +6794,7 @@ There is no guarantee that this info is always available, so this may return -1. * [`RedisModule_GetClusterSize`](#RedisModule_GetClusterSize) * [`RedisModule_GetCommand`](#RedisModule_GetCommand) * [`RedisModule_GetCommandKeys`](#RedisModule_GetCommandKeys) +* [`RedisModule_GetCommandKeysWithFlags`](#RedisModule_GetCommandKeysWithFlags) * [`RedisModule_GetContextFlags`](#RedisModule_GetContextFlags) * [`RedisModule_GetContextFlagsAll`](#RedisModule_GetContextFlagsAll) * [`RedisModule_GetCurrentCommandName`](#RedisModule_GetCurrentCommandName) @@ -6814,6 +6847,7 @@ There is no guarantee that this info is always available, so this may return -1. * [`RedisModule_IsModuleNameBusy`](#RedisModule_IsModuleNameBusy) * [`RedisModule_IsSubEventSupported`](#RedisModule_IsSubEventSupported) * [`RedisModule_KeyAtPos`](#RedisModule_KeyAtPos) +* [`RedisModule_KeyAtPosWithFlags`](#RedisModule_KeyAtPosWithFlags) * [`RedisModule_KeyExists`](#RedisModule_KeyExists) * [`RedisModule_KeyType`](#RedisModule_KeyType) * [`RedisModule_KillForkChild`](#RedisModule_KillForkChild)