@@ -693,7 +693,7 @@ static bool do_fetch(pdo_stmt_t *stmt, zval *return_value, enum pdo_fetch_type h
693
693
if (how == PDO_FETCH_COLUMN ) {
694
694
int colno = stmt -> fetch .column ;
695
695
696
- if ((flags & PDO_FETCH_GROUP ) && stmt -> fetch .column == -1 ) {
696
+ if ((flags & ( PDO_FETCH_GROUP | PDO_FETCH_UNIQUE ) ) && stmt -> fetch .column == -1 ) {
697
697
colno = 1 ;
698
698
}
699
699
@@ -946,59 +946,81 @@ static bool do_fetch(pdo_stmt_t *stmt, zval *return_value, enum pdo_fetch_type h
946
946
947
947
948
948
// TODO Error on the following cases:
949
- // Using any fetch flag with PDO_FETCH_KEY_PAIR
950
949
// Combining PDO_FETCH_UNIQUE and PDO_FETCH_GROUP
951
- // Using PDO_FETCH_UNIQUE or PDO_FETCH_GROUP outside of fetchAll()
952
- // Combining PDO_FETCH_PROPS_LATE with a fetch mode different than PDO_FETCH_CLASS
953
- // Improve error detection when combining PDO_FETCH_USE_DEFAULT with
954
- // Reject PDO_FETCH_INTO mode with fetch_all as no support
955
950
// Reject $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, value); bypass
956
- static bool pdo_stmt_verify_mode ( pdo_stmt_t * stmt , zend_long mode , uint32_t mode_arg_num , bool fetch_all ) /* {{{ */
951
+ static bool pdo_verify_fetch_mode ( uint32_t default_mode_and_flags , zend_long mode_and_flags , uint32_t mode_arg_num , bool fetch_all ) /* {{{ */
957
952
{
958
- int flags = mode & PDO_FETCH_FLAGS ;
959
-
960
- mode = mode & ~PDO_FETCH_FLAGS ;
961
-
962
- if (mode < 0 || mode >= PDO_FETCH__MAX ) {
953
+ /* Mode must be a positive */
954
+ if (mode_and_flags < 0 || mode_and_flags >= PDO_FIRST_INVALID_FLAG ) {
963
955
zend_argument_value_error (mode_arg_num , "must be a bitmask of PDO::FETCH_* constants" );
964
- return 0 ;
956
+ return false ;
965
957
}
966
958
959
+ uint32_t flags = (zend_ulong )mode_and_flags & PDO_FETCH_FLAGS ;
960
+ enum pdo_fetch_type mode = (zend_ulong )mode_and_flags & ~PDO_FETCH_FLAGS ;
961
+
967
962
if (mode == PDO_FETCH_USE_DEFAULT ) {
968
- flags = stmt -> default_fetch_type & PDO_FETCH_FLAGS ;
969
- mode = stmt -> default_fetch_type & ~PDO_FETCH_FLAGS ;
963
+ flags = default_mode_and_flags & PDO_FETCH_FLAGS ;
964
+ mode = default_mode_and_flags & ~PDO_FETCH_FLAGS ;
970
965
}
971
966
972
- switch (mode ) {
967
+ /* Flags can only be used in limited circumstances */
968
+ if (flags != 0 ) {
969
+ bool has_class_flags = (flags & (PDO_FETCH_CLASSTYPE |PDO_FETCH_PROPS_LATE |PDO_FETCH_SERIALIZE )) != 0 ;
970
+ if (has_class_flags && mode != PDO_FETCH_CLASS ) {
971
+ zend_argument_value_error (mode_arg_num , "cannot use PDO::FETCH_CLASSTYPE, PDO::FETCH_PROPS_LATE, or PDO::FETCH_SERIALIZE fetch flags with a fetch mode different than PDO::FETCH_CLASS" );
972
+ return false;
973
+ }
974
+ // TODO Prevent setting those flags together or not? This would affect PDO::setFetchMode()
975
+ //bool has_grouping_flags = flags & (PDO_FETCH_GROUP|PDO_FETCH_UNIQUE);
976
+ //if (has_grouping_flags && !fetch_all) {
977
+ // zend_argument_value_error(mode_arg_num, "cannot use PDO::FETCH_GROUP, or PDO::FETCH_UNIQUE fetch flags outside of PDOStatemnt::fetchAll()");
978
+ // return false;
979
+ //}
980
+ if (flags & PDO_FETCH_SERIALIZE ) {
981
+ php_error_docref (NULL , E_DEPRECATED , "The PDO::FETCH_SERIALIZE mode is deprecated" );
982
+ if (UNEXPECTED (EG (exception ))) {
983
+ return false;
984
+ }
985
+ }
986
+ }
987
+
988
+ switch (mode ) {
973
989
case PDO_FETCH_FUNC :
974
990
if (!fetch_all ) {
975
- zend_value_error ( "Can only use PDO::FETCH_FUNC in PDOStatement::fetchAll()" );
976
- return 0 ;
991
+ zend_argument_value_error ( mode_arg_num , " PDO::FETCH_FUNC can only be used with PDOStatement::fetchAll()" );
992
+ return false ;
977
993
}
978
- return 1 ;
994
+ return true ;
979
995
980
996
case PDO_FETCH_LAZY :
981
997
if (fetch_all ) {
982
- zend_argument_value_error (mode_arg_num , "cannot be PDO::FETCH_LAZY in PDOStatement::fetchAll()" );
983
- return 0 ;
984
- }
985
- ZEND_FALLTHROUGH ;
986
- default :
987
- if ((flags & PDO_FETCH_SERIALIZE ) == PDO_FETCH_SERIALIZE ) {
988
- zend_argument_value_error (mode_arg_num , "must use PDO::FETCH_SERIALIZE with PDO::FETCH_CLASS" );
989
- return 0 ;
998
+ zend_argument_value_error (mode_arg_num , "PDO::FETCH_LAZY cannot be used with PDOStatement::fetchAll()" );
999
+ return false;
990
1000
}
991
- if ((flags & PDO_FETCH_CLASSTYPE ) == PDO_FETCH_CLASSTYPE ) {
992
- zend_argument_value_error (mode_arg_num , "must use PDO::FETCH_CLASSTYPE with PDO::FETCH_CLASS" );
993
- return 0 ;
1001
+ return true;
1002
+
1003
+ case PDO_FETCH_INTO :
1004
+ if (fetch_all ) {
1005
+ zend_argument_value_error (mode_arg_num , "PDO::FETCH_INTO cannot be used with PDOStatement::fetchAll()" );
1006
+ return false;
994
1007
}
995
- ZEND_FALLTHROUGH ;
1008
+ return true ;
996
1009
1010
+ case PDO_FETCH_ASSOC :
1011
+ case PDO_FETCH_NUM :
1012
+ case PDO_FETCH_BOTH :
1013
+ case PDO_FETCH_OBJ :
1014
+ case PDO_FETCH_BOUND :
1015
+ case PDO_FETCH_COLUMN :
997
1016
case PDO_FETCH_CLASS :
998
- if (flags & PDO_FETCH_SERIALIZE ) {
999
- php_error_docref (NULL , E_DEPRECATED , "The PDO::FETCH_SERIALIZE mode is deprecated" );
1000
- }
1001
- return 1 ;
1017
+ case PDO_FETCH_NAMED :
1018
+ case PDO_FETCH_KEY_PAIR :
1019
+ return true;
1020
+
1021
+ default :
1022
+ zend_argument_value_error (mode_arg_num , "must be a bitmask of PDO::FETCH_* constants" );
1023
+ return false;
1002
1024
}
1003
1025
}
1004
1026
/* }}} */
@@ -1020,7 +1042,7 @@ PHP_METHOD(PDOStatement, fetch)
1020
1042
PHP_STMT_GET_OBJ ;
1021
1043
PDO_STMT_CLEAR_ERR ();
1022
1044
1023
- if (!pdo_stmt_verify_mode (stmt , how , 1 , false)) {
1045
+ if (!pdo_verify_fetch_mode (stmt -> default_fetch_type , how , 1 , false)) {
1024
1046
RETURN_THROWS ();
1025
1047
}
1026
1048
@@ -1140,7 +1162,7 @@ PHP_METHOD(PDOStatement, fetchAll)
1140
1162
ZEND_PARSE_PARAMETERS_END ();
1141
1163
1142
1164
PHP_STMT_GET_OBJ ;
1143
- if (!pdo_stmt_verify_mode (stmt , how , 1 , true)) {
1165
+ if (!pdo_verify_fetch_mode (stmt -> default_fetch_type , how , 1 , true)) {
1144
1166
RETURN_THROWS ();
1145
1167
}
1146
1168
@@ -1215,7 +1237,7 @@ PHP_METHOD(PDOStatement, fetchAll)
1215
1237
}
1216
1238
stmt -> fetch .column = Z_LVAL_P (arg2 );
1217
1239
} else {
1218
- stmt -> fetch .column = flags & PDO_FETCH_GROUP ? -1 : 0 ;
1240
+ stmt -> fetch .column = flags & ( PDO_FETCH_GROUP | PDO_FETCH_UNIQUE ) ? -1 : 0 ;
1219
1241
}
1220
1242
break ;
1221
1243
@@ -1606,7 +1628,7 @@ bool pdo_stmt_setup_fetch_mode(pdo_stmt_t *stmt, zend_long mode, uint32_t mode_a
1606
1628
1607
1629
flags = mode & PDO_FETCH_FLAGS ;
1608
1630
1609
- if (!pdo_stmt_verify_mode (stmt , mode , mode_arg_num , false)) {
1631
+ if (!pdo_verify_fetch_mode (stmt -> default_fetch_type , mode , mode_arg_num , false)) {
1610
1632
return false;
1611
1633
}
1612
1634
0 commit comments