Modified how to bind parameters when AE is enabled
This commit is contained in:
parent
04f50341bc
commit
ef45560db0
|
@ -545,6 +545,21 @@ void core_sqlsrv_prepare( _Inout_ sqlsrv_stmt* stmt, _In_reads_bytes_(sql_len) c
|
||||||
|
|
||||||
// prepare our wide char query string
|
// prepare our wide char query string
|
||||||
core::SQLPrepareW( stmt, reinterpret_cast<SQLWCHAR*>( wsql_string.get() ), wsql_len TSRMLS_CC );
|
core::SQLPrepareW( stmt, reinterpret_cast<SQLWCHAR*>( wsql_string.get() ), wsql_len TSRMLS_CC );
|
||||||
|
|
||||||
|
stmt->param_descriptions.clear();
|
||||||
|
|
||||||
|
// if AE is enabled, get meta data for all parameters before binding them
|
||||||
|
if( stmt->conn->ce_option.enabled ) {
|
||||||
|
SQLSMALLINT num_params;
|
||||||
|
core::SQLNumParams( stmt, &num_params);
|
||||||
|
for( int i = 0; i < num_params; i++ ) {
|
||||||
|
param_meta_data param;
|
||||||
|
|
||||||
|
core::SQLDescribeParam( stmt, i + 1, &( param.sql_type ), &( param.column_size ), &( param.decimal_digits ), &( param.nullable ) );
|
||||||
|
|
||||||
|
stmt->param_descriptions.push_back( param );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch( core::CoreException& ) {
|
catch( core::CoreException& ) {
|
||||||
|
|
||||||
|
|
|
@ -156,6 +156,7 @@ OACR_WARNING_POP
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
// included for SQL Server specific constants
|
// included for SQL Server specific constants
|
||||||
#include "msodbcsql.h"
|
#include "msodbcsql.h"
|
||||||
|
|
||||||
|
@ -1345,6 +1346,23 @@ struct sqlsrv_output_param {
|
||||||
// forward decls
|
// forward decls
|
||||||
struct sqlsrv_result_set;
|
struct sqlsrv_result_set;
|
||||||
|
|
||||||
|
// *** parameter metadata struct ***
|
||||||
|
struct param_meta_data
|
||||||
|
{
|
||||||
|
SQLSMALLINT sql_type;
|
||||||
|
SQLSMALLINT decimal_digits;
|
||||||
|
SQLSMALLINT nullable;
|
||||||
|
SQLULEN column_size;
|
||||||
|
|
||||||
|
param_meta_data() : sql_type(0), decimal_digits(0), column_size(0), nullable(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~param_meta_data()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// *** Statement resource structure ***
|
// *** Statement resource structure ***
|
||||||
struct sqlsrv_stmt : public sqlsrv_context {
|
struct sqlsrv_stmt : public sqlsrv_context {
|
||||||
|
|
||||||
|
@ -1383,6 +1401,8 @@ struct sqlsrv_stmt : public sqlsrv_context {
|
||||||
zval col_cache; // Used by get_field_as_string not to call SQLColAttribute() after every fetch.
|
zval col_cache; // Used by get_field_as_string not to call SQLColAttribute() after every fetch.
|
||||||
zval active_stream; // the currently active stream reading data from the database
|
zval active_stream; // the currently active stream reading data from the database
|
||||||
|
|
||||||
|
std::vector<param_meta_data> param_descriptions;
|
||||||
|
|
||||||
sqlsrv_stmt( _In_ sqlsrv_conn* c, _In_ SQLHANDLE handle, _In_ error_callback e, _In_opt_ void* drv TSRMLS_DC );
|
sqlsrv_stmt( _In_ sqlsrv_conn* c, _In_ SQLHANDLE handle, _In_ error_callback e, _In_opt_ void* drv TSRMLS_DC );
|
||||||
virtual ~sqlsrv_stmt( void );
|
virtual ~sqlsrv_stmt( void );
|
||||||
|
|
||||||
|
@ -2007,6 +2027,16 @@ namespace core {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void SQLNumParams( _Inout_ sqlsrv_stmt* stmt, _Out_opt_ SQLSMALLINT* num_params)
|
||||||
|
{
|
||||||
|
SQLRETURN r;
|
||||||
|
r = ::SQLNumParams( stmt->handle(), num_params );
|
||||||
|
|
||||||
|
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
|
||||||
|
throw CoreException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline void SQLEndTran( _In_ SQLSMALLINT handleType, _Inout_ sqlsrv_conn* conn, _In_ SQLSMALLINT completionType TSRMLS_DC )
|
inline void SQLEndTran( _In_ SQLSMALLINT handleType, _Inout_ sqlsrv_conn* conn, _In_ SQLSMALLINT completionType TSRMLS_DC )
|
||||||
{
|
{
|
||||||
SQLRETURN r = ::SQLEndTran( handleType, conn->handle(), completionType );
|
SQLRETURN r = ::SQLEndTran( handleType, conn->handle(), completionType );
|
||||||
|
|
|
@ -102,8 +102,6 @@ void default_sql_size_and_scale( _Inout_ sqlsrv_stmt* stmt, _In_opt_ unsigned in
|
||||||
// given a zval and encoding, determine the appropriate sql type, column size, and decimal scale (if appropriate)
|
// given a zval and encoding, determine the appropriate sql type, column size, and decimal scale (if appropriate)
|
||||||
void default_sql_type( _Inout_ sqlsrv_stmt* stmt, _In_opt_ SQLULEN paramno, _In_ zval* param_z, _In_ SQLSRV_ENCODING encoding,
|
void default_sql_type( _Inout_ sqlsrv_stmt* stmt, _In_opt_ SQLULEN paramno, _In_ zval* param_z, _In_ SQLSRV_ENCODING encoding,
|
||||||
_Out_ SQLSMALLINT& sql_type TSRMLS_DC );
|
_Out_ SQLSMALLINT& sql_type TSRMLS_DC );
|
||||||
void ae_get_sql_type_info( _Inout_ sqlsrv_stmt* stmt, _In_opt_ SQLULEN paramno, _In_ SQLSMALLINT direction, _In_ zval* param_z, _In_ SQLSRV_ENCODING encoding,
|
|
||||||
_Out_ SQLSMALLINT& sql_type, _Out_ SQLULEN& column_size, _Out_ SQLSMALLINT& decimal_digits TSRMLS_DC );
|
|
||||||
void col_cache_dtor( _Inout_ zval* data_z );
|
void col_cache_dtor( _Inout_ zval* data_z );
|
||||||
void field_cache_dtor( _Inout_ zval* data_z );
|
void field_cache_dtor( _Inout_ zval* data_z );
|
||||||
void finalize_output_parameters( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC );
|
void finalize_output_parameters( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC );
|
||||||
|
@ -466,7 +464,11 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_
|
||||||
encoding == SQLSRV_ENCODING_BINARY ), "core_sqlsrv_bind_param: invalid encoding" );
|
encoding == SQLSRV_ENCODING_BINARY ), "core_sqlsrv_bind_param: invalid encoding" );
|
||||||
|
|
||||||
if( stmt->conn->ce_option.enabled && ( sql_type == SQL_UNKNOWN_TYPE || column_size == SQLSRV_UNKNOWN_SIZE )){
|
if( stmt->conn->ce_option.enabled && ( sql_type == SQL_UNKNOWN_TYPE || column_size == SQLSRV_UNKNOWN_SIZE )){
|
||||||
ae_get_sql_type_info( stmt, param_num, direction, param_z, encoding, sql_type, column_size, decimal_digits TSRMLS_CC );
|
// use the meta data only if the user has not specified the sql type or column size
|
||||||
|
sql_type = stmt->param_descriptions[param_num].sql_type;
|
||||||
|
column_size = stmt->param_descriptions[param_num].column_size;
|
||||||
|
decimal_digits = stmt->param_descriptions[param_num].decimal_digits;
|
||||||
|
|
||||||
// change long to double if the sql type is decimal
|
// change long to double if the sql type is decimal
|
||||||
if(( sql_type == SQL_DECIMAL || sql_type == SQL_NUMERIC ) && Z_TYPE_P(param_z) == IS_LONG )
|
if(( sql_type == SQL_DECIMAL || sql_type == SQL_NUMERIC ) && Z_TYPE_P(param_z) == IS_LONG )
|
||||||
convert_to_double( param_z );
|
convert_to_double( param_z );
|
||||||
|
@ -2085,13 +2087,6 @@ void default_sql_size_and_scale( _Inout_ sqlsrv_stmt* stmt, _In_opt_ unsigned in
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ae_get_sql_type_info( _Inout_ sqlsrv_stmt* stmt, _In_opt_ SQLULEN paramno, _In_ SQLSMALLINT direction, _In_ zval* param_z, _In_ SQLSRV_ENCODING encoding,
|
|
||||||
_Out_ SQLSMALLINT& sql_type, _Out_ SQLULEN& column_size, _Out_ SQLSMALLINT& decimal_digits TSRMLS_DC )
|
|
||||||
{
|
|
||||||
SQLSMALLINT Nullable;
|
|
||||||
core::SQLDescribeParam( stmt, paramno + 1, &sql_type, &column_size, &decimal_digits, &Nullable );
|
|
||||||
}
|
|
||||||
|
|
||||||
void col_cache_dtor( _Inout_ zval* data_z )
|
void col_cache_dtor( _Inout_ zval* data_z )
|
||||||
{
|
{
|
||||||
col_cache* cache = static_cast<col_cache*>( Z_PTR_P( data_z ));
|
col_cache* cache = static_cast<col_cache*>( Z_PTR_P( data_z ));
|
||||||
|
|
|
@ -8,12 +8,12 @@ require_once("MsCommon_mid-refactor.inc");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Connect
|
// Connect
|
||||||
// set errmode to silent to compare sqlstates in the test
|
$conn = connect();
|
||||||
$conn = connect("", array(), PDO::ERRMODE_SILENT);
|
|
||||||
|
|
||||||
// Create table
|
// Create table
|
||||||
$tableName = 'pdo_040test';
|
$tableName = 'pdo_040test';
|
||||||
// common function insertRow() is not used here since the test deliberately executes an invalid insertion statement
|
// common function insertRow() is not used here since the test deliberately
|
||||||
|
// executes an invalid insertion statement
|
||||||
// thus it's not necessary to create an encrypted column for testing column encryption
|
// thus it's not necessary to create an encrypted column for testing column encryption
|
||||||
$sql = "CREATE TABLE $tableName (code INT)";
|
$sql = "CREATE TABLE $tableName (code INT)";
|
||||||
$stmt = $conn->exec($sql);
|
$stmt = $conn->exec($sql);
|
||||||
|
@ -22,37 +22,36 @@ try {
|
||||||
// Number of supplied values does not match table definition
|
// Number of supplied values does not match table definition
|
||||||
$sql = "INSERT INTO $tableName VALUES (?,?)";
|
$sql = "INSERT INTO $tableName VALUES (?,?)";
|
||||||
$stmt = $conn->prepare($sql);
|
$stmt = $conn->prepare($sql);
|
||||||
$params = array(2010,"London");
|
$params = array(2010, "London");
|
||||||
|
|
||||||
// SQL statement has an error, which is then reported
|
// SQL statement has an error, which is then reported
|
||||||
$stmt->execute($params);
|
if ($stmt) {
|
||||||
$error = $stmt->errorInfo();
|
$stmt->execute($params);
|
||||||
|
}
|
||||||
$success = true;
|
} catch (PDOException $e) {
|
||||||
|
$error = $e->errorInfo;
|
||||||
|
$success = false;
|
||||||
if (!isColEncrypted()) {
|
if (!isColEncrypted()) {
|
||||||
// 21S01 is the expected ODBC Column name or number of supplied values does not match table definition error
|
// 21S01 is the expected ODBC Column name or number of supplied values does not match table definition error
|
||||||
if ($error[0] != "21S01") {
|
if ($error[0] === "21S01") {
|
||||||
$success = false;
|
$success = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 07009 is the expected ODBC Invalid Descriptor Index error
|
// 07009 is the expected ODBC Invalid Descriptor Index error
|
||||||
if ($error[0] != "07009") {
|
if ($error[0] === "07009") {
|
||||||
$success = false;
|
$success = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close connection
|
|
||||||
dropTable($conn, $tableName);
|
|
||||||
unset($stmt);
|
|
||||||
unset($conn);
|
|
||||||
|
|
||||||
if ($success) {
|
if ($success) {
|
||||||
print "Done";
|
print "Done";
|
||||||
} else {
|
} else {
|
||||||
var_dump($error);
|
var_dump($error);
|
||||||
}
|
}
|
||||||
} catch (PDOException $e) {
|
} finally {
|
||||||
var_dump($e->errorInfo);
|
// Clean up and close connection
|
||||||
|
dropTable($conn, $tableName);
|
||||||
|
unset($stmt);
|
||||||
|
unset($conn);
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|
||||||
|
|
|
@ -7,20 +7,14 @@ Exception is thrown for the unsupported connection attribute ATTR_PREFETCH only
|
||||||
--FILE--
|
--FILE--
|
||||||
<?php
|
<?php
|
||||||
require_once("MsSetup.inc");
|
require_once("MsSetup.inc");
|
||||||
|
require_once("MsCommon_mid-refactor.inc");
|
||||||
try {
|
try {
|
||||||
echo "Testing a connection with ATTR_PREFETCH before ERRMODE_EXCEPTION...\n";
|
echo "Testing a connection with ATTR_PREFETCH before ERRMODE_EXCEPTION...\n";
|
||||||
$dsn = "sqlsrv:Server = $server;database = $databaseName";
|
$dsn = getDSN($server, $databaseName);
|
||||||
if ($keystore != "none")
|
|
||||||
$dsn .= "ColumnEncryption=Enabled;";
|
|
||||||
if ($keystore == "ksp") {
|
|
||||||
require_once("AE_Ksp.inc");
|
|
||||||
$ksp_path = getKSPPath();
|
|
||||||
$dsn .= "CEKeystoreProvider=$ksp_path;CEKeystoreName=$ksp_name;CEKeystoreEncryptKey=$encrypt_key;";
|
|
||||||
}
|
|
||||||
|
|
||||||
$attr = array(PDO::ATTR_PREFETCH => true, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION);
|
$attr = array(PDO::ATTR_PREFETCH => true, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION);
|
||||||
$conn = new PDO($dsn, $uid, $pwd, $attr);
|
$conn = new PDO($dsn, $uid, $pwd, $attr);
|
||||||
echo "Error from supported attribute (ATTR_PREFETCH) is silented\n\n";
|
echo "Error from unsupported attribute (ATTR_PREFETCH) is silenced\n\n";
|
||||||
unset($conn);
|
unset($conn);
|
||||||
|
|
||||||
echo "Testing a connection with ATTR_PREFETCH after ERRMODE_EXCEPTION...\n";
|
echo "Testing a connection with ATTR_PREFETCH after ERRMODE_EXCEPTION...\n";
|
||||||
|
@ -35,7 +29,7 @@ try {
|
||||||
|
|
||||||
--EXPECT--
|
--EXPECT--
|
||||||
Testing a connection with ATTR_PREFETCH before ERRMODE_EXCEPTION...
|
Testing a connection with ATTR_PREFETCH before ERRMODE_EXCEPTION...
|
||||||
Error from supported attribute (ATTR_PREFETCH) is silented
|
Error from unsupported attribute (ATTR_PREFETCH) is silenced
|
||||||
|
|
||||||
Testing a connection with ATTR_PREFETCH after ERRMODE_EXCEPTION...
|
Testing a connection with ATTR_PREFETCH after ERRMODE_EXCEPTION...
|
||||||
Exception from unsupported attribute (ATTR_PREFETCH) is caught
|
Exception from unsupported attribute (ATTR_PREFETCH) is caught
|
||||||
|
|
|
@ -12,9 +12,9 @@ function insertOneRow($conn, $tableName)
|
||||||
$result = null;
|
$result = null;
|
||||||
if (AE\isColEncrypted()) {
|
if (AE\isColEncrypted()) {
|
||||||
$data = array("Field2" => "This is field 2.",
|
$data = array("Field2" => "This is field 2.",
|
||||||
"Field3" => array("010203", null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_IMAGE),
|
"Field3" => "010203",
|
||||||
"Field4" => "This is field 4.",
|
"Field4" => "This is field 4.",
|
||||||
"Field5" => array("040506", null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY('max')),
|
"Field5" => "040506",
|
||||||
"Field6" => "This is field 6.",
|
"Field6" => "This is field 6.",
|
||||||
"Field7" => "This is field 7.");
|
"Field7" => "This is field 7.");
|
||||||
$query = AE\getInsertSqlPlaceholders($tableName, $data);
|
$query = AE\getInsertSqlPlaceholders($tableName, $data);
|
||||||
|
@ -42,8 +42,7 @@ function updateRow($conn, $tableName, $updateField, $params)
|
||||||
|
|
||||||
if (AE\isColEncrypted()) {
|
if (AE\isColEncrypted()) {
|
||||||
$query = "UPDATE $tableName SET $updateField=? WHERE $condField = ?";
|
$query = "UPDATE $tableName SET $updateField=? WHERE $condField = ?";
|
||||||
|
array_push($params, $condition);
|
||||||
array_push($params, array($condition, SQLSRV_PARAM_IN, null, SQLSRV_SQLTYPE_NVARCHAR('max')));
|
|
||||||
} else {
|
} else {
|
||||||
$query = "UPDATE $tableName SET $updateField=? WHERE $condField = '$condition'";
|
$query = "UPDATE $tableName SET $updateField=? WHERE $condField = '$condition'";
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue