@@ -4355,187 +4355,167 @@ PHP_METHOD(Redis, zIncrBy)
43554355 generic_incrby_method (INTERNAL_FUNCTION_PARAM_PASSTHRU , "ZINCRBY" , sizeof ("ZINCRBY" )- 1 );
43564356}
43574357/* }}} */
4358- PHPAPI void generic_z_command (INTERNAL_FUNCTION_PARAMETERS , char * command , int command_len ) {
4359-
4360- zval * object , * keys_array , * weights_array = NULL , * * data ;
4361- HashTable * arr_weights_hash = NULL , * arr_keys_hash ;
4362- int key_output_len , array_weights_count , array_keys_count , operation_len = 0 ;
4363- char * key_output , * operation ;
4364- RedisSock * redis_sock ;
43654358
4366- HashPosition pointer ;
4367- char * cmd = "" ;
4368- char * old_cmd ;
4369- int cmd_len , cmd_elements ;
4370- int free_key_output ;
4359+ PHPAPI void generic_z_command (INTERNAL_FUNCTION_PARAMETERS , char * command , int command_len ) {
4360+ zval * object , * z_keys , * z_weights = NULL , * * z_data ;
4361+ HashTable * ht_keys , * ht_weights = NULL ;
4362+ RedisSock * redis_sock ;
4363+ smart_str cmd = {0 };
4364+ HashPosition ptr ;
4365+ char * store_key , * agg_op = NULL ;
4366+ int cmd_arg_count = 2 , store_key_len , agg_op_len , keys_count ;
43714367
4372- if (zend_parse_method_parameters (ZEND_NUM_ARGS () TSRMLS_CC , getThis (), "Osa|a!s" ,
4373- & object , redis_ce ,
4374- & key_output , & key_output_len , & keys_array , & weights_array , & operation , & operation_len ) == FAILURE ) {
4375- RETURN_FALSE ;
4376- }
4368+ // Grab our parameters
4369+ if (zend_parse_method_parameters (ZEND_NUM_ARGS () TSRMLS_CC , getThis (), "Osa|a!s" ,
4370+ & object , redis_ce , & store_key , & store_key_len ,
4371+ & z_keys , & z_weights , & agg_op , & agg_op_len ) == FAILURE )
4372+ {
4373+ RETURN_FALSE ;
4374+ }
43774375
4376+ // We'll need our socket
43784377 if (redis_sock_get (object , & redis_sock TSRMLS_CC , 0 ) < 0 ) {
4379- RETURN_FALSE ;
4378+ RETURN_FALSE ;
43804379 }
43814380
4382- arr_keys_hash = Z_ARRVAL_P ( keys_array );
4383- array_keys_count = zend_hash_num_elements ( arr_keys_hash );
4381+ // Grab our keys argument as an array
4382+ ht_keys = Z_ARRVAL_P ( z_keys );
43844383
4385- if (array_keys_count == 0 ) {
4384+ // Nothing to do if there aren't any keys
4385+ if ((keys_count = zend_hash_num_elements (ht_keys )) == 0 ) {
43864386 RETURN_FALSE ;
4387+ } else {
4388+ // Increment our overall argument count
4389+ cmd_arg_count += keys_count ;
43874390 }
43884391
4389- if (weights_array != NULL ) {
4390- arr_weights_hash = Z_ARRVAL_P (weights_array );
4391- array_weights_count = zend_hash_num_elements (arr_weights_hash );
4392- if (array_weights_count == 0 ) {
4393- RETURN_FALSE ;
4394- }
4395- if ((array_weights_count != 0 ) && (array_weights_count != array_keys_count )) {
4396- RETURN_FALSE ;
4397- }
4392+ // Grab and validate our weights array
4393+ if (z_weights != NULL ) {
4394+ ht_weights = Z_ARRVAL_P (z_weights );
43984395
4399- }
4396+ // This command is invalid if the weights array isn't the same size
4397+ // as our keys array.
4398+ if (zend_hash_num_elements (ht_weights ) != keys_count ) {
4399+ RETURN_FALSE ;
4400+ }
44004401
4401- free_key_output = redis_key_prefix (redis_sock , & key_output , & key_output_len TSRMLS_CC );
4402- cmd_elements = 3 ;
4403- cmd_len = redis_cmd_format (& cmd ,
4404- "$%d" _NL /* command_len */
4405- "%s" _NL /* command */
4402+ // Increment our overall argument count by the number of keys
4403+ // plus one, for the "WEIGHTS" argument itself
4404+ cmd_arg_count += keys_count + 1 ;
4405+ }
44064406
4407- "$%d" _NL /* key_output_len */
4408- "%s" _NL /* key_output */
4407+ // AGGREGATE option
4408+ if (agg_op_len != 0 ) {
4409+ // Verify our aggregation option
4410+ if (strncasecmp (agg_op , "SUM" , sizeof ("SUM" )) &&
4411+ strncasecmp (agg_op , "MIN" , sizeof ("MIN" )) &&
4412+ strncasecmp (agg_op , "MAX" , sizeof ("MAX" )))
4413+ {
4414+ RETURN_FALSE ;
4415+ }
44094416
4410- "$%d" _NL
4411- "%d" _NL /* array_keys_count */
4417+ // Two more arguments: "AGGREGATE" and agg_op
4418+ cmd_arg_count += 2 ;
4419+ }
44124420
4413- , command_len , command , command_len
4414- , key_output_len , key_output , key_output_len
4415- , integer_length (array_keys_count ), array_keys_count );
4416- if (free_key_output ) efree (key_output );
4421+ // Command header
4422+ redis_cmd_init_sstr (& cmd , cmd_arg_count , command , command_len );
44174423
4418- /* keys */
4419- for (zend_hash_internal_pointer_reset_ex (arr_keys_hash , & pointer );
4420- zend_hash_get_current_data_ex (arr_keys_hash , (void * * ) & data ,
4421- & pointer ) == SUCCESS ;
4422- zend_hash_move_forward_ex (arr_keys_hash , & pointer )) {
4424+ // Prefix our key if necessary and add the output key
4425+ int key_free = redis_key_prefix (redis_sock , & store_key , & store_key_len TSRMLS_CC );
4426+ redis_cmd_append_sstr (& cmd , store_key , store_key_len );
4427+ if (key_free ) efree (store_key );
44234428
4424- if (Z_TYPE_PP (data ) == IS_STRING ) {
4425- char * old_cmd = NULL ;
4426- char * data_str ;
4427- int data_len ;
4428- int free_data ;
4429-
4430- if (* cmd ) {
4431- old_cmd = cmd ;
4432- }
4433- data_str = Z_STRVAL_PP (data );
4434- data_len = Z_STRLEN_PP (data );
4435-
4436- free_data = redis_key_prefix (redis_sock , & data_str , & data_len TSRMLS_CC );
4437- cmd_len = redis_cmd_format (& cmd ,
4438- "%s" /* cmd */
4439- "$%d" _NL
4440- "%s" _NL
4441- , cmd , cmd_len
4442- , data_len , data_str , data_len );
4443- cmd_elements ++ ;
4444- if (free_data ) efree (data_str );
4445- if (old_cmd ) {
4446- efree (old_cmd );
4447- }
4429+ // Number of input keys argument
4430+ redis_cmd_append_sstr_int (& cmd , keys_count );
4431+
4432+ // Process input keys
4433+ for (zend_hash_internal_pointer_reset_ex (ht_keys , & ptr );
4434+ zend_hash_get_current_data_ex (ht_keys , (void * * )& z_data , & ptr )== SUCCESS ;
4435+ zend_hash_move_forward_ex (ht_keys , & ptr ))
4436+ {
4437+ char * key ;
4438+ int key_free , key_len ;
4439+ zval * z_tmp = NULL ;
4440+
4441+ if (Z_TYPE_PP (z_data ) == IS_STRING ) {
4442+ key = Z_STRVAL_PP (z_data );
4443+ key_len = Z_STRLEN_PP (z_data );
4444+ } else {
4445+ MAKE_STD_ZVAL (z_tmp );
4446+ * z_tmp = * * z_data ;
4447+ convert_to_string (z_tmp );
4448+
4449+ key = Z_STRVAL_P (z_tmp );
4450+ key_len = Z_STRLEN_P (z_tmp );
44484451 }
4449- }
44504452
4451- /* weight */
4452- if (weights_array != NULL ) {
4453- cmd_len = redis_cmd_format (& cmd ,
4454- "%s" /* cmd */
4455- "$7" _NL
4456- "WEIGHTS" _NL
4457- , cmd , cmd_len );
4458- cmd_elements ++ ;
4459-
4460- for (zend_hash_internal_pointer_reset_ex (arr_weights_hash , & pointer );
4461- zend_hash_get_current_data_ex (arr_weights_hash , (void * * ) & data , & pointer ) == SUCCESS ;
4462- zend_hash_move_forward_ex (arr_weights_hash , & pointer )) {
4463-
4464- // Ignore non numeric arguments, unless they're the special Redis numbers
4465- // "inf" ,"-inf", and "+inf" which can be passed as weights
4466- if (Z_TYPE_PP (data ) != IS_LONG && Z_TYPE_PP (data ) != IS_DOUBLE &&
4467- strncasecmp (Z_STRVAL_PP (data ), "inf" , sizeof ("inf" )) != 0 &&
4468- strncasecmp (Z_STRVAL_PP (data ), "-inf" , sizeof ("-inf" )) != 0 &&
4469- strncasecmp (Z_STRVAL_PP (data ), "+inf" , sizeof ("+inf" )) != 0 )
4470- {
4471- continue ;
4472- }
4453+ // Apply key prefix if necessary
4454+ key_free = redis_key_prefix (redis_sock , & key , & key_len TSRMLS_CC );
44734455
4474- old_cmd = NULL ;
4475- if (* cmd ) {
4476- old_cmd = cmd ;
4477- }
4456+ // Append this input set
4457+ redis_cmd_append_sstr (& cmd , key , key_len );
44784458
4479- if (Z_TYPE_PP (data ) == IS_LONG ) {
4480- cmd_len = redis_cmd_format (& cmd ,
4481- "%s" /* cmd */
4482- "$%d" _NL /* data_len */
4483- "%d" _NL /* data */
4484- , cmd , cmd_len
4485- , integer_length (Z_LVAL_PP (data )), Z_LVAL_PP (data ));
4486-
4487- } else if (Z_TYPE_PP (data ) == IS_DOUBLE ) {
4488- cmd_len = redis_cmd_format (& cmd ,
4489- "%s" /* cmd */
4490- "$%f" _NL /* data, including size */
4491- , cmd , cmd_len
4492- , Z_DVAL_PP (data ));
4493- } else if (Z_TYPE_PP (data ) == IS_STRING ) {
4494- cmd_len = redis_cmd_format (& cmd ,
4495- "%s" /* cmd */
4496- "$%d" _NL /* data len */
4497- "%s" _NL /* data */
4498- , cmd , cmd_len , Z_STRLEN_PP (data ),
4499- Z_STRVAL_PP (data ), Z_STRLEN_PP (data ));
4500- }
4459+ // Free our key if it was prefixed
4460+ if (key_free ) efree (key );
45014461
4502- // keep track of elements added
4503- cmd_elements ++ ;
4504- if ( old_cmd ) {
4505- efree (old_cmd );
4506- }
4507- }
4508- }
4462+ // Free our temporary z_val if it was converted
4463+ if ( z_tmp ) {
4464+ zval_dtor ( z_tmp );
4465+ efree (z_tmp );
4466+ z_tmp = NULL ;
4467+ }
4468+ }
45094469
4510- if (operation_len != 0 ) {
4511- char * old_cmd = NULL ;
4512- old_cmd = cmd ;
4513- cmd_len = redis_cmd_format (& cmd ,
4514- "%s" /* cmd */
4515- "$9" _NL
4516- "AGGREGATE" _NL
4517- "$%d" _NL
4518- "%s" _NL
4519- , cmd , cmd_len
4520- , operation_len , operation , operation_len );
4521- cmd_elements += 2 ;
4522- efree (old_cmd );
4523- }
4470+ // Weights
4471+ if (ht_weights != NULL ) {
4472+ // Append "WEIGHTS" argument
4473+ redis_cmd_append_sstr (& cmd , "WEIGHTS" , sizeof ("WEIGHTS" ) - 1 );
45244474
4525- old_cmd = cmd ;
4526- cmd_len = redis_cmd_format (& cmd ,
4527- "*%d" _NL
4528- "%s"
4529- , cmd_elements
4530- , cmd , cmd_len );
4531- efree (old_cmd );
4475+ // Process weights
4476+ for (zend_hash_internal_pointer_reset_ex (ht_weights , & ptr );
4477+ zend_hash_get_current_data_ex (ht_weights , (void * * )& z_data , & ptr )== SUCCESS ;
4478+ zend_hash_move_forward_ex (ht_weights , & ptr ))
4479+ {
4480+ // Ignore non numeric arguments, unless they're special Redis numbers
4481+ if (Z_TYPE_PP (z_data ) != IS_LONG && Z_TYPE_PP (z_data ) != IS_DOUBLE &&
4482+ strncasecmp (Z_STRVAL_PP (z_data ), "inf" , sizeof ("inf" )) != 0 &&
4483+ strncasecmp (Z_STRVAL_PP (z_data ), "-inf" , sizeof ("-inf" )) != 0 &&
4484+ strncasecmp (Z_STRVAL_PP (z_data ), "+inf" , sizeof ("+inf" )) != 0 )
4485+ {
4486+ // We should abort if we have an invalid weight, rather than pass
4487+ // a different number of weights than the user is expecting
4488+ efree (cmd .c );
4489+ RETURN_FALSE ;
4490+ }
45324491
4533- REDIS_PROCESS_REQUEST (redis_sock , cmd , cmd_len );
4534- IF_ATOMIC () {
4535- redis_long_response (INTERNAL_FUNCTION_PARAM_PASSTHRU , redis_sock , NULL , NULL );
4536- }
4537- REDIS_PROCESS_RESPONSE (redis_long_response );
4492+ // Append the weight based on the input type
4493+ switch (Z_TYPE_PP (z_data )) {
4494+ case IS_LONG :
4495+ redis_cmd_append_sstr_long (& cmd , Z_LVAL_PP (z_data ));
4496+ break ;
4497+ case IS_DOUBLE :
4498+ redis_cmd_append_sstr_dbl (& cmd , Z_DVAL_PP (z_data ));
4499+ break ;
4500+ case IS_STRING :
4501+ redis_cmd_append_sstr (& cmd , Z_STRVAL_PP (z_data ), Z_STRLEN_PP (z_data ));
4502+ break ;
4503+ }
4504+ }
4505+ }
4506+
4507+ // Aggregation options, if we have them
4508+ if (agg_op_len != 0 ) {
4509+ redis_cmd_append_sstr (& cmd , "AGGREGATE" , sizeof ("AGGREGATE" ) - 1 );
4510+ redis_cmd_append_sstr (& cmd , agg_op , agg_op_len );
4511+ }
45384512
4513+ // Kick off our request
4514+ REDIS_PROCESS_REQUEST (redis_sock , cmd .c , cmd .len );
4515+ IF_ATOMIC () {
4516+ redis_long_response (INTERNAL_FUNCTION_PARAM_PASSTHRU , redis_sock , NULL , NULL );
4517+ }
4518+ REDIS_PROCESS_RESPONSE (redis_long_response );
45394519}
45404520
45414521/* zInter */
0 commit comments