2018-12-20 20:49:06 +01:00
# ifndef PHP_SQLSRV_INT_H
# define PHP_SQLSRV_INT_H
//---------------------------------------------------------------------------------------------------------------------------------
// File: php_sqlsrv_int.h
//
// Contents: Internal declarations for the extension
//
// Comments: Also contains "internal" declarations shared across source files.
//
2021-09-08 02:38:17 +02:00
// Microsoft Drivers 5.10 for PHP for SQL Server
2018-12-20 20:49:06 +01:00
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the ""Software""),
// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions :
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//---------------------------------------------------------------------------------------------------------------------------------
# include "core_sqlsrv.h"
# include "version.h"
//*********************************************************************************************************************************
// Global variables
//*********************************************************************************************************************************
// INI settings and constants
// (these are defined as macros to allow concatenation as we do below)
# define INI_WARNINGS_RETURN_AS_ERRORS "WarningsReturnAsErrors"
# define INI_LOG_SEVERITY "LogSeverity"
# define INI_LOG_SUBSYSTEMS "LogSubsystems"
# define INI_BUFFERED_QUERY_LIMIT "ClientBufferMaxKBSize"
# define INI_PREFIX "sqlsrv."
2019-12-19 20:03:25 +01:00
# ifndef _WIN32
# define INI_SET_LOCALE_INFO "SetLocaleInfo"
# endif
2018-12-20 20:49:06 +01:00
PHP_INI_BEGIN ( )
STD_PHP_INI_BOOLEAN ( INI_PREFIX INI_WARNINGS_RETURN_AS_ERRORS , " 1 " , PHP_INI_ALL , OnUpdateBool , warnings_return_as_errors ,
zend_sqlsrv_globals , sqlsrv_globals )
STD_PHP_INI_ENTRY ( INI_PREFIX INI_LOG_SEVERITY , " 0 " , PHP_INI_ALL , OnUpdateLong , log_severity , zend_sqlsrv_globals ,
sqlsrv_globals )
STD_PHP_INI_ENTRY ( INI_PREFIX INI_LOG_SUBSYSTEMS , " 0 " , PHP_INI_ALL , OnUpdateLong , log_subsystems , zend_sqlsrv_globals ,
sqlsrv_globals )
STD_PHP_INI_ENTRY ( INI_PREFIX INI_BUFFERED_QUERY_LIMIT , INI_BUFFERED_QUERY_LIMIT_DEFAULT , PHP_INI_ALL , OnUpdateLong , buffered_query_limit ,
zend_sqlsrv_globals , sqlsrv_globals )
2019-12-19 20:03:25 +01:00
# ifndef _WIN32
STD_PHP_INI_ENTRY ( INI_PREFIX INI_SET_LOCALE_INFO , " 2 " , PHP_INI_ALL , OnUpdateLong , set_locale_info ,
zend_sqlsrv_globals , sqlsrv_globals )
# endif
2018-12-20 20:49:06 +01:00
PHP_INI_END ( )
//*********************************************************************************************************************************
// Initialization Functions
//*********************************************************************************************************************************
// module global variables (initialized in minit and freed in mshutdown)
extern HashTable * g_ss_errors_ht ;
extern HashTable * g_ss_encodings_ht ;
extern HashTable * g_ss_warnings_to_ignore_ht ;
extern HMODULE g_sqlsrv_hmodule ; // used for getting the version information
// henv context for creating connections
extern sqlsrv_context * g_ss_henv_cp ;
extern sqlsrv_context * g_ss_henv_ncp ;
//*********************************************************************************************************************************
// Connection
//*********************************************************************************************************************************
struct ss_sqlsrv_conn : sqlsrv_conn
{
HashTable * stmts ;
bool date_as_string ;
bool format_decimals ; // flag set to turn on formatting for values of decimal / numeric types
short decimal_places ; // number of decimal digits to show in a result set unless format_numbers is false
bool in_transaction ; // flag set when inside a transaction and used for checking validity of tran API calls
// static variables used in process_params
static const char * resource_name ;
static int descriptor ;
// initialize with default values
2020-04-21 00:17:21 +02:00
ss_sqlsrv_conn ( _In_ SQLHANDLE h , _In_ error_callback e , _In_ void * drv ) :
sqlsrv_conn ( h , e , drv , SQLSRV_ENCODING_SYSTEM ) ,
2018-12-20 20:49:06 +01:00
stmts ( NULL ) ,
date_as_string ( false ) ,
format_decimals ( false ) ,
decimal_places ( NO_CHANGE_DECIMAL_PLACES ) ,
in_transaction ( false )
{
}
} ;
// resource destructor
2020-04-21 00:17:21 +02:00
void __cdecl sqlsrv_conn_dtor ( _Inout_ zend_resource * rsrc ) ;
2018-12-20 20:49:06 +01:00
//*********************************************************************************************************************************
// Statement
//*********************************************************************************************************************************
// holds the field names for reuse by sqlsrv_fetch_array/object as keys
struct sqlsrv_fetch_field_name {
char * name ;
SQLLEN len ;
} ;
struct stmt_option_ss_scrollable : public stmt_option_functor {
2020-04-21 00:17:21 +02:00
virtual void operator ( ) ( _Inout_ sqlsrv_stmt * stmt , stmt_option const * /*opt*/ , _In_ zval * value_z ) ;
2018-12-20 20:49:06 +01:00
} ;
// This object inherits and overrides the callbacks necessary
struct ss_sqlsrv_stmt : public sqlsrv_stmt {
2020-04-21 00:17:21 +02:00
ss_sqlsrv_stmt ( _In_ sqlsrv_conn * c , _In_ SQLHANDLE handle , _In_ error_callback e , _In_ void * drv ) ;
2018-12-20 20:49:06 +01:00
virtual ~ ss_sqlsrv_stmt ( void ) ;
2020-04-21 00:17:21 +02:00
void new_result_set ( void ) ;
2018-12-20 20:49:06 +01:00
// driver specific conversion rules from a SQL Server/ODBC type to one of the SQLSRV_PHPTYPE_* constants
sqlsrv_phptype sql_type_to_php_type ( _In_ SQLINTEGER sql_type , _In_ SQLUINTEGER size , _In_ bool prefer_string_to_stream ) ;
bool prepared ; // whether the statement has been prepared yet (used for error messages)
2020-04-21 00:17:21 +02:00
zend_ulong conn_index ; // index into the connection hash that contains this statement structure
2018-12-20 20:49:06 +01:00
zval * params_z ; // hold parameters passed to sqlsrv_prepare but not used until sqlsrv_execute
sqlsrv_fetch_field_name * fetch_field_names ; // field names for current results used by sqlsrv_fetch_array/object as keys
int fetch_fields_count ;
// static variables used in process_params
static const char * resource_name ;
static int descriptor ;
} ;
// holds the field names for reuse by sqlsrv_fetch_array/object as keys
struct sqlsrv_fetch_field {
char * name ;
unsigned int len ;
} ;
// holds the stream param and the encoding that it was assigned
struct sqlsrv_stream_encoding {
zval * stream_z ;
unsigned int encoding ;
sqlsrv_stream_encoding ( _In_ zval * str_z , _In_ unsigned int enc ) :
stream_z ( str_z ) , encoding ( enc )
{
}
} ;
// resource destructor
2020-04-21 00:17:21 +02:00
void __cdecl sqlsrv_stmt_dtor ( _Inout_ zend_resource * rsrc ) ;
2018-12-20 20:49:06 +01:00
// "internal" statement functions shared by functions in conn.cpp and stmt.cpp
2020-04-21 00:17:21 +02:00
void bind_params ( _Inout_ ss_sqlsrv_stmt * stmt ) ;
2018-12-20 20:49:06 +01:00
bool sqlsrv_stmt_common_execute ( sqlsrv_stmt * s , const SQLCHAR * sql_string , int sql_len , bool direct , const char * function
2020-04-21 00:17:21 +02:00
) ;
void free_odbc_resources ( ss_sqlsrv_stmt * stmt ) ;
void free_stmt_resource ( _Inout_ zval * stmt_z ) ;
2018-12-20 20:49:06 +01:00
//*********************************************************************************************************************************
// Errors
//*********************************************************************************************************************************
// represents the mapping between an error_code and the corresponding error message.
struct ss_error {
unsigned int error_code ;
sqlsrv_error_const sqlsrv_error ;
} ;
// List of all driver specific error codes.
enum SS_ERROR_CODES {
SS_SQLSRV_ERROR_ALREADY_IN_TXN = SQLSRV_ERROR_DRIVER_SPECIFIC ,
SS_SQLSRV_ERROR_NOT_IN_TXN ,
SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER ,
SS_SQLSRV_ERROR_REGISTER_RESOURCE ,
SS_SQLSRV_ERROR_INVALID_CONNECTION_KEY ,
SS_SQLSRV_ERROR_STATEMENT_NOT_PREPARED ,
SS_SQLSRV_ERROR_INVALID_FETCH_STYLE ,
SS_SQLSRV_ERROR_INVALID_FETCH_TYPE ,
SS_SQLSRV_WARNING_FIELD_NAME_EMPTY ,
SS_SQLSRV_ERROR_ZEND_OBJECT_FAILED ,
SS_SQLSRV_ERROR_ZEND_BAD_CLASS ,
SS_SQLSRV_ERROR_STATEMENT_SCROLLABLE ,
SS_SQLSRV_ERROR_STATEMENT_NOT_SCROLLABLE ,
SS_SQLSRV_ERROR_INVALID_OPTION ,
SS_SQLSRV_ERROR_PARAM_INVALID_INDEX ,
SS_SQLSRV_ERROR_INVALID_PARAMETER_PRECISION ,
SS_SQLSRV_ERROR_INVALID_PARAMETER_DIRECTION ,
SS_SQLSRV_ERROR_VAR_REQUIRED ,
SS_SQLSRV_ERROR_CONNECT_ILLEGAL_ENCODING ,
SS_SQLSRV_ERROR_CONNECT_BRACES_NOT_ESCAPED ,
SS_SQLSRV_ERROR_INVALID_OUTPUT_PARAM_TYPE ,
SS_SQLSRV_ERROR_PARAM_VAR_NOT_REF ,
SS_SQLSRV_ERROR_AE_QUERY_SQLTYPE_REQUIRED
} ;
extern ss_error SS_ERRORS [ ] ;
2020-10-17 00:17:58 +02:00
bool ss_error_handler ( _Inout_ sqlsrv_context & ctx , _In_ unsigned int sqlsrv_error_code , _In_ int warning , _In_opt_ va_list * print_args ) ;
2018-12-20 20:49:06 +01:00
// convert from the default encoding specified by the "CharacterSet"
// connection option to UTF-16. mbcs_len and utf16_len are sizes in
// bytes. The return is the number of UTF-16 characters in the string
// returned in utf16_out_string.
unsigned int convert_string_from_default_encoding ( _In_ unsigned int php_encoding , _In_reads_bytes_ ( mbcs_len ) char const * mbcs_in_string ,
_In_ unsigned int mbcs_len , _Out_writes_ ( utf16_len ) __transfer ( mbcs_in_string ) wchar_t * utf16_out_string ,
2019-05-10 22:03:22 +02:00
_In_ unsigned int utf16_len , bool use_strict_conversion = false ) ;
2018-12-20 20:49:06 +01:00
// 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.
SQLWCHAR * utf16_string_from_mbcs_string ( _In_ unsigned int php_encoding , _In_reads_bytes_ ( mbcs_len ) const char * mbcs_string ,
2019-05-10 22:03:22 +02:00
_In_ unsigned int mbcs_len , _Out_ unsigned int * utf16_len , bool use_strict_conversion = false ) ;
2018-12-20 20:49:06 +01:00
// *** internal error macros and functions ***
bool handle_error ( sqlsrv_context const * ctx , int log_subsystem , const char * function ,
2020-04-21 00:17:21 +02:00
sqlsrv_error const * ssphp , . . . ) ;
2018-12-20 20:49:06 +01:00
void handle_warning ( sqlsrv_context const * ctx , int log_subsystem , const char * function ,
2020-04-21 00:17:21 +02:00
sqlsrv_error const * ssphp , . . . ) ;
void __cdecl sqlsrv_error_dtor ( zend_resource * rsrc ) ;
2018-12-20 20:49:06 +01:00
// release current error lists and set to NULL
2020-04-21 00:17:21 +02:00
inline void reset_errors ( void )
2018-12-20 20:49:06 +01:00
{
if ( Z_TYPE ( SQLSRV_G ( errors ) ) ! = IS_ARRAY & & Z_TYPE ( SQLSRV_G ( errors ) ) ! = IS_NULL ) {
DIE ( " sqlsrv_errors contains an invalid type " ) ;
}
if ( Z_TYPE ( SQLSRV_G ( warnings ) ) ! = IS_ARRAY & & Z_TYPE ( SQLSRV_G ( warnings ) ) ! = IS_NULL ) {
DIE ( " sqlsrv_warnings contains an invalid type " ) ;
}
if ( Z_TYPE ( SQLSRV_G ( errors ) ) = = IS_ARRAY ) {
zend_hash_destroy ( Z_ARRVAL ( SQLSRV_G ( errors ) ) ) ;
FREE_HASHTABLE ( Z_ARRVAL ( SQLSRV_G ( errors ) ) ) ;
}
if ( Z_TYPE ( SQLSRV_G ( warnings ) ) = = IS_ARRAY ) {
zend_hash_destroy ( Z_ARRVAL ( SQLSRV_G ( warnings ) ) ) ;
FREE_HASHTABLE ( Z_ARRVAL ( SQLSRV_G ( warnings ) ) ) ;
}
ZVAL_NULL ( & SQLSRV_G ( errors ) ) ;
ZVAL_NULL ( & SQLSRV_G ( warnings ) ) ;
}
# define THROW_SS_ERROR( ctx, error_code, ... ) \
2020-10-17 00:17:58 +02:00
( void ) call_error_handler ( ctx , error_code , 0 /*warning*/ , # # __VA_ARGS__ ) ; \
2018-12-20 20:49:06 +01:00
throw ss : : SSException ( ) ;
class sqlsrv_context_auto_ptr : public sqlsrv_auto_ptr < sqlsrv_context , sqlsrv_context_auto_ptr > {
public :
sqlsrv_context_auto_ptr ( void ) :
sqlsrv_auto_ptr < sqlsrv_context , sqlsrv_context_auto_ptr > ( NULL )
{
}
sqlsrv_context_auto_ptr ( _Inout_opt_ const sqlsrv_context_auto_ptr & src ) :
sqlsrv_auto_ptr < sqlsrv_context , sqlsrv_context_auto_ptr > ( src )
{
}
// free the original pointer and assign a new pointer. Use NULL to simply free the pointer.
void reset ( _In_opt_ sqlsrv_context * ptr = NULL )
{
if ( _ptr ) {
_ptr - > ~ sqlsrv_context ( ) ;
sqlsrv_free ( ( void * ) _ptr ) ;
}
_ptr = ptr ;
}
sqlsrv_context * operator = ( _In_opt_ sqlsrv_context * ptr )
{
return sqlsrv_auto_ptr < sqlsrv_context , sqlsrv_context_auto_ptr > : : operator = ( ptr ) ;
}
void operator = ( _Inout_opt_ sqlsrv_context_auto_ptr & src )
{
sqlsrv_context * p = src . get ( ) ;
src . transferred ( ) ;
this - > _ptr = p ;
}
} ;
//*********************************************************************************************************************************
// Logging
//*********************************************************************************************************************************
# define LOG_FUNCTION( function_name ) \
const char * _FN_ = function_name ; \
SQLSRV_G ( current_subsystem ) = current_log_subsystem ; \
2020-03-25 17:53:18 +01:00
core_sqlsrv_register_severity_checker ( ss_severity_check ) ; \
LOG ( SEV_NOTICE , " %1!s!: entering " , _FN_ ) ;
2018-12-20 20:49:06 +01:00
2020-03-25 17:53:18 +01:00
// check the global variables of sqlsrv severity whether the message qualifies to be logged with the LOG macro
2020-04-21 00:17:21 +02:00
bool ss_severity_check ( _In_ unsigned int severity ) ;
2018-12-20 20:49:06 +01:00
// subsystems that may report log messages. These may be used to filter which systems write to the log to prevent noise.
enum logging_subsystems {
LOG_INIT = 0x01 ,
LOG_CONN = 0x02 ,
LOG_STMT = 0x04 ,
LOG_UTIL = 0x08 ,
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 ( )
{
}
} ;
2020-04-21 00:17:21 +02:00
inline void zend_register_resource ( _Inout_ zval & rsrc_result , _Inout_ void * rsrc_pointer , _In_ int rsrc_type , _In_opt_ const char * rsrc_name )
2018-12-20 20:49:06 +01:00
{
int zr = ( NULL ! = ( Z_RES ( rsrc_result ) = : : zend_register_resource ( rsrc_pointer , rsrc_type ) ) ? SUCCESS : FAILURE ) ;
CHECK_CUSTOM_ERROR ( ( zr = = FAILURE ) , reinterpret_cast < sqlsrv_context * > ( rsrc_pointer ) , SS_SQLSRV_ERROR_REGISTER_RESOURCE ,
rsrc_name ) {
throw ss : : SSException ( ) ;
}
Z_TYPE_INFO ( rsrc_result ) = IS_RESOURCE_EX ;
}
} // namespace ss
//*********************************************************************************************************************************
// Utility Functions
//*********************************************************************************************************************************
// generic function used to validate parameters to a PHP function.
// Register an invalid parameter error and returns NULL when parameters don't match the spec given.
template < typename H >
inline H * process_params ( INTERNAL_FUNCTION_PARAMETERS , _In_ char const * param_spec , _In_ const char * calling_func , _In_ size_t param_count , . . . )
{
2020-10-17 00:17:58 +02:00
// SQLSRV_UNUSED( return_value );
2018-12-20 20:49:06 +01:00
zval * rsrc ;
2020-07-15 02:22:46 +02:00
H * h = NULL ;
2018-12-20 20:49:06 +01:00
// reset the errors from the previous API call
2020-04-21 00:17:21 +02:00
reset_errors ( ) ;
2018-12-20 20:49:06 +01:00
if ( ZEND_NUM_ARGS ( ) > param_count + 1 ) {
DIE ( " Param count and argument count don't match. " ) ;
return NULL ; // for static analysis tools
}
try {
if ( param_count > 6 ) {
DIE ( " Param count cannot exceed 6 " ) ;
return NULL ; // for static analysis tools
}
void * arr [ 6 ] ;
va_list vaList ;
va_start ( vaList , param_count ) ; //set the pointer to first argument
for ( size_t i = 0 ; i < param_count ; + + i ) {
arr [ i ] = va_arg ( vaList , void * ) ;
}
va_end ( vaList ) ;
int result = SUCCESS ;
// dummy context to pass to the error handler
sqlsrv_context error_ctx ( 0 , ss_error_handler , NULL ) ;
error_ctx . set_func ( calling_func ) ;
switch ( param_count ) {
case 0 :
2020-04-21 00:17:21 +02:00
result = zend_parse_parameters ( ZEND_NUM_ARGS ( ) , const_cast < char * > ( param_spec ) , & rsrc ) ;
2018-12-20 20:49:06 +01:00
break ;
case 1 :
2020-04-21 00:17:21 +02:00
result = zend_parse_parameters ( ZEND_NUM_ARGS ( ) , const_cast < char * > ( param_spec ) , & rsrc , arr [ 0 ] ) ;
2018-12-20 20:49:06 +01:00
break ;
case 2 :
2020-04-21 00:17:21 +02:00
result = zend_parse_parameters ( ZEND_NUM_ARGS ( ) , const_cast < char * > ( param_spec ) , & rsrc , arr [ 0 ] ,
2018-12-20 20:49:06 +01:00
arr [ 1 ] ) ;
break ;
case 3 :
2020-04-21 00:17:21 +02:00
result = zend_parse_parameters ( ZEND_NUM_ARGS ( ) , const_cast < char * > ( param_spec ) , & rsrc , arr [ 0 ] ,
2018-12-20 20:49:06 +01:00
arr [ 1 ] , arr [ 2 ] ) ;
break ;
case 4 :
2020-04-21 00:17:21 +02:00
result = zend_parse_parameters ( ZEND_NUM_ARGS ( ) , const_cast < char * > ( param_spec ) , & rsrc , arr [ 0 ] ,
2018-12-20 20:49:06 +01:00
arr [ 1 ] , arr [ 2 ] , arr [ 3 ] ) ;
break ;
case 5 :
2020-04-21 00:17:21 +02:00
result = zend_parse_parameters ( ZEND_NUM_ARGS ( ) , const_cast < char * > ( param_spec ) , & rsrc , arr [ 0 ] ,
2018-12-20 20:49:06 +01:00
arr [ 1 ] , arr [ 2 ] , arr [ 3 ] , arr [ 4 ] ) ;
break ;
case 6 :
2020-04-21 00:17:21 +02:00
result = zend_parse_parameters ( ZEND_NUM_ARGS ( ) , const_cast < char * > ( param_spec ) , & rsrc , arr [ 0 ] ,
2018-12-20 20:49:06 +01:00
arr [ 1 ] , arr [ 2 ] , arr [ 3 ] , arr [ 4 ] , arr [ 5 ] ) ;
break ;
default :
{
THROW_CORE_ERROR ( error_ctx , SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER , calling_func ) ;
break ;
}
}
CHECK_CUSTOM_ERROR ( ( result = = FAILURE ) , & error_ctx , SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER , calling_func ) {
throw ss : : SSException ( ) ;
}
// get the resource registered
2020-04-21 00:17:21 +02:00
h = static_cast < H * > ( zend_fetch_resource ( Z_RES_P ( rsrc ) , H : : resource_name , H : : descriptor ) ) ;
2018-12-20 20:49:06 +01:00
CHECK_CUSTOM_ERROR ( ( h = = NULL ) , & error_ctx , SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER , calling_func ) {
throw ss : : SSException ( ) ;
}
h - > set_func ( calling_func ) ;
}
catch ( core : : CoreException & ) {
return NULL ;
}
catch ( . . . ) {
DIE ( " %1!s!: Unknown exception caught in process_params. " , calling_func ) ;
}
return h ;
}
# endif /* PHP_SQLSRV_INT_H */