Simulation d’instructions de mise à jour et de suppression positionnées

Si la source de données ne prend pas en charge les instructions de mise à jour et de suppression positionnées, le pilote peut les simuler. Par exemple, la bibliothèque de curseurs ODBC simule les instructions de mise à jour et de suppression positionnées. La stratégie générale pour simuler des instructions de mise à jour et de suppression positionnées consiste à convertir les instructions positionnées en instructions recherchées. Pour ce faire, remplacez la clause WHERE CURRENT OF par une clause WHERE recherchée qui identifie la ligne active.

Par exemple, étant donné que la colonne CustID identifie de façon unique chaque ligne de la table Customers, l’instruction delete positionnée

DELETE FROM Customers WHERE CURRENT OF CustCursor  

peut être converti en

DELETE FROM Customers WHERE (CustID = ?)  

Le pilote peut utiliser l’un des identificateurs de ligne suivants dans la clause WHERE :

  • Colonnes dont les valeurs servent à identifier de manière unique chaque ligne de la table. Par exemple, l’appel de SQLSpecialColumns avec SQL_BEST_ROWID retourne la colonne ou l’ensemble optimal de colonnes qui servent cet objectif.

  • Pseudo-colonnes, fournies par certaines sources de données, à des fins d’identification unique de chaque ligne. Ceux-ci peuvent également être récupérables en appelant SQLSpecialColumns.

  • Index unique, le cas échéant.

  • Toutes les colonnes du jeu de résultats.

Exactement quelles colonnes un pilote doit utiliser dans la clause WHERE qu’il construit dépend du pilote. Sur certaines sources de données, la détermination d’un identificateur de ligne peut être coûteuse. Toutefois, il est plus rapide d’exécuter et de garantir qu’une instruction simulée met à jour ou supprime au maximum une ligne. Selon les fonctionnalités du SGBD sous-jacent, l’utilisation d’un identificateur de ligne peut être coûteuse à configurer. Toutefois, il est plus rapide d’exécuter et de garantir qu’une instruction simulée met à jour ou supprime une seule ligne. L’option d’utilisation de toutes les colonnes du jeu de résultats est généralement beaucoup plus facile à configurer. Toutefois, il est plus lent à s’exécuter et, si les colonnes n’identifient pas de manière unique une ligne, peuvent entraîner la mise à jour ou la suppression involontaires de lignes, en particulier lorsque la liste de sélection pour le jeu de résultats ne contient pas toutes les colonnes qui existent dans la table sous-jacente.

Selon les stratégies précédentes que le pilote prend en charge, une application peut choisir la stratégie qu’elle souhaite utiliser avec l’attribut d’instruction SQL_ATTR_SIMULATE_CURSOR. Bien qu’il semble étrange qu’une application risque de mettre à jour ou de supprimer involontairement une ligne, l’application peut supprimer ce risque en garantissant que les colonnes du jeu de résultats identifient de manière unique chaque ligne dans le jeu de résultats. Cela permet au pilote d’avoir à le faire.

Si le pilote choisit d’utiliser un identificateur de ligne, il intercepte l’instruction SELECT FOR UPDATE qui crée le jeu de résultats. Si les colonnes de la liste de sélection n’identifient pas efficacement une ligne, le pilote ajoute les colonnes nécessaires à la fin de la liste de sélection. Certaines sources de données ont une seule colonne qui identifie toujours de manière unique une ligne, telle que la colonne ROWID dans Oracle ; si une telle colonne est disponible, le pilote l’utilise. Sinon, le pilote appelle SQLSpecialColumns pour chaque table de la clause FROM pour récupérer une liste des colonnes qui identifient de manière unique chaque ligne. Une restriction courante qui résulte de cette technique est que la simulation de curseur échoue s’il existe plusieurs tables dans la clause FROM .

Peu importe la façon dont le pilote identifie les lignes, il supprime généralement la clause FOR UPDATE OF de l’instruction SELECT FOR UPDATE avant de l’envoyer à la source de données. La clause FOR UPDATE OF est utilisée uniquement avec les instructions de mise à jour et de suppression positionnées. Les sources de données qui ne prennent pas en charge les instructions de mise à jour et de suppression positionnées ne le prennent généralement pas en charge.

Lorsque l’application envoie une instruction de mise à jour ou de suppression positionnée pour l’exécution, le pilote remplace la clause WHERE CURRENT OF par une clause WHERE contenant l’identificateur de ligne. Les valeurs de ces colonnes sont récupérées à partir d’un cache géré par le pilote pour chaque colonne utilisée dans la clause WHERE . Une fois que le pilote a remplacé la clause WHERE , il envoie l’instruction à la source de données pour l’exécution.

Par exemple, supposons que l’application envoie l’instruction suivante pour créer un jeu de résultats :

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

Si l’application a défini SQL_ATTR_SIMULATE_CURSOR pour demander une garantie d’unicité et si la source de données ne fournit pas de pseudo-colonne qui identifie toujours de manière unique une ligne, le pilote appelle SQLSpecialColumns pour la table Customers, découvre que CustID est la clé de la table Customers et l’ajoute à la liste de sélection, et supprime la clause FOR UPDATE OF :

SELECT Name, Address, Phone, CustID FROM Customers  

Si l’application n’a pas demandé de garantie d’unicité, le pilote supprime uniquement la clause FOR UPDATE OF :

SELECT Name, Address, Phone FROM Customers  

Supposons que l’application fait défiler le jeu de résultats et envoie l’instruction de mise à jour positionnée suivante pour l’exécution, où Cust est le nom du curseur sur le jeu de résultats :

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

Si l’application n’a pas demandé de garantie d’unicité, le pilote remplace la clause WHERE et lie le paramètre CustID à la variable dans son cache :

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

Si l’application n’a pas demandé de garantie d’unicité, le pilote remplace la clause WHERE et lie les paramètres Name, Address et Téléphone dans cette clause aux variables de son cache :

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