2016-01-30 03:00:20 +01:00
//---------------------------------------------------------------------------------------------------------------------------------
// File: conn.cpp
//
// Contents: Routines that use connection handles
//
2021-09-08 02:38:17 +02:00
// Microsoft Drivers 5.10 for PHP for SQL Server
2016-01-30 03:00:20 +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.
//---------------------------------------------------------------------------------------------------------------------------------
2018-12-20 20:49:06 +01:00
extern " C " {
# include "php_sqlsrv.h"
}
# include "php_sqlsrv_int.h"
2017-01-19 17:17:45 +01:00
2016-01-30 03:00:20 +01:00
# include <string>
# include <sstream>
// *** internal variables and constants ***
namespace {
2021-05-19 01:56:49 +02:00
const int MAX_CONN_VALSTRING_LEN = 256 ;
2016-01-30 03:00:20 +01:00
// current subsytem. defined for the CHECK_SQL_{ERROR|WARNING} macros
unsigned int current_log_subsystem = LOG_CONN ;
struct date_as_string_func {
2020-04-21 00:17:21 +02:00
static void func ( connection_option const * /*option*/ , _In_ zval * value , _Inout_ sqlsrv_conn * conn , std : : string & /*conn_str*/ )
2016-01-30 03:00:20 +01:00
{
ss_sqlsrv_conn * ss_conn = static_cast < ss_sqlsrv_conn * > ( conn ) ;
2021-05-19 01:56:49 +02:00
ss_conn - > date_as_string = zend_is_true ( value ) ;
2016-01-30 03:00:20 +01:00
}
} ;
2018-11-28 02:18:38 +01:00
struct format_decimals_func
{
2020-04-21 00:17:21 +02:00
static void func ( connection_option const * /*option*/ , _In_ zval * value , _Inout_ sqlsrv_conn * conn , std : : string & /*conn_str*/ )
2018-11-28 02:18:38 +01:00
{
ss_sqlsrv_conn * ss_conn = static_cast < ss_sqlsrv_conn * > ( conn ) ;
2021-05-19 01:56:49 +02:00
ss_conn - > format_decimals = zend_is_true ( value ) ;
2018-11-28 02:18:38 +01:00
}
} ;
struct decimal_places_func
{
2020-04-21 00:17:21 +02:00
static void func ( connection_option const * /*option*/ , _In_ zval * value , _Inout_ sqlsrv_conn * conn , std : : string & /*conn_str*/ )
2018-11-28 02:18:38 +01:00
{
// first check if the input is an integer
if ( Z_TYPE_P ( value ) ! = IS_LONG ) {
THROW_SS_ERROR ( conn , SQLSRV_ERROR_INVALID_DECIMAL_PLACES ) ;
}
zend_long decimal_places = Z_LVAL_P ( value ) ;
if ( decimal_places < 0 | | decimal_places > SQL_SERVER_MAX_MONEY_SCALE ) {
decimal_places = NO_CHANGE_DECIMAL_PLACES ;
}
ss_sqlsrv_conn * ss_conn = static_cast < ss_sqlsrv_conn * > ( conn ) ;
ss_conn - > decimal_places = static_cast < short > ( decimal_places ) ;
}
} ;
2021-12-07 01:40:41 +01:00
struct srv_encrypt_set_func {
static void func ( connection_option const * option , _In_ zval * value_z , _Inout_ sqlsrv_conn * conn , std : : string & conn_str )
{
std : : string attr ;
if ( Z_TYPE_P ( value_z ) = = IS_LONG ) {
long val = Z_LVAL_P ( value_z ) ;
if ( val = = 1 ) {
attr = " yes " ;
} else if ( val = = 0 ) {
attr = " no " ;
} else {
attr = std : : to_string ( val ) ;
}
} else if ( Z_TYPE_P ( value_z ) = = IS_TRUE | | Z_TYPE_P ( value_z ) = = IS_FALSE ) {
attr = zend_is_true ( value_z ) ? " yes " : " no " ;
} else {
attr = Z_STRVAL_P ( value_z ) ;
}
char temp_str [ MAX_CONN_VALSTRING_LEN ] ;
snprintf ( temp_str , MAX_CONN_VALSTRING_LEN , " %s={%s}; " , option - > odbc_name , attr . c_str ( ) ) ;
conn_str + = temp_str ;
}
} ;
2016-01-30 03:00:20 +01:00
struct conn_char_set_func {
2020-04-21 00:17:21 +02:00
static void func ( connection_option const * /*option*/ , _Inout_ zval * value , _Inout_ sqlsrv_conn * conn , std : : string & /*conn_str*/ )
2016-01-30 03:00:20 +01:00
{
convert_to_string ( value ) ;
const char * encoding = Z_STRVAL_P ( value ) ;
2016-03-15 04:09:46 +01:00
size_t encoding_len = Z_STRLEN_P ( value ) ;
2016-01-30 03:00:20 +01:00
2017-05-06 02:17:52 +02:00
zend_ulong index = - 1 ;
zend_string * key = NULL ;
void * ss_encoding_temp = NULL ;
2016-01-30 03:00:20 +01:00
2017-05-06 02:17:52 +02:00
ZEND_HASH_FOREACH_KEY_PTR ( g_ss_encodings_ht , index , key , ss_encoding_temp ) {
sqlsrv_encoding * ss_encoding = reinterpret_cast < sqlsrv_encoding * > ( ss_encoding_temp ) ;
ss_encoding_temp = NULL ;
if ( ! strnicmp ( encoding , ss_encoding - > iana , encoding_len ) ) {
2016-01-30 03:00:20 +01:00
2017-05-06 02:17:52 +02:00
if ( ss_encoding - > not_for_connection ) {
THROW_SS_ERROR ( conn , SS_SQLSRV_ERROR_CONNECT_ILLEGAL_ENCODING , encoding ) ;
}
2016-01-30 03:00:20 +01:00
2017-05-06 02:17:52 +02:00
conn - > set_encoding ( static_cast < SQLSRV_ENCODING > ( ss_encoding - > code_page ) ) ;
return ;
}
} ZEND_HASH_FOREACH_END ( ) ;
2016-01-30 03:00:20 +01:00
THROW_SS_ERROR ( conn , SS_SQLSRV_ERROR_CONNECT_ILLEGAL_ENCODING , encoding ) ;
}
} ;
struct bool_conn_str_func {
2020-04-21 00:17:21 +02:00
static void func ( _In_ connection_option const * option , _In_ zval * value , sqlsrv_conn * /*conn*/ , _Out_ std : : string & conn_str )
2016-01-30 03:00:20 +01:00
{
2021-05-19 01:56:49 +02:00
char temp_str [ MAX_CONN_VALSTRING_LEN ] ;
snprintf ( temp_str , MAX_CONN_VALSTRING_LEN , " %s={%s}; " , option - > odbc_name , ( zend_is_true ( value ) ? " yes " : " no " ) ) ;
conn_str + = temp_str ;
2016-01-30 03:00:20 +01:00
}
} ;
2017-04-04 22:40:30 +02:00
struct int_conn_str_func {
2020-04-21 00:17:21 +02:00
static void func ( _In_ connection_option const * option , _In_ zval * value , sqlsrv_conn * /*conn*/ , _Out_ std : : string & conn_str )
2017-04-04 22:40:30 +02:00
{
SQLSRV_ASSERT ( Z_TYPE_P ( value ) = = IS_LONG , " An integer is expected for this keyword " )
2021-05-19 01:56:49 +02:00
char temp_str [ MAX_CONN_VALSTRING_LEN ] ;
2021-08-13 19:57:19 +02:00
snprintf ( temp_str , MAX_CONN_VALSTRING_LEN , " %s={%ld}; " , option - > odbc_name , Z_LVAL_P ( value ) ) ;
2021-05-19 01:56:49 +02:00
conn_str + = temp_str ;
2017-04-04 22:40:30 +02:00
}
} ;
2016-01-30 03:00:20 +01:00
template < unsigned int Attr >
struct int_conn_attr_func {
2020-04-21 00:17:21 +02:00
static void func ( connection_option const * /*option*/ , _In_ zval * value , _Inout_ sqlsrv_conn * conn , std : : string & /*conn_str*/ )
2016-01-30 03:00:20 +01:00
{
try {
2020-04-21 00:17:21 +02:00
core : : SQLSetConnectAttr ( conn , Attr , reinterpret_cast < SQLPOINTER > ( Z_LVAL_P ( value ) ) , SQL_IS_UINTEGER ) ;
2016-01-30 03:00:20 +01:00
}
catch ( core : : CoreException & ) {
throw ;
}
}
} ;
template < unsigned int Attr >
struct bool_conn_attr_func {
2020-04-21 00:17:21 +02:00
static void func ( connection_option const * /*option*/ , _In_ zval * value , _Inout_ sqlsrv_conn * conn , std : : string & /*conn_str*/ )
2016-01-30 03:00:20 +01:00
{
try {
2020-04-21 00:17:21 +02:00
core : : SQLSetConnectAttr ( conn , Attr , reinterpret_cast < SQLPOINTER > ( ( zend_long ) zend_is_true ( value ) ) , SQL_IS_UINTEGER ) ;
2016-01-30 03:00:20 +01:00
}
catch ( core : : CoreException & ) {
throw ;
}
}
} ;
//// *** internal functions ***
2020-04-21 00:17:21 +02:00
void sqlsrv_conn_close_stmts ( _Inout_ ss_sqlsrv_conn * conn ) ;
2017-06-22 23:04:34 +02:00
void validate_conn_options ( _Inout_ sqlsrv_context & ctx , _In_ zval * user_options_z , _Inout_ char * * uid , _Inout_ char * * pwd ,
2020-04-21 00:17:21 +02:00
_Inout_ HashTable * ss_conn_options_ht ) ;
void validate_stmt_options ( _Inout_ sqlsrv_context & ctx , _Inout_ zval * stmt_options , _Inout_ HashTable * ss_stmt_options_ht ) ;
2017-06-22 23:04:34 +02:00
void add_conn_option_key ( _Inout_ sqlsrv_context & ctx , _In_ zend_string * key , _In_ size_t key_len ,
2020-04-21 00:17:21 +02:00
_Inout_ HashTable * options_ht , _Inout_ zval * data ) ;
void add_stmt_option_key ( _Inout_ sqlsrv_context & ctx , _In_ zend_string * key , _In_ size_t key_len , _Inout_ HashTable * options_ht , _Inout_ zval * data ) ;
int get_conn_option_key ( _Inout_ sqlsrv_context & ctx , _In_ zend_string * key , _In_ size_t key_len , _Inout_ zval const * value_z ) ;
int get_stmt_option_key ( _In_ zend_string * key , _In_ size_t key_len ) ;
2016-01-30 03:00:20 +01:00
}
// constants for parameters used by process_params function(s)
int ss_sqlsrv_conn : : descriptor ;
2017-02-15 01:52:42 +01:00
const char * ss_sqlsrv_conn : : resource_name = " ss_sqlsrv_conn " ;
2016-01-30 03:00:20 +01:00
// connection specific parameter proccessing. Use the generic function specialised to return a connection
// resource.
# define PROCESS_PARAMS( rsrc, param_spec, calling_func, param_count, ... ) \
2017-01-19 17:17:45 +01:00
rsrc = process_params < ss_sqlsrv_conn > ( INTERNAL_FUNCTION_PARAM_PASSTHRU , param_spec , calling_func , param_count , # # __VA_ARGS__ ) ; \
2016-01-30 03:00:20 +01:00
if ( rsrc = = NULL ) { \
RETURN_FALSE ; \
}
namespace SSStmtOptionNames {
const char QUERY_TIMEOUT [ ] = " QueryTimeout " ;
const char SEND_STREAMS_AT_EXEC [ ] = " SendStreamParamsAtExec " ;
const char SCROLLABLE [ ] = " Scrollable " ;
const char CLIENT_BUFFER_MAX_SIZE [ ] = INI_BUFFERED_QUERY_LIMIT ;
2018-09-18 01:25:02 +02:00
const char DATE_AS_STRING [ ] = " ReturnDatesAsStrings " ;
2018-10-13 00:22:27 +02:00
const char FORMAT_DECIMALS [ ] = " FormatDecimals " ;
2018-11-28 02:18:38 +01:00
const char DECIMAL_PLACES [ ] = " DecimalPlaces " ;
2019-05-01 17:03:33 +02:00
const char DATA_CLASSIFICATION [ ] = " DataClassification " ;
2016-01-30 03:00:20 +01:00
}
namespace SSConnOptionNames {
// most of these strings are the same for both the sqlsrv_connect connection option
// and the name put into the connection string. MARS is the only one that's different.
const char APP [ ] = " APP " ;
2018-09-06 20:32:04 +02:00
const char AccessToken [ ] = " AccessToken " ;
2016-01-30 03:00:20 +01:00
const char ApplicationIntent [ ] = " ApplicationIntent " ;
const char AttachDBFileName [ ] = " AttachDbFileName " ;
2017-05-06 01:28:33 +02:00
const char Authentication [ ] = " Authentication " ;
2018-05-06 02:08:01 +02:00
const char CharacterSet [ ] = " CharacterSet " ;
const char ColumnEncryption [ ] = " ColumnEncryption " ;
2016-01-30 03:00:20 +01:00
const char ConnectionPooling [ ] = " ConnectionPooling " ;
2019-02-13 13:56:12 +01:00
const char Language [ ] = " Language " ;
2017-04-04 22:40:30 +02:00
const char ConnectRetryCount [ ] = " ConnectRetryCount " ;
const char ConnectRetryInterval [ ] = " ConnectRetryInterval " ;
2016-01-30 03:00:20 +01:00
const char Database [ ] = " Database " ;
2018-11-28 02:18:38 +01:00
const char DecimalPlaces [ ] = " DecimalPlaces " ;
const char FormatDecimals [ ] = " FormatDecimals " ;
2016-01-30 03:00:20 +01:00
const char DateAsString [ ] = " ReturnDatesAsStrings " ;
2018-05-06 02:08:01 +02:00
const char Driver [ ] = " Driver " ;
2016-01-30 03:00:20 +01:00
const char Encrypt [ ] = " Encrypt " ;
const char Failover_Partner [ ] = " Failover_Partner " ;
2018-05-06 02:08:01 +02:00
const char KeyStoreAuthentication [ ] = " KeyStoreAuthentication " ;
const char KeyStorePrincipalId [ ] = " KeyStorePrincipalId " ;
const char KeyStoreSecret [ ] = " KeyStoreSecret " ;
2016-01-30 03:00:20 +01:00
const char LoginTimeout [ ] = " LoginTimeout " ;
const char MARS_Option [ ] = " MultipleActiveResultSets " ;
const char MultiSubnetFailover [ ] = " MultiSubnetFailover " ;
const char PWD [ ] = " PWD " ;
const char QuotedId [ ] = " QuotedId " ;
const char TraceFile [ ] = " TraceFile " ;
const char TraceOn [ ] = " TraceOn " ;
const char TrustServerCertificate [ ] = " TrustServerCertificate " ;
const char TransactionIsolation [ ] = " TransactionIsolation " ;
2017-06-07 22:53:04 +02:00
const char TransparentNetworkIPResolution [ ] = " TransparentNetworkIPResolution " ;
2016-01-30 03:00:20 +01:00
const char UID [ ] = " UID " ;
const char WSID [ ] = " WSID " ;
2021-12-08 00:29:03 +01:00
const char ComputePool [ ] = " ComputePool " ;
2022-01-05 17:59:48 +01:00
const char HostNameInCertificate [ ] = " HostNameInCertificate " ;
2016-01-30 03:00:20 +01:00
}
enum SS_CONN_OPTIONS {
SS_CONN_OPTION_DATE_AS_STRING = SQLSRV_CONN_OPTION_DRIVER_SPECIFIC ,
2018-11-28 02:18:38 +01:00
SS_CONN_OPTION_FORMAT_DECIMALS ,
SS_CONN_OPTION_DECIMAL_PLACES ,
2016-01-30 03:00:20 +01:00
} ;
//List of all statement options supported by this driver
const stmt_option SS_STMT_OPTS [ ] = {
{
SSStmtOptionNames : : QUERY_TIMEOUT ,
sizeof ( SSStmtOptionNames : : QUERY_TIMEOUT ) ,
SQLSRV_STMT_OPTION_QUERY_TIMEOUT ,
2017-05-06 02:17:52 +02:00
std : : unique_ptr < stmt_option_query_timeout > ( new stmt_option_query_timeout )
2016-01-30 03:00:20 +01:00
} ,
{
SSStmtOptionNames : : SEND_STREAMS_AT_EXEC ,
sizeof ( SSStmtOptionNames : : SEND_STREAMS_AT_EXEC ) ,
SQLSRV_STMT_OPTION_SEND_STREAMS_AT_EXEC ,
2017-05-06 02:17:52 +02:00
std : : unique_ptr < stmt_option_send_at_exec > ( new stmt_option_send_at_exec )
2016-01-30 03:00:20 +01:00
} ,
{
SSStmtOptionNames : : SCROLLABLE ,
sizeof ( SSStmtOptionNames : : SCROLLABLE ) ,
SQLSRV_STMT_OPTION_SCROLLABLE ,
2017-05-06 02:17:52 +02:00
std : : unique_ptr < stmt_option_ss_scrollable > ( new stmt_option_ss_scrollable )
2016-01-30 03:00:20 +01:00
} ,
{
SSStmtOptionNames : : CLIENT_BUFFER_MAX_SIZE ,
sizeof ( SSStmtOptionNames : : CLIENT_BUFFER_MAX_SIZE ) ,
SQLSRV_STMT_OPTION_CLIENT_BUFFER_MAX_SIZE ,
2017-05-06 02:17:52 +02:00
std : : unique_ptr < stmt_option_buffered_query_limit > ( new stmt_option_buffered_query_limit )
2016-01-30 03:00:20 +01:00
} ,
2018-09-18 01:25:02 +02:00
{
SSStmtOptionNames : : DATE_AS_STRING ,
sizeof ( SSStmtOptionNames : : DATE_AS_STRING ) ,
SQLSRV_STMT_OPTION_DATE_AS_STRING ,
std : : unique_ptr < stmt_option_date_as_string > ( new stmt_option_date_as_string )
} ,
2018-10-13 00:22:27 +02:00
{
SSStmtOptionNames : : FORMAT_DECIMALS ,
sizeof ( SSStmtOptionNames : : FORMAT_DECIMALS ) ,
SQLSRV_STMT_OPTION_FORMAT_DECIMALS ,
std : : unique_ptr < stmt_option_format_decimals > ( new stmt_option_format_decimals )
} ,
2018-11-28 02:18:38 +01:00
{
SSStmtOptionNames : : DECIMAL_PLACES ,
sizeof ( SSStmtOptionNames : : DECIMAL_PLACES ) ,
SQLSRV_STMT_OPTION_DECIMAL_PLACES ,
std : : unique_ptr < stmt_option_decimal_places > ( new stmt_option_decimal_places )
} ,
2019-05-01 17:03:33 +02:00
{
SSStmtOptionNames : : DATA_CLASSIFICATION ,
sizeof ( SSStmtOptionNames : : DATA_CLASSIFICATION ) ,
SQLSRV_STMT_OPTION_DATA_CLASSIFICATION ,
std : : unique_ptr < stmt_option_data_classification > ( new stmt_option_data_classification )
} ,
2016-03-15 04:09:46 +01:00
{ NULL , 0 , SQLSRV_STMT_OPTION_INVALID , std : : unique_ptr < stmt_option_functor > { } } ,
2016-01-30 03:00:20 +01:00
} ;
// List of all connection options supported by this driver.
const connection_option SS_CONN_OPTS [ ] = {
{
SSConnOptionNames : : APP ,
sizeof ( SSConnOptionNames : : APP ) ,
SQLSRV_CONN_OPTION_APP ,
ODBCConnOptions : : APP ,
sizeof ( ODBCConnOptions : : APP ) ,
CONN_ATTR_STRING ,
conn_str_append_func : : func
} ,
2018-09-06 20:32:04 +02:00
{
SSConnOptionNames : : AccessToken ,
sizeof ( SSConnOptionNames : : AccessToken ) ,
SQLSRV_CONN_OPTION_ACCESS_TOKEN ,
ODBCConnOptions : : AccessToken ,
sizeof ( ODBCConnOptions : : AccessToken ) ,
CONN_ATTR_STRING ,
access_token_set_func : : func
} ,
2016-01-30 03:00:20 +01:00
{
SSConnOptionNames : : ApplicationIntent ,
sizeof ( SSConnOptionNames : : ApplicationIntent ) ,
SQLSRV_CONN_OPTION_APPLICATION_INTENT ,
ODBCConnOptions : : ApplicationIntent ,
sizeof ( ODBCConnOptions : : ApplicationIntent ) ,
CONN_ATTR_STRING ,
conn_str_append_func : : func
} ,
{
SSConnOptionNames : : AttachDBFileName ,
sizeof ( SSConnOptionNames : : AttachDBFileName ) ,
SQLSRV_CONN_OPTION_ATTACHDBFILENAME ,
ODBCConnOptions : : AttachDBFileName ,
sizeof ( ODBCConnOptions : : AttachDBFileName ) ,
CONN_ATTR_STRING ,
conn_str_append_func : : func
} ,
{
SSConnOptionNames : : CharacterSet ,
sizeof ( SSConnOptionNames : : CharacterSet ) ,
SQLSRV_CONN_OPTION_CHARACTERSET ,
ODBCConnOptions : : CharacterSet ,
sizeof ( ODBCConnOptions : : CharacterSet ) ,
CONN_ATTR_STRING ,
conn_char_set_func : : func
} ,
2017-05-06 02:17:52 +02:00
{
SSConnOptionNames : : Authentication ,
sizeof ( SSConnOptionNames : : Authentication ) ,
SQLSRV_CONN_OPTION_AUTHENTICATION ,
ODBCConnOptions : : Authentication ,
sizeof ( ODBCConnOptions : : Authentication ) ,
CONN_ATTR_STRING ,
conn_str_append_func : : func
} ,
2017-08-29 22:42:15 +02:00
{
SSConnOptionNames : : ConnectionPooling ,
sizeof ( SSConnOptionNames : : ConnectionPooling ) ,
SQLSRV_CONN_OPTION_CONN_POOLING ,
ODBCConnOptions : : ConnectionPooling ,
sizeof ( ODBCConnOptions : : ConnectionPooling ) ,
CONN_ATTR_BOOL ,
conn_null_func : : func
} ,
2019-02-13 13:56:12 +01:00
{
SSConnOptionNames : : Language ,
sizeof ( SSConnOptionNames : : Language ) ,
SQLSRV_CONN_OPTION_LANGUAGE ,
ODBCConnOptions : : Language ,
sizeof ( ODBCConnOptions : : Language ) ,
CONN_ATTR_STRING ,
conn_str_append_func : : func
} ,
2017-09-12 22:30:14 +02:00
{
SSConnOptionNames : : Driver ,
sizeof ( SSConnOptionNames : : Driver ) ,
SQLSRV_CONN_OPTION_DRIVER ,
ODBCConnOptions : : Driver ,
sizeof ( ODBCConnOptions : : Driver ) ,
CONN_ATTR_STRING ,
driver_set_func : : func
} ,
2017-08-29 22:42:15 +02:00
{
2018-02-08 18:00:16 +01:00
SSConnOptionNames : : ColumnEncryption ,
sizeof ( SSConnOptionNames : : ColumnEncryption ) ,
SQLSRV_CONN_OPTION_COLUMNENCRYPTION ,
ODBCConnOptions : : ColumnEncryption ,
sizeof ( ODBCConnOptions : : ColumnEncryption ) ,
2017-08-29 22:42:15 +02:00
CONN_ATTR_STRING ,
2018-02-08 18:00:16 +01:00
column_encryption_set_func : : func
2017-08-29 22:42:15 +02:00
} ,
2017-04-04 22:40:30 +02:00
{
SSConnOptionNames : : ConnectRetryCount ,
sizeof ( SSConnOptionNames : : ConnectRetryCount ) ,
SQLSRV_CONN_OPTION_CONN_RETRY_COUNT ,
ODBCConnOptions : : ConnectRetryCount ,
sizeof ( ODBCConnOptions : : ConnectRetryCount ) ,
CONN_ATTR_INT ,
int_conn_str_func : : func
} ,
{
SSConnOptionNames : : ConnectRetryInterval ,
sizeof ( SSConnOptionNames : : ConnectRetryInterval ) ,
SQLSRV_CONN_OPTION_CONN_RETRY_INTERVAL ,
ODBCConnOptions : : ConnectRetryInterval ,
sizeof ( ODBCConnOptions : : ConnectRetryInterval ) ,
CONN_ATTR_INT ,
int_conn_str_func : : func
} ,
2016-01-30 03:00:20 +01:00
{
SSConnOptionNames : : Database ,
sizeof ( SSConnOptionNames : : Database ) ,
SQLSRV_CONN_OPTION_DATABASE ,
ODBCConnOptions : : Database ,
sizeof ( ODBCConnOptions : : Database ) ,
CONN_ATTR_STRING ,
conn_str_append_func : : func
} ,
{
SSConnOptionNames : : Encrypt ,
sizeof ( SSConnOptionNames : : Encrypt ) ,
SQLSRV_CONN_OPTION_ENCRYPT ,
ODBCConnOptions : : Encrypt ,
sizeof ( ODBCConnOptions : : Encrypt ) ,
2021-12-07 01:40:41 +01:00
CONN_ATTR_MIXED ,
srv_encrypt_set_func : : func
2016-01-30 03:00:20 +01:00
} ,
{
SSConnOptionNames : : Failover_Partner ,
sizeof ( SSConnOptionNames : : Failover_Partner ) ,
SQLSRV_CONN_OPTION_FAILOVER_PARTNER ,
ODBCConnOptions : : Failover_Partner ,
sizeof ( ODBCConnOptions : : Failover_Partner ) ,
CONN_ATTR_STRING ,
conn_str_append_func : : func
} ,
2018-05-06 02:08:01 +02:00
{
SSConnOptionNames : : KeyStoreAuthentication ,
sizeof ( SSConnOptionNames : : KeyStoreAuthentication ) ,
SQLSRV_CONN_OPTION_KEYSTORE_AUTHENTICATION ,
ODBCConnOptions : : KeyStoreAuthentication ,
sizeof ( ODBCConnOptions : : KeyStoreAuthentication ) ,
CONN_ATTR_STRING ,
ce_akv_str_set_func : : func
} ,
{
SSConnOptionNames : : KeyStorePrincipalId ,
sizeof ( SSConnOptionNames : : KeyStorePrincipalId ) ,
SQLSRV_CONN_OPTION_KEYSTORE_PRINCIPAL_ID ,
ODBCConnOptions : : KeyStorePrincipalId ,
sizeof ( ODBCConnOptions : : KeyStorePrincipalId ) ,
CONN_ATTR_STRING ,
ce_akv_str_set_func : : func
} ,
{
SSConnOptionNames : : KeyStoreSecret ,
sizeof ( SSConnOptionNames : : KeyStoreSecret ) ,
SQLSRV_CONN_OPTION_KEYSTORE_SECRET ,
ODBCConnOptions : : KeyStoreSecret ,
sizeof ( ODBCConnOptions : : KeyStoreSecret ) ,
CONN_ATTR_STRING ,
ce_akv_str_set_func : : func
} ,
2016-01-30 03:00:20 +01:00
{
SSConnOptionNames : : LoginTimeout ,
sizeof ( SSConnOptionNames : : LoginTimeout ) ,
SQLSRV_CONN_OPTION_LOGIN_TIMEOUT ,
ODBCConnOptions : : LoginTimeout ,
sizeof ( ODBCConnOptions : : LoginTimeout ) ,
CONN_ATTR_INT ,
int_conn_attr_func < SQL_ATTR_LOGIN_TIMEOUT > : : func
} ,
{
SSConnOptionNames : : MARS_Option ,
sizeof ( SSConnOptionNames : : MARS_Option ) ,
SQLSRV_CONN_OPTION_MARS ,
ODBCConnOptions : : MARS_ODBC ,
sizeof ( ODBCConnOptions : : MARS_ODBC ) ,
CONN_ATTR_BOOL ,
bool_conn_str_func : : func
} ,
{
SSConnOptionNames : : MultiSubnetFailover ,
sizeof ( SSConnOptionNames : : MultiSubnetFailover ) ,
SQLSRV_CONN_OPTION_MULTI_SUBNET_FAILOVER ,
ODBCConnOptions : : MultiSubnetFailover ,
sizeof ( ODBCConnOptions : : MultiSubnetFailover ) ,
CONN_ATTR_BOOL ,
bool_conn_str_func : : func
} ,
{
SSConnOptionNames : : QuotedId ,
sizeof ( SSConnOptionNames : : QuotedId ) ,
SQLSRV_CONN_OPTION_QUOTED_ID ,
ODBCConnOptions : : QuotedId ,
sizeof ( ODBCConnOptions : : QuotedId ) ,
CONN_ATTR_BOOL ,
bool_conn_str_func : : func
} ,
{
SSConnOptionNames : : TraceFile ,
sizeof ( SSConnOptionNames : : TraceFile ) ,
SQLSRV_CONN_OPTION_TRACE_FILE ,
ODBCConnOptions : : TraceFile ,
sizeof ( ODBCConnOptions : : TraceFile ) ,
CONN_ATTR_STRING ,
str_conn_attr_func < SQL_ATTR_TRACEFILE > : : func
} ,
{
SSConnOptionNames : : TraceOn ,
sizeof ( SSConnOptionNames : : TraceOn ) ,
SQLSRV_CONN_OPTION_TRACE_ON ,
ODBCConnOptions : : TraceOn ,
sizeof ( ODBCConnOptions : : TraceOn ) ,
CONN_ATTR_BOOL ,
bool_conn_attr_func < SQL_ATTR_TRACE > : : func
} ,
{
SSConnOptionNames : : TransactionIsolation ,
sizeof ( SSConnOptionNames : : TransactionIsolation ) ,
SQLSRV_CONN_OPTION_TRANS_ISOLATION ,
ODBCConnOptions : : TransactionIsolation ,
sizeof ( ODBCConnOptions : : TransactionIsolation ) ,
CONN_ATTR_INT ,
int_conn_attr_func < SQL_COPT_SS_TXN_ISOLATION > : : func
} ,
{
SSConnOptionNames : : TrustServerCertificate ,
sizeof ( SSConnOptionNames : : TrustServerCertificate ) ,
SQLSRV_CONN_OPTION_TRUST_SERVER_CERT ,
ODBCConnOptions : : TrustServerCertificate ,
sizeof ( ODBCConnOptions : : TrustServerCertificate ) ,
CONN_ATTR_BOOL ,
bool_conn_str_func : : func
} ,
2017-06-07 22:53:04 +02:00
{
SSConnOptionNames : : TransparentNetworkIPResolution ,
sizeof ( SSConnOptionNames : : TransparentNetworkIPResolution ) ,
2018-05-06 02:08:01 +02:00
SQLSRV_CONN_OPTION_TRANSPARENT_NETWORK_IP_RESOLUTION ,
2017-06-07 22:53:04 +02:00
ODBCConnOptions : : TransparentNetworkIPResolution ,
sizeof ( ODBCConnOptions : : TransparentNetworkIPResolution ) ,
CONN_ATTR_STRING ,
conn_str_append_func : : func
} ,
2016-01-30 03:00:20 +01:00
{
SSConnOptionNames : : WSID ,
sizeof ( SSConnOptionNames : : WSID ) ,
SQLSRV_CONN_OPTION_WSID ,
ODBCConnOptions : : WSID ,
sizeof ( ODBCConnOptions : : WSID ) ,
CONN_ATTR_STRING ,
conn_str_append_func : : func
} ,
{
SSConnOptionNames : : DateAsString ,
sizeof ( SSConnOptionNames : : DateAsString ) ,
SS_CONN_OPTION_DATE_AS_STRING ,
SSConnOptionNames : : DateAsString ,
sizeof ( SSConnOptionNames : : DateAsString ) ,
CONN_ATTR_BOOL ,
date_as_string_func : : func
} ,
2018-11-28 02:18:38 +01:00
{
SSConnOptionNames : : FormatDecimals ,
sizeof ( SSConnOptionNames : : FormatDecimals ) ,
SS_CONN_OPTION_FORMAT_DECIMALS ,
SSConnOptionNames : : FormatDecimals ,
sizeof ( SSConnOptionNames : : FormatDecimals ) ,
CONN_ATTR_BOOL ,
format_decimals_func : : func
} ,
{
SSConnOptionNames : : DecimalPlaces ,
sizeof ( SSConnOptionNames : : DecimalPlaces ) ,
SS_CONN_OPTION_DECIMAL_PLACES ,
SSConnOptionNames : : DecimalPlaces ,
sizeof ( SSConnOptionNames : : DecimalPlaces ) ,
CONN_ATTR_INT ,
decimal_places_func : : func
} ,
2021-12-08 00:29:03 +01:00
{
SSConnOptionNames : : ComputePool ,
sizeof ( SSConnOptionNames : : ComputePool ) ,
SQLSRV_CONN_OPTION_COMPUTE_POOL ,
ODBCConnOptions : : ComputePool ,
sizeof ( ODBCConnOptions : : ComputePool ) ,
CONN_ATTR_STRING ,
conn_str_append_func : : func
} ,
2022-01-05 17:59:48 +01:00
{
SSConnOptionNames : : HostNameInCertificate ,
sizeof ( SSConnOptionNames : : HostNameInCertificate ) ,
SQLSRV_CONN_OPTION_HOSTNAME_IN_CERT ,
ODBCConnOptions : : HostNameInCertificate ,
sizeof ( ODBCConnOptions : : HostNameInCertificate ) ,
CONN_ATTR_STRING ,
conn_str_append_func : : func
} ,
2021-12-08 00:29:03 +01:00
2016-01-30 03:00:20 +01:00
{ NULL , 0 , SQLSRV_CONN_OPTION_INVALID , NULL , 0 , CONN_ATTR_INVALID , NULL } , //terminate the table
} ;
// sqlsrv_connect( string $serverName [, array $connectionInfo])
//
// Creates a connection resource and opens a connection. By default, the
// connection is attempted using Windows Authentication.
//
// Parameters
// $serverName: A string specifying the name of the server to which a connection
// is being established. An instance name (for example, "myServer\instanceName")
// or port number (for example, "myServer, 1521") can be included as part of
// this string. For a complete description of the options available for this
// parameter, see the Server keyword in the ODBC Driver Connection String
// Keywords section of Using Connection String Keywords with ODBC Driver 11 for SQL Server.
//
// $connectionInfo [OPTIONAL]: An associative array that contains connection
// attributes (for example, array("Database" => "AdventureWorks")).
//
// Return Value
// A PHP connection resource. If a connection cannot be successfully created and
// opened, false is returned
PHP_FUNCTION ( sqlsrv_connect )
{
LOG_FUNCTION ( " sqlsrv_connect " ) ;
2020-03-25 17:53:18 +01:00
g_ss_henv_cp - > set_func ( _FN_ ) ;
g_ss_henv_ncp - > set_func ( _FN_ ) ;
2016-01-30 03:00:20 +01:00
2020-04-21 00:17:21 +02:00
reset_errors ( ) ;
2016-01-30 03:00:20 +01:00
const char * server = NULL ;
zval * options_z = NULL ;
char * uid = NULL ;
char * pwd = NULL ;
size_t server_len = 0 ;
zval conn_z ;
ZVAL_UNDEF ( & conn_z ) ;
// get the server name and connection options
2020-04-21 00:17:21 +02:00
int result = zend_parse_parameters ( ZEND_NUM_ARGS ( ) , " s|a " , & server , & server_len , & options_z ) ;
2016-01-30 03:00:20 +01:00
2017-04-07 00:44:04 +02:00
CHECK_CUSTOM_ERROR ( ( result = = FAILURE ) , * g_ss_henv_cp , SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER , " sqlsrv_connect " ) {
2016-01-30 03:00:20 +01:00
RETURN_FALSE ;
}
hash_auto_ptr ss_conn_options_ht ;
hash_auto_ptr stmts ;
ss_sqlsrv_conn * conn = NULL ;
try {
// Initialize the options array to be passed to the core layer
ALLOC_HASHTABLE ( ss_conn_options_ht ) ;
2017-04-07 00:44:04 +02:00
core : : sqlsrv_zend_hash_init ( * g_ss_henv_cp , ss_conn_options_ht , 10 /* # of buckets */ ,
2020-04-21 00:17:21 +02:00
ZVAL_PTR_DTOR , 0 /*persistent*/ ) ;
2016-01-30 03:00:20 +01:00
2018-05-06 02:08:01 +02:00
// Either of g_ss_henv_cp or g_ss_henv_ncp can be used to propagate the error.
2020-04-21 00:17:21 +02:00
: : validate_conn_options ( * g_ss_henv_cp , options_z , & uid , & pwd , ss_conn_options_ht ) ;
2016-01-30 03:00:20 +01:00
// call the core connect function
2017-04-07 00:44:04 +02:00
conn = static_cast < ss_sqlsrv_conn * > ( core_sqlsrv_connect ( * g_ss_henv_cp , * g_ss_henv_ncp , & core : : allocate_conn < ss_sqlsrv_conn > ,
2016-01-30 03:00:20 +01:00
server , uid , pwd , ss_conn_options_ht , ss_error_handler ,
2020-04-21 00:17:21 +02:00
SS_CONN_OPTS , NULL , " sqlsrv_connect " ) ) ;
2016-01-30 03:00:20 +01:00
SQLSRV_ASSERT ( conn ! = NULL , " sqlsrv_connect: Invalid connection returned. Exception should have been thrown. " ) ;
// create a bunch of statements
ALLOC_HASHTABLE ( stmts ) ;
2020-04-21 00:17:21 +02:00
core : : sqlsrv_zend_hash_init ( * g_ss_henv_cp , stmts , 5 , NULL /* dtor */ , 0 /* persistent */ ) ;
2016-01-30 03:00:20 +01:00
// register the connection with the PHP runtime
2016-03-15 04:09:46 +01:00
2020-04-21 00:17:21 +02:00
ss : : zend_register_resource ( conn_z , conn , ss_sqlsrv_conn : : descriptor , ss_sqlsrv_conn : : resource_name ) ;
2016-01-30 03:00:20 +01:00
conn - > stmts = stmts ;
stmts . transferred ( ) ;
2017-05-06 02:17:52 +02:00
RETURN_RES ( Z_RES ( conn_z ) ) ;
2016-01-30 03:00:20 +01:00
}
catch ( core : : CoreException & ) {
if ( conn ! = NULL ) {
conn - > invalidate ( ) ;
}
RETURN_FALSE ;
}
catch ( . . . ) {
DIE ( " sqlsrv_connect: Unknown exception caught. " ) ;
}
}
// sqlsrv_begin_transaction( resource $conn )
//
// Begins a transaction on a specified connection. The current transaction
// includes all statements on the specified connection that were executed after
// the call to sqlsrv_begin_transaction and before any calls to sqlsrv_rollback
// or sqlsrv_commit.
//
// The SQLSRV driver is in auto-commit mode by default. This means that all
// queries are automatically committed upon success unless they have been
// designated as part of an explicit transaction by using
// sqlsrv_begin_transaction.
//
// If sqlsrv_begin_transaction is called after a transaction has already been
// initiated on the connection but not completed by calling either sqlsrv_commit
// or sqlsrv_rollback, the call returns false and an Already in Transaction
// error is added to the error collection.
//
// Parameters
// $conn: The connection with which the transaction is associated.
//
// Return Value
// A Boolean value: true if the transaction was successfully begun. Otherwise, false.
PHP_FUNCTION ( sqlsrv_begin_transaction )
{
LOG_FUNCTION ( " sqlsrv_begin_transaction " ) ;
ss_sqlsrv_conn * conn = NULL ;
PROCESS_PARAMS ( conn , " r " , _FN_ , 0 ) ;
// Return false if already in transaction
CHECK_CUSTOM_ERROR ( ( conn - > in_transaction = = true ) , * conn , SS_SQLSRV_ERROR_ALREADY_IN_TXN ) {
RETURN_FALSE ;
}
try {
2020-04-21 00:17:21 +02:00
core_sqlsrv_begin_transaction ( conn ) ;
2016-01-30 03:00:20 +01:00
conn - > in_transaction = true ;
RETURN_TRUE ;
}
catch ( core : : CoreException & ) {
RETURN_FALSE ;
}
catch ( . . . ) {
DIE ( " sqlsrv_begin_transaction: Unknown exception caught. " ) ;
}
}
// sqlsrv_close( resource $conn )
// Closes the specified connection and releases associated resources.
//
// Parameters
// $conn: The connection to be closed. Null is a valid value parameter for this
// parameter. This allows the function to be called multiple times in a
// script. For example, if you close a connection in an error condition and
// close it again at the end of the script, the second call to sqlsrv_close will
// return true because the first call to sqlsrv_close (in the error condition)
// sets the connection resource to null.
//
// Return Value
// The Boolean value true unless the function is called with an invalid
// parameter. If the function is called with an invalid parameter, false is
// returned.
PHP_FUNCTION ( sqlsrv_close )
{
LOG_FUNCTION ( " sqlsrv_close " ) ;
zval * conn_r = NULL ;
ss_sqlsrv_conn * conn = NULL ;
sqlsrv_context_auto_ptr error_ctx ;
2020-04-21 00:17:21 +02:00
reset_errors ( ) ;
2016-01-30 03:00:20 +01:00
try {
2016-03-15 04:09:46 +01:00
2017-05-06 02:17:52 +02:00
// dummy context to pass to the error handler
2016-01-30 03:00:20 +01:00
error_ctx = new ( sqlsrv_malloc ( sizeof ( sqlsrv_context ) ) ) sqlsrv_context ( 0 , ss_error_handler , NULL ) ;
2020-03-25 17:53:18 +01:00
error_ctx - > set_func ( _FN_ ) ;
2016-05-04 05:05:41 +02:00
2020-04-21 00:17:21 +02:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) , " r " , & conn_r ) = = FAILURE ) {
2016-01-30 03:00:20 +01:00
// Check if it was a zval
2020-04-21 00:17:21 +02:00
int zr = zend_parse_parameters ( ZEND_NUM_ARGS ( ) , " z " , & conn_r ) ;
2016-01-30 03:00:20 +01:00
CHECK_CUSTOM_ERROR ( ( zr = = FAILURE ) , error_ctx , SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER , _FN_ ) {
throw ss : : SSException ( ) ;
}
2017-05-06 02:17:52 +02:00
2016-05-04 05:05:41 +02:00
// if sqlsrv_close was called on a non-existent connection then we just return success.
2016-01-30 03:00:20 +01:00
if ( Z_TYPE_P ( conn_r ) = = IS_NULL ) {
RETURN_TRUE ;
}
2016-03-15 04:09:46 +01:00
else {
THROW_CORE_ERROR ( error_ctx , SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER , _FN_ ) ;
2016-01-30 03:00:20 +01:00
}
}
2017-06-22 23:04:34 +02:00
SQLSRV_ASSERT ( conn_r ! = NULL , " sqlsrv_close: conn_r was null " ) ;
2020-04-21 00:17:21 +02:00
conn = static_cast < ss_sqlsrv_conn * > ( zend_fetch_resource ( Z_RES_P ( conn_r ) , ss_sqlsrv_conn : : resource_name , ss_sqlsrv_conn : : descriptor ) ) ;
2016-05-04 05:05:41 +02:00
2017-05-06 02:17:52 +02:00
// if sqlsrv_close was called on an already closed connection then we just return success.
if ( Z_RES_TYPE_P ( conn_r ) = = RSRC_INVALID_TYPE ) {
RETURN_TRUE ;
}
CHECK_CUSTOM_ERROR ( ( conn = = NULL ) , error_ctx , SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER , _FN_ ) {
2016-01-30 03:00:20 +01:00
throw ss : : SSException ( ) ;
}
2020-03-25 17:53:18 +01:00
conn - > set_func ( _FN_ ) ;
2017-05-06 02:17:52 +02:00
2016-01-30 03:00:20 +01:00
// cause any variables still holding a reference to this to be invalid so they cause
// an error when passed to a sqlsrv function. There's nothing we can do if the
// removal fails, so we just log it and move on.
2020-09-02 01:54:26 +02:00
# if PHP_VERSION_ID < 80000
if ( zend_list_close ( Z_RES_P ( conn_r ) ) = = FAILURE ) {
LOG ( SEV_ERROR , " Failed to remove connection resource %1!d! " , Z_RES_HANDLE_P ( conn_r ) ) ;
2016-01-30 03:00:20 +01:00
}
2020-09-02 01:54:26 +02:00
# else
zend_list_close ( Z_RES_P ( conn_r ) ) ;
# endif
2017-06-17 00:43:15 +02:00
2017-06-19 21:55:40 +02:00
// when conn_r is first parsed in zend_parse_parameters, conn_r becomes a zval that points to a zend_resource with a refcount of 2
// need to DELREF here so the refcount becomes 1 and conn_r can be appropriate destroyed by the garbage collector when it goes out of scope
// zend_list_close only destroy the resource pointed to by Z_RES_P( conn_r ), not the zend_resource itself
2017-06-17 00:43:15 +02:00
Z_TRY_DELREF_P ( conn_r ) ;
2017-05-06 02:17:52 +02:00
ZVAL_NULL ( conn_r ) ;
2016-03-15 04:09:46 +01:00
2016-01-30 03:00:20 +01:00
RETURN_TRUE ;
}
catch ( core : : CoreException & ) {
2017-05-06 02:17:52 +02:00
2016-01-30 03:00:20 +01:00
RETURN_FALSE ;
}
catch ( . . . ) {
DIE ( " sqlsrv_close: Unknown exception caught. " ) ;
}
}
2020-04-21 00:17:21 +02:00
void __cdecl sqlsrv_conn_dtor ( _Inout_ zend_resource * rsrc )
2016-01-30 03:00:20 +01:00
{
2020-03-25 17:53:18 +01:00
// Without sqlsrv_close(), this function is invoked by php during the final clean up stage.
// To prevent memory/resource leaks, no more logging at this point.
//LOG_FUNCTION( "sqlsrv_conn_dtor" );
2016-01-30 03:00:20 +01:00
// get the structure
ss_sqlsrv_conn * conn = static_cast < ss_sqlsrv_conn * > ( rsrc - > ptr ) ;
SQLSRV_ASSERT ( conn ! = NULL , " sqlsrv_conn_dtor: connection was null " ) ;
2020-03-25 17:53:18 +01:00
conn - > set_func ( __func__ ) ;
2016-01-30 03:00:20 +01:00
// close all statements associated with the connection.
2020-04-21 00:17:21 +02:00
sqlsrv_conn_close_stmts ( conn ) ;
2016-01-30 03:00:20 +01:00
// close the connection itself.
2020-04-21 00:17:21 +02:00
core_sqlsrv_close ( conn ) ;
2016-01-30 03:00:20 +01:00
rsrc - > ptr = NULL ;
}
// sqlsrv_commit( resource $conn )
//
// Commits the current transaction on the specified connection and returns the
// connection to the auto-commit mode. The current transaction includes all
// statements on the specified connection that were executed after the call to
// sqlsrv_begin_transaction and before any calls to sqlsrv_rollback or
// sqlsrv_commit.
// The SQLSRV driver is in auto-commit mode by
// default. This means that all queries are automatically committed upon success
// unless they have been designated as part of an explicit transaction by using
// sqlsrv_begin_transaction. If sqlsrv_commit is called on a connection that is
// not in an active transaction and that was initiated with
// sqlsrv_begin_transaction, the call returns false and a Not in Transaction
// error is added to the error collection.
//
// Parameters
// $conn: The connection on which the transaction is active.
//
// Return Value
// A Boolean value: true if the transaction was successfully committed. Otherwise, false.
PHP_FUNCTION ( sqlsrv_commit )
{
LOG_FUNCTION ( " sqlsrv_commit " ) ;
ss_sqlsrv_conn * conn = NULL ;
PROCESS_PARAMS ( conn , " r " , _FN_ , 0 ) ;
// Return false if not in transaction
CHECK_CUSTOM_ERROR ( ( conn - > in_transaction = = false ) , * conn , SS_SQLSRV_ERROR_NOT_IN_TXN ) {
RETURN_FALSE ;
}
try {
conn - > in_transaction = false ;
2020-04-21 00:17:21 +02:00
core_sqlsrv_commit ( conn ) ;
2016-01-30 03:00:20 +01:00
RETURN_TRUE ;
}
catch ( core : : CoreException & ) {
RETURN_FALSE ;
}
catch ( . . . ) {
DIE ( " sqlsrv_commit: Unknown exception caught. " ) ;
}
}
// sqlsrv_rollback( resource $conn )
//
// Rolls back the current transaction on the specified connection and returns
// the connection to the auto-commit mode. The current transaction includes all
// statements on the specified connection that were executed after the call to
// sqlsrv_begin_transaction and before any calls to sqlsrv_rollback or
// sqlsrv_commit.
//
// The SQLSRV driver is in auto-commit mode by default. This
// means that all queries are automatically committed upon success unless they
// have been designated as part of an explicit transaction by using
// sqlsrv_begin_transaction.
//
// If sqlsrv_rollback is called on a connection that is not in an active
// transaction that was initiated with sqlsrv_begin_transaction, the call
// returns false and a Not in Transaction error is added to the error
// collection.
//
// Parameters
// $conn: The connection on which the transaction is active.
//
// Return Value
// A Boolean value: true if the transaction was successfully rolled back. Otherwise, false.
PHP_FUNCTION ( sqlsrv_rollback )
{
LOG_FUNCTION ( " sqlsrv_rollback " ) ;
ss_sqlsrv_conn * conn = NULL ;
PROCESS_PARAMS ( conn , " r " , _FN_ , 0 ) ;
// Return false if not in transaction
CHECK_CUSTOM_ERROR ( ( conn - > in_transaction = = false ) , * conn , SS_SQLSRV_ERROR_NOT_IN_TXN ) {
RETURN_FALSE ;
}
try {
conn - > in_transaction = false ;
2020-04-21 00:17:21 +02:00
core_sqlsrv_rollback ( conn ) ;
2016-01-30 03:00:20 +01:00
RETURN_TRUE ;
}
catch ( core : : CoreException & ) {
RETURN_FALSE ;
}
catch ( . . . ) {
DIE ( " sqlsrv_rollback: Unknown exception caught. " ) ;
}
}
// sqlsrv_client_info
// Returns the ODBC driver's dll name, version and the ODBC version. Also returns
// the version of this extension.
// Parameters:
// $conn - The connection resource by which the client and server are connected.
PHP_FUNCTION ( sqlsrv_client_info )
{
LOG_FUNCTION ( " sqlsrv_client_info " ) ;
ss_sqlsrv_conn * conn = NULL ;
PROCESS_PARAMS ( conn , " r " , _FN_ , 0 ) ;
try {
2020-07-23 22:46:25 +02:00
core_sqlsrv_get_client_info ( conn , return_value ) ;
2016-01-30 03:00:20 +01:00
// Add the sqlsrv driver's file version
2017-01-19 17:17:45 +01:00
//Declarations below eliminate compiler warnings about string constant to char* conversions
const char * extver = " ExtensionVer " ;
std : : string filever = VER_FILEVERSION_STR ;
2020-07-23 22:46:25 +02:00
add_assoc_string ( return_value , extver , & filever [ 0 ] ) ;
} catch ( core : : CoreException & ) {
2016-01-30 03:00:20 +01:00
RETURN_FALSE ;
2020-07-23 22:46:25 +02:00
} catch ( . . . ) {
DIE ( " sqlsrv_client_info: Unknown exception caught. " ) ;
2016-01-30 03:00:20 +01:00
}
}
// sqlsrv_server_info( resource $conn )
//
// Returns information about the server.
//
// Parameters
// $conn: The connection resource by which the client and server are connected.
//
// Return Value
// An associative array with the following keys:
// CurrentDatabase
// The database currently being targeted.
// SQLServerVersion
// The version of SQL Server.
// SQLServerName
// The name of the server.
PHP_FUNCTION ( sqlsrv_server_info )
{
try {
2020-07-23 22:46:25 +02:00
LOG_FUNCTION ( " sqlsrv_server_info " ) ;
2016-01-30 03:00:20 +01:00
ss_sqlsrv_conn * conn = NULL ;
2020-07-23 22:46:25 +02:00
PROCESS_PARAMS ( conn , " r " , _FN_ , 0 ) ;
2016-01-30 03:00:20 +01:00
2020-07-23 22:46:25 +02:00
core_sqlsrv_get_server_info ( conn , return_value ) ;
} catch ( core : : CoreException & ) {
2016-01-30 03:00:20 +01:00
RETURN_FALSE ;
2020-07-23 22:46:25 +02:00
} catch ( . . . ) {
DIE ( " sqlsrv_server_info: Unknown exception caught. " ) ;
2016-01-30 03:00:20 +01:00
}
}
// sqlsrv_prepare( resource $conn, string $tsql [, array $params [, array $options]])
//
// Creates a statement resource associated with the specified connection. A statement
// resource returned by sqlsrv_prepare may be executed multiple times by sqlsrv_execute.
// In between each execution, the values may be updated by changing the value of the
// variables bound. Output parameters cannot be relied upon to contain their results until
// all rows are processed.
//
// Parameters
// $conn: The connection resource associated with the created statement.
//
// $tsql: The Transact-SQL expression that corresponds to the created statement.
//
// $params [OPTIONAL]: An array of values that correspond to parameters in a
// parameterized query. Each parameter may be specified as:
// $value | array($value [, $direction [, $phpType [, $sqlType]]])
// When given just a $value, the direction is default input, and phptype is the value
// given, with the sql type inferred from the php type.
//
// $options [OPTIONAL]: An associative array that sets query properties. The
// table below lists the supported keys and corresponding values:
// QueryTimeout
// Sets the query timeout in seconds. By default, the driver will wait
// indefinitely for results.
// SendStreamParamsAtExec
// Configures the driver to send all stream data at execution (true), or to
// send stream data in chunks (false). By default, the value is set to
// true. For more information, see sqlsrv_send_stream_data.
//
// Return Value
// A statement resource. If the statement resource cannot be created, false is returned.
PHP_FUNCTION ( sqlsrv_prepare )
{
LOG_FUNCTION ( " sqlsrv_prepare " ) ;
sqlsrv_malloc_auto_ptr < ss_sqlsrv_stmt > stmt ;
ss_sqlsrv_conn * conn = NULL ;
char * sql = NULL ;
zend_long sql_len = 0 ;
zval * params_z = NULL ;
zval * options_z = NULL ;
hash_auto_ptr ss_stmt_options_ht ;
zval stmt_z ;
ZVAL_UNDEF ( & stmt_z ) ;
PROCESS_PARAMS ( conn , " rs|a!a! " , _FN_ , 4 , & sql , & sql_len , & params_z , & options_z ) ;
try {
if ( options_z & & zend_hash_num_elements ( Z_ARRVAL_P ( options_z ) ) > 0 ) {
// Initialize the options array to be passed to the core layer
ALLOC_HASHTABLE ( ss_stmt_options_ht ) ;
2018-09-18 01:25:02 +02:00
core : : sqlsrv_zend_hash_init ( * conn , ss_stmt_options_ht , 5 /* # of buckets */ ,
2020-04-21 00:17:21 +02:00
ZVAL_PTR_DTOR , 0 /*persistent*/ ) ;
2016-01-30 03:00:20 +01:00
2020-04-21 00:17:21 +02:00
validate_stmt_options ( * conn , options_z , ss_stmt_options_ht ) ;
2016-01-30 03:00:20 +01:00
}
if ( params_z & & Z_TYPE_P ( params_z ) ! = IS_ARRAY ) {
THROW_SS_ERROR ( conn , SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER , _FN_ ) ;
}
if ( options_z & & Z_TYPE_P ( options_z ) ! = IS_ARRAY ) {
THROW_SS_ERROR ( conn , SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER , _FN_ ) ;
}
if ( sql = = NULL ) {
DIE ( " sqlsrv_prepare: sql string was null. " ) ;
}
stmt = static_cast < ss_sqlsrv_stmt * > ( core_sqlsrv_create_stmt ( conn , core : : allocate_stmt < ss_sqlsrv_stmt > ,
ss_stmt_options_ht , SS_STMT_OPTS ,
2020-04-21 00:17:21 +02:00
ss_error_handler , NULL ) ) ;
2016-01-30 03:00:20 +01:00
2020-04-21 00:17:21 +02:00
core_sqlsrv_prepare ( stmt , sql , sql_len ) ;
2016-01-30 03:00:20 +01:00
2017-05-06 02:17:52 +02:00
if ( params_z ) {
stmt - > params_z = ( zval * ) sqlsrv_malloc ( sizeof ( zval ) ) ;
ZVAL_COPY ( stmt - > params_z , params_z ) ;
}
2016-01-30 03:00:20 +01:00
stmt - > prepared = true ;
// register the statement with the PHP runtime
2020-04-21 00:17:21 +02:00
ss : : zend_register_resource ( stmt_z , stmt , ss_sqlsrv_stmt : : descriptor , ss_sqlsrv_stmt : : resource_name ) ;
2016-01-30 03:00:20 +01:00
// store the resource id with the connection so the connection
// can release this statement when it closes.
2016-03-15 04:09:46 +01:00
zend_long next_index = zend_hash_next_free_element ( conn - > stmts ) ;
2016-01-30 03:00:20 +01:00
2020-04-21 00:17:21 +02:00
core : : sqlsrv_zend_hash_index_update ( * conn , conn - > stmts , next_index , & stmt_z ) ;
2016-01-30 03:00:20 +01:00
stmt - > conn_index = next_index ;
// the statement is now registered with EG( regular_list )
stmt . transferred ( ) ;
RETURN_RES ( Z_RES ( stmt_z ) ) ;
}
catch ( core : : CoreException & ) {
if ( stmt ) {
stmt - > conn = NULL ;
stmt - > ~ ss_sqlsrv_stmt ( ) ;
}
if ( ! Z_ISUNDEF ( stmt_z ) ) {
2020-04-21 00:17:21 +02:00
free_stmt_resource ( & stmt_z ) ;
2016-01-30 03:00:20 +01:00
}
RETURN_FALSE ;
}
catch ( . . . ) {
DIE ( " sqlsrv_prepare: Unknown exception caught. " ) ;
}
}
// sqlsrv_query( resource $conn, string $tsql [, array $params [, array $options]])
//
// Creates a statement resource associated with the specified connection. The statement
// is immediately executed and may not be executed again using sqlsrv_execute.
//
// Parameters
// $conn: The connection resource associated with the created statement.
//
// $tsql: The Transact-SQL expression that corresponds to the created statement.
//
// $params [OPTIONAL]: An array of values that correspond to parameters in a
// parameterized query. Each parameter may be specified as:
// $value | array($value [, $direction [, $phpType [, $sqlType]]])
// When given just a $value, the direction is default input, and phptype is the value
// given, with the sql type inferred from the php type.
//
// $options [OPTIONAL]: An associative array that sets query properties. The
// table below lists the supported keys and corresponding values:
// QueryTimeout
// Sets the query timeout in seconds. By default, the driver will wait
// indefinitely for results.
// SendStreamParamsAtExec
// Configures the driver to send all stream data at execution (true), or to
// send stream data in chunks (false). By default, the value is set to
// true. For more information, see sqlsrv_send_stream_data.
//
// Return Value
// A statement resource. If the statement resource cannot be created, false is returned.
PHP_FUNCTION ( sqlsrv_query )
{
LOG_FUNCTION ( " sqlsrv_query " ) ;
ss_sqlsrv_conn * conn = NULL ;
sqlsrv_malloc_auto_ptr < ss_sqlsrv_stmt > stmt ;
char * sql = NULL ;
hash_auto_ptr ss_stmt_options_ht ;
2017-01-19 17:17:45 +01:00
size_t sql_len = 0 ;
2016-01-30 03:00:20 +01:00
zval * options_z = NULL ;
2017-05-06 02:17:52 +02:00
zval * params_z = NULL ;
2016-01-30 03:00:20 +01:00
zval stmt_z ;
ZVAL_UNDEF ( & stmt_z ) ;
PROCESS_PARAMS ( conn , " rs|a!a! " , _FN_ , 4 , & sql , & sql_len , & params_z , & options_z ) ;
try {
// check for statement options
if ( options_z & & zend_hash_num_elements ( Z_ARRVAL_P ( options_z ) ) > 0 ) {
// Initialize the options array to be passed to the core layer
ALLOC_HASHTABLE ( ss_stmt_options_ht ) ;
2018-09-18 01:25:02 +02:00
core : : sqlsrv_zend_hash_init ( * conn , ss_stmt_options_ht , 5 /* # of buckets */ , ZVAL_PTR_DTOR ,
2020-04-21 00:17:21 +02:00
0 /*persistent*/ ) ;
2016-01-30 03:00:20 +01:00
2020-04-21 00:17:21 +02:00
validate_stmt_options ( * conn , options_z , ss_stmt_options_ht ) ;
2016-01-30 03:00:20 +01:00
}
if ( params_z & & Z_TYPE_P ( params_z ) ! = IS_ARRAY ) {
THROW_SS_ERROR ( conn , SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER , _FN_ ) ;
}
if ( options_z & & Z_TYPE_P ( options_z ) ! = IS_ARRAY ) {
THROW_SS_ERROR ( conn , SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER , _FN_ ) ;
}
if ( sql = = NULL ) {
DIE ( " sqlsrv_query: sql string was null. " ) ;
}
stmt = static_cast < ss_sqlsrv_stmt * > ( core_sqlsrv_create_stmt ( conn , core : : allocate_stmt < ss_sqlsrv_stmt > ,
ss_stmt_options_ht , SS_STMT_OPTS ,
2020-04-21 00:17:21 +02:00
ss_error_handler , NULL ) ) ;
2016-01-30 03:00:20 +01:00
if ( params_z ) {
2017-05-06 02:17:52 +02:00
stmt - > params_z = ( zval * ) sqlsrv_malloc ( sizeof ( zval ) ) ;
ZVAL_COPY ( stmt - > params_z , params_z ) ;
2016-01-30 03:00:20 +01:00
}
stmt - > set_func ( " sqlsrv_query " ) ;
2020-04-21 00:17:21 +02:00
bind_params ( stmt ) ;
2016-01-30 03:00:20 +01:00
// execute the statement
2020-04-21 00:17:21 +02:00
core_sqlsrv_execute ( stmt , sql , static_cast < int > ( sql_len ) ) ;
2016-01-30 03:00:20 +01:00
// register the statement with the PHP runtime
2020-04-21 00:17:21 +02:00
ss : : zend_register_resource ( stmt_z , stmt , ss_sqlsrv_stmt : : descriptor , ss_sqlsrv_stmt : : resource_name ) ;
2016-01-30 03:00:20 +01:00
// store the resource id with the connection so the connection
// can release this statement when it closes.
2017-05-06 02:17:52 +02:00
zend_ulong next_index = zend_hash_next_free_element ( conn - > stmts ) ;
2016-01-30 03:00:20 +01:00
2020-04-21 00:17:21 +02:00
core : : sqlsrv_zend_hash_index_update ( * conn , conn - > stmts , next_index , & stmt_z ) ;
2016-01-30 03:00:20 +01:00
stmt - > conn_index = next_index ;
stmt . transferred ( ) ;
RETURN_RES ( Z_RES ( stmt_z ) ) ;
}
catch ( core : : CoreException & ) {
if ( stmt ) {
stmt - > conn = NULL ; // tell the statement that it isn't part of the connection so it doesn't try to remove itself
stmt - > ~ ss_sqlsrv_stmt ( ) ;
}
if ( ! Z_ISUNDEF ( stmt_z ) ) {
2020-04-21 00:17:21 +02:00
free_stmt_resource ( & stmt_z ) ;
2016-01-30 03:00:20 +01:00
}
RETURN_FALSE ;
}
catch ( . . . ) {
DIE ( " sqlsrv_query: Unknown exception caught. " ) ;
}
}
2020-04-21 00:17:21 +02:00
void free_stmt_resource ( _Inout_ zval * stmt_z )
2016-01-30 03:00:20 +01:00
{
2020-09-02 01:54:26 +02:00
# if PHP_VERSION_ID < 80000
if ( FAILURE = = zend_list_close ( Z_RES_P ( stmt_z ) ) ) {
2016-01-30 03:00:20 +01:00
LOG ( SEV_ERROR , " Failed to remove stmt resource %1!d! " , Z_RES_HANDLE_P ( stmt_z ) ) ;
}
2020-09-02 01:54:26 +02:00
# else
zend_list_close ( Z_RES_P ( stmt_z ) ) ;
# endif
2016-01-30 03:00:20 +01:00
ZVAL_NULL ( stmt_z ) ;
zval_ptr_dtor ( stmt_z ) ;
}
// internal connection functions
namespace {
// must close all statement handles opened by this connection before closing the connection
// no errors are returned, since close should always succeed
2020-04-21 00:17:21 +02:00
void sqlsrv_conn_close_stmts ( _Inout_ ss_sqlsrv_conn * conn )
2016-01-30 03:00:20 +01:00
{
//pre-condition check
SQLSRV_ASSERT ( ( conn - > handle ( ) ! = NULL ) , " sqlsrv_conn_close_stmts: Connection handle is NULL. Trying to destroy an "
" already destroyed connection. " ) ;
SQLSRV_ASSERT ( ( conn - > stmts ) , " sqlsrv_conn_close_stmts: Connection doesn't contain a statement array. " ) ;
// loop through the stmts hash table and destroy each stmt resource so we can close the
// ODBC connection
2017-05-06 02:17:52 +02:00
zval * rsrc_ptr = NULL ;
ZEND_HASH_FOREACH_VAL ( conn - > stmts , rsrc_ptr ) {
try {
int zr = ( rsrc_ptr ) ! = NULL ? SUCCESS : FAILURE ;
CHECK_ZEND_ERROR ( zr , * conn , SQLSRV_ERROR_ZEND_HASH ) {
throw core : : CoreException ( ) ;
}
}
catch ( core : : CoreException & ) {
DIE ( " sqlsrv_conn_close_stmts: Failed to retrieve a statement resource from the connection " ) ;
}
// see if the statement is still valid, and if not skip to the next one
// presumably this should never happen because if it's in the list, it should still be valid
// by virtue that a statement resource should remove itself from its connection when it is
// destroyed in sqlsrv_stmt_dtor. However, rather than die (assert), we simply skip this resource
// and move to the next one.
ss_sqlsrv_stmt * stmt = NULL ;
stmt = static_cast < ss_sqlsrv_stmt * > ( Z_RES_VAL_P ( rsrc_ptr ) ) ;
if ( stmt = = NULL | | Z_RES_TYPE_P ( rsrc_ptr ) ! = ss_sqlsrv_stmt : : descriptor ) {
LOG ( SEV_ERROR , " Non existent statement found in connection. Statements should remove themselves "
" from the connection so this shouldn't be out of sync. " ) ;
continue ;
}
// delete the statement by deleting it from Zend's resource list, which will force its destruction
stmt - > conn = NULL ;
2016-01-30 03:00:20 +01:00
2017-01-19 17:17:45 +01:00
// this would call the destructor on the statement.
// There's nothing we can do if the removal fails, so we just log it and move on.
2020-09-02 01:54:26 +02:00
# if PHP_VERSION_ID < 80000
if ( zend_list_close ( Z_RES_P ( rsrc_ptr ) ) = = FAILURE ) {
2017-01-19 17:17:45 +01:00
LOG ( SEV_ERROR , " Failed to remove statement resource %1!d! when closing the connection " , Z_RES_HANDLE_P ( rsrc_ptr ) ) ;
}
2020-09-02 01:54:26 +02:00
# else
zend_list_close ( Z_RES_P ( rsrc_ptr ) ) ;
# endif
2017-01-19 17:17:45 +01:00
} ZEND_HASH_FOREACH_END ( ) ;
2016-01-30 03:00:20 +01:00
zend_hash_destroy ( conn - > stmts ) ;
FREE_HASHTABLE ( conn - > stmts ) ;
conn - > stmts = NULL ;
}
2020-04-21 00:17:21 +02:00
int get_conn_option_key ( _Inout_ sqlsrv_context & ctx , _In_ zend_string * key , _In_ size_t key_len , _Inout_ zval const * value_z )
2016-01-30 03:00:20 +01:00
{
2018-08-01 02:22:56 +02:00
for ( int i = 0 ; SS_CONN_OPTS [ i ] . conn_option_key ! = SQLSRV_CONN_OPTION_INVALID ; + + i )
2016-01-30 03:00:20 +01:00
{
2018-08-01 02:22:56 +02:00
if ( key_len = = SS_CONN_OPTS [ i ] . sqlsrv_len & & ! stricmp ( ZSTR_VAL ( key ) , SS_CONN_OPTS [ i ] . sqlsrv_name ) ) {
2016-01-30 03:00:20 +01:00
2018-08-01 02:22:56 +02:00
switch ( SS_CONN_OPTS [ i ] . value_type ) {
2016-01-30 03:00:20 +01:00
case CONN_ATTR_BOOL :
// bool attributes can be either strings to be appended to the connection string
// as yes or no or integral connection attributes. This will have to be reworked
// if we ever introduce a boolean connection option that maps to a string connection
// attribute.
break ;
2021-12-07 01:40:41 +01:00
case CONN_ATTR_MIXED :
break ;
2016-01-30 03:00:20 +01:00
case CONN_ATTR_INT :
{
CHECK_CUSTOM_ERROR ( ( Z_TYPE_P ( value_z ) ! = IS_LONG ) , ctx , SQLSRV_ERROR_INVALID_OPTION_TYPE_INT ,
2018-08-01 02:22:56 +02:00
SS_CONN_OPTS [ i ] . sqlsrv_name )
2016-01-30 03:00:20 +01:00
{
throw ss : : SSException ( ) ;
}
break ;
}
case CONN_ATTR_STRING :
{
CHECK_CUSTOM_ERROR ( Z_TYPE_P ( value_z ) ! = IS_STRING , ctx , SQLSRV_ERROR_INVALID_OPTION_TYPE_STRING ,
2018-08-01 02:22:56 +02:00
SS_CONN_OPTS [ i ] . sqlsrv_name ) {
2016-01-30 03:00:20 +01:00
throw ss : : SSException ( ) ;
}
char * value = Z_STRVAL_P ( value_z ) ;
2016-03-15 04:09:46 +01:00
size_t value_len = Z_STRLEN_P ( value_z ) ;
2016-01-30 03:00:20 +01:00
bool escaped = core_is_conn_opt_value_escaped ( value , value_len ) ;
2018-08-01 02:22:56 +02:00
CHECK_CUSTOM_ERROR ( ! escaped , ctx , SS_SQLSRV_ERROR_CONNECT_BRACES_NOT_ESCAPED , SS_CONN_OPTS [ i ] . sqlsrv_name ) {
2016-01-30 03:00:20 +01:00
throw ss : : SSException ( ) ;
}
2017-05-06 01:28:33 +02:00
2016-01-30 03:00:20 +01:00
break ;
}
2020-10-17 00:17:58 +02:00
case CONN_ATTR_INVALID :
SQLSRV_ASSERT ( false , " Should not have reached CONN_ATTR_INVALID. " ) ;
break ;
}
2016-01-30 03:00:20 +01:00
2018-08-01 02:22:56 +02:00
return SS_CONN_OPTS [ i ] . conn_option_key ;
2016-01-30 03:00:20 +01:00
}
}
return SQLSRV_CONN_OPTION_INVALID ;
}
2020-04-21 00:17:21 +02:00
int get_stmt_option_key ( _In_ zend_string * key , _In_ size_t key_len )
2016-01-30 03:00:20 +01:00
{
2018-08-01 02:22:56 +02:00
for ( int i = 0 ; SS_STMT_OPTS [ i ] . key ! = SQLSRV_STMT_OPTION_INVALID ; + + i )
2016-01-30 03:00:20 +01:00
{
2018-08-01 02:22:56 +02:00
if ( key_len = = SS_STMT_OPTS [ i ] . name_len & & ! stricmp ( ZSTR_VAL ( key ) , SS_STMT_OPTS [ i ] . name ) ) {
return SS_STMT_OPTS [ i ] . key ;
2016-01-30 03:00:20 +01:00
}
}
return SQLSRV_STMT_OPTION_INVALID ;
}
2017-06-22 23:04:34 +02:00
void add_stmt_option_key ( _Inout_ sqlsrv_context & ctx , _In_ zend_string * key , _In_ size_t key_len ,
2020-04-21 00:17:21 +02:00
_Inout_ HashTable * options_ht , _Inout_ zval * data )
2016-01-30 03:00:20 +01:00
{
2020-04-21 00:17:21 +02:00
int option_key = : : get_stmt_option_key ( key , key_len ) ;
2016-01-30 03:00:20 +01:00
2016-08-24 23:28:20 +02:00
CHECK_CUSTOM_ERROR ( ( option_key = = SQLSRV_STMT_OPTION_INVALID ) , ctx , SQLSRV_ERROR_INVALID_OPTION_KEY , ZSTR_VAL ( key ) ) {
2016-01-30 03:00:20 +01:00
throw ss : : SSException ( ) ;
}
2016-02-24 03:06:51 +01:00
Z_TRY_ADDREF_P ( data ) ; // inc the ref count since this is going into the options_ht too.
2020-04-21 00:17:21 +02:00
core : : sqlsrv_zend_hash_index_update ( ctx , options_ht , option_key , data ) ;
2016-01-30 03:00:20 +01:00
}
2017-06-22 23:04:34 +02:00
void add_conn_option_key ( _Inout_ sqlsrv_context & ctx , _In_ zend_string * key , _In_ size_t key_len ,
2020-04-21 00:17:21 +02:00
_Inout_ HashTable * options_ht , _Inout_ zval * data )
2016-01-30 03:00:20 +01:00
{
2020-04-21 00:17:21 +02:00
int option_key = : : get_conn_option_key ( ctx , key , key_len , data ) ;
2016-10-25 01:11:52 +02:00
CHECK_CUSTOM_ERROR ( ( option_key = = SQLSRV_STMT_OPTION_INVALID ) , ctx , SS_SQLSRV_ERROR_INVALID_OPTION , ZSTR_VAL ( key ) ) {
2016-01-30 03:00:20 +01:00
throw ss : : SSException ( ) ;
}
2016-02-24 03:06:51 +01:00
Z_TRY_ADDREF_P ( data ) ; // inc the ref count since this is going into the options_ht too.
2020-04-21 00:17:21 +02:00
core : : sqlsrv_zend_hash_index_update ( ctx , options_ht , option_key , data ) ;
2016-01-30 03:00:20 +01:00
}
// Iterates through the list of statement options provided by the user and validates them
// against the list of supported statement options by this driver. After validation
// creates a Hashtable of statement options to be sent to the core layer for processing.
2020-04-21 00:17:21 +02:00
void validate_stmt_options ( _Inout_ sqlsrv_context & ctx , _Inout_ zval * stmt_options , _Inout_ HashTable * ss_stmt_options_ht )
2016-01-30 03:00:20 +01:00
{
try {
if ( stmt_options ) {
HashTable * options_ht = Z_ARRVAL_P ( stmt_options ) ;
2017-05-06 02:17:52 +02:00
zend_ulong int_key = - 1 ;
zend_string * key = NULL ;
zval * data = NULL ;
ZEND_HASH_FOREACH_KEY_VAL ( options_ht , int_key , key , data ) {
int type = HASH_KEY_NON_EXISTENT ;
size_t key_len = 0 ;
type = key ? HASH_KEY_IS_STRING : HASH_KEY_IS_LONG ;
if ( type ! = HASH_KEY_IS_STRING ) {
CHECK_CUSTOM_ERROR ( true , ctx , SQLSRV_ERROR_INVALID_OPTION_KEY , std : : to_string ( int_key ) . c_str ( ) ) {
throw core : : CoreException ( ) ;
}
}
2017-06-22 23:04:34 +02:00
else if ( key ! = NULL ) {
key_len = ZSTR_LEN ( key ) + 1 ;
2020-04-21 00:17:21 +02:00
add_stmt_option_key ( ctx , key , key_len , ss_stmt_options_ht , data ) ;
2017-06-22 23:04:34 +02:00
}
else {
DIE ( " validate_stmt_options: key was null. " ) ;
}
2017-05-06 02:17:52 +02:00
} ZEND_HASH_FOREACH_END ( ) ;
2016-01-30 03:00:20 +01:00
}
}
catch ( core : : CoreException & ) {
throw ;
}
}
// Iterates through the list of connection options provided by the user and validates them
// against the predefined list of supported connection options by this driver. After validation
// creates a Hashtable of connection options to be sent to the core layer for processing.
2020-04-21 00:17:21 +02:00
void validate_conn_options ( _Inout_ sqlsrv_context & ctx , _In_ zval * user_options_z , _Inout_ char * * uid , _Inout_ char * * pwd , _Inout_ HashTable * ss_conn_options_ht )
2016-01-30 03:00:20 +01:00
{
try {
if ( user_options_z ) {
HashTable * options_ht = Z_ARRVAL_P ( user_options_z ) ;
2017-05-06 02:17:52 +02:00
zend_ulong int_key = - 1 ;
zend_string * key = NULL ;
zval * data = NULL ;
ZEND_HASH_FOREACH_KEY_VAL ( options_ht , int_key , key , data ) {
int type = HASH_KEY_NON_EXISTENT ;
type = key ? HASH_KEY_IS_STRING : HASH_KEY_IS_LONG ;
CHECK_CUSTOM_ERROR ( ( Z_TYPE_P ( data ) = = IS_NULL | | Z_TYPE_P ( data ) = = IS_UNDEF ) , ctx , SS_SQLSRV_ERROR_INVALID_OPTION , key ) {
throw ss : : SSException ( ) ;
}
2016-06-13 23:44:53 +02:00
2017-05-06 02:17:52 +02:00
CHECK_CUSTOM_ERROR ( ( type ! = HASH_KEY_IS_STRING ) , ctx , SS_SQLSRV_ERROR_INVALID_CONNECTION_KEY ) {
throw ss : : SSException ( ) ;
}
2017-06-22 23:04:34 +02:00
if ( key ! = NULL ) {
// Length of the key string does not include the null terminator in PHP7, +1 has to be added
size_t key_len = ZSTR_LEN ( key ) + 1 ;
if ( key_len = = sizeof ( SSConnOptionNames : : UID ) & & ! stricmp ( ZSTR_VAL ( key ) , SSConnOptionNames : : UID ) ) {
2016-06-13 23:44:53 +02:00
2017-06-22 23:04:34 +02:00
* uid = Z_STRVAL_P ( data ) ;
}
2016-01-30 03:00:20 +01:00
2017-06-22 23:04:34 +02:00
else if ( key_len = = sizeof ( SSConnOptionNames : : PWD ) & & ! stricmp ( ZSTR_VAL ( key ) , SSConnOptionNames : : PWD ) ) {
2016-01-30 03:00:20 +01:00
2017-06-22 23:04:34 +02:00
* pwd = Z_STRVAL_P ( data ) ;
}
else {
2016-01-30 03:00:20 +01:00
2020-04-21 00:17:21 +02:00
: : add_conn_option_key ( ctx , key , key_len , ss_conn_options_ht , data ) ;
2017-06-22 23:04:34 +02:00
}
2017-05-06 02:17:52 +02:00
}
else {
2017-06-22 23:04:34 +02:00
DIE ( " validate_conn_options: key was null. " ) ;
2017-05-06 02:17:52 +02:00
}
} ZEND_HASH_FOREACH_END ( ) ;
2016-01-30 03:00:20 +01:00
}
}
catch ( core : : CoreException & ) {
throw ;
}
}
} // namespace