diff --git a/source/pdo_sqlsrv/pdo_dbh.cpp b/source/pdo_sqlsrv/pdo_dbh.cpp index 77ea5ba7..c1c63a22 100644 --- a/source/pdo_sqlsrv/pdo_dbh.cpp +++ b/source/pdo_sqlsrv/pdo_dbh.cpp @@ -19,13 +19,9 @@ #include "php_pdo_sqlsrv.h" -#include -#include -#include #include #include - typedef const zend_function_entry pdo_sqlsrv_function_entry; // *** internal variables and constants *** @@ -73,7 +69,7 @@ enum PDO_STMT_OPTIONS { PDO_STMT_OPTION_CURSOR_SCROLL_TYPE, PDO_STMT_OPTION_CLIENT_BUFFER_MAX_KB_SIZE, PDO_STMT_OPTION_EMULATE_PREPARES, - PDO_STMT_OPTION_FETCHES_NUMERIC_TYPE, + PDO_STMT_OPTION_FETCHES_NUMERIC_TYPE, }; // List of all the statement options supported by this driver. @@ -86,9 +82,9 @@ const stmt_option PDO_STMT_OPTS[] = { { NULL, 0, PDO_STMT_OPTION_CURSOR_SCROLL_TYPE, std::unique_ptr( new stmt_option_cursor_scroll_type ) }, { NULL, 0, PDO_STMT_OPTION_CLIENT_BUFFER_MAX_KB_SIZE, std::unique_ptr( new stmt_option_buffered_query_limit ) }, { NULL, 0, PDO_STMT_OPTION_EMULATE_PREPARES, std::unique_ptr( new stmt_option_emulate_prepares ) }, - { NULL, 0, PDO_STMT_OPTION_FETCHES_NUMERIC_TYPE, std::unique_ptr( new stmt_option_fetch_numeric ) }, + { NULL, 0, PDO_STMT_OPTION_FETCHES_NUMERIC_TYPE, std::unique_ptr( new stmt_option_fetch_numeric ) }, - { NULL, 0, SQLSRV_STMT_OPTION_INVALID, std::unique_ptr{} }, + { NULL, 0, SQLSRV_STMT_OPTION_INVALID, std::unique_ptr{} }, }; // boolean connection string @@ -350,27 +346,40 @@ struct pdo_dbh_methods pdo_sqlsrv_dbh_methods = { NULL, // check liveness not implemented pdo_sqlsrv_get_driver_methods, NULL, // request shutdown not implemented - NULL // in transaction not implemented + NULL // in transaction not implemented }; // log a function entry point +#ifndef _WIN32 +#define PDO_LOG_DBH_ENTRY \ +{ \ + pdo_sqlsrv_dbh* driver_dbh = reinterpret_cast( dbh->driver_data ); \ + driver_dbh->set_func( __FUNCTION__ ); \ + int length = strlen( __FUNCTION__ ) + strlen( ": entering" ); \ + char func[length+1]; \ + strcpy_s( func, sizeof( __FUNCTION__ ), __FUNCTION__ ); \ + strcat_s( func, length+1, ": entering" ); \ + LOG( SEV_NOTICE, func ); \ +} +#else #define PDO_LOG_DBH_ENTRY \ { \ pdo_sqlsrv_dbh* driver_dbh = reinterpret_cast( dbh->driver_data ); \ driver_dbh->set_func( __FUNCTION__ ); \ LOG( SEV_NOTICE, __FUNCTION__ ## ": entering" ); \ } +#endif // constructor for the internal object for connections pdo_sqlsrv_dbh::pdo_sqlsrv_dbh( SQLHANDLE h, error_callback e, void* driver TSRMLS_DC ) : - sqlsrv_conn( h, e, driver, SQLSRV_ENCODING_UTF8 TSRMLS_CC ), - stmts( NULL ), - direct_query( false ), - query_timeout( QUERY_TIMEOUT_INVALID ), - client_buffer_max_size( PDO_SQLSRV_G( client_buffer_max_size )), - bind_param_encoding( SQLSRV_ENCODING_CHAR ), - fetch_numeric( false ) + sqlsrv_conn( h, e, driver, SQLSRV_ENCODING_UTF8 TSRMLS_CC ), + stmts( NULL ), + direct_query( false ), + query_timeout( QUERY_TIMEOUT_INVALID ), + client_buffer_max_size( PDO_SQLSRV_G( client_buffer_max_size )), + bind_param_encoding( SQLSRV_ENCODING_CHAR ), + fetch_numeric( false ) { if( client_buffer_max_size < 0 ) { client_buffer_max_size = sqlsrv_buffered_result_set::BUFFERED_QUERY_LIMIT_DEFAULT; @@ -408,7 +417,7 @@ int pdo_sqlsrv_db_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC) zval* temp_server_z = NULL; sqlsrv_malloc_auto_ptr dsn_parser; zval server_z; - ZVAL_UNDEF( &server_z ); + ZVAL_UNDEF( &server_z ); try { @@ -452,8 +461,8 @@ int pdo_sqlsrv_db_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC) dbh->username, dbh->password, pdo_conn_options_ht, pdo_sqlsrv_handle_dbh_error, PDO_CONN_OPTS, dbh, "pdo_sqlsrv_db_handle_factory" TSRMLS_CC ); - // Free the string in server_z after being used - zend_string_release( Z_STR( server_z )); + // Free the string in server_z after being used + zend_string_release( Z_STR( server_z )); SQLSRV_ASSERT( conn != NULL, "Invalid connection returned. Exception should have been thrown." ); @@ -465,11 +474,13 @@ int pdo_sqlsrv_db_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC) } catch( core::CoreException& ) { - if ( Z_TYPE( server_z ) == IS_STRING ) { - zend_string_release( Z_STR( server_z )); - } + + if ( Z_TYPE( server_z ) == IS_STRING ) { + zend_string_release( Z_STR( server_z )); + } dbh->error_mode = prev_err_mode; // reset the error mode - g_henv_cp->last_error().reset(); // reset the last error; callee will check if last_error exist before freeing it and setting it to NULL + g_henv_cp->last_error().reset(); // reset the last error; callee will check if last_error exist before freeing it and setting it to NULL + return 0; } catch( ... ) { @@ -574,12 +585,13 @@ int pdo_sqlsrv_dbh_prepare( pdo_dbh_t *dbh, const char *sql, // rewrite the query to map named parameters to positional parameters. We do this rather than use the ODBC named // parameters for consistency with the PDO MySQL and PDO ODBC drivers. - int zr = pdo_subst_named_params( stmt, const_cast( sql ), sql_len, &sql_rewrite, &sql_rewrite_len TSRMLS_CC ); - CHECK_ZEND_ERROR( zr, driver_dbh, PDO_SQLSRV_ERROR_PARAM_PARSE ) { + int zr = pdo_parse_params( stmt, const_cast( sql ), sql_len, &sql_rewrite, &sql_rewrite_len TSRMLS_CC ); + + CHECK_ZEND_ERROR( zr, driver_dbh, PDO_SQLSRV_ERROR_PARAM_PARSE) { throw core::CoreException(); } // if parameter substitution happened, use that query instead of the original - if( sql_rewrite != NULL ) { + if( sql_rewrite != 0) { sql = sql_rewrite; sql_len = sql_rewrite_len; } @@ -910,16 +922,16 @@ int pdo_sqlsrv_dbh_set_attr( pdo_dbh_t *dbh, zend_long attr, zval *val TSRMLS_DC driver_dbh->client_buffer_max_size = Z_LVAL_P( val ); break; - case SQLSRV_ATTR_FETCHES_NUMERIC_TYPE: - driver_dbh->fetch_numeric = (zend_is_true(val)) ? true : false; - break; + case SQLSRV_ATTR_FETCHES_NUMERIC_TYPE: + driver_dbh->fetch_numeric = (zend_is_true(val)) ? true : false; + break; // Not supported case PDO_ATTR_FETCH_TABLE_NAMES: case PDO_ATTR_FETCH_CATALOG_NAMES: case PDO_ATTR_PREFETCH: case PDO_ATTR_MAX_COLUMN_LEN: - case PDO_ATTR_CURSOR_NAME: + case PDO_ATTR_CURSOR_NAME: case PDO_ATTR_AUTOCOMMIT: case PDO_ATTR_PERSISTENT: case PDO_ATTR_TIMEOUT: @@ -929,10 +941,10 @@ int pdo_sqlsrv_dbh_set_attr( pdo_dbh_t *dbh, zend_long attr, zval *val TSRMLS_DC // Read-only case PDO_ATTR_SERVER_VERSION: - case PDO_ATTR_SERVER_INFO: + case PDO_ATTR_SERVER_INFO: case PDO_ATTR_CLIENT_VERSION: case PDO_ATTR_DRIVER_NAME: - case PDO_ATTR_CONNECTION_STATUS: + case PDO_ATTR_CONNECTION_STATUS: { THROW_PDO_ERROR( driver_dbh, PDO_SQLSRV_ERROR_READ_ONLY_DBH_ATTR ); } @@ -940,7 +952,7 @@ int pdo_sqlsrv_dbh_set_attr( pdo_dbh_t *dbh, zend_long attr, zval *val TSRMLS_DC // Statement level only case PDO_ATTR_EMULATE_PREPARES: case PDO_ATTR_CURSOR: - case SQLSRV_ATTR_CURSOR_SCROLL_TYPE: + case SQLSRV_ATTR_CURSOR_SCROLL_TYPE: { THROW_PDO_ERROR( driver_dbh, PDO_SQLSRV_ERROR_STMT_LEVEL_ATTR ); } @@ -997,7 +1009,7 @@ int pdo_sqlsrv_dbh_get_attr( pdo_dbh_t *dbh, zend_long attr, zval *return_value // Statement level only case PDO_ATTR_EMULATE_PREPARES: case PDO_ATTR_CURSOR: - case SQLSRV_ATTR_CURSOR_SCROLL_TYPE: + case SQLSRV_ATTR_CURSOR_SCROLL_TYPE: { THROW_PDO_ERROR( driver_dbh, PDO_SQLSRV_ERROR_STMT_LEVEL_ATTR ); } @@ -1025,8 +1037,11 @@ int pdo_sqlsrv_dbh_get_attr( pdo_dbh_t *dbh, zend_long attr, zval *return_value { core_sqlsrv_get_client_info( driver_dbh, return_value TSRMLS_CC ); - //Add the PDO SQLSRV driver's file version - core::sqlsrv_add_assoc_string( *driver_dbh, return_value, "ExtensionVer", VER_FILEVERSION_STR, 1 /*duplicate*/ + //Add the PDO SQLSRV driver's file version + //Declarations below eliminate compiler warnings about string constant to char* conversions + const char* extver = "ExtensionVer"; + std::string filever = VER_FILEVERSION_STR; + core::sqlsrv_add_assoc_string( *driver_dbh, return_value, extver, &filever[0], 1 /*duplicate*/ TSRMLS_CC ); break; } @@ -1055,11 +1070,11 @@ int pdo_sqlsrv_dbh_get_attr( pdo_dbh_t *dbh, zend_long attr, zval *return_value break; } - case SQLSRV_ATTR_FETCHES_NUMERIC_TYPE: - { - ZVAL_BOOL( return_value, driver_dbh->fetch_numeric ); - break; - } + case SQLSRV_ATTR_FETCHES_NUMERIC_TYPE: + { + ZVAL_BOOL( return_value, driver_dbh->fetch_numeric ); + break; + } default: { @@ -1095,8 +1110,8 @@ int pdo_sqlsrv_dbh_return_error( pdo_dbh_t *dbh, pdo_stmt_t *stmt, else { ctx_error = static_cast( dbh->driver_data )->last_error(); } - - pdo_sqlsrv_retrieve_context_error( ctx_error, info ); + + pdo_sqlsrv_retrieve_context_error( ctx_error, info ); return 1; } @@ -1135,10 +1150,10 @@ char * pdo_sqlsrv_dbh_last_id( pdo_dbh_t *dbh, const char *name, _Out_ size_t* l } else { char* quoted_table = NULL; - size_t quoted_len = 0; + size_t quoted_len = 0; int quoted = pdo_sqlsrv_dbh_quote( dbh, name, strlen( name ), "ed_table, "ed_len, PDO_PARAM_NULL TSRMLS_CC ); - SQLSRV_ASSERT( quoted, "PDO::lastInsertId failed to quote the table name." ); - sprintf_s( last_insert_id_query, LAST_INSERT_ID_QUERY_MAX_LEN, TABLE_LAST_INSERT_ID_QUERY, quoted_table ); + SQLSRV_ASSERT( quoted, "PDO::lastInsertId failed to quote the table name."); + snprintf( last_insert_id_query, LAST_INSERT_ID_QUERY_MAX_LEN, TABLE_LAST_INSERT_ID_QUERY, quoted_table ); sqlsrv_free( quoted_table ); } @@ -1158,7 +1173,7 @@ char * pdo_sqlsrv_dbh_last_id( pdo_dbh_t *dbh, const char *name, _Out_ size_t* l SQLRETURN r = core::SQLGetData( driver_stmt, 1, SQL_C_CHAR, id_str, LAST_INSERT_ID_BUFF_LEN, reinterpret_cast( len ), false TSRMLS_CC ); - CHECK_CUSTOM_ERROR( (!SQL_SUCCEEDED( r ) || *len == SQL_NULL_DATA || *len == SQL_NO_TOTAL), driver_stmt, + CHECK_CUSTOM_ERROR( (!SQL_SUCCEEDED( r ) || *len == SQL_NULL_DATA || *len == SQL_NO_TOTAL), driver_stmt, PDO_SQLSRV_ERROR_LAST_INSERT_ID ) { throw core::CoreException(); } @@ -1204,81 +1219,79 @@ char * pdo_sqlsrv_dbh_last_id( pdo_dbh_t *dbh, const char *name, _Out_ size_t* l int pdo_sqlsrv_dbh_quote( pdo_dbh_t* dbh, const char* unquoted, size_t unquoted_len, char **quoted, size_t* quoted_len, enum pdo_param_type /*paramtype*/ TSRMLS_DC ) { - PDO_RESET_DBH_ERROR; - PDO_VALIDATE_CONN; + PDO_RESET_DBH_ERROR; + PDO_VALIDATE_CONN; PDO_LOG_DBH_ENTRY; - pdo_sqlsrv_dbh* driver_dbh = reinterpret_cast( dbh->driver_data ); - SQLSRV_ENCODING encoding = driver_dbh->bind_param_encoding; + pdo_sqlsrv_dbh* driver_dbh = reinterpret_cast( dbh->driver_data ); + SQLSRV_ENCODING encoding = driver_dbh->bind_param_encoding; - if ( encoding == SQLSRV_ENCODING_BINARY ) { - // convert from char* to hex digits using os - std::basic_ostringstream os; - for ( size_t index = 0; index < unquoted_len && unquoted[index] != '\0'; ++index ) { - os << std::hex << ( int )unquoted[index]; - } - std::basic_string str_hex = os.str(); - // each character is represented by 2 digits of hex - size_t unquoted_str_len = unquoted_len * 2; // length returned should not account for null terminator - char* unquoted_str = reinterpret_cast( sqlsrv_malloc( unquoted_str_len, sizeof( char ), 1 )); // include space for null terminator - strcpy_s( unquoted_str, unquoted_str_len + 1 /* include null terminator*/, str_hex.c_str()); - // include length of '0x' in the binary string - *quoted_len = unquoted_str_len + 2; - *quoted = reinterpret_cast( sqlsrv_malloc( *quoted_len, sizeof( char ), 1 )); - unsigned int out_current = 0; - // insert '0x' - ( *quoted )[out_current++] = '0'; - ( *quoted )[out_current++] = 'x'; - for ( size_t index = 0; index < unquoted_str_len && unquoted_str[index] != '\0'; ++index ) { - ( *quoted )[out_current++] = unquoted_str[index]; - } - // null terminator - ( *quoted )[out_current] = '\0'; - sqlsrv_free( unquoted_str ); - return 1; - } - else { - // count the number of quotes needed - unsigned int quotes_needed = 2; // the initial start and end quotes of course - // include the N proceeding the initial quote if encoding is UTF8 - if ( encoding == SQLSRV_ENCODING_UTF8 ) { - quotes_needed = 3; - } + if ( encoding == SQLSRV_ENCODING_BINARY ) { + // convert from char* to hex digits using os + std::basic_ostringstream os; + for ( size_t index = 0; index < unquoted_len && unquoted[ index ] != '\0'; ++index ) { + os << std::hex << ( int )unquoted[ index ]; + } + std::basic_string str_hex = os.str(); + // each character is represented by 2 digits of hex + size_t unquoted_str_len = unquoted_len * 2; // length returned should not account for null terminator + char* unquoted_str = reinterpret_cast( sqlsrv_malloc( unquoted_str_len, sizeof( char ), 1 )); // include space for null terminator + strcpy_s( unquoted_str, unquoted_str_len + 1 /* include null terminator*/, str_hex.c_str() ); + // include length of '0x' in the binary string + *quoted_len = unquoted_str_len + 2; + *quoted = reinterpret_cast( sqlsrv_malloc( *quoted_len, sizeof( char ), 1 )); + unsigned int out_current = 0; + // insert '0x' + ( *quoted )[ out_current++ ] = '0'; + ( *quoted )[ out_current++ ] = 'x'; + for ( size_t index = 0; index < unquoted_str_len && unquoted_str[ index ] != '\0'; ++index ) { + ( *quoted )[ out_current++ ] = unquoted_str[ index ]; + } + // null terminator + ( *quoted )[ out_current ] = '\0'; + sqlsrv_free( unquoted_str ); + return 1; + } + else { + // count the number of quotes needed + unsigned int quotes_needed = 2; // the initial start and end quotes of course + // include the N proceeding the initial quote if encoding is UTF8 + if ( encoding == SQLSRV_ENCODING_UTF8 ) { + quotes_needed = 3; + } + for ( size_t index = 0; index < unquoted_len && unquoted[ index ] != '\0'; ++index ) { + if ( unquoted[ index ] == '\'' ) { + ++quotes_needed; + } + } - for ( size_t index = 0; index < unquoted_len && unquoted[index] != '\0'; ++index ) { - if ( unquoted[index] == '\'' ) { - ++quotes_needed; - } - } + *quoted_len = unquoted_len + quotes_needed; // length returned to the caller should not account for null terminator. + *quoted = reinterpret_cast( sqlsrv_malloc( *quoted_len, sizeof( char ), 1 )); // include space for null terminator. + unsigned int out_current = 0; - *quoted_len = unquoted_len + quotes_needed; // length returned to the caller should not account for null terminator. - *quoted = reinterpret_cast( sqlsrv_malloc( *quoted_len, sizeof( char ), 1 )); // include space for null terminator. - unsigned int out_current = 0; + // insert N if the encoding is UTF8 + if ( encoding == SQLSRV_ENCODING_UTF8 ) { + ( *quoted )[ out_current++ ] = 'N'; + } + // insert initial quote + ( *quoted )[ out_current++ ] = '\''; - // insert N if the encoding is UTF8 - if ( encoding == SQLSRV_ENCODING_UTF8 ) { - ( *quoted )[out_current++] = 'N'; - } - // insert initial quote - ( *quoted )[out_current++] = '\''; + for ( size_t index = 0; index < unquoted_len && unquoted[ index ] != '\0'; ++index ) { + if ( unquoted[ index ] == '\'' ) { + ( *quoted )[ out_current++ ] = '\''; + ( *quoted )[ out_current++ ] = '\''; + } + else { + ( *quoted )[ out_current++ ] = unquoted[ index ]; + } + } - for ( size_t index = 0; index < unquoted_len && unquoted[index] != '\0'; ++index ) { + // trailing quote and null terminator + ( *quoted )[ out_current++ ] = '\''; + ( *quoted )[ out_current ] = '\0'; - if ( unquoted[index] == '\'' ) { - ( *quoted )[out_current++] = '\''; - ( *quoted )[out_current++] = '\''; - } - else { - ( *quoted )[out_current++] = unquoted[index]; - } - } - - // trailing quote and null terminator - ( *quoted )[out_current++] = '\''; - ( *quoted )[out_current] = '\0'; - - return 1; - } + return 1; + } } // This method is not implemented by this driver. @@ -1293,7 +1306,7 @@ pdo_sqlsrv_function_entry *pdo_sqlsrv_get_driver_methods( pdo_dbh_t *dbh, int ki return NULL; } - return NULL; // to avoid a compiler warning + return NULL; // to avoid a compiler warning } namespace { @@ -1337,8 +1350,9 @@ void add_stmt_option_key( sqlsrv_context& ctx, size_t key, HashTable* options_ht option_key = PDO_STMT_OPTION_EMULATE_PREPARES; break; - case SQLSRV_ATTR_FETCHES_NUMERIC_TYPE: - option_key = PDO_STMT_OPTION_FETCHES_NUMERIC_TYPE; + case SQLSRV_ATTR_FETCHES_NUMERIC_TYPE: + option_key = PDO_STMT_OPTION_FETCHES_NUMERIC_TYPE; + break; default: CHECK_CUSTOM_ERROR( true, ctx, PDO_SQLSRV_ERROR_INVALID_STMT_OPTION ) { @@ -1370,20 +1384,20 @@ void validate_stmt_options( sqlsrv_context& ctx, zval* stmt_options, _Inout_ Has if( stmt_options ) { HashTable* options_ht = Z_ARRVAL_P( stmt_options ); - size_t int_key = -1; - zend_string *key = NULL; - zval* data = NULL; + size_t int_key = -1; + zend_string *key = NULL; + zval* data = NULL; - ZEND_HASH_FOREACH_KEY_VAL( options_ht, int_key, key, data ) { - int type = HASH_KEY_NON_EXISTENT; - int result = 0; - type = key ? HASH_KEY_IS_STRING : HASH_KEY_IS_LONG; - CHECK_CUSTOM_ERROR(( type != HASH_KEY_IS_LONG ), ctx, PDO_SQLSRV_ERROR_INVALID_STMT_OPTION ) { - throw core::CoreException(); - } + ZEND_HASH_FOREACH_KEY_VAL( options_ht, int_key, key, data ) { + int type = HASH_KEY_NON_EXISTENT; + int result = 0; + type = key ? HASH_KEY_IS_STRING : HASH_KEY_IS_LONG; + CHECK_CUSTOM_ERROR(( type != HASH_KEY_IS_LONG ), ctx, PDO_SQLSRV_ERROR_INVALID_STMT_OPTION ) { + throw core::CoreException(); + } - add_stmt_option_key( ctx, int_key, pdo_stmt_options_ht, data TSRMLS_CC ); - } ZEND_HASH_FOREACH_END(); + add_stmt_option_key( ctx, int_key, pdo_stmt_options_ht, data TSRMLS_CC ); + } ZEND_HASH_FOREACH_END(); } } catch( core::CoreException& ) { @@ -1421,35 +1435,35 @@ void pdo_txn_isolation_conn_attr_func::func( connection_option const* /*option*/ // READ_COMMITTED if(( val_len == ( sizeof( PDOTxnIsolationValues::READ_COMMITTED ) - 1 ) - && !_stricmp( val, PDOTxnIsolationValues::READ_COMMITTED ))) { + && !strcasecmp( val, PDOTxnIsolationValues::READ_COMMITTED ))) { out_val = SQL_TXN_READ_COMMITTED; } // READ_UNCOMMITTED else if(( val_len == ( sizeof( PDOTxnIsolationValues::READ_UNCOMMITTED ) - 1 ) - && !_stricmp( val, PDOTxnIsolationValues::READ_UNCOMMITTED ))) { + && !strcasecmp( val, PDOTxnIsolationValues::READ_UNCOMMITTED ))) { out_val = SQL_TXN_READ_UNCOMMITTED; } // REPEATABLE_READ else if(( val_len == ( sizeof( PDOTxnIsolationValues::REPEATABLE_READ ) - 1 ) - && !_stricmp( val, PDOTxnIsolationValues::REPEATABLE_READ ))) { + && !strcasecmp( val, PDOTxnIsolationValues::REPEATABLE_READ ))) { out_val = SQL_TXN_REPEATABLE_READ; } // SERIALIZABLE else if(( val_len == ( sizeof( PDOTxnIsolationValues::SERIALIZABLE ) - 1 ) - && !_stricmp( val, PDOTxnIsolationValues::SERIALIZABLE ))) { + && !strcasecmp( val, PDOTxnIsolationValues::SERIALIZABLE ))) { out_val = SQL_TXN_SERIALIZABLE; } // SNAPSHOT else if(( val_len == ( sizeof( PDOTxnIsolationValues::SNAPSHOT ) - 1 ) - && !_stricmp( val, PDOTxnIsolationValues::SNAPSHOT ))) { + && !strcasecmp( val, PDOTxnIsolationValues::SNAPSHOT ))) { out_val = SQL_TXN_SS_SNAPSHOT; } diff --git a/source/pdo_sqlsrv/pdo_init.cpp b/source/pdo_sqlsrv/pdo_init.cpp index f3fca1b8..b20388ed 100644 --- a/source/pdo_sqlsrv/pdo_init.cpp +++ b/source/pdo_sqlsrv/pdo_init.cpp @@ -18,7 +18,6 @@ //--------------------------------------------------------------------------------------------------------------------------------- #include "php_pdo_sqlsrv.h" -#include #ifdef ZTS ZEND_TSRMLS_CACHE_DEFINE(); @@ -46,45 +45,11 @@ pdo_driver_t pdo_sqlsrv_driver = { pdo_sqlsrv_db_handle_factory }; -const char PDO_DLL_NAME[] = "php_pdo.dll"; - -// PHP_DEBUG is always defined as either 0 or 1 -#if PHP_DEBUG == 1 && !defined(ZTS) - -const char PHP_DLL_NAME[] = "php7_debug.dll"; - -#elif PHP_DEBUG == 1 && defined(ZTS) - -const char PHP_DLL_NAME[] = "php7ts_debug.dll"; - -#elif PHP_DEBUG == 0 && !defined(ZTS) - -const char PHP_DLL_NAME[] = "php7.dll"; - -#elif PHP_DEBUG == 0 && defined(ZTS) - -const char PHP_DLL_NAME[] = "php7ts.dll"; - -#else - -#error Invalid combination of PHP_DEBUG and ZTS macros - -#endif - -typedef PDO_API int (*pdo_register_func)(pdo_driver_t *); - -// function pointers to register and unregister this driver -pdo_register_func pdo_register_driver; -pdo_register_func pdo_unregister_driver; - // functions to register SQLSRV constants with the PDO class // (It's in all CAPS so it looks like the Zend macros that do similar work) void REGISTER_PDO_SQLSRV_CLASS_CONST_LONG( char const* name, long value TSRMLS_DC ); void REGISTER_PDO_SQLSRV_CLASS_CONST_STRING( char const* name, char const* value TSRMLS_DC ); -// return the Zend class entry for the PDO dbh (connection) class -zend_class_entry* (*pdo_get_dbh_class)( void ); - struct sqlsrv_attr_pdo_constant { const char *name; int value; @@ -96,8 +61,8 @@ extern sqlsrv_attr_pdo_constant pdo_attr_constants[]; } static zend_module_dep pdo_sqlsrv_depends[] = { - ZEND_MOD_REQUIRED("pdo") - {NULL, NULL, NULL} + ZEND_MOD_REQUIRED("pdo") + {NULL, NULL, NULL} }; @@ -116,7 +81,7 @@ zend_module_entry g_pdo_sqlsrv_module_entry = { STANDARD_MODULE_HEADER_EX, NULL, - pdo_sqlsrv_depends, + pdo_sqlsrv_depends, "pdo_sqlsrv", pdo_sqlsrv_functions, // exported function table // initialization and shutdown functions @@ -134,15 +99,10 @@ zend_module_entry g_pdo_sqlsrv_module_entry = STANDARD_MODULE_PROPERTIES_EX }; -// functions dynamically linked from the PDO (or PHP) dll and called by other parts of the driver -zend_class_entry* (*pdo_get_exception_class)( void ); -int (*pdo_subst_named_params)(pdo_stmt_t *stmt, char *inquery, size_t inquery_len, - char **outquery, size_t *outquery_len TSRMLS_DC); - // called by Zend for each parameter in the g_pdo_errors_ht hash table when it is destroyed -void pdo_error_dtor(zval* elem) { - pdo_error* error_to_ignore = reinterpret_cast(Z_PTR_P(elem)); - pefree(error_to_ignore, 1); +void pdo_error_dtor( zval* elem ) { + pdo_error* error_to_ignore = reinterpret_cast( Z_PTR_P( elem ) ); + pefree( error_to_ignore, 1 ); } // Module initialization @@ -155,9 +115,9 @@ PHP_MINIT_FUNCTION(pdo_sqlsrv) // our global variables are initialized in the RINIT function #if defined(ZTS) if( ts_allocate_id( &pdo_sqlsrv_globals_id, - sizeof( zend_pdo_sqlsrv_globals ), - (ts_allocate_ctor) NULL, - (ts_allocate_dtor) NULL ) == 0 ) + sizeof( zend_pdo_sqlsrv_globals ), + (ts_allocate_ctor) NULL, + (ts_allocate_dtor) NULL ) == 0 ) return FAILURE; ZEND_TSRMLS_CACHE_UPDATE(); #endif @@ -168,62 +128,6 @@ PHP_MINIT_FUNCTION(pdo_sqlsrv) LOG( SEV_NOTICE, "pdo_sqlsrv: entering minit" ); - // PHP extensions may be either external DLLs loaded by PHP or statically compiled into the PHP dll - // This becomes an issue when we are dependent on other extensions, e.g. PDO. Normally this is solved - // by the build process by linking our extension to the appropriate import library (either php*.dll or php_pdo.dll) - // However, this leaves us with a problem that the extension has a dependency on that build type. - // Since we don't distribute our extension with PHP directly (yet), it would mean that we would have to have SKUs - // for both types of PDO builds, internal and external. Rather than this, we just dynamically link the PDO routines we call - // against either the PDO dll if it exists and is loaded, otherwise against the PHP dll directly. - - DWORD needed = 0; - HANDLE hprocess = GetCurrentProcess(); - HMODULE pdo_hmodule; - - pdo_hmodule = GetModuleHandle( PDO_DLL_NAME ); - if( pdo_hmodule == 0 ) { - - pdo_hmodule = GetModuleHandle( PHP_DLL_NAME ); - if( pdo_hmodule == NULL ) { - LOG( SEV_ERROR, "Failed to get PHP module handle." ); - return FAILURE; - } - } - - pdo_register_driver = reinterpret_cast( GetProcAddress( pdo_hmodule, "php_pdo_register_driver" )); - if( pdo_register_driver == NULL ) { - LOG( SEV_ERROR, "Failed to register driver." ); - return FAILURE; - } - - pdo_unregister_driver = reinterpret_cast( GetProcAddress( pdo_hmodule, "php_pdo_unregister_driver" )); - if( pdo_unregister_driver == NULL ) { - LOG( SEV_ERROR, "Failed to register driver." ); - return FAILURE; - } - - pdo_get_exception_class = reinterpret_cast( GetProcAddress( pdo_hmodule, - "php_pdo_get_exception" )); - if( pdo_get_exception_class == NULL ) { - LOG( SEV_ERROR, "Failed to register driver." ); - return FAILURE; - } - - pdo_get_dbh_class = reinterpret_cast( GetProcAddress( pdo_hmodule, "php_pdo_get_dbh_ce" )); - if( pdo_get_dbh_class == NULL ) { - LOG( SEV_ERROR, "Failed to register driver." ); - return FAILURE; - } - - pdo_subst_named_params = - reinterpret_cast( - GetProcAddress( pdo_hmodule, "pdo_parse_params" )); - if( pdo_subst_named_params == NULL ) { - LOG( SEV_ERROR, "Failed to register driver." ); - return FAILURE; - } - // initialize list of pdo errors g_pdo_errors_ht = reinterpret_cast( pemalloc( sizeof( HashTable ), 1 )); ::zend_hash_init( g_pdo_errors_ht, 50, NULL, pdo_error_dtor /*pDestructor*/, 1 ); @@ -263,13 +167,11 @@ PHP_MINIT_FUNCTION(pdo_sqlsrv) return FAILURE; } - pdo_register_driver( &pdo_sqlsrv_driver ); + php_pdo_register_driver( &pdo_sqlsrv_driver ); return SUCCESS; } -// Module shutdown function - // Module shutdown function // This function is called once per execution of the Zend engine @@ -281,7 +183,7 @@ PHP_MSHUTDOWN_FUNCTION(pdo_sqlsrv) UNREGISTER_INI_ENTRIES(); - pdo_unregister_driver( &pdo_sqlsrv_driver ); + php_pdo_unregister_driver( &pdo_sqlsrv_driver ); // clean up the list of pdo errors zend_hash_destroy( g_pdo_errors_ht ); @@ -352,8 +254,9 @@ namespace { void REGISTER_PDO_SQLSRV_CLASS_CONST_LONG( char const* name, long value TSRMLS_DC ) { - zend_class_entry* zend_class = pdo_get_dbh_class(); - SQLSRV_ASSERT( zend_class != NULL, "REGISTER_PDO_SQLSRV_CLASS_CONST_LONG: pdo_get_dbh_class failed" ); + zend_class_entry* zend_class = php_pdo_get_dbh_ce(); + + SQLSRV_ASSERT( zend_class != NULL, "REGISTER_PDO_SQLSRV_CLASS_CONST_LONG: php_pdo_get_dbh_ce failed"); int zr = zend_declare_class_constant_long( zend_class, const_cast( name ), strlen( name ), value TSRMLS_CC ); if( zr == FAILURE ) { throw core::CoreException(); @@ -362,8 +265,9 @@ namespace { void REGISTER_PDO_SQLSRV_CLASS_CONST_STRING( char const* name, char const* value TSRMLS_DC ) { - zend_class_entry* zend_class = pdo_get_dbh_class(); - SQLSRV_ASSERT( zend_class != NULL, "REGISTER_PDO_SQLSRV_CLASS_CONST_STRING: pdo_get_dbh_class failed" ); + zend_class_entry* zend_class = php_pdo_get_dbh_ce(); + + SQLSRV_ASSERT( zend_class != NULL, "REGISTER_PDO_SQLSRV_CLASS_CONST_STRING: php_pdo_get_dbh_ce failed"); int zr = zend_declare_class_constant_string( zend_class, const_cast( name ), strlen( name ), const_cast( value ) TSRMLS_CC ); if( zr == FAILURE ) { @@ -372,15 +276,15 @@ namespace { } // array of pdo constants. - sqlsrv_attr_pdo_constant pdo_attr_constants[] = { + sqlsrv_attr_pdo_constant pdo_attr_constants[] = { - // driver specific attributes - { "SQLSRV_ATTR_ENCODING" , SQLSRV_ATTR_ENCODING }, - { "SQLSRV_ATTR_QUERY_TIMEOUT" , SQLSRV_ATTR_QUERY_TIMEOUT }, - { "SQLSRV_ATTR_DIRECT_QUERY" , SQLSRV_ATTR_DIRECT_QUERY }, - { "SQLSRV_ATTR_CURSOR_SCROLL_TYPE" , SQLSRV_ATTR_CURSOR_SCROLL_TYPE }, - { "SQLSRV_ATTR_CLIENT_BUFFER_MAX_KB_SIZE", SQLSRV_ATTR_CLIENT_BUFFER_MAX_KB_SIZE }, - { "SQLSRV_ATTR_FETCHES_NUMERIC_TYPE", SQLSRV_ATTR_FETCHES_NUMERIC_TYPE }, + // driver specific attributes + { "SQLSRV_ATTR_ENCODING" , SQLSRV_ATTR_ENCODING }, + { "SQLSRV_ATTR_QUERY_TIMEOUT" , SQLSRV_ATTR_QUERY_TIMEOUT }, + { "SQLSRV_ATTR_DIRECT_QUERY" , SQLSRV_ATTR_DIRECT_QUERY }, + { "SQLSRV_ATTR_CURSOR_SCROLL_TYPE" , SQLSRV_ATTR_CURSOR_SCROLL_TYPE }, + { "SQLSRV_ATTR_CLIENT_BUFFER_MAX_KB_SIZE", SQLSRV_ATTR_CLIENT_BUFFER_MAX_KB_SIZE }, + { "SQLSRV_ATTR_FETCHES_NUMERIC_TYPE", SQLSRV_ATTR_FETCHES_NUMERIC_TYPE }, // used for the size for output parameters: PDO::PARAM_INT and PDO::PARAM_BOOL use the default size of int, // PDO::PARAM_STR uses the size of the string in the variable diff --git a/source/pdo_sqlsrv/pdo_parser.cpp b/source/pdo_sqlsrv/pdo_parser.cpp index 6e735b56..74c1a222 100644 --- a/source/pdo_sqlsrv/pdo_parser.cpp +++ b/source/pdo_sqlsrv/pdo_parser.cpp @@ -29,6 +29,8 @@ conn_string_parser:: conn_string_parser( sqlsrv_context& ctx, const char* dsn, i this->conn_options_ht = conn_options_ht; this->pos = -1; this->ctx = &ctx; + this->current_key = 0; + this->current_key_name = NULL; } // Move to the next character @@ -131,7 +133,7 @@ void conn_string_parser::validate_key(const char *key, int key_len TSRMLS_DC ) for( int i=0; PDO_CONN_OPTS[ i ].conn_option_key != SQLSRV_CONN_OPTION_INVALID; ++i ) { // discard the null terminator. - if( new_len == ( PDO_CONN_OPTS[ i ].sqlsrv_len - 1 ) && !_strnicmp( key, PDO_CONN_OPTS[ i ].sqlsrv_name, new_len )) { + if( new_len == ( PDO_CONN_OPTS[ i ].sqlsrv_len - 1 ) && !strncasecmp( key, PDO_CONN_OPTS[ i ].sqlsrv_name, new_len )) { this->current_key = PDO_CONN_OPTS[ i ].conn_option_key; this->current_key_name = PDO_CONN_OPTS[ i ].sqlsrv_name; @@ -143,9 +145,10 @@ void conn_string_parser::validate_key(const char *key, int key_len TSRMLS_DC ) sqlsrv_malloc_auto_ptr key_name; key_name = static_cast( sqlsrv_malloc( new_len + 1 )); memcpy_s( key_name, new_len + 1 ,key, new_len ); + key_name[ new_len ] = '\0'; - THROW_PDO_ERROR( this->ctx, PDO_SQLSRV_ERROR_INVALID_DSN_KEY, key_name ); + THROW_PDO_ERROR( this->ctx, PDO_SQLSRV_ERROR_INVALID_DSN_KEY, static_cast( key_name ) ); } // Primary function which parses the connection string/DSN. diff --git a/source/pdo_sqlsrv/pdo_stmt.cpp b/source/pdo_sqlsrv/pdo_stmt.cpp index 95c3e861..e25388d1 100644 --- a/source/pdo_sqlsrv/pdo_stmt.cpp +++ b/source/pdo_sqlsrv/pdo_stmt.cpp @@ -39,9 +39,11 @@ const int SQL_SERVER_IDENT_SIZE_MAX = 128; inline SQLSMALLINT pdo_fetch_ori_to_odbc_fetch_ori (enum pdo_fetch_orientation ori) { - SQLSRV_ASSERT( ori >= PDO_FETCH_ORI_NEXT && ori <= PDO_FETCH_ORI_REL, "Fetch orientation out of range." ); + SQLSRV_ASSERT( ori >= PDO_FETCH_ORI_NEXT && ori <= PDO_FETCH_ORI_REL, "Fetch orientation out of range."); +#ifdef _WIN32 OACR_WARNING_SUPPRESS( 26001, "Buffer length verified above" ); OACR_WARNING_SUPPRESS( 26000, "Buffer length verified above" ); +#endif return odbc_fetch_orientation[ori]; } @@ -202,9 +204,9 @@ void set_stmt_encoding( sqlsrv_stmt* stmt, zval* value_z TSRMLS_DC ) // internal helper function to free meta data structures allocated void meta_data_free( field_meta_data* meta ) { - if( meta->field_name ) { - meta->field_name.reset(); - } + if( meta->field_name ) { + meta->field_name.reset(); + } sqlsrv_free( meta ); } @@ -332,18 +334,31 @@ void stmt_option_emulate_prepares:: operator()( sqlsrv_stmt* stmt, stmt_option c void stmt_option_fetch_numeric:: operator()( sqlsrv_stmt* stmt, stmt_option const* /*opt*/, zval* value_z TSRMLS_DC ) { - pdo_sqlsrv_stmt *pdo_stmt = static_cast( stmt ); - pdo_stmt->fetch_numeric = ( zend_is_true( value_z )) ? true : false; + pdo_sqlsrv_stmt *pdo_stmt = static_cast( stmt ); + pdo_stmt->fetch_numeric = ( zend_is_true( value_z )) ? true : false; } // log a function entry point +#ifndef _WIN32 +#define PDO_LOG_STMT_ENTRY \ +{ \ + pdo_sqlsrv_stmt* driver_stmt = reinterpret_cast( stmt->driver_data ); \ + driver_stmt->set_func( __FUNCTION__ ); \ + int length = strlen( __FUNCTION__ ) + strlen( ": entering" ); \ + char func[length+1]; \ + strcpy_s( func, sizeof( __FUNCTION__ ), __FUNCTION__ ); \ + strcat_s( func, length+1, ": entering" ); \ + LOG( SEV_NOTICE, func ); \ +} +#else #define PDO_LOG_STMT_ENTRY \ { \ pdo_sqlsrv_stmt* driver_stmt = reinterpret_cast( stmt->driver_data ); \ driver_stmt->set_func( __FUNCTION__ ); \ LOG( SEV_NOTICE, __FUNCTION__ ## ": entering" ); \ } +#endif // PDO SQLSRV statement destructor pdo_sqlsrv_stmt::~pdo_sqlsrv_stmt( void ) @@ -440,7 +455,7 @@ int pdo_sqlsrv_stmt_describe_col(pdo_stmt_t *stmt, int colno TSRMLS_DC) // Set the name column_data->name = zend_string_init( (const char*)core_meta_data->field_name.get(), core_meta_data->field_name_len, 0 ); - core_meta_data->field_name.reset(); + core_meta_data->field_name.reset(); // Set the maxlen column_data->maxlen = ( core_meta_data->field_precision > 0 ) ? core_meta_data->field_precision : core_meta_data->field_size; @@ -698,9 +713,6 @@ int pdo_sqlsrv_stmt_get_col_data(pdo_stmt_t *stmt, int colno, // Let PDO free the memory after use. *caller_frees = 1; - - // set the metadata for the current column - pdo_column_data* column_data = &(stmt->columns[colno]); // translate the pdo type to a type the core layer understands sqlsrv_phptype sqlsrv_php_type; @@ -756,7 +768,7 @@ int pdo_sqlsrv_stmt_get_col_data(pdo_stmt_t *stmt, int colno, core_sqlsrv_get_field( driver_stmt, colno, sqlsrv_php_type, false, *(reinterpret_cast(ptr)), reinterpret_cast( len ), true, &sqlsrv_phptype_out TSRMLS_CC ); - zval* zval_ptr = ( zval* )( sqlsrv_malloc( sizeof( zval ))); + zval* zval_ptr = reinterpret_cast( sqlsrv_malloc( sizeof( zval ))); *zval_ptr = convert_to_zval( sqlsrv_phptype_out, reinterpret_cast( ptr ), *len ); *ptr = reinterpret_cast( zval_ptr ); @@ -787,7 +799,7 @@ int pdo_sqlsrv_stmt_set_attr(pdo_stmt_t *stmt, zend_long attr, zval *val TSRMLS_ PDO_VALIDATE_STMT; PDO_LOG_STMT_ENTRY; - pdo_sqlsrv_stmt* driver_stmt = static_cast( stmt->driver_data ); + pdo_sqlsrv_stmt* driver_stmt = static_cast( stmt->driver_data ); try { @@ -896,11 +908,11 @@ int pdo_sqlsrv_stmt_get_attr( pdo_stmt_t *stmt, zend_long attr, zval *return_val break; } - case SQLSRV_ATTR_FETCHES_NUMERIC_TYPE: - { - ZVAL_BOOL( return_value, driver_stmt->fetch_numeric ); - break; - } + case SQLSRV_ATTR_FETCHES_NUMERIC_TYPE: + { + ZVAL_BOOL( return_value, driver_stmt->fetch_numeric ); + break; + } default: THROW_PDO_ERROR( driver_stmt, PDO_SQLSRV_ERROR_INVALID_STMT_ATTR ); @@ -966,7 +978,12 @@ int pdo_sqlsrv_stmt_get_col_meta(pdo_stmt_t *stmt, zend_long colno, zval *return long pdo_type = sql_type_to_pdo_type( core_meta_data->field_type ); switch( pdo_type ) { case PDO_PARAM_STR: - add_assoc_string( return_value, "native_type", "string" ); + { + //Declarations eliminate compiler warnings about string constant to char* conversions + std::string key = "native_type"; + std::string str = "string"; + add_assoc_string( return_value, &key[0], &str[0] ); + } break; default: DIE( "pdo_sqlsrv_stmt_get_col_data: Unknown PDO type returned" ); @@ -1076,11 +1093,11 @@ int pdo_sqlsrv_stmt_param_hook(pdo_stmt_t *stmt, // since the param isn't reliable, we don't do anything here case PDO_PARAM_EVT_ALLOC: - // if emulate prepare is on, set the bind_param_encoding so it can be used in PDO::quote when binding parameters on the client side - if ( stmt->supports_placeholders == PDO_PLACEHOLDER_NONE ) { - pdo_sqlsrv_dbh* driver_dbh = reinterpret_cast( stmt->dbh->driver_data ); - driver_dbh->bind_param_encoding = static_cast( Z_LVAL( param->driver_params )); - } + // if emulate prepare is on, set the bind_param_encoding so it can be used in PDO::quote when binding parameters on the client side + if ( stmt->supports_placeholders == PDO_PLACEHOLDER_NONE ) { + pdo_sqlsrv_dbh* driver_dbh = reinterpret_cast( stmt->dbh->driver_data ); + driver_dbh->bind_param_encoding = static_cast( Z_LVAL( param->driver_params )); + } break; case PDO_PARAM_EVT_FREE: break; @@ -1239,7 +1256,7 @@ int pdo_sqlsrv_stmt_param_hook(pdo_stmt_t *stmt, if( !param->is_param ) { break; } - + core_sqlsrv_post_param( reinterpret_cast( stmt->driver_data ), param->paramno, &(param->parameter) TSRMLS_CC ); } @@ -1281,28 +1298,28 @@ sqlsrv_phptype pdo_sqlsrv_stmt::sql_type_to_php_type( SQLINTEGER sql_type, SQLUI } switch( sql_type ) { - case SQL_BIT: - case SQL_INTEGER: - case SQL_SMALLINT: - case SQL_TINYINT: - if ( this->fetch_numeric ) { - sqlsrv_phptype.typeinfo.type = SQLSRV_PHPTYPE_INT; - } - else { - sqlsrv_phptype.typeinfo.type = SQLSRV_PHPTYPE_STRING; - sqlsrv_phptype.typeinfo.encoding = local_encoding; - } - break; - case SQL_FLOAT: - case SQL_REAL: - if ( this->fetch_numeric ) { - sqlsrv_phptype.typeinfo.type = SQLSRV_PHPTYPE_FLOAT; - } - else { - sqlsrv_phptype.typeinfo.type = SQLSRV_PHPTYPE_STRING; - sqlsrv_phptype.typeinfo.encoding = local_encoding; - } - break; + case SQL_BIT: + case SQL_INTEGER: + case SQL_SMALLINT: + case SQL_TINYINT: + if ( this->fetch_numeric ) { + sqlsrv_phptype.typeinfo.type = SQLSRV_PHPTYPE_INT; + } + else { + sqlsrv_phptype.typeinfo.type = SQLSRV_PHPTYPE_STRING; + sqlsrv_phptype.typeinfo.encoding = local_encoding; + } + break; + case SQL_FLOAT: + case SQL_REAL: + if ( this->fetch_numeric ) { + sqlsrv_phptype.typeinfo.type = SQLSRV_PHPTYPE_FLOAT; + } + else { + sqlsrv_phptype.typeinfo.type = SQLSRV_PHPTYPE_STRING; + sqlsrv_phptype.typeinfo.encoding = local_encoding; + } + break; case SQL_BIGINT: case SQL_CHAR: case SQL_DECIMAL: diff --git a/source/pdo_sqlsrv/pdo_util.cpp b/source/pdo_sqlsrv/pdo_util.cpp index fd36a9c2..c3f0fb36 100644 --- a/source/pdo_sqlsrv/pdo_util.cpp +++ b/source/pdo_sqlsrv/pdo_util.cpp @@ -53,8 +53,8 @@ pdo_error PDO_ERRORS[] = { { SQLSRV_ERROR_DRIVER_NOT_INSTALLED, - { IMSSP, (SQLCHAR*) "This extension requires the Microsoft ODBC Driver 11 or 13 for SQL Server to " - "communicate with SQL Server. Access the following URL to download the ODBC Driver 11 or 13 for SQL Server " + { IMSSP, (SQLCHAR*) "This extension requires the Microsoft ODBC Driver 13 for SQL Server to " + "communicate with SQL Server. Access the following URL to download the ODBC Driver 13 for SQL Server " "for %1!s!: " "http://go.microsoft.com/fwlink/?LinkId=163712", -1, true } }, @@ -376,8 +376,8 @@ pdo_error PDO_ERRORS[] = { // 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 = (error_message = reinterpret_cast(zend_hash_index_find_ptr(g_pdo_errors_ht, sqlsrv_error_code))) != NULL ? SUCCESS : FAILURE; + sqlsrv_error_const *error_message = NULL; + int zr = (error_message = reinterpret_cast(zend_hash_index_find_ptr(g_pdo_errors_ht, sqlsrv_error_code))) != NULL ? SUCCESS : FAILURE; if( zr == FAILURE ) { DIE( "get_error_message: zend_hash_index_find returned failure for sqlsrv_error_code = %1!d!", sqlsrv_error_code ); } @@ -448,8 +448,8 @@ bool pdo_sqlsrv_handle_dbh_error( sqlsrv_context& ctx, unsigned int sqlsrv_error SQLSRV_ASSERT( err == true, "No ODBC error was found" ); } - SQLSRV_ASSERT(strlen(reinterpret_cast(error->sqlstate)) <= sizeof(dbh->error_code), "Error code overflow"); - strcpy_s(dbh->error_code, sizeof(dbh->error_code), reinterpret_cast(error->sqlstate)); + SQLSRV_ASSERT(strlen(reinterpret_cast(error->sqlstate)) <= sizeof(dbh->error_code), "Error code overflow"); + strcpy_s(dbh->error_code, sizeof(dbh->error_code), reinterpret_cast(error->sqlstate)); switch( dbh->error_mode ) { case PDO_ERRMODE_EXCEPTION: @@ -463,9 +463,9 @@ bool pdo_sqlsrv_handle_dbh_error( sqlsrv_context& ctx, unsigned int sqlsrv_error if( !warning ) { size_t msg_len = strlen( reinterpret_cast( error->native_message )) + SQL_SQLSTATE_BUFSIZE + MAX_DIGITS + WARNING_MIN_LENGTH + 1; - sqlsrv_malloc_auto_ptr msg; - msg = static_cast( sqlsrv_malloc( msg_len ) ); - core_sqlsrv_format_message( msg, static_cast( msg_len ), WARNING_TEMPLATE, error->sqlstate, error->native_code, + sqlsrv_malloc_auto_ptr msg; + msg = static_cast( sqlsrv_malloc( msg_len ) ); + core_sqlsrv_format_message( msg, static_cast( msg_len ), WARNING_TEMPLATE, error->sqlstate, error->native_code, error->native_message ); php_error( E_WARNING, msg ); } @@ -535,7 +535,6 @@ bool pdo_sqlsrv_handle_stmt_error( sqlsrv_context& ctx, unsigned int sqlsrv_erro 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( last_error->native_message )); @@ -550,6 +549,7 @@ void pdo_sqlsrv_log( unsigned int severity TSRMLS_DC, const char* msg, va_list* } 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 )); @@ -565,7 +565,8 @@ void pdo_sqlsrv_throw_exception( sqlsrv_error_const* error TSRMLS_DC ) { zval ex_obj; ZVAL_UNDEF( &ex_obj ); - zend_class_entry* ex_class = pdo_get_exception_class(); + + zend_class_entry* ex_class = php_pdo_get_exception(); int zr = object_init_ex( &ex_obj, ex_class ); SQLSRV_ASSERT( zr != FAILURE, "Failed to initialize exception object" ); @@ -586,15 +587,15 @@ void pdo_sqlsrv_throw_exception( sqlsrv_error_const* error TSRMLS_DC ) add_next_index_string( &ex_error_info, reinterpret_cast( error->sqlstate )); add_next_index_long( &ex_error_info, error->native_code ); add_next_index_string( &ex_error_info, reinterpret_cast( error->native_message )); - //zend_update_property makes an entry in the properties_table in ex_obj point to the Z_ARRVAL( ex_error_info ) - //and the refcount of the zend_array is incremented by 1 + //zend_update_property makes an entry in the properties_table in ex_obj point to the Z_ARRVAL( ex_error_info ) + //and the refcount of the zend_array is incremented by 1 zend_update_property( ex_class, &ex_obj, EXCEPTION_PROPERTY_ERRORINFO, sizeof( EXCEPTION_PROPERTY_ERRORINFO ) - 1, &ex_error_info TSRMLS_CC ); - //DELREF ex_error_info here to decrement the refcount of the zend_array is 1 - //the global hashtable EG(exception) then points to the zend_object in ex_obj in zend_throw_exception_object; - //this ensure when EG(exception) cleans itself at php shutdown, the zend_array allocated is properly destroyed - Z_DELREF( ex_error_info ); + //DELREF ex_error_info here to decrement the refcount of the zend_array is 1 + //the global hashtable EG(exception) then points to the zend_object in ex_obj in zend_throw_exception_object; + //this ensure when EG(exception) cleans itself at php shutdown, the zend_array allocated is properly destroyed + Z_DELREF( ex_error_info ); zend_throw_exception_object( &ex_obj TSRMLS_CC ); } diff --git a/source/pdo_sqlsrv/php_pdo_sqlsrv.h b/source/pdo_sqlsrv/php_pdo_sqlsrv.h index f158d933..348bf7d2 100644 --- a/source/pdo_sqlsrv/php_pdo_sqlsrv.h +++ b/source/pdo_sqlsrv/php_pdo_sqlsrv.h @@ -27,7 +27,6 @@ extern "C" { #include "pdo/php_pdo.h" #include "pdo/php_pdo_driver.h" -#include "pdo/php_pdo_int.h" } @@ -48,7 +47,7 @@ enum PDO_SQLSRV_ATTR { SQLSRV_ATTR_DIRECT_QUERY, SQLSRV_ATTR_CURSOR_SCROLL_TYPE, SQLSRV_ATTR_CLIENT_BUFFER_MAX_KB_SIZE, - SQLSRV_ATTR_FETCHES_NUMERIC_TYPE, + SQLSRV_ATTR_FETCHES_NUMERIC_TYPE, }; // valid set of values for TransactionIsolation connection option @@ -111,6 +110,8 @@ extern sqlsrv_context* g_henv_ncp; // module global variables (initialized in minit and freed in mshutdown) extern HashTable* g_pdo_errors_ht; +#define phpext_pdo_sqlsrv_ptr &g_pdo_sqlsrv_module_entry + // module initialization PHP_MINIT_FUNCTION(pdo_sqlsrv); // module shutdown function @@ -155,7 +156,7 @@ class conn_string_parser inline bool is_white_space( char c ); bool discard_white_spaces( void ); int discard_trailing_white_spaces( const char* str, int len ); - void conn_string_parser::validate_key( const char *key, int key_len TSRMLS_DC ); + void validate_key( const char *key, int key_len TSRMLS_DC ); void add_key_value_pair( const char* value, int len TSRMLS_DC ); public: @@ -177,8 +178,8 @@ struct pdo_sqlsrv_dbh : public sqlsrv_conn { bool direct_query; long query_timeout; zend_long client_buffer_max_size; - SQLSRV_ENCODING bind_param_encoding; - bool fetch_numeric; + SQLSRV_ENCODING bind_param_encoding; + bool fetch_numeric; pdo_sqlsrv_dbh( SQLHANDLE h, error_callback e, void* driver TSRMLS_DC ); }; @@ -214,7 +215,7 @@ struct stmt_option_emulate_prepares : public stmt_option_functor { }; struct stmt_option_fetch_numeric : public stmt_option_functor { - virtual void operator()( sqlsrv_stmt* stmt, stmt_option const* /*opt*/, zval* value_z TSRMLS_DC ); + virtual void operator()( sqlsrv_stmt* stmt, stmt_option const* /*opt*/, zval* value_z TSRMLS_DC ); }; extern struct pdo_stmt_methods pdo_sqlsrv_stmt_methods; @@ -228,11 +229,11 @@ struct pdo_sqlsrv_stmt : public sqlsrv_stmt { direct_query_subst_string( NULL ), direct_query_subst_string_len( 0 ), bound_column_param_types( NULL ), - fetch_numeric( false ) + fetch_numeric( false ) { pdo_sqlsrv_dbh* db = static_cast( c ); direct_query = db->direct_query; - fetch_numeric = db->fetch_numeric; + fetch_numeric = db->fetch_numeric; } virtual ~pdo_sqlsrv_stmt( void ); @@ -248,7 +249,7 @@ struct pdo_sqlsrv_stmt : public sqlsrv_stmt { // meta data for current result set std::vector > current_meta_data; pdo_param_type* bound_column_param_types; - bool fetch_numeric; + bool fetch_numeric; }; @@ -273,9 +274,6 @@ bool pdo_sqlsrv_handle_dbh_error( sqlsrv_context& ctx, unsigned int sqlsrv_error bool pdo_sqlsrv_handle_stmt_error( sqlsrv_context& ctx, unsigned int sqlsrv_error_code, bool warning TSRMLS_DC, va_list* print_args ); -// pointer to the function to return the class entry for the PDO exception Set in MINIT -extern zend_class_entry* (*pdo_get_exception_class)( void ); - // common routine to transfer a sqlsrv_context's error to a PDO zval void pdo_sqlsrv_retrieve_context_error( sqlsrv_error const* last_error, zval* pdo_zval ); @@ -375,7 +373,7 @@ enum PDO_ERROR_CODES { extern pdo_error PDO_ERRORS[]; #define THROW_PDO_ERROR( ctx, custom, ... ) \ - call_error_handler( ctx, custom TSRMLS_CC, false, __VA_ARGS__ ); \ + call_error_handler( ctx, custom TSRMLS_CC, false, ## __VA_ARGS__ ); \ throw pdo::PDOException(); namespace pdo { @@ -390,14 +388,8 @@ namespace pdo { } // namespace pdo -// called pdo_parse_params in php_pdo_driver.h -// we renamed it for 2 reasons: 1) we can't have the same name since it would conflict with our dynamic linking, and -// 2) this is a more precise name -extern int (*pdo_subst_named_params)(pdo_stmt_t *stmt, char *inquery, size_t inquery_len, - char **outquery, size_t *outquery_len TSRMLS_DC); - // logger for pdo_sqlsrv called by the core layer when it wants to log something with the LOG macro void pdo_sqlsrv_log( unsigned int severity TSRMLS_DC, const char* msg, va_list* print_args ); -#endif /* PHP_PDO_SQLSRV_H */ +#endif /* PHP_PDO_SQLSRV_H */