Postgres syntax error with creat when use $$ - sql

I want execute next script migration.
But i catch syntax error.
How can i resolve it?
Script example:
CREATE OR REPLACE FUNCTION __execute(TEXT) RETURNS VOID AS $$
BEGIN EXECUTE $1; END;
$$ LANGUAGE plpgsql STRICT;
CREATE OR REPLACE FUNCTION __index_exists(TEXT, TEXT, TEXT) RETURNS bool as $$
SELECT exists(SELECT 1 FROM pg_indexes WHERE (schemaname, tablename, indexname) = ($1, $2, $3));
$$ language sql STRICT;
DO $$ BEGIN IF __my_function('true') THEN
SELECT __execute($$
CREATE INDEX "test_idx"
ON test_table
USING btree (column_name);
$$)
WHERE NOT __index_exists('public', 'test_table', 'test_idx');
END IF; END; $$;
Error:
SQL State : 42601
Error Code : 0
Message : ERROR: syntax error at or near "CREATE"

I think postgresql get confused between dollar quoting inside function, probably if you give it a tag name will solve the issue
DO $$ BEGIN IF __my_function('true') THEN
perform __execute($param$ CREATE INDEX "test_idx"
ON test_table
USING btree (column_name);$param$)
WHERE NOT __index_exists('public', 'test_table', 'test_idx');
END IF; END; $$;

Related

How to concat regclass name with a string in postgres query

I want to create indexes on partition tables using this function. Select query gives me all partitioned tables of test.t and then I iterate over its names and create indexes.
CREATE OR REPLACE FUNCTION test.create_index_test() RETURNS void AS
$BODY$
DECLARE
f record;
BEGIN
FOR f IN
SELECT inhrelid::regclass-- optionally cast to text
FROM pg_catalog.pg_inherits
WHERE inhparent = 'test.t'::regclass
loop
CREATE INDEX concat(f::text,'_geom_index') ON f USING gist (geom);
-- can do some processing here
END LOOP;
END;
$BODY$
LANGUAGE plpgsql;
But this is giving me error in concat function
ERROR: syntax error at or near "("
LINE 11: CREATE INDEX concat(f,'_geom_index') ON f USING gist (geom)...
DDL statements doesn't support parametrizations - so you cannot to use variables there.
You need to use dynamic SQL - EXECUTE statement
CREATE OR REPLACE FUNCTION test.create_index_test() RETURNS void AS
$BODY$
DECLARE
r record;
BEGIN
FOR r IN
SELECT inhrelid::regclass AS fullpath, c.relname
FROM pg_catalog.pg_inherits
JOIN pg_class c ON c.oid = inhrelid
WHERE inhparent = 'test.t'::regclass
LOOP
EXECUTE FORMAT('CREATE INDEX %I ON %s USING gist(geom)',
r.relname || '_geom_index',
r.fullpath);
-- the index name is optional in postgres, so it can be simplified
-- EXECUTE FORMAT('CREATE INDEX ON %s USING gist(geom)',
-- r.fullpath);
-- can do some processing here
END LOOP;
END;
$BODY$
LANGUAGE plpgsql;

Postgresql Syntax Error in Trigger Function

I want to create the following trigger function in my Postgresql DB :
CREATE FUNCTION attribute_edit_history()
RETURNS TRIGGER AS
$BODY$
BEGIN
Select
CASE
WHEN NOT EXISTS
(SELECT * FROM public."TB02_MDD_KEY" where "ENCODED_ID" =ENCODE(CONVERT_TO(NEW."ATTRIBUTE_NAME", 'UTF-8'), 'base64'))
THEN
CASE
WHEN OLD."ATTRIBUTE_NAME" is distinct from NEW."ATTRIBUTE_NAME"
THEN
INSERT INTO public."TB08_ATTRIBUTE_EDIT_HISTORY"(
"ENCODED_ID_OLD","ENCODED_ID_NEW" , "VERSION", "ATTRIBUTE_OLD", "ATTRIBUTE_NEW", "ATTRIBUTE_NEW_ID")
VALUES ( OLD."ENCODED_ID", NEW."ENCODED_ID", NEW."VERSION", OLD."ATTRIBUTE_NAME", NEW."ATTRIBUTE_NAME", ENCODE(CONVERT_TO(NEW."ATTRIBUTE_NAME", 'UTF-8'), 'base64'));
END;
END;
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql;
CREATE TRIGGER "attribute_edit_history" BEFORE UPDATE ON "TB02_MDD_KEY"
FOR EACH ROW EXECUTE PROCEDURE attribute_edit_history();
I am getting the following syntax error :
ERROR: syntax error at or near "INTO"
LINE 13: INSERT INTO public."TB08_ATTRIBUTE_EDIT_HISTORY"(
^
SQL state: 42601
Character: 352
I dont know where I am going wrong.
Thanks in advance!
Most likely, you want a simple IF statement rather than nested CASE expressions:
CREATE FUNCTION attribute_edit_history()
RETURNS TRIGGER AS
$BODY$
BEGIN
IF
NOT EXISTS(
SELECT 1
FROM public.TB02_MDD_KEY
WHERE ENCODED_ID = ENCODE(CONVERT_TO(NEW.ATTRIBUTE_NAME, 'UTF-8'), 'base64')
)
AND OLD.ATTRIBUTE_NAME IS DISTINCT FROM NEW.ATTRIBUTE_NAME
THEN
INSERT INTO public.TB08_ATTRIBUTE_EDIT_HISTORY(
ENCODED_ID_OLD,
ENCODED_ID_NEW ,
VERSION,
ATTRIBUTE_OLD,
ATTRIBUTE_NEW,
ATTRIBUTE_NEW_ID
) VALUES (
OLD.ENCODED_ID,
NEW.ENCODED_ID,
NEW.VERSION,
OLD.ATTRIBUTE_NAME,
NEW.ATTRIBUTE_NAME,
ENCODE(CONVERT_TO(NEW.ATTRIBUTE_NAME, 'UTF-8'), 'base64')
);
END IF;
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql;
Note that I removed the double quotes around the tables and columns identifiers; you don't need those (unless you have case-sensitive identifiers, which does not seem to be the case here).

Error "relation does not exist" in PostgreSQL function()

Function defined:
CREATE OR REPLACE FUNCTION len_chars(t_name VARCHAR, f_name VARCHAR) RETURNS BIGINT AS $$
BEGIN
SELECT sum(char_length(f_name)) FROM t_name;
END;
$$ LANGUAGE plpgsql;
Calling it from psql
SELECT len_chars('public.tag', 'name');
for table "tag" and column "name" returns Error:
psql: ERROR: relation "t_name" does not exist
LINE 1: SELECT sum(char_length(f_name)) FROM t_name
^
QUERY: SELECT sum(char_length(f_name)) FROM t_name
CONTEXT: PL/pgSQL function len_chars(character varying,character varying) line 1 at SQL statement
Is it possible to choice table name in postgresql functions?
You need dynamic SQL for that. And to safely construct a dynamic SQL string, the best way is to use the format() function using %I placeholders to properly deal with quoting identifiers if needed.
CREATE OR REPLACE FUNCTION len_chars(t_name VARCHAR, f_name VARCHAR)
RETURNS BIGINT AS $$
declare
l_result bigint;
BEGIN
execute format('SELECT sum(char_length(%I)) FROM %I', f_name, t_name)
into l_result;
return l_result;
END;
$$ LANGUAGE plpgsql;

How can alter the values of a composite type column inside trigger function before insert?

I have a table which has the following columns:
inspireId type : inspireid (composite type)
gid type : integer (primary key)
The inspireId column type is as following :
CREATE TYPE inspireId AS (
nameSpace text,
local_id integer
)
I want to fill local_id automatically with the value of gid when creating a new row in the table.
I tried the following :
CREATE OR REPLACE FUNCTION script.addLocalId() RETURNS TRIGGER AS
$$
BEGIN
NEW."inspireId".local_id := NEW.gid;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
But this is not working. The following error is thrown when creating the trigger function:
«new.inspireId.local_id» is not a known variable.
What is the right syntax for this?
You can not directly access to type element.
CREATE OR REPLACE FUNCTION script.addLocalId() RETURNS TRIGGER AS
$$
BEGIN
NEW."inspireId" = ((NEW.inspireId).nameSpace, NEW.gid)::inspireId;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION script.addLocalId() RETURNS TRIGGER AS
$$
BEGIN
SELECT (
'any value for nameSpace ',
NEW.gid
)::inspireId INTO NEW.inspireId;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;

syntax error at or near create when creating a function

So I am creating a function in PostgreSQL for the first time and I am having a problem with the syntax
CREATE OR REPLACE FUNCTION uni() RETURNS INTEGER AS $$
DECLARE
mviews RECORD;
BEGIN
FOR mviews IN SELECT id,universite_adi FROM proaca.a LOOP
INSERT INTO proaca.universite (id,ad,ulke_id)
VALUES (mviews.id,mviews.universite_adi,1)
END LOOP;
RETURN 1;
END;
$$ LANGUAGE plpgsql;
ERROR: syntax error at or near "create"
Line 2: $BODY$CREATE OR REPLACE FUNCTION uni() RETURNS INTEGER AS $$
The syntax error was solved by a_horse in the comments:
missing a ; to terminate the INSERT statement.
You don't need that loop. Just plain sql
create or replace function uni()
returns integer as $$
insert into proaca.universite (id, ad, ulke_id)
select id, universite_adi, 1
from proaca.a
returning 1
;
$$ language sql;