How to CAST empty array value of an ANYARRAY-function to ANYARRAY? - arrays

I am using pgv10. The function that I need seems this wrong function:
CREATE FUNCTION array_coalesce(ANYARRAY) RETURNS ANYARRAY AS $f$
SELECT CASE WHEN $1 IS NULL THEN array[]::ANYARRAY ELSE $1 END;
$f$ language SQL IMMUTABLE;
Curiosity
... I started to simplify a complex problem, and arrives in the test select coalesce(null::text[], array[]::text[]) that not worked... So it was a good question, how to implement it? But sorry, I do something workng, COALESCE(array,array) is working fine (phew!).
So, "coalesce problem" is merely illustrative/didatic. What I really want to understand here is: How to use ANYARRAY?
PS: other curiosity, the string concat(), || and other concatenation operators in PostgreSQL do some "coalescing",
select concat(NULL::text, 'Hello', NULL::text); -- 'Hello'
select null::text[] || array[]::text[]; -- []
select array[]::text[] || null::text[]; -- []

How to use anyarray?
It's an interesting issue, in the context of the usage described in the question. The only way I know is to use an argument as a variable. It's possible in plpgsql (not in plain sql) function:
create or replace function array_coalesce(anyarray)
returns anyarray as $f$
begin
if $1 is null then
select '{}' into $1;
end if;
return $1;
end
$f$ language plpgsql immutable;
select array_coalesce(null::int[]);
array_coalesce
----------------
{}
(1 row)
By the way, you can simply use coalesce() for arrays:
select coalesce(null::text[], '{}'::text[]);
coalesce
----------
{}
(1 row)

Related

My function with array as parameter does not work

I proceed to specify my question and the solution I gave to the problem, for the benefit of the community.
I was trying to perform a multi-column insert using the identifier with a function.
For which, I was getting an error, my code was the following:
CREATE OR REPLACE FUNCTION acc.asignar_periodo(ids NUMERIC[], periodo INTEGER,codigo_subdiario VARCHAR)
RETURNS void
VOLATILE
AS
$$
DECLARE
cant_registros integer:= 0;
BEGIN
cant_registros := array_length(ids,1);
FOR i IN 1..cant_registros LOOP
EXECUTE'UPDATE '||$3||' SET periodo_tributario = $2 WHERE id = ids[i]';
END LOOP;
END;
$$ LANGUAGE plpgsql;
and my query is:
SELECT acc.asignar_periodo('{2291,2292,2293,2294,2295,2296,2297,2298,2299,2300,2301,2302}'::NUMERIC[],201612,'_08');
My solution was the following:
CREATE OR REPLACE FUNCTION acc.asignar_periodo(INTEGER[],INTEGER,INTEGER) RETURNS text VOLATILE AS
$$
DECLARE
qty integer:= array_length($1,1);
respuesta varchar := null;
BEGIN
FOR i IN 1..qty LOOP
EXECUTE'UPDATE _'||$3||' SET periodo_tributario = '||$2||' WHERE id = '||$1[i];
END LOOP;
respuesta := 'Periodo '||$2||' asignado a '||qty||' comprobantes del subdiario '||$3;
RETURN respuesta;
END;
$$ LANGUAGE plpgsql;
Note the correction, since when using EXECUTE it is necessary that the arguments escape the statements
There is no to loop needed to process the array. Postgres will process the entry array at once. After all set processing is what SQL is all about. Get into the mindset that whenever you write loop, likely incorrect and much slower. (Yes there occasions where it is necessary, but very few.) So: (see demo)
create or replace function asignar_periodo(ids numeric[], periodo integer,codigo_subdiario varchar)
returns void
language plpgsql
as $$
declare
stmt constant text = 'update %I set periodo_tributario = %s where id = any (''%s'')';
torun text;
begin
--torun = format(stmt, $3, $2, $1); -- this would work but
torun = format(stmt, codigo_subdiario, periodo, ids); -- I perfer parameter names to position reference
raise notice '%', torun;
execute torun;
end ;
$$;

How to loop from an array received as a parameter in plpgsql function?

I'm kinda new into pgplsql and so far I have to create a function that loops an array that is received as a function.
The main idea of the function is to insert new records into a table that maps each id contained in the array received with a new formatted id, the format depends on the second parameter received and return the table "idsTable".
The problem is that when I try to create the function it sends me an error:
ERROR: loop variable of FOREACH must be a known variable or list of variables
LINE 38: FOREACH objectid IN ARRAY idsList LOOP
I'm not sure if I have to declare the objectid variable cause in the examples that I have seen they didn't.
So far I have this:
CREATE OR REPLACE FUNCTION createId(idsList varchar[], objectType varchar)
RETURNS TABLE(original_id varchar, new_id char) as
$$
BEGIN
IF LOWER(objectType) = 'global' THEN
FOREACH objectid IN ARRAY idsList LOOP
INSERT INTO idsTable(original_id, new_id)
VALUES(objectid, 'GID'||nextval('mapSquema.globalid')::TEXT);
END LOOP;
ELSE
FOREACH objectid IN ARRAY idsList LOOP
INSERT INTO idsTable(original_id, new_id)
VALUES(objectid, 'ORG'||nextval('mapSquema.globalid')::TEXT);
END LOOP;
END IF;
END;
$$ LANGUAGE plpgsql;
Any ideas of what could be wrong?
edit: I haven't add the part where the idsTable is returned.
Unrelated, but: you don't really need a loop for that. And you can simplify the function by only writing the INSERT once. You also forgot to return something from your function. As it is declared as returns table that is required:
CREATE OR REPLACE FUNCTION createid(idslist varchar[], objecttype varchar)
RETURNS TABLE(original_id varchar, new_id varchar) as
$$
declare
l_prefix text;
BEGIN
IF LOWER(objectType) = 'global' THEN
l_prefix := 'GID';
ELSE
l_prefix := 'ORG';
END IF;
RETURN QUERY --<< return the result of the insert
INSERT INTO idstable(original_id, new_id)
select t.x, l_prefix||nextval('mapSquema.globalid')::TEXT
from unnest(idslist) as t(x)
returning *
END;
$$ LANGUAGE plpgsql;

GreenPlum -- 'concat ' function in greenplum

Is there 'concat' function in GreenPlum? I can use concat function in postgresql and it works well, but when i use it in Greenplum, I got an error.
select concat('a', 'b');
ERROR: function concat(unknown, unknown) does not exist at character 8
HINT: No function matches the given name and argument types. You may need to add explicit type casts.
LINE 1: select concat('a', 'b');
^
Is there some other functions can instead of 'concat' function in GreenPlum? And I have tried to create a function to instead of it, but got some syntax errors also.
CREATE OR REPLACE FUNCTION my_concat(VARIADIC arr VARCHAR[] ) RETURNS VARCHAR AS $$ SELECT array_to_string(arr, ''); $$ LANGUAGE SQL;
ERROR: syntax error at or near "VARCHAR" at character 51
LINE 1: CREATE OR REPLACE FUNCTION my_concat(VARIADIC arr VARCHAR[] ...
^
Anyone can help? Thanks very much!
Like most databases, Greenplum uses "||" to concatenate two strings together.
SELECT 'Green' || 'plum';
Result:
Greenplum
its a versional issue , you have use || in place where ever u using contact function.
Greenplum doesn't have the concat function yet. May be you can modify your code to use "||" instead of concat.
Well,
First I agree that you should replace your code to use the correct SQL syntax '||' for concatenation.
If you really want to create a function to emulate the concat, you could do something like:
create or replace function myschema.concat(arg1 text, arg2 text)
returns text as
$body$
declare
v_arg1 text;
v_arg2 text;
begin
v_arg1 := arg1;
v_arg2 := arg2;
return v_arg1 || v_arg2;
end
$body$
language plpgsql volatile;
Then, the query will work:
select myschema.concat('test1', 'test2');
>>test1test2
Hope you are looking for the below query.
gpadmin=# CREATE OR REPLACE FUNCTION my_concat( character varying[] ) RETURNS VARCHAR AS $$ SELECT array_to_string($1, ''); $$ LANGUAGE SQL;
gpadmin=# select my_concat(ARRAY['Green','plum']);
my_concat
Greenplum

PostgreSQL full-text search with arrays

I would like to implement full-text search within my application but I'm running into some roadblocks associated with my Array-type columns. How would one implement a psql trigger so that the when my "object" table is updated, each element (which are strings) of its array column is added to the tsvector column of my "search" table?
In Postgres 9.6 array_to_tsvector was added.
If you are dealing with same table you can write it something like this.
CREATE FUNCTION tsv_trigger() RETURNS trigger AS $$
begin
IF (TG_OP = 'INSERT') OR old.array_column <> new.array_column THEN
new.tsv := array_to_tsvector( new.array_column);
END IF;
return new;
end
$$ LANGUAGE plpgsql;
CREATE TRIGGER tsvectorupdate BEFORE INSERT OR UPDATE
ON my_table FOR EACH ROW EXECUTE PROCEDURE tsv_trigger();
If you are dealing with two tables than you need to write update
CREATE FUNCTION cross_tables_tsv_trigger() RETURNS trigger AS $$
begin
IF (TG_OP = 'INSERT') OR old.array_column <> new.array_column THEN
UPDATE search_table st
SET tsv = array_to_tsvector( new.array_column )
WHERE st.id = new.searchable_record_id
END IF;
# you can't return NULL because you'll break the chain
return new;
end
$$ LANGUAGE plpgsql;
Pay attention that it will differ from default to_tsvector( array_to_string() ) combination.
It goes without position numbers, and lowercase normalization so you can get a unexpected results.

how to call a pg function with libpq and get the param value

ALL
I have a postgresql function,so this:
CREATE OR REPLACE FUNCTION query_callouts(
INOUT io_cursor_ref refcursor,
INOUT opstatus integer,
INOUT errtext character varying)
RETURNS record AS
$BODY$
DECLARE
BEGIN
OPEN $1 FOR
SELECT tablename FROM pg_tables limit 10;
--SELECT * from call_out_numbers;
RETURN;
Exception
When Others Then
GET STACKED DIAGNOSTICS opstatus = RETURNED_SQLSTATE,
errText = MESSAGE_TEXT;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION query_callouts(refcursor, integer, character varying)
OWNER TO postgres;
I want to known ,how to use libpq in my c codes to visit the function - query_callouts and get the param io_cursor_ref and opstatus and errtext?
You can call the function just like you are executing any query:
select * from query_callouts('mycur', 0, '');
io_cursor_ref | opstatus | errtext
---------------+----------+---------
mycur | 0 |
(1 row)
opstatus and errtext would be set to the appropriate values if an exception occurs.
io_cursor_ref contains the name you have passed to the function.
Internally, a refcursor value is simply the string name of a so-called
portal containing the active query for the cursor. This name can be
passed around, assigned to other refcursor variables, and so on,
without disturbing the portal.
Note, you can use a refcursor only within a transaction.
All portals are implicitly closed at transaction end. Therefore a
refcursor value is usable to reference an open cursor only until the
end of the transaction.
You can use explicit transaction:
begin;
select * from query_callouts('mycur', 0, '');
fetch all in mycur;
-- save or show the query result
-- and finally
commit;
or use mycur inside a function.
The quotes are from the documentation.
It's just like any other query.
SELECT * FROM query_callouts('cursorname', 4, 'msg')
I suspect some if not all of your parameters should be OUT parameters not INOUT parameters, though. You don't ever use the input value of errtext at least.

Resources