Snowflake Javascript Procedure Truncate Table not effective - javascript

I spent most of this week writing out some Javascript stored procedure in Snowflake to handle a few things. But I can't for the life of me figure out why Truncate Table doesn't work.
try {
var get_tables = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'SCHEMA' AND TABLE_CATALOG = 'DATABASE' ORDER BY TABLE_NAME DESC;"
var tableStmt = snowflake.createStatement( {sqlText: get_tables} );
var rs = tableStmt.execute();
while (rs.next()) {
var table = rs.getColumnValue(1);
var truncateTable = "TRUNCATE TABLE DATABASE.SCHEMA." + table
var truncateStmt = snowflake.createStatment( {sqlText: truncateTable} );
var truncateEx = truncateStmt.execute();
}
}
This pattern of creating queries is in their documentation and seems to work for every other query I've put together. But it fails for this one and I don't get a syntax error or anything. I've left out the catch and stuff because this is the only relevant part.
I have additionally tried
var truncateTable = "TRUNCATE TABLE DATABASE.SCHEMA." + table + ";"
I have tested this specific query against tables in a normal SQL query in Snowflake and confirmed that it works.
Am I missing something here?

this will work:
create or replace procedure util_db.public.truncate_table("table_name" varchar,"truncate" boolean)
returns string
language javascript
strict
execute as owner
as
$$
var sql_command = "Truncate table " + table_name ;
try {
if (truncate){
snowflake.execute (
{sqlText: sql_command}
);
return "Succeeded."; // Return a success/error indicator.
}
}
catch (err) {
throw(err);
// return "Failed: " + err; // Return a success/error indicator.
}
$$
;

Since you the SQL executes inside a try block, it won't display errors. Maybe you're handling that in a catch, but it's not shown.
If you comment out the try block, it should display the error when run. Maybe it's a permissions issue. Stored procedures can run with caller rights or owner rights. If the caller does not have the privilege to read from INFORMATION_SCHEMA or truncate the tables in the list, it will error out. You can call using owner's rights if that makes sense in the situation.
What happens when you run it like this?
//try {
var get_tables = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'SCHEMA' AND TABLE_CATALOG = 'DATABASE' ORDER BY TABLE_NAME DESC;"
var tableStmt = snowflake.createStatement( {sqlText: get_tables} );
var rs = tableStmt.execute();
while (rs.next()) {
var table = rs.getColumnValue(1);
var truncateTable = "TRUNCATE TABLE DATABASE.SCHEMA." + table
var truncateStmt = snowflake.createStatment( {sqlText: truncateTable} );
var truncateEx = truncateStmt.execute();
}
//}

Related

Snowflake only executes first SQL command in stored procedure

I was trying to create a procedure that copies the content of my table into S3 partitioned by 2 different combinations. For that I did the following:
$$
var cmd_partition1 = `...`
var cmd_partition2 = `...`
var store_data_partitioned_by_1_command = snowflake.createStatement({ sqlText: cmd_partition1 })
var store_data_partitioned_by_2_command = snowflake.createStatement({ sqlText: cmd_partition2 })
try {
store_data_partitioned_by_1_command.execute()
store_data_partitioned_by_2_command.execute()
return 'Succeeded.'
}
catch (err) {
return "Failed: " + err
}
$$;
However, each time I execute the procedure the partitioning is only performed for the 1st combination, while the 2nd one is ignored.
Do you know why this is happening and how can I solve it?
I tested each one of the cmd_partition (1 and 2) in the Snowflake GUI and both of them work as expected.
create table test_sp(id int);
-- test sql is good
insert into test_sp values (1);
insert into test_sp values (2);
-- clean up
truncate table test_sp;
create or replace procedure double_exec()
returns varchar
language javascript as
$$
var cmd_partition1 = `insert into test_sp values (1)`
var cmd_partition2 = `insert into test_sp values (2)`
var store_data_partitioned_by_1_command = snowflake.createStatement({ sqlText: cmd_partition1 })
var store_data_partitioned_by_2_command = snowflake.createStatement({ sqlText: cmd_partition2 })
try {
store_data_partitioned_by_1_command.execute()
store_data_partitioned_by_2_command.execute()
return 'Succeeded.'
}
catch (err) {
return "Failed: " + err
}
$$;
and now to run
call double_exec();
DOUBLE_EXEC
Succeeded.
so lets check the steps ran
select * from test_sp;
ID
1
2
so the concept of having to executions in a row is valid.
which makes it something about the SQL itself, and not the stored procedure.

How to pass sql query with . in name - Javascript/Node.JS - Alexa App

Good Day,
I am trying to have Alexa say the results of a SQOL query, but I receive an error every-time try to include owner.name in the output.
this.t("CASEINFO",resp.records[0]._fields.casenumber, resp.records[0]._fields.subject,resp.records[0]._fields.priority,resp.records[0]._fields.owner.name);
. I believe this is because it has a "." in the name, but I am not sure how to escape the period so it reads it correctly.
Note if I don't put "resp.records[0]._fields.owner.name" into the script, everything works without issue. I know, this is the reason for the error.
This what I have tried...
1) this.t("CASEINFO",resp.records[0]._fields.casenumber, resp.records[0]._fields.subject,resp.records[0]._fields.priority,resp.records[0]._fields.[owner.name]);
2) this.t("CASEINFO",resp.records[0]._fields.casenumber, resp.records[0]._fields.subject,resp.records[0]._fields.priority,resp.records[0]._fields.owner//.name);
3)putting into a var (var casenumber = owner.name) and then using casenumber in the query.
Any help would be appreciated.
'CaseInformation': function () {
console.log("CaseInformation function");
if (preFunctions.call(this)) {
//const OwnerName = getSlotValue(this.event.request.intent.slots.caseowner_name.value);
var CaseInfo = this.event.request.intent.slots.case_info.value;
console.log(`CaseInfo: ${CaseInfo}`);
const accessToken = this.event.session.user.accessToken;
sf.query("select casenumber,subject, owner.name, status, priority, account.name, lastmodifieddate from case where casenumber='" + CaseInfo + "'", accessToken, (err, resp) => {
if (resp.records!="") {
if (resp.records) {
const output = this.t("CASEINFO",resp.records[0]._fields.casenumber, resp.records[0]._fields.subject,resp.records[0]._fields.priority,resp.records[0]._fields.owner.name);
this.emit(":ask", output, this.t("PROMPT")); ```
Square bracket notation:
this.t("CASEINFO",resp.records[0]._fields.casenumber, resp.records[0]._fields.subject,resp.records[0]._fields.priority,resp.records[0]._fields["owner.name"]);

GlideAjax request doesn't return any response

I'm newer in servicenow developing.
I try to create a bundle "Script Include" - "Client Script".
Using background script I see, that my script include works fine.
But when I try to call this include via client script, it doesn't return any response.
Here is my method in Script Include:
usersCounter: function () {
var gr = new GlideRecord('sys_user');
gr.query();
var users = gr.getRowCount();
gs.info('Number of users'+ ' ' + users);
return users;
And here is my client script:
var ga = new GlideAjax('SCI_Training_ScriptIncludeOnChange');
ga.addParam('sysparm_name', 'usersCounter');
ga.getXML(getUsers);
function getUsers(response) {
var numberOfUsers = response.responseXML.documentElement.getAttribute("answer");
g_form.clearValue('description');
console.log(numberOfUsers);
And I have null in my console.
What have I missed?
Irrespective of why it's not working, you probably want to change your server side GlideRecord to use GlideAggregate instead, and just let mysql return the row count:
var gr = new GlideAggregate('sys_user');
gr.addAggregate('COUNT');
gr.query();
gr.next();
var users = gr.getAggregate('COUNT');
gs.info('Number of users'+ ' ' + users);
return users;
Doing a GlideRecord#query with no where clause is essentially doing a "SELECT * FROM sys_user", bringing over all the data, when all you're asking for is the row count from the metadata in the result set.
Beyond that, make sure your Script Include properly extends AbstractAjaxProcessor and has the client-callable field set to true per this:
https://docs.servicenow.com/bundle/geneva-servicenow-platform/page/script/server_scripting/reference/r_ExamplesOfAsynchronousGlideAjax.html
You can try to debug your getUsers() method. Try to check what the object structure of response is.
You could also use
var ga = new GlideAjax('SCI_Training_ScriptIncludeOnChange');
ga.addParam('sysparm_name', 'usersCounter');
ga.getXMLAnswer(getUsers);
function getUsers(response) {
var numberOfUsers = response;
g_form.clearValue('description');
console.log(numberOfUsers);
}

Node js mysql syntax error

I write some code in the server-side, in node js for update MySQL database.
this is my code:
exports.addPlayerToMatch = function(uid,matchId){
return new Promise(function(resolve,reject){
dbFunctions.getPlayerUids(matchId).then(function(rows){
playerUids = JSON.parse(rows[0].uids_of_players);
playerUids.push(uid);
console.log("new player uids: " +playerUids);
numberOfPlayers = playerUids.length;
db.query('UPDATE current_matches SET number_of_players = ?,
uids_of_players = ? WHERE id = ?' ,[numberOfPlayers,playerUids,matchId],
function (err, rows) {
if (err){ console.log("ErrorForAddPlayerToMatch: "+err);}
});
resolve(numberOfPlayers);
});
});
};
and this is the error:
ErrorForAddPlayerToMatch: Error: ER_PARSE_ERROR: You have an error in your
SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''3d8b7210fc1999bf191b0e1f7d744269' WHERE id = 29' at line 1
I have no idea !!
help, please.
The Problem was that I forgot to turn an array into a JSON object again before using it in the query.
it will solve with something like this:
var playerUids = JSON.stringify(playerUids);
and then use it in the query.

calling javascript on document.ready

My jquery will not run my java script function on document ready.
cont += "<script>";
cont += "$(document).ready(function() {Puma.getReasonForBTI()});";
cont += "</script>";
JS function
Puma.getReasonForBTI = function() {
var reason = document.getElementById("reasonId").value;
var msql = "SELECT Pid FROM tPid WHERE Reason = 'reason'";
sql = "action=getReasonForBTI&sql=" + encodeURIComponent(msql);
objAjaxAd.main_flag = "getReasonForBTI";
objAjaxAd.SendQuery(sql);
}
Any help would be appreciated.
Why not just add the DocReady to your JS?
Puma.getReasonForBTI = function() {
var reason = document.getElementById("reasonId").value;
var msql = "SELECT Pid FROM tPid WHERE Reason = 'reason'";
sql = "action=getReasonForBTI&sql=" + encodeURIComponent(msql);
objAjaxAd.main_flag = "getReasonForBTI";
objAjaxAd.SendQuery(sql);
}
$(document).ready(function() {
Puma.getReasonForBTI()
});
EDIT:
Also, I would send reason by itself and Sanitize it server side, then put it into a query. Sending a SQL query over Javascript/AJAX is just asking for trouble.
Faux-Code:
sql("
SELECT Pid
FROM tPid
WHERE Reason = ?
", $ajax.reason)
DOUBLE EDIT
Also, putting reason in single quotes in a string does not evaluate the value of reason. Just figured I'd save you some future headache
var foo = "bar";
console.log("The value of foo is 'foo'");
=> "The value of foo is 'foo'"
console.log("The value of foo is " + foo);
=> "The value of foo is bar"
Try a chrome browser and the Development tools (F12).
Take a look at the errorconsole.
Fix the error
Change your Code, because Someone can use YOUR code to delete any data from the underlying database
update
var reason = document.getElementById("reasonId").value;
// reason is entered directly byy a user (or Mr. EvilHacker).
var msql = "SELECT Pid FROM tPid WHERE Reason = 'reason'";
// Here you create a SQL, which may sounds like this:
SELECT Pid FROM tPid WHERE Reason = ''; DROP table tPid;--'
if the evil hacker entered ';DROP table tPid;-- into the textbox. Look at owasp.org for further information

Categories

Resources