diff --git a/source/shared/core_stmt.cpp b/source/shared/core_stmt.cpp index 052884eeb..f9c854b27 100644 --- a/source/shared/core_stmt.cpp +++ b/source/shared/core_stmt.cpp @@ -394,6 +394,9 @@ void core_sqlsrv_bind_param( sqlsrv_stmt* stmt, SQLUSMALLINT param_num, SQLSMALL break; case SQLSRV_PHPTYPE_STRING: convert_to_string( param_z ); + if (column_size == SQL_SS_LENGTH_UNLIMITED) { + column_size = SQLSRV_UNKNOWN_SIZE; // reset + } break; case SQLSRV_PHPTYPE_NULL: case SQLSRV_PHPTYPE_DATETIME: @@ -533,6 +536,7 @@ void core_sqlsrv_bind_param( sqlsrv_stmt* stmt, SQLUSMALLINT param_num, SQLSMALL case SQL_VARBINARY: case SQL_VARCHAR: case SQL_WVARCHAR: + case SQL_SS_XML: column_size = SQL_SS_LENGTH_UNLIMITED; break; diff --git a/test/sqlsrv/srv_231_string_truncation_varchar_max.phpt b/test/sqlsrv/srv_231_string_truncation_varchar_max.phpt new file mode 100644 index 000000000..1720d353e --- /dev/null +++ b/test/sqlsrv/srv_231_string_truncation_varchar_max.phpt @@ -0,0 +1,204 @@ +--TEST-- +GitHub issue #231 - String truncation when binding varchar(max) +--SKIPIF-- +--FILE-- +$username, "PWD"=>$password); +$conn = sqlsrv_connect($serverName, $connectionInfo); +if( $conn === false ) { + die( print_r( sqlsrv_errors(), true )); +} + +$tableName = "#testDataTypes_GH231"; +$columnNames = array( "c1","c2" ); + +for ($k = 1; $k <= 8; $k++) +{ + $sqlType = GetSqlType($k); + $dataType = "[$columnNames[0]] int, [$columnNames[1]] $sqlType"; + + $sql = "CREATE TABLE [$tableName] ($dataType)"; + $stmt1 = sqlsrv_query($conn, $sql); + sqlsrv_free_stmt($stmt1); + + $sql = "INSERT INTO [$tableName] ($columnNames[0], $columnNames[1]) VALUES (?, ?)"; + $data = GetData($k); + $phpType = GetPhpType($k); + $driverType = GetDriverType($k, strlen($data)); + + $params = array($k, array($data, SQLSRV_PARAM_IN, $phpType, $driverType)); + $stmt2 = sqlsrv_prepare($conn, $sql, $params); + sqlsrv_execute($stmt2); + sqlsrv_free_stmt($stmt2); + + ExecProc($conn, $tableName, $columnNames, $k, $data, $sqlType); + + $stmt3 = sqlsrv_query($conn, "DROP TABLE [$tableName]"); + sqlsrv_free_stmt($stmt3); +} + +sqlsrv_close($conn); + + +function ExecProc($conn, $tableName, $columnNames, $k, $data, $sqlType) +{ + $driverType = GetDriverType($k, strlen($data)); + + $spArgs = "@p1 int, @p2 $sqlType OUTPUT"; + $spCode = "SET @p2 = ( SELECT c2 FROM $tableName WHERE c1 = @p1 )"; + $procName = "testBindOutSp"; + + $stmt1 = sqlsrv_query($conn, "CREATE PROC [$procName] ($spArgs) AS BEGIN $spCode END"); + sqlsrv_free_stmt($stmt1); + + $callArgs = "?, ?"; + + // Data to initialize $callResult variable. This variable should be shorter than inserted data in the table + $initData = "ShortString"; + $callResult = $initData; + + // Do not specify PHP type + $params = array( array( $k, SQLSRV_PARAM_IN ), + array( &$callResult, SQLSRV_PARAM_OUT, null, $driverType )); + + echo "\nData Type: ".$sqlType."\n"; + echo "Table data:\t$data\nInitial data:\t$initData\nInitial call result:\t$callResult\n"; + + $stmt2 = sqlsrv_query($conn, "{ CALL [$procName] ($callArgs)}", $params); + + // $callResult should be updated to the value in the table + echo "New call result:\t$callResult\n\n"; + + if($stmt2 === false) + { + var_dump( sqlsrv_errors()); + } + else + { + sqlsrv_free_stmt($stmt2); + } + + $stmt3 = sqlsrv_query($conn, "DROP PROC [$procName]"); + sqlsrv_free_stmt($stmt3); +} + +function GetData($k) +{ + $data = "LongStringForTesting"; + if ($k == 8) { + $data = "The quick brown fox jumps over the lazy dog0123456789"; + } + + return $data; +} + +function GetPhpType($k) +{ + $phpType = SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR); + if ($k == 7) { + $phpType = SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_BINARY); + } + + return $phpType; +} + +function GetSqlType($k) +{ + switch ($k) + { + case 1: return ("char(512)"); + case 2: return ("varchar(512)"); + case 3: return ("varchar(max)"); + case 4: return ("nchar(512)"); + case 5: return ("nvarchar(512)"); + case 6: return ("nvarchar(max)"); + case 7: return ("varbinary(max)"); + case 8: return ("xml"); + default: break; + } + return ("udt"); +} + +function GetDriverType($k, $dataSize) +{ + switch ($k) + { + case 1: return (SQLSRV_SQLTYPE_CHAR($dataSize)); + case 2: return (SQLSRV_SQLTYPE_VARCHAR($dataSize)); + case 3: return (SQLSRV_SQLTYPE_VARCHAR('max')); + case 4: return (SQLSRV_SQLTYPE_NCHAR($dataSize)); + case 5: return (SQLSRV_SQLTYPE_NVARCHAR($dataSize)); + case 6: return (SQLSRV_SQLTYPE_NVARCHAR('max')); + case 7: return (SQLSRV_SQLTYPE_VARBINARY('max')); + case 8: return (SQLSRV_SQLTYPE_XML); + + default: break; + } + return (SQLSRV_SQLTYPE_UDT); +} + +?> +--EXPECT-- + +Data Type: char(512) +Table data: LongStringForTesting +Initial data: ShortString +Initial call result: ShortString +New call result: LongStringForTesting + + +Data Type: varchar(512) +Table data: LongStringForTesting +Initial data: ShortString +Initial call result: ShortString +New call result: LongStringForTesting + + +Data Type: varchar(max) +Table data: LongStringForTesting +Initial data: ShortString +Initial call result: ShortString +New call result: LongStringForTesting + + +Data Type: nchar(512) +Table data: LongStringForTesting +Initial data: ShortString +Initial call result: ShortString +New call result: LongStringForTesting + + +Data Type: nvarchar(512) +Table data: LongStringForTesting +Initial data: ShortString +Initial call result: ShortString +New call result: LongStringForTesting + + +Data Type: nvarchar(max) +Table data: LongStringForTesting +Initial data: ShortString +Initial call result: ShortString +New call result: LongStringForTesting + + +Data Type: varbinary(max) +Table data: LongStringForTesting +Initial data: ShortString +Initial call result: ShortString +New call result: 4C6F6E67537472696E67466F7254657374696E67 + + +Data Type: xml +Table data: The quick brown fox jumps over the lazy dog0123456789 +Initial data: ShortString +Initial call result: ShortString +New call result: The quick brown fox jumps over the lazy dog0123456789 + +