Parametrizing blob types using gnatcoll.sql - blob

I am using the Ada library gnatcoll.sql to create parametrizable SQL queries.
While I am able to create Integer parameters for type SQL_Field_Integer using the function:
function Integer_Param (Index : Positive) return Integer_Fields.Field'Class
renames Integer_Fields.Param;
As well as for the following types using their respective functions:
SQL_Field_Bigint, SQL_Field_Text, SQL_Field_Boolean, SQL_Field_Float, SQL_Field_Long_Float, SQL_Field_Money, SQL_Field_Time, SQL_Field_Date
I am not able to parametrize Blob fields, I don't find those type mappings nor any service except the postgresql/sqlite bindings at low-level.
How can I parametrize blob types? As String?

Related

How can I perform a regex/text search on a SUPER type?

What I'm doing now:
I have a table with one field that is a json value that is stored as a super type in my staging schema.
the field containing the json is called elements
In my clean table, I typecast this field to VARCHAR in order to search it and use string functions
I want to search for the string net within that json in order to determine the key/value that I want to use for my filter
I tried the following:
select
elements
, elements_raw
from clean.events
where 1=1
and lower(elements) like '%net%'
or strpos(elements,'net')
My output
When running the above query, I keep getting an empty set returned.
My issue
I tried running the above code and using the elements_raw value instead but I got an issue :ERROR: function strpos(super, "unknown") does not exist Hint: No function matches the given name and argument types. You may need to add explicit type casts.
I checked the redshift super page and it doesn't list any specifics on searching strings within super types
Desired result:
Perform string operations on super field
Cast super field to a string type
There are some super related idiosyncrasies that are being run into here:
You cannot change the type of a super field via :: or cast()
String functions like and strpos do not work on super types
To address both of these issues, you can use the function json_serialize to return your super as a string.

How to get a Row representation of a generated table?

I want to get Row[N]<...> representation of a generated JOOQ table type. I want to use it in this context:
val p = PROJECTS.`as`("p")
val pmu = PROJECTMEMBERUSERS.`as`("pmu")
val query = db
.select(p.asterisk(), DSL.arrayAgg(DSL.rowField(<-- insert Row[N]<...> here -->)))
.from(p.join(pmu).on(p.ID.eq(pmu.PROJECTID)))
.groupBy(p.ID)
I already tried inserting pmu.fieldsRow(), but DSL.rowField(...) expects another parameter type.
Error:(39, 58) Kotlin: None of the following functions can be called with the arguments supplied [...]
This question is a follow up question to Using PosgreSQL array_agg with join alias in JOOQ DSL but should be self contained.
Missing feature in jOOQ 3.11
There seems to be a missing feature in the jOOQ code generator, a generated Table.fieldsRow() overridden method that provides a more narrow, covariant Row[N]<...> return type. I've created a feature request for this, to be implemented in jOOQ 3.12:
https://github.com/jOOQ/jOOQ/issues/7809
Also missing, an overloaded DSL.rowField(RowN) method:
https://github.com/jOOQ/jOOQ/issues/7810
Workaround, list columns explicitly
This is the most obvious workaround, which you obviously want to avoid: Listing all the column names explicitly:
row(pmu.COL1, pmu.COL2, ..., pmu.COLN)
Workaround, use generated records
There already is such a generated method in generated records. As a workaround, you could use
new ProjectMembersUsersRecord().fieldsRow();
Workaround, extend the code generator
You can implement #7809 yourself already now, by extending the JavaGenerator with a custom code section:
https://www.jooq.org/doc/latest/manual/code-generation/codegen-custom-code

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);

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.

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.