From 9036ffca6adf0b5c8b2f4b08d9552b6d38a4bc33 Mon Sep 17 00:00:00 2001 From: Pavlo Yatsukhnenko Date: Thu, 30 Jan 2025 20:15:00 +0200 Subject: [PATCH] Add getWithMeta method --- cluster_library.c | 39 ++++++++++++++---------- cluster_library.h | 2 ++ common.h | 7 +++++ library.c | 55 +++++++++++++++++++++------------- library.h | 1 + redis.c | 35 ++++++++++++++++++---- redis.stub.php | 10 +++++++ redis_arginfo.h | 18 ++++++----- redis_cluster.c | 20 +++++++++++-- redis_cluster.h | 1 + redis_cluster.stub.php | 5 ++++ redis_cluster_arginfo.h | 18 ++++++----- redis_cluster_legacy_arginfo.h | 6 +++- redis_legacy_arginfo.h | 6 +++- tests/RedisClusterTest.php | 15 ++++++++++ tests/RedisTest.php | 16 ++++++++++ 16 files changed, 195 insertions(+), 59 deletions(-) diff --git a/cluster_library.c b/cluster_library.c index e919e2b..45a60e2 100644 --- a/cluster_library.c +++ b/cluster_library.c @@ -1677,27 +1677,33 @@ PHP_REDIS_API void cluster_bulk_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster void *ctx) { char *resp; + zval z_unpacked, z_ret, *zv; // Make sure we can read the response - if (c->reply_type != TYPE_BULK || - (resp = redis_sock_read_bulk_reply(c->cmd_sock, c->reply_len)) == NULL) - { - CLUSTER_RETURN_FALSE(c); + if (c->reply_type != TYPE_BULK) { + ZVAL_FALSE(&z_unpacked); + c->reply_len = 0; + } else if ((resp = redis_sock_read_bulk_reply(c->cmd_sock, c->reply_len)) == NULL) { + ZVAL_FALSE(&z_unpacked); + } else { + if (!redis_unpack(c->flags, resp, c->reply_len, &z_unpacked)) { + ZVAL_STRINGL_FAST(&z_unpacked, resp, c->reply_len); + } + efree(resp); + } + + if (c->flags->flags & PHPREDIS_WITH_METADATA) { + redis_with_metadata(&z_ret, &z_unpacked, c->reply_len); + zv = &z_ret; + } else { + zv = &z_unpacked; } if (CLUSTER_IS_ATOMIC(c)) { - if (!redis_unpack(c->flags, resp, c->reply_len, return_value)) { - CLUSTER_RETURN_STRING(c, resp, c->reply_len); - } + RETVAL_ZVAL(zv, 0, 1); } else { - zval z_unpacked; - if (redis_unpack(c->flags, resp, c->reply_len, &z_unpacked)) { - add_next_index_zval(&c->multi_resp, &z_unpacked); - } else { - add_next_index_stringl(&c->multi_resp, resp, c->reply_len); - } + add_next_index_zval(&c->multi_resp, zv); } - efree(resp); } /* Bulk response where we expect a double */ @@ -2553,8 +2559,9 @@ PHP_REDIS_API void cluster_multi_mbulk_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx) { zval *multi_resp = &c->multi_resp; - array_init(multi_resp); + uint8_t flags = c->flags->flags; + array_init(multi_resp); clusterFoldItem *fi = c->multi_head; while (fi) { /* Make sure our transaction didn't fail here */ @@ -2570,7 +2577,9 @@ PHP_REDIS_API void cluster_multi_mbulk_resp(INTERNAL_FUNCTION_PARAMETERS, RETURN_FALSE; } + c->flags->flags = fi->flags; fi->callback(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, fi->ctx); + c->flags->flags = flags; } else { /* Just add false */ add_next_index_bool(multi_resp, 0); diff --git a/cluster_library.h b/cluster_library.h index cef7e75..3adfaf0 100644 --- a/cluster_library.h +++ b/cluster_library.h @@ -264,6 +264,8 @@ struct clusterFoldItem { /* Next item in our list */ struct clusterFoldItem *next; + + uint8_t flags; }; /* Key and value container, with info if they need freeing */ diff --git a/common.h b/common.h index c1ed664..5720f8d 100644 --- a/common.h +++ b/common.h @@ -152,6 +152,7 @@ typedef enum { #define PIPELINE 2 #define PHPREDIS_DEBUG_LOGGING 0 +#define PHPREDIS_WITH_METADATA 1 #if PHP_VERSION_ID < 80000 #define Z_PARAM_ARRAY_HT_OR_NULL(dest) \ @@ -184,6 +185,7 @@ typedef enum { #define REDIS_SAVE_CALLBACK(callback, closure_context) do { \ fold_item *fi = redis_add_reply_callback(redis_sock); \ fi->fun = callback; \ + fi->flags = redis_sock->flags; \ fi->ctx = closure_context; \ } while (0) @@ -266,6 +268,9 @@ static inline int redis_strncmp(const char *s1, const char *s2, size_t n) { #define REDIS_ENABLE_MODE(redis_sock, m) (redis_sock->mode |= m) #define REDIS_DISABLE_MODE(redis_sock, m) (redis_sock->mode &= ~m) +#define REDIS_ENABLE_FLAG(redis_sock, f) (redis_sock->flags |= f) +#define REDIS_DISABLE_FLAG(redis_sock, f) (redis_sock->flags &= ~f) + /* HOST_NAME_MAX doesn't exist everywhere */ #ifndef HOST_NAME_MAX #if defined(_POSIX_HOST_NAME_MAX) @@ -325,6 +330,7 @@ typedef struct { int sentinel; size_t txBytes; size_t rxBytes; + uint8_t flags; } RedisSock; /* }}} */ @@ -334,6 +340,7 @@ typedef int (*FailableResultCallback)(INTERNAL_FUNCTION_PARAMETERS, RedisSock*, typedef struct fold_item { FailableResultCallback fun; + uint8_t flags; void *ctx; } fold_item; diff --git a/library.c b/library.c index 35883ff..0520278 100644 --- a/library.c +++ b/library.c @@ -2669,32 +2669,34 @@ PHP_REDIS_API int redis_string_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock char *response; int response_len; + zval z_unpacked, z_ret, *zv; + zend_bool ret; - if ((response = redis_sock_read(redis_sock, &response_len)) - == NULL) - { - if (IS_ATOMIC(redis_sock)) { - RETVAL_FALSE; - } else { - add_next_index_bool(z_tab, 0); - } - return FAILURE; - } - if (IS_ATOMIC(redis_sock)) { - if (!redis_unpack(redis_sock, response, response_len, return_value)) { - RETVAL_STRINGL_FAST(response, response_len); - } + if ((response = redis_sock_read(redis_sock, &response_len)) == NULL) { + ZVAL_FALSE(&z_unpacked); + ret = FAILURE; } else { - zval z_unpacked; - if (redis_unpack(redis_sock, response, response_len, &z_unpacked)) { - add_next_index_zval(z_tab, &z_unpacked); - } else { - redis_add_next_index_stringl(z_tab, response, response_len); + if (!redis_unpack(redis_sock, response, response_len, &z_unpacked)) { + ZVAL_STRINGL_FAST(&z_unpacked, response, response_len); } + efree(response); + ret = SUCCESS; } - efree(response); - return SUCCESS; + if (redis_sock->flags & PHPREDIS_WITH_METADATA) { + redis_with_metadata(&z_ret, &z_unpacked, response_len); + zv = &z_ret; + } else { + zv = &z_unpacked; + } + + if (IS_ATOMIC(redis_sock)) { + RETVAL_ZVAL(zv, 0, 1); + } else { + add_next_index_zval(z_tab, zv); + } + + return ret; } /* like string response, but never unserialized. */ @@ -4455,6 +4457,17 @@ int redis_extract_auth_info(zval *ztest, zend_string **user, zend_string **pass) return FAILURE; } +PHP_REDIS_API void redis_with_metadata(zval *zdst, zval *zsrc, zend_long length) { + zval z_sub; + + array_init(zdst); + add_next_index_zval(zdst, zsrc); + + array_init(&z_sub); + add_assoc_long_ex(&z_sub, ZEND_STRL("length"), length); + add_next_index_zval(zdst, &z_sub); +} + /* Helper methods to extract configuration settings from a hash table */ zval *redis_hash_str_find_type(HashTable *ht, const char *key, int keylen, int type) { diff --git a/library.h b/library.h index 47c339a..2706941 100644 --- a/library.h +++ b/library.h @@ -44,6 +44,7 @@ fold_item* redis_add_reply_callback(RedisSock *redis_sock); void redis_free_reply_callbacks(RedisSock *redis_sock); PHP_REDIS_API int redis_extract_auth_info(zval *ztest, zend_string **user, zend_string **pass); +PHP_REDIS_API void redis_with_metadata(zval *zdst, zval *zsrc, zend_long length); int redis_cmd_init_sstr(smart_string *str, int num_args, char *keyword, int keyword_len); int redis_cmd_append_sstr(smart_string *str, char *append, int append_len); diff --git a/redis.c b/redis.c index 4ec516c..d049989 100644 --- a/redis.c +++ b/redis.c @@ -760,11 +760,32 @@ PHP_METHOD(Redis, reset) } /* }}} */ +static void +redis_get_passthru(INTERNAL_FUNCTION_PARAMETERS) +{ + REDIS_PROCESS_KW_CMD("GET", redis_key_cmd, redis_string_response); +} + /* {{{ proto string Redis::get(string key) */ PHP_METHOD(Redis, get) { - REDIS_PROCESS_KW_CMD("GET", redis_key_cmd, redis_string_response); + redis_get_passthru(INTERNAL_FUNCTION_PARAM_PASSTHRU); +} +/* }}} */ + +/* {{{ proto Redis|array|false Redis::getWithMeta(string key) + */ +PHP_METHOD(Redis, getWithMeta) +{ + RedisSock *redis_sock; + if ((redis_sock = redis_sock_get_instance(getThis(), 0)) == NULL) { + RETURN_FALSE; + } + + REDIS_ENABLE_FLAG(redis_sock, PHPREDIS_WITH_METADATA); + redis_get_passthru(INTERNAL_FUNCTION_PARAM_PASSTHRU); + REDIS_DISABLE_FLAG(redis_sock, PHPREDIS_WITH_METADATA); } /* }}} */ @@ -2067,13 +2088,17 @@ PHP_REDIS_API int redis_sock_read_multibulk_multi_reply_loop(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab) { - fold_item fi; + fold_item *fi; + uint8_t flags; size_t i; + flags = redis_sock->flags; for (i = 0; i < redis_sock->reply_callback_count; i++) { - fi = redis_sock->reply_callback[i]; - if (fi.fun) { - fi.fun(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, fi.ctx); + fi = &redis_sock->reply_callback[i]; + if (fi->fun) { + redis_sock->flags = fi->flags; + fi->fun(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, fi->ctx); + redis_sock->flags = flags; continue; } size_t len; diff --git a/redis.stub.php b/redis.stub.php index 8d0b765..5f2e769 100644 --- a/redis.stub.php +++ b/redis.stub.php @@ -1467,6 +1467,16 @@ class Redis { */ public function get(string $key): mixed; + /** + * Retrieve a value and metadata of key. + * + * @param string $key The key to query + * @return Redis|array|false + * + * @example $redis->getWithMeta('foo'); + */ + public function getWithMeta(string $key): Redis|array|false; + /** * Get the authentication information on the connection, if any. * diff --git a/redis_arginfo.h b/redis_arginfo.h index 072e1fb..e880450 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: 3c4051fdd9f860523bcd72aba260b1af823d1d9c */ + * Stub hash: 6dd5a9e9d1d5ed8a78e248c99352232e30046f28 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis___construct, 0, 0, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "null") @@ -323,6 +323,10 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_get, 0, 1, IS_MIXED, ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_getWithMeta, 0, 1, Redis, MAY_BE_ARRAY|MAY_BE_FALSE) + ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_getAuth, 0, 0, IS_MIXED, 0) ZEND_END_ARG_INFO() @@ -404,9 +408,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_hGet, 0, 2, IS_MIXED ZEND_ARG_TYPE_INFO(0, member, IS_STRING, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_hGetAll, 0, 1, Redis, MAY_BE_ARRAY|MAY_BE_FALSE) - ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0) -ZEND_END_ARG_INFO() +#define arginfo_class_Redis_hGetAll arginfo_class_Redis_getWithMeta ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_hIncrBy, 0, 3, Redis, MAY_BE_LONG|MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0) @@ -420,7 +422,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_hIncrByFloat, 0, ZEND_ARG_TYPE_INFO(0, value, IS_DOUBLE, 0) ZEND_END_ARG_INFO() -#define arginfo_class_Redis_hKeys arginfo_class_Redis_hGetAll +#define arginfo_class_Redis_hKeys arginfo_class_Redis_getWithMeta #define arginfo_class_Redis_hLen arginfo_class_Redis_expiretime @@ -455,7 +457,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_hStrLen, 0, 2, R ZEND_ARG_TYPE_INFO(0, field, IS_STRING, 0) ZEND_END_ARG_INFO() -#define arginfo_class_Redis_hVals arginfo_class_Redis_hGetAll +#define arginfo_class_Redis_hVals arginfo_class_Redis_getWithMeta ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_hscan, 0, 2, Redis, MAY_BE_ARRAY|MAY_BE_BOOL) ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0) @@ -747,7 +749,7 @@ ZEND_END_ARG_INFO() #define arginfo_class_Redis_sInterStore arginfo_class_Redis_del -#define arginfo_class_Redis_sMembers arginfo_class_Redis_hGetAll +#define arginfo_class_Redis_sMembers arginfo_class_Redis_getWithMeta #define arginfo_class_Redis_sMisMember arginfo_class_Redis_geohash @@ -1249,6 +1251,7 @@ ZEND_METHOD(Redis, georadiusbymember_ro); ZEND_METHOD(Redis, geosearch); ZEND_METHOD(Redis, geosearchstore); ZEND_METHOD(Redis, get); +ZEND_METHOD(Redis, getWithMeta); ZEND_METHOD(Redis, getAuth); ZEND_METHOD(Redis, getBit); ZEND_METHOD(Redis, getEx); @@ -1507,6 +1510,7 @@ static const zend_function_entry class_Redis_methods[] = { ZEND_ME(Redis, geosearch, arginfo_class_Redis_geosearch, ZEND_ACC_PUBLIC) ZEND_ME(Redis, geosearchstore, arginfo_class_Redis_geosearchstore, ZEND_ACC_PUBLIC) ZEND_ME(Redis, get, arginfo_class_Redis_get, ZEND_ACC_PUBLIC) + ZEND_ME(Redis, getWithMeta, arginfo_class_Redis_getWithMeta, ZEND_ACC_PUBLIC) ZEND_ME(Redis, getAuth, arginfo_class_Redis_getAuth, ZEND_ACC_PUBLIC) ZEND_ME(Redis, getBit, arginfo_class_Redis_getBit, ZEND_ACC_PUBLIC) ZEND_ME(Redis, getEx, arginfo_class_Redis_getEx, ZEND_ACC_PUBLIC) diff --git a/redis_cluster.c b/redis_cluster.c index 1106a42..ee11f25 100644 --- a/redis_cluster.c +++ b/redis_cluster.c @@ -275,12 +275,28 @@ PHP_METHOD(RedisCluster, close) { RETURN_TRUE; } -/* {{{ proto string RedisCluster::get(string key) */ -PHP_METHOD(RedisCluster, get) { +static void +cluster_get_passthru(INTERNAL_FUNCTION_PARAMETERS) +{ CLUSTER_PROCESS_KW_CMD("GET", redis_key_cmd, cluster_bulk_resp, 1); } + +/* {{{ proto string RedisCluster::get(string key) */ +PHP_METHOD(RedisCluster, get) { + cluster_get_passthru(INTERNAL_FUNCTION_PARAM_PASSTHRU); +} /* }}} */ +/* {{{ proto array|false RedisCluster::getWithMeta(string key) */ +PHP_METHOD(RedisCluster, getWithMeta) { + redisCluster *c = GET_CONTEXT(); + REDIS_ENABLE_FLAG(c->flags, PHPREDIS_WITH_METADATA); + cluster_get_passthru(INTERNAL_FUNCTION_PARAM_PASSTHRU); + REDIS_DISABLE_FLAG(c->flags, PHPREDIS_WITH_METADATA); +} +/* }}} */ + + /* {{{ proto bool RedisCluster::set(string key, string value) */ PHP_METHOD(RedisCluster, set) { CLUSTER_PROCESS_CMD(set, cluster_set_resp, 0); diff --git a/redis_cluster.h b/redis_cluster.h index ebef921..49e1bcd 100644 --- a/redis_cluster.h +++ b/redis_cluster.h @@ -22,6 +22,7 @@ _item->slot = slot; \ _item->ctx = ctx; \ _item->next = NULL; \ + _item->flags = c->flags->flags; \ if(c->multi_head == NULL) { \ c->multi_head = _item; \ c->multi_curr = _item; \ diff --git a/redis_cluster.stub.php b/redis_cluster.stub.php index d5cab71..56c91f4 100644 --- a/redis_cluster.stub.php +++ b/redis_cluster.stub.php @@ -390,6 +390,11 @@ class RedisCluster { */ public function get(string $key): mixed; + /** + * @see Redis::getWithMeta + */ + public function getWithMeta(string $key): RedisCluster|array|false; + /** * @see Redis::getEx */ diff --git a/redis_cluster_arginfo.h b/redis_cluster_arginfo.h index 8507932..b182584 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: b9310b607794caa862d509ba316a2a512d2736fe */ + * Stub hash: 5966b99fd578eca94880e09539542edfbcbcdaed */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 1) @@ -325,6 +325,10 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_get, 0, 1, IS ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_getWithMeta, 0, 1, RedisCluster, MAY_BE_ARRAY|MAY_BE_FALSE) + ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_getex, 0, 1, RedisCluster, MAY_BE_STRING|MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 0, "[]") @@ -379,9 +383,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_hget, 0, 2, I ZEND_ARG_TYPE_INFO(0, member, IS_STRING, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_hgetall, 0, 1, RedisCluster, MAY_BE_ARRAY|MAY_BE_FALSE) - ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0) -ZEND_END_ARG_INFO() +#define arginfo_class_RedisCluster_hgetall arginfo_class_RedisCluster_getWithMeta ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_hincrby, 0, 3, RedisCluster, MAY_BE_LONG|MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0) @@ -395,7 +397,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_hincrbyfl ZEND_ARG_TYPE_INFO(0, value, IS_DOUBLE, 0) ZEND_END_ARG_INFO() -#define arginfo_class_RedisCluster_hkeys arginfo_class_RedisCluster_hgetall +#define arginfo_class_RedisCluster_hkeys arginfo_class_RedisCluster_getWithMeta #define arginfo_class_RedisCluster_hlen arginfo_class_RedisCluster_expiretime @@ -451,7 +453,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_hstrlen, ZEND_ARG_TYPE_INFO(0, field, IS_STRING, 0) ZEND_END_ARG_INFO() -#define arginfo_class_RedisCluster_hvals arginfo_class_RedisCluster_hgetall +#define arginfo_class_RedisCluster_hvals arginfo_class_RedisCluster_getWithMeta #define arginfo_class_RedisCluster_incr arginfo_class_RedisCluster_decr @@ -754,7 +756,7 @@ ZEND_END_ARG_INFO() #define arginfo_class_RedisCluster_slowlog arginfo_class_RedisCluster_script -#define arginfo_class_RedisCluster_smembers arginfo_class_RedisCluster_hgetall +#define arginfo_class_RedisCluster_smembers arginfo_class_RedisCluster_getWithMeta ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_smove, 0, 3, RedisCluster, MAY_BE_BOOL) ZEND_ARG_TYPE_INFO(0, src, IS_STRING, 0) @@ -1127,6 +1129,7 @@ ZEND_METHOD(RedisCluster, georadiusbymember_ro); ZEND_METHOD(RedisCluster, geosearch); ZEND_METHOD(RedisCluster, geosearchstore); ZEND_METHOD(RedisCluster, get); +ZEND_METHOD(RedisCluster, getWithMeta); ZEND_METHOD(RedisCluster, getex); ZEND_METHOD(RedisCluster, getbit); ZEND_METHOD(RedisCluster, getlasterror); @@ -1356,6 +1359,7 @@ static const zend_function_entry class_RedisCluster_methods[] = { ZEND_ME(RedisCluster, geosearch, arginfo_class_RedisCluster_geosearch, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, geosearchstore, arginfo_class_RedisCluster_geosearchstore, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, get, arginfo_class_RedisCluster_get, ZEND_ACC_PUBLIC) + ZEND_ME(RedisCluster, getWithMeta, arginfo_class_RedisCluster_getWithMeta, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, getex, arginfo_class_RedisCluster_getex, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, getbit, arginfo_class_RedisCluster_getbit, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, getlasterror, arginfo_class_RedisCluster_getlasterror, ZEND_ACC_PUBLIC) diff --git a/redis_cluster_legacy_arginfo.h b/redis_cluster_legacy_arginfo.h index 64d6951..99edcca 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: b9310b607794caa862d509ba316a2a512d2736fe */ + * Stub hash: 5966b99fd578eca94880e09539542edfbcbcdaed */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster___construct, 0, 0, 1) ZEND_ARG_INFO(0, name) @@ -295,6 +295,8 @@ ZEND_END_ARG_INFO() #define arginfo_class_RedisCluster_get arginfo_class_RedisCluster__prefix +#define arginfo_class_RedisCluster_getWithMeta arginfo_class_RedisCluster__prefix + ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_getex, 0, 0, 1) ZEND_ARG_INFO(0, key) ZEND_ARG_INFO(0, options) @@ -969,6 +971,7 @@ ZEND_METHOD(RedisCluster, georadiusbymember_ro); ZEND_METHOD(RedisCluster, geosearch); ZEND_METHOD(RedisCluster, geosearchstore); ZEND_METHOD(RedisCluster, get); +ZEND_METHOD(RedisCluster, getWithMeta); ZEND_METHOD(RedisCluster, getex); ZEND_METHOD(RedisCluster, getbit); ZEND_METHOD(RedisCluster, getlasterror); @@ -1198,6 +1201,7 @@ static const zend_function_entry class_RedisCluster_methods[] = { ZEND_ME(RedisCluster, geosearch, arginfo_class_RedisCluster_geosearch, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, geosearchstore, arginfo_class_RedisCluster_geosearchstore, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, get, arginfo_class_RedisCluster_get, ZEND_ACC_PUBLIC) + ZEND_ME(RedisCluster, getWithMeta, arginfo_class_RedisCluster_getWithMeta, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, getex, arginfo_class_RedisCluster_getex, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, getbit, arginfo_class_RedisCluster_getbit, ZEND_ACC_PUBLIC) ZEND_ME(RedisCluster, getlasterror, arginfo_class_RedisCluster_getlasterror, ZEND_ACC_PUBLIC) diff --git a/redis_legacy_arginfo.h b/redis_legacy_arginfo.h index 27f0c44..4fd45c7 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: 3c4051fdd9f860523bcd72aba260b1af823d1d9c */ + * Stub hash: 6dd5a9e9d1d5ed8a78e248c99352232e30046f28 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis___construct, 0, 0, 0) ZEND_ARG_INFO(0, options) @@ -301,6 +301,8 @@ ZEND_END_ARG_INFO() #define arginfo_class_Redis_get arginfo_class_Redis__prefix +#define arginfo_class_Redis_getWithMeta arginfo_class_Redis__prefix + #define arginfo_class_Redis_getAuth arginfo_class_Redis___destruct ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_getBit, 0, 0, 2) @@ -1092,6 +1094,7 @@ ZEND_METHOD(Redis, georadiusbymember_ro); ZEND_METHOD(Redis, geosearch); ZEND_METHOD(Redis, geosearchstore); ZEND_METHOD(Redis, get); +ZEND_METHOD(Redis, getWithMeta); ZEND_METHOD(Redis, getAuth); ZEND_METHOD(Redis, getBit); ZEND_METHOD(Redis, getEx); @@ -1350,6 +1353,7 @@ static const zend_function_entry class_Redis_methods[] = { ZEND_ME(Redis, geosearch, arginfo_class_Redis_geosearch, ZEND_ACC_PUBLIC) ZEND_ME(Redis, geosearchstore, arginfo_class_Redis_geosearchstore, ZEND_ACC_PUBLIC) ZEND_ME(Redis, get, arginfo_class_Redis_get, ZEND_ACC_PUBLIC) + ZEND_ME(Redis, getWithMeta, arginfo_class_Redis_getWithMeta, ZEND_ACC_PUBLIC) ZEND_ME(Redis, getAuth, arginfo_class_Redis_getAuth, ZEND_ACC_PUBLIC) ZEND_ME(Redis, getBit, arginfo_class_Redis_getBit, ZEND_ACC_PUBLIC) ZEND_ME(Redis, getEx, arginfo_class_Redis_getEx, ZEND_ACC_PUBLIC) diff --git a/tests/RedisClusterTest.php b/tests/RedisClusterTest.php index 1be83c2..7cea87f 100644 --- a/tests/RedisClusterTest.php +++ b/tests/RedisClusterTest.php @@ -248,6 +248,21 @@ class Redis_Cluster_Test extends Redis_Test { $this->assertTrue($this->redis->client($key, 'kill', $addr)); } + public function testGetWithMeta() { + $this->redis->del('key'); + $this->assertFalse($this->redis->get('key')); + $this->assertEquals([false, ['length' => -1]], $this->redis->getWithMeta('key')); + + $this->assertEquals([true, ['value', ['length' => strlen('value')]]], $this->redis->multi()->set('key', 'value')->getWithMeta('key')->exec()); + + $serializer = $this->redis->getOption(Redis::OPT_SERIALIZER); + $this->redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_PHP); + $this->assertTrue($this->redis->set('key', false)); + $this->assertEquals([false, ['length' => strlen(serialize(false))]], $this->redis->getWithMeta('key')); + $this->assertFalse($this->redis->get('key')); + $this->redis->setOption(Redis::OPT_SERIALIZER, $serializer); + } + public function testTime() { [$sec, $usec] = $this->redis->time(uniqid()); $this->assertEquals(strval(intval($sec)), strval($sec)); diff --git a/tests/RedisTest.php b/tests/RedisTest.php index 3b46622..93a106c 100644 --- a/tests/RedisTest.php +++ b/tests/RedisTest.php @@ -5800,6 +5800,22 @@ class Redis_Test extends TestSuite { $this->redis->setOption(Redis::OPT_COMPRESSION, $oldcmp); } + public function testGetWithMeta() { + $this->redis->del('key'); + $this->assertFalse($this->redis->get('key')); + $this->assertEquals([false, ['length' => -1]], $this->redis->getWithMeta('key')); + + $this->assertEquals([false, [false, ['length' => -1]]], $this->redis->pipeline()->get('key')->getWithMeta('key')->exec()); + $this->assertEquals([true, ['value', ['length' => strlen('value')]]], $this->redis->multi()->set('key', 'value')->getWithMeta('key')->exec()); + + $serializer = $this->redis->getOption(Redis::OPT_SERIALIZER); + $this->redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_PHP); + $this->assertTrue($this->redis->set('key', false)); + $this->assertEquals([false, ['length' => strlen(serialize(false))]], $this->redis->getWithMeta('key')); + $this->assertFalse($this->redis->get('key')); + $this->redis->setOption(Redis::OPT_SERIALIZER, $serializer); + } + public function testPrefix() { // no prefix $this->redis->setOption(Redis::OPT_PREFIX, '');