FirebirdSQL logo
 Firebird InterfacesÉcriture de plugins 

Exécution d’une instruction SQL sans paramètres d’entrée et avec des lignes renvoyées

Une fois la transaction lancée, nous sommes prêts à exécuter nos premières instructions SQL.La méthode execute() utilisée à cet effet dans IAttachment est assez générique, et peut également être utilisée pour exécuter des instructions SQL avec des paramètres d’entrée et de sortie (ce qui est typique de EXECUTE PROCEDURE), mais pour l’instant nous allons utiliser sa forme la plus simple. Les instructions DDL et DML peuvent être exécutées :

att->execute(&status, tra, 0, "create table dates_table (d1 date)",
    SQL_DIALECT_V6, NULL, NULL, NULL, NULL);
tra->commitRetaining(&status);
att->execute(&status, tra, 0, "insert into dates_table values (CURRENT_DATE)",
    SQL_DIALECT_V6, NULL, NULL, NULL, NULL);

Comme vous pouvez le voir, l’interface de transaction est un paramètre obligatoire pour la méthode execute() (ne doit être NULL que si vous exécutez l’instruction SET TRANSACTION). Le paramètre suivant est la longueur de l’instruction SQL (qui peut être nulle, auquel cas les règles C sont utilisées pour déterminer la longueur de la chaîne), puis le texte de l’instruction et le dialecte SQL qui doit être utilisé pour elle. Ceci est suivi de quelques NULLs qui sont substitués pour décrire les métadonnées, et les tampons des paramètres d’entrée et de sortie. Pour une description complète de cette méthode, consultez IAttachment.

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.