SQL Server Driver for PHP 1.1 October 2009
This commit is contained in:
parent
273ea337e7
commit
08be0b80ff
2
CREDITS
2
CREDITS
|
@ -1 +1 @@
|
|||
SQL Server Driver for PHP 1.1 August 2009 CTP
|
||||
SQL Server Driver for PHP 1.1 October 2009
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
|
||||
* Notes about changes to the SQL Server Driver for PHP 1.1 August 2009 CTP *
|
||||
* Notes about changes to the SQL Server Driver for PHP 1.1 October 2009 *
|
||||
|
||||
For details about the changes included in this release, please see our blog at
|
||||
http://blogs.msdn.com/sqlphp or see the SQLServerDriverForPHP_Readme.htm
|
||||
file that is part of the download package.
|
||||
|
||||
* Notes about compiling the SQL Server Driver for PHP 1.1 August 2009 CTP *
|
||||
* Notes about compiling the SQL Server Driver for PHP 1.1 October 2009 *
|
||||
|
||||
Prerequisites: You must first be able to build PHP without including
|
||||
the SQL Server Driver for PHP extension. For help with doing this, see
|
||||
|
@ -32,7 +32,7 @@ wish to do so, run "nmake clean" first.
|
|||
5) To install the resulting build, run "nmake install" or just copy
|
||||
php_sqlsrv.dll to your PHP extension directory.
|
||||
|
||||
This software has been compiled and tested under PHP 5.2.10 and PHP 5.3.0
|
||||
This software has been compiled and tested under PHP 5.2.11 and PHP 5.3.0
|
||||
using the Visual C++ 2008 Express and Standard compilers.
|
||||
|
||||
This software is released under the Microsoft Public License. A copy of
|
||||
|
|
57
conn.cpp
57
conn.cpp
|
@ -43,22 +43,15 @@ const int INFO_BUFFER_LEN = 256;
|
|||
// number of segments in a version resource
|
||||
const int VERSION_SUBVERSIONS = 4;
|
||||
|
||||
// url table for driver links based on processor
|
||||
struct _platform_url {
|
||||
const char* platform;
|
||||
const char* url;
|
||||
} driver_info[] = {
|
||||
{ "x86", "http://go.microsoft.com/fwlink/?LinkId=137108" },
|
||||
{ "x64", "http://go.microsoft.com/fwlink/?LinkId=137109" },
|
||||
{ "ia64", "http://go.microsoft.com/fwlink/?LinkId=137110" }
|
||||
};
|
||||
// processor architectures
|
||||
const char* PROCESSOR_ARCH[] = { "x86", "x64", "ia64" };
|
||||
|
||||
// *** internal function prototypes ***
|
||||
sqlsrv_stmt* allocate_stmt( sqlsrv_conn* conn, zval const* options_z, char const* _FN_ TSRMLS_DC );
|
||||
SQLRETURN build_connection_string_and_set_conn_attr( sqlsrv_conn* conn, const char* server, zval const* options,
|
||||
__inout std::string& connection_string TSRMLS_DC );
|
||||
SQLRETURN determine_server_version( sqlsrv_conn* conn, const char* _FN_ TSRMLS_DC );
|
||||
struct _platform_url* get_driver_info( void );
|
||||
const char* get_processor_arch( void );
|
||||
bool mark_params_by_reference( zval** params_zz, char const* _FN_ TSRMLS_DC );
|
||||
void sqlsrv_conn_close_stmts( sqlsrv_conn* conn TSRMLS_DC );
|
||||
|
||||
|
@ -201,20 +194,20 @@ PHP_FUNCTION( sqlsrv_connect )
|
|||
catch( std::bad_alloc& ex ) {
|
||||
memset( const_cast<char*>( conn_str.c_str()), 0, conn_str.size() );
|
||||
conn_str.clear();
|
||||
LOG( SEV_ERROR, LOG_CONN, "C++ exception returned: %s", ex.what() );
|
||||
LOG( SEV_ERROR, LOG_CONN, "C++ exception returned: %1!s!", ex.what() );
|
||||
LOG( SEV_ERROR, LOG_CONN, "C++ memory allocation failure building the connection string." );
|
||||
DIE( "C++ memory allocation failure building the connection string." );
|
||||
}
|
||||
catch( std::out_of_range const& ex ) {
|
||||
memset( const_cast<char*>( conn_str.c_str()), 0, conn_str.size() );
|
||||
conn_str.clear();
|
||||
LOG( SEV_ERROR, LOG_CONN, "C++ exception returned: %s", ex.what() );
|
||||
LOG( SEV_ERROR, LOG_CONN, "C++ exception returned: %1!s!", ex.what() );
|
||||
RETURN_FALSE;
|
||||
}
|
||||
catch( std::length_error const& ex ) {
|
||||
memset( const_cast<char*>( conn_str.c_str()), 0, conn_str.size() );
|
||||
conn_str.clear();
|
||||
LOG( SEV_ERROR, LOG_CONN, "C++ exception returned: %s", ex.what() );
|
||||
LOG( SEV_ERROR, LOG_CONN, "C++ exception returned: %1!s!", ex.what() );
|
||||
SQLFreeHandle( conn->ctx.handle_type, conn->ctx.handle );
|
||||
conn->ctx.handle = SQL_NULL_HANDLE;
|
||||
RETURN_FALSE;
|
||||
|
@ -246,8 +239,8 @@ PHP_FUNCTION( sqlsrv_connect )
|
|||
SQLRETURN r = SQLGetDiagField( SQL_HANDLE_DBC, conn->ctx.handle, 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len );
|
||||
// if it's a IM002, meaning that the driver is not installed
|
||||
if( SQL_SUCCEEDED( r ) && state[0] == 'I' && state[1] == 'M' && state[2] == '0' && state[3] == '0' && state[4] == '2' ) {
|
||||
struct _platform_url* info = get_driver_info();
|
||||
handle_error( &conn->ctx, LOG_CONN, _FN_, SQLSRV_ERROR_DRIVER_NOT_INSTALLED TSRMLS_CC, info->platform, info->url );
|
||||
const char* arch = get_processor_arch();
|
||||
handle_error( &conn->ctx, LOG_CONN, _FN_, SQLSRV_ERROR_DRIVER_NOT_INSTALLED TSRMLS_CC, arch );
|
||||
SQLFreeHandle( conn->ctx.handle_type, conn->ctx.handle );
|
||||
conn->ctx.handle = SQL_NULL_HANDLE;
|
||||
RETURN_FALSE;
|
||||
|
@ -461,7 +454,7 @@ PHP_FUNCTION( sqlsrv_close )
|
|||
// removal fails, so we just log it and move on.
|
||||
int zr = zend_hash_index_del( &EG( regular_list ), Z_RESVAL_P( conn_r ));
|
||||
if( zr == FAILURE ) {
|
||||
LOG( SEV_ERROR, LOG_CONN, "Failed to remove connection resource %d", Z_RESVAL_P( conn_r ));
|
||||
LOG( SEV_ERROR, LOG_CONN, "Failed to remove connection resource %1!d!", Z_RESVAL_P( conn_r ));
|
||||
}
|
||||
ZVAL_NULL( conn_r );
|
||||
|
||||
|
@ -1689,20 +1682,21 @@ bool mark_params_by_reference( __inout zval** params_zz, char const* _FN_ TSRMLS
|
|||
return true;
|
||||
}
|
||||
|
||||
struct _platform_url* get_driver_info( void )
|
||||
const char* get_processor_arch( void )
|
||||
{
|
||||
SYSTEM_INFO sys_info;
|
||||
|
||||
GetSystemInfo( &sys_info );
|
||||
|
||||
GetSystemInfo( &sys_info);
|
||||
switch( sys_info.wProcessorArchitecture ) {
|
||||
|
||||
case PROCESSOR_ARCHITECTURE_INTEL:
|
||||
return &driver_info[0];
|
||||
return PROCESSOR_ARCH[0];
|
||||
|
||||
case PROCESSOR_ARCHITECTURE_AMD64:
|
||||
return &driver_info[1];
|
||||
return PROCESSOR_ARCH[1];
|
||||
|
||||
case PROCESSOR_ARCHITECTURE_IA64:
|
||||
return &driver_info[2];
|
||||
return PROCESSOR_ARCH[2];
|
||||
|
||||
default:
|
||||
DIE( "Unknown Windows processor architecture" );
|
||||
return NULL;
|
||||
|
@ -1729,21 +1723,16 @@ SQLRETURN determine_server_version( sqlsrv_conn* conn, const char* _FN_ TSRMLS_D
|
|||
version_major_str[ 2 ] = '\0';
|
||||
version_major = static_cast<SERVER_VERSION>( atoi( version_major_str ));
|
||||
|
||||
if( errno == ERANGE || errno == EINVAL ) {
|
||||
if( version_major == 0 || errno == ERANGE || errno == EINVAL ) {
|
||||
conn->server_version = SERVER_VERSION_UNKNOWN;
|
||||
handle_error( &conn->ctx, LOG_CONN, _FN_, SQLSRV_ERROR_INVALID_SERVER_VERSION TSRMLS_CC, version_major );
|
||||
handle_error( &conn->ctx, LOG_CONN, _FN_, SQLSRV_ERROR_UNKNOWN_SERVER_VERSION TSRMLS_CC );
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
if( version_major >= SERVER_VERSION_2000 ) {
|
||||
conn->server_version = version_major;
|
||||
return SQL_SUCCESS;
|
||||
}
|
||||
else {
|
||||
conn->server_version = SERVER_VERSION_UNKNOWN;
|
||||
handle_error( &conn->ctx, LOG_CONN, _FN_, SQLSRV_ERROR_INVALID_SERVER_VERSION TSRMLS_CC, version_major );
|
||||
return SQL_ERROR;
|
||||
}
|
||||
// SNAC won't connect to versions older than SQL Server 2000, so we know that the version is at least
|
||||
// that high
|
||||
conn->server_version = version_major;
|
||||
return SQL_SUCCESS;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
33
init.cpp
33
init.cpp
|
@ -209,6 +209,7 @@ zend_function_entry sqlsrv_functions[] = {
|
|||
HMODULE g_sqlsrv_hmodule = NULL;
|
||||
HENV g_henv_ncp = SQL_NULL_HANDLE;
|
||||
HENV g_henv_cp = SQL_NULL_HANDLE;
|
||||
OSVERSIONINFO g_osversion;
|
||||
|
||||
|
||||
// the structure returned to Zend that exposes the extension to the Zend engine.
|
||||
|
@ -471,6 +472,15 @@ PHP_MINIT_FUNCTION(sqlsrv)
|
|||
}
|
||||
CHECK_SQL_WARNING( r, (&henv_ctx), _FN_, NULL );
|
||||
|
||||
// get the version of the OS we're running on. For now this governs certain flags used by
|
||||
// WideCharToMultiByte. It might be relevant to other things in the future.
|
||||
g_osversion.dwOSVersionInfoSize = sizeof( g_osversion );
|
||||
BOOL ver_return = GetVersionEx( &g_osversion );
|
||||
if( !ver_return ) {
|
||||
LOG( SEV_ERROR, LOG_INIT, "Failed to retrieve Windows version information." );
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -542,7 +552,7 @@ PHP_RINIT_FUNCTION(sqlsrv)
|
|||
|
||||
// initialize list of warnings to ignore
|
||||
ALLOC_HASHTABLE( SQLSRV_G( warnings_to_ignore ));
|
||||
int zr = zend_hash_init( SQLSRV_G( warnings_to_ignore ), 5, NULL, NULL, 0 );
|
||||
int zr = zend_hash_init( SQLSRV_G( warnings_to_ignore ), 6, NULL, NULL, 0 );
|
||||
if( zr == FAILURE ) {
|
||||
LOG( SEV_ERROR, LOG_INIT, "PHP_RINIT: warnings hash table failure" );
|
||||
return FAILURE;
|
||||
|
@ -558,6 +568,7 @@ PHP_RINIT_FUNCTION(sqlsrv)
|
|||
LOG( SEV_ERROR, LOG_INIT, "PHP_RINIT: warnings hash table failure" );
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// changed language warning
|
||||
to_ignore.sqlstate = "01000";
|
||||
to_ignore.native_message = NULL;
|
||||
|
@ -568,6 +579,7 @@ PHP_RINIT_FUNCTION(sqlsrv)
|
|||
LOG( SEV_ERROR, LOG_INIT, "PHP_RINIT: warnings hash table failure" );
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// option value changed
|
||||
to_ignore.sqlstate = "01S02";
|
||||
to_ignore.native_message = NULL;
|
||||
|
@ -578,6 +590,7 @@ PHP_RINIT_FUNCTION(sqlsrv)
|
|||
LOG( SEV_ERROR, LOG_INIT, "PHP_RINIT: warnings hash table failure" );
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// cursor operation conflict
|
||||
to_ignore.sqlstate = "01001";
|
||||
to_ignore.native_message = NULL;
|
||||
|
@ -588,7 +601,8 @@ PHP_RINIT_FUNCTION(sqlsrv)
|
|||
LOG( SEV_ERROR, LOG_INIT, "PHP_RINIT: warnings hash table failure" );
|
||||
return FAILURE;
|
||||
}
|
||||
// null value eliminiated in set function
|
||||
|
||||
// null value eliminated in set function
|
||||
to_ignore.sqlstate = "01003";
|
||||
to_ignore.native_message = NULL;
|
||||
to_ignore.native_code = -1;
|
||||
|
@ -598,6 +612,17 @@ PHP_RINIT_FUNCTION(sqlsrv)
|
|||
LOG( SEV_ERROR, LOG_INIT, "PHP_RINIT: warnings hash table failure" );
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// SQL Azure warning: This session has been assigned a tracing id of ..
|
||||
to_ignore.sqlstate = "01000";
|
||||
to_ignore.native_message = NULL;
|
||||
to_ignore.native_code = 40608;
|
||||
to_ignore.format = false;
|
||||
zr = zend_hash_next_index_insert( SQLSRV_G( warnings_to_ignore ), &to_ignore, sizeof( sqlsrv_error ), NULL );
|
||||
if( zr == FAILURE ) {
|
||||
LOG( SEV_ERROR, LOG_INIT, "PHP_RINIT: warnings hash table failure" );
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// supported encodings
|
||||
ALLOC_HASHTABLE( SQLSRV_G( encodings ));
|
||||
|
@ -652,6 +677,10 @@ PHP_RSHUTDOWN_FUNCTION(sqlsrv)
|
|||
zend_hash_destroy( SQLSRV_G( warnings_to_ignore ));
|
||||
FREE_HASHTABLE( SQLSRV_G( warnings_to_ignore ));
|
||||
}
|
||||
if( SQLSRV_G( encodings )) {
|
||||
zend_hash_destroy( SQLSRV_G( encodings ));
|
||||
FREE_HASHTABLE( SQLSRV_G( encodings ));
|
||||
}
|
||||
sqlsrv_free( SQLSRV_G( henv_context ));
|
||||
|
||||
// verify memory at the end of the request (in debug mode only)
|
||||
|
|
20
php_sqlsrv.h
20
php_sqlsrv.h
|
@ -80,6 +80,11 @@ OACR_WARNING_POP
|
|||
#include <sql.h>
|
||||
#include <sqlext.h>
|
||||
|
||||
#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)
|
||||
|
@ -100,6 +105,8 @@ OACR_WARNING_POP
|
|||
#define SQL_SS_TIME2 (-154)
|
||||
#define SQL_SS_TIMESTAMPOFFSET (-155)
|
||||
|
||||
|
||||
|
||||
// static assert for enforcing compile time conditions
|
||||
template <bool b>
|
||||
struct sqlsrv_static_assert;
|
||||
|
@ -234,6 +241,9 @@ extern zend_module_entry g_sqlsrv_module_entry; // describes the extension to
|
|||
extern HMODULE g_sqlsrv_hmodule; // used for getting the version information
|
||||
extern SQLHANDLE g_henv_ncp; // used to create connection handles with connection pooling off
|
||||
extern SQLHANDLE g_henv_cp; // used to create connection handles with connection pooling on
|
||||
extern OSVERSIONINFO g_osversion; // used to determine which OS we're running in
|
||||
|
||||
const int SQLSRV_OS_VISTA_OR_LATER = 6; // major version for Vista
|
||||
|
||||
// maps an IANA encoding to a code page
|
||||
struct sqlsrv_encoding {
|
||||
|
@ -332,9 +342,10 @@ struct sqlsrv_output_string {
|
|||
zval* string_z;
|
||||
unsigned int encoding;
|
||||
int 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_output_string( zval* str_z, unsigned int enc, int num ) :
|
||||
string_z( str_z ), encoding( enc ), param_num( num )
|
||||
sqlsrv_output_string( zval* str_z, unsigned int enc, int num, SQLUINTEGER buffer_len ) :
|
||||
string_z( str_z ), encoding( enc ), param_num( num ), original_buffer_len( buffer_len )
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -362,7 +373,7 @@ struct sqlsrv_stmt {
|
|||
bool past_fetch_end; // sqlsrv_fetch sets when the statement goes beyond the last row
|
||||
bool past_next_result_end; // sqlsrv_next_resultset sets when the statement goes beyond the last results
|
||||
zval* params_z; // hold parameters passed to sqlsrv_prepare but not used until sqlsrv_execute
|
||||
SQLINTEGER* params_ind_ptr; // buffer to hold the sizes returend by ODBC
|
||||
SQLLEN* params_ind_ptr; // buffer to hold the sizes returned by ODBC
|
||||
zval* param_datetime_buffers; // track which datetime parameter to convert from string to datetime objects
|
||||
zval* param_streams; // track which streams to send data to the server
|
||||
zval* param_strings; // track which output strings need to be converted to UTF-8
|
||||
|
@ -482,6 +493,7 @@ unsigned int log_subsystems;
|
|||
zend_bool warnings_return_as_errors;
|
||||
// special list of warnings to ignore even if warnings are treated as errors
|
||||
HashTable* warnings_to_ignore;
|
||||
// encodings we understand
|
||||
HashTable* encodings;
|
||||
|
||||
ZEND_END_MODULE_GLOBALS(sqlsrv)
|
||||
|
@ -672,7 +684,7 @@ extern sqlsrv_error SQLSRV_ERROR_STATEMENT_NOT_SCROLLABLE[];
|
|||
extern sqlsrv_error SQLSRV_ERROR_STATEMENT_SCROLLABLE[];
|
||||
extern sqlsrv_error SQLSRV_ERROR_INVALID_FETCH_STYLE[];
|
||||
extern sqlsrv_error SQLSRV_ERROR_INVALID_OPTION_SCROLLABLE[];
|
||||
extern sqlsrv_error SQLSRV_ERROR_INVALID_SERVER_VERSION[];
|
||||
extern sqlsrv_error SQLSRV_ERROR_UNKNOWN_SERVER_VERSION[];
|
||||
|
||||
// definitions for PHP specific warnings returned by sqlsrv
|
||||
extern sqlsrv_error SQLSRV_WARNING_FIELD_NAME_EMPTY[];
|
||||
|
|
216
stmt.cpp
216
stmt.cpp
|
@ -115,7 +115,7 @@ bool calc_string_size( sqlsrv_stmt const* s, SQLUSMALLINT field_index, SQLUINTEG
|
|||
bool check_for_next_stream_parameter( sqlsrv_stmt* stmt, zval* return_value, const char* _FN_ TSRMLS_DC );
|
||||
void close_active_stream( sqlsrv_stmt* s TSRMLS_DC );
|
||||
bool convert_input_param_to_utf16( zval* input_param_z, zval* convert_param_z );
|
||||
bool convert_string_from_utf16( sqlsrv_phptype sqlsrv_phptype, char** string, SQLINTEGER& len );
|
||||
bool convert_string_from_utf16( unsigned int encoding, char** string, SQLINTEGER& len );
|
||||
SQLSMALLINT determine_c_type( int php_type, int encoding );
|
||||
bool determine_column_size_or_precision( sqlsrv_stmt const* stmt, sqlsrv_sqltype sqlsrv_type, SQLUINTEGER* column_size, SQLSMALLINT* decimal_digits );
|
||||
bool determine_param_defaults( sqlsrv_stmt const* stmt, const char* _FN_, zval const* param_z, int param_num, zend_uchar& php_type, int& direction,
|
||||
|
@ -1242,7 +1242,7 @@ bool sqlsrv_stmt_common_execute( sqlsrv_stmt* stmt, const SQLCHAR* sql_string, i
|
|||
SQLUINTEGER column_size = 0;
|
||||
SQLSMALLINT decimal_digits = 0;
|
||||
SQLPOINTER buffer = NULL;
|
||||
SQLUINTEGER buffer_len = 0;
|
||||
SQLLEN buffer_len = 0;
|
||||
sqlsrv_sqltype sql_type;
|
||||
sqlsrv_phptype sqlsrv_phptype;
|
||||
sql_type.typeinfo.type = SQL_BINARY;
|
||||
|
@ -1302,6 +1302,7 @@ bool sqlsrv_stmt_common_execute( sqlsrv_stmt* stmt, const SQLCHAR* sql_string, i
|
|||
case IS_STRING:
|
||||
buffer = Z_STRVAL_PP( ¶m_z );
|
||||
buffer_len = Z_STRLEN_PP( ¶m_z );
|
||||
stmt->params_ind_ptr[ i-1 ] = buffer_len;
|
||||
if( direction == SQL_PARAM_INPUT && sqlsrv_phptype.typeinfo.encoding == CP_UTF8 ) {
|
||||
|
||||
zval_auto_ptr wbuffer_z;
|
||||
|
@ -1317,68 +1318,96 @@ bool sqlsrv_stmt_common_execute( sqlsrv_stmt* stmt, const SQLCHAR* sql_string, i
|
|||
// memory added here is released upon function exit
|
||||
add_next_index_zval( wbuffer_allocs, wbuffer_z );
|
||||
wbuffer_z.transferred();
|
||||
stmt->params_ind_ptr[ i-1 ] = buffer_len;
|
||||
}
|
||||
// if the output params zval in the statement isn't initialized, do so
|
||||
if( direction != SQL_PARAM_INPUT && stmt->param_strings == NULL ) {
|
||||
ALLOC_INIT_ZVAL( stmt->param_strings );
|
||||
int zr = array_init( stmt->param_strings );
|
||||
CHECK_ZEND_ERROR( zr, SQLSRV_ERROR_ZEND_HASH, return false );
|
||||
}
|
||||
if( direction == SQL_PARAM_OUTPUT ) {
|
||||
// if the current buffer size is smaller than the necessary size, resize the buffer and set the zval to use it.
|
||||
if( buffer_len < column_size ) {
|
||||
buffer = static_cast<char*>( sqlsrv_realloc( buffer, column_size + 1 ));
|
||||
buffer_len = column_size + 1;
|
||||
ZVAL_STRINGL( param_z, reinterpret_cast<char*>( buffer ), buffer_len, 0 );
|
||||
// if it is an output or input/output string parameters
|
||||
if( direction != SQL_PARAM_INPUT ) {
|
||||
|
||||
// lazy allocate the array that holds the output string parameters. These are held so that their lengths
|
||||
// may be adjusted after output strings are fully retrieved.
|
||||
if( stmt->param_strings == NULL ) {
|
||||
ALLOC_INIT_ZVAL( stmt->param_strings );
|
||||
int zr = array_init( stmt->param_strings );
|
||||
CHECK_ZEND_ERROR( zr, SQLSRV_ERROR_ZEND_HASH, return false );
|
||||
}
|
||||
// save the parameter to be adjusted and/or converted after the results are processed
|
||||
sqlsrv_output_string output_string( param_z, sqlsrv_phptype.typeinfo.encoding, i - 1 );
|
||||
HashTable* strings_ht = Z_ARRVAL_P( stmt->param_strings );
|
||||
int next_index = zend_hash_next_free_element( strings_ht );
|
||||
int zr = zend_hash_index_update( strings_ht, next_index, &output_string, sizeof( output_string ), NULL );
|
||||
CHECK_ZEND_ERROR( zr, SQLSRV_ERROR_ZEND_HASH, return false );
|
||||
zval_add_ref( ¶m_z ); // we have a reference to the param
|
||||
}
|
||||
if( direction == SQL_PARAM_INPUT_OUTPUT ) {
|
||||
|
||||
buffer = Z_STRVAL_PP( ¶m_z );
|
||||
buffer_len = Z_STRLEN_PP( ¶m_z );
|
||||
|
||||
if( sqlsrv_phptype.typeinfo.encoding == CP_UTF8 ) {
|
||||
// if it's a UTF-8 input output parameter (signified by the C type being SQL_C_WCHAR)
|
||||
// or if the PHP type is a binary encoded string with a N(VAR)CHAR/NTEXTSQL type,
|
||||
// convert it to wchar first
|
||||
if( direction == SQL_PARAM_INPUT_OUTPUT &&
|
||||
(sql_c_type == SQL_C_WCHAR ||
|
||||
(sql_c_type == SQL_C_BINARY &&
|
||||
(sql_type.typeinfo.type == SQL_WCHAR ||
|
||||
sql_type.typeinfo.type == SQL_WVARCHAR ||
|
||||
sql_type.typeinfo.type == SQL_WLONGVARCHAR )))) {
|
||||
|
||||
bool converted = convert_input_param_to_utf16( param_z, param_z );
|
||||
if( !converted ) {
|
||||
handle_error( &stmt->ctx, LOG_STMT, _FN_, SQLSRV_ERROR_INPUT_PARAM_ENCODING_TRANSLATE TSRMLS_CC, i, get_last_error_message() );
|
||||
return false;
|
||||
}
|
||||
// free the original buffer and set to our converted buffer
|
||||
sqlsrv_free( buffer );
|
||||
buffer = Z_STRVAL_PP( ¶m_z );
|
||||
buffer_len = Z_STRLEN_PP( ¶m_z );
|
||||
// save the parameter to be adjusted and/or converted after the results are processed
|
||||
sqlsrv_output_string output_string( param_z, sqlsrv_phptype.typeinfo.encoding, i - 1 );
|
||||
HashTable* strings_ht = Z_ARRVAL_P( stmt->param_strings );
|
||||
int next_index = zend_hash_next_free_element( strings_ht );
|
||||
int zr = zend_hash_index_update( strings_ht, next_index, &output_string, sizeof( output_string ), NULL );
|
||||
CHECK_ZEND_ERROR( zr, SQLSRV_ERROR_ZEND_HASH, return false );
|
||||
zval_add_ref( ¶m_z );
|
||||
}
|
||||
// if the current buffer size is smaller than the necessary size, resize the buffer and set the zval to use it.
|
||||
if( buffer_len < column_size ) {
|
||||
buffer = static_cast<char*>( sqlsrv_realloc( buffer, column_size + 1 ));
|
||||
buffer_len = column_size;
|
||||
ZVAL_STRINGL( param_z, reinterpret_cast<char*>( buffer ), buffer_len, 0 );
|
||||
efree( buffer );
|
||||
buffer = Z_STRVAL_P( param_z );
|
||||
buffer_len = Z_STRLEN_P( param_z );
|
||||
}
|
||||
|
||||
// calculate the necessary size for the output buffer and reallocate the buffer given if necessary.
|
||||
|
||||
// verify there is enough buffer space to hold the output parameter and set variables for the
|
||||
// correct sizes
|
||||
SQLLEN expected_len;
|
||||
SQLLEN buffer_null_extra;
|
||||
SQLLEN elem_size;
|
||||
SQLLEN without_null_len;
|
||||
// calculate the size of each 'element' represented by column_size. WCHAR is of course 2,
|
||||
// as is a n(var)char/ntext field being returned as a binary field.
|
||||
elem_size = (sql_c_type == SQL_C_WCHAR || (sql_c_type == SQL_C_BINARY && (sql_type.typeinfo.type == SQL_WCHAR || sql_type.typeinfo.type == SQL_WVARCHAR))) ? 2 : 1;
|
||||
// account for the NULL terminator returned by ODBC and needed by Zend to avoid a "String not null terminated" debug warning
|
||||
expected_len = column_size * elem_size + elem_size;
|
||||
// binary fields aren't null terminated, so we need to account for that in our buffer length calcuations
|
||||
buffer_null_extra = (sql_c_type == SQL_C_BINARY) ? elem_size : 0;
|
||||
// this is the size of the string for Zend and for the StrLen parameter to SQLBindParameter
|
||||
without_null_len = column_size * elem_size;
|
||||
// increment to include the null terminator
|
||||
buffer_len += elem_size;
|
||||
// if the current buffer size is smaller than the necessary size, resize the buffer and set the zval to the new
|
||||
// length.
|
||||
if( buffer_len < expected_len ) {
|
||||
if( expected_len < expected_len - buffer_null_extra ) {
|
||||
DIE( "Integer overflow/underflow caused a corrupt field length." );
|
||||
return false; // avoid a static analysis error
|
||||
}
|
||||
// allocate enough space to ALWAYS include the NULL regardless of the type being retrieved since
|
||||
// we set the last byte(s) to be NULL to avoid the debug build warning from the Zend engine about
|
||||
// not having a NULL terminator on a string.
|
||||
buffer = static_cast<char*>( sqlsrv_realloc( buffer, expected_len ));
|
||||
buffer_len = expected_len; // set the buffer_len to the new allocation size (includes the null terminator taken out below)
|
||||
// A zval string len doesn't include the null. This calculates the length it should be
|
||||
// regardless of whether the ODBC type contains the NULL or not.
|
||||
ZVAL_STRINGL( param_z, reinterpret_cast<char*>( buffer ), without_null_len, 0 );
|
||||
// null terminate the string to avoid a warning in debug PHP builds
|
||||
(static_cast<char*>(buffer))[ without_null_len ] = '\0';
|
||||
}
|
||||
// buffer_len is the length passed to SQLBindParameter. It must contain the space for NULL in the
|
||||
// buffer when retrieving anything but SQLSRV_ENC_BINARY/SQL_C_BINARY
|
||||
buffer_len -= buffer_null_extra;
|
||||
// The StrLen_Ind_Ptr parameter of SQLBindParameter should contain the length of the buffer minus
|
||||
// any NULL needed. This should never be less than the output length required. If it is more,
|
||||
// the error 22001 is returned by ODBC.
|
||||
stmt->params_ind_ptr[ i-1 ] = buffer_len - (elem_size - buffer_null_extra);
|
||||
|
||||
// save the parameter to be adjusted and/or converted after the results are processed
|
||||
sqlsrv_output_string output_string( param_z, sqlsrv_phptype.typeinfo.encoding, i - 1, buffer_len );
|
||||
HashTable* strings_ht = Z_ARRVAL_P( stmt->param_strings );
|
||||
int next_index = zend_hash_next_free_element( strings_ht );
|
||||
int zr = zend_hash_index_update( strings_ht, next_index, &output_string, sizeof( output_string ), NULL );
|
||||
CHECK_ZEND_ERROR( zr, SQLSRV_ERROR_ZEND_HASH, return false );
|
||||
zval_add_ref( ¶m_z ); // we have a reference to the param
|
||||
}
|
||||
// correct the column size to be number of characters, not the number of bytes.
|
||||
if( sql_type.typeinfo.type == SQL_WCHAR || sql_type.typeinfo.type == SQL_WVARCHAR ) {
|
||||
column_size /= sizeof( wchar_t );
|
||||
}
|
||||
stmt->params_ind_ptr[ i-1 ] = buffer_len;
|
||||
break;
|
||||
case IS_OBJECT:
|
||||
{
|
||||
char* class_name;
|
||||
sqlsrv_malloc_auto_ptr<char> class_name;
|
||||
zend_uint class_name_len;
|
||||
zval_auto_ptr function_z;
|
||||
zval_auto_ptr buffer_z;
|
||||
|
@ -1705,43 +1734,28 @@ bool adjust_output_lengths_and_encodings( sqlsrv_stmt* stmt, const char* _FN_ TS
|
|||
|
||||
// adjust the length of the string to the value returned by SQLBindParameter in the ind_ptr parameter
|
||||
char* str = Z_STRVAL_P( output_string->string_z );
|
||||
int str_len = stmt->params_ind_ptr[ output_string->param_num ];
|
||||
SQLLEN str_len = stmt->params_ind_ptr[ output_string->param_num ];
|
||||
if( str_len == SQL_NULL_DATA ) {
|
||||
ZVAL_NULL( output_string->string_z );
|
||||
continue;
|
||||
}
|
||||
|
||||
// if it's not in the 8 bit encodings, then it's in UTF-16
|
||||
if( output_string->encoding != SQLSRV_ENCODING_CHAR && output_string->encoding != SQLSRV_ENCODING_BINARY ) {
|
||||
|
||||
str_len >>= 1; // from # of bytes to # of wchars
|
||||
++str_len; // include the NULL character
|
||||
|
||||
// get the size of the wide char string
|
||||
int enc_size = WideCharToMultiByte( output_string->encoding, 0, reinterpret_cast<wchar_t*>( str ), str_len, NULL, 0, NULL, NULL );
|
||||
// if no errors occurred
|
||||
if( enc_size != 0 ) {
|
||||
// allocate a buffer large enough
|
||||
char* enc_buffer = reinterpret_cast<char*>( sqlsrv_malloc( enc_size + 1 ));
|
||||
// convert the string
|
||||
int r = WideCharToMultiByte( CP_UTF8, 0, reinterpret_cast<wchar_t*>( str ), str_len, enc_buffer, enc_size, NULL, NULL );
|
||||
// if an error occurred during conversion
|
||||
if( r == 0 ) {
|
||||
// free the UTF-8 string and leave the current output param alone
|
||||
sqlsrv_free( enc_buffer );
|
||||
converted = false;
|
||||
}
|
||||
else {
|
||||
--enc_size;
|
||||
// swap the converted string for the original string
|
||||
enc_buffer[ enc_size ] = '\0';
|
||||
ZVAL_STRINGL( output_string->string_z, enc_buffer, enc_size, 0 );
|
||||
sqlsrv_free( str );
|
||||
}
|
||||
}
|
||||
else {
|
||||
converted = false;
|
||||
bool converted = convert_string_from_utf16( output_string->encoding, &str, str_len );
|
||||
if( !converted ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ZVAL_STRINGL( output_string->string_z, str, str_len, 0 );
|
||||
str[ str_len ] = '\0'; // null terminate the string to avoid the debug php warning
|
||||
else if( output_string->encoding == SQLSRV_ENCODING_BINARY && str_len < output_string->original_buffer_len ) {
|
||||
// ODBC doesn't null terminate binary encodings, but PHP complains if a string isn't null terminated
|
||||
// so we do that here if the length of the returned data is less than the original allocation. The original
|
||||
// allocation null terminates the buffer already.
|
||||
str[ str_len ] = '\0';
|
||||
}
|
||||
// set the string length
|
||||
ZVAL_STRINGL( output_string->string_z, str, str_len, 0 );
|
||||
}
|
||||
|
||||
zval_ptr_dtor( &stmt->param_strings );
|
||||
|
@ -2197,7 +2211,6 @@ sqlsrv_phptype determine_sqlsrv_php_type( sqlsrv_stmt const* stmt, SQLINTEGER sq
|
|||
|
||||
// put in the column size and scale/decimal digits of the sql server type
|
||||
// these values are taken from the MSDN page at http://msdn2.microsoft.com/en-us/library/ms711786(VS.85).aspx
|
||||
// column_size is actually the size of the field in bytes, so a nvarchar(4000) is 8000 bytes
|
||||
bool determine_column_size_or_precision( sqlsrv_stmt const* stmt, sqlsrv_sqltype sqlsrv_type, __out SQLUINTEGER* column_size, __out SQLSMALLINT* decimal_digits )
|
||||
{
|
||||
*decimal_digits = 0;
|
||||
|
@ -2257,7 +2270,6 @@ bool determine_column_size_or_precision( sqlsrv_stmt const* stmt, sqlsrv_sqltype
|
|||
*column_size = SQL_SS_LENGTH_UNLIMITED;
|
||||
break;
|
||||
}
|
||||
*column_size *= 2; // convert to byte size from wchar size
|
||||
if( *column_size > SQL_SERVER_MAX_FIELD_SIZE || *column_size == SQLSRV_INVALID_SIZE ) {
|
||||
*column_size = SQLSRV_INVALID_SIZE;
|
||||
return false;
|
||||
|
@ -2489,20 +2501,33 @@ void close_active_stream( __inout sqlsrv_stmt* stmt TSRMLS_DC )
|
|||
}
|
||||
}
|
||||
|
||||
// convert a string from utf-16 to another encoding and return the new string. The utf-16 string is released
|
||||
// by this function if no errors occurred. Otherwise the parameters are not changed.
|
||||
// convert a string from utf-16 to the encoding and return the new string in the pointer parameter and new
|
||||
// length in the len parameter. If no errors occurred during convertion, true is returned and the original
|
||||
// utf-16 string is released by this function if no errors occurred. Otherwise the parameters are not changed
|
||||
// and false is returned.
|
||||
|
||||
bool convert_string_from_utf16( sqlsrv_phptype sqlsrv_phptype, char** string, SQLINTEGER& len )
|
||||
bool convert_string_from_utf16( unsigned int encoding, char** string, SQLINTEGER& len )
|
||||
{
|
||||
char* utf16_string = *string;
|
||||
unsigned int utf16_len = len / 2; // from # of bytes to # of wchars
|
||||
char *enc_string = NULL;
|
||||
unsigned int enc_len = 0;
|
||||
|
||||
++utf16_len; // include the NULL character
|
||||
// for the empty string, we simply returned we converted it
|
||||
if( len == 0 && *string[0] == '\0' ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// flags set to 0 by default, which means that any invalid characters are dropped rather than causing
|
||||
// an error. This happens only on XP.
|
||||
DWORD flags = 0;
|
||||
if( encoding == CP_UTF8 && g_osversion.dwMajorVersion >= SQLSRV_OS_VISTA_OR_LATER ) {
|
||||
// Vista (and later) will detect invalid UTF-16 characters and raise an error.
|
||||
flags = WC_ERR_INVALID_CHARS;
|
||||
}
|
||||
|
||||
// calculate the number of characters needed
|
||||
enc_len = WideCharToMultiByte( sqlsrv_phptype.typeinfo.encoding, 0,
|
||||
enc_len = WideCharToMultiByte( encoding, flags,
|
||||
reinterpret_cast<LPCWSTR>( utf16_string ), utf16_len,
|
||||
NULL, 0, NULL, NULL );
|
||||
if( enc_len == 0 ) {
|
||||
|
@ -2510,17 +2535,18 @@ bool convert_string_from_utf16( sqlsrv_phptype sqlsrv_phptype, char** string, SQ
|
|||
}
|
||||
// we must allocate a new buffer because it is possible that a UTF-8 string is longer than
|
||||
// the corresponding UTF-16 string, so we cannot use an inplace conversion
|
||||
enc_string = reinterpret_cast<char*>( sqlsrv_malloc( enc_len + 1 ));
|
||||
int rc = WideCharToMultiByte( sqlsrv_phptype.typeinfo.encoding, 0,
|
||||
enc_string = reinterpret_cast<char*>( sqlsrv_malloc( enc_len + 1 /* NULL char*/ ));
|
||||
int rc = WideCharToMultiByte( encoding, flags,
|
||||
reinterpret_cast<LPCWSTR>( utf16_string ), utf16_len,
|
||||
enc_string, enc_len, NULL, NULL );
|
||||
if( rc == 0 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
enc_string[ enc_len ] = '\0'; // null terminate the encoded string
|
||||
sqlsrv_free( utf16_string );
|
||||
*string = enc_string;
|
||||
len = enc_len - 1;
|
||||
len = enc_len;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -2699,7 +2725,7 @@ void get_field_as_string( sqlsrv_stmt const* s, sqlsrv_phptype sqlsrv_phptype, S
|
|||
}
|
||||
|
||||
if( c_type == SQL_C_WCHAR ) {
|
||||
bool converted = convert_string_from_utf16( sqlsrv_phptype, &field, field_len );
|
||||
bool converted = convert_string_from_utf16( sqlsrv_phptype.typeinfo.encoding, &field, field_len );
|
||||
if( !converted ) {
|
||||
handle_error( &s->ctx, LOG_STMT, _FN_, SQLSRV_ERROR_FIELD_ENCODING_TRANSLATE TSRMLS_CC, get_last_error_message() );
|
||||
sqlsrv_free( field );
|
||||
|
@ -2739,7 +2765,7 @@ void get_field_as_string( sqlsrv_stmt const* s, sqlsrv_phptype sqlsrv_phptype, S
|
|||
|
||||
if( c_type == SQL_C_WCHAR ) {
|
||||
|
||||
bool converted = convert_string_from_utf16( sqlsrv_phptype, &field, field_len );
|
||||
bool converted = convert_string_from_utf16( sqlsrv_phptype.typeinfo.encoding, &field, field_len );
|
||||
if( !converted ) {
|
||||
handle_error( &s->ctx, LOG_STMT, _FN_, SQLSRV_ERROR_FIELD_ENCODING_TRANSLATE TSRMLS_CC, get_last_error_message() );
|
||||
sqlsrv_free( field );
|
||||
|
@ -2995,8 +3021,8 @@ void fetch_common( __inout sqlsrv_stmt* stmt, int fetch_type, long fetch_style,
|
|||
SQLLEN field_type;
|
||||
SQLLEN field_len;
|
||||
sqlsrv_phptype sqlsrv_php_type;
|
||||
// we don't use a zend_auto_ptr because ownership is transferred to the fields hash table
|
||||
// that will be destroyed if an error occurs.
|
||||
// this zval_auto_ptr is never transferred because we rely on its destructor to decrement the reference count
|
||||
// we increment its reference count within each fetch type (below)
|
||||
zval_auto_ptr field;
|
||||
|
||||
MAKE_STD_ZVAL( field );
|
||||
|
|
10
stream.cpp
10
stream.cpp
|
@ -101,8 +101,16 @@ size_t sqlsrv_stream_read( php_stream* stream, __out_bcount(count) char* buf, si
|
|||
|
||||
// convert it to UTF-8 if that's what's needed
|
||||
if( c_type == SQL_C_WCHAR ) {
|
||||
|
||||
count *= 2; // undo the shift to use the full buffer
|
||||
int w = WideCharToMultiByte( ss->encoding, 0, reinterpret_cast<LPCWSTR>( ss->stmt->param_buffer ),
|
||||
// flags set to 0 by default, which means that any invalid characters are dropped rather than causing
|
||||
// an error. This happens only on XP.
|
||||
DWORD flags = 0;
|
||||
if( ss->encoding == CP_UTF8 && g_osversion.dwMajorVersion >= SQLSRV_OS_VISTA_OR_LATER ) {
|
||||
// Vista (and later) will detect invalid UTF-16 characters and raise an error.
|
||||
flags = WC_ERR_INVALID_CHARS;
|
||||
}
|
||||
int w = WideCharToMultiByte( ss->encoding, flags, reinterpret_cast<LPCWSTR>( ss->stmt->param_buffer ),
|
||||
read >> 1, buf, count, NULL, NULL );
|
||||
if( w == 0 ) {
|
||||
stream->eof = 1;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// Comments:
|
||||
//
|
||||
// License: This software is released under the Microsoft Public License. A copy of the license agreement
|
||||
// may be found online at http://www.codeplex.com/SQL2K5PHP/license.
|
||||
// may be found online at http://www.codeplex.com/SQLSRVPHP/license.
|
||||
//----------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
|
|
18
util.cpp
18
util.cpp
|
@ -195,7 +195,7 @@ sqlsrv_error SQLSRV_ERROR_CONNECT_ILLEGAL_ENCODING[] = {
|
|||
};
|
||||
sqlsrv_error SQLSRV_ERROR_DRIVER_NOT_INSTALLED[] = {
|
||||
{ IMSSP, "The SQL Server Driver for PHP requires the SQL Server 2008 Native Client ODBC Driver (SP1 or later) to communicate with SQL Server. "
|
||||
"That ODBC Driver is not currently installed. Accessing the following URL will download the SQL Server 2008 Native Client ODBC driver for %1!s!: %2!s!", -49, true }
|
||||
"That ODBC Driver is not currently installed. Access the following URL to download the SQL Server 2008 Native Client ODBC driver for %1!s!: http://go.microsoft.com/fwlink/?LinkId=163712", -49, true }
|
||||
};
|
||||
sqlsrv_error SQLSRV_ERROR_MARS_OFF[] = {
|
||||
{ IMSSP, "The connection cannot process this operation because there is a statement with pending results. "
|
||||
|
@ -214,8 +214,8 @@ sqlsrv_error SQLSRV_ERROR_INVALID_FETCH_STYLE[] = {
|
|||
sqlsrv_error SQLSRV_ERROR_INVALID_OPTION_SCROLLABLE[] = {
|
||||
{ IMSSP, "The value passed for the 'Scrollable' statement option is invalid. Please use 'static', 'dynamic', 'keyset', or 'forward'.", -54, false }
|
||||
};
|
||||
sqlsrv_error SQLSRV_ERROR_INVALID_SERVER_VERSION[] = {
|
||||
{ IMSSP, "Attempted to connect to a server of version %1!d!. Only connections to SQL Server 2000 (8) or later are supported.", -55, true }
|
||||
sqlsrv_error SQLSRV_ERROR_UNKNOWN_SERVER_VERSION[] = {
|
||||
{ IMSSP, "Failed to retrieve the server version. Unable to continue.", -55, false }
|
||||
};
|
||||
|
||||
|
||||
|
@ -784,6 +784,8 @@ bool handle_errors_and_warnings( sqlsrv_context const* ctx, zval** reported_chai
|
|||
zval_ptr_dtor( &ssphp_z );
|
||||
break;
|
||||
}
|
||||
// increasing the ref count since we've added it to the ssphp_z array twice
|
||||
zval_add_ref( &temp );
|
||||
MAKE_STD_ZVAL( temp );
|
||||
ZVAL_LONG( temp, ssphp->native_code );
|
||||
zr = add_next_index_zval( ssphp_z, temp );
|
||||
|
@ -796,6 +798,8 @@ bool handle_errors_and_warnings( sqlsrv_context const* ctx, zval** reported_chai
|
|||
zval_ptr_dtor( &ssphp_z );
|
||||
break;
|
||||
}
|
||||
// increasing the ref count since we've added it to the ssphp_z array twice
|
||||
zval_add_ref( &temp );
|
||||
MAKE_STD_ZVAL( temp );
|
||||
ZVAL_STRING( temp, const_cast<char*>( ssphp->native_message ), 1 );
|
||||
zr = add_next_index_zval( ssphp_z, temp );
|
||||
|
@ -808,6 +812,8 @@ bool handle_errors_and_warnings( sqlsrv_context const* ctx, zval** reported_chai
|
|||
zval_ptr_dtor( &ssphp_z );
|
||||
break;
|
||||
}
|
||||
// increasing the ref count since we've added it to the ssphp_z array twice
|
||||
zval_add_ref( &temp );
|
||||
|
||||
if( ignore_warning( ssphp->sqlstate, ssphp->native_code TSRMLS_CC ) && ignored_chain != NULL ) {
|
||||
zr = add_next_index_zval( *ignored_chain, ssphp_z );
|
||||
|
@ -861,6 +867,8 @@ bool handle_errors_and_warnings( sqlsrv_context const* ctx, zval** reported_chai
|
|||
zval_ptr_dtor( &ssphp_z );
|
||||
continue;
|
||||
}
|
||||
// increasing the ref count since we've added it to the ssphp_z array twice
|
||||
zval_add_ref( &temp );
|
||||
MAKE_STD_ZVAL( temp );
|
||||
ZVAL_LONG( temp, native_error );
|
||||
zr = add_next_index_zval( ssphp_z, temp );
|
||||
|
@ -873,6 +881,8 @@ bool handle_errors_and_warnings( sqlsrv_context const* ctx, zval** reported_chai
|
|||
zval_ptr_dtor( &ssphp_z );
|
||||
continue;
|
||||
}
|
||||
// increasing the ref count since we've added it to the ssphp_z array twice
|
||||
zval_add_ref( &temp );
|
||||
MAKE_STD_ZVAL( temp );
|
||||
ZVAL_STRINGL( temp, reinterpret_cast<char*>( message_text ), message_len, 1 );
|
||||
zr = add_next_index_zval( ssphp_z, temp );
|
||||
|
@ -885,6 +895,8 @@ bool handle_errors_and_warnings( sqlsrv_context const* ctx, zval** reported_chai
|
|||
zval_ptr_dtor( &ssphp_z );
|
||||
continue;
|
||||
}
|
||||
// increasing the ref count since we've added it to the ssphp_z array twice
|
||||
zval_add_ref( &temp );
|
||||
|
||||
if( ignore_warning( reinterpret_cast<const char*>( sql_state ), native_error TSRMLS_CC ) && ignored_chain != NULL ) {
|
||||
zr = add_next_index_zval( *ignored_chain, ssphp_z );
|
||||
|
|
Loading…
Reference in a new issue