feat(bit): add BYTE/BIT option support for BITPOS command#3460
feat(bit): add BYTE/BIT option support for BITPOS command#3460gongna-au wants to merge 2 commits intoapache:unstablefrom
Conversation
|
Hi @gongna-au. Glad to see your PR. If your code was generated with AI assistance, please refer to the guidelines: https://kvrocks.apache.org/community/contributing#guidelines-for-ai-assisted-contributions. This will help us conduct a more focused and effective review. I used GPT-5.4 to review your PR, and it identified some issues. Below are the test cases that would fail. t.Run("BITPOS rejects BIT unit without end offset", func(t *testing.T) {
require.NoError(t, rdb.Set(ctx, "mykey", "\x80", 0).Err())
err := rdb.Do(ctx, "BITPOS", "mykey", 1, 0, "BIT").Err()
require.ErrorContains(t, err, "value is not an integer or out of range")
})
t.Run("BITPOS rejects BYTE unit without end offset", func(t *testing.T) {
require.NoError(t, rdb.Set(ctx, "mykey", "\x80", 0).Err())
err := rdb.Do(ctx, "BITPOS", "mykey", 1, 0, "BYTE").Err()
require.ErrorContains(t, err, "value is not an integer or out of range")
})
t.Run("BITPOS rejects non-integer bit argument with integer error", func(t *testing.T) {
require.NoError(t, rdb.Set(ctx, "mykey", "\x80", 0).Err())
err := rdb.Do(ctx, "BITPOS", "mykey", "x").Err()
require.ErrorContains(t, err, "value is not an integer or out of range")
})
t.Run("BITPOS rejects non-integer bit argument even with BIT unit form", func(t *testing.T) {
require.NoError(t, rdb.Set(ctx, "mykey", "\x80", 0).Err())
err := rdb.Do(ctx, "BITPOS", "mykey", "x", 0, 0, "BIT").Err()
require.ErrorContains(t, err, "value is not an integer or out of range")
})If you’re also using AI tools to assist with coding, you can have them review your code once before submitting the PR. |
1c9b12f to
5524331
Compare
jihuayu
left a comment
There was a problem hiding this comment.
LGTM. Thank you!
It would be great if you could chat with the reviewers a bit more.
b0e4998 to
cf463aa
Compare
|
@jihuayu Thank you! I've added extensive tests covering the BYTE/BIT option:
Happy to discuss any design concerns |
|
@jihuayu thank you for the reminder! AI usage disclosure: I used AI tools to assist with the following parts of this PR:
The core implementation in cmd_bit.cc (the Parse logic for BYTE/BIT option handling and strict syntax validation) was written with my understanding of the Redis 7.0 BITPOS specification. I can explain the design decisions:
Happy to answer any specific questions about the implementation or test coverage! |
jihuayu
left a comment
There was a problem hiding this comment.
Well done. Thank you for the explanation.
Add explicit BYTE/BIT index option to BITPOS with strict syntax validation matching Redis 7.0 behavior. Reject invalid option values and extra arguments. Add Go integration tests for BYTE option, BIT vs BYTE comparison, case-insensitivity and error cases. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
121b46a to
35e5084
Compare
|



Summary
This PR adds support for the
BYTE/BITunit option to theBITPOScommand, aligning it with the Redis 7.0 specification.The previous implementation only checked for
BITat a fixed argument position (args[5]) and ignoredBYTEentirely. This PR refactors the parser to correctly handle the full Redis 7.0 syntax:The
BYTE|BITunit is strictly nested: it can only appear after bothstartandendare provided, matching Redis behavior exactly.Changes
1. Command Parser Refactor (
src/commands/cmd_bit.cc)CommandBitPos::Parseto cleanly separate argument parsing by count.args[4](the 5th argument) is always parsed as theendinteger — never as a unit keyword. This matches Redis, which rejectsBITPOS key 1 0 BITwith a "not an integer" error.args[5](the 6th argument) is checked forBIT/BYTEkeyword, witherrInvalidSyntaxon anything else.BYTErecognition (previously onlyBITwas partially handled).bitargument validation to the top for clarity.ParseInt+ manual error check withGET_OR_RETmacro for consistency.2. Storage Layer — No Changes Needed
CHECK(stop_given)assertion inBitmap::BitPosis preserved as a defensive guard. Since the parser guaranteesstop_given=truewheneveris_bit_index=true(unit keyword requiresendto be present), this assertion is correct and protects against future regressions.Compatibility
BITPOS key bitBITPOS key bit startBITPOS key bit start endBITPOS key bit start end BYTEBITPOS key bit start end BITBITPOS key bit start BITVerification
BITPOS key bit [start [end [BYTE | BIT]]].is_bit_indexis only set whenargs.size() == 6, guaranteeingstop_given_ == true, so theCHECK(stop_given)assertion in the storage layer is always satisfied.BITCOUNTalready has correctBYTE/BITsupport and is not affected by this PR.