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 98c051cac fix(stream): allow group and consumer names starting with 
digits (#3442)
98c051cac is described below

commit 98c051cacb0f77192f8f086050bcb3f5eee2351f
Author: Songqing Zhang <[email protected]>
AuthorDate: Fri Apr 17 09:13:43 2026 +0800

    fix(stream): allow group and consumer names starting with digits (#3442)
    
    Redis does not restrict group or consumer names from starting with
    digits. The restriction was kvrocks-specific and broke compatibility.
---
 src/types/redis_stream.cc                    |  6 ------
 tests/gocase/unit/type/stream/stream_test.go | 27 ++++++++++++++++++++++++++-
 2 files changed, 26 insertions(+), 7 deletions(-)

diff --git a/src/types/redis_stream.cc b/src/types/redis_stream.cc
index 60606df08..6dc47fba2 100644
--- a/src/types/redis_stream.cc
+++ b/src/types/redis_stream.cc
@@ -685,9 +685,6 @@ rocksdb::Status Stream::AutoClaim(engine::Context &ctx, 
const Slice &stream_name
 }
 rocksdb::Status Stream::CreateGroup(engine::Context &ctx, const Slice 
&stream_name,
                                     const StreamXGroupCreateOptions &options, 
const std::string &group_name) {
-  if (std::isdigit(group_name[0])) {
-    return rocksdb::Status::InvalidArgument("group name cannot start with 
number");
-  }
   std::string ns_key = AppendNamespacePrefix(stream_name);
 
   StreamMetadata metadata;
@@ -797,9 +794,6 @@ rocksdb::Status Stream::DestroyGroup(engine::Context &ctx, 
const Slice &stream_n
 rocksdb::Status Stream::createConsumerWithoutLock(engine::Context &ctx, const 
Slice &stream_name,
                                                   const std::string 
&group_name, const std::string &consumer_name,
                                                   int *created_number) {
-  if (std::isdigit(consumer_name[0])) {
-    return rocksdb::Status::InvalidArgument("consumer name cannot start with 
number");
-  }
   std::string ns_key = AppendNamespacePrefix(stream_name);
   StreamMetadata metadata;
   rocksdb::Status s = GetMetadata(ctx, ns_key, &metadata);
diff --git a/tests/gocase/unit/type/stream/stream_test.go 
b/tests/gocase/unit/type/stream/stream_test.go
index df065ebf9..1590847af 100644
--- a/tests/gocase/unit/type/stream/stream_test.go
+++ b/tests/gocase/unit/type/stream/stream_test.go
@@ -962,7 +962,8 @@ func TestStreamOffset(t *testing.T) {
                require.Error(t, rdb.Do(ctx, "XGROUP", "CREAT", streamName, 
groupName, "$").Err())
                require.Error(t, rdb.Do(ctx, "XGROUP", "CREATE", streamName, 
groupName, "$", "ENTRIEREAD", "10").Err())
                require.Error(t, rdb.Do(ctx, "XGROUP", "CREATE", streamName, 
groupName, "$", "ENTRIESREAD", "-10").Err())
-               require.Error(t, rdb.Do(ctx, "XGROUP", "CREATE", streamName, 
"1test-group-c", "$").Err())
+               // Group names may start with a digit (RESP bulk string); same 
as Redis — not a syntax error.
+               require.NoError(t, rdb.Do(ctx, "XGROUP", "CREATE", streamName, 
"1test-group-c", "$").Err())
 
                require.NoError(t, rdb.Del(ctx, "myStream").Err())
                require.NoError(t, rdb.XAdd(ctx, &redis.XAddArgs{Stream: 
"myStream", Values: []string{"iTeM", "1", "vAluE", "a"}}).Err())
@@ -978,6 +979,30 @@ func TestStreamOffset(t *testing.T) {
                require.Equal(t, int64(0), result)
        })
 
+       t.Run("XGROUP CREATE and CREATECONSUMER with names starting with 
digits", func(t *testing.T) {
+               streamKey := "stream-digit-names"
+               require.NoError(t, rdb.Del(ctx, streamKey).Err())
+               require.NoError(t, rdb.XAdd(ctx, &redis.XAddArgs{Stream: 
streamKey, Values: []string{"f", "v"}}).Err())
+
+               // Group name starting with a digit should be allowed (matches 
Redis behavior)
+               require.NoError(t, rdb.XGroupCreateMkStream(ctx, streamKey, 
"1group", "0").Err())
+
+               // Consumer name starting with a digit should be allowed
+               result := rdb.Do(ctx, "XGROUP", "CREATECONSUMER", streamKey, 
"1group", "2consumer")
+               require.NoError(t, result.Err())
+
+               // Read with the digit-prefixed group and consumer
+               _, err := rdb.XReadGroup(ctx, &redis.XReadGroupArgs{
+                       Group:    "1group",
+                       Consumer: "2consumer",
+                       Streams:  []string{streamKey, ">"},
+                       Count:    10,
+               }).Result()
+               require.NoError(t, err)
+
+               require.NoError(t, rdb.Del(ctx, streamKey).Err())
+       })
+
        t.Run("XGROUP CREATECONSUMER with different kinds of commands", func(t 
*testing.T) {
                streamName := "test-stream"
                groupName := "test-group"

Reply via email to