Informix with 64bit unixODBC segfault

在unixODBC中使用Informix 64位驱动程序(Redhat和2.3.1的缺省值为2.2.14),并在列有空值时出现问题。 unixODBC使用SQLLEN作为(最后一个)StrLen_or_Ind参数,而Informix 64位驱动程序似乎使用SQLINTEGER。

因此,当testing返回值是否为SQL_NULL_DATA时,testing不起作用。因为当作为64位整数处理时,值为-1(其中SQL_NULL_DATA被定义为)32位整数是4294967296。

当使用PHP ODBC驱动程序时,我发现这个问题,因为它导致了段错误。 有谁知道一个解决方法? 我想有一个自定义编译的unixODBC和PHP的工作与Informix的ODBC驱动程序,但它不能正常工作与其他ODBC驱动程序:(

下面是我写的一个简单的C程序来testing这个。

#include <stdio.h> #include <stdlib.h> #include <sql.h> #include <sqlext.h> typedef struct odbc_connection { SQLHENV henv; SQLHDBC hdbc; } odbc_connection; typedef struct odbc_result_value { char name[32]; char *value; SQLLEN vallen; SQLLEN coltype; } odbc_result_value; typedef struct odbc_result { SQLHSTMT stmt; odbc_result_value *values; SQLSMALLINT numcols; odbc_connection *conn; } odbc_result; int print_error (SQLHENV henv, SQLHDBC hdbc, SQLHSTMT hstmt) { SQLCHAR buffer[SQL_MAX_MESSAGE_LENGTH + 1]; SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1]; SQLINTEGER sqlcode; SQLSMALLINT length; while ( SQLError(henv, hdbc, hstmt, sqlstate, &sqlcode, buffer, SQL_MAX_MESSAGE_LENGTH + 1, &length) == SQL_SUCCESS ) { printf("\n **** ERROR *****\n"); printf(" SQLSTATE: %s\n", sqlstate); printf("Native Error Code: %ld\n", sqlcode); printf("%s \n", buffer); }; return ( SQL_ERROR); } int terminate(SQLHENV henv, SQLHDBC hdbc) { SQLRETURN rc; rc = SQLDisconnect (hdbc); /* disconnect from database */ if (rc != SQL_SUCCESS ) print_error (henv, hdbc, SQL_NULL_HSTMT); rc = SQLFreeConnect (hdbc); /* free connection handle */ if (rc != SQL_SUCCESS ) print_error (henv, hdbc, SQL_NULL_HSTMT); rc = SQLFreeEnv (henv); /* free environment handle */ if (rc != SQL_SUCCESS ) print_error (henv, hdbc, SQL_NULL_HSTMT); return(rc); } int check_error (SQLHENV henv, SQLHDBC hdbc, SQLHSTMT hstmt, SQLRETURN frc) { SQLRETURN rc; print_error(henv, hdbc, hstmt); switch (frc){ case SQL_SUCCESS : break; case SQL_ERROR : case SQL_INVALID_HANDLE: printf("\n ** FATAL ERROR, Attempting to rollback transaction**\n"); rc = SQLTransact(henv, hdbc, SQL_ROLLBACK); if (rc != SQL_SUCCESS) printf("Rollback Failed, Exiting application\n"); else printf("Rollback Successful, Exiting application\n"); terminate(henv, hdbc); exit(frc); break; case SQL_SUCCESS_WITH_INFO : printf("\n ** Warning Message, application continuing\n"); break; case SQL_NO_DATA_FOUND : printf("\n ** No Data Found ** \n"); break; default : printf("\n ** Invalid Return Code ** \n"); printf(" ** Attempting to rollback transaction **\n"); SQLTransact(henv, hdbc, SQL_ROLLBACK); terminate(henv, hdbc); exit(frc); break; } return(SQL_SUCCESS); } odbc_connection* odbc_connect(char *dsn, char *user, char* password) { SQLRETURN rc; odbc_connection *conn; conn = (odbc_connection *) malloc(sizeof(odbc_connection)); // Allocate environment handle rc = SQLAllocEnv(&conn->henv); if (rc != SQL_SUCCESS) { printf("Unable to allocate environment\n"); check_error(conn->henv, conn->hdbc, SQL_NULL_HSTMT, rc); } // Allocate connection handle rc = SQLAllocConnect(conn->henv, &conn->hdbc); if (rc != SQL_SUCCESS) { printf("Unable to allocate connection handle\n"); check_error(conn->henv, conn->hdbc, SQL_NULL_HSTMT, rc); } // Connect to database rc = SQLConnect(conn->hdbc, dsn, SQL_NTS, user, SQL_NTS, password, SQL_NTS); if (rc != SQL_SUCCESS) { printf("Unable to connect\n"); check_error(conn->henv, conn->hdbc, SQL_NULL_HSTMT, rc); } return conn; } odbc_result* odbc_query(odbc_connection *conn, char *sql) { SQLRETURN rc; odbc_result *result; int i; SQLSMALLINT colnamelen; /* Not used */ SQLLEN displaysize; result = (odbc_result *) malloc(sizeof(odbc_result)); result->conn = conn; rc = SQLAllocStmt(conn->hdbc, &(result->stmt)); if (rc != SQL_SUCCESS) { printf("Unable to allocate statement\n"); check_error(conn->henv, conn->hdbc, SQL_NULL_HSTMT, rc); } rc = SQLExecDirect(result->stmt, sql, SQL_NTS); if (rc != SQL_SUCCESS) { printf("Unable to execute statement\n"); check_error(conn->henv, conn->hdbc, SQL_NULL_HSTMT, rc); } SQLNumResultCols(result->stmt, &(result->numcols)); if (result->numcols > 0) { // Bind columns result->values = (odbc_result_value *) malloc(sizeof(odbc_result_value) * result->numcols); for (i = 0; i < result->numcols; i++) { rc = SQLColAttributes(result->stmt, (SQLUSMALLINT)(i+1), SQL_COLUMN_NAME, result->values[i].name, sizeof(result->values[i].name), &colnamelen, 0); rc = SQLColAttributes(result->stmt, (SQLUSMALLINT)(i+1), SQL_COLUMN_TYPE, NULL, 0, NULL, &result->values[i].coltype); rc = SQLColAttributes(result->stmt, (SQLUSMALLINT)(i+1), SQL_COLUMN_DISPLAY_SIZE, NULL, 0, NULL, &displaysize); result->values[i].value = (char *) malloc(sizeof(char) * (displaysize + 1)); rc = SQLBindCol(result->stmt, (SQLUSMALLINT)(i+1), SQL_C_CHAR, result->values[i].value, displaysize + 1, &result->values[i].vallen); } } return result; } int odbc_print_row(odbc_result *result) { SQLRETURN rc; int i; rc = SQLFetch(result->stmt); if (rc != SQL_SUCCESS) { return 0; } for (i = 0; i < result->numcols; i++) { /* BUG: the 64 bit informix driver here is has returned a 32 bit -1 integer but is stored in a 64 integer field */ if (result->values[i].vallen == SQL_NULL_DATA) { printf("NULL;"); } else { printf("\""); printf("%s", result->values[i].value); printf("\";"); } } printf("\n"); return 1; } int main(int argc, char *argv[]) { odbc_connection* conn; odbc_result *result; conn = odbc_connect("authlive", "auth", "xxx"); result = odbc_query(conn, argv[1]); while (odbc_print_row(result)); SQLFreeStmt(result->stmt, SQL_CLOSE); free(result); terminate(conn->henv, conn->hdbc); free(conn); return 0; } 

这是CSDK 3.70和早期版本的Informix ODBC驱动程序中的已知问题。

昨天(2013-03-26),IBM发布了IBM Informix 12.10.xC1和配套的IBM Informix ClientSDK 4.10.xC1。 那里的ODBC版本应该有SQLLEN和SQLULEN的正确的64位类型。

这意味着如果你升级了,你应该没问题。 这意味着任何代码都需要用新版本的ODBC重新编译。 这也意味着某些(商业)ODBC驱动程序管理器在Informix 3.70及更早版本中的怪异(bug)工作将需要重建,或配置为使用标准的64位驱动程序接口,而不是使用错误的Informix接口新的4.10驱动程序。