Snowflake UDF behaves differently while using "LIMIT" - javascript

I have created a UDF that evaluates rows. It works fine in most cases, but sometimes it acts weird. See example below. These are exactly the same query. One with "Limit" and the other without. The total record count here is 32 but I add Limit 1000 just for the example. Would you know why the these two queries behave differently?
Without Limit - Wrong Output
With Limit - Correct Output - Again total records is 32.

The function code:
create or replace function new_row_evaluator
(b varchar, m datetime, f DATETIME, t datetime )
returns string
language javascript
as '
if (typeof tmp_barcode === "undefined") {
tmp_barcode = B;
tmp_fromdate = F;
tmp_todate = T;
return "1";
}
if (tmp_barcode == B) {
if (M >= tmp_fromdate && M <= tmp_todate) {
return "0";
} else {
tmp_fromdate = F;
tmp_todate = T;
return "1";
}
} else {
tmp_barcode = B;
tmp_fromdate = F;
tmp_todate = T;
return "1";
} ';
I assume that the UDF is using some sort of global state tmp_barcode.
Global state
Snowflake usually preserves the JavaScript global state between iterations of a UDF. However, you should not rely on previous modifications to the global state being available between function calls. Additionally, you should not assume that all rows will execute within the same JavaScript environment.
a recommended pattern is to guarantee that relevant code is evaluated only once, using JavaScript’s global variable semantics. For example:
var setup = function() {
/* SETUP LOGIC */
};
if (typeof(setup_done) === "undefined") {
setup();
setup_done = true; // setting global variable to true
}
Note that this mechanism is only safe for caching the effects of code evaluation. It is not guaranteed that after an initialization the global context will be preserved for all rows, and no business logic should depend on it.

Related

Assigning String to Variable with If Else Statements

sorry this is a super basic question, but I'm not too familiar with google script yet so finding answers to these simple tasks is proving to be difficult. In this code, I'm trying to set a string of numbers to a variable based on another variable. AppNaming is the variable I'm trying to assign the numbers to. AppType is already defined earlier in the code, and depending on the type, I need it to take only part of the variable AppNumber. Depending on the AppType, the AppNumber is separated by commas or slashes, hence the indexOf parts. Are if statements not allowed with var functions? I need the var AppNaming to change based on the AppType in order to name a file later on in the code. Thanks for all the help and sorry again if these questions are annoying; I'm still learning.
function AutoFill(e) {
// variables all defined earlier
//Naming code
var AppNaming = if( AppType == '1' ){
AppNumber.substring( 0, AppNumber.indexOf(","))
}
else if ( AppType == '2'){
AppNumber.substring( 0, AppNumber.indexOf("/"))
}
else ( AppType == '3'){
AppNumber.substring( 0, AppNumber.indexOf(","))
}
You can only assign values to variables. Unfortunately, if statements are not values so you can't say var a = if (...) { } but you can say var a = 3
An if statement controls the flow of the application.
var something = 20;
var a;
if (something > 20) {
a = "this block runs if something is greater than 20";
} else if (something < 20) {
a = "this block runs if something is less than 20";
} else {
a = "this block runs otherwise";
}
// The value of 'a' is 'this block runs otherwise' at this point
So in your example, you can assign App.Number.substring(0, AppNumber.indexOf(",") to a variable because that expression will return a value.
I would recommend you to learn the basics of JavaScript.

Recursive array with a push

Can someone show me where I am going wrong within this Code Academy problem. I'm having a world of trouble with Recursion and am only vaguely beginning to understand how it works at a fundamental level... The first set of code is what I have written followed by the same code with the blanks I have tried to fill in.
Fill in the blanks: Write a conditional statement for the base case of multiplyEach(). We want to end the recursion when there are no more values in stack. Then we want to return the variable int, since this represents the last value evaluated. Complete the recursive case with a recursive call to the function, without any arguments.
Blank Problem with fill-in-the-blanks (___):
var stack = [];
function countDown(int) {
stack.push(int);
if (int === 1) {
return 1;
}
return countDown(int - 1);
}
function multiplyEach() {
// Remove the last value of the stack
// and assign it to the variable int
int = stack.pop();
x = stack.length;
// Base case
if (___) {
return ___;
}
// Recursive case
else {
stack[x - 1] = int * stack[x - 1];
return ___;
}
}
// Call the function countDown(7)
countDown(7);
// And then print out the value returned by multiplyEach()
console.log(multiplyEach());
This is my Try:
var stack = [];
function countDown(int) {
stack.push(int);
if (int === 1) {
return 1;
}
return countDown(int - 1);
}
function multiplyEach() {
// Remove the last value of the stack
// and assign it to the variable int
int = stack.pop(int);
x = stack.length;
// Base case
if (x === 0) {
return int;
}
// Recursive case
else {
stack[x - 1] = int * stack[x - 1];
return multiplyEach(stack);
}
}
// Call the function countDown(7)
countDown(7);
// And then print out the value returned by multiplyEach()
console.log(multiplyEach());
Thanks!
You filled in the blanks correctly!
There is just one bug you introduced in a part of the code you did not have to touch:
Replace:
int = stack.pop(int);
with:
var int = stack.pop();
Because pop returns the value you need. There is no need to pass anything.
Also, you passed the stack argument to a function that does not take that argument (the variable is global). This does no harm, but to avoid confusion, it is better to call the function without arguments, as it is supposed to be:
return multiplyEach();
Some side-comments on the code you have been provided with:
it is bad practice to name a variable int as it might become a reserved word in future versions of JavaScript;
That same variable should better be declared locally to the function, as now it is created in the global scope. So with var: var int = ...

Eloquent Javascript 2nd. Chapter 4. Computing Correlation. Final Analysis - [Variable Recursion & in operator] Pt 2

I'm working through the end of the first example in Chapter 4 Eloquent Javascript. Here is the full piece of code (It's the last piece that I have questions regarding but I attached the first portion for reference).
var journal = [];
function addEntry(events, didITurnIntoASquirrel) {
journal.push({
events: events,
squirrel: didITurnIntoASquirrel
});
function phi(table) {
return (table[3] * table[0] - table[2] * table[1]) /
Math.sqrt((table[2] + table[3]) *
(table[0] + table[1]) *
(table[1] + table[3]) *
(table[0] + table[2]));
}
function hasEvent(event, entry) {
return entry.events.indexOf(event) != -1;
}
function tableFor(event, journal) {
var table = [0, 0, 0, 0];
for (var i = 0; i < journal.length; i++) {
var entry = journal[i], index = 0;
if (hasEvent(event, entry)) index += 1;
if (entry.squirrel) index += 2;
table[index] += 1;
}
return table;
}
function gatherCorrelations(journal) {
var phis = {};
for (var entry = 0; entry < journal.length; entry++) {
var events = journal[entry].events;
for (var i = 0; i < events.length; i++) {
var event = events[i];
if (!(event in phis))
phis[event] = phi(tableFor(event, journal));
}
}
return phis;
}
var correlations = gatherCorrelations(JOURNAL);
console.log(correlations.pizza);
My questions are:
What is the purpose of the .events in
var events = journal[entry].events;
Does it call on itself as a recursion? If so why? Couldn't we have just had journal[entry] and the function would run calling on the entry from the tableFor function? Does it call back to the AddEntry function (where the events variable was established) in an important way?
What is the purpose of (!(event in phis)).
I read it as : if event in phis is true then flip it to be not true and then trigger necessary phi calculation. Wouldn't it make more sense to eliminate the ! (does not equal) or that piece of code altogether? If we already have a for loop won't the function run on it's on until the max length of journal and stop?
var events = journal[entry].events; you are getting the events object from the object at index entry in the array journal and assigning it to a temporary variable called events.
This is just done for convenience so you don't have to keep referring to journal[entry].events. For example, later on it has this line:
var event = events[i];
which would become:
var event = journal[entry].events[i];
Without the assignment to a temporary variable.
if(!(event in phis)) it's testing to see if the object phis does not have a property with the name contained in the variable event. If the object doesn't already have that property, it adds it with the next line:
phis[event] = phi(tableFor(event, journal));
See in operator
Here's a very simple snippet of code to help understand the in operator:
var foo = {};
console.log("bar" in foo); // logs "false" because foo doesn't have a "bar" property
foo.bar = 1; // or foo["bar"] = 1;
console.log("bar" in foo); // logs "true" because foo now has a "bar" property
What is the purpose of the .events in
var events = journal[entry].events;
The purpose of this declaration conforms with 2 concepts of scripting convenience and economy. Every level of an object depth adds to the overall recall time when called. Certainly modern browsers have done much to flatten an objects variable stack, but if you think about it logically, any call to say object1.object2["Memeber3"].object4 has to go through 4 steps to get to the value itself. Flattening the value to a local object is more economic. Second, the readability (and therefore maintainability) of the code is enhanced in that you don't have the extra "journal[entry]." clogging up your expressions. As a general rule of thumb, if you are going to use a member of an object more than once in a block, then you should create a local variable of that member.
What is the purpose of
(!(event in phis)).
The purpose of this evaluation is to determine if a particular member(event) is NOT in the object(phis). In this example, the next line creates that member if it is indeed missing.

Refactor this Lisp and Haskell style macro in JavaScript

Consider this Lisp macro:
(defmacro doif (x y) `(if ,x ,y))
The same in Haskell:
doif x y = if x then (Just y) else Nothing
Is it possible to achieve this elegance in the "lisp-y" language of JavaScript? (the use of the word "lisp-y" comes from the author of the JS language)
Yes, it is possible. If you simply want to a one-to-one mapping of the lisp-y code then you could use the conditional operator as follows:
x ? y : null // note that x and y are expressions, not values: they aren't eval'd
If you don't mind the result of the expression being a falsy value (instead of an explicit null value) then you could use the guard operator instead:
x && y // reminder: x and y are expressions - they aren't evaluated until needed
If you want to create your own doif syntax then you can use hygienic macros provided by sweet.js as follows:
macro doif {
rule { ($x:expr) ($y:expr) } => { $x ? $y : null }
}
The above macro allows you to write code like this:
doif (x < 100) (x + 1)
The above code gets converted to:
x < 100 ? x + 1 : null
When using either of these operators if the condition x is falsy then y is not evaluated.
You can implements macros in Javascript because the compiler is part of the runtime (you can eval a string and get back code). However to get close to Lisp you need to implement your own full language because eval can only produce full functions, not expressions.
If instead you're just thinking about delayed evaluation this can be done trivially by wrapping the code in a closure:
function my_if(condition, then_part, else_part) {
return condition ? then_part() : else_part();
}
my_if(foo < bar,
function(){ return bar -= foo; },
function(){ return foo -= bar; });
You can of course also create a closure that will encapsulate the whole operation by delaying also the test...
function my_if(condition, then_part, else_part) {
return function() {
return condition() ? then_part() : else_part();
}
}
var my_prog = my_if(function(){ return foo < bar; },
function(){ return bar -= foo; },
function(){ return foo -= bar; });
my_prog(); // executes the code
I suppose the usual way to emulate laziness in a non-lazy language is to manually thunkify. I don't know Javascript very well, so I'm going to write pseudocode instead and hope that you can paint Javascript syntax on the idea.
function doif(x, y) {
if(x) { return y(); }
else { return undefined; }
}
And a sample call:
function expensive() {
// do a lot of work here
}
doif(false, expensive); // runs very fast
doif(true , expensive); // runs very slow
doif(true , expensive); // runs very slow (unlike Haskell, but I think like Lisp)

keep add the value without overwrite the function

function checkData() {
var temp = 0;
var totalMarks = countMark(temp);
if (totalMarks != 100)
window.alert("Marks must total 100");
}
function countMark(mark) {
var totalMark = 0;
totalMark += parseInt(mark)
return totalMark;
}
function doAdd() {
var taskid = document.getElementById("taskid").value;
var taskname = document.getElementById("taskname").value;
var taskmark = document.getElementById("taskmark").value;
if (taskid.length === 0)
window.alert("Task Id cannot be empty!");
if (taskname.length === 0)
window.alert("Task name cannot be empty!");
if (taskmark.length === 0)
window.alert("Task Mark cannot be empty!");
else if (!markpattern.test(taskmark))
window.alert("Invalid data in mark field");
var marks = parseInt(document.getElementById("taskmark"));
if (marks < 0 || marks > 100)
window.alert("Marks out of range. Please re-enter");
countMark(marks);
}
My question is when i keep call the doAdd() function. my marks will keep adding . want to do like passing reference like in C++ . my function countMark(...) will keep adding .
after that, when my form submitted, my form will call the function checkData()
If my totalmark is not 100 . will prompt out the alert and error.
but my code is not working . I guess that my countMark function wrong somewhere
If I understand you correctly, you're looking for the equivalent of a static variable - something that gets initialized the first time the function is called, and keeps it's value for subsequent calls.
Take a look at this related question: https://stackoverflow.com/a/1535650/2444111
The top answer (by CMS) is talking about class-based static variables, which are not quite the same thing.
The second answer (by Pascal MARTIN) is what you're looking for. It takes advantage of the fact that JS functions are also objects, and stores the variable as a property of the function object. This is a better solution than using a global variable (or a property of window, which is what a global actually is)
There are several issues in your code and it's really hard to say what your intention was. But I will address what I found.
In the following piece of code you are requesting a DOM Element and try to parse it as an Integer. The result of that type convertion is always NaN. Maybe wanted to get the value attribute of your element, like you did before. (Also, don't request the same element multiple times. Request it once, save the result in a variable and use that variable from that on).
var marks = parseInt(document.getElementById("taskmark"));
if (marks < 0 || marks > 100)
window.alert("Marks out of range. Please re-enter");
countMark(marks);
Your function countMark is pretty useless, because it will always return whatever Number you pass to it (see comments in your code).
function countMark(mark) {
var totalMark = 0; //create a new variable with value 0
totalMark += parseInt(mark) //add "mark" to that variable
return totalMark; //return that variable => 0 + mark = mark (and if mark = NaN => 0 + mark = NaN)
}
Maybe you wanted to make totalMark a global variable, than you would need to define it outside of your function:
var totalMark = 0;
function countMark(mark) {
totalMark += parseInt(mark);
return totalMark;
}
Last but not least, lets analyse your function checkData:
function checkData() {
var temp = 0; //create a local variable with value 0
var totalMarks = countMark(temp); //pass 0 to countMark => return 0 => totalMarks = 0
if (totalMarks != 100) //always true since totalMarks is always 0
window.alert("Marks must total 100"); //will always alert
}

Categories

Resources