模拟定位更新和删除语句

如果数据源不支持定位更新和删除语句,驱动程序可以模拟这些语句。 例如,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 子句仅用于定位的更新和删除语句。 不支持定位更新和删除语句的数据源通常不支持这一子句。

当应用程序提交定位更新或删除语句以供执行时,驱动程序会将 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 = ?)