Modified how to bind parameters when AE is enabled

This commit is contained in:
Jenny Tam 2017-11-16 10:30:44 -08:00
parent 04f50341bc
commit ef45560db0
6 changed files with 77 additions and 45 deletions

View file

@ -545,6 +545,21 @@ void core_sqlsrv_prepare( _Inout_ sqlsrv_stmt* stmt, _In_reads_bytes_(sql_len) c
// prepare our wide char query string
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& ) {

View file

@ -156,6 +156,7 @@ OACR_WARNING_POP
#include <limits>
#include <cassert>
#include <memory>
#include <vector>
// included for SQL Server specific constants
#include "msodbcsql.h"
@ -1345,6 +1346,23 @@ struct sqlsrv_output_param {
// forward decls
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 ***
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 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 );
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 )
{
SQLRETURN r = ::SQLEndTran( handleType, conn->handle(), completionType );

View file

@ -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)
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 );
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 field_cache_dtor( _Inout_ zval* data_z );
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" );
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
if(( sql_type == SQL_DECIMAL || sql_type == SQL_NUMERIC ) && Z_TYPE_P(param_z) == IS_LONG )
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 )
{
col_cache* cache = static_cast<col_cache*>( Z_PTR_P( data_z ));

View file

@ -8,12 +8,12 @@ require_once("MsCommon_mid-refactor.inc");
try {
// Connect
// set errmode to silent to compare sqlstates in the test
$conn = connect("", array(), PDO::ERRMODE_SILENT);
$conn = connect();
// Create table
$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
$sql = "CREATE TABLE $tableName (code INT)";
$stmt = $conn->exec($sql);
@ -22,37 +22,36 @@ try {
// Number of supplied values does not match table definition
$sql = "INSERT INTO $tableName VALUES (?,?)";
$stmt = $conn->prepare($sql);
$params = array(2010,"London");
$params = array(2010, "London");
// SQL statement has an error, which is then reported
$stmt->execute($params);
$error = $stmt->errorInfo();
$success = true;
if ($stmt) {
$stmt->execute($params);
}
} catch (PDOException $e) {
$error = $e->errorInfo;
$success = false;
if (!isColEncrypted()) {
// 21S01 is the expected ODBC Column name or number of supplied values does not match table definition error
if ($error[0] != "21S01") {
$success = false;
if ($error[0] === "21S01") {
$success = true;
}
} else {
// 07009 is the expected ODBC Invalid Descriptor Index error
if ($error[0] != "07009") {
$success = false;
if ($error[0] === "07009") {
$success = true;
}
}
// Close connection
dropTable($conn, $tableName);
unset($stmt);
unset($conn);
}
if ($success) {
print "Done";
} else {
var_dump($error);
}
} catch (PDOException $e) {
var_dump($e->errorInfo);
} finally {
// Clean up and close connection
dropTable($conn, $tableName);
unset($stmt);
unset($conn);
}
?>

View file

@ -7,20 +7,14 @@ Exception is thrown for the unsupported connection attribute ATTR_PREFETCH only
--FILE--
<?php
require_once("MsSetup.inc");
require_once("MsCommon_mid-refactor.inc");
try {
echo "Testing a connection with ATTR_PREFETCH before ERRMODE_EXCEPTION...\n";
$dsn = "sqlsrv:Server = $server;database = $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;";
}
$dsn = getDSN($server, $databaseName);
$attr = array(PDO::ATTR_PREFETCH => true, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION);
$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);
echo "Testing a connection with ATTR_PREFETCH after ERRMODE_EXCEPTION...\n";
@ -35,7 +29,7 @@ try {
--EXPECT--
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...
Exception from unsupported attribute (ATTR_PREFETCH) is caught

View file

@ -12,9 +12,9 @@ function insertOneRow($conn, $tableName)
$result = null;
if (AE\isColEncrypted()) {
$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.",
"Field5" => array("040506", null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY('max')),
"Field5" => "040506",
"Field6" => "This is field 6.",
"Field7" => "This is field 7.");
$query = AE\getInsertSqlPlaceholders($tableName, $data);
@ -42,8 +42,7 @@ function updateRow($conn, $tableName, $updateField, $params)
if (AE\isColEncrypted()) {
$query = "UPDATE $tableName SET $updateField=? WHERE $condField = ?";
array_push($params, array($condition, SQLSRV_PARAM_IN, null, SQLSRV_SQLTYPE_NVARCHAR('max')));
array_push($params, $condition);
} else {
$query = "UPDATE $tableName SET $updateField=? WHERE $condField = '$condition'";
}