I recently read abou the DO block.
It is known that SQL functions run faster than plpgsql functions. So if an operation can be done in SQL we would prefer doing it with SQL.
Now what about this situation?
create or replace function asql()
returns void as $$
begin
raise notice ''hello, world!';
end;
$$ language plpgsql;
AND:
CREATE OR REPLACE FUNCTION aplpgsql()
RETURNS void AS
$BODY$
DO language plpgsql $$
BEGIN
RAISE NOTICE 'hello, world!';
END
$$;
$BODY$
LANGUAGE sql
And what if I have more complex query other than just plain print?
the DO block allows to actualy always use SQL functions for anything, take all the LOOPs and IFs and put them in DO block.
What am I missing?
SQL functions are not faster than plpgsql function. Without inlining these functions are slower. Only when inlining was successful, then SQL fuctions are optically faster. What is inlining? Example:
CREATE OR REPLACE FUNCTION myleft(text, int) RETURNS text AS $$
SELECT substring($1 FROM 1 FOR $2)
$$ LANGUAGE sql;
When you use function myleft, then a rewriter rewrites query
SELECT myleft('AHOJ',2)
to
SELECT substring('AHOJ FROM 1 FOR 2)
And the spead is same as native C function. But inlining is possible inly in some not too complex situations.
Wrapping PLpgSQL code to SQL function has only negative effect on performance.
Related
How to call nested Stored precedure in redshift?
I have bunch sql queries, where I need to ignore error and run next set of queries.
Ignore an error that occurs in a redshift stored procedure
This link I have gone through where if stored procedure will be executed as single command if exception occurs further statements wont continue.
I am thinking of having multiple sub SP inside the master SP like as below,
create or replace PROCEDURE schema.master_sp(var int4)
LANGUAGE plpgsql
AS $$
BEGIN
create or replace procedure schema.sp1(var int4)
Language plpgsql
AS $$
BEGIN
...statements
END;
CREATE OR REPLACE PROCEDURE schema.sp2(var int4)
Language plpgsql
AS $$
BEGIN
END;
END
$$
;
Can I run like this, if sub SP is used will all sql queries inside SP runs without exiting if exception occurs..
If any other way please let me know...
Thanks
Tried with sub nested SP, it is throwing error...
My goal is to create a schema, based on the uuid of a user.
I've therfor wrote a function that gets executed every time a user is created and confirmed.
As the documentation says PostgreSQL Documentation
i may have to write another function that creates a schema because of compatibility.
the 'create_user_schema()' function works in a new query but seems to not work if used in my trigger function. I've tried a lot with casting the uuid to a string but it still don't work.
Did i do something wrong, has this something to do with security and won't work in any case?
CREATE OR REPLACE FUNCTION user_setup() RETURNS trigger AS $user_setup$
DECLARE
s_name uuid := NEW.id;
BEGIN
-- cutout content that works so far
SELECT create_user_schema(CAST(s_name AS TEXT));
RETURN NULL;
END;
$user_setup$ LANGUAGE plpgsql;
CREATE TRIGGER user_setup AFTER INSERT OR UPDATE ON auth.users
FOR EACH ROW EXECUTE FUNCTION user_setup();
CREATE OR REPLACE FUNCTION create_user_schema(s_name text) RETURNS void AS $$
BEGIN
EXECUTE 'CREATE SCHEMA ' || quote_ident(s_name);
END;
$$ LANGUAGE plpgsql;
Well it wasn't really a bug and more some missing piece of information in "how postgres works".
It was necessary to add a 'Security Definer' keyword to the function to let the trigger have the correct privilges on execution.
I am initializing functions as part of an ETL pipeline; however, one of the functions is dependant to operate on a certain table, which has not yet been created by the time this function has been initialized.
Illustration:
CREATE OR REPLACE FUNCTION some_schema.my_func(parameter_1 BIGINT)
RETURNS TEXT
AS
$$
SELECT foo
FROM non_existent_schema.non_existent_schema AS my_table -- will cause error as this relation does not yet exist
WHERE my_table.bar = parameter_1
;
$$ LANGUAGE sql;
Section 42.6.8 in the documentation (Trapping Errors) discusses exception handling but using BEGIN statements (I am not sure where to include a BEGIN or if it is relevant to my case).
My question is, how can I avoid having this error, and if I would want to silence that Exception, what is the right way to do it.
note: I am a beginner with writing functions in Postgres.
You cannot do that in an SQL function, because SQL does not have procedural code. You need to use a different procedural language, for example PL/pgSQL:
CREATE FUNCTION some_schema.my_func(parameter_1 BIGINT) RETURNS TEXT
LANGUAGE plpgsql AS
$$BEGIN
RETURN (SELECT foo
FROM non_existent_schema.non_existent_schema AS my_table
WHERE my_table.bar = parameter_1);
EXCEPTION
WHEN undefined_table THEN
NULL; -- ignore
END;$$;
I know how to define functions in pl/pgsql ... but (for testing purposes) I would now like to write pl/pgsql as a script. (That is, the code should not be enclosed in a function.) Somehow this does not seem possible. I get syntax errors for things I know are correct (inside a pl/pgsql-function), for example:
declare v_test character varying;
Even this simple one-line script fails.
How can I write a pl/pgsql script?
PostgreSQL parser doesn't support PLpgSQL. PLpgSQL can be parsed (executed) only inside functions (procedures) or inside anonymous block - statement DO
DO $$
DECLARE x int DEFAULT 10;
BEGIN
RAISE NOTICE '%', x;
END;
$$;
There are not any other possibility.
Am very new in Database development so I have some doubts regarding my following example:
Function f1() - language sql
create or replace function f1(istr varchar)
returns text as $$
select 'hello! '::varchar || istr;
$$ language sql;
Function f2() - language plpgsql
create or replace function f2(istr varchar)
returns text as $$
begin select 'hello! '::varchar || istr; end;
$$ language plpgsql;
Both functions can be called like select f1('world') or select f2('world').
If I call select f1('world') the output will be:
`hello! world`
And output for select f2('world'):
ERROR: query has no destination for result data
HINT: If you want to discard the results of a SELECT, use PERFORM instead.
CONTEXT: PL/pgSQL function f11(character varying) line 2 at SQL statement
********** Error **********
I wish to know the difference and in which situations I should use language sql or language plpgsql.
Any useful link or answers regarding functions will much appreciated.
SQL functions
... are the better choice:
For simple scalar queries. Not much to plan, better save any overhead.
For single (or very few) calls per session. Nothing to gain from plan caching via prepared statements that PL/pgSQL has to offer. See below.
If they are typically called in the context of bigger queries and are simple enough to be inlined.
For lack of experience with any procedural language like PL/pgSQL. Many know SQL well and that's about all you need for SQL functions. Few can say the same about PL/pgSQL. (Though it's rather simple.)
A bit shorter code. No block overhead.
PL/pgSQL functions
... are the better choice:
When you need any procedural elements or variables that are not available in SQL functions, obviously.
For any kind of dynamic SQL, where you build and EXECUTE statements dynamically. Special care is needed to avoid SQL injection. More details:
Postgres functions vs prepared queries
When you have computations that can be reused in several places and a CTE can't be stretched for the purpose. In an SQL function you don't have variables and would be forced to compute repeatedly or write to a table. This related answer on dba.SE has side-by-side code examples for solving the same problem using an SQL function / a plpgsql function / a query with CTEs:
How to pass a parameter into a function
Assignments are somewhat more expensive than in other procedural languages. Adapt a programming style that doesn't use more assignments than necessary.
When a function cannot be inlined and is called repeatedly. Unlike with SQL functions, query plans can be cached for all SQL statements inside a PL/pgSQL functions; they are treated like prepared statements, the plan is cached for repeated calls within the same session (if Postgres expects the cached (generic) plan to perform better than re-planning every time. That's the reason why PL/pgSQL functions are typically faster after the first couple of calls in such cases.
Here is a thread on pgsql-performance discussing some of these items:
Re: pl/pgsql functions outperforming sql ones?
When you need to trap errors.
For trigger functions.
When including DDL statements changing objects or altering system catalogs in any way relevant to subsequent commands - because all statements in SQL functions are parsed at once while PL/pgSQL functions plan and execute each statement sequentially (like a prepared statement). See:
Why can PL/pgSQL functions have side effect, while SQL functions can't?
Also consider:
PostgreSQL Stored Procedure Performance
To actually return from a PL/pgSQL function, you could write:
CREATE FUNCTION f2(istr varchar)
RETURNS text AS
$func$
BEGIN
RETURN 'hello! '; -- defaults to type text anyway
END
$func$ LANGUAGE plpgsql;
There are other ways:
Can I make a plpgsql function return an integer without using a variable?
The manual on "Returning From a Function"
PL/PgSQL is a PostgreSQL-specific procedural language based on SQL. It has loops, variables, error/exception handling, etc. Not all SQL is valid PL/PgSQL - as you discovered, for example, you can't use SELECT without INTO or RETURN QUERY. PL/PgSQL may also be used in DO blocks for one-shot procedures.
sql functions can only use pure SQL, but they're often more efficient and they're simpler to write because you don't need a BEGIN ... END; block, etc. SQL functions may be inlined, which is not true for PL/PgSQL.
People often use PL/PgSQL where plain SQL would be sufficient, because they're used to thinking procedurally. In most cases when you think you need PL/PgSQL you probably actually don't. Recursive CTEs, lateral queries, etc generally meet most needs.
For more info ... see the manual.
just make the select query you wrote inside the function as the returned value:
create or replace function f2(istr varchar)
returns text as $$
begin return(select 'hello! '::varchar || istr); end;
$$ language plpgsql;