| Bug #48699 | c/ODBC cuts BINARY parameter after encountering first 00 | ||
|---|---|---|---|
| Submitted: | 11 Nov 2009 20:10 | Modified: | 19 Nov 2009 15:15 |
| Reporter: | Tonci Grgin | Email Updates: | |
| Status: | Not a Bug | Impact on me: | |
| Category: | Connector / ODBC | Severity: | S2 (Serious) |
| Version: | all | OS: | Any |
| Assigned to: | Lawrenty Novitsky | CPU Architecture: | Any |
[13 Nov 2009 8:32]
Tonci Grgin
Bug#48752 was marked as duplicate of this report.
[13 Nov 2009 9:54]
Bogdan Degtyariov
patch and test case
Attachment: patch48699.diff (text/x-diff), 2.96 KiB.
[13 Nov 2009 9:56]
Bogdan Degtyariov
The initial test case does not reproduce the problem because it does not use row-wise parameter binding. Please see the test case in the attached file.
[13 Nov 2009 16:20]
Lawrenty Novitsky
If we agree this is not a bug, and i tend to think so, the outcome of this bug should be following patch:
=== modified file 'driver/execute.c'
--- driver/execute.c 2009-10-07 20:43:23 +0000
+++ driver/execute.c 2009-11-13 16:15:14 +0000
@@ -276,13 +276,20 @@
*toptr= add_to_buffer(net,*toptr,"NULL",4);
return SQL_SUCCESS;
}
+ /*
+ According to http://msdn.microsoft.com/en-us/library/ms710963%28VS.85%29.aspx
+
+ "... If StrLen_or_IndPtr is a null pointer, the driver assumes that all^M
+ input parameter values are non-NULL and that character and *binary* data
+ is null-terminated."
+ */
else if (!octet_length_ptr || *octet_length_ptr == SQL_NTS)
{
if (data)
{
if (aprec->concise_type == SQL_C_WCHAR)
length= sqlwcharlen((SQLWCHAR *)data) * sizeof(SQLWCHAR);
- else /* TODO this is stupid, check condition above, shouldn't we be checking only octet_length, not ptr? */
+ else
length= strlen(data);
if (!octet_length_ptr && aprec->octet_length > 0 &&
Because seems like quote from msdn answers the question in the comment this patch removes.
[16 Nov 2009 4:08]
Bogdan Degtyariov
Lawrin, thank you. Confirmed as not a bug.
[19 Nov 2009 7:57]
Tonci Grgin
Lawrin, Bogdan: We should check on this again... The above msdn link quote is only applied to null pointer value for StrLen_or_IndPtr parameter for SQLBindParameter. But not for when one calls SQLBinParameter for SQL_C_BINARY type, passing the number of bytes in C binary structure and not a null pointer for StrLen_or_IndPtr. As you see in my example, the value for input parameter StrLen_or_IndPtr for SQLBindParameter is len= strlen(buf); Following quote from MSDN should apply: http://msdn.microsoft.com/en-us/library/ms710963%28VS.85%29.aspx: StrLen_or_IndPtr Argument The StrLen_or_IndPtr argument points to a buffer that, when SQLExecute or SQLExecDirect is called, contains one of the following. (This argument sets the SQL_DESC_OCTET_LENGTH_PTR and SQL_DESC_INDICATOR_PTR record fields of the application parameter pointers.) * The length of the parameter value stored in *ParameterValuePtr. This is ignored except for character or binary C data. * SQL_NTS. The parameter value is a null-terminated string. Lawrentiy, please recheck your ruling.
[19 Nov 2009 15:15]
Lawrenty Novitsky
If to change in Tonci's example len= strlen() to len= 5, everything is gonna work just fine. strlen won't work here, because it stops counting bytes on first 0 byte. You can test the value - it will be 1. Value pointed by StrLen_Or_IndicatorPtr is used as number of bytes to copy from binary parameter. I believe that is in full accordance with the given quote from MSDN.

Description: Using following test case one can see in server log that only the value #80 gets inserted: CHAR buf[5]; SQLINTEGER len; buf[0] = '\128'; buf[1] = '\00'; buf[2] = '\CE'; buf[3] = '\C4'; buf[4] = '\88'; len= strlen(buf); buf[5]= 0; SQLRETURN rc; SQLHENV henv; SQLHDBC hdbc; SQLHSTMT hstmt; rc = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv); if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) return(-1); rc = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, SQL_NTS); if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) return(-1); rc = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc); if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) return(-1); std::cout << "Connecting to " << "5-1-5-on-opensol" << std::endl; rc = SQLConnect(hdbc, (SQLCHAR *)"5-1-5-on-opensol", SQL_NTS, (SQLCHAR *)"root", SQL_NTS, (SQLCHAR *)"***", SQL_NTS); if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) return(-1); rc = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) return(-1); rc=SQLExecDirect(hstmt, (SQLCHAR *)"drop table if exists issuexx", SQL_NTS); rc=SQLExecDirect(hstmt, (SQLCHAR *)"create table issuexx (id integer NOT NULL PRIMARY KEY, obj BINARY(5)) DEFAULT CHARSET UTF8", SQL_NTS); if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) return(-1); rc = (hstmt, SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_BINARY, 5, 0, buf, 0, &len));//SQL_LONGVARCHAR SQL_WCHAR if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) return(-1); rc = SQLExecDirect(hstmt, (SQLCHAR *)"insert into issuexx(id, obj) values(1, ?)", SQL_NTS); if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) return(-1); std::cout << "Success:" << "test done" << std::endl; return 0; How to repeat: See above. Further more, if first byte is "00" the execution will break with error in syntax. Suggested fix: -