Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added error handling for LOB types as output parameters #584

Merged
merged 3 commits into from
Nov 3, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions source/pdo_sqlsrv/pdo_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,10 @@ pdo_error PDO_ERRORS[] = {
PDO_SQLSRV_ERROR_CE_EMULATE_PREPARE_UNSUPPORTED,
{ IMSSP, (SQLCHAR*) "Parameterized statement with attribute PDO::ATTR_EMULATE_PREPARES is not supported in a Column Encryption enabled Connection.", -82, false }
},
{
SQLSRV_ERROR_OUTPUT_PARAM_TYPES_NOT_SUPPORTED,
{ IMSSP, (SQLCHAR*) "Stored Procedures do not support text, ntext or image as OUTPUT parameters.", -83, false }
},
{ UINT_MAX, {} }
};

Expand Down
1 change: 1 addition & 0 deletions source/shared/core_sqlsrv.h
Original file line number Diff line number Diff line change
Expand Up @@ -1689,6 +1689,7 @@ enum SQLSRV_ERROR_CODES {
SQLSRV_ERROR_KEYSTORE_PATH_MISSING,
SQLSRV_ERROR_KEYSTORE_KEY_MISSING,
SQLSRV_ERROR_KEYSTORE_INVALID_VALUE,
SQLSRV_ERROR_OUTPUT_PARAM_TYPES_NOT_SUPPORTED,

// Driver specific error codes starts from here.
SQLSRV_ERROR_DRIVER_SPECIFIC = 1000,
Expand Down
6 changes: 6 additions & 0 deletions source/shared/core_stmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,12 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_

// if it's an output parameter and the user asks for a certain type, we have to convert the zval to that type so
// when the buffer is filled, the type is correct
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should amend this comment to explain the error check that you added below. "But first, check that we are not using a LOB type with an output parameter" or something like that.

CHECK_CUSTOM_ERROR( direction != SQL_PARAM_INPUT && (sql_type == SQL_LONGVARCHAR
|| sql_type == SQL_WLONGVARCHAR || sql_type == SQL_LONGVARBINARY),
stmt, SQLSRV_ERROR_OUTPUT_PARAM_TYPES_NOT_SUPPORTED ){
throw core::CoreException();
}

if( direction == SQL_PARAM_OUTPUT ){
switch( php_out_type ) {
case SQLSRV_PHPTYPE_INT:
Expand Down
5 changes: 5 additions & 0 deletions source/sqlsrv/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,11 @@ ss_error SS_ERRORS[] = {
SQLSRV_ERROR_SPECIFIED_DRIVER_NOT_FOUND,
{ IMSSP, (SQLCHAR*) "The specified ODBC Driver is not found.", -107, false }
},
{
SQLSRV_ERROR_OUTPUT_PARAM_TYPES_NOT_SUPPORTED,
{ IMSSP, (SQLCHAR*) "Stored Procedures do not support text, ntext or image as OUTPUT parameters.", -108, false }
},

// terminate the list of errors/warnings
{ UINT_MAX, {} }
};
Expand Down
133 changes: 133 additions & 0 deletions test/functional/sqlsrv/srv_231_string_truncation_text.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
--TEST--
GitHub issue #231 - String truncation when binding text/ntext/image to check error messages
--ENV--
PHPT_EXEC=true
--SKIPIF--
<?php require('skipif_versions_old.inc'); ?>
--FILE--
<?php

sqlsrv_configure('WarningsReturnAsErrors', 1);

require_once("MsCommon.inc");

// connect
$conn = AE\connect();
if (!$conn) {
fatalError("Connection could not be established.\n");
}

$tableName = 'testLOBTypes_GH231';
$columnNames = array("c1", "c2");

for ($k = 1; $k <= 3; $k++) {
$sqlType = sqlType($k);
$columns = array(new AE\ColumnMeta('int', $columnNames[0]),
new AE\ColumnMeta($sqlType, $columnNames[1]));
AE\createTable($conn, $tableName, $columns);

$sql = "INSERT INTO [$tableName] ($columnNames[0], $columnNames[1]) VALUES (?, ?)";
$data = getData($k);

$phpType = SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR);
$sqlsrvSQLType = sqlsrvSqlType($k, strlen($data));

$params = array($k, array($data, SQLSRV_PARAM_IN, $phpType, $sqlsrvSQLType));
$stmt = sqlsrv_prepare($conn, $sql, $params);
sqlsrv_execute($stmt);
sqlsrv_free_stmt($stmt);

execProc($conn, $tableName, $columnNames, $k, $data, $sqlType);

dropTable($conn, $tableName);
}

sqlsrv_close($conn);


function execProc($conn, $tableName, $columnNames, $k, $data, $sqlType)
{
$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);

echo "\nData Type: ".$sqlType." binding as \n";

$direction = SQLSRV_PARAM_OUT;
echo "Output parameter: ";
invokeProc($conn, $procName, $k, $direction, $data);

$direction = SQLSRV_PARAM_INOUT;
echo "InOut parameter: ";
invokeProc($conn, $procName, $k, $direction, $data);

dropProc($conn, $procName);
}

function invokeProc($conn, $procName, $k, $direction, $data)
{
$sqlsrvSQLType = sqlsrvSqlType($k, strlen($data));
$callArgs = "?, ?";

// Data to initialize $callResult variable
$initData = "ShortString";
$callResult = $initData;

// Make sure not to specify the PHP type
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why must you not specify the php type here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a copy of another test for issue #231. I can remove the comment if you like. It doesn't matter for this particular test

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then may as well remove it...

$intType = AE\isColEncrypted()? SQLSRV_SQLTYPE_INT : null;
$params = array( array( $k, SQLSRV_PARAM_IN, null, $intType ),
array( &$callResult, $direction, null, $sqlsrvSQLType ));
$stmt = sqlsrv_query($conn, "{ CALL [$procName] ($callArgs)}", $params);
if ($stmt) {
fatalError("Expect this to fail!");
} else {
echo (sqlsrv_errors()[0]['message']) . PHP_EOL;
}
}

function getData($k)
{
$data = "LongStringForTesting";
return $data;
}

function sqlType($k)
{
switch ($k) {
case 1: return ("text");
case 2: return ("ntext");
case 3: return ("image");
default: break;
}
return ("udt");
}

function sqlsrvSqlType($k, $dataSize)
{
switch ($k) {
case 1: return (SQLSRV_SQLTYPE_TEXT);
case 2: return (SQLSRV_SQLTYPE_NTEXT);
case 3: return (SQLSRV_SQLTYPE_IMAGE);
default: break;
}
return (SQLSRV_SQLTYPE_UDT);
}

?>

--EXPECT--

Data Type: text binding as
Output parameter: Stored Procedures do not support text, ntext or image as OUTPUT parameters.
InOut parameter: Stored Procedures do not support text, ntext or image as OUTPUT parameters.

Data Type: ntext binding as
Output parameter: Stored Procedures do not support text, ntext or image as OUTPUT parameters.
InOut parameter: Stored Procedures do not support text, ntext or image as OUTPUT parameters.

Data Type: image binding as
Output parameter: Stored Procedures do not support text, ntext or image as OUTPUT parameters.
InOut parameter: Stored Procedures do not support text, ntext or image as OUTPUT parameters.