Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/phpredis/phpredis.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPavlo Yatsukhnenko <yatsukhnenko@gmail.com>2021-03-21 00:21:18 +0300
committerPavlo Yatsukhnenko <yatsukhnenko@gmail.com>2021-03-21 00:29:08 +0300
commitd5cf52cb8ad38718894052038d8e32dc53f4d5b5 (patch)
tree3f175c84dc32b52b8d2b7582228fecddffd111d9
parent747d3245721f4d7eb0a26dd0baaa551b74751ce2 (diff)
[WIP] Issue #1894
Add Redis::zinter and Redis::zunion commands
-rw-r--r--php_redis.h2
-rw-r--r--redis.c24
-rw-r--r--redis_cluster.c4
-rw-r--r--redis_commands.c121
-rw-r--r--redis_commands.h5
-rw-r--r--tests/RedisClusterTest.php2
-rw-r--r--tests/RedisTest.php34
7 files changed, 186 insertions, 6 deletions
diff --git a/php_redis.h b/php_redis.h
index 975b8ab5..6b7b3be4 100644
--- a/php_redis.h
+++ b/php_redis.h
@@ -146,7 +146,9 @@ PHP_METHOD(Redis, zRevRank);
PHP_METHOD(Redis, zScore);
PHP_METHOD(Redis, zdiff);
PHP_METHOD(Redis, zdiffstore);
+PHP_METHOD(Redis, zinter);
PHP_METHOD(Redis, zinterstore);
+PHP_METHOD(Redis, zunion);
PHP_METHOD(Redis, zunionstore);
PHP_METHOD(Redis, eval);
diff --git a/redis.c b/redis.c
index 481ccb20..5d860401 100644
--- a/redis.c
+++ b/redis.c
@@ -120,6 +120,12 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_zdiff, 0, 0, 1)
ZEND_ARG_ARRAY_INFO(0, options, 0)
ZEND_END_ARG_INFO()
+ZEND_BEGIN_ARG_INFO_EX(arginfo_zinterunion, 0, 0, 1)
+ ZEND_ARG_ARRAY_INFO(0, keys, 0)
+ ZEND_ARG_ARRAY_INFO(0, weights, 1)
+ 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)
@@ -484,8 +490,10 @@ static zend_function_entry redis_functions[] = {
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, zinter, arginfo_zinterunion, ZEND_ACC_PUBLIC)
PHP_ME(Redis, zinterstore, arginfo_zstore, ZEND_ACC_PUBLIC)
PHP_ME(Redis, zscan, arginfo_kscan, ZEND_ACC_PUBLIC)
+ PHP_ME(Redis, zunion, arginfo_zinterunion, ZEND_ACC_PUBLIC)
PHP_ME(Redis, zunionstore, arginfo_zstore, ZEND_ACC_PUBLIC)
PHP_FE_END
};
@@ -2317,6 +2325,18 @@ PHP_METHOD(Redis, zdiff) {
}
/* }}} */
+/* {{{ proto array Redis::zinter(array keys, array|null weights, array options) */
+PHP_METHOD(Redis, zinter) {
+ REDIS_PROCESS_KW_CMD("ZINTER", redis_zinterunion_cmd, redis_zdiff_response);
+}
+/* }}} */
+
+/* {{{ proto array Redis::zunion(array keys, array|null weights, array options) */
+PHP_METHOD(Redis, zunion) {
+ REDIS_PROCESS_KW_CMD("ZUNION", redis_zinterunion_cmd, redis_zdiff_response);
+}
+/* }}} */
+
/* {{{ proto array Redis::zdiffstore(string destination, array keys) */
PHP_METHOD(Redis, zdiffstore) {
REDIS_PROCESS_CMD(zdiffstore, redis_long_response);
@@ -2325,12 +2345,12 @@ PHP_METHOD(Redis, zdiffstore) {
/* zinterstore */
PHP_METHOD(Redis, zinterstore) {
- REDIS_PROCESS_KW_CMD("ZINTERSTORE", redis_zinter_cmd, redis_long_response);
+ REDIS_PROCESS_KW_CMD("ZINTERSTORE", redis_zinterunionstore_cmd, redis_long_response);
}
/* zunionstore */
PHP_METHOD(Redis, zunionstore) {
- REDIS_PROCESS_KW_CMD("ZUNIONSTORE", redis_zinter_cmd, redis_long_response);
+ REDIS_PROCESS_KW_CMD("ZUNIONSTORE", redis_zinterunionstore_cmd, redis_long_response);
}
/* {{{ proto array Redis::zPopMax(string key) */
diff --git a/redis_cluster.c b/redis_cluster.c
index ab9d55b7..23bf781a 100644
--- a/redis_cluster.c
+++ b/redis_cluster.c
@@ -1683,14 +1683,14 @@ PHP_METHOD(RedisCluster, zrangebyscore) {
/* {{{ proto RedisCluster::zunionstore(string dst, array keys, [array weights,
* string agg]) */
PHP_METHOD(RedisCluster, zunionstore) {
- CLUSTER_PROCESS_KW_CMD("ZUNIONSTORE", redis_zinter_cmd, cluster_long_resp, 0);
+ CLUSTER_PROCESS_KW_CMD("ZUNIONSTORE", redis_zinterunionstore_cmd, cluster_long_resp, 0);
}
/* }}} */
/* {{{ proto RedisCluster::zinterstore(string dst, array keys, [array weights,
* string agg]) */
PHP_METHOD(RedisCluster, zinterstore) {
- CLUSTER_PROCESS_KW_CMD("ZINTERSTORE", redis_zinter_cmd, cluster_long_resp, 0);
+ CLUSTER_PROCESS_KW_CMD("ZINTERSTORE", redis_zinterunionstore_cmd, cluster_long_resp, 0);
}
/* }}} */
diff --git a/redis_commands.c b/redis_commands.c
index e18690a4..aa1cf62d 100644
--- a/redis_commands.c
+++ b/redis_commands.c
@@ -676,6 +676,124 @@ redis_zdiff_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
}
int
+redis_zinterunion_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
+ char *kw, char **cmd, int *cmd_len, short *slot,
+ void **ctx)
+{
+ int numkeys;
+ smart_string cmdstr = {0};
+ zval *z_keys, *z_weights = NULL, *z_opts = NULL, *z_ele;
+ zend_string *aggregate = NULL;
+ zend_bool withscores = 0;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|a!a",
+ &z_keys, &z_weights, &z_opts) == FAILURE)
+ {
+ return FAILURE;
+ }
+
+ if ((numkeys = zend_hash_num_elements(Z_ARRVAL_P(z_keys))) == 0) {
+ return FAILURE;
+ }
+
+ if (z_weights) {
+ if (zend_hash_num_elements(Z_ARRVAL_P(z_weights)) != numkeys) {
+ php_error_docref(NULL, E_WARNING,
+ "WEIGHTS and keys array should be the same size!");
+ 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, "aggregate")) {
+ aggregate = zval_get_string(z_ele);
+ if (!zend_string_equals_literal_ci(aggregate, "sum") &&
+ !zend_string_equals_literal_ci(aggregate, "min") &&
+ !zend_string_equals_literal_ci(aggregate, "max")
+ ) {
+ php_error_docref(NULL, E_WARNING,
+ "Invalid AGGREGATE option provided!");
+ zend_string_release(aggregate);
+ return FAILURE;
+ }
+ } else if (zend_string_equals_literal_ci(zkey, "withscores")) {
+ withscores = zval_is_true(z_ele);
+ }
+ }
+ } ZEND_HASH_FOREACH_END();
+ }
+
+ redis_cmd_init_sstr(&cmdstr, 1 + numkeys + (z_weights ? 1 + numkeys : 0) + (aggregate ? 2 : 0) + withscores, kw, strlen(kw));
+ 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 (z_weights) {
+ REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "WEIGHTS");
+ ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(z_weights), z_ele) {
+ ZVAL_DEREF(z_ele);
+ switch (Z_TYPE_P(z_ele)) {
+ case IS_LONG:
+ redis_cmd_append_sstr_long(&cmdstr, Z_LVAL_P(z_ele));
+ break;
+ case IS_DOUBLE:
+ redis_cmd_append_sstr_dbl(&cmdstr, Z_DVAL_P(z_ele));
+ break;
+ case IS_STRING: {
+ double dval;
+ zend_long lval;
+ zend_uchar type = is_numeric_string(Z_STRVAL_P(z_ele), Z_STRLEN_P(z_ele), &lval, &dval, 0);
+ if (type == IS_LONG) {
+ redis_cmd_append_sstr_long(&cmdstr, lval);
+ break;
+ } else if (type == IS_DOUBLE) {
+ redis_cmd_append_sstr_dbl(&cmdstr, dval);
+ break;
+ } else if (strncasecmp(Z_STRVAL_P(z_ele), "-inf", sizeof("-inf") - 1) == 0 ||
+ strncasecmp(Z_STRVAL_P(z_ele), "+inf", sizeof("+inf") - 1) == 0 ||
+ strncasecmp(Z_STRVAL_P(z_ele), "inf", sizeof("inf") - 1) == 0
+ ) {
+ redis_cmd_append_sstr(&cmdstr, Z_STRVAL_P(z_ele), Z_STRLEN_P(z_ele));
+ break;
+ }
+ // fall through
+ }
+ default:
+ php_error_docref(NULL, E_WARNING,
+ "Weights must be numeric or '-inf','inf','+inf'");
+ if (aggregate) zend_string_release(aggregate);
+ efree(cmdstr.c);
+ return FAILURE;
+ }
+ } ZEND_HASH_FOREACH_END();
+ }
+
+ if (aggregate) {
+ REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "AGGREGATE");
+ redis_cmd_append_sstr_zstr(&cmdstr, aggregate);
+ zend_string_release(aggregate);
+ }
+
+ 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)
{
@@ -710,7 +828,8 @@ redis_zdiffstore_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
}
/* ZUNIONSTORE, ZINTERSTORE */
-int redis_zinter_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
+int
+redis_zinterunionstore_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot,
void **ctx)
{
diff --git a/redis_commands.h b/redis_commands.h
index c2f79095..be30a310 100644
--- a/redis_commands.h
+++ b/redis_commands.h
@@ -106,10 +106,13 @@ int redis_zrangebyscore_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
int redis_zdiff_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
+int redis_zinterunion_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
+ char *kw, 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,
+int redis_zinterunionstore_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_subscribe_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
diff --git a/tests/RedisClusterTest.php b/tests/RedisClusterTest.php
index b7746c5e..350f35f8 100644
--- a/tests/RedisClusterTest.php
+++ b/tests/RedisClusterTest.php
@@ -52,6 +52,8 @@ class Redis_Cluster_Test extends Redis_Test {
public function testlMove() { return $this->markTestSkipped(); }
public function testsMisMember() { return $this->markTestSkipped(); }
public function testzDiff() { return $this->markTestSkipped(); }
+ public function testzInter() { return $this->markTestSkipped(); }
+ public function testzUnion() { return $this->markTestSkipped(); }
public function testzDiffStore() { return $this->markTestSkipped(); }
public function testzMscore() { return $this->marktestSkipped(); }
public function testCopy() { return $this->marktestSkipped(); }
diff --git a/tests/RedisTest.php b/tests/RedisTest.php
index b4410cd9..a2463f59 100644
--- a/tests/RedisTest.php
+++ b/tests/RedisTest.php
@@ -2547,6 +2547,40 @@ class Redis_Test extends TestSuite
$this->assertEquals(['a' => 1.0, 'b' => 1.0, 'c' => 1.0], $this->redis->zDiff(['key'], ['withscores' => true]));
}
+ public function testzInter()
+ {
+ // 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->zInter(['key']));
+ $this->assertEquals(['a' => 1.0, 'b' => 1.0, 'c' => 1.0], $this->redis->zInter(['key'], null, ['withscores' => true]));
+ }
+
+ public function testzUnion()
+ {
+ // 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->zUnion(['key']));
+ $this->assertEquals(['a' => 1.0, 'b' => 1.0, 'c' => 1.0], $this->redis->zUnion(['key'], null, ['withscores' => true]));
+ }
+
public function testzDiffStore()
{
// Only available since 6.2.0