How to call nested stored create table procedures in Snowflake - snowflake-cloud-data-platform

Looking for advice on how to correct these two stored procedures so that one will trigger the other.
Stored procedure 2 is designed to simply create Table 2:
CREATE OR REPLACE PROCEDURE create_table_2()
returns string not null
language javascript
as
$$
var create_table_2 = `
create or replace table DATABASE.SCHEMA.TABLE_2
(
COL_1 string,
COL_2 string,
COL_3 date
)
;
`
var create_table_2_cmd = snowflake.createStatement({sqlText: create_table_2});
var result = sql_create_table_2.execute();
return 'Table 2 created';
$$;
And stored procedure 1, which should be run first, create table 1 and then run stored procedure 2:
CREATE OR REPLACE PROCEDURE create_table_1()
returns string not null
language javascript
as
$$
var create_table_1 = `
create or replace table DATABASE.SCHEMA.TABLE_1
(
COL_1 string,
COL_2 string,
COL_3 date
)
;
`
var create_table_1_cmd = snowflake.createStatement({sqlText: create_table_1 });
var result = create_table_1_cmd .execute();
return 'Table 1 created';
var call_next_function_cmd = `
call create_table_2();
;
`
var call_next_func = snowflake.createStatement({sqlText: call_next_function_cmd});
var final = call_next_func.execute();
$$;
The SQL code within the create_table_1() procedure executes without issue but does not call the create_table_2() procedure. Is there an adjustment to be made that can trigger this?

The return has to be moved to the end of stored procedure, at current position it makes the second call unreachable code:
CREATE OR REPLACE PROCEDURE create_table_1()
returns string not null
language javascript
as
$$
var create_table_1 = `
create or replace table DATABASE.SCHEMA.TABLE_1
(
COL_1 string,
COL_2 string,
COL_3 date
)
;
`
var create_table_1_cmd = snowflake.createStatement({sqlText: create_table_1 });
var result = create_table_1_cmd .execute();
//return 'Table 1 created'; -- << HERE
var call_next_function_cmd = `
call create_table_2();
;
`
var call_next_func = snowflake.createStatement({sqlText: call_next_function_cmd});
var final = call_next_func.execute();
return '...';
$$;

Related

Create stored procedure that create users in snowflake

I am trying to create a stored procedure in snowflake that create users in snowflake. But I am unable to bind variables.
Here is what I tried using snowflake scripting. I was not successful in creating a version that works
create or replace procedure create_user(user_name varchar, password_value varchar)
returns varchar
language sql
as
$$
begin
create user :USER_NAME password = :password_value;
return 'Completed.';
end;
$$
;
In the above stored procedure, when I use :USER_NAME (I have tried upper and lower case). I get an error saying unexpected :. Password_value seems to work correctly.
I have also tried javascript version
CREATE OR REPLACE PROCEDURE security.create_user_v2(USER_NAME varchar, PASSWORD_VALUE varchar)
RETURNS BOOLEAN
LANGUAGE JAVASCRIPT
AS
$$
var cmd = "create user :1 password = :2;";
var stmt = snowflake.createStatement(
{
sqlText: cmd,
binds: [USER_NAME, PASSWORD_VALUE]
}
);
var result = stmt.execute();
result.next();
return true
$$
;
I get the same here as well, says unexpected :.
This version works, but this is concatenation, i want to avoid this (possible sql injection)
CREATE OR REPLACE PROCEDURE security.create_user_v2(USER_NAME varchar, PASSWORD_VALUE varchar)
RETURNS BOOLEAN
LANGUAGE JAVASCRIPT
AS
$$
var cmd = "create user "+USER_NAME+" password = :1;";
var stmt = snowflake.createStatement(
{
sqlText: cmd,
binds: [PASSWORD_VALUE]
}
);
var result = stmt.execute();
result.next();
return true
$$
;
How do I create a snowflake scripting version or javascript version that bind variables when creating users in stored procedure.
User name must be enclosed with IDENTIFIER in order to use variable:
CREATE OR REPLACE PROCEDURE security.create_user_v2(USER_NAME varchar,
PASSWORD_VALUE varchar)
RETURNS BOOLEAN
LANGUAGE JAVASCRIPT
AS
$$
var cmd = "create user IDENTIFIER(:1) password = :2;";
var stmt = snowflake.createStatement(
{
sqlText: cmd,
binds: [USER_NAME, PASSWORD_VALUE]
}
);
var result = stmt.execute();
result.next();
return true
$$
;
Call:
CALL security.create_user_v2('user1', 'password123');
CALL security.create_user_v2('"user1#x.com"', 'password123');
SHOW USERS;
Snowflake Scripting:
create or replace procedure security.create_user(user_name varchar,
password_value varchar)
returns varchar
language sql
as
$$
begin
create user IDENTIFIER(:USER_NAME) password = :password_value;
return 'Completed.';
end;
$$;

schema does not exist and not authorized

I am trying to create a Procedure in snowflake.
CREATE OR REPLACE PROCEDURE test()
returns string not null language javascript as
$$
var cmd = "select count(1) from Test1.table1";
var sql = snowflake.createStatement({sqlText: cmd});
var result = sql.execute();
return '1';
$$;
"table1" existing in schema "schema1" but i am trying to create this procedure in schema2. schema2 does have an access to "table1.
when I run the same query in snowflake web UI with schema "schema2" where i am creating the procedure select count(1) from Test1.table1 it is working but inside procedure it is not working and displaying me error
schema does not exist and not authorized
CREATE OR REPLACE PROCEDURE test()
returns string not null language javascript as
$$
var cmd = "select count(1) from Test1.table1";
var sql = snowflake.createStatement({sqlText: cmd});
var result = sql.execute();
return '1';
$$;
if you fully qualify you names, things just work:
use schema test.test;
create schema test.test1;
create table test.test1.table1(id int);
CREATE OR REPLACE PROCEDURE test.test1.test()
returns string not null language javascript as
$$
var cmd = "select count(1) from test.test1.table1";
var sql = snowflake.createStatement({sqlText: cmd});
var result = sql.execute();
return '1';
$$;
call test.test1.test();
TEST
1
create schema test.test2;
use schema test.test2;
call test.test1.test();
TEST
1
use schema test.test2;
CREATE OR REPLACE PROCEDURE test.test2.test()
returns string not null language javascript as
$$
var cmd = "select count(1) from test.test1.table1";
var sql = snowflake.createStatement({sqlText: cmd});
var result = sql.execute();
return 'called table1 from schema2';
$$;
call test.test2.test();
TEST
called table1 from schema2
So why your error?
The below SQL I have made non fully qualified. So the function will be in the current scehma. Which for me is test.test2. But now I am referring to schema schema1.table1 and schema1 does not exist. thus the error message when I run the code.
CREATE OR REPLACE PROCEDURE test()
returns string not null language javascript as
$$
var cmd = "select count(1) from schema1.table1";
var sql = snowflake.createStatement({sqlText: cmd});
var result = sql.execute();
return 'called table1 from schema2';
$$;
call test.test2.test();
gives:
SQL compilation error:
Schema 'TEST.SCHEMA1' does not exist or not authorized.
At Statement.execute, line 4 position 21
The other possible outcome is you have the function defined as EXECUTE AS OWNER and the two functions do have two different owners, with different owning permissions. But I am going to doubt that.

Snowflake Stored Procedure For Loop

i'm working with Snowflake,
i created this Stored Procedure, it's purpose is to do the following steps:
extract the relevant 'application_id' values from the SQL query
use a FOR loop over a SQL query, with the 'application_id' values that i extracted
in step 1, and delete the relevant rows from the target table.
when i call the Stored Procedure, it runs without errors, but it doesn't do anything ( the relevant records are not been deleted).
i added my SP code,
please let me know if you see any syntax / logic errors,
thanks
CREATE OR REPLACE PROCEDURE DWH.sp_testing()
RETURNS string
LANGUAGE javascript
strict
EXECUTE AS owner
AS
$$
try
{
var application_list = ` SELECT application_id
FROM PUBLIC.my_source_table_name
WHERE my_flag = 1
`
var query_statement = snowflake.createStatement({sqlText: application_list});
var application_list_result = query_statement.execute();
for (i = 1; i <= query_statement.getRowCount(); i++)
{
application_list_result.next()
application_id = application_list_result.getColumnValue(1)
var delete_daily_records = `
DELETE FROM PUBLIC.my_target_table_name AS target
WHERE target.application_id = ${application_id}
`
snowflake.execute({sqlText: delete_daily_records});
}
}
catch (err)
{
throw "Failed: " + err;
}
$$
;
CALL DWH.sp_testing();
Are you sure your query is returning data? Also are you sure the target table has data matching your DELETE statement?
The following test works for me using your stored procedure:
select count(*) from citibike_trips where end_station_id=6215;
returns: 14565
Now, I created your stored proc:
CREATE OR REPLACE PROCEDURE sp_testing()
RETURNS string
LANGUAGE javascript
strict
EXECUTE AS owner
AS
$$
try
{
var application_list = `SELECT end_station_id
FROM citibike_trips
WHERE end_station_id=6215 limit 10
`
var query_statement = snowflake.createStatement({sqlText: application_list});
var application_list_result = query_statement.execute();
for (i = 1; i <= query_statement.getRowCount(); i++)
{
application_list_result.next()
end_station_id = application_list_result.getColumnValue(1)
var delete_daily_records = `
DELETE FROM citibike_trips AS target
WHERE target.end_station_id = ${end_station_id}
`
snowflake.execute({sqlText: delete_daily_records});
}
}
catch (err)
{
throw "Failed: " + err;
}
$$
;
Run it:
CALL SP_TESTING();
Shows NULL as result (expected since it is not returning anything).
But then when I check the table again:
select count(*) from citibike_trips where end_station_id=6215;
returns: 0

Capture and run result_scan using query_id in Snowflake Procedure

Trying to run Describe table and running RESULT_SCAN on the query id of the describe table query.
Procedure:
var qry = ` describe table TEST_TABLE `;
var qry_rslt = snowflake.execute({sqlText: qry});
var qry_id= qry_rslt.getQueryId();
var qry2 = ` select * from table(result_scan('`+qry_id+`')) `
snowflake.execute({sqlText: qry2});
The procedure is returning Null and not running the SQL. On manually running the result scan query it says statement not found.
ANy idea how to read describe result.
You're not actually reading the results of the second query. It's running it but not collecting the results. This will collect the first column only of the result set:
create or replace procedure test()
returns string
language javascript
as
$$
var qry = ` describe table TEST_TABLE `;
var qry_rslt = snowflake.execute({sqlText: qry});
var qry_id= qry_rslt.getQueryId();
var qry2 = ` select * from table(result_scan('${qry_id}')) `;
rs = snowflake.execute({sqlText: qry2});
var out = "";
var i = 0;
while (rs.next()) {
if (i++ > 0) out += ",";
out += rs.getColumnValue(1);
}
return out;
$$;
call test();
Are you looking to get the entire DDL in one statement? If so you can run get_ddl and then read just the first row, first column. It will have the DDL for the entire table. If you want it as a table, you'll need to read the rows and columns to do what needs to be done with them.

Stream and Task Stored procedure example, I am not sure how to troubleshoot the javascript

I have just learned about Streams and Tasks in Snowflake and have tested the example for tracking members and sign ups in the first example here.
I have attempted to create a stored procedure that looks like this:
CREATE OR REPLACE procedure member_update()
returns string not null
language javascript
as
$$
var statement = snowflake.createStatement({sqlText: "BEGIN"} );
statement.execute();
var statement = snowflake.createStatement({sqlText: "UPDATE members SET fee = fee + 15 where fee > 0"} );
statement.execute();
var statement = snowflake.createStatement({sqlText: "SELECT * FROM member_check"} );
statement.execute();
var statement = snowflake.createStatement({sqlText: "COMMIT"} );
statement.execute();
var statement = snowflake.createStatement({sqlText: "SELECT * FROM member_check"} );
statement.execute();
$$
;
INSERT INTO members (id,name,fee)
VALUES
(11,'Bill',0),
(12,'Jason',0),
(13,'Suzan',0),
(14,'Michelle',0),
(15,'AARON',0);
SELECT * FROM MEMBER_CHECK;
INSERT INTO signup
VALUES
(11,'2018-01-01'),
(12,'2018-02-15'),
(13,'2018-05-01'),
(14,'2018-07-16'),
(15,'2018-08-21');
MERGE INTO members m
USING (
SELECT id, dt
FROM signup s
WHERE DATEDIFF(day, '2018-08-15'::date, s.dt::DATE) < -30) s
ON m.id = s.id
WHEN MATCHED THEN UPDATE SET m.fee = 90;
Call member_update();
I have run into an error and was hoping I might get some guidance on by very beginner stored procedure.
Error:
Execution error in store procedure MEMBER_UPDATE: empty argument
passed At Snowflake.createStatement, line 2 position 29

Resources