SQLBindCol 函数

一致性
引入的版本:ODBC 1.0 标准符合性:ISO 92

摘要
SQLBindCol 将应用程序数据缓冲区绑定到结果集中的列。

语法

  
SQLRETURN SQLBindCol(  
      SQLHSTMT       StatementHandle,  
      SQLUSMALLINT   ColumnNumber,  
      SQLSMALLINT    TargetType,  
      SQLPOINTER     TargetValuePtr,  
      SQLLEN         BufferLength,  
      SQLLEN *       StrLen_or_IndPtr);  

参数

StatementHandle
[输入]语句句柄。

ColumnNumber
[输入]要绑定的结果集列的数目。 列按从 0 开始的递增列顺序进行编号,其中列 0 是书签列。 如果未使用书签(即,SQL_ATTR_USE_BOOKMARKS 语句属性设置为 SQL_UB_OFF),则列号从 1 开始。

TargetType
[输入]*TargetValuePtr 缓冲区的 C 数据类型的标识符。 当它使用 SQLFetchSQLFetchScrollSQLBulkOperationsSQLSetPos 从数据源中检索数据时,驱动程序会将数据转换为此类型;当它使用 SQLBulkOperationsSQLSetPos 将数据发送到数据源时,驱动程序会从此类型转换数据。 有关有效 C 数据类型和类型标识符的列表,请参阅附录 D:数据类型中的 C 数据类型部分。

如果 TargetType 参数是间隔数据类型,则默认间隔前导精度 (2) ,默认间隔秒精度 (6) ,分别在 ARD 的SQL_DESC_DATETIME_INTERVAL_PRECISION和SQL_DESC_PRECISION字段中设置,用于数据。 如果 TargetType 参数为SQL_C_NUMERIC,则默认精度 (驱动程序定义的) 和默认刻度 (0) (如 ARD 的SQL_DESC_PRECISION和SQL_DESC_SCALE字段中设置)用于数据。 如果任何默认精度或刻度都不适合,应用程序应通过调用 SQLSetDescFieldSQLSetDescRec 显式设置相应的描述符字段。

还可以指定扩展 C 数据类型。 有关详细信息,请参阅 ODBC 中的 C 数据类型

TargetValuePtr
[延迟输入/输出]指向要绑定到列的数据缓冲区的指针。 SQLFetchSQLFetchScroll 在此缓冲区中返回数据。 当操作SQL_FETCH_BY_BOOKMARK时,SQLBulkOperations 将返回此缓冲区中的数据;当操作SQL_ADD或SQL_UPDATE_BY_BOOKMARK时,它会从此缓冲区检索数据。 当操作SQL_REFRESH时,SQLSetPos 将返回此缓冲区中的数据;SQL_UPDATE操作时,它会从此缓冲区检索数据。

如果 TargetValuePtr 是空指针,则驱动程序将取消绑定列的数据缓冲区。 应用程序可以通过使用 SQL_UNBIND 选项调用 SQLFreeStmt 来取消绑定所有列。 如果调用 SQLBindCol 中的 TargetValuePtr 参数为 null 指针,但 StrLen_or_IndPtr 参数为有效值,则应用程序可以取消绑定列的数据缓冲区,但仍具有该列的长度/指示器缓冲区。

BufferLength
[输入]*TargetValuePtr 缓冲区的长度(以字节为单位)。

驱动程序使用 BufferLength 避免在返回可变长度数据(如字符或二进制数据)时写入 *TargetValuePtr 缓冲区的末尾。 请注意,驱动程序在将字符数据返回到 *TargetValuePtr 时对 null 终止字符进行计数。 *因此,TargetValuePtr 必须包含 null 终止字符的空间,否则驱动程序将截断数据。

当驱动程序返回固定长度的数据(如整数或日期结构)时,驱动程序将忽略 BufferLength 并假定缓冲区足够大,足以保存数据。 因此,应用程序必须为固定长度的数据分配足够大的缓冲区,否则驱动程序将写入缓冲区末尾。

BufferLength 小于 0 时,SQLBindCol 返回 SQLSTATE HY090 (无效的字符串或缓冲区长度) ,但 BufferLength 为 0 时不返回。 但是,如果 TargetType 指定字符类型,则应用程序不应将 BufferLength 设置为 0,因为符合 ISO CLI 的驱动程序返回 SQLSTATE HY090 (在这种情况下,字符串或缓冲区长度) 无效。

StrLen_or_IndPtr
[延迟输入/输出]指向要绑定到列的长度/指示器缓冲区的指针。 SQLFetchSQLFetchScroll 在此缓冲区中返回一个值。 当操作SQL_ADD、SQL_UPDATE_BY_BOOKMARK或SQL_DELETE_BY_BOOKMARK时,SQLBulkOperations 将从此缓冲区中检索值。 SQL_FETCH_BY_BOOKMARK操作时,SQLBulkOperations 将返回此缓冲区中的值。 当操作SQL_REFRESH时,SQLSetPos 将返回此缓冲区中的值;当操作SQL_UPDATE时,它会从此缓冲区中检索值。

SQLFetchSQLFetchScrollSQLBulkOperationsSQLSetPos 可以在长度/指示器缓冲区中返回以下值:

  • 可返回的数据的长度

  • SQL_NO_TOTAL

  • SQL_NULL_DATA

应用程序可以将以下值放入长度/指示器缓冲区中,以便与 SQLBulkOperationsSQLSetPos 配合使用

  • 正在发送的数据的长度

  • SQL_NTS

  • SQL_NULL_DATA

  • SQL_DATA_AT_EXEC

  • SQL_LEN_DATA_AT_EXEC宏的结果

  • SQL_COLUMN_IGNORE

如果指示器缓冲区和长度缓冲区是单独的缓冲区,则指示器缓冲区只能返回SQL_NULL_DATA,而长度缓冲区可以返回所有其他值。

有关详细信息,请参阅 SQLBulkOperations 函数SQLFetch 函数SQLSetPos 函数和使用 长度/指示器值

如果 StrLen_or_IndPtr 为 null 指针,则不使用长度或指示器值。 提取数据时出错,数据为 NULL。

如果应用程序将在 64 位操作系统上运行,请参阅 ODBC 64 位信息。

返回

SQL_SUCCESS、SQL_SUCCESS_WITH_INFO、SQL_ERROR或SQL_INVALID_HANDLE。

诊断

SQLBindCol 返回SQL_ERROR或SQL_SUCCESS_WITH_INFO时,可以通过使用 handleType 为 SQL_HANDLE_STMT 和 Handle ofStatementHandle 调用 SQLGetDiagRec 来获取关联的 SQLSTATE 值。 下表列出了 SQLBindCol 通常返回的 SQLSTATE 值,并对此函数上下文中的每个值进行了说明:表示法“ (DM) ”位于驱动程序管理器返回的 SQLSTATE 说明之前。 与每个 SQLSTATE 值关联的返回代码SQL_ERROR,除非另有说明。

SQLSTATE 错误 说明
01000 常规警告 特定于驱动程序的信息性消息。 (函数返回 SQL_SUCCESS_WITH_INFO.)
07006 受限数据类型属性冲突 (DM) ColumnNumber 参数为 0,并且 TargetType 参数未SQL_C_BOOKMARK或SQL_C_VARBOOKMARK。
07009 描述符索引无效 为参数 ColumnNumber 指定的值超出了结果集中的最大列数。
HY000 常规错误 发生错误,其中没有特定的 SQLSTATE,也没有定义特定于实现的 SQLSTATE。 SQLGetDiagRec*MessageText 缓冲区中返回的错误消息描述了错误及其原因。
HY001 内存分配错误 驱动程序无法分配支持执行或完成函数所需的内存。
HY003 应用程序缓冲区类型无效 参数 TargetType 既不是有效的数据类型,也不是SQL_C_DEFAULT。
HY010 函数序列错误 (DM) 为与 StatementHandle 关联的连接句柄调用了异步执行的函数。 调用 SQLBindCol 时,此异步函数仍在执行。

(DM) SQLExecuteSQLExecDirectSQLMoreResults 已为 StatementHandle 调用并返回SQL_PARAM_DATA_AVAILABLE。 此函数是在检索所有流参数的数据之前调用的。

(DM) 为 StatementHandle 调用了异步执行的函数,并在调用此函数时仍在执行。

(DM) SQLExecuteSQLExecDirectSQLBulkOperationsSQLSetPos 已为 StatementHandle 调用,并返回SQL_NEED_DATA。 在针对所有数据执行参数或列发送数据之前调用了此函数。
HY013 内存管理错误 无法处理函数调用,因为无法访问基础内存对象,可能是由于内存不足。
HY090 无效的字符串或缓冲区长度 (DM) 为参数 BufferLength 指定的值小于 0。

(DM) 驱动程序是 ODBC 2。x 驱动程序, ColumnNumber 参数设置为 0,并且为 参数 BufferLength 指定的值不等于 4。
HY117 由于事务状态未知,连接已暂停。 仅允许断开连接和只读函数。 (DM) 有关挂起状态的详细信息,请参阅 SQLEndTran 函数
HYC00 未实现可选功能 驱动程序或数据源不支持由 TargetType 参数和相应列的特定于驱动程序的 SQL 数据类型的组合指定的转换。

参数 ColumnNumber 为 0,驱动程序不支持书签。

驱动程序仅支持 ODBC 2。x 和参数 TargetType 是下列值之一:

SQL_C_NUMERIC SQL_C_SBIGINT SQL_C_UBIGINT

和附录 D:数据类型中的 C 数据类型 中列出的任何间隔 C 数据类型。

驱动程序仅支持 3.50 之前的 ODBC 版本,并且参数 TargetType 已SQL_C_GUID。
HYT01 超过连接超时时间 在数据源响应请求之前,连接超时期限已过期。 连接超时期限通过 SQLSetConnectAttr SQL_ATTR_CONNECTION_TIMEOUT设置。
IM001 驱动程序不支持此函数 (DM) 与 StatementHandle 关联的驱动程序不支持 函数。

注释

SQLBindCol 用于将结果集中的列关联或 绑定到 应用程序中的数据缓冲区和长度/指示器缓冲区。 当应用程序调用 SQLFetchSQLFetchScrollSQLSetPos 来提取数据时,驱动程序将返回指定缓冲区中绑定列的数据;有关详细信息,请参阅 SQLFetch 函数。 当应用程序调用 SQLBulkOperations 更新或插入行或 SQLSetPos 以更新行时,驱动程序从指定的缓冲区检索绑定列的数据;有关详细信息,请参阅 SQLBulkOperations 函数SQLSetPos 函数。 有关绑定的详细信息,请参阅 检索基本) (结果

请注意,不必绑定列来从中检索数据。 应用程序还可以调用 SQLGetData 来检索列中的数据。 尽管可以绑定行中的某些列,并为其他列调用 SQLGetData ,但这受到一些限制。 有关详细信息,请参阅 SQLGetData

绑定、取消绑定和重新绑定列

列可以随时绑定、取消绑定或反弹,即使在从结果集中提取数据之后也是如此。 新绑定在下次调用使用绑定的函数时生效。 例如,假设应用程序绑定结果集中的列并调用 SQLFetch。 驱动程序返回绑定缓冲区中的数据。 现在,假设应用程序将列绑定到一组不同的缓冲区。 驱动程序不会将刚提取的行的数据放入新绑定的缓冲区中。 相反,它会等待,直到再次调用 SQLFetch ,然后将下一行的数据放在新绑定的缓冲区中。

注意

在将列绑定到列 0 之前,应始终设置语句属性SQL_ATTR_USE_BOOKMARKS。 这不是必需的,但强烈建议这样做。

绑定列

为了绑定列,应用程序调用 SQLBindCol 并传递数据缓冲区的列号、类型、地址和长度,以及长度/指示器缓冲区的地址。 有关如何使用这些地址的信息,请参阅本部分后面的“缓冲区地址”。 有关绑定列的详细信息,请参阅 使用 SQLBindCol

延迟使用这些缓冲区;也就是说,应用程序在 SQLBindCol 中绑定它们,但驱动程序从其他函数(即 SQLBulkOperationsSQLFetchSQLFetchScrollSQLSetPos)访问它们。 只要绑定仍然有效,应用程序负责确保 SQLBindCol 中指定的指针保持有效。 如果应用程序允许这些指针变得无效(例如,释放缓冲区),然后调用一个预期它们有效的函数,则后果是未定义的。 有关详细信息,请参阅 延迟缓冲区

绑定一直有效,直到它被新绑定替换、列未绑定或语句释放为止。

取消绑定列

若要取消绑定单个列,应用程序会调用将 ColumnNumber 设置为该列数且 TargetValuePtr 设置为 null 指针的 SQLBindCol。 如果 ColumnNumber 引用未绑定的列, SQLBindCol 仍返回SQL_SUCCESS。

若要取消绑定所有列,应用程序调用将 fOption 设置为 SQL_UNBIND的 SQLFreeStmt。 也可以通过将 ARD 的 SQL_DESC_COUNT 字段设置为零来实现此目的。

重新绑定列

应用程序可以执行以下两种操作之一来更改绑定:

  • 调用 SQLBindCol 为已绑定的列指定新绑定。 驱动程序使用新绑定覆盖旧绑定。

  • 指定要添加到由 对 SQLBindCol 的绑定调用指定的缓冲区地址的偏移量。 有关详细信息,请参阅下一节“绑定偏移量”。

绑定偏移量

绑定偏移量是在取消引用之前添加到 targetValuePtrStrLen_or_IndPtr 参数) 中指定的数据和长度/指示器缓冲区 (地址的值。 使用偏移量时,绑定是应用程序缓冲区布局方式的“模板”,应用程序可以通过更改偏移量将此“模板”移动到不同的内存区域。 由于将相同的偏移量添加到每个绑定中的每个地址,因此,每个缓冲区集中不同列的缓冲区之间的相对偏移量必须相同。 使用行绑定时,始终如此:应用程序必须仔细布局其缓冲区,以便在使用列式绑定时为 true。

使用绑定偏移与通过调用 SQLBindCol 重新绑定列的效果基本相同。 区别在于,对 SQLBindCol 的新调用为数据缓冲区和长度/指示器缓冲区指定新地址,而使用绑定偏移量不会更改地址,而只是向其添加偏移量。 应用程序可以在需要时指定新的偏移量,并且始终将此偏移量添加到最初绑定的地址。 具体而言,如果偏移量设置为 0 或语句属性设置为 null 指针,则驱动程序将使用最初绑定的地址。

为了指定绑定偏移量,应用程序将 SQL_ATTR_ROW_BIND_OFFSET_PTR 语句属性设置为 SQLINTEGER 缓冲区的地址。 在应用程序调用使用绑定的函数之前,它会在此缓冲区中以字节为单位放置偏移量。 若要确定要使用的缓冲区的地址,驱动程序会将偏移量添加到绑定中的地址。 地址和偏移量的总和必须是有效的地址,但添加偏移量的地址不必有效。 有关如何使用绑定偏移量的详细信息,请参阅本部分后面的“缓冲区地址”。

绑定数组

如果行集大小 () SQL_ATTR_ROW_ARRAY_SIZE 语句属性的值大于 1,则应用程序将绑定缓冲区数组,而不是单个缓冲区。 有关详细信息,请参阅 块游标

应用程序可以通过两种方式绑定数组:

  • 将数组绑定到每列。 这称为 列级绑定 ,因为数组 (每个数据结构) 包含单个列的数据。

  • 定义一个结构,用于保存整行的数据并绑定这些结构的数组。 这称为 行绑定, 因为每个数据结构都包含单个行的数据。

每个缓冲区数组的元素数必须至少与行集的大小一样多。

注意

应用程序必须验证对齐是否有效。 有关对齐注意事项的详细信息,请参阅 对齐

按列绑定

在按列绑定中,应用程序将单独的数据和长度/指示器数组绑定到每一列。

若要使用列式绑定,应用程序首先将 SQL_ATTR_ROW_BIND_TYPE 语句属性设置为 SQL_BIND_BY_COLUMN。 (这是 default.) 对于要绑定的每个列,应用程序执行以下步骤:

  1. 分配数据缓冲区数组。

  2. 分配长度/指示器缓冲区数组。

    注意

    如果使用列式绑定时应用程序直接写入描述符,则可以将单独的数组用于长度和指示器数据。

  3. 使用以下参数调用 SQLBindCol

    • TargetType 是数据缓冲区数组中单个元素的类型。

    • TargetValuePtr 是数据缓冲区数组的地址。

    • BufferLength 是数据缓冲区数组中单个元素的大小。 当数据是固定长度的数据时, 将忽略 BufferLength 参数。

    • StrLen_or_IndPtr 是长度/指示器数组的地址。

有关如何使用此信息的详细信息,请参阅本部分后面的“缓冲区地址”。 有关列式绑定的详细信息,请参阅 列式绑定

按行绑定

在行绑定中,应用程序定义一个结构,该结构包含要绑定的每一列的数据和长度/指示器缓冲区。

若要使用行绑定,应用程序会执行以下步骤:

  1. 定义一个结构,用于保存单行数据 (包括数据和长度/指示器缓冲区) ,并分配这些结构的数组。

    注意

    如果使用行绑定时应用程序直接写入描述符,则可以将单独的字段用于长度和指示器数据。

  2. 将 SQL_ATTR_ROW_BIND_TYPE 语句属性设置为包含单行数据的结构的大小或结果列将绑定到的缓冲区实例的大小。 长度必须包含所有绑定列的空间以及结构或缓冲区的任何填充,以确保当绑定列的地址以指定长度递增时,结果将指向下一行中同一列的开头。 在 ANSI C 中使用 sizeof 运算符时,可以保证此行为。

  3. 调用 SQLBindCol ,其中包含要绑定的每个列的以下参数:

    • TargetType 是要绑定到列的数据缓冲区成员的类型。

    • TargetValuePtr 是第一个数组元素中数据缓冲区成员的地址。

    • BufferLength 是数据缓冲区成员的大小。

    • StrLen_or_IndPtr 是要绑定的长度/指示器成员的地址。

有关如何使用此信息的详细信息,请参阅本部分后面的“缓冲区地址”。 有关列式绑定的详细信息,请参阅 行-Wise Binding

缓冲区地址

缓冲区地址是数据或长度/指示器缓冲区的实际地址。 驱动程序在写入缓冲区 ((例如在提取时间) 期间)之前计算缓冲区地址。 它根据以下公式计算,该公式使用 TargetValuePtr 中指定的地址和 StrLen_or_IndPtr 参数、绑定偏移量和行号:

绑定地址 + 绑定偏移量 + ( (行号 - 1) x 元素大小)

其中公式的变量定义如下表中所述。

变量 说明
绑定地址 对于数据缓冲区,是使用 SQLBindColTargetValuePtr 参数指定的地址。

对于长度/指示器缓冲区,使用 SQLBindCol 中的 StrLen_or_IndPtr 参数指定的地址。 有关详细信息,请参阅“描述符和 SQLBindCol”部分中的“其他注释”。

如果绑定地址为 0,则不返回任何数据值,即使上一公式计算的地址为非零。
绑定偏移量 如果使用行绑定,则存储在使用 SQL_ATTR_ROW_BIND_OFFSET_PTR 语句属性指定的地址处的值。

如果使用列式绑定,或者如果 SQL_ATTR_ROW_BIND_OFFSET_PTR 语句属性的值为 null 指针, 则 Binding Offset 为 0。
Row Number 行集中行的从 1 开始的行号。 对于默认的单行提取,这是 1。
元素大小 绑定数组中元素的大小。

如果使用列式绑定,则长度/指示器缓冲区 的大小为 (SQLINTEGER) 。 对于数据缓冲区,如果数据类型为可变长度,则为 SQLBindColBufferLength 参数的值;如果数据类型为固定长度,则为数据类型的大小。

如果使用行绑定,则这是数据和长度/指示器缓冲区的 SQL_ATTR_ROW_BIND_TYPE 语句属性的值。

描述符和 SQLBindCol

以下部分介绍了 SQLBindCol 如何与描述符交互。

注意

为一个语句调用 SQLBindCol 可能会影响其他语句。 当显式分配与 语句关联的 ARD 并且也与其他语句关联时,将发生这种情况。 由于 SQLBindCol 修改描述符,因此修改适用于与此描述符关联的所有语句。 如果这不是必需的行为,则应用程序应在调用 SQLBindCol 之前将此描述符与其他语句取消关联。

参数映射

从概念上讲, SQLBindCol 按顺序执行以下步骤:

  1. 调用 SQLGetStmtAttr 以获取 ARD 句柄。

  2. 调用 SQLGetDescField 以获取此描述符的SQL_DESC_COUNT字段,如果 ColumnNumber 参数中的值超过 SQL_DESC_COUNT 的值,则调用 SQLSetDescField 将 SQL_DESC_COUNT 的值增加到 ColumnNumber

  3. 多次调用 SQLSetDescField 以向 ARD 的以下字段赋值:

    • 将SQL_DESC_TYPE和SQL_DESC_CONCISE_TYPE设置为 TargetType 的值,但如果 TargetType 是日期/时间或间隔子类型的简明标识符之一,则分别将SQL_DESC_TYPE设置为SQL_DATETIME或SQL_INTERVAL;将SQL_DESC_CONCISE_TYPE设置为简明标识符;和 将SQL_DESC_DATETIME_INTERVAL_CODE设置为相应的日期/时间或间隔子代码。

    • 根据 TargetType 设置一个或多个SQL_DESC_LENGTH、SQL_DESC_PRECISION、SQL_DESC_SCALE和SQL_DESC_DATETIME_INTERVAL_PRECISION。

    • 将SQL_DESC_OCTET_LENGTH字段设置为 BufferLength 的值。

    • 将 SQL_DESC_DATA_PTR 字段设置为 TargetValuePtr 的值。

    • 将SQL_DESC_INDICATOR_PTR字段设置为 StrLen_or_IndPtr 的值。 (请参阅以下段落。)

    • 将SQL_DESC_OCTET_LENGTH_PTR字段设置为 StrLen_or_IndPtr 的值。 (请参阅以下段落。)

StrLen_or_IndPtr 参数引用的变量同时用于指示器和长度信息。 如果提取遇到列的 null 值,它将SQL_NULL_DATA存储在此变量中;否则,它将数据长度存储在此变量中。 将 null 指针作为 StrLen_or_IndPtr 使提取操作不会返回数据长度,但如果提取遇到 null 值并且无法返回SQL_NULL_DATA,则提取操作会失败。

如果对 SQLBindCol 的调用失败,它将在 ARD 中设置的描述符字段的内容未定义,并且 ARD SQL_DESC_COUNT 字段的值保持不变。

COUNT 字段的隐式重置

仅当这会增加 SQL_DESC_COUNT 的值时,SQLBindCol 才会将SQL_DESC_COUNT设置为 ColumnNumber 参数的值。 如果 TargetValuePtr 参数中的值为 null 指针,并且 ColumnNumber 参数中的值等于SQL_DESC_COUNT (即取消绑定最高绑定列) 时,SQL_DESC_COUNT设置为剩余绑定列的最大数目。

有关SQL_DEFAULT的注意事项

若要成功检索列数据,应用程序必须正确确定应用程序缓冲区中数据的长度和起点。 当应用程序指定显式 TargetType 时,很容易检测到应用程序误解。 但是,当应用程序将 TargetType 指定为 SQL_DEFAULT 时, SQLBindCol 可以应用于与应用程序预期的数据类型不同的列,无论是对元数据的更改,还是通过将代码应用于其他列。 在这种情况下,应用程序可能并不总是确定提取的列数据的开头或长度。 这可能会导致未报告的数据错误或内存冲突。

代码示例

在以下示例中,应用程序对 Customers 表执行 SELECT 语句,以返回按名称排序的客户 ID、姓名和电话号码的结果集。 然后,它调用 SQLBindCol 将数据列绑定到本地缓冲区。 最后,应用程序使用 SQLFetch 提取每一行数据,并打印每个客户的姓名、ID 和电话号码。

有关更多代码示例,请参阅 SQLBulkOperations 函数SQLColumns 函数SQLFetchScroll 函数SQLSetPos 函数

// SQLBindCol_ref.cpp  
// compile with: odbc32.lib  
#include <windows.h>  
#include <stdio.h>  
  
#define UNICODE  
#include <sqlext.h>  
  
#define NAME_LEN 50  
#define PHONE_LEN 60
  
void show_error() {  
   printf("error\n");  
}  
  
int main() {  
   SQLHENV henv;  
   SQLHDBC hdbc;  
   SQLHSTMT hstmt = 0;  
   SQLRETURN retcode;  
   SQLWCHAR szName[NAME_LEN], szPhone[PHONE_LEN], sCustID[NAME_LEN];  
   SQLLEN cbName = 0, cbCustID = 0, cbPhone = 0;  
  
   // Allocate environment handle  
   retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);  
  
   // Set the ODBC version environment attribute  
   if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {  
      retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER*)SQL_OV_ODBC3, 0);   
  
      // Allocate connection handle  
      if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {  
         retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);  
  
         // Set login timeout to 5 seconds  
         if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {  
            SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);  
  
            // Connect to data source  
            retcode = SQLConnect(hdbc, (SQLWCHAR*) L"NorthWind", SQL_NTS, (SQLWCHAR*) NULL, 0, NULL, 0);  
  
            // Allocate statement handle  
            if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {   
               retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);   
  
               retcode = SQLExecDirect(hstmt, (SQLWCHAR *) L"SELECT CustomerID, ContactName, Phone FROM CUSTOMERS ORDER BY 2, 1, 3", SQL_NTS);  
               if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {  
  
                  // Bind columns 1, 2, and 3  
                  retcode = SQLBindCol(hstmt, 1, SQL_C_WCHAR, &sCustID, 100, &cbCustID);  
                  retcode = SQLBindCol(hstmt, 2, SQL_C_WCHAR, szName, NAME_LEN, &cbName);  
                  retcode = SQLBindCol(hstmt, 3, SQL_C_WCHAR, szPhone, PHONE_LEN, &cbPhone);   
  
                  // Fetch and print each row of data. On an error, display a message and exit.  
                  for (int i=0 ; ; i++) {  
                     retcode = SQLFetch(hstmt);  
                     if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO)  
                        show_error();  
                     if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)  
                     {
                        //replace wprintf with printf
                        //%S with %ls
                        //warning C4477: 'wprintf' : format string '%S' requires an argument of type 'char *'
                        //but variadic argument 2 has type 'SQLWCHAR *'
                        //wprintf(L"%d: %S %S %S\n", i + 1, sCustID, szName, szPhone);  
                        printf("%d: %ls %ls %ls\n", i + 1, sCustID, szName, szPhone);  
                    }    
                     else  
                        break;  
                  }  
               }  
  
               // Process data  
               if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {  
                  SQLCancel(hstmt);  
                  SQLFreeHandle(SQL_HANDLE_STMT, hstmt);  
               }  
  
               SQLDisconnect(hdbc);  
            }  
  
            SQLFreeHandle(SQL_HANDLE_DBC, hdbc);  
         }  
      }  
      SQLFreeHandle(SQL_HANDLE_ENV, henv);  
   }  
}  

另请参阅 示例 ODBC 程序

有关以下方面的信息 请参阅
返回有关结果集中列的信息 SQLDescribeCol 函数
提取数据块或滚动浏览结果集 SQLFetchScroll Function(SQLFetchScroll 函数)
提取多行数据 SQLFetch 函数
释放 语句上的列缓冲区 SQLFreeStmt 函数
提取部分或全部数据列 SQLGetData 函数
返回结果集列数 SQLNumResultCols 函数

另请参阅

ODBC API 参考
ODBC 头文件