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,39 +124,49 @@ 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 );
|
||||
|
||||
build_connection_string_and_set_conn_attr( conn, server, uid, pwd, options_ht, valid_conn_opts, driver,
|
||||
conn_str TSRMLS_CC );
|
||||
|
||||
// We only support UTF-8 encoding for connection string.
|
||||
// Convert our UTF-8 connection string to UTF-16 before connecting with SQLDriverConnnectW
|
||||
wconn_len = static_cast<unsigned int>( conn_str.length() + 1 ) * sizeof( wchar_t );
|
||||
// We only support UTF-8 encoding for connection string.
|
||||
// Convert our UTF-8 connection string to UTF-16 before connecting with SQLDriverConnnectW
|
||||
wconn_len = static_cast<unsigned int>( conn_str.length() + 1 ) * sizeof( wchar_t );
|
||||
|
||||
wconn_string = utf16_string_from_mbcs_string( SQLSRV_ENCODING_UTF8, conn_str.c_str(), static_cast<unsigned int>( conn_str.length() ), &wconn_len );
|
||||
CHECK_CUSTOM_ERROR( wconn_string == NULL, conn, SQLSRV_ERROR_CONNECT_STRING_ENCODING_TRANSLATE, get_last_error_message() )
|
||||
{
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
SQLSMALLINT output_conn_size;
|
||||
r = SQLDriverConnectW( conn->handle(), NULL, reinterpret_cast<SQLWCHAR*>( wconn_string.get() ),
|
||||
static_cast<SQLSMALLINT>( wconn_len ), NULL,
|
||||
0, &output_conn_size, SQL_DRIVER_NOPROMPT );
|
||||
// clear the connection string from memory to remove sensitive data (such as a password).
|
||||
memset( const_cast<char*>( conn_str.c_str()), 0, conn_str.size() );
|
||||
memset( wconn_string, 0, wconn_len * sizeof( wchar_t )); // wconn_len is the number of characters, not bytes
|
||||
conn_str.clear();
|
||||
wconn_string = utf16_string_from_mbcs_string(SQLSRV_ENCODING_UTF8, conn_str.c_str(), static_cast<unsigned int>(conn_str.length()), &wconn_len);
|
||||
CHECK_CUSTOM_ERROR( wconn_string == NULL, conn, SQLSRV_ERROR_CONNECT_STRING_ENCODING_TRANSLATE, get_last_error_message())
|
||||
{
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
if( !SQL_SUCCEEDED( r )) {
|
||||
SQLCHAR state[ SQL_SQLSTATE_BUFSIZE ];
|
||||
SQLSMALLINT len;
|
||||
SQLRETURN r = SQLGetDiagField( SQL_HANDLE_DBC, conn->handle(), 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len );
|
||||
// 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() ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
}
|
||||
SQLSMALLINT output_conn_size;
|
||||
r = SQLDriverConnectW( conn->handle(), NULL, reinterpret_cast<SQLWCHAR*>( wconn_string.get()),
|
||||
static_cast<SQLSMALLINT>( wconn_len ), NULL,
|
||||
0, &output_conn_size, SQL_DRIVER_NOPROMPT );
|
||||
// clear the connection string from memory to remove sensitive data (such as a password).
|
||||
memset( const_cast<char*>( conn_str.c_str()), 0, conn_str.size() );
|
||||
memset( wconn_string, 0, wconn_len * sizeof( wchar_t )); // wconn_len is the number of characters, not bytes
|
||||
conn_str.clear();
|
||||
|
||||
if( !SQL_SUCCEEDED( r )) {
|
||||
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( 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();
|
||||
}
|
||||
|
@ -168,7 +178,7 @@ sqlsrv_conn* core_sqlsrv_connect( sqlsrv_context& henv_cp, sqlsrv_context& henv_
|
|||
// determine the version of the server we're connected to. The server version is left in the
|
||||
// connection upon return.
|
||||
determine_server_version( conn TSRMLS_CC );
|
||||
|
||||
|
||||
}
|
||||
catch( std::bad_alloc& ) {
|
||||
memset( const_cast<char*>( conn_str.c_str()), 0, conn_str.size() );
|
||||
|
@ -532,9 +542,7 @@ void build_connection_string_and_set_conn_attr( sqlsrv_conn* conn, const char* s
|
|||
int zr = SUCCESS;
|
||||
|
||||
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,30 +594,25 @@ 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;
|
||||
zval* data = NULL;
|
||||
zend_string *key = NULL;
|
||||
zend_ulong index = -1;
|
||||
zval* data = NULL;
|
||||
|
||||
type = zend_hash_get_current_key( options, &key, &index );
|
||||
|
||||
// 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 );
|
||||
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;
|
||||
|
||||
conn_opt = get_connection_option( conn, index, valid_conn_opts TSRMLS_CC );
|
||||
|
||||
if( index == SQLSRV_CONN_OPTION_MARS ) {
|
||||
mars_mentioned = true;
|
||||
}
|
||||
|
||||
conn_opt->func( conn_opt, data, conn, connection_string TSRMLS_CC );
|
||||
}
|
||||
// The driver layer should ensure a valid key.
|
||||
DEBUG_SQLSRV_ASSERT(( type == HASH_KEY_IS_LONG ), "build_connection_string_and_set_conn_attr: invalid connection option key type." );
|
||||
|
||||
conn_opt = get_connection_option( conn, index, valid_conn_opts TSRMLS_CC );
|
||||
|
||||
if( index == SQLSRV_CONN_OPTION_MARS ) {
|
||||
mars_mentioned = true;
|
||||
}
|
||||
|
||||
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,8 +1323,8 @@ 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 SQLSRV_PHPTYPE *sqlsrv_php_type_out TSRMLS_DC );
|
||||
__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 );
|
||||
void core_sqlsrv_post_param( sqlsrv_stmt* stmt, zend_ulong paramno, zval* param_z TSRMLS_DC );
|
||||
|
@ -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,
|
||||
|
@ -91,8 +91,8 @@ void default_sql_type( sqlsrv_stmt* stmt, SQLULEN paramno, zval* param_z, SQLSRV
|
|||
__out SQLSMALLINT& sql_type TSRMLS_DC );
|
||||
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 );
|
||||
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 );
|
||||
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,32 +248,26 @@ 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_ulong index = -1;
|
||||
zend_string *key = NULL;
|
||||
zval* value_z = NULL;
|
||||
|
||||
zend_string *key = NULL;
|
||||
zend_ulong index = -1;
|
||||
zval* value_z = NULL;
|
||||
ZEND_HASH_FOREACH_KEY_VAL( options_ht, index, key, value_z ) {
|
||||
|
||||
int type = zend_hash_get_current_key( options_ht, &key, &index);
|
||||
|
||||
// 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.
|
||||
// The driver layer should ensure that the key is valid.
|
||||
DEBUG_SQLSRV_ASSERT( stmt_opt != NULL, "allocate_stmt: unexpected null value for statement option." );
|
||||
|
||||
// perform the actions the statement option needs done.
|
||||
(*stmt_opt->func)( stmt, stmt_opt, value_z TSRMLS_CC );
|
||||
}
|
||||
int type = key ? HASH_KEY_IS_STRING : HASH_KEY_IS_LONG;
|
||||
|
||||
zend_hash_internal_pointer_end( options_ht );
|
||||
// The driver layer should ensure a valid key.
|
||||
DEBUG_SQLSRV_ASSERT(( type == HASH_KEY_IS_LONG ), "allocate_stmt: Invalid statment option key provided." );
|
||||
|
||||
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.
|
||||
// The driver layer should ensure that the key is valid.
|
||||
DEBUG_SQLSRV_ASSERT( stmt_opt != NULL, "allocate_stmt: unexpected null value for statement option." );
|
||||
|
||||
// perform the actions the statement option needs done.
|
||||
(*stmt_opt->func)( stmt, stmt_opt, value_z TSRMLS_CC );
|
||||
} 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
|
||||
zend_hash_clean( Z_ARRVAL( stmt->param_streams ));
|
||||
|
||||
if ( stmt->send_streams_at_exec ) {
|
||||
zend_hash_clean( Z_ARRVAL( stmt->param_streams ));
|
||||
}
|
||||
}
|
||||
catch( core::CoreException& e ) {
|
||||
|
||||
|
@ -869,100 +864,100 @@ 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 SQLSRV_PHPTYPE *sqlsrv_php_type_out TSRMLS_DC )
|
||||
__out void*& field_value, __out SQLLEN* field_len, bool cache_field,
|
||||
__out SQLSRV_PHPTYPE *sqlsrv_php_type_out TSRMLS_DC)
|
||||
{
|
||||
try {
|
||||
|
||||
// close the stream to release the resource
|
||||
close_active_stream( stmt TSRMLS_CC );
|
||||
|
||||
// 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))))) {
|
||||
// the field value is NULL
|
||||
if( cached->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 );
|
||||
if( cached->type.typeinfo.type == SQLSRV_PHPTYPE_STRING ) {
|
||||
// prevent the 'string not null terminated' warning
|
||||
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 ); }
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sqlsrv_phptype sqlsrv_php_type = sqlsrv_php_type_in;
|
||||
try {
|
||||
|
||||
SQLLEN sql_field_type = 0;
|
||||
SQLLEN sql_field_len = 0;
|
||||
// close the stream to release the resource
|
||||
close_active_stream(stmt TSRMLS_CC);
|
||||
|
||||
// Make sure that the statement was executed and not just prepared.
|
||||
CHECK_CUSTOM_ERROR( !stmt->executed, stmt, SQLSRV_ERROR_STATEMENT_NOT_EXECUTED ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
// if the field has been retrieved before, return the previous result
|
||||
field_cache* cached = NULL;
|
||||
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_len = 0;
|
||||
if( sqlsrv_php_type_out ) { *sqlsrv_php_type_out = SQLSRV_PHPTYPE_NULL; }
|
||||
}
|
||||
else {
|
||||
|
||||
// if the field is to be cached, and this field is being retrieved out of order, cache prior fields so they
|
||||
// may also be retrieved.
|
||||
if( cache_field && ( field_index - stmt->last_field_index ) >= 2 ) {
|
||||
sqlsrv_phptype invalid;
|
||||
invalid.typeinfo.type = SQLSRV_PHPTYPE_INVALID;
|
||||
for( int i = stmt->last_field_index + 1; i < field_index; ++i ) {
|
||||
SQLSRV_ASSERT((cached = reinterpret_cast<field_cache*>(zend_hash_index_find_ptr(Z_ARRVAL(stmt->field_cache), i))) == NULL,
|
||||
"Field already cached." );
|
||||
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;
|
||||
*field_len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
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';
|
||||
}
|
||||
*field_len = cached->len;
|
||||
if( sqlsrv_php_type_out) { *sqlsrv_php_type_out = static_cast<SQLSRV_PHPTYPE>(cached->type.typeinfo.type); }
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// If the php type was not specified set the php type to be the default type.
|
||||
if( sqlsrv_php_type.typeinfo.type == SQLSRV_PHPTYPE_INVALID ) {
|
||||
|
||||
// Get the SQL type of the field.
|
||||
core::SQLColAttribute( stmt, field_index + 1, SQL_DESC_CONCISE_TYPE, NULL, 0, NULL, &sql_field_type TSRMLS_CC );
|
||||
|
||||
// Get the length of the field.
|
||||
core::SQLColAttribute( stmt, field_index + 1, SQL_DESC_LENGTH, NULL, 0, NULL, &sql_field_len TSRMLS_CC );
|
||||
sqlsrv_phptype sqlsrv_php_type = sqlsrv_php_type_in;
|
||||
|
||||
// Get the corresponding php type from the sql type.
|
||||
sqlsrv_php_type = stmt->sql_type_to_php_type( static_cast<SQLINTEGER>( sql_field_type ), static_cast<SQLUINTEGER>( sql_field_len ), prefer_string );
|
||||
}
|
||||
SQLLEN sql_field_type = 0;
|
||||
SQLLEN sql_field_len = 0;
|
||||
|
||||
// Verify that we have an acceptable type to convert.
|
||||
CHECK_CUSTOM_ERROR( !is_valid_sqlsrv_phptype( sqlsrv_php_type ), stmt, SQLSRV_ERROR_INVALID_TYPE ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
if( sqlsrv_php_type_out != NULL )
|
||||
*sqlsrv_php_type_out = static_cast<SQLSRV_PHPTYPE>( sqlsrv_php_type.typeinfo.type );
|
||||
// Make sure that the statement was executed and not just prepared.
|
||||
CHECK_CUSTOM_ERROR( !stmt->executed, stmt, SQLSRV_ERROR_STATEMENT_NOT_EXECUTED ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
// Retrieve the data
|
||||
core_get_field_common( stmt, field_index, sqlsrv_php_type, field_value, field_len TSRMLS_CC );
|
||||
|
||||
// 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 );
|
||||
core::sqlsrv_zend_hash_index_update_mem( *stmt, Z_ARRVAL( stmt->field_cache ), field_index, &cache, sizeof(field_cache) TSRMLS_CC );
|
||||
}
|
||||
}
|
||||
// if the field is to be cached, and this field is being retrieved out of order, cache prior fields so they
|
||||
// may also be retrieved.
|
||||
if( cache_field && (field_index - stmt->last_field_index ) >= 2 ) {
|
||||
sqlsrv_phptype invalid;
|
||||
invalid.typeinfo.type = SQLSRV_PHPTYPE_INVALID;
|
||||
for( int i = stmt->last_field_index + 1; i < field_index; ++i ) {
|
||||
SQLSRV_ASSERT((cached = reinterpret_cast<field_cache*>(zend_hash_index_find_ptr(Z_ARRVAL(stmt->field_cache), i))) == NULL,
|
||||
"Field already cached." );
|
||||
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;
|
||||
*field_len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
catch( core::CoreException& e) {
|
||||
throw e;
|
||||
}
|
||||
// If the php type was not specified set the php type to be the default type.
|
||||
if( sqlsrv_php_type.typeinfo.type == SQLSRV_PHPTYPE_INVALID ) {
|
||||
|
||||
// Get the SQL type of the field.
|
||||
core::SQLColAttribute( stmt, field_index + 1, SQL_DESC_CONCISE_TYPE, NULL, 0, NULL, &sql_field_type TSRMLS_CC );
|
||||
|
||||
// Get the length of the field.
|
||||
core::SQLColAttribute( stmt, field_index + 1, SQL_DESC_LENGTH, NULL, 0, NULL, &sql_field_len TSRMLS_CC );
|
||||
|
||||
// Get the corresponding php type from the sql type.
|
||||
sqlsrv_php_type = stmt->sql_type_to_php_type( static_cast<SQLINTEGER>( sql_field_type ), static_cast<SQLUINTEGER>( sql_field_len ), prefer_string );
|
||||
}
|
||||
|
||||
// Verify that we have an acceptable type to convert.
|
||||
CHECK_CUSTOM_ERROR( !is_valid_sqlsrv_phptype( sqlsrv_php_type ), stmt, SQLSRV_ERROR_INVALID_TYPE ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
if( sqlsrv_php_type_out != NULL )
|
||||
*sqlsrv_php_type_out = static_cast<SQLSRV_PHPTYPE>( sqlsrv_php_type.typeinfo.type );
|
||||
|
||||
// Retrieve the data
|
||||
core_get_field_common( stmt, field_index, sqlsrv_php_type, field_value, field_len TSRMLS_CC );
|
||||
|
||||
// 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 );
|
||||
core::sqlsrv_zend_hash_index_update_mem( *stmt, Z_ARRVAL( stmt->field_cache ), field_index, &cache, sizeof(field_cache) TSRMLS_CC );
|
||||
}
|
||||
}
|
||||
|
||||
catch( core::CoreException& e ) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
// core_sqlsrv_has_any_result
|
||||
|
@ -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." );
|
||||
|
||||
}
|
||||
|
||||
|
@ -1470,191 +1468,191 @@ size_t calc_utf8_missing( sqlsrv_stmt* stmt, const char* buffer, size_t buffer_e
|
|||
// The memory allocation has to happen in the core layer because otherwise
|
||||
// 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 )
|
||||
{
|
||||
try {
|
||||
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 )
|
||||
{
|
||||
try {
|
||||
|
||||
close_active_stream( stmt TSRMLS_CC );
|
||||
close_active_stream( stmt TSRMLS_CC );
|
||||
|
||||
// make sure that fetch is called before trying to retrieve.
|
||||
CHECK_CUSTOM_ERROR( !stmt->fetch_called, stmt, SQLSRV_ERROR_FETCH_NOT_CALLED ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
// make sure that fetch is called before trying to retrieve.
|
||||
CHECK_CUSTOM_ERROR( !stmt->fetch_called, stmt, SQLSRV_ERROR_FETCH_NOT_CALLED ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
// make sure that fields are not retrieved incorrectly.
|
||||
CHECK_CUSTOM_ERROR( stmt->last_field_index > field_index, stmt, SQLSRV_ERROR_FIELD_INDEX_ERROR, field_index,
|
||||
stmt->last_field_index ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
// make sure that fields are not retrieved incorrectly.
|
||||
CHECK_CUSTOM_ERROR( stmt->last_field_index > field_index, stmt, SQLSRV_ERROR_FIELD_INDEX_ERROR, field_index,
|
||||
stmt->last_field_index ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
switch( sqlsrv_php_type.typeinfo.type ) {
|
||||
|
||||
case SQLSRV_PHPTYPE_INT:
|
||||
{
|
||||
sqlsrv_malloc_auto_ptr<long> field_value_temp;
|
||||
field_value_temp = static_cast<long*>( sqlsrv_malloc( sizeof( long )));
|
||||
switch( sqlsrv_php_type.typeinfo.type ) {
|
||||
|
||||
SQLRETURN r = stmt->current_results->get_data(field_index + 1, SQL_C_LONG, field_value_temp, sizeof( long ),
|
||||
field_len, true /*handle_warning*/ TSRMLS_CC );
|
||||
|
||||
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
case SQLSRV_PHPTYPE_INT:
|
||||
{
|
||||
sqlsrv_malloc_auto_ptr<long> field_value_temp;
|
||||
field_value_temp = static_cast<long*>( sqlsrv_malloc( sizeof( long )));
|
||||
|
||||
CHECK_CUSTOM_ERROR( (r == SQL_NO_DATA), stmt, SQLSRV_ERROR_NO_DATA, field_index ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
SQLRETURN r = stmt->current_results->get_data( field_index + 1, SQL_C_LONG, field_value_temp, sizeof( long ),
|
||||
field_len, true /*handle_warning*/ TSRMLS_CC );
|
||||
|
||||
if( *field_len == SQL_NULL_DATA ) {
|
||||
*field_value = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
*field_value = field_value_temp;
|
||||
field_value_temp.transferred();
|
||||
break;
|
||||
}
|
||||
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
case SQLSRV_PHPTYPE_FLOAT:
|
||||
{
|
||||
sqlsrv_malloc_auto_ptr<double> field_value_temp;
|
||||
field_value_temp = static_cast<double*>( sqlsrv_malloc( sizeof( double )));
|
||||
CHECK_CUSTOM_ERROR(( r == SQL_NO_DATA ), stmt, SQLSRV_ERROR_NO_DATA, field_index ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
SQLRETURN r = stmt->current_results->get_data( field_index + 1, SQL_C_DOUBLE, field_value_temp, sizeof( double ),
|
||||
field_len, true /*handle_warning*/ TSRMLS_CC );
|
||||
|
||||
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
if( *field_len == SQL_NULL_DATA ) {
|
||||
field_value = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
CHECK_CUSTOM_ERROR( (r == SQL_NO_DATA), stmt, SQLSRV_ERROR_NO_DATA, field_index ) {
|
||||
throw core::CoreException ();
|
||||
}
|
||||
field_value = field_value_temp;
|
||||
field_value_temp.transferred();
|
||||
break;
|
||||
}
|
||||
|
||||
if( *field_len == SQL_NULL_DATA ) {
|
||||
*field_value = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
*field_value = field_value_temp;
|
||||
field_value_temp.transferred();
|
||||
break;
|
||||
}
|
||||
|
||||
case SQLSRV_PHPTYPE_STRING:
|
||||
{
|
||||
get_field_as_string( stmt, field_index, sqlsrv_php_type, field_value, field_len TSRMLS_CC );
|
||||
break;
|
||||
}
|
||||
|
||||
// get the date as a string (http://msdn2.microsoft.com/en-us/library/ms712387(VS.85).aspx) and
|
||||
// convert it to a DateTime object and return the created object
|
||||
case SQLSRV_PHPTYPE_DATETIME:
|
||||
{
|
||||
char field_value_temp[ MAX_DATETIME_STRING_LEN ];
|
||||
zval params[1];
|
||||
zval field_value_temp_z;
|
||||
zval function_z;
|
||||
zval_auto_ptr return_value_z;
|
||||
|
||||
ZVAL_UNDEF( &field_value_temp_z );
|
||||
ZVAL_UNDEF( &function_z );
|
||||
ZVAL_UNDEF( params );
|
||||
return_value_z = (zval *)sqlsrv_malloc( sizeof(zval) );
|
||||
ZVAL_UNDEF( return_value_z );
|
||||
|
||||
SQLRETURN r = stmt->current_results->get_data( field_index + 1, SQL_C_CHAR, field_value_temp,
|
||||
MAX_DATETIME_STRING_LEN, field_len, true TSRMLS_CC );
|
||||
case SQLSRV_PHPTYPE_FLOAT:
|
||||
{
|
||||
sqlsrv_malloc_auto_ptr<double> field_value_temp;
|
||||
field_value_temp = static_cast<double*>( sqlsrv_malloc( sizeof( double )));
|
||||
|
||||
SQLRETURN r = stmt->current_results->get_data( field_index + 1, SQL_C_DOUBLE, field_value_temp, sizeof( double ),
|
||||
field_len, true /*handle_warning*/ TSRMLS_CC );
|
||||
|
||||
CHECK_CUSTOM_ERROR( (r == SQL_NO_DATA), stmt, SQLSRV_ERROR_NO_DATA, field_index ) {
|
||||
throw core::CoreException ();
|
||||
}
|
||||
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
if( *field_len == SQL_NULL_DATA ) {
|
||||
ZVAL_NULL( return_value_z );
|
||||
*field_value = reinterpret_cast<void*>( return_value_z.get() );
|
||||
return_value_z.transferred();
|
||||
break;
|
||||
}
|
||||
|
||||
// Convert the string date to a DateTime object
|
||||
core::sqlsrv_zval_stringl( &field_value_temp_z, field_value_temp, *field_len );
|
||||
core::sqlsrv_zval_stringl( &function_z, "date_create", sizeof("date_create") -1 );
|
||||
params[0] = field_value_temp_z;
|
||||
CHECK_CUSTOM_ERROR(( r == SQL_NO_DATA ), stmt, SQLSRV_ERROR_NO_DATA, field_index ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
if( call_user_function( EG( function_table ), NULL, &function_z, return_value_z, 1,
|
||||
params TSRMLS_CC ) == FAILURE ) {
|
||||
THROW_CORE_ERROR( stmt, SQLSRV_ERROR_DATETIME_CONVERSION_FAILED );
|
||||
}
|
||||
|
||||
*field_value = reinterpret_cast<void*>( return_value_z.get() );
|
||||
return_value_z.transferred();
|
||||
break;
|
||||
}
|
||||
|
||||
// create a stream wrapper around the field and return that object to the PHP script. calls to fread
|
||||
// on the stream will result in calls to SQLGetData. This is handled in stream.cpp. See that file
|
||||
// for how these fields are used.
|
||||
case SQLSRV_PHPTYPE_STREAM:
|
||||
{
|
||||
|
||||
zval_auto_ptr return_value_z;
|
||||
return_value_z = (zval *)sqlsrv_malloc(sizeof(zval));
|
||||
ZVAL_UNDEF(return_value_z);
|
||||
php_stream* stream = NULL;
|
||||
sqlsrv_stream* ss = NULL;
|
||||
SQLLEN sql_type;
|
||||
if( *field_len == SQL_NULL_DATA ) {
|
||||
field_value = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
SQLRETURN r = SQLColAttribute( stmt->handle(), field_index + 1, SQL_DESC_TYPE, NULL, 0, NULL, &sql_type );
|
||||
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
CHECK_CUSTOM_ERROR( !is_streamable_type( sql_type ), stmt, SQLSRV_ERROR_STREAMABLE_TYPES_ONLY ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
stream = php_stream_open_wrapper( "sqlsrv://sqlncli10", "r", 0, NULL );
|
||||
field_value = field_value_temp;
|
||||
field_value_temp.transferred();
|
||||
break;
|
||||
}
|
||||
|
||||
CHECK_CUSTOM_ERROR( !stream, stmt, SQLSRV_ERROR_STREAM_CREATE ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
case SQLSRV_PHPTYPE_STRING:
|
||||
{
|
||||
get_field_as_string( stmt, field_index, sqlsrv_php_type, field_value, field_len TSRMLS_CC );
|
||||
break;
|
||||
}
|
||||
|
||||
ss = static_cast<sqlsrv_stream*>( stream->abstract );
|
||||
ss->stmt = stmt;
|
||||
ss->field_index = field_index;
|
||||
ss->sql_type = static_cast<SQLUSMALLINT>( sql_type );
|
||||
ss->encoding = static_cast<SQLSRV_ENCODING>( sqlsrv_php_type.typeinfo.encoding );
|
||||
// get the date as a string (http://msdn2.microsoft.com/en-us/library/ms712387(VS.85).aspx) and
|
||||
// convert it to a DateTime object and return the created object
|
||||
case SQLSRV_PHPTYPE_DATETIME:
|
||||
{
|
||||
char field_value_temp[ MAX_DATETIME_STRING_LEN ];
|
||||
zval params[1];
|
||||
zval field_value_temp_z;
|
||||
zval function_z;
|
||||
zval_auto_ptr return_value_z;
|
||||
|
||||
// turn our stream into a zval to be returned
|
||||
php_stream_to_zval( stream, return_value_z );
|
||||
ZVAL_UNDEF( &field_value_temp_z );
|
||||
ZVAL_UNDEF( &function_z );
|
||||
ZVAL_UNDEF( params );
|
||||
return_value_z = (zval *)sqlsrv_malloc( sizeof( zval ));
|
||||
ZVAL_UNDEF( return_value_z );
|
||||
|
||||
// mark this as our active stream
|
||||
stmt->active_stream = return_value_z;
|
||||
*field_value = reinterpret_cast<void*>( return_value_z.get() );
|
||||
return_value_z.transferred();
|
||||
break;
|
||||
}
|
||||
SQLRETURN r = stmt->current_results->get_data( field_index + 1, SQL_C_CHAR, field_value_temp,
|
||||
MAX_DATETIME_STRING_LEN, field_len, true TSRMLS_CC );
|
||||
|
||||
case SQLSRV_PHPTYPE_NULL:
|
||||
*field_value = NULL;
|
||||
*field_len = 0;
|
||||
break;
|
||||
CHECK_CUSTOM_ERROR(( r == SQL_NO_DATA ), stmt, SQLSRV_ERROR_NO_DATA, field_index ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
default:
|
||||
DIE( "core_get_field_common: Unexpected sqlsrv_phptype provided" );
|
||||
break;
|
||||
}
|
||||
if( *field_len == SQL_NULL_DATA ) {
|
||||
ZVAL_NULL( return_value_z );
|
||||
field_value = reinterpret_cast<void*>( return_value_z.get());
|
||||
return_value_z.transferred();
|
||||
break;
|
||||
}
|
||||
|
||||
// sucessfully retrieved the field, so update our last retrieved field
|
||||
if( stmt->last_field_index < field_index ) {
|
||||
stmt->last_field_index = field_index;
|
||||
}
|
||||
}
|
||||
catch( core::CoreException& e ) {
|
||||
throw e;
|
||||
}
|
||||
// Convert the string date to a DateTime object
|
||||
core::sqlsrv_zval_stringl( &field_value_temp_z, field_value_temp, *field_len );
|
||||
core::sqlsrv_zval_stringl( &function_z, "date_create", sizeof("date_create") - 1 );
|
||||
params[0] = field_value_temp_z;
|
||||
|
||||
if( call_user_function( EG( function_table ), NULL, &function_z, return_value_z, 1,
|
||||
params TSRMLS_CC ) == FAILURE) {
|
||||
THROW_CORE_ERROR(stmt, SQLSRV_ERROR_DATETIME_CONVERSION_FAILED);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// create a stream wrapper around the field and return that object to the PHP script. calls to fread
|
||||
// on the stream will result in calls to SQLGetData. This is handled in stream.cpp. See that file
|
||||
// for how these fields are used.
|
||||
case SQLSRV_PHPTYPE_STREAM:
|
||||
{
|
||||
|
||||
zval_auto_ptr return_value_z;
|
||||
return_value_z = (zval *)sqlsrv_malloc(sizeof(zval));
|
||||
ZVAL_UNDEF(return_value_z);
|
||||
php_stream* stream = NULL;
|
||||
sqlsrv_stream* ss = NULL;
|
||||
SQLLEN sql_type;
|
||||
|
||||
SQLRETURN r = SQLColAttribute( stmt->handle(), field_index + 1, SQL_DESC_TYPE, NULL, 0, NULL, &sql_type );
|
||||
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
CHECK_CUSTOM_ERROR( !is_streamable_type( sql_type ), stmt, SQLSRV_ERROR_STREAMABLE_TYPES_ONLY ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
stream = php_stream_open_wrapper( "sqlsrv://sqlncli10", "r", 0, NULL );
|
||||
|
||||
CHECK_CUSTOM_ERROR( !stream, stmt, SQLSRV_ERROR_STREAM_CREATE ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
ss = static_cast<sqlsrv_stream*>( stream->abstract );
|
||||
ss->stmt = stmt;
|
||||
ss->field_index = field_index;
|
||||
ss->sql_type = static_cast<SQLUSMALLINT>( sql_type );
|
||||
ss->encoding = static_cast<SQLSRV_ENCODING>( sqlsrv_php_type.typeinfo.encoding );
|
||||
|
||||
// turn our stream into a zval to be returned
|
||||
php_stream_to_zval( stream, return_value_z );
|
||||
|
||||
field_value = reinterpret_cast<void*>( return_value_z.get());
|
||||
return_value_z.transferred();
|
||||
break;
|
||||
}
|
||||
|
||||
case SQLSRV_PHPTYPE_NULL:
|
||||
field_value = NULL;
|
||||
*field_len = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
DIE( "core_get_field_common: Unexpected sqlsrv_phptype provided" );
|
||||
break;
|
||||
}
|
||||
|
||||
// sucessfully retrieved the field, so update our last retrieved field
|
||||
if( stmt->last_field_index < field_index ) {
|
||||
stmt->last_field_index = field_index;
|
||||
}
|
||||
}
|
||||
catch( core::CoreException& e ) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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,241 +2036,241 @@ 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 ));
|
||||
return;
|
||||
}
|
||||
|
||||
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 )
|
||||
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 )
|
||||
{
|
||||
SQLRETURN r;
|
||||
SQLSMALLINT c_type;
|
||||
SQLLEN sql_field_type = 0;
|
||||
SQLSMALLINT extra = 0;
|
||||
SQLLEN field_len_temp;
|
||||
SQLLEN sql_display_size = 0;
|
||||
char* field_value_temp = NULL;
|
||||
SQLRETURN r;
|
||||
SQLSMALLINT c_type;
|
||||
SQLLEN sql_field_type = 0;
|
||||
SQLSMALLINT extra = 0;
|
||||
SQLLEN field_len_temp;
|
||||
SQLLEN sql_display_size = 0;
|
||||
char* field_value_temp = NULL;
|
||||
|
||||
try {
|
||||
try {
|
||||
|
||||
DEBUG_SQLSRV_ASSERT( sqlsrv_php_type.typeinfo.type == SQLSRV_PHPTYPE_STRING,
|
||||
"Type should be SQLSRV_PHPTYPE_STRING in get_field_as_string" );
|
||||
|
||||
if( sqlsrv_php_type.typeinfo.encoding == SQLSRV_ENCODING_DEFAULT ) {
|
||||
sqlsrv_php_type.typeinfo.encoding = stmt->conn->encoding();
|
||||
}
|
||||
DEBUG_SQLSRV_ASSERT( sqlsrv_php_type.typeinfo.type == SQLSRV_PHPTYPE_STRING,
|
||||
"Type should be SQLSRV_PHPTYPE_STRING in get_field_as_string" );
|
||||
|
||||
// Set the C type and account for null characters at the end of the data.
|
||||
switch( sqlsrv_php_type.typeinfo.encoding ) {
|
||||
case CP_UTF8:
|
||||
c_type = SQL_C_WCHAR;
|
||||
extra = sizeof( SQLWCHAR );
|
||||
break;
|
||||
case SQLSRV_ENCODING_BINARY:
|
||||
c_type = SQL_C_BINARY;
|
||||
extra = 0;
|
||||
break;
|
||||
default:
|
||||
c_type = SQL_C_CHAR;
|
||||
extra = sizeof( SQLCHAR );
|
||||
break;
|
||||
}
|
||||
if( sqlsrv_php_type.typeinfo.encoding == SQLSRV_ENCODING_DEFAULT ) {
|
||||
sqlsrv_php_type.typeinfo.encoding = stmt->conn->encoding();
|
||||
}
|
||||
|
||||
// Get the SQL type of the field.
|
||||
core::SQLColAttribute( stmt, field_index + 1, SQL_DESC_CONCISE_TYPE, NULL, 0, NULL, &sql_field_type TSRMLS_CC );
|
||||
// Set the C type and account for null characters at the end of the data.
|
||||
switch( sqlsrv_php_type.typeinfo.encoding ) {
|
||||
case CP_UTF8:
|
||||
c_type = SQL_C_WCHAR;
|
||||
extra = sizeof( SQLWCHAR );
|
||||
break;
|
||||
case SQLSRV_ENCODING_BINARY:
|
||||
c_type = SQL_C_BINARY;
|
||||
extra = 0;
|
||||
break;
|
||||
default:
|
||||
c_type = SQL_C_CHAR;
|
||||
extra = sizeof( SQLCHAR );
|
||||
break;
|
||||
}
|
||||
|
||||
// Calculate the field size.
|
||||
calc_string_size( stmt, field_index, sql_field_type, sql_display_size TSRMLS_CC );
|
||||
// Get the SQL type of the field.
|
||||
core::SQLColAttribute( stmt, field_index + 1, SQL_DESC_CONCISE_TYPE, NULL, 0, NULL, &sql_field_type TSRMLS_CC );
|
||||
|
||||
// if this is a large type, then read the first few bytes to get the actual length from SQLGetData
|
||||
if( sql_display_size == 0 || sql_display_size == LONG_MAX ||
|
||||
sql_display_size == LONG_MAX >> 1 || sql_display_size == ULONG_MAX - 1 ) {
|
||||
// Calculate the field size.
|
||||
calc_string_size( stmt, field_index, sql_field_type, sql_display_size TSRMLS_CC );
|
||||
|
||||
field_len_temp = INITIAL_FIELD_STRING_LEN;
|
||||
|
||||
field_value_temp = static_cast<char*>( sqlsrv_malloc( field_len_temp + extra + 1 ));
|
||||
|
||||
r = stmt->current_results->get_data( field_index + 1, c_type, field_value_temp, ( field_len_temp + extra ),
|
||||
&field_len_temp, false /*handle_warning*/ TSRMLS_CC );
|
||||
|
||||
CHECK_CUSTOM_ERROR( (r == SQL_NO_DATA), stmt, SQLSRV_ERROR_NO_DATA, field_index ) {
|
||||
throw core::CoreException ();
|
||||
}
|
||||
// if this is a large type, then read the first few bytes to get the actual length from SQLGetData
|
||||
if( sql_display_size == 0 || sql_display_size == LONG_MAX ||
|
||||
sql_display_size == LONG_MAX >> 1 || sql_display_size == ULONG_MAX - 1 ) {
|
||||
|
||||
if( field_len_temp == SQL_NULL_DATA ) {
|
||||
*field_value = NULL;
|
||||
sqlsrv_free( field_value_temp );
|
||||
return;
|
||||
}
|
||||
field_len_temp = INITIAL_FIELD_STRING_LEN;
|
||||
|
||||
if( r == SQL_SUCCESS_WITH_INFO ) {
|
||||
field_value_temp = static_cast<char*>( sqlsrv_malloc( field_len_temp + extra + 1 ));
|
||||
|
||||
r = stmt->current_results->get_data( field_index + 1, c_type, field_value_temp, ( field_len_temp + extra ),
|
||||
&field_len_temp, false /*handle_warning*/ TSRMLS_CC );
|
||||
|
||||
CHECK_CUSTOM_ERROR(( r == SQL_NO_DATA ), stmt, SQLSRV_ERROR_NO_DATA, field_index ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
if( field_len_temp == SQL_NULL_DATA ) {
|
||||
field_value = NULL;
|
||||
sqlsrv_free( field_value_temp );
|
||||
return;
|
||||
}
|
||||
|
||||
if( r == SQL_SUCCESS_WITH_INFO ) {
|
||||
|
||||
SQLCHAR state[ SQL_SQLSTATE_BUFSIZE ];
|
||||
SQLSMALLINT len;
|
||||
|
||||
stmt->current_results->get_diag_field( 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len TSRMLS_CC );
|
||||
|
||||
if( is_truncated_warning( state )) {
|
||||
|
||||
SQLCHAR state[ SQL_SQLSTATE_BUFSIZE ];
|
||||
SQLSMALLINT len;
|
||||
|
||||
stmt->current_results->get_diag_field( 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len TSRMLS_CC );
|
||||
|
||||
if( is_truncated_warning( state ) ) {
|
||||
|
||||
SQLLEN dummy_field_len;
|
||||
|
||||
// for XML (and possibly other conditions) the field length returned is not the real field length, so
|
||||
// in every pass, we double the allocation size to retrieve all the contents.
|
||||
if( field_len_temp == SQL_NO_TOTAL ) {
|
||||
|
||||
// reset the field_len_temp
|
||||
field_len_temp = INITIAL_FIELD_STRING_LEN;
|
||||
// for XML (and possibly other conditions) the field length returned is not the real field length, so
|
||||
// in every pass, we double the allocation size to retrieve all the contents.
|
||||
if( field_len_temp == SQL_NO_TOTAL ) {
|
||||
|
||||
do {
|
||||
SQLLEN initial_field_len = field_len_temp;
|
||||
// Double the size.
|
||||
field_len_temp *= 2;
|
||||
|
||||
field_value_temp = static_cast<char*>( sqlsrv_realloc( field_value_temp, field_len_temp + extra + 1 ));
|
||||
|
||||
field_len_temp -= initial_field_len;
|
||||
// reset the field_len_temp
|
||||
field_len_temp = INITIAL_FIELD_STRING_LEN;
|
||||
|
||||
// Get the rest of the data.
|
||||
r = stmt->current_results->get_data( field_index + 1, c_type, field_value_temp + initial_field_len,
|
||||
field_len_temp + extra, &dummy_field_len,
|
||||
false /*handle_warning*/ TSRMLS_CC );
|
||||
do {
|
||||
SQLLEN initial_field_len = field_len_temp;
|
||||
// Double the size.
|
||||
field_len_temp *= 2;
|
||||
|
||||
// the last packet will contain the actual amount retrieved, not SQL_NO_TOTAL
|
||||
// so we calculate the actual length of the string with that.
|
||||
if( dummy_field_len != SQL_NO_TOTAL )
|
||||
field_len_temp += dummy_field_len;
|
||||
else
|
||||
field_len_temp += initial_field_len;
|
||||
field_value_temp = static_cast<char*>( sqlsrv_realloc( field_value_temp, field_len_temp + extra + 1 ));
|
||||
|
||||
if( r == SQL_SUCCESS_WITH_INFO ) {
|
||||
core::SQLGetDiagField( stmt, 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len
|
||||
TSRMLS_CC );
|
||||
}
|
||||
field_len_temp -= initial_field_len;
|
||||
|
||||
} while( r == SQL_SUCCESS_WITH_INFO && is_truncated_warning( state ));
|
||||
}
|
||||
else {
|
||||
// Get the rest of the data.
|
||||
r = stmt->current_results->get_data( field_index + 1, c_type, field_value_temp + initial_field_len,
|
||||
field_len_temp + extra, &dummy_field_len,
|
||||
false /*handle_warning*/ TSRMLS_CC );
|
||||
|
||||
// We got the field_len_temp from SQLGetData call.
|
||||
field_value_temp = static_cast<char*>( sqlsrv_realloc( field_value_temp, field_len_temp + extra + 1 ));
|
||||
|
||||
// We have already recieved INITIAL_FIELD_STRING_LEN size data.
|
||||
field_len_temp -= INITIAL_FIELD_STRING_LEN;
|
||||
|
||||
// Get the rest of the data.
|
||||
r = stmt->current_results->get_data( field_index + 1, c_type, field_value_temp + INITIAL_FIELD_STRING_LEN,
|
||||
field_len_temp + extra, &dummy_field_len,
|
||||
true /*handle_warning*/ TSRMLS_CC );
|
||||
// the last packet will contain the actual amount retrieved, not SQL_NO_TOTAL
|
||||
// so we calculate the actual length of the string with that.
|
||||
if( dummy_field_len != SQL_NO_TOTAL )
|
||||
field_len_temp += dummy_field_len;
|
||||
else
|
||||
field_len_temp += initial_field_len;
|
||||
|
||||
if( dummy_field_len == SQL_NULL_DATA ) {
|
||||
*field_value = NULL;
|
||||
sqlsrv_free( field_value_temp );
|
||||
return;
|
||||
}
|
||||
|
||||
CHECK_CUSTOM_ERROR( (r == SQL_NO_DATA), stmt, SQLSRV_ERROR_NO_DATA, field_index ) {
|
||||
throw core::CoreException ();
|
||||
}
|
||||
|
||||
field_len_temp += INITIAL_FIELD_STRING_LEN;
|
||||
}
|
||||
if( r == SQL_SUCCESS_WITH_INFO ) {
|
||||
core::SQLGetDiagField( stmt, 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len
|
||||
TSRMLS_CC );
|
||||
}
|
||||
|
||||
} // if( is_truncation_warning ( state ) )
|
||||
else {
|
||||
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
}
|
||||
} // if( r == SQL_SUCCESS_WITH_INFO )
|
||||
} while( r == SQL_SUCCESS_WITH_INFO && is_truncated_warning( state ));
|
||||
}
|
||||
else {
|
||||
|
||||
if( sqlsrv_php_type.typeinfo.encoding == SQLSRV_ENCODING_UTF8 ) {
|
||||
// We got the field_len_temp from SQLGetData call.
|
||||
field_value_temp = static_cast<char*>( sqlsrv_realloc( field_value_temp, field_len_temp + extra + 1 ));
|
||||
|
||||
bool converted = convert_string_from_utf16_inplace( static_cast<SQLSRV_ENCODING>( sqlsrv_php_type.typeinfo.encoding ),
|
||||
&field_value_temp, field_len_temp );
|
||||
|
||||
CHECK_CUSTOM_ERROR( !converted, stmt, SQLSRV_ERROR_FIELD_ENCODING_TRANSLATE, get_last_error_message() ) {
|
||||
throw core::CoreException ();
|
||||
}
|
||||
}
|
||||
} // if ( sql_display_size == 0 || sql_display_size == LONG_MAX .. )
|
||||
|
||||
else if( sql_display_size >= 1 && sql_display_size <= SQL_SERVER_MAX_FIELD_SIZE ) {
|
||||
// We have already recieved INITIAL_FIELD_STRING_LEN size data.
|
||||
field_len_temp -= INITIAL_FIELD_STRING_LEN;
|
||||
|
||||
// only allow binary retrievals for char and binary types. All others get a string converted
|
||||
// to the encoding type they asked for.
|
||||
|
||||
// null terminator
|
||||
if( c_type == SQL_C_CHAR ) {
|
||||
sql_display_size += sizeof( SQLCHAR );
|
||||
}
|
||||
// Get the rest of the data.
|
||||
r = stmt->current_results->get_data( field_index + 1, c_type, field_value_temp + INITIAL_FIELD_STRING_LEN,
|
||||
field_len_temp + extra, &dummy_field_len,
|
||||
true /*handle_warning*/ TSRMLS_CC );
|
||||
|
||||
// For WCHAR multiply by sizeof(WCHAR) and include the null terminator
|
||||
else if( c_type == SQL_C_WCHAR ) {
|
||||
sql_display_size = (sql_display_size * sizeof(WCHAR)) + sizeof(WCHAR);
|
||||
}
|
||||
if( dummy_field_len == SQL_NULL_DATA ) {
|
||||
field_value = NULL;
|
||||
sqlsrv_free( field_value_temp );
|
||||
return;
|
||||
}
|
||||
|
||||
field_value_temp = static_cast<char*>( sqlsrv_malloc( sql_display_size + extra + 1 ));
|
||||
|
||||
// get the data
|
||||
r = stmt->current_results->get_data( field_index + 1, c_type, field_value_temp, sql_display_size,
|
||||
&field_len_temp, true /*handle_warning*/ TSRMLS_CC );
|
||||
CHECK_SQL_ERROR( r, stmt ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
CHECK_CUSTOM_ERROR( (r == SQL_NO_DATA), stmt, SQLSRV_ERROR_NO_DATA, field_index ) {
|
||||
throw core::CoreException ();
|
||||
}
|
||||
CHECK_CUSTOM_ERROR(( r == SQL_NO_DATA ), stmt, SQLSRV_ERROR_NO_DATA, field_index ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
if( field_len_temp == SQL_NULL_DATA ) {
|
||||
*field_value = NULL;
|
||||
sqlsrv_free( field_value_temp );
|
||||
return;
|
||||
}
|
||||
|
||||
if( sqlsrv_php_type.typeinfo.encoding == CP_UTF8 ) {
|
||||
field_len_temp += INITIAL_FIELD_STRING_LEN;
|
||||
}
|
||||
|
||||
bool converted = convert_string_from_utf16_inplace( static_cast<SQLSRV_ENCODING>( sqlsrv_php_type.typeinfo.encoding ),
|
||||
&field_value_temp, field_len_temp );
|
||||
|
||||
CHECK_CUSTOM_ERROR( !converted, stmt, SQLSRV_ERROR_FIELD_ENCODING_TRANSLATE, get_last_error_message() ) {
|
||||
throw core::CoreException ();
|
||||
}
|
||||
}
|
||||
} // else if( sql_display_size >= 1 && sql_display_size <= SQL_SERVER_MAX_FIELD_SIZE )
|
||||
} // if( is_truncation_warning ( state ) )
|
||||
else {
|
||||
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
}
|
||||
} // if( r == SQL_SUCCESS_WITH_INFO )
|
||||
|
||||
else {
|
||||
|
||||
DIE( "Invalid sql_display_size" );
|
||||
return; // to eliminate a warning
|
||||
}
|
||||
|
||||
*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
|
||||
// runtime checks to see if a string is null terminated and issues a warning about it if running in debug mode.
|
||||
// SQL_C_BINARY fields don't return a NULL terminator, so we allocate an extra byte on each field and use the ternary
|
||||
// operator to set add 1 to fill the null terminator
|
||||
field_value_temp[field_len_temp] = '\0';
|
||||
}
|
||||
if( sqlsrv_php_type.typeinfo.encoding == SQLSRV_ENCODING_UTF8 ) {
|
||||
|
||||
catch( core::CoreException& ) {
|
||||
bool converted = convert_string_from_utf16_inplace( static_cast<SQLSRV_ENCODING>( sqlsrv_php_type.typeinfo.encoding ),
|
||||
&field_value_temp, field_len_temp );
|
||||
|
||||
*field_value = NULL;
|
||||
*field_len = 0;
|
||||
sqlsrv_free( field_value_temp );
|
||||
throw;
|
||||
}
|
||||
catch ( ... ) {
|
||||
CHECK_CUSTOM_ERROR( !converted, stmt, SQLSRV_ERROR_FIELD_ENCODING_TRANSLATE, get_last_error_message()) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
}
|
||||
} // if ( sql_display_size == 0 || sql_display_size == LONG_MAX .. )
|
||||
|
||||
*field_value = NULL;
|
||||
*field_len = 0;
|
||||
sqlsrv_free( field_value_temp );
|
||||
throw;
|
||||
}
|
||||
else if( sql_display_size >= 1 && sql_display_size <= SQL_SERVER_MAX_FIELD_SIZE ) {
|
||||
|
||||
// only allow binary retrievals for char and binary types. All others get a string converted
|
||||
// to the encoding type they asked for.
|
||||
|
||||
// null terminator
|
||||
if( c_type == SQL_C_CHAR ) {
|
||||
sql_display_size += sizeof( SQLCHAR );
|
||||
}
|
||||
|
||||
// For WCHAR multiply by sizeof(WCHAR) and include the null terminator
|
||||
else if( c_type == SQL_C_WCHAR ) {
|
||||
sql_display_size = (sql_display_size * sizeof(WCHAR)) + sizeof(WCHAR);
|
||||
}
|
||||
|
||||
field_value_temp = static_cast<char*>( sqlsrv_malloc( sql_display_size + extra + 1 ));
|
||||
|
||||
// get the data
|
||||
r = stmt->current_results->get_data( field_index + 1, c_type, field_value_temp, sql_display_size,
|
||||
&field_len_temp, true /*handle_warning*/ TSRMLS_CC );
|
||||
CHECK_SQL_ERROR( r, stmt ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
CHECK_CUSTOM_ERROR(( r == SQL_NO_DATA ), stmt, SQLSRV_ERROR_NO_DATA, field_index ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
if( field_len_temp == SQL_NULL_DATA ) {
|
||||
field_value = NULL;
|
||||
sqlsrv_free( field_value_temp );
|
||||
return;
|
||||
}
|
||||
|
||||
if( sqlsrv_php_type.typeinfo.encoding == CP_UTF8 ) {
|
||||
|
||||
bool converted = convert_string_from_utf16_inplace( static_cast<SQLSRV_ENCODING>( sqlsrv_php_type.typeinfo.encoding ),
|
||||
&field_value_temp, field_len_temp );
|
||||
|
||||
CHECK_CUSTOM_ERROR( !converted, stmt, SQLSRV_ERROR_FIELD_ENCODING_TRANSLATE, get_last_error_message()) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
}
|
||||
} // else if( sql_display_size >= 1 && sql_display_size <= SQL_SERVER_MAX_FIELD_SIZE )
|
||||
|
||||
else {
|
||||
|
||||
DIE( "Invalid sql_display_size" );
|
||||
return; // to eliminate a warning
|
||||
}
|
||||
|
||||
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
|
||||
// runtime checks to see if a string is null terminated and issues a warning about it if running in debug mode.
|
||||
// SQL_C_BINARY fields don't return a NULL terminator, so we allocate an extra byte on each field and use the ternary
|
||||
// operator to set add 1 to fill the null terminator
|
||||
field_value_temp[field_len_temp] = '\0';
|
||||
}
|
||||
|
||||
catch( core::CoreException& ) {
|
||||
|
||||
field_value = NULL;
|
||||
*field_len = 0;
|
||||
sqlsrv_free( field_value_temp );
|
||||
throw;
|
||||
}
|
||||
catch ( ... ) {
|
||||
|
||||
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 )) {
|
||||
size_t int_key = -1;
|
||||
zend_string *key = NULL;
|
||||
zval* data = NULL;
|
||||
|
||||
int type = HASH_KEY_NON_EXISTENT;
|
||||
zend_string *key = NULL;
|
||||
size_t int_key = -1;
|
||||
zval* data;
|
||||
int result = 0;
|
||||
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();
|
||||
}
|
||||
|
||||
type = zend_hash_get_current_key( options_ht, &key, &int_key);
|
||||
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 );
|
||||
}
|
||||
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 );
|
||||
|
||||
|
|
195
sqlsrv/conn.cpp
195
sqlsrv/conn.cpp
|
@ -57,23 +57,23 @@ 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 )) {
|
||||
zend_ulong index = -1;
|
||||
zend_string* key = NULL;
|
||||
void* ss_encoding_temp = NULL;
|
||||
|
||||
sqlsrv_encoding* ss_encoding = NULL;
|
||||
core::sqlsrv_zend_hash_get_current_data_ptr( *conn, g_ss_encodings_ht,(void*&) ss_encoding TSRMLS_CC );
|
||||
|
||||
if( !strnicmp( encoding, ss_encoding->iana, encoding_len ) ) {
|
||||
ZEND_HASH_FOREACH_KEY_PTR( g_ss_encodings_ht, index, key, ss_encoding_temp ) {
|
||||
sqlsrv_encoding* ss_encoding = reinterpret_cast<sqlsrv_encoding*>( ss_encoding_temp );
|
||||
ss_encoding_temp = NULL;
|
||||
if (!strnicmp( encoding, ss_encoding->iana, encoding_len )) {
|
||||
|
||||
if( ss_encoding->not_for_connection ) {
|
||||
THROW_SS_ERROR( conn, SS_SQLSRV_ERROR_CONNECT_ILLEGAL_ENCODING, encoding );
|
||||
}
|
||||
if ( ss_encoding->not_for_connection ) {
|
||||
THROW_SS_ERROR( conn, SS_SQLSRV_ERROR_CONNECT_ILLEGAL_ENCODING, encoding );
|
||||
}
|
||||
|
||||
conn->set_encoding( static_cast<SQLSRV_ENCODING>( ss_encoding->code_page ));
|
||||
return;
|
||||
}
|
||||
}
|
||||
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,45 +1085,41 @@ 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;
|
||||
|
||||
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 );
|
||||
}
|
||||
catch( core::CoreException& ) {
|
||||
zval* rsrc_ptr = NULL;
|
||||
ZEND_HASH_FOREACH_VAL( conn->stmts, rsrc_ptr ) {
|
||||
try {
|
||||
int zr = ( rsrc_ptr ) != NULL ? SUCCESS : FAILURE;
|
||||
CHECK_ZEND_ERROR( zr, *conn, SQLSRV_ERROR_ZEND_HASH ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
}
|
||||
catch( core::CoreException& ) {
|
||||
DIE( "sqlsrv_conn_close_stmts: Failed to retrieve a statement resource from the connection" );
|
||||
}
|
||||
// see if the statement is still valid, and if not skip to the next one
|
||||
// presumably this should never happen because if it's in the list, it should still be valid
|
||||
// by virtue that a statement resource should remove itself from its connection when it is
|
||||
// destroyed in sqlsrv_stmt_dtor. However, rather than die (assert), we simply skip this resource
|
||||
// and move to the next one.
|
||||
ss_sqlsrv_stmt* stmt = NULL;
|
||||
stmt = static_cast<ss_sqlsrv_stmt*>( Z_RES_VAL_P( rsrc_ptr ));
|
||||
if( stmt == NULL || Z_RES_TYPE_P( rsrc_ptr ) != ss_sqlsrv_stmt::descriptor ) {
|
||||
LOG( SEV_ERROR, "Non existent statement found in connection. Statements should remove themselves"
|
||||
" from the connection so this shouldn't be out of sync." );
|
||||
continue;
|
||||
}
|
||||
// delete the statement by deleting it from Zend's resource list, which will force its destruction
|
||||
stmt->conn = NULL;
|
||||
|
||||
DIE( "sqlsrv_conn_close_stmts: Failed to retrieve a statement resource from the connection" );
|
||||
}
|
||||
|
||||
// see if the statement is still valid, and if not skip to the next one
|
||||
// presumably this should never happen because if it's in the list, it should still be valid
|
||||
// by virtue that a statement resource should remove itself from its connection when it is
|
||||
// destroyed in sqlsrv_stmt_dtor. However, rather than die (assert), we simply skip this resource
|
||||
// and move to the next one.
|
||||
ss_sqlsrv_stmt* stmt = NULL;
|
||||
stmt = static_cast<ss_sqlsrv_stmt*>( Z_RES_VAL_P( rsrc_ptr ));
|
||||
if (stmt == NULL || Z_RES_TYPE_P(rsrc_ptr) != ss_sqlsrv_stmt::descriptor) {
|
||||
LOG( SEV_ERROR, "Non existent statement found in connection. Statements should remove themselves"
|
||||
" from the connection so this shouldn't be out of sync." );
|
||||
continue;
|
||||
}
|
||||
|
||||
// delete the statement by deleting it from Zend's resource list, which will force its destruction
|
||||
stmt->conn = NULL;
|
||||
|
||||
try {
|
||||
// this would call the destructor on the statement.
|
||||
int zr = zend_list_close(Z_RES_P(rsrc_ptr));
|
||||
}
|
||||
catch( core::CoreException& ) {
|
||||
LOG(SEV_ERROR, "Failed to remove statement resource %1!d! when closing the connection", Z_RES_HANDLE_P(rsrc_ptr));
|
||||
}
|
||||
}
|
||||
try {
|
||||
// this would call the destructor on the statement.
|
||||
int zr = zend_list_close(Z_RES_P(rsrc_ptr));
|
||||
}
|
||||
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,31 +1225,27 @@ 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 )) {
|
||||
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;
|
||||
|
||||
int type = HASH_KEY_NON_EXISTENT;
|
||||
zend_string *key = NULL;
|
||||
size_t key_len = 0;
|
||||
zend_ulong int_key = -1;
|
||||
zval* data = NULL;
|
||||
zval* conn_opt = NULL;
|
||||
int result = 0;
|
||||
key_len = ZSTR_LEN( key ) + 1;
|
||||
type = key ? HASH_KEY_IS_STRING : HASH_KEY_IS_LONG;
|
||||
|
||||
type = zend_hash_get_current_key(options_ht, &key, &int_key);
|
||||
key_len = ZSTR_LEN(key) + 1;
|
||||
|
||||
if( type != HASH_KEY_IS_STRING ) {
|
||||
std::ostringstream itoa;
|
||||
itoa << int_key;
|
||||
CHECK_CUSTOM_ERROR( true , ctx, SQLSRV_ERROR_INVALID_OPTION_KEY, itoa.str() ) {
|
||||
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 );
|
||||
}
|
||||
if( type != HASH_KEY_IS_STRING ) {
|
||||
std::ostringstream itoa;
|
||||
itoa << int_key;
|
||||
CHECK_CUSTOM_ERROR( true, ctx, SQLSRV_ERROR_INVALID_OPTION_KEY, itoa.str() ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
}
|
||||
add_stmt_option_key( ctx, key, key_len, ss_stmt_options_ht, data TSRMLS_CC );
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
}
|
||||
}
|
||||
catch( core::CoreException& ) {
|
||||
|
@ -1274,39 +1265,37 @@ void validate_conn_options( sqlsrv_context& ctx, zval* user_options_z, __out cha
|
|||
if( user_options_z ) {
|
||||
|
||||
HashTable* options_ht = Z_ARRVAL_P( user_options_z );
|
||||
|
||||
for( zend_hash_internal_pointer_reset( options_ht ); zend_hash_has_more_elements( options_ht ) == SUCCESS;
|
||||
zend_hash_move_forward( options_ht )) {
|
||||
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;
|
||||
|
||||
int type = HASH_KEY_NON_EXISTENT;
|
||||
zend_string *key = NULL;
|
||||
zend_ulong int_key = -1;
|
||||
zval* data = NULL;
|
||||
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();
|
||||
}
|
||||
|
||||
type = zend_hash_get_current_key(options_ht, &key, &int_key);
|
||||
|
||||
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
|
||||
CHECK_CUSTOM_ERROR(( type != HASH_KEY_IS_STRING ), ctx, SS_SQLSRV_ERROR_INVALID_CONNECTION_KEY ) {
|
||||
throw ss::SSException();
|
||||
}
|
||||
|
||||
// Length of the key string does not include the null terminator in PHP7, +1 has to be added
|
||||
size_t key_len = ZSTR_LEN(key) + 1;
|
||||
if(key_len == sizeof( SSConnOptionNames::UID ) && !stricmp( ZSTR_VAL( key ), SSConnOptionNames::UID )) {
|
||||
if( key_len == sizeof(SSConnOptionNames::UID) && !stricmp(ZSTR_VAL(key), SSConnOptionNames::UID )) {
|
||||
|
||||
*uid = Z_STRVAL_P( data );
|
||||
}
|
||||
*uid = Z_STRVAL_P( data );
|
||||
}
|
||||
|
||||
else if(key_len == sizeof( SSConnOptionNames::PWD ) && !stricmp( ZSTR_VAL ( key ), SSConnOptionNames::PWD )) {
|
||||
|
||||
*pwd = Z_STRVAL_P( data );
|
||||
}
|
||||
else {
|
||||
else if( key_len == sizeof( SSConnOptionNames::PWD ) && !stricmp( ZSTR_VAL( key ), SSConnOptionNames::PWD )) {
|
||||
|
||||
::add_conn_option_key( ctx, key, key_len, ss_conn_options_ht, data TSRMLS_CC );
|
||||
}
|
||||
}
|
||||
*pwd = Z_STRVAL_P( data );
|
||||
}
|
||||
else {
|
||||
|
||||
::add_conn_option_key( ctx, key, key_len, ss_conn_options_ht, data TSRMLS_CC );
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
}
|
||||
}
|
||||
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,39 +124,49 @@ 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 );
|
||||
|
||||
build_connection_string_and_set_conn_attr( conn, server, uid, pwd, options_ht, valid_conn_opts, driver,
|
||||
conn_str TSRMLS_CC );
|
||||
|
||||
// We only support UTF-8 encoding for connection string.
|
||||
// Convert our UTF-8 connection string to UTF-16 before connecting with SQLDriverConnnectW
|
||||
wconn_len = static_cast<unsigned int>( conn_str.length() + 1 ) * sizeof( wchar_t );
|
||||
// We only support UTF-8 encoding for connection string.
|
||||
// Convert our UTF-8 connection string to UTF-16 before connecting with SQLDriverConnnectW
|
||||
wconn_len = static_cast<unsigned int>( conn_str.length() + 1 ) * sizeof( wchar_t );
|
||||
|
||||
wconn_string = utf16_string_from_mbcs_string( SQLSRV_ENCODING_UTF8, conn_str.c_str(), static_cast<unsigned int>( conn_str.length() ), &wconn_len );
|
||||
CHECK_CUSTOM_ERROR( wconn_string == NULL, conn, SQLSRV_ERROR_CONNECT_STRING_ENCODING_TRANSLATE, get_last_error_message() )
|
||||
{
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
SQLSMALLINT output_conn_size;
|
||||
r = SQLDriverConnectW( conn->handle(), NULL, reinterpret_cast<SQLWCHAR*>( wconn_string.get() ),
|
||||
static_cast<SQLSMALLINT>( wconn_len ), NULL,
|
||||
0, &output_conn_size, SQL_DRIVER_NOPROMPT );
|
||||
// clear the connection string from memory to remove sensitive data (such as a password).
|
||||
memset( const_cast<char*>( conn_str.c_str()), 0, conn_str.size() );
|
||||
memset( wconn_string, 0, wconn_len * sizeof( wchar_t )); // wconn_len is the number of characters, not bytes
|
||||
conn_str.clear();
|
||||
wconn_string = utf16_string_from_mbcs_string(SQLSRV_ENCODING_UTF8, conn_str.c_str(), static_cast<unsigned int>(conn_str.length()), &wconn_len);
|
||||
CHECK_CUSTOM_ERROR( wconn_string == NULL, conn, SQLSRV_ERROR_CONNECT_STRING_ENCODING_TRANSLATE, get_last_error_message())
|
||||
{
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
if( !SQL_SUCCEEDED( r )) {
|
||||
SQLCHAR state[ SQL_SQLSTATE_BUFSIZE ];
|
||||
SQLSMALLINT len;
|
||||
SQLRETURN r = SQLGetDiagField( SQL_HANDLE_DBC, conn->handle(), 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len );
|
||||
// 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() ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
}
|
||||
SQLSMALLINT output_conn_size;
|
||||
r = SQLDriverConnectW( conn->handle(), NULL, reinterpret_cast<SQLWCHAR*>( wconn_string.get()),
|
||||
static_cast<SQLSMALLINT>( wconn_len ), NULL,
|
||||
0, &output_conn_size, SQL_DRIVER_NOPROMPT );
|
||||
// clear the connection string from memory to remove sensitive data (such as a password).
|
||||
memset( const_cast<char*>( conn_str.c_str()), 0, conn_str.size() );
|
||||
memset( wconn_string, 0, wconn_len * sizeof( wchar_t )); // wconn_len is the number of characters, not bytes
|
||||
conn_str.clear();
|
||||
|
||||
if( !SQL_SUCCEEDED( r )) {
|
||||
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( 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();
|
||||
}
|
||||
|
@ -168,7 +178,7 @@ sqlsrv_conn* core_sqlsrv_connect( sqlsrv_context& henv_cp, sqlsrv_context& henv_
|
|||
// determine the version of the server we're connected to. The server version is left in the
|
||||
// connection upon return.
|
||||
determine_server_version( conn TSRMLS_CC );
|
||||
|
||||
|
||||
}
|
||||
catch( std::bad_alloc& ) {
|
||||
memset( const_cast<char*>( conn_str.c_str()), 0, conn_str.size() );
|
||||
|
@ -532,9 +542,7 @@ void build_connection_string_and_set_conn_attr( sqlsrv_conn* conn, const char* s
|
|||
int zr = SUCCESS;
|
||||
|
||||
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,30 +594,25 @@ 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;
|
||||
zval* data = NULL;
|
||||
zend_string *key = NULL;
|
||||
zend_ulong index = -1;
|
||||
zval* data = NULL;
|
||||
|
||||
type = zend_hash_get_current_key( options, &key, &index );
|
||||
|
||||
// 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 );
|
||||
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;
|
||||
|
||||
conn_opt = get_connection_option( conn, index, valid_conn_opts TSRMLS_CC );
|
||||
|
||||
if( index == SQLSRV_CONN_OPTION_MARS ) {
|
||||
mars_mentioned = true;
|
||||
}
|
||||
|
||||
conn_opt->func( conn_opt, data, conn, connection_string TSRMLS_CC );
|
||||
}
|
||||
// The driver layer should ensure a valid key.
|
||||
DEBUG_SQLSRV_ASSERT(( type == HASH_KEY_IS_LONG ), "build_connection_string_and_set_conn_attr: invalid connection option key type." );
|
||||
|
||||
conn_opt = get_connection_option( conn, index, valid_conn_opts TSRMLS_CC );
|
||||
|
||||
if( index == SQLSRV_CONN_OPTION_MARS ) {
|
||||
mars_mentioned = true;
|
||||
}
|
||||
|
||||
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,8 +1323,8 @@ 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 SQLSRV_PHPTYPE *sqlsrv_php_type_out TSRMLS_DC );
|
||||
__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 );
|
||||
void core_sqlsrv_post_param( sqlsrv_stmt* stmt, zend_ulong paramno, zval* param_z TSRMLS_DC );
|
||||
|
@ -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,
|
||||
|
@ -91,8 +91,8 @@ void default_sql_type( sqlsrv_stmt* stmt, SQLULEN paramno, zval* param_z, SQLSRV
|
|||
__out SQLSMALLINT& sql_type TSRMLS_DC );
|
||||
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 );
|
||||
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 );
|
||||
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,32 +248,26 @@ 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_ulong index = -1;
|
||||
zend_string *key = NULL;
|
||||
zval* value_z = NULL;
|
||||
|
||||
zend_string *key = NULL;
|
||||
zend_ulong index = -1;
|
||||
zval* value_z = NULL;
|
||||
ZEND_HASH_FOREACH_KEY_VAL( options_ht, index, key, value_z ) {
|
||||
|
||||
int type = zend_hash_get_current_key( options_ht, &key, &index);
|
||||
|
||||
// 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.
|
||||
// The driver layer should ensure that the key is valid.
|
||||
DEBUG_SQLSRV_ASSERT( stmt_opt != NULL, "allocate_stmt: unexpected null value for statement option." );
|
||||
|
||||
// perform the actions the statement option needs done.
|
||||
(*stmt_opt->func)( stmt, stmt_opt, value_z TSRMLS_CC );
|
||||
}
|
||||
int type = key ? HASH_KEY_IS_STRING : HASH_KEY_IS_LONG;
|
||||
|
||||
zend_hash_internal_pointer_end( options_ht );
|
||||
// The driver layer should ensure a valid key.
|
||||
DEBUG_SQLSRV_ASSERT(( type == HASH_KEY_IS_LONG ), "allocate_stmt: Invalid statment option key provided." );
|
||||
|
||||
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.
|
||||
// The driver layer should ensure that the key is valid.
|
||||
DEBUG_SQLSRV_ASSERT( stmt_opt != NULL, "allocate_stmt: unexpected null value for statement option." );
|
||||
|
||||
// perform the actions the statement option needs done.
|
||||
(*stmt_opt->func)( stmt, stmt_opt, value_z TSRMLS_CC );
|
||||
} 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
|
||||
zend_hash_clean( Z_ARRVAL( stmt->param_streams ));
|
||||
|
||||
if ( stmt->send_streams_at_exec ) {
|
||||
zend_hash_clean( Z_ARRVAL( stmt->param_streams ));
|
||||
}
|
||||
}
|
||||
catch( core::CoreException& e ) {
|
||||
|
||||
|
@ -869,100 +864,100 @@ 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 SQLSRV_PHPTYPE *sqlsrv_php_type_out TSRMLS_DC )
|
||||
__out void*& field_value, __out SQLLEN* field_len, bool cache_field,
|
||||
__out SQLSRV_PHPTYPE *sqlsrv_php_type_out TSRMLS_DC)
|
||||
{
|
||||
try {
|
||||
|
||||
// close the stream to release the resource
|
||||
close_active_stream( stmt TSRMLS_CC );
|
||||
|
||||
// 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))))) {
|
||||
// the field value is NULL
|
||||
if( cached->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 );
|
||||
if( cached->type.typeinfo.type == SQLSRV_PHPTYPE_STRING ) {
|
||||
// prevent the 'string not null terminated' warning
|
||||
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 ); }
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sqlsrv_phptype sqlsrv_php_type = sqlsrv_php_type_in;
|
||||
try {
|
||||
|
||||
SQLLEN sql_field_type = 0;
|
||||
SQLLEN sql_field_len = 0;
|
||||
// close the stream to release the resource
|
||||
close_active_stream(stmt TSRMLS_CC);
|
||||
|
||||
// Make sure that the statement was executed and not just prepared.
|
||||
CHECK_CUSTOM_ERROR( !stmt->executed, stmt, SQLSRV_ERROR_STATEMENT_NOT_EXECUTED ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
// if the field has been retrieved before, return the previous result
|
||||
field_cache* cached = NULL;
|
||||
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_len = 0;
|
||||
if( sqlsrv_php_type_out ) { *sqlsrv_php_type_out = SQLSRV_PHPTYPE_NULL; }
|
||||
}
|
||||
else {
|
||||
|
||||
// if the field is to be cached, and this field is being retrieved out of order, cache prior fields so they
|
||||
// may also be retrieved.
|
||||
if( cache_field && ( field_index - stmt->last_field_index ) >= 2 ) {
|
||||
sqlsrv_phptype invalid;
|
||||
invalid.typeinfo.type = SQLSRV_PHPTYPE_INVALID;
|
||||
for( int i = stmt->last_field_index + 1; i < field_index; ++i ) {
|
||||
SQLSRV_ASSERT((cached = reinterpret_cast<field_cache*>(zend_hash_index_find_ptr(Z_ARRVAL(stmt->field_cache), i))) == NULL,
|
||||
"Field already cached." );
|
||||
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;
|
||||
*field_len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
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';
|
||||
}
|
||||
*field_len = cached->len;
|
||||
if( sqlsrv_php_type_out) { *sqlsrv_php_type_out = static_cast<SQLSRV_PHPTYPE>(cached->type.typeinfo.type); }
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// If the php type was not specified set the php type to be the default type.
|
||||
if( sqlsrv_php_type.typeinfo.type == SQLSRV_PHPTYPE_INVALID ) {
|
||||
|
||||
// Get the SQL type of the field.
|
||||
core::SQLColAttribute( stmt, field_index + 1, SQL_DESC_CONCISE_TYPE, NULL, 0, NULL, &sql_field_type TSRMLS_CC );
|
||||
|
||||
// Get the length of the field.
|
||||
core::SQLColAttribute( stmt, field_index + 1, SQL_DESC_LENGTH, NULL, 0, NULL, &sql_field_len TSRMLS_CC );
|
||||
sqlsrv_phptype sqlsrv_php_type = sqlsrv_php_type_in;
|
||||
|
||||
// Get the corresponding php type from the sql type.
|
||||
sqlsrv_php_type = stmt->sql_type_to_php_type( static_cast<SQLINTEGER>( sql_field_type ), static_cast<SQLUINTEGER>( sql_field_len ), prefer_string );
|
||||
}
|
||||
SQLLEN sql_field_type = 0;
|
||||
SQLLEN sql_field_len = 0;
|
||||
|
||||
// Verify that we have an acceptable type to convert.
|
||||
CHECK_CUSTOM_ERROR( !is_valid_sqlsrv_phptype( sqlsrv_php_type ), stmt, SQLSRV_ERROR_INVALID_TYPE ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
if( sqlsrv_php_type_out != NULL )
|
||||
*sqlsrv_php_type_out = static_cast<SQLSRV_PHPTYPE>( sqlsrv_php_type.typeinfo.type );
|
||||
// Make sure that the statement was executed and not just prepared.
|
||||
CHECK_CUSTOM_ERROR( !stmt->executed, stmt, SQLSRV_ERROR_STATEMENT_NOT_EXECUTED ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
// Retrieve the data
|
||||
core_get_field_common( stmt, field_index, sqlsrv_php_type, field_value, field_len TSRMLS_CC );
|
||||
|
||||
// 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 );
|
||||
core::sqlsrv_zend_hash_index_update_mem( *stmt, Z_ARRVAL( stmt->field_cache ), field_index, &cache, sizeof(field_cache) TSRMLS_CC );
|
||||
}
|
||||
}
|
||||
// if the field is to be cached, and this field is being retrieved out of order, cache prior fields so they
|
||||
// may also be retrieved.
|
||||
if( cache_field && (field_index - stmt->last_field_index ) >= 2 ) {
|
||||
sqlsrv_phptype invalid;
|
||||
invalid.typeinfo.type = SQLSRV_PHPTYPE_INVALID;
|
||||
for( int i = stmt->last_field_index + 1; i < field_index; ++i ) {
|
||||
SQLSRV_ASSERT((cached = reinterpret_cast<field_cache*>(zend_hash_index_find_ptr(Z_ARRVAL(stmt->field_cache), i))) == NULL,
|
||||
"Field already cached." );
|
||||
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;
|
||||
*field_len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
catch( core::CoreException& e) {
|
||||
throw e;
|
||||
}
|
||||
// If the php type was not specified set the php type to be the default type.
|
||||
if( sqlsrv_php_type.typeinfo.type == SQLSRV_PHPTYPE_INVALID ) {
|
||||
|
||||
// Get the SQL type of the field.
|
||||
core::SQLColAttribute( stmt, field_index + 1, SQL_DESC_CONCISE_TYPE, NULL, 0, NULL, &sql_field_type TSRMLS_CC );
|
||||
|
||||
// Get the length of the field.
|
||||
core::SQLColAttribute( stmt, field_index + 1, SQL_DESC_LENGTH, NULL, 0, NULL, &sql_field_len TSRMLS_CC );
|
||||
|
||||
// Get the corresponding php type from the sql type.
|
||||
sqlsrv_php_type = stmt->sql_type_to_php_type( static_cast<SQLINTEGER>( sql_field_type ), static_cast<SQLUINTEGER>( sql_field_len ), prefer_string );
|
||||
}
|
||||
|
||||
// Verify that we have an acceptable type to convert.
|
||||
CHECK_CUSTOM_ERROR( !is_valid_sqlsrv_phptype( sqlsrv_php_type ), stmt, SQLSRV_ERROR_INVALID_TYPE ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
if( sqlsrv_php_type_out != NULL )
|
||||
*sqlsrv_php_type_out = static_cast<SQLSRV_PHPTYPE>( sqlsrv_php_type.typeinfo.type );
|
||||
|
||||
// Retrieve the data
|
||||
core_get_field_common( stmt, field_index, sqlsrv_php_type, field_value, field_len TSRMLS_CC );
|
||||
|
||||
// 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 );
|
||||
core::sqlsrv_zend_hash_index_update_mem( *stmt, Z_ARRVAL( stmt->field_cache ), field_index, &cache, sizeof(field_cache) TSRMLS_CC );
|
||||
}
|
||||
}
|
||||
|
||||
catch( core::CoreException& e ) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
// core_sqlsrv_has_any_result
|
||||
|
@ -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." );
|
||||
|
||||
}
|
||||
|
||||
|
@ -1470,191 +1468,191 @@ size_t calc_utf8_missing( sqlsrv_stmt* stmt, const char* buffer, size_t buffer_e
|
|||
// The memory allocation has to happen in the core layer because otherwise
|
||||
// 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 )
|
||||
{
|
||||
try {
|
||||
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 )
|
||||
{
|
||||
try {
|
||||
|
||||
close_active_stream( stmt TSRMLS_CC );
|
||||
close_active_stream( stmt TSRMLS_CC );
|
||||
|
||||
// make sure that fetch is called before trying to retrieve.
|
||||
CHECK_CUSTOM_ERROR( !stmt->fetch_called, stmt, SQLSRV_ERROR_FETCH_NOT_CALLED ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
// make sure that fetch is called before trying to retrieve.
|
||||
CHECK_CUSTOM_ERROR( !stmt->fetch_called, stmt, SQLSRV_ERROR_FETCH_NOT_CALLED ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
// make sure that fields are not retrieved incorrectly.
|
||||
CHECK_CUSTOM_ERROR( stmt->last_field_index > field_index, stmt, SQLSRV_ERROR_FIELD_INDEX_ERROR, field_index,
|
||||
stmt->last_field_index ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
// make sure that fields are not retrieved incorrectly.
|
||||
CHECK_CUSTOM_ERROR( stmt->last_field_index > field_index, stmt, SQLSRV_ERROR_FIELD_INDEX_ERROR, field_index,
|
||||
stmt->last_field_index ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
switch( sqlsrv_php_type.typeinfo.type ) {
|
||||
|
||||
case SQLSRV_PHPTYPE_INT:
|
||||
{
|
||||
sqlsrv_malloc_auto_ptr<long> field_value_temp;
|
||||
field_value_temp = static_cast<long*>( sqlsrv_malloc( sizeof( long )));
|
||||
switch( sqlsrv_php_type.typeinfo.type ) {
|
||||
|
||||
SQLRETURN r = stmt->current_results->get_data(field_index + 1, SQL_C_LONG, field_value_temp, sizeof( long ),
|
||||
field_len, true /*handle_warning*/ TSRMLS_CC );
|
||||
|
||||
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
case SQLSRV_PHPTYPE_INT:
|
||||
{
|
||||
sqlsrv_malloc_auto_ptr<long> field_value_temp;
|
||||
field_value_temp = static_cast<long*>( sqlsrv_malloc( sizeof( long )));
|
||||
|
||||
CHECK_CUSTOM_ERROR( (r == SQL_NO_DATA), stmt, SQLSRV_ERROR_NO_DATA, field_index ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
SQLRETURN r = stmt->current_results->get_data( field_index + 1, SQL_C_LONG, field_value_temp, sizeof( long ),
|
||||
field_len, true /*handle_warning*/ TSRMLS_CC );
|
||||
|
||||
if( *field_len == SQL_NULL_DATA ) {
|
||||
*field_value = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
*field_value = field_value_temp;
|
||||
field_value_temp.transferred();
|
||||
break;
|
||||
}
|
||||
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
case SQLSRV_PHPTYPE_FLOAT:
|
||||
{
|
||||
sqlsrv_malloc_auto_ptr<double> field_value_temp;
|
||||
field_value_temp = static_cast<double*>( sqlsrv_malloc( sizeof( double )));
|
||||
CHECK_CUSTOM_ERROR(( r == SQL_NO_DATA ), stmt, SQLSRV_ERROR_NO_DATA, field_index ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
SQLRETURN r = stmt->current_results->get_data( field_index + 1, SQL_C_DOUBLE, field_value_temp, sizeof( double ),
|
||||
field_len, true /*handle_warning*/ TSRMLS_CC );
|
||||
|
||||
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
if( *field_len == SQL_NULL_DATA ) {
|
||||
field_value = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
CHECK_CUSTOM_ERROR( (r == SQL_NO_DATA), stmt, SQLSRV_ERROR_NO_DATA, field_index ) {
|
||||
throw core::CoreException ();
|
||||
}
|
||||
field_value = field_value_temp;
|
||||
field_value_temp.transferred();
|
||||
break;
|
||||
}
|
||||
|
||||
if( *field_len == SQL_NULL_DATA ) {
|
||||
*field_value = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
*field_value = field_value_temp;
|
||||
field_value_temp.transferred();
|
||||
break;
|
||||
}
|
||||
|
||||
case SQLSRV_PHPTYPE_STRING:
|
||||
{
|
||||
get_field_as_string( stmt, field_index, sqlsrv_php_type, field_value, field_len TSRMLS_CC );
|
||||
break;
|
||||
}
|
||||
|
||||
// get the date as a string (http://msdn2.microsoft.com/en-us/library/ms712387(VS.85).aspx) and
|
||||
// convert it to a DateTime object and return the created object
|
||||
case SQLSRV_PHPTYPE_DATETIME:
|
||||
{
|
||||
char field_value_temp[ MAX_DATETIME_STRING_LEN ];
|
||||
zval params[1];
|
||||
zval field_value_temp_z;
|
||||
zval function_z;
|
||||
zval_auto_ptr return_value_z;
|
||||
|
||||
ZVAL_UNDEF( &field_value_temp_z );
|
||||
ZVAL_UNDEF( &function_z );
|
||||
ZVAL_UNDEF( params );
|
||||
return_value_z = (zval *)sqlsrv_malloc( sizeof(zval) );
|
||||
ZVAL_UNDEF( return_value_z );
|
||||
|
||||
SQLRETURN r = stmt->current_results->get_data( field_index + 1, SQL_C_CHAR, field_value_temp,
|
||||
MAX_DATETIME_STRING_LEN, field_len, true TSRMLS_CC );
|
||||
case SQLSRV_PHPTYPE_FLOAT:
|
||||
{
|
||||
sqlsrv_malloc_auto_ptr<double> field_value_temp;
|
||||
field_value_temp = static_cast<double*>( sqlsrv_malloc( sizeof( double )));
|
||||
|
||||
SQLRETURN r = stmt->current_results->get_data( field_index + 1, SQL_C_DOUBLE, field_value_temp, sizeof( double ),
|
||||
field_len, true /*handle_warning*/ TSRMLS_CC );
|
||||
|
||||
CHECK_CUSTOM_ERROR( (r == SQL_NO_DATA), stmt, SQLSRV_ERROR_NO_DATA, field_index ) {
|
||||
throw core::CoreException ();
|
||||
}
|
||||
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
if( *field_len == SQL_NULL_DATA ) {
|
||||
ZVAL_NULL( return_value_z );
|
||||
*field_value = reinterpret_cast<void*>( return_value_z.get() );
|
||||
return_value_z.transferred();
|
||||
break;
|
||||
}
|
||||
|
||||
// Convert the string date to a DateTime object
|
||||
core::sqlsrv_zval_stringl( &field_value_temp_z, field_value_temp, *field_len );
|
||||
core::sqlsrv_zval_stringl( &function_z, "date_create", sizeof("date_create") -1 );
|
||||
params[0] = field_value_temp_z;
|
||||
CHECK_CUSTOM_ERROR(( r == SQL_NO_DATA ), stmt, SQLSRV_ERROR_NO_DATA, field_index ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
if( call_user_function( EG( function_table ), NULL, &function_z, return_value_z, 1,
|
||||
params TSRMLS_CC ) == FAILURE ) {
|
||||
THROW_CORE_ERROR( stmt, SQLSRV_ERROR_DATETIME_CONVERSION_FAILED );
|
||||
}
|
||||
|
||||
*field_value = reinterpret_cast<void*>( return_value_z.get() );
|
||||
return_value_z.transferred();
|
||||
break;
|
||||
}
|
||||
|
||||
// create a stream wrapper around the field and return that object to the PHP script. calls to fread
|
||||
// on the stream will result in calls to SQLGetData. This is handled in stream.cpp. See that file
|
||||
// for how these fields are used.
|
||||
case SQLSRV_PHPTYPE_STREAM:
|
||||
{
|
||||
|
||||
zval_auto_ptr return_value_z;
|
||||
return_value_z = (zval *)sqlsrv_malloc(sizeof(zval));
|
||||
ZVAL_UNDEF(return_value_z);
|
||||
php_stream* stream = NULL;
|
||||
sqlsrv_stream* ss = NULL;
|
||||
SQLLEN sql_type;
|
||||
if( *field_len == SQL_NULL_DATA ) {
|
||||
field_value = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
SQLRETURN r = SQLColAttribute( stmt->handle(), field_index + 1, SQL_DESC_TYPE, NULL, 0, NULL, &sql_type );
|
||||
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
CHECK_CUSTOM_ERROR( !is_streamable_type( sql_type ), stmt, SQLSRV_ERROR_STREAMABLE_TYPES_ONLY ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
stream = php_stream_open_wrapper( "sqlsrv://sqlncli10", "r", 0, NULL );
|
||||
field_value = field_value_temp;
|
||||
field_value_temp.transferred();
|
||||
break;
|
||||
}
|
||||
|
||||
CHECK_CUSTOM_ERROR( !stream, stmt, SQLSRV_ERROR_STREAM_CREATE ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
case SQLSRV_PHPTYPE_STRING:
|
||||
{
|
||||
get_field_as_string( stmt, field_index, sqlsrv_php_type, field_value, field_len TSRMLS_CC );
|
||||
break;
|
||||
}
|
||||
|
||||
ss = static_cast<sqlsrv_stream*>( stream->abstract );
|
||||
ss->stmt = stmt;
|
||||
ss->field_index = field_index;
|
||||
ss->sql_type = static_cast<SQLUSMALLINT>( sql_type );
|
||||
ss->encoding = static_cast<SQLSRV_ENCODING>( sqlsrv_php_type.typeinfo.encoding );
|
||||
// get the date as a string (http://msdn2.microsoft.com/en-us/library/ms712387(VS.85).aspx) and
|
||||
// convert it to a DateTime object and return the created object
|
||||
case SQLSRV_PHPTYPE_DATETIME:
|
||||
{
|
||||
char field_value_temp[ MAX_DATETIME_STRING_LEN ];
|
||||
zval params[1];
|
||||
zval field_value_temp_z;
|
||||
zval function_z;
|
||||
zval_auto_ptr return_value_z;
|
||||
|
||||
// turn our stream into a zval to be returned
|
||||
php_stream_to_zval( stream, return_value_z );
|
||||
ZVAL_UNDEF( &field_value_temp_z );
|
||||
ZVAL_UNDEF( &function_z );
|
||||
ZVAL_UNDEF( params );
|
||||
return_value_z = (zval *)sqlsrv_malloc( sizeof( zval ));
|
||||
ZVAL_UNDEF( return_value_z );
|
||||
|
||||
// mark this as our active stream
|
||||
stmt->active_stream = return_value_z;
|
||||
*field_value = reinterpret_cast<void*>( return_value_z.get() );
|
||||
return_value_z.transferred();
|
||||
break;
|
||||
}
|
||||
SQLRETURN r = stmt->current_results->get_data( field_index + 1, SQL_C_CHAR, field_value_temp,
|
||||
MAX_DATETIME_STRING_LEN, field_len, true TSRMLS_CC );
|
||||
|
||||
case SQLSRV_PHPTYPE_NULL:
|
||||
*field_value = NULL;
|
||||
*field_len = 0;
|
||||
break;
|
||||
CHECK_CUSTOM_ERROR(( r == SQL_NO_DATA ), stmt, SQLSRV_ERROR_NO_DATA, field_index ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
default:
|
||||
DIE( "core_get_field_common: Unexpected sqlsrv_phptype provided" );
|
||||
break;
|
||||
}
|
||||
if( *field_len == SQL_NULL_DATA ) {
|
||||
ZVAL_NULL( return_value_z );
|
||||
field_value = reinterpret_cast<void*>( return_value_z.get());
|
||||
return_value_z.transferred();
|
||||
break;
|
||||
}
|
||||
|
||||
// sucessfully retrieved the field, so update our last retrieved field
|
||||
if( stmt->last_field_index < field_index ) {
|
||||
stmt->last_field_index = field_index;
|
||||
}
|
||||
}
|
||||
catch( core::CoreException& e ) {
|
||||
throw e;
|
||||
}
|
||||
// Convert the string date to a DateTime object
|
||||
core::sqlsrv_zval_stringl( &field_value_temp_z, field_value_temp, *field_len );
|
||||
core::sqlsrv_zval_stringl( &function_z, "date_create", sizeof("date_create") - 1 );
|
||||
params[0] = field_value_temp_z;
|
||||
|
||||
if( call_user_function( EG( function_table ), NULL, &function_z, return_value_z, 1,
|
||||
params TSRMLS_CC ) == FAILURE) {
|
||||
THROW_CORE_ERROR(stmt, SQLSRV_ERROR_DATETIME_CONVERSION_FAILED);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// create a stream wrapper around the field and return that object to the PHP script. calls to fread
|
||||
// on the stream will result in calls to SQLGetData. This is handled in stream.cpp. See that file
|
||||
// for how these fields are used.
|
||||
case SQLSRV_PHPTYPE_STREAM:
|
||||
{
|
||||
|
||||
zval_auto_ptr return_value_z;
|
||||
return_value_z = (zval *)sqlsrv_malloc(sizeof(zval));
|
||||
ZVAL_UNDEF(return_value_z);
|
||||
php_stream* stream = NULL;
|
||||
sqlsrv_stream* ss = NULL;
|
||||
SQLLEN sql_type;
|
||||
|
||||
SQLRETURN r = SQLColAttribute( stmt->handle(), field_index + 1, SQL_DESC_TYPE, NULL, 0, NULL, &sql_type );
|
||||
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
CHECK_CUSTOM_ERROR( !is_streamable_type( sql_type ), stmt, SQLSRV_ERROR_STREAMABLE_TYPES_ONLY ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
stream = php_stream_open_wrapper( "sqlsrv://sqlncli10", "r", 0, NULL );
|
||||
|
||||
CHECK_CUSTOM_ERROR( !stream, stmt, SQLSRV_ERROR_STREAM_CREATE ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
ss = static_cast<sqlsrv_stream*>( stream->abstract );
|
||||
ss->stmt = stmt;
|
||||
ss->field_index = field_index;
|
||||
ss->sql_type = static_cast<SQLUSMALLINT>( sql_type );
|
||||
ss->encoding = static_cast<SQLSRV_ENCODING>( sqlsrv_php_type.typeinfo.encoding );
|
||||
|
||||
// turn our stream into a zval to be returned
|
||||
php_stream_to_zval( stream, return_value_z );
|
||||
|
||||
field_value = reinterpret_cast<void*>( return_value_z.get());
|
||||
return_value_z.transferred();
|
||||
break;
|
||||
}
|
||||
|
||||
case SQLSRV_PHPTYPE_NULL:
|
||||
field_value = NULL;
|
||||
*field_len = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
DIE( "core_get_field_common: Unexpected sqlsrv_phptype provided" );
|
||||
break;
|
||||
}
|
||||
|
||||
// sucessfully retrieved the field, so update our last retrieved field
|
||||
if( stmt->last_field_index < field_index ) {
|
||||
stmt->last_field_index = field_index;
|
||||
}
|
||||
}
|
||||
catch( core::CoreException& e ) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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,241 +2036,241 @@ 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 ));
|
||||
return;
|
||||
}
|
||||
|
||||
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 )
|
||||
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 )
|
||||
{
|
||||
SQLRETURN r;
|
||||
SQLSMALLINT c_type;
|
||||
SQLLEN sql_field_type = 0;
|
||||
SQLSMALLINT extra = 0;
|
||||
SQLLEN field_len_temp;
|
||||
SQLLEN sql_display_size = 0;
|
||||
char* field_value_temp = NULL;
|
||||
SQLRETURN r;
|
||||
SQLSMALLINT c_type;
|
||||
SQLLEN sql_field_type = 0;
|
||||
SQLSMALLINT extra = 0;
|
||||
SQLLEN field_len_temp;
|
||||
SQLLEN sql_display_size = 0;
|
||||
char* field_value_temp = NULL;
|
||||
|
||||
try {
|
||||
try {
|
||||
|
||||
DEBUG_SQLSRV_ASSERT( sqlsrv_php_type.typeinfo.type == SQLSRV_PHPTYPE_STRING,
|
||||
"Type should be SQLSRV_PHPTYPE_STRING in get_field_as_string" );
|
||||
|
||||
if( sqlsrv_php_type.typeinfo.encoding == SQLSRV_ENCODING_DEFAULT ) {
|
||||
sqlsrv_php_type.typeinfo.encoding = stmt->conn->encoding();
|
||||
}
|
||||
DEBUG_SQLSRV_ASSERT( sqlsrv_php_type.typeinfo.type == SQLSRV_PHPTYPE_STRING,
|
||||
"Type should be SQLSRV_PHPTYPE_STRING in get_field_as_string" );
|
||||
|
||||
// Set the C type and account for null characters at the end of the data.
|
||||
switch( sqlsrv_php_type.typeinfo.encoding ) {
|
||||
case CP_UTF8:
|
||||
c_type = SQL_C_WCHAR;
|
||||
extra = sizeof( SQLWCHAR );
|
||||
break;
|
||||
case SQLSRV_ENCODING_BINARY:
|
||||
c_type = SQL_C_BINARY;
|
||||
extra = 0;
|
||||
break;
|
||||
default:
|
||||
c_type = SQL_C_CHAR;
|
||||
extra = sizeof( SQLCHAR );
|
||||
break;
|
||||
}
|
||||
if( sqlsrv_php_type.typeinfo.encoding == SQLSRV_ENCODING_DEFAULT ) {
|
||||
sqlsrv_php_type.typeinfo.encoding = stmt->conn->encoding();
|
||||
}
|
||||
|
||||
// Get the SQL type of the field.
|
||||
core::SQLColAttribute( stmt, field_index + 1, SQL_DESC_CONCISE_TYPE, NULL, 0, NULL, &sql_field_type TSRMLS_CC );
|
||||
// Set the C type and account for null characters at the end of the data.
|
||||
switch( sqlsrv_php_type.typeinfo.encoding ) {
|
||||
case CP_UTF8:
|
||||
c_type = SQL_C_WCHAR;
|
||||
extra = sizeof( SQLWCHAR );
|
||||
break;
|
||||
case SQLSRV_ENCODING_BINARY:
|
||||
c_type = SQL_C_BINARY;
|
||||
extra = 0;
|
||||
break;
|
||||
default:
|
||||
c_type = SQL_C_CHAR;
|
||||
extra = sizeof( SQLCHAR );
|
||||
break;
|
||||
}
|
||||
|
||||
// Calculate the field size.
|
||||
calc_string_size( stmt, field_index, sql_field_type, sql_display_size TSRMLS_CC );
|
||||
// Get the SQL type of the field.
|
||||
core::SQLColAttribute( stmt, field_index + 1, SQL_DESC_CONCISE_TYPE, NULL, 0, NULL, &sql_field_type TSRMLS_CC );
|
||||
|
||||
// if this is a large type, then read the first few bytes to get the actual length from SQLGetData
|
||||
if( sql_display_size == 0 || sql_display_size == LONG_MAX ||
|
||||
sql_display_size == LONG_MAX >> 1 || sql_display_size == ULONG_MAX - 1 ) {
|
||||
// Calculate the field size.
|
||||
calc_string_size( stmt, field_index, sql_field_type, sql_display_size TSRMLS_CC );
|
||||
|
||||
field_len_temp = INITIAL_FIELD_STRING_LEN;
|
||||
|
||||
field_value_temp = static_cast<char*>( sqlsrv_malloc( field_len_temp + extra + 1 ));
|
||||
|
||||
r = stmt->current_results->get_data( field_index + 1, c_type, field_value_temp, ( field_len_temp + extra ),
|
||||
&field_len_temp, false /*handle_warning*/ TSRMLS_CC );
|
||||
|
||||
CHECK_CUSTOM_ERROR( (r == SQL_NO_DATA), stmt, SQLSRV_ERROR_NO_DATA, field_index ) {
|
||||
throw core::CoreException ();
|
||||
}
|
||||
// if this is a large type, then read the first few bytes to get the actual length from SQLGetData
|
||||
if( sql_display_size == 0 || sql_display_size == LONG_MAX ||
|
||||
sql_display_size == LONG_MAX >> 1 || sql_display_size == ULONG_MAX - 1 ) {
|
||||
|
||||
if( field_len_temp == SQL_NULL_DATA ) {
|
||||
*field_value = NULL;
|
||||
sqlsrv_free( field_value_temp );
|
||||
return;
|
||||
}
|
||||
field_len_temp = INITIAL_FIELD_STRING_LEN;
|
||||
|
||||
if( r == SQL_SUCCESS_WITH_INFO ) {
|
||||
field_value_temp = static_cast<char*>( sqlsrv_malloc( field_len_temp + extra + 1 ));
|
||||
|
||||
r = stmt->current_results->get_data( field_index + 1, c_type, field_value_temp, ( field_len_temp + extra ),
|
||||
&field_len_temp, false /*handle_warning*/ TSRMLS_CC );
|
||||
|
||||
CHECK_CUSTOM_ERROR(( r == SQL_NO_DATA ), stmt, SQLSRV_ERROR_NO_DATA, field_index ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
if( field_len_temp == SQL_NULL_DATA ) {
|
||||
field_value = NULL;
|
||||
sqlsrv_free( field_value_temp );
|
||||
return;
|
||||
}
|
||||
|
||||
if( r == SQL_SUCCESS_WITH_INFO ) {
|
||||
|
||||
SQLCHAR state[ SQL_SQLSTATE_BUFSIZE ];
|
||||
SQLSMALLINT len;
|
||||
|
||||
stmt->current_results->get_diag_field( 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len TSRMLS_CC );
|
||||
|
||||
if( is_truncated_warning( state )) {
|
||||
|
||||
SQLCHAR state[ SQL_SQLSTATE_BUFSIZE ];
|
||||
SQLSMALLINT len;
|
||||
|
||||
stmt->current_results->get_diag_field( 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len TSRMLS_CC );
|
||||
|
||||
if( is_truncated_warning( state ) ) {
|
||||
|
||||
SQLLEN dummy_field_len;
|
||||
|
||||
// for XML (and possibly other conditions) the field length returned is not the real field length, so
|
||||
// in every pass, we double the allocation size to retrieve all the contents.
|
||||
if( field_len_temp == SQL_NO_TOTAL ) {
|
||||
|
||||
// reset the field_len_temp
|
||||
field_len_temp = INITIAL_FIELD_STRING_LEN;
|
||||
// for XML (and possibly other conditions) the field length returned is not the real field length, so
|
||||
// in every pass, we double the allocation size to retrieve all the contents.
|
||||
if( field_len_temp == SQL_NO_TOTAL ) {
|
||||
|
||||
do {
|
||||
SQLLEN initial_field_len = field_len_temp;
|
||||
// Double the size.
|
||||
field_len_temp *= 2;
|
||||
|
||||
field_value_temp = static_cast<char*>( sqlsrv_realloc( field_value_temp, field_len_temp + extra + 1 ));
|
||||
|
||||
field_len_temp -= initial_field_len;
|
||||
// reset the field_len_temp
|
||||
field_len_temp = INITIAL_FIELD_STRING_LEN;
|
||||
|
||||
// Get the rest of the data.
|
||||
r = stmt->current_results->get_data( field_index + 1, c_type, field_value_temp + initial_field_len,
|
||||
field_len_temp + extra, &dummy_field_len,
|
||||
false /*handle_warning*/ TSRMLS_CC );
|
||||
do {
|
||||
SQLLEN initial_field_len = field_len_temp;
|
||||
// Double the size.
|
||||
field_len_temp *= 2;
|
||||
|
||||
// the last packet will contain the actual amount retrieved, not SQL_NO_TOTAL
|
||||
// so we calculate the actual length of the string with that.
|
||||
if( dummy_field_len != SQL_NO_TOTAL )
|
||||
field_len_temp += dummy_field_len;
|
||||
else
|
||||
field_len_temp += initial_field_len;
|
||||
field_value_temp = static_cast<char*>( sqlsrv_realloc( field_value_temp, field_len_temp + extra + 1 ));
|
||||
|
||||
if( r == SQL_SUCCESS_WITH_INFO ) {
|
||||
core::SQLGetDiagField( stmt, 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len
|
||||
TSRMLS_CC );
|
||||
}
|
||||
field_len_temp -= initial_field_len;
|
||||
|
||||
} while( r == SQL_SUCCESS_WITH_INFO && is_truncated_warning( state ));
|
||||
}
|
||||
else {
|
||||
// Get the rest of the data.
|
||||
r = stmt->current_results->get_data( field_index + 1, c_type, field_value_temp + initial_field_len,
|
||||
field_len_temp + extra, &dummy_field_len,
|
||||
false /*handle_warning*/ TSRMLS_CC );
|
||||
|
||||
// We got the field_len_temp from SQLGetData call.
|
||||
field_value_temp = static_cast<char*>( sqlsrv_realloc( field_value_temp, field_len_temp + extra + 1 ));
|
||||
|
||||
// We have already recieved INITIAL_FIELD_STRING_LEN size data.
|
||||
field_len_temp -= INITIAL_FIELD_STRING_LEN;
|
||||
|
||||
// Get the rest of the data.
|
||||
r = stmt->current_results->get_data( field_index + 1, c_type, field_value_temp + INITIAL_FIELD_STRING_LEN,
|
||||
field_len_temp + extra, &dummy_field_len,
|
||||
true /*handle_warning*/ TSRMLS_CC );
|
||||
// the last packet will contain the actual amount retrieved, not SQL_NO_TOTAL
|
||||
// so we calculate the actual length of the string with that.
|
||||
if( dummy_field_len != SQL_NO_TOTAL )
|
||||
field_len_temp += dummy_field_len;
|
||||
else
|
||||
field_len_temp += initial_field_len;
|
||||
|
||||
if( dummy_field_len == SQL_NULL_DATA ) {
|
||||
*field_value = NULL;
|
||||
sqlsrv_free( field_value_temp );
|
||||
return;
|
||||
}
|
||||
|
||||
CHECK_CUSTOM_ERROR( (r == SQL_NO_DATA), stmt, SQLSRV_ERROR_NO_DATA, field_index ) {
|
||||
throw core::CoreException ();
|
||||
}
|
||||
|
||||
field_len_temp += INITIAL_FIELD_STRING_LEN;
|
||||
}
|
||||
if( r == SQL_SUCCESS_WITH_INFO ) {
|
||||
core::SQLGetDiagField( stmt, 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len
|
||||
TSRMLS_CC );
|
||||
}
|
||||
|
||||
} // if( is_truncation_warning ( state ) )
|
||||
else {
|
||||
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
}
|
||||
} // if( r == SQL_SUCCESS_WITH_INFO )
|
||||
} while( r == SQL_SUCCESS_WITH_INFO && is_truncated_warning( state ));
|
||||
}
|
||||
else {
|
||||
|
||||
if( sqlsrv_php_type.typeinfo.encoding == SQLSRV_ENCODING_UTF8 ) {
|
||||
// We got the field_len_temp from SQLGetData call.
|
||||
field_value_temp = static_cast<char*>( sqlsrv_realloc( field_value_temp, field_len_temp + extra + 1 ));
|
||||
|
||||
bool converted = convert_string_from_utf16_inplace( static_cast<SQLSRV_ENCODING>( sqlsrv_php_type.typeinfo.encoding ),
|
||||
&field_value_temp, field_len_temp );
|
||||
|
||||
CHECK_CUSTOM_ERROR( !converted, stmt, SQLSRV_ERROR_FIELD_ENCODING_TRANSLATE, get_last_error_message() ) {
|
||||
throw core::CoreException ();
|
||||
}
|
||||
}
|
||||
} // if ( sql_display_size == 0 || sql_display_size == LONG_MAX .. )
|
||||
|
||||
else if( sql_display_size >= 1 && sql_display_size <= SQL_SERVER_MAX_FIELD_SIZE ) {
|
||||
// We have already recieved INITIAL_FIELD_STRING_LEN size data.
|
||||
field_len_temp -= INITIAL_FIELD_STRING_LEN;
|
||||
|
||||
// only allow binary retrievals for char and binary types. All others get a string converted
|
||||
// to the encoding type they asked for.
|
||||
|
||||
// null terminator
|
||||
if( c_type == SQL_C_CHAR ) {
|
||||
sql_display_size += sizeof( SQLCHAR );
|
||||
}
|
||||
// Get the rest of the data.
|
||||
r = stmt->current_results->get_data( field_index + 1, c_type, field_value_temp + INITIAL_FIELD_STRING_LEN,
|
||||
field_len_temp + extra, &dummy_field_len,
|
||||
true /*handle_warning*/ TSRMLS_CC );
|
||||
|
||||
// For WCHAR multiply by sizeof(WCHAR) and include the null terminator
|
||||
else if( c_type == SQL_C_WCHAR ) {
|
||||
sql_display_size = (sql_display_size * sizeof(WCHAR)) + sizeof(WCHAR);
|
||||
}
|
||||
if( dummy_field_len == SQL_NULL_DATA ) {
|
||||
field_value = NULL;
|
||||
sqlsrv_free( field_value_temp );
|
||||
return;
|
||||
}
|
||||
|
||||
field_value_temp = static_cast<char*>( sqlsrv_malloc( sql_display_size + extra + 1 ));
|
||||
|
||||
// get the data
|
||||
r = stmt->current_results->get_data( field_index + 1, c_type, field_value_temp, sql_display_size,
|
||||
&field_len_temp, true /*handle_warning*/ TSRMLS_CC );
|
||||
CHECK_SQL_ERROR( r, stmt ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
CHECK_CUSTOM_ERROR( (r == SQL_NO_DATA), stmt, SQLSRV_ERROR_NO_DATA, field_index ) {
|
||||
throw core::CoreException ();
|
||||
}
|
||||
CHECK_CUSTOM_ERROR(( r == SQL_NO_DATA ), stmt, SQLSRV_ERROR_NO_DATA, field_index ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
if( field_len_temp == SQL_NULL_DATA ) {
|
||||
*field_value = NULL;
|
||||
sqlsrv_free( field_value_temp );
|
||||
return;
|
||||
}
|
||||
|
||||
if( sqlsrv_php_type.typeinfo.encoding == CP_UTF8 ) {
|
||||
field_len_temp += INITIAL_FIELD_STRING_LEN;
|
||||
}
|
||||
|
||||
bool converted = convert_string_from_utf16_inplace( static_cast<SQLSRV_ENCODING>( sqlsrv_php_type.typeinfo.encoding ),
|
||||
&field_value_temp, field_len_temp );
|
||||
|
||||
CHECK_CUSTOM_ERROR( !converted, stmt, SQLSRV_ERROR_FIELD_ENCODING_TRANSLATE, get_last_error_message() ) {
|
||||
throw core::CoreException ();
|
||||
}
|
||||
}
|
||||
} // else if( sql_display_size >= 1 && sql_display_size <= SQL_SERVER_MAX_FIELD_SIZE )
|
||||
} // if( is_truncation_warning ( state ) )
|
||||
else {
|
||||
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
}
|
||||
} // if( r == SQL_SUCCESS_WITH_INFO )
|
||||
|
||||
else {
|
||||
|
||||
DIE( "Invalid sql_display_size" );
|
||||
return; // to eliminate a warning
|
||||
}
|
||||
|
||||
*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
|
||||
// runtime checks to see if a string is null terminated and issues a warning about it if running in debug mode.
|
||||
// SQL_C_BINARY fields don't return a NULL terminator, so we allocate an extra byte on each field and use the ternary
|
||||
// operator to set add 1 to fill the null terminator
|
||||
field_value_temp[field_len_temp] = '\0';
|
||||
}
|
||||
if( sqlsrv_php_type.typeinfo.encoding == SQLSRV_ENCODING_UTF8 ) {
|
||||
|
||||
catch( core::CoreException& ) {
|
||||
bool converted = convert_string_from_utf16_inplace( static_cast<SQLSRV_ENCODING>( sqlsrv_php_type.typeinfo.encoding ),
|
||||
&field_value_temp, field_len_temp );
|
||||
|
||||
*field_value = NULL;
|
||||
*field_len = 0;
|
||||
sqlsrv_free( field_value_temp );
|
||||
throw;
|
||||
}
|
||||
catch ( ... ) {
|
||||
CHECK_CUSTOM_ERROR( !converted, stmt, SQLSRV_ERROR_FIELD_ENCODING_TRANSLATE, get_last_error_message()) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
}
|
||||
} // if ( sql_display_size == 0 || sql_display_size == LONG_MAX .. )
|
||||
|
||||
*field_value = NULL;
|
||||
*field_len = 0;
|
||||
sqlsrv_free( field_value_temp );
|
||||
throw;
|
||||
}
|
||||
else if( sql_display_size >= 1 && sql_display_size <= SQL_SERVER_MAX_FIELD_SIZE ) {
|
||||
|
||||
// only allow binary retrievals for char and binary types. All others get a string converted
|
||||
// to the encoding type they asked for.
|
||||
|
||||
// null terminator
|
||||
if( c_type == SQL_C_CHAR ) {
|
||||
sql_display_size += sizeof( SQLCHAR );
|
||||
}
|
||||
|
||||
// For WCHAR multiply by sizeof(WCHAR) and include the null terminator
|
||||
else if( c_type == SQL_C_WCHAR ) {
|
||||
sql_display_size = (sql_display_size * sizeof(WCHAR)) + sizeof(WCHAR);
|
||||
}
|
||||
|
||||
field_value_temp = static_cast<char*>( sqlsrv_malloc( sql_display_size + extra + 1 ));
|
||||
|
||||
// get the data
|
||||
r = stmt->current_results->get_data( field_index + 1, c_type, field_value_temp, sql_display_size,
|
||||
&field_len_temp, true /*handle_warning*/ TSRMLS_CC );
|
||||
CHECK_SQL_ERROR( r, stmt ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
CHECK_CUSTOM_ERROR(( r == SQL_NO_DATA ), stmt, SQLSRV_ERROR_NO_DATA, field_index ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
if( field_len_temp == SQL_NULL_DATA ) {
|
||||
field_value = NULL;
|
||||
sqlsrv_free( field_value_temp );
|
||||
return;
|
||||
}
|
||||
|
||||
if( sqlsrv_php_type.typeinfo.encoding == CP_UTF8 ) {
|
||||
|
||||
bool converted = convert_string_from_utf16_inplace( static_cast<SQLSRV_ENCODING>( sqlsrv_php_type.typeinfo.encoding ),
|
||||
&field_value_temp, field_len_temp );
|
||||
|
||||
CHECK_CUSTOM_ERROR( !converted, stmt, SQLSRV_ERROR_FIELD_ENCODING_TRANSLATE, get_last_error_message()) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
}
|
||||
} // else if( sql_display_size >= 1 && sql_display_size <= SQL_SERVER_MAX_FIELD_SIZE )
|
||||
|
||||
else {
|
||||
|
||||
DIE( "Invalid sql_display_size" );
|
||||
return; // to eliminate a warning
|
||||
}
|
||||
|
||||
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
|
||||
// runtime checks to see if a string is null terminated and issues a warning about it if running in debug mode.
|
||||
// SQL_C_BINARY fields don't return a NULL terminator, so we allocate an extra byte on each field and use the ternary
|
||||
// operator to set add 1 to fill the null terminator
|
||||
field_value_temp[field_len_temp] = '\0';
|
||||
}
|
||||
|
||||
catch( core::CoreException& ) {
|
||||
|
||||
field_value = NULL;
|
||||
*field_len = 0;
|
||||
sqlsrv_free( field_value_temp );
|
||||
throw;
|
||||
}
|
||||
catch ( ... ) {
|
||||
|
||||
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;
|
||||
|
|
|
@ -493,17 +493,17 @@ PHP_MINIT_FUNCTION(sqlsrv)
|
|||
zend_hash_init( g_ss_encodings_ht, 3, NULL /*use standard hash function*/, sqlsrv_encoding_dtor /*resource destructor*/, 1 /*persistent*/ );
|
||||
|
||||
sqlsrv_encoding sql_enc_char( "char", SQLSRV_ENCODING_CHAR );
|
||||
if (NULL == zend_hash_next_index_insert_mem(g_ss_encodings_ht, (void*)&sql_enc_char, sizeof( sqlsrv_encoding ))) {
|
||||
if (NULL == zend_hash_next_index_insert_mem( g_ss_encodings_ht, (void*)&sql_enc_char, sizeof( sqlsrv_encoding ))) {
|
||||
throw ss::SSException();
|
||||
}
|
||||
|
||||
sqlsrv_encoding sql_enc_bin( "binary", SQLSRV_ENCODING_BINARY, true );
|
||||
if (NULL == zend_hash_next_index_insert_mem(g_ss_encodings_ht, (void*)&sql_enc_bin, sizeof( sqlsrv_encoding ))) {
|
||||
if (NULL == zend_hash_next_index_insert_mem( g_ss_encodings_ht, (void*)&sql_enc_bin, sizeof( sqlsrv_encoding ))) {
|
||||
throw ss::SSException();
|
||||
}
|
||||
|
||||
sqlsrv_encoding sql_enc_utf8( "utf-8", CP_UTF8 );
|
||||
if (NULL == zend_hash_next_index_insert_mem(g_ss_encodings_ht, (void*)&sql_enc_utf8, sizeof( sqlsrv_encoding ))) {
|
||||
if (NULL == zend_hash_next_index_insert_mem( g_ss_encodings_ht, (void*)&sql_enc_utf8, sizeof( sqlsrv_encoding ))) {
|
||||
throw ss::SSException();
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
1628
sqlsrv/msodbcsql.h
1628
sqlsrv/msodbcsql.h
|
@ -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)
|
||||
|
@ -165,12 +167,12 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
// max SQL Server identifier length
|
||||
// max SQL Server identifier length
|
||||
#define SQL_MAX_SQLSERVERNAME 128
|
||||
|
||||
// SQLSetConnectAttr driver specific defines.
|
||||
// Microsoft has 1200 thru 1249 reserved for Microsoft SQL Server Native Client driver usage.
|
||||
// Connection attributes
|
||||
// SQLSetConnectAttr driver specific defines.
|
||||
// Microsoft has 1200 thru 1249 reserved for Microsoft SQL Server Native Client driver usage.
|
||||
// Connection attributes
|
||||
#define SQL_COPT_SS_BASE 1200
|
||||
#define SQL_COPT_SS_REMOTE_PWD (SQL_COPT_SS_BASE+1) // dbrpwset SQLSetConnectOption only
|
||||
#define SQL_COPT_SS_USE_PROC_FOR_PREP (SQL_COPT_SS_BASE+2) // Use create proc for SQLPrepare
|
||||
|
@ -203,14 +205,18 @@ 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 old names
|
||||
|
||||
#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
|
||||
#define SQL_INTEGRATED_SECURITY SQL_COPT_SS_INTEGRATED_SECURITY
|
||||
#define SQL_PRESERVE_CURSORS SQL_COPT_SS_PRESERVE_CURSORS
|
||||
|
||||
// SQLSetStmtAttr SQL Server Native Client driver specific defines.
|
||||
// Statement attributes
|
||||
// SQLSetStmtAttr SQL Server Native Client driver specific defines.
|
||||
// Statement attributes
|
||||
#define SQL_SOPT_SS_BASE 1225
|
||||
#define SQL_SOPT_SS_TEXTPTR_LOGGING (SQL_SOPT_SS_BASE+0) // Text pointer logging
|
||||
#define SQL_SOPT_SS_CURRENT_COMMAND (SQL_SOPT_SS_BASE+1) // dbcurcmd SQLGetStmtOption only
|
||||
|
@ -225,8 +231,9 @@ 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 old names
|
||||
#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
|
||||
#define SQL_COPT_SS_BROWSE_CONNECT (SQL_COPT_SS_BASE_EX+1) // Browse connect mode of operation
|
||||
|
@ -237,11 +244,17 @@ 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.
|
||||
// Microsoft has 1200 thru 1249 reserved for Microsoft SQL Server Native Client driver usage.
|
||||
// SQLColAttributes driver specific defines.
|
||||
// SQLSetDescField/SQLGetDescField driver specific defines.
|
||||
// Microsoft has 1200 thru 1249 reserved for Microsoft SQL Server Native Client driver usage.
|
||||
#define SQL_CA_SS_BASE 1200
|
||||
#define SQL_CA_SS_COLUMN_SSTYPE (SQL_CA_SS_BASE+0) // dbcoltype/dbalttype
|
||||
#define SQL_CA_SS_COLUMN_UTYPE (SQL_CA_SS_BASE+1) // dbcolutype/dbaltutype
|
||||
|
@ -256,13 +269,13 @@ extern "C" {
|
|||
#define SQL_CA_SS_COLUMN_SIZE (SQL_CA_SS_BASE+10) // dbcollen
|
||||
#define SQL_CA_SS_COLUMN_HIDDEN (SQL_CA_SS_BASE+11) // Column is hidden (FOR BROWSE)
|
||||
#define SQL_CA_SS_COLUMN_KEY (SQL_CA_SS_BASE+12) // Column is key column (FOR BROWSE)
|
||||
//#define SQL_DESC_BASE_COLUMN_NAME_OLD (SQL_CA_SS_BASE+13) // This is defined at another location.
|
||||
//#define SQL_DESC_BASE_COLUMN_NAME_OLD (SQL_CA_SS_BASE+13) // This is defined at another location.
|
||||
#define SQL_CA_SS_COLUMN_COLLATION (SQL_CA_SS_BASE+14) // Column collation (only for chars)
|
||||
#define SQL_CA_SS_VARIANT_TYPE (SQL_CA_SS_BASE+15)
|
||||
#define SQL_CA_SS_VARIANT_SQL_TYPE (SQL_CA_SS_BASE+16)
|
||||
#define SQL_CA_SS_VARIANT_SERVER_TYPE (SQL_CA_SS_BASE+17)
|
||||
|
||||
// XML, CLR UDT, and table valued parameter related metadata
|
||||
// XML, CLR UDT, and table valued parameter related metadata
|
||||
#define SQL_CA_SS_UDT_CATALOG_NAME (SQL_CA_SS_BASE+18) // UDT catalog name
|
||||
#define SQL_CA_SS_UDT_SCHEMA_NAME (SQL_CA_SS_BASE+19) // UDT schema name
|
||||
#define SQL_CA_SS_UDT_TYPE_NAME (SQL_CA_SS_BASE+20) // UDT type name
|
||||
|
@ -274,128 +287,143 @@ extern "C" {
|
|||
#define SQL_CA_SS_SCHEMA_NAME (SQL_CA_SS_BASE+26) // Schema name
|
||||
#define SQL_CA_SS_TYPE_NAME (SQL_CA_SS_BASE+27) // Type name
|
||||
|
||||
// table valued parameter related metadata
|
||||
// table valued parameter related metadata
|
||||
#define SQL_CA_SS_COLUMN_COMPUTED (SQL_CA_SS_BASE+29) // column is computed
|
||||
#define SQL_CA_SS_COLUMN_IN_UNIQUE_KEY (SQL_CA_SS_BASE+30) // column is part of a unique key
|
||||
#define SQL_CA_SS_COLUMN_SORT_ORDER (SQL_CA_SS_BASE+31) // column sort order
|
||||
#define SQL_CA_SS_COLUMN_SORT_ORDINAL (SQL_CA_SS_BASE+32) // column sort ordinal
|
||||
#define SQL_CA_SS_COLUMN_HAS_DEFAULT_VALUE (SQL_CA_SS_BASE+33) // column has default value for all rows of the table valued parameter
|
||||
|
||||
// sparse column related metadata
|
||||
// sparse column related metadata
|
||||
#define SQL_CA_SS_IS_COLUMN_SET (SQL_CA_SS_BASE+34) // column is a column-set column for sparse columns
|
||||
|
||||
// Legacy datetime related metadata
|
||||
// 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
|
||||
|
||||
// Defines returned by SQL_ATTR_CURSOR_TYPE/SQL_CURSOR_TYPE
|
||||
#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
|
||||
// Defines for use with SQL_COPT_SS_USE_PROC_FOR_PREP
|
||||
// Defines for use with SQL_COPT_SS_USE_PROC_FOR_PREP
|
||||
#define SQL_UP_OFF 0L // Procedures won't be used for prepare
|
||||
#define SQL_UP_ON 1L // Procedures will be used for prepare
|
||||
#define SQL_UP_ON_DROP 2L // Temp procedures will be explicitly dropped
|
||||
#define SQL_UP_DEFAULT SQL_UP_ON
|
||||
// Defines for use with SQL_COPT_SS_INTEGRATED_SECURITY - Pre-Connect Option only
|
||||
// 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
|
||||
// Defines for use with SQL_COPT_SS_PRESERVE_CURSORS
|
||||
#define SQL_PC_OFF 0L // Cursors are closed on SQLTransact
|
||||
#define SQL_PC_ON 1L // Cursors remain open on SQLTransact
|
||||
#define SQL_PC_DEFAULT SQL_PC_OFF
|
||||
// Defines for use with SQL_COPT_SS_USER_DATA
|
||||
// Defines for use with SQL_COPT_SS_USER_DATA
|
||||
#define SQL_UD_NOTSET NULL // No user data pointer set
|
||||
// Defines for use with SQL_COPT_SS_TRANSLATE
|
||||
// Defines for use with SQL_COPT_SS_TRANSLATE
|
||||
#define SQL_XL_OFF 0L // Code page translation is not performed
|
||||
#define SQL_XL_ON 1L // Code page translation is performed
|
||||
#define SQL_XL_DEFAULT SQL_XL_ON
|
||||
// Defines for use with SQL_COPT_SS_FALLBACK_CONNECT - Pre-Connect Option only
|
||||
// Defines for use with SQL_COPT_SS_FALLBACK_CONNECT - Pre-Connect Option only
|
||||
#define SQL_FB_OFF 0L // FallBack connections are disabled
|
||||
#define SQL_FB_ON 1L // FallBack connections are enabled
|
||||
#define SQL_FB_DEFAULT SQL_FB_OFF
|
||||
// Defines for use with SQL_COPT_SS_BCP - Pre-Connect Option only
|
||||
// Defines for use with SQL_COPT_SS_BCP - Pre-Connect Option only
|
||||
#define SQL_BCP_OFF 0L // BCP is not allowed on connection
|
||||
#define SQL_BCP_ON 1L // BCP is allowed on connection
|
||||
#define SQL_BCP_DEFAULT SQL_BCP_OFF
|
||||
// Defines for use with SQL_COPT_SS_QUOTED_IDENT
|
||||
// Defines for use with SQL_COPT_SS_QUOTED_IDENT
|
||||
#define SQL_QI_OFF 0L // Quoted identifiers are enable
|
||||
#define SQL_QI_ON 1L // Quoted identifiers are disabled
|
||||
#define SQL_QI_DEFAULT SQL_QI_ON
|
||||
// Defines for use with SQL_COPT_SS_ANSI_NPW - Pre-Connect Option only
|
||||
// Defines for use with SQL_COPT_SS_ANSI_NPW - Pre-Connect Option only
|
||||
#define SQL_AD_OFF 0L // ANSI NULLs, Padding and Warnings are enabled
|
||||
#define SQL_AD_ON 1L // ANSI NULLs, Padding and Warnings are disabled
|
||||
#define SQL_AD_DEFAULT SQL_AD_ON
|
||||
// Defines for use with SQL_COPT_SS_CONCAT_NULL - Pre-Connect Option only
|
||||
// Defines for use with SQL_COPT_SS_CONCAT_NULL - Pre-Connect Option only
|
||||
#define SQL_CN_OFF 0L // CONCAT_NULL_YIELDS_NULL is off
|
||||
#define SQL_CN_ON 1L // CONCAT_NULL_YIELDS_NULL is on
|
||||
#define SQL_CN_DEFAULT SQL_CN_ON
|
||||
// Defines for use with SQL_SOPT_SS_TEXTPTR_LOGGING
|
||||
// Defines for use with SQL_SOPT_SS_TEXTPTR_LOGGING
|
||||
#define SQL_TL_OFF 0L // No logging on text pointer ops
|
||||
#define SQL_TL_ON 1L // Logging occurs on text pointer ops
|
||||
#define SQL_TL_DEFAULT SQL_TL_ON
|
||||
// Defines for use with SQL_SOPT_SS_HIDDEN_COLUMNS
|
||||
// Defines for use with SQL_SOPT_SS_HIDDEN_COLUMNS
|
||||
#define SQL_HC_OFF 0L // FOR BROWSE columns are hidden
|
||||
#define SQL_HC_ON 1L // FOR BROWSE columns are exposed
|
||||
#define SQL_HC_DEFAULT SQL_HC_OFF
|
||||
// Defines for use with SQL_SOPT_SS_NOBROWSETABLE
|
||||
// Defines for use with SQL_SOPT_SS_NOBROWSETABLE
|
||||
#define SQL_NB_OFF 0L // NO_BROWSETABLE is off
|
||||
#define SQL_NB_ON 1L // NO_BROWSETABLE is on
|
||||
#define SQL_NB_DEFAULT SQL_NB_OFF
|
||||
// Defines for use with SQL_SOPT_SS_REGIONALIZE
|
||||
// Defines for use with SQL_SOPT_SS_REGIONALIZE
|
||||
#define SQL_RE_OFF 0L // No regionalization occurs on output character conversions
|
||||
#define SQL_RE_ON 1L // Regionalization occurs on output character conversions
|
||||
#define SQL_RE_DEFAULT SQL_RE_OFF
|
||||
// Defines for use with SQL_SOPT_SS_CURSOR_OPTIONS
|
||||
// Defines for use with SQL_SOPT_SS_CURSOR_OPTIONS
|
||||
#define SQL_CO_OFF 0L // Clear all cursor options
|
||||
#define SQL_CO_FFO 1L // Fast-forward cursor will be used
|
||||
#define SQL_CO_AF 2L // Autofetch on cursor open
|
||||
#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
|
||||
//SQL_SOPT_SS_NOCOUNT_STATUS
|
||||
// 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
|
||||
//SQL_SOPT_SS_DEFER_PREPARE
|
||||
//SQL_SOPT_SS_DEFER_PREPARE
|
||||
#define SQL_DP_OFF 0L
|
||||
#define SQL_DP_ON 1L
|
||||
//SQL_SOPT_SS_NAME_SCOPE
|
||||
//SQL_SOPT_SS_NAME_SCOPE
|
||||
#define SQL_SS_NAME_SCOPE_TABLE 0L
|
||||
#define SQL_SS_NAME_SCOPE_TABLE_TYPE 1L
|
||||
#define SQL_SS_NAME_SCOPE_EXTENDED 2L
|
||||
#define SQL_SS_NAME_SCOPE_SPARSE_COLUMN_SET 3L
|
||||
#define SQL_SS_NAME_SCOPE_DEFAULT SQL_SS_NAME_SCOPE_TABLE
|
||||
//SQL_COPT_SS_ENCRYPT
|
||||
//SQL_COPT_SS_ENCRYPT
|
||||
#define SQL_EN_OFF 0L
|
||||
#define SQL_EN_ON 1L
|
||||
//SQL_COPT_SS_TRUST_SERVER_CERTIFICATE
|
||||
//SQL_COPT_SS_TRUST_SERVER_CERTIFICATE
|
||||
#define SQL_TRUST_SERVER_CERTIFICATE_NO 0L
|
||||
#define SQL_TRUST_SERVER_CERTIFICATE_YES 1L
|
||||
//SQL_COPT_SS_BROWSE_CONNECT
|
||||
//SQL_COPT_SS_BROWSE_CONNECT
|
||||
#define SQL_MORE_INFO_NO 0L
|
||||
#define SQL_MORE_INFO_YES 1L
|
||||
//SQL_COPT_SS_BROWSE_CACHE_DATA
|
||||
//SQL_COPT_SS_BROWSE_CACHE_DATA
|
||||
#define SQL_CACHE_DATA_NO 0L
|
||||
#define SQL_CACHE_DATA_YES 1L
|
||||
//SQL_COPT_SS_RESET_CONNECTION
|
||||
//SQL_COPT_SS_RESET_CONNECTION
|
||||
#define SQL_RESET_YES 1L
|
||||
//SQL_COPT_SS_WARN_ON_CP_ERROR
|
||||
//SQL_COPT_SS_WARN_ON_CP_ERROR
|
||||
#define SQL_WARN_NO 0L
|
||||
#define SQL_WARN_YES 1L
|
||||
//SQL_COPT_SS_MARS_ENABLED
|
||||
//SQL_COPT_SS_MARS_ENABLED
|
||||
#define SQL_MARS_ENABLED_NO 0L
|
||||
#define SQL_MARS_ENABLED_YES 1L
|
||||
/* SQL_TXN_ISOLATION_OPTION bitmasks */
|
||||
/* SQL_TXN_ISOLATION_OPTION bitmasks */
|
||||
#define SQL_TXN_SS_SNAPSHOT 0x00000020L
|
||||
|
||||
// The following are defines for SQL_CA_SS_COLUMN_SORT_ORDER
|
||||
// The following are defines for SQL_CA_SS_COLUMN_SORT_ORDER
|
||||
#define SQL_SS_ORDER_UNSPECIFIED 0L
|
||||
#define SQL_SS_DESCENDING_ORDER 1L
|
||||
#define SQL_SS_ASCENDING_ORDER 2L
|
||||
#define SQL_SS_ORDER_DEFAULT SQL_SS_ORDER_UNSPECIFIED
|
||||
|
||||
// Driver specific SQL data type defines.
|
||||
// Microsoft has -150 thru -199 reserved for Microsoft SQL Server Native Client driver usage.
|
||||
// Driver specific SQL data type defines.
|
||||
// Microsoft has -150 thru -199 reserved for Microsoft SQL Server Native Client driver usage.
|
||||
#define SQL_SS_VARIANT (-150)
|
||||
#define SQL_SS_UDT (-151)
|
||||
#define SQL_SS_XML (-152)
|
||||
|
@ -403,22 +431,22 @@ extern "C" {
|
|||
#define SQL_SS_TIME2 (-154)
|
||||
#define SQL_SS_TIMESTAMPOFFSET (-155)
|
||||
|
||||
// Local types to be used with SQL_CA_SS_SERVER_TYPE
|
||||
// Local types to be used with SQL_CA_SS_SERVER_TYPE
|
||||
#define SQL_SS_TYPE_DEFAULT 0L
|
||||
#define SQL_SS_TYPE_SMALLDATETIME 1L
|
||||
#define SQL_SS_TYPE_DATETIME 2L
|
||||
|
||||
// Extended C Types range 4000 and above. Range of -100 thru 200 is reserved by Driver Manager.
|
||||
// Extended C Types range 4000 and above. Range of -100 thru 200 is reserved by Driver Manager.
|
||||
#define SQL_C_TYPES_EXTENDED 0x04000L
|
||||
#define SQL_C_SS_TIME2 (SQL_C_TYPES_EXTENDED+0)
|
||||
#define SQL_C_SS_TIMESTAMPOFFSET (SQL_C_TYPES_EXTENDED+1)
|
||||
|
||||
#ifndef SQLNCLI_NO_BCP
|
||||
// Define the symbol SQLNCLI_NO_BCP if you are not using BCP in your application
|
||||
// and you want to exclude the BCP-related definitions in this header file.
|
||||
// Define the symbol SQLNCLI_NO_BCP if you are not using BCP in your application
|
||||
// and you want to exclude the BCP-related definitions in this header file.
|
||||
|
||||
// SQL Server Data Type defines.
|
||||
// New types for SQL 6.0 and later servers
|
||||
// SQL Server Data Type defines.
|
||||
// New types for SQL 6.0 and later servers
|
||||
#define SQLTEXT 0x23
|
||||
#define SQLVARBINARY 0x25
|
||||
#define SQLINTN 0x26
|
||||
|
@ -439,10 +467,10 @@ extern "C" {
|
|||
#define SQLFLT4 0x3b
|
||||
#define SQLMONEY4 0x7a
|
||||
#define SQLDATETIM4 0x3a
|
||||
// New types for SQL 6.0 and later servers
|
||||
// New types for SQL 6.0 and later servers
|
||||
#define SQLDECIMAL 0x6a
|
||||
#define SQLNUMERIC 0x6c
|
||||
// New types for SQL 7.0 and later servers
|
||||
// New types for SQL 7.0 and later servers
|
||||
#define SQLUNIQUEID 0x24
|
||||
#define SQLBIGCHAR 0xaf
|
||||
#define SQLBIGVARCHAR 0xa7
|
||||
|
@ -452,29 +480,29 @@ extern "C" {
|
|||
#define SQLNCHAR 0xef
|
||||
#define SQLNVARCHAR 0xe7
|
||||
#define SQLNTEXT 0x63
|
||||
// New types for SQL 2000 and later servers
|
||||
// New types for SQL 2000 and later servers
|
||||
#define SQLINT8 0x7f
|
||||
#define SQLVARIANT 0x62
|
||||
// New types for SQL 2005 and later servers
|
||||
// New types for SQL 2005 and later servers
|
||||
#define SQLUDT 0xf0
|
||||
#define SQLXML 0xf1
|
||||
// New types for SQL 2008 and later servers
|
||||
// New types for SQL 2008 and later servers
|
||||
#define SQLTABLE 0xf3
|
||||
#define SQLDATEN 0x28
|
||||
#define SQLTIMEN 0x29
|
||||
#define SQLDATETIME2N 0x2a
|
||||
#define SQLDATETIMEOFFSETN 0x2b
|
||||
// Define old names
|
||||
// Define old names
|
||||
#define SQLDECIMALN 0x6a
|
||||
#define SQLNUMERICN 0x6c
|
||||
#endif // SQLNCLI_NO_BCP
|
||||
|
||||
// SQL_SS_LENGTH_UNLIMITED is used to describe the max length of
|
||||
// VARCHAR(max), VARBINARY(max), NVARCHAR(max), and XML columns
|
||||
// SQL_SS_LENGTH_UNLIMITED is used to describe the max length of
|
||||
// VARCHAR(max), VARBINARY(max), NVARCHAR(max), and XML columns
|
||||
#define SQL_SS_LENGTH_UNLIMITED 0
|
||||
|
||||
// User Data Type definitions.
|
||||
// Returned by SQLColAttributes/SQL_CA_SS_COLUMN_UTYPE.
|
||||
// User Data Type definitions.
|
||||
// Returned by SQLColAttributes/SQL_CA_SS_COLUMN_UTYPE.
|
||||
#define SQLudtBINARY 3
|
||||
#define SQLudtBIT 16
|
||||
#define SQLudtBITN 0
|
||||
|
@ -504,8 +532,8 @@ extern "C" {
|
|||
#define SQLudtVARBINARY 4
|
||||
#define SQLudtVARCHAR 2
|
||||
#define MIN_USER_DATATYPE 256
|
||||
// Aggregate operator types.
|
||||
// Returned by SQLColAttributes/SQL_CA_SS_COLUMN_OP.
|
||||
// Aggregate operator types.
|
||||
// Returned by SQLColAttributes/SQL_CA_SS_COLUMN_OP.
|
||||
#define SQLAOPSTDEV 0x30 // Standard deviation
|
||||
#define SQLAOPSTDEVP 0x31 // Standard deviation population
|
||||
#define SQLAOPVAR 0x32 // Variance
|
||||
|
@ -517,8 +545,8 @@ extern "C" {
|
|||
#define SQLAOPMAX 0x52 // Max
|
||||
#define SQLAOPANY 0x53 // Any
|
||||
#define SQLAOPNOOP 0x56 // None
|
||||
// SQLGetInfo driver specific defines.
|
||||
// Microsoft has 1151 thru 1200 reserved for Microsoft SQL Server Native Client driver usage.
|
||||
// SQLGetInfo driver specific defines.
|
||||
// Microsoft has 1151 thru 1200 reserved for Microsoft SQL Server Native Client driver usage.
|
||||
#define SQL_INFO_SS_FIRST 1199
|
||||
#define SQL_INFO_SS_NETLIB_NAMEW (SQL_INFO_SS_FIRST+0) // dbprocinfo
|
||||
#define SQL_INFO_SS_NETLIB_NAMEA (SQL_INFO_SS_FIRST+1) // dbprocinfo
|
||||
|
@ -529,16 +557,16 @@ extern "C" {
|
|||
#define SQL_INFO_SS_NETLIB_NAME SQL_INFO_SS_NETLIB_NAMEA
|
||||
#endif
|
||||
|
||||
// SQLGetDiagField driver specific defines.
|
||||
// Microsoft has -1150 thru -1199 reserved for Microsoft SQL Server Native Client driver usage.
|
||||
// SQLGetDiagField driver specific defines.
|
||||
// Microsoft has -1150 thru -1199 reserved for Microsoft SQL Server Native Client driver usage.
|
||||
#define SQL_DIAG_SS_BASE (-1150)
|
||||
#define SQL_DIAG_SS_MSGSTATE (SQL_DIAG_SS_BASE)
|
||||
#define SQL_DIAG_SS_SEVERITY (SQL_DIAG_SS_BASE-1)
|
||||
#define SQL_DIAG_SS_SRVNAME (SQL_DIAG_SS_BASE-2)
|
||||
#define SQL_DIAG_SS_PROCNAME (SQL_DIAG_SS_BASE-3)
|
||||
#define SQL_DIAG_SS_LINE (SQL_DIAG_SS_BASE-4)
|
||||
// SQLGetDiagField/SQL_DIAG_DYNAMIC_FUNCTION_CODE driver specific defines.
|
||||
// Microsoft has -200 thru -299 reserved for Microsoft SQL Server Native Client driver usage.
|
||||
// SQLGetDiagField/SQL_DIAG_DYNAMIC_FUNCTION_CODE driver specific defines.
|
||||
// Microsoft has -200 thru -299 reserved for Microsoft SQL Server Native Client driver usage.
|
||||
#define SQL_DIAG_DFC_SS_BASE (-200)
|
||||
#define SQL_DIAG_DFC_SS_ALTER_DATABASE (SQL_DIAG_DFC_SS_BASE-0)
|
||||
#define SQL_DIAG_DFC_SS_CHECKPOINT (SQL_DIAG_DFC_SS_BASE-1)
|
||||
|
@ -603,7 +631,7 @@ extern "C" {
|
|||
#define SQL_DIAG_DFC_SS_SET_XCTLVL (SQL_DIAG_DFC_SS_BASE-55)
|
||||
#define SQL_DIAG_DFC_SS_MERGE (SQL_DIAG_DFC_SS_BASE-56)
|
||||
|
||||
// Severity codes for SQL_DIAG_SS_SEVERITY
|
||||
// Severity codes for SQL_DIAG_SS_SEVERITY
|
||||
#define EX_ANY 0
|
||||
#define EX_INFO 10
|
||||
#define EX_MAXISEVERITY EX_INFO
|
||||
|
@ -624,75 +652,75 @@ extern "C" {
|
|||
#define EX_DBCORRUPT 23
|
||||
#define EX_HARDWARE 24
|
||||
#define EX_CONTROL 25
|
||||
// Internal server datatypes - used when binding to SQL_C_BINARY
|
||||
// Internal server datatypes - used when binding to SQL_C_BINARY
|
||||
#ifndef MAXNUMERICLEN // Resolve ODS/DBLib conflicts
|
||||
// DB-Library datatypes
|
||||
// DB-Library datatypes
|
||||
#define DBMAXCHAR (8000+1) // Max length of DBVARBINARY and DBVARCHAR, etc. +1 for zero byte
|
||||
#define MAXNAME (SQL_MAX_SQLSERVERNAME+1) // Max server identifier length including zero byte
|
||||
#ifdef UNICODE
|
||||
typedef wchar_t DBCHAR;
|
||||
typedef wchar_t DBCHAR;
|
||||
#else
|
||||
typedef char DBCHAR;
|
||||
typedef char DBCHAR;
|
||||
|
||||
#endif
|
||||
typedef short SQLSMALLINT;
|
||||
typedef short SQLSMALLINT;
|
||||
|
||||
typedef unsigned short SQLUSMALLINT;
|
||||
typedef unsigned short SQLUSMALLINT;
|
||||
|
||||
typedef unsigned char DBBINARY;
|
||||
typedef unsigned char DBBINARY;
|
||||
|
||||
typedef unsigned char DBTINYINT;
|
||||
typedef unsigned char DBTINYINT;
|
||||
|
||||
typedef short DBSMALLINT;
|
||||
typedef short DBSMALLINT;
|
||||
|
||||
typedef unsigned short DBUSMALLINT;
|
||||
typedef unsigned short DBUSMALLINT;
|
||||
|
||||
typedef double DBFLT8;
|
||||
typedef double DBFLT8;
|
||||
|
||||
typedef unsigned char DBBIT;
|
||||
typedef unsigned char DBBIT;
|
||||
|
||||
typedef unsigned char DBBOOL;
|
||||
typedef unsigned char DBBOOL;
|
||||
|
||||
typedef float DBFLT4;
|
||||
typedef float DBFLT4;
|
||||
|
||||
typedef DBFLT4 DBREAL;
|
||||
typedef DBFLT4 DBREAL;
|
||||
|
||||
typedef UINT DBUBOOL;
|
||||
typedef UINT DBUBOOL;
|
||||
|
||||
typedef struct dbmoney
|
||||
typedef struct dbmoney
|
||||
{
|
||||
LONG mnyhigh;
|
||||
ULONG mnylow;
|
||||
LONG mnyhigh;
|
||||
ULONG mnylow;
|
||||
} DBMONEY;
|
||||
|
||||
typedef struct dbdatetime
|
||||
typedef struct dbdatetime
|
||||
{
|
||||
LONG dtdays;
|
||||
ULONG dttime;
|
||||
LONG dtdays;
|
||||
ULONG dttime;
|
||||
} DBDATETIME;
|
||||
|
||||
typedef struct dbdatetime4
|
||||
typedef struct dbdatetime4
|
||||
{
|
||||
USHORT numdays;
|
||||
USHORT nummins;
|
||||
USHORT numdays;
|
||||
USHORT nummins;
|
||||
} DBDATETIM4;
|
||||
|
||||
typedef LONG DBMONEY4;
|
||||
typedef LONG DBMONEY4;
|
||||
|
||||
#include <pshpack8.h> // 8-byte structure packing
|
||||
|
||||
// New Date Time Structures
|
||||
// New Structure for TIME2
|
||||
typedef struct tagSS_TIME2_STRUCT
|
||||
{
|
||||
// New Date Time Structures
|
||||
// New Structure for TIME2
|
||||
typedef struct tagSS_TIME2_STRUCT
|
||||
{
|
||||
SQLUSMALLINT hour;
|
||||
SQLUSMALLINT minute;
|
||||
SQLUSMALLINT second;
|
||||
SQLUINTEGER fraction;
|
||||
} SQL_SS_TIME2_STRUCT;
|
||||
// New Structure for TIMESTAMPOFFSET
|
||||
typedef struct tagSS_TIMESTAMPOFFSET_STRUCT
|
||||
{
|
||||
} SQL_SS_TIME2_STRUCT;
|
||||
// New Structure for TIMESTAMPOFFSET
|
||||
typedef struct tagSS_TIMESTAMPOFFSET_STRUCT
|
||||
{
|
||||
SQLSMALLINT year;
|
||||
SQLUSMALLINT month;
|
||||
SQLUSMALLINT day;
|
||||
|
@ -702,130 +730,130 @@ typedef struct tagSS_TIMESTAMPOFFSET_STRUCT
|
|||
SQLUINTEGER fraction;
|
||||
SQLSMALLINT timezone_hour;
|
||||
SQLSMALLINT timezone_minute;
|
||||
} SQL_SS_TIMESTAMPOFFSET_STRUCT;
|
||||
} SQL_SS_TIMESTAMPOFFSET_STRUCT;
|
||||
|
||||
typedef struct tagDBTIME2
|
||||
{
|
||||
USHORT hour;
|
||||
USHORT minute;
|
||||
USHORT second;
|
||||
ULONG fraction;
|
||||
} DBTIME2;
|
||||
typedef struct tagDBTIME2
|
||||
{
|
||||
USHORT hour;
|
||||
USHORT minute;
|
||||
USHORT second;
|
||||
ULONG fraction;
|
||||
} DBTIME2;
|
||||
|
||||
typedef struct tagDBTIMESTAMPOFFSET
|
||||
{
|
||||
SHORT year;
|
||||
USHORT month;
|
||||
USHORT day;
|
||||
USHORT hour;
|
||||
USHORT minute;
|
||||
USHORT second;
|
||||
ULONG fraction;
|
||||
SHORT timezone_hour;
|
||||
SHORT timezone_minute;
|
||||
} DBTIMESTAMPOFFSET;
|
||||
typedef struct tagDBTIMESTAMPOFFSET
|
||||
{
|
||||
SHORT year;
|
||||
USHORT month;
|
||||
USHORT day;
|
||||
USHORT hour;
|
||||
USHORT minute;
|
||||
USHORT second;
|
||||
ULONG fraction;
|
||||
SHORT timezone_hour;
|
||||
SHORT timezone_minute;
|
||||
} DBTIMESTAMPOFFSET;
|
||||
|
||||
#include <poppack.h> // restore original structure packing
|
||||
|
||||
// Money value *10,000
|
||||
// Money value *10,000
|
||||
#define DBNUM_PREC_TYPE BYTE
|
||||
#define DBNUM_SCALE_TYPE BYTE
|
||||
#define DBNUM_VAL_TYPE BYTE
|
||||
|
||||
#if (ODBCVER < 0x0300)
|
||||
#define MAXNUMERICLEN 16
|
||||
typedef struct dbnumeric // Internal representation of NUMERIC data type
|
||||
{
|
||||
DBNUM_PREC_TYPE precision; // Precision
|
||||
DBNUM_SCALE_TYPE scale; // Scale
|
||||
BYTE sign; // Sign (1 if positive, 0 if negative)
|
||||
DBNUM_VAL_TYPE val[MAXNUMERICLEN];// Value
|
||||
} DBNUMERIC;
|
||||
typedef DBNUMERIC DBDECIMAL;// Internal representation of DECIMAL data type
|
||||
typedef struct dbnumeric // Internal representation of NUMERIC data type
|
||||
{
|
||||
DBNUM_PREC_TYPE precision; // Precision
|
||||
DBNUM_SCALE_TYPE scale; // Scale
|
||||
BYTE sign; // Sign (1 if positive, 0 if negative)
|
||||
DBNUM_VAL_TYPE val[MAXNUMERICLEN];// Value
|
||||
} DBNUMERIC;
|
||||
typedef DBNUMERIC DBDECIMAL;// Internal representation of DECIMAL data type
|
||||
#else // Use ODBC 3.0 definitions since same as DBLib
|
||||
#define MAXNUMERICLEN SQL_MAX_NUMERIC_LEN
|
||||
typedef SQL_NUMERIC_STRUCT DBNUMERIC;
|
||||
typedef SQL_NUMERIC_STRUCT DBDECIMAL;
|
||||
typedef SQL_NUMERIC_STRUCT DBNUMERIC;
|
||||
typedef SQL_NUMERIC_STRUCT DBDECIMAL;
|
||||
#endif // ODCBVER
|
||||
#endif // MAXNUMERICLEN
|
||||
|
||||
#ifndef INT
|
||||
typedef int INT;
|
||||
typedef LONG DBINT;
|
||||
typedef DBINT * LPDBINT;
|
||||
typedef int INT;
|
||||
typedef LONG DBINT;
|
||||
typedef DBINT * LPDBINT;
|
||||
#ifndef _LPCBYTE_DEFINED
|
||||
#define _LPCBYTE_DEFINED
|
||||
typedef BYTE const* LPCBYTE;
|
||||
typedef BYTE const* LPCBYTE;
|
||||
#endif //_LPCBYTE_DEFINED
|
||||
#endif // INT
|
||||
/**************************************************************************
|
||||
This struct is a global used for gathering statistical data on the driver.
|
||||
Access to this structure is controlled via the pStatCrit;
|
||||
***************************************************************************/
|
||||
typedef struct sqlperf
|
||||
{
|
||||
// Application Profile Statistics
|
||||
DWORD TimerResolution;
|
||||
DWORD SQLidu;
|
||||
DWORD SQLiduRows;
|
||||
DWORD SQLSelects;
|
||||
DWORD SQLSelectRows;
|
||||
DWORD Transactions;
|
||||
DWORD SQLPrepares;
|
||||
DWORD ExecDirects;
|
||||
DWORD SQLExecutes;
|
||||
DWORD CursorOpens;
|
||||
DWORD CursorSize;
|
||||
DWORD CursorUsed;
|
||||
LDOUBLE PercentCursorUsed;
|
||||
LDOUBLE AvgFetchTime;
|
||||
LDOUBLE AvgCursorSize;
|
||||
LDOUBLE AvgCursorUsed;
|
||||
DWORD SQLFetchTime;
|
||||
DWORD SQLFetchCount;
|
||||
DWORD CurrentStmtCount;
|
||||
DWORD MaxOpenStmt;
|
||||
DWORD SumOpenStmt;
|
||||
// Connection Statistics
|
||||
DWORD CurrentConnectionCount;
|
||||
DWORD MaxConnectionsOpened;
|
||||
DWORD SumConnectionsOpened;
|
||||
DWORD SumConnectiontime;
|
||||
LDOUBLE AvgTimeOpened;
|
||||
// Network Statistics
|
||||
DWORD ServerRndTrips;
|
||||
DWORD BuffersSent;
|
||||
DWORD BuffersRec;
|
||||
DWORD BytesSent;
|
||||
DWORD BytesRec;
|
||||
// Time Statistics;
|
||||
DWORD msExecutionTime;
|
||||
DWORD msNetWorkServerTime;
|
||||
} SQLPERF;
|
||||
// The following are options for SQL_COPT_SS_PERF_DATA and SQL_COPT_SS_PERF_QUERY
|
||||
/**************************************************************************
|
||||
This struct is a global used for gathering statistical data on the driver.
|
||||
Access to this structure is controlled via the pStatCrit;
|
||||
***************************************************************************/
|
||||
typedef struct sqlperf
|
||||
{
|
||||
// Application Profile Statistics
|
||||
DWORD TimerResolution;
|
||||
DWORD SQLidu;
|
||||
DWORD SQLiduRows;
|
||||
DWORD SQLSelects;
|
||||
DWORD SQLSelectRows;
|
||||
DWORD Transactions;
|
||||
DWORD SQLPrepares;
|
||||
DWORD ExecDirects;
|
||||
DWORD SQLExecutes;
|
||||
DWORD CursorOpens;
|
||||
DWORD CursorSize;
|
||||
DWORD CursorUsed;
|
||||
LDOUBLE PercentCursorUsed;
|
||||
LDOUBLE AvgFetchTime;
|
||||
LDOUBLE AvgCursorSize;
|
||||
LDOUBLE AvgCursorUsed;
|
||||
DWORD SQLFetchTime;
|
||||
DWORD SQLFetchCount;
|
||||
DWORD CurrentStmtCount;
|
||||
DWORD MaxOpenStmt;
|
||||
DWORD SumOpenStmt;
|
||||
// Connection Statistics
|
||||
DWORD CurrentConnectionCount;
|
||||
DWORD MaxConnectionsOpened;
|
||||
DWORD SumConnectionsOpened;
|
||||
DWORD SumConnectiontime;
|
||||
LDOUBLE AvgTimeOpened;
|
||||
// Network Statistics
|
||||
DWORD ServerRndTrips;
|
||||
DWORD BuffersSent;
|
||||
DWORD BuffersRec;
|
||||
DWORD BytesSent;
|
||||
DWORD BytesRec;
|
||||
// Time Statistics;
|
||||
DWORD msExecutionTime;
|
||||
DWORD msNetWorkServerTime;
|
||||
} SQLPERF;
|
||||
// The following are options for SQL_COPT_SS_PERF_DATA and SQL_COPT_SS_PERF_QUERY
|
||||
#define SQL_PERF_START 1 // Starts the driver sampling performance data.
|
||||
#define SQL_PERF_STOP 2 // Stops the counters from sampling performance data.
|
||||
// The following are defines for SQL_COPT_SS_PERF_DATA_LOG
|
||||
// The following are defines for SQL_COPT_SS_PERF_DATA_LOG
|
||||
#define SQL_SS_DL_DEFAULT TEXT("STATS.LOG")
|
||||
// The following are defines for SQL_COPT_SS_PERF_QUERY_LOG
|
||||
// The following are defines for SQL_COPT_SS_PERF_QUERY_LOG
|
||||
#define SQL_SS_QL_DEFAULT TEXT("QUERY.LOG")
|
||||
// The following are defines for SQL_COPT_SS_PERF_QUERY_INTERVAL
|
||||
// The following are defines for SQL_COPT_SS_PERF_QUERY_INTERVAL
|
||||
#define SQL_SS_QI_DEFAULT 30000 // 30,000 milliseconds
|
||||
|
||||
#ifndef SQLNCLI_NO_BCP
|
||||
// Define the symbol SQLNCLI_NO_BCP if you are not using BCP in your application
|
||||
// and you want to exclude the BCP-related definitions in this header file.
|
||||
// Define the symbol SQLNCLI_NO_BCP if you are not using BCP in your application
|
||||
// and you want to exclude the BCP-related definitions in this header file.
|
||||
|
||||
// ODBC BCP prototypes and defines
|
||||
// Return codes
|
||||
// ODBC BCP prototypes and defines
|
||||
// Return codes
|
||||
#define SUCCEED 1
|
||||
#define FAIL 0
|
||||
#define SUCCEED_ABORT 2
|
||||
#define SUCCEED_ASYNC 3
|
||||
// Transfer directions
|
||||
// Transfer directions
|
||||
#define DB_IN 1 // Transfer from client to server
|
||||
#define DB_OUT 2 // Transfer from server to client
|
||||
// bcp_control option
|
||||
// bcp_control option
|
||||
#define BCPMAXERRS 1 // Sets max errors allowed
|
||||
#define BCPFIRST 2 // Sets first row to be copied out
|
||||
#define BCPLAST 3 // Sets number of rows to be copied out
|
||||
|
@ -848,14 +876,14 @@ typedef struct sqlperf
|
|||
#define BCPLASTEX 18 // Ending Row for BCP operation (64 bit)
|
||||
#define BCPROWCOUNT 19 // Total Number of Rows Copied (64 bit)
|
||||
#define BCPDELAYREADFMT 20 // Delay reading format file unil bcp_exec
|
||||
// BCPFILECP values
|
||||
// Any valid code page that is installed on the client can be passed plus:
|
||||
// BCPFILECP values
|
||||
// Any valid code page that is installed on the client can be passed plus:
|
||||
#define BCPFILECP_ACP 0 // Data in file is in Windows code page
|
||||
#define BCPFILECP_OEMCP 1 // Data in file is in OEM code page (default)
|
||||
#define BCPFILECP_RAW (-1)// Data in file is in Server code page (no conversion)
|
||||
// bcp_collen definition
|
||||
// bcp_collen definition
|
||||
#define SQL_VARLEN_DATA (-10) // Use default length for column
|
||||
// BCP column format properties
|
||||
// BCP column format properties
|
||||
#define BCP_FMT_TYPE 0x01
|
||||
#define BCP_FMT_INDICATOR_LEN 0x02
|
||||
#define BCP_FMT_DATA_LEN 0x03
|
||||
|
@ -863,7 +891,7 @@ typedef struct sqlperf
|
|||
#define BCP_FMT_SERVER_COL 0x05
|
||||
#define BCP_FMT_COLLATION 0x06
|
||||
#define BCP_FMT_COLLATION_ID 0x07
|
||||
// bcp_setbulkmode properties
|
||||
// bcp_setbulkmode properties
|
||||
#define BCP_OUT_CHARACTER_MODE 0x01
|
||||
#define BCP_OUT_WIDE_CHARACTER_MODE 0x02
|
||||
#define BCP_OUT_NATIVE_TEXT_MODE 0x03
|
||||
|
@ -871,31 +899,31 @@ typedef struct sqlperf
|
|||
|
||||
|
||||
|
||||
// BCP functions
|
||||
DBINT SQL_API bcp_batch (HDBC);
|
||||
RETCODE SQL_API bcp_bind (HDBC, LPCBYTE, INT, DBINT, LPCBYTE, INT, INT, INT);
|
||||
RETCODE SQL_API bcp_colfmt (HDBC, INT, BYTE, INT, DBINT, LPCBYTE, INT, INT);
|
||||
RETCODE SQL_API bcp_collen (HDBC, DBINT, INT);
|
||||
RETCODE SQL_API bcp_colptr (HDBC, LPCBYTE, INT);
|
||||
RETCODE SQL_API bcp_columns (HDBC, INT);
|
||||
RETCODE SQL_API bcp_control (HDBC, INT, void *);
|
||||
DBINT SQL_API bcp_done (HDBC);
|
||||
RETCODE SQL_API bcp_exec (HDBC, LPDBINT);
|
||||
RETCODE SQL_API bcp_getcolfmt (HDBC, INT, INT, void *, INT, INT *);
|
||||
RETCODE SQL_API bcp_initA (HDBC, LPCSTR, LPCSTR, LPCSTR, INT);
|
||||
RETCODE SQL_API bcp_initW (HDBC, LPCWSTR, LPCWSTR, LPCWSTR, INT);
|
||||
RETCODE SQL_API bcp_moretext (HDBC, DBINT, LPCBYTE);
|
||||
RETCODE SQL_API bcp_readfmtA (HDBC, LPCSTR);
|
||||
RETCODE SQL_API bcp_readfmtW (HDBC, LPCWSTR);
|
||||
RETCODE SQL_API bcp_sendrow (HDBC);
|
||||
RETCODE SQL_API bcp_setbulkmode (HDBC, INT, __in_bcount(cbField) void*, INT cbField, __in_bcount(cbRow) void *, INT cbRow);
|
||||
RETCODE SQL_API bcp_setcolfmt (HDBC, INT, INT, void *, INT);
|
||||
RETCODE SQL_API bcp_writefmtA (HDBC, LPCSTR);
|
||||
RETCODE SQL_API bcp_writefmtW (HDBC, LPCWSTR);
|
||||
CHAR* SQL_API dbprtypeA (INT);
|
||||
WCHAR* SQL_API dbprtypeW (INT);
|
||||
CHAR* SQL_API bcp_gettypenameA (INT, DBBOOL);
|
||||
WCHAR* SQL_API bcp_gettypenameW (INT, DBBOOL);
|
||||
// BCP functions
|
||||
DBINT SQL_API bcp_batch(HDBC);
|
||||
RETCODE SQL_API bcp_bind(HDBC, LPCBYTE, INT, DBINT, LPCBYTE, INT, INT, INT);
|
||||
RETCODE SQL_API bcp_colfmt(HDBC, INT, BYTE, INT, DBINT, LPCBYTE, INT, INT);
|
||||
RETCODE SQL_API bcp_collen(HDBC, DBINT, INT);
|
||||
RETCODE SQL_API bcp_colptr(HDBC, LPCBYTE, INT);
|
||||
RETCODE SQL_API bcp_columns(HDBC, INT);
|
||||
RETCODE SQL_API bcp_control(HDBC, INT, void *);
|
||||
DBINT SQL_API bcp_done(HDBC);
|
||||
RETCODE SQL_API bcp_exec(HDBC, LPDBINT);
|
||||
RETCODE SQL_API bcp_getcolfmt(HDBC, INT, INT, void *, INT, INT *);
|
||||
RETCODE SQL_API bcp_initA(HDBC, LPCSTR, LPCSTR, LPCSTR, INT);
|
||||
RETCODE SQL_API bcp_initW(HDBC, LPCWSTR, LPCWSTR, LPCWSTR, INT);
|
||||
RETCODE SQL_API bcp_moretext(HDBC, DBINT, LPCBYTE);
|
||||
RETCODE SQL_API bcp_readfmtA(HDBC, LPCSTR);
|
||||
RETCODE SQL_API bcp_readfmtW(HDBC, LPCWSTR);
|
||||
RETCODE SQL_API bcp_sendrow(HDBC);
|
||||
RETCODE SQL_API bcp_setbulkmode(HDBC, INT, __in_bcount(cbField) void*, INT cbField, __in_bcount(cbRow) void *, INT cbRow);
|
||||
RETCODE SQL_API bcp_setcolfmt(HDBC, INT, INT, void *, INT);
|
||||
RETCODE SQL_API bcp_writefmtA(HDBC, LPCSTR);
|
||||
RETCODE SQL_API bcp_writefmtW(HDBC, LPCWSTR);
|
||||
CHAR* SQL_API dbprtypeA(INT);
|
||||
WCHAR* SQL_API dbprtypeW(INT);
|
||||
CHAR* SQL_API bcp_gettypenameA(INT, DBBOOL);
|
||||
WCHAR* SQL_API bcp_gettypenameW(INT, DBBOOL);
|
||||
|
||||
#ifdef UNICODE
|
||||
#define bcp_init bcp_initW
|
||||
|
@ -915,9 +943,9 @@ WCHAR* SQL_API bcp_gettypenameW (INT, DBBOOL);
|
|||
|
||||
#endif // SQLNCLI_NO_BCP
|
||||
|
||||
// The following options have been deprecated
|
||||
// The following options have been deprecated
|
||||
#define SQL_FAST_CONNECT (SQL_COPT_SS_BASE+0)
|
||||
// Defines for use with SQL_FAST_CONNECT - only useable before connecting
|
||||
// Defines for use with SQL_FAST_CONNECT - only useable before connecting
|
||||
#define SQL_FC_OFF 0L // Fast connect is off
|
||||
#define SQL_FC_ON 1L // Fast connect is on
|
||||
#define SQL_FC_DEFAULT SQL_FC_OFF
|
||||
|
@ -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"
|
||||
|
@ -941,12 +1023,12 @@ extern "C" {
|
|||
#endif
|
||||
#include <windows.h>
|
||||
|
||||
//The following facilitates opening a handle to a SQL filestream
|
||||
typedef enum _SQL_FILESTREAM_DESIRED_ACCESS {
|
||||
SQL_FILESTREAM_READ = 0,
|
||||
SQL_FILESTREAM_WRITE = 1,
|
||||
SQL_FILESTREAM_READWRITE = 2
|
||||
} SQL_FILESTREAM_DESIRED_ACCESS;
|
||||
//The following facilitates opening a handle to a SQL filestream
|
||||
typedef enum _SQL_FILESTREAM_DESIRED_ACCESS {
|
||||
SQL_FILESTREAM_READ = 0,
|
||||
SQL_FILESTREAM_WRITE = 1,
|
||||
SQL_FILESTREAM_READWRITE = 2
|
||||
} SQL_FILESTREAM_DESIRED_ACCESS;
|
||||
#define SQL_FILESTREAM_OPEN_FLAG_ASYNC 0x00000001L
|
||||
#define SQL_FILESTREAM_OPEN_FLAG_NO_BUFFERING 0x00000002L
|
||||
#define SQL_FILESTREAM_OPEN_FLAG_NO_WRITE_THROUGH 0x00000004L
|
||||
|
@ -954,14 +1036,14 @@ typedef enum _SQL_FILESTREAM_DESIRED_ACCESS {
|
|||
#define SQL_FILESTREAM_OPEN_FLAG_RANDOM_ACCESS 0x00000010L
|
||||
|
||||
|
||||
HANDLE __stdcall OpenSqlFilestream (
|
||||
LPCWSTR FilestreamPath,
|
||||
SQL_FILESTREAM_DESIRED_ACCESS DesiredAccess,
|
||||
ULONG OpenOptions,
|
||||
__in_bcount(FilestreamTransactionContextLength)
|
||||
LPBYTE FilestreamTransactionContext,
|
||||
SSIZE_T FilestreamTransactionContextLength,
|
||||
PLARGE_INTEGER AllocationSize);
|
||||
HANDLE __stdcall OpenSqlFilestream(
|
||||
LPCWSTR FilestreamPath,
|
||||
SQL_FILESTREAM_DESIRED_ACCESS DesiredAccess,
|
||||
ULONG OpenOptions,
|
||||
__in_bcount(FilestreamTransactionContextLength)
|
||||
LPBYTE FilestreamTransactionContext,
|
||||
SSIZE_T FilestreamTransactionContextLength,
|
||||
PLARGE_INTEGER AllocationSize);
|
||||
#define FSCTL_SQL_FILESTREAM_FETCH_OLD_CONTENT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 2392, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -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,491 +1073,504 @@ HANDLE __stdcall OpenSqlFilestream (
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct _CERT_CONTEXT;
|
||||
typedef _CERT_CONTEXT CERT_CONTEXT;
|
||||
typedef const CERT_CONTEXT *PCCERT_CONTEXT;
|
||||
|
||||
// Recommended buffer size to store a LocalDB connection string
|
||||
// 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
|
||||
|
||||
// type definition for LocalDBCreateInstance function
|
||||
typedef HRESULT __cdecl FnLocalDBCreateInstance (
|
||||
// I the LocalDB version (e.g. 11.0 or 11.0.1094.2)
|
||||
__in_z PCWSTR wszVersion,
|
||||
// I the instance name
|
||||
__in_z PCWSTR pInstanceName,
|
||||
// I reserved for the future use. Currently should be set to 0.
|
||||
__in DWORD dwFlags
|
||||
);
|
||||
// type definition for LocalDBCreateInstance function
|
||||
typedef HRESULT __cdecl FnLocalDBCreateInstance(
|
||||
// I the LocalDB version (e.g. 11.0 or 11.0.1094.2)
|
||||
__in_z PCWSTR wszVersion,
|
||||
// I the instance name
|
||||
__in_z PCWSTR pInstanceName,
|
||||
// I reserved for the future use. Currently should be set to 0.
|
||||
__in DWORD dwFlags
|
||||
);
|
||||
|
||||
// type definition for pointer to LocalDBCreateInstance function
|
||||
typedef FnLocalDBCreateInstance* PFnLocalDBCreateInstance;
|
||||
// type definition for pointer to LocalDBCreateInstance function
|
||||
typedef FnLocalDBCreateInstance* PFnLocalDBCreateInstance;
|
||||
|
||||
// type definition for LocalDBStartInstance function
|
||||
typedef HRESULT __cdecl FnLocalDBStartInstance (
|
||||
// I the LocalDB instance name
|
||||
__in_z PCWSTR pInstanceName,
|
||||
// I reserved for the future use. Currently should be set to 0.
|
||||
__in DWORD dwFlags,
|
||||
// O the buffer to store the connection string to the LocalDB instance
|
||||
__out_ecount_z_opt(*lpcchSqlConnection) LPWSTR wszSqlConnection,
|
||||
// I/O on input has the size of the wszSqlConnection buffer in characters. On output, if the given buffer size is
|
||||
// too small, has the buffer size required, in characters, including trailing null.
|
||||
__inout_opt LPDWORD lpcchSqlConnection
|
||||
);
|
||||
// type definition for LocalDBStartInstance function
|
||||
typedef HRESULT __cdecl FnLocalDBStartInstance(
|
||||
// I the LocalDB instance name
|
||||
__in_z PCWSTR pInstanceName,
|
||||
// I reserved for the future use. Currently should be set to 0.
|
||||
__in DWORD dwFlags,
|
||||
// O the buffer to store the connection string to the LocalDB instance
|
||||
__out_ecount_z_opt(*lpcchSqlConnection) LPWSTR wszSqlConnection,
|
||||
// I/O on input has the size of the wszSqlConnection buffer in characters. On output, if the given buffer size is
|
||||
// too small, has the buffer size required, in characters, including trailing null.
|
||||
__inout_opt LPDWORD lpcchSqlConnection
|
||||
);
|
||||
|
||||
// type definition for pointer to LocalDBStartInstance function
|
||||
typedef FnLocalDBStartInstance* PFnLocalDBStartInstance;
|
||||
// type definition for pointer to LocalDBStartInstance function
|
||||
typedef FnLocalDBStartInstance* PFnLocalDBStartInstance;
|
||||
|
||||
// Flags for the LocalDBFormatMessage function
|
||||
// Flags for the LocalDBFormatMessage function
|
||||
#define LOCALDB_TRUNCATE_ERR_MESSAGE 0x0001L
|
||||
|
||||
// type definition for LocalDBFormatMessage function
|
||||
typedef HRESULT __cdecl FnLocalDBFormatMessage(
|
||||
// I the LocalDB error code
|
||||
__in HRESULT hrLocalDB,
|
||||
// I Available flags:
|
||||
// LOCALDB_TRUNCATE_ERR_MESSAGE - if the input buffer is too short,
|
||||
// the error message will be truncated to fit into the buffer
|
||||
__in DWORD dwFlags,
|
||||
// I Language desired (LCID) or 0 (in which case Win32 FormatMessage order is used)
|
||||
__in DWORD dwLanguageId,
|
||||
// O the buffer to store the LocalDB error message
|
||||
__out_ecount_z(*lpcchMessage) LPWSTR wszMessage,
|
||||
// I/O on input has the size of the wszMessage buffer in characters. On output, if the given buffer size is
|
||||
// too small, has the buffer size required, in characters, including trailing null. If the function succeeds
|
||||
// contains the number of characters in the message, excluding the trailing null
|
||||
__inout LPDWORD lpcchMessage
|
||||
);
|
||||
// type definition for LocalDBFormatMessage function
|
||||
typedef HRESULT __cdecl FnLocalDBFormatMessage(
|
||||
// I the LocalDB error code
|
||||
__in HRESULT hrLocalDB,
|
||||
// I Available flags:
|
||||
// LOCALDB_TRUNCATE_ERR_MESSAGE - if the input buffer is too short,
|
||||
// the error message will be truncated to fit into the buffer
|
||||
__in DWORD dwFlags,
|
||||
// I Language desired (LCID) or 0 (in which case Win32 FormatMessage order is used)
|
||||
__in DWORD dwLanguageId,
|
||||
// O the buffer to store the LocalDB error message
|
||||
__out_ecount_z(*lpcchMessage) LPWSTR wszMessage,
|
||||
// I/O on input has the size of the wszMessage buffer in characters. On output, if the given buffer size is
|
||||
// too small, has the buffer size required, in characters, including trailing null. If the function succeeds
|
||||
// contains the number of characters in the message, excluding the trailing null
|
||||
__inout LPDWORD lpcchMessage
|
||||
);
|
||||
|
||||
// type definition for function pointer to LocalDBFormatMessage function
|
||||
typedef FnLocalDBFormatMessage* PFnLocalDBFormatMessage;
|
||||
// type definition for function pointer to LocalDBFormatMessage function
|
||||
typedef FnLocalDBFormatMessage* PFnLocalDBFormatMessage;
|
||||
|
||||
|
||||
// MessageId: LOCALDB_ERROR_NOT_INSTALLED
|
||||
//
|
||||
// MessageText:
|
||||
//
|
||||
// LocalDB is not installed.
|
||||
//
|
||||
// MessageId: LOCALDB_ERROR_NOT_INSTALLED
|
||||
//
|
||||
// MessageText:
|
||||
//
|
||||
// LocalDB is not installed.
|
||||
//
|
||||
#define LOCALDB_ERROR_NOT_INSTALLED ((HRESULT)0x89C50116L)
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Function: LocalDBCreateInstance
|
||||
//
|
||||
// Description: This function will create the new LocalDB instance.
|
||||
//
|
||||
// Available Flags:
|
||||
// No flags available. Reserved for future use.
|
||||
//
|
||||
// Return Values:
|
||||
// S_OK, if the function succeeds
|
||||
// LOCALDB_ERROR_INVALID_PARAM_INSTANCE_NAME, if the instance name parameter is invalid
|
||||
// LOCALDB_ERROR_INVALID_PARAM_VERSION, if the version parameter is invalid
|
||||
// LOCALDB_ERROR_INVALID_PARAM_FLAGS, if the flags are invalid
|
||||
// LOCALDB_ERROR_INVALID_OPERATION, if the user tries to create a default instance
|
||||
// LOCALDB_ERROR_INSTANCE_FOLDER_PATH_TOO_LONG, if the path where instance should be stored is longer than MAX_PATH
|
||||
// LOCALDB_ERROR_VERSION_REQUESTED_NOT_INSTALLED, if the specified service level is not installed
|
||||
// LOCALDB_ERROR_INSTANCE_FOLDER_ALREADY_EXISTS, if the instance folder already exists and is not empty
|
||||
// LOCALDB_ERROR_INSTANCE_EXISTS_WITH_LOWER_VERSION, if the specified instance already exists but with lower version
|
||||
// LOCALDB_ERROR_CANNOT_CREATE_INSTANCE_FOLDER, if a folder cannot be created under %userprofile%
|
||||
// LOCALDB_ERROR_CANNOT_GET_USER_PROFILE_FOLDER, if a user profile folder cannot be retrieved
|
||||
// LOCALDB_ERROR_CANNOT_ACCESS_INSTANCE_FOLDER, if a instance folder cannot be accessed
|
||||
// LOCALDB_ERROR_CANNOT_ACCESS_INSTANCE_REGISTRY, if a instance registry cannot be accessed
|
||||
// LOCALDB_ERROR_INTERNAL_ERROR, if an unexpected error occurred. See event log for details
|
||||
// LOCALDB_ERROR_CANNOT_MODIFY_INSTANCE_REGISTRY, if an instance registry cannot be modified
|
||||
// LOCALDB_ERROR_CANNOT_CREATE_SQL_PROCESS, if a process for Sql Server cannot be created
|
||||
// LOCALDB_ERROR_SQL_SERVER_STARTUP_FAILED, if a Sql Server process is started but Sql Server startup failed.
|
||||
// LOCALDB_ERROR_INSTANCE_CONFIGURATION_CORRUPT, if a instance configuration is corrupted
|
||||
//
|
||||
FnLocalDBCreateInstance LocalDBCreateInstance;
|
||||
//---------------------------------------------------------------------
|
||||
// Function: LocalDBCreateInstance
|
||||
//
|
||||
// Description: This function will create the new LocalDB instance.
|
||||
//
|
||||
// Available Flags:
|
||||
// No flags available. Reserved for future use.
|
||||
//
|
||||
// Return Values:
|
||||
// S_OK, if the function succeeds
|
||||
// LOCALDB_ERROR_INVALID_PARAM_INSTANCE_NAME, if the instance name parameter is invalid
|
||||
// LOCALDB_ERROR_INVALID_PARAM_VERSION, if the version parameter is invalid
|
||||
// LOCALDB_ERROR_INVALID_PARAM_FLAGS, if the flags are invalid
|
||||
// LOCALDB_ERROR_INVALID_OPERATION, if the user tries to create a default instance
|
||||
// LOCALDB_ERROR_INSTANCE_FOLDER_PATH_TOO_LONG, if the path where instance should be stored is longer than MAX_PATH
|
||||
// LOCALDB_ERROR_VERSION_REQUESTED_NOT_INSTALLED, if the specified service level is not installed
|
||||
// LOCALDB_ERROR_INSTANCE_FOLDER_ALREADY_EXISTS, if the instance folder already exists and is not empty
|
||||
// LOCALDB_ERROR_INSTANCE_EXISTS_WITH_LOWER_VERSION, if the specified instance already exists but with lower version
|
||||
// LOCALDB_ERROR_CANNOT_CREATE_INSTANCE_FOLDER, if a folder cannot be created under %userprofile%
|
||||
// LOCALDB_ERROR_CANNOT_GET_USER_PROFILE_FOLDER, if a user profile folder cannot be retrieved
|
||||
// LOCALDB_ERROR_CANNOT_ACCESS_INSTANCE_FOLDER, if a instance folder cannot be accessed
|
||||
// LOCALDB_ERROR_CANNOT_ACCESS_INSTANCE_REGISTRY, if a instance registry cannot be accessed
|
||||
// LOCALDB_ERROR_INTERNAL_ERROR, if an unexpected error occurred. See event log for details
|
||||
// LOCALDB_ERROR_CANNOT_MODIFY_INSTANCE_REGISTRY, if an instance registry cannot be modified
|
||||
// LOCALDB_ERROR_CANNOT_CREATE_SQL_PROCESS, if a process for Sql Server cannot be created
|
||||
// LOCALDB_ERROR_SQL_SERVER_STARTUP_FAILED, if a Sql Server process is started but Sql Server startup failed.
|
||||
// LOCALDB_ERROR_INSTANCE_CONFIGURATION_CORRUPT, if a instance configuration is corrupted
|
||||
//
|
||||
FnLocalDBCreateInstance LocalDBCreateInstance;
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Function: LocalDBStartInstance
|
||||
//
|
||||
// Description: This function will start the given LocalDB instance.
|
||||
//
|
||||
// Return Values:
|
||||
// S_OK, if the function succeeds
|
||||
// LOCALDB_ERROR_UNKNOWN_INSTANCE, if the specified instance doesn't exist
|
||||
// LOCALDB_ERROR_INVALID_PARAM_INSTANCE_NAME, if the instance name parameter is invalid
|
||||
// LOCALDB_ERROR_INVALID_PARAM_CONNECTION, if the wszSqlConnection parameter is NULL
|
||||
// LOCALDB_ERROR_INVALID_PARAM_FLAGS, if the flags are invalid
|
||||
// LOCALDB_ERROR_INSUFFICIENT_BUFFER, if the buffer wszSqlConnection is too small
|
||||
// LOCALDB_ERROR_INSTANCE_FOLDER_PATH_TOO_LONG, if the path where instance should be stored is longer than MAX_PATH
|
||||
//---------------------------------------------------------------------
|
||||
// Function: LocalDBStartInstance
|
||||
//
|
||||
// Description: This function will start the given LocalDB instance.
|
||||
//
|
||||
// Return Values:
|
||||
// S_OK, if the function succeeds
|
||||
// LOCALDB_ERROR_UNKNOWN_INSTANCE, if the specified instance doesn't exist
|
||||
// LOCALDB_ERROR_INVALID_PARAM_INSTANCE_NAME, if the instance name parameter is invalid
|
||||
// LOCALDB_ERROR_INVALID_PARAM_CONNECTION, if the wszSqlConnection parameter is NULL
|
||||
// LOCALDB_ERROR_INVALID_PARAM_FLAGS, if the flags are invalid
|
||||
// LOCALDB_ERROR_INSUFFICIENT_BUFFER, if the buffer wszSqlConnection is too small
|
||||
// LOCALDB_ERROR_INSTANCE_FOLDER_PATH_TOO_LONG, if the path where instance should be stored is longer than MAX_PATH
|
||||
|
||||
// LOCALDB_ERROR_CANNOT_GET_USER_PROFILE_FOLDER, if a user profile folder cannot be retrieved
|
||||
// LOCALDB_ERROR_CANNOT_ACCESS_INSTANCE_FOLDER, if a instance folder cannot be accessed
|
||||
// LOCALDB_ERROR_CANNOT_ACCESS_INSTANCE_REGISTRY, if a instance registry cannot be accessed
|
||||
// LOCALDB_ERROR_INTERNAL_ERROR, if an unexpected error occurred. See event log for details
|
||||
// LOCALDB_ERROR_CANNOT_MODIFY_INSTANCE_REGISTRY, if an instance registry cannot be modified
|
||||
// LOCALDB_ERROR_CANNOT_CREATE_SQL_PROCESS, if a process for Sql Server cannot be created
|
||||
// LOCALDB_ERROR_SQL_SERVER_STARTUP_FAILED, if a Sql Server process is started but Sql Server startup failed.
|
||||
// LOCALDB_ERROR_INSTANCE_CONFIGURATION_CORRUPT, if a instance configuration is corrupted
|
||||
//
|
||||
FnLocalDBStartInstance LocalDBStartInstance;
|
||||
// LOCALDB_ERROR_CANNOT_GET_USER_PROFILE_FOLDER, if a user profile folder cannot be retrieved
|
||||
// LOCALDB_ERROR_CANNOT_ACCESS_INSTANCE_FOLDER, if a instance folder cannot be accessed
|
||||
// LOCALDB_ERROR_CANNOT_ACCESS_INSTANCE_REGISTRY, if a instance registry cannot be accessed
|
||||
// LOCALDB_ERROR_INTERNAL_ERROR, if an unexpected error occurred. See event log for details
|
||||
// LOCALDB_ERROR_CANNOT_MODIFY_INSTANCE_REGISTRY, if an instance registry cannot be modified
|
||||
// LOCALDB_ERROR_CANNOT_CREATE_SQL_PROCESS, if a process for Sql Server cannot be created
|
||||
// LOCALDB_ERROR_SQL_SERVER_STARTUP_FAILED, if a Sql Server process is started but Sql Server startup failed.
|
||||
// LOCALDB_ERROR_INSTANCE_CONFIGURATION_CORRUPT, if a instance configuration is corrupted
|
||||
//
|
||||
FnLocalDBStartInstance LocalDBStartInstance;
|
||||
|
||||
// type definition for LocalDBStopInstance function
|
||||
typedef HRESULT __cdecl FnLocalDBStopInstance (
|
||||
// I the LocalDB instance name
|
||||
__in_z PCWSTR pInstanceName,
|
||||
// I Available flags:
|
||||
// LOCALDB_SHUTDOWN_KILL_PROCESS - force the instance to stop immediately
|
||||
// LOCALDB_SHUTDOWN_WITH_NOWAIT - shutdown the instance with NOWAIT option
|
||||
__in DWORD dwFlags,
|
||||
// I the time in seconds to wait this operation to complete. If this value is 0, this function will return immediately
|
||||
// without waiting for LocalDB instance to stop
|
||||
__in ULONG ulTimeout
|
||||
);
|
||||
// type definition for LocalDBStopInstance function
|
||||
typedef HRESULT __cdecl FnLocalDBStopInstance(
|
||||
// I the LocalDB instance name
|
||||
__in_z PCWSTR pInstanceName,
|
||||
// I Available flags:
|
||||
// LOCALDB_SHUTDOWN_KILL_PROCESS - force the instance to stop immediately
|
||||
// LOCALDB_SHUTDOWN_WITH_NOWAIT - shutdown the instance with NOWAIT option
|
||||
__in DWORD dwFlags,
|
||||
// I the time in seconds to wait this operation to complete. If this value is 0, this function will return immediately
|
||||
// without waiting for LocalDB instance to stop
|
||||
__in ULONG ulTimeout
|
||||
);
|
||||
|
||||
// type definition for pointer to LocalDBStopInstance function
|
||||
typedef FnLocalDBStopInstance* PFnLocalDBStopInstance;
|
||||
// type definition for pointer to LocalDBStopInstance function
|
||||
typedef FnLocalDBStopInstance* PFnLocalDBStopInstance;
|
||||
|
||||
// Flags for the StopLocalDBInstance function
|
||||
// Flags for the StopLocalDBInstance function
|
||||
#define LOCALDB_SHUTDOWN_KILL_PROCESS 0x0001L
|
||||
#define LOCALDB_SHUTDOWN_WITH_NOWAIT 0x0002L
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Function: LocalDBStopInstance
|
||||
//
|
||||
// Description: This function will shutdown the given LocalDB instance.
|
||||
// If the flag LOCALDB_SHUTDOWN_KILL_PROCESS is set, the LocalDB instance will be killed immediately.
|
||||
// IF the flag LOCALDB_SHUTDOWN_WITH_NOWAIT is set, the LocalDB instance will shutdown with NOWAIT option.
|
||||
//
|
||||
// Return Values:
|
||||
// S_OK, if the function succeeds
|
||||
// LOCALDB_ERROR_UNKNOWN_INSTANCE, if the specified instance doesn't exist
|
||||
// LOCALDB_ERROR_INVALID_PARAM_INSTANCE_NAME, if the instance name parameter is invalid
|
||||
// LOCALDB_ERROR_INVALID_PARAM_FLAGS, if the flags are invalid
|
||||
// LOCALDB_ERROR_WAIT_TIMEOUT - if this function has not finished in given time
|
||||
// LOCALDB_ERROR_INTERNAL_ERROR, if an unexpected error occurred. See event log for details
|
||||
//
|
||||
FnLocalDBStopInstance LocalDBStopInstance;
|
||||
//---------------------------------------------------------------------
|
||||
// Function: LocalDBStopInstance
|
||||
//
|
||||
// Description: This function will shutdown the given LocalDB instance.
|
||||
// If the flag LOCALDB_SHUTDOWN_KILL_PROCESS is set, the LocalDB instance will be killed immediately.
|
||||
// IF the flag LOCALDB_SHUTDOWN_WITH_NOWAIT is set, the LocalDB instance will shutdown with NOWAIT option.
|
||||
//
|
||||
// Return Values:
|
||||
// S_OK, if the function succeeds
|
||||
// LOCALDB_ERROR_UNKNOWN_INSTANCE, if the specified instance doesn't exist
|
||||
// LOCALDB_ERROR_INVALID_PARAM_INSTANCE_NAME, if the instance name parameter is invalid
|
||||
// LOCALDB_ERROR_INVALID_PARAM_FLAGS, if the flags are invalid
|
||||
// LOCALDB_ERROR_WAIT_TIMEOUT - if this function has not finished in given time
|
||||
// LOCALDB_ERROR_INTERNAL_ERROR, if an unexpected error occurred. See event log for details
|
||||
//
|
||||
FnLocalDBStopInstance LocalDBStopInstance;
|
||||
|
||||
// type definition for LocalDBDeleteInstance function
|
||||
typedef HRESULT __cdecl FnLocalDBDeleteInstance (
|
||||
// I the LocalDB instance name
|
||||
__in_z PCWSTR pInstanceName,
|
||||
// I reserved for the future use. Currently should be set to 0.
|
||||
__in DWORD dwFlags
|
||||
);
|
||||
// type definition for LocalDBDeleteInstance function
|
||||
typedef HRESULT __cdecl FnLocalDBDeleteInstance(
|
||||
// I the LocalDB instance name
|
||||
__in_z PCWSTR pInstanceName,
|
||||
// I reserved for the future use. Currently should be set to 0.
|
||||
__in DWORD dwFlags
|
||||
);
|
||||
|
||||
// type definition for pointer to LocalDBDeleteInstance function
|
||||
typedef FnLocalDBDeleteInstance* PFnLocalDBDeleteInstance;
|
||||
// type definition for pointer to LocalDBDeleteInstance function
|
||||
typedef FnLocalDBDeleteInstance* PFnLocalDBDeleteInstance;
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Function: LocalDBDeleteInstance
|
||||
//
|
||||
// Description: This function will remove the given LocalDB instance. If the given instance is running this function will
|
||||
// fail with the error code LOCALDB_ERROR_INSTANCE_BUSY.
|
||||
//
|
||||
// Return Values:
|
||||
// S_OK, if the function succeeds
|
||||
// LOCALDB_ERROR_INVALID_PARAM_INSTANCE_NAME, if the instance name parameter is invalid
|
||||
// LOCALDB_ERROR_INVALID_PARAM_FLAGS, if the flags are invalid
|
||||
// LOCALDB_ERROR_UNKNOWN_INSTANCE, if the specified instance doesn't exist
|
||||
// LOCALDB_ERROR_INSTANCE_BUSY, if the given instance is running
|
||||
// LOCALDB_ERROR_INTERNAL_ERROR, if an unexpected error occurred. See event log for details
|
||||
//
|
||||
FnLocalDBDeleteInstance LocalDBDeleteInstance;
|
||||
//---------------------------------------------------------------------
|
||||
// Function: LocalDBDeleteInstance
|
||||
//
|
||||
// Description: This function will remove the given LocalDB instance. If the given instance is running this function will
|
||||
// fail with the error code LOCALDB_ERROR_INSTANCE_BUSY.
|
||||
//
|
||||
// Return Values:
|
||||
// S_OK, if the function succeeds
|
||||
// LOCALDB_ERROR_INVALID_PARAM_INSTANCE_NAME, if the instance name parameter is invalid
|
||||
// LOCALDB_ERROR_INVALID_PARAM_FLAGS, if the flags are invalid
|
||||
// LOCALDB_ERROR_UNKNOWN_INSTANCE, if the specified instance doesn't exist
|
||||
// LOCALDB_ERROR_INSTANCE_BUSY, if the given instance is running
|
||||
// LOCALDB_ERROR_INTERNAL_ERROR, if an unexpected error occurred. See event log for details
|
||||
//
|
||||
FnLocalDBDeleteInstance LocalDBDeleteInstance;
|
||||
|
||||
// Function: LocalDBFormatMessage
|
||||
//
|
||||
// Description: This function will return the localized textual description for the given LocalDB error
|
||||
//
|
||||
// Available Flags:
|
||||
// LOCALDB_TRUNCATE_ERR_MESSAGE - the error message should be truncated to fit into the provided buffer
|
||||
//
|
||||
// Return Value:
|
||||
// S_OK, if the function succeeds
|
||||
//
|
||||
// LOCALDB_ERROR_UNKNOWN_HRESULT, if the given HRESULT is unknown
|
||||
// LOCALDB_ERROR_UNKNOWN_LANGUAGE_ID, if the given language id is unknown (0 is recommended for the // default language)
|
||||
// LOCALDB_ERROR_UNKNOWN_ERROR_CODE, if the LocalDB error code is unknown
|
||||
// LOCALDB_ERROR_INVALID_PARAM_FLAGS, if the flags are invalid
|
||||
// LOCALDB_ERROR_INSUFFICIENT_BUFFER, if the input buffer is too short and LOCALDB_TRUNCATE_ERR_MESSAGE flag
|
||||
// is not set
|
||||
// LOCALDB_ERROR_INTERNAL_ERROR, if an unexpected error occurred. See event log for details
|
||||
//
|
||||
FnLocalDBFormatMessage LocalDBFormatMessage;
|
||||
// Function: LocalDBFormatMessage
|
||||
//
|
||||
// Description: This function will return the localized textual description for the given LocalDB error
|
||||
//
|
||||
// Available Flags:
|
||||
// LOCALDB_TRUNCATE_ERR_MESSAGE - the error message should be truncated to fit into the provided buffer
|
||||
//
|
||||
// Return Value:
|
||||
// S_OK, if the function succeeds
|
||||
//
|
||||
// LOCALDB_ERROR_UNKNOWN_HRESULT, if the given HRESULT is unknown
|
||||
// LOCALDB_ERROR_UNKNOWN_LANGUAGE_ID, if the given language id is unknown (0 is recommended for the // default language)
|
||||
// LOCALDB_ERROR_UNKNOWN_ERROR_CODE, if the LocalDB error code is unknown
|
||||
// LOCALDB_ERROR_INVALID_PARAM_FLAGS, if the flags are invalid
|
||||
// LOCALDB_ERROR_INSUFFICIENT_BUFFER, if the input buffer is too short and LOCALDB_TRUNCATE_ERR_MESSAGE flag
|
||||
// is not set
|
||||
// LOCALDB_ERROR_INTERNAL_ERROR, if an unexpected error occurred. See event log for details
|
||||
//
|
||||
FnLocalDBFormatMessage LocalDBFormatMessage;
|
||||
|
||||
#define MAX_LOCALDB_INSTANCE_NAME_LENGTH 128
|
||||
#define MAX_LOCALDB_PARENT_INSTANCE_LENGTH MAX_INSTANCE_NAME
|
||||
|
||||
typedef WCHAR TLocalDBInstanceName[MAX_LOCALDB_INSTANCE_NAME_LENGTH + 1];
|
||||
typedef TLocalDBInstanceName* PTLocalDBInstanceName;
|
||||
typedef WCHAR TLocalDBInstanceName[MAX_LOCALDB_INSTANCE_NAME_LENGTH + 1];
|
||||
typedef TLocalDBInstanceName* PTLocalDBInstanceName;
|
||||
|
||||
// type definition for LocalDBGetInstances function
|
||||
typedef HRESULT __cdecl FnLocalDBGetInstances(
|
||||
// O buffer for a LocalDB instance names
|
||||
__out PTLocalDBInstanceName pInstanceNames,
|
||||
// I/O on input has the number slots for instance names in the pInstanceNames buffer. On output,
|
||||
// has the number of existing LocalDB instances
|
||||
__inout LPDWORD lpdwNumberOfInstances
|
||||
);
|
||||
// type definition for LocalDBGetInstances function
|
||||
typedef HRESULT __cdecl FnLocalDBGetInstances(
|
||||
// O buffer for a LocalDB instance names
|
||||
__out PTLocalDBInstanceName pInstanceNames,
|
||||
// I/O on input has the number slots for instance names in the pInstanceNames buffer. On output,
|
||||
// has the number of existing LocalDB instances
|
||||
__inout LPDWORD lpdwNumberOfInstances
|
||||
);
|
||||
|
||||
// type definition for pointer to LocalDBGetInstances function
|
||||
typedef FnLocalDBGetInstances* PFnLocalDBGetInstances;
|
||||
// type definition for pointer to LocalDBGetInstances function
|
||||
typedef FnLocalDBGetInstances* PFnLocalDBGetInstances;
|
||||
|
||||
// Function: LocalDBGetInstances
|
||||
//
|
||||
// Description: This function returns names for all existing Local DB instances
|
||||
//
|
||||
// Usage Example:
|
||||
// DWORD dwN = 0;
|
||||
// LocalDBGetInstances(NULL, &dwN);
|
||||
// Function: LocalDBGetInstances
|
||||
//
|
||||
// Description: This function returns names for all existing Local DB instances
|
||||
//
|
||||
// Usage Example:
|
||||
// DWORD dwN = 0;
|
||||
// LocalDBGetInstances(NULL, &dwN);
|
||||
|
||||
// PTLocalDBInstanceName insts = (PTLocalDBInstanceName) malloc(dwN * sizeof(TLocalDBInstanceName));
|
||||
// LocalDBGetInstances(insts, &dwN);
|
||||
// PTLocalDBInstanceName insts = (PTLocalDBInstanceName) malloc(dwN * sizeof(TLocalDBInstanceName));
|
||||
// LocalDBGetInstances(insts, &dwN);
|
||||
|
||||
// for (int i = 0; i < dwN; i++)
|
||||
// wprintf(L"%s\n", insts[i]);
|
||||
//
|
||||
// Return values:
|
||||
// S_OK, if the function succeeds
|
||||
//
|
||||
// LOCALDB_ERROR_INSUFFICIENT_BUFFER, the given buffer is to small
|
||||
// LOCALDB_ERROR_INTERNAL_ERROR, if an unexpected error occurred. See event log for details
|
||||
//
|
||||
FnLocalDBGetInstances LocalDBGetInstances;
|
||||
// for (int i = 0; i < dwN; i++)
|
||||
// wprintf(L"%s\n", insts[i]);
|
||||
//
|
||||
// Return values:
|
||||
// S_OK, if the function succeeds
|
||||
//
|
||||
// LOCALDB_ERROR_INSUFFICIENT_BUFFER, the given buffer is to small
|
||||
// LOCALDB_ERROR_INTERNAL_ERROR, if an unexpected error occurred. See event log for details
|
||||
//
|
||||
FnLocalDBGetInstances LocalDBGetInstances;
|
||||
|
||||
// SID string format: S - Revision(1B) - Authority ID (6B) {- Sub authority ID (4B)} * max 15 sub-authorities = 1 + 1 + 3 + 1 + 15 + (1 + 10) * 15
|
||||
// SID string format: S - Revision(1B) - Authority ID (6B) {- Sub authority ID (4B)} * max 15 sub-authorities = 1 + 1 + 3 + 1 + 15 + (1 + 10) * 15
|
||||
#define MAX_STRING_SID_LENGTH 186
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack(8)
|
||||
|
||||
// DEVNOTE: If you want to modify this structure please read DEVNOTEs on top of function LocalDBGetInstanceInfo in sqluserinstance.cpp file.
|
||||
//
|
||||
typedef struct _LocalDBInstanceInfo
|
||||
{
|
||||
DWORD cbLocalDBInstanceInfoSize;
|
||||
TLocalDBInstanceName wszInstanceName;
|
||||
BOOL bExists;
|
||||
BOOL bConfigurationCorrupted;
|
||||
BOOL bIsRunning;
|
||||
DWORD dwMajor;
|
||||
DWORD dwMinor;
|
||||
DWORD dwBuild;
|
||||
DWORD dwRevision;
|
||||
FILETIME ftLastStartDateUTC;
|
||||
WCHAR wszConnection[LOCALDB_MAX_SQLCONNECTION_BUFFER_SIZE];
|
||||
BOOL bIsShared;
|
||||
TLocalDBInstanceName wszSharedInstanceName;
|
||||
WCHAR wszOwnerSID[MAX_STRING_SID_LENGTH + 1];
|
||||
BOOL bIsAutomatic;
|
||||
} LocalDBInstanceInfo;
|
||||
// DEVNOTE: If you want to modify this structure please read DEVNOTEs on top of function LocalDBGetInstanceInfo in sqluserinstance.cpp file.
|
||||
//
|
||||
typedef struct _LocalDBInstanceInfo
|
||||
{
|
||||
DWORD cbLocalDBInstanceInfoSize;
|
||||
TLocalDBInstanceName wszInstanceName;
|
||||
BOOL bExists;
|
||||
BOOL bConfigurationCorrupted;
|
||||
BOOL bIsRunning;
|
||||
DWORD dwMajor;
|
||||
DWORD dwMinor;
|
||||
DWORD dwBuild;
|
||||
DWORD dwRevision;
|
||||
FILETIME ftLastStartDateUTC;
|
||||
WCHAR wszConnection[LOCALDB_MAX_SQLCONNECTION_BUFFER_SIZE];
|
||||
BOOL bIsShared;
|
||||
TLocalDBInstanceName wszSharedInstanceName;
|
||||
WCHAR wszOwnerSID[MAX_STRING_SID_LENGTH + 1];
|
||||
BOOL bIsAutomatic;
|
||||
} LocalDBInstanceInfo;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef LocalDBInstanceInfo* PLocalDBInstanceInfo;
|
||||
typedef LocalDBInstanceInfo* PLocalDBInstanceInfo;
|
||||
|
||||
// type definition for LocalDBGetInstanceInfo function
|
||||
typedef HRESULT __cdecl FnLocalDBGetInstanceInfo(
|
||||
// I the LocalDB instance name
|
||||
__in_z PCWSTR wszInstanceName,
|
||||
// O instance information
|
||||
__out PLocalDBInstanceInfo pInfo,
|
||||
// I Size of LocalDBInstanceInfo structure in bytes
|
||||
__in DWORD cbInfo);
|
||||
// type definition for LocalDBGetInstanceInfo function
|
||||
typedef HRESULT __cdecl FnLocalDBGetInstanceInfo(
|
||||
// I the LocalDB instance name
|
||||
__in_z PCWSTR wszInstanceName,
|
||||
// O instance information
|
||||
__out PLocalDBInstanceInfo pInfo,
|
||||
// I Size of LocalDBInstanceInfo structure in bytes
|
||||
__in DWORD cbInfo);
|
||||
|
||||
// type definition for pointer to LocalDBGetInstances function
|
||||
typedef FnLocalDBGetInstanceInfo* PFnLocalDBGetInstanceInfo;
|
||||
// type definition for pointer to LocalDBGetInstances function
|
||||
typedef FnLocalDBGetInstanceInfo* PFnLocalDBGetInstanceInfo;
|
||||
|
||||
// Function: LocalDBGetInstanceInfo
|
||||
//
|
||||
// Description: This function returns information about the given instance.
|
||||
//
|
||||
// Return values:
|
||||
// S_OK, if the function succeeds
|
||||
//
|
||||
// ERROR_INVALID_PARAMETER, if some of the parameters is invalid
|
||||
// LOCALDB_ERROR_INTERNAL_ERROR, if an unexpected error occurred. See event log for details
|
||||
//
|
||||
FnLocalDBGetInstanceInfo LocalDBGetInstanceInfo;
|
||||
// Function: LocalDBGetInstanceInfo
|
||||
//
|
||||
// Description: This function returns information about the given instance.
|
||||
//
|
||||
// Return values:
|
||||
// S_OK, if the function succeeds
|
||||
//
|
||||
// ERROR_INVALID_PARAMETER, if some of the parameters is invalid
|
||||
// LOCALDB_ERROR_INTERNAL_ERROR, if an unexpected error occurred. See event log for details
|
||||
//
|
||||
FnLocalDBGetInstanceInfo LocalDBGetInstanceInfo;
|
||||
|
||||
// Version has format: Major.Minor[.Build[.Revision]]. Each of components is 32bit integer which is at most 40 digits and 3 dots
|
||||
//
|
||||
// Version has format: Major.Minor[.Build[.Revision]]. Each of components is 32bit integer which is at most 40 digits and 3 dots
|
||||
//
|
||||
#define MAX_LOCALDB_VERSION_LENGTH 43
|
||||
|
||||
typedef WCHAR TLocalDBVersion[MAX_LOCALDB_VERSION_LENGTH + 1];
|
||||
typedef TLocalDBVersion* PTLocalDBVersion;
|
||||
typedef WCHAR TLocalDBVersion[MAX_LOCALDB_VERSION_LENGTH + 1];
|
||||
typedef TLocalDBVersion* PTLocalDBVersion;
|
||||
|
||||
// type definition for LocalDBGetVersions function
|
||||
typedef HRESULT __cdecl FnLocalDBGetVersions(
|
||||
// O buffer for installed LocalDB versions
|
||||
__out PTLocalDBVersion pVersions,
|
||||
// I/O on input has the number slots for versions in the pVersions buffer. On output,
|
||||
// has the number of existing LocalDB versions
|
||||
__inout LPDWORD lpdwNumberOfVersions
|
||||
);
|
||||
// type definition for LocalDBGetVersions function
|
||||
typedef HRESULT __cdecl FnLocalDBGetVersions(
|
||||
// O buffer for installed LocalDB versions
|
||||
__out PTLocalDBVersion pVersions,
|
||||
// I/O on input has the number slots for versions in the pVersions buffer. On output,
|
||||
// has the number of existing LocalDB versions
|
||||
__inout LPDWORD lpdwNumberOfVersions
|
||||
);
|
||||
|
||||
// type definition for pointer to LocalDBGetVersions function
|
||||
typedef FnLocalDBGetVersions* PFnLocalDBGetVersions;
|
||||
// type definition for pointer to LocalDBGetVersions function
|
||||
typedef FnLocalDBGetVersions* PFnLocalDBGetVersions;
|
||||
|
||||
// Function: LocalDBGetVersions
|
||||
//
|
||||
// Description: This function returns all installed LocalDB versions. Returned versions will be in format Major.Minor
|
||||
//
|
||||
// Usage Example:
|
||||
// DWORD dwN = 0;
|
||||
// LocalDBGetVersions(NULL, &dwN);
|
||||
// Function: LocalDBGetVersions
|
||||
//
|
||||
// Description: This function returns all installed LocalDB versions. Returned versions will be in format Major.Minor
|
||||
//
|
||||
// Usage Example:
|
||||
// DWORD dwN = 0;
|
||||
// LocalDBGetVersions(NULL, &dwN);
|
||||
|
||||
// PTLocalDBVersion versions = (PTLocalDBVersion) malloc(dwN * sizeof(TLocalDBVersion));
|
||||
// LocalDBGetVersions(insts, &dwN);
|
||||
// PTLocalDBVersion versions = (PTLocalDBVersion) malloc(dwN * sizeof(TLocalDBVersion));
|
||||
// LocalDBGetVersions(insts, &dwN);
|
||||
|
||||
// for (int i = 0; i < dwN; i++)
|
||||
// wprintf(L"%s\n", insts[i]);
|
||||
//
|
||||
// Return values:
|
||||
// S_OK, if the function succeeds
|
||||
//
|
||||
// LOCALDB_ERROR_INSUFFICIENT_BUFFER, the given buffer is to small
|
||||
// LOCALDB_ERROR_INTERNAL_ERROR, if an unexpected error occurs.
|
||||
//
|
||||
FnLocalDBGetVersions LocalDBGetVersions;
|
||||
// for (int i = 0; i < dwN; i++)
|
||||
// wprintf(L"%s\n", insts[i]);
|
||||
//
|
||||
// Return values:
|
||||
// S_OK, if the function succeeds
|
||||
//
|
||||
// LOCALDB_ERROR_INSUFFICIENT_BUFFER, the given buffer is to small
|
||||
// LOCALDB_ERROR_INTERNAL_ERROR, if an unexpected error occurs.
|
||||
//
|
||||
FnLocalDBGetVersions LocalDBGetVersions;
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack(8)
|
||||
|
||||
// DEVNOTE: If you want to modify this structure please read DEVNOTEs on top of function LocalDBGetVersionInfo in sqluserinstance.cpp file.
|
||||
//
|
||||
typedef struct _LocalDBVersionInfo
|
||||
{
|
||||
DWORD cbLocalDBVersionInfoSize;
|
||||
TLocalDBVersion wszVersion;
|
||||
BOOL bExists;
|
||||
DWORD dwMajor;
|
||||
DWORD dwMinor;
|
||||
DWORD dwBuild;
|
||||
DWORD dwRevision;
|
||||
} LocalDBVersionInfo;
|
||||
// DEVNOTE: If you want to modify this structure please read DEVNOTEs on top of function LocalDBGetVersionInfo in sqluserinstance.cpp file.
|
||||
//
|
||||
typedef struct _LocalDBVersionInfo
|
||||
{
|
||||
DWORD cbLocalDBVersionInfoSize;
|
||||
TLocalDBVersion wszVersion;
|
||||
BOOL bExists;
|
||||
DWORD dwMajor;
|
||||
DWORD dwMinor;
|
||||
DWORD dwBuild;
|
||||
DWORD dwRevision;
|
||||
} LocalDBVersionInfo;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef LocalDBVersionInfo* PLocalDBVersionInfo;
|
||||
typedef LocalDBVersionInfo* PLocalDBVersionInfo;
|
||||
|
||||
// type definition for LocalDBGetVersionInfo function
|
||||
typedef HRESULT __cdecl FnLocalDBGetVersionInfo(
|
||||
// I LocalDB version string
|
||||
__in_z PCWSTR wszVersion,
|
||||
// O version information
|
||||
__out PLocalDBVersionInfo pVersionInfo,
|
||||
// I Size of LocalDBVersionInfo structure in bytes
|
||||
__in DWORD cbVersionInfo
|
||||
);
|
||||
// type definition for LocalDBGetVersionInfo function
|
||||
typedef HRESULT __cdecl FnLocalDBGetVersionInfo(
|
||||
// I LocalDB version string
|
||||
__in_z PCWSTR wszVersion,
|
||||
// O version information
|
||||
__out PLocalDBVersionInfo pVersionInfo,
|
||||
// I Size of LocalDBVersionInfo structure in bytes
|
||||
__in DWORD cbVersionInfo
|
||||
);
|
||||
|
||||
// type definition for pointer to LocalDBGetVersionInfo function
|
||||
typedef FnLocalDBGetVersionInfo* PFnLocalDBGetVersionInfo;
|
||||
// type definition for pointer to LocalDBGetVersionInfo function
|
||||
typedef FnLocalDBGetVersionInfo* PFnLocalDBGetVersionInfo;
|
||||
|
||||
// Function: LocalDBGetVersionInfo
|
||||
//
|
||||
// Description: This function returns information about the given LocalDB version
|
||||
//
|
||||
// Return values:
|
||||
// S_OK, if the function succeeds
|
||||
// LOCALDB_ERROR_INTERNAL_ERROR, if some internal error occurred
|
||||
// LOCALDB_ERROR_INVALID_PARAMETER, if a input parameter is invalid
|
||||
//
|
||||
FnLocalDBGetVersionInfo LocalDBGetVersionInfo;
|
||||
// Function: LocalDBGetVersionInfo
|
||||
//
|
||||
// Description: This function returns information about the given LocalDB version
|
||||
//
|
||||
// Return values:
|
||||
// S_OK, if the function succeeds
|
||||
// LOCALDB_ERROR_INTERNAL_ERROR, if some internal error occurred
|
||||
// LOCALDB_ERROR_INVALID_PARAMETER, if a input parameter is invalid
|
||||
//
|
||||
FnLocalDBGetVersionInfo LocalDBGetVersionInfo;
|
||||
|
||||
typedef HRESULT __cdecl FnLocalDBStartTracing();
|
||||
typedef FnLocalDBStartTracing* PFnLocalDBStartTracing;
|
||||
typedef HRESULT __cdecl FnLocalDBStartTracing();
|
||||
typedef FnLocalDBStartTracing* PFnLocalDBStartTracing;
|
||||
|
||||
// Function: LocalDBStartTracing
|
||||
//
|
||||
// Description: This function will write in registry that Tracing sessions should be started for the current user.
|
||||
//
|
||||
// Return values:
|
||||
// S_OK - on success
|
||||
// Propper HRESULT in case of failure
|
||||
//
|
||||
FnLocalDBStartTracing LocalDBStartTracing;
|
||||
// Function: LocalDBStartTracing
|
||||
//
|
||||
// Description: This function will write in registry that Tracing sessions should be started for the current user.
|
||||
//
|
||||
// Return values:
|
||||
// S_OK - on success
|
||||
// Propper HRESULT in case of failure
|
||||
//
|
||||
FnLocalDBStartTracing LocalDBStartTracing;
|
||||
|
||||
typedef HRESULT __cdecl FnLocalDBStopTracing();
|
||||
typedef FnLocalDBStopTracing* PFnFnLocalDBStopTracing;
|
||||
typedef HRESULT __cdecl FnLocalDBStopTracing();
|
||||
typedef FnLocalDBStopTracing* PFnFnLocalDBStopTracing;
|
||||
|
||||
// Function: LocalDBStopTracing
|
||||
//
|
||||
// Description: This function will write in registry that Tracing sessions should be stopped for the current user.
|
||||
//
|
||||
// Return values:
|
||||
// S_OK - on success
|
||||
// Propper HRESULT in case of failure
|
||||
//
|
||||
FnLocalDBStopTracing LocalDBStopTracing;
|
||||
// Function: LocalDBStopTracing
|
||||
//
|
||||
// Description: This function will write in registry that Tracing sessions should be stopped for the current user.
|
||||
//
|
||||
// Return values:
|
||||
// S_OK - on success
|
||||
// Propper HRESULT in case of failure
|
||||
//
|
||||
FnLocalDBStopTracing LocalDBStopTracing;
|
||||
|
||||
// type definition for LocalDBShareInstance function
|
||||
typedef HRESULT __cdecl FnLocalDBShareInstance(
|
||||
// I the SID of the LocalDB instance owner
|
||||
__in_opt PSID pOwnerSID,
|
||||
// I the private name of LocalDB instance which should be shared
|
||||
__in_z PCWSTR wszPrivateLocalDBInstanceName,
|
||||
// I the public shared name
|
||||
__in_z PCWSTR wszSharedName,
|
||||
// I reserved for the future use. Currently should be set to 0.
|
||||
__in DWORD dwFlags);
|
||||
// type definition for LocalDBShareInstance function
|
||||
typedef HRESULT __cdecl FnLocalDBShareInstance(
|
||||
// I the SID of the LocalDB instance owner
|
||||
__in_opt PSID pOwnerSID,
|
||||
// I the private name of LocalDB instance which should be shared
|
||||
__in_z PCWSTR wszPrivateLocalDBInstanceName,
|
||||
// I the public shared name
|
||||
__in_z PCWSTR wszSharedName,
|
||||
// I reserved for the future use. Currently should be set to 0.
|
||||
__in DWORD dwFlags);
|
||||
|
||||
// type definition for pointer to LocalDBShareInstance function
|
||||
typedef FnLocalDBShareInstance* PFnLocalDBShareInstance;
|
||||
// type definition for pointer to LocalDBShareInstance function
|
||||
typedef FnLocalDBShareInstance* PFnLocalDBShareInstance;
|
||||
|
||||
// Function: LocalDBShareInstance
|
||||
//
|
||||
// Description: This function will share the given private instance of the given user with the given shared name.
|
||||
// This function has to be executed elevated.
|
||||
//
|
||||
// Return values:
|
||||
// HRESULT
|
||||
//
|
||||
FnLocalDBShareInstance LocalDBShareInstance;
|
||||
// Function: LocalDBShareInstance
|
||||
//
|
||||
// Description: This function will share the given private instance of the given user with the given shared name.
|
||||
// This function has to be executed elevated.
|
||||
//
|
||||
// Return values:
|
||||
// HRESULT
|
||||
//
|
||||
FnLocalDBShareInstance LocalDBShareInstance;
|
||||
|
||||
// type definition for LocalDBUnshareInstance function
|
||||
typedef HRESULT __cdecl FnLocalDBUnshareInstance(
|
||||
// I the LocalDB instance name
|
||||
__in_z PCWSTR pInstanceName,
|
||||
// I reserved for the future use. Currently should be set to 0.
|
||||
__in DWORD dwFlags);
|
||||
// type definition for LocalDBUnshareInstance function
|
||||
typedef HRESULT __cdecl FnLocalDBUnshareInstance(
|
||||
// I the LocalDB instance name
|
||||
__in_z PCWSTR pInstanceName,
|
||||
// I reserved for the future use. Currently should be set to 0.
|
||||
__in DWORD dwFlags);
|
||||
|
||||
// type definition for pointer to LocalDBUnshareInstance function
|
||||
typedef FnLocalDBUnshareInstance* PFnLocalDBUnshareInstance;
|
||||
// type definition for pointer to LocalDBUnshareInstance function
|
||||
typedef FnLocalDBUnshareInstance* PFnLocalDBUnshareInstance;
|
||||
|
||||
// Function: LocalDBUnshareInstance
|
||||
//
|
||||
// Description: This function unshares the given LocalDB instance.
|
||||
// If a shared name is given then that shared instance will be unshared.
|
||||
// If a private name is given then we will check if the caller
|
||||
// shares a private instance with the given private name and unshare it.
|
||||
//
|
||||
// Return values:
|
||||
// HRESULT
|
||||
//
|
||||
FnLocalDBUnshareInstance LocalDBUnshareInstance;
|
||||
// Function: LocalDBUnshareInstance
|
||||
//
|
||||
// Description: This function unshares the given LocalDB instance.
|
||||
// If a shared name is given then that shared instance will be unshared.
|
||||
// If a private name is given then we will check if the caller
|
||||
// shares a private instance with the given private name and unshare it.
|
||||
//
|
||||
// Return values:
|
||||
// HRESULT
|
||||
//
|
||||
FnLocalDBUnshareInstance LocalDBUnshareInstance;
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#if defined(LOCALDB_DEFINE_PROXY_FUNCTIONS)
|
||||
//---------------------------------------------------------------------
|
||||
// The following section is enabled only if the constant LOCALDB_DEFINE_PROXY_FUNCTIONS
|
||||
// is defined. It provides an implementation of proxies for each of the LocalDB APIs.
|
||||
// The proxy implementations use a common function to bind to entry points in the
|
||||
// latest installed SqlUserInstance DLL, and then forward the requests.
|
||||
//
|
||||
// The current implementation loads the SqlUserInstance DLL on the first call into
|
||||
// a proxy function. There is no provision for unloading the DLL. Note that if the
|
||||
// process includes multiple binaries (EXE and one or more DLLs), each of them could
|
||||
// load a separate instance of the SqlUserInstance DLL.
|
||||
//
|
||||
// For future consideration: allow the SqlUserInstance DLL to be unloaded dynamically.
|
||||
//
|
||||
// WARNING: these functions must not be called in DLL initialization, since a deadlock
|
||||
// could result loading dependent DLLs.
|
||||
//---------------------------------------------------------------------
|
||||
//---------------------------------------------------------------------
|
||||
// The following section is enabled only if the constant LOCALDB_DEFINE_PROXY_FUNCTIONS
|
||||
// is defined. It provides an implementation of proxies for each of the LocalDB APIs.
|
||||
// The proxy implementations use a common function to bind to entry points in the
|
||||
// latest installed SqlUserInstance DLL, and then forward the requests.
|
||||
//
|
||||
// The current implementation loads the SqlUserInstance DLL on the first call into
|
||||
// a proxy function. There is no provision for unloading the DLL. Note that if the
|
||||
// process includes multiple binaries (EXE and one or more DLLs), each of them could
|
||||
// load a separate instance of the SqlUserInstance DLL.
|
||||
//
|
||||
// For future consideration: allow the SqlUserInstance DLL to be unloaded dynamically.
|
||||
//
|
||||
// WARNING: these functions must not be called in DLL initialization, since a deadlock
|
||||
// could result loading dependent DLLs.
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
// This macro provides the body for each proxy function.
|
||||
//
|
||||
// This macro provides the body for each proxy function.
|
||||
//
|
||||
#define LOCALDB_PROXY(LocalDBFn) static Fn##LocalDBFn* pfn##LocalDBFn = NULL; if (!pfn##LocalDBFn) {HRESULT hr = LocalDBGetPFn(#LocalDBFn, (FARPROC *)&pfn##LocalDBFn); if (FAILED(hr)) return hr;} return (*pfn##LocalDBFn)
|
||||
|
||||
// Structure and function to parse the "Installed Versions" registry subkeys
|
||||
//
|
||||
// Structure and function to parse the "Installed Versions" registry subkeys
|
||||
//
|
||||
typedef struct {
|
||||
DWORD dwComponent[2];
|
||||
WCHAR wszKeyName[256];
|
||||
|
@ -1508,7 +1606,7 @@ static BOOL ParseVersion(Version * pVersion)
|
|||
if (!fHaveDigit)
|
||||
return FALSE;
|
||||
|
||||
pVersion->dwComponent[i] = (DWORD) llVal;
|
||||
pVersion->dwComponent[i] = (DWORD)llVal;
|
||||
|
||||
if (*pwch == L'\0')
|
||||
return TRUE;
|
||||
|
@ -1538,11 +1636,11 @@ static HRESULT LocalDBGetPFn(LPCSTR szLocalDBFn, FARPROC *pfnLocalDBFn)
|
|||
LONG ec;
|
||||
HKEY hkeyVersions = NULL;
|
||||
HKEY hkeyVersion = NULL;
|
||||
Version verHigh = {0};
|
||||
Version verHigh = { 0 };
|
||||
Version verCurrent;
|
||||
DWORD cchKeyName;
|
||||
DWORD dwValueType;
|
||||
WCHAR wszLocalDBDll[MAX_PATH+1];
|
||||
WCHAR wszLocalDBDll[MAX_PATH + 1];
|
||||
DWORD cbLocalDBDll = sizeof(wszLocalDBDll) - sizeof(WCHAR); // to deal with RegQueryValueEx null-termination quirk
|
||||
HMODULE hLocalDBDllTemp = NULL;
|
||||
|
||||
|
@ -1592,7 +1690,7 @@ static HRESULT LocalDBGetPFn(LPCSTR szLocalDBFn, FARPROC *pfnLocalDBFn)
|
|||
{
|
||||
goto Cleanup;
|
||||
}
|
||||
if (ERROR_SUCCESS != (ec = RegQueryValueExW(hkeyVersion, L"InstanceAPIPath", NULL, &dwValueType, (PBYTE) wszLocalDBDll, &cbLocalDBDll)))
|
||||
if (ERROR_SUCCESS != (ec = RegQueryValueExW(hkeyVersion, L"InstanceAPIPath", NULL, &dwValueType, (PBYTE)wszLocalDBDll, &cbLocalDBDll)))
|
||||
{
|
||||
goto Cleanup;
|
||||
}
|
||||
|
@ -1604,7 +1702,7 @@ static HRESULT LocalDBGetPFn(LPCSTR szLocalDBFn, FARPROC *pfnLocalDBFn)
|
|||
// Ensure string value null-terminated
|
||||
// Note that we left a spare character in the output buffer for RegQueryValueEx for this purpose
|
||||
//
|
||||
wszLocalDBDll[cbLocalDBDll/sizeof(WCHAR)] = L'\0';
|
||||
wszLocalDBDll[cbLocalDBDll / sizeof(WCHAR)] = L'\0';
|
||||
|
||||
hLocalDBDllTemp = LoadLibraryW(wszLocalDBDll);
|
||||
if (NULL == hLocalDBDllTemp)
|
||||
|
@ -1619,7 +1717,7 @@ static HRESULT LocalDBGetPFn(LPCSTR szLocalDBFn, FARPROC *pfnLocalDBFn)
|
|||
hLocalDBDllTemp = NULL;
|
||||
}
|
||||
ec = ERROR_SUCCESS;
|
||||
Cleanup:
|
||||
Cleanup:
|
||||
if (hLocalDBDllTemp)
|
||||
FreeLibrary(hLocalDBDllTemp);
|
||||
if (hkeyVersion)
|
||||
|
@ -1641,7 +1739,7 @@ Cleanup:
|
|||
|
||||
if (!pfn)
|
||||
{
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
*pfnLocalDBFn = pfn;
|
||||
return S_OK;
|
||||
|
@ -1651,165 +1749,165 @@ Cleanup:
|
|||
//
|
||||
|
||||
HRESULT __cdecl
|
||||
LocalDBCreateInstance (
|
||||
// I the LocalDB version (e.g. 11.0 or 11.0.1094.2)
|
||||
__in_z PCWSTR wszVersion,
|
||||
// I the instance name
|
||||
__in_z PCWSTR pInstanceName,
|
||||
// I reserved for the future use. Currently should be set to 0.
|
||||
__in DWORD dwFlags
|
||||
)
|
||||
LocalDBCreateInstance(
|
||||
// I the LocalDB version (e.g. 11.0 or 11.0.1094.2)
|
||||
__in_z PCWSTR wszVersion,
|
||||
// I the instance name
|
||||
__in_z PCWSTR pInstanceName,
|
||||
// I reserved for the future use. Currently should be set to 0.
|
||||
__in DWORD dwFlags
|
||||
)
|
||||
{
|
||||
LOCALDB_PROXY(LocalDBCreateInstance)(wszVersion, pInstanceName, dwFlags);
|
||||
LOCALDB_PROXY(LocalDBCreateInstance)(wszVersion, pInstanceName, dwFlags);
|
||||
}
|
||||
|
||||
HRESULT __cdecl
|
||||
LocalDBStartInstance(
|
||||
// I the instance name
|
||||
__in_z PCWSTR pInstanceName,
|
||||
// I reserved for the future use. Currently should be set to 0.
|
||||
__in DWORD dwFlags,
|
||||
// O the buffer to store the connection string to the LocalDB instance
|
||||
__out_ecount_z_opt(*lpcchSqlConnection) LPWSTR wszSqlConnection,
|
||||
// I/O on input has the size of the wszSqlConnection buffer in characters. On output, if the given buffer size is
|
||||
// too small, has the buffer size required, in characters, including trailing null.
|
||||
__inout_opt LPDWORD lpcchSqlConnection
|
||||
)
|
||||
// I the instance name
|
||||
__in_z PCWSTR pInstanceName,
|
||||
// I reserved for the future use. Currently should be set to 0.
|
||||
__in DWORD dwFlags,
|
||||
// O the buffer to store the connection string to the LocalDB instance
|
||||
__out_ecount_z_opt(*lpcchSqlConnection) LPWSTR wszSqlConnection,
|
||||
// I/O on input has the size of the wszSqlConnection buffer in characters. On output, if the given buffer size is
|
||||
// too small, has the buffer size required, in characters, including trailing null.
|
||||
__inout_opt LPDWORD lpcchSqlConnection
|
||||
)
|
||||
{
|
||||
LOCALDB_PROXY(LocalDBStartInstance)(pInstanceName, dwFlags, wszSqlConnection, lpcchSqlConnection);
|
||||
LOCALDB_PROXY(LocalDBStartInstance)(pInstanceName, dwFlags, wszSqlConnection, lpcchSqlConnection);
|
||||
}
|
||||
|
||||
HRESULT __cdecl
|
||||
LocalDBStopInstance (
|
||||
// I the instance name
|
||||
__in_z PCWSTR pInstanceName,
|
||||
// I Available flags:
|
||||
// LOCALDB_SHUTDOWN_KILL_PROCESS - force the instance to stop immediately
|
||||
// LOCALDB_SHUTDOWN_WITH_NOWAIT - shutdown the instance with NOWAIT option
|
||||
__in DWORD dwFlags,
|
||||
// I the time in seconds to wait this operation to complete. If this value is 0, this function will return immediately
|
||||
// without waiting for LocalDB instance to stop
|
||||
__in ULONG ulTimeout
|
||||
)
|
||||
LocalDBStopInstance(
|
||||
// I the instance name
|
||||
__in_z PCWSTR pInstanceName,
|
||||
// I Available flags:
|
||||
// LOCALDB_SHUTDOWN_KILL_PROCESS - force the instance to stop immediately
|
||||
// LOCALDB_SHUTDOWN_WITH_NOWAIT - shutdown the instance with NOWAIT option
|
||||
__in DWORD dwFlags,
|
||||
// I the time in seconds to wait this operation to complete. If this value is 0, this function will return immediately
|
||||
// without waiting for LocalDB instance to stop
|
||||
__in ULONG ulTimeout
|
||||
)
|
||||
{
|
||||
LOCALDB_PROXY(LocalDBStopInstance)(pInstanceName, dwFlags, ulTimeout);
|
||||
LOCALDB_PROXY(LocalDBStopInstance)(pInstanceName, dwFlags, ulTimeout);
|
||||
}
|
||||
|
||||
HRESULT __cdecl
|
||||
LocalDBDeleteInstance (
|
||||
// I the instance name
|
||||
__in_z PCWSTR pInstanceName,
|
||||
// reserved for the future use. Currently should be set to 0.
|
||||
__in DWORD dwFlags
|
||||
)
|
||||
LocalDBDeleteInstance(
|
||||
// I the instance name
|
||||
__in_z PCWSTR pInstanceName,
|
||||
// reserved for the future use. Currently should be set to 0.
|
||||
__in DWORD dwFlags
|
||||
)
|
||||
{
|
||||
LOCALDB_PROXY(LocalDBDeleteInstance)(pInstanceName, dwFlags);
|
||||
LOCALDB_PROXY(LocalDBDeleteInstance)(pInstanceName, dwFlags);
|
||||
}
|
||||
|
||||
HRESULT __cdecl
|
||||
LocalDBFormatMessage(
|
||||
// I the LocalDB error code
|
||||
__in HRESULT hrLocalDB,
|
||||
// I Available flags:
|
||||
// LOCALDB_TRUNCATE_ERR_MESSAGE - if the input buffer is too short,
|
||||
// the error message will be truncated to fit into the buffer
|
||||
__in DWORD dwFlags,
|
||||
// I Language desired (LCID) or 0 (in which case Win32 FormatMessage order is used)
|
||||
__in DWORD dwLanguageId,
|
||||
// O the buffer to store the LocalDB error message
|
||||
__out_ecount_z(*lpcchMessage) LPWSTR wszMessage,
|
||||
// I/O on input has the size of the wszMessage buffer in characters. On output, if the given buffer size is
|
||||
// too small, has the buffer size required, in characters, including trailing null. If the function succeeds
|
||||
// contains the number of characters in the message, excluding the trailing null
|
||||
__inout LPDWORD lpcchMessage
|
||||
)
|
||||
// I the LocalDB error code
|
||||
__in HRESULT hrLocalDB,
|
||||
// I Available flags:
|
||||
// LOCALDB_TRUNCATE_ERR_MESSAGE - if the input buffer is too short,
|
||||
// the error message will be truncated to fit into the buffer
|
||||
__in DWORD dwFlags,
|
||||
// I Language desired (LCID) or 0 (in which case Win32 FormatMessage order is used)
|
||||
__in DWORD dwLanguageId,
|
||||
// O the buffer to store the LocalDB error message
|
||||
__out_ecount_z(*lpcchMessage) LPWSTR wszMessage,
|
||||
// I/O on input has the size of the wszMessage buffer in characters. On output, if the given buffer size is
|
||||
// too small, has the buffer size required, in characters, including trailing null. If the function succeeds
|
||||
// contains the number of characters in the message, excluding the trailing null
|
||||
__inout LPDWORD lpcchMessage
|
||||
)
|
||||
{
|
||||
LOCALDB_PROXY(LocalDBFormatMessage)(hrLocalDB, dwFlags, dwLanguageId, wszMessage, lpcchMessage);
|
||||
LOCALDB_PROXY(LocalDBFormatMessage)(hrLocalDB, dwFlags, dwLanguageId, wszMessage, lpcchMessage);
|
||||
}
|
||||
|
||||
HRESULT __cdecl
|
||||
LocalDBGetInstances(
|
||||
// O buffer with instance names
|
||||
__out PTLocalDBInstanceName pInstanceNames,
|
||||
// I/O on input has the number slots for instance names in the pInstanceNames buffer. On output,
|
||||
// has the number of existing LocalDB instances
|
||||
__inout LPDWORD lpdwNumberOfInstances
|
||||
)
|
||||
// O buffer with instance names
|
||||
__out PTLocalDBInstanceName pInstanceNames,
|
||||
// I/O on input has the number slots for instance names in the pInstanceNames buffer. On output,
|
||||
// has the number of existing LocalDB instances
|
||||
__inout LPDWORD lpdwNumberOfInstances
|
||||
)
|
||||
{
|
||||
LOCALDB_PROXY(LocalDBGetInstances)(pInstanceNames, lpdwNumberOfInstances);
|
||||
LOCALDB_PROXY(LocalDBGetInstances)(pInstanceNames, lpdwNumberOfInstances);
|
||||
}
|
||||
|
||||
HRESULT __cdecl
|
||||
LocalDBGetInstanceInfo(
|
||||
// I the instance name
|
||||
__in_z PCWSTR wszInstanceName,
|
||||
// O instance information
|
||||
__out PLocalDBInstanceInfo pInfo,
|
||||
// I Size of LocalDBInstanceInfo structure in bytes
|
||||
__in DWORD cbInfo
|
||||
)
|
||||
// I the instance name
|
||||
__in_z PCWSTR wszInstanceName,
|
||||
// O instance information
|
||||
__out PLocalDBInstanceInfo pInfo,
|
||||
// I Size of LocalDBInstanceInfo structure in bytes
|
||||
__in DWORD cbInfo
|
||||
)
|
||||
{
|
||||
LOCALDB_PROXY(LocalDBGetInstanceInfo)(wszInstanceName, pInfo, cbInfo);
|
||||
LOCALDB_PROXY(LocalDBGetInstanceInfo)(wszInstanceName, pInfo, cbInfo);
|
||||
}
|
||||
|
||||
HRESULT __cdecl
|
||||
LocalDBStartTracing()
|
||||
{
|
||||
LOCALDB_PROXY(LocalDBStartTracing)();
|
||||
LOCALDB_PROXY(LocalDBStartTracing)();
|
||||
}
|
||||
|
||||
HRESULT __cdecl
|
||||
LocalDBStopTracing()
|
||||
{
|
||||
LOCALDB_PROXY(LocalDBStopTracing)();
|
||||
LOCALDB_PROXY(LocalDBStopTracing)();
|
||||
}
|
||||
|
||||
HRESULT __cdecl
|
||||
HRESULT __cdecl
|
||||
LocalDBShareInstance(
|
||||
// I the SID of the LocalDB instance owner
|
||||
__in_opt PSID pOwnerSID,
|
||||
// I the private name of LocalDB instance which should be shared
|
||||
__in_z PCWSTR wszLocalDBInstancePrivateName,
|
||||
// I the public shared name
|
||||
__in_z PCWSTR wszSharedName,
|
||||
// I reserved for the future use. Currently should be set to 0.
|
||||
__in DWORD dwFlags)
|
||||
// I the SID of the LocalDB instance owner
|
||||
__in_opt PSID pOwnerSID,
|
||||
// I the private name of LocalDB instance which should be shared
|
||||
__in_z PCWSTR wszLocalDBInstancePrivateName,
|
||||
// I the public shared name
|
||||
__in_z PCWSTR wszSharedName,
|
||||
// I reserved for the future use. Currently should be set to 0.
|
||||
__in DWORD dwFlags)
|
||||
{
|
||||
LOCALDB_PROXY(LocalDBShareInstance)(pOwnerSID, wszLocalDBInstancePrivateName, wszSharedName, dwFlags);
|
||||
LOCALDB_PROXY(LocalDBShareInstance)(pOwnerSID, wszLocalDBInstancePrivateName, wszSharedName, dwFlags);
|
||||
}
|
||||
|
||||
HRESULT __cdecl
|
||||
LocalDBGetVersions(
|
||||
// O buffer for installed LocalDB versions
|
||||
__out PTLocalDBVersion pVersions,
|
||||
// I/O on input has the number slots for versions in the pVersions buffer. On output,
|
||||
// has the number of existing LocalDB versions
|
||||
__inout LPDWORD lpdwNumberOfVersions
|
||||
)
|
||||
// O buffer for installed LocalDB versions
|
||||
__out PTLocalDBVersion pVersions,
|
||||
// I/O on input has the number slots for versions in the pVersions buffer. On output,
|
||||
// has the number of existing LocalDB versions
|
||||
__inout LPDWORD lpdwNumberOfVersions
|
||||
)
|
||||
{
|
||||
LOCALDB_PROXY(LocalDBGetVersions)(pVersions, lpdwNumberOfVersions);
|
||||
LOCALDB_PROXY(LocalDBGetVersions)(pVersions, lpdwNumberOfVersions);
|
||||
}
|
||||
|
||||
HRESULT __cdecl
|
||||
LocalDBUnshareInstance(
|
||||
// I the LocalDB instance name
|
||||
__in_z PCWSTR pInstanceName,
|
||||
// I reserved for the future use. Currently should be set to 0.
|
||||
__in DWORD dwFlags)
|
||||
// I the LocalDB instance name
|
||||
__in_z PCWSTR pInstanceName,
|
||||
// I reserved for the future use. Currently should be set to 0.
|
||||
__in DWORD dwFlags)
|
||||
{
|
||||
LOCALDB_PROXY(LocalDBUnshareInstance)(pInstanceName, dwFlags);
|
||||
LOCALDB_PROXY(LocalDBUnshareInstance)(pInstanceName, dwFlags);
|
||||
}
|
||||
|
||||
HRESULT __cdecl
|
||||
HRESULT __cdecl
|
||||
LocalDBGetVersionInfo(
|
||||
// I LocalDB version string
|
||||
__in_z PCWSTR wszVersion,
|
||||
// O version information
|
||||
__out PLocalDBVersionInfo pVersionInfo,
|
||||
// I Size of LocalDBVersionInfo structure in bytes
|
||||
__in DWORD cbVersionInfo)
|
||||
// I LocalDB version string
|
||||
__in_z PCWSTR wszVersion,
|
||||
// O version information
|
||||
__out PLocalDBVersionInfo pVersionInfo,
|
||||
// I Size of LocalDBVersionInfo structure in bytes
|
||||
__in DWORD cbVersionInfo)
|
||||
{
|
||||
LOCALDB_PROXY(LocalDBGetVersionInfo)(wszVersion, pVersionInfo, cbVersionInfo);
|
||||
LOCALDB_PROXY(LocalDBGetVersionInfo)(wszVersion, pVersionInfo, cbVersionInfo);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -2173,7 +2271,7 @@ LocalDBGetVersionInfo(
|
|||
//
|
||||
#define LOCALDB_ERROR_CANNOT_LOAD_RESOURCES ((HRESULT)0x89C50121L)
|
||||
|
||||
// Detailed error descriptions
|
||||
// Detailed error descriptions
|
||||
//
|
||||
// MessageId: LOCALDB_EDETAIL_DATADIRECTORY_IS_MISSING
|
||||
//
|
||||
|
|
|
@ -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, ... ) \
|
||||
|
|
409
sqlsrv/stmt.cpp
409
sqlsrv/stmt.cpp
|
@ -88,9 +88,10 @@ 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
|
||||
TSRMLS_DC );
|
||||
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 );
|
||||
sqlsrv_phptype determine_sqlsrv_php_type( sqlsrv_stmt const* stmt, SQLINTEGER sql_type, SQLUINTEGER size, bool prefer_string );
|
||||
|
@ -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
|
||||
CHECK_ZEND_ERROR( zr, stmt, SS_SQLSRV_ERROR_ZEND_OBJECT_FAILED, class_name ) {
|
||||
throw ss::SSException();
|
||||
}
|
||||
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;
|
||||
zval* value_z = NULL;
|
||||
|
||||
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);
|
||||
|
||||
CHECK_CUSTOM_ERROR( type != HASH_KEY_IS_LONG, stmt, SS_SQLSRV_ERROR_PARAM_INVALID_INDEX ) {
|
||||
throw ss::SSException();
|
||||
}
|
||||
// make sure it's an integer 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
|
||||
|
@ -1190,21 +1194,21 @@ void mark_params_by_reference( ss_sqlsrv_stmt* stmt, zval* params_z TSRMLS_DC )
|
|||
// parameter array's first element.
|
||||
|
||||
// if it's a sole variable
|
||||
if (Z_TYPE_P(value_z) != IS_ARRAY) {
|
||||
ZVAL_MAKE_REF(value_z);
|
||||
if ( Z_TYPE_P( value_z ) != IS_ARRAY ) {
|
||||
ZVAL_MAKE_REF( value_z );
|
||||
}
|
||||
else {
|
||||
zval* var = NULL;
|
||||
int zr = (NULL != (var = zend_hash_index_find(Z_ARRVAL_P(value_z), 0))) ? SUCCESS : FAILURE;
|
||||
CHECK_CUSTOM_ERROR(zr == FAILURE, stmt, SS_SQLSRV_ERROR_VAR_REQUIRED, index + 1) {
|
||||
int zr = ( NULL != ( var = zend_hash_index_find( Z_ARRVAL_P( value_z ), 0 ))) ? SUCCESS : FAILURE;
|
||||
CHECK_CUSTOM_ERROR( zr == FAILURE, stmt, SS_SQLSRV_ERROR_VAR_REQUIRED, index + 1 ) {
|
||||
throw ss::SSException();
|
||||
}
|
||||
ZVAL_MAKE_REF(var);
|
||||
ZVAL_MAKE_REF( var );
|
||||
}
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
|
||||
// save our parameters for later.
|
||||
Z_TRY_ADDREF_P(params_z);
|
||||
Z_TRY_ADDREF_P( params_z );
|
||||
stmt->params_z = params_z;
|
||||
}
|
||||
|
||||
|
@ -1225,38 +1229,33 @@ 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_ulong index = -1;
|
||||
zend_string *key = NULL;
|
||||
zval* param_z = NULL;
|
||||
|
||||
zend_string *key = NULL;
|
||||
zend_ulong index = -1;
|
||||
zval* param_z = NULL;
|
||||
zval* value_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();
|
||||
if( stmt->encoding() == SQLSRV_ENCODING_DEFAULT ) {
|
||||
encoding = stmt->conn->encoding();
|
||||
}
|
||||
SQLSMALLINT sql_type = SQL_UNKNOWN_TYPE;
|
||||
SQLULEN column_size = SQLSRV_UNKNOWN_SIZE;
|
||||
SQLSMALLINT decimal_digits = 0;
|
||||
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);
|
||||
SQLSRV_ENCODING encoding = stmt->encoding();
|
||||
if( stmt->encoding() == SQLSRV_ENCODING_DEFAULT ) {
|
||||
encoding = stmt->conn->encoding();
|
||||
}
|
||||
SQLSMALLINT sql_type = SQL_UNKNOWN_TYPE;
|
||||
SQLULEN column_size = SQLSRV_UNKNOWN_SIZE;
|
||||
SQLSMALLINT decimal_digits = 0;
|
||||
SQLSRV_PHPTYPE php_out_type = SQLSRV_PHPTYPE_INVALID;
|
||||
|
||||
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 );
|
||||
// make sure it's an integer 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();
|
||||
}
|
||||
|
||||
// if it's a parameter array
|
||||
if( Z_TYPE_P( param_z ) == IS_ARRAY ) {
|
||||
|
||||
zval* var = NULL;
|
||||
int zr = (NULL != (var = zend_hash_index_find(Z_ARRVAL_P(param_z), 0))) ? SUCCESS : FAILURE;
|
||||
int zr = ( NULL != ( var = zend_hash_index_find( Z_ARRVAL_P( param_z ), 0 ))) ? SUCCESS : FAILURE;
|
||||
CHECK_CUSTOM_ERROR( zr == FAILURE, stmt, SS_SQLSRV_ERROR_VAR_REQUIRED, index + 1 ) {
|
||||
throw ss::SSException();
|
||||
}
|
||||
|
@ -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 );
|
||||
|
@ -1481,69 +1480,60 @@ 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) {
|
||||
if ( in_val == NULL ) {
|
||||
ZVAL_NULL( &out_zval);
|
||||
return;
|
||||
}
|
||||
|
||||
out_zval = ( zval* )sqlsrv_malloc(sizeof( zval ));
|
||||
ZVAL_NULL( out_zval );
|
||||
return out_zval;
|
||||
}
|
||||
switch (sqlsrv_php_type) {
|
||||
|
||||
switch( sqlsrv_php_type ) {
|
||||
|
||||
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 )));
|
||||
}
|
||||
else {
|
||||
ZVAL_DOUBLE( out_zval, *( static_cast<double*>( in_val )));
|
||||
}
|
||||
sqlsrv_free( in_val );
|
||||
break;
|
||||
}
|
||||
case SQLSRV_PHPTYPE_INT:
|
||||
case SQLSRV_PHPTYPE_FLOAT:
|
||||
{
|
||||
if (sqlsrv_php_type == SQLSRV_PHPTYPE_INT) {
|
||||
ZVAL_LONG( &out_zval, *(static_cast<int*>( in_val )));
|
||||
}
|
||||
else {
|
||||
ZVAL_DOUBLE( &out_zval, *(static_cast<double*>( 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 );
|
||||
break;
|
||||
}
|
||||
|
||||
case SQLSRV_PHPTYPE_STREAM:
|
||||
case SQLSRV_PHPTYPE_DATETIME :
|
||||
{
|
||||
out_zval = ( static_cast<zval*>( in_val ) );
|
||||
case SQLSRV_PHPTYPE_STRING:
|
||||
{
|
||||
ZVAL_STRINGL( &out_zval, static_cast<const char*>( in_val ), field_len);
|
||||
break;
|
||||
}
|
||||
|
||||
//addref here because deleting out_zval later will decrement the refcount
|
||||
Z_TRY_ADDREF_P( out_zval );
|
||||
in_val = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
case SQLSRV_PHPTYPE_NULL:
|
||||
out_zval = ( zval* )sqlsrv_malloc(sizeof( zval ));
|
||||
ZVAL_NULL( out_zval );
|
||||
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 ));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
DIE( "Unknown php type" );
|
||||
break;
|
||||
}
|
||||
case SQLSRV_PHPTYPE_NULL:
|
||||
ZVAL_NULL(&out_zval);
|
||||
break;
|
||||
|
||||
return out_zval;
|
||||
default:
|
||||
DIE("Unknown php type");
|
||||
break;
|
||||
}
|
||||
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,94 +1785,92 @@ 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
|
||||
TSRMLS_DC )
|
||||
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 );
|
||||
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;
|
||||
|
||||
// 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() ) {
|
||||
throw ss::SSException();
|
||||
}
|
||||
// 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()) {
|
||||
throw ss::SSException();
|
||||
}
|
||||
|
||||
// get the numer of columns in the result set
|
||||
SQLSMALLINT num_cols = core::SQLNumResultCols( stmt TSRMLS_CC );
|
||||
|
||||
// if this is the first fetch in a new result set, then get the field names and
|
||||
// store them off for successive fetches.
|
||||
if(( fetch_type & SQLSRV_FETCH_ASSOC ) && stmt->fetch_field_names == NULL ) {
|
||||
// get the numer of columns in the result set
|
||||
SQLSMALLINT num_cols = core::SQLNumResultCols(stmt TSRMLS_CC);
|
||||
|
||||
SQLSMALLINT field_name_len;
|
||||
char field_name_temp[ SS_MAXCOLNAMELEN+1 ];
|
||||
sqlsrv_malloc_auto_ptr<sqlsrv_fetch_field_name> field_names;
|
||||
field_names = static_cast<sqlsrv_fetch_field_name*>( sqlsrv_malloc( num_cols * sizeof( sqlsrv_fetch_field_name )));
|
||||
// if this is the first fetch in a new result set, then get the field names and
|
||||
// store them off for successive fetches.
|
||||
if(( fetch_type & SQLSRV_FETCH_ASSOC ) && stmt->fetch_field_names == NULL) {
|
||||
|
||||
for( int i = 0; i < num_cols; ++i ) {
|
||||
SQLSMALLINT field_name_len;
|
||||
char field_name_temp[SS_MAXCOLNAMELEN + 1];
|
||||
sqlsrv_malloc_auto_ptr<sqlsrv_fetch_field_name> field_names;
|
||||
field_names = static_cast<sqlsrv_fetch_field_name*>( sqlsrv_malloc( num_cols * sizeof(sqlsrv_fetch_field_name)));
|
||||
|
||||
core::SQLColAttribute( stmt, i + 1, SQL_DESC_NAME, field_name_temp, SS_MAXCOLNAMELEN+1, &field_name_len, NULL
|
||||
TSRMLS_CC );
|
||||
field_names[ i ].name = static_cast<char*>( sqlsrv_malloc( field_name_len, sizeof( char ), 1 ));
|
||||
memcpy( (void*) field_names[ i ].name, field_name_temp, field_name_len );
|
||||
field_names[ i ].name[ field_name_len ] = '\0'; // null terminate the field name since SQLColAttribute doesn't.
|
||||
field_names[ i ].len = field_name_len + 1;
|
||||
}
|
||||
for(int i = 0; i < num_cols; ++i) {
|
||||
|
||||
stmt->fetch_field_names = field_names;
|
||||
stmt->fetch_fields_count = num_cols;
|
||||
field_names.transferred();
|
||||
}
|
||||
core::SQLColAttribute(stmt, i + 1, SQL_DESC_NAME, field_name_temp, SS_MAXCOLNAMELEN + 1, &field_name_len, NULL
|
||||
TSRMLS_CC);
|
||||
field_names[i].name = static_cast<char*>( sqlsrv_malloc( field_name_len, sizeof(char), 1 ));
|
||||
memcpy(( void* )field_names[i].name, field_name_temp, field_name_len);
|
||||
field_names[i].name[field_name_len] = '\0'; // null terminate the field name since SQLColAttribute doesn't.
|
||||
field_names[i].len = field_name_len + 1;
|
||||
}
|
||||
|
||||
int zr = array_init( &fields );
|
||||
CHECK_ZEND_ERROR( zr, stmt, SQLSRV_ERROR_ZEND_HASH ) {
|
||||
throw ss::SSException();
|
||||
}
|
||||
stmt->fetch_field_names = field_names;
|
||||
stmt->fetch_fields_count = num_cols;
|
||||
field_names.transferred();
|
||||
}
|
||||
|
||||
// get the fields
|
||||
for( int i = 0; i < num_cols; ++i ) {
|
||||
int zr = array_init( &fields );
|
||||
CHECK_ZEND_ERROR( zr, stmt, SQLSRV_ERROR_ZEND_HASH ) {
|
||||
throw ss::SSException();
|
||||
}
|
||||
|
||||
for( int i = 0; i < num_cols; ++i ) {
|
||||
SQLLEN field_len = -1;
|
||||
|
||||
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 );
|
||||
|
||||
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 ));
|
||||
|
||||
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);
|
||||
}
|
||||
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 ) {
|
||||
|
||||
if( fetch_type & SQLSRV_FETCH_ASSOC ) {
|
||||
|
||||
CHECK_CUSTOM_WARNING_AS_ERROR(( stmt->fetch_field_names[ i ].len == 1 && !allow_empty_field_names ), stmt,
|
||||
SS_SQLSRV_WARNING_FIELD_NAME_EMPTY ) {
|
||||
throw ss::SSException();
|
||||
}
|
||||
zr = add_next_index_zval( &fields, &field );
|
||||
CHECK_ZEND_ERROR( zr, stmt, SQLSRV_ERROR_ZEND_HASH ) {
|
||||
throw ss::SSException();
|
||||
}
|
||||
}
|
||||
|
||||
if( stmt->fetch_field_names[ i ].len > 1 || allow_empty_field_names ) {
|
||||
|
||||
zr = add_assoc_zval( &fields, stmt->fetch_field_names[ i ].name, &field );
|
||||
CHECK_ZEND_ERROR( zr, stmt, SQLSRV_ERROR_ZEND_HASH ) {
|
||||
throw ss::SSException();
|
||||
}
|
||||
Z_TRY_ADDREF_P(&field);
|
||||
}
|
||||
}
|
||||
} //for loop
|
||||
if( fetch_type & SQLSRV_FETCH_ASSOC ) {
|
||||
|
||||
CHECK_CUSTOM_WARNING_AS_ERROR(( stmt->fetch_field_names[i].len == 1 && !allow_empty_field_names ), stmt,
|
||||
SS_SQLSRV_WARNING_FIELD_NAME_EMPTY) {
|
||||
throw ss::SSException();
|
||||
}
|
||||
|
||||
if( stmt->fetch_field_names[ i ].len > 1 || allow_empty_field_names ) {
|
||||
|
||||
zr = add_assoc_zval( &fields, stmt->fetch_field_names[i].name, &field );
|
||||
CHECK_ZEND_ERROR( zr, stmt, SQLSRV_ERROR_ZEND_HASH ) {
|
||||
throw ss::SSException();
|
||||
}
|
||||
}
|
||||
}
|
||||
//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 ) {
|
||||
DIE( "Fatal: Error retrieving encoding from encoding hash table." );
|
||||
}
|
||||
|
||||
if( !stricmp( encoding_string, encoding->iana )) {
|
||||
phptype_encoding.typeinfo.encoding = encoding->code_page;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
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"
|
||||
|
|
122
sqlsrv/util.cpp
122
sqlsrv/util.cpp
|
@ -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;
|
||||
}
|
||||
int result;
|
||||
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 )) {
|
||||
|
||||
LOG(SEV_ERROR, "An invalid parameter was passed to %1!s!.", _FN_ );
|
||||
RETURN_FALSE;
|
||||
}
|
||||
RETURN_FALSE;
|
||||
}
|
||||
}
|
||||
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 )) {
|
||||
|
||||
if( flags == SQLSRV_ERR_ALL ) {
|
||||
|
||||
int result;
|
||||
zval both_z;
|
||||
ZVAL_UNDEF( &both_z );
|
||||
result = array_init( &both_z );
|
||||
if( result == FAILURE ) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
}
|
||||
if( zend_hash_num_elements( Z_ARRVAL_P( &err_z )) == 0 ) {
|
||||
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
if( Z_TYPE_P( SQLSRV_G( errors )) == IS_ARRAY && !sqlsrv_merge_zend_hash( &both_z, SQLSRV_G( errors ) 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 ) {
|
||||
|
||||
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_NULL();
|
||||
}
|
||||
RETURN_ZVAL( &err_z, 1, 1 );
|
||||
}
|
||||
|
||||
// sqlsrv_configure( string $setting, mixed $value )
|
||||
|
@ -875,20 +861,21 @@ 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;
|
||||
}
|
||||
|
||||
if( !strncmp( reinterpret_cast<char*>( error->sqlstate ), sql_state, SQL_SQLSTATE_SIZE ) &&
|
||||
( error->native_code == native_code || error->native_code == -1 )) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if( !strncmp( reinterpret_cast<char*>( error->sqlstate ), sql_state, SQL_SQLSTATE_SIZE ) &&
|
||||
( 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;
|
||||
zend_ulong index = -1;
|
||||
zend_string* key = NULL;
|
||||
zval* value_z = NULL;
|
||||
|
||||
for( zend_hash_internal_pointer_reset( src_ht );
|
||||
zend_hash_has_more_elements( src_ht ) == SUCCESS;
|
||||
zend_hash_move_forward( src_ht ) ) {
|
||||
|
||||
zval* value_z = NULL;
|
||||
result = (value_z = zend_hash_get_current_data( src_ht )) != NULL ? SUCCESS : FAILURE;
|
||||
if( result == FAILURE ) {
|
||||
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 );
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
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