Dropped the use of LOCK TIMEOUT (#1165)

This commit is contained in:
Jenny Tam 2020-07-23 16:07:41 -07:00 committed by GitHub
parent 460d9aa2df
commit e1e0108b1f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 90 additions and 44 deletions

View file

@ -1523,12 +1523,3 @@ sqlsrv_phptype pdo_sqlsrv_stmt::sql_type_to_php_type( _In_ SQLINTEGER sql_type,
return sqlsrv_phptype;
}
void pdo_sqlsrv_stmt::set_query_timeout()
{
if (query_timeout == QUERY_TIMEOUT_INVALID || query_timeout < 0) {
return;
}
core::SQLSetStmtAttr(this, SQL_ATTR_QUERY_TIMEOUT, reinterpret_cast<SQLPOINTER>((SQLLEN)query_timeout), SQL_IS_UINTEGER);
}

View file

@ -260,9 +260,6 @@ struct pdo_sqlsrv_stmt : public sqlsrv_stmt {
// for PDO, everything is a string, so we return SQLSRV_PHPTYPE_STRING for all SQL types
virtual sqlsrv_phptype sql_type_to_php_type( _In_ SQLINTEGER sql_type, _In_ SQLUINTEGER size, _In_ bool prefer_string_to_stream );
// driver specific way to set query timeout
virtual void set_query_timeout();
bool direct_query; // flag set if the query should be executed directly or prepared
const char* direct_query_subst_string; // if the query is direct, hold the substitution string if using named parameters
size_t direct_query_subst_string_len; // length of query string used for direct queries

View file

@ -1520,6 +1520,8 @@ struct sqlsrv_stmt : public sqlsrv_context {
// free sensitivity classification metadata
void clean_up_sensitivity_metadata();
// set query timeout
void set_query_timeout();
sqlsrv_conn* conn; // Connection that created this statement
@ -1571,8 +1573,6 @@ struct sqlsrv_stmt : public sqlsrv_context {
// 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( _In_ SQLINTEGER sql_type, _In_ SQLUINTEGER size, _In_ bool prefer_string_to_stream ) = 0;
// driver specific way to set query timeout
virtual void set_query_timeout() = 0;
};
// *** field metadata struct ***

View file

@ -275,6 +275,15 @@ void sqlsrv_stmt::clean_up_sensitivity_metadata()
}
}
void sqlsrv_stmt::set_query_timeout()
{
if (query_timeout == QUERY_TIMEOUT_INVALID || query_timeout < 0) {
return;
}
core::SQLSetStmtAttr(this, SQL_ATTR_QUERY_TIMEOUT, reinterpret_cast<SQLPOINTER>((SQLLEN)query_timeout), SQL_IS_UINTEGER);
}
// core_sqlsrv_create_stmt
// Common code to allocate a statement from either driver. Returns a valid driver statement object or
// throws an exception if an error occurs.

View file

@ -130,9 +130,6 @@ struct ss_sqlsrv_stmt : public sqlsrv_stmt {
// driver specific conversion rules from a SQL Server/ODBC type to one of the SQLSRV_PHPTYPE_* constants
sqlsrv_phptype sql_type_to_php_type( _In_ SQLINTEGER sql_type, _In_ SQLUINTEGER size, _In_ bool prefer_string_to_stream );
// driver specific way to set query timeout
virtual void set_query_timeout();
bool prepared; // whether the statement has been prepared yet (used for error messages)
zend_ulong conn_index; // index into the connection hash that contains this statement structure
zval* params_z; // hold parameters passed to sqlsrv_prepare but not used until sqlsrv_execute

View file

@ -261,29 +261,6 @@ sqlsrv_phptype ss_sqlsrv_stmt::sql_type_to_php_type( _In_ SQLINTEGER sql_type, _
return ss_phptype;
}
void ss_sqlsrv_stmt::set_query_timeout()
{
if (query_timeout == QUERY_TIMEOUT_INVALID || query_timeout < 0) {
return;
}
// set the statement attribute
core::SQLSetStmtAttr(this, SQL_ATTR_QUERY_TIMEOUT, reinterpret_cast<SQLPOINTER>( (SQLLEN)query_timeout ), SQL_IS_UINTEGER );
// a query timeout of 0 indicates "no timeout", which means that lock_timeout should also be set to "no timeout" which
// is represented by -1.
int lock_timeout = (( query_timeout == 0 ) ? -1 : query_timeout * 1000 /*convert to milliseconds*/ );
// set the LOCK_TIMEOUT on the server.
char lock_timeout_sql[32] = {'\0'};
int written = snprintf( lock_timeout_sql, sizeof( lock_timeout_sql ), "SET LOCK_TIMEOUT %d", lock_timeout );
SQLSRV_ASSERT( (written != -1 && written != sizeof( lock_timeout_sql )),
"stmt_option_query_timeout: snprintf failed. Shouldn't ever fail." );
core::SQLExecDirect(this, lock_timeout_sql );
}
// statement specific parameter proccessing. Uses the generic function specialised to return a statement
// resource.
#define PROCESS_PARAMS( rsrc, param_spec, calling_func, param_count, ... ) \

View file

@ -0,0 +1,72 @@
--TEST--
GitHub issue 1100 - PDO::SQLSRV_ATTR_QUERY_TIMEOUT had no effect when reconnecting
--DESCRIPTION--
This test verifies that setting PDO::SQLSRV_ATTR_QUERY_TIMEOUT should work when reconnecting after disconnecting
--ENV--
PHPT_EXEC=true
--SKIPIF--
<?php require('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
require_once("MsSetup.inc");
require_once("MsCommon_mid-refactor.inc");
function checkTimeElapsed($t0, $t1, $expectedDelay)
{
$elapsed = $t1 - $t0;
$diff = abs($elapsed - $expectedDelay);
$leeway = 1.0;
$missed = ($diff > $leeway);
trace("$elapsed secs elapsed\n");
if ($missed) {
echo "Expected $expectedDelay but $elapsed secs elapsed\n";
}
}
function testTimeout($conn, $timeout)
{
$delay = 5;
$query = "WAITFOR DELAY '00:00:$delay'; SELECT 1";
$error = '*Query timeout expired';
$t0 = microtime(true);
try {
$conn->exec($query);
$elapsed = microtime(true) - $t0;
echo "Should have failed after $timeout secs but $elapsed secs have elapsed" . PHP_EOL;
} catch (PDOException $e) {
$t1 = microtime(true);
$message = '*Query timeout expired';
if (!fnmatch($message, $e->getMessage())) {
var_dump($e->getMessage());
}
checkTimeElapsed($t0, $t1, $timeout);
}
}
try {
$keywords = 'MultipleActiveResultSets=false;';
$timeout = 1;
$options = array(PDO::SQLSRV_ATTR_QUERY_TIMEOUT => $timeout);
$conn = connect($keywords, $options);
testTimeout($conn, $timeout);
unset($conn);
$conn = connect($keywords);
$conn->setAttribute(PDO::SQLSRV_ATTR_QUERY_TIMEOUT, $timeout);
testTimeout($conn, $timeout);
unset($conn);
echo "Done\n";
} catch (PdoException $e) {
echo $e->getMessage() . PHP_EOL;
}
?>
--EXPECT--
Done

View file

@ -10,19 +10,23 @@ sqlsrv_configure( 'LogSeverity', SQLSRV_LOG_SEVERITY_ALL );
require( 'MsCommon.inc' );
$throwaway = Connect(array( 'ConnectionPooling' => 1 ));
// MARS allows applications to have more than one pending request per connection and to have more
// than one active default result set per connection, which is not required for this test.
$options = array('ConnectionPooling' => 1, 'MultipleActiveResultSets' => 0);
$throwaway = Connect();
if( !$throwaway ) {
die( print_r( sqlsrv_errors(), true ));
}
for( $i = 1; $i <= 3; ++$i ) {
$conn = Connect(array( 'ConnectionPooling' => 1 ));
$conn = Connect($options);
if( !$conn ) {
die( print_r( sqlsrv_errors(), true ));
}
$conn2 = Connect(array( 'ConnectionPooling' => 1 ));
$conn2 = Connect($options);
if( !$conn2 ) {
die( print_r( sqlsrv_errors(), true ));
}
@ -47,7 +51,6 @@ for( $i = 1; $i <= 3; ++$i ) {
die( print_r( sqlsrv_errors(), true ));
}
$stmt2 = sqlsrv_query( $conn2, "WAITFOR DELAY '00:00:05'; SELECT * FROM [test_query_timeout]", array(null), array( 'QueryTimeout' => 1 ));
if( $stmt2 === false ) {
print_r( sqlsrv_errors() );