? Success

User tests: Successful: Unsuccessful:

avatar photodude
photodude
9 Oct 2016

Pull Request for Issue When pgsql $this->cursor is false .

Summary of Changes

A call to pg_result_error_field() when $this->cursor is false from a query failing will result in an error pg_result_error_field() expects parameter 1 to be resource, boolean given

Try to get a valid error message and throw a JDatabaseExceptionExecuting Exception

Testing Instructions

(I'm not sure what testing is needed or if the unit tests need modifications)
Code review, Travis pass, (check this HHVM for resolving error on JDatabaseDriverPostgresqlTest::testReleaseTransactionSavepoint only 10 errors)

Documentation Changes Required

pgsql getErrorNumber() now throws an Exception when $this->cursor is false

avatar photodude photodude - open - 9 Oct 2016
avatar photodude photodude - change - 9 Oct 2016
Status New Pending
avatar joomla-cms-bot joomla-cms-bot - change - 9 Oct 2016
Labels Added: ?
avatar joomla-cms-bot joomla-cms-bot - change - 9 Oct 2016
Category Postgresql Libraries
avatar photodude photodude - change - 9 Oct 2016
The description was changed
avatar photodude photodude - edited - 9 Oct 2016
avatar wilsonge wilsonge - change - 9 Oct 2016
Milestone Added:
avatar mbabker
mbabker - comment - 9 Oct 2016

Please port to the Framework as well.

avatar photodude
photodude - comment - 9 Oct 2016

@mbabker I'm on my phone at the moment but I don't recall the framework having a getErrorNumber() method in the driver. I think the framework handles these error requests directly and puts the error in a log while in the method that has a possible error condition like $this->cursor being false.

avatar mbabker
mbabker - comment - 9 Oct 2016

It doesn't have getErrorNumber() methods, the errors are handled inline to the execute() methods (the CMS abstracted it out in part to mask the table prefixes which we aren't doing on the Framework; actually there the SQL query is no longer part of the Exception message).

avatar photodude
photodude - comment - 9 Oct 2016

So nothing to port to the framework?

Do we need to quotename, escape or remove the sql from the exception here?

avatar mbabker
mbabker - comment - 9 Oct 2016

The check if $this->cursor is false needs to be added for the two calls to pg_result_error_field() for the same reason you're PR'ing it here. Except instead of throwing an Exception directly I'd just give it a default 0 value since the Exception gets thrown a couple lines down there.

avatar photodude
photodude - comment - 9 Oct 2016

@mbabker do we need to add additional if ($this->cursor === false) when the framework is already checking with if (!$this->cursor) ? I believe this should already catch the false condition for $this->cursor.

avatar mbabker
mbabker - comment - 9 Oct 2016

Eh, fair point. But if pg_result_error_field() requires a valid resource and that entire conditional operates with a boolean value then that whole branch is bugged anyway and we probably need to do something with it.

avatar Hackwar
Hackwar - comment - 10 Oct 2016

Sorry, but it seems to me to rather be an issue that we are using the Postgres functions incorrectly. pg_result_error_field() has a specific comment that you should use different functions to get a resource instead of either resource or boolean. Seems to me as if the code would have to look somewhat more like

pg_send_query($this->connection, $query);

$this->cusor = pg_get_result($this->connection);
if (pg_result_error($this->cursor) != '')
{
    // Get the error number and message before we execute any more queries.
    $errorNum = $this->getErrorNumber();
    $errorMsg = $this->getErrorMessage($query);

    // Check if the server was disconnected.
    if (!$this->connected())
    {
        try
        {
            // Attempt to reconnect.
            $this->connection = null;
            $this->connect();
        }
        // If connect fails, ignore that exception and throw the normal exception.
        catch (RuntimeException $e)
        {
            $this->errorNum = $this->getErrorNumber();
            $this->errorMsg = $this->getErrorMessage($query);
            // Throw the normal query exception.
            JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED', $this->errorNum, $this->errorMsg), JLog::ERROR, 'database-error');
            throw new JDatabaseExceptionExecuting($query, $this->errorMsg, null, $e);
        }
        // Since we were able to reconnect, run the query again.
        return $this->execute();
    }
    // The server was not disconnected.
    else
    {
        // Get the error number and message from before we tried to reconnect.
        $this->errorNum = $errorNum;
        $this->errorMsg = $errorMsg;
        // Throw the normal query exception.
        JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED', $this->errorNum, $this->errorMsg), JLog::ERROR, 'database-error');
        throw new JDatabaseExceptionExecuting($query, $this->errorMsg);
    }
}
return $this->cursor;
avatar mbabker
mbabker - comment - 10 Oct 2016

Can't say I've looked through the pgsql_* docs closely but if we need to fix that stuff let's do it.

avatar Hackwar
Hackwar - comment - 10 Oct 2016

Ok, I tried the code that I posted above and it does NOT work. The problem is still, that we are using pg_query() and later, in case of an error, expect a resource where there can't be one. I don't see a case where getErrorNumber() could not run into the JDatabaseExceptionExecuting exception of this PR. If there is an error in pg_query(), we don't have a resource. But if there is no resource, we can not get the error number. I have no idea what to do.

avatar photodude
photodude - comment - 10 Oct 2016

When I started trying to solve this I looked a little at trying to follow the recommendation for pg_result_error_field() that "if the query fails, you must use pg_send_query() and pg_get_result() to get the result handle" but I read something about pg_send_query() not being able to be used with trasactions. Which is one reason I moved towards throwing an Exception when the query fails.

I can't find the reference regarding pg_send_query() and transaction issues at the moment.

avatar photodude
photodude - comment - 10 Oct 2016

@Hackwar two issues with the code you posted, you need to "call pg_get_result() one or more times to obtain the results" and we also have to take into consideration "pg_send_query() cannot be called again (on the same connection) until pg_get_result() has returned a null pointer"

I think we are likely opening a big rework if we go down the road of implementing Asynchronous Command Processing just to handle a single error condition from a query failing.

avatar Hackwar
Hackwar - comment - 11 Oct 2016

I followed the comment in the docs of pg_result_error_field() where it indeed says to use pg_send_query() and pg_get_result(). But after testing that code and then reading the docs carefully of pg_get_result(), I've seen that that one, too, returns false upon error. So the comment is simply wrong. Seems like pg_last_error() or something like that would actually be the way to go?

avatar photodude
photodude - comment - 11 Oct 2016

I agree, Let's move forward on merging this PR.

avatar brianteeman brianteeman - change - 17 Oct 2016
Milestone Removed:
avatar brianteeman brianteeman - change - 17 Oct 2016
Milestone Added:
avatar brianteeman brianteeman - change - 17 Oct 2016
Milestone Added:
avatar brianteeman brianteeman - change - 17 Oct 2016
Milestone Removed:
avatar photodude
photodude - comment - 26 Oct 2016

Bump for merge consideration

avatar wilsonge wilsonge - change - 28 Oct 2016
Status Pending Fixed in Code Base
Closed_Date 0000-00-00 00:00:00 2016-10-28 15:10:37
Closed_By wilsonge
avatar wilsonge wilsonge - close - 28 Oct 2016
avatar wilsonge wilsonge - merge - 28 Oct 2016
avatar wilsonge wilsonge - reference | 461e8d0 - 28 Oct 16
avatar wilsonge wilsonge - merge - 28 Oct 2016
avatar wilsonge wilsonge - close - 28 Oct 2016

Add a Comment

Login with GitHub to post a comment