@@ -708,14 +708,38 @@ static void do_fetch_opt_finish(pdo_stmt_t *stmt, int free_ctor_agrs) /* {{{ */
708708}
709709/* }}} */
710710
711+ static bool pdo_do_key_pair_fetch (pdo_stmt_t * stmt , enum pdo_fetch_orientation ori , zend_long offset , HashTable * container )
712+ {
713+ if (!do_fetch_common (stmt , ori , offset )) {
714+ return false;
715+ }
716+ if (stmt -> column_count != 2 ) {
717+ /* TODO: Error? */
718+ pdo_raise_impl_error (stmt -> dbh , stmt , "HY000" , "PDO::FETCH_KEY_PAIR fetch mode requires the result set to contain exactly 2 columns." );
719+ return false;
720+ }
721+
722+ zval key , val ;
723+ fetch_value (stmt , & key , 0 , NULL );
724+ fetch_value (stmt , & val , 1 , NULL );
725+
726+ if (Z_TYPE (key ) == IS_LONG ) {
727+ zend_hash_index_update (container , Z_LVAL (key ), & val );
728+ } else {
729+ convert_to_string (& key );
730+ zend_symtable_update (container , Z_STR (key ), & val );
731+ }
732+ zval_ptr_dtor (& key );
733+ return true;
734+ }
735+
711736/* perform a fetch.
712737 * Stores values into return_value according to HOW. */
713- static bool do_fetch (pdo_stmt_t * stmt , zval * return_value , enum pdo_fetch_type how , enum pdo_fetch_orientation ori , zend_long offset , zval * return_all ) /* {{{ */
738+ static bool do_fetch (pdo_stmt_t * stmt , zval * return_value , enum pdo_fetch_type how , enum pdo_fetch_orientation ori , zend_long offset , zval * group_key ) /* {{{ */
714739{
715740 int flags , idx , old_arg_count = 0 ;
716741 zend_class_entry * ce = NULL , * old_ce = NULL ;
717- zval grp_val , * pgrp , retval , old_ctor_args = {{0 }, {0 }, {0 }};
718- int colno ;
742+ zval retval , old_ctor_args = {{0 }, {0 }, {0 }};
719743 int i = 0 ;
720744
721745 if (how == PDO_FETCH_USE_DEFAULT ) {
@@ -725,23 +749,54 @@ static bool do_fetch(pdo_stmt_t *stmt, zval *return_value, enum pdo_fetch_type h
725749 how = how & ~PDO_FETCH_FLAGS ;
726750
727751 if (!do_fetch_common (stmt , ori , offset )) {
728- return 0 ;
752+ return false ;
729753 }
730754
731755 if (how == PDO_FETCH_BOUND ) {
732756 RETVAL_TRUE ;
733- return 1 ;
734- }
735-
736- if ((flags & PDO_FETCH_GROUP ) && stmt -> fetch .column == -1 ) {
737- colno = 1 ;
738- } else {
739- colno = stmt -> fetch .column ;
757+ return true;
740758 }
741759
742760 if (how == PDO_FETCH_LAZY ) {
743761 get_lazy_object (stmt , return_value );
744- return 1 ;
762+ return true;
763+ }
764+
765+ /* When fetching a column we only do one value fetch, so handle it separately */
766+ if (how == PDO_FETCH_COLUMN ) {
767+ int colno = stmt -> fetch .column ;
768+
769+ if ((flags & PDO_FETCH_GROUP ) && stmt -> fetch .column == -1 ) {
770+ colno = 1 ;
771+ }
772+
773+ if (colno < 0 ) {
774+ zend_value_error ("Column index must be greater than or equal to 0" );
775+ return false;
776+ }
777+
778+ if (colno >= stmt -> column_count ) {
779+ zend_value_error ("Invalid column index" );
780+ return false;
781+ }
782+
783+ if (flags == PDO_FETCH_GROUP && stmt -> fetch .column == -1 ) {
784+ fetch_value (stmt , return_value , 1 , NULL );
785+ } else if (flags == PDO_FETCH_GROUP && colno ) {
786+ fetch_value (stmt , return_value , 0 , NULL );
787+ } else {
788+ fetch_value (stmt , return_value , colno , NULL );
789+ }
790+
791+ if (group_key ) {
792+ if (flags == PDO_FETCH_GROUP && stmt -> fetch .column > 0 ) {
793+ fetch_value (stmt , group_key , colno , NULL );
794+ } else {
795+ fetch_value (stmt , group_key , 0 , NULL );
796+ }
797+ convert_to_string (group_key );
798+ }
799+ return true;
745800 }
746801
747802 RETVAL_FALSE ;
@@ -752,47 +807,13 @@ static bool do_fetch(pdo_stmt_t *stmt, zval *return_value, enum pdo_fetch_type h
752807 case PDO_FETCH_BOTH :
753808 case PDO_FETCH_NUM :
754809 case PDO_FETCH_NAMED :
755- if (!return_all ) {
810+ if (!group_key ) {
756811 array_init_size (return_value , stmt -> column_count );
757812 } else {
758813 array_init (return_value );
759814 }
760815 break ;
761816
762- case PDO_FETCH_KEY_PAIR :
763- if (stmt -> column_count != 2 ) {
764- /* TODO: Error? */
765- pdo_raise_impl_error (stmt -> dbh , stmt , "HY000" , "PDO::FETCH_KEY_PAIR fetch mode requires the result set to contain exactly 2 columns." );
766- return 0 ;
767- }
768- if (!return_all ) {
769- array_init (return_value );
770- }
771- break ;
772-
773- case PDO_FETCH_COLUMN :
774- if (colno < 0 ) {
775- zend_value_error ("Column index must be greater than or equal to 0" );
776- return false;
777- }
778-
779- if (colno >= stmt -> column_count ) {
780- zend_value_error ("Invalid column index" );
781- return false;
782- }
783-
784- if (flags == PDO_FETCH_GROUP && stmt -> fetch .column == -1 ) {
785- fetch_value (stmt , return_value , 1 , NULL );
786- } else if (flags == PDO_FETCH_GROUP && colno ) {
787- fetch_value (stmt , return_value , 0 , NULL );
788- } else {
789- fetch_value (stmt , return_value , colno , NULL );
790- }
791- if (!return_all ) {
792- return 1 ;
793- }
794- break ;
795-
796817 case PDO_FETCH_OBJ :
797818 object_init_ex (return_value , ZEND_STANDARD_CLASS_DEF_PTR );
798819 break ;
@@ -889,18 +910,10 @@ static bool do_fetch(pdo_stmt_t *stmt, zval *return_value, enum pdo_fetch_type h
889910 EMPTY_SWITCH_DEFAULT_CASE ();
890911 }
891912
892- if (return_all && how != PDO_FETCH_KEY_PAIR ) {
893- if (flags == PDO_FETCH_GROUP && how == PDO_FETCH_COLUMN && stmt -> fetch .column > 0 ) {
894- fetch_value (stmt , & grp_val , colno , NULL );
895- } else {
896- fetch_value (stmt , & grp_val , i , NULL );
897- }
898- convert_to_string (& grp_val );
899- if (how == PDO_FETCH_COLUMN ) {
900- i = stmt -> column_count ; /* no more data to fetch */
901- } else {
902- i ++ ;
903- }
913+ if (group_key ) {
914+ fetch_value (stmt , group_key , i , NULL );
915+ convert_to_string (group_key );
916+ i ++ ;
904917 }
905918
906919 for (idx = 0 ; i < stmt -> column_count ; i ++ , idx ++ ) {
@@ -912,22 +925,6 @@ static bool do_fetch(pdo_stmt_t *stmt, zval *return_value, enum pdo_fetch_type h
912925 zend_symtable_update (Z_ARRVAL_P (return_value ), stmt -> columns [i ].name , & val );
913926 break ;
914927
915- case PDO_FETCH_KEY_PAIR :
916- {
917- zval tmp ;
918- fetch_value (stmt , & tmp , ++ i , NULL );
919-
920- if (Z_TYPE (val ) == IS_LONG ) {
921- zend_hash_index_update ((return_all ? Z_ARRVAL_P (return_all ) : Z_ARRVAL_P (return_value )), Z_LVAL (val ), & tmp );
922- } else {
923- convert_to_string (& val );
924- zend_symtable_update ((return_all ? Z_ARRVAL_P (return_all ) : Z_ARRVAL_P (return_value )), Z_STR (val ), & tmp );
925- }
926- zval_ptr_dtor (& val );
927- return 1 ;
928- }
929- break ;
930-
931928 case PDO_FETCH_USE_DEFAULT :
932929 case PDO_FETCH_BOTH :
933930 zend_symtable_update (Z_ARRVAL_P (return_value ), stmt -> columns [i ].name , & val );
@@ -1048,10 +1045,7 @@ static bool do_fetch(pdo_stmt_t *stmt, zval *return_value, enum pdo_fetch_type h
10481045 pdo_raise_impl_error (stmt -> dbh , stmt , "HY000" , "could not call user-supplied function" );
10491046 return 0 ;
10501047 } else {
1051- if (return_all ) {
1052- zval_ptr_dtor (return_value ); /* we don't need that */
1053- ZVAL_COPY_VALUE (return_value , & retval );
1054- } else if (!Z_ISUNDEF (retval )) {
1048+ if (!Z_ISUNDEF (retval )) {
10551049 ZVAL_COPY_VALUE (return_value , & retval );
10561050 }
10571051 }
@@ -1064,26 +1058,19 @@ static bool do_fetch(pdo_stmt_t *stmt, zval *return_value, enum pdo_fetch_type h
10641058 break ;
10651059 }
10661060
1067- if (return_all ) {
1068- if ((flags & PDO_FETCH_UNIQUE ) == PDO_FETCH_UNIQUE ) {
1069- zend_symtable_update (Z_ARRVAL_P (return_all ), Z_STR (grp_val ), return_value );
1070- } else {
1071- zval grp ;
1072- if ((pgrp = zend_symtable_find (Z_ARRVAL_P (return_all ), Z_STR (grp_val ))) == NULL ) {
1073- array_init (& grp );
1074- zend_symtable_update (Z_ARRVAL_P (return_all ), Z_STR (grp_val ), & grp );
1075- } else {
1076- ZVAL_COPY_VALUE (& grp , pgrp );
1077- }
1078- zend_hash_next_index_insert (Z_ARRVAL (grp ), return_value );
1079- }
1080- zval_ptr_dtor_str (& grp_val );
1081- }
1082-
10831061 return 1 ;
10841062}
10851063/* }}} */
10861064
1065+
1066+ // TODO Error on the following cases:
1067+ // Using any fetch flag with PDO_FETCH_KEY_PAIR
1068+ // Combining PDO_FETCH_UNIQUE and PDO_FETCH_GROUP
1069+ // Using PDO_FETCH_UNIQUE or PDO_FETCH_GROUP outside of fetchAll()
1070+ // Combining PDO_FETCH_PROPS_LATE with a fetch mode different than PDO_FETCH_CLASS
1071+ // Improve error detection when combining PDO_FETCH_USE_DEFAULT with
1072+ // Reject PDO_FETCH_INTO mode with fetch_all as no support
1073+ // Reject $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, value); bypass
10871074static bool pdo_stmt_verify_mode (pdo_stmt_t * stmt , zend_long mode , uint32_t mode_arg_num , bool fetch_all ) /* {{{ */
10881075{
10891076 int flags = mode & PDO_FETCH_FLAGS ;
@@ -1155,6 +1142,17 @@ PHP_METHOD(PDOStatement, fetch)
11551142 RETURN_THROWS ();
11561143 }
11571144
1145+ int fetch_mode = how & ~PDO_FETCH_FLAGS ;
1146+ if (fetch_mode == PDO_FETCH_KEY_PAIR ) {
1147+ array_init_size (return_value , 1 );
1148+ bool success = pdo_do_key_pair_fetch (stmt , ori , off , Z_ARRVAL_P (return_value ));
1149+ if (!success ) {
1150+ zval_dtor (return_value );
1151+ PDO_HANDLE_STMT_ERR ();
1152+ RETURN_FALSE ;
1153+ }
1154+ return ;
1155+ }
11581156 if (!do_fetch (stmt , return_value , how , ori , off , NULL )) {
11591157 PDO_HANDLE_STMT_ERR ();
11601158 RETURN_FALSE ;
@@ -1234,12 +1232,10 @@ PHP_METHOD(PDOStatement, fetchColumn)
12341232PHP_METHOD (PDOStatement , fetchAll )
12351233{
12361234 zend_long how = PDO_FETCH_USE_DEFAULT ;
1237- zval data , * return_all = NULL ;
12381235 zval * arg2 = NULL ;
12391236 zend_class_entry * old_ce ;
12401237 zval old_ctor_args , * ctor_args = NULL ;
1241- bool error = false;
1242- int flags , old_arg_count ;
1238+ uint32_t old_arg_count ;
12431239
12441240 ZEND_PARSE_PARAMETERS_START (0 , 3 )
12451241 Z_PARAM_OPTIONAL
@@ -1253,6 +1249,9 @@ PHP_METHOD(PDOStatement, fetchAll)
12531249 RETURN_THROWS ();
12541250 }
12551251
1252+ int fetch_mode = how & ~PDO_FETCH_FLAGS ;
1253+ int flags = how & PDO_FETCH_FLAGS ;
1254+
12561255 old_ce = stmt -> fetch .cls .ce ;
12571256 ZVAL_COPY_VALUE (& old_ctor_args , & stmt -> fetch .cls .ctor_args );
12581257 old_arg_count = stmt -> fetch .cls .fci .param_count ;
@@ -1261,7 +1260,7 @@ PHP_METHOD(PDOStatement, fetchAll)
12611260
12621261 /* TODO Would be good to reuse part of pdo_stmt_setup_fetch_mode() in some way */
12631262
1264- switch (how & ~ PDO_FETCH_FLAGS ) {
1263+ switch (fetch_mode ) {
12651264 case PDO_FETCH_CLASS :
12661265 /* Figure out correct class */
12671266 if (arg2 ) {
@@ -1328,7 +1327,7 @@ PHP_METHOD(PDOStatement, fetchAll)
13281327 }
13291328 stmt -> fetch .column = Z_LVAL_P (arg2 );
13301329 } else {
1331- stmt -> fetch .column = how & PDO_FETCH_GROUP ? -1 : 0 ;
1330+ stmt -> fetch .column = flags & PDO_FETCH_GROUP ? -1 : 0 ;
13321331 }
13331332 break ;
13341333
@@ -1343,34 +1342,47 @@ PHP_METHOD(PDOStatement, fetchAll)
13431342 }
13441343 }
13451344
1346- flags = how & PDO_FETCH_FLAGS ;
13471345
1348- if (( how & ~ PDO_FETCH_FLAGS ) == PDO_FETCH_USE_DEFAULT ) {
1346+ if (fetch_mode == PDO_FETCH_USE_DEFAULT ) {
13491347 flags |= stmt -> default_fetch_type & PDO_FETCH_FLAGS ;
1350- how |= stmt -> default_fetch_type & ~PDO_FETCH_FLAGS ;
1348+ fetch_mode = stmt -> default_fetch_type & ~PDO_FETCH_FLAGS ;
1349+ how = fetch_mode | flags ;
13511350 }
13521351
13531352 PDO_STMT_CLEAR_ERR ();
1354- if ((how & PDO_FETCH_GROUP ) || how == PDO_FETCH_KEY_PAIR ||
1355- (how == PDO_FETCH_USE_DEFAULT && stmt -> default_fetch_type == PDO_FETCH_KEY_PAIR )
1356- ) {
1357- array_init (return_value );
1358- return_all = return_value ;
1359- }
1360- if (!do_fetch (stmt , & data , how | flags , PDO_FETCH_ORI_NEXT , /* offset */ 0 , return_all )) {
1361- error = true;
1353+
1354+ zval data , group_key ;
1355+
1356+ array_init (return_value );
1357+
1358+ if (fetch_mode == PDO_FETCH_KEY_PAIR ) {
1359+ while (pdo_do_key_pair_fetch (stmt , PDO_FETCH_ORI_NEXT , /* offset */ 0 , Z_ARRVAL_P (return_value )));
1360+ PDO_HANDLE_STMT_ERR ();
1361+ return ;
13621362 }
13631363
1364- if (!error ) {
1365- if ((how & PDO_FETCH_GROUP ) || how == PDO_FETCH_KEY_PAIR ||
1366- (how == PDO_FETCH_USE_DEFAULT && stmt -> default_fetch_type == PDO_FETCH_KEY_PAIR )
1367- ) {
1368- while (do_fetch (stmt , & data , how | flags , PDO_FETCH_ORI_NEXT , /* offset */ 0 , return_all ));
1369- } else {
1370- array_init (return_value );
1371- do {
1372- zend_hash_next_index_insert_new (Z_ARRVAL_P (return_value ), & data );
1373- } while (do_fetch (stmt , & data , how | flags , PDO_FETCH_ORI_NEXT , /* offset */ 0 , NULL ));
1364+ // Need to handle the "broken" PDO_FETCH_GROUP|PDO_FETCH_UNIQUE fetch case
1365+ //if (flags == PDO_FETCH_GROUP || flags == PDO_FETCH_UNIQUE) {
1366+ if (flags & PDO_FETCH_GROUP || flags & PDO_FETCH_UNIQUE ) {
1367+ while (do_fetch (stmt , & data , how | flags , PDO_FETCH_ORI_NEXT , /* offset */ 0 , & group_key )) {
1368+ ZEND_ASSERT (Z_TYPE (group_key ) == IS_STRING );
1369+ if ((flags & PDO_FETCH_UNIQUE ) == PDO_FETCH_UNIQUE ) {
1370+ zend_symtable_update (Z_ARRVAL_P (return_value ), Z_STR (group_key ), & data );
1371+ } else {
1372+ zval * group_ptr = zend_symtable_find (Z_ARRVAL_P (return_value ), Z_STR (group_key ));
1373+ zval group ;
1374+ if (group_ptr == NULL ) {
1375+ group_ptr = & group ;
1376+ array_init (group_ptr );
1377+ zend_symtable_update (Z_ARRVAL_P (return_value ), Z_STR (group_key ), group_ptr );
1378+ }
1379+ zend_hash_next_index_insert (Z_ARRVAL_P (group_ptr ), & data );
1380+ }
1381+ zval_ptr_dtor_str (& group_key );
1382+ }
1383+ } else {
1384+ while (do_fetch (stmt , & data , how , PDO_FETCH_ORI_NEXT , /* offset */ 0 , NULL )) {
1385+ zend_hash_next_index_insert_new (Z_ARRVAL_P (return_value ), & data );
13741386 }
13751387 }
13761388
@@ -1381,13 +1393,7 @@ PHP_METHOD(PDOStatement, fetchAll)
13811393 ZVAL_COPY_VALUE (& stmt -> fetch .cls .ctor_args , & old_ctor_args );
13821394 stmt -> fetch .cls .fci .param_count = old_arg_count ;
13831395
1384- /* on no results, return an empty array */
1385- if (error ) {
1386- PDO_HANDLE_STMT_ERR ();
1387- if (Z_TYPE_P (return_value ) != IS_ARRAY ) {
1388- array_init (return_value );
1389- }
1390- }
1396+ PDO_HANDLE_STMT_ERR ();
13911397}
13921398/* }}} */
13931399
0 commit comments