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:
-rw-r--r--cluster_library.c112
-rw-r--r--cluster_library.h4
-rw-r--r--common.h2
-rw-r--r--library.c62
-rw-r--r--library.h2
-rw-r--r--redis.c1
-rw-r--r--redis_commands.c6
-rw-r--r--tests/RedisClusterTest.php20
-rw-r--r--tests/RedisTest.php46
9 files changed, 181 insertions, 74 deletions
diff --git a/cluster_library.c b/cluster_library.c
index 3720f72c..5bcd2338 100644
--- a/cluster_library.c
+++ b/cluster_library.c
@@ -61,7 +61,7 @@ static void dump_reply(clusterReply *reply, int indent) {
smart_string_appendl(&buf, "\"", 1);
break;
case TYPE_MULTIBULK:
- if (reply->elements == (size_t)-1) {
+ if (reply->elements < 0) {
smart_string_appendl(&buf, "(nil)", sizeof("(nil)")-1);
} else {
for (i = 0; i < reply->elements; i++) {
@@ -91,7 +91,7 @@ static void dump_reply(clusterReply *reply, int indent) {
/* Recursively free our reply object. If free_data is non-zero we'll also free
* the payload data (strings) themselves. If not, we just free the structs */
void cluster_free_reply(clusterReply *reply, int free_data) {
- int i;
+ long long i;
switch(reply->type) {
case TYPE_ERR:
@@ -101,10 +101,14 @@ void cluster_free_reply(clusterReply *reply, int free_data) {
efree(reply->str);
break;
case TYPE_MULTIBULK:
- for (i = 0; i < reply->elements && reply->element[i]; i++) {
- cluster_free_reply(reply->element[i], free_data);
+ if (reply->element) {
+ if (reply->elements > 0) {
+ for (i = 0; i < reply->elements && reply->element[i]; i++) {
+ cluster_free_reply(reply->element[i], free_data);
+ }
+ }
+ efree(reply->element);
}
- if (reply->element) efree(reply->element);
break;
default:
break;
@@ -154,13 +158,11 @@ cluster_multibulk_resp_recursive(RedisSock *sock, size_t elements,
}
break;
case TYPE_MULTIBULK:
- if (r->len >= 0) {
- r->elements = r->len;
- if (r->len > 0) {
- r->element = ecalloc(r->len,sizeof(clusterReply*));
- if (cluster_multibulk_resp_recursive(sock, r->elements, r->element, status_strings) < 0) {
- return FAILURE;
- }
+ r->elements = r->len;
+ if (r->elements > 0) {
+ r->element = ecalloc(r->len, sizeof(*r->element));
+ if (cluster_multibulk_resp_recursive(sock, r->elements, r->element, status_strings) < 0) {
+ return FAILURE;
}
}
break;
@@ -204,7 +206,7 @@ clusterReply *cluster_read_resp(redisCluster *c, int status_strings) {
* command and consumed the reply type and meta info (length) */
clusterReply*
cluster_read_sock_resp(RedisSock *redis_sock, REDIS_REPLY_TYPE type,
- char *line_reply, size_t len)
+ char *line_reply, long long len)
{
clusterReply *r;
@@ -232,7 +234,7 @@ cluster_read_sock_resp(RedisSock *redis_sock, REDIS_REPLY_TYPE type,
break;
case TYPE_MULTIBULK:
r->elements = len;
- if (len != (size_t)-1) {
+ if (r->elements > 0) {
r->element = ecalloc(len, sizeof(clusterReply*));
if (cluster_multibulk_resp_recursive(redis_sock, len, r->element, line_reply != NULL) < 0) {
cluster_free_reply(r, 1);
@@ -241,7 +243,7 @@ cluster_read_sock_resp(RedisSock *redis_sock, REDIS_REPLY_TYPE type,
}
break;
default:
- cluster_free_reply(r,1);
+ cluster_free_reply(r, 1);
return NULL;
}
@@ -1939,10 +1941,11 @@ PHP_REDIS_API void cluster_unsub_resp(INTERNAL_FUNCTION_PARAMETERS,
}
/* Recursive MULTI BULK -> PHP style response handling */
-static void cluster_mbulk_variant_resp(clusterReply *r, zval *z_ret)
+static void cluster_mbulk_variant_resp(clusterReply *r, int null_mbulk_as_null,
+ zval *z_ret)
{
zval z_sub_ele;
- int i;
+ long long i;
switch(r->type) {
case TYPE_INT:
@@ -1963,11 +1966,15 @@ static void cluster_mbulk_variant_resp(clusterReply *r, zval *z_ret)
}
break;
case TYPE_MULTIBULK:
- array_init(&z_sub_ele);
- for (i = 0; i < r->elements; i++) {
- cluster_mbulk_variant_resp(r->element[i], &z_sub_ele);
+ if (r->elements < 0 && null_mbulk_as_null) {
+ add_next_index_null(z_ret);
+ } else {
+ array_init(&z_sub_ele);
+ for (i = 0; i < r->elements; i++) {
+ cluster_mbulk_variant_resp(r->element[i], null_mbulk_as_null, &z_sub_ele);
+ }
+ add_next_index_zval(z_ret, &z_sub_ele);
}
- add_next_index_zval(z_ret, &z_sub_ele);
break;
default:
add_next_index_bool(z_ret, 0);
@@ -1983,7 +1990,7 @@ cluster_variant_resp_generic(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
{
clusterReply *r;
zval zv, *z_arr = &zv;
- int i;
+ long long i;
// Make sure we can read it
if ((r = cluster_read_resp(c, status_strings)) == NULL) {
@@ -2014,12 +2021,15 @@ cluster_variant_resp_generic(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
}
break;
case TYPE_MULTIBULK:
- array_init(z_arr);
-
- for (i = 0; i < r->elements; i++) {
- cluster_mbulk_variant_resp(r->element[i], z_arr);
+ if (r->elements < 0 && c->flags->null_mbulk_as_null) {
+ RETVAL_NULL();
+ } else {
+ array_init(z_arr);
+ for (i = 0; i < r->elements; i++) {
+ cluster_mbulk_variant_resp(r->element[i], c->flags->null_mbulk_as_null, z_arr);
+ }
+ RETVAL_ZVAL(z_arr, 0, 0);
}
- RETVAL_ZVAL(z_arr, 0, 0);
break;
default:
RETVAL_FALSE;
@@ -2048,7 +2058,11 @@ cluster_variant_resp_generic(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
}
break;
case TYPE_MULTIBULK:
- cluster_mbulk_variant_resp(r, &c->multi_resp);
+ if (r->elements < 0 && c->flags->null_mbulk_as_null) {
+ add_next_index_null(&c->multi_resp);
+ } else {
+ cluster_mbulk_variant_resp(r, c->flags->null_mbulk_as_null, &c->multi_resp);
+ }
break;
default:
add_next_index_bool(&c->multi_resp, 0);
@@ -2069,7 +2083,8 @@ PHP_REDIS_API void cluster_variant_resp(INTERNAL_FUNCTION_PARAMETERS, redisClust
PHP_REDIS_API void cluster_variant_raw_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx)
{
- cluster_variant_resp_generic(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, c->flags->reply_literal, ctx);
+ cluster_variant_resp_generic(INTERNAL_FUNCTION_PARAM_PASSTHRU, c,
+ c->flags->reply_literal, ctx);
}
PHP_REDIS_API void cluster_variant_resp_strings(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
@@ -2084,23 +2099,25 @@ PHP_REDIS_API void cluster_gen_mbulk_resp(INTERNAL_FUNCTION_PARAMETERS,
{
zval z_result;
- /* Return FALSE if we didn't get a multi-bulk response */
- if (c->reply_type != TYPE_MULTIBULK) {
+ /* Abort if the reply isn't MULTIBULK or has an invalid length */
+ if (c->reply_type != TYPE_MULTIBULK || c->reply_len < -1) {
CLUSTER_RETURN_FALSE(c);
}
- /* Allocate our array */
- array_init(&z_result);
+ if (c->reply_len == -1 && c->flags->null_mbulk_as_null) {
+ ZVAL_NULL(&z_result);
+ } else {
+ array_init(&z_result);
- /* Consume replies as long as there are more than zero */
- if (c->reply_len > 0) {
- /* Push serialization settings from the cluster into our socket */
- c->cmd_sock->serializer = c->flags->serializer;
+ if (c->reply_len > 0) {
+ /* Push serialization settings from the cluster into our socket */
+ c->cmd_sock->serializer = c->flags->serializer;
- /* Call our specified callback */
- if (cb(c->cmd_sock, &z_result, c->reply_len, ctx) == FAILURE) {
- zval_dtor(&z_result);
- CLUSTER_RETURN_FALSE(c);
+ /* Call our specified callback */
+ if (cb(c->cmd_sock, &z_result, c->reply_len, ctx) == FAILURE) {
+ zval_dtor(&z_result);
+ CLUSTER_RETURN_FALSE(c);
+ }
}
}
@@ -2245,14 +2262,17 @@ PHP_REDIS_API void
cluster_xread_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx) {
zval z_streams;
- array_init(&z_streams);
-
c->cmd_sock->serializer = c->flags->serializer;
c->cmd_sock->compression = c->flags->compression;
- if (redis_read_stream_messages_multi(c->cmd_sock, c->reply_len, &z_streams) < 0) {
- zval_dtor(&z_streams);
- CLUSTER_RETURN_FALSE(c);
+ if (c->reply_len == -1 && c->flags->null_mbulk_as_null) {
+ ZVAL_NULL(&z_streams);
+ } else {
+ array_init(&z_streams);
+ if (redis_read_stream_messages_multi(c->cmd_sock, c->reply_len, &z_streams) < 0) {
+ zval_dtor(&z_streams);
+ CLUSTER_RETURN_FALSE(c);
+ }
}
if (CLUSTER_IS_ATOMIC(c)) {
diff --git a/cluster_library.h b/cluster_library.h
index 98e9b0ec..f8f1eec8 100644
--- a/cluster_library.h
+++ b/cluster_library.h
@@ -325,14 +325,14 @@ typedef struct clusterReply {
size_t integer; /* Integer reply */
long long len; /* Length of our string */
char *str; /* String reply */
- size_t elements; /* Count of array elements */
+ long long elements; /* Count of array elements */
struct clusterReply **element; /* Array elements */
} clusterReply;
/* Direct variant response handler */
clusterReply *cluster_read_resp(redisCluster *c, int status_strings);
clusterReply *cluster_read_sock_resp(RedisSock *redis_sock,
- REDIS_REPLY_TYPE type, char *line_reply, size_t reply_len);
+ REDIS_REPLY_TYPE type, char *line_reply, long long reply_len);
void cluster_free_reply(clusterReply *reply, int free_data);
/* Cluster distribution helpers for WATCH */
diff --git a/common.h b/common.h
index dda14366..80b34e65 100644
--- a/common.h
+++ b/common.h
@@ -82,6 +82,7 @@ typedef enum _PUBSUB_TYPE {
#define REDIS_OPT_COMPRESSION 7
#define REDIS_OPT_REPLY_LITERAL 8
#define REDIS_OPT_COMPRESSION_LEVEL 9
+#define REDIS_OPT_NULL_MBULK_AS_NULL 10
/* cluster options */
#define REDIS_FAILOVER_NONE 0
@@ -296,6 +297,7 @@ typedef struct {
int readonly;
int reply_literal;
+ int null_mbulk_as_null;
int tcp_keepalive;
} RedisSock;
/* }}} */
diff --git a/library.c b/library.c
index 6aef6274..2648c565 100644
--- a/library.c
+++ b/library.c
@@ -1600,10 +1600,13 @@ redis_xread_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
if (read_mbulk_header(redis_sock, &streams) < 0)
goto failure;
- array_init(&z_rv);
-
- if (redis_read_stream_messages_multi(redis_sock, streams, &z_rv) < 0)
- goto cleanup;
+ if (streams == -1 && redis_sock->null_mbulk_as_null) {
+ ZVAL_NULL(&z_rv);
+ } else {
+ array_init(&z_rv);
+ if (redis_read_stream_messages_multi(redis_sock, streams, &z_rv) < 0)
+ goto cleanup;
+ }
if (IS_ATOMIC(redis_sock)) {
RETVAL_ZVAL(&z_rv, 0, 1);
@@ -2427,6 +2430,7 @@ PHP_REDIS_API int redis_sock_read_multibulk_reply(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock, zval *z_tab,
void *ctx)
{
+ zval z_multi_result;
char inbuf[4096];
int numElems;
size_t len;
@@ -2448,10 +2452,13 @@ PHP_REDIS_API int redis_sock_read_multibulk_reply(INTERNAL_FUNCTION_PARAMETERS,
}
numElems = atoi(inbuf+1);
- zval z_multi_result;
- array_init(&z_multi_result); /* pre-allocate array for multi's results. */
- redis_mbulk_reply_loop(redis_sock, &z_multi_result, numElems, UNSERIALIZE_ALL);
+ if (numElems == -1 && redis_sock->null_mbulk_as_null) {
+ ZVAL_NULL(&z_multi_result);
+ } else {
+ array_init(&z_multi_result);
+ redis_mbulk_reply_loop(redis_sock, &z_multi_result, numElems, UNSERIALIZE_ALL);
+ }
if (IS_ATOMIC(redis_sock)) {
RETVAL_ZVAL(&z_multi_result, 0, 1);
@@ -2459,7 +2466,6 @@ PHP_REDIS_API int redis_sock_read_multibulk_reply(INTERNAL_FUNCTION_PARAMETERS,
add_next_index_zval(z_tab, &z_multi_result);
}
- /*zval_copy_ctor(return_value); */
return 0;
}
@@ -3231,7 +3237,7 @@ redis_read_variant_bulk(RedisSock *redis_sock, int size, zval *z_ret
}
PHP_REDIS_API int
-redis_read_multibulk_recursive(RedisSock *redis_sock, int elements, int status_strings,
+redis_read_multibulk_recursive(RedisSock *redis_sock, long long elements, int status_strings,
zval *z_ret)
{
long reply_info;
@@ -3267,11 +3273,15 @@ redis_read_multibulk_recursive(RedisSock *redis_sock, int elements, int status_s
add_next_index_zval(z_ret, &z_subelem);
break;
case TYPE_MULTIBULK:
- // Construct an array for our sub element, and add it, and recurse
- array_init(&z_subelem);
- add_next_index_zval(z_ret, &z_subelem);
- redis_read_multibulk_recursive(redis_sock, reply_info, status_strings,
- &z_subelem);
+ if (reply_info < 0 && redis_sock->null_mbulk_as_null) {
+ add_next_index_null(z_ret);
+ } else {
+ array_init(&z_subelem);
+ if (reply_info > 0) {
+ redis_read_multibulk_recursive(redis_sock, reply_info, status_strings, &z_subelem);
+ }
+ add_next_index_zval(z_ret, &z_subelem);
+ }
break;
default:
// Stop the compiler from whinging
@@ -3287,7 +3297,8 @@ redis_read_multibulk_recursive(RedisSock *redis_sock, int elements, int status_s
static int
variant_reply_generic(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
- int status_strings, zval *z_tab, void *ctx)
+ int status_strings, int null_mbulk_as_null,
+ zval *z_tab, void *ctx)
{
// Reply type, and reply size vars
REDIS_REPLY_TYPE reply_type;
@@ -3312,13 +3323,15 @@ variant_reply_generic(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
redis_read_variant_bulk(redis_sock, reply_info, &z_ret);
break;
case TYPE_MULTIBULK:
- /* Initialize an array for our multi-bulk response */
- array_init(&z_ret);
-
- // If we've got more than zero elements, parse our multi bulk
- // response recursively
if (reply_info > -1) {
+ array_init(&z_ret);
redis_read_multibulk_recursive(redis_sock, reply_info, status_strings, &z_ret);
+ } else {
+ if (null_mbulk_as_null) {
+ ZVAL_NULL(&z_ret);
+ } else {
+ array_init(&z_ret);
+ }
}
break;
default:
@@ -3343,21 +3356,24 @@ redis_read_raw_variant_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock
zval *z_tab, void *ctx)
{
return variant_reply_generic(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock,
- redis_sock->reply_literal, z_tab, ctx);
+ redis_sock->reply_literal,
+ redis_sock->null_mbulk_as_null,
+ z_tab, ctx);
}
PHP_REDIS_API int
redis_read_variant_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
zval *z_tab, void *ctx)
{
- return variant_reply_generic(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, 0, z_tab, ctx);
+ return variant_reply_generic(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, 0,
+ redis_sock->null_mbulk_as_null, z_tab, ctx);
}
PHP_REDIS_API int
redis_read_variant_reply_strings(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
zval *z_tab, void *ctx)
{
- return variant_reply_generic(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, 1, z_tab, ctx);
+ return variant_reply_generic(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, 1, 0, z_tab, ctx);
}
PHP_REDIS_API
diff --git a/library.h b/library.h
index da73b34d..db47545d 100644
--- a/library.h
+++ b/library.h
@@ -144,7 +144,7 @@ PHP_REDIS_API int redis_acl_log_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *r
PHP_REDIS_API int redis_read_reply_type(RedisSock *redis_sock, REDIS_REPLY_TYPE *reply_type, long *reply_info);
PHP_REDIS_API int redis_read_variant_bulk(RedisSock *redis_sock, int size, zval *z_ret);
-PHP_REDIS_API int redis_read_multibulk_recursive(RedisSock *redis_sock, int elements, int status_strings, zval *z_ret);
+PHP_REDIS_API int redis_read_multibulk_recursive(RedisSock *redis_sock, long long elements, int status_strings, zval *z_ret);
PHP_REDIS_API int redis_read_variant_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_read_raw_variant_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_read_variant_reply_strings(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
diff --git a/redis.c b/redis.c
index 585a5161..821e8bcb 100644
--- a/redis.c
+++ b/redis.c
@@ -713,6 +713,7 @@ static void add_class_constants(zend_class_entry *ce, int is_cluster) {
zend_declare_class_constant_long(ce, ZEND_STRL("OPT_COMPRESSION"), REDIS_OPT_COMPRESSION);
zend_declare_class_constant_long(ce, ZEND_STRL("OPT_REPLY_LITERAL"), REDIS_OPT_REPLY_LITERAL);
zend_declare_class_constant_long(ce, ZEND_STRL("OPT_COMPRESSION_LEVEL"), REDIS_OPT_COMPRESSION_LEVEL);
+ zend_declare_class_constant_long(ce, ZEND_STRL("OPT_NULL_MULTIBULK_AS_NULL"), REDIS_OPT_NULL_MBULK_AS_NULL);
/* serializer */
zend_declare_class_constant_long(ce, ZEND_STRL("SERIALIZER_NONE"), REDIS_SERIALIZER_NONE);
diff --git a/redis_commands.c b/redis_commands.c
index d6bb2bcf..07f409c7 100644
--- a/redis_commands.c
+++ b/redis_commands.c
@@ -3996,6 +3996,8 @@ void redis_getoption_handler(INTERNAL_FUNCTION_PARAMETERS,
RETURN_LONG(redis_sock->scan);
case REDIS_OPT_REPLY_LITERAL:
RETURN_LONG(redis_sock->reply_literal);
+ case REDIS_OPT_NULL_MBULK_AS_NULL:
+ RETURN_LONG(redis_sock->null_mbulk_as_null);
case REDIS_OPT_FAILOVER:
RETURN_LONG(c->failover);
default:
@@ -4040,6 +4042,10 @@ void redis_setoption_handler(INTERNAL_FUNCTION_PARAMETERS,
val_long = zval_get_long(val);
redis_sock->reply_literal = val_long != 0;
RETURN_TRUE;
+ case REDIS_OPT_NULL_MBULK_AS_NULL:
+ val_long = zval_get_long(val);
+ redis_sock->null_mbulk_as_null = val_long != 0;
+ RETURN_TRUE;
case REDIS_OPT_COMPRESSION:
val_long = zval_get_long(val);
if (val_long == REDIS_COMPRESSION_NONE
diff --git a/tests/RedisClusterTest.php b/tests/RedisClusterTest.php
index 0da0904c..a1baf90d 100644
--- a/tests/RedisClusterTest.php
+++ b/tests/RedisClusterTest.php
@@ -751,5 +751,25 @@ class Redis_Cluster_Test extends Redis_Test {
return 'seed[]=' . $host;
}, self::$_arr_node_map)) . ($auth ? "&$auth" : '');
}
+
+ /* Test correct handling of null multibulk replies */
+ public function testNullArray() {
+ $key = "key:arr";
+ $this->redis->del($key);
+
+ foreach ([false => [], true => NULL] as $opt => $test) {
+ $this->redis->setOption(Redis::OPT_NULL_MULTIBULK_AS_NULL, $opt);
+
+ $r = $this->redis->rawCommand($key, "BLPOP", $key, .05);
+ $this->assertEquals($test, $r);
+
+ $this->redis->multi();
+ $this->redis->rawCommand($key, "BLPOP", $key, .05);
+ $r = $this->redis->exec();
+ $this->assertEquals([$test], $r);
+ }
+
+ $this->redis->setOption(Redis::OPT_NULL_MULTIBULK_AS_NULL, false);
+ }
}
?>
diff --git a/tests/RedisTest.php b/tests/RedisTest.php
index 3c848853..781fb0ea 100644
--- a/tests/RedisTest.php
+++ b/tests/RedisTest.php
@@ -935,8 +935,15 @@ class Redis_Test extends TestSuite
// blocking blpop, brpop
$this->redis->del('list');
- $this->assertTrue($this->redis->blPop(['list'], 1) === []);
- $this->assertTrue($this->redis->brPop(['list'], 1) === []);
+
+ /* Also test our option that we want *-1 to be returned as NULL */
+ foreach ([false => [], true => NULL] as $opt => $val) {
+ $this->redis->setOption(Redis::OPT_NULL_MULTIBULK_AS_NULL, $opt);
+ $this->assertEquals($val, $this->redis->blPop(['list'], 1));
+ $this->assertEquals($val, $this->redis->brPop(['list'], 1));
+ }
+
+ $this->redis->setOption(Redis::OPT_NULL_MULTIBULK_AS_NULL, false);
}
public function testllen()
@@ -4952,6 +4959,41 @@ class Redis_Test extends TestSuite
$this->redis->setOption(Redis::OPT_REPLY_LITERAL, false);
}
+ public function testNullArray() {
+ $key = "key:arr";
+ $this->redis->del($key);
+
+ foreach ([false => [], true => NULL] as $opt => $test) {
+ $this->redis->setOption(Redis::OPT_NULL_MULTIBULK_AS_NULL, $opt);
+
+ $r = $this->redis->rawCommand("BLPOP", $key, .05);
+ $this->assertEquals($test, $r);
+
+ $this->redis->multi();
+ $this->redis->rawCommand("BLPOP", $key, .05);
+ $r = $this->redis->exec();
+ $this->assertEquals([$test], $r);
+ }
+
+ $this->redis->setOption(Redis::OPT_NULL_MULTIBULK_AS_NULL, false);
+ }
+
+ /* Test that we can configure PhpRedis to return NULL for *-1 even nestedwithin replies */
+ public function testNestedNullArray() {
+ $this->redis->del('{notaset}');
+
+ foreach ([false => [], true => NULL] as $opt => $test) {
+ $this->redis->setOption(Redis::OPT_NULL_MULTIBULK_AS_NULL, $opt);
+ $this->assertEquals([$test, $test], $this->redis->geoPos('{notaset}', 'm1', 'm2'));
+
+ $this->redis->multi();
+ $this->redis->geoPos('{notaset}', 'm1', 'm2');
+ $this->assertEquals([[$test, $test]], $this->redis->exec());
+ }
+
+ $this->redis->setOption(Redis::OPT_NULL_MULTIBULK_AS_NULL, false);
+ }
+
public function testReconnectSelect() {
$key = 'reconnect-select';
$value = 'Has been set!';