SQLCopyDesc 函数
一致性
引入的版本:ODBC 3.0 标准符合性:ISO 92
摘要
SQLCopyDesc 将描述符信息从一个描述符句柄复制到另一个描述符句柄。
语法
SQLRETURN SQLCopyDesc(
SQLHDESC SourceDescHandle,
SQLHDESC TargetDescHandle);
参数
SourceDescHandle
[输入]源描述符句柄。
TargetDescHandle
[输入]目标描述符句柄。
TargetDescHandle 参数可以是应用程序描述符或 IPD 的句柄。
TargetDescHandle 不能设置为 IRD 的句柄,或者 SQLCopyDesc 将返回 SQLSTATE HY016 (无法修改实现行描述符) 。
返回
SQL_SUCCESS、SQL_SUCCESS_WITH_INFO、SQL_ERROR 或 SQL_INVALID_HANDLE。
诊断
当 SQLCopyDesc 返回SQL_ERROR或SQL_SUCCESS_WITH_INFO时,可以通过调用 SqlGetDiagRec 来获取关联的 SQLSTATE 值,该 SQLGetDiagRec 的 HandleType 为 SQL_HANDLE_DESC, 句柄 为 TargetDescHandle。 如果在调用中传递了无效的 SourceDescHandle ,将返回SQL_INVALID_HANDLE,但不会返回 SQLSTATE。 下表列出了 SQLCopyDesc 通常返回的 SQLSTATE 值,并说明了此函数上下文中的每个值;表示法“ (DM) ”位于驱动程序管理器返回的 SQLSTATEs 说明之前。 与每个 SQLSTATE 值关联的返回代码SQL_ERROR,除非另有说明。
返回错误时,将立即中止对 SQLCopyDesc 的调用,并且 TargetDescHandle 描述符中字段的内容未定义。
由于 SQLCopyDescc 可通过调用 SQLGetDescField 和 SQLSetDescField 来实现, 因此 SQLCopyDescc 可能会返回由 SQLGetDescField 或 SQLSetDescField 返回的 SQLSTATEs。
SQLSTATE | 错误 | 描述 |
---|---|---|
01000 | 常规警告 | 特定于驱动程序的信息性消息。 (函数返回 SQL_SUCCESS_WITH_INFO.) |
08S01 | 通信链接失败 | 在函数完成处理之前,驱动程序与驱动程序连接到的数据源之间的通信链接失败。 |
HY000 | 常规错误 | 发生错误,其中没有特定的 SQLSTATE,并且没有定义特定于实现的 SQLSTATE。 *MessageText 缓冲区中 SQLGetDiagRec 返回的错误消息描述了错误及其原因。 |
HY001 | 内存分配错误 | 驱动程序无法分配支持执行或完成函数所需的内存。 |
HY007 | 未准备关联的语句 | SourceDescHandle 与 IRD 相关联,关联的语句句柄未处于准备或已执行状态。 |
HY010 | 函数序列错误 | (DM) SourceDescHandle 或 TargetDescHandle 中的描述符句柄与 StatementHandle 相关联,该语句的异步执行函数 (调用了) 的函数,并在调用此函数时仍在执行。 (DM) SourceDescHandle 或 TargetDescHandle 中的描述符句柄与为其调用 SQLExecute、SQLExecDirect、SQLBulkOperations 或 SQLSetPos 并返回SQL_NEED_DATA的 StatementHandle 相关联。 在为所有数据执行时参数或列发送数据之前调用了此函数。 (DM) 已为与 SourceDescHandle 或 TargetDescHandle 关联的连接句柄调用异步执行的函数。 调用 SQLCopyDesc 函数时,此异步函数仍在执行。 (DM) SQLExecute、SQLExecDirect 或 SQLMoreResults 已为与 SourceDescHandle 或 TargetDescHandle 关联的语句句柄之一调用,并返回SQL_PARAM_DATA_AVAILABLE。 此函数是在检索所有流式处理参数的数据之前调用的。 |
HY013 | 内存管理错误 | 无法处理函数调用,因为无法访问基础内存对象,可能是因为内存不足。 |
HY016 | 无法修改实现行描述符 | TargetDescHandle 与 IRD 相关联。 |
HY021 | 描述符信息不一致 | 在一致性检查期间检查的描述符信息不一致。 有关详细信息,请参阅 SQLSetDescField 中的“一致性检查”。 |
HY092 | 无效的属性/选项标识符 | 对 SQLCopyDesc 的调用提示调用 SQLSetDescField,但 *ValuePtr 对 TargetDescHandle 上的 FieldIdentifier 参数无效。 |
HY117 | 由于未知的事务状态,连接已挂起。 仅允许断开连接和只读函数。 | (DM) 有关挂起状态的详细信息,请参阅 SQLEndTran 函数。 |
HYT01 | 超过连接超时时间 | 在数据源响应请求之前,连接超时期限已过期。 连接超时期限是通过 SQLSetConnectAttr SQL_ATTR_CONNECTION_TIMEOUT设置的。 |
IM001 | 驱动程序不支持此函数 | (DM) 与 SourceDescHandle 或 TargetDescHandle 关联的驱动程序不支持函数。 |
注释
调用 SQLCopyDesc 会将源描述符句柄的字段复制到目标描述符句柄。 字段只能复制到应用程序描述符或 IPD,而不能复制到 IRD。 可以从应用程序或实现描述符复制字段。
仅当语句句柄处于准备或执行状态时,才能从 IRD 复制字段;否则,函数返回 SQLSTATE HY007 (Associated 语句未准备) 。
无论语句是否已准备好,都可以从 IPD 复制字段。 如果已准备好具有动态参数的 SQL 语句,并且支持并启用了 IPD 的自动填充,则驱动程序将填充 IPD。 当使用 IPD 作为 SourceDescHandle 调用 SQLCopyDesc 时,将复制填充的字段。 如果驱动程序未填充 IPD,则会复制 IPD 中最初字段的内容。
除指定是自动还是显式分配描述符句柄) SQL_DESC_ALLOC_TYPE (之外,将复制描述符的所有字段,无论字段是否为目标描述符定义。 复制的字段将覆盖现有字段。
如果 SourceDescHandle 和 TargetDescHandle 参数与同一驱动程序相关联,驱动程序将复制所有描述符字段,即使驱动程序位于两个不同的连接或环境中也是如此。 如果 SourceDescHandle 和 TargetDescHandle 参数与不同的驱动程序相关联,驱动程序管理器将复制 ODBC 定义的字段,但不复制驱动程序定义的字段或未由 ODBC 为描述符类型定义的字段。
如果发生错误,将立即中止对 SQLCopyDesc 的调用。
复制SQL_DESC_DATA_PTR字段时,对目标描述符执行一致性检查。 如果一致性检查失败,将返回 SQLSTATE HY021 (不一致的描述符信息) ,并立即中止对 SQLCopyDesc 的调用。 有关一致性检查的详细信息,请参阅 SQLSetDescRec 函数中的“一致性检查”。
即使连接位于不同的环境中,也可以跨连接复制描述符句柄。 如果驱动程序管理器检测到源和目标描述符句柄不属于同一连接,并且两个连接属于单独的驱动程序,则它通过使用 SQLGetDescField 和 SQLSetDescField 逐字段复制来实现 SQLCopyDescc。
当在一个驱动程序上使用 SourceDescHandle 和在另一个驱动程序上使用 TargetDescHandle 调用 SQLCopyDesc时,将清除 SourceDescHandle 的错误队列。 之所以发生这种情况,是因为在这种情况下 ,SQLCopyDescc 是通过调用 SQLGetDescField 和 SQLSetDescField 实现的。
注意
应用程序也许能够将显式分配的描述符句柄与 StatementHandle 相关联,而不是调用 SQLCopyDesc 将字段从一个描述符复制到另一个描述符。 通过将 SQL_ATTR_APP_ROW_DESC 或 SQL_ATTR_APP_PARAM_DESC 语句属性设置为显式分配的描述符的句柄,可以将显式分配的描述符与同一 ConnectionHandle 上的另 一个 StatementHandle 相关联。 完成此操作后,无需调用 SQLCopyDesc 将描述符字段值从一个描述符复制到另一个描述符。 但是,描述符句柄不能与另一个 ConnectionHandle 上的 StatementHandle 相关联;若要在不同的 ConnectionHandles 上对 StatementHandles 使用相同的描述符字段值,必须调用 SQLCopyDesc。
有关描述符标头或记录中字段的说明,请参阅 SQLSetDescField 函数。 有关描述符的详细信息,请参阅 描述符。
在表之间复制行
应用程序可将数据从一个表复制到另一个表,而无需在应用程序级别复制数据。 为此,应用程序将相同的数据缓冲区和描述符信息绑定到提取数据的语句和将数据插入副本的语句。 这可以通过共享应用程序描述符 (将显式分配的描述符作为 ARD 绑定到一个语句和另一个) 中的 APD 来实现,也可以使用 SQLCopyDesc 复制两个语句的 ARD 和 APD 之间的绑定。 如果语句位于不同的连接上,则必须使用 SQLCopyDesc 。 此外,必须调用 SQLCopyDesc 来复制 IRD 和两个语句的 IPD 之间的绑定。 在同一连接上跨语句复制时,驱动程序为调用 SQLGetInfo 返回的SQL_ACTIVE_STATEMENTS信息类型必须大于 1,此操作才能成功。 (跨连接复制时,情况并非如此。)
代码示例
在以下示例中,描述符操作用于将 PartsSource 表的字段复制到 PartsCopy 表中。 PartsSource 表的内容将提取到 hstmt0 中的行集缓冲区中。 这些值用作 hstmt1 上 INSERT 语句的参数,用于填充 PartsCopy 表的列。 为此,将 hstmt0 IRD 的字段复制到 hstmt1 的 IPD 字段,并将 hstmt0 的 ARD 字段复制到 hstmt1 的 APD 字段。 将具有输出参数的语句中的 IRD 字段复制到需要输入参数的 IPD 字段时,使用 SQLSetDDescField 将 IPD 的 SQL_DESC_PARAMETER_TYPE 属性设置为SQL_PARAM_INPUT。
#define ROWS 100
#define DESC_LEN 50
#define SQL_SUCCEEDED(rc) (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)
// Template for a row
typedef struct {
SQLINTEGER sPartID;
SQLINTEGER cbPartID;
SQLUCHAR szDescription[DESC_LENGTH];
SQLINTEGER cbDescription;
REAL sPrice;
SQLINTEGER cbPrice;
} PartsSource;
PartsSource rget[ROWS]; // rowset buffer
SQLUSMALLINT sts_ptr[ROWS]; // status pointer
SQLHSTMT hstmt0, hstmt1;
SQLHDESC hArd0, hIrd0, hApd1, hIpd1;
// ARD and IRD of hstmt0
SQLGetStmtAttr(hstmt0, SQL_ATTR_APP_ROW_DESC, &hArd0, 0, NULL);
SQLGetStmtAttr(hstmt0, SQL_ATTR_IMP_ROW_DESC, &hIrd0, 0, NULL);
// APD and IPD of hstmt1
SQLGetStmtAttr(hstmt1, SQL_ATTR_APP_PARAM_DESC, &hApd1, 0, NULL);
SQLGetStmtAttr(hstmt1, SQL_ATTR_IMP_PARAM_DESC, &hIpd1, 0, NULL);
// Use row-wise binding on hstmt0 to fetch rows
SQLSetStmtAttr(hstmt0, SQL_ATTR_ROW_BIND_TYPE, (SQLPOINTER) sizeof(PartsSource), 0);
// Set rowset size for hstmt0
SQLSetStmtAttr(hstmt0, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER) ROWS, 0);
// Execute a select statement
SQLExecDirect(hstmt0, "SELECT PARTID, DESCRIPTION, PRICE FROM PARTS ORDER BY 3, 1, 2"",
SQL_NTS);
// Bind
SQLBindCol(hstmt0, 1, SQL_C_SLONG, rget[0].sPartID, 0,
&rget[0].cbPartID);
SQLBindCol(hstmt0, 2, SQL_C_CHAR, &rget[0].szDescription, DESC_LEN,
&rget[0].cbDescription);
SQLBindCol(hstmt0, 3, SQL_C_FLOAT, rget[0].sPrice,
0, &rget[0].cbPrice);
// Perform parameter bindings on hstmt1.
SQLCopyDesc(hArd0, hApd1);
SQLCopyDesc(hIrd0, hIpd1);
// Set the array status pointer of IRD
SQLSetStmtAttr(hstmt0, SQL_ATTR_ROW_STATUS_PTR, sts_ptr, SQL_IS_POINTER);
// Set the ARRAY_STATUS_PTR field of APD to be the same
// as that in IRD.
SQLSetStmtAttr(hstmt1, SQL_ATTR_PARAM_OPERATION_PTR, sts_ptr, SQL_IS_POINTER);
// Set the hIpd1 records as input parameters
rc = SQLSetDescField(hIpd1, 1, SQL_DESC_PARAMETER_TYPE, (SQLPOINTER)SQL_PARAM_INPUT, SQL_IS_INTEGER);
rc = SQLSetDescField(hIpd1, 2, SQL_DESC_PARAMETER_TYPE, (SQLPOINTER)SQL_PARAM_INPUT, SQL_IS_INTEGER);
rc = SQLSetDescField(hIpd1, 3, SQL_DESC_PARAMETER_TYPE, (SQLPOINTER)SQL_PARAM_INPUT, SQL_IS_INTEGER);
// Prepare an insert statement on hstmt1. PartsCopy is a copy of
// PartsSource
SQLPrepare(hstmt1, "INSERT INTO PARTS_COPY VALUES (?, ?, ?)", SQL_NTS);
// In a loop, fetch a rowset, and copy the fetched rowset to PARTS_COPY
rc = SQLFetchScroll(hstmt0, SQL_FETCH_NEXT, 0);
while (SQL_SUCCEEDED(rc)) {
// After the call to SQLFetchScroll, the status array has row
// statuses. This array is used as input status in the APD
// and hence determines which elements of the rowset buffer
// are inserted.
SQLExecute(hstmt1);
rc = SQLFetchScroll(hstmt0, SQL_FETCH_NEXT, 0);
} // while
相关函数
有关以下方面的信息 | 请参阅 |
---|---|
获取多个描述符字段 | SQLGetDescRec 函数 |
设置单个描述符字段 | SQLSetDescField 函数 |
设置多个描述符字段 | SQLSetDescRec 函数 |