From 7b4861fc8e282843624ae1e34c2353151a73696f Mon Sep 17 00:00:00 2001 From: Pavlo Yatsukhnenko Date: Sat, 12 Nov 2022 13:06:24 +0200 Subject: [WIP] Refactor command --- library.c | 42 ++++++++++++++++++++++++ library.h | 1 + redis.c | 2 +- redis.stub.php | 2 +- redis_arginfo.h | 6 ++-- redis_commands.c | 89 ++++++++++++++++++++++---------------------------- redis_legacy_arginfo.h | 6 ++-- 7 files changed, 90 insertions(+), 58 deletions(-) diff --git a/library.c b/library.c index 1560e6b0..4bc52a88 100644 --- a/library.c +++ b/library.c @@ -1858,6 +1858,48 @@ redis_client_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval return redis_client_trackinginfo_reply(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL); } else { ZEND_ASSERT(!"memory corruption?"); + return FAILURE; + } +} + +static int +redis_command_info_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx) +{ + int numElems; + zval z_ret; + + if (read_mbulk_header(redis_sock, &numElems) < 0) { + if (IS_ATOMIC(redis_sock)) { + RETVAL_FALSE; + } else { + add_next_index_bool(z_tab, 0); + } + return FAILURE; + } + + array_init(&z_ret); + redis_read_multibulk_recursive(redis_sock, numElems, 0, &z_ret); + if (IS_ATOMIC(redis_sock)) { + RETVAL_ZVAL(&z_ret, 0, 1); + } else { + add_next_index_zval(z_tab, &z_ret); + } + + return SUCCESS; +} + +PHP_REDIS_API int +redis_command_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx) +{ + if (ctx == NULL) { + return redis_command_info_reply(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL); + } else if (ctx == PHPREDIS_CTX_PTR) { + return redis_long_response(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL); + } else if (ctx == PHPREDIS_CTX_PTR + 1) { + return redis_mbulk_reply_raw(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL); + } else { + ZEND_ASSERT(!"memory corruption?"); + return FAILURE; } } diff --git a/library.h b/library.h index c52b0f2f..d3ae8df5 100644 --- a/library.h +++ b/library.h @@ -187,6 +187,7 @@ PHP_REDIS_API int redis_hrandfield_response(INTERNAL_FUNCTION_PARAMETERS, RedisS PHP_REDIS_API int redis_pop_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx); PHP_REDIS_API int redis_lpos_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx); PHP_REDIS_API int redis_client_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx); +PHP_REDIS_API int redis_command_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx); /* Helper methods to get configuration values from a HashTable. */ diff --git a/redis.c b/redis.c index 2aef973d..d90a0689 100644 --- a/redis.c +++ b/redis.c @@ -3077,7 +3077,7 @@ PHP_METHOD(Redis, rawcommand) { * proto array Redis::command('info', string cmd) * proto array Redis::command('getkeys', array cmd_args) */ PHP_METHOD(Redis, command) { - REDIS_PROCESS_CMD(command, redis_read_variant_reply); + REDIS_PROCESS_CMD(command, redis_command_response); } /* }}} */ diff --git a/redis.stub.php b/redis.stub.php index 12f77301..66a2aa8a 100644 --- a/redis.stub.php +++ b/redis.stub.php @@ -434,7 +434,7 @@ class Redis { public function close(): bool; - public function command(string $opt = null, string|array $arg): mixed; + public function command(string $opt = null, mixed ...$args): mixed; /** * Execute the Redis CONFIG command in a variety of ways. What the command does in particular depends diff --git a/redis_arginfo.h b/redis_arginfo.h index a13002a1..bc3b8846 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: 42952974e3686f29934dfff1ebba07150942a405 */ + * Stub hash: babd74e96036b211b97579605f9739698de2e65d */ 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") @@ -120,9 +120,9 @@ ZEND_END_ARG_INFO() #define arginfo_class_Redis_close arginfo_class_Redis_clearLastError -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_command, 0, 2, IS_MIXED, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_command, 0, 0, IS_MIXED, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, opt, IS_STRING, 0, "null") - ZEND_ARG_TYPE_MASK(0, arg, MAY_BE_STRING|MAY_BE_ARRAY, NULL) + ZEND_ARG_VARIADIC_TYPE_INFO(0, args, IS_MIXED, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_config, 0, 1, IS_MIXED, 0) diff --git a/redis_commands.c b/redis_commands.c index e75b1892..899839ef 100644 --- a/redis_commands.c +++ b/redis_commands.c @@ -5245,63 +5245,52 @@ redis_client_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, int redis_command_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, char **cmd, int *cmd_len, short *slot, void **ctx) { - char *kw=NULL; - zval *z_arg; - size_t kw_len; - - /* Parse our args */ - if (zend_parse_parameters(ZEND_NUM_ARGS(), "|sz", &kw, &kw_len, - &z_arg) == FAILURE) - { - return FAILURE; - } + smart_string cmdstr = {0}; + zend_string *op = NULL, *zstr; + zval *z_args = NULL; + int i, argc = 0; - /* Construct our command */ - if (!kw) { - *cmd_len = REDIS_CMD_SPPRINTF(cmd, "COMMAND", ""); - } else if (!z_arg) { - /* Sanity check */ - if (strncasecmp(kw, "count", sizeof("count") - 1)) { - return FAILURE; - } - /* COMMAND COUNT */ - *cmd_len = REDIS_CMD_SPPRINTF(cmd, "COMMAND", "s", "COUNT", sizeof("COUNT") - 1); - } else if (Z_TYPE_P(z_arg) == IS_STRING) { - /* Sanity check */ - if (strncasecmp(kw, "info", sizeof("info") - 1)) { - return FAILURE; - } + ZEND_PARSE_PARAMETERS_START(0, -1) + Z_PARAM_OPTIONAL + Z_PARAM_STR(op) + Z_PARAM_VARIADIC('*', z_args, argc) + ZEND_PARSE_PARAMETERS_END_EX(return FAILURE); - /* COMMAND INFO */ - *cmd_len = REDIS_CMD_SPPRINTF(cmd, "COMMAND", "ss", "INFO", sizeof("INFO") - 1, - Z_STRVAL_P(z_arg), Z_STRLEN_P(z_arg)); + if (op == NULL) { + *ctx = NULL; + argc = 0; + } else if (zend_string_equals_literal_ci(op, "COUNT")) { + *ctx = PHPREDIS_CTX_PTR; + argc = 0; + } else if (zend_string_equals_literal_ci(op, "DOCS") || + zend_string_equals_literal_ci(op, "INFO") + ) { + *ctx = NULL; + } else if (zend_string_equals_literal_ci(op, "GETKEYS")) { + *ctx = PHPREDIS_CTX_PTR + 1; + } else if (zend_string_equals_literal_ci(op, "GETKEYSANDFLAGS")) { + *ctx = PHPREDIS_CTX_PTR + 2; + } else if (zend_string_equals_literal_ci(op, "LIST")) { + *ctx = PHPREDIS_CTX_PTR + 1; } else { - int arr_len; - - /* Sanity check on args */ - if (strncasecmp(kw, "getkeys", sizeof("getkeys")-1) || - Z_TYPE_P(z_arg)!=IS_ARRAY || - (arr_len=zend_hash_num_elements(Z_ARRVAL_P(z_arg)))<1) - { - return FAILURE; - } + php_error_docref(NULL, E_WARNING, "Unknown COMMAND operation '%s'", ZSTR_VAL(op)); + return FAILURE; + } - zval *z_ele; - HashTable *ht_arr = Z_ARRVAL_P(z_arg); - smart_string cmdstr = {0}; + REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, !!op + argc, "COMMAND"); + if (op) redis_cmd_append_sstr_zstr(&cmdstr, op); - redis_cmd_init_sstr(&cmdstr, 1 + arr_len, ZEND_STRL("COMMAND")); - redis_cmd_append_sstr(&cmdstr, ZEND_STRL("GETKEYS")); + for (i = 0; i < argc; ++i) { + zstr = zval_get_string(&z_args[i]); + redis_cmd_append_sstr(&cmdstr, ZSTR_VAL(zstr), ZSTR_LEN(zstr)); + zend_string_release(zstr); + } - ZEND_HASH_FOREACH_VAL(ht_arr, z_ele) { - zend_string *zstr = zval_get_string(z_ele); - redis_cmd_append_sstr(&cmdstr, ZSTR_VAL(zstr), ZSTR_LEN(zstr)); - zend_string_release(zstr); - } ZEND_HASH_FOREACH_END(); + puts(cmdstr.c); - *cmd = cmdstr.c; - *cmd_len = cmdstr.len; - } + // Push out values + *cmd = cmdstr.c; + *cmd_len = cmdstr.len; /* Any slot will do */ CMD_RAND_SLOT(slot); diff --git a/redis_legacy_arginfo.h b/redis_legacy_arginfo.h index 196ea90a..a099cec5 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: 42952974e3686f29934dfff1ebba07150942a405 */ + * Stub hash: babd74e96036b211b97579605f9739698de2e65d */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis___construct, 0, 0, 0) ZEND_ARG_INFO(0, options) @@ -114,9 +114,9 @@ ZEND_END_ARG_INFO() #define arginfo_class_Redis_close arginfo_class_Redis___destruct -ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_command, 0, 0, 2) +ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_command, 0, 0, 0) ZEND_ARG_INFO(0, opt) - ZEND_ARG_INFO(0, arg) + ZEND_ARG_VARIADIC_INFO(0, args) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_config, 0, 0, 1) -- cgit v1.2.3