Refine error message for HSETEX command with PERSIST (#14880)
Some checks failed
CI / test-ubuntu-latest (push) Has been cancelled
CI / test-sanitizer-address (push) Has been cancelled
CI / build-debian-old (push) Has been cancelled
CI / build-macos-latest (push) Has been cancelled
CI / build-32bit (push) Has been cancelled
CI / build-libc-malloc (push) Has been cancelled
CI / build-centos-jemalloc (push) Has been cancelled
CI / build-old-chain-jemalloc (push) Has been cancelled
Codecov / code-coverage (push) Has been cancelled
External Server Tests / test-external-standalone (push) Has been cancelled
External Server Tests / test-external-cluster (push) Has been cancelled
External Server Tests / test-external-nodebug (push) Has been cancelled
Spellcheck / Spellcheck (push) Has been cancelled

Fixes #14879 

> PERSIST can only be given for HGETEX and KEEPTTL for HSETEX but the
code doesn’t verify it.

**Behavior currently:**
 ```
127.0.0.1:5555> HSETEX h ex 100 persist fields 1 k v
(error) ERR Only one of EX, PX, EXAT, PXAT or KEEPTTL arguments can be
specified
```

**With this PR, behavior would be:**

```
127.0.0.1:5555> HSETEX h ex 100 persist fields 1 k v
(error) ERR unknown argument: persist
```
This commit is contained in:
Cong Chen 2026-03-20 10:19:00 +08:00 committed by GitHub
parent 7d5708180e
commit 9accf8bd24
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 14 additions and 11 deletions

View file

@ -2295,19 +2295,19 @@ static int parseHashFieldExpireArgs(client *c, int *flags,
return C_ERR;
*expire_time_pos = i;
} else if (!strcasecmp(c->argv[i]->ptr, "PERSIST")) {
} else if (command_type == HASH_CMD_HGETEX && !strcasecmp(c->argv[i]->ptr, "PERSIST")) {
if (*flags & (HFE_EX | HFE_EXAT | HFE_PX | HFE_PXAT | HFE_PERSIST))
goto err_expiration;
*flags |= HFE_PERSIST;
} else if (!strcasecmp(c->argv[i]->ptr, "KEEPTTL")) {
} else if (command_type == HASH_CMD_HSETEX && !strcasecmp(c->argv[i]->ptr, "KEEPTTL")) {
if (*flags & (HFE_EX | HFE_EXAT | HFE_PX | HFE_PXAT | HFE_KEEPTTL))
goto err_expiration;
*flags |= HFE_KEEPTTL;
} else if (!strcasecmp(c->argv[i]->ptr, "FXX")) {
} else if (command_type == HASH_CMD_HSETEX && !strcasecmp(c->argv[i]->ptr, "FXX")) {
if (*flags & (HFE_FXX | HFE_FNX))
goto err_condition;
*flags |= HFE_FXX;
} else if (!strcasecmp(c->argv[i]->ptr, "FNX")) {
} else if (command_type == HASH_CMD_HSETEX && !strcasecmp(c->argv[i]->ptr, "FNX")) {
if (*flags & (HFE_FXX | HFE_FNX))
goto err_condition;
*flags |= HFE_FNX;
@ -2323,13 +2323,6 @@ static int parseHashFieldExpireArgs(client *c, int *flags,
return C_ERR;
}
/* Validate command-specific argument compatibility */
if ((command_type == HASH_CMD_HGETEX && (*flags & (HFE_KEEPTTL | HFE_FXX | HFE_FNX))) ||
(command_type == HASH_CMD_HSETEX && (*flags & HFE_PERSIST))) {
addReplyError(c, "unknown argument");
return C_ERR;
}
return C_OK;
err_missing_expire:

View file

@ -962,10 +962,18 @@ start_server {tags {"external:skip needs:debug"}} {
assert_error "*wrong number of arguments*" {r HGETEX h1 FIELDS 1}
assert_error "*unknown argument*" {r HGETEX h1 XFIELDX 1 a}
assert_error "*unknown argument*" {r HGETEX h1 PXAT 1 1}
assert_error "*unknown argument*" {r HGETEX h1 KEEPTTL fields 1 a}
assert_error "*wrong number of arguments*" {r HGETEX h1 FIELDS 2 a}
assert_error "*invalid number of fields*" {r HGETEX h1 FIELDS 0 a}
assert_error "*invalid number of fields*" {r HGETEX h1 FIELDS -1 a}
assert_error "*invalid number of fields*" {r HGETEX h1 FIELDS 9223372036854775808 a}
# Only one of EX, PX, EXAT, PXAT or PERSIST can be specified
assert_error {*Only one of EX, PX, EXAT, PXAT or PERSIST arguments*} {r HGETEX h1 EX 100 PX 1000 FIELDS 1 a}
assert_error {*Only one of EX, PX, EXAT, PXAT or PERSIST arguments*} {r HGETEX h1 EXAT 100 EX 1000 FIELDS 1 a}
assert_error {*Only one of EX, PX, EXAT, PXAT or PERSIST arguments*} {r HGETEX h1 PX 100 EXAT 100 FIELDS 1 a}
assert_error {*Only one of EX, PX, EXAT, PXAT or PERSIST arguments*} {r HGETEX h1 PXAT 100 EX 100 FIELDS 1 a}
assert_error {*Only one of EX, PX, EXAT, PXAT or PERSIST arguments*} {r HGETEX h1 PERSIST EX 100 FIELDS 1 a}
}
test "HGETEX - input validation (expire time) ($type)" {
@ -1124,6 +1132,8 @@ start_server {tags {"external:skip needs:debug"}} {
assert_error {*unknown argument*} {r hsetex myhash nx fields 1 a b}
assert_error {*unknown argument*} {r hsetex myhash 1 fields 1 a b}
assert_error {*wrong number of arguments*} {r hsetex myhash fields 1 a}
assert_error {*unknown argument*} {r hsetex myhash persist fields 1 a b}
assert_error {*unknown argument*} {r hsetex myhash ex 100 persist fields 1 a b}
# Only one of FNX or FXX
assert_error {*Only one of FXX or FNX arguments *} {r hsetex myhash fxx fxx EX 100 fields 1 a b}