@@ -6765,6 +6765,187 @@ redis_vadd_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
67656765return SUCCESS ;
67666766}
67676767
6768+ typedef enum redisVSimMemberType {
6769+ REDIS_VSIM_NONE ,
6770+ REDIS_VSIM_FP32 ,
6771+ REDIS_VSIM_VALUES ,
6772+ REDIS_VSIM_ELE ,
6773+ }redisVSimMemberType ;
6774+
6775+ typedef struct redisVSimOptions {
6776+ redisVSimMemberType type ;
6777+ zend_long count ;
6778+ zend_long ef ;
6779+ zend_string * filter ;
6780+ zend_long filter_ef ;
6781+ zend_bool truth ;
6782+ zend_bool nothread ;
6783+ zend_bool withscores ;
6784+ }redisVSimOptions ;
6785+
6786+ static void free_vsim_options (redisVSimOptions * opts ) {
6787+ if (opts -> filter != NULL )
6788+ zend_string_release (opts -> filter );
6789+ }
6790+
6791+ static void parse_vsim_options (redisVSimOptions * dst ,HashTable * ht ) {
6792+ zend_string * key ;
6793+ zval * zv ;
6794+
6795+ * dst = (redisVSimOptions ){
6796+ .filter_ef = -1 ,
6797+ .ef = -1 ,
6798+ };
6799+
6800+ if (ht == NULL )
6801+ return ;
6802+
6803+ ZEND_HASH_FOREACH_STR_KEY_VAL (ht ,key ,zv ) {
6804+ if (key != NULL ) {
6805+ if (zend_string_equals_literal_ci (key ,"EF" )) {
6806+ if (validate_vadd_integer (key ,zv ,1 ))
6807+ dst -> ef = Z_LVAL_P (zv );
6808+ }else if (zend_string_equals_literal_ci (key ,"FILTER" )) {
6809+ dst -> filter = zval_get_string (zv );
6810+ }else if (zend_string_equals_literal_ci (key ,"FILTER-EF" )) {
6811+ if (validate_vadd_integer (key ,zv ,1 ))
6812+ dst -> filter_ef = Z_LVAL_P (zv );
6813+ }else if (zend_string_equals_literal_ci (key ,"COUNT" )) {
6814+ if (validate_vadd_integer (key ,zv ,1 ))
6815+ dst -> count = Z_LVAL_P (zv );
6816+ }else if (zend_string_equals_literal_ci (key ,"WITHSCORES" )) {
6817+ dst -> withscores = zval_is_true (zv );
6818+ }
6819+ }else if (Z_TYPE_P (zv )== IS_STRING ) {
6820+ if (zend_string_equals_literal_ci (Z_STR_P (zv ),"FP32" )) {
6821+ dst -> type = REDIS_VSIM_FP32 ;
6822+ }else if (zend_string_equals_literal_ci (Z_STR_P (zv ),"VALUES" )) {
6823+ dst -> type = REDIS_VSIM_VALUES ;
6824+ }else if (zend_string_equals_literal_ci (Z_STR_P (zv ),"ELE" )) {
6825+ dst -> type = REDIS_VSIM_ELE ;
6826+ }else if (zend_string_equals_literal_ci (Z_STR_P (zv ),"NOTHREAD" )) {
6827+ dst -> nothread = 1 ;
6828+ }else if (zend_string_equals_literal_ci (Z_STR_P (zv ),"TRUTH" )) {
6829+ dst -> truth = 1 ;
6830+ }else if (zend_string_equals_literal_ci (Z_STR_P (zv ),"WITHSCORES" )) {
6831+ dst -> withscores = 1 ;
6832+ }
6833+ }
6834+ }ZEND_HASH_FOREACH_END ();
6835+ }
6836+
6837+ static redisVSimMemberType detect_vsim_type (zval * zv ) {
6838+ zval * ele ;
6839+
6840+ if (Z_TYPE_P (zv )!= IS_ARRAY )
6841+ return REDIS_VSIM_ELE ;
6842+
6843+ ZEND_HASH_FOREACH_VAL (Z_ARRVAL_P (zv ),ele ) {
6844+ if (Z_TYPE_P (ele )!= IS_LONG && Z_TYPE_P (ele )!= IS_DOUBLE )
6845+ return REDIS_VSIM_ELE ;
6846+ }ZEND_HASH_FOREACH_END ();
6847+
6848+ return REDIS_VSIM_FP32 ;
6849+ }
6850+
6851+ int
6852+ redis_vsim_cmd (INTERNAL_FUNCTION_PARAMETERS ,RedisSock * redis_sock ,
6853+ char * * cmd ,int * cmd_len ,short * slot ,void * * ctx )
6854+ {
6855+ HashTable * options = NULL ;
6856+ smart_string cmdstr = {0 };
6857+ redisVSimOptions opts ;
6858+ zend_string * key ;
6859+ zval * member ;
6860+ int argc ;
6861+
6862+ ZEND_PARSE_PARAMETERS_START (2 ,3 ) {
6863+ Z_PARAM_STR (key )
6864+ Z_PARAM_ZVAL (member )
6865+ Z_PARAM_OPTIONAL
6866+ Z_PARAM_ARRAY_HT_OR_NULL (options )
6867+ }ZEND_PARSE_PARAMETERS_END_EX (return FAILURE );
6868+
6869+ parse_vsim_options (& opts ,options );
6870+
6871+ if (opts .type == REDIS_VSIM_NONE )
6872+ opts .type = detect_vsim_type (member );
6873+
6874+ /* Sanity check on the member type */
6875+ if (opts .type != REDIS_VSIM_ELE && Z_TYPE_P (member )!= IS_ARRAY ) {
6876+ php_error_docref (NULL ,E_WARNING ,
6877+ "member must be an array when not querying in ELE mode" );
6878+ return FAILURE ;
6879+ }
6880+
6881+ argc = 1 + (opts .count > 0 ?2 :0 )+ (opts .ef > 0 ?2 :0 )
6882+ + (opts .filter != NULL ?2 :0 )+ (opts .filter_ef > 0 ?2 :0 )
6883+ + !!opts .truth + !!opts .nothread + !!opts .withscores ;
6884+
6885+ if (opts .type == REDIS_VSIM_ELE || opts .type == REDIS_VSIM_FP32 ) {
6886+ // ELE <element> or FP32 <fp32 blob>
6887+ argc += 2 ;
6888+ }else if (opts .type == REDIS_VSIM_VALUES ) {
6889+ // VALUES <num> <num values>
6890+ argc += 2 + zend_hash_num_elements (Z_ARRVAL_P (member ));
6891+ }else {
6892+ zend_error_noreturn (E_ERROR ,
6893+ "Internal error. type shouldn't be REDIS_VSIM_NONE!" );
6894+ }
6895+
6896+ REDIS_CMD_INIT_SSTR_STATIC (& cmdstr ,argc ,"VSIM" );
6897+ redis_cmd_append_sstr_key_zstr (& cmdstr ,key ,redis_sock ,slot );
6898+
6899+ if (opts .type == REDIS_VSIM_FP32 ) {
6900+ REDIS_CMD_APPEND_SSTR_STATIC (& cmdstr ,"FP32" );
6901+ redis_cmd_append_sstr_fp32 (& cmdstr ,Z_ARRVAL_P (member ));
6902+ }else if (opts .type == REDIS_VSIM_VALUES ) {
6903+ REDIS_CMD_APPEND_SSTR_STATIC (& cmdstr ,"VALUES" );
6904+ redis_cmd_append_sstr_long (& cmdstr ,
6905+ zend_hash_num_elements (Z_ARRVAL_P (member )));
6906+ redis_cmd_append_sstr_fp32_values (& cmdstr ,Z_ARRVAL_P (member ));
6907+ }else {
6908+ REDIS_CMD_APPEND_SSTR_STATIC (& cmdstr ,"ELE" );
6909+ redis_cmd_append_sstr_zval (& cmdstr ,member ,redis_sock );
6910+ }
6911+
6912+ if (opts .withscores ) {
6913+ REDIS_CMD_APPEND_SSTR_STATIC (& cmdstr ,"WITHSCORES" );
6914+ * ctx = PHPREDIS_CTX_PTR ;
6915+ }
6916+
6917+ if (opts .count > 0 ) {
6918+ REDIS_CMD_APPEND_SSTR_STATIC (& cmdstr ,"COUNT" );
6919+ redis_cmd_append_sstr_long (& cmdstr ,opts .count );
6920+ }
6921+
6922+ if (opts .ef > 0 ) {
6923+ REDIS_CMD_APPEND_SSTR_STATIC (& cmdstr ,"EF" );
6924+ redis_cmd_append_sstr_long (& cmdstr ,opts .ef );
6925+ }
6926+
6927+ if (opts .filter != NULL ) {
6928+ REDIS_CMD_APPEND_SSTR_STATIC (& cmdstr ,"FILTER" );
6929+ redis_cmd_append_sstr_zstr (& cmdstr ,opts .filter );
6930+ }
6931+
6932+ if (opts .filter_ef > 0 ) {
6933+ REDIS_CMD_APPEND_SSTR_STATIC (& cmdstr ,"FILTER-EF" );
6934+ redis_cmd_append_sstr_long (& cmdstr ,opts .filter_ef );
6935+ }
6936+
6937+ if (opts .truth )
6938+ REDIS_CMD_APPEND_SSTR_STATIC (& cmdstr ,"TRUTH" );
6939+ if (opts .nothread )
6940+ REDIS_CMD_APPEND_SSTR_STATIC (& cmdstr ,"NOTHREAD" );
6941+
6942+ free_vsim_options (& opts );
6943+
6944+ * cmd = cmdstr .c ;
6945+ * cmd_len = cmdstr .len ;
6946+
6947+ return SUCCESS ;
6948+ }
67686949/*
67696950 * Redis commands that don't deal with the server at all. The RedisSock*
67706951 * pointer is the only thing retrieved differently, so we just take that