/pdo_sqlsrv/pdo_util.cpp
# · C++ · 612 lines · 507 code · 63 blank · 42 comment · 36 complexity · 7a775a5a3be97b645a5188aafcd72835 MD5 · raw file
- //---------------------------------------------------------------------------------------------------------------------------------
- // File: pdo_util.cpp
- //
- // Contents: Utility functions used by both connection or statement functions
- //
- // Copyright Microsoft Corporation
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- //
- // You may obtain a copy of the License at:
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- //---------------------------------------------------------------------------------------------------------------------------------
-
- #include "pdo_sqlsrv.h"
-
- #include "zend_exceptions.h"
-
-
- // *** internal constants ***
- namespace {
-
- const char WARNING_TEMPLATE[] = "SQLSTATE: %1!s!\nError Code: %2!d!\nMError Message: %3!s!\n";
- const char EXCEPTION_MSG_TEMPLATE[] = "SQLSTATE[%s]: %s";
- char EXCEPTION_PROPERTY_MSG[] = "message";
- char EXCEPTION_PROPERTY_CODE[] = "code";
- char EXCEPTION_PROPERTY_ERRORINFO[] = "errorInfo";
- const int MAX_DIGITS = 11; // +-2 billion = 10 digits + 1 for the sign if negative
-
- // buffer used to hold a formatted log message prior to actually logging it.
- const int LOG_MSG_SIZE = 2048;
- char log_msg[ LOG_MSG_SIZE ];
-
- // internal error that says that FormatMessage failed
- SQLCHAR INTERNAL_FORMAT_ERROR[] = "An internal error occurred. FormatMessage failed writing an error message.";
-
- // build the object and throw the PDO exception
- void pdo_sqlsrv_throw_exception( sqlsrv_error_const* error TSRMLS_DC );
-
- }
-
- // pdo driver error messages
- // errors have 3 components, the SQLSTATE (always 'IMSSP'), the error message, and an error code, which for us is always < 0
- pdo_error PDO_ERRORS[] = {
-
- {
- SQLSRV_ERROR_DRIVER_NOT_INSTALLED,
- { IMSSP, (SQLCHAR*) "This extension requires either the Microsoft SQL Server 2008 Native Client (SP1 or later) or the "
- "Microsoft SQL Server 2008 R2 Native Client ODBC Driver to communicate with SQL Server. Neither of those ODBC Drivers are currently installed. "
- "Access the following URL to download the Microsoft SQL Server 2008 R2 Native Client ODBC driver for %1!s!: "
- "http://go.microsoft.com/fwlink/?LinkId=163712", -1, true }
- },
- {
- SQLSRV_ERROR_ZEND_HASH,
- { IMSSP, (SQLCHAR*) "An error occurred creating or accessing a Zend hash table.", -2, false }
- },
- {
- PDO_SQLSRV_ERROR_INVALID_OUTPUT_PARAM_TYPE,
- { IMSSP, (SQLCHAR*) "An invalid PHP type was specified as an output parameter. DateTime objects, NULL values, and streams "
- "cannot be specified as output parameters.", -3, false }
- },
- {
- SQLSRV_ERROR_INVALID_PARAMETER_PHPTYPE,
- { IMSSP, (SQLCHAR*) "An invalid type for parameter %1!d! was specified. Only booleans, integers, floating point "
- "numbers, strings, and streams may be used as parameters.", -4, true }
- },
- {
- SQLSRV_ERROR_INVALID_PARAMETER_SQLTYPE,
- { IMSSP, (SQLCHAR*) "An invalid SQL Server type for parameter %1!d! was specified.", -5, true }
- },
- {
- SQLSRV_ERROR_INVALID_PARAMETER_ENCODING,
- { IMSSP, (SQLCHAR*) "An invalid encoding was specified for parameter %1!d!.", -6, true }
- },
- {
- SQLSRV_ERROR_INPUT_PARAM_ENCODING_TRANSLATE,
- { IMSSP, (SQLCHAR*) "An error occurred translating string for input param %1!d! to UCS-2: %2!s!", -7, true }
- },
- {
- SQLSRV_ERROR_OUTPUT_PARAM_ENCODING_TRANSLATE,
- { IMSSP, (SQLCHAR*) "An error occurred translating string for an output param to UTF-8: %1!s!", -8, true }
- },
- {
- SQLSRV_ERROR_CONNECT_STRING_ENCODING_TRANSLATE,
- { IMSSP, (SQLCHAR*) "An error occurred translating the connection string to UTF-16: %1!s!", -9, true }
- },
- {
- SQLSRV_ERROR_ZEND_STREAM,
- { IMSSP, (SQLCHAR*) "An error occurred reading from a PHP stream.", -10, false }
- },
- {
- SQLSRV_ERROR_INPUT_STREAM_ENCODING_TRANSLATE,
- { IMSSP, (SQLCHAR*) "An error occurred translating a PHP stream from UTF-8 to UTF-16: %1!s!", -11, true }
- },
- {
- SQLSRV_ERROR_UNKNOWN_SERVER_VERSION,
- { IMSSP, (SQLCHAR*) "Failed to retrieve the server version. Unable to continue.", -12, false }
- },
- {
- SQLSRV_ERROR_FETCH_PAST_END,
- { IMSSP, (SQLCHAR*) "There are no more rows in the active result set. Since this result set is not scrollable, "
- "no more data may be retrieved.", -13, false }
- },
- {
- SQLSRV_ERROR_STATEMENT_NOT_EXECUTED,
- { IMSSP, (SQLCHAR*) "The statement must be executed before results can be retrieved.", -14, false }
- },
- {
- SQLSRV_ERROR_NO_FIELDS,
- { IMSSP, (SQLCHAR*) "The active result for the query contains no fields.", -15, false }
- },
-
- {
- SQLSRV_ERROR_FETCH_NOT_CALLED,
- { IMSSP, (SQLCHAR*) "Internal pdo_sqlsrv error: Tried to retrieve a field before one of the PDOStatement::fetch "
- "functions was called.", -16, false }
- },
- {
- SQLSRV_ERROR_NO_DATA,
- { IMSSP, (SQLCHAR*)"Field %1!d! returned no data.", -17, true }
- },
- {
- SQLSRV_ERROR_FIELD_ENCODING_TRANSLATE,
- { IMSSP, (SQLCHAR*)"An error occurred translating string for a field to UTF-8: %1!s!", -18, true }
- },
- {
- SQLSRV_ERROR_ZEND_HASH_CREATE_FAILED,
- { IMSSP, (SQLCHAR*) "Zend returned an error when creating an associative array.", -19, false }
- },
- {
- SQLSRV_ERROR_NEXT_RESULT_PAST_END,
- { IMSSP, (SQLCHAR*)"There are no more results returned by the query.", -20, false }
- },
- {
- SQLSRV_ERROR_UID_PWD_BRACES_NOT_ESCAPED,
- { IMSSP, (SQLCHAR*) "An unescaped right brace (}) was found in either the user name or password. All right braces must be"
- " escaped with another right brace (}}).", -21, false }
- },
- {
- SQLSRV_ERROR_UNESCAPED_RIGHT_BRACE_IN_DSN,
- { IMSSP, (SQLCHAR*) "An unescaped right brace (}) was found in the DSN string for keyword '%1!s!'. All right braces "
- "must be escaped with another right brace (}}).", -22, true }
- },
- {
- SQLSRV_ERROR_INVALID_OPTION_TYPE_INT,
- { IMSSP, (SQLCHAR*) "Invalid value type for option %1!s! was specified. Integer type was expected.", -23, true }
- },
- {
- SQLSRV_ERROR_INVALID_OPTION_TYPE_STRING,
- { IMSSP, (SQLCHAR*) "Invalid value type for option %1!s! was specified. String type was expected.", -24, true }
- },
- {
- SQLSRV_ERROR_CONN_OPTS_WRONG_TYPE,
- { IMSSP, (SQLCHAR*) "Expected an array of options for the connection. Connection options must be passed as an array of "
- "key/value pairs.", -25, false }
- },
- {
- SQLSRV_ERROR_INVALID_CONNECTION_KEY,
- { IMSSP, (SQLCHAR*) "An invalid connection option key type was received. Option key types must be strings.", -26, false }
- },
-
- {
- SQLSRV_ERROR_INVALID_TYPE,
- { IMSSP, (SQLCHAR*) "Invalid type.", -27, false }
- },
-
- {
- PDO_SQLSRV_ERROR_INVALID_COLUMN_INDEX,
- {IMSSP, (SQLCHAR*)"An invalid column number was specified.", -28, false }
- },
-
- {
- SQLSRV_ERROR_MAX_PARAMS_EXCEEDED,
- { IMSSP, (SQLCHAR*) "Tried to bind parameter number %1!d!. SQL Server supports a maximum of 2100 parameters.", -29, true }
- },
- {
- SQLSRV_ERROR_INVALID_OPTION_KEY,
- { IMSSP, (SQLCHAR*) "Invalid option key %1!s! specified.", -30, true }
- },
- {
- SQLSRV_ERROR_INVALID_QUERY_TIMEOUT_VALUE,
- { IMSSP, (SQLCHAR*) "Invalid value %1!s! specified for option PDO::SQLSRV_ATTR_QUERY_TIMEOUT.", -31, true }
- },
- {
- SQLSRV_ERROR_INVALID_OPTION_SCROLLABLE,
- { IMSSP, (SQLCHAR*) "The value passed for the 'Scrollable' statement option is invalid.", -32, false }
- },
- {
- PDO_SQLSRV_ERROR_INVALID_DBH_ATTR,
- { IMSSP, (SQLCHAR*) "An invalid attribute was designated on the PDO object.", -33, false }
- },
- {
- PDO_SQLSRV_ERROR_INVALID_STMT_ATTR,
- { IMSSP, (SQLCHAR*) "An invalid attribute was designated on the PDOStatement object.", -34, false }
- },
- {
- PDO_SQLSRV_ERROR_INVALID_ENCODING,
- { IMSSP, (SQLCHAR*) "An invalid encoding was specified for SQLSRV_ATTR_ENCODING.", -35, false }
- },
- {
- PDO_SQLSRV_ERROR_INVALID_DRIVER_PARAM,
- { IMSSP, (SQLCHAR*) "An invalid type or value was given for the parameter driver data. Only encoding constants "
- "such as PDO::SQLSRV_ENCODING_UTF8 may be used as parameter driver options.", -36, false }
- },
- {
- PDO_SQLSRV_ERROR_PDO_STMT_UNSUPPORTED,
- { IMSSP, (SQLCHAR*) "PDO::PARAM_STMT is not a supported parameter type.", -37, false }
- },
- {
- PDO_SQLSRV_ERROR_UNSUPPORTED_DBH_ATTR,
- { IMSSP, (SQLCHAR*) "An unsupported attribute was designated on the PDO object.", -38, false }
- },
- {
- PDO_SQLSRV_ERROR_STMT_LEVEL_ATTR,
- { IMSSP, (SQLCHAR*) "The given attribute is only supported on the PDOStatement object.", -39, false }
- },
- {
- PDO_SQLSRV_ERROR_READ_ONLY_DBH_ATTR,
- { IMSSP, (SQLCHAR*) "A read-only attribute was designated on the PDO object.", -40, false }
- },
- {
- PDO_SQLSRV_ERROR_INVALID_DSN_STRING,
- {IMSSP, (SQLCHAR*)"An invalid DSN string was specified.", -41, false }
- },
- {
- PDO_SQLSRV_ERROR_INVALID_DSN_KEY,
- { IMSSP, (SQLCHAR*) "An invalid keyword '%1!s!' was specified in the DSN string.", -42, true }
- },
- {
- PDO_SQLSRV_ERROR_INVALID_STMT_OPTION,
- { IMSSP, (SQLCHAR*) "An invalid statement option was specified.", -43, false }
- },
- {
- PDO_SQLSRV_ERROR_INVALID_CURSOR_TYPE,
- { IMSSP, (SQLCHAR*) "An invalid cursor type was specified for either PDO::ATTR_CURSOR or "
- "PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE", -44, false }
- },
- {
- PDO_SQLSRV_ERROR_PARAM_PARSE,
- { IMSSP, (SQLCHAR*) "An error occurred substituting the named parameters.", -45, false }
- },
- {
- PDO_SQLSRV_ERROR_LAST_INSERT_ID,
- { IMSSP, (SQLCHAR*) "An error occurred retrieving the last insert id.", -46, false }
- },
- {
- SQLSRV_ERROR_QUERY_STRING_ENCODING_TRANSLATE,
- { IMSSP, (SQLCHAR*) "An error occurred translating the query string to UTF-16: %1!s!.", -47, true }
- },
- {
- PDO_SQLSRV_ERROR_INVALID_COLUMN_DRIVER_DATA,
- { IMSSP, (SQLCHAR*) "An invalid type or value was given as bound column driver data for column %1!d!. Only "
- "encoding constants such as PDO::SQLSRV_ENCODING_UTF8 may be used as bound column driver data.", -48, true }
- },
- {
- PDO_SQLSRV_ERROR_COLUMN_TYPE_DOES_NOT_SUPPORT_ENCODING,
- { IMSSP, (SQLCHAR*) "An encoding was specified for column %1!d!. Only PDO::PARAM_LOB and PDO::PARAM_STR column types "
- "can take an encoding option.", -49, true }
- },
- {
- PDO_SQLSRV_ERROR_INVALID_DRIVER_COLUMN_ENCODING,
- { IMSSP, (SQLCHAR*) "Invalid encoding specified for column %1!d!.", -50, true }
- },
- {
- PDO_SQLSRV_ERROR_INVALID_DRIVER_PARAM_TYPE,
- { IMSSP, (SQLCHAR*) "An encoding was specified for parameter %1!d!. Only PDO::PARAM_LOB and PDO::PARAM_STR can take an "
- "encoding option.", -51, true }
- },
- {
- PDO_SQLSRV_ERROR_INVALID_DRIVER_PARAM_ENCODING,
- { IMSSP, (SQLCHAR*) "Invalid encoding specified for parameter %1!d!.", -52, true }
- },
- {
- PDO_SQLSRV_ERROR_CURSOR_ATTR_AT_PREPARE_ONLY,
- { IMSSP, (SQLCHAR*) "The PDO::ATTR_CURSOR and PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE attributes may only be set in the "
- "$driver_options array of PDO::prepare.", -53, false }
- },
- {
- SQLSRV_ERROR_OUTPUT_PARAM_TRUNCATED,
- { IMSSP, (SQLCHAR*) "String data, right truncated for output parameter %1!d!.", -54, true }
- },
- {
- SQLSRV_ERROR_INPUT_OUTPUT_PARAM_TYPE_MATCH,
- { IMSSP, (SQLCHAR*) "Types for parameter value and PDO::PARAM_* constant must be compatible for input/output "
- "parameter %1!d!.", -55, true }
- },
- {
- PDO_SQLSRV_ERROR_INVALID_PARAM_DIRECTION,
- { IMSSP, (SQLCHAR*) "Invalid direction specified for parameter %1!d!. Input/output parameters must have a length.",
- -56, true }
- },
- {
- PDO_SQLSRV_ERROR_INVALID_OUTPUT_STRING_SIZE,
- { IMSSP, (SQLCHAR*) "Invalid size for output string parameter %1!d!. Input/output string parameters must have an "
- "explicit length.", -57, true }
- },
- {
- PDO_SQLSRV_ERROR_FUNCTION_NOT_IMPLEMENTED,
- { IMSSP, (SQLCHAR*) "This function is not implemented by this driver.", -58, false }
- },
- {
- /* The stream related errors are not currently used in PDO, but the core layer can throw the stream related
- errors so having a mapping here */
-
- SQLSRV_ERROR_STREAMABLE_TYPES_ONLY,
- { IMSSP, (SQLCHAR*) "Only char, nchar, varchar, nvarchar, binary, varbinary, and large object types can be read by using "
- "streams.", -59, false}
- },
- {
- SQLSRV_ERROR_STREAM_CREATE,
- { IMSSP, (SQLCHAR*)"An error occurred while retrieving a SQL Server field as a stream.", -60, false }
- },
- {
- SQLSRV_ERROR_MARS_OFF,
- { IMSSP, (SQLCHAR*)"The connection cannot process this operation because there is a statement with pending results. "
- "To make the connection available for other queries, either fetch all results or cancel or free the statement. "
- "For more information, see the product documentation about the MultipleActiveResultSets connection option.", -61, false }
- },
- {
- SQLSRV_ERROR_FIELD_INDEX_ERROR,
- { IMSSP, (SQLCHAR*)"Fields within a row must be accessed in ascending order. Cannot retrieve field %1!d! because its "
- "index is less than the index of a field that has already been retrieved (%2!d!).", -62, true }
- },
- {
- PDO_SQLSRV_ERROR_INVALID_DSN_VALUE,
- { IMSSP, (SQLCHAR*) "An invalid value was specified for the keyword '%1!s!' in the DSN string.", -63, true }
- },
- {
- PDO_SQLSRV_ERROR_SERVER_NOT_SPECIFIED,
- { IMSSP, (SQLCHAR*) "Server keyword was not specified in the DSN string.", -64, false }
- },
- {
- PDO_SQLSRV_ERROR_DSN_STRING_ENDED_UNEXPECTEDLY,
- { IMSSP, (SQLCHAR*) "The DSN string ended unexpectedly.", -65, false }
- },
- {
- PDO_SQLSRV_ERROR_EXTRA_SEMI_COLON_IN_DSN_STRING,
- { IMSSP, (SQLCHAR*) "An extra semi-colon was encountered in the DSN string at character (byte-count) position '%1!d!' .",
- -66, true }
- },
- {
- PDO_SQLSRV_ERROR_RCB_MISSING_IN_DSN_VALUE,
- { IMSSP, (SQLCHAR*) "An expected right brace (}) was not found in the DSN string for the value of the keyword '%1!s!'.",
- -67, true }
- },
- {
- PDO_SQLSRV_ERROR_DQ_ATTR_AT_PREPARE_ONLY,
- { IMSSP, (SQLCHAR*) "The PDO::SQLSRV_ATTR_DIRECT_QUERY attribute may only be set in the $driver_options array of "
- "PDO::prepare.", -68, false }
- },
- {
- PDO_SQLSRV_ERROR_INVALID_CURSOR_WITH_SCROLL_TYPE,
- { IMSSP, (SQLCHAR*) "The PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE attribute may only be set when PDO::ATTR_CURSOR is set to "
- "PDO::CURSOR_SCROLL in the $driver_options array of PDO::prepare.", -69, false }
- },
- {
- SQLSRV_ERROR_INVALID_BUFFER_LIMIT,
- { IMSSP, (SQLCHAR*) "The PDO::SQLSRV_ATTR_CLIENT_BUFFER_MAX_KB_SIZE attribute is not a number or the number is not "
- "positive. Only positive numbers are valid for this attribute.", -70, false }
- },
- {
- SQLSRV_ERROR_BUFFER_LIMIT_EXCEEDED,
- { IMSSP, (SQLCHAR*) "Memory limit of %1!d! KB exceeded for buffered query", -71, true }
- },
-
- { -1, {} }
- };
-
- // Returns a sqlsrv_error for a given error code.
- sqlsrv_error_const* get_error_message( unsigned int sqlsrv_error_code ) {
-
- sqlsrv_error_const *error_message = NULL;
- int zr = zend_hash_index_find( g_pdo_errors_ht, sqlsrv_error_code, reinterpret_cast<void**>( &error_message ));
- if( zr == FAILURE ) {
- DIE( "get_error_message: zend_hash_index_find returned failure for sqlsrv_error_code = %1!d!", sqlsrv_error_code );
- }
-
- SQLSRV_ASSERT( error_message != NULL, "get_error_message: error_message was null");
-
- return error_message;
- }
-
- // PDO error handler for the environment context.
- bool pdo_sqlsrv_handle_env_error( sqlsrv_context& ctx, unsigned int sqlsrv_error_code, bool warning TSRMLS_DC,
- va_list* print_args )
- {
- SQLSRV_ASSERT(( ctx != NULL ), "pdo_sqlsrv_handle_env_error: sqlsrv_context was null" );
- pdo_dbh_t* dbh = reinterpret_cast<pdo_dbh_t*>( ctx.driver());
- SQLSRV_ASSERT(( dbh != NULL ), "pdo_sqlsrv_handle_env_error: pdo_dbh_t was null" );
-
- sqlsrv_error_auto_ptr error;
-
- if( sqlsrv_error_code != SQLSRV_ERROR_ODBC ) {
-
- core_sqlsrv_format_driver_error( ctx, get_error_message( sqlsrv_error_code ), error, SEV_ERROR TSRMLS_CC, print_args );
- }
- else {
-
- bool err = core_sqlsrv_get_odbc_error( ctx, 1, error, SEV_ERROR TSRMLS_CC );
- SQLSRV_ASSERT( err == true, "No ODBC error was found" );
- }
-
- strcpy_s( dbh->error_code, sizeof( pdo_error_type ), reinterpret_cast<const char*>( error->sqlstate ));
-
- switch( dbh->error_mode ) {
-
- case PDO_ERRMODE_EXCEPTION:
- if( !warning ) {
-
- pdo_sqlsrv_throw_exception( error TSRMLS_CC );
- }
- ctx.set_last_error( error );
- break;
-
- default:
- DIE( "pdo_sqlsrv_handle_env_error: Unexpected error mode. %1!d!", dbh->error_mode );
- break;
- }
-
- // we don't transfer the zval_auto_ptr since set_last_error increments the zval ref count
- // return error ignored = true for warnings.
- return ( warning ? true : false );
-
- }
-
- // pdo error handler for the dbh context.
- bool pdo_sqlsrv_handle_dbh_error( sqlsrv_context& ctx, unsigned int sqlsrv_error_code, bool warning TSRMLS_DC,
- va_list* print_args )
- {
- pdo_dbh_t* dbh = reinterpret_cast<pdo_dbh_t*>( ctx.driver());
- SQLSRV_ASSERT( dbh != NULL, "pdo_sqlsrv_handle_dbh_error: Null dbh passed" );
-
- sqlsrv_error_auto_ptr error;
-
- if( sqlsrv_error_code != SQLSRV_ERROR_ODBC ) {
-
- core_sqlsrv_format_driver_error( ctx, get_error_message( sqlsrv_error_code ), error, SEV_ERROR TSRMLS_CC, print_args );
- }
- else {
- bool err = core_sqlsrv_get_odbc_error( ctx, 1, error, SEV_ERROR TSRMLS_CC );
- SQLSRV_ASSERT( err == true, "No ODBC error was found" );
- }
-
- SQLSRV_STATIC_ASSERT( sizeof( error->sqlstate ) <= sizeof( dbh->error_code ));
- strcpy_s( dbh->error_code, sizeof( dbh->error_code ), reinterpret_cast<const char*>( error->sqlstate ));
-
- switch( dbh->error_mode ) {
- case PDO_ERRMODE_EXCEPTION:
- if( !warning ) {
-
- pdo_sqlsrv_throw_exception( error TSRMLS_CC );
- }
- ctx.set_last_error( error );
- break;
- case PDO_ERRMODE_WARNING:
- if( !warning ) {
- unsigned int msg_len = strlen( reinterpret_cast<const char*>( error->native_message )) + SQL_SQLSTATE_BUFSIZE
- + MAX_DIGITS + 1;
- sqlsrv_malloc_auto_ptr<char> msg;
- msg = static_cast<char*>( sqlsrv_malloc( msg_len ));
- core_sqlsrv_format_message( msg, msg_len, WARNING_TEMPLATE, error->sqlstate, error->native_code,
- error->native_message );
- php_error( E_WARNING, msg );
- sqlsrv_free( msg );
- }
- ctx.set_last_error( error );
- break;
- case PDO_ERRMODE_SILENT:
- ctx.set_last_error( error );
- break;
- default:
- DIE( "Unknown error mode. %1!d!", dbh->error_mode );
- break;
- }
-
- // return error ignored = true for warnings.
- return ( warning ? true : false );
- }
-
- // PDO error handler for the statement context.
- bool pdo_sqlsrv_handle_stmt_error( sqlsrv_context& ctx, unsigned int sqlsrv_error_code, bool warning TSRMLS_DC,
- va_list* print_args )
- {
- pdo_stmt_t* pdo_stmt = reinterpret_cast<pdo_stmt_t*>( ctx.driver());
- SQLSRV_ASSERT( pdo_stmt != NULL && pdo_stmt->dbh != NULL, "pdo_sqlsrv_handle_stmt_error: Null statement or dbh passed" );
-
- sqlsrv_error_auto_ptr error;
-
- if( sqlsrv_error_code != SQLSRV_ERROR_ODBC ) {
- core_sqlsrv_format_driver_error( ctx, get_error_message( sqlsrv_error_code ), error, SEV_ERROR TSRMLS_CC, print_args );
- }
- else {
- bool err = core_sqlsrv_get_odbc_error( ctx, 1, error, SEV_ERROR TSRMLS_CC );
- SQLSRV_ASSERT( err == true, "No ODBC error was found" );
- }
-
- SQLSRV_STATIC_ASSERT( sizeof( error->sqlstate ) <= sizeof( pdo_stmt->error_code ));
- strcpy_s( pdo_stmt->error_code, sizeof( pdo_stmt->error_code ), reinterpret_cast<const char*>( error->sqlstate ));
-
- switch( pdo_stmt->dbh->error_mode ) {
- case PDO_ERRMODE_EXCEPTION:
- if( !warning ) {
-
- pdo_sqlsrv_throw_exception( error TSRMLS_CC );
- }
- ctx.set_last_error( error );
- break;
- case PDO_ERRMODE_WARNING:
- if( !warning ) {
- unsigned int msg_len = strlen( reinterpret_cast<const char*>( error->native_message )) + SQL_SQLSTATE_BUFSIZE
- + MAX_DIGITS + 1;
- sqlsrv_malloc_auto_ptr<char> msg;
- msg = static_cast<char*>( sqlsrv_malloc( msg_len ));
- core_sqlsrv_format_message( msg, msg_len, WARNING_TEMPLATE, error->sqlstate, error->native_code,
- error->native_message );
- php_error( E_WARNING, msg );
- sqlsrv_free( msg );
- }
- ctx.set_last_error( error );
- break;
- case PDO_ERRMODE_SILENT:
- ctx.set_last_error( error );
- break;
- default:
- DIE( "Unknown error mode. %1!d!", pdo_stmt->dbh->error_mode );
- break;
- }
-
- // return error ignored = true for warnings.
- return ( warning ? true : false );
- }
-
-
- // Transfer a sqlsrv_context's error to a PDO zval. The standard format for a zval error is 3 elements:
- // 0, native code
- // 1, native message
- // 2, SQLSTATE of the error (driver specific error messages are 'IMSSP')
-
- void pdo_sqlsrv_retrieve_context_error( sqlsrv_error const* last_error, zval* pdo_zval )
- {
- if( last_error ) {
-
- // SQLSTATE is already present in the zval.
- add_next_index_long( pdo_zval, last_error->native_code );
- add_next_index_string( pdo_zval, reinterpret_cast<char*>( last_error->native_message ), 1 /*dup*/ );
- }
- else {
- add_next_index_null( pdo_zval ); /* native code */
- add_next_index_null( pdo_zval ); /* native message */
- }
-
- }
-
- // Formats the error message and writes to the php error log.
- void pdo_sqlsrv_log( unsigned int severity TSRMLS_DC, const char* msg, va_list* print_args )
- {
- if( (severity & PDO_SQLSRV_G( log_severity )) == 0 ) {
- return;
- }
-
- DWORD rc = FormatMessage( FORMAT_MESSAGE_FROM_STRING, msg, 0, 0, log_msg, LOG_MSG_SIZE, print_args );
- // if an error occurs for FormatMessage, we just output an internal error occurred.
- if( rc == 0 ) {
- SQLSRV_STATIC_ASSERT( sizeof( INTERNAL_FORMAT_ERROR ) < sizeof( log_msg ));
- std::copy( INTERNAL_FORMAT_ERROR, INTERNAL_FORMAT_ERROR + sizeof( INTERNAL_FORMAT_ERROR ), log_msg );
- }
-
- php_log_err( log_msg TSRMLS_CC );
- }
-
- namespace {
-
- void pdo_sqlsrv_throw_exception( sqlsrv_error_const* error TSRMLS_DC )
- {
- zval_auto_ptr ex_obj;
- MAKE_STD_ZVAL( ex_obj );
- zend_class_entry* ex_class = pdo_get_exception_class();
-
- int zr = object_init_ex( ex_obj, ex_class );
- SQLSRV_ASSERT( zr != FAILURE, "Failed to initialize exception object" );
-
- sqlsrv_malloc_auto_ptr<char> ex_msg;
- size_t ex_msg_len = strlen( reinterpret_cast<const char*>( error->native_message )) + SQL_SQLSTATE_BUFSIZE +
- 12 + 1; // 12 = "SQLSTATE[]: "
- ex_msg = reinterpret_cast<char*>( sqlsrv_malloc( ex_msg_len ));
- snprintf( ex_msg, ex_msg_len, EXCEPTION_MSG_TEMPLATE, error->sqlstate, error->native_message );
- zend_update_property_string( ex_class, ex_obj, EXCEPTION_PROPERTY_MSG, sizeof( EXCEPTION_PROPERTY_MSG ) - 1,
- ex_msg TSRMLS_CC );
- zend_update_property_string( ex_class, ex_obj, EXCEPTION_PROPERTY_CODE, sizeof( EXCEPTION_PROPERTY_CODE ) - 1,
- reinterpret_cast<char*>( error->sqlstate ) TSRMLS_CC );
-
- zval_auto_ptr ex_error_info;
- MAKE_STD_ZVAL( ex_error_info );
- array_init( ex_error_info );
- add_next_index_string( ex_error_info, reinterpret_cast<char*>( error->sqlstate ), 1 /* dup */ );
- add_next_index_long( ex_error_info, error->native_code );
- add_next_index_string( ex_error_info, reinterpret_cast<char*>( error->native_message ), 1 /* dup */ );
- zend_update_property( ex_class, ex_obj, EXCEPTION_PROPERTY_ERRORINFO, sizeof( EXCEPTION_PROPERTY_ERRORINFO ) - 1,
- ex_error_info TSRMLS_CC );
-
- zend_throw_exception_object( ex_obj TSRMLS_CC );
- ex_msg.transferred();
- ex_obj.transferred();
- }
-
- }