@@ -693,7 +693,7 @@ static bool do_fetch(pdo_stmt_t *stmt, zval *return_value, enum pdo_fetch_type h
693693 if (how == PDO_FETCH_COLUMN ) {
694694 int colno = stmt -> fetch .column ;
695695
696- if ((flags & PDO_FETCH_GROUP ) && stmt -> fetch .column == -1 ) {
696+ if ((flags & ( PDO_FETCH_GROUP | PDO_FETCH_UNIQUE ) ) && stmt -> fetch .column == -1 ) {
697697 colno = 1 ;
698698 }
699699
@@ -946,59 +946,81 @@ static bool do_fetch(pdo_stmt_t *stmt, zval *return_value, enum pdo_fetch_type h
946946
947947
948948// TODO Error on the following cases:
949- // Using any fetch flag with PDO_FETCH_KEY_PAIR
950949// 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
955950// 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 ) /* {{{ */
957952{
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 ) {
963955 zend_argument_value_error (mode_arg_num , "must be a bitmask of PDO::FETCH_* constants" );
964- return 0 ;
956+ return false ;
965957 }
966958
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+
967962 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 ;
970965 }
971966
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 ) {
973989 case PDO_FETCH_FUNC :
974990 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 ;
977993 }
978- return 1 ;
994+ return true ;
979995
980996 case PDO_FETCH_LAZY :
981997 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;
9901000 }
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;
9941007 }
995- ZEND_FALLTHROUGH ;
1008+ return true ;
9961009
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 :
9971016 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;
10021024 }
10031025}
10041026/* }}} */
@@ -1020,7 +1042,7 @@ PHP_METHOD(PDOStatement, fetch)
10201042 PHP_STMT_GET_OBJ ;
10211043 PDO_STMT_CLEAR_ERR ();
10221044
1023- if (!pdo_stmt_verify_mode (stmt , how , 1 , false)) {
1045+ if (!pdo_verify_fetch_mode (stmt -> default_fetch_type , how , 1 , false)) {
10241046 RETURN_THROWS ();
10251047 }
10261048
@@ -1140,7 +1162,7 @@ PHP_METHOD(PDOStatement, fetchAll)
11401162 ZEND_PARSE_PARAMETERS_END ();
11411163
11421164 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)) {
11441166 RETURN_THROWS ();
11451167 }
11461168
@@ -1215,7 +1237,7 @@ PHP_METHOD(PDOStatement, fetchAll)
12151237 }
12161238 stmt -> fetch .column = Z_LVAL_P (arg2 );
12171239 } else {
1218- stmt -> fetch .column = flags & PDO_FETCH_GROUP ? -1 : 0 ;
1240+ stmt -> fetch .column = flags & ( PDO_FETCH_GROUP | PDO_FETCH_UNIQUE ) ? -1 : 0 ;
12191241 }
12201242 break ;
12211243
@@ -1606,7 +1628,7 @@ bool pdo_stmt_setup_fetch_mode(pdo_stmt_t *stmt, zend_long mode, uint32_t mode_a
16061628
16071629 flags = mode & PDO_FETCH_FLAGS ;
16081630
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)) {
16101632 return false;
16111633 }
16121634
0 commit comments