SnowConvert AI - SQL Server-Azure Synapse - Procedimentos¶
Esta seção documenta a transformação da sintaxe e das instruções TSQL de procedimento para o snowflake javascript
Applies to
SQL Server
Azure Synapse Analytics
Nota
Algumas partes do código de saída foram omitidas por motivos de clareza.
1. CREATE PROCEDURE Translation¶
O Snowflake CREATE PROCEDURE é definido na sintaxe SQL, enquanto suas instruções internas são definidas em JavaScript.
Transact¶
-- Additional Params: -t JavaScript
CREATE PROCEDURE HumanResources.uspGetAllEmployees
@FirstName NVARCHAR(50),
@Age INT
AS
-- TSQL Statements and queries...
GO
Snowflake¶
CREATE OR REPLACE PROCEDURE HumanResources.uspGetAllEmployees (FIRSTNAME STRING, AGE INT)
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
// SnowConvert AI Helpers Code section is omitted.
$$;
Tipos de dados de parâmetros¶
Os tipos de dados de parâmetros estão sendo traduzidos para o equivalente do Snowflake. Consulte também Tipos de dados.
Auxiliar EXEC¶
Para que seja possível executar instruções de um procedimento no ambiente SnowFlake, essas instruções precisam ser pré-processadas e adaptadas para refletir sua execução em diversas variáveis específicas da linguagem de origem.
O SnowConvert AI traduz automaticamente as instruções compatíveis e faz uso de um auxiliar EXEC. Esse auxiliar fornece recursos de acesso e atualização para muitas variáveis que simulam como seria a execução dessas instruções em seu ambiente nativo.
Por exemplo, você pode ver que, nos procedimentos migrados, há um bloco de código que é sempre adicionado. Na próxima seção, explicaremos a estrutura básica desse código. Lembre-se de que estamos sempre avaliando e buscando maneiras novas e aprimoradas de agilizar as transformações e qualquer auxiliar que precisarmos.
Estrutura¶
A estrutura básica do auxiliar EXEC é a seguinte:
Seção de declaração de variáveis: Aqui, declaramos as diferentes variáveis ou objetos que conterão valores associados à execução das instruções dentro do procedimento. Isso inclui valores como o número de linhas afetadas por uma instrução ou até mesmo o próprio conjunto de resultados.
Declaração da função fixBind: Esta é uma função auxiliar usada para corrigir vinculações quando elas são do tipo Date.
Declaração da função EXEC: Esta é a principal função do auxiliar EXEC. Ela recebe a instrução a ser executada, a matriz de vinculações (basicamente as variáveis ou os parâmetros que podem ser modificados pela execução e que exigem a permanência dos dados durante toda a execução do procedimento), o sinalizador noCatch que determina se ERROR_HANDLERS deve ser usado e a função catchFunction para executar o código personalizado quando houver uma exceção na execução da instrução. O corpo da função EXEC é muito simples: executa a instrução e armazena todos os dados valiosos produzidos por sua execução, tudo dentro de um bloco de tratamento de erros.
ERROR VARS: O bloco de captura EXEC configura uma lista de variáveis de erro, como
MESSAGE_TEXT,SQLCODE,SQLSTATE,PROC_NAMEeERROR_LINE, que podem ser usadas para recuperar valores de funções definidas pelo usuário, a fim de emular o comportamento das funções integradas do SQL Server ERROR_LINE, ERROR_MESSAGE, ERROR_NUMBER, ERROR_PROCEDURE e ERROR_STATE . Depois que todas essas variáveis forem definidas com um valor, a função definida pelo usuárioUPDATE_ERROR_VARSserá responsável por atualizar algumas variáveis de ambiente com os valores de erro, para ter acesso a elas no escopo SQL.
Código¶
O bloco de código a seguir representa o auxiliar EXEC dentro de um procedimento:
var _RS, ROW_COUNT, _ROWS, MESSAGE_TEXT, SQLCODE = 0, SQLSTATE = '00000', ERROR_HANDLERS, NUM_ROWS_AFFECTED, INTO;
var fixBind = function (arg) {
arg = arg == undefined ? null : arg instanceof Date ? arg.toISOString() : arg;
return arg;
};
var fetch = (count,rows,stmt) => (count && rows.next() && Array.apply(null,Array(stmt.getColumnCount())).map((_,i) => rows.getColumnValue(i + 1))) || [];
var EXEC = (stmt,binds = [],noCatch = false) => {
binds = binds ? binds.map(fixBind) : binds;
for(var stmt of stmt.split(";").filter((_) => _)) {
try {
_RS = snowflake.createStatement({
sqlText : stmt,
binds : binds
});
_ROWS = _RS.execute();
ROW_COUNT = _RS.getRowCount();
NUM_ROWS_AFFECTED = _RS.getNumRowsAffected();
return {
THEN : (action) => !SQLCODE && action(fetch(_ROWS))
};
} catch(error) {
let rStack = new RegExp('At .*, line (\\d+) position (\\d+)');
let stackLine = error.stackTraceTxt.match(rStack) || [0,-1];
MESSAGE_TEXT = error.message.toString();
SQLCODE = error.code.toString();
SQLSTATE = error.state.toString();
snowflake.execute({sqlText: `SELECT UPDATE_ERROR_VARS_UDF(?,?,?,?,?)`,binds: [stackLine[1], SQLCODE, SQLSTATE, MESSAGE_TEXT, PROC_NAME]});
throw error;
}
}
};
Exemplo simples de EXEC
Este é um exemplo simples de uma chamada EXEC dentro de um procedimento armazenado
Código-fonte
-- Additional Params: -t JavaScript
CREATE PROCEDURE dbo.EXEC_EXAMPLE_1
AS
EXECUTE('SELECT 1 AS Message');
GO
-- =============================================
-- Example to execute the stored procedure
-- =============================================
EXECUTE dbo.EXEC_EXAMPLE_1
GO
Código esperado
CREATE OR REPLACE PROCEDURE dbo.EXEC_EXAMPLE_1 ()
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
// REGION SnowConvert AI Helpers Code
var _RS, ROW_COUNT, _ROWS, MESSAGE_TEXT, SQLCODE = 0, SQLSTATE = '00000', OBJECT_SCHEMA_NAME = 'dbo', ERROR_HANDLERS, NUM_ROWS_AFFECTED, PROC_NAME = arguments.callee.name, DOLLAR_DOLLAR = '$' + '$';
function* sqlsplit(sql) {
var part = '';
var ismark = () => sql[i] == '$' && sql[i + 1] == '$';
for(var i = 0;i < sql.length;i++) {
if (sql[i] == ';') {
yield part + sql[i];
part = '';
} else if (ismark()) {
part += sql[i++] + sql[i++];
while ( i < sql.length && !ismark() ) {
part += sql[i++];
}
part += sql[i] + sql[i++];
} else part += sql[i];
}
if (part.trim().length) yield part;
};
var formatDate = (arg) => (new Date(arg - (arg.getTimezoneOffset() * 60000))).toISOString().slice(0,-1);
var fixBind = function (arg) {
arg = arg == undefined ? null : arg instanceof Date ? formatDate(arg) : arg;
return arg;
};
var EXEC = (stmt,binds = [],severity = "16",noCatch = false) => {
binds = binds ? binds.map(fixBind) : binds;
for(var stmt of sqlsplit(stmt)) {
try {
_RS = snowflake.createStatement({
sqlText : stmt,
binds : binds
});
_ROWS = _RS.execute();
ROW_COUNT = _RS.getRowCount();
NUM_ROWS_AFFECTED = _RS.getNumRowsAffected();
return {
THEN : (action) => !SQLCODE && action(fetch(_ROWS))
};
} catch(error) {
let rStack = new RegExp('At .*, line (\\d+) position (\\d+)');
let stackLine = error.stackTraceTxt.match(rStack) || [0,-1];
MESSAGE_TEXT = error.message.toString();
SQLCODE = error.code.toString();
SQLSTATE = error.state.toString();
snowflake.execute({
sqlText : `SELECT UPDATE_ERROR_VARS_UDF(?,?,?,?,?,?)`,
binds : [stackLine[1],SQLCODE,SQLSTATE,MESSAGE_TEXT,PROC_NAME,severity]
});
throw error;
}
}
};
// END REGION
EXEC(`SELECT 1 AS Message;`);
$$;
EXEC em um procedimento armazenado com um parâmetro
Neste exemplo, o comando EXEC está dentro de um procedimento armazenado e recebe um valor de parâmetro
Código-fonte
-- Additional Params: -t JavaScript
CREATE PROCEDURE dbo.EXEC_EXAMPLE_2
@p1 varchar(50) = N''
AS
EXEC ('SELECT ' + @p1);
GO
-- =============================================
-- Example to execute the stored procedure
-- =============================================
EXECUTE dbo.EXEC_EXAMPLE_2 N'''Hello World!'''
GO
Código esperado
CREATE OR REPLACE PROCEDURE dbo.EXEC_EXAMPLE_2 (P1 STRING DEFAULT '')
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
// SnowConvert AI Helpers Code section is omitted.
EXEC(`SELECT
${P1};`);
$$;
EXEC invocando um procedimento armazenado com um parâmetro
Neste exemplo, o EXEC invoca outro procedimento armazenado e adiciona um parâmetro
Código-fonte
-- Additional Params: -t JavaScript
CREATE PROCEDURE dbo.EXEC_EXAMPLE_3
@p1 varchar(50) = N''
AS
EXEC EXEC_EXAMPLE_2 @p1
GO
-- =============================================
-- Example to execute the stored procedure
-- =============================================
EXECUTE dbo.EXEC_EXAMPLE_3 N'''Hello World!'''
GO
Código esperado
CREATE OR REPLACE PROCEDURE dbo.EXEC_EXAMPLE_3 (P1 STRING DEFAULT '')
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
// SnowConvert AI Helpers Code section is omitted.
EXEC(`CALL EXEC_EXAMPLE_2(?)`,[P1]);
$$;
Parâmetros com valor padrão.¶
No SqlServer, pode haver parâmetros com um valor padrão, caso não sejam especificados quando um procedimento estiver sendo chamado.
SQL Server¶
CREATE PROCEDURE PROC_WITH_DEFAULT_PARAMS1
@PARAM1 INT = 0, @PARAM2 INT = 0, @PARAM3 INT = 0, @PARAM4 INT = 0
AS
BEGIN
.
.
.
END
Snowflake¶
CREATE OR REPLACE PROCEDURE PROC_WITH_DEFAULT_PARAMS1(param1 int default 0, param2 int default 0, param3 int default 0, param4 int default 0)
RETURNS TABLE()
LANGUAGE SQL
EXECUTE AS CALLER
AS
$$
.
.
.
$$;
CALL PROC_WITH_DEFAULT_PARAMS1(param2 => 10, param4 => 15);
auxiliar CURSOR¶
CREATE OR REPLACE PROCEDURE PROC1()
RETURNS STRING
LANGUAGE JAVASCRIPT
EXECUTE AS CALLER
AS
$$
var CURSOR = function (stmt, binds) {
var statementObj, result_set, total_rows, isOpen = false, self = this, row_count;
this.CURRENT = new Object;
var fetch = (count,rows,stmt) => (count && rows.next() && Array.apply(null,Array(stmt.getColumnCount())).map((_,i) => rows.getColumnValue(i + 1))) || [];
var fixBind = function (arg) {
arg = arg == undefined ? null : arg instanceof Date ? formatDate(arg) : arg;
return arg;
};
this.OPEN = function(openParameters) {
if (result_set == undefined) {
try {
if (openParameters) binds = openParameters;
if (binds instanceof Function) binds = binds();
var finalBinds = binds && binds.map(fixBind);
var finalStmt = stmt instanceof Function ? stmt() : stmt;
statementObj = snowflake.createStatement({
sqlText : finalStmt,
binds : finalBinds
});
result_set = statementObj.execute();
total_rows = statementObj.getRowCount();
isOpen = true;
row_count = 0;
} catch(error) {
RAISE(error.code,"error",error.message);
}
else {
isOpen = true;
}
}
return this;
};
this.CURSOR_ROWS = function () {
return total_rows;
};
this.FETCH_STATUS = function() {
if(total_rows > row_count)
return 0;
else
return -1;
};
this.FETCH_NEXT = function() {
self.res = [];
if (isOpen) {
self.res = fetch(total_rows,result_set,statementObj);
if (self.res)
row_count++;
}
return self.res && self.res.length > 0;
};
this.INTO = function () {
return self.res;
};
this.CLOSE = function () {
isOpen = false;
};
this.DEALLOCATE = function() {
this.CURRENT = row_count = result_set_table = total_rows = result_set = statementObj = self = undefined;
};
};
var COL1, COL2;
var sql_stmt = ``;
let c = new CURSOR(`SELECT COL1, COL2 FROM TABLE1;`,() => []);
c.OPEN();
c.FETCH_NEXT();
[COL1, COL2] = c.INTO();
while ( c.FETCH_STATUS()) {
sql_stmt = `INSERT INTO TABLE2 (COL1, COL2) VALUES (` + COL1+ `, ` + COL2 + `)`;
snowflake.createStatement({
sqlText : sql_stmt
}).execute();
}
c.CLOSE();
c.DEALLOCATE();
return 'sucess';
$$;
Auxiliar Insert Into EXEC¶
O auxiliar Insert into Exec gera uma função chamada Insert insertIntoTemporaryTable(sql). Essa função permitirá que a transformação de INSERT INTO TABLE_NAME EXEC(...) de TSQL para Snowflake imite o comportamento da instrução original, inserindo seus dados em uma tabela temporária e, em seguida, adicionando-os novamente ao Insert original.
Para obter mais informações sobre como o código para essa instrução é modificado, consulte a seção para o Insert Into Exec
Nota
Esse código gerado para INSERT INTO EXEC pode apresentar problemas de desempenho ao lidar com instruções EXECUTE que contêm várias consultas.
function insertIntoTemporaryTable(sql) {
var table = "SnowConvertPivotTemporaryTable";
return EXEC('CREATE OR REPLACE TEMPORARY TABLE ${table} AS ${sql}');
}
insertIntoTemporaryTable(`${DBTABLES}`)
EXEC(`INSERT INTO MYDB.PUBLIC.T_Table SELECT * FROM MYDB.PUBLIC.SnowConvertPivotTemporaryTable`);
EXEC(`DROP TABLE SnowConvertPivotTemporaryTable`)
Auxiliar LIKE¶
Caso uma expressão semelhante seja encontrada em um procedimento, por exemplo
CREATE PROCEDURE ProcedureLike @VariableValue VARCHAR(50) AS
BEGIN
IF @VariableValue like '%c%'
BEGIN
Select AValue from ATable;
END;
END;
Como o interior do procedimento é transformado em javascript, a expressão like gerará um erro. Para manter a funcionalidade, uma função é adicionada no início do procedimento se uma expressão semelhante for encontrada.
function LIKE(expr,pattern,esc,cs) {
function fixPattern(pattern,esc) {
const specials = '/.*+?|(){}[]\\'.split('');
var newPattern = "";
var fix = (c) => specials.includes(c) ? '\\' + c : c;
for(var i = 0;i < pattern.length;i++) {
var c = pattern[i];
if (c === esc) {
newPattern += pattern[i + 1]
i++
} else if (c === '%') {
newPattern += ".*?"
} else if (c === '_') {
newPattern += "."
} else if (c === '[' || ']') {
newPattern += c
} else newPattern += fix(c)
}
return newPattern;
}
return new RegExp(`^${fixPattern(pattern,esc)}$`,cs ? '' : 'i').exec(expr) != null;
}
Com essa função, podemos replicar a funcionalidade da expressão like do sql. Vejamos os diferentes casos em que ele pode ser usado
-- Additional Params: -t JavaScript
CREATE PROCEDURE ProcedureLike @VariableValue VARCHAR(50) AS
BEGIN
IF @VariableValue like '%c%'
BEGIN
Select AValue from ATable;
END;
IF @VariableValue not like '%c%'
BEGIN
Select BValue from BTable;
END;
IF @VariableValue like '%c!%%' escape '!'
BEGIN
Select CValue from CTable;
END;
END;
No último código, há um like normal, um not like e um like com escape. A transformação será
CREATE OR REPLACE PROCEDURE ProcedureLike (VARIABLEVALUE STRING)
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
// SnowConvert AI Helpers Code section is omitted.
if (LIKE(VARIABLEVALUE,`%c%`)) {
{
EXEC(` Select
AValue
from
ATable`);
}
}
if (!LIKE(VARIABLEVALUE,`%c%`)) {
{
EXEC(` Select
BValue
from
BTable`);
}
}
if (LIKE(VARIABLEVALUE,`%c!%%`,`!`)) {
{
EXEC(` Select
CValue
from
CTable`);
}
}
$$;
Observe que likes são transformados em chamadas de função
LIKE(VARIABLEVALUE,`%c%`)
!LIKE(VARIABLEVALUE,`%c%`)
LIKE(VARIABLEVALUE,`%c!%%`,`!`)
Os parâmetros que a função LIKE recebe são os seguintes:
A expressão que está sendo avaliada.
O padrão de comparação
Se estiver presente, o caractere de escape, que é um parâmetro opcional.
Auxiliar Select¶
Gera uma função chamada SELECT quando um valor escalar precisa ser definido em uma variável
-- Additional Params: -t JavaScript
CREATE PROCEDURE MAX_EMPLOYEE_ID
AS
BEGIN
DECLARE @VARIABLE INT
SET @VARIABLE = (SELECT MAX(EMPLOYEE_ID) FROM EMPLOYEES);
RETURN @VARIABLE
END;
Nesse caso, ele gerará o seguinte código com o auxiliar SELECT
CREATE OR REPLACE PROCEDURE MAX_EMPLOYEE_ID ()
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
// SnowConvert AI Helpers Code section is omitted.
let VARIABLE;
VARIABLE = EXEC(`SELECT
MAX(EMPLOYEE_ID) FROM
EMPLOYEES`);
return VARIABLE;
$$;
O auxiliar SELECT também pode ser usado para inserir em um valor local um valor recuperado de uma consulta. O auxiliar foi projetado especificamente para suportar o mesmo comportamento do SQL Server SELECT @local_variable. O parâmetro args representa cada operação aplicada a todas as variáveis locais dentro do select. Consulte também SELECT @Variable. Por exemplo:
-- Additional Params: -t JavaScript
CREATE PROCEDURE [PROCEDURE1] AS
DECLARE @VAR1 int;
DECLARE @VAR2 int;
select @VAR1 = col1 + col2, @VAR2 += col1 from table1;
GO
Nesse caso, as atribuições de variáveis serão convertidas para lambdas JavaScript a fim de emular o comportamento do SQL Server.
CREATE OR REPLACE PROCEDURE PROCEDURE1 ()
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
// SnowConvert AI Helpers Code section is omitted.
let VAR1;
let VAR2;
SELECT(` col1 + col2,
col1
from
table1`,[],(value) => VAR1 = value,(value) => VAR2 += value);
$$;
Auxiliar RAISERROR¶
Esse auxiliar é gerado quando há usos de uma chamada RAISERROR no código-fonte. Exemplo:
var RAISERROR = (message,severity,state) => {
snowflake.execute({
sqlText : `SELECT UPDATE_ERROR_VARS_UDF(?,?,?)`,
binds : [message,severity,state]
});
var msg = `Message: ${message}, Level: ${severity}, State: ${state}`;
throw msg;
};
O RAISERROR executa o UPDATE_ERROR_VARS_UDF para armazenar o valor da mensagem de erro, a gravidade e o estado como variáveis de ambiente, caso precisem ser usados ao chamar qualquer uma das funções integradas de ERROR. Por fim, a mensagem de erro é lançada com o mesmo formato do SQL Server.
Auxiliar de função Identity¶
Esse auxiliar é gerado sempre que a função Identity é usada em um Select Into dentro de um procedimento.
var IdentityHelper = (seed,increment) => {
var sequenceString = "`CREATE OR REPLACE SEQUENCE SnowConvert_Temp_Seq START = ${seed} INCREMENT = ${increment}`";
return EXEC(sequenceString);
Os parâmetros desse auxiliar são os mesmos da função original. Ele foi criado para gerar uma sequência que imite o comportamento da função Identity no TSQL. As alterações no código original são as seguintes:
Uma chamada de método adicional para a função IdentityHelper usando os mesmos parâmetros encontrados no código-fonte.
E uma chamada para IDENTITY_UDF um design de função para obter o próximo valor na sequência.
IdentityHelper(1,1)
EXEC(`CREATE TABLE PUBLIC.department_table3 AS SELECT IDENTITY_UDF() /*** MSC-WARNING - MSCEWI1046 - 'identity' FUNCTION MAPPED TO 'IDENTITY_UDF', FUNCTIONAL EQUIVALENCE VERIFICATION PENDING ***/ as Primary_Rank
from PUBLIC.department_table`);
Assim como no TSQL, se nenhum parâmetro for fornecido, (1,1) serão os valores padrão.
Auxiliar de procedimento CALL¶
Esse auxiliar é gerado sempre que há uma chamada para o que antes era uma função definida pelo usuário, mas que agora é um procedimento como resultado do processo de conversão.
var CALL = (sql,binds = [],...args) => {
EXEC("CALL " + sql,binds);
_ROWS.next();
return (_ROWS.getColumnValue(1))[0];
};
O objetivo desse auxiliar é encapsular a lógica necessária para chamar procedimentos como se fossem funções.
Lembre-se de que essa funcionalidade é limitada, pois os procedimentos não podem ser invocados em consultas como SELECT.
Exemplo de uso, supondo que FooSelfAssign(@PAR INT) tenha sido convertido para um procedimento:
// Input code
DECLARE @VAR1 INT = FooSelfAssign(1);
DECLARE @VAR4 INT = FooSelfAssign(FooSelfAssign(FooSelfAssign(FooSelfAssign(4))));
// Output code
let VAR1 = CALL(`FooSelfAssign(1)`)
let VAR4 = CALL(`FooSelfAssign(?)`,[CALL(`FooSelfAssign(?)`,[CALL(`FooSelfAssign(?)`,[CALL(`FooSelfAssign(4)`)])])]);
Observe que a conversão para VAR1 é muito simples, mas para VAR4, o CALL mais externo contém uma lista com o restante de CALLs, como vinculações.
Cada CALL sucessivo é convertido para uma vinculação, se estiver contido em outro CALL.
2. Variables¶
DECLARE @Variable¶
SQL Server¶
DECLARE @product_list VARCHAR(MAX) = ' ';
DECLARE @Variable1 AS VARCHAR(100), @Variable2 AS VARCHAR(100);
Snowflake¶
let PRODUCT_LIST = ` `;
let VARIABLE1;
let VARIABLE2;
DECLARE @Variable Table¶
Nesse caso, DECLARE é usado para declarar uma tabela de variáveis. Vejamos um exemplo.
-- Additional Params: -t JavaScript
CREATE PROCEDURE PROC1
AS
BEGIN
DECLARE @VariableNameTable TABLE
(
[Col1] INT NOT NULL,
[Col2] INT NOT NULL
);
INSERT INTO @VariableNameTable Values(111,222);
Select * from @VariableNameTable;
END
Exec PROC1;
Se executarmos esse código no Sql Server, obteremos o seguinte resultado
col1 |
col2 |
|---|---|
111 |
222 |
Agora, vamos ver a transformação no Snowflake
CREATE OR REPLACE PROCEDURE PROC1 ()
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
// SnowConvert AI Helpers Code section is omitted.
{
EXEC(`CREATE OR REPLACE TEMPORARY TABLE T_VariableNameTable
(
Col1 INT NOT NULL,
Col2 INT NOT NULL
)`);
EXEC(`INSERT INTO T_VariableNameTable Values(111,222)`);
EXEC(`Select
*
from
T_VariableNameTable`);
}
EXEC(`CALL PROC1()`);
$$;
Observe que das linhas 61 a 67 estão os resultados dessas instruções dentro do procedimento.
A tabela de variáveis Declare é transformada em uma tabela temporária. Observe que no nome o caractere @ foi substituído por T_.
Se executarmos esse código no Snowflake, não obteremos nenhum resultado. Ele exibirá apenas null. Isso ocorre porque o último Select está agora no auxiliar EXEC. Então, como sabemos que a tabela está lá?
Como ela foi criada como uma tabela temporária dentro do procedimento em um EXEC, podemos fazer um Select para essa tabela fora do procedimento.
Select * from PUBLIC.T_VariableNameTable;
Se executarmos essa instrução, obteremos o seguinte resultado
col1 |
col2 |
|---|---|
111 |
222 |
SET @Variable¶
Por enquanto, Set Variable é transformado de acordo com a expressão que está no lado direito.
Se a expressão tiver uma transformação, ela será transformada em seu equivalente no JavaScript.
Exemplo
-- Additional Params: -t JavaScript
CREATE PROCEDURE PROC1
AS
BEGIN
SET @product_list2 = '';
SET @product_list = '';
SET @var1 += '';
SET @var2 &= '';
SET @var3 ^= '';
SET @var4 |= '';
SET @var5 /= '';
SET @var6 %= '';
SET @var7 *= '';
SET @var8 -= '';
SET @ProviderStatement = 'SELECT * FROM TABLE1
WHERE COL1 = '+@PARAM1+ ' AND COL2 = ' + @LOCALVAR1;
SET @NotSupported = functionValue(a,b,c);
END
Snowflake¶
CREATE OR REPLACE PROCEDURE PROC1 ()
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
// SnowConvert AI Helpers Code section is omitted.
PRODUCT_LIST2 = ``;
PRODUCT_LIST = ``;
VAR1 += ``;
VAR2 &= ``;
VAR3 ^= ``;
VAR4 |= ``;
VAR5 /= ``;
VAR6 %= ``;
VAR7 *= ``;
VAR8 -= ``;
PROVIDERSTATEMENT = `SELECT
*
FROM
TABLE1
WHERE
COL1 = ${PARAM1}
AND COL2 = ${LOCALVAR1};`;
NOTSUPPORTED = SELECT(` functionValue(a,b,c) !!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'functionValue' NODE ***/!!!`);
$$;
Como você pode ver no exemplo, o valor da variável NOTSUPPORTED é comentado, pois ela não está sendo transformada por enquanto. Observe que isso significa que a transformação ainda não foi concluída.
Outros tipos de conjuntos são comentados, por exemplo, os seguintes
SQL Server¶
-- Additional Params: -t JavaScript
CREATE PROCEDURE PROC1
AS
BEGIN
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
;
SET NOCOUNT ON
;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
;
SET NOCOUNT OFF
;
END
Snowflake¶
CREATE OR REPLACE PROCEDURE PROC1 ()
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
// SnowConvert AI Helpers Code section is omitted.
/*** SSC-EWI-0040 - THE 'SET' CLAUSE IS NOT SUPPORTED IN SNOWFLAKE ***/
/*SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED*/
;
/*** SSC-EWI-0040 - THE 'SET' CLAUSE IS NOT SUPPORTED IN SNOWFLAKE ***/
/*SET NOCOUNT ON*/
;
/*** SSC-EWI-0040 - THE 'SET' CLAUSE IS NOT SUPPORTED IN SNOWFLAKE ***/
/*SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED*/
;
/*** SSC-EWI-0040 - THE 'SET' CLAUSE IS NOT SUPPORTED IN SNOWFLAKE ***/
/*SET NOCOUNT OFF*/
;
$$;
SELECT @Variable¶
Por enquanto, SELECT @variable está sendo transformado em um Select simples, removendo as atribuições de variáveis e mantendo as expressões no lado direito do operador. As operações de atribuição das variáveis locais no Select serão substituídas por funções arrow que representam o mesmo comportamento da operação realizada durante a atribuição da variável local no SQL Server.
SQL Server¶
-- Additional Params: -t JavaScript
CREATE PROCEDURE PROC1 AS
DECLARE @VAR1 int;
DECLARE @VAR2 int;
SELECT @VAR1 = COL1 + COL2, @VAR2 = COL3 FROM TABLE1;
GO
Snowflake¶
CREATE OR REPLACE PROCEDURE PROC1 ()
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
// SnowConvert AI Helpers Code section is omitted.
let VAR1;
let VAR2;
SELECT(` COL1 + COL2,
COL3
FROM
TABLE1`,[],(value) => VAR1 = value,(value) => VAR2 = value);
$$;
3. Statements translation¶
SELECT¶
Forma básica¶
O formulário SELECT básico não tem vinculações, portanto, a tradução implica a criação de uma chamada para a função auxiliar EXEC com um parâmetro. Por exemplo:
-- Source code:
SELECT * FROM DEMO_TABLE_1;
// Translated code:
EXEC(`SELECT * FROM DEMO_TABLE_1`);
IF¶
SQL Server¶
IF Conditional_Expression
-- SQL Statement
ELSE IF Conditiona_Expression2
-- SQL Statement
ELSE
-- SQL Statement
Snowflake¶
if (Conditional_Expression) {
// SQL Statement
} else if (Conditional_Expression2) {
// SQL Statement
} else{
// SQL Statement
}
WHILE¶
SQL Server¶
WHILE ( Conditional_Expression )
BEGIN
-- SQL STATEMENTS
END;
Snowflake¶
while ( Conditional_Expression )
{
// SQL STATEMENTS
}
EXEC / EXECUTE¶
SQL Server¶
-- Execute simple statement
Exec('Select 1');
-- Execute statement using Dynamic Sql
Exec('Select ' + @par1 + ' from [db].[t1]');
-- Execute Procedure with parameter
EXEC db.sp2 'Create proc [db].[p3] AS', @par1, 1
Snowflake¶
-- Execute simple statement
EXEC(`Select 1`);
-- Execute statement using Dynamic Sql
EXEC(`Select ${PAR1} from MYDB.db.t1`);
-- Execute Procedure with parameter
EXEC(`CALL db.sp2(/*** SSC-EWI-0038 - THIS STATEMENT MAY BE A DYNAMIC SQL THAT COULD NOT BE RECOGNIZED AND CONVERTED ***/
'Select * from MYDB.db.t1', ?, 1, Default)`,[PAR1]);
THROW¶
A transformação para THROW garante que o bloco de captura que recebe o erro tenha acesso às informações especificadas na instrução original.
SQL Server¶
-- Case 1
THROW
-- Case 2
THROW 123, 'The error message', 1
-- Case 3
THROW @var1, @var2, @var3
Snowflake¶
// Case 1
throw {};
// Case 2
throw { code: 123, message: "The error message", status: 1 };
// Case 3
throw { code: VAR1, message: VAR2, status: VAR3 };
RAISERROR¶
A função do SQL Server RAISERROR não é compatível com o Snowflake. O SnowConvert AI identifica todos os usos para gerar um auxiliar que emula o comportamento original. Exemplo:
SQL Server¶
-- Additional Params: -t JavaScript
CREATE OR ALTER PROCEDURE RAISERRORTEST AS
BEGIN
DECLARE @MessageTXT VARCHAR = 'ERROR MESSAGE';
RAISERROR (N'E_INVALIDARG', 16, 1);
RAISERROR ('Diagram does not exist or you do not have permission.', 16, 1);
RAISERROR(@MessageTXT, 16, 1);
END
GO
Snowflake¶
CREATE OR REPLACE PROCEDURE RAISERRORTEST ()
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
// SnowConvert AI Helpers Code section is omitted.
let MESSAGETXT = `ERROR MESSAGE`;
RAISERROR("E_INVALIDARG","16","1");
RAISERROR("Diagram does not exist or you do not have permission.","16","1");
RAISERROR(MESSAGETXT,"16","1");
$$;
BREAK/CONTINUE¶
A transformação Break/Continue garante que o fluxo do código seja interrompido ou continue com outro bloco.
SQL Server¶
-- Additional Params: -t JavaScript
CREATE PROCEDURE ProcSample
AS
BEGIN
IF @@ROWCOUNT > 0
Continue;
ELSE
BREAK;
END
Snowflake¶
CREATE OR REPLACE PROCEDURE ProcSample ()
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
// SnowConvert AI Helpers Code section is omitted.
if (ROW_COUNT > 0) {
continue;
} else {
break;
}
$$;
INSERT INTO EXEC¶
O código foi ligeiramente modificado devido ao fato de a instrução INSERT INTO [Table] EXEC(...) não ser compatível com o Snowflake, o que nos permite replicar o comportamento adicionando algumas linhas de código:
A primeira linha adicionada é uma chamada para
insertIntoTemporaryTablepara onde o código extraído do argumento dentro deEXEC; isso inserirá o conjunto de resultados em uma tabela temporária. Para obter mais informações sobre a função, consulte a seção Auxiliar Insert Into EXEC.O Exec do Insert é removido do código e uma consulta recupera os resultados do EXEC da tabela temporária.
SELECT * FROM MYDB.PUBLIC.SnowConvertPivotTemporaryTable
A última linha adicionada é uma instrução DROP TABLE para a tabela temporária adicionada.
DROP TABLE SnowConvertPivotTemporaryTable
SQL Server¶
INSERT INTO #Table1
EXEC ('SELECT
Table1.ID
FROM Population');
INSERT INTO #Table1
EXEC (@DBTables);
Snowflake¶
insertIntoTemporaryTable(`SELECT Table1.ID FROM MYDB.PUBLIC.Population)
EXEC(`INSERT INTO MYDB.PUBLIC.T_Table1 SELECT * FROM MYDB.PUBLIC.SnowConvertPivotTemporaryTable`);
EXEC(`DROP TABLE SnowConvertPivotTemporaryTable`)
insertIntoTemporaryTable(`${DBTABLES}`)
EXEC(`INSERT INTO MYDB.PUBLIC.T_Table1 SELECT * FROM MYDB.PUBLIC.SnowConvertPivotTemporaryTable`);
EXEC(`DROP TABLE SnowConvertPivotTemporaryTable`)
BEGIN TRANSACTION¶
BEGIN TRANSACTION é transformado no comando BEGIN do Snowflake e inserido em uma chamada do auxiliar EXEC.
O auxiliar é responsável por executar de fato o resultado BEGIN.
SQL Server¶
-- Input code
BEGIN TRAN @transaction_name;
Snowflake¶
// Output code
EXEC(`BEGIN`, []);
COMMIT TRANSACTION¶
COMMIT TRANSACTION é transformado no comando COMMIT do Snowflake e inserido em uma chamada do auxiliar EXEC.
O auxiliar é responsável por executar de fato o resultado COMMIT.
SQL Server¶
-- Input code
COMMIT TRAN @transaction_name;
Snowflake¶
// Output code
EXEC(`COMMIT`, []);
ROLLBACK TRANSACTION¶
ROLLBACK TRANSACTION é transformado no comando ROLLBACK do Snowflake e inserido em uma chamada do auxiliar EXEC.
O auxiliar é responsável por executar de fato o resultado ROLLBACK.
SQL Server¶
-- Input code
ROLLBACK TRAN @transaction_name;
Snowflake¶
// Output code
EXEC(`ROLLBACK`, []);
WAITFOR DELAY¶
A cláusula WAITFOR DELAY é transformada na função SYSTEM$WAIT do Snowflake. O parâmetro time_to_pass do DELAY é transformado em segundos, para uso como parâmetro na função SYSTEM$WAIT.
As outras variantes da cláusula WAITFOR não são compatíveis com o Snowflake e, portanto, são marcadas com a mensagem correspondente.
SQL Server¶
-- Input code
1) WAITFOR DELAY '02:00';
2) WAITFOR TIME '13:30';
3) WAITFOR (RECEIVE TOP (1)
@dh = conversation_handle,
@mt = message_type_name,
@body = message_body
FROM [eqe]), TIMEOUT 5000;
Snowflake¶
// Output code
1) EXEC(`SYSTEM$WAIT(120)`,[]);
2) /*** SSC-EWI-0040 - THE 'WAIT FOR' CLAUSE IS NOT SUPPORTED IN SNOWFLAKE ***/
/*WAITFOR TIME '13:30'*/
;
3) /*** SSC-EWI-0040 - THE 'WAIT FOR' CLAUSE IS NOT SUPPORTED IN SNOWFLAKE ***/
/*WAITFOR (RECEIVE TOP (1)
@dh = conversation_handle,
@mt = message_type_name,
@body = message_body
FROM [eqe]), TIMEOUT 5000*/
;
3. Cursors¶
Visto que CURSORS não são compatíveis com o Snowflake, o SnowConvert AI mapeia sua funcionalidade para um auxiliar JavaScript que emula o comportamento original na plataforma de destino. Exemplo:
SQL Server¶
-- Additional Params: -t JavaScript
CREATE PROCEDURE [procCursorHelper] AS
DECLARE vendor_cursor CURSOR FOR
SELECT VendorID, Name
FROM Purchasing.Vendor
WHERE PreferredVendorStatus = 1
ORDER BY VendorID;
GO
Snowflake¶
CREATE OR REPLACE PROCEDURE procCursorHelper ()
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
// SnowConvert AI Helpers Code section is omitted.
var VENDOR_CURSOR = new CURSOR(`SELECT
VendorID,
Name
FROM
Purchasing.Vendor
WHERE
PreferredVendorStatus = 1
ORDER BY VendorID`,[],false);
$$;
DECLARE CURSOR¶
SQL Server¶
DECLARE myCursor1 CURSOR FOR SELECT COL1 FROM TABLE1
Snowflake¶
let myCursor1 = new CURSOR(`SELECT COL1 FROM TABLE1`,() => []);
OPEN¶
SQL Server¶
OPEN myCursor1
OPEN GLOBAL myCursor2
Snowflake¶
myCursor1.OPEN();
myCursor2.OPEN()
FETCH¶
SQL Server¶
DECLARE @VALUE1 INT
FETCH NEXT FROM myCursor1 into @VALUE1
Snowflake¶
var VALUE1;
myCursor1.FETCH_NEXT();
VALUE1 = myCursor1.INTO();
CLOSE¶
SQL Server¶
CLOSE myCursor1
CLOSE GLOBAL myCursor2
Snowflake¶
myCursor1.CLOSE()
myCursor2.CLOSE()
DEALLOCATE¶
SQL Server¶
DEALLOCATE myCursor1
DEALLOCATE GLOBAL myCursor2
Snowflake¶
myCursor1.DEALLOCATE()
myCursor2.DEALLOCATE()
@@FETCH_STATUS¶
SQL Server¶
@@FETCH_STATUS
Snowflake¶
myCursor1.FETCH_STATUS()
@@CURSOR_ROWS¶
SQL Server¶
@@CURSOR_ROWS
Snowflake¶
myCursor1.FETCH_STATUS()
4. Expressions¶
Operações binárias¶
SQL Server¶
SET @var1 = 1 + 1;
SET @var1 = 1 - 1;
SET @var1 = 1 / 1;
SET @var1 = 1 * 1;
SET @var1 = 1 OR 1;
SET @var1 = 1 AND 1;
Snowflake¶
VAR1 = 1 + 1;
VAR1 = 1 - 1;
VAR1 = 1 / 1;
VAR1 = 1 * 1;
VAR1 = 1 || 1;
VAR1 = 1 && 1;
Condicionais¶
SQL Server¶
@var1 > 0
@var1 = 0
@var1 < 0
@var1 <> 0
Snowflake¶
VAR1 > 0
VAR1 = 0
VAR1 < 0
VAR1 != 0
Predicado NULL¶
SQL Server¶
@var1 is null
@var2 is not null
Snowflake¶
VAR1 == null
VAR2 != null
5. Labels and Goto¶
Rótulos não têm o mesmo comportamento no JavaScript que o SQL Server tem. Para simular o comportamento, eles estão sendo transformados em funções. Seu uso está sendo substituído por uma chamada da função gerada que contém toda a lógica do rótulo. Exemplo:
Código-fonte¶
-- Additional Params: -t JavaScript
CREATE PROCEDURE [procWithLabels]
AS
SUCCESS_EXIT:
SET @ErrorStatus = 0
RETURN @ErrorStatus
ERROR_EXIT:
RETURN @ErrorStatus
Snowflake¶
CREATE OR REPLACE PROCEDURE procWithLabels ()
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
// SnowConvert AI Helpers Code section is omitted.
SUCCESS_EXIT();
ERROR_EXIT();
function SUCCESS_EXIT() {
ERRORSTATUS = 0;
return ERRORSTATUS;
}
function ERROR_EXIT() {
return ERRORSTATUS;
}
$$;
Como você vê no exemplo acima, as declarações de função que eram os rótulos no código-fonte serão colocadas no final do código para torná-lo mais limpo.
GOTO é outro comando que não existe no JavaScript. Para simular seu comportamento, seus usos estão sendo transformados em chamadas para a função (rótulo) que é referenciada, precedida por uma instrução de retorno. Exemplo:
SQL Server¶
-- Additional Params: -t JavaScript
CREATE PROCEDURE [procWithLabels]
AS
DECLARE @ErrorStatus int = 0;
IF @ErrorStatus <> 0 GOTO ERROR_EXIT
SUCCESS_EXIT:
SET @ErrorStatus = 0
RETURN @ErrorStatus
ERROR_EXIT:
RETURN @ErrorStatus
Snowflake¶
CREATE OR REPLACE PROCEDURE procWithLabels ()
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
// SnowConvert AI Helpers Code section is omitted.
let ERRORSTATUS = 0;
if (ERRORSTATUS != 0) {
return ERROR_EXIT();
}
SUCCESS_EXIT();
ERROR_EXIT();
function SUCCESS_EXIT() {
ERRORSTATUS = 0;
return ERRORSTATUS;
}
function ERROR_EXIT() {
return ERRORSTATUS;
}
$$;
Como você vê no exemplo acima, return é adicionado à chamada da função para interromper o fluxo do código, como o SQL Server com GOTO.