Execução de instruções

As instruções podem ser executadas por meio do método connection.execute(). O método execute() aceita um objeto options que pode ser usado para especificar o texto SQL e uma chamada de retorno complete. A complete chamada de retorno é invocada quando uma instrução termina de ser executada e o resultado está pronto para ser consumido:

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

Nota

O tamanho máximo de carga útil de uma única solicitação é 16 MB.

Vinculação de parâmetros de instrução

Ocasionalmente, você pode querer vincular os dados em uma instrução com um espaço reservado. Executar instruções desta maneira é útil porque ajuda a impedir ataques de injeção SQL. Considere a seguinte instrução:

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

Você pode alcançar o mesmo resultado usando as seguintes vinculações:

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

A sintaxe ? para vinculações também tem suporte:

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

Nota

Há um limite máximo para o tamanho dos dados que você pode vincular ou que pode combinar em um lote. Para obter mais detalhes, consulte Limites no tamanho do texto de consulta.

Execução de um lote de instruções SQL (suporte para múltiplas instruções)

Na versão 1.6.18 e superior do conector Node.js, você pode enviar um lote de instruções SQL separadas por ponto e vírgula a serem executadas em uma única solicitação.

Nota

Por padrão, o Snowflake retorna um erro para consultas emitidas com múltiplas instruções para se proteger contra ataques de injeção de SQL. O recurso de múltiplas instruções torna seu sistema mais vulnerável a injeções de SQL, e por isso deve ser usado com cuidado. Você pode reduzir o risco usando o parâmetro MULTI_STATEMENT_COUNT para especificar o número de instruções a serem executadas, o que torna mais difícil injetar uma instrução anexando-a.

Você pode executar múltiplas instruções como um lote da mesma forma que executa consultas com instruções únicas, exceto que a cadeia de caracteres de consulta contém múltiplas instruções separadas por ponto e vírgula. Observe que múltiplas instruões são executadas sequencialmente, não em paralelo. O parâmetro MULTI_STATEMENT_COUNT especifica o número exato de instruções que o lote contém.

Por exemplo, se você definir MULTI_STATEMENT_COUNT=3, uma instrução de lote deve incluir precisamente três instruções. Se você enviar uma instruções de lote com qualquer outro número de instruções, o driver do Node.js rejeita a solicitação. Você pode definir MULTI_STATEMENT_COUNT=0 para permitir que as consultas de lote contenham qualquer número de instruções. Entretanto, esteja ciente de que o uso deste valor reduz a proteção contra ataques de injeção de SQL.

Você pode definir este parâmetro no nível de sessão usando o seguinte comando, ou você pode definir o valor separadamente cada vez que enviar uma consulta.

ALTER SESSION SET multi_statement_count = <n>
Copy

Ao definir o valor do nível de sessão, você não precisa defini-lo ao executá-lo cada vez que executa uma instrução de lote. O exemplo a seguir define o número de instruções no nível da sessão como três e depois executa três instruções 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

Você também pode definir o número de instruções em um lote cada vez que executar uma consulta de múltiplas instruções definindo MULTI_STATEMENT_COUNT como um parâmetro para a função connection.execute. O exemplo a seguir define o número de instruções como três para o lote e inclui três instruções SQL na consulta do lote:

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

Vinculação de uma matriz para inserções em massa

A vinculação de uma matriz de dados tem suporte para uma operação INSERT em lote. Passe uma matriz de matrizes da seguinte forma:

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

Nota

A vinculação de uma matriz grande terá impacto no desempenho e poderá ser rejeitada se o tamanho dos dados for muito grande para ser tratado pelo servidor.

Cancelamento de instruções

Uma instrução pode ser cancelada chamando o método 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

Reenvio de solicitações

Se você não tiver certeza se o Snowflake executou com sucesso uma instrução SQL, talvez devido a um erro ou tempo limite da rede, você pode reenviar a mesma instrução usando a ID de solicitação. Por exemplo, suponha que você envia um comando INSERT para adicionar dados, mas não recebe uma confirmação em tempo hábil, de modo que você não sabe o que aconteceu com o comando. Nesse cenário, você não quer apenas executar o mesmo comando como um novo comando, pois poderia resultar na execução do comando duas vezes, produzindo duplicação de dados.

Ao incluir a ID de solicitação na instrução SQL, você pode evitar o potencial de duplicação de dados. O reenvio da solicitação com a ID da solicitação inicial garante que o comando reenviado só seja executado se a solicitação inicial tiver falhado. Para obter mais informações, consulte Como reenviar uma solicitação para executar instruções SQL.

Nota

Para reenviar uma consulta usando um ID da solicitação, você deverá usar a mesma conexão que gerou o ID da solicitação. Se você quiser recuperar o resultado da consulta de uma conexão diferente, consulte RESULT_SCAN.

As amostras de código a seguir demonstram como você pode salvar e usar o ID da solicitação para reenviar uma instrução. Quando você executa uma instrução, pode usar a função getRequestId() para recuperar a ID da solicitação enviada. Você pode então usar essa ID para executar a mesma instrução em um momento posterior. O exemplo a seguir executa uma instrução INSERT e salva sua ID de solicitação na variável 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

Se não receber uma confirmação de que o comando foi executado com sucesso, você pode reenviar a solicitação usando a ID de solicitação salva como mostrado abaixo.

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

Se você escolher reenviar uma solicitação com um requestId e sqlText, esteja ciente das seguintes interações:

  • Se requestId já existir, ou seja, corresponde a uma solicitação anterior, o comando ignora a consulta sqlText e reenvia a consulta a partir do comando original.

  • Se requestId não existir, significando que não corresponde a uma solicitação anterior, o comando executa a consulta sqlText.