diff options
-rw-r--r-- | library.c | 23 | ||||
-rw-r--r-- | library.h | 2 | ||||
-rw-r--r-- | php_redis.h | 2 | ||||
-rw-r--r-- | redis.c | 24 | ||||
-rw-r--r-- | redis_commands.c | 83 | ||||
-rw-r--r-- | redis_commands.h | 6 | ||||
-rw-r--r-- | tests/RedisTest.php | 33 |
7 files changed, 171 insertions, 2 deletions
@@ -1285,6 +1285,15 @@ redis_parse_client_list_response(char *response, zval *z_ret) } PHP_REDIS_API int +redis_zdiff_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx) +{ + if (ctx == NULL) { + return redis_mbulk_reply_raw(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL); + } + return redis_mbulk_reply_zipped_keys_dbl(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL); +} + +PHP_REDIS_API int redis_boolean_response_impl(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx, SuccessCallback success_callback) @@ -1455,7 +1464,12 @@ redis_mbulk_reply_zipped(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, size_t len; if (redis_sock_gets(redis_sock, inbuf, sizeof(inbuf) - 1, &len) < 0) { - return -1; + if (IS_ATOMIC(redis_sock)) { + RETVAL_FALSE; + } else { + add_next_index_bool(z_tab, 0); + } + return FAILURE; } if(inbuf[0] != '*') { @@ -2514,7 +2528,12 @@ redis_mbulk_reply_raw(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval size_t len; if (redis_sock_gets(redis_sock, inbuf, sizeof(inbuf) - 1, &len) < 0) { - return -1; + if (IS_ATOMIC(redis_sock)) { + RETVAL_FALSE; + } else { + add_next_index_bool(z_tab, 0); + } + return FAILURE; } if(inbuf[0] != '*') { @@ -151,6 +151,8 @@ PHP_REDIS_API int redis_read_raw_variant_reply(INTERNAL_FUNCTION_PARAMETERS, Red PHP_REDIS_API int redis_read_variant_reply_strings(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx); PHP_REDIS_API int redis_client_list_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx); +PHP_REDIS_API int redis_zdiff_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx); + /* Helper methods to get configuration values from a HashTable. */ #define REDIS_HASH_STR_FIND_STATIC(ht, sstr) \ diff --git a/php_redis.h b/php_redis.h index 9d44e513..975b8ab5 100644 --- a/php_redis.h +++ b/php_redis.h @@ -144,6 +144,8 @@ PHP_METHOD(Redis, zRevRangeByLex); PHP_METHOD(Redis, zRevRangeByScore); PHP_METHOD(Redis, zRevRank); PHP_METHOD(Redis, zScore); +PHP_METHOD(Redis, zdiff); +PHP_METHOD(Redis, zdiffstore); PHP_METHOD(Redis, zinterstore); PHP_METHOD(Redis, zunionstore); @@ -115,6 +115,16 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_connect, 0, 0, 1) ZEND_ARG_INFO(0, retry_interval) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_zdiff, 0, 0, 1) + ZEND_ARG_ARRAY_INFO(0, keys, 0) + ZEND_ARG_ARRAY_INFO(0, options, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_zdiffstore, 0, 0, 2) + ZEND_ARG_INFO(0, destination) + ZEND_ARG_ARRAY_INFO(0, keys, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO_EX(arginfo_info, 0, 0, 0) ZEND_ARG_INFO(0, option) ZEND_END_ARG_INFO() @@ -472,6 +482,8 @@ static zend_function_entry redis_functions[] = { PHP_ME(Redis, zRevRangeByScore, arginfo_zrangebyscore, ZEND_ACC_PUBLIC) PHP_ME(Redis, zRevRank, arginfo_key_member, ZEND_ACC_PUBLIC) PHP_ME(Redis, zScore, arginfo_key_member, ZEND_ACC_PUBLIC) + PHP_ME(Redis, zdiff, arginfo_zdiff, ZEND_ACC_PUBLIC) + PHP_ME(Redis, zdiffstore, arginfo_zdiffstore, ZEND_ACC_PUBLIC) PHP_ME(Redis, zinterstore, arginfo_zstore, ZEND_ACC_PUBLIC) PHP_ME(Redis, zscan, arginfo_kscan, ZEND_ACC_PUBLIC) PHP_ME(Redis, zunionstore, arginfo_zstore, ZEND_ACC_PUBLIC) @@ -2299,6 +2311,18 @@ PHP_METHOD(Redis, zIncrBy) } /* }}} */ +/* {{{ proto array Redis::zdiff(array keys, array options) */ +PHP_METHOD(Redis, zdiff) { + REDIS_PROCESS_CMD(zdiff, redis_zdiff_response); +} +/* }}} */ + +/* {{{ proto array Redis::zdiffstore(string destination, array keys) */ +PHP_METHOD(Redis, zdiffstore) { + REDIS_PROCESS_CMD(zdiffstore, redis_long_response); +} +/* }}} */ + /* zinterstore */ PHP_METHOD(Redis, zinterstore) { REDIS_PROCESS_KW_CMD("ZINTERSTORE", redis_zinter_cmd, redis_long_response); diff --git a/redis_commands.c b/redis_commands.c index 027fbda0..e18690a4 100644 --- a/redis_commands.c +++ b/redis_commands.c @@ -625,6 +625,89 @@ int redis_zrangebyscore_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, return SUCCESS; } +int +redis_zdiff_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, + char **cmd, int *cmd_len, short *slot, void **ctx) +{ + int numkeys; + smart_string cmdstr = {0}; + zval *z_keys, *z_opts = NULL, *z_ele; + zend_bool withscores = 0; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|a", + &z_keys, &z_opts) == FAILURE) + { + return FAILURE; + } + + if ((numkeys = zend_hash_num_elements(Z_ARRVAL_P(z_keys))) == 0) { + return FAILURE; + } + + if (z_opts && Z_TYPE_P(z_opts) == IS_ARRAY) { + zend_ulong idx; + zend_string *zkey; + ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(z_opts), idx, zkey, z_ele) { + if (zkey != NULL) { + ZVAL_DEREF(z_ele); + if (zend_string_equals_literal_ci(zkey, "withscores")) { + withscores = zval_is_true(z_ele); + } + } + } ZEND_HASH_FOREACH_END(); + } + + REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, 1 + numkeys + withscores, "ZDIFF"); + redis_cmd_append_sstr_long(&cmdstr, numkeys); + + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(z_keys), z_ele) { + ZVAL_DEREF(z_ele); + redis_cmd_append_sstr_zval(&cmdstr, z_ele, redis_sock); + } ZEND_HASH_FOREACH_END(); + + if (withscores) { + REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "WITHSCORES"); + *ctx = redis_sock; + } + + *cmd = cmdstr.c; + *cmd_len = cmdstr.len; + return SUCCESS; +} + +int +redis_zdiffstore_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, + char **cmd, int *cmd_len, short *slot, void **ctx) +{ + char *dst; + size_t dst_len; + int numkeys; + zval *z_keys, *z_ele; + smart_string cmdstr = {0}; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sa", + &dst, &dst_len, &z_keys) == FAILURE) + { + return FAILURE; + } + + if ((numkeys = zend_hash_num_elements(Z_ARRVAL_P(z_keys))) == 0) { + return FAILURE; + } + + REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, 2 + numkeys, "ZDIFFSTORE"); + redis_cmd_append_sstr(&cmdstr, dst, dst_len); + redis_cmd_append_sstr_long(&cmdstr, numkeys); + + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(z_keys), z_ele) { + ZVAL_DEREF(z_ele); + redis_cmd_append_sstr_zval(&cmdstr, z_ele, redis_sock); + } ZEND_HASH_FOREACH_END(); + + *cmd = cmdstr.c; + *cmd_len = cmdstr.len; + return SUCCESS; +} /* ZUNIONSTORE, ZINTERSTORE */ int redis_zinter_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, diff --git a/redis_commands.h b/redis_commands.h index 3a3e0491..c2f79095 100644 --- a/redis_commands.h +++ b/redis_commands.h @@ -103,6 +103,12 @@ int redis_zrangebyscore_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, char *kw, char **cmd, int *cmd_len, int *withscores, short *slot, void **ctx); +int redis_zdiff_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, + char **cmd, int *cmd_len, short *slot, void **ctx); + +int redis_zdiffstore_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, + char **cmd, int *cmd_len, short *slot, void **ctx); + int redis_zinter_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, char *kw, char **cmd, int *cmd_len, short *slot, void **ctx); diff --git a/tests/RedisTest.php b/tests/RedisTest.php index d4b3cfe1..fcf5d811 100644 --- a/tests/RedisTest.php +++ b/tests/RedisTest.php @@ -2530,6 +2530,39 @@ class Redis_Test extends TestSuite } } + public function testzDiff() + { + // Only available since 6.2.0 + if (version_compare($this->version, '6.2.0') < 0) { + $this->markTestSkipped(); + return; + } + + $this->redis->del('key'); + foreach (range('a', 'c') as $c) { + $this->redis->zAdd('key', 1, $c); + } + + $this->assertEquals(['a', 'b', 'c'], $this->redis->zDiff(['key'])); + $this->assertEquals(['a' => 1.0, 'b' => 1.0, 'c' => 1.0], $this->redis->zDiff(['key'], ['withscores' => true])); + } + + public function testzDiffStore() + { + // Only available since 6.2.0 + if (version_compare($this->version, '6.2.0') < 0) { + $this->markTestSkipped(); + return; + } + + $this->redis->del('key'); + foreach (range('a', 'c') as $c) { + $this->redis->zAdd('key', 1, $c); + } + $this->assertEquals(3, $this->redis->zDiffStore('key2', ['key'])); + $this->assertEquals(['a', 'b', 'c'], $this->redis->zRange('key2', 0, -1)); + } + public function testzMscore() { // Only available since 6.2.0 |