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()); } } });
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;' });
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] });
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] });
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>
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 } } } }); }
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 } } } });
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]] });
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'); } });
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'); }); } });
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'); }); } });
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 consultasqlText
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 consultasqlText
.