Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit fa5d1af

Browse files
Implement GEOSEARCH and GEOSEARCHSTORE for RedisCluster. (#2277)
* Implement GEOSEARCH and GEOSEARCHSTORE for RedisCluster. See #1894
1 parent 7121aaa commit fa5d1af

11 files changed

Lines changed: 158 additions & 50 deletions

cluster_library.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1776,6 +1776,24 @@ cluster_lpos_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx)
17761776
}
17771777
}
17781778

1779+
PHP_REDIS_API void
1780+
cluster_geosearch_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx) {
1781+
zval zret = {0};
1782+
1783+
c->cmd_sock->null_mbulk_as_null = c->flags->null_mbulk_as_null;
1784+
if (c->reply_type != TYPE_MULTIBULK ||
1785+
redis_read_geosearch_response(&zret, c->cmd_sock, c->reply_len, ctx != NULL) < 0)
1786+
{
1787+
ZVAL_FALSE(&zret);
1788+
}
1789+
1790+
if (CLUSTER_IS_ATOMIC(c)) {
1791+
RETVAL_ZVAL(&zret, 0, 1);
1792+
} else {
1793+
add_next_index_zval(&c->multi_resp, &zret);
1794+
}
1795+
}
1796+
17791797
PHP_REDIS_API void
17801798
cluster_set_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx)
17811799
{

cluster_library.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,8 @@ PHP_REDIS_API void cluster_lpos_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster
414414
void *ctx);
415415
PHP_REDIS_API void cluster_set_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
416416
void *ctx);
417+
PHP_REDIS_API void cluster_geosearch_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
418+
void *ctx);
417419
PHP_REDIS_API void cluster_single_line_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
418420
void *ctx);
419421
PHP_REDIS_API void cluster_bulk_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,

library.c

Lines changed: 62 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1781,64 +1781,85 @@ redis_mpop_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
17811781
return res;
17821782
}
17831783

1784+
#if PHP_VERSION_ID < 80200
1785+
static HashTable *zend_array_to_list(HashTable *arr) {
1786+
zval zret = {0}, *zv;
1787+
1788+
array_init_size(&zret, zend_hash_num_elements(arr));
1789+
1790+
ZEND_HASH_FOREACH_VAL(arr, zv) {
1791+
Z_TRY_ADDREF_P(zv);
1792+
add_next_index_zval(&zret, zv);
1793+
} ZEND_HASH_FOREACH_END();
1794+
1795+
return Z_ARRVAL(zret);
1796+
}
1797+
#endif
1798+
17841799
PHP_REDIS_API int
1785-
redis_geosearch_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
1786-
zval *z_tab, void *ctx)
1800+
redis_read_geosearch_response(zval *zdst, RedisSock *redis_sock,
1801+
long long elements, int with_aux_data)
17871802
{
1788-
int numElems;
1789-
zval z_ret, z_multi_result, z_sub, z_tmp, *z_ele, *zv;
1803+
zval z_multi_result, z_sub, *z_ele, *zv;
17901804
zend_string *zkey;
17911805

1792-
if (read_mbulk_header(redis_sock, &numElems) < 0) {
1793-
if (IS_ATOMIC(redis_sock)) {
1794-
RETVAL_FALSE;
1795-
} else {
1796-
add_next_index_bool(z_tab, 0);
1797-
}
1798-
return FAILURE;
1806+
/* Handle the trivial "empty" result first */
1807+
if (elements < 0 && redis_sock->null_mbulk_as_null) {
1808+
ZVAL_NULL(zdst);
1809+
return SUCCESS;
17991810
}
18001811

1801-
if (numElems < 0 && redis_sock->null_mbulk_as_null) {
1802-
ZVAL_NULL(&z_ret);
1812+
array_init(zdst);
1813+
1814+
if (with_aux_data == 0) {
1815+
redis_mbulk_reply_loop(redis_sock, zdst, elements, UNSERIALIZE_NONE);
18031816
} else {
1804-
array_init(&z_ret);
1805-
if (ctx == NULL) {
1806-
redis_mbulk_reply_loop(redis_sock, &z_ret, numElems, UNSERIALIZE_NONE);
1807-
} else {
1808-
array_init(&z_multi_result);
1809-
redis_read_multibulk_recursive(redis_sock, numElems, 0, &z_multi_result);
1817+
array_init(&z_multi_result);
18101818

1811-
ZEND_HASH_FOREACH_VAL(Z_ARRVAL(z_multi_result), z_ele) {
1812-
// The first item in the sub-array is always the name of the returned item
1813-
zv = zend_hash_index_find(Z_ARRVAL_P(z_ele), 0);
1814-
zkey = zval_get_string(zv);
1819+
redis_read_multibulk_recursive(redis_sock, elements, 0, &z_multi_result);
18151820

1816-
zend_hash_index_del(Z_ARRVAL_P(z_ele), 0);
1821+
ZEND_HASH_FOREACH_VAL(Z_ARRVAL(z_multi_result), z_ele) {
1822+
// The first item in the sub-array is always the name of the returned item
1823+
zv = zend_hash_index_find(Z_ARRVAL_P(z_ele), 0);
1824+
zkey = zval_get_string(zv);
18171825

1818-
// The other information is returned in the following order as successive
1819-
// elements of the sub-array: distance, geohash, coordinates
1820-
zend_hash_apply(Z_ARRVAL_P(z_ele), geosearch_cast);
1826+
zend_hash_index_del(Z_ARRVAL_P(z_ele), 0);
18211827

1822-
// Copy values to re-order from zero
1823-
array_init(&z_sub);
1824-
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(z_ele), zv) {
1825-
ZVAL_ZVAL(&z_tmp, zv, 1, 0);
1826-
add_next_index_zval(&z_sub, &z_tmp);
1827-
} ZEND_HASH_FOREACH_END();
1828+
// The other information is returned in the following order as successive
1829+
// elements of the sub-array: distance, geohash, coordinates
1830+
zend_hash_apply(Z_ARRVAL_P(z_ele), geosearch_cast);
18281831

1829-
add_assoc_zval_ex(&z_ret, ZSTR_VAL(zkey), ZSTR_LEN(zkey), &z_sub);
1830-
zend_string_release(zkey);
1831-
} ZEND_HASH_FOREACH_END();
1832+
// Reindex elements so they start at zero */
1833+
ZVAL_ARR(&z_sub, zend_array_to_list(Z_ARRVAL_P(z_ele)));
18321834

1833-
// Cleanup
1834-
zval_dtor(&z_multi_result);
1835-
}
1835+
add_assoc_zval_ex(zdst, ZSTR_VAL(zkey), ZSTR_LEN(zkey), &z_sub);
1836+
zend_string_release(zkey);
1837+
} ZEND_HASH_FOREACH_END();
1838+
1839+
// Cleanup
1840+
zval_dtor(&z_multi_result);
1841+
}
1842+
1843+
return SUCCESS;
1844+
}
1845+
1846+
PHP_REDIS_API int
1847+
redis_geosearch_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
1848+
zval *z_tab, void *ctx)
1849+
{
1850+
zval zret = {0};
1851+
int elements;
1852+
1853+
if (read_mbulk_header(redis_sock, &elements) < 0 ||
1854+
redis_read_geosearch_response(&zret, redis_sock, elements, ctx != NULL) < 0)
1855+
{
1856+
ZVAL_FALSE(&zret);
18361857
}
18371858

18381859
if (IS_ATOMIC(redis_sock)) {
1839-
RETVAL_ZVAL(&z_ret, 0, 1);
1860+
RETVAL_ZVAL(&zret, 0, 1);
18401861
} else {
1841-
add_next_index_zval(z_tab, &z_ret);
1862+
add_next_index_zval(z_tab, &zret);
18421863
}
18431864

18441865
return SUCCESS;

library.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ PHP_REDIS_API int redis_client_list_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSoc
184184
PHP_REDIS_API int redis_zrandmember_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
185185
PHP_REDIS_API int redis_zdiff_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
186186
PHP_REDIS_API int redis_set_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
187+
PHP_REDIS_API int redis_read_geosearch_response(zval *zdst, RedisSock *redis_sock, long long elements, int with_aux_data);
187188
PHP_REDIS_API int redis_geosearch_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
188189
PHP_REDIS_API int redis_hrandfield_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
189190
PHP_REDIS_API int redis_pop_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);

redis_cluster.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2864,6 +2864,15 @@ PHP_METHOD(RedisCluster, georadiusbymember_ro) {
28642864
CLUSTER_PROCESS_KW_CMD("GEORADIUSBYMEMBER_RO", redis_georadiusbymember_cmd, cluster_variant_resp, 1);
28652865
}
28662866

2867+
PHP_METHOD(RedisCluster, geosearch) {
2868+
CLUSTER_PROCESS_CMD(geosearch, cluster_geosearch_resp, 1);
2869+
}
2870+
2871+
PHP_METHOD(RedisCluster, geosearchstore) {
2872+
CLUSTER_PROCESS_CMD(geosearchstore, cluster_long_resp, 0);
2873+
}
2874+
2875+
28672876
/* {{{ proto array RedisCluster::role(string key)
28682877
* proto array RedisCluster::role(array host_port) */
28692878
PHP_METHOD(RedisCluster, role) {

redis_cluster.stub.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,16 @@ public function georadiusbymember(string $key, string $member, float $radius, st
367367
*/
368368
public function georadiusbymember_ro(string $key, string $member, float $radius, string $unit, array $options = []): mixed;
369369

370+
/**
371+
* @see https://redis.io/commands/geosearch
372+
*/
373+
public function geosearch(string $key, array|string $position, array|int|float $shape, string $unit, array $options = []): RedisCluster|array;
374+
375+
/**
376+
* @see https://redis.io/commands/geosearchstore
377+
*/
378+
public function geosearchstore(string $dst, string $src, array|string $position, array|int|float $shape, string $unit, array $options = []): RedisCluster|array|int|false;
379+
370380
/**
371381
* @see Redis::get
372382
*/

redis_cluster_arginfo.h

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* This is a generated file, edit the .stub.php file instead.
2-
* Stub hash: 048afee969c189861f5ba0b8f8fb8cbeeba9a206 */
2+
* Stub hash: ed8ae1edcec62f211d6ba70e78b3c0f087b2cbde */
33

44
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster___construct, 0, 0, 1)
55
ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 1)
@@ -291,6 +291,23 @@ ZEND_END_ARG_INFO()
291291

292292
#define arginfo_class_RedisCluster_georadiusbymember_ro arginfo_class_RedisCluster_georadiusbymember
293293

294+
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_geosearch, 0, 4, RedisCluster, MAY_BE_ARRAY)
295+
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
296+
ZEND_ARG_TYPE_MASK(0, position, MAY_BE_ARRAY|MAY_BE_STRING, NULL)
297+
ZEND_ARG_TYPE_MASK(0, shape, MAY_BE_ARRAY|MAY_BE_LONG|MAY_BE_DOUBLE, NULL)
298+
ZEND_ARG_TYPE_INFO(0, unit, IS_STRING, 0)
299+
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 0, "[]")
300+
ZEND_END_ARG_INFO()
301+
302+
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_geosearchstore, 0, 5, RedisCluster, MAY_BE_ARRAY|MAY_BE_LONG|MAY_BE_FALSE)
303+
ZEND_ARG_TYPE_INFO(0, dst, IS_STRING, 0)
304+
ZEND_ARG_TYPE_INFO(0, src, IS_STRING, 0)
305+
ZEND_ARG_TYPE_MASK(0, position, MAY_BE_ARRAY|MAY_BE_STRING, NULL)
306+
ZEND_ARG_TYPE_MASK(0, shape, MAY_BE_ARRAY|MAY_BE_LONG|MAY_BE_DOUBLE, NULL)
307+
ZEND_ARG_TYPE_INFO(0, unit, IS_STRING, 0)
308+
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 0, "[]")
309+
ZEND_END_ARG_INFO()
310+
294311
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_get, 0, 1, IS_MIXED, 0)
295312
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
296313
ZEND_END_ARG_INFO()
@@ -1048,6 +1065,8 @@ ZEND_METHOD(RedisCluster, georadius);
10481065
ZEND_METHOD(RedisCluster, georadius_ro);
10491066
ZEND_METHOD(RedisCluster, georadiusbymember);
10501067
ZEND_METHOD(RedisCluster, georadiusbymember_ro);
1068+
ZEND_METHOD(RedisCluster, geosearch);
1069+
ZEND_METHOD(RedisCluster, geosearchstore);
10511070
ZEND_METHOD(RedisCluster, get);
10521071
ZEND_METHOD(RedisCluster, getbit);
10531072
ZEND_METHOD(RedisCluster, getlasterror);
@@ -1263,6 +1282,8 @@ static const zend_function_entry class_RedisCluster_methods[] = {
12631282
ZEND_ME(RedisCluster, georadius_ro, arginfo_class_RedisCluster_georadius_ro, ZEND_ACC_PUBLIC)
12641283
ZEND_ME(RedisCluster, georadiusbymember, arginfo_class_RedisCluster_georadiusbymember, ZEND_ACC_PUBLIC)
12651284
ZEND_ME(RedisCluster, georadiusbymember_ro, arginfo_class_RedisCluster_georadiusbymember_ro, ZEND_ACC_PUBLIC)
1285+
ZEND_ME(RedisCluster, geosearch, arginfo_class_RedisCluster_geosearch, ZEND_ACC_PUBLIC)
1286+
ZEND_ME(RedisCluster, geosearchstore, arginfo_class_RedisCluster_geosearchstore, ZEND_ACC_PUBLIC)
12661287
ZEND_ME(RedisCluster, get, arginfo_class_RedisCluster_get, ZEND_ACC_PUBLIC)
12671288
ZEND_ME(RedisCluster, getbit, arginfo_class_RedisCluster_getbit, ZEND_ACC_PUBLIC)
12681289
ZEND_ME(RedisCluster, getlasterror, arginfo_class_RedisCluster_getlasterror, ZEND_ACC_PUBLIC)

redis_cluster_legacy_arginfo.h

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* This is a generated file, edit the .stub.php file instead.
2-
* Stub hash: 048afee969c189861f5ba0b8f8fb8cbeeba9a206 */
2+
* Stub hash: ed8ae1edcec62f211d6ba70e78b3c0f087b2cbde */
33

44
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster___construct, 0, 0, 1)
55
ZEND_ARG_INFO(0, name)
@@ -263,6 +263,23 @@ ZEND_END_ARG_INFO()
263263

264264
#define arginfo_class_RedisCluster_georadiusbymember_ro arginfo_class_RedisCluster_georadiusbymember
265265

266+
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_geosearch, 0, 0, 4)
267+
ZEND_ARG_INFO(0, key)
268+
ZEND_ARG_INFO(0, position)
269+
ZEND_ARG_INFO(0, shape)
270+
ZEND_ARG_INFO(0, unit)
271+
ZEND_ARG_INFO(0, options)
272+
ZEND_END_ARG_INFO()
273+
274+
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_geosearchstore, 0, 0, 5)
275+
ZEND_ARG_INFO(0, dst)
276+
ZEND_ARG_INFO(0, src)
277+
ZEND_ARG_INFO(0, position)
278+
ZEND_ARG_INFO(0, shape)
279+
ZEND_ARG_INFO(0, unit)
280+
ZEND_ARG_INFO(0, options)
281+
ZEND_END_ARG_INFO()
282+
266283
#define arginfo_class_RedisCluster_get arginfo_class_RedisCluster__prefix
267284

268285
#define arginfo_class_RedisCluster_getbit arginfo_class_RedisCluster_append
@@ -895,6 +912,8 @@ ZEND_METHOD(RedisCluster, georadius);
895912
ZEND_METHOD(RedisCluster, georadius_ro);
896913
ZEND_METHOD(RedisCluster, georadiusbymember);
897914
ZEND_METHOD(RedisCluster, georadiusbymember_ro);
915+
ZEND_METHOD(RedisCluster, geosearch);
916+
ZEND_METHOD(RedisCluster, geosearchstore);
898917
ZEND_METHOD(RedisCluster, get);
899918
ZEND_METHOD(RedisCluster, getbit);
900919
ZEND_METHOD(RedisCluster, getlasterror);
@@ -1110,6 +1129,8 @@ static const zend_function_entry class_RedisCluster_methods[] = {
11101129
ZEND_ME(RedisCluster, georadius_ro, arginfo_class_RedisCluster_georadius_ro, ZEND_ACC_PUBLIC)
11111130
ZEND_ME(RedisCluster, georadiusbymember, arginfo_class_RedisCluster_georadiusbymember, ZEND_ACC_PUBLIC)
11121131
ZEND_ME(RedisCluster, georadiusbymember_ro, arginfo_class_RedisCluster_georadiusbymember_ro, ZEND_ACC_PUBLIC)
1132+
ZEND_ME(RedisCluster, geosearch, arginfo_class_RedisCluster_geosearch, ZEND_ACC_PUBLIC)
1133+
ZEND_ME(RedisCluster, geosearchstore, arginfo_class_RedisCluster_geosearchstore, ZEND_ACC_PUBLIC)
11131134
ZEND_ME(RedisCluster, get, arginfo_class_RedisCluster_get, ZEND_ACC_PUBLIC)
11141135
ZEND_ME(RedisCluster, getbit, arginfo_class_RedisCluster_getbit, ZEND_ACC_PUBLIC)
11151136
ZEND_ME(RedisCluster, getlasterror, arginfo_class_RedisCluster_getlasterror, ZEND_ACC_PUBLIC)

redis_commands.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1521,7 +1521,7 @@ int redis_subscribe_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
15211521
ZEND_HASH_FOREACH_VAL(ht_chan, z_chan) {
15221522
// We want to deal with strings here
15231523
zend_string *zstr = zval_get_string(z_chan);
1524-
1524+
15251525
// Grab channel name, prefix if required
15261526
key = ZSTR_VAL(zstr);
15271527
key_len = ZSTR_LEN(zstr);
@@ -4650,6 +4650,7 @@ redis_geosearchstore_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
46504650
smart_string cmdstr = {0};
46514651
zval *position, *shape, *opts = NULL, *z_ele;
46524652
zend_string *zkey;
4653+
short s2 = 0;
46534654

46544655
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sszzs|a",
46554656
&dest, &destlen, &src, &srclen, &position, &shape,
@@ -4708,7 +4709,13 @@ redis_geosearchstore_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
47084709

47094710
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, argc, "GEOSEARCHSTORE");
47104711
redis_cmd_append_sstr_key(&cmdstr, dest, destlen, redis_sock, slot);
4711-
redis_cmd_append_sstr_key(&cmdstr, src, srclen, redis_sock, slot);
4712+
redis_cmd_append_sstr_key(&cmdstr, src, srclen, redis_sock, slot ? &s2 : NULL);
4713+
4714+
if (slot && *slot != s2) {
4715+
php_error_docref(NULL, E_WARNING, "All keys must hash to the same slot");
4716+
efree(cmdstr.c);
4717+
return FAILURE;
4718+
}
47124719

47134720
if (Z_TYPE_P(position) == IS_ARRAY) {
47144721
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "FROMLONLAT");

tests/RedisClusterTest.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,6 @@ public function testzDiffStore() { return $this->markTestSkipped(); }
5858
public function testzMscore() { return $this->marktestSkipped(); }
5959
public function testZRandMember() { return $this->marktestSkipped(); }
6060
public function testCopy() { return $this->marktestSkipped(); }
61-
public function testGeoSearch() { return $this->marktestSkipped(); }
62-
public function testGeoSearchStore() { return $this->marktestSkipped(); }
6361
public function testHRandField() { return $this->marktestSkipped(); }
6462
public function testConfig() { return $this->markTestSkipped(); }
6563
public function testFlushDB() { return $this->markTestSkipped(); }

0 commit comments

Comments
 (0)