2016-04-12 23:43:46 +02:00
# ifndef CORE_SQLSRV_H
# define CORE_SQLSRV_H
//---------------------------------------------------------------------------------------------------------------------------------
// File: core_sqlsrv.h
//
// Contents: Core routines and constants shared by the Microsoft Drivers for PHP for SQL Server
//
2019-01-16 19:19:01 +01:00
// Microsoft Drivers 5.6 for PHP for SQL Server
2016-04-12 23:43:46 +02:00
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the ""Software""),
// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions :
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//---------------------------------------------------------------------------------------------------------------------------------
//*********************************************************************************************************************************
// Includes
//*********************************************************************************************************************************
2017-01-24 02:22:15 +01:00
# ifdef SQL_WCHART_CONVERT
# undef SQL_WCHART_CONVERT
# endif
# ifndef _WCHART_DEFINED
# define _WCHART_DEFINED
# endif
2017-01-26 22:54:02 +01:00
# include "php.h"
# include "php_globals.h"
# include "php_ini.h"
# include "ext/standard/php_standard.h"
# include "ext/standard/info.h"
2017-06-29 21:49:00 +02:00
# ifndef _WIN32 // !_WIN32
2017-01-24 02:22:15 +01:00
# include "FormattedPrint.h"
# include "StringFunctions.h"
2017-06-29 21:49:00 +02:00
# else
# include "VersionHelpers.h"
# endif
2017-01-24 02:22:15 +01:00
2016-04-12 23:43:46 +02:00
# ifdef HAVE_CONFIG_H
# include "config.h"
# endif
# ifdef PHP_WIN32
# define PHP_SQLSRV_API __declspec(dllexport)
# else
# define PHP_SQLSRV_API
# endif
2017-01-24 02:22:15 +01:00
// #define MultiByteToWideChar SystemLocale::ToUtf16
# define stricmp strcasecmp
# define strnicmp strncasecmp
2018-04-14 00:06:10 +02:00
# define strnlen_s(s) strnlen_s(s, INT_MAX)
2017-01-24 02:22:15 +01:00
2017-01-27 02:06:17 +01:00
# ifndef _WIN32
2017-01-24 02:22:15 +01:00
# define GetLastError() errno
# define SetLastError(err) errno=err
typedef struct _OSVERSIONINFOA {
DWORD dwOSVersionInfoSize ;
DWORD dwMajorVersion ;
DWORD dwMinorVersion ;
DWORD dwBuildNumber ;
DWORD dwPlatformId ;
2018-08-01 02:22:56 +02:00
CHAR szCSDVersion [ 128 ] ; // Maintenance string for PSS usage
2017-01-24 02:22:15 +01:00
} OSVERSIONINFOA , * POSVERSIONINFOA , * LPOSVERSIONINFOA ;
typedef OSVERSIONINFOA OSVERSIONINFO ;
2017-01-27 02:06:17 +01:00
# endif // !_WIN32
2017-01-24 02:22:15 +01:00
2016-04-12 23:43:46 +02:00
// OACR is an internal Microsoft static code analysis tool
# if defined(OACR)
# include <oacr.h>
OACR_WARNING_PUSH
OACR_WARNING_DISABLE ( ALLOC_SIZE_OVERFLOW , " Third party code. " )
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 " {
2017-01-24 02:22:15 +01:00
# if defined(_MSC_VER)
2016-04-12 23:43:46 +02:00
# pragma warning(push)
# pragma warning( disable: 4005 4100 4127 4142 4244 4505 4530 )
2017-01-24 02:22:15 +01:00
# endif
2016-04-12 23:43:46 +02:00
# ifdef ZTS
# include "TSRM.h"
# endif
# if _MSC_VER >= 1400
// typedef and macro to prevent a conflict between php.h and ws2tcpip.h.
// php.h defines this constant as unsigned int which causes a compile error
// in ws2tcpip.h. Fortunately php.h allows an override by defining
// HAVE_SOCKLEN_T. Since ws2tcpip.h isn't included until later, we define
// socklen_t here and override the php.h version.
typedef int socklen_t ;
# define HAVE_SOCKLEN_T
# endif
2017-01-24 02:22:15 +01:00
# if defined(_MSC_VER)
2016-04-12 23:43:46 +02:00
# pragma warning(pop)
2017-01-24 02:22:15 +01:00
# endif
2016-04-12 23:43:46 +02:00
# if ZEND_DEBUG
// debug build causes warning C4505 to pop up from the Zend header files
# pragma warning( disable: 4505 )
# endif
} // extern "C"
# if defined(OACR)
OACR_WARNING_POP
# endif
2017-01-26 22:54:02 +01:00
# ifdef _WIN32
2016-04-12 23:43:46 +02:00
# include <sql.h>
# include <sqlext.h>
2017-01-26 22:54:02 +01:00
# endif // _WIN32
2016-04-12 23:43:46 +02:00
2017-02-08 23:28:04 +01:00
# if !defined(SQL_GUID)
// imported from sqlext.h
2017-02-07 01:55:39 +01:00
# define SQL_GUID (-11)
2017-02-08 23:28:04 +01:00
# endif
2017-02-07 01:55:39 +01:00
2016-04-12 23:43:46 +02:00
# 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
# endif
// PHP defines inline as __forceinline, which in debug mode causes a warning to be emitted when
// we use std::copy, which causes compilation to fail since we compile with warnings as errors.
# if defined(ZEND_DEBUG) && defined(inline)
# undef inline
# endif
# include <deque>
# include <map>
2017-09-12 01:17:24 +02:00
# include <string>
2016-04-12 23:43:46 +02:00
# include <algorithm>
# include <limits>
# include <cassert>
# include <memory>
2017-11-16 19:30:44 +01:00
# include <vector>
2016-04-12 23:43:46 +02:00
// included for SQL Server specific constants
# include "msodbcsql.h"
2017-01-25 23:05:08 +01:00
# ifdef _WIN32
# include <strsafe.h>
# endif // _WIN32
2016-04-12 23:43:46 +02:00
//*********************************************************************************************************************************
// Constants and Types
//*********************************************************************************************************************************
// constants for maximums in SQL Server
const int SS_MAXCOLNAMELEN = 128 ;
const int SQL_SERVER_MAX_FIELD_SIZE = 8000 ;
const int SQL_SERVER_MAX_PRECISION = 38 ;
const int SQL_SERVER_MAX_TYPE_SIZE = 0 ;
const int SQL_SERVER_MAX_PARAMS = 2100 ;
2018-11-28 02:18:38 +01:00
const int SQL_SERVER_MAX_MONEY_SCALE = 4 ;
2017-09-08 00:26:46 +02:00
// increase the maximum message length to accommodate for the long error returned for operand type clash
2018-05-29 00:08:46 +02:00
// or for conversion of a long string
2018-08-20 23:51:33 +02:00
const int SQL_MAX_ERROR_MESSAGE_LENGTH = SQL_MAX_MESSAGE_LENGTH * 2 ;
2016-04-12 23:43:46 +02:00
// max size of a date time string when converting from a DateTime object to a string
const int MAX_DATETIME_STRING_LEN = 256 ;
2019-04-13 05:49:03 +02:00
// identifier for whether or not we have obtained the number of rows and columns
// of a result
const short ACTIVE_NUM_COLS_INVALID = - 99 ;
const long ACTIVE_NUM_ROWS_INVALID = - 99 ;
2016-04-12 23:43:46 +02:00
// precision and scale for the date time types between servers
const int SQL_SERVER_2005_DEFAULT_DATETIME_PRECISION = 23 ;
const int SQL_SERVER_2005_DEFAULT_DATETIME_SCALE = 3 ;
const int SQL_SERVER_2008_DEFAULT_DATETIME_PRECISION = 34 ;
const int SQL_SERVER_2008_DEFAULT_DATETIME_SCALE = 7 ;
2017-05-06 01:28:33 +02:00
namespace AzureADOptions {
2017-05-06 01:39:51 +02:00
const char AZURE_AUTH_SQL_PASSWORD [ ] = " SqlPassword " ;
const char AZURE_AUTH_AD_PASSWORD [ ] = " ActiveDirectoryPassword " ;
2019-01-12 02:17:45 +01:00
const char AZURE_AUTH_AD_MSI [ ] = " ActiveDirectoryMsi " ;
2017-05-06 01:28:33 +02:00
}
2017-09-15 18:58:47 +02:00
// the message returned by ODBC Driver for SQL Server
const char ODBC_CONNECTION_BUSY_ERROR [ ] = " Connection is busy with results for another command " ;
2016-04-12 23:43:46 +02:00
// types for conversions on output parameters (though they can be used for input parameters, they are ignored)
enum SQLSRV_PHPTYPE {
MIN_SQLSRV_PHPTYPE = 1 , // lowest value for a php type
SQLSRV_PHPTYPE_NULL = 1 ,
SQLSRV_PHPTYPE_INT ,
SQLSRV_PHPTYPE_FLOAT ,
SQLSRV_PHPTYPE_STRING ,
SQLSRV_PHPTYPE_DATETIME ,
SQLSRV_PHPTYPE_STREAM ,
MAX_SQLSRV_PHPTYPE , // highest value for a php type
SQLSRV_PHPTYPE_INVALID = MAX_SQLSRV_PHPTYPE // used to see if a type is invalid
} ;
// encodings supported by this extension. These basically translate into the use of SQL_C_CHAR or SQL_C_BINARY when getting
// information as a string or a stream.
enum SQLSRV_ENCODING {
SQLSRV_ENCODING_INVALID , // unknown or invalid encoding. Used to initialize variables.
SQLSRV_ENCODING_DEFAULT , // use what is the connection's default for a statement, use system if a connection
SQLSRV_ENCODING_BINARY , // use SQL_C_BINARY when using SQLGetData
SQLSRV_ENCODING_CHAR , // use SQL_C_CHAR when using SQLGetData
SQLSRV_ENCODING_SYSTEM = SQLSRV_ENCODING_CHAR ,
SQLSRV_ENCODING_UTF8 = CP_UTF8 ,
} ;
// the array keys used when returning a row via sqlsrv_fetch_array and sqlsrv_fetch_object.
enum SQLSRV_FETCH_TYPE {
MIN_SQLSRV_FETCH = 1 , // lowest value for fetch type
SQLSRV_FETCH_NUMERIC = 1 , // return an array with only numeric indices
SQLSRV_FETCH_ASSOC = 2 , // return an array with keys made from the field names
SQLSRV_FETCH_BOTH = 3 , // return an array indexed with both numbers and keys
MAX_SQLSRV_FETCH = 3 , // highest value for fetch type
} ;
// buffer size of a sql state (including the null character)
const int SQL_SQLSTATE_BUFSIZE = SQL_SQLSTATE_SIZE + 1 ;
2018-11-28 02:18:38 +01:00
// default value of decimal places (no formatting required)
const short NO_CHANGE_DECIMAL_PLACES = - 1 ;
2016-04-12 23:43:46 +02:00
// buffer size allocated to retrieve data from a PHP stream. This number
// was chosen since PHP doesn't return more than 8k at a time even if
// the amount requested was more.
const int PHP_STREAM_BUFFER_SIZE = 8192 ;
// SQL types for parameters encoded in an integer. The type corresponds to the SQL type ODBC constants.
// The size is the column size or precision, and scale is the decimal digits for precise numeric types.
union sqlsrv_sqltype {
struct typeinfo_t {
int type : 9 ;
int size : 14 ;
int scale : 8 ;
} typeinfo ;
zend_long value ;
} ;
// SQLSRV PHP types (as opposed to the Zend PHP type constants). Contains the type (see SQLSRV_PHPTYPE)
// and the encoding for strings and streams (see SQLSRV_ENCODING)
union sqlsrv_phptype {
struct typeinfo_t {
unsigned type : 8 ;
unsigned encoding : 16 ;
} typeinfo ;
zend_long value ;
} ;
// static assert for enforcing compile time conditions
template < bool b >
struct sqlsrv_static_assert ;
template < >
2017-06-22 23:04:34 +02:00
struct sqlsrv_static_assert < true > { _In_ static const int value = 1 ; } ;
2016-04-12 23:43:46 +02:00
# 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
2017-06-22 23:04:34 +02:00
typedef void ( * log_callback ) ( _In_ unsigned int severity TSRMLS_DC , _In_ const char * msg , _In_opt_ va_list * print_args ) ;
2016-04-12 23:43:46 +02:00
// each driver must register a log callback. This should be the first thing a driver does.
2017-06-22 23:04:34 +02:00
void core_sqlsrv_register_logger ( _In_ log_callback ) ;
2016-04-12 23:43:46 +02:00
// a simple wrapper around a PHP error logging function.
2017-06-22 23:04:34 +02:00
void write_to_log ( _In_ unsigned int severity TSRMLS_DC , _In_ const char * msg , . . . ) ;
2016-04-12 23:43:46 +02:00
// a macro to make it convenient to use the function.
2017-01-21 00:14:46 +01:00
# define LOG( severity, msg, ...) write_to_log( severity TSRMLS_CC, msg, ## __VA_ARGS__ )
2016-04-12 23:43:46 +02:00
// 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
2017-06-22 23:04:34 +02:00
void die ( _In_opt_ const char * msg , . . . ) ;
2017-01-21 00:14:46 +01:00
# define DIE( msg, ... ) { die( msg, ## __VA_ARGS__ ); }
2016-04-12 23:43:46 +02:00
//*********************************************************************************************************************************
// 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.
// It's meant for internal use but might be useful for people adding features to our extension.
// To use it, uncomment the #define below and compile in Debug NTS. All allocations and releases
// must be done with sqlsrv_malloc and sqlsrv_free.
// #define SQLSRV_MEM_DEBUG 1
# if defined( PHP_DEBUG ) && !defined( ZTS ) && defined( SQLSRV_MEM_DEBUG )
2017-06-22 23:04:34 +02:00
inline void * sqlsrv_malloc_trace ( _In_ size_t size , _In_ const char * file , _In_ int line )
2016-04-12 23:43:46 +02:00
{
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 ;
}
2017-06-22 23:04:34 +02:00
inline void * sqlsrv_malloc_trace ( _In_ size_t element_count , _In_ size_t element_size , _In_ size_t extra , _In_ const char * file , _In_ int line )
2016-04-12 23:43:46 +02:00
{
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 ;
}
2017-06-22 23:04:34 +02:00
inline void * sqlsrv_realloc_trace ( void * buffer , _In_ size_t size , _In_ const char * file , _In_ int line )
2016-04-12 23:43:46 +02:00
{
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 ;
}
2017-06-22 23:04:34 +02:00
inline void sqlsrv_free_trace ( _Inout_ void * ptr , _In_ const char * file , _In_ int line )
2016-04-12 23:43:46 +02:00
{
LOG ( SEV_NOTICE , " efree %1!08x! at %2!s!:%3!d! " , ptr , file , line ) ;
efree ( ptr ) ;
}
# 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
2017-06-22 23:04:34 +02:00
inline void * sqlsrv_malloc ( _In_ size_t size )
2016-04-12 23:43:46 +02:00
{
return emalloc ( size ) ;
}
2017-06-22 23:04:34 +02:00
inline void * sqlsrv_malloc ( _In_ size_t element_count , _In_ size_t element_size , _In_ size_t extra )
2016-04-12 23:43:46 +02:00
{
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 ) ;
}
2017-06-22 23:04:34 +02:00
inline void * sqlsrv_realloc ( _Inout_ void * buffer , _In_ size_t size )
2016-04-12 23:43:46 +02:00
{
return erealloc ( buffer , size ) ;
}
2017-06-22 23:04:34 +02:00
inline void sqlsrv_free ( _Inout_ void * ptr )
2016-04-12 23:43:46 +02:00
{
efree ( ptr ) ;
}
# endif
// trait class that allows us to assign const types to an auto_ptr
template < typename T >
struct remove_const {
typedef T type ;
} ;
template < typename T >
struct remove_const < const T * > {
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 < typename T >
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 < typename U >
struct rebind {
typedef sqlsrv_allocator < U > other ;
} ;
inline sqlsrv_allocator ( ) { }
inline ~ sqlsrv_allocator ( ) { }
inline sqlsrv_allocator ( sqlsrv_allocator const & ) { }
template < typename U >
inline sqlsrv_allocator ( sqlsrv_allocator < U > const & ) { }
// address (doesn't work if the class defines operator&)
2017-06-22 23:04:34 +02:00
inline pointer address ( _In_ reference r )
2016-04-12 23:43:46 +02:00
{
return & r ;
}
2017-06-22 23:04:34 +02:00
inline const_pointer address ( _In_ const_reference r )
2016-04-12 23:43:46 +02:00
{
return & r ;
}
// memory allocation/deallocation
2017-06-22 23:04:34 +02:00
inline pointer allocate ( _In_ size_type cnt ,
2016-04-12 23:43:46 +02:00
typename std : : allocator < void > : : const_pointer = 0 )
{
return reinterpret_cast < pointer > ( sqlsrv_malloc ( cnt , sizeof ( T ) , 0 ) ) ;
}
2017-06-22 23:04:34 +02:00
inline void deallocate ( _Inout_ pointer p , size_type )
2016-04-12 23:43:46 +02:00
{
sqlsrv_free ( p ) ;
}
// size
inline size_type max_size ( void ) const
{
return std : : numeric_limits < size_type > : : max ( ) / sizeof ( T ) ;
}
// object construction/destruction
2017-06-22 23:04:34 +02:00
inline void construct ( _In_ pointer p , _In_ const T & t )
2016-04-12 23:43:46 +02:00
{
new ( p ) T ( t ) ;
}
2017-06-22 23:04:34 +02:00
inline void destroy ( _Inout_ pointer p )
2016-04-12 23:43:46 +02:00
{
p - > ~ T ( ) ;
}
// equality operators
inline bool operator = = ( sqlsrv_allocator const & )
{
return true ;
}
2017-06-22 23:04:34 +02:00
inline bool operator ! = ( _In_ sqlsrv_allocator const & a )
2016-04-12 23:43:46 +02:00
{
return ! operator = = ( a ) ;
}
} ;
// base class for auto_ptrs that we define below. It provides common operators and functions
// used by all the classes.
template < typename T , typename Subclass >
class sqlsrv_auto_ptr {
public :
sqlsrv_auto_ptr ( void ) : _ptr ( NULL )
{
}
~ sqlsrv_auto_ptr ( void )
{
static_cast < Subclass * > ( this ) - > reset ( NULL ) ;
}
// call when ownership is transferred
void transferred ( void )
{
_ptr = NULL ;
}
// explicit function to get the pointer.
T * get ( void ) const
{
return _ptr ;
}
// cast operator to allow auto_ptr to be used where a normal const * can be.
operator const T * ( ) const
{
return _ptr ;
}
// cast operator to allow auto_ptr to be used where a normal pointer can be.
operator typename remove_const < T * > : : type ( ) const
{
return _ptr ;
}
operator bool ( ) const
{
return _ptr ! = NULL ;
}
// there are a number of places where we allocate a block intended to be accessed as
// an array of elements, so this operator allows us to treat the memory as such.
2017-06-22 23:04:34 +02:00
T & operator [ ] ( _In_ int index ) const
2016-04-12 23:43:46 +02:00
{
2018-08-01 02:22:56 +02:00
return _ptr [ index ] ;
2016-04-12 23:43:46 +02:00
}
// there are a number of places where we allocate a block intended to be accessed as
// an array of elements, so this operator allows us to treat the memory as such.
2017-06-22 23:04:34 +02:00
T & operator [ ] ( _In_ unsigned int index ) const
2016-04-12 23:43:46 +02:00
{
2018-08-01 02:22:56 +02:00
return _ptr [ index ] ;
2016-04-12 23:43:46 +02:00
}
// there are a number of places where we allocate a block intended to be accessed as
// an array of elements, so this operator allows us to treat the memory as such.
2017-06-22 23:04:34 +02:00
T & operator [ ] ( _In_ long index ) const
2016-04-12 23:43:46 +02:00
{
2018-08-01 02:22:56 +02:00
return _ptr [ index ] ;
2016-04-12 23:43:46 +02:00
}
# ifdef __WIN64
// there are a number of places where we allocate a block intended to be accessed as
// an array of elements, so this operator allows us to treat the memory as such.
2017-06-22 23:04:34 +02:00
T & operator [ ] ( _In_ std : : size_t index ) const
2016-04-12 23:43:46 +02:00
{
return _ptr [ index ] ;
}
# endif
// there are a number of places where we allocate a block intended to be accessed as
// an array of elements, so this operator allows us to treat the memory as such.
2017-06-22 23:04:34 +02:00
T & operator [ ] ( _In_ unsigned short index ) const
2016-04-12 23:43:46 +02:00
{
2018-08-01 02:22:56 +02:00
return _ptr [ index ] ;
2016-04-12 23:43:46 +02:00
}
// access elements of a structure through the auto ptr
T * const operator - > ( void ) const
{
return _ptr ;
}
// value from reference operator (i.e., i = *(&i); or *i = blah;)
T & operator * ( ) const
{
return * _ptr ;
}
// allow the use of the address-of operator to simulate a **.
// Note: this operator conflicts with storing these within an STL container. If you need
// to do that, then redefine this as getpp and change instances of &auto_ptr to auto_ptr.getpp()
T * * operator & ( void )
{
return & _ptr ;
}
protected :
2017-06-22 23:04:34 +02:00
sqlsrv_auto_ptr ( _In_opt_ T * ptr ) :
2016-04-12 23:43:46 +02:00
_ptr ( ptr )
{
}
2017-06-22 23:04:34 +02:00
sqlsrv_auto_ptr ( _Inout_opt_ sqlsrv_auto_ptr & src )
2016-04-12 23:43:46 +02:00
{
if ( _ptr ) {
static_cast < Subclass * > ( this ) - > reset ( src . _ptr ) ;
}
src . transferred ( ) ;
}
// assign a new pointer to the auto_ptr. It will free the previous memory block
// because ownership is deemed finished.
2017-06-22 23:04:34 +02:00
T * operator = ( _In_opt_ T * ptr )
2016-04-12 23:43:46 +02:00
{
static_cast < Subclass * > ( this ) - > reset ( ptr ) ;
return ptr ;
}
T * _ptr ;
} ;
// an auto_ptr for sqlsrv_malloc/sqlsrv_free. When allocating a chunk of memory using sqlsrv_malloc, wrap that pointer
// 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 < typename T >
class sqlsrv_malloc_auto_ptr : public sqlsrv_auto_ptr < T , sqlsrv_malloc_auto_ptr < T > > {
public :
sqlsrv_malloc_auto_ptr ( void ) :
sqlsrv_auto_ptr < T , sqlsrv_malloc_auto_ptr < T > > ( NULL )
{
}
2017-06-22 23:04:34 +02:00
sqlsrv_malloc_auto_ptr ( _Inout_opt_ const sqlsrv_malloc_auto_ptr & src ) :
2016-04-12 23:43:46 +02:00
sqlsrv_auto_ptr < T , sqlsrv_malloc_auto_ptr < T > > ( src )
{
}
// free the original pointer and assign a new pointer. Use NULL to simply free the pointer.
2017-06-22 23:04:34 +02:00
void reset ( _In_opt_ T * ptr = NULL )
2016-04-12 23:43:46 +02:00
{
2017-01-21 00:14:46 +01:00
if ( sqlsrv_auto_ptr < T , sqlsrv_malloc_auto_ptr < T > > : : _ptr )
sqlsrv_free ( ( void * ) sqlsrv_auto_ptr < T , sqlsrv_malloc_auto_ptr < T > > : : _ptr ) ;
sqlsrv_auto_ptr < T , sqlsrv_malloc_auto_ptr < T > > : : _ptr = ptr ;
2016-04-12 23:43:46 +02:00
}
2017-06-22 23:04:34 +02:00
T * operator = ( _In_opt_ T * ptr )
2016-04-12 23:43:46 +02:00
{
return sqlsrv_auto_ptr < T , sqlsrv_malloc_auto_ptr < T > > : : operator = ( ptr ) ;
}
2017-06-22 23:04:34 +02:00
void operator = ( _Inout_opt_ sqlsrv_malloc_auto_ptr < T > & src )
2016-04-12 23:43:46 +02:00
{
T * p = src . get ( ) ;
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
2017-06-22 23:04:34 +02:00
void resize ( _In_ size_t new_size )
2017-01-21 00:14:46 +01:00
{
sqlsrv_auto_ptr < T , sqlsrv_malloc_auto_ptr < T > > : : _ptr = reinterpret_cast < T * > ( sqlsrv_realloc ( sqlsrv_auto_ptr < T , sqlsrv_malloc_auto_ptr < T > > : : _ptr , new_size ) ) ;
2016-04-12 23:43:46 +02:00
}
} ;
// auto ptr for Zend hash tables. Used to clean up a hash table allocated when
// something caused an early exit from the function. This is used when the hash_table is
// allocated in a zval that itself can't be released. Otherwise, use the zval_auto_ptr.
class hash_auto_ptr : public sqlsrv_auto_ptr < HashTable , hash_auto_ptr > {
public :
hash_auto_ptr ( void ) :
sqlsrv_auto_ptr < HashTable , hash_auto_ptr > ( NULL )
{
}
// free the original pointer and assign a new pointer. Use NULL to simply free the pointer.
2017-06-22 23:04:34 +02:00
void reset ( _In_opt_ HashTable * ptr = NULL )
2016-04-12 23:43:46 +02:00
{
2018-07-27 00:21:03 +02:00
if ( _ptr ! = NULL ) {
zend_hash_destroy ( _ptr ) ;
FREE_HASHTABLE ( _ptr ) ;
2016-04-12 23:43:46 +02:00
}
_ptr = ptr ;
}
2017-06-22 23:04:34 +02:00
HashTable * operator = ( _In_opt_ HashTable * ptr )
2016-04-12 23:43:46 +02:00
{
return sqlsrv_auto_ptr < HashTable , hash_auto_ptr > : : operator = ( ptr ) ;
}
private :
2017-06-22 23:04:34 +02:00
hash_auto_ptr ( _In_ HashTable const & hash ) ;
2016-04-12 23:43:46 +02:00
2017-06-22 23:04:34 +02:00
hash_auto_ptr ( _In_ hash_auto_ptr const & hash ) ;
2016-04-12 23:43:46 +02:00
} ;
// an auto_ptr for zvals. When allocating a zval, wrap that pointer in a variable of zval_auto_ptr.
// zval_auto_ptr will "own" that zval and assure that it is freed when the variable is destroyed
// (out of scope) or ownership is transferred using the function "transferred".
class zval_auto_ptr : public sqlsrv_auto_ptr < zval , zval_auto_ptr > {
public :
zval_auto_ptr ( void )
{
}
// free the original pointer and assign a new pointer. Use NULL to simply free the pointer.
2017-06-22 23:04:34 +02:00
void reset ( _In_opt_ zval * ptr = NULL )
2016-04-12 23:43:46 +02:00
{
if ( _ptr )
zval_ptr_dtor ( _ptr ) ;
_ptr = ptr ;
}
2017-06-22 23:04:34 +02:00
zval * operator = ( _In_opt_ zval * ptr )
2016-04-12 23:43:46 +02:00
{
return sqlsrv_auto_ptr < zval , zval_auto_ptr > : : operator = ( ptr ) ;
}
private :
2017-06-22 23:04:34 +02:00
zval_auto_ptr ( _In_ const zval_auto_ptr & src ) ;
2016-04-12 23:43:46 +02:00
} ;
# pragma pop_macro( "max" )
//*********************************************************************************************************************************
// sqlsrv_error
//*********************************************************************************************************************************
// *** PHP specific errors ***
// sqlsrv errors are held in a structure of this type used by the driver handle_error functions
// format is a flag that tells the driver error handler functions if there are parameters to use with FormatMessage
// into the error message before returning it.
// base class which can be instatiated with aggregates (see error constants)
struct sqlsrv_error_const {
SQLCHAR * sqlstate ;
SQLCHAR * native_message ;
SQLINTEGER native_code ;
bool format ;
} ;
// subclass which is used by the core layer to instantiate ODBC errors
struct sqlsrv_error : public sqlsrv_error_const {
sqlsrv_error ( void )
{
sqlstate = NULL ;
native_message = NULL ;
native_code = - 1 ;
format = false ;
}
2017-06-22 23:04:34 +02:00
sqlsrv_error ( _In_ SQLCHAR * sql_state , _In_ SQLCHAR * message , _In_ SQLINTEGER code , _In_ bool printf_format = false )
2016-04-12 23:43:46 +02:00
{
sqlstate = reinterpret_cast < SQLCHAR * > ( sqlsrv_malloc ( SQL_SQLSTATE_BUFSIZE ) ) ;
2017-09-06 01:51:40 +02:00
native_message = reinterpret_cast < SQLCHAR * > ( sqlsrv_malloc ( SQL_MAX_ERROR_MESSAGE_LENGTH + 1 ) ) ;
2016-04-12 23:43:46 +02:00
strcpy_s ( reinterpret_cast < char * > ( sqlstate ) , SQL_SQLSTATE_BUFSIZE , reinterpret_cast < const char * > ( sql_state ) ) ;
2017-09-06 01:51:40 +02:00
strcpy_s ( reinterpret_cast < char * > ( native_message ) , SQL_MAX_ERROR_MESSAGE_LENGTH + 1 , reinterpret_cast < const char * > ( message ) ) ;
2016-04-12 23:43:46 +02:00
native_code = code ;
format = printf_format ;
}
2017-06-22 23:04:34 +02:00
sqlsrv_error ( _In_ sqlsrv_error_const const & prototype )
2016-04-12 23:43:46 +02:00
{
sqlsrv_error ( prototype . sqlstate , prototype . native_message , prototype . native_code , prototype . format ) ;
}
~ sqlsrv_error ( void )
{
if ( sqlstate ! = NULL ) {
sqlsrv_free ( sqlstate ) ;
}
if ( native_message ! = NULL ) {
sqlsrv_free ( native_message ) ;
}
}
} ;
// an auto_ptr for sqlsrv_errors. These call the destructor explicitly rather than call delete
class sqlsrv_error_auto_ptr : public sqlsrv_auto_ptr < sqlsrv_error , sqlsrv_error_auto_ptr > {
public :
sqlsrv_error_auto_ptr ( void ) :
sqlsrv_auto_ptr < sqlsrv_error , sqlsrv_error_auto_ptr > ( NULL )
{
}
2017-06-22 23:04:34 +02:00
sqlsrv_error_auto_ptr ( _Inout_opt_ sqlsrv_error_auto_ptr const & src ) :
2016-04-12 23:43:46 +02:00
sqlsrv_auto_ptr < sqlsrv_error , sqlsrv_error_auto_ptr > ( ( sqlsrv_error_auto_ptr & ) src )
{
}
// free the original pointer and assign a new pointer. Use NULL to simply free the pointer.
2017-06-22 23:04:34 +02:00
void reset ( _In_opt_ sqlsrv_error * ptr = NULL )
2016-04-12 23:43:46 +02:00
{
if ( _ptr ) {
_ptr - > ~ sqlsrv_error ( ) ;
sqlsrv_free ( ( void * ) _ptr ) ;
}
_ptr = ptr ;
}
2017-06-22 23:04:34 +02:00
sqlsrv_error * operator = ( _In_opt_ sqlsrv_error * ptr )
2016-04-12 23:43:46 +02:00
{
return sqlsrv_auto_ptr < sqlsrv_error , sqlsrv_error_auto_ptr > : : operator = ( ptr ) ;
}
// unlike traditional assignment operators, the chained assignment of an auto_ptr doesn't make much
// sense. Only the last one would have anything in it.
2017-06-22 23:04:34 +02:00
void operator = ( _Inout_opt_ sqlsrv_error_auto_ptr & src )
2016-04-12 23:43:46 +02:00
{
sqlsrv_error * p = src . get ( ) ;
src . transferred ( ) ;
2017-01-21 00:14:46 +01:00
reset ( p ) ;
2016-04-12 23:43:46 +02:00
}
} ;
//*********************************************************************************************************************************
// Context
//*********************************************************************************************************************************
class sqlsrv_context ;
struct sqlsrv_conn ;
// error_callback
// a driver specific callback for processing errors.
// ctx - the context holding the handles
// sqlsrv_error_code - specific error code to return.
2017-06-22 23:04:34 +02:00
typedef bool ( * error_callback ) ( _Inout_ sqlsrv_context & ctx , _In_ unsigned int sqlsrv_error_code , _In_ bool error TSRMLS_DC , _In_opt_ va_list * print_args ) ;
2016-04-12 23:43:46 +02:00
// sqlsrv_context
// a context holds relevant information to be passed with a connection and statement objects.
class sqlsrv_context {
public :
2017-06-22 23:04:34 +02:00
sqlsrv_context ( _In_opt_ SQLSMALLINT type , _In_ error_callback e , _In_opt_ void * drv , _In_ SQLSRV_ENCODING encoding = SQLSRV_ENCODING_INVALID ) :
2016-04-12 23:43:46 +02:00
handle_ ( SQL_NULL_HANDLE ) ,
handle_type_ ( type ) ,
name_ ( NULL ) ,
2017-01-21 00:14:46 +01:00
err_ ( e ) ,
2016-04-12 23:43:46 +02:00
driver_ ( drv ) ,
last_error_ ( ) ,
encoding_ ( encoding )
{
}
2017-06-22 23:04:34 +02:00
sqlsrv_context ( _In_ SQLHANDLE h , _In_opt_ SQLSMALLINT t , _In_ error_callback e , _In_opt_ void * drv , _In_ SQLSRV_ENCODING encoding = SQLSRV_ENCODING_INVALID ) :
2016-04-12 23:43:46 +02:00
handle_ ( h ) ,
handle_type_ ( t ) ,
name_ ( NULL ) ,
2017-01-21 00:14:46 +01:00
err_ ( e ) ,
2016-04-12 23:43:46 +02:00
driver_ ( drv ) ,
last_error_ ( ) ,
encoding_ ( encoding )
{
}
2017-06-22 23:04:34 +02:00
sqlsrv_context ( _In_ sqlsrv_context const & ctx ) :
2016-04-12 23:43:46 +02:00
handle_ ( ctx . handle_ ) ,
handle_type_ ( ctx . handle_type_ ) ,
name_ ( ctx . name_ ) ,
2017-01-21 00:14:46 +01:00
err_ ( ctx . err_ ) ,
2016-04-12 23:43:46 +02:00
driver_ ( ctx . driver_ ) ,
last_error_ ( ctx . last_error_ )
{
}
2017-01-21 00:14:46 +01:00
virtual ~ sqlsrv_context ( )
{
}
2017-06-22 23:04:34 +02:00
void set_func ( _In_z_ const char * f )
2016-04-12 23:43:46 +02:00
{
name_ = f ;
}
2017-06-22 23:04:34 +02:00
void set_last_error ( _In_ sqlsrv_error_auto_ptr & last_error )
2016-04-12 23:43:46 +02:00
{
last_error_ = last_error ;
}
sqlsrv_error_auto_ptr & last_error ( void )
{
return last_error_ ;
}
// since the primary responsibility of a context is to hold an ODBC handle, we
// provide these convenience operators for using them interchangeably
operator SQLHANDLE ( void ) const
{
return handle_ ;
}
error_callback error_handler ( void ) const
{
return err_ ;
}
SQLHANDLE handle ( void ) const
{
return handle_ ;
}
SQLSMALLINT handle_type ( void ) const
{
return handle_type_ ;
}
const char * func ( void ) const
{
return name_ ;
}
void * driver ( void ) const
{
return driver_ ;
}
2017-06-22 23:04:34 +02:00
void set_driver ( _In_ void * driver )
2016-04-12 23:43:46 +02:00
{
this - > driver_ = driver ;
}
void invalidate ( void )
{
if ( handle_ ! = SQL_NULL_HANDLE ) {
: : SQLFreeHandle ( handle_type_ , handle_ ) ;
2016-07-06 20:47:05 +02:00
last_error_ . reset ( ) ;
2016-04-12 23:43:46 +02:00
}
handle_ = SQL_NULL_HANDLE ;
}
bool valid ( void )
{
return handle_ ! = SQL_NULL_HANDLE ;
}
SQLSRV_ENCODING encoding ( void ) const
{
return encoding_ ;
}
2017-06-22 23:04:34 +02:00
void set_encoding ( _In_ SQLSRV_ENCODING e )
2016-04-12 23:43:46 +02:00
{
encoding_ = e ;
}
private :
SQLHANDLE handle_ ; // ODBC handle for this context
SQLSMALLINT handle_type_ ; // type of the ODBC handle
const char * name_ ; // function name currently executing this context
error_callback err_ ; // driver error callback if error occurs in core layer
void * driver_ ; // points back to the driver for PDO
sqlsrv_error_auto_ptr last_error_ ; // last error that happened on this object
SQLSRV_ENCODING encoding_ ; // encoding of the context
} ;
const int SQLSRV_OS_VISTA_OR_LATER = 6 ; // major version for Vista
// maps an IANA encoding to a code page
struct sqlsrv_encoding {
const char * iana ;
size_t iana_len ;
unsigned int code_page ;
bool not_for_connection ;
2017-06-22 23:04:34 +02:00
sqlsrv_encoding ( _In_ const char * iana , _In_ unsigned int code_page , _In_ bool not_for_conn = false ) :
2018-04-14 00:06:10 +02:00
iana ( iana ) , iana_len ( strnlen_s ( iana ) ) , code_page ( code_page ) , not_for_connection ( not_for_conn )
2016-04-12 23:43:46 +02:00
{
}
} ;
//*********************************************************************************************************************************
// Initialization
//*********************************************************************************************************************************
// variables set during initialization
2017-06-29 21:23:46 +02:00
extern bool isVistaOrGreater ; // used to determine if OS is Vista or Greater
2016-04-12 23:43:46 +02:00
extern HashTable * g_encodings ; // encodings supported by this driver
2017-06-22 23:04:34 +02:00
void core_sqlsrv_minit ( _Outptr_ sqlsrv_context * * henv_cp , _Inout_ sqlsrv_context * * henv_ncp , _In_ error_callback err , _In_z_ const char * driver_func TSRMLS_DC ) ;
void core_sqlsrv_mshutdown ( _Inout_ sqlsrv_context & henv_cp , _Inout_ sqlsrv_context & henv_ncp ) ;
2016-04-12 23:43:46 +02:00
// environment context used by sqlsrv_connect for when a connection error occurs.
struct sqlsrv_henv {
sqlsrv_context ctx ;
2017-06-22 23:04:34 +02:00
sqlsrv_henv ( _In_ SQLHANDLE handle , _In_ error_callback e , _In_opt_ void * drv ) :
2016-04-12 23:43:46 +02:00
ctx ( handle , SQL_HANDLE_ENV , e , drv )
{
}
} ;
//*********************************************************************************************************************************
// Connection
//*********************************************************************************************************************************
// supported server versions (determined at connection time)
enum SERVER_VERSION {
SERVER_VERSION_UNKNOWN = - 1 ,
SERVER_VERSION_2000 = 8 ,
SERVER_VERSION_2005 ,
SERVER_VERSION_2008 , // use this for anything 2008 or later
} ;
2016-06-13 23:44:53 +02:00
// supported driver versions.
2017-09-14 18:34:48 +02:00
// the latest RTWed ODBC is the first one
2017-09-27 01:38:34 +02:00
enum DRIVER_VERSION {
ODBC_DRIVER_UNKNOWN = - 1 ,
2017-09-06 19:55:08 +02:00
FIRST = 0 ,
2018-01-03 00:26:33 +01:00
ODBC_DRIVER_17 = FIRST ,
ODBC_DRIVER_13 = 1 ,
ODBC_DRIVER_11 = 2 ,
LAST = ODBC_DRIVER_11
2016-06-13 23:44:53 +02:00
} ;
2016-04-12 23:43:46 +02:00
// forward decl
struct sqlsrv_stmt ;
struct stmt_option ;
2017-07-25 20:01:00 +02:00
// This holds the various details of column encryption.
struct col_encryption_option {
2018-09-26 23:51:16 +02:00
bool enabled ; // column encryption enabled, false by default
SQLINTEGER akv_mode ;
sqlsrv_malloc_auto_ptr < char > akv_id ;
sqlsrv_malloc_auto_ptr < char > akv_secret ;
bool akv_required ;
2017-07-25 20:01:00 +02:00
2018-05-14 21:04:25 +02:00
col_encryption_option ( ) : enabled ( false ) , akv_mode ( - 1 ) , akv_required ( false )
2017-07-25 20:01:00 +02:00
{
}
2018-09-26 23:51:16 +02:00
void akv_reset ( )
{
akv_id . reset ( ) ;
akv_secret . reset ( ) ;
akv_required = false ;
akv_mode = - 1 ;
}
2017-07-25 20:01:00 +02:00
} ;
2016-04-12 23:43:46 +02:00
// *** connection resource structure ***
// this is the resource structure returned when a connection is made.
struct sqlsrv_conn : public sqlsrv_context {
// instance variables
SERVER_VERSION server_version ; // version of the server that we're connected to
2017-07-25 20:01:00 +02:00
col_encryption_option ce_option ; // holds the details of what are required to enable column encryption
2017-09-27 01:38:34 +02:00
DRIVER_VERSION driver_version ; // version of ODBC driver
2016-06-13 23:44:53 +02:00
2018-09-06 20:32:04 +02:00
sqlsrv_malloc_auto_ptr < ACCESSTOKEN > azure_ad_access_token ;
2016-04-12 23:43:46 +02:00
// initialize with default values
2017-06-22 23:04:34 +02:00
sqlsrv_conn ( _In_ SQLHANDLE h , _In_ error_callback e , _In_opt_ void * drv , _In_ SQLSRV_ENCODING encoding TSRMLS_DC ) :
2016-04-12 23:43:46 +02:00
sqlsrv_context ( h , SQL_HANDLE_DBC , e , drv , encoding )
{
2017-01-21 00:14:46 +01:00
server_version = SERVER_VERSION_UNKNOWN ;
2017-09-27 01:38:34 +02:00
driver_version = ODBC_DRIVER_UNKNOWN ;
2016-04-12 23:43:46 +02:00
}
// sqlsrv_conn has no destructor since its allocated using placement new, which requires that the destructor be
// called manually. Instead, we leave it to the allocator to invalidate the handle when an error occurs allocating
// the sqlsrv_conn with a connection.
} ;
enum SQLSRV_STMT_OPTIONS {
SQLSRV_STMT_OPTION_INVALID ,
SQLSRV_STMT_OPTION_QUERY_TIMEOUT ,
SQLSRV_STMT_OPTION_SEND_STREAMS_AT_EXEC ,
SQLSRV_STMT_OPTION_SCROLLABLE ,
SQLSRV_STMT_OPTION_CLIENT_BUFFER_MAX_SIZE ,
2018-09-18 01:25:02 +02:00
SQLSRV_STMT_OPTION_DATE_AS_STRING ,
2018-10-13 00:22:27 +02:00
SQLSRV_STMT_OPTION_FORMAT_DECIMALS ,
2018-11-28 02:18:38 +01:00
SQLSRV_STMT_OPTION_DECIMAL_PLACES ,
2019-05-01 17:03:33 +02:00
SQLSRV_STMT_OPTION_DATA_CLASSIFICATION ,
2016-04-12 23:43:46 +02:00
// Driver specific connection options
SQLSRV_STMT_OPTION_DRIVER_SPECIFIC = 1000 ,
} ;
namespace ODBCConnOptions {
const char APP [ ] = " APP " ;
2018-09-06 20:32:04 +02:00
const char AccessToken [ ] = " AccessToken " ;
2016-04-12 23:43:46 +02:00
const char ApplicationIntent [ ] = " ApplicationIntent " ;
const char AttachDBFileName [ ] = " AttachDbFileName " ;
2017-05-06 01:28:33 +02:00
const char Authentication [ ] = " Authentication " ;
2017-09-09 01:47:43 +02:00
const char Driver [ ] = " Driver " ;
2016-04-12 23:43:46 +02:00
const char CharacterSet [ ] = " CharacterSet " ;
const char ConnectionPooling [ ] = " ConnectionPooling " ;
2019-02-13 13:56:12 +01:00
const char Language [ ] = " Language " ;
2018-02-08 18:00:16 +01:00
const char ColumnEncryption [ ] = " ColumnEncryption " ;
2017-04-04 22:40:30 +02:00
const char ConnectRetryCount [ ] = " ConnectRetryCount " ;
const char ConnectRetryInterval [ ] = " ConnectRetryInterval " ;
2016-04-12 23:43:46 +02:00
const char Database [ ] = " Database " ;
const char Encrypt [ ] = " Encrypt " ;
const char Failover_Partner [ ] = " Failover_Partner " ;
2018-05-06 02:08:01 +02:00
const char KeyStoreAuthentication [ ] = " KeyStoreAuthentication " ;
const char KeyStorePrincipalId [ ] = " KeyStorePrincipalId " ;
const char KeyStoreSecret [ ] = " KeyStoreSecret " ;
2016-04-12 23:43:46 +02:00
const char LoginTimeout [ ] = " LoginTimeout " ;
const char MARS_ODBC [ ] = " MARS_Connection " ;
const char MultiSubnetFailover [ ] = " MultiSubnetFailover " ;
const char QuotedId [ ] = " QuotedId " ;
const char TraceFile [ ] = " TraceFile " ;
const char TraceOn [ ] = " TraceOn " ;
const char TrustServerCertificate [ ] = " TrustServerCertificate " ;
const char TransactionIsolation [ ] = " TransactionIsolation " ;
2017-06-07 22:53:04 +02:00
const char TransparentNetworkIPResolution [ ] = " TransparentNetworkIPResolution " ;
2016-04-12 23:43:46 +02:00
const char WSID [ ] = " WSID " ;
const char UID [ ] = " UID " ;
const char PWD [ ] = " PWD " ;
const char SERVER [ ] = " Server " ;
}
enum SQLSRV_CONN_OPTIONS {
2017-04-04 22:40:30 +02:00
SQLSRV_CONN_OPTION_INVALID ,
SQLSRV_CONN_OPTION_APP ,
2018-09-06 20:32:04 +02:00
SQLSRV_CONN_OPTION_ACCESS_TOKEN ,
2017-04-04 22:40:30 +02:00
SQLSRV_CONN_OPTION_CHARACTERSET ,
SQLSRV_CONN_OPTION_CONN_POOLING ,
2019-02-13 13:56:12 +01:00
SQLSRV_CONN_OPTION_LANGUAGE ,
2017-04-04 22:40:30 +02:00
SQLSRV_CONN_OPTION_DATABASE ,
SQLSRV_CONN_OPTION_ENCRYPT ,
SQLSRV_CONN_OPTION_FAILOVER_PARTNER ,
SQLSRV_CONN_OPTION_LOGIN_TIMEOUT ,
SQLSRV_CONN_OPTION_MARS ,
SQLSRV_CONN_OPTION_QUOTED_ID ,
SQLSRV_CONN_OPTION_TRACE_FILE ,
SQLSRV_CONN_OPTION_TRACE_ON ,
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 ,
2017-05-06 01:39:51 +02:00
SQLSRV_CONN_OPTION_AUTHENTICATION ,
2017-07-25 20:01:00 +02:00
SQLSRV_CONN_OPTION_COLUMNENCRYPTION ,
2017-09-09 01:47:43 +02:00
SQLSRV_CONN_OPTION_DRIVER ,
2017-08-23 21:36:24 +02:00
SQLSRV_CONN_OPTION_CEKEYSTORE_PROVIDER ,
SQLSRV_CONN_OPTION_CEKEYSTORE_NAME ,
SQLSRV_CONN_OPTION_CEKEYSTORE_ENCRYPT_KEY ,
2018-05-06 02:08:01 +02:00
SQLSRV_CONN_OPTION_KEYSTORE_AUTHENTICATION ,
SQLSRV_CONN_OPTION_KEYSTORE_PRINCIPAL_ID ,
SQLSRV_CONN_OPTION_KEYSTORE_SECRET ,
SQLSRV_CONN_OPTION_TRANSPARENT_NETWORK_IP_RESOLUTION ,
2017-04-04 22:40:30 +02:00
SQLSRV_CONN_OPTION_CONN_RETRY_COUNT ,
SQLSRV_CONN_OPTION_CONN_RETRY_INTERVAL ,
2016-04-12 23:43:46 +02:00
// Driver specific connection options
SQLSRV_CONN_OPTION_DRIVER_SPECIFIC = 1000 ,
} ;
# define NO_ATTRIBUTE -1
// type of connection attributes
enum CONN_ATTR_TYPE {
CONN_ATTR_INT ,
CONN_ATTR_BOOL ,
CONN_ATTR_STRING ,
CONN_ATTR_INVALID ,
} ;
// a connection option that includes the callback function that handles that option (e.g., adds it to the connection string or
// sets an attribute)
struct connection_option {
// the name of the option as passed in by the user
const char * sqlsrv_name ;
unsigned int sqlsrv_len ;
unsigned int conn_option_key ;
// the name of the option in the ODBC connection string
const char * odbc_name ;
unsigned int odbc_len ;
enum CONN_ATTR_TYPE value_type ;
// process the connection type
// return whether or not the function was successful in processing the connection option
void ( * func ) ( connection_option const * , zval * value , sqlsrv_conn * conn , std : : string & conn_str TSRMLS_DC ) ;
} ;
2017-09-12 01:17:24 +02:00
// connection attribute functions
2016-04-12 23:43:46 +02:00
// simply add the parsed value to the connection string
struct conn_str_append_func {
2017-06-22 23:04:34 +02:00
static void func ( _In_ connection_option const * option , _In_ zval * value , sqlsrv_conn * /*conn*/ , _Inout_ std : : string & conn_str TSRMLS_DC ) ;
2016-04-12 23:43:46 +02:00
} ;
struct conn_null_func {
2017-09-09 01:47:43 +02:00
static void func ( connection_option const * /*option*/ , zval * /*value*/ , sqlsrv_conn * /*conn*/ , std : : string & /*conn_str*/ TSRMLS_DC ) ;
2016-04-12 23:43:46 +02:00
} ;
2017-09-09 01:47:43 +02:00
struct column_encryption_set_func {
2017-09-15 03:21:25 +02:00
static void func ( _In_ connection_option const * option , _In_ zval * value , _Inout_ sqlsrv_conn * conn , _Inout_ std : : string & conn_str TSRMLS_DC ) ;
2017-09-09 01:47:43 +02:00
} ;
2017-09-14 21:00:51 +02:00
struct driver_set_func {
2017-09-15 03:21:25 +02:00
static void func ( _In_ connection_option const * option , _In_ zval * value , _Inout_ sqlsrv_conn * conn , _Inout_ std : : string & conn_str TSRMLS_DC ) ;
2017-09-09 01:47:43 +02:00
} ;
2018-05-06 02:08:01 +02:00
struct ce_akv_str_set_func {
static void func ( _In_ connection_option const * option , _In_ zval * value , _Inout_ sqlsrv_conn * conn , _Inout_ std : : string & conn_str TSRMLS_DC ) ;
} ;
2018-09-06 20:32:04 +02:00
struct access_token_set_func {
static void func ( _In_ connection_option const * option , _In_ zval * value , _Inout_ sqlsrv_conn * conn , _Inout_ std : : string & conn_str TSRMLS_DC ) ;
} ;
2017-09-09 01:47:43 +02:00
2016-04-12 23:43:46 +02:00
// factory to create a connection (since they are subclassed to instantiate statements)
2017-06-22 23:04:34 +02:00
typedef sqlsrv_conn * ( * driver_conn_factory ) ( _In_ SQLHANDLE h , _In_ error_callback e , _In_ void * drv TSRMLS_DC ) ;
2016-04-12 23:43:46 +02:00
// *** connection functions ***
2017-06-22 23:04:34 +02:00
sqlsrv_conn * core_sqlsrv_connect ( _In_ sqlsrv_context & henv_cp , _In_ sqlsrv_context & henv_ncp , _In_ driver_conn_factory conn_factory ,
_Inout_z_ const char * server , _Inout_opt_z_ const char * uid , _Inout_opt_z_ const char * pwd ,
_Inout_opt_ HashTable * options_ht , _In_ error_callback err , _In_ const connection_option valid_conn_opts [ ] ,
_In_ void * driver , _In_z_ const char * driver_func TSRMLS_DC ) ;
2017-09-27 01:38:34 +02:00
SQLRETURN core_odbc_connect ( _Inout_ sqlsrv_conn * conn , _Inout_ std : : string & conn_str , _In_ bool is_pooled ) ;
2017-06-22 23:04:34 +02:00
void core_sqlsrv_close ( _Inout_opt_ sqlsrv_conn * conn TSRMLS_DC ) ;
void core_sqlsrv_prepare ( _Inout_ sqlsrv_stmt * stmt , _In_reads_bytes_ ( sql_len ) const char * sql , _In_ SQLLEN sql_len TSRMLS_DC ) ;
void core_sqlsrv_begin_transaction ( _Inout_ sqlsrv_conn * conn TSRMLS_DC ) ;
void core_sqlsrv_commit ( _Inout_ sqlsrv_conn * conn TSRMLS_DC ) ;
void core_sqlsrv_rollback ( _Inout_ sqlsrv_conn * conn TSRMLS_DC ) ;
void core_sqlsrv_get_server_info ( _Inout_ sqlsrv_conn * conn , _Out_ zval * server_info TSRMLS_DC ) ;
void core_sqlsrv_get_server_version ( _Inout_ sqlsrv_conn * conn , _Inout_ zval * server_version TSRMLS_DC ) ;
void core_sqlsrv_get_client_info ( _Inout_ sqlsrv_conn * conn , _Out_ zval * client_info TSRMLS_DC ) ;
2017-07-01 00:17:14 +02:00
bool core_is_conn_opt_value_escaped ( _Inout_ const char * value , _Inout_ size_t value_len ) ;
2017-06-22 23:04:34 +02:00
size_t core_str_zval_is_true ( _Inout_ zval * str_zval ) ;
bool core_is_authentication_option_valid ( _In_z_ const char * value , _In_ size_t value_len ) ;
2017-09-27 01:38:34 +02:00
bool core_search_odbc_driver_unix ( _In_ DRIVER_VERSION driver_version ) ;
bool core_compare_error_state ( _In_ sqlsrv_conn * conn , _In_ SQLRETURN r , _In_ const char * error_state ) ;
2016-04-12 23:43:46 +02:00
//*********************************************************************************************************************************
// Statement
//*********************************************************************************************************************************
struct stmt_option_functor {
2017-06-22 23:04:34 +02:00
virtual void operator ( ) ( _Inout_ sqlsrv_stmt * /*stmt*/ , stmt_option const * /*opt*/ , _In_ zval * /*value_z*/ TSRMLS_DC ) ;
2016-04-12 23:43:46 +02:00
} ;
struct stmt_option_query_timeout : public stmt_option_functor {
2017-06-22 23:04:34 +02:00
virtual void operator ( ) ( _Inout_ sqlsrv_stmt * stmt , stmt_option const * opt , _In_ zval * value_z TSRMLS_DC ) ;
2016-04-12 23:43:46 +02:00
} ;
struct stmt_option_send_at_exec : public stmt_option_functor {
2017-06-22 23:04:34 +02:00
virtual void operator ( ) ( _Inout_ sqlsrv_stmt * stmt , stmt_option const * opt , _In_ zval * value_z TSRMLS_DC ) ;
2016-04-12 23:43:46 +02:00
} ;
struct stmt_option_buffered_query_limit : public stmt_option_functor {
2017-06-22 23:04:34 +02:00
virtual void operator ( ) ( _Inout_ sqlsrv_stmt * stmt , stmt_option const * opt , _In_ zval * value_z TSRMLS_DC ) ;
2016-04-12 23:43:46 +02:00
} ;
2018-09-18 01:25:02 +02:00
struct stmt_option_date_as_string : public stmt_option_functor {
virtual void operator ( ) ( _Inout_ sqlsrv_stmt * stmt , stmt_option const * opt , _In_ zval * value_z TSRMLS_DC ) ;
} ;
2018-10-13 00:22:27 +02:00
struct stmt_option_format_decimals : public stmt_option_functor {
virtual void operator ( ) ( _Inout_ sqlsrv_stmt * stmt , stmt_option const * opt , _In_ zval * value_z TSRMLS_DC ) ;
} ;
2018-11-28 02:18:38 +01:00
struct stmt_option_decimal_places : public stmt_option_functor {
virtual void operator ( ) ( _Inout_ sqlsrv_stmt * stmt , stmt_option const * opt , _In_ zval * value_z TSRMLS_DC ) ;
} ;
2019-05-01 17:03:33 +02:00
struct stmt_option_data_classification : public stmt_option_functor {
virtual void operator ( ) ( _Inout_ sqlsrv_stmt * stmt , stmt_option const * opt , _In_ zval * value_z TSRMLS_DC ) ;
} ;
2016-04-12 23:43:46 +02:00
// used to hold the table for statment options
struct stmt_option {
const char * name ; // name of the statement option
unsigned int name_len ; // name length
unsigned int key ;
std : : unique_ptr < stmt_option_functor > func ; // callback that actually handles the work of the option
} ;
// holds the stream param and the encoding that it was assigned
struct sqlsrv_stream {
zval * stream_z ;
SQLSRV_ENCODING encoding ;
SQLUSMALLINT field_index ;
SQLSMALLINT sql_type ;
sqlsrv_stmt * stmt ;
2017-06-22 23:04:34 +02:00
sqlsrv_stream ( _In_opt_ zval * str_z , _In_ SQLSRV_ENCODING enc ) :
2017-01-21 00:14:46 +01:00
stream_z ( str_z ) , encoding ( enc ) , field_index ( 0 ) , sql_type ( SQL_UNKNOWN_TYPE ) , stmt ( NULL )
2016-04-12 23:43:46 +02:00
{
}
2017-01-21 00:14:46 +01:00
sqlsrv_stream ( ) : stream_z ( NULL ) , encoding ( SQLSRV_ENCODING_INVALID ) , field_index ( 0 ) , sql_type ( SQL_UNKNOWN_TYPE ) , stmt ( NULL )
2016-04-12 23:43:46 +02:00
{
}
} ;
// close any active stream
2016-07-06 20:47:05 +02:00
void close_active_stream ( _Inout_ sqlsrv_stmt * stmt TSRMLS_DC ) ;
2016-04-12 23:43:46 +02:00
extern php_stream_wrapper g_sqlsrv_stream_wrapper ;
// resource constants used when registering the stream type with PHP
# define SQLSRV_STREAM_WRAPPER "sqlsrv"
# define SQLSRV_STREAM "sqlsrv_stream"
2018-10-13 00:22:27 +02:00
// *** parameter metadata struct ***
struct param_meta_data
{
SQLSMALLINT sql_type ;
SQLSMALLINT decimal_digits ;
SQLSMALLINT nullable ;
SQLULEN column_size ;
param_meta_data ( ) : sql_type ( 0 ) , decimal_digits ( 0 ) , column_size ( 0 ) , nullable ( 0 )
{
}
~ param_meta_data ( )
{
}
SQLSMALLINT get_sql_type ( ) { return sql_type ; }
SQLSMALLINT get_decimal_digits ( ) { return decimal_digits ; }
SQLSMALLINT get_nullable ( ) { return nullable ; }
SQLULEN get_column_size ( ) { return column_size ; }
} ;
2016-04-12 23:43:46 +02:00
// holds the output parameter information. Strings also need the encoding and other information for
// after processing. Only integer, float, and strings are allowable output parameters.
struct sqlsrv_output_param {
zval * param_z ;
SQLSRV_ENCODING encoding ;
2018-10-13 00:22:27 +02:00
SQLUSMALLINT param_num ; // used to index into the ind_or_len of the statement
SQLLEN original_buffer_len ; // used to make sure the returned length didn't overflow the buffer
SQLSRV_PHPTYPE php_out_type ; // used to convert output param if necessary
2016-04-12 23:43:46 +02:00
bool is_bool ;
2018-11-28 02:18:38 +01:00
param_meta_data meta_data ; // parameter meta data
2016-04-12 23:43:46 +02:00
// string output param constructor
2018-04-10 02:15:58 +02:00
sqlsrv_output_param ( _In_ zval * p_z , _In_ SQLSRV_ENCODING enc , _In_ int num , _In_ SQLUINTEGER buffer_len ) :
2018-04-26 00:43:56 +02:00
param_z ( p_z ) , encoding ( enc ) , param_num ( num ) , original_buffer_len ( buffer_len ) , is_bool ( false ) , php_out_type ( SQLSRV_PHPTYPE_INVALID )
2016-04-12 23:43:46 +02:00
{
}
// every other type output parameter constructor
2018-04-26 00:43:56 +02:00
sqlsrv_output_param ( _In_ zval * p_z , _In_ int num , _In_ bool is_bool , _In_ SQLSRV_PHPTYPE php_out_type ) :
2016-04-12 23:43:46 +02:00
param_z ( p_z ) ,
encoding ( SQLSRV_ENCODING_INVALID ) ,
2017-01-21 00:14:46 +01:00
param_num ( num ) ,
2016-04-12 23:43:46 +02:00
original_buffer_len ( - 1 ) ,
2018-04-26 00:43:56 +02:00
is_bool ( is_bool ) ,
php_out_type ( php_out_type )
2016-04-12 23:43:46 +02:00
{
}
2018-10-13 00:22:27 +02:00
void saveMetaData ( SQLSMALLINT sql_type , SQLSMALLINT column_size , SQLSMALLINT decimal_digits , SQLSMALLINT nullable = SQL_NULLABLE )
{
meta_data . sql_type = sql_type ;
meta_data . column_size = column_size ;
meta_data . decimal_digits = decimal_digits ;
meta_data . nullable = nullable ;
2017-11-16 19:30:44 +01:00
}
2018-11-28 02:18:38 +01:00
param_meta_data & getMetaData ( )
2018-10-13 00:22:27 +02:00
{
2018-11-28 02:18:38 +01:00
return meta_data ;
2017-11-16 19:30:44 +01:00
}
} ;
2019-05-01 17:03:33 +02:00
namespace data_classification {
// *** data classficiation metadata structures and helper methods -- to store and/or process the sensitivity classification data ***
struct name_id_pair ;
struct sensitivity_metadata ;
void name_id_pair_free ( name_id_pair * pair ) ;
2019-05-09 00:18:15 +02:00
void parse_sensitivity_name_id_pairs ( _Inout_ sqlsrv_stmt * stmt , _Inout_ USHORT & numpairs , _Inout_ std : : vector < name_id_pair * , sqlsrv_allocator < name_id_pair * > > * pairs , _Inout_ unsigned char * * pptr TSRMLS_CC ) ;
2019-05-01 17:03:33 +02:00
void parse_column_sensitivity_props ( _Inout_ sensitivity_metadata * meta , _Inout_ unsigned char * * pptr ) ;
USHORT fill_column_sensitivity_array ( _Inout_ sqlsrv_stmt * stmt , _In_ SQLSMALLINT colno , _Inout_ zval * column_data TSRMLS_CC ) ;
struct name_id_pair {
UCHAR name_len ;
sqlsrv_malloc_auto_ptr < char > name ;
UCHAR id_len ;
sqlsrv_malloc_auto_ptr < char > id ;
name_id_pair ( ) : name_len ( 0 ) , id_len ( 0 )
{
}
~ name_id_pair ( )
{
}
} ;
struct label_infotype_pair {
USHORT label_idx ;
USHORT infotype_idx ;
label_infotype_pair ( ) : label_idx ( 0 ) , infotype_idx ( 0 )
{
}
} ;
struct column_sensitivity {
USHORT num_pairs ;
std : : vector < label_infotype_pair > label_info_pairs ;
column_sensitivity ( ) : num_pairs ( 0 )
{
}
~ column_sensitivity ( )
{
label_info_pairs . clear ( ) ;
}
} ;
struct sensitivity_metadata {
USHORT num_labels ;
std : : vector < name_id_pair * , sqlsrv_allocator < name_id_pair * > > labels ;
USHORT num_infotypes ;
std : : vector < name_id_pair * , sqlsrv_allocator < name_id_pair * > > infotypes ;
USHORT num_columns ;
std : : vector < column_sensitivity > columns_sensitivity ;
sensitivity_metadata ( ) : num_labels ( 0 ) , num_infotypes ( 0 ) , num_columns ( 0 )
{
}
~ sensitivity_metadata ( )
{
reset ( ) ;
}
void reset ( ) ;
} ;
} // namespace data_classification
2018-10-13 00:22:27 +02:00
// forward decls
struct sqlsrv_result_set ;
struct field_meta_data ;
2016-04-12 23:43:46 +02:00
// *** Statement resource structure ***
struct sqlsrv_stmt : public sqlsrv_context {
void free_param_data ( TSRMLS_D ) ;
virtual void new_result_set ( TSRMLS_D ) ;
2019-05-01 17:03:33 +02:00
// free sensitivity classification metadata
void clean_up_sensitivity_metadata ( ) ;
2016-04-12 23:43:46 +02:00
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
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
2019-04-05 21:34:33 +02:00
bool past_next_result_end ; // core_sqlsrv_next_result sets this to true when the statement goes beyond the last results
2019-04-11 21:33:39 +02:00
short column_count ; // Number of columns in the current result set obtained from SQLNumResultCols
long row_count ; // Number of rows in the current result set obtained from SQLRowCount
2016-04-12 23:43:46 +02:00
unsigned long query_timeout ; // maximum allowed statement execution time
2017-11-10 00:24:08 +01:00
zend_long buffered_query_limit ; // maximum allowed memory for a buffered query (measured in KB)
2018-09-18 01:25:02 +02:00
bool date_as_string ; // false by default but the user can set this to true to retrieve datetime values as strings
2018-11-28 02:18:38 +01:00
bool format_decimals ; // false by default but the user can set this to true to add the missing leading zeroes and/or control number of decimal digits to show
short decimal_places ; // indicates number of decimals shown in fetched results (-1 by default, which means no change to number of decimal digits)
2019-05-01 17:03:33 +02:00
bool data_classification ; // false by default but the user can set this to true to retrieve data classification sensitivity metadata
2016-04-12 23:43:46 +02:00
// 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
// memory, which is important because we pass the pointer to an element of the deque to SQLBindParameter to hold
std : : deque < SQLLEN > param_ind_ptrs ; // output pointers for lengths for calls to SQLBindParameter
2017-11-10 00:24:08 +01:00
zval param_input_strings ; // hold all UTF-16 input strings that aren't managed by PHP
zval output_params ; // hold all the output parameters
zval param_streams ; // track which streams to send data to the server
zval param_datetime_buffers ; // datetime strings to be converted back to DateTime objects
2016-04-12 23:43:46 +02:00
bool send_streams_at_exec ; // send all stream data right after execution before returning
sqlsrv_stream current_stream ; // current stream sending data to the server as an input parameter
unsigned int current_stream_read ; // # of bytes read so far. (if we read an empty PHP stream, we send an empty string
// to the server)
2017-11-10 00:24:08 +01:00
zval field_cache ; // cache for a single row of fields, to allow multiple and out of order retrievals
zval col_cache ; // Used by get_field_as_string not to call SQLColAttribute() after every fetch.
zval active_stream ; // the currently active stream reading data from the database
2016-04-12 23:43:46 +02:00
2017-11-16 19:30:44 +01:00
std : : vector < param_meta_data > param_descriptions ;
2018-10-06 00:01:18 +02:00
// meta data for current result set
std : : vector < field_meta_data * , sqlsrv_allocator < field_meta_data * > > current_meta_data ;
2019-05-01 17:03:33 +02:00
// meta data for data classification
sqlsrv_malloc_auto_ptr < data_classification : : sensitivity_metadata > current_sensitivity_metadata ;
2017-06-22 23:04:34 +02:00
sqlsrv_stmt ( _In_ sqlsrv_conn * c , _In_ SQLHANDLE handle , _In_ error_callback e , _In_opt_ void * drv TSRMLS_DC ) ;
2016-04-12 23:43:46 +02:00
virtual ~ sqlsrv_stmt ( void ) ;
// driver specific conversion rules from a SQL Server/ODBC type to one of the SQLSRV_PHPTYPE_* constants
2017-06-22 23:04:34 +02:00
virtual sqlsrv_phptype sql_type_to_php_type ( _In_ SQLINTEGER sql_type , _In_ SQLUINTEGER size , _In_ bool prefer_string_to_stream ) = 0 ;
2016-04-12 23:43:46 +02:00
} ;
// *** field metadata struct ***
struct field_meta_data {
sqlsrv_malloc_auto_ptr < SQLCHAR > field_name ;
SQLSMALLINT field_name_len ;
SQLSMALLINT field_type ;
SQLULEN field_size ;
SQLULEN field_precision ;
SQLSMALLINT field_scale ;
SQLSMALLINT field_is_nullable ;
2018-11-28 02:18:38 +01:00
bool field_is_money_type ;
2016-04-12 23:43:46 +02:00
field_meta_data ( ) : field_name_len ( 0 ) , field_type ( 0 ) , field_size ( 0 ) , field_precision ( 0 ) ,
2018-11-28 02:18:38 +01:00
field_scale ( 0 ) , field_is_nullable ( 0 ) , field_is_money_type ( false )
2016-04-12 23:43:46 +02:00
{
}
~ field_meta_data ( )
{
}
} ;
// *** statement constants ***
// unknown column size used by core_sqlsrv_bind_param when the user doesn't supply a value
const SQLULEN SQLSRV_UNKNOWN_SIZE = 0xffffffff ;
const int SQLSRV_DEFAULT_SIZE = - 1 ; // size given for an output parameter that doesn't really need one (e.g., int)
// uninitialized query timeout value
const unsigned int QUERY_TIMEOUT_INVALID = 0xffffffff ;
// special buffered query constant
2017-01-27 02:06:17 +01:00
# ifndef _WIN32
2017-01-21 00:14:46 +01:00
const size_t SQLSRV_CURSOR_BUFFERED = 42 ; // arbitrary number that doesn't map to any other SQL_CURSOR_* constant
# else
2016-04-12 23:43:46 +02:00
const size_t SQLSRV_CURSOR_BUFFERED = 0xfffffffeUL ; // arbitrary number that doesn't map to any other SQL_CURSOR_* constant
2017-01-27 02:06:17 +01:00
# endif // !_WIN32
2016-04-12 23:43:46 +02:00
// factory to create a statement
typedef sqlsrv_stmt * ( * driver_stmt_factory ) ( sqlsrv_conn * conn , SQLHANDLE h , error_callback e , void * drv TSRMLS_DC ) ;
// *** statement functions ***
2017-06-22 23:04:34 +02:00
sqlsrv_stmt * core_sqlsrv_create_stmt ( _Inout_ sqlsrv_conn * conn , _In_ driver_stmt_factory stmt_factory , _In_opt_ HashTable * options_ht ,
_In_opt_ const stmt_option valid_stmt_opts [ ] , _In_ error_callback const err , _In_opt_ void * driver TSRMLS_DC ) ;
void core_sqlsrv_bind_param ( _Inout_ sqlsrv_stmt * stmt , _In_ SQLUSMALLINT param_num , _In_ SQLSMALLINT direction , _Inout_ zval * param_z ,
2017-10-18 00:37:59 +02:00
_In_ SQLSRV_PHPTYPE php_out_type , _Inout_ SQLSRV_ENCODING encoding , _Inout_ SQLSMALLINT sql_type , _Inout_ SQLULEN column_size ,
2017-06-22 23:04:34 +02:00
_Inout_ SQLSMALLINT decimal_digits TSRMLS_DC ) ;
SQLRETURN core_sqlsrv_execute ( _Inout_ sqlsrv_stmt * stmt TSRMLS_DC , _In_reads_bytes_ ( sql_len ) const char * sql = NULL , _In_ int sql_len = 0 ) ;
field_meta_data * core_sqlsrv_field_metadata ( _Inout_ sqlsrv_stmt * stmt , _In_ SQLSMALLINT colno TSRMLS_DC ) ;
bool core_sqlsrv_fetch ( _Inout_ sqlsrv_stmt * stmt , _In_ SQLSMALLINT fetch_orientation , _In_ SQLULEN fetch_offset TSRMLS_DC ) ;
void core_sqlsrv_get_field ( _Inout_ sqlsrv_stmt * stmt , _In_ SQLUSMALLINT field_index , _In_ sqlsrv_phptype sqlsrv_phptype , _In_ bool prefer_string ,
_Outref_result_bytebuffer_maybenull_ ( * field_length ) void * & field_value , _Inout_ SQLLEN * field_length , _In_ bool cache_field ,
2016-07-06 20:47:05 +02:00
_Out_ SQLSRV_PHPTYPE * sqlsrv_php_type_out TSRMLS_DC ) ;
2017-06-22 23:04:34 +02:00
bool core_sqlsrv_has_any_result ( _Inout_ sqlsrv_stmt * stmt TSRMLS_DC ) ;
void core_sqlsrv_next_result ( _Inout_ sqlsrv_stmt * stmt TSRMLS_DC , _In_ bool finalize_output_params = true , _In_ bool throw_on_errors = true ) ;
void core_sqlsrv_post_param ( _Inout_ sqlsrv_stmt * stmt , _In_ zend_ulong paramno , zval * param_z TSRMLS_DC ) ;
void core_sqlsrv_set_scrollable ( _Inout_ sqlsrv_stmt * stmt , _In_ unsigned long cursor_type TSRMLS_DC ) ;
void core_sqlsrv_set_query_timeout ( _Inout_ sqlsrv_stmt * stmt , _In_ long timeout TSRMLS_DC ) ;
void core_sqlsrv_set_query_timeout ( _Inout_ sqlsrv_stmt * stmt , _Inout_ zval * value_z TSRMLS_DC ) ;
void core_sqlsrv_set_send_at_exec ( _Inout_ sqlsrv_stmt * stmt , _In_ zval * value_z TSRMLS_DC ) ;
bool core_sqlsrv_send_stream_packet ( _Inout_ sqlsrv_stmt * stmt TSRMLS_DC ) ;
void core_sqlsrv_set_buffered_query_limit ( _Inout_ sqlsrv_stmt * stmt , _In_ zval * value_z TSRMLS_DC ) ;
void core_sqlsrv_set_buffered_query_limit ( _Inout_ sqlsrv_stmt * stmt , _In_ SQLLEN limit TSRMLS_DC ) ;
2018-11-28 02:18:38 +01:00
void core_sqlsrv_set_decimal_places ( _Inout_ sqlsrv_stmt * stmt , _In_ zval * value_z TSRMLS_DC ) ;
2019-05-01 17:03:33 +02:00
void core_sqlsrv_sensitivity_metadata ( _Inout_ sqlsrv_stmt * stmt TSRMLS_DC ) ;
2016-04-12 23:43:46 +02:00
//*********************************************************************************************************************************
// Result Set
//*********************************************************************************************************************************
// 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).
struct sqlsrv_result_set {
sqlsrv_stmt * odbc ;
2017-06-22 23:04:34 +02:00
explicit sqlsrv_result_set ( _In_ sqlsrv_stmt * ) ;
2016-04-12 23:43:46 +02:00
virtual ~ sqlsrv_result_set ( void ) { }
virtual bool cached ( int field_index ) = 0 ;
2017-06-22 23:04:34 +02:00
virtual SQLRETURN fetch ( _Inout_ SQLSMALLINT fetch_orientation , _Inout_opt_ SQLLEN fetch_offset TSRMLS_DC ) = 0 ;
virtual SQLRETURN get_data ( _In_ SQLUSMALLINT field_index , _In_ SQLSMALLINT target_type ,
_Out_writes_bytes_opt_ ( buffer_length ) void * buffer , _In_ SQLLEN buffer_length , _Inout_ SQLLEN * out_buffer_length ,
2016-04-12 23:43:46 +02:00
bool handle_warning TSRMLS_DC ) = 0 ;
2017-06-22 23:04:34 +02:00
virtual SQLRETURN get_diag_field ( _In_ SQLSMALLINT record_number , _In_ SQLSMALLINT diag_identifier ,
_Inout_updates_ ( buffer_length ) SQLPOINTER diag_info_buffer , _In_ SQLSMALLINT buffer_length ,
_Inout_ SQLSMALLINT * out_buffer_length TSRMLS_DC ) = 0 ;
virtual sqlsrv_error * get_diag_rec ( _In_ SQLSMALLINT record_number ) = 0 ;
2016-04-12 23:43:46 +02:00
virtual SQLLEN row_count ( TSRMLS_D ) = 0 ;
} ;
struct sqlsrv_odbc_result_set : public sqlsrv_result_set {
2017-06-22 23:04:34 +02:00
explicit sqlsrv_odbc_result_set ( _In_ sqlsrv_stmt * ) ;
2016-04-12 23:43:46 +02:00
virtual ~ sqlsrv_odbc_result_set ( void ) ;
virtual bool cached ( int field_index ) { return false ; }
2017-06-22 23:04:34 +02:00
virtual SQLRETURN fetch ( _In_ SQLSMALLINT fetch_orientation , _In_ SQLLEN fetch_offset TSRMLS_DC ) ;
virtual SQLRETURN get_data ( _In_ SQLUSMALLINT field_index , _In_ SQLSMALLINT target_type ,
_Out_writes_opt_ ( buffer_length ) void * buffer , _In_ SQLLEN buffer_length , _Inout_ SQLLEN * out_buffer_length ,
_In_ bool handle_warning TSRMLS_DC ) ;
virtual SQLRETURN get_diag_field ( _In_ SQLSMALLINT record_number , _In_ SQLSMALLINT diag_identifier ,
_Inout_updates_ ( buffer_length ) SQLPOINTER diag_info_buffer , _In_ SQLSMALLINT buffer_length ,
_Inout_ SQLSMALLINT * out_buffer_length TSRMLS_DC ) ;
virtual sqlsrv_error * get_diag_rec ( _In_ SQLSMALLINT record_number ) ;
2016-04-12 23:43:46 +02:00
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 zend_long BUFFERED_QUERY_LIMIT_DEFAULT = 10240 ; // measured in KB
static const zend_long BUFFERED_QUERY_LIMIT_INVALID = 0 ;
2017-06-22 23:04:34 +02:00
explicit sqlsrv_buffered_result_set ( _Inout_ sqlsrv_stmt * odbc TSRMLS_DC ) ;
2016-04-12 23:43:46 +02:00
virtual ~ sqlsrv_buffered_result_set ( void ) ;
virtual bool cached ( int field_index ) { return true ; }
2017-06-22 23:04:34 +02:00
virtual SQLRETURN fetch ( _Inout_ SQLSMALLINT fetch_orientation , _Inout_opt_ SQLLEN fetch_offset TSRMLS_DC ) ;
virtual SQLRETURN get_data ( _In_ SQLUSMALLINT field_index , _In_ SQLSMALLINT target_type ,
_Out_writes_bytes_opt_ ( buffer_length ) void * buffer , _In_ SQLLEN buffer_length , _Inout_ SQLLEN * out_buffer_length ,
2016-04-12 23:43:46 +02:00
bool handle_warning TSRMLS_DC ) ;
2017-06-22 23:04:34 +02:00
virtual SQLRETURN get_diag_field ( _In_ SQLSMALLINT record_number , _In_ SQLSMALLINT diag_identifier ,
_Inout_updates_ ( buffer_length ) SQLPOINTER diag_info_buffer , _In_ SQLSMALLINT buffer_length ,
_Inout_ SQLSMALLINT * out_buffer_length TSRMLS_DC ) ;
virtual sqlsrv_error * get_diag_rec ( _In_ SQLSMALLINT record_number ) ;
2016-04-12 23:43:46 +02:00
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
2017-02-24 22:29:09 +01:00
sqlsrv_malloc_auto_ptr < meta_data > meta ; // metadata for fields in the cache
2016-04-12 23:43:46 +02:00
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 < SQLCHAR > temp_string ; // temp buffer to hold a converted field while in use
SQLLEN temp_length ; // number of bytes in the temp conversion buffer
2017-06-22 23:04:34 +02:00
typedef SQLRETURN ( sqlsrv_buffered_result_set : : * conv_fn ) ( _In_ SQLSMALLINT field_index , _Out_writes_z_ ( * out_buffer_length ) void * buffer , _In_ SQLLEN buffer_length ,
_Inout_ SQLLEN * out_buffer_length ) ;
2016-04-12 23:43:46 +02:00
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
2017-06-22 23:04:34 +02:00
SQLRETURN binary_to_wide_string ( _In_ SQLSMALLINT field_index , _Out_writes_z_ ( * out_buffer_length ) void * buffer , _In_ SQLLEN buffer_length ,
_Inout_ SQLLEN * out_buffer_length ) ;
SQLRETURN binary_to_system_string ( _In_ SQLSMALLINT field_index , _Out_writes_z_ ( * out_buffer_length ) void * buffer , _In_ SQLLEN buffer_length ,
_Inout_ SQLLEN * out_buffer_length ) ;
SQLRETURN system_to_wide_string ( _In_ SQLSMALLINT field_index , _Out_writes_z_ ( * out_buffer_length ) void * buffer , _In_ SQLLEN buffer_length ,
2016-07-06 20:47:05 +02:00
_Out_ SQLLEN * out_buffer_length ) ;
2017-06-22 23:04:34 +02:00
SQLRETURN to_binary_string ( _In_ SQLSMALLINT field_index , _Out_writes_bytes_to_opt_ ( buffer_length , * out_buffer_length ) void * buffer , _In_ SQLLEN buffer_length ,
2016-07-06 20:47:05 +02:00
_Out_ SQLLEN * out_buffer_length ) ;
2017-06-22 23:04:34 +02:00
SQLRETURN to_same_string ( _In_ SQLSMALLINT field_index , _Out_writes_bytes_to_opt_ ( buffer_length , * out_buffer_length ) void * buffer , _In_ SQLLEN buffer_length ,
2016-07-06 20:47:05 +02:00
_Out_ SQLLEN * out_buffer_length ) ;
2017-06-22 23:04:34 +02:00
SQLRETURN wide_to_system_string ( _In_ SQLSMALLINT field_index , _Inout_updates_bytes_to_ ( buffer_length , * out_buffer_length ) void * buffer , _In_ SQLLEN buffer_length ,
_Inout_ SQLLEN * out_buffer_length ) ;
2016-04-12 23:43:46 +02:00
// long conversion functions
2017-06-22 23:04:34 +02:00
SQLRETURN to_long ( _In_ SQLSMALLINT field_index , _Out_writes_bytes_to_opt_ ( buffer_length , * out_buffer_length ) void * buffer , _In_ SQLLEN buffer_length , _Out_ SQLLEN * out_buffer_length ) ;
SQLRETURN long_to_system_string ( _In_ SQLSMALLINT field_index , _Out_writes_bytes_to_opt_ ( buffer_length , * out_buffer_length ) void * buffer , _In_ SQLLEN buffer_length ,
_Inout_ SQLLEN * out_buffer_length ) ;
SQLRETURN long_to_wide_string ( _In_ SQLSMALLINT field_index , _Out_writes_bytes_to_opt_ ( buffer_length , * out_buffer_length ) void * buffer , _In_ SQLLEN buffer_length ,
_Inout_ SQLLEN * out_buffer_length ) ;
SQLRETURN long_to_double ( _In_ SQLSMALLINT field_index , _Out_writes_bytes_ ( * out_buffer_length ) void * buffer , _In_ SQLLEN buffer_length ,
2016-07-06 20:47:05 +02:00
_Out_ SQLLEN * out_buffer_length ) ;
2016-04-12 23:43:46 +02:00
// double conversion functions
2017-06-22 23:04:34 +02:00
SQLRETURN to_double ( _In_ SQLSMALLINT field_index , _Out_writes_bytes_to_opt_ ( buffer_length , * out_buffer_length ) void * buffer , _In_ SQLLEN buffer_length , _Out_ SQLLEN * out_buffer_length ) ;
SQLRETURN double_to_system_string ( _In_ SQLSMALLINT field_index , _Out_writes_bytes_to_opt_ ( buffer_length , * out_buffer_length ) void * buffer , _In_ SQLLEN buffer_length ,
_Inout_ SQLLEN * out_buffer_length ) ;
SQLRETURN double_to_wide_string ( _In_ SQLSMALLINT field_index , _Out_writes_bytes_to_opt_ ( buffer_length , * out_buffer_length ) void * buffer , _In_ SQLLEN buffer_length ,
_Inout_ SQLLEN * out_buffer_length ) ;
SQLRETURN double_to_long ( _In_ SQLSMALLINT field_index , _Inout_updates_bytes_ ( * out_buffer_length ) void * buffer , _In_ SQLLEN buffer_length ,
_Inout_ SQLLEN * out_buffer_length ) ;
2016-04-12 23:43:46 +02:00
// string to number conversion functions
// Future: See if these can be converted directly to template member functions
2017-06-22 23:04:34 +02:00
SQLRETURN string_to_double ( _In_ SQLSMALLINT field_index , _Out_writes_bytes_ ( * out_buffer_length ) void * buffer , _In_ SQLLEN buffer_length ,
_Inout_ SQLLEN * out_buffer_length ) ;
SQLRETURN string_to_long ( _In_ SQLSMALLINT field_index , _Out_writes_bytes_ ( * out_buffer_length ) void * buffer , _In_ SQLLEN buffer_length ,
_Inout_ SQLLEN * out_buffer_length ) ;
SQLRETURN wstring_to_double ( _In_ SQLSMALLINT field_index , _Out_writes_bytes_ ( * out_buffer_length ) void * buffer , _In_ SQLLEN buffer_length ,
_Inout_ SQLLEN * out_buffer_length ) ;
SQLRETURN wstring_to_long ( _In_ SQLSMALLINT field_index , _Out_writes_bytes_ ( * out_buffer_length ) void * buffer , _In_ SQLLEN buffer_length ,
_Inout_ SQLLEN * out_buffer_length ) ;
2016-04-12 23:43:46 +02:00
// utility functions for conversions
unsigned char * get_row ( void ) ;
} ;
//*********************************************************************************************************************************
// Utility
//*********************************************************************************************************************************
// Simple macro to alleviate unused variable warnings. These are optimized out by the compiler.
// We use this since the unused variables are buried in the PHP_FUNCTION macro.
# define SQLSRV_UNUSED( var ) var;
// do a heap check in debug mode, but only print errors, not all of the allocations
# define MEMCHECK_SILENT 1
// utility functions shared by multiple callers across files
2017-06-22 23:04:34 +02:00
bool convert_string_from_utf16_inplace ( _In_ SQLSRV_ENCODING encoding , _Inout_updates_z_ ( len ) char * * string , _Inout_ SQLLEN & len ) ;
bool validate_string ( _In_ char * string , _In_ SQLLEN & len ) ;
bool convert_string_from_utf16 ( _In_ SQLSRV_ENCODING encoding , _In_reads_bytes_ ( cchInLen ) const SQLWCHAR * inString , _In_ SQLINTEGER cchInLen , _Inout_updates_bytes_ ( cchOutLen ) char * * outString , _Out_ SQLLEN & cchOutLen ) ;
2019-05-10 22:03:22 +02:00
SQLWCHAR * utf16_string_from_mbcs_string ( _In_ SQLSRV_ENCODING php_encoding , _In_reads_bytes_ ( mbcs_len ) const char * mbcs_string , _In_ unsigned int mbcs_len , _Out_ unsigned int * utf16_len , bool use_strict_conversion = false ) ;
2016-04-12 23:43:46 +02:00
//*********************************************************************************************************************************
// Error handling routines and Predefined Errors
//*********************************************************************************************************************************
enum SQLSRV_ERROR_CODES {
SQLSRV_ERROR_ODBC ,
SQLSRV_ERROR_DRIVER_NOT_INSTALLED ,
2017-09-30 00:54:34 +02:00
SQLSRV_ERROR_CE_DRIVER_REQUIRED ,
2017-09-12 22:30:14 +02:00
SQLSRV_ERROR_CONNECT_INVALID_DRIVER ,
2017-09-28 22:22:00 +02:00
SQLSRV_ERROR_SPECIFIED_DRIVER_NOT_FOUND ,
2016-04-12 23:43:46 +02:00
SQLSRV_ERROR_ZEND_HASH ,
SQLSRV_ERROR_INVALID_PARAMETER_PHPTYPE ,
SQLSRV_ERROR_INVALID_PARAMETER_SQLTYPE ,
SQLSRV_ERROR_INVALID_PARAMETER_ENCODING ,
SQLSRV_ERROR_INPUT_PARAM_ENCODING_TRANSLATE ,
SQLSRV_ERROR_OUTPUT_PARAM_ENCODING_TRANSLATE ,
SQLSRV_ERROR_CONNECT_STRING_ENCODING_TRANSLATE ,
SQLSRV_ERROR_ZEND_STREAM ,
SQLSRV_ERROR_INPUT_STREAM_ENCODING_TRANSLATE ,
SQLSRV_ERROR_UNKNOWN_SERVER_VERSION ,
SQLSRV_ERROR_FETCH_PAST_END ,
SQLSRV_ERROR_STATEMENT_NOT_EXECUTED ,
SQLSRV_ERROR_NO_FIELDS ,
SQLSRV_ERROR_INVALID_TYPE ,
SQLSRV_ERROR_FETCH_NOT_CALLED ,
SQLSRV_ERROR_NO_DATA ,
SQLSRV_ERROR_FIELD_ENCODING_TRANSLATE ,
SQLSRV_ERROR_ZEND_HASH_CREATE_FAILED ,
SQLSRV_ERROR_NEXT_RESULT_PAST_END ,
SQLSRV_ERROR_UID_PWD_BRACES_NOT_ESCAPED ,
SQLSRV_ERROR_INVALID_OPTION_TYPE_INT ,
SQLSRV_ERROR_INVALID_OPTION_TYPE_STRING ,
SQLSRV_ERROR_CONN_OPTS_WRONG_TYPE ,
SQLSRV_ERROR_INVALID_CONNECTION_KEY ,
SQLSRV_ERROR_MAX_PARAMS_EXCEEDED ,
SQLSRV_ERROR_INVALID_OPTION_KEY ,
SQLSRV_ERROR_INVALID_QUERY_TIMEOUT_VALUE ,
SQLSRV_ERROR_INVALID_OPTION_SCROLLABLE ,
SQLSRV_ERROR_QUERY_STRING_ENCODING_TRANSLATE ,
SQLSRV_ERROR_OUTPUT_PARAM_TRUNCATED ,
SQLSRV_ERROR_INPUT_OUTPUT_PARAM_TYPE_MATCH ,
SQLSRV_ERROR_DATETIME_CONVERSION_FAILED ,
SQLSRV_ERROR_STREAMABLE_TYPES_ONLY ,
SQLSRV_ERROR_STREAM_CREATE ,
SQLSRV_ERROR_MARS_OFF ,
SQLSRV_ERROR_FIELD_INDEX_ERROR ,
SQLSRV_ERROR_BUFFER_LIMIT_EXCEEDED ,
SQLSRV_ERROR_INVALID_BUFFER_LIMIT ,
2017-11-03 18:00:08 +01:00
SQLSRV_ERROR_OUTPUT_PARAM_TYPES_NOT_SUPPORTED ,
2018-05-06 02:08:01 +02:00
SQLSRV_ERROR_INVALID_AKV_AUTHENTICATION_OPTION ,
SQLSRV_ERROR_AKV_AUTH_MISSING ,
SQLSRV_ERROR_AKV_NAME_MISSING ,
SQLSRV_ERROR_AKV_SECRET_MISSING ,
2018-05-08 23:12:14 +02:00
SQLSRV_ERROR_KEYSTORE_INVALID_VALUE ,
2018-04-26 00:43:56 +02:00
SQLSRV_ERROR_DOUBLE_CONVERSION_FAILED ,
2018-09-06 20:32:04 +02:00
SQLSRV_ERROR_INVALID_OPTION_WITH_ACCESS_TOKEN ,
SQLSRV_ERROR_EMPTY_ACCESS_TOKEN ,
2018-11-28 02:18:38 +01:00
SQLSRV_ERROR_INVALID_DECIMAL_PLACES ,
2019-01-12 02:17:45 +01:00
SQLSRV_ERROR_AAD_MSI_UID_PWD_NOT_NULL ,
2019-05-01 17:03:33 +02:00
SQLSRV_ERROR_DATA_CLASSIFICATION_PRE_EXECUTION ,
SQLSRV_ERROR_DATA_CLASSIFICATION_NOT_AVAILABLE ,
SQLSRV_ERROR_DATA_CLASSIFICATION_FAILED ,
2016-04-12 23:43:46 +02:00
// Driver specific error codes starts from here.
SQLSRV_ERROR_DRIVER_SPECIFIC = 1000 ,
} ;
// SQLSTATE for all internal errors
extern SQLCHAR IMSSP [ ] ;
// SQLSTATE for all internal warnings
extern SQLCHAR SSPWARN [ ] ;
// flags passed to sqlsrv_errors to filter its return values
enum error_handling_flags {
SQLSRV_ERR_ERRORS ,
SQLSRV_ERR_WARNINGS ,
SQLSRV_ERR_ALL
} ;
// *** internal error macros and functions ***
// call to retrieve an error from ODBC. This uses SQLGetDiagRec, so the
// errno is 1 based. It returns it as an array with 3 members:
// 1/SQLSTATE) sqlstate
// 2/code) driver specific error code
// 3/message) driver specific error message
// The fetch type determines if the indices are numeric, associative, or both.
2017-06-22 23:04:34 +02:00
bool core_sqlsrv_get_odbc_error ( _Inout_ sqlsrv_context & ctx , _In_ int record_number , _Inout_ sqlsrv_error_auto_ptr & error ,
_In_ logging_severity severity TSRMLS_DC ) ;
2016-04-12 23:43:46 +02:00
// format and return a driver specfic error
2017-06-22 23:04:34 +02:00
void core_sqlsrv_format_driver_error ( _In_ sqlsrv_context & ctx , _In_ sqlsrv_error_const const * custom_error ,
_Out_ sqlsrv_error_auto_ptr & formatted_error , _In_ logging_severity severity TSRMLS_DC , _In_opt_ va_list * args ) ;
2016-04-12 23:43:46 +02:00
// return the message for the HRESULT returned by GetLastError. Some driver errors use this to
// return the Windows error, e.g, when a UTF-8 <-> UTF-16 conversion fails.
2017-06-22 23:04:34 +02:00
const char * get_last_error_message ( _Inout_ DWORD last_error = 0 ) ;
2016-04-12 23:43:46 +02:00
// a wrapper around FormatMessage that can take variadic args rather than a a va_arg pointer
2017-06-22 23:04:34 +02:00
DWORD core_sqlsrv_format_message ( _Out_ char * output_buffer , _In_ unsigned output_len , _In_opt_ const char * format , . . . ) ;
2016-04-12 23:43:46 +02:00
// convenience functions that overload either a reference or a pointer so we can use
// either in the CHECK_* functions.
2017-06-22 23:04:34 +02:00
inline bool call_error_handler ( _Inout_ sqlsrv_context & ctx , _In_ unsigned long sqlsrv_error_code TSRMLS_DC , _In_ bool warning , . . . )
2016-04-12 23:43:46 +02:00
{
va_list print_params ;
va_start ( print_params , warning ) ;
bool ignored = ctx . error_handler ( ) ( ctx , sqlsrv_error_code , warning TSRMLS_CC , & print_params ) ;
va_end ( print_params ) ;
return ignored ;
}
2017-06-22 23:04:34 +02:00
inline bool call_error_handler ( _Inout_ sqlsrv_context * ctx , _In_ unsigned long sqlsrv_error_code TSRMLS_DC , _In_ bool warning , . . . )
2016-04-12 23:43:46 +02:00
{
va_list print_params ;
va_start ( print_params , warning ) ;
bool ignored = ctx - > error_handler ( ) ( * ctx , sqlsrv_error_code , warning TSRMLS_CC , & print_params ) ;
va_end ( print_params ) ;
return ignored ;
}
// PHP equivalent of ASSERT. C asserts cause a dialog to show and halt the process which
// we don't want on a web server
2017-01-24 02:22:15 +01:00
# define SQLSRV_ASSERT( condition, msg, ...) if( !(condition)) DIE( msg, ## __VA_ARGS__ );
2016-04-12 23:43:46 +02:00
# if defined( PHP_DEBUG )
# define DEBUG_SQLSRV_ASSERT( condition, msg, ... ) \
if ( ! ( condition ) ) { \
2017-01-24 02:22:15 +01:00
DIE ( msg , # # __VA_ARGS__ ) ; \
2016-04-12 23:43:46 +02:00
}
# else
# define DEBUG_SQLSRV_ASSERT( condition, msg, ... ) ((void)0)
# endif
// check to see if the sqlstate is 01004, truncated field retrieved. Used for retrieving large fields.
2017-06-22 23:04:34 +02:00
inline bool is_truncated_warning ( _In_ SQLCHAR * state )
2016-04-12 23:43:46 +02:00
{
# if defined(ZEND_DEBUG)
2018-04-14 00:06:10 +02:00
if ( state = = NULL | | strnlen_s ( reinterpret_cast < char * > ( state ) ) ! = 5 ) { \
2016-04-12 23:43:46 +02:00
DIE ( " Incorrect SQLSTATE given to is_truncated_warning. " ) ; \
}
# endif
return ( state [ 0 ] = = ' 0 ' & & state [ 1 ] = = ' 1 ' & & state [ 2 ] = = ' 0 ' & & state [ 3 ] = = ' 0 ' & & state [ 4 ] = = ' 4 ' ) ;
}
// Macros for handling errors. These macros are simplified if statements that take boilerplate
// code down to a single line to avoid distractions in the code.
# define CHECK_ERROR_EX( unique, condition, context, ssphp, ... ) \
bool flag # # unique = ( condition ) ; \
bool ignored # # unique = true ; \
if ( flag # # unique ) { \
2017-01-24 02:22:15 +01:00
ignored # # unique = call_error_handler ( context , ssphp TSRMLS_CC , /*warning*/ false , # # __VA_ARGS__ ) ; \
2016-04-12 23:43:46 +02:00
} \
if ( ! ignored # # unique )
# define CHECK_ERROR_UNIQUE( unique, condition, context, ssphp, ...) \
2017-01-24 02:22:15 +01:00
CHECK_ERROR_EX ( unique , condition , context , ssphp , # # __VA_ARGS__ )
2016-04-12 23:43:46 +02:00
# define CHECK_ERROR( condition, context, ... ) \
2017-01-24 02:22:15 +01:00
CHECK_ERROR_UNIQUE ( __COUNTER__ , condition , context , 0 , # # __VA_ARGS__ )
2016-04-12 23:43:46 +02:00
# define CHECK_CUSTOM_ERROR( condition, context, ssphp, ... ) \
2017-01-24 02:22:15 +01:00
CHECK_ERROR_UNIQUE ( __COUNTER__ , condition , context , ssphp , # # __VA_ARGS__ )
2016-04-12 23:43:46 +02:00
# define CHECK_SQL_ERROR( result, context, ... ) \
SQLSRV_ASSERT ( result ! = SQL_INVALID_HANDLE , " Invalid handle returned. " ) ; \
2017-01-24 02:22:15 +01:00
CHECK_ERROR ( result = = SQL_ERROR , context , # # __VA_ARGS__ )
2016-04-12 23:43:46 +02:00
# define CHECK_WARNING_AS_ERROR_UNIQUE( unique, condition, context, ssphp, ... ) \
bool ignored # # unique = true ; \
if ( condition ) { \
2017-01-24 02:22:15 +01:00
ignored # # unique = call_error_handler ( context , ssphp TSRMLS_CC , /*warning*/ true , # # __VA_ARGS__ ) ; \
2016-04-12 23:43:46 +02:00
} \
if ( ! ignored # # unique )
# define CHECK_SQL_WARNING_AS_ERROR( result, context, ... ) \
2017-01-24 02:22:15 +01:00
CHECK_WARNING_AS_ERROR_UNIQUE ( __COUNTER__ , ( result = = SQL_SUCCESS_WITH_INFO ) , context , SQLSRV_ERROR_ODBC , # # __VA_ARGS__ )
2016-04-12 23:43:46 +02:00
# define CHECK_SQL_WARNING( result, context, ... ) \
if ( result = = SQL_SUCCESS_WITH_INFO ) { \
2017-01-24 02:22:15 +01:00
( void ) call_error_handler ( context , 0 TSRMLS_CC , /*warning*/ true , # # __VA_ARGS__ ) ; \
}
2016-04-12 23:43:46 +02:00
# define CHECK_CUSTOM_WARNING_AS_ERROR( condition, context, ssphp, ... ) \
2017-01-24 02:22:15 +01:00
CHECK_WARNING_AS_ERROR_UNIQUE ( __COUNTER__ , condition , context , ssphp , # # __VA_ARGS__ )
2016-04-12 23:43:46 +02:00
# define CHECK_ZEND_ERROR( zr, ctx, error, ... ) \
2017-01-24 02:22:15 +01:00
CHECK_ERROR_UNIQUE ( __COUNTER__ , ( zr = = FAILURE ) , ctx , error , # # __VA_ARGS__ ) \
2016-04-12 23:43:46 +02:00
# define CHECK_SQL_ERROR_OR_WARNING( result, context, ... ) \
SQLSRV_ASSERT ( result ! = SQL_INVALID_HANDLE , " Invalid handle returned. " ) ; \
bool ignored = true ; \
if ( result = = SQL_ERROR ) { \
2017-01-24 02:22:15 +01:00
ignored = call_error_handler ( context , SQLSRV_ERROR_ODBC TSRMLS_CC , false , # # __VA_ARGS__ ) ; \
2016-04-12 23:43:46 +02:00
} \
else if ( result = = SQL_SUCCESS_WITH_INFO ) { \
2017-01-24 02:22:15 +01:00
ignored = call_error_handler ( context , SQLSRV_ERROR_ODBC TSRMLS_CC , true TSRMLS_CC , # # __VA_ARGS__ ) ; \
2016-04-12 23:43:46 +02:00
} \
if ( ! ignored )
// throw an exception after it has been hooked into the custom error handler
# define THROW_CORE_ERROR( ctx, custom, ... ) \
2017-01-24 02:22:15 +01:00
( void ) call_error_handler ( ctx , custom TSRMLS_CC , /*warning*/ false , # # __VA_ARGS__ ) ; \
2016-04-12 23:43:46 +02:00
throw core : : CoreException ( ) ;
//*********************************************************************************************************************************
// ODBC/Zend function wrappers
//*********************************************************************************************************************************
namespace core {
// base exception for the driver
struct CoreException : public std : : exception {
CoreException ( )
{
}
} ;
2017-06-22 23:04:34 +02:00
inline void check_for_mars_error ( _Inout_ sqlsrv_stmt * stmt , _In_ SQLRETURN r TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
2018-10-19 23:48:21 +02:00
// Skip this if not SQL_ERROR -
2016-04-12 23:43:46 +02:00
// We check for the 'connection busy' error caused by having MultipleActiveResultSets off
// and return a more helpful message prepended to the ODBC errors if that error occurs
2018-10-19 23:48:21 +02:00
if ( r = = SQL_ERROR ) {
2016-04-12 23:43:46 +02:00
2018-08-20 23:51:33 +02:00
SQLCHAR err_msg [ SQL_MAX_MESSAGE_LENGTH + 1 ] = { ' \0 ' } ;
2016-04-12 23:43:46 +02:00
SQLSMALLINT len = 0 ;
2017-01-21 00:14:46 +01:00
SQLRETURN rtemp = : : SQLGetDiagField ( stmt - > handle_type ( ) , stmt - > handle ( ) , 1 , SQL_DIAG_MESSAGE_TEXT ,
2018-08-20 23:51:33 +02:00
err_msg , SQL_MAX_MESSAGE_LENGTH , & len ) ;
2016-04-12 23:43:46 +02:00
2018-08-20 23:51:33 +02:00
if ( rtemp = = SQL_SUCCESS_WITH_INFO & & len > SQL_MAX_MESSAGE_LENGTH ) {
// if the error message is this long, then it must not be the mars message
// defined as ODBC_CONNECTION_BUSY_ERROR -- so return here and continue the
// regular error handling
return ;
}
2017-01-21 00:14:46 +01:00
CHECK_SQL_ERROR_OR_WARNING ( rtemp , stmt ) {
2018-08-20 23:51:33 +02:00
2016-04-12 23:43:46 +02:00
throw CoreException ( ) ;
}
2017-09-12 01:17:24 +02:00
// the message returned by ODBC Driver for SQL Server
2017-09-15 18:58:47 +02:00
const std : : string connection_busy_error ( ODBC_CONNECTION_BUSY_ERROR ) ;
2017-09-12 01:17:24 +02:00
const std : : string returned_error ( reinterpret_cast < char * > ( err_msg ) ) ;
2017-09-12 22:30:14 +02:00
if ( ( returned_error . find ( connection_busy_error ) ! = std : : string : : npos ) ) {
2016-04-12 23:43:46 +02:00
THROW_CORE_ERROR ( stmt , SQLSRV_ERROR_MARS_OFF ) ;
}
}
}
// *** ODBC wrappers ***
// wrap the ODBC functions to throw exceptions rather than use the return value to signal errors
// some of the signatures have been altered to be more convenient since the return value is no longer
// required to return the status of the call (e.g., SQLNumResultCols).
// These functions take the sqlsrv_context type. However, since the error handling code can alter
// the context to hold the error, they are not passed as const.
2017-06-22 23:04:34 +02:00
inline SQLRETURN SQLGetDiagField ( _Inout_ sqlsrv_context * ctx , _In_ SQLSMALLINT record_number , _In_ SQLSMALLINT diag_identifier ,
_Out_writes_opt_ ( buffer_length ) SQLPOINTER diag_info_buffer , _In_ SQLSMALLINT buffer_length ,
_Out_opt_ SQLSMALLINT * out_buffer_length TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
SQLRETURN r = : : SQLGetDiagField ( ctx - > handle_type ( ) , ctx - > handle ( ) , record_number , diag_identifier ,
diag_info_buffer , buffer_length , out_buffer_length ) ;
CHECK_SQL_ERROR_OR_WARNING ( r , ctx ) {
throw CoreException ( ) ;
}
return r ;
}
2017-06-22 23:04:34 +02:00
inline void SQLAllocHandle ( _In_ SQLSMALLINT HandleType , _Inout_ sqlsrv_context & InputHandle ,
2018-05-06 02:08:01 +02:00
_Out_ SQLHANDLE * OutputHandlePtr TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
SQLRETURN r ;
r = : : SQLAllocHandle ( HandleType , InputHandle . handle ( ) , OutputHandlePtr ) ;
CHECK_SQL_ERROR_OR_WARNING ( r , InputHandle ) {
throw CoreException ( ) ;
}
}
2017-06-22 23:04:34 +02:00
inline void SQLBindParameter ( _Inout_ sqlsrv_stmt * stmt ,
_In_ SQLUSMALLINT ParameterNumber ,
_In_ SQLSMALLINT InputOutputType ,
_In_ SQLSMALLINT ValueType ,
_In_ SQLSMALLINT ParameterType ,
_In_ SQLULEN ColumnSize ,
_In_ SQLSMALLINT DecimalDigits ,
_Inout_opt_ SQLPOINTER ParameterValuePtr ,
_Inout_ SQLLEN BufferLength ,
_Inout_ SQLLEN * StrLen_Or_IndPtr
2016-04-12 23:43:46 +02:00
TSRMLS_DC )
{
SQLRETURN r ;
r = : : SQLBindParameter ( stmt - > handle ( ) , ParameterNumber , InputOutputType , ValueType , ParameterType , ColumnSize ,
DecimalDigits , ParameterValuePtr , BufferLength , StrLen_Or_IndPtr ) ;
CHECK_SQL_ERROR_OR_WARNING ( r , stmt ) {
throw CoreException ( ) ;
}
}
2017-08-08 21:03:51 +02:00
inline void SQLCloseCursor ( _Inout_ sqlsrv_stmt * stmt TSRMLS_DC )
{
SQLRETURN r = : : SQLCloseCursor ( stmt - > handle ( ) ) ;
CHECK_SQL_ERROR_OR_WARNING ( r , stmt ) {
throw CoreException ( ) ;
}
}
2016-04-12 23:43:46 +02:00
2017-06-22 23:04:34 +02:00
inline void SQLColAttribute ( _Inout_ sqlsrv_stmt * stmt , _In_ SQLUSMALLINT field_index , _In_ SQLUSMALLINT field_identifier ,
_Out_writes_bytes_opt_ ( buffer_length ) SQLPOINTER field_type_char , _In_ SQLSMALLINT buffer_length ,
_Out_opt_ SQLSMALLINT * out_buffer_length , _Out_opt_ SQLLEN * field_type_num TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
SQLRETURN r = : : SQLColAttribute ( stmt - > handle ( ) , field_index , field_identifier , field_type_char ,
buffer_length , out_buffer_length , field_type_num ) ;
CHECK_SQL_ERROR_OR_WARNING ( r , stmt ) {
throw CoreException ( ) ;
}
}
2017-06-22 23:04:34 +02:00
inline void SQLColAttributeW ( _Inout_ sqlsrv_stmt * stmt , _In_ SQLUSMALLINT field_index , _In_ SQLUSMALLINT field_identifier ,
_Out_writes_bytes_opt_ ( buffer_length ) SQLPOINTER field_type_char , _In_ SQLSMALLINT buffer_length ,
_Out_opt_ SQLSMALLINT * out_buffer_length , _Out_opt_ SQLLEN * field_type_num TSRMLS_DC )
2017-01-17 21:38:31 +01:00
{
SQLRETURN r = : : SQLColAttributeW ( stmt - > handle ( ) , field_index , field_identifier , field_type_char ,
2017-01-17 23:19:45 +01:00
buffer_length , out_buffer_length , field_type_num ) ;
2017-01-17 21:38:31 +01:00
CHECK_SQL_ERROR_OR_WARNING ( r , stmt ) {
throw CoreException ( ) ;
}
}
2016-04-12 23:43:46 +02:00
2017-07-01 00:17:14 +02:00
inline void SQLDescribeCol ( _Inout_ sqlsrv_stmt * stmt , _In_ SQLSMALLINT colno , _Out_writes_opt_ ( col_name_length ) SQLCHAR * col_name , _In_ SQLSMALLINT col_name_length ,
2017-06-22 23:04:34 +02:00
_Out_opt_ SQLSMALLINT * col_name_length_out , _Out_opt_ SQLSMALLINT * data_type , _Out_opt_ SQLULEN * col_size ,
_Out_opt_ SQLSMALLINT * decimal_digits , _Out_opt_ SQLSMALLINT * nullable TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
SQLRETURN r ;
r = : : SQLDescribeCol ( stmt - > handle ( ) , colno , col_name , col_name_length , col_name_length_out ,
data_type , col_size , decimal_digits , nullable ) ;
CHECK_SQL_ERROR_OR_WARNING ( r , stmt ) {
throw CoreException ( ) ;
}
}
2017-06-22 23:04:34 +02:00
inline void SQLDescribeColW ( _Inout_ sqlsrv_stmt * stmt , _In_ SQLSMALLINT colno , _Out_writes_opt_ ( col_name_length ) SQLWCHAR * col_name , _In_ SQLSMALLINT col_name_length ,
_Out_opt_ SQLSMALLINT * col_name_length_out , _Out_opt_ SQLSMALLINT * data_type , _Out_opt_ SQLULEN * col_size ,
_Out_opt_ SQLSMALLINT * decimal_digits , _Out_opt_ SQLSMALLINT * nullable TSRMLS_DC )
2017-01-17 21:38:31 +01:00
{
SQLRETURN r ;
r = : : SQLDescribeColW ( stmt - > handle ( ) , colno , col_name , col_name_length , col_name_length_out ,
2017-01-17 23:19:45 +01:00
data_type , col_size , decimal_digits , nullable ) ;
2017-01-17 21:38:31 +01:00
CHECK_SQL_ERROR_OR_WARNING ( r , stmt ) {
throw CoreException ( ) ;
}
}
2016-04-12 23:43:46 +02:00
2017-09-06 01:51:40 +02:00
inline void SQLDescribeParam ( _Inout_ sqlsrv_stmt * stmt , _In_ SQLSMALLINT paramno , _Out_opt_ SQLSMALLINT * data_type , _Out_opt_ SQLULEN * col_size ,
_Out_opt_ SQLSMALLINT * decimal_digits , _Out_opt_ SQLSMALLINT * nullable TSRMLS_DC )
{
SQLRETURN r ;
r = : : SQLDescribeParam ( stmt - > handle ( ) , paramno , data_type , col_size , decimal_digits , nullable ) ;
CHECK_SQL_ERROR_OR_WARNING ( r , stmt ) {
throw CoreException ( ) ;
}
}
2017-11-16 19:30:44 +01:00
inline void SQLNumParams ( _Inout_ sqlsrv_stmt * stmt , _Out_opt_ SQLSMALLINT * num_params )
{
SQLRETURN r ;
r = : : SQLNumParams ( stmt - > handle ( ) , num_params ) ;
CHECK_SQL_ERROR_OR_WARNING ( r , stmt ) {
throw CoreException ( ) ;
}
}
2017-06-22 23:04:34 +02:00
inline void SQLEndTran ( _In_ SQLSMALLINT handleType , _Inout_ sqlsrv_conn * conn , _In_ SQLSMALLINT completionType TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
SQLRETURN r = : : SQLEndTran ( handleType , conn - > handle ( ) , completionType ) ;
CHECK_SQL_ERROR_OR_WARNING ( r , conn ) {
throw CoreException ( ) ;
}
}
// SQLExecDirect returns the status code since it returns either SQL_NEED_DATA or SQL_NO_DATA besides just errors/success
2017-06-22 23:04:34 +02:00
inline SQLRETURN SQLExecDirect ( _Inout_ sqlsrv_stmt * stmt , _In_ char * sql TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
SQLRETURN r = : : SQLExecDirect ( stmt - > handle ( ) , reinterpret_cast < SQLCHAR * > ( sql ) , SQL_NTS ) ;
check_for_mars_error ( stmt , r TSRMLS_CC ) ;
CHECK_SQL_ERROR_OR_WARNING ( r , stmt ) {
throw CoreException ( ) ;
}
return r ;
}
2017-06-22 23:04:34 +02:00
inline SQLRETURN SQLExecDirectW ( _Inout_ sqlsrv_stmt * stmt , _In_ SQLWCHAR * wsql TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
SQLRETURN r ;
r = : : SQLExecDirectW ( stmt - > handle ( ) , reinterpret_cast < SQLWCHAR * > ( wsql ) , SQL_NTS ) ;
check_for_mars_error ( stmt , r TSRMLS_CC ) ;
CHECK_SQL_ERROR_OR_WARNING ( r , stmt ) {
throw CoreException ( ) ;
}
return r ;
}
// SQLExecute returns the status code since it returns either SQL_NEED_DATA or SQL_NO_DATA besides just errors/success
2017-06-22 23:04:34 +02:00
inline SQLRETURN SQLExecute ( _Inout_ sqlsrv_stmt * stmt TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
SQLRETURN r ;
r = : : SQLExecute ( stmt - > handle ( ) ) ;
check_for_mars_error ( stmt , r TSRMLS_CC ) ;
CHECK_SQL_ERROR_OR_WARNING ( r , stmt ) {
throw CoreException ( ) ;
}
return r ;
}
2017-06-22 23:04:34 +02:00
inline SQLRETURN SQLFetchScroll ( _Inout_ sqlsrv_stmt * stmt , _In_ SQLSMALLINT fetch_orientation , _In_ SQLLEN fetch_offset TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
SQLRETURN r = : : SQLFetchScroll ( stmt - > handle ( ) , fetch_orientation , fetch_offset ) ;
CHECK_SQL_ERROR_OR_WARNING ( r , stmt ) {
throw CoreException ( ) ;
}
return r ;
}
// wrap SQLFreeHandle and report any errors, but don't actually signal an error to the calling routine
2017-06-22 23:04:34 +02:00
inline void SQLFreeHandle ( _Inout_ sqlsrv_context & ctx TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
SQLRETURN r ;
r = : : SQLFreeHandle ( ctx . handle_type ( ) , ctx . handle ( ) ) ;
CHECK_SQL_ERROR_OR_WARNING ( r , ctx ) { }
}
2017-08-08 21:03:51 +02:00
inline void SQLGetStmtAttr ( _Inout_ sqlsrv_stmt * stmt , _In_ SQLINTEGER attr , _Out_writes_opt_ ( buf_len ) void * value_ptr , _In_ SQLINTEGER buf_len , _Out_opt_ SQLINTEGER * str_len TSRMLS_DC )
{
SQLRETURN r ;
r = : : SQLGetStmtAttr ( stmt - > handle ( ) , attr , value_ptr , buf_len , str_len ) ;
CHECK_SQL_ERROR_OR_WARNING ( r , stmt ) {
throw CoreException ( ) ;
}
}
2017-06-22 23:04:34 +02:00
inline SQLRETURN SQLGetData ( _Inout_ sqlsrv_stmt * stmt , _In_ SQLUSMALLINT field_index , _In_ SQLSMALLINT target_type ,
_Out_writes_opt_ ( buffer_length ) void * buffer , _In_ SQLLEN buffer_length , _Out_opt_ SQLLEN * out_buffer_length ,
_In_ bool handle_warning TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
SQLRETURN r = : : SQLGetData ( stmt - > handle ( ) , field_index , target_type , buffer , buffer_length , out_buffer_length ) ;
if ( r = = SQL_NO_DATA )
return r ;
CHECK_SQL_ERROR ( r , stmt ) {
throw CoreException ( ) ;
}
if ( handle_warning ) {
CHECK_SQL_WARNING_AS_ERROR ( r , stmt ) {
throw CoreException ( ) ;
}
}
return r ;
}
2017-06-22 23:04:34 +02:00
inline void SQLGetInfo ( _Inout_ sqlsrv_conn * conn , _In_ SQLUSMALLINT info_type , _Out_writes_bytes_opt_ ( buffer_len ) SQLPOINTER info_value , _In_ SQLSMALLINT buffer_len ,
_Out_opt_ SQLSMALLINT * str_len TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
SQLRETURN r ;
r = : : SQLGetInfo ( conn - > handle ( ) , info_type , info_value , buffer_len , str_len ) ;
CHECK_SQL_ERROR_OR_WARNING ( r , conn ) {
throw CoreException ( ) ;
}
}
2017-06-22 23:04:34 +02:00
inline void SQLGetTypeInfo ( _Inout_ sqlsrv_stmt * stmt , _In_ SQLUSMALLINT data_type TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
SQLRETURN r ;
r = : : SQLGetTypeInfo ( stmt - > handle ( ) , data_type ) ;
CHECK_SQL_ERROR_OR_WARNING ( r , stmt ) {
throw CoreException ( ) ;
}
}
// SQLMoreResults returns the status code since it returns SQL_NO_DATA when there is no more data in a result set.
2017-06-22 23:04:34 +02:00
inline SQLRETURN SQLMoreResults ( _Inout_ sqlsrv_stmt * stmt TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
SQLRETURN r = : : SQLMoreResults ( stmt - > handle ( ) ) ;
CHECK_SQL_ERROR_OR_WARNING ( r , stmt ) {
throw CoreException ( ) ;
}
return r ;
}
2017-06-22 23:04:34 +02:00
inline SQLSMALLINT SQLNumResultCols ( _Inout_ sqlsrv_stmt * stmt TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
SQLRETURN r ;
SQLSMALLINT num_cols ;
r = : : SQLNumResultCols ( stmt - > handle ( ) , & num_cols ) ;
2017-03-28 02:49:01 +02:00
2016-04-12 23:43:46 +02:00
CHECK_SQL_ERROR_OR_WARNING ( r , stmt ) {
throw CoreException ( ) ;
}
return num_cols ;
}
// SQLParamData returns the status code since it returns either SQL_NEED_DATA or SQL_NO_DATA when there are more
// parameters or when the parameters are all processed.
2017-06-22 23:04:34 +02:00
inline SQLRETURN SQLParamData ( _Inout_ sqlsrv_stmt * stmt , _Out_opt_ SQLPOINTER * value_ptr_ptr TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
SQLRETURN r ;
r = : : SQLParamData ( stmt - > handle ( ) , value_ptr_ptr ) ;
CHECK_SQL_ERROR_OR_WARNING ( r , stmt ) {
throw CoreException ( ) ;
}
return r ;
}
2017-06-22 23:04:34 +02:00
inline void SQLPrepareW ( _Inout_ sqlsrv_stmt * stmt , _In_reads_ ( sql_len ) SQLWCHAR * sql , _In_ SQLINTEGER sql_len TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
SQLRETURN r ;
r = : : SQLPrepareW ( stmt - > handle ( ) , sql , sql_len ) ;
CHECK_SQL_ERROR_OR_WARNING ( r , stmt ) {
throw CoreException ( ) ;
}
}
2017-06-22 23:04:34 +02:00
inline void SQLPutData ( _Inout_ sqlsrv_stmt * stmt , _In_reads_ ( strlen_or_ind ) SQLPOINTER data_ptr , _In_ SQLLEN strlen_or_ind TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
SQLRETURN r ;
r = : : SQLPutData ( stmt - > handle ( ) , data_ptr , strlen_or_ind ) ;
CHECK_SQL_ERROR_OR_WARNING ( r , stmt ) {
throw CoreException ( ) ;
}
}
2017-06-22 23:04:34 +02:00
inline SQLLEN SQLRowCount ( _Inout_ sqlsrv_stmt * stmt TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
SQLRETURN r ;
SQLLEN rows_affected ;
r = : : SQLRowCount ( stmt - > handle ( ) , & rows_affected ) ;
2017-01-26 23:43:15 +01:00
// On Linux platform
// DriverName: libmsodbcsql-13.0.so.0.0
// DriverODBCVer: 03.52
// DriverVer: 13.00.0000
// unixODBC: 2.3.1
// r = ::SQLRowCount( stmt->handle(), &rows_affected );
// returns r=-1 for an empty result set.
2017-02-01 21:41:13 +01:00
# ifndef _WIN32
2017-01-26 23:43:15 +01:00
if ( r = = - 1 & & rows_affected = = - 1 )
return 0 ;
2017-02-01 21:41:13 +01:00
# endif // !_WIN32
2017-01-24 02:22:15 +01:00
2016-04-12 23:43:46 +02:00
CHECK_SQL_ERROR_OR_WARNING ( r , stmt ) {
throw CoreException ( ) ;
}
return rows_affected ;
}
2018-05-17 00:14:47 +02:00
inline void SQLSetConnectAttr ( _Inout_ sqlsrv_context & ctx , _In_ SQLINTEGER attr , _In_reads_bytes_opt_ ( str_len ) SQLPOINTER value_ptr , _In_ SQLINTEGER str_len TSRMLS_DC )
{
SQLRETURN r ;
r = : : SQLSetConnectAttr ( ctx . handle ( ) , attr , value_ptr , str_len ) ;
2016-04-12 23:43:46 +02:00
2018-05-17 00:14:47 +02:00
CHECK_SQL_ERROR_OR_WARNING ( r , ctx ) {
throw CoreException ( ) ;
}
}
2016-04-12 23:43:46 +02:00
2017-09-08 00:26:46 +02:00
inline void SQLSetDescField ( _Inout_ sqlsrv_stmt * stmt , _In_ SQLSMALLINT rec_num , _In_ SQLSMALLINT fld_id , _In_reads_bytes_opt_ ( str_len ) SQLPOINTER value_ptr , _In_ SQLINTEGER str_len TSRMLS_DC )
2017-09-06 01:51:40 +02:00
{
SQLRETURN r ;
SQLHDESC hIpd = NULL ;
2017-09-08 00:26:46 +02:00
core : : SQLGetStmtAttr ( stmt , SQL_ATTR_IMP_PARAM_DESC , & hIpd , 0 , 0 ) ;
2017-12-13 22:33:32 +01:00
if ( value_ptr ) {
r = : : SQLSetDescField ( hIpd , rec_num , fld_id , value_ptr , str_len ) ;
CHECK_SQL_ERROR_OR_WARNING ( r , stmt ) {
throw CoreException ( ) ;
}
2017-09-06 01:51:40 +02:00
}
}
2016-04-12 23:43:46 +02:00
2017-06-22 23:04:34 +02:00
inline void SQLSetEnvAttr ( _Inout_ sqlsrv_context & ctx , _In_ SQLINTEGER attr , _In_reads_bytes_opt_ ( str_len ) SQLPOINTER value_ptr , _In_ SQLINTEGER str_len TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
SQLRETURN r ;
r = : : SQLSetEnvAttr ( ctx . handle ( ) , attr , value_ptr , str_len ) ;
CHECK_SQL_ERROR_OR_WARNING ( r , ctx ) {
throw CoreException ( ) ;
}
}
2017-06-22 23:04:34 +02:00
inline void SQLSetConnectAttr ( _Inout_ sqlsrv_conn * conn , _In_ SQLINTEGER attribute , _In_reads_bytes_opt_ ( value_len ) SQLPOINTER value_ptr , _In_ SQLINTEGER value_len TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
SQLRETURN r = : : SQLSetConnectAttr ( conn - > handle ( ) , attribute , value_ptr , value_len ) ;
CHECK_SQL_ERROR_OR_WARNING ( r , conn ) {
throw CoreException ( ) ;
}
}
2017-06-22 23:04:34 +02:00
inline void SQLSetStmtAttr ( _Inout_ sqlsrv_stmt * stmt , _In_ SQLINTEGER attr , _In_reads_ ( str_len ) SQLPOINTER value_ptr , _In_ SQLINTEGER str_len TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
SQLRETURN r ;
r = : : SQLSetStmtAttr ( stmt - > handle ( ) , attr , value_ptr , str_len ) ;
CHECK_SQL_ERROR_OR_WARNING ( r , stmt ) {
throw CoreException ( ) ;
}
}
// *** zend wrappers ***
2016-05-04 05:05:41 +02:00
//zend_resource_dtor sets the type of destroyed resources to -1
# define RSRC_INVALID_TYPE -1
2016-04-12 23:43:46 +02:00
// wrapper for ZVAL_STRINGL macro. ZVAL_STRINGL always allocates memory when initialzing new string from char string
// so allocated memory inside of value_z should be released before assigning it to the new string
2017-06-22 23:04:34 +02:00
inline void sqlsrv_zval_stringl ( _Inout_ zval * value_z , _In_reads_ ( str_len ) const char * str , _In_ const std : : size_t str_len )
2016-04-12 23:43:46 +02:00
{
if ( Z_TYPE_P ( value_z ) = = IS_STRING & & Z_STR_P ( value_z ) ! = NULL ) {
zend_string * temp_zstr = zend_string_init ( str , str_len , 0 ) ;
zend_string_release ( Z_STR_P ( value_z ) ) ;
ZVAL_NEW_STR ( value_z , temp_zstr ) ;
}
else {
ZVAL_STRINGL ( value_z , str , str_len ) ;
}
}
// exception thrown when a zend function wrapped here fails.
// wrappers for the zend functions called by our driver. These functions hook into the error reporting of our driver and throw
// exceptions when an error occurs. They are prefaced with sqlsrv_<zend_function_name> because many of the zend functions are
// actually macros that call other functions, so the sqlsrv_ is necessary to differentiate them from the macro system.
// If there is a zend function in the source that isn't found here, it is because it returns void and there is no error
// that can be thrown from it.
2017-06-22 23:04:34 +02:00
inline void sqlsrv_add_index_zval ( _Inout_ sqlsrv_context & ctx , _Inout_ zval * array , _In_ zend_ulong index , _In_ zval * value TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
int zr = : : add_index_zval ( array , index , value ) ;
CHECK_ZEND_ERROR ( zr , ctx , SQLSRV_ERROR_ZEND_HASH ) {
throw CoreException ( ) ;
}
}
2017-06-22 23:04:34 +02:00
inline void sqlsrv_add_next_index_zval ( _Inout_ sqlsrv_context & ctx , _Inout_ zval * array , _In_ zval * value TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
int zr = : : add_next_index_zval ( array , value ) ;
CHECK_ZEND_ERROR ( zr , ctx , SQLSRV_ERROR_ZEND_HASH ) {
throw CoreException ( ) ;
}
}
2017-06-22 23:04:34 +02:00
inline void sqlsrv_add_assoc_null ( _Inout_ sqlsrv_context & ctx , _Inout_ zval * array_z , _In_ const char * key TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
int zr = : : add_assoc_null ( array_z , key ) ;
CHECK_ZEND_ERROR ( zr , ctx , SQLSRV_ERROR_ZEND_HASH ) {
throw CoreException ( ) ;
}
}
2017-06-22 23:04:34 +02:00
inline void sqlsrv_add_assoc_long ( _Inout_ sqlsrv_context & ctx , _Inout_ zval * array_z , _In_ const char * key , _In_ zend_long val TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
int zr = : : add_assoc_long ( array_z , key , val ) ;
CHECK_ZEND_ERROR ( zr , ctx , SQLSRV_ERROR_ZEND_HASH ) {
throw CoreException ( ) ;
}
}
2017-06-22 23:04:34 +02:00
inline void sqlsrv_add_assoc_string ( _Inout_ sqlsrv_context & ctx , _Inout_ zval * array_z , _In_ const char * key , _Inout_z_ char * val , _In_ bool duplicate TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
int zr = : : add_assoc_string ( array_z , key , val ) ;
CHECK_ZEND_ERROR ( zr , ctx , SQLSRV_ERROR_ZEND_HASH ) {
throw CoreException ( ) ;
}
if ( duplicate = = 0 ) {
sqlsrv_free ( val ) ;
}
}
2019-05-01 17:03:33 +02:00
inline void sqlsrv_add_assoc_zval ( _Inout_ sqlsrv_context & ctx , _Inout_ zval * array_z , _In_ const char * key , _In_ zval * val TSRMLS_DC )
{
int zr = : : add_assoc_zval ( array_z , key , val ) ;
CHECK_ZEND_ERROR ( zr , ctx , SQLSRV_ERROR_ZEND_HASH ) {
throw CoreException ( ) ;
}
}
2017-06-22 23:04:34 +02:00
inline void sqlsrv_array_init ( _Inout_ sqlsrv_context & ctx , _Out_ zval * new_array TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
2018-07-27 00:21:03 +02:00
# if PHP_VERSION_ID < 70300
CHECK_ZEND_ERROR ( : : array_init ( new_array ) , ctx , SQLSRV_ERROR_ZEND_HASH ) {
2016-04-12 23:43:46 +02:00
throw CoreException ( ) ;
}
2018-07-27 00:21:03 +02:00
# else
array_init ( new_array ) ;
# endif
2016-04-12 23:43:46 +02:00
}
2017-06-22 23:04:34 +02:00
inline void sqlsrv_php_stream_from_zval_no_verify ( _Inout_ sqlsrv_context & ctx , _Outref_result_maybenull_ php_stream * & stream , _In_opt_ zval * stream_z TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
// this duplicates the macro php_stream_from_zval_no_verify, which we can't use because it has an assignment
php_stream_from_zval_no_verify ( stream , stream_z ) ;
CHECK_CUSTOM_ERROR ( stream = = NULL , ctx , SQLSRV_ERROR_ZEND_STREAM ) {
throw CoreException ( ) ;
}
}
2017-06-22 23:04:34 +02:00
inline void sqlsrv_zend_hash_get_current_data ( _In_ sqlsrv_context & ctx , _In_ HashTable * ht , _Outref_result_maybenull_ zval * & output_data TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
int zr = ( output_data = : : zend_hash_get_current_data ( ht ) ) ! = NULL ? SUCCESS : FAILURE ;
CHECK_ZEND_ERROR ( zr , ctx , SQLSRV_ERROR_ZEND_HASH ) {
throw CoreException ( ) ;
}
}
2017-06-22 23:04:34 +02:00
inline void sqlsrv_zend_hash_get_current_data_ptr ( _Inout_ sqlsrv_context & ctx , _In_ HashTable * ht , _Outref_result_maybenull_ void * & output_data TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
int zr = ( output_data = : : zend_hash_get_current_data_ptr ( ht ) ) ! = NULL ? SUCCESS : FAILURE ;
CHECK_ZEND_ERROR ( zr , ctx , SQLSRV_ERROR_ZEND_HASH ) {
throw CoreException ( ) ;
}
}
2017-06-22 23:04:34 +02:00
inline void sqlsrv_zend_hash_index_del ( _Inout_ sqlsrv_context & ctx , _Inout_ HashTable * ht , _In_ zend_ulong index TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
int zr = : : zend_hash_index_del ( ht , index ) ;
CHECK_ZEND_ERROR ( zr , ctx , SQLSRV_ERROR_ZEND_HASH ) {
throw CoreException ( ) ;
}
}
2017-06-22 23:04:34 +02:00
inline void sqlsrv_zend_hash_index_update ( _Inout_ sqlsrv_context & ctx , _Inout_ HashTable * ht , _In_ zend_ulong index , _In_ zval * data_z TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
int zr = ( data_z = : : zend_hash_index_update ( ht , index , data_z ) ) ! = NULL ? SUCCESS : FAILURE ;
CHECK_ZEND_ERROR ( zr , ctx , SQLSRV_ERROR_ZEND_HASH ) {
throw CoreException ( ) ;
}
}
2017-06-22 23:04:34 +02:00
inline void sqlsrv_zend_hash_index_update_ptr ( _Inout_ sqlsrv_context & ctx , _Inout_ HashTable * ht , _In_ zend_ulong index , _In_ void * pData TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
int zr = ( pData = : : zend_hash_index_update_ptr ( ht , index , pData ) ) ! = NULL ? SUCCESS : FAILURE ;
CHECK_ZEND_ERROR ( zr , ctx , SQLSRV_ERROR_ZEND_HASH ) {
throw CoreException ( ) ;
}
}
2017-06-22 23:04:34 +02:00
inline void sqlsrv_zend_hash_index_update_mem ( _Inout_ sqlsrv_context & ctx , _Inout_ HashTable * ht , _In_ zend_ulong index , _In_reads_bytes_ ( size ) void * pData , _In_ std : : size_t size TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
int zr = ( pData = : : zend_hash_index_update_mem ( ht , index , pData , size ) ) ! = NULL ? SUCCESS : FAILURE ;
CHECK_ZEND_ERROR ( zr , ctx , SQLSRV_ERROR_ZEND_HASH ) {
throw CoreException ( ) ;
}
}
2017-06-22 23:04:34 +02:00
inline void sqlsrv_zend_hash_next_index_insert ( _Inout_ sqlsrv_context & ctx , _Inout_ HashTable * ht , _In_ zval * data TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
int zr = ( data = : : zend_hash_next_index_insert ( ht , data ) ) ! = NULL ? SUCCESS : FAILURE ;
CHECK_ZEND_ERROR ( zr , ctx , SQLSRV_ERROR_ZEND_HASH ) {
throw CoreException ( ) ;
}
}
2017-06-22 23:04:34 +02:00
inline void sqlsrv_zend_hash_next_index_insert_mem ( _Inout_ sqlsrv_context & ctx , _In_ HashTable * ht , _In_reads_bytes_ ( data_size ) void * data , _In_ uint data_size TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
int zr = ( data = : : zend_hash_next_index_insert_mem ( ht , data , data_size ) ) ! = NULL ? SUCCESS : FAILURE ;
CHECK_ZEND_ERROR ( zr , ctx , SQLSRV_ERROR_ZEND_HASH ) {
throw CoreException ( ) ;
}
}
2017-06-22 23:04:34 +02:00
inline void sqlsrv_zend_hash_next_index_insert_ptr ( _Inout_ sqlsrv_context & ctx , _Inout_ HashTable * ht , _In_ void * data TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
int zr = ( data = : : zend_hash_next_index_insert_ptr ( ht , data ) ) ! = NULL ? SUCCESS : FAILURE ;
CHECK_ZEND_ERROR ( zr , ctx , SQLSRV_ERROR_ZEND_HASH ) {
throw CoreException ( ) ;
}
}
2017-06-22 23:04:34 +02:00
inline void sqlsrv_zend_hash_init ( sqlsrv_context & ctx , _Inout_ HashTable * ht , _Inout_ uint32_t initial_size ,
_In_ dtor_func_t dtor_fn , _In_ zend_bool persistent TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
: : zend_hash_init ( ht , initial_size , NULL , dtor_fn , persistent ) ;
}
template < typename Statement >
2017-06-22 23:04:34 +02:00
sqlsrv_stmt * allocate_stmt ( _In_ sqlsrv_conn * conn , _In_ SQLHANDLE h , _In_ error_callback e , _In_ void * driver TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
return new ( sqlsrv_malloc ( sizeof ( Statement ) ) ) Statement ( conn , h , e , driver TSRMLS_CC ) ;
}
template < typename Connection >
2017-06-22 23:04:34 +02:00
sqlsrv_conn * allocate_conn ( _In_ SQLHANDLE h , _In_ error_callback e , _In_ void * driver TSRMLS_DC )
2016-04-12 23:43:46 +02:00
{
return new ( sqlsrv_malloc ( sizeof ( Connection ) ) ) Connection ( h , e , driver TSRMLS_CC ) ;
}
} // namespace core
2017-09-12 18:46:22 +02:00
template < unsigned int Attr >
struct str_conn_attr_func {
2017-09-14 21:00:51 +02:00
static void func ( connection_option const * /*option*/ , zval * value , _Inout_ sqlsrv_conn * conn , std : : string & /*conn_str*/ TSRMLS_DC )
2017-09-12 18:46:22 +02:00
{
try {
2017-09-15 03:21:25 +02:00
core : : SQLSetConnectAttr ( conn , Attr , reinterpret_cast < SQLPOINTER > ( Z_STRVAL_P ( value ) ) , static_cast < SQLINTEGER > ( Z_STRLEN_P ( value ) ) TSRMLS_CC ) ;
2017-09-12 18:46:22 +02:00
}
2017-09-14 21:00:51 +02:00
catch ( core : : CoreException & ) {
2017-09-12 18:46:22 +02:00
throw ;
}
}
} ;
2017-01-26 22:54:02 +01:00
2016-04-12 23:43:46 +02:00
# endif // CORE_SQLSRV_H