Reset sql type and column size for input params that were bound as nulls (#1333)

This commit is contained in:
Jenny Tam 2021-11-22 13:59:32 -08:00 коммит произвёл GitHub
Родитель 14aa44933d
Коммит a570522863
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
4 изменённых файлов: 239 добавлений и 2 удалений

Просмотреть файл

@ -395,6 +395,13 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_
stmt->params_container.insert_param(param_num, new_param); stmt->params_container.insert_param(param_num, new_param);
param_ptr = new_param; param_ptr = new_param;
new_param.transferred(); new_param.transferred();
} else if (direction == SQL_PARAM_INPUT
&& param_ptr->sql_data_type != SQL_SS_TABLE
&& param_ptr->strlen_or_indptr == SQL_NULL_DATA) {
// reset the followings for regular input parameters if it was bound as a null param before
param_ptr->sql_data_type = sql_type;
param_ptr->column_size = column_size;
param_ptr->strlen_or_indptr = 0;
} }
SQLSRV_ASSERT(param_ptr != NULL, "core_sqlsrv_bind_param: param_ptr is null. Something went wrong."); SQLSRV_ASSERT(param_ptr != NULL, "core_sqlsrv_bind_param: param_ptr is null. Something went wrong.");

Просмотреть файл

@ -1187,8 +1187,6 @@ void bind_params( _Inout_ ss_sqlsrv_stmt* stmt )
try { try {
stmt->free_param_data();
stmt->executed = false; stmt->executed = false;
zval* params_z = stmt->params_z; zval* params_z = stmt->params_z;
@ -1265,6 +1263,8 @@ void bind_params( _Inout_ ss_sqlsrv_stmt* stmt )
} ZEND_HASH_FOREACH_END(); } ZEND_HASH_FOREACH_END();
} }
catch( core::CoreException& ) { catch( core::CoreException& ) {
stmt->free_param_data();
SQLFreeStmt( stmt->handle(), SQL_RESET_PARAMS ); SQLFreeStmt( stmt->handle(), SQL_RESET_PARAMS );
zval_ptr_dtor( stmt->params_z ); zval_ptr_dtor( stmt->params_z );
sqlsrv_free( stmt->params_z ); sqlsrv_free( stmt->params_z );

Просмотреть файл

@ -0,0 +1,118 @@
--TEST--
GitHub issue 1329 - string truncation error when binding some parameters as non-nulls the second time
--DESCRIPTION--
The test shows the same parameters, though bound as nulls in the first insertion, can be bound as non-nulls in the subsequent insertions.
--ENV--
PHPT_EXEC=true
--SKIPIF--
<?php require('skipif.inc'); ?>
--FILE--
<?php
require_once("MsSetup.inc");
function dropTable($conn, $tableName)
{
$drop = "IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'" . $tableName . "') AND type in (N'U')) DROP TABLE $tableName";
$conn->exec($drop);
}
try {
$conn = new PDO("sqlsrv:server=$server; Database = $databaseName;", $uid, $pwd);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
dropTable($conn, 'domains');
$tsql = <<<CREATESQL
CREATE TABLE domains (
id bigint IDENTITY(1,1) NOT NULL,
authority nvarchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
base_url_redirect nvarchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
regular_not_found_redirect nvarchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
invalid_short_url_redirect nvarchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
CONSTRAINT PK__domains__3213E83F512B36BA PRIMARY KEY (id))
CREATESQL;
$conn->exec($tsql);
$tsql = <<<INSERTSQL
INSERT INTO domains (authority, base_url_redirect, regular_not_found_redirect, invalid_short_url_redirect) VALUES (?, ?, ?, ?)
INSERTSQL;
$stmt = $conn->prepare($tsql);
$authority = 'foo.com';
$base = null;
$notFound = null;
$invalid = null;
$stmt->bindParam(1, $authority);
$stmt->bindParam(2, $base);
$stmt->bindParam(3, $notFound);
$stmt->bindParam(4, $invalid);
$stmt->execute();
$authority = 'detached-with-ředirects.com';
$base = 'fŏő.com';
$notFound = 'baŗ.com';
$invalid = null;
$stmt->bindParam(1, $authority);
$stmt->bindParam(2, $base);
$stmt->bindParam(3, $notFound);
$stmt->bindParam(4, $invalid);
$stmt->execute();
$authority = 'Őther-redirects.com';
$base = 'fooš.com';
$notFound = null;
$invalid = 'ŷëå';
$stmt->bindParam(1, $authority);
$stmt->bindParam(2, $base);
$stmt->bindParam(3, $notFound);
$stmt->bindParam(4, $invalid);
$stmt->execute();
// fetch the data
$stmt = $conn->prepare("SELECT * FROM domains");
$stmt->execute();
$row = $stmt->fetchAll(PDO::FETCH_NUM);
print_r($row);
dropTable($conn, 'domains');
echo "Done\n";
} catch (PdoException $e) {
echo $e->getMessage();
}
?>
--EXPECT--
Array
(
[0] => Array
(
[0] => 1
[1] => foo.com
[2] =>
[3] =>
[4] =>
)
[1] => Array
(
[0] => 2
[1] => detached-with-ředirects.com
[2] => fŏő.com
[3] => baŗ.com
[4] =>
)
[2] => Array
(
[0] => 3
[1] => Őther-redirects.com
[2] => fooš.com
[3] =>
[4] => ŷëå
)
)
Done

Просмотреть файл

@ -0,0 +1,112 @@
--TEST--
GitHub issue 1329 - string truncation error when binding some parameters as non-nulls the second time
--DESCRIPTION--
The test shows the same parameters, though bound as nulls in the first insertion, can be bound as non-nulls in the subsequent insertions.
--ENV--
PHPT_EXEC=true
--SKIPIF--
<?php require('skipif_versions_old.inc'); ?>
--FILE--
<?php
require_once('MsCommon.inc');
$connectionInfo = array('CharacterSet'=>'UTF-8');
$conn = AE\connect($connectionInfo);
dropTable($conn, 'srv_domains');
$tsql = <<<CREATESQL
CREATE TABLE srv_domains (
id bigint IDENTITY(1,1) NOT NULL,
authority nvarchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
base_url_redirect nvarchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
regular_not_found_redirect nvarchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
invalid_short_url_redirect nvarchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
CONSTRAINT PK__srv_domains__3213E83F512B36BA PRIMARY KEY (id))
CREATESQL;
$stmt = sqlsrv_query($conn, $tsql);
if (!$stmt) {
fatalError("failed to create test table");
}
$tsql = <<<INSERTSQL
INSERT INTO srv_domains (authority, base_url_redirect, regular_not_found_redirect, invalid_short_url_redirect) VALUES (?, ?, ?, ?)
INSERTSQL;
$authority = 'foo.com';
$base = null;
$notFound = null;
$invalid = null;
$params = [&$authority, &$base, &$notFound, &$invalid];
$stmt = sqlsrv_prepare($conn, $tsql, $params);
if (!$stmt) {
fatalError("failed to prepare the insert statement");
}
$result = sqlsrv_execute($stmt);
if (!$result) {
fatalError("failed to execute the insert statement (1)");
}
$authority = 'detached-with-ředirects.com';
$base = 'fŏő.com';
$notFound = 'baŗ.com';
$invalid = null;
$result = sqlsrv_execute($stmt);
if (!$result) {
fatalError("failed to execute the insert statement (2)");
}
$authority = 'Őther-redirects.com';
$base = 'fooš.com';
$notFound = null;
$invalid = 'ŷëå';
$result = sqlsrv_execute($stmt);
if (!$result) {
fatalError("failed to execute the insert statement (3)");
}
// fetch the data
$tsql = "SELECT * FROM srv_domains";
$stmt = sqlsrv_query($conn, $tsql);
if (!$stmt) {
fatalError("failed to run select query");
}
while ($row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_NUMERIC)) {
print_r($row);
}
dropTable($conn, 'srv_domains');
sqlsrv_free_stmt($stmt);
sqlsrv_close($conn);
echo "Done\n";
?>
--EXPECT--
Array
(
[0] => 1
[1] => foo.com
[2] =>
[3] =>
[4] =>
)
Array
(
[0] => 2
[1] => detached-with-ředirects.com
[2] => fŏő.com
[3] => baŗ.com
[4] =>
)
Array
(
[0] => 3
[1] => Őther-redirects.com
[2] => fooš.com
[3] =>
[4] => ŷëå
)
Done