From b0ac91c10ab32def2fd83c82458f839a64047a83 Mon Sep 17 00:00:00 2001 From: Calvin Buckley Date: Mon, 10 Jul 2023 13:28:49 -0300 Subject: [PATCH 01/11] Add untested, unexposed PARAM_BINARY --- ext/pdo/pdo_dbh.stub.php | 2 ++ ext/pdo/pdo_dbh_arginfo.h | 9 ++++++++- ext/pdo/pdo_stmt.c | 3 ++- ext/pdo/php_pdo_driver.h | 2 ++ 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/ext/pdo/pdo_dbh.stub.php b/ext/pdo/pdo_dbh.stub.php index 7fcec0226b0ba..b87b5a193ac64 100644 --- a/ext/pdo/pdo_dbh.stub.php +++ b/ext/pdo/pdo_dbh.stub.php @@ -17,6 +17,8 @@ class PDO public const int PARAM_LOB = 3; /** @cvalue LONG_CONST(PDO_PARAM_STMT) */ public const int PARAM_STMT = 4; + /** @cvalue LONG_CONST(PDO_PARAM_BINARY) */ + public const int PARAM_BINARY = 4; /** @cvalue LONG_CONST(PDO_PARAM_INPUT_OUTPUT) */ public const int PARAM_INPUT_OUTPUT = UNKNOWN; /** @cvalue LONG_CONST(PDO_PARAM_STR_NATL) */ diff --git a/ext/pdo/pdo_dbh_arginfo.h b/ext/pdo/pdo_dbh_arginfo.h index 71df4c519e1a7..fe6b2aef44175 100644 --- a/ext/pdo/pdo_dbh_arginfo.h +++ b/ext/pdo/pdo_dbh_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 006be61b2c519e7d9ca997a7f12135eb3e0f3500 */ + * Stub hash: 6b172de5fd309fc3be57c2e0d6ced2d0f63b8383 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_PDO___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, dsn, IS_STRING, 0) @@ -151,6 +151,13 @@ static zend_class_entry *register_class_PDO(void) zend_string_release(const_PARAM_STMT_name); ZEND_ASSERT(LONG_CONST(PDO_PARAM_STMT) == 4); + zval const_PARAM_BINARY_value; + ZVAL_LONG(&const_PARAM_BINARY_value, LONG_CONST(PDO_PARAM_BINARY)); + zend_string *const_PARAM_BINARY_name = zend_string_init_interned("PARAM_BINARY", sizeof("PARAM_BINARY") - 1, 1); + zend_declare_typed_class_constant(class_entry, const_PARAM_BINARY_name, &const_PARAM_BINARY_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(const_PARAM_BINARY_name); + ZEND_ASSERT(LONG_CONST(PDO_PARAM_BINARY) == 4); + zval const_PARAM_INPUT_OUTPUT_value; ZVAL_LONG(&const_PARAM_INPUT_OUTPUT_value, LONG_CONST(PDO_PARAM_INPUT_OUTPUT)); zend_string *const_PARAM_INPUT_OUTPUT_name = zend_string_init_interned("PARAM_INPUT_OUTPUT", sizeof("PARAM_INPUT_OUTPUT") - 1, 1); diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c index a39b7a3b06804..f0c5baa69ed1e 100644 --- a/ext/pdo/pdo_stmt.c +++ b/ext/pdo/pdo_stmt.c @@ -269,7 +269,7 @@ static bool really_register_bound_param(struct pdo_bound_param_data *param, pdo_ parameter = Z_REFVAL(param->parameter); } - if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_STR && param->max_value_len <= 0 && !Z_ISNULL_P(parameter)) { + if ((PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_STR || PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_BINARY) && param->max_value_len <= 0 && !Z_ISNULL_P(parameter)) { if (!try_convert_to_string(parameter)) { return 0; } @@ -517,6 +517,7 @@ static inline void fetch_value(pdo_stmt_t *stmt, zval *dest, int colno, enum pdo convert_to_boolean(dest); break; case PDO_PARAM_STR: + case PDO_PARAM_BINARY: if (Z_TYPE_P(dest) == IS_FALSE) { /* Return "0" rather than "", because this is what database drivers that * don't have a dedicated boolean type would return. */ diff --git a/ext/pdo/php_pdo_driver.h b/ext/pdo/php_pdo_driver.h index c3930f4022464..630e03032e8f4 100644 --- a/ext/pdo/php_pdo_driver.h +++ b/ext/pdo/php_pdo_driver.h @@ -47,6 +47,8 @@ enum pdo_param_type { /* get_col: Not supported (yet?) */ PDO_PARAM_STMT = 4, /* hierarchical result set */ + PDO_PARAM_BINARY = 6, + /* magic flag to denote a parameter as being input/output */ PDO_PARAM_INPUT_OUTPUT = 0x80000000, From cb2ba6d4e87bf088f7af940528d3ae02002e6883 Mon Sep 17 00:00:00 2001 From: Calvin Buckley Date: Mon, 10 Jul 2023 13:31:06 -0300 Subject: [PATCH 02/11] Adapt GH-10343 for PARAM_BINARY Original text: >If the user is specifying a PDO::PARAM_LOB, there's a good chance >that it's a binary file (i.e. an image), that is too fragile to >survive in a string, as escaping it is insufficient. Because >PDO_DBLIB relies on PDO to fill in a parameterized query and >submits the filled string to the server, it ends up mangling the >query. > >This adds logic in the PDO_DBLIB quoter to handle binary parameters >by using the SQL Server binary literal syntax (a hex string that >begins with `0x`). This resolves the issue because PDO consults the >quoter for filling in the query string. --- ext/pdo_dblib/dblib_driver.c | 25 +++++++++++- ext/pdo_dblib/tests/pdo_dblib_binary.phpt | 46 +++++++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 ext/pdo_dblib/tests/pdo_dblib_binary.phpt diff --git a/ext/pdo_dblib/dblib_driver.c b/ext/pdo_dblib/dblib_driver.c index 17036d2b002fd..dd03cdcf8b244 100644 --- a/ext/pdo_dblib/dblib_driver.c +++ b/ext/pdo_dblib/dblib_driver.c @@ -145,7 +145,7 @@ static zend_long dblib_handle_doer(pdo_dbh_t *dbh, const zend_string *sql) static zend_string* dblib_handle_quoter(pdo_dbh_t *dbh, const zend_string *unquoted, enum pdo_param_type paramtype) { pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data; - bool use_national_character_set = 0; + bool use_national_character_set = 0, is_binary = false; size_t i; char *q; size_t quotedlen = 0; @@ -160,6 +160,29 @@ static zend_string* dblib_handle_quoter(pdo_dbh_t *dbh, const zend_string *unquo if ((paramtype & PDO_PARAM_STR_CHAR) == PDO_PARAM_STR_CHAR) { use_national_character_set = 0; } + /* + * A user could be passing a binary (i.e. an image file) in a query. + * It's fragile trying to escape it as a string, so encode it as a + * binary literal instead. + */ + if (paramtype == PDO_PARAM_BINARY) { + is_binary = true; + } + + if (is_binary) { + /* 1 char = 2 chars in hex, plus 0x */ + quotedlen = ZSTR_LEN(unquoted) * 2; /* XXX: Overflow? */ + quotedlen += 2; + + quoted_str = zend_string_alloc(quotedlen, 0); + q = ZSTR_VAL(quoted_str); + *q++ = '0'; + *q++ = 'x'; + for (i = 0; i < ZSTR_LEN(unquoted); i++) { + q += sprintf(q, "%02X", (unsigned char)ZSTR_VAL(unquoted)[i]); + } + return quoted_str; + } /* Detect quoted length, adding extra char for doubled single quotes */ for (i = 0; i < ZSTR_LEN(unquoted); i++) { diff --git a/ext/pdo_dblib/tests/pdo_dblib_binary.phpt b/ext/pdo_dblib/tests/pdo_dblib_binary.phpt new file mode 100644 index 0000000000000..e8e99f37ae959 --- /dev/null +++ b/ext/pdo_dblib/tests/pdo_dblib_binary.phpt @@ -0,0 +1,46 @@ +--TEST-- +PDO_DBLIB: Ensure binary bound parameter is a binary literal +--EXTENSIONS-- +pdo_dblib +--SKIPIF-- + +--FILE-- +prepare($query); +// PARAM_LOB gets converted to a binary literal instead of a string literal +$stmt->bindParam(1, $binary, PDO::PARAM_BINARY); +$result = $stmt->execute(); + +// Verify we sent the binary literal over the wire +var_dump($stmt->debugDumpParams()); + +// Verify that we get the same PNG back over the wire +$rows = $stmt->fetchAll(); +var_dump(base64_encode($rows[0][0])); + +?> +--EXPECT-- +SQL: [8] SELECT ? +Sent SQL: [149] SELECT 0x89504E470D0A1A0A0000000D49484452000000010000000108060000001F15C4890000000D49444154085B63606060F80F0001040100C12D8E500000000049454E44AE426082 +Params: 1 +Key: Position #0: +paramno=0 +name=[0] "" +is_param=1 +param_type=3 +NULL +string(96) "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2NgYGD4DwABBAEAwS2OUAAAAABJRU5ErkJggg==" From e963e9e5e76d436074ae4e5a737c6b435fc88f0f Mon Sep 17 00:00:00 2001 From: Calvin Buckley Date: Mon, 10 Jul 2023 14:04:21 -0300 Subject: [PATCH 03/11] Untested PARAM_BINARY support for PDO SQLite --- ext/pdo_sqlite/sqlite_statement.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/ext/pdo_sqlite/sqlite_statement.c b/ext/pdo_sqlite/sqlite_statement.c index 29309ac5f1ff0..ff1650cd30501 100644 --- a/ext/pdo_sqlite/sqlite_statement.c +++ b/ext/pdo_sqlite/sqlite_statement.c @@ -129,6 +129,8 @@ static int pdo_sqlite_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_d return 0; case PDO_PARAM_LOB: + // For SQLite BLOB columns, these are identical + case PDO_PARAM_BINARY: if (Z_ISREF(param->parameter)) { parameter = Z_REFVAL(param->parameter); } else { @@ -329,9 +331,11 @@ static int pdo_sqlite_stmt_col_meta(pdo_stmt_t *stmt, zend_long colno, zval *ret break; case SQLITE_BLOB: - add_next_index_string(&flags, "blob"); - /* TODO Check this is correct */ - ZEND_FALLTHROUGH; + // add_next_index_string(&flags, "blob"); + add_assoc_str(return_value, "native_type", ZSTR_KNOWN(ZEND_STR_STRING)); + add_assoc_long(return_value, "pdo_type", PDO_PARAM_BINARY); + break; + case SQLITE_TEXT: add_assoc_str(return_value, "native_type", ZSTR_KNOWN(ZEND_STR_STRING)); add_assoc_long(return_value, "pdo_type", PDO_PARAM_STR); From 837cb8778086c49d48ae736164e04676467f539e Mon Sep 17 00:00:00 2001 From: Calvin Buckley Date: Mon, 10 Jul 2023 15:01:41 -0300 Subject: [PATCH 04/11] Add a test for SQLite PARAM_BINARY --- ext/pdo_sqlite/tests/pdo_sqlite_binary.phpt | 37 +++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 ext/pdo_sqlite/tests/pdo_sqlite_binary.phpt diff --git a/ext/pdo_sqlite/tests/pdo_sqlite_binary.phpt b/ext/pdo_sqlite/tests/pdo_sqlite_binary.phpt new file mode 100644 index 0000000000000..58486e0a5b2fe --- /dev/null +++ b/ext/pdo_sqlite/tests/pdo_sqlite_binary.phpt @@ -0,0 +1,37 @@ +--TEST-- +PDO_sqlite: Test PARAM_BINARY with a BLOB +--EXTENSIONS-- +pdo_sqlite +--FILE-- +exec("CREATE TABLE test_binary(field BLOB)"); + +$stmt = $db->prepare("INSERT INTO test_binary(field) VALUES (?)"); +$stmt->bindParam(1, $binary, PDO::PARAM_BINARY); +$result = $stmt->execute(); +var_dump($result); + +// We have to bind the result as a PDO binary/SQLite BLOB, +// because just getting the results otherwise will be +// considered a "null" type to SQLite. +$stmt = $db->prepare("SELECT field FROM test_binary"); +$result = $stmt->execute(); +$binary = ""; +$stmt->bindColumn(1, $binary, PDO::PARAM_BINARY); +$result = $stmt->execute(); +$result = $stmt->fetch(); + +var_dump(base64_encode($binary)); +var_dump($stmt->getColumnMeta(0)["pdo_type"]); +var_dump($stmt->getColumnMeta(0)["sqlite:decl_type"]); +?> +--EXPECT-- +bool(true) +string(96) "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2NgYGD4DwABBAEAwS2OUAAAAABJRU5ErkJggg==" +int(6) +string(4) "BLOB" From bab97daa041d282016596c07b687b0be2f1d5805 Mon Sep 17 00:00:00 2001 From: Calvin Buckley Date: Mon, 10 Jul 2023 15:32:28 -0300 Subject: [PATCH 05/11] Add untested PARAM_BINARY support to PDO_ODBC --- ext/pdo_odbc/odbc_stmt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ext/pdo_odbc/odbc_stmt.c b/ext/pdo_odbc/odbc_stmt.c index ffe09a6bf16aa..4508a9dd362e4 100644 --- a/ext/pdo_odbc/odbc_stmt.c +++ b/ext/pdo_odbc/odbc_stmt.c @@ -332,6 +332,7 @@ static int odbc_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *p sqltype = SQL_INTEGER; break; case PDO_PARAM_LOB: + case PDO_PARAM_BINARY: sqltype = SQL_LONGVARBINARY; break; default: From b9e76acc38d490140f31a9292d4e36cddaca5cfd Mon Sep 17 00:00:00 2001 From: Calvin Buckley Date: Mon, 10 Jul 2023 16:11:35 -0300 Subject: [PATCH 06/11] adapt binary test to check for binary type --- ext/pdo_dblib/tests/pdo_dblib_binary.phpt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/pdo_dblib/tests/pdo_dblib_binary.phpt b/ext/pdo_dblib/tests/pdo_dblib_binary.phpt index e8e99f37ae959..f209474a0b518 100644 --- a/ext/pdo_dblib/tests/pdo_dblib_binary.phpt +++ b/ext/pdo_dblib/tests/pdo_dblib_binary.phpt @@ -41,6 +41,6 @@ Key: Position #0: paramno=0 name=[0] "" is_param=1 -param_type=3 +param_type=6 NULL string(96) "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2NgYGD4DwABBAEAwS2OUAAAAABJRU5ErkJggg==" From f2bc71c56edba9deda409ae2696c678ac55a27a4 Mon Sep 17 00:00:00 2001 From: Calvin Buckley Date: Mon, 10 Jul 2023 18:25:51 -0300 Subject: [PATCH 07/11] Add to SQL_BINARY and PDO_PARAM_BINARY in PDO_ODBC ...including a test. I'm not sure if the semantics are right here though. This does binary data if the DB returns it, instead of listening to the PDO param type. This does mean that binary data works like expected, but the binary bound to SQL_C_CHAR converting behaviour in some drivers[1] may be desired and specified instead... [1]: At least Db2i and SQL Server's drivers, when I tested them. --- ext/pdo_odbc/odbc_stmt.c | 28 ++++++++++++++--- ext/pdo_odbc/tests/pdo_odbc_binary.phpt | 40 +++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 4 deletions(-) create mode 100644 ext/pdo_odbc/tests/pdo_odbc_binary.phpt diff --git a/ext/pdo_odbc/odbc_stmt.c b/ext/pdo_odbc/odbc_stmt.c index 4508a9dd362e4..faad626f361b6 100644 --- a/ext/pdo_odbc/odbc_stmt.c +++ b/ext/pdo_odbc/odbc_stmt.c @@ -32,6 +32,18 @@ enum pdo_odbc_conv_result { PDO_ODBC_CONV_FAIL }; +/* + * Used for determing if we should use SQL_C_BINARY on binary columns + * XXX: Callers use what ODBC returns, rather that what user told PDO, + * need to propagate + */ +static bool php_odbc_sqltype_is_binary(SWORD sqltype) { + if (sqltype == SQL_BINARY || sqltype == SQL_VARBINARY || sqltype == SQL_LONGVARBINARY) { + return true; + } + return false; +} + static int pdo_odbc_sqltype_is_unicode(pdo_odbc_stmt *S, SQLSMALLINT sqltype) { if (!S->assume_utf8) return 0; @@ -621,7 +633,7 @@ static int odbc_stmt_describe(pdo_stmt_t *stmt, int colno) S->cols[colno].is_long = 0; rc = SQLBindCol(S->stmt, colno+1, - S->cols[colno].is_unicode ? SQL_C_BINARY : SQL_C_CHAR, + (php_odbc_sqltype_is_binary(S->cols[colno].coltype) || S->cols[colno].is_unicode) ? SQL_C_BINARY : SQL_C_CHAR, S->cols[colno].data, S->cols[colno].datalen+1, &S->cols[colno].fetched_len); @@ -642,8 +654,15 @@ static int odbc_stmt_describe(pdo_stmt_t *stmt, int colno) static int odbc_stmt_get_column_meta(pdo_stmt_t *stmt, zend_long colno, zval *return_value) { + pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data; + pdo_odbc_column *C = &S->cols[colno]; + array_init(return_value); - add_assoc_long(return_value, "pdo_type", PDO_PARAM_STR); + if (php_odbc_sqltype_is_binary(C->coltype)) { + add_assoc_long(return_value, "pdo_type", PDO_PARAM_BINARY); + } else { + add_assoc_long(return_value, "pdo_type", PDO_PARAM_STR); + } return 1; } @@ -652,6 +671,7 @@ static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, zval *result, enum pdo pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data; pdo_odbc_column *C = &S->cols[colno]; + SQLSMALLINT c_type = (php_odbc_sqltype_is_binary(C->coltype) || C->is_unicode) ? SQL_C_BINARY : SQL_C_CHAR; /* if it is a column containing "long" data, perform late binding now */ if (C->is_long) { SQLLEN orig_fetched_len = SQL_NULL_DATA; @@ -661,7 +681,7 @@ static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, zval *result, enum pdo * of 256 bytes; if there is more to be had, we then allocate * bigger buffer for the caller to free */ - rc = SQLGetData(S->stmt, colno+1, C->is_unicode ? SQL_C_BINARY : SQL_C_CHAR, C->data, + rc = SQLGetData(S->stmt, colno+1, c_type, C->data, 256, &C->fetched_len); orig_fetched_len = C->fetched_len; @@ -688,7 +708,7 @@ static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, zval *result, enum pdo do { C->fetched_len = 0; /* read block. 256 bytes => 255 bytes are actually read, the last 1 is NULL */ - rc = SQLGetData(S->stmt, colno+1, C->is_unicode ? SQL_C_BINARY : SQL_C_CHAR, buf2, 256, &C->fetched_len); + rc = SQLGetData(S->stmt, colno+1, c_type, buf2, 256, &C->fetched_len); /* adjust `used` in case we have proper length info from the driver */ if (orig_fetched_len >= 0 && C->fetched_len >= 0) { diff --git a/ext/pdo_odbc/tests/pdo_odbc_binary.phpt b/ext/pdo_odbc/tests/pdo_odbc_binary.phpt new file mode 100644 index 0000000000000..c4925b1e8887c --- /dev/null +++ b/ext/pdo_odbc/tests/pdo_odbc_binary.phpt @@ -0,0 +1,40 @@ +--TEST-- +PDO_odbc: Test PARAM_BINARY +--EXTENSIONS-- +pdo_odbc +--FILE-- +exec("CREATE TABLE test_binary(field VARBINARY(256))"); + +$stmt = $db->prepare("INSERT INTO test_binary(field) VALUES (?)"); +$stmt->bindParam(1, $binary, PDO::PARAM_BINARY); +$result = $stmt->execute(); +var_dump($result); + +$stmt = $db->prepare("SELECT field FROM test_binary"); +$result = $stmt->execute(); +$binary = ""; +$stmt->bindColumn(1, $binary, PDO::PARAM_BINARY); +$result = $stmt->execute(); +$result = $stmt->fetch(); + +var_dump(base64_encode($binary)); +var_dump($stmt->getColumnMeta(0)["pdo_type"]); +?> +--CLEAN-- +exec("DROP TABLE test_binary"); +?> +--EXPECT-- +bool(true) +string(96) "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2NgYGD4DwABBAEAwS2OUAAAAABJRU5ErkJggg==" +int(6) From 98ef4600bc21558c50c17fb92ba134fa64b30ae5 Mon Sep 17 00:00:00 2001 From: Calvin Buckley Date: Wed, 19 Jul 2023 15:38:43 -0300 Subject: [PATCH 08/11] Fixes bug80783 but not bug80783a by using type override --- ext/pdo_odbc/odbc_stmt.c | 7 +++++-- ext/pdo_odbc/tests/bug80783.phpt | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/ext/pdo_odbc/odbc_stmt.c b/ext/pdo_odbc/odbc_stmt.c index faad626f361b6..9caf6342b3632 100644 --- a/ext/pdo_odbc/odbc_stmt.c +++ b/ext/pdo_odbc/odbc_stmt.c @@ -633,7 +633,7 @@ static int odbc_stmt_describe(pdo_stmt_t *stmt, int colno) S->cols[colno].is_long = 0; rc = SQLBindCol(S->stmt, colno+1, - (php_odbc_sqltype_is_binary(S->cols[colno].coltype) || S->cols[colno].is_unicode) ? SQL_C_BINARY : SQL_C_CHAR, + S->cols[colno].is_unicode ? SQL_C_BINARY : SQL_C_CHAR, S->cols[colno].data, S->cols[colno].datalen+1, &S->cols[colno].fetched_len); @@ -671,7 +671,10 @@ static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, zval *result, enum pdo pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data; pdo_odbc_column *C = &S->cols[colno]; - SQLSMALLINT c_type = (php_odbc_sqltype_is_binary(C->coltype) || C->is_unicode) ? SQL_C_BINARY : SQL_C_CHAR; + SQLSMALLINT c_type = C->is_unicode ? SQL_C_BINARY : SQL_C_CHAR; + if (type && (*type == PDO_PARAM_BINARY || *type == PDO_PARAM_LOB)) { + c_type = SQL_C_BINARY; + } /* if it is a column containing "long" data, perform late binding now */ if (C->is_long) { SQLLEN orig_fetched_len = SQL_NULL_DATA; diff --git a/ext/pdo_odbc/tests/bug80783.phpt b/ext/pdo_odbc/tests/bug80783.phpt index 1660815f95148..5b0bf83736235 100644 --- a/ext/pdo_odbc/tests/bug80783.phpt +++ b/ext/pdo_odbc/tests/bug80783.phpt @@ -21,7 +21,7 @@ $stmt->bindColumn(1, $data, PDO::PARAM_LOB); $stmt->execute(); $stmt->fetch(PDO::FETCH_BOUND); -var_dump($data === bin2hex($string)); +var_dump($data === $string); ?> --CLEAN-- Date: Mon, 24 Jul 2023 11:02:44 -0300 Subject: [PATCH 09/11] make suggested simplifications the PDO_DBLIB change predates the PDO_BINARY proposa, so... --- ext/pdo_dblib/dblib_driver.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/ext/pdo_dblib/dblib_driver.c b/ext/pdo_dblib/dblib_driver.c index dd03cdcf8b244..70a0aaf4522a5 100644 --- a/ext/pdo_dblib/dblib_driver.c +++ b/ext/pdo_dblib/dblib_driver.c @@ -145,7 +145,7 @@ static zend_long dblib_handle_doer(pdo_dbh_t *dbh, const zend_string *sql) static zend_string* dblib_handle_quoter(pdo_dbh_t *dbh, const zend_string *unquoted, enum pdo_param_type paramtype) { pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data; - bool use_national_character_set = 0, is_binary = false; + bool use_national_character_set = 0; size_t i; char *q; size_t quotedlen = 0; @@ -166,15 +166,8 @@ static zend_string* dblib_handle_quoter(pdo_dbh_t *dbh, const zend_string *unquo * binary literal instead. */ if (paramtype == PDO_PARAM_BINARY) { - is_binary = true; - } - - if (is_binary) { /* 1 char = 2 chars in hex, plus 0x */ - quotedlen = ZSTR_LEN(unquoted) * 2; /* XXX: Overflow? */ - quotedlen += 2; - - quoted_str = zend_string_alloc(quotedlen, 0); + quoted_str = zend_string_safe_alloc(ZSTR_LEN(unquoted), 2, 2, false); q = ZSTR_VAL(quoted_str); *q++ = '0'; *q++ = 'x'; From 386cb4e106767e5170adb65eeafa938120859127 Mon Sep 17 00:00:00 2001 From: Calvin Buckley Date: Fri, 8 Nov 2024 13:42:18 -0400 Subject: [PATCH 10/11] Fix rebase error --- ext/pdo/pdo_dbh.stub.php | 2 +- ext/pdo/pdo_dbh_arginfo.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ext/pdo/pdo_dbh.stub.php b/ext/pdo/pdo_dbh.stub.php index b87b5a193ac64..c8376c21836bc 100644 --- a/ext/pdo/pdo_dbh.stub.php +++ b/ext/pdo/pdo_dbh.stub.php @@ -18,7 +18,7 @@ class PDO /** @cvalue LONG_CONST(PDO_PARAM_STMT) */ public const int PARAM_STMT = 4; /** @cvalue LONG_CONST(PDO_PARAM_BINARY) */ - public const int PARAM_BINARY = 4; + public const int PARAM_BINARY = 6; /** @cvalue LONG_CONST(PDO_PARAM_INPUT_OUTPUT) */ public const int PARAM_INPUT_OUTPUT = UNKNOWN; /** @cvalue LONG_CONST(PDO_PARAM_STR_NATL) */ diff --git a/ext/pdo/pdo_dbh_arginfo.h b/ext/pdo/pdo_dbh_arginfo.h index fe6b2aef44175..4271ccc4652d7 100644 --- a/ext/pdo/pdo_dbh_arginfo.h +++ b/ext/pdo/pdo_dbh_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 6b172de5fd309fc3be57c2e0d6ced2d0f63b8383 */ + * Stub hash: e0faa5c9dda689ae7c22a73df8d720f75e721d50 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_PDO___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, dsn, IS_STRING, 0) @@ -156,7 +156,7 @@ static zend_class_entry *register_class_PDO(void) zend_string *const_PARAM_BINARY_name = zend_string_init_interned("PARAM_BINARY", sizeof("PARAM_BINARY") - 1, 1); zend_declare_typed_class_constant(class_entry, const_PARAM_BINARY_name, &const_PARAM_BINARY_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_PARAM_BINARY_name); - ZEND_ASSERT(LONG_CONST(PDO_PARAM_BINARY) == 4); + ZEND_ASSERT(LONG_CONST(PDO_PARAM_BINARY) == 6); zval const_PARAM_INPUT_OUTPUT_value; ZVAL_LONG(&const_PARAM_INPUT_OUTPUT_value, LONG_CONST(PDO_PARAM_INPUT_OUTPUT)); From deca6739df3a5e6dd20da368994d4123416727b3 Mon Sep 17 00:00:00 2001 From: Calvin Buckley Date: Fri, 8 Nov 2024 14:49:24 -0400 Subject: [PATCH 11/11] use getDbConnection for this test --- ext/pdo_dblib/tests/pdo_dblib_binary.phpt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/pdo_dblib/tests/pdo_dblib_binary.phpt b/ext/pdo_dblib/tests/pdo_dblib_binary.phpt index f209474a0b518..1fd3c4467db62 100644 --- a/ext/pdo_dblib/tests/pdo_dblib_binary.phpt +++ b/ext/pdo_dblib/tests/pdo_dblib_binary.phpt @@ -18,7 +18,7 @@ $query = // "insert into #php_pdo values ?;" . // "drop table #php_pdo;"; -$db = new PDO($dsn, $user, $pass); +$db = getDbConnection(); $stmt = $db->prepare($query); // PARAM_LOB gets converted to a binary literal instead of a string literal