Skip to content

Commit

Permalink
Workaround for a bug in unixODBC 2.3.4 (#334)
Browse files Browse the repository at this point in the history
* Adding a workaround for the error handling issue with unixODBC 2.3.4 when conneciton pooling is enabled

* Adding a check to apply the workaround only to PDO SQLSRV

* Update core_util.cpp

* Unix Conn Pool test

* Modifying the test to use autonomous_setup.php

* Updating path to isPooled.php
  • Loading branch information
ulvii authored Mar 27, 2017
1 parent 6bd361c commit 6809f0f
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 0 deletions.
11 changes: 11 additions & 0 deletions source/shared/core_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,17 @@ bool core_sqlsrv_get_odbc_error( sqlsrv_context& ctx, int record_number, sqlsrv_
r = SQLGetDiagRecW( h_type, h, record_number, wsqlstate, &error->native_code, wnative_message,
SQL_MAX_MESSAGE_LENGTH + 1, &wmessage_len );
// don't use the CHECK* macros here since it will trigger reentry into the error handling system
// Workaround for a bug in unixODBC 2.3.4 when connection pooling is enabled (PDO SQLSRV).
// Instead of returning false, we return an empty error message to prevent the driver from throwing an exception.
// To reproduce:
// Create a connection and close it (return it to the pool)
// Create a new connection from the pool.
// Prepare and execute a statement that generates an info message (such as 'USE tempdb;')
#ifdef __APPLE__
if( r == SQL_NO_DATA && ctx.driver() != NULL /*PDO SQLSRV*/ ) {
r = SQL_SUCCESS;
}
#endif // __APPLE__
if( !SQL_SUCCEEDED( r ) || r == SQL_NO_DATA ) {
return false;
}
Expand Down
34 changes: 34 additions & 0 deletions test/pdo_sqlsrv/PDO_ConnPool_Unix.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
--TEST--
PDO Connection Pooling Test on Unix
This test assumes odbcinst.ini has not been modified.
This test also requires root privileges to modify odbcinst.ini file on Linux.
--SKIPIF--
<?php if(PHP_OS === "WINNT") die("Skipped: Test for Linux and Mac");
--FILE--
<?php
$lines_to_add="CPTimeout=5\n[ODBC]\nPooling=Yes\n";

//get odbcinst.ini location
$lines = explode("\n", shell_exec("odbcinst -j"));
$odbcinst_ini = explode(" ", $lines[1])[1];

//enable pooling by modifying the odbcinst.ini file
$current = file_get_contents($odbcinst_ini);
$current.=$lines_to_add;
file_put_contents($odbcinst_ini, $current);

//Creating a new php process, because for changes in odbcinst.ini file to affect pooling, drivers must be reloaded.
print_r(shell_exec("php ./test/pdo_sqlsrv/isPooled.php"));

//disable pooling by modifying the odbcinst.ini file
$current = file_get_contents($odbcinst_ini);
$current = str_replace("CPTimeout=5\n[ODBC]\nPooling=Yes\n",'',$current);
file_put_contents($odbcinst_ini, $current);

print_r(shell_exec("php ./test/pdo_sqlsrv/isPooled.php"));
?>
--EXPECT--
Pooled
Not Pooled


25 changes: 25 additions & 0 deletions test/pdo_sqlsrv/isPooled.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php
include_once 'autonomous_setup.php';
$conn1 = new PDO("sqlsrv:Server=$serverName", $username, $password);
$connId1 = ConnectionID($conn1);
$conn1 = null;

$conn2 = new PDO("sqlsrv:Server=$serverName", $username, $password);
$connId2 = ConnectionID($conn2);

if ($connId1 === $connId2){
echo "Pooled\n";
}else{
echo "Not Pooled\n";
}

function ConnectionID($conn)
{
$tsql = "SELECT [connection_id] FROM [sys].[dm_exec_connections] where session_id = @@SPID";
$stmt = $conn->query($tsql);
$connID = $stmt->fetchColumn(0);
$stmt->closeCursor();
$stmt = null;
return ($connID);
}
?>

0 comments on commit 6809f0f

Please sign in to comment.