Simular instruções de exclusão e atualização posicionadas

Se a fonte de dados não der suporte a instruções de exclusão e atualização posicionadas, o driver poderá simulá-las. Por exemplo, a biblioteca de cursores ODBC simula instruções de exclusão e atualização posicionadas. A estratégia geral para simular instruções de exclusão e atualização posicionadas é converter instruções posicionadas em pesquisadas. Isso é feito substituindo a cláusula WHERE CURRENT OF por uma cláusula WHERE pesquisada que identifica a linha atual.

Por exemplo, como a coluna CustID identifica exclusivamente cada linha na tabela Customers, a instrução de exclusão posicionada

DELETE FROM Customers WHERE CURRENT OF CustCursor  

pode ser convertida em

DELETE FROM Customers WHERE (CustID = ?)  

O driver pode usar um dos seguintes identificadores de linha na cláusula WHERE:

  • Colunas cujos valores servem para identificar de modo exclusivo cada linha na tabela. Por exemplo, chamar SQLSpecialColumns com SQL_BEST_ROWID retorna a coluna ideal ou o conjunto de colunas que cumprem esse propósito.

  • Pseudocolunas, fornecidas por algumas fontes de dados, com a finalidade de identificar cada linha de modo exclusivo. Elas também podem ser recuperadas chamando SQLSpecialColumns.

  • Um índice exclusivo, se disponível.

  • Todas as colunas no conjunto de resultados.

Exatamente quais colunas um driver deve usar na cláusula WHERE que ele constrói depende do driver. Em algumas fontes de dados, determinar um identificador de linha pode ter um alto custo. Porém, isso é mais rápido de executar e garante que uma instrução simulada atualize ou exclua no máximo uma linha. Dependendo dos recursos do DBMS subjacente, a configuração do uso de um identificador de linha pode ter um alto custo. Porém, isso é mais rápido de executar e garante que uma instrução simulada atualize ou exclua apenas uma linha. A configuração da opção de usar todas as colunas no conjunto de resultados geralmente é muito mais fácil. Contudo, a execução é mais lenta e, se as colunas não identificarem exclusivamente uma linha, poderá resultar em linhas serem involuntariamente atualizadas ou excluídas, em especial quando a lista de seleção do conjunto de resultados não contém todas as colunas que existem na tabela subjacente.

Dependendo de a qual das estratégias anteriores o driver dá suporte, um aplicativo pode escolher qual estratégia deseja que o driver use com o atributo de instrução SQL_ATTR_SIMULATE_CURSOR. Embora possa parecer estranho para um aplicativo correr o risco de atualizar ou excluir uma linha por engano, o aplicativo pode remover esse risco garantindo que as colunas no conjunto de resultados identifiquem exclusivamente cada linha no conjunto de resultados. Isso poupa o driver do esforço de precisar fazer isso.

Se o driver optar por usar um identificador de linha, ele interceptará a instrução SELECT FOR UPDATE que cria o conjunto de resultados. Se as colunas na lista de seleção não identificarem efetivamente uma linha, o driver adicionará as colunas necessárias ao fim da lista de seleção. Algumas fontes de dados têm uma só coluna que sempre identifica exclusivamente uma linha, como a coluna ROWID no Oracle. Se essa coluna estiver disponível, o driver a usará. Caso contrário, o driver chamará SQLSpecialColumns para cada tabela na cláusula FROM para recuperar uma lista das colunas que identificam exclusivamente cada linha. Uma restrição comum que resulta dessa técnica é que a simulação do cursor falha se há mais de uma tabela na cláusula FROM.

Não importa como o driver identifique linhas, ele geralmente retira a cláusula FOR UPDATE DA INSTRUÇÃO SELECT FOR UPDATE antes de enviá-la para a fonte de dados. A cláusula FOR UPDATE OF usada apenas com instruções de exclusão e atualização posicionadas. As fontes de dados que não dão suporte a instruções de exclusão e atualização posicionadas geralmente não dão suporte a elas.

Quando o aplicativo envia uma instrução de exclusão ou atualização posicionada para execução, o driver substitui a cláusula WHERE CURRENT OF por uma cláusula WHERE que contém o identificador de linha. Os valores dessas colunas são recuperados de um cache mantido pelo driver para cada coluna usada na cláusula WHERE. Depois que o driver substitui a cláusula WHERE, ele envia a instrução para a fonte de dados para execução.

Como exemplo, suponha que o aplicativo envie a seguinte instrução para criar um conjunto de resultados:

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

Se o aplicativo tiver definido SQL_ATTR_SIMULATE_CURSOR para solicitar uma garantia de exclusividade e se a fonte de dados não fornecer uma pseudocoluna que sempre identifique exclusivamente uma linha, o driver chamará SQLSpecialColumns para a tabela Customers, descobrirá que CustID é a chave para a tabela Customers e o adicionará à lista de seleção, e removerá a cláusula FOR UPDATE OF:

SELECT Name, Address, Phone, CustID FROM Customers  

Se o aplicativo não tiver solicitado uma garantia de exclusividade, o driver removerá apenas a cláusula FOR UPDATE OF:

SELECT Name, Address, Phone FROM Customers  

Suponha que o aplicativo role pelo conjunto de resultados e envie a seguinte instrução de atualização posicionada para execução, em que Cust é o nome do cursor sobre o conjunto de resultados:

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

Se o aplicativo não tiver solicitado uma garantia de exclusividade, o driver substituirá a cláusula WHERE e vinculará o parâmetro CustID à variável em seu cache:

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

Se o aplicativo não tiver solicitado uma garantia de exclusividade, o driver substituirá a cláusula WHERE e associará os parâmetros Name, Address e Phone nessa cláusula às variáveis em seu cache:

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