How to get quantitative and qualitative info about function arguments in PostgreSQL? - sql

I have the following function:
func_name(p_1, p_2, p_3, ...)
Is there any way in the body of the function to query and get, for example:
a) the total number of the arguments/parameters of the current function
b) the type of them
Of course, I could modify the function as
func_name(n, ..., p_1, p_2, p_3, ...)
and include the info I require as arguments but it does not make me happy!
I would prefer to create a table with all functions' info (function name, function argument names and types) and query that when I have to.
Tia

you can try parsing it. lets fn() be:
t=# create or replace function fn(i int, t text) returns void as $$
declare
c text;
a text[];
begin
GET DIAGNOSTICS c = PG_CONTEXT;
raise info 'name: %',substring(c from 'function (.*?)\(');
a := string_to_array(substring(c from '\((.*?)\)'), ',');
raise info 'args: %',a;
raise info 'names: %', (select proargnames from pg_proc where proname = substring(c from 'function (.*?)\('));
raise info 'amount: %',array_length(a,1);
end;
$$ language plpgsql;
CREATE FUNCTION
so the info is:
t=# select fn(1,null);
INFO: name: fn
INFO: args: {integer,text}
INFO: names: {i,t}
INFO: amount: 2
fn
----
(1 row)
of course it will be more complicated to support not unique function name select and so on. This is just a simple example

Related

ORA-40593: name conflicts were found during execution of DBMS_JSON.CREATE_VIEW: name

When using JSON_DATAGUIDE to create a view:
declare
dg clob;
BEGIN
SELECT json_dataguide(json_document, dbms_json.FORMAT_HIERARCHICAL, dbms_json.pretty) into dg
FROM STATION_INFORMATION;
dbms_json.create_view('STATION_INFORMATION_VIEW', 'STATION_INFORMATION', 'JSON_DOCUMENT', dg);
END;
/
I get the following error:
ORA-40593: name conflicts were found during execution of DBMS_JSON.CREATE_VIEW
This happens when the dataguide uses the same JSON key name in more than one context. You can specify resolveNameConflicts => true to have it automatically make the names unique.
declare
dg clob;
BEGIN
SELECT json_dataguide(json_document, dbms_json.FORMAT_HIERARCHICAL, dbms_json.pretty) into dg
FROM STATION_INFORMATION;
dbms_json.create_view('STATION_INFORMATION_VIEW', 'STATION_INFORMATION', 'JSON_DOCUMENT', dg, resolveNameConflicts => true);
END;
/

Postgresql column reference is ambiguous

I want to call my function but I get this error:
ERROR: column reference "list" is ambiguous LINE 3: SET
list = ARRAY_APPEND(list, input_list2),
the error is on the second list inside array_append function.
My function:
CREATE OR REPLACE FUNCTION update_order(input_id uuid,input_sku text,input_store_id uuid,input_order_date bigint,input_asin text,input_amount int,input_list text[],input_price real,input_list2 text) RETURNS void LANGUAGE plpgsql AS
$body$
#variable_conflict use_column
BEGIN
INSERT INTO orders_summary(id,sku,store_id,order_date,asin,amount,list,price)
VALUES(input_id,input_sku,input_store_id,to_timestamp(input_order_date / 1000.0),input_asin,input_amount,input_list,input_price) ON CONFLICT(sku,order_date) DO UPDATE
SET list = ARRAY_APPEND(list, input_list2),
amount = amount + input_amount,
price = input_price
WHERE NOT list #> input_list;
END
$body$;
You have to use the alias name in the insert query because list has two references, one reference in EXCLUDED.list and another reference to the column for an update statement.
Please check the below query (I append the alias with name os in query):
CREATE OR REPLACE FUNCTION update_order(input_id uuid,input_sku text,input_store_id uuid,input_order_date bigint,input_asin text,input_amount int,input_list text[],input_price real,input_list2 text) RETURNS void LANGUAGE plpgsql AS
$body$
#variable_conflict use_column
BEGIN
INSERT INTO orders_summary as os (id,sku,store_id,order_date,asin,amount,list,price)
VALUES(input_id,input_sku,input_store_id,to_timestamp(input_order_date / 1000.0),input_asin,input_amount,input_list,input_price) ON CONFLICT(sku,order_date) DO UPDATE
SET list = ARRAY_APPEND(os.list, input_list2),
amount = os.amount + input_amount,
price = input_price
WHERE NOT os.list #> input_list;
END
$body$;
Or you can use table name:
CREATE OR REPLACE FUNCTION update_order(input_id uuid,input_sku text,input_store_id uuid,input_order_date bigint,input_asin text,input_amount int,input_list text[],input_price real,input_list2 text) RETURNS void LANGUAGE plpgsql AS
$body$
#variable_conflict use_column
BEGIN
INSERT INTO orders_summary (id,sku,store_id,order_date,asin,amount,list,price)
VALUES(input_id,input_sku,input_store_id,to_timestamp(input_order_date / 1000.0),input_asin,input_amount,input_list,input_price) ON CONFLICT(sku,order_date) DO UPDATE
SET list = ARRAY_APPEND(orders_summary.list, input_list2),
amount = orders_summary.amount + input_amount,
price = input_price
WHERE NOT orders_summary.list #> input_list;
END
$body$;

PostgreSQL how to disable plan caching to fix my base62 hashing?

From the documentation i gather, that PostgreSQL somehow employs its own cache and prepares satements ahead...
This is really bad for my base62 hash values. At some point, after 2-3 tries, they start returning the same number:
LOG: base62_id.val 1501145675089
CONTEXT: PL/pgSQL function copy_article(text) line 23 at RAISE
STATEMENT: select to_json("public"."copy_article"($1)) as value
LOG: copied_article_id QQZCFzm | article_count 1
CONTEXT: PL/pgSQL function copy_article(text) line 37 at RAISE
STATEMENT: select to_json("public"."copy_article"($1)) as value
LOG: base62_id.val 1501145675089
CONTEXT: PL/pgSQL function copy_article(text) line 23 at RAISE
STATEMENT: select to_json("public"."copy_article"($1)) as value
LOG: copied_article_id QQZCFzm | article_count 1
CONTEXT: PL/pgSQL function copy_article(text) line 37 at RAISE
STATEMENT: select to_json("public"."copy_article"($1)) as value
LOG: base62_id.val 1501145675089
CONTEXT: PL/pgSQL function copy_article(text) line 23 at RAISE
STATEMENT: select to_json("public"."copy_article"($1)) as value
LOG: copied_article_id QQZCFzm | article_count 1
CONTEXT: PL/pgSQL function copy_article(text) line 37 at RAISE
STATEMENT: select to_json("public"."copy_article"($1)) as value
LOG: base62_id.val 1501145675089
Here is my function:
CREATE OR REPLACE FUNCTION base62_id() RETURNS character varying
LANGUAGE plpgsql IMMUTABLE
AS $$
DECLARE
chars char[];
ret varchar;
val bigint;
BEGIN
chars := ARRAY['0','1','2','3','4','5','6','7','8','9'
,'A','B','C','D','E','F','G','H','I','J','K','L','M'
,'N','O','P','Q','R','S','T','U','V','W','X','Y','Z'
,'a','b','c','d','e','f','g','h','i','j','k','l','m'
,'n','o','p','q','r','s','t','u','v','w','x','y','z'];
val := (CEIL(EXTRACT(EPOCH FROM now()) * 1000))::bigint;
RAISE LOG 'base62_id.val %', val;
ret := '';
IF val < 0 THEN
val := val * -1;
END IF;
WHILE val != 0 LOOP
ret := chars[(val % 62)+1] || ret;
val := val / 62;
END LOOP;
RETURN ret;
END;$$;
In theory, this should work...
Any ideas?
Edit: How i use the function:
DECLARE
copied_article_id text := base62_id();
duplication_check int := 1;
copied_article articles;
BEGIN
WHILE duplication_check IS NOT NULL LOOP
SELECT COUNT(*) INTO duplication_check FROM articles WHERE id = copied_article_id;
END LOOP;
INSERT ... INTO ... SELECT ...
FROM
articles
WHERE
id = base_id;
SELECT * INTO copied_article FROM articles WHERE id = copied_article_id LIMIT 1;
Your explanation is pretty bogus. Plan caching has nothing to do with this outcome, the plancache doesn't care about individual function outputs.
There's at least two giant gaping bugs in the function:
You declare it IMMUTABLE but you call now() which is not immutable. IMMUTABLE functions must return the same result for every call with the same inputs. In fact, your function must be declared VOLATILE if it's allowed to return a different value for each call with the same inputs.
now() is STABLE. It actually returns the same value for each call within a transaction. So presumably using it when you want unique values makes no sense at all. I imagine you actually want clock_timestamp().
The latter problem with now() (a.k.a. current_timestamp) being STABLE across a transaction is likely the cause for the results you report.
BTW, the function will also probably be amazingly slow implemented in plpgsql. If you can turn it into a set operation plus string_agg it might be more tolerable, but still slow.

Postgresql function auto add 's' character to the end of string

I have a function in PostgreSQL database. However, every time I run the function in PostgreSQL, it auto-adda the character s behind of the query, therefore, I receive an error when it executes.
An example query ends up looking like this:
WHAT IN HERE: query SELECT uom_id FROM ps_quantity where id = 11s
My version is PostgreSQL 9.2.13. How can I solve this? Thanks.
CREATE OR REPLACE FUNCTION select_field(
selected_table text,
selected_field text,
field_type_sample anyelement,
where_clause text DEFAULT ''::text)
RETURNS anyelement AS
$BODY$ DECLARE
-- Log
ME constant text := 'selected_field()';
-- Local variables
_qry varchar := '';
_result_value ALIAS FOR $0;
where_clause1 varchar := 'asdasdsad';
BEGIN
RAISE NOTICE 'FUNCTION: SELECT_FIELD';
-- BANGPH
RAISE NOTICE 'BANGPH - CHANGE 11s to 11';
_qry := 'SELECT uom_id FROM ps_quantity where id = 11';
RAISE NOTICE 'WHERE = %s', where_clause1;
RAISE NOTICE 'WHAT IN HERE: query %s', _qry;
As the manual explains:
instead of:
RAISE NOTICE 'WHAT IN HERE: query %s', _qry;
you need to use:
RAISE NOTICE 'WHAT IN HERE: query %', _qry;
Placeholders for the RAISE statement don't have a "type modifier", it's a plain %

How to pass a record as parameter for PL/pgSQL function?

I keep looking for this answer online but I cannot find it.
I am trying to pass one record over a PL/pgSQL function. I tried it in two ways.
Fist way :
CREATE OR REPLACE FUNCTION translateToReadableDate(mRecord dim_date%ROWTYPE) RETURNS void AS $$
That is the ouput :
psql:requestExample.sql:21: ERROR: syntax error at or near "%"
LINE 1: ... FUNCTION translateToReadableDate(mRecord dim_date%ROWTYPE) ...
^
Second way :
CREATE OR REPLACE FUNCTION translateToReadableDate(mRecord RECORD) RETURNS void AS $$
And there is the output
psql:requestExample.sql:21: ERROR: PL/pgSQL functions cannot accept type record
Someone does know how to do this please ?
CREATE OR REPLACE FUNCTION translateToReadableDate(mRecord dim_date) RETURNS void AS $$
BEGIN
SELECT dim_day.name || ' (' || dim_day_in_month.id || ') ' || dim_month.name || 'is the ' || dim_week.id || ' week of the year. ' AS "Une phrase", dim_quarter.id, dim_year.id
FROM dim_date dd
JOIN dim_day ON dd.day_id = dim_day.day_id
JOIN dim_day_in_month ON dd.day_in_month_id = day_in_month.day_in_month_id
JOIN dim_week ON dd.week_id = dim_week.week_id
JOIN dim_month ON dd.month_id = dim_month.month_id
JOIN dim_quarter ON dd.quarter_id = dim_quarter.quarter_id
JOIN dim_year ON dd.year_id = dim_year.year_id
WHERE dd.day_id = mRecord.day_id
AND dd.day_in_month_id = mRecord.day_in_month_id
AND dd.week_id = mRecord.week_id
AND dd.month_id = mRecord.month_id
AND dd.quarter_id = mRecord.quarter_id
AND dd.year_id = mRecord.year_id;
END;
$$ LANGUAGE plpgsql;
Try this:
CREATE OR REPLACE FUNCTION translateToReadableDate(mRecord dim_date) RETURNS void AS $$
dim_date must be a table.
EDIT:
Ok, now I'm really really confused.
A date should be a column, not a table. I can't understand why would you create a table with date values.
You can format dates no problem with to_char. Read this: Data Type Formatting Functions to learn how to. That function you created makes zero sense.
Are you outputting PL/pgSQL? Shouldn't the formatting be done by the middle tier? You should just return a Date from the database.
Lastly, I would recommend reading the PL/pgSQL Manual. There's lots of good stuff in there.