@@ -708,14 +708,38 @@ static void do_fetch_opt_finish(pdo_stmt_t *stmt, int free_ctor_agrs) /* {{{ */
708
708
}
709
709
/* }}} */
710
710
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
+
711
736
/* perform a fetch.
712
737
* 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 ) /* {{{ */
714
739
{
715
740
int flags , idx , old_arg_count = 0 ;
716
741
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 }};
719
743
int i = 0 ;
720
744
721
745
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
725
749
how = how & ~PDO_FETCH_FLAGS ;
726
750
727
751
if (!do_fetch_common (stmt , ori , offset )) {
728
- return 0 ;
752
+ return false ;
729
753
}
730
754
731
755
if (how == PDO_FETCH_BOUND ) {
732
756
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;
740
758
}
741
759
742
760
if (how == PDO_FETCH_LAZY ) {
743
761
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;
745
800
}
746
801
747
802
RETVAL_FALSE ;
@@ -752,47 +807,13 @@ static bool do_fetch(pdo_stmt_t *stmt, zval *return_value, enum pdo_fetch_type h
752
807
case PDO_FETCH_BOTH :
753
808
case PDO_FETCH_NUM :
754
809
case PDO_FETCH_NAMED :
755
- if (!return_all ) {
810
+ if (!group_key ) {
756
811
array_init_size (return_value , stmt -> column_count );
757
812
} else {
758
813
array_init (return_value );
759
814
}
760
815
break ;
761
816
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
-
796
817
case PDO_FETCH_OBJ :
797
818
object_init_ex (return_value , ZEND_STANDARD_CLASS_DEF_PTR );
798
819
break ;
@@ -889,18 +910,10 @@ static bool do_fetch(pdo_stmt_t *stmt, zval *return_value, enum pdo_fetch_type h
889
910
EMPTY_SWITCH_DEFAULT_CASE ();
890
911
}
891
912
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 ++ ;
904
917
}
905
918
906
919
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
912
925
zend_symtable_update (Z_ARRVAL_P (return_value ), stmt -> columns [i ].name , & val );
913
926
break ;
914
927
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
-
931
928
case PDO_FETCH_USE_DEFAULT :
932
929
case PDO_FETCH_BOTH :
933
930
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
1048
1045
pdo_raise_impl_error (stmt -> dbh , stmt , "HY000" , "could not call user-supplied function" );
1049
1046
return 0 ;
1050
1047
} 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 )) {
1055
1049
ZVAL_COPY_VALUE (return_value , & retval );
1056
1050
}
1057
1051
}
@@ -1064,26 +1058,19 @@ static bool do_fetch(pdo_stmt_t *stmt, zval *return_value, enum pdo_fetch_type h
1064
1058
break ;
1065
1059
}
1066
1060
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
-
1083
1061
return 1 ;
1084
1062
}
1085
1063
/* }}} */
1086
1064
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
1087
1074
static bool pdo_stmt_verify_mode (pdo_stmt_t * stmt , zend_long mode , uint32_t mode_arg_num , bool fetch_all ) /* {{{ */
1088
1075
{
1089
1076
int flags = mode & PDO_FETCH_FLAGS ;
@@ -1155,6 +1142,17 @@ PHP_METHOD(PDOStatement, fetch)
1155
1142
RETURN_THROWS ();
1156
1143
}
1157
1144
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
+ }
1158
1156
if (!do_fetch (stmt , return_value , how , ori , off , NULL )) {
1159
1157
PDO_HANDLE_STMT_ERR ();
1160
1158
RETURN_FALSE ;
@@ -1234,12 +1232,10 @@ PHP_METHOD(PDOStatement, fetchColumn)
1234
1232
PHP_METHOD (PDOStatement , fetchAll )
1235
1233
{
1236
1234
zend_long how = PDO_FETCH_USE_DEFAULT ;
1237
- zval data , * return_all = NULL ;
1238
1235
zval * arg2 = NULL ;
1239
1236
zend_class_entry * old_ce ;
1240
1237
zval old_ctor_args , * ctor_args = NULL ;
1241
- bool error = false;
1242
- int flags , old_arg_count ;
1238
+ uint32_t old_arg_count ;
1243
1239
1244
1240
ZEND_PARSE_PARAMETERS_START (0 , 3 )
1245
1241
Z_PARAM_OPTIONAL
@@ -1253,6 +1249,9 @@ PHP_METHOD(PDOStatement, fetchAll)
1253
1249
RETURN_THROWS ();
1254
1250
}
1255
1251
1252
+ int fetch_mode = how & ~PDO_FETCH_FLAGS ;
1253
+ int flags = how & PDO_FETCH_FLAGS ;
1254
+
1256
1255
old_ce = stmt -> fetch .cls .ce ;
1257
1256
ZVAL_COPY_VALUE (& old_ctor_args , & stmt -> fetch .cls .ctor_args );
1258
1257
old_arg_count = stmt -> fetch .cls .fci .param_count ;
@@ -1261,7 +1260,7 @@ PHP_METHOD(PDOStatement, fetchAll)
1261
1260
1262
1261
/* TODO Would be good to reuse part of pdo_stmt_setup_fetch_mode() in some way */
1263
1262
1264
- switch (how & ~ PDO_FETCH_FLAGS ) {
1263
+ switch (fetch_mode ) {
1265
1264
case PDO_FETCH_CLASS :
1266
1265
/* Figure out correct class */
1267
1266
if (arg2 ) {
@@ -1328,7 +1327,7 @@ PHP_METHOD(PDOStatement, fetchAll)
1328
1327
}
1329
1328
stmt -> fetch .column = Z_LVAL_P (arg2 );
1330
1329
} else {
1331
- stmt -> fetch .column = how & PDO_FETCH_GROUP ? -1 : 0 ;
1330
+ stmt -> fetch .column = flags & PDO_FETCH_GROUP ? -1 : 0 ;
1332
1331
}
1333
1332
break ;
1334
1333
@@ -1343,34 +1342,47 @@ PHP_METHOD(PDOStatement, fetchAll)
1343
1342
}
1344
1343
}
1345
1344
1346
- flags = how & PDO_FETCH_FLAGS ;
1347
1345
1348
- if (( how & ~ PDO_FETCH_FLAGS ) == PDO_FETCH_USE_DEFAULT ) {
1346
+ if (fetch_mode == PDO_FETCH_USE_DEFAULT ) {
1349
1347
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 ;
1351
1350
}
1352
1351
1353
1352
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 ;
1362
1362
}
1363
1363
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 );
1374
1386
}
1375
1387
}
1376
1388
@@ -1381,13 +1393,7 @@ PHP_METHOD(PDOStatement, fetchAll)
1381
1393
ZVAL_COPY_VALUE (& stmt -> fetch .cls .ctor_args , & old_ctor_args );
1382
1394
stmt -> fetch .cls .fci .param_count = old_arg_count ;
1383
1395
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 ();
1391
1397
}
1392
1398
/* }}} */
1393
1399
0 commit comments