Skip to content

Commit

Permalink
4.1.0 Latest Snap of Code
Browse files Browse the repository at this point in the history
  • Loading branch information
meet-bhagdev committed Jul 30, 2016
1 parent 57f21e8 commit 458b785
Show file tree
Hide file tree
Showing 17 changed files with 228 additions and 131 deletions.
57 changes: 12 additions & 45 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,50 +10,18 @@ The Microsoft Drivers for PHP for SQL Server Team

##Announcements

June 30, 2016 (4.0.6): The quality of SQLSRV and PDO_SQLSRV is improved and includes some memory leak fixes:
- Fixed a heap corruption when binding parameters in a prepare statement with error
- Fixed leaks in SQLSRV streams and output parameters handling
- Fixed leaks in SQLSRV fetch object
- Fixed leaks in SQLSRV binding object parameters
- Fixed leaks in SQLSRV buffered result set
- Fixed leaks in SQLSRV getting datetime and stream fields
- Fixed leaks in PDO_SQLSRV field cache
- Fixed leaks in PDO_SQLSRV construct when connecting with error
- Fixed leaks in PDO_SQLSRV exception handling

June 13, 2016 (4.0.5): The quality of SQLSRV and PDO_SQLSRV is improved and includes some bug fixes:
- Added ability to connect to Microsoft ODBC Driver 13.
- Fixed some memory leaks in data retrieval.
- Fixed issue with error handling in bound stream parameters when send_stream_at_exec option is set to false.
- Fixed issue with when connecting twice when Sqlsrv_errors configured to only WARNINGS.
- Fixed issue with double and string as input-output parameters in PDO_SQLSRV driver.
- Fixed a heap corruption in PDO_SQLSRV connection.

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
- Fixed issue with binding output parameters with php type string with binary and char encodings and sql types SQLSRV_SQLTYPE_NCHAR and SQLSRV_SQLTYPE_NVARCHAR

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 community’s 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

July 28, 2016 (4.1.0): Thanks to the community's input, this release expands drivers functionalities and also includes some bug fixes:

- `SQLSRV_ATTR_FETCHES_NUMERIC_TYPE` connection attribute flag is added to PDO_SQLSRV driver to handle numeric fetches from columns with numeric Sql types (only bit, integer, smallint, tinyint, float and real). This flag can be turned on by setting its value in `PDO::setAttribute` to `true`, For example,
`$conn->setAttribute(PDO::SQLSRV_ATTR_FETCHES_NUMERIC_TYPE,true);`
If `SQLSRV_ATTR_FETCHES_NUMERIC_TYPE` is set to `true` the results from an integer column will be represented as an `int`, likewise, Sql types float and real will be represented as `float`.
Note for exceptions:
- When connection option flag `ATTR_STRINGIFY_FETCHES` is on, even when `SQLSRV_ATTR_FETCHES_NUMERIC_TYPE` is on, the return value will still be string.
- When the returned PDO type in bind column is `PDO_PARAM_INT`, the return value from a integer column will be int even if `SQLSRV_ATTR_FETCHES_NUMERIC_TYPE` is off.
- Fixed float truncation when using buffered query.
- Fixed handling of Unicode strings and binary when emulate prepare is on in `PDOStatement::bindParam`. To bind a Unicode string, `PDO::SQLSRV_ENCODING_UTF8` should be set using `$driverOption`, and to bind a string to column of Sql type binary, `PDO::SQLSRV_ENCODING_BINARY` should be set.
- Fixed string truncation in bind output parameters when the size is not set and the length of initialized variable is less than the output.
- Fixed bind string parameters as bidirectional parameters (`PDO::PARAM_INPUT_OUTPUT `) in PDO_SQLSRV driver. Note for output or bidirectional parameters, `PDOStatement::closeCursor`should be called to get the output value.

## Build

Expand Down Expand Up @@ -107,7 +75,6 @@ SQLSRV:

## Future Plans

- Linux Version
- Expand SQL 16 Feature Support (example: Always Encrypted)
- Build Verification/Fundamental Tests
- Bug Fixes
Expand Down
2 changes: 1 addition & 1 deletion pdo_sqlsrv/CREDITS
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Microsoft Drivers 4.0.0 for PHP for SQL Server (PDO driver)
Microsoft Drivers 4.1.0 for PHP for SQL Server (PDO driver)
22 changes: 20 additions & 2 deletions pdo_sqlsrv/core_results.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,25 @@ template <typename Char, typename Number>
SQLRETURN number_to_string( Number* number_data, _Out_ void* buffer, SQLLEN buffer_length, _Out_ SQLLEN* out_buffer_length,
sqlsrv_error_auto_ptr& last_error )
{
// get to display size by removing the null terminator from buffer length
size_t display_size = ( buffer_length - sizeof( Char )) / sizeof( Char );

std::basic_ostringstream<Char> os;
// use the display size to determine the sql type. And if it is a double, set the precision accordingly
// the display sizes are set by the ODBC driver based on the precision of the sql type
// otherwise we can just use the default precision as long will not be truncated
size_t real_display_size = 14;
size_t float_display_size = 24;
size_t real_precision = 7;
size_t float_precision = 15;
// this is the case of sql type float(24) or real
if ( display_size == real_display_size ) {
os.precision( real_precision );
}
// this is the case of sql type float(53)
else if ( display_size == float_display_size ) {
os.precision( float_precision );
}
std::locale loc;
os.imbue( loc );
std::use_facet< std::num_put< Char > >( loc ).put( std::basic_ostream<Char>::_Iter( os.rdbuf() ), os, ' ', *number_data );
Expand All @@ -100,13 +118,13 @@ SQLRETURN number_to_string( Number* number_data, _Out_ void* buffer, SQLLEN buff
return SQL_ERROR;
}

if( str_num.size() * sizeof(Char) + sizeof(Char) > (size_t) buffer_length ) {
if( str_num.size() * sizeof(Char) > (size_t) buffer_length ) {
last_error = new ( sqlsrv_malloc( sizeof( sqlsrv_error ))) sqlsrv_error(
(SQLCHAR*) "HY090", (SQLCHAR*) "Buffer length too small to hold number as string", -1 );
return SQL_ERROR;
}

*out_buffer_length = str_num.size() * sizeof(Char) + sizeof(Char); // include NULL terminator
*out_buffer_length = str_num.size() * sizeof( Char ); // str_num.size() already include the NULL terminator
memcpy_s( buffer, buffer_length, str_num.c_str(), *out_buffer_length );

return SQL_SUCCESS;
Expand Down
3 changes: 1 addition & 2 deletions pdo_sqlsrv/core_sqlsrv.h
Original file line number Diff line number Diff line change
Expand Up @@ -1276,7 +1276,7 @@ struct sqlsrv_stmt : public sqlsrv_context {
virtual ~sqlsrv_stmt( void );

// driver specific conversion rules from a SQL Server/ODBC type to one of the SQLSRV_PHPTYPE_* constants
virtual sqlsrv_phptype sql_type_to_php_type( SQLINTEGER sql_type, SQLUINTEGER size, bool prefer_string_to_stream ) = 0;
virtual sqlsrv_phptype sql_type_to_php_type( SQLINTEGER sql_type, SQLUINTEGER size, bool prefer_string_to_stream, bool prefer_number_to_string = false ) = 0;

};

Expand Down Expand Up @@ -1337,7 +1337,6 @@ 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, SQLLEN limit TSRMLS_DC );
void core_finalize_output_parameters(sqlsrv_stmt* stmt TSRMLS_DC);


//*********************************************************************************************************************************
Expand Down
9 changes: 3 additions & 6 deletions pdo_sqlsrv/core_stmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1305,10 +1305,6 @@ bool core_sqlsrv_send_stream_packet( sqlsrv_stmt* stmt TSRMLS_DC )
return true;
}

void core_finalize_output_parameters(sqlsrv_stmt* stmt TSRMLS_DC) {
finalize_output_parameters(stmt TSRMLS_CC);
}

void stmt_option_functor::operator()( sqlsrv_stmt* /*stmt*/, stmt_option const* /*opt*/, zval* /*value_z*/ TSRMLS_DC )
{
TSRMLS_C;
Expand Down Expand Up @@ -1908,12 +1904,13 @@ void default_sql_size_and_scale( sqlsrv_stmt* stmt, unsigned int paramno, zval*
break;
case IS_STRING:
{
SQLULEN byte_len = Z_STRLEN_P( param_z ) * ((encoding == SQLSRV_ENCODING_UTF8) ? sizeof( wchar_t ) : sizeof( char ));
size_t char_size = ( encoding == SQLSRV_ENCODING_UTF8 ) ? sizeof( wchar_t ) : sizeof( char );
SQLULEN byte_len = Z_STRLEN_P( param_z ) * char_size;
if( byte_len > SQL_SERVER_MAX_FIELD_SIZE ) {
column_size = SQL_SERVER_MAX_TYPE_SIZE;
}
else {
column_size = Z_STRLEN_P( param_z );
column_size = SQL_SERVER_MAX_FIELD_SIZE / char_size;
}
break;
}
Expand Down
121 changes: 89 additions & 32 deletions pdo_sqlsrv/pdo_dbh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ enum PDO_STMT_OPTIONS {
PDO_STMT_OPTION_CURSOR_SCROLL_TYPE,
PDO_STMT_OPTION_CLIENT_BUFFER_MAX_KB_SIZE,
PDO_STMT_OPTION_EMULATE_PREPARES,
PDO_STMT_OPTION_FETCHES_NUMERIC_TYPE,
};

// List of all the statement options supported by this driver.
Expand All @@ -85,6 +86,7 @@ const stmt_option PDO_STMT_OPTS[] = {
{ NULL, 0, PDO_STMT_OPTION_CURSOR_SCROLL_TYPE, std::unique_ptr<stmt_option_cursor_scroll_type>( new stmt_option_cursor_scroll_type ) },
{ NULL, 0, PDO_STMT_OPTION_CLIENT_BUFFER_MAX_KB_SIZE, std::unique_ptr<stmt_option_buffered_query_limit>( new stmt_option_buffered_query_limit ) },
{ NULL, 0, PDO_STMT_OPTION_EMULATE_PREPARES, std::unique_ptr<stmt_option_emulate_prepares>( new stmt_option_emulate_prepares ) },
{ NULL, 0, PDO_STMT_OPTION_FETCHES_NUMERIC_TYPE, std::unique_ptr<stmt_option_fetch_numeric>( new stmt_option_fetch_numeric ) },

{ NULL, 0, SQLSRV_STMT_OPTION_INVALID, std::unique_ptr<stmt_option_functor>{} },
};
Expand Down Expand Up @@ -362,11 +364,13 @@ struct pdo_dbh_methods pdo_sqlsrv_dbh_methods = {

// constructor for the internal object for connections
pdo_sqlsrv_dbh::pdo_sqlsrv_dbh( SQLHANDLE h, error_callback e, void* driver TSRMLS_DC ) :
sqlsrv_conn( h, e, driver, SQLSRV_ENCODING_UTF8 TSRMLS_CC ),
stmts( NULL ),
direct_query( false ),
query_timeout( QUERY_TIMEOUT_INVALID ),
client_buffer_max_size( PDO_SQLSRV_G( client_buffer_max_size ) )
sqlsrv_conn( h, e, driver, SQLSRV_ENCODING_UTF8 TSRMLS_CC ),
stmts( NULL ),
direct_query( false ),
query_timeout( QUERY_TIMEOUT_INVALID ),
client_buffer_max_size( PDO_SQLSRV_G( client_buffer_max_size )),
bind_param_encoding( SQLSRV_ENCODING_CHAR ),
fetch_numeric( false )
{
if( client_buffer_max_size < 0 ) {
client_buffer_max_size = sqlsrv_buffered_result_set::BUFFERED_QUERY_LIMIT_DEFAULT;
Expand Down Expand Up @@ -906,6 +910,10 @@ int pdo_sqlsrv_dbh_set_attr( pdo_dbh_t *dbh, zend_long attr, zval *val TSRMLS_DC
driver_dbh->client_buffer_max_size = Z_LVAL_P( val );
break;

case SQLSRV_ATTR_FETCHES_NUMERIC_TYPE:
driver_dbh->fetch_numeric = (zend_is_true(val)) ? true : false;
break;

// Not supported
case PDO_ATTR_FETCH_TABLE_NAMES:
case PDO_ATTR_FETCH_CATALOG_NAMES:
Expand Down Expand Up @@ -1047,6 +1055,12 @@ int pdo_sqlsrv_dbh_get_attr( pdo_dbh_t *dbh, zend_long attr, zval *return_value
break;
}

case SQLSRV_ATTR_FETCHES_NUMERIC_TYPE:
{
ZVAL_BOOL( return_value, driver_dbh->fetch_numeric );
break;
}

default:
{
THROW_PDO_ERROR( driver_dbh, PDO_SQLSRV_ERROR_INVALID_DBH_ATTR );
Expand Down Expand Up @@ -1190,41 +1204,81 @@ char * pdo_sqlsrv_dbh_last_id( pdo_dbh_t *dbh, const char *name, _Out_ size_t* l
int pdo_sqlsrv_dbh_quote( pdo_dbh_t* dbh, const char* unquoted, size_t unquoted_len, char **quoted, size_t* quoted_len,
enum pdo_param_type /*paramtype*/ TSRMLS_DC )
{
PDO_RESET_DBH_ERROR;
PDO_VALIDATE_CONN;
PDO_RESET_DBH_ERROR;
PDO_VALIDATE_CONN;
PDO_LOG_DBH_ENTRY;

// count the number of quotes needed
unsigned int quotes_needed = 2; // the initial start and end quotes of course
for(size_t index = 0; index < unquoted_len && unquoted[ index ] != '\0'; ++index ) {
if( unquoted[ index ] == '\'' ) {
++quotes_needed;
}
}
pdo_sqlsrv_dbh* driver_dbh = reinterpret_cast<pdo_sqlsrv_dbh*>( dbh->driver_data );
SQLSRV_ENCODING encoding = driver_dbh->bind_param_encoding;

*quoted_len = unquoted_len + quotes_needed; // length returned to the caller should not account for null terminator.
*quoted = reinterpret_cast<char*>( sqlsrv_malloc( *quoted_len, sizeof( char ), 1 )); // include space for null terminator.
unsigned int out_current = 0;
if ( encoding == SQLSRV_ENCODING_BINARY ) {
// convert from char* to hex digits using os
std::basic_ostringstream<char> os;
for ( size_t index = 0; index < unquoted_len && unquoted[index] != '\0'; ++index ) {
os << std::hex << ( int )unquoted[index];
}
std::basic_string<char> str_hex = os.str();
// each character is represented by 2 digits of hex
size_t unquoted_str_len = unquoted_len * 2; // length returned should not account for null terminator
char* unquoted_str = reinterpret_cast<char*>( sqlsrv_malloc( unquoted_str_len, sizeof( char ), 1 )); // include space for null terminator
strcpy_s( unquoted_str, unquoted_str_len + 1 /* include null terminator*/, str_hex.c_str());
// include length of '0x' in the binary string
*quoted_len = unquoted_str_len + 2;
*quoted = reinterpret_cast<char*>( sqlsrv_malloc( *quoted_len, sizeof( char ), 1 ));
unsigned int out_current = 0;
// insert '0x'
( *quoted )[out_current++] = '0';
( *quoted )[out_current++] = 'x';
for ( size_t index = 0; index < unquoted_str_len && unquoted_str[index] != '\0'; ++index ) {
( *quoted )[out_current++] = unquoted_str[index];
}
// null terminator
( *quoted )[out_current] = '\0';
sqlsrv_free( unquoted_str );
return 1;
}
else {
// count the number of quotes needed
unsigned int quotes_needed = 2; // the initial start and end quotes of course
// include the N proceeding the initial quote if encoding is UTF8
if ( encoding == SQLSRV_ENCODING_UTF8 ) {
quotes_needed = 3;
}

// insert initial quote
(*quoted)[ out_current++ ] ='\'';
for ( size_t index = 0; index < unquoted_len && unquoted[index] != '\0'; ++index ) {
if ( unquoted[index] == '\'' ) {
++quotes_needed;
}
}

for(size_t index = 0; index < unquoted_len && unquoted[ index ] != '\0'; ++index ) {
*quoted_len = unquoted_len + quotes_needed; // length returned to the caller should not account for null terminator.
*quoted = reinterpret_cast<char*>( sqlsrv_malloc( *quoted_len, sizeof( char ), 1 )); // include space for null terminator.
unsigned int out_current = 0;

if( unquoted[ index ] == '\'' ) {
(*quoted)[ out_current++ ] = '\'';
(*quoted)[ out_current++ ] = '\'';
}
else {
(*quoted)[ out_current++ ] = unquoted[ index ];
}
}
// insert N if the encoding is UTF8
if ( encoding == SQLSRV_ENCODING_UTF8 ) {
( *quoted )[out_current++] = 'N';
}
// insert initial quote
( *quoted )[out_current++] = '\'';

for ( size_t index = 0; index < unquoted_len && unquoted[index] != '\0'; ++index ) {

if ( unquoted[index] == '\'' ) {
( *quoted )[out_current++] = '\'';
( *quoted )[out_current++] = '\'';
}
else {
( *quoted )[out_current++] = unquoted[index];
}
}

// trailing quote and null terminator
(*quoted)[ out_current++ ] ='\'';
(*quoted)[ out_current ] = '\0';
// trailing quote and null terminator
( *quoted )[out_current++] = '\'';
( *quoted )[out_current] = '\0';

return 1;
return 1;
}
}

// This method is not implemented by this driver.
Expand Down Expand Up @@ -1283,6 +1337,9 @@ void add_stmt_option_key( sqlsrv_context& ctx, size_t key, HashTable* options_ht
option_key = PDO_STMT_OPTION_EMULATE_PREPARES;
break;

case SQLSRV_ATTR_FETCHES_NUMERIC_TYPE:
option_key = PDO_STMT_OPTION_FETCHES_NUMERIC_TYPE;

default:
CHECK_CUSTOM_ERROR( true, ctx, PDO_SQLSRV_ERROR_INVALID_STMT_OPTION ) {
throw core::CoreException();
Expand Down
17 changes: 9 additions & 8 deletions pdo_sqlsrv/pdo_init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -372,14 +372,15 @@ namespace {
}

// array of pdo constants.
sqlsrv_attr_pdo_constant pdo_attr_constants[] = {

// driver specific attributes
{ "SQLSRV_ATTR_ENCODING" , SQLSRV_ATTR_ENCODING },
{ "SQLSRV_ATTR_QUERY_TIMEOUT" , SQLSRV_ATTR_QUERY_TIMEOUT },
{ "SQLSRV_ATTR_DIRECT_QUERY" , SQLSRV_ATTR_DIRECT_QUERY },
{ "SQLSRV_ATTR_CURSOR_SCROLL_TYPE" , SQLSRV_ATTR_CURSOR_SCROLL_TYPE },
{ "SQLSRV_ATTR_CLIENT_BUFFER_MAX_KB_SIZE", SQLSRV_ATTR_CLIENT_BUFFER_MAX_KB_SIZE },
sqlsrv_attr_pdo_constant pdo_attr_constants[] = {

// driver specific attributes
{ "SQLSRV_ATTR_ENCODING" , SQLSRV_ATTR_ENCODING },
{ "SQLSRV_ATTR_QUERY_TIMEOUT" , SQLSRV_ATTR_QUERY_TIMEOUT },
{ "SQLSRV_ATTR_DIRECT_QUERY" , SQLSRV_ATTR_DIRECT_QUERY },
{ "SQLSRV_ATTR_CURSOR_SCROLL_TYPE" , SQLSRV_ATTR_CURSOR_SCROLL_TYPE },
{ "SQLSRV_ATTR_CLIENT_BUFFER_MAX_KB_SIZE", SQLSRV_ATTR_CLIENT_BUFFER_MAX_KB_SIZE },
{ "SQLSRV_ATTR_FETCHES_NUMERIC_TYPE", SQLSRV_ATTR_FETCHES_NUMERIC_TYPE },

// used for the size for output parameters: PDO::PARAM_INT and PDO::PARAM_BOOL use the default size of int,
// PDO::PARAM_STR uses the size of the string in the variable
Expand Down
Loading

0 comments on commit 458b785

Please sign in to comment.