Merge pull request #384 from yitam/azure-ad
Azure AD implementation - preview
This commit is contained in:
commit
d5dcf9b4bc
|
@ -114,9 +114,9 @@ install:
|
|||
- ps: (new-object net.webclient).DownloadFile('http://windows.php.net/downloads/releases/php-' + ${env:PHP_VERSION} + '-src.zip', ${env:APPVEYOR_BUILD_FOLDER} + '\..\php.zip')
|
||||
#- echo Downloading PHP deps [%PHP_DEPSVER%]
|
||||
#- ps: (new-object net.webclient).DownloadFile('http://windows.php.net/downloads/php-sdk/deps-' + ${env:PHP_DEPSVER} + '-vc' + ${env:PHP_VC} + '-' + ${env:BUILD_PLATFORM} + '.7z', ${env:APPVEYOR_BUILD_FOLDER} + '\..\deps.7z')
|
||||
- echo Downloading MSODBCSQL 13
|
||||
- ps: (new-object net.webclient).DownloadFile('https://download.microsoft.com/download/1/E/7/1E7B1181-3974-4B29-9A47-CC857B271AA2/English/' + ${env:BUILD_PLATFORM} + '/msodbcsql.msi', 'msodbcsql.msi')
|
||||
- ps: msiexec /i msodbcsql.msi /quiet /qn /norestart
|
||||
- echo Downloading MSODBCSQL 13.1
|
||||
- ps: (new-object net.webclient).DownloadFile('https://download.microsoft.com/download/D/5/E/D5EEF288-A277-45C8-855B-8E2CB7E25B96/' + ${env:BUILD_PLATFORM} + '/msodbcsql.msi', 'msodbcsql.msi')
|
||||
- ps: msiexec /i msodbcsql.msi /quiet /qn
|
||||
- cd ..
|
||||
- cd
|
||||
- 7z x -y php-sdk-binary-tools-20110915.zip -o%PHP_SDK%
|
||||
|
|
|
@ -41,6 +41,7 @@ const char APP[] = "APP";
|
|||
const char ApplicationIntent[] = "ApplicationIntent";
|
||||
const char AttachDBFileName[] = "AttachDbFileName";
|
||||
const char ConnectionPooling[] = "ConnectionPooling";
|
||||
const char Authentication[] = "Authentication";
|
||||
#ifdef _WIN32
|
||||
const char ConnectRetryCount[] = "ConnectRetryCount";
|
||||
const char ConnectRetryInterval[] = "ConnectRetryInterval";
|
||||
|
@ -200,6 +201,15 @@ const connection_option PDO_CONN_OPTS[] = {
|
|||
CONN_ATTR_STRING,
|
||||
conn_str_append_func::func
|
||||
},
|
||||
{
|
||||
PDOConnOptionNames::Authentication,
|
||||
sizeof( PDOConnOptionNames::Authentication ),
|
||||
SQLSRV_CONN_OPTION_AUTHENTICATION,
|
||||
ODBCConnOptions::Authentication,
|
||||
sizeof( ODBCConnOptions::Authentication ),
|
||||
CONN_ATTR_STRING,
|
||||
conn_str_append_func::func
|
||||
},
|
||||
{
|
||||
PDOConnOptionNames::ConnectionPooling,
|
||||
sizeof( PDOConnOptionNames::ConnectionPooling ),
|
||||
|
|
|
@ -139,7 +139,7 @@ void string_parser::add_key_value_pair( const char* value, int len TSRMLS_DC )
|
|||
void sql_string_parser::add_key_int_value_pair( unsigned int value TSRMLS_DC ) {
|
||||
zval value_z;
|
||||
ZVAL_LONG( &value_z, value );
|
||||
|
||||
|
||||
core::sqlsrv_zend_hash_index_update( *ctx, this->element_ht, this->current_key, &value_z TSRMLS_CC );
|
||||
}
|
||||
|
||||
|
@ -169,6 +169,31 @@ void conn_string_parser::validate_key(const char *key, int key_len TSRMLS_DC )
|
|||
THROW_PDO_ERROR( this->ctx, PDO_SQLSRV_ERROR_INVALID_DSN_KEY, static_cast<char*>( key_name ) );
|
||||
}
|
||||
|
||||
void conn_string_parser::add_key_value_pair( const char* value, int len TSRMLS_DC )
|
||||
{
|
||||
// if the keyword is 'Authentication', check whether the user specified option is supported
|
||||
bool valid = true;
|
||||
if ( stricmp( this->current_key_name, ODBCConnOptions::Authentication ) == 0 ) {
|
||||
if (len <= 0)
|
||||
valid = false;
|
||||
else {
|
||||
// extract option from the value by len
|
||||
sqlsrv_malloc_auto_ptr<char> option;
|
||||
option = static_cast<char*>( sqlsrv_malloc( len + 1 ) );
|
||||
memcpy_s( option, len + 1, value, len );
|
||||
option[len] = '\0';
|
||||
|
||||
valid = core_is_authentication_option_valid( option, len );
|
||||
}
|
||||
}
|
||||
if( !valid ) {
|
||||
THROW_PDO_ERROR( this->ctx, PDO_SQLSRV_ERROR_INVALID_AUTHENTICATION_OPTION, this->current_key_name );
|
||||
}
|
||||
|
||||
string_parser::add_key_value_pair( value, len );
|
||||
}
|
||||
|
||||
|
||||
inline bool sql_string_parser::is_placeholder_char( char c )
|
||||
{
|
||||
// placeholder only accepts numbers, upper and lower case alphabets and underscore
|
||||
|
@ -411,7 +436,7 @@ void sql_string_parser::parse_sql_string( TSRMLS_D ) {
|
|||
start_pos = this->pos;
|
||||
next();
|
||||
// keep going until the next space or line break
|
||||
// while (!is_white_space(this->orig_str[pos]) && !this->is_eos()) {
|
||||
// while (!is_white_space(this->orig_str[pos]) && !this->is_eos()) {
|
||||
while ( is_placeholder_char( this->orig_str[pos] )) {
|
||||
next();
|
||||
}
|
||||
|
|
|
@ -377,6 +377,10 @@ pdo_error PDO_ERRORS[] = {
|
|||
PDO_SQLSRV_ERROR_EMULATE_INOUT_UNSUPPORTED,
|
||||
{ IMSSP, (SQLCHAR*) "Statement with emulate prepare on does not support output or input_output parameters.", -72, false }
|
||||
},
|
||||
{
|
||||
PDO_SQLSRV_ERROR_INVALID_AUTHENTICATION_OPTION,
|
||||
{ IMSSP, (SQLCHAR*) "Invalid option for the Authentication keyword. Only SqlPassword or ActiveDirectoryPassword is supported.", -73, false }
|
||||
},
|
||||
{ UINT_MAX, {} }
|
||||
};
|
||||
|
||||
|
@ -558,15 +562,15 @@ namespace {
|
|||
// Place get_error_message into the anonymous namespace in pdo_util.cpp
|
||||
sqlsrv_error_const* get_error_message(unsigned int sqlsrv_error_code) {
|
||||
|
||||
sqlsrv_error_const *error_message = NULL;
|
||||
int zr = (error_message = reinterpret_cast<sqlsrv_error_const*>(zend_hash_index_find_ptr(g_pdo_errors_ht, sqlsrv_error_code))) != NULL ? SUCCESS : FAILURE;
|
||||
if (zr == FAILURE) {
|
||||
DIE("get_error_message: zend_hash_index_find returned failure for sqlsrv_error_code = %1!d!", sqlsrv_error_code);
|
||||
}
|
||||
sqlsrv_error_const *error_message = NULL;
|
||||
int zr = (error_message = reinterpret_cast<sqlsrv_error_const*>(zend_hash_index_find_ptr(g_pdo_errors_ht, sqlsrv_error_code))) != NULL ? SUCCESS : FAILURE;
|
||||
if (zr == FAILURE) {
|
||||
DIE("get_error_message: zend_hash_index_find returned failure for sqlsrv_error_code = %1!d!", sqlsrv_error_code);
|
||||
}
|
||||
|
||||
SQLSRV_ASSERT(error_message != NULL, "get_error_message: error_message was null");
|
||||
SQLSRV_ASSERT(error_message != NULL, "get_error_message: error_message was null");
|
||||
|
||||
return error_message;
|
||||
return error_message;
|
||||
}
|
||||
|
||||
void pdo_sqlsrv_throw_exception( sqlsrv_error_const* error TSRMLS_DC )
|
||||
|
|
|
@ -165,6 +165,9 @@ class conn_string_parser : private string_parser
|
|||
int discard_trailing_white_spaces(const char* str, int len);
|
||||
void validate_key(const char *key, int key_len TSRMLS_DC);
|
||||
|
||||
protected:
|
||||
void add_key_value_pair(const char* value, int len TSRMLS_DC);
|
||||
|
||||
public:
|
||||
conn_string_parser( sqlsrv_context& ctx, const char* dsn, int len, _Inout_ HashTable* conn_options_ht );
|
||||
void parse_conn_string( TSRMLS_D );
|
||||
|
@ -390,6 +393,7 @@ enum PDO_ERROR_CODES {
|
|||
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
|
||||
};
|
||||
|
||||
extern pdo_error PDO_ERRORS[];
|
||||
|
|
|
@ -92,7 +92,7 @@ void common_conn_str_append_func( const char* odbc_name, const char* val, size_t
|
|||
sqlsrv_conn* core_sqlsrv_connect( sqlsrv_context& henv_cp, sqlsrv_context& henv_ncp, driver_conn_factory conn_factory,
|
||||
const char* server, const char* uid, const char* pwd,
|
||||
HashTable* options_ht, error_callback err, const connection_option valid_conn_opts[],
|
||||
void* driver, const char* driver_func TSRMLS_DC )
|
||||
void* driver, const char* driver_func TSRMLS_DC )
|
||||
|
||||
{
|
||||
SQLRETURN r;
|
||||
|
@ -112,7 +112,7 @@ sqlsrv_conn* core_sqlsrv_connect( sqlsrv_context& henv_cp, sqlsrv_context& henv_
|
|||
// Due to the limitations on connection pooling in unixODBC 2.3.1 driver manager, we do not consider
|
||||
// the connection string attributes to set (enable/disable) connection pooling.
|
||||
// Instead, MSPHPSQL connection pooling is set according to the ODBCINST.INI file in [ODBC] section.
|
||||
|
||||
|
||||
#ifndef _WIN32
|
||||
char pooling_string[ 128 ] = {0};
|
||||
SQLGetPrivateProfileString( "ODBC", "Pooling", "0", pooling_string, sizeof( pooling_string ), "ODBCINST.INI" );
|
||||
|
@ -128,7 +128,7 @@ sqlsrv_conn* core_sqlsrv_connect( sqlsrv_context& henv_cp, sqlsrv_context& henv_
|
|||
// it in build_connection_string_and_set_conn_attr.
|
||||
|
||||
if( options_ht && zend_hash_num_elements( options_ht ) > 0 ) {
|
||||
|
||||
|
||||
zval* option_z = NULL;
|
||||
option_z = zend_hash_index_find(options_ht, SQLSRV_CONN_OPTION_CONN_POOLING);
|
||||
if ( option_z ) {
|
||||
|
@ -163,18 +163,18 @@ sqlsrv_conn* core_sqlsrv_connect( sqlsrv_context& henv_cp, sqlsrv_context& henv_
|
|||
|
||||
SQLSMALLINT output_conn_size;
|
||||
#ifndef _WIN32
|
||||
// unixODBC 2.3.1 requires a non-wide SQLDriverConnect call while pooling enabled.
|
||||
// connection handle has been allocated using henv_cp, means pooling enabled in a PHP script
|
||||
if ( henv == &henv_cp )
|
||||
{
|
||||
r = SQLDriverConnect( conn->handle(), NULL, (SQLCHAR*)conn_str.c_str(), SQL_NTS, NULL, 0, &output_conn_size, SQL_DRIVER_NOPROMPT );
|
||||
}
|
||||
else
|
||||
{
|
||||
r = SQLDriverConnectW( conn->handle(), NULL, reinterpret_cast<SQLWCHAR*>( wconn_string.get() ), static_cast<SQLSMALLINT>( wconn_len ), NULL, 0, &output_conn_size, SQL_DRIVER_NOPROMPT );
|
||||
// unixODBC 2.3.1 requires a non-wide SQLDriverConnect call while pooling enabled.
|
||||
// connection handle has been allocated using henv_cp, means pooling enabled in a PHP script
|
||||
if ( henv == &henv_cp )
|
||||
{
|
||||
r = SQLDriverConnect( conn->handle(), NULL, (SQLCHAR*)conn_str.c_str(), SQL_NTS, NULL, 0, &output_conn_size, SQL_DRIVER_NOPROMPT );
|
||||
}
|
||||
else
|
||||
{
|
||||
r = SQLDriverConnectW( conn->handle(), NULL, reinterpret_cast<SQLWCHAR*>( wconn_string.get() ), static_cast<SQLSMALLINT>( wconn_len ), NULL, 0, &output_conn_size, SQL_DRIVER_NOPROMPT );
|
||||
}
|
||||
#else
|
||||
r = SQLDriverConnectW( conn->handle(), NULL, reinterpret_cast<SQLWCHAR*>( wconn_string.get() ), static_cast<SQLSMALLINT>( wconn_len ), NULL, 0, &output_conn_size, SQL_DRIVER_NOPROMPT );
|
||||
r = SQLDriverConnectW( conn->handle(), NULL, reinterpret_cast<SQLWCHAR*>( wconn_string.get() ), static_cast<SQLSMALLINT>( wconn_len ), NULL, 0, &output_conn_size, SQL_DRIVER_NOPROMPT );
|
||||
#endif // !_WIN32
|
||||
|
||||
// clear the connection string from memory to remove sensitive data (such as a password).
|
||||
|
@ -215,11 +215,11 @@ sqlsrv_conn* core_sqlsrv_connect( sqlsrv_context& henv_cp, sqlsrv_context& henv_
|
|||
// but fails if the connection is using a pool, i.e. r= SQL_SUCCESS.
|
||||
// Thus, in Linux, we don't call determine_server_version() for a connection that uses pool.
|
||||
#ifndef _WIN32
|
||||
if ( r == SQL_SUCCESS_WITH_INFO ) {
|
||||
if ( r == SQL_SUCCESS_WITH_INFO ) {
|
||||
#endif // !_WIN32
|
||||
determine_server_version( conn TSRMLS_CC );
|
||||
#ifndef _WIN32
|
||||
}
|
||||
}
|
||||
#endif // !_WIN32
|
||||
}
|
||||
catch( std::bad_alloc& ) {
|
||||
|
@ -550,6 +550,20 @@ bool core_is_conn_opt_value_escaped( const char* value, size_t value_len )
|
|||
return true;
|
||||
}
|
||||
|
||||
// core_is_authentication_option_valid
|
||||
// if the option for the authentication is valid, returns true. This returns false otherwise.
|
||||
bool core_is_authentication_option_valid(const char* value, size_t value_len)
|
||||
{
|
||||
if (value_len <= 0)
|
||||
return false;
|
||||
|
||||
if( ! stricmp( value, AzureADOptions::AZURE_AUTH_SQL_PASSWORD ) || ! stricmp( value, AzureADOptions::AZURE_AUTH_AD_PASSWORD ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// *** internal connection functions and classes ***
|
||||
|
||||
|
@ -625,33 +639,33 @@ void build_connection_string_and_set_conn_attr( sqlsrv_conn* conn, const char* s
|
|||
if( zend_hash_index_exists( options, SQLSRV_CONN_OPTION_TRACE_FILE )) {
|
||||
|
||||
zval* trace_value = NULL;
|
||||
trace_value = zend_hash_index_find(options, SQLSRV_CONN_OPTION_TRACE_ON);
|
||||
trace_value = zend_hash_index_find(options, SQLSRV_CONN_OPTION_TRACE_ON);
|
||||
|
||||
if (trace_value == NULL || !zend_is_true(trace_value)) {
|
||||
if (trace_value == NULL || !zend_is_true(trace_value)) {
|
||||
|
||||
zend_hash_index_del( options, SQLSRV_CONN_OPTION_TRACE_FILE );
|
||||
}
|
||||
}
|
||||
|
||||
zend_string *key = NULL;
|
||||
zend_ulong index = -1;
|
||||
zval* data = NULL;
|
||||
zend_string *key = NULL;
|
||||
zend_ulong index = -1;
|
||||
zval* data = NULL;
|
||||
|
||||
ZEND_HASH_FOREACH_KEY_VAL( options, index, key, data ) {
|
||||
int type = HASH_KEY_NON_EXISTENT;
|
||||
type = key ? HASH_KEY_IS_STRING : HASH_KEY_IS_LONG;
|
||||
ZEND_HASH_FOREACH_KEY_VAL( options, index, key, data ) {
|
||||
int type = HASH_KEY_NON_EXISTENT;
|
||||
type = key ? HASH_KEY_IS_STRING : HASH_KEY_IS_LONG;
|
||||
|
||||
// The driver layer should ensure a valid key.
|
||||
DEBUG_SQLSRV_ASSERT(( type == HASH_KEY_IS_LONG ), "build_connection_string_and_set_conn_attr: invalid connection option key type." );
|
||||
// The driver layer should ensure a valid key.
|
||||
DEBUG_SQLSRV_ASSERT(( type == HASH_KEY_IS_LONG ), "build_connection_string_and_set_conn_attr: invalid connection option key type." );
|
||||
|
||||
conn_opt = get_connection_option( conn, index, valid_conn_opts TSRMLS_CC );
|
||||
conn_opt = get_connection_option( conn, index, valid_conn_opts TSRMLS_CC );
|
||||
|
||||
if( index == SQLSRV_CONN_OPTION_MARS ) {
|
||||
mars_mentioned = true;
|
||||
}
|
||||
if( index == SQLSRV_CONN_OPTION_MARS ) {
|
||||
mars_mentioned = true;
|
||||
}
|
||||
|
||||
conn_opt->func( conn_opt, data, conn, connection_string TSRMLS_CC );
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
conn_opt->func( conn_opt, data, conn, connection_string TSRMLS_CC );
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
|
||||
// MARS on if not explicitly turned off
|
||||
if( !mars_mentioned ) {
|
||||
|
@ -707,7 +721,7 @@ const char* get_processor_arch( void )
|
|||
return PROCESSOR_ARCH[2];
|
||||
} else {
|
||||
DIE( "Unknown processor architecture." );
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
#else
|
||||
SYSTEM_INFO sys_info;
|
||||
|
@ -727,7 +741,7 @@ const char* get_processor_arch( void )
|
|||
DIE( "Unknown Windows processor architecture." );
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
return NULL;
|
||||
#endif // !_WIN32
|
||||
}
|
||||
|
||||
|
@ -747,7 +761,7 @@ void determine_server_version( sqlsrv_conn* conn TSRMLS_DC )
|
|||
errno = 0;
|
||||
char version_major_str[ 3 ];
|
||||
SERVER_VERSION version_major;
|
||||
memcpy_s( version_major_str, sizeof( version_major_str ), p, 2 );
|
||||
memcpy_s( version_major_str, sizeof( version_major_str ), p, 2 );
|
||||
|
||||
version_major_str[ 2 ] = '\0';
|
||||
version_major = static_cast<SERVER_VERSION>( atoi( version_major_str ));
|
||||
|
@ -817,7 +831,7 @@ size_t core_str_zval_is_true( zval* value_z )
|
|||
}
|
||||
|
||||
// save adjustments to the value made by stripping whitespace at the end
|
||||
Z_STRLEN_P( value_z ) = val_len;
|
||||
Z_STRLEN_P( value_z ) = val_len;
|
||||
|
||||
const char VALID_TRUE_VALUE_1[] = "true";
|
||||
const char VALID_TRUE_VALUE_2[] = "1";
|
||||
|
|
|
@ -180,6 +180,11 @@ const int SQL_SERVER_2005_DEFAULT_DATETIME_SCALE = 3;
|
|||
const int SQL_SERVER_2008_DEFAULT_DATETIME_PRECISION = 34;
|
||||
const int SQL_SERVER_2008_DEFAULT_DATETIME_SCALE = 7;
|
||||
|
||||
namespace AzureADOptions {
|
||||
const char AZURE_AUTH_SQL_PASSWORD[] = "SqlPassword";
|
||||
const char AZURE_AUTH_AD_PASSWORD[] = "ActiveDirectoryPassword";
|
||||
}
|
||||
|
||||
// types for conversions on output parameters (though they can be used for input parameters, they are ignored)
|
||||
enum SQLSRV_PHPTYPE {
|
||||
MIN_SQLSRV_PHPTYPE = 1, // lowest value for a php type
|
||||
|
@ -1077,6 +1082,7 @@ namespace ODBCConnOptions {
|
|||
const char APP[] = "APP";
|
||||
const char ApplicationIntent[] = "ApplicationIntent";
|
||||
const char AttachDBFileName[] = "AttachDbFileName";
|
||||
const char Authentication[] = "Authentication";
|
||||
const char CharacterSet[] = "CharacterSet";
|
||||
const char ConnectionPooling[] = "ConnectionPooling";
|
||||
#ifdef _WIN32
|
||||
|
@ -1121,6 +1127,7 @@ enum SQLSRV_CONN_OPTIONS {
|
|||
SQLSRV_CONN_OPTION_ATTACHDBFILENAME,
|
||||
SQLSRV_CONN_OPTION_APPLICATION_INTENT,
|
||||
SQLSRV_CONN_OPTION_MULTI_SUBNET_FAILOVER,
|
||||
SQLSRV_CONN_OPTION_AUTHENTICATION,
|
||||
#ifdef _WIN32
|
||||
SQLSRV_CONN_OPTION_CONN_RETRY_COUNT,
|
||||
SQLSRV_CONN_OPTION_CONN_RETRY_INTERVAL,
|
||||
|
@ -1190,6 +1197,7 @@ void core_sqlsrv_get_server_version( sqlsrv_conn* conn, _Out_ zval *server_versi
|
|||
void core_sqlsrv_get_client_info( sqlsrv_conn* conn, _Out_ zval *client_info TSRMLS_DC );
|
||||
bool core_is_conn_opt_value_escaped( const char* value, size_t value_len );
|
||||
size_t core_str_zval_is_true( zval* str_zval );
|
||||
bool core_is_authentication_option_valid( const char* value, size_t value_len );
|
||||
|
||||
//*********************************************************************************************************************************
|
||||
// Statement
|
||||
|
|
|
@ -90,7 +90,8 @@
|
|||
#define SQL_COPT_SS_AEKEYSTOREPROVIDER (SQL_COPT_SS_BASE_EX+11) /* Load a keystore provider or read the list of loaded keystore providers */
|
||||
#define SQL_COPT_SS_AEKEYSTOREDATA (SQL_COPT_SS_BASE_EX+12) /* Communicate with a loaded keystore provider */
|
||||
#define SQL_COPT_SS_AETRUSTEDCMKPATHS (SQL_COPT_SS_BASE_EX+13) /* List of trusted CMK paths */
|
||||
#define SQL_COPT_SS_AECEKCACHETTL (SQL_COPT_SS_BASE_EX+14)// Symmetric Key Cache TTL
|
||||
#define SQL_COPT_SS_AECEKCACHETTL (SQL_COPT_SS_BASE_EX+14) /* Symmetric Key Cache TTL */
|
||||
#define SQL_COPT_SS_AUTHENTICATION (SQL_COPT_SS_BASE_EX+15) /* The authentication method used for the connection */
|
||||
|
||||
/*
|
||||
* SQLColAttributes driver specific defines.
|
||||
|
|
|
@ -54,23 +54,23 @@ struct conn_char_set_func {
|
|||
const char* encoding = Z_STRVAL_P( value );
|
||||
size_t encoding_len = Z_STRLEN_P( value );
|
||||
|
||||
zend_ulong index = -1;
|
||||
zend_string* key = NULL;
|
||||
void* ss_encoding_temp = NULL;
|
||||
zend_ulong index = -1;
|
||||
zend_string* key = NULL;
|
||||
void* ss_encoding_temp = NULL;
|
||||
|
||||
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 )) {
|
||||
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 )) {
|
||||
|
||||
if ( ss_encoding->not_for_connection ) {
|
||||
THROW_SS_ERROR( conn, SS_SQLSRV_ERROR_CONNECT_ILLEGAL_ENCODING, encoding );
|
||||
}
|
||||
if ( ss_encoding->not_for_connection ) {
|
||||
THROW_SS_ERROR( conn, SS_SQLSRV_ERROR_CONNECT_ILLEGAL_ENCODING, encoding );
|
||||
}
|
||||
|
||||
conn->set_encoding( static_cast<SQLSRV_ENCODING>(ss_encoding->code_page ));
|
||||
return;
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
conn->set_encoding( static_cast<SQLSRV_ENCODING>(ss_encoding->code_page ));
|
||||
return;
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
|
||||
THROW_SS_ERROR( conn, SS_SQLSRV_ERROR_CONNECT_ILLEGAL_ENCODING, encoding );
|
||||
}
|
||||
|
@ -134,8 +134,8 @@ struct bool_conn_attr_func {
|
|||
static void func( connection_option const* /*option*/, zval* value, sqlsrv_conn* conn, std::string& /*conn_str*/ TSRMLS_DC )
|
||||
{
|
||||
try {
|
||||
core::SQLSetConnectAttr(conn, Attr, reinterpret_cast<SQLPOINTER>((zend_long)zend_is_true(value)),
|
||||
SQL_IS_UINTEGER TSRMLS_CC);
|
||||
core::SQLSetConnectAttr(conn, Attr, reinterpret_cast<SQLPOINTER>((zend_long)zend_is_true(value)),
|
||||
SQL_IS_UINTEGER TSRMLS_CC);
|
||||
|
||||
}
|
||||
catch( core::CoreException& ) {
|
||||
|
@ -186,6 +186,7 @@ const char APP[] = "APP";
|
|||
const char ApplicationIntent[] = "ApplicationIntent";
|
||||
const char AttachDBFileName[] = "AttachDbFileName";
|
||||
const char CharacterSet[] = "CharacterSet";
|
||||
const char Authentication[] = "Authentication";
|
||||
const char ConnectionPooling[] = "ConnectionPooling";
|
||||
#ifdef _WIN32
|
||||
const char ConnectRetryCount[] = "ConnectRetryCount";
|
||||
|
@ -220,25 +221,25 @@ const stmt_option SS_STMT_OPTS[] = {
|
|||
SSStmtOptionNames::QUERY_TIMEOUT,
|
||||
sizeof( SSStmtOptionNames::QUERY_TIMEOUT ),
|
||||
SQLSRV_STMT_OPTION_QUERY_TIMEOUT,
|
||||
std::unique_ptr<stmt_option_query_timeout>( new stmt_option_query_timeout )
|
||||
std::unique_ptr<stmt_option_query_timeout>( new stmt_option_query_timeout )
|
||||
},
|
||||
{
|
||||
SSStmtOptionNames::SEND_STREAMS_AT_EXEC,
|
||||
sizeof( SSStmtOptionNames::SEND_STREAMS_AT_EXEC ),
|
||||
SQLSRV_STMT_OPTION_SEND_STREAMS_AT_EXEC,
|
||||
std::unique_ptr<stmt_option_send_at_exec>( new stmt_option_send_at_exec )
|
||||
std::unique_ptr<stmt_option_send_at_exec>( new stmt_option_send_at_exec )
|
||||
},
|
||||
{
|
||||
SSStmtOptionNames::SCROLLABLE,
|
||||
sizeof( SSStmtOptionNames::SCROLLABLE ),
|
||||
SQLSRV_STMT_OPTION_SCROLLABLE,
|
||||
std::unique_ptr<stmt_option_ss_scrollable>( new stmt_option_ss_scrollable )
|
||||
std::unique_ptr<stmt_option_ss_scrollable>( new stmt_option_ss_scrollable )
|
||||
},
|
||||
{
|
||||
SSStmtOptionNames::CLIENT_BUFFER_MAX_SIZE,
|
||||
sizeof( SSStmtOptionNames::CLIENT_BUFFER_MAX_SIZE ),
|
||||
SQLSRV_STMT_OPTION_CLIENT_BUFFER_MAX_SIZE,
|
||||
std::unique_ptr<stmt_option_buffered_query_limit>( new stmt_option_buffered_query_limit )
|
||||
std::unique_ptr<stmt_option_buffered_query_limit>( new stmt_option_buffered_query_limit )
|
||||
},
|
||||
{ NULL, 0, SQLSRV_STMT_OPTION_INVALID, std::unique_ptr<stmt_option_functor>{} },
|
||||
};
|
||||
|
@ -282,6 +283,15 @@ const connection_option SS_CONN_OPTS[] = {
|
|||
CONN_ATTR_STRING,
|
||||
conn_char_set_func::func
|
||||
},
|
||||
{
|
||||
SSConnOptionNames::Authentication,
|
||||
sizeof( SSConnOptionNames::Authentication ),
|
||||
SQLSRV_CONN_OPTION_AUTHENTICATION,
|
||||
ODBCConnOptions::Authentication,
|
||||
sizeof( ODBCConnOptions::Authentication ),
|
||||
CONN_ATTR_STRING,
|
||||
conn_str_append_func::func
|
||||
},
|
||||
{
|
||||
SSConnOptionNames::ConnectionPooling,
|
||||
sizeof( SSConnOptionNames::ConnectionPooling ),
|
||||
|
@ -503,11 +513,11 @@ PHP_FUNCTION ( sqlsrv_connect )
|
|||
|
||||
// register the connection with the PHP runtime
|
||||
|
||||
ss::zend_register_resource(conn_z, conn, ss_sqlsrv_conn::descriptor, ss_sqlsrv_conn::resource_name TSRMLS_CC);
|
||||
ss::zend_register_resource(conn_z, conn, ss_sqlsrv_conn::descriptor, ss_sqlsrv_conn::resource_name TSRMLS_CC);
|
||||
|
||||
conn->stmts = stmts;
|
||||
stmts.transferred();
|
||||
RETURN_RES( Z_RES(conn_z) );
|
||||
RETURN_RES( Z_RES(conn_z) );
|
||||
}
|
||||
|
||||
catch( core::CoreException& ) {
|
||||
|
@ -607,7 +617,7 @@ PHP_FUNCTION( sqlsrv_close )
|
|||
|
||||
try {
|
||||
|
||||
// dummy context to pass to the error handler
|
||||
// dummy context to pass to the error handler
|
||||
error_ctx = new (sqlsrv_malloc( sizeof( sqlsrv_context ))) sqlsrv_context( 0, ss_error_handler, NULL );
|
||||
SET_FUNCTION_NAME( *error_ctx );
|
||||
|
||||
|
@ -618,7 +628,7 @@ PHP_FUNCTION( sqlsrv_close )
|
|||
CHECK_CUSTOM_ERROR(( zr == FAILURE ), error_ctx, SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER, _FN_ ) {
|
||||
throw ss::SSException();
|
||||
}
|
||||
|
||||
|
||||
// if sqlsrv_close was called on a non-existent connection then we just return success.
|
||||
if( Z_TYPE_P( conn_r ) == IS_NULL ) {
|
||||
RETURN_TRUE;
|
||||
|
@ -630,31 +640,31 @@ PHP_FUNCTION( sqlsrv_close )
|
|||
|
||||
conn = static_cast<ss_sqlsrv_conn*>( zend_fetch_resource( Z_RES_P( conn_r ) TSRMLS_CC, ss_sqlsrv_conn::resource_name, ss_sqlsrv_conn::descriptor ));
|
||||
|
||||
// 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_ ) {
|
||||
|
||||
// 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_ ) {
|
||||
|
||||
throw ss::SSException();
|
||||
}
|
||||
|
||||
SET_FUNCTION_NAME( *conn );
|
||||
|
||||
|
||||
// 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.
|
||||
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 ));
|
||||
}
|
||||
|
||||
ZVAL_NULL( conn_r );
|
||||
|
||||
ZVAL_NULL( conn_r );
|
||||
|
||||
RETURN_TRUE;
|
||||
}
|
||||
catch( core::CoreException& ) {
|
||||
|
||||
|
||||
RETURN_FALSE;
|
||||
}
|
||||
catch( ... ) {
|
||||
|
@ -937,10 +947,10 @@ PHP_FUNCTION( sqlsrv_prepare )
|
|||
|
||||
core_sqlsrv_prepare( stmt, sql, sql_len TSRMLS_CC );
|
||||
|
||||
if (params_z) {
|
||||
stmt->params_z = (zval *)sqlsrv_malloc(sizeof(zval));
|
||||
ZVAL_COPY(stmt->params_z, params_z);
|
||||
}
|
||||
if (params_z) {
|
||||
stmt->params_z = (zval *)sqlsrv_malloc(sizeof(zval));
|
||||
ZVAL_COPY(stmt->params_z, params_z);
|
||||
}
|
||||
|
||||
stmt->prepared = true;
|
||||
|
||||
|
@ -1021,7 +1031,7 @@ PHP_FUNCTION( sqlsrv_query )
|
|||
hash_auto_ptr ss_stmt_options_ht;
|
||||
size_t sql_len = 0;
|
||||
zval* options_z = NULL;
|
||||
zval* params_z = NULL;
|
||||
zval* params_z = NULL;
|
||||
zval stmt_z;
|
||||
ZVAL_UNDEF(&stmt_z);
|
||||
|
||||
|
@ -1058,8 +1068,8 @@ PHP_FUNCTION( sqlsrv_query )
|
|||
ss_error_handler, NULL TSRMLS_CC ) );
|
||||
|
||||
if( params_z ) {
|
||||
stmt->params_z = (zval *)sqlsrv_malloc(sizeof(zval));
|
||||
ZVAL_COPY(stmt->params_z, params_z);
|
||||
stmt->params_z = (zval *)sqlsrv_malloc(sizeof(zval));
|
||||
ZVAL_COPY(stmt->params_z, params_z);
|
||||
}
|
||||
|
||||
stmt->set_func( "sqlsrv_query" );
|
||||
|
@ -1073,7 +1083,7 @@ PHP_FUNCTION( sqlsrv_query )
|
|||
ss::zend_register_resource(stmt_z, stmt, ss_sqlsrv_stmt::descriptor, ss_sqlsrv_stmt::resource_name TSRMLS_CC);
|
||||
// store the resource id with the connection so the connection
|
||||
// can release this statement when it closes.
|
||||
zend_ulong next_index = zend_hash_next_free_element( conn->stmts );
|
||||
zend_ulong next_index = zend_hash_next_free_element( conn->stmts );
|
||||
|
||||
core::sqlsrv_zend_hash_index_update(*conn, conn->stmts, next_index, &stmt_z TSRMLS_CC);
|
||||
stmt->conn_index = next_index;
|
||||
|
@ -1103,7 +1113,7 @@ PHP_FUNCTION( sqlsrv_query )
|
|||
|
||||
void free_stmt_resource( zval* stmt_z TSRMLS_DC )
|
||||
{
|
||||
if( FAILURE == zend_list_close( Z_RES_P( stmt_z ))) {
|
||||
if( FAILURE == zend_list_close( Z_RES_P( stmt_z ))) {
|
||||
LOG(SEV_ERROR, "Failed to remove stmt resource %1!d!", Z_RES_HANDLE_P(stmt_z));
|
||||
}
|
||||
ZVAL_NULL( stmt_z );
|
||||
|
@ -1127,31 +1137,31 @@ void sqlsrv_conn_close_stmts( ss_sqlsrv_conn* conn TSRMLS_DC )
|
|||
// loop through the stmts hash table and destroy each stmt resource so we can close the
|
||||
// ODBC connection
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
// 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.
|
||||
|
@ -1205,6 +1215,17 @@ int get_conn_option_key( sqlsrv_context& ctx, zend_string* key, size_t key_len,
|
|||
|
||||
throw ss::SSException();
|
||||
}
|
||||
|
||||
bool valid = true;
|
||||
if( stricmp( SS_CONN_OPTS[i].sqlsrv_name, SSConnOptionNames::Authentication ) == 0 ) {
|
||||
valid = core_is_authentication_option_valid( value, value_len );
|
||||
}
|
||||
|
||||
CHECK_CUSTOM_ERROR( !valid, ctx, SS_SQLSRV_ERROR_INVALID_AUTHENTICATION_OPTION, SS_CONN_OPTS[ i ].sqlsrv_name ) {
|
||||
|
||||
throw ss::SSException();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1263,23 +1284,23 @@ void validate_stmt_options( sqlsrv_context& ctx, zval* stmt_options, _Inout_ Has
|
|||
if( stmt_options ) {
|
||||
|
||||
HashTable* options_ht = Z_ARRVAL_P( stmt_options );
|
||||
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;
|
||||
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;
|
||||
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();
|
||||
}
|
||||
}
|
||||
key_len = ZSTR_LEN(key) + 1;
|
||||
add_stmt_option_key( ctx, key, key_len, ss_stmt_options_ht, data TSRMLS_CC );
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
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();
|
||||
}
|
||||
}
|
||||
key_len = ZSTR_LEN(key) + 1;
|
||||
add_stmt_option_key( ctx, key, key_len, ss_stmt_options_ht, data TSRMLS_CC );
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
}
|
||||
}
|
||||
catch( core::CoreException& ) {
|
||||
|
@ -1299,37 +1320,37 @@ void validate_conn_options( sqlsrv_context& ctx, zval* user_options_z, _Out_ cha
|
|||
if( user_options_z ) {
|
||||
|
||||
HashTable* options_ht = Z_ARRVAL_P( user_options_z );
|
||||
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;
|
||||
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();
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
CHECK_CUSTOM_ERROR(( type != HASH_KEY_IS_STRING ), ctx, SS_SQLSRV_ERROR_INVALID_CONNECTION_KEY ) {
|
||||
throw ss::SSException();
|
||||
}
|
||||
CHECK_CUSTOM_ERROR(( type != HASH_KEY_IS_STRING ), ctx, SS_SQLSRV_ERROR_INVALID_CONNECTION_KEY ) {
|
||||
throw ss::SSException();
|
||||
}
|
||||
|
||||
// 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 )) {
|
||||
// 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 )) {
|
||||
|
||||
*uid = Z_STRVAL_P( data );
|
||||
}
|
||||
*uid = Z_STRVAL_P( data );
|
||||
}
|
||||
|
||||
else if( key_len == sizeof( SSConnOptionNames::PWD ) && !stricmp( ZSTR_VAL( key ), SSConnOptionNames::PWD )) {
|
||||
else if( key_len == sizeof( SSConnOptionNames::PWD ) && !stricmp( ZSTR_VAL( key ), SSConnOptionNames::PWD )) {
|
||||
|
||||
*pwd = Z_STRVAL_P( data );
|
||||
}
|
||||
else {
|
||||
*pwd = Z_STRVAL_P( data );
|
||||
}
|
||||
else {
|
||||
|
||||
::add_conn_option_key( ctx, key, key_len, ss_conn_options_ht, data TSRMLS_CC );
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
::add_conn_option_key( ctx, key, key_len, ss_conn_options_ht, data TSRMLS_CC );
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
}
|
||||
}
|
||||
catch( core::CoreException& ) {
|
||||
|
|
|
@ -352,7 +352,8 @@ enum SS_ERROR_CODES {
|
|||
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_PARAM_VAR_NOT_REF,
|
||||
SS_SQLSRV_ERROR_INVALID_AUTHENTICATION_OPTION
|
||||
};
|
||||
|
||||
extern ss_error SS_ERRORS[];
|
||||
|
|
|
@ -366,6 +366,10 @@ ss_error SS_ERRORS[] = {
|
|||
"Output or bidirectional variable parameters (SQLSRV_PARAM_OUT and SQLSRV_PARAM_INOUT) passed to sqlsrv_prepare or sqlsrv_query should be passed by reference, not by value."
|
||||
, -61, true }
|
||||
},
|
||||
{
|
||||
SS_SQLSRV_ERROR_INVALID_AUTHENTICATION_OPTION,
|
||||
{ IMSSP, (SQLCHAR*)"Invalid option for the Authentication keyword. Only SqlPassword or ActiveDirectoryPassword is supported.", -62, false }
|
||||
},
|
||||
|
||||
// internal warning definitions
|
||||
{
|
||||
|
|
63
test/pdo_sqlsrv/pdo_azure_ad_authentication.phpt
Normal file
63
test/pdo_sqlsrv/pdo_azure_ad_authentication.phpt
Normal file
|
@ -0,0 +1,63 @@
|
|||
--TEST--
|
||||
Test the Authentication keyword with options SqlPassword and ActiveDirectoryIntegrated.
|
||||
--SKIPIF--
|
||||
|
||||
--FILE--
|
||||
<?php
|
||||
require_once("autonomous_setup.php");
|
||||
|
||||
$connectionInfo = " Authentication = SqlPassword; TrustServerCertificate = true;";
|
||||
|
||||
try
|
||||
{
|
||||
$conn = new PDO( "sqlsrv:server = $serverName ; $connectionInfo", $username, $password );
|
||||
echo "Connected successfully with Authentication=SqlPassword.\n";
|
||||
}
|
||||
catch( PDOException $e )
|
||||
{
|
||||
echo "Could not connect with Authentication=SqlPassword.\n";
|
||||
print_r( $e->getMessage() );
|
||||
echo "\n";
|
||||
}
|
||||
|
||||
$stmt = $conn->query( "SELECT name FROM master.dbo.sysdatabases" );
|
||||
if ( $stmt === false )
|
||||
{
|
||||
echo "Query failed.\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$first_db = $stmt->fetch();
|
||||
var_dump( $first_db );
|
||||
}
|
||||
|
||||
$conn = null;
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
$connectionInfo = "Authentication = ActiveDirectoryIntegrated; TrustServerCertificate = true;";
|
||||
|
||||
try
|
||||
{
|
||||
$conn = new PDO( "sqlsrv:server = $serverName ; $connectionInfo" );
|
||||
echo "Connected successfully with Authentication=ActiveDirectoryIntegrated.\n";
|
||||
$conn = null;
|
||||
}
|
||||
catch( PDOException $e )
|
||||
{
|
||||
echo "Could not connect with Authentication=ActiveDirectoryIntegrated.\n";
|
||||
print_r( $e->getMessage() );
|
||||
echo "\n";
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Connected successfully with Authentication=SqlPassword.
|
||||
array(2) {
|
||||
["name"]=>
|
||||
string(6) "master"
|
||||
[0]=>
|
||||
string(6) "master"
|
||||
}
|
||||
Could not connect with Authentication=ActiveDirectoryIntegrated.
|
||||
SQLSTATE[IMSSP]: Invalid option for the Authentication keyword. Only SqlPassword or ActiveDirectoryPassword is supported.
|
72
test/sqlsrv/sqlsrv_azure_ad_authentication.phpt
Normal file
72
test/sqlsrv/sqlsrv_azure_ad_authentication.phpt
Normal file
|
@ -0,0 +1,72 @@
|
|||
--TEST--
|
||||
Test the Authentication keyword with options SqlPassword and ActiveDirectoryIntegrated.
|
||||
--SKIPIF--
|
||||
|
||||
--FILE--
|
||||
<?php
|
||||
require_once("autonomous_setup.php");
|
||||
|
||||
if (strtoupper(substr(PHP_OS, 0, 3)) != 'WIN')
|
||||
{
|
||||
$connectionInfo = array( "UID"=>$username, "PWD"=>$password,
|
||||
"Authentication"=>"SqlPassword", "TrustServerCertificate"=>true );
|
||||
|
||||
$conn = sqlsrv_connect( $serverName, $connectionInfo );
|
||||
|
||||
if( $conn === false )
|
||||
{
|
||||
echo "Could not connect with Authentication=SqlPassword.\n";
|
||||
print_r( sqlsrv_errors() );
|
||||
}
|
||||
// else
|
||||
// {
|
||||
// echo "Connected successfully with Authentication=SqlPassword.\n";
|
||||
// }
|
||||
|
||||
$stmt = sqlsrv_query( $conn, "SELECT name FROM master.dbo.sysdatabases" );
|
||||
if ( $stmt === false )
|
||||
{
|
||||
echo "Query failed.\n";
|
||||
}
|
||||
// else
|
||||
// {
|
||||
// $first_db = sqlsrv_fetch_array( $stmt );
|
||||
// var_dump( $first_db );
|
||||
// }
|
||||
|
||||
sqlsrv_free_stmt( $stmt );
|
||||
sqlsrv_close( $conn );
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
$connectionInfo = array( "Authentication"=>"ActiveDirectoryIntegrated", "TrustServerCertificate"=>true );
|
||||
|
||||
$conn = sqlsrv_connect( $serverName, $connectionInfo );
|
||||
if( $conn === false )
|
||||
{
|
||||
echo "Could not connect with Authentication=ActiveDirectoryIntegrated.\n";
|
||||
print_r( sqlsrv_errors() );
|
||||
}
|
||||
else
|
||||
{
|
||||
echo "Connected successfully with Authentication=ActiveDirectoryIntegrated.\n";
|
||||
sqlsrv_close( $conn );
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Could not connect with Authentication=ActiveDirectoryIntegrated.
|
||||
Array
|
||||
(
|
||||
[0] => Array
|
||||
(
|
||||
[0] => IMSSP
|
||||
[SQLSTATE] => IMSSP
|
||||
[1] => -62
|
||||
[code] => -62
|
||||
[2] => Invalid option for the Authentication keyword. Only SqlPassword or ActiveDirectoryPassword is supported.
|
||||
[message] => Invalid option for the Authentication keyword. Only SqlPassword or ActiveDirectoryPassword is supported.
|
||||
)
|
||||
|
||||
)
|
Loading…
Reference in a new issue