SQLBulkOperations, fonction

Conformité
Version introduite : Conformité aux normes ODBC 3.0 : ODBC

Résumé
SQLBulkOperations effectue des insertions en bloc et des opérations de signet en bloc, notamment la mise à jour, la suppression et la récupération par signet.

Syntaxe

  
SQLRETURN SQLBulkOperations(  
     SQLHSTMT       StatementHandle,  
     SQLUSMALLINT   Operation);  

Arguments

StatementHandle
[Entrée] Handle d’instruction.

opération
[Entrée] Opération à effectuer :

SQL_ADD SQL_UPDATE_BY_BOOKMARK SQL_DELETE_BY_BOOKMARK SQL_FETCH_BY_BOOKMARK

Pour plus d’informations, consultez « Commentaires ».

Retours

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_NEED_DATA, SQL_STILL_EXECUTING, SQL_ERROR ou SQL_INVALID_HANDLE.

Diagnostics

Lorsque SQLBulkOperations retourne SQL_ERROR ou SQL_SUCCESS_WITH_INFO, une valeur SQLSTATE associée peut être obtenue en appelant SQLGetDiagRec avec un HandleType de SQL_HANDLE_STMT et un Handle of StatementHandle. Le tableau suivant répertorie les valeurs SQLSTATE généralement retournées par SQLBulkOperations et explique chacune d’elles dans le contexte de cette fonction ; la notation « (DM) » précède les descriptions de SQLSTATEs retournées par le Gestionnaire de pilotes. Le code de retour associé à chaque valeur SQLSTATE est SQL_ERROR, sauf indication contraire.

Pour tous les SQLSTATEs qui peuvent retourner des SQL_SUCCESS_WITH_INFO ou des SQL_ERROR (à l’exception de 01xxx SQLSTATEs), SQL_SUCCESS_WITH_INFO est retourné si une erreur se produit sur une ou plusieurs lignes, mais pas toutes, d’une opération multirow, et SQL_ERROR est retourné si une erreur se produit sur une opération à une seule ligne.

SQLSTATE Error Description
01000 Avertissement général Message d’information spécifique au pilote. (La fonction retourne SQL_SUCCESS_WITH_INFO.)
01004 Troncation droite des données de chaîne L’argument Operation a été SQL_FETCH_BY_BOOKMARK, et les données de chaîne ou binaires retournées pour une colonne ou des colonnes avec un type de données SQL_C_CHAR ou SQL_C_BINARY entraîné la troncation de caractères non vides ou de données binaires non NULL.
01S01 Erreur dans la ligne L’argument Operation a été SQL_ADD, et une erreur s’est produite dans une ou plusieurs lignes lors de l’exécution de l’opération, mais au moins une ligne a été ajoutée avec succès. (La fonction retourne SQL_SUCCESS_WITH_INFO.)

(Cette erreur est générée uniquement lorsqu’une application fonctionne avec odbc 2. x pilote.)
01S07 Troncation fractionnaire L’argument Operation a été SQL_FETCH_BY_BOOKMARK, le type de données de la mémoire tampon d’application n’était ni SQL_C_CHAR ni SQL_C_BINARY, et les données retournées aux mémoires tampons d’application pour une ou plusieurs colonnes ont été tronquées. (Pour les types de données C numériques, la partie fractionnaire du nombre a été tronquée. Pour les types de données time, timestamp et interval C qui contiennent un composant de temps, la partie fractionnaire de l’heure a été tronquée.)

(La fonction retourne SQL_SUCCESS_WITH_INFO.)
07006 Violation d’attribut de type de données restreinte L’argument Operation a été SQL_FETCH_BY_BOOKMARK et la valeur de données d’une colonne du jeu de résultats n’a pas pu être convertie en type de données spécifié par l’argument TargetType dans l’appel à SQLBindCol.

L’argument Operation a été SQL_UPDATE_BY_BOOKMARK ou SQL_ADD, et la valeur des données dans les mémoires tampons d’application n’a pas pu être convertie en type de données d’une colonne dans le jeu de résultats.
07009 Index de descripteur non valide L’argument Opération a été SQL_ADD, et une colonne était liée avec un nombre de colonnes supérieur au nombre de colonnes dans le jeu de résultats.
21S02 Le degré de la table dérivée ne correspond pas à la liste de colonnes L’argument Opération a été SQL_UPDATE_BY_BOOKMARK ; et aucune colonne n’était modifiable, car toutes les colonnes étaient non liées ou en lecture seule, ou la valeur dans la mémoire tampon de longueur/d’indicateur liée était SQL_COLUMN_IGNORE.
22001 Troncation droite des données de chaîne L’affectation d’un caractère ou d’une valeur binaire à une colonne du jeu de résultats a entraîné la troncation de caractères ou d’octets non vides (pour les caractères) ou non null (pour les binaires).
22003 Valeur numérique hors plage L’argument Operation a été SQL_ADD ou SQL_UPDATE_BY_BOOKMARK, et l’affectation d’une valeur numérique à une colonne dans le jeu de résultats a entraîné la tronquation de la partie entière (et non fractionnaire) du nombre.

L’argument Opération a été SQL_FETCH_BY_BOOKMARK, et le renvoi de la valeur numérique pour une ou plusieurs colonnes liées aurait entraîné une perte de chiffres significatifs.
22007 Format datetime non valide L’argument Operation a été SQL_ADD ou SQL_UPDATE_BY_BOOKMARK, et l’attribution d’une valeur de date ou d’horodatage à une colonne dans le jeu de résultats a entraîné l’expiration du champ year, month ou day.

L’argument Opération a été SQL_FETCH_BY_BOOKMARK, et le renvoi de la date ou de la valeur d’horodatage d’une ou de plusieurs colonnes liées aurait entraîné l’expiration du champ year, month ou day.
22008 Dépassement de champ date/heure L’argument Opération a été SQL_ADD ou SQL_UPDATE_BY_BOOKMARK, et les performances de l’arithmétique datetime sur les données envoyées à une colonne du jeu de résultats ont entraîné un champ datetime (champ année, mois, jour, heure, minute ou deuxième champ) du résultat se trouvant en dehors de la plage de valeurs autorisées pour le champ ou non valide en fonction des règles naturelles du calendrier grégorien pour datetimes.

L’argument Operation a été SQL_FETCH_BY_BOOKMARK, et les performances de l’arithmétique datetime sur les données récupérées à partir du jeu de résultats ont donné lieu à un champ datetime (l’année, le mois, le jour, l’heure, la minute ou le deuxième champ) du résultat qui sortait de la plage de valeurs autorisée pour le champ ou n’était pas valide en fonction des règles naturelles du calendrier grégorien pour datetimes.
22015 Dépassement de champ d’intervalle L’argument Operation a été SQL_ADD ou SQL_UPDATE_BY_BOOKMARK, et l’affectation d’un type C numérique ou d’intervalle exact à un type de données SQL d’intervalle a entraîné une perte de chiffres significatifs.

L’argument Operation a été SQL_ADD ou SQL_UPDATE_BY_BOOKMARK ; lors de l’affectation à un type SQL d’intervalle, il n’y avait aucune représentation de la valeur du type C dans le type SQL d’intervalle.

L’argument Operation a été SQL_FETCH_BY_BOOKMARK, et l’affectation d’un type SQL numérique ou d’intervalle exact à un type C d’intervalle a entraîné une perte de chiffres significatifs dans le champ de début.

L’argument Operation a été SQL_FETCH_BY_BOOKMARK ; lors de l’affectation à un type d’intervalle C, il n’y avait aucune représentation de la valeur du type SQL dans le type d’intervalle C.
22018 Valeur de caractère non valide pour la spécification de cast L’argument Operation a été SQL_FETCH_BY_BOOKMARK ; le type C était un type de données numérique exact ou approximatif, un datetime ou un type de données d’intervalle ; le type SQL de la colonne était un type de données caractère ; et la valeur de la colonne n’était pas un littéral valide du type C lié.

L’argument Opération a été SQL_ADD ou SQL_UPDATE_BY_BOOKMARK ; le type SQL était un type de données numérique exact ou approximatif, un datetime ou un type de données d’intervalle ; le type C était SQL_C_CHAR ; et la valeur de la colonne n’était pas un littéral valide du type SQL lié.
23000 Violation de contrainte d’intégrité L’argument Operation a été SQL_ADD, SQL_DELETE_BY_BOOKMARK ou SQL_UPDATE_BY_BOOKMARK, et une contrainte d’intégrité a été violée.

L’argument Operation a été SQL_ADD, et une colonne qui n’était pas liée est définie comme NOT NULL et n’a pas de valeur par défaut.

L’argument Operation a été SQL_ADD, la longueur spécifiée dans la mémoire tampon liée StrLen_or_IndPtr était SQL_COLUMN_IGNORE et la colonne n’avait pas de valeur par défaut.
24 000 État de curseur non valide L’InstructionHandle était dans un état exécuté, mais aucun jeu de résultats n’a été associé à l’InstructionHandle.
40001 Échec de sérialisation La transaction a été annulée en raison d’un blocage des ressources avec une autre transaction.
40003 Saisie semi-automatique d’instruction inconnue La connexion associée a échoué pendant l’exécution de cette fonction et l’état de la transaction ne peut pas être déterminé.
42000 Erreur de syntaxe ou violation d’accès Le pilote n’a pas pu verrouiller la ligne si nécessaire pour effectuer l’opération demandée dans l’argument Operation .
44000 Violation de WITH CHECK OPTION L’argument Operation a été SQL_ADD ou SQL_UPDATE_BY_BOOKMARK, et l’insertion ou la mise à jour a été effectuée sur une table consultée (ou une table dérivée de la table consultée) qui a été créée en spécifiant WITH CHECK OPTION, de telle sorte qu’une ou plusieurs lignes affectées par l’insertion ou la mise à jour ne soient plus présentes dans la table consultée.
HY000 Erreur générale Une erreur s’est produite pour laquelle il n’y avait pas de SQLSTATE spécifique et pour laquelle aucun SQLSTATE spécifique à l’implémentation n’a été défini. Le message d’erreur retourné par SQLGetDiagRec dans la mémoire tampon *MessageText décrit l’erreur et sa cause.
HY001 Erreur d’allocation de mémoire Le pilote n’a pas pu allouer la mémoire nécessaire pour prendre en charge l’exécution ou l’achèvement de la fonction.
HY008 Opération annulée Le traitement asynchrone a été activé pour l’InstructionHandle. La fonction a été appelée et, avant la fin de son exécution, SQLCancel ou SQLCancelHandle a été appelée sur l’InstructionHandle. Ensuite, la fonction a été appelée à nouveau sur l’InstructionHandle.

La fonction a été appelée et, avant la fin de son exécution, SQLCancel ou SQLCancelHandle a été appelé sur l’InstructionHandle à partir d’un thread différent dans une application multithread.
HY010 Erreur de séquence de fonction (DM) Une fonction en exécution asynchrone a été appelée pour le handle de connexion associé à l’InstructionHandle. Cette fonction asynchrone était toujours en cours d’exécution lorsque la fonction SQLBulkOperations a été appelée.

(DM) SQLExecute, SQLExecDirect ou SQLMoreResults a été appelé pour l’InstructionHandle et a retourné SQL_PARAM_DATA_AVAILABLE. Cette fonction a été appelée avant la récupération des données pour tous les paramètres diffusés en continu.

(DM) L’InstructionHandle spécifiée n’était pas dans un état exécuté. La fonction a été appelée sans avoir d’abord appelé SQLExecDirect, SQLExecute ou une fonction de catalogue.

(DM) Une fonction en cours d’exécution asynchrone (et non celle-ci) a été appelée pour l’InstructionHandle et était toujours en cours d’exécution lorsque cette fonction a été appelée.

(DM) SQLExecute, SQLExecDirect ou SQLSetPos a été appelé pour l’InstructionHandle et a retourné SQL_NEED_DATA. Cette fonction a été appelée avant l’envoi des données pour toutes les colonnes ou paramètres de données au moment de l’exécution.

(DM) Le pilote était odbc 2. Le pilote x et SQLBulkOperations ont été appelés pour un InstructionHandle avant l’appel de SQLFetchScroll ou SQLFetch .

(DM) SQLBulkOperations a été appelé après l’appel de SQLExtendedFetch sur l’InstructionHandle.
HY011 Impossible de définir l’attribut maintenant (DM) Le pilote était odbc 2. Le pilote x et l’attribut d’instruction SQL_ATTR_ROW_STATUS_PTR ont été définis entre les appels à SQLFetch ou SQLFetchScroll et SQLBulkOperations.
HY013 Erreur de gestion de la mémoire L’appel de fonction n’a pas pu être traité, car les objets de mémoire sous-jacents n’ont pas pu être accessibles, peut-être en raison de conditions de mémoire insuffisantes.
HY090 Chaîne ou longueur de mémoire tampon non valide L’argument Opération était SQL_ADD ou SQL_UPDATE_BY_BOOKMARK ; une valeur de données n’était pas un pointeur Null ; le type de données C a été SQL_C_BINARY ou SQL_C_CHAR ; et la valeur de longueur de colonne était inférieure à 0, mais non égale à SQL_DATA_AT_EXEC, SQL_COLUMN_IGNORE, SQL_NTS ou SQL_NULL_DATA, ou inférieure ou égale à SQL_LEN_DATA_AT_EXEC_OFFSET.

La valeur d’une mémoire tampon de longueur/indicateur a été SQL_DATA_AT_EXEC ; le type SQL était SQL_LONGVARCHAR, SQL_LONGVARBINARY ou un type de données long spécifique à la source de données ; et le type d’informations SQL_NEED_LONG_DATA_LEN dans SQLGetInfo était « Y ».

L’argument Operation a été SQL_ADD, l’attribut d’instruction SQL_ATTR_USE_BOOKMARK a été défini sur SQL_UB_VARIABLE et la colonne 0 a été liée à une mémoire tampon dont la longueur n’était pas égale à la longueur maximale du signet pour ce jeu de résultats. (Cette longueur est disponible dans le champ SQL_DESC_OCTET_LENGTH de l’IRD et peut être obtenue en appelant SQLDescribeCol, SQLColAttribute ou SQLGetDescField.)
HY092 Identificateur d’attribut non valide (DM) La valeur spécifiée pour l’argument Operation n’était pas valide.

L’argument Operation a été SQL_ADD, SQL_UPDATE_BY_BOOKMARK ou SQL_DELETE_BY_BOOKMARK, et l’attribut d’instruction SQL_ATTR_CONCURRENCY a été défini sur SQL_CONCUR_READ_ONLY.

L’argument Opération était SQL_DELETE_BY_BOOKMARK, SQL_FETCH_BY_BOOKMARK ou SQL_UPDATE_BY_BOOKMARK, et la colonne bookmark n’était pas liée ou l’attribut d’instruction SQL_ATTR_USE_BOOKMARKS a été défini sur SQL_UB_OFF.
HY117 La connexion est suspendue en raison d’un état de transaction inconnu. Seules les fonctions de déconnexion et de lecture seule sont autorisées. (DM) Pour plus d’informations sur l’état suspendu, consultez Fonction SQLEndTran.
HYC00 Fonctionnalité facultative non implémentée Le pilote ou la source de données ne prend pas en charge l’opération demandée dans l’argument Opération .
HYT00 Délai expiré Le délai d’expiration de la requête a expiré avant que la source de données n’a retourné le jeu de résultats. Le délai d’expiration est défini via SQLSetStmtAttr avec un argument Attribute de SQL_ATTR_QUERY_TIMEOUT.
HYT01 Délai d’attente de la connexion expiré Le délai d’expiration de la connexion a expiré avant que la source de données ne réponde à la demande. Le délai d’expiration de connexion est défini via SQLSetConnectAttr, SQL_ATTR_CONNECTION_TIMEOUT.
IM001 Le pilote ne prend pas en charge cette fonction (DM) Le pilote associé à l’InstructionHandle ne prend pas en charge la fonction .
IM017 L’interrogation est désactivée en mode de notification asynchrone Chaque fois que le modèle de notification est utilisé, l’interrogation est désactivée.
IM018 SQLCompleteAsync n’a pas été appelé pour effectuer l’opération asynchrone précédente sur ce handle. Si l’appel de fonction précédent sur le handle retourne SQL_STILL_EXECUTING et si le mode de notification est activé, SQLCompleteAsync doit être appelé sur le handle pour effectuer le post-traitement et terminer l’opération.

Commentaires

Attention

Pour plus d’informations sur les états d’instruction qui peuvent être appelés dans SQLBulkOperations et sur ce qu’il doit faire pour la compatibilité avec ODBC 2. Pour les applications x , consultez la section Curseurs de bloc, Curseurs à défilement et Compatibilité descendante de l’Annexe G : Instructions de pilote pour la compatibilité descendante.

Une application utilise SQLBulkOperations pour effectuer les opérations suivantes sur la table ou la vue de base qui correspond à la requête actuelle :

  • Ajoutez de nouvelles lignes.

  • Mettez à jour un ensemble de lignes où chaque ligne est identifiée par un signet.

  • Supprimez un ensemble de lignes où chaque ligne est identifiée par un signet.

  • Récupérez un ensemble de lignes où chaque ligne est identifiée par un signet.

Après un appel à SQLBulkOperations, la position du curseur de bloc n’est pas définie. L’application doit appeler SQLFetchScroll pour définir la position du curseur. Une application doit appeler SQLFetchScroll uniquement avec un argument FetchOrientation de SQL_FETCH_FIRST, SQL_FETCH_LAST, SQL_FETCH_ABSOLUTE ou SQL_FETCH_BOOKMARK. La position du curseur n’est pas définie si l’application appelle SQLFetch ou SQLFetchScroll avec un argument FetchOrientation de SQL_FETCH_PRIOR, SQL_FETCH_NEXT ou SQL_FETCH_RELATIVE.

Une colonne peut être ignorée dans les opérations en bloc effectuées par un appel à SQLBulkOperations en définissant la longueur de colonne/la mémoire tampon d’indicateur spécifiée dans l’appel à SQLBindCol sur SQL_COLUMN_IGNORE.

Il n’est pas nécessaire que l’application définisse l’attribut d’instruction SQL_ATTR_ROW_OPERATION_PTR lorsqu’elle appelle SQLBulkOperations , car les lignes ne peuvent pas être ignorées lors de l’exécution d’opérations en bloc avec cette fonction.

La mémoire tampon pointée par l’attribut d’instruction SQL_ATTR_ROWS_FETCHED_PTR contient le nombre de lignes affectées par un appel à SQLBulkOperations.

Lorsque l’argument Opération est SQL_ADD ou SQL_UPDATE_BY_BOOKMARK et que la liste de sélection de la spécification de requête associée au curseur contient plusieurs références à la même colonne, il est défini par le pilote si une erreur est générée ou si le pilote ignore les références dupliquées et effectue les opérations demandées.

Pour plus d’informations sur l’utilisation de SQLBulkOperations, consultez Mise à jour des données avec SQLBulkOperations.

Exécution d’insertions en bloc

Pour insérer des données avec SQLBulkOperations, une application effectue la séquence d’étapes suivante :

  1. Exécute une requête qui retourne un jeu de résultats.

  2. Définit l’attribut d’instruction SQL_ATTR_ROW_ARRAY_SIZE sur le nombre de lignes qu’il souhaite insérer.

  3. Appelle SQLBindCol pour lier les données qu’il souhaite insérer. Les données sont liées à un tableau dont la taille est égale à la valeur de SQL_ATTR_ROW_ARRAY_SIZE.

    Notes

    La taille du tableau pointé par l’attribut d’instruction SQL_ATTR_ROW_STATUS_PTR doit être égale à SQL_ATTR_ROW_ARRAY_SIZE ou SQL_ATTR_ROW_STATUS_PTR doit être un pointeur Null.

  4. Appelle SQLBulkOperations(StatementHandle, SQL_ADD) pour effectuer l’insertion.

  5. Si l’application a défini l’attribut d’instruction SQL_ATTR_ROW_STATUS_PTR, elle peut inspecter ce tableau pour voir le résultat de l’opération.

Si une application lie la colonne 0 avant d’appeler SQLBulkOperations avec un argument Operation de SQL_ADD, le pilote met à jour les mémoires tampons de colonne 0 liée avec les valeurs de signet pour la ligne nouvellement insérée. Pour cela, l’application doit avoir défini l’attribut d’instruction SQL_ATTR_USE_BOOKMARKS sur SQL_UB_VARIABLE avant d’exécuter l’instruction. (Cela ne fonctionne pas avec odbc 2. pilote x .)

Les données longues peuvent être ajoutées en parties par SQLBulkOperations, à l’aide d’appels à SQLParamData et SQLPutData. Pour plus d’informations, consultez « Fourniture de données longues pour les insertions en bloc et les Mises à jour » plus loin dans cette référence de fonction.

Il n’est pas nécessaire pour l’application d’appeler SQLFetch ou SQLFetchScroll avant d’appeler SQLBulkOperations (sauf en cas de comparaison avec ODBC 2). pilote x ; consultez Compatibilité descendante et conformité aux normes).

Le comportement est défini par le pilote si SQLBulkOperations, avec l’argument Opération SQL_ADD, est appelé sur un curseur qui contient des colonnes en double. Le pilote peut retourner un SQLSTATE défini par le pilote, ajouter les données à la première colonne qui apparaît dans le jeu de résultats ou effectuer un autre comportement défini par le pilote.

Exécution de Mises à jour en bloc à l’aide de signets

Pour effectuer des mises à jour en bloc à l’aide de signets avec SQLBulkOperations, une application effectue les étapes suivantes dans l’ordre :

  1. Définit l’attribut d’instruction SQL_ATTR_USE_BOOKMARKS sur SQL_UB_VARIABLE.

  2. Exécute une requête qui retourne un jeu de résultats.

  3. Définit l’attribut d’instruction SQL_ATTR_ROW_ARRAY_SIZE sur le nombre de lignes qu’il souhaite mettre à jour.

  4. Appelle SQLBindCol pour lier les données qu’il souhaite mettre à jour. Les données sont liées à un tableau d’une taille égale à la valeur de SQL_ATTR_ROW_ARRAY_SIZE. Il appelle également SQLBindCol pour lier la colonne 0 (colonne signet).

  5. Copie les signets pour les lignes qu’il souhaite mettre à jour dans le tableau lié à la colonne 0.

  6. Mises à jour les données dans les mémoires tampons liées.

    Notes

    La taille du tableau pointé vers l’attribut d’instruction SQL_ATTR_ROW_STATUS_PTR doit être égale à SQL_ATTR_ROW_ARRAY_SIZE ou SQL_ATTR_ROW_STATUS_PTR doit être un pointeur null.

  7. Appelle SQLBulkOperations(StatementHandle, SQL_UPDATE_BY_BOOKMARK).

    Notes

    Si l’application a défini l’attribut d’instruction SQL_ATTR_ROW_STATUS_PTR, elle peut inspecter ce tableau pour voir le résultat de l’opération.

  8. Appelle éventuellement SQLBulkOperations(StatementHandle, SQL_FETCH_BY_BOOKMARK) pour extraire des données dans les mémoires tampons d’application liées afin de vérifier que la mise à jour s’est produite.

  9. Si les données ont été mises à jour, le pilote modifie la valeur dans le tableau d’état des lignes pour les lignes appropriées en SQL_ROW_UPDATED.

Les mises à jour en bloc effectuées par SQLBulkOperations peuvent inclure des données longues à l’aide d’appels à SQLParamData et SQLPutData. Pour plus d’informations, consultez « Fourniture de données longues pour les insertions en bloc et les Mises à jour » plus loin dans cette référence de fonction.

Si les signets persistent entre les curseurs, l’application n’a pas besoin d’appeler SQLFetch ou SQLFetchScroll avant de procéder à la mise à jour par signets. Il peut utiliser des signets qu’il a stockés à partir d’un curseur précédent. Si les signets ne sont pas persistants entre les curseurs, l’application doit appeler SQLFetch ou SQLFetchScroll pour récupérer les signets.

Le comportement est défini par le pilote si SQLBulkOperations, avec un argument Operation de SQL_UPDATE_BY_BOOKMARK, est appelé sur un curseur qui contient des colonnes en double. Le pilote peut retourner un SQLSTATE défini par le pilote, mettre à jour la première colonne qui apparaît dans le jeu de résultats ou effectuer un autre comportement défini par le pilote.

Exécution d’extractions en bloc à l’aide de signets

Pour effectuer des extractions en bloc à l’aide de signets avec SQLBulkOperations, une application effectue les étapes suivantes dans l’ordre :

  1. Définit l’attribut d’instruction SQL_ATTR_USE_BOOKMARKS sur SQL_UB_VARIABLE.

  2. Exécute une requête qui retourne un jeu de résultats.

  3. Définit l’attribut d’instruction SQL_ATTR_ROW_ARRAY_SIZE sur le nombre de lignes qu’il souhaite extraire.

  4. Appelle SQLBindCol pour lier les données qu’il souhaite extraire. Les données sont liées à un tableau d’une taille égale à la valeur de SQL_ATTR_ROW_ARRAY_SIZE. Il appelle également SQLBindCol pour lier la colonne 0 (colonne signet).

  5. Copie les signets pour les lignes qu’il souhaite extraire dans le tableau lié à la colonne 0. (Cela suppose que l’application a déjà obtenu les signets séparément.)

    Notes

    La taille du tableau pointé vers l’attribut d’instruction SQL_ATTR_ROW_STATUS_PTR doit être égale à SQL_ATTR_ROW_ARRAY_SIZE ou SQL_ATTR_ROW_STATUS_PTR doit être un pointeur null.

  6. Appelle SQLBulkOperations(StatementHandle, SQL_FETCH_BY_BOOKMARK).

  7. Si l’application a défini l’attribut d’instruction SQL_ATTR_ROW_STATUS_PTR, elle peut inspecter ce tableau pour voir le résultat de l’opération.

Si les signets persistent entre les curseurs, l’application n’a pas besoin d’appeler SQLFetch ou SQLFetchScroll avant d’effectuer l’extraction par signets. Il peut utiliser des signets qu’il a stockés à partir d’un curseur précédent. Si les signets ne sont pas persistants entre les curseurs, l’application doit appeler SQLFetch ou SQLFetchScroll une fois pour récupérer les signets.

Exécution de suppressions en bloc à l’aide de signets

Pour effectuer des suppressions en bloc à l’aide de signets avec SQLBulkOperations, une application effectue les étapes suivantes dans l’ordre :

  1. Définit l’attribut d’instruction SQL_ATTR_USE_BOOKMARKS sur SQL_UB_VARIABLE.

  2. Exécute une requête qui retourne un jeu de résultats.

  3. Définit l’attribut d’instruction SQL_ATTR_ROW_ARRAY_SIZE sur le nombre de lignes qu’il souhaite supprimer.

  4. Appelle SQLBindCol pour lier la colonne 0 (colonne signet).

  5. Copie les signets pour les lignes qu’il souhaite supprimer dans le tableau lié à la colonne 0.

    Notes

    La taille du tableau pointé vers l’attribut d’instruction SQL_ATTR_ROW_STATUS_PTR doit être égale à SQL_ATTR_ROW_ARRAY_SIZE ou SQL_ATTR_ROW_STATUS_PTR doit être un pointeur null.

  6. Appelle SQLBulkOperations(StatementHandle, SQL_DELETE_BY_BOOKMARK).

  7. Si l’application a défini l’attribut d’instruction SQL_ATTR_ROW_STATUS_PTR, elle peut inspecter ce tableau pour voir le résultat de l’opération.

Si les signets persistent entre les curseurs, l’application n’a pas besoin d’appeler SQLFetch ou SQLFetchScroll avant de supprimer par signets. Il peut utiliser des signets qu’il a stockés à partir d’un curseur précédent. Si les signets ne sont pas persistants entre les curseurs, l’application doit appeler SQLFetch ou SQLFetchScroll une fois pour récupérer les signets.

Fourniture de données longues pour les insertions en bloc et les Mises à jour

Les données longues peuvent être fournies pour les insertions et mises à jour en bloc effectuées par des appels à SQLBulkOperations. Pour insérer ou mettre à jour des données longues, une application effectue les étapes suivantes en plus des étapes décrites dans les sections « Exécution d’insertions en bloc » et « Exécution d’un Mises à jour en bloc à l’aide de signets » plus haut dans cette rubrique.

  1. Lorsqu’elle lie les données à l’aide de SQLBindCol, l’application place une valeur définie par l’application, telle que le numéro de colonne, dans la mémoire tampon *TargetValuePtr pour les colonnes data-at-execution. La valeur peut être utilisée ultérieurement pour identifier la colonne.

    L’application place le résultat de la macro SQL_LEN_DATA_AT_EXEC(length) dans la mémoire tampon *StrLen_or_IndPtr . Si le type de données SQL de la colonne est SQL_LONGVARBINARY, SQL_LONGVARCHAR ou un type de données long spécifique à la source de données et que le pilote retourne « Y » pour le type d’informations SQL_NEED_LONG_DATA_LEN dans SQLGetInfo, la longueur correspond au nombre d’octets de données à envoyer pour le paramètre ; sinon, il doit s’agir d’une valeur non négative et est ignoré.

  2. Quand SQLBulkOperations est appelé, s’il existe des colonnes data-at-execution, la fonction retourne SQL_NEED_DATA et passe à l’étape 3, qui suit. (S’il n’existe aucune colonne data-at-execution, le processus est terminé.)

  3. L’application appelle SQLParamData pour récupérer l’adresse de la mémoire tampon *TargetValuePtr pour la première colonne data-at-execution à traiter. SQLParamData retourne SQL_NEED_DATA. L’application récupère la valeur définie par l’application à partir de la mémoire tampon *TargetValuePtr .

    Notes

    Bien que les paramètres data-at-execution ressemblent à des colonnes data-at-execution, la valeur retournée par SQLParamData est différente pour chacune d’elles.

    Les colonnes data-at-execution sont des colonnes d’un ensemble de lignes pour lesquelles des données sont envoyées avec SQLPutData lorsqu’une ligne est mise à jour ou insérée avec SQLBulkOperations. Ils sont liés à SQLBindCol. La valeur retournée par SQLParamData est l’adresse de la ligne dans la mémoire tampon *TargetValuePtr en cours de traitement.

  4. L’application appelle SQLPutData une ou plusieurs fois pour envoyer des données pour la colonne. Plusieurs appels sont nécessaires si toutes les valeurs de données ne peuvent pas être retournées dans la mémoire tampon *TargetValuePtr spécifiée dans SQLPutData ; plusieurs appels à SQLPutData pour la même colonne sont autorisés uniquement lors de l’envoi de données de caractère C à une colonne avec un type de données spécifique à la source de données, ou lors de l’envoi de données binaires C à une colonne avec un type de données caractère, binaire ou spécifique à la source de données.

  5. L’application appelle à nouveau SQLParamData pour signaler que toutes les données ont été envoyées pour la colonne.

    • S’il existe davantage de colonnes de données à l’exécution, SQLParamData retourne SQL_NEED_DATA et l’adresse de la mémoire tampon TargetValuePtr pour la colonne de données à l’exécution suivante à traiter. L’application répète les étapes 4 et 5.

    • S’il n’y a plus de colonnes de données à l’exécution, le processus est terminé. Si l’instruction a été exécutée correctement, SQLParamData retourne SQL_SUCCESS ou SQL_SUCCESS_WITH_INFO ; si l’exécution a échoué, elle retourne SQL_ERROR. À ce stade, SQLParamData peut retourner n’importe quel SQLSTATE qui peut être retourné par SQLBulkOperations.

Si l’opération est annulée ou si une erreur se produit dans SQLParamData ou SQLPutData après que SQLBulkOperations retourne SQL_NEED_DATA et avant que les données ne soient envoyées pour toutes les colonnes de données à l’exécution, l’application peut appeler uniquement SQLCancel, SQLGetDiagField, SQLGetDiagRec, SQLGetFunctions, SQLParamData ou SQLPutData pour l’instruction ou la connexion associée à l’instruction. Si elle appelle une autre fonction pour l’instruction ou la connexion associée à l’instruction, la fonction retourne SQL_ERROR et SQLSTATE HY010 (erreur de séquence de fonction).

Si l’application appelle SQLCancel alors que le pilote a toujours besoin de données pour les colonnes de données à l’exécution, le pilote annule l’opération. L’application peut ensuite appeler à nouveau SQLBulkOperations ; l’annulation n’affecte pas l’état du curseur ou la position actuelle du curseur.

Tableau d’état des lignes

Le tableau d’état des lignes contient des valeurs d’état pour chaque ligne de données de l’ensemble de lignes après un appel à SQLBulkOperations. Le pilote définit les valeurs d’état dans ce tableau après un appel à SQLFetch, SQLFetchScroll, SQLSetPos ou SQLBulkOperations. Ce tableau est initialement rempli par un appel à SQLBulkOperations si SQLFetch ou SQLFetchScroll n’a pas été appelé avant SQLBulkOperations. Ce tableau est pointé vers l’attribut d’instruction SQL_ATTR_ROW_STATUS_PTR. Le nombre d’éléments dans les tableaux d’état de ligne doit être égal au nombre de lignes dans l’ensemble de lignes (tel que défini par l’attribut d’instruction SQL_ATTR_ROW_ARRAY_SIZE). Pour plus d’informations sur ce tableau d’état de ligne, consultez SQLFetch.

Exemple de code

L’exemple suivant extrait 10 lignes de données à la fois à partir de la table Customers. Il invite ensuite l’utilisateur à effectuer une action. Pour réduire le trafic réseau, l’exemple de mémoire tampon met à jour, supprime et insère localement dans les tableaux liés, mais à des décalages au-delà des données de l’ensemble de lignes. Lorsque l’utilisateur choisit d’envoyer des mises à jour, des suppressions et des insertions à la source de données, le code définit le décalage de liaison de manière appropriée et appelle SQLBulkOperations. Par souci de simplicité, l’utilisateur ne peut pas mettre en mémoire tampon plus de 10 mises à jour, suppressions ou insertions.

// SQLBulkOperations_Function.cpp  
// compile with: ODBC32.lib  
#include <windows.h>  
#include <sqlext.h>  
#include "stdio.h"  
  
#define UPDATE_ROW 100  
#define DELETE_ROW 101  
#define ADD_ROW 102  
#define SEND_TO_DATA_SOURCE 103  
#define UPDATE_OFFSET 10  
#define INSERT_OFFSET 20  
#define DELETE_OFFSET 30  
  
// Define structure for customer data (assume 10 byte maximum bookmark size).  
typedef struct tagCustStruct {  
   SQLCHAR Bookmark[10];  
   SQLINTEGER BookmarkLen;  
   SQLUINTEGER CustomerID;  
   SQLINTEGER CustIDInd;  
   SQLCHAR CompanyName[51];  
   SQLINTEGER NameLenOrInd;  
   SQLCHAR Address[51];  
   SQLINTEGER AddressLenOrInd;  
   SQLCHAR Phone[11];  
   SQLINTEGER PhoneLenOrInd;  
} CustStruct;  
  
// Allocate 40 of these structures. Elements 0-9 are for the current rowset,  
// elements 10-19 are for the buffered updates, elements 20-29 are for  
// the buffered inserts, and elements 30-39 are for the buffered deletes.  
CustStruct CustArray[40];  
SQLUSMALLINT RowStatusArray[10], Action, RowNum, NumUpdates = 0, NumInserts = 0,  
NumDeletes = 0;  
SQLLEN BindOffset = 0;  
SQLRETURN retcode;  
SQLHENV henv = NULL;  
SQLHDBC hdbc = NULL;  
SQLHSTMT hstmt = NULL;  
  
int main() {  
   retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);  
   retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER*)SQL_OV_ODBC3, 0);   
  
   retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);   
   retcode = SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);  
  
   retcode = SQLConnect(hdbc, (SQLCHAR*) "Northwind", SQL_NTS, (SQLCHAR*) NULL, 0, NULL, 0);  
   retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);  
  
   // Set the following statement attributes:  
   // SQL_ATTR_CURSOR_TYPE:           Keyset-driven  
   // SQL_ATTR_ROW_BIND_TYPE:         Row-wise  
   // SQL_ATTR_ROW_ARRAY_SIZE:        10  
   // SQL_ATTR_USE_BOOKMARKS:         Use variable-length bookmarks  
   // SQL_ATTR_ROW_STATUS_PTR:        Points to RowStatusArray  
   // SQL_ATTR_ROW_BIND_OFFSET_PTR:   Points to BindOffset  
   retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_CURSOR_TYPE, (SQLPOINTER)SQL_CURSOR_KEYSET_DRIVEN, 0);  
   retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_BIND_TYPE, (SQLPOINTER)sizeof(CustStruct), 0);  
   retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)10, 0);  
   retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_USE_BOOKMARKS, (SQLPOINTER)SQL_UB_VARIABLE, 0);  
   retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_STATUS_PTR, RowStatusArray, 0);  
   retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_BIND_OFFSET_PTR, &BindOffset, 0);  
  
   // Bind arrays to the bookmark, CustomerID, CompanyName, Address, and Phone columns.  
   retcode = SQLBindCol(hstmt, 0, SQL_C_VARBOOKMARK, CustArray[0].Bookmark, sizeof(CustArray[0].Bookmark), &CustArray[0].BookmarkLen);  
   retcode = SQLBindCol(hstmt, 1, SQL_C_ULONG, &CustArray[0].CustomerID, 0, &CustArray[0].CustIDInd);  
   retcode = SQLBindCol(hstmt, 2, SQL_C_CHAR, CustArray[0].CompanyName, sizeof(CustArray[0].CompanyName), &CustArray[0].NameLenOrInd);  
   retcode = SQLBindCol(hstmt, 3, SQL_C_CHAR, CustArray[0].Address, sizeof(CustArray[0].Address), &CustArray[0].AddressLenOrInd);  
   retcode = SQLBindCol(hstmt, 4, SQL_C_CHAR, CustArray[0].Phone, sizeof(CustArray[0].Phone), &CustArray[0].PhoneLenOrInd);  
  
   // Execute a statement to retrieve rows from the Customers table.  
   retcode = SQLExecDirect(hstmt, (SQLCHAR*)"SELECT CustomerID, CompanyName, Address, Phone FROM Customers", SQL_NTS);  
  
   // Fetch and display the first 10 rows.  
   retcode = SQLFetchScroll(hstmt, SQL_FETCH_NEXT, 0);  
   // DisplayCustData(CustArray, 10);  
  
   // Call GetAction to get an action and a row number from the user.  
   // while (GetAction(&Action, &RowNum)) {  
   Action = SQL_FETCH_NEXT;  
   RowNum = 2;  
   switch (Action) {  
      case SQL_FETCH_NEXT:  
      case SQL_FETCH_PRIOR:  
      case SQL_FETCH_FIRST:  
      case SQL_FETCH_LAST:  
      case SQL_FETCH_ABSOLUTE:  
      case SQL_FETCH_RELATIVE:  
         // Fetch and display the requested data.  
         SQLFetchScroll(hstmt, Action, RowNum);  
         // DisplayCustData(CustArray, 10);  
         break;  
  
      case UPDATE_ROW:  
         // Check if we have reached the maximum number of buffered updates.  
         if (NumUpdates < 10) {  
            // Get the new customer data and place it in the next available element of  
            // the buffered updates section of CustArray, copy the bookmark of the row  
            // being updated to the same element, and increment the update counter.  
            // Checking to see we have not already buffered an update for this  
            // row not shown.  
            // GetNewCustData(CustArray, UPDATE_OFFSET + NumUpdates);  
            memcpy(CustArray[UPDATE_OFFSET + NumUpdates].Bookmark,  
               CustArray[RowNum - 1].Bookmark,  
               CustArray[RowNum - 1].BookmarkLen);  
            CustArray[UPDATE_OFFSET + NumUpdates].BookmarkLen =  
               CustArray[RowNum - 1].BookmarkLen;  
            NumUpdates++;  
         } else {  
            printf("Buffers full. Send buffered changes to the data source.");  
         }  
         break;  
      case DELETE_ROW:  
         // Check if we have reached the maximum number of buffered deletes.  
         if (NumDeletes < 10) {  
            // Copy the bookmark of the row being deleted to the next available element  
            // of the buffered deletes section of CustArray and increment the delete  
            // counter. Checking to see we have not already buffered an update for  
            // this row not shown.  
            memcpy(CustArray[DELETE_OFFSET + NumDeletes].Bookmark,  
               CustArray[RowNum - 1].Bookmark,  
               CustArray[RowNum - 1].BookmarkLen);  
  
            CustArray[DELETE_OFFSET + NumDeletes].BookmarkLen =  
               CustArray[RowNum - 1].BookmarkLen;  
  
            NumDeletes++;  
         } else  
            printf("Buffers full. Send buffered changes to the data source.");  
         break;  
  
      case ADD_ROW:  
         // reached maximum number of buffered inserts?  
         if (NumInserts < 10) {  
            // Get the new customer data and place it in the next available element of  
            // the buffered inserts section of CustArray and increment insert counter.  
            // GetNewCustData(CustArray, INSERT_OFFSET + NumInserts);  
            NumInserts++;  
         } else  
            printf("Buffers full. Send buffered changes to the data source.");  
         break;  
  
      case SEND_TO_DATA_SOURCE:  
         // If there are any buffered updates, inserts, or deletes, set the array size  
         // to that number, set the binding offset to use the data in the buffered  
         // update, insert, or delete part of CustArray, and call SQLBulkOperations to  
         // do the updates, inserts, or deletes. Because we will never have more than  
         // 10 updates, inserts, or deletes, we can use the same row status array.  
         if (NumUpdates) {  
            SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)NumUpdates, 0);  
            BindOffset = UPDATE_OFFSET * sizeof(CustStruct);  
            SQLBulkOperations(hstmt, SQL_UPDATE_BY_BOOKMARK);  
            NumUpdates = 0;  
         }  
  
         if (NumInserts) {  
            SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)NumInserts, 0);  
            BindOffset = INSERT_OFFSET * sizeof(CustStruct);  
            SQLBulkOperations(hstmt, SQL_ADD);  
            NumInserts = 0;  
         }  
  
         if (NumDeletes) {  
            SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)NumDeletes, 0);  
            BindOffset = DELETE_OFFSET * sizeof(CustStruct);  
            SQLBulkOperations(hstmt, SQL_DELETE_BY_BOOKMARK);  
            NumDeletes = 0;  
         }  
  
         // If there were any updates, inserts, or deletes, reset the binding offset  
         // and array size to their original values.  
         if (NumUpdates || NumInserts || NumDeletes) {  
            SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)10, 0);  
            BindOffset = 0;  
         }  
         break;  
   }  
   // }  
  
   // Close the cursor.  
   SQLFreeStmt(hstmt, SQL_CLOSE);  
}  
Pour obtenir des informations sur Consultez
Liaison d’une mémoire tampon à une colonne dans un jeu de résultats Fonction SQLBindCol
Annulation du traitement des instructions SQLCancel, fonction
Extraction d’un bloc de données ou défilement d’un jeu de résultats Fonction SQLFetchScroll
Obtention d’un champ unique d’un descripteur Fonction SQLGetDescField
Obtention de plusieurs champs d’un descripteur SQLGetDescRec, fonction
Définition d’un champ unique d’un descripteur SQLSetDescField, fonction
Définition de plusieurs champs d’un descripteur SQLSetDescRec, fonction
Positionnement du curseur, actualisation des données dans l’ensemble de lignes ou mise à jour ou suppression de données dans l’ensemble de lignes SQLSetPos, fonction
Définition d’un attribut d’instruction Fonction SQLSetStmtAttr

Voir aussi

Informations de référence sur l’API ODBC
Fichiers d’en-tête ODBC