RC release code
This commit is contained in:
parent
3dd0ebaa44
commit
de040a9327
|
@ -42,7 +42,7 @@ const int INFO_BUFFER_LEN = 256;
|
|||
const char* PROCESSOR_ARCH[] = { "x86", "x64", "ia64" };
|
||||
|
||||
// ODBC driver name.
|
||||
const char CONNECTION_STRING_DRIVER_NAME[] = "Driver={ODBC Driver 11 for SQL Server};";
|
||||
const char* CONNECTION_STRING_DRIVER_NAME[] = {"Driver={ODBC Driver 13 for SQL Server};", "Driver={ODBC Driver 11 for SQL Server};"};
|
||||
|
||||
// default options if only the server is specified
|
||||
const char CONNECTION_STRING_DEFAULT_OPTIONS[] = "Mars_Connection={Yes}";
|
||||
|
@ -124,7 +124,8 @@ sqlsrv_conn* core_sqlsrv_connect( sqlsrv_context& henv_cp, sqlsrv_context& henv_
|
|||
conn = conn_factory( temp_conn_h, err, driver TSRMLS_CC );
|
||||
conn->set_func( driver_func );
|
||||
|
||||
|
||||
for ( std::size_t i = DRIVER_VERSION::MIN; i <= DRIVER_VERSION::MAX; ++i ) {
|
||||
conn_str = CONNECTION_STRING_DRIVER_NAME[i];
|
||||
build_connection_string_and_set_conn_attr( conn, server, uid, pwd, options_ht, valid_conn_opts, driver,
|
||||
conn_str TSRMLS_CC );
|
||||
|
||||
|
@ -151,11 +152,20 @@ sqlsrv_conn* core_sqlsrv_connect( sqlsrv_context& henv_cp, sqlsrv_context& henv_
|
|||
SQLCHAR state[SQL_SQLSTATE_BUFSIZE];
|
||||
SQLSMALLINT len;
|
||||
SQLRETURN r = SQLGetDiagField( SQL_HANDLE_DBC, conn->handle(), 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len );
|
||||
bool missing_driver_error = ( SQL_SUCCEEDED( r ) && state[0] == 'I' && state[1] == 'M' && state[2] == '0' && state[3] == '0' &&
|
||||
state[4] == '2' );
|
||||
// if it's a IM002, meaning that the correct ODBC driver is not installed
|
||||
CHECK_CUSTOM_ERROR( SQL_SUCCEEDED( r ) && state[0] == 'I' && state[1] == 'M' && state[2] == '0' && state[3] == '0' &&
|
||||
state[4] == '2', conn, SQLSRV_ERROR_DRIVER_NOT_INSTALLED, get_processor_arch() ) {
|
||||
CHECK_CUSTOM_ERROR( missing_driver_error && ( i == DRIVER_VERSION::MAX ), conn, SQLSRV_ERROR_DRIVER_NOT_INSTALLED, get_processor_arch()) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
if ( !missing_driver_error ) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
conn->driver_version = static_cast<DRIVER_VERSION>( i );
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
CHECK_SQL_ERROR( r, conn ) {
|
||||
throw core::CoreException();
|
||||
|
@ -533,8 +543,6 @@ void build_connection_string_and_set_conn_attr( sqlsrv_conn* conn, const char* s
|
|||
|
||||
try {
|
||||
|
||||
connection_string = CONNECTION_STRING_DRIVER_NAME;
|
||||
|
||||
// Add the server name
|
||||
common_conn_str_append_func( ODBCConnOptions::SERVER, server, strlen( server ), connection_string TSRMLS_CC );
|
||||
|
||||
|
@ -586,22 +594,17 @@ void build_connection_string_and_set_conn_attr( sqlsrv_conn* conn, const char* s
|
|||
}
|
||||
}
|
||||
|
||||
for( zend_hash_internal_pointer_reset( options );
|
||||
zend_hash_has_more_elements( options ) == SUCCESS;
|
||||
zend_hash_move_forward( options )) {
|
||||
|
||||
int type = HASH_KEY_NON_EXISTENT;
|
||||
zend_string *key = NULL;
|
||||
zend_ulong index = 0;
|
||||
zend_ulong index = -1;
|
||||
zval* data = NULL;
|
||||
|
||||
type = zend_hash_get_current_key( options, &key, &index );
|
||||
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." );
|
||||
|
||||
core::sqlsrv_zend_hash_get_current_data( *conn, options, data TSRMLS_CC );
|
||||
|
||||
conn_opt = get_connection_option( conn, index, valid_conn_opts TSRMLS_CC );
|
||||
|
||||
if( index == SQLSRV_CONN_OPTION_MARS ) {
|
||||
|
@ -609,7 +612,7 @@ void build_connection_string_and_set_conn_attr( sqlsrv_conn* conn, const char* s
|
|||
}
|
||||
|
||||
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 ) {
|
||||
|
@ -755,7 +758,7 @@ size_t core_str_zval_is_true( zval* value_z )
|
|||
}
|
||||
|
||||
// save adjustments to the value made by stripping whitespace at the end
|
||||
core::sqlsrv_zval_stringl( value_z, value_in, val_len);
|
||||
Z_STRLEN_P( value_z ) = val_len;
|
||||
|
||||
const char VALID_TRUE_VALUE_1[] = "true";
|
||||
const char VALID_TRUE_VALUE_2[] = "1";
|
||||
|
|
|
@ -970,6 +970,14 @@ enum SERVER_VERSION {
|
|||
SERVER_VERSION_2008, // use this for anything 2008 or later
|
||||
};
|
||||
|
||||
// supported driver versions.
|
||||
enum DRIVER_VERSION : size_t {
|
||||
MIN = 0,
|
||||
ODBC_DRIVER_13 = MIN,
|
||||
ODBC_DRIVER_11 = 1,
|
||||
MAX = ODBC_DRIVER_11,
|
||||
};
|
||||
|
||||
// forward decl
|
||||
struct sqlsrv_stmt;
|
||||
struct stmt_option;
|
||||
|
@ -981,6 +989,8 @@ struct sqlsrv_conn : public sqlsrv_context {
|
|||
// instance variables
|
||||
SERVER_VERSION server_version; // version of the server that we're connected to
|
||||
|
||||
DRIVER_VERSION driver_version;
|
||||
|
||||
// initialize with default values
|
||||
sqlsrv_conn( SQLHANDLE h, error_callback e, void* drv, SQLSRV_ENCODING encoding TSRMLS_DC ) :
|
||||
sqlsrv_context( h, SQL_HANDLE_DBC, e, drv, encoding )
|
||||
|
@ -1258,7 +1268,7 @@ struct sqlsrv_stmt : public sqlsrv_context {
|
|||
unsigned int current_stream_read; // # of bytes read so far. (if we read an empty PHP stream, we send an empty string
|
||||
// to the server)
|
||||
zval field_cache; // cache for a single row of fields, to allow multiple and out of order retrievals
|
||||
zval* active_stream; // the currently active stream reading data from the database
|
||||
zval active_stream; // the currently active stream reading data from the database
|
||||
|
||||
sqlsrv_stmt( sqlsrv_conn* c, SQLHANDLE handle, error_callback e, void* drv TSRMLS_DC );
|
||||
virtual ~sqlsrv_stmt( void );
|
||||
|
@ -1313,7 +1323,7 @@ void core_sqlsrv_execute( sqlsrv_stmt* stmt TSRMLS_DC, const char* sql = NULL, i
|
|||
field_meta_data* core_sqlsrv_field_metadata( sqlsrv_stmt* stmt, SQLSMALLINT colno TSRMLS_DC );
|
||||
bool core_sqlsrv_fetch( sqlsrv_stmt* stmt, SQLSMALLINT fetch_orientation, SQLULEN fetch_offset TSRMLS_DC );
|
||||
void core_sqlsrv_get_field(sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_phptype sqlsrv_phptype, bool prefer_string,
|
||||
__out void** field_value, __out SQLLEN* field_length, bool cache_field,
|
||||
__out void*& field_value, __out SQLLEN* field_length, bool cache_field,
|
||||
__out SQLSRV_PHPTYPE *sqlsrv_php_type_out TSRMLS_DC);
|
||||
bool core_sqlsrv_has_any_result( sqlsrv_stmt* stmt TSRMLS_DC );
|
||||
void core_sqlsrv_next_result( sqlsrv_stmt* stmt TSRMLS_DC, bool finalize_output_params = true, bool throw_on_errors = true );
|
||||
|
@ -1325,6 +1335,7 @@ void core_sqlsrv_set_send_at_exec( sqlsrv_stmt* stmt, zval* value_z TSRMLS_DC );
|
|||
bool core_sqlsrv_send_stream_packet( sqlsrv_stmt* stmt TSRMLS_DC );
|
||||
void core_sqlsrv_set_buffered_query_limit( sqlsrv_stmt* stmt, zval* value_z TSRMLS_DC );
|
||||
void core_sqlsrv_set_buffered_query_limit( sqlsrv_stmt* stmt, SQLLEN limit TSRMLS_DC );
|
||||
void core_finalize_output_parameters(sqlsrv_stmt* stmt TSRMLS_DC);
|
||||
|
||||
|
||||
//*********************************************************************************************************************************
|
||||
|
@ -1564,8 +1575,8 @@ enum SQLSRV_ERROR_CODES {
|
|||
};
|
||||
|
||||
// the message returned by ODBC Driver 11 for SQL Server
|
||||
const char CONNECTION_BUSY_ODBC_ERROR[] = "[Microsoft][ODBC Driver 11 for SQL Server]Connection is busy with results for "
|
||||
"another command";
|
||||
static const char* CONNECTION_BUSY_ODBC_ERROR[] = { "[Microsoft][ODBC Driver 13 for SQL Server]Connection is busy with results for another command",
|
||||
"[Microsoft][ODBC Driver 11 for SQL Server]Connection is busy with results for another command" };
|
||||
|
||||
// SQLSTATE for all internal errors
|
||||
extern SQLCHAR IMSSP[];
|
||||
|
@ -1742,9 +1753,9 @@ namespace core {
|
|||
|
||||
throw CoreException();
|
||||
}
|
||||
|
||||
if(( len == sizeof( CONNECTION_BUSY_ODBC_ERROR ) - 1 ) &&
|
||||
!strcmp( reinterpret_cast<const char*>( err_msg ), CONNECTION_BUSY_ODBC_ERROR )) {
|
||||
std::size_t driver_version = stmt->conn->driver_version;
|
||||
if(( len == sizeof( CONNECTION_BUSY_ODBC_ERROR[driver_version] ) - 1 ) &&
|
||||
!strcmp( reinterpret_cast<const char*>( err_msg ), CONNECTION_BUSY_ODBC_ERROR[driver_version] )) {
|
||||
|
||||
THROW_CORE_ERROR( stmt, SQLSRV_ERROR_MARS_OFF );
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ size_t calc_utf8_missing( sqlsrv_stmt* stmt, const char* buffer, size_t buffer_e
|
|||
bool check_for_next_stream_parameter( sqlsrv_stmt* stmt TSRMLS_DC );
|
||||
bool convert_input_param_to_utf16( zval* input_param_z, zval* convert_param_z );
|
||||
void core_get_field_common(__inout sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_phptype
|
||||
sqlsrv_php_type, __out void** field_value, __out SQLLEN* field_len TSRMLS_DC );
|
||||
sqlsrv_php_type, __out void*& field_value, __out SQLLEN* field_len TSRMLS_DC);
|
||||
// returns the ODBC C type constant that matches the PHP type and encoding given
|
||||
SQLSMALLINT default_c_type( sqlsrv_stmt* stmt, SQLULEN paramno, zval const* param_z, SQLSRV_ENCODING encoding TSRMLS_DC );
|
||||
void default_sql_size_and_scale( sqlsrv_stmt* stmt, unsigned int paramno, zval* param_z, SQLSRV_ENCODING encoding,
|
||||
|
@ -92,7 +92,7 @@ void default_sql_type( sqlsrv_stmt* stmt, SQLULEN paramno, zval* param_z, SQLSRV
|
|||
void field_cache_dtor( zval* data_z );
|
||||
void finalize_output_parameters( sqlsrv_stmt* stmt TSRMLS_DC );
|
||||
void get_field_as_string( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_phptype sqlsrv_php_type,
|
||||
__out void** field_value, __out SQLLEN* field_len TSRMLS_DC );
|
||||
__out void*& field_value, __out SQLLEN* field_len TSRMLS_DC );
|
||||
stmt_option const* get_stmt_option( sqlsrv_conn const* conn, zend_ulong key, const stmt_option stmt_opts[] TSRMLS_DC );
|
||||
bool is_valid_sqlsrv_phptype( sqlsrv_phptype type );
|
||||
// assure there is enough space for the output parameter string
|
||||
|
@ -127,9 +127,9 @@ sqlsrv_stmt::sqlsrv_stmt( sqlsrv_conn* c, SQLHANDLE handle, error_callback e, vo
|
|||
current_stream( NULL, SQLSRV_ENCODING_DEFAULT ),
|
||||
current_stream_read( 0 ),
|
||||
query_timeout( QUERY_TIMEOUT_INVALID ),
|
||||
buffered_query_limit( sqlsrv_buffered_result_set::BUFFERED_QUERY_LIMIT_INVALID ),
|
||||
active_stream( NULL )
|
||||
buffered_query_limit( sqlsrv_buffered_result_set::BUFFERED_QUERY_LIMIT_INVALID )
|
||||
{
|
||||
ZVAL_UNDEF( &active_stream );
|
||||
// initialize the input string parameters array (which holds zvals)
|
||||
core::sqlsrv_array_init( *conn, ¶m_input_strings TSRMLS_CC );
|
||||
|
||||
|
@ -152,7 +152,7 @@ sqlsrv_stmt::sqlsrv_stmt( sqlsrv_conn* c, SQLHANDLE handle, error_callback e, vo
|
|||
// desctructor for sqlsrv statement.
|
||||
sqlsrv_stmt::~sqlsrv_stmt( void )
|
||||
{
|
||||
if( active_stream ) {
|
||||
if( Z_TYPE( active_stream ) != IS_UNDEF ) {
|
||||
TSRMLS_FETCH();
|
||||
close_active_stream( this TSRMLS_CC );
|
||||
}
|
||||
|
@ -248,21 +248,17 @@ sqlsrv_stmt* core_sqlsrv_create_stmt( sqlsrv_conn* conn, driver_stmt_factory stm
|
|||
|
||||
// process the options array given to core_sqlsrv_prepare.
|
||||
if( options_ht && zend_hash_num_elements( options_ht ) > 0 ) {
|
||||
for( zend_hash_internal_pointer_reset( options_ht );
|
||||
zend_hash_has_more_elements( options_ht ) == SUCCESS;
|
||||
zend_hash_move_forward( options_ht )) {
|
||||
|
||||
zend_string *key = NULL;
|
||||
zend_ulong index = -1;
|
||||
zend_string *key = NULL;
|
||||
zval* value_z = NULL;
|
||||
|
||||
int type = zend_hash_get_current_key( options_ht, &key, &index);
|
||||
ZEND_HASH_FOREACH_KEY_VAL( options_ht, index, key, value_z ) {
|
||||
|
||||
int 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 ), "allocate_stmt: Invalid statment option key provided." );
|
||||
|
||||
core::sqlsrv_zend_hash_get_current_data( *(stmt->conn), options_ht, value_z TSRMLS_CC );
|
||||
|
||||
const stmt_option* stmt_opt = get_stmt_option( stmt->conn, index, valid_stmt_opts TSRMLS_CC );
|
||||
|
||||
// if the key didn't match, then return the error to the script.
|
||||
|
@ -271,9 +267,7 @@ sqlsrv_stmt* core_sqlsrv_create_stmt( sqlsrv_conn* conn, driver_stmt_factory stm
|
|||
|
||||
// perform the actions the statement option needs done.
|
||||
(*stmt_opt->func)( stmt, stmt_opt, value_z TSRMLS_CC );
|
||||
}
|
||||
|
||||
zend_hash_internal_pointer_end( options_ht );
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
}
|
||||
|
||||
sqlsrv_stmt* return_stmt = stmt;
|
||||
|
@ -658,13 +652,13 @@ void core_sqlsrv_bind_param(sqlsrv_stmt* stmt, SQLUSMALLINT param_num, SQLSMALLI
|
|||
|
||||
void core_sqlsrv_execute( sqlsrv_stmt* stmt TSRMLS_DC, const char* sql, int sql_len )
|
||||
{
|
||||
SQLRETURN r;
|
||||
|
||||
try {
|
||||
|
||||
// close the stream to release the resource
|
||||
close_active_stream( stmt TSRMLS_CC );
|
||||
|
||||
SQLRETURN r;
|
||||
|
||||
if( sql ) {
|
||||
|
||||
sqlsrv_malloc_auto_ptr<wchar_t> wsql_string;
|
||||
|
@ -705,8 +699,9 @@ void core_sqlsrv_execute( sqlsrv_stmt* stmt TSRMLS_DC, const char* sql, int sql_
|
|||
finalize_output_parameters( stmt TSRMLS_CC );
|
||||
}
|
||||
// stream parameters are sent, clean the Hashtable
|
||||
if ( stmt->send_streams_at_exec ) {
|
||||
zend_hash_clean( Z_ARRVAL( stmt->param_streams ));
|
||||
|
||||
}
|
||||
}
|
||||
catch( core::CoreException& e ) {
|
||||
|
||||
|
@ -869,7 +864,7 @@ field_meta_data* core_sqlsrv_field_metadata( sqlsrv_stmt* stmt, SQLSMALLINT coln
|
|||
// Nothing, excpetion thrown if an error occurs
|
||||
|
||||
void core_sqlsrv_get_field( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_phptype sqlsrv_php_type_in, bool prefer_string,
|
||||
__out void** field_value, __out SQLLEN* field_len, bool cache_field,
|
||||
__out void*& field_value, __out SQLLEN* field_len, bool cache_field,
|
||||
__out SQLSRV_PHPTYPE *sqlsrv_php_type_out TSRMLS_DC)
|
||||
{
|
||||
try {
|
||||
|
@ -879,20 +874,20 @@ void core_sqlsrv_get_field( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_
|
|||
|
||||
// if the field has been retrieved before, return the previous result
|
||||
field_cache* cached = NULL;
|
||||
if (NULL != (cached = reinterpret_cast<field_cache*>(zend_hash_index_find_ptr(Z_ARRVAL(stmt->field_cache), static_cast<zend_ulong>(field_index))))) {
|
||||
if (NULL != ( cached = static_cast<field_cache*>( zend_hash_index_find_ptr( Z_ARRVAL( stmt->field_cache ), static_cast<zend_ulong>( field_index ))))) {
|
||||
// the field value is NULL
|
||||
if( cached->value == NULL ) {
|
||||
*field_value = NULL;
|
||||
field_value = NULL;
|
||||
*field_len = 0;
|
||||
if( sqlsrv_php_type_out ) { *sqlsrv_php_type_out = SQLSRV_PHPTYPE_NULL; }
|
||||
}
|
||||
else {
|
||||
|
||||
*field_value = sqlsrv_malloc( cached->len, sizeof( char ), 1 );
|
||||
memcpy( *field_value, cached->value, cached->len );
|
||||
field_value = sqlsrv_malloc( cached->len, sizeof( char ), 1 );
|
||||
memcpy( field_value, cached->value, cached->len );
|
||||
if( cached->type.typeinfo.type == SQLSRV_PHPTYPE_STRING) {
|
||||
// prevent the 'string not null terminated' warning
|
||||
reinterpret_cast<char*>( *field_value )[ cached->len ] = '\0';
|
||||
reinterpret_cast<char*>( field_value )[ cached->len ] = '\0';
|
||||
}
|
||||
*field_len = cached->len;
|
||||
if( sqlsrv_php_type_out) { *sqlsrv_php_type_out = static_cast<SQLSRV_PHPTYPE>(cached->type.typeinfo.type); }
|
||||
|
@ -921,9 +916,9 @@ void core_sqlsrv_get_field( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_
|
|||
core_sqlsrv_get_field( stmt, i, invalid, prefer_string, field_value, field_len, cache_field,
|
||||
sqlsrv_php_type_out TSRMLS_CC );
|
||||
// delete the value returned since we only want it cached, not the actual value
|
||||
if( *field_value ) {
|
||||
efree( *field_value );
|
||||
*field_value = NULL;
|
||||
if( field_value ) {
|
||||
efree( field_value );
|
||||
field_value = NULL;
|
||||
*field_len = 0;
|
||||
}
|
||||
}
|
||||
|
@ -955,7 +950,7 @@ void core_sqlsrv_get_field( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_
|
|||
|
||||
// if the user wants us to cache the field, we'll do it
|
||||
if( cache_field ) {
|
||||
field_cache cache( *field_value, *field_len, sqlsrv_php_type );
|
||||
field_cache cache( field_value, *field_len, sqlsrv_php_type );
|
||||
core::sqlsrv_zend_hash_index_update_mem( *stmt, Z_ARRVAL( stmt->field_cache ), field_index, &cache, sizeof(field_cache) TSRMLS_CC );
|
||||
}
|
||||
}
|
||||
|
@ -1304,6 +1299,9 @@ bool core_sqlsrv_send_stream_packet( sqlsrv_stmt* stmt TSRMLS_DC )
|
|||
return true;
|
||||
}
|
||||
|
||||
void core_finalize_output_parameters(sqlsrv_stmt* stmt TSRMLS_DC) {
|
||||
finalize_output_parameters(stmt TSRMLS_CC);
|
||||
}
|
||||
|
||||
void stmt_option_functor::operator()( sqlsrv_stmt* /*stmt*/, stmt_option const* /*opt*/, zval* /*value_z*/ TSRMLS_DC )
|
||||
{
|
||||
|
@ -1334,20 +1332,20 @@ void stmt_option_buffered_query_limit:: operator()( sqlsrv_stmt* stmt, stmt_opti
|
|||
void close_active_stream( __inout sqlsrv_stmt* stmt TSRMLS_DC )
|
||||
{
|
||||
// if there is no active stream, return
|
||||
if( stmt->active_stream == NULL ) {
|
||||
if( Z_TYPE( stmt->active_stream ) == IS_UNDEF ) {
|
||||
return;
|
||||
}
|
||||
|
||||
php_stream* stream = NULL;
|
||||
|
||||
// we use no verify since verify would return immediately and we want to assert, not return.
|
||||
php_stream_from_zval_no_verify( stream, stmt->active_stream );
|
||||
php_stream_from_zval_no_verify( stream, &( stmt->active_stream ));
|
||||
|
||||
SQLSRV_ASSERT(( stream != NULL ), "close_active_stream: Unknown resource type as our active stream." );
|
||||
|
||||
php_stream_close( stream ); // this will NULL out the active stream in the statement. We don't check for errors here.
|
||||
|
||||
SQLSRV_ASSERT( stmt->active_stream == NULL, "close_active_stream: Active stream not closed." );
|
||||
SQLSRV_ASSERT( Z_TYPE( stmt->active_stream ) == IS_UNDEF, "close_active_stream: Active stream not closed." );
|
||||
|
||||
}
|
||||
|
||||
|
@ -1471,7 +1469,7 @@ size_t calc_utf8_missing( sqlsrv_stmt* stmt, const char* buffer, size_t buffer_e
|
|||
// the driver layer would have to calculate size of the field_value
|
||||
// to decide the amount of memory allocation.
|
||||
void core_get_field_common( __inout sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_phptype
|
||||
sqlsrv_php_type, __out void** field_value, __out SQLLEN* field_len TSRMLS_DC )
|
||||
sqlsrv_php_type, __out void*& field_value, __out SQLLEN* field_len TSRMLS_DC )
|
||||
{
|
||||
try {
|
||||
|
||||
|
@ -1507,11 +1505,11 @@ void core_get_field_common( __inout sqlsrv_stmt* stmt, SQLUSMALLINT field_index,
|
|||
}
|
||||
|
||||
if( *field_len == SQL_NULL_DATA ) {
|
||||
*field_value = NULL;
|
||||
field_value = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
*field_value = field_value_temp;
|
||||
field_value = field_value_temp;
|
||||
field_value_temp.transferred();
|
||||
break;
|
||||
}
|
||||
|
@ -1533,11 +1531,11 @@ void core_get_field_common( __inout sqlsrv_stmt* stmt, SQLUSMALLINT field_index,
|
|||
}
|
||||
|
||||
if( *field_len == SQL_NULL_DATA ) {
|
||||
*field_value = NULL;
|
||||
field_value = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
*field_value = field_value_temp;
|
||||
field_value = field_value_temp;
|
||||
field_value_temp.transferred();
|
||||
break;
|
||||
}
|
||||
|
@ -1573,7 +1571,7 @@ void core_get_field_common( __inout sqlsrv_stmt* stmt, SQLUSMALLINT field_index,
|
|||
|
||||
if( *field_len == SQL_NULL_DATA ) {
|
||||
ZVAL_NULL( return_value_z );
|
||||
*field_value = reinterpret_cast<void*>( return_value_z.get() );
|
||||
field_value = reinterpret_cast<void*>( return_value_z.get());
|
||||
return_value_z.transferred();
|
||||
break;
|
||||
}
|
||||
|
@ -1588,8 +1586,10 @@ void core_get_field_common( __inout sqlsrv_stmt* stmt, SQLUSMALLINT field_index,
|
|||
THROW_CORE_ERROR(stmt, SQLSRV_ERROR_DATETIME_CONVERSION_FAILED);
|
||||
}
|
||||
|
||||
*field_value = reinterpret_cast<void*>( return_value_z.get() );
|
||||
field_value = reinterpret_cast<void*>( return_value_z.get());
|
||||
return_value_z.transferred();
|
||||
zend_string_free( Z_STR( field_value_temp_z ));
|
||||
zend_string_free( Z_STR( function_z ));
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1630,15 +1630,13 @@ void core_get_field_common( __inout sqlsrv_stmt* stmt, SQLUSMALLINT field_index,
|
|||
// turn our stream into a zval to be returned
|
||||
php_stream_to_zval( stream, return_value_z );
|
||||
|
||||
// mark this as our active stream
|
||||
stmt->active_stream = return_value_z;
|
||||
*field_value = reinterpret_cast<void*>( return_value_z.get() );
|
||||
field_value = reinterpret_cast<void*>( return_value_z.get());
|
||||
return_value_z.transferred();
|
||||
break;
|
||||
}
|
||||
|
||||
case SQLSRV_PHPTYPE_NULL:
|
||||
*field_value = NULL;
|
||||
field_value = NULL;
|
||||
*field_len = 0;
|
||||
break;
|
||||
|
||||
|
@ -1956,11 +1954,12 @@ void finalize_output_parameters( sqlsrv_stmt* stmt TSRMLS_DC )
|
|||
|
||||
bool converted = true;
|
||||
HashTable* params_ht = Z_ARRVAL( stmt->output_params );
|
||||
for( zend_hash_internal_pointer_reset( params_ht );
|
||||
zend_hash_has_more_elements( params_ht ) == SUCCESS;
|
||||
zend_hash_move_forward( params_ht ) ) {
|
||||
sqlsrv_output_param* output_param = NULL;
|
||||
core::sqlsrv_zend_hash_get_current_data_ptr(*stmt, params_ht, (void*&) output_param TSRMLS_CC);
|
||||
zend_ulong index = -1;
|
||||
zend_string* key = NULL;
|
||||
void* output_param_temp = NULL;
|
||||
|
||||
ZEND_HASH_FOREACH_KEY_PTR( params_ht, index, key, output_param_temp ) {
|
||||
sqlsrv_output_param* output_param = static_cast<sqlsrv_output_param*>( output_param_temp );
|
||||
zval* value_z = Z_REFVAL_P( output_param->param_z );
|
||||
switch( Z_TYPE_P( value_z )) {
|
||||
case IS_STRING:
|
||||
|
@ -2037,7 +2036,7 @@ void finalize_output_parameters( sqlsrv_stmt* stmt TSRMLS_DC )
|
|||
break;
|
||||
}
|
||||
value_z = NULL;
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
|
||||
// empty the hash table since it's been processed
|
||||
zend_hash_clean( Z_ARRVAL( stmt->output_params ));
|
||||
|
@ -2045,7 +2044,7 @@ void finalize_output_parameters( sqlsrv_stmt* stmt TSRMLS_DC )
|
|||
}
|
||||
|
||||
void get_field_as_string( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_phptype sqlsrv_php_type,
|
||||
__out void** field_value, __out SQLLEN* field_len TSRMLS_DC )
|
||||
__out void*& field_value, __out SQLLEN* field_len TSRMLS_DC )
|
||||
{
|
||||
SQLRETURN r;
|
||||
SQLSMALLINT c_type;
|
||||
|
@ -2102,7 +2101,7 @@ void get_field_as_string( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_ph
|
|||
}
|
||||
|
||||
if( field_len_temp == SQL_NULL_DATA ) {
|
||||
*field_value = NULL;
|
||||
field_value = NULL;
|
||||
sqlsrv_free( field_value_temp );
|
||||
return;
|
||||
}
|
||||
|
@ -2167,7 +2166,7 @@ void get_field_as_string( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_ph
|
|||
true /*handle_warning*/ TSRMLS_CC );
|
||||
|
||||
if( dummy_field_len == SQL_NULL_DATA ) {
|
||||
*field_value = NULL;
|
||||
field_value = NULL;
|
||||
sqlsrv_free( field_value_temp );
|
||||
return;
|
||||
}
|
||||
|
@ -2226,7 +2225,7 @@ void get_field_as_string( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_ph
|
|||
}
|
||||
|
||||
if( field_len_temp == SQL_NULL_DATA ) {
|
||||
*field_value = NULL;
|
||||
field_value = NULL;
|
||||
sqlsrv_free( field_value_temp );
|
||||
return;
|
||||
}
|
||||
|
@ -2248,7 +2247,7 @@ void get_field_as_string( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_ph
|
|||
return; // to eliminate a warning
|
||||
}
|
||||
|
||||
*field_value = field_value_temp;
|
||||
field_value = field_value_temp;
|
||||
*field_len = field_len_temp;
|
||||
|
||||
// prevent a warning in debug mode about strings not being NULL terminated. Even though nulls are not necessary, the PHP
|
||||
|
@ -2260,14 +2259,14 @@ void get_field_as_string( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_ph
|
|||
|
||||
catch( core::CoreException& ) {
|
||||
|
||||
*field_value = NULL;
|
||||
field_value = NULL;
|
||||
*field_len = 0;
|
||||
sqlsrv_free( field_value_temp );
|
||||
throw;
|
||||
}
|
||||
catch ( ... ) {
|
||||
|
||||
*field_value = NULL;
|
||||
field_value = NULL;
|
||||
*field_len = 0;
|
||||
sqlsrv_free( field_value_temp );
|
||||
throw;
|
||||
|
|
|
@ -32,11 +32,8 @@ int sqlsrv_stream_close( php_stream* stream, int /*close_handle*/ TSRMLS_DC )
|
|||
// free the stream resources in the Zend engine
|
||||
php_stream_free( stream, PHP_STREAM_FREE_RELEASE_STREAM );
|
||||
|
||||
// NULL out the stream zval and delete our reference count to it.
|
||||
ZVAL_NULL( ss->stmt->active_stream );
|
||||
|
||||
// there is no active stream
|
||||
ss->stmt->active_stream = NULL;
|
||||
// UNDEF the stream zval and delete our reference count to it.
|
||||
ZVAL_UNDEF( &( ss->stmt->active_stream ) );
|
||||
|
||||
sqlsrv_free( ss );
|
||||
stream->abstract = NULL;
|
||||
|
|
|
@ -463,6 +463,8 @@ int pdo_sqlsrv_db_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC)
|
|||
|
||||
dbh->error_mode = prev_err_mode; // reset the error mode
|
||||
|
||||
g_henv_cp->invalidate();
|
||||
|
||||
return 0;
|
||||
}
|
||||
catch( ... ) {
|
||||
|
@ -1310,25 +1312,20 @@ void validate_stmt_options( sqlsrv_context& ctx, zval* stmt_options, __inout Has
|
|||
if( stmt_options ) {
|
||||
|
||||
HashTable* options_ht = Z_ARRVAL_P( stmt_options );
|
||||
|
||||
for( zend_hash_internal_pointer_reset( options_ht ); zend_hash_has_more_elements( options_ht ) == SUCCESS;
|
||||
zend_hash_move_forward( options_ht )) {
|
||||
|
||||
int type = HASH_KEY_NON_EXISTENT;
|
||||
zend_string *key = NULL;
|
||||
size_t int_key = -1;
|
||||
zval* data;
|
||||
int result = 0;
|
||||
zend_string *key = NULL;
|
||||
zval* data = NULL;
|
||||
|
||||
type = zend_hash_get_current_key( options_ht, &key, &int_key);
|
||||
ZEND_HASH_FOREACH_KEY_VAL( options_ht, int_key, key, data ) {
|
||||
int type = HASH_KEY_NON_EXISTENT;
|
||||
int result = 0;
|
||||
type = key ? HASH_KEY_IS_STRING : HASH_KEY_IS_LONG;
|
||||
CHECK_CUSTOM_ERROR(( type != HASH_KEY_IS_LONG ), ctx, PDO_SQLSRV_ERROR_INVALID_STMT_OPTION ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
core::sqlsrv_zend_hash_get_current_data( ctx, options_ht, data TSRMLS_CC );
|
||||
|
||||
add_stmt_option_key( ctx, int_key, pdo_stmt_options_ht, data TSRMLS_CC );
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
}
|
||||
}
|
||||
catch( core::CoreException& ) {
|
||||
|
|
|
@ -743,9 +743,15 @@ int pdo_sqlsrv_stmt_get_col_data(pdo_stmt_t *stmt, int colno,
|
|||
}
|
||||
|
||||
SQLSRV_PHPTYPE sqlsrv_phptype_out = SQLSRV_PHPTYPE_INVALID;
|
||||
core_sqlsrv_get_field( driver_stmt, colno, sqlsrv_php_type, false, reinterpret_cast<void**>( ptr ),
|
||||
core_sqlsrv_get_field( driver_stmt, colno, sqlsrv_php_type, false, *(reinterpret_cast<void**>(ptr)),
|
||||
reinterpret_cast<SQLLEN*>( len ), true, &sqlsrv_phptype_out TSRMLS_CC );
|
||||
zval* zval_ptr = reinterpret_cast<zval*>( sqlsrv_malloc( sizeof( zval )));
|
||||
|
||||
// if the current column is the last fetch column, finalize output params
|
||||
if ( stmt->column_count == colno + 1 ) {
|
||||
core_finalize_output_parameters( driver_stmt TSRMLS_CC );
|
||||
}
|
||||
|
||||
zval* zval_ptr = ( zval* )( sqlsrv_malloc( sizeof( zval )));
|
||||
*zval_ptr = convert_to_zval( sqlsrv_phptype_out, reinterpret_cast<void**>( ptr ), *len );
|
||||
*ptr = reinterpret_cast<char*>( zval_ptr );
|
||||
|
||||
|
|
|
@ -57,13 +57,13 @@ struct conn_char_set_func {
|
|||
const char* encoding = Z_STRVAL_P( value );
|
||||
size_t encoding_len = Z_STRLEN_P( value );
|
||||
|
||||
for( zend_hash_internal_pointer_reset( g_ss_encodings_ht );
|
||||
zend_hash_has_more_elements( g_ss_encodings_ht ) == SUCCESS;
|
||||
zend_hash_move_forward( g_ss_encodings_ht )) {
|
||||
|
||||
sqlsrv_encoding* ss_encoding = NULL;
|
||||
core::sqlsrv_zend_hash_get_current_data_ptr( *conn, g_ss_encodings_ht,(void*&) ss_encoding TSRMLS_CC );
|
||||
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 )) {
|
||||
|
||||
if ( ss_encoding->not_for_connection ) {
|
||||
|
@ -73,7 +73,7 @@ struct conn_char_set_func {
|
|||
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 );
|
||||
}
|
||||
|
@ -1062,8 +1062,7 @@ PHP_FUNCTION( sqlsrv_query )
|
|||
|
||||
void free_stmt_resource( zval* stmt_z TSRMLS_DC )
|
||||
{
|
||||
int zr = zend_list_close(Z_RES_P(stmt_z));
|
||||
if( zr == FAILURE ) {
|
||||
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 );
|
||||
|
@ -1086,21 +1085,18 @@ 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
|
||||
for( zend_hash_internal_pointer_reset( conn->stmts );
|
||||
zend_hash_has_more_elements( conn->stmts ) == SUCCESS;
|
||||
zend_hash_move_forward( conn->stmts )) {
|
||||
|
||||
zval* rsrc_ptr = NULL;
|
||||
|
||||
ZEND_HASH_FOREACH_VAL( conn->stmts, rsrc_ptr ) {
|
||||
try {
|
||||
// get the resource id for the next statement created with this connection
|
||||
core::sqlsrv_zend_hash_get_current_data( *conn, conn->stmts, rsrc_ptr TSRMLS_CC );
|
||||
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
|
||||
|
@ -1113,7 +1109,6 @@ void sqlsrv_conn_close_stmts( ss_sqlsrv_conn* conn TSRMLS_DC )
|
|||
" 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;
|
||||
|
||||
|
@ -1124,7 +1119,7 @@ void sqlsrv_conn_close_stmts( ss_sqlsrv_conn* conn TSRMLS_DC )
|
|||
catch( core::CoreException& ) {
|
||||
LOG(SEV_ERROR, "Failed to remove statement resource %1!d! when closing the connection", Z_RES_HANDLE_P(rsrc_ptr));
|
||||
}
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
|
||||
zend_hash_destroy( conn->stmts );
|
||||
FREE_HASHTABLE( conn->stmts );
|
||||
|
@ -1230,20 +1225,17 @@ void validate_stmt_options( sqlsrv_context& ctx, zval* stmt_options, __inout Has
|
|||
if( stmt_options ) {
|
||||
|
||||
HashTable* options_ht = Z_ARRVAL_P( stmt_options );
|
||||
|
||||
for( zend_hash_internal_pointer_reset( options_ht ); zend_hash_has_more_elements( options_ht ) == SUCCESS;
|
||||
zend_hash_move_forward( options_ht )) {
|
||||
|
||||
int type = HASH_KEY_NON_EXISTENT;
|
||||
zend_string *key = NULL;
|
||||
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;
|
||||
zval* conn_opt = NULL;
|
||||
int result = 0;
|
||||
|
||||
type = zend_hash_get_current_key(options_ht, &key, &int_key);
|
||||
key_len = ZSTR_LEN( key ) + 1;
|
||||
type = key ? HASH_KEY_IS_STRING : HASH_KEY_IS_LONG;
|
||||
|
||||
if( type != HASH_KEY_IS_STRING ) {
|
||||
std::ostringstream itoa;
|
||||
|
@ -1252,9 +1244,8 @@ void validate_stmt_options( sqlsrv_context& ctx, zval* stmt_options, __inout Has
|
|||
throw core::CoreException();
|
||||
}
|
||||
}
|
||||
core::sqlsrv_zend_hash_get_current_data( ctx, options_ht, data TSRMLS_CC );
|
||||
add_stmt_option_key( ctx, key, key_len, ss_stmt_options_ht, data TSRMLS_CC );
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
}
|
||||
}
|
||||
catch( core::CoreException& ) {
|
||||
|
@ -1274,23 +1265,21 @@ 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 );
|
||||
|
||||
for( zend_hash_internal_pointer_reset( options_ht ); zend_hash_has_more_elements( options_ht ) == SUCCESS;
|
||||
zend_hash_move_forward( options_ht )) {
|
||||
|
||||
int type = HASH_KEY_NON_EXISTENT;
|
||||
zend_string *key = NULL;
|
||||
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;
|
||||
|
||||
type = zend_hash_get_current_key(options_ht, &key, &int_key);
|
||||
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();
|
||||
}
|
||||
|
||||
core::sqlsrv_zend_hash_get_current_data( ctx, options_ht, data TSRMLS_CC );
|
||||
|
||||
// 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 )) {
|
||||
|
@ -1306,7 +1295,7 @@ void validate_conn_options( sqlsrv_context& ctx, zval* user_options_z, __out cha
|
|||
|
||||
::add_conn_option_key( ctx, key, key_len, ss_conn_options_ht, data TSRMLS_CC );
|
||||
}
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
}
|
||||
}
|
||||
catch( core::CoreException& ) {
|
||||
|
|
|
@ -42,7 +42,7 @@ const int INFO_BUFFER_LEN = 256;
|
|||
const char* PROCESSOR_ARCH[] = { "x86", "x64", "ia64" };
|
||||
|
||||
// ODBC driver name.
|
||||
const char CONNECTION_STRING_DRIVER_NAME[] = "Driver={ODBC Driver 11 for SQL Server};";
|
||||
const char* CONNECTION_STRING_DRIVER_NAME[] = {"Driver={ODBC Driver 13 for SQL Server};", "Driver={ODBC Driver 11 for SQL Server};"};
|
||||
|
||||
// default options if only the server is specified
|
||||
const char CONNECTION_STRING_DEFAULT_OPTIONS[] = "Mars_Connection={Yes}";
|
||||
|
@ -124,7 +124,8 @@ sqlsrv_conn* core_sqlsrv_connect( sqlsrv_context& henv_cp, sqlsrv_context& henv_
|
|||
conn = conn_factory( temp_conn_h, err, driver TSRMLS_CC );
|
||||
conn->set_func( driver_func );
|
||||
|
||||
|
||||
for ( std::size_t i = DRIVER_VERSION::MIN; i <= DRIVER_VERSION::MAX; ++i ) {
|
||||
conn_str = CONNECTION_STRING_DRIVER_NAME[i];
|
||||
build_connection_string_and_set_conn_attr( conn, server, uid, pwd, options_ht, valid_conn_opts, driver,
|
||||
conn_str TSRMLS_CC );
|
||||
|
||||
|
@ -151,11 +152,20 @@ sqlsrv_conn* core_sqlsrv_connect( sqlsrv_context& henv_cp, sqlsrv_context& henv_
|
|||
SQLCHAR state[SQL_SQLSTATE_BUFSIZE];
|
||||
SQLSMALLINT len;
|
||||
SQLRETURN r = SQLGetDiagField( SQL_HANDLE_DBC, conn->handle(), 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len );
|
||||
bool missing_driver_error = ( SQL_SUCCEEDED( r ) && state[0] == 'I' && state[1] == 'M' && state[2] == '0' && state[3] == '0' &&
|
||||
state[4] == '2' );
|
||||
// if it's a IM002, meaning that the correct ODBC driver is not installed
|
||||
CHECK_CUSTOM_ERROR( SQL_SUCCEEDED( r ) && state[0] == 'I' && state[1] == 'M' && state[2] == '0' && state[3] == '0' &&
|
||||
state[4] == '2', conn, SQLSRV_ERROR_DRIVER_NOT_INSTALLED, get_processor_arch() ) {
|
||||
CHECK_CUSTOM_ERROR( missing_driver_error && ( i == DRIVER_VERSION::MAX ), conn, SQLSRV_ERROR_DRIVER_NOT_INSTALLED, get_processor_arch()) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
if ( !missing_driver_error ) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
conn->driver_version = static_cast<DRIVER_VERSION>( i );
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
CHECK_SQL_ERROR( r, conn ) {
|
||||
throw core::CoreException();
|
||||
|
@ -533,8 +543,6 @@ void build_connection_string_and_set_conn_attr( sqlsrv_conn* conn, const char* s
|
|||
|
||||
try {
|
||||
|
||||
connection_string = CONNECTION_STRING_DRIVER_NAME;
|
||||
|
||||
// Add the server name
|
||||
common_conn_str_append_func( ODBCConnOptions::SERVER, server, strlen( server ), connection_string TSRMLS_CC );
|
||||
|
||||
|
@ -586,22 +594,17 @@ void build_connection_string_and_set_conn_attr( sqlsrv_conn* conn, const char* s
|
|||
}
|
||||
}
|
||||
|
||||
for( zend_hash_internal_pointer_reset( options );
|
||||
zend_hash_has_more_elements( options ) == SUCCESS;
|
||||
zend_hash_move_forward( options )) {
|
||||
|
||||
int type = HASH_KEY_NON_EXISTENT;
|
||||
zend_string *key = NULL;
|
||||
zend_ulong index = 0;
|
||||
zend_ulong index = -1;
|
||||
zval* data = NULL;
|
||||
|
||||
type = zend_hash_get_current_key( options, &key, &index );
|
||||
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." );
|
||||
|
||||
core::sqlsrv_zend_hash_get_current_data( *conn, options, data TSRMLS_CC );
|
||||
|
||||
conn_opt = get_connection_option( conn, index, valid_conn_opts TSRMLS_CC );
|
||||
|
||||
if( index == SQLSRV_CONN_OPTION_MARS ) {
|
||||
|
@ -609,7 +612,7 @@ void build_connection_string_and_set_conn_attr( sqlsrv_conn* conn, const char* s
|
|||
}
|
||||
|
||||
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 ) {
|
||||
|
@ -755,7 +758,7 @@ size_t core_str_zval_is_true( zval* value_z )
|
|||
}
|
||||
|
||||
// save adjustments to the value made by stripping whitespace at the end
|
||||
core::sqlsrv_zval_stringl( value_z, value_in, val_len);
|
||||
Z_STRLEN_P( value_z ) = val_len;
|
||||
|
||||
const char VALID_TRUE_VALUE_1[] = "true";
|
||||
const char VALID_TRUE_VALUE_2[] = "1";
|
||||
|
|
|
@ -970,6 +970,14 @@ enum SERVER_VERSION {
|
|||
SERVER_VERSION_2008, // use this for anything 2008 or later
|
||||
};
|
||||
|
||||
// supported driver versions.
|
||||
enum DRIVER_VERSION : size_t {
|
||||
MIN = 0,
|
||||
ODBC_DRIVER_13 = MIN,
|
||||
ODBC_DRIVER_11 = 1,
|
||||
MAX = ODBC_DRIVER_11,
|
||||
};
|
||||
|
||||
// forward decl
|
||||
struct sqlsrv_stmt;
|
||||
struct stmt_option;
|
||||
|
@ -981,6 +989,8 @@ struct sqlsrv_conn : public sqlsrv_context {
|
|||
// instance variables
|
||||
SERVER_VERSION server_version; // version of the server that we're connected to
|
||||
|
||||
DRIVER_VERSION driver_version;
|
||||
|
||||
// initialize with default values
|
||||
sqlsrv_conn( SQLHANDLE h, error_callback e, void* drv, SQLSRV_ENCODING encoding TSRMLS_DC ) :
|
||||
sqlsrv_context( h, SQL_HANDLE_DBC, e, drv, encoding )
|
||||
|
@ -1258,7 +1268,7 @@ struct sqlsrv_stmt : public sqlsrv_context {
|
|||
unsigned int current_stream_read; // # of bytes read so far. (if we read an empty PHP stream, we send an empty string
|
||||
// to the server)
|
||||
zval field_cache; // cache for a single row of fields, to allow multiple and out of order retrievals
|
||||
zval* active_stream; // the currently active stream reading data from the database
|
||||
zval active_stream; // the currently active stream reading data from the database
|
||||
|
||||
sqlsrv_stmt( sqlsrv_conn* c, SQLHANDLE handle, error_callback e, void* drv TSRMLS_DC );
|
||||
virtual ~sqlsrv_stmt( void );
|
||||
|
@ -1313,7 +1323,7 @@ void core_sqlsrv_execute( sqlsrv_stmt* stmt TSRMLS_DC, const char* sql = NULL, i
|
|||
field_meta_data* core_sqlsrv_field_metadata( sqlsrv_stmt* stmt, SQLSMALLINT colno TSRMLS_DC );
|
||||
bool core_sqlsrv_fetch( sqlsrv_stmt* stmt, SQLSMALLINT fetch_orientation, SQLULEN fetch_offset TSRMLS_DC );
|
||||
void core_sqlsrv_get_field(sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_phptype sqlsrv_phptype, bool prefer_string,
|
||||
__out void** field_value, __out SQLLEN* field_length, bool cache_field,
|
||||
__out void*& field_value, __out SQLLEN* field_length, bool cache_field,
|
||||
__out SQLSRV_PHPTYPE *sqlsrv_php_type_out TSRMLS_DC);
|
||||
bool core_sqlsrv_has_any_result( sqlsrv_stmt* stmt TSRMLS_DC );
|
||||
void core_sqlsrv_next_result( sqlsrv_stmt* stmt TSRMLS_DC, bool finalize_output_params = true, bool throw_on_errors = true );
|
||||
|
@ -1325,6 +1335,7 @@ void core_sqlsrv_set_send_at_exec( sqlsrv_stmt* stmt, zval* value_z TSRMLS_DC );
|
|||
bool core_sqlsrv_send_stream_packet( sqlsrv_stmt* stmt TSRMLS_DC );
|
||||
void core_sqlsrv_set_buffered_query_limit( sqlsrv_stmt* stmt, zval* value_z TSRMLS_DC );
|
||||
void core_sqlsrv_set_buffered_query_limit( sqlsrv_stmt* stmt, SQLLEN limit TSRMLS_DC );
|
||||
void core_finalize_output_parameters(sqlsrv_stmt* stmt TSRMLS_DC);
|
||||
|
||||
|
||||
//*********************************************************************************************************************************
|
||||
|
@ -1564,8 +1575,8 @@ enum SQLSRV_ERROR_CODES {
|
|||
};
|
||||
|
||||
// the message returned by ODBC Driver 11 for SQL Server
|
||||
const char CONNECTION_BUSY_ODBC_ERROR[] = "[Microsoft][ODBC Driver 11 for SQL Server]Connection is busy with results for "
|
||||
"another command";
|
||||
static const char* CONNECTION_BUSY_ODBC_ERROR[] = { "[Microsoft][ODBC Driver 13 for SQL Server]Connection is busy with results for another command",
|
||||
"[Microsoft][ODBC Driver 11 for SQL Server]Connection is busy with results for another command" };
|
||||
|
||||
// SQLSTATE for all internal errors
|
||||
extern SQLCHAR IMSSP[];
|
||||
|
@ -1742,9 +1753,9 @@ namespace core {
|
|||
|
||||
throw CoreException();
|
||||
}
|
||||
|
||||
if(( len == sizeof( CONNECTION_BUSY_ODBC_ERROR ) - 1 ) &&
|
||||
!strcmp( reinterpret_cast<const char*>( err_msg ), CONNECTION_BUSY_ODBC_ERROR )) {
|
||||
std::size_t driver_version = stmt->conn->driver_version;
|
||||
if(( len == sizeof( CONNECTION_BUSY_ODBC_ERROR[driver_version] ) - 1 ) &&
|
||||
!strcmp( reinterpret_cast<const char*>( err_msg ), CONNECTION_BUSY_ODBC_ERROR[driver_version] )) {
|
||||
|
||||
THROW_CORE_ERROR( stmt, SQLSRV_ERROR_MARS_OFF );
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ size_t calc_utf8_missing( sqlsrv_stmt* stmt, const char* buffer, size_t buffer_e
|
|||
bool check_for_next_stream_parameter( sqlsrv_stmt* stmt TSRMLS_DC );
|
||||
bool convert_input_param_to_utf16( zval* input_param_z, zval* convert_param_z );
|
||||
void core_get_field_common(__inout sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_phptype
|
||||
sqlsrv_php_type, __out void** field_value, __out SQLLEN* field_len TSRMLS_DC );
|
||||
sqlsrv_php_type, __out void*& field_value, __out SQLLEN* field_len TSRMLS_DC);
|
||||
// returns the ODBC C type constant that matches the PHP type and encoding given
|
||||
SQLSMALLINT default_c_type( sqlsrv_stmt* stmt, SQLULEN paramno, zval const* param_z, SQLSRV_ENCODING encoding TSRMLS_DC );
|
||||
void default_sql_size_and_scale( sqlsrv_stmt* stmt, unsigned int paramno, zval* param_z, SQLSRV_ENCODING encoding,
|
||||
|
@ -92,7 +92,7 @@ void default_sql_type( sqlsrv_stmt* stmt, SQLULEN paramno, zval* param_z, SQLSRV
|
|||
void field_cache_dtor( zval* data_z );
|
||||
void finalize_output_parameters( sqlsrv_stmt* stmt TSRMLS_DC );
|
||||
void get_field_as_string( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_phptype sqlsrv_php_type,
|
||||
__out void** field_value, __out SQLLEN* field_len TSRMLS_DC );
|
||||
__out void*& field_value, __out SQLLEN* field_len TSRMLS_DC );
|
||||
stmt_option const* get_stmt_option( sqlsrv_conn const* conn, zend_ulong key, const stmt_option stmt_opts[] TSRMLS_DC );
|
||||
bool is_valid_sqlsrv_phptype( sqlsrv_phptype type );
|
||||
// assure there is enough space for the output parameter string
|
||||
|
@ -127,9 +127,9 @@ sqlsrv_stmt::sqlsrv_stmt( sqlsrv_conn* c, SQLHANDLE handle, error_callback e, vo
|
|||
current_stream( NULL, SQLSRV_ENCODING_DEFAULT ),
|
||||
current_stream_read( 0 ),
|
||||
query_timeout( QUERY_TIMEOUT_INVALID ),
|
||||
buffered_query_limit( sqlsrv_buffered_result_set::BUFFERED_QUERY_LIMIT_INVALID ),
|
||||
active_stream( NULL )
|
||||
buffered_query_limit( sqlsrv_buffered_result_set::BUFFERED_QUERY_LIMIT_INVALID )
|
||||
{
|
||||
ZVAL_UNDEF( &active_stream );
|
||||
// initialize the input string parameters array (which holds zvals)
|
||||
core::sqlsrv_array_init( *conn, ¶m_input_strings TSRMLS_CC );
|
||||
|
||||
|
@ -152,7 +152,7 @@ sqlsrv_stmt::sqlsrv_stmt( sqlsrv_conn* c, SQLHANDLE handle, error_callback e, vo
|
|||
// desctructor for sqlsrv statement.
|
||||
sqlsrv_stmt::~sqlsrv_stmt( void )
|
||||
{
|
||||
if( active_stream ) {
|
||||
if( Z_TYPE( active_stream ) != IS_UNDEF ) {
|
||||
TSRMLS_FETCH();
|
||||
close_active_stream( this TSRMLS_CC );
|
||||
}
|
||||
|
@ -248,21 +248,17 @@ sqlsrv_stmt* core_sqlsrv_create_stmt( sqlsrv_conn* conn, driver_stmt_factory stm
|
|||
|
||||
// process the options array given to core_sqlsrv_prepare.
|
||||
if( options_ht && zend_hash_num_elements( options_ht ) > 0 ) {
|
||||
for( zend_hash_internal_pointer_reset( options_ht );
|
||||
zend_hash_has_more_elements( options_ht ) == SUCCESS;
|
||||
zend_hash_move_forward( options_ht )) {
|
||||
|
||||
zend_string *key = NULL;
|
||||
zend_ulong index = -1;
|
||||
zend_string *key = NULL;
|
||||
zval* value_z = NULL;
|
||||
|
||||
int type = zend_hash_get_current_key( options_ht, &key, &index);
|
||||
ZEND_HASH_FOREACH_KEY_VAL( options_ht, index, key, value_z ) {
|
||||
|
||||
int 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 ), "allocate_stmt: Invalid statment option key provided." );
|
||||
|
||||
core::sqlsrv_zend_hash_get_current_data( *(stmt->conn), options_ht, value_z TSRMLS_CC );
|
||||
|
||||
const stmt_option* stmt_opt = get_stmt_option( stmt->conn, index, valid_stmt_opts TSRMLS_CC );
|
||||
|
||||
// if the key didn't match, then return the error to the script.
|
||||
|
@ -271,9 +267,7 @@ sqlsrv_stmt* core_sqlsrv_create_stmt( sqlsrv_conn* conn, driver_stmt_factory stm
|
|||
|
||||
// perform the actions the statement option needs done.
|
||||
(*stmt_opt->func)( stmt, stmt_opt, value_z TSRMLS_CC );
|
||||
}
|
||||
|
||||
zend_hash_internal_pointer_end( options_ht );
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
}
|
||||
|
||||
sqlsrv_stmt* return_stmt = stmt;
|
||||
|
@ -658,13 +652,13 @@ void core_sqlsrv_bind_param(sqlsrv_stmt* stmt, SQLUSMALLINT param_num, SQLSMALLI
|
|||
|
||||
void core_sqlsrv_execute( sqlsrv_stmt* stmt TSRMLS_DC, const char* sql, int sql_len )
|
||||
{
|
||||
SQLRETURN r;
|
||||
|
||||
try {
|
||||
|
||||
// close the stream to release the resource
|
||||
close_active_stream( stmt TSRMLS_CC );
|
||||
|
||||
SQLRETURN r;
|
||||
|
||||
if( sql ) {
|
||||
|
||||
sqlsrv_malloc_auto_ptr<wchar_t> wsql_string;
|
||||
|
@ -705,8 +699,9 @@ void core_sqlsrv_execute( sqlsrv_stmt* stmt TSRMLS_DC, const char* sql, int sql_
|
|||
finalize_output_parameters( stmt TSRMLS_CC );
|
||||
}
|
||||
// stream parameters are sent, clean the Hashtable
|
||||
if ( stmt->send_streams_at_exec ) {
|
||||
zend_hash_clean( Z_ARRVAL( stmt->param_streams ));
|
||||
|
||||
}
|
||||
}
|
||||
catch( core::CoreException& e ) {
|
||||
|
||||
|
@ -869,7 +864,7 @@ field_meta_data* core_sqlsrv_field_metadata( sqlsrv_stmt* stmt, SQLSMALLINT coln
|
|||
// Nothing, excpetion thrown if an error occurs
|
||||
|
||||
void core_sqlsrv_get_field( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_phptype sqlsrv_php_type_in, bool prefer_string,
|
||||
__out void** field_value, __out SQLLEN* field_len, bool cache_field,
|
||||
__out void*& field_value, __out SQLLEN* field_len, bool cache_field,
|
||||
__out SQLSRV_PHPTYPE *sqlsrv_php_type_out TSRMLS_DC)
|
||||
{
|
||||
try {
|
||||
|
@ -879,20 +874,20 @@ void core_sqlsrv_get_field( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_
|
|||
|
||||
// if the field has been retrieved before, return the previous result
|
||||
field_cache* cached = NULL;
|
||||
if (NULL != (cached = reinterpret_cast<field_cache*>(zend_hash_index_find_ptr(Z_ARRVAL(stmt->field_cache), static_cast<zend_ulong>(field_index))))) {
|
||||
if (NULL != ( cached = static_cast<field_cache*>( zend_hash_index_find_ptr( Z_ARRVAL( stmt->field_cache ), static_cast<zend_ulong>( field_index ))))) {
|
||||
// the field value is NULL
|
||||
if( cached->value == NULL ) {
|
||||
*field_value = NULL;
|
||||
field_value = NULL;
|
||||
*field_len = 0;
|
||||
if( sqlsrv_php_type_out ) { *sqlsrv_php_type_out = SQLSRV_PHPTYPE_NULL; }
|
||||
}
|
||||
else {
|
||||
|
||||
*field_value = sqlsrv_malloc( cached->len, sizeof( char ), 1 );
|
||||
memcpy( *field_value, cached->value, cached->len );
|
||||
field_value = sqlsrv_malloc( cached->len, sizeof( char ), 1 );
|
||||
memcpy( field_value, cached->value, cached->len );
|
||||
if( cached->type.typeinfo.type == SQLSRV_PHPTYPE_STRING) {
|
||||
// prevent the 'string not null terminated' warning
|
||||
reinterpret_cast<char*>( *field_value )[ cached->len ] = '\0';
|
||||
reinterpret_cast<char*>( field_value )[ cached->len ] = '\0';
|
||||
}
|
||||
*field_len = cached->len;
|
||||
if( sqlsrv_php_type_out) { *sqlsrv_php_type_out = static_cast<SQLSRV_PHPTYPE>(cached->type.typeinfo.type); }
|
||||
|
@ -921,9 +916,9 @@ void core_sqlsrv_get_field( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_
|
|||
core_sqlsrv_get_field( stmt, i, invalid, prefer_string, field_value, field_len, cache_field,
|
||||
sqlsrv_php_type_out TSRMLS_CC );
|
||||
// delete the value returned since we only want it cached, not the actual value
|
||||
if( *field_value ) {
|
||||
efree( *field_value );
|
||||
*field_value = NULL;
|
||||
if( field_value ) {
|
||||
efree( field_value );
|
||||
field_value = NULL;
|
||||
*field_len = 0;
|
||||
}
|
||||
}
|
||||
|
@ -955,7 +950,7 @@ void core_sqlsrv_get_field( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_
|
|||
|
||||
// if the user wants us to cache the field, we'll do it
|
||||
if( cache_field ) {
|
||||
field_cache cache( *field_value, *field_len, sqlsrv_php_type );
|
||||
field_cache cache( field_value, *field_len, sqlsrv_php_type );
|
||||
core::sqlsrv_zend_hash_index_update_mem( *stmt, Z_ARRVAL( stmt->field_cache ), field_index, &cache, sizeof(field_cache) TSRMLS_CC );
|
||||
}
|
||||
}
|
||||
|
@ -1304,6 +1299,9 @@ bool core_sqlsrv_send_stream_packet( sqlsrv_stmt* stmt TSRMLS_DC )
|
|||
return true;
|
||||
}
|
||||
|
||||
void core_finalize_output_parameters(sqlsrv_stmt* stmt TSRMLS_DC) {
|
||||
finalize_output_parameters(stmt TSRMLS_CC);
|
||||
}
|
||||
|
||||
void stmt_option_functor::operator()( sqlsrv_stmt* /*stmt*/, stmt_option const* /*opt*/, zval* /*value_z*/ TSRMLS_DC )
|
||||
{
|
||||
|
@ -1334,20 +1332,20 @@ void stmt_option_buffered_query_limit:: operator()( sqlsrv_stmt* stmt, stmt_opti
|
|||
void close_active_stream( __inout sqlsrv_stmt* stmt TSRMLS_DC )
|
||||
{
|
||||
// if there is no active stream, return
|
||||
if( stmt->active_stream == NULL ) {
|
||||
if( Z_TYPE( stmt->active_stream ) == IS_UNDEF ) {
|
||||
return;
|
||||
}
|
||||
|
||||
php_stream* stream = NULL;
|
||||
|
||||
// we use no verify since verify would return immediately and we want to assert, not return.
|
||||
php_stream_from_zval_no_verify( stream, stmt->active_stream );
|
||||
php_stream_from_zval_no_verify( stream, &( stmt->active_stream ));
|
||||
|
||||
SQLSRV_ASSERT(( stream != NULL ), "close_active_stream: Unknown resource type as our active stream." );
|
||||
|
||||
php_stream_close( stream ); // this will NULL out the active stream in the statement. We don't check for errors here.
|
||||
|
||||
SQLSRV_ASSERT( stmt->active_stream == NULL, "close_active_stream: Active stream not closed." );
|
||||
SQLSRV_ASSERT( Z_TYPE( stmt->active_stream ) == IS_UNDEF, "close_active_stream: Active stream not closed." );
|
||||
|
||||
}
|
||||
|
||||
|
@ -1471,7 +1469,7 @@ size_t calc_utf8_missing( sqlsrv_stmt* stmt, const char* buffer, size_t buffer_e
|
|||
// the driver layer would have to calculate size of the field_value
|
||||
// to decide the amount of memory allocation.
|
||||
void core_get_field_common( __inout sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_phptype
|
||||
sqlsrv_php_type, __out void** field_value, __out SQLLEN* field_len TSRMLS_DC )
|
||||
sqlsrv_php_type, __out void*& field_value, __out SQLLEN* field_len TSRMLS_DC )
|
||||
{
|
||||
try {
|
||||
|
||||
|
@ -1507,11 +1505,11 @@ void core_get_field_common( __inout sqlsrv_stmt* stmt, SQLUSMALLINT field_index,
|
|||
}
|
||||
|
||||
if( *field_len == SQL_NULL_DATA ) {
|
||||
*field_value = NULL;
|
||||
field_value = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
*field_value = field_value_temp;
|
||||
field_value = field_value_temp;
|
||||
field_value_temp.transferred();
|
||||
break;
|
||||
}
|
||||
|
@ -1533,11 +1531,11 @@ void core_get_field_common( __inout sqlsrv_stmt* stmt, SQLUSMALLINT field_index,
|
|||
}
|
||||
|
||||
if( *field_len == SQL_NULL_DATA ) {
|
||||
*field_value = NULL;
|
||||
field_value = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
*field_value = field_value_temp;
|
||||
field_value = field_value_temp;
|
||||
field_value_temp.transferred();
|
||||
break;
|
||||
}
|
||||
|
@ -1573,7 +1571,7 @@ void core_get_field_common( __inout sqlsrv_stmt* stmt, SQLUSMALLINT field_index,
|
|||
|
||||
if( *field_len == SQL_NULL_DATA ) {
|
||||
ZVAL_NULL( return_value_z );
|
||||
*field_value = reinterpret_cast<void*>( return_value_z.get() );
|
||||
field_value = reinterpret_cast<void*>( return_value_z.get());
|
||||
return_value_z.transferred();
|
||||
break;
|
||||
}
|
||||
|
@ -1588,8 +1586,10 @@ void core_get_field_common( __inout sqlsrv_stmt* stmt, SQLUSMALLINT field_index,
|
|||
THROW_CORE_ERROR(stmt, SQLSRV_ERROR_DATETIME_CONVERSION_FAILED);
|
||||
}
|
||||
|
||||
*field_value = reinterpret_cast<void*>( return_value_z.get() );
|
||||
field_value = reinterpret_cast<void*>( return_value_z.get());
|
||||
return_value_z.transferred();
|
||||
zend_string_free( Z_STR( field_value_temp_z ));
|
||||
zend_string_free( Z_STR( function_z ));
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1630,15 +1630,13 @@ void core_get_field_common( __inout sqlsrv_stmt* stmt, SQLUSMALLINT field_index,
|
|||
// turn our stream into a zval to be returned
|
||||
php_stream_to_zval( stream, return_value_z );
|
||||
|
||||
// mark this as our active stream
|
||||
stmt->active_stream = return_value_z;
|
||||
*field_value = reinterpret_cast<void*>( return_value_z.get() );
|
||||
field_value = reinterpret_cast<void*>( return_value_z.get());
|
||||
return_value_z.transferred();
|
||||
break;
|
||||
}
|
||||
|
||||
case SQLSRV_PHPTYPE_NULL:
|
||||
*field_value = NULL;
|
||||
field_value = NULL;
|
||||
*field_len = 0;
|
||||
break;
|
||||
|
||||
|
@ -1956,11 +1954,12 @@ void finalize_output_parameters( sqlsrv_stmt* stmt TSRMLS_DC )
|
|||
|
||||
bool converted = true;
|
||||
HashTable* params_ht = Z_ARRVAL( stmt->output_params );
|
||||
for( zend_hash_internal_pointer_reset( params_ht );
|
||||
zend_hash_has_more_elements( params_ht ) == SUCCESS;
|
||||
zend_hash_move_forward( params_ht ) ) {
|
||||
sqlsrv_output_param* output_param = NULL;
|
||||
core::sqlsrv_zend_hash_get_current_data_ptr(*stmt, params_ht, (void*&) output_param TSRMLS_CC);
|
||||
zend_ulong index = -1;
|
||||
zend_string* key = NULL;
|
||||
void* output_param_temp = NULL;
|
||||
|
||||
ZEND_HASH_FOREACH_KEY_PTR( params_ht, index, key, output_param_temp ) {
|
||||
sqlsrv_output_param* output_param = static_cast<sqlsrv_output_param*>( output_param_temp );
|
||||
zval* value_z = Z_REFVAL_P( output_param->param_z );
|
||||
switch( Z_TYPE_P( value_z )) {
|
||||
case IS_STRING:
|
||||
|
@ -2037,7 +2036,7 @@ void finalize_output_parameters( sqlsrv_stmt* stmt TSRMLS_DC )
|
|||
break;
|
||||
}
|
||||
value_z = NULL;
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
|
||||
// empty the hash table since it's been processed
|
||||
zend_hash_clean( Z_ARRVAL( stmt->output_params ));
|
||||
|
@ -2045,7 +2044,7 @@ void finalize_output_parameters( sqlsrv_stmt* stmt TSRMLS_DC )
|
|||
}
|
||||
|
||||
void get_field_as_string( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_phptype sqlsrv_php_type,
|
||||
__out void** field_value, __out SQLLEN* field_len TSRMLS_DC )
|
||||
__out void*& field_value, __out SQLLEN* field_len TSRMLS_DC )
|
||||
{
|
||||
SQLRETURN r;
|
||||
SQLSMALLINT c_type;
|
||||
|
@ -2102,7 +2101,7 @@ void get_field_as_string( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_ph
|
|||
}
|
||||
|
||||
if( field_len_temp == SQL_NULL_DATA ) {
|
||||
*field_value = NULL;
|
||||
field_value = NULL;
|
||||
sqlsrv_free( field_value_temp );
|
||||
return;
|
||||
}
|
||||
|
@ -2167,7 +2166,7 @@ void get_field_as_string( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_ph
|
|||
true /*handle_warning*/ TSRMLS_CC );
|
||||
|
||||
if( dummy_field_len == SQL_NULL_DATA ) {
|
||||
*field_value = NULL;
|
||||
field_value = NULL;
|
||||
sqlsrv_free( field_value_temp );
|
||||
return;
|
||||
}
|
||||
|
@ -2226,7 +2225,7 @@ void get_field_as_string( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_ph
|
|||
}
|
||||
|
||||
if( field_len_temp == SQL_NULL_DATA ) {
|
||||
*field_value = NULL;
|
||||
field_value = NULL;
|
||||
sqlsrv_free( field_value_temp );
|
||||
return;
|
||||
}
|
||||
|
@ -2248,7 +2247,7 @@ void get_field_as_string( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_ph
|
|||
return; // to eliminate a warning
|
||||
}
|
||||
|
||||
*field_value = field_value_temp;
|
||||
field_value = field_value_temp;
|
||||
*field_len = field_len_temp;
|
||||
|
||||
// prevent a warning in debug mode about strings not being NULL terminated. Even though nulls are not necessary, the PHP
|
||||
|
@ -2260,14 +2259,14 @@ void get_field_as_string( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_ph
|
|||
|
||||
catch( core::CoreException& ) {
|
||||
|
||||
*field_value = NULL;
|
||||
field_value = NULL;
|
||||
*field_len = 0;
|
||||
sqlsrv_free( field_value_temp );
|
||||
throw;
|
||||
}
|
||||
catch ( ... ) {
|
||||
|
||||
*field_value = NULL;
|
||||
field_value = NULL;
|
||||
*field_len = 0;
|
||||
sqlsrv_free( field_value_temp );
|
||||
throw;
|
||||
|
|
|
@ -32,11 +32,8 @@ int sqlsrv_stream_close( php_stream* stream, int /*close_handle*/ TSRMLS_DC )
|
|||
// free the stream resources in the Zend engine
|
||||
php_stream_free( stream, PHP_STREAM_FREE_RELEASE_STREAM );
|
||||
|
||||
// NULL out the stream zval and delete our reference count to it.
|
||||
ZVAL_NULL( ss->stmt->active_stream );
|
||||
|
||||
// there is no active stream
|
||||
ss->stmt->active_stream = NULL;
|
||||
// UNDEF the stream zval and delete our reference count to it.
|
||||
ZVAL_UNDEF( &( ss->stmt->active_stream ) );
|
||||
|
||||
sqlsrv_free( ss );
|
||||
stream->abstract = NULL;
|
||||
|
|
|
@ -531,7 +531,6 @@ PHP_MINIT_FUNCTION(sqlsrv)
|
|||
}
|
||||
|
||||
try {
|
||||
|
||||
// retrieve the handles for the environments
|
||||
core_sqlsrv_minit( &g_henv_cp, &g_henv_ncp, ss_error_handler, "PHP_MINIT_FUNCTION for sqlsrv" TSRMLS_CC );
|
||||
}
|
||||
|
@ -551,13 +550,13 @@ PHP_MINIT_FUNCTION(sqlsrv)
|
|||
|
||||
// called by Zend for each parameter in the g_ss_warnings_to_ignore_ht and g_ss_errors_ht hash table when it is destroyed
|
||||
void sqlsrv_error_const_dtor( zval* elem ) {
|
||||
sqlsrv_error_const* error_to_ignore = reinterpret_cast<sqlsrv_error_const*>( Z_PTR_P(elem) );
|
||||
sqlsrv_error_const* error_to_ignore = static_cast<sqlsrv_error_const*>( Z_PTR_P(elem) );
|
||||
pefree(error_to_ignore, 1);
|
||||
}
|
||||
|
||||
// called by Zend for each parameter in the g_ss_encodings_ht hash table when it is destroyed
|
||||
void sqlsrv_encoding_dtor( zval* elem ) {
|
||||
sqlsrv_encoding* sql_enc = reinterpret_cast<sqlsrv_encoding*>( Z_PTR_P(elem) );
|
||||
sqlsrv_encoding* sql_enc = static_cast<sqlsrv_encoding*>( Z_PTR_P(elem) );
|
||||
pefree(sql_enc, 1);
|
||||
}
|
||||
|
||||
|
@ -611,10 +610,8 @@ PHP_RINIT_FUNCTION(sqlsrv)
|
|||
#endif
|
||||
|
||||
SQLSRV_G( warnings_return_as_errors ) = true;
|
||||
SQLSRV_G( errors ) = (zval *)sqlsrv_malloc(sizeof(zval));
|
||||
ZVAL_NULL(SQLSRV_G(errors));
|
||||
SQLSRV_G( warnings ) = (zval *)sqlsrv_malloc(sizeof(zval));
|
||||
ZVAL_NULL(SQLSRV_G(warnings));
|
||||
ZVAL_NULL( &SQLSRV_G( errors ));
|
||||
ZVAL_NULL( &SQLSRV_G( warnings ));
|
||||
|
||||
LOG_FUNCTION( "PHP_RINIT for php_sqlsrv" );
|
||||
|
||||
|
@ -646,8 +643,8 @@ PHP_RSHUTDOWN_FUNCTION(sqlsrv)
|
|||
reset_errors( TSRMLS_C );
|
||||
|
||||
// TODO - destruction
|
||||
zval_ptr_dtor( SQLSRV_G( errors ));
|
||||
zval_ptr_dtor( SQLSRV_G( warnings ));
|
||||
zval_ptr_dtor( &SQLSRV_G( errors ));
|
||||
zval_ptr_dtor( &SQLSRV_G( warnings ));
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
|
|
@ -10,28 +10,30 @@
|
|||
#define __msodbcsql_h__
|
||||
|
||||
#if !defined(SQLODBC_VER)
|
||||
#define SQLODBC_VER 1100
|
||||
#define SQLODBC_VER 1300
|
||||
#endif
|
||||
|
||||
#if SQLODBC_VER >= 1100
|
||||
#if SQLODBC_VER >= 1300
|
||||
|
||||
#define SQLODBC_PRODUCT_NAME_FULL_VER_ANSI "Microsoft ODBC Driver 11 for SQL Server"
|
||||
#define SQLODBC_PRODUCT_NAME_FULL_VER_ANSI "Microsoft ODBC Driver 13 for SQL Server"
|
||||
#define SQLODBC_PRODUCT_NAME_FULL_ANSI "Microsoft ODBC Driver for SQL Server"
|
||||
#define SQLODBC_PRODUCT_NAME_SHORT_VER_ANSI "ODBC Driver 11 for SQL Server"
|
||||
#define SQLODBC_PRODUCT_NAME_SHORT_VER_ANSI "ODBC Driver 13 for SQL Server"
|
||||
|
||||
#define SQLODBC_PRODUCT_NAME_SHORT_ANSI "ODBC Driver for SQL Server"
|
||||
|
||||
#define SQLODBC_FILE_NAME_ANSI "msodbcsql"
|
||||
#define SQLODBC_FILE_NAME_VER_ANSI "msodbcsql11"
|
||||
#define SQLODBC_FILE_NAME_FULL_ANSI "msodbcsql11.dll"
|
||||
#define SQLODBC_FILE_NAME_VER_ANSI "msodbcsql13"
|
||||
#define SQLODBC_FILE_NAME_FULL_ANSI "msodbcsql13.dll"
|
||||
|
||||
#define SQLODBC_PRODUCT_NAME_FULL_VER_UNICODE L"Microsoft ODBC Driver 11 for SQL Server"
|
||||
#define SQLODBC_PRODUCT_NAME_FULL_VER_UNICODE L"Microsoft ODBC Driver 13 for SQL Server"
|
||||
#define SQLODBC_PRODUCT_NAME_FULL_UNICODE L"Microsoft ODBC Driver for SQL Server"
|
||||
#define SQLODBC_PRODUCT_NAME_SHORT_VER_UNICODE L"ODBC Driver 11 for SQL Server"
|
||||
#define SQLODBC_PRODUCT_NAME_SHORT_VER_UNICODE L"ODBC Driver 13 for SQL Server"
|
||||
|
||||
#define SQLODBC_PRODUCT_NAME_SHORT_UNICODE L"ODBC Driver for SQL Server"
|
||||
|
||||
#define SQLODBC_FILE_NAME_UNICODE L"msodbcsql"
|
||||
#define SQLODBC_FILE_NAME_VER_UNICODE L"msodbcsql11"
|
||||
#define SQLODBC_FILE_NAME_FULL_UNICODE L"msodbcsql11.dll"
|
||||
#define SQLODBC_FILE_NAME_VER_UNICODE L"msodbcsql13"
|
||||
#define SQLODBC_FILE_NAME_FULL_UNICODE L"msodbcsql13.dll"
|
||||
|
||||
// define the character type agnostic constants
|
||||
#if defined(_UNICODE) || defined(UNICODE)
|
||||
|
@ -203,6 +205,10 @@ extern "C" {
|
|||
#define SQL_COPT_SS_INTEGRATED_AUTHENTICATION_METHOD (SQL_COPT_SS_BASE+31) // The integrated authentication method used for the connection
|
||||
#define SQL_COPT_SS_MUTUALLY_AUTHENTICATED (SQL_COPT_SS_BASE+32) // Used to decide if the connection is mutually authenticated
|
||||
#define SQL_COPT_SS_CLIENT_CONNECTION_ID (SQL_COPT_SS_BASE+33) // Post connection attribute used to get the ConnectionID
|
||||
|
||||
#define SQL_COPT_SS_CLIENT_CERTIFICATE (SQL_COPT_SS_BASE+36) // Client certificate
|
||||
#define SQL_COPT_SS_CLIENT_CERTIFICATE_FALLBACK (SQL_COPT_SS_BASE+37) // Client certificate fallback
|
||||
|
||||
// Define old names
|
||||
#define SQL_REMOTE_PWD SQL_COPT_SS_REMOTE_PWD
|
||||
#define SQL_USE_PROCEDURE_FOR_PREPARE SQL_COPT_SS_USE_PROC_FOR_PREP
|
||||
|
@ -225,7 +231,8 @@ extern "C" {
|
|||
#define SQL_SOPT_SS_QUERYNOTIFICATION_OPTIONS (SQL_SOPT_SS_BASE+10)// SQL service broker name
|
||||
#define SQL_SOPT_SS_PARAM_FOCUS (SQL_SOPT_SS_BASE+11)// Direct subsequent calls to parameter related methods to set properties on constituent columns/parameters of container types
|
||||
#define SQL_SOPT_SS_NAME_SCOPE (SQL_SOPT_SS_BASE+12)// Sets name scope for subsequent catalog function calls
|
||||
#define SQL_SOPT_SS_MAX_USED SQL_SOPT_SS_NAME_SCOPE
|
||||
#define SQL_SOPT_SS_COLUMN_ENCRYPTION (SQL_SOPT_SS_BASE+13)// Sets the column encryption mode
|
||||
#define SQL_SOPT_SS_MAX_USED SQL_SOPT_SS_COLUMN_ENCRYPTION
|
||||
// Define old names
|
||||
#define SQL_TEXTPTR_LOGGING SQL_SOPT_SS_TEXTPTR_LOGGING
|
||||
#define SQL_COPT_SS_BASE_EX 1240
|
||||
|
@ -237,7 +244,13 @@ extern "C" {
|
|||
#define SQL_COPT_SS_RESET_CONNECTION (SQL_COPT_SS_BASE_EX+6) // When this option is set, we will perform connection reset on next packet
|
||||
#define SQL_COPT_SS_APPLICATION_INTENT (SQL_COPT_SS_BASE_EX+7) // Application Intent
|
||||
#define SQL_COPT_SS_MULTISUBNET_FAILOVER (SQL_COPT_SS_BASE_EX+8) // Multi-subnet Failover
|
||||
#define SQL_COPT_SS_EX_MAX_USED SQL_COPT_SS_MULTISUBNET_FAILOVER
|
||||
#define SQL_COPT_SS_TNIR (SQL_COPT_SS_BASE_EX+9) // Transparent Network IP Resolution
|
||||
#define SQL_COPT_SS_COLUMN_ENCRYPTION (SQL_COPT_SS_BASE_EX+10) // Always Encrypted Enabled or Disabled
|
||||
#define SQL_COPT_SS_AEKEYSTOREPROVIDER (SQL_COPT_SS_BASE_EX+11) // Used to load a keystore provider DLL
|
||||
#define SQL_COPT_SS_AEKEYSTOREDATA (SQL_COPT_SS_BASE_EX+12) // Used to communicate with keystore providers
|
||||
#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_EX_MAX_USED SQL_COPT_SS_AECEKCACHETTL
|
||||
|
||||
// SQLColAttributes driver specific defines.
|
||||
// SQLSetDescField/SQLGetDescField driver specific defines.
|
||||
|
@ -287,7 +300,10 @@ extern "C" {
|
|||
// Legacy datetime related metadata
|
||||
#define SQL_CA_SS_SERVER_TYPE (SQL_CA_SS_BASE+35) // column type to send on the wire for datetime types
|
||||
|
||||
#define SQL_CA_SS_MAX_USED (SQL_CA_SS_BASE+36)
|
||||
// force column encryption
|
||||
#define SQL_CA_SS_FORCE_ENCRYPT (SQL_CA_SS_BASE+36) // indicate mandatory encryption for this parameter
|
||||
|
||||
#define SQL_CA_SS_MAX_USED (SQL_CA_SS_BASE+37)
|
||||
|
||||
// Defines returned by SQL_ATTR_CURSOR_TYPE/SQL_CURSOR_TYPE
|
||||
#define SQL_CURSOR_FAST_FORWARD_ONLY 8 // Only returned by SQLGetStmtAttr/Option
|
||||
|
@ -299,6 +315,8 @@ extern "C" {
|
|||
// Defines for use with SQL_COPT_SS_INTEGRATED_SECURITY - Pre-Connect Option only
|
||||
#define SQL_IS_OFF 0L // Integrated security isn't used
|
||||
#define SQL_IS_ON 1L // Integrated security is used
|
||||
#define SQL_IS_AD_OFF 2L // Active Directory integrated security isn't used
|
||||
#define SQL_IS_AD_ON 3L // Active Directory integrated security is used
|
||||
#define SQL_IS_DEFAULT SQL_IS_OFF
|
||||
// Defines for use with SQL_COPT_SS_PRESERVE_CURSORS
|
||||
#define SQL_PC_OFF 0L // Cursors are closed on SQLTransact
|
||||
|
@ -353,6 +371,16 @@ extern "C" {
|
|||
#define SQL_CO_FFO_AF (SQL_CO_FFO|SQL_CO_AF) // Fast-forward cursor with autofetch
|
||||
#define SQL_CO_FIREHOSE_AF 4L // Auto fetch on fire-hose cursors
|
||||
#define SQL_CO_DEFAULT SQL_CO_OFF
|
||||
// Defines for use with SQL_SOPT_SS_COLUMN_ENCRYPTION
|
||||
#define SQL_CE_DISABLED 0L // Disabled
|
||||
#define SQL_CE_RESULTSETONLY 1L // Decryption Only (resultsets and return values)
|
||||
#define SQL_CE_ENABLED 3L // Enabled (both encryption and decryption)
|
||||
// Defines for use with SQL_COPT_SS_COLUMN_ENCRYPTION
|
||||
#define SQL_COLUMN_ENCRYPTION_DISABLE 0L
|
||||
#define SQL_COLUMN_ENCRYPTION_ENABLE 1L
|
||||
#define SQL_COLUMN_ENCRYPTION_DEFAULT SQL_COLUMN_ENCRYPTION_DISABLE
|
||||
// Defines for use with SQL_COPT_SS_AECEKCACHETTL
|
||||
#define SQL_AECEKCACHETTL_DEFAULT 7200L // TTL value in seconds (2 hours)
|
||||
//SQL_SOPT_SS_NOCOUNT_STATUS
|
||||
#define SQL_NC_OFF 0L
|
||||
#define SQL_NC_ON 1L
|
||||
|
@ -927,6 +955,60 @@ WCHAR* SQL_API bcp_gettypenameW (INT, DBBOOL);
|
|||
#define SQL_AO_DEFAULT SQL_AO_OFF
|
||||
#define SQL_CA_SS_BASE_COLUMN_NAME SQL_DESC_BASE_COLUMN_NAME
|
||||
|
||||
// Keystore Provider interface definition
|
||||
|
||||
typedef void errFunc(void *ctx, const wchar_t *msg, ...);
|
||||
|
||||
#define IDS_MSG(x) ((const wchar_t*)(x))
|
||||
|
||||
typedef struct AEKeystoreProvider
|
||||
{
|
||||
wchar_t *Name;
|
||||
int (*Init)(void *ctx, errFunc *onError);
|
||||
int (*Read)(void *ctx, errFunc *onError, void *data, unsigned int *len);
|
||||
int (*Write)(void *ctx, errFunc *onError, void *data, unsigned int len);
|
||||
int (*DecryptCEK)(
|
||||
void *ctx,
|
||||
errFunc *onError,
|
||||
const wchar_t *keyPath,
|
||||
const wchar_t *alg,
|
||||
unsigned char *ecek,
|
||||
unsigned short ecek_len,
|
||||
unsigned char **cek_out,
|
||||
unsigned short *cek_len);
|
||||
void (*Free)();
|
||||
} AEKEYSTOREPROVIDER;
|
||||
|
||||
/* Data is defined to be past the end of the structure header.
|
||||
This is accepted by MSVC, GCC, and C99 standard but former emits
|
||||
unnecessary warning, hence it has to be disabled.
|
||||
*/
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4200)
|
||||
|
||||
typedef struct AEKeystoreData
|
||||
{
|
||||
wchar_t *Name;
|
||||
unsigned int dataSize;
|
||||
char Data[];
|
||||
} AEKEYSTOREPROVIDERDATA;
|
||||
|
||||
#pragma warning(pop)
|
||||
|
||||
// The following constants are for the Azure Key Vault configuration interface
|
||||
#define AKV_CONFIG_FLAGS 0
|
||||
#define AKVCFG_USECLIENTID 0x00000001
|
||||
#define AKVCFG_AUTORENEW 0x00000002
|
||||
|
||||
#define AKV_CONFIG_CLIENTID 1
|
||||
#define AKV_CONFIG_CLIENTKEY 2
|
||||
|
||||
#define AKV_CONFIG_ACCESSTOKEN 3
|
||||
#define AKV_CONFIG_TOKENEXPIRY 4
|
||||
|
||||
#define AKV_CONFIG_MAXRETRIES 5
|
||||
#define AKV_CONFIG_RETRYTIMEOUT 6
|
||||
#define AKV_CONFIG_RETRYWAIT 7
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
|
@ -973,10 +1055,13 @@ HANDLE __stdcall OpenSqlFilestream (
|
|||
|
||||
#define SQL_COPT_SS_CONNECT_RETRY_COUNT (SQL_COPT_SS_BASE+34) // Post connection attribute used to get ConnectRetryCount
|
||||
#define SQL_COPT_SS_CONNECT_RETRY_INTERVAL (SQL_COPT_SS_BASE+35) // Post connection attribute used to get ConnectRetryInterval
|
||||
#define SQL_COPT_SS_CLIENT_CERTIFICATE (SQL_COPT_SS_BASE+36) // Client certificate
|
||||
#define SQL_COPT_SS_CLIENT_CERTIFICATE_FALLBACK (SQL_COPT_SS_BASE+37) // Client certificate fallback
|
||||
|
||||
#ifdef SQL_COPT_SS_MAX_USED
|
||||
#undef SQL_COPT_SS_MAX_USED
|
||||
#endif // SQL_COPT_SS_MAX_USED
|
||||
#define SQL_COPT_SS_MAX_USED SQL_COPT_SS_CONNECT_RETRY_INTERVAL
|
||||
#define SQL_COPT_SS_MAX_USED SQL_COPT_SS_CLIENT_CERTIFICATE_FALLBACK
|
||||
|
||||
|
||||
#ifndef _SQLUSERINSTANCE_H_
|
||||
|
@ -988,6 +1073,19 @@ HANDLE __stdcall OpenSqlFilestream (
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct _CERT_CONTEXT;
|
||||
typedef _CERT_CONTEXT CERT_CONTEXT;
|
||||
typedef const CERT_CONTEXT *PCCERT_CONTEXT;
|
||||
|
||||
// type definition for client certificate fallback function
|
||||
typedef DWORD(WINAPI *PFnClientCertificateFallback)(
|
||||
__in BOOL fHash,
|
||||
__in_z LPCWSTR pszCertificate,
|
||||
__out PCCERT_CONTEXT *ppCertContext,
|
||||
__out DWORD *pdwFlags,
|
||||
__out ULONG cchKeyContainer,
|
||||
__out_ecount(cchKeyContainer) WCHAR *pwchKeyContainer
|
||||
);
|
||||
|
||||
// Recommended buffer size to store a LocalDB connection string
|
||||
#define LOCALDB_MAX_SQLCONNECTION_BUFFER_SIZE 260
|
||||
|
|
|
@ -265,8 +265,8 @@ extern "C" {
|
|||
ZEND_BEGIN_MODULE_GLOBALS(sqlsrv)
|
||||
|
||||
// global objects for errors and warnings. These are returned by sqlsrv_errors.
|
||||
zval* errors;
|
||||
zval* warnings;
|
||||
zval errors;
|
||||
zval warnings;
|
||||
|
||||
// flags for error handling and logging (set via sqlsrv_configure or php.ini)
|
||||
zend_long log_severity;
|
||||
|
@ -386,24 +386,24 @@ void __cdecl sqlsrv_error_dtor( zend_resource *rsrc TSRMLS_DC );
|
|||
// release current error lists and set to NULL
|
||||
inline void reset_errors( TSRMLS_D )
|
||||
{
|
||||
if( Z_TYPE_P( SQLSRV_G( errors )) != IS_ARRAY && Z_TYPE_P( SQLSRV_G( errors )) != IS_NULL ) {
|
||||
if( Z_TYPE( SQLSRV_G( errors )) != IS_ARRAY && Z_TYPE( SQLSRV_G( errors )) != IS_NULL ) {
|
||||
DIE( "sqlsrv_errors contains an invalid type" );
|
||||
}
|
||||
if( Z_TYPE_P( SQLSRV_G( warnings )) != IS_ARRAY && Z_TYPE_P( SQLSRV_G( warnings )) != IS_NULL ) {
|
||||
if( Z_TYPE( SQLSRV_G( warnings )) != IS_ARRAY && Z_TYPE( SQLSRV_G( warnings )) != IS_NULL ) {
|
||||
DIE( "sqlsrv_warnings contains an invalid type" );
|
||||
}
|
||||
|
||||
if( Z_TYPE_P( SQLSRV_G( errors )) == IS_ARRAY ) {
|
||||
zend_hash_destroy( Z_ARRVAL_P( SQLSRV_G( errors )));
|
||||
FREE_HASHTABLE( Z_ARRVAL_P( SQLSRV_G( errors )));
|
||||
if( Z_TYPE( SQLSRV_G( errors )) == IS_ARRAY ) {
|
||||
zend_hash_destroy( Z_ARRVAL( SQLSRV_G( errors )));
|
||||
FREE_HASHTABLE( Z_ARRVAL( SQLSRV_G( errors )));
|
||||
}
|
||||
if( Z_TYPE_P( SQLSRV_G( warnings )) == IS_ARRAY ) {
|
||||
zend_hash_destroy( Z_ARRVAL_P( SQLSRV_G( warnings )));
|
||||
FREE_HASHTABLE( Z_ARRVAL_P( SQLSRV_G( warnings )));
|
||||
if( Z_TYPE( SQLSRV_G( warnings )) == IS_ARRAY ) {
|
||||
zend_hash_destroy( Z_ARRVAL( SQLSRV_G( warnings )));
|
||||
FREE_HASHTABLE( Z_ARRVAL( SQLSRV_G( warnings )));
|
||||
}
|
||||
|
||||
ZVAL_NULL( SQLSRV_G( errors ));
|
||||
ZVAL_NULL( SQLSRV_G( warnings ));
|
||||
ZVAL_NULL( &SQLSRV_G( errors ));
|
||||
ZVAL_NULL( &SQLSRV_G( warnings ));
|
||||
}
|
||||
|
||||
#define THROW_SS_ERROR( ctx, error_code, ... ) \
|
||||
|
|
161
sqlsrv/stmt.cpp
161
sqlsrv/stmt.cpp
|
@ -88,8 +88,9 @@ const char SS_SQLSRV_WARNING_PARAM_VAR_NOT_REF[] = "Variable parameter %d not pa
|
|||
|
||||
/* internal functions */
|
||||
|
||||
zval* convert_to_zval( SQLSRV_PHPTYPE sqlsrv_php_type, void* in_val, SQLLEN field_len );
|
||||
void fetch_fields_common( __inout ss_sqlsrv_stmt* stmt, zend_long fetch_type, __out zval* return_value, bool allow_empty_field_names
|
||||
void convert_to_zval( sqlsrv_stmt* stmt, SQLSRV_PHPTYPE sqlsrv_php_type, void* in_val, SQLLEN field_len, zval& out_zval );
|
||||
|
||||
void fetch_fields_common( __inout ss_sqlsrv_stmt* stmt, zend_long fetch_type, __out zval& fields, bool allow_empty_field_names
|
||||
TSRMLS_DC );
|
||||
bool determine_column_size_or_precision( sqlsrv_stmt const* stmt, sqlsrv_sqltype sqlsrv_type, __out SQLULEN* column_size,
|
||||
__out SQLSMALLINT* decimal_digits );
|
||||
|
@ -405,8 +406,10 @@ PHP_FUNCTION( sqlsrv_fetch_array )
|
|||
if( !result ) {
|
||||
RETURN_NULL();
|
||||
}
|
||||
|
||||
fetch_fields_common( stmt, fetch_type, return_value, true /*allow_empty_field_names*/ TSRMLS_CC );
|
||||
zval fields;
|
||||
ZVAL_UNDEF( &fields );
|
||||
fetch_fields_common( stmt, fetch_type, fields, true /*allow_empty_field_names*/ TSRMLS_CC );
|
||||
RETURN_ARR( Z_ARRVAL( fields ));
|
||||
}
|
||||
|
||||
catch( core::CoreException& ) {
|
||||
|
@ -768,6 +771,8 @@ PHP_FUNCTION( sqlsrv_fetch_object )
|
|||
char* class_name = const_cast<char*>( STDCLASS_NAME );
|
||||
std::size_t class_name_len = STDCLASS_NAME_LEN;
|
||||
HashTable* properties_ht = NULL;
|
||||
zval retval_z;
|
||||
ZVAL_UNDEF( &retval_z );
|
||||
|
||||
// retrieve the statement resource and optional fetch type (see enum SQLSRV_FETCH_TYPE),
|
||||
// fetch style (see SQLSRV_SCROLL_* constants) and fetch offset
|
||||
|
@ -802,8 +807,8 @@ PHP_FUNCTION( sqlsrv_fetch_object )
|
|||
RETURN_NULL();
|
||||
}
|
||||
|
||||
fetch_fields_common( stmt, SQLSRV_FETCH_ASSOC, return_value, false /*allow_empty_field_names*/ TSRMLS_CC );
|
||||
properties_ht = Z_ARRVAL_P( return_value );
|
||||
fetch_fields_common( stmt, SQLSRV_FETCH_ASSOC, retval_z, false /*allow_empty_field_names*/ TSRMLS_CC );
|
||||
properties_ht = Z_ARRVAL( retval_z );
|
||||
|
||||
// find the zend_class_entry of the class the user requested (stdClass by default) for use below
|
||||
zend_class_entry* class_entry = NULL;
|
||||
|
@ -815,7 +820,7 @@ PHP_FUNCTION( sqlsrv_fetch_object )
|
|||
|
||||
// create an instance of the object with its default properties
|
||||
// we pass NULL for the properties so that the object will be populated by its default properties
|
||||
zr = object_and_properties_init( return_value, class_entry, NULL /*properties*/ );
|
||||
zr = object_and_properties_init( &retval_z, class_entry, NULL /*properties*/ );
|
||||
CHECK_ZEND_ERROR( zr, stmt, SS_SQLSRV_ERROR_ZEND_OBJECT_FAILED, class_name ) {
|
||||
throw ss::SSException();
|
||||
}
|
||||
|
@ -825,7 +830,7 @@ PHP_FUNCTION( sqlsrv_fetch_object )
|
|||
// causes duplicate properties when the visibilities are different and also references the
|
||||
// default parameters directly in the object, meaning the default property value is changed when
|
||||
// the object's property is changed.
|
||||
zend_merge_properties( return_value, properties_ht TSRMLS_CC );
|
||||
zend_merge_properties( &retval_z, properties_ht TSRMLS_CC );
|
||||
|
||||
// find and call the object's constructor
|
||||
|
||||
|
@ -853,16 +858,16 @@ PHP_FUNCTION( sqlsrv_fetch_object )
|
|||
num_params = zend_hash_num_elements( ctor_params_ht );
|
||||
params_m = reinterpret_cast<zval*>( sqlsrv_malloc( num_params * sizeof( zval ) ));
|
||||
|
||||
int i;
|
||||
for( i = 0, zend_hash_internal_pointer_reset( ctor_params_ht );
|
||||
zend_hash_has_more_elements( ctor_params_ht ) == SUCCESS;
|
||||
zend_hash_move_forward( ctor_params_ht ), ++i ) {
|
||||
ZVAL_COPY_VALUE( ¶ms_m[i], zend_hash_get_current_data_ex(ctor_params_ht, &ctor_params_ht->nInternalPointer ) );
|
||||
int i = 0;
|
||||
zval* value_z = NULL;
|
||||
ZEND_HASH_FOREACH_VAL( ctor_params_ht, value_z ) {
|
||||
ZVAL_COPY_VALUE( ¶ms_m[i], value_z );
|
||||
zr = ( NULL != ¶ms_m[i] ) ? SUCCESS : FAILURE;
|
||||
CHECK_ZEND_ERROR( zr, stmt, SS_SQLSRV_ERROR_ZEND_OBJECT_FAILED, class_name ) {
|
||||
throw ss::SSException();
|
||||
}
|
||||
} //for
|
||||
i++;
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
} //if( !Z_ISUNDEF( ctor_params_z ))
|
||||
|
||||
// call the constructor function itself.
|
||||
|
@ -877,14 +882,14 @@ PHP_FUNCTION( sqlsrv_fetch_object )
|
|||
fci.param_count = num_params;
|
||||
fci.params = params_m; // purposefully not transferred since ownership isn't actually transferred.
|
||||
|
||||
fci.object = reinterpret_cast<zend_object*>(return_value);
|
||||
fci.object = reinterpret_cast<zend_object*>( &retval_z );
|
||||
|
||||
memset( &fcic, 0, sizeof( fcic ));
|
||||
fcic.initialized = 1;
|
||||
fcic.function_handler = class_entry->constructor;
|
||||
fcic.calling_scope = class_entry;
|
||||
|
||||
fci.object = reinterpret_cast<zend_object*>(return_value);
|
||||
fci.object = reinterpret_cast<zend_object*>( &retval_z );
|
||||
|
||||
zr = zend_call_function( &fci, &fcic TSRMLS_CC );
|
||||
CHECK_ZEND_ERROR( zr, stmt, SS_SQLSRV_ERROR_ZEND_OBJECT_FAILED, class_name ) {
|
||||
|
@ -892,6 +897,7 @@ PHP_FUNCTION( sqlsrv_fetch_object )
|
|||
}
|
||||
|
||||
} //if( class_entry->constructor )
|
||||
RETURN_ZVAL( &retval_z, 1, 1 );
|
||||
}
|
||||
|
||||
catch( core::CoreException& ) {
|
||||
|
@ -1055,6 +1061,8 @@ PHP_FUNCTION( sqlsrv_get_field )
|
|||
void* field_value = NULL;
|
||||
int field_index = -1;
|
||||
SQLLEN field_len = -1;
|
||||
zval retval_z;
|
||||
ZVAL_UNDEF(&retval_z);
|
||||
|
||||
// get the statement, the field index and the optional type
|
||||
PROCESS_PARAMS( stmt, "rl|l", _FN_, 2, &field_index, &sqlsrv_php_type );
|
||||
|
@ -1068,11 +1076,11 @@ PHP_FUNCTION( sqlsrv_get_field )
|
|||
THROW_SS_ERROR( stmt, SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER, _FN_ );
|
||||
}
|
||||
|
||||
core_sqlsrv_get_field( stmt, field_index, sqlsrv_php_type, false, &field_value, &field_len, false/*cache_field*/,
|
||||
core_sqlsrv_get_field( stmt, field_index, sqlsrv_php_type, false, field_value, &field_len, false/*cache_field*/,
|
||||
&sqlsrv_php_type_out TSRMLS_CC );
|
||||
|
||||
zval* retval_z = convert_to_zval(sqlsrv_php_type_out, field_value, field_len);
|
||||
RETURN_ZVAL(retval_z, 1, 1);
|
||||
convert_to_zval( stmt, sqlsrv_php_type_out, field_value, field_len, retval_z );
|
||||
sqlsrv_free( field_value );
|
||||
RETURN_ZVAL( &retval_z, 1, 1 );
|
||||
}
|
||||
|
||||
catch( core::CoreException& ) {
|
||||
|
@ -1166,23 +1174,19 @@ void mark_params_by_reference( ss_sqlsrv_stmt* stmt, zval* params_z TSRMLS_DC )
|
|||
|
||||
HashTable* params_ht = Z_ARRVAL_P( params_z );
|
||||
|
||||
for( zend_hash_internal_pointer_reset( params_ht );
|
||||
zend_hash_has_more_elements( params_ht ) == SUCCESS;
|
||||
zend_hash_move_forward( params_ht )) {
|
||||
|
||||
zend_ulong index;
|
||||
zend_string* key = NULL;
|
||||
zend_ulong index = -1;
|
||||
zval* value_z = NULL;
|
||||
|
||||
ZEND_HASH_FOREACH_KEY_VAL( params_ht, index, key, value_z ) {
|
||||
|
||||
// make sure it's an integer index
|
||||
int type = zend_hash_get_current_key( params_ht, &key, &index);
|
||||
int type = key ? HASH_KEY_IS_STRING : HASH_KEY_IS_LONG;
|
||||
|
||||
CHECK_CUSTOM_ERROR( type != HASH_KEY_IS_LONG, stmt, SS_SQLSRV_ERROR_PARAM_INVALID_INDEX ) {
|
||||
throw ss::SSException();
|
||||
}
|
||||
|
||||
core::sqlsrv_zend_hash_get_current_data( *stmt, params_ht, value_z TSRMLS_CC );
|
||||
|
||||
// This code turns parameters into references. Since the function declaration cannot
|
||||
// pass array elements as references (without requiring & in front of each variable),
|
||||
// we have to set the reference in each of the zvals ourselves. In the event of a
|
||||
|
@ -1201,7 +1205,7 @@ void mark_params_by_reference( ss_sqlsrv_stmt* stmt, zval* params_z TSRMLS_DC )
|
|||
}
|
||||
ZVAL_MAKE_REF( var );
|
||||
}
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
|
||||
// save our parameters for later.
|
||||
Z_TRY_ADDREF_P( params_z );
|
||||
|
@ -1225,13 +1229,11 @@ void bind_params( ss_sqlsrv_stmt* stmt TSRMLS_DC )
|
|||
|
||||
HashTable* params_ht = Z_ARRVAL_P( params_z );
|
||||
|
||||
for( zend_hash_internal_pointer_reset( params_ht );
|
||||
zend_hash_has_more_elements( params_ht ) == SUCCESS;
|
||||
zend_hash_move_forward( params_ht )) {
|
||||
|
||||
zend_string *key = NULL;
|
||||
zend_ulong index = -1;
|
||||
zend_string *key = NULL;
|
||||
zval* param_z = NULL;
|
||||
|
||||
ZEND_HASH_FOREACH_KEY_VAL( params_ht, index, key, param_z ) {
|
||||
zval* value_z = NULL;
|
||||
SQLSMALLINT direction = SQL_PARAM_INPUT;
|
||||
SQLSRV_ENCODING encoding = stmt->encoding();
|
||||
|
@ -1244,14 +1246,11 @@ void bind_params( ss_sqlsrv_stmt* stmt TSRMLS_DC )
|
|||
SQLSRV_PHPTYPE php_out_type = SQLSRV_PHPTYPE_INVALID;
|
||||
|
||||
// make sure it's an integer index
|
||||
int type = zend_hash_get_current_key( params_ht, &key, &index);
|
||||
|
||||
int type = key ? HASH_KEY_IS_STRING : HASH_KEY_IS_LONG;
|
||||
CHECK_CUSTOM_ERROR( type != HASH_KEY_IS_LONG, stmt, SS_SQLSRV_ERROR_PARAM_INVALID_INDEX ) {
|
||||
throw ss::SSException();
|
||||
}
|
||||
|
||||
core::sqlsrv_zend_hash_get_current_data( *stmt, params_ht, param_z TSRMLS_CC );
|
||||
|
||||
// if it's a parameter array
|
||||
if( Z_TYPE_P( param_z ) == IS_ARRAY ) {
|
||||
|
||||
|
@ -1273,7 +1272,7 @@ void bind_params( ss_sqlsrv_stmt* stmt TSRMLS_DC )
|
|||
core_sqlsrv_bind_param( stmt, index, direction, value_z, php_out_type, encoding, sql_type, column_size,
|
||||
decimal_digits TSRMLS_CC );
|
||||
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
}
|
||||
catch( core::CoreException& ) {
|
||||
SQLFreeStmt( stmt->handle(), SQL_RESET_PARAMS );
|
||||
|
@ -1482,14 +1481,11 @@ void stmt_option_scrollable:: operator()( sqlsrv_stmt* stmt, stmt_option const*
|
|||
|
||||
namespace {
|
||||
|
||||
zval* convert_to_zval( SQLSRV_PHPTYPE sqlsrv_php_type, void* in_val, SQLLEN field_len )
|
||||
void convert_to_zval(sqlsrv_stmt* stmt, SQLSRV_PHPTYPE sqlsrv_php_type, void* in_val, SQLLEN field_len, zval& out_zval)
|
||||
{
|
||||
zval* out_zval = NULL;
|
||||
if ( in_val == NULL ) {
|
||||
|
||||
out_zval = ( zval* )sqlsrv_malloc(sizeof( zval ));
|
||||
ZVAL_NULL( out_zval );
|
||||
return out_zval;
|
||||
ZVAL_NULL( &out_zval);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (sqlsrv_php_type) {
|
||||
|
@ -1497,53 +1493,47 @@ zval* convert_to_zval( SQLSRV_PHPTYPE sqlsrv_php_type, void* in_val, SQLLEN fiel
|
|||
case SQLSRV_PHPTYPE_INT:
|
||||
case SQLSRV_PHPTYPE_FLOAT:
|
||||
{
|
||||
out_zval = ( zval* )sqlsrv_malloc(sizeof( zval ));
|
||||
ZVAL_UNDEF( out_zval );
|
||||
if (sqlsrv_php_type == SQLSRV_PHPTYPE_INT) {
|
||||
ZVAL_LONG( out_zval, *( static_cast<int*>( in_val )));
|
||||
ZVAL_LONG( &out_zval, *(static_cast<int*>( in_val )));
|
||||
}
|
||||
else {
|
||||
ZVAL_DOUBLE( out_zval, *( static_cast<double*>( in_val )));
|
||||
ZVAL_DOUBLE( &out_zval, *(static_cast<double*>( in_val )));
|
||||
}
|
||||
sqlsrv_free( in_val );
|
||||
break;
|
||||
}
|
||||
|
||||
case SQLSRV_PHPTYPE_STRING:
|
||||
{
|
||||
out_zval = ( zval* )sqlsrv_malloc( sizeof( zval ));
|
||||
ZVAL_UNDEF( out_zval );
|
||||
core::sqlsrv_zval_stringl( out_zval, reinterpret_cast<char*>( in_val ), field_len );
|
||||
sqlsrv_free( in_val );
|
||||
ZVAL_STRINGL( &out_zval, static_cast<const char*>( in_val ), field_len);
|
||||
break;
|
||||
}
|
||||
|
||||
case SQLSRV_PHPTYPE_STREAM:
|
||||
{
|
||||
out_zval = *( static_cast<zval*>( in_val ));
|
||||
stmt->active_stream = out_zval;
|
||||
//addref here because deleting out_zval later will decrement the refcount
|
||||
Z_TRY_ADDREF( out_zval );
|
||||
break;
|
||||
}
|
||||
case SQLSRV_PHPTYPE_DATETIME:
|
||||
{
|
||||
out_zval = ( static_cast<zval*>( in_val ) );
|
||||
|
||||
//addref here because deleting out_zval later will decrement the refcount
|
||||
Z_TRY_ADDREF_P( out_zval );
|
||||
in_val = NULL;
|
||||
out_zval = *( static_cast<zval*>( in_val ));
|
||||
break;
|
||||
}
|
||||
|
||||
case SQLSRV_PHPTYPE_NULL:
|
||||
out_zval = ( zval* )sqlsrv_malloc(sizeof( zval ));
|
||||
ZVAL_NULL( out_zval );
|
||||
ZVAL_NULL(&out_zval);
|
||||
break;
|
||||
|
||||
default:
|
||||
DIE("Unknown php type");
|
||||
break;
|
||||
}
|
||||
|
||||
return out_zval;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// put in the column size and scale/decimal digits of the sql server type
|
||||
// these values are taken from the MSDN page at http://msdn2.microsoft.com/en-us/library/ms711786(VS.85).aspx
|
||||
bool determine_column_size_or_precision( sqlsrv_stmt const* stmt, sqlsrv_sqltype sqlsrv_type, __out SQLULEN* column_size,
|
||||
|
@ -1795,15 +1785,13 @@ void determine_stmt_has_rows( ss_sqlsrv_stmt* stmt TSRMLS_DC )
|
|||
}
|
||||
}
|
||||
|
||||
void fetch_fields_common( __inout ss_sqlsrv_stmt* stmt, zend_long fetch_type, __out zval* return_value, bool allow_empty_field_names
|
||||
void fetch_fields_common( __inout ss_sqlsrv_stmt* stmt, zend_long fetch_type, __out zval& fields, bool allow_empty_field_names
|
||||
TSRMLS_DC )
|
||||
{
|
||||
void* field_value = NULL;
|
||||
sqlsrv_phptype sqlsrv_php_type;
|
||||
sqlsrv_php_type.typeinfo.type = SQLSRV_PHPTYPE_INVALID;
|
||||
SQLSRV_PHPTYPE sqlsrv_php_type_out = SQLSRV_PHPTYPE_INVALID;
|
||||
zval fields;
|
||||
ZVAL_UNDEF( &fields );
|
||||
|
||||
// make sure that the fetch type is legal
|
||||
CHECK_CUSTOM_ERROR((fetch_type < MIN_SQLSRV_FETCH || fetch_type > MAX_SQLSRV_FETCH), stmt, SS_SQLSRV_ERROR_INVALID_FETCH_TYPE, stmt->func()) {
|
||||
|
@ -1842,24 +1830,22 @@ void fetch_fields_common( __inout ss_sqlsrv_stmt* stmt, zend_long fetch_type, __
|
|||
throw ss::SSException();
|
||||
}
|
||||
|
||||
// get the fields
|
||||
for( int i = 0; i < num_cols; ++i ) {
|
||||
|
||||
|
||||
zval field;
|
||||
SQLLEN field_len = -1;
|
||||
|
||||
core_sqlsrv_get_field( stmt, i, sqlsrv_php_type, true /*prefer string*/,
|
||||
&field_value, &field_len, false /*cache_field*/, &sqlsrv_php_type_out TSRMLS_CC );
|
||||
field = *(convert_to_zval( sqlsrv_php_type_out, field_value, field_len ));
|
||||
field_value, &field_len, false /*cache_field*/, &sqlsrv_php_type_out TSRMLS_CC );
|
||||
|
||||
zval field;
|
||||
ZVAL_UNDEF( &field );
|
||||
convert_to_zval( stmt, sqlsrv_php_type_out, field_value, field_len, field );
|
||||
sqlsrv_free( field_value );
|
||||
if( fetch_type & SQLSRV_FETCH_NUMERIC ) {
|
||||
|
||||
zr = add_next_index_zval( &fields, &field );
|
||||
CHECK_ZEND_ERROR( zr, stmt, SQLSRV_ERROR_ZEND_HASH ) {
|
||||
throw ss::SSException();
|
||||
}
|
||||
Z_TRY_ADDREF_P(&field);
|
||||
}
|
||||
|
||||
if( fetch_type & SQLSRV_FETCH_ASSOC ) {
|
||||
|
@ -1875,14 +1861,16 @@ void fetch_fields_common( __inout ss_sqlsrv_stmt* stmt, zend_long fetch_type, __
|
|||
CHECK_ZEND_ERROR( zr, stmt, SQLSRV_ERROR_ZEND_HASH ) {
|
||||
throw ss::SSException();
|
||||
}
|
||||
Z_TRY_ADDREF_P(&field);
|
||||
}
|
||||
}
|
||||
//only addref when the fetch_type is BOTH because this is the only case when fields(hashtable)
|
||||
//has 2 elements pointing to field. Do not addref if the type is NUMBERIC or ASSOC because
|
||||
//fields now only has 1 element pointing to field and we want the ref count to be only 1
|
||||
if (fetch_type == SQLSRV_FETCH_BOTH) {
|
||||
Z_TRY_ADDREF(field);
|
||||
}
|
||||
} //for loop
|
||||
|
||||
*return_value = fields;
|
||||
ZVAL_NULL( &fields );
|
||||
zval_ptr_dtor( &fields );
|
||||
}
|
||||
|
||||
void parse_param_array( ss_sqlsrv_stmt* stmt, __inout zval* param_array, zend_ulong index, __out SQLSMALLINT& direction,
|
||||
|
@ -2123,21 +2111,20 @@ bool is_valid_sqlsrv_sqltype( sqlsrv_sqltype sql_type )
|
|||
// of standard encodings created at module initialization time
|
||||
bool verify_and_set_encoding( const char* encoding_string, __out sqlsrv_phptype& phptype_encoding TSRMLS_DC )
|
||||
{
|
||||
for( zend_hash_internal_pointer_reset( g_ss_encodings_ht );
|
||||
zend_hash_has_more_elements( g_ss_encodings_ht ) == SUCCESS;
|
||||
zend_hash_move_forward( g_ss_encodings_ht ) ) {
|
||||
|
||||
sqlsrv_encoding* encoding;
|
||||
int zr = (encoding = reinterpret_cast<sqlsrv_encoding*>(zend_hash_get_current_data_ptr(g_ss_encodings_ht))) != NULL ? SUCCESS : FAILURE;
|
||||
if( zr == FAILURE ) {
|
||||
void* encoding_temp = NULL;
|
||||
zend_ulong index = -1;
|
||||
zend_string* key = NULL;
|
||||
ZEND_HASH_FOREACH_KEY_PTR( g_ss_encodings_ht, index, key, encoding_temp ) {
|
||||
if ( !encoding_temp ) {
|
||||
DIE( "Fatal: Error retrieving encoding from encoding hash table." );
|
||||
}
|
||||
|
||||
sqlsrv_encoding* encoding = reinterpret_cast<sqlsrv_encoding*>( encoding_temp );
|
||||
encoding_temp = NULL;
|
||||
if( !stricmp( encoding_string, encoding->iana )) {
|
||||
phptype_encoding.typeinfo.encoding = encoding->code_page;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ BEGIN
|
|||
BEGIN
|
||||
VALUE "Comments", "This product includes PHP software that is freely available from http://www.php.net/software/. Copyright © 2001-2016 The PHP Group. All rights reserved.\0"
|
||||
VALUE "CompanyName", "Microsoft Corp.\0"
|
||||
VALUE "FileDescription", "Microsoft Drivers for PHP for SQL Server (SQLSRV Driver)\0"
|
||||
VALUE "FileDescription", "Microsoft Drivers for PHP for SQL Server (PDO Driver)\0"
|
||||
VALUE "FileVersion", STRVER4(SQLVERSION_MAJOR,SQLVERSION_MINOR, SQLVERSION_MMDD, SQLVERSION_REVISION)
|
||||
VALUE "InternalName", FILE_NAME "\0"
|
||||
VALUE "LegalCopyright", "Copyright Microsoft Corporation.\0"
|
||||
|
|
|
@ -415,7 +415,7 @@ bool ss_error_handler(sqlsrv_context& ctx, unsigned int sqlsrv_error_code, bool
|
|||
severity = SEV_WARNING;
|
||||
}
|
||||
|
||||
return handle_errors_and_warnings( ctx, SQLSRV_G( errors ), SQLSRV_G( warnings ), severity, sqlsrv_error_code, warning,
|
||||
return handle_errors_and_warnings( ctx, &SQLSRV_G( errors ), &SQLSRV_G( warnings ), severity, sqlsrv_error_code, warning,
|
||||
print_args TSRMLS_CC );
|
||||
}
|
||||
|
||||
|
@ -464,49 +464,35 @@ PHP_FUNCTION( sqlsrv_errors )
|
|||
|
||||
LOG_FUNCTION( "sqlsrv_errors" );
|
||||
|
||||
if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flags ) == FAILURE ) {
|
||||
|
||||
if(( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flags ) == FAILURE ) ||
|
||||
( flags != SQLSRV_ERR_ALL && flags != SQLSRV_ERR_ERRORS && flags != SQLSRV_ERR_WARNINGS )) {
|
||||
LOG( SEV_ERROR, "An invalid parameter was passed to %1!s!.", _FN_ );
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
if( flags == SQLSRV_ERR_ALL ) {
|
||||
|
||||
int result;
|
||||
zval both_z;
|
||||
ZVAL_UNDEF( &both_z );
|
||||
result = array_init( &both_z );
|
||||
zval err_z;
|
||||
ZVAL_UNDEF( &err_z );
|
||||
result = array_init( &err_z );
|
||||
if( result == FAILURE ) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
if( flags == SQLSRV_ERR_ALL || flags == SQLSRV_ERR_ERRORS ) {
|
||||
if( Z_TYPE( SQLSRV_G( errors )) == IS_ARRAY && !sqlsrv_merge_zend_hash( &err_z, &SQLSRV_G( errors ) TSRMLS_CC )) {
|
||||
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
if( Z_TYPE_P( SQLSRV_G( errors )) == IS_ARRAY && !sqlsrv_merge_zend_hash( &both_z, SQLSRV_G( errors ) TSRMLS_CC )) {
|
||||
}
|
||||
if( flags == SQLSRV_ERR_ALL || flags == SQLSRV_ERR_WARNINGS ) {
|
||||
if( Z_TYPE( SQLSRV_G( warnings )) == IS_ARRAY && !sqlsrv_merge_zend_hash( &err_z, &SQLSRV_G( warnings ) TSRMLS_CC )) {
|
||||
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
if( Z_TYPE_P( SQLSRV_G( warnings )) == IS_ARRAY && !sqlsrv_merge_zend_hash( &both_z, SQLSRV_G( warnings ) TSRMLS_CC )) {
|
||||
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
if( zend_hash_num_elements( Z_ARRVAL_P( &both_z )) == 0 ) {
|
||||
if( zend_hash_num_elements( Z_ARRVAL_P( &err_z )) == 0 ) {
|
||||
|
||||
RETURN_NULL();
|
||||
}
|
||||
|
||||
RETURN_ZVAL( &both_z , 1, 1 );
|
||||
}
|
||||
|
||||
else if( flags == SQLSRV_ERR_WARNINGS ) {
|
||||
|
||||
RETURN_ZVAL( SQLSRV_G( warnings ), 1, 0 );
|
||||
}
|
||||
else {
|
||||
|
||||
RETURN_ZVAL( SQLSRV_G( errors ), 1, 0 );
|
||||
}
|
||||
RETURN_ZVAL( &err_z, 1, 1 );
|
||||
}
|
||||
|
||||
// sqlsrv_configure( string $setting, mixed $value )
|
||||
|
@ -875,11 +861,12 @@ bool handle_errors_and_warnings( sqlsrv_context& ctx, zval* reported_chain, zval
|
|||
// see RINIT in init.cpp for information about which errors are ignored.
|
||||
bool ignore_warning( char* sql_state, int native_code TSRMLS_DC )
|
||||
{
|
||||
for( zend_hash_internal_pointer_reset( g_ss_warnings_to_ignore_ht );
|
||||
zend_hash_has_more_elements( g_ss_warnings_to_ignore_ht ) == SUCCESS;
|
||||
zend_hash_move_forward( g_ss_warnings_to_ignore_ht ) ) {
|
||||
zend_ulong index = -1;
|
||||
zend_string* key = NULL;
|
||||
void* error_temp = NULL;
|
||||
|
||||
sqlsrv_error* error = static_cast<sqlsrv_error*>(zend_hash_get_current_data_ptr( g_ss_warnings_to_ignore_ht ));
|
||||
ZEND_HASH_FOREACH_KEY_PTR( g_ss_warnings_to_ignore_ht, index, key, error_temp ) {
|
||||
sqlsrv_error* error = static_cast<sqlsrv_error*>( error_temp );
|
||||
if (NULL == error) {
|
||||
return false;
|
||||
}
|
||||
|
@ -888,7 +875,7 @@ bool ignore_warning( char* sql_state, int native_code TSRMLS_DC )
|
|||
( error->native_code == native_code || error->native_code == -1 )) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -911,27 +898,24 @@ bool sqlsrv_merge_zend_hash( __inout zval* dest_z, zval const* src_z TSRMLS_DC )
|
|||
}
|
||||
|
||||
HashTable* src_ht = Z_ARRVAL_P( src_z );
|
||||
int result = SUCCESS;
|
||||
|
||||
for( zend_hash_internal_pointer_reset( src_ht );
|
||||
zend_hash_has_more_elements( src_ht ) == SUCCESS;
|
||||
zend_hash_move_forward( src_ht ) ) {
|
||||
|
||||
zend_ulong index = -1;
|
||||
zend_string* key = NULL;
|
||||
zval* value_z = NULL;
|
||||
result = (value_z = zend_hash_get_current_data( src_ht )) != NULL ? SUCCESS : FAILURE;
|
||||
if( result == FAILURE ) {
|
||||
|
||||
ZEND_HASH_FOREACH_KEY_VAL( src_ht, index, key, value_z ) {
|
||||
if ( !value_z ) {
|
||||
zend_hash_apply( Z_ARRVAL_P(dest_z), sqlsrv_merge_zend_hash_dtor TSRMLS_CC );
|
||||
return false;
|
||||
}
|
||||
|
||||
result = add_next_index_zval( dest_z, value_z );
|
||||
int result = add_next_index_zval( dest_z, value_z );
|
||||
|
||||
if( result == FAILURE ) {
|
||||
zend_hash_apply( Z_ARRVAL_P( dest_z ), sqlsrv_merge_zend_hash_dtor TSRMLS_CC );
|
||||
return false;
|
||||
}
|
||||
Z_TRY_ADDREF_P( value_z );
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue