commit
55d0461bf6
|
@ -25,6 +25,10 @@ script:
|
|||
- docker ps -a
|
||||
- docker exec client php ./source/pdo_sqlsrv/run-tests.php ./test/pdo_sqlsrv/*.phpt
|
||||
- docker exec client php ./source/sqlsrv/run-tests.php ./test/sqlsrv/*.phpt
|
||||
- docker exec client bash -c 'for f in ./test/sqlsrv/*.diff; do ls $f 2>/dev/null; cat $f 2>/dev/null; done || true'
|
||||
- docker exec client bash -c 'for f in ./test/sqlsrv/*.out; do ls $f 2>/dev/null; cat $f 2>/dev/null; done || true'
|
||||
- docker exec client bash -c 'for f in ./test/pdo_sqlsrv/*.diff; do ls $f 2>/dev/null; cat $f 2>/dev/null; done || true'
|
||||
- docker exec client bash -c 'for f in ./test/pdo_sqlsrv/*.out; do ls $f 2>/dev/null; cat $f 2>/dev/null; done || true'
|
||||
- docker exec client coveralls -e ./source/shared/ --gcov-options '\-lp'
|
||||
- docker stop client
|
||||
- docker ps -a
|
||||
|
|
|
@ -182,3 +182,4 @@ after_test:
|
|||
$host.SetShouldExit(1);
|
||||
Write-Host "Forcing build failure due to phpt unit test failure(s)";
|
||||
}
|
||||
|
||||
|
|
|
@ -1308,6 +1308,7 @@ struct sqlsrv_stmt : public sqlsrv_context {
|
|||
unsigned int current_stream_read; // # of bytes read so far. (if we read an empty PHP stream, we send an empty string
|
||||
// to the server)
|
||||
zval field_cache; // cache for a single row of fields, to allow multiple and out of order retrievals
|
||||
zval col_cache; // Used by get_field_as_string not to call SQLColAttribute() after every fetch.
|
||||
zval active_stream; // the currently active stream reading data from the database
|
||||
|
||||
sqlsrv_stmt( sqlsrv_conn* c, SQLHANDLE handle, error_callback e, void* drv TSRMLS_DC );
|
||||
|
|
|
@ -48,6 +48,18 @@ struct field_cache {
|
|||
// rely on the hash table destructor to free the memory
|
||||
};
|
||||
|
||||
// Used to cache display size and SQL type of a column in get_field_as_string()
|
||||
struct col_cache {
|
||||
SQLLEN sql_type;
|
||||
SQLLEN display_size;
|
||||
|
||||
col_cache( SQLLEN col_sql_type, SQLLEN col_display_size )
|
||||
{
|
||||
sql_type = col_sql_type;
|
||||
display_size = col_display_size;
|
||||
}
|
||||
};
|
||||
|
||||
const int INITIAL_FIELD_STRING_LEN = 256; // base allocation size when retrieving a string field
|
||||
|
||||
// UTF-8 tags for byte length of characters, used by streams to make sure we don't clip a character in between reads
|
||||
|
@ -89,6 +101,7 @@ void default_sql_size_and_scale( sqlsrv_stmt* stmt, unsigned int paramno, zval*
|
|||
// given a zval and encoding, determine the appropriate sql type, column size, and decimal scale (if appropriate)
|
||||
void default_sql_type( sqlsrv_stmt* stmt, SQLULEN paramno, zval* param_z, SQLSRV_ENCODING encoding,
|
||||
_Out_ SQLSMALLINT& sql_type TSRMLS_DC );
|
||||
void col_cache_dtor( zval* data_z );
|
||||
void field_cache_dtor( zval* data_z );
|
||||
void finalize_output_parameters( sqlsrv_stmt* stmt TSRMLS_DC );
|
||||
void get_field_as_string( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_phptype sqlsrv_php_type,
|
||||
|
@ -144,6 +157,10 @@ sqlsrv_stmt::sqlsrv_stmt( sqlsrv_conn* c, SQLHANDLE handle, error_callback e, vo
|
|||
ZVAL_NEW_ARR( &output_params );
|
||||
core::sqlsrv_zend_hash_init(*conn, Z_ARRVAL( output_params ), 5 /* # of buckets */, sqlsrv_output_param_dtor, 0 /*persistent*/ TSRMLS_CC);
|
||||
|
||||
// initialize the col cache
|
||||
ZVAL_NEW_ARR( &col_cache );
|
||||
core::sqlsrv_zend_hash_init( *conn, Z_ARRVAL(col_cache), 5 /* # of buckets */, col_cache_dtor, 0 /*persistent*/ TSRMLS_CC );
|
||||
|
||||
// initialize the field cache
|
||||
ZVAL_NEW_ARR( &field_cache );
|
||||
core::sqlsrv_zend_hash_init(*conn, Z_ARRVAL(field_cache), 5 /* # of buckets */, field_cache_dtor, 0 /*persistent*/ TSRMLS_CC);
|
||||
|
@ -169,6 +186,7 @@ sqlsrv_stmt::~sqlsrv_stmt( void )
|
|||
zval_ptr_dtor( &output_params );
|
||||
zval_ptr_dtor( ¶m_streams );
|
||||
zval_ptr_dtor( ¶m_datetime_buffers );
|
||||
zval_ptr_dtor( &col_cache );
|
||||
zval_ptr_dtor( &field_cache );
|
||||
}
|
||||
|
||||
|
@ -184,6 +202,7 @@ void sqlsrv_stmt::free_param_data( TSRMLS_D )
|
|||
zend_hash_clean( Z_ARRVAL( output_params ));
|
||||
zend_hash_clean( Z_ARRVAL( param_streams ));
|
||||
zend_hash_clean( Z_ARRVAL( param_datetime_buffers ));
|
||||
zend_hash_clean( Z_ARRVAL( col_cache ));
|
||||
zend_hash_clean( Z_ARRVAL( field_cache ));
|
||||
}
|
||||
|
||||
|
@ -755,12 +774,13 @@ bool core_sqlsrv_fetch( sqlsrv_stmt* stmt, SQLSMALLINT fetch_orientation, SQLULE
|
|||
CHECK_CUSTOM_ERROR( stmt->past_fetch_end, stmt, SQLSRV_ERROR_FETCH_PAST_END ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
// First time only
|
||||
if ( !stmt->fetch_called ) {
|
||||
SQLSMALLINT has_fields = core::SQLNumResultCols( stmt TSRMLS_CC );
|
||||
|
||||
CHECK_CUSTOM_ERROR( has_fields == 0, stmt, SQLSRV_ERROR_NO_FIELDS ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
}
|
||||
|
||||
// close the stream to release the resource
|
||||
close_active_stream( stmt TSRMLS_CC );
|
||||
|
@ -1014,6 +1034,9 @@ void core_sqlsrv_next_result( sqlsrv_stmt* stmt TSRMLS_DC, bool finalize_output_
|
|||
|
||||
close_active_stream( stmt TSRMLS_CC );
|
||||
|
||||
//Clear column sql types and sql display sizes.
|
||||
zend_hash_clean( Z_ARRVAL( stmt->col_cache ));
|
||||
|
||||
SQLRETURN r;
|
||||
if( throw_on_errors ) {
|
||||
r = core::SQLMoreResults( stmt TSRMLS_CC );
|
||||
|
@ -1971,6 +1994,12 @@ void default_sql_size_and_scale( sqlsrv_stmt* stmt, unsigned int paramno, zval*
|
|||
}
|
||||
}
|
||||
|
||||
void col_cache_dtor( zval* data_z )
|
||||
{
|
||||
col_cache* cache = static_cast<col_cache*>( Z_PTR_P( data_z ));
|
||||
sqlsrv_free( cache );
|
||||
}
|
||||
|
||||
void field_cache_dtor( zval* data_z )
|
||||
{
|
||||
field_cache* cache = static_cast<field_cache*>( Z_PTR_P( data_z ));
|
||||
|
@ -2132,12 +2161,23 @@ void get_field_as_string( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_ph
|
|||
break;
|
||||
}
|
||||
|
||||
col_cache* cached = NULL;
|
||||
if ( NULL != ( cached = static_cast< col_cache* >( zend_hash_index_find_ptr( Z_ARRVAL( stmt->col_cache ), static_cast< zend_ulong >( field_index ))))) {
|
||||
sql_field_type = cached->sql_type;
|
||||
sql_display_size = cached->display_size;
|
||||
}
|
||||
else {
|
||||
// Get the SQL type of the field. unixODBC 2.3.1 requires wide calls to support pooling
|
||||
core::SQLColAttributeW( stmt, field_index + 1, SQL_DESC_CONCISE_TYPE, NULL, 0, NULL, &sql_field_type TSRMLS_CC );
|
||||
|
||||
// Calculate the field size.
|
||||
calc_string_size( stmt, field_index, sql_field_type, sql_display_size TSRMLS_CC );
|
||||
|
||||
col_cache cache( sql_field_type, sql_display_size );
|
||||
core::sqlsrv_zend_hash_index_update_mem( *stmt, Z_ARRVAL( stmt->col_cache ), field_index, &cache, sizeof( col_cache ) TSRMLS_CC );
|
||||
}
|
||||
|
||||
|
||||
// if this is a large type, then read the first few bytes to get the actual length from SQLGetData
|
||||
if( sql_display_size == 0 || sql_display_size == INT_MAX ||
|
||||
sql_display_size == INT_MAX >> 1 || sql_display_size == UINT_MAX - 1 ) {
|
||||
|
|
|
@ -97,9 +97,9 @@ Repro();
|
|||
--EXPECTREGEX--
|
||||
|
||||
...Starting 'sqlsrv_statement_cancel' test...
|
||||
\[Microsoft\](\[ODBC Driver 13 for SQL Server\]|\[ODBC Driver Manager\])( Function sequence error|Associated statement is not prepared)
|
||||
\[Microsoft\](\[ODBC Driver 13 for SQL Server\]|\[ODBC Driver Manager\])([ ]{0,1}Function sequence error)
|
||||
0
|
||||
(HY010|HY007)
|
||||
(HY010)
|
||||
|
||||
Done
|
||||
...Test 'sqlsrv_statement_cancel' completed successfully.
|
||||
|
|
Loading…
Reference in a new issue