Exécution d’instructions

Les instructions peuvent être exécutées en utilisant la méthode connection.execute(). La méthode execute() accepte un objet options qui peut être utilisé pour spécifier le texte SQL et un rappel complete. Le rappel complete est invoqué lorsqu’une instruction est terminée et que le résultat est prêt à être exploité :

var statement = connection.execute({
  sqlText: 'CREATE DATABASE testdb',
  complete: function(err, stmt, rows) {
    if (err) {
      console.error('Failed to execute statement due to the following error: ' + err.message);
    } else {
      console.log('Successfully executed statement: ' + stmt.getSqlText());
    }
  }
});
Copy

Note

La taille maximale des données utiles d’une seule demande est de 16 MB.

Paramètres d’instruction de liaison

Il peut arriver que vous souhaitiez lier des données dans une instruction avec un caractère de remplacement. Exécuter des instructions de cette manière est utile car cela aide à prévenir les attaques par injection de commandes SQL. Considérez l’énoncé suivant :

connection.execute({
  sqlText: 'SELECT c1 FROM (SELECT 1 AS c1 UNION ALL SELECT 2 AS c1) WHERE c1 = 1;'
});
Copy

Vous pouvez obtenir le même résultat en utilisant les liaisons suivantes :

connection.execute({
  sqlText: 'SELECT c1 FROM (SELECT :1 AS c1 UNION ALL SELECT :2 AS c1) WHERE c1 = :1;',
  binds: [1, 2]
});
Copy

La syntaxe ? pour les liaisons est également prise en charge :

connection.execute({
p
  sqlText: 'SELECT c1 FROM (SELECT ? AS c1 UNION ALL SELECT ? AS c1) WHERE c1 = ?;',
  binds: [1, 2, 1]
});
Copy

Note

Il existe une limite supérieure à la taille des données que vous pouvez lier ou que vous pouvez combiner dans un lot. Pour plus de détails, voir Limites de la taille du texte de requête.

Exécution d’un lot d’instructions SQL (prise en charge des multi-instructions)

Dans les versions 1.6.18 et ultérieures du connecteur Node.js, vous pouvez envoyer un lot d’instructions SQL séparées par des points-virgules à exécuter en une seule requête.

Note

Par défaut, Snowflake renvoie une erreur pour les requêtes émises avec plusieurs instructions en vue d’apporter une protection contre les attaques par injection SQL. La fonctionnalité d’instructions multiples rend votre système plus vulnérable aux injections SQL et doit donc être utilisée avec précaution. Vous pouvez réduire le risque en utilisant le paramètre MULTI_STATEMENT_COUNT pour spécifier le nombre d’instructions à exécuter, ce qui rend plus difficile l’injection d’une instruction en l’ajoutant.

Vous pouvez exécuter plusieurs instructions en tant que lot de la même manière que vous exécutez des requêtes avec des instructions uniques, sauf que la chaîne de requête contient plusieurs instructions séparées par des points-virgules. Notez que les instructions multiples s’exécutent de manière séquentielle, et non en parallèle. Le paramètre MULTI_STATEMENT_COUNT indique le nombre exact d’instructions que le lot contient.

Par exemple, si vous définissez MULTI_STATEMENT_COUNT=3, une instruction par lot doit comprendre exactement trois instructions. Si vous soumettez une instruction par lot avec un autre nombre d’instructions, le pilote Node.js rejette la demande. Vous pouvez définir MULTI_STATEMENT_COUNT=0 pour permettre aux requêtes par lots de contenir n’importe quel nombre d’instructions. Cependant, il faut savoir que l’utilisation de cette valeur réduit la protection contre les attaques par injection de SQL.

Vous pouvez définir ce paramètre au niveau de la session à l’aide de la commande suivante, ou vous pouvez définir la valeur séparément à chaque fois que vous soumettez une requête.

ALTER SESSION SET multi_statement_count = <n>
Copy

En définissant la valeur au niveau de la session, vous n’avez pas besoin de la définir à chaque fois que vous exécutez une instruction par lot. L’exemple suivant définit le nombre d’instructions au niveau de la session sur trois, puis exécute trois instructions SQL :

var statement = connection.execute({
    sqlText: "ALTER SESSION SET multi_statement_count=0",
    complete: function (err, stmt, rows) {
      if (err) {
        console.error('1 Failed to execute statement due to the following error: ' + err.message);
      } else {
        testMulti();
      }
    }
  });
function testMulti() {
  console.log('select bind execute.');
  var selectStatement = connection.execute({
    sqlText: "create or replace table test(n int); insert into test values(1), (2); select * from test order by n",
    complete: function (err, stmt, rows) {
      if (err) {
        console.error('1 Failed to execute statement due to the following error: ' + err.message);
      }
      else {
        console.log('==== complete');
        console.log('==== sqlText=' + stmt.getSqlText());
        if(stmt.hasNext())
        {
          stmt.NextResult();
        }
        else {
          // do something else, e.g. close the connection
        }
      }
    }
  });
}
Copy

Vous pouvez également définir le nombre d’instructions dans un lot chaque fois que vous exécutez une requête à plusieurs instructions en définissant MULTI_STATEMENT_COUNT comme paramètre de la fonction connection.execute. L’exemple suivant fixe le nombre d’instructions à trois pour le lot et inclut trois instructions SQL dans la requête de lot :

var selectStatement = connection.execute({
    sqlText: "CREATE OR REPLACE TABLE test(n int); INSERT INTO test values(1), (2); SELECT * FROM test ORDER BY n",
    parameters: { MULTI_STATEMENT_COUNT: 3 },
    complete: function (err, stmt, rows) {
      if (err) {
        console.error('1 Failed to execute statement due to the following error: ' + err.message);
      }
      else {
        console.log('==== complete');
        console.log('==== sqlText=' + stmt.getSqlText());
        if(stmt.hasNext())
        {
          stmt.NextResult();
        }
        else {
          // do something else, e.g. close the connection
        }
      }
    }
  });
Copy

Liaison d’un tableau pour les insertions en masse

La liaison d’un tableau de données est prise en charge pour le fonctionnement en masse INSERT. Transmettez un tableau de tableaux comme suit :

connection.execute({
  sqlText: 'INSERT INTO t(c1, c2, c3) values(?, ?, ?)',
  binds: [[1, 'string1', 2.0], [2, 'string2', 4.0], [3, 'string3', 6.0]]
});
Copy

Note

Le fait de lier un grand tableau aura une conséquence sur les performances et pourrait être refusé si la taille des données est trop grande pour être gérée par le serveur.

Annulation d’instructions

Une instruction peut être annulée en utilisant la méthode statement.cancel() :

statement.cancel(function(err, stmt) {
  if (err) {
    console.error('Unable to abort statement due to the following error: ' + err.message);
  } else {
    console.log('Successfully aborted statement');
  }
});
Copy

Nouvelle soumission de requêtes

Si vous n’avez pas la certitude que Snowflake a exécuté avec succès une instruction SQL, peut-être en raison d’une erreur de réseau ou d’un dépassement de délai, vous pouvez soumettre à nouveau la même instruction en utilisant son ID de requête. Par exemple, supposons que vous soumettiez une commande INSERT pour ajouter des données, mais que vous n’ayez pas reçu d’accusé de réception en temps voulu, de sorte que vous ne savez pas comme s’est déroulée la commande. Dans ce scénario, vous ne voulez pas simplement exécuter la même commande en tant que nouvelle commande, car cela pourrait entraîner une double exécution de la commande, produisant ainsi une duplication des données.

En incluant l’ID de requête dans l’instruction SQL, vous pouvez éviter le risque de duplication des données. La nouvelle soumission de la requête avec l’ID de requête d’origine garantit que la commande resoumise n’est exécutée que si la requête d’origine a échoué. Pour plus d’informations, reportez-vous à Nouvelle soumission d’une requête d’exécution d’instructions SQL.

Note

Pour soumettre à nouveau une requête à l’aide d’un ID de requête , vous devez utiliser la même connexion que celle qui a généré l’ID de requête. Si vous souhaitez récupérer le résultat d’une requête à partir d’une autre connexion, reportez-vous à RESULT_SCAN.

Les exemples de code suivants montrent comment vous pouvez enregistrer et utiliser l’ID de requête pour soumettre à nouveau une instruction. Lorsque vous exécutez une instruction, vous pouvez utiliser la fonction getRequestId() pour récupérer les ID de la requête soumise. Vous pouvez ensuite utiliser cet ID pour exécuter la même instruction à un moment ultérieur. L’exemple suivant exécute une instruction INSERT et enregistre son ID de requête dans la variable requestId.

var requestId;
connection.execute({
  sqlText: 'INSERT INTO testTable VALUES (1);',
    complete: function (err, stmt, rows)
    {
      var stream = stmt.streamRows();
      requestId = stmt.getRequestId();   // Retrieves the request ID
      stream.on('data', function (row)
      {
        console.log(row);
      });
      stream.on('end', function (row)
      {
        console.log('done');
      });
    }
});
Copy

Si vous ne recevez pas d’accusé de réception indiquant que la commande a été exécutée avec succès, vous pouvez soumettre à nouveau la requête en utilisant l’ID de requête enregistré comme indiqué ci-dessous.

connection.execute({
  sqlText: 'INSERT INTO testTable VALUES (1);',  // optional
    requestId: requestId,  // Uses the request ID from before
    complete: function (err, stmt, rows)
    {
      var stream = stmt.streamRows();
      stream.on('data', function (row)
      {
        console.log(row);
      });
      stream.on('end', function (row)
      {
        console.log('done');
      });
  }
});
Copy

Si vous choisissez de soumettre à nouveau une requête avec un requestId et un sqlText, tenez compte des interactions suivantes :

  • Si le requestId existe déjà, c’est-à-dire qu’il correspond à une requête précédente, la commande ignore la requête sqlText et soumet à nouveau la requête de la commande d’origine.

  • Si la requête requestId n’existe pas, c’est-à-dire qu’elle ne correspond pas à une requête précédente, la commande exécute la requête sqlText.