I am writing a database using flyway and maven to apply migration scripts to a Postgres 11 database.
I'd like to be able to write statements in PL/pgSQL that flyway can run over its JDBC connection, just like regular ansi SQL.
Eg,
--some regular sql statements
create table test(id bigint);
select * from test;
--etc
--switch to plpgsql
language plpgsql;
--some plpgsql code goes here
Is this possible?
You can embed PL/pgSQL in SQL using a DO statement:
DO $$
DECLARE
...
BEGIN
...
END;
$$;
Related
I am implementing Row Level Security (RLS) on a postgres table. To use a single user, I am setting a configuaration_parameter for each session that maps to the row's identity and it works. I can test this using SQL but since I am using Mulesoft for the application, I don't have control over setting up connections and setting the parameter then. I tried to create a stored procedure where I try to set the value in the beginning but postgres doesn't like it. The docs don't share whether I can implement it in the SP or not so wondering if you guys know for sure so I can look at alternate solutions.
https://www.postgresql.org/docs/12/sql-set.html
The below does not work if I uncomment the line SET doc.provider=$1;
CREATE OR REPLACE PROCEDURE getParticipants(text)
LANGUAGE plpgsql
AS $$
BEGIN
--SET doc.provider=$1;
SELECT * FROM disclosure.participantsxref;
END;
$$;
Statement SET doesn't allow parametrization.Instead you can use a function set_config:
CREATE OR REPLACE FUNCTION foo(text)
RETURNS SETOF disclosure.participantsxref AS $$
BEGIN
PERFORM set_config('doc.provider', $1, true);
RETURN QUERY SELECT * FROM disclosure.participantsxref;
END $$
LANGUAGE plpgsql;
In your example, there is another issue - PostgreSQL's procedures cannot to returns tables - if you want to return table, then you have to use function. Functions can return tables with statement RETURN QUERY.
You can try to use dynamic SQL :
create or replace procedure myproc ()
as $$
begin
execute format('set lc_numeric=%L', 'fr_FR') ;
end;
$$
language 'plpgsql';
CREATE PROCEDURE
show lc_numeric;
lc_numeric
-------------
en_US.UTF-8
(1 row)
call myproc();
CALL
show lc_numeric;
lc_numeric
------------
fr_FR
(1 row)
is it possible to create a stored procedures on sql workbench that uses a redshift database ?
I tried to put in some procedure found on the internet like this one
CREATE OR REPLACE FUNCTION proc_sample RETURN INTEGER
IS
l_result INTEGER;
BEGIN
SELECT max(col1) INTO l_result FROM sometable;
RETURN l_result;
END;
but I get an error
the cursor is not located inside a statement
help please.
Here is my translation of your stored procedure for Redshift:
CREATE OR REPLACE PROCEDURE proc_sample (
l_result OUT INTEGER
)
LANGUAGE plpgsql
AS $$
BEGIN
SELECT max(col1) INTO l_result FROM sometable;
END
$$;
You call this stored procedure in Redshift as follows:
BEGIN; CALL proc_sample(); END;
-- l_result
-- ----------
-- 99
For more information see "Overview of stored procedures in Amazon Redshift"
you can not use from clause in function. you have to use procedure having parameter with out clause.
I am learning Postgreslq and I have a question about this code sample:
CREATE OR REPLACE PROCEDURE CreateProject(
IN projectName VARCHAR(45),
IN projectYear SMALLINT)
LANGUAGE plpgsql
AS $$
BEGIN
-- PREPARE addProject (VARCHAR(45),SMALLINT) AS
-- INSERT INTO projects (projectName, year) VALUES ($1, $2);
-- EXECUTE addProject(projectName, projectYear );
EXECUTE 'INSERT INTO projects (projectName, year) VALUES ($1, $2)'
USING projectName,projectYear;
END $$;
I am trying to write stored procedure that would be safe against SQL injection. Coming from Mysql, I know that I would have to use prepared statement with parameters. Here in Postgresql it doesn't allow to(commented code), on the other hand if I use dynamic command it works. Could someone explain, why it is not possible to use prepared statement in such a situation?
Execution plans are prepared and cached for PL/PgSQL, it happens automatically. So, there's no need to use PREPARE inside PL/PGSQL ( As you've seen, you can't) for the sake of optimisation.
SQL injection is possible if you use dynamic arguments and use concatenation to append them instead of parameterising. However, since you are running a simple insert without dynamic columns/tables, EXECUTE is not needed.
CREATE OR REPLACE procedure CreateProject(
IN projectName VARCHAR(45),
IN projectYear SMALLINT )
LANGUAGE plpgsql
AS $$
BEGIN
INSERT INTO projects (projectName, year) VALUES ($1, $2);
END $$;
DEMO
I'm trying to store a simple SELECT query with the new CREATE PROCEDURE method in PostgreSQL 11. My idea is to store the queries in the DB, because I can have a much simple code in my API server and maybe I don't need to develop a query builder if I can use if/else in an sql function with enforced type safety. I have this minimal example:
First I tried this plpgsql function:
CREATE OR REPLACE PROCEDURE test_proc() AS $$
BEGIN
SELECT * FROM my_db
LIMIT 1;
END;
$$ LANGUAGE plpgsql;
CALL test_proc();
However throws this error:
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 test_proc() line 3 at SQL statement SQL state: 42601
If I trying to use RETURN QUERY:
CREATE OR REPLACE PROCEDURE test_proc() AS $$
BEGIN
RETURN QUERY;
SELECT * FROM my_db
LIMIT 1;
END;
$$ LANGUAGE plpgsql;
I'm getting this error:
ERROR: cannot use RETURN QUERY in a non-SETOF function
LINE 17: RETURN QUERY; ^
SQL state: 42804
Character: 310
I'm also getting error when I try to use RETURNS void AS $$ or RETURNS table(...) AS $$. Seems like RETURNS not supported in CREATE PROCEDURE? So, is it possible to return a table with the new stored procedure method? Or if it's not, maybe JSON?
Procedures in PostgreSQL (Oracle, DB2) are not same like procedures in MS-SQL. It has different target, and you cannot use it. Usually, the best what you can do, forgot all what you know from MSSQL. The procedural part is really different.
Only functions can returns some data - so you need to use functions. Functions can returns scalar value, composite value or array value, or table. You want function that returns table.
CREATE OR REPLACE FUNCTION fx()
RETURNS SETOF mytab AS $$
BEGIN
RETURN QUERY SELECT * FROM mytab;
END
$$ LANGUAGE plpgsql;
SELECT * FROM fx();
For record:
You can use SQL function, that can have better (or worse) performance (depends on context). These functions are sometimes named as parametrized views.
CREATE OR REPLACE FUNCTION fx()
RETURNS SETOF mytab AS $$
SELECT * FROM mytab;
$$ LANGUAGE sql;
Attention: this technique is antipattern!!! Don't do it. It is really not good idea. The functions should not to wrap queries. If you want to hide some complexity of queries, then use a views. Don't use a functions. Functions are effective barier for query optimizer, and when you use this antipattern, then optimizer cannot to well optimize any non trivial queries that use in this form evaluated subqueries.
Use it - if you want very very slow applications - or if your data model or queries are primitive. In other cases, don't do it.
Don't afraid of SQL - it is great language designed for manual usage. It is good to place all data access to one module (model), to don't access database everywhere in your code, but it is bad too hide SQL in your code.
First of all Procedure was introduced in PostgreSQL 11, If you are using below 11th version, you cannot use Procedures. Instead to Procedure you can use functions.
Syntax to create function
CREATE or replace function function_name(_parameter varchar)
returns table(col1 varchar, col2 varchar, col3 varchar)
language 'plpgsql'
as $BODY$
BEGIN
return query select a.col1, a.col2, b.col3 from table a
join table2 as b on a.col1 = b.col1;
END;
$BODY$;
you can call a function same a like table
select * From function_name('sample data');
syntax to create Procedure.
CREATE OR REPLACE PROCEDURE procedure_name(_parameter varcar,INOUT result refcursor)
LANGUAGE 'plpgsql'
AS $BODY$
BEGIN
open result for SELECT , * from sampletable where a = _parameter;
END;
$BODY$;
you can execute a Procedure using call keyword, within a transaction
BEGIN;
CALL public.procedure_name( 'sample data', 'test');
fetch all in "test";
COMMIT;
The postgreSql 11. we have to create a stored procedure
there is the solution :
Create procedure to execute query in PostgreSQL
I am attempting to get a better understanding of the DO command in postgreSQL 9.1
I have following code block,
DO
$do$
BEGIN
IF 1=1 THEN
SELECT 'foo';
ELSE
SELECT 'bar';
END IF;
END
$do$
However it returns the following error:
[42601] ERROR: query has no destination for result data Hint: If you want to discard the results of a SELECT, use PERFORM instead. Where: PL/pgSQL function "inline_code_block" line 4 at SQL statement
PostgreSQL DO command creates and executes some specific short life function. This function has not any interface, and then it cannot to return any output other then changes data in tables and some debug output.
Your example has more than one issues:
Only PostgreSQL table functions can returns some tabular data. But the mechanism is significantly different than MSSQL. PostgreSQL user's should to use RETURN NEXT or RETURN QUERY commands.
CREATE OR REPLACE FUNCTION foo(a int)
RETURNS TABLE(b int, c int) AS $$
BEGIN
RETURN QUERY SELECT i, i + 1 FROM generate_series(1,a) g(i);
END;
$$ LANGUAGE plpgsql;
SELECT * FROM foo(10);
DO anonymous functions are not table functions - so no output is allowed.
PostgreSQL 9.1 is not supported version, please upgrade
If you have some experience only from MSSQL, then forget it. A concept of stored procedures of PostgreSQL is very similar to Oracle or DB2, and it is significantly different to MSSQL does. T-SQL integrates procedural and SQL constructs to one set. Oracle, PostgreSQL, ... procedural functionality can embedded SQL, but procedural functionality is not integrated to SQL.
Please, read PostgreSQL PLpgSQL documentation for better imagine about this technology.