FirebirdSQL / php-firebird

Firebird PHP driver
Other
66 stars 15 forks source link

ibase_close not working as expected #22

Open haanerg opened 2 years ago

haanerg commented 2 years ago

It looks like ibase_close noes not work as expected, at least if the docs are to be believed. Closing a connection doesn't work for us with PHP7.4.3 and version 1.1.1 of the driver. Other combinations tested yields the same result. There also seems to be a mismatch between the docs and the test case (ibase_close_001.phpt).

If we have a look at the test case:

--TEST--
ibase_close(): Basic test
--SKIPIF--
<?php include("skipif.inc"); ?>
--FILE--
<?php

require("interbase.inc");

$x = ibase_connect($test_base);
var_dump(ibase_close($x));
var_dump(ibase_close($x));
var_dump(ibase_close());
var_dump(ibase_close('foo'));

?>
--EXPECTF--
bool(true)
bool(true)
bool(true)

Warning: ibase_close() expects parameter 1 to be resource, string given in %s on line %d
NULL

If the connection ($x) is truly closed, the second and third call to ibase_close should return false. However, it seems like calling ibase_close($x) does not close the connection. Calling ibase_close() without a resource seems to close all connections, which is ok but not documented.

mortzdk commented 2 years ago

So it looks like if ibase_close is called without arguments, only the latest resource (default_link) will be closed, after which any further calls to ibase_close without arguments will result in the function returning false. https://github.com/FirebirdSQL/php-firebird/blob/master/interbase.c#L1060

Whenever ibase_close is called with a connection, the function will always return true.

We end up having problems because of the behavior of ibase_close. (The behaviour is not the same in previous versions - we tested it in PHP 7.0).

Our test does the following:

  1. We select a value.
  2. We update the value in a transaction and commit the change.
  3. We select the value again (here we get the old value, since the query is performed on the connection which is in a state prior to the transaction just performed - as far as I understand)
  4. Then we close the connection
  5. We do a select on the closed connection (Which works? - But still yields the old value)
  6. We select the value again using a newly created connection (This is now expected to be in a state after the transaction performed above) This is the part that fails with the new firebird driver, while it works in the PHP 7.0 CORE version, hence we get the old value rather than the updated one.
  7. We create a new transaction and fetch the value, which results in the updated value as expected.
        $connection = ibase_connect($database, $username, $password);

        //INITIAL SELECT
        $stmt = ibase_prepare($connection, "SELECT ARRANGOR_ID FROM \"EVENT\" WHERE EVENT_NO = ?");
        $res = ibase_execute($stmt, $eventNo);
        $data = ibase_fetch_assoc($res);
        echo "PRE UPDATE\n";
        var_dump($data);
        ibase_free_result($res);
        ibase_free_query($stmt);

        //TRANSACTION UDPATE AND SELECT
        IBASE_DEFAULT;
        $transaction = ibase_trans(IBASE_DEFAULT, $connection);
        $stmt = ibase_prepare($connection, $transaction,  "UPDATE \"EVENT\" SET ARRANGOR_ID = ? WHERE EVENT_NO = ?");
        ibase_execute($stmt, $newID, $eventNo);
        ibase_free_query($stmt);

        $stmt = ibase_prepare($connection, $transaction, "SELECT ARRANGOR_ID FROM \"EVENT\" WHERE EVENT_NO = ?");
        $res = ibase_execute($stmt, $eventNo);
        $data = ibase_fetch_assoc($res);
        ibase_free_result($res);
        ibase_free_query($stmt);

        echo "IN TRANSACTION\n";
        var_dump($data);

        ibase_commit($transaction);

        //AFTER TRANSACTION
        $stmt = ibase_prepare($connection, "SELECT ARRANGOR_ID FROM \"EVENT\" WHERE EVENT_NO = ?");
        $res = ibase_execute($stmt, $eventNo);
        $data = ibase_fetch_assoc($res);
        ibase_free_result($res);
        ibase_free_query($stmt);

        echo "AFTER TRANSACTION\n";
        var_dump($data);

        //CLOSE CONNECTION 
//        ibase_close();
        ibase_close($connection);

//        TEST CLOSED CONNECTION WORKING
        $stmt = ibase_prepare($connection, "SELECT ARRANGOR_ID FROM \"EVENT\" WHERE EVENT_NO = ?");
        $res = ibase_execute($stmt, $eventNo);
        $data = ibase_fetch_assoc($res);
        ibase_free_result($res);

        echo "AFTER CLOSE\n";
        var_dump($data);

        $newConnection = ibase_connect($database, $username, $password);

        //AFTER RECONNECT
        $stmt = ibase_prepare($newConnection, "SELECT ARRANGOR_ID FROM \"EVENT\" WHERE EVENT_NO = ?");
        $res = ibase_execute($stmt, $eventNo);
        $data = ibase_fetch_assoc($res);
        echo "AFTER RECONNECT \n";
        var_dump($data);
        ibase_free_result($res);

        //SELECT IN NEW TRANSACTION 
        $transaction = ibase_trans(IBASE_DEFAULT, $newConnection);
        $stmt = ibase_prepare($newConnection, $transaction, "SELECT ARRANGOR_ID FROM \"EVENT\" WHERE EVENT_NO = ?");
        $res = ibase_execute($stmt, $eventNo);
        $data = ibase_fetch_assoc($res);
        ibase_free_result($res);

        echo "IN NEW TRANSACTION\n";
        var_dump($data);

        ibase_commit($transaction);