How to alter session parameters within a Snowflake stored procedure - stored-procedures

I'm building a date dimension with a stored procedure and need to alter session parameter WEEK_START to ensure correct calculation of certain values. On this topic, Snowflake documentation is mostly focused on distinguishing Caller vs Owner rights, but implies this should be possible. However, the result I get when calling the procedure defined below is: "Failed: Stored procedure execution error: Unsupported statement type 'ALTER_SESSION'."
CREATE OR REPLACE PROCEDURE PUBLIC.USP_ALTER_SESSION_TEST(BATCH_ID float)
returns string
language javascript
as
$$
var sql_session,
sql_test,
stmt_session,
stmt_test;
sql_session = "ALTER SESSION SET WEEK_START = 1;";
sql_test = "SELECT DAYOFWEEK(CURRENT_DATE());";
try
{
stmt_session = snowflake.createStatement( {sqlText: sql_session} );
stmt_session.execute ();
stmt_test = snowflake.createStatement( {sqlText: sql_test} );
stmt_test.execute ();
return "Succeeded.";
}
catch (err)
{
return "Failed: " + err;
}
$$
;

There are somethings that are not when executing as owner. Week start is allowed with caller execution. Add EXECUTE AS CALLER to the definition and it should work.

Related

how to bind the variables passed through a function in snowflake stored procedure

I created a stored procedure with a function in it for logging into a log table, the output is as below:
100132 (P0000): JavaScript execution error: Uncaught ERROR:LOG_LEVEL is not defined in FUNCTION_TEST at '     throw "ERROR:" +err.message   ' position 5
stackstrace:
log_file line: 39
FUNCTION_TEST line: 5.
the code is show in below
create or replace procedure function_test()
returns varchar not null
language JAVASCRIPT
as
$$
const ProceName=Object.keys(this)[0];
try
{
log("INFO",ProceName,0,"RUNNING","","")
var copy_into_cmd = `copy into my_table from #my_stage
file_format=(format_name= 'my_file_format')
on_error = skip_file;`;
var copy_into_stmt = snowflake.createStatement({sqlText: copy_into_cmd});
log("INFO",ProceName,0,"EXECUTING",copy_into_stmt.getQueryId(),copy_into_stmt.getSqlText())
var result_set= copy_into_stmt.execute();
return "SUCCESS"
}
catch(err)
{
var query_id = copy_into_stmt.getQueryId();
var sqltext= copy_into_stmt.getSqlText();
log("INFO",ProceName,err.code,err.message,query_id,sqltext)
return err.message
}
function log(log_level,src_name,err,message,query_id,stmt_txt)
{
try
{
var load_cmd="insert into log_table(timestamp,log_level,usr_name,src_name,err,message,query_id,sql_text) values(current_timestamp(),?,current_user(),?,NULLIFZERO(?),?,?,?);"
var load_stmt=snowflake.createStatement({sqlText: load_cmd, binds:[LOG_LEVEL,SRC_NAME,ERR,MESSAGE,QUERY_ID,STMT_TXT]}).execute();
}
catch(err)
{
throw "ERROR: "+err.message
}
}
$$;
any suggestions, would be helpful.
JavaScript is a case-sensitive language. So you need to update the line with LOG_LEVEL like this:
var load_stmt=snowflake.createStatement({sqlText: load_cmd, binds:[log_level,src_name,err,message,query_id,stmt_txt]}).execute();
When you call the main function/procedure from the SQL engine, the SQL engine will send the parameter names in uppercase (unless you wrap them in double-quotes); this is why the main function will reach the function params in uppercase.

Exit the stored procedure and RAISE error in Snowflake stored procedure like BREAK or RAISERROR in SQL Server

I have a stored procedure which executes multiple queries and for each of those queries I have a try and catch block as shown below. If there is an error, I capture and insert into a LOG table.
However, I also need to BREAK and come out of that step, wherever error is encountered. as an e.g. if I have error in the first try / catch it shouldn't execute the second query and exit with ERROR.
code:
CREATE OR REPLACE PROCEDURE DIM_TABLES_REFRESH()
RETURNS STRING
LANGUAGE JAVASCRIPT
AS
$$
var DB_SCHEMA = 'DB_DEV.DMS';
try {
/***** Refresh DIM table DIM_ACT_REVCODE_HIER ****/
var truncate_1 =` TRUNCATE TABLE ${DB_SCHEMA}.DIM_ACT_REVCODE `;
snowflake.execute({sqlText: truncate_1, binds: [DB_SCHEMA]});
var populate_1 = `INSERT INTO ${DB_SCHEMA}.DIM_ACT_REVCODE
(
ACT_REVCODE_HIER_KEY
,REV_CODE
,REV_CODE_DESC
)
SELECT
ROW_NUMBER() OVER ( ORDER BY REV_CODE ) AS ACT_REVCODE_HIER_KEY
,REV_CODE
,REV_CODE_DESC
FROM ${DB_SCHEMA}.OBIEE_ACT_REVCODE`;
snowflake.execute({sqlText: populate_1, binds: [DB_SCHEMA]});
var insert_status_sp1=`INSERT INTO STATS_QUERY_LOAD_STATUS_LOG values (Current_TIMESTAMP(),1,'ACT_REVCODE','Success','');`
var exec_sp1_status = snowflake.createStatement({sqlText: insert_status_sp1}).execute();
exec_sp1_status.next();
var exec_status='Success';
}
catch (err) {
exec_status =err;
if (exec_status!='Success') {
var insert_status_sp1=`INSERT INTO STATS_QUERY_LOAD_STATUS_LOG values (Current_TIMESTAMP(),1,'ACT_REVCODE','Failed',:1);`
var exec_sp1_status = snowflake.createStatement({sqlText: insert_status_sp1,binds:[err.message]}).execute();
exec_sp1_status.next();
}
}
try {
/***** Refresh DIM table ACTIVITY_HIER ****/
var truncate_2 =` TRUNCATE TABLE ${DB_SCHEMA}.ACTIVITY_HIER `;
snowflake.execute({sqlText: truncate_2, binds: [DB_SCHEMA]});
var populate_2 = `INSERT INTO ${DB_SCHEMA}.ACTIVITY_HIER
(
ACTIVITY_HIER_KEY
,ACTIVITY_CD
,ACTIVITY_DESC
,ACTIVITY_CD
)
SELECT
ROW_NUMBER() OVER ( ORDER BY ACTIVITY_CD ,ORG_CODE ) AS ACTIVITY_HIER_KEY
,ACTIVITY_CD
,ACTIVITY_DESC
,ACTIVITY_CD
FROM ${DB_SCHEMA}.OBIEE_ACTIVITY_HIER`;
snowflake.execute({sqlText: populate_2, binds: [DB_SCHEMA]});
var insert_status_sp1=`INSERT INTO STATS_QUERY_LOAD_STATUS_LOG values (Current_TIMESTAMP(),2,'ACTIVITY_HIER','Success','');`
var exec_sp1_status = snowflake.createStatement({sqlText: insert_status_sp1}).execute();
exec_sp1_status.next();
var exec_status='Success';
}
catch (err) {
exec_status =err;
if (exec_status!='Success') {
var insert_status_sp1=`INSERT INTO STATS_QUERY_LOAD_STATUS_LOG values (Current_TIMESTAMP(),2,'ACTIVITY_HIER','Failed',:1);`
var exec_sp1_status = snowflake.createStatement({sqlText: insert_status_sp1,binds:[err.message]}).execute();
exec_sp1_status.next();
}
}
return 'Success';
$$;
CALL DIM_TABLES_REFRESH() ;
we can use THROW statement as shown below to stop and exit by reporting an error.
e.g. THROW ERROR;

How to read text (Definition) of a Stored Procedure in JDBC Code

Executing "SHOW PROCEDURE STORE_PROCEDURE_NAME" return full definition in SQL assistant but when we execute using JDBC it returns only a starting part of SP >> "REPLACE PROCEDURE DATABASENAME."
String getviewDDL = "SHOW PROCEDURE STORE_PROCEDURE_NAME";
try {
stmt = conn.createStatement();
rs = stmt.executeQuery(getviewDDL);
while (rs.next()) {
ddlString = rs.getString(1).trim();
}

How to get the ID of an inserted record in HANA back to SAPUI5 application?

I got an SAPUI5-application in which I create entries and save them via OData-service. That works, the code for the create operation can be found below. What I have to do now is, I need the ID of the inserted record in HANA back in my application. So what I did I implemented a success handler and thought I would get back this ID in the response from my OData-service. But that is not the case, I get back the same value I provided, in this case 0 since this just a dummy value for the OData-service. I did some research on how to tackle this problem, but none of the approaches worked. So I hope someone of you can help me out or got a hint how to do this. Below the code for create-operation, odata-service and the create.xsjs:
Create-operation in SAPUI5:
this.getOwnerComponent().getModel("Mitarbeiter").create("/ARB", oEntry, {
success: function(oData, response){
console.log(response);
}
});
OData-service:
service {
"MITARBEITERABTEILUNG"."ABTEILUNG" as "ABT" navigates ("Mitarbeiter" as "ARB");
"MITARBEITERABTEILUNG"."Mitarbeiter" as "ARB" create using "public.MitarbeiterAbteilung:mitarbeiterMethods.xsjslib::mitarbeiterCreate";
association "Mitarbeiter"
principal "ABT"("ID")
multiplicity "1"
dependent "ARB"("Abteilung")
multiplicity "*";
}
Create.xsjs:
function mitarbeiterCreate(param) {
let aAfterTableName = param.afterTableName;
var oEntry = {};
try {
var statement = param.connection.prepareStatement("SELECT * FROM\"" + aAfterTableName + "\"");
var rs = statement.executeQuery();
var statement2 = param.connection.prepareStatement('SELECT "MITARBEITERABTEILUNG"."MASEQUENCE".NEXTVAL from dummy');
var rs2 = statement2.executeQuery();
while (rs2.next()) {
oEntry.ID = rs2.getInteger(1);
}
statement2.close();
while (rs.next()) {
oEntry.Name = rs.getString(2);
oEntry.Adresse = rs.getString(3);
oEntry.bz = rs.getString(4);
oEntry.Abteilung = rs.getInteger(5);
}
statement = param.connection.prepareStatement('INSERT INTO "MITARBEITERABTEILUNG"."Mitarbeiter" VALUES (?,?,?,?,?)');
statement.setInteger(1, oEntry.ID);
statement.setString(2, oEntry.Name);
statement.setString(3, oEntry.Adresse);
statement.setString(4, oEntry.bz);
statement.setInteger(5, oEntry.Abteilung);
statement.execute();
statement.close();
} catch (e) {
statement.close();
}
}
Answered in the SAP Community here: https://answers.sap.com/questions/566957/how-to-get-the-id-of-an-inserted-record-in-hana-ba.html
The only thing you need to do, is to update the ID value in the "afterTableName" table provided by the function parameter. Something like that:
let statement = param.connection.prepareStatement('update "' + param.afterTableName + '" set ID = ' + oEntry.ID);
statement.executeUpdate();
Of course that needs to be done after you have determined your new ID. In case your column name is not "ID", please replace it with the real column name.

Incrementing Value of incoming value in Azure Table Insert

I am an iOS developer & currently working with Azure mobile services SDK in iOS.
In my case, I am providing each user as a uniqueid say 'myid' in Table say 'todomytable'. In todomytable.js file I am performing check for myid value. If coming value of 'myid' from device is less than stored value in table then I am increasing incoming value greater than earlier stored value in table by One. Below is my logic in todomytable.js
table.insert(function (context) {
context.item.userId = context.user.id;
//....
var intIncomingID = context.item.myid; //ID coming from mobile device
//Call back to get max value of 'myid' from Table
var myFunction = function( callback) {
var query = {
sql: 'select MAX(myid) from TodoItem'
};
context.data.execute(query).then(function (results) {
var objectTest = eval(JSON.stringify(results));
var tempObject = objectTest[0];
var previuosIntID = tempObject["MAX(myid)"];
callback(previuosIntID);
});
};
myFunction(function(returnValue) {
console.log("returnValue is : "+returnValue);
if (intIncomingID<=returnValue)
{
console.log('IF');
context.item.userId = context.user.id;
returnValue = returnValue+1;
context.item.myid = returnValue;
console.log("UPDATED value is : "+context.item.myid);
}
else{
context.item.myid = intIncomingID;
console.log("ITEM value is :"+intIncomingID);
}
return context.execute();
});
});
But issue is that table is not getting update & in mobile log I am getting network request time out error as below
{Error Domain=NSURLErrorDomain Code=-1001 "The request timed out."}
Can anyone suggest how to resolve this issue? I have to store 'myid' in incremented order in table. I am new to Node.js, so sorry If I am making any foolish mistake.
It is likely that there is an exception occurring at some point that causes a promise to reject. Given that there is no promise exception handler defined, the exception ends up being "swallowed". Try the following:
var table = module.exports = require('azure-mobile-apps').table()
table.insert(function (context) {
context.item.userId = context.user.id;
var intIncomingID = context.item.myid; //ID coming from mobile device
var query = { sql: 'select MAX(myid) from TodoItem' };
return context.data.execute(query)
.then(function (results) {
var tempObject = results[0];
var previousIntID = tempObject["MAX(myid)"];
console.log("previous ID is : " + previousIntID);
if (intIncomingID <= previousIntID) {
context.item.myid = previousIntID + 1;
console.log("UPDATED value is : " + context.item.myid);
} else {
context.item.myid = intIncomingID;
console.log("ITEM value is :" + intIncomingID);
}
return context.execute();
});
});
Some points to note:
context.data.execute returns a promise - we are returning this from the insert function so that the Mobile Apps runtime handles any rejected promises
context.execute also returns a promise; we are returning this so that the promises are "chained" properly
Hope this helps!

Resources