Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a2eef77

Browse files
Implement Valkey >= 8.1 IFEQ set option
Implement the new `IFEQ` `SET` option that will be included in `Valkey` 8.1. See: valkey-io/valkey#1324
1 parent faa4bc2 commit a2eef77

File tree

4 files changed

+45
-4
lines changed

4 files changed

+45
-4
lines changed

redis_commands.c

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2293,7 +2293,8 @@ int redis_set_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
22932293
char **cmd, int *cmd_len, short *slot, void **ctx)
22942294
{
22952295
char *key = NULL, *exp_type = NULL, *set_type = NULL;
2296-
zval *z_value, *z_opts=NULL;
2296+
zend_string *ifeq = NULL, *tmp = NULL;
2297+
zval *z_value, *z_opts = NULL;
22972298
smart_string cmdstr = {0};
22982299
zend_long expire = -1;
22992300
zend_bool get = 0;
@@ -2312,7 +2313,6 @@ int redis_set_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
23122313
return FAILURE;
23132314
}
23142315

2315-
23162316
// Check for an options array
23172317
if (z_opts && Z_TYPE_P(z_opts) == IS_ARRAY) {
23182318
HashTable *kt = Z_ARRVAL_P(z_opts);
@@ -2329,11 +2329,14 @@ int redis_set_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
23292329
zend_string_equals_literal_ci(zkey, "PXAT"))
23302330
) {
23312331
if (redis_try_get_expiry(v, &expire) == FAILURE || expire < 1) {
2332+
zend_tmp_string_release(tmp);
23322333
setExpiryWarning(v);
23332334
return FAILURE;
23342335
}
23352336

23362337
exp_type = ZSTR_VAL(zkey);
2338+
} else if (zkey && !ifeq && zend_string_equals_literal_ci(zkey, "IFEQ")) {
2339+
ifeq = zval_get_tmp_string(v, &tmp);
23372340
} else if (Z_TYPE_P(v) == IS_STRING) {
23382341
if (zend_string_equals_literal_ci(Z_STR_P(v), "KEEPTTL")) {
23392342
keep_ttl = 1;
@@ -2348,6 +2351,7 @@ int redis_set_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
23482351
} ZEND_HASH_FOREACH_END();
23492352
} else if (z_opts && Z_TYPE_P(z_opts) != IS_NULL) {
23502353
if (redis_try_get_expiry(z_opts, &expire) == FAILURE || expire < 1) {
2354+
zend_tmp_string_release(tmp);
23512355
setExpiryWarning(z_opts);
23522356
return FAILURE;
23532357
}
@@ -2356,18 +2360,28 @@ int redis_set_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
23562360
/* Protect the user from syntax errors but give them some info about what's wrong */
23572361
if (exp_type && keep_ttl) {
23582362
php_error_docref(NULL, E_WARNING, "KEEPTTL can't be combined with EX or PX option");
2363+
zend_tmp_string_release(tmp);
2364+
return FAILURE;
2365+
}
2366+
2367+
/* You can't use IFEQ with NX or XX */
2368+
if (set_type && ifeq) {
2369+
php_error_docref(NULL, E_WARNING, "IFEQ can't be combined with NX or XX option");
2370+
zend_tmp_string_release(tmp);
23592371
return FAILURE;
23602372
}
23612373

23622374
/* Backward compatibility: If we are passed no options except an EXPIRE ttl, we
23632375
* actually execute a SETEX command */
23642376
if (expire > 0 && !exp_type && !set_type && !keep_ttl) {
23652377
*cmd_len = REDIS_CMD_SPPRINTF(cmd, "SETEX", "klv", key, key_len, expire, z_value);
2378+
zend_tmp_string_release(tmp);
23662379
return SUCCESS;
23672380
}
23682381

23692382
/* Calculate argc based on options set */
2370-
int argc = 2 + (exp_type ? 2 : 0) + (set_type != NULL) + (keep_ttl != 0) + get;
2383+
int argc = 2 + (ifeq ? 2 : 0) + (exp_type ? 2 : 0) + (set_type != NULL) +
2384+
(keep_ttl != 0) + get;
23712385

23722386
/* Initial SET <key> <value> */
23732387
redis_cmd_init_sstr(&cmdstr, argc, "SET", 3);
@@ -2379,15 +2393,22 @@ int redis_set_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
23792393
redis_cmd_append_sstr_long(&cmdstr, (long)expire);
23802394
}
23812395

2382-
if (set_type)
2396+
if (ifeq) {
2397+
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "IFEQ");
2398+
redis_cmd_append_sstr_zstr(&cmdstr, ifeq);
2399+
} else if (set_type) {
23832400
redis_cmd_append_sstr(&cmdstr, set_type, strlen(set_type));
2401+
}
2402+
23842403
if (keep_ttl)
23852404
redis_cmd_append_sstr(&cmdstr, "KEEPTTL", 7);
23862405
if (get) {
23872406
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "GET");
23882407
*ctx = PHPREDIS_CTX_PTR;
23892408
}
23902409

2410+
zend_tmp_string_release(tmp);
2411+
23912412
/* Push command and length to the caller */
23922413
*cmd = cmdstr.c;
23932414
*cmd_len = cmdstr.len;

tests/RedisClusterTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ public function setUp() {
133133
$info = $this->redis->info(uniqid());
134134
$this->version = $info['redis_version'] ?? '0.0.0';
135135
$this->is_keydb = $this->detectKeyDB($info);
136+
$this->is_valkey = $this->detectValkey($info);
136137
}
137138

138139
/* Override newInstance as we want a RedisCluster object */

tests/RedisTest.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,16 @@ protected function detectKeyDB(array $info) {
6767
isset($info['mvcc_depth']);
6868
}
6969

70+
protected function detectValkey(array $info) {
71+
return isset($info['server_name']) && $info['server_name'] === 'valkey';
72+
}
73+
7074
public function setUp() {
7175
$this->redis = $this->newInstance();
7276
$info = $this->redis->info();
7377
$this->version = (isset($info['redis_version'])?$info['redis_version']:'0.0.0');
7478
$this->is_keydb = $this->detectKeyDB($info);
79+
$this->is_valkey = $this->detectValKey($info);
7580
}
7681

7782
protected function minVersionCheck($version) {
@@ -629,6 +634,19 @@ public function testExtendedSet() {
629634
$this->assertEquals('bar', $this->redis->set('foo', 'baz', ['GET']));
630635
}
631636

637+
/* Test Valkey >= 8.1 IFEQ SET option */
638+
public function testValkeyIfEq() {
639+
if ( ! $this->is_valkey || ! $this->minVersionCheck('8.1.0'))
640+
$this->markTestSkipped();
641+
642+
$this->redis->del('foo');
643+
$this->assertTrue($this->redis->set('foo', 'bar'));
644+
$this->assertTrue($this->redis->set('foo', 'bar2', ['IFEQ' => 'bar']));
645+
$this->assertFalse($this->redis->set('foo', 'bar4', ['IFEQ' => 'bar3']));
646+
647+
$this->assertEquals('bar2', $this->redis->set('foo', 'bar3', ['IFEQ' => 'bar2', 'GET']));
648+
}
649+
632650
public function testGetSet() {
633651
$this->redis->del('key');
634652
$this->assertFalse($this->redis->getSet('key', '42'));

tests/TestSuite.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ class TestSuite
1616
/* Redis server version */
1717
protected $version;
1818
protected bool $is_keydb;
19+
protected bool $is_valkey;
1920

2021
private static bool $colorize = false;
2122

0 commit comments

Comments
 (0)