Referencing column in Snowflake JS UDF - sql

I created a JS UDF in Snowflake that has two inputs: a string from a column, and then another string that I use to create a mapping object.
Here's the function:
CREATE OR REPLACE FUNCTION function(supplier_name varchar, supplier_replace varchar)
RETURNS string
LANGUAGE JAVASCRIPT
AS
$$
regex_string = SUPPLIER_REPLACE.replace(/\b:\b/g, '":"').toLowerCase();
regex_final = '{"' + regex_string.replace(/\s*,\s*/g, '","') + '"}'
obj = JSON.parse(regex_final);
var supplier = SUPPLIER_NAME.toLowerCase();
for (var key in obj) {
if (supplier.includes(key)) {
var new_supplier = obj[key]
}
}
return new_supplier;
$$;
When I call the function in a SQL statement
select parent_supplier
, function(parent_supplier, 'Fedex:Fedex')
from table
I get the following error: "JavaScript execution error: Uncaught TypeError: Cannot read properties of undefined (reading 'toLowerCase') in TEST at ' const supplier = SUPPLIER_NAME.toLowerCase();' position 35 stackstrace: TEST line: 7".
I know this error is because I'm using a column as one of my input variables, but I can't figure out how to properly call it.
I'd appreciate any help!
Function works testing with a string as the input variable.

The error message claims the error is on a line reading this:
const supplier = SUPPLIER_NAME.toLowerCase();
However, there is no line like that in the UDF code in the question. Instead, the line closest to that line is this one:
var supplier = SUPPLIER_NAME.toLowerCase();
Since the line with the const does not appear in the UDF, this means it must be calling a different version of the UDF. There are a couple of common reasons why this happens. UDFs are owned by a directory and schema, and unless they're explicitly called using a three-part identifier (db_name.schema_name.udf_name), Snowflake will use the current schema in context and use that schema's UDF if there is one with that name and signature. The other reason is that Snowflake supports overloaded UDFs. That means that multiple versions of the same UDF name can exist provided they have different numbers of input parameters or different types of input parameters.
You can check to make sure the SQL is calling the right version of the UDF by placing something like return "foo" or some other recognizable return on the first line of the UDF temporarily. If calling it does not return that message (assuming there are no compilation errors) then it's running another version of the UDF.

Related

var error = new Error(message); Why am I getting this message in the terminal?

Everything works effectively until I add the const amountOut to the file.
Code with Error & location of function that breaks code
You are passing 2 parameters into a function that is expecting 3. The second parameter is one value because you have it as an array in brackets - [AddressFrom, AddressTo].
You will need to either modify how you are passing in the parameters to the getAmountsOut function or modify the getAmountsOut function to accept 2 parameters, with one being an array.

ERROR [37000] [IBM][CLI Driver] CLI0118E Invalid SQL syntax. SQLSTATE=37000

I have a simple SQL statement query that is executed as command from C# code. It is targetting DB2. I created variables for the server/schemas as follows. It throws error.
private const string DB2Query
= #"SELECT Name as Name FROM {Schema}.Application WHERE ID = ?";
I get this error.
ERROR [37000] [IBM][CLI Driver] CLI0118E Invalid SQL syntax. SQLSTATE=37000
However, I don't get that error when executing from SQL as follows:
SELECT Name as Name
FROM MyServer..FOR3.Application
WHERE ID = 'MOM'
To support this, I tried to also do something like below in code, still throws different error.
private const string DB2Query
= #"SELECT Name as Name FROM {ServerName}..{Schema}.Application WHERE ID = ?";
It throws error on this line of code:
DataApplicationBlockHelper<string>.Get(db, dbCommand, Obj);
UPDATE
I found the culprit. It's not replacing the {Schema} placeholder. When I actually removed that from query and placed the schema name, it worked like a charm. It's a .net thing I believe? Can someone please help how to replace {Schema} with a value fetched from web.config?
While I can't really speak to the syntax of DB2 queries themselves, so I'll rely on your assertion that the query itself should work...
What you have in C# is simply a string and nothing more:
private const string DB2Query = #"SELECT Name as Name FROM {Schema}.Application WHERE ID = ?";
Note that there's no need for the # operator in this string definition, so let's simplify:
private const string DB2Query = "SELECT Name as Name FROM {Schema}.Application WHERE ID = ?";
While this string appears intuitively to have a placeholder that can be replaced with a value, if there's no code which does that anywhere then it won't happen. For that you have a few options. For example, you can use a placeholder that string.Format() understands:
private const string DB2Query = "SELECT Name as Name FROM {0}.Application WHERE ID = ?";
And then later in a method somewhere, when you want to use that string, apply the format value to it:
var sql = string.Format(DB2Query, someVariable);
In this case someVariable (which doesn't even need to be a variable and could be a string literal) would be used to replace the placeholder in the string.
Or, if you want to keep the named placeholder, you can potentially replace it manually:
private const string DB2Query = "SELECT Name as Name FROM {Schema}.Application WHERE ID = ?";
and later in a method:
var sql = DB2Query.Replace("{Schema}", someVariable);
This would observably accomplish the same thing, perhaps with an extremely minor performance difference.
You could also take advantage of both approaches by using the more recent language feature of string interpolation. This would use the $ operator to apply format placeholders in place directly. I don't think you can use this in a const, it's more for a local variable. Something like this:
var sql = $"SELECT Name as Name FROM {someVariable}.Application WHERE ID = ?";
This would still perform the same replacement, putting someVariable where the placeholder is, it's just using a more concise syntax than a call to string.Format(). One thing to note about this syntax is that it makes it look more like this interpolation is happening directly in-place on the string. It's still a multi-step process behind the scenes, which is why it likely won't work on a const or on class members at all (and should I imagine produce a compiler error).
Remember that strings are immutable, so any operation you perform which modifies a string would be returning a new string rather than modifying the existing one in place.
In any case, you'll of course also need to apply your query parameter for the ? placeholder. Note that what C# considers to be a placeholder in a string formatting/interpolating operation and what DB2 considers to be a placeholder for a query parameter are two entirely different things which happen at different times in different environments. (One in the .NET runtime, one in the database server's query execution.) But again, I'm relying on your assertion that the database query itself works and the only problem we're focusing on here is the C# string placeholder.

Trying to deserialize and serialize a table in lua using the serpent library

So I am trying to do a simple serialization of a lua table, and deserialize it back into a table. But for some reason it just fails.
local a = {}
a[0] = {name="presetA"}
local line = serpent.line(a)
local presets, err = loadstring(line)
if (err) then
log("Error")
log(err)
else
log("Success")
log(serpent.block(presets))
end
After running, log(err) shows
[string "{[0] = {name = "presetA"}}"]:1: unexpected symbol near '{'
loadstring loads a Lua chunk from the given string and runs it.
As your serialized table is not a valid Lua expression the interpreter reports the observed error.
Let's serialze an example:
serpent.line({key = "value"})
returns
"{key = "value"} --[[table: 0D80CF40]]"
A table constructor on it's own is not a valid Lua expression.
Try to run that line and you'll Lua will report:
input:1: unexpected symbol near '{'
The output of serpent.line cannot be used as input to loadstring.
Now see the difference if you use serpent.dump instead
"do local _={name="hallo"};return _;end"
This is a valid, executable Lua chunk that will return the serialized table.
Please note the following section from the serpent documentation:
Note that line and block functions return pretty-printed data
structures and if you want to deserialize them, you need to add return
before running them through loadstring. For example:
loadstring('return '..require('mobdebug').line("foo"))() == "foo".
While you can use loadstring or load functions to load serialized
fragments, Serpent also provides load function that adds safety checks
and reports an error if there is any executable code in the fragment...
Please read manuals.

PostgreSQL create type PL/pgSQL and cstring

I wanna format some fields in the output of my PostgreSQL 9.1 database. I thought of creating a type, so I could do the formatting in the output function, and checking for inconsistencies in the input function. I decided to use the procedural language PL/pgSQL. But I'm getting some errors:
CREATE OR REPLACE FUNCTION "CPF_in"(cstring)
"PL/pgSQL functions cannot accept type cstring"
(But that's how it is in the manual.) I can put "character varying" instead of cstring, or even leave the () empty. But when I'm going to create the desired type:
CREATE TYPE Tcpf (
INPUT = CPF_in(character varying),
OUTPUT = CPF_out
);
I got an error:
ERROR: syntax error at or near ")"
LINE 2: INPUT = CPF_in(character varying),
and if I try
CREATE TYPE Tcpf (
INPUT = CPF_in(),
OUTPUT = CPF_out
);
I get
ERROR: syntax error at or near ")"
LINE 2: INPUT = CPF_in(),
How is this supposed to be done? The manual only say cstring...
The cstring pseudo-type is used for programming in a low-level language like C, not in PL/pgSQL. You have to use a low-level language like C if you're creating a new base type.
You must register two or more functions (using CREATE FUNCTION) before
defining the type. The support functions input_function and
output_function are required . . . .
Generally these functions have to be coded in C or another low-level
language.
A simpler way to control the output format is to use a view. If your formatting is complex, write a function, and call that function from a view. You can revoke permissions on the base table if you need to force every client to use your formatting. You might need to create triggers to make your view fully updatable.
For controlling input, you can use a function. (CREATE FUNCTION...) You can write functions in PL/pgSQL. Again, consider revoking permissions on the table.

Call stored function without knowing the parameter names through vb.net

Can some one suggest me how to call a stored function in oracle through vb.net.
From vb.net should i able to pass the values to arguments of that function without knowing the parameter names?
Example: I have a function,
Create or Repalce Function Func_Name(param1 Varchar2,param2 varchar2)
Inorder to call this function through vb.net, we need to give
parameterargs.paramtername="param1"
Is there anyway so that i cannot use the parameter name and call the function
Thanks in advance
Rupesh
The way that we handled it was to open the Oracle DB up through an OleDbConnection, then call GetOleDbSchemaTable asking for the Procedure_Columns.
For example:
DataTable dtTable;
dtData = this.Connection.GetOleDbSchemaTable(OleDbSchemaGuid.Procedure_Columns, new object[] {null, null, sName, null});
foreach (DataRow theRow in dtData.Rows)
{
// Columns available in the row include:
// column_name, data_type, type_name, precision, and scale
}
Then, if you need to execute it without valid parameters (for example, to get the columns it exposes) you could execute it using DbNull.Value for each parameter.
Also, I can't remember exactly how Oracle operates, but in SQL Server you need to include the namespace when executing the function (i.e. select * from dbo.fn_my_test()). Also, depending on how the function is structured, you may have to select from it instead of executing it.
I'm not sure if you can use named parameters with Oracle.
When you create the parameterized query, try using question marks as a place holder:
Select col1, col2 From tablename Where col1 = ? and col2 = ?
Then, be sure to add the parameters to the command object in the correct order.
You don't need to know the parameter names to call it.
You need to know the number and type of them
Adding parameter names to the call means you don't have to pass all of them and / or you can pass them in a different order to the signature of the SP.
Call it like a parameterised query.
PSEUDOCODE
int customer_ID = 786;
Command.CommandText = 'Exec SP_MYProc #MyVar';
Command.Parameters.Add(new Parameter('MyVar',DbType.Int,customer_ID));
Command.Exec