PostgreSQL create type PL/pgSQL and cstring - sql

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.

Related

Referencing column in Snowflake JS UDF

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.

SQL: Agregate function for user defined type

I have user defined type:
create type indeks as integer
And question for my exam says: "Define aggregate function max for type indeks"
create function max(indeks)
returns indeks
source sysibm.max(integer);
Can you help me understand this? Because I know this is some elementary stuff.
create function max(indeks)
returns indeks
These two lines are OK, I'm creating function and return type is also indeks.
source sysibm.max(integer);
But this is what I don't understand. I have no idea what is this line for.
Thanks in advance.
The schema name SYSIBM is used for built-in data types and built-in functions. The function source from the SYSIBM.MAX catalog table is merged into the statement.
The built-in functions cannot simply
be applied to User Defined Types. If they are
required, then UDFs-based on the desired built-in functions must be generated. It means that you need to put this statement there
source sysibm.max(integer);

How to declare variables with a type in Lua

Is it possible to create variables to be a specific type in Lua?
E.g. int x = 4
If this is not possible, is there at least some way to have a fake "type" shown before the variable so that anyone reading the code will know what type the variable is supposed to be?
E.g. function addInt(int x=4, int y=5), but x/y could still be any type of variable? I find it much easier to type the variable's type before it rather than putting a comment at above the function to let any readers know what type of variable it is supposed to be.
The sole reason I'm asking isn't to limit the variable to a specific data type, but simply to have the ability to put a data type before the variable, whether it does anything or not, to let the reader know what type of variable that it is supposed to be without getting an error.
You can do this using comments:
local x = 4 -- int
function addInt(x --[[int]],
y --[[int]] )
You can make the syntax a = int(5) from your other comment work using the following:
function int(a) return a end
function string(a) return a end
function dictionary(a) return a end
a = int(5)
b = string "hello, world!"
c = dictionary({foo = "hey"})
Still, this doesn't really offer any benefits over a comment.
The only way I can think of to do this, would be by creating a custom type in C.
Lua Integer type
No. But I understand your goal is to improve understanding when reading and writing functions calls.
Stating the expected data type of parameters adds only a little in terms of giving a specification for the function. Also, some function parameters are polymorphic, accepting a specific value, or a function or table from which to obtain the value for a context in which the function operates. See string.gsub, for example.
When reading a function call, the only thing known at the call site is the name of the variable or field whose value is being invoked as a function (sometimes read as the "name" of the function) and the expressions being passed as actual parameters. It is sometimes helpful to refactor parameter expressions into named local variables to add to the readability.
When writing a function call, the name of the function is key. The names of the formal parameters are also helpful. But still, names (like types) do not comprise much of a specification. The most help comes from embedded structured documentation used in conjunction with an IDE that infers the context of a name and performs content assistance and presentations of available documentation.
luadoc is one such a system of documentation. You can write luadoc for function you declare.
Eclipse Koneki LDT is one such an IDE. Due to the dynamic nature of Lua, it is a difficult problem so LDT is not always as helpful as one would like. (To be clear, LDT does not use luadoc; It evolved its own embedded documentation system.)

DB2 SQL array in attribute-defs of user defined type

I have a question concerning user defined types in DB2(v. 9.7.0.441). I want to create a type which has an attribute-array of another user defined type. Let me show you what I mean by a brief (fictional) example:
This is the UDT I want to use in another type
CREATE TYPE sport AS
(
Sport VARCHAR(10)
) MODE DB2SQL;
This is the UDT which should use the one above
CREATE TYPE person AS
(
plays sport ARRAY[3] // 'REF(sport)' or 'plays VARCHAR(10) ARRAY[3]' don't work either
) MODE DB2SQL;
DB2 just says that the token ARRAY[3] is unexpected.
Any hint what could be wrong here? By now it would be enough to have an CHAR Array in a UDT...
Thanks in advance
Ok ok,
according to db2's CREATE TYPE (array) statement "an array type can only be used as the data type of:
A local variable in a compound SQL (compiled) statement
A parameter of an SQL routine
A parameter of a Java procedure (ordinary arrays only)
The returns type of an SQL function
A global variable
and
A variable or parameter defined with an array type can only be used in compound SQL (compiled) statements
"
So its just not possible to use an array type inside a user defined type :-/
I would assume something like the following...
CREATE TYPE sport AS(Sport VARCHAR(10)) MODE DB2SQL;
CREATE TYPE PersonT AS(plays SportT ARRAY[3]) MODE DB2SQL;
CREATE TYPE SportArrayT AS SportT ARRAY[3];
CREATE TYPE PersonT AS (plays SportT SportArrayT) MODE DB2SQL;
However, the 3rd statement fails. Obviously an array of a user-defined type (or REF(SportT)) is not allowed :-(
Have a look at the doc for CREATE TYPE (array).
I'm not really sure what you're trying to do but the examples they give are like this:
CREATE TYPE CAPITALSARRAY AS VARCHAR(30) ARRAY[VARCHAR(20)]

Lambdas with captured variables

Consider the following line of code:
private void DoThis() {
int i = 5;
var repo = new ReportsRepository<RptCriteriaHint>();
// This does NOT work
var query1 = repo.Find(x => x.CriteriaTypeID == i).ToList<RptCriteriaHint>();
// This DOES work
var query1 = repo.Find(x => x.CriteriaTypeID == 5).ToList<RptCriteriaHint>();
}
So when I hardwire an actual number into the lambda function, it works fine. When I use a captured variable into the expression it comes back with the following error:
No mapping exists from object type
ReportBuilder.Reporter+<>c__DisplayClass0
to a known managed provider native
type.
Why? How can I fix it?
Technically, the correct way to fix this is for the framework that is accepting the expression tree from your lambda to evaluate the i reference; in other words, it's a LINQ framework limitation for some specific framework. What it is currently trying to do is interpret the i as a member access on some type known to it (the provider) from the database. Because of the way lambda variable capture works, the i local variable is actually a field on a hidden class, the one with the funny name, that the provider doesn't recognize.
So, it's a framework problem.
If you really must get by, you could construct the expression manually, like this:
ParameterExpression x = Expression.Parameter(typeof(RptCriteriaHint), "x");
var query = repo.Find(
Expression.Lambda<Func<RptCriteriaHint,bool>>(
Expression.Equal(
Expression.MakeMemberAccess(
x,
typeof(RptCriteriaHint).GetProperty("CriteriaTypeID")),
Expression.Constant(i)),
x)).ToList();
... but that's just masochism.
Your comment on this entry prompts me to explain further.
Lambdas are convertible into one of two types: a delegate with the correct signature, or an Expression<TDelegate> of the correct signature. LINQ to external databases (as opposed to any kind of in-memory query) works using the second kind of conversion.
The compiler converts lambda expressions into expression trees, roughly speaking, by:
The syntax tree is parsed by the compiler - this happens for all code.
The syntax tree is rewritten after taking into account variable capture. Capturing variables is just like in a normal delegate or lambda - so display classes get created, and captured locals get moved into them (this is the same behaviour as variable capture in C# 2.0 anonymous delegates).
The new syntax tree is converted into a series of calls to the Expression class so that, at runtime, an object tree is created that faithfully represents the parsed text.
LINQ to external data sources is supposed to take this expression tree and interpret it for its semantic content, and interpret symbolic expressions inside the tree as either referring to things specific to its context (e.g. columns in the DB), or immediate values to convert. Usually, System.Reflection is used to look for framework-specific attributes to guide this conversion.
However, it looks like SubSonic is not properly treating symbolic references that it cannot find domain-specific correspondences for; rather than evaluating the symbolic references, it's just punting. Thus, it's a SubSonic problem.