diff options
author | michael-grunder <michael.grunder@gmail.com> | 2022-10-01 20:25:54 +0300 |
---|---|---|
committer | Michael Grunder <michael.grunder@gmail.com> | 2022-10-01 20:42:23 +0300 |
commit | 643005080839b35c40d78af40eda3e2743ad4d6f (patch) | |
tree | 51a2f7e4c3ad1fe09ef09119efb69d3075265eb8 | |
parent | 239678a03bb9efcd30893a99c37ba62d22d22b5d (diff) |
SINTERCARD and ZINTERCARD commands
Implement Redis 7.0.0 commands SINTERCARD and ZINTERCARD.
-rw-r--r-- | cluster_library.c | 4 | ||||
-rw-r--r-- | cluster_library.h | 1 | ||||
-rw-r--r-- | library.c | 41 | ||||
-rw-r--r-- | library.h | 4 | ||||
-rw-r--r-- | redis.c | 8 | ||||
-rw-r--r-- | redis.stub.php | 4 | ||||
-rw-r--r-- | redis_arginfo.h | 13 | ||||
-rw-r--r-- | redis_cluster.c | 13 | ||||
-rw-r--r-- | redis_cluster.stub.php | 4 | ||||
-rw-r--r-- | redis_cluster_arginfo.h | 13 | ||||
-rw-r--r-- | redis_cluster_legacy_arginfo.h | 13 | ||||
-rw-r--r-- | redis_commands.c | 57 | ||||
-rw-r--r-- | redis_commands.h | 4 | ||||
-rw-r--r-- | redis_legacy_arginfo.h | 13 | ||||
-rw-r--r-- | tests/RedisTest.php | 49 |
15 files changed, 237 insertions, 4 deletions
diff --git a/cluster_library.c b/cluster_library.c index f11c2dcb..6e69c518 100644 --- a/cluster_library.c +++ b/cluster_library.c @@ -530,6 +530,10 @@ unsigned short cluster_hash_key(const char *key, int len) { return crc16((char*)key+s+1,e-s-1) & REDIS_CLUSTER_MOD; } +unsigned short cluster_hash_key_zstr(zend_string *key) { + return cluster_hash_key(ZSTR_VAL(key), ZSTR_LEN(key)); +} + /* Grab the current time in milliseconds */ long long mstime(void) { struct timeval tv; diff --git a/cluster_library.h b/cluster_library.h index fe2962f0..ddb29f29 100644 --- a/cluster_library.h +++ b/cluster_library.h @@ -352,6 +352,7 @@ void cluster_multi_fini(clusterMultiCmd *mc); /* Hash a key to it's slot, using the Redis Cluster hash algorithm */ unsigned short cluster_hash_key_zval(zval *key); unsigned short cluster_hash_key(const char *key, int len); +unsigned short cluster_hash_key_zstr(zend_string *key); /* Validate and sanitize cluster construction args */ zend_string** cluster_validate_args(double timeout, double read_timeout, @@ -3502,6 +3502,47 @@ redis_key_prefix(RedisSock *redis_sock, char **key, size_t *key_len) { return 1; } +/* This is very similar to PHP >= 7.4 zend_string_concat2 only we are taking + * two zend_string arguments rather than two char*, size_t pairs */ +static zend_string *redis_zstr_concat(zend_string *prefix, zend_string *suffix) { + zend_string *res; + size_t len; + + ZEND_ASSERT(prefix != NULL && suffix != NULL); + + len = ZSTR_LEN(prefix) + ZSTR_LEN(suffix); + res = zend_string_alloc(len, 0); + + memcpy(ZSTR_VAL(res), ZSTR_VAL(prefix), ZSTR_LEN(prefix)); + memcpy(ZSTR_VAL(res) + ZSTR_LEN(prefix), ZSTR_VAL(suffix), ZSTR_LEN(suffix)); + ZSTR_VAL(res)[len] = '\0'; + + return res; +} + +PHP_REDIS_API zend_string * +redis_key_prefix_zval(RedisSock *redis_sock, zval *zv) { + zend_string *zstr, *dup; + + zstr = zval_get_string(zv); + if (redis_sock->prefix == NULL) + return zstr; + + dup = redis_zstr_concat(redis_sock->prefix, zstr); + + zend_string_release(zstr); + + return dup; +} + +PHP_REDIS_API zend_string * +redis_key_prefix_zstr(RedisSock *redis_sock, zend_string *key) { + if (redis_sock->prefix == NULL) + return zend_string_copy(key); + + return redis_zstr_concat(redis_sock->prefix, key); +} + /* * Processing for variant reply types (think EVAL) */ @@ -123,6 +123,10 @@ PHP_REDIS_API int redis_serialize(RedisSock *redis_sock, zval *z, char **val, size_t *val_len); PHP_REDIS_API int redis_key_prefix(RedisSock *redis_sock, char **key, size_t *key_len); +PHP_REDIS_API zend_string* +redis_key_prefix_zval(RedisSock *redis_sock, zval *zv); +PHP_REDIS_API zend_string * +redis_key_prefix_zstr(RedisSock *redis_sock, zend_string *key); PHP_REDIS_API int redis_unserialize(RedisSock *redis_sock, const char *val, int val_len, zval *z_ret); @@ -1435,6 +1435,10 @@ PHP_METHOD(Redis, sInter) { } /* }}} */ +PHP_METHOD(Redis, sintercard) { + REDIS_PROCESS_KW_CMD("SINTERCARD", redis_intercard_cmd, redis_long_response); +} + /* {{{ proto array Redis::sInterStore(string dst, string key0,...string keyN) */ PHP_METHOD(Redis, sInterStore) { REDIS_PROCESS_CMD(sinterstore, redis_long_response); @@ -2071,6 +2075,10 @@ PHP_METHOD(Redis, zinter) { } /* }}} */ +PHP_METHOD(Redis, zintercard) { + REDIS_PROCESS_KW_CMD("ZINTERCARD", redis_intercard_cmd, redis_long_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); diff --git a/redis.stub.php b/redis.stub.php index be56508d..7f125ddf 100644 --- a/redis.stub.php +++ b/redis.stub.php @@ -363,6 +363,8 @@ public function persist(string $key): bool; public function sInter(string $key, string ...$other_keys): array; + public function sintercard(array $keys, int $limit = -1): Redis|int|false; + public function sInterStore(string $dst, string $key, string ...$other_keys): int; public function sMembers(string $key): array; @@ -548,6 +550,8 @@ public function persist(string $key): bool; public function zinter(array $keys, array $weights = null, array $options = null): array; + public function zintercard(array $keys, int $limit = -1): Redis|int|false; + public function zinterstore(string $dst, array $keys, array $weights = null, string $aggregate = null): int; public function zscan(string $key, ?int &$iterator, ?string $pattern = null, int $count = 0): bool|array; diff --git a/redis_arginfo.h b/redis_arginfo.h index 66176b34..33526de0 100644 --- a/redis_arginfo.h +++ b/redis_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 122b5ca534302a09a4f072106d097f2831ba6f22 */ + * Stub hash: f43a528bc5874c419161b5eb874537fbe9c00e87 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis___construct, 0, 0, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 0, "null") @@ -628,6 +628,11 @@ ZEND_END_ARG_INFO() #define arginfo_class_Redis_sInter arginfo_class_Redis_sDiff +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_sintercard, 0, 1, Redis, MAY_BE_LONG|MAY_BE_FALSE) + ZEND_ARG_TYPE_INFO(0, keys, IS_ARRAY, 0) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, limit, IS_LONG, 0, "-1") +ZEND_END_ARG_INFO() + #define arginfo_class_Redis_sInterStore arginfo_class_Redis_sDiffStore #define arginfo_class_Redis_sMembers arginfo_class_Redis_hGetAll @@ -971,6 +976,8 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_zinter, 0, 1, IS_ARR ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 0, "null") ZEND_END_ARG_INFO() +#define arginfo_class_Redis_zintercard arginfo_class_Redis_sintercard + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_zinterstore, 0, 2, IS_LONG, 0) ZEND_ARG_TYPE_INFO(0, dst, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, keys, IS_ARRAY, 0) @@ -1130,6 +1137,7 @@ ZEND_METHOD(Redis, sAddArray); ZEND_METHOD(Redis, sDiff); ZEND_METHOD(Redis, sDiffStore); ZEND_METHOD(Redis, sInter); +ZEND_METHOD(Redis, sintercard); ZEND_METHOD(Redis, sInterStore); ZEND_METHOD(Redis, sMembers); ZEND_METHOD(Redis, sMisMember); @@ -1209,6 +1217,7 @@ ZEND_METHOD(Redis, zScore); ZEND_METHOD(Redis, zdiff); ZEND_METHOD(Redis, zdiffstore); ZEND_METHOD(Redis, zinter); +ZEND_METHOD(Redis, zintercard); ZEND_METHOD(Redis, zinterstore); ZEND_METHOD(Redis, zscan); ZEND_METHOD(Redis, zunion); @@ -1364,6 +1373,7 @@ static const zend_function_entry class_Redis_methods[] = { ZEND_ME(Redis, sDiff, arginfo_class_Redis_sDiff, ZEND_ACC_PUBLIC) ZEND_ME(Redis, sDiffStore, arginfo_class_Redis_sDiffStore, ZEND_ACC_PUBLIC) ZEND_ME(Redis, sInter, arginfo_class_Redis_sInter, ZEND_ACC_PUBLIC) + ZEND_ME(Redis, sintercard, arginfo_class_Redis_sintercard, ZEND_ACC_PUBLIC) ZEND_ME(Redis, sInterStore, arginfo_class_Redis_sInterStore, ZEND_ACC_PUBLIC) ZEND_ME(Redis, sMembers, arginfo_class_Redis_sMembers, ZEND_ACC_PUBLIC) ZEND_ME(Redis, sMisMember, arginfo_class_Redis_sMisMember, ZEND_ACC_PUBLIC) @@ -1443,6 +1453,7 @@ static const zend_function_entry class_Redis_methods[] = { ZEND_ME(Redis, zdiff, arginfo_class_Redis_zdiff, ZEND_ACC_PUBLIC) ZEND_ME(Redis, zdiffstore, arginfo_class_Redis_zdiffstore, ZEND_ACC_PUBLIC) ZEND_ME(Redis, zinter, arginfo_class_Redis_zinter, ZEND_ACC_PUBLIC) + ZEND_ME(Redis, zintercard, arginfo_class_Redis_zintercard, ZEND_ACC_PUBLIC) ZEND_ME(Redis, zinterstore, arginfo_class_Redis_zinterstore, ZEND_ACC_PUBLIC) ZEND_ME(Redis, zscan, arginfo_class_Redis_zscan, ZEND_ACC_PUBLIC) ZEND_ME(Redis, zunion, arginfo_class_Redis_zunion, ZEND_ACC_PUBLIC) diff --git a/redis_cluster.c b/redis_cluster.c index f163158a..4be54bf8 100644 --- a/redis_cluster.c +++ b/redis_cluster.c @@ -1021,6 +1021,13 @@ PHP_METHOD(RedisCluster, sunionstore) { PHP_METHOD(RedisCluster, sinter) { CLUSTER_PROCESS_CMD(sinter, cluster_mbulk_resp, 0); } + +/* {{{ proto RedisCluster::sintercard(array $keys, int $count = -1) */ +PHP_METHOD(RedisCluster, sintercard) { + CLUSTER_PROCESS_KW_CMD("SINTERCARD", redis_intercard_cmd, cluster_long_resp, 0); +} +/* }}} */ + /* }}} */ /* {{{ ptoto long RedisCluster::sinterstore(string dst, string k1, ... kN) */ @@ -1457,6 +1464,12 @@ PHP_METHOD(RedisCluster, zinterstore) { } /* }}} */ +/* {{{ proto RedisCluster::zintercard(array $keys, int $count = -1) */ +PHP_METHOD(RedisCluster, zintercard) { + CLUSTER_PROCESS_KW_CMD("ZINTERCARD", redis_intercard_cmd, cluster_long_resp, 0); +} +/* }}} */ + /* {{{ proto RedisCluster::zrem(string key, string val1, ... valN) */ PHP_METHOD(RedisCluster, zrem) { CLUSTER_PROCESS_KW_CMD("ZREM", redis_key_varval_cmd, cluster_long_resp, 0); diff --git a/redis_cluster.stub.php b/redis_cluster.stub.php index ed0a8293..924b9c04 100644 --- a/redis_cluster.stub.php +++ b/redis_cluster.stub.php @@ -276,6 +276,8 @@ class RedisCluster { public function sinter(string $key, string ...$other_keys): array; + public function sintercard(array $keys, int $limit = -1): Redis|int|false; + public function sinterstore(string $dst, string $key, string ...$other_keys): bool; public function sismember(string $key): int; @@ -354,6 +356,8 @@ class RedisCluster { public function zinterstore(string $key, array $keys, array $weights = null, string $aggregate = null): int; + public function zintercard(array $keys, int $limit = -1): Redis|int|false; + public function zlexcount(string $key, string $min, string $max): int; public function zpopmax(string $key, int $value = null): bool|array; diff --git a/redis_cluster_arginfo.h b/redis_cluster_arginfo.h index 842cd4a2..35f2ab11 100644 --- a/redis_cluster_arginfo.h +++ b/redis_cluster_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 97fe79bf371074b77d22e1e820903fb2103d10c9 */ + * Stub hash: c9bfd7de5c930c9d7190139e207eb6025e33bdb2 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 1) @@ -584,6 +584,11 @@ ZEND_END_ARG_INFO() #define arginfo_class_RedisCluster_sinter arginfo_class_RedisCluster_del +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_sintercard, 0, 1, Redis, MAY_BE_LONG|MAY_BE_FALSE) + ZEND_ARG_TYPE_INFO(0, keys, IS_ARRAY, 0) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, limit, IS_LONG, 0, "-1") +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_sinterstore, 0, 2, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, dst, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0) @@ -775,6 +780,8 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_zinterstore, ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, aggregate, IS_STRING, 0, "null") ZEND_END_ARG_INFO() +#define arginfo_class_RedisCluster_zintercard arginfo_class_RedisCluster_sintercard + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_zlexcount, 0, 3, IS_LONG, 0) ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, min, IS_STRING, 0) @@ -973,6 +980,7 @@ ZEND_METHOD(RedisCluster, setnx); ZEND_METHOD(RedisCluster, setoption); ZEND_METHOD(RedisCluster, setrange); ZEND_METHOD(RedisCluster, sinter); +ZEND_METHOD(RedisCluster, sintercard); ZEND_METHOD(RedisCluster, sinterstore); ZEND_METHOD(RedisCluster, sismember); ZEND_METHOD(RedisCluster, slowlog); @@ -1012,6 +1020,7 @@ ZEND_METHOD(RedisCluster, zcard); ZEND_METHOD(RedisCluster, zcount); ZEND_METHOD(RedisCluster, zincrby); ZEND_METHOD(RedisCluster, zinterstore); +ZEND_METHOD(RedisCluster, zintercard); ZEND_METHOD(RedisCluster, zlexcount); ZEND_METHOD(RedisCluster, zpopmax); ZEND_METHOD(RedisCluster, zpopmin); @@ -1167,6 +1176,7 @@ static const zend_function_entry class_RedisCluster_methods[] = { ZEND_ME(RedisCluster, setoption, arginfo_class_RedisCluster_setoption, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, setrange, arginfo_class_RedisCluster_setrange, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, sinter, arginfo_class_RedisCluster_sinter, ZEND_ACC_PUBLIC) + ZEND_ME(RedisCluster, sintercard, arginfo_class_RedisCluster_sintercard, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, sinterstore, arginfo_class_RedisCluster_sinterstore, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, sismember, arginfo_class_RedisCluster_sismember, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, slowlog, arginfo_class_RedisCluster_slowlog, ZEND_ACC_PUBLIC) @@ -1206,6 +1216,7 @@ static const zend_function_entry class_RedisCluster_methods[] = { ZEND_ME(RedisCluster, zcount, arginfo_class_RedisCluster_zcount, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, zincrby, arginfo_class_RedisCluster_zincrby, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, zinterstore, arginfo_class_RedisCluster_zinterstore, ZEND_ACC_PUBLIC) + ZEND_ME(RedisCluster, zintercard, arginfo_class_RedisCluster_zintercard, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, zlexcount, arginfo_class_RedisCluster_zlexcount, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, zpopmax, arginfo_class_RedisCluster_zpopmax, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, zpopmin, arginfo_class_RedisCluster_zpopmin, ZEND_ACC_PUBLIC) diff --git a/redis_cluster_legacy_arginfo.h b/redis_cluster_legacy_arginfo.h index 3cc0618d..bff23cd6 100644 --- a/redis_cluster_legacy_arginfo.h +++ b/redis_cluster_legacy_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 97fe79bf371074b77d22e1e820903fb2103d10c9 */ + * Stub hash: c9bfd7de5c930c9d7190139e207eb6025e33bdb2 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster___construct, 0, 0, 1) ZEND_ARG_INFO(0, name) @@ -507,6 +507,11 @@ ZEND_END_ARG_INFO() #define arginfo_class_RedisCluster_sinter arginfo_class_RedisCluster_del +ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_sintercard, 0, 0, 1) + ZEND_ARG_INFO(0, keys) + ZEND_ARG_INFO(0, limit) +ZEND_END_ARG_INFO() + #define arginfo_class_RedisCluster_sinterstore arginfo_class_RedisCluster_sdiffstore #define arginfo_class_RedisCluster_sismember arginfo_class_RedisCluster__prefix @@ -673,6 +678,8 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_zinterstore, 0, 0, 2) ZEND_ARG_INFO(0, aggregate) ZEND_END_ARG_INFO() +#define arginfo_class_RedisCluster_zintercard arginfo_class_RedisCluster_sintercard + ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_zlexcount, 0, 0, 3) ZEND_ARG_INFO(0, key) ZEND_ARG_INFO(0, min) @@ -861,6 +868,7 @@ ZEND_METHOD(RedisCluster, setnx); ZEND_METHOD(RedisCluster, setoption); ZEND_METHOD(RedisCluster, setrange); ZEND_METHOD(RedisCluster, sinter); +ZEND_METHOD(RedisCluster, sintercard); ZEND_METHOD(RedisCluster, sinterstore); ZEND_METHOD(RedisCluster, sismember); ZEND_METHOD(RedisCluster, slowlog); @@ -900,6 +908,7 @@ ZEND_METHOD(RedisCluster, zcard); ZEND_METHOD(RedisCluster, zcount); ZEND_METHOD(RedisCluster, zincrby); ZEND_METHOD(RedisCluster, zinterstore); +ZEND_METHOD(RedisCluster, zintercard); ZEND_METHOD(RedisCluster, zlexcount); ZEND_METHOD(RedisCluster, zpopmax); ZEND_METHOD(RedisCluster, zpopmin); @@ -1055,6 +1064,7 @@ static const zend_function_entry class_RedisCluster_methods[] = { ZEND_ME(RedisCluster, setoption, arginfo_class_RedisCluster_setoption, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, setrange, arginfo_class_RedisCluster_setrange, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, sinter, arginfo_class_RedisCluster_sinter, ZEND_ACC_PUBLIC) + ZEND_ME(RedisCluster, sintercard, arginfo_class_RedisCluster_sintercard, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, sinterstore, arginfo_class_RedisCluster_sinterstore, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, sismember, arginfo_class_RedisCluster_sismember, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, slowlog, arginfo_class_RedisCluster_slowlog, ZEND_ACC_PUBLIC) @@ -1094,6 +1104,7 @@ static const zend_function_entry class_RedisCluster_methods[] = { ZEND_ME(RedisCluster, zcount, arginfo_class_RedisCluster_zcount, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, zincrby, arginfo_class_RedisCluster_zincrby, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, zinterstore, arginfo_class_RedisCluster_zinterstore, ZEND_ACC_PUBLIC) + ZEND_ME(RedisCluster, zintercard, arginfo_class_RedisCluster_zintercard, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, zlexcount, arginfo_class_RedisCluster_zlexcount, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, zpopmax, arginfo_class_RedisCluster_zpopmax, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, zpopmin, arginfo_class_RedisCluster_zpopmin, ZEND_ACC_PUBLIC) diff --git a/redis_commands.c b/redis_commands.c index 3db45146..1db729a6 100644 --- a/redis_commands.c +++ b/redis_commands.c @@ -841,6 +841,63 @@ static int redis_cmd_append_sstr_score(smart_string *dst, zval *score) { return FAILURE; } +int redis_intercard_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, + char *kw, char **cmd, int *cmd_len, short *slot, + void **ctx) +{ + smart_string cmdstr = {0}; + zend_long limit = -1; + HashTable *keys; + zend_string *key; + zval *zv; + + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_ARRAY_HT(keys) + Z_PARAM_OPTIONAL + Z_PARAM_LONG(limit) + ZEND_PARSE_PARAMETERS_END_EX(return FAILURE); + + if (zend_hash_num_elements(keys) == 0) { + php_error_docref(NULL, E_WARNING, "Must pass at least one key"); + return FAILURE; + } else if (ZEND_NUM_ARGS() == 2 && limit < 0) { + php_error_docref(NULL, E_WARNING, "LIMIT cannot be negative"); + return FAILURE; + } + + redis_cmd_init_sstr(&cmdstr, 1 + zend_hash_num_elements(keys) + (limit > 0 ? 2 : 0), kw, strlen(kw)); + redis_cmd_append_sstr_long(&cmdstr, zend_hash_num_elements(keys)); + + if (slot) *slot = -1; + + ZEND_HASH_FOREACH_VAL(keys, zv) { + key = redis_key_prefix_zval(redis_sock, zv); + + if (slot) { + if (*slot == -1) { + *slot = cluster_hash_key_zstr(key); + } else if (*slot != cluster_hash_key_zstr(key)) { + php_error_docref(NULL, E_WARNING, "All keys don't hash to the same slot"); + efree(cmdstr.c); + zend_string_release(key); + return FAILURE; + } + } + + redis_cmd_append_sstr_zstr(&cmdstr, key); + zend_string_release(key); + } ZEND_HASH_FOREACH_END(); + + if (limit > 0) { + REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "LIMIT"); + redis_cmd_append_sstr_long(&cmdstr, limit); + } + + *cmd = cmdstr.c; + *cmd_len = cmdstr.len; + return SUCCESS; +} + int redis_zinterunion_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, char *kw, char **cmd, int *cmd_len, short *slot, diff --git a/redis_commands.h b/redis_commands.h index 662d0500..24fbe92c 100644 --- a/redis_commands.h +++ b/redis_commands.h @@ -125,6 +125,10 @@ int redis_zdiffstore_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_intercard_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, char *kw, char **cmd, int *cmd_len, short *slot, void **ctx); diff --git a/redis_legacy_arginfo.h b/redis_legacy_arginfo.h index 1d7673e6..aaf02d19 100644 --- a/redis_legacy_arginfo.h +++ b/redis_legacy_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 122b5ca534302a09a4f072106d097f2831ba6f22 */ + * Stub hash: f43a528bc5874c419161b5eb874537fbe9c00e87 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis___construct, 0, 0, 0) ZEND_ARG_INFO(0, options) @@ -552,6 +552,11 @@ ZEND_END_ARG_INFO() #define arginfo_class_Redis_sInter arginfo_class_Redis_del +ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_sintercard, 0, 0, 1) + ZEND_ARG_INFO(0, keys) + ZEND_ARG_INFO(0, limit) +ZEND_END_ARG_INFO() + #define arginfo_class_Redis_sInterStore arginfo_class_Redis_sDiffStore #define arginfo_class_Redis_sMembers arginfo_class_Redis__prefix @@ -863,6 +868,8 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_zinter, 0, 0, 1) ZEND_ARG_INFO(0, options) ZEND_END_ARG_INFO() +#define arginfo_class_Redis_zintercard arginfo_class_Redis_sintercard + ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_zinterstore, 0, 0, 2) ZEND_ARG_INFO(0, dst) ZEND_ARG_INFO(0, keys) @@ -1022,6 +1029,7 @@ ZEND_METHOD(Redis, sAddArray); ZEND_METHOD(Redis, sDiff); ZEND_METHOD(Redis, sDiffStore); ZEND_METHOD(Redis, sInter); +ZEND_METHOD(Redis, sintercard); ZEND_METHOD(Redis, sInterStore); ZEND_METHOD(Redis, sMembers); ZEND_METHOD(Redis, sMisMember); @@ -1101,6 +1109,7 @@ ZEND_METHOD(Redis, zScore); ZEND_METHOD(Redis, zdiff); ZEND_METHOD(Redis, zdiffstore); ZEND_METHOD(Redis, zinter); +ZEND_METHOD(Redis, zintercard); ZEND_METHOD(Redis, zinterstore); ZEND_METHOD(Redis, zscan); ZEND_METHOD(Redis, zunion); @@ -1256,6 +1265,7 @@ static const zend_function_entry class_Redis_methods[] = { ZEND_ME(Redis, sDiff, arginfo_class_Redis_sDiff, ZEND_ACC_PUBLIC) ZEND_ME(Redis, sDiffStore, arginfo_class_Redis_sDiffStore, ZEND_ACC_PUBLIC) ZEND_ME(Redis, sInter, arginfo_class_Redis_sInter, ZEND_ACC_PUBLIC) + ZEND_ME(Redis, sintercard, arginfo_class_Redis_sintercard, ZEND_ACC_PUBLIC) ZEND_ME(Redis, sInterStore, arginfo_class_Redis_sInterStore, ZEND_ACC_PUBLIC) ZEND_ME(Redis, sMembers, arginfo_class_Redis_sMembers, ZEND_ACC_PUBLIC) ZEND_ME(Redis, sMisMember, arginfo_class_Redis_sMisMember, ZEND_ACC_PUBLIC) @@ -1335,6 +1345,7 @@ static const zend_function_entry class_Redis_methods[] = { ZEND_ME(Redis, zdiff, arginfo_class_Redis_zdiff, ZEND_ACC_PUBLIC) ZEND_ME(Redis, zdiffstore, arginfo_class_Redis_zdiffstore, ZEND_ACC_PUBLIC) ZEND_ME(Redis, zinter, arginfo_class_Redis_zinter, ZEND_ACC_PUBLIC) + ZEND_ME(Redis, zintercard, arginfo_class_Redis_zintercard, ZEND_ACC_PUBLIC) ZEND_ME(Redis, zinterstore, arginfo_class_Redis_zinterstore, ZEND_ACC_PUBLIC) ZEND_ME(Redis, zscan, arginfo_class_Redis_zscan, ZEND_ACC_PUBLIC) ZEND_ME(Redis, zunion, arginfo_class_Redis_zunion, ZEND_ACC_PUBLIC) diff --git a/tests/RedisTest.php b/tests/RedisTest.php index 6c04c9d0..551c6346 100644 --- a/tests/RedisTest.php +++ b/tests/RedisTest.php @@ -1948,6 +1948,55 @@ class Redis_Test extends TestSuite $this->assertTrue($count === 0); } + public function testInterCard() { + if(version_compare($this->version, "7.0.0") < 0) { + $this->markTestSkipped(); + } + + $set_data = [ + ['aardvark', 'dog', 'fish', 'squirrel', 'tiger'], + ['bear', 'coyote', 'fish', 'gorilla', 'dog'] + ]; + + $ssets = $zsets = []; + + foreach ($set_data as $n => $values) { + $sset = "s{set}:$n"; + $zset = "z{set}:$n"; + + $this->redis->del([$sset, $zset]); + + $ssets[] = $sset; + $zsets[] = $zset; + + foreach ($values as $score => $value) { + $this->assertEquals(1, $this->redis->sAdd("s{set}:$n", $value)); + $this->assertEquals(1, $this->redis->zAdd("z{set}:$n", $score, $value)); + } + } + + $exp = count(array_intersect(...$set_data)); + + $act = $this->redis->sintercard($ssets); + $this->assertEquals($exp, $act); + $act = $this->redis->zintercard($zsets); + $this->assertEquals($exp, $act); + + $this->assertEquals(1, $this->redis->sintercard($ssets, 1)); + $this->assertEquals(2, $this->redis->sintercard($ssets, 2)); + + $this->assertEquals(1, $this->redis->zintercard($zsets, 1)); + $this->assertEquals(2, $this->redis->zintercard($zsets, 2)); + + $this->assertFalse(@$this->redis->sintercard($ssets, -1)); + $this->assertFalse(@$this->redis->zintercard($ssets, -1)); + + $this->assertFalse(@$this->redis->sintercard([])); + $this->assertFalse(@$this->redis->zintercard([])); + + $this->redis->del(array_merge($ssets, $zsets)); + } + public function testlrange() { $this->redis->del('list'); $this->redis->lPush('list', 'val'); |