模擬定點更新和刪除陳述式
如果資料來源不支援定點更新和 Delete 陳述式,驅動程式可以模擬這些操作。 例如,ODBC 資料指標程式庫會模擬定點更新和 Delete 陳述式。 模擬定點更新和 Delete 陳述式的一般策略,是將定點陳述式轉換成搜尋陳述式。 做法是將 WHERE CURRENT OF 子句取代為可識別目前資料列的搜尋 WHERE 子句。
例如,因為 CustID 資料行會唯一識別 Customers 資料表中的每個資料列,已定位的 Delete 陳述式
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 子句中有一個以上的資料表,資料指標模擬就會失敗。
不論驅動程式如何識別資料列,通常會先從 SELECT FOR UPDATE 陳述式移除 FOR UPDATE OF 子句,再傳送至資料來源。 FOR UPDATE OF 子句只會與定點更新和 Delete 陳述式搭配使用。 若資料來源不支援定點更新和 Delete 陳述式,通常也不支援此子句。
應用程式提交定點更新或 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 = ?)