microsoft / msphpsql

Microsoft Drivers for PHP for SQL Server
MIT License
1.8k stars 373 forks source link

SQL_ASSERT(sqlsrv_field_metadata): 'Meta data vector out of sync' #937

Closed obmsch closed 5 years ago

obmsch commented 5 years ago

(SQLServer(2016)/Win10(1809)/PHP(7.2.15)/MSODBC(17.3.1.1)

This started with 5.6 (5.3 had no issues). This is on a multi layer application (MantisBT->ADOdb->sqlsvr), so getting the real source of this is not obviuos. The triggering sequence ($sql = 'UPDATE ...'):

  $stm = sqlsrv_query($connection, $sql);   [Ok]
  $fieldmeta = sqlsrv_field_metadata($stmt) [SQL_ASSERTs]

Looking at the docs: // sqlsrv_field_metadata( resource $stmt ) // // Retrieves metadata for the fields of a prepared statement. For information // about preparing a statement, see sqlsrv_query or sqlsrv_prepare. Note that // sqlsrv_field_metadata can be called on any prepared statement, pre- or // post-execution. // // Parameters // $stmt: A statement resource for which field metadata is sought. // // Return Value // retrieve an array of metadata for the current result set on a statement. Each element of the // array is a sub-array containing 5 elements accessed by key: // name - name of the field. // type - integer of the type. Can be compared against the SQLSRV_SQLTYPE constants. // size - length of the field. null if the field uses precision and scale instead. // precision - number of digits in a numeric field. null if the field uses size. // scale - number of decimal digits in a numeric field. null if the field uses sizes. // is_nullable - if the field may contain a NULL instead of a value // false is returned if an error occurs retrieving the metadata

This looks like an API (contract) violation. Neither documented, nor deprecated or warned on.

yitam commented 5 years ago

Yes @obmsch we can reproduce this with UPDATE / DELETE statements that return no fields. We will fix this. That being said, is there any reason for calling sqlsrv_field_metadata() for UPDATE / DELETE statements?

mrbarletta commented 5 years ago

Thanks @yitam for your quick response!. let me chime in:

We had this issue as well first with Store Procedures that return no data and also with updates, in my case it was PHP ADODB 5.21 trying to do that automatically after a query execution, we spent hours debugging and finally found this call to be the one failing (without any errors).

We used version 5.6 on Ubuntu 18.04 with php 7.2, we started receiving 500 errors without any trace of what could have gone wrong.

Forgive my ignorance but besides fixing this issue is it possible to show more errors on PHP, silent errors are hard to track down, no error_log just a dead php process.

thanks again!

yitam commented 5 years ago

Thanks @mrbarletta for the additional information. We will likely fix this and address the logging for next preview. Are you using sqlsrv too?

mrbarletta commented 5 years ago

Thanks @mrbarletta for the additional information. We will likely fix this and address the logging for next preview. Are you using sqlsrv too?

Yes we use that as well, previous versions (on other servers) didn't have that issue

obmsch commented 5 years ago

Sorry @yitam I don't know the reasoning. That's inside the database abstraction layer (ADOdb 5.20) of the bugtracker app I use. I just tried to figure out, why the app stops working after updating the driver from 5.3 to 5.6.

Bill1000 commented 5 years ago

@obmsch, I found a workaround for ADODB that seems to resolve it until the next release: https://github.com/ADOdb/ADOdb/issues/492

cwchien commented 5 years ago

PHP 7.3.2 with sqlsrv 5.5.0preview / 5.6.0 also throw this error, where 5.4.0preview is fine.

OS: CentOS 7 x64 Database: SQL Server 2017 Linux

My PHP application runs on the same host with SQL Server.

yitam commented 5 years ago

@cwchien we've identified the problem, which occurs when calling sqlsrv_field_metadata after a DELETE / UPDATE statement, and the fix is already merged for next preview.

genyslt commented 5 years ago
$query = 'INSERT INTO Revisions_Results (StatusId,Comments,RevisionId) values (10018,213,17); SELECT SCOPE_IDENTITY() AS id';
$stmt = sqlsrv_query($connection, $query);
sqlsrv_fetch($stmt);
$scope = sqlsrv_get_field($stmt, 0);

Also throws same error: Fatal error: Meta data vector out of sync in

OS: UBUNTU PHP 7.2.* Microsoft SQL Server 2016 (SP1) (KB3182545) - 13.0.4001.0 (X64) sqlsrv 5.6.0

yitam commented 5 years ago

Thanks @genyslt. Please also provide the table schema of your Revisions_Results to help us investigate.

yitam commented 5 years ago

@genyslt While waiting for you, I tested with the following table:

CREATE TABLE test1([id] [int] IDENTITY, [name] [nvarchar](50) NOT NULL)

Yes, I could reproduce the same error, but with the fix, the problem is gone.

That being said, for your particular example, you should call sqlsrv_next_result() before fetching. That is,

$tsql = "INSERT INTO test1 VALUES ('abcde'); SELECT SCOPE_IDENTITY() AS id";
$stmt = sqlsrv_query($conn, $tsql);
sqlsrv_next_result($stmt);
sqlsrv_fetch($stmt);
$scope = sqlsrv_get_field($stmt, 0);
var_dump($scope);

The result I got from the above is string(1) "1" (because SCOPE_IDENTITY() returns a numeric type).

yitam commented 5 years ago

Closing this issue, as this is fixed by 5.6.1 hotfix

cwchien commented 5 years ago

Confirmed 5.6.1 fixed my problem. Thanks very much! :)

PHP 7.3.2 with sqlsrv 5.5.0preview / 5.6.0 also throw this error, where 5.4.0preview is fine.

OS: CentOS 7 x64 Database: SQL Server 2017 Linux

My PHP application runs on the same host with SQL Server.