Exécution d’instructions SQL avec des paramètres d’entrée
Il existe deux façons d’exécuter une instruction avec des paramètres d’entrée.Le choix de la bonne méthode dépend du fait que vous deviez l’exécuter plus d’une fois et que vous connaissiez ou non le format des paramètres au préalable. Lorsque ce format est connu et que vous n’avez besoin d’exécuter l’instruction qu’une seule fois, vous pouvez utiliser un seul appel à IAttachment::execute(). Sinon, vous devez d’abord préparer une requête SQL, puis vous pouvez l’exécuter à plusieurs reprises avec différents paramètres.
Pour préparer une instruction SQL en vue de son exécution, utilisez la méthode prepare()
de l’interface IAttachment
:
IStatement* stmt = att->prepare(&status, tra, 0,
"UPDATE department SET budget = ? * budget + budget WHERE dept_no = ?",
SQL_DIALECT_V6, IStatement::PREPARE_PREFETCH_METADATA);
Si vous n’avez pas l’intention d’utiliser la description des paramètres de Firebird (c’est-à-dire que vous pouvez fournir cette information vous-même), utilisez IStatement::PREPARE_PREFETCH_NONE
au lieu de IStatement::PREPARE_PREFETCH_METADATA
– cela réduira légèrement le trafic client/serveur et économisera des ressources.
Dans l’API ISC, la structure XSQLDA
est utilisée pour décrire le format des paramètres de l’opérateur. La nouvelle API n’utilise pas XSQLDA
— elle utilise IMessageMetadata
à la place.Un ensemble de paramètres d’entrée (ainsi qu’un enregistrement extrait du curseur) est décrit dans l’API Firebird de la même manière, ci-après dénommé message.IMessageMetadata
est transmis en tant que paramètre aux méthodes de messagerie entre le programme et le moteur de base de données. Il existe de nombreuses façons d’obtenir une instance de IMessageMetadata, en voici quelques-unes :
-
obtenir à partir de
IStatement
; -
construite à l’aide de l’interface
IMetadataBuilder
; -
Avec votre propre implémentation de cette interface.
La récupération des métadonnées à partir d’une requête préparée est très simple : la méthode getInputMetadata()
renvoie une interface qui décrit le message d’entrée (c’est-à-dire les paramètres de l’opérateur), l’interface renvoyée par getOutputMetadata()
décrit le message de sortie (c’est-à-dire une chaîne de données ou de valeurs sélectionnées renvoyées par la procédure). Dans notre cas, nous pouvons faire ce qui suit :
IMessageMetadata* meta = stmt->getInputMetadata(&status);
Ou nous pouvons créer nous-mêmes le message de métadonnées. Pour ce faire, tout d’abord, nous devons obtenir l’interface du constructeur :
IMetadataBuilder* builder = master->getMetadataBuilder(&status, 2);
Le deuxième paramètre est le nombre attendu de champs dans le message, il peut être modifié ultérieurement, c’est-à-dire qu’il n’est nécessaire que pour l’optimisation.
Ensuite, vous devez définir les caractéristiques individuelles des champs dans le générateur. Les types et longueurs de champ minimum requis sont les suivants :
builder->setType(&status, 0, SQL_DOUBLE + 1);
builder->setType(&status, 1, SQL_TEXT + 1);
builder->setLength(&status, 1, 3);
La nouvelle API utilise les anciennes constantes pour les types SQL, le plus petit bit est toujours utilisé pour indiquer la possibilité de prendre une valeur null
. Dans certains cas, il est judicieux de définir un sous-type (pour les BLOB), un jeu de caractères (pour les zones de texte) ou un facteur d’échelle (pour les champs numériques).Enfin, il est temps d’obtenir une instance de IMessageMetadata :
IMessageMetadata* meta = builder->getMetadata(&status);
Nous ne discutons pas ici de notre propre implémentation de IMessageMetadata
. Si cela vous intéresse, vous pouvez consulter l’exemple de 05.user_metadata.cpp
.
Nous avons donc une instance de la description des métadonnées des paramètres d’entrée. Mais pour travailler avec le message, nous avons aussi besoin d’un tampon. La taille de la mémoire tampon est l’une des principales caractéristiques des messages de métadonnées et est renvoyée par la méthode getMessageLength()
de IMessageMetadata
:
char* buffer = new char[meta->getMessageLength(&status)];
Afin de traiter les valeurs individuelles à l’intérieur du tampon, le décalage par rapport à celles-ci doit être pris en compte. IMessageMetadata renseigne les décalages pour toutes les valeurs du message, en l’utilisant, nous pouvons créer des pointeurs vers celles-ci :
double* percent_inc = (double*) &buffer[meta->getOffset(&status, 0)];
char* dept_no = &buffer[meta->getOffset(&status, 1)];
N’oubliez pas non plus de traiter les flags NULL :
short* flag = (short*)&buffer[meta->getNullOffset(&status, 0)];
*flag = 0;
flag = (short*) &buffer[meta->getNullOffset(&status, 1)];
*flag = 0;
Une fois les manipulations de décalage terminées, nous sommes prêts à obtenir les valeurs des paramètres :
getInputValues(dept_no, percent_inc);
et exécutez l’instruction préparée :
stmt->execute(&status, tra, meta, buffer, NULL, NULL);
Les deux derniers paramètres NULL
sont pour les messages de sortie et sont généralement utilisés pour l’instruction EXECUTE PROCEDURE
.
Si vous n’avez pas besoin de récupérer les métadonnées de l’instruction et que vous prévoyez de ne l’exécuter qu’une seule fois, vous pouvez choisir une méthode plus simple — utilisez la méthode execute()
de l’interface IAttachment
:
att->execute(&status, tra, 0,
"UPDATE department SET budget = ? * budget + budget WHERE dept_no = ?",
SQL_DIALECT_V6, meta, buffer, NULL, NULL);
Dans ce cas, vous n’avez pas du tout besoin d’utiliser IStatement
.
Un exemple d’exécution de l’instruction UPDATE
avec des paramètres est présent dans 02.update.cpp
ou l’exemple en Pascal 02.update.pas
, vous verrez également comment une exception levée dans un déclencheur / procédure peut être interceptée dans un programme C++ ou Pascal.