PHP 4.0.4 release

This commit is contained in:
Meet Bhagdev 2016-05-03 20:05:41 -07:00
parent abeda24d73
commit f7a10d1f91
23 changed files with 197 additions and 88 deletions

View file

@ -1,4 +1,4 @@
Copyright(c) 2015 Microsoft Corporation
Copyright(c) 2016 Microsoft Corporation
All rights reserved.
MIT License

View file

@ -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
@ -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
@ -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

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -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();

View file

@ -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 );
@ -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)

View file

@ -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.
@ -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
@ -442,13 +442,15 @@ 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 );
}
}
@ -456,11 +458,11 @@ void core_sqlsrv_bind_param(sqlsrv_stmt* stmt, SQLUSMALLINT param_num, SQLSMALLI
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 );
}
}
@ -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,
@ -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
@ -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;
}
@ -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 ) {
@ -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.
@ -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 {
@ -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;
@ -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
@ -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
@ -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 )) {
@ -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;
@ -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;
}
@ -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
}
@ -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
}

View file

@ -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 ) {

View file

@ -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 ) {
@ -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 );

View file

@ -0,0 +1,74 @@
<?php
echo "\n";
$serverName = "tcp:yourserver.database.windows.net,1433";
$database = "yourdatabase";
$uid = "yourusername";
$pwd = "yourpassword";
//Establishes the connection
$conn = new PDO( "sqlsrv:server=$serverName ; Database = $database", $uid, $pwd);
//Select Query
$tsql = "SELECT [CompanyName] FROM SalesLT.Customer";
//Executes the query
$getProducts = $conn->query( $tsql );
//Error handling
FormatErrors ($conn->errorInfo());
$productCount = 0;
$ctr = 0;
?>
<h1> First 10 results are : </h1>
<?php
while($row = $getProducts->fetch(PDO::FETCH_ASSOC))
{
if($ctr>9)
break;
$ctr++;
echo($row['CompanyName']);
echo("<br/>");
$productCount++;
}
$getProducts = NULL;
$tsql = "INSERT INTO SalesLT.Product (Name, ProductNumber, StandardCost, ListPrice, SellStartDate) OUTPUT INSERTED.* VALUES ('SQL New 1', 'SQL New 2', 0, 0, getdate())";
//Insert query
$insertReview = $conn->query( $tsql );
FormatErrors ($conn->errorInfo());
?>
<h1> Product Key inserted is :</h1>
<?php
while($row = $insertReview->fetch(PDO::FETCH_ASSOC))
{
echo($row['ProductID']."<br/>");
}
$insertReview = NULL;
//Delete Query
//We are deleting the same record
$tsql = "DELETE FROM [SalesLT].[Product] WHERE Name=?";
$param = "SQL New 1";
$deleteReview = $conn->prepare($tsql);
$deleteReview->bindParam(1, $param);
$deleteReview->execute();
FormatErrors ($deleteReview->errorInfo());
function FormatErrors( $error )
{
/* Display error. */
echo "Error information: <br/>";
echo "SQLSTATE: ".$error[0]."<br/>";
echo "Code: ".$error[1]."<br/>";
echo "Message: ".$error[2]."<br/>";
}
?>

View file

@ -1,7 +1,7 @@
<?php
echo "\n";
$serverName = "tcp:yourserver.database.windows.net,1433";
$connectionOptions = array("Database"=>"yourpassword", "Uid"=>"yourusername", "PWD"=>"yourpassword");
$connectionOptions = array("Database"=>"yourdatabase", "Uid"=>"yourusername", "PWD"=>"yourpassword");
//Establishes the connection
$conn = sqlsrv_connect($serverName, $connectionOptions);
@ -28,7 +28,7 @@
}
sqlsrv_free_stmt($getProducts);
$tsql = "INSERT SalesLT.Product (Name, ProductNumber, StandardCost, ListPrice, SellStartDate) OUTPUT INSERTED.ProductID VALUES ('SQL New 1', 'SQL New 2', 0, 0, getdate())";
$tsql = "INSERT INTO SalesLT.Product (Name, ProductNumber, StandardCost, ListPrice, SellStartDate) OUTPUT INSERTED.ProductID VALUES ('SQL New 1', 'SQL New 2', 0, 0, getdate())";
//Insert query
$insertReview = sqlsrv_query($conn, $tsql);
if($insertReview == FALSE)

View file

@ -571,7 +571,7 @@ PHP_FUNCTION( sqlsrv_close )
// 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 ) {
// Check if it was a zval
@ -580,7 +580,7 @@ PHP_FUNCTION( sqlsrv_close )
throw ss::SSException();
}
// if sqlsrv_close was called on a non-existent connection than we just return success.
// if sqlsrv_close was called on a non-existent connection then we just return success.
if( Z_TYPE_P( conn_r ) == IS_NULL ) {
RETURN_TRUE;
}
@ -588,9 +588,15 @@ PHP_FUNCTION( sqlsrv_close )
THROW_CORE_ERROR( error_ctx, SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER, _FN_ );
}
}
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_ ) {
// if sqlsrv_close was called on an already closed connection then we just return success.
if ( Z_RES_TYPE_P( conn_r ) == RSRC_INVALID_TYPE) {
RETURN_TRUE;
}
CHECK_CUSTOM_ERROR(( conn == NULL ), error_ctx, SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER, _FN_ ) {
throw ss::SSException();
}
@ -603,8 +609,8 @@ PHP_FUNCTION( sqlsrv_close )
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 );
ZVAL_NULL( conn_r );
RETURN_TRUE;
}

View file

@ -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();

View file

@ -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 );
@ -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)

View file

@ -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.
@ -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
@ -442,13 +442,15 @@ 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 );
}
}
@ -456,11 +458,11 @@ void core_sqlsrv_bind_param(sqlsrv_stmt* stmt, SQLUSMALLINT param_num, SQLSMALLI
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 );
}
}
@ -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,
@ -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
@ -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;
}
@ -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 ) {
@ -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.
@ -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 {
@ -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;
@ -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
@ -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
@ -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 )) {
@ -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;
@ -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;
}
@ -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
}
@ -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
}

View file

@ -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 ) {

View file

@ -1059,7 +1059,6 @@ 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
@ -1259,7 +1258,6 @@ void bind_params( ss_sqlsrv_stmt* stmt TSRMLS_DC )
zval* var = NULL;
int zr = (NULL != (var = zend_hash_index_find(Z_ARRVAL_P(param_z), 0))) ? SUCCESS : FAILURE;
CHECK_CUSTOM_ERROR( zr == FAILURE, stmt, SS_SQLSRV_ERROR_VAR_REQUIRED, index + 1 ) {
zval_ptr_dtor( params_z );
throw ss::SSException();
}
@ -1406,19 +1404,24 @@ PHP_FUNCTION( sqlsrv_free_stmt )
// verify the resource so we know we're deleting a statement
stmt = static_cast<ss_sqlsrv_stmt*>(zend_fetch_resource_ex(stmt_r TSRMLS_CC, ss_sqlsrv_stmt::resource_name, ss_sqlsrv_stmt::descriptor));
// if sqlsrv_free_stmt was called on an already closed statment then we just return success.
// zend_list_close sets the type of the closed statment to -1.
if ( Z_RES_TYPE_P( stmt_r ) == RSRC_INVALID_TYPE ) {
RETURN_TRUE;
}
if( stmt == NULL ) {
THROW_CORE_ERROR( error_ctx, SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER, _FN_ );
}
// delete the resource from Zend's master list, which will trigger the statement's destructor
if( zend_list_close( Z_RES_P(stmt_r) ) == FAILURE ) {
LOG( SEV_ERROR, "Failed to remove stmt resource %1!d!", Z_RES_P( stmt_r )->handle);
}
ZVAL_NULL( stmt_r );
RETURN_TRUE;
}
@ -1440,7 +1443,7 @@ void stmt_option_scrollable:: operator()( sqlsrv_stmt* stmt, stmt_option const*
}
const char* scroll_type = Z_STRVAL_P( value_z );
SQLULEN cursor_type = -1;
unsigned long cursor_type = -1;
// find which cursor type they would like and set the ODBC statement attribute as such
if( !stricmp( scroll_type, SSCursorTypes::QUERY_OPTION_SCROLLABLE_STATIC )) {
@ -1518,7 +1521,10 @@ zval* convert_to_zval( SQLSRV_PHPTYPE sqlsrv_php_type, void* in_val, SQLLEN fiel
case SQLSRV_PHPTYPE_STREAM:
case SQLSRV_PHPTYPE_DATETIME :
{
out_zval = (reinterpret_cast<zval*>( in_val ));
out_zval = ( static_cast<zval*>( in_val ) );
//addref here because deleting out_zval later will decrement the refcount
Z_TRY_ADDREF_P( out_zval );
in_val = NULL;
break;
}