From 6d7cddf5f66152f0f1606adf93fc82fae63d1712 Mon Sep 17 00:00:00 2001 From: v-kaywon Date: Fri, 21 Apr 2017 14:57:57 -0700 Subject: [PATCH] added error handling for emulate prepare with output parameter --- source/pdo_sqlsrv/pdo_parser.cpp | 12 ++++- source/pdo_sqlsrv/php_pdo_sqlsrv.h | 2 +- ...ement_bindParam_inout_emulate_prepare.phpt | 2 +- ...ment_bindParam_output_emulate_prepare.phpt | 52 +++++++++++++++++++ 4 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 test/pdo_sqlsrv/pdoStatement_bindParam_output_emulate_prepare.phpt diff --git a/source/pdo_sqlsrv/pdo_parser.cpp b/source/pdo_sqlsrv/pdo_parser.cpp index 0bc645387..10cedace9 100644 --- a/source/pdo_sqlsrv/pdo_parser.cpp +++ b/source/pdo_sqlsrv/pdo_parser.cpp @@ -101,7 +101,7 @@ int conn_string_parser::discard_trailing_white_spaces( const char* str, int len } // Discard white spaces. -bool conn_string_parser::discard_white_spaces() +bool string_parser::discard_white_spaces() { if( this->is_eos() ) { @@ -477,6 +477,12 @@ void sql_string_parser::parse_sql_string( TSRMLS_D ) { next(); } add_key_value_pair( &( this->orig_str[start_pos] ), this->pos - start_pos TSRMLS_CC ); + discard_white_spaces(); + // if an '=' is right after a placeholder, it means the placeholder is for output parameters + // and emulate prepare does not support output parameters + if (this->orig_str[pos] == '=') { + THROW_PDO_ERROR(this->ctx, PDO_SQLSRV_ERROR_EMULATE_INOUT_UNSUPPORTED); + } this->current_key++; } // if '?', don't need to parse anymore since the position of the bound_param is already stored in the bound_params ht @@ -484,6 +490,10 @@ void sql_string_parser::parse_sql_string( TSRMLS_D ) { next(); // add dummy value to placeholders ht to keep count of the number of placeholders add_key_int_value_pair( this->current_key ); + discard_white_spaces(); + if (this->orig_str[pos] == '=') { + THROW_PDO_ERROR(this->ctx, PDO_SQLSRV_ERROR_EMULATE_INOUT_UNSUPPORTED); + } this->current_key++; } } diff --git a/source/pdo_sqlsrv/php_pdo_sqlsrv.h b/source/pdo_sqlsrv/php_pdo_sqlsrv.h index 26bb0cc16..1b5234f5f 100644 --- a/source/pdo_sqlsrv/php_pdo_sqlsrv.h +++ b/source/pdo_sqlsrv/php_pdo_sqlsrv.h @@ -138,6 +138,7 @@ class string_parser inline bool next(void); inline bool is_eos(void); inline bool is_white_space(char c); + bool discard_white_spaces(void); void add_key_value_pair(const char* value, int len TSRMLS_DC); }; @@ -161,7 +162,6 @@ class conn_string_parser : private string_parser private: const char* current_key_name; - bool discard_white_spaces(void); int discard_trailing_white_spaces(const char* str, int len); void validate_key(const char *key, int key_len TSRMLS_DC); diff --git a/test/pdo_sqlsrv/pdoStatement_bindParam_inout_emulate_prepare.phpt b/test/pdo_sqlsrv/pdoStatement_bindParam_inout_emulate_prepare.phpt index 93483b30c..71d495ea3 100644 --- a/test/pdo_sqlsrv/pdoStatement_bindParam_inout_emulate_prepare.phpt +++ b/test/pdo_sqlsrv/pdoStatement_bindParam_inout_emulate_prepare.phpt @@ -1,5 +1,5 @@ --TEST-- -uses an input/output parameter with emulate prepare +Tests error returned when binding input/output parameter with emulate prepare --SKIPIF-- --FILE-- setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + $count = 0; + + $query = "select ? = count(* ) from cd_info"; + $stmt = $conn->prepare($query, array(PDO::ATTR_EMULATE_PREPARES => true)); + $stmt->bindParam( 1, $count, PDO::PARAM_STR, 10 ); + $stmt->execute(); + echo "Result: ".$count."\n"; + + $query = "select bigint_type, int_type, money_type from [test_types] where int_type < 0"; + $stmt1 = $conn->prepare($query); + $stmt1->execute(); + $row = $stmt1->fetch( PDO::FETCH_ASSOC ); + print_r($row); + + $int = 0; + $bigint = 100; + $query = "select ? = bigint_type, ? = int_type, ? = money_type from [test_types] where int_type < 0"; + $stmt2 = $conn->prepare($query, array(PDO::ATTR_EMULATE_PREPARES => true)); + $stmt2->bindparam( 1, $bigint, PDO::PARAM_STR, 256 ); + $stmt2->bindParam( 2, $int, PDO::PARAM_INT, 4 ); + $stmt2->bindParam( 3, $money, PDO::PARAM_STR, 1024 ); + $stmt2->execute(); + echo "Big integer: ".$bigint."\n"; + echo "Integer: ".$int."\n"; + echo "Money: ".$money."\n"; + + //free the statement and connection + $stmt = null; + $stmt1 = null; + $stmt2 = null; + $conn = null; + +} +catch(PDOException $e) { + print("Error: " . $e->getMessage() . "\n"); +} +?> +--EXPECT-- +Error: SQLSTATE[IMSSP]: Statement with emulate prepare on does not support output or input_output parameters. \ No newline at end of file