2018-12-20 20:49:06 +01:00
# ifndef PHP_PDO_SQLSRV_INT_H
# define PHP_PDO_SQLSRV_INT_H
//---------------------------------------------------------------------------------------------------------------------------------
// File: php_pdo_sqlsrv_int.h
//
// Contents: Internal declarations for the extension
//
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"
extern " C " {
# include "pdo/php_pdo.h"
# include "pdo/php_pdo_driver.h"
}
# include <vector>
# include <map>
//*********************************************************************************************************************************
// Global variables
//*********************************************************************************************************************************
// henv context for creating connections
extern sqlsrv_context * g_pdo_henv_cp ;
extern sqlsrv_context * g_pdo_henv_ncp ;
// used for getting the version information
extern HMODULE g_sqlsrv_hmodule ;
// macros used to access the global variables. Use these to make global variable access agnostic to threads
# ifdef ZTS
# define PDO_SQLSRV_G(v) TSRMG(pdo_sqlsrv_globals_id, zend_pdo_sqlsrv_globals *, v)
# else
# define PDO_SQLSRV_G(v) pdo_sqlsrv_globals.v
# endif
// INI settings and constants
// (these are defined as macros to allow concatenation as we do below)
# define INI_PDO_SQLSRV_CLIENT_BUFFER_MAX_SIZE "client_buffer_max_kb_size"
# define INI_PDO_SQLSRV_LOG "log_severity"
2020-05-23 00:09:28 +02:00
# define INI_PDO_SQLSRV_MORE_ERRORS "report_additional_errors"
2018-12-20 20:49:06 +01:00
# define INI_PREFIX "pdo_sqlsrv."
2019-12-19 20:03:25 +01:00
# ifndef _WIN32
# define INI_PDO_SET_LOCALE_INFO "set_locale_info"
# endif
2018-12-20 20:49:06 +01:00
PHP_INI_BEGIN ( )
2020-03-25 17:53:18 +01:00
STD_PHP_INI_ENTRY ( INI_PREFIX INI_PDO_SQLSRV_LOG , " 0 " , PHP_INI_ALL , OnUpdateLong , pdo_log_severity ,
2018-12-20 20:49:06 +01:00
zend_pdo_sqlsrv_globals , pdo_sqlsrv_globals )
STD_PHP_INI_ENTRY ( INI_PREFIX INI_PDO_SQLSRV_CLIENT_BUFFER_MAX_SIZE , INI_BUFFERED_QUERY_LIMIT_DEFAULT , PHP_INI_ALL , OnUpdateLong ,
client_buffer_max_size , zend_pdo_sqlsrv_globals , pdo_sqlsrv_globals )
2020-05-23 00:09:28 +02:00
STD_PHP_INI_ENTRY ( INI_PREFIX INI_PDO_SQLSRV_MORE_ERRORS , " 1 " , PHP_INI_ALL , OnUpdateLong , report_additional_errors , zend_pdo_sqlsrv_globals , pdo_sqlsrv_globals )
2019-12-19 20:03:25 +01:00
# ifndef _WIN32
STD_PHP_INI_ENTRY ( INI_PREFIX INI_PDO_SET_LOCALE_INFO , " 2 " , PHP_INI_ALL , OnUpdateLong , set_locale_info ,
zend_pdo_sqlsrv_globals , pdo_sqlsrv_globals )
# endif
2018-12-20 20:49:06 +01:00
PHP_INI_END ( )
//*********************************************************************************************************************************
// Constants and Types
//*********************************************************************************************************************************
// sqlsrv driver specific PDO attributes
enum PDO_SQLSRV_ATTR {
// The custom attributes for this driver:
SQLSRV_ATTR_ENCODING = PDO_ATTR_DRIVER_SPECIFIC ,
SQLSRV_ATTR_QUERY_TIMEOUT ,
SQLSRV_ATTR_DIRECT_QUERY ,
SQLSRV_ATTR_CURSOR_SCROLL_TYPE ,
SQLSRV_ATTR_CLIENT_BUFFER_MAX_KB_SIZE ,
SQLSRV_ATTR_FETCHES_NUMERIC_TYPE ,
SQLSRV_ATTR_FETCHES_DATETIME_TYPE ,
SQLSRV_ATTR_FORMAT_DECIMALS ,
2019-05-01 17:03:33 +02:00
SQLSRV_ATTR_DECIMAL_PLACES ,
SQLSRV_ATTR_DATA_CLASSIFICATION
2018-12-20 20:49:06 +01:00
} ;
// valid set of values for TransactionIsolation connection option
namespace PDOTxnIsolationValues {
const char READ_UNCOMMITTED [ ] = " READ_UNCOMMITTED " ;
const char READ_COMMITTED [ ] = " READ_COMMITTED " ;
const char REPEATABLE_READ [ ] = " REPEATABLE_READ " ;
const char SERIALIZABLE [ ] = " SERIALIZABLE " ;
const char SNAPSHOT [ ] = " SNAPSHOT " ;
}
//*********************************************************************************************************************************
// Initialization
//*********************************************************************************************************************************
// Basic string parser
class string_parser
{
protected :
const char * orig_str ;
sqlsrv_context * ctx ;
int len ;
int pos ;
unsigned int current_key ;
HashTable * element_ht ;
inline bool next ( void ) ;
inline bool is_eos ( void ) ;
inline bool is_white_space ( _In_ char c ) ;
bool discard_white_spaces ( void ) ;
2020-04-21 00:17:21 +02:00
void add_key_value_pair ( _In_reads_ ( len ) const char * value , _In_ int len ) ;
2018-12-20 20:49:06 +01:00
} ;
//*********************************************************************************************************************************
// PDO DSN Parser
//*********************************************************************************************************************************
// Parser class used to parse DSN connection string.
class conn_string_parser : private string_parser
{
enum States
{
FirstKeyValuePair ,
Key ,
Value ,
ValueContent1 ,
ValueContent2 ,
RCBEncountered ,
NextKeyValuePair ,
} ;
private :
const char * current_key_name ;
int discard_trailing_white_spaces ( _In_reads_ ( len ) const char * str , _Inout_ int len ) ;
2020-04-21 00:17:21 +02:00
void validate_key ( _In_reads_ ( key_len ) const char * key , _Inout_ int key_len ) ;
2018-12-20 20:49:06 +01:00
2019-10-24 00:12:52 +02:00
protected :
2020-04-21 00:17:21 +02:00
void add_key_value_pair ( _In_reads_ ( len ) const char * value , _In_ int len ) ;
2018-12-20 20:49:06 +01:00
public :
conn_string_parser ( _In_ sqlsrv_context & ctx , _In_ const char * dsn , _In_ int len , _In_ HashTable * conn_options_ht ) ;
2020-04-21 00:17:21 +02:00
void parse_conn_string ( void ) ;
2018-12-20 20:49:06 +01:00
} ;
//*********************************************************************************************************************************
// PDO Query Parser
//*********************************************************************************************************************************
// Parser class used to parse DSN named placeholders.
class sql_string_parser : private string_parser
{
private :
bool is_placeholder_char ( char ) ;
public :
2020-04-21 00:17:21 +02:00
void add_key_int_value_pair ( _In_ unsigned int value ) ;
2018-12-20 20:49:06 +01:00
sql_string_parser ( _In_ sqlsrv_context & ctx , _In_ const char * sql_str , _In_ int len , _In_ HashTable * placeholder_ht ) ;
2020-04-21 00:17:21 +02:00
void parse_sql_string ( void ) ;
2018-12-20 20:49:06 +01:00
} ;
//*********************************************************************************************************************************
// Connection
//*********************************************************************************************************************************
extern const connection_option PDO_CONN_OPTS [ ] ;
2020-04-21 00:17:21 +02:00
int pdo_sqlsrv_db_handle_factory ( _Inout_ pdo_dbh_t * dbh , _In_opt_ zval * driver_options ) ;
2018-12-20 20:49:06 +01:00
// a core layer pdo dbh object. This object inherits and overrides the statement factory
struct pdo_sqlsrv_dbh : public sqlsrv_conn {
zval * stmts ;
bool direct_query ;
long query_timeout ;
zend_long client_buffer_max_size ;
bool fetch_numeric ;
bool fetch_datetime ;
bool format_decimals ;
short decimal_places ;
2019-10-24 00:12:52 +02:00
short use_national_characters ;
2021-11-02 16:12:09 +01:00
bool emulate_prepare ;
2018-12-20 20:49:06 +01:00
2020-04-21 00:17:21 +02:00
pdo_sqlsrv_dbh ( _In_ SQLHANDLE h , _In_ error_callback e , _In_ void * driver ) ;
2018-12-20 20:49:06 +01:00
} ;
//*********************************************************************************************************************************
// Statement
//*********************************************************************************************************************************
struct stmt_option_encoding : 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
} ;
struct stmt_option_pdo_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
} ;
struct stmt_option_direct_query : 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
} ;
struct stmt_option_cursor_scroll_type : 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
} ;
struct stmt_option_emulate_prepares : 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
} ;
struct stmt_option_fetch_numeric : 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
} ;
struct stmt_option_fetch_datetime : 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
} ;
extern struct pdo_stmt_methods pdo_sqlsrv_stmt_methods ;
// a core layer pdo stmt object. This object inherits and overrides the callbacks necessary
struct pdo_sqlsrv_stmt : public sqlsrv_stmt {
2020-04-21 00:17:21 +02:00
pdo_sqlsrv_stmt ( _In_ sqlsrv_conn * c , _In_ SQLHANDLE handle , _In_ error_callback e , _In_ void * drv ) :
sqlsrv_stmt ( c , handle , e , drv ) ,
2018-12-20 20:49:06 +01:00
direct_query ( false ) ,
direct_query_subst_string ( NULL ) ,
direct_query_subst_string_len ( 0 ) ,
placeholders ( NULL ) ,
bound_column_param_types ( NULL ) ,
fetch_numeric ( false ) ,
fetch_datetime ( false )
{
pdo_sqlsrv_dbh * db = static_cast < pdo_sqlsrv_dbh * > ( c ) ;
direct_query = db - > direct_query ;
fetch_numeric = db - > fetch_numeric ;
fetch_datetime = db - > fetch_datetime ;
format_decimals = db - > format_decimals ;
decimal_places = db - > decimal_places ;
2019-09-18 16:49:14 +02:00
query_timeout = db - > query_timeout ;
2018-12-20 20:49:06 +01:00
}
virtual ~ pdo_sqlsrv_stmt ( void ) ;
// driver specific conversion rules from a SQL Server/ODBC type to one of the SQLSRV_PHPTYPE_* constants
// for PDO, everything is a string, so we return SQLSRV_PHPTYPE_STRING for all SQL types
virtual sqlsrv_phptype sql_type_to_php_type ( _In_ SQLINTEGER sql_type , _In_ SQLUINTEGER size , _In_ bool prefer_string_to_stream ) ;
bool direct_query ; // flag set if the query should be executed directly or prepared
const char * direct_query_subst_string ; // if the query is direct, hold the substitution string if using named parameters
size_t direct_query_subst_string_len ; // length of query string used for direct queries
HashTable * placeholders ; // hashtable of named placeholders to keep track of params ordering in emulate prepare
pdo_param_type * bound_column_param_types ;
bool fetch_numeric ;
bool fetch_datetime ;
} ;
//*********************************************************************************************************************************
// Error Handling Functions
//*********************************************************************************************************************************
// represents the mapping between an error_code and the corresponding error message.
struct pdo_error {
unsigned int error_code ;
sqlsrv_error_const sqlsrv_error ;
} ;
// called when an error occurs in the core layer. These routines are set as the error_callback in a
// context. The context is passed to this function since it contains the function
2020-10-17 00:17:58 +02:00
bool pdo_sqlsrv_handle_env_error ( _Inout_ sqlsrv_context & ctx , _In_opt_ unsigned int sqlsrv_error_code , _In_opt_ int warning ,
2018-12-20 20:49:06 +01:00
_In_opt_ va_list * print_args ) ;
2020-10-17 00:17:58 +02:00
bool pdo_sqlsrv_handle_dbh_error ( _Inout_ sqlsrv_context & ctx , _In_opt_ unsigned int sqlsrv_error_code , _In_opt_ int warning ,
2018-12-20 20:49:06 +01:00
_In_opt_ va_list * print_args ) ;
2020-10-17 00:17:58 +02:00
bool pdo_sqlsrv_handle_stmt_error ( _Inout_ sqlsrv_context & ctx , _In_opt_ unsigned int sqlsrv_error_code , _In_opt_ int warning ,
2018-12-20 20:49:06 +01:00
_In_opt_ va_list * print_args ) ;
// common routine to transfer a sqlsrv_context's error to a PDO zval
void pdo_sqlsrv_retrieve_context_error ( _In_ sqlsrv_error const * last_error , _Out_ zval * pdo_zval ) ;
// reset the errors from the last operation
2020-04-21 00:17:21 +02:00
inline void pdo_reset_dbh_error ( _Inout_ pdo_dbh_t * dbh )
2018-12-20 20:49:06 +01:00
{
strcpy_s ( dbh - > error_code , sizeof ( dbh - > error_code ) , " 00000 " ) ; // 00000 means no error
// release the last statement from the dbh so that error handling won't have a statement passed to it
if ( dbh - > query_stmt ) {
dbh - > query_stmt = NULL ;
zval_ptr_dtor ( & dbh - > query_stmt_zval ) ;
}
// if the driver isn't valid, just return (PDO calls close sometimes more than once?)
if ( dbh - > driver_data = = NULL ) {
return ;
}
// reset the last error on the sqlsrv_context
sqlsrv_context * ctx = static_cast < sqlsrv_conn * > ( dbh - > driver_data ) ;
if ( ctx - > last_error ( ) ) {
ctx - > last_error ( ) . reset ( ) ;
}
}
2020-03-25 17:53:18 +01:00
# define PDO_LOG_NOTICE(message) \
core_sqlsrv_register_severity_checker ( pdo_severity_check ) ; \
LOG ( SEV_NOTICE , message ) ;
2020-04-21 00:17:21 +02:00
# define PDO_RESET_DBH_ERROR pdo_reset_dbh_error( dbh );
2018-12-20 20:49:06 +01:00
inline void pdo_reset_stmt_error ( _Inout_ pdo_stmt_t * stmt )
{
strcpy_s ( stmt - > error_code , sizeof ( stmt - > error_code ) , " 00000 " ) ; // 00000 means no error
// if the driver isn't valid, just return (PDO calls close sometimes more than once?)
if ( stmt - > driver_data = = NULL ) {
return ;
}
// reset the last error on the sqlsrv_context
sqlsrv_context * ctx = static_cast < sqlsrv_stmt * > ( stmt - > driver_data ) ;
if ( ctx - > last_error ( ) ) {
ctx - > last_error ( ) . reset ( ) ;
}
}
# define PDO_RESET_STMT_ERROR pdo_reset_stmt_error( stmt );
// validate the driver objects
# define PDO_VALIDATE_CONN if( dbh->driver_data == NULL ) { DIE( "Invalid driver data in PDO object." ); }
# define PDO_VALIDATE_STMT if( stmt->driver_data == NULL ) { DIE( "Invalid driver data in PDOStatement object." ); }
//*********************************************************************************************************************************
// Utility Functions
//*********************************************************************************************************************************
// List of PDO specific error messages.
enum PDO_ERROR_CODES {
PDO_SQLSRV_ERROR_INVALID_DBH_ATTR = SQLSRV_ERROR_DRIVER_SPECIFIC ,
PDO_SQLSRV_ERROR_INVALID_STMT_ATTR ,
PDO_SQLSRV_ERROR_INVALID_ENCODING ,
PDO_SQLSRV_ERROR_INVALID_DRIVER_PARAM ,
PDO_SQLSRV_ERROR_PDO_STMT_UNSUPPORTED ,
PDO_SQLSRV_ERROR_UNSUPPORTED_DBH_ATTR ,
PDO_SQLSRV_ERROR_STMT_LEVEL_ATTR ,
PDO_SQLSRV_ERROR_READ_ONLY_DBH_ATTR ,
PDO_SQLSRV_ERROR_INVALID_STMT_OPTION ,
PDO_SQLSRV_ERROR_INVALID_CURSOR_TYPE ,
PDO_SQLSRV_ERROR_FUNCTION_NOT_IMPLEMENTED ,
PDO_SQLSRV_ERROR_PARAM_PARSE ,
PDO_SQLSRV_ERROR_LAST_INSERT_ID ,
PDO_SQLSRV_ERROR_INVALID_COLUMN_DRIVER_DATA ,
PDO_SQLSRV_ERROR_COLUMN_TYPE_DOES_NOT_SUPPORT_ENCODING ,
PDO_SQLSRV_ERROR_INVALID_DRIVER_COLUMN_ENCODING ,
PDO_SQLSRV_ERROR_INVALID_DRIVER_PARAM_TYPE ,
PDO_SQLSRV_ERROR_INVALID_DRIVER_PARAM_ENCODING ,
PDO_SQLSRV_ERROR_INVALID_PARAM_DIRECTION ,
PDO_SQLSRV_ERROR_INVALID_OUTPUT_STRING_SIZE ,
PDO_SQLSRV_ERROR_CURSOR_ATTR_AT_PREPARE_ONLY ,
PDO_SQLSRV_ERROR_INVALID_DSN_STRING ,
PDO_SQLSRV_ERROR_INVALID_DSN_KEY ,
PDO_SQLSRV_ERROR_INVALID_DSN_VALUE ,
PDO_SQLSRV_ERROR_SERVER_NOT_SPECIFIED ,
PDO_SQLSRV_ERROR_DSN_STRING_ENDED_UNEXPECTEDLY ,
PDO_SQLSRV_ERROR_EXTRA_SEMI_COLON_IN_DSN_STRING ,
SQLSRV_ERROR_UNESCAPED_RIGHT_BRACE_IN_DSN ,
PDO_SQLSRV_ERROR_RCB_MISSING_IN_DSN_VALUE ,
PDO_SQLSRV_ERROR_DQ_ATTR_AT_PREPARE_ONLY ,
PDO_SQLSRV_ERROR_INVALID_COLUMN_INDEX ,
PDO_SQLSRV_ERROR_INVALID_OUTPUT_PARAM_TYPE ,
PDO_SQLSRV_ERROR_INVALID_CURSOR_WITH_SCROLL_TYPE ,
PDO_SQLSRV_ERROR_EMULATE_INOUT_UNSUPPORTED ,
PDO_SQLSRV_ERROR_INVALID_AUTHENTICATION_OPTION ,
PDO_SQLSRV_ERROR_CE_DIRECT_QUERY_UNSUPPORTED ,
2019-10-24 00:12:52 +02:00
PDO_SQLSRV_ERROR_CE_EMULATE_PREPARE_UNSUPPORTED ,
PDO_SQLSRV_ERROR_EXTENDED_STRING_TYPE_INVALID
2018-12-20 20:49:06 +01:00
} ;
extern pdo_error PDO_ERRORS [ ] ;
# define THROW_PDO_ERROR( ctx, custom, ... ) \
2020-04-21 00:17:21 +02:00
call_error_handler ( ctx , custom , false , # # __VA_ARGS__ ) ; \
2018-12-20 20:49:06 +01:00
throw pdo : : PDOException ( ) ;
namespace pdo {
// an error which occurred in our PDO driver, NOT an exception thrown by PDO
struct PDOException : public core : : CoreException {
PDOException ( ) : CoreException ( )
{
}
} ;
} // namespace pdo
2020-03-25 17:53:18 +01:00
// check the global variable of pdo_sqlsrv severity whether the message qualifies to be logged with the LOG macro
2020-04-21 00:17:21 +02:00
bool pdo_severity_check ( _In_ unsigned int severity ) ;
2018-12-20 20:49:06 +01:00
# endif /* PHP_PDO_SQLSRV_INT_H */