将 32 位 Informix ODBC 应用程序迁移到 64 位模式

Informix® 64 位 ODBC 驱动程序二进制文件在许多年前就已经可用,但是直到 2013 年初发布 Informix Client SDK v4.10 时才推出真正的 64 位 Informix ODBC 驱动程序。本文将讨论 Informix ODBC 驱动程序的 64 位二进制文件与真正的 64 位驱动程序的差别。同时,您还将了解如何迁移当前的 32 位或 64 位 Informix ODBC 应用程序,从而能够利用真正的 64 位驱动程序。

Yunming Wang, 高级支持工程师, IBM

Yunming Wang 是 IBM Informix Advanced Problem Diagnostics (APD) 团队的高级支持工程师。他从 1998 年开始在 IBM 负责 Informix 方面的工作,专注于 Informix 和 DB2 编程 API 和数据库连接。专业领域包括 ODBC、JDBC、OLEDB/.Net、ESQL/C 和 TCP/IP。最近,他加入了一个 IDS 虚拟应用程序项目,负责处理虚拟化和云计算技术。在加入 Informix 之前,他是一名软件开发人员。他于 1995 年获得了阿肯色大学(University of Arkansas)的计算机工程硕士学位。



Yunming Wang, 高级支持工程师, IBM

Yunming WangYunming Wang 是 Informix Advanced Problem Diagnostics (APD) 团队的高级支持工程师。他从 1998 年开始在 IBM 负责 Informix 方面的工作,专注于 Informix 和 DB2 编程 API 和数据库连接。Yunming Wang 擅长的领域包括 ODBC、JDBC、OLEDB/.Net、ESQL/C 和 TCP/IP。在加入 Informix/IBM 之前,他是一名软件开发人员。他于 1995 年获得了阿肯色大学(University of Arkansas)的计算机系统工程硕士学位。



2014 年 7 月 10 日

简介

包括个人电脑在内的所有新计算机都支持 64 位处理能力。64 位系统与 32 位系统相比具有明显优势,因此越来越多的系统都运行在 64 位操作系统上。64 位操作系统可以处理 64 位宽度的整数位数和内存地址,这将在整体上提高性能和可扩展性。如果将 32 位和 64 位应用程序链接到 32 位库,那么 64 位系统可以同时运行 32 位和 64 位应用程序。

下载 Informix 数据库软件进行试用。

IBM Informix 从 Client SDK (CSDK) 2.20 版本开始附带了一个 64 位 Open Database Connectivity (ODBC) 库,适用于所有受支持的 UNIX® 平台,包括 AIX®、HP-UX、Solaris 等。对于 Linux® 和 Windows®,Informix 从 Client SDK 2.90 和 3.00 开始附带 64 位 ODBC 库。64 位 Informix ODBC 驱动程序的版本号包含字母 F,这表示该驱动程序是在 64 位模式下编译的,不受平台限制。例如,Informix Client SDK v3.70.FC7 表示客户机是在 64 位模式下构建的,所用的平台可以是 Windows、Linux 或 UNIX。4.10 版本以前的 Informix 64 位 ODBC 驱动程序实际上是 64 位二进制文件,并不包括真正的 64 位 ODBC API 包含的所有变更,因此不能与 64 位 ODBC 规范完全兼容。

IBM 在 IBM Informix Client SDK 4.10 版本中引入了第一个真正的 64 位 ODBC 驱动程序。这个新的 64 位 ODBC 驱动程序包含支持 64 位 ODBC 所需的所有变更,并且与 UNIX、Linux 和 Windows 上广泛使用的 64 位 ODBC 驱动程序管理器完全兼容。

本文将讨论 64 位二进制文件与驱动程序之间的差异。您将了解如何迁移旧的应用程序,从而能够利用真正的 64 位驱动程序。本文的所有代码和命令示例仅供演示使用。


32 位和 64 位 ODBC API 的差异

在将 32 位 ODBC 应用程序迁移到 64 位应用程序之前,您需要了解 32 位和 64 位 ODBC API 两者的差异。

总的来说,两者之间的差异在于 32 位 ODBC API 只能处理 4 字节内存地址指针和整数。在 64 位模式下重新编译现有的 32 位 ODBC 代码通常并不能满足需要,因为整数和长整数仍然保持 4 字节的宽度,即使内存地址指针变为 64 位。为了确保能够恰当地处理传递给 ODBC API 的 8 字节整数参数,64 位 ODBC 在 64 位平台上将 SQLLEN 和 SQLULEN 数据类型声明为 8 字节整数。

不同平台上 SQLLEN 和 SQLULEN 的声明方式各有不同。对于 32 位平台,SQLLEN 和 SQLULEN 分别被声明为 4 字节整数和无符号整数。对于 64 位平台,它们被声明为 8 字节整数和无符号整数。

例如,在 Windows 上,SQLLEN 和 SQLULEN 在 sqltypes.h 头文件中进行声明,如清单 1 所示。

清单 1. 在 Windows 上的 sqltypes.h 文件中声明 SQLLEN 和 SQLULEN
#ifdef _WIN64
typedef INT64           SQLLEN;
typedef UINT64          SQLULEN;
#else
#define SQLLEN          SQLINTEGER
#define SQLULEN         SQLUINTEGER
#endif

在 Linux 或 UNIX 上,您将看到 SQLLEN 和 SQLULEN 在 Progress DataDirect ODBC 的 sqltypes.h 头文件中以类似的方式进行声明,如清单 2 所示。

清单 2. 在 Linux 或 UNIX 上的 sqltypes.h 文件中声明 SQLLEN 和 SQLULEN
#if defined(ODBC64)
typedef INT64           SQLLEN;
typedef UINT64          SQLULEN;
#else
#define SQLLEN          SQLINTEGER
#define SQLULEN         SQLUINTEGER
#endif

相应地,对指针设置和获取的一些 ODBC 函数和描述符字段也进行了修改,使之适应使用 SQLLEN 或 SQLULEN 的 64 位值。例如,SQLColAttribute() 函数在 64 位 Microsoft sqltypes.h 头文件中以不同的方式进行声明,如清单 3 所示。

清单 3. Microsoft ODBC 中的 SQLColAttribute() 声明
#ifdef _WIN64
SQLRETURN  SQL_API SQLColAttribute (
           SQLHSTMT StatementHandle,
           SQLUSMALLINT ColumnNumber, SQLUSMALLINT FieldIdentifier,
           __out_bcount_opt(BufferLength) SQLPOINTER CharacterAttribute,
           SQLSMALLINT BufferLength,
           __out_opt SQLSMALLINT *StringLength,
           __out_opt SQLLEN *NumericAttribute);
#else
SQLRETURN  SQL_API SQLColAttribute (
           SQLHSTMT StatementHandle,
           SQLUSMALLINT ColumnNumber,
           SQLUSMALLINT FieldIdentifier,
           __out_bcount_opt(BufferLength) SQLPOINTER CharacterAttribute,
           SQLSMALLINT BufferLength,
           __out_opt SQLSMALLINT *StringLength,
           __out_opt SQLPOINTER NumericAttribute);
#endif

这个函数在 UNIX 和 Linux 上的 Progress DataDirect ODBC sql.h 头文件中以类似方式声明,如清单 4 所示。

清单 4. DataDirect ODBC sql.h 头文件中的 SQLColAttribute() 声明
#if defined(_WIN64) || defined(ODBC64)
SQLRETURN  SQL_API SQLColAttribute (
           SQLHSTMT StatementHandle,
           SQLUSMALLINT ColumnNumber,
           SQLUSMALLINT FieldIdentifier,
           SQLPOINTER CharacterAttribute,
           SQLSMALLINT BufferLength,
           SQLSMALLINT *StringLength,
           SQLLEN *NumericAttribute);
#else
SQLRETURN  SQL_API SQLColAttribute (
           SQLHSTMT StatementHandle,
           SQLUSMALLINT ColumnNumber,
           SQLUSMALLINT FieldIdentifier,
           SQLPOINTER CharacterAttribute,
           SQLSMALLINT BufferLength,
           SQLSMALLINT *StringLength,
           SQLPOINTER NumericAttribute);
#endif

在 Informix ODBC 驱动程序中,SQLLEN 和 SQLULEN 数据类型的声明方式类似于 ODBC 驱动程序管理器。因为 IBM 分别附带了 32 位和 64 位 Informix ODBC 驱动程序。根据 Informix ODBC 驱动程序的具体版本,SQLLEN 和 SQLULEN 将采用不同的方式在 infxsql.h 头文件中进行声明,不需要使用编译指令。

在 32 位 Informix ODBC 驱动程序和 64 位 Informix ODBC 驱动程序二进制文件 3.70 以及之前版本中,SQLLEN 和 SQLULEN 被定义为 4 字节整数。在清单 5 所示的例子中,SQLINTEGER 和 SQLUINTEGER 都是 4 字节整数,它们分别被定义为 sqlint32 和 unsqluint32。

清单 5. 32 位 Informix ODBC infxsql.h 头文件中的 SQLLEN 和 SQLULEN 声明
#define SQLLEN          SQLINTEGER
#define SQLULEN         SQLUINTEGER

在 64 位 Informix ODBC 驱动程序中,SQLLEN 和 SQLULEN 被定义为 8 字节整数,如清单 6 所示。

清单 6. 64 位 Informix ODBC infxsql.h 头文件中的 SQLLEN 和 SQLULEN 声明
typedef unsigned long long  SQLULEN;
typedef long long           SQLLEN;

32 位和 64 位 Informix ODBC 驱动程序在 SQLLEN 和 SQLULEN 声明方面存在一些差异,与此不同的是,从 2.90 版本开始,所有 Informix ODBC API 函数都使用相同的方式声明。如果您按照与 Informix ODBC 函数签名相同的方式声明您的主机变量,则不需要修改 ODBC 应用程序。不过,在 Informix ODBC 4.10.FC1 中,需要对清单 7 中的 Informix ODBC 函数进行修改,以便支持新的 8 字节 SQLLEN 和 SQLULEN 数据类型。

清单 7. v4.10.C1 中受 8 字节 SQLLEN 和 SQLULEN 影响的 Informix ODBC 函数
SQLBindCol
SQLBindParam
SQLFetchScroll
SQLGetData
SQLGetDescRec
SQLPutData
SQLRowCount
SQLSetDescRec
SQLSetParam
SQLColAttributeW
SQLColAttributesW
SQLGetDescRecW

如前所述,在 3.70 以及之前版本的 Informix 64 位 ODBC 驱动程序二进制文件中,SQLLEN 和 SQLULEN 仍然只有 4 字节长。当前编译并链接至 Informix 64 位 ODBC 库 3.70 及之前版本的 64 位 ODBC 应用程序不能充分利用 64 位系统的优势,即使您使用真正的 64 位 ODBC 驱动程序运行 Informix ODBC 应用程序,情况也是相同的。此外,调用 Informix ODBC API 从真正的 64 位 ODBC 驱动程序管理器获取 SQLULEN 或 SQLLEN 的参数也会带来不可预测的问题,比如数据截断、内存崩溃等。这些内容将在下一小节中详细讨论。


将 32 位 Informix 应用程序迁移到 64 位模式

如前所述,INFORMIXDIR/incl/cli/infxsql.h 头文件针对真正的 64 位 Informix ODBC 驱动程序进行了修改。因此,您必须用真正的 64 位 Informix Client SDK 重现编译当前的 32 位或 64 位 Informix ODBC 应用程序,然后才能迁移您的应用程序,让更改在完整的 64 位 ODBC 驱动程序中生效。根据您的 Informix ODBC 应用程序是否运行 ODBC 驱动程序管理器,您需要使用 ODBC 驱动程序管理器定义的相应编译指令重新编译您的 Informix ODBC 应用程序。

将独立 Informix ODBC 应用程序迁移到 64 位模式

如果您的 Informix ODBC 应用程序是独立应用程序,没有运行 ODBC 驱动程序管理器,那么您可以直接进行编译,不需要使用特定于 64 位 ODBC 的编译指令 — 前提是调用所有 ODBC API 函数的所有参数必须使用与 infxsql.h Informix ODBC 头文件中每个函数签名相同的声明方式。

下面提供了一个 Linux 系统上的例子。

gcc -o
fxODBCTest -I$INFORMIXDIR/incl/cli  -L$INFORMIXDIR/lib/cli -lthcli -lifdmr
    -L$INFORMIXDIR/lib/esql -lgls -lifglx ifxODBCTest.c

如果您的 ODBC 应用程序仍然以 32 位方式调用 ODBC API 函数,那么您必须相应地修改代码来适应 64 位 ODBC 驱动程序。遗留的 ODBC 应用程序使用 ODBC API 函数原型中指定的数据类型以外的数据类型声明变量,这种情况很常见但不符合标准。

清单 8 中的例子调用了 SQLExtendedFetch() 函数,其中参数 pcrow 被声明为 UDWORD,这是不同于 SQLExtendedFetch() 函数原型的类型。

清单 8. 用 32 位签名调用 SQLExtendedFetch()
   UWORD Row_Stat[ROWSET_SZ];
   UDWORD pcrow;
   ......
    while ((rc = SQLExtendedFetch(hstmt,
		SQL_FETCH_NEXT,
		0,
		&pcrow,
		Row_Stat)) == SQL_SUCCESS)
      {
        /* do something here */
      }

在使用 v3.70 或之前版本的 64 位 Informix ODBC 驱动程序二进制文件编译清单 8 的代码时,不会出现任何问题,因为 SQLLEN 是 4 字节长。您可以将 pcrow 内存地址(声明为 UDWORD)传递给 SQLExtendedFetch。然而,在将 64 位 Informix ODBC 驱动程序升级到 v4.10 中真正的 64 位驱动程序后,仅仅重新编译应用程序是不够的,因为在新的驱动程序中,SQLLEN 现在是 8 字节长,而 UDWORD 仍然是 4 个字节。存储到 pcrow 变量内存地址的 8 字节数据在运行时将被截短为 4 字节,并造成 pcrow 变量存储的数据发生崩溃。对于这种情况,您必须修改应用程序代码来使用相同的数据类型。

例如,清单 9 所示的一个小程序使用逐列捆绑(column-wise binding)方式从 Informix stores_demo 数据库中的 customer 表检索数据。

清单 9. 使用 32 位签名调用 SQLExtendedFetch()
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#ifdef IFXODBC
  #include "infxcli.h"
  #include "infxsql.h"
#else
  #include "sql.h"
  #include "sqlext.h"
#endif


#define ROWSET_SZ 2

int main()
{
   SQLHENV henv = SQL_NULL_HENV;
   SQLHDBC hdbc = SQL_NULL_HDBC;
   SQLHSTMT hstmt = SQL_NULL_HSTMT;
   RETCODE retcode;
   SQLCHAR szFname[ROWSET_SZ][32];
   SQLLEN cbFname[ROWSET_SZ], cbCust_num[ROWSET_SZ];
   UWORD Row_Stat[ROWSET_SZ];
   UDWORD pcrow;
   SQLINTEGER Cust_num[ROWSET_SZ];

   long int i = 0, total = 0;

      // Allocate the ODBC environment and save handle.
      retcode = SQLAllocHandle (SQL_HANDLE_ENV, NULL, &henv);
      if ( (retcode != SQL_SUCCESS_WITH_INFO) && (retcode !=
SQL_SUCCESS))
      {
         printf("SQLAllocHandle(Env) Failed\n\n");
         return(1);
      }

      // Notify ODBC that this is an ODBC 3.0 app.
      retcode = SQLSetEnvAttr(henv,
		SQL_ATTR_ODBC_VERSION,
		(SQLPOINTER) SQL_OV_ODBC3,
		SQL_IS_INTEGER);
      if ( (retcode != SQL_SUCCESS_WITH_INFO) && (retcode !=
SQL_SUCCESS))
      {
         printf("SQLSetEnvAttr(ODBC version) Failed\n\n");
         return(1);
      }

      // Allocate ODBC connection handle and connect.
      retcode = SQLAllocHandle(SQL_HANDLE_DBC,
		henv, &hdbc);
      if ( (retcode != SQL_SUCCESS_WITH_INFO) && (retcode !=
SQL_SUCCESS))
      {
         printf("SQLAllocHandle(hdbc) Failed\n\n");
         return(1);
      }

      // Connect to Informix server
      if (hdbc != 0)
      {
        retcode = SQLConnect(hdbc,
		(SQLCHAR*) "IfxDSN", SQL_NTS,
		(SQLCHAR*) "informix", SQL_NTS,
		(SQLCHAR*) "mypassword", SQL_NTS);
      }

      if ( (retcode != SQL_SUCCESS) && (retcode !=
SQL_SUCCESS_WITH_INFO) )
      {
         printf("SQLConnect() Failed\n\n");
         return (1);
      }

      // Allocate ODBC statement handle for an SQL statement.
      retcode = SQLAllocHandle(SQL_HANDLE_STMT,
		hdbc, &hstmt);
      if ( (retcode != SQL_SUCCESS) && (retcode !=
SQL_SUCCESS_WITH_INFO) )
      {
         printf("SQLAllocHandle(hstmt) Failed\n\n");
         return(1);
      }

      // Execute an SQL statement.
      retcode = SQLExecDirect(hstmt,
		(UCHAR*)"SELECT CUSTOMER_NUM, FNAME FROM CUSTOMER", SQL_NTS);

      // Set the row size to ROWSET_SZ
      retcode = SQLSetStmtAttr(hstmt, SQL_ROWSET_SIZE, (void*) ROWSET_SZ,
0);

      // Retrieve the rows.
      retcode = SQLBindCol(hstmt, 1, SQL_C_SLONG, (SQLPOINTER) Cust_num, 4,
cbCust_num);
      retcode = SQLBindCol(hstmt, 2, SQL_C_CHAR, (SQLPOINTER) szFname, 32,
cbFname);

      while ((retcode = SQLExtendedFetch(hstmt,
		SQL_FETCH_NEXT,
		0,
		&pcrow,
		Row_Stat)) == SQL_SUCCESS)
      {
         for (i = 0; i < pcrow; i++)
         {
           total++;
         }
         if (pcrow < ROWSET_SZ)
            break;
      }

      printf("Total number of rows fetched: %ld\n", total);

   // Free the statement handle
   SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

   // Disconnect and free the handles
   retcode = SQLDisconnect(hdbc);
   if ( (retcode != SQL_SUCCESS) && (retcode !=
SQL_SUCCESS_WITH_INFO) )
   {
      printf("SQLDisconnect(hdbc) Failed\n\n");
      return(1);
   }
   SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
   SQLFreeHandle(SQL_HANDLE_ENV, henv);

   return (0);
}

在本例中,pcrow 变量仍被声明为 UDWORD。在使用 Informix CSDK 3.70.FC7 对其进行编译时,您不会看到任何警告或错误消息。现在,让我们使用 CSDK v4.10.FC1(安装在 AIX 7.1 上的 /work/ywang/csdk410fc1 中)进行编译,如清单 10 所示。

清单 10. 使用 CSDK v4.10.FC1 进行编译
export INFORMIXDIR=/work/ywang/csdk410fc1
export INFORMIXSQLHOSTS=/work/ywang/sqlhosts
export PATH=${INFORMIXDIR}/bin:${PATH}
export
LIBPATH=${INFORMIXDIR}/lib:${INFORMIXDIR}/lib/esql:${INFORMIXDIR}/lib/cli:
${LIBPATH}
$ gcc -o
listing9 -DIFXODBC -I$INFORMIXDIR/incl/cli -L$INFORMIXDIR/lib/cli -lthcli
-lifdmr -L$INFORMIXDIR/lib/esql -lgls -lifglx listing9.c

编译进程将以一个警告消息结束,因为数据类型 pcrow 与函数签名中的声明不匹配,如清单 11 所示。

清单 11. 消息
cc -qchars=signed -q64 -qlanglvl=extc99 -qalign=natural
 -qcheck=nullptr -qmaxmem=-1
-qspill=2000 -o
listing9 -DIFXODBC -I$INFORMIXDIR/incl/cli -L$INFORMIXDIR/lib/cli -lifcli
-lifdmr -L$INFORMIXDIR/lib/esql -lgls -lifglx -ltli -lc_r -lmsaa -lm_r -ldl 
-lbsd
listing9.c

"listing9.c", line 78.68: 1506-280 (W) Function argument assignment between
types
"unsigned long long*" and "unsigned int*" is not allowed.

如果忽略该警告消息并继续运行程序,则会看到最终没有返回任何行:

    $ listing9
    Total number of rows fetched: 0

让我们在 While 循环中添加以下代码,显示 pcrow 的值:

            printf("pcrow = %ld\n", pcrow);

重新编译 listing9.c 并返回,如清单 12 所示。

清单 12. 重新运行
    $ listing9
    pcrow = 0
    Total number of rows fetched: 0

结果是 SQLExtendedFetch() 返回 pcrow 变量,该变量的值为 0。pcrow 变量的值被截断,因为它在程序中被声明为 4 字节 UDWORD,而在 SQLExtendedFetch() function 函数的签名中,它被声明为 8 字节 SQLULEN,如清单 13 所示。

清单 13. 截断
SQLRETURN SQL_API SQLExtendedFetch(
	SQLHSTMT		hstmt,
	SQLUSMALLINT	fFetchType,
 	SQLLEN		irow,
	SQLULEN		*pcrow,
	SQLUSMALLINT	*rgfRowStatus);

SQLExtendedFetch() Informix ODBC API 函数返回时,&pcrow 中的值在高位优先系统(本文中为 AIX)上被保存为 0x00000000 00000002。由于pcrow 在程序中被声明为 4 字节整数,因此第二个 4 字节内存被截断,值变为 0x0000000。

这个例子说明,按照 ODBC 函数签名中使用的数据类型声明变量非常重要。如果本地变量和 ODBC API 函数的数据类型不匹配,则会造成不必要的数据类型转换和数据截断。您需要查看应用程序代码,确保本地变量使用了正确的数据类型,并检查编译期间的所有警告消息。

将使用 ODBC Driver Manager 编译并运行的 Informix ODBC 应用程序迁移到 64 位模式

对于使用 ODBC Driver Manager 编译并运行的 Informix ODBC 应用程序(如 Progress DataDirect ODBC 或 unixODBC),Informix ODBC 驱动程序并没有编译并直接链接到应用程序。Informix ODBC 驱动程序共享库是驱动程序管理器在运行时加载的。在本文中,ODBC 应用程序仍然必须由 ODBC 驱动程序管理器进行编译,因此 SQLLEN 和 SQLULEN 的大小由您所使用的 ODBC 驱动程序管理器来决定。ODBC 驱动程序声明的 SQLLEN 和 SQLULEN 的大小可能与 Informix ODBC 驱动程序声明的大小不匹配。要确保 64 位 Informix ODBC 驱动程序正常工作,ODBC 驱动程序管理器中声明的 SQLLEN 和 SQLULEN 的大小必须与 Informix ODBC 驱动程序相匹配。假设应用程序中所有变量都使用了正确的声明,那么您必须用驱动程序管理器的特定于 64 位 ODBC 的编译指令重新编译应用程序。

查看 sqltypes.h 头文件,其中包含 unixODBC、DataDirect 和 Microsoft ODBC 驱动程序管理器中定义的 64 位 ODBC 编译指令。

unixODBC:

	SQLRETURN SQL_API SQLExtendedFetch(
	#ifdef BUILD_LEGACY_64_BIT_MODE
	typedef int             SQLINTEGER;
	typedef unsigned int    SQLUINTEGER;
	#define SQLLEN          SQLINTEGER
	#define SQLULEN         SQLUINTEGER
	#define SQLSETPOSIROW   SQLUSMALLINT

Progress DataDirect ODBC:

	#if defined(ODBC64)
	#ifdef _WIN64
	#ifndef _BASETSD_H_
	typedef __int64 INT64;
	typedef unsigned __int64 UINT64;
	#endif
	#else

	#ifndef _DLFCN_INCLUDED
	typedef unsigned long   UINT64;
	#endif

	typedef signed long     INT64;
	#endif
	typedef INT64           SQLLEN;
	typedef UINT64          SQLULEN;
	typedef UINT64          SQLSETPOSIROW;

Microsoft 的 ODBC:

	#ifdef _WIN64
	typedef INT64           SQLLEN;
	typedef UINT64          SQLULEN;
	typedef UINT64          SQLSETPOSIROW;

在 64 位 Windows 上,如果选择 x64 作为 Visual Studio 项目的新的解决方案平台来重新编译 ODBC 应用程序,则会自动定义 _WIN64 宏。

在 UNIX 和 Linux 平台上,Informix ODBC 应用程序通常通过一个 makefile 文件编译,该文件定义了所有编译选项,包括所有共享库的指令。如果 Informix ODBC 应用程序通过 ODBC 驱动程序管理器编译,那么您需要修改 makefile 文件,在其中包含 ODBC 驱动程序管理器的相应编译指令。

如清单 14 所示,我们将在 Linux 机器上用 Progress DataDirect ODBC 驱动程序管理器重新编译 list9.c。64 位 Progress DataDirect ODBC 驱动程序管理器的编译指令为 ODBC64。pcrow 变量仍然被声明为 SQLULEN。

清单 14. 使用 Progress DataDirect ODBC 驱动程序管理器重新编译
export ODBCHOME=/home/ywang/ddodbc64
gcc -g -DODBC64 -o listing9 -L$ODBCHOME/lib -lodbc -I$ODBCHOME/include
listing9.c

在运行程序后,所有行均被返回,如下所示:

  $ listing9
  Total number of rows fetched: 29

不管使用何种 ODBC 驱动程序管理器,都可以在调试器中查看 pcrow 变量的大小。

例如,在 AIX 上,您可以在 SQLExtendedFetch 放置一个断点,在 dbx 中查看该变量,如清单 15 所示。

清单 15. 在 AIX 上查看
$ dbx listing9
Type 'help' for help.
reading symbolic information ...

(dbx) stop in SQLExtendedFetch
[1] stop in SQLExtendedFetch

(dbx) run
[1] stopped in glink64.SQLExtendedFetch at 0x100000be8 ($t1)
0x100000be8 (SQLExtendedFetch)    e98200c8          ld   r12,0xc8(r2)

(dbx) p sizeof(&pcrow)
8

在 Linux 上,您可以通过相同的方式查看此变量,如清单 16 所示。

清单 16. 在 Linux 上查看
......

(gdb) p pcrow
$1 = (SQLULEN *) 0x7fff0425c80c

(gdb) p sizeof(SQLULEN)
$2 = 8

故障排除

在将 32 位 Informix ODBC 应用程序迁移到 64 位模式时会出现一些问题。出现这些问题通常是因为应用程序被链接到错误的共享库,或者应用程序变量和 ODBC 函数参数的数据类型不匹配。

如果对 64 位 ODBC 应用程序排除故障,遵循下面几个指导原则可能会很有帮助:

  • 如果使用了 ODBC 驱动程序管理器,则需要确保使用相应的编译指令编译 ODBC 程序。
  • 如果可以的话,应尽量减少编译警告消息,特别是与数据类型有关的消息。
  • 运行 ldd > program name < 命令,确保应用程序被链接到正确的共享库。
  • 检查您的 ODBC.INI 文件是否得到正确配置。

如果所有内容都设置正确的情况下仍然出现问题,那么可以考虑收集以下诊断数据进行进一步故障排除:

  • ODBC 跟踪数据
  • Informix SQLIDEBUG 输出

有关收集 ODBC 跟踪数据和 Informix SQLIDEBUG 输出的详情,请参见 收集数据以排除 ODBC 问题

当然,您始终可以联系 IBM 技术支持人员来获得帮助。


总结

64 位 Informix Client SDK v4.10.FC1 之前的版本附带的 Informix ODBC 驱动程序是 64 位二进制文件,不能充分利用更新的、真正的 64 位 ODBC 驱动程序。要迁移 32 位 Informix ODBC 应用程序,或迁移用 4.10.FC1 之前的 64 位 Informix CSDK 版本编译的 64 位应用程序,必须使用新的 4.10.FC1 或更高版本的 Informix 64 位 ODBC 驱动程序进行重新编译。如果使用了第三方 ODBC 驱动程序管理器,则必须使用 64 位 ODBC 驱动程序管理器的对应指令编译 ODBC 应用程序。

参考资料

学习

获得产品和技术

  • 以最适合您的方式 评估 IBM 产品:下载产品试用版,在线试用产品,或在云环境中使用产品。

讨论

  • 加入 My developerWorks 社区,探索由开发人员驱动的博客、论坛、群组和维基,并与其他 developerWorks 用户进行交流。

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Information Management
ArticleID=977510
ArticleTitle=将 32 位 Informix ODBC 应用程序迁移到 64 位模式
publish-date=07102014