Skip to content

Commit a3456cd

Browse files
Merge pull request #972 from david-puglielli/redundant-apis
Fix for redundant calls to SQLNumResultCols and SQLRowCount
2 parents fd24a97 + ad1d990 commit a3456cd

File tree

6 files changed

+79
-17
lines changed

6 files changed

+79
-17
lines changed

source/pdo_sqlsrv/pdo_stmt.cpp

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -593,12 +593,26 @@ int pdo_sqlsrv_stmt_execute( _Inout_ pdo_stmt_t *stmt TSRMLS_DC )
593593
if ( execReturn == SQL_NO_DATA ) {
594594
stmt->column_count = 0;
595595
stmt->row_count = 0;
596+
driver_stmt->column_count = 0;
597+
driver_stmt->row_count = 0;
596598
}
597599
else {
598-
stmt->column_count = core::SQLNumResultCols( driver_stmt TSRMLS_CC );
600+
if (driver_stmt->column_count == ACTIVE_NUM_COLS_INVALID) {
601+
stmt->column_count = core::SQLNumResultCols( driver_stmt TSRMLS_CC );
602+
driver_stmt->column_count = stmt->column_count;
603+
}
604+
else {
605+
stmt->column_count = driver_stmt->column_count;
606+
}
599607

600-
// return the row count regardless if there are any rows or not
601-
stmt->row_count = core::SQLRowCount( driver_stmt TSRMLS_CC );
608+
if (driver_stmt->row_count == ACTIVE_NUM_ROWS_INVALID) {
609+
// return the row count regardless if there are any rows or not
610+
stmt->row_count = core::SQLRowCount( driver_stmt TSRMLS_CC );
611+
driver_stmt->row_count = stmt->row_count;
612+
}
613+
else {
614+
stmt->row_count = driver_stmt->row_count;
615+
}
602616
}
603617

604618
// workaround for a bug in the PDO driver manager. It is fairly simple to crash the PDO driver manager with
@@ -692,11 +706,16 @@ int pdo_sqlsrv_stmt_fetch( _Inout_ pdo_stmt_t *stmt, _In_ enum pdo_fetch_orienta
692706
SQLSMALLINT odbc_fetch_ori = pdo_fetch_ori_to_odbc_fetch_ori( ori );
693707
bool data = core_sqlsrv_fetch( driver_stmt, odbc_fetch_ori, offset TSRMLS_CC );
694708

695-
// support for the PDO rowCount method. Since rowCount doesn't call a method, PDO relies on us to fill the
696-
// pdo_stmt_t::row_count member
697-
if( driver_stmt->past_fetch_end || driver_stmt->cursor_type != SQL_CURSOR_FORWARD_ONLY ) {
709+
// support for the PDO rowCount method. Since rowCount doesn't call a
710+
// method, PDO relies on us to fill the pdo_stmt_t::row_count member
711+
// The if condition was changed from
712+
// `driver_stmt->past_fetch_end || driver_stmt->cursor_type != SQL_CURSOR_FORWARD_ONLY`
713+
// because it caused SQLRowCount to be called at each fetch if using a non-forward cursor
714+
// which is unnecessary and a performance hit
715+
if( driver_stmt->past_fetch_end || driver_stmt->cursor_type == SQL_CURSOR_DYNAMIC) {
698716

699717
stmt->row_count = core::SQLRowCount( driver_stmt TSRMLS_CC );
718+
driver_stmt->row_count = stmt->row_count;
700719

701720
// a row_count of -1 means no rows, but we change it to 0
702721
if( stmt->row_count == -1 ) {
@@ -1146,6 +1165,9 @@ int pdo_sqlsrv_stmt_next_rowset( _Inout_ pdo_stmt_t *stmt TSRMLS_DC )
11461165

11471166
// return the row count regardless if there are any rows or not
11481167
stmt->row_count = core::SQLRowCount( driver_stmt TSRMLS_CC );
1168+
1169+
driver_stmt->column_count = stmt->column_count;
1170+
driver_stmt->row_count = stmt->row_count;
11491171
}
11501172
catch( core::CoreException& ) {
11511173

source/shared/core_sqlsrv.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,11 @@ const int SQL_MAX_ERROR_MESSAGE_LENGTH = SQL_MAX_MESSAGE_LENGTH * 2;
182182
// max size of a date time string when converting from a DateTime object to a string
183183
const int MAX_DATETIME_STRING_LEN = 256;
184184

185+
// identifier for whether or not we have obtained the number of rows and columns
186+
// of a result
187+
const short ACTIVE_NUM_COLS_INVALID = -99;
188+
const long ACTIVE_NUM_ROWS_INVALID = -99;
189+
185190
// precision and scale for the date time types between servers
186191
const int SQL_SERVER_2005_DEFAULT_DATETIME_PRECISION = 23;
187192
const int SQL_SERVER_2005_DEFAULT_DATETIME_SCALE = 3;
@@ -1438,8 +1443,9 @@ struct sqlsrv_stmt : public sqlsrv_context {
14381443
bool has_rows; // Has_rows is set if there are actual rows in the row set
14391444
bool fetch_called; // Used by core_sqlsrv_get_field to return an informative error if fetch not yet called
14401445
int last_field_index; // last field retrieved by core_sqlsrv_get_field
1441-
bool past_next_result_end; // core_sqlsrv_next_result sets this to true when the statement goes beyond the
1442-
// last results
1446+
bool past_next_result_end; // core_sqlsrv_next_result sets this to true when the statement goes beyond the last results
1447+
short column_count; // Number of columns in the current result set obtained from SQLNumResultCols
1448+
long row_count; // Number of rows in the current result set obtained from SQLRowCount
14431449
unsigned long query_timeout; // maximum allowed statement execution time
14441450
zend_long buffered_query_limit; // maximum allowed memory for a buffered query (measured in KB)
14451451
bool date_as_string; // false by default but the user can set this to true to retrieve datetime values as strings

source/shared/core_stmt.cpp

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ sqlsrv_stmt::sqlsrv_stmt( _In_ sqlsrv_conn* c, _In_ SQLHANDLE handle, _In_ error
140140
fetch_called( false ),
141141
last_field_index( -1 ),
142142
past_next_result_end( false ),
143+
column_count( ACTIVE_NUM_COLS_INVALID ),
144+
row_count( ACTIVE_NUM_ROWS_INVALID ),
143145
query_timeout( QUERY_TIMEOUT_INVALID ),
144146
date_as_string(false),
145147
format_decimals(false), // no formatting needed
@@ -225,6 +227,8 @@ void sqlsrv_stmt::new_result_set( TSRMLS_D )
225227
this->past_next_result_end = false;
226228
this->past_fetch_end = false;
227229
this->last_field_index = -1;
230+
this->column_count = ACTIVE_NUM_COLS_INVALID;
231+
this->row_count = ACTIVE_NUM_ROWS_INVALID;
228232

229233
// delete any current results
230234
if( current_results ) {
@@ -819,9 +823,17 @@ bool core_sqlsrv_fetch( _Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT fetch_orient
819823
CHECK_CUSTOM_ERROR( stmt->past_fetch_end, stmt, SQLSRV_ERROR_FETCH_PAST_END ) {
820824
throw core::CoreException();
821825
}
826+
822827
// First time only
823828
if ( !stmt->fetch_called ) {
824-
SQLSMALLINT has_fields = core::SQLNumResultCols( stmt TSRMLS_CC );
829+
SQLSMALLINT has_fields;
830+
if (stmt->column_count != ACTIVE_NUM_COLS_INVALID) {
831+
has_fields = stmt->column_count;
832+
} else {
833+
has_fields = core::SQLNumResultCols( stmt TSRMLS_CC );
834+
stmt->column_count = has_fields;
835+
}
836+
825837
CHECK_CUSTOM_ERROR( has_fields == 0, stmt, SQLSRV_ERROR_NO_FIELDS ) {
826838
throw core::CoreException();
827839
}
@@ -1066,10 +1078,27 @@ void core_sqlsrv_get_field( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_i
10661078

10671079
bool core_sqlsrv_has_any_result( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC )
10681080
{
1069-
// Use SQLNumResultCols to determine if we have rows or not.
1070-
SQLSMALLINT num_cols = core::SQLNumResultCols( stmt TSRMLS_CC );
1071-
// use SQLRowCount to determine if there is a rows status waiting
1072-
SQLLEN rows_affected = core::SQLRowCount( stmt TSRMLS_CC );
1081+
SQLSMALLINT num_cols;
1082+
SQLLEN rows_affected;
1083+
1084+
if (stmt->column_count != ACTIVE_NUM_COLS_INVALID) {
1085+
num_cols = stmt->column_count;
1086+
}
1087+
else {
1088+
// Use SQLNumResultCols to determine if we have rows or not
1089+
num_cols = core::SQLNumResultCols( stmt TSRMLS_CC );
1090+
stmt->column_count = num_cols;
1091+
}
1092+
1093+
if (stmt->row_count != ACTIVE_NUM_ROWS_INVALID) {
1094+
rows_affected = stmt->row_count;
1095+
}
1096+
else {
1097+
// Use SQLRowCount to determine if there is a rows status waiting
1098+
rows_affected = core::SQLRowCount( stmt TSRMLS_CC );
1099+
stmt->row_count = rows_affected;
1100+
}
1101+
10731102
return (num_cols != 0) || (rows_affected > 0);
10741103
}
10751104

source/sqlsrv/stmt.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1791,7 +1791,12 @@ SQLSMALLINT get_resultset_meta_data(_Inout_ sqlsrv_stmt * stmt)
17911791

17921792
if (num_cols == 0) {
17931793
getMetaData = true;
1794-
num_cols = core::SQLNumResultCols(stmt TSRMLS_CC);
1794+
if (stmt->column_count == ACTIVE_NUM_COLS_INVALID) {
1795+
num_cols = core::SQLNumResultCols(stmt TSRMLS_CC);
1796+
stmt->column_count = num_cols;
1797+
} else {
1798+
num_cols = stmt->column_count;
1799+
}
17951800
}
17961801

17971802
try {

source/sqlsrv/util.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,8 +205,8 @@ ss_error SS_ERRORS[] = {
205205
},
206206

207207
{
208-
SS_SQLSRV_ERROR_ZEND_OBJECT_FAILED,
209-
{ IMSSP, (SQLCHAR*)"Failed to create an instance of class %1!s!.", -30, true }
208+
SS_SQLSRV_ERROR_ZEND_OBJECT_FAILED,
209+
{ IMSSP, (SQLCHAR*)"Failed to create an instance of class %1!s!.", -30, true }
210210
},
211211

212212
{

test/functional/sqlsrv/sqlsrv_empty_result_error.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ echo "Null result set, call next result first: #############################\n";
153153

154154
$stmt = sqlsrv_query($conn, "TestEmptySetProc @a='a', @b='c'");
155155
NextResult($stmt, []);
156-
Fetch($stmt, [$errorFuncSeq()]);
156+
Fetch($stmt, [$errorNoFields]);
157157

158158
// Call next_result twice in succession on a null result set
159159
echo "Null result set, call next result twice: #############################\n";

0 commit comments

Comments
 (0)