SQL Server Driver for PHP 1.0 April 2009 Cumulative Update
Please see the README.txt for informaton about changes made for this update.
This commit is contained in:
parent
c62bf03a62
commit
c920eb693c
|
@ -1,17 +1,17 @@
|
|||
|
||||
* Notes about changes to the SQL Server 2005 Driver for PHP October 2008 Cumulative Update (CU) *
|
||||
* Notes about changes to the SQL Server Driver for PHP April 2009 Cumulative Update (CU) *
|
||||
|
||||
For details about the changes included in this CU, 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 2005 Driver for PHP October 2008 CU *
|
||||
* Notes about compiling the SQL Server Driver for PHP April 2009 CU *
|
||||
|
||||
Prerequisites: You must first be able to build PHP without including
|
||||
the SQL Server 2005 Driver for PHP extension. For help with doing this, see
|
||||
the SQL Server Driver for PHP extension. For help with doing this, see
|
||||
the official PHP website, http://php.net.
|
||||
|
||||
To compile the SQL Server 2005 Driver for PHP:
|
||||
To compile the SQL Server Driver for PHP:
|
||||
|
||||
1) Copy the source code into the ext\sqlsrv directory.
|
||||
|
||||
|
|
87
conn.cpp
87
conn.cpp
|
@ -40,11 +40,21 @@ 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" }
|
||||
};
|
||||
|
||||
// *** 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 const* conn, const char* server, zval const* options,
|
||||
__inout std::string& connection_string TSRMLS_DC );
|
||||
struct _platform_url* get_driver_info( void );
|
||||
bool mark_params_by_reference( zval** params_zz, char const* _FN_ TSRMLS_DC );
|
||||
void sqlsrv_conn_common_close( sqlsrv_conn* c, const char* function, bool check_errors TSRMLS_DC );
|
||||
|
||||
|
@ -213,6 +223,19 @@ PHP_FUNCTION( sqlsrv_connect )
|
|||
memset( const_cast<char*>( conn_str.c_str()), 0, conn_str.size() );
|
||||
conn_str.clear();
|
||||
|
||||
if( !SQL_SUCCEEDED( r )) {
|
||||
SQLCHAR state[ SQL_SQLSTATE_BUFSIZE ];
|
||||
SQLSMALLINT len;
|
||||
SQLRETURN r = SQLGetDiagField( SQL_HANDLE_DBC, conn->ctx.handle, 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len );
|
||||
// if the SQLSTATE is IM002, that means 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 );
|
||||
SQLFreeHandle( conn->ctx.handle_type, conn->ctx.handle );
|
||||
conn->ctx.handle = SQL_NULL_HANDLE;
|
||||
RETURN_FALSE;
|
||||
}
|
||||
}
|
||||
CHECK_SQL_ERROR( r, conn, _FN_, NULL,
|
||||
SQLFreeHandle( conn->ctx.handle_type, conn->ctx.handle ); conn->ctx.handle = SQL_NULL_HANDLE; RETURN_FALSE );
|
||||
CHECK_SQL_WARNING( r, conn, _FN_, NULL );
|
||||
|
@ -237,7 +260,7 @@ PHP_FUNCTION( sqlsrv_connect )
|
|||
// the call to sqlsrv_begin_transaction and before any calls to sqlsrv_rollback
|
||||
// or sqlsrv_commit.
|
||||
//
|
||||
// The SQL Server 2005 Driver for PHP is in auto-commit mode by default. This
|
||||
// The SQL Server Driver for PHP is in auto-commit mode by default. This
|
||||
// means that all queries are automatically committed upon success unless they
|
||||
// have been designated as part of an explicit transaction by using
|
||||
// sqlsrv_begin_transaction.
|
||||
|
@ -444,7 +467,7 @@ void __cdecl sqlsrv_conn_dtor( zend_rsrc_list_entry *rsrc TSRMLS_DC )
|
|||
// connection to the auto-commit mode. The current transaction includes all
|
||||
// statements on the specified connection that were executed after the call to
|
||||
// sqlsrv_begin_transaction and before any calls to sqlsrv_rollback or
|
||||
// sqlsrv_commit. The SQL Server 2005 Driver for PHP is in auto-commit mode by
|
||||
// sqlsrv_commit. The SQL Server Driver for PHP is in auto-commit mode by
|
||||
// default. This means that all queries are automatically committed upon success
|
||||
// unless they have been designated as part of an explicit transaction by using
|
||||
// sqlsrv_begin_transaction. If sqlsrv_commit is called on a connection that is
|
||||
|
@ -552,9 +575,10 @@ PHP_FUNCTION( sqlsrv_prepare )
|
|||
|
||||
stmt->prepared = true;
|
||||
|
||||
if( !mark_params_by_reference( ¶ms_z, _FN_ TSRMLS_CC )) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
if( !mark_params_by_reference( ¶ms_z, _FN_ TSRMLS_CC )) {
|
||||
free_odbc_resources( stmt TSRMLS_CC );
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
stmt->params_z = params_z;
|
||||
|
||||
|
@ -639,12 +663,18 @@ PHP_FUNCTION( sqlsrv_query )
|
|||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
if( !mark_params_by_reference( ¶ms_z, _FN_ TSRMLS_CC )) {
|
||||
// if it's not a NULL pointer and not an array, return an error
|
||||
if( params_z && Z_TYPE_P( params_z ) != IS_ARRAY ) {
|
||||
free_odbc_resources( stmt TSRMLS_CC );
|
||||
handle_error( NULL, LOG_CONN, _FN_, SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER TSRMLS_CC, _FN_ );
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
stmt->params_z = params_z;
|
||||
// zval_add_ref released in free_odbc_resources
|
||||
if( params_z ) {
|
||||
zval_add_ref( ¶ms_z );
|
||||
}
|
||||
|
||||
executed = sqlsrv_stmt_common_execute( stmt, sql_string, sql_len, true, _FN_ TSRMLS_CC );
|
||||
|
||||
|
@ -687,7 +717,7 @@ PHP_FUNCTION( sqlsrv_query )
|
|||
// statements on the specified connection that were executed after the call to
|
||||
// sqlsrv_begin_transaction and before any calls to sqlsrv_rollback or
|
||||
// sqlsrv_commit.
|
||||
// The SQL Server 2005 Driver for PHP is in auto-commit mode by default. This
|
||||
// The SQL Server Driver for PHP is in auto-commit mode by default. This
|
||||
// means that all queries are automatically committed upon success unless they
|
||||
// have been designated as part of an explicit transaction by using
|
||||
// sqlsrv_begin_transaction.
|
||||
|
@ -1116,7 +1146,9 @@ sqlsrv_stmt* allocate_stmt( __in sqlsrv_conn* conn, zval const* options_z, char
|
|||
stmt->current_parameter = NULL;
|
||||
stmt->current_parameter_read = 0;
|
||||
stmt->params_z = NULL;
|
||||
stmt->params_ind_ptr = NULL;
|
||||
stmt->param_datetime_buffers = NULL;
|
||||
stmt->param_output_strings = NULL;
|
||||
stmt->param_buffer = param_buffer;
|
||||
stmt->param_buffer_size = PHP_STREAM_BUFFER_SIZE;
|
||||
stmt->send_at_exec = true;
|
||||
|
@ -1226,13 +1258,20 @@ bool mark_params_by_reference( __inout zval** params_zz, char const* _FN_ TSRMLS
|
|||
zend_hash_has_more_elements( params_ht ) == SUCCESS;
|
||||
zend_hash_move_forward( params_ht ), ++i ) {
|
||||
|
||||
|
||||
zr = zend_hash_get_current_data_ex( params_ht, reinterpret_cast<void**>( ¶m ), NULL );
|
||||
CHECK_ZEND_ERROR( zr, SQLSRV_ERROR_ZEND_HASH, zval_ptr_dtor( params_zz ); return false; );
|
||||
|
||||
// if it's a sole variable
|
||||
if( Z_TYPE_PP( param ) != IS_ARRAY ) {
|
||||
(*param)->is_ref = 1; // mark it as a reference
|
||||
if( !PZVAL_IS_REF( *param ) && Z_REFCOUNT_P( *param ) > 1 ) {
|
||||
// 10 should be sufficient for adding up to a 3 digit number to the message
|
||||
int warning_len = strlen( PHP_WARNING_VAR_NOT_REFERENCE->native_message ) + 10;
|
||||
emalloc_auto_ptr<char> warning;
|
||||
warning = static_cast<char*>( emalloc( warning_len ));
|
||||
snprintf( warning, warning_len, PHP_WARNING_VAR_NOT_REFERENCE->native_message, i );
|
||||
php_error( E_WARNING, warning );
|
||||
}
|
||||
Z_SET_ISREF_PP( param ); // mark it as a reference
|
||||
}
|
||||
// else mark [0] as a reference
|
||||
else {
|
||||
|
@ -1243,11 +1282,39 @@ bool mark_params_by_reference( __inout zval** params_zz, char const* _FN_ TSRMLS
|
|||
zval_ptr_dtor( params_zz );
|
||||
return false;
|
||||
}
|
||||
(*var)->is_ref = 1;
|
||||
if( !PZVAL_IS_REF( *var ) && Z_REFCOUNT_P( *var ) > 1 ) {
|
||||
// 10 should be sufficient for adding up to a 3 digit number to the message
|
||||
int warning_len = strlen( PHP_WARNING_VAR_NOT_REFERENCE->native_message ) + 10;
|
||||
emalloc_auto_ptr<char> warning;
|
||||
warning = static_cast<char*>( emalloc( warning_len ));
|
||||
snprintf( warning, warning_len, PHP_WARNING_VAR_NOT_REFERENCE->native_message, i );
|
||||
php_error( E_WARNING, warning );
|
||||
}
|
||||
Z_SET_ISREF_PP( var );
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct _platform_url* get_driver_info( void )
|
||||
{
|
||||
SYSTEM_INFO sys_info;
|
||||
|
||||
GetSystemInfo( &sys_info );
|
||||
|
||||
switch( sys_info.wProcessorArchitecture ) {
|
||||
|
||||
case PROCESSOR_ARCHITECTURE_INTEL:
|
||||
return &driver_info[0];
|
||||
case PROCESSOR_ARCHITECTURE_AMD64:
|
||||
return &driver_info[1];
|
||||
case PROCESSOR_ARCHITECTURE_IA64:
|
||||
return &driver_info[2];
|
||||
default:
|
||||
DIE( "Unknown Windows processor architecture" );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
6
init.cpp
6
init.cpp
|
@ -3,7 +3,7 @@
|
|||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// Contents: The initialization routines for the SQL Server 2005 Driver for PHP 1.0
|
||||
// Contents: The initialization routines for the SQL Server Driver for PHP 1.0
|
||||
//
|
||||
// Comments:
|
||||
//
|
||||
|
@ -495,9 +495,9 @@ PHP_RINIT_FUNCTION(sqlsrv)
|
|||
SQLSRV_G( henv_context )->ctx.handle = g_henv_cp;
|
||||
SQLSRV_G( henv_context )->ctx.handle_type = SQL_HANDLE_ENV;
|
||||
ALLOC_INIT_ZVAL( SQLSRV_G( errors ));
|
||||
SQLSRV_G( errors )->is_ref = 1;
|
||||
Z_SET_ISREF_PP( &SQLSRV_G( errors ) );
|
||||
ALLOC_INIT_ZVAL( SQLSRV_G( warnings ));
|
||||
SQLSRV_G( warnings )->is_ref = 1;
|
||||
Z_SET_ISREF_PP( &SQLSRV_G( warnings ) );
|
||||
|
||||
// read INI settings
|
||||
SQLSRV_G( warnings_return_as_errors ) = INI_BOOL( INI_PREFIX INI_WARNINGS_RETURN_AS_ERRORS );
|
||||
|
|
41
php_sqlsrv.h
41
php_sqlsrv.h
|
@ -6,7 +6,7 @@
|
|||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// Contents: Declarations for the SQL Server 2005 Driver for PHP 1.0
|
||||
// Contents: Declarations for the SQL Server Driver for PHP 1.0
|
||||
//
|
||||
// Comments: Also contains "internal" declarations shared across source files.
|
||||
//
|
||||
|
@ -61,6 +61,10 @@ typedef int socklen_t;
|
|||
|
||||
#pragma warning(pop)
|
||||
|
||||
#if PHP_MAJOR_VERSION > 5 || PHP_MAJOR_VERSION < 5 || ( PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 2 ) || ( PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 3 )
|
||||
#error Trying to compile "Microsoft SQL Server Driver for PHP" with an unsupported version of PHP
|
||||
#endif
|
||||
|
||||
#if ZEND_DEBUG
|
||||
// debug build causes warning C4505 to pop up from the Zend header files
|
||||
#pragma warning( disable: 4505 )
|
||||
|
@ -102,6 +106,12 @@ struct sqlsrv_static_assert<true> { static const int value = 1; };
|
|||
|
||||
#define SQLSRV_STATIC_ASSERT( c ) (sqlsrv_static_assert<(c) != 0>() )
|
||||
|
||||
#if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION <= 2
|
||||
#define Z_SET_ISREF_P( pzval ) ((pzval)->is_ref = 1)
|
||||
#define Z_SET_ISREF_PP( ppzval ) Z_SET_ISREF_P(*(ppzval))
|
||||
#define Z_REFCOUNT_P( pzval ) ((pzval)->refcount)
|
||||
#endif
|
||||
|
||||
|
||||
//**********************************************************************************************************************************
|
||||
// Initialization Functions
|
||||
|
@ -182,10 +192,21 @@ struct sqlsrv_fetch_field {
|
|||
unsigned int len;
|
||||
};
|
||||
|
||||
// holds the string output parameter information
|
||||
struct sqlsrv_output_string {
|
||||
zval* string_z;
|
||||
int param_num; // used to index into the params_ind_ptr of sqlsrv_stmt to get the length of the output string
|
||||
|
||||
sqlsrv_output_string( zval* str_z, int param ) : string_z( str_z ), param_num( param )
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// *** statement resource structure ***
|
||||
struct sqlsrv_stmt {
|
||||
|
||||
void new_result_set( bool release_datetime_buffers = true );
|
||||
void free_param_data( void );
|
||||
void new_result_set( void );
|
||||
|
||||
sqlsrv_context ctx;
|
||||
sqlsrv_conn* conn;
|
||||
|
@ -201,7 +222,9 @@ struct sqlsrv_stmt {
|
|||
bool past_fetch_end;
|
||||
bool past_next_result_end;
|
||||
zval* params_z;
|
||||
SQLINTEGER* params_ind_ptr;
|
||||
zval* param_datetime_buffers;
|
||||
zval* param_output_strings; // list of output string parameters that need null terminating for proper length
|
||||
void* param_buffer;
|
||||
int param_buffer_size;
|
||||
bool send_at_exec;
|
||||
|
@ -500,10 +523,15 @@ extern sqlsrv_error SQLSRV_ERROR_COMMIT_FAILED[];
|
|||
extern sqlsrv_error SQLSRV_ERROR_ROLLBACK_FAILED[];
|
||||
extern sqlsrv_error SQLSRV_ERROR_AUTO_COMMIT_STILL_OFF[];
|
||||
extern sqlsrv_error SQLSRV_ERROR_REGISTER_RESOURCE[];
|
||||
extern sqlsrv_error SQLSRV_ERROR_DRIVER_NOT_INSTALLED[];
|
||||
|
||||
// definitions for PHP specific warnings returned by sqlsrv
|
||||
extern sqlsrv_error SQLSRV_WARNING_FIELD_NAME_EMPTY[];
|
||||
|
||||
|
||||
// definitios for PHP warnings returned via php_error
|
||||
extern sqlsrv_error PHP_WARNING_VAR_NOT_REFERENCE[];
|
||||
|
||||
enum error_handling_flags {
|
||||
SQLSRV_ERR_ERRORS,
|
||||
SQLSRV_ERR_WARNINGS,
|
||||
|
@ -1073,6 +1101,15 @@ public:
|
|||
return sqlsrv_auto_ptr<zval, zval_auto_ptr>::operator=( ptr );
|
||||
}
|
||||
|
||||
#if PHP_MAJOR_VERSION > 5 || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 3)
|
||||
// New for 5.3. 5.3.x now uses an augmented zval, called a zval_gc_info which contains
|
||||
// information about the gc buffer it was allocated from
|
||||
operator zval_gc_info*()
|
||||
{
|
||||
return reinterpret_cast<zval_gc_info*>( _ptr );
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
zval_auto_ptr( const zval_auto_ptr& src );
|
||||
|
|
215
stmt.cpp
215
stmt.cpp
|
@ -40,11 +40,11 @@ const size_t DATETIME_CLASS_NAME_LEN = sizeof( DATETIME_CLASS_NAME ) - 1;
|
|||
const char DATETIME_FORMAT[] = "Y-m-d H:i:s.u";
|
||||
const size_t DATETIME_FORMAT_LEN = sizeof( DATETIME_FORMAT );
|
||||
|
||||
// constants for maximums in SQL Server 2005
|
||||
const int SQL_SERVER_2005_MAX_FIELD_SIZE = 8000;
|
||||
const int SQL_SERVER_2005_MAX_PRECISION = 38;
|
||||
const int SQL_SERVER_2005_DEFAULT_PRECISION = 18;
|
||||
const int SQL_SERVER_2005_DEFAULT_SCALE = 0;
|
||||
// constants for maximums in SQL Server
|
||||
const int SQL_SERVER_MAX_FIELD_SIZE = 8000;
|
||||
const int SQL_SERVER_MAX_PRECISION = 38;
|
||||
const int SQL_SERVER_DEFAULT_PRECISION = 18;
|
||||
const int SQL_SERVER_DEFAULT_SCALE = 0;
|
||||
|
||||
// base allocation size when retrieving a string field
|
||||
const int INITIAL_FIELD_STRING_LEN = 256;
|
||||
|
@ -69,6 +69,7 @@ const char STDCLASS_NAME_LEN = sizeof( STDCLASS_NAME ) - 1;
|
|||
// *** internal function prototypes ***
|
||||
|
||||
// These are arranged alphabetically. They are all used by the sqlsrv statement functions.
|
||||
bool adjust_output_string_lengths( sqlsrv_stmt* stmt, const char* _FN_ TSRMLS_DC );
|
||||
SQLSMALLINT binary_or_char_encoding( SQLSMALLINT c_type );
|
||||
bool check_for_next_stream_parameter( sqlsrv_stmt* stmt, zval* return_value TSRMLS_DC );
|
||||
void close_active_stream( sqlsrv_stmt* s TSRMLS_DC );
|
||||
|
@ -81,6 +82,7 @@ sqlsrv_sqltype determine_sql_type( int php_type, int encoding, zval const* value
|
|||
void fetch_common( sqlsrv_stmt* stmt, int fetch_type, zval* return_value, const char* _FN_, bool allow_empty_field_names TSRMLS_DC );
|
||||
void get_field_common( sqlsrv_stmt* s, const char* _FN_, sqlsrv_phptype sqlsrv_phptype, SQLUSMALLINT field_index, zval**field_value TSRMLS_DC );
|
||||
void get_field_as_string( sqlsrv_stmt const* s, SQLSMALLINT c_type, SQLUSMALLINT field_index, zval* return_value, const char* _FN_ TSRMLS_DC );
|
||||
SQLRETURN has_rows( sqlsrv_stmt* stmt, bool& rows_present );
|
||||
bool is_fixed_size_type( SQLINTEGER sql_type );
|
||||
bool is_streamable_type( SQLINTEGER sql_type );
|
||||
bool is_valid_sqlsrv_sqltype( sqlsrv_sqltype type );
|
||||
|
@ -204,15 +206,6 @@ PHP_FUNCTION( sqlsrv_free_stmt )
|
|||
// this frees up the php resources as well
|
||||
remove_from_connection( stmt TSRMLS_CC );
|
||||
|
||||
// cause any variables still holding a reference to this to be invalid so they cause
|
||||
// an error when passed to a sqlsrv function. There's nothing we can do if the
|
||||
// removal fails, so we just log it and move on.
|
||||
int zr = zend_hash_index_del( &EG( regular_list ), Z_RESVAL_P( stmt_r ));
|
||||
if( zr == FAILURE ) {
|
||||
LOG( SEV_ERROR, LOG_STMT, "Failed to remove stmt resource %d", Z_RESVAL_P( stmt_r ));
|
||||
}
|
||||
ZVAL_NULL( stmt_r );
|
||||
|
||||
RETURN_TRUE;
|
||||
}
|
||||
|
||||
|
@ -382,7 +375,7 @@ PHP_FUNCTION( sqlsrv_fetch_array )
|
|||
// class property, a property with the result set field name is added to the
|
||||
// object and the result set value is applied to the property. For more
|
||||
// information about calling sqlsrv_fetch_object with the $className parameter,
|
||||
// see How to: Retrieve Data as an Object (SQL Server 2005 Driver for PHP).
|
||||
// see How to: Retrieve Data as an Object (SQL Server Driver for PHP).
|
||||
//
|
||||
// If a field with no name is returned, sqlsrv_fetch_object will discard the
|
||||
// field value and issue a warning.
|
||||
|
@ -491,12 +484,20 @@ PHP_FUNCTION( sqlsrv_fetch_object )
|
|||
fci.retval_ptr_ptr = &ctor_retval_z;
|
||||
fci.param_count = num_params;
|
||||
fci.params = params_m; // purposefully not transferred since ownership isn't actually transferred.
|
||||
#if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION <= 2
|
||||
fci.object_pp = &return_value;
|
||||
#else
|
||||
fci.object_ptr = return_value;
|
||||
#endif
|
||||
memset( &fcic, 0, sizeof( fcic ));
|
||||
fcic.initialized = 1;
|
||||
fcic.function_handler = (*class_entry)->constructor;
|
||||
fcic.calling_scope = *class_entry;
|
||||
#if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION <= 2
|
||||
fcic.object_pp = &return_value;
|
||||
#else
|
||||
fcic.object_ptr = return_value;
|
||||
#endif
|
||||
zr = zend_call_function( &fci, &fcic TSRMLS_CC );
|
||||
if( zr == FAILURE ) {
|
||||
zval_ptr_dtor( &return_value );
|
||||
|
@ -655,7 +656,7 @@ PHP_FUNCTION( sqlsrv_field_metadata )
|
|||
// $fieldIndex: The index of the field to be retrieved. Indexes begin at zero.
|
||||
// $getAsType [OPTIONAL]: A SQLSRV constant (SQLSRV_PHPTYPE) that determines
|
||||
// the PHP data type for the returned data. For information about supported data
|
||||
// types, see SQLSRV Constants (SQL Server 2005 Driver for PHP). If no return
|
||||
// types, see SQLSRV Constants (SQL Server Driver for PHP). If no return
|
||||
// type is specified, a default PHP type will be returned. For information about
|
||||
// default PHP types, see Default PHP Data Types. For information about
|
||||
// specifying PHP data types, see How to: Specify PHP Data Types.
|
||||
|
@ -753,6 +754,13 @@ PHP_FUNCTION( sqlsrv_next_result )
|
|||
// call the ODBC API that does what we want
|
||||
r = SQLMoreResults( stmt->ctx.handle );
|
||||
if( r == SQL_NO_DATA ) {
|
||||
|
||||
if( stmt->param_output_strings ) {
|
||||
if( !adjust_output_string_lengths( stmt, _FN_ TSRMLS_CC )) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// if we're at the end, then return NULL
|
||||
stmt->past_next_result_end = true;
|
||||
RETURN_NULL();
|
||||
|
@ -955,7 +963,6 @@ bool sqlsrv_stmt_common_execute( sqlsrv_stmt* stmt, const SQLCHAR* sql_string, i
|
|||
{
|
||||
SQLRETURN r;
|
||||
SQLSMALLINT i;
|
||||
emalloc_auto_ptr<SQLINTEGER> ind_ptr;
|
||||
|
||||
close_active_stream( stmt TSRMLS_CC );
|
||||
|
||||
|
@ -967,6 +974,8 @@ bool sqlsrv_stmt_common_execute( sqlsrv_stmt* stmt, const SQLCHAR* sql_string, i
|
|||
} while( r != SQL_NO_DATA );
|
||||
}
|
||||
|
||||
stmt->free_param_data();
|
||||
|
||||
stmt->executed = false;
|
||||
|
||||
if( stmt->params_z ) {
|
||||
|
@ -974,7 +983,12 @@ bool sqlsrv_stmt_common_execute( sqlsrv_stmt* stmt, const SQLCHAR* sql_string, i
|
|||
|
||||
HashTable* params_ht = Z_ARRVAL_P( stmt->params_z );
|
||||
|
||||
ind_ptr = static_cast<SQLINTEGER*>( emalloc( zend_hash_num_elements( params_ht ) * sizeof( SQLINTEGER )));
|
||||
// allocate the buffer size array used by SQLBindParameter if it wasn't allocated by a
|
||||
// previous execution. The size of the array cannot change because the number of parameters
|
||||
// cannot change in between executions.
|
||||
if( stmt->params_ind_ptr == NULL ) {
|
||||
stmt->params_ind_ptr = static_cast<SQLINTEGER*>( emalloc( zend_hash_num_elements( params_ht ) * sizeof( SQLINTEGER )));
|
||||
}
|
||||
|
||||
for( i = 1, zend_hash_internal_pointer_reset( params_ht );
|
||||
zend_hash_has_more_elements( params_ht ) == SUCCESS;
|
||||
|
@ -1026,27 +1040,47 @@ bool sqlsrv_stmt_common_execute( sqlsrv_stmt* stmt, const SQLCHAR* sql_string, i
|
|||
SQLSRV_ERROR_INVALID_OUTPUT_PARAM_TYPE, SQLFreeStmt( stmt->ctx.handle, SQL_RESET_PARAMS ); return false; );
|
||||
buffer = NULL;
|
||||
buffer_len = 0;
|
||||
ind_ptr[ i-1 ] = SQL_NULL_DATA;
|
||||
stmt->params_ind_ptr[ i-1 ] = SQL_NULL_DATA;
|
||||
break;
|
||||
case IS_LONG:
|
||||
buffer = ¶m_z->value;
|
||||
buffer_len = sizeof( param_z->value.lval );
|
||||
ind_ptr[ i-1 ] = buffer_len;
|
||||
stmt->params_ind_ptr[ i-1 ] = buffer_len;
|
||||
break;
|
||||
case IS_DOUBLE:
|
||||
buffer = ¶m_z->value;
|
||||
buffer_len = sizeof( param_z->value.dval );
|
||||
ind_ptr[ i-1 ] = buffer_len;
|
||||
stmt->params_ind_ptr[ i-1 ] = buffer_len;
|
||||
break;
|
||||
case IS_STRING:
|
||||
buffer = Z_STRVAL_PP( ¶m_z );
|
||||
buffer_len = Z_STRLEN_PP( ¶m_z );
|
||||
ind_ptr[ i-1 ] = buffer_len;
|
||||
// resize the buffer to match the column size if it's smaller
|
||||
// than the buffer given already
|
||||
if(( direction == SQL_PARAM_INPUT_OUTPUT || direction == SQL_PARAM_OUTPUT ) && buffer_len < column_size ) {
|
||||
if(( direction == SQL_PARAM_INPUT_OUTPUT || direction == SQL_PARAM_OUTPUT )) {
|
||||
if( stmt->param_output_strings == NULL ) {
|
||||
ALLOC_INIT_ZVAL( stmt->param_output_strings );
|
||||
int zr = array_init( stmt->param_output_strings );
|
||||
CHECK_ZEND_ERROR( zr, SQLSRV_ERROR_ZEND_HASH, return false );
|
||||
}
|
||||
// if we don't have enough space, then reallocate the buffer (and copy its contents)
|
||||
// the string keeps its original content until it is updated by the output, at which
|
||||
// time its length will be set to match the output in adjust_output_string_parameters
|
||||
if( buffer_len < column_size ) {
|
||||
buffer = static_cast<char*>( erealloc( buffer, column_size + 1 ));
|
||||
buffer_len = column_size + 1;
|
||||
reinterpret_cast<char*>( buffer )[ column_size ] = '\0';
|
||||
ZVAL_STRINGL( param_z, reinterpret_cast<char*>( buffer ), Z_STRLEN_P( param_z ), 0 );
|
||||
}
|
||||
// register the output string so that it will be updated when adjust_output_string_parameters is called
|
||||
sqlsrv_output_string output_string( param_z, i - 1 );
|
||||
HashTable* strings_ht = Z_ARRVAL_P( stmt->param_output_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 in the statement
|
||||
}
|
||||
stmt->params_ind_ptr[ i-1 ] = buffer_len;
|
||||
break;
|
||||
case IS_OBJECT:
|
||||
{
|
||||
|
@ -1100,7 +1134,7 @@ bool sqlsrv_stmt_common_execute( sqlsrv_stmt* stmt, const SQLCHAR* sql_string, i
|
|||
CHECK_ZEND_ERROR( zr, SQLSRV_ERROR_ZEND_HASH, return false );
|
||||
buffer_len = Z_STRLEN_P( buffer_z );
|
||||
buffer_z.transferred();
|
||||
ind_ptr[ i-1 ] = buffer_len;
|
||||
stmt->params_ind_ptr[ i-1 ] = buffer_len;
|
||||
break;
|
||||
}
|
||||
case IS_RESOURCE:
|
||||
|
@ -1112,7 +1146,7 @@ bool sqlsrv_stmt_common_execute( sqlsrv_stmt* stmt, const SQLCHAR* sql_string, i
|
|||
buffer = param_z;
|
||||
zval_add_ref( ¶m_z ); // so that it doesn't go away while we're using it
|
||||
buffer_len = 0;
|
||||
ind_ptr[ i-1 ] = SQL_DATA_AT_EXEC;
|
||||
stmt->params_ind_ptr[ i-1 ] = SQL_DATA_AT_EXEC;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -1123,7 +1157,7 @@ bool sqlsrv_stmt_common_execute( sqlsrv_stmt* stmt, const SQLCHAR* sql_string, i
|
|||
|
||||
if( direction < 0 || direction > 0xffff ) DIE( "direction not valid SQLSMALLINT" );
|
||||
r = SQLBindParameter( stmt->ctx.handle, i, static_cast<SQLSMALLINT>( direction ), sql_c_type, sql_type.typeinfo.type, column_size, decimal_digits,
|
||||
buffer, buffer_len, &ind_ptr[ i-1 ] );
|
||||
buffer, buffer_len, &stmt->params_ind_ptr[ i-1 ] );
|
||||
CHECK_SQL_ERROR( r, stmt, _FN_, NULL, SQLFreeStmt( stmt->ctx.handle, SQL_RESET_PARAMS ); return false; );
|
||||
CHECK_SQL_WARNING( r, stmt, _FN_, NULL );
|
||||
}
|
||||
|
@ -1152,15 +1186,35 @@ bool sqlsrv_stmt_common_execute( sqlsrv_stmt* stmt, const SQLCHAR* sql_string, i
|
|||
}
|
||||
}
|
||||
}
|
||||
// if a result set was generated, check for errors. Otherwise, it completed successfully but no data was
|
||||
// generated.
|
||||
else if( r != SQL_NO_DATA ) {
|
||||
// if no result set was generated just adjust any output string parameter lengths
|
||||
else if( r == SQL_NO_DATA ) {
|
||||
bool adjusted = adjust_output_string_lengths( stmt, _FN_ TSRMLS_CC );
|
||||
if( !adjusted ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
CHECK_SQL_ERROR( r, stmt, _FN_, NULL, SQLFreeStmt( stmt->ctx.handle, SQL_RESET_PARAMS ); return false; );
|
||||
CHECK_SQL_WARNING( r, stmt, _FN_, NULL );
|
||||
|
||||
// if we succeeded and are still here, then handle output string parameters
|
||||
if( SQL_SUCCEEDED( r )) {
|
||||
|
||||
bool rows_present;
|
||||
r = has_rows( stmt, rows_present );
|
||||
CHECK_SQL_ERROR( r, stmt, _FN_, NULL, SQLFreeStmt( stmt->ctx.handle, SQL_RESET_PARAMS ); return false; );
|
||||
CHECK_SQL_WARNING( r, stmt, _FN_, NULL );
|
||||
if( !rows_present ) {
|
||||
bool adjusted = adjust_output_string_lengths( stmt, _FN_ TSRMLS_CC );
|
||||
if( !adjusted ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// false means to not release the datetime buffers we just allocated.
|
||||
stmt->new_result_set( false );
|
||||
stmt->new_result_set();
|
||||
stmt->executed = true;
|
||||
|
||||
return true;
|
||||
|
@ -1177,6 +1231,10 @@ void free_odbc_resources( sqlsrv_stmt* stmt TSRMLS_DC )
|
|||
if( stmt->params_z ) {
|
||||
zval_ptr_dtor( &stmt->params_z );
|
||||
stmt->params_z = NULL;
|
||||
// free the parameter size buffer if we had one (if the statement was executed)
|
||||
if( stmt->params_ind_ptr ) {
|
||||
efree( stmt->params_ind_ptr );
|
||||
}
|
||||
}
|
||||
|
||||
close_active_stream( stmt TSRMLS_CC );
|
||||
|
@ -1188,9 +1246,9 @@ void free_odbc_resources( sqlsrv_stmt* stmt TSRMLS_DC )
|
|||
|
||||
r = SQLFreeHandle( SQL_HANDLE_STMT, stmt->ctx.handle );
|
||||
|
||||
// we don't check errors here because the error log may have already gone away. We just log them.
|
||||
// we don't handle errors here because the error log may have already gone away. We just log them.
|
||||
if( !SQL_SUCCEEDED( r ) ) {
|
||||
LOG( SEV_ERROR, LOG_STMT, "Failed to free handle for stmt resource %d", stmt->conn_index );
|
||||
LOG( SEV_ERROR, LOG_STMT, "Failed to free statement handle %1!d!", stmt->ctx.handle );
|
||||
}
|
||||
|
||||
// mark the statement as closed
|
||||
|
@ -1207,16 +1265,22 @@ void free_php_resources( zval* stmt_z TSRMLS_DC )
|
|||
return;
|
||||
}
|
||||
|
||||
stmt->free_param_data();
|
||||
|
||||
// cause any variables still holding a reference to this to be invalid so
|
||||
// they cause an error when passed to a sqlsrv function. If the removal fails,
|
||||
// we log it.
|
||||
int zr = zend_hash_index_del( &EG( regular_list ), Z_RESVAL_P( stmt_z ));
|
||||
if( zr == FAILURE ) {
|
||||
LOG( SEV_ERROR, LOG_STMT, "Failed to remove stmt resource %d", Z_RESVAL_P( stmt_z ));
|
||||
LOG( SEV_ERROR, LOG_STMT, "Failed to remove stmt resource %1!d!", Z_RESVAL_P( stmt_z ));
|
||||
}
|
||||
else {
|
||||
|
||||
// stmt won't leak if this isn't hit, since Zend cleans up the heap at the end of each request/script
|
||||
efree( stmt );
|
||||
}
|
||||
|
||||
ZVAL_NULL( stmt_z );
|
||||
efree( stmt );
|
||||
zval_ptr_dtor( &stmt_z );
|
||||
}
|
||||
|
||||
|
@ -1241,7 +1305,7 @@ void sqlsrv_stmt_hash_dtor( void* stmt_ptr )
|
|||
{
|
||||
zval* stmt_z = *(static_cast<zval**>( stmt_ptr ));
|
||||
|
||||
if( stmt_z->refcount <= 0 ) {
|
||||
if( Z_REFCOUNT_P( stmt_z ) <= 0 ) {
|
||||
DIE( "Statement refcount should be > 0 when deleting from the connection's statement list" );
|
||||
}
|
||||
|
||||
|
@ -1277,10 +1341,27 @@ void __cdecl sqlsrv_stmt_dtor( zend_rsrc_list_entry *rsrc TSRMLS_DC )
|
|||
}
|
||||
}
|
||||
|
||||
// centralized place to release all the parameter data that accrues during the execution
|
||||
// phase.
|
||||
void sqlsrv_stmt::free_param_data( void )
|
||||
{
|
||||
// if we allocated any output string parameters in a previous execution, release them here.
|
||||
if( param_output_strings ) {
|
||||
zval_ptr_dtor( ¶m_output_strings );
|
||||
param_output_strings = NULL;
|
||||
}
|
||||
|
||||
// if we allocated any datetime strings in a previous execution, release them here.
|
||||
if( param_datetime_buffers ) {
|
||||
zval_ptr_dtor( ¶m_datetime_buffers );
|
||||
param_datetime_buffers = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// to be called whenever a new result set is created, such as after an
|
||||
// execute or next_result. Resets the state variables.
|
||||
void sqlsrv_stmt::new_result_set( bool release_datetime_buffers )
|
||||
void sqlsrv_stmt::new_result_set( void )
|
||||
{
|
||||
fetch_called = false;
|
||||
if( fetch_fields ) {
|
||||
|
@ -1294,18 +1375,50 @@ void sqlsrv_stmt::new_result_set( bool release_datetime_buffers )
|
|||
last_field_index = -1;
|
||||
past_fetch_end = false;
|
||||
past_next_result_end = false;
|
||||
|
||||
// if we allocated any datetime strings, release them here.
|
||||
if( param_datetime_buffers && release_datetime_buffers ) {
|
||||
zval_ptr_dtor( ¶m_datetime_buffers );
|
||||
param_datetime_buffers = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// *** internal functions ***
|
||||
|
||||
namespace {
|
||||
|
||||
SQLRETURN has_rows( sqlsrv_stmt* stmt, bool& rows_present )
|
||||
{
|
||||
// Use SQLNumResultCols to determine if we have rows or not.
|
||||
SQLRETURN r;
|
||||
SQLSMALLINT num_cols;
|
||||
r = SQLNumResultCols( stmt->ctx.handle, &num_cols );
|
||||
rows_present = (num_cols != 0);
|
||||
return r;
|
||||
}
|
||||
|
||||
// adjust_output_string_lengths
|
||||
// called after all result sets are consumed or if there are no results sets, this function adjusts the length
|
||||
// of any output string parameters to the length returned by ODBC in the ind_ptr buffer passed as to SQLBindParameter
|
||||
bool adjust_output_string_lengths( sqlsrv_stmt* stmt, const char* _FN_ TSRMLS_DC )
|
||||
{
|
||||
if( stmt->param_output_strings == NULL )
|
||||
return true;
|
||||
|
||||
HashTable* params_ht = Z_ARRVAL_P( stmt->param_output_strings );
|
||||
|
||||
for( zend_hash_internal_pointer_reset( params_ht );
|
||||
zend_hash_has_more_elements( params_ht ) == SUCCESS;
|
||||
zend_hash_move_forward( params_ht ) ) {
|
||||
|
||||
sqlsrv_output_string *output_string;
|
||||
int zr = zend_hash_get_current_data( params_ht, (void**) &output_string );
|
||||
CHECK_ZEND_ERROR( zr, SQLSRV_ERROR_ZEND_HASH, zval_ptr_dtor( &stmt->param_output_strings ); return false; );
|
||||
char* str = Z_STRVAL_P( output_string->string_z );
|
||||
int str_len = stmt->params_ind_ptr[ output_string->param_num ];
|
||||
ZVAL_STRINGL( output_string->string_z, str, str_len, 0 );
|
||||
}
|
||||
|
||||
zval_ptr_dtor( &stmt->param_output_strings );
|
||||
stmt->param_output_strings = NULL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// check_for_next_stream_parameter
|
||||
// check for the next stream parameter. Returns true if another parameter is ready, false if either an error
|
||||
// or there are no more parameters.
|
||||
|
@ -1575,7 +1688,7 @@ sqlsrv_sqltype determine_sql_type( int php_type, int encoding, zval const* value
|
|||
else {
|
||||
sql_type.typeinfo.type = SQL_VARBINARY;
|
||||
}
|
||||
if( Z_STRLEN_P( value ) > SQL_SERVER_2005_MAX_FIELD_SIZE ) {
|
||||
if( Z_STRLEN_P( value ) > SQL_SERVER_MAX_FIELD_SIZE ) {
|
||||
sql_type.typeinfo.size = SQLSRV_SIZE_MAX_TYPE;
|
||||
}
|
||||
else {
|
||||
|
@ -1722,7 +1835,7 @@ bool determine_column_size_or_precision( sqlsrv_sqltype sqlsrv_type, __out SQLUI
|
|||
if( *column_size == SQLSRV_SIZE_MAX_TYPE ) {
|
||||
*column_size = SQL_SS_LENGTH_UNLIMITED;
|
||||
}
|
||||
else if( *column_size > SQL_SERVER_2005_MAX_FIELD_SIZE || *column_size == SQLSRV_INVALID_SIZE ) {
|
||||
else if( *column_size > SQL_SERVER_MAX_FIELD_SIZE || *column_size == SQLSRV_INVALID_SIZE ) {
|
||||
*column_size = SQLSRV_INVALID_SIZE;
|
||||
return false;
|
||||
}
|
||||
|
@ -1980,7 +2093,7 @@ void get_field_as_string( sqlsrv_stmt const* s, SQLSMALLINT c_type, SQLUSMALLINT
|
|||
CHECK_SQL_ERROR( r, s, _FN_, NULL, efree( field ); RETURN_FALSE; );
|
||||
}
|
||||
}
|
||||
else if( sql_display_size >= 1 && sql_display_size <= SQL_SERVER_2005_MAX_FIELD_SIZE ) {
|
||||
else if( sql_display_size >= 1 && sql_display_size <= SQL_SERVER_MAX_FIELD_SIZE ) {
|
||||
// only allow binary retrievals for char and binary types. All others get a char type automatically.
|
||||
if( is_fixed_size_type( sql_type )) {
|
||||
c_type = SQL_C_CHAR;
|
||||
|
@ -2047,7 +2160,7 @@ void type_and_size_calc( INTERNAL_FUNCTION_PARAMETERS, int type )
|
|||
}
|
||||
}
|
||||
|
||||
int max_size = SQL_SERVER_2005_MAX_FIELD_SIZE;
|
||||
int max_size = SQL_SERVER_MAX_FIELD_SIZE;
|
||||
// size is actually the number of characters, not the number of bytes, so if they ask for a
|
||||
// 2 byte per character type, then we half the maximum size allowed.
|
||||
if( type == SQL_WVARCHAR || type == SQL_WCHAR ) {
|
||||
|
@ -2076,15 +2189,15 @@ void type_and_precision_calc( INTERNAL_FUNCTION_PARAMETERS, int type )
|
|||
SQLSRV_UNUSED( this_ptr );
|
||||
SQLSRV_UNUSED( return_value_ptr );
|
||||
|
||||
long prec = SQL_SERVER_2005_DEFAULT_PRECISION;
|
||||
long scale = SQL_SERVER_2005_DEFAULT_SCALE;
|
||||
long prec = SQL_SERVER_DEFAULT_PRECISION;
|
||||
long scale = SQL_SERVER_DEFAULT_SCALE;
|
||||
|
||||
if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "|ll", &prec, &scale ) == FAILURE ) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if( prec > SQL_SERVER_2005_MAX_PRECISION ) {
|
||||
if( prec > SQL_SERVER_MAX_PRECISION ) {
|
||||
LOG( SEV_ERROR, LOG_STMT, "Invalid precision. Precision can't be > 38" );
|
||||
prec = SQLSRV_INVALID_PRECISION;
|
||||
}
|
||||
|
@ -2511,7 +2624,7 @@ zval* parse_param_array( sqlsrv_stmt const* stmt, const char* _FN_, const zval*
|
|||
if( Z_TYPE_PP( var_or_val ) == IS_NULL ) {
|
||||
Z_TYPE_PP( var_or_val ) = php_type;
|
||||
if( php_type == IS_STRING ) {
|
||||
Z_STRVAL_PP( var_or_val ) = static_cast<char*>( emalloc( column_size ));
|
||||
ZVAL_STRINGL( *var_or_val, static_cast<char*>( emalloc( column_size )), column_size, 0 /* don't dup the string */ );
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -126,7 +126,7 @@ OACR_WARNING_DISABLE( UNANNOTATED_BUFFER, "STREAMS_DC is a Zend macro that evals
|
|||
// open a stream and return the sqlsrv_stream_ops function table as part of the
|
||||
// return value. There is only one valid way to open a stream, using sqlsrv_get_field on
|
||||
// certain field types. A sqlsrv stream may only be opened in read mode.
|
||||
static php_stream* sqlsrv_stream_opener( php_stream_wrapper* wrapper,
|
||||
php_stream* sqlsrv_stream_opener( php_stream_wrapper* wrapper,
|
||||
__in char*, __in char* mode,
|
||||
int options, __in char **,
|
||||
php_stream_context*
|
||||
|
|
|
@ -58,9 +58,9 @@ BEGIN
|
|||
VALUE "FileDescription", FILE_DESCRIPTION "\0"
|
||||
VALUE "FileVersion", STRVER4(SQLVERSION_MAJOR,SQLVERSION_MINOR, SQLVERSION_MMDD, SQLVERSION_REVISION)
|
||||
VALUE "InternalName", FILE_NAME "\0"
|
||||
VALUE "LegalCopyright", "© 2008 Microsoft Corp. All Rights Reserved.\0"
|
||||
VALUE "LegalCopyright", "© 2009 Microsoft Corp. All Rights Reserved.\0"
|
||||
VALUE "OriginalFilename", FILE_NAME "\0"
|
||||
VALUE "ProductName", "Microsoft SQL Server 2005 Driver for PHP\0"
|
||||
VALUE "ProductName", "Microsoft SQL Server Driver for PHP\0"
|
||||
VALUE "ProductVersion", STRVER3(SQLVERSION_MAJOR,SQLVERSION_MINOR, SQLVERSION_MMDD)
|
||||
VALUE "URL", "http://www.microsoft.com\0"
|
||||
END
|
||||
|
|
13
util.cpp
13
util.cpp
|
@ -3,7 +3,7 @@
|
|||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// Contents: Utility functions for the SQL Server 2005 Driver for PHP 1.0
|
||||
// Contents: Utility functions for the SQL Server Driver for PHP 1.0
|
||||
//
|
||||
// Comments: Mostly error handling and some type handling
|
||||
//
|
||||
|
@ -165,6 +165,10 @@ sqlsrv_error SQLSRV_ERROR_AUTO_COMMIT_STILL_OFF[] = {
|
|||
sqlsrv_error SQLSRV_ERROR_REGISTER_RESOURCE[] = {
|
||||
{ IMSSP, "Registering the %1!s! resource failed.", -39, true }
|
||||
};
|
||||
sqlsrv_error SQLSRV_ERROR_DRIVER_NOT_INSTALLED[] = {
|
||||
{ IMSSP, "The SQL Server Driver for PHP requires the SQL Server 2005 Native Client ODBC Driver to communicate with SQL Server. "
|
||||
"That ODBC Driver is not currently installed. Accessing the following URL will download the SQL Server 2005 Native Client ODBC driver for %1!s!: %2!s!", -40, true }
|
||||
};
|
||||
|
||||
|
||||
// internal warning definitions
|
||||
|
@ -173,6 +177,11 @@ sqlsrv_error SQLSRV_WARNING_FIELD_NAME_EMPTY[] = {
|
|||
};
|
||||
|
||||
|
||||
// This warning is special since it's reported by php_error rather than sqlsrv_errors. That's also why it has
|
||||
// a printf format specification instead of a FormatMessage format specification.
|
||||
sqlsrv_error PHP_WARNING_VAR_NOT_REFERENCE[] = {
|
||||
{ SSPWARN, "Variable parameter %d not passed by reference (prefaced with an &). Variable parameters passed to sqlsrv_prepare should be passed by reference, not by value. For more information, see sqlsrv_prepare in the API Reference section of the product documentation.", -101, true }
|
||||
};
|
||||
|
||||
// sqlsrv_errors( [int $errorsAndOrWarnings] )
|
||||
//
|
||||
|
@ -237,7 +246,7 @@ PHP_FUNCTION( sqlsrv_errors )
|
|||
zval_ptr_dtor( &both_z );
|
||||
RETURN_FALSE;
|
||||
}
|
||||
both_z->is_ref = 1;
|
||||
Z_SET_ISREF_P( both_z );
|
||||
if( Z_TYPE_P( SQLSRV_G( errors )) == IS_ARRAY && !sqlsrv_merge_zend_hash( both_z, SQLSRV_G( errors ) TSRMLS_CC )) {
|
||||
zend_hash_destroy( Z_ARRVAL_P( both_z ));
|
||||
RETURN_FALSE;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// Contents: Routines that use connection handles
|
||||
// Contents: Version resource information
|
||||
//
|
||||
// Comments:
|
||||
//
|
||||
|
@ -11,9 +11,9 @@
|
|||
// may be found online at http://www.codeplex.com/SQL2K5PHP/license.
|
||||
//----------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
#define VER_FILEVERSION_STR "1.0.1015.0"
|
||||
#define _FILEVERSION 1,0,1015,0
|
||||
#define VER_FILEVERSION_STR "1.0.0.0"
|
||||
#define _FILEVERSION 1,0,0,0
|
||||
#define SQLVERSION_MAJOR 1
|
||||
#define SQLVERSION_MINOR 0
|
||||
#define SQLVERSION_MMDD 1015
|
||||
#define SQLVERSION_MMDD 0
|
||||
#define SQLVERSION_REVISION 0
|
||||
|
|
Loading…
Reference in a new issue