Skip to content

Commit

Permalink
PHP 4.0.4 release
Browse files Browse the repository at this point in the history
  • Loading branch information
meet-bhagdev committed May 4, 2016
1 parent abeda24 commit f7a10d1
Show file tree
Hide file tree
Showing 23 changed files with 197 additions and 88 deletions.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright(c) 2015 Microsoft Corporation
Copyright(c) 2016 Microsoft Corporation
All rights reserved.

MIT License
Expand Down
27 changes: 17 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,23 @@

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 and PDO_SQLSRV drivers for PHP 7 with limitations (see Limitations below for details). Upcoming release(s) will contain more functionality, bug fixes, and more (see Plans below for more details).
This preview contains the SQLSRV and PDO_SQLSRV drivers for PHP 7 with improvements on both drivers and some limitations (see Limitations below for details). Upcoming release(s) will contain more functionality, bug fixes, and more (see Plans below for more details).

The Microsoft Drivers for PHP for SQL Server Team

##Announcements

May 3, 2016 (4.0.4): The quality of SQLSRV and PDO_SQLSRV is improved and includes some bug fixes:
- Fixed retrieving stream data and metadata.
- Fixed issue with bind stream parameters.
- Fixed issue with retrieval in error case when trying to retrieve a non-streamble data type with SQLSRV_SQLTYPE_STREAM option
- Fixed issue with querying after another query with empty array of parameters.
- Fixed issue with retrieving integers as output parameter in SQLSRV 64-bit.
- Fixed issue scrollable statement option in SQLSRV_PDO 64-bit.
- Improved handling closed connection and statement resources.
- Fixed issue with binding bit parameter.
- Fix for The $driver_options (for specifying encoding) is included in PDOStatement::bindParam is included in PHP 7.0.6 release.

April 12, 2016 (4.0.3): The PDO_SQLSRV driver (32-bit and 64-bit) is now available. For the SQLSRV driver, we also have a few bug fixes to share:
- Fixed ability to fetch a user defined object into a class
- Fixed issue with re-preparing the same statement with referenced datetime parameters
Expand Down Expand Up @@ -47,7 +58,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 and/or php_pdo_sqlsrv.dll to your PHP extension directory.

This software has been compiled and tested under PHP 7.0.5 using the Visual C++ 2015 compiler.
This software has been compiled and tested under PHP 7.0.6 using the Visual C++ 2015 compiler.

## Install

Expand All @@ -69,18 +80,14 @@ For samples, please see the sample folder. For setup instructions, see [here] [

## Limitations

This preview contains the PHP 7 port of the SQLSRV and PDO_SQLSRV drivers. The focus was on basic functionality and does not provide backwards compatibility with PHP 5. The following items have known issues:
This preview contains the PHP 7 port of the SQLSRV and PDO_SQLSRV drivers, and does not provide backwards compatibility with PHP 5. The following items have known issues:

SQLSRV:
- Retrieving stream data and metadata
- Handle UTF8 strings
- Memory management
- Memory management.

SQLSRV 64-bit only:
- Retrieving integers as output parameters
PDO_SQLSRV 64-bit only:
- Retrieving integers as output parameters.

PDO_SQLSRV:
- The $driver_options (for specifying encoding) in PDOStatement::bindParam does not work due to a bug in the PDO extension source code. A fix for this bug now [exists](https://github.com/php/php-src/commit/5b8d0dc6ae01907d35ea51c061addedfe81e4e1f) but it hasn't made it into an official PHP release yet.

## Future Plans

Expand Down
Binary file modified binaries/x64/php_pdo_sqlsrv_7_nts.dll
Binary file not shown.
Binary file modified binaries/x64/php_pdo_sqlsrv_7_ts.dll
Binary file not shown.
Binary file modified binaries/x64/php_sqlsrv_7_nts.dll
Binary file not shown.
Binary file modified binaries/x64/php_sqlsrv_7_ts.dll
Binary file not shown.
Binary file modified binaries/x86/php_pdo_sqlsrv_7_nts.dll
Binary file not shown.
Binary file modified binaries/x86/php_pdo_sqlsrv_7_ts.dll
Binary file not shown.
Binary file modified binaries/x86/php_sqlsrv_7_nts.dll
Binary file not shown.
Binary file modified binaries/x86/php_sqlsrv_7_ts.dll
Binary file not shown.
4 changes: 2 additions & 2 deletions pdo_sqlsrv/core_conn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +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 = (unsigned int) (conn_str.length() + 1) * sizeof( wchar_t );
wconn_len = static_cast<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 );
wconn_string = utf16_string_from_mbcs_string( SQLSRV_ENCODING_UTF8, conn_str.c_str(), static_cast<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();
Expand Down
5 changes: 4 additions & 1 deletion pdo_sqlsrv/core_sqlsrv.h
Original file line number Diff line number Diff line change
Expand Up @@ -1318,7 +1318,7 @@ void core_sqlsrv_get_field(sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_p
bool core_sqlsrv_has_any_result( sqlsrv_stmt* stmt TSRMLS_DC );
void core_sqlsrv_next_result( sqlsrv_stmt* stmt TSRMLS_DC, bool finalize_output_params = true, bool throw_on_errors = true );
void core_sqlsrv_post_param( sqlsrv_stmt* stmt, zend_ulong paramno, zval* param_z TSRMLS_DC );
void core_sqlsrv_set_scrollable( sqlsrv_stmt* stmt, SQLULEN cursor_type TSRMLS_DC );
void core_sqlsrv_set_scrollable( sqlsrv_stmt* stmt, unsigned long cursor_type TSRMLS_DC );
void core_sqlsrv_set_query_timeout( sqlsrv_stmt* stmt, long timeout TSRMLS_DC );
void core_sqlsrv_set_query_timeout( sqlsrv_stmt* stmt, zval* value_z TSRMLS_DC );
void core_sqlsrv_set_send_at_exec( sqlsrv_stmt* stmt, zval* value_z TSRMLS_DC );
Expand Down Expand Up @@ -2061,6 +2061,9 @@ namespace core {

// *** zend wrappers ***

//zend_resource_dtor sets the type of destroyed resources to -1
#define RSRC_INVALID_TYPE -1

// wrapper for ZVAL_STRINGL macro. ZVAL_STRINGL always allocates memory when initialzing new string from char string
// so allocated memory inside of value_z should be released before assigning it to the new string
inline void sqlsrv_zval_stringl(zval* value_z, const char* str, const std::size_t str_len)
Expand Down
57 changes: 31 additions & 26 deletions pdo_sqlsrv/core_stmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -348,8 +348,8 @@ void core_sqlsrv_bind_param(sqlsrv_stmt* stmt, SQLUSMALLINT param_num, SQLSMALLI
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_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 );
// 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.
Expand Down Expand Up @@ -422,7 +422,7 @@ void core_sqlsrv_bind_param(sqlsrv_stmt* stmt, SQLUSMALLINT param_num, SQLSMALLI

// 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, (unsigned int)param_num, param_z, encoding, column_size, decimal_digits TSRMLS_CC );
default_sql_size_and_scale( stmt, static_cast<unsigned int>( param_num ), param_z, encoding, column_size, decimal_digits TSRMLS_CC );
}

// determine the ODBC C type
Expand All @@ -442,25 +442,27 @@ void core_sqlsrv_bind_param(sqlsrv_stmt* stmt, SQLUSMALLINT param_num, SQLSMALLI
case IS_TRUE:
case IS_FALSE:
case IS_LONG:
{
{
// if it is boolean, set the lval to 0 or 1
convert_to_long( param_z );
buffer = &param_z->value;
buffer_len = sizeof( param_z->value.lval );
buffer_len = sizeof( Z_LVAL_P( param_z ));
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_ref, int(param_num), zval_was_bool );
sqlsrv_output_param output_param( param_ref, static_cast<int>( param_num ), zval_was_bool );
save_output_param_for_later( stmt, output_param TSRMLS_CC );
}
}
break;
case IS_DOUBLE:
{
buffer = &param_z->value;
buffer_len = sizeof(Z_DVAL_P(param_z));
buffer_len = sizeof( Z_DVAL_P( param_z ));
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_ref, int(param_num), false );
sqlsrv_output_param output_param(param_ref, static_cast<int>( param_num ), false );
save_output_param_for_later( stmt, output_param TSRMLS_CC );
}
}
Expand All @@ -472,7 +474,7 @@ void core_sqlsrv_bind_param(sqlsrv_stmt* stmt, SQLUSMALLINT param_num, SQLSMALLI
if( direction == SQL_PARAM_INPUT && encoding == CP_UTF8 ) {

zval wbuffer_z;
ZVAL_NULL(&wbuffer_z);
ZVAL_NULL( &wbuffer_z );

bool converted = convert_input_param_to_utf16( param_z, &wbuffer_z );
CHECK_CUSTOM_ERROR( !converted, stmt, SQLSRV_ERROR_INPUT_PARAM_ENCODING_TRANSLATE,
Expand Down Expand Up @@ -519,12 +521,12 @@ void core_sqlsrv_bind_param(sqlsrv_stmt* stmt, SQLUSMALLINT param_num, SQLSMALLI
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_ref, encoding, param_num, (SQLUINTEGER)buffer_len );
sqlsrv_output_param output_param( param_ref, encoding, param_num, static_cast<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,
// than if there is a truncation due to the data coming from the server being
// then if there is a truncation due to the data coming from the server being
// greater than the column_size, we don't get any truncation error. In order to
// avoid this silent truncation, we set the column_size to be "MAX" size for
// string types. This will guarantee that there is no silent truncation for
Expand Down Expand Up @@ -552,7 +554,7 @@ void core_sqlsrv_bind_param(sqlsrv_stmt* stmt, SQLUSMALLINT param_num, SQLSMALLI
HashTable* streams_ht = Z_ARRVAL( stmt->param_streams );
core::sqlsrv_zend_hash_index_update_mem(*stmt, streams_ht, param_num, &stream_encoding, sizeof(stream_encoding) TSRMLS_CC);
buffer = reinterpret_cast<SQLPOINTER>( param_num );
Z_TRY_ADDREF_P(param_z); // so that it doesn't go away while we're using it
Z_TRY_ADDREF_P( param_z ); // so that it doesn't go away while we're using it
buffer_len = 0;
ind_ptr = SQL_DATA_AT_EXEC;
}
Expand Down Expand Up @@ -702,6 +704,8 @@ void core_sqlsrv_execute( sqlsrv_stmt* stmt TSRMLS_DC, const char* sql, int sql_

finalize_output_parameters( stmt TSRMLS_CC );
}
// stream parameters are sent, clean the Hashtable
zend_hash_clean( Z_ARRVAL( stmt->param_streams ));

}
catch( core::CoreException& e ) {
Expand Down Expand Up @@ -935,7 +939,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( (SQLINTEGER)sql_field_type, (SQLUINTEGER)sql_field_len, prefer_string );
sqlsrv_php_type = stmt->sql_type_to_php_type( static_cast<SQLINTEGER>( sql_field_type ), static_cast<SQLUINTEGER>( sql_field_len ), prefer_string );
}

// Verify that we have an acceptable type to convert.
Expand Down Expand Up @@ -1060,7 +1064,7 @@ void core_sqlsrv_post_param( sqlsrv_stmt* stmt, zend_ulong param_num, zval* para
}

//Calls SQLSetStmtAttr to set a cursor.
void core_sqlsrv_set_scrollable( sqlsrv_stmt* stmt, SQLULEN cursor_type TSRMLS_DC )
void core_sqlsrv_set_scrollable( sqlsrv_stmt* stmt, unsigned long cursor_type TSRMLS_DC )
{
try {

Expand Down Expand Up @@ -1139,7 +1143,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, (long)Z_LVAL_P( value_z ) TSRMLS_CC );
core_sqlsrv_set_query_timeout( stmt, static_cast<long>( Z_LVAL_P( value_z )) TSRMLS_CC );
}
catch( core::CoreException& ) {
throw;
Expand Down Expand Up @@ -1242,7 +1246,7 @@ bool core_sqlsrv_send_stream_packet( sqlsrv_stmt* stmt TSRMLS_DC )
throw core::CoreException();
}

stmt->current_stream_read += (unsigned int)read;
stmt->current_stream_read += static_cast<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
Expand All @@ -1256,7 +1260,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, int(read), wbuffer, int(sizeof( wbuffer ) / sizeof( wchar_t )));
buffer, static_cast<int>( read ), wbuffer, static_cast<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
Expand All @@ -1272,7 +1276,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, int(read + new_read), wbuffer, int(sizeof( wbuffer ) / sizeof( wchar_t )));
buffer, static_cast<int>( read + new_read ), wbuffer, static_cast<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 )) {
Expand Down Expand Up @@ -1596,7 +1600,8 @@ void core_get_field_common( __inout sqlsrv_stmt* stmt, SQLUSMALLINT field_index,
{

zval_auto_ptr return_value_z;
return_value_z = (zval *)sqlsrv_malloc(sizeof(zval*));
return_value_z = (zval *)sqlsrv_malloc(sizeof(zval));
ZVAL_UNDEF(return_value_z);
php_stream* stream = NULL;
sqlsrv_stream* ss = NULL;
SQLLEN sql_type;
Expand Down Expand Up @@ -1627,7 +1632,7 @@ void core_get_field_common( __inout sqlsrv_stmt* stmt, SQLUSMALLINT field_index,

// mark this as our active stream
stmt->active_stream = return_value_z;
*field_value = reinterpret_cast<void*>( return_value_z.get() );
*field_value = reinterpret_cast<void*>( return_value_z.get() );
return_value_z.transferred();
break;
}
Expand Down Expand Up @@ -2410,9 +2415,9 @@ void resize_output_buffer_if_necessary( sqlsrv_stmt* stmt, zval* param_z, SQLULE
void save_output_param_for_later( sqlsrv_stmt* stmt, sqlsrv_output_param& param TSRMLS_DC )
{
HashTable* param_ht = Z_ARRVAL( stmt->output_params );
zend_ulong paramno = static_cast<zend_ulong>(param.param_num);
core::sqlsrv_zend_hash_index_update_mem(*stmt, param_ht, paramno, &param, sizeof(sqlsrv_output_param));
Z_TRY_ADDREF_P(param.param_z); // we have a reference to the param
zend_ulong paramno = static_cast<zend_ulong>( param.param_num );
core::sqlsrv_zend_hash_index_update_mem(*stmt, param_ht, paramno, &param, sizeof( sqlsrv_output_param ));
Z_TRY_ADDREF_P( param.param_z ); // we have a reference to the param
}


Expand All @@ -2427,14 +2432,14 @@ void send_param_streams( sqlsrv_stmt* stmt TSRMLS_DC )
// called by Zend for each parameter in the sqlsrv_stmt::output_params hash table when it is cleaned/destroyed
void sqlsrv_output_param_dtor( zval* data )
{
sqlsrv_output_param *output_param = reinterpret_cast<sqlsrv_output_param*>( Z_PTR_P(data) );
sqlsrv_output_param *output_param = static_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
}

// called by Zend for each stream in the sqlsrv_stmt::param_streams hash table when it is cleaned/destroyed
void sqlsrv_stream_dtor(zval* data )
void sqlsrv_stream_dtor( zval* data )
{
sqlsrv_stream* stream_encoding = reinterpret_cast<sqlsrv_stream*>( Z_PTR_P(data) );
sqlsrv_stream* stream_encoding = static_cast<sqlsrv_stream*>( Z_PTR_P( data ));
zval_ptr_dtor( stream_encoding->stream_z ); // undo the reference to the stream we will no longer hold
}

Expand Down
2 changes: 1 addition & 1 deletion pdo_sqlsrv/core_stream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ size_t sqlsrv_stream_read( php_stream* stream, __out_bcount(count) char* buf, si
}

int enc_len = WideCharToMultiByte( ss->encoding, flags, reinterpret_cast<LPCWSTR>( temp_buf.get() ),
int(read >> 1), buf, int(count), NULL, NULL );
static_cast<int>(read >> 1), buf, static_cast<int>(count), NULL, NULL );

if( enc_len == 0 ) {

Expand Down
4 changes: 2 additions & 2 deletions pdo_sqlsrv/pdo_stmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ void set_stmt_cursors( sqlsrv_stmt* stmt, zval* value_z TSRMLS_DC )
}

zend_long pdo_cursor_type = Z_LVAL_P( value_z );
SQLULEN odbc_cursor_type = -1;
long odbc_cursor_type = -1;

switch( pdo_cursor_type ) {

Expand Down Expand Up @@ -164,7 +164,7 @@ void set_stmt_cursor_scroll_type( sqlsrv_stmt* stmt, zval* value_z TSRMLS_DC )
THROW_PDO_ERROR( stmt, PDO_SQLSRV_ERROR_INVALID_CURSOR_WITH_SCROLL_TYPE );
}

SQLULEN odbc_cursor_type = Z_LVAL_P( value_z );
long odbc_cursor_type = static_cast<long>( Z_LVAL_P( value_z ) );

core_sqlsrv_set_scrollable( stmt, odbc_cursor_type TSRMLS_CC );

Expand Down
Loading

0 comments on commit f7a10d1

Please sign in to comment.