How do I call this Postgres function with custom enum input? - postgresql

I expected this to be simple, but I've tried multiple combinations and I can't get PostgreSQL to accept them. It claims there are no matching functions, yet the types listed (as seen in the example below) clearly matches my defined function.
List of data types
Schema | Name | Internal name | Size | Elements | Access privileges | Description
--------+--------+---------------+------+----------+-------------------+-------------
public | levels | levels | 4 | debug +| |
| | | | info +| |
| | | | warn +| |
| | | | critical | |
CREATE FUNCTION public."logEvent"(IN in_type text,IN in_priority public.levels,IN in_message text)
RETURNS void
LANGUAGE 'sql'
NOT LEAKPROOF
AS $function$
INSERT INTO public.log (type,priority,message) VALUES (in_type, in_priority, in_message);
$function$;
The failing query:
SELECT 1 FROM public.logEvent('test'::text,'debug'::public.levels,'test from sql prompt'::text);
ERROR: function public.logevent(text, levels, text) does not exist
LINE 1: SELECT 1 FROM public.logEvent('test'::text,'debug'::public.l...
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
An alternate function definition: I get the same error when trying to execute this create function call:
CREATE FUNCTION public."logEvent"(IN in_type text, IN in_priority text, IN in_message text)
RETURNS boolean
LANGUAGE 'sql'
NOT LEAKPROOF
AS $function$
SELECT public.logEvent( in_type, CAST(lower(in_priority) AS public.levels), in_message);
$function$;

Are you aware that double-quoted identifiers are case-sensitive?
Are PostgreSQL column names case-sensitive?
CREATE FUNCTION public."logEvent"
But:
SELECT 1 FROM public.logEvent
This should work:
SELECT 1 FROM public."logEvent"('test', 'debug', 'test from sql prompt');
Explicit type casts are only necessary if there can be ambiguity with overloaded function.
Either keep double-quoting "logEvent" for the rest of its existence, or (smarter) use unquoted (effectively lower-case), legal identifiers.

Related

Overwrite Postgres now() function

In my test database, I want to override now() in Postgres, so I can travel to a certain point in time. I'd like to override it like this:
CREATE SCHEMA if not exists override;
CREATE OR REPLACE FUNCTION override.now()
RETURNS timestamp with time zone
AS
$$
BEGIN
RETURN pg_catalog.now() + COALESCE(
NULLIF(current_setting('timecop.offset_in_seconds', true), '')::integer, 0
) * interval '1 second';
END;
$$
LANGUAGE plpgsql STABLE PARALLEL SAFE STRICT;
SET search_path TO DEFAULT;
SELECT set_config('search_path', 'override,' || current_setting('search_path'), false);
To enable it, I call
SET timecop.offset_in_seconds = 3600 -- 1 hour ahead
To disable it, I call
RESET timecop.offset_in_seconds
The problem is, that Postgres somehow doesn't use the function:
app_test=# select now();
now
-------------------------------
2022-12-04 10:22:26.824469+00
(1 row)
app_test=# SET timecop.offset_in_seconds = 3600;
SET
app_test=# select now();
now
-------------------------------
2022-12-04 10:22:34.481502+00
(1 row)
Looking at the now() method itself, I seems like the search path searches in pg_catalog before the override schema:
app_test=# \df+ now
List of functions
Schema | Name | Result data type | Argument data types | Type | Volatility | Parallel | Owner | Security | Access privileges | Language | Source code | Description
------------+------+--------------------------+---------------------+------+------------+----------+----------+----------+-------------------+----------+-------------+--------------------------
pg_catalog | now | timestamp with time zone | | func | stable | safe | postgres | invoker | | internal | now | current transaction time
So, how could I move my overwritten now() BEFORE the pg_catalog?
pg_catalog is always on the search path, but you can opt not to have it in the beginning:
SET search_path = override, pg_catalog;

PostgreSQL trouble trying to run a stored procedure HINT: No procedure matches the given name and argument types. SQL state: 42883

For some time I've been trying to get into PostgreSQL looking forward to use it as a RDBMS for a PyQt5 system. So far my main difficulty arises when trying to run a stored procedure where I usually get the 42883 error code. I already went through the need to cast the string variables to varchar and the date data to date which helped me sort same errors, but I couldn't pass through 42883. When checking the documentation, the error describes so many possibilities, some of them not to clear though, I couldn't get any clue from it.
I tried enclosing table names with quotes with similar results.
This is my first stored procedure try - even though simple is just a try since I foresee the need of using transactions -
CREATE OR REPLACE PROCEDURE public.es_load_image(IN _coordinates character varying, IN _photo
character varying, IN _report_date date, IN _reporterid smallint, IN _categoryid smallint, IN
_description character varying)
LANGUAGE plpgsql
AS $$
BEGIN
INSERT INTO image_points
(geom, photo, report_date, reporterid, categoryid, description)
VALUES(ST_GeomFromText('POINT('||_coordinates ||')', 4326), _photo, _report_date,
_reporterid,_categoryid, _description);
END;
$$
After running the stored procedure (PgAdmin4) as follows:
CALL es_load_image('-59.74553210 -35.75147550'::varchar,
'C:/gis/photos/photo_13052022_162549.jpg'::varchar,
'2022-05-13'::date, 3, 0, 'Just testing'::varchar)
I get this notice:
"ERROR: procedure es_load_image(character varying, character varying, date, integer, integer,
character varying) does not exist
LINE 1: CALL es_load_image('-59.74553210 -35.75147550'::varchar,
^
HINT: No procedure matches the given name and argument types. You might need to add explicit
type casts.
SQL state: 42883
Character: 6"
I supposed there is a simple solution to this issue but I wasn't able to figure it out.
Note: PostgreSQL 14.1
To follow up on my comment:
CREATE OR REPLACE PROCEDURE public.es_load_image(IN _coordinates character varying, IN _photo character varying, IN _report_date date, IN _reporterid smallint, IN _categoryid smallint, IN _description character varying)
LANGUAGE plpgsql
AS $procedure$
BEGIN
RAISE NOTICE '%, %, %, %, %, %', _coordinates, _photo, _report_date, _reporterid, _categoryid, _description;
END;
$procedure$
CALL es_load_image('-59.74553210 -35.75147550',
'C:/gis/photos/photo_13052022_162549.jpg',
'2022-05-13', 3::smallint, 0::smallint, 'Just testing')
;
NOTICE: -59.74553210 -35.75147550, C:/gis/photos/photo_13052022_162549.jpg, 2022-05-13, 3, 0, Just testing
The casting is done according to this:
select castsource::regtype, casttarget::regtype, castcontext from pg_cast where castsource = 'integer'::regtype;
castsource | casttarget | castcontext
------------+------------------+-------------
integer | bigint | i
integer | smallint | a
integer | real | i
integer | double precision | i
integer | numeric | i
integer | money | a
integer | boolean | e
integer | oid | i
integer | regproc | i
integer | regprocedure | i
integer | regoper | i
integer | regoperator | i
integer | regclass | i
integer | regcollation | i
integer | regtype | i
integer | regconfig | i
integer | regdictionary | i
integer | regrole | i
integer | regnamespace | i
integer | "char" | e
integer | bit | e
Where from here pg_cast:
castcontext char
Indicates what contexts the cast can be invoked in. e means only as an explicit cast (using CAST or :: syntax). a means implicitly in assignment to a target column, as well as explicitly. i means implicitly in expressions, as well as the other cases.

how to pass multiple variables to same parameter when calling postgresql function

i have total of 4 records in my table
id | url | name | description | last_update
----+------------------------------------+---------------------+-------------+-------------
1 | https://www.postgresqltutorial.com | PostgreSQL Tutorial | |
2 | http://www.oreilly.com | O'Reilly Media | |
3 | https://www.google.com | Google | | 2013-06-01
4 | http://www.postgresql.org | PostgreSQL | |
i have written a function to delete by passing name as a parameter, now i want to pass multiple names but i am facing error.
CREATE OR REPLACE FUNCTION testing(first_name varchar(255))
RETURNS INTEGER AS
$BODY$
DECLARE emp_id INTEGER;
BEGIN
SELECT id into emp_id from links e where name = first_name;
DELETE FROM links WHERE id = emp_id;
return emp_id;
END
$BODY$
LANGUAGE plpgsql;
select * from testing('Google, PostgreSQL');
Error:- no function matches the given name and argument types. you might need to add explicit type casts
Since you have a comma separated list, you can cast your parameter as an array with string_to_array function then apply the any operator. Further there is no reason for pgplsql, this can be written in a single sql statement, then wrapped it into a sql parameter/function. (see demo)
create or replace procedure testing(first_names varchar(255))
language sql
as $$
delete from links
where name = any(string_to_array(first_names, ','));
$$;
If you want to pass several values, you have to define the function to accept several values. There are two ways:
a variadic function:
CREATE FUNCTION testing(VARIADIC first_name text[]) ...
This is called like
SELECT testing('arg1', 'arg2', 'arg3');
a function that accepts an array as parameter:
CREATE FUNCTION testing(first_name text[]) ...
This is called like
SELECT testing(ARRAY['arg1', 'arg2', 'arg3']);

search for multiple values in comma separated column (postgresql)

I need to fetch all records where these (5565bffd-b1c8-4556-ae5d-4bef61af48f5","5565bffd-cd78-4e6f-ae13-4bef61af48f5) values exists in categories_id column.
The value that I need to search in categories_id can be multiple because it coming from the form.
+--------------------------------------+-------------+-------------+-------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------+
| id | name | alias | description | categories_id |
+--------------------------------------+-------------+-------------+-------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 5565c08d-9f18-4b76-9cae-4a8261af48f5 | Honeycolony | honeycolony | null | ["5565bffd-7f64-494c-8950-4bef61af48f5"] |
+--------------------------------------+-------------+-------------+-------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------+
| c8f16660-32cf-11e6-b73c-1924f891ba4d | LOFT | loft | null | ["5565bffd-25bc-4b09-8a83-4bef61af48f5","5565bffd-b1c8-4556-ae5d-4bef61af48f5","5565bffd-cd78-4e6f-ae13-4bef61af48f5"] |
+--------------------------------------+-------------+-------------+-------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 5565c17f-80d8-4390-aadf-4a8061af48f5 | Fawn Shoppe | fawn-shoppe | null | ["5565bffd-25bc-4b09-8a83-4bef61af48f5","5565bffd-0744-4740-81f5-4bef61af48f5","5565bffd-b1c8-4556-ae5d-4bef61af48f5","5565bffd-cd78-4e6f-ae13-4bef61af48f5"] |
+--------------------------------------+-------------+-------------+-------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------+
I have this function which work as in_array function php.
CREATE OR REPLACE FUNCTION public.arraycontain(
x json,
y json)
RETURNS boolean
LANGUAGE 'plpgsql'
COST 100
VOLATILE
AS $BODY$
DECLARE a text;b text;
BEGIN
FOR a IN SELECT json_array_elements_text($1)
LOOP
FOR b IN SELECT json_array_elements_text($2)
LOOP
IF a = b THEN
RETURN TRUE;
END IF;
END LOOP;
END LOOP;
RETURN FALSE ;
END;
$BODY$;
ALTER FUNCTION public.arraycontain(json, json)
OWNER TO postgres;
But when I do this:
select * from "stores"
where arrayContain(stores.categories_id::JSON,'["5565bffd-b1c8-4556-ae5d-4bef61af48f5","5565bffd-cd78-4e6f-ae13-4bef61af48f5"]')
it shows
ERROR: invalid input syntax for type json
DETAIL: The input string
ended unexpectedly.
CONTEXT: JSON data, line 1: SQL state: 22P02
here is the sqlfiddle (I couldn't update the arraycontain function in fiddle.)
My expected output from the fiddle is it should return last 3 rows that is Furbish Studio,Fawn Shoppe AND LOFT if search using this values ["5565bffd-b1c8-4556-ae5d-4bef61af48f5","5565bffd-cd78-4e6f-ae13-4bef61af48f5"])
I am open for any recommendation.
I also tried this query below but it returns empty.
select id
from stores
where string_to_array(categories_id,',') && array['5565bffd-cd78-4e6f-ae13-4bef61af48f5','5565bffd-b1c8-4556-ae5d-4bef61af48f5'];
EDIT:
This code is actually a filter to filter data. So if I only filter using categories it didn't work but if there is a query before it it works
select * from "stores"
where name like '%ab%' and arrayContain(stores.categories_id::JSON,'["5565bffd-b1c8-4556-ae5d-4bef61af48f5","5565bffd-cd78-4e6f-ae13-4bef61af48f5"]')
also the thing that amaze me is that the '%ab%' must contain more than two character if there's below <2 it will throw error. what could be wrong.
Click: demo:db<>fiddle
You can use the ?| operator, which takes a jsonb array (your column in that case) and checks a text array if any elements are included:
SELECT
*
FROM
mytable
WHERE categories_id ?| '{5565bffd-b1c8-4556-ae5d-4bef61af48f5,5565bffd-cd78-4e6f-ae13-4bef61af48f5}'
If your categories_id is not of type json (which is what the error message says) but a simple text array, you can compare two text arrays directly using the && operator:
Click: demo:db<>fiddle
SELECT
*
FROM
mytable
WHERE categories_id && '{5565bffd-b1c8-4556-ae5d-4bef61af48f5,5565bffd-cd78-4e6f-ae13-4bef61af48f5}'
Your code seems to work fine so perhaps sqlfiddle is the problem.
Try changing the separator in the schema building part to / (instead of ;) and make sure you have the correct version for Postgresql. json_array_elements_text is not supported in 9.3 (you can use json_array_elements instead in this case).
Also skip the " in the select statement.
Look here http://sqlfiddle.com/#!17/918b75/1
There might be an error in your data. Perhaps categories_id is an empty string somewhere.
Try this to see the offending data if any.
do $$
declare
r record;
b boolean;
begin
for r in (select * from stores) loop
b:= arrayContain(r.categories_id::JSON,'["5565bffd-b1c8-4556-ae5d-4bef61af48f5","5565bffd-cd78-4e6f-ae13-4bef61af48f5"]') ;
end loop;
exception
when others
then raise notice '%,%',r,r.categories_id;
return;
end;
$$
Best regards.
Bjarni

PSQL Error: function does not exist

I have made a function in postgres
CREATE OR REPLACE FUNCTION foobar(
x TEXT,
y TEXT,
z REAL
) RETURNS BOOLEAN AS $func$
.
.
.
$func$ LANGUAGE plpgsql;
When I do \df i get the following:
+----------+--------+------------------+------------------------+---------+
| Schema | Name | Result data type | Argument data types | Type |
+----------+--------+------------------+------------------------+---------+
| mySchema | foobar | boolean | x text, y text, z real | normal |
+----------+--------+------------------+------------------------+---------+
But when I try to use it I get [42883] ERROR: function foobar(text, text, real) does not exist. Hint: No function matches the given name and argument types. You might need to add explicit type casts. The call I'm doing is:
SELECT * FROM myTable WHERE foobar(column1::text, 'hello'::text, 7.2::real);
To me it seems like the function exists and the types match, I'm struggling to figure out what's wrong.
As a_horse_with_no_name mentioned in his comment, the solution is prefix the function with the schema.
Wrong: SELECT * FROM myTable WHERE foobar(column1::text, 'hello'::text, 7.2::real);
Correct: SELECT * FROM myTable WHERE mySchema.foobar(column1::text, 'hello'::text, 7.2::real);