模拟定位更新和删除语句

如果数据源不支持定位更新和删除语句,驱动程序可以模拟这些语句。 例如,ODBC 游标库模拟定位的更新和删除语句。 模拟定位更新和删除语句的一般策略是将定位语句转换为搜索语句。 通过将 WHERE CURRENT OF 子句替换为标识当前行的搜索 WHERE 子句来实现这一点。

例如,由于 CustID 列唯一标识 Customers 表中的每一行,因此定向删除语句

DELETE FROM Customers WHERE CURRENT OF CustCursor  

可能转换为

DELETE FROM Customers WHERE (CustID = ?)  

驱动程序可以在 WHERE 子句中使用以下行标识符之一:

  • 其值用于唯一标识表中每一行的列。 例如,使用 SQL_BEST_ROWID调用 SQLSpecialColumns 将返回满足此目的的最佳列或列集。

  • 伪列由某些数据源提供,目的是唯一标识每一行。 这些也可以通过调用 SQLSpecialColumns 进行检索。

  • 唯一索引(如果可用)。

  • 结果集中的所有列。

驱动程序在构造 WHERE 子句时应使用的确切列取决于具体的驱动程序。 在某些数据源中,确定行标识符的成本可能很高。 但是,执行速度更快并保证模拟语句最多更新或删除一行。 根据基础 DBMS 的功能,使用行标识符设置成本可能很高。 但是,执行速度更快并保证模拟语句仅更新或删除一行。 使用结果集中所有列的选项通常更容易设置。 但是,执行速度较慢,如果列不唯一地标识行,则可能会导致意外更新或删除行,尤其是在结果集的选择列表不包含基础表中存在的所有列时。

根据驱动程序支持的上述策略中的哪一种,应用程序可以选择它希望驱动程序与 SQL_ATTR_SIMULATE_CURSOR 语句属性一起使用的策略。 尽管应用程序在无意中更新或删除行的风险似乎很奇怪,但应用程序可以通过确保结果集中的列唯一地标识结果集中的每一行来消除此风险。 这样,司机就无需再完成这项任务。

如果驱动程序选择使用行标识符,它将截获创建结果集的 SELECT FOR UPDATE 语句。 如果选择列表中的列无法有效地标识行,驱动程序会将必要的列添加到选择列表的末尾。 某些数据源具有一个始终唯一标识行的列,例如 Oracle 中的 ROWID 列;如果此类列可用,驱动程序将使用此列。 否则,驱动程序将对 FROM 子句中的每个表调用 SQLSpecialColumns,以检索唯一标识每行的列的列表。 此方法产生的常见限制是,如果 FROM 子句中有多个表,游标模拟将失败。

无论驱动程序如何标识行,它通常都会在将 FOR UPDATE OF 子句从 SELECT FOR UPDATE 语句中剥离出来,然后再将其发送到数据源。 FOR UPDATE OF 子句仅用于定位的 update 和 delete 语句。 不支持定位更新和删除语句的数据源通常不支持它。

当应用程序提交定位更新或删除语句以供执行时,驱动程序会将 WHERE CURRENT OF 子句替换为包含行标识符的 WHERE 子句。 这些列的值从驱动程序维护的缓存中检索到它在 WHERE 子句中使用的每一列。 在驱动程序替换 WHERE 子句后,它将语句发送到数据源以供执行。

例如,假设应用程序提交以下语句来创建结果集:

SELECT Name, Address, Phone FROM Customers FOR UPDATE OF Phone, Address  

如果应用程序已设置SQL_ATTR_SIMULATE_CURSOR请求唯一性保证,并且数据源未提供始终唯一标识行的伪列,驱动程序将调用 Customers 表的 SQLSpecialColumns ,发现 CustID 是 Customers 表的关键,并将其添加到选择列表中, 并去除 FOR UPDATE OF 子句:

SELECT Name, Address, Phone, CustID FROM Customers  

如果应用程序未请求唯一性保证,驱动程序仅去除 FOR UPDATE OF 子句:

SELECT Name, Address, Phone FROM Customers  

假设应用程序滚动浏览结果集,并提交以下定位更新语句以供执行,其中 Cust 是结果集上的游标名称:

UPDATE Customers SET Address = ?, Phone = ? WHERE CURRENT OF Cust  

如果应用程序未请求唯一性保证,驱动程序将替换 WHERE 子句并将 CustID 参数绑定到其缓存中的变量:

UPDATE Customers SET Address = ?, Phone = ? WHERE (CustID = ?)  

如果应用程序未请求唯一性保证,驱动程序将替换 WHERE 子句并将此子句中的 Name、Address 和 Phone 参数绑定到其缓存中的变量:

UPDATE Customers SET Address = ?, Phone = ?  
   WHERE (Name = ?) AND (Address = ?) AND (Phone = ?)