From 455ae2880e44bb8372afcdd9cb3b52f1042fa59e Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Wed, 1 Apr 2026 23:40:25 +0200 Subject: [PATCH 1/8] Fix function JIT JMPNZ smart branch When a smart branch and jump live in separate basic blocks, the JIT can't skip the jitting of the jump, as it may be reachable through another predecessor. When the smart branch is executed using zend_jit_handler(), we're manually writing the result of the branch to the given temporary so that the jump will work as expected. That happens in zend_jit_set_cond(). However, this was only correctly handled for JMPZ branches. The current opline was compared to opline following the jump, which would set the var to 1 if equal, i.e. the branch was not taken, meaning var was not zero. For JMPNZ we need to do the opposite. Fixes GH-21593 --- NEWS | 1 + ext/opcache/jit/zend_jit.c | 2 +- ext/opcache/jit/zend_jit_ir.c | 5 +-- ext/opcache/tests/jit/gh21593.phpt | 49 ++++++++++++++++++++++++++++++ 4 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 ext/opcache/tests/jit/gh21593.phpt diff --git a/NEWS b/NEWS index b9dffade35db8..2472825c0dab5 100644 --- a/NEWS +++ b/NEWS @@ -16,6 +16,7 @@ PHP NEWS - Opcache: . Fixed bug GH-21158 (JIT: Assertion jit->ra[var].flags & (1<<0) failed in zend_jit_use_reg). (Arnaud) + . Fixed bug GH-21593 (Borked function JIT JMPNZ smart branch). (ilutov) - SPL: . Fixed bug GH-21499 (RecursiveArrayIterator getChildren UAF after parent diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index 19e5520b1569e..da73c98c43552 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -2748,7 +2748,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op if (i == end && (opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) { /* smart branch split across basic blocks */ - if (!zend_jit_set_cond(&ctx, opline + 2, opline->result.var)) { + if (!zend_jit_set_cond(&ctx, opline, opline + 2, opline->result.var)) { goto jit_failure; } } diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c index 2bad605c537d0..4251d6b891c94 100644 --- a/ext/opcache/jit/zend_jit_ir.c +++ b/ext/opcache/jit/zend_jit_ir.c @@ -4105,11 +4105,12 @@ static int zend_jit_cond_jmp(zend_jit_ctx *jit, const zend_op *next_opline, int return 1; } -static int zend_jit_set_cond(zend_jit_ctx *jit, const zend_op *next_opline, uint32_t var) +static int zend_jit_set_cond(zend_jit_ctx *jit, const zend_op *opline, const zend_op *next_opline, uint32_t var) { ir_ref ref; - ref = ir_ADD_U32(ir_ZEXT_U32(jit_CMP_IP(jit, IR_EQ, next_opline)), ir_CONST_U32(IS_FALSE)); + ir_op op = (opline->result_type & IS_SMART_BRANCH_JMPZ) ? IR_EQ : IR_NE; + ref = ir_ADD_U32(ir_ZEXT_U32(jit_CMP_IP(jit, op, next_opline)), ir_CONST_U32(IS_FALSE)); // EX_VAR(var) = ... ir_STORE(ir_ADD_OFFSET(jit_FP(jit), var + offsetof(zval, u1.type_info)), ref); diff --git a/ext/opcache/tests/jit/gh21593.phpt b/ext/opcache/tests/jit/gh21593.phpt new file mode 100644 index 0000000000000..d37500195737d --- /dev/null +++ b/ext/opcache/tests/jit/gh21593.phpt @@ -0,0 +1,49 @@ +--TEST-- +GH-21593: Function JIT JMPNZ smart branch +--CREDITS-- +paulmhh +--EXTENSIONS-- +opcache +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.jit=function +--FILE-- +a)) { + echo "1\n"; + } +} + +function test2($a) { + if (!isset($a?->a)) { + echo "2\n"; + } +} + +function test3($a) { + if (empty($a?->a)) { + echo "3\n"; + } +} + +function test4($a) { + if (!empty($a?->a)) { + echo "4\n"; + } +} + +$a = new stdClass; +$a->a = 'a'; + +test1($a); +test2($a); +test3($a); +test4($a); + +?> +--EXPECT-- +1 +4 From 818bc8a17738ac2a44f7f3978b21429429bb7f9e Mon Sep 17 00:00:00 2001 From: Weilin Du <108666168+LamentXU123@users.noreply.github.com> Date: Thu, 2 Apr 2026 21:47:39 +0800 Subject: [PATCH 2/8] ext/pgsql: Remove unnecessary `+1` in memcpy when appending newline (GH-21597) --- ext/pgsql/pgsql.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/pgsql/pgsql.c b/ext/pgsql/pgsql.c index 3f4b606b5106e..2ddbf0af23095 100644 --- a/ext/pgsql/pgsql.c +++ b/ext/pgsql/pgsql.c @@ -3429,7 +3429,7 @@ static zend_result pgsql_copy_from_query(PGconn *pgsql, PGresult *pgsql_result, int result; if (ZSTR_LEN(tmp) > 0 && ZSTR_VAL(tmp)[ZSTR_LEN(tmp) - 1] != '\n') { char *zquery = emalloc(ZSTR_LEN(tmp) + 2); - memcpy(zquery, ZSTR_VAL(tmp), ZSTR_LEN(tmp) + 1); + memcpy(zquery, ZSTR_VAL(tmp), ZSTR_LEN(tmp)); zquery[ZSTR_LEN(tmp)] = '\n'; zquery[ZSTR_LEN(tmp) + 1] = '\0'; result = PQputCopyData(pgsql, zquery, ZSTR_LEN(tmp) + 1); From 266f85f4e89957a02142f5fc9baea723d57bd90b Mon Sep 17 00:00:00 2001 From: Jordi Kroon Date: Thu, 2 Apr 2026 17:04:56 +0200 Subject: [PATCH 3/8] replace ERR_NUM_ERRORS with PHP_OPENSSL_ERR_BUFFER_SIZE (#21579) --- ext/openssl/openssl.c | 6 +++--- ext/openssl/php_openssl.h | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index bc00b6b189b9b..4baa199888914 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -218,9 +218,9 @@ void php_openssl_store_errors(void) errors = OPENSSL_G(errors); do { - errors->top = (errors->top + 1) % ERR_NUM_ERRORS; + errors->top = (errors->top + 1) % PHP_OPENSSL_ERR_BUFFER_SIZE; if (errors->top == errors->bottom) { - errors->bottom = (errors->bottom + 1) % ERR_NUM_ERRORS; + errors->bottom = (errors->bottom + 1) % PHP_OPENSSL_ERR_BUFFER_SIZE; } errors->buffer[errors->top] = error_code; } while ((error_code = ERR_get_error())); @@ -4042,7 +4042,7 @@ PHP_FUNCTION(openssl_error_string) RETURN_FALSE; } - OPENSSL_G(errors)->bottom = (OPENSSL_G(errors)->bottom + 1) % ERR_NUM_ERRORS; + OPENSSL_G(errors)->bottom = (OPENSSL_G(errors)->bottom + 1) % PHP_OPENSSL_ERR_BUFFER_SIZE; val = OPENSSL_G(errors)->buffer[OPENSSL_G(errors)->bottom]; if (val) { diff --git a/ext/openssl/php_openssl.h b/ext/openssl/php_openssl.h index 92ccd9a546f9e..e565707a3c403 100644 --- a/ext/openssl/php_openssl.h +++ b/ext/openssl/php_openssl.h @@ -36,6 +36,8 @@ extern zend_module_entry openssl_module_entry; #define PHP_OPENSSL_API_VERSION 0x30200 #endif +#define PHP_OPENSSL_ERR_BUFFER_SIZE 16 + #define OPENSSL_RAW_DATA 1 #define OPENSSL_ZERO_PADDING 2 #define OPENSSL_DONT_ZERO_PAD_KEY 4 @@ -65,7 +67,7 @@ extern zend_module_entry openssl_module_entry; #endif struct php_openssl_errors { - int buffer[ERR_NUM_ERRORS]; + int buffer[PHP_OPENSSL_ERR_BUFFER_SIZE]; int top; int bottom; }; From eab1c01b481d6bf9c9f04514c244e17293f7cdbf Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 2 Apr 2026 16:56:12 +0100 Subject: [PATCH 4/8] ext/standard/tests/filters: add missing CTYPE extension requirement (#21581) --- ext/standard/tests/filters/user_filter_seek_01.phpt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ext/standard/tests/filters/user_filter_seek_01.phpt b/ext/standard/tests/filters/user_filter_seek_01.phpt index cb4e9fe72267f..31ec95ca6aa64 100644 --- a/ext/standard/tests/filters/user_filter_seek_01.phpt +++ b/ext/standard/tests/filters/user_filter_seek_01.phpt @@ -1,5 +1,7 @@ --TEST-- php_user_filter with seek method - always seekable (stateless filter) +--EXTENSIONS-- +ctype --FILE-- Date: Thu, 2 Apr 2026 18:49:33 +0200 Subject: [PATCH 5/8] [RFC] Add DocComments for function parameters (#21279) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RFC: https://wiki.php.net/rfc/parameter-doccomments --------- Co-authored-by: Christian Schneider Co-authored-by: Tim Düsterhus Co-authored-by: Daniel Scherzer --- NEWS | 1 + UPGRADING | 2 + Zend/zend_API.c | 1 + Zend/zend_compile.c | 2 + Zend/zend_compile.h | 1 + Zend/zend_language_parser.y | 6 +- Zend/zend_opcode.c | 3 + ext/opcache/zend_persist.c | 3 + ext/opcache/zend_persist_calc.c | 3 + ext/reflection/php_reflection.c | 16 ++ ext/reflection/php_reflection.stub.php | 2 + ext/reflection/php_reflection_arginfo.h | 12 +- ext/reflection/php_reflection_decl.h | 8 +- ...flectionParameter_getDocComment_basic.phpt | 248 ++++++++++++++++++ ...ctionParameter_getDocComment_indented.phpt | 84 ++++++ ...arameter_getDocComment_property_hooks.phpt | 143 ++++++++++ 16 files changed, 524 insertions(+), 11 deletions(-) create mode 100644 ext/reflection/tests/ReflectionParameter_getDocComment_basic.phpt create mode 100644 ext/reflection/tests/ReflectionParameter_getDocComment_indented.phpt create mode 100644 ext/reflection/tests/ReflectionParameter_getDocComment_property_hooks.phpt diff --git a/NEWS b/NEWS index 44f53eb99c7ae..bb7df3d41c973 100644 --- a/NEWS +++ b/NEWS @@ -100,6 +100,7 @@ PHP NEWS (ilutov) . Fixed bug GH-21362 (ReflectionMethod::invoke/invokeArgs() did not verify Closure instance identity for Closure::__invoke()). (Ilia Alshanetsky) + . Added ReflectionParameter::getDocComment(). (chschneider) - Session: . Fixed bug 71162 (updateTimestamp never called when session data is empty). diff --git a/UPGRADING b/UPGRADING index 8c312f1814a02..560e0a5eca872 100644 --- a/UPGRADING +++ b/UPGRADING @@ -144,6 +144,8 @@ PHP 8.6 UPGRADE NOTES . ReflectionConstant::inNamespace() . Added ReflectionProperty::isReadable() and ReflectionProperty::isWritable(). RFC: https://wiki.php.net/rfc/isreadable-iswriteable + . Added ReflectionParameter::getDocComment(). + RFC: https://wiki.php.net/rfc/parameter-doccomments - Intl: . `grapheme_strrev()` returns strrev for grapheme cluster unit. diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 211a5d14e6c3a..bd3f89a245025 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -2997,6 +2997,7 @@ ZEND_API void zend_convert_internal_arg_info(zend_arg_info *new_arg_info, const new_arg_info->name = NULL; new_arg_info->default_value = NULL; } + new_arg_info->doc_comment = NULL; new_arg_info->type = arg_info->type; zend_convert_internal_arg_info_type(&new_arg_info->type, persistent); } diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index ab6f2fb1e98fc..6734db09a2e9d 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -8027,6 +8027,7 @@ static void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32 } else { arg_infos->type = (zend_type) ZEND_TYPE_INIT_CODE(fallback_return_type, 0, 0); } + arg_infos->doc_comment = NULL; arg_infos++; op_array->fn_flags |= ZEND_ACC_HAS_RETURN_TYPE; @@ -8125,6 +8126,7 @@ static void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32 arg_info->name = zend_string_copy(name); arg_info->type = (zend_type) ZEND_TYPE_INIT_NONE(0); arg_info->default_value = NULL; + arg_info->doc_comment = doc_comment_ast ? zend_string_copy(zend_ast_get_str(doc_comment_ast)) : NULL; if (attributes_ast) { zend_compile_attributes( diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 5414467f3f874..abe2a53fe7448 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -515,6 +515,7 @@ typedef struct _zend_arg_info { zend_string *name; zend_type type; zend_string *default_value; + zend_string *doc_comment; } zend_arg_info; /* the following structure repeats the layout of zend_internal_arg_info, diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index e2686c7e1c5a8..57ebf02fe024e 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -821,9 +821,9 @@ parameter: { $$ = zend_ast_create_ex(ZEND_AST_PARAM, $1 | $3 | $4, $2, $5, NULL, NULL, $6 ? zend_ast_create_zval_from_str($6) : NULL, $7); } | optional_cpp_modifiers optional_type_without_static - is_reference is_variadic T_VARIABLE backup_doc_comment '=' expr optional_property_hook_list - { $$ = zend_ast_create_ex(ZEND_AST_PARAM, $1 | $3 | $4, $2, $5, $8, - NULL, $6 ? zend_ast_create_zval_from_str($6) : NULL, $9); } + is_reference is_variadic T_VARIABLE '=' expr backup_doc_comment optional_property_hook_list + { $$ = zend_ast_create_ex(ZEND_AST_PARAM, $1 | $3 | $4, $2, $5, $7, + NULL, $8 ? zend_ast_create_zval_from_str($8) : NULL, $9); } ; optional_type_without_static: diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 24b480ad71e66..35de02b557298 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -648,6 +648,9 @@ ZEND_API void destroy_op_array(zend_op_array *op_array) if (arg_info[i].name) { zend_string_release_ex(arg_info[i].name, 0); } + if (arg_info[i].doc_comment) { + zend_string_release_ex(arg_info[i].doc_comment, 0); + } zend_type_release(arg_info[i].type, /* persistent */ false); } efree(arg_info); diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c index 9bc2496837ce4..568db085bb2c4 100644 --- a/ext/opcache/zend_persist.c +++ b/ext/opcache/zend_persist.c @@ -652,6 +652,9 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc zend_accel_store_interned_string(arg_info[i].name); } zend_persist_type(&arg_info[i].type); + if (arg_info[i].doc_comment) { + zend_accel_store_interned_string(arg_info[i].doc_comment); + } } if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) { arg_info++; diff --git a/ext/opcache/zend_persist_calc.c b/ext/opcache/zend_persist_calc.c index 0b0ff51d0d4df..657cc03eb3901 100644 --- a/ext/opcache/zend_persist_calc.c +++ b/ext/opcache/zend_persist_calc.c @@ -306,6 +306,9 @@ static void zend_persist_op_array_calc_ex(zend_op_array *op_array) ADD_INTERNED_STRING(arg_info[i].name); } zend_persist_type_calc(&arg_info[i].type); + if (arg_info[i].doc_comment) { + ADD_INTERNED_STRING(arg_info[i].doc_comment); + } } } diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 957339b869ef1..9665d14532846 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -2649,6 +2649,22 @@ ZEND_METHOD(ReflectionParameter, __toString) /* }}} */ +/* {{{ Returns the doc comment for this parameter */ +ZEND_METHOD(ReflectionParameter, getDocComment) +{ + reflection_object *intern; + parameter_reference *param; + + ZEND_PARSE_PARAMETERS_NONE(); + + GET_REFLECTION_OBJECT_PTR(param); + if (param->arg_info->doc_comment) { + RETURN_STR_COPY(param->arg_info->doc_comment); + } + RETURN_FALSE; +} +/* }}} */ + /* {{{ Returns this parameter's name */ ZEND_METHOD(ReflectionParameter, getName) { diff --git a/ext/reflection/php_reflection.stub.php b/ext/reflection/php_reflection.stub.php index b0273a3174f8e..dd605100f8ba7 100644 --- a/ext/reflection/php_reflection.stub.php +++ b/ext/reflection/php_reflection.stub.php @@ -652,6 +652,8 @@ public function __construct($function, int|string $param) {} public function __toString(): string {} + public function getDocComment(): string|false {} + /** @tentative-return-type */ public function getName(): string {} diff --git a/ext/reflection/php_reflection_arginfo.h b/ext/reflection/php_reflection_arginfo.h index 66605a22bbd66..65571f38d43c7 100644 --- a/ext/reflection/php_reflection_arginfo.h +++ b/ext/reflection/php_reflection_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit php_reflection.stub.php instead. - * Stub hash: 267472e2b726ca5e788eb5cc3e946bc9aa7c9c41 + * Stub hash: c80946cc8c8215bb6527e09bb71b3a97a76a6a98 * Has decl header: yes */ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_Reflection_getModifierNames, 0, 1, IS_ARRAY, 0) @@ -526,6 +526,9 @@ ZEND_END_ARG_INFO() #define arginfo_class_ReflectionParameter___toString arginfo_class_ReflectionFunction___toString +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_ReflectionParameter_getDocComment, 0, 0, MAY_BE_STRING|MAY_BE_FALSE) +ZEND_END_ARG_INFO() + #define arginfo_class_ReflectionParameter_getName arginfo_class_ReflectionFunctionAbstract_getName #define arginfo_class_ReflectionParameter_isPassedByReference arginfo_class_ReflectionFunctionAbstract_inNamespace @@ -721,13 +724,12 @@ ZEND_END_ARG_INFO() #define arginfo_class_ReflectionConstant_isDeprecated arginfo_class_ReflectionFunctionAbstract_hasTentativeReturnType -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_ReflectionConstant_getFileName, 0, 0, MAY_BE_STRING|MAY_BE_FALSE) -ZEND_END_ARG_INFO() +#define arginfo_class_ReflectionConstant_getFileName arginfo_class_ReflectionParameter_getDocComment ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_ReflectionConstant_getExtension, 0, 0, ReflectionExtension, 1) ZEND_END_ARG_INFO() -#define arginfo_class_ReflectionConstant_getExtensionName arginfo_class_ReflectionConstant_getFileName +#define arginfo_class_ReflectionConstant_getExtensionName arginfo_class_ReflectionParameter_getDocComment #define arginfo_class_ReflectionConstant___toString arginfo_class_ReflectionFunction___toString @@ -921,6 +923,7 @@ ZEND_METHOD(ReflectionClassConstant, hasType); ZEND_METHOD(ReflectionClassConstant, getType); ZEND_METHOD(ReflectionParameter, __construct); ZEND_METHOD(ReflectionParameter, __toString); +ZEND_METHOD(ReflectionParameter, getDocComment); ZEND_METHOD(ReflectionParameter, getName); ZEND_METHOD(ReflectionParameter, isPassedByReference); ZEND_METHOD(ReflectionParameter, canBePassedByValue); @@ -1237,6 +1240,7 @@ static const zend_function_entry class_ReflectionParameter_methods[] = { ZEND_RAW_FENTRY("__clone", zim_ReflectionClass___clone, arginfo_class_ReflectionParameter___clone, ZEND_ACC_PRIVATE, NULL, NULL) ZEND_ME(ReflectionParameter, __construct, arginfo_class_ReflectionParameter___construct, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionParameter, __toString, arginfo_class_ReflectionParameter___toString, ZEND_ACC_PUBLIC) + ZEND_ME(ReflectionParameter, getDocComment, arginfo_class_ReflectionParameter_getDocComment, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionParameter, getName, arginfo_class_ReflectionParameter_getName, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionParameter, isPassedByReference, arginfo_class_ReflectionParameter_isPassedByReference, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionParameter, canBePassedByValue, arginfo_class_ReflectionParameter_canBePassedByValue, ZEND_ACC_PUBLIC) diff --git a/ext/reflection/php_reflection_decl.h b/ext/reflection/php_reflection_decl.h index a5e8affd0beb1..a87e1635419bf 100644 --- a/ext/reflection/php_reflection_decl.h +++ b/ext/reflection/php_reflection_decl.h @@ -1,12 +1,12 @@ /* This is a generated file, edit php_reflection.stub.php instead. - * Stub hash: 267472e2b726ca5e788eb5cc3e946bc9aa7c9c41 */ + * Stub hash: c80946cc8c8215bb6527e09bb71b3a97a76a6a98 */ -#ifndef ZEND_PHP_REFLECTION_DECL_267472e2b726ca5e788eb5cc3e946bc9aa7c9c41_H -#define ZEND_PHP_REFLECTION_DECL_267472e2b726ca5e788eb5cc3e946bc9aa7c9c41_H +#ifndef ZEND_PHP_REFLECTION_DECL_c80946cc8c8215bb6527e09bb71b3a97a76a6a98_H +#define ZEND_PHP_REFLECTION_DECL_c80946cc8c8215bb6527e09bb71b3a97a76a6a98_H typedef enum zend_enum_PropertyHookType { ZEND_ENUM_PropertyHookType_Get = 1, ZEND_ENUM_PropertyHookType_Set = 2, } zend_enum_PropertyHookType; -#endif /* ZEND_PHP_REFLECTION_DECL_267472e2b726ca5e788eb5cc3e946bc9aa7c9c41_H */ +#endif /* ZEND_PHP_REFLECTION_DECL_c80946cc8c8215bb6527e09bb71b3a97a76a6a98_H */ diff --git a/ext/reflection/tests/ReflectionParameter_getDocComment_basic.phpt b/ext/reflection/tests/ReflectionParameter_getDocComment_basic.phpt new file mode 100644 index 0000000000000..46e47bf603248 --- /dev/null +++ b/ext/reflection/tests/ReflectionParameter_getDocComment_basic.phpt @@ -0,0 +1,248 @@ +--TEST-- +Test ReflectionParameter::getDocComment() usage. +--INI-- +opcache.save_comments=1 +--FILE-- +property = $value; } +} +} + +function global_function( + /** + * My Doc Comment for $a + * + */ + $a, $b, $c, + /** + * My Doc Comment for $d + */ + $d, + // Not a doc comment + /**Not a doc comment */ + $e, + /** + * Doc comment for $f + */ + $f, + $g /** Doc comment for $g after parameter */, + /** Doc comment for $h */ + $h /** Doc comment for $h after parameter */, +) {} + +$closure = function( + /** + * My Doc Comment for $a + * + */ + $a, $b, $c, + /** + * My Doc Comment for $d + */ + $d, + // Not a doc comment + /**Not a doc comment */ + $e, + /** + * Doc comment for $f + */ + $f, + $g /** Doc comment for $g after parameter */, + /** Doc comment for $h */ + $h /** Doc comment for $h after parameter */, +) {}; + +$arrow_function = fn( + /** + * My Doc Comment for $a + * + */ + $a, $b, $c, + /** + * My Doc Comment for $d + */ + $d, + // Not a doc comment + /**Not a doc comment */ + $e, + /** + * Doc comment for $f + */ + $f, + $g /** Doc comment for $g after parameter */, + /** Doc comment for $h */ + $h /** Doc comment for $h after parameter */, +) => true; + +foreach([ + 'A::method' => (new ReflectionClass('A'))->getMethod('method'), + 'global_function' => new ReflectionFunction('global_function'), + 'closure' => new ReflectionFunction($closure), + 'arrow_function' => new ReflectionFunction($arrow_function), + 'property hook' => (new ReflectionClass('A'))->getProperty('property')->getHook(PropertyHookType::Set), + ] as $function => $rc) { + $rps = $rc->getParameters(); + foreach($rps as $rp) { + echo "\n---> Doc comment for $function parameter $" . $rp->getName() . ":\n"; + var_dump($rp->getDocComment()); + } +} + +?> +--EXPECTF-- +---> Doc comment for A::method parameter $a: +string(%d) "/** + * My Doc Comment for $a + * + */" + +---> Doc comment for A::method parameter $b: +bool(false) + +---> Doc comment for A::method parameter $c: +bool(false) + +---> Doc comment for A::method parameter $d: +string(%d) "/** + * My Doc Comment for $d + */" + +---> Doc comment for A::method parameter $e: +bool(false) + +---> Doc comment for A::method parameter $f: +string(%d) "/** + * Doc comment for $f + */" + +---> Doc comment for A::method parameter $g: +string(%d) "/** Doc comment for $g after parameter */" + +---> Doc comment for A::method parameter $h: +string(%d) "/** Doc comment for $h after parameter */" + +---> Doc comment for global_function parameter $a: +string(%d) "/** + * My Doc Comment for $a + * + */" + +---> Doc comment for global_function parameter $b: +bool(false) + +---> Doc comment for global_function parameter $c: +bool(false) + +---> Doc comment for global_function parameter $d: +string(%d) "/** + * My Doc Comment for $d + */" + +---> Doc comment for global_function parameter $e: +bool(false) + +---> Doc comment for global_function parameter $f: +string(%d) "/** + * Doc comment for $f + */" + +---> Doc comment for global_function parameter $g: +string(%d) "/** Doc comment for $g after parameter */" + +---> Doc comment for global_function parameter $h: +string(%d) "/** Doc comment for $h after parameter */" + +---> Doc comment for closure parameter $a: +string(%d) "/** + * My Doc Comment for $a + * + */" + +---> Doc comment for closure parameter $b: +bool(false) + +---> Doc comment for closure parameter $c: +bool(false) + +---> Doc comment for closure parameter $d: +string(%d) "/** + * My Doc Comment for $d + */" + +---> Doc comment for closure parameter $e: +bool(false) + +---> Doc comment for closure parameter $f: +string(%d) "/** + * Doc comment for $f + */" + +---> Doc comment for closure parameter $g: +string(%d) "/** Doc comment for $g after parameter */" + +---> Doc comment for closure parameter $h: +string(%d) "/** Doc comment for $h after parameter */" + +---> Doc comment for arrow_function parameter $a: +string(%d) "/** + * My Doc Comment for $a + * + */" + +---> Doc comment for arrow_function parameter $b: +bool(false) + +---> Doc comment for arrow_function parameter $c: +bool(false) + +---> Doc comment for arrow_function parameter $d: +string(%d) "/** + * My Doc Comment for $d + */" + +---> Doc comment for arrow_function parameter $e: +bool(false) + +---> Doc comment for arrow_function parameter $f: +string(%d) "/** + * Doc comment for $f + */" + +---> Doc comment for arrow_function parameter $g: +string(%d) "/** Doc comment for $g after parameter */" + +---> Doc comment for arrow_function parameter $h: +string(%d) "/** Doc comment for $h after parameter */" + +---> Doc comment for property hook parameter $value: +string(%d) "/** Doc Comment for property hook parameter $value */" + diff --git a/ext/reflection/tests/ReflectionParameter_getDocComment_indented.phpt b/ext/reflection/tests/ReflectionParameter_getDocComment_indented.phpt new file mode 100644 index 0000000000000..ede7a00e0edd4 --- /dev/null +++ b/ext/reflection/tests/ReflectionParameter_getDocComment_indented.phpt @@ -0,0 +1,84 @@ +--TEST-- +Test ReflectionParameter::getDocComment() usage when methods are indented. +--INI-- +opcache.save_comments=1 +--FILE-- +property = $value; } + } +} + +foreach([ + 'A::method' => (new ReflectionClass('A'))->getMethod('method'), + 'property hook' => (new ReflectionClass('A'))->getProperty('property')->getHook(PropertyHookType::Set), + ] as $function => $rc) { + $rps = $rc->getParameters(); + foreach($rps as $rp) { + echo "\n---> Doc comment for $function parameter $" . $rp->getName() . ":\n"; + var_dump($rp->getDocComment()); + } +} + +?> +--EXPECTF-- +---> Doc comment for A::method parameter $a: +string(%d) "/** + * My Doc Comment for $a + * + */" + +---> Doc comment for A::method parameter $b: +bool(false) + +---> Doc comment for A::method parameter $c: +bool(false) + +---> Doc comment for A::method parameter $d: +string(%d) "/** + * My Doc Comment for $d + */" + +---> Doc comment for A::method parameter $e: +bool(false) + +---> Doc comment for A::method parameter $f: +string(%d) "/** + * Doc comment for $f + */" + +---> Doc comment for A::method parameter $g: +string(%d) "/** Doc comment for $g after parameter */" + +---> Doc comment for A::method parameter $h: +string(%d) "/** Doc comment for $h after parameter */" + +---> Doc comment for property hook parameter $value: +string(%d) "/** Doc Comment for property hook parameter $value */" diff --git a/ext/reflection/tests/ReflectionParameter_getDocComment_property_hooks.phpt b/ext/reflection/tests/ReflectionParameter_getDocComment_property_hooks.phpt new file mode 100644 index 0000000000000..5689a2c46acaf --- /dev/null +++ b/ext/reflection/tests/ReflectionParameter_getDocComment_property_hooks.phpt @@ -0,0 +1,143 @@ +--TEST-- +Test ReflectionParameter::getDocComment() usage for property with hook. +--INI-- +opcache.save_comments=1 +--FILE-- +getProperty('foo'); +echo "\n---> Doc comment for A::property $" . $rp->getName() . ":\n"; +var_dump($rp->getDocComment()); + +$rh = $rp->getHook(PropertyHookType::Get); +echo "\n---> Doc comment for A::property " . $rh->getName() . ":\n"; +var_dump($rh->getDocComment()); + +$rh = $rp->getHook(PropertyHookType::Set); +echo "\n---> Doc comment for A::property " . $rh->getName() . ":\n"; +var_dump($rh->getDocComment()); + +$rp = $rh->getParameters()[0]; +echo "\n---> Doc comment for A::property \$foo::set parameter $" . $rp->getName() . ":\n"; +var_dump($rp->getDocComment()); + +// --------- + +$rp = $rc->getConstructor()->getParameters()[1]; +echo "\n---> Doc comment for A::constructor parameter $" . $rp->getName() . ":\n"; +var_dump($rp->getDocComment()); + +$rp = $rc->getProperty('bar'); +echo "\n---> Doc comment for A::property $" . $rp->getName() . ":\n"; +var_dump($rp->getDocComment()); + +$rh = $rp->getHook(PropertyHookType::Get); +echo "\n---> Doc comment for A::property " . $rh->getName() . ":\n"; +var_dump($rh->getDocComment()); + +$rh = $rp->getHook(PropertyHookType::Set); +echo "\n---> Doc comment for A::property " . $rh->getName() . ":\n"; +var_dump($rh->getDocComment()); + +$rp = $rh->getParameters()[0]; +echo "\n---> Doc comment for A::property \$bar::set parameter $" . $rp->getName() . ":\n"; +var_dump($rp->getDocComment()); + +// --------- + +$rp = $rc->getConstructor()->getParameters()[2]; +echo "\n---> Doc comment for A::constructor parameter $" . $rp->getName() . ":\n"; +var_dump($rp->getDocComment()); + +$rp = $rc->getProperty('baz'); +echo "\n---> Doc comment for A::property $" . $rp->getName() . ":\n"; +var_dump($rp->getDocComment()); + +$rh = $rp->getHook(PropertyHookType::Get); +echo "\n---> Doc comment for A::property " . $rh->getName() . ":\n"; +var_dump($rh->getDocComment()); + +$rh = $rp->getHook(PropertyHookType::Set); +echo "\n---> Doc comment for A::property " . $rh->getName() . ":\n"; +var_dump($rh->getDocComment()); + +$rp = $rh->getParameters()[0]; +echo "\n---> Doc comment for A::property \$baz::set parameter $" . $rp->getName() . ":\n"; +var_dump($rp->getDocComment()); + +$rp = $rc->getConstructor()->getParameters()[0]; +echo "\n---> Doc comment for A::constructor parameter $" . $rp->getName() . ":\n"; +var_dump($rp->getDocComment()); + +?> +--EXPECTF-- +---> Doc comment for A::property $foo: +string(11) "/** $foo */" + +---> Doc comment for A::property $foo::get: +string(13) "/** getter */" + +---> Doc comment for A::property $foo::set: +string(13) "/** setter */" + +---> Doc comment for A::property $foo::set parameter $value: +string(13) "/** $value */" + +---> Doc comment for A::constructor parameter $bar: +string(11) "/** $bar */" + +---> Doc comment for A::property $bar: +string(11) "/** $bar */" + +---> Doc comment for A::property $bar::get: +string(13) "/** getter */" + +---> Doc comment for A::property $bar::set: +string(13) "/** setter */" + +---> Doc comment for A::property $bar::set parameter $value: +string(13) "/** $value */" + +---> Doc comment for A::constructor parameter $baz: +bool(false) + +---> Doc comment for A::property $baz: +bool(false) + +---> Doc comment for A::property $baz::get: +string(13) "/** getter */" + +---> Doc comment for A::property $baz::set: +string(13) "/** setter */" + +---> Doc comment for A::property $baz::set parameter $value: +string(13) "/** $value */" + +---> Doc comment for A::constructor parameter $foo: +string(11) "/** $foo */" From 3619caa0b1a9781aef6c8a59e0fa0f5da001b6f8 Mon Sep 17 00:00:00 2001 From: Peter Kokot Date: Thu, 2 Apr 2026 19:40:00 +0200 Subject: [PATCH 6/8] ext/{pdo_pgsql,pgsql}: Enable HAVE_PG_RESULT_MEMORY_SIZE (#21595) PQresultMemorySize is available since libpq 12. On Windows libpq 16.2 is used at time of writing: https://github.com/winlibs/postgresql --- ext/pdo_pgsql/config.w32 | 1 + ext/pgsql/config.w32 | 1 + 2 files changed, 2 insertions(+) diff --git a/ext/pdo_pgsql/config.w32 b/ext/pdo_pgsql/config.w32 index 5fc25f2159000..87ad0a661b534 100644 --- a/ext/pdo_pgsql/config.w32 +++ b/ext/pdo_pgsql/config.w32 @@ -7,6 +7,7 @@ if (PHP_PDO_PGSQL != "no") { CHECK_HEADER("libpq-fe.h", "CFLAGS_PDO_PGSQL", PHP_PDO_PGSQL + "\\include;" + PHP_PHP_BUILD + "\\include\\pgsql;" + PHP_PHP_BUILD + "\\include\\libpq;")) { EXTENSION("pdo_pgsql", "pdo_pgsql.c pgsql_driver.c pgsql_statement.c pgsql_sql_parser.c"); + AC_DEFINE('HAVE_PG_RESULT_MEMORY_SIZE', 1, "Define to 1 if libpq has the 'PQresultMemorySize' function (PostgreSQL 12 or later)."); AC_DEFINE('HAVE_PDO_PGSQL', 1, "Define to 1 if the PHP extension 'pdo_pgsql' is available."); ADD_EXTENSION_DEP('pdo_pgsql', 'pdo'); diff --git a/ext/pgsql/config.w32 b/ext/pgsql/config.w32 index 14eb5a07a0e9d..4c8d6f3bd7151 100644 --- a/ext/pgsql/config.w32 +++ b/ext/pgsql/config.w32 @@ -6,6 +6,7 @@ if (PHP_PGSQL != "no") { if (CHECK_LIB("libpq.lib", "pgsql", PHP_PGSQL) && CHECK_HEADER("libpq-fe.h", "CFLAGS_PGSQL", PHP_PGSQL + "\\include;" + PHP_PHP_BUILD + "\\include\\pgsql;" + PHP_PHP_BUILD + "\\include\\libpq;" + PHP_PGSQL)) { EXTENSION("pgsql", "pgsql.c", PHP_PGSQL_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); + AC_DEFINE('HAVE_PG_RESULT_MEMORY_SIZE', 1, "Define to 1 if libpq has the 'PQresultMemorySize' function (PostgreSQL 12 or later)."); AC_DEFINE('HAVE_PGSQL', 1, "Define to 1 if the PHP extension 'pgsql' is available."); ADD_FLAG("CFLAGS_PGSQL", "/D PGSQL_EXPORTS"); ADD_EXTENSION_DEP('pgsql', 'pcre'); From 32c1931f18109655bc074dd5cda3248b838de636 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Thu, 2 Apr 2026 21:19:27 +0200 Subject: [PATCH 7/8] standard: Add `enum SortDirection` (#21501) RFC: https://wiki.php.net/rfc/sort_direction_enum --- NEWS | 1 + UPGRADING | 4 ++++ .../ReflectionExtension_getClassNames_basic.phpt | 1 + ext/standard/array.c | 1 + ext/standard/basic_functions.c | 1 + ext/standard/basic_functions.stub.php | 5 +++++ ext/standard/basic_functions_arginfo.h | 13 ++++++++++++- ext/standard/basic_functions_decl.h | 13 +++++++++---- ext/standard/php_array.h | 2 ++ 9 files changed, 36 insertions(+), 5 deletions(-) diff --git a/NEWS b/NEWS index bb7df3d41c973..1759f6e2ee765 100644 --- a/NEWS +++ b/NEWS @@ -142,6 +142,7 @@ PHP NEWS . Fixed bug GH-13204 (glob() fails if square bracket is in current directory). (ndossche) . Add array size maximum to array_diff(). (ndossche) + . Add enum SortDirection. (timwolla) - Streams: . Added so_keepalive, tcp_keepidle, tcp_keepintvl and tcp_keepcnt stream diff --git a/UPGRADING b/UPGRADING index 560e0a5eca872..467387a9ea3c9 100644 --- a/UPGRADING +++ b/UPGRADING @@ -163,6 +163,10 @@ PHP 8.6 UPGRADE NOTES 7. New Classes and Interfaces ======================================== +- Standard: + . enum SortDirection + RFC: https://wiki.php.net/rfc/sort_direction_enum + ======================================== 8. Removed Extensions and SAPIs ======================================== diff --git a/ext/reflection/tests/ReflectionExtension_getClassNames_basic.phpt b/ext/reflection/tests/ReflectionExtension_getClassNames_basic.phpt index 47813255381e4..9d12107050967 100644 --- a/ext/reflection/tests/ReflectionExtension_getClassNames_basic.phpt +++ b/ext/reflection/tests/ReflectionExtension_getClassNames_basic.phpt @@ -15,6 +15,7 @@ foreach ($classNames as $className) { AssertionError Directory RoundingMode +SortDirection StreamBucket __PHP_Incomplete_Class php_user_filter diff --git a/ext/standard/array.c b/ext/standard/array.c index f391829c676ab..7aafe6ea0a176 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -60,6 +60,7 @@ /* }}} */ ZEND_DECLARE_MODULE_GLOBALS(array) +PHPAPI zend_class_entry *sort_direction_ce; /* {{{ php_array_init_globals */ static void php_array_init_globals(zend_array_globals *array_globals) diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index a7417f2a39036..04505db15833c 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -297,6 +297,7 @@ PHP_MINIT_FUNCTION(basic) /* {{{ */ assertion_error_ce = register_class_AssertionError(zend_ce_error); rounding_mode_ce = register_class_RoundingMode(); + sort_direction_ce = register_class_SortDirection(); BASIC_MINIT_SUBMODULE(var) BASIC_MINIT_SUBMODULE(file) diff --git a/ext/standard/basic_functions.stub.php b/ext/standard/basic_functions.stub.php index 6d0c565fc2d41..1f3d5617f8dfb 100644 --- a/ext/standard/basic_functions.stub.php +++ b/ext/standard/basic_functions.stub.php @@ -90,6 +90,11 @@ */ const SORT_FLAG_CASE = UNKNOWN; +enum SortDirection { + case Ascending; + case Descending; +} + /** * @var int * @cvalue PHP_CASE_LOWER diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index d0109fa27c960..991d76d91fc1c 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit basic_functions.stub.php instead. - * Stub hash: f5583557f058e4862750d1262296d7f59cb0eed0 + * Stub hash: 749c71a6220260eb3fb593b982a9d97821e0539b * Has decl header: yes */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0) @@ -3980,6 +3980,17 @@ static void register_basic_functions_symbols(int module_number) attribute_Deprecated_const_ASSERT_EXCEPTION_0->args[1].name = ZSTR_KNOWN(ZEND_STR_MESSAGE); } +static zend_class_entry *register_class_SortDirection(void) +{ + zend_class_entry *class_entry = zend_register_internal_enum("SortDirection", IS_UNDEF, NULL); + + zend_enum_add_case_cstr(class_entry, "Ascending", NULL); + + zend_enum_add_case_cstr(class_entry, "Descending", NULL); + + return class_entry; +} + static zend_class_entry *register_class___PHP_Incomplete_Class(void) { zend_class_entry ce, *class_entry; diff --git a/ext/standard/basic_functions_decl.h b/ext/standard/basic_functions_decl.h index 139b47f2444d4..fce41100fc79a 100644 --- a/ext/standard/basic_functions_decl.h +++ b/ext/standard/basic_functions_decl.h @@ -1,8 +1,13 @@ /* This is a generated file, edit basic_functions.stub.php instead. - * Stub hash: f5583557f058e4862750d1262296d7f59cb0eed0 */ + * Stub hash: 749c71a6220260eb3fb593b982a9d97821e0539b */ -#ifndef ZEND_BASIC_FUNCTIONS_DECL_f5583557f058e4862750d1262296d7f59cb0eed0_H -#define ZEND_BASIC_FUNCTIONS_DECL_f5583557f058e4862750d1262296d7f59cb0eed0_H +#ifndef ZEND_BASIC_FUNCTIONS_DECL_749c71a6220260eb3fb593b982a9d97821e0539b_H +#define ZEND_BASIC_FUNCTIONS_DECL_749c71a6220260eb3fb593b982a9d97821e0539b_H + +typedef enum zend_enum_SortDirection { + ZEND_ENUM_SortDirection_Ascending = 1, + ZEND_ENUM_SortDirection_Descending = 2, +} zend_enum_SortDirection; typedef enum zend_enum_RoundingMode { ZEND_ENUM_RoundingMode_HalfAwayFromZero = 1, @@ -15,4 +20,4 @@ typedef enum zend_enum_RoundingMode { ZEND_ENUM_RoundingMode_PositiveInfinity = 8, } zend_enum_RoundingMode; -#endif /* ZEND_BASIC_FUNCTIONS_DECL_f5583557f058e4862750d1262296d7f59cb0eed0_H */ +#endif /* ZEND_BASIC_FUNCTIONS_DECL_749c71a6220260eb3fb593b982a9d97821e0539b_H */ diff --git a/ext/standard/php_array.h b/ext/standard/php_array.h index 2205082e91dfd..a7eae0777d995 100644 --- a/ext/standard/php_array.h +++ b/ext/standard/php_array.h @@ -63,6 +63,8 @@ PHPAPI bool php_array_pick_keys(php_random_algo_with_state engine, zval *input, #define ARRAY_FILTER_USE_BOTH 1 #define ARRAY_FILTER_USE_KEY 2 +extern PHPAPI zend_class_entry *sort_direction_ce; + ZEND_BEGIN_MODULE_GLOBALS(array) bucket_compare_func_t *multisort_func; bool compare_deprecation_thrown; From 660996662a2649c73b6908deb7fec6d3b84a67a0 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Mon, 23 Mar 2026 01:04:24 +0100 Subject: [PATCH 8/8] Switch sqlite tests from "" to '' and re-enable for FreeBSD FreeBSD builds without DQS (double-quote support). Transform tests so we can re-eanble them for FreeBSD. Add separate tests for DQS. Closes GH-21495 --- .github/actions/freebsd/action.yml | 6 ++-- ext/pdo_sqlite/tests/bug38334.phpt | 8 +++--- ext/pdo_sqlite/tests/bug_42589.phpt | 2 +- .../tests/pdo_sqlite_createaggregate.phpt | 2 +- .../tests/pdo_sqlite_createcollation.phpt | 2 +- .../tests/pdo_sqlite_createfunction.phpt | 2 +- .../pdo_sqlite_createfunction_with_flags.phpt | 2 +- ext/pdo_sqlite/tests/pdo_sqlite_dqs.phpt | 27 ++++++++++++++++++ .../tests/pdo_sqlite_lastinsertid.phpt | 2 +- ext/pdo_sqlite/tests/pdo_sqlite_parser.phpt | 19 +++++++++++-- .../tests/pdo_sqlite_transaction.phpt | 2 +- ...pdo_sqlite_createafunction_trampoline.phpt | 8 +++--- .../pdo_sqlite_createaggregate.phpt | 2 +- .../pdo_sqlite_createcollation.phpt | 2 +- ...pdo_sqlite_createcollation_trampoline.phpt | 2 +- .../pdo_sqlite_createfunction_with_flags.phpt | 2 +- .../subclasses/pdo_sqlite_getattr_busy.phpt | 2 +- .../pdo_sqlite_getsetattr_explain.phpt | 28 +++++++++---------- .../tests/subclasses/pdosqlite_001.phpt | 4 +-- .../tests/subclasses/pdosqlite_002.phpt | 4 +-- ext/sqlite3/tests/bug72668.phpt | 6 ++-- .../tests/sqlite3_29_createfunction.phpt | 6 ++-- .../sqlite3_37_createfunction_flags.phpt | 6 ++-- ext/sqlite3/tests/sqlite3_dqs.phpt | 28 +++++++++++++++++++ ext/sqlite3/tests/sqlite3_explain.phpt | 28 +++++++++---------- ext/sqlite3/tests/sqlite3_rename_column.phpt | 2 +- ext/sqlite3/tests/sqlite3_stmt_busy.phpt | 2 +- .../sqlite3_trampoline_createfunction.phpt | 4 +-- 28 files changed, 139 insertions(+), 71 deletions(-) create mode 100644 ext/pdo_sqlite/tests/pdo_sqlite_dqs.phpt create mode 100644 ext/sqlite3/tests/sqlite3_dqs.phpt diff --git a/.github/actions/freebsd/action.yml b/.github/actions/freebsd/action.yml index 3b6d0c4e86178..197362d9f52b3 100644 --- a/.github/actions/freebsd/action.yml +++ b/.github/actions/freebsd/action.yml @@ -46,7 +46,7 @@ runs: pkgconf \ webp \ libavif \ - `#sqlite3` \ + sqlite3 \ curl \ $OPCACHE_TLS_TESTS_DEPS @@ -57,9 +57,7 @@ runs: --enable-debug \ --enable-option-checking=fatal \ --enable-fpm \ - `#--with-pdo-sqlite` \ - --without-sqlite3 \ - --without-pdo-sqlite \ + --with-pdo-sqlite \ --without-pear \ --with-bz2 \ --with-avif \ diff --git a/ext/pdo_sqlite/tests/bug38334.phpt b/ext/pdo_sqlite/tests/bug38334.phpt index b4e9a378d7174..eefd997cc71a4 100644 --- a/ext/pdo_sqlite/tests/bug38334.phpt +++ b/ext/pdo_sqlite/tests/bug38334.phpt @@ -7,11 +7,11 @@ pdo_sqlite $db = new PDO('sqlite::memory:'); $db->exec('CREATE TABLE test_38334 (i INTEGER , f DOUBLE, s VARCHAR(255))'); -$db->exec('INSERT INTO test_38334 VALUES (42, 46.7, "test")'); +$db->exec("INSERT INTO test_38334 VALUES (42, 46.7, 'test')"); var_dump($db->query('SELECT * FROM test_38334')->fetch(PDO::FETCH_ASSOC)); // Check handling of integers larger than 32-bit. -$db->exec('INSERT INTO test_38334 VALUES (10000000000, 0.0, "")'); +$db->exec("INSERT INTO test_38334 VALUES (10000000000, 0.0, '')"); $i = $db->query('SELECT i FROM test_38334 WHERE f = 0.0')->fetchColumn(0); if (PHP_INT_SIZE >= 8) { var_dump($i === 10000000000); @@ -20,8 +20,8 @@ if (PHP_INT_SIZE >= 8) { } // Check storing of strings into integer/float columns. -$db->exec('INSERT INTO test_38334 VALUES ("test", "test", "x")'); -var_dump($db->query('SELECT * FROM test_38334 WHERE s = "x"')->fetch(PDO::FETCH_ASSOC)); +$db->exec("INSERT INTO test_38334 VALUES ('test', 'test', 'x')"); +var_dump($db->query("SELECT * FROM test_38334 WHERE s = 'x'")->fetch(PDO::FETCH_ASSOC)); ?> --EXPECT-- diff --git a/ext/pdo_sqlite/tests/bug_42589.phpt b/ext/pdo_sqlite/tests/bug_42589.phpt index 46ded8d027a61..39b87b1065214 100644 --- a/ext/pdo_sqlite/tests/bug_42589.phpt +++ b/ext/pdo_sqlite/tests/bug_42589.phpt @@ -15,7 +15,7 @@ if(!in_array('ENABLE_COLUMN_METADATA', $options, true)) $db = new PDO("sqlite::memory:"); $db->exec('CREATE TABLE test_42589 (field1 VARCHAR(10))'); -$db->exec('INSERT INTO test_42589 VALUES("test")'); +$db->exec("INSERT INTO test_42589 VALUES('test')"); $result = $db->query('SELECT * FROM test_42589 t1 LEFT JOIN test_42589 t2 ON t1.field1 = t2.field1'); $meta1 = $result->getColumnMeta(0); diff --git a/ext/pdo_sqlite/tests/pdo_sqlite_createaggregate.phpt b/ext/pdo_sqlite/tests/pdo_sqlite_createaggregate.phpt index 1a620d6b9d5f6..cba2c49556f7b 100644 --- a/ext/pdo_sqlite/tests/pdo_sqlite_createaggregate.phpt +++ b/ext/pdo_sqlite/tests/pdo_sqlite_createaggregate.phpt @@ -9,7 +9,7 @@ $db = new PDO('sqlite::memory:'); $db->query('CREATE TABLE test_pdo_sqlite_createaggregate (id INT AUTO INCREMENT, name TEXT)'); -$db->query('INSERT INTO test_pdo_sqlite_createaggregate VALUES (NULL, "PHP"), (NULL, "PHP6")'); +$db->query("INSERT INTO test_pdo_sqlite_createaggregate VALUES (NULL, 'PHP'), (NULL, 'PHP6')"); $db->sqliteCreateAggregate('testing', function(&$a, $b) { $a .= $b; return $a; }, function(&$v) { return $v; }); diff --git a/ext/pdo_sqlite/tests/pdo_sqlite_createcollation.phpt b/ext/pdo_sqlite/tests/pdo_sqlite_createcollation.phpt index 14a2c2e0d0233..eb5ea6c97b7d9 100644 --- a/ext/pdo_sqlite/tests/pdo_sqlite_createcollation.phpt +++ b/ext/pdo_sqlite/tests/pdo_sqlite_createcollation.phpt @@ -10,7 +10,7 @@ $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $db->query('CREATE TABLE test_pdo_sqlite_createcollation (id INT AUTO INCREMENT, name TEXT)'); -$db->query('INSERT INTO test_pdo_sqlite_createcollation VALUES (NULL, "1"), (NULL, "2"), (NULL, "10")'); +$db->query("INSERT INTO test_pdo_sqlite_createcollation VALUES (NULL, '1'), (NULL, '2'), (NULL, '10')"); $db->sqliteCreateCollation('MYCOLLATE', function($a, $b) { return strnatcmp($a, $b); }); diff --git a/ext/pdo_sqlite/tests/pdo_sqlite_createfunction.phpt b/ext/pdo_sqlite/tests/pdo_sqlite_createfunction.phpt index b2cb073cb58f1..49daabf5a7a96 100644 --- a/ext/pdo_sqlite/tests/pdo_sqlite_createfunction.phpt +++ b/ext/pdo_sqlite/tests/pdo_sqlite_createfunction.phpt @@ -9,7 +9,7 @@ $db = new PDO('sqlite::memory:'); $db->query('CREATE TABLE test_pdo_sqlite_createfunction (id INT AUTO INCREMENT, name TEXT)'); -$db->query('INSERT INTO test_pdo_sqlite_createfunction VALUES (NULL, "PHP"), (NULL, "PHP6")'); +$db->query("INSERT INTO test_pdo_sqlite_createfunction VALUES (NULL, 'PHP'), (NULL, 'PHP6')"); $db->sqliteCreateFunction('testing', function($v) { return strtolower($v); }); diff --git a/ext/pdo_sqlite/tests/pdo_sqlite_createfunction_with_flags.phpt b/ext/pdo_sqlite/tests/pdo_sqlite_createfunction_with_flags.phpt index 6f507789dbf27..9f0c777e83d83 100644 --- a/ext/pdo_sqlite/tests/pdo_sqlite_createfunction_with_flags.phpt +++ b/ext/pdo_sqlite/tests/pdo_sqlite_createfunction_with_flags.phpt @@ -13,7 +13,7 @@ $db = new PDO('sqlite::memory:'); $db->query('CREATE TABLE test_pdo_sqlite_createfunction_with_flags (id INT AUTO INCREMENT, name TEXT)'); -$db->query('INSERT INTO test_pdo_sqlite_createfunction_with_flags VALUES (NULL, "PHP"), (NULL, "PHP6")'); +$db->query("INSERT INTO test_pdo_sqlite_createfunction_with_flags VALUES (NULL, 'PHP'), (NULL, 'PHP6')"); $db->sqliteCreateFunction('testing', function($v) { return strtolower($v); }, 1, Pdo\Sqlite::DETERMINISTIC); diff --git a/ext/pdo_sqlite/tests/pdo_sqlite_dqs.phpt b/ext/pdo_sqlite/tests/pdo_sqlite_dqs.phpt new file mode 100644 index 0000000000000..8ae6684284849 --- /dev/null +++ b/ext/pdo_sqlite/tests/pdo_sqlite_dqs.phpt @@ -0,0 +1,27 @@ +--TEST-- +PDO_sqlite: Testing DQS support +--EXTENSIONS-- +pdo_sqlite +--SKIPIF-- +exec('SELECT "test"'); +} catch (\PDOException) { + die('skip SQLite is lacking DQS'); +} +?> +--FILE-- +exec('CREATE TABLE test (s1 VARCHAR(255), s2 VARCHAR(255))'); +$db->exec('INSERT INTO test VALUES (\'test\', "test")'); +var_dump($db->query('SELECT * FROM test')->fetch(PDO::FETCH_ASSOC)); +?> +--EXPECT-- +array(2) { + ["s1"]=> + string(4) "test" + ["s2"]=> + string(4) "test" +} diff --git a/ext/pdo_sqlite/tests/pdo_sqlite_lastinsertid.phpt b/ext/pdo_sqlite/tests/pdo_sqlite_lastinsertid.phpt index 7e55ed60d5f1d..0f1cba84dcceb 100644 --- a/ext/pdo_sqlite/tests/pdo_sqlite_lastinsertid.phpt +++ b/ext/pdo_sqlite/tests/pdo_sqlite_lastinsertid.phpt @@ -7,7 +7,7 @@ pdo_sqlite $db = new PDO('sqlite::memory:'); $db->query('CREATE TABLE test_pdo_sqlite_lastinsertid (id INT AUTO INCREMENT, name TEXT)'); -$db->query('INSERT INTO test_pdo_sqlite_lastinsertid VALUES (NULL, "PHP"), (NULL, "PHP6")'); +$db->query("INSERT INTO test_pdo_sqlite_lastinsertid VALUES (NULL, 'PHP'), (NULL, 'PHP6')"); var_dump($db->query('SELECT * FROM test_pdo_sqlite_lastinsertid')); var_dump($db->errorInfo()); var_dump($db->lastInsertId()); diff --git a/ext/pdo_sqlite/tests/pdo_sqlite_parser.phpt b/ext/pdo_sqlite/tests/pdo_sqlite_parser.phpt index d5eda8d9b8274..c1eed6f3adc8f 100644 --- a/ext/pdo_sqlite/tests/pdo_sqlite_parser.phpt +++ b/ext/pdo_sqlite/tests/pdo_sqlite_parser.phpt @@ -31,9 +31,8 @@ foreach ($queries as $k => $query) { // One parameter $queries = [ "SELECT * FROM {$table} WHERE '1' = ?", - "SELECT * FROM {$table} WHERE \"?\" IN (?, \"?\")", + "SELECT * FROM {$table} WHERE '?' IN (?, '?')", "SELECT * FROM {$table} WHERE `a``?` = ?", - "SELECT * FROM {$table} WHERE \"a`?\" = ?", "SELECT * FROM {$table} WHERE [a`?] = ?", ]; @@ -43,6 +42,22 @@ foreach ($queries as $k => $query) { var_dump($stmt->fetch(PDO::FETCH_NUM) === [0 => 1]); } +// Check if DQS are enabled. +$dqs = true; +try { + $db->exec('SELECT "test"'); +} catch (\PDOException) { + $dqs = false; +} + +if ($dqs) { + $stmt = $db->prepare("SELECT * FROM {$table} WHERE \"a`?\" = ?"); + $stmt->execute([1]); + var_dump($stmt->fetch(PDO::FETCH_NUM) === [0 => 1]); +} else { + var_dump(true); +} + ?> --CLEAN-- query('CREATE TABLE test_pdo_sqlite_transaction (id INT AUTO INCREMENT, nam $db->commit(); $db->beginTransaction(); -$db->query('INSERT INTO test_pdo_sqlite_transaction VALUES (NULL, "PHP"), (NULL, "PHP6")'); +$db->query("INSERT INTO test_pdo_sqlite_transaction VALUES (NULL, 'PHP'), (NULL, 'PHP6')"); $db->rollback(); $r = $db->query('SELECT COUNT(*) FROM test_pdo_sqlite_transaction'); diff --git a/ext/pdo_sqlite/tests/subclasses/pdo_sqlite_createafunction_trampoline.phpt b/ext/pdo_sqlite/tests/subclasses/pdo_sqlite_createafunction_trampoline.phpt index adcb130e0b9c1..a1286e2e026d9 100644 --- a/ext/pdo_sqlite/tests/subclasses/pdo_sqlite_createafunction_trampoline.phpt +++ b/ext/pdo_sqlite/tests/subclasses/pdo_sqlite_createafunction_trampoline.phpt @@ -20,11 +20,11 @@ class TrampolineTest { var_dump($db->createFunction('strtoupper', [new TrampolineTest(), 'strtoupper'])); -foreach ($db->query('SELECT strtoupper("test")') as $row) { +foreach ($db->query("SELECT strtoupper('test')") as $row) { var_dump($row); } -foreach ($db->query('SELECT strtoupper("test")') as $row) { +foreach ($db->query("SELECT strtoupper('test')") as $row) { var_dump($row); } @@ -33,14 +33,14 @@ foreach ($db->query('SELECT strtoupper("test")') as $row) { bool(true) Trampoline for strtoupper array(2) { - ["strtoupper("test")"]=> + ["strtoupper('test')"]=> string(4) "TEST" [0]=> string(4) "TEST" } Trampoline for strtoupper array(2) { - ["strtoupper("test")"]=> + ["strtoupper('test')"]=> string(4) "TEST" [0]=> string(4) "TEST" diff --git a/ext/pdo_sqlite/tests/subclasses/pdo_sqlite_createaggregate.phpt b/ext/pdo_sqlite/tests/subclasses/pdo_sqlite_createaggregate.phpt index 1f96da8e1fa32..af04daaec7fac 100644 --- a/ext/pdo_sqlite/tests/subclasses/pdo_sqlite_createaggregate.phpt +++ b/ext/pdo_sqlite/tests/subclasses/pdo_sqlite_createaggregate.phpt @@ -10,7 +10,7 @@ $db = new Pdo\Sqlite('sqlite::memory:'); $db->query('CREATE TABLE test_pdo_sqlite_createaggregate (id INT AUTO INCREMENT, name TEXT)'); -$db->query('INSERT INTO test_pdo_sqlite_createaggregate VALUES (NULL, "PHP"), (NULL, "PHP6")'); +$db->query("INSERT INTO test_pdo_sqlite_createaggregate VALUES (NULL, 'PHP'), (NULL, 'PHP6')"); $db->createAggregate('testing', function(&$a, $b) { $a .= $b; return $a; }, function(&$v) { return $v; }); diff --git a/ext/pdo_sqlite/tests/subclasses/pdo_sqlite_createcollation.phpt b/ext/pdo_sqlite/tests/subclasses/pdo_sqlite_createcollation.phpt index d043dda7a526e..4ba37ec6aa6ec 100644 --- a/ext/pdo_sqlite/tests/subclasses/pdo_sqlite_createcollation.phpt +++ b/ext/pdo_sqlite/tests/subclasses/pdo_sqlite_createcollation.phpt @@ -11,7 +11,7 @@ $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $db->query('CREATE TABLE test_pdo_sqlite_createcollation (id INT AUTO INCREMENT, name TEXT)'); -$db->query('INSERT INTO test_pdo_sqlite_createcollation VALUES (NULL, "1"), (NULL, "2"), (NULL, "10")'); +$db->query("INSERT INTO test_pdo_sqlite_createcollation VALUES (NULL, '1'), (NULL, '2'), (NULL, '10')"); $db->createCollation('MYCOLLATE', function($a, $b) { return strnatcmp($a, $b); }); diff --git a/ext/pdo_sqlite/tests/subclasses/pdo_sqlite_createcollation_trampoline.phpt b/ext/pdo_sqlite/tests/subclasses/pdo_sqlite_createcollation_trampoline.phpt index 1635fd7007711..7f2b309ebf4cc 100644 --- a/ext/pdo_sqlite/tests/subclasses/pdo_sqlite_createcollation_trampoline.phpt +++ b/ext/pdo_sqlite/tests/subclasses/pdo_sqlite_createcollation_trampoline.phpt @@ -9,7 +9,7 @@ $db = new Pdo\Sqlite('sqlite::memory:'); $db->query('CREATE TABLE test_pdo_sqlite_createcollation_trampoline (s VARCHAR(4))'); -$stmt = $db->query('INSERT INTO test_pdo_sqlite_createcollation_trampoline VALUES ("a1"), ("a10"), ("a2")'); +$stmt = $db->query("INSERT INTO test_pdo_sqlite_createcollation_trampoline VALUES ('a1'), ('a10'), ('a2')"); class TrampolineTest { public function __call(string $name, array $arguments) { diff --git a/ext/pdo_sqlite/tests/subclasses/pdo_sqlite_createfunction_with_flags.phpt b/ext/pdo_sqlite/tests/subclasses/pdo_sqlite_createfunction_with_flags.phpt index c828817d2c3ad..5178daefa6d5e 100644 --- a/ext/pdo_sqlite/tests/subclasses/pdo_sqlite_createfunction_with_flags.phpt +++ b/ext/pdo_sqlite/tests/subclasses/pdo_sqlite_createfunction_with_flags.phpt @@ -11,7 +11,7 @@ if (!defined('Pdo\Sqlite::DETERMINISTIC')) die('skip system sqlite is too old'); // This test was copied from the pdo_sqlite test for sqliteCreateCollation $db = new Pdo\Sqlite('sqlite::memory:'); $db->query('CREATE TABLE test_pdo_sqlite_createfunction_with_flags (id INT AUTO INCREMENT, name TEXT)'); -$db->query('INSERT INTO test_pdo_sqlite_createfunction_with_flags VALUES (NULL, "PHP"), (NULL, "PHP6")'); +$db->query("INSERT INTO test_pdo_sqlite_createfunction_with_flags VALUES (NULL, 'PHP'), (NULL, 'PHP6')"); $db->createFunction('testing', function($v) { return strtolower($v); }, 1, Pdo\Sqlite::DETERMINISTIC); diff --git a/ext/pdo_sqlite/tests/subclasses/pdo_sqlite_getattr_busy.phpt b/ext/pdo_sqlite/tests/subclasses/pdo_sqlite_getattr_busy.phpt index 230fb7390ae50..c1f82e96c07b5 100644 --- a/ext/pdo_sqlite/tests/subclasses/pdo_sqlite_getattr_busy.phpt +++ b/ext/pdo_sqlite/tests/subclasses/pdo_sqlite_getattr_busy.phpt @@ -8,7 +8,7 @@ pdo_sqlite $db = new Pdo\Sqlite('sqlite::memory:'); $db->query('CREATE TABLE test_busy (a string);'); -$db->query('INSERT INTO test_busy VALUES ("interleaved"), ("statements")'); +$db->query("INSERT INTO test_busy VALUES ('interleaved'), ('statements')"); $st = $db->prepare('SELECT a FROM test_busy'); var_dump($st->getAttribute(Pdo\Sqlite::ATTR_BUSY_STATEMENT)); $st->execute(); diff --git a/ext/pdo_sqlite/tests/subclasses/pdo_sqlite_getsetattr_explain.phpt b/ext/pdo_sqlite/tests/subclasses/pdo_sqlite_getsetattr_explain.phpt index 383457f3a79e8..d2a6c2a5f52b6 100644 --- a/ext/pdo_sqlite/tests/subclasses/pdo_sqlite_getsetattr_explain.phpt +++ b/ext/pdo_sqlite/tests/subclasses/pdo_sqlite_getsetattr_explain.phpt @@ -13,7 +13,7 @@ if (!defined('Pdo\Sqlite::EXPLAIN_MODE_EXPLAIN')) die('skip system sqlite does n $db = new Pdo\Sqlite('sqlite::memory:'); $db->query('CREATE TABLE test_explain (a string);'); -$stmt = $db->prepare('INSERT INTO test_explain VALUES ("first insert"), ("second_insert")'); +$stmt = $db->prepare("INSERT INTO test_explain VALUES ('first insert'), ('second_insert')"); $stmt->setAttribute(Pdo\Sqlite::ATTR_EXPLAIN_STATEMENT, Pdo\Sqlite::EXPLAIN_MODE_EXPLAIN); var_dump($stmt->getAttribute(Pdo\Sqlite::ATTR_EXPLAIN_STATEMENT) == Pdo\Sqlite::EXPLAIN_MODE_EXPLAIN); $r = $stmt->execute(); @@ -24,7 +24,7 @@ var_dump($stmt->getAttribute(Pdo\Sqlite::ATTR_EXPLAIN_STATEMENT) == Pdo\Sqlite:: $r = $stmts->execute(); var_dump($stmts->fetchAll(PDO::FETCH_ASSOC)); -$stmt = $db->prepare('INSERT INTO test_explain VALUES ("first insert"), ("second_insert")'); +$stmt = $db->prepare("INSERT INTO test_explain VALUES ('first insert'), ('second_insert')"); $stmt->setAttribute(Pdo\Sqlite::ATTR_EXPLAIN_STATEMENT, Pdo\Sqlite::EXPLAIN_MODE_PREPARED); $stmt->execute(); $stmts->setAttribute(Pdo\Sqlite::ATTR_EXPLAIN_STATEMENT, Pdo\Sqlite::EXPLAIN_MODE_PREPARED); @@ -88,7 +88,7 @@ array(%d) { ["opcode"]=> string(13) "InitCoroutine" ["p1"]=> - int(3) + int(%d) ["p2"]=> int(%d) ["p3"]=> @@ -109,7 +109,7 @@ array(%d) { ["p1"]=> int(0) ["p2"]=> - int(2) + int(%d) ["p3"]=> int(0) ["p4"]=> @@ -126,7 +126,7 @@ array(%d) { ["opcode"]=> string(5) "Yield" ["p1"]=> - int(3) + int(%d) ["p2"]=> int(0) ["p3"]=> @@ -147,7 +147,7 @@ array(%d) { ["p1"]=> int(0) ["p2"]=> - int(2) + int(%d) ["p3"]=> int(0) ["p4"]=> @@ -164,7 +164,7 @@ array(%d) { ["opcode"]=> string(5) "Yield" ["p1"]=> - int(3) + int(%d) ["p2"]=> int(0) ["p3"]=> @@ -183,7 +183,7 @@ array(%d) { ["opcode"]=> string(12) "EndCoroutine" ["p1"]=> - int(3) + int(%d) ["p2"]=> int(0) ["p3"]=> @@ -221,7 +221,7 @@ array(%d) { ["opcode"]=> string(5) "Yield" ["p1"]=> - int(3) + int(%d) ["p2"]=> int(%d) ["p3"]=> @@ -242,7 +242,7 @@ array(%d) { ["p1"]=> int(0) ["p2"]=> - int(1) + int(%d) ["p3"]=> int(0) ["p4"]=> @@ -259,11 +259,11 @@ array(%d) { ["opcode"]=> string(10) "MakeRecord" ["p1"]=> - int(2) + int(%d) ["p2"]=> int(1) ["p3"]=> - int(4) + int(%d) ["p4"]=> string(1) "C" ["p5"]=> @@ -280,9 +280,9 @@ array(%d) { ["p1"]=> int(0) ["p2"]=> - int(4) + int(%d) ["p3"]=> - int(1) + int(%d) ["p4"]=> string(12) "test_explain" ["p5"]=> diff --git a/ext/pdo_sqlite/tests/subclasses/pdosqlite_001.phpt b/ext/pdo_sqlite/tests/subclasses/pdosqlite_001.phpt index ea88a6316b645..52233745820d9 100644 --- a/ext/pdo_sqlite/tests/subclasses/pdosqlite_001.phpt +++ b/ext/pdo_sqlite/tests/subclasses/pdosqlite_001.phpt @@ -9,8 +9,8 @@ $db = new Pdo\Sqlite('sqlite::memory:'); $db->query('CREATE TABLE pdosqlite_001 (id INT AUTO INCREMENT, name TEXT)'); -$db->query('INSERT INTO pdosqlite_001 VALUES (NULL, "PHP")'); -$db->query('INSERT INTO pdosqlite_001 VALUES (NULL, "PHP6")'); +$db->query("INSERT INTO pdosqlite_001 VALUES (NULL, 'PHP')"); +$db->query("INSERT INTO pdosqlite_001 VALUES (NULL, 'PHP6')"); $db->createFunction('testing', function($v) { return strtolower($v); }, 1, Pdo\Sqlite::DETERMINISTIC); diff --git a/ext/pdo_sqlite/tests/subclasses/pdosqlite_002.phpt b/ext/pdo_sqlite/tests/subclasses/pdosqlite_002.phpt index 28534f4a2365c..f2de79b6c8477 100644 --- a/ext/pdo_sqlite/tests/subclasses/pdosqlite_002.phpt +++ b/ext/pdo_sqlite/tests/subclasses/pdosqlite_002.phpt @@ -11,8 +11,8 @@ if (!$db instanceof Pdo\Sqlite) { } $db->query('CREATE TABLE pdosqlite_002 (id INT AUTO INCREMENT, name TEXT)'); -$db->query('INSERT INTO pdosqlite_002 VALUES (NULL, "PHP")'); -$db->query('INSERT INTO pdosqlite_002 VALUES (NULL, "PHP6")'); +$db->query("INSERT INTO pdosqlite_002 VALUES (NULL, 'PHP')"); +$db->query("INSERT INTO pdosqlite_002 VALUES (NULL, 'PHP6')"); $db->createFunction('testing', function($v) { return strtolower($v); }, 1, Pdo\Sqlite::DETERMINISTIC); diff --git a/ext/sqlite3/tests/bug72668.phpt b/ext/sqlite3/tests/bug72668.phpt index 40ede8883cc23..7f33338eb5e68 100644 --- a/ext/sqlite3/tests/bug72668.phpt +++ b/ext/sqlite3/tests/bug72668.phpt @@ -12,20 +12,20 @@ $db = new SQLite3(':memory:'); $db->createFunction('my_udf_md5', 'my_udf_md5'); try { - $result = $db->query('SELECT my_udf_md5("test")'); + $result = $db->query("SELECT my_udf_md5('test')"); var_dump($result); } catch(\Exception $e) { echo "Exception: ".$e->getMessage(); } try { - $result = $db->querySingle('SELECT my_udf_md5("test")'); + $result = $db->querySingle("SELECT my_udf_md5('test')"); var_dump($result); } catch(\Exception $e) { echo "Exception: ".$e->getMessage(); } -$statement = $db->prepare('SELECT my_udf_md5("test")'); +$statement = $db->prepare("SELECT my_udf_md5('test')"); try { $result = $statement->execute(); var_dump($result); diff --git a/ext/sqlite3/tests/sqlite3_29_createfunction.phpt b/ext/sqlite3/tests/sqlite3_29_createfunction.phpt index ef28b3b62deff..1a511ee139967 100644 --- a/ext/sqlite3/tests/sqlite3_29_createfunction.phpt +++ b/ext/sqlite3/tests/sqlite3_29_createfunction.phpt @@ -9,14 +9,14 @@ require_once(__DIR__ . '/new_db.inc'); $func = 'strtoupper'; var_dump($db->createfunction($func, $func)); -var_dump($db->querySingle('SELECT strtoupper("test")')); +var_dump($db->querySingle("SELECT strtoupper('test')")); $func2 = 'strtolower'; var_dump($db->createfunction($func2, $func2)); -var_dump($db->querySingle('SELECT strtolower("TEST")')); +var_dump($db->querySingle("SELECT strtolower('TEST')")); var_dump($db->createfunction($func, $func2)); -var_dump($db->querySingle('SELECT strtoupper("tEst")')); +var_dump($db->querySingle("SELECT strtoupper('tEst')")); ?> diff --git a/ext/sqlite3/tests/sqlite3_37_createfunction_flags.phpt b/ext/sqlite3/tests/sqlite3_37_createfunction_flags.phpt index 4297d622e939a..962075bf14785 100644 --- a/ext/sqlite3/tests/sqlite3_37_createfunction_flags.phpt +++ b/ext/sqlite3/tests/sqlite3_37_createfunction_flags.phpt @@ -13,14 +13,14 @@ require_once(__DIR__ . '/new_db.inc'); $func = 'strtoupper'; var_dump($db->createfunction($func, $func, 1, SQLITE3_DETERMINISTIC)); -var_dump($db->querySingle('SELECT strtoupper("test")')); +var_dump($db->querySingle("SELECT strtoupper('test')")); $func2 = 'strtolower'; var_dump($db->createfunction($func2, $func2, 1, SQLITE3_DETERMINISTIC)); -var_dump($db->querySingle('SELECT strtolower("TEST")')); +var_dump($db->querySingle("SELECT strtolower('TEST')")); var_dump($db->createfunction($func, $func2, 1, SQLITE3_DETERMINISTIC)); -var_dump($db->querySingle('SELECT strtoupper("tEst")')); +var_dump($db->querySingle("SELECT strtoupper('tEst')")); ?> diff --git a/ext/sqlite3/tests/sqlite3_dqs.phpt b/ext/sqlite3/tests/sqlite3_dqs.phpt new file mode 100644 index 0000000000000..1efa8ad475fef --- /dev/null +++ b/ext/sqlite3/tests/sqlite3_dqs.phpt @@ -0,0 +1,28 @@ +--TEST-- +SQLite3 DQS +--EXTENSIONS-- +sqlite3 +--SKIPIF-- +enableExceptions(true); + $db->exec('SELECT "test"'); +} catch (\SQLite3Exception) { + die('skip SQLite is lacking DQS'); +} +?> +--FILE-- +exec('CREATE TABLE test (s1 VARCHAR(255), s2 VARCHAR(255))'); +$db->exec('INSERT INTO test VALUES (\'test\', "test")'); +var_dump($db->prepare('SELECT * FROM test')->execute()->fetchArray(SQLITE3_ASSOC)); +?> +--EXPECT-- +array(2) { + ["s1"]=> + string(4) "test" + ["s2"]=> + string(4) "test" +} diff --git a/ext/sqlite3/tests/sqlite3_explain.phpt b/ext/sqlite3/tests/sqlite3_explain.phpt index 40648588733c6..1f9d4fc940e41 100644 --- a/ext/sqlite3/tests/sqlite3_explain.phpt +++ b/ext/sqlite3/tests/sqlite3_explain.phpt @@ -14,7 +14,7 @@ if ($version <= 3043000) die("skip for sqlite3 < 3.43.0"); require_once(__DIR__ . '/new_db.inc'); $db->exec('CREATE TABLE test_explain (a string);'); -$stmt = $db->prepare('INSERT INTO test_explain VALUES ("first insert"), ("second_insert")'); +$stmt = $db->prepare("INSERT INTO test_explain VALUES ('first insert'), ('second_insert')"); $stmt->setExplain(Sqlite3Stmt::EXPLAIN_MODE_EXPLAIN); var_dump($stmt->explain() == Sqlite3Stmt::EXPLAIN_MODE_EXPLAIN); $r = $stmt->execute(); @@ -28,7 +28,7 @@ $result = []; while (($arr = $r->fetchArray(SQLITE3_ASSOC)) !== false) $result[] = $arr; var_dump($result); -$stmt = $db->prepare('INSERT INTO test_explain VALUES ("first insert"), ("second_insert")'); +$stmt = $db->prepare("INSERT INTO test_explain VALUES ('first insert'), ('second_insert')"); $stmt->setExplain(Sqlite3Stmt::EXPLAIN_MODE_PREPARED); $stmt->execute(); $stmts = $db->prepare('SELECT * FROM test_explain'); @@ -81,7 +81,7 @@ array(%d) { ["opcode"]=> string(%d) "%s" ["p1"]=> - int(3) + int(%d) ["p2"]=> int(%d) ["p3"]=> @@ -102,7 +102,7 @@ array(%d) { ["p1"]=> int(0) ["p2"]=> - int(2) + int(%d) ["p3"]=> int(0) ["p4"]=> @@ -119,7 +119,7 @@ array(%d) { ["opcode"]=> string(5) "Yield" ["p1"]=> - int(3) + int(%d) ["p2"]=> int(0) ["p3"]=> @@ -140,7 +140,7 @@ array(%d) { ["p1"]=> int(0) ["p2"]=> - int(2) + int(%d) ["p3"]=> int(0) ["p4"]=> @@ -157,7 +157,7 @@ array(%d) { ["opcode"]=> string(5) "Yield" ["p1"]=> - int(3) + int(%d) ["p2"]=> int(0) ["p3"]=> @@ -176,7 +176,7 @@ array(%d) { ["opcode"]=> string(12) "EndCoroutine" ["p1"]=> - int(3) + int(%d) ["p2"]=> int(0) ["p3"]=> @@ -214,7 +214,7 @@ array(%d) { ["opcode"]=> string(5) "Yield" ["p1"]=> - int(3) + int(%d) ["p2"]=> int(%d) ["p3"]=> @@ -235,7 +235,7 @@ array(%d) { ["p1"]=> int(0) ["p2"]=> - int(1) + int(%d) ["p3"]=> int(0) ["p4"]=> @@ -252,11 +252,11 @@ array(%d) { ["opcode"]=> string(10) "MakeRecord" ["p1"]=> - int(2) + int(%d) ["p2"]=> int(1) ["p3"]=> - int(4) + int(%d) ["p4"]=> string(1) "C" ["p5"]=> @@ -273,9 +273,9 @@ array(%d) { ["p1"]=> int(0) ["p2"]=> - int(4) + int(%d) ["p3"]=> - int(1) + int(%d) ["p4"]=> string(12) "test_explain" ["p5"]=> diff --git a/ext/sqlite3/tests/sqlite3_rename_column.phpt b/ext/sqlite3/tests/sqlite3_rename_column.phpt index 6b4e23bc7186b..a3a4caef3ce67 100644 --- a/ext/sqlite3/tests/sqlite3_rename_column.phpt +++ b/ext/sqlite3/tests/sqlite3_rename_column.phpt @@ -14,7 +14,7 @@ if (SQLite3::version()['versionNumber'] < 3025000) { $db = new SQLite3(':memory:'); $db->exec('CREATE TABLE tbl (orig text)'); -$db->exec('insert into tbl values ("one"), ("two")'); +$db->exec("insert into tbl values ('one'), ('two')"); $res1 = $db->prepare('select * from tbl')->execute(); $res2 = $db->prepare('select * from tbl')->execute(); diff --git a/ext/sqlite3/tests/sqlite3_stmt_busy.phpt b/ext/sqlite3/tests/sqlite3_stmt_busy.phpt index 8110d374afe68..33eb759772be1 100644 --- a/ext/sqlite3/tests/sqlite3_stmt_busy.phpt +++ b/ext/sqlite3/tests/sqlite3_stmt_busy.phpt @@ -12,7 +12,7 @@ if ($version['versionNumber'] < 3007004) die("skip"); require_once(__DIR__ . '/new_db.inc'); $db->exec('CREATE TABLE test_busy (a string);'); -$db->exec('INSERT INTO test_busy VALUES ("interleaved"), ("statements")'); +$db->exec("INSERT INTO test_busy VALUES ('interleaved'), ('statements')"); $st = $db->prepare('SELECT a FROM test_busy'); var_dump($st->busy()); $r = $st->execute(); diff --git a/ext/sqlite3/tests/sqlite3_trampoline_createfunction.phpt b/ext/sqlite3/tests/sqlite3_trampoline_createfunction.phpt index 81245f5b4beff..52d5b726415e7 100644 --- a/ext/sqlite3/tests/sqlite3_trampoline_createfunction.phpt +++ b/ext/sqlite3/tests/sqlite3_trampoline_createfunction.phpt @@ -16,8 +16,8 @@ class TrampolineTest { $o = new TrampolineTest(); $callback = [$o, 'strtoupper']; var_dump($db->createfunction('strtoupper', $callback)); -var_dump($db->querySingle('SELECT strtoupper("test")')); -var_dump($db->querySingle('SELECT strtoupper("test")')); +var_dump($db->querySingle("SELECT strtoupper('test')")); +var_dump($db->querySingle("SELECT strtoupper('test')")); ?> --EXPECT--