Enable compiling extensions statically into PHP (#904)
This commit is contained in:
parent
d4f840f630
commit
4efb54e45a
|
@ -95,4 +95,3 @@ if test "$PHP_PDO_SQLSRV" != "no"; then
|
|||
PHP_ADD_EXTENSION_DEP(pdo_sqlsrv, pdo)
|
||||
PHP_ADD_BUILD_DIR([$ext_builddir/shared], 1)
|
||||
fi
|
||||
|
||||
|
|
|
@ -17,7 +17,11 @@
|
|||
// IN THE SOFTWARE.
|
||||
//---------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
#include "php_pdo_sqlsrv.h"
|
||||
extern "C" {
|
||||
#include "php_pdo_sqlsrv.h"
|
||||
}
|
||||
|
||||
#include "php_pdo_sqlsrv_int.h"
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
|
|
@ -17,12 +17,18 @@
|
|||
// IN THE SOFTWARE.
|
||||
//---------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
#include "php_pdo_sqlsrv.h"
|
||||
extern "C" {
|
||||
#include "php_pdo_sqlsrv.h"
|
||||
}
|
||||
|
||||
#include "php_pdo_sqlsrv_int.h"
|
||||
|
||||
#ifdef COMPILE_DL_PDO_SQLSRV
|
||||
#ifdef ZTS
|
||||
ZEND_TSRMLS_CACHE_DEFINE();
|
||||
#endif
|
||||
ZEND_GET_MODULE(g_pdo_sqlsrv)
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
|
||||
|
@ -308,3 +314,23 @@ namespace {
|
|||
{ NULL , 0 } // terminate the table
|
||||
};
|
||||
}
|
||||
|
||||
// DllMain for the extension.
|
||||
#ifdef _WIN32
|
||||
// Only needed if extension is built shared
|
||||
#ifdef COMPILE_DL_PDO_SQLSRV
|
||||
BOOL WINAPI DllMain( _In_ HINSTANCE hinstDLL, _In_ DWORD fdwReason, LPVOID )
|
||||
{
|
||||
switch( fdwReason ) {
|
||||
case DLL_PROCESS_ATTACH:
|
||||
// store the module handle for use by client_info and server_info
|
||||
g_sqlsrv_hmodule = hinstDLL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -19,7 +19,11 @@
|
|||
// IN THE SOFTWARE.
|
||||
//---------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
#include "php_pdo_sqlsrv.h"
|
||||
extern "C" {
|
||||
#include "php_pdo_sqlsrv.h"
|
||||
}
|
||||
|
||||
#include "php_pdo_sqlsrv_int.h"
|
||||
|
||||
// Constructor
|
||||
conn_string_parser:: conn_string_parser( _In_ sqlsrv_context& ctx, _In_ const char* dsn, _In_ int len, _In_ HashTable* conn_options_ht )
|
||||
|
|
|
@ -17,7 +17,11 @@
|
|||
// IN THE SOFTWARE.
|
||||
//---------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
#include "php_pdo_sqlsrv.h"
|
||||
extern "C" {
|
||||
#include "php_pdo_sqlsrv.h"
|
||||
}
|
||||
|
||||
#include "php_pdo_sqlsrv_int.h"
|
||||
|
||||
// *** internal variables and constants ***
|
||||
|
||||
|
|
|
@ -17,7 +17,11 @@
|
|||
// IN THE SOFTWARE.
|
||||
//---------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
#include "php_pdo_sqlsrv.h"
|
||||
extern "C" {
|
||||
#include "php_pdo_sqlsrv.h"
|
||||
}
|
||||
|
||||
#include "php_pdo_sqlsrv_int.h"
|
||||
|
||||
#include "zend_exceptions.h"
|
||||
|
||||
|
|
|
@ -20,55 +20,12 @@
|
|||
// 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>
|
||||
|
||||
|
||||
//*********************************************************************************************************************************
|
||||
// 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,
|
||||
SQLSRV_ATTR_DECIMAL_PLACES
|
||||
};
|
||||
|
||||
// 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";
|
||||
}
|
||||
#include "php.h"
|
||||
|
||||
//*********************************************************************************************************************************
|
||||
// Global variables
|
||||
//*********************************************************************************************************************************
|
||||
|
||||
extern "C" {
|
||||
|
||||
// request level variables
|
||||
ZEND_BEGIN_MODULE_GLOBALS(pdo_sqlsrv)
|
||||
|
||||
|
@ -79,32 +36,6 @@ ZEND_END_MODULE_GLOBALS(pdo_sqlsrv)
|
|||
|
||||
ZEND_EXTERN_MODULE_GLOBALS(pdo_sqlsrv);
|
||||
|
||||
}
|
||||
|
||||
// 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"
|
||||
#define INI_PREFIX "pdo_sqlsrv."
|
||||
|
||||
PHP_INI_BEGIN()
|
||||
STD_PHP_INI_ENTRY( INI_PREFIX INI_PDO_SQLSRV_LOG , "0", PHP_INI_ALL, OnUpdateLong, log_severity,
|
||||
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 )
|
||||
PHP_INI_END()
|
||||
|
||||
// henv context for creating connections
|
||||
extern sqlsrv_context* g_pdo_henv_cp;
|
||||
extern sqlsrv_context* g_pdo_henv_ncp;
|
||||
|
||||
|
||||
//*********************************************************************************************************************************
|
||||
// Initialization
|
||||
|
@ -128,309 +59,4 @@ PHP_MINFO_FUNCTION(pdo_sqlsrv);
|
|||
|
||||
extern zend_module_entry g_pdo_sqlsrv_module_entry; // describes the extension to PHP
|
||||
|
||||
// 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);
|
||||
void add_key_value_pair( _In_reads_(len) const char* value, _In_ int len TSRMLS_DC );
|
||||
};
|
||||
|
||||
//*********************************************************************************************************************************
|
||||
// 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 );
|
||||
void validate_key( _In_reads_(key_len) const char *key, _Inout_ int key_len TSRMLS_DC);
|
||||
|
||||
protected:
|
||||
void add_key_value_pair( _In_reads_(len) const char* value, _In_ int len TSRMLS_DC);
|
||||
|
||||
public:
|
||||
conn_string_parser( _In_ sqlsrv_context& ctx, _In_ const char* dsn, _In_ int len, _In_ HashTable* conn_options_ht );
|
||||
void parse_conn_string( TSRMLS_D );
|
||||
};
|
||||
|
||||
//*********************************************************************************************************************************
|
||||
// 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:
|
||||
void add_key_int_value_pair( _In_ unsigned int value TSRMLS_DC );
|
||||
sql_string_parser(_In_ sqlsrv_context& ctx, _In_ const char* sql_str, _In_ int len, _In_ HashTable* placeholder_ht);
|
||||
void parse_sql_string(TSRMLS_D);
|
||||
};
|
||||
|
||||
//*********************************************************************************************************************************
|
||||
// Connection
|
||||
//*********************************************************************************************************************************
|
||||
extern const connection_option PDO_CONN_OPTS[];
|
||||
|
||||
int pdo_sqlsrv_db_handle_factory( _Inout_ pdo_dbh_t *dbh, _In_opt_ zval *driver_options TSRMLS_DC);
|
||||
|
||||
// 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;
|
||||
|
||||
pdo_sqlsrv_dbh( _In_ SQLHANDLE h, _In_ error_callback e, _In_ void* driver TSRMLS_DC );
|
||||
};
|
||||
|
||||
|
||||
//*********************************************************************************************************************************
|
||||
// Statement
|
||||
//*********************************************************************************************************************************
|
||||
|
||||
struct stmt_option_encoding : public stmt_option_functor {
|
||||
|
||||
virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC );
|
||||
};
|
||||
|
||||
struct stmt_option_pdo_scrollable : public stmt_option_functor {
|
||||
|
||||
virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC );
|
||||
};
|
||||
|
||||
struct stmt_option_direct_query : public stmt_option_functor {
|
||||
|
||||
virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC );
|
||||
};
|
||||
|
||||
struct stmt_option_cursor_scroll_type : public stmt_option_functor {
|
||||
|
||||
virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC );
|
||||
};
|
||||
|
||||
struct stmt_option_emulate_prepares : public stmt_option_functor {
|
||||
|
||||
virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC );
|
||||
};
|
||||
|
||||
struct stmt_option_fetch_numeric : public stmt_option_functor {
|
||||
virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC );
|
||||
};
|
||||
|
||||
struct stmt_option_fetch_datetime : public stmt_option_functor {
|
||||
virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC );
|
||||
};
|
||||
|
||||
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 {
|
||||
|
||||
pdo_sqlsrv_stmt( _In_ sqlsrv_conn* c, _In_ SQLHANDLE handle, _In_ error_callback e, _In_ void* drv TSRMLS_DC ) :
|
||||
sqlsrv_stmt( c, handle, e, drv TSRMLS_CC ),
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
bool pdo_sqlsrv_handle_env_error( _Inout_ sqlsrv_context& ctx, _In_opt_ unsigned int sqlsrv_error_code, _In_opt_ bool warning TSRMLS_DC,
|
||||
_In_opt_ va_list* print_args );
|
||||
bool pdo_sqlsrv_handle_dbh_error( _Inout_ sqlsrv_context& ctx, _In_opt_ unsigned int sqlsrv_error_code, _In_opt_ bool warning TSRMLS_DC,
|
||||
_In_opt_ va_list* print_args );
|
||||
bool pdo_sqlsrv_handle_stmt_error( _Inout_ sqlsrv_context& ctx, _In_opt_ unsigned int sqlsrv_error_code, _In_opt_ bool warning TSRMLS_DC,
|
||||
_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
|
||||
inline void pdo_reset_dbh_error( _Inout_ pdo_dbh_t* dbh TSRMLS_DC )
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
#define PDO_RESET_DBH_ERROR pdo_reset_dbh_error( dbh TSRMLS_CC );
|
||||
|
||||
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,
|
||||
PDO_SQLSRV_ERROR_CE_EMULATE_PREPARE_UNSUPPORTED
|
||||
};
|
||||
|
||||
extern pdo_error PDO_ERRORS[];
|
||||
|
||||
#define THROW_PDO_ERROR( ctx, custom, ... ) \
|
||||
call_error_handler( ctx, custom TSRMLS_CC, false, ## __VA_ARGS__ ); \
|
||||
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
|
||||
|
||||
// logger for pdo_sqlsrv called by the core layer when it wants to log something with the LOG macro
|
||||
void pdo_sqlsrv_log( _In_opt_ unsigned int severity TSRMLS_DC, _In_opt_ const char* msg, _In_opt_ va_list* print_args );
|
||||
|
||||
#endif /* PHP_PDO_SQLSRV_H */
|
||||
|
||||
|
|
409
source/pdo_sqlsrv/php_pdo_sqlsrv_int.h
Normal file
409
source/pdo_sqlsrv/php_pdo_sqlsrv_int.h
Normal file
|
@ -0,0 +1,409 @@
|
|||
#ifndef PHP_PDO_SQLSRV_INT_H
|
||||
#define PHP_PDO_SQLSRV_INT_H
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------------------
|
||||
// File: php_pdo_sqlsrv_int.h
|
||||
//
|
||||
// Contents: Internal declarations for the extension
|
||||
//
|
||||
// Microsoft Drivers 5.5 for PHP for SQL Server
|
||||
// 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"
|
||||
#define INI_PREFIX "pdo_sqlsrv."
|
||||
|
||||
PHP_INI_BEGIN()
|
||||
STD_PHP_INI_ENTRY( INI_PREFIX INI_PDO_SQLSRV_LOG , "0", PHP_INI_ALL, OnUpdateLong, log_severity,
|
||||
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 )
|
||||
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,
|
||||
SQLSRV_ATTR_DECIMAL_PLACES
|
||||
};
|
||||
|
||||
// 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);
|
||||
void add_key_value_pair( _In_reads_(len) const char* value, _In_ int len TSRMLS_DC );
|
||||
};
|
||||
|
||||
|
||||
//*********************************************************************************************************************************
|
||||
// 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 );
|
||||
void validate_key( _In_reads_(key_len) const char *key, _Inout_ int key_len TSRMLS_DC);
|
||||
|
||||
protected:
|
||||
void add_key_value_pair( _In_reads_(len) const char* value, _In_ int len TSRMLS_DC);
|
||||
|
||||
public:
|
||||
conn_string_parser( _In_ sqlsrv_context& ctx, _In_ const char* dsn, _In_ int len, _In_ HashTable* conn_options_ht );
|
||||
void parse_conn_string( TSRMLS_D );
|
||||
};
|
||||
|
||||
|
||||
//*********************************************************************************************************************************
|
||||
// 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:
|
||||
void add_key_int_value_pair( _In_ unsigned int value TSRMLS_DC );
|
||||
sql_string_parser(_In_ sqlsrv_context& ctx, _In_ const char* sql_str, _In_ int len, _In_ HashTable* placeholder_ht);
|
||||
void parse_sql_string(TSRMLS_D);
|
||||
};
|
||||
|
||||
|
||||
//*********************************************************************************************************************************
|
||||
// Connection
|
||||
//*********************************************************************************************************************************
|
||||
|
||||
extern const connection_option PDO_CONN_OPTS[];
|
||||
|
||||
int pdo_sqlsrv_db_handle_factory( _Inout_ pdo_dbh_t *dbh, _In_opt_ zval *driver_options TSRMLS_DC);
|
||||
|
||||
// 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;
|
||||
|
||||
pdo_sqlsrv_dbh( _In_ SQLHANDLE h, _In_ error_callback e, _In_ void* driver TSRMLS_DC );
|
||||
};
|
||||
|
||||
|
||||
//*********************************************************************************************************************************
|
||||
// Statement
|
||||
//*********************************************************************************************************************************
|
||||
|
||||
struct stmt_option_encoding : public stmt_option_functor {
|
||||
|
||||
virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC );
|
||||
};
|
||||
|
||||
struct stmt_option_pdo_scrollable : public stmt_option_functor {
|
||||
|
||||
virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC );
|
||||
};
|
||||
|
||||
struct stmt_option_direct_query : public stmt_option_functor {
|
||||
|
||||
virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC );
|
||||
};
|
||||
|
||||
struct stmt_option_cursor_scroll_type : public stmt_option_functor {
|
||||
|
||||
virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC );
|
||||
};
|
||||
|
||||
struct stmt_option_emulate_prepares : public stmt_option_functor {
|
||||
|
||||
virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC );
|
||||
};
|
||||
|
||||
struct stmt_option_fetch_numeric : public stmt_option_functor {
|
||||
virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC );
|
||||
};
|
||||
|
||||
struct stmt_option_fetch_datetime : public stmt_option_functor {
|
||||
virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC );
|
||||
};
|
||||
|
||||
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 {
|
||||
|
||||
pdo_sqlsrv_stmt( _In_ sqlsrv_conn* c, _In_ SQLHANDLE handle, _In_ error_callback e, _In_ void* drv TSRMLS_DC ) :
|
||||
sqlsrv_stmt( c, handle, e, drv TSRMLS_CC ),
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
bool pdo_sqlsrv_handle_env_error( _Inout_ sqlsrv_context& ctx, _In_opt_ unsigned int sqlsrv_error_code, _In_opt_ bool warning TSRMLS_DC,
|
||||
_In_opt_ va_list* print_args );
|
||||
bool pdo_sqlsrv_handle_dbh_error( _Inout_ sqlsrv_context& ctx, _In_opt_ unsigned int sqlsrv_error_code, _In_opt_ bool warning TSRMLS_DC,
|
||||
_In_opt_ va_list* print_args );
|
||||
bool pdo_sqlsrv_handle_stmt_error( _Inout_ sqlsrv_context& ctx, _In_opt_ unsigned int sqlsrv_error_code, _In_opt_ bool warning TSRMLS_DC,
|
||||
_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
|
||||
inline void pdo_reset_dbh_error( _Inout_ pdo_dbh_t* dbh TSRMLS_DC )
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
#define PDO_RESET_DBH_ERROR pdo_reset_dbh_error( dbh TSRMLS_CC );
|
||||
|
||||
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,
|
||||
PDO_SQLSRV_ERROR_CE_EMULATE_PREPARE_UNSUPPORTED
|
||||
};
|
||||
|
||||
extern pdo_error PDO_ERRORS[];
|
||||
|
||||
#define THROW_PDO_ERROR( ctx, custom, ... ) \
|
||||
call_error_handler( ctx, custom TSRMLS_CC, false, ## __VA_ARGS__ ); \
|
||||
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
|
||||
|
||||
// logger for pdo_sqlsrv called by the core layer when it wants to log something with the LOG macro
|
||||
void pdo_sqlsrv_log( _In_opt_ unsigned int severity TSRMLS_DC, _In_opt_ const char* msg, _In_opt_ va_list* print_args );
|
||||
|
||||
|
||||
#endif /* PHP_PDO_SQLSRV_INT_H */
|
|
@ -159,20 +159,3 @@ void core_sqlsrv_mshutdown( _Inout_ sqlsrv_context& henv_cp, _Inout_ sqlsrv_cont
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
// DllMain for the extension.
|
||||
#ifdef _WIN32
|
||||
BOOL WINAPI DllMain( _In_ HINSTANCE hinstDLL, _In_ DWORD fdwReason, LPVOID )
|
||||
{
|
||||
switch( fdwReason ) {
|
||||
case DLL_PROCESS_ATTACH:
|
||||
// store the module handle for use by client_info and server_info
|
||||
g_sqlsrv_hmodule = hinstDLL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -40,7 +40,10 @@ if test "$PHP_SQLSRV" != "no"; then
|
|||
shared/StringFunctions.cpp \
|
||||
"
|
||||
AC_MSG_CHECKING([for SQLSRV headers])
|
||||
if test -f $srcdir/ext/sqlsrv/shared/core_sqlsrv.h; then
|
||||
if test -f $srcdir/ext/pdo_sqlsrv/shared/core_sqlsrv.h && test "$PHP_PDO_SQLSRV" != "no"; then
|
||||
pdo_sqlsrv_inc_path=$srcdir/ext/pdo_sqlsrv/shared/
|
||||
shared_src_class=""
|
||||
elif 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/
|
||||
|
|
|
@ -27,7 +27,9 @@ if( PHP_SQLSRV != "no" ) {
|
|||
if (CHECK_LIB("odbc32.lib", "sqlsrv") && CHECK_LIB("odbccp32.lib", "sqlsrv") &&
|
||||
CHECK_LIB("version.lib", "sqlsrv") && CHECK_LIB("psapi.lib", "sqlsrv")&&
|
||||
CHECK_HEADER_ADD_INCLUDE( "core_sqlsrv.h", "CFLAGS_SQLSRV", configure_module_dirname + "\\shared")) {
|
||||
ADD_SOURCES( configure_module_dirname + "\\shared", shared_src_class, "sqlsrv" );
|
||||
if (PHP_PDO_SQLSRV == "no" || PHP_SQLSRV_SHARED) {
|
||||
ADD_SOURCES( configure_module_dirname + "\\shared", shared_src_class, "sqlsrv" );
|
||||
}
|
||||
CHECK_HEADER_ADD_INCLUDE("sql.h", "CFLAGS_SQLSRV_ODBC");
|
||||
CHECK_HEADER_ADD_INCLUDE("sqlext.h", "CFLAGS_SQLSRV_ODBC");
|
||||
ADD_FLAG( "LDFLAGS_SQLSRV", "/NXCOMPAT /DYNAMICBASE /debug /guard:cf" );
|
||||
|
|
|
@ -17,7 +17,11 @@
|
|||
// IN THE SOFTWARE.
|
||||
//---------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
#include "php_sqlsrv.h"
|
||||
extern "C" {
|
||||
#include "php_sqlsrv.h"
|
||||
}
|
||||
|
||||
#include "php_sqlsrv_int.h"
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
|
|
@ -16,12 +16,18 @@
|
|||
// IN THE SOFTWARE.
|
||||
//---------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
#include "php_sqlsrv.h"
|
||||
extern "C" {
|
||||
#include "php_sqlsrv.h"
|
||||
}
|
||||
|
||||
#include "php_sqlsrv_int.h"
|
||||
|
||||
#ifdef COMPILE_DL_SQLSRV
|
||||
#ifdef ZTS
|
||||
ZEND_TSRMLS_CACHE_DEFINE();
|
||||
#endif
|
||||
ZEND_GET_MODULE(g_sqlsrv)
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
|
||||
|
@ -685,3 +691,23 @@ PHP_MINFO_FUNCTION(sqlsrv)
|
|||
php_info_print_table_end();
|
||||
DISPLAY_INI_ENTRIES();
|
||||
}
|
||||
|
||||
// DllMain for the extension.
|
||||
#ifdef _WIN32
|
||||
// Only needed if extension is built shared
|
||||
#ifdef COMPILE_DL_SQLSRV
|
||||
BOOL WINAPI DllMain( _In_ HINSTANCE hinstDLL, _In_ DWORD fdwReason, LPVOID )
|
||||
{
|
||||
switch( fdwReason ) {
|
||||
case DLL_PROCESS_ATTACH:
|
||||
// store the module handle for use by client_info and server_info
|
||||
g_sqlsrv_hmodule = hinstDLL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -22,248 +22,12 @@
|
|||
// IN THE SOFTWARE.
|
||||
//---------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
#include "core_sqlsrv.h"
|
||||
#include "version.h"
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef PHP_WIN32
|
||||
#define PHP_SQLSRV_API __declspec(dllexport)
|
||||
#else
|
||||
#define PHP_SQLSRV_API
|
||||
#endif
|
||||
|
||||
// OACR is an internal Microsoft static code analysis tool
|
||||
#if defined(OACR)
|
||||
#include <oacr.h>
|
||||
OACR_WARNING_PUSH
|
||||
OACR_WARNING_DISABLE( ALLOC_SIZE_OVERFLOW, "Third party code." )
|
||||
OACR_WARNING_DISABLE( INDEX_NEGATIVE, "Third party code." )
|
||||
OACR_WARNING_DISABLE( UNANNOTATED_BUFFER, "Third party code." )
|
||||
OACR_WARNING_DISABLE( INDEX_UNDERFLOW, "Third party code." )
|
||||
OACR_WARNING_DISABLE( REALLOCLEAK, "Third party code." )
|
||||
#endif
|
||||
|
||||
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"
|
||||
#endif
|
||||
|
||||
#if _MSC_VER >= 1400
|
||||
// typedef and macro to prevent a conflict between php.h and ws2tcpip.h.
|
||||
// php.h defines this constant as unsigned int which causes a compile error
|
||||
// in ws2tcpip.h. Fortunately php.h allows an override by defining
|
||||
// HAVE_SOCKLEN_T. Since ws2tcpip.h isn't included until later, we define
|
||||
// socklen_t here and override the php.h version.
|
||||
typedef int socklen_t;
|
||||
#define HAVE_SOCKLEN_T
|
||||
#endif
|
||||
|
||||
#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
|
||||
#endif
|
||||
|
||||
#if ZEND_DEBUG
|
||||
// debug build causes warning C4505 to pop up from the Zend header files
|
||||
#pragma warning( disable: 4505 )
|
||||
#endif
|
||||
|
||||
} // extern "C"
|
||||
|
||||
//*********************************************************************************************************************************
|
||||
// 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;
|
||||
|
||||
// variables set during initialization
|
||||
extern zend_module_entry g_sqlsrv_module_entry; // describes the extension to PHP
|
||||
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;
|
||||
|
||||
extern bool isVistaOrGreater; // used to determine if OS is Vista or Greater
|
||||
|
||||
#define phpext_sqlsrv_ptr &g_sqlsrv_module_entry
|
||||
|
||||
// module initialization
|
||||
PHP_MINIT_FUNCTION(sqlsrv);
|
||||
// module shutdown function
|
||||
PHP_MSHUTDOWN_FUNCTION(sqlsrv);
|
||||
// request initialization function
|
||||
PHP_RINIT_FUNCTION(sqlsrv);
|
||||
// request shutdown function
|
||||
PHP_RSHUTDOWN_FUNCTION(sqlsrv);
|
||||
// module info function (info returned by phpinfo())
|
||||
PHP_MINFO_FUNCTION(sqlsrv);
|
||||
|
||||
//*********************************************************************************************************************************
|
||||
// Connection
|
||||
//*********************************************************************************************************************************
|
||||
PHP_FUNCTION(sqlsrv_connect);
|
||||
PHP_FUNCTION(sqlsrv_begin_transaction);
|
||||
PHP_FUNCTION(sqlsrv_client_info);
|
||||
PHP_FUNCTION(sqlsrv_close);
|
||||
PHP_FUNCTION(sqlsrv_commit);
|
||||
PHP_FUNCTION(sqlsrv_query);
|
||||
PHP_FUNCTION(sqlsrv_prepare);
|
||||
PHP_FUNCTION(sqlsrv_rollback);
|
||||
PHP_FUNCTION(sqlsrv_server_info);
|
||||
|
||||
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
|
||||
ss_sqlsrv_conn( _In_ SQLHANDLE h, _In_ error_callback e, _In_ void* drv TSRMLS_DC ) :
|
||||
sqlsrv_conn( h, e, drv, SQLSRV_ENCODING_SYSTEM TSRMLS_CC ),
|
||||
stmts( NULL ),
|
||||
date_as_string( false ),
|
||||
format_decimals( false ),
|
||||
decimal_places( NO_CHANGE_DECIMAL_PLACES ),
|
||||
in_transaction( false )
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// resource destructor
|
||||
void __cdecl sqlsrv_conn_dtor( _Inout_ zend_resource *rsrc TSRMLS_DC );
|
||||
|
||||
//*********************************************************************************************************************************
|
||||
// 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 {
|
||||
|
||||
virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC );
|
||||
};
|
||||
|
||||
// This object inherits and overrides the callbacks necessary
|
||||
struct ss_sqlsrv_stmt : public sqlsrv_stmt {
|
||||
|
||||
ss_sqlsrv_stmt( _In_ sqlsrv_conn* c, _In_ SQLHANDLE handle, _In_ error_callback e, _In_ void* drv TSRMLS_DC );
|
||||
|
||||
virtual ~ss_sqlsrv_stmt( void );
|
||||
|
||||
void new_result_set( TSRMLS_D );
|
||||
|
||||
// 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)
|
||||
zend_ulong conn_index; // index into the connection hash that contains this statement structure
|
||||
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 )
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// *** statement functions ***
|
||||
PHP_FUNCTION(sqlsrv_cancel);
|
||||
PHP_FUNCTION(sqlsrv_execute);
|
||||
PHP_FUNCTION(sqlsrv_fetch);
|
||||
PHP_FUNCTION(sqlsrv_fetch_array);
|
||||
PHP_FUNCTION(sqlsrv_fetch_object);
|
||||
PHP_FUNCTION(sqlsrv_field_metadata);
|
||||
PHP_FUNCTION(sqlsrv_free_stmt);
|
||||
PHP_FUNCTION(sqlsrv_get_field);
|
||||
PHP_FUNCTION(sqlsrv_has_rows);
|
||||
PHP_FUNCTION(sqlsrv_next_result);
|
||||
PHP_FUNCTION(sqlsrv_num_fields);
|
||||
PHP_FUNCTION(sqlsrv_num_rows);
|
||||
PHP_FUNCTION(sqlsrv_rows_affected);
|
||||
PHP_FUNCTION(sqlsrv_send_stream_data);
|
||||
|
||||
// resource destructor
|
||||
void __cdecl sqlsrv_stmt_dtor( _Inout_ zend_resource *rsrc TSRMLS_DC );
|
||||
|
||||
// "internal" statement functions shared by functions in conn.cpp and stmt.cpp
|
||||
void bind_params( _Inout_ ss_sqlsrv_stmt* stmt TSRMLS_DC );
|
||||
bool sqlsrv_stmt_common_execute( sqlsrv_stmt* s, const SQLCHAR* sql_string, int sql_len, bool direct, const char* function
|
||||
TSRMLS_DC );
|
||||
void free_odbc_resources( ss_sqlsrv_stmt* stmt TSRMLS_DC );
|
||||
void free_stmt_resource( _Inout_ zval* stmt_z TSRMLS_DC );
|
||||
|
||||
//*********************************************************************************************************************************
|
||||
// Type Functions
|
||||
//*********************************************************************************************************************************
|
||||
|
||||
// type functions for SQL types.
|
||||
// to expose SQL Server paramterized types, we use functions that return encoded integers that contain the size/precision etc.
|
||||
// for example, SQLSRV_SQLTYPE_VARCHAR(4000) matches the usage of SQLSRV_SQLTYPE_INT with the size added.
|
||||
PHP_FUNCTION(SQLSRV_SQLTYPE_BINARY);
|
||||
PHP_FUNCTION(SQLSRV_SQLTYPE_CHAR);
|
||||
PHP_FUNCTION(SQLSRV_SQLTYPE_DECIMAL);
|
||||
PHP_FUNCTION(SQLSRV_SQLTYPE_NCHAR);
|
||||
PHP_FUNCTION(SQLSRV_SQLTYPE_NUMERIC);
|
||||
PHP_FUNCTION(SQLSRV_SQLTYPE_NVARCHAR);
|
||||
PHP_FUNCTION(SQLSRV_SQLTYPE_VARBINARY);
|
||||
PHP_FUNCTION(SQLSRV_SQLTYPE_VARCHAR);
|
||||
|
||||
// PHP type functions
|
||||
// strings and streams may have an encoding parameterized, so we use the functions
|
||||
// the valid encodings are SQLSRV_ENC_BINARY and SQLSRV_ENC_CHAR.
|
||||
PHP_FUNCTION(SQLSRV_PHPTYPE_STREAM);
|
||||
PHP_FUNCTION(SQLSRV_PHPTYPE_STRING);
|
||||
#include "php.h"
|
||||
|
||||
//*********************************************************************************************************************************
|
||||
// Global variables
|
||||
//*********************************************************************************************************************************
|
||||
|
||||
extern "C" {
|
||||
|
||||
// request level variables
|
||||
ZEND_BEGIN_MODULE_GLOBALS(sqlsrv)
|
||||
|
||||
|
@ -282,8 +46,6 @@ ZEND_END_MODULE_GLOBALS(sqlsrv)
|
|||
|
||||
ZEND_EXTERN_MODULE_GLOBALS(sqlsrv);
|
||||
|
||||
}
|
||||
|
||||
// macro used to access the global variables. Use it to make global variable access agnostic to threads
|
||||
#define SQLSRV_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(sqlsrv, v)
|
||||
|
||||
|
@ -291,335 +53,83 @@ ZEND_EXTERN_MODULE_GLOBALS(sqlsrv);
|
|||
ZEND_TSRMLS_CACHE_EXTERN();
|
||||
#endif
|
||||
|
||||
// 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."
|
||||
|
||||
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 )
|
||||
PHP_INI_END()
|
||||
|
||||
//*********************************************************************************************************************************
|
||||
// Configuration
|
||||
// Initialization Functions
|
||||
//*********************************************************************************************************************************
|
||||
|
||||
// variables set during initialization
|
||||
extern zend_module_entry g_sqlsrv_module_entry; // describes the extension to PHP
|
||||
|
||||
#define phpext_sqlsrv_ptr &g_sqlsrv_module_entry
|
||||
|
||||
// module initialization
|
||||
PHP_MINIT_FUNCTION(sqlsrv);
|
||||
// module shutdown function
|
||||
PHP_MSHUTDOWN_FUNCTION(sqlsrv);
|
||||
// request initialization function
|
||||
PHP_RINIT_FUNCTION(sqlsrv);
|
||||
// request shutdown function
|
||||
PHP_RSHUTDOWN_FUNCTION(sqlsrv);
|
||||
// module info function (info returned by phpinfo())
|
||||
PHP_MINFO_FUNCTION(sqlsrv);
|
||||
|
||||
|
||||
//*********************************************************************************************************************************
|
||||
// Functions
|
||||
//*********************************************************************************************************************************
|
||||
|
||||
PHP_FUNCTION(sqlsrv_connect);
|
||||
PHP_FUNCTION(sqlsrv_begin_transaction);
|
||||
PHP_FUNCTION(sqlsrv_client_info);
|
||||
PHP_FUNCTION(sqlsrv_close);
|
||||
PHP_FUNCTION(sqlsrv_commit);
|
||||
PHP_FUNCTION(sqlsrv_query);
|
||||
PHP_FUNCTION(sqlsrv_prepare);
|
||||
PHP_FUNCTION(sqlsrv_rollback);
|
||||
PHP_FUNCTION(sqlsrv_server_info);
|
||||
|
||||
PHP_FUNCTION(sqlsrv_cancel);
|
||||
PHP_FUNCTION(sqlsrv_execute);
|
||||
PHP_FUNCTION(sqlsrv_fetch);
|
||||
PHP_FUNCTION(sqlsrv_fetch_array);
|
||||
PHP_FUNCTION(sqlsrv_fetch_object);
|
||||
PHP_FUNCTION(sqlsrv_field_metadata);
|
||||
PHP_FUNCTION(sqlsrv_free_stmt);
|
||||
PHP_FUNCTION(sqlsrv_get_field);
|
||||
PHP_FUNCTION(sqlsrv_has_rows);
|
||||
PHP_FUNCTION(sqlsrv_next_result);
|
||||
PHP_FUNCTION(sqlsrv_num_fields);
|
||||
PHP_FUNCTION(sqlsrv_num_rows);
|
||||
PHP_FUNCTION(sqlsrv_rows_affected);
|
||||
PHP_FUNCTION(sqlsrv_send_stream_data);
|
||||
|
||||
// type functions for SQL types.
|
||||
// to expose SQL Server paramterized types, we use functions that return encoded integers that contain the size/precision etc.
|
||||
// for example, SQLSRV_SQLTYPE_VARCHAR(4000) matches the usage of SQLSRV_SQLTYPE_INT with the size added.
|
||||
PHP_FUNCTION(SQLSRV_SQLTYPE_BINARY);
|
||||
PHP_FUNCTION(SQLSRV_SQLTYPE_CHAR);
|
||||
PHP_FUNCTION(SQLSRV_SQLTYPE_DECIMAL);
|
||||
PHP_FUNCTION(SQLSRV_SQLTYPE_NCHAR);
|
||||
PHP_FUNCTION(SQLSRV_SQLTYPE_NUMERIC);
|
||||
PHP_FUNCTION(SQLSRV_SQLTYPE_NVARCHAR);
|
||||
PHP_FUNCTION(SQLSRV_SQLTYPE_VARBINARY);
|
||||
PHP_FUNCTION(SQLSRV_SQLTYPE_VARCHAR);
|
||||
|
||||
// PHP type functions
|
||||
// strings and streams may have an encoding parameterized, so we use the functions
|
||||
// the valid encodings are SQLSRV_ENC_BINARY and SQLSRV_ENC_CHAR.
|
||||
PHP_FUNCTION(SQLSRV_PHPTYPE_STREAM);
|
||||
PHP_FUNCTION(SQLSRV_PHPTYPE_STRING);
|
||||
|
||||
// These functions set and retrieve configuration settings. Configuration settings defined are:
|
||||
// WarningsReturnAsErrors - treat all ODBC warnings as errors and return false from sqlsrv APIs.
|
||||
// LogSeverity - combination of severity of messages to log (see Logging)
|
||||
// LogSubsystems - subsystems within sqlsrv to log messages (see Logging)
|
||||
|
||||
PHP_FUNCTION(sqlsrv_configure);
|
||||
PHP_FUNCTION(sqlsrv_get_config);
|
||||
|
||||
//*********************************************************************************************************************************
|
||||
// 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_INVALID_AUTHENTICATION_OPTION,
|
||||
SS_SQLSRV_ERROR_AE_QUERY_SQLTYPE_REQUIRED
|
||||
};
|
||||
|
||||
extern ss_error SS_ERRORS[];
|
||||
|
||||
bool ss_error_handler( _Inout_ sqlsrv_context& ctx, _In_ unsigned int sqlsrv_error_code, _In_ bool warning TSRMLS_DC, _In_opt_ va_list* print_args );
|
||||
|
||||
// *** extension error functions ***
|
||||
PHP_FUNCTION(sqlsrv_errors);
|
||||
|
||||
// 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,
|
||||
_In_ unsigned int utf16_len );
|
||||
// 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,
|
||||
_In_ unsigned int mbcs_len, _Out_ unsigned int* utf16_len );
|
||||
|
||||
// *** internal error macros and functions ***
|
||||
bool handle_error( sqlsrv_context const* ctx, int log_subsystem, const char* function,
|
||||
sqlsrv_error const* ssphp TSRMLS_DC, ... );
|
||||
void handle_warning( sqlsrv_context const* ctx, int log_subsystem, const char* function,
|
||||
sqlsrv_error const* ssphp TSRMLS_DC, ... );
|
||||
void __cdecl sqlsrv_error_dtor( zend_resource *rsrc TSRMLS_DC );
|
||||
|
||||
// release current error lists and set to NULL
|
||||
inline void reset_errors( TSRMLS_D )
|
||||
{
|
||||
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, ... ) \
|
||||
(void)call_error_handler( ctx, error_code TSRMLS_CC, false /*warning*/, ## __VA_ARGS__ ); \
|
||||
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; \
|
||||
LOG( SEV_NOTICE, "%1!s!: entering", _FN_ );
|
||||
|
||||
#define SET_FUNCTION_NAME( context ) \
|
||||
{ \
|
||||
(context).set_func( _FN_ ); \
|
||||
}
|
||||
|
||||
// logger for ss_sqlsrv called by the core layer when it wants to log something with the LOG macro
|
||||
void ss_sqlsrv_log( _In_ unsigned int severity TSRMLS_DC, _In_opt_ const char* msg, _In_opt_ va_list* print_args );
|
||||
|
||||
// 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()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
inline void zend_register_resource( _Inout_ zval& rsrc_result, _Inout_ void* rsrc_pointer, _In_ int rsrc_type, _In_opt_ const 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<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, ... )
|
||||
{
|
||||
SQLSRV_UNUSED( return_value );
|
||||
|
||||
zval* rsrc;
|
||||
H* h;
|
||||
|
||||
// reset the errors from the previous API call
|
||||
reset_errors( TSRMLS_C );
|
||||
|
||||
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:
|
||||
result = zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>( param_spec ), &rsrc );
|
||||
break;
|
||||
|
||||
case 1:
|
||||
result = zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>( param_spec ), &rsrc, arr[0] );
|
||||
break;
|
||||
|
||||
case 2:
|
||||
result = zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>( param_spec ), &rsrc, arr[0],
|
||||
arr[1] );
|
||||
break;
|
||||
|
||||
case 3:
|
||||
result = zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>( param_spec ), &rsrc, arr[0],
|
||||
arr[1], arr[2] );
|
||||
break;
|
||||
|
||||
case 4:
|
||||
result = zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>( param_spec ), &rsrc, arr[0],
|
||||
arr[1], arr[2], arr[3] );
|
||||
break;
|
||||
|
||||
case 5:
|
||||
result = zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>( param_spec ), &rsrc, arr[0],
|
||||
arr[1], arr[2], arr[3], arr[4] );
|
||||
break;
|
||||
|
||||
case 6:
|
||||
result = zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>( param_spec ), &rsrc, arr[0],
|
||||
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
|
||||
h = static_cast<H*>( zend_fetch_resource(Z_RES_P(rsrc) TSRMLS_CC, H::resource_name, H::descriptor ));
|
||||
|
||||
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_H */
|
||||
|
|
468
source/sqlsrv/php_sqlsrv_int.h
Normal file
468
source/sqlsrv/php_sqlsrv_int.h
Normal file
|
@ -0,0 +1,468 @@
|
|||
#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.
|
||||
//
|
||||
// Microsoft Drivers 5.5 for PHP for SQL Server
|
||||
// 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."
|
||||
|
||||
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 )
|
||||
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
|
||||
ss_sqlsrv_conn( _In_ SQLHANDLE h, _In_ error_callback e, _In_ void* drv TSRMLS_DC ) :
|
||||
sqlsrv_conn( h, e, drv, SQLSRV_ENCODING_SYSTEM TSRMLS_CC ),
|
||||
stmts( NULL ),
|
||||
date_as_string( false ),
|
||||
format_decimals( false ),
|
||||
decimal_places( NO_CHANGE_DECIMAL_PLACES ),
|
||||
in_transaction( false )
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// resource destructor
|
||||
void __cdecl sqlsrv_conn_dtor( _Inout_ zend_resource *rsrc TSRMLS_DC );
|
||||
|
||||
|
||||
//*********************************************************************************************************************************
|
||||
// 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 {
|
||||
|
||||
virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC );
|
||||
};
|
||||
|
||||
// This object inherits and overrides the callbacks necessary
|
||||
struct ss_sqlsrv_stmt : public sqlsrv_stmt {
|
||||
|
||||
ss_sqlsrv_stmt( _In_ sqlsrv_conn* c, _In_ SQLHANDLE handle, _In_ error_callback e, _In_ void* drv TSRMLS_DC );
|
||||
|
||||
virtual ~ss_sqlsrv_stmt( void );
|
||||
|
||||
void new_result_set( TSRMLS_D );
|
||||
|
||||
// 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)
|
||||
zend_ulong conn_index; // index into the connection hash that contains this statement structure
|
||||
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
|
||||
void __cdecl sqlsrv_stmt_dtor( _Inout_ zend_resource *rsrc TSRMLS_DC );
|
||||
|
||||
// "internal" statement functions shared by functions in conn.cpp and stmt.cpp
|
||||
void bind_params( _Inout_ ss_sqlsrv_stmt* stmt TSRMLS_DC );
|
||||
bool sqlsrv_stmt_common_execute( sqlsrv_stmt* s, const SQLCHAR* sql_string, int sql_len, bool direct, const char* function
|
||||
TSRMLS_DC );
|
||||
void free_odbc_resources( ss_sqlsrv_stmt* stmt TSRMLS_DC );
|
||||
void free_stmt_resource( _Inout_ zval* stmt_z TSRMLS_DC );
|
||||
|
||||
|
||||
//*********************************************************************************************************************************
|
||||
// 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_INVALID_AUTHENTICATION_OPTION,
|
||||
SS_SQLSRV_ERROR_AE_QUERY_SQLTYPE_REQUIRED
|
||||
};
|
||||
|
||||
extern ss_error SS_ERRORS[];
|
||||
|
||||
bool ss_error_handler( _Inout_ sqlsrv_context& ctx, _In_ unsigned int sqlsrv_error_code, _In_ bool warning TSRMLS_DC, _In_opt_ va_list* print_args );
|
||||
|
||||
// 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,
|
||||
_In_ unsigned int utf16_len );
|
||||
// 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,
|
||||
_In_ unsigned int mbcs_len, _Out_ unsigned int* utf16_len );
|
||||
|
||||
// *** internal error macros and functions ***
|
||||
bool handle_error( sqlsrv_context const* ctx, int log_subsystem, const char* function,
|
||||
sqlsrv_error const* ssphp TSRMLS_DC, ... );
|
||||
void handle_warning( sqlsrv_context const* ctx, int log_subsystem, const char* function,
|
||||
sqlsrv_error const* ssphp TSRMLS_DC, ... );
|
||||
void __cdecl sqlsrv_error_dtor( zend_resource *rsrc TSRMLS_DC );
|
||||
|
||||
// release current error lists and set to NULL
|
||||
inline void reset_errors( TSRMLS_D )
|
||||
{
|
||||
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, ... ) \
|
||||
(void)call_error_handler( ctx, error_code TSRMLS_CC, false /*warning*/, ## __VA_ARGS__ ); \
|
||||
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; \
|
||||
LOG( SEV_NOTICE, "%1!s!: entering", _FN_ );
|
||||
|
||||
#define SET_FUNCTION_NAME( context ) \
|
||||
{ \
|
||||
(context).set_func( _FN_ ); \
|
||||
}
|
||||
|
||||
// logger for ss_sqlsrv called by the core layer when it wants to log something with the LOG macro
|
||||
void ss_sqlsrv_log( _In_ unsigned int severity TSRMLS_DC, _In_opt_ const char* msg, _In_opt_ va_list* print_args );
|
||||
|
||||
// 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()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
inline void zend_register_resource( _Inout_ zval& rsrc_result, _Inout_ void* rsrc_pointer, _In_ int rsrc_type, _In_opt_ const 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<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, ... )
|
||||
{
|
||||
SQLSRV_UNUSED( return_value );
|
||||
|
||||
zval* rsrc;
|
||||
H* h;
|
||||
|
||||
// reset the errors from the previous API call
|
||||
reset_errors( TSRMLS_C );
|
||||
|
||||
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:
|
||||
result = zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>( param_spec ), &rsrc );
|
||||
break;
|
||||
|
||||
case 1:
|
||||
result = zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>( param_spec ), &rsrc, arr[0] );
|
||||
break;
|
||||
|
||||
case 2:
|
||||
result = zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>( param_spec ), &rsrc, arr[0],
|
||||
arr[1] );
|
||||
break;
|
||||
|
||||
case 3:
|
||||
result = zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>( param_spec ), &rsrc, arr[0],
|
||||
arr[1], arr[2] );
|
||||
break;
|
||||
|
||||
case 4:
|
||||
result = zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>( param_spec ), &rsrc, arr[0],
|
||||
arr[1], arr[2], arr[3] );
|
||||
break;
|
||||
|
||||
case 5:
|
||||
result = zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>( param_spec ), &rsrc, arr[0],
|
||||
arr[1], arr[2], arr[3], arr[4] );
|
||||
break;
|
||||
|
||||
case 6:
|
||||
result = zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>( param_spec ), &rsrc, arr[0],
|
||||
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
|
||||
h = static_cast<H*>( zend_fetch_resource(Z_RES_P(rsrc) TSRMLS_CC, H::resource_name, H::descriptor ));
|
||||
|
||||
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 */
|
|
@ -18,7 +18,12 @@
|
|||
//---------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// *** header files ***
|
||||
#include "php_sqlsrv.h"
|
||||
extern "C" {
|
||||
#include "php_sqlsrv.h"
|
||||
}
|
||||
|
||||
#include "php_sqlsrv_int.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <sal.h>
|
||||
#endif // _WIN32
|
||||
|
|
|
@ -19,7 +19,11 @@
|
|||
// IN THE SOFTWARE.
|
||||
//---------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
#include "php_sqlsrv.h"
|
||||
extern "C" {
|
||||
#include "php_sqlsrv.h"
|
||||
}
|
||||
|
||||
#include "php_sqlsrv_int.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
|
Loading…
Reference in a new issue