Apache Adobe Flex TutorialTutoriaux Adobe Flex & AIR en Français

28jan/115

AIR SQLite – Utilisation de requête paramétrée (SQLStatement parameters)

Dans le dernier tutorial flex, on a vu comme envoyer des requêtes SQL en utilisant SQLStatement. On va maintenant voir une technique que vous allez sûrement voir à de nombreuses reprises dans les exemples disponibles sur le net, les requêtes SQL paramétrées.

Les requêtes SQL paramétrées ne sont pas une spécificité AIR SQLite, elles existent dans la plupart des langages permettant d'accéder à une base de données. Ces requêtes paramétrées apportent de nombreux avantages que l'on va voir dans cet article, mais avant cela, une petite explication.

Utilisation de paramètres dans un SQLStatement

Il n'est pas rare dans une application d'utiliser une seule requête SQL à de multiple reprises dans une application, avec simplement de petites variations. Par exemple une application qui répertorie des films dans une base de données SQLite. A chaque ajout dans la BDD, une requête SQL INSERT va ajouter la donnée à la base. Cependant, chaque requête est exécutée avec certaines variations: le contenu des colonnes (titre, description, photo, …).

Si vous êtes dans ce cas, dans lequel vous avez des SQLStatement utilisés à de multiples reprises avec des valeurs différentes pour la requête, la meilleure approche est d'utiliser des paramètres pour votre requêtes SQL plutôt que des valeurs texte dans votre "texte" SQL. C'est un peu comme créer une fonction dans votre code ActionScript prenant plusieurs arguments afin de factoriser votre code.

Pour utiliser des paramètres, il va falloir modifier votre requête SQL pour respecter une certaine syntaxe afin d'indiquer à quels emplacements vont venir se mettre les paramètres. Ensuite, vous devrez définir une valeur pour chaque paramètre en utilisant la propriété "parameters" de SQLStatement.

La propriété "parameters" de SQLStatement est un tableau associatif, vous pouvez donc y insérer une valeur correspondant à une clé. Votre clé est en fait l'emplacement que vous avez créé dans votre requête SQL. Voici la syntaxe:

statement.parameters[parameter_identifier] = value;

Les paramètres peuvent se présenter sous deux formes: nommés un non-nommés.

Utilisation de paramètres nommés (named parameters)

Un paramètres nommé a un nom spécifique que la base de données utilise pour faire la correspondance entre l'emplacement et la valeur du paramètre. Un nom de paramètre est constitué du caractère ":" ou "@" suivi du nom du paramètre comme:

:itemName
@firstName

Utilisation de paramètres non-nommés (unnamed parameters)

La deuxième approche utilise des paramètres non-nommés. Pour cela, vous allez spécifier l'emplacement d'un paramètre avec le caractère "?". Chaque paramètre sera cette fois repéré par un index numérique (0, 1, 2, …). Notez bien que comme les tableaux en ActionScript, le premier paramètre est à l'index 0.

Pour spécifier les valeurs des paramètres, vous allez utiliser le tableau associatif "parameters" mais cette fois-ci, la clé sera l'index de position de l'emplacement dans la requête:

var sql:String =
    "INSERT INTO inventoryItems (name, productCode)" +
    "VALUES (?, ?)";
var addItemStmt:SQLStatement = new SQLStatement();
addItemStmt.sqlConnection = conn;
addItemStmt.text = sql;

// set parameter values
addItemStmt.parameters[0] = "Item name";
addItemStmt.parameters[1] = "12345";

addItemStmt.execute();

Pourquoi les SQLStatement parameters sont une bonne pratique

Les SQLStatement parameters sont souvent considérés comme "Best Practice" pour plusieurs raisons.

Performances

Un SQLStatement paramétré va s'exécuter plus rapidement que si vous assignez la propriété "text" à chaque fois. En fait, lorsque vous assignez la valeur "text", la requête va être compilée / préparée par la base de donnée. Si vous utilisez un SQLStatement paramétré, la propriété "text" ne sera assignée qu'une fois (à l'initialisation), donc la base n'aura pas à re-compiler la requête (traitement lourd pour certaines requêtes).

Typage de données explicite

L'utilisation de requête paramétrés vous permet de faire des substitutions de valeurs qui seront fortement typées. Cela évite au runtime de convertir les valeurs suivant le type de colonne en utilisant les "column affinity".

Pour plus d'informations sur ces types de valeur / colonnes, vous pouvez consulter cet article:

AIR SQLite – Création de tables SQLite et types de données

Meilleure sécurité contre les injections SQL

Même si les attaques par injections SQL sont habituellement ciblées sur des sites en technologies web "classiques", vous pouvez en être la cible de la même manière:

http://fr.wikipedia.org/wiki/Injection_SQL

L'utilisation des paramètres permet de se protéger contre ces attaques. Lors d'une attaque par injection SQL, l'utilisateur entre du code SQL dans une zone de saisie, par exemple le champ d'un formulaire. Si votre application remplit la propriété "text" en faisant une simple concaténation de texte SQL,  le code SQL entré par l'utilisateur peut-être exécuté par la base de donnée.

Voici un exemple à ne pas reproduire! :

// assume the variables "username" and "password"
// contain user-entered data
var sql:String =
    "SELECT userId " +
    "FROM users " +
    "WHERE username = '" + username + "' " +
    "    AND password = '" + password + "'";
var statement:SQLStatement = new SQLStatement();
statement.text = sql;

En utilisant des paramètres, ce type d'attaque ne peut se produire car les valeurs sont substituées au niveau de la base au lieu de faire partie de la requête. Voici l'alternative au code précédent en utilisant des paramètres SQL:

// assume the variables "username" and "password"
// contain user-entered data
var sql:String =
    "SELECT userId " +
    "FROM users " +
    "WHERE username = :username " +
    "    AND password = :password";
var statement:SQLStatement = new SQLStatement();
statement.text = sql;

// set parameter values
statement.parameters[":username"] = username;
statement.parameters[":password"] = password;

Articles similaires

Commentaires (5) Trackbacks (1)
  1. Cette fonctionnalité est effectivement une bénédiction.
    Et si quelqu'un a besoin d'un outil qui vous permette de "testez" des requêtes paramétrées, SQLite Sorcerer les gère dans son Query Panel (il y a une section Parameter) qui reconnait la syntaxe :param ou @param et vous permet ensuite de taper vos paramètres ;)
    http://afoucal.free.fr/index.php/applications/sqlite-sorcerer/

  2. Oui Sorcerer est très bien fait, je le préfère à Lita, mais c'est une question de goût…

    A noter que seules les requêtes paramétrées permettent d'insérer des objets en base (plutôt logique).
    Par contre dès que je caste l'objet, ou que j'utilise un vecteur, l'objet renvoyé est bien typé, mais ses paramètres sont "undefined"
    En utilisant un objet "anonyme", pas de souci ça marche parfaitement. Tant pis pour l'auto-complétion

  3. Salut Nicolas,
    tu fais bien un registerClassAlias() avant l'insertion et la récupération sur ton objet typé? Un tuto la dessus devrait suivre dans quelques jours

    Fabien

  4. Super, je ne connaissait pas !
    ça marche parfaitement.

    Si tu fais un tuto dessus prochainement, pourrais-tu expliquer les cas nécessitant getClassByAlias() (peut-être dans un swf chargé par celui ayant fait le register ?).

    Dans mon cas, j'ai fait un registerClassAlias() lors de l'init de ma connexion et c'est tout.

    Merci Fabien

  5. Salut Nicolas,
    Content de t'avoir débloqué :) . Il y aura un tuto la-dessus mais je n'ai rien inventé, tout est dans la doc. Dans un prochain tutorial, je vais parler de itemClass et de ces problèmes d'enregistrement. Sûrement dans la semaine qui arrive !

    Fabien


Leave a comment

(required)