This is an automated email from the ASF dual-hosted git repository.

twice pushed a commit to branch unstable
in repository https://gitbox.apache.org/repos/asf/kvrocks.git


The following commit(s) were added to refs/heads/unstable by this push:
     new 6747b8da fix(cmd): args should be parsed before retrieving keys in 
COMMAND GETKEYS (#2661)
6747b8da is described below

commit 6747b8da7a7280a39b4f85e498249dc51f6322d4
Author: Twice <[email protected]>
AuthorDate: Thu Nov 14 16:43:15 2024 +0800

    fix(cmd): args should be parsed before retrieving keys in COMMAND GETKEYS 
(#2661)
---
 src/cluster/cluster.cc                    |  8 +++++---
 src/commands/commander.cc                 |  5 +++++
 src/commands/commander.h                  |  2 ++
 src/storage/scripting.cc                  | 14 +++++++-------
 tests/gocase/unit/command/command_test.go | 16 ++++++++--------
 5 files changed, 27 insertions(+), 18 deletions(-)

diff --git a/src/cluster/cluster.cc b/src/cluster/cluster.cc
index 3850e12f..b04fb589 100644
--- a/src/cluster/cluster.cc
+++ b/src/cluster/cluster.cc
@@ -835,9 +835,11 @@ Status Cluster::CanExecByMySelf(const 
redis::CommandAttributes *attributes, cons
                                 redis::Connection *conn, lua::ScriptRunCtx 
*script_run_ctx) {
   std::vector<int> key_indexes;
 
-  auto s = redis::CommandTable::GetKeysFromCommand(attributes, cmd_tokens);
-  if (!s) return Status::OK();
-  key_indexes = *s;
+  attributes->ForEachKeyRange(
+      [&](const std::vector<std::string> &, redis::CommandKeyRange key_range) {
+        key_range.ForEachKeyIndex([&](int i) { key_indexes.push_back(i); }, 
cmd_tokens.size());
+      },
+      cmd_tokens);
 
   if (key_indexes.empty()) return Status::OK();
 
diff --git a/src/commands/commander.cc b/src/commands/commander.cc
index 063b1c46..da32800b 100644
--- a/src/commands/commander.cc
+++ b/src/commands/commander.cc
@@ -88,6 +88,11 @@ StatusOr<std::vector<int>> 
CommandTable::GetKeysFromCommand(const CommandAttribu
     return {Status::NotOK, "Invalid number of arguments specified for 
command"};
   }
 
+  auto cmd = attributes->factory();
+  if (auto s = cmd->Parse(cmd_tokens); !s) {
+    return {Status::NotOK, "Invalid syntax found in this command arguments: " 
+ s.Msg()};
+  }
+
   Status status;
   std::vector<int> key_indexes;
 
diff --git a/src/commands/commander.h b/src/commands/commander.h
index b1d0a049..ac3d3aa9 100644
--- a/src/commands/commander.h
+++ b/src/commands/commander.h
@@ -254,6 +254,8 @@ struct CommandAttributes {
     return {Status::NotOK, "key range is unavailable without command 
arguments"};
   }
 
+  // the command arguments must be parsed and in valid syntax
+  // before this method is called, otherwise the behavior is UNDEFINED
   template <typename F, typename G>
   void ForEachKeyRange(F &&f, const std::vector<std::string> &args, G &&g) 
const {
     if (key_range_.first_key > 0) {
diff --git a/src/storage/scripting.cc b/src/storage/scripting.cc
index 5768aee8..9676b439 100644
--- a/src/storage/scripting.cc
+++ b/src/storage/scripting.cc
@@ -778,6 +778,13 @@ int RedisGenericCommand(lua_State *lua, int raise_error) {
   auto *srv = conn->GetServer();
   Config *config = srv->GetConfig();
 
+  cmd->SetArgs(args);
+  auto s = cmd->Parse();
+  if (!s) {
+    PushError(lua, s.Msg().data());
+    return raise_error ? RaiseError(lua) : 1;
+  }
+
   if (config->cluster_enabled) {
     if (script_run_ctx->flags & ScriptFlagType::kScriptNoCluster) {
       PushError(lua, "Can not run script on cluster, 'no-cluster' flag is 
set");
@@ -807,13 +814,6 @@ int RedisGenericCommand(lua_State *lua, int raise_error) {
     return raise_error ? RaiseError(lua) : 1;
   }
 
-  cmd->SetArgs(args);
-  auto s = cmd->Parse();
-  if (!s) {
-    PushError(lua, s.Msg().data());
-    return raise_error ? RaiseError(lua) : 1;
-  }
-
   std::string output;
   // TODO: make it possible for multiple redis commands in lua script to use 
the same txn context.
   {
diff --git a/tests/gocase/unit/command/command_test.go 
b/tests/gocase/unit/command/command_test.go
index 18fb2d3d..d6f233fa 100644
--- a/tests/gocase/unit/command/command_test.go
+++ b/tests/gocase/unit/command/command_test.go
@@ -180,7 +180,7 @@ func TestCommand(t *testing.T) {
        })
 
        t.Run("COMMAND GETKEYS ZMPOP", func(t *testing.T) {
-               r := rdb.Do(ctx, "COMMAND", "GETKEYS", "ZMPOP", "2", "key1", 
"key2")
+               r := rdb.Do(ctx, "COMMAND", "GETKEYS", "ZMPOP", "2", "key1", 
"key2", "min")
                vs, err := r.Slice()
                require.NoError(t, err)
                require.Len(t, vs, 2)
@@ -189,7 +189,7 @@ func TestCommand(t *testing.T) {
        })
 
        t.Run("COMMAND GETKEYS BZMPOP", func(t *testing.T) {
-               r := rdb.Do(ctx, "COMMAND", "GETKEYS", "BZMPOP", "0", "2", 
"key1", "key2")
+               r := rdb.Do(ctx, "COMMAND", "GETKEYS", "BZMPOP", "0", "2", 
"key1", "key2", "min")
                vs, err := r.Slice()
                require.NoError(t, err)
                require.Len(t, vs, 2)
@@ -198,7 +198,7 @@ func TestCommand(t *testing.T) {
        })
 
        t.Run("COMMAND GETKEYS LMPOP", func(t *testing.T) {
-               r := rdb.Do(ctx, "COMMAND", "GETKEYS", "LMPOP", "2", "key1", 
"key2")
+               r := rdb.Do(ctx, "COMMAND", "GETKEYS", "LMPOP", "2", "key1", 
"key2", "left")
                vs, err := r.Slice()
                require.NoError(t, err)
                require.Len(t, vs, 2)
@@ -207,7 +207,7 @@ func TestCommand(t *testing.T) {
        })
 
        t.Run("COMMAND GETKEYS BLMPOP", func(t *testing.T) {
-               r := rdb.Do(ctx, "COMMAND", "GETKEYS", "BLMPOP", "0", "2", 
"key1", "key2")
+               r := rdb.Do(ctx, "COMMAND", "GETKEYS", "BLMPOP", "0", "2", 
"key1", "key2", "left")
                vs, err := r.Slice()
                require.NoError(t, err)
                require.Len(t, vs, 2)
@@ -250,14 +250,14 @@ func TestCommand(t *testing.T) {
 
        t.Run("COMMAND GETKEYS GEORADIUSBYMEMBER", func(t *testing.T) {
                // non-store
-               r := rdb.Do(ctx, "COMMAND", "GETKEYS", "GEORADIUSBYMEMBER", 
"src", "member", "radius", "m")
+               r := rdb.Do(ctx, "COMMAND", "GETKEYS", "GEORADIUSBYMEMBER", 
"src", "member", "100", "m")
                vs, err := r.Slice()
                require.NoError(t, err)
                require.Len(t, vs, 1)
                require.Equal(t, "src", vs[0])
 
                // store
-               r = rdb.Do(ctx, "COMMAND", "GETKEYS", "GEORADIUSBYMEMBER", 
"src", "member", "radius", "m", "store", "dst")
+               r = rdb.Do(ctx, "COMMAND", "GETKEYS", "GEORADIUSBYMEMBER", 
"src", "member", "100", "m", "store", "dst")
                vs, err = r.Slice()
                require.NoError(t, err)
                require.Len(t, vs, 2)
@@ -265,7 +265,7 @@ func TestCommand(t *testing.T) {
                require.Equal(t, "dst", vs[1])
 
                // storedist
-               r = rdb.Do(ctx, "COMMAND", "GETKEYS", "GEORADIUSBYMEMBER", 
"src", "member", "radius", "m", "storedist", "dst")
+               r = rdb.Do(ctx, "COMMAND", "GETKEYS", "GEORADIUSBYMEMBER", 
"src", "member", "100", "m", "storedist", "dst")
                vs, err = r.Slice()
                require.NoError(t, err)
                require.Len(t, vs, 2)
@@ -273,7 +273,7 @@ func TestCommand(t *testing.T) {
                require.Equal(t, "dst", vs[1])
 
                // store + storedist
-               r = rdb.Do(ctx, "COMMAND", "GETKEYS", "GEORADIUSBYMEMBER", 
"src", "member", "radius", "m", "store", "dst1", "storedist", "dst2")
+               r = rdb.Do(ctx, "COMMAND", "GETKEYS", "GEORADIUSBYMEMBER", 
"src", "member", "100", "m", "store", "dst1", "storedist", "dst2")
                vs, err = r.Slice()
                require.NoError(t, err)
                require.Len(t, vs, 2)

Reply via email to