How can I execute pl/pgsql code without creating a function? - postgresql

With SQL Server, I can execute code ad hoc T-SQL code with full procedural logic through SQL Server Management Studio, or any other client. I've begun working with PostgreSQL and have run into a bit of a difference in that PGSQL requires any logic to be embedded in a function.
Is there a way to execute PL/PGSQL code without creating an executing a function?

Postgres 9
DO $$
-- declare
BEGIN
/* pl/pgsql here */
END $$;

No, not yet. Version 9.0 (still alpha) will have this option (do), you a have to wait until it's released.

I struggled to get this working because it's fairly strict about adding semi colons in exactly the right places. But once you get used to that it works well. Besides the inability to return records of course, however you can raise notices & exceptions and do the other workarounds like using temp tables as #ErwinBrandstetter pointed out in a comment above.
e.g.:
DO
$$
BEGIN
IF EXISTS(SELECT 'any rows?'
FROM {your_table}
WHERE {your_column} = 'blah')
THEN
RAISE NOTICE 'record exists';
ELSE
RAISE EXCEPTION 'record does not exist';
END IF;
DROP TABLE IF EXISTS foo;
CREATE TEMP TABLE foo AS
SELECT 'bar'::character varying(5) as baz;
END
$$;
SELECT * FROM foo;

Related

PL/pgSQL procedures and transaction control

I'm new to Postgres, but with experience from Oracle. Trying to create a stored procedure which is going to:
Insert a row
Handle exceptions and in case of an exception insert a row into a log table by calling dedicated procedure
Emit an audit log record into a log table in case the whole procedure ran successfully
By pseudo code:
CREATE OR REPLACE PROCEDURE test.p_insert(IN p_test_param character varying)
LANGUAGE 'plpgsql'
SECURITY DEFINER
AS $BODY$
DECLARE
-- some declarations
BEGIN
BEGIN
INSERT INTO test.a(a) VALUES (p_test_param);
EXCEPTION
WHEN OTHERS THEN
-- GET STACKED DIAGNOSTICS
CALL test.p_insert_log(...); -- Inserts a row into a log table, another COMMIT may be required?
RAISE;
END;
COMMIT; -- CAN'T DO
BEGIN
IF (SELECT test.f_debug()) THEN
CALL test.p_insert_log(...); -- Audit the execution
END IF;
END;
COMMIT; -- CAN'T DO EITHER
END;
$$BODY$$;
However when I try to test the procedure out from an anonymous block in PgAdmin such as:
BEGIN;
DO
LANGUAGE plpgsql
$$
BEGIN
CALL test.p_insert(
p_test_param => 'test'
);
END;
$$
I'm getting an error ERROR: invalid transaction termination. How can I get rid of it? My objective is to let the procedure carry out the transaction control, I don't want the caller to COMMIT or ROLLBACK anything. If I remove both COMMIT commands from the code of the procedure, it executes well, however the invoker must explicitly COMMIT or REVOKE the transaction afterwards, which is not desired. In Oracle the pseudo code with COMMIT statements would work, in Postgres it doesn't seem to work as I would like to. Could you please help me out? Thanks
Your code will work as intended. Perhaps you made some mistake in calling the code:
you cannot call the procedure from a function
you cannot call the procedure in an explicitly started transaction:
BEGIN;
CALL p_insert('something); -- will fail
COMMIT;

From SQL Server to Postgres

I'm new to Postgresql; I have only used SQL Server before so I'm trying to migrate an ASP.NET MVC application to ASP.NET Core 3.0 and replace SQL Server with PostgreSQL in the process, and move to Ubuntu.
Can anyone tell what's wrong with my query here?
CREATE OR REPLACE PROCEDURE officekit.testsp (mode CHARACTER)
LANGUAGE plpgsql AS $plpgsql$
BEGIN
IF mode = 'test' THEN
SELECT a,b,c,d FROM testSchema.test;
END IF;
COMMIT;
END;
$plpgsql$;
In your code almost every line is not good.
First if you want to write stored procedures in Postgres, please start with the documentation. The concept of stored procedures in MSSQL is significantly different to that in Oracle, DB2, and certainly different to that in Postgres. PLpgSQL in Postgres is similar to Oracle's PL/SQL. The best thing to do, is to forget all that you know about stored procedures and start from scratch.
The errors:
procedures in Postgres cannot return data - only functions can do this - in your example you probably need a table function.
CREATE OR REPLACE FUNCTION officekit.testsp(mode text)
RETURNS TABLE(a text, b text, c text)
AS $$
BEGIN
IF mode = 'test' THEN
RETURN QUERY SELECT test.a, test.b, test.c FROM test;
END IF;
END;
$$ LANGUAGE plpgsql;
Personally I don't like this style of programming. Functions should not just wrap queries. A lot of significant performance problems and architecture issues arise from the bad use of this possibility, but it depends on context.
Why is commit there? This code doesn't make any change in the database. There is no reason to call commit.

execute immediate errors

I'm using Amazon RedShift SQL (used to use Oracle many years ago) and am getting constant syntax errors every way that I try EXECUTE IMMEDIATE. I have even copied and posted code from PostgreSQL documentation pages (e.g. using sprintf) but to no avail. I reckon the below should work...?
declare
stm varchar(200);
begin
stm = 'GRANT SELECT, INSERT, TRIGGER, UPDATE, DELETE, REFERENCES, RULE ON public.angus TO adcd;';
execute immediate stm;
end;
Amazon Invalid operation: syntax error at or near "varchar"
There are two problems:
You use EXECUTE IMMEDIATE, which you cannot have found in the PostgreSQL documentation, since it is Oracle syntax. The PL/pgSQL statement is EXECUTE.
You are trying to execute PL/pgSQL code as SQL statement, which won't work.
Use a DO statement:
DO $$DECLARE
...
END;$$;
Syntax for a standalone anonymous block slightly different, also the code is actually submitted as a string. See Postgres DO and search Dollar Quoting. Try
Do $$
declare
stm varchar(200);
begin
stm = 'GRANT SELECT, INSERT, TRIGGER, UPDATE, DELETE, REFERENCES, RULE ON public.angus TO adcd;';
execute immediate stm;
end;
$$

How to use DO in postgres

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.

Postgresql how to multiple stored procedure in transaction

I have many stored procedure in my postgresql db,
and for some reason i need to run many procedure in transaction so if there is a error it will rollback.
is there any way to do this?
edit 1
i run this through java and for some reason i cant make transaction from java and i cant run query string, just store procedure only.
I actually thinking making procedure like this
CREATE OR REPLACE FUNCTION ldt_pricing_rule_v1_api.start()
RETURNS VOID
LANGUAGE PLPGSQL
SECURITY DEFINER
AS $$
BEGIN
EXECUTE 'begin transaction'
RETURN;
END
$$;
select ldt_pricing_rule_v1_api.start();
but it's will display this
ERROR: cannot begin/end transactions in PL/pgSQL
HINT: Use a BEGIN block with an EXCEPTION clause instead.
BEGIN ... COMMIT should to work.
BEGIN
SELECT func1();
SELECT func2();
COMMIT;
PostgreSQL 11 (it is not released yet) has procedures where you can control transactions explicitly. Procedures are started by CALL statement like any other databases. Now, PostgreSQL functions doesn't allow control transactions (explicitly).
Any PostgreSQL function is executed under transaction - explicitly started by user (like my example), or implicitly started by system (by autocommit mode).
So outer BEGIN starts explicit transaction:
BEGIN
SELECT func1();
SELECT func2();
COMMIT;
and if there is any unhandled fail, then only ROLLBACK command is available.
or implicit transaction:
CREATE OR REPLACE FUNCTION outerfx()
RETURNS void AS $$
BEGIN
PERFORM func1();
PERFORM func2();
END;
$$ LANGUAGE plpgsql;
SELECT outerfx(); -- starts outer transaction implicitly.
Now, functions func1, func2 are executed under transaction too.