[php-src] Issue #10847: SQLPutData errors are not handled in PDO_ODBC, causing a function sequence error in SQLParamData

From: Date: Mon, 13 Mar 2023 22:18:29 +0000
Subject: [php-src] Issue #10847: SQLPutData errors are not handled in PDO_ODBC, causing a function sequence error in SQLParamData
Groups: php.bugs 
Request: Send a blank email to php-bugs+get-243907@lists.php.net to get a copy of this message
Issue: https://github.com/php/php-src/issues/10847 Author: NattyNarwhal ### Description A user reported to me an issue where PDO_ODBC was returning a function sequence error. Unfortunately, it's a little hard to reproduce independently (large Laravel application, large dataset), but I can clearly see what's causing the error, and that it's obscuring another error that's the source of the actual problem. The relevant part of the unixODBC trace (I'm not posting the full file because it's ~100k lines): ``` [ODBC][718][1678733794.839656][SQLAllocHandle.c][560] Entry: Handle Type = 3 Input Handle = 0x56088464f120 [ODBC][718][1678733794.839724][SQLAllocHandle.c][1105] Exit:[SQL_SUCCESS] Output Handle = 0x56088467eaa0 [ODBC][718][1678733794.839741][SQLPrepare.c][196] Entry: Statement = 0x56088467eaa0 SQL = [select id from new table (insert into documents (id, title, body, keywords, user_id, category_id, role_id, categoryname, created...][length = 198 (SQL_NTS)] [ODBC][718][1678733794.840339][SQLPrepare.c][377] Exit:[SQL_SUCCESS] [ODBC][718][1678733794.840394][SQLDescribeParam.c][185] Entry: Statement = 0x56088467eaa0 Parameter Number = 1 SQL Type = 0x7ffc4db00cd2 Param Def = 0x7ffc4db00cd8 Scale = 0x7ffc4db00cd4 Nullable = 0x7ffc4db00cd6 [ODBC][718][1678733794.840414][SQLDescribeParam.c][338] Exit:[SQL_SUCCESS] SQL Type = 0x7ffc4db00ba0 Param Def = 0x7ffc4db00ab0 Scale = 0x7ffc4db009c0 Nullable = 0x7ffc4db008d0 [ODBC][718][1678733794.840441][SQLBindParameter.c][217] Entry: Statement = 0x56088467eaa0 Param Number = 1 Param Type = 1 C Type = 1 SQL_C_CHAR SQL Type = -5 SQL_BIGINT Col Def = 20 Scale = 0 Rgb Value = 0x7f6bcd1ceaf0 Value Max = 0 StrLen Or Ind = 0x7f6bcd04d8c0 [ODBC][718][1678733794.840459][SQLBindParameter.c][434] Exit:[SQL_SUCCESS] [ODBC][718][1678733794.840475][SQLDescribeParam.c][185] Entry: Statement = 0x56088467eaa0 Parameter Number = 2 SQL Type = 0x7ffc4db00cd2 Param Def = 0x7ffc4db00cd8 Scale = 0x7ffc4db00cd4 Nullable = 0x7ffc4db00cd6 [ODBC][718][1678733794.840502][SQLDescribeParam.c][338] Exit:[SQL_SUCCESS] SQL Type = 0x7ffc4db00ba0 Param Def = 0x7ffc4db00ab0 Scale = 0x7ffc4db009c0 Nullable = 0x7ffc4db008d0 [ODBC][718][1678733794.840517][SQLBindParameter.c][217] Entry: Statement = 0x56088467eaa0 Param Number = 2 Param Type = 1 C Type = 1 SQL_C_CHAR SQL Type = 12 SQL_VARCHAR Col Def = 500 Scale = 0 Rgb Value = 0x7f6bcd1ce820 Value Max = 0 StrLen Or Ind = 0x7f6bcd050460 [ODBC][718][1678733794.840531][SQLBindParameter.c][434] Exit:[SQL_SUCCESS] [ODBC][718][1678733794.840546][SQLDescribeParam.c][185] Entry: Statement = 0x56088467eaa0 Parameter Number = 3 SQL Type = 0x7ffc4db00cd2 Param Def = 0x7ffc4db00cd8 Scale = 0x7ffc4db00cd4 Nullable = 0x7ffc4db00cd6 [ODBC][718][1678733794.840562][SQLDescribeParam.c][338] Exit:[SQL_SUCCESS] SQL Type = 0x7ffc4db00ba0 Param Def = 0x7ffc4db00ab0 Scale = 0x7ffc4db009c0 Nullable = 0x7ffc4db008d0 [ODBC][718][1678733794.840576][SQLBindParameter.c][217] Entry: Statement = 0x56088467eaa0 Param Number = 3 Param Type = 1 C Type = 1 SQL_C_CHAR SQL Type = -1 SQL_LONGVARCHAR Col Def = 65536 Scale = 0 Rgb Value = 0x7f6bcd1ce780 Value Max = 0 StrLen Or Ind = 0x7f6bcd04d940 [ODBC][718][1678733794.840592][SQLBindParameter.c][434] Exit:[SQL_SUCCESS] [ODBC][718][1678733794.840608][SQLDescribeParam.c][185] Entry: Statement = 0x56088467eaa0 Parameter Number = 4 SQL Type = 0x7ffc4db00cd2 Param Def = 0x7ffc4db00cd8 Scale = 0x7ffc4db00cd4 Nullable = 0x7ffc4db00cd6 [ODBC][718][1678733794.840624][SQLDescribeParam.c][338] Exit:[SQL_SUCCESS] SQL Type = 0x7ffc4db00ba0 Param Def = 0x7ffc4db00ab0 Scale = 0x7ffc4db009c0 Nullable = 0x7ffc4db008d0 [ODBC][718][1678733794.840655][SQLBindParameter.c][217] Entry: Statement = 0x56088467eaa0 Param Number = 4 Param Type = 1 C Type = 1 SQL_C_CHAR SQL Type = -1 SQL_LONGVARCHAR Col Def = 65536 Scale = 0 Rgb Value = 0x7f6bcd1ce690 Value Max = 0 StrLen Or Ind = 0x7f6bcd04df00 [ODBC][718][1678733794.840670][SQLBindParameter.c][434] Exit:[SQL_SUCCESS] [ODBC][718][1678733794.840686][SQLDescribeParam.c][185] Entry: Statement = 0x56088467eaa0 Parameter Number = 5 SQL Type = 0x7ffc4db00cd2 Param Def = 0x7ffc4db00cd8 Scale = 0x7ffc4db00cd4 Nullable = 0x7ffc4db00cd6 [ODBC][718][1678733794.840701][SQLDescribeParam.c][338] Exit:[SQL_SUCCESS] SQL Type = 0x7ffc4db00ba0 Param Def = 0x7ffc4db00ab0 Scale = 0x7ffc4db009c0 Nullable = 0x7ffc4db008d0 [ODBC][718][1678733794.840715][SQLBindParameter.c][217] Entry: Statement = 0x56088467eaa0 Param Number = 5 Param Type = 1 C Type = 1 SQL_C_CHAR SQL Type = -5 SQL_BIGINT Col Def = 20 Scale = 0 Rgb Value = 0x7f6bcd1ce9b0 Value Max = 0 StrLen Or Ind = 0x7f6bcd04d800 [ODBC][718][1678733794.840729][SQLBindParameter.c][434] Exit:[SQL_SUCCESS] [ODBC][718][1678733794.840744][SQLDescribeParam.c][185] Entry: Statement = 0x56088467eaa0 Parameter Number = 6 SQL Type = 0x7ffc4db00cd2 Param Def = 0x7ffc4db00cd8 Scale = 0x7ffc4db00cd4 Nullable = 0x7ffc4db00cd6 [ODBC][718][1678733794.840760][SQLDescribeParam.c][338] Exit:[SQL_SUCCESS] SQL Type = 0x7ffc4db00ba0 Param Def = 0x7ffc4db00ab0 Scale = 0x7ffc4db009c0 Nullable = 0x7ffc4db008d0 [ODBC][718][1678733794.840790][SQLBindParameter.c][217] Entry: Statement = 0x56088467eaa0 Param Number = 6 Param Type = 1 C Type = 1 SQL_C_CHAR SQL Type = -5 SQL_BIGINT Col Def = 20 Scale = 0 Rgb Value = 0x7f6bcd1ce8c0 Value Max = 0 StrLen Or Ind = 0x7f6bcd041b20 [ODBC][718][1678733794.840806][SQLBindParameter.c][434] Exit:[SQL_SUCCESS] [ODBC][718][1678733794.840822][SQLDescribeParam.c][185] Entry: Statement = 0x56088467eaa0 Parameter Number = 7 SQL Type = 0x7ffc4db00cd2 Param Def = 0x7ffc4db00cd8 Scale = 0x7ffc4db00cd4 Nullable = 0x7ffc4db00cd6 [ODBC][718][1678733794.840847][SQLDescribeParam.c][338] Exit:[SQL_SUCCESS] SQL Type = 0x7ffc4db00ba0 Param Def = 0x7ffc4db00ab0 Scale = 0x7ffc4db009c0 Nullable = 0x7ffc4db008d0 [ODBC][718][1678733794.840861][SQLBindParameter.c][217] Entry: Statement = 0x56088467eaa0 Param Number = 7 Param Type = 1 C Type = 1 SQL_C_CHAR SQL Type = -5 SQL_BIGINT Col Def = 20 Scale = 0 Rgb Value = 0x7f6bcd1ce960 Value Max = 0 StrLen Or Ind = 0x7f6bcd0439c0 [ODBC][718][1678733794.840875][SQLBindParameter.c][434] Exit:[SQL_SUCCESS] [ODBC][718][1678733794.840890][SQLDescribeParam.c][185] Entry: Statement = 0x56088467eaa0 Parameter Number = 8 SQL Type = 0x7ffc4db00cd2 Param Def = 0x7ffc4db00cd8 Scale = 0x7ffc4db00cd4 Nullable = 0x7ffc4db00cd6 [ODBC][718][1678733794.840905][SQLDescribeParam.c][338] Exit:[SQL_SUCCESS] SQL Type = 0x7ffc4db00ba0 Param Def = 0x7ffc4db00ab0 Scale = 0x7ffc4db009c0 Nullable = 0x7ffc4db008d0 [ODBC][718][1678733794.840919][SQLBindParameter.c][217] Entry: Statement = 0x56088467eaa0 Param Number = 8 Param Type = 1 C Type = 1 SQL_C_CHAR SQL Type = 12 SQL_VARCHAR Col Def = 500 Scale = 0 Rgb Value = 0x7f6bcd1cea00 Value Max = 0 StrLen Or Ind = 0x7f6bcd04d900 [ODBC][718][1678733794.840933][SQLBindParameter.c][434] Exit:[SQL_SUCCESS] [ODBC][718][1678733794.840949][SQLDescribeParam.c][185] Entry: Statement = 0x56088467eaa0 Parameter Number = 9 SQL Type = 0x7ffc4db00cd2 Param Def = 0x7ffc4db00cd8 Scale = 0x7ffc4db00cd4 Nullable = 0x7ffc4db00cd6 [ODBC][718][1678733794.840971][SQLDescribeParam.c][338] Exit:[SQL_SUCCESS] SQL Type = 0x7ffc4db00ba0 Param Def = 0x7ffc4db00ab0 Scale = 0x7ffc4db009c0 Nullable = 0x7ffc4db008d0 [ODBC][718][1678733794.840985][SQLBindParameter.c][217] Entry: Statement = 0x56088467eaa0 Param Number = 9 Param Type = 1 C Type = 1 SQL_C_CHAR SQL Type = 93 SQL_TYPE_TIMESTAMP Col Def = 26 Scale = 6 Rgb Value = 0x7f6bcd1ceb90 Value Max = 0 StrLen Or Ind = 0x7f6bcd043c20 [ODBC][718][1678733794.840999][SQLBindParameter.c][434] Exit:[SQL_SUCCESS] [ODBC][718][1678733794.841015][SQLDescribeParam.c][185] Entry: Statement = 0x56088467eaa0 Parameter Number = 10 SQL Type = 0x7ffc4db00cd2 Param Def = 0x7ffc4db00cd8 Scale = 0x7ffc4db00cd4 Nullable = 0x7ffc4db00cd6 [ODBC][718][1678733794.841030][SQLDescribeParam.c][338] Exit:[SQL_SUCCESS] SQL Type = 0x7ffc4db00ba0 Param Def = 0x7ffc4db00ab0 Scale = 0x7ffc4db009c0 Nullable = 0x7ffc4db008d0 [ODBC][718][1678733794.841044][SQLBindParameter.c][217] Entry: Statement = 0x56088467eaa0 Param Number = 10 Param Type = 1 C Type = 1 SQL_C_CHAR SQL Type = 93 SQL_TYPE_TIMESTAMP Col Def = 26 Scale = 6 Rgb Value = 0x7f6bcd1ce4b0 Value Max = 0 StrLen Or Ind = 0x7f6bcd041ce0 [ODBC][718][1678733794.841057][SQLBindParameter.c][434] Exit:[SQL_SUCCESS] [ODBC][718][1678733794.841072][SQLDescribeParam.c][185] Entry: Statement = 0x56088467eaa0 Parameter Number = 11 SQL Type = 0x7ffc4db00cd2 Param Def = 0x7ffc4db00cd8 Scale = 0x7ffc4db00cd4 Nullable = 0x7ffc4db00cd6 [ODBC][718][1678733794.841088][SQLDescribeParam.c][338] Exit:[SQL_SUCCESS] SQL Type = 0x7ffc4db00ba0 Param Def = 0x7ffc4db00ab0 Scale = 0x7ffc4db009c0 Nullable = 0x7ffc4db008d0 [ODBC][718][1678733794.841102][SQLBindParameter.c][217] Entry: Statement = 0x56088467eaa0 Param Number = 11 Param Type = 1 C Type = 1 SQL_C_CHAR SQL Type = 93 SQL_TYPE_TIMESTAMP Col Def = 26 Scale = 6 Rgb Value = 0x7f6bcd1ce730 Value Max = 0 StrLen Or Ind = 0x7f6bcd04d7c0 [ODBC][718][1678733794.841115][SQLBindParameter.c][434] Exit:[SQL_SUCCESS] [ODBC][718][1678733794.841132][SQLExecute.c][187] Entry: Statement = 0x56088467eaa0 [ODBC][718][1678733794.841148][SQLExecute.c][357] Exit:[SQL_NEED_DATA] [ODBC][718][1678733794.841163][SQLParamData.c][166] Entry: Statement = 0x56088467eaa0 Value = 0x7ffc4db00ea0 [ODBC][718][1678733794.841177][SQLParamData.c][362] Exit:[SQL_NEED_DATA] Value = 0x7f6bcd1ceaf0 [ODBC][718][1678733794.841190][SQLPutData.c][148] Entry: Statement = 0x56088467eaa0 Data = 0x7f6bcd04d838 StrLen = 3 [ODBC][718][1678733794.841205][SQLPutData.c][315] Exit:[SQL_SUCCESS] [ODBC][718][1678733794.841218][SQLParamData.c][166] Entry: Statement = 0x56088467eaa0 Value = 0x7ffc4db00ea0 [ODBC][718][1678733794.841231][SQLParamData.c][362] Exit:[SQL_NEED_DATA] Value = 0x7f6bcd1ce820 [ODBC][718][1678733794.841244][SQLPutData.c][148] Entry: Statement = 0x56088467eaa0 Data = 0x7f6bcd1d2be8 StrLen = 20 [ODBC][718][1678733794.841258][SQLPutData.c][315] Exit:[SQL_SUCCESS] [ODBC][718][1678733794.841271][SQLParamData.c][166] Entry: Statement = 0x56088467eaa0 Value = 0x7ffc4db00ea0 [ODBC][718][1678733794.841285][SQLParamData.c][362] Exit:[SQL_NEED_DATA] Value = 0x7f6bcd1ce780 [ODBC][718][1678733794.841299][SQLPutData.c][148] Entry: Statement = 0x56088467eaa0 Data = 0x7f6bcd186e18 StrLen = 2106 [ODBC][718][1678733794.841808][SQLPutData.c][315] Exit:[SQL_ERROR] [ODBC][718][1678733794.841826][SQLParamData.c][166] Entry: Statement = 0x56088467eaa0 Value = 0x7ffc4db00ea0 [ODBC][718][1678733794.841838][SQLParamData.c][189]Error: HY010 [ODBC][718][1678733794.841867][SQLGetDiagRec.c][677] Entry: Statement = 0x56088467eaa0 Rec Number = 1 SQLState = 0x7f6bccf98718 Native = 0x7f6bccf98920 Message Text = 0x7f6bccf9871e Buffer Length = 511 Text Len Ptr = 0x7ffc4db00a22 [ODBC][718][1678733794.841887][SQLGetDiagRec.c][726] Exit:[SQL_SUCCESS] SQLState = HY010 Native = 0x7f6bccf98920 -> 0 (32 bits) Message Text = [[unixODBC][Driver Manager]Function sequence error] [ODBC][718][1678733794.841901][SQLGetDiagRec.c][677] Entry: Statement = 0x56088467eaa0 Rec Number = 2 SQLState = 0x7ffc4db00a2a Native = 0x7ffc4db00a24 Message Text = 0x7ffc4db00a30 Buffer Length = 1023 Text Len Ptr = 0x7ffc4db00a22 [ODBC][718][1678733794.841915][SQLGetDiagRec.c][726] Exit:[SQL_NO_DATA] ``` As you can see, there's some DATA_AT_EXEC going on (the unixODBC trace makes it hard to determine what parameter is bound as such), so PDO_ODBC starts with an [SQLParamData](https://github.com/php/php-src/blob/PHP-8.1.16/ext/pdo_odbc/odbc_stmt.c#L172), and calls [SQLPutData](https://github.com/php/php-src/blob/PHP-8.1.16/ext/pdo_odbc/odbc_stmt.c#L194-L200) ([alternative call site](https://github.com/php/php-src/blob/PHP-8.1.16/ext/pdo_odbc/odbc_stmt.c#L236)) in a loop as needed. The problem is that failures in SQLPutData are not correctly handled. As you can see in the trace, one of the laterr SQLPutData calls is returning an error (unfortunately, unixODBC tracing doesn't decide to find specifics on its own), but PDO_ODBC doesn't actually do anything with the error code it stores (if it stores it at all). Instead, it continues on, calling SQLParamData again, which is now in an invalid state and within its rights to return [HY010](https://learn.microsoft.com/en-us/sql/odbc/reference/syntax/sqlparamdata-function?view=sql-server-ver16) (as documented, though it's not clear that only successful SQLPutData or exec calls are valid). The actual error we care about is for the SQLPutData call, but that's not being surfaced, and the misleading function sequence error is returned instead because it ignores that previous error. If it helps, I also have the application's Laravel log from trying to insert the rows, although this does include the user's data. I'm also trying to get the schema and mapping from them as well. It's using the Db2i driver as well, but on Linux. ### PHP Version PHP 8.1.16 ### Operating System Ubuntu 22.04

« previous php.bugs (#243907) next »