How to initialize row datatype variables? - postgresql

I would like to create a function that initialize and return the row datatype of a table as
CREATE FUNCTION get_default_table_row_object()
RETURNS mytable AS $$
DECLARE
row mytable;
BEGIN
row.field1 := 0;
row.field2 := -1;
row.record_reg_id := 1;
row.record_upd_id := 1;
row.record_reg_date := current_timestamp;
row.record_upd_date := current_timestamp;
RETURN row;
END;
$$ LANGUAGE plpgsql;
becuase my table has alot of columns and I need to create dozens of variables at several functions. I would like to use above function as
CREATE FUNCTION some_function() RETURNS VOID AS $$
DECLARE
i_obj1 mytable := get_default_table_row_object(); -- declare and initialize default values
BEGIN
-- function body
END;
$$ LANGUAGE plpgsql;
But this give me the error ERROR: default value for row or record variable is not supported. Has someway to figure it out ?

You can set it in the body instead, like so:
CREATE FUNCTION some_function() RETURNS VOID AS $$
DECLARE
i_obj1 mytable; -- declare only
BEGIN
i_obj1 := get_default_table_row_object(); -- set default values
END;
$$ LANGUAGE plpgsql;

Related

Trigger doesn't work and doesn't show any errors

I'm trying to create a trigger that will shorten the name and the middle name to initials.
That's what i have:
CREATE OR REPLACE FUNCTION myfunc() RETURNS TRIGGER AS $$
DECLARE nm VARCHAR(50);
DECLARE mdnm VARCHAR(50);
BEGIN
nm = LEFT(NEW.name, 1);
mdnm = LEFT(NEW.middle_name, 1);
SET NEW.name = nm;
SET NEW.middle_name = mdnm;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER table_before_insert BEFORE INSERT OR UPDATE ON table1
FOR EACH ROW EXECUTE PROCEDURE myfunc();
But for some reasons it doesn't work, what can it be?
As documented in the manual variables are assigned with := or =. But not with the SET command - which changes configuration properties. You also don't need a separate DECLARE block for each variable:
So your trigger function should look like this:
CREATE OR REPLACE FUNCTION myfunc() RETURNS TRIGGER AS $$
DECLARE
nm VARCHAR(50);
mdnm VARCHAR(50);
BEGIN
nm := LEFT(NEW.name, 1);
mdnm := LEFT(NEW.middle_name, 1);
NEW.name := nm;
NEW.middle_name := mdnm;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
You don't even need the variables:
CREATE OR REPLACE FUNCTION myfunc() RETURNS TRIGGER AS $$
BEGIN
NEW.name := LEFT(NEW.name, 1);
NEW.middle_name := LEFT(NEW.middle_name, 1);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;

How can I debug this function with v_operation and v_message?

CREATE OR REPLACE FUNCTION f_sync_from_xml()
RETURNS boolean AS
$BODY$
DECLARE
myxml xml;
datafile text := 'Documenti/ABBATE_EMANUELE_Lvl1F2Va_20160418-1759.xml';
BEGIN
myxml := pg_read_file(datafile, 0, 100000000);
CREATE TABLE tmp AS
SELECT (xpath('//some_id/text()', x))[1]::text AS id
FROM unnest(xpath('/xml/path/to/datum', myxml)) x;
END;
$BODY$ language plpgsql;
SELECT * from tmp;
This function should allow to transform a XML into postgres table. This function doesn't give an error but not create the table. How can I use v_operation and/or v_message to find possible errors?

How to pass table name to plpgsql function

I am trying to run the code:
CREATE OR REPLACE FUNCTION anly_work_tbls.testfncjh (tablename text) returns int
AS $$
DECLARE
counter int;
rec record;
tname text;
BEGIN
counter = 0;
tname := tablename;
FOR rec IN
select *
from tname
loop
counter = counter + 1;
end loop;
RETURN counter;
END;
$$
LANGUAGE 'plpgsql' IMMUTABLE
SECURITY DEFINER;
The goal of this code is to return the number of rows in the table you input. I know that this might not be the best way to accomplish this task, but the structure of this function would extend nicely to another question I am trying to tackle. Every time I run the code, I get the error:
ERROR: syntax error at or near "$1"
All online resources I have found tell me how to use the input variable within and EXECUTE block, but not in the above situation.
Currently running PostgreSQL 8.2.15.
CREATE OR REPLACE FUNCTION anly_work_tbls.testfncjh (tbl regclass, OUT row_ct int) AS
$func$
BEGIN
EXECUTE 'SELECT count(*) FROM '|| tbl
INTO row_ct;
END
$func$ LANGUAGE plpgsql IMMUTABLE SECURITY DEFINER;
Call:
SELECT anly_work_tbls.testfncjh('anly_work_tbls.text_tbl');
This should work for Postgres 8.2, but you consider upgrading to a current version anyway.
I pass the table name as object identifier type regclass, which takes care of quoting automatically and works with schema-qualified names. Details:
Table name as a PostgreSQL function parameter
Using an OUT parameter simplifies the function.
Don't quote the language name. It's an identifier.
If you actually need to loop through the result of a dynamic query:
CREATE OR REPLACE FUNCTION anly_work_tbls.testfncjh (tbl regclass)
RETURNS int AS
$func$
DECLARE
counter int := 0; -- init at declaration time
rec record;
BEGIN
FOR rec IN EXECUTE
'SELECT * FROM ' || tbl
LOOP
counter := counter + 1; -- placeholder for some serious action
END LOOP;
RETURN counter;
END
$func$ LANGUAGE plpgsql IMMUTABLE SECURITY DEFINER;
Read this chapter in the manual: Looping Through Query Results
The documented assignment operator in plpgsql is :=:
The forgotten assignment operator "=" and the commonplace ":="
Yes is really not the best way, but this would work:
CREATE OR REPLACE FUNCTION testfncjh (tablename text) returns int
AS $$
DECLARE
counter int;
rec record;
BEGIN
counter = 0;
FOR rec IN
EXECUTE 'select * from '||quote_ident(tablename) loop
counter = counter + 1;
end loop;
RETURN counter;
END;
$$
LANGUAGE 'plpgsql' IMMUTABLE
SECURITY DEFINER;
This would be nicer:
CREATE OR REPLACE FUNCTION testfncjh (tablename text) returns int
AS $$
DECLARE _count INT;
BEGIN
EXECUTE 'SELECT count(*) FROM '|| quote_ident(tablename) INTO _count;
RETURN _count;
END;
$$
LANGUAGE 'plpgsql' IMMUTABLE
SECURITY DEFINER;

Using OUT parameters in Postgres Stored Procedure

Is there any way I can set some value to OUT parameter in Postgres stored procedure? Below is the example what I want to do. In oracle PL/SQL you can use out parameters and set it to any value and return it. After that u can use that value and manipulate it.
CREATE OR REPLACE FUNCTION demo_procedure(p_invoice text, OUT p_out1 integer, OUT p_out2 integer)
returns SETOF record
as
$func$
DECLARE
s_inv_rest integer;
s_state integer;
BEGIN
BEGIN
SELECT "REST_TO_PAY", "STATE"
INTO s_inv_rest, s_state
FROM "INVOICE"
WHERE "INVOICE_REFERENCE" = p_invoice;
EXCEPTION
WHEN NO_DATA_FOUND THEN
p_out1 := 1;
p_out2 := 2;
RETURN;
END;
END;
$func$
language plpgsql;
So in this example for instance if no data is found I want to return some out code and out message.

How postgresql return a data set like the follows?

Just like the below function. I don't know how to return a set of inside parameter in postgresql?
create or replace function g_i(num int)
returns setof integer
as $$
declare
i int;
begin
while i < $1 loop
select i; -- How to write statements here?
end loop;
end;
$$ language plpgsql;
create or replace function g_i(num int)
returns setof integer
as $$
declare
i int;
begin
i := 0;
while i< $1 loop
i := i+1;
return query select i;
end loop;
end;
$$ language plpgsql;