diff --git a/source/sqlsrv/config.m4 b/source/sqlsrv/config.m4 new file mode 100644 index 00000000..6c988a17 --- /dev/null +++ b/source/sqlsrv/config.m4 @@ -0,0 +1,41 @@ +PHP_ARG_ENABLE(sqlsrv, whether to enable sqlsrv functions, +[ --disable-sqlsrv Disable sqlsrv functions], yes) + +if test "$PHP_SQLSRV" != "no"; then + sqlsrv_src_class="\ + conn.cpp \ + util.cpp \ + init.cpp \ + stmt.cpp \ + " + shared_src_class="\ + shared/core_conn.cpp \ + shared/core_results.cpp \ + shared/core_stream.cpp \ + shared/core_init.cpp \ + shared/core_stmt.cpp \ + shared/core_util.cpp \ + shared/FormattedPrint.cpp \ + shared/localizationimpl.cpp \ + shared/StringFunctions.cpp \ + " + AC_MSG_CHECKING([for SQLSRV headers]) + if test -f $srcdir/ext/sqlsrv/shared/core_sqlsrv.h; then + sqlsrv_inc_path=$srcdir/ext/sqlsrv/shared/ + elif test -f $srcdir/shared/core_sqlsrv.h; then + sqlsrv_inc_path=$srcdir/shared/ + else + AC_MSG_ERROR([Cannot find SQLSRV headers]) + fi + AC_MSG_RESULT($sqlsrv_inc_path) + + CXXFLAGS="$CXXFLAGS -std=c++11" + PHP_REQUIRE_CXX() + PHP_ADD_LIBRARY(stdc++, 1, SQLSRV_SHARED_LIBADD) + PHP_ADD_LIBRARY(odbc, 1, SQLSRV_SHARED_LIBADD) + PHP_SUBST(SQLSRV_SHARED_LIBADD) + AC_DEFINE(HAVE_SQLSRV, 1, [ ]) + PHP_ADD_INCLUDE([$sqlsrv_inc_path]) + PHP_NEW_EXTENSION(sqlsrv, $sqlsrv_src_class $shared_src_class, $ext_shared,,-std=c++11) + +fi diff --git a/source/sqlsrv/conn.cpp b/source/sqlsrv/conn.cpp index 773f36c4..59a2479f 100644 --- a/source/sqlsrv/conn.cpp +++ b/source/sqlsrv/conn.cpp @@ -18,9 +18,6 @@ //--------------------------------------------------------------------------------------------------------------------------------- #include "php_sqlsrv.h" -#include -#include -#include #include #include @@ -146,12 +143,12 @@ int get_stmt_option_key( zend_string* key, size_t key_len TSRMLS_DC ); // constants for parameters used by process_params function(s) int ss_sqlsrv_conn::descriptor; -char* ss_sqlsrv_conn::resource_name = "ss_sqlsrv_conn"; +char* ss_sqlsrv_conn::resource_name = static_cast("ss_sqlsrv_conn"); // connection specific parameter proccessing. Use the generic function specialised to return a connection // resource. #define PROCESS_PARAMS( rsrc, param_spec, calling_func, param_count, ... ) \ - rsrc = process_params( INTERNAL_FUNCTION_PARAM_PASSTHRU, param_spec, calling_func, param_count, __VA_ARGS__ ); \ + rsrc = process_params( INTERNAL_FUNCTION_PARAM_PASSTHRU, param_spec, calling_func, param_count, ##__VA_ARGS__ );\ if( rsrc == NULL ) { \ RETURN_FALSE; \ } @@ -765,7 +762,10 @@ PHP_FUNCTION( sqlsrv_client_info ) core_sqlsrv_get_client_info( conn, return_value TSRMLS_CC ); // Add the sqlsrv driver's file version - core::sqlsrv_add_assoc_string( *conn, return_value, "ExtensionVer", VER_FILEVERSION_STR, 1 /*duplicate*/ TSRMLS_CC ); + //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( *conn, return_value, extver, &filever[0], 1 /*duplicate*/ TSRMLS_CC ); } catch( core::CoreException& ) { @@ -978,7 +978,7 @@ PHP_FUNCTION( sqlsrv_query ) sqlsrv_malloc_auto_ptr stmt; char* sql = NULL; hash_auto_ptr ss_stmt_options_ht; - int sql_len = 0; + size_t sql_len = 0; zval* options_z = NULL; zval* params_z = NULL; zval stmt_z; @@ -1026,7 +1026,7 @@ PHP_FUNCTION( sqlsrv_query ) bind_params( stmt TSRMLS_CC ); // execute the statement - core_sqlsrv_execute( stmt TSRMLS_CC, sql, sql_len ); + core_sqlsrv_execute( stmt TSRMLS_CC, sql, static_cast( sql_len ) ); // register the statement with the PHP runtime ss::zend_register_resource(stmt_z, stmt, ss_sqlsrv_stmt::descriptor, ss_sqlsrv_stmt::resource_name TSRMLS_CC); @@ -1112,14 +1112,12 @@ void sqlsrv_conn_close_stmts( ss_sqlsrv_conn* conn TSRMLS_DC ) // delete the statement by deleting it from Zend's resource list, which will force its destruction stmt->conn = NULL; - try { - // this would call the destructor on the statement. - int zr = zend_list_close(Z_RES_P(rsrc_ptr)); - } - catch( core::CoreException& ) { - LOG(SEV_ERROR, "Failed to remove statement resource %1!d! when closing the connection", Z_RES_HANDLE_P(rsrc_ptr)); - } - } ZEND_HASH_FOREACH_END(); + // this would call the destructor on the statement. + // There's nothing we can do if the removal fails, so we just log it and move on. + if( zend_list_close( Z_RES_P(rsrc_ptr) ) == FAILURE ) { + LOG(SEV_ERROR, "Failed to remove statement resource %1!d! when closing the connection", Z_RES_HANDLE_P(rsrc_ptr)); + } + } ZEND_HASH_FOREACH_END(); zend_hash_destroy( conn->stmts ); FREE_HASHTABLE( conn->stmts ); @@ -1230,8 +1228,6 @@ void validate_stmt_options( sqlsrv_context& ctx, zval* stmt_options, _Inout_ Has ZEND_HASH_FOREACH_KEY_VAL( options_ht, int_key, key, data ) { int type = HASH_KEY_NON_EXISTENT; size_t key_len = 0; - zval* conn_opt = NULL; - int result = 0; type = key ? HASH_KEY_IS_STRING : HASH_KEY_IS_LONG; diff --git a/source/sqlsrv/init.cpp b/source/sqlsrv/init.cpp index 19934cab..5f047f4b 100644 --- a/source/sqlsrv/init.cpp +++ b/source/sqlsrv/init.cpp @@ -328,8 +328,11 @@ PHP_MINIT_FUNCTION(sqlsrv) REGISTER_LONG_CONSTANT( "SQLSRV_PHPTYPE_FLOAT", SQLSRV_PHPTYPE_FLOAT, CONST_PERSISTENT | CONST_CS ); REGISTER_LONG_CONSTANT( "SQLSRV_PHPTYPE_DATETIME", SQLSRV_PHPTYPE_DATETIME, CONST_PERSISTENT | CONST_CS ); - REGISTER_STRING_CONSTANT( "SQLSRV_ENC_BINARY", "binary", CONST_PERSISTENT | CONST_CS ); - REGISTER_STRING_CONSTANT( "SQLSRV_ENC_CHAR", "char", CONST_PERSISTENT | CONST_CS ); + std::string bin = "binary"; + std::string chr = "char"; + + REGISTER_STRING_CONSTANT( "SQLSRV_ENC_BINARY", &bin[0], CONST_PERSISTENT | CONST_CS ); + REGISTER_STRING_CONSTANT( "SQLSRV_ENC_CHAR", &chr[0], CONST_PERSISTENT | CONST_CS ); REGISTER_LONG_CONSTANT( "SQLSRV_NULLABLE_NO", 0, CONST_PERSISTENT | CONST_CS ); REGISTER_LONG_CONSTANT( "SQLSRV_NULLABLE_YES", 1, CONST_PERSISTENT | CONST_CS ); @@ -413,11 +416,17 @@ PHP_MINIT_FUNCTION(sqlsrv) REGISTER_LONG_CONSTANT( "SQLSRV_SCROLL_ABSOLUTE", SQL_FETCH_ABSOLUTE, CONST_PERSISTENT | CONST_CS ); REGISTER_LONG_CONSTANT( "SQLSRV_SCROLL_RELATIVE", SQL_FETCH_RELATIVE, CONST_PERSISTENT | CONST_CS ); - REGISTER_STRING_CONSTANT( "SQLSRV_CURSOR_FORWARD", "forward", CONST_PERSISTENT | CONST_CS ); - REGISTER_STRING_CONSTANT( "SQLSRV_CURSOR_STATIC", "static", CONST_PERSISTENT | CONST_CS ); - REGISTER_STRING_CONSTANT( "SQLSRV_CURSOR_DYNAMIC", "dynamic", CONST_PERSISTENT | CONST_CS ); - REGISTER_STRING_CONSTANT( "SQLSRV_CURSOR_KEYSET", "keyset", CONST_PERSISTENT | CONST_CS ); - REGISTER_STRING_CONSTANT( "SQLSRV_CURSOR_CLIENT_BUFFERED", "buffered", CONST_PERSISTENT | CONST_CS ); + std::string fwd = "forward"; + std::string stc = "static"; + std::string dyn = "dynamic"; + std::string key = "keyset"; + std::string buf = "buffered"; + + REGISTER_STRING_CONSTANT( "SQLSRV_CURSOR_FORWARD", &fwd[0], CONST_PERSISTENT | CONST_CS ); + REGISTER_STRING_CONSTANT( "SQLSRV_CURSOR_STATIC", &stc[0], CONST_PERSISTENT | CONST_CS ); + REGISTER_STRING_CONSTANT( "SQLSRV_CURSOR_DYNAMIC", &dyn[0], CONST_PERSISTENT | CONST_CS ); + REGISTER_STRING_CONSTANT( "SQLSRV_CURSOR_KEYSET", &key[0], CONST_PERSISTENT | CONST_CS ); + REGISTER_STRING_CONSTANT( "SQLSRV_CURSOR_CLIENT_BUFFERED", &buf[0], CONST_PERSISTENT | CONST_CS ); try { diff --git a/source/sqlsrv/php_sqlsrv.h b/source/sqlsrv/php_sqlsrv.h index bb1955bc..1aadb95b 100644 --- a/source/sqlsrv/php_sqlsrv.h +++ b/source/sqlsrv/php_sqlsrv.h @@ -48,8 +48,10 @@ OACR_WARNING_DISABLE( REALLOCLEAK, "Third party code." ) extern "C" { +#if defined(_MSC_VER) #pragma warning(push) #pragma warning( disable: 4005 4100 4127 4142 4244 4505 4530 ) +#endif #ifdef ZTS #include "TSRM.h" @@ -65,13 +67,9 @@ typedef int socklen_t; #define HAVE_SOCKLEN_T #endif -#include "php.h" -#include "php_globals.h" -#include "php_ini.h" -#include "ext/standard/php_standard.h" -#include "ext/standard/info.h" - +#if defined(_MSC_VER) #pragma warning(pop) +#endif #if PHP_MAJOR_VERSION < 7 #error Trying to compile "Microsoft Drivers for PHP for SQL Server (SQLSRV Driver)" with an unsupported version of PHP @@ -103,6 +101,8 @@ extern sqlsrv_context* g_henv_ncp; extern OSVERSIONINFO g_osversion; // used to determine which OS we're running in +#define phpext_sqlsrv_ptr &g_sqlsrv_module_entry + // module initialization PHP_MINIT_FUNCTION(sqlsrv); // module shutdown function @@ -373,7 +373,7 @@ unsigned int convert_string_from_default_encoding( unsigned int php_encoding, ch // create a wide char string from the passed in mbcs string. NULL is returned if the string // could not be created. No error is posted by this function. utf16_len is the number of // wchar_t characters, not the number of bytes. -wchar_t* utf16_string_from_mbcs_string( unsigned int php_encoding, const char* mbcs_string, +SQLWCHAR* utf16_string_from_mbcs_string( unsigned int php_encoding, const char* mbcs_string, unsigned int mbcs_len, _Out_ unsigned int* utf16_len ); // *** internal error macros and functions *** @@ -407,7 +407,7 @@ inline void reset_errors( TSRMLS_D ) } #define THROW_SS_ERROR( ctx, error_code, ... ) \ - (void)call_error_handler( ctx, error_code TSRMLS_CC, false /*warning*/, __VA_ARGS__ ); \ + (void)call_error_handler( ctx, error_code TSRMLS_CC, false /*warning*/, ## __VA_ARGS__ ); \ throw ss::SSException(); @@ -475,6 +475,31 @@ enum logging_subsystems { LOG_ALL = -1, }; +//********************************************************************************************************************************* +// Common function wrappers +// have to place this namespace before the utility functions +// otherwise can't compile in Linux because 'ss' not defined +//********************************************************************************************************************************* +namespace ss { + + // an error which occurred in our SQLSRV driver + struct SSException : public core::CoreException { + + SSException() + { + } + }; + + inline void zend_register_resource(_Out_ zval& rsrc_result, void* rsrc_pointer, int rsrc_type, char* rsrc_name TSRMLS_DC) + { + int zr = (NULL != (Z_RES(rsrc_result) = ::zend_register_resource(rsrc_pointer, rsrc_type)) ? SUCCESS : FAILURE); + CHECK_CUSTOM_ERROR(( zr == FAILURE ), reinterpret_cast( rsrc_pointer ), SS_SQLSRV_ERROR_REGISTER_RESOURCE, + rsrc_name ) { + throw ss::SSException(); + } + Z_TYPE_INFO(rsrc_result) = IS_RESOURCE_EX; + } +} // namespace ss //********************************************************************************************************************************* // Utility Functions @@ -519,7 +544,7 @@ inline H* process_params( INTERNAL_FUNCTION_PARAMETERS, char const* param_spec, int result = SUCCESS; // dummy context to pass to the error handler - sqlsrv_context error_ctx( 0, ss_error_handler, NULL );; + sqlsrv_context error_ctx( 0, ss_error_handler, NULL ); error_ctx.set_func( calling_func ); switch( param_count ) { @@ -591,28 +616,5 @@ inline H* process_params( INTERNAL_FUNCTION_PARAMETERS, char const* param_spec, DIE( "%1!s!: Unknown exception caught in process_params.", calling_func ); } } -//********************************************************************************************************************************* -// Common function wrappers -//********************************************************************************************************************************* -namespace ss { - - // an error which occurred in our SQLSRV driver - struct SSException : public core::CoreException { - - SSException() - { - } - }; - - inline void zend_register_resource(_Out_ zval& rsrc_result, void* rsrc_pointer, int rsrc_type, char* rsrc_name TSRMLS_DC) - { - int zr = (NULL != (Z_RES(rsrc_result) = ::zend_register_resource(rsrc_pointer, rsrc_type)) ? SUCCESS : FAILURE); - CHECK_CUSTOM_ERROR(( zr == FAILURE ), reinterpret_cast( rsrc_pointer ), SS_SQLSRV_ERROR_REGISTER_RESOURCE, - rsrc_name ) { - throw ss::SSException(); - } - Z_TYPE_INFO(rsrc_result) = IS_RESOURCE_EX; - } -} // namespace ss #endif /* PHP_SQLSRV_H */ diff --git a/source/sqlsrv/stmt.cpp b/source/sqlsrv/stmt.cpp index 40165e4e..d018b057 100644 --- a/source/sqlsrv/stmt.cpp +++ b/source/sqlsrv/stmt.cpp @@ -19,14 +19,16 @@ // *** header files *** #include "php_sqlsrv.h" +#ifdef _WIN32 #include +#endif // // *** internal variables and constants *** // // our resource descriptor assigned in minit int ss_sqlsrv_stmt::descriptor = 0; -char* ss_sqlsrv_stmt::resource_name = "ss_sqlsrv_stmt"; // not const for a reason. see sqlsrv_stmt in php_sqlsrv.h +char* ss_sqlsrv_stmt::resource_name = static_cast("ss_sqlsrv_stmt"); // not const for a reason. see sqlsrv_stmt in php_sqlsrv.h namespace { @@ -72,12 +74,12 @@ enum SQLSRV_PHPTYPE zend_to_sqlsrv_phptype[] = { // (char to avoid having to cast them where they are used) namespace FieldMetaData { -char* NAME = "Name"; -char* TYPE = "Type"; -char* SIZE = "Size"; -char* PREC = "Precision"; -char* SCALE = "Scale"; -char* NULLABLE = "Nullable"; +const char* NAME = "Name"; +const char* TYPE = "Type"; +const char* SIZE = "Size"; +const char* PREC = "Precision"; +const char* SCALE = "Scale"; +const char* NULLABLE = "Nullable"; } @@ -248,7 +250,7 @@ sqlsrv_phptype ss_sqlsrv_stmt::sql_type_to_php_type( SQLINTEGER sql_type, SQLUIN // statement specific parameter proccessing. Uses the generic function specialised to return a statement // resource. #define PROCESS_PARAMS( rsrc, param_spec, calling_func, param_count, ... ) \ - rsrc = process_params( INTERNAL_FUNCTION_PARAM_PASSTHRU, param_spec, calling_func, param_count, __VA_ARGS__ );\ + rsrc = process_params( INTERNAL_FUNCTION_PARAM_PASSTHRU, param_spec, calling_func, param_count, ## __VA_ARGS__ );\ if( rsrc == NULL ) { \ RETURN_FALSE; \ } @@ -553,7 +555,6 @@ PHP_FUNCTION( sqlsrv_next_result ) { LOG_FUNCTION( "sqlsrv_next_result" ); - SQLRETURN r = SQL_SUCCESS; ss_sqlsrv_stmt* stmt = NULL; PROCESS_PARAMS( stmt, "r", _FN_, 0 ); @@ -597,7 +598,6 @@ PHP_FUNCTION( sqlsrv_next_result ) PHP_FUNCTION( sqlsrv_rows_affected ) { LOG_FUNCTION( "sqlsrv_rows_affected" ); - SQLRETURN r = SQL_SUCCESS; ss_sqlsrv_stmt* stmt = NULL; SQLLEN rows = -1; @@ -1067,10 +1067,10 @@ PHP_FUNCTION( sqlsrv_get_field ) sqlsrv_php_type.typeinfo.type = SQLSRV_PHPTYPE_INVALID; SQLSRV_PHPTYPE sqlsrv_php_type_out = SQLSRV_PHPTYPE_INVALID; void* field_value = NULL; - int field_index = -1; + zend_long field_index = -1; SQLLEN field_len = -1; - zval retval_z; - ZVAL_UNDEF(&retval_z); + zval retval_z; + ZVAL_UNDEF(&retval_z); // get the statement, the field index and the optional type PROCESS_PARAMS( stmt, "rl|l", _FN_, 2, &field_index, &sqlsrv_php_type ); @@ -1084,10 +1084,10 @@ PHP_FUNCTION( sqlsrv_get_field ) THROW_SS_ERROR( stmt, SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER, _FN_ ); } - core_sqlsrv_get_field( stmt, field_index, sqlsrv_php_type, false, field_value, &field_len, false/*cache_field*/, - &sqlsrv_php_type_out TSRMLS_CC ); + core_sqlsrv_get_field( stmt, static_cast( field_index ), sqlsrv_php_type, false, field_value, &field_len, false/*cache_field*/, + &sqlsrv_php_type_out TSRMLS_CC ); convert_to_zval( stmt, sqlsrv_php_type_out, field_value, field_len, retval_z ); - sqlsrv_free( field_value ); + sqlsrv_free( field_value ); RETURN_ZVAL( &retval_z, 1, 1 ); } @@ -1824,8 +1824,14 @@ void fetch_fields_common( _Inout_ ss_sqlsrv_stmt* stmt, zend_long fetch_type, _O SQLSRV_ENCODING encoding = (( stmt->encoding() == SQLSRV_ENCODING_DEFAULT ) ? stmt->conn->encoding() : stmt->encoding()); for( int i = 0; i < num_cols; ++i ) { - core::SQLColAttributeW( stmt, i + 1, SQL_DESC_NAME, field_name_w, ( SS_MAXCOLNAMELEN + 1 ) * 2, &field_name_len_w, NULL TSRMLS_CC ); - bool converted = convert_string_from_utf16( encoding, field_name_w, field_name_len_w, ( char** ) &field_name, field_name_len ); + core::SQLColAttributeW ( stmt, i + 1, SQL_DESC_NAME, field_name_w, ( SS_MAXCOLNAMELEN + 1 ) * 2, &field_name_len_w, NULL TSRMLS_CC ); +#ifdef __linux__ + //Conversion function in Linux expects size in characters. + field_name_len_w = field_name_len_w / sizeof ( SQLWCHAR ); +#endif + bool converted = convert_string_from_utf16( encoding, field_name_w, + field_name_len_w, ( char** ) &field_name, field_name_len ); + CHECK_CUSTOM_ERROR( !converted, stmt, SQLSRV_ERROR_FIELD_ENCODING_TRANSLATE, get_last_error_message() ) { throw core::CoreException(); } @@ -2152,7 +2158,7 @@ void type_and_size_calc( INTERNAL_FUNCTION_PARAMETERS, int type ) { char* size_p = NULL; size_t size_len = 0; - long size = 0; + int size = 0; if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "s", &size_p, &size_len ) == FAILURE ) { @@ -2163,7 +2169,11 @@ void type_and_size_calc( INTERNAL_FUNCTION_PARAMETERS, int type ) size = SQLSRV_SIZE_MAX_TYPE; } else { - _set_errno( 0 ); // reset errno for atol +#ifdef __linux__ + errno = 0; +#else + _set_errno(0); // reset errno for atol +#endif size = atol( size_p ); if( errno != 0 ) { size = SQLSRV_INVALID_SIZE; diff --git a/source/sqlsrv/util.cpp b/source/sqlsrv/util.cpp index c2b2123b..81eaa242 100644 --- a/source/sqlsrv/util.cpp +++ b/source/sqlsrv/util.cpp @@ -21,8 +21,6 @@ #include "php_sqlsrv.h" -#include - namespace { // current subsytem. defined for the CHECK_SQL_{ERROR|WARNING} macros