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时,可以通过使用 handleType of SQL_HANDLE_DESC 和 TargetDescHandle调用 SQLGetDiagRec 来获取关联的 SQLSTATE 值。 如果在调用中传递了无效 的 SourceDescHandle ,将返回SQL_INVALID_HANDLE,但不会返回 SQLSTATE。 下表列出了 SQLCopyDesc 通常返回的 SQLSTATE 值,并解释此函数上下文中的每个值;表示法“(DM)”位于驱动程序管理器返回的 SQLSTATE 的说明之前。 除非另有说明,否则与每个 SQLSTATE 值关联的返回代码SQL_ERROR。

返回错误后,将立即中止对 SQLCopyDesc 的调用,并且 TargetDescHandle 描述符中字段的内容未定义。

由于 SQLCopyDesc 可以通过调用 SQLGetDescField 和 SQLSetDescField 来实现,SQLCopyDesc 可能会返回 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、SQLExecuteSQLExecDirectSQLBulkOperationsSQLSetPos 调用并返回SQL_NEED_DATA的 StatementHandle 相关联。 在为所有数据执行参数或列发送数据之前调用此函数。

(DM) 为与 SourceDescHandle 或 TargetDescHandle 关联的连接句柄调用异步执行函数。 调用 SQLCopyDesc 函数时,此异步函数仍在执行。

(DM) SQLExecuteSQLExecDirectSQLMoreResults 被调用为与 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(未准备关联的语句)。

无论是否已准备好语句,都可以从 IPD 复制字段。 如果已准备好具有动态参数的 SQL 语句,并且支持并启用 IPD 的自动填充,则驱动程序将填充 IPD。 使用 IPD 作为 SourceDescHandle 调用 SQLCopyDesc,将复制填充的字段。 如果驱动程序未填充 IPD,则会复制最初在 IPD 中的字段内容。

将复制描述符的所有字段(SQL_DESC_ALLOC_TYPE(它指定描述符句柄是自动还是显式分配),无论是否为目标描述符定义字段。 复制的字段将覆盖现有字段。

如果 SourceDescHandle 和 TargetDescHandle 参数与同一驱动程序关联,则驱动程序将复制所有描述符字段,即使驱动程序位于两个不同的连接或环境中也是如此。 如果 SourceDescHandleTargetDescHandle 参数与不同的驱动程序相关联,驱动程序管理器将复制 ODBC 定义的字段,但不复制 ODBC 未为描述符类型定义的驱动程序定义的字段或字段。

如果发生错误,将立即中止对 SQLCopyDesc 的调用。

复制SQL_DESC_DATA_PTR字段时,对目标描述符执行一致性检查。 如果一致性检查失败,则会返回 SQLSTATE HY021(不一致的描述符信息),并立即中止对 SQLCopyDesc 的 调用。 有关一致性检查的详细信息,请参阅 SQLSetDescRec 函数中的“一致性检查”。

即使连接在不同的环境中,也可以跨连接复制描述符句柄。 如果驱动程序管理器检测到源和目标描述符句柄不属于同一连接,并且两个连接属于单独的驱动程序,则它通过使用 SQLGetDescField 和 SQLSetDescField 执行逐字段复制来实现 SQLCopyDescc

在一个驱动程序上使用 SourceDescHandle 和另一个驱动程序上的 TargetDescHandle 调用 SQLCopyDesc 时,将清除 SourceDescHandle 的错误队列。 之所以发生这种情况,是因为 SQLCopyDesc 在本例中通过调用 SQLGetDescFieldSQLSetDescField 来实现。

注意

应用程序可能能够将显式分配的描述符句柄与 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 字段将复制到 hstmt1APD 字段。 使用 SQLSetDescField 将具有输出参数的语句中的 IRD 字段复制到需要输入参数的 IPD 字段时,将 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 函数

另请参阅

ODBC API 参考
ODBC 头文件