From aaa3203e550d80dca6bdaac75acc9c6c0f9cea46 Mon Sep 17 00:00:00 2001 From: David Puglielli Date: Thu, 19 Jan 2017 11:53:21 -0800 Subject: [PATCH] Merged Linux and Windows PDO_SQLSRV code --- source/pdo_sqlsrv/pdo_dbh.cpp | 194 ++++++++++++++++------------- source/pdo_sqlsrv/pdo_init.cpp | 114 ++--------------- source/pdo_sqlsrv/pdo_parser.cpp | 7 +- source/pdo_sqlsrv/pdo_stmt.cpp | 63 ++++++---- source/pdo_sqlsrv/pdo_util.cpp | 9 +- source/pdo_sqlsrv/php_pdo_sqlsrv.h | 15 +-- 6 files changed, 171 insertions(+), 231 deletions(-) diff --git a/source/pdo_sqlsrv/pdo_dbh.cpp b/source/pdo_sqlsrv/pdo_dbh.cpp index 77ea5ba7..7bfa8dbd 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 *** @@ -355,12 +351,25 @@ struct pdo_dbh_methods pdo_sqlsrv_dbh_methods = { // log a function entry point +#ifdef __linux__ +#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 ) : @@ -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 )); } 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 + 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,9 +922,9 @@ 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: @@ -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; } @@ -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; } @@ -1137,8 +1152,8 @@ char * pdo_sqlsrv_dbh_last_id( pdo_dbh_t *dbh, const char *name, _Out_ size_t* l char* quoted_table = NULL; 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 ); } @@ -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. @@ -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 ) { @@ -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..2acdff84 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; @@ -134,11 +99,6 @@ 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)); @@ -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,7 +276,7 @@ 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 }, diff --git a/source/pdo_sqlsrv/pdo_parser.cpp b/source/pdo_sqlsrv/pdo_parser.cpp index 6e735b56..cd553dc3 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..c05a7540 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."); +#ifndef __linux__ OACR_WARNING_SUPPRESS( 26001, "Buffer length verified above" ); OACR_WARNING_SUPPRESS( 26000, "Buffer length verified above" ); +#endif return odbc_fetch_orientation[ori]; } @@ -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 +#ifdef __linux__ +#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 ) @@ -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; @@ -708,7 +720,7 @@ int pdo_sqlsrv_stmt_get_col_data(pdo_stmt_t *stmt, int colno, "Invalid column number in pdo_sqlsrv_stmt_get_col_data" ); sqlsrv_php_type = driver_stmt->sql_type_to_php_type( static_cast( driver_stmt->current_meta_data[ colno ]->field_type ), static_cast( driver_stmt->current_meta_data[ colno ]->field_size ), - true ); + true ); // set the encoding if the user specified one via bindColumn, otherwise use the statement's encoding sqlsrv_php_type.typeinfo.encoding = driver_stmt->encoding(); @@ -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 { @@ -817,9 +829,9 @@ int pdo_sqlsrv_stmt_set_attr(pdo_stmt_t *stmt, zend_long attr, zval *val TSRMLS_ core_sqlsrv_set_buffered_query_limit( driver_stmt, val TSRMLS_CC ); break; - case SQLSRV_ATTR_FETCHES_NUMERIC_TYPE: - driver_stmt->fetch_numeric = ( zend_is_true( val )) ? true : false; - break; + case SQLSRV_ATTR_FETCHES_NUMERIC_TYPE: + driver_stmt->fetch_numeric = ( zend_is_true( val )) ? true : false; + break; default: THROW_PDO_ERROR( driver_stmt, PDO_SQLSRV_ERROR_INVALID_STMT_ATTR ); @@ -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; diff --git a/source/pdo_sqlsrv/pdo_util.cpp b/source/pdo_sqlsrv/pdo_util.cpp index fd36a9c2..c1db4ce6 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 } }, @@ -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" ); diff --git a/source/pdo_sqlsrv/php_pdo_sqlsrv.h b/source/pdo_sqlsrv/php_pdo_sqlsrv.h index f158d933..f17387f9 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" } @@ -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: @@ -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; @@ -274,7 +275,7 @@ bool pdo_sqlsrv_handle_stmt_error( sqlsrv_context& ctx, unsigned int sqlsrv_erro 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 ); +//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 +376,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 { @@ -393,8 +394,8 @@ 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); +//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 );