@@ -642,28 +642,6 @@ static bool do_fetch_class_prepare(pdo_stmt_t *stmt) /* {{{ */
642642}
643643/* }}} */
644644
645- static bool pdo_stmt_init_fci_fcc_for_function_fetch_mode (pdo_stmt_t * stmt , zval * callable )
646- {
647- char * is_callable_error = NULL ;
648-
649- if (zend_fcall_info_init (callable , 0 , & stmt -> fetch .func .fci , & stmt -> fetch .func .fcc , NULL , & is_callable_error ) == FAILURE ) {
650- if (is_callable_error ) {
651- zend_type_error ("%s" , is_callable_error );
652- efree (is_callable_error );
653- } else {
654- zend_type_error ("User-supplied function must be a valid callback" );
655- }
656- return false;
657- }
658- ZEND_ASSERT (is_callable_error == NULL );
659-
660- uint32_t num_args = stmt -> column_count ;
661- stmt -> fetch .func .fci .param_count = num_args ; /* probably less */
662- stmt -> fetch .func .fci .params = safe_emalloc (sizeof (zval ), num_args , 0 );
663-
664- return true;
665- }
666-
667645static void do_fetch_opt_finish (pdo_stmt_t * stmt , bool free_ctor_agrs ) /* {{{ */
668646{
669647 /* fci.size is used to check if it is valid */
@@ -716,8 +694,10 @@ static bool do_fetch(pdo_stmt_t *stmt, zval *return_value, enum pdo_fetch_type h
716694{
717695 int flags , idx , old_arg_count = 0 ;
718696 zend_class_entry * ce = NULL , * old_ce = NULL ;
719- zval retval , old_ctor_args = {{0 }, {0 }, {0 }};
697+ zval old_ctor_args = {{0 }, {0 }, {0 }};
720698 int i = 0 ;
699+ zval * fetch_function_params = NULL ;
700+ uint32_t fetch_function_param_num = 0 ;
721701
722702 if (how == PDO_FETCH_USE_DEFAULT ) {
723703 how = stmt -> default_fetch_type ;
@@ -872,11 +852,14 @@ static bool do_fetch(pdo_stmt_t *stmt, zval *return_value, enum pdo_fetch_type h
872852
873853 case PDO_FETCH_FUNC :
874854 /* TODO: Make this an assertion and ensure this is true higher up? */
875- if (!ZEND_FCI_INITIALIZED (stmt -> fetch .func .fci )) {
855+ if (!ZEND_FCC_INITIALIZED (stmt -> fetch .func .fcc )) {
876856 /* TODO ArgumentCountError? */
877857 pdo_raise_impl_error (stmt -> dbh , stmt , "HY000" , "No fetch function specified" );
878858 return false;
879859 }
860+ /* There will be at most stmt->column_count parameters.
861+ * However, if we fetch a group key we will have over allocated. */
862+ fetch_function_params = safe_emalloc (sizeof (zval ), stmt -> column_count , 0 );
880863 break ;
881864 EMPTY_SWITCH_DEFAULT_CASE ();
882865 }
@@ -971,7 +954,7 @@ static bool do_fetch(pdo_stmt_t *stmt, zval *return_value, enum pdo_fetch_type h
971954 break ;
972955
973956 case PDO_FETCH_FUNC :
974- ZVAL_COPY_VALUE (& stmt -> fetch . func . fci . params [ idx ], & val );
957+ ZVAL_COPY_VALUE (& fetch_function_params [ fetch_function_param_num ++ ], & val );
975958 break ;
976959
977960 default :
@@ -1006,21 +989,12 @@ static bool do_fetch(pdo_stmt_t *stmt, zval *return_value, enum pdo_fetch_type h
1006989 break ;
1007990
1008991 case PDO_FETCH_FUNC :
1009- stmt -> fetch .func .fci .param_count = idx ;
1010- stmt -> fetch .func .fci .retval = & retval ;
1011- if (zend_call_function (& stmt -> fetch .func .fci , & stmt -> fetch .func .fcc ) == FAILURE ) {
1012- /* TODO Error? */
1013- pdo_raise_impl_error (stmt -> dbh , stmt , "HY000" , "could not call user-supplied function" );
1014- return 0 ;
1015- } else {
1016- if (!Z_ISUNDEF (retval )) {
1017- ZVAL_COPY_VALUE (return_value , & retval );
1018- }
1019- }
992+ zend_call_known_fcc (& stmt -> fetch .func .fcc , return_value , fetch_function_param_num , fetch_function_params , NULL );
1020993 /* Free FCI parameters that were allocated in the previous loop */
1021- for (uint32_t param_num = 0 ; param_num < stmt -> fetch . func . fci . param_count ; param_num ++ ) {
1022- zval_ptr_dtor (& stmt -> fetch . func . fci . params [param_num ]);
994+ for (uint32_t param_num = 0 ; param_num < fetch_function_param_num ; param_num ++ ) {
995+ zval_ptr_dtor (& fetch_function_params [param_num ]);
1023996 }
997+ efree (fetch_function_params );
1024998 break ;
1025999
10261000 default :
@@ -1197,6 +1171,26 @@ PHP_METHOD(PDOStatement, fetchColumn)
11971171}
11981172/* }}} */
11991173
1174+ static bool pdo_get_fcc_from_zval (zend_fcall_info_cache * fcc , zval * callable ) {
1175+ if (callable == NULL ) {
1176+ /* TODO use "must be of type callable" format? */
1177+ zend_argument_type_error (2 , "must be a callable, null given" );
1178+ return false;
1179+ }
1180+
1181+ char * is_callable_error = NULL ;
1182+ if (!zend_is_callable_ex (callable , NULL , 0 , NULL , fcc , & is_callable_error )) {
1183+ if (is_callable_error ) {
1184+ zend_type_error ("%s" , is_callable_error );
1185+ efree (is_callable_error );
1186+ } else {
1187+ zend_type_error ("User-supplied function must be a valid callback" );
1188+ }
1189+ return false;
1190+ }
1191+ return true;
1192+ }
1193+
12001194/* {{{ Returns an array of all of the results. */
12011195PHP_METHOD (PDOStatement , fetchAll )
12021196{
@@ -1263,12 +1257,7 @@ PHP_METHOD(PDOStatement, fetchAll)
12631257 zend_string_release (func );
12641258 RETURN_THROWS ();
12651259 }
1266- if (arg2 == NULL ) {
1267- /* TODO use "must be of type callable" format? */
1268- zend_argument_type_error (2 , "must be a callable, null given" );
1269- RETURN_THROWS ();
1270- }
1271- if (pdo_stmt_init_fci_fcc_for_function_fetch_mode (stmt , arg2 ) == false) {
1260+ if (!pdo_get_fcc_from_zval (& stmt -> fetch .func .fcc , arg2 )) {
12721261 RETURN_THROWS ();
12731262 }
12741263 break ;
0 commit comments