How to wrap record_out() function? - postgresql

I'd like to create an IMMUTABLE wrapper function as discussed by https://stackoverflow.com/a/11007216/14731 but it's not clear how to proceed. The above Stackoverflow answer provides the following example:
For example, given:
CREATE OR REPLACE FUNCTION public.immutable_unaccent(regdictionary, text)
RETURNS text LANGUAGE c IMMUTABLE PARALLEL SAFE STRICT AS
'$libdir/unaccent', 'unaccent_dict';
CREATE OR REPLACE FUNCTION public.f_unaccent(text)
RETURNS text LANGUAGE sql IMMUTABLE PARALLEL SAFE STRICT AS
$func$
SELECT public.immutable_unaccent(regdictionary 'public.unaccent', $1)
$func$;
I scanned all the libraries in lib/ and as far as I can tell none of them export functions related to record_out(). Any ideas?

The record_out() function is an internal built-in function. You can get its definition like this:
select pg_get_functiondef('record_out'::regproc);
pg_get_functiondef
----------------------------------------------------------
CREATE OR REPLACE FUNCTION pg_catalog.record_out(record)+
RETURNS cstring +
LANGUAGE internal +
STABLE PARALLEL SAFE STRICT +
AS $function$record_out$function$ +
I don't know for what purpose you want the wrapping function. It only remains to warn that such a change may bring unexpected results.

Related

Does function written in sql inherit IMMUTABLE or PARALLEL SAFE automatically in PostgreSQL?

For example, if I write
create function foo(int x)
RETURNS int
AS xxxxx
language 'c' IMMUTABLE PARALLEL SAFE;
and
create function bar(int x)
RETURNS int
AS 'select foo(x)'
language 'sql';
Would bar() be treated as immutable and parallel safe when performing queries?
No, the function will not "inherit" any attributes from the called function.
You will have to specify those options when creating the function bar().
Btw: the language name is an identifier and should not be enclosed in single quotes. Support for that is deprecated and might break in a future version.

In PostgreSQL, how can you declare a variadic function that accepts arguments of differing types?

It's definitely possible to define such a function through the C API as can be witnessed by looking at json_build_array() for example:
Unfortunately trying to create a SQL or pl/pgSQL function like this fails
CREATE OR REPLACE FUNCTION my_function( VARIADIC _args anyelement[]) RETURNS ...
and this is no surprise as the PostgreSQL documentation mentions that 'VARIADIC' only works for arrays (and it seems there is no such thing as an anyelement[]). Does anybody know how to get this working without having to write a C function ?
There is not possibility now. PLpgSQL and SQL languages are out of game, because there are not arrays with fields of different types. And PL/Perl or PL/Python just doesn't support, it what I know.

Alias for function or procedure name

I was running into the issue defined in the following article, and the first answer solved my main concern of naming a parameter the same name as a table column. My new concern is that my function/procedure parameters are widely used and the name of my functions/procedures are fairly detailed.
PL/pgSQL column name the same as variable
Is there a way to define an alias for a function or procedure name - to be used inside its body?
Current code:
CREATE OR REPLACE PROCEDURE dbo.PR_DeleteCrazyNamedItemByCrazyNamedID(in NamedID UUID)
LANGUAGE plpgsql AS
$BODY$
DECLARE
BEGIN
Delete from dbo.Table t where PR_DeleteCrazyNamedItemByCrazyNamedID.NamedID = t.NamedID;
...
Desired code:
CREATE OR REPLACE PROCEDURE dbo.PR_DeleteCrazyNamedItemByCrazyNamedID(in NamedID UUID) as proc
LANGUAGE plpgsql AS
$BODY$
DECLARE
BEGIN
Delete from dbo.Table t where proc.NamedID = t.NamedID;
...
Not directly. The function name seems to be visible as record containing input parameters inside the function body, but it is not accessible for an ALIAS as suggested in my referenced answer because it actually serves as outer label. The manual:
Note
There is actually a hidden “outer block” surrounding the body of any
PL/pgSQL function. This block provides the declarations of the
function's parameters (if any), as well as some special variables such
as FOUND (see Section 42.5.5). The outer block is labeled with the
function's name, meaning that parameters and special variables can be
qualified with the function's name.
But you can combine an ALIAS for function parameters with an outer block label (one nesting level below the built-in outer block labeled with the function name) like this:
General example with a function:
CREATE OR REPLACE FUNCTION weird_procedure_name(named_id int)
RETURNS TABLE (referenced_how text, input_value int) LANGUAGE plpgsql AS
$func$
<< proc >> -- outer label!
DECLARE
named_id ALIAS FOR named_id; -- sic!
BEGIN
RETURN QUERY VALUES
('weird_procedure_name.named_id', weird_procedure_name.named_id)
, ('proc.named_id', proc.named_id)
, ('named_id', named_id)
;
END
$func$;
SELECT * FROM weird_procedure_name(666);
referenced_how | input_value
:---------------------------- | ----------:
weird_procedure_name.named_id | 666
proc.named_id | 666
named_id | 666
db<>fiddle here
named_id ALIAS FOR named_id; seems to be pointless noise, but now the input parameter is accessible via block label - effectively doing what you ask for. (You might chose a different name while being at it.)
And I would certainly add a code comment explaining why label and alias are needed, lest the next smart developer should be tempted to remove either.
Applied to your example:
CREATE OR REPLACE PROCEDURE PR_DeleteCrazyNamedItemByCrazyNamedID(in NamedID UUID)
LANGUAGE plpgsql AS
$BODY$
<< proc >> -- !
DECLARE
NamedID ALIAS FOR NamedID; -- sic!
BEGIN
DELETE FROM dbo.tbl t WHERE t.NamedID = proc.NamedID; -- what you wanted !
END
$BODY$;
I would still much rather work with unique parameter names to begin with, so no qualification is required at all. I like to prefix all parameter names with underscore (like: _named_id) - and never do the same for other object names.

Use custom function with HugSQL

I am using PostgreSQL version 10 on macOS 10.12.6 and would like to use a custom plpgsql function in a query which shall be accessible to HugSQL. The following ansatz works correctly:
-- :name do-something! :! :1
CREATE OR REPLACE FUNCTION helper()
... (function body of helper)
LANGUAGE plpgsql;
INSERT INTO SomeTable (someColumn) VALUES (helper());
This works since HugSQL allows me to write multi-line SQL statements and I can include the function definition of helper().
However, I wonder whether it's actually efficient to do so since now I am redefining the function every time the query do-something! is run. I have tried to put the function definition at the top of the input file, but it only resulted in a compiler exception.
Question: What is the best way to this?
I found a solution. Here it is for the convenience of other users of HugSQL.
The function can be defined in the migrations file that sets up the tables (I use migratus for this purpose). The scope of the function definitions is identical to the scope of the tables, so if the migration reads
CREATE OR REPLACE FUNCTION helper()
... (function body of helper)
LANGUAGE plpqsql;
CREATE TABLE IF NOT EXISTS SomeTable
(...row definitions);
then the function helper() can be used in the query posted above without having to (re-)define it prior to usage:
-- :name do-something! :! :1
INSERT INTO SomeTable (someColumn) VALUES (helper());

Can one create a custom type in postgres without writing functions in C?

I'm trying to create a type to store color hexes preferably in byte form. I followed all the instructions in postgres docs here: http://www.postgresql.org/docs/9.3/static/sql-createtype.html
and found the part where it says CREATE FUNCTION my_box_in_function(cstring) RETURNS box AS ... ; a bit... unsettling. What goes in the ellipses? Turns out that was justified as I cannot find any example of creating a simple data type without custom PG functions written in C.
My best attempt was this:
CREATE TYPE color;
CREATE FUNCTION color_in(cstring) RETURNS color AS $$
BEGIN
RETURN decode($1::text, 'hex')::color;
END;
$$ LANGUAGE PLPGSQL IMMUTABLE RETURNS NULL ON NULL INPUT;
CREATE FUNCTION color_out(color) RETURNS cstring AS $$
BEGIN
RETURN encode($1::bytea, 'hex')::text;
END;
$$ LANGUAGE PLPGSQL IMMUTABLE RETURNS NULL ON NULL INPUT;
CREATE TYPE color (
INTERNALLENGTH = 3,
LIKE = bytea,
INPUT = color_in,
OUTPUT = color_out
);
This yields the error:
NOTICE: return type color is only a shell
ERROR: PL/pgSQL functions cannot return type color
Similar error if I use Language SQL or default to SPL.
The example in-out functions are listed here: http://www.postgresql.org/docs/9.3/static/xtypes.html. The only example functions are written in C. Am I correct in assuming this is the only way to write a UDT in postgres? Is there another way? My goal is to have the colors stored as bytes but have their native text form be hexadecimal (for the purposes of dumping, restoring, and casting from raw).
From http://www.postgresql.org/docs/9.4/interactive/datatype-pseudo.html
Functions coded in procedural languages can use pseudo-types only as
allowed by their implementation languages. At present the procedural
languages all forbid use of a pseudo-type as argument type, and allow
only void and record as a result type (plus trigger when the function
is used as a trigger). Some also support polymorphic functions using
the types anyelement, anyarray, anynonarray, anyenum, and anyrange.
And from the docs for create type
http://www.postgresql.org/docs/9.4/interactive/sql-createtype.html
The input function can be declared as taking one argument of type
cstring, or as taking three arguments of types cstring, oid, integer.
The output function must return type cstring.
Given the above:
Base data type input and output functions use cstring.
Procedural languages can not use cstring.
Base data type functions can't be written in procedural language.
Defining a base data type can't be done purely in procedural languages.
You can use pre-existing input and output functions, but I don't think
that any of them will directly get you a hex string. The closest
is probably the \x hex escaped bytea, but you'd have a \x at the beginning of your text representation. If you're willing to cast to and from text, I think you could create a type using bytea_in and bytea_out and writing custom casts to and from text. You'd have to explicitly cast to avoid the \x though.