From c727ada07e89fbe1e24956cd198c062f7b3dfd5e Mon Sep 17 00:00:00 2001 From: icosahedron Date: Wed, 7 Mar 2012 02:49:23 +0000 Subject: [PATCH] Microsoft Drivers 3.0 for PHP for SQL Server --- pdo_sqlsrv/CREDITS | 2 +- pdo_sqlsrv/README.TXT | 24 +- pdo_sqlsrv/config.w32 | 9 +- pdo_sqlsrv/core_conn.cpp | 27 +- pdo_sqlsrv/core_init.cpp | 2 +- pdo_sqlsrv/core_results.cpp | 1338 +++++++++++++++ pdo_sqlsrv/core_sqlsrv.h | 438 ++++- pdo_sqlsrv/core_stmt.cpp | 248 ++- pdo_sqlsrv/core_stream.cpp | 9 +- pdo_sqlsrv/core_util.cpp | 64 +- pdo_sqlsrv/pdo_dbh.cpp | 181 ++- pdo_sqlsrv/pdo_init.cpp | 42 +- pdo_sqlsrv/pdo_parser.cpp | 2 +- pdo_sqlsrv/pdo_sqlsrv.h | 53 +- pdo_sqlsrv/pdo_stmt.cpp | 304 +++- pdo_sqlsrv/pdo_util.cpp | 49 +- pdo_sqlsrv/sqlncli.h | 3043 +++++++++++++++++++++++++++++++++++ pdo_sqlsrv/template.rc | 4 +- pdo_sqlsrv/version.h | 18 +- sqlsrv/CREDITS | 2 +- sqlsrv/README.TXT | 24 +- sqlsrv/config.w32 | 8 +- sqlsrv/conn.cpp | 60 +- sqlsrv/core_conn.cpp | 27 +- sqlsrv/core_init.cpp | 2 +- sqlsrv/core_results.cpp | 1338 +++++++++++++++ sqlsrv/core_sqlsrv.h | 438 ++++- sqlsrv/core_stmt.cpp | 248 ++- sqlsrv/core_stream.cpp | 9 +- sqlsrv/core_util.cpp | 64 +- sqlsrv/init.cpp | 112 +- sqlsrv/php_sqlsrv.h | 55 +- sqlsrv/sqlncli.h | 3043 +++++++++++++++++++++++++++++++++++ sqlsrv/stmt.cpp | 63 +- sqlsrv/template.rc | 4 +- sqlsrv/util.cpp | 50 +- sqlsrv/version.h | 18 +- 37 files changed, 10831 insertions(+), 591 deletions(-) create mode 100644 pdo_sqlsrv/core_results.cpp create mode 100644 pdo_sqlsrv/sqlncli.h create mode 100644 sqlsrv/core_results.cpp create mode 100644 sqlsrv/sqlncli.h diff --git a/pdo_sqlsrv/CREDITS b/pdo_sqlsrv/CREDITS index c3489015..dc84c47c 100644 --- a/pdo_sqlsrv/CREDITS +++ b/pdo_sqlsrv/CREDITS @@ -1 +1 @@ -Microsoft Drivers for PHP for SQL Server 2.0 Cumulative Update 1 +Microsoft Drivers 3.0 for PHP for SQL Server (PDO driver) diff --git a/pdo_sqlsrv/README.TXT b/pdo_sqlsrv/README.TXT index 8a678ad1..3cd5b187 100644 --- a/pdo_sqlsrv/README.TXT +++ b/pdo_sqlsrv/README.TXT @@ -1,6 +1,6 @@ * Copyright and License Information * -Copyright 2010 Microsoft Corporation +Copyright Microsoft Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,33 +14,25 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. -* Notes about changes to the Microsoft Drivers for PHP for SQL Server - Driver 2.0 * +* Notes about changes to the Microsoft Drivers 3.0 for PHP for SQL Server * For details about the changes included in this release, please see our blog at -http://blogs.msdn.com/sqlphp or see the SQLSRV20_Readme.htm +http://blogs.msdn.com/sqlphp or see the SQLSRV_Readme.htm file that is part of the download package. -* Notes about compiling the Microsoft Drivers for PHP for SQL Server 2.0 * +* Notes about compiling the Microsoft Drivers 3.0 for PHP for SQL Server * Prerequisites: * You must first be able to build PHP without including these -extensions. For help with doing this, see xthe official PHP website, +extensions. For help with doing this, see the official PHP website, http://php.net. -* The header file sqlncli.h is required to build these extensions. It -may be installed with the Microsoft SQL ServerŪ 2008 R2 Native Client -(found at Microsoft.com) - -To compile the SQLSRV20 and PDO_SQLSRV20: +To compile the SQLSRV30 and PDO_SQLSRV30: 1) Copy the source code directories from this repository into the ext subdirectory. - 1a) Make sure that sqlncli.h is either on the INCLUDE file path or - copied locally to the extension directories. - 2) run buildconf.bat to rebuild the configure.js script to include the new drivers. @@ -61,8 +53,8 @@ wish to do so, run "nmake clean" first. php_sqlsrv.dll and php_pdo_sqlsrv.dll to your PHP extension directory. Also enable them within your PHP installation's php.ini file. -This software has been compiled and tested under PHP 5.2.10 and PHP 5.3.0 -using the Visual C++ 2008 Express and Standard compilers. +This software has been compiled and tested under PHP 5.3.6 and later +using the Visual C++ 2008 and 2010, Express and Standard compilers. * Note about version.h * diff --git a/pdo_sqlsrv/config.w32 b/pdo_sqlsrv/config.w32 index 27359d65..b95ebe3e 100644 --- a/pdo_sqlsrv/config.w32 +++ b/pdo_sqlsrv/config.w32 @@ -3,7 +3,7 @@ // // Contents: JScript build configuration used by buildconf.bat // -// Copyright 2010 Microsoft Corporation +// Copyright Microsoft Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -18,20 +18,21 @@ // limitations under the License. //---------------------------------------------------------------------------------------------------------------------------------- -ARG_WITH("pdo-sqlsrv", "MS SQL Server support for PDO", "no"); - +ARG_WITH("pdo-sqlsrv", "enable Microsoft Drivers for PHP for SQL Server (PDO driver)", "no"); if( PHP_PDO_SQLSRV != "no" ) { if (CHECK_LIB("odbc32.lib", "pdo_sqlsrv") && CHECK_LIB("odbccp32.lib", "pdo_sqlsrv") && CHECK_LIB("version.lib", "pdo_sqlsrv") && CHECK_LIB("psapi.lib", "pdo_sqlsrv")) { - EXTENSION("pdo_sqlsrv", "pdo_dbh.cpp pdo_init.cpp pdo_stmt.cpp pdo_util.cpp pdo_parser.cpp core_init.cpp core_conn.cpp core_stmt.cpp core_util.cpp core_stream.cpp" ) + EXTENSION("pdo_sqlsrv", "pdo_dbh.cpp pdo_init.cpp pdo_stmt.cpp pdo_util.cpp pdo_parser.cpp core_init.cpp core_conn.cpp core_stmt.cpp core_util.cpp core_stream.cpp core_results.cpp" ) CHECK_HEADER_ADD_INCLUDE('sql.h', 'CFLAGS_PDO_SQLSRV_ODBC'); CHECK_HEADER_ADD_INCLUDE('sqlext.h', 'CFLAGS_PDO_SQLSRV_ODBC'); ADD_FLAG( 'LDFLAGS_PDO_SQLSRV', '/NXCOMPAT /DYNAMICBASE' ); ADD_FLAG( 'CFLAGS_PDO_SQLSRV', '/EHsc' ); ADD_FLAG( 'CFLAGS_PDO_SQLSRV', '/GS' ); + ADD_FLAG( 'CFLAGS_PDO_SQLSRV', '/D ZEND_WIN32_FORCE_INLINE' ); + ADD_FLAG( 'CFLAGS_PDO_SQLSRV', '/D _HAS_CPP0X=0' ); ADD_EXTENSION_DEP('pdo_sqlsrv', 'pdo'); } diff --git a/pdo_sqlsrv/core_conn.cpp b/pdo_sqlsrv/core_conn.cpp index 5bb01348..4dcc4f8f 100644 --- a/pdo_sqlsrv/core_conn.cpp +++ b/pdo_sqlsrv/core_conn.cpp @@ -3,7 +3,7 @@ // // Contents: Core routines that use connection handles shared between sqlsrv and pdo_sqlsrv // -// Copyright 2010 Microsoft Corporation +// Copyright Microsoft Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -43,7 +43,7 @@ const int INFO_BUFFER_LEN = 256; const char* PROCESSOR_ARCH[] = { "x86", "x64", "ia64" }; // ODBC driver name. -const char CONNECTION_STRING_DRIVER_NAME[] = "Driver={SQL Server Native Client 10.0};"; +const char CONNECTION_STRING_DRIVER_NAME[] = "Driver={SQL Server Native Client 11.0};"; // default options if only the server is specified const char CONNECTION_STRING_DEFAULT_OPTIONS[] = "Mars_Connection={Yes}"; @@ -562,6 +562,20 @@ void build_connection_string_and_set_conn_attr( sqlsrv_conn* conn, const char* s return; } + // workaround for a bug in ODBC Driver Manager wherein the Driver Manager creates a 0 KB file + // if the TraceFile option is set, even if the "TraceOn" is not present or the "TraceOn" + // flag is set to false. + if( zend_hash_index_exists( options, SQLSRV_CONN_OPTION_TRACE_FILE )) { + + zval** trace_value = NULL; + int zr = zend_hash_index_find( options, SQLSRV_CONN_OPTION_TRACE_ON, (void**)&trace_value ); + + if( zr == FAILURE || !zend_is_true( *trace_value )) { + + zend_hash_index_del( options, SQLSRV_CONN_OPTION_TRACE_FILE ); + } + } + for( zend_hash_internal_pointer_reset( options ); zend_hash_has_more_elements( options ) == SUCCESS; zend_hash_move_forward( options )) { @@ -573,10 +587,10 @@ void build_connection_string_and_set_conn_attr( sqlsrv_conn* conn, const char* s zval** data = NULL; type = zend_hash_get_current_key_ex( options, &key, &key_len, &index, 0, NULL ); - CHECK_CUSTOM_ERROR(( type != HASH_KEY_IS_LONG ), conn, SQLSRV_ERROR_INVALID_OPTION_KEY ) { - throw core::CoreException(); - } + // 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, (void**) &data TSRMLS_CC ); conn_opt = get_connection_option( conn, index, valid_conn_opts TSRMLS_CC ); @@ -660,13 +674,14 @@ void determine_server_version( sqlsrv_conn* conn TSRMLS_DC ) char p[ INFO_BUFFER_LEN ]; core::SQLGetInfo( conn, SQL_DBMS_VER, p, INFO_BUFFER_LEN, &info_len TSRMLS_CC ); + errno = 0; char version_major_str[ 3 ]; SERVER_VERSION version_major; memcpy( version_major_str, p, 2 ); version_major_str[ 2 ] = '\0'; version_major = static_cast( atoi( version_major_str )); - CHECK_CUSTOM_ERROR( version_major == 0 || errno == ERANGE || errno == EINVAL, conn, SQLSRV_ERROR_UNKNOWN_SERVER_VERSION ) + CHECK_CUSTOM_ERROR( version_major == 0 && ( errno == ERANGE || errno == EINVAL ), conn, SQLSRV_ERROR_UNKNOWN_SERVER_VERSION ) { throw core::CoreException(); } diff --git a/pdo_sqlsrv/core_init.cpp b/pdo_sqlsrv/core_init.cpp index 543d8280..8d3436cf 100644 --- a/pdo_sqlsrv/core_init.cpp +++ b/pdo_sqlsrv/core_init.cpp @@ -3,7 +3,7 @@ // // Contents: common initialization routines shared by PDO and sqlsrv // -// Copyright 2010 Microsoft Corporation +// Copyright Microsoft Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/pdo_sqlsrv/core_results.cpp b/pdo_sqlsrv/core_results.cpp new file mode 100644 index 00000000..bce8061f --- /dev/null +++ b/pdo_sqlsrv/core_results.cpp @@ -0,0 +1,1338 @@ +//--------------------------------------------------------------------------------------------------------------------------------- +// File: core_results.cpp +// +// Contents: Result sets +// +// Copyright Microsoft Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// +// You may obtain a copy of the License at: +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//--------------------------------------------------------------------------------------------------------------------------------- + +#include "core_sqlsrv.h" + +#include +#include +#include + +using namespace core; + +// conversion matrix +// each entry holds a function that can perform the conversion or NULL which means the conversion isn't supported +// this is initialized the first time the buffered result set is created. +sqlsrv_buffered_result_set::conv_matrix_t sqlsrv_buffered_result_set::conv_matrix; + +namespace { + +// *** internal types *** + +#pragma warning(disable:4200) + +// *** internal constants *** + +const int INITIAL_FIELD_STRING_LEN = 256; // base allocation size when retrieving a string field + +// *** internal functions *** + +// return an integral type rounded up to a certain number +template +T align_to( T number ) +{ + DEBUG_SQLSRV_ASSERT( (number + align) > number, "Number to align overflowed" ); + return ((number % align) == 0) ? number : (number + align - (number % align)); +} + +// return a pointer address aligned to a certain address boundary +template +T* align_to( T* ptr ) +{ + size_t p_value = (size_t) ptr; + return align_to( p_value ); +} + +// set the nth bit of the bitstream starting at ptr +void set_bit( void* ptr, unsigned int bit ) +{ + unsigned char* null_bits = reinterpret_cast( ptr ); + null_bits += bit >> 3; + *null_bits |= 1 << ( 7 - ( bit & 0x7 )); +} + +// retrieve the nth bit from the bitstream starting at ptr +bool get_bit( void* ptr, unsigned int bit ) +{ + unsigned char* null_bits = reinterpret_cast( ptr ); + null_bits += bit >> 3; + return ((*null_bits & (1 << ( 7 - ( bit & 0x07 )))) != 0); +} + +// read in LOB field during buffered result creation +SQLPOINTER read_lob_field( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_buffered_result_set::meta_data& meta, + unsigned long mem_used TSRMLS_DC ); + +// dtor for each row in the cache +void cache_row_dtor( void* data ); + +// convert a number to a string using locales +// There is an extra copy here, but given the size is short (usually <20 bytes) and the complications of +// subclassing a new streambuf just to avoid the copy, it's easier to do the copy +template +SQLRETURN number_to_string( Number* number_data, __out void* buffer, SQLLEN buffer_length, __out SQLLEN* out_buffer_length, + sqlsrv_error_auto_ptr& last_error ) +{ + std::basic_ostringstream os; + std::locale loc; + os.imbue( loc ); + std::use_facet< std::num_put< Char > >( loc ).put( std::basic_ostream::_Iter( os.rdbuf() ), os, ' ', *number_data ); + std::basic_string& str_num = os.str(); + + if( os.fail() ) { + last_error = new ( sqlsrv_malloc( sizeof( sqlsrv_error ))) sqlsrv_error( + (SQLCHAR*) "IMSSP", (SQLCHAR*) "Failed to convert number to string", -1 ); + return SQL_ERROR; + } + + if( str_num.size() * sizeof(Char) + sizeof(Char) > (size_t) buffer_length ) { + last_error = new ( sqlsrv_malloc( sizeof( sqlsrv_error ))) sqlsrv_error( + (SQLCHAR*) "HY090", (SQLCHAR*) "Buffer length too small to hold number as string", -1 ); + return SQL_ERROR; + } + + *out_buffer_length = str_num.size() * sizeof(Char) + sizeof(Char); // include NULL terminator + memcpy( buffer, str_num.c_str(), *out_buffer_length ); + + return SQL_SUCCESS; +} + +template +SQLRETURN string_to_number( Char* string_data, SQLLEN str_len, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length, sqlsrv_error_auto_ptr& last_error ) +{ + Number* number_data = reinterpret_cast( buffer ); + std::locale loc; // default locale should match system + std::basic_istringstream is; + is.str( string_data ); + is.imbue( loc ); + std::ios_base::iostate st = 0; + + std::use_facet< std::num_get< Char > >( loc ).get( std::basic_istream::_Iter( is.rdbuf( ) ), + std::basic_istream::_Iter(0), is, st, *number_data ); + + if( st & std::ios_base::failbit ) { + last_error = new ( sqlsrv_malloc( sizeof( sqlsrv_error ))) sqlsrv_error( + (SQLCHAR*) "22003", (SQLCHAR*) "Numeric value out of range", 103 ); + return SQL_ERROR; + } + + *out_buffer_length = sizeof( Number ); + + return SQL_SUCCESS; +} + +// "closure" for the hash table destructor +struct row_dtor_closure { + + sqlsrv_buffered_result_set* results; + BYTE* row_data; + + row_dtor_closure( sqlsrv_buffered_result_set* st, BYTE* row ) : + results( st ), row_data( row ) + { + } +}; + +sqlsrv_error* odbc_get_diag_rec( sqlsrv_stmt* odbc, SQLSMALLINT record_number ) +{ + SQLWCHAR wsql_state[ SQL_SQLSTATE_BUFSIZE ]; + SQLCHAR* sql_state = reinterpret_cast( wsql_state ); + SQLWCHAR wnative_message[ SQL_MAX_MESSAGE_LENGTH + 1 ]; + sqlsrv_malloc_auto_ptr native_message; + SQLINTEGER native_code; + SQLINTEGER message_len; + + SQLRETURN r = SQLGetDiagRecW( SQL_HANDLE_STMT, odbc->handle(), record_number, wsql_state, &native_code, wnative_message, + SQL_MAX_MESSAGE_LENGTH + 1, NULL ); + if( !SQL_SUCCEEDED( r ) || r == SQL_NO_DATA ) { + return NULL; + } + + // convert the error into the encoding of the context + SQLSRV_ENCODING enc = odbc->encoding(); + if( enc == SQLSRV_ENCODING_DEFAULT ) { + enc = odbc->conn->encoding(); + } + + // convert the error into the encoding of the context + message_len = SQL_SQLSTATE_BUFSIZE * sizeof(WCHAR); + convert_string_from_utf16( enc, reinterpret_cast( &sql_state ), message_len, + false /*no free*/ ); + message_len = (SQL_MAX_MESSAGE_LENGTH + 1) * sizeof( WCHAR ); + native_message = reinterpret_cast( wnative_message ); + convert_string_from_utf16( enc, reinterpret_cast( &native_message ), message_len, + false /*no free*/ ); + + return new (sqlsrv_malloc( sizeof( sqlsrv_error ))) sqlsrv_error( (SQLCHAR*) sql_state, (SQLCHAR*) native_message, + native_code ); +} + +} // namespace + +// base class result set + +sqlsrv_result_set::sqlsrv_result_set( sqlsrv_stmt* stmt ) : + odbc( stmt ) +{ +} + + +// ODBC result set +// This object simply wraps ODBC function calls + +sqlsrv_odbc_result_set::sqlsrv_odbc_result_set( sqlsrv_stmt* stmt ) : + sqlsrv_result_set( stmt ) +{ +} + +sqlsrv_odbc_result_set::~sqlsrv_odbc_result_set( void ) +{ +} + +SQLRETURN sqlsrv_odbc_result_set::fetch( SQLSMALLINT orientation, SQLLEN offset TSRMLS_DC ) +{ + SQLSRV_ASSERT( odbc != NULL, "Invalid statement handle" ); + return core::SQLFetchScroll( odbc, orientation, offset TSRMLS_CC ); +} + +SQLRETURN sqlsrv_odbc_result_set::get_data( SQLUSMALLINT field_index, SQLSMALLINT target_type, + __out SQLPOINTER buffer, SQLLEN buffer_length, __out SQLLEN* out_buffer_length, + bool handle_warning TSRMLS_DC ) +{ + SQLSRV_ASSERT( odbc != NULL, "Invalid statement handle" ); + return core::SQLGetData( odbc, field_index, target_type, buffer, buffer_length, out_buffer_length, handle_warning TSRMLS_CC ); +} + +SQLRETURN sqlsrv_odbc_result_set::get_diag_field( SQLSMALLINT record_number, SQLSMALLINT diag_identifier, + __out SQLPOINTER diag_info_buffer, SQLSMALLINT buffer_length, + __out SQLSMALLINT* out_buffer_length TSRMLS_DC ) +{ + SQLSRV_ASSERT( odbc != NULL, "Invalid statement handle" ); + return core::SQLGetDiagField( odbc, record_number, diag_identifier, diag_info_buffer, buffer_length, + out_buffer_length TSRMLS_CC ); +} + +sqlsrv_error* sqlsrv_odbc_result_set::get_diag_rec( SQLSMALLINT record_number ) +{ + SQLSRV_ASSERT( odbc != NULL, "Invalid statement handle" ); + return odbc_get_diag_rec( odbc, record_number ); +} + +SQLLEN sqlsrv_odbc_result_set::row_count( TSRMLS_D ) +{ + SQLSRV_ASSERT( odbc != NULL, "Invalid statement handle" ); + return core::SQLRowCount( odbc TSRMLS_CC ); +} + + +// Buffered result set +// This class holds a result set in memory + +sqlsrv_buffered_result_set::sqlsrv_buffered_result_set( sqlsrv_stmt* stmt TSRMLS_DC ) : + sqlsrv_result_set( stmt ), + cache(NULL), + col_count(0), + meta(NULL), + current(0), + last_field_index(-1), + read_so_far(0) +{ + // 10 is an arbitrary number for now for the initial size of the cache + ALLOC_HASHTABLE( cache ); + + core::sqlsrv_zend_hash_init( *stmt, cache, 10 /* # of buckets */, NULL /* hashfn */, cache_row_dtor /*dtor*/, 0 /*persistent*/ + TSRMLS_CC ); + col_count = core::SQLNumResultCols( stmt TSRMLS_CC ); + // there is no result set to buffer + if( col_count == 0 ) { + return; + } + + SQLULEN null_bytes = ( col_count / 8 ) + 1; // number of bits to reserve at the beginning of each row for NULL flags + meta = static_cast( sqlsrv_malloc( col_count * + sizeof( sqlsrv_buffered_result_set::meta_data ))); + + // set up the conversion matrix if this is the first time we're called + if( conv_matrix.size() == 0 ) { + + conv_matrix[ SQL_C_CHAR ][ SQL_C_CHAR ] = &sqlsrv_buffered_result_set::to_same_string; + conv_matrix[ SQL_C_CHAR ][ SQL_C_WCHAR ] = &sqlsrv_buffered_result_set::system_to_wide_string; + conv_matrix[ SQL_C_CHAR ][ SQL_C_BINARY ] = &sqlsrv_buffered_result_set::to_binary_string; + conv_matrix[ SQL_C_CHAR ][ SQL_C_DOUBLE ] = &sqlsrv_buffered_result_set::string_to_double; + conv_matrix[ SQL_C_CHAR ][ SQL_C_LONG ] = &sqlsrv_buffered_result_set::string_to_long; + conv_matrix[ SQL_C_WCHAR ][ SQL_C_WCHAR ] = &sqlsrv_buffered_result_set::to_same_string; + conv_matrix[ SQL_C_WCHAR ][ SQL_C_BINARY ] = &sqlsrv_buffered_result_set::to_binary_string; + conv_matrix[ SQL_C_WCHAR ][ SQL_C_CHAR ] = &sqlsrv_buffered_result_set::wide_to_system_string; + conv_matrix[ SQL_C_WCHAR ][ SQL_C_DOUBLE ] = &sqlsrv_buffered_result_set::wstring_to_double; + conv_matrix[ SQL_C_WCHAR ][ SQL_C_LONG ] = &sqlsrv_buffered_result_set::wstring_to_long; + conv_matrix[ SQL_C_BINARY ][ SQL_C_BINARY ] = &sqlsrv_buffered_result_set::to_same_string; + conv_matrix[ SQL_C_BINARY ][ SQL_C_CHAR ] = &sqlsrv_buffered_result_set::binary_to_system_string; + conv_matrix[ SQL_C_BINARY ][ SQL_C_WCHAR ] = &sqlsrv_buffered_result_set::binary_to_wide_string; + conv_matrix[ SQL_C_LONG ][ SQL_C_DOUBLE ] = &sqlsrv_buffered_result_set::long_to_double; + conv_matrix[ SQL_C_LONG ][ SQL_C_LONG ] = &sqlsrv_buffered_result_set::to_long; + conv_matrix[ SQL_C_LONG ][ SQL_C_BINARY ] = &sqlsrv_buffered_result_set::to_long; + conv_matrix[ SQL_C_LONG ][ SQL_C_CHAR ] = &sqlsrv_buffered_result_set::long_to_system_string; + conv_matrix[ SQL_C_LONG ][ SQL_C_WCHAR ] = &sqlsrv_buffered_result_set::long_to_wide_string; + conv_matrix[ SQL_C_DOUBLE ][ SQL_C_DOUBLE ] = &sqlsrv_buffered_result_set::to_double; + conv_matrix[ SQL_C_DOUBLE ][ SQL_C_BINARY ] = &sqlsrv_buffered_result_set::to_double; + conv_matrix[ SQL_C_DOUBLE ][ SQL_C_CHAR ] = &sqlsrv_buffered_result_set::double_to_system_string; + conv_matrix[ SQL_C_DOUBLE ][ SQL_C_LONG ] = &sqlsrv_buffered_result_set::double_to_long; + conv_matrix[ SQL_C_DOUBLE ][ SQL_C_WCHAR ] = &sqlsrv_buffered_result_set::double_to_wide_string; + } + + // get the meta data and calculate the size of a row buffer + SQLULEN offset = null_bytes; + for( SQLSMALLINT i = 0; i < col_count; ++i ) { + + core::SQLDescribeCol( stmt, i + 1, NULL, 0, NULL, &meta[i].type, &meta[i].length, &meta[i].scale, NULL TSRMLS_CC ); + + offset = align_to<4>( offset ); + meta[i].offset = offset; + + switch( meta[i].type ) { + + // these types are the display size + case SQL_BIGINT: + case SQL_DECIMAL: + case SQL_GUID: + case SQL_NUMERIC: + core::SQLColAttribute( stmt, i + 1, SQL_DESC_DISPLAY_SIZE, NULL, 0, NULL, + reinterpret_cast( &meta[i].length ) TSRMLS_CC ); + meta[i].length += sizeof( char ) + sizeof( SQLULEN ); // null terminator space + offset += meta[i].length; + break; + + // these types are the column size + case SQL_BINARY: + case SQL_CHAR: + case SQL_SS_UDT: + case SQL_VARBINARY: + case SQL_VARCHAR: + // var* field types are length prefixed + if( meta[i].length == sqlsrv_buffered_result_set::meta_data::SIZE_UNKNOWN ) { + offset += sizeof( void* ); + } + else { + meta[i].length += sizeof( SQLULEN ) + sizeof( char ); // length plus null terminator space + offset += meta[i].length; + } + break; + + case SQL_WCHAR: + case SQL_WVARCHAR: + if( meta[i].length == sqlsrv_buffered_result_set::meta_data::SIZE_UNKNOWN ) { + offset += sizeof( void* ); + } + else { + meta[i].length *= sizeof( WCHAR ); + meta[i].length += sizeof( SQLULEN ) + sizeof( WCHAR ); // length plus null terminator space + offset += meta[i].length; + } + break; + + // these types are LOBs + case SQL_LONGVARBINARY: + case SQL_LONGVARCHAR: + case SQL_WLONGVARCHAR: + case SQL_SS_XML: + meta[i].length = sqlsrv_buffered_result_set::meta_data::SIZE_UNKNOWN; + offset += sizeof( void* ); + break; + + // these types are the ISO date size + case SQL_DATETIME: + case SQL_TYPE_DATE: + case SQL_SS_TIME2: + case SQL_SS_TIMESTAMPOFFSET: + case SQL_TYPE_TIMESTAMP: + core::SQLColAttribute( stmt, i + 1, SQL_DESC_DISPLAY_SIZE, NULL, 0, NULL, + reinterpret_cast( &meta[i].length ) TSRMLS_CC ); + meta[i].length += sizeof(char) + sizeof( SQLULEN ); // null terminator space + offset += meta[i].length; + break; + + // these types are the native size + case SQL_BIT: + case SQL_INTEGER: + case SQL_SMALLINT: + case SQL_TINYINT: + meta[i].length = sizeof( long ); + offset += meta[i].length; + break; + + case SQL_REAL: + case SQL_FLOAT: + meta[i].length = sizeof( double ); + offset += meta[i].length; + break; + + default: + SQLSRV_ASSERT( false, "Unknown type in sqlsrv_buffered_query::sqlsrv_buffered_query" ); + break; + } + + switch( meta[i].type ) { + + case SQL_BIGINT: + case SQL_CHAR: + case SQL_DATETIME: + case SQL_DECIMAL: + case SQL_GUID: + case SQL_NUMERIC: + case SQL_LONGVARCHAR: + case SQL_TYPE_DATE: + case SQL_SS_TIME2: + case SQL_SS_TIMESTAMPOFFSET: + case SQL_SS_XML: + case SQL_TYPE_TIMESTAMP: + case SQL_VARCHAR: + meta[i].c_type = SQL_C_CHAR; + break; + + case SQL_SS_UDT: + case SQL_LONGVARBINARY: + case SQL_BINARY: + case SQL_VARBINARY: + meta[i].c_type = SQL_C_BINARY; + break; + + case SQL_WLONGVARCHAR: + case SQL_WCHAR: + case SQL_WVARCHAR: + meta[i].c_type = SQL_C_WCHAR; + break; + + case SQL_BIT: + case SQL_INTEGER: + case SQL_SMALLINT: + case SQL_TINYINT: + meta[i].c_type = SQL_C_LONG; + break; + + case SQL_REAL: + case SQL_FLOAT: + meta[i].c_type = SQL_C_DOUBLE; + break; + + default: + SQLSRV_ASSERT( false, "Unknown type in sqlsrv_buffered_query::sqlsrv_buffered_query" ); + break; + } + + } + + // read the data into the cache + // (offset from the above loop has the size of the row buffer necessary) + unsigned long mem_used = 0; + unsigned long row_count = 0; + + while( core::SQLFetchScroll( stmt, SQL_FETCH_NEXT, 0 TSRMLS_CC ) != SQL_NO_DATA ) { + + // allocate the row buffer + unsigned char* row = static_cast( sqlsrv_malloc( offset )); + memset( row, 0, offset ); + + // read the fields into the row buffer + for( SQLSMALLINT i = 0; i < col_count; ++i ) { + + SQLLEN out_buffer_temp = SQL_NULL_DATA; + SQLPOINTER buffer; + SQLLEN* out_buffer_length = &out_buffer_temp; + + switch( meta[i].c_type ) { + + case SQL_C_CHAR: + case SQL_C_WCHAR: + case SQL_C_BINARY: + if( meta[i].length == sqlsrv_buffered_result_set::meta_data::SIZE_UNKNOWN ) { + + out_buffer_length = &out_buffer_temp; + SQLPOINTER* lob_addr = reinterpret_cast( &row[ meta[i].offset ] ); + *lob_addr = read_lob_field( stmt, i, meta[i], mem_used TSRMLS_CC ); + // a NULL pointer means NULL field + if( *lob_addr == NULL ) { + *out_buffer_length = SQL_NULL_DATA; + } + else { + *out_buffer_length = **reinterpret_cast( lob_addr ); + mem_used += *out_buffer_length; + } + } + else { + + mem_used += meta[i].length; + CHECK_CUSTOM_ERROR( mem_used > stmt->buffered_query_limit * 1024, stmt, + SQLSRV_ERROR_BUFFER_LIMIT_EXCEEDED, stmt->buffered_query_limit ) { + + throw core::CoreException(); + } + + buffer = row + meta[i].offset + sizeof( SQLULEN ); + out_buffer_length = reinterpret_cast( row + meta[i].offset ); + core::SQLGetData( stmt, i + 1, meta[i].c_type, buffer, meta[i].length, out_buffer_length, + false TSRMLS_CC ); + } + break; + + case SQL_C_LONG: + case SQL_C_DOUBLE: + { + mem_used += meta[i].length; + CHECK_CUSTOM_ERROR( mem_used > stmt->buffered_query_limit * 1024, stmt, + SQLSRV_ERROR_BUFFER_LIMIT_EXCEEDED, stmt->buffered_query_limit ) { + + throw core::CoreException(); + } + buffer = row + meta[i].offset; + out_buffer_length = &out_buffer_temp; + core::SQLGetData( stmt, i + 1, meta[i].c_type, buffer, meta[i].length, out_buffer_length, + false TSRMLS_CC ); + } + break; + + default: + SQLSRV_ASSERT( false, "Unknown C type" ); + break; + } + + if( *out_buffer_length == SQL_NULL_DATA ) { + unsigned char* null_bits = reinterpret_cast( row ); + set_bit( row, i ); + } + } + + SQLSRV_ASSERT( row_count < LONG_MAX, "Hard maximum of 2 billion rows exceeded in a buffered query" ); + + // add it to the cache + row_dtor_closure cl( this, row ); + sqlsrv_zend_hash_next_index_insert( *stmt, cache, &cl, sizeof( cl ) TSRMLS_CC ); + } + +} + +sqlsrv_buffered_result_set::~sqlsrv_buffered_result_set( void ) +{ + // free the rows + if( cache ) { + zend_hash_destroy( cache ); + FREE_HASHTABLE( cache ); + cache = NULL; + } + + // free the meta data + if( meta ) { + efree( meta ); + meta = NULL; + } +} + +SQLRETURN sqlsrv_buffered_result_set::fetch( SQLSMALLINT orientation, SQLLEN offset TSRMLS_DC ) +{ + last_error = NULL; + last_field_index = -1; + read_so_far = 0; + + switch( orientation ) { + + case SQL_FETCH_NEXT: + offset = 1; + orientation = SQL_FETCH_RELATIVE; + break; + case SQL_FETCH_PRIOR: + offset = -1; + orientation = SQL_FETCH_RELATIVE; + break; + } + + switch( orientation ) { + + case SQL_FETCH_FIRST: + current = 1; + break; + case SQL_FETCH_LAST: + current = row_count( TSRMLS_C ); + break; + case SQL_FETCH_ABSOLUTE: + current = offset; + break; + case SQL_FETCH_RELATIVE: + current += offset; + break; + default: + SQLSRV_ASSERT( false, "Invalid fetch orientation. Should have been caught before here." ); + break; + } + + // check validity of current row + // the cursor can never get further away than just before the first row + if( current <= 0 && ( offset < 0 || orientation != SQL_FETCH_RELATIVE )) { + current = 0; + return SQL_NO_DATA; + } + + // the cursor can never get further away than just after the last row + if( current > row_count( TSRMLS_C ) || ( current <= 0 && offset > 0 ) /*overflow condition*/ ) { + current = row_count( TSRMLS_C ) + 1; + return SQL_NO_DATA; + } + + return SQL_SUCCESS; +} + +SQLRETURN sqlsrv_buffered_result_set::get_data( SQLUSMALLINT field_index, SQLSMALLINT target_type, + __out SQLPOINTER buffer, SQLLEN buffer_length, __out SQLLEN* out_buffer_length, + bool handle_warning TSRMLS_DC ) +{ + last_error = NULL; + field_index--; // convert from 1 based to 0 based + SQLSRV_ASSERT( field_index < column_count(), "Invalid field index requested" ); + + if( field_index != last_field_index ) { + last_field_index = field_index; + read_so_far = 0; + } + + unsigned char* row = get_row(); + + // if the field is null, then return SQL_NULL_DATA + if( get_bit( row, field_index )) { + *out_buffer_length = SQL_NULL_DATA; + return SQL_SUCCESS; + } + + // check to make sure the conversion type is valid + if( conv_matrix.find( meta[ field_index ].c_type ) == conv_matrix.end() || + conv_matrix.find( meta[ field_index ].c_type )->second.find( target_type ) == + conv_matrix.find( meta[ field_index ].c_type )->second.end() ) { + + last_error = new (sqlsrv_malloc( sizeof( sqlsrv_error ))) + sqlsrv_error( (SQLCHAR*) "07006", + (SQLCHAR*) "Restricted data type attribute violation", 0 ); + return SQL_ERROR; + } + + return (( this )->*( conv_matrix[ meta[ field_index ].c_type ][ target_type ] ))( field_index, buffer, buffer_length, + out_buffer_length ); +} + +SQLRETURN sqlsrv_buffered_result_set::get_diag_field( SQLSMALLINT record_number, SQLSMALLINT diag_identifier, + __out SQLPOINTER diag_info_buffer, SQLSMALLINT buffer_length, + __out SQLSMALLINT* out_buffer_length TSRMLS_DC ) +{ + SQLSRV_ASSERT( record_number == 1, "Only record number 1 can be fetched by sqlsrv_buffered_result_set::get_diag_field" ); + SQLSRV_ASSERT( diag_identifier == SQL_DIAG_SQLSTATE, + "Only SQL_DIAG_SQLSTATE can be fetched by sqlsrv_buffered_result_set::get_diag_field" ); + SQLSRV_ASSERT( buffer_length >= SQL_SQLSTATE_BUFSIZE, + "Buffer not big enough to return SQLSTATE in sqlsrv_buffered_result_set::get_diag_field" ); + + if( last_error == NULL ) { + return SQL_NO_DATA; + } + + SQLSRV_ASSERT( last_error->sqlstate != NULL, + "Must have a SQLSTATE in a valid last_error in sqlsrv_buffered_result_set::get_diag_field" ); + + memcpy( diag_info_buffer, last_error->sqlstate, min( buffer_length, SQL_SQLSTATE_BUFSIZE )); + + return SQL_SUCCESS; +} + +unsigned char* sqlsrv_buffered_result_set::get_row( void ) +{ + row_dtor_closure* cl_ptr; + int zr = zend_hash_index_find( cache, current - 1, (void**) &cl_ptr ); + SQLSRV_ASSERT( zr == SUCCESS, "Failed to find row %1!d! in the cache", current ); + return cl_ptr->row_data; +} + +sqlsrv_error* sqlsrv_buffered_result_set::get_diag_rec( SQLSMALLINT record_number ) +{ + // we only hold a single error if there is one, otherwise return the ODBC error(s) + if( last_error == NULL ) { + return odbc_get_diag_rec( odbc, record_number ); + } + if( record_number > 1 ) { + return NULL; + } + + return new (sqlsrv_malloc( sizeof( sqlsrv_error ))) + sqlsrv_error( last_error->sqlstate, last_error->native_message, last_error->native_code ); +} + +SQLLEN sqlsrv_buffered_result_set::row_count( TSRMLS_D ) +{ + last_error = NULL; + + return zend_hash_num_elements( cache ); +} + +// private functions +template +SQLRETURN binary_to_string( SQLCHAR* field_data, SQLLEN& read_so_far, __out void* buffer, + SQLLEN buffer_length, __out SQLLEN* out_buffer_length, + sqlsrv_error_auto_ptr& out_error ) +{ + // hex characters for the conversion loop below + static char hex_chars[] = "0123456789ABCDEF"; + + SQLSRV_ASSERT( out_error == NULL, "Pending error for sqlsrv_buffered_results_set::binary_to_string" ); + + SQLRETURN r = SQL_ERROR; + + // Set the amount of space necessary for null characters at the end of the data. + SQLSMALLINT extra = sizeof(Char); + + SQLSRV_ASSERT( ((buffer_length - extra) % (extra * 2)) == 0, "Must be multiple of 2 for binary to system string or " + "multiple of 4 for binary to wide string" ); + + // all fields will be treated as ODBC returns varchar(max) fields: + // the entire length of the string is returned the first + // call in out_buffer_len. Successive calls return how much is + // left minus how much has already been read by previous reads + // *2 is for each byte to hex conversion and * extra is for either system or wide string allocation + *out_buffer_length = (*reinterpret_cast( field_data - sizeof( SQLULEN )) - read_so_far) * 2 * extra; + + // copy as much as we can into the buffer + SQLLEN to_copy; + if( buffer_length < *out_buffer_length + extra ) { + to_copy = (buffer_length - extra); + out_error = new ( sqlsrv_malloc( sizeof( sqlsrv_error ))) + sqlsrv_error( (SQLCHAR*) "01004", (SQLCHAR*) "String data, right truncated", -1 ); + r = SQL_SUCCESS_WITH_INFO; + } + else { + r = SQL_SUCCESS; + to_copy = *out_buffer_length; + } + + // if there are bytes to copy as hex + if( to_copy > 0 ) { + // quick hex conversion routine + Char* h = reinterpret_cast( buffer ); + BYTE* b = reinterpret_cast( field_data ); + // to_copy contains the number of bytes to copy, so we divide the number in half (or quarter) + // to get the number of hex digits we can copy + SQLLEN to_copy_hex = to_copy / (2 * extra); + for( int i = 0; i < to_copy_hex; ++i ) { + *h = hex_chars[ (*b & 0xf0) >> 4 ]; + h++; + *h = hex_chars[ (*b++ & 0x0f) ]; + h++; + } + read_so_far += to_copy_hex; + *h = static_cast( 0 ); + } + else { + reinterpret_cast( buffer )[0] = '\0'; + } + + return r; +} + +SQLRETURN sqlsrv_buffered_result_set::binary_to_system_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ) +{ + SQLCHAR* row = get_row(); + SQLCHAR* field_data = NULL; + + if( meta[ field_index ].length == sqlsrv_buffered_result_set::meta_data::SIZE_UNKNOWN ) { + + field_data = *reinterpret_cast( &row[ meta[ field_index ].offset ] ) + sizeof( SQLULEN ); + } + else { + + field_data = &row[ meta[ field_index ].offset ] + sizeof( SQLULEN ); + } + + return binary_to_string( field_data, read_so_far, buffer, buffer_length, out_buffer_length, last_error ); +} + +SQLRETURN sqlsrv_buffered_result_set::binary_to_wide_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ) +{ + SQLCHAR* row = get_row(); + SQLCHAR* field_data = NULL; + + if( meta[ field_index ].length == sqlsrv_buffered_result_set::meta_data::SIZE_UNKNOWN ) { + + field_data = *reinterpret_cast( &row[ meta[ field_index ].offset ] ) + sizeof( SQLULEN ); + } + else { + + field_data = &row[ meta[ field_index ].offset ] + sizeof( SQLULEN ); + } + + return binary_to_string( field_data, read_so_far, buffer, buffer_length, out_buffer_length, last_error ); +} + + +SQLRETURN sqlsrv_buffered_result_set::double_to_long( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ) +{ + SQLSRV_ASSERT( meta[ field_index ].c_type == SQL_C_DOUBLE, "Invalid conversion to long" ); + SQLSRV_ASSERT( buffer_length >= sizeof(LONG), "Buffer length must be able to find a long in " + "sqlsrv_buffered_result_set::double_to_long" ); + + unsigned char* row = get_row(); + double* double_data = reinterpret_cast( &row[ meta[ field_index ].offset ] ); + LONG* long_data = reinterpret_cast( buffer ); + + if( *double_data < double( LONG_MIN ) || *double_data > double( LONG_MAX )) { + last_error = new (sqlsrv_malloc( sizeof( sqlsrv_error ))) sqlsrv_error( (SQLCHAR*) "22003", + (SQLCHAR*) "Numeric value out of range", 0 ); + return SQL_ERROR; + } + + if( *double_data != floor( *double_data )) { + last_error = new (sqlsrv_malloc( sizeof( sqlsrv_error ))) sqlsrv_error( (SQLCHAR*) "01S07", + (SQLCHAR*) "Fractional truncation", 0 ); + return SQL_SUCCESS_WITH_INFO; + } + + *long_data = static_cast( *double_data ); + *out_buffer_length = sizeof( LONG ); + + return SQL_SUCCESS; +} + +SQLRETURN sqlsrv_buffered_result_set::double_to_system_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ) +{ + SQLSRV_ASSERT( meta[ field_index ].c_type == SQL_C_DOUBLE, "Invalid conversion to system string" ); + SQLSRV_ASSERT( buffer_length > 0, "Buffer length must be > 0 in sqlsrv_buffered_result_set::double_to_system_string" ); + + unsigned char* row = get_row(); + double* double_data = reinterpret_cast( &row[ meta[ field_index ].offset ] ); + + return number_to_string( double_data, buffer, buffer_length, out_buffer_length, last_error ); +} + +SQLRETURN sqlsrv_buffered_result_set::double_to_wide_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ) +{ + SQLSRV_ASSERT( meta[ field_index ].c_type == SQL_C_DOUBLE, "Invalid conversion to wide string" ); + SQLSRV_ASSERT( buffer_length > 0, "Buffer length must be > 0 in sqlsrv_buffered_result_set::double_to_wide_string" ); + + unsigned char* row = get_row(); + double* double_data = reinterpret_cast( &row[ meta[ field_index ].offset ] ); + + return number_to_string( double_data, buffer, buffer_length, out_buffer_length, last_error ); +} + +SQLRETURN sqlsrv_buffered_result_set::long_to_double( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ) +{ + SQLSRV_ASSERT( meta[ field_index ].c_type == SQL_C_LONG, "Invalid conversion to long" ); + SQLSRV_ASSERT( buffer_length >= sizeof(double), "Buffer length must be able to find a long in sqlsrv_buffered_result_set::double_to_long" ); + + unsigned char* row = get_row(); + double* double_data = reinterpret_cast( buffer ); + LONG* long_data = reinterpret_cast( &row[ meta[ field_index ].offset ] ); + + *double_data = static_cast( *long_data ); + *out_buffer_length = sizeof( double ); + + return SQL_SUCCESS; +} +SQLRETURN sqlsrv_buffered_result_set::long_to_system_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ) +{ + SQLSRV_ASSERT( meta[ field_index ].c_type == SQL_C_LONG, "Invalid conversion to system string" ); + SQLSRV_ASSERT( buffer_length > 0, "Buffer length must be > 0 in sqlsrv_buffered_result_set::long_to_system_string" ); + + unsigned char* row = get_row(); + LONG* long_data = reinterpret_cast( &row[ meta[ field_index ].offset ] ); + + return number_to_string( long_data, buffer, buffer_length, out_buffer_length, last_error ); +} + +SQLRETURN sqlsrv_buffered_result_set::long_to_wide_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ) +{ + SQLSRV_ASSERT( meta[ field_index ].c_type == SQL_C_LONG, "Invalid conversion to wide string" ); + SQLSRV_ASSERT( buffer_length > 0, "Buffer length must be > 0 in sqlsrv_buffered_result_set::long_to_wide_string" ); + + unsigned char* row = get_row(); + LONG* long_data = reinterpret_cast( &row[ meta[ field_index ].offset ] ); + + return number_to_string( long_data, buffer, buffer_length, out_buffer_length, last_error ); +} + +SQLRETURN sqlsrv_buffered_result_set::string_to_double( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ) +{ + SQLSRV_ASSERT( meta[ field_index ].c_type == SQL_C_CHAR, "Invalid conversion from string to double" ); + SQLSRV_ASSERT( buffer_length >= sizeof( double ), "Buffer needs to be big enough to hold a double" ); + + unsigned char* row = get_row(); + char* string_data = reinterpret_cast( &row[ meta[ field_index ].offset ] ) + sizeof( SQLULEN ); + + return string_to_number( string_data, meta[ field_index ].length, buffer, buffer_length, out_buffer_length, last_error ); +} + +SQLRETURN sqlsrv_buffered_result_set::wstring_to_double( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ) +{ + SQLSRV_ASSERT( meta[ field_index ].c_type == SQL_C_WCHAR, "Invalid conversion from wide string to double" ); + SQLSRV_ASSERT( buffer_length >= sizeof( double ), "Buffer needs to be big enough to hold a double" ); + + unsigned char* row = get_row(); + SQLWCHAR* string_data = reinterpret_cast( &row[ meta[ field_index ].offset ] ) + sizeof( SQLULEN ) / sizeof( SQLWCHAR ); + + return string_to_number( string_data, meta[ field_index ].length, buffer, buffer_length, out_buffer_length, last_error ); +} + +SQLRETURN sqlsrv_buffered_result_set::string_to_long( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ) +{ + SQLSRV_ASSERT( meta[ field_index ].c_type == SQL_C_CHAR, "Invalid conversion from string to long" ); + SQLSRV_ASSERT( buffer_length >= sizeof( LONG ), "Buffer needs to be big enough to hold a long" ); + + unsigned char* row = get_row(); + char* string_data = reinterpret_cast( &row[ meta[ field_index ].offset ] ) + sizeof( SQLULEN ); + + return string_to_number( string_data, meta[ field_index ].length, buffer, buffer_length, out_buffer_length, last_error ); +} + +SQLRETURN sqlsrv_buffered_result_set::wstring_to_long( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ) +{ + SQLSRV_ASSERT( meta[ field_index ].c_type == SQL_C_WCHAR, "Invalid conversion from wide string to long" ); + SQLSRV_ASSERT( buffer_length >= sizeof( LONG ), "Buffer needs to be big enough to hold a long" ); + + unsigned char* row = get_row(); + SQLWCHAR* string_data = reinterpret_cast( &row[ meta[ field_index ].offset ] ) + sizeof( SQLULEN ) / sizeof( SQLWCHAR ); + + return string_to_number( string_data, meta[ field_index ].length, buffer, buffer_length, out_buffer_length, last_error ); +} + +SQLRETURN sqlsrv_buffered_result_set::system_to_wide_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ) +{ + SQLSRV_ASSERT( last_error == NULL, "Pending error for sqlsrv_buffered_results_set::system_to_wide_string" ); + SQLSRV_ASSERT( buffer_length % 2 == 0, "Odd buffer length passed to sqlsrv_buffered_result_set::system_to_wide_string" ); + + SQLRETURN r = SQL_ERROR; + unsigned char* row = get_row(); + + SQLCHAR* field_data = NULL; + SQLULEN field_len = NULL; + + if( meta[ field_index ].length == sqlsrv_buffered_result_set::meta_data::SIZE_UNKNOWN ) { + + field_len = **reinterpret_cast( &row[ meta[ field_index ].offset ] ); + field_data = *reinterpret_cast( &row[ meta[ field_index ].offset ] ) + sizeof( SQLULEN ) + read_so_far; + } + else { + + field_len = *reinterpret_cast( &row[ meta[ field_index ].offset ] ); + field_data = &row[ meta[ field_index ].offset ] + sizeof( SQLULEN ) + read_so_far; + } + + // all fields will be treated as ODBC returns varchar(max) fields: + // the entire length of the string is returned the first + // call in out_buffer_len. Successive calls return how much is + // left minus how much has already been read by previous reads + *out_buffer_length = (*reinterpret_cast( field_data - sizeof( SQLULEN )) - read_so_far) * sizeof(WCHAR); + + // to_copy is the number of characters to copy, not including the null terminator + // supposedly it will never happen that a Windows MBCS will explode to UTF-16 surrogate pair. + SQLLEN to_copy; + + if( (size_t) buffer_length < (field_len - read_so_far + sizeof(char)) * sizeof(WCHAR)) { + + to_copy = (buffer_length - sizeof(WCHAR)) / sizeof(WCHAR); // to_copy is the number of characters + last_error = new ( sqlsrv_malloc( sizeof( sqlsrv_error ))) + sqlsrv_error( (SQLCHAR*) "01004", (SQLCHAR*) "String data, right truncated", -1 ); + r = SQL_SUCCESS_WITH_INFO; + } + else { + + r = SQL_SUCCESS; + to_copy = field_len - read_so_far; + } + + if( to_copy > 0 ) { + + bool tried_again = false; + do { + int ch_space = MultiByteToWideChar( CP_ACP, MB_ERR_INVALID_CHARS, (LPCSTR) field_data, to_copy, + (LPWSTR) buffer, to_copy ); + if( ch_space == 0 ) { + + switch( GetLastError() ) { + + case ERROR_NO_UNICODE_TRANSLATION: + // the theory here is the conversion failed because the end of the buffer we provided contained only + // half a character at the end + if( !tried_again ) { + to_copy--; + tried_again = true; + continue; + } + last_error = new ( sqlsrv_malloc( sizeof( sqlsrv_error ))) + sqlsrv_error( (SQLCHAR*) "IMSSP", (SQLCHAR*) "Invalid Unicode translation", -1 ); + break; + default: + SQLSRV_ASSERT( false, "Severe error translating Unicode" ); + break; + } + + return SQL_ERROR; + } + + ((WCHAR*)buffer)[ to_copy ] = L'\0'; + read_so_far += to_copy; + break; + + } while( true ); + } + else { + reinterpret_cast( buffer )[0] = L'\0'; + } + + return r; +} + +SQLRETURN sqlsrv_buffered_result_set::to_same_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ) +{ + SQLSRV_ASSERT( last_error == NULL, "Pending error for sqlsrv_buffered_results_set::to_same_string" ); + + SQLRETURN r = SQL_ERROR; + unsigned char* row = get_row(); + + // Set the amount of space necessary for null characters at the end of the data. + SQLSMALLINT extra = 0; + + switch( meta[ field_index ].c_type ) { + case SQL_C_WCHAR: + extra = sizeof( SQLWCHAR ); + break; + case SQL_C_BINARY: + extra = 0; + break; + case SQL_C_CHAR: + extra = sizeof( SQLCHAR ); + break; + default: + SQLSRV_ASSERT( false, "Invalid type in get_string_data" ); + break; + } + + SQLCHAR* field_data = NULL; + + if( meta[ field_index ].length == sqlsrv_buffered_result_set::meta_data::SIZE_UNKNOWN ) { + + field_data = *reinterpret_cast( &row[ meta[ field_index ].offset ] ) + sizeof( SQLULEN ); + } + else { + + field_data = &row[ meta[ field_index ].offset ] + sizeof( SQLULEN ); + } + + // all fields will be treated as ODBC returns varchar(max) fields: + // the entire length of the string is returned the first + // call in out_buffer_len. Successive calls return how much is + // left minus how much has already been read by previous reads + *out_buffer_length = *reinterpret_cast( field_data - sizeof( SQLULEN )) - read_so_far; + + // copy as much as we can into the buffer + SQLLEN to_copy; + if( buffer_length < *out_buffer_length + extra ) { + to_copy = buffer_length - extra; + last_error = new ( sqlsrv_malloc( sizeof( sqlsrv_error ))) + sqlsrv_error( (SQLCHAR*) "01004", (SQLCHAR*) "String data, right truncated", -1 ); + r = SQL_SUCCESS_WITH_INFO; + } + else { + r = SQL_SUCCESS; + to_copy = *out_buffer_length; + } + + SQLSRV_ASSERT( to_copy >= 0, "Negative field length calculated in buffered result set" ); + + if( to_copy > 0 ) { + memcpy( buffer, field_data + read_so_far, to_copy ); + read_so_far += to_copy; + } + if( extra ) { + OACR_WARNING_SUPPRESS( 26001, "Buffer length verified above" ); + memcpy( reinterpret_cast( buffer ) + to_copy, L"\0", extra ); + } + + return r; +} + +SQLRETURN sqlsrv_buffered_result_set::wide_to_system_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ) +{ + SQLSRV_ASSERT( last_error == NULL, "Pending error for sqlsrv_buffered_results_set::wide_to_system_string" ); + + SQLRETURN r = SQL_ERROR; + unsigned char* row = get_row(); + + SQLCHAR* field_data = NULL; + SQLULEN field_len = NULL; + + // if this is the first time called for this field, just convert the entire string to system first then + // use that to read from instead of converting chunk by chunk. This is because it's impossible to know + // the total length of the string for output_buffer_length without doing the conversion and returning + // SQL_NO_TOTAL is not consistent with what our other conversion functions do (system_to_wide_string and + // to_same_string). + + if( read_so_far == 0 ) { + + if( meta[ field_index ].length == sqlsrv_buffered_result_set::meta_data::SIZE_UNKNOWN ) { + + field_len = **reinterpret_cast( &row[ meta[ field_index ].offset ] ); + field_data = *reinterpret_cast( &row[ meta[ field_index ].offset ] ) + sizeof( SQLULEN ) + read_so_far; + } + else { + + field_len = *reinterpret_cast( &row[ meta[ field_index ].offset ] ); + field_data = &row[ meta[ field_index ].offset ] + sizeof( SQLULEN ) + read_so_far; + } + + BOOL default_char_used = FALSE; + char default_char = '?'; + + // allocate enough to handle WC -> DBCS conversion if it happens + temp_string = reinterpret_cast( sqlsrv_malloc( field_len, sizeof( char ), sizeof(char))); + temp_length = WideCharToMultiByte( CP_ACP, 0, (LPCWSTR) field_data, field_len / sizeof(WCHAR), + (LPSTR) temp_string.get(), field_len, &default_char, &default_char_used ); + + if( temp_length == 0 ) { + + switch( GetLastError() ) { + + case ERROR_NO_UNICODE_TRANSLATION: + last_error = new ( sqlsrv_malloc( sizeof( sqlsrv_error ))) + sqlsrv_error( (SQLCHAR*) "IMSSP", (SQLCHAR*) "Invalid Unicode translation", -1 ); + break; + default: + SQLSRV_ASSERT( false, "Severe error translating Unicode" ); + break; + } + + return SQL_ERROR; + } + } + + *out_buffer_length = (temp_length - read_so_far); + + SQLLEN to_copy = 0; + + if( (size_t) buffer_length < (temp_length - read_so_far + sizeof(char))) { + + to_copy = buffer_length - sizeof(char); + last_error = new ( sqlsrv_malloc( sizeof( sqlsrv_error ))) + sqlsrv_error( (SQLCHAR*) "01004", (SQLCHAR*) "String data, right truncated", -1 ); + r = SQL_SUCCESS_WITH_INFO; + } + else { + + to_copy = (temp_length - read_so_far); + r = SQL_SUCCESS; + } + + if( to_copy > 0 ) { + + memcpy( buffer, temp_string.get() + read_so_far, to_copy ); + } + SQLSRV_ASSERT( to_copy >= 0, "Invalid field copy length" ); + OACR_WARNING_SUPPRESS( BUFFER_UNDERFLOW, "Buffer length verified above" ); + ((SQLCHAR*) buffer)[ to_copy ] = '\0'; + read_so_far += to_copy; + + return r; +} + + +SQLRETURN sqlsrv_buffered_result_set::to_binary_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ) +{ + return to_same_string( field_index, buffer, buffer_length, out_buffer_length ); +} + +SQLRETURN sqlsrv_buffered_result_set::to_long( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ) +{ + SQLSRV_ASSERT( meta[ field_index ].c_type == SQL_C_LONG, "Invlid conversion to long" ); + SQLSRV_ASSERT( buffer_length >= sizeof( LONG ), "Buffer too small for SQL_C_LONG" ); // technically should ignore this + + unsigned char* row = get_row(); + LONG* long_data = reinterpret_cast( &row[ meta[ field_index ].offset ] ); + + memcpy( buffer, long_data, sizeof( LONG )); + *out_buffer_length = sizeof( LONG ); + + return SQL_SUCCESS; +} + +SQLRETURN sqlsrv_buffered_result_set::to_double( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ) +{ + SQLSRV_ASSERT( meta[ field_index ].c_type == SQL_C_DOUBLE, "Invlid conversion to double" ); + SQLSRV_ASSERT( buffer_length >= sizeof( double ), "Buffer too small for SQL_C_DOUBLE" ); // technically should ignore this + + unsigned char* row = get_row(); + double* double_data = reinterpret_cast( &row[ meta[ field_index ].offset ] ); + + memcpy( buffer, double_data, sizeof( double )); + *out_buffer_length = sizeof( double ); + + return SQL_SUCCESS; +} + +namespace { + +// called for each row in the cache when the cache is destroyed in the destructor +void cache_row_dtor( void* data ) +{ + row_dtor_closure* cl = reinterpret_cast( data ); + BYTE* row = cl->row_data; + // don't release this here, since this is called from the destructor of the result_set + sqlsrv_buffered_result_set* result_set = cl->results; + + for( SQLSMALLINT i = 0; i < result_set->column_count(); ++i ) { + + if( result_set->col_meta_data(i).length == sqlsrv_buffered_result_set::meta_data::SIZE_UNKNOWN ) { + + void* out_of_row_data = *reinterpret_cast( &row[ result_set->col_meta_data(i).offset ] ); + sqlsrv_free( out_of_row_data ); + } + } + + sqlsrv_free( row ); +} + +SQLPOINTER read_lob_field( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_buffered_result_set::meta_data& meta, + unsigned long mem_used TSRMLS_DC ) +{ + SQLSMALLINT extra = 0; + SQLLEN* output_buffer_len = NULL; + + // Set the amount of space necessary for null characters at the end of the data. + switch( meta.c_type ) { + case SQL_C_WCHAR: + extra = sizeof( SQLWCHAR ); + break; + case SQL_C_BINARY: + extra = 0; + break; + case SQL_C_CHAR: + extra = sizeof( SQLCHAR ); + break; + default: + SQLSRV_ASSERT( false, "Invalid type in read_lob_field" ); + break; + } + + SQLLEN already_read = 0; + SQLLEN to_read = INITIAL_FIELD_STRING_LEN; + sqlsrv_malloc_auto_ptr buffer; + buffer = static_cast( sqlsrv_malloc( INITIAL_FIELD_STRING_LEN + extra + sizeof( SQLULEN ))); + SQLRETURN r = SQL_SUCCESS; + SQLCHAR state[ SQL_SQLSTATE_BUFSIZE ]; + SQLLEN last_field_len = 0; + bool full_length_returned = false; + + do { + + + output_buffer_len = reinterpret_cast( buffer.get() ); + r = core::SQLGetData( stmt, field_index + 1, meta.c_type, buffer.get() + already_read + sizeof( SQLULEN ), + to_read - already_read + extra, &last_field_len, false /*handle_warning*/ TSRMLS_CC ); + + // if the field is NULL, then return a NULL pointer + if( last_field_len == SQL_NULL_DATA ) { + return NULL; + } + + // if the last read was successful, we're done + if( r == SQL_SUCCESS ) { + // check to make sure we haven't overflown our memory limit + CHECK_CUSTOM_ERROR( mem_used + last_field_len > stmt->buffered_query_limit * 1024, stmt, + SQLSRV_ERROR_BUFFER_LIMIT_EXCEEDED, stmt->buffered_query_limit ) { + + throw core::CoreException(); + } + break; + } + // else if it wasn't the truncated warning (01004) then we're done + else if( r == SQL_SUCCESS_WITH_INFO ) { + SQLSMALLINT len; + core::SQLGetDiagField( stmt, 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len + TSRMLS_CC ); + + if( !is_truncated_warning( state )) { + break; + } + } + + SQLSRV_ASSERT( SQL_SUCCEEDED( r ), "Unknown SQL error not triggered" ); + + // if the type of the field returns the total to be read, we use that and preallocate the buffer + if( last_field_len != SQL_NO_TOTAL ) { + + CHECK_CUSTOM_ERROR( mem_used + last_field_len > stmt->buffered_query_limit * 1024, stmt, + SQLSRV_ERROR_BUFFER_LIMIT_EXCEEDED, stmt->buffered_query_limit ) { + + throw core::CoreException(); + } + + already_read += to_read - already_read; + to_read = last_field_len; + buffer.resize( to_read + extra + sizeof( SQLULEN )); + output_buffer_len = reinterpret_cast( buffer.get() ); + // record the size of the field since we have it available + *output_buffer_len = last_field_len; + full_length_returned = true; + } + // otherwise allocate another chunk of memory to read in + else { + already_read += to_read - already_read; + to_read *= 2; + CHECK_CUSTOM_ERROR( mem_used + to_read > stmt->buffered_query_limit * 1024, stmt, + SQLSRV_ERROR_BUFFER_LIMIT_EXCEEDED, stmt->buffered_query_limit ) { + + throw core::CoreException(); + } + buffer.resize( to_read + extra + sizeof( SQLULEN )); + output_buffer_len = reinterpret_cast( buffer.get() ); + } + + } while( true ); + + SQLSRV_ASSERT( output_buffer_len != NULL, "Output buffer not allocated properly" ); + + // most LOB field types return the total length in the last_field_len, but some field types such as XML + // only return the amount read on the last read + if( !full_length_returned ) { + *output_buffer_len = already_read + last_field_len; + } + + char* return_buffer = buffer; + buffer.transferred(); + return return_buffer; +} + +} diff --git a/pdo_sqlsrv/core_sqlsrv.h b/pdo_sqlsrv/core_sqlsrv.h index 0a68c04a..108d7de5 100644 --- a/pdo_sqlsrv/core_sqlsrv.h +++ b/pdo_sqlsrv/core_sqlsrv.h @@ -6,7 +6,7 @@ // // Contents: Core routines and constants shared by the Microsoft Drivers for PHP for SQL Server // -// Copyright 2010 Microsoft Corporation +// Copyright Microsoft Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -45,6 +45,10 @@ OACR_WARNING_DISABLE( INDEX_NEGATIVE, "Third party code." ) OACR_WARNING_DISABLE( UNANNOTATED_BUFFER, "Third party code." ) OACR_WARNING_DISABLE( INDEX_UNDERFLOW, "Third party code." ) OACR_WARNING_DISABLE( REALLOCLEAK, "Third party code." ) +OACR_WARNING_DISABLE( ALLOC_SIZE_OVERFLOW_WITH_ACCESS, "Third party code." ) +#else +// define to eliminate static analysis hints in the code +#define OACR_WARNING_SUPPRESS( warning, msg ) #endif extern "C" { @@ -88,8 +92,6 @@ OACR_WARNING_POP #include #include -#include - #if !defined(WC_ERR_INVALID_CHARS) // imported from winnls.h as it isn't included by 5.3.0 #define WC_ERR_INVALID_CHARS 0x00000080 // error for invalid chars @@ -101,8 +103,10 @@ OACR_WARNING_POP #undef inline #endif +#include +#include #include - +#include #include #include @@ -216,10 +220,46 @@ struct sqlsrv_static_assert { static const int value = 1; }; #define SQLSRV_STATIC_ASSERT( c ) (sqlsrv_static_assert<(c) != 0>() ) +//********************************************************************************************************************************* +// Logging +//********************************************************************************************************************************* +// log_callback +// a driver specific callback for logging messages +// severity - severity of the message: notice, warning, or error +// msg - the message to log in a FormatMessage style formatting +// print_args - args to the message +typedef void (*log_callback)( unsigned int severity TSRMLS_DC, const char* msg, va_list* print_args ); + +// each driver must register a log callback. This should be the first thing a driver does. +void core_sqlsrv_register_logger( log_callback ); + +// a simple wrapper around a PHP error logging function. +void write_to_log( unsigned int severity TSRMLS_DC, const char* msg, ... ); + +// a macro to make it convenient to use the function. +#define LOG( severity, msg, ...) write_to_log( severity TSRMLS_CC, msg, __VA_ARGS__ ) + +// mask for filtering which severities are written to the log +enum logging_severity { + SEV_ERROR = 0x01, + SEV_WARNING = 0x02, + SEV_NOTICE = 0x04, + SEV_ALL = -1, +}; + +// Kill the PHP process and log the message to PHP +void die( const char* msg, ... ); +#define DIE( msg, ... ) { die( msg, __VA_ARGS__ ); } + + //********************************************************************************************************************************* // Resource/Memory Management //********************************************************************************************************************************* +// the macro max is defined and overrides the call to max in the allocator class +#pragma push_macro( "max" ) +#undef max + // new memory allocation/free debugging facilities to help us verify that all allocations are being // released in a timely manner and not just at the end of the script. // Zend has memory logging and checking, but it can generate a lot of noise for just one extension. @@ -229,36 +269,89 @@ struct sqlsrv_static_assert { static const int value = 1; }; // #define SQLSRV_MEM_DEBUG 1 #if defined( PHP_DEBUG ) && !defined( ZTS ) && defined( SQLSRV_MEM_DEBUG ) -// macro to log memory allocation and frees locations and their sizes -inline void* emalloc_trace( size_t size, const char* file, int line ) +inline void* sqlsrv_malloc_trace( size_t size, const char* file, int line ) { void* ptr = emalloc( size ); LOG( SEV_NOTICE, "emalloc returned %4!08x!: %1!d! bytes at %2!s!:%3!d!", size, file, line, ptr ); return ptr; } -inline void* erealloc_trace( void* original, size_t size, const char* file, int line ) +inline void* sqlsrv_malloc_trace( size_t element_count, size_t element_size, size_t extra, const char* file, int line ) +{ + OACR_WARNING_SUPPRESS( ALLOC_SIZE_OVERFLOW_IN_ALLOC_WRAPPER, "Overflow verified below" ); + + if(( element_count > 0 && element_size > 0 ) && + ( element_count > element_size * element_count || element_size > element_size * element_count )) { + DIE( "Integer overflow in sqlsrv_malloc" ); + } + + if( element_size * element_count > element_size * element_count + extra ) { + DIE( "Integer overflow in sqlsrv_malloc" ); + } + + if( element_size * element_count + extra == 0 ) { + DIE( "Allocation size must be more than 0" ); + } + + void* ptr = emalloc( element_size * element_count + extra ); + LOG( SEV_NOTICE, "emalloc returned %4!08x!: %1!d! bytes at %2!s!:%3!d!", size, file, line, ptr ); + return ptr; +} + +inline void* sqlsrv_realloc_trace( void* buffer, size_t size, const char* file, int line ) { void* ptr = erealloc( original, size ); LOG( SEV_NOTICE, "erealloc returned %5!08x! from %4!08x!: %1!d! bytes at %2!s!:%3!d!", size, file, line, ptr, original ); return ptr; } -inline void efree_trace( void* ptr, const char* file, int line ) +inline void sqlsrv_free_trace( void* ptr, const char* file, int line ) { LOG( SEV_NOTICE, "efree %1!08x! at %2!s!:%3!d!", ptr, file, line ); efree( ptr ); } -#define sqlsrv_malloc( size ) emalloc_trace( size, __FILE__, __LINE__ ) -#define sqlsrv_realloc( buffer, size ) erealloc_trace( buffer, size, __FILE__, __LINE__ ) -#define sqlsrv_free( ptr ) efree_trace( ptr, __FILE__, __LINE__ ) +#define sqlsrv_malloc( size ) sqlsrv_malloc_trace( size, __FILE__, __LINE__ ) +#define sqlsrv_malloc( count, size, extra ) sqlsrv_malloc_trace( count, size, extra, __FILE__, __LINE__ ) +#define sqlsrv_realloc( buffer, size ) sqlsrv_realloc_trace( buffer, size, __FILE__, __LINE__ ) +#define sqlsrv_free( ptr ) sqlsrv_free_trace( ptr, __FILE__, __LINE__ ) #else -#define sqlsrv_malloc( size ) emalloc( size ) -#define sqlsrv_realloc( buffer, size ) erealloc( buffer, size ) -#define sqlsrv_free( ptr ) efree( ptr ) +inline void* sqlsrv_malloc( size_t size ) +{ + return emalloc( size ); +} + +inline void* sqlsrv_malloc( size_t element_count, size_t element_size, size_t extra ) +{ + OACR_WARNING_SUPPRESS( ALLOC_SIZE_OVERFLOW_IN_ALLOC_WRAPPER, "Overflow verified below" ); + + if(( element_count > 0 && element_size > 0 ) && + ( element_count > element_size * element_count || element_size > element_size * element_count )) { + DIE( "Integer overflow in sqlsrv_malloc" ); + } + + if( element_size * element_count > element_size * element_count + extra ) { + DIE( "Integer overflow in sqlsrv_malloc" ); + } + + if( element_size * element_count + extra == 0 ) { + DIE( "Allocation size must be more than 0" ); + } + + return emalloc( element_size * element_count + extra ); +} + +inline void* sqlsrv_realloc( void* buffer, size_t size ) +{ + return erealloc( buffer, size ); +} + +inline void sqlsrv_free( void* ptr ) +{ + efree( ptr ); +} #endif @@ -273,6 +366,84 @@ struct remove_const { typedef T* type; }; +// allocator that uses the zend memory manager to manage memory +// this allows us to use STL classes that still work with Zend objects +template +struct sqlsrv_allocator { + + // typedefs used by the STL classes + typedef T value_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + // conversion typedef (used by list and other STL classes) + template + struct rebind { + typedef sqlsrv_allocator other; + }; + + inline sqlsrv_allocator() {} + inline ~sqlsrv_allocator() {} + inline sqlsrv_allocator( sqlsrv_allocator const& ) {} + template + inline sqlsrv_allocator( sqlsrv_allocator const& ) {} + + // address (doesn't work if the class defines operator&) + inline pointer address( reference r ) + { + return &r; + } + + inline const_pointer address( const_reference r ) + { + return &r; + } + + // memory allocation/deallocation + inline pointer allocate( size_type cnt, + typename std::allocator::const_pointer = 0 ) + { + return reinterpret_cast( sqlsrv_malloc(cnt, sizeof (T), 0)); + } + + inline void deallocate( pointer p, size_type ) + { + sqlsrv_free(p); + } + + // size + inline size_type max_size( void ) const + { + return std::numeric_limits::max() / sizeof(T); + } + + // object construction/destruction + inline void construct( pointer p, const T& t ) + { + new(p) T(t); + } + + inline void destroy(pointer p) + { + p->~T(); + } + + // equality operators + inline bool operator==( sqlsrv_allocator const& ) + { + return true; + } + + inline bool operator!=( sqlsrv_allocator const& a ) + { + return !operator==(a); + } +}; + // base class for auto_ptrs that we define below. It provides common operators and functions // used by all the classes. @@ -398,6 +569,8 @@ protected: // in a variable of sqlsrv_malloc_auto_ptr. sqlsrv_malloc_auto_ptr will "own" that block and assure that it is // freed until the variable is destroyed (out of scope) or ownership is transferred using the function // "transferred". +// DO NOT CALL sqlsrv_realloc with a sqlsrv_malloc_auto_ptr. Use the resize member function. + template class sqlsrv_malloc_auto_ptr : public sqlsrv_auto_ptr > { @@ -432,6 +605,13 @@ public: src.transferred(); this->_ptr = p; } + + // DO NOT CALL sqlsrv_realloc with a sqlsrv_malloc_auto_ptr. Use the resize member function. + // has the same parameter list as sqlsrv_realloc: new_size is the size in bytes of the newly allocated buffer + void resize( size_t new_size ) + { + _ptr = reinterpret_cast( sqlsrv_realloc( _ptr, new_size )); + } }; @@ -507,6 +687,9 @@ private: zval_auto_ptr( const zval_auto_ptr& src ); }; +#pragma pop_macro( "max" ) + + //********************************************************************************************************************************* // sqlsrv_error //********************************************************************************************************************************* @@ -546,6 +729,11 @@ struct sqlsrv_error : public sqlsrv_error_const { format = printf_format; } + sqlsrv_error( sqlsrv_error_const const& prototype ) + { + sqlsrv_error( prototype.sqlstate, prototype.native_message, prototype.native_code, prototype.format ); + } + ~sqlsrv_error( void ) { if( sqlstate != NULL ) { @@ -816,6 +1004,7 @@ enum SQLSRV_STMT_OPTIONS { SQLSRV_STMT_OPTION_QUERY_TIMEOUT, SQLSRV_STMT_OPTION_SEND_STREAMS_AT_EXEC, SQLSRV_STMT_OPTION_SCROLLABLE, + SQLSRV_STMT_OPTION_CLIENT_BUFFER_MAX_SIZE, // Driver specific connection options SQLSRV_STMT_OPTION_DRIVER_SPECIFIC = 1000, @@ -825,6 +1014,8 @@ enum SQLSRV_STMT_OPTIONS { namespace ODBCConnOptions { const char APP[] = "APP"; +const char ApplicationIntent[] = "ApplicationIntent"; +const char AttachDBFileName[] = "AttachDbFileName"; const char CharacterSet[] = "CharacterSet"; const char ConnectionPooling[] = "ConnectionPooling"; const char Database[] = "Database"; @@ -832,6 +1023,7 @@ const char Encrypt[] = "Encrypt"; const char Failover_Partner[] = "Failover_Partner"; const char LoginTimeout[] = "LoginTimggeout"; const char MARS_ODBC[] = "MARS_Connection"; +const char MultiSubnetFailover[] = "MultiSubnetFailover"; const char QuotedId[] = "QuotedId"; const char TraceFile[] = "TraceFile"; const char TraceOn[] = "TraceOn"; @@ -861,6 +1053,9 @@ enum SQLSRV_CONN_OPTIONS { SQLSRV_CONN_OPTION_TRANS_ISOLATION, SQLSRV_CONN_OPTION_TRUST_SERVER_CERT, SQLSRV_CONN_OPTION_WSID, + SQLSRV_CONN_OPTION_ATTACHDBFILENAME, + SQLSRV_CONN_OPTION_APPLICATION_INTENT, + SQLSRV_CONN_OPTION_MULTI_SUBNET_FAILOVER, // Driver specific connection options SQLSRV_CONN_OPTION_DRIVER_SPECIFIC = 1000, @@ -963,6 +1158,11 @@ struct stmt_option_send_at_exec : public stmt_option_functor { virtual void operator()( sqlsrv_stmt* stmt, stmt_option const* opt, zval* value_z TSRMLS_DC ); }; +struct stmt_option_buffered_query_limit : public stmt_option_functor { + + virtual void operator()( sqlsrv_stmt* stmt, stmt_option const* opt, zval* value_z TSRMLS_DC ); +}; + // used to hold the table for statment options struct stmt_option { @@ -1029,25 +1229,28 @@ struct sqlsrv_output_param { } }; +// forward decls +struct sqlsrv_result_set; + // *** Statement resource structure *** struct sqlsrv_stmt : public sqlsrv_context { void free_param_data( TSRMLS_D ); - virtual void new_result_set( void ); + virtual void new_result_set( TSRMLS_D ); sqlsrv_conn* conn; // Connection that created this statement bool executed; // Whether the statement has been executed yet (used for error messages) bool past_fetch_end; // Core_sqlsrv_fetch sets this field when the statement goes beyond the last row - bool scrollable; // Determines if the statement was created with the Scrollable query attribute - // (don't have to use ODBC to find out) - bool scroll_is_dynamic; // if scrollable, is it a dynamic cursor. + sqlsrv_result_set* current_results; // Current result set + SQLULEN cursor_type; // Type of cursor for the current result set bool has_rows; // Has_rows is set if there are actual rows in the row set bool fetch_called; // Used by core_sqlsrv_get_field to return an informative error if fetch not yet called int last_field_index; // last field retrieved by core_sqlsrv_get_field bool past_next_result_end; // core_sqlsrv_next_result sets this to true when the statement goes beyond the // last results unsigned long query_timeout; // maximum allowed statement execution time + unsigned long buffered_query_limit; // maximum allowed memory for a buffered query (measured in KB) // holds output pointers for SQLBindParameter // We use a deque because it 1) provides the at/[] access in constant time, and 2) grows dynamically without moving @@ -1101,6 +1304,9 @@ const int SQLSRV_DEFAULT_SIZE = -1; // size given for an output parameter th // uninitialized query timeout value const unsigned int QUERY_TIMEOUT_INVALID = 0xffffffff; +// special buffered query constant +const size_t SQLSRV_CURSOR_BUFFERED = 0xfffffffeUL; // arbitrary number that doesn't map to any other SQL_CURSOR_* constant + // factory to create a statement typedef sqlsrv_stmt* (*driver_stmt_factory)( sqlsrv_conn* conn, SQLHANDLE h, error_callback e, void* drv TSRMLS_DC ); @@ -1117,42 +1323,181 @@ void core_sqlsrv_get_field( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_ __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 ); +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, unsigned int paramno, zval* param_z TSRMLS_DC ); void core_sqlsrv_set_scrollable( sqlsrv_stmt* stmt, unsigned int cursor_type TSRMLS_DC ); void core_sqlsrv_set_query_timeout( sqlsrv_stmt* stmt, long timeout TSRMLS_DC ); void core_sqlsrv_set_query_timeout( sqlsrv_stmt* stmt, zval* value_z TSRMLS_DC ); 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, long limit TSRMLS_DC ); //********************************************************************************************************************************* -// Logging +// Result Set //********************************************************************************************************************************* -// log_callback -// a driver specific callback for logging messages -// severity - severity of the message: notice, warning, or error -// msg - the message to log in a FormatMessage style formatting -// print_args - args to the message -typedef void (*log_callback)( unsigned int severity TSRMLS_DC, const char* msg, va_list* print_args ); -// each driver must register a log callback. This should be the first thing a driver does. -void core_sqlsrv_register_logger( log_callback ); +// Abstract the result set so that a result set can either be used as is from ODBC or buffered. +// This is not a complete abstraction of a result set. Only enough is abstracted to allow for +// information and capabilities normally not available when a result set is not buffered +// (e.g., forward only vs buffered means row count is available and cursor movement is possible). +// Otherwise, normal ODBC calls are still valid and should be used to get information about the +// result set (e.g., SQLNumResultCols). -// a simple wrapper around a PHP error logging function. -void write_to_log( unsigned int severity TSRMLS_DC, const char* msg, ... ); +struct sqlsrv_result_set { -// a macro to make it convenient to use the function. -#define LOG( severity, msg, ...) write_to_log( severity TSRMLS_CC, msg, __VA_ARGS__ ) + sqlsrv_stmt* odbc; -// mask for filtering which severities are written to the log -enum logging_severity { - SEV_ERROR = 0x01, - SEV_WARNING = 0x02, - SEV_NOTICE = 0x04, - SEV_ALL = -1, + explicit sqlsrv_result_set( sqlsrv_stmt* ); + virtual ~sqlsrv_result_set( void ) { } + + virtual bool cached( int field_index ) = 0; + virtual SQLRETURN fetch( SQLSMALLINT fetch_orientation, SQLLEN fetch_offset TSRMLS_DC ) = 0; + virtual SQLRETURN get_data( SQLUSMALLINT field_index, SQLSMALLINT target_type, + __out void* buffer, SQLLEN buffer_length, __out SQLLEN* out_buffer_length, + bool handle_warning TSRMLS_DC )= 0; + virtual SQLRETURN get_diag_field( SQLSMALLINT record_number, SQLSMALLINT diag_identifier, + __out SQLPOINTER diag_info_buffer, SQLSMALLINT buffer_length, + __out SQLSMALLINT* out_buffer_length TSRMLS_DC ) = 0; + virtual sqlsrv_error* get_diag_rec( SQLSMALLINT record_number ) = 0; + virtual SQLLEN row_count( TSRMLS_D ) = 0; }; +struct sqlsrv_odbc_result_set : public sqlsrv_result_set { + + explicit sqlsrv_odbc_result_set( sqlsrv_stmt* ); + virtual ~sqlsrv_odbc_result_set( void ); + + virtual bool cached( int field_index ) { return false; } + virtual SQLRETURN fetch( SQLSMALLINT fetch_orientation, SQLLEN fetch_offset TSRMLS_DC ); + virtual SQLRETURN get_data( SQLUSMALLINT field_index, SQLSMALLINT target_type, + __out void* buffer, SQLLEN buffer_length, __out SQLLEN* out_buffer_length, + bool handle_warning TSRMLS_DC ); + virtual SQLRETURN get_diag_field( SQLSMALLINT record_number, SQLSMALLINT diag_identifier, + __out SQLPOINTER diag_info_buffer, SQLSMALLINT buffer_length, + __out SQLSMALLINT* out_buffer_length TSRMLS_DC ); + virtual sqlsrv_error* get_diag_rec( SQLSMALLINT record_number ); + virtual SQLLEN row_count( TSRMLS_D ); + + private: + // prevent invalid instantiations and assignments + sqlsrv_odbc_result_set( void ); + sqlsrv_odbc_result_set( sqlsrv_odbc_result_set& ); + sqlsrv_odbc_result_set& operator=( sqlsrv_odbc_result_set& ); +}; + +struct sqlsrv_buffered_result_set : public sqlsrv_result_set { + + struct meta_data { + SQLSMALLINT type; + SQLSMALLINT c_type; // convenience + SQLULEN offset; // in bytes + SQLULEN length; // in bytes + SQLSMALLINT scale; + + static const SQLULEN SIZE_UNKNOWN = 0; + }; + + // default maximum amount of memory that a buffered query can consume + #define INI_BUFFERED_QUERY_LIMIT_DEFAULT "10240" // default used by the php.ini settings + static const unsigned long BUFFERED_QUERY_LIMIT_DEFAULT = 10240; // measured in KB + static const long BUFFERED_QUERY_LIMIT_INVALID = 0; + + explicit sqlsrv_buffered_result_set( sqlsrv_stmt* odbc TSRMLS_DC ); + virtual ~sqlsrv_buffered_result_set( void ); + + virtual bool cached( int field_index ) { return true; } + virtual SQLRETURN fetch( SQLSMALLINT fetch_orientation, SQLLEN fetch_offset TSRMLS_DC ); + virtual SQLRETURN get_data( SQLUSMALLINT field_index, SQLSMALLINT target_type, + __out void* buffer, SQLLEN buffer_length, __out SQLLEN* out_buffer_length, + bool handle_warning TSRMLS_DC ); + virtual SQLRETURN get_diag_field( SQLSMALLINT record_number, SQLSMALLINT diag_identifier, + __out SQLPOINTER diag_info_buffer, SQLSMALLINT buffer_length, + __out SQLSMALLINT* out_buffer_length TSRMLS_DC ); + virtual sqlsrv_error* get_diag_rec( SQLSMALLINT record_number ); + virtual SQLLEN row_count( TSRMLS_D ); + + // buffered result set specific + SQLSMALLINT column_count( void ) + { + return col_count; + } + + struct meta_data& col_meta_data( SQLSMALLINT i ) + { + return meta[i]; + } + + private: + // prevent invalid instantiations and assignments + sqlsrv_buffered_result_set( void ); + sqlsrv_buffered_result_set( sqlsrv_buffered_result_set& ); + sqlsrv_buffered_result_set& operator=( sqlsrv_buffered_result_set& ); + + HashTable* cache; // rows of data kept in index based hash table + SQLSMALLINT col_count; // number of columns in the current result set + meta_data* meta; // metadata for fields in the cache + SQLLEN current; // 1 based, 0 means before first row + sqlsrv_error_auto_ptr last_error; // if an error occurred, it is kept here + SQLUSMALLINT last_field_index; // the last field data retrieved from + SQLLEN read_so_far; // position within string to read from (for partial reads of strings) + sqlsrv_malloc_auto_ptr temp_string; // temp buffer to hold a converted field while in use + SQLLEN temp_length; // number of bytes in the temp conversion buffer + + typedef SQLRETURN (sqlsrv_buffered_result_set::*conv_fn)( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ); + typedef std::map< SQLINTEGER, std::map< SQLINTEGER, conv_fn > > conv_matrix_t; + + // two dimentional sparse matrix that holds the [from][to] functions that do conversions + static conv_matrix_t conv_matrix; + + // string conversion functions + SQLRETURN binary_to_wide_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ); + SQLRETURN binary_to_system_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ); + SQLRETURN system_to_wide_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ); + SQLRETURN to_binary_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ); + SQLRETURN to_same_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ); + SQLRETURN wide_to_system_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ); + + // long conversion functions + SQLRETURN to_long( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, __out SQLLEN* out_buffer_length ); + SQLRETURN long_to_system_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ); + SQLRETURN long_to_wide_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ); + SQLRETURN long_to_double( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ); + + // double conversion functions + SQLRETURN to_double( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, __out SQLLEN* out_buffer_length ); + SQLRETURN double_to_system_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ); + SQLRETURN double_to_wide_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ); + SQLRETURN double_to_long( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ); + + // string to number conversion functions + // Future: See if these can be converted directly to template member functions + SQLRETURN string_to_double( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ); + SQLRETURN string_to_long( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ); + SQLRETURN wstring_to_double( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ); + SQLRETURN wstring_to_long( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ); + + // utility functions for conversions + unsigned char* get_row( void ); +}; //********************************************************************************************************************************* // Utility @@ -1205,7 +1550,7 @@ enum SQLSRV_ERROR_CODES { SQLSRV_ERROR_INVALID_CONNECTION_KEY, SQLSRV_ERROR_MAX_PARAMS_EXCEEDED, SQLSRV_ERROR_INVALID_OPTION_KEY, - SQLSRV_ERROR_INVALID_OPTION_VALUE, + SQLSRV_ERROR_INVALID_QUERY_TIMEOUT_VALUE, SQLSRV_ERROR_INVALID_OPTION_SCROLLABLE, SQLSRV_ERROR_QUERY_STRING_ENCODING_TRANSLATE, SQLSRV_ERROR_OUTPUT_PARAM_TRUNCATED, @@ -1215,6 +1560,8 @@ enum SQLSRV_ERROR_CODES { SQLSRV_ERROR_STREAM_CREATE, SQLSRV_ERROR_MARS_OFF, SQLSRV_ERROR_FIELD_INDEX_ERROR, + SQLSRV_ERROR_BUFFER_LIMIT_EXCEEDED, + SQLSRV_ERROR_INVALID_BUFFER_LIMIT, // Driver specific error codes starts from here. SQLSRV_ERROR_DRIVER_SPECIFIC = 1000, @@ -1222,7 +1569,8 @@ enum SQLSRV_ERROR_CODES { }; // the message returned by SQL Native Client -const char CONNECTION_BUSY_ODBC_ERROR[] = "[Microsoft][SQL Server Native Client 10.0]Connection is busy with results for another command"; +const char CONNECTION_BUSY_ODBC_ERROR[] = "[Microsoft][SQL Server Native Client 11.0]Connection is busy with results for " + "another command"; // SQLSTATE for all internal errors extern SQLCHAR IMSSP[]; @@ -1244,11 +1592,12 @@ enum error_handling_flags { // 2/code) driver specific error code // 3/message) driver specific error message // The fetch type determines if the indices are numeric, associative, or both. -bool core_sqlsrv_get_odbc_error( sqlsrv_context& ctx, int record_number, sqlsrv_error* error, logging_severity severity TSRMLS_DC ); +bool core_sqlsrv_get_odbc_error( sqlsrv_context& ctx, int record_number, __out sqlsrv_error_auto_ptr& error, + logging_severity severity TSRMLS_DC ); // format and return a driver specfic error void core_sqlsrv_format_driver_error( sqlsrv_context& ctx, sqlsrv_error_const const* custom_error, - sqlsrv_error* formatted_error, logging_severity severity TSRMLS_DC, va_list* args ); + sqlsrv_error_auto_ptr& formatted_error, logging_severity severity TSRMLS_DC, va_list* args ); // return the message for the HRESULT returned by GetLastError. Some driver errors use this to @@ -1278,10 +1627,6 @@ inline bool call_error_handler( sqlsrv_context* ctx, unsigned int sqlsrv_error_c return ignored; } -// Kill the PHP process and log the message to PHP -void die( const char* msg, ... ); -#define DIE( msg, ... ) { die( msg, __VA_ARGS__ ); } - // PHP equivalent of ASSERT. C asserts cause a dialog to show and halt the process which // we don't want on a web server @@ -1300,7 +1645,6 @@ void die( const char* msg, ... ); #endif - // check to see if the sqlstate is 01004, truncated field retrieved. Used for retrieving large fields. inline bool is_truncated_warning( SQLCHAR* state ) { diff --git a/pdo_sqlsrv/core_stmt.cpp b/pdo_sqlsrv/core_stmt.cpp index 4d250820..76b831d0 100644 --- a/pdo_sqlsrv/core_stmt.cpp +++ b/pdo_sqlsrv/core_stmt.cpp @@ -3,7 +3,7 @@ // // Contents: Core routines that use statement handles shared between sqlsrv and pdo_sqlsrv // -// Copyright 2010 Microsoft Corporation +// Copyright Microsoft Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -28,8 +28,10 @@ struct field_cache { void* value; SQLLEN len; + sqlsrv_phptype type; - field_cache( void* field_value, SQLLEN field_len ) + field_cache( void* field_value, SQLLEN field_len, sqlsrv_phptype t ) + : type( t ) { // if the value is NULL, then just record a NULL pointer if( field_value != NULL ) { @@ -105,7 +107,6 @@ void send_param_streams( sqlsrv_stmt* stmt TSRMLS_DC ); void sqlsrv_output_param_dtor( void* data ); // called when a bound stream parameter is to be destroyed. void sqlsrv_stream_dtor( void* data ); -sqlsrv_phptype sql_type_to_php_type( sqlsrv_stmt const* stmt, SQLINTEGER sql_type, SQLUINTEGER size, bool prefer_string ); bool is_streamable_type( SQLINTEGER sql_type ); } @@ -116,7 +117,8 @@ sqlsrv_stmt::sqlsrv_stmt( sqlsrv_conn* c, SQLHANDLE handle, error_callback e, vo conn( c ), executed( false ), past_fetch_end( false ), - scrollable( false ), + current_results( NULL ), + cursor_type( SQL_CURSOR_FORWARD_ONLY ), has_rows( false ), fetch_called( false ), last_field_index( -1 ), @@ -126,6 +128,7 @@ 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 ) { // initialize the input string parameters array (which holds zvals) @@ -165,6 +168,14 @@ sqlsrv_stmt::~sqlsrv_stmt( void ) TSRMLS_FETCH(); close_active_stream( this TSRMLS_CC ); } + + // delete any current results + if( current_results ) { + current_results->~sqlsrv_result_set(); + efree( current_results ); + current_results = NULL; + } + invalidate(); zval_ptr_dtor( ¶m_input_strings ); zval_ptr_dtor( &output_params ); @@ -192,13 +203,28 @@ void sqlsrv_stmt::free_param_data( TSRMLS_D ) // to be called whenever a new result set is created, such as after an // execute or next_result. Resets the state variables. -void sqlsrv_stmt::new_result_set( void ) +void sqlsrv_stmt::new_result_set( TSRMLS_D ) { this->fetch_called = false; this->has_rows = false; this->past_next_result_end = false; this->past_fetch_end = false; this->last_field_index = -1; + + // delete any current results + if( current_results ) { + current_results->~sqlsrv_result_set(); + efree( current_results ); + current_results = NULL; + } + + // create a new result set + if( cursor_type == SQLSRV_CURSOR_BUFFERED ) { + current_results = new (sqlsrv_malloc( sizeof( sqlsrv_buffered_result_set ))) sqlsrv_buffered_result_set( this TSRMLS_CC ); + } + else { + current_results = new (sqlsrv_malloc( sizeof( sqlsrv_odbc_result_set ))) sqlsrv_odbc_result_set( this ); + } } // core_sqlsrv_create_stmt @@ -247,16 +273,15 @@ sqlsrv_stmt* core_sqlsrv_create_stmt( sqlsrv_conn* conn, driver_stmt_factory stm int type = zend_hash_get_current_key_ex( options_ht, &key, &key_len, &index, 0, NULL ); // The driver layer should ensure a valid key. - SQLSRV_ASSERT( (type == HASH_KEY_IS_LONG), "allocate_stmt: Invalid statment option key provided" ); + 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, (void**) &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 - if( !stmt_opt ) { - THROW_CORE_ERROR( stmt->conn, SQLSRV_ERROR_INVALID_OPTION_KEY ); - } + // 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 ); @@ -273,6 +298,8 @@ sqlsrv_stmt* core_sqlsrv_create_stmt( sqlsrv_conn* conn, driver_stmt_factory stm catch( core::CoreException& ) { if( stmt ) { + + conn->set_last_error( stmt->last_error() ); stmt->~sqlsrv_stmt(); } @@ -321,7 +348,7 @@ void core_sqlsrv_bind_param( sqlsrv_stmt* stmt, unsigned int param_num, int dire try { // check is only < because params are 0 based - CHECK_CUSTOM_ERROR( param_num >= SQL_SERVER_MAX_PARAMS, stmt, SQLSRV_ERROR_MAX_PARAMS_EXCEEDED, param_num ) { + CHECK_CUSTOM_ERROR( param_num >= SQL_SERVER_MAX_PARAMS, stmt, SQLSRV_ERROR_MAX_PARAMS_EXCEEDED, param_num + 1 ) { throw core::CoreException(); } @@ -498,6 +525,27 @@ void core_sqlsrv_bind_param( sqlsrv_stmt* stmt, unsigned int param_num, int dire // save the parameter to be adjusted and/or converted after the results are processed sqlsrv_output_param output_param( param_z, encoding, param_num, buffer_len ); save_output_param_for_later( stmt, output_param TSRMLS_CC ); + + // For output parameters, if we set the column_size to be same as the buffer_len, + // than if there is a truncation due to the data coming from the server being + // greater than the column_size, we don't get any truncation error. In order to + // avoid this silent truncation, we set the column_size to be "MAX" size for + // string types. This will guarantee that there is no silent truncation for + // output parameters. + if( direction == SQL_PARAM_OUTPUT ) { + + switch( sql_type ) { + + case SQL_VARBINARY: + case SQL_VARCHAR: + case SQL_WVARCHAR: + column_size = SQL_SS_LENGTH_UNLIMITED; + break; + + default: + break; + } + } } break; case IS_RESOURCE: @@ -516,22 +564,33 @@ void core_sqlsrv_bind_param( sqlsrv_stmt* stmt, unsigned int param_num, int dire case IS_OBJECT: { SQLSRV_ASSERT( direction == SQL_PARAM_INPUT, "Invalid output param type. The driver layer should catch this." ); - sqlsrv_malloc_auto_ptr class_name; - zend_uint class_name_len; zval_auto_ptr function_z; zval_auto_ptr buffer_z; zval_auto_ptr format_z; zval* params[1]; + bool valid_class_name_found = false; - int zr = zend_get_object_classname( param_z, &class_name, &class_name_len TSRMLS_CC ); - CHECK_CUSTOM_ERROR( zr == FAILURE, stmt, SQLSRV_ERROR_INVALID_PARAMETER_PHPTYPE, param_num + 1 ) { - throw core::CoreException(); - } - CHECK_CUSTOM_ERROR( class_name_len != DateTime::DATETIME_CLASS_NAME_LEN || - stricmp( class_name, DateTime::DATETIME_CLASS_NAME ), - stmt, SQLSRV_ERROR_INVALID_PARAMETER_PHPTYPE, param_num + 1 ) { + zend_class_entry *class_entry = zend_get_class_entry( param_z TSRMLS_CC ); + + while( class_entry != NULL ) { + + if( class_entry->name_length == DateTime::DATETIME_CLASS_NAME_LEN && class_entry->name != NULL && + stricmp( class_entry->name, DateTime::DATETIME_CLASS_NAME ) == 0 ) { + valid_class_name_found = true; + break; + } + + else { + + // Check the parent + class_entry = class_entry->parent; + } + } + + CHECK_CUSTOM_ERROR( !valid_class_name_found, stmt, SQLSRV_ERROR_INVALID_PARAMETER_PHPTYPE, param_num + 1 ) { throw core::CoreException(); } + ALLOC_INIT_ZVAL( buffer_z ); ALLOC_INIT_ZVAL( function_z ); ALLOC_INIT_ZVAL( format_z ); @@ -554,7 +613,7 @@ void core_sqlsrv_bind_param( sqlsrv_stmt* stmt, unsigned int param_num, int dire params[0] = format_z; // This is equivalent to the PHP code: $param_z->format( $format_z ); where param_z is the // DateTime object and $format_z is the format string. - zr = call_user_function( EG( function_table ), ¶m_z, function_z, buffer_z, 1, params TSRMLS_CC ); + int zr = call_user_function( EG( function_table ), ¶m_z, function_z, buffer_z, 1, params TSRMLS_CC ); CHECK_CUSTOM_ERROR( zr == FAILURE, stmt, SQLSRV_ERROR_INVALID_PARAMETER_PHPTYPE, param_num + 1 ) { throw core::CoreException(); } @@ -602,6 +661,8 @@ void core_sqlsrv_bind_param( sqlsrv_stmt* stmt, unsigned int param_num, int dire void core_sqlsrv_execute( sqlsrv_stmt* stmt TSRMLS_DC, const char* sql, int sql_len ) { + try { + // close the stream to release the resource close_active_stream( stmt TSRMLS_CC ); @@ -632,7 +693,7 @@ void core_sqlsrv_execute( sqlsrv_stmt* stmt TSRMLS_DC, const char* sql, int sql_ r = core::SQLExecute( stmt TSRMLS_CC ); } - stmt->new_result_set(); + stmt->new_result_set( TSRMLS_C ); stmt->executed = true; // if data is needed (streams were bound) and they should be sent at execute time, then do so now @@ -646,6 +707,19 @@ void core_sqlsrv_execute( sqlsrv_stmt* stmt TSRMLS_DC, const char* sql, int sql_ finalize_output_parameters( stmt TSRMLS_CC ); } + + } + catch( core::CoreException& e ) { + + // if the statement executed but failed in a subsequent operation before returning, + // we need to cancel the statement + if( stmt->executed ) { + SQLCancel( stmt->handle() ); + // stmt->executed = false; should this be reset if something fails? + } + + throw e; + } } @@ -689,20 +763,19 @@ bool core_sqlsrv_fetch( sqlsrv_stmt* stmt, SQLSMALLINT fetch_orientation, SQLLEN // if the statement has rows and is not scrollable but doesn't yet have // fetch_called, this must be the first time we've called sqlsrv_fetch. - if( !stmt->scrollable && stmt->has_rows && !stmt->fetch_called ) { + if( stmt->cursor_type == SQL_CURSOR_FORWARD_ONLY && stmt->has_rows && !stmt->fetch_called ) { stmt->fetch_called = true; return true; } // move to the record requested. For absolute records, we use a 0 based offset, so +1 since // SQLFetchScroll uses a 1 based offset, otherwise for relative, just use the fetch_offset provided. - SQLRETURN r = core::SQLFetchScroll( stmt, fetch_orientation, - ( fetch_orientation == SQL_FETCH_RELATIVE ) ? fetch_offset : fetch_offset + 1 - TSRMLS_CC ); - + SQLRETURN r = stmt->current_results->fetch( fetch_orientation, + ( fetch_orientation == SQL_FETCH_RELATIVE ) ? fetch_offset : fetch_offset + 1 + TSRMLS_CC ); if( r == SQL_NO_DATA ) { // if this is a forward only cursor, mark that we've passed the end so future calls result in an error - if( !stmt->scrollable ) { + if( stmt->cursor_type == SQL_CURSOR_FORWARD_ONLY ) { stmt->past_fetch_end = true; } return false; @@ -812,13 +885,18 @@ void core_sqlsrv_get_field( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_ 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 + 1 ); + *field_value = sqlsrv_malloc( cached->len, sizeof( char ), 1 ); memcpy( *field_value, cached->value, cached->len ); - reinterpret_cast( *field_value )[ cached->len ] = '\0'; // prevent the 'string not null terminated' warning + if( cached->type.typeinfo.type == SQLSRV_PHPTYPE_STRING ) { + // prevent the 'string not null terminated' warning + reinterpret_cast( *field_value )[ cached->len ] = '\0'; + } *field_len = cached->len; + if( sqlsrv_php_type_out ) { *sqlsrv_php_type_out = static_cast( cached->type.typeinfo.type ); } } return; } @@ -878,7 +956,7 @@ void core_sqlsrv_get_field( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_ // if the user wants us to cache the field, we'll do it if( cache_field ) { - field_cache cache( *field_value, *field_len ); + field_cache cache( *field_value, *field_len, sqlsrv_php_type ); core::sqlsrv_zend_hash_index_update( *stmt, Z_ARRVAL_P( stmt->field_cache ), field_index, &cache, sizeof( field_cache ) TSRMLS_CC ); } @@ -913,7 +991,7 @@ bool core_sqlsrv_has_any_result( sqlsrv_stmt* stmt TSRMLS_DC ) // Returns // Nothing, exception thrown if problem occurs -void core_sqlsrv_next_result( sqlsrv_stmt* stmt TSRMLS_DC, bool finalize_output_params ) +void core_sqlsrv_next_result( sqlsrv_stmt* stmt TSRMLS_DC, bool finalize_output_params, bool throw_on_errors ) { try { @@ -928,7 +1006,13 @@ void core_sqlsrv_next_result( sqlsrv_stmt* stmt TSRMLS_DC, bool finalize_output_ close_active_stream( stmt TSRMLS_CC ); - SQLRETURN r = core::SQLMoreResults( stmt TSRMLS_CC ); + SQLRETURN r; + if( throw_on_errors ) { + r = core::SQLMoreResults( stmt TSRMLS_CC ); + } + else { + r = SQLMoreResults( stmt->handle() ); + } if( r == SQL_NO_DATA ) { @@ -942,7 +1026,7 @@ void core_sqlsrv_next_result( sqlsrv_stmt* stmt TSRMLS_DC, bool finalize_output_ return; } - stmt->new_result_set(); + stmt->new_result_set( TSRMLS_C ); } catch( core::CoreException& e ) { @@ -991,42 +1075,62 @@ void core_sqlsrv_set_scrollable( sqlsrv_stmt* stmt, unsigned int cursor_type TSR case SQL_CURSOR_STATIC: core::SQLSetStmtAttr( stmt, SQL_ATTR_CURSOR_TYPE, reinterpret_cast( SQL_CURSOR_STATIC ), SQL_IS_UINTEGER TSRMLS_CC ); - stmt->scrollable = true; - stmt->scroll_is_dynamic = false; break; case SQL_CURSOR_DYNAMIC: core::SQLSetStmtAttr( stmt, SQL_ATTR_CURSOR_TYPE, reinterpret_cast( SQL_CURSOR_DYNAMIC ), SQL_IS_UINTEGER TSRMLS_CC ); - stmt->scrollable = true; - stmt->scroll_is_dynamic = true; // this cursor is dynamic break; case SQL_CURSOR_KEYSET_DRIVEN: core::SQLSetStmtAttr( stmt, SQL_ATTR_CURSOR_TYPE, reinterpret_cast( SQL_CURSOR_KEYSET_DRIVEN ), SQL_IS_UINTEGER TSRMLS_CC ); - stmt->scrollable = true; - stmt->scroll_is_dynamic = false; break; case SQL_CURSOR_FORWARD_ONLY: core::SQLSetStmtAttr( stmt, SQL_ATTR_CURSOR_TYPE, reinterpret_cast( SQL_CURSOR_FORWARD_ONLY ), SQL_IS_UINTEGER TSRMLS_CC ); - stmt->scrollable = false; // reset since forward isn't scrollable - stmt->scroll_is_dynamic = false; + break; + + case SQLSRV_CURSOR_BUFFERED: + core::SQLSetStmtAttr( stmt, SQL_ATTR_CURSOR_TYPE, + reinterpret_cast( SQL_CURSOR_FORWARD_ONLY ), SQL_IS_UINTEGER TSRMLS_CC ); break; default: THROW_CORE_ERROR( stmt, SQLSRV_ERROR_INVALID_OPTION_SCROLLABLE ); break; } + + stmt->cursor_type = cursor_type; + } - catch( core::CoreException& ) { throw; } } +void core_sqlsrv_set_buffered_query_limit( sqlsrv_stmt* stmt, zval* value_z TSRMLS_DC ) +{ + if( Z_TYPE_P( value_z ) != IS_LONG ) { + + THROW_CORE_ERROR( stmt, SQLSRV_ERROR_INVALID_BUFFER_LIMIT ); + } + + core_sqlsrv_set_buffered_query_limit( stmt, Z_LVAL_P( value_z ) TSRMLS_CC ); +} + +void core_sqlsrv_set_buffered_query_limit( sqlsrv_stmt* stmt, long limit TSRMLS_DC ) +{ + if( limit <= 0 ) { + + THROW_CORE_ERROR( stmt, SQLSRV_ERROR_INVALID_BUFFER_LIMIT ); + } + + stmt->buffered_query_limit = limit; +} + + // Overloaded. Extracts the long value and calls the core_sqlsrv_set_query_timeout // which accepts timeout parameter as a long. If the zval is not of type long // than throws error. @@ -1038,7 +1142,7 @@ void core_sqlsrv_set_query_timeout( sqlsrv_stmt* stmt, zval* value_z TSRMLS_DC ) if( Z_TYPE_P( value_z ) != IS_LONG || Z_LVAL_P( value_z ) < 0 ) { convert_to_string( value_z ); - THROW_CORE_ERROR( stmt, SQLSRV_ERROR_INVALID_OPTION_VALUE, Z_STRVAL_P( value_z ) ); + THROW_CORE_ERROR( stmt, SQLSRV_ERROR_INVALID_QUERY_TIMEOUT_VALUE, Z_STRVAL_P( value_z ) ); } core_sqlsrv_set_query_timeout( stmt, Z_LVAL_P( value_z ) TSRMLS_CC ); @@ -1214,6 +1318,11 @@ void stmt_option_send_at_exec:: operator()( sqlsrv_stmt* stmt, stmt_option const core_sqlsrv_set_send_at_exec( stmt, value_z TSRMLS_CC ); } +void stmt_option_buffered_query_limit:: operator()( sqlsrv_stmt* stmt, stmt_option const* /*opt*/, zval* value_z TSRMLS_DC ) +{ + core_sqlsrv_set_buffered_query_limit( stmt, value_z TSRMLS_CC ); +} + // internal function to release the active stream. Called by each main API function // that will alter the statement and cancel any retrieval of data from a stream. @@ -1382,9 +1491,13 @@ void core_get_field_common( __inout sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_malloc_auto_ptr field_value_temp; field_value_temp = static_cast( sqlsrv_malloc( sizeof( long ))); - SQLRETURN r = core::SQLGetData( stmt, field_index + 1, SQL_C_LONG, field_value_temp, 0, - field_len, true /*handle_warning*/ TSRMLS_CC ); + 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(); + } + CHECK_CUSTOM_ERROR( (r == SQL_NO_DATA), stmt, SQLSRV_ERROR_NO_DATA, field_index ) { throw core::CoreException(); } @@ -1404,9 +1517,13 @@ void core_get_field_common( __inout sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_malloc_auto_ptr field_value_temp; field_value_temp = static_cast( sqlsrv_malloc( sizeof( double ))); - SQLRETURN r = core::SQLGetData( stmt, field_index + 1, SQL_C_DOUBLE, field_value_temp, 0, - field_len, true /*handle_warning*/ TSRMLS_CC ); + 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(); + } + CHECK_CUSTOM_ERROR( (r == SQL_NO_DATA), stmt, SQLSRV_ERROR_NO_DATA, field_index ) { throw core::CoreException (); } @@ -1440,8 +1557,8 @@ void core_get_field_common( __inout sqlsrv_stmt* stmt, SQLUSMALLINT field_index, ALLOC_INIT_ZVAL( function_z ); ALLOC_INIT_ZVAL( return_value_z ); - SQLRETURN r = core::SQLGetData( stmt, field_index + 1, SQL_C_CHAR, field_value_temp, MAX_DATETIME_STRING_LEN, - field_len, true TSRMLS_CC ); + 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 ); CHECK_CUSTOM_ERROR( (r == SQL_NO_DATA), stmt, SQLSRV_ERROR_NO_DATA, field_index ) { throw core::CoreException (); @@ -1512,6 +1629,11 @@ void core_get_field_common( __inout sqlsrv_stmt* stmt, SQLUSMALLINT field_index, break; } + case SQLSRV_PHPTYPE_NULL: + *field_value = NULL; + *field_len = 0; + break; + default: DIE( "core_get_field_common: Unexpected sqlsrv_phptype provided" ); break; @@ -1630,7 +1752,7 @@ SQLSMALLINT default_c_type( sqlsrv_stmt* stmt, unsigned int paramno, zval const* sql_c_type = SQL_C_CHAR; break; } - break; + break; case IS_BOOL: case IS_LONG: sql_c_type = SQL_C_LONG; @@ -1951,8 +2073,8 @@ void get_field_as_string( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_ph field_value_temp = static_cast( sqlsrv_malloc( field_len_temp + extra + 1 )); - r = core::SQLGetData( stmt, field_index + 1, c_type, field_value_temp, ( field_len_temp + extra ), - &field_len_temp, false /*handle_warning*/ TSRMLS_CC ); + 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 (); @@ -1969,7 +2091,7 @@ void get_field_as_string( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_ph SQLCHAR state[ SQL_SQLSTATE_BUFSIZE ]; SQLSMALLINT len; - core::SQLGetDiagField( stmt, 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len TSRMLS_CC ); + stmt->current_results->get_diag_field( 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len TSRMLS_CC ); if( is_truncated_warning( state ) ) { @@ -1993,8 +2115,9 @@ void get_field_as_string( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_ph field_len_temp -= initial_field_len; // Get the rest of the data. - r = core::SQLGetData( stmt, field_index + 1, c_type, field_value_temp + initial_field_len, - field_len_temp + extra, &dummy_field_len, false /*handle_warning*/ TSRMLS_CC ); + 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 ); // the last packet will contain the actual amount retrieved, not SQL_NO_TOTAL // so we calculate the actual length of the string with that. @@ -2019,8 +2142,9 @@ void get_field_as_string( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_ph field_len_temp -= INITIAL_FIELD_STRING_LEN; // Get the rest of the data. - r = core::SQLGetData( stmt, field_index + 1, c_type, field_value_temp + INITIAL_FIELD_STRING_LEN, - field_len_temp + extra, &dummy_field_len, true /*handle_warning*/ TSRMLS_CC ); + 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 ); if( dummy_field_len == SQL_NULL_DATA ) { *field_value = NULL; @@ -2072,9 +2196,11 @@ void get_field_as_string( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_ph field_value_temp = static_cast( sqlsrv_malloc( sql_display_size + extra + 1 )); // get the data - r = core::SQLGetData( stmt, field_index + 1, c_type, field_value_temp, sql_display_size, - &field_len_temp, true /*handle_warning*/ TSRMLS_CC ); - + 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 (); } diff --git a/pdo_sqlsrv/core_stream.cpp b/pdo_sqlsrv/core_stream.cpp index d1d3a020..340d4dcc 100644 --- a/pdo_sqlsrv/core_stream.cpp +++ b/pdo_sqlsrv/core_stream.cpp @@ -3,7 +3,7 @@ // // Contents: Implementation of PHP streams for reading SQL Server data // -// Copyright 2010 Microsoft Corporation +// Copyright Microsoft Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -113,8 +113,9 @@ size_t sqlsrv_stream_read( php_stream* stream, __out_bcount(count) char* buf, si SQLCHAR state[ SQL_SQLSTATE_BUFSIZE ]; SQLSMALLINT len; - core::SQLGetDiagField( ss->stmt, 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len TSRMLS_CC ); - + + ss->stmt->current_results->get_diag_field( 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len TSRMLS_CC ); + if( read == SQL_NO_TOTAL ) { SQLSRV_ASSERT( is_truncated_warning( state ), "sqlsrv_stream_read: truncation warning was expected but it " "did not occur." ); @@ -135,7 +136,7 @@ size_t sqlsrv_stream_read( php_stream* stream, __out_bcount(count) char* buf, si read = count - 1; break; default: - DIE( "sqlsrv_stream_read: should have never reached in this switch case. "); + DIE( "sqlsrv_stream_read: should have never reached in this switch case."); break; } } diff --git a/pdo_sqlsrv/core_util.cpp b/pdo_sqlsrv/core_util.cpp index e335afec..a29cfe38 100644 --- a/pdo_sqlsrv/core_util.cpp +++ b/pdo_sqlsrv/core_util.cpp @@ -5,7 +5,7 @@ // // Comments: Mostly error handling and some type handling // -// Copyright 2010 Microsoft Corporation +// Copyright Microsoft Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -147,7 +147,8 @@ wchar_t* utf16_string_from_mbcs_string( SQLSRV_ENCODING php_encoding, const char // 3/message) driver specific error message // The fetch type determines if the indices are numeric, associative, or both. -bool core_sqlsrv_get_odbc_error( sqlsrv_context& ctx, int record_number, sqlsrv_error* error, logging_severity severity TSRMLS_DC ) +bool core_sqlsrv_get_odbc_error( sqlsrv_context& ctx, int record_number, sqlsrv_error_auto_ptr& error, logging_severity severity + TSRMLS_DC ) { SQLHANDLE h = ctx.handle(); SQLSMALLINT h_type = ctx.handle_type(); @@ -165,22 +166,50 @@ bool core_sqlsrv_get_odbc_error( sqlsrv_context& ctx, int record_number, sqlsrv_ SQLINTEGER message_len = 0; SQLWCHAR wsqlstate[ SQL_SQLSTATE_BUFSIZE ]; SQLWCHAR wnative_message[ SQL_MAX_MESSAGE_LENGTH + 1 ]; + SQLSRV_ENCODING enc = ctx.encoding(); - r = SQLGetDiagRecW( h_type, h, record_number, wsqlstate, &error->native_code, wnative_message, - SQL_MAX_MESSAGE_LENGTH + 1, &wmessage_len ); - // don't use the CHECK* macros here since it will trigger reentry into the error handling system - if( !SQL_SUCCEEDED( r ) || r == SQL_NO_DATA ) { - return false; - } + switch( h_type ) { + + case SQL_HANDLE_STMT: + { + sqlsrv_stmt* stmt = static_cast( &ctx ); + if( stmt->current_results != NULL ) { + + error = stmt->current_results->get_diag_rec( record_number ); + // don't use the CHECK* macros here since it will trigger reentry into the error handling system + if( error == NULL ) { + return false; + } + break; + } + + // convert the error into the encoding of the context + if( enc == SQLSRV_ENCODING_DEFAULT ) { + enc = stmt->conn->encoding(); + } + } + + + default: + + error = new ( sqlsrv_malloc( sizeof( sqlsrv_error ))) sqlsrv_error(); + r = SQLGetDiagRecW( h_type, h, record_number, wsqlstate, &error->native_code, wnative_message, + SQL_MAX_MESSAGE_LENGTH + 1, &wmessage_len ); + // don't use the CHECK* macros here since it will trigger reentry into the error handling system + if( !SQL_SUCCEEDED( r ) || r == SQL_NO_DATA ) { + return false; + } + + error->sqlstate = reinterpret_cast( wsqlstate ); + convert_string_from_utf16( enc, reinterpret_cast( &error->sqlstate ), sqlstate_len, + false /*no free*/ ); + error->native_message = reinterpret_cast( wnative_message ); + message_len = wmessage_len * sizeof( wchar_t ); + convert_string_from_utf16( enc, reinterpret_cast( &error->native_message ), message_len, + false /*no free*/ ); + break; + } - // convert the error into the encoding of the context - error->sqlstate = reinterpret_cast( wsqlstate ); - convert_string_from_utf16( ctx.encoding(), reinterpret_cast( &error->sqlstate ), sqlstate_len, - false /*no free*/ ); - error->native_message = reinterpret_cast( wnative_message ); - message_len = wmessage_len * sizeof( wchar_t ); - convert_string_from_utf16( ctx.encoding(), reinterpret_cast( &error->native_message ), message_len, - false /*no free*/ ); // log the error first LOG( severity, "%1!s!: SQLSTATE = %2!s!", ctx.func(), error->sqlstate ); @@ -194,9 +223,10 @@ bool core_sqlsrv_get_odbc_error( sqlsrv_context& ctx, int record_number, sqlsrv_ // format and return a driver specfic error void core_sqlsrv_format_driver_error( sqlsrv_context& ctx, sqlsrv_error_const const* custom_error, - sqlsrv_error* formatted_error, logging_severity severity TSRMLS_DC, va_list* args ) + sqlsrv_error_auto_ptr& formatted_error, logging_severity severity TSRMLS_DC, va_list* args ) { // allocate space for the formatted message + formatted_error = new (sqlsrv_malloc( sizeof( sqlsrv_error ))) sqlsrv_error(); formatted_error->sqlstate = reinterpret_cast( sqlsrv_malloc( SQL_SQLSTATE_BUFSIZE )); formatted_error->native_message = reinterpret_cast( sqlsrv_malloc( SQL_MAX_MESSAGE_LENGTH + 1 )); diff --git a/pdo_sqlsrv/pdo_dbh.cpp b/pdo_sqlsrv/pdo_dbh.cpp index abc511ce..c91a34a9 100644 --- a/pdo_sqlsrv/pdo_dbh.cpp +++ b/pdo_sqlsrv/pdo_dbh.cpp @@ -3,7 +3,7 @@ // // Contents: Implements the PDO object for PDO_SQLSRV // -// Copyright 2010 Microsoft Corporation +// Copyright Microsoft Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -52,12 +52,15 @@ namespace PDOConnOptionNames { const char Server[] = "Server"; const char APP[] = "APP"; +const char ApplicationIntent[] = "ApplicationIntent"; +const char AttachDBFileName[] = "AttachDbFileName"; const char ConnectionPooling[] = "ConnectionPooling"; const char Database[] = "Database"; const char Encrypt[] = "Encrypt"; const char Failover_Partner[] = "Failover_Partner"; const char LoginTimeout[] = "LoginTimeout"; const char MARS_Option[] = "MultipleActiveResultSets"; +const char MultiSubnetFailover[] = "MultiSubnetFailover"; const char QuotedId[] = "QuotedId"; const char TraceFile[] = "TraceFile"; const char TraceOn[] = "TraceOn"; @@ -77,6 +80,9 @@ enum PDO_STMT_OPTIONS { PDO_STMT_OPTION_ENCODING = SQLSRV_STMT_OPTION_DRIVER_SPECIFIC, PDO_STMT_OPTION_DIRECT_QUERY, + PDO_STMT_OPTION_CURSOR_SCROLL_TYPE, + PDO_STMT_OPTION_CLIENT_BUFFER_MAX_KB_SIZE, + PDO_STMT_OPTION_EMULATE_PREPARES, }; // List of all the statement options supported by this driver. @@ -86,6 +92,9 @@ const stmt_option PDO_STMT_OPTS[] = { { NULL, 0, SQLSRV_STMT_OPTION_SCROLLABLE, new stmt_option_scrollable }, { NULL, 0, PDO_STMT_OPTION_ENCODING, new stmt_option_encoding }, { NULL, 0, PDO_STMT_OPTION_DIRECT_QUERY, new stmt_option_direct_query }, + { NULL, 0, PDO_STMT_OPTION_CURSOR_SCROLL_TYPE, new stmt_option_cursor_scroll_type }, + { NULL, 0, PDO_STMT_OPTION_CLIENT_BUFFER_MAX_KB_SIZE, new stmt_option_buffered_query_limit }, + { NULL, 0, PDO_STMT_OPTION_EMULATE_PREPARES, new stmt_option_emulate_prepares }, { NULL, 0, SQLSRV_STMT_OPTION_INVALID, NULL}, }; @@ -163,6 +172,24 @@ const connection_option PDO_CONN_OPTS[] = { CONN_ATTR_STRING, conn_str_append_func::func }, + { + PDOConnOptionNames::ApplicationIntent, + sizeof( PDOConnOptionNames::ApplicationIntent ), + SQLSRV_CONN_OPTION_APPLICATION_INTENT, + ODBCConnOptions::ApplicationIntent, + sizeof( ODBCConnOptions::ApplicationIntent ), + CONN_ATTR_STRING, + conn_str_append_func::func + }, + { + PDOConnOptionNames::AttachDBFileName, + sizeof( PDOConnOptionNames::AttachDBFileName ), + SQLSRV_CONN_OPTION_ATTACHDBFILENAME, + ODBCConnOptions::AttachDBFileName, + sizeof( ODBCConnOptions::AttachDBFileName ), + CONN_ATTR_STRING, + conn_str_append_func::func + }, { PDOConnOptionNames::ConnectionPooling, sizeof( PDOConnOptionNames::ConnectionPooling ), @@ -217,6 +244,15 @@ const connection_option PDO_CONN_OPTS[] = { CONN_ATTR_BOOL, pdo_bool_conn_str_func::func }, + { + PDOConnOptionNames::MultiSubnetFailover, + sizeof( PDOConnOptionNames::MultiSubnetFailover ), + SQLSRV_CONN_OPTION_MULTI_SUBNET_FAILOVER, + ODBCConnOptions::MultiSubnetFailover, + sizeof( ODBCConnOptions::MultiSubnetFailover ), + CONN_ATTR_BOOL, + pdo_bool_conn_str_func::func + }, { PDOConnOptionNames::QuotedId, sizeof( PDOConnOptionNames::QuotedId ), @@ -333,6 +369,20 @@ struct pdo_dbh_methods pdo_sqlsrv_dbh_methods = { LOG( SEV_NOTICE, __FUNCTION__ ## ": entering" ); \ } +// constructor for the internal object for connections +pdo_sqlsrv_dbh::pdo_sqlsrv_dbh( SQLHANDLE h, error_callback e, void* driver TSRMLS_DC ) : + sqlsrv_conn( h, e, driver, SQLSRV_ENCODING_UTF8 TSRMLS_CC ), + stmts( NULL ), + direct_query( false ), + query_timeout( QUERY_TIMEOUT_INVALID ), + client_buffer_max_size( PDO_SQLSRV_G( client_buffer_max_size ) ) +{ + if( client_buffer_max_size < 0 ) { + client_buffer_max_size = sqlsrv_buffered_result_set::BUFFERED_QUERY_LIMIT_DEFAULT; + LOG( SEV_WARNING, INI_PDO_SQLSRV_CLIENT_BUFFER_MAX_SIZE " set to a invalid value. Resetting to default value." ); + } +} + // pdo_sqlsrv_db_handle_factory // Maps to PDO::__construct. // Factory method called by the PDO driver manager to create a SQLSRV PDO connection. @@ -481,29 +531,16 @@ int pdo_sqlsrv_dbh_prepare( pdo_dbh_t *dbh, const char *sql, int sql_rewrite_len = 0; sqlsrv_malloc_auto_ptr driver_stmt; - try { + pdo_sqlsrv_dbh* driver_dbh = reinterpret_cast( dbh->driver_data ); + SQLSRV_ASSERT(( driver_dbh != NULL ), "pdo_sqlsrv_dbh_prepare: dbh->driver_data was null"); - pdo_sqlsrv_dbh* driver_dbh = reinterpret_cast( dbh->driver_data ); - SQLSRV_ASSERT(( driver_dbh != NULL ), "pdo_sqlsrv_dbh_prepare: dbh->driver_data was null"); + try { // assign the methods for the statement object. This is necessary even if the // statement fails so the user can retrieve the error information. stmt->methods = &pdo_sqlsrv_stmt_methods; stmt->supports_placeholders = PDO_PLACEHOLDER_POSITIONAL; // we support parameterized queries with ?, not names - // rewrite the query to map named parameters to positional parameters. We do this rather than use the ODBC named - // parameters for consistency with the PDO MySQL and PDO ODBC drivers. - int zr = pdo_subst_params_named_to_positional( stmt, const_cast( sql ), sql_len, - &sql_rewrite, &sql_rewrite_len TSRMLS_CC ); - CHECK_ZEND_ERROR( zr, driver_dbh, PDO_SQLSRV_ERROR_PARAM_PARSE ) { - throw core::CoreException(); - } - // if parameter substitution happened, use that query instead of the original - if( sql_rewrite != NULL ) { - sql = sql_rewrite; - sql_len = sql_rewrite_len; - } - // Initialize the options array to be passed to the core layer ALLOC_HASHTABLE( pdo_stmt_options_ht ); core::sqlsrv_zend_hash_init( *driver_dbh , pdo_stmt_options_ht, 3 /* # of buckets */, NULL /*hashfn*/, @@ -516,6 +553,13 @@ int pdo_sqlsrv_dbh_prepare( pdo_dbh_t *dbh, const char *sql, pdo_stmt_options_ht, PDO_STMT_OPTS, pdo_sqlsrv_handle_stmt_error, stmt TSRMLS_CC )); + // if the user didn't set anything in the prepare options, then set the buffer limit + // to the value set on the connection. + if( driver_stmt->buffered_query_limit== sqlsrv_buffered_result_set::BUFFERED_QUERY_LIMIT_INVALID ) { + + driver_stmt->buffered_query_limit = driver_dbh->client_buffer_max_size; + } + // if the user didn't set anything in the prepare options, then set the query timeout // to the value set on the connection. if(( driver_stmt->query_timeout == QUERY_TIMEOUT_INVALID ) && ( driver_dbh->query_timeout != QUERY_TIMEOUT_INVALID )) { @@ -523,12 +567,24 @@ int pdo_sqlsrv_dbh_prepare( pdo_dbh_t *dbh, const char *sql, core_sqlsrv_set_query_timeout( driver_stmt, driver_dbh->query_timeout TSRMLS_CC ); } - if( driver_stmt->direct_query ) { + // rewrite named parameters in the query to positional parameters if we aren't letting PDO do the + // parameter substitution for us + if( stmt->supports_placeholders != PDO_PLACEHOLDER_NONE ) { - driver_stmt->query = estrndup( sql, sql_len ); - driver_stmt->query_len = sql_len; + // rewrite the query to map named parameters to positional parameters. We do this rather than use the ODBC named + // parameters for consistency with the PDO MySQL and PDO ODBC drivers. + int zr = pdo_subst_named_params( stmt, const_cast( sql ), sql_len, &sql_rewrite, &sql_rewrite_len TSRMLS_CC ); + CHECK_ZEND_ERROR( zr, driver_dbh, PDO_SQLSRV_ERROR_PARAM_PARSE ) { + throw core::CoreException(); + } + // if parameter substitution happened, use that query instead of the original + if( sql_rewrite != NULL ) { + sql = sql_rewrite; + sql_len = sql_rewrite_len; + } } - else { + + if( !driver_stmt->direct_query && stmt->supports_placeholders != PDO_PLACEHOLDER_NONE ) { core_sqlsrv_prepare( driver_stmt, sql, sql_len TSRMLS_CC ); } @@ -545,6 +601,14 @@ int pdo_sqlsrv_dbh_prepare( pdo_dbh_t *dbh, const char *sql, driver_stmt->~pdo_sqlsrv_stmt(); } + // in the event that the statement caused an error that was copied to the connection, update the + // connection with the error's SQLSTATE. + if( driver_dbh->last_error() ) { + + strcpy_s( dbh->error_code, sizeof( dbh->error_code ), + reinterpret_cast( driver_dbh->last_error()->sqlstate )); + } + return 0; } @@ -819,17 +883,24 @@ int pdo_sqlsrv_dbh_set_attr( pdo_dbh_t *dbh, long attr, zval *val TSRMLS_DC ) case SQLSRV_ATTR_QUERY_TIMEOUT: if( Z_TYPE_P( val ) != IS_LONG || Z_LVAL_P( val ) < 0 ) { convert_to_string( val ); - THROW_PDO_ERROR( driver_dbh, SQLSRV_ERROR_INVALID_OPTION_VALUE, Z_STRVAL_P( val )); + THROW_PDO_ERROR( driver_dbh, SQLSRV_ERROR_INVALID_QUERY_TIMEOUT_VALUE, Z_STRVAL_P( val )); } driver_dbh->query_timeout = Z_LVAL_P( val ); break; + case SQLSRV_ATTR_CLIENT_BUFFER_MAX_KB_SIZE: + if( Z_TYPE_P( val ) != IS_LONG || Z_LVAL_P( val ) <= 0 ) { + convert_to_string( val ); + THROW_PDO_ERROR( driver_dbh, SQLSRV_ERROR_INVALID_BUFFER_LIMIT, Z_STRVAL_P( val )); + } + driver_dbh->client_buffer_max_size = Z_LVAL_P( val ); + break; + // Not supported case PDO_ATTR_FETCH_TABLE_NAMES: case PDO_ATTR_FETCH_CATALOG_NAMES: case PDO_ATTR_PREFETCH: case PDO_ATTR_MAX_COLUMN_LEN: - case PDO_ATTR_EMULATE_PREPARES: case PDO_ATTR_CURSOR_NAME: case PDO_ATTR_AUTOCOMMIT: case PDO_ATTR_PERSISTENT: @@ -849,7 +920,9 @@ int pdo_sqlsrv_dbh_set_attr( pdo_dbh_t *dbh, long attr, zval *val TSRMLS_DC ) } // Statement level only - case PDO_ATTR_CURSOR: + case PDO_ATTR_EMULATE_PREPARES: + case PDO_ATTR_CURSOR: + case SQLSRV_ATTR_CURSOR_SCROLL_TYPE: { THROW_PDO_ERROR( driver_dbh, PDO_SQLSRV_ERROR_STMT_LEVEL_ATTR ); } @@ -895,7 +968,6 @@ int pdo_sqlsrv_dbh_get_attr( pdo_dbh_t *dbh, long attr, zval *return_value TSRML case PDO_ATTR_FETCH_CATALOG_NAMES: case PDO_ATTR_PREFETCH: case PDO_ATTR_MAX_COLUMN_LEN: - case PDO_ATTR_EMULATE_PREPARES: case PDO_ATTR_CURSOR_NAME: case PDO_ATTR_AUTOCOMMIT: case PDO_ATTR_TIMEOUT: @@ -904,8 +976,10 @@ int pdo_sqlsrv_dbh_get_attr( pdo_dbh_t *dbh, long attr, zval *return_value TSRML THROW_PDO_ERROR( driver_dbh, PDO_SQLSRV_ERROR_UNSUPPORTED_DBH_ATTR ); } - // Statement level only - case PDO_ATTR_CURSOR: + // Statement level only + case PDO_ATTR_EMULATE_PREPARES: + case PDO_ATTR_CURSOR: + case SQLSRV_ATTR_CURSOR_SCROLL_TYPE: { THROW_PDO_ERROR( driver_dbh, PDO_SQLSRV_ERROR_STMT_LEVEL_ATTR ); } @@ -957,6 +1031,12 @@ int pdo_sqlsrv_dbh_get_attr( pdo_dbh_t *dbh, long attr, zval *return_value TSRML break; } + case SQLSRV_ATTR_CLIENT_BUFFER_MAX_KB_SIZE: + { + ZVAL_LONG( return_value, driver_dbh->client_buffer_max_size ); + break; + } + default: { THROW_PDO_ERROR( driver_dbh, PDO_SQLSRV_ERROR_INVALID_DBH_ATTR ); @@ -1113,8 +1193,8 @@ int pdo_sqlsrv_dbh_quote( pdo_dbh_t* dbh, const char* unquoted, int unquoted_len } } - *quoted_len = unquoted_len + quotes_needed; // length returned to the caller should not account for null terminator. - *quoted = reinterpret_cast( sqlsrv_malloc( *quoted_len + 1 )); // include space for null terminator. + *quoted_len = unquoted_len + quotes_needed; // length returned to the caller should not account for null terminator. + *quoted = reinterpret_cast( sqlsrv_malloc( *quoted_len, sizeof( char ), 1 )); // include space for null terminator. unsigned int out_current = 0; // insert initial quote @@ -1163,29 +1243,42 @@ void add_stmt_option_key( sqlsrv_context& ctx, unsigned long key, HashTable* opt unsigned long option_key = -1; switch( key ) { - case PDO_ATTR_CURSOR: - option_key = SQLSRV_STMT_OPTION_SCROLLABLE; - break; + case PDO_ATTR_CURSOR: + option_key = SQLSRV_STMT_OPTION_SCROLLABLE; + break; - case SQLSRV_ATTR_ENCODING: - option_key = PDO_STMT_OPTION_ENCODING; - break; + case SQLSRV_ATTR_ENCODING: + option_key = PDO_STMT_OPTION_ENCODING; + break; - case SQLSRV_ATTR_QUERY_TIMEOUT: - option_key = SQLSRV_STMT_OPTION_QUERY_TIMEOUT; - break; + case SQLSRV_ATTR_QUERY_TIMEOUT: + option_key = SQLSRV_STMT_OPTION_QUERY_TIMEOUT; + break; - case PDO_ATTR_STATEMENT_CLASS: - break; + case PDO_ATTR_STATEMENT_CLASS: + break; case SQLSRV_ATTR_DIRECT_QUERY: option_key = PDO_STMT_OPTION_DIRECT_QUERY; break; - default: - CHECK_CUSTOM_ERROR( true, ctx, PDO_SQLSRV_ERROR_INVALID_STMT_OPTION ) { - throw core::CoreException(); - } + case SQLSRV_ATTR_CURSOR_SCROLL_TYPE: + option_key = PDO_STMT_OPTION_CURSOR_SCROLL_TYPE; + break; + + case SQLSRV_ATTR_CLIENT_BUFFER_MAX_KB_SIZE: + option_key = PDO_STMT_OPTION_CLIENT_BUFFER_MAX_KB_SIZE; + break; + + case PDO_ATTR_EMULATE_PREPARES: + option_key = PDO_STMT_OPTION_EMULATE_PREPARES; + break; + + default: + CHECK_CUSTOM_ERROR( true, ctx, PDO_SQLSRV_ERROR_INVALID_STMT_OPTION ) { + throw core::CoreException(); + } + break; } // if a PDO handled option makes it through (such as PDO_ATTR_STATEMENT_CLASS, just skip it diff --git a/pdo_sqlsrv/pdo_init.cpp b/pdo_sqlsrv/pdo_init.cpp index 63b45d2f..eb5c7f62 100644 --- a/pdo_sqlsrv/pdo_init.cpp +++ b/pdo_sqlsrv/pdo_init.cpp @@ -3,7 +3,7 @@ // // Contents: initialization routines for PDO_SQLSRV // -// Copyright 2010 Microsoft Corporation +// Copyright Microsoft Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -134,8 +134,8 @@ zend_module_entry g_pdo_sqlsrv_module_entry = // functions dynamically linked from the PDO (or PHP) dll and called by other parts of the driver zend_class_entry* (*pdo_get_exception_class)( void ); -int (*pdo_subst_params_named_to_positional)(pdo_stmt_t *stmt, char *inquery, int inquery_len, - char **outquery, int *outquery_len TSRMLS_DC); +int (*pdo_subst_named_params)(pdo_stmt_t *stmt, char *inquery, int inquery_len, + char **outquery, int *outquery_len TSRMLS_DC); // Module initialization // This function is called once per execution of the Zend engine @@ -206,11 +206,11 @@ PHP_MINIT_FUNCTION(pdo_sqlsrv) return FAILURE; } - pdo_subst_params_named_to_positional = + pdo_subst_named_params = reinterpret_cast( GetProcAddress( pdo_hmodule, "pdo_parse_params" )); - if( pdo_subst_params_named_to_positional == NULL ) { + if( pdo_subst_named_params == NULL ) { LOG( SEV_ERROR, "Failed to register driver." ); return FAILURE; } @@ -243,16 +243,6 @@ PHP_MINIT_FUNCTION(pdo_sqlsrv) } - // used for the size for output parameters: PDO::PARAM_INT and PDO::PARAM_BOOL use the default size of int, - // PDO::PARAM_STR uses the size of the string in the variable - REGISTER_PDO_SQLSRV_CLASS_CONST_LONG( "SQLSRV_PARAM_OUT_DEFAULT_SIZE", -1 TSRMLS_CC ); - - // encoding attributes - REGISTER_PDO_SQLSRV_CLASS_CONST_LONG( "SQLSRV_ENCODING_DEFAULT", SQLSRV_ENCODING_DEFAULT TSRMLS_CC ); - REGISTER_PDO_SQLSRV_CLASS_CONST_LONG( "SQLSRV_ENCODING_SYSTEM", SQLSRV_ENCODING_SYSTEM TSRMLS_CC ); - REGISTER_PDO_SQLSRV_CLASS_CONST_LONG( "SQLSRV_ENCODING_BINARY", SQLSRV_ENCODING_BINARY TSRMLS_CC ); - REGISTER_PDO_SQLSRV_CLASS_CONST_LONG( "SQLSRV_ENCODING_UTF8", SQLSRV_ENCODING_UTF8 TSRMLS_CC ); - REGISTER_PDO_SQLSRV_CLASS_CONST_STRING( "SQLSRV_TXN_READ_UNCOMMITTED", PDOTxnIsolationValues::READ_UNCOMMITTED TSRMLS_CC ); REGISTER_PDO_SQLSRV_CLASS_CONST_STRING( "SQLSRV_TXN_READ_COMMITTED", PDOTxnIsolationValues::READ_COMMITTED TSRMLS_CC ); REGISTER_PDO_SQLSRV_CLASS_CONST_STRING( "SQLSRV_TXN_REPEATABLE_READ", PDOTxnIsolationValues::REPEATABLE_READ TSRMLS_CC ); @@ -383,10 +373,30 @@ namespace { // array of pdo constants. sqlsrv_attr_pdo_constant pdo_attr_constants[] = { - + + // driver specific attributes { "SQLSRV_ATTR_ENCODING" , SQLSRV_ATTR_ENCODING }, { "SQLSRV_ATTR_QUERY_TIMEOUT" , SQLSRV_ATTR_QUERY_TIMEOUT }, { "SQLSRV_ATTR_DIRECT_QUERY" , SQLSRV_ATTR_DIRECT_QUERY }, + { "SQLSRV_ATTR_CURSOR_SCROLL_TYPE" , SQLSRV_ATTR_CURSOR_SCROLL_TYPE }, + { "SQLSRV_ATTR_CLIENT_BUFFER_MAX_KB_SIZE", SQLSRV_ATTR_CLIENT_BUFFER_MAX_KB_SIZE }, + + // used for the size for output parameters: PDO::PARAM_INT and PDO::PARAM_BOOL use the default size of int, + // PDO::PARAM_STR uses the size of the string in the variable + { "SQLSRV_PARAM_OUT_DEFAULT_SIZE" , -1 }, + + // encoding attributes + { "SQLSRV_ENCODING_DEFAULT" , SQLSRV_ENCODING_DEFAULT }, + { "SQLSRV_ENCODING_SYSTEM" , SQLSRV_ENCODING_SYSTEM }, + { "SQLSRV_ENCODING_BINARY" , SQLSRV_ENCODING_BINARY }, + { "SQLSRV_ENCODING_UTF8" , SQLSRV_ENCODING_UTF8 }, + + // cursor types (can be assigned to SQLSRV_ATTR_CURSOR_SCROLL_TYPE + { "SQLSRV_CURSOR_STATIC" , SQL_CURSOR_STATIC }, + { "SQLSRV_CURSOR_DYNAMIC" , SQL_CURSOR_DYNAMIC }, + { "SQLSRV_CURSOR_KEYSET" , SQL_CURSOR_KEYSET_DRIVEN }, + { "SQLSRV_CURSOR_BUFFERED" , SQLSRV_CURSOR_BUFFERED }, + { NULL , 0 } // terminate the table }; } diff --git a/pdo_sqlsrv/pdo_parser.cpp b/pdo_sqlsrv/pdo_parser.cpp index 7f72aaee..e2f3b897 100644 --- a/pdo_sqlsrv/pdo_parser.cpp +++ b/pdo_sqlsrv/pdo_parser.cpp @@ -3,7 +3,7 @@ // // Contents: Implements a parser to parse the PDO DSN. // -// Copyright 2010 Microsoft Corporation +// Copyright Microsoft Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/pdo_sqlsrv/pdo_sqlsrv.h b/pdo_sqlsrv/pdo_sqlsrv.h index 2ae03415..f185022a 100644 --- a/pdo_sqlsrv/pdo_sqlsrv.h +++ b/pdo_sqlsrv/pdo_sqlsrv.h @@ -6,7 +6,7 @@ // // Contents: Declarations for the extension // -// Copyright 2010 Microsoft Corporation +// Copyright Microsoft Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -32,6 +32,10 @@ extern "C" { } +#include +#include + + //********************************************************************************************************************************* // Constants and Types //********************************************************************************************************************************* @@ -43,6 +47,8 @@ enum PDO_SQLSRV_ATTR { SQLSRV_ATTR_ENCODING = PDO_ATTR_DRIVER_SPECIFIC, SQLSRV_ATTR_QUERY_TIMEOUT, SQLSRV_ATTR_DIRECT_QUERY, + SQLSRV_ATTR_CURSOR_SCROLL_TYPE, + SQLSRV_ATTR_CLIENT_BUFFER_MAX_KB_SIZE, }; // valid set of values for TransactionIsolation connection option @@ -65,6 +71,7 @@ extern "C" { ZEND_BEGIN_MODULE_GLOBALS(pdo_sqlsrv) unsigned int log_severity; +long client_buffer_max_size; ZEND_END_MODULE_GLOBALS(pdo_sqlsrv) @@ -81,12 +88,15 @@ ZEND_EXTERN_MODULE_GLOBALS(pdo_sqlsrv); // INI settings and constants // (these are defined as macros to allow concatenation as we do below) +#define INI_PDO_SQLSRV_CLIENT_BUFFER_MAX_SIZE "client_buffer_max_kb_size" #define INI_PDO_SQLSRV_LOG "log_severity" #define INI_PREFIX "pdo_sqlsrv." PHP_INI_BEGIN() STD_PHP_INI_ENTRY( INI_PREFIX INI_PDO_SQLSRV_LOG , "0", PHP_INI_ALL, OnUpdateLong, log_severity, zend_pdo_sqlsrv_globals, pdo_sqlsrv_globals ) + STD_PHP_INI_ENTRY( INI_PREFIX INI_PDO_SQLSRV_CLIENT_BUFFER_MAX_SIZE , INI_BUFFERED_QUERY_LIMIT_DEFAULT, PHP_INI_ALL, OnUpdateLong, + client_buffer_max_size, zend_pdo_sqlsrv_globals, pdo_sqlsrv_globals ) PHP_INI_END() // henv context for creating connections @@ -166,14 +176,9 @@ struct pdo_sqlsrv_dbh : public sqlsrv_conn { zval* stmts; bool direct_query; long query_timeout; + long client_buffer_max_size; - pdo_sqlsrv_dbh( SQLHANDLE h, error_callback e, void* driver TSRMLS_DC ) : - sqlsrv_conn( h, e, driver, SQLSRV_ENCODING_UTF8 TSRMLS_CC ), - stmts( NULL ), - direct_query( false ), - query_timeout( QUERY_TIMEOUT_INVALID ) - { - } + pdo_sqlsrv_dbh( SQLHANDLE h, error_callback e, void* driver TSRMLS_DC ); }; @@ -196,6 +201,16 @@ struct stmt_option_direct_query : public stmt_option_functor { virtual void operator()( sqlsrv_stmt* stmt, stmt_option const* /*opt*/, zval* value_z TSRMLS_DC ); }; +struct stmt_option_cursor_scroll_type : public stmt_option_functor { + + virtual void operator()( sqlsrv_stmt* stmt, stmt_option const* /*opt*/, zval* value_z TSRMLS_DC ); +}; + +struct stmt_option_emulate_prepares : public stmt_option_functor { + + virtual void operator()( sqlsrv_stmt* stmt, stmt_option const* /*opt*/, zval* value_z TSRMLS_DC ); +}; + extern struct pdo_stmt_methods pdo_sqlsrv_stmt_methods; // a core layer pdo stmt object. This object inherits and overrides the callbacks necessary @@ -204,28 +219,22 @@ struct pdo_sqlsrv_stmt : public sqlsrv_stmt { pdo_sqlsrv_stmt( sqlsrv_conn* c, SQLHANDLE handle, error_callback e, void* drv TSRMLS_DC ) : sqlsrv_stmt( c, handle, e, drv TSRMLS_CC ), direct_query( false ), - query( NULL ), - query_len( 0 ) + bound_column_param_types( NULL ) { pdo_sqlsrv_dbh* db = static_cast( c ); direct_query = db->direct_query; } - virtual ~pdo_sqlsrv_stmt( void ) - { - if( query ) { - sqlsrv_free( query ); - query = NULL; - } - } + virtual ~pdo_sqlsrv_stmt( void ); // driver specific conversion rules from a SQL Server/ODBC type to one of the SQLSRV_PHPTYPE_* constants // for PDO, everything is a string, so we return SQLSRV_PHPTYPE_STRING for all SQL types virtual sqlsrv_phptype sql_type_to_php_type( SQLINTEGER sql_type, SQLUINTEGER size, bool prefer_string_to_stream ); bool direct_query; // flag set if the query should be executed directly or prepared - char* query; // if the query should be executed directly, this holds the query to execute - unsigned int query_len; // length of the query string. + // meta data for current result set + std::vector > current_meta_data; + pdo_param_type* bound_column_param_types; }; @@ -345,6 +354,8 @@ enum PDO_ERROR_CODES { PDO_SQLSRV_ERROR_DQ_ATTR_AT_PREPARE_ONLY, PDO_SQLSRV_ERROR_INVALID_COLUMN_INDEX, PDO_SQLSRV_ERROR_INVALID_OUTPUT_PARAM_TYPE, + PDO_SQLSRV_ERROR_INVALID_CURSOR_WITH_SCROLL_TYPE, + }; extern pdo_error PDO_ERRORS[]; @@ -368,8 +379,8 @@ namespace pdo { // called pdo_parse_params in php_pdo_driver.h // we renamed it for 2 reasons: 1) we can't have the same name since it would conflict with our dynamic linking, and // 2) this is a more precise name -extern int (*pdo_subst_params_named_to_positional)(pdo_stmt_t *stmt, char *inquery, int inquery_len, - char **outquery, int *outquery_len TSRMLS_DC); +extern int (*pdo_subst_named_params)(pdo_stmt_t *stmt, char *inquery, int inquery_len, + char **outquery, int *outquery_len TSRMLS_DC); // logger for pdo_sqlsrv called by the core layer when it wants to log something with the LOG macro void pdo_sqlsrv_log( unsigned int severity TSRMLS_DC, const char* msg, va_list* print_args ); diff --git a/pdo_sqlsrv/pdo_stmt.cpp b/pdo_sqlsrv/pdo_stmt.cpp index 6e80d96b..01be2816 100644 --- a/pdo_sqlsrv/pdo_stmt.cpp +++ b/pdo_sqlsrv/pdo_stmt.cpp @@ -3,7 +3,7 @@ // // Contents: Implements the PDOStatement object for the PDO_SQLSRV // -// Copyright 2010 Microsoft Corporation +// Copyright Microsoft Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -39,7 +39,10 @@ SQLSMALLINT odbc_fetch_orientation[] = const int SQL_SERVER_IDENT_SIZE_MAX = 128; inline SQLSMALLINT pdo_fetch_ori_to_odbc_fetch_ori (enum pdo_fetch_orientation ori) -{ +{ + SQLSRV_ASSERT( ori >= PDO_FETCH_ORI_NEXT && ori <= PDO_FETCH_ORI_REL, "Fetch orientation out of range." ); + OACR_WARNING_SUPPRESS( 26001, "Buffer length verified above" ); + OACR_WARNING_SUPPRESS( 26000, "Buffer length verified above" ); return odbc_fetch_orientation[ori]; } @@ -60,7 +63,8 @@ SQLSRV_PHPTYPE pdo_type_to_sqlsrv_php_type( sqlsrv_stmt* driver_stmt, enum pdo_p return SQLSRV_PHPTYPE_NULL; case PDO_PARAM_LOB: - return SQLSRV_PHPTYPE_STREAM; + // TODO: This will eventually be changed to SQLSRV_PHPTYPE_STREAM when output streaming is implemented. + return SQLSRV_PHPTYPE_STRING; case PDO_PARAM_STMT: THROW_PDO_ERROR( driver_stmt, PDO_SQLSRV_ERROR_PDO_STMT_UNSUPPORTED ); @@ -72,31 +76,6 @@ SQLSRV_PHPTYPE pdo_type_to_sqlsrv_php_type( sqlsrv_stmt* driver_stmt, enum pdo_p return SQLSRV_PHPTYPE_INVALID; // to prevent compiler warning } - -// Returns PDO type for a given SQLSRV type. See pdo_param_type -// for list of supported pdo types. -inline pdo_param_type sqlsrv_php_type_to_pdo_type( enum SQLSRV_PHPTYPE sqlsrv_php_type ) -{ - switch( sqlsrv_php_type ) { - - case SQLSRV_PHPTYPE_INT: - case SQLSRV_PHPTYPE_FLOAT: - return PDO_PARAM_INT; - - case SQLSRV_PHPTYPE_DATETIME: - case SQLSRV_PHPTYPE_STRING: - return PDO_PARAM_STR; - - case SQLSRV_PHPTYPE_STREAM: - return PDO_PARAM_LOB; - - case SQLSRV_PHPTYPE_NULL: - return PDO_PARAM_NULL; - - default: - DIE( "sqlsrv_php_type_to_pdo_type: Unexpected sqlsrv_php_type encountered." ); - } -} // Returns a pdo type for a given SQL type. See pdo_param_type // for list of supported pdo types. @@ -124,6 +103,7 @@ inline pdo_param_type sql_type_to_pdo_type( SQLSMALLINT sql_type ) case SQL_SS_TIME2: case SQL_SS_TIMESTAMPOFFSET: case SQL_SS_UDT: + case SQL_SS_VARIANT: case SQL_SS_XML: case SQL_TYPE_DATE: case SQL_TYPE_TIMESTAMP: @@ -173,6 +153,25 @@ void set_stmt_cursors( sqlsrv_stmt* stmt, zval* value_z TSRMLS_DC ) core_sqlsrv_set_scrollable( stmt, odbc_cursor_type TSRMLS_CC ); } +void set_stmt_cursor_scroll_type( sqlsrv_stmt* stmt, zval* value_z TSRMLS_DC ) +{ + if( Z_TYPE_P( value_z ) != IS_LONG ) { + + THROW_PDO_ERROR( stmt, PDO_SQLSRV_ERROR_INVALID_CURSOR_TYPE ); + } + + if( stmt->cursor_type == SQL_CURSOR_FORWARD_ONLY ) { + + THROW_PDO_ERROR( stmt, PDO_SQLSRV_ERROR_INVALID_CURSOR_WITH_SCROLL_TYPE ); + } + + long odbc_cursor_type = Z_LVAL_P( value_z ); + + core_sqlsrv_set_scrollable( stmt, odbc_cursor_type TSRMLS_CC ); + + return; +} + // Sets the statement encoding. Default encoding on the statement // implies use the connection's encoding. void set_stmt_encoding( sqlsrv_stmt* stmt, zval* value_z TSRMLS_DC ) @@ -201,17 +200,87 @@ void set_stmt_encoding( sqlsrv_stmt* stmt, zval* value_z TSRMLS_DC ) } } +// internal helper function to free meta data structures allocated +void meta_data_free( field_meta_data* meta ) +{ + sqlsrv_free( meta ); +} + +zval* convert_to_zval( SQLSRV_PHPTYPE sqlsrv_php_type, void** in_val, SQLLEN field_len ) +{ + zval* out_zval = NULL; + + switch( sqlsrv_php_type ) { + + case SQLSRV_PHPTYPE_INT: + case SQLSRV_PHPTYPE_FLOAT: + { + ALLOC_INIT_ZVAL( out_zval ); + if( *in_val == NULL ) { + ZVAL_NULL( out_zval ); + } + else { + + if( sqlsrv_php_type == SQLSRV_PHPTYPE_INT ) { + ZVAL_LONG( out_zval, **( reinterpret_cast( in_val ))); + } + else { + ZVAL_DOUBLE( out_zval, **( reinterpret_cast( in_val ))); + } + } + + if( *in_val ) { + sqlsrv_free( *in_val ); + } + + break; + } + + case SQLSRV_PHPTYPE_STRING: + case SQLSRV_PHPTYPE_STREAM: // TODO: this will be moved when output streaming is implemented + { + ALLOC_INIT_ZVAL( out_zval ); + + if( *in_val == NULL ) { + + ZVAL_NULL( out_zval ); + } + else { + + ZVAL_STRINGL( out_zval, reinterpret_cast( *in_val ), field_len, 0 /*duplicate*/ ); + } + break; + } + + case SQLSRV_PHPTYPE_DATETIME: + DIE( "Unsupported php type" ); + out_zval = ( reinterpret_cast( *in_val )); + break; + + case SQLSRV_PHPTYPE_NULL: + ALLOC_INIT_ZVAL( out_zval ); + ZVAL_NULL( out_zval ); + break; + + default: + DIE( "Unknown php type" ); + break; + } + + return out_zval; +} + } // namespace int pdo_sqlsrv_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC); int pdo_sqlsrv_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC); int pdo_sqlsrv_stmt_fetch(pdo_stmt_t *stmt, enum pdo_fetch_orientation ori, - long offset TSRMLS_DC); + long offset TSRMLS_DC); int pdo_sqlsrv_stmt_param_hook(pdo_stmt_t *stmt, - struct pdo_bound_param_data *param, enum pdo_param_event event_type TSRMLS_DC); + struct pdo_bound_param_data *param, enum pdo_param_event event_type TSRMLS_DC); int pdo_sqlsrv_stmt_describe_col(pdo_stmt_t *stmt, int colno TSRMLS_DC); int pdo_sqlsrv_stmt_get_col_data(pdo_stmt_t *stmt, int colno, - char **ptr, unsigned long *len, int *caller_frees TSRMLS_DC); + char **ptr, unsigned long *len, int *caller_frees TSRMLS_DC); int pdo_sqlsrv_stmt_set_attr(pdo_stmt_t *stmt, long attr, zval *val TSRMLS_DC); int pdo_sqlsrv_stmt_get_attr(pdo_stmt_t *stmt, long attr, zval *return_value TSRMLS_DC); int pdo_sqlsrv_stmt_get_col_meta(pdo_stmt_t *stmt, long colno, zval *return_value TSRMLS_DC); @@ -243,12 +312,25 @@ void stmt_option_encoding:: operator()( sqlsrv_stmt* stmt, stmt_option const* /* { set_stmt_encoding( stmt, value_z TSRMLS_CC ); } + void stmt_option_direct_query:: operator()( sqlsrv_stmt* stmt, stmt_option const* /*opt*/, zval* value_z TSRMLS_DC ) { pdo_sqlsrv_stmt *pdo_stmt = static_cast( stmt ); pdo_stmt->direct_query = ( zend_is_true( value_z )) ? true : false; } +void stmt_option_cursor_scroll_type:: operator()( sqlsrv_stmt* stmt, stmt_option const* /*opt*/, zval* value_z TSRMLS_DC ) +{ + set_stmt_cursor_scroll_type( stmt, value_z TSRMLS_CC ); +} + +void stmt_option_emulate_prepares:: operator()( sqlsrv_stmt* stmt, stmt_option const* /*opt*/, zval* value_z TSRMLS_DC ) +{ + pdo_stmt_t *pdo_stmt = static_cast( stmt->driver() ); + pdo_stmt->supports_placeholders = ( zend_is_true( value_z )) ? PDO_PLACEHOLDER_NONE : PDO_PLACEHOLDER_POSITIONAL; +} + + // log a function entry point #define PDO_LOG_STMT_ENTRY \ { \ @@ -257,6 +339,19 @@ void stmt_option_direct_query:: operator()( sqlsrv_stmt* stmt, stmt_option const LOG( SEV_NOTICE, __FUNCTION__ ## ": entering" ); \ } +// PDO SQLSRV statement destructor +pdo_sqlsrv_stmt::~pdo_sqlsrv_stmt( void ) +{ + std::for_each( current_meta_data.begin(), current_meta_data.end(), meta_data_free ); + current_meta_data.clear(); + + if( bound_column_param_types ) { + sqlsrv_free( bound_column_param_types ); + bound_column_param_types = NULL; + } +} + + // pdo_sqlsrv_stmt_close_cursor // Close any open cursors on the statement. Maps to PDO function PDOStatement::closeCursor. // Parameters: @@ -337,7 +432,7 @@ int pdo_sqlsrv_stmt_describe_col(pdo_stmt_t *stmt, int colno TSRMLS_DC) // Set the namelen column_data->namelen = core_meta_data->field_name_len; - + // Set the maxlen column_data->maxlen = ( core_meta_data->field_precision > 0 ) ? core_meta_data->field_precision : core_meta_data->field_size; @@ -345,10 +440,14 @@ int pdo_sqlsrv_stmt_describe_col(pdo_stmt_t *stmt, int colno TSRMLS_DC) column_data->precision = core_meta_data->field_scale; // Set the param_type - column_data->param_type = sql_type_to_pdo_type( core_meta_data->field_type ); + column_data->param_type = PDO_PARAM_ZVAL; - // always good to call destructor for allocations done through placement new operator. - core_meta_data->~field_meta_data(); + // store the field data for use by pdo_sqlsrv_stmt_get_col_data + pdo_sqlsrv_stmt* driver_stmt = reinterpret_cast( stmt->driver_data ); + SQLSRV_ASSERT( driver_stmt != NULL, "Invalid driver statement in pdo_sqlsrv_stmt_describe_col" ); + driver_stmt->current_meta_data.push_back( core_meta_data.get() ); + SQLSRV_ASSERT( driver_stmt->current_meta_data.size() == colno + 1, "Meta data vector out of sync with column numbers" ); + core_meta_data.transferred(); return 1; } @@ -407,8 +506,24 @@ int pdo_sqlsrv_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC) core_sqlsrv_next_result( driver_stmt TSRMLS_CC, false ); } } + + const char* query = NULL; + unsigned int query_len = 0; - core_sqlsrv_execute( driver_stmt TSRMLS_CC, driver_stmt->query, driver_stmt->query_len ); + // if the user is doing a direct query (PDO::SQLSRV_ATTR_DIRECT_QUERY), set the query here + if( driver_stmt->direct_query ) { + query = stmt->query_string; + query_len = stmt->query_stringlen; + } + + // if the user is using prepare emulation (PDO::ATTR_EMULATE_PREPARES), set the query to the + // subtituted query provided by PDO + if( stmt->supports_placeholders == PDO_PLACEHOLDER_NONE ) { + query = stmt->active_query_string; + query_len = stmt->active_query_stringlen; + } + + core_sqlsrv_execute( driver_stmt TSRMLS_CC, query, query_len ); stmt->column_count = core::SQLNumResultCols( driver_stmt TSRMLS_CC ); @@ -468,16 +583,48 @@ int pdo_sqlsrv_stmt_fetch(pdo_stmt_t *stmt, enum pdo_fetch_orientation ori, SQLSRV_ASSERT( stmt != NULL, "pdo_sqlsrv_stmt_fetch: pdo_stmt object was null" ); - sqlsrv_stmt* driver_stmt = reinterpret_cast( stmt->driver_data ); + pdo_sqlsrv_stmt* driver_stmt = reinterpret_cast( stmt->driver_data ); SQLSRV_ASSERT( driver_stmt != NULL, "pdo_sqlsrv_stmt_fetch: driver_data object was null" ); + // set the types for bound columns to zval so that PDO does no conversion when the value + // is returned by pdo_sqlsrv_get_col_data. Remember the types that were bound by the user + // and use it to manually convert data types + if( stmt->bound_columns ) { + + pdo_bound_param_data* bind_data = NULL; + + if( !driver_stmt->bound_column_param_types ) { + driver_stmt->bound_column_param_types = + reinterpret_cast( sqlsrv_malloc( stmt->column_count, sizeof( pdo_param_type ), 0 )); + std::fill( driver_stmt->bound_column_param_types, driver_stmt->bound_column_param_types + stmt->column_count, + PDO_PARAM_ZVAL ); + } + + for( long i = 0; i < stmt->column_count; ++i ) { + + if( zend_hash_index_find( stmt->bound_columns, i, (void**) &bind_data ) == FAILURE && + zend_hash_find( stmt->bound_columns, stmt->columns[ i ].name, stmt->columns[ i ].namelen, + (void**) &bind_data ) == FAILURE ) { + + driver_stmt->bound_column_param_types[ i ] = PDO_PARAM_ZVAL; + continue; + } + + if( bind_data->param_type != PDO_PARAM_ZVAL ) { + + driver_stmt->bound_column_param_types[ i ] = bind_data->param_type; + bind_data->param_type = PDO_PARAM_ZVAL; + } + } + } + SQLSMALLINT odbc_fetch_ori = pdo_fetch_ori_to_odbc_fetch_ori( ori ); bool data = core_sqlsrv_fetch( driver_stmt, odbc_fetch_ori, offset TSRMLS_CC ); // support for the PDO rowCount method. Since rowCount doesn't call a method, PDO relies on us to fill the // pdo_stmt_t::row_count member - if( driver_stmt->past_fetch_end || driver_stmt->scrollable ) { + if( driver_stmt->past_fetch_end || driver_stmt->cursor_type != SQL_CURSOR_FORWARD_ONLY ) { stmt->row_count = core::SQLRowCount( driver_stmt TSRMLS_CC ); @@ -531,7 +678,7 @@ int pdo_sqlsrv_stmt_get_col_data(pdo_stmt_t *stmt, int colno, SQLSRV_ASSERT( stmt != NULL, "pdo_sqlsrv_stmt_get_col_data: pdo_stmt object was null" ); - sqlsrv_stmt* driver_stmt = reinterpret_cast( stmt->driver_data ); + pdo_sqlsrv_stmt* driver_stmt = reinterpret_cast( stmt->driver_data ); SQLSRV_ASSERT( driver_stmt != NULL, "pdo_sqlsrv_stmt_get_col_data: driver_data object was null" ); @@ -547,12 +694,21 @@ int pdo_sqlsrv_stmt_get_col_data(pdo_stmt_t *stmt, int colno, // translate the pdo type to a type the core layer understands sqlsrv_phptype sqlsrv_php_type; - sqlsrv_php_type.typeinfo.type = pdo_type_to_sqlsrv_php_type( driver_stmt, column_data->param_type TSRMLS_CC ); + SQLSRV_ASSERT( colno >= 0 && colno < static_cast( driver_stmt->current_meta_data.size()), + "Invalid column number in pdo_sqlsrv_stmt_get_col_data" ); + sqlsrv_php_type = driver_stmt->sql_type_to_php_type( driver_stmt->current_meta_data[ colno ]->field_type, + driver_stmt->current_meta_data[ colno ]->field_size, true ); // set the encoding if the user specified one via bindColumn, otherwise use the statement's encoding sqlsrv_php_type.typeinfo.encoding = driver_stmt->encoding(); - if( stmt->bound_columns ) { + // if a column is bound to a type different than the column type, figure out a way to convert it to the + // type they want + if( stmt->bound_columns && driver_stmt->bound_column_param_types[ colno ] != PDO_PARAM_ZVAL ) { + + sqlsrv_php_type.typeinfo.type = pdo_type_to_sqlsrv_php_type( driver_stmt, + driver_stmt->bound_column_param_types[ colno ] + TSRMLS_CC ); pdo_bound_param_data* bind_data = NULL; int zr = zend_hash_index_find( stmt->bound_columns, colno, (void**) &bind_data ); @@ -560,13 +716,15 @@ int pdo_sqlsrv_stmt_get_col_data(pdo_stmt_t *stmt, int colno, if( bind_data != NULL && bind_data->driver_params != NULL ) { CHECK_CUSTOM_ERROR( Z_TYPE_P( bind_data->driver_params ) != IS_LONG, driver_stmt, - PDO_SQLSRV_ERROR_INVALID_COLUMN_DRIVER_DATA, colno ) { + PDO_SQLSRV_ERROR_INVALID_COLUMN_DRIVER_DATA, colno + 1 ) { throw pdo::PDOException(); } - CHECK_CUSTOM_ERROR( bind_data->param_type != PDO_PARAM_STR && bind_data->param_type != PDO_PARAM_LOB, - driver_stmt, PDO_SQLSRV_ERROR_COLUMN_TYPE_DOES_NOT_SUPPORT_ENCODING, colno ) { - throw pdo::PDOException(); + CHECK_CUSTOM_ERROR( driver_stmt->bound_column_param_types[ colno ] != PDO_PARAM_STR + && driver_stmt->bound_column_param_types[ colno ] != PDO_PARAM_LOB, driver_stmt, + PDO_SQLSRV_ERROR_COLUMN_TYPE_DOES_NOT_SUPPORT_ENCODING, colno + 1 ) { + + throw pdo::PDOException(); } sqlsrv_php_type.typeinfo.encoding = Z_LVAL_P( bind_data->driver_params ); @@ -582,9 +740,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( ptr ), - reinterpret_cast( len ), true, NULL TSRMLS_CC ); + reinterpret_cast( len ), true, &sqlsrv_phptype_out TSRMLS_CC ); + zval** zval_ptr = reinterpret_cast( sqlsrv_malloc( sizeof( zval* ))); + *zval_ptr = reinterpret_cast( convert_to_zval( sqlsrv_phptype_out, reinterpret_cast( ptr ), *len )); + *ptr = reinterpret_cast( zval_ptr ); + + *len = sizeof( zval ); return 1; } @@ -633,6 +797,14 @@ int pdo_sqlsrv_stmt_set_attr(pdo_stmt_t *stmt, long attr, zval *val TSRMLS_DC) core_sqlsrv_set_query_timeout( driver_stmt, val TSRMLS_CC ); break; + case SQLSRV_ATTR_CURSOR_SCROLL_TYPE: + THROW_PDO_ERROR( driver_stmt, PDO_SQLSRV_ERROR_CURSOR_ATTR_AT_PREPARE_ONLY ); + break; + + case SQLSRV_ATTR_CLIENT_BUFFER_MAX_KB_SIZE: + core_sqlsrv_set_buffered_query_limit( driver_stmt, val TSRMLS_CC ); + break; + default: THROW_PDO_ERROR( driver_stmt, PDO_SQLSRV_ERROR_INVALID_STMT_ATTR ); break; @@ -685,9 +857,23 @@ int pdo_sqlsrv_stmt_get_attr( pdo_stmt_t *stmt, long attr, zval *return_value TS case PDO_ATTR_CURSOR: { - ZVAL_LONG( return_value, ( driver_stmt->scrollable ? PDO_CURSOR_SCROLL : PDO_CURSOR_FWDONLY )); + ZVAL_LONG( return_value, ( driver_stmt->cursor_type != SQL_CURSOR_FORWARD_ONLY ? + PDO_CURSOR_SCROLL : PDO_CURSOR_FWDONLY )); break; } + + case SQLSRV_ATTR_CURSOR_SCROLL_TYPE: + { + ZVAL_LONG( return_value, driver_stmt->cursor_type ); + break; + } + + case SQLSRV_ATTR_CLIENT_BUFFER_MAX_KB_SIZE: + { + ZVAL_LONG( return_value, driver_stmt->buffered_query_limit ); + break; + } + case SQLSRV_ATTR_QUERY_TIMEOUT: { ZVAL_LONG( return_value, ( driver_stmt->query_timeout == QUERY_TIMEOUT_INVALID ? 0 : driver_stmt->query_timeout )); @@ -755,7 +941,8 @@ int pdo_sqlsrv_stmt_get_col_meta(pdo_stmt_t *stmt, long colno, zval *return_valu // get the PHP type of the column. The types returned here mirror the types returned by debug_zval_dump when // given a variable of the same type. However, debug_zval_dump also gives the length of a string, and we only // say string, since the length is given in another field of the metadata array. - switch( sql_type_to_pdo_type( core_meta_data->field_type )) { + long pdo_type = sql_type_to_pdo_type( core_meta_data->field_type ); + switch( pdo_type ) { case PDO_PARAM_STR: add_assoc_string( return_value, "native_type", "string", 1 ); break; @@ -770,7 +957,11 @@ int pdo_sqlsrv_stmt_get_col_meta(pdo_stmt_t *stmt, long colno, zval *return_valu core::SQLColAttribute( driver_stmt, (SQLUSMALLINT) colno + 1, SQL_DESC_TABLE_NAME, table_name, SQL_SERVER_IDENT_SIZE_MAX, &out_buff_len, &field_type_num TSRMLS_CC ); add_assoc_string( return_value, "table", table_name, 1 ); - + + if( stmt->columns[ colno ].param_type == PDO_PARAM_ZVAL ) { + add_assoc_long( return_value, "pdo_type", pdo_type ); + } + // this will ensure that the field_name field, which is an auto pointer gets freed. (*core_meta_data).~field_meta_data(); } @@ -807,12 +998,16 @@ int pdo_sqlsrv_stmt_next_rowset(pdo_stmt_t *stmt TSRMLS_DC) SQLSRV_ASSERT( stmt != NULL, "pdo_sqlsrv_stmt_next_rowset: pdo_stmt object was null" ); - sqlsrv_stmt* driver_stmt = reinterpret_cast( stmt->driver_data ); + pdo_sqlsrv_stmt* driver_stmt = reinterpret_cast( stmt->driver_data ); SQLSRV_ASSERT( driver_stmt != NULL, "pdo_sqlsrv_stmt_next_rowset: driver_data object was null" ); core_sqlsrv_next_result( static_cast( stmt->driver_data ) TSRMLS_CC ); + // clear the current meta data since the new result will generate new meta data + std::for_each( driver_stmt->current_meta_data.begin(), driver_stmt->current_meta_data.end(), meta_data_free ); + driver_stmt->current_meta_data.clear(); + // if there are no more result sets, return that it failed. if( driver_stmt->past_next_result_end == true ) { return 0; @@ -822,7 +1017,6 @@ int pdo_sqlsrv_stmt_next_rowset(pdo_stmt_t *stmt TSRMLS_DC) // return the row count regardless if there are any rows or not stmt->row_count = core::SQLRowCount( driver_stmt TSRMLS_CC ); - } catch( core::CoreException& ) { @@ -971,7 +1165,7 @@ int pdo_sqlsrv_stmt_param_hook(pdo_stmt_t *stmt, // 2.0 driver. To be consistent and avoid surprises of one object type working and others // not, we block all objects here. CHECK_CUSTOM_ERROR( direction != SQL_PARAM_OUTPUT && Z_TYPE_P( param->parameter ) == IS_OBJECT, - driver_stmt, SQLSRV_ERROR_INVALID_PARAMETER_PHPTYPE ) { + driver_stmt, SQLSRV_ERROR_INVALID_PARAMETER_PHPTYPE, param->paramno + 1 ) { throw pdo::PDOException(); } // the encoding by default is that set on the statement @@ -987,7 +1181,7 @@ int pdo_sqlsrv_stmt_param_hook(pdo_stmt_t *stmt, throw pdo::PDOException(); } CHECK_CUSTOM_ERROR( pdo_type != PDO_PARAM_STR && pdo_type != PDO_PARAM_LOB, driver_stmt, - PDO_SQLSRV_ERROR_INVALID_DRIVER_PARAM_TYPE, param->paramno ) { + PDO_SQLSRV_ERROR_INVALID_DRIVER_PARAM_TYPE, param->paramno + 1 ) { throw pdo::PDOException(); } encoding = static_cast( Z_LVAL_P( param->driver_params )); @@ -999,7 +1193,7 @@ int pdo_sqlsrv_stmt_param_hook(pdo_stmt_t *stmt, break; default: THROW_PDO_ERROR( driver_stmt, PDO_SQLSRV_ERROR_INVALID_DRIVER_PARAM_ENCODING, - param->paramno ); + param->paramno + 1 ); break; } } diff --git a/pdo_sqlsrv/pdo_util.cpp b/pdo_sqlsrv/pdo_util.cpp index a19537d4..c2bf2d84 100644 --- a/pdo_sqlsrv/pdo_util.cpp +++ b/pdo_sqlsrv/pdo_util.cpp @@ -3,7 +3,7 @@ // // Contents: Utility functions used by both connection or statement functions // -// Copyright 2010 Microsoft Corporation +// Copyright Microsoft Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -144,8 +144,8 @@ pdo_error PDO_ERRORS[] = { }, { SQLSRV_ERROR_UNESCAPED_RIGHT_BRACE_IN_DSN, - { IMSSP, (SQLCHAR*) "An unescaped right brace (}) was found in the DSN string for keyword '%1!s!'. All right braces must be escaped " - "with another right brace (}}).", -22, true } + { IMSSP, (SQLCHAR*) "An unescaped right brace (}) was found in the DSN string for keyword '%1!s!'. All right braces " + "must be escaped with another right brace (}}).", -22, true } }, { SQLSRV_ERROR_INVALID_OPTION_TYPE_INT, @@ -184,8 +184,8 @@ pdo_error PDO_ERRORS[] = { { IMSSP, (SQLCHAR*) "Invalid option key %1!s! specified.", -30, true } }, { - SQLSRV_ERROR_INVALID_OPTION_VALUE, - { IMSSP, (SQLCHAR*) "Invalid value specified for option %1!s!.", -31, true } + SQLSRV_ERROR_INVALID_QUERY_TIMEOUT_VALUE, + { IMSSP, (SQLCHAR*) "Invalid value %1!s! specified for option PDO::SQLSRV_ATTR_QUERY_TIMEOUT.", -31, true } }, { SQLSRV_ERROR_INVALID_OPTION_SCROLLABLE, @@ -238,7 +238,8 @@ pdo_error PDO_ERRORS[] = { }, { PDO_SQLSRV_ERROR_INVALID_CURSOR_TYPE, - { IMSSP, (SQLCHAR*) "An invalid cursor type was specified for the PDO cursor attribute", -44, false } + { IMSSP, (SQLCHAR*) "An invalid cursor type was specified for either PDO::ATTR_CURSOR or " + "PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE", -44, false } }, { PDO_SQLSRV_ERROR_PARAM_PARSE, @@ -277,8 +278,8 @@ pdo_error PDO_ERRORS[] = { }, { PDO_SQLSRV_ERROR_CURSOR_ATTR_AT_PREPARE_ONLY, - { IMSSP, (SQLCHAR*) "The PDO::ATTR_CURSOR attribute may only be set in the $driver_options array of PDO::prepare.", - -53, false } + { IMSSP, (SQLCHAR*) "The PDO::ATTR_CURSOR and PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE attributes may only be set in the " + "$driver_options array of PDO::prepare.", -53, false } }, { SQLSRV_ERROR_OUTPUT_PARAM_TRUNCATED, @@ -340,17 +341,33 @@ pdo_error PDO_ERRORS[] = { }, { PDO_SQLSRV_ERROR_EXTRA_SEMI_COLON_IN_DSN_STRING, - { IMSSP, (SQLCHAR*) "An extra semi-colon was encountered in the DSN string at character (byte-count) position '%1!d!' .", -66, true } + { IMSSP, (SQLCHAR*) "An extra semi-colon was encountered in the DSN string at character (byte-count) position '%1!d!' .", + -66, true } }, { PDO_SQLSRV_ERROR_RCB_MISSING_IN_DSN_VALUE, - { IMSSP, (SQLCHAR*) "An expected right brace (}) was not found in the DSN string for the value of the keyword '%1!s!'.", -67, true } + { IMSSP, (SQLCHAR*) "An expected right brace (}) was not found in the DSN string for the value of the keyword '%1!s!'.", + -67, true } }, { PDO_SQLSRV_ERROR_DQ_ATTR_AT_PREPARE_ONLY, { IMSSP, (SQLCHAR*) "The PDO::SQLSRV_ATTR_DIRECT_QUERY attribute may only be set in the $driver_options array of " "PDO::prepare.", -68, false } }, + { + PDO_SQLSRV_ERROR_INVALID_CURSOR_WITH_SCROLL_TYPE, + { IMSSP, (SQLCHAR*) "The PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE attribute may only be set when PDO::ATTR_CURSOR is set to " + "PDO::CURSOR_SCROLL in the $driver_options array of PDO::prepare.", -69, false } + }, + { + SQLSRV_ERROR_INVALID_BUFFER_LIMIT, + { IMSSP, (SQLCHAR*) "The PDO::SQLSRV_ATTR_CLIENT_BUFFER_MAX_KB_SIZE attribute is not a number or the number is not " + "positive. Only positive numbers are valid for this attribute.", -70, false } + }, + { + SQLSRV_ERROR_BUFFER_LIMIT_EXCEEDED, + { IMSSP, (SQLCHAR*) "Memory limit of %1!d! KB exceeded for buffered query", -71, true } + }, { -1, {} } }; @@ -378,7 +395,6 @@ bool pdo_sqlsrv_handle_env_error( sqlsrv_context& ctx, unsigned int sqlsrv_error SQLSRV_ASSERT(( dbh != NULL ), "pdo_sqlsrv_handle_env_error: pdo_dbh_t was null" ); sqlsrv_error_auto_ptr error; - error = new ( sqlsrv_malloc( sizeof( sqlsrv_error ))) sqlsrv_error; if( sqlsrv_error_code != SQLSRV_ERROR_ODBC ) { @@ -386,7 +402,8 @@ bool pdo_sqlsrv_handle_env_error( sqlsrv_context& ctx, unsigned int sqlsrv_error } else { - core_sqlsrv_get_odbc_error( ctx, 1, error, SEV_ERROR TSRMLS_CC ); + bool err = core_sqlsrv_get_odbc_error( ctx, 1, error, SEV_ERROR TSRMLS_CC ); + SQLSRV_ASSERT( err == true, "No ODBC error was found" ); } strcpy_s( dbh->error_code, sizeof( pdo_error_type ), reinterpret_cast( error->sqlstate )); @@ -420,14 +437,14 @@ bool pdo_sqlsrv_handle_dbh_error( sqlsrv_context& ctx, unsigned int sqlsrv_error SQLSRV_ASSERT( dbh != NULL, "pdo_sqlsrv_handle_dbh_error: Null dbh passed" ); sqlsrv_error_auto_ptr error; - error = new ( sqlsrv_malloc( sizeof( sqlsrv_error ))) sqlsrv_error; if( sqlsrv_error_code != SQLSRV_ERROR_ODBC ) { core_sqlsrv_format_driver_error( ctx, get_error_message( sqlsrv_error_code ), error, SEV_ERROR TSRMLS_CC, print_args ); } else { - core_sqlsrv_get_odbc_error( ctx, 1, error, SEV_ERROR TSRMLS_CC ); + bool err = core_sqlsrv_get_odbc_error( ctx, 1, error, SEV_ERROR TSRMLS_CC ); + SQLSRV_ASSERT( err == true, "No ODBC error was found" ); } SQLSRV_STATIC_ASSERT( sizeof( error->sqlstate ) <= sizeof( dbh->error_code )); @@ -474,13 +491,13 @@ bool pdo_sqlsrv_handle_stmt_error( sqlsrv_context& ctx, unsigned int sqlsrv_erro SQLSRV_ASSERT( pdo_stmt != NULL && pdo_stmt->dbh != NULL, "pdo_sqlsrv_handle_stmt_error: Null statement or dbh passed" ); sqlsrv_error_auto_ptr error; - error = new ( sqlsrv_malloc( sizeof( sqlsrv_error ))) sqlsrv_error; if( sqlsrv_error_code != SQLSRV_ERROR_ODBC ) { core_sqlsrv_format_driver_error( ctx, get_error_message( sqlsrv_error_code ), error, SEV_ERROR TSRMLS_CC, print_args ); } else { - core_sqlsrv_get_odbc_error( ctx, 1, error, SEV_ERROR TSRMLS_CC ); + bool err = core_sqlsrv_get_odbc_error( ctx, 1, error, SEV_ERROR TSRMLS_CC ); + SQLSRV_ASSERT( err == true, "No ODBC error was found" ); } SQLSRV_STATIC_ASSERT( sizeof( error->sqlstate ) <= sizeof( pdo_stmt->error_code )); diff --git a/pdo_sqlsrv/sqlncli.h b/pdo_sqlsrv/sqlncli.h new file mode 100644 index 00000000..518ddd4f --- /dev/null +++ b/pdo_sqlsrv/sqlncli.h @@ -0,0 +1,3043 @@ + + +/* this ALWAYS GENERATED file contains the definitions for the interfaces */ + + + /* File created by MIDL compiler version 7.00.0474 */ +/* Compiler settings for sqlncli.idl: + Oicf, W1, Zp8, env=Win32 (32b run) + protocol : dce , ms_ext, c_ext, robust + error checks: allocation ref bounds_check enum stub_data + VC __declspec() decoration level: + __declspec(uuid()), __declspec(selectany), __declspec(novtable) + DECLSPEC_UUID(), MIDL_INTERFACE() +*/ +//@@MIDL_FILE_HEADING( ) + +#pragma warning( disable: 4049 ) /* more than 64k source lines */ + + +/* verify that the version is high enough to compile this file*/ +#ifndef __REQUIRED_RPCNDR_H_VERSION__ +#define __REQUIRED_RPCNDR_H_VERSION__ 475 +#endif + +#include "rpc.h" +#include "rpcndr.h" + +#ifndef __RPCNDR_H_VERSION__ +#error this stub requires an updated version of +#endif // __RPCNDR_H_VERSION__ + +#ifndef COM_NO_WINDOWS_H +#include "windows.h" +#include "ole2.h" +#endif /*COM_NO_WINDOWS_H*/ + +#ifndef __sqlncli_h__ +#define __sqlncli_h__ + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +/* Forward Declarations */ + +#ifndef __ICommandWithParameters_FWD_DEFINED__ +#define __ICommandWithParameters_FWD_DEFINED__ +typedef interface ICommandWithParameters ICommandWithParameters; +#endif /* __ICommandWithParameters_FWD_DEFINED__ */ + + +#ifndef __IUMSInitialize_FWD_DEFINED__ +#define __IUMSInitialize_FWD_DEFINED__ +typedef interface IUMSInitialize IUMSInitialize; +#endif /* __IUMSInitialize_FWD_DEFINED__ */ + + +#ifndef __ISQLServerErrorInfo_FWD_DEFINED__ +#define __ISQLServerErrorInfo_FWD_DEFINED__ +typedef interface ISQLServerErrorInfo ISQLServerErrorInfo; +#endif /* __ISQLServerErrorInfo_FWD_DEFINED__ */ + + +#ifndef __IRowsetFastLoad_FWD_DEFINED__ +#define __IRowsetFastLoad_FWD_DEFINED__ +typedef interface IRowsetFastLoad IRowsetFastLoad; +#endif /* __IRowsetFastLoad_FWD_DEFINED__ */ + + +#ifndef __ISchemaLock_FWD_DEFINED__ +#define __ISchemaLock_FWD_DEFINED__ +typedef interface ISchemaLock ISchemaLock; +#endif /* __ISchemaLock_FWD_DEFINED__ */ + + +#ifndef __IBCPSession_FWD_DEFINED__ +#define __IBCPSession_FWD_DEFINED__ +typedef interface IBCPSession IBCPSession; +#endif /* __IBCPSession_FWD_DEFINED__ */ + + +#ifndef __ISSAbort_FWD_DEFINED__ +#define __ISSAbort_FWD_DEFINED__ +typedef interface ISSAbort ISSAbort; +#endif /* __ISSAbort_FWD_DEFINED__ */ + + +#ifndef __ISSCommandWithParameters_FWD_DEFINED__ +#define __ISSCommandWithParameters_FWD_DEFINED__ +typedef interface ISSCommandWithParameters ISSCommandWithParameters; +#endif /* __ISSCommandWithParameters_FWD_DEFINED__ */ + + +#ifndef __IDBAsynchStatus_FWD_DEFINED__ +#define __IDBAsynchStatus_FWD_DEFINED__ +typedef interface IDBAsynchStatus IDBAsynchStatus; +#endif /* __IDBAsynchStatus_FWD_DEFINED__ */ + + +#ifndef __ISSAsynchStatus_FWD_DEFINED__ +#define __ISSAsynchStatus_FWD_DEFINED__ +typedef interface ISSAsynchStatus ISSAsynchStatus; +#endif /* __ISSAsynchStatus_FWD_DEFINED__ */ + + +/* header files for imported files */ +#include "unknwn.h" +#include "oaidl.h" + +#ifdef __cplusplus +extern "C"{ +#endif + + +/* interface __MIDL_itf_sqlncli_0000_0000 */ +/* [local] */ + +//----------------------------------------------------------------------------- +// File: sqlncli.h +// +// Copyright: Copyright (c) Microsoft Corporation +// +// Contents: SQL Server Native Client OLEDB provider and ODBC driver specific +// definitions. +// +//----------------------------------------------------------------------------- + +#if !defined(SQLNCLI_VER) +#define SQLNCLI_VER 1000 +#endif + +#if SQLNCLI_VER >= 1000 + +#define SQLNCLI_PRODUCT_NAME_FULL_VER_ANSI "Microsoft SQL Server Native Client 10.0" +#define SQLNCLI_PRODUCT_NAME_FULL_ANSI "Microsoft SQL Server Native Client" +#define SQLNCLI_PRODUCT_NAME_SHORT_VER_ANSI "SQL Server Native Client 10.0" +#define SQLNCLI_PRODUCT_NAME_SHORT_ANSI "SQL Server Native Client" + +#define SQLNCLI_FILE_NAME_ANSI "sqlncli" +#define SQLNCLI_FILE_NAME_VER_ANSI "sqlncli10" +#define SQLNCLI_FILE_NAME_FULL_ANSI "sqlncli10.dll" + +#define SQLNCLI_PRODUCT_NAME_FULL_VER_UNICODE L"Microsoft SQL Server Native Client 10.0" +#define SQLNCLI_PRODUCT_NAME_FULL_UNICODE L"Microsoft SQL Server Native Client" +#define SQLNCLI_PRODUCT_NAME_SHORT_VER_UNICODE L"SQL Server Native Client 10.0" +#define SQLNCLI_PRODUCT_NAME_SHORT_UNICODE L"SQL Server Native Client" + +#define SQLNCLI_FILE_NAME_UNICODE L"sqlncli" +#define SQLNCLI_FILE_NAME_VER_UNICODE L"sqlncli10" +#define SQLNCLI_FILE_NAME_FULL_UNICODE L"sqlncli10.dll" + +#if defined(_SQLNCLI_OLEDB_) || !defined(_SQLNCLI_ODBC_) + +#define SQLNCLI_VI_PROG_ID_ANSI "SQLNCLI10" +#define SQLNCLI_VI_ERROR_LOOKUP_PROG_ID_ANSI "SQLNCLI10 ErrorLookup" +#define SQLNCLI_VI_ENUMERATOR_PROG_ID_ANSI "SQLNCLI10 Enumerator" + +#define SQLNCLI_PROG_ID_ANSI "SQLNCLI10.1" +#define SQLNCLI_ERROR_LOOKUP_PROG_ID_ANSI "SQLNCLI10 ErrorLookup.1" +#define SQLNCLI_ENUMERATOR_PROG_ID_ANSI "SQLNCLI10 Enumerator.1" + +#define SQLNCLI_VI_PROG_ID_UNICODE L"SQLNCLI10" +#define SQLNCLI_VI_ERROR_LOOKUP_PROG_ID_UNICODE L"SQLNCLI10 ErrorLookup" +#define SQLNCLI_VI_ENUMERATOR_PROG_ID_UNICODE L"SQLNCLI10 Enumerator" + +#define SQLNCLI_PROG_ID_UNICODE L"SQLNCLI10.1" +#define SQLNCLI_ERROR_LOOKUP_PROG_ID_UNICODE L"SQLNCLI10 ErrorLookup.1" +#define SQLNCLI_ENUMERATOR_PROG_ID_UNICODE L"SQLNCLI10 Enumerator.1" + +#define SQLNCLI_CLSID CLSID_SQLNCLI10 +#define SQLNCLI_ERROR_CLSID CLSID_SQLNCLI10_ERROR +#define SQLNCLI_ENUMERATOR_CLSID CLSID_SQLNCLI10_ENUMERATOR + +#endif // defined(_SQLNCLI_OLEDB_) || !defined(_SQLNCLI_ODBC_) + +#else // SQLNCLI_VER >= 1000 + +#define SQLNCLI_PRODUCT_NAME_FULL_VER_ANSI "Microsoft SQL Server Native Client" +#define SQLNCLI_PRODUCT_NAME_FULL_ANSI "Microsoft SQL Server Native Client" +#define SQLNCLI_PRODUCT_NAME_SHORT_VER_ANSI "SQL Native Client" +#define SQLNCLI_PRODUCT_NAME_SHORT_ANSI "SQL Native Client" + +#define SQLNCLI_FILE_NAME_ANSI "sqlncli" +#define SQLNCLI_FILE_NAME_VER_ANSI "sqlncli" +#define SQLNCLI_FILE_NAME_FULL_ANSI "sqlncli.dll" + +#define SQLNCLI_PRODUCT_NAME_FULL_VER_UNICODE L"Microsoft SQL Server Native Client" +#define SQLNCLI_PRODUCT_NAME_FULL_UNICODE L"Microsoft SQL Server Native Client" +#define SQLNCLI_PRODUCT_NAME_SHORT_VER_UNICODE L"SQL Native Client" +#define SQLNCLI_PRODUCT_NAME_SHORT_UNICODE L"SQL Native Client" + +#define SQLNCLI_FILE_NAME_UNICODE L"sqlncli" +#define SQLNCLI_FILE_NAME_VER_UNICODE L"sqlncli" +#define SQLNCLI_FILE_NAME_FULL_UNICODE L"sqlncli.dll" + +#if defined(_SQLNCLI_OLEDB_) || !defined(_SQLNCLI_ODBC_) + +#define SQLNCLI_VI_PROG_ID_ANSI "SQLNCLI" +#define SQLNCLI_VI_ERROR_LOOKUP_PROG_ID_ANSI "SQLNCLI ErrorLookup" +#define SQLNCLI_VI_ENUMERATOR_PROG_ID_ANSI "SQLNCLI Enumerator" + +#define SQLNCLI_PROG_ID_ANSI "SQLNCLI.1" +#define SQLNCLI_ERROR_LOOKUP_PROG_ID_ANSI "SQLNCLI ErrorLookup.1" +#define SQLNCLI_ENUMERATOR_PROG_ID_ANSI "SQLNCLI Enumerator.1" + +#define SQLNCLI_VI_PROG_ID_UNICODE L"SQLNCLI" +#define SQLNCLI_VI_ERROR_LOOKUP_PROG_ID_UNICODE L"SQLNCLI ErrorLookup" +#define SQLNCLI_VI_ENUMERATOR_PROG_ID_UNICODE L"SQLNCLI Enumerator" + +#define SQLNCLI_PROG_ID_UNICODE L"SQLNCLI.1" +#define SQLNCLI_ERROR_LOOKUP_PROG_ID_UNICODE L"SQLNCLI ErrorLookup.1" +#define SQLNCLI_ENUMERATOR_PROG_ID_UNICODE L"SQLNCLI Enumerator.1" + +#define SQLNCLI_CLSID CLSID_SQLNCLI +#define SQLNCLI_ERROR_CLSID CLSID_SQLNCLI_ERROR +#define SQLNCLI_ENUMERATOR_CLSID CLSID_SQLNCLI_ENUMERATOR + +#endif // defined(_SQLNCLI_OLEDB_) || !defined(_SQLNCLI_ODBC_) + +#endif // SQLNCLI_VER >= 1000 + +// define the character type agnostic constants +#if defined(_UNICODE) || defined(UNICODE) + +#define SQLNCLI_PRODUCT_NAME_FULL_VER SQLNCLI_PRODUCT_NAME_FULL_VER_UNICODE +#define SQLNCLI_PRODUCT_NAME_FULL SQLNCLI_PRODUCT_NAME_FULL_UNICODE +#define SQLNCLI_PRODUCT_NAME_SHORT_VER SQLNCLI_PRODUCT_NAME_SHORT_VER_UNICODE +#define SQLNCLI_PRODUCT_NAME_SHORT SQLNCLI_PRODUCT_NAME_SHORT_UNICODE + +#define SQLNCLI_FILE_NAME SQLNCLI_FILE_NAME_UNICODE +#define SQLNCLI_FILE_NAME_VER SQLNCLI_FILE_NAME_VER_UNICODE +#define SQLNCLI_FILE_NAME_FULL SQLNCLI_FILE_NAME_FULL_UNICODE + +#if defined(_SQLNCLI_OLEDB_) || !defined(_SQLNCLI_ODBC_) + +#define SQLNCLI_VI_PROG_ID SQLNCLI_VI_PROG_ID_UNICODE +#define SQLNCLI_VI_ERROR_LOOKUP_PROG_ID SQLNCLI_VI_ERROR_LOOKUP_PROG_ID_UNICODE +#define SQLNCLI_VI_ENUMERATOR_PROG_ID SQLNCLI_VI_ENUMERATOR_PROG_ID_UNICODE + +#define SQLNCLI_PROG_ID SQLNCLI_PROG_ID_UNICODE +#define SQLNCLI_ERROR_LOOKUP_PROG_ID SQLNCLI_ERROR_LOOKUP_PROG_ID_UNICODE +#define SQLNCLI_ENUMERATOR_PROG_ID SQLNCLI_ENUMERATOR_PROG_ID_UNICODE + +#endif // defined(_SQLNCLI_OLEDB_) || !defined(_SQLNCLI_ODBC_) + +#else // _UNICODE || UNICODE + +#define SQLNCLI_PRODUCT_NAME_FULL_VER SQLNCLI_PRODUCT_NAME_FULL_VER_ANSI +#define SQLNCLI_PRODUCT_NAME_FULL SQLNCLI_PRODUCT_NAME_FULL_ANSI +#define SQLNCLI_PRODUCT_NAME_SHORT_VER SQLNCLI_PRODUCT_NAME_SHORT_VER_ANSI +#define SQLNCLI_PRODUCT_NAME_SHORT SQLNCLI_PRODUCT_NAME_SHORT_ANSI + +#define SQLNCLI_FILE_NAME SQLNCLI_FILE_NAME_ANSI +#define SQLNCLI_FILE_NAME_VER SQLNCLI_FILE_NAME_VER_ANSI +#define SQLNCLI_FILE_NAME_FULL SQLNCLI_FILE_NAME_FULL_ANSI + +#if defined(_SQLNCLI_OLEDB_) || !defined(_SQLNCLI_ODBC_) + +#define SQLNCLI_VI_PROG_ID SQLNCLI_VI_PROG_ID_ANSI +#define SQLNCLI_VI_ERROR_LOOKUP_PROG_ID SQLNCLI_VI_ERROR_LOOKUP_PROG_ID_ANSI +#define SQLNCLI_VI_ENUMERATOR_PROG_ID SQLNCLI_VI_ENUMERATOR_PROG_ID_ANSI + +#define SQLNCLI_PROG_ID SQLNCLI_PROG_ID_ANSI +#define SQLNCLI_ERROR_LOOKUP_PROG_ID SQLNCLI_ERROR_LOOKUP_PROG_ID_ANSI +#define SQLNCLI_ENUMERATOR_PROG_ID SQLNCLI_ENUMERATOR_PROG_ID_ANSI + +#endif // defined(_SQLNCLI_OLEDB_) || !defined(_SQLNCLI_ODBC_) + +#endif // _UNICODE || UNICODE + +#if defined(_SQLNCLI_ODBC_) || !defined(_SQLNCLI_OLEDB_) + +#define SQLNCLI_DRIVER_NAME SQLNCLI_PRODUCT_NAME_SHORT_VER + +#endif + +// OLEDB part of SQL Server Native Client header - begin here +#if defined(_SQLNCLI_OLEDB_) || !defined(_SQLNCLI_ODBC_) +#ifndef __oledb_h__ +#include +#endif /*__oledb_h__*/ + +#if 0 // This is already defined in oledb.h + +#ifdef _WIN64 + +// Length of a non-character object, size +typedef ULONGLONG DBLENGTH; + +// Offset within a rowset +typedef LONGLONG DBROWOFFSET; + +// Number of rows +typedef LONGLONG DBROWCOUNT; + +typedef ULONGLONG DBCOUNTITEM; + +// Ordinal (column number, etc.) +typedef ULONGLONG DBORDINAL; + +typedef LONGLONG DB_LORDINAL; + +// Bookmarks +typedef ULONGLONG DBBKMARK; +// Offset in the buffer + +typedef ULONGLONG DBBYTEOFFSET; +// Reference count of each row/accessor handle + +typedef ULONG DBREFCOUNT; + +// Parameters +typedef ULONGLONG DB_UPARAMS; + +typedef LONGLONG DB_LPARAMS; + +// hash values corresponding to the elements (bookmarks) +typedef DWORDLONG DBHASHVALUE; + +// For reserve +typedef DWORDLONG DB_DWRESERVE; + +typedef LONGLONG DB_LRESERVE; + +typedef ULONGLONG DB_URESERVE; + +#else //_WIN64 + +// Length of a non-character object, size +typedef ULONG DBLENGTH; + +// Offset within a rowset +typedef LONG DBROWOFFSET; + +// Number of rows +typedef LONG DBROWCOUNT; + +typedef ULONG DBCOUNTITEM; + +// Ordinal (column number, etc.) +typedef ULONG DBORDINAL; + +typedef LONG DB_LORDINAL; + +// Bookmarks +typedef ULONG DBBKMARK; + +// Offset in the buffer +typedef ULONG DBBYTEOFFSET; + +// Reference count of each row handle +typedef ULONG DBREFCOUNT; + +// Parameters +typedef ULONG DB_UPARAMS; + +typedef LONG DB_LPARAMS; + +// hash values corresponding to the elements (bookmarks) +typedef DWORD DBHASHVALUE; + +// For reserve +typedef DWORD DB_DWRESERVE; + +typedef LONG DB_LRESERVE; + +typedef ULONG DB_URESERVE; + +#endif // _WIN64 +typedef DWORD DBKIND; + + +enum DBKINDENUM + { DBKIND_GUID_NAME = 0, + DBKIND_GUID_PROPID = ( DBKIND_GUID_NAME + 1 ) , + DBKIND_NAME = ( DBKIND_GUID_PROPID + 1 ) , + DBKIND_PGUID_NAME = ( DBKIND_NAME + 1 ) , + DBKIND_PGUID_PROPID = ( DBKIND_PGUID_NAME + 1 ) , + DBKIND_PROPID = ( DBKIND_PGUID_PROPID + 1 ) , + DBKIND_GUID = ( DBKIND_PROPID + 1 ) + } ; +typedef struct tagDBID + { + union + { + GUID guid; + GUID *pguid; + /* Empty union arm */ + } uGuid; + DBKIND eKind; + union + { + LPOLESTR pwszName; + ULONG ulPropid; + /* Empty union arm */ + } uName; + } DBID; + +typedef struct tagDB_NUMERIC + { + BYTE precision; + BYTE scale; + BYTE sign; + BYTE val[ 16 ]; + } DB_NUMERIC; + +typedef struct tagDBDATE + { + SHORT year; + USHORT month; + USHORT day; + } DBDATE; + +typedef struct tagDBTIME + { + USHORT hour; + USHORT minute; + USHORT second; + } DBTIME; + +typedef struct tagDBTIMESTAMP + { + SHORT year; + USHORT month; + USHORT day; + USHORT hour; + USHORT minute; + USHORT second; + ULONG fraction; + } DBTIMESTAMP; + +typedef struct tagDBOBJECT + { + DWORD dwFlags; + IID iid; + } DBOBJECT; + +typedef WORD DBTYPE; + +typedef ULONG_PTR HACCESSOR; + +typedef ULONG_PTR HCHAPTER; + +typedef DWORD DBPARAMFLAGS; + +typedef struct tagDBPARAMINFO + { + DBPARAMFLAGS dwFlags; + DBORDINAL iOrdinal; + LPOLESTR pwszName; + ITypeInfo *pTypeInfo; + DBLENGTH ulParamSize; + DBTYPE wType; + BYTE bPrecision; + BYTE bScale; + } DBPARAMINFO; + +typedef DWORD DBPROPID; + +typedef struct tagDBPROPIDSET + { + DBPROPID *rgPropertyIDs; + ULONG cPropertyIDs; + GUID guidPropertySet; + } DBPROPIDSET; + +typedef DWORD DBPROPFLAGS; + +typedef DWORD DBPROPOPTIONS; + +typedef DWORD DBPROPSTATUS; + +typedef struct tagDBPROP + { + DBPROPID dwPropertyID; + DBPROPOPTIONS dwOptions; + DBPROPSTATUS dwStatus; + DBID colid; + VARIANT vValue; + } DBPROP; + +typedef struct tagDBPROPSET + { + DBPROP *rgProperties; + ULONG cProperties; + GUID guidPropertySet; + } DBPROPSET; + + + +extern RPC_IF_HANDLE __MIDL_itf_sqlncli_0000_0000_v0_0_c_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_sqlncli_0000_0000_v0_0_s_ifspec; + +#ifndef __ICommandWithParameters_INTERFACE_DEFINED__ +#define __ICommandWithParameters_INTERFACE_DEFINED__ + +/* interface ICommandWithParameters */ +/* [unique][uuid][object][local] */ + +typedef struct tagDBPARAMBINDINFO + { + LPOLESTR pwszDataSourceType; + LPOLESTR pwszName; + DBLENGTH ulParamSize; + DBPARAMFLAGS dwFlags; + BYTE bPrecision; + BYTE bScale; + } DBPARAMBINDINFO; + + +EXTERN_C const IID IID_ICommandWithParameters; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("0c733a64-2a1c-11ce-ade5-00aa0044773d") + ICommandWithParameters : public IUnknown + { + public: + virtual /* [local] */ HRESULT STDMETHODCALLTYPE GetParameterInfo( + /* [out][in] */ DB_UPARAMS *pcParams, + /* [size_is][size_is][out] */ DBPARAMINFO **prgParamInfo, + /* [out] */ OLECHAR **ppNamesBuffer) = 0; + + virtual /* [local] */ HRESULT STDMETHODCALLTYPE MapParameterNames( + /* [in] */ DB_UPARAMS cParamNames, + /* [size_is][in] */ const OLECHAR *rgParamNames[ ], + /* [size_is][out] */ DB_LPARAMS rgParamOrdinals[ ]) = 0; + + virtual /* [local] */ HRESULT STDMETHODCALLTYPE SetParameterInfo( + /* [in] */ DB_UPARAMS cParams, + /* [size_is][unique][in] */ const DB_UPARAMS rgParamOrdinals[ ], + /* [size_is][unique][in] */ const DBPARAMBINDINFO rgParamBindInfo[ ]) = 0; + + }; + +#else /* C style interface */ + + typedef struct ICommandWithParametersVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICommandWithParameters * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICommandWithParameters * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICommandWithParameters * This); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *GetParameterInfo )( + ICommandWithParameters * This, + /* [out][in] */ DB_UPARAMS *pcParams, + /* [size_is][size_is][out] */ DBPARAMINFO **prgParamInfo, + /* [out] */ OLECHAR **ppNamesBuffer); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *MapParameterNames )( + ICommandWithParameters * This, + /* [in] */ DB_UPARAMS cParamNames, + /* [size_is][in] */ const OLECHAR *rgParamNames[ ], + /* [size_is][out] */ DB_LPARAMS rgParamOrdinals[ ]); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *SetParameterInfo )( + ICommandWithParameters * This, + /* [in] */ DB_UPARAMS cParams, + /* [size_is][unique][in] */ const DB_UPARAMS rgParamOrdinals[ ], + /* [size_is][unique][in] */ const DBPARAMBINDINFO rgParamBindInfo[ ]); + + END_INTERFACE + } ICommandWithParametersVtbl; + + interface ICommandWithParameters + { + CONST_VTBL struct ICommandWithParametersVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICommandWithParameters_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICommandWithParameters_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICommandWithParameters_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICommandWithParameters_GetParameterInfo(This,pcParams,prgParamInfo,ppNamesBuffer) \ + ( (This)->lpVtbl -> GetParameterInfo(This,pcParams,prgParamInfo,ppNamesBuffer) ) + +#define ICommandWithParameters_MapParameterNames(This,cParamNames,rgParamNames,rgParamOrdinals) \ + ( (This)->lpVtbl -> MapParameterNames(This,cParamNames,rgParamNames,rgParamOrdinals) ) + +#define ICommandWithParameters_SetParameterInfo(This,cParams,rgParamOrdinals,rgParamBindInfo) \ + ( (This)->lpVtbl -> SetParameterInfo(This,cParams,rgParamOrdinals,rgParamBindInfo) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE ICommandWithParameters_RemoteGetParameterInfo_Proxy( + ICommandWithParameters * This, + /* [out][in] */ DB_UPARAMS *pcParams, + /* [size_is][size_is][out] */ DBPARAMINFO **prgParamInfo, + /* [size_is][size_is][out] */ DBBYTEOFFSET **prgNameOffsets, + /* [out][in] */ DBLENGTH *pcbNamesBuffer, + /* [size_is][size_is][unique][out][in] */ OLECHAR **ppNamesBuffer, + /* [out] */ IErrorInfo **ppErrorInfoRem); + + +void __RPC_STUB ICommandWithParameters_RemoteGetParameterInfo_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase); + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE ICommandWithParameters_RemoteMapParameterNames_Proxy( + ICommandWithParameters * This, + /* [in] */ DB_UPARAMS cParamNames, + /* [size_is][in] */ LPCOLESTR *rgParamNames, + /* [size_is][out] */ DB_LPARAMS *rgParamOrdinals, + /* [out] */ IErrorInfo **ppErrorInfoRem); + + +void __RPC_STUB ICommandWithParameters_RemoteMapParameterNames_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase); + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE ICommandWithParameters_RemoteSetParameterInfo_Proxy( + ICommandWithParameters * This, + /* [in] */ DB_UPARAMS cParams, + /* [size_is][unique][in] */ const DB_UPARAMS *rgParamOrdinals, + /* [size_is][unique][in] */ const DBPARAMBINDINFO *rgParamBindInfo, + /* [out] */ IErrorInfo **ppErrorInfoRem); + + +void __RPC_STUB ICommandWithParameters_RemoteSetParameterInfo_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase); + + + +#endif /* __ICommandWithParameters_INTERFACE_DEFINED__ */ + + +/* interface __MIDL_itf_sqlncli_0000_0001 */ +/* [local] */ + +typedef DWORD DBASYNCHOP; + +typedef DWORD DBASYNCHPHASE; + +#endif // This is already defined in oledb.h + +//------------------------------------------------------------------- +// Variant Access macros, similar to ole automation. +//------------------------------------------------------------------- +#define V_SS_VT(X) ((X)->vt) +#define V_SS_UNION(X, Y) ((X)->Y) + +#define V_SS_UI1(X) V_SS_UNION(X, bTinyIntVal) +#define V_SS_I2(X) V_SS_UNION(X, sShortIntVal) +#define V_SS_I4(X) V_SS_UNION(X, lIntVal) +#define V_SS_I8(X) V_SS_UNION(X, llBigIntVal) + +#define V_SS_R4(X) V_SS_UNION(X, fltRealVal) +#define V_SS_R8(X) V_SS_UNION(X, dblFloatVal) +#define V_SS_UI4(X) V_SS_UNION(X, ulVal) + +#define V_SS_MONEY(X) V_SS_UNION(X, cyMoneyVal) +#define V_SS_SMALLMONEY(X) V_SS_UNION(X, cyMoneyVal) + +#define V_SS_WSTRING(X) V_SS_UNION(X, NCharVal) +#define V_SS_WVARSTRING(X) V_SS_UNION(X, NCharVal) + +#define V_SS_STRING(X) V_SS_UNION(X, CharVal) +#define V_SS_VARSTRING(X) V_SS_UNION(X, CharVal) + +#define V_SS_BIT(X) V_SS_UNION(X, fBitVal) +#define V_SS_GUID(X) V_SS_UNION(X, rgbGuidVal) + +#define V_SS_NUMERIC(X) V_SS_UNION(X, numNumericVal) +#define V_SS_DECIMAL(X) V_SS_UNION(X, numNumericVal) + +#define V_SS_BINARY(X) V_SS_UNION(X, BinaryVal) +#define V_SS_VARBINARY(X) V_SS_UNION(X, BinaryVal) + +#define V_SS_DATETIME(X) V_SS_UNION(X, tsDateTimeVal) +#define V_SS_SMALLDATETIME(X) V_SS_UNION(X, tsDateTimeVal) + +#define V_SS_UNKNOWN(X) V_SS_UNION(X, UnknownType) + +//Text and image types. +#define V_SS_IMAGE(X) V_SS_UNION(X, ImageVal) +#define V_SS_TEXT(X) V_SS_UNION(X, TextVal) +#define V_SS_NTEXT(X) V_SS_UNION(X, NTextVal) + +//Microsoft SQL Server 2008 datetime. +#define V_SS_DATE(X) V_SS_UNION(X, dDateVal) +#define V_SS_TIME2(X) V_SS_UNION(X, Time2Val) +#define V_SS_DATETIME2(X) V_SS_UNION(X, DateTimeVal) +#define V_SS_DATETIMEOFFSET(X) V_SS_UNION(X, DateTimeOffsetVal) + +//------------------------------------------------------------------- +// define SQL Server specific types. +//------------------------------------------------------------------- +typedef enum DBTYPEENUM EOledbTypes; +#define DBTYPE_XML ((EOledbTypes) 141) // introduced in SQL 2005 +#define DBTYPE_TABLE ((EOledbTypes) 143) // introduced in SQL 2008 +#define DBTYPE_DBTIME2 ((EOledbTypes) 145) // introduced in SQL 2008 +#define DBTYPE_DBTIMESTAMPOFFSET ((EOledbTypes) 146) // introduced in SQL 2008 +#ifdef _SQLOLEDB_H_ +#undef DBTYPE_SQLVARIANT +#endif //_SQLOLEDB_H_ +#define DBTYPE_SQLVARIANT ((EOledbTypes) 144) // introduced in MDAC 2.5 + + +#ifndef _SQLOLEDB_H_ +enum SQLVARENUM + { + VT_SS_EMPTY = DBTYPE_EMPTY, + VT_SS_NULL = DBTYPE_NULL, + VT_SS_UI1 = DBTYPE_UI1, + VT_SS_I2 = DBTYPE_I2, + VT_SS_I4 = DBTYPE_I4, + VT_SS_I8 = DBTYPE_I8, + + //Floats + VT_SS_R4 = DBTYPE_R4, + VT_SS_R8 = DBTYPE_R8, + + //Money + VT_SS_MONEY = DBTYPE_CY, + VT_SS_SMALLMONEY = 200, + + //Strings + VT_SS_WSTRING = 201, + VT_SS_WVARSTRING = 202, + + VT_SS_STRING = 203, + VT_SS_VARSTRING = 204, + + //Bit + VT_SS_BIT = DBTYPE_BOOL, + + //Guid + VT_SS_GUID = DBTYPE_GUID, + + //Exact precision + VT_SS_NUMERIC = DBTYPE_NUMERIC, + VT_SS_DECIMAL = 205, + + //Datetime + VT_SS_DATETIME = DBTYPE_DBTIMESTAMP, + VT_SS_SMALLDATETIME =206, + + //Binary + VT_SS_BINARY =207, + VT_SS_VARBINARY = 208, + //Future + VT_SS_UNKNOWN = 209, + + //Additional datetime + VT_SS_DATE = DBTYPE_DBDATE, + VT_SS_TIME2 = DBTYPE_DBTIME2, + VT_SS_DATETIME2 = 212, + VT_SS_DATETIMEOFFSET = DBTYPE_DBTIMESTAMPOFFSET, + }; +typedef unsigned short SSVARTYPE; + + +enum DBPARAMFLAGSENUM_SS_100 + { DBPARAMFLAGS_SS_ISVARIABLESCALE = 0x40000000 + } ; +enum DBCOLUMNFLAGSENUM_SS_100 + { DBCOLUMNFLAGS_SS_ISVARIABLESCALE = 0x40000000, + DBCOLUMNFLAGS_SS_ISCOLUMNSET = 0x80000000 + } ; + +//------------------------------------------------------------------- +// Class Factory Interface used to initialize pointer to UMS. +//------------------------------------------------------------------- + + +extern RPC_IF_HANDLE __MIDL_itf_sqlncli_0000_0001_v0_0_c_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_sqlncli_0000_0001_v0_0_s_ifspec; + +#ifndef __IUMSInitialize_INTERFACE_DEFINED__ +#define __IUMSInitialize_INTERFACE_DEFINED__ + +/* interface IUMSInitialize */ +/* [unique][uuid][object][local] */ + + +EXTERN_C const IID IID_IUMSInitialize; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("5cf4ca14-ef21-11d0-97e7-00c04fc2ad98") + IUMSInitialize : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Initialize( + /* [in] */ void *pUMS) = 0; + + }; + +#else /* C style interface */ + + typedef struct IUMSInitializeVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IUMSInitialize * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IUMSInitialize * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IUMSInitialize * This); + + HRESULT ( STDMETHODCALLTYPE *Initialize )( + IUMSInitialize * This, + /* [in] */ void *pUMS); + + END_INTERFACE + } IUMSInitializeVtbl; + + interface IUMSInitialize + { + CONST_VTBL struct IUMSInitializeVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IUMSInitialize_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IUMSInitialize_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IUMSInitialize_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IUMSInitialize_Initialize(This,pUMS) \ + ( (This)->lpVtbl -> Initialize(This,pUMS) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IUMSInitialize_INTERFACE_DEFINED__ */ + + +/* interface __MIDL_itf_sqlncli_0000_0002 */ +/* [local] */ + + +// the structure returned by ISQLServerErrorInfo::GetSQLServerInfo +typedef struct tagSSErrorInfo + { + LPOLESTR pwszMessage; + LPOLESTR pwszServer; + LPOLESTR pwszProcedure; + LONG lNative; + BYTE bState; + BYTE bClass; + WORD wLineNumber; + } SSERRORINFO; + + + +extern RPC_IF_HANDLE __MIDL_itf_sqlncli_0000_0002_v0_0_c_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_sqlncli_0000_0002_v0_0_s_ifspec; + +#ifndef __ISQLServerErrorInfo_INTERFACE_DEFINED__ +#define __ISQLServerErrorInfo_INTERFACE_DEFINED__ + +/* interface ISQLServerErrorInfo */ +/* [unique][uuid][object][local] */ + + +EXTERN_C const IID IID_ISQLServerErrorInfo; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("5CF4CA12-EF21-11d0-97E7-00C04FC2AD98") + ISQLServerErrorInfo : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetErrorInfo( + /* [out] */ SSERRORINFO **ppErrorInfo, + /* [out] */ OLECHAR **ppStringsBuffer) = 0; + + }; + +#else /* C style interface */ + + typedef struct ISQLServerErrorInfoVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ISQLServerErrorInfo * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ISQLServerErrorInfo * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ISQLServerErrorInfo * This); + + HRESULT ( STDMETHODCALLTYPE *GetErrorInfo )( + ISQLServerErrorInfo * This, + /* [out] */ SSERRORINFO **ppErrorInfo, + /* [out] */ OLECHAR **ppStringsBuffer); + + END_INTERFACE + } ISQLServerErrorInfoVtbl; + + interface ISQLServerErrorInfo + { + CONST_VTBL struct ISQLServerErrorInfoVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ISQLServerErrorInfo_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ISQLServerErrorInfo_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ISQLServerErrorInfo_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ISQLServerErrorInfo_GetErrorInfo(This,ppErrorInfo,ppStringsBuffer) \ + ( (This)->lpVtbl -> GetErrorInfo(This,ppErrorInfo,ppStringsBuffer) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ISQLServerErrorInfo_INTERFACE_DEFINED__ */ + + +#ifndef __IRowsetFastLoad_INTERFACE_DEFINED__ +#define __IRowsetFastLoad_INTERFACE_DEFINED__ + +/* interface IRowsetFastLoad */ +/* [unique][uuid][object][local] */ + + +EXTERN_C const IID IID_IRowsetFastLoad; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("5CF4CA13-EF21-11d0-97E7-00C04FC2AD98") + IRowsetFastLoad : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE InsertRow( + /* [in] */ HACCESSOR hAccessor, + /* [in] */ void *pData) = 0; + + virtual HRESULT STDMETHODCALLTYPE Commit( + /* [in] */ BOOL fDone) = 0; + + }; + +#else /* C style interface */ + + typedef struct IRowsetFastLoadVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IRowsetFastLoad * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IRowsetFastLoad * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IRowsetFastLoad * This); + + HRESULT ( STDMETHODCALLTYPE *InsertRow )( + IRowsetFastLoad * This, + /* [in] */ HACCESSOR hAccessor, + /* [in] */ void *pData); + + HRESULT ( STDMETHODCALLTYPE *Commit )( + IRowsetFastLoad * This, + /* [in] */ BOOL fDone); + + END_INTERFACE + } IRowsetFastLoadVtbl; + + interface IRowsetFastLoad + { + CONST_VTBL struct IRowsetFastLoadVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IRowsetFastLoad_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IRowsetFastLoad_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IRowsetFastLoad_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IRowsetFastLoad_InsertRow(This,hAccessor,pData) \ + ( (This)->lpVtbl -> InsertRow(This,hAccessor,pData) ) + +#define IRowsetFastLoad_Commit(This,fDone) \ + ( (This)->lpVtbl -> Commit(This,fDone) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IRowsetFastLoad_INTERFACE_DEFINED__ */ + + +/* interface __MIDL_itf_sqlncli_0000_0004 */ +/* [local] */ + +#include // 8-byte structure packing + +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; + +#include // restore original structure packing + +struct SSVARIANT + { + SSVARTYPE vt; + DWORD dwReserved1; + DWORD dwReserved2; + union + { + BYTE bTinyIntVal; + SHORT sShortIntVal; + LONG lIntVal; + LONGLONG llBigIntVal; + FLOAT fltRealVal; + DOUBLE dblFloatVal; + CY cyMoneyVal; + VARIANT_BOOL fBitVal; + BYTE rgbGuidVal[ 16 ]; + DB_NUMERIC numNumericVal; + DBDATE dDateVal; + DBTIMESTAMP tsDateTimeVal; + struct _Time2Val + { + DBTIME2 tTime2Val; + BYTE bScale; + } Time2Val; + struct _DateTimeVal + { + DBTIMESTAMP tsDateTimeVal; + BYTE bScale; + } DateTimeVal; + struct _DateTimeOffsetVal + { + DBTIMESTAMPOFFSET tsoDateTimeOffsetVal; + BYTE bScale; + } DateTimeOffsetVal; + struct _NCharVal + { + SHORT sActualLength; + SHORT sMaxLength; + WCHAR *pwchNCharVal; + BYTE rgbReserved[ 5 ]; + DWORD dwReserved; + WCHAR *pwchReserved; + } NCharVal; + struct _CharVal + { + SHORT sActualLength; + SHORT sMaxLength; + CHAR *pchCharVal; + BYTE rgbReserved[ 5 ]; + DWORD dwReserved; + WCHAR *pwchReserved; + } CharVal; + struct _BinaryVal + { + SHORT sActualLength; + SHORT sMaxLength; + BYTE *prgbBinaryVal; + DWORD dwReserved; + } BinaryVal; + struct _UnknownType + { + DWORD dwActualLength; + BYTE rgMetadata[ 16 ]; + BYTE *pUnknownData; + } UnknownType; + struct _BLOBType + { + DBOBJECT dbobj; + IUnknown *pUnk; + } BLOBType; + } ; + } ; +typedef DWORD LOCKMODE; + + +enum LOCKMODEENUM + { LOCKMODE_INVALID = 0, + LOCKMODE_EXCLUSIVE = ( LOCKMODE_INVALID + 1 ) , + LOCKMODE_SHARED = ( LOCKMODE_EXCLUSIVE + 1 ) + } ; + + +extern RPC_IF_HANDLE __MIDL_itf_sqlncli_0000_0004_v0_0_c_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_sqlncli_0000_0004_v0_0_s_ifspec; + +#ifndef __ISchemaLock_INTERFACE_DEFINED__ +#define __ISchemaLock_INTERFACE_DEFINED__ + +/* interface ISchemaLock */ +/* [unique][uuid][object][local] */ + + +EXTERN_C const IID IID_ISchemaLock; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("4C2389FB-2511-11d4-B258-00C04F7971CE") + ISchemaLock : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetSchemaLock( + /* [in] */ DBID *pTableID, + /* [in] */ LOCKMODE lmMode, + /* [out] */ HANDLE *phLockHandle, + /* [out] */ ULONGLONG *pTableVersion) = 0; + + virtual HRESULT STDMETHODCALLTYPE ReleaseSchemaLock( + /* [in] */ HANDLE hLockHandle) = 0; + + }; + +#else /* C style interface */ + + typedef struct ISchemaLockVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ISchemaLock * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ISchemaLock * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ISchemaLock * This); + + HRESULT ( STDMETHODCALLTYPE *GetSchemaLock )( + ISchemaLock * This, + /* [in] */ DBID *pTableID, + /* [in] */ LOCKMODE lmMode, + /* [out] */ HANDLE *phLockHandle, + /* [out] */ ULONGLONG *pTableVersion); + + HRESULT ( STDMETHODCALLTYPE *ReleaseSchemaLock )( + ISchemaLock * This, + /* [in] */ HANDLE hLockHandle); + + END_INTERFACE + } ISchemaLockVtbl; + + interface ISchemaLock + { + CONST_VTBL struct ISchemaLockVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ISchemaLock_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ISchemaLock_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ISchemaLock_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ISchemaLock_GetSchemaLock(This,pTableID,lmMode,phLockHandle,pTableVersion) \ + ( (This)->lpVtbl -> GetSchemaLock(This,pTableID,lmMode,phLockHandle,pTableVersion) ) + +#define ISchemaLock_ReleaseSchemaLock(This,hLockHandle) \ + ( (This)->lpVtbl -> ReleaseSchemaLock(This,hLockHandle) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ISchemaLock_INTERFACE_DEFINED__ */ + + +#ifndef __IBCPSession_INTERFACE_DEFINED__ +#define __IBCPSession_INTERFACE_DEFINED__ + +/* interface IBCPSession */ +/* [unique][uuid][object][local] */ + + +EXTERN_C const IID IID_IBCPSession; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("88352D80-42D1-42f0-A170-AB0F8B45B939") + IBCPSession : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE BCPColFmt( + /* [in] */ DBORDINAL idxUserDataCol, + /* [in] */ int eUserDataType, + /* [in] */ int cbIndicator, + /* [in] */ int cbUserData, + /* [size_is][in] */ BYTE *pbUserDataTerm, + /* [in] */ int cbUserDataTerm, + /* [in] */ DBORDINAL idxServerCol) = 0; + + virtual HRESULT STDMETHODCALLTYPE BCPColumns( + /* [in] */ DBCOUNTITEM nColumns) = 0; + + virtual HRESULT STDMETHODCALLTYPE BCPControl( + /* [in] */ int eOption, + /* [in] */ void *iValue) = 0; + + virtual HRESULT STDMETHODCALLTYPE BCPDone( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE BCPExec( + /* [out] */ DBROWCOUNT *pRowsCopied) = 0; + + virtual HRESULT STDMETHODCALLTYPE BCPInit( + /* [string][in] */ const wchar_t *pwszTable, + /* [string][in] */ const wchar_t *pwszDataFile, + /* [string][in] */ const wchar_t *pwszErrorFile, + /* [in] */ int eDirection) = 0; + + virtual HRESULT STDMETHODCALLTYPE BCPReadFmt( + /* [string][in] */ const wchar_t *pwszFormatFile) = 0; + + virtual HRESULT STDMETHODCALLTYPE BCPWriteFmt( + /* [string][in] */ const wchar_t *pwszFormatFile) = 0; + + }; + +#else /* C style interface */ + + typedef struct IBCPSessionVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IBCPSession * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IBCPSession * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IBCPSession * This); + + HRESULT ( STDMETHODCALLTYPE *BCPColFmt )( + IBCPSession * This, + /* [in] */ DBORDINAL idxUserDataCol, + /* [in] */ int eUserDataType, + /* [in] */ int cbIndicator, + /* [in] */ int cbUserData, + /* [size_is][in] */ BYTE *pbUserDataTerm, + /* [in] */ int cbUserDataTerm, + /* [in] */ DBORDINAL idxServerCol); + + HRESULT ( STDMETHODCALLTYPE *BCPColumns )( + IBCPSession * This, + /* [in] */ DBCOUNTITEM nColumns); + + HRESULT ( STDMETHODCALLTYPE *BCPControl )( + IBCPSession * This, + /* [in] */ int eOption, + /* [in] */ void *iValue); + + HRESULT ( STDMETHODCALLTYPE *BCPDone )( + IBCPSession * This); + + HRESULT ( STDMETHODCALLTYPE *BCPExec )( + IBCPSession * This, + /* [out] */ DBROWCOUNT *pRowsCopied); + + HRESULT ( STDMETHODCALLTYPE *BCPInit )( + IBCPSession * This, + /* [string][in] */ const wchar_t *pwszTable, + /* [string][in] */ const wchar_t *pwszDataFile, + /* [string][in] */ const wchar_t *pwszErrorFile, + /* [in] */ int eDirection); + + HRESULT ( STDMETHODCALLTYPE *BCPReadFmt )( + IBCPSession * This, + /* [string][in] */ const wchar_t *pwszFormatFile); + + HRESULT ( STDMETHODCALLTYPE *BCPWriteFmt )( + IBCPSession * This, + /* [string][in] */ const wchar_t *pwszFormatFile); + + END_INTERFACE + } IBCPSessionVtbl; + + interface IBCPSession + { + CONST_VTBL struct IBCPSessionVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IBCPSession_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IBCPSession_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IBCPSession_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IBCPSession_BCPColFmt(This,idxUserDataCol,eUserDataType,cbIndicator,cbUserData,pbUserDataTerm,cbUserDataTerm,idxServerCol) \ + ( (This)->lpVtbl -> BCPColFmt(This,idxUserDataCol,eUserDataType,cbIndicator,cbUserData,pbUserDataTerm,cbUserDataTerm,idxServerCol) ) + +#define IBCPSession_BCPColumns(This,nColumns) \ + ( (This)->lpVtbl -> BCPColumns(This,nColumns) ) + +#define IBCPSession_BCPControl(This,eOption,iValue) \ + ( (This)->lpVtbl -> BCPControl(This,eOption,iValue) ) + +#define IBCPSession_BCPDone(This) \ + ( (This)->lpVtbl -> BCPDone(This) ) + +#define IBCPSession_BCPExec(This,pRowsCopied) \ + ( (This)->lpVtbl -> BCPExec(This,pRowsCopied) ) + +#define IBCPSession_BCPInit(This,pwszTable,pwszDataFile,pwszErrorFile,eDirection) \ + ( (This)->lpVtbl -> BCPInit(This,pwszTable,pwszDataFile,pwszErrorFile,eDirection) ) + +#define IBCPSession_BCPReadFmt(This,pwszFormatFile) \ + ( (This)->lpVtbl -> BCPReadFmt(This,pwszFormatFile) ) + +#define IBCPSession_BCPWriteFmt(This,pwszFormatFile) \ + ( (This)->lpVtbl -> BCPWriteFmt(This,pwszFormatFile) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IBCPSession_INTERFACE_DEFINED__ */ + + +/* interface __MIDL_itf_sqlncli_0000_0006 */ +/* [local] */ + + +#endif //_SQLOLEDB_H_ + +#define ISOLATIONLEVEL_SNAPSHOT ((ISOLATIONLEVEL)(0x01000000)) // Changes made in other transactions can not be seen. + +#define DBPROPVAL_TI_SNAPSHOT 0x01000000L + + + +extern RPC_IF_HANDLE __MIDL_itf_sqlncli_0000_0006_v0_0_c_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_sqlncli_0000_0006_v0_0_s_ifspec; + +#ifndef __ISSAbort_INTERFACE_DEFINED__ +#define __ISSAbort_INTERFACE_DEFINED__ + +/* interface ISSAbort */ +/* [unique][uuid][object][local] */ + + +EXTERN_C const IID IID_ISSAbort; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("5CF4CA15-EF21-11d0-97E7-00C04FC2AD98") + ISSAbort : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Abort( void) = 0; + + }; + +#else /* C style interface */ + + typedef struct ISSAbortVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ISSAbort * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ISSAbort * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ISSAbort * This); + + HRESULT ( STDMETHODCALLTYPE *Abort )( + ISSAbort * This); + + END_INTERFACE + } ISSAbortVtbl; + + interface ISSAbort + { + CONST_VTBL struct ISSAbortVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ISSAbort_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ISSAbort_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ISSAbort_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ISSAbort_Abort(This) \ + ( (This)->lpVtbl -> Abort(This) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ISSAbort_INTERFACE_DEFINED__ */ + + +/* interface __MIDL_itf_sqlncli_0000_0007 */ +/* [local] */ + + +enum DBBINDFLAGENUM90 + { DBBINDFLAG_OBJECT = 0x2 + } ; + +enum SSACCESSORFLAGS + { SSACCESSOR_ROWDATA = 0x100 + } ; + +enum DBPROPFLAGSENUM90 + { DBPROPFLAGS_PARAMETER = 0x10000 + } ; +typedef struct tagSSPARAMPROPS + { + DBORDINAL iOrdinal; + ULONG cPropertySets; + DBPROPSET *rgPropertySets; + } SSPARAMPROPS; + + + +extern RPC_IF_HANDLE __MIDL_itf_sqlncli_0000_0007_v0_0_c_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_sqlncli_0000_0007_v0_0_s_ifspec; + +#ifndef __ISSCommandWithParameters_INTERFACE_DEFINED__ +#define __ISSCommandWithParameters_INTERFACE_DEFINED__ + +/* interface ISSCommandWithParameters */ +/* [unique][uuid][object][local] */ + + +EXTERN_C const IID IID_ISSCommandWithParameters; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("eec30162-6087-467c-b995-7c523ce96561") + ISSCommandWithParameters : public ICommandWithParameters + { + public: + virtual /* [local] */ HRESULT STDMETHODCALLTYPE GetParameterProperties( + /* [out][in] */ DB_UPARAMS *pcParams, + /* [size_is][size_is][out] */ SSPARAMPROPS **prgParamProperties) = 0; + + virtual /* [local] */ HRESULT STDMETHODCALLTYPE SetParameterProperties( + /* [in] */ DB_UPARAMS cParams, + /* [size_is][unique][in] */ SSPARAMPROPS rgParamProperties[ ]) = 0; + + }; + +#else /* C style interface */ + + typedef struct ISSCommandWithParametersVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ISSCommandWithParameters * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ISSCommandWithParameters * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ISSCommandWithParameters * This); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *GetParameterInfo )( + ISSCommandWithParameters * This, + /* [out][in] */ DB_UPARAMS *pcParams, + /* [size_is][size_is][out] */ DBPARAMINFO **prgParamInfo, + /* [out] */ OLECHAR **ppNamesBuffer); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *MapParameterNames )( + ISSCommandWithParameters * This, + /* [in] */ DB_UPARAMS cParamNames, + /* [size_is][in] */ const OLECHAR *rgParamNames[ ], + /* [size_is][out] */ DB_LPARAMS rgParamOrdinals[ ]); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *SetParameterInfo )( + ISSCommandWithParameters * This, + /* [in] */ DB_UPARAMS cParams, + /* [size_is][unique][in] */ const DB_UPARAMS rgParamOrdinals[ ], + /* [size_is][unique][in] */ const DBPARAMBINDINFO rgParamBindInfo[ ]); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *GetParameterProperties )( + ISSCommandWithParameters * This, + /* [out][in] */ DB_UPARAMS *pcParams, + /* [size_is][size_is][out] */ SSPARAMPROPS **prgParamProperties); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *SetParameterProperties )( + ISSCommandWithParameters * This, + /* [in] */ DB_UPARAMS cParams, + /* [size_is][unique][in] */ SSPARAMPROPS rgParamProperties[ ]); + + END_INTERFACE + } ISSCommandWithParametersVtbl; + + interface ISSCommandWithParameters + { + CONST_VTBL struct ISSCommandWithParametersVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ISSCommandWithParameters_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ISSCommandWithParameters_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ISSCommandWithParameters_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ISSCommandWithParameters_GetParameterInfo(This,pcParams,prgParamInfo,ppNamesBuffer) \ + ( (This)->lpVtbl -> GetParameterInfo(This,pcParams,prgParamInfo,ppNamesBuffer) ) + +#define ISSCommandWithParameters_MapParameterNames(This,cParamNames,rgParamNames,rgParamOrdinals) \ + ( (This)->lpVtbl -> MapParameterNames(This,cParamNames,rgParamNames,rgParamOrdinals) ) + +#define ISSCommandWithParameters_SetParameterInfo(This,cParams,rgParamOrdinals,rgParamBindInfo) \ + ( (This)->lpVtbl -> SetParameterInfo(This,cParams,rgParamOrdinals,rgParamBindInfo) ) + + +#define ISSCommandWithParameters_GetParameterProperties(This,pcParams,prgParamProperties) \ + ( (This)->lpVtbl -> GetParameterProperties(This,pcParams,prgParamProperties) ) + +#define ISSCommandWithParameters_SetParameterProperties(This,cParams,rgParamProperties) \ + ( (This)->lpVtbl -> SetParameterProperties(This,cParams,rgParamProperties) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ISSCommandWithParameters_INTERFACE_DEFINED__ */ + + +#ifndef __IDBAsynchStatus_INTERFACE_DEFINED__ +#define __IDBAsynchStatus_INTERFACE_DEFINED__ + +/* interface IDBAsynchStatus */ +/* [unique][uuid][object][local] */ + + +EXTERN_C const IID IID_IDBAsynchStatus; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("0c733a95-2a1c-11ce-ade5-00aa0044773d") + IDBAsynchStatus : public IUnknown + { + public: + virtual /* [local] */ HRESULT STDMETHODCALLTYPE Abort( + /* [in] */ HCHAPTER hChapter, + /* [in] */ DBASYNCHOP eOperation) = 0; + + virtual /* [local] */ HRESULT STDMETHODCALLTYPE GetStatus( + /* [in] */ HCHAPTER hChapter, + /* [in] */ DBASYNCHOP eOperation, + /* [out] */ DBCOUNTITEM *pulProgress, + /* [out] */ DBCOUNTITEM *pulProgressMax, + /* [out] */ DBASYNCHPHASE *peAsynchPhase, + /* [out] */ LPOLESTR *ppwszStatusText) = 0; + + }; + +#else /* C style interface */ + + typedef struct IDBAsynchStatusVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDBAsynchStatus * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDBAsynchStatus * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDBAsynchStatus * This); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *Abort )( + IDBAsynchStatus * This, + /* [in] */ HCHAPTER hChapter, + /* [in] */ DBASYNCHOP eOperation); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *GetStatus )( + IDBAsynchStatus * This, + /* [in] */ HCHAPTER hChapter, + /* [in] */ DBASYNCHOP eOperation, + /* [out] */ DBCOUNTITEM *pulProgress, + /* [out] */ DBCOUNTITEM *pulProgressMax, + /* [out] */ DBASYNCHPHASE *peAsynchPhase, + /* [out] */ LPOLESTR *ppwszStatusText); + + END_INTERFACE + } IDBAsynchStatusVtbl; + + interface IDBAsynchStatus + { + CONST_VTBL struct IDBAsynchStatusVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDBAsynchStatus_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDBAsynchStatus_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDBAsynchStatus_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDBAsynchStatus_Abort(This,hChapter,eOperation) \ + ( (This)->lpVtbl -> Abort(This,hChapter,eOperation) ) + +#define IDBAsynchStatus_GetStatus(This,hChapter,eOperation,pulProgress,pulProgressMax,peAsynchPhase,ppwszStatusText) \ + ( (This)->lpVtbl -> GetStatus(This,hChapter,eOperation,pulProgress,pulProgressMax,peAsynchPhase,ppwszStatusText) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE IDBAsynchStatus_RemoteAbort_Proxy( + IDBAsynchStatus * This, + /* [in] */ HCHAPTER hChapter, + /* [in] */ DBASYNCHOP eOperation, + /* [out] */ IErrorInfo **ppErrorInfoRem); + + +void __RPC_STUB IDBAsynchStatus_RemoteAbort_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase); + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE IDBAsynchStatus_RemoteGetStatus_Proxy( + IDBAsynchStatus * This, + /* [in] */ HCHAPTER hChapter, + /* [in] */ DBASYNCHOP eOperation, + /* [unique][out][in] */ DBCOUNTITEM *pulProgress, + /* [unique][out][in] */ DBCOUNTITEM *pulProgressMax, + /* [unique][out][in] */ DBASYNCHPHASE *peAsynchPhase, + /* [unique][out][in] */ LPOLESTR *ppwszStatusText, + /* [out] */ IErrorInfo **ppErrorInfoRem); + + +void __RPC_STUB IDBAsynchStatus_RemoteGetStatus_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase); + + + +#endif /* __IDBAsynchStatus_INTERFACE_DEFINED__ */ + + +#ifndef __ISSAsynchStatus_INTERFACE_DEFINED__ +#define __ISSAsynchStatus_INTERFACE_DEFINED__ + +/* interface ISSAsynchStatus */ +/* [unique][uuid][object][local] */ + + +EXTERN_C const IID IID_ISSAsynchStatus; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("1FF1F743-8BB0-4c00-ACC4-C10E43B08FC1") + ISSAsynchStatus : public IDBAsynchStatus + { + public: + virtual /* [local] */ HRESULT STDMETHODCALLTYPE WaitForAsynchCompletion( + /* [in] */ DWORD dwMillisecTimeOut) = 0; + + }; + +#else /* C style interface */ + + typedef struct ISSAsynchStatusVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ISSAsynchStatus * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ISSAsynchStatus * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ISSAsynchStatus * This); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *Abort )( + ISSAsynchStatus * This, + /* [in] */ HCHAPTER hChapter, + /* [in] */ DBASYNCHOP eOperation); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *GetStatus )( + ISSAsynchStatus * This, + /* [in] */ HCHAPTER hChapter, + /* [in] */ DBASYNCHOP eOperation, + /* [out] */ DBCOUNTITEM *pulProgress, + /* [out] */ DBCOUNTITEM *pulProgressMax, + /* [out] */ DBASYNCHPHASE *peAsynchPhase, + /* [out] */ LPOLESTR *ppwszStatusText); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *WaitForAsynchCompletion )( + ISSAsynchStatus * This, + /* [in] */ DWORD dwMillisecTimeOut); + + END_INTERFACE + } ISSAsynchStatusVtbl; + + interface ISSAsynchStatus + { + CONST_VTBL struct ISSAsynchStatusVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ISSAsynchStatus_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ISSAsynchStatus_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ISSAsynchStatus_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ISSAsynchStatus_Abort(This,hChapter,eOperation) \ + ( (This)->lpVtbl -> Abort(This,hChapter,eOperation) ) + +#define ISSAsynchStatus_GetStatus(This,hChapter,eOperation,pulProgress,pulProgressMax,peAsynchPhase,ppwszStatusText) \ + ( (This)->lpVtbl -> GetStatus(This,hChapter,eOperation,pulProgress,pulProgressMax,peAsynchPhase,ppwszStatusText) ) + + +#define ISSAsynchStatus_WaitForAsynchCompletion(This,dwMillisecTimeOut) \ + ( (This)->lpVtbl -> WaitForAsynchCompletion(This,dwMillisecTimeOut) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ISSAsynchStatus_INTERFACE_DEFINED__ */ + + +/* interface __MIDL_itf_sqlncli_0000_0010 */ +/* [local] */ + +//---------------------------------------------------------------------------- +// Values for STATUS bitmask for DBSCHEMA_TABLES & DBSCHEMA_TABLES_INFO +#define TABLE_HAS_UPDATE_INSTEAD_OF_TRIGGER 0x00000001 //table has IOT defined +#define TABLE_HAS_DELETE_INSTEAD_OF_TRIGGER 0x00000002 //table has IOT defined +#define TABLE_HAS_INSERT_INSTEAD_OF_TRIGGER 0x00000004 //table has IOT defined +#define TABLE_HAS_AFTER_UPDATE_TRIGGER 0x00000008 //table has update trigger +#define TABLE_HAS_AFTER_DELETE_TRIGGER 0x00000010 //table has delete trigger +#define TABLE_HAS_AFTER_INSERT_TRIGGER 0x00000020 //table has insert trigger +#define TABLE_HAS_CASCADE_UPDATE 0x00000040 //table has cascade update +#define TABLE_HAS_CASCADE_DELETE 0x00000080 //table has cascade delete + +//---------------------------------------------------------------------------- +// PropIds for DBPROP_INIT_GENERALTIMEOUT +#if (OLEDBVER >= 0x0210) +#define DBPROP_INIT_GENERALTIMEOUT 0x11cL +#endif + +//---------------------------------------------------------------------------- +// PropIds for DBPROPSET_SQLSERVERDATASOURCE +#define SSPROP_ENABLEFASTLOAD 2 +#define SSPROP_ENABLEBULKCOPY 3 + +//---------------------------------------------------------------------------- +// PropIds for DBPROPSET_SQLSERVERDATASOURCEINFO +#define SSPROP_UNICODELCID 2 +#define SSPROP_UNICODECOMPARISONSTYLE 3 +#define SSPROP_COLUMNLEVELCOLLATION 4 +#define SSPROP_CHARACTERSET 5 +#define SSPROP_SORTORDER 6 +#define SSPROP_CURRENTCOLLATION 7 +#define SSPROP_INTEGRATEDAUTHENTICATIONMETHOD 8 +#define SSPROP_MUTUALLYAUTHENTICATED 9 + +//---------------------------------------------------------------------------- +// PropIds for DBPROPSET_SQLSERVERDBINIT +#define SSPROP_INIT_CURRENTLANGUAGE 4 +#define SSPROP_INIT_NETWORKADDRESS 5 +#define SSPROP_INIT_NETWORKLIBRARY 6 +#define SSPROP_INIT_USEPROCFORPREP 7 +#define SSPROP_INIT_AUTOTRANSLATE 8 +#define SSPROP_INIT_PACKETSIZE 9 +#define SSPROP_INIT_APPNAME 10 +#define SSPROP_INIT_WSID 11 +#define SSPROP_INIT_FILENAME 12 +#define SSPROP_INIT_ENCRYPT 13 +#define SSPROP_AUTH_REPL_SERVER_NAME 14 +#define SSPROP_INIT_TAGCOLUMNCOLLATION 15 +#define SSPROP_INIT_MARSCONNECTION 16 +#define SSPROP_INIT_FAILOVERPARTNER 18 +#define SSPROP_AUTH_OLD_PASSWORD 19 +#define SSPROP_INIT_DATATYPECOMPATIBILITY 20 +#define SSPROP_INIT_TRUST_SERVER_CERTIFICATE 21 +#define SSPROP_INIT_SERVERSPN 22 +#define SSPROP_INIT_FAILOVERPARTNERSPN 23 + +//----------------------------------------------------------------------------- +// Values for SSPROP_INIT_USEPROCFORPREP +#define SSPROPVAL_USEPROCFORPREP_OFF 0 +#define SSPROPVAL_USEPROCFORPREP_ON 1 +#define SSPROPVAL_USEPROCFORPREP_ON_DROP 2 + +//----------------------------------------------------------------------------- +// Values for SSPROP_INIT_DATATYPECOMPATIBILITY +#define SSPROPVAL_DATATYPECOMPATIBILITY_SQL2000 80 +#define SSPROPVAL_DATATYPECOMPATIBILITY_DEFAULT 0 + +//---------------------------------------------------------------------------- +// PropIds for DBPROPSET_SQLSERVERSESSION +#define SSPROP_QUOTEDCATALOGNAMES 2 +#define SSPROP_ALLOWNATIVEVARIANT 3 +#define SSPROP_SQLXMLXPROGID 4 +#define SSPROP_ASYNCH_BULKCOPY 5 + +//---------------------------------------------------------------------------- +// PropIds for DBPROPSET_SQLSERVERROWSET +#define SSPROP_MAXBLOBLENGTH 8 +#define SSPROP_FASTLOADOPTIONS 9 +#define SSPROP_FASTLOADKEEPNULLS 10 +#define SSPROP_FASTLOADKEEPIDENTITY 11 +#define SSPROP_CURSORAUTOFETCH 12 +#define SSPROP_DEFERPREPARE 13 +#define SSPROP_IRowsetFastLoad 14 +#define SSPROP_QP_NOTIFICATION_TIMEOUT 17 +#define SSPROP_QP_NOTIFICATION_MSGTEXT 18 +#define SSPROP_QP_NOTIFICATION_OPTIONS 19 +#define SSPROP_NOCOUNT_STATUS 20 +#define SSPROP_COMPUTE_ID 21 +#define SSPROP_COLUMN_ID 22 +#define SSPROP_COMPUTE_BYLIST 23 +#define SSPROP_ISSAsynchStatus 24 + +//----------------------------------------------------------------------------- +// Values for SSPROP_QP_NOTIFICATION_TIMEOUT +#define SSPROPVAL_DEFAULT_NOTIFICATION_TIMEOUT 432000 /* in sec */ +#define SSPROPVAL_MAX_NOTIFICATION_TIMEOUT 0x7FFFFFFF /* in sec */ +#define MAX_NOTIFICATION_LEN 2000 /* NVARCHAR [2000] for both ID & DELIVERY_QUEUE */ + +//---------------------------------------------------------------------------- +// PropIds for DBPROPSET_SQLSERVERCOLUMN +#define SSPROP_COL_COLLATIONNAME 14 +#define SSPROP_COL_UDT_CATALOGNAME 31 +#define SSPROP_COL_UDT_SCHEMANAME 32 +#define SSPROP_COL_UDT_NAME 33 +#define SSPROP_COL_XML_SCHEMACOLLECTION_CATALOGNAME 34 +#define SSPROP_COL_XML_SCHEMACOLLECTION_SCHEMANAME 35 +#define SSPROP_COL_XML_SCHEMACOLLECTIONNAME 36 +#define SSPROP_COL_COMPUTED 37 + + +//---------------------------------------------------------------------------- +// PropIds for DBPROPSET_SQLSERVERSTREAM +#define SSPROP_STREAM_XMLROOT 19 + +//---------------------------------------------------------------------------- +// PropIds for DBPROPSET_SQLSERVERPARAMETER +#define SSPROP_PARAM_XML_SCHEMACOLLECTION_CATALOGNAME 24 +#define SSPROP_PARAM_XML_SCHEMACOLLECTION_SCHEMANAME 25 +#define SSPROP_PARAM_XML_SCHEMACOLLECTIONNAME 26 +#define SSPROP_PARAM_UDT_CATALOGNAME 27 +#define SSPROP_PARAM_UDT_SCHEMANAME 28 +#define SSPROP_PARAM_UDT_NAME 29 +#define SSPROP_PARAM_TYPE_CATALOGNAME 38 +#define SSPROP_PARAM_TYPE_SCHEMANAME 39 +#define SSPROP_PARAM_TYPE_TYPENAME 40 +#define SSPROP_PARAM_TABLE_DEFAULT_COLUMNS 41 +#define SSPROP_PARAM_TABLE_COLUMN_SORT_ORDER 42 + +//---------------------------------------------------------------------------- +// PropIds for DBPROPSET_SQLSERVERINDEX +#define SSPROP_INDEX_XML 1 + +//----------------------------------------------------------------------------- +// +#define BCP_TYPE_DEFAULT 0x00 +#define BCP_TYPE_SQLTEXT 0x23 +#define BCP_TYPE_SQLVARBINARY 0x25 +#define BCP_TYPE_SQLINTN 0x26 +#define BCP_TYPE_SQLVARCHAR 0x27 +#define BCP_TYPE_SQLBINARY 0x2d +#define BCP_TYPE_SQLIMAGE 0x22 +#define BCP_TYPE_SQLCHARACTER 0x2f +#define BCP_TYPE_SQLINT1 0x30 +#define BCP_TYPE_SQLBIT 0x32 +#define BCP_TYPE_SQLINT2 0x34 +#define BCP_TYPE_SQLINT4 0x38 +#define BCP_TYPE_SQLMONEY 0x3c +#define BCP_TYPE_SQLDATETIME 0x3d +#define BCP_TYPE_SQLFLT8 0x3e +#define BCP_TYPE_SQLFLTN 0x6d +#define BCP_TYPE_SQLMONEYN 0x6e +#define BCP_TYPE_SQLDATETIMN 0x6f +#define BCP_TYPE_SQLFLT4 0x3b +#define BCP_TYPE_SQLMONEY4 0x7a +#define BCP_TYPE_SQLDATETIM4 0x3a +#define BCP_TYPE_SQLDECIMAL 0x6a +#define BCP_TYPE_SQLNUMERIC 0x6c +#define BCP_TYPE_SQLUNIQUEID 0x24 +#define BCP_TYPE_SQLBIGCHAR 0xaf +#define BCP_TYPE_SQLBIGVARCHAR 0xa7 +#define BCP_TYPE_SQLBIGBINARY 0xad +#define BCP_TYPE_SQLBIGVARBINARY 0xa5 +#define BCP_TYPE_SQLBITN 0x68 +#define BCP_TYPE_SQLNCHAR 0xef +#define BCP_TYPE_SQLNVARCHAR 0xe7 +#define BCP_TYPE_SQLNTEXT 0x63 +#define BCP_TYPE_SQLDECIMALN 0x6a +#define BCP_TYPE_SQLNUMERICN 0x6c +#define BCP_TYPE_SQLINT8 0x7f +#define BCP_TYPE_SQLVARIANT 0x62 +#define BCP_TYPE_SQLUDT 0xf0 +#define BCP_TYPE_SQLXML 0xf1 +#define BCP_TYPE_SQLDATE 0x28 +#define BCP_TYPE_SQLTIME 0x29 +#define BCP_TYPE_SQLDATETIME2 0x2a +#define BCP_TYPE_SQLDATETIMEOFFSET 0x2b + +#define BCP_DIRECTION_IN 1 +#define BCP_DIRECTION_OUT 2 + +#define BCP_OPTION_MAXERRS 1 +#define BCP_OPTION_FIRST 2 +#define BCP_OPTION_LAST 3 +#define BCP_OPTION_BATCH 4 +#define BCP_OPTION_KEEPNULLS 5 +#define BCP_OPTION_ABORT 6 +#define BCP_OPTION_KEEPIDENTITY 8 +#define BCP_OPTION_HINTSA 10 +#define BCP_OPTION_HINTSW 11 +#define BCP_OPTION_FILECP 12 +#define BCP_OPTION_UNICODEFILE 13 +#define BCP_OPTION_TEXTFILE 14 +#define BCP_OPTION_FILEFMT 15 +#define BCP_OPTION_FMTXML 16 +#define BCP_OPTION_FIRSTEX 17 +#define BCP_OPTION_LASTEX 18 +#define BCP_OPTION_ROWCOUNT 19 + +#define BCP_FILECP_ACP 0 +#define BCP_FILECP_OEMCP 1 +#define BCP_FILECP_RAW (-1) + +#ifdef UNICODE +#define BCP_OPTION_HINTS BCP_OPTION_HINTSW +#else +#define BCP_OPTION_HINTS BCP_OPTION_HINTSA +#endif + +#define BCP_PREFIX_DEFAULT (-10) + +#define BCP_LENGTH_NULL (-1) +#define BCP_LENGTH_VARIABLE (-10) +// +//----------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +// Provider-specific Class Ids +// + +#if SQLNCLI_VER >= 1000 + +extern const GUID OLEDBDECLSPEC CLSID_SQLNCLI10 = {0x8F4A6B68L,0x4F36,0x4e3c,{0xBE,0x81,0xBC,0x7C,0xA4,0xE9,0xC4,0x5C}}; +extern const GUID OLEDBDECLSPEC CLSID_SQLNCLI10_ERROR = {0x53F9C3BCL,0x275F,0x4FA5,{0xB3,0xE6,0x25,0xED,0xCD,0x51,0x20,0x23}}; +extern const GUID OLEDBDECLSPEC CLSID_SQLNCLI10_ENUMERATOR = {0x91E4F2A5L,0x1B07,0x45f6,{0x86,0xBF,0x92,0x03,0xC7,0xC7,0x2B,0xE3}}; + +#endif + +extern const GUID OLEDBDECLSPEC CLSID_SQLNCLI = {0x85ecafccL,0xbdd9,0x4b03,{0x97,0xa8,0xfa,0x65,0xcb,0xe3,0x85,0x9b}}; +extern const GUID OLEDBDECLSPEC CLSID_SQLNCLI_ERROR = {0xe8bc0a7aL,0xea71,0x4263,{0x8c,0xda,0x94,0xf3,0x88,0xb8,0xed,0x10}}; +extern const GUID OLEDBDECLSPEC CLSID_SQLNCLI_ENUMERATOR = {0x4898ad37L,0xfe05,0x42df,{0x92,0xf9,0xe8,0x57,0xdd,0xfe,0xe7,0x30}}; +extern const GUID OLEDBDECLSPEC CLSID_ROWSET_TVP = {0xc7ef28d5L,0x7bee,0x443f,{0x86,0xda,0xe3,0x98,0x4f,0xcd,0x4d,0xf9}}; + +//---------------------------------------------------------------------------- +// Provider-specific Interface Ids +// +#ifndef _SQLOLEDB_H_ +extern const GUID OLEDBDECLSPEC IID_ISQLServerErrorInfo = {0x5cf4ca12,0xef21,0x11d0,{0x97,0xe7,0x0,0xc0,0x4f,0xc2,0xad,0x98}}; +extern const GUID OLEDBDECLSPEC IID_IRowsetFastLoad = {0x5cf4ca13,0xef21,0x11d0,{0x97,0xe7,0x0,0xc0,0x4f,0xc2,0xad,0x98}}; +extern const GUID OLEDBDECLSPEC IID_IUMSInitialize = {0x5cf4ca14,0xef21,0x11d0,{0x97,0xe7,0x0,0xc0,0x4f,0xc2,0xad,0x98}}; +extern const GUID OLEDBDECLSPEC IID_ISchemaLock = {0x4c2389fb,0x2511,0x11d4,{0xb2,0x58,0x0,0xc0,0x4f,0x79,0x71,0xce}}; +extern const GUID OLEDBDECLSPEC IID_ISQLXMLHelper = {0xd22a7678L,0xf860,0x40cd,{0xa5,0x67,0x15,0x63,0xde,0xb4,0x6d,0x49}}; +#endif //_SQLOLEDB_H_ +extern const GUID OLEDBDECLSPEC IID_ISSAbort = {0x5cf4ca15,0xef21,0x11d0,{0x97,0xe7,0x0,0xc0,0x4f,0xc2,0xad,0x98}}; +extern const GUID OLEDBDECLSPEC IID_IBCPSession = {0x88352D80,0x42D1,0x42f0,{0xA1,0x70,0xAB,0x0F,0x8B,0x45,0xB9,0x39}}; +extern const GUID OLEDBDECLSPEC IID_ISSCommandWithParameters = {0xeec30162,0x6087,0x467c,{0xb9,0x95,0x7c,0x52,0x3c,0xe9,0x65,0x61}}; +extern const GUID OLEDBDECLSPEC IID_ISSAsynchStatus = {0x1FF1F743,0x8BB0, 0x4c00,{0xAC,0xC4,0xC1,0x0E,0x43,0xB0,0x8F,0xC1}}; + + +//---------------------------------------------------------------------------- +// Provider-specific schema rowsets +// +#ifndef _SQLOLEDB_H_ +extern const GUID OLEDBDECLSPEC DBSCHEMA_LINKEDSERVERS = {0x9093caf4,0x2eac,0x11d1,{0x98,0x9,0x0,0xc0,0x4f,0xc2,0xad,0x98}}; +#endif //_SQLOLEDB_H_ +extern const GUID OLEDBDECLSPEC DBSCHEMA_SQL_ASSEMBLIES = {0x7c1112c8, 0xc2d3, 0x4f6e, {0x94, 0x9a, 0x98, 0x3d, 0x38, 0xa5, 0x8f, 0x46}}; +extern const GUID OLEDBDECLSPEC DBSCHEMA_SQL_ASSEMBLY_DEPENDENCIES = {0xcb0f837b, 0x974c, 0x41b8, {0x90, 0x9d, 0x64, 0x9c, 0xaf, 0x45, 0xad, 0x2f}}; +extern const GUID OLEDBDECLSPEC DBSCHEMA_SQL_USER_TYPES = {0xf1198bd8, 0xa424, 0x4ea3, {0x8d, 0x4c, 0x60, 0x7e, 0xee, 0x2b, 0xab, 0x60}}; +extern const GUID OLEDBDECLSPEC DBSCHEMA_XML_COLLECTIONS = {0x56bfad8c, 0x6e8f, 0x480d, {0x91, 0xde, 0x35, 0x16, 0xd9, 0x9a, 0x5d, 0x10}}; +extern const GUID OLEDBDECLSPEC DBSCHEMA_SQL_TABLE_TYPES = {0x4e26cde7, 0xaaa4, 0x41ed, {0x93, 0xdd, 0x37, 0x6e, 0x6d, 0x40, 0x9c, 0x17}}; +extern const GUID OLEDBDECLSPEC DBSCHEMA_SQL_TABLE_TYPE_PRIMARY_KEYS = {0x9738faea, 0x31e8, 0x4f63, {0xae, 0xd, 0x61, 0x33, 0x16, 0x41, 0x8c, 0xdd}}; +extern const GUID OLEDBDECLSPEC DBSCHEMA_SQL_TABLE_TYPE_COLUMNS = {0xa663d94b, 0xddf7, 0x4a7f, {0xa5, 0x37, 0xd6, 0x1f, 0x12, 0x36, 0x5d, 0x7c}}; +extern const GUID OLEDBDECLSPEC DBSCHEMA_COLUMNS_EXTENDED = {0x66462f01, 0x633a, 0x44d9, {0xb0, 0xd0, 0xfe, 0x66, 0xf2, 0x1a, 0x0d, 0x24}}; +extern const GUID OLEDBDECLSPEC DBSCHEMA_SPARSE_COLUMN_SET = {0x31a4837c, 0xf9ff, 0x405f, {0x89, 0x82, 0x02, 0x19, 0xaa, 0xaa, 0x4a, 0x12}}; + + +#ifndef CRESTRICTIONS_DBSCHEMA_LINKEDSERVERS +#define CRESTRICTIONS_DBSCHEMA_LINKEDSERVERS 1 +#endif + +#ifndef CRESTRICTIONS_DBSCHEMA_ASSEMBLIES +#define CRESTRICTIONS_DBSCHEMA_SQL_ASSEMBLIES 4 +#endif + +#ifndef CRESTRICTIONS_DBSCHEMA_ASSEMBLY_DEPENDENCIES +#define CRESTRICTIONS_DBSCHEMA_SQL_ASSEMBLY_DEPENDENCIES 4 +#endif + +#ifndef CRESTRICTIONS_DBSCHEMA_USER_TYPES +#define CRESTRICTIONS_DBSCHEMA_SQL_USER_TYPES 3 +#endif + +#ifndef CRESTRICTIONS_DBSCHEMA_XML_COLLECTIONS +#define CRESTRICTIONS_DBSCHEMA_XML_COLLECTIONS 4 +#endif + +#ifndef CRESTRICTIONS_DBSCHEMA_SQL_TABLE_TYPES +#define CRESTRICTIONS_DBSCHEMA_SQL_TABLE_TYPES 3 +#endif + +#ifndef CRESTRICTIONS_DBSCHEMA_SQL_TABLE_TYPE_PRIMARY_KEYS +#define CRESTRICTIONS_DBSCHEMA_SQL_TABLE_TYPE_PRIMARY_KEYS 3 +#endif + +#ifndef CRESTRICTIONS_DBSCHEMA_SQL_TABLE_TYPE_COLUMNS +#define CRESTRICTIONS_DBSCHEMA_SQL_TABLE_TYPE_COLUMNS 4 +#endif + +#ifndef CRESTRICTIONS_DBSCHEMA_COLUMNS_EXTENDED +#define CRESTRICTIONS_DBSCHEMA_COLUMNS_EXTENDED 4 +#endif + +#ifndef CRESTRICTIONS_DBSCHEMA_SPARSE_COLUMN_SET +#define CRESTRICTIONS_DBSCHEMA_SPARSE_COLUMN_SET 4 +#endif + + +//---------------------------------------------------------------------------- +// Provider-specific property sets +// +#ifndef _SQLOLEDB_H_ +extern const GUID OLEDBDECLSPEC DBPROPSET_SQLSERVERDATASOURCE = {0x28efaee4,0x2d2c,0x11d1,{0x98,0x7,0x0,0xc0,0x4f,0xc2,0xad,0x98}}; +extern const GUID OLEDBDECLSPEC DBPROPSET_SQLSERVERDATASOURCEINFO= {0xdf10cb94,0x35f6,0x11d2,{0x9c,0x54,0x0,0xc0,0x4f,0x79,0x71,0xd3}}; +extern const GUID OLEDBDECLSPEC DBPROPSET_SQLSERVERDBINIT = {0x5cf4ca10,0xef21,0x11d0,{0x97,0xe7,0x0,0xc0,0x4f,0xc2,0xad,0x98}}; +extern const GUID OLEDBDECLSPEC DBPROPSET_SQLSERVERROWSET = {0x5cf4ca11,0xef21,0x11d0,{0x97,0xe7,0x0,0xc0,0x4f,0xc2,0xad,0x98}}; +extern const GUID OLEDBDECLSPEC DBPROPSET_SQLSERVERSESSION = {0x28efaee5,0x2d2c,0x11d1,{0x98,0x7,0x0,0xc0,0x4f,0xc2,0xad,0x98}}; +extern const GUID OLEDBDECLSPEC DBPROPSET_SQLSERVERCOLUMN = {0x3b63fb5e,0x3fbb,0x11d3,{0x9f,0x29,0x0,0xc0,0x4f,0x8e,0xe9,0xdc}}; +extern const GUID OLEDBDECLSPEC DBPROPSET_SQLSERVERSTREAM = {0x9f79c073,0x8a6d,0x4bca,{0xa8,0xa8,0xc9,0xb7,0x9a,0x9b,0x96,0x2d}}; +#endif //_SQLOLEDB_H_ +extern const GUID OLEDBDECLSPEC DBPROPSET_SQLSERVERPARAMETER = {0xfee09128,0xa67d,0x47ea,{0x8d,0x40,0x24,0xa1,0xd4,0x73,0x7e,0x8d}}; +extern const GUID OLEDBDECLSPEC DBPROPSET_SQLSERVERINDEX = {0xE428B84E,0xA6B7,0x413a,{0x94,0x65,0x56,0x23,0x2E,0x0D,0x2B,0xEB}}; +extern const GUID OLEDBDECLSPEC DBPROPSET_PARAMETERALL = {0x2cd2b7d8,0xe7c2,0x4f6c,{0x9b,0x30,0x75,0xe2,0x58,0x46,0x10,0x97}}; + + +//---------------------------------------------------------------------------- +// Provider-specific columns for IColumnsRowset +// +#define DBCOLUMN_SS_X_GUID {0x627bd890,0xed54,0x11d2,{0xb9,0x94,0x0,0xc0,0x4f,0x8c,0xa8,0x2c}} +// +#ifndef _SQLOLEDB_H_ +extern const DBID OLEDBDECLSPEC DBCOLUMN_SS_COMPFLAGS = {DBCOLUMN_SS_X_GUID, DBKIND_GUID_PROPID, (LPOLESTR)100}; +extern const DBID OLEDBDECLSPEC DBCOLUMN_SS_SORTID = {DBCOLUMN_SS_X_GUID, DBKIND_GUID_PROPID, (LPOLESTR)101}; +extern const DBID OLEDBDECLSPEC DBCOLUMN_BASETABLEINSTANCE = {DBCOLUMN_SS_X_GUID, DBKIND_GUID_PROPID, (LPOLESTR)102}; +extern const DBID OLEDBDECLSPEC DBCOLUMN_SS_TDSCOLLATION = {DBCOLUMN_SS_X_GUID, DBKIND_GUID_PROPID, (LPOLESTR)103}; +#endif //_SQLOLEDB_H_ +extern const DBID OLEDBDECLSPEC DBCOLUMN_BASESERVERNAME = {DBCOLUMN_SS_X_GUID, DBKIND_GUID_PROPID, (LPOLESTR)104}; +extern const DBID OLEDBDECLSPEC DBCOLUMN_SS_XML_SCHEMACOLLECTION_CATALOGNAME= {DBCOLUMN_SS_X_GUID, DBKIND_GUID_PROPID, (LPOLESTR)105}; +extern const DBID OLEDBDECLSPEC DBCOLUMN_SS_XML_SCHEMACOLLECTION_SCHEMANAME = {DBCOLUMN_SS_X_GUID, DBKIND_GUID_PROPID, (LPOLESTR)106}; +extern const DBID OLEDBDECLSPEC DBCOLUMN_SS_XML_SCHEMACOLLECTIONNAME = {DBCOLUMN_SS_X_GUID, DBKIND_GUID_PROPID, (LPOLESTR)107}; +extern const DBID OLEDBDECLSPEC DBCOLUMN_SS_UDT_CATALOGNAME = {DBCOLUMN_SS_X_GUID, DBKIND_GUID_PROPID, (LPOLESTR)108}; +extern const DBID OLEDBDECLSPEC DBCOLUMN_SS_UDT_SCHEMANAME = {DBCOLUMN_SS_X_GUID, DBKIND_GUID_PROPID, (LPOLESTR)109}; +extern const DBID OLEDBDECLSPEC DBCOLUMN_SS_UDT_NAME = {DBCOLUMN_SS_X_GUID, DBKIND_GUID_PROPID, (LPOLESTR)110}; +extern const DBID OLEDBDECLSPEC DBCOLUMN_SS_ASSEMBLY_TYPENAME= {DBCOLUMN_SS_X_GUID, DBKIND_GUID_PROPID, (LPOLESTR)111}; + +// OLEDB part of SQL Server Native Client header - end here! +#endif // defined(_SQLNCLI_OLEDB_) || !defined(_SQLNCLI_ODBC_) + +// ODBC part of SQL Server Native Client header - begin here! +#if defined(_SQLNCLI_ODBC_) || !defined(_SQLNCLI_OLEDB_) +#ifdef ODBCVER + +// 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 +#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 +#define SQL_COPT_SS_INTEGRATED_SECURITY (SQL_COPT_SS_BASE+3) // Force integrated security on login +#define SQL_COPT_SS_PRESERVE_CURSORS (SQL_COPT_SS_BASE+4) // Preserve server cursors after SQLTransact +#define SQL_COPT_SS_USER_DATA (SQL_COPT_SS_BASE+5) // dbgetuserdata/dbsetuserdata +#define SQL_COPT_SS_ENLIST_IN_DTC SQL_ATTR_ENLIST_IN_DTC // Enlist in a DTC transaction +#define SQL_COPT_SS_ENLIST_IN_XA SQL_ATTR_ENLIST_IN_XA // Enlist in a XA transaction +#define SQL_COPT_SS_FALLBACK_CONNECT (SQL_COPT_SS_BASE+10) // Enables FallBack connections +#define SQL_COPT_SS_PERF_DATA (SQL_COPT_SS_BASE+11) // Used to access SQL Server ODBC driver performance data +#define SQL_COPT_SS_PERF_DATA_LOG (SQL_COPT_SS_BASE+12) // Used to set the logfile name for the Performance data +#define SQL_COPT_SS_PERF_QUERY_INTERVAL (SQL_COPT_SS_BASE+13) // Used to set the query logging threshold in milliseconds. +#define SQL_COPT_SS_PERF_QUERY_LOG (SQL_COPT_SS_BASE+14) // Used to set the logfile name for saving queryies. +#define SQL_COPT_SS_PERF_QUERY (SQL_COPT_SS_BASE+15) // Used to start and stop query logging. +#define SQL_COPT_SS_PERF_DATA_LOG_NOW (SQL_COPT_SS_BASE+16) // Used to make a statistics log entry to disk. +#define SQL_COPT_SS_QUOTED_IDENT (SQL_COPT_SS_BASE+17) // Enable/Disable Quoted Identifiers +#define SQL_COPT_SS_ANSI_NPW (SQL_COPT_SS_BASE+18) // Enable/Disable ANSI NULL, Padding and Warnings +#define SQL_COPT_SS_BCP (SQL_COPT_SS_BASE+19) // Allow BCP usage on connection +#define SQL_COPT_SS_TRANSLATE (SQL_COPT_SS_BASE+20) // Perform code page translation +#define SQL_COPT_SS_ATTACHDBFILENAME (SQL_COPT_SS_BASE+21) // File name to be attached as a database +#define SQL_COPT_SS_CONCAT_NULL (SQL_COPT_SS_BASE+22) // Enable/Disable CONCAT_NULL_YIELDS_NULL +#define SQL_COPT_SS_ENCRYPT (SQL_COPT_SS_BASE+23) // Allow strong encryption for data +#define SQL_COPT_SS_MARS_ENABLED (SQL_COPT_SS_BASE+24) // Multiple active result set per connection +#define SQL_COPT_SS_FAILOVER_PARTNER (SQL_COPT_SS_BASE+25) // Failover partner server +#define SQL_COPT_SS_OLDPWD (SQL_COPT_SS_BASE+26) // Old Password, used when changing password during login +#define SQL_COPT_SS_TXN_ISOLATION (SQL_COPT_SS_BASE+27) // Used to set/get any driver-specific or ODBC-defined TXN iso level +#define SQL_COPT_SS_TRUST_SERVER_CERTIFICATE (SQL_COPT_SS_BASE+28) // Trust server certificate +#define SQL_COPT_SS_SERVER_SPN (SQL_COPT_SS_BASE+29) // Server SPN +#define SQL_COPT_SS_FAILOVER_PARTNER_SPN (SQL_COPT_SS_BASE+30) // Failover partner server SPN +#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_MAX_USED SQL_COPT_SS_MUTUALLY_AUTHENTICATED +// 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 +#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 +#define SQL_SOPT_SS_HIDDEN_COLUMNS (SQL_SOPT_SS_BASE+2) // Expose FOR BROWSE hidden columns +#define SQL_SOPT_SS_NOBROWSETABLE (SQL_SOPT_SS_BASE+3) // Set NOBROWSETABLE option +#define SQL_SOPT_SS_REGIONALIZE (SQL_SOPT_SS_BASE+4) // Regionalize output character conversions +#define SQL_SOPT_SS_CURSOR_OPTIONS (SQL_SOPT_SS_BASE+5) // Server cursor options +#define SQL_SOPT_SS_NOCOUNT_STATUS (SQL_SOPT_SS_BASE+6) // Real vs. Not Real row count indicator +#define SQL_SOPT_SS_DEFER_PREPARE (SQL_SOPT_SS_BASE+7) // Defer prepare until necessary +#define SQL_SOPT_SS_QUERYNOTIFICATION_TIMEOUT (SQL_SOPT_SS_BASE+8) // Notification timeout +#define SQL_SOPT_SS_QUERYNOTIFICATION_MSGTEXT (SQL_SOPT_SS_BASE+9) // Notification message text +#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_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 +#define SQL_COPT_SS_BROWSE_SERVER (SQL_COPT_SS_BASE_EX+2) // Single Server browse request. +#define SQL_COPT_SS_WARN_ON_CP_ERROR (SQL_COPT_SS_BASE_EX+3) // Issues warning when data from the server had a loss during code page conversion. +#define SQL_COPT_SS_CONNECTION_DEAD (SQL_COPT_SS_BASE_EX+4) // dbdead SQLGetConnectOption only. It will try to ping the server. Expensive connection check +#define SQL_COPT_SS_BROWSE_CACHE_DATA (SQL_COPT_SS_BASE_EX+5) // Determines if we should cache browse info. Used when returned buffer is greater then ODBC limit (32K) +#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_EX_MAX_USED SQL_COPT_SS_RESET_CONNECTION + +// 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 +#define SQL_CA_SS_NUM_ORDERS (SQL_CA_SS_BASE+2) // dbnumorders +#define SQL_CA_SS_COLUMN_ORDER (SQL_CA_SS_BASE+3) // dbordercol +#define SQL_CA_SS_COLUMN_VARYLEN (SQL_CA_SS_BASE+4) // dbvarylen +#define SQL_CA_SS_NUM_COMPUTES (SQL_CA_SS_BASE+5) // dbnumcompute +#define SQL_CA_SS_COMPUTE_ID (SQL_CA_SS_BASE+6) // dbnextrow status return +#define SQL_CA_SS_COMPUTE_BYLIST (SQL_CA_SS_BASE+7) // dbbylist +#define SQL_CA_SS_COLUMN_ID (SQL_CA_SS_BASE+8) // dbaltcolid +#define SQL_CA_SS_COLUMN_OP (SQL_CA_SS_BASE+9) // dbaltop +#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_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 +#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 +#define SQL_CA_SS_UDT_ASSEMBLY_TYPE_NAME (SQL_CA_SS_BASE+21) // Qualified name of the assembly containing the UDT class +#define SQL_CA_SS_XML_SCHEMACOLLECTION_CATALOG_NAME (SQL_CA_SS_BASE+22) // Name of the catalog that contains XML Schema collection +#define SQL_CA_SS_XML_SCHEMACOLLECTION_SCHEMA_NAME (SQL_CA_SS_BASE+23) // Name of the schema that contains XML Schema collection +#define SQL_CA_SS_XML_SCHEMACOLLECTION_NAME (SQL_CA_SS_BASE+24) // Name of the XML Schema collection +#define SQL_CA_SS_CATALOG_NAME (SQL_CA_SS_BASE+25) // Catalog name +#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 +#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 +#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 +#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) + +// 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 +#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 +#define SQL_IS_OFF 0L // Integrated security isn't used +#define SQL_IS_ON 1L // Integrated security is used +#define SQL_IS_DEFAULT SQL_IS_OFF +// Defines for use with SQL_COPT_SS_PRESERVE_CURSORS +#define SQL_PC_OFF 0L // Cursors are closed on SQLTransact +#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 +#define SQL_UD_NOTSET NULL // No user data pointer set +// 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 +#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 +#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 +#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 +#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 +#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 +#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 +#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 +#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 +#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 +#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 +#define SQL_NC_OFF 0L +#define SQL_NC_ON 1L +//SQL_SOPT_SS_DEFER_PREPARE +#define SQL_DP_OFF 0L +#define SQL_DP_ON 1L +//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 +#define SQL_EN_OFF 0L +#define SQL_EN_ON 1L +//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 +#define SQL_MORE_INFO_NO 0L +#define SQL_MORE_INFO_YES 1L +//SQL_COPT_SS_BROWSE_CACHE_DATA +#define SQL_CACHE_DATA_NO 0L +#define SQL_CACHE_DATA_YES 1L +//SQL_COPT_SS_RESET_CONNECTION +#define SQL_RESET_YES 1L +//SQL_COPT_SS_WARN_ON_CP_ERROR +#define SQL_WARN_NO 0L +#define SQL_WARN_YES 1L +//SQL_COPT_SS_MARS_ENABLED +#define SQL_MARS_ENABLED_NO 0L +#define SQL_MARS_ENABLED_YES 1L +/* SQL_TXN_ISOLATION_OPTION bitmasks */ +#define SQL_TXN_SS_SNAPSHOT 0x00000020L + +// 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. +#define SQL_SS_VARIANT (-150) +#define SQL_SS_UDT (-151) +#define SQL_SS_XML (-152) +#define SQL_SS_TABLE (-153) +#define SQL_SS_TIME2 (-154) +#define SQL_SS_TIMESTAMPOFFSET (-155) + +// 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 + +#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. + +// SQL Server Data Type defines. +// New types for SQL 6.0 and later servers +#define SQLTEXT 0x23 +#define SQLVARBINARY 0x25 +#define SQLINTN 0x26 +#define SQLVARCHAR 0x27 +#define SQLBINARY 0x2d +#define SQLIMAGE 0x22 +#define SQLCHARACTER 0x2f +#define SQLINT1 0x30 +#define SQLBIT 0x32 +#define SQLINT2 0x34 +#define SQLINT4 0x38 +#define SQLMONEY 0x3c +#define SQLDATETIME 0x3d +#define SQLFLT8 0x3e +#define SQLFLTN 0x6d +#define SQLMONEYN 0x6e +#define SQLDATETIMN 0x6f +#define SQLFLT4 0x3b +#define SQLMONEY4 0x7a +#define SQLDATETIM4 0x3a +// New types for SQL 6.0 and later servers +#define SQLDECIMAL 0x6a +#define SQLNUMERIC 0x6c +// New types for SQL 7.0 and later servers +#define SQLUNIQUEID 0x24 +#define SQLBIGCHAR 0xaf +#define SQLBIGVARCHAR 0xa7 +#define SQLBIGBINARY 0xad +#define SQLBIGVARBINARY 0xa5 +#define SQLBITN 0x68 +#define SQLNCHAR 0xef +#define SQLNVARCHAR 0xe7 +#define SQLNTEXT 0x63 +// New types for SQL 2000 and later servers +#define SQLINT8 0x7f +#define SQLVARIANT 0x62 +// New types for SQL 2005 and later servers +#define SQLUDT 0xf0 +#define SQLXML 0xf1 +// 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 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 +#define SQL_SS_LENGTH_UNLIMITED 0 + +// User Data Type definitions. +// Returned by SQLColAttributes/SQL_CA_SS_COLUMN_UTYPE. +#define SQLudtBINARY 3 +#define SQLudtBIT 16 +#define SQLudtBITN 0 +#define SQLudtCHAR 1 +#define SQLudtDATETIM4 22 +#define SQLudtDATETIME 12 +#define SQLudtDATETIMN 15 +#define SQLudtDECML 24 +#define SQLudtDECMLN 26 +#define SQLudtFLT4 23 +#define SQLudtFLT8 8 +#define SQLudtFLTN 14 +#define SQLudtIMAGE 20 +#define SQLudtINT1 5 +#define SQLudtINT2 6 +#define SQLudtINT4 7 +#define SQLudtINTN 13 +#define SQLudtMONEY 11 +#define SQLudtMONEY4 21 +#define SQLudtMONEYN 17 +#define SQLudtNUM 10 +#define SQLudtNUMN 25 +#define SQLudtSYSNAME 18 +#define SQLudtTEXT 19 +#define SQLudtTIMESTAMP 80 +#define SQLudtUNIQUEIDENTIFIER 0 +#define SQLudtVARBINARY 4 +#define SQLudtVARCHAR 2 +#define MIN_USER_DATATYPE 256 +// 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 +#define SQLAOPVARP 0x33 // Variance population +#define SQLAOPCNT 0x4b // Count +#define SQLAOPSUM 0x4d // Sum +#define SQLAOPAVG 0x4f // Average +#define SQLAOPMIN 0x51 // Min +#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. +#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 +#define SQL_INFO_SS_MAX_USED SQL_INFO_SS_NETLIB_NAMEA +#ifdef UNICODE +#define SQL_INFO_SS_NETLIB_NAME SQL_INFO_SS_NETLIB_NAMEW +#else +#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. +#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. +#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) +#define SQL_DIAG_DFC_SS_CONDITION (SQL_DIAG_DFC_SS_BASE-2) +#define SQL_DIAG_DFC_SS_CREATE_DATABASE (SQL_DIAG_DFC_SS_BASE-3) +#define SQL_DIAG_DFC_SS_CREATE_DEFAULT (SQL_DIAG_DFC_SS_BASE-4) +#define SQL_DIAG_DFC_SS_CREATE_PROCEDURE (SQL_DIAG_DFC_SS_BASE-5) +#define SQL_DIAG_DFC_SS_CREATE_RULE (SQL_DIAG_DFC_SS_BASE-6) +#define SQL_DIAG_DFC_SS_CREATE_TRIGGER (SQL_DIAG_DFC_SS_BASE-7) +#define SQL_DIAG_DFC_SS_CURSOR_DECLARE (SQL_DIAG_DFC_SS_BASE-8) +#define SQL_DIAG_DFC_SS_CURSOR_OPEN (SQL_DIAG_DFC_SS_BASE-9) +#define SQL_DIAG_DFC_SS_CURSOR_FETCH (SQL_DIAG_DFC_SS_BASE-10) +#define SQL_DIAG_DFC_SS_CURSOR_CLOSE (SQL_DIAG_DFC_SS_BASE-11) +#define SQL_DIAG_DFC_SS_DEALLOCATE_CURSOR (SQL_DIAG_DFC_SS_BASE-12) +#define SQL_DIAG_DFC_SS_DBCC (SQL_DIAG_DFC_SS_BASE-13) +#define SQL_DIAG_DFC_SS_DISK (SQL_DIAG_DFC_SS_BASE-14) +#define SQL_DIAG_DFC_SS_DROP_DATABASE (SQL_DIAG_DFC_SS_BASE-15) +#define SQL_DIAG_DFC_SS_DROP_DEFAULT (SQL_DIAG_DFC_SS_BASE-16) +#define SQL_DIAG_DFC_SS_DROP_PROCEDURE (SQL_DIAG_DFC_SS_BASE-17) +#define SQL_DIAG_DFC_SS_DROP_RULE (SQL_DIAG_DFC_SS_BASE-18) +#define SQL_DIAG_DFC_SS_DROP_TRIGGER (SQL_DIAG_DFC_SS_BASE-19) +#define SQL_DIAG_DFC_SS_DUMP_DATABASE (SQL_DIAG_DFC_SS_BASE-20) +#define SQL_DIAG_DFC_SS_BACKUP_DATABASE (SQL_DIAG_DFC_SS_BASE-20) +#define SQL_DIAG_DFC_SS_DUMP_TABLE (SQL_DIAG_DFC_SS_BASE-21) +#define SQL_DIAG_DFC_SS_DUMP_TRANSACTION (SQL_DIAG_DFC_SS_BASE-22) +#define SQL_DIAG_DFC_SS_BACKUP_TRANSACTION (SQL_DIAG_DFC_SS_BASE-22) +#define SQL_DIAG_DFC_SS_GOTO (SQL_DIAG_DFC_SS_BASE-23) +#define SQL_DIAG_DFC_SS_INSERT_BULK (SQL_DIAG_DFC_SS_BASE-24) +#define SQL_DIAG_DFC_SS_KILL (SQL_DIAG_DFC_SS_BASE-25) +#define SQL_DIAG_DFC_SS_LOAD_DATABASE (SQL_DIAG_DFC_SS_BASE-26) +#define SQL_DIAG_DFC_SS_RESTORE_DATABASE (SQL_DIAG_DFC_SS_BASE-26) +#define SQL_DIAG_DFC_SS_LOAD_HEADERONLY (SQL_DIAG_DFC_SS_BASE-27) +#define SQL_DIAG_DFC_SS_RESTORE_HEADERONLY (SQL_DIAG_DFC_SS_BASE-27) +#define SQL_DIAG_DFC_SS_LOAD_TABLE (SQL_DIAG_DFC_SS_BASE-28) +#define SQL_DIAG_DFC_SS_LOAD_TRANSACTION (SQL_DIAG_DFC_SS_BASE-29) +#define SQL_DIAG_DFC_SS_RESTORE_TRANSACTION (SQL_DIAG_DFC_SS_BASE-29) +#define SQL_DIAG_DFC_SS_PRINT (SQL_DIAG_DFC_SS_BASE-30) +#define SQL_DIAG_DFC_SS_RAISERROR (SQL_DIAG_DFC_SS_BASE-31) +#define SQL_DIAG_DFC_SS_READTEXT (SQL_DIAG_DFC_SS_BASE-32) +#define SQL_DIAG_DFC_SS_RECONFIGURE (SQL_DIAG_DFC_SS_BASE-33) +#define SQL_DIAG_DFC_SS_RETURN (SQL_DIAG_DFC_SS_BASE-34) +#define SQL_DIAG_DFC_SS_SELECT_INTO (SQL_DIAG_DFC_SS_BASE-35) +#define SQL_DIAG_DFC_SS_SET (SQL_DIAG_DFC_SS_BASE-36) +#define SQL_DIAG_DFC_SS_SET_IDENTITY_INSERT (SQL_DIAG_DFC_SS_BASE-37) +#define SQL_DIAG_DFC_SS_SET_ROW_COUNT (SQL_DIAG_DFC_SS_BASE-38) +#define SQL_DIAG_DFC_SS_SET_STATISTICS (SQL_DIAG_DFC_SS_BASE-39) +#define SQL_DIAG_DFC_SS_SET_TEXTSIZE (SQL_DIAG_DFC_SS_BASE-40) +#define SQL_DIAG_DFC_SS_SETUSER (SQL_DIAG_DFC_SS_BASE-41) +#define SQL_DIAG_DFC_SS_SHUTDOWN (SQL_DIAG_DFC_SS_BASE-42) +#define SQL_DIAG_DFC_SS_TRANS_BEGIN (SQL_DIAG_DFC_SS_BASE-43) +#define SQL_DIAG_DFC_SS_TRANS_COMMIT (SQL_DIAG_DFC_SS_BASE-44) +#define SQL_DIAG_DFC_SS_TRANS_PREPARE (SQL_DIAG_DFC_SS_BASE-45) +#define SQL_DIAG_DFC_SS_TRANS_ROLLBACK (SQL_DIAG_DFC_SS_BASE-46) +#define SQL_DIAG_DFC_SS_TRANS_SAVE (SQL_DIAG_DFC_SS_BASE-47) +#define SQL_DIAG_DFC_SS_TRUNCATE_TABLE (SQL_DIAG_DFC_SS_BASE-48) +#define SQL_DIAG_DFC_SS_UPDATE_STATISTICS (SQL_DIAG_DFC_SS_BASE-49) +#define SQL_DIAG_DFC_SS_UPDATETEXT (SQL_DIAG_DFC_SS_BASE-50) +#define SQL_DIAG_DFC_SS_USE (SQL_DIAG_DFC_SS_BASE-51) +#define SQL_DIAG_DFC_SS_WAITFOR (SQL_DIAG_DFC_SS_BASE-52) +#define SQL_DIAG_DFC_SS_WRITETEXT (SQL_DIAG_DFC_SS_BASE-53) +#define SQL_DIAG_DFC_SS_DENY (SQL_DIAG_DFC_SS_BASE-54) +#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 +#define EX_ANY 0 +#define EX_INFO 10 +#define EX_MAXISEVERITY EX_INFO +#define EX_MISSING 11 +#define EX_TYPE 12 +#define EX_DEADLOCK 13 +#define EX_PERMIT 14 +#define EX_SYNTAX 15 +#define EX_USER 16 +#define EX_RESOURCE 17 +#define EX_INTOK 18 +#define MAXUSEVERITY EX_INTOK +#define EX_LIMIT 19 +#define EX_CMDFATAL 20 +#define MINFATALERR EX_CMDFATAL +#define EX_DBFATAL 21 +#define EX_TABCORRUPT 22 +#define EX_DBCORRUPT 23 +#define EX_HARDWARE 24 +#define EX_CONTROL 25 +// Internal server datatypes - used when binding to SQL_C_BINARY +#ifndef MAXNUMERICLEN // Resolve ODS/DBLib conflicts +// 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; +#else +typedef char DBCHAR; + +#endif +typedef short SQLSMALLINT; + +typedef unsigned short SQLUSMALLINT; + +typedef long SQLINTEGER; + +typedef unsigned long SQLUINTEGER; + +typedef unsigned char DBBINARY; + +typedef unsigned char DBTINYINT; + +typedef short DBSMALLINT; + +typedef unsigned short DBUSMALLINT; + +typedef double DBFLT8; + +typedef unsigned char DBBIT; + +typedef unsigned char DBBOOL; + +typedef float DBFLT4; + +typedef DBFLT4 DBREAL; + +typedef UINT DBUBOOL; + +typedef struct dbmoney + { + LONG mnyhigh; + ULONG mnylow; + } DBMONEY; + +typedef struct dbdatetime + { + LONG dtdays; + ULONG dttime; + } DBDATETIME; + +typedef struct dbdatetime4 + { + USHORT numdays; + USHORT nummins; + } DBDATETIM4; + +typedef LONG DBMONEY4; + +#include // 8-byte structure packing + +// 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 + { + SQLSMALLINT year; + SQLUSMALLINT month; + SQLUSMALLINT day; + SQLUSMALLINT hour; + SQLUSMALLINT minute; + SQLUSMALLINT second; + SQLUINTEGER fraction; + SQLSMALLINT timezone_hour; + SQLSMALLINT timezone_minute; + } SQL_SS_TIMESTAMPOFFSET_STRUCT; + +#include // restore original structure packing + +// 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 +#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; +#endif // ODCBVER +#endif // MAXNUMERICLEN + +#ifndef INT +typedef int INT; +typedef long DBINT; +typedef DBINT * LPDBINT; +#ifndef _LPCBYTE_DEFINED +#define _LPCBYTE_DEFINED +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 +#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 +#define SQL_SS_DL_DEFAULT TEXT("STATS.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 +#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. + +// ODBC BCP prototypes and defines +// Return codes +#define SUCCEED 1 +#define FAIL 0 +#define SUCCEED_ABORT 2 +#define SUCCEED_ASYNC 3 +// Transfer directions +#define DB_IN 1 // Transfer from client to server +#define DB_OUT 2 // Transfer from server to client +// 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 +#define BCPBATCH 4 // Sets input batch size +#define BCPKEEPNULLS 5 // Sets to insert NULLs for empty input values +#define BCPABORT 6 // Sets to have bcpexec return SUCCEED_ABORT +#define BCPODBC 7 // Sets ODBC canonical character output +#define BCPKEEPIDENTITY 8 // Sets IDENTITY_INSERT on +#if SQLNCLI_VER < 1000 +#define BCP6xFILEFMT 9 // DEPRECATED: Sets 6x file format on +#endif +#define BCPHINTSA 10 // Sets server BCP hints (ANSI string) +#define BCPHINTSW 11 // Sets server BCP hints (UNICODE string) +#define BCPFILECP 12 // Sets clients code page for the file +#define BCPUNICODEFILE 13 // Sets that the file contains unicode header +#define BCPTEXTFILE 14 // Sets BCP mode to expect a text file and to detect Unicode or ANSI automatically +#define BCPFILEFMT 15 // Sets file format version +#define BCPFMTXML 16 // Sets the format file type to xml +#define BCPFIRSTEX 17 // Starting Row for BCP operation (64 bit) +#define BCPLASTEX 18 // Ending Row for BCP operation (64 bit) +#define BCPROWCOUNT 19 // Total Number of Rows Copied (64 bit) +// 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 +#define SQL_VARLEN_DATA (-10) // Use default length for column +// BCP column format properties +#define BCP_FMT_TYPE 0x01 +#define BCP_FMT_INDICATOR_LEN 0x02 +#define BCP_FMT_DATA_LEN 0x03 +#define BCP_FMT_TERMINATOR 0x04 +#define BCP_FMT_SERVER_COL 0x05 +#define BCP_FMT_COLLATION 0x06 +#define BCP_FMT_COLLATION_ID 0x07 +// 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_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 +#define bcp_readfmt bcp_readfmtW +#define bcp_writefmt bcp_writefmtW +#define dbprtype dbprtypeW +#define bcp_gettypename bcp_gettypenameW +#define BCPHINTS BCPHINTSW +#else +#define bcp_init bcp_initA +#define bcp_readfmt bcp_readfmtA +#define bcp_writefmt bcp_writefmtA +#define dbprtype dbprtypeA +#define bcp_gettypename bcp_gettypenameA +#define BCPHINTS BCPHINTSA +#endif // UNICODE + +#endif // SQLNCLI_NO_BCP + +// 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 +#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 +#define SQL_COPT_SS_ANSI_OEM (SQL_COPT_SS_BASE+6) +#define SQL_AO_OFF 0L +#define SQL_AO_ON 1L +#define SQL_AO_DEFAULT SQL_AO_OFF +#define SQL_CA_SS_BASE_COLUMN_NAME SQL_DESC_BASE_COLUMN_NAME + +#endif // ODBCVER +#endif // defined(_SQLNCLI_ODBC_) || !defined(_SQLNCLI_OLEDB_) +// ODBC part of SQL Server Native Client header - end here! + +//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 +#define SQL_FILESTREAM_OPEN_FLAG_SEQUENTIAL_SCAN 0x00000008L +#define SQL_FILESTREAM_OPEN_FLAG_RANDOM_ACCESS 0x00000010L +HANDLE __stdcall OpenSqlFilestream ( + LPCWSTR FilestreamPath, + SQL_FILESTREAM_DESIRED_ACCESS DesiredAccess, + ULONG OpenOptions, + 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) + + + +extern RPC_IF_HANDLE __MIDL_itf_sqlncli_0000_0010_v0_0_c_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_sqlncli_0000_0010_v0_0_s_ifspec; + +/* Additional Prototypes for ALL interfaces */ + +/* end of Additional Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/pdo_sqlsrv/template.rc b/pdo_sqlsrv/template.rc index 34ae4df7..3ad029d1 100644 --- a/pdo_sqlsrv/template.rc +++ b/pdo_sqlsrv/template.rc @@ -3,7 +3,7 @@ // // Contents: Version resource // -// Copyright 2010 Microsoft Corporation +// Copyright Microsoft Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -65,7 +65,7 @@ BEGIN 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 2010 Microsoft Corporation.\0" + VALUE "LegalCopyright", "Copyright Microsoft Corporation.\0" VALUE "OriginalFilename", FILE_NAME "\0" VALUE "ProductName", "Microsoft Drivers for PHP for SQL Server\0" VALUE "ProductVersion", STRVER3(SQLVERSION_MAJOR,SQLVERSION_MINOR, SQLVERSION_MMDD) diff --git a/pdo_sqlsrv/version.h b/pdo_sqlsrv/version.h index 6be3f9e7..845c94da 100644 --- a/pdo_sqlsrv/version.h +++ b/pdo_sqlsrv/version.h @@ -1,9 +1,9 @@ -//--------------------------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------------------------- // File: version.h // -// Contents: Version information for compile and resources -// -// Copyright 2010 Microsoft Corporation +// Contents: Version number constants +// +// Copyright Microsoft Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,11 +16,11 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -//--------------------------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------------------------- -#define VER_FILEVERSION_STR "2.0.0.200" -#define _FILEVERSION 2,0,0,200 -#define SQLVERSION_MAJOR 2 +#define VER_FILEVERSION_STR "3.0.0.0" +#define _FILEVERSION 3,0,0,0 +#define SQLVERSION_MAJOR 3 #define SQLVERSION_MINOR 0 #define SQLVERSION_MMDD 0 -#define SQLVERSION_REVISION 200 +#define SQLVERSION_REVISION 0 diff --git a/sqlsrv/CREDITS b/sqlsrv/CREDITS index c3489015..d6edefd8 100644 --- a/sqlsrv/CREDITS +++ b/sqlsrv/CREDITS @@ -1 +1 @@ -Microsoft Drivers for PHP for SQL Server 2.0 Cumulative Update 1 +Microsoft Drivers 3.0 for PHP for SQL Server (SQLSRV driver) diff --git a/sqlsrv/README.TXT b/sqlsrv/README.TXT index 8a678ad1..3cd5b187 100644 --- a/sqlsrv/README.TXT +++ b/sqlsrv/README.TXT @@ -1,6 +1,6 @@ * Copyright and License Information * -Copyright 2010 Microsoft Corporation +Copyright Microsoft Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,33 +14,25 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. -* Notes about changes to the Microsoft Drivers for PHP for SQL Server - Driver 2.0 * +* Notes about changes to the Microsoft Drivers 3.0 for PHP for SQL Server * For details about the changes included in this release, please see our blog at -http://blogs.msdn.com/sqlphp or see the SQLSRV20_Readme.htm +http://blogs.msdn.com/sqlphp or see the SQLSRV_Readme.htm file that is part of the download package. -* Notes about compiling the Microsoft Drivers for PHP for SQL Server 2.0 * +* Notes about compiling the Microsoft Drivers 3.0 for PHP for SQL Server * Prerequisites: * You must first be able to build PHP without including these -extensions. For help with doing this, see xthe official PHP website, +extensions. For help with doing this, see the official PHP website, http://php.net. -* The header file sqlncli.h is required to build these extensions. It -may be installed with the Microsoft SQL ServerŪ 2008 R2 Native Client -(found at Microsoft.com) - -To compile the SQLSRV20 and PDO_SQLSRV20: +To compile the SQLSRV30 and PDO_SQLSRV30: 1) Copy the source code directories from this repository into the ext subdirectory. - 1a) Make sure that sqlncli.h is either on the INCLUDE file path or - copied locally to the extension directories. - 2) run buildconf.bat to rebuild the configure.js script to include the new drivers. @@ -61,8 +53,8 @@ wish to do so, run "nmake clean" first. php_sqlsrv.dll and php_pdo_sqlsrv.dll to your PHP extension directory. Also enable them within your PHP installation's php.ini file. -This software has been compiled and tested under PHP 5.2.10 and PHP 5.3.0 -using the Visual C++ 2008 Express and Standard compilers. +This software has been compiled and tested under PHP 5.3.6 and later +using the Visual C++ 2008 and 2010, Express and Standard compilers. * Note about version.h * diff --git a/sqlsrv/config.w32 b/sqlsrv/config.w32 index 3cb98510..fbb8bfee 100644 --- a/sqlsrv/config.w32 +++ b/sqlsrv/config.w32 @@ -3,7 +3,7 @@ // // Contents: JScript build configuration used by buildconf.bat // -// Copyright 2010 Microsoft Corporation +// Copyright Microsoft Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -18,18 +18,20 @@ // limitations under the License. //---------------------------------------------------------------------------------------------------------------------------------- -ARG_ENABLE("sqlsrv", "enable MS SQL Server extension", "no"); +ARG_ENABLE("sqlsrv", "enable Microsoft Drivers for PHP for SQL Server (SQLSRV driver)", "no"); if( PHP_SQLSRV != "no" ) { if (CHECK_LIB("odbc32.lib", "sqlsrv") && CHECK_LIB("odbccp32.lib", "sqlsrv") && CHECK_LIB("version.lib", "sqlsrv") && CHECK_LIB("psapi.lib", "sqlsrv")) { - EXTENSION("sqlsrv", "conn.cpp init.cpp stmt.cpp util.cpp core_init.cpp core_conn.cpp core_stmt.cpp core_util.cpp core_stream.cpp" ) + EXTENSION("sqlsrv", "conn.cpp init.cpp stmt.cpp util.cpp core_init.cpp core_conn.cpp core_stmt.cpp core_util.cpp core_stream.cpp core_results.cpp" ) CHECK_HEADER_ADD_INCLUDE('sql.h', 'CFLAGS_SQLSRV_ODBC'); CHECK_HEADER_ADD_INCLUDE('sqlext.h', 'CFLAGS_SQLSRV_ODBC'); ADD_FLAG( 'LDFLAGS_SQLSRV', '/NXCOMPAT /DYNAMICBASE' ); + ADD_FLAG( 'CFLAGS_SQLSRV', '/D ZEND_WIN32_FORCE_INLINE' ); + ADD_FLAG( 'CFLAGS_SQLSRV', '/D _HAS_CPP0X=0' ); ADD_FLAG( 'CFLAGS_SQLSRV', '/EHsc' ); ADD_FLAG( 'CFLAGS_SQLSRV', '/GS' ); } diff --git a/sqlsrv/conn.cpp b/sqlsrv/conn.cpp index 0f4e82a1..e2beb029 100644 --- a/sqlsrv/conn.cpp +++ b/sqlsrv/conn.cpp @@ -3,7 +3,7 @@ // // Contents: Routines that use connection handles // -// Copyright 2010 Microsoft Corporation +// Copyright Microsoft Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -162,6 +162,7 @@ namespace SSStmtOptionNames { const char QUERY_TIMEOUT[]= "QueryTimeout"; const char SEND_STREAMS_AT_EXEC[] = "SendStreamParamsAtExec"; const char SCROLLABLE[] = "Scrollable"; + const char CLIENT_BUFFER_MAX_SIZE[] = INI_BUFFERED_QUERY_LIMIT; } namespace SSConnOptionNames { @@ -169,6 +170,8 @@ namespace SSConnOptionNames { // most of these strings are the same for both the sqlsrv_connect connection option // and the name put into the connection string. MARS is the only one that's different. const char APP[] = "APP"; +const char ApplicationIntent[] = "ApplicationIntent"; +const char AttachDBFileName[] = "AttachDbFileName"; const char CharacterSet[] = "CharacterSet"; const char ConnectionPooling[] = "ConnectionPooling"; const char Database[] = "Database"; @@ -177,6 +180,7 @@ const char Encrypt[] = "Encrypt"; const char Failover_Partner[] = "Failover_Partner"; const char LoginTimeout[] = "LoginTimeout"; const char MARS_Option[] = "MultipleActiveResultSets"; +const char MultiSubnetFailover[] = "MultiSubnetFailover"; const char PWD[] = "PWD"; const char QuotedId[] = "QuotedId"; const char TraceFile[] = "TraceFile"; @@ -213,6 +217,12 @@ const stmt_option SS_STMT_OPTS[] = { SQLSRV_STMT_OPTION_SCROLLABLE, new stmt_option_scrollable }, + { + SSStmtOptionNames::CLIENT_BUFFER_MAX_SIZE, + sizeof( SSStmtOptionNames::CLIENT_BUFFER_MAX_SIZE ), + SQLSRV_STMT_OPTION_CLIENT_BUFFER_MAX_SIZE, + new stmt_option_buffered_query_limit + }, { NULL, 0, SQLSRV_STMT_OPTION_INVALID, NULL }, }; @@ -228,6 +238,24 @@ const connection_option SS_CONN_OPTS[] = { CONN_ATTR_STRING, conn_str_append_func::func }, + { + SSConnOptionNames::ApplicationIntent, + sizeof( SSConnOptionNames::ApplicationIntent ), + SQLSRV_CONN_OPTION_APPLICATION_INTENT, + ODBCConnOptions::ApplicationIntent, + sizeof( ODBCConnOptions::ApplicationIntent ), + CONN_ATTR_STRING, + conn_str_append_func::func + }, + { + SSConnOptionNames::AttachDBFileName, + sizeof( SSConnOptionNames::AttachDBFileName ), + SQLSRV_CONN_OPTION_ATTACHDBFILENAME, + ODBCConnOptions::AttachDBFileName, + sizeof( ODBCConnOptions::AttachDBFileName ), + CONN_ATTR_STRING, + conn_str_append_func::func + }, { SSConnOptionNames::CharacterSet, sizeof( SSConnOptionNames::CharacterSet ), @@ -291,6 +319,15 @@ const connection_option SS_CONN_OPTS[] = { CONN_ATTR_BOOL, bool_conn_str_func::func }, + { + SSConnOptionNames::MultiSubnetFailover, + sizeof( SSConnOptionNames::MultiSubnetFailover ), + SQLSRV_CONN_OPTION_MULTI_SUBNET_FAILOVER, + ODBCConnOptions::MultiSubnetFailover, + sizeof( ODBCConnOptions::MultiSubnetFailover ), + CONN_ATTR_BOOL, + bool_conn_str_func::func + }, { SSConnOptionNames::QuotedId, sizeof( SSConnOptionNames::QuotedId ), @@ -868,6 +905,19 @@ PHP_FUNCTION( sqlsrv_prepare ) } + if( params_z && Z_TYPE_P( params_z ) != IS_ARRAY ) { + THROW_SS_ERROR( conn, SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER, _FN_ ); + } + + if( options_z && Z_TYPE_P( options_z ) != IS_ARRAY ) { + THROW_SS_ERROR( conn, SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER, _FN_ ); + } + + if( sql == NULL ) { + + DIE( "sqlsrv_query: sql string was null." ); + } + stmt = static_cast( core_sqlsrv_create_stmt( conn, core::allocate_stmt, ss_stmt_options_ht, SS_STMT_OPTS, ss_error_handler, NULL TSRMLS_CC ) ); @@ -979,6 +1029,14 @@ PHP_FUNCTION( sqlsrv_query ) validate_stmt_options( *conn, options_z, ss_stmt_options_ht TSRMLS_CC ); } + if( params_z && Z_TYPE_P( params_z ) != IS_ARRAY ) { + THROW_SS_ERROR( conn, SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER, _FN_ ); + } + + if( options_z && Z_TYPE_P( options_z ) != IS_ARRAY ) { + THROW_SS_ERROR( conn, SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER, _FN_ ); + } + if( sql == NULL ) { DIE( "sqlsrv_query: sql string was null." ); diff --git a/sqlsrv/core_conn.cpp b/sqlsrv/core_conn.cpp index 5bb01348..4dcc4f8f 100644 --- a/sqlsrv/core_conn.cpp +++ b/sqlsrv/core_conn.cpp @@ -3,7 +3,7 @@ // // Contents: Core routines that use connection handles shared between sqlsrv and pdo_sqlsrv // -// Copyright 2010 Microsoft Corporation +// Copyright Microsoft Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -43,7 +43,7 @@ const int INFO_BUFFER_LEN = 256; const char* PROCESSOR_ARCH[] = { "x86", "x64", "ia64" }; // ODBC driver name. -const char CONNECTION_STRING_DRIVER_NAME[] = "Driver={SQL Server Native Client 10.0};"; +const char CONNECTION_STRING_DRIVER_NAME[] = "Driver={SQL Server Native Client 11.0};"; // default options if only the server is specified const char CONNECTION_STRING_DEFAULT_OPTIONS[] = "Mars_Connection={Yes}"; @@ -562,6 +562,20 @@ void build_connection_string_and_set_conn_attr( sqlsrv_conn* conn, const char* s return; } + // workaround for a bug in ODBC Driver Manager wherein the Driver Manager creates a 0 KB file + // if the TraceFile option is set, even if the "TraceOn" is not present or the "TraceOn" + // flag is set to false. + if( zend_hash_index_exists( options, SQLSRV_CONN_OPTION_TRACE_FILE )) { + + zval** trace_value = NULL; + int zr = zend_hash_index_find( options, SQLSRV_CONN_OPTION_TRACE_ON, (void**)&trace_value ); + + if( zr == FAILURE || !zend_is_true( *trace_value )) { + + zend_hash_index_del( options, SQLSRV_CONN_OPTION_TRACE_FILE ); + } + } + for( zend_hash_internal_pointer_reset( options ); zend_hash_has_more_elements( options ) == SUCCESS; zend_hash_move_forward( options )) { @@ -573,10 +587,10 @@ void build_connection_string_and_set_conn_attr( sqlsrv_conn* conn, const char* s zval** data = NULL; type = zend_hash_get_current_key_ex( options, &key, &key_len, &index, 0, NULL ); - CHECK_CUSTOM_ERROR(( type != HASH_KEY_IS_LONG ), conn, SQLSRV_ERROR_INVALID_OPTION_KEY ) { - throw core::CoreException(); - } + // 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, (void**) &data TSRMLS_CC ); conn_opt = get_connection_option( conn, index, valid_conn_opts TSRMLS_CC ); @@ -660,13 +674,14 @@ void determine_server_version( sqlsrv_conn* conn TSRMLS_DC ) char p[ INFO_BUFFER_LEN ]; core::SQLGetInfo( conn, SQL_DBMS_VER, p, INFO_BUFFER_LEN, &info_len TSRMLS_CC ); + errno = 0; char version_major_str[ 3 ]; SERVER_VERSION version_major; memcpy( version_major_str, p, 2 ); version_major_str[ 2 ] = '\0'; version_major = static_cast( atoi( version_major_str )); - CHECK_CUSTOM_ERROR( version_major == 0 || errno == ERANGE || errno == EINVAL, conn, SQLSRV_ERROR_UNKNOWN_SERVER_VERSION ) + CHECK_CUSTOM_ERROR( version_major == 0 && ( errno == ERANGE || errno == EINVAL ), conn, SQLSRV_ERROR_UNKNOWN_SERVER_VERSION ) { throw core::CoreException(); } diff --git a/sqlsrv/core_init.cpp b/sqlsrv/core_init.cpp index 543d8280..8d3436cf 100644 --- a/sqlsrv/core_init.cpp +++ b/sqlsrv/core_init.cpp @@ -3,7 +3,7 @@ // // Contents: common initialization routines shared by PDO and sqlsrv // -// Copyright 2010 Microsoft Corporation +// Copyright Microsoft Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/sqlsrv/core_results.cpp b/sqlsrv/core_results.cpp new file mode 100644 index 00000000..bce8061f --- /dev/null +++ b/sqlsrv/core_results.cpp @@ -0,0 +1,1338 @@ +//--------------------------------------------------------------------------------------------------------------------------------- +// File: core_results.cpp +// +// Contents: Result sets +// +// Copyright Microsoft Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// +// You may obtain a copy of the License at: +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//--------------------------------------------------------------------------------------------------------------------------------- + +#include "core_sqlsrv.h" + +#include +#include +#include + +using namespace core; + +// conversion matrix +// each entry holds a function that can perform the conversion or NULL which means the conversion isn't supported +// this is initialized the first time the buffered result set is created. +sqlsrv_buffered_result_set::conv_matrix_t sqlsrv_buffered_result_set::conv_matrix; + +namespace { + +// *** internal types *** + +#pragma warning(disable:4200) + +// *** internal constants *** + +const int INITIAL_FIELD_STRING_LEN = 256; // base allocation size when retrieving a string field + +// *** internal functions *** + +// return an integral type rounded up to a certain number +template +T align_to( T number ) +{ + DEBUG_SQLSRV_ASSERT( (number + align) > number, "Number to align overflowed" ); + return ((number % align) == 0) ? number : (number + align - (number % align)); +} + +// return a pointer address aligned to a certain address boundary +template +T* align_to( T* ptr ) +{ + size_t p_value = (size_t) ptr; + return align_to( p_value ); +} + +// set the nth bit of the bitstream starting at ptr +void set_bit( void* ptr, unsigned int bit ) +{ + unsigned char* null_bits = reinterpret_cast( ptr ); + null_bits += bit >> 3; + *null_bits |= 1 << ( 7 - ( bit & 0x7 )); +} + +// retrieve the nth bit from the bitstream starting at ptr +bool get_bit( void* ptr, unsigned int bit ) +{ + unsigned char* null_bits = reinterpret_cast( ptr ); + null_bits += bit >> 3; + return ((*null_bits & (1 << ( 7 - ( bit & 0x07 )))) != 0); +} + +// read in LOB field during buffered result creation +SQLPOINTER read_lob_field( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_buffered_result_set::meta_data& meta, + unsigned long mem_used TSRMLS_DC ); + +// dtor for each row in the cache +void cache_row_dtor( void* data ); + +// convert a number to a string using locales +// There is an extra copy here, but given the size is short (usually <20 bytes) and the complications of +// subclassing a new streambuf just to avoid the copy, it's easier to do the copy +template +SQLRETURN number_to_string( Number* number_data, __out void* buffer, SQLLEN buffer_length, __out SQLLEN* out_buffer_length, + sqlsrv_error_auto_ptr& last_error ) +{ + std::basic_ostringstream os; + std::locale loc; + os.imbue( loc ); + std::use_facet< std::num_put< Char > >( loc ).put( std::basic_ostream::_Iter( os.rdbuf() ), os, ' ', *number_data ); + std::basic_string& str_num = os.str(); + + if( os.fail() ) { + last_error = new ( sqlsrv_malloc( sizeof( sqlsrv_error ))) sqlsrv_error( + (SQLCHAR*) "IMSSP", (SQLCHAR*) "Failed to convert number to string", -1 ); + return SQL_ERROR; + } + + if( str_num.size() * sizeof(Char) + sizeof(Char) > (size_t) buffer_length ) { + last_error = new ( sqlsrv_malloc( sizeof( sqlsrv_error ))) sqlsrv_error( + (SQLCHAR*) "HY090", (SQLCHAR*) "Buffer length too small to hold number as string", -1 ); + return SQL_ERROR; + } + + *out_buffer_length = str_num.size() * sizeof(Char) + sizeof(Char); // include NULL terminator + memcpy( buffer, str_num.c_str(), *out_buffer_length ); + + return SQL_SUCCESS; +} + +template +SQLRETURN string_to_number( Char* string_data, SQLLEN str_len, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length, sqlsrv_error_auto_ptr& last_error ) +{ + Number* number_data = reinterpret_cast( buffer ); + std::locale loc; // default locale should match system + std::basic_istringstream is; + is.str( string_data ); + is.imbue( loc ); + std::ios_base::iostate st = 0; + + std::use_facet< std::num_get< Char > >( loc ).get( std::basic_istream::_Iter( is.rdbuf( ) ), + std::basic_istream::_Iter(0), is, st, *number_data ); + + if( st & std::ios_base::failbit ) { + last_error = new ( sqlsrv_malloc( sizeof( sqlsrv_error ))) sqlsrv_error( + (SQLCHAR*) "22003", (SQLCHAR*) "Numeric value out of range", 103 ); + return SQL_ERROR; + } + + *out_buffer_length = sizeof( Number ); + + return SQL_SUCCESS; +} + +// "closure" for the hash table destructor +struct row_dtor_closure { + + sqlsrv_buffered_result_set* results; + BYTE* row_data; + + row_dtor_closure( sqlsrv_buffered_result_set* st, BYTE* row ) : + results( st ), row_data( row ) + { + } +}; + +sqlsrv_error* odbc_get_diag_rec( sqlsrv_stmt* odbc, SQLSMALLINT record_number ) +{ + SQLWCHAR wsql_state[ SQL_SQLSTATE_BUFSIZE ]; + SQLCHAR* sql_state = reinterpret_cast( wsql_state ); + SQLWCHAR wnative_message[ SQL_MAX_MESSAGE_LENGTH + 1 ]; + sqlsrv_malloc_auto_ptr native_message; + SQLINTEGER native_code; + SQLINTEGER message_len; + + SQLRETURN r = SQLGetDiagRecW( SQL_HANDLE_STMT, odbc->handle(), record_number, wsql_state, &native_code, wnative_message, + SQL_MAX_MESSAGE_LENGTH + 1, NULL ); + if( !SQL_SUCCEEDED( r ) || r == SQL_NO_DATA ) { + return NULL; + } + + // convert the error into the encoding of the context + SQLSRV_ENCODING enc = odbc->encoding(); + if( enc == SQLSRV_ENCODING_DEFAULT ) { + enc = odbc->conn->encoding(); + } + + // convert the error into the encoding of the context + message_len = SQL_SQLSTATE_BUFSIZE * sizeof(WCHAR); + convert_string_from_utf16( enc, reinterpret_cast( &sql_state ), message_len, + false /*no free*/ ); + message_len = (SQL_MAX_MESSAGE_LENGTH + 1) * sizeof( WCHAR ); + native_message = reinterpret_cast( wnative_message ); + convert_string_from_utf16( enc, reinterpret_cast( &native_message ), message_len, + false /*no free*/ ); + + return new (sqlsrv_malloc( sizeof( sqlsrv_error ))) sqlsrv_error( (SQLCHAR*) sql_state, (SQLCHAR*) native_message, + native_code ); +} + +} // namespace + +// base class result set + +sqlsrv_result_set::sqlsrv_result_set( sqlsrv_stmt* stmt ) : + odbc( stmt ) +{ +} + + +// ODBC result set +// This object simply wraps ODBC function calls + +sqlsrv_odbc_result_set::sqlsrv_odbc_result_set( sqlsrv_stmt* stmt ) : + sqlsrv_result_set( stmt ) +{ +} + +sqlsrv_odbc_result_set::~sqlsrv_odbc_result_set( void ) +{ +} + +SQLRETURN sqlsrv_odbc_result_set::fetch( SQLSMALLINT orientation, SQLLEN offset TSRMLS_DC ) +{ + SQLSRV_ASSERT( odbc != NULL, "Invalid statement handle" ); + return core::SQLFetchScroll( odbc, orientation, offset TSRMLS_CC ); +} + +SQLRETURN sqlsrv_odbc_result_set::get_data( SQLUSMALLINT field_index, SQLSMALLINT target_type, + __out SQLPOINTER buffer, SQLLEN buffer_length, __out SQLLEN* out_buffer_length, + bool handle_warning TSRMLS_DC ) +{ + SQLSRV_ASSERT( odbc != NULL, "Invalid statement handle" ); + return core::SQLGetData( odbc, field_index, target_type, buffer, buffer_length, out_buffer_length, handle_warning TSRMLS_CC ); +} + +SQLRETURN sqlsrv_odbc_result_set::get_diag_field( SQLSMALLINT record_number, SQLSMALLINT diag_identifier, + __out SQLPOINTER diag_info_buffer, SQLSMALLINT buffer_length, + __out SQLSMALLINT* out_buffer_length TSRMLS_DC ) +{ + SQLSRV_ASSERT( odbc != NULL, "Invalid statement handle" ); + return core::SQLGetDiagField( odbc, record_number, diag_identifier, diag_info_buffer, buffer_length, + out_buffer_length TSRMLS_CC ); +} + +sqlsrv_error* sqlsrv_odbc_result_set::get_diag_rec( SQLSMALLINT record_number ) +{ + SQLSRV_ASSERT( odbc != NULL, "Invalid statement handle" ); + return odbc_get_diag_rec( odbc, record_number ); +} + +SQLLEN sqlsrv_odbc_result_set::row_count( TSRMLS_D ) +{ + SQLSRV_ASSERT( odbc != NULL, "Invalid statement handle" ); + return core::SQLRowCount( odbc TSRMLS_CC ); +} + + +// Buffered result set +// This class holds a result set in memory + +sqlsrv_buffered_result_set::sqlsrv_buffered_result_set( sqlsrv_stmt* stmt TSRMLS_DC ) : + sqlsrv_result_set( stmt ), + cache(NULL), + col_count(0), + meta(NULL), + current(0), + last_field_index(-1), + read_so_far(0) +{ + // 10 is an arbitrary number for now for the initial size of the cache + ALLOC_HASHTABLE( cache ); + + core::sqlsrv_zend_hash_init( *stmt, cache, 10 /* # of buckets */, NULL /* hashfn */, cache_row_dtor /*dtor*/, 0 /*persistent*/ + TSRMLS_CC ); + col_count = core::SQLNumResultCols( stmt TSRMLS_CC ); + // there is no result set to buffer + if( col_count == 0 ) { + return; + } + + SQLULEN null_bytes = ( col_count / 8 ) + 1; // number of bits to reserve at the beginning of each row for NULL flags + meta = static_cast( sqlsrv_malloc( col_count * + sizeof( sqlsrv_buffered_result_set::meta_data ))); + + // set up the conversion matrix if this is the first time we're called + if( conv_matrix.size() == 0 ) { + + conv_matrix[ SQL_C_CHAR ][ SQL_C_CHAR ] = &sqlsrv_buffered_result_set::to_same_string; + conv_matrix[ SQL_C_CHAR ][ SQL_C_WCHAR ] = &sqlsrv_buffered_result_set::system_to_wide_string; + conv_matrix[ SQL_C_CHAR ][ SQL_C_BINARY ] = &sqlsrv_buffered_result_set::to_binary_string; + conv_matrix[ SQL_C_CHAR ][ SQL_C_DOUBLE ] = &sqlsrv_buffered_result_set::string_to_double; + conv_matrix[ SQL_C_CHAR ][ SQL_C_LONG ] = &sqlsrv_buffered_result_set::string_to_long; + conv_matrix[ SQL_C_WCHAR ][ SQL_C_WCHAR ] = &sqlsrv_buffered_result_set::to_same_string; + conv_matrix[ SQL_C_WCHAR ][ SQL_C_BINARY ] = &sqlsrv_buffered_result_set::to_binary_string; + conv_matrix[ SQL_C_WCHAR ][ SQL_C_CHAR ] = &sqlsrv_buffered_result_set::wide_to_system_string; + conv_matrix[ SQL_C_WCHAR ][ SQL_C_DOUBLE ] = &sqlsrv_buffered_result_set::wstring_to_double; + conv_matrix[ SQL_C_WCHAR ][ SQL_C_LONG ] = &sqlsrv_buffered_result_set::wstring_to_long; + conv_matrix[ SQL_C_BINARY ][ SQL_C_BINARY ] = &sqlsrv_buffered_result_set::to_same_string; + conv_matrix[ SQL_C_BINARY ][ SQL_C_CHAR ] = &sqlsrv_buffered_result_set::binary_to_system_string; + conv_matrix[ SQL_C_BINARY ][ SQL_C_WCHAR ] = &sqlsrv_buffered_result_set::binary_to_wide_string; + conv_matrix[ SQL_C_LONG ][ SQL_C_DOUBLE ] = &sqlsrv_buffered_result_set::long_to_double; + conv_matrix[ SQL_C_LONG ][ SQL_C_LONG ] = &sqlsrv_buffered_result_set::to_long; + conv_matrix[ SQL_C_LONG ][ SQL_C_BINARY ] = &sqlsrv_buffered_result_set::to_long; + conv_matrix[ SQL_C_LONG ][ SQL_C_CHAR ] = &sqlsrv_buffered_result_set::long_to_system_string; + conv_matrix[ SQL_C_LONG ][ SQL_C_WCHAR ] = &sqlsrv_buffered_result_set::long_to_wide_string; + conv_matrix[ SQL_C_DOUBLE ][ SQL_C_DOUBLE ] = &sqlsrv_buffered_result_set::to_double; + conv_matrix[ SQL_C_DOUBLE ][ SQL_C_BINARY ] = &sqlsrv_buffered_result_set::to_double; + conv_matrix[ SQL_C_DOUBLE ][ SQL_C_CHAR ] = &sqlsrv_buffered_result_set::double_to_system_string; + conv_matrix[ SQL_C_DOUBLE ][ SQL_C_LONG ] = &sqlsrv_buffered_result_set::double_to_long; + conv_matrix[ SQL_C_DOUBLE ][ SQL_C_WCHAR ] = &sqlsrv_buffered_result_set::double_to_wide_string; + } + + // get the meta data and calculate the size of a row buffer + SQLULEN offset = null_bytes; + for( SQLSMALLINT i = 0; i < col_count; ++i ) { + + core::SQLDescribeCol( stmt, i + 1, NULL, 0, NULL, &meta[i].type, &meta[i].length, &meta[i].scale, NULL TSRMLS_CC ); + + offset = align_to<4>( offset ); + meta[i].offset = offset; + + switch( meta[i].type ) { + + // these types are the display size + case SQL_BIGINT: + case SQL_DECIMAL: + case SQL_GUID: + case SQL_NUMERIC: + core::SQLColAttribute( stmt, i + 1, SQL_DESC_DISPLAY_SIZE, NULL, 0, NULL, + reinterpret_cast( &meta[i].length ) TSRMLS_CC ); + meta[i].length += sizeof( char ) + sizeof( SQLULEN ); // null terminator space + offset += meta[i].length; + break; + + // these types are the column size + case SQL_BINARY: + case SQL_CHAR: + case SQL_SS_UDT: + case SQL_VARBINARY: + case SQL_VARCHAR: + // var* field types are length prefixed + if( meta[i].length == sqlsrv_buffered_result_set::meta_data::SIZE_UNKNOWN ) { + offset += sizeof( void* ); + } + else { + meta[i].length += sizeof( SQLULEN ) + sizeof( char ); // length plus null terminator space + offset += meta[i].length; + } + break; + + case SQL_WCHAR: + case SQL_WVARCHAR: + if( meta[i].length == sqlsrv_buffered_result_set::meta_data::SIZE_UNKNOWN ) { + offset += sizeof( void* ); + } + else { + meta[i].length *= sizeof( WCHAR ); + meta[i].length += sizeof( SQLULEN ) + sizeof( WCHAR ); // length plus null terminator space + offset += meta[i].length; + } + break; + + // these types are LOBs + case SQL_LONGVARBINARY: + case SQL_LONGVARCHAR: + case SQL_WLONGVARCHAR: + case SQL_SS_XML: + meta[i].length = sqlsrv_buffered_result_set::meta_data::SIZE_UNKNOWN; + offset += sizeof( void* ); + break; + + // these types are the ISO date size + case SQL_DATETIME: + case SQL_TYPE_DATE: + case SQL_SS_TIME2: + case SQL_SS_TIMESTAMPOFFSET: + case SQL_TYPE_TIMESTAMP: + core::SQLColAttribute( stmt, i + 1, SQL_DESC_DISPLAY_SIZE, NULL, 0, NULL, + reinterpret_cast( &meta[i].length ) TSRMLS_CC ); + meta[i].length += sizeof(char) + sizeof( SQLULEN ); // null terminator space + offset += meta[i].length; + break; + + // these types are the native size + case SQL_BIT: + case SQL_INTEGER: + case SQL_SMALLINT: + case SQL_TINYINT: + meta[i].length = sizeof( long ); + offset += meta[i].length; + break; + + case SQL_REAL: + case SQL_FLOAT: + meta[i].length = sizeof( double ); + offset += meta[i].length; + break; + + default: + SQLSRV_ASSERT( false, "Unknown type in sqlsrv_buffered_query::sqlsrv_buffered_query" ); + break; + } + + switch( meta[i].type ) { + + case SQL_BIGINT: + case SQL_CHAR: + case SQL_DATETIME: + case SQL_DECIMAL: + case SQL_GUID: + case SQL_NUMERIC: + case SQL_LONGVARCHAR: + case SQL_TYPE_DATE: + case SQL_SS_TIME2: + case SQL_SS_TIMESTAMPOFFSET: + case SQL_SS_XML: + case SQL_TYPE_TIMESTAMP: + case SQL_VARCHAR: + meta[i].c_type = SQL_C_CHAR; + break; + + case SQL_SS_UDT: + case SQL_LONGVARBINARY: + case SQL_BINARY: + case SQL_VARBINARY: + meta[i].c_type = SQL_C_BINARY; + break; + + case SQL_WLONGVARCHAR: + case SQL_WCHAR: + case SQL_WVARCHAR: + meta[i].c_type = SQL_C_WCHAR; + break; + + case SQL_BIT: + case SQL_INTEGER: + case SQL_SMALLINT: + case SQL_TINYINT: + meta[i].c_type = SQL_C_LONG; + break; + + case SQL_REAL: + case SQL_FLOAT: + meta[i].c_type = SQL_C_DOUBLE; + break; + + default: + SQLSRV_ASSERT( false, "Unknown type in sqlsrv_buffered_query::sqlsrv_buffered_query" ); + break; + } + + } + + // read the data into the cache + // (offset from the above loop has the size of the row buffer necessary) + unsigned long mem_used = 0; + unsigned long row_count = 0; + + while( core::SQLFetchScroll( stmt, SQL_FETCH_NEXT, 0 TSRMLS_CC ) != SQL_NO_DATA ) { + + // allocate the row buffer + unsigned char* row = static_cast( sqlsrv_malloc( offset )); + memset( row, 0, offset ); + + // read the fields into the row buffer + for( SQLSMALLINT i = 0; i < col_count; ++i ) { + + SQLLEN out_buffer_temp = SQL_NULL_DATA; + SQLPOINTER buffer; + SQLLEN* out_buffer_length = &out_buffer_temp; + + switch( meta[i].c_type ) { + + case SQL_C_CHAR: + case SQL_C_WCHAR: + case SQL_C_BINARY: + if( meta[i].length == sqlsrv_buffered_result_set::meta_data::SIZE_UNKNOWN ) { + + out_buffer_length = &out_buffer_temp; + SQLPOINTER* lob_addr = reinterpret_cast( &row[ meta[i].offset ] ); + *lob_addr = read_lob_field( stmt, i, meta[i], mem_used TSRMLS_CC ); + // a NULL pointer means NULL field + if( *lob_addr == NULL ) { + *out_buffer_length = SQL_NULL_DATA; + } + else { + *out_buffer_length = **reinterpret_cast( lob_addr ); + mem_used += *out_buffer_length; + } + } + else { + + mem_used += meta[i].length; + CHECK_CUSTOM_ERROR( mem_used > stmt->buffered_query_limit * 1024, stmt, + SQLSRV_ERROR_BUFFER_LIMIT_EXCEEDED, stmt->buffered_query_limit ) { + + throw core::CoreException(); + } + + buffer = row + meta[i].offset + sizeof( SQLULEN ); + out_buffer_length = reinterpret_cast( row + meta[i].offset ); + core::SQLGetData( stmt, i + 1, meta[i].c_type, buffer, meta[i].length, out_buffer_length, + false TSRMLS_CC ); + } + break; + + case SQL_C_LONG: + case SQL_C_DOUBLE: + { + mem_used += meta[i].length; + CHECK_CUSTOM_ERROR( mem_used > stmt->buffered_query_limit * 1024, stmt, + SQLSRV_ERROR_BUFFER_LIMIT_EXCEEDED, stmt->buffered_query_limit ) { + + throw core::CoreException(); + } + buffer = row + meta[i].offset; + out_buffer_length = &out_buffer_temp; + core::SQLGetData( stmt, i + 1, meta[i].c_type, buffer, meta[i].length, out_buffer_length, + false TSRMLS_CC ); + } + break; + + default: + SQLSRV_ASSERT( false, "Unknown C type" ); + break; + } + + if( *out_buffer_length == SQL_NULL_DATA ) { + unsigned char* null_bits = reinterpret_cast( row ); + set_bit( row, i ); + } + } + + SQLSRV_ASSERT( row_count < LONG_MAX, "Hard maximum of 2 billion rows exceeded in a buffered query" ); + + // add it to the cache + row_dtor_closure cl( this, row ); + sqlsrv_zend_hash_next_index_insert( *stmt, cache, &cl, sizeof( cl ) TSRMLS_CC ); + } + +} + +sqlsrv_buffered_result_set::~sqlsrv_buffered_result_set( void ) +{ + // free the rows + if( cache ) { + zend_hash_destroy( cache ); + FREE_HASHTABLE( cache ); + cache = NULL; + } + + // free the meta data + if( meta ) { + efree( meta ); + meta = NULL; + } +} + +SQLRETURN sqlsrv_buffered_result_set::fetch( SQLSMALLINT orientation, SQLLEN offset TSRMLS_DC ) +{ + last_error = NULL; + last_field_index = -1; + read_so_far = 0; + + switch( orientation ) { + + case SQL_FETCH_NEXT: + offset = 1; + orientation = SQL_FETCH_RELATIVE; + break; + case SQL_FETCH_PRIOR: + offset = -1; + orientation = SQL_FETCH_RELATIVE; + break; + } + + switch( orientation ) { + + case SQL_FETCH_FIRST: + current = 1; + break; + case SQL_FETCH_LAST: + current = row_count( TSRMLS_C ); + break; + case SQL_FETCH_ABSOLUTE: + current = offset; + break; + case SQL_FETCH_RELATIVE: + current += offset; + break; + default: + SQLSRV_ASSERT( false, "Invalid fetch orientation. Should have been caught before here." ); + break; + } + + // check validity of current row + // the cursor can never get further away than just before the first row + if( current <= 0 && ( offset < 0 || orientation != SQL_FETCH_RELATIVE )) { + current = 0; + return SQL_NO_DATA; + } + + // the cursor can never get further away than just after the last row + if( current > row_count( TSRMLS_C ) || ( current <= 0 && offset > 0 ) /*overflow condition*/ ) { + current = row_count( TSRMLS_C ) + 1; + return SQL_NO_DATA; + } + + return SQL_SUCCESS; +} + +SQLRETURN sqlsrv_buffered_result_set::get_data( SQLUSMALLINT field_index, SQLSMALLINT target_type, + __out SQLPOINTER buffer, SQLLEN buffer_length, __out SQLLEN* out_buffer_length, + bool handle_warning TSRMLS_DC ) +{ + last_error = NULL; + field_index--; // convert from 1 based to 0 based + SQLSRV_ASSERT( field_index < column_count(), "Invalid field index requested" ); + + if( field_index != last_field_index ) { + last_field_index = field_index; + read_so_far = 0; + } + + unsigned char* row = get_row(); + + // if the field is null, then return SQL_NULL_DATA + if( get_bit( row, field_index )) { + *out_buffer_length = SQL_NULL_DATA; + return SQL_SUCCESS; + } + + // check to make sure the conversion type is valid + if( conv_matrix.find( meta[ field_index ].c_type ) == conv_matrix.end() || + conv_matrix.find( meta[ field_index ].c_type )->second.find( target_type ) == + conv_matrix.find( meta[ field_index ].c_type )->second.end() ) { + + last_error = new (sqlsrv_malloc( sizeof( sqlsrv_error ))) + sqlsrv_error( (SQLCHAR*) "07006", + (SQLCHAR*) "Restricted data type attribute violation", 0 ); + return SQL_ERROR; + } + + return (( this )->*( conv_matrix[ meta[ field_index ].c_type ][ target_type ] ))( field_index, buffer, buffer_length, + out_buffer_length ); +} + +SQLRETURN sqlsrv_buffered_result_set::get_diag_field( SQLSMALLINT record_number, SQLSMALLINT diag_identifier, + __out SQLPOINTER diag_info_buffer, SQLSMALLINT buffer_length, + __out SQLSMALLINT* out_buffer_length TSRMLS_DC ) +{ + SQLSRV_ASSERT( record_number == 1, "Only record number 1 can be fetched by sqlsrv_buffered_result_set::get_diag_field" ); + SQLSRV_ASSERT( diag_identifier == SQL_DIAG_SQLSTATE, + "Only SQL_DIAG_SQLSTATE can be fetched by sqlsrv_buffered_result_set::get_diag_field" ); + SQLSRV_ASSERT( buffer_length >= SQL_SQLSTATE_BUFSIZE, + "Buffer not big enough to return SQLSTATE in sqlsrv_buffered_result_set::get_diag_field" ); + + if( last_error == NULL ) { + return SQL_NO_DATA; + } + + SQLSRV_ASSERT( last_error->sqlstate != NULL, + "Must have a SQLSTATE in a valid last_error in sqlsrv_buffered_result_set::get_diag_field" ); + + memcpy( diag_info_buffer, last_error->sqlstate, min( buffer_length, SQL_SQLSTATE_BUFSIZE )); + + return SQL_SUCCESS; +} + +unsigned char* sqlsrv_buffered_result_set::get_row( void ) +{ + row_dtor_closure* cl_ptr; + int zr = zend_hash_index_find( cache, current - 1, (void**) &cl_ptr ); + SQLSRV_ASSERT( zr == SUCCESS, "Failed to find row %1!d! in the cache", current ); + return cl_ptr->row_data; +} + +sqlsrv_error* sqlsrv_buffered_result_set::get_diag_rec( SQLSMALLINT record_number ) +{ + // we only hold a single error if there is one, otherwise return the ODBC error(s) + if( last_error == NULL ) { + return odbc_get_diag_rec( odbc, record_number ); + } + if( record_number > 1 ) { + return NULL; + } + + return new (sqlsrv_malloc( sizeof( sqlsrv_error ))) + sqlsrv_error( last_error->sqlstate, last_error->native_message, last_error->native_code ); +} + +SQLLEN sqlsrv_buffered_result_set::row_count( TSRMLS_D ) +{ + last_error = NULL; + + return zend_hash_num_elements( cache ); +} + +// private functions +template +SQLRETURN binary_to_string( SQLCHAR* field_data, SQLLEN& read_so_far, __out void* buffer, + SQLLEN buffer_length, __out SQLLEN* out_buffer_length, + sqlsrv_error_auto_ptr& out_error ) +{ + // hex characters for the conversion loop below + static char hex_chars[] = "0123456789ABCDEF"; + + SQLSRV_ASSERT( out_error == NULL, "Pending error for sqlsrv_buffered_results_set::binary_to_string" ); + + SQLRETURN r = SQL_ERROR; + + // Set the amount of space necessary for null characters at the end of the data. + SQLSMALLINT extra = sizeof(Char); + + SQLSRV_ASSERT( ((buffer_length - extra) % (extra * 2)) == 0, "Must be multiple of 2 for binary to system string or " + "multiple of 4 for binary to wide string" ); + + // all fields will be treated as ODBC returns varchar(max) fields: + // the entire length of the string is returned the first + // call in out_buffer_len. Successive calls return how much is + // left minus how much has already been read by previous reads + // *2 is for each byte to hex conversion and * extra is for either system or wide string allocation + *out_buffer_length = (*reinterpret_cast( field_data - sizeof( SQLULEN )) - read_so_far) * 2 * extra; + + // copy as much as we can into the buffer + SQLLEN to_copy; + if( buffer_length < *out_buffer_length + extra ) { + to_copy = (buffer_length - extra); + out_error = new ( sqlsrv_malloc( sizeof( sqlsrv_error ))) + sqlsrv_error( (SQLCHAR*) "01004", (SQLCHAR*) "String data, right truncated", -1 ); + r = SQL_SUCCESS_WITH_INFO; + } + else { + r = SQL_SUCCESS; + to_copy = *out_buffer_length; + } + + // if there are bytes to copy as hex + if( to_copy > 0 ) { + // quick hex conversion routine + Char* h = reinterpret_cast( buffer ); + BYTE* b = reinterpret_cast( field_data ); + // to_copy contains the number of bytes to copy, so we divide the number in half (or quarter) + // to get the number of hex digits we can copy + SQLLEN to_copy_hex = to_copy / (2 * extra); + for( int i = 0; i < to_copy_hex; ++i ) { + *h = hex_chars[ (*b & 0xf0) >> 4 ]; + h++; + *h = hex_chars[ (*b++ & 0x0f) ]; + h++; + } + read_so_far += to_copy_hex; + *h = static_cast( 0 ); + } + else { + reinterpret_cast( buffer )[0] = '\0'; + } + + return r; +} + +SQLRETURN sqlsrv_buffered_result_set::binary_to_system_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ) +{ + SQLCHAR* row = get_row(); + SQLCHAR* field_data = NULL; + + if( meta[ field_index ].length == sqlsrv_buffered_result_set::meta_data::SIZE_UNKNOWN ) { + + field_data = *reinterpret_cast( &row[ meta[ field_index ].offset ] ) + sizeof( SQLULEN ); + } + else { + + field_data = &row[ meta[ field_index ].offset ] + sizeof( SQLULEN ); + } + + return binary_to_string( field_data, read_so_far, buffer, buffer_length, out_buffer_length, last_error ); +} + +SQLRETURN sqlsrv_buffered_result_set::binary_to_wide_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ) +{ + SQLCHAR* row = get_row(); + SQLCHAR* field_data = NULL; + + if( meta[ field_index ].length == sqlsrv_buffered_result_set::meta_data::SIZE_UNKNOWN ) { + + field_data = *reinterpret_cast( &row[ meta[ field_index ].offset ] ) + sizeof( SQLULEN ); + } + else { + + field_data = &row[ meta[ field_index ].offset ] + sizeof( SQLULEN ); + } + + return binary_to_string( field_data, read_so_far, buffer, buffer_length, out_buffer_length, last_error ); +} + + +SQLRETURN sqlsrv_buffered_result_set::double_to_long( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ) +{ + SQLSRV_ASSERT( meta[ field_index ].c_type == SQL_C_DOUBLE, "Invalid conversion to long" ); + SQLSRV_ASSERT( buffer_length >= sizeof(LONG), "Buffer length must be able to find a long in " + "sqlsrv_buffered_result_set::double_to_long" ); + + unsigned char* row = get_row(); + double* double_data = reinterpret_cast( &row[ meta[ field_index ].offset ] ); + LONG* long_data = reinterpret_cast( buffer ); + + if( *double_data < double( LONG_MIN ) || *double_data > double( LONG_MAX )) { + last_error = new (sqlsrv_malloc( sizeof( sqlsrv_error ))) sqlsrv_error( (SQLCHAR*) "22003", + (SQLCHAR*) "Numeric value out of range", 0 ); + return SQL_ERROR; + } + + if( *double_data != floor( *double_data )) { + last_error = new (sqlsrv_malloc( sizeof( sqlsrv_error ))) sqlsrv_error( (SQLCHAR*) "01S07", + (SQLCHAR*) "Fractional truncation", 0 ); + return SQL_SUCCESS_WITH_INFO; + } + + *long_data = static_cast( *double_data ); + *out_buffer_length = sizeof( LONG ); + + return SQL_SUCCESS; +} + +SQLRETURN sqlsrv_buffered_result_set::double_to_system_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ) +{ + SQLSRV_ASSERT( meta[ field_index ].c_type == SQL_C_DOUBLE, "Invalid conversion to system string" ); + SQLSRV_ASSERT( buffer_length > 0, "Buffer length must be > 0 in sqlsrv_buffered_result_set::double_to_system_string" ); + + unsigned char* row = get_row(); + double* double_data = reinterpret_cast( &row[ meta[ field_index ].offset ] ); + + return number_to_string( double_data, buffer, buffer_length, out_buffer_length, last_error ); +} + +SQLRETURN sqlsrv_buffered_result_set::double_to_wide_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ) +{ + SQLSRV_ASSERT( meta[ field_index ].c_type == SQL_C_DOUBLE, "Invalid conversion to wide string" ); + SQLSRV_ASSERT( buffer_length > 0, "Buffer length must be > 0 in sqlsrv_buffered_result_set::double_to_wide_string" ); + + unsigned char* row = get_row(); + double* double_data = reinterpret_cast( &row[ meta[ field_index ].offset ] ); + + return number_to_string( double_data, buffer, buffer_length, out_buffer_length, last_error ); +} + +SQLRETURN sqlsrv_buffered_result_set::long_to_double( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ) +{ + SQLSRV_ASSERT( meta[ field_index ].c_type == SQL_C_LONG, "Invalid conversion to long" ); + SQLSRV_ASSERT( buffer_length >= sizeof(double), "Buffer length must be able to find a long in sqlsrv_buffered_result_set::double_to_long" ); + + unsigned char* row = get_row(); + double* double_data = reinterpret_cast( buffer ); + LONG* long_data = reinterpret_cast( &row[ meta[ field_index ].offset ] ); + + *double_data = static_cast( *long_data ); + *out_buffer_length = sizeof( double ); + + return SQL_SUCCESS; +} +SQLRETURN sqlsrv_buffered_result_set::long_to_system_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ) +{ + SQLSRV_ASSERT( meta[ field_index ].c_type == SQL_C_LONG, "Invalid conversion to system string" ); + SQLSRV_ASSERT( buffer_length > 0, "Buffer length must be > 0 in sqlsrv_buffered_result_set::long_to_system_string" ); + + unsigned char* row = get_row(); + LONG* long_data = reinterpret_cast( &row[ meta[ field_index ].offset ] ); + + return number_to_string( long_data, buffer, buffer_length, out_buffer_length, last_error ); +} + +SQLRETURN sqlsrv_buffered_result_set::long_to_wide_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ) +{ + SQLSRV_ASSERT( meta[ field_index ].c_type == SQL_C_LONG, "Invalid conversion to wide string" ); + SQLSRV_ASSERT( buffer_length > 0, "Buffer length must be > 0 in sqlsrv_buffered_result_set::long_to_wide_string" ); + + unsigned char* row = get_row(); + LONG* long_data = reinterpret_cast( &row[ meta[ field_index ].offset ] ); + + return number_to_string( long_data, buffer, buffer_length, out_buffer_length, last_error ); +} + +SQLRETURN sqlsrv_buffered_result_set::string_to_double( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ) +{ + SQLSRV_ASSERT( meta[ field_index ].c_type == SQL_C_CHAR, "Invalid conversion from string to double" ); + SQLSRV_ASSERT( buffer_length >= sizeof( double ), "Buffer needs to be big enough to hold a double" ); + + unsigned char* row = get_row(); + char* string_data = reinterpret_cast( &row[ meta[ field_index ].offset ] ) + sizeof( SQLULEN ); + + return string_to_number( string_data, meta[ field_index ].length, buffer, buffer_length, out_buffer_length, last_error ); +} + +SQLRETURN sqlsrv_buffered_result_set::wstring_to_double( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ) +{ + SQLSRV_ASSERT( meta[ field_index ].c_type == SQL_C_WCHAR, "Invalid conversion from wide string to double" ); + SQLSRV_ASSERT( buffer_length >= sizeof( double ), "Buffer needs to be big enough to hold a double" ); + + unsigned char* row = get_row(); + SQLWCHAR* string_data = reinterpret_cast( &row[ meta[ field_index ].offset ] ) + sizeof( SQLULEN ) / sizeof( SQLWCHAR ); + + return string_to_number( string_data, meta[ field_index ].length, buffer, buffer_length, out_buffer_length, last_error ); +} + +SQLRETURN sqlsrv_buffered_result_set::string_to_long( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ) +{ + SQLSRV_ASSERT( meta[ field_index ].c_type == SQL_C_CHAR, "Invalid conversion from string to long" ); + SQLSRV_ASSERT( buffer_length >= sizeof( LONG ), "Buffer needs to be big enough to hold a long" ); + + unsigned char* row = get_row(); + char* string_data = reinterpret_cast( &row[ meta[ field_index ].offset ] ) + sizeof( SQLULEN ); + + return string_to_number( string_data, meta[ field_index ].length, buffer, buffer_length, out_buffer_length, last_error ); +} + +SQLRETURN sqlsrv_buffered_result_set::wstring_to_long( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ) +{ + SQLSRV_ASSERT( meta[ field_index ].c_type == SQL_C_WCHAR, "Invalid conversion from wide string to long" ); + SQLSRV_ASSERT( buffer_length >= sizeof( LONG ), "Buffer needs to be big enough to hold a long" ); + + unsigned char* row = get_row(); + SQLWCHAR* string_data = reinterpret_cast( &row[ meta[ field_index ].offset ] ) + sizeof( SQLULEN ) / sizeof( SQLWCHAR ); + + return string_to_number( string_data, meta[ field_index ].length, buffer, buffer_length, out_buffer_length, last_error ); +} + +SQLRETURN sqlsrv_buffered_result_set::system_to_wide_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ) +{ + SQLSRV_ASSERT( last_error == NULL, "Pending error for sqlsrv_buffered_results_set::system_to_wide_string" ); + SQLSRV_ASSERT( buffer_length % 2 == 0, "Odd buffer length passed to sqlsrv_buffered_result_set::system_to_wide_string" ); + + SQLRETURN r = SQL_ERROR; + unsigned char* row = get_row(); + + SQLCHAR* field_data = NULL; + SQLULEN field_len = NULL; + + if( meta[ field_index ].length == sqlsrv_buffered_result_set::meta_data::SIZE_UNKNOWN ) { + + field_len = **reinterpret_cast( &row[ meta[ field_index ].offset ] ); + field_data = *reinterpret_cast( &row[ meta[ field_index ].offset ] ) + sizeof( SQLULEN ) + read_so_far; + } + else { + + field_len = *reinterpret_cast( &row[ meta[ field_index ].offset ] ); + field_data = &row[ meta[ field_index ].offset ] + sizeof( SQLULEN ) + read_so_far; + } + + // all fields will be treated as ODBC returns varchar(max) fields: + // the entire length of the string is returned the first + // call in out_buffer_len. Successive calls return how much is + // left minus how much has already been read by previous reads + *out_buffer_length = (*reinterpret_cast( field_data - sizeof( SQLULEN )) - read_so_far) * sizeof(WCHAR); + + // to_copy is the number of characters to copy, not including the null terminator + // supposedly it will never happen that a Windows MBCS will explode to UTF-16 surrogate pair. + SQLLEN to_copy; + + if( (size_t) buffer_length < (field_len - read_so_far + sizeof(char)) * sizeof(WCHAR)) { + + to_copy = (buffer_length - sizeof(WCHAR)) / sizeof(WCHAR); // to_copy is the number of characters + last_error = new ( sqlsrv_malloc( sizeof( sqlsrv_error ))) + sqlsrv_error( (SQLCHAR*) "01004", (SQLCHAR*) "String data, right truncated", -1 ); + r = SQL_SUCCESS_WITH_INFO; + } + else { + + r = SQL_SUCCESS; + to_copy = field_len - read_so_far; + } + + if( to_copy > 0 ) { + + bool tried_again = false; + do { + int ch_space = MultiByteToWideChar( CP_ACP, MB_ERR_INVALID_CHARS, (LPCSTR) field_data, to_copy, + (LPWSTR) buffer, to_copy ); + if( ch_space == 0 ) { + + switch( GetLastError() ) { + + case ERROR_NO_UNICODE_TRANSLATION: + // the theory here is the conversion failed because the end of the buffer we provided contained only + // half a character at the end + if( !tried_again ) { + to_copy--; + tried_again = true; + continue; + } + last_error = new ( sqlsrv_malloc( sizeof( sqlsrv_error ))) + sqlsrv_error( (SQLCHAR*) "IMSSP", (SQLCHAR*) "Invalid Unicode translation", -1 ); + break; + default: + SQLSRV_ASSERT( false, "Severe error translating Unicode" ); + break; + } + + return SQL_ERROR; + } + + ((WCHAR*)buffer)[ to_copy ] = L'\0'; + read_so_far += to_copy; + break; + + } while( true ); + } + else { + reinterpret_cast( buffer )[0] = L'\0'; + } + + return r; +} + +SQLRETURN sqlsrv_buffered_result_set::to_same_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ) +{ + SQLSRV_ASSERT( last_error == NULL, "Pending error for sqlsrv_buffered_results_set::to_same_string" ); + + SQLRETURN r = SQL_ERROR; + unsigned char* row = get_row(); + + // Set the amount of space necessary for null characters at the end of the data. + SQLSMALLINT extra = 0; + + switch( meta[ field_index ].c_type ) { + case SQL_C_WCHAR: + extra = sizeof( SQLWCHAR ); + break; + case SQL_C_BINARY: + extra = 0; + break; + case SQL_C_CHAR: + extra = sizeof( SQLCHAR ); + break; + default: + SQLSRV_ASSERT( false, "Invalid type in get_string_data" ); + break; + } + + SQLCHAR* field_data = NULL; + + if( meta[ field_index ].length == sqlsrv_buffered_result_set::meta_data::SIZE_UNKNOWN ) { + + field_data = *reinterpret_cast( &row[ meta[ field_index ].offset ] ) + sizeof( SQLULEN ); + } + else { + + field_data = &row[ meta[ field_index ].offset ] + sizeof( SQLULEN ); + } + + // all fields will be treated as ODBC returns varchar(max) fields: + // the entire length of the string is returned the first + // call in out_buffer_len. Successive calls return how much is + // left minus how much has already been read by previous reads + *out_buffer_length = *reinterpret_cast( field_data - sizeof( SQLULEN )) - read_so_far; + + // copy as much as we can into the buffer + SQLLEN to_copy; + if( buffer_length < *out_buffer_length + extra ) { + to_copy = buffer_length - extra; + last_error = new ( sqlsrv_malloc( sizeof( sqlsrv_error ))) + sqlsrv_error( (SQLCHAR*) "01004", (SQLCHAR*) "String data, right truncated", -1 ); + r = SQL_SUCCESS_WITH_INFO; + } + else { + r = SQL_SUCCESS; + to_copy = *out_buffer_length; + } + + SQLSRV_ASSERT( to_copy >= 0, "Negative field length calculated in buffered result set" ); + + if( to_copy > 0 ) { + memcpy( buffer, field_data + read_so_far, to_copy ); + read_so_far += to_copy; + } + if( extra ) { + OACR_WARNING_SUPPRESS( 26001, "Buffer length verified above" ); + memcpy( reinterpret_cast( buffer ) + to_copy, L"\0", extra ); + } + + return r; +} + +SQLRETURN sqlsrv_buffered_result_set::wide_to_system_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ) +{ + SQLSRV_ASSERT( last_error == NULL, "Pending error for sqlsrv_buffered_results_set::wide_to_system_string" ); + + SQLRETURN r = SQL_ERROR; + unsigned char* row = get_row(); + + SQLCHAR* field_data = NULL; + SQLULEN field_len = NULL; + + // if this is the first time called for this field, just convert the entire string to system first then + // use that to read from instead of converting chunk by chunk. This is because it's impossible to know + // the total length of the string for output_buffer_length without doing the conversion and returning + // SQL_NO_TOTAL is not consistent with what our other conversion functions do (system_to_wide_string and + // to_same_string). + + if( read_so_far == 0 ) { + + if( meta[ field_index ].length == sqlsrv_buffered_result_set::meta_data::SIZE_UNKNOWN ) { + + field_len = **reinterpret_cast( &row[ meta[ field_index ].offset ] ); + field_data = *reinterpret_cast( &row[ meta[ field_index ].offset ] ) + sizeof( SQLULEN ) + read_so_far; + } + else { + + field_len = *reinterpret_cast( &row[ meta[ field_index ].offset ] ); + field_data = &row[ meta[ field_index ].offset ] + sizeof( SQLULEN ) + read_so_far; + } + + BOOL default_char_used = FALSE; + char default_char = '?'; + + // allocate enough to handle WC -> DBCS conversion if it happens + temp_string = reinterpret_cast( sqlsrv_malloc( field_len, sizeof( char ), sizeof(char))); + temp_length = WideCharToMultiByte( CP_ACP, 0, (LPCWSTR) field_data, field_len / sizeof(WCHAR), + (LPSTR) temp_string.get(), field_len, &default_char, &default_char_used ); + + if( temp_length == 0 ) { + + switch( GetLastError() ) { + + case ERROR_NO_UNICODE_TRANSLATION: + last_error = new ( sqlsrv_malloc( sizeof( sqlsrv_error ))) + sqlsrv_error( (SQLCHAR*) "IMSSP", (SQLCHAR*) "Invalid Unicode translation", -1 ); + break; + default: + SQLSRV_ASSERT( false, "Severe error translating Unicode" ); + break; + } + + return SQL_ERROR; + } + } + + *out_buffer_length = (temp_length - read_so_far); + + SQLLEN to_copy = 0; + + if( (size_t) buffer_length < (temp_length - read_so_far + sizeof(char))) { + + to_copy = buffer_length - sizeof(char); + last_error = new ( sqlsrv_malloc( sizeof( sqlsrv_error ))) + sqlsrv_error( (SQLCHAR*) "01004", (SQLCHAR*) "String data, right truncated", -1 ); + r = SQL_SUCCESS_WITH_INFO; + } + else { + + to_copy = (temp_length - read_so_far); + r = SQL_SUCCESS; + } + + if( to_copy > 0 ) { + + memcpy( buffer, temp_string.get() + read_so_far, to_copy ); + } + SQLSRV_ASSERT( to_copy >= 0, "Invalid field copy length" ); + OACR_WARNING_SUPPRESS( BUFFER_UNDERFLOW, "Buffer length verified above" ); + ((SQLCHAR*) buffer)[ to_copy ] = '\0'; + read_so_far += to_copy; + + return r; +} + + +SQLRETURN sqlsrv_buffered_result_set::to_binary_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ) +{ + return to_same_string( field_index, buffer, buffer_length, out_buffer_length ); +} + +SQLRETURN sqlsrv_buffered_result_set::to_long( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ) +{ + SQLSRV_ASSERT( meta[ field_index ].c_type == SQL_C_LONG, "Invlid conversion to long" ); + SQLSRV_ASSERT( buffer_length >= sizeof( LONG ), "Buffer too small for SQL_C_LONG" ); // technically should ignore this + + unsigned char* row = get_row(); + LONG* long_data = reinterpret_cast( &row[ meta[ field_index ].offset ] ); + + memcpy( buffer, long_data, sizeof( LONG )); + *out_buffer_length = sizeof( LONG ); + + return SQL_SUCCESS; +} + +SQLRETURN sqlsrv_buffered_result_set::to_double( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ) +{ + SQLSRV_ASSERT( meta[ field_index ].c_type == SQL_C_DOUBLE, "Invlid conversion to double" ); + SQLSRV_ASSERT( buffer_length >= sizeof( double ), "Buffer too small for SQL_C_DOUBLE" ); // technically should ignore this + + unsigned char* row = get_row(); + double* double_data = reinterpret_cast( &row[ meta[ field_index ].offset ] ); + + memcpy( buffer, double_data, sizeof( double )); + *out_buffer_length = sizeof( double ); + + return SQL_SUCCESS; +} + +namespace { + +// called for each row in the cache when the cache is destroyed in the destructor +void cache_row_dtor( void* data ) +{ + row_dtor_closure* cl = reinterpret_cast( data ); + BYTE* row = cl->row_data; + // don't release this here, since this is called from the destructor of the result_set + sqlsrv_buffered_result_set* result_set = cl->results; + + for( SQLSMALLINT i = 0; i < result_set->column_count(); ++i ) { + + if( result_set->col_meta_data(i).length == sqlsrv_buffered_result_set::meta_data::SIZE_UNKNOWN ) { + + void* out_of_row_data = *reinterpret_cast( &row[ result_set->col_meta_data(i).offset ] ); + sqlsrv_free( out_of_row_data ); + } + } + + sqlsrv_free( row ); +} + +SQLPOINTER read_lob_field( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_buffered_result_set::meta_data& meta, + unsigned long mem_used TSRMLS_DC ) +{ + SQLSMALLINT extra = 0; + SQLLEN* output_buffer_len = NULL; + + // Set the amount of space necessary for null characters at the end of the data. + switch( meta.c_type ) { + case SQL_C_WCHAR: + extra = sizeof( SQLWCHAR ); + break; + case SQL_C_BINARY: + extra = 0; + break; + case SQL_C_CHAR: + extra = sizeof( SQLCHAR ); + break; + default: + SQLSRV_ASSERT( false, "Invalid type in read_lob_field" ); + break; + } + + SQLLEN already_read = 0; + SQLLEN to_read = INITIAL_FIELD_STRING_LEN; + sqlsrv_malloc_auto_ptr buffer; + buffer = static_cast( sqlsrv_malloc( INITIAL_FIELD_STRING_LEN + extra + sizeof( SQLULEN ))); + SQLRETURN r = SQL_SUCCESS; + SQLCHAR state[ SQL_SQLSTATE_BUFSIZE ]; + SQLLEN last_field_len = 0; + bool full_length_returned = false; + + do { + + + output_buffer_len = reinterpret_cast( buffer.get() ); + r = core::SQLGetData( stmt, field_index + 1, meta.c_type, buffer.get() + already_read + sizeof( SQLULEN ), + to_read - already_read + extra, &last_field_len, false /*handle_warning*/ TSRMLS_CC ); + + // if the field is NULL, then return a NULL pointer + if( last_field_len == SQL_NULL_DATA ) { + return NULL; + } + + // if the last read was successful, we're done + if( r == SQL_SUCCESS ) { + // check to make sure we haven't overflown our memory limit + CHECK_CUSTOM_ERROR( mem_used + last_field_len > stmt->buffered_query_limit * 1024, stmt, + SQLSRV_ERROR_BUFFER_LIMIT_EXCEEDED, stmt->buffered_query_limit ) { + + throw core::CoreException(); + } + break; + } + // else if it wasn't the truncated warning (01004) then we're done + else if( r == SQL_SUCCESS_WITH_INFO ) { + SQLSMALLINT len; + core::SQLGetDiagField( stmt, 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len + TSRMLS_CC ); + + if( !is_truncated_warning( state )) { + break; + } + } + + SQLSRV_ASSERT( SQL_SUCCEEDED( r ), "Unknown SQL error not triggered" ); + + // if the type of the field returns the total to be read, we use that and preallocate the buffer + if( last_field_len != SQL_NO_TOTAL ) { + + CHECK_CUSTOM_ERROR( mem_used + last_field_len > stmt->buffered_query_limit * 1024, stmt, + SQLSRV_ERROR_BUFFER_LIMIT_EXCEEDED, stmt->buffered_query_limit ) { + + throw core::CoreException(); + } + + already_read += to_read - already_read; + to_read = last_field_len; + buffer.resize( to_read + extra + sizeof( SQLULEN )); + output_buffer_len = reinterpret_cast( buffer.get() ); + // record the size of the field since we have it available + *output_buffer_len = last_field_len; + full_length_returned = true; + } + // otherwise allocate another chunk of memory to read in + else { + already_read += to_read - already_read; + to_read *= 2; + CHECK_CUSTOM_ERROR( mem_used + to_read > stmt->buffered_query_limit * 1024, stmt, + SQLSRV_ERROR_BUFFER_LIMIT_EXCEEDED, stmt->buffered_query_limit ) { + + throw core::CoreException(); + } + buffer.resize( to_read + extra + sizeof( SQLULEN )); + output_buffer_len = reinterpret_cast( buffer.get() ); + } + + } while( true ); + + SQLSRV_ASSERT( output_buffer_len != NULL, "Output buffer not allocated properly" ); + + // most LOB field types return the total length in the last_field_len, but some field types such as XML + // only return the amount read on the last read + if( !full_length_returned ) { + *output_buffer_len = already_read + last_field_len; + } + + char* return_buffer = buffer; + buffer.transferred(); + return return_buffer; +} + +} diff --git a/sqlsrv/core_sqlsrv.h b/sqlsrv/core_sqlsrv.h index 0a68c04a..108d7de5 100644 --- a/sqlsrv/core_sqlsrv.h +++ b/sqlsrv/core_sqlsrv.h @@ -6,7 +6,7 @@ // // Contents: Core routines and constants shared by the Microsoft Drivers for PHP for SQL Server // -// Copyright 2010 Microsoft Corporation +// Copyright Microsoft Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -45,6 +45,10 @@ OACR_WARNING_DISABLE( INDEX_NEGATIVE, "Third party code." ) OACR_WARNING_DISABLE( UNANNOTATED_BUFFER, "Third party code." ) OACR_WARNING_DISABLE( INDEX_UNDERFLOW, "Third party code." ) OACR_WARNING_DISABLE( REALLOCLEAK, "Third party code." ) +OACR_WARNING_DISABLE( ALLOC_SIZE_OVERFLOW_WITH_ACCESS, "Third party code." ) +#else +// define to eliminate static analysis hints in the code +#define OACR_WARNING_SUPPRESS( warning, msg ) #endif extern "C" { @@ -88,8 +92,6 @@ OACR_WARNING_POP #include #include -#include - #if !defined(WC_ERR_INVALID_CHARS) // imported from winnls.h as it isn't included by 5.3.0 #define WC_ERR_INVALID_CHARS 0x00000080 // error for invalid chars @@ -101,8 +103,10 @@ OACR_WARNING_POP #undef inline #endif +#include +#include #include - +#include #include #include @@ -216,10 +220,46 @@ struct sqlsrv_static_assert { static const int value = 1; }; #define SQLSRV_STATIC_ASSERT( c ) (sqlsrv_static_assert<(c) != 0>() ) +//********************************************************************************************************************************* +// Logging +//********************************************************************************************************************************* +// log_callback +// a driver specific callback for logging messages +// severity - severity of the message: notice, warning, or error +// msg - the message to log in a FormatMessage style formatting +// print_args - args to the message +typedef void (*log_callback)( unsigned int severity TSRMLS_DC, const char* msg, va_list* print_args ); + +// each driver must register a log callback. This should be the first thing a driver does. +void core_sqlsrv_register_logger( log_callback ); + +// a simple wrapper around a PHP error logging function. +void write_to_log( unsigned int severity TSRMLS_DC, const char* msg, ... ); + +// a macro to make it convenient to use the function. +#define LOG( severity, msg, ...) write_to_log( severity TSRMLS_CC, msg, __VA_ARGS__ ) + +// mask for filtering which severities are written to the log +enum logging_severity { + SEV_ERROR = 0x01, + SEV_WARNING = 0x02, + SEV_NOTICE = 0x04, + SEV_ALL = -1, +}; + +// Kill the PHP process and log the message to PHP +void die( const char* msg, ... ); +#define DIE( msg, ... ) { die( msg, __VA_ARGS__ ); } + + //********************************************************************************************************************************* // Resource/Memory Management //********************************************************************************************************************************* +// the macro max is defined and overrides the call to max in the allocator class +#pragma push_macro( "max" ) +#undef max + // new memory allocation/free debugging facilities to help us verify that all allocations are being // released in a timely manner and not just at the end of the script. // Zend has memory logging and checking, but it can generate a lot of noise for just one extension. @@ -229,36 +269,89 @@ struct sqlsrv_static_assert { static const int value = 1; }; // #define SQLSRV_MEM_DEBUG 1 #if defined( PHP_DEBUG ) && !defined( ZTS ) && defined( SQLSRV_MEM_DEBUG ) -// macro to log memory allocation and frees locations and their sizes -inline void* emalloc_trace( size_t size, const char* file, int line ) +inline void* sqlsrv_malloc_trace( size_t size, const char* file, int line ) { void* ptr = emalloc( size ); LOG( SEV_NOTICE, "emalloc returned %4!08x!: %1!d! bytes at %2!s!:%3!d!", size, file, line, ptr ); return ptr; } -inline void* erealloc_trace( void* original, size_t size, const char* file, int line ) +inline void* sqlsrv_malloc_trace( size_t element_count, size_t element_size, size_t extra, const char* file, int line ) +{ + OACR_WARNING_SUPPRESS( ALLOC_SIZE_OVERFLOW_IN_ALLOC_WRAPPER, "Overflow verified below" ); + + if(( element_count > 0 && element_size > 0 ) && + ( element_count > element_size * element_count || element_size > element_size * element_count )) { + DIE( "Integer overflow in sqlsrv_malloc" ); + } + + if( element_size * element_count > element_size * element_count + extra ) { + DIE( "Integer overflow in sqlsrv_malloc" ); + } + + if( element_size * element_count + extra == 0 ) { + DIE( "Allocation size must be more than 0" ); + } + + void* ptr = emalloc( element_size * element_count + extra ); + LOG( SEV_NOTICE, "emalloc returned %4!08x!: %1!d! bytes at %2!s!:%3!d!", size, file, line, ptr ); + return ptr; +} + +inline void* sqlsrv_realloc_trace( void* buffer, size_t size, const char* file, int line ) { void* ptr = erealloc( original, size ); LOG( SEV_NOTICE, "erealloc returned %5!08x! from %4!08x!: %1!d! bytes at %2!s!:%3!d!", size, file, line, ptr, original ); return ptr; } -inline void efree_trace( void* ptr, const char* file, int line ) +inline void sqlsrv_free_trace( void* ptr, const char* file, int line ) { LOG( SEV_NOTICE, "efree %1!08x! at %2!s!:%3!d!", ptr, file, line ); efree( ptr ); } -#define sqlsrv_malloc( size ) emalloc_trace( size, __FILE__, __LINE__ ) -#define sqlsrv_realloc( buffer, size ) erealloc_trace( buffer, size, __FILE__, __LINE__ ) -#define sqlsrv_free( ptr ) efree_trace( ptr, __FILE__, __LINE__ ) +#define sqlsrv_malloc( size ) sqlsrv_malloc_trace( size, __FILE__, __LINE__ ) +#define sqlsrv_malloc( count, size, extra ) sqlsrv_malloc_trace( count, size, extra, __FILE__, __LINE__ ) +#define sqlsrv_realloc( buffer, size ) sqlsrv_realloc_trace( buffer, size, __FILE__, __LINE__ ) +#define sqlsrv_free( ptr ) sqlsrv_free_trace( ptr, __FILE__, __LINE__ ) #else -#define sqlsrv_malloc( size ) emalloc( size ) -#define sqlsrv_realloc( buffer, size ) erealloc( buffer, size ) -#define sqlsrv_free( ptr ) efree( ptr ) +inline void* sqlsrv_malloc( size_t size ) +{ + return emalloc( size ); +} + +inline void* sqlsrv_malloc( size_t element_count, size_t element_size, size_t extra ) +{ + OACR_WARNING_SUPPRESS( ALLOC_SIZE_OVERFLOW_IN_ALLOC_WRAPPER, "Overflow verified below" ); + + if(( element_count > 0 && element_size > 0 ) && + ( element_count > element_size * element_count || element_size > element_size * element_count )) { + DIE( "Integer overflow in sqlsrv_malloc" ); + } + + if( element_size * element_count > element_size * element_count + extra ) { + DIE( "Integer overflow in sqlsrv_malloc" ); + } + + if( element_size * element_count + extra == 0 ) { + DIE( "Allocation size must be more than 0" ); + } + + return emalloc( element_size * element_count + extra ); +} + +inline void* sqlsrv_realloc( void* buffer, size_t size ) +{ + return erealloc( buffer, size ); +} + +inline void sqlsrv_free( void* ptr ) +{ + efree( ptr ); +} #endif @@ -273,6 +366,84 @@ struct remove_const { typedef T* type; }; +// allocator that uses the zend memory manager to manage memory +// this allows us to use STL classes that still work with Zend objects +template +struct sqlsrv_allocator { + + // typedefs used by the STL classes + typedef T value_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + // conversion typedef (used by list and other STL classes) + template + struct rebind { + typedef sqlsrv_allocator other; + }; + + inline sqlsrv_allocator() {} + inline ~sqlsrv_allocator() {} + inline sqlsrv_allocator( sqlsrv_allocator const& ) {} + template + inline sqlsrv_allocator( sqlsrv_allocator const& ) {} + + // address (doesn't work if the class defines operator&) + inline pointer address( reference r ) + { + return &r; + } + + inline const_pointer address( const_reference r ) + { + return &r; + } + + // memory allocation/deallocation + inline pointer allocate( size_type cnt, + typename std::allocator::const_pointer = 0 ) + { + return reinterpret_cast( sqlsrv_malloc(cnt, sizeof (T), 0)); + } + + inline void deallocate( pointer p, size_type ) + { + sqlsrv_free(p); + } + + // size + inline size_type max_size( void ) const + { + return std::numeric_limits::max() / sizeof(T); + } + + // object construction/destruction + inline void construct( pointer p, const T& t ) + { + new(p) T(t); + } + + inline void destroy(pointer p) + { + p->~T(); + } + + // equality operators + inline bool operator==( sqlsrv_allocator const& ) + { + return true; + } + + inline bool operator!=( sqlsrv_allocator const& a ) + { + return !operator==(a); + } +}; + // base class for auto_ptrs that we define below. It provides common operators and functions // used by all the classes. @@ -398,6 +569,8 @@ protected: // in a variable of sqlsrv_malloc_auto_ptr. sqlsrv_malloc_auto_ptr will "own" that block and assure that it is // freed until the variable is destroyed (out of scope) or ownership is transferred using the function // "transferred". +// DO NOT CALL sqlsrv_realloc with a sqlsrv_malloc_auto_ptr. Use the resize member function. + template class sqlsrv_malloc_auto_ptr : public sqlsrv_auto_ptr > { @@ -432,6 +605,13 @@ public: src.transferred(); this->_ptr = p; } + + // DO NOT CALL sqlsrv_realloc with a sqlsrv_malloc_auto_ptr. Use the resize member function. + // has the same parameter list as sqlsrv_realloc: new_size is the size in bytes of the newly allocated buffer + void resize( size_t new_size ) + { + _ptr = reinterpret_cast( sqlsrv_realloc( _ptr, new_size )); + } }; @@ -507,6 +687,9 @@ private: zval_auto_ptr( const zval_auto_ptr& src ); }; +#pragma pop_macro( "max" ) + + //********************************************************************************************************************************* // sqlsrv_error //********************************************************************************************************************************* @@ -546,6 +729,11 @@ struct sqlsrv_error : public sqlsrv_error_const { format = printf_format; } + sqlsrv_error( sqlsrv_error_const const& prototype ) + { + sqlsrv_error( prototype.sqlstate, prototype.native_message, prototype.native_code, prototype.format ); + } + ~sqlsrv_error( void ) { if( sqlstate != NULL ) { @@ -816,6 +1004,7 @@ enum SQLSRV_STMT_OPTIONS { SQLSRV_STMT_OPTION_QUERY_TIMEOUT, SQLSRV_STMT_OPTION_SEND_STREAMS_AT_EXEC, SQLSRV_STMT_OPTION_SCROLLABLE, + SQLSRV_STMT_OPTION_CLIENT_BUFFER_MAX_SIZE, // Driver specific connection options SQLSRV_STMT_OPTION_DRIVER_SPECIFIC = 1000, @@ -825,6 +1014,8 @@ enum SQLSRV_STMT_OPTIONS { namespace ODBCConnOptions { const char APP[] = "APP"; +const char ApplicationIntent[] = "ApplicationIntent"; +const char AttachDBFileName[] = "AttachDbFileName"; const char CharacterSet[] = "CharacterSet"; const char ConnectionPooling[] = "ConnectionPooling"; const char Database[] = "Database"; @@ -832,6 +1023,7 @@ const char Encrypt[] = "Encrypt"; const char Failover_Partner[] = "Failover_Partner"; const char LoginTimeout[] = "LoginTimggeout"; const char MARS_ODBC[] = "MARS_Connection"; +const char MultiSubnetFailover[] = "MultiSubnetFailover"; const char QuotedId[] = "QuotedId"; const char TraceFile[] = "TraceFile"; const char TraceOn[] = "TraceOn"; @@ -861,6 +1053,9 @@ enum SQLSRV_CONN_OPTIONS { SQLSRV_CONN_OPTION_TRANS_ISOLATION, SQLSRV_CONN_OPTION_TRUST_SERVER_CERT, SQLSRV_CONN_OPTION_WSID, + SQLSRV_CONN_OPTION_ATTACHDBFILENAME, + SQLSRV_CONN_OPTION_APPLICATION_INTENT, + SQLSRV_CONN_OPTION_MULTI_SUBNET_FAILOVER, // Driver specific connection options SQLSRV_CONN_OPTION_DRIVER_SPECIFIC = 1000, @@ -963,6 +1158,11 @@ struct stmt_option_send_at_exec : public stmt_option_functor { virtual void operator()( sqlsrv_stmt* stmt, stmt_option const* opt, zval* value_z TSRMLS_DC ); }; +struct stmt_option_buffered_query_limit : public stmt_option_functor { + + virtual void operator()( sqlsrv_stmt* stmt, stmt_option const* opt, zval* value_z TSRMLS_DC ); +}; + // used to hold the table for statment options struct stmt_option { @@ -1029,25 +1229,28 @@ struct sqlsrv_output_param { } }; +// forward decls +struct sqlsrv_result_set; + // *** Statement resource structure *** struct sqlsrv_stmt : public sqlsrv_context { void free_param_data( TSRMLS_D ); - virtual void new_result_set( void ); + virtual void new_result_set( TSRMLS_D ); sqlsrv_conn* conn; // Connection that created this statement bool executed; // Whether the statement has been executed yet (used for error messages) bool past_fetch_end; // Core_sqlsrv_fetch sets this field when the statement goes beyond the last row - bool scrollable; // Determines if the statement was created with the Scrollable query attribute - // (don't have to use ODBC to find out) - bool scroll_is_dynamic; // if scrollable, is it a dynamic cursor. + sqlsrv_result_set* current_results; // Current result set + SQLULEN cursor_type; // Type of cursor for the current result set bool has_rows; // Has_rows is set if there are actual rows in the row set bool fetch_called; // Used by core_sqlsrv_get_field to return an informative error if fetch not yet called int last_field_index; // last field retrieved by core_sqlsrv_get_field bool past_next_result_end; // core_sqlsrv_next_result sets this to true when the statement goes beyond the // last results unsigned long query_timeout; // maximum allowed statement execution time + unsigned long buffered_query_limit; // maximum allowed memory for a buffered query (measured in KB) // holds output pointers for SQLBindParameter // We use a deque because it 1) provides the at/[] access in constant time, and 2) grows dynamically without moving @@ -1101,6 +1304,9 @@ const int SQLSRV_DEFAULT_SIZE = -1; // size given for an output parameter th // uninitialized query timeout value const unsigned int QUERY_TIMEOUT_INVALID = 0xffffffff; +// special buffered query constant +const size_t SQLSRV_CURSOR_BUFFERED = 0xfffffffeUL; // arbitrary number that doesn't map to any other SQL_CURSOR_* constant + // factory to create a statement typedef sqlsrv_stmt* (*driver_stmt_factory)( sqlsrv_conn* conn, SQLHANDLE h, error_callback e, void* drv TSRMLS_DC ); @@ -1117,42 +1323,181 @@ void core_sqlsrv_get_field( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_ __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 ); +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, unsigned int paramno, zval* param_z TSRMLS_DC ); void core_sqlsrv_set_scrollable( sqlsrv_stmt* stmt, unsigned int cursor_type TSRMLS_DC ); void core_sqlsrv_set_query_timeout( sqlsrv_stmt* stmt, long timeout TSRMLS_DC ); void core_sqlsrv_set_query_timeout( sqlsrv_stmt* stmt, zval* value_z TSRMLS_DC ); 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, long limit TSRMLS_DC ); //********************************************************************************************************************************* -// Logging +// Result Set //********************************************************************************************************************************* -// log_callback -// a driver specific callback for logging messages -// severity - severity of the message: notice, warning, or error -// msg - the message to log in a FormatMessage style formatting -// print_args - args to the message -typedef void (*log_callback)( unsigned int severity TSRMLS_DC, const char* msg, va_list* print_args ); -// each driver must register a log callback. This should be the first thing a driver does. -void core_sqlsrv_register_logger( log_callback ); +// Abstract the result set so that a result set can either be used as is from ODBC or buffered. +// This is not a complete abstraction of a result set. Only enough is abstracted to allow for +// information and capabilities normally not available when a result set is not buffered +// (e.g., forward only vs buffered means row count is available and cursor movement is possible). +// Otherwise, normal ODBC calls are still valid and should be used to get information about the +// result set (e.g., SQLNumResultCols). -// a simple wrapper around a PHP error logging function. -void write_to_log( unsigned int severity TSRMLS_DC, const char* msg, ... ); +struct sqlsrv_result_set { -// a macro to make it convenient to use the function. -#define LOG( severity, msg, ...) write_to_log( severity TSRMLS_CC, msg, __VA_ARGS__ ) + sqlsrv_stmt* odbc; -// mask for filtering which severities are written to the log -enum logging_severity { - SEV_ERROR = 0x01, - SEV_WARNING = 0x02, - SEV_NOTICE = 0x04, - SEV_ALL = -1, + explicit sqlsrv_result_set( sqlsrv_stmt* ); + virtual ~sqlsrv_result_set( void ) { } + + virtual bool cached( int field_index ) = 0; + virtual SQLRETURN fetch( SQLSMALLINT fetch_orientation, SQLLEN fetch_offset TSRMLS_DC ) = 0; + virtual SQLRETURN get_data( SQLUSMALLINT field_index, SQLSMALLINT target_type, + __out void* buffer, SQLLEN buffer_length, __out SQLLEN* out_buffer_length, + bool handle_warning TSRMLS_DC )= 0; + virtual SQLRETURN get_diag_field( SQLSMALLINT record_number, SQLSMALLINT diag_identifier, + __out SQLPOINTER diag_info_buffer, SQLSMALLINT buffer_length, + __out SQLSMALLINT* out_buffer_length TSRMLS_DC ) = 0; + virtual sqlsrv_error* get_diag_rec( SQLSMALLINT record_number ) = 0; + virtual SQLLEN row_count( TSRMLS_D ) = 0; }; +struct sqlsrv_odbc_result_set : public sqlsrv_result_set { + + explicit sqlsrv_odbc_result_set( sqlsrv_stmt* ); + virtual ~sqlsrv_odbc_result_set( void ); + + virtual bool cached( int field_index ) { return false; } + virtual SQLRETURN fetch( SQLSMALLINT fetch_orientation, SQLLEN fetch_offset TSRMLS_DC ); + virtual SQLRETURN get_data( SQLUSMALLINT field_index, SQLSMALLINT target_type, + __out void* buffer, SQLLEN buffer_length, __out SQLLEN* out_buffer_length, + bool handle_warning TSRMLS_DC ); + virtual SQLRETURN get_diag_field( SQLSMALLINT record_number, SQLSMALLINT diag_identifier, + __out SQLPOINTER diag_info_buffer, SQLSMALLINT buffer_length, + __out SQLSMALLINT* out_buffer_length TSRMLS_DC ); + virtual sqlsrv_error* get_diag_rec( SQLSMALLINT record_number ); + virtual SQLLEN row_count( TSRMLS_D ); + + private: + // prevent invalid instantiations and assignments + sqlsrv_odbc_result_set( void ); + sqlsrv_odbc_result_set( sqlsrv_odbc_result_set& ); + sqlsrv_odbc_result_set& operator=( sqlsrv_odbc_result_set& ); +}; + +struct sqlsrv_buffered_result_set : public sqlsrv_result_set { + + struct meta_data { + SQLSMALLINT type; + SQLSMALLINT c_type; // convenience + SQLULEN offset; // in bytes + SQLULEN length; // in bytes + SQLSMALLINT scale; + + static const SQLULEN SIZE_UNKNOWN = 0; + }; + + // default maximum amount of memory that a buffered query can consume + #define INI_BUFFERED_QUERY_LIMIT_DEFAULT "10240" // default used by the php.ini settings + static const unsigned long BUFFERED_QUERY_LIMIT_DEFAULT = 10240; // measured in KB + static const long BUFFERED_QUERY_LIMIT_INVALID = 0; + + explicit sqlsrv_buffered_result_set( sqlsrv_stmt* odbc TSRMLS_DC ); + virtual ~sqlsrv_buffered_result_set( void ); + + virtual bool cached( int field_index ) { return true; } + virtual SQLRETURN fetch( SQLSMALLINT fetch_orientation, SQLLEN fetch_offset TSRMLS_DC ); + virtual SQLRETURN get_data( SQLUSMALLINT field_index, SQLSMALLINT target_type, + __out void* buffer, SQLLEN buffer_length, __out SQLLEN* out_buffer_length, + bool handle_warning TSRMLS_DC ); + virtual SQLRETURN get_diag_field( SQLSMALLINT record_number, SQLSMALLINT diag_identifier, + __out SQLPOINTER diag_info_buffer, SQLSMALLINT buffer_length, + __out SQLSMALLINT* out_buffer_length TSRMLS_DC ); + virtual sqlsrv_error* get_diag_rec( SQLSMALLINT record_number ); + virtual SQLLEN row_count( TSRMLS_D ); + + // buffered result set specific + SQLSMALLINT column_count( void ) + { + return col_count; + } + + struct meta_data& col_meta_data( SQLSMALLINT i ) + { + return meta[i]; + } + + private: + // prevent invalid instantiations and assignments + sqlsrv_buffered_result_set( void ); + sqlsrv_buffered_result_set( sqlsrv_buffered_result_set& ); + sqlsrv_buffered_result_set& operator=( sqlsrv_buffered_result_set& ); + + HashTable* cache; // rows of data kept in index based hash table + SQLSMALLINT col_count; // number of columns in the current result set + meta_data* meta; // metadata for fields in the cache + SQLLEN current; // 1 based, 0 means before first row + sqlsrv_error_auto_ptr last_error; // if an error occurred, it is kept here + SQLUSMALLINT last_field_index; // the last field data retrieved from + SQLLEN read_so_far; // position within string to read from (for partial reads of strings) + sqlsrv_malloc_auto_ptr temp_string; // temp buffer to hold a converted field while in use + SQLLEN temp_length; // number of bytes in the temp conversion buffer + + typedef SQLRETURN (sqlsrv_buffered_result_set::*conv_fn)( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ); + typedef std::map< SQLINTEGER, std::map< SQLINTEGER, conv_fn > > conv_matrix_t; + + // two dimentional sparse matrix that holds the [from][to] functions that do conversions + static conv_matrix_t conv_matrix; + + // string conversion functions + SQLRETURN binary_to_wide_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ); + SQLRETURN binary_to_system_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ); + SQLRETURN system_to_wide_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ); + SQLRETURN to_binary_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ); + SQLRETURN to_same_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ); + SQLRETURN wide_to_system_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ); + + // long conversion functions + SQLRETURN to_long( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, __out SQLLEN* out_buffer_length ); + SQLRETURN long_to_system_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ); + SQLRETURN long_to_wide_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ); + SQLRETURN long_to_double( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ); + + // double conversion functions + SQLRETURN to_double( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, __out SQLLEN* out_buffer_length ); + SQLRETURN double_to_system_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ); + SQLRETURN double_to_wide_string( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ); + SQLRETURN double_to_long( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ); + + // string to number conversion functions + // Future: See if these can be converted directly to template member functions + SQLRETURN string_to_double( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ); + SQLRETURN string_to_long( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ); + SQLRETURN wstring_to_double( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ); + SQLRETURN wstring_to_long( SQLSMALLINT field_index, __out void* buffer, SQLLEN buffer_length, + __out SQLLEN* out_buffer_length ); + + // utility functions for conversions + unsigned char* get_row( void ); +}; //********************************************************************************************************************************* // Utility @@ -1205,7 +1550,7 @@ enum SQLSRV_ERROR_CODES { SQLSRV_ERROR_INVALID_CONNECTION_KEY, SQLSRV_ERROR_MAX_PARAMS_EXCEEDED, SQLSRV_ERROR_INVALID_OPTION_KEY, - SQLSRV_ERROR_INVALID_OPTION_VALUE, + SQLSRV_ERROR_INVALID_QUERY_TIMEOUT_VALUE, SQLSRV_ERROR_INVALID_OPTION_SCROLLABLE, SQLSRV_ERROR_QUERY_STRING_ENCODING_TRANSLATE, SQLSRV_ERROR_OUTPUT_PARAM_TRUNCATED, @@ -1215,6 +1560,8 @@ enum SQLSRV_ERROR_CODES { SQLSRV_ERROR_STREAM_CREATE, SQLSRV_ERROR_MARS_OFF, SQLSRV_ERROR_FIELD_INDEX_ERROR, + SQLSRV_ERROR_BUFFER_LIMIT_EXCEEDED, + SQLSRV_ERROR_INVALID_BUFFER_LIMIT, // Driver specific error codes starts from here. SQLSRV_ERROR_DRIVER_SPECIFIC = 1000, @@ -1222,7 +1569,8 @@ enum SQLSRV_ERROR_CODES { }; // the message returned by SQL Native Client -const char CONNECTION_BUSY_ODBC_ERROR[] = "[Microsoft][SQL Server Native Client 10.0]Connection is busy with results for another command"; +const char CONNECTION_BUSY_ODBC_ERROR[] = "[Microsoft][SQL Server Native Client 11.0]Connection is busy with results for " + "another command"; // SQLSTATE for all internal errors extern SQLCHAR IMSSP[]; @@ -1244,11 +1592,12 @@ enum error_handling_flags { // 2/code) driver specific error code // 3/message) driver specific error message // The fetch type determines if the indices are numeric, associative, or both. -bool core_sqlsrv_get_odbc_error( sqlsrv_context& ctx, int record_number, sqlsrv_error* error, logging_severity severity TSRMLS_DC ); +bool core_sqlsrv_get_odbc_error( sqlsrv_context& ctx, int record_number, __out sqlsrv_error_auto_ptr& error, + logging_severity severity TSRMLS_DC ); // format and return a driver specfic error void core_sqlsrv_format_driver_error( sqlsrv_context& ctx, sqlsrv_error_const const* custom_error, - sqlsrv_error* formatted_error, logging_severity severity TSRMLS_DC, va_list* args ); + sqlsrv_error_auto_ptr& formatted_error, logging_severity severity TSRMLS_DC, va_list* args ); // return the message for the HRESULT returned by GetLastError. Some driver errors use this to @@ -1278,10 +1627,6 @@ inline bool call_error_handler( sqlsrv_context* ctx, unsigned int sqlsrv_error_c return ignored; } -// Kill the PHP process and log the message to PHP -void die( const char* msg, ... ); -#define DIE( msg, ... ) { die( msg, __VA_ARGS__ ); } - // PHP equivalent of ASSERT. C asserts cause a dialog to show and halt the process which // we don't want on a web server @@ -1300,7 +1645,6 @@ void die( const char* msg, ... ); #endif - // check to see if the sqlstate is 01004, truncated field retrieved. Used for retrieving large fields. inline bool is_truncated_warning( SQLCHAR* state ) { diff --git a/sqlsrv/core_stmt.cpp b/sqlsrv/core_stmt.cpp index 4d250820..76b831d0 100644 --- a/sqlsrv/core_stmt.cpp +++ b/sqlsrv/core_stmt.cpp @@ -3,7 +3,7 @@ // // Contents: Core routines that use statement handles shared between sqlsrv and pdo_sqlsrv // -// Copyright 2010 Microsoft Corporation +// Copyright Microsoft Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -28,8 +28,10 @@ struct field_cache { void* value; SQLLEN len; + sqlsrv_phptype type; - field_cache( void* field_value, SQLLEN field_len ) + field_cache( void* field_value, SQLLEN field_len, sqlsrv_phptype t ) + : type( t ) { // if the value is NULL, then just record a NULL pointer if( field_value != NULL ) { @@ -105,7 +107,6 @@ void send_param_streams( sqlsrv_stmt* stmt TSRMLS_DC ); void sqlsrv_output_param_dtor( void* data ); // called when a bound stream parameter is to be destroyed. void sqlsrv_stream_dtor( void* data ); -sqlsrv_phptype sql_type_to_php_type( sqlsrv_stmt const* stmt, SQLINTEGER sql_type, SQLUINTEGER size, bool prefer_string ); bool is_streamable_type( SQLINTEGER sql_type ); } @@ -116,7 +117,8 @@ sqlsrv_stmt::sqlsrv_stmt( sqlsrv_conn* c, SQLHANDLE handle, error_callback e, vo conn( c ), executed( false ), past_fetch_end( false ), - scrollable( false ), + current_results( NULL ), + cursor_type( SQL_CURSOR_FORWARD_ONLY ), has_rows( false ), fetch_called( false ), last_field_index( -1 ), @@ -126,6 +128,7 @@ 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 ) { // initialize the input string parameters array (which holds zvals) @@ -165,6 +168,14 @@ sqlsrv_stmt::~sqlsrv_stmt( void ) TSRMLS_FETCH(); close_active_stream( this TSRMLS_CC ); } + + // delete any current results + if( current_results ) { + current_results->~sqlsrv_result_set(); + efree( current_results ); + current_results = NULL; + } + invalidate(); zval_ptr_dtor( ¶m_input_strings ); zval_ptr_dtor( &output_params ); @@ -192,13 +203,28 @@ void sqlsrv_stmt::free_param_data( TSRMLS_D ) // to be called whenever a new result set is created, such as after an // execute or next_result. Resets the state variables. -void sqlsrv_stmt::new_result_set( void ) +void sqlsrv_stmt::new_result_set( TSRMLS_D ) { this->fetch_called = false; this->has_rows = false; this->past_next_result_end = false; this->past_fetch_end = false; this->last_field_index = -1; + + // delete any current results + if( current_results ) { + current_results->~sqlsrv_result_set(); + efree( current_results ); + current_results = NULL; + } + + // create a new result set + if( cursor_type == SQLSRV_CURSOR_BUFFERED ) { + current_results = new (sqlsrv_malloc( sizeof( sqlsrv_buffered_result_set ))) sqlsrv_buffered_result_set( this TSRMLS_CC ); + } + else { + current_results = new (sqlsrv_malloc( sizeof( sqlsrv_odbc_result_set ))) sqlsrv_odbc_result_set( this ); + } } // core_sqlsrv_create_stmt @@ -247,16 +273,15 @@ sqlsrv_stmt* core_sqlsrv_create_stmt( sqlsrv_conn* conn, driver_stmt_factory stm int type = zend_hash_get_current_key_ex( options_ht, &key, &key_len, &index, 0, NULL ); // The driver layer should ensure a valid key. - SQLSRV_ASSERT( (type == HASH_KEY_IS_LONG), "allocate_stmt: Invalid statment option key provided" ); + 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, (void**) &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 - if( !stmt_opt ) { - THROW_CORE_ERROR( stmt->conn, SQLSRV_ERROR_INVALID_OPTION_KEY ); - } + // 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 ); @@ -273,6 +298,8 @@ sqlsrv_stmt* core_sqlsrv_create_stmt( sqlsrv_conn* conn, driver_stmt_factory stm catch( core::CoreException& ) { if( stmt ) { + + conn->set_last_error( stmt->last_error() ); stmt->~sqlsrv_stmt(); } @@ -321,7 +348,7 @@ void core_sqlsrv_bind_param( sqlsrv_stmt* stmt, unsigned int param_num, int dire try { // check is only < because params are 0 based - CHECK_CUSTOM_ERROR( param_num >= SQL_SERVER_MAX_PARAMS, stmt, SQLSRV_ERROR_MAX_PARAMS_EXCEEDED, param_num ) { + CHECK_CUSTOM_ERROR( param_num >= SQL_SERVER_MAX_PARAMS, stmt, SQLSRV_ERROR_MAX_PARAMS_EXCEEDED, param_num + 1 ) { throw core::CoreException(); } @@ -498,6 +525,27 @@ void core_sqlsrv_bind_param( sqlsrv_stmt* stmt, unsigned int param_num, int dire // save the parameter to be adjusted and/or converted after the results are processed sqlsrv_output_param output_param( param_z, encoding, param_num, buffer_len ); save_output_param_for_later( stmt, output_param TSRMLS_CC ); + + // For output parameters, if we set the column_size to be same as the buffer_len, + // than if there is a truncation due to the data coming from the server being + // greater than the column_size, we don't get any truncation error. In order to + // avoid this silent truncation, we set the column_size to be "MAX" size for + // string types. This will guarantee that there is no silent truncation for + // output parameters. + if( direction == SQL_PARAM_OUTPUT ) { + + switch( sql_type ) { + + case SQL_VARBINARY: + case SQL_VARCHAR: + case SQL_WVARCHAR: + column_size = SQL_SS_LENGTH_UNLIMITED; + break; + + default: + break; + } + } } break; case IS_RESOURCE: @@ -516,22 +564,33 @@ void core_sqlsrv_bind_param( sqlsrv_stmt* stmt, unsigned int param_num, int dire case IS_OBJECT: { SQLSRV_ASSERT( direction == SQL_PARAM_INPUT, "Invalid output param type. The driver layer should catch this." ); - sqlsrv_malloc_auto_ptr class_name; - zend_uint class_name_len; zval_auto_ptr function_z; zval_auto_ptr buffer_z; zval_auto_ptr format_z; zval* params[1]; + bool valid_class_name_found = false; - int zr = zend_get_object_classname( param_z, &class_name, &class_name_len TSRMLS_CC ); - CHECK_CUSTOM_ERROR( zr == FAILURE, stmt, SQLSRV_ERROR_INVALID_PARAMETER_PHPTYPE, param_num + 1 ) { - throw core::CoreException(); - } - CHECK_CUSTOM_ERROR( class_name_len != DateTime::DATETIME_CLASS_NAME_LEN || - stricmp( class_name, DateTime::DATETIME_CLASS_NAME ), - stmt, SQLSRV_ERROR_INVALID_PARAMETER_PHPTYPE, param_num + 1 ) { + zend_class_entry *class_entry = zend_get_class_entry( param_z TSRMLS_CC ); + + while( class_entry != NULL ) { + + if( class_entry->name_length == DateTime::DATETIME_CLASS_NAME_LEN && class_entry->name != NULL && + stricmp( class_entry->name, DateTime::DATETIME_CLASS_NAME ) == 0 ) { + valid_class_name_found = true; + break; + } + + else { + + // Check the parent + class_entry = class_entry->parent; + } + } + + CHECK_CUSTOM_ERROR( !valid_class_name_found, stmt, SQLSRV_ERROR_INVALID_PARAMETER_PHPTYPE, param_num + 1 ) { throw core::CoreException(); } + ALLOC_INIT_ZVAL( buffer_z ); ALLOC_INIT_ZVAL( function_z ); ALLOC_INIT_ZVAL( format_z ); @@ -554,7 +613,7 @@ void core_sqlsrv_bind_param( sqlsrv_stmt* stmt, unsigned int param_num, int dire params[0] = format_z; // This is equivalent to the PHP code: $param_z->format( $format_z ); where param_z is the // DateTime object and $format_z is the format string. - zr = call_user_function( EG( function_table ), ¶m_z, function_z, buffer_z, 1, params TSRMLS_CC ); + int zr = call_user_function( EG( function_table ), ¶m_z, function_z, buffer_z, 1, params TSRMLS_CC ); CHECK_CUSTOM_ERROR( zr == FAILURE, stmt, SQLSRV_ERROR_INVALID_PARAMETER_PHPTYPE, param_num + 1 ) { throw core::CoreException(); } @@ -602,6 +661,8 @@ void core_sqlsrv_bind_param( sqlsrv_stmt* stmt, unsigned int param_num, int dire void core_sqlsrv_execute( sqlsrv_stmt* stmt TSRMLS_DC, const char* sql, int sql_len ) { + try { + // close the stream to release the resource close_active_stream( stmt TSRMLS_CC ); @@ -632,7 +693,7 @@ void core_sqlsrv_execute( sqlsrv_stmt* stmt TSRMLS_DC, const char* sql, int sql_ r = core::SQLExecute( stmt TSRMLS_CC ); } - stmt->new_result_set(); + stmt->new_result_set( TSRMLS_C ); stmt->executed = true; // if data is needed (streams were bound) and they should be sent at execute time, then do so now @@ -646,6 +707,19 @@ void core_sqlsrv_execute( sqlsrv_stmt* stmt TSRMLS_DC, const char* sql, int sql_ finalize_output_parameters( stmt TSRMLS_CC ); } + + } + catch( core::CoreException& e ) { + + // if the statement executed but failed in a subsequent operation before returning, + // we need to cancel the statement + if( stmt->executed ) { + SQLCancel( stmt->handle() ); + // stmt->executed = false; should this be reset if something fails? + } + + throw e; + } } @@ -689,20 +763,19 @@ bool core_sqlsrv_fetch( sqlsrv_stmt* stmt, SQLSMALLINT fetch_orientation, SQLLEN // if the statement has rows and is not scrollable but doesn't yet have // fetch_called, this must be the first time we've called sqlsrv_fetch. - if( !stmt->scrollable && stmt->has_rows && !stmt->fetch_called ) { + if( stmt->cursor_type == SQL_CURSOR_FORWARD_ONLY && stmt->has_rows && !stmt->fetch_called ) { stmt->fetch_called = true; return true; } // move to the record requested. For absolute records, we use a 0 based offset, so +1 since // SQLFetchScroll uses a 1 based offset, otherwise for relative, just use the fetch_offset provided. - SQLRETURN r = core::SQLFetchScroll( stmt, fetch_orientation, - ( fetch_orientation == SQL_FETCH_RELATIVE ) ? fetch_offset : fetch_offset + 1 - TSRMLS_CC ); - + SQLRETURN r = stmt->current_results->fetch( fetch_orientation, + ( fetch_orientation == SQL_FETCH_RELATIVE ) ? fetch_offset : fetch_offset + 1 + TSRMLS_CC ); if( r == SQL_NO_DATA ) { // if this is a forward only cursor, mark that we've passed the end so future calls result in an error - if( !stmt->scrollable ) { + if( stmt->cursor_type == SQL_CURSOR_FORWARD_ONLY ) { stmt->past_fetch_end = true; } return false; @@ -812,13 +885,18 @@ void core_sqlsrv_get_field( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_ 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 + 1 ); + *field_value = sqlsrv_malloc( cached->len, sizeof( char ), 1 ); memcpy( *field_value, cached->value, cached->len ); - reinterpret_cast( *field_value )[ cached->len ] = '\0'; // prevent the 'string not null terminated' warning + if( cached->type.typeinfo.type == SQLSRV_PHPTYPE_STRING ) { + // prevent the 'string not null terminated' warning + reinterpret_cast( *field_value )[ cached->len ] = '\0'; + } *field_len = cached->len; + if( sqlsrv_php_type_out ) { *sqlsrv_php_type_out = static_cast( cached->type.typeinfo.type ); } } return; } @@ -878,7 +956,7 @@ void core_sqlsrv_get_field( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_ // if the user wants us to cache the field, we'll do it if( cache_field ) { - field_cache cache( *field_value, *field_len ); + field_cache cache( *field_value, *field_len, sqlsrv_php_type ); core::sqlsrv_zend_hash_index_update( *stmt, Z_ARRVAL_P( stmt->field_cache ), field_index, &cache, sizeof( field_cache ) TSRMLS_CC ); } @@ -913,7 +991,7 @@ bool core_sqlsrv_has_any_result( sqlsrv_stmt* stmt TSRMLS_DC ) // Returns // Nothing, exception thrown if problem occurs -void core_sqlsrv_next_result( sqlsrv_stmt* stmt TSRMLS_DC, bool finalize_output_params ) +void core_sqlsrv_next_result( sqlsrv_stmt* stmt TSRMLS_DC, bool finalize_output_params, bool throw_on_errors ) { try { @@ -928,7 +1006,13 @@ void core_sqlsrv_next_result( sqlsrv_stmt* stmt TSRMLS_DC, bool finalize_output_ close_active_stream( stmt TSRMLS_CC ); - SQLRETURN r = core::SQLMoreResults( stmt TSRMLS_CC ); + SQLRETURN r; + if( throw_on_errors ) { + r = core::SQLMoreResults( stmt TSRMLS_CC ); + } + else { + r = SQLMoreResults( stmt->handle() ); + } if( r == SQL_NO_DATA ) { @@ -942,7 +1026,7 @@ void core_sqlsrv_next_result( sqlsrv_stmt* stmt TSRMLS_DC, bool finalize_output_ return; } - stmt->new_result_set(); + stmt->new_result_set( TSRMLS_C ); } catch( core::CoreException& e ) { @@ -991,42 +1075,62 @@ void core_sqlsrv_set_scrollable( sqlsrv_stmt* stmt, unsigned int cursor_type TSR case SQL_CURSOR_STATIC: core::SQLSetStmtAttr( stmt, SQL_ATTR_CURSOR_TYPE, reinterpret_cast( SQL_CURSOR_STATIC ), SQL_IS_UINTEGER TSRMLS_CC ); - stmt->scrollable = true; - stmt->scroll_is_dynamic = false; break; case SQL_CURSOR_DYNAMIC: core::SQLSetStmtAttr( stmt, SQL_ATTR_CURSOR_TYPE, reinterpret_cast( SQL_CURSOR_DYNAMIC ), SQL_IS_UINTEGER TSRMLS_CC ); - stmt->scrollable = true; - stmt->scroll_is_dynamic = true; // this cursor is dynamic break; case SQL_CURSOR_KEYSET_DRIVEN: core::SQLSetStmtAttr( stmt, SQL_ATTR_CURSOR_TYPE, reinterpret_cast( SQL_CURSOR_KEYSET_DRIVEN ), SQL_IS_UINTEGER TSRMLS_CC ); - stmt->scrollable = true; - stmt->scroll_is_dynamic = false; break; case SQL_CURSOR_FORWARD_ONLY: core::SQLSetStmtAttr( stmt, SQL_ATTR_CURSOR_TYPE, reinterpret_cast( SQL_CURSOR_FORWARD_ONLY ), SQL_IS_UINTEGER TSRMLS_CC ); - stmt->scrollable = false; // reset since forward isn't scrollable - stmt->scroll_is_dynamic = false; + break; + + case SQLSRV_CURSOR_BUFFERED: + core::SQLSetStmtAttr( stmt, SQL_ATTR_CURSOR_TYPE, + reinterpret_cast( SQL_CURSOR_FORWARD_ONLY ), SQL_IS_UINTEGER TSRMLS_CC ); break; default: THROW_CORE_ERROR( stmt, SQLSRV_ERROR_INVALID_OPTION_SCROLLABLE ); break; } + + stmt->cursor_type = cursor_type; + } - catch( core::CoreException& ) { throw; } } +void core_sqlsrv_set_buffered_query_limit( sqlsrv_stmt* stmt, zval* value_z TSRMLS_DC ) +{ + if( Z_TYPE_P( value_z ) != IS_LONG ) { + + THROW_CORE_ERROR( stmt, SQLSRV_ERROR_INVALID_BUFFER_LIMIT ); + } + + core_sqlsrv_set_buffered_query_limit( stmt, Z_LVAL_P( value_z ) TSRMLS_CC ); +} + +void core_sqlsrv_set_buffered_query_limit( sqlsrv_stmt* stmt, long limit TSRMLS_DC ) +{ + if( limit <= 0 ) { + + THROW_CORE_ERROR( stmt, SQLSRV_ERROR_INVALID_BUFFER_LIMIT ); + } + + stmt->buffered_query_limit = limit; +} + + // Overloaded. Extracts the long value and calls the core_sqlsrv_set_query_timeout // which accepts timeout parameter as a long. If the zval is not of type long // than throws error. @@ -1038,7 +1142,7 @@ void core_sqlsrv_set_query_timeout( sqlsrv_stmt* stmt, zval* value_z TSRMLS_DC ) if( Z_TYPE_P( value_z ) != IS_LONG || Z_LVAL_P( value_z ) < 0 ) { convert_to_string( value_z ); - THROW_CORE_ERROR( stmt, SQLSRV_ERROR_INVALID_OPTION_VALUE, Z_STRVAL_P( value_z ) ); + THROW_CORE_ERROR( stmt, SQLSRV_ERROR_INVALID_QUERY_TIMEOUT_VALUE, Z_STRVAL_P( value_z ) ); } core_sqlsrv_set_query_timeout( stmt, Z_LVAL_P( value_z ) TSRMLS_CC ); @@ -1214,6 +1318,11 @@ void stmt_option_send_at_exec:: operator()( sqlsrv_stmt* stmt, stmt_option const core_sqlsrv_set_send_at_exec( stmt, value_z TSRMLS_CC ); } +void stmt_option_buffered_query_limit:: operator()( sqlsrv_stmt* stmt, stmt_option const* /*opt*/, zval* value_z TSRMLS_DC ) +{ + core_sqlsrv_set_buffered_query_limit( stmt, value_z TSRMLS_CC ); +} + // internal function to release the active stream. Called by each main API function // that will alter the statement and cancel any retrieval of data from a stream. @@ -1382,9 +1491,13 @@ void core_get_field_common( __inout sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_malloc_auto_ptr field_value_temp; field_value_temp = static_cast( sqlsrv_malloc( sizeof( long ))); - SQLRETURN r = core::SQLGetData( stmt, field_index + 1, SQL_C_LONG, field_value_temp, 0, - field_len, true /*handle_warning*/ TSRMLS_CC ); + 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(); + } + CHECK_CUSTOM_ERROR( (r == SQL_NO_DATA), stmt, SQLSRV_ERROR_NO_DATA, field_index ) { throw core::CoreException(); } @@ -1404,9 +1517,13 @@ void core_get_field_common( __inout sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_malloc_auto_ptr field_value_temp; field_value_temp = static_cast( sqlsrv_malloc( sizeof( double ))); - SQLRETURN r = core::SQLGetData( stmt, field_index + 1, SQL_C_DOUBLE, field_value_temp, 0, - field_len, true /*handle_warning*/ TSRMLS_CC ); + 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(); + } + CHECK_CUSTOM_ERROR( (r == SQL_NO_DATA), stmt, SQLSRV_ERROR_NO_DATA, field_index ) { throw core::CoreException (); } @@ -1440,8 +1557,8 @@ void core_get_field_common( __inout sqlsrv_stmt* stmt, SQLUSMALLINT field_index, ALLOC_INIT_ZVAL( function_z ); ALLOC_INIT_ZVAL( return_value_z ); - SQLRETURN r = core::SQLGetData( stmt, field_index + 1, SQL_C_CHAR, field_value_temp, MAX_DATETIME_STRING_LEN, - field_len, true TSRMLS_CC ); + 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 ); CHECK_CUSTOM_ERROR( (r == SQL_NO_DATA), stmt, SQLSRV_ERROR_NO_DATA, field_index ) { throw core::CoreException (); @@ -1512,6 +1629,11 @@ void core_get_field_common( __inout sqlsrv_stmt* stmt, SQLUSMALLINT field_index, break; } + case SQLSRV_PHPTYPE_NULL: + *field_value = NULL; + *field_len = 0; + break; + default: DIE( "core_get_field_common: Unexpected sqlsrv_phptype provided" ); break; @@ -1630,7 +1752,7 @@ SQLSMALLINT default_c_type( sqlsrv_stmt* stmt, unsigned int paramno, zval const* sql_c_type = SQL_C_CHAR; break; } - break; + break; case IS_BOOL: case IS_LONG: sql_c_type = SQL_C_LONG; @@ -1951,8 +2073,8 @@ void get_field_as_string( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_ph field_value_temp = static_cast( sqlsrv_malloc( field_len_temp + extra + 1 )); - r = core::SQLGetData( stmt, field_index + 1, c_type, field_value_temp, ( field_len_temp + extra ), - &field_len_temp, false /*handle_warning*/ TSRMLS_CC ); + 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 (); @@ -1969,7 +2091,7 @@ void get_field_as_string( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_ph SQLCHAR state[ SQL_SQLSTATE_BUFSIZE ]; SQLSMALLINT len; - core::SQLGetDiagField( stmt, 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len TSRMLS_CC ); + stmt->current_results->get_diag_field( 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len TSRMLS_CC ); if( is_truncated_warning( state ) ) { @@ -1993,8 +2115,9 @@ void get_field_as_string( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_ph field_len_temp -= initial_field_len; // Get the rest of the data. - r = core::SQLGetData( stmt, field_index + 1, c_type, field_value_temp + initial_field_len, - field_len_temp + extra, &dummy_field_len, false /*handle_warning*/ TSRMLS_CC ); + 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 ); // the last packet will contain the actual amount retrieved, not SQL_NO_TOTAL // so we calculate the actual length of the string with that. @@ -2019,8 +2142,9 @@ void get_field_as_string( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_ph field_len_temp -= INITIAL_FIELD_STRING_LEN; // Get the rest of the data. - r = core::SQLGetData( stmt, field_index + 1, c_type, field_value_temp + INITIAL_FIELD_STRING_LEN, - field_len_temp + extra, &dummy_field_len, true /*handle_warning*/ TSRMLS_CC ); + 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 ); if( dummy_field_len == SQL_NULL_DATA ) { *field_value = NULL; @@ -2072,9 +2196,11 @@ void get_field_as_string( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_ph field_value_temp = static_cast( sqlsrv_malloc( sql_display_size + extra + 1 )); // get the data - r = core::SQLGetData( stmt, field_index + 1, c_type, field_value_temp, sql_display_size, - &field_len_temp, true /*handle_warning*/ TSRMLS_CC ); - + 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 (); } diff --git a/sqlsrv/core_stream.cpp b/sqlsrv/core_stream.cpp index d1d3a020..340d4dcc 100644 --- a/sqlsrv/core_stream.cpp +++ b/sqlsrv/core_stream.cpp @@ -3,7 +3,7 @@ // // Contents: Implementation of PHP streams for reading SQL Server data // -// Copyright 2010 Microsoft Corporation +// Copyright Microsoft Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -113,8 +113,9 @@ size_t sqlsrv_stream_read( php_stream* stream, __out_bcount(count) char* buf, si SQLCHAR state[ SQL_SQLSTATE_BUFSIZE ]; SQLSMALLINT len; - core::SQLGetDiagField( ss->stmt, 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len TSRMLS_CC ); - + + ss->stmt->current_results->get_diag_field( 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len TSRMLS_CC ); + if( read == SQL_NO_TOTAL ) { SQLSRV_ASSERT( is_truncated_warning( state ), "sqlsrv_stream_read: truncation warning was expected but it " "did not occur." ); @@ -135,7 +136,7 @@ size_t sqlsrv_stream_read( php_stream* stream, __out_bcount(count) char* buf, si read = count - 1; break; default: - DIE( "sqlsrv_stream_read: should have never reached in this switch case. "); + DIE( "sqlsrv_stream_read: should have never reached in this switch case."); break; } } diff --git a/sqlsrv/core_util.cpp b/sqlsrv/core_util.cpp index e335afec..a29cfe38 100644 --- a/sqlsrv/core_util.cpp +++ b/sqlsrv/core_util.cpp @@ -5,7 +5,7 @@ // // Comments: Mostly error handling and some type handling // -// Copyright 2010 Microsoft Corporation +// Copyright Microsoft Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -147,7 +147,8 @@ wchar_t* utf16_string_from_mbcs_string( SQLSRV_ENCODING php_encoding, const char // 3/message) driver specific error message // The fetch type determines if the indices are numeric, associative, or both. -bool core_sqlsrv_get_odbc_error( sqlsrv_context& ctx, int record_number, sqlsrv_error* error, logging_severity severity TSRMLS_DC ) +bool core_sqlsrv_get_odbc_error( sqlsrv_context& ctx, int record_number, sqlsrv_error_auto_ptr& error, logging_severity severity + TSRMLS_DC ) { SQLHANDLE h = ctx.handle(); SQLSMALLINT h_type = ctx.handle_type(); @@ -165,22 +166,50 @@ bool core_sqlsrv_get_odbc_error( sqlsrv_context& ctx, int record_number, sqlsrv_ SQLINTEGER message_len = 0; SQLWCHAR wsqlstate[ SQL_SQLSTATE_BUFSIZE ]; SQLWCHAR wnative_message[ SQL_MAX_MESSAGE_LENGTH + 1 ]; + SQLSRV_ENCODING enc = ctx.encoding(); - r = SQLGetDiagRecW( h_type, h, record_number, wsqlstate, &error->native_code, wnative_message, - SQL_MAX_MESSAGE_LENGTH + 1, &wmessage_len ); - // don't use the CHECK* macros here since it will trigger reentry into the error handling system - if( !SQL_SUCCEEDED( r ) || r == SQL_NO_DATA ) { - return false; - } + switch( h_type ) { + + case SQL_HANDLE_STMT: + { + sqlsrv_stmt* stmt = static_cast( &ctx ); + if( stmt->current_results != NULL ) { + + error = stmt->current_results->get_diag_rec( record_number ); + // don't use the CHECK* macros here since it will trigger reentry into the error handling system + if( error == NULL ) { + return false; + } + break; + } + + // convert the error into the encoding of the context + if( enc == SQLSRV_ENCODING_DEFAULT ) { + enc = stmt->conn->encoding(); + } + } + + + default: + + error = new ( sqlsrv_malloc( sizeof( sqlsrv_error ))) sqlsrv_error(); + r = SQLGetDiagRecW( h_type, h, record_number, wsqlstate, &error->native_code, wnative_message, + SQL_MAX_MESSAGE_LENGTH + 1, &wmessage_len ); + // don't use the CHECK* macros here since it will trigger reentry into the error handling system + if( !SQL_SUCCEEDED( r ) || r == SQL_NO_DATA ) { + return false; + } + + error->sqlstate = reinterpret_cast( wsqlstate ); + convert_string_from_utf16( enc, reinterpret_cast( &error->sqlstate ), sqlstate_len, + false /*no free*/ ); + error->native_message = reinterpret_cast( wnative_message ); + message_len = wmessage_len * sizeof( wchar_t ); + convert_string_from_utf16( enc, reinterpret_cast( &error->native_message ), message_len, + false /*no free*/ ); + break; + } - // convert the error into the encoding of the context - error->sqlstate = reinterpret_cast( wsqlstate ); - convert_string_from_utf16( ctx.encoding(), reinterpret_cast( &error->sqlstate ), sqlstate_len, - false /*no free*/ ); - error->native_message = reinterpret_cast( wnative_message ); - message_len = wmessage_len * sizeof( wchar_t ); - convert_string_from_utf16( ctx.encoding(), reinterpret_cast( &error->native_message ), message_len, - false /*no free*/ ); // log the error first LOG( severity, "%1!s!: SQLSTATE = %2!s!", ctx.func(), error->sqlstate ); @@ -194,9 +223,10 @@ bool core_sqlsrv_get_odbc_error( sqlsrv_context& ctx, int record_number, sqlsrv_ // format and return a driver specfic error void core_sqlsrv_format_driver_error( sqlsrv_context& ctx, sqlsrv_error_const const* custom_error, - sqlsrv_error* formatted_error, logging_severity severity TSRMLS_DC, va_list* args ) + sqlsrv_error_auto_ptr& formatted_error, logging_severity severity TSRMLS_DC, va_list* args ) { // allocate space for the formatted message + formatted_error = new (sqlsrv_malloc( sizeof( sqlsrv_error ))) sqlsrv_error(); formatted_error->sqlstate = reinterpret_cast( sqlsrv_malloc( SQL_SQLSTATE_BUFSIZE )); formatted_error->native_message = reinterpret_cast( sqlsrv_malloc( SQL_MAX_MESSAGE_LENGTH + 1 )); diff --git a/sqlsrv/init.cpp b/sqlsrv/init.cpp index 03c62b7d..ec711b69 100644 --- a/sqlsrv/init.cpp +++ b/sqlsrv/init.cpp @@ -2,7 +2,7 @@ // File: init.cpp // Contents: initialization routines for the extension // -// Copyright 2010 Microsoft Corporation +// Copyright Microsoft Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -46,134 +46,137 @@ unsigned int current_log_subsystem = LOG_INIT; // argument info structures for functions, arranged alphabetically. // see zend_API.h in the PHP sources for more information about these macros ZEND_BEGIN_ARG_INFO_EX( sqlsrv_begin_transaction_arginfo, 0, 0, 1 ) - ZEND_ARG_INFO( 0, "connection resource" ) + ZEND_ARG_INFO( 0, conn ) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO( sqlsrv_cancel_arginfo, 0 ) - ZEND_ARG_INFO( 0, "statement resource" ) + ZEND_ARG_INFO( 0, stmt ) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX( sqlsrv_close_arginfo, 0, 0, 1 ) - ZEND_ARG_INFO( 0, "connection resource" ) + ZEND_ARG_INFO( 0, conn ) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_INFO_EX( sqlsrv_client_info_arginfo, 0, 0, 0 ) - ZEND_ARG_INFO( 0, "connection resource" ) +ZEND_BEGIN_ARG_INFO_EX( sqlsrv_client_info_arginfo, 0, 0, 1 ) + ZEND_ARG_INFO( 0, conn ) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX( sqlsrv_commit_arginfo, 0, 0, 1 ) - ZEND_ARG_INFO( 0, "connection resource" ) + ZEND_ARG_INFO( 0, conn ) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX( sqlsrv_configure_arginfo, 0, 0, 2 ) - ZEND_ARG_INFO( 0, "option name" ) - ZEND_ARG_INFO( 0, "value" ) + ZEND_ARG_INFO( 0, setting ) + ZEND_ARG_INFO( 0, value ) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX( sqlsrv_connect_arginfo, 0, 0, 1 ) - ZEND_ARG_INFO( 0, "server" ) - ZEND_ARG_ARRAY_INFO( 0, "options", 0 ) + ZEND_ARG_INFO( 0, server_name ) + ZEND_ARG_ARRAY_INFO( 0, connection_info, 0 ) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX( sqlsrv_errors_arginfo, 0, 1, 0 ) - ZEND_ARG_INFO( 0, "flags (errors, warnings, or all)" ) + ZEND_ARG_INFO( 0, errors_and_or_warnings ) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX( sqlsrv_execute_arginfo, 0, 0, 1 ) - ZEND_ARG_INFO( 0, "statement resource" ) - ZEND_ARG_INFO( 0, "parameters" ) + ZEND_ARG_INFO( 0, stmt ) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX( sqlsrv_fetch_arginfo, 0, 0, 1 ) - ZEND_ARG_INFO( 0, "statement resource" ) + ZEND_ARG_INFO( 0, stmt ) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX( sqlsrv_fetch_array_arginfo, 0, 1, 1 ) - ZEND_ARG_INFO( 0, "statement resource" ) - ZEND_ARG_INFO( 0, "array type" ) + ZEND_ARG_INFO( 0, stmt ) + ZEND_ARG_INFO( 0, fetch_type ) + ZEND_ARG_INFO( 0, row ) + ZEND_ARG_INFO( 0, offset ) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX( sqlsrv_fetch_object_arginfo, 0, 1, 1 ) - ZEND_ARG_INFO( 0, "statement resource" ) - ZEND_ARG_INFO( 0, "class name" ) - ZEND_ARG_INFO( 0, "ctor params" ) + ZEND_ARG_INFO( 0, stmt ) + ZEND_ARG_INFO( 0, class_name ) + ZEND_ARG_INFO( 0, ctor_params ) + ZEND_ARG_INFO( 0, row ) + ZEND_ARG_INFO( 0, offset ) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX( sqlsrv_field_metadata_arginfo, 0, 1, 1 ) - ZEND_ARG_INFO( 0, "statement resource" ) + ZEND_ARG_INFO( 0, stmt ) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO( sqlsrv_free_stmt_arginfo, 0 ) - ZEND_ARG_INFO( 0, "statement resource" ) + ZEND_ARG_INFO( 0, stmt ) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX( sqlsrv_get_config_arginfo, 0, 0, 1 ) - ZEND_ARG_INFO( 0, "option name" ) + ZEND_ARG_INFO( 0, setting ) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX( sqlsrv_get_field_arginfo, 0, 1, 2 ) - ZEND_ARG_INFO( 0, "statement resource" ) - ZEND_ARG_INFO( 0, "field index" ) - ZEND_ARG_INFO( 0, "type" ) + ZEND_ARG_INFO( 0, stmt ) + ZEND_ARG_INFO( 0, field_index ) + ZEND_ARG_INFO( 0, get_as_type ) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO( sqlsrv_has_rows_arginfo, 0 ) - ZEND_ARG_INFO( 0, "statement resource" ) + ZEND_ARG_INFO( 0, stmt ) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO( sqlsrv_next_result_arginfo, 0 ) - ZEND_ARG_INFO( 0, "statement resource" ) + ZEND_ARG_INFO( 0, stmt ) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO( sqlsrv_num_fields_arginfo, 0 ) - ZEND_ARG_INFO( 0, "statement resource" ) + ZEND_ARG_INFO( 0, stmt ) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO( sqlsrv_num_rows_arginfo, 0 ) - ZEND_ARG_INFO( 0, "statement resource" ) + ZEND_ARG_INFO( 0, stmt ) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX( sqlsrv_prepare_arginfo, 0, 1, 2 ) - ZEND_ARG_INFO( 0, "connection resource" ) - ZEND_ARG_INFO( 0, "sql command" ) - ZEND_ARG_INFO( 0, "parameters" ) - ZEND_ARG_ARRAY_INFO( 0, "options", 0 ) + ZEND_ARG_INFO( 0, conn ) + ZEND_ARG_INFO( 0, tsql ) + ZEND_ARG_INFO( 0, params ) + ZEND_ARG_INFO( 0, options ) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX( sqlsrv_query_arginfo, 0, 1, 2 ) - ZEND_ARG_INFO( 0, "connection resource" ) - ZEND_ARG_INFO( 0, "sql command" ) - ZEND_ARG_INFO( 0, "parameters" ) - ZEND_ARG_ARRAY_INFO( 0, "options", 0 ) + ZEND_ARG_INFO( 0, conn ) + ZEND_ARG_INFO( 0, tsql ) + ZEND_ARG_INFO( 0, params ) + ZEND_ARG_INFO( 0, options ) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX( sqlsrv_rollback_arginfo, 0, 0, 1 ) - ZEND_ARG_INFO( 0, "connection resource" ) + ZEND_ARG_INFO( 0, conn ) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO( sqlsrv_rows_affected_arginfo, 0 ) - ZEND_ARG_INFO( 0, "statement resource" ) + ZEND_ARG_INFO( 0, stmt ) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO( sqlsrv_send_stream_data_arginfo, 0 ) - ZEND_ARG_INFO( 0, "statement resource" ) + ZEND_ARG_INFO( 0, stmt ) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO( sqlsrv_server_info_arginfo, 0 ) - ZEND_ARG_INFO( 0, "statement resource" ) + ZEND_ARG_INFO( 0, stmt ) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO( sqlsrv_sqltype_size_arginfo, 0 ) - ZEND_ARG_INFO( 0, "size" ) + ZEND_ARG_INFO( 0, size ) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO( sqlsrv_sqltype_precision_scale_arginfo, 0 ) - ZEND_ARG_INFO( 0, "precision" ) - ZEND_ARG_INFO( 0, "scale" ) + ZEND_ARG_INFO( 0, precision ) + ZEND_ARG_INFO( 0, scale ) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO( sqlsrv_phptype_encoding_arginfo, 0 ) - ZEND_ARG_INFO( 0, "encoding" ) + ZEND_ARG_INFO( 0, encoding ) ZEND_END_ARG_INFO() // function table with associated arginfo structures @@ -290,7 +293,8 @@ PHP_MINIT_FUNCTION(sqlsrv) REGISTER_LONG_CONSTANT( "SQLSRV_LOG_SEVERITY_ALL", -1, CONST_PERSISTENT | CONST_CS ); // -1 so that all the bits are set // register connection resource - ss_sqlsrv_conn::descriptor = zend_register_list_destructors_ex( sqlsrv_conn_dtor, NULL, "SQL Server Connection", module_number ); + ss_sqlsrv_conn::descriptor = zend_register_list_destructors_ex( sqlsrv_conn_dtor, NULL, "SQL Server Connection", + module_number ); if( ss_sqlsrv_conn::descriptor == FAILURE ) { LOG( SEV_ERROR, "%1!s!: connection resource registration failed", _FN_ ); @@ -319,8 +323,8 @@ PHP_MINIT_FUNCTION(sqlsrv) REGISTER_STRING_CONSTANT( "SQLSRV_ENC_BINARY", "binary", CONST_PERSISTENT | CONST_CS ); REGISTER_STRING_CONSTANT( "SQLSRV_ENC_CHAR", "char", CONST_PERSISTENT | CONST_CS ); - REGISTER_LONG_CONSTANT( "SQLSRV_NULLABLE_YES", 0, CONST_PERSISTENT | CONST_CS ); - REGISTER_LONG_CONSTANT( "SQLSRV_NULLABLE_NO", 1, CONST_PERSISTENT | CONST_CS ); + REGISTER_LONG_CONSTANT( "SQLSRV_NULLABLE_NO", 0, CONST_PERSISTENT | CONST_CS ); + REGISTER_LONG_CONSTANT( "SQLSRV_NULLABLE_YES", 1, CONST_PERSISTENT | CONST_CS ); REGISTER_LONG_CONSTANT( "SQLSRV_NULLABLE_UNKNOWN", 2, CONST_PERSISTENT | CONST_CS ); REGISTER_LONG_CONSTANT( "SQLSRV_SQLTYPE_BIGINT", SQL_BIGINT, CONST_PERSISTENT | CONST_CS ); @@ -394,6 +398,7 @@ PHP_MINIT_FUNCTION(sqlsrv) REGISTER_STRING_CONSTANT( "SQLSRV_CURSOR_STATIC", "static", CONST_PERSISTENT | CONST_CS ); REGISTER_STRING_CONSTANT( "SQLSRV_CURSOR_DYNAMIC", "dynamic", CONST_PERSISTENT | CONST_CS ); REGISTER_STRING_CONSTANT( "SQLSRV_CURSOR_KEYSET", "keyset", CONST_PERSISTENT | CONST_CS ); + REGISTER_STRING_CONSTANT( "SQLSRV_CURSOR_CLIENT_BUFFERED", "buffered", CONST_PERSISTENT | CONST_CS ); try { @@ -601,9 +606,16 @@ PHP_RINIT_FUNCTION(sqlsrv) LOG_FUNCTION( "PHP_RINIT for php_sqlsrv" ); + // read INI settings + SQLSRV_G( warnings_return_as_errors ) = INI_BOOL( INI_PREFIX INI_WARNINGS_RETURN_AS_ERRORS ); + SQLSRV_G( log_severity ) = INI_INT( INI_PREFIX INI_LOG_SEVERITY ); + SQLSRV_G( log_subsystems ) = INI_INT( INI_PREFIX INI_LOG_SUBSYSTEMS ); + SQLSRV_G( buffered_query_limit ) = INI_INT( INI_PREFIX INI_BUFFERED_QUERY_LIMIT ); + LOG( SEV_NOTICE, INI_PREFIX INI_WARNINGS_RETURN_AS_ERRORS " = %1!s!", SQLSRV_G( warnings_return_as_errors ) ? "On" : "Off"); LOG( SEV_NOTICE, INI_PREFIX INI_LOG_SEVERITY " = %1!d!", SQLSRV_G( log_severity )); LOG( SEV_NOTICE, INI_PREFIX INI_LOG_SUBSYSTEMS " = %1!d!", SQLSRV_G( log_subsystems )); + LOG( SEV_NOTICE, INI_PREFIX INI_BUFFERED_QUERY_LIMIT " = %1!d!", SQLSRV_G( buffered_query_limit )); // verify memory at the end of the request (in debug mode only) full_mem_check(MEMCHECK_SILENT); @@ -626,7 +638,7 @@ PHP_RSHUTDOWN_FUNCTION(sqlsrv) zval_ptr_dtor( &SQLSRV_G( errors )); zval_ptr_dtor( &SQLSRV_G( warnings )); - // verify memory at the end of the request (in debug mode only) + // verify memory at the end of the request (in debug mode only) full_mem_check(MEMCHECK_SILENT); return SUCCESS; diff --git a/sqlsrv/php_sqlsrv.h b/sqlsrv/php_sqlsrv.h index cb15d19d..61c68349 100644 --- a/sqlsrv/php_sqlsrv.h +++ b/sqlsrv/php_sqlsrv.h @@ -8,7 +8,7 @@ // // Comments: Also contains "internal" declarations shared across source files. // -// Copyright 2010 Microsoft Corporation +// Copyright Microsoft Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -169,19 +169,11 @@ struct stmt_option_scrollable : public stmt_option_functor { // This object inherits and overrides the callbacks necessary struct ss_sqlsrv_stmt : public sqlsrv_stmt { - ss_sqlsrv_stmt( sqlsrv_conn* c, SQLHANDLE handle, error_callback e, void* drv TSRMLS_DC ) : - sqlsrv_stmt( c, handle, e, drv TSRMLS_CC ), - prepared( false ), - conn_index( -1 ), - params_z( NULL ), - fetch_field_names( NULL ), - fetch_fields_count ( 0 ) - { - } + ss_sqlsrv_stmt( sqlsrv_conn* c, SQLHANDLE handle, error_callback e, void* drv TSRMLS_DC ); virtual ~ss_sqlsrv_stmt( void ); - void new_result_set( void ); + void new_result_set( TSRMLS_D ); // driver specific conversion rules from a SQL Server/ODBC type to one of the SQLSRV_PHPTYPE_* constants sqlsrv_phptype sql_type_to_php_type( SQLINTEGER sql_type, SQLUINTEGER size, bool prefer_string_to_stream ); @@ -278,10 +270,11 @@ zval* errors; zval* warnings; // flags for error handling and logging (set via sqlsrv_configure or php.ini) -unsigned int log_severity; -unsigned int log_subsystems; -unsigned int current_subsystem; +long log_severity; +long log_subsystems; +long current_subsystem; zend_bool warnings_return_as_errors; +long buffered_query_limit; ZEND_END_MODULE_GLOBALS(sqlsrv) @@ -301,6 +294,7 @@ ZEND_EXTERN_MODULE_GLOBALS(sqlsrv); #define INI_WARNINGS_RETURN_AS_ERRORS "WarningsReturnAsErrors" #define INI_LOG_SEVERITY "LogSeverity" #define INI_LOG_SUBSYSTEMS "LogSubsystems" +#define INI_BUFFERED_QUERY_LIMIT "ClientBufferMaxKBSize" #define INI_PREFIX "sqlsrv." PHP_INI_BEGIN() @@ -310,6 +304,8 @@ PHP_INI_BEGIN() sqlsrv_globals ) STD_PHP_INI_ENTRY( INI_PREFIX INI_LOG_SUBSYSTEMS, "0", PHP_INI_ALL, OnUpdateLong, log_subsystems, zend_sqlsrv_globals, sqlsrv_globals ) + STD_PHP_INI_ENTRY( INI_PREFIX INI_BUFFERED_QUERY_LIMIT, INI_BUFFERED_QUERY_LIMIT_DEFAULT, PHP_INI_ALL, OnUpdateLong, buffered_query_limit, + zend_sqlsrv_globals, sqlsrv_globals ) PHP_INI_END() //********************************************************************************************************************************* @@ -366,7 +362,6 @@ bool ss_error_handler( sqlsrv_context& ctx, unsigned int sqlsrv_error_code, bool // *** extension error functions *** PHP_FUNCTION(sqlsrv_errors); -PHP_FUNCTION(sqlsrv_warnings); // convert from the default encoding specified by the "CharacterSet" // connection option to UTF-16. mbcs_len and utf16_len are sizes in @@ -461,7 +456,8 @@ public: #define LOG_FUNCTION( function_name ) \ const char* _FN_ = function_name; \ SQLSRV_G( current_subsystem ) = current_log_subsystem; \ - LOG( SEV_NOTICE, "%1!s!: entering", _FN_ ); + LOG( SEV_NOTICE, "%1!s!: entering", _FN_ ); \ + CheckMemory _check_memory_; #define SET_FUNCTION_NAME( context ) \ { \ @@ -480,6 +476,22 @@ enum logging_subsystems { LOG_ALL = -1, }; +struct CheckMemory { + + CheckMemory( void ) + { + // test the integrity of the Zend heap. + full_mem_check(MEMCHECK_SILENT); + } + + ~CheckMemory( void ) + { + // test the integrity of the Zend heap. + full_mem_check(MEMCHECK_SILENT); + } +}; + + //********************************************************************************************************************************* // Utility Functions //********************************************************************************************************************************* @@ -497,9 +509,6 @@ inline H* process_params( INTERNAL_FUNCTION_PARAMETERS, char const* param_spec, zval* rsrc; H* h; - // test the integrity of the Zend heap. - full_mem_check(MEMCHECK_SILENT); - // reset the errors from the previous API call reset_errors( TSRMLS_C ); @@ -529,8 +538,8 @@ inline H* process_params( INTERNAL_FUNCTION_PARAMETERS, char const* param_spec, int result = SUCCESS; // dummy context to pass to the error handler - sqlsrv_context *error_ctx = new sqlsrv_context( 0, ss_error_handler, NULL ); - error_ctx->set_func( calling_func ); + sqlsrv_context error_ctx( 0, ss_error_handler, NULL );; + error_ctx.set_func( calling_func ); switch( param_count ) { @@ -574,7 +583,7 @@ inline H* process_params( INTERNAL_FUNCTION_PARAMETERS, char const* param_spec, } } - CHECK_CUSTOM_ERROR(( result == FAILURE ), error_ctx, SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER, calling_func ) { + CHECK_CUSTOM_ERROR(( result == FAILURE ), &error_ctx, SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER, calling_func ) { throw ss::SSException(); } @@ -582,7 +591,7 @@ inline H* process_params( INTERNAL_FUNCTION_PARAMETERS, char const* param_spec, // get the resource registered h = static_cast( zend_fetch_resource( &rsrc TSRMLS_CC, -1, H::resource_name, NULL, 1, H::descriptor )); - CHECK_CUSTOM_ERROR(( h == NULL ), error_ctx, SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER, calling_func ) { + CHECK_CUSTOM_ERROR(( h == NULL ), &error_ctx, SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER, calling_func ) { throw ss::SSException(); } diff --git a/sqlsrv/sqlncli.h b/sqlsrv/sqlncli.h new file mode 100644 index 00000000..518ddd4f --- /dev/null +++ b/sqlsrv/sqlncli.h @@ -0,0 +1,3043 @@ + + +/* this ALWAYS GENERATED file contains the definitions for the interfaces */ + + + /* File created by MIDL compiler version 7.00.0474 */ +/* Compiler settings for sqlncli.idl: + Oicf, W1, Zp8, env=Win32 (32b run) + protocol : dce , ms_ext, c_ext, robust + error checks: allocation ref bounds_check enum stub_data + VC __declspec() decoration level: + __declspec(uuid()), __declspec(selectany), __declspec(novtable) + DECLSPEC_UUID(), MIDL_INTERFACE() +*/ +//@@MIDL_FILE_HEADING( ) + +#pragma warning( disable: 4049 ) /* more than 64k source lines */ + + +/* verify that the version is high enough to compile this file*/ +#ifndef __REQUIRED_RPCNDR_H_VERSION__ +#define __REQUIRED_RPCNDR_H_VERSION__ 475 +#endif + +#include "rpc.h" +#include "rpcndr.h" + +#ifndef __RPCNDR_H_VERSION__ +#error this stub requires an updated version of +#endif // __RPCNDR_H_VERSION__ + +#ifndef COM_NO_WINDOWS_H +#include "windows.h" +#include "ole2.h" +#endif /*COM_NO_WINDOWS_H*/ + +#ifndef __sqlncli_h__ +#define __sqlncli_h__ + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +/* Forward Declarations */ + +#ifndef __ICommandWithParameters_FWD_DEFINED__ +#define __ICommandWithParameters_FWD_DEFINED__ +typedef interface ICommandWithParameters ICommandWithParameters; +#endif /* __ICommandWithParameters_FWD_DEFINED__ */ + + +#ifndef __IUMSInitialize_FWD_DEFINED__ +#define __IUMSInitialize_FWD_DEFINED__ +typedef interface IUMSInitialize IUMSInitialize; +#endif /* __IUMSInitialize_FWD_DEFINED__ */ + + +#ifndef __ISQLServerErrorInfo_FWD_DEFINED__ +#define __ISQLServerErrorInfo_FWD_DEFINED__ +typedef interface ISQLServerErrorInfo ISQLServerErrorInfo; +#endif /* __ISQLServerErrorInfo_FWD_DEFINED__ */ + + +#ifndef __IRowsetFastLoad_FWD_DEFINED__ +#define __IRowsetFastLoad_FWD_DEFINED__ +typedef interface IRowsetFastLoad IRowsetFastLoad; +#endif /* __IRowsetFastLoad_FWD_DEFINED__ */ + + +#ifndef __ISchemaLock_FWD_DEFINED__ +#define __ISchemaLock_FWD_DEFINED__ +typedef interface ISchemaLock ISchemaLock; +#endif /* __ISchemaLock_FWD_DEFINED__ */ + + +#ifndef __IBCPSession_FWD_DEFINED__ +#define __IBCPSession_FWD_DEFINED__ +typedef interface IBCPSession IBCPSession; +#endif /* __IBCPSession_FWD_DEFINED__ */ + + +#ifndef __ISSAbort_FWD_DEFINED__ +#define __ISSAbort_FWD_DEFINED__ +typedef interface ISSAbort ISSAbort; +#endif /* __ISSAbort_FWD_DEFINED__ */ + + +#ifndef __ISSCommandWithParameters_FWD_DEFINED__ +#define __ISSCommandWithParameters_FWD_DEFINED__ +typedef interface ISSCommandWithParameters ISSCommandWithParameters; +#endif /* __ISSCommandWithParameters_FWD_DEFINED__ */ + + +#ifndef __IDBAsynchStatus_FWD_DEFINED__ +#define __IDBAsynchStatus_FWD_DEFINED__ +typedef interface IDBAsynchStatus IDBAsynchStatus; +#endif /* __IDBAsynchStatus_FWD_DEFINED__ */ + + +#ifndef __ISSAsynchStatus_FWD_DEFINED__ +#define __ISSAsynchStatus_FWD_DEFINED__ +typedef interface ISSAsynchStatus ISSAsynchStatus; +#endif /* __ISSAsynchStatus_FWD_DEFINED__ */ + + +/* header files for imported files */ +#include "unknwn.h" +#include "oaidl.h" + +#ifdef __cplusplus +extern "C"{ +#endif + + +/* interface __MIDL_itf_sqlncli_0000_0000 */ +/* [local] */ + +//----------------------------------------------------------------------------- +// File: sqlncli.h +// +// Copyright: Copyright (c) Microsoft Corporation +// +// Contents: SQL Server Native Client OLEDB provider and ODBC driver specific +// definitions. +// +//----------------------------------------------------------------------------- + +#if !defined(SQLNCLI_VER) +#define SQLNCLI_VER 1000 +#endif + +#if SQLNCLI_VER >= 1000 + +#define SQLNCLI_PRODUCT_NAME_FULL_VER_ANSI "Microsoft SQL Server Native Client 10.0" +#define SQLNCLI_PRODUCT_NAME_FULL_ANSI "Microsoft SQL Server Native Client" +#define SQLNCLI_PRODUCT_NAME_SHORT_VER_ANSI "SQL Server Native Client 10.0" +#define SQLNCLI_PRODUCT_NAME_SHORT_ANSI "SQL Server Native Client" + +#define SQLNCLI_FILE_NAME_ANSI "sqlncli" +#define SQLNCLI_FILE_NAME_VER_ANSI "sqlncli10" +#define SQLNCLI_FILE_NAME_FULL_ANSI "sqlncli10.dll" + +#define SQLNCLI_PRODUCT_NAME_FULL_VER_UNICODE L"Microsoft SQL Server Native Client 10.0" +#define SQLNCLI_PRODUCT_NAME_FULL_UNICODE L"Microsoft SQL Server Native Client" +#define SQLNCLI_PRODUCT_NAME_SHORT_VER_UNICODE L"SQL Server Native Client 10.0" +#define SQLNCLI_PRODUCT_NAME_SHORT_UNICODE L"SQL Server Native Client" + +#define SQLNCLI_FILE_NAME_UNICODE L"sqlncli" +#define SQLNCLI_FILE_NAME_VER_UNICODE L"sqlncli10" +#define SQLNCLI_FILE_NAME_FULL_UNICODE L"sqlncli10.dll" + +#if defined(_SQLNCLI_OLEDB_) || !defined(_SQLNCLI_ODBC_) + +#define SQLNCLI_VI_PROG_ID_ANSI "SQLNCLI10" +#define SQLNCLI_VI_ERROR_LOOKUP_PROG_ID_ANSI "SQLNCLI10 ErrorLookup" +#define SQLNCLI_VI_ENUMERATOR_PROG_ID_ANSI "SQLNCLI10 Enumerator" + +#define SQLNCLI_PROG_ID_ANSI "SQLNCLI10.1" +#define SQLNCLI_ERROR_LOOKUP_PROG_ID_ANSI "SQLNCLI10 ErrorLookup.1" +#define SQLNCLI_ENUMERATOR_PROG_ID_ANSI "SQLNCLI10 Enumerator.1" + +#define SQLNCLI_VI_PROG_ID_UNICODE L"SQLNCLI10" +#define SQLNCLI_VI_ERROR_LOOKUP_PROG_ID_UNICODE L"SQLNCLI10 ErrorLookup" +#define SQLNCLI_VI_ENUMERATOR_PROG_ID_UNICODE L"SQLNCLI10 Enumerator" + +#define SQLNCLI_PROG_ID_UNICODE L"SQLNCLI10.1" +#define SQLNCLI_ERROR_LOOKUP_PROG_ID_UNICODE L"SQLNCLI10 ErrorLookup.1" +#define SQLNCLI_ENUMERATOR_PROG_ID_UNICODE L"SQLNCLI10 Enumerator.1" + +#define SQLNCLI_CLSID CLSID_SQLNCLI10 +#define SQLNCLI_ERROR_CLSID CLSID_SQLNCLI10_ERROR +#define SQLNCLI_ENUMERATOR_CLSID CLSID_SQLNCLI10_ENUMERATOR + +#endif // defined(_SQLNCLI_OLEDB_) || !defined(_SQLNCLI_ODBC_) + +#else // SQLNCLI_VER >= 1000 + +#define SQLNCLI_PRODUCT_NAME_FULL_VER_ANSI "Microsoft SQL Server Native Client" +#define SQLNCLI_PRODUCT_NAME_FULL_ANSI "Microsoft SQL Server Native Client" +#define SQLNCLI_PRODUCT_NAME_SHORT_VER_ANSI "SQL Native Client" +#define SQLNCLI_PRODUCT_NAME_SHORT_ANSI "SQL Native Client" + +#define SQLNCLI_FILE_NAME_ANSI "sqlncli" +#define SQLNCLI_FILE_NAME_VER_ANSI "sqlncli" +#define SQLNCLI_FILE_NAME_FULL_ANSI "sqlncli.dll" + +#define SQLNCLI_PRODUCT_NAME_FULL_VER_UNICODE L"Microsoft SQL Server Native Client" +#define SQLNCLI_PRODUCT_NAME_FULL_UNICODE L"Microsoft SQL Server Native Client" +#define SQLNCLI_PRODUCT_NAME_SHORT_VER_UNICODE L"SQL Native Client" +#define SQLNCLI_PRODUCT_NAME_SHORT_UNICODE L"SQL Native Client" + +#define SQLNCLI_FILE_NAME_UNICODE L"sqlncli" +#define SQLNCLI_FILE_NAME_VER_UNICODE L"sqlncli" +#define SQLNCLI_FILE_NAME_FULL_UNICODE L"sqlncli.dll" + +#if defined(_SQLNCLI_OLEDB_) || !defined(_SQLNCLI_ODBC_) + +#define SQLNCLI_VI_PROG_ID_ANSI "SQLNCLI" +#define SQLNCLI_VI_ERROR_LOOKUP_PROG_ID_ANSI "SQLNCLI ErrorLookup" +#define SQLNCLI_VI_ENUMERATOR_PROG_ID_ANSI "SQLNCLI Enumerator" + +#define SQLNCLI_PROG_ID_ANSI "SQLNCLI.1" +#define SQLNCLI_ERROR_LOOKUP_PROG_ID_ANSI "SQLNCLI ErrorLookup.1" +#define SQLNCLI_ENUMERATOR_PROG_ID_ANSI "SQLNCLI Enumerator.1" + +#define SQLNCLI_VI_PROG_ID_UNICODE L"SQLNCLI" +#define SQLNCLI_VI_ERROR_LOOKUP_PROG_ID_UNICODE L"SQLNCLI ErrorLookup" +#define SQLNCLI_VI_ENUMERATOR_PROG_ID_UNICODE L"SQLNCLI Enumerator" + +#define SQLNCLI_PROG_ID_UNICODE L"SQLNCLI.1" +#define SQLNCLI_ERROR_LOOKUP_PROG_ID_UNICODE L"SQLNCLI ErrorLookup.1" +#define SQLNCLI_ENUMERATOR_PROG_ID_UNICODE L"SQLNCLI Enumerator.1" + +#define SQLNCLI_CLSID CLSID_SQLNCLI +#define SQLNCLI_ERROR_CLSID CLSID_SQLNCLI_ERROR +#define SQLNCLI_ENUMERATOR_CLSID CLSID_SQLNCLI_ENUMERATOR + +#endif // defined(_SQLNCLI_OLEDB_) || !defined(_SQLNCLI_ODBC_) + +#endif // SQLNCLI_VER >= 1000 + +// define the character type agnostic constants +#if defined(_UNICODE) || defined(UNICODE) + +#define SQLNCLI_PRODUCT_NAME_FULL_VER SQLNCLI_PRODUCT_NAME_FULL_VER_UNICODE +#define SQLNCLI_PRODUCT_NAME_FULL SQLNCLI_PRODUCT_NAME_FULL_UNICODE +#define SQLNCLI_PRODUCT_NAME_SHORT_VER SQLNCLI_PRODUCT_NAME_SHORT_VER_UNICODE +#define SQLNCLI_PRODUCT_NAME_SHORT SQLNCLI_PRODUCT_NAME_SHORT_UNICODE + +#define SQLNCLI_FILE_NAME SQLNCLI_FILE_NAME_UNICODE +#define SQLNCLI_FILE_NAME_VER SQLNCLI_FILE_NAME_VER_UNICODE +#define SQLNCLI_FILE_NAME_FULL SQLNCLI_FILE_NAME_FULL_UNICODE + +#if defined(_SQLNCLI_OLEDB_) || !defined(_SQLNCLI_ODBC_) + +#define SQLNCLI_VI_PROG_ID SQLNCLI_VI_PROG_ID_UNICODE +#define SQLNCLI_VI_ERROR_LOOKUP_PROG_ID SQLNCLI_VI_ERROR_LOOKUP_PROG_ID_UNICODE +#define SQLNCLI_VI_ENUMERATOR_PROG_ID SQLNCLI_VI_ENUMERATOR_PROG_ID_UNICODE + +#define SQLNCLI_PROG_ID SQLNCLI_PROG_ID_UNICODE +#define SQLNCLI_ERROR_LOOKUP_PROG_ID SQLNCLI_ERROR_LOOKUP_PROG_ID_UNICODE +#define SQLNCLI_ENUMERATOR_PROG_ID SQLNCLI_ENUMERATOR_PROG_ID_UNICODE + +#endif // defined(_SQLNCLI_OLEDB_) || !defined(_SQLNCLI_ODBC_) + +#else // _UNICODE || UNICODE + +#define SQLNCLI_PRODUCT_NAME_FULL_VER SQLNCLI_PRODUCT_NAME_FULL_VER_ANSI +#define SQLNCLI_PRODUCT_NAME_FULL SQLNCLI_PRODUCT_NAME_FULL_ANSI +#define SQLNCLI_PRODUCT_NAME_SHORT_VER SQLNCLI_PRODUCT_NAME_SHORT_VER_ANSI +#define SQLNCLI_PRODUCT_NAME_SHORT SQLNCLI_PRODUCT_NAME_SHORT_ANSI + +#define SQLNCLI_FILE_NAME SQLNCLI_FILE_NAME_ANSI +#define SQLNCLI_FILE_NAME_VER SQLNCLI_FILE_NAME_VER_ANSI +#define SQLNCLI_FILE_NAME_FULL SQLNCLI_FILE_NAME_FULL_ANSI + +#if defined(_SQLNCLI_OLEDB_) || !defined(_SQLNCLI_ODBC_) + +#define SQLNCLI_VI_PROG_ID SQLNCLI_VI_PROG_ID_ANSI +#define SQLNCLI_VI_ERROR_LOOKUP_PROG_ID SQLNCLI_VI_ERROR_LOOKUP_PROG_ID_ANSI +#define SQLNCLI_VI_ENUMERATOR_PROG_ID SQLNCLI_VI_ENUMERATOR_PROG_ID_ANSI + +#define SQLNCLI_PROG_ID SQLNCLI_PROG_ID_ANSI +#define SQLNCLI_ERROR_LOOKUP_PROG_ID SQLNCLI_ERROR_LOOKUP_PROG_ID_ANSI +#define SQLNCLI_ENUMERATOR_PROG_ID SQLNCLI_ENUMERATOR_PROG_ID_ANSI + +#endif // defined(_SQLNCLI_OLEDB_) || !defined(_SQLNCLI_ODBC_) + +#endif // _UNICODE || UNICODE + +#if defined(_SQLNCLI_ODBC_) || !defined(_SQLNCLI_OLEDB_) + +#define SQLNCLI_DRIVER_NAME SQLNCLI_PRODUCT_NAME_SHORT_VER + +#endif + +// OLEDB part of SQL Server Native Client header - begin here +#if defined(_SQLNCLI_OLEDB_) || !defined(_SQLNCLI_ODBC_) +#ifndef __oledb_h__ +#include +#endif /*__oledb_h__*/ + +#if 0 // This is already defined in oledb.h + +#ifdef _WIN64 + +// Length of a non-character object, size +typedef ULONGLONG DBLENGTH; + +// Offset within a rowset +typedef LONGLONG DBROWOFFSET; + +// Number of rows +typedef LONGLONG DBROWCOUNT; + +typedef ULONGLONG DBCOUNTITEM; + +// Ordinal (column number, etc.) +typedef ULONGLONG DBORDINAL; + +typedef LONGLONG DB_LORDINAL; + +// Bookmarks +typedef ULONGLONG DBBKMARK; +// Offset in the buffer + +typedef ULONGLONG DBBYTEOFFSET; +// Reference count of each row/accessor handle + +typedef ULONG DBREFCOUNT; + +// Parameters +typedef ULONGLONG DB_UPARAMS; + +typedef LONGLONG DB_LPARAMS; + +// hash values corresponding to the elements (bookmarks) +typedef DWORDLONG DBHASHVALUE; + +// For reserve +typedef DWORDLONG DB_DWRESERVE; + +typedef LONGLONG DB_LRESERVE; + +typedef ULONGLONG DB_URESERVE; + +#else //_WIN64 + +// Length of a non-character object, size +typedef ULONG DBLENGTH; + +// Offset within a rowset +typedef LONG DBROWOFFSET; + +// Number of rows +typedef LONG DBROWCOUNT; + +typedef ULONG DBCOUNTITEM; + +// Ordinal (column number, etc.) +typedef ULONG DBORDINAL; + +typedef LONG DB_LORDINAL; + +// Bookmarks +typedef ULONG DBBKMARK; + +// Offset in the buffer +typedef ULONG DBBYTEOFFSET; + +// Reference count of each row handle +typedef ULONG DBREFCOUNT; + +// Parameters +typedef ULONG DB_UPARAMS; + +typedef LONG DB_LPARAMS; + +// hash values corresponding to the elements (bookmarks) +typedef DWORD DBHASHVALUE; + +// For reserve +typedef DWORD DB_DWRESERVE; + +typedef LONG DB_LRESERVE; + +typedef ULONG DB_URESERVE; + +#endif // _WIN64 +typedef DWORD DBKIND; + + +enum DBKINDENUM + { DBKIND_GUID_NAME = 0, + DBKIND_GUID_PROPID = ( DBKIND_GUID_NAME + 1 ) , + DBKIND_NAME = ( DBKIND_GUID_PROPID + 1 ) , + DBKIND_PGUID_NAME = ( DBKIND_NAME + 1 ) , + DBKIND_PGUID_PROPID = ( DBKIND_PGUID_NAME + 1 ) , + DBKIND_PROPID = ( DBKIND_PGUID_PROPID + 1 ) , + DBKIND_GUID = ( DBKIND_PROPID + 1 ) + } ; +typedef struct tagDBID + { + union + { + GUID guid; + GUID *pguid; + /* Empty union arm */ + } uGuid; + DBKIND eKind; + union + { + LPOLESTR pwszName; + ULONG ulPropid; + /* Empty union arm */ + } uName; + } DBID; + +typedef struct tagDB_NUMERIC + { + BYTE precision; + BYTE scale; + BYTE sign; + BYTE val[ 16 ]; + } DB_NUMERIC; + +typedef struct tagDBDATE + { + SHORT year; + USHORT month; + USHORT day; + } DBDATE; + +typedef struct tagDBTIME + { + USHORT hour; + USHORT minute; + USHORT second; + } DBTIME; + +typedef struct tagDBTIMESTAMP + { + SHORT year; + USHORT month; + USHORT day; + USHORT hour; + USHORT minute; + USHORT second; + ULONG fraction; + } DBTIMESTAMP; + +typedef struct tagDBOBJECT + { + DWORD dwFlags; + IID iid; + } DBOBJECT; + +typedef WORD DBTYPE; + +typedef ULONG_PTR HACCESSOR; + +typedef ULONG_PTR HCHAPTER; + +typedef DWORD DBPARAMFLAGS; + +typedef struct tagDBPARAMINFO + { + DBPARAMFLAGS dwFlags; + DBORDINAL iOrdinal; + LPOLESTR pwszName; + ITypeInfo *pTypeInfo; + DBLENGTH ulParamSize; + DBTYPE wType; + BYTE bPrecision; + BYTE bScale; + } DBPARAMINFO; + +typedef DWORD DBPROPID; + +typedef struct tagDBPROPIDSET + { + DBPROPID *rgPropertyIDs; + ULONG cPropertyIDs; + GUID guidPropertySet; + } DBPROPIDSET; + +typedef DWORD DBPROPFLAGS; + +typedef DWORD DBPROPOPTIONS; + +typedef DWORD DBPROPSTATUS; + +typedef struct tagDBPROP + { + DBPROPID dwPropertyID; + DBPROPOPTIONS dwOptions; + DBPROPSTATUS dwStatus; + DBID colid; + VARIANT vValue; + } DBPROP; + +typedef struct tagDBPROPSET + { + DBPROP *rgProperties; + ULONG cProperties; + GUID guidPropertySet; + } DBPROPSET; + + + +extern RPC_IF_HANDLE __MIDL_itf_sqlncli_0000_0000_v0_0_c_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_sqlncli_0000_0000_v0_0_s_ifspec; + +#ifndef __ICommandWithParameters_INTERFACE_DEFINED__ +#define __ICommandWithParameters_INTERFACE_DEFINED__ + +/* interface ICommandWithParameters */ +/* [unique][uuid][object][local] */ + +typedef struct tagDBPARAMBINDINFO + { + LPOLESTR pwszDataSourceType; + LPOLESTR pwszName; + DBLENGTH ulParamSize; + DBPARAMFLAGS dwFlags; + BYTE bPrecision; + BYTE bScale; + } DBPARAMBINDINFO; + + +EXTERN_C const IID IID_ICommandWithParameters; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("0c733a64-2a1c-11ce-ade5-00aa0044773d") + ICommandWithParameters : public IUnknown + { + public: + virtual /* [local] */ HRESULT STDMETHODCALLTYPE GetParameterInfo( + /* [out][in] */ DB_UPARAMS *pcParams, + /* [size_is][size_is][out] */ DBPARAMINFO **prgParamInfo, + /* [out] */ OLECHAR **ppNamesBuffer) = 0; + + virtual /* [local] */ HRESULT STDMETHODCALLTYPE MapParameterNames( + /* [in] */ DB_UPARAMS cParamNames, + /* [size_is][in] */ const OLECHAR *rgParamNames[ ], + /* [size_is][out] */ DB_LPARAMS rgParamOrdinals[ ]) = 0; + + virtual /* [local] */ HRESULT STDMETHODCALLTYPE SetParameterInfo( + /* [in] */ DB_UPARAMS cParams, + /* [size_is][unique][in] */ const DB_UPARAMS rgParamOrdinals[ ], + /* [size_is][unique][in] */ const DBPARAMBINDINFO rgParamBindInfo[ ]) = 0; + + }; + +#else /* C style interface */ + + typedef struct ICommandWithParametersVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICommandWithParameters * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICommandWithParameters * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICommandWithParameters * This); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *GetParameterInfo )( + ICommandWithParameters * This, + /* [out][in] */ DB_UPARAMS *pcParams, + /* [size_is][size_is][out] */ DBPARAMINFO **prgParamInfo, + /* [out] */ OLECHAR **ppNamesBuffer); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *MapParameterNames )( + ICommandWithParameters * This, + /* [in] */ DB_UPARAMS cParamNames, + /* [size_is][in] */ const OLECHAR *rgParamNames[ ], + /* [size_is][out] */ DB_LPARAMS rgParamOrdinals[ ]); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *SetParameterInfo )( + ICommandWithParameters * This, + /* [in] */ DB_UPARAMS cParams, + /* [size_is][unique][in] */ const DB_UPARAMS rgParamOrdinals[ ], + /* [size_is][unique][in] */ const DBPARAMBINDINFO rgParamBindInfo[ ]); + + END_INTERFACE + } ICommandWithParametersVtbl; + + interface ICommandWithParameters + { + CONST_VTBL struct ICommandWithParametersVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICommandWithParameters_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICommandWithParameters_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICommandWithParameters_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICommandWithParameters_GetParameterInfo(This,pcParams,prgParamInfo,ppNamesBuffer) \ + ( (This)->lpVtbl -> GetParameterInfo(This,pcParams,prgParamInfo,ppNamesBuffer) ) + +#define ICommandWithParameters_MapParameterNames(This,cParamNames,rgParamNames,rgParamOrdinals) \ + ( (This)->lpVtbl -> MapParameterNames(This,cParamNames,rgParamNames,rgParamOrdinals) ) + +#define ICommandWithParameters_SetParameterInfo(This,cParams,rgParamOrdinals,rgParamBindInfo) \ + ( (This)->lpVtbl -> SetParameterInfo(This,cParams,rgParamOrdinals,rgParamBindInfo) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE ICommandWithParameters_RemoteGetParameterInfo_Proxy( + ICommandWithParameters * This, + /* [out][in] */ DB_UPARAMS *pcParams, + /* [size_is][size_is][out] */ DBPARAMINFO **prgParamInfo, + /* [size_is][size_is][out] */ DBBYTEOFFSET **prgNameOffsets, + /* [out][in] */ DBLENGTH *pcbNamesBuffer, + /* [size_is][size_is][unique][out][in] */ OLECHAR **ppNamesBuffer, + /* [out] */ IErrorInfo **ppErrorInfoRem); + + +void __RPC_STUB ICommandWithParameters_RemoteGetParameterInfo_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase); + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE ICommandWithParameters_RemoteMapParameterNames_Proxy( + ICommandWithParameters * This, + /* [in] */ DB_UPARAMS cParamNames, + /* [size_is][in] */ LPCOLESTR *rgParamNames, + /* [size_is][out] */ DB_LPARAMS *rgParamOrdinals, + /* [out] */ IErrorInfo **ppErrorInfoRem); + + +void __RPC_STUB ICommandWithParameters_RemoteMapParameterNames_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase); + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE ICommandWithParameters_RemoteSetParameterInfo_Proxy( + ICommandWithParameters * This, + /* [in] */ DB_UPARAMS cParams, + /* [size_is][unique][in] */ const DB_UPARAMS *rgParamOrdinals, + /* [size_is][unique][in] */ const DBPARAMBINDINFO *rgParamBindInfo, + /* [out] */ IErrorInfo **ppErrorInfoRem); + + +void __RPC_STUB ICommandWithParameters_RemoteSetParameterInfo_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase); + + + +#endif /* __ICommandWithParameters_INTERFACE_DEFINED__ */ + + +/* interface __MIDL_itf_sqlncli_0000_0001 */ +/* [local] */ + +typedef DWORD DBASYNCHOP; + +typedef DWORD DBASYNCHPHASE; + +#endif // This is already defined in oledb.h + +//------------------------------------------------------------------- +// Variant Access macros, similar to ole automation. +//------------------------------------------------------------------- +#define V_SS_VT(X) ((X)->vt) +#define V_SS_UNION(X, Y) ((X)->Y) + +#define V_SS_UI1(X) V_SS_UNION(X, bTinyIntVal) +#define V_SS_I2(X) V_SS_UNION(X, sShortIntVal) +#define V_SS_I4(X) V_SS_UNION(X, lIntVal) +#define V_SS_I8(X) V_SS_UNION(X, llBigIntVal) + +#define V_SS_R4(X) V_SS_UNION(X, fltRealVal) +#define V_SS_R8(X) V_SS_UNION(X, dblFloatVal) +#define V_SS_UI4(X) V_SS_UNION(X, ulVal) + +#define V_SS_MONEY(X) V_SS_UNION(X, cyMoneyVal) +#define V_SS_SMALLMONEY(X) V_SS_UNION(X, cyMoneyVal) + +#define V_SS_WSTRING(X) V_SS_UNION(X, NCharVal) +#define V_SS_WVARSTRING(X) V_SS_UNION(X, NCharVal) + +#define V_SS_STRING(X) V_SS_UNION(X, CharVal) +#define V_SS_VARSTRING(X) V_SS_UNION(X, CharVal) + +#define V_SS_BIT(X) V_SS_UNION(X, fBitVal) +#define V_SS_GUID(X) V_SS_UNION(X, rgbGuidVal) + +#define V_SS_NUMERIC(X) V_SS_UNION(X, numNumericVal) +#define V_SS_DECIMAL(X) V_SS_UNION(X, numNumericVal) + +#define V_SS_BINARY(X) V_SS_UNION(X, BinaryVal) +#define V_SS_VARBINARY(X) V_SS_UNION(X, BinaryVal) + +#define V_SS_DATETIME(X) V_SS_UNION(X, tsDateTimeVal) +#define V_SS_SMALLDATETIME(X) V_SS_UNION(X, tsDateTimeVal) + +#define V_SS_UNKNOWN(X) V_SS_UNION(X, UnknownType) + +//Text and image types. +#define V_SS_IMAGE(X) V_SS_UNION(X, ImageVal) +#define V_SS_TEXT(X) V_SS_UNION(X, TextVal) +#define V_SS_NTEXT(X) V_SS_UNION(X, NTextVal) + +//Microsoft SQL Server 2008 datetime. +#define V_SS_DATE(X) V_SS_UNION(X, dDateVal) +#define V_SS_TIME2(X) V_SS_UNION(X, Time2Val) +#define V_SS_DATETIME2(X) V_SS_UNION(X, DateTimeVal) +#define V_SS_DATETIMEOFFSET(X) V_SS_UNION(X, DateTimeOffsetVal) + +//------------------------------------------------------------------- +// define SQL Server specific types. +//------------------------------------------------------------------- +typedef enum DBTYPEENUM EOledbTypes; +#define DBTYPE_XML ((EOledbTypes) 141) // introduced in SQL 2005 +#define DBTYPE_TABLE ((EOledbTypes) 143) // introduced in SQL 2008 +#define DBTYPE_DBTIME2 ((EOledbTypes) 145) // introduced in SQL 2008 +#define DBTYPE_DBTIMESTAMPOFFSET ((EOledbTypes) 146) // introduced in SQL 2008 +#ifdef _SQLOLEDB_H_ +#undef DBTYPE_SQLVARIANT +#endif //_SQLOLEDB_H_ +#define DBTYPE_SQLVARIANT ((EOledbTypes) 144) // introduced in MDAC 2.5 + + +#ifndef _SQLOLEDB_H_ +enum SQLVARENUM + { + VT_SS_EMPTY = DBTYPE_EMPTY, + VT_SS_NULL = DBTYPE_NULL, + VT_SS_UI1 = DBTYPE_UI1, + VT_SS_I2 = DBTYPE_I2, + VT_SS_I4 = DBTYPE_I4, + VT_SS_I8 = DBTYPE_I8, + + //Floats + VT_SS_R4 = DBTYPE_R4, + VT_SS_R8 = DBTYPE_R8, + + //Money + VT_SS_MONEY = DBTYPE_CY, + VT_SS_SMALLMONEY = 200, + + //Strings + VT_SS_WSTRING = 201, + VT_SS_WVARSTRING = 202, + + VT_SS_STRING = 203, + VT_SS_VARSTRING = 204, + + //Bit + VT_SS_BIT = DBTYPE_BOOL, + + //Guid + VT_SS_GUID = DBTYPE_GUID, + + //Exact precision + VT_SS_NUMERIC = DBTYPE_NUMERIC, + VT_SS_DECIMAL = 205, + + //Datetime + VT_SS_DATETIME = DBTYPE_DBTIMESTAMP, + VT_SS_SMALLDATETIME =206, + + //Binary + VT_SS_BINARY =207, + VT_SS_VARBINARY = 208, + //Future + VT_SS_UNKNOWN = 209, + + //Additional datetime + VT_SS_DATE = DBTYPE_DBDATE, + VT_SS_TIME2 = DBTYPE_DBTIME2, + VT_SS_DATETIME2 = 212, + VT_SS_DATETIMEOFFSET = DBTYPE_DBTIMESTAMPOFFSET, + }; +typedef unsigned short SSVARTYPE; + + +enum DBPARAMFLAGSENUM_SS_100 + { DBPARAMFLAGS_SS_ISVARIABLESCALE = 0x40000000 + } ; +enum DBCOLUMNFLAGSENUM_SS_100 + { DBCOLUMNFLAGS_SS_ISVARIABLESCALE = 0x40000000, + DBCOLUMNFLAGS_SS_ISCOLUMNSET = 0x80000000 + } ; + +//------------------------------------------------------------------- +// Class Factory Interface used to initialize pointer to UMS. +//------------------------------------------------------------------- + + +extern RPC_IF_HANDLE __MIDL_itf_sqlncli_0000_0001_v0_0_c_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_sqlncli_0000_0001_v0_0_s_ifspec; + +#ifndef __IUMSInitialize_INTERFACE_DEFINED__ +#define __IUMSInitialize_INTERFACE_DEFINED__ + +/* interface IUMSInitialize */ +/* [unique][uuid][object][local] */ + + +EXTERN_C const IID IID_IUMSInitialize; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("5cf4ca14-ef21-11d0-97e7-00c04fc2ad98") + IUMSInitialize : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Initialize( + /* [in] */ void *pUMS) = 0; + + }; + +#else /* C style interface */ + + typedef struct IUMSInitializeVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IUMSInitialize * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IUMSInitialize * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IUMSInitialize * This); + + HRESULT ( STDMETHODCALLTYPE *Initialize )( + IUMSInitialize * This, + /* [in] */ void *pUMS); + + END_INTERFACE + } IUMSInitializeVtbl; + + interface IUMSInitialize + { + CONST_VTBL struct IUMSInitializeVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IUMSInitialize_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IUMSInitialize_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IUMSInitialize_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IUMSInitialize_Initialize(This,pUMS) \ + ( (This)->lpVtbl -> Initialize(This,pUMS) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IUMSInitialize_INTERFACE_DEFINED__ */ + + +/* interface __MIDL_itf_sqlncli_0000_0002 */ +/* [local] */ + + +// the structure returned by ISQLServerErrorInfo::GetSQLServerInfo +typedef struct tagSSErrorInfo + { + LPOLESTR pwszMessage; + LPOLESTR pwszServer; + LPOLESTR pwszProcedure; + LONG lNative; + BYTE bState; + BYTE bClass; + WORD wLineNumber; + } SSERRORINFO; + + + +extern RPC_IF_HANDLE __MIDL_itf_sqlncli_0000_0002_v0_0_c_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_sqlncli_0000_0002_v0_0_s_ifspec; + +#ifndef __ISQLServerErrorInfo_INTERFACE_DEFINED__ +#define __ISQLServerErrorInfo_INTERFACE_DEFINED__ + +/* interface ISQLServerErrorInfo */ +/* [unique][uuid][object][local] */ + + +EXTERN_C const IID IID_ISQLServerErrorInfo; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("5CF4CA12-EF21-11d0-97E7-00C04FC2AD98") + ISQLServerErrorInfo : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetErrorInfo( + /* [out] */ SSERRORINFO **ppErrorInfo, + /* [out] */ OLECHAR **ppStringsBuffer) = 0; + + }; + +#else /* C style interface */ + + typedef struct ISQLServerErrorInfoVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ISQLServerErrorInfo * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ISQLServerErrorInfo * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ISQLServerErrorInfo * This); + + HRESULT ( STDMETHODCALLTYPE *GetErrorInfo )( + ISQLServerErrorInfo * This, + /* [out] */ SSERRORINFO **ppErrorInfo, + /* [out] */ OLECHAR **ppStringsBuffer); + + END_INTERFACE + } ISQLServerErrorInfoVtbl; + + interface ISQLServerErrorInfo + { + CONST_VTBL struct ISQLServerErrorInfoVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ISQLServerErrorInfo_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ISQLServerErrorInfo_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ISQLServerErrorInfo_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ISQLServerErrorInfo_GetErrorInfo(This,ppErrorInfo,ppStringsBuffer) \ + ( (This)->lpVtbl -> GetErrorInfo(This,ppErrorInfo,ppStringsBuffer) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ISQLServerErrorInfo_INTERFACE_DEFINED__ */ + + +#ifndef __IRowsetFastLoad_INTERFACE_DEFINED__ +#define __IRowsetFastLoad_INTERFACE_DEFINED__ + +/* interface IRowsetFastLoad */ +/* [unique][uuid][object][local] */ + + +EXTERN_C const IID IID_IRowsetFastLoad; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("5CF4CA13-EF21-11d0-97E7-00C04FC2AD98") + IRowsetFastLoad : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE InsertRow( + /* [in] */ HACCESSOR hAccessor, + /* [in] */ void *pData) = 0; + + virtual HRESULT STDMETHODCALLTYPE Commit( + /* [in] */ BOOL fDone) = 0; + + }; + +#else /* C style interface */ + + typedef struct IRowsetFastLoadVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IRowsetFastLoad * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IRowsetFastLoad * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IRowsetFastLoad * This); + + HRESULT ( STDMETHODCALLTYPE *InsertRow )( + IRowsetFastLoad * This, + /* [in] */ HACCESSOR hAccessor, + /* [in] */ void *pData); + + HRESULT ( STDMETHODCALLTYPE *Commit )( + IRowsetFastLoad * This, + /* [in] */ BOOL fDone); + + END_INTERFACE + } IRowsetFastLoadVtbl; + + interface IRowsetFastLoad + { + CONST_VTBL struct IRowsetFastLoadVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IRowsetFastLoad_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IRowsetFastLoad_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IRowsetFastLoad_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IRowsetFastLoad_InsertRow(This,hAccessor,pData) \ + ( (This)->lpVtbl -> InsertRow(This,hAccessor,pData) ) + +#define IRowsetFastLoad_Commit(This,fDone) \ + ( (This)->lpVtbl -> Commit(This,fDone) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IRowsetFastLoad_INTERFACE_DEFINED__ */ + + +/* interface __MIDL_itf_sqlncli_0000_0004 */ +/* [local] */ + +#include // 8-byte structure packing + +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; + +#include // restore original structure packing + +struct SSVARIANT + { + SSVARTYPE vt; + DWORD dwReserved1; + DWORD dwReserved2; + union + { + BYTE bTinyIntVal; + SHORT sShortIntVal; + LONG lIntVal; + LONGLONG llBigIntVal; + FLOAT fltRealVal; + DOUBLE dblFloatVal; + CY cyMoneyVal; + VARIANT_BOOL fBitVal; + BYTE rgbGuidVal[ 16 ]; + DB_NUMERIC numNumericVal; + DBDATE dDateVal; + DBTIMESTAMP tsDateTimeVal; + struct _Time2Val + { + DBTIME2 tTime2Val; + BYTE bScale; + } Time2Val; + struct _DateTimeVal + { + DBTIMESTAMP tsDateTimeVal; + BYTE bScale; + } DateTimeVal; + struct _DateTimeOffsetVal + { + DBTIMESTAMPOFFSET tsoDateTimeOffsetVal; + BYTE bScale; + } DateTimeOffsetVal; + struct _NCharVal + { + SHORT sActualLength; + SHORT sMaxLength; + WCHAR *pwchNCharVal; + BYTE rgbReserved[ 5 ]; + DWORD dwReserved; + WCHAR *pwchReserved; + } NCharVal; + struct _CharVal + { + SHORT sActualLength; + SHORT sMaxLength; + CHAR *pchCharVal; + BYTE rgbReserved[ 5 ]; + DWORD dwReserved; + WCHAR *pwchReserved; + } CharVal; + struct _BinaryVal + { + SHORT sActualLength; + SHORT sMaxLength; + BYTE *prgbBinaryVal; + DWORD dwReserved; + } BinaryVal; + struct _UnknownType + { + DWORD dwActualLength; + BYTE rgMetadata[ 16 ]; + BYTE *pUnknownData; + } UnknownType; + struct _BLOBType + { + DBOBJECT dbobj; + IUnknown *pUnk; + } BLOBType; + } ; + } ; +typedef DWORD LOCKMODE; + + +enum LOCKMODEENUM + { LOCKMODE_INVALID = 0, + LOCKMODE_EXCLUSIVE = ( LOCKMODE_INVALID + 1 ) , + LOCKMODE_SHARED = ( LOCKMODE_EXCLUSIVE + 1 ) + } ; + + +extern RPC_IF_HANDLE __MIDL_itf_sqlncli_0000_0004_v0_0_c_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_sqlncli_0000_0004_v0_0_s_ifspec; + +#ifndef __ISchemaLock_INTERFACE_DEFINED__ +#define __ISchemaLock_INTERFACE_DEFINED__ + +/* interface ISchemaLock */ +/* [unique][uuid][object][local] */ + + +EXTERN_C const IID IID_ISchemaLock; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("4C2389FB-2511-11d4-B258-00C04F7971CE") + ISchemaLock : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetSchemaLock( + /* [in] */ DBID *pTableID, + /* [in] */ LOCKMODE lmMode, + /* [out] */ HANDLE *phLockHandle, + /* [out] */ ULONGLONG *pTableVersion) = 0; + + virtual HRESULT STDMETHODCALLTYPE ReleaseSchemaLock( + /* [in] */ HANDLE hLockHandle) = 0; + + }; + +#else /* C style interface */ + + typedef struct ISchemaLockVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ISchemaLock * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ISchemaLock * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ISchemaLock * This); + + HRESULT ( STDMETHODCALLTYPE *GetSchemaLock )( + ISchemaLock * This, + /* [in] */ DBID *pTableID, + /* [in] */ LOCKMODE lmMode, + /* [out] */ HANDLE *phLockHandle, + /* [out] */ ULONGLONG *pTableVersion); + + HRESULT ( STDMETHODCALLTYPE *ReleaseSchemaLock )( + ISchemaLock * This, + /* [in] */ HANDLE hLockHandle); + + END_INTERFACE + } ISchemaLockVtbl; + + interface ISchemaLock + { + CONST_VTBL struct ISchemaLockVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ISchemaLock_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ISchemaLock_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ISchemaLock_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ISchemaLock_GetSchemaLock(This,pTableID,lmMode,phLockHandle,pTableVersion) \ + ( (This)->lpVtbl -> GetSchemaLock(This,pTableID,lmMode,phLockHandle,pTableVersion) ) + +#define ISchemaLock_ReleaseSchemaLock(This,hLockHandle) \ + ( (This)->lpVtbl -> ReleaseSchemaLock(This,hLockHandle) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ISchemaLock_INTERFACE_DEFINED__ */ + + +#ifndef __IBCPSession_INTERFACE_DEFINED__ +#define __IBCPSession_INTERFACE_DEFINED__ + +/* interface IBCPSession */ +/* [unique][uuid][object][local] */ + + +EXTERN_C const IID IID_IBCPSession; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("88352D80-42D1-42f0-A170-AB0F8B45B939") + IBCPSession : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE BCPColFmt( + /* [in] */ DBORDINAL idxUserDataCol, + /* [in] */ int eUserDataType, + /* [in] */ int cbIndicator, + /* [in] */ int cbUserData, + /* [size_is][in] */ BYTE *pbUserDataTerm, + /* [in] */ int cbUserDataTerm, + /* [in] */ DBORDINAL idxServerCol) = 0; + + virtual HRESULT STDMETHODCALLTYPE BCPColumns( + /* [in] */ DBCOUNTITEM nColumns) = 0; + + virtual HRESULT STDMETHODCALLTYPE BCPControl( + /* [in] */ int eOption, + /* [in] */ void *iValue) = 0; + + virtual HRESULT STDMETHODCALLTYPE BCPDone( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE BCPExec( + /* [out] */ DBROWCOUNT *pRowsCopied) = 0; + + virtual HRESULT STDMETHODCALLTYPE BCPInit( + /* [string][in] */ const wchar_t *pwszTable, + /* [string][in] */ const wchar_t *pwszDataFile, + /* [string][in] */ const wchar_t *pwszErrorFile, + /* [in] */ int eDirection) = 0; + + virtual HRESULT STDMETHODCALLTYPE BCPReadFmt( + /* [string][in] */ const wchar_t *pwszFormatFile) = 0; + + virtual HRESULT STDMETHODCALLTYPE BCPWriteFmt( + /* [string][in] */ const wchar_t *pwszFormatFile) = 0; + + }; + +#else /* C style interface */ + + typedef struct IBCPSessionVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IBCPSession * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IBCPSession * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IBCPSession * This); + + HRESULT ( STDMETHODCALLTYPE *BCPColFmt )( + IBCPSession * This, + /* [in] */ DBORDINAL idxUserDataCol, + /* [in] */ int eUserDataType, + /* [in] */ int cbIndicator, + /* [in] */ int cbUserData, + /* [size_is][in] */ BYTE *pbUserDataTerm, + /* [in] */ int cbUserDataTerm, + /* [in] */ DBORDINAL idxServerCol); + + HRESULT ( STDMETHODCALLTYPE *BCPColumns )( + IBCPSession * This, + /* [in] */ DBCOUNTITEM nColumns); + + HRESULT ( STDMETHODCALLTYPE *BCPControl )( + IBCPSession * This, + /* [in] */ int eOption, + /* [in] */ void *iValue); + + HRESULT ( STDMETHODCALLTYPE *BCPDone )( + IBCPSession * This); + + HRESULT ( STDMETHODCALLTYPE *BCPExec )( + IBCPSession * This, + /* [out] */ DBROWCOUNT *pRowsCopied); + + HRESULT ( STDMETHODCALLTYPE *BCPInit )( + IBCPSession * This, + /* [string][in] */ const wchar_t *pwszTable, + /* [string][in] */ const wchar_t *pwszDataFile, + /* [string][in] */ const wchar_t *pwszErrorFile, + /* [in] */ int eDirection); + + HRESULT ( STDMETHODCALLTYPE *BCPReadFmt )( + IBCPSession * This, + /* [string][in] */ const wchar_t *pwszFormatFile); + + HRESULT ( STDMETHODCALLTYPE *BCPWriteFmt )( + IBCPSession * This, + /* [string][in] */ const wchar_t *pwszFormatFile); + + END_INTERFACE + } IBCPSessionVtbl; + + interface IBCPSession + { + CONST_VTBL struct IBCPSessionVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IBCPSession_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IBCPSession_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IBCPSession_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IBCPSession_BCPColFmt(This,idxUserDataCol,eUserDataType,cbIndicator,cbUserData,pbUserDataTerm,cbUserDataTerm,idxServerCol) \ + ( (This)->lpVtbl -> BCPColFmt(This,idxUserDataCol,eUserDataType,cbIndicator,cbUserData,pbUserDataTerm,cbUserDataTerm,idxServerCol) ) + +#define IBCPSession_BCPColumns(This,nColumns) \ + ( (This)->lpVtbl -> BCPColumns(This,nColumns) ) + +#define IBCPSession_BCPControl(This,eOption,iValue) \ + ( (This)->lpVtbl -> BCPControl(This,eOption,iValue) ) + +#define IBCPSession_BCPDone(This) \ + ( (This)->lpVtbl -> BCPDone(This) ) + +#define IBCPSession_BCPExec(This,pRowsCopied) \ + ( (This)->lpVtbl -> BCPExec(This,pRowsCopied) ) + +#define IBCPSession_BCPInit(This,pwszTable,pwszDataFile,pwszErrorFile,eDirection) \ + ( (This)->lpVtbl -> BCPInit(This,pwszTable,pwszDataFile,pwszErrorFile,eDirection) ) + +#define IBCPSession_BCPReadFmt(This,pwszFormatFile) \ + ( (This)->lpVtbl -> BCPReadFmt(This,pwszFormatFile) ) + +#define IBCPSession_BCPWriteFmt(This,pwszFormatFile) \ + ( (This)->lpVtbl -> BCPWriteFmt(This,pwszFormatFile) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IBCPSession_INTERFACE_DEFINED__ */ + + +/* interface __MIDL_itf_sqlncli_0000_0006 */ +/* [local] */ + + +#endif //_SQLOLEDB_H_ + +#define ISOLATIONLEVEL_SNAPSHOT ((ISOLATIONLEVEL)(0x01000000)) // Changes made in other transactions can not be seen. + +#define DBPROPVAL_TI_SNAPSHOT 0x01000000L + + + +extern RPC_IF_HANDLE __MIDL_itf_sqlncli_0000_0006_v0_0_c_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_sqlncli_0000_0006_v0_0_s_ifspec; + +#ifndef __ISSAbort_INTERFACE_DEFINED__ +#define __ISSAbort_INTERFACE_DEFINED__ + +/* interface ISSAbort */ +/* [unique][uuid][object][local] */ + + +EXTERN_C const IID IID_ISSAbort; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("5CF4CA15-EF21-11d0-97E7-00C04FC2AD98") + ISSAbort : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Abort( void) = 0; + + }; + +#else /* C style interface */ + + typedef struct ISSAbortVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ISSAbort * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ISSAbort * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ISSAbort * This); + + HRESULT ( STDMETHODCALLTYPE *Abort )( + ISSAbort * This); + + END_INTERFACE + } ISSAbortVtbl; + + interface ISSAbort + { + CONST_VTBL struct ISSAbortVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ISSAbort_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ISSAbort_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ISSAbort_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ISSAbort_Abort(This) \ + ( (This)->lpVtbl -> Abort(This) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ISSAbort_INTERFACE_DEFINED__ */ + + +/* interface __MIDL_itf_sqlncli_0000_0007 */ +/* [local] */ + + +enum DBBINDFLAGENUM90 + { DBBINDFLAG_OBJECT = 0x2 + } ; + +enum SSACCESSORFLAGS + { SSACCESSOR_ROWDATA = 0x100 + } ; + +enum DBPROPFLAGSENUM90 + { DBPROPFLAGS_PARAMETER = 0x10000 + } ; +typedef struct tagSSPARAMPROPS + { + DBORDINAL iOrdinal; + ULONG cPropertySets; + DBPROPSET *rgPropertySets; + } SSPARAMPROPS; + + + +extern RPC_IF_HANDLE __MIDL_itf_sqlncli_0000_0007_v0_0_c_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_sqlncli_0000_0007_v0_0_s_ifspec; + +#ifndef __ISSCommandWithParameters_INTERFACE_DEFINED__ +#define __ISSCommandWithParameters_INTERFACE_DEFINED__ + +/* interface ISSCommandWithParameters */ +/* [unique][uuid][object][local] */ + + +EXTERN_C const IID IID_ISSCommandWithParameters; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("eec30162-6087-467c-b995-7c523ce96561") + ISSCommandWithParameters : public ICommandWithParameters + { + public: + virtual /* [local] */ HRESULT STDMETHODCALLTYPE GetParameterProperties( + /* [out][in] */ DB_UPARAMS *pcParams, + /* [size_is][size_is][out] */ SSPARAMPROPS **prgParamProperties) = 0; + + virtual /* [local] */ HRESULT STDMETHODCALLTYPE SetParameterProperties( + /* [in] */ DB_UPARAMS cParams, + /* [size_is][unique][in] */ SSPARAMPROPS rgParamProperties[ ]) = 0; + + }; + +#else /* C style interface */ + + typedef struct ISSCommandWithParametersVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ISSCommandWithParameters * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ISSCommandWithParameters * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ISSCommandWithParameters * This); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *GetParameterInfo )( + ISSCommandWithParameters * This, + /* [out][in] */ DB_UPARAMS *pcParams, + /* [size_is][size_is][out] */ DBPARAMINFO **prgParamInfo, + /* [out] */ OLECHAR **ppNamesBuffer); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *MapParameterNames )( + ISSCommandWithParameters * This, + /* [in] */ DB_UPARAMS cParamNames, + /* [size_is][in] */ const OLECHAR *rgParamNames[ ], + /* [size_is][out] */ DB_LPARAMS rgParamOrdinals[ ]); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *SetParameterInfo )( + ISSCommandWithParameters * This, + /* [in] */ DB_UPARAMS cParams, + /* [size_is][unique][in] */ const DB_UPARAMS rgParamOrdinals[ ], + /* [size_is][unique][in] */ const DBPARAMBINDINFO rgParamBindInfo[ ]); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *GetParameterProperties )( + ISSCommandWithParameters * This, + /* [out][in] */ DB_UPARAMS *pcParams, + /* [size_is][size_is][out] */ SSPARAMPROPS **prgParamProperties); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *SetParameterProperties )( + ISSCommandWithParameters * This, + /* [in] */ DB_UPARAMS cParams, + /* [size_is][unique][in] */ SSPARAMPROPS rgParamProperties[ ]); + + END_INTERFACE + } ISSCommandWithParametersVtbl; + + interface ISSCommandWithParameters + { + CONST_VTBL struct ISSCommandWithParametersVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ISSCommandWithParameters_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ISSCommandWithParameters_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ISSCommandWithParameters_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ISSCommandWithParameters_GetParameterInfo(This,pcParams,prgParamInfo,ppNamesBuffer) \ + ( (This)->lpVtbl -> GetParameterInfo(This,pcParams,prgParamInfo,ppNamesBuffer) ) + +#define ISSCommandWithParameters_MapParameterNames(This,cParamNames,rgParamNames,rgParamOrdinals) \ + ( (This)->lpVtbl -> MapParameterNames(This,cParamNames,rgParamNames,rgParamOrdinals) ) + +#define ISSCommandWithParameters_SetParameterInfo(This,cParams,rgParamOrdinals,rgParamBindInfo) \ + ( (This)->lpVtbl -> SetParameterInfo(This,cParams,rgParamOrdinals,rgParamBindInfo) ) + + +#define ISSCommandWithParameters_GetParameterProperties(This,pcParams,prgParamProperties) \ + ( (This)->lpVtbl -> GetParameterProperties(This,pcParams,prgParamProperties) ) + +#define ISSCommandWithParameters_SetParameterProperties(This,cParams,rgParamProperties) \ + ( (This)->lpVtbl -> SetParameterProperties(This,cParams,rgParamProperties) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ISSCommandWithParameters_INTERFACE_DEFINED__ */ + + +#ifndef __IDBAsynchStatus_INTERFACE_DEFINED__ +#define __IDBAsynchStatus_INTERFACE_DEFINED__ + +/* interface IDBAsynchStatus */ +/* [unique][uuid][object][local] */ + + +EXTERN_C const IID IID_IDBAsynchStatus; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("0c733a95-2a1c-11ce-ade5-00aa0044773d") + IDBAsynchStatus : public IUnknown + { + public: + virtual /* [local] */ HRESULT STDMETHODCALLTYPE Abort( + /* [in] */ HCHAPTER hChapter, + /* [in] */ DBASYNCHOP eOperation) = 0; + + virtual /* [local] */ HRESULT STDMETHODCALLTYPE GetStatus( + /* [in] */ HCHAPTER hChapter, + /* [in] */ DBASYNCHOP eOperation, + /* [out] */ DBCOUNTITEM *pulProgress, + /* [out] */ DBCOUNTITEM *pulProgressMax, + /* [out] */ DBASYNCHPHASE *peAsynchPhase, + /* [out] */ LPOLESTR *ppwszStatusText) = 0; + + }; + +#else /* C style interface */ + + typedef struct IDBAsynchStatusVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDBAsynchStatus * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDBAsynchStatus * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDBAsynchStatus * This); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *Abort )( + IDBAsynchStatus * This, + /* [in] */ HCHAPTER hChapter, + /* [in] */ DBASYNCHOP eOperation); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *GetStatus )( + IDBAsynchStatus * This, + /* [in] */ HCHAPTER hChapter, + /* [in] */ DBASYNCHOP eOperation, + /* [out] */ DBCOUNTITEM *pulProgress, + /* [out] */ DBCOUNTITEM *pulProgressMax, + /* [out] */ DBASYNCHPHASE *peAsynchPhase, + /* [out] */ LPOLESTR *ppwszStatusText); + + END_INTERFACE + } IDBAsynchStatusVtbl; + + interface IDBAsynchStatus + { + CONST_VTBL struct IDBAsynchStatusVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDBAsynchStatus_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDBAsynchStatus_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDBAsynchStatus_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDBAsynchStatus_Abort(This,hChapter,eOperation) \ + ( (This)->lpVtbl -> Abort(This,hChapter,eOperation) ) + +#define IDBAsynchStatus_GetStatus(This,hChapter,eOperation,pulProgress,pulProgressMax,peAsynchPhase,ppwszStatusText) \ + ( (This)->lpVtbl -> GetStatus(This,hChapter,eOperation,pulProgress,pulProgressMax,peAsynchPhase,ppwszStatusText) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE IDBAsynchStatus_RemoteAbort_Proxy( + IDBAsynchStatus * This, + /* [in] */ HCHAPTER hChapter, + /* [in] */ DBASYNCHOP eOperation, + /* [out] */ IErrorInfo **ppErrorInfoRem); + + +void __RPC_STUB IDBAsynchStatus_RemoteAbort_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase); + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE IDBAsynchStatus_RemoteGetStatus_Proxy( + IDBAsynchStatus * This, + /* [in] */ HCHAPTER hChapter, + /* [in] */ DBASYNCHOP eOperation, + /* [unique][out][in] */ DBCOUNTITEM *pulProgress, + /* [unique][out][in] */ DBCOUNTITEM *pulProgressMax, + /* [unique][out][in] */ DBASYNCHPHASE *peAsynchPhase, + /* [unique][out][in] */ LPOLESTR *ppwszStatusText, + /* [out] */ IErrorInfo **ppErrorInfoRem); + + +void __RPC_STUB IDBAsynchStatus_RemoteGetStatus_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase); + + + +#endif /* __IDBAsynchStatus_INTERFACE_DEFINED__ */ + + +#ifndef __ISSAsynchStatus_INTERFACE_DEFINED__ +#define __ISSAsynchStatus_INTERFACE_DEFINED__ + +/* interface ISSAsynchStatus */ +/* [unique][uuid][object][local] */ + + +EXTERN_C const IID IID_ISSAsynchStatus; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("1FF1F743-8BB0-4c00-ACC4-C10E43B08FC1") + ISSAsynchStatus : public IDBAsynchStatus + { + public: + virtual /* [local] */ HRESULT STDMETHODCALLTYPE WaitForAsynchCompletion( + /* [in] */ DWORD dwMillisecTimeOut) = 0; + + }; + +#else /* C style interface */ + + typedef struct ISSAsynchStatusVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ISSAsynchStatus * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ISSAsynchStatus * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ISSAsynchStatus * This); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *Abort )( + ISSAsynchStatus * This, + /* [in] */ HCHAPTER hChapter, + /* [in] */ DBASYNCHOP eOperation); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *GetStatus )( + ISSAsynchStatus * This, + /* [in] */ HCHAPTER hChapter, + /* [in] */ DBASYNCHOP eOperation, + /* [out] */ DBCOUNTITEM *pulProgress, + /* [out] */ DBCOUNTITEM *pulProgressMax, + /* [out] */ DBASYNCHPHASE *peAsynchPhase, + /* [out] */ LPOLESTR *ppwszStatusText); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *WaitForAsynchCompletion )( + ISSAsynchStatus * This, + /* [in] */ DWORD dwMillisecTimeOut); + + END_INTERFACE + } ISSAsynchStatusVtbl; + + interface ISSAsynchStatus + { + CONST_VTBL struct ISSAsynchStatusVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ISSAsynchStatus_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ISSAsynchStatus_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ISSAsynchStatus_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ISSAsynchStatus_Abort(This,hChapter,eOperation) \ + ( (This)->lpVtbl -> Abort(This,hChapter,eOperation) ) + +#define ISSAsynchStatus_GetStatus(This,hChapter,eOperation,pulProgress,pulProgressMax,peAsynchPhase,ppwszStatusText) \ + ( (This)->lpVtbl -> GetStatus(This,hChapter,eOperation,pulProgress,pulProgressMax,peAsynchPhase,ppwszStatusText) ) + + +#define ISSAsynchStatus_WaitForAsynchCompletion(This,dwMillisecTimeOut) \ + ( (This)->lpVtbl -> WaitForAsynchCompletion(This,dwMillisecTimeOut) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ISSAsynchStatus_INTERFACE_DEFINED__ */ + + +/* interface __MIDL_itf_sqlncli_0000_0010 */ +/* [local] */ + +//---------------------------------------------------------------------------- +// Values for STATUS bitmask for DBSCHEMA_TABLES & DBSCHEMA_TABLES_INFO +#define TABLE_HAS_UPDATE_INSTEAD_OF_TRIGGER 0x00000001 //table has IOT defined +#define TABLE_HAS_DELETE_INSTEAD_OF_TRIGGER 0x00000002 //table has IOT defined +#define TABLE_HAS_INSERT_INSTEAD_OF_TRIGGER 0x00000004 //table has IOT defined +#define TABLE_HAS_AFTER_UPDATE_TRIGGER 0x00000008 //table has update trigger +#define TABLE_HAS_AFTER_DELETE_TRIGGER 0x00000010 //table has delete trigger +#define TABLE_HAS_AFTER_INSERT_TRIGGER 0x00000020 //table has insert trigger +#define TABLE_HAS_CASCADE_UPDATE 0x00000040 //table has cascade update +#define TABLE_HAS_CASCADE_DELETE 0x00000080 //table has cascade delete + +//---------------------------------------------------------------------------- +// PropIds for DBPROP_INIT_GENERALTIMEOUT +#if (OLEDBVER >= 0x0210) +#define DBPROP_INIT_GENERALTIMEOUT 0x11cL +#endif + +//---------------------------------------------------------------------------- +// PropIds for DBPROPSET_SQLSERVERDATASOURCE +#define SSPROP_ENABLEFASTLOAD 2 +#define SSPROP_ENABLEBULKCOPY 3 + +//---------------------------------------------------------------------------- +// PropIds for DBPROPSET_SQLSERVERDATASOURCEINFO +#define SSPROP_UNICODELCID 2 +#define SSPROP_UNICODECOMPARISONSTYLE 3 +#define SSPROP_COLUMNLEVELCOLLATION 4 +#define SSPROP_CHARACTERSET 5 +#define SSPROP_SORTORDER 6 +#define SSPROP_CURRENTCOLLATION 7 +#define SSPROP_INTEGRATEDAUTHENTICATIONMETHOD 8 +#define SSPROP_MUTUALLYAUTHENTICATED 9 + +//---------------------------------------------------------------------------- +// PropIds for DBPROPSET_SQLSERVERDBINIT +#define SSPROP_INIT_CURRENTLANGUAGE 4 +#define SSPROP_INIT_NETWORKADDRESS 5 +#define SSPROP_INIT_NETWORKLIBRARY 6 +#define SSPROP_INIT_USEPROCFORPREP 7 +#define SSPROP_INIT_AUTOTRANSLATE 8 +#define SSPROP_INIT_PACKETSIZE 9 +#define SSPROP_INIT_APPNAME 10 +#define SSPROP_INIT_WSID 11 +#define SSPROP_INIT_FILENAME 12 +#define SSPROP_INIT_ENCRYPT 13 +#define SSPROP_AUTH_REPL_SERVER_NAME 14 +#define SSPROP_INIT_TAGCOLUMNCOLLATION 15 +#define SSPROP_INIT_MARSCONNECTION 16 +#define SSPROP_INIT_FAILOVERPARTNER 18 +#define SSPROP_AUTH_OLD_PASSWORD 19 +#define SSPROP_INIT_DATATYPECOMPATIBILITY 20 +#define SSPROP_INIT_TRUST_SERVER_CERTIFICATE 21 +#define SSPROP_INIT_SERVERSPN 22 +#define SSPROP_INIT_FAILOVERPARTNERSPN 23 + +//----------------------------------------------------------------------------- +// Values for SSPROP_INIT_USEPROCFORPREP +#define SSPROPVAL_USEPROCFORPREP_OFF 0 +#define SSPROPVAL_USEPROCFORPREP_ON 1 +#define SSPROPVAL_USEPROCFORPREP_ON_DROP 2 + +//----------------------------------------------------------------------------- +// Values for SSPROP_INIT_DATATYPECOMPATIBILITY +#define SSPROPVAL_DATATYPECOMPATIBILITY_SQL2000 80 +#define SSPROPVAL_DATATYPECOMPATIBILITY_DEFAULT 0 + +//---------------------------------------------------------------------------- +// PropIds for DBPROPSET_SQLSERVERSESSION +#define SSPROP_QUOTEDCATALOGNAMES 2 +#define SSPROP_ALLOWNATIVEVARIANT 3 +#define SSPROP_SQLXMLXPROGID 4 +#define SSPROP_ASYNCH_BULKCOPY 5 + +//---------------------------------------------------------------------------- +// PropIds for DBPROPSET_SQLSERVERROWSET +#define SSPROP_MAXBLOBLENGTH 8 +#define SSPROP_FASTLOADOPTIONS 9 +#define SSPROP_FASTLOADKEEPNULLS 10 +#define SSPROP_FASTLOADKEEPIDENTITY 11 +#define SSPROP_CURSORAUTOFETCH 12 +#define SSPROP_DEFERPREPARE 13 +#define SSPROP_IRowsetFastLoad 14 +#define SSPROP_QP_NOTIFICATION_TIMEOUT 17 +#define SSPROP_QP_NOTIFICATION_MSGTEXT 18 +#define SSPROP_QP_NOTIFICATION_OPTIONS 19 +#define SSPROP_NOCOUNT_STATUS 20 +#define SSPROP_COMPUTE_ID 21 +#define SSPROP_COLUMN_ID 22 +#define SSPROP_COMPUTE_BYLIST 23 +#define SSPROP_ISSAsynchStatus 24 + +//----------------------------------------------------------------------------- +// Values for SSPROP_QP_NOTIFICATION_TIMEOUT +#define SSPROPVAL_DEFAULT_NOTIFICATION_TIMEOUT 432000 /* in sec */ +#define SSPROPVAL_MAX_NOTIFICATION_TIMEOUT 0x7FFFFFFF /* in sec */ +#define MAX_NOTIFICATION_LEN 2000 /* NVARCHAR [2000] for both ID & DELIVERY_QUEUE */ + +//---------------------------------------------------------------------------- +// PropIds for DBPROPSET_SQLSERVERCOLUMN +#define SSPROP_COL_COLLATIONNAME 14 +#define SSPROP_COL_UDT_CATALOGNAME 31 +#define SSPROP_COL_UDT_SCHEMANAME 32 +#define SSPROP_COL_UDT_NAME 33 +#define SSPROP_COL_XML_SCHEMACOLLECTION_CATALOGNAME 34 +#define SSPROP_COL_XML_SCHEMACOLLECTION_SCHEMANAME 35 +#define SSPROP_COL_XML_SCHEMACOLLECTIONNAME 36 +#define SSPROP_COL_COMPUTED 37 + + +//---------------------------------------------------------------------------- +// PropIds for DBPROPSET_SQLSERVERSTREAM +#define SSPROP_STREAM_XMLROOT 19 + +//---------------------------------------------------------------------------- +// PropIds for DBPROPSET_SQLSERVERPARAMETER +#define SSPROP_PARAM_XML_SCHEMACOLLECTION_CATALOGNAME 24 +#define SSPROP_PARAM_XML_SCHEMACOLLECTION_SCHEMANAME 25 +#define SSPROP_PARAM_XML_SCHEMACOLLECTIONNAME 26 +#define SSPROP_PARAM_UDT_CATALOGNAME 27 +#define SSPROP_PARAM_UDT_SCHEMANAME 28 +#define SSPROP_PARAM_UDT_NAME 29 +#define SSPROP_PARAM_TYPE_CATALOGNAME 38 +#define SSPROP_PARAM_TYPE_SCHEMANAME 39 +#define SSPROP_PARAM_TYPE_TYPENAME 40 +#define SSPROP_PARAM_TABLE_DEFAULT_COLUMNS 41 +#define SSPROP_PARAM_TABLE_COLUMN_SORT_ORDER 42 + +//---------------------------------------------------------------------------- +// PropIds for DBPROPSET_SQLSERVERINDEX +#define SSPROP_INDEX_XML 1 + +//----------------------------------------------------------------------------- +// +#define BCP_TYPE_DEFAULT 0x00 +#define BCP_TYPE_SQLTEXT 0x23 +#define BCP_TYPE_SQLVARBINARY 0x25 +#define BCP_TYPE_SQLINTN 0x26 +#define BCP_TYPE_SQLVARCHAR 0x27 +#define BCP_TYPE_SQLBINARY 0x2d +#define BCP_TYPE_SQLIMAGE 0x22 +#define BCP_TYPE_SQLCHARACTER 0x2f +#define BCP_TYPE_SQLINT1 0x30 +#define BCP_TYPE_SQLBIT 0x32 +#define BCP_TYPE_SQLINT2 0x34 +#define BCP_TYPE_SQLINT4 0x38 +#define BCP_TYPE_SQLMONEY 0x3c +#define BCP_TYPE_SQLDATETIME 0x3d +#define BCP_TYPE_SQLFLT8 0x3e +#define BCP_TYPE_SQLFLTN 0x6d +#define BCP_TYPE_SQLMONEYN 0x6e +#define BCP_TYPE_SQLDATETIMN 0x6f +#define BCP_TYPE_SQLFLT4 0x3b +#define BCP_TYPE_SQLMONEY4 0x7a +#define BCP_TYPE_SQLDATETIM4 0x3a +#define BCP_TYPE_SQLDECIMAL 0x6a +#define BCP_TYPE_SQLNUMERIC 0x6c +#define BCP_TYPE_SQLUNIQUEID 0x24 +#define BCP_TYPE_SQLBIGCHAR 0xaf +#define BCP_TYPE_SQLBIGVARCHAR 0xa7 +#define BCP_TYPE_SQLBIGBINARY 0xad +#define BCP_TYPE_SQLBIGVARBINARY 0xa5 +#define BCP_TYPE_SQLBITN 0x68 +#define BCP_TYPE_SQLNCHAR 0xef +#define BCP_TYPE_SQLNVARCHAR 0xe7 +#define BCP_TYPE_SQLNTEXT 0x63 +#define BCP_TYPE_SQLDECIMALN 0x6a +#define BCP_TYPE_SQLNUMERICN 0x6c +#define BCP_TYPE_SQLINT8 0x7f +#define BCP_TYPE_SQLVARIANT 0x62 +#define BCP_TYPE_SQLUDT 0xf0 +#define BCP_TYPE_SQLXML 0xf1 +#define BCP_TYPE_SQLDATE 0x28 +#define BCP_TYPE_SQLTIME 0x29 +#define BCP_TYPE_SQLDATETIME2 0x2a +#define BCP_TYPE_SQLDATETIMEOFFSET 0x2b + +#define BCP_DIRECTION_IN 1 +#define BCP_DIRECTION_OUT 2 + +#define BCP_OPTION_MAXERRS 1 +#define BCP_OPTION_FIRST 2 +#define BCP_OPTION_LAST 3 +#define BCP_OPTION_BATCH 4 +#define BCP_OPTION_KEEPNULLS 5 +#define BCP_OPTION_ABORT 6 +#define BCP_OPTION_KEEPIDENTITY 8 +#define BCP_OPTION_HINTSA 10 +#define BCP_OPTION_HINTSW 11 +#define BCP_OPTION_FILECP 12 +#define BCP_OPTION_UNICODEFILE 13 +#define BCP_OPTION_TEXTFILE 14 +#define BCP_OPTION_FILEFMT 15 +#define BCP_OPTION_FMTXML 16 +#define BCP_OPTION_FIRSTEX 17 +#define BCP_OPTION_LASTEX 18 +#define BCP_OPTION_ROWCOUNT 19 + +#define BCP_FILECP_ACP 0 +#define BCP_FILECP_OEMCP 1 +#define BCP_FILECP_RAW (-1) + +#ifdef UNICODE +#define BCP_OPTION_HINTS BCP_OPTION_HINTSW +#else +#define BCP_OPTION_HINTS BCP_OPTION_HINTSA +#endif + +#define BCP_PREFIX_DEFAULT (-10) + +#define BCP_LENGTH_NULL (-1) +#define BCP_LENGTH_VARIABLE (-10) +// +//----------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +// Provider-specific Class Ids +// + +#if SQLNCLI_VER >= 1000 + +extern const GUID OLEDBDECLSPEC CLSID_SQLNCLI10 = {0x8F4A6B68L,0x4F36,0x4e3c,{0xBE,0x81,0xBC,0x7C,0xA4,0xE9,0xC4,0x5C}}; +extern const GUID OLEDBDECLSPEC CLSID_SQLNCLI10_ERROR = {0x53F9C3BCL,0x275F,0x4FA5,{0xB3,0xE6,0x25,0xED,0xCD,0x51,0x20,0x23}}; +extern const GUID OLEDBDECLSPEC CLSID_SQLNCLI10_ENUMERATOR = {0x91E4F2A5L,0x1B07,0x45f6,{0x86,0xBF,0x92,0x03,0xC7,0xC7,0x2B,0xE3}}; + +#endif + +extern const GUID OLEDBDECLSPEC CLSID_SQLNCLI = {0x85ecafccL,0xbdd9,0x4b03,{0x97,0xa8,0xfa,0x65,0xcb,0xe3,0x85,0x9b}}; +extern const GUID OLEDBDECLSPEC CLSID_SQLNCLI_ERROR = {0xe8bc0a7aL,0xea71,0x4263,{0x8c,0xda,0x94,0xf3,0x88,0xb8,0xed,0x10}}; +extern const GUID OLEDBDECLSPEC CLSID_SQLNCLI_ENUMERATOR = {0x4898ad37L,0xfe05,0x42df,{0x92,0xf9,0xe8,0x57,0xdd,0xfe,0xe7,0x30}}; +extern const GUID OLEDBDECLSPEC CLSID_ROWSET_TVP = {0xc7ef28d5L,0x7bee,0x443f,{0x86,0xda,0xe3,0x98,0x4f,0xcd,0x4d,0xf9}}; + +//---------------------------------------------------------------------------- +// Provider-specific Interface Ids +// +#ifndef _SQLOLEDB_H_ +extern const GUID OLEDBDECLSPEC IID_ISQLServerErrorInfo = {0x5cf4ca12,0xef21,0x11d0,{0x97,0xe7,0x0,0xc0,0x4f,0xc2,0xad,0x98}}; +extern const GUID OLEDBDECLSPEC IID_IRowsetFastLoad = {0x5cf4ca13,0xef21,0x11d0,{0x97,0xe7,0x0,0xc0,0x4f,0xc2,0xad,0x98}}; +extern const GUID OLEDBDECLSPEC IID_IUMSInitialize = {0x5cf4ca14,0xef21,0x11d0,{0x97,0xe7,0x0,0xc0,0x4f,0xc2,0xad,0x98}}; +extern const GUID OLEDBDECLSPEC IID_ISchemaLock = {0x4c2389fb,0x2511,0x11d4,{0xb2,0x58,0x0,0xc0,0x4f,0x79,0x71,0xce}}; +extern const GUID OLEDBDECLSPEC IID_ISQLXMLHelper = {0xd22a7678L,0xf860,0x40cd,{0xa5,0x67,0x15,0x63,0xde,0xb4,0x6d,0x49}}; +#endif //_SQLOLEDB_H_ +extern const GUID OLEDBDECLSPEC IID_ISSAbort = {0x5cf4ca15,0xef21,0x11d0,{0x97,0xe7,0x0,0xc0,0x4f,0xc2,0xad,0x98}}; +extern const GUID OLEDBDECLSPEC IID_IBCPSession = {0x88352D80,0x42D1,0x42f0,{0xA1,0x70,0xAB,0x0F,0x8B,0x45,0xB9,0x39}}; +extern const GUID OLEDBDECLSPEC IID_ISSCommandWithParameters = {0xeec30162,0x6087,0x467c,{0xb9,0x95,0x7c,0x52,0x3c,0xe9,0x65,0x61}}; +extern const GUID OLEDBDECLSPEC IID_ISSAsynchStatus = {0x1FF1F743,0x8BB0, 0x4c00,{0xAC,0xC4,0xC1,0x0E,0x43,0xB0,0x8F,0xC1}}; + + +//---------------------------------------------------------------------------- +// Provider-specific schema rowsets +// +#ifndef _SQLOLEDB_H_ +extern const GUID OLEDBDECLSPEC DBSCHEMA_LINKEDSERVERS = {0x9093caf4,0x2eac,0x11d1,{0x98,0x9,0x0,0xc0,0x4f,0xc2,0xad,0x98}}; +#endif //_SQLOLEDB_H_ +extern const GUID OLEDBDECLSPEC DBSCHEMA_SQL_ASSEMBLIES = {0x7c1112c8, 0xc2d3, 0x4f6e, {0x94, 0x9a, 0x98, 0x3d, 0x38, 0xa5, 0x8f, 0x46}}; +extern const GUID OLEDBDECLSPEC DBSCHEMA_SQL_ASSEMBLY_DEPENDENCIES = {0xcb0f837b, 0x974c, 0x41b8, {0x90, 0x9d, 0x64, 0x9c, 0xaf, 0x45, 0xad, 0x2f}}; +extern const GUID OLEDBDECLSPEC DBSCHEMA_SQL_USER_TYPES = {0xf1198bd8, 0xa424, 0x4ea3, {0x8d, 0x4c, 0x60, 0x7e, 0xee, 0x2b, 0xab, 0x60}}; +extern const GUID OLEDBDECLSPEC DBSCHEMA_XML_COLLECTIONS = {0x56bfad8c, 0x6e8f, 0x480d, {0x91, 0xde, 0x35, 0x16, 0xd9, 0x9a, 0x5d, 0x10}}; +extern const GUID OLEDBDECLSPEC DBSCHEMA_SQL_TABLE_TYPES = {0x4e26cde7, 0xaaa4, 0x41ed, {0x93, 0xdd, 0x37, 0x6e, 0x6d, 0x40, 0x9c, 0x17}}; +extern const GUID OLEDBDECLSPEC DBSCHEMA_SQL_TABLE_TYPE_PRIMARY_KEYS = {0x9738faea, 0x31e8, 0x4f63, {0xae, 0xd, 0x61, 0x33, 0x16, 0x41, 0x8c, 0xdd}}; +extern const GUID OLEDBDECLSPEC DBSCHEMA_SQL_TABLE_TYPE_COLUMNS = {0xa663d94b, 0xddf7, 0x4a7f, {0xa5, 0x37, 0xd6, 0x1f, 0x12, 0x36, 0x5d, 0x7c}}; +extern const GUID OLEDBDECLSPEC DBSCHEMA_COLUMNS_EXTENDED = {0x66462f01, 0x633a, 0x44d9, {0xb0, 0xd0, 0xfe, 0x66, 0xf2, 0x1a, 0x0d, 0x24}}; +extern const GUID OLEDBDECLSPEC DBSCHEMA_SPARSE_COLUMN_SET = {0x31a4837c, 0xf9ff, 0x405f, {0x89, 0x82, 0x02, 0x19, 0xaa, 0xaa, 0x4a, 0x12}}; + + +#ifndef CRESTRICTIONS_DBSCHEMA_LINKEDSERVERS +#define CRESTRICTIONS_DBSCHEMA_LINKEDSERVERS 1 +#endif + +#ifndef CRESTRICTIONS_DBSCHEMA_ASSEMBLIES +#define CRESTRICTIONS_DBSCHEMA_SQL_ASSEMBLIES 4 +#endif + +#ifndef CRESTRICTIONS_DBSCHEMA_ASSEMBLY_DEPENDENCIES +#define CRESTRICTIONS_DBSCHEMA_SQL_ASSEMBLY_DEPENDENCIES 4 +#endif + +#ifndef CRESTRICTIONS_DBSCHEMA_USER_TYPES +#define CRESTRICTIONS_DBSCHEMA_SQL_USER_TYPES 3 +#endif + +#ifndef CRESTRICTIONS_DBSCHEMA_XML_COLLECTIONS +#define CRESTRICTIONS_DBSCHEMA_XML_COLLECTIONS 4 +#endif + +#ifndef CRESTRICTIONS_DBSCHEMA_SQL_TABLE_TYPES +#define CRESTRICTIONS_DBSCHEMA_SQL_TABLE_TYPES 3 +#endif + +#ifndef CRESTRICTIONS_DBSCHEMA_SQL_TABLE_TYPE_PRIMARY_KEYS +#define CRESTRICTIONS_DBSCHEMA_SQL_TABLE_TYPE_PRIMARY_KEYS 3 +#endif + +#ifndef CRESTRICTIONS_DBSCHEMA_SQL_TABLE_TYPE_COLUMNS +#define CRESTRICTIONS_DBSCHEMA_SQL_TABLE_TYPE_COLUMNS 4 +#endif + +#ifndef CRESTRICTIONS_DBSCHEMA_COLUMNS_EXTENDED +#define CRESTRICTIONS_DBSCHEMA_COLUMNS_EXTENDED 4 +#endif + +#ifndef CRESTRICTIONS_DBSCHEMA_SPARSE_COLUMN_SET +#define CRESTRICTIONS_DBSCHEMA_SPARSE_COLUMN_SET 4 +#endif + + +//---------------------------------------------------------------------------- +// Provider-specific property sets +// +#ifndef _SQLOLEDB_H_ +extern const GUID OLEDBDECLSPEC DBPROPSET_SQLSERVERDATASOURCE = {0x28efaee4,0x2d2c,0x11d1,{0x98,0x7,0x0,0xc0,0x4f,0xc2,0xad,0x98}}; +extern const GUID OLEDBDECLSPEC DBPROPSET_SQLSERVERDATASOURCEINFO= {0xdf10cb94,0x35f6,0x11d2,{0x9c,0x54,0x0,0xc0,0x4f,0x79,0x71,0xd3}}; +extern const GUID OLEDBDECLSPEC DBPROPSET_SQLSERVERDBINIT = {0x5cf4ca10,0xef21,0x11d0,{0x97,0xe7,0x0,0xc0,0x4f,0xc2,0xad,0x98}}; +extern const GUID OLEDBDECLSPEC DBPROPSET_SQLSERVERROWSET = {0x5cf4ca11,0xef21,0x11d0,{0x97,0xe7,0x0,0xc0,0x4f,0xc2,0xad,0x98}}; +extern const GUID OLEDBDECLSPEC DBPROPSET_SQLSERVERSESSION = {0x28efaee5,0x2d2c,0x11d1,{0x98,0x7,0x0,0xc0,0x4f,0xc2,0xad,0x98}}; +extern const GUID OLEDBDECLSPEC DBPROPSET_SQLSERVERCOLUMN = {0x3b63fb5e,0x3fbb,0x11d3,{0x9f,0x29,0x0,0xc0,0x4f,0x8e,0xe9,0xdc}}; +extern const GUID OLEDBDECLSPEC DBPROPSET_SQLSERVERSTREAM = {0x9f79c073,0x8a6d,0x4bca,{0xa8,0xa8,0xc9,0xb7,0x9a,0x9b,0x96,0x2d}}; +#endif //_SQLOLEDB_H_ +extern const GUID OLEDBDECLSPEC DBPROPSET_SQLSERVERPARAMETER = {0xfee09128,0xa67d,0x47ea,{0x8d,0x40,0x24,0xa1,0xd4,0x73,0x7e,0x8d}}; +extern const GUID OLEDBDECLSPEC DBPROPSET_SQLSERVERINDEX = {0xE428B84E,0xA6B7,0x413a,{0x94,0x65,0x56,0x23,0x2E,0x0D,0x2B,0xEB}}; +extern const GUID OLEDBDECLSPEC DBPROPSET_PARAMETERALL = {0x2cd2b7d8,0xe7c2,0x4f6c,{0x9b,0x30,0x75,0xe2,0x58,0x46,0x10,0x97}}; + + +//---------------------------------------------------------------------------- +// Provider-specific columns for IColumnsRowset +// +#define DBCOLUMN_SS_X_GUID {0x627bd890,0xed54,0x11d2,{0xb9,0x94,0x0,0xc0,0x4f,0x8c,0xa8,0x2c}} +// +#ifndef _SQLOLEDB_H_ +extern const DBID OLEDBDECLSPEC DBCOLUMN_SS_COMPFLAGS = {DBCOLUMN_SS_X_GUID, DBKIND_GUID_PROPID, (LPOLESTR)100}; +extern const DBID OLEDBDECLSPEC DBCOLUMN_SS_SORTID = {DBCOLUMN_SS_X_GUID, DBKIND_GUID_PROPID, (LPOLESTR)101}; +extern const DBID OLEDBDECLSPEC DBCOLUMN_BASETABLEINSTANCE = {DBCOLUMN_SS_X_GUID, DBKIND_GUID_PROPID, (LPOLESTR)102}; +extern const DBID OLEDBDECLSPEC DBCOLUMN_SS_TDSCOLLATION = {DBCOLUMN_SS_X_GUID, DBKIND_GUID_PROPID, (LPOLESTR)103}; +#endif //_SQLOLEDB_H_ +extern const DBID OLEDBDECLSPEC DBCOLUMN_BASESERVERNAME = {DBCOLUMN_SS_X_GUID, DBKIND_GUID_PROPID, (LPOLESTR)104}; +extern const DBID OLEDBDECLSPEC DBCOLUMN_SS_XML_SCHEMACOLLECTION_CATALOGNAME= {DBCOLUMN_SS_X_GUID, DBKIND_GUID_PROPID, (LPOLESTR)105}; +extern const DBID OLEDBDECLSPEC DBCOLUMN_SS_XML_SCHEMACOLLECTION_SCHEMANAME = {DBCOLUMN_SS_X_GUID, DBKIND_GUID_PROPID, (LPOLESTR)106}; +extern const DBID OLEDBDECLSPEC DBCOLUMN_SS_XML_SCHEMACOLLECTIONNAME = {DBCOLUMN_SS_X_GUID, DBKIND_GUID_PROPID, (LPOLESTR)107}; +extern const DBID OLEDBDECLSPEC DBCOLUMN_SS_UDT_CATALOGNAME = {DBCOLUMN_SS_X_GUID, DBKIND_GUID_PROPID, (LPOLESTR)108}; +extern const DBID OLEDBDECLSPEC DBCOLUMN_SS_UDT_SCHEMANAME = {DBCOLUMN_SS_X_GUID, DBKIND_GUID_PROPID, (LPOLESTR)109}; +extern const DBID OLEDBDECLSPEC DBCOLUMN_SS_UDT_NAME = {DBCOLUMN_SS_X_GUID, DBKIND_GUID_PROPID, (LPOLESTR)110}; +extern const DBID OLEDBDECLSPEC DBCOLUMN_SS_ASSEMBLY_TYPENAME= {DBCOLUMN_SS_X_GUID, DBKIND_GUID_PROPID, (LPOLESTR)111}; + +// OLEDB part of SQL Server Native Client header - end here! +#endif // defined(_SQLNCLI_OLEDB_) || !defined(_SQLNCLI_ODBC_) + +// ODBC part of SQL Server Native Client header - begin here! +#if defined(_SQLNCLI_ODBC_) || !defined(_SQLNCLI_OLEDB_) +#ifdef ODBCVER + +// 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 +#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 +#define SQL_COPT_SS_INTEGRATED_SECURITY (SQL_COPT_SS_BASE+3) // Force integrated security on login +#define SQL_COPT_SS_PRESERVE_CURSORS (SQL_COPT_SS_BASE+4) // Preserve server cursors after SQLTransact +#define SQL_COPT_SS_USER_DATA (SQL_COPT_SS_BASE+5) // dbgetuserdata/dbsetuserdata +#define SQL_COPT_SS_ENLIST_IN_DTC SQL_ATTR_ENLIST_IN_DTC // Enlist in a DTC transaction +#define SQL_COPT_SS_ENLIST_IN_XA SQL_ATTR_ENLIST_IN_XA // Enlist in a XA transaction +#define SQL_COPT_SS_FALLBACK_CONNECT (SQL_COPT_SS_BASE+10) // Enables FallBack connections +#define SQL_COPT_SS_PERF_DATA (SQL_COPT_SS_BASE+11) // Used to access SQL Server ODBC driver performance data +#define SQL_COPT_SS_PERF_DATA_LOG (SQL_COPT_SS_BASE+12) // Used to set the logfile name for the Performance data +#define SQL_COPT_SS_PERF_QUERY_INTERVAL (SQL_COPT_SS_BASE+13) // Used to set the query logging threshold in milliseconds. +#define SQL_COPT_SS_PERF_QUERY_LOG (SQL_COPT_SS_BASE+14) // Used to set the logfile name for saving queryies. +#define SQL_COPT_SS_PERF_QUERY (SQL_COPT_SS_BASE+15) // Used to start and stop query logging. +#define SQL_COPT_SS_PERF_DATA_LOG_NOW (SQL_COPT_SS_BASE+16) // Used to make a statistics log entry to disk. +#define SQL_COPT_SS_QUOTED_IDENT (SQL_COPT_SS_BASE+17) // Enable/Disable Quoted Identifiers +#define SQL_COPT_SS_ANSI_NPW (SQL_COPT_SS_BASE+18) // Enable/Disable ANSI NULL, Padding and Warnings +#define SQL_COPT_SS_BCP (SQL_COPT_SS_BASE+19) // Allow BCP usage on connection +#define SQL_COPT_SS_TRANSLATE (SQL_COPT_SS_BASE+20) // Perform code page translation +#define SQL_COPT_SS_ATTACHDBFILENAME (SQL_COPT_SS_BASE+21) // File name to be attached as a database +#define SQL_COPT_SS_CONCAT_NULL (SQL_COPT_SS_BASE+22) // Enable/Disable CONCAT_NULL_YIELDS_NULL +#define SQL_COPT_SS_ENCRYPT (SQL_COPT_SS_BASE+23) // Allow strong encryption for data +#define SQL_COPT_SS_MARS_ENABLED (SQL_COPT_SS_BASE+24) // Multiple active result set per connection +#define SQL_COPT_SS_FAILOVER_PARTNER (SQL_COPT_SS_BASE+25) // Failover partner server +#define SQL_COPT_SS_OLDPWD (SQL_COPT_SS_BASE+26) // Old Password, used when changing password during login +#define SQL_COPT_SS_TXN_ISOLATION (SQL_COPT_SS_BASE+27) // Used to set/get any driver-specific or ODBC-defined TXN iso level +#define SQL_COPT_SS_TRUST_SERVER_CERTIFICATE (SQL_COPT_SS_BASE+28) // Trust server certificate +#define SQL_COPT_SS_SERVER_SPN (SQL_COPT_SS_BASE+29) // Server SPN +#define SQL_COPT_SS_FAILOVER_PARTNER_SPN (SQL_COPT_SS_BASE+30) // Failover partner server SPN +#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_MAX_USED SQL_COPT_SS_MUTUALLY_AUTHENTICATED +// 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 +#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 +#define SQL_SOPT_SS_HIDDEN_COLUMNS (SQL_SOPT_SS_BASE+2) // Expose FOR BROWSE hidden columns +#define SQL_SOPT_SS_NOBROWSETABLE (SQL_SOPT_SS_BASE+3) // Set NOBROWSETABLE option +#define SQL_SOPT_SS_REGIONALIZE (SQL_SOPT_SS_BASE+4) // Regionalize output character conversions +#define SQL_SOPT_SS_CURSOR_OPTIONS (SQL_SOPT_SS_BASE+5) // Server cursor options +#define SQL_SOPT_SS_NOCOUNT_STATUS (SQL_SOPT_SS_BASE+6) // Real vs. Not Real row count indicator +#define SQL_SOPT_SS_DEFER_PREPARE (SQL_SOPT_SS_BASE+7) // Defer prepare until necessary +#define SQL_SOPT_SS_QUERYNOTIFICATION_TIMEOUT (SQL_SOPT_SS_BASE+8) // Notification timeout +#define SQL_SOPT_SS_QUERYNOTIFICATION_MSGTEXT (SQL_SOPT_SS_BASE+9) // Notification message text +#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_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 +#define SQL_COPT_SS_BROWSE_SERVER (SQL_COPT_SS_BASE_EX+2) // Single Server browse request. +#define SQL_COPT_SS_WARN_ON_CP_ERROR (SQL_COPT_SS_BASE_EX+3) // Issues warning when data from the server had a loss during code page conversion. +#define SQL_COPT_SS_CONNECTION_DEAD (SQL_COPT_SS_BASE_EX+4) // dbdead SQLGetConnectOption only. It will try to ping the server. Expensive connection check +#define SQL_COPT_SS_BROWSE_CACHE_DATA (SQL_COPT_SS_BASE_EX+5) // Determines if we should cache browse info. Used when returned buffer is greater then ODBC limit (32K) +#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_EX_MAX_USED SQL_COPT_SS_RESET_CONNECTION + +// 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 +#define SQL_CA_SS_NUM_ORDERS (SQL_CA_SS_BASE+2) // dbnumorders +#define SQL_CA_SS_COLUMN_ORDER (SQL_CA_SS_BASE+3) // dbordercol +#define SQL_CA_SS_COLUMN_VARYLEN (SQL_CA_SS_BASE+4) // dbvarylen +#define SQL_CA_SS_NUM_COMPUTES (SQL_CA_SS_BASE+5) // dbnumcompute +#define SQL_CA_SS_COMPUTE_ID (SQL_CA_SS_BASE+6) // dbnextrow status return +#define SQL_CA_SS_COMPUTE_BYLIST (SQL_CA_SS_BASE+7) // dbbylist +#define SQL_CA_SS_COLUMN_ID (SQL_CA_SS_BASE+8) // dbaltcolid +#define SQL_CA_SS_COLUMN_OP (SQL_CA_SS_BASE+9) // dbaltop +#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_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 +#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 +#define SQL_CA_SS_UDT_ASSEMBLY_TYPE_NAME (SQL_CA_SS_BASE+21) // Qualified name of the assembly containing the UDT class +#define SQL_CA_SS_XML_SCHEMACOLLECTION_CATALOG_NAME (SQL_CA_SS_BASE+22) // Name of the catalog that contains XML Schema collection +#define SQL_CA_SS_XML_SCHEMACOLLECTION_SCHEMA_NAME (SQL_CA_SS_BASE+23) // Name of the schema that contains XML Schema collection +#define SQL_CA_SS_XML_SCHEMACOLLECTION_NAME (SQL_CA_SS_BASE+24) // Name of the XML Schema collection +#define SQL_CA_SS_CATALOG_NAME (SQL_CA_SS_BASE+25) // Catalog name +#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 +#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 +#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 +#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) + +// 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 +#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 +#define SQL_IS_OFF 0L // Integrated security isn't used +#define SQL_IS_ON 1L // Integrated security is used +#define SQL_IS_DEFAULT SQL_IS_OFF +// Defines for use with SQL_COPT_SS_PRESERVE_CURSORS +#define SQL_PC_OFF 0L // Cursors are closed on SQLTransact +#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 +#define SQL_UD_NOTSET NULL // No user data pointer set +// 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 +#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 +#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 +#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 +#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 +#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 +#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 +#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 +#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 +#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 +#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 +#define SQL_NC_OFF 0L +#define SQL_NC_ON 1L +//SQL_SOPT_SS_DEFER_PREPARE +#define SQL_DP_OFF 0L +#define SQL_DP_ON 1L +//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 +#define SQL_EN_OFF 0L +#define SQL_EN_ON 1L +//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 +#define SQL_MORE_INFO_NO 0L +#define SQL_MORE_INFO_YES 1L +//SQL_COPT_SS_BROWSE_CACHE_DATA +#define SQL_CACHE_DATA_NO 0L +#define SQL_CACHE_DATA_YES 1L +//SQL_COPT_SS_RESET_CONNECTION +#define SQL_RESET_YES 1L +//SQL_COPT_SS_WARN_ON_CP_ERROR +#define SQL_WARN_NO 0L +#define SQL_WARN_YES 1L +//SQL_COPT_SS_MARS_ENABLED +#define SQL_MARS_ENABLED_NO 0L +#define SQL_MARS_ENABLED_YES 1L +/* SQL_TXN_ISOLATION_OPTION bitmasks */ +#define SQL_TXN_SS_SNAPSHOT 0x00000020L + +// 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. +#define SQL_SS_VARIANT (-150) +#define SQL_SS_UDT (-151) +#define SQL_SS_XML (-152) +#define SQL_SS_TABLE (-153) +#define SQL_SS_TIME2 (-154) +#define SQL_SS_TIMESTAMPOFFSET (-155) + +// 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 + +#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. + +// SQL Server Data Type defines. +// New types for SQL 6.0 and later servers +#define SQLTEXT 0x23 +#define SQLVARBINARY 0x25 +#define SQLINTN 0x26 +#define SQLVARCHAR 0x27 +#define SQLBINARY 0x2d +#define SQLIMAGE 0x22 +#define SQLCHARACTER 0x2f +#define SQLINT1 0x30 +#define SQLBIT 0x32 +#define SQLINT2 0x34 +#define SQLINT4 0x38 +#define SQLMONEY 0x3c +#define SQLDATETIME 0x3d +#define SQLFLT8 0x3e +#define SQLFLTN 0x6d +#define SQLMONEYN 0x6e +#define SQLDATETIMN 0x6f +#define SQLFLT4 0x3b +#define SQLMONEY4 0x7a +#define SQLDATETIM4 0x3a +// New types for SQL 6.0 and later servers +#define SQLDECIMAL 0x6a +#define SQLNUMERIC 0x6c +// New types for SQL 7.0 and later servers +#define SQLUNIQUEID 0x24 +#define SQLBIGCHAR 0xaf +#define SQLBIGVARCHAR 0xa7 +#define SQLBIGBINARY 0xad +#define SQLBIGVARBINARY 0xa5 +#define SQLBITN 0x68 +#define SQLNCHAR 0xef +#define SQLNVARCHAR 0xe7 +#define SQLNTEXT 0x63 +// New types for SQL 2000 and later servers +#define SQLINT8 0x7f +#define SQLVARIANT 0x62 +// New types for SQL 2005 and later servers +#define SQLUDT 0xf0 +#define SQLXML 0xf1 +// 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 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 +#define SQL_SS_LENGTH_UNLIMITED 0 + +// User Data Type definitions. +// Returned by SQLColAttributes/SQL_CA_SS_COLUMN_UTYPE. +#define SQLudtBINARY 3 +#define SQLudtBIT 16 +#define SQLudtBITN 0 +#define SQLudtCHAR 1 +#define SQLudtDATETIM4 22 +#define SQLudtDATETIME 12 +#define SQLudtDATETIMN 15 +#define SQLudtDECML 24 +#define SQLudtDECMLN 26 +#define SQLudtFLT4 23 +#define SQLudtFLT8 8 +#define SQLudtFLTN 14 +#define SQLudtIMAGE 20 +#define SQLudtINT1 5 +#define SQLudtINT2 6 +#define SQLudtINT4 7 +#define SQLudtINTN 13 +#define SQLudtMONEY 11 +#define SQLudtMONEY4 21 +#define SQLudtMONEYN 17 +#define SQLudtNUM 10 +#define SQLudtNUMN 25 +#define SQLudtSYSNAME 18 +#define SQLudtTEXT 19 +#define SQLudtTIMESTAMP 80 +#define SQLudtUNIQUEIDENTIFIER 0 +#define SQLudtVARBINARY 4 +#define SQLudtVARCHAR 2 +#define MIN_USER_DATATYPE 256 +// 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 +#define SQLAOPVARP 0x33 // Variance population +#define SQLAOPCNT 0x4b // Count +#define SQLAOPSUM 0x4d // Sum +#define SQLAOPAVG 0x4f // Average +#define SQLAOPMIN 0x51 // Min +#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. +#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 +#define SQL_INFO_SS_MAX_USED SQL_INFO_SS_NETLIB_NAMEA +#ifdef UNICODE +#define SQL_INFO_SS_NETLIB_NAME SQL_INFO_SS_NETLIB_NAMEW +#else +#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. +#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. +#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) +#define SQL_DIAG_DFC_SS_CONDITION (SQL_DIAG_DFC_SS_BASE-2) +#define SQL_DIAG_DFC_SS_CREATE_DATABASE (SQL_DIAG_DFC_SS_BASE-3) +#define SQL_DIAG_DFC_SS_CREATE_DEFAULT (SQL_DIAG_DFC_SS_BASE-4) +#define SQL_DIAG_DFC_SS_CREATE_PROCEDURE (SQL_DIAG_DFC_SS_BASE-5) +#define SQL_DIAG_DFC_SS_CREATE_RULE (SQL_DIAG_DFC_SS_BASE-6) +#define SQL_DIAG_DFC_SS_CREATE_TRIGGER (SQL_DIAG_DFC_SS_BASE-7) +#define SQL_DIAG_DFC_SS_CURSOR_DECLARE (SQL_DIAG_DFC_SS_BASE-8) +#define SQL_DIAG_DFC_SS_CURSOR_OPEN (SQL_DIAG_DFC_SS_BASE-9) +#define SQL_DIAG_DFC_SS_CURSOR_FETCH (SQL_DIAG_DFC_SS_BASE-10) +#define SQL_DIAG_DFC_SS_CURSOR_CLOSE (SQL_DIAG_DFC_SS_BASE-11) +#define SQL_DIAG_DFC_SS_DEALLOCATE_CURSOR (SQL_DIAG_DFC_SS_BASE-12) +#define SQL_DIAG_DFC_SS_DBCC (SQL_DIAG_DFC_SS_BASE-13) +#define SQL_DIAG_DFC_SS_DISK (SQL_DIAG_DFC_SS_BASE-14) +#define SQL_DIAG_DFC_SS_DROP_DATABASE (SQL_DIAG_DFC_SS_BASE-15) +#define SQL_DIAG_DFC_SS_DROP_DEFAULT (SQL_DIAG_DFC_SS_BASE-16) +#define SQL_DIAG_DFC_SS_DROP_PROCEDURE (SQL_DIAG_DFC_SS_BASE-17) +#define SQL_DIAG_DFC_SS_DROP_RULE (SQL_DIAG_DFC_SS_BASE-18) +#define SQL_DIAG_DFC_SS_DROP_TRIGGER (SQL_DIAG_DFC_SS_BASE-19) +#define SQL_DIAG_DFC_SS_DUMP_DATABASE (SQL_DIAG_DFC_SS_BASE-20) +#define SQL_DIAG_DFC_SS_BACKUP_DATABASE (SQL_DIAG_DFC_SS_BASE-20) +#define SQL_DIAG_DFC_SS_DUMP_TABLE (SQL_DIAG_DFC_SS_BASE-21) +#define SQL_DIAG_DFC_SS_DUMP_TRANSACTION (SQL_DIAG_DFC_SS_BASE-22) +#define SQL_DIAG_DFC_SS_BACKUP_TRANSACTION (SQL_DIAG_DFC_SS_BASE-22) +#define SQL_DIAG_DFC_SS_GOTO (SQL_DIAG_DFC_SS_BASE-23) +#define SQL_DIAG_DFC_SS_INSERT_BULK (SQL_DIAG_DFC_SS_BASE-24) +#define SQL_DIAG_DFC_SS_KILL (SQL_DIAG_DFC_SS_BASE-25) +#define SQL_DIAG_DFC_SS_LOAD_DATABASE (SQL_DIAG_DFC_SS_BASE-26) +#define SQL_DIAG_DFC_SS_RESTORE_DATABASE (SQL_DIAG_DFC_SS_BASE-26) +#define SQL_DIAG_DFC_SS_LOAD_HEADERONLY (SQL_DIAG_DFC_SS_BASE-27) +#define SQL_DIAG_DFC_SS_RESTORE_HEADERONLY (SQL_DIAG_DFC_SS_BASE-27) +#define SQL_DIAG_DFC_SS_LOAD_TABLE (SQL_DIAG_DFC_SS_BASE-28) +#define SQL_DIAG_DFC_SS_LOAD_TRANSACTION (SQL_DIAG_DFC_SS_BASE-29) +#define SQL_DIAG_DFC_SS_RESTORE_TRANSACTION (SQL_DIAG_DFC_SS_BASE-29) +#define SQL_DIAG_DFC_SS_PRINT (SQL_DIAG_DFC_SS_BASE-30) +#define SQL_DIAG_DFC_SS_RAISERROR (SQL_DIAG_DFC_SS_BASE-31) +#define SQL_DIAG_DFC_SS_READTEXT (SQL_DIAG_DFC_SS_BASE-32) +#define SQL_DIAG_DFC_SS_RECONFIGURE (SQL_DIAG_DFC_SS_BASE-33) +#define SQL_DIAG_DFC_SS_RETURN (SQL_DIAG_DFC_SS_BASE-34) +#define SQL_DIAG_DFC_SS_SELECT_INTO (SQL_DIAG_DFC_SS_BASE-35) +#define SQL_DIAG_DFC_SS_SET (SQL_DIAG_DFC_SS_BASE-36) +#define SQL_DIAG_DFC_SS_SET_IDENTITY_INSERT (SQL_DIAG_DFC_SS_BASE-37) +#define SQL_DIAG_DFC_SS_SET_ROW_COUNT (SQL_DIAG_DFC_SS_BASE-38) +#define SQL_DIAG_DFC_SS_SET_STATISTICS (SQL_DIAG_DFC_SS_BASE-39) +#define SQL_DIAG_DFC_SS_SET_TEXTSIZE (SQL_DIAG_DFC_SS_BASE-40) +#define SQL_DIAG_DFC_SS_SETUSER (SQL_DIAG_DFC_SS_BASE-41) +#define SQL_DIAG_DFC_SS_SHUTDOWN (SQL_DIAG_DFC_SS_BASE-42) +#define SQL_DIAG_DFC_SS_TRANS_BEGIN (SQL_DIAG_DFC_SS_BASE-43) +#define SQL_DIAG_DFC_SS_TRANS_COMMIT (SQL_DIAG_DFC_SS_BASE-44) +#define SQL_DIAG_DFC_SS_TRANS_PREPARE (SQL_DIAG_DFC_SS_BASE-45) +#define SQL_DIAG_DFC_SS_TRANS_ROLLBACK (SQL_DIAG_DFC_SS_BASE-46) +#define SQL_DIAG_DFC_SS_TRANS_SAVE (SQL_DIAG_DFC_SS_BASE-47) +#define SQL_DIAG_DFC_SS_TRUNCATE_TABLE (SQL_DIAG_DFC_SS_BASE-48) +#define SQL_DIAG_DFC_SS_UPDATE_STATISTICS (SQL_DIAG_DFC_SS_BASE-49) +#define SQL_DIAG_DFC_SS_UPDATETEXT (SQL_DIAG_DFC_SS_BASE-50) +#define SQL_DIAG_DFC_SS_USE (SQL_DIAG_DFC_SS_BASE-51) +#define SQL_DIAG_DFC_SS_WAITFOR (SQL_DIAG_DFC_SS_BASE-52) +#define SQL_DIAG_DFC_SS_WRITETEXT (SQL_DIAG_DFC_SS_BASE-53) +#define SQL_DIAG_DFC_SS_DENY (SQL_DIAG_DFC_SS_BASE-54) +#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 +#define EX_ANY 0 +#define EX_INFO 10 +#define EX_MAXISEVERITY EX_INFO +#define EX_MISSING 11 +#define EX_TYPE 12 +#define EX_DEADLOCK 13 +#define EX_PERMIT 14 +#define EX_SYNTAX 15 +#define EX_USER 16 +#define EX_RESOURCE 17 +#define EX_INTOK 18 +#define MAXUSEVERITY EX_INTOK +#define EX_LIMIT 19 +#define EX_CMDFATAL 20 +#define MINFATALERR EX_CMDFATAL +#define EX_DBFATAL 21 +#define EX_TABCORRUPT 22 +#define EX_DBCORRUPT 23 +#define EX_HARDWARE 24 +#define EX_CONTROL 25 +// Internal server datatypes - used when binding to SQL_C_BINARY +#ifndef MAXNUMERICLEN // Resolve ODS/DBLib conflicts +// 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; +#else +typedef char DBCHAR; + +#endif +typedef short SQLSMALLINT; + +typedef unsigned short SQLUSMALLINT; + +typedef long SQLINTEGER; + +typedef unsigned long SQLUINTEGER; + +typedef unsigned char DBBINARY; + +typedef unsigned char DBTINYINT; + +typedef short DBSMALLINT; + +typedef unsigned short DBUSMALLINT; + +typedef double DBFLT8; + +typedef unsigned char DBBIT; + +typedef unsigned char DBBOOL; + +typedef float DBFLT4; + +typedef DBFLT4 DBREAL; + +typedef UINT DBUBOOL; + +typedef struct dbmoney + { + LONG mnyhigh; + ULONG mnylow; + } DBMONEY; + +typedef struct dbdatetime + { + LONG dtdays; + ULONG dttime; + } DBDATETIME; + +typedef struct dbdatetime4 + { + USHORT numdays; + USHORT nummins; + } DBDATETIM4; + +typedef LONG DBMONEY4; + +#include // 8-byte structure packing + +// 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 + { + SQLSMALLINT year; + SQLUSMALLINT month; + SQLUSMALLINT day; + SQLUSMALLINT hour; + SQLUSMALLINT minute; + SQLUSMALLINT second; + SQLUINTEGER fraction; + SQLSMALLINT timezone_hour; + SQLSMALLINT timezone_minute; + } SQL_SS_TIMESTAMPOFFSET_STRUCT; + +#include // restore original structure packing + +// 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 +#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; +#endif // ODCBVER +#endif // MAXNUMERICLEN + +#ifndef INT +typedef int INT; +typedef long DBINT; +typedef DBINT * LPDBINT; +#ifndef _LPCBYTE_DEFINED +#define _LPCBYTE_DEFINED +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 +#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 +#define SQL_SS_DL_DEFAULT TEXT("STATS.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 +#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. + +// ODBC BCP prototypes and defines +// Return codes +#define SUCCEED 1 +#define FAIL 0 +#define SUCCEED_ABORT 2 +#define SUCCEED_ASYNC 3 +// Transfer directions +#define DB_IN 1 // Transfer from client to server +#define DB_OUT 2 // Transfer from server to client +// 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 +#define BCPBATCH 4 // Sets input batch size +#define BCPKEEPNULLS 5 // Sets to insert NULLs for empty input values +#define BCPABORT 6 // Sets to have bcpexec return SUCCEED_ABORT +#define BCPODBC 7 // Sets ODBC canonical character output +#define BCPKEEPIDENTITY 8 // Sets IDENTITY_INSERT on +#if SQLNCLI_VER < 1000 +#define BCP6xFILEFMT 9 // DEPRECATED: Sets 6x file format on +#endif +#define BCPHINTSA 10 // Sets server BCP hints (ANSI string) +#define BCPHINTSW 11 // Sets server BCP hints (UNICODE string) +#define BCPFILECP 12 // Sets clients code page for the file +#define BCPUNICODEFILE 13 // Sets that the file contains unicode header +#define BCPTEXTFILE 14 // Sets BCP mode to expect a text file and to detect Unicode or ANSI automatically +#define BCPFILEFMT 15 // Sets file format version +#define BCPFMTXML 16 // Sets the format file type to xml +#define BCPFIRSTEX 17 // Starting Row for BCP operation (64 bit) +#define BCPLASTEX 18 // Ending Row for BCP operation (64 bit) +#define BCPROWCOUNT 19 // Total Number of Rows Copied (64 bit) +// 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 +#define SQL_VARLEN_DATA (-10) // Use default length for column +// BCP column format properties +#define BCP_FMT_TYPE 0x01 +#define BCP_FMT_INDICATOR_LEN 0x02 +#define BCP_FMT_DATA_LEN 0x03 +#define BCP_FMT_TERMINATOR 0x04 +#define BCP_FMT_SERVER_COL 0x05 +#define BCP_FMT_COLLATION 0x06 +#define BCP_FMT_COLLATION_ID 0x07 +// 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_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 +#define bcp_readfmt bcp_readfmtW +#define bcp_writefmt bcp_writefmtW +#define dbprtype dbprtypeW +#define bcp_gettypename bcp_gettypenameW +#define BCPHINTS BCPHINTSW +#else +#define bcp_init bcp_initA +#define bcp_readfmt bcp_readfmtA +#define bcp_writefmt bcp_writefmtA +#define dbprtype dbprtypeA +#define bcp_gettypename bcp_gettypenameA +#define BCPHINTS BCPHINTSA +#endif // UNICODE + +#endif // SQLNCLI_NO_BCP + +// 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 +#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 +#define SQL_COPT_SS_ANSI_OEM (SQL_COPT_SS_BASE+6) +#define SQL_AO_OFF 0L +#define SQL_AO_ON 1L +#define SQL_AO_DEFAULT SQL_AO_OFF +#define SQL_CA_SS_BASE_COLUMN_NAME SQL_DESC_BASE_COLUMN_NAME + +#endif // ODBCVER +#endif // defined(_SQLNCLI_ODBC_) || !defined(_SQLNCLI_OLEDB_) +// ODBC part of SQL Server Native Client header - end here! + +//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 +#define SQL_FILESTREAM_OPEN_FLAG_SEQUENTIAL_SCAN 0x00000008L +#define SQL_FILESTREAM_OPEN_FLAG_RANDOM_ACCESS 0x00000010L +HANDLE __stdcall OpenSqlFilestream ( + LPCWSTR FilestreamPath, + SQL_FILESTREAM_DESIRED_ACCESS DesiredAccess, + ULONG OpenOptions, + 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) + + + +extern RPC_IF_HANDLE __MIDL_itf_sqlncli_0000_0010_v0_0_c_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_sqlncli_0000_0010_v0_0_s_ifspec; + +/* Additional Prototypes for ALL interfaces */ + +/* end of Additional Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/sqlsrv/stmt.cpp b/sqlsrv/stmt.cpp index 5ef7024f..521296ec 100644 --- a/sqlsrv/stmt.cpp +++ b/sqlsrv/stmt.cpp @@ -3,7 +3,7 @@ // // Contents: Routines that use statement handles // -// Copyright 2010 Microsoft Corporation +// Copyright Microsoft Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -112,6 +112,18 @@ namespace SSCursorTypes { const char QUERY_OPTION_SCROLLABLE_DYNAMIC[] = "dynamic"; const char QUERY_OPTION_SCROLLABLE_KEYSET[] = "keyset"; const char QUERY_OPTION_SCROLLABLE_FORWARD[] = "forward"; + const char QUERY_OPTION_SCROLLABLE_BUFFERED[] = "buffered"; +} + +ss_sqlsrv_stmt::ss_sqlsrv_stmt( sqlsrv_conn* c, SQLHANDLE handle, error_callback e, void* drv TSRMLS_DC ) : + sqlsrv_stmt( c, handle, e, drv TSRMLS_CC ), + prepared( false ), + conn_index( -1 ), + params_z( NULL ), + fetch_field_names( NULL ), + fetch_fields_count ( 0 ) +{ + core_sqlsrv_set_buffered_query_limit( this, SQLSRV_G( buffered_query_limit ) TSRMLS_CC ); } ss_sqlsrv_stmt::~ss_sqlsrv_stmt( void ) @@ -132,8 +144,8 @@ ss_sqlsrv_stmt::~ss_sqlsrv_stmt( void ) } // to be called whenever a new result set is created, such as after an -// execute or next_result. Resets the state variables. -void ss_sqlsrv_stmt::new_result_set( void ) +// execute or next_result. Resets the state variables and calls the subclass. +void ss_sqlsrv_stmt::new_result_set( TSRMLS_D ) { if( fetch_field_names != NULL ) { @@ -146,7 +158,7 @@ void ss_sqlsrv_stmt::new_result_set( void ) fetch_field_names = NULL; fetch_fields_count = 0; - sqlsrv_stmt::new_result_set(); + sqlsrv_stmt::new_result_set( TSRMLS_C ); } // Returns a php type for a given sql type. Also sets the encoding wherever applicable. @@ -164,6 +176,7 @@ sqlsrv_phptype ss_sqlsrv_stmt::sql_type_to_php_type( SQLINTEGER sql_type, SQLUIN case SQL_GUID: case SQL_NUMERIC: case SQL_WCHAR: + case SQL_SS_VARIANT: ss_phptype.typeinfo.type = SQLSRV_PHPTYPE_STRING; ss_phptype.typeinfo.encoding = this->conn->encoding(); break; @@ -272,7 +285,7 @@ PHP_FUNCTION( sqlsrv_execute ) // to prepare to execute the next statement, we skip any remaining results (and skip parameter finalization too) while( stmt->past_next_result_end == false ) { - core_sqlsrv_next_result( stmt TSRMLS_CC, false ); + core_sqlsrv_next_result( stmt TSRMLS_CC, false, false ); } } @@ -597,11 +610,11 @@ PHP_FUNCTION( sqlsrv_rows_affected ) // make sure it is not scrollable. This function should only work for inserts, updates, and deletes, // but this is the best we can do to enforce that. - CHECK_CUSTOM_ERROR( stmt->scrollable, stmt, SS_SQLSRV_ERROR_STATEMENT_SCROLLABLE ) { + CHECK_CUSTOM_ERROR( stmt->cursor_type != SQL_CURSOR_FORWARD_ONLY, stmt, SS_SQLSRV_ERROR_STATEMENT_SCROLLABLE ) { throw ss::SSException(); } - rows = core::SQLRowCount( stmt TSRMLS_CC ); + rows = stmt->current_results->row_count( TSRMLS_C ); RETURN_LONG( rows ); } @@ -645,11 +658,12 @@ PHP_FUNCTION( sqlsrv_num_rows ) // make sure that the statement is scrollable and the cursor is not dynamic. // if the cursor is dynamic, then the number of rows returned is always -1. - CHECK_CUSTOM_ERROR( !stmt->scrollable || stmt->scroll_is_dynamic, stmt, SS_SQLSRV_ERROR_STATEMENT_NOT_SCROLLABLE ) { + CHECK_CUSTOM_ERROR( stmt->cursor_type == SQL_CURSOR_FORWARD_ONLY || stmt->cursor_type == SQL_CURSOR_DYNAMIC, stmt, + SS_SQLSRV_ERROR_STATEMENT_NOT_SCROLLABLE ) { throw ss::SSException(); } - rows = core::SQLRowCount( stmt TSRMLS_CC ); + rows = stmt->current_results->row_count( TSRMLS_C ); RETURN_LONG( rows ); } @@ -1147,7 +1161,7 @@ PHP_FUNCTION(SQLSRV_SQLTYPE_VARCHAR) void mark_params_by_reference( ss_sqlsrv_stmt* stmt, zval* params_z TSRMLS_DC ) { - SQLSRV_ASSERT( stmt->params_z == NULL, "mark_params_by_reference: parameters list shouldn't be present" ); + SQLSRV_ASSERT( stmt->params_z == NULL, "mark_params_by_reference: parameters list shouldn't be present" ); if( params_z == NULL ) { return; @@ -1259,7 +1273,7 @@ void bind_params( ss_sqlsrv_stmt* stmt TSRMLS_DC ) zval** var = NULL; int zr = zend_hash_index_find( Z_ARRVAL_PP( param_z ), 0, reinterpret_cast( &var )); - CHECK_CUSTOM_ERROR( zr == FAILURE, stmt, SS_SQLSRV_ERROR_VAR_REQUIRED, index ) { + CHECK_CUSTOM_ERROR( zr == FAILURE, stmt, SS_SQLSRV_ERROR_VAR_REQUIRED, index + 1 ) { zval_ptr_dtor( ¶ms_z ); throw ss::SSException(); } @@ -1413,7 +1427,8 @@ PHP_FUNCTION( sqlsrv_free_stmt ) } // verify the resource so we know we're deleting a statement - stmt = static_cast( zend_fetch_resource( &stmt_r TSRMLS_CC, -1, ss_sqlsrv_stmt::resource_name, NULL, 1, ss_sqlsrv_stmt::descriptor )); + stmt = static_cast( zend_fetch_resource( &stmt_r TSRMLS_CC, -1, ss_sqlsrv_stmt::resource_name, NULL, + 1, ss_sqlsrv_stmt::descriptor )); if( stmt == NULL ) { @@ -1472,6 +1487,11 @@ void stmt_option_scrollable:: operator()( sqlsrv_stmt* stmt, stmt_option const* cursor_type = SQL_CURSOR_FORWARD_ONLY; } + else if( !stricmp( scroll_type, SSCursorTypes::QUERY_OPTION_SCROLLABLE_BUFFERED )) { + + cursor_type = SQLSRV_CURSOR_BUFFERED; + } + else { THROW_SS_ERROR( stmt, SQLSRV_ERROR_INVALID_OPTION_SCROLLABLE ); @@ -1534,6 +1554,11 @@ zval* convert_to_zval( SQLSRV_PHPTYPE sqlsrv_php_type, void** in_val, SQLLEN fie out_zval = ( reinterpret_cast( *in_val )); break; + case SQLSRV_PHPTYPE_NULL: + ALLOC_INIT_ZVAL( out_zval ); + ZVAL_NULL( out_zval ); + break; + default: DIE( "Unknown php type" ); break; @@ -1764,22 +1789,22 @@ void determine_stmt_has_rows( ss_sqlsrv_stmt* stmt TSRMLS_DC ) // if the statement is scrollable, our work is easier though less performant. We simply // fetch the first row, and then roll the cursor back to be prior to the first row - if( stmt->scrollable ) { + if( stmt->cursor_type != SQL_CURSOR_FORWARD_ONLY ) { - r = core::SQLFetchScroll( stmt, SQL_FETCH_FIRST, 0 TSRMLS_CC ); + r = stmt->current_results->fetch( SQL_FETCH_FIRST, 0 TSRMLS_CC ); if( SQL_SUCCEEDED( r )) { stmt->has_rows = true; CHECK_SQL_WARNING( r, stmt ); // restore the cursor to its original position. - r = SQLFetchScroll( stmt->handle(), SQL_FETCH_ABSOLUTE, 0 ); + r = stmt->current_results->fetch( SQL_FETCH_ABSOLUTE, 0 TSRMLS_CC ); SQLSRV_ASSERT(( r == SQL_NO_DATA ), "core_sqlsrv_has_rows: Should have scrolled the cursor to the beginning " "of the result set." ); } } else { - // otherwise, we fetch the first row, but record that we di. sqlsrv_fetch checks this + // otherwise, we fetch the first row, but record that we did. sqlsrv_fetch checks this // flag and simply skips the first fetch, knowing it was already done. It records its own // flags to know if it should fetch on subsequent calls. @@ -1823,7 +1848,7 @@ void fetch_fields_common( __inout ss_sqlsrv_stmt* stmt, int fetch_type, __out zv 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( sqlsrv_malloc( field_name_len + 1 )); + field_names[ i ].name = static_cast( 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; @@ -1908,7 +1933,7 @@ void parse_param_array( ss_sqlsrv_stmt* stmt, __inout zval* param_array, unsigne if( zend_hash_has_more_elements( param_ht ) == FAILURE || zend_hash_get_current_data( param_ht, (void**) &var_or_val ) == FAILURE ) { - THROW_SS_ERROR( stmt, SS_SQLSRV_ERROR_VAR_REQUIRED, index ); + THROW_SS_ERROR( stmt, SS_SQLSRV_ERROR_VAR_REQUIRED, index + 1 ); } // if the direction is included, then use what they gave, otherwise INPUT is assumed @@ -1921,7 +1946,7 @@ void parse_param_array( ss_sqlsrv_stmt* stmt, __inout zval* param_array, unsigne } direction = Z_LVAL_PP( temp ); CHECK_CUSTOM_ERROR( direction != SQL_PARAM_INPUT && direction != SQL_PARAM_OUTPUT && direction != SQL_PARAM_INPUT_OUTPUT, - stmt, SS_SQLSRV_ERROR_INVALID_PARAMETER_DIRECTION, index ) { + stmt, SS_SQLSRV_ERROR_INVALID_PARAMETER_DIRECTION, index + 1 ) { throw ss::SSException(); } } diff --git a/sqlsrv/template.rc b/sqlsrv/template.rc index 1aa3b9fd..c9ef56f7 100644 --- a/sqlsrv/template.rc +++ b/sqlsrv/template.rc @@ -3,7 +3,7 @@ // // Contents: Version resource // -// Copyright 2010 Microsoft Corporation +// Copyright Microsoft Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -65,7 +65,7 @@ BEGIN VALUE "FileDescription", "Microsoft Drivers for PHP for SQL Server (SQLSRV Driver)\0" VALUE "FileVersion", STRVER4(SQLVERSION_MAJOR,SQLVERSION_MINOR, SQLVERSION_MMDD, SQLVERSION_REVISION) VALUE "InternalName", FILE_NAME "\0" - VALUE "LegalCopyright", "Copyright 2010 Microsoft Corporation.\0" + VALUE "LegalCopyright", "Copyright Microsoft Corporation.\0" VALUE "OriginalFilename", FILE_NAME "\0" VALUE "ProductName", "Microsoft Drivers for PHP for SQL Server\0" VALUE "ProductVersion", STRVER3(SQLVERSION_MAJOR,SQLVERSION_MINOR, SQLVERSION_MMDD) diff --git a/sqlsrv/util.cpp b/sqlsrv/util.cpp index 977ca191..7b7871ef 100644 --- a/sqlsrv/util.cpp +++ b/sqlsrv/util.cpp @@ -5,7 +5,7 @@ // // Comments: Mostly error handling and some type handling // -// Copyright 2010 Microsoft Corporation +// Copyright Microsoft Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -218,8 +218,8 @@ ss_error SS_ERRORS[] = { // these three errors are returned for invalid options, so they are given the same number for compatibility with 1.1 { - SQLSRV_ERROR_INVALID_OPTION_VALUE, - { IMSSP, (SQLCHAR*) "Invalid value specified for option %1!s!.", -33, true } + SQLSRV_ERROR_INVALID_QUERY_TIMEOUT_VALUE, + { IMSSP, (SQLCHAR*) "Invalid value %1!s! specified for option SQLSRV_QUERY_TIMEOUT.", -33, true } }, { @@ -301,9 +301,8 @@ ss_error SS_ERRORS[] = { { SQLSRV_ERROR_DRIVER_NOT_INSTALLED, - { IMSSP, (SQLCHAR*) "This extension requires either the Microsoft SQL Server 2008 Native Client (SP1 or later) or the " - "Microsoft SQL Server 2008 R2 Native Client ODBC Driver to communicate with SQL Server. Neither of those ODBC Drivers are currently installed. " - "Access the following URL to download the Microsoft SQL Server 2008 R2 Native Client ODBC driver for %1!s!: " + { IMSSP, (SQLCHAR*) "This extension requires the Microsoft SQL Server 2011 Native Client. " + "Access the following URL to download the Microsoft SQL Server 2011 Native Client ODBC driver for %1!s!: " "http://go.microsoft.com/fwlink/?LinkId=163712", -49, true } }, @@ -332,7 +331,7 @@ ss_error SS_ERRORS[] = { { SQLSRV_ERROR_INVALID_OPTION_SCROLLABLE, { IMSSP, (SQLCHAR*)"The value passed for the 'Scrollable' statement option is invalid. Please use 'static', 'dynamic', " - "'keyset', or 'forward'.", -54, false } + "'keyset', 'forward', or 'buffered'.", -54, false } }, { @@ -354,6 +353,14 @@ ss_error SS_ERRORS[] = { SQLSRV_ERROR_OUTPUT_PARAM_TRUNCATED, { IMSSP, (SQLCHAR*) "String data, right truncated for output parameter %1!d!.", -58, true } }, + { + SQLSRV_ERROR_BUFFER_LIMIT_EXCEEDED, + { IMSSP, (SQLCHAR*) "Memory limit of %1!d! KB exceeded for buffered query", -59, true } + }, + { + SQLSRV_ERROR_INVALID_BUFFER_LIMIT, + { IMSSP, (SQLCHAR*) "Setting for " INI_BUFFERED_QUERY_LIMIT " was non-int or non-positive.", -60, false } + }, // internal warning definitions { @@ -402,7 +409,8 @@ 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, print_args TSRMLS_CC ); + return handle_errors_and_warnings( ctx, &SQLSRV_G( errors ), &SQLSRV_G( warnings ), severity, sqlsrv_error_code, warning, + print_args TSRMLS_CC ); } // sqlsrv_errors( [int $errorsAndOrWarnings] ) @@ -595,6 +603,25 @@ PHP_FUNCTION( sqlsrv_configure ) RETURN_TRUE; } + else if( !stricmp( option, INI_BUFFERED_QUERY_LIMIT )) { + + CHECK_CUSTOM_ERROR(( Z_TYPE_P( value_z ) != IS_LONG ), error_ctx, SQLSRV_ERROR_INVALID_BUFFER_LIMIT, _FN_ ) { + + throw ss::SSException(); + } + + long buffered_query_limit = Z_LVAL_P( value_z ); + + CHECK_CUSTOM_ERROR( buffered_query_limit < 0, error_ctx, SQLSRV_ERROR_INVALID_BUFFER_LIMIT, _FN_ ) { + + throw ss::SSException(); + } + + SQLSRV_G( buffered_query_limit ) = buffered_query_limit; + LOG( SEV_NOTICE, INI_PREFIX INI_BUFFERED_QUERY_LIMIT " = %1!d!", SQLSRV_G( buffered_query_limit )); + RETURN_TRUE; + } + else { THROW_CORE_ERROR( error_ctx, SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER, _FN_ ); @@ -666,6 +693,11 @@ PHP_FUNCTION( sqlsrv_get_config ) ZVAL_LONG( return_value, SQLSRV_G( log_subsystems )); return; } + else if( !stricmp( option, INI_BUFFERED_QUERY_LIMIT )) { + + ZVAL_LONG( return_value, SQLSRV_G( buffered_query_limit )); + return; + } else { THROW_CORE_ERROR( error_ctx, SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER, _FN_ ); @@ -773,8 +805,6 @@ bool handle_errors_and_warnings( sqlsrv_context& ctx, zval** reported_chain, zva zval* error_z = NULL; sqlsrv_error_auto_ptr error; - error = new ( sqlsrv_malloc( sizeof( sqlsrv_error ))) sqlsrv_error; - // array of reported errors if( Z_TYPE_P( *reported_chain ) == IS_NULL ) { diff --git a/sqlsrv/version.h b/sqlsrv/version.h index 6be3f9e7..845c94da 100644 --- a/sqlsrv/version.h +++ b/sqlsrv/version.h @@ -1,9 +1,9 @@ -//--------------------------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------------------------- // File: version.h // -// Contents: Version information for compile and resources -// -// Copyright 2010 Microsoft Corporation +// Contents: Version number constants +// +// Copyright Microsoft Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,11 +16,11 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -//--------------------------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------------------------- -#define VER_FILEVERSION_STR "2.0.0.200" -#define _FILEVERSION 2,0,0,200 -#define SQLVERSION_MAJOR 2 +#define VER_FILEVERSION_STR "3.0.0.0" +#define _FILEVERSION 3,0,0,0 +#define SQLVERSION_MAJOR 3 #define SQLVERSION_MINOR 0 #define SQLVERSION_MMDD 0 -#define SQLVERSION_REVISION 200 +#define SQLVERSION_REVISION 0