Подключение к версии 11.50 версии IDS с включенным ведением журнала транзакций:
onstat -version
Program Name: onstat
Build Version: 11.50.UC5XE
Build Number: N104
Build Host: ku
Build OS: Linux kernel-2.6.9-34.ELsmp glibc-2.3.4-2.19 compat-glibc-2.3.2-95.30
Build Date: Thu Jul 15 12:44:25 CDT 2010
GLS Version: glslib-4.50.UC6
Использование UnixODBC 2.2.11 поверх версии 3.50UC8 драйверов Connect в той же системе, что и экземпляр IDS (RHEL 4.8 32-bit) или удаленная система, работающая под управлением CentOS 4.8 32-bit.Я получаю segfault всякий раз, когда пытаюсь вставить BLOB в базу данных.
Вот пример кода, демонстрирующий проблему:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sqlext.h>
#define CONNECTION_STRING "<valid connection string>"
#define CREATE_TABLE "CREATE TABLE blob_test(id SERIAL, test BLOB)"
#define INSERT_BLOB "INSERT INTO blob_test(test) VALUES(?)"
#define BLOB_SIZE 4096
int main(int argc, const char ** args) {
printf("Informix ODBC BLOB test.\n");
int exitCode = 0;
SQLHENV henv;
SQLHDBC hdbc;
SQLHSTMT hstmt;
SQLLEN ind;
SQLRETURN ret;
char data[BLOB_SIZE];
char * paramData = NULL;
// Allocate environment handle
if(!SQL_SUCCEEDED(SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv))) {
printf("Failed to allocate environment handle.\n");
goto exit;
}
if(!SQL_SUCCEEDED(SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0))) {
printf("Failed to initialize environment handle.\n");
goto cleanup_env;
}
// Connect
if(!SQL_SUCCEEDED(SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc))) {
printf("Failed to allocate connection handle.\n");
goto cleanup_env;
}
if(!SQL_SUCCEEDED(SQLDriverConnectA(hdbc, NULL,
(SQLCHAR *)CONNECTION_STRING, SQL_NTS,
NULL, 0, NULL, SQL_DRIVER_COMPLETE))) {
printf("Failed to connect.\n");
goto cleanup_dbc;
}
printf("Connected.\n");
// Allocate statement
if(!SQL_SUCCEEDED(SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt))) {
printf("Failed to allocate statement handle.\n");
goto disconnect;
}
//Create table
if(!SQL_SUCCEEDED(SQLExecDirectA(hstmt,
(SQLCHAR *)CREATE_TABLE, strlen(CREATE_TABLE)))) {
printf("Failed to create table.\n");
//continue anyway
} else {
printf("Created test table.\n");
}
//Prepare data
memset(data, 0, BLOB_SIZE);
//Prepare statement
if(!SQL_SUCCEEDED(SQLPrepareA(hstmt,
(SQLCHAR *)INSERT_BLOB, strlen(INSERT_BLOB)))) {
printf("Failed to prepare statement.\n");
goto cleanup_stmt;
}
//Bind data
ind = SQL_LEN_DATA_AT_EXEC(BLOB_SIZE);
if(!SQL_SUCCEEDED(SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_BINARY,
SQL_LONGVARBINARY, BLOB_SIZE, 0, &data, 0, &ind))) {
printf("Failed to bind blob.\n");
goto cleanup_stmt;
}
//Execute
printf("Inserting BLOB.\n");
ret = SQLExecute(hstmt);
if(SQL_NEED_DATA == ret) {
//send additional data
ret = SQLParamData(hstmt,
reinterpret_cast<SQLPOINTER *>(¶mData));
if(paramData != data) {
printf("Warning, data pointers(%p,%p) do not match!\n", data, paramData);
}
while(SQL_NEED_DATA == ret) {
ret = SQLPutData(hstmt, data, BLOB_SIZE);
if(!SQL_SUCCEEDED(ret)) {
printf("Error setting parameter data.\n");
goto cleanup_stmt;
}
//Read the next parameter requiring data, if any
/**
* ===== CRASH HAPPENS ON THIS LINE =====
*/
ret = SQLParamData(hstmt,
reinterpret_cast<SQLPOINTER *>(¶mData));
}
}
if(!SQL_SUCCEEDED(ret)) {
printf("Failed to execute.\n");
goto cleanup_stmt;
}
printf("Inserted blob data.\n");
cleanup_stmt:
printf("Freeing hstmt.\n");
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
disconnect:
printf("Disconnecting.\n");
SQLDisconnect(hdbc);
cleanup_dbc:
printf("Freeing hdbc.\n");
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
cleanup_env:
printf("Freeing henv.\n");
SQLFreeHandle(SQL_HANDLE_ENV, henv);
exit:
return exitCode;
}
Makefile:
blob_test : main.cpp
g++ -o blob_test -l odbc main.cpp
Итрассировка стека:
#0 0x00a07363 in memmove () from /lib/tls/libc.so.6
#1 0x001fccbe in _iwrite () from /opt/informix/lib/cli/iclit09b.so
#2 0x001fb431 in _iputpbuf () from /opt/informix/lib/cli/iclit09b.so
#3 0x00184c42 in _Odbcputpbuf () from /opt/informix/lib/cli/iclit09b.so
#4 0x00182cc8 in _OdbcPutChstrNoCsc () from /opt/informix/lib/cli/iclit09b.so
#5 0x00164b4f in _OdbcPutAsfLvarcharVal () from /opt/informix/lib/cli/iclit09b.so
#6 0x001acef8 in _OdbcExtBinary2IntSendrecv () from /opt/informix/lib/cli/iclit09b.so
#7 0x0016ca48 in _OdbcPutBindings () from /opt/informix/lib/cli/iclit09b.so
#8 0x0016c836 in _OdbcAssignInputParams () from /opt/informix/lib/cli/iclit09b.so
#9 0x0016d373 in _OdbcExecute () from /opt/informix/lib/cli/iclit09b.so
#10 0x0014c125 in _OdbcExecuteRow () from /opt/informix/lib/cli/iclit09b.so
#11 0x0014c3a4 in SQLParamData () from /opt/informix/lib/cli/iclit09b.so
#12 0x00b17f09 in SQLParamData () from /usr/lib/libodbc.so.1
#13 0x08048a16 in main ()
И наконец, трассировка от драйвера odbc:
[ODBC][26114][SQLPrepare.c][189]
Entry:
Statement = 0x9e56060
SQL = [INSERT INTO blob_test(test) VALUES(?)][length = 37]
[ODBC][26114][SQLPrepare.c][364]
Exit:[SQL_SUCCESS]
[ODBC][26114][SQLBindParameter.c][193]
Entry:
Statement = 0x9e56060
Param Number = 1
Param Type = 1
C Type = -2 SQL_C_BINARY
SQL Type = -4 SQL_LONGVARBINARY
Col Def = 4096
Scale = 0
Rgb Value = 0xbfe9a990
Value Max = 0
StrLen Or Ind = 0xbfe9b99c
[ODBC][26114][SQLBindParameter.c][339]
Exit:[SQL_SUCCESS]
[ODBC][26114][SQLExecute.c][183]
Entry:
Statement = 0x9e56060
[ODBC][26114][SQLExecute.c][344]
Exit:[SQL_NEED_DATA]
[ODBC][26114][SQLParamData.c][156]
Entry:
Statement = 0x9e56060
Value = 0xbfe9a98c
[ODBC][26114][SQLParamData.c][327]
Exit:[SQL_NEED_DATA]
Value = 0xbfe9a990
[ODBC][26114][SQLPutData.c][144]
Entry:
Statement = 0x9e56060
Data = 0xbfe9a990
StrLen = 4096
[ODBC][26114][SQLPutData.c][289]
Exit:[SQL_SUCCESS]
[ODBC][26114][SQLParamData.c][156]
Entry:
Statement = 0x9e56060
Value = 0xbfe9a98c
Я что-то упустил или у меня где-то есть посторонний вызов?