| Bug #1316 | Sending long data by SQLBindSQLPutData and SQLParamData | ||
|---|---|---|---|
| Submitted: | 16 Sep 2003 23:55 | Modified: | 16 Oct 2003 22:33 |
| Reporter: | Lev Kadisov | Email Updates: | |
| Status: | Closed | Impact on me: | |
| Category: | Connector / ODBC | Severity: | S2 (Serious) |
| Version: | 3.51.06.00 & 2.50.39.00 | OS: | Windows (Win98) |
| Assigned to: | Venu Anuganti | CPU Architecture: | Any |
[17 Sep 2003 1:18]
Lev Kadisov
Previous and this code (SQLPutData) works with Borland Firebird 1.5 without any problem!
But with MySQL and MyODBC exist small problem.
If I'am dynamic binding all parameters by next code.
const int POS_ID =1;
const int POS_TIME_SEC = 2;
const int POS_TIME_MSEC = 3;
const int POS_BLOBLEN = 4;
const int POS_BLOB_DATA = 5;
resId = dynData ? SQL_LEN_DATA_AT_EXEC(0) : 0;
resUTimeSec = dynData ? SQL_LEN_DATA_AT_EXEC(0) : 0;
resUTimeMSec = dynData ? SQL_LEN_DATA_AT_EXEC(0) : 0;
resDataLen = dynData ? SQL_LEN_DATA_AT_EXEC(0) : 0;
resData = dynData ? SQL_LEN_DATA_AT_EXEC(0) : datalen;
SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_SLONG,
SQL_INTEGER, 0, 0, dynData ? (SQLPOINTER) POS_ID : &id, 0, &resId);
SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_SLONG,
SQL_INTEGER, 0, 0,
dynData ? (SQLPOINTER) POS_TIME_SEC : &u_time.tm, 0, &resUTimeSec);
SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_SLONG,
SQL_INTEGER, 0, 0,
dynData ? (SQLPOINTER) POS_TIME_MSEC : &u_time.cnt, 0, &resUTimeMSec);
SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_SLONG,
SQL_INTEGER, 0, 0,
dynData ? (SQLPOINTER) POS_BLOBLEN : &commonLen, 0, &resDataLen);
SQLBindParameter(stmt, POS_BLOB_DATA, SQL_PARAM_INPUT,
SQL_C_BINARY,
SQL_LONGVARBINARY, 0, 0,
dynData ?
(SQLPOINTER) POS_BLOB_DATA
: pdata,
0, &resData);
then
exception exist at address 01556cc3
at last call SQLParamData() for parameter 5 (POS_BLOB_DATA) after all SQLParamData() and SQLPutData() for parameters 1,2,3,4 in myodbc3.dll.
registers:
EAX = 0065FA42 EBX = 016D1F00
ECX = 0000000C EDX = 00000006
ESI = 00000001 EDI = 015C8A4C
EIP = 01556CC3 ESP = 0065F478
EBP = 015C8A4C EFL = 00010246
CS = 018F DS = 0197 ES = 0197
SS = 0197 FS = 8A8F GS = 0000 OV=0
UP=0 EI=1 PL=0 ZR=1 AC=0 PE=1 CY=0
00000001 = ????????
ST0 = +0.00000000000000000e+0000
ST1 = +0.00000000000000000e+0000
ST2 = +0.00000000000000000e+0000
ST3 = +0.00000000000000000e+0000
ST4 = +0.00000000000000000e+0000
ST5 = +0.00000000000000000e+0000
ST6 = +0.00000000000000000e+0000
ST7 = +1.00000000000000000e+0000
CTRL = 027F STAT = 0020 TAGS = FFFF
EIP = 7FC348FA CS = 018F DS = 0197
EDO = 0065D354
01556BF9 push 4
01556BFB push 157F0E0h
01556C00 push edx
01556C01 push eax
01556C02 call 01556960
01556C07 add esp,10h
01556C0A pop edi
01556C0B pop esi
01556C0C pop ebp
01556C0D pop ebx
01556C0E add esp,80h
01556C14 ret
01556C15 mov esi,dword ptr [ebp+4]
01556C18 test esi,esi
01556C1A je 01556C3F
01556C1C mov eax,dword ptr [ebp+10h]
01556C1F test eax,eax
01556C21 je 01556C2F
01556C23 push eax
01556C24 push esi
01556C25 call 01562E40
01556C2A add esp,8
01556C2D jmp 01556C41
01556C2F or ecx,0FFh
01556C32 xor eax,eax
01556C34 mov edi,esi
01556C36 repne scas byte ptr [edi]
01556C38 not ecx
01556C3A dec ecx
01556C3B mov eax,ecx
01556C3D jmp 01556C41
01556C3F xor eax,eax
01556C41 movsx ecx,word ptr [ebp+2]
01556C45 add ecx,1Ch
01556C48 cmp ecx,79h
01556C4B ja 01556E01
01556C51 xor edx,edx
01556C53 mov dl,byte ptr [ecx+1557018h]
01556C59 jmp dword ptr [edx*4+1556FDCh]
01556C60 mov bl,1
01556C62 jmp 01556E01
01556C67 movsx ecx,byte ptr [esi]
01556C6A push 0F6h
01556C6C lea eax,[esp+14h]
01556C70 push eax
01556C71 push ecx
01556C72 call 015619A0
01556C77 add esp,0Ch
01556C7A jmp 01556D14
01556C7F xor ecx,ecx
01556C81 mov cl,byte ptr [esi]
01556C83 push 0F6h
01556C85 lea eax,[esp+14h]
01556C89 push eax
01556C8A push ecx
01556C8B call 015619A0
01556C90 add esp,0Ch
01556C93 jmp 01556D14
01556C95 movsx ecx,word ptr [esi]
01556C98 push 0F6h
01556C9A lea eax,[esp+14h]
01556C9E push eax
01556C9F push ecx
01556CA0 call 015619A0
01556CA5 add esp,0Ch
01556CAF push 0F6h
01556CB1 lea eax,[esp+14h]
01556CB5 push eax
01556CB6 push ecx
01556CB7 call 015619A0
01556CBC add esp,0Ch
01556CBF jmp 01556D14
01556CC1 push 0F6h
01556CC3 mov ecx,dword ptr [esi] // this is point of exception
01556CC5 lea eax,[esp+14h]
01556CC9 push eax
01556CCA push ecx
01556CCB call 015619A0
01556CD0 add esp,0Ch
01556CD3 jmp 01556D14
01556CD5 push 0Ah
01556CD7 jmp 01556CC3
01556CD9 mov ecx,dword ptr [esi+4]
01556CDC mov edx,dword ptr [esi]
01556CDE push 0F6h
01556CE0 lea eax,[esp+14h]
01556CE4 push eax
01556CE5 push ecx
01556CE6 push edx
01556CE7 call 01562D20
01556CEC lea ecx,[esp+20h]
01556CF0 add esp,10h
01556CF3 sub eax,ecx
01556CF5 lea esi,[esp+10h]
01556CF9 jmp 01556E01
01556CFE mov eax,dword ptr [esi+4]
01556D01 mov ecx,dword ptr [esi]
01556D03 push 0Ah
01556D05 lea edx,[esp+14h]
01556D09 push edx
01556D0A push eax
01556D0B push ecx
01556D0C call 01562D20
01556D11 add esp,10h
01556D14 lea edx,[esp+10h]
[17 Sep 2003 1:42]
Lev Kadisov
OS is Windows98, but not 95.
[6 Oct 2003 0:20]
Venu Anuganti
Hi !! I tried to reproduce this, but no luck.. it just works fine at my end.. Here is a simple test and its output /* Test for a simple SQLPutData and SQLParamData handling bug #1316 */ static void t_putdata3(SQLHDBC hdbc, SQLHSTMT hstmt) { char buffer[]= "MySQL - The worlds's most popular open source database"; SQLRETURN rc; const int MAX_PART_SIZE = 5; char *pdata= 0, data[50]; int dynData; int commonLen= 20; SQLINTEGER id, id1, id2, id3, resId; SQLINTEGER resUTimeSec; SQLINTEGER resUTimeMSec; SQLINTEGER resDataLen; SQLINTEGER resData; myheader("t_putdata3"); SQLExecDirect(hstmt,"drop table t_putdata3",SQL_NTS); rc = SQLExecDirect(hstmt,"CREATE TABLE t_putdata3 ( id INT, id1 INT, \ id2 INT, id3 INT, pdata blob);",SQL_NTS); mystmt(hstmt,rc); dynData = 1; rc = SQLPrepare(hstmt, "INSERT INTO t_putdata3 VALUES ( ?, ?, ?, ?, ? )", SQL_NTS); mystmt(hstmt,rc); id= 1, id1= 2, id2= 3, id3= 4; resId = 0; resUTimeSec = 0; resUTimeMSec = 0; resDataLen = 0; resData = SQL_LEN_DATA_AT_EXEC(0); rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &id, 0, &resId); mystmt(hstmt,rc); rc = SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &id1, 0, &resUTimeSec); mystmt(hstmt,rc); rc = SQLBindParameter(hstmt, 3, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &id2, 0, &resUTimeMSec); mystmt(hstmt,rc); rc = SQLBindParameter(hstmt, 4, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &id3, 0, &resDataLen); mystmt(hstmt,rc); rc = SQLBindParameter(hstmt, 5, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, 10, 10, dynData ? (SQLPOINTER)5 : pdata, 0, &resData); mystmt(hstmt,rc); rc = SQLExecute(hstmt); if (rc == SQL_NEED_DATA) { int parameter; if (SQLParamData(hstmt,(void**)¶meter) == SQL_NEED_DATA && parameter == 5) { int len = 0; int partsize; /* storing long data by parts */ while (len < commonLen) { partsize = commonLen - len; if (partsize > MAX_PART_SIZE) partsize = MAX_PART_SIZE; rc = SQLPutData(hstmt, buffer+len, partsize); mystmt(hstmt,rc); len += partsize; } if (SQLParamData(hstmt,(void**)¶meter) == SQL_ERROR) { } } } /* end if (rc == SQL_NEED_DATA) */ SQLFreeStmt(hstmt, SQL_UNBIND); SQLFreeStmt(hstmt, SQL_CLOSE); rc = tmysql_exec(hstmt,"select id, id1, id2, id3, convert(pdata,char) from t_putdata3"); mystmt(hstmt,rc); rc = SQLFetch(hstmt); my_assert(1 == my_fetch_int(hstmt,1)); my_assert(2 == my_fetch_int(hstmt,2)); my_assert(3 == my_fetch_int(hstmt,3)); my_assert(4 == my_fetch_int(hstmt,4)); my_assert(strncmp(buffer, my_fetch_str(hstmt,data,5), commonLen) == 0); rc = SQLFreeStmt(hstmt,SQL_CLOSE); mystmt(hstmt,rc); } output: ###################################### t_putdata3 ###################################### my_fetch_int: 1 my_fetch_int: 2 my_fetch_int: 3 my_fetch_int: 4 my_fetch_str: MySQL - The worlds's(20) Thanks
[13 Oct 2003 3:55]
Lev Kadisov
Hi!
Sorry for my careless mistake.
I not used functions after SQLFetch()
SQLFreeStmt(hstmt, SQL_UNBIND);
SQLFreeStmt(hstmt, SQL_CLOSE);
Now, all Ok.
Thanks.

Description: Calling SQLPutData() after several call SQLBindParameter() and one call SQLBindParameter() with SQL_LEN_DATA_AT_EXEC is damages links first parameters. I tested this error with MySQL 3.23 + MyODBC 2.50.39.00 and MySQL 4.0.13 + MyODBC 3.51.06.00. How to repeat: I created table 'objdata' by command by ODBC-function: CREATE TABLE objdata ( id INT NOT NULL, u_time_sec INT NOT NULL, u_time_msec INT NOT NULL, pdata_len INT NOT NULL, pdata BLOB NOT NULL ); or CREATE TABLE objdata ( id INT, u_time_sec INT, u_time_msec INT, pdata_len INT, pdata BLOB ); Then I want save my long data by several parts with ODBC: const int POS_BLOB_DATA = 5; const int MAX_PART_SIZE = 16; SQLHSTMT stmt; char *pdata; int datalen; int dynData; int commonLen; SQLLEN resUTimeSec; SQLLEN resUTimeMSec; SQLLEN resDataLen; SQLLEN resData; ....... dynData = 1; // If dynData = 1 then we will not use SQLPutData() // and SQLParamData() // if this dynData = 0 then all OK, data are correctly stored ! SQLPrepare(stmt, "INSERT INTO objdata VALUES ( ?, ?, ?, ?, ? )", SQL_NTS); ......... resId = 0; resUTimeSec = 0; resUTimeMSec = 0; resDataLen = 0; resData = dynData ? SQL_LEN_DATA_AT_EXEC(0) : datalen; sqlRes = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &id, 0, &resId); // check sqlRes - always OK ......... sqlRes = SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &u_time.tm, 0, &resUTimeSec); // check sqlRes - always OK ......... sqlRes = SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &u_time.cnt, 0, &resUTimeMSec); // check sqlRes - always OK ......... sqlRes = SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &commonLen, 0, &resDataLen); // check sqlRes - always OK ......... sqlRes = SQLBindParameter(stmt, POS_BLOB_DATA, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, 0, 0, dynData ? (SQLPOINTER) POS_BLOB_DATA : pdata, 0, &resData); // check sqlRes - always OK sqlRes = SQLExecute(stmt); if(sqlRes == SQL_NEED_DATA) { // this code executing when dynData == 1 int parameter; if(SQLParamData(stmt,(void**)¶meter) == SQL_NEED_DATA && parameter == POS_BLOB_DATA) { int len = 0; int partsize; // storing long data by parts while (len < commonLen) { partsize = commonLen - len; if(partsize > MAX_PART_SIZE) partsize = MAX_PART_SIZE; sqlRes = SQLPutData(stmt, buffer+len, partsize); if(sqlRes == SQL_ERROR) return ...; // Always OK, not SQL_ERROR! len += partsize; } if(SQLParamData(stmt,(void**)¶meter) == SQL_ERROR) PrintDiagCode(); // Print state and error text // This is printed ERROR if columns (1,2,3,4): // id , u_time_sec , u_time_msec , pdata_len // are created with flag 'not NULL' // Another, if 'NULL' is permited, // this parameters take value NULL, blob pdata is correctly stored // and SQLParamData() return SQL_SUCCESS! // But I not wanted 'NULL', I setted values. } } // end if(sqlRes == SQL_NEED_DATA) else if(sqlRes == SQL_SUCCESS) { // this code executing when dynData == 0 // all data always correctly stored ....... Suggested fix: Check it.