2013-03-28 72 views
3

在unixODBC中使用Informix 64位驅動程序(默認爲Redhat和2.3.1附帶的2.2.14),並在列有空值時運行到問題 。 unixODBC使用SQLLEN作爲(last) StrLen_or_Ind參數,而Informix 64位驅動程序似乎使用SQLINTEGER。帶有64位unixODBC的Informix段錯誤

所以在測試時,如果返回值是SQL_NULL_DATA測試沒有由於值-1(其SQL_NULL_DATA被定義爲)作爲32位整數工作.. 是 4294967296時爲64位整數進行處理。

我在PHP ODBC中使用驅動程序時發現此問題,因爲它導致 段錯誤。有誰知道解決方法?我想有一個自定義編譯的unixODBC和PHP與Informix ODBC驅動程序的工作,但那麼它不會與其他ODBC驅動程序:(

下面是我寫來測試這一個簡單的C程序正常工作。

#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; 
} 

回答

3

這是Informix ODBC驅動程序的CSDK 3.70及更早版本的已知問題。

昨天(2013年3月26日),IBM發佈了IBM的Informix 12.10.xC1和同伴IBM的Informix ClientSDK 4.10.xC1。那裏的ODBC版本應該有用於SQLLEN和SQLULEN的正確的64位類型。

這意味着如果你得到升級,你應該沒問題。這意味着任何代碼都需要用新版本的ODBC重新編譯。這也意味着某些(商業)ODBC驅動程序管理器在Informix 3.70及更早版本中解決奇怪問題(缺陷)時需要重新構建,或配置爲使用標準64位驅動程序接口而不是錯誤的Informix接口新的4.10驅動程序。

+0

哇..非常感謝你! – grom 2013-03-28 05:33:59

+0

現在我在整數字段上得到NULL的段錯誤。有任何想法嗎? – grom 2013-04-02 01:03:55

+0

簡潔,沒有。你能創造一個最小的repro? – 2013-04-02 01:20:02