diff options
author | Pavlo Yatsukhnenko <yatsukhnenko@gmail.com> | 2016-11-28 19:00:01 +0300 |
---|---|---|
committer | Pavlo Yatsukhnenko <yatsukhnenko@gmail.com> | 2016-11-28 19:00:01 +0300 |
commit | 71c9f7c84c65c10dbe0ded9740f7dcce00da650c (patch) | |
tree | b78cdd74bb0a4f45702fa7b9ffde4f8e764a2a98 /redis_commands.c | |
parent | 48c8f2a30a254b28194047c3720950fe53289210 (diff) |
Issue #760
Diffstat (limited to 'redis_commands.c')
-rw-r--r-- | redis_commands.c | 75 |
1 files changed, 60 insertions, 15 deletions
diff --git a/redis_commands.c b/redis_commands.c index c2c438c3..717b69e6 100644 --- a/redis_commands.c +++ b/redis_commands.c @@ -2577,25 +2577,57 @@ int redis_zadd_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, char **cmd, int *cmd_len, short *slot, void **ctx) { zval *z_args; - char *key, *val; + char *key, *val, *exp_type = NULL; int key_len, key_free, val_len, val_free; - int argc = ZEND_NUM_ARGS(), i; + int num = ZEND_NUM_ARGS(), i = 1, argc; + zend_bool ch = 0, incr = 0; smart_string cmdstr = {0}; - z_args = emalloc(argc * sizeof(zval)); - if (zend_get_parameters_array(ht, argc, z_args) == FAILURE) { + if (num < 3) return FAILURE; + z_args = ecalloc(num, sizeof(zval)); + if (zend_get_parameters_array(ht, num, z_args) == FAILURE) { efree(z_args); return FAILURE; } - // Need key, score, value, [score, value...] */ - if(argc>0) convert_to_string(&z_args[0]); - if(argc<3 || Z_TYPE(z_args[0])!=IS_STRING || (argc-1)%2 != 0) { - efree(z_args); - return FAILURE; + // Need key, [NX|XX] [CH] [INCR] score, value, [score, value...] */ + if (num % 2 == 0) { + if (Z_TYPE(z_args[1]) != IS_ARRAY) { + efree(z_args); + return FAILURE; + } + zval *z_opt; + ZEND_HASH_FOREACH_VAL(Z_ARRVAL(z_args[1]), z_opt) { + if (Z_TYPE_P(z_opt) == IS_STRING) { + if (Z_STRLEN_P(z_opt) == 2) { + if (IS_NX_XX_ARG(Z_STRVAL_P(z_opt))) { + exp_type = Z_STRVAL_P(z_opt); + } else if (strncasecmp(Z_STRVAL_P(z_opt), "ch", 2) == 0) { + ch = 1; + } + } else if (Z_STRLEN_P(z_opt) == 4 && + strncasecmp(Z_STRVAL_P(z_opt), "incr", 4) == 0 + ) { + if (num > 4) { + // Only one score-element pair can be specified in this mode. + efree(z_args); + return FAILURE; + } + incr = 1; + } + + } + } ZEND_HASH_FOREACH_END(); + argc = num - 1; + if (exp_type) argc++; + argc += ch + incr; + i++; + } else { + argc = num; } // Prefix our key + convert_to_string(&z_args[0]); key = Z_STRVAL(z_args[0]); key_len = Z_STRLEN(z_args[0]); key_free = redis_key_prefix(redis_sock, &key, &key_len); @@ -2608,19 +2640,32 @@ int redis_zadd_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, CMD_SET_SLOT(slot,key,key_len); if(key_free) efree(key); + if (exp_type) redis_cmd_append_sstr(&cmdstr, exp_type, 2); + if (ch) redis_cmd_append_sstr(&cmdstr, "CH", 2); + if (incr) redis_cmd_append_sstr(&cmdstr, "INCR", 4); + // Now the rest of our arguments - for(i=1;i<argc;i+=2) { - // Convert score to a double, serialize value if requested - convert_to_double(&z_args[i]); + while (i < num) { + // Append score and member + if (Z_TYPE(z_args[i]) == IS_STRING && ( + /* The score values should be the string representation of a double + * precision floating point number. +inf and -inf values are valid + * values as well. */ + strncasecmp(Z_STRVAL(z_args[i]), "-inf", 4) == 0 || + strncasecmp(Z_STRVAL(z_args[i]), "+inf", 4) == 0 + )) { + redis_cmd_append_sstr(&cmdstr, Z_STRVAL(z_args[i]), Z_STRLEN(z_args[i])); + } else { + redis_cmd_append_sstr_dbl(&cmdstr, zval_get_double(&z_args[i])); + } + // serialize value if requested val_free = redis_serialize(redis_sock, &z_args[i+1], &val, &val_len TSRMLS_CC); - - // Append score and member - redis_cmd_append_sstr_dbl(&cmdstr, Z_DVAL(z_args[i])); redis_cmd_append_sstr(&cmdstr, val, val_len); // Free value if we serialized if(val_free) efree(val); + i += 2; } // Push output values |