php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #78196 PDOStatement::errorInfo() gives incorrect output
Submitted: 2019-06-21 22:06 UTC Modified: 2020-09-29 14:49 UTC
From: dpuglielli at magnitude dot com Assigned:
Status: Open Package: PDO ODBC
PHP Version: 7.3.6 OS: Windows 10
Private report: No CVE-ID: None
 [2019-06-21 22:06 UTC] dpuglielli at magnitude dot com
Description:
------------
Calling PDOStatement::errorInfo with the results of a batched query and a non-forward cursor yields a four element array, with the fourth element as another SQLSTATE. This is not consistent with the documentation, which states that there are three fields in this array (according to https://www.php.net/manual/en/pdostatement.errorinfo.php). Moreover, the first element is an incorrect SQLSTATE.

The problem appears to lie in line 49 of ext/pdo_odbc/odbc_driver.c in pdo_odbc_fetch_error_func(), where the three elements of the error array are populated. This occurs after an error code has already been added in line 1678 of ext/pdo/pdo_stmt.c, producing four elements instead of three.

Test script:
---------------
https://github.com/david-puglielli/msphpsql/blob/pdo-errorinfo-bug/test/functional/pdo_sqlsrv/pdo_errorinfo_bug.phpt

Expected result:
----------------
The output of errorInfo() should have three elements. The first element should correctly correspond to the diagnostic message in the third element, like so:

Array
(
    [0] => 01S02
    [1] => 0
    [2] => [Microsoft][ODBC Driver 17 for SQL Server]Cursor type changed (SQLExecute[0] at ext\pdo_odbc\odbc_stmt.c:254)
)

Actual result:
--------------
The output of the provided test script is as follows:

Database error info:
Array
(
    [0] => 00000
    [1] =>
    [2] =>
)
Statement error info:
Array
(
    [0] => 01S02
    [1] => 0
    [2] => [Microsoft][ODBC Driver 17 for SQL Server]Cursor type changed (SQLExecute[0] at ext\pdo_odbc\odbc_stmt.c:254)
    [3] => 01S02
)
Array
(
    [0] => 00000
    [1] => 0
    [2] => [Microsoft][ODBC Driver 17 for SQL Server]Cursor type changed (SQLExecute[0] at ext\pdo_odbc\odbc_stmt.c:254)
    [3] => 01S02
)
Array
(
    [0] => 00000
    [1] => 0
    [2] => [Microsoft][ODBC Driver 17 for SQL Server]Cursor type changed (SQLExecute[0] at ext\pdo_odbc\odbc_stmt.c:254)
    [3] => 01S02
)

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2019-06-22 00:39 UTC] daverandom@php.net
It's worth noting that the general PDO documentation is lowest common denominator, it defines the minimum common behaviour for all drivers but may be extended if a particular driver has a need to do so. In the case of PDOStatement::$errorInfo it would be more accurate to say that the result will always contain *at least* those 3 elements, I have updated the docs accordingly⁽¹⁾.

Whether this is a bug is debatable - I can certainly see why it could be considered incorrect, but it's also not definitely wrong either...

I'm not 100% on this, however I don't think 01S02 is a standard SQLSTATE value. It seems to be in common usage - I found documentation from both MS⁽²⁾ and IBM⁽³⁾ which references it - but it is not included in the Wikipedia entry⁽⁴⁾ or any other generic/implementation independent documentation that I could find with a 5 minute Google. Since I do not own a copy of ISO:9075 and don't have a spare CHF178 lying around I cannot confirm this for sure. If it is non-standard, or indeed if there are other circumstances where ODBC may emit non-standard values, this may be the reason for the current behaviour - the PDO documentation explicitly states that this first element will be an ISO standard SQLSTATE code. 

Regardless, the existing behaviour is arguably "better" than documented. Note that the info returned on the first iteration of your test does in fact have the "correct" value for the first element - it's only subsequent iterations where there's a discrepancy - because it pertains to the previous operation. The later values are correctly reporting the previous operation was successful because in those cases the previous operation was fetching a row, which succeeded. By providing the SQLSTATE of the previous *query execution operation* in the additional element, code can be structured such that the data is processed before errors without the need for boilerplate code to store the error data in temporary var etc. While I wouldn't design code like this myself, I can see why it might be desirable in some circumstances.


I will leave this bug open for now but I don't personally think this needs "fixing" since it gives a bit of flexibility and it's not incompatible with the documented behaviour. Perhaps the documentation for the PDO ODBC driver should be updated instead?

[1] https://svn.php.net/viewvc?view=revision&revision=347629
[2] https://docs.microsoft.com/en-us/sql/odbc/reference/syntax/sqlexecute-function
[3] https://www.ibm.com/support/knowledgecenter/en/SSEPEK_11.0.0/odbc/src/tpc/db2z_hdtab.html
[4] https://en.wikipedia.org/wiki/SQLSTATE
 [2020-09-29 14:49 UTC] cmb@php.net
This looks like a bug to me.  Having the former status as fourth
element would be okay, but the driver specific error code and
message (second and third) need to match, but apparently don't:

Array
(
    [0] => 00000
    [1] => 0
    [2] => [Microsoft][ODBC Driver 17 for SQL Server]Cursor type changed (SQLExecute[0] at ext\pdo_odbc\odbc_stmt.c:254)
    [3] => 01S02
)

Unfortunately, the test script is no longer available.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Nov 23 08:01:28 2024 UTC