64 bit support for sqlsrv

This commit is contained in:
Meet Bhagdev 2016-03-14 20:09:46 -07:00
parent 1631882be1
commit 3c9d15704f
19 changed files with 295 additions and 211 deletions

View file

@ -4,13 +4,17 @@
The Microsoft Drivers for PHP for SQL Server are PHP extensions that allow for the reading and writing of SQL Server data from within PHP scripts. The SQLSRV extension provides a procedural interface while the PDO_SQLSRV extension implements PDO for accessing data in all editions of SQL Server 2005 and later (including Azure SQL DB). These drivers rely on the Microsoft ODBC Driver for SQL Server to handle the low-level communication with SQL Server.
This preview contains the SQLSRV driver for 32-bit PHP 7 with limitations (see Limitations below for details). Upcoming release(s) will contain more functionality, bug fixes, the PDO_SQLSRV driver, 64-bit support and more (see Plans below for more details).
This preview contains the SQLSRV driver for PHP 7 with limitations (see Limitations below for details). Upcoming release(s) will contain more functionality, bug fixes, the PDO_SQLSRV driver and more (see Plans below for more details).
The Microsoft Drivers for PHP for SQL Server Team
##Announcements
Feb 23, 2016: Thanks to the communitys input, we have mostly been focusing on making updates to support native 64-bit and the PDO driver. We will be sharing these updates in the coming weeks once we have something functional. In the meantime, we have a couple of minor updates to the SQLSRV driver to share:
March 15, 2016 (4.0.2): 64-bit support is now available for the SQLSRV driver. We also have some additional minor improvements to share:
- Fixed the ability to retrieve strings as an output parameter
- Fixed a number of memory leaks in initialization
Feb 23, 2016 (4.0.1): Thanks to the communitys input, we have mostly been focusing on making updates to support native 64-bit and the PDO driver. We will be sharing these updates in the coming weeks once we have something functional. In the meantime, we have a couple of minor updates to the SQLSRV driver to share:
- Fixed the ability to bind parameters with datetime types
- Fixed output and bidirectional (input/output) parameters. Note to users: we determined that output and bidirectional parameters now need to be passed in by reference (i.e. &$var) so that they can be updated with the output data and added an error check for these cases.
- Updated refcounting to avoid unnecessary reference counting for scalar values
@ -18,7 +22,7 @@ Feb 23, 2016: Thanks to the communitys input, we have mostly been focusing on
## Build
Note: if you prefer, you can use the pre-compiled binary found [HERE](https://github.com/Azure/msphpsql/releases/tag/v4.0.0)
Note: if you prefer, you can use the pre-compiled binary found [HERE](https://github.com/Azure/msphpsql/tree/PHP-7.0/binaries)
####Prerequisites
@ -36,7 +40,7 @@ You must first be able to build PHP 7 without including these extensions. For h
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 7.0.2 using the Visual C++ 2015 compiler.
This software has been compiled and tested under PHP 7.0.4 using the Visual C++ 2015 compiler.
## Install
@ -58,21 +62,23 @@ For samples, please see the sample folder. For setup instructions, see [here] [
## Limitations
This preview contains the 32-bit port for PHP 7 of the SQLSRV driver. The focus was on basic functionality. The following items are not supported:
This preview contains the PHP 7 port of the SQLSRV driver. The focus was on basic functionality. The following items are not supported:
- PDO
- Native 64 Bit
- Backwards compatibility with PHP 5
- Retrieving stream data and metadata
- Retrieving some varchar, nvarchar, ntext, binary, varbinary, uniqueidentifier, datetime, smalldatetime, and timestamp fields
- Handle UTF8 strings
- Retrieve strings as an output parameter
- Fetch a user defined object into a class
And some aspects of the following items need improvement:
- Memory management
- Logging and error handling
Known issues for 64-bit only:
- Retrieving integers as output parameters
- Re-preparing the same statement with referenced datetime parameters
## Future Plans
@ -125,4 +131,3 @@ The Microsoft Drivers for PHP for SQL Server are licensed under the MIT license.
[phpazure]: https://azure.microsoft.com/en-us/documentation/articles/sql-database-develop-php-simple-windows/

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1 +1 @@
Microsoft Drivers 4.0.8219 for PHP for SQL Server (SQLSRV driver)
Microsoft Drivers 4.0.0 for PHP for SQL Server (SQLSRV driver)

View file

@ -55,7 +55,7 @@ struct conn_char_set_func {
{
convert_to_string( value );
const char* encoding = Z_STRVAL_P( value );
unsigned int encoding_len = Z_STRLEN_P( value );
size_t encoding_len = Z_STRLEN_P( value );
for( zend_hash_internal_pointer_reset( g_ss_encodings_ht );
zend_hash_has_more_elements( g_ss_encodings_ht ) == SUCCESS;
@ -105,8 +105,7 @@ struct int_conn_attr_func {
{
try {
core::SQLSetConnectAttr( conn, Attr, reinterpret_cast<SQLPOINTER>( Z_LVAL_P( value )),
SQL_IS_UINTEGER TSRMLS_CC );
core::SQLSetConnectAttr( conn, Attr, reinterpret_cast<SQLPOINTER>( Z_LVAL_P( value )), SQL_IS_UINTEGER TSRMLS_CC );
}
catch( core::CoreException& ) {
throw;
@ -120,9 +119,9 @@ struct bool_conn_attr_func {
static void func( connection_option const* /*option*/, zval* value, sqlsrv_conn* conn, std::string& /*conn_str*/ TSRMLS_DC )
{
try {
core::SQLSetConnectAttr(conn, Attr, reinterpret_cast<SQLPOINTER>((zend_long)zend_is_true(value)),
SQL_IS_UINTEGER TSRMLS_CC);
core::SQLSetConnectAttr( conn, Attr, reinterpret_cast<SQLPOINTER>( zend_is_true( value )),
SQL_IS_UINTEGER TSRMLS_CC );
}
catch( core::CoreException& ) {
throw;
@ -202,27 +201,27 @@ const stmt_option SS_STMT_OPTS[] = {
SSStmtOptionNames::QUERY_TIMEOUT,
sizeof( SSStmtOptionNames::QUERY_TIMEOUT ),
SQLSRV_STMT_OPTION_QUERY_TIMEOUT,
new stmt_option_query_timeout
std::unique_ptr<stmt_option_query_timeout>( new stmt_option_query_timeout )
},
{
SSStmtOptionNames::SEND_STREAMS_AT_EXEC,
sizeof( SSStmtOptionNames::SEND_STREAMS_AT_EXEC ),
SQLSRV_STMT_OPTION_SEND_STREAMS_AT_EXEC,
new stmt_option_send_at_exec
std::unique_ptr<stmt_option_send_at_exec>( new stmt_option_send_at_exec )
},
{
SSStmtOptionNames::SCROLLABLE,
sizeof( SSStmtOptionNames::SCROLLABLE ),
SQLSRV_STMT_OPTION_SCROLLABLE,
new stmt_option_scrollable
std::unique_ptr<stmt_option_scrollable>( new stmt_option_scrollable )
},
{
SSStmtOptionNames::CLIENT_BUFFER_MAX_SIZE,
sizeof( SSStmtOptionNames::CLIENT_BUFFER_MAX_SIZE ),
SQLSRV_STMT_OPTION_CLIENT_BUFFER_MAX_SIZE,
new stmt_option_buffered_query_limit
std::unique_ptr<stmt_option_buffered_query_limit>( new stmt_option_buffered_query_limit )
},
{ NULL, 0, SQLSRV_STMT_OPTION_INVALID, NULL },
{ NULL, 0, SQLSRV_STMT_OPTION_INVALID, std::unique_ptr<stmt_option_functor>{} },
};
@ -464,8 +463,8 @@ PHP_FUNCTION ( sqlsrv_connect )
core::sqlsrv_zend_hash_init( *g_henv_cp, stmts, 5, NULL /* dtor */, 0 /* persistent */ TSRMLS_CC );
// register the connection with the PHP runtime
ss::zend_register_resource(conn_z, conn, ss_sqlsrv_conn::descriptor, ss_sqlsrv_conn::resource_name TSRMLS_CC);
ss::zend_register_resource(conn_z, conn, ss_sqlsrv_conn::descriptor, ss_sqlsrv_conn::resource_name TSRMLS_CC);
conn->stmts = stmts;
stmts.transferred();
@ -568,56 +567,49 @@ PHP_FUNCTION( sqlsrv_close )
reset_errors( TSRMLS_C );
try {
// dummy context to pass to the error handler
// dummy context to pass to the error handler
error_ctx = new (sqlsrv_malloc( sizeof( sqlsrv_context ))) sqlsrv_context( 0, ss_error_handler, NULL );
SET_FUNCTION_NAME( *error_ctx );
if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "r", &conn_r ) == FAILURE ) {
if( zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &conn_r) == FAILURE ) {
// Check if it was a zval
int zr = zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "z", &conn_r );
CHECK_CUSTOM_ERROR(( zr == FAILURE ), error_ctx, SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER, _FN_ ) {
throw ss::SSException();
}
// if sqlsrv_close was called on a non-existent connection than we just return success.
if( Z_TYPE_P( conn_r ) == IS_NULL ) {
RETURN_TRUE;
}
else {
THROW_CORE_ERROR( error_ctx, SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER, _FN_ );
else {
THROW_CORE_ERROR( error_ctx, SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER, _FN_ );
}
}
conn = static_cast<ss_sqlsrv_conn*>( zend_fetch_resource_ex( conn_r TSRMLS_CC, NULL, ss_sqlsrv_conn::descriptor ));
conn = static_cast<ss_sqlsrv_conn*>( zend_fetch_resource( Z_RES_P( conn_r ) TSRMLS_CC, ss_sqlsrv_conn::resource_name, ss_sqlsrv_conn::descriptor ));
CHECK_CUSTOM_ERROR(( conn == NULL ), error_ctx, SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER, _FN_ ) {
throw ss::SSException();
}
SET_FUNCTION_NAME( *conn );
// 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_list_close(Z_RES_P(conn_r));
if( zr == FAILURE ) {
if( zend_list_close( Z_RES_P( conn_r ) ) == FAILURE ) {
LOG( SEV_ERROR, "Failed to remove connection resource %1!d!", Z_RES_HANDLE_P( conn_r ));
}
ZVAL_NULL( conn_r );
RETURN_TRUE;
}
catch( core::CoreException& ) {
RETURN_FALSE;
}
catch( ... ) {
@ -910,7 +902,7 @@ PHP_FUNCTION( sqlsrv_prepare )
// store the resource id with the connection so the connection
// can release this statement when it closes.
int next_index = zend_hash_next_free_element( conn->stmts );
zend_long next_index = zend_hash_next_free_element( conn->stmts );
core::sqlsrv_zend_hash_index_update(*conn, conn->stmts, next_index, &stmt_z TSRMLS_CC);
@ -980,7 +972,7 @@ PHP_FUNCTION( sqlsrv_query )
sqlsrv_malloc_auto_ptr<ss_sqlsrv_stmt> stmt;
char* sql = NULL;
hash_auto_ptr ss_stmt_options_ht;
zend_long sql_len = 0;
int sql_len = 0;
zval* options_z = NULL;
zval* params_z = NULL;
zval stmt_z;
@ -1034,7 +1026,7 @@ PHP_FUNCTION( sqlsrv_query )
ss::zend_register_resource(stmt_z, stmt, ss_sqlsrv_stmt::descriptor, ss_sqlsrv_stmt::resource_name TSRMLS_CC);
// store the resource id with the connection so the connection
// can release this statement when it closes.
zend_ulong next_index = zend_hash_next_free_element( conn->stmts );
zend_long next_index = zend_hash_next_free_element( conn->stmts );
core::sqlsrv_zend_hash_index_update(*conn, conn->stmts, next_index, &stmt_z TSRMLS_CC);
stmt->conn_index = next_index;
@ -1166,7 +1158,7 @@ int get_conn_option_key( sqlsrv_context& ctx, zend_string* key, size_t key_len,
}
char* value = Z_STRVAL_P( value_z );
int value_len = Z_STRLEN_P( value_z );
size_t value_len = Z_STRLEN_P( value_z );
bool escaped = core_is_conn_opt_value_escaped( value, value_len );
CHECK_CUSTOM_ERROR( !escaped, ctx, SS_SQLSRV_ERROR_CONNECT_BRACES_NOT_ESCAPED, SS_CONN_OPTS[ i ].sqlsrv_name ) {

View file

@ -61,8 +61,8 @@ void build_connection_string_and_set_conn_attr( sqlsrv_conn* conn, const char* s
void determine_server_version( sqlsrv_conn* conn TSRMLS_DC );
const char* get_processor_arch( void );
void get_server_version( sqlsrv_conn* conn, char** server_version, SQLSMALLINT& len TSRMLS_DC );
connection_option const* get_connection_option( sqlsrv_conn* conn, const char* key, unsigned int key_len TSRMLS_DC );
void common_conn_str_append_func( const char* odbc_name, const char* val, int val_len, std::string& conn_str TSRMLS_DC );
connection_option const* get_connection_option( sqlsrv_conn* conn, const char* key, SQLULEN key_len TSRMLS_DC );
void common_conn_str_append_func( const char* odbc_name, const char* val, size_t val_len, std::string& conn_str TSRMLS_DC );
}
@ -130,8 +130,9 @@ sqlsrv_conn* core_sqlsrv_connect( sqlsrv_context& henv_cp, sqlsrv_context& henv_
// We only support UTF-8 encoding for connection string.
// Convert our UTF-8 connection string to UTF-16 before connecting with SQLDriverConnnectW
wconn_len = (conn_str.length() + 1) * sizeof( wchar_t );
wconn_string = utf16_string_from_mbcs_string( SQLSRV_ENCODING_UTF8, conn_str.c_str(), conn_str.length(), &wconn_len );
wconn_len = (unsigned int) (conn_str.length() + 1) * sizeof( wchar_t );
wconn_string = utf16_string_from_mbcs_string( SQLSRV_ENCODING_UTF8, conn_str.c_str(), (unsigned int) conn_str.length(), &wconn_len );
CHECK_CUSTOM_ERROR( wconn_string == NULL, conn, SQLSRV_ERROR_CONNECT_STRING_ENCODING_TRANSLATE, get_last_error_message() )
{
throw core::CoreException();
@ -318,7 +319,7 @@ void core_sqlsrv_close( sqlsrv_conn* conn TSRMLS_DC )
// sql - T-SQL command to prepare
// sql_len - length of the T-SQL string
void core_sqlsrv_prepare( sqlsrv_stmt* stmt, const char* sql, long sql_len TSRMLS_DC )
void core_sqlsrv_prepare( sqlsrv_stmt* stmt, const char* sql, SQLLEN sql_len TSRMLS_DC )
{
try {
@ -333,10 +334,17 @@ void core_sqlsrv_prepare( sqlsrv_stmt* stmt, const char* sql, long sql_len TSRML
wsql_len = 0;
}
else {
if (sql_len > INT_MAX)
{
LOG(SEV_ERROR, "Convert input parameter to utf16: buffer length exceeded.");
throw core::CoreException();
}
SQLSRV_ENCODING encoding = (( stmt->encoding() == SQLSRV_ENCODING_DEFAULT ) ? stmt->conn->encoding() :
stmt->encoding() );
wsql_string = utf16_string_from_mbcs_string( encoding, reinterpret_cast<const char*>( sql ),
sql_len, &wsql_len );
(int) sql_len, &wsql_len );
CHECK_CUSTOM_ERROR( wsql_string == NULL, stmt, SQLSRV_ERROR_QUERY_STRING_ENCODING_TRANSLATE,
get_last_error_message() ) {
throw core::CoreException();
@ -466,7 +474,7 @@ void core_sqlsrv_get_client_info( sqlsrv_conn* conn, __out zval *client_info TSR
// Properly escaped means that any '}' should be escaped by a prior '}'. It is assumed that
// the value will be surrounded by { and } by the caller after it has been validated
bool core_is_conn_opt_value_escaped( const char* value, int value_len )
bool core_is_conn_opt_value_escaped( const char* value, size_t value_len )
{
// if the value is already quoted, then only analyse the part inside the quotes and return it as
// unquoted since we quote it when adding it to the connection string.
@ -475,7 +483,7 @@ bool core_is_conn_opt_value_escaped( const char* value, int value_len )
value_len -= 2;
}
// check to make sure that all right braces are escaped
int i = 0;
size_t i = 0;
while( ( value[i] != '}' || ( value[i] == '}' && value[i+1] == '}' )) && i < value_len ) {
// skip both braces
if( value[i] == '}' )
@ -494,7 +502,7 @@ bool core_is_conn_opt_value_escaped( const char* value, int value_len )
namespace {
connection_option const* get_connection_option( sqlsrv_conn* conn, unsigned long key,
connection_option const* get_connection_option( sqlsrv_conn* conn, SQLULEN key,
const connection_option conn_opts[] TSRMLS_DC )
{
for( int opt_idx = 0; conn_opts[ opt_idx ].conn_option_key != SQLSRV_CONN_OPTION_INVALID; ++opt_idx ) {
@ -584,7 +592,7 @@ void build_connection_string_and_set_conn_attr( sqlsrv_conn* conn, const char* s
int type = HASH_KEY_NON_EXISTENT;
zend_string *key = NULL;
zend_ulong index = -1;
zend_ulong index = 0;
zval* data = NULL;
type = zend_hash_get_current_key( options, &key, &index );
@ -692,7 +700,7 @@ void determine_server_version( sqlsrv_conn* conn TSRMLS_DC )
conn->server_version = version_major;
}
void common_conn_str_append_func( const char* odbc_name, const char* val, int val_len, std::string& conn_str TSRMLS_DC )
void common_conn_str_append_func( const char* odbc_name, const char* val, size_t val_len, std::string& conn_str TSRMLS_DC )
{
// wrap a connection option in a quote. It is presumed that any character that need to be escaped will
// be escaped, such as a closing }.
@ -715,7 +723,7 @@ void conn_str_append_func::func( connection_option const* option, zval* value, s
TSRMLS_DC )
{
const char* val_str = Z_STRVAL_P( value );
int val_len = Z_STRLEN_P( value );
size_t val_len = Z_STRLEN_P( value );
common_conn_str_append_func( option->odbc_name, val_str, val_len, conn_str TSRMLS_CC );
}
@ -736,10 +744,10 @@ int core_str_zval_is_true( zval* value_z )
SQLSRV_ASSERT( Z_TYPE_P( value_z ) == IS_STRING, "core_str_zval_is_true: This function only accepts zval of type string." );
char* value_in = Z_STRVAL_P( value_z );
int val_len = Z_STRLEN_P( value_z );
size_t val_len = Z_STRLEN_P( value_z );
// strip any whitespace at the end (whitespace is the same value in ASCII and UTF-8)
int last_char = val_len - 1;
size_t last_char = val_len - 1;
while( isspace( value_in[ last_char ] )) {
value_in[ last_char ] = '\0';
val_len = last_char;

View file

@ -37,8 +37,8 @@ OSVERSIONINFO g_osversion;
// err - Driver specific error handler which handles any errors during initialization.
void core_sqlsrv_minit( sqlsrv_context** henv_cp, sqlsrv_context** henv_ncp, error_callback err, const char* driver_func TSRMLS_DC )
{
SQLSRV_STATIC_ASSERT( sizeof( sqlsrv_sqltype ) == sizeof( long ));
SQLSRV_STATIC_ASSERT( sizeof( sqlsrv_phptype ) == sizeof( long ));
SQLSRV_STATIC_ASSERT( sizeof( sqlsrv_sqltype ) == sizeof( zend_long ) );
SQLSRV_STATIC_ASSERT( sizeof( sqlsrv_phptype ) == sizeof( zend_long ));
*henv_cp = *henv_ncp = SQL_NULL_HANDLE; // initialize return values to NULL
@ -145,11 +145,13 @@ void core_sqlsrv_mshutdown( sqlsrv_context& henv_cp, sqlsrv_context& henv_ncp )
if( henv_ncp != SQL_NULL_HANDLE ) {
henv_ncp.invalidate();
delete &henv_ncp;
}
if( henv_cp != SQL_NULL_HANDLE ) {
henv_cp.invalidate();
delete &henv_cp;
}
return;

View file

@ -76,7 +76,7 @@ bool get_bit( void* ptr, unsigned int bit )
// read in LOB field during buffered result creation
SQLPOINTER read_lob_field( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_buffered_result_set::meta_data& meta,
unsigned long mem_used TSRMLS_DC );
zend_long mem_used TSRMLS_DC );
// dtor for each row in the cache
void cache_row_dtor(zval* data);
@ -170,13 +170,13 @@ sqlsrv_error* odbc_get_diag_rec( sqlsrv_stmt* odbc, SQLSMALLINT record_number )
// convert the error into the encoding of the context
sqlsrv_malloc_auto_ptr<SQLCHAR> sql_state;
SQLINTEGER sql_state_len = 0;
SQLLEN sql_state_len = 0;
if (!convert_string_from_utf16( enc, wsql_state, sizeof(wsql_state), (char**)&sql_state, sql_state_len )) {
return NULL;
}
sqlsrv_malloc_auto_ptr<SQLCHAR> native_message;
SQLINTEGER native_message_len = 0;
SQLLEN native_message_len = 0;
if (!convert_string_from_utf16( enc, wnative_message, wnative_message_len, (char**)&native_message, native_message_len )) {
return NULL;
}
@ -439,7 +439,7 @@ sqlsrv_buffered_result_set::sqlsrv_buffered_result_set( sqlsrv_stmt* stmt TSRMLS
// read the data into the cache
// (offset from the above loop has the size of the row buffer necessary)
unsigned long mem_used = 0;
zend_ulong mem_used = 0;
unsigned long row_count = 0;
while( core::SQLFetchScroll( stmt, SQL_FETCH_NEXT, 0 TSRMLS_CC ) != SQL_NO_DATA ) {
@ -476,7 +476,7 @@ sqlsrv_buffered_result_set::sqlsrv_buffered_result_set( sqlsrv_stmt* stmt TSRMLS
}
else {
mem_used += meta[i].length;
mem_used += meta[i].length;
CHECK_CUSTOM_ERROR( mem_used > stmt->buffered_query_limit * 1024, stmt,
SQLSRV_ERROR_BUFFER_LIMIT_EXCEEDED, stmt->buffered_query_limit ) {
@ -786,7 +786,7 @@ SQLRETURN sqlsrv_buffered_result_set::double_to_long( SQLSMALLINT field_index, _
__out SQLLEN* out_buffer_length )
{
SQLSRV_ASSERT( meta[ field_index ].c_type == SQL_C_DOUBLE, "Invalid conversion to long" );
SQLSRV_ASSERT( buffer_length >= sizeof(LONG), "Buffer length must be able to find a long in "
SQLSRV_ASSERT( buffer_length >= sizeof(SQLLEN), "Buffer length must be able to find a long in "
"sqlsrv_buffered_result_set::double_to_long" );
unsigned char* row = get_row();
@ -972,8 +972,13 @@ SQLRETURN sqlsrv_buffered_result_set::system_to_wide_string( SQLSMALLINT field_i
bool tried_again = false;
do {
int ch_space = MultiByteToWideChar( CP_ACP, MB_ERR_INVALID_CHARS, (LPCSTR) field_data, to_copy,
(LPWSTR) buffer, to_copy );
if (to_copy > INT_MAX ) {
LOG(SEV_ERROR, "MultiByteToWideChar: Buffer length exceeded.");
throw core::CoreException();
}
int ch_space = MultiByteToWideChar( CP_ACP, MB_ERR_INVALID_CHARS, (LPCSTR) field_data, static_cast<int>(to_copy),
static_cast<LPWSTR>(buffer), static_cast<int>(to_copy));
if( ch_space == 0 ) {
switch( GetLastError() ) {
@ -1089,7 +1094,7 @@ SQLRETURN sqlsrv_buffered_result_set::wide_to_system_string( SQLSMALLINT field_i
unsigned char* row = get_row();
SQLCHAR* field_data = NULL;
SQLULEN field_len = NULL;
SQLLEN field_len = NULL;
// if this is the first time called for this field, just convert the entire string to system first then
// use that to read from instead of converting chunk by chunk. This is because it's impossible to know
@ -1114,9 +1119,9 @@ SQLRETURN sqlsrv_buffered_result_set::wide_to_system_string( SQLSMALLINT field_i
char default_char = '?';
// allocate enough to handle WC -> DBCS conversion if it happens
temp_string = reinterpret_cast<SQLCHAR*>( sqlsrv_malloc( field_len, sizeof( char ), sizeof(char)));
temp_length = WideCharToMultiByte( CP_ACP, 0, (LPCWSTR) field_data, field_len / sizeof(WCHAR),
(LPSTR) temp_string.get(), field_len, &default_char, &default_char_used );
temp_string = reinterpret_cast<SQLCHAR*>( sqlsrv_malloc( field_len, sizeof(char), sizeof(char)));
temp_length = WideCharToMultiByte( CP_ACP, 0, (LPCWSTR) field_data, static_cast<int>(field_len / sizeof(WCHAR)),
(LPSTR) temp_string.get(), static_cast<int>(field_len), &default_char, &default_char_used );
if( temp_length == 0 ) {
@ -1224,10 +1229,10 @@ void cache_row_dtor( zval* data )
}
SQLPOINTER read_lob_field( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_buffered_result_set::meta_data& meta,
unsigned long mem_used TSRMLS_DC )
zend_long mem_used TSRMLS_DC )
{
SQLSMALLINT extra = 0;
SQLLEN* output_buffer_len = NULL;
SQLULEN* output_buffer_len = NULL;
// Set the amount of space necessary for null characters at the end of the data.
switch( meta.c_type ) {
@ -1245,8 +1250,8 @@ SQLPOINTER read_lob_field( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_b
break;
}
SQLLEN already_read = 0;
SQLLEN to_read = INITIAL_FIELD_STRING_LEN;
SQLULEN already_read = 0;
SQLULEN to_read = INITIAL_FIELD_STRING_LEN;
sqlsrv_malloc_auto_ptr<char> buffer;
buffer = static_cast<char*>( sqlsrv_malloc( INITIAL_FIELD_STRING_LEN + extra + sizeof( SQLULEN )));
SQLRETURN r = SQL_SUCCESS;
@ -1257,7 +1262,7 @@ SQLPOINTER read_lob_field( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_b
do {
output_buffer_len = reinterpret_cast<SQLLEN*>( buffer.get() );
output_buffer_len = reinterpret_cast<SQLULEN*>( buffer.get() );
r = core::SQLGetData( stmt, field_index + 1, meta.c_type, buffer.get() + already_read + sizeof( SQLULEN ),
to_read - already_read + extra, &last_field_len, false /*handle_warning*/ TSRMLS_CC );
@ -1301,7 +1306,7 @@ SQLPOINTER read_lob_field( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_b
already_read += to_read - already_read;
to_read = last_field_len;
buffer.resize( to_read + extra + sizeof( SQLULEN ));
output_buffer_len = reinterpret_cast<SQLLEN*>( buffer.get() );
output_buffer_len = reinterpret_cast<SQLULEN*>( buffer.get() );
// record the size of the field since we have it available
*output_buffer_len = last_field_len;
full_length_returned = true;
@ -1316,7 +1321,7 @@ SQLPOINTER read_lob_field( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_b
throw core::CoreException();
}
buffer.resize( to_read + extra + sizeof( SQLULEN ));
output_buffer_len = reinterpret_cast<SQLLEN*>( buffer.get() );
output_buffer_len = reinterpret_cast<SQLULEN*>( buffer.get() );
}
} while( true );

View file

@ -107,7 +107,7 @@ OACR_WARNING_POP
#include <limits>
#include <cassert>
#include <strsafe.h>
#include <memory>
// included for SQL Server specific constants
#include "msodbcsql.h"
@ -196,7 +196,7 @@ union sqlsrv_phptype {
unsigned encoding:16;
} typeinfo;
long value;
zend_long value;
};
// static assert for enforcing compile time conditions
@ -500,6 +500,16 @@ public:
return _ptr[ index ];
}
#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.
T& operator[](std::size_t index) const
{
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.
T& operator[]( unsigned short index ) const
@ -914,7 +924,7 @@ const int SQLSRV_OS_VISTA_OR_LATER = 6; // major version for Vista
struct sqlsrv_encoding {
const char* iana;
unsigned int iana_len;
size_t iana_len;
unsigned int code_page;
bool not_for_connection;
@ -1082,9 +1092,8 @@ struct str_conn_attr_func {
static void func( connection_option const* /*option*/, zval* value, sqlsrv_conn* conn, std::string& /*conn_str*/ TSRMLS_DC )
{
try {
core::SQLSetConnectAttr( conn, Attr, reinterpret_cast<SQLPOINTER>( Z_STRVAL_P( value )),
Z_STRLEN_P( value ) TSRMLS_CC );
static_cast<SQLINTEGER>(Z_STRLEN_P( value )) TSRMLS_CC );
}
catch( core::CoreException& ) {
throw;
@ -1113,14 +1122,14 @@ sqlsrv_conn* core_sqlsrv_connect( sqlsrv_context& henv_cp, sqlsrv_context& henv_
HashTable* options_ht, error_callback err, const connection_option driver_conn_opt_list[],
void* driver, const char* driver_func TSRMLS_DC );
void core_sqlsrv_close( sqlsrv_conn* conn TSRMLS_DC );
void core_sqlsrv_prepare( sqlsrv_stmt* stmt, const char* sql, long sql_len TSRMLS_DC );
void core_sqlsrv_prepare( sqlsrv_stmt* stmt, const char* sql, SQLLEN sql_len TSRMLS_DC );
void core_sqlsrv_begin_transaction( sqlsrv_conn* conn TSRMLS_DC );
void core_sqlsrv_commit( sqlsrv_conn* conn TSRMLS_DC );
void core_sqlsrv_rollback( sqlsrv_conn* conn TSRMLS_DC );
void core_sqlsrv_get_server_info( sqlsrv_conn* conn, __out zval* server_info TSRMLS_DC );
void core_sqlsrv_get_server_version( sqlsrv_conn* conn, __out zval *server_version TSRMLS_DC );
void core_sqlsrv_get_client_info( sqlsrv_conn* conn, __out zval *client_info TSRMLS_DC );
bool core_is_conn_opt_value_escaped( const char* value, int value_len );
bool core_is_conn_opt_value_escaped( const char* value, size_t value_len );
int core_str_zval_is_true( zval* str_zval );
//*********************************************************************************************************************************
@ -1153,7 +1162,7 @@ struct stmt_option {
const char * name; // name of the statement option
unsigned int name_len; // name length
unsigned int key;
stmt_option_functor* func; // callback that actually handles the work of the option
std::unique_ptr<stmt_option_functor> func; // callback that actually handles the work of the option
};
@ -1192,7 +1201,7 @@ struct sqlsrv_output_param {
zval* param_z;
SQLSRV_ENCODING encoding;
int param_num; // used to index into the ind_or_len of the statement
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
bool is_bool;
@ -1297,7 +1306,7 @@ typedef sqlsrv_stmt* (*driver_stmt_factory)( sqlsrv_conn* conn, SQLHANDLE h, err
// *** statement functions ***
sqlsrv_stmt* core_sqlsrv_create_stmt( sqlsrv_conn* conn, driver_stmt_factory stmt_factory, HashTable* options_ht,
const stmt_option valid_stmt_opts[], error_callback const err, void* driver TSRMLS_DC );
void core_sqlsrv_bind_param( sqlsrv_stmt* stmt, zend_ulong param_num, int direction, zval* param_z,
void core_sqlsrv_bind_param( sqlsrv_stmt* stmt, SQLUSMALLINT param_num, SQLSMALLINT direction, zval* param_z,
SQLSRV_PHPTYPE php_out_type, SQLSRV_ENCODING encoding, SQLSMALLINT sql_type, SQLULEN column_size,
SQLSMALLINT decimal_digits TSRMLS_DC );
void core_sqlsrv_execute( sqlsrv_stmt* stmt TSRMLS_DC, const char* sql = NULL, int sql_len = 0 );
@ -1315,7 +1324,7 @@ void core_sqlsrv_set_query_timeout( sqlsrv_stmt* stmt, zval* value_z TSRMLS_DC )
void core_sqlsrv_set_send_at_exec( sqlsrv_stmt* stmt, zval* value_z TSRMLS_DC );
bool core_sqlsrv_send_stream_packet( sqlsrv_stmt* stmt TSRMLS_DC );
void core_sqlsrv_set_buffered_query_limit( sqlsrv_stmt* stmt, zval* value_z TSRMLS_DC );
void core_sqlsrv_set_buffered_query_limit( sqlsrv_stmt* stmt, long limit TSRMLS_DC );
void core_sqlsrv_set_buffered_query_limit( sqlsrv_stmt* stmt, SQLLEN limit TSRMLS_DC );
//*********************************************************************************************************************************
@ -1495,8 +1504,8 @@ struct sqlsrv_buffered_result_set : public sqlsrv_result_set {
#define MEMCHECK_SILENT 1
// utility functions shared by multiple callers across files
bool convert_string_from_utf16_inplace( SQLSRV_ENCODING encoding, char** string, SQLINTEGER& len);
bool convert_string_from_utf16( SQLSRV_ENCODING encoding, const wchar_t* inString, SQLINTEGER cchInLen, char** outString, SQLINTEGER& cchOutLen );
bool convert_string_from_utf16_inplace( SQLSRV_ENCODING encoding, char** string, SQLLEN& len);
bool convert_string_from_utf16( SQLSRV_ENCODING encoding, const wchar_t* inString, SQLINTEGER cchInLen, char** outString, SQLLEN& cchOutLen );
wchar_t* utf16_string_from_mbcs_string( SQLSRV_ENCODING php_encoding, const char* mbcs_string,
unsigned int mbcs_len, __out unsigned int* utf16_len );
@ -1594,7 +1603,7 @@ DWORD core_sqlsrv_format_message( char* output_buffer, unsigned output_len, cons
// convenience functions that overload either a reference or a pointer so we can use
// either in the CHECK_* functions.
inline bool call_error_handler( sqlsrv_context& ctx, unsigned int sqlsrv_error_code TSRMLS_DC, bool warning, ... )
inline bool call_error_handler( sqlsrv_context& ctx, unsigned long sqlsrv_error_code TSRMLS_DC, bool warning, ... )
{
va_list print_params;
va_start( print_params, warning );
@ -1603,7 +1612,7 @@ inline bool call_error_handler( sqlsrv_context& ctx, unsigned int sqlsrv_error_c
return ignored;
}
inline bool call_error_handler( sqlsrv_context* ctx, unsigned int sqlsrv_error_code TSRMLS_DC, bool warning, ... )
inline bool call_error_handler( sqlsrv_context* ctx, unsigned long sqlsrv_error_code TSRMLS_DC, bool warning, ... )
{
va_list print_params;
va_start( print_params, warning );
@ -2191,7 +2200,7 @@ namespace core {
}
}
inline void sqlsrv_zend_hash_init(sqlsrv_context& ctx, HashTable* ht, std::size_t initial_size,
inline void sqlsrv_zend_hash_init(sqlsrv_context& ctx, HashTable* ht, uint32_t initial_size,
dtor_func_t dtor_fn, zend_bool persistent TSRMLS_DC )
{
::zend_hash_init(ht, initial_size, NULL, dtor_fn, persistent);

View file

@ -83,11 +83,11 @@ bool convert_input_param_to_utf16( zval* input_param_z, zval* convert_param_z );
void core_get_field_common(__inout sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_phptype
sqlsrv_php_type, __out void** field_value, __out SQLLEN* field_len TSRMLS_DC );
// returns the ODBC C type constant that matches the PHP type and encoding given
SQLSMALLINT default_c_type( sqlsrv_stmt* stmt, unsigned int paramno, zval const* param_z, SQLSRV_ENCODING encoding TSRMLS_DC );
SQLSMALLINT default_c_type( sqlsrv_stmt* stmt, SQLULEN paramno, zval const* param_z, SQLSRV_ENCODING encoding TSRMLS_DC );
void default_sql_size_and_scale( sqlsrv_stmt* stmt, unsigned int paramno, zval* param_z, SQLSRV_ENCODING encoding,
__out SQLULEN& column_size, __out SQLSMALLINT& decimal_digits TSRMLS_DC );
// given a zval and encoding, determine the appropriate sql type, column size, and decimal scale (if appropriate)
void default_sql_type( sqlsrv_stmt* stmt, unsigned int paramno, zval* param_z, SQLSRV_ENCODING encoding,
void default_sql_type( sqlsrv_stmt* stmt, SQLULEN paramno, zval* param_z, SQLSRV_ENCODING encoding,
__out SQLSMALLINT& sql_type TSRMLS_DC );
void field_cache_dtor( zval* data_z );
void finalize_output_parameters( sqlsrv_stmt* stmt TSRMLS_DC );
@ -96,7 +96,7 @@ void get_field_as_string( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_ph
stmt_option const* get_stmt_option( sqlsrv_conn const* conn, zend_ulong key, const stmt_option stmt_opts[] TSRMLS_DC );
bool is_valid_sqlsrv_phptype( sqlsrv_phptype type );
// assure there is enough space for the output parameter string
void resize_output_buffer_if_necessary( sqlsrv_stmt* stmt, zval* param_z, unsigned int paramno, SQLSRV_ENCODING encoding,
void resize_output_buffer_if_necessary( sqlsrv_stmt* stmt, zval* param_z, SQLULEN paramno, SQLSRV_ENCODING encoding,
SQLSMALLINT c_type, SQLSMALLINT sql_type, SQLULEN column_size, SQLPOINTER& buffer,
SQLLEN& buffer_len TSRMLS_DC );
void save_output_param_for_later( sqlsrv_stmt* stmt, sqlsrv_output_param& param TSRMLS_DC );
@ -164,7 +164,7 @@ sqlsrv_stmt::~sqlsrv_stmt( void )
current_results = NULL;
}
invalidate();
invalidate();
zval_ptr_dtor( &param_input_strings );
zval_ptr_dtor( &output_params );
zval_ptr_dtor( &param_streams );
@ -316,9 +316,9 @@ sqlsrv_stmt* core_sqlsrv_create_stmt( sqlsrv_conn* conn, driver_stmt_factory stm
// Return:
// Nothing, though an exception is thrown if an error occurs
// The php type of the parameter is taken from the zval.
// The sql type is given as a hint if the driver provides it.
// The sql type is given as a hint if the driver provides it.
void core_sqlsrv_bind_param(sqlsrv_stmt* stmt, zend_ulong param_num, int direction, zval* param_z,
void core_sqlsrv_bind_param(sqlsrv_stmt* stmt, SQLUSMALLINT param_num, SQLSMALLINT direction, zval* param_z,
SQLSRV_PHPTYPE php_out_type, SQLSRV_ENCODING encoding, SQLSMALLINT sql_type, SQLULEN column_size,
SQLSMALLINT decimal_digits TSRMLS_DC )
{
@ -339,13 +339,17 @@ void core_sqlsrv_bind_param(sqlsrv_stmt* stmt, zend_ulong param_num, int directi
}
// resize the statements array of int_ptrs if the parameter isn't already set.
if( stmt->param_ind_ptrs.size() < param_num + 1 ) {
if( stmt->param_ind_ptrs.size() < static_cast<size_t>(param_num + 1) ) {
stmt->param_ind_ptrs.resize( param_num + 1, SQL_NULL_DATA );
}
SQLLEN& ind_ptr = stmt->param_ind_ptrs[ param_num ];
zval* param_ref = param_z;
if ( Z_ISREF_P( param_z ) ) {
ZVAL_DEREF( param_z );
}
bool zval_was_null = (Z_TYPE_P( param_z ) == IS_NULL);
bool zval_was_bool = (Z_TYPE_P(param_z) == IS_TRUE || Z_TYPE_P(param_z) == IS_FALSE);
bool zval_was_bool = (Z_TYPE_P( param_z ) == IS_TRUE || Z_TYPE_P( param_z ) == IS_FALSE);
// if the user asks for for a specific type for input and output, make sure the data type we send matches the data we
// type we expect back, since we can only send and receive the same type. Anything can be converted to a string, so
// we always let that match if they want a string back.
@ -413,12 +417,12 @@ void core_sqlsrv_bind_param(sqlsrv_stmt* stmt, zend_ulong param_num, int directi
// if the sql type is unknown, then set the default based on the PHP type passed in
if( sql_type == SQL_UNKNOWN_TYPE ) {
default_sql_type( stmt, param_num, param_z, encoding, sql_type TSRMLS_CC );
default_sql_type(stmt, param_num, param_z, encoding, sql_type TSRMLS_CC);
}
// if the size is unknown, then set the default based on the PHP type passed in
if( column_size == SQLSRV_UNKNOWN_SIZE ) {
default_sql_size_and_scale( stmt, param_num, param_z, encoding, column_size, decimal_digits TSRMLS_CC );
default_sql_size_and_scale( stmt, (unsigned int)param_num, param_z, encoding, column_size, decimal_digits TSRMLS_CC );
}
// determine the ODBC C type
@ -444,7 +448,7 @@ void core_sqlsrv_bind_param(sqlsrv_stmt* stmt, zend_ulong param_num, int directi
ind_ptr = buffer_len;
if( direction != SQL_PARAM_INPUT ) {
// save the parameter so that 1) the buffer doesn't go away, and 2) we can set it to NULL if returned
sqlsrv_output_param output_param( param_z, param_num, zval_was_bool );
sqlsrv_output_param output_param( param_ref, int(param_num), zval_was_bool );
save_output_param_for_later( stmt, output_param TSRMLS_CC );
}
}
@ -456,7 +460,7 @@ void core_sqlsrv_bind_param(sqlsrv_stmt* stmt, zend_ulong param_num, int directi
ind_ptr = buffer_len;
if( direction != SQL_PARAM_INPUT ) {
// save the parameter so that 1) the buffer doesn't go away, and 2) we can set it to NULL if returned
sqlsrv_output_param output_param(param_z, param_num, false );
sqlsrv_output_param output_param(param_ref, int(param_num), false );
save_output_param_for_later( stmt, output_param TSRMLS_CC );
}
}
@ -515,7 +519,8 @@ void core_sqlsrv_bind_param(sqlsrv_stmt* stmt, zend_ulong param_num, int directi
buffer, buffer_len TSRMLS_CC );
// save the parameter to be adjusted and/or converted after the results are processed
sqlsrv_output_param output_param( param_z, encoding, param_num, buffer_len );
sqlsrv_output_param output_param( param_ref, encoding, param_num, (SQLUINTEGER)buffer_len );
save_output_param_for_later( stmt, output_param TSRMLS_CC );
// For output parameters, if we set the column_size to be same as the buffer_len,
@ -626,8 +631,8 @@ void core_sqlsrv_bind_param(sqlsrv_stmt* stmt, zend_ulong param_num, int directi
ind_ptr = SQL_NULL_DATA;
}
core::SQLBindParameter( stmt, param_num + 1, direction, c_type, sql_type, column_size, decimal_digits, buffer, buffer_len,
&ind_ptr TSRMLS_CC );
core::SQLBindParameter( stmt, param_num + 1, direction,
c_type, sql_type, column_size, decimal_digits, buffer, buffer_len, &ind_ptr TSRMLS_CC );
}
catch( core::CoreException& e ) {
@ -926,7 +931,7 @@ void core_sqlsrv_get_field( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_
core::SQLColAttribute( stmt, field_index + 1, SQL_DESC_LENGTH, NULL, 0, NULL, &sql_field_len TSRMLS_CC );
// Get the corresponding php type from the sql type.
sqlsrv_php_type = stmt->sql_type_to_php_type( sql_field_type, sql_field_len, prefer_string );
sqlsrv_php_type = stmt->sql_type_to_php_type( (SQLINTEGER)sql_field_type, (SQLUINTEGER)sql_field_len, prefer_string );
}
// Verify that we have an acceptable type to convert.
@ -940,10 +945,12 @@ void core_sqlsrv_get_field( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_
// Retrieve the data
core_get_field_common( stmt, field_index, sqlsrv_php_type, field_value, field_len TSRMLS_CC );
// if the user wants us to cache the field, we'll do it
if( cache_field ) {
field_cache cache( *field_value, *field_len, sqlsrv_php_type );
core::sqlsrv_zend_hash_index_update_ptr( *stmt, Z_ARRVAL( stmt->field_cache ), field_index, &cache TSRMLS_CC );
core::sqlsrv_zend_hash_index_update_mem( *stmt, Z_ARRVAL( stmt->field_cache ), field_index, &cache, sizeof(field_cache) TSRMLS_CC );
}
}
@ -1105,14 +1112,14 @@ void core_sqlsrv_set_buffered_query_limit( sqlsrv_stmt* stmt, zval* value_z TSRM
core_sqlsrv_set_buffered_query_limit( stmt, Z_LVAL_P( value_z ) TSRMLS_CC );
}
void core_sqlsrv_set_buffered_query_limit( sqlsrv_stmt* stmt, long limit TSRMLS_DC )
void core_sqlsrv_set_buffered_query_limit( sqlsrv_stmt* stmt, SQLLEN limit TSRMLS_DC )
{
if( limit <= 0 ) {
THROW_CORE_ERROR( stmt, SQLSRV_ERROR_INVALID_BUFFER_LIMIT );
}
stmt->buffered_query_limit = limit;
stmt->buffered_query_limit = (unsigned long)limit;
}
@ -1130,7 +1137,7 @@ void core_sqlsrv_set_query_timeout( sqlsrv_stmt* stmt, zval* value_z TSRMLS_DC )
THROW_CORE_ERROR( stmt, SQLSRV_ERROR_INVALID_QUERY_TIMEOUT_VALUE, Z_STRVAL_P( value_z ) );
}
core_sqlsrv_set_query_timeout( stmt, Z_LVAL_P( value_z ) TSRMLS_CC );
core_sqlsrv_set_query_timeout( stmt, (long)Z_LVAL_P( value_z ) TSRMLS_CC );
}
catch( core::CoreException& ) {
throw;
@ -1145,7 +1152,7 @@ void core_sqlsrv_set_query_timeout( sqlsrv_stmt* stmt, long timeout TSRMLS_DC )
DEBUG_SQLSRV_ASSERT( timeout >= 0 , "core_sqlsrv_set_query_timeout: The value of query timeout cannot be less than 0." );
// set the statement attribute
core::SQLSetStmtAttr( stmt, SQL_ATTR_QUERY_TIMEOUT, reinterpret_cast<SQLPOINTER>( timeout ), SQL_IS_UINTEGER TSRMLS_CC );
core::SQLSetStmtAttr( stmt, SQL_ATTR_QUERY_TIMEOUT, reinterpret_cast<SQLPOINTER>( (SQLLEN)timeout ), SQL_IS_UINTEGER TSRMLS_CC );
// a query timeout of 0 indicates "no timeout", which means that lock_timeout should also be set to "no timeout" which
// is represented by -1.
@ -1224,9 +1231,16 @@ bool core_sqlsrv_send_stream_packet( sqlsrv_stmt* stmt TSRMLS_DC )
// read the data from the stream, send it via SQLPutData and track how much we've sent.
else {
char buffer[ PHP_STREAM_BUFFER_SIZE + 1 ];
size_t buffer_size = sizeof( buffer ) - 3; // -3 to preserve enough space for a cut off UTF-8 character
size_t read = php_stream_read( param_stream, buffer, buffer_size );
stmt->current_stream_read += read;
std::size_t buffer_size = sizeof( buffer ) - 3; // -3 to preserve enough space for a cut off UTF-8 character
std::size_t read = php_stream_read( param_stream, buffer, buffer_size );
if (read > UINT_MAX)
{
LOG(SEV_ERROR, "PHP stream: buffer length exceeded.");
throw core::CoreException();
}
stmt->current_stream_read += (unsigned int)read;
if( read > 0 ) {
// if this is a UTF-8 stream, then we will use the UTF-8 encoding to determine if we're in the middle of a character
// then read in the appropriate number more bytes and then retest the string. This way we try at most to convert it
@ -1240,7 +1254,7 @@ bool core_sqlsrv_send_stream_packet( sqlsrv_stmt* stmt TSRMLS_DC )
wchar_t wbuffer[ PHP_STREAM_BUFFER_SIZE + 1 ];
// buffer_size is the # of wchars. Since it set to stmt->param_buffer_size / 2, this is accurate
int wsize = MultiByteToWideChar( stmt->current_stream.encoding, MB_ERR_INVALID_CHARS,
buffer, read, wbuffer, sizeof( wbuffer ) / sizeof( wchar_t ));
buffer, int(read), wbuffer, int(sizeof( wbuffer ) / sizeof( wchar_t )));
if( wsize == 0 && GetLastError() == ERROR_NO_UNICODE_TRANSLATION ) {
// this will calculate how many bytes were cut off from the last UTF-8 character and read that many more
@ -1256,7 +1270,7 @@ bool core_sqlsrv_send_stream_packet( sqlsrv_stmt* stmt TSRMLS_DC )
}
// try the conversion again with the complete character
wsize = MultiByteToWideChar( stmt->current_stream.encoding, MB_ERR_INVALID_CHARS,
buffer, read + new_read, wbuffer, sizeof( wbuffer ) / sizeof( wchar_t ));
buffer, int(read + new_read), wbuffer, int(sizeof( wbuffer ) / sizeof( wchar_t )));
// something else must be wrong if it failed
CHECK_CUSTOM_ERROR( wsize == 0, stmt, SQLSRV_ERROR_INPUT_STREAM_ENCODING_TRANSLATE,
get_last_error_message( ERROR_NO_UNICODE_TRANSLATION )) {
@ -1335,7 +1349,7 @@ void close_active_stream( __inout sqlsrv_stmt* stmt TSRMLS_DC )
namespace {
bool is_streamable_type( SQLINTEGER sql_type )
bool is_streamable_type( SQLLEN sql_type )
{
switch( sql_type ) {
case SQL_CHAR:
@ -1478,6 +1492,7 @@ void core_get_field_common( __inout sqlsrv_stmt* stmt, SQLUSMALLINT field_index,
SQLRETURN r = stmt->current_results->get_data(field_index + 1, SQL_C_LONG, field_value_temp, sizeof( long ),
field_len, true /*handle_warning*/ TSRMLS_CC );
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
throw core::CoreException();
}
@ -1493,6 +1508,7 @@ void core_get_field_common( __inout sqlsrv_stmt* stmt, SQLUSMALLINT field_index,
*field_value = field_value_temp;
field_value_temp.transferred();
break;
}
@ -1519,6 +1535,7 @@ void core_get_field_common( __inout sqlsrv_stmt* stmt, SQLUSMALLINT field_index,
*field_value = field_value_temp;
field_value_temp.transferred();
break;
}
@ -1580,7 +1597,7 @@ void core_get_field_common( __inout sqlsrv_stmt* stmt, SQLUSMALLINT field_index,
return_value_z = (zval *)sqlsrv_malloc(sizeof(zval*));
php_stream* stream = NULL;
sqlsrv_stream* ss = NULL;
SQLINTEGER sql_type;
SQLLEN sql_type;
SQLRETURN r = SQLColAttribute( stmt->handle(), field_index + 1, SQL_DESC_TYPE, NULL, 0, NULL, &sql_type );
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
@ -1679,7 +1696,13 @@ bool convert_input_param_to_utf16( zval* input_param_z, zval* converted_param_z
const char* buffer = Z_STRVAL_P( input_param_z );
std::size_t buffer_len = Z_STRLEN_P( input_param_z );
std::size_t wchar_size;
int wchar_size;
if (buffer_len > INT_MAX)
{
LOG(SEV_ERROR, "Convert input parameter to utf16: buffer length exceeded.");
throw core::CoreException();
}
// if the string is empty, then just return that the conversion succeeded as
// MultiByteToWideChar will "fail" on an empty string.
@ -1689,7 +1712,9 @@ bool convert_input_param_to_utf16( zval* input_param_z, zval* converted_param_z
}
// if the parameter is an input parameter, calc the size of the necessary buffer from the length of the string
wchar_size = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, reinterpret_cast<LPCSTR>( buffer ), buffer_len, NULL, 0 );
wchar_size = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS,
reinterpret_cast<LPCSTR>( buffer ), (int) buffer_len, NULL, 0 );
// if there was a problem determining the size of the string, return false
if( wchar_size == 0 ) {
return false;
@ -1698,14 +1723,14 @@ bool convert_input_param_to_utf16( zval* input_param_z, zval* converted_param_z
wbuffer = reinterpret_cast<wchar_t*>( sqlsrv_malloc( (wchar_size + 1) * sizeof( wchar_t ) ));
// convert the utf-8 string to a wchar string in the new buffer
int r = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, reinterpret_cast<LPCSTR>( buffer ),
buffer_len, wbuffer, wchar_size );
(int) buffer_len, wbuffer, wchar_size );
// if there was a problem converting the string, then free the memory and return false
if( r == 0 ) {
return false;
}
// null terminate the string, set the size within the zval, and return success
wbuffer[ wchar_size ] = L'\0';
wbuffer[wchar_size] = L'\0';
ZVAL_STRINGL( converted_param_z, reinterpret_cast<char*>( wbuffer.get() ),
wchar_size * sizeof( wchar_t ) );
sqlsrv_free(wbuffer);
@ -1716,7 +1741,7 @@ bool convert_input_param_to_utf16( zval* input_param_z, zval* converted_param_z
// returns the ODBC C type constant that matches the PHP type and encoding given
SQLSMALLINT default_c_type( sqlsrv_stmt* stmt, unsigned int paramno, zval const* param_z, SQLSRV_ENCODING encoding TSRMLS_DC )
SQLSMALLINT default_c_type( sqlsrv_stmt* stmt, SQLULEN paramno, zval const* param_z, SQLSRV_ENCODING encoding TSRMLS_DC )
{
SQLSMALLINT sql_c_type = SQL_UNKNOWN_TYPE;
int php_type = Z_TYPE_P( param_z );
@ -1779,7 +1804,7 @@ SQLSMALLINT default_c_type( sqlsrv_stmt* stmt, unsigned int paramno, zval const*
// given a zval and encoding, determine the appropriate sql type
void default_sql_type( sqlsrv_stmt* stmt, unsigned int paramno, zval* param_z, SQLSRV_ENCODING encoding,
void default_sql_type( sqlsrv_stmt* stmt, SQLULEN paramno, zval* param_z, SQLSRV_ENCODING encoding,
__out SQLSMALLINT& sql_type TSRMLS_DC )
{
sql_type = SQL_UNKNOWN_TYPE;
@ -1927,16 +1952,17 @@ void finalize_output_parameters( sqlsrv_stmt* stmt TSRMLS_DC )
for( zend_hash_internal_pointer_reset( params_ht );
zend_hash_has_more_elements( params_ht ) == SUCCESS;
zend_hash_move_forward( params_ht ) ) {
sqlsrv_output_param* output_param;
sqlsrv_output_param* output_param = NULL;
core::sqlsrv_zend_hash_get_current_data_ptr(*stmt, params_ht, (void*&) output_param TSRMLS_CC);
switch( Z_TYPE_P( output_param->param_z )) {
zval* value_z = Z_REFVAL_P( output_param->param_z );
switch( Z_TYPE_P( value_z )) {
case IS_STRING:
{
// adjust the length of the string to the value returned by SQLBindParameter in the ind_ptr parameter
char* str = Z_STRVAL_P( output_param->param_z );
char* str = Z_STRVAL_P( value_z );
SQLLEN str_len = stmt->param_ind_ptrs[ output_param->param_num ];
if( str_len == SQL_NULL_DATA ) {
ZVAL_NULL( output_param->param_z );
ZVAL_NULL( value_z );
continue;
}
@ -1964,7 +1990,7 @@ void finalize_output_parameters( sqlsrv_stmt* stmt TSRMLS_DC )
// if it's not in the 8 bit encodings, then it's in UTF-16
if( output_param->encoding != SQLSRV_ENCODING_CHAR && output_param->encoding != SQLSRV_ENCODING_BINARY ) {
bool converted = convert_string_from_utf16_inplace( output_param->encoding, &str, str_len );
bool converted = convert_string_from_utf16_inplace(output_param->encoding, &str, str_len);
CHECK_CUSTOM_ERROR( !converted, stmt, SQLSRV_ERROR_OUTPUT_PARAM_ENCODING_TRANSLATE, get_last_error_message()) {
throw core::CoreException();
}
@ -1976,34 +2002,38 @@ void finalize_output_parameters( sqlsrv_stmt* stmt TSRMLS_DC )
str[ str_len ] = '\0';
}
// set the string length
ZVAL_STRINGL( output_param->param_z, str, str_len);
ZVAL_STRINGL( value_z, str, str_len);
sqlsrv_free(str);
}
break;
case IS_LONG:
// for a long or a float, simply check if NULL was returned and set the parameter to a PHP null if so
if( stmt->param_ind_ptrs[ output_param->param_num ] == SQL_NULL_DATA ) {
ZVAL_NULL( output_param->param_z );
ZVAL_NULL( value_z );
}
else if( output_param->is_bool ) {
convert_to_boolean( output_param->param_z );
convert_to_boolean( value_z );
}
else
{
ZVAL_LONG(value_z, static_cast<int>(Z_LVAL_P(value_z)));
}
break;
case IS_DOUBLE:
// for a long or a float, simply check if NULL was returned and set the parameter to a PHP null if so
if( stmt->param_ind_ptrs[ output_param->param_num ] == SQL_NULL_DATA ) {
ZVAL_NULL( output_param->param_z );
ZVAL_NULL( value_z );
}
break;
default:
DIE( "Illegal or unknown output parameter type. This should have been caught in core_sqlsrv_bind_parameter." );
break;
}
value_z = NULL;
}
// empty the hash table since it's been processed
zend_hash_clean( Z_ARRVAL( stmt->output_params ));
return;
}
@ -2079,7 +2109,7 @@ void get_field_as_string( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_ph
if( is_truncated_warning( state ) ) {
SQLINTEGER dummy_field_len;
SQLLEN dummy_field_len;
// for XML (and possibly other conditions) the field length returned is not the real field length, so
// in every pass, we double the allocation size to retrieve all the contents.
@ -2089,8 +2119,7 @@ void get_field_as_string( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_ph
field_len_temp = INITIAL_FIELD_STRING_LEN;
do {
SQLINTEGER initial_field_len = field_len_temp;
SQLLEN initial_field_len = field_len_temp;
// Double the size.
field_len_temp *= 2;
@ -2309,7 +2338,7 @@ bool is_valid_sqlsrv_phptype( sqlsrv_phptype type )
// string is place in the stmt->output_params. param_z is modified to hold the new buffer, and buffer, buffer_len and
// stmt->param_ind_ptrs are modified to hold the correct values for SQLBindParameter
void resize_output_buffer_if_necessary( sqlsrv_stmt* stmt, zval* param_z, unsigned int paramno, SQLSRV_ENCODING encoding,
void resize_output_buffer_if_necessary( sqlsrv_stmt* stmt, zval* param_z, SQLULEN paramno, SQLSRV_ENCODING encoding,
SQLSMALLINT c_type, SQLSMALLINT sql_type, SQLULEN column_size, SQLPOINTER& buffer,
SQLLEN& buffer_len TSRMLS_DC )
{
@ -2397,6 +2426,8 @@ void sqlsrv_output_param_dtor( zval* data )
{
sqlsrv_output_param *output_param = reinterpret_cast<sqlsrv_output_param*>( Z_PTR_P(data) );
zval_ptr_dtor( output_param->param_z ); // undo the reference to the string we will no longer hold
efree( output_param );
output_param = NULL;
}
// called by Zend for each stream in the sqlsrv_stmt::param_streams hash table when it is cleaned/destroyed

View file

@ -50,8 +50,7 @@ int sqlsrv_stream_close( php_stream* stream, int /*close_handle*/ TSRMLS_DC )
size_t sqlsrv_stream_read( php_stream* stream, __out_bcount(count) char* buf, size_t count TSRMLS_DC )
{
SQLINTEGER read = 0;
SQLLEN read = 0;
SQLSMALLINT c_type = SQL_C_CHAR;
char* get_data_buffer = buf;
sqlsrv_malloc_auto_ptr<char> temp_buf;
@ -145,21 +144,28 @@ size_t sqlsrv_stream_read( php_stream* stream, __out_bcount(count) char* buf, si
}
// if the encoding is UTF-8
if( c_type == SQL_C_WCHAR ) {
count *= 2; // undo the shift to use the full buffer
if (c_type == SQL_C_WCHAR) {
// 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;
count *= 2; // undo the shift to use the full 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;
// convert to UTF-8
if (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;
}
if ( count > INT_MAX || (read >> 1) > INT_MAX )
{
LOG(SEV_ERROR, "UTF-16 (wide character) string mapping: buffer length exceeded.");
throw core::CoreException();
}
// convert to UTF-8
if( 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 enc_len = WideCharToMultiByte( ss->encoding, flags, reinterpret_cast<LPCWSTR>( temp_buf.get() ),
read >> 1, buf, count, NULL, NULL );
int(read >> 1), buf, int(count), NULL, NULL );
if( enc_len == 0 ) {

View file

@ -70,7 +70,7 @@ void core_sqlsrv_register_logger( log_callback driver_logger )
// 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_inplace( SQLSRV_ENCODING encoding, char** string, SQLINTEGER& len)
bool convert_string_from_utf16_inplace( SQLSRV_ENCODING encoding, char** string, SQLLEN& len)
{
SQLSRV_ASSERT( string != NULL && *string != NULL, "String must be specified" );
@ -80,8 +80,16 @@ bool convert_string_from_utf16_inplace( SQLSRV_ENCODING encoding, char** string,
}
char* outString = NULL;
SQLINTEGER outLen = 0;
bool result = convert_string_from_utf16( encoding, reinterpret_cast<const wchar_t*>(*string), len / sizeof(wchar_t), &outString, outLen);
SQLLEN outLen = 0;
if( (len/sizeof(wchar_t)) > INT_MAX )
{
LOG(SEV_ERROR, "UTF-16 (wide character) string mapping: buffer length exceeded.");
throw core::CoreException();
}
bool result = convert_string_from_utf16( encoding,
reinterpret_cast<const wchar_t*>(*string), int(len / sizeof(wchar_t)), &outString, outLen);
if (result)
{
@ -93,7 +101,7 @@ bool convert_string_from_utf16_inplace( SQLSRV_ENCODING encoding, char** string,
return result;
}
bool convert_string_from_utf16( SQLSRV_ENCODING encoding, const wchar_t* inString, SQLINTEGER cchInLen, char** outString, SQLINTEGER& cchOutLen )
bool convert_string_from_utf16( SQLSRV_ENCODING encoding, const wchar_t* inString, SQLINTEGER cchInLen, char** outString, SQLLEN& cchOutLen )
{
SQLSRV_ASSERT( inString != NULL, "Input string must be specified" );
SQLSRV_ASSERT( outString != NULL, "Output buffer pointer must be specified" );
@ -126,7 +134,7 @@ bool convert_string_from_utf16( SQLSRV_ENCODING encoding, const wchar_t* inStrin
char* newString = reinterpret_cast<char*>( sqlsrv_malloc( cchOutLen + 1 /* NULL char*/ ));
int rc = WideCharToMultiByte( encoding, flags,
inString, cchInLen,
newString, cchOutLen, NULL, NULL );
newString, static_cast<int>(cchOutLen), NULL, NULL );
if( rc == 0 ) {
cchOutLen = 0;
sqlsrv_free( newString );
@ -219,10 +227,10 @@ bool core_sqlsrv_get_odbc_error( sqlsrv_context& ctx, int record_number, sqlsrv_
return false;
}
SQLINTEGER sqlstate_len = 0;
SQLLEN sqlstate_len = 0;
convert_string_from_utf16(enc, wsqlstate, sizeof(wsqlstate), (char**)&error->sqlstate, sqlstate_len);
SQLINTEGER message_len = 0;
SQLLEN message_len = 0;
convert_string_from_utf16(enc, wnative_message, wmessage_len, (char**)&error->native_message, message_len);
break;
}

View file

@ -36,6 +36,10 @@ HashTable* g_ss_warnings_to_ignore_ht = NULL;
// encodings we understand
HashTable* g_ss_encodings_ht = NULL;
// Destructors called by Zend for each element in the hashtable
void sqlsrv_error_const_dtor( zval* element );
void sqlsrv_encoding_dtor( zval* element );
// henv context for creating connections
sqlsrv_context* g_henv_cp;
sqlsrv_context* g_henv_ncp;
@ -260,9 +264,9 @@ zend_module_entry g_sqlsrv_module_entry =
PHP_MINIT_FUNCTION(sqlsrv)
{
SQLSRV_UNUSED( type );
core_sqlsrv_register_logger( ss_sqlsrv_log );
core_sqlsrv_register_logger( ss_sqlsrv_log );
// our global variables are initialized in the RINIT function
#if defined(ZTS)
if( ts_allocate_id( &sqlsrv_globals_id,
@ -273,8 +277,8 @@ PHP_MINIT_FUNCTION(sqlsrv)
ZEND_TSRMLS_CACHE_UPDATE();
#endif
SQLSRV_STATIC_ASSERT( sizeof( sqlsrv_sqltype ) == sizeof( long ));
SQLSRV_STATIC_ASSERT( sizeof( sqlsrv_phptype ) == sizeof( long ));
SQLSRV_STATIC_ASSERT( sizeof( sqlsrv_sqltype ) == sizeof( zend_long ));
SQLSRV_STATIC_ASSERT( sizeof( sqlsrv_phptype ) == sizeof( zend_long ));
REGISTER_INI_ENTRIES();
@ -408,7 +412,7 @@ PHP_MINIT_FUNCTION(sqlsrv)
// initialize list of warnings to ignore
g_ss_warnings_to_ignore_ht = reinterpret_cast<HashTable*>( pemalloc( sizeof( HashTable ), 1 ));
zend_hash_init( g_ss_warnings_to_ignore_ht, 6, NULL, NULL, 1 );
zend_hash_init( g_ss_warnings_to_ignore_ht, 6, NULL, sqlsrv_error_const_dtor /*pDestructor*/, 1 );
sqlsrv_error_const error_to_ignore;
@ -486,7 +490,7 @@ PHP_MINIT_FUNCTION(sqlsrv)
// supported encodings
g_ss_encodings_ht = reinterpret_cast<HashTable*>( pemalloc( sizeof( HashTable ), 1 ));
zend_hash_init( g_ss_encodings_ht, 3, NULL /*use standard hash function*/, NULL /*no resource destructor*/, 1 /*persistent*/ );
zend_hash_init( g_ss_encodings_ht, 3, NULL /*use standard hash function*/, sqlsrv_encoding_dtor /*resource destructor*/, 1 /*persistent*/ );
sqlsrv_encoding sql_enc_char( "char", SQLSRV_ENCODING_CHAR );
if (NULL == zend_hash_next_index_insert_mem(g_ss_encodings_ht, (void*)&sql_enc_char, sizeof( sqlsrv_encoding ))) {
@ -511,7 +515,7 @@ PHP_MINIT_FUNCTION(sqlsrv)
// initialize list of sqlsrv errors
g_ss_errors_ht = reinterpret_cast<HashTable*>( pemalloc( sizeof( HashTable ), 1 ));
::zend_hash_init( g_ss_errors_ht, 50, NULL, NULL, 1 );
::zend_hash_init( g_ss_errors_ht, 50, NULL, sqlsrv_error_const_dtor /*pDestructor*/, 1 );
for( int i = 0; SS_ERRORS[ i ].error_code != UINT_MAX; ++i ) {
if (NULL == ::zend_hash_index_update_mem( g_ss_errors_ht, SS_ERRORS[ i ].error_code,
@ -545,6 +549,18 @@ PHP_MINIT_FUNCTION(sqlsrv)
return SUCCESS;
}
// called by Zend for each parameter in the g_ss_warnings_to_ignore_ht and g_ss_errors_ht hash table when it is destroyed
void sqlsrv_error_const_dtor( zval* elem ) {
sqlsrv_error_const* error_to_ignore = reinterpret_cast<sqlsrv_error_const*>( Z_PTR_P(elem) );
pefree(error_to_ignore, 1);
}
// called by Zend for each parameter in the g_ss_encodings_ht hash table when it is destroyed
void sqlsrv_encoding_dtor( zval* elem ) {
sqlsrv_encoding* sql_enc = reinterpret_cast<sqlsrv_encoding*>( Z_PTR_P(elem) );
pefree(sql_enc, 1);
}
// Module shutdown function
// Free the environment handles allocated in MINIT and unregister our stream wrapper.
@ -554,7 +570,7 @@ PHP_MINIT_FUNCTION(sqlsrv)
PHP_MSHUTDOWN_FUNCTION(sqlsrv)
{
SQLSRV_UNUSED( type );
UNREGISTER_INI_ENTRIES();
// clean up the list of sqlsrv errors

View file

@ -178,7 +178,7 @@ struct ss_sqlsrv_stmt : public sqlsrv_stmt {
sqlsrv_phptype sql_type_to_php_type( SQLINTEGER sql_type, SQLUINTEGER size, bool prefer_string_to_stream );
bool prepared; // whether the statement has been prepared yet (used for error messages)
int conn_index; // index into the connection hash that contains this statement structure
zend_long conn_index; // index into the connection hash that contains this statement structure
zval* params_z; // hold parameters passed to sqlsrv_prepare but not used until sqlsrv_execute
sqlsrv_fetch_field_name* fetch_field_names; // field names for current results used by sqlsrv_fetch_array/object as keys
int fetch_fields_count;

View file

@ -91,13 +91,13 @@ const char SS_SQLSRV_WARNING_PARAM_VAR_NOT_REF[] = "Variable parameter %d not pa
zval* convert_to_zval( SQLSRV_PHPTYPE sqlsrv_php_type, void* in_val, SQLLEN field_len );
void fetch_fields_common( __inout ss_sqlsrv_stmt* stmt, zend_long fetch_type, __out zval* return_value, bool allow_empty_field_names
TSRMLS_DC );
bool determine_column_size_or_precision( sqlsrv_stmt const* stmt, sqlsrv_sqltype sqlsrv_type, __out SQLUINTEGER* column_size,
__out SQLSMALLINT* decimal_digits );
bool determine_column_size_or_precision( sqlsrv_stmt const* stmt, sqlsrv_sqltype sqlsrv_type, __out SQLULEN* column_size,
__out SQLSMALLINT* decimal_digits );
sqlsrv_phptype determine_sqlsrv_php_type( sqlsrv_stmt const* stmt, SQLINTEGER sql_type, SQLUINTEGER size, bool prefer_string );
void determine_stmt_has_rows( ss_sqlsrv_stmt* stmt TSRMLS_DC );
bool is_valid_sqlsrv_phptype( sqlsrv_phptype type );
bool is_valid_sqlsrv_sqltype( sqlsrv_sqltype type );
void parse_param_array( ss_sqlsrv_stmt* stmt, __inout zval* param_array, zend_ulong index, __out int& direction,
void parse_param_array( ss_sqlsrv_stmt* stmt, __inout zval* param_array, zend_ulong index, __out SQLSMALLINT& direction,
__out SQLSRV_PHPTYPE& php_out_type, __out SQLSRV_ENCODING& encoding, __out SQLSMALLINT& sql_type,
__out SQLULEN& column_size, __out SQLSMALLINT& decimal_digits TSRMLS_DC );
void type_and_encoding( INTERNAL_FUNCTION_PARAMETERS, int type );
@ -596,7 +596,7 @@ PHP_FUNCTION( sqlsrv_rows_affected )
LOG_FUNCTION( "sqlsrv_rows_affected" );
SQLRETURN r = SQL_SUCCESS;
ss_sqlsrv_stmt* stmt = NULL;
SQLINTEGER rows = -1;
SQLLEN rows = -1;
PROCESS_PARAMS( stmt, "r", _FN_, 0 );
@ -644,7 +644,7 @@ PHP_FUNCTION( sqlsrv_num_rows )
LOG_FUNCTION( "sqlsrv_num_rows" );
ss_sqlsrv_stmt* stmt = NULL;
SQLINTEGER rows = -1;
SQLLEN rows = -1;
PROCESS_PARAMS( stmt, "r", _FN_, 0 );
@ -1061,10 +1061,12 @@ PHP_FUNCTION( sqlsrv_get_field )
// get the statement, the field index and the optional type
PROCESS_PARAMS( stmt, "rl|l", _FN_, 2, &field_index, &sqlsrv_php_type );
try {
// validate that the field index is within range
SQLSMALLINT num_cols = core::SQLNumResultCols( stmt TSRMLS_CC );
int num_cols = core::SQLNumResultCols( stmt TSRMLS_CC );
if( field_index < 0 || field_index >= num_cols ) {
THROW_SS_ERROR( stmt, SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER, _FN_ );
}
@ -1200,7 +1202,7 @@ void mark_params_by_reference( ss_sqlsrv_stmt* stmt, zval* params_z TSRMLS_DC )
CHECK_CUSTOM_ERROR(zr == FAILURE, stmt, SS_SQLSRV_ERROR_VAR_REQUIRED, index + 1) {
throw ss::SSException();
}
ZVAL_MAKE_REF(var);
ZVAL_MAKE_REF(var);
}
}
@ -1234,7 +1236,7 @@ void bind_params( ss_sqlsrv_stmt* stmt TSRMLS_DC )
zend_ulong index = -1;
zval* param_z = NULL;
zval* value_z = NULL;
int direction = SQL_PARAM_INPUT;
SQLSMALLINT direction = SQL_PARAM_INPUT;
SQLSRV_ENCODING encoding = stmt->encoding();
if( stmt->encoding() == SQLSRV_ENCODING_DEFAULT ) {
encoding = stmt->conn->encoding();
@ -1271,13 +1273,9 @@ void bind_params( ss_sqlsrv_stmt* stmt TSRMLS_DC )
else {
value_z = param_z;
}
if (Z_ISREF_P(value_z))
{
ZVAL_DEREF(value_z);
}
// bind the parameter
core_sqlsrv_bind_param( stmt, index, direction, value_z, php_out_type, encoding, sql_type, column_size, decimal_digits
TSRMLS_CC );
core_sqlsrv_bind_param( stmt, index, direction, value_z, php_out_type, encoding, sql_type, column_size,
decimal_digits TSRMLS_CC );
}
}
@ -1501,13 +1499,13 @@ zval* convert_to_zval( SQLSRV_PHPTYPE sqlsrv_php_type, void* in_val, SQLLEN fiel
case SQLSRV_PHPTYPE_FLOAT:
{
out_zval = (zval*)sqlsrv_malloc(sizeof(zval));
if( sqlsrv_php_type == SQLSRV_PHPTYPE_INT ) {
ZVAL_LONG( out_zval, *(reinterpret_cast<zend_long*>( in_val )));
}
else {
ZVAL_DOUBLE( out_zval, *(reinterpret_cast<double*>( in_val )));
}
sqlsrv_free( in_val );
if( sqlsrv_php_type == SQLSRV_PHPTYPE_INT ) {
ZVAL_LONG( out_zval, *(static_cast<int*>( in_val )));
}
else {
ZVAL_DOUBLE( out_zval, *(static_cast<double*>( in_val )));
}
sqlsrv_free( in_val );
break;
}
@ -1515,17 +1513,17 @@ zval* convert_to_zval( SQLSRV_PHPTYPE sqlsrv_php_type, void* in_val, SQLLEN fiel
{
out_zval = (zval*) sqlsrv_malloc( sizeof(zval) );
ZVAL_STRINGL( out_zval, reinterpret_cast<char*>( in_val ), field_len);
sqlsrv_free( in_val );
sqlsrv_free( in_val );
break;
}
case SQLSRV_PHPTYPE_STREAM:
case SQLSRV_PHPTYPE_DATETIME :
{
{
out_zval = (reinterpret_cast<zval*>( in_val ));
in_val = NULL;
break;
}
break;
}
case SQLSRV_PHPTYPE_NULL:
out_zval = (zval*)sqlsrv_malloc(sizeof(zval));
@ -1540,9 +1538,11 @@ zval* convert_to_zval( SQLSRV_PHPTYPE sqlsrv_php_type, void* in_val, SQLLEN fiel
return out_zval;
}
// put in the column size and scale/decimal digits of the sql server type
// these values are taken from the MSDN page at http://msdn2.microsoft.com/en-us/library/ms711786(VS.85).aspx
bool determine_column_size_or_precision( sqlsrv_stmt const* stmt, sqlsrv_sqltype sqlsrv_type, __out SQLUINTEGER* column_size,
bool determine_column_size_or_precision( sqlsrv_stmt const* stmt, sqlsrv_sqltype sqlsrv_type, __out SQLULEN* column_size,
__out SQLSMALLINT* decimal_digits )
{
*decimal_digits = 0;
@ -1881,7 +1881,7 @@ void fetch_fields_common( __inout ss_sqlsrv_stmt* stmt, zend_long fetch_type, __
zval_ptr_dtor( &fields );
}
void parse_param_array( ss_sqlsrv_stmt* stmt, __inout zval* param_array, zend_ulong index, __out int& direction,
void parse_param_array( ss_sqlsrv_stmt* stmt, __inout zval* param_array, zend_ulong index, __out SQLSMALLINT& direction,
__out SQLSRV_PHPTYPE& php_out_type, __out SQLSRV_ENCODING& encoding, __out SQLSMALLINT& sql_type,
__out SQLULEN& column_size, __out SQLSMALLINT& decimal_digits TSRMLS_DC )
@ -1915,7 +1915,7 @@ void parse_param_array( ss_sqlsrv_stmt* stmt, __inout zval* param_array, zend_ul
throw ss::SSException();
}
direction = Z_LVAL_P( temp );
direction = static_cast<SQLSMALLINT>(Z_LVAL_P( temp ));
CHECK_CUSTOM_ERROR( direction != SQL_PARAM_INPUT && direction != SQL_PARAM_OUTPUT && direction != SQL_PARAM_INPUT_OUTPUT,
stmt, SS_SQLSRV_ERROR_INVALID_PARAMETER_DIRECTION, index + 1 ) {
throw ss::SSException();
@ -1995,7 +1995,7 @@ void parse_param_array( ss_sqlsrv_stmt* stmt, __inout zval* param_array, zend_ul
throw ss::SSException();
}
bool size_okay = determine_column_size_or_precision( stmt, sqlsrv_sql_type, &column_size, &decimal_digits );
bool size_okay = determine_column_size_or_precision(stmt, sqlsrv_sql_type, &column_size, &decimal_digits);
CHECK_CUSTOM_ERROR( !size_okay, stmt, SS_SQLSRV_ERROR_INVALID_PARAMETER_PRECISION, index + 1 ) {
@ -2020,7 +2020,9 @@ void parse_param_array( ss_sqlsrv_stmt* stmt, __inout zval* param_array, zend_ul
int encoding;
sqlsrv_phptype sqlsrv_phptype;
sqlsrv_phptype = determine_sqlsrv_php_type( stmt, sql_type, column_size, true );
sqlsrv_phptype = determine_sqlsrv_php_type( stmt, sql_type, (SQLUINTEGER)column_size, true );
// we DIE here since everything should have been validated already and to return the user an error
// for our own logic error would be confusing/misleading.
SQLSRV_ASSERT( sqlsrv_phptype.typeinfo.type != PHPTYPE_INVALID, "An invalid php type was returned with (supposed) "

View file

@ -567,7 +567,7 @@ PHP_FUNCTION( sqlsrv_configure )
throw ss::SSException();
}
long severity_mask = Z_LVAL_P( value_z );
zend_long severity_mask = Z_LVAL_P( value_z );
// make sure they can't use 0 to shut off the masking in the severity
if( severity_mask < SEV_ALL || severity_mask == 0 || severity_mask > (SEV_NOTICE + SEV_ERROR + SEV_WARNING) ) {
RETURN_FALSE;
@ -586,7 +586,7 @@ PHP_FUNCTION( sqlsrv_configure )
throw ss::SSException();
}
long subsystem_mask = Z_LVAL_P( value_z );
zend_long subsystem_mask = Z_LVAL_P( value_z );
if( subsystem_mask < LOG_ALL || subsystem_mask > (LOG_INIT + LOG_CONN + LOG_STMT + LOG_UTIL) ) {
RETURN_FALSE;
@ -604,7 +604,7 @@ PHP_FUNCTION( sqlsrv_configure )
throw ss::SSException();
}
long buffered_query_limit = Z_LVAL_P( value_z );
zend_long buffered_query_limit = Z_LVAL_P( value_z );
CHECK_CUSTOM_ERROR( buffered_query_limit < 0, error_ctx, SQLSRV_ERROR_INVALID_BUFFER_LIMIT, _FN_ ) {

View file

@ -16,11 +16,11 @@
// IN THE SOFTWARE.
//---------------------------------------------------------------------------------------------------------------------------------
#define VER_FILEVERSION_STR "4.0.8219.0"
#define VER_FILEVERSION_STR "4.0.0.0"
#define _FILEVERSION 4,0,0,0
#define SQLVERSION_MAJOR 4
#define SQLVERSION_MINOR 0
#define SQLVERSION_MMDD 8219
#define SQLVERSION_MMDD 0
#define SQLVERSION_REVISION 0