Skip to content

Commit b523306

Browse files
authored
Save meta data for the fetched result set (#855)
* Save meta data on fetched result sets * Fixed a compilation error * Optimized some more -- metadata should be available when fetching * Skip conversion for strings of numeric values, integers, floats, decimals etc * Set encoding char for numeric data * Apply review
1 parent a4eb46c commit b523306

File tree

5 files changed

+148
-87
lines changed

5 files changed

+148
-87
lines changed

source/pdo_sqlsrv/pdo_stmt.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1377,6 +1377,7 @@ sqlsrv_phptype pdo_sqlsrv_stmt::sql_type_to_php_type( _In_ SQLINTEGER sql_type,
13771377
}
13781378
else {
13791379
sqlsrv_phptype.typeinfo.type = SQLSRV_PHPTYPE_STRING;
1380+
sqlsrv_phptype.typeinfo.encoding = SQLSRV_ENCODING_CHAR;
13801381
}
13811382
break;
13821383
case SQL_FLOAT:
@@ -1386,6 +1387,7 @@ sqlsrv_phptype pdo_sqlsrv_stmt::sql_type_to_php_type( _In_ SQLINTEGER sql_type,
13861387
}
13871388
else {
13881389
sqlsrv_phptype.typeinfo.type = SQLSRV_PHPTYPE_STRING;
1390+
sqlsrv_phptype.typeinfo.encoding = SQLSRV_ENCODING_CHAR;
13891391
}
13901392
break;
13911393
case SQL_TYPE_DATE:
@@ -1400,10 +1402,13 @@ sqlsrv_phptype pdo_sqlsrv_stmt::sql_type_to_php_type( _In_ SQLINTEGER sql_type,
14001402
}
14011403
break;
14021404
case SQL_BIGINT:
1403-
case SQL_CHAR:
14041405
case SQL_DECIMAL:
1405-
case SQL_GUID:
14061406
case SQL_NUMERIC:
1407+
sqlsrv_phptype.typeinfo.type = SQLSRV_PHPTYPE_STRING;
1408+
sqlsrv_phptype.typeinfo.encoding = SQLSRV_ENCODING_CHAR;
1409+
break;
1410+
case SQL_CHAR:
1411+
case SQL_GUID:
14071412
case SQL_WCHAR:
14081413
case SQL_VARCHAR:
14091414
case SQL_WVARCHAR:

source/pdo_sqlsrv/php_pdo_sqlsrv.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -279,8 +279,6 @@ struct pdo_sqlsrv_stmt : public sqlsrv_stmt {
279279
size_t direct_query_subst_string_len; // length of query string used for direct queries
280280
HashTable* placeholders; // hashtable of named placeholders to keep track of params ordering in emulate prepare
281281

282-
// meta data for current result set
283-
std::vector<field_meta_data*, sqlsrv_allocator< field_meta_data* > > current_meta_data;
284282
pdo_param_type* bound_column_param_types;
285283
bool fetch_numeric;
286284
bool fetch_datetime;

source/shared/core_sqlsrv.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1365,6 +1365,7 @@ struct sqlsrv_output_param {
13651365

13661366
// forward decls
13671367
struct sqlsrv_result_set;
1368+
struct field_meta_data;
13681369

13691370
// *** parameter metadata struct ***
13701371
struct param_meta_data
@@ -1427,6 +1428,9 @@ struct sqlsrv_stmt : public sqlsrv_context {
14271428

14281429
std::vector<param_meta_data> param_descriptions;
14291430

1431+
// meta data for current result set
1432+
std::vector<field_meta_data*, sqlsrv_allocator<field_meta_data*>> current_meta_data;
1433+
14301434
sqlsrv_stmt( _In_ sqlsrv_conn* c, _In_ SQLHANDLE handle, _In_ error_callback e, _In_opt_ void* drv TSRMLS_DC );
14311435
virtual ~sqlsrv_stmt( void );
14321436

source/shared/core_stmt.cpp

Lines changed: 60 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@ void send_param_streams( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC );
124124
void sqlsrv_output_param_dtor( _Inout_ zval* data );
125125
// called when a bound stream parameter is to be destroyed.
126126
void sqlsrv_stream_dtor( _Inout_ zval* data );
127-
bool is_streamable_type( _In_ SQLINTEGER sql_type );
128127

129128
}
130129

@@ -997,22 +996,24 @@ void core_sqlsrv_get_field( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_i
997996
efree( field_value );
998997
field_value = NULL;
999998
*field_len = 0;
1000-
}
1001-
}
1002-
}
1003-
1004-
// If the php type was not specified set the php type to be the default type.
1005-
if( sqlsrv_php_type.typeinfo.type == SQLSRV_PHPTYPE_INVALID ) {
1006-
1007-
// Get the SQL type of the field.
1008-
core::SQLColAttributeW( stmt, field_index + 1, SQL_DESC_CONCISE_TYPE, NULL, 0, NULL, &sql_field_type TSRMLS_CC );
999+
}
1000+
}
1001+
}
10091002

1010-
// Get the length of the field.
1011-
core::SQLColAttributeW( stmt, field_index + 1, SQL_DESC_LENGTH, NULL, 0, NULL, &sql_field_len TSRMLS_CC );
1003+
// If the php type was not specified set the php type to be the default type.
1004+
if (sqlsrv_php_type.typeinfo.type == SQLSRV_PHPTYPE_INVALID) {
1005+
SQLSRV_ASSERT(stmt->current_meta_data.size() > field_index, "core_sqlsrv_get_field - meta data vector not in sync" );
1006+
sql_field_type = stmt->current_meta_data[field_index]->field_type;
1007+
if (stmt->current_meta_data[field_index]->field_precision > 0) {
1008+
sql_field_len = stmt->current_meta_data[field_index]->field_precision;
1009+
}
1010+
else {
1011+
sql_field_len = stmt->current_meta_data[field_index]->field_size;
1012+
}
10121013

1013-
// Get the corresponding php type from the sql type.
1014-
sqlsrv_php_type = stmt->sql_type_to_php_type( static_cast<SQLINTEGER>( sql_field_type ), static_cast<SQLUINTEGER>( sql_field_len ), prefer_string );
1015-
}
1014+
// Get the corresponding php type from the sql type.
1015+
sqlsrv_php_type = stmt->sql_type_to_php_type(static_cast<SQLINTEGER>(sql_field_type), static_cast<SQLUINTEGER>(sql_field_len), prefer_string);
1016+
}
10161017

10171018
// Verify that we have an acceptable type to convert.
10181019
CHECK_CUSTOM_ERROR( !is_valid_sqlsrv_phptype( sqlsrv_php_type ), stmt, SQLSRV_ERROR_INVALID_TYPE ) {
@@ -1441,7 +1442,7 @@ void close_active_stream( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC )
14411442

14421443
namespace {
14431444

1444-
bool is_streamable_type( _In_ SQLLEN sql_type )
1445+
bool is_streamable_type( _In_ SQLSMALLINT sql_type )
14451446
{
14461447
switch( sql_type ) {
14471448
case SQL_CHAR:
@@ -1460,6 +1461,25 @@ bool is_streamable_type( _In_ SQLLEN sql_type )
14601461
return false;
14611462
}
14621463

1464+
bool is_a_numeric_type(_In_ SQLSMALLINT sql_type)
1465+
{
1466+
switch (sql_type) {
1467+
case SQL_BIGINT:
1468+
case SQL_BIT:
1469+
case SQL_INTEGER:
1470+
case SQL_SMALLINT:
1471+
case SQL_TINYINT:
1472+
case SQL_FLOAT:
1473+
case SQL_DOUBLE:
1474+
case SQL_REAL:
1475+
case SQL_DECIMAL:
1476+
case SQL_NUMERIC:
1477+
return true;
1478+
}
1479+
1480+
return false;
1481+
}
1482+
14631483
void calc_string_size( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_index, _In_ SQLLEN sql_type, _Inout_ SQLLEN& size TSRMLS_DC )
14641484
{
14651485
try {
@@ -1693,12 +1713,10 @@ void core_get_field_common( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_i
16931713
{
16941714
php_stream* stream = NULL;
16951715
sqlsrv_stream* ss = NULL;
1696-
SQLLEN sql_type;
1716+
SQLSMALLINT sql_type;
16971717

1698-
SQLRETURN r = SQLColAttributeW( stmt->handle(), field_index + 1, SQL_DESC_TYPE, NULL, 0, NULL, &sql_type );
1699-
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
1700-
throw core::CoreException();
1701-
}
1718+
SQLSRV_ASSERT(stmt->current_meta_data.size() > field_index, "core_get_field_common - meta data vector not in sync" );
1719+
sql_type = stmt->current_meta_data[field_index]->field_type;
17021720

17031721
CHECK_CUSTOM_ERROR( !is_streamable_type( sql_type ), stmt, SQLSRV_ERROR_STREAMABLE_TYPES_ONLY ) {
17041722
throw core::CoreException();
@@ -2208,9 +2226,30 @@ void get_field_as_string( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_ind
22082226
DEBUG_SQLSRV_ASSERT( sqlsrv_php_type.typeinfo.type == SQLSRV_PHPTYPE_STRING,
22092227
"Type should be SQLSRV_PHPTYPE_STRING in get_field_as_string" );
22102228

2229+
col_cache* cached = NULL;
2230+
if ( NULL != ( cached = static_cast< col_cache* >( zend_hash_index_find_ptr( Z_ARRVAL( stmt->col_cache ), static_cast< zend_ulong >( field_index ))))) {
2231+
sql_field_type = cached->sql_type;
2232+
sql_display_size = cached->display_size;
2233+
}
2234+
else {
2235+
SQLSRV_ASSERT(stmt->current_meta_data.size() > field_index, "get_field_as_string - meta data vector not in sync" );
2236+
sql_field_type = stmt->current_meta_data[field_index]->field_type;
2237+
2238+
// Calculate the field size.
2239+
calc_string_size( stmt, field_index, sql_field_type, sql_display_size TSRMLS_CC );
2240+
2241+
col_cache cache( sql_field_type, sql_display_size );
2242+
core::sqlsrv_zend_hash_index_update_mem( *stmt, Z_ARRVAL( stmt->col_cache ), field_index, &cache, sizeof( col_cache ) TSRMLS_CC );
2243+
}
2244+
2245+
// Determine the correct encoding
22112246
if( sqlsrv_php_type.typeinfo.encoding == SQLSRV_ENCODING_DEFAULT ) {
22122247
sqlsrv_php_type.typeinfo.encoding = stmt->conn->encoding();
22132248
}
2249+
// For numbers, no need to convert
2250+
if (is_a_numeric_type(sql_field_type)) {
2251+
sqlsrv_php_type.typeinfo.encoding = SQLSRV_ENCODING_CHAR;
2252+
}
22142253

22152254
// Set the C type and account for null characters at the end of the data.
22162255
switch( sqlsrv_php_type.typeinfo.encoding ) {
@@ -2228,22 +2267,6 @@ void get_field_as_string( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_ind
22282267
break;
22292268
}
22302269

2231-
col_cache* cached = NULL;
2232-
if ( NULL != ( cached = static_cast< col_cache* >( zend_hash_index_find_ptr( Z_ARRVAL( stmt->col_cache ), static_cast< zend_ulong >( field_index ))))) {
2233-
sql_field_type = cached->sql_type;
2234-
sql_display_size = cached->display_size;
2235-
}
2236-
else {
2237-
// Get the SQL type of the field. unixODBC 2.3.1 requires wide calls to support pooling
2238-
core::SQLColAttributeW( stmt, field_index + 1, SQL_DESC_CONCISE_TYPE, NULL, 0, NULL, &sql_field_type TSRMLS_CC );
2239-
2240-
// Calculate the field size.
2241-
calc_string_size( stmt, field_index, sql_field_type, sql_display_size TSRMLS_CC );
2242-
2243-
col_cache cache( sql_field_type, sql_display_size );
2244-
core::sqlsrv_zend_hash_index_update_mem( *stmt, Z_ARRVAL( stmt->col_cache ), field_index, &cache, sizeof( col_cache ) TSRMLS_CC );
2245-
}
2246-
22472270
// if this is a large type, then read the first few bytes to get the actual length from SQLGetData
22482271
if( sql_display_size == 0 || sql_display_size == INT_MAX ||
22492272
sql_display_size == INT_MAX >> 1 || sql_display_size == UINT_MAX - 1 ) {

0 commit comments

Comments
 (0)