I'm using quite a few Postgres functions (both sql and pl/pgsql) in a particular application. Some of the sql functions depend on other sql functions, e.g.
create or replace function my_function ()
returns table (a text, b text) as
$$
select * from my_other_function();
$$
language sql;
For my_function to load properly, my_other_function has to be loaded first, else I get a my_other_function does not exist error. To manage this, I have been manually ensuring that my_other_function does get loaded first, but it would be nice not to have to do that.
In other words, is there a way to load all of my functions without regard to order and somehow check that all the necessary dependencies are available (function objects) after the fact?
I'm using Postgres 9.6.
You can use SETcheck_function_bodies= false; prior creating your functions to suppress the error.
Related
When I try to use RAISE NOTICE in a Query tool in PgAdmin I just get "ERROR: syntax error at or near "RAISE"". This is stopping defining a stored procedure which uses RAISE NOTICE.
I have simply typed the following into a Query Tool window:
RAISE NOTICE 'Bob';
I am using PgAdmin 6.3 (the latest), just updated from v4.5 which had the same problem.
RAISE is part of pl/pgsql, Postgres's default procedural language. It is not available in a direct SQL context, or any function or stored procedure defined with LANGUAGE sql rather than LANGUAGE plpgsql.
If you're used to a different DBMS like MySQL or SQL Server, you might expect to have procedural code (variables, conditionals, loops, etc) available by default, but that's not how Postgres works. In order to use procedural code, you need to be inside a function, stored procedure, or DO statement.
I would like to know if it is possible in Firebird to assign and reference a variable in SQL Editor context.
To be clear, I present a code sample in MySQL that do what I want.
SET #var = 10;
SELECT #var;
Firebird only supports variables in PSQL (Procedural SQL), including anonymous procedures (EXECUTE BLOCK). There is no direct equivalent of using variables like in MySQL in DSQL (Dynamic SQL, the normal 'SQL' you use with Firebird).
The closest alternative is to use the context variables using RDB$GET_CONTEXT and RDB$SET_CONTEXT. The near equivalent of your code would be
select RDB$SET_CONTEXT('USER_TRANSACTION', 'var', 10) from RDB$DATABASE;
select RDB$GET_CONTEXT('USER_TRANSACTION', 'var') from RDB$DATABASE;
Be aware, a context variable is stored and retrieved as VARCHAR(255), so if you need to retrieve an integer, you will need to explicitly cast it.
Instead of 'USER_TRANSACTION', with scope limited to the current transaction, you can also use 'USER_SESSION', with scope limited to the current connection.
There is no such thing as "Editor context". Notepad, Word, SynWrite - you can edit anything in them, SQL or not. An editor is just an editor, there is no special context, SQL-wise, in it.
In editor you edit all the SQL texts. DSQL statements, PSQL scripts, everything. Editor does not matter, only difference between DSQL vs PSQL matters here, so read about them in the documentation. Editor has no its own SQL context.
Language-native variables only exist in PSQL context, that is "Procedural" SQL, language used for writing stored procedures, triggers, execute blocks, etc. Also, SQL functions, starting with Firebird 3.
Example from https://firebirdsql.org/file/documentation/reference_manuals/fblangref25-en/html/fblangref25-psql.html
CREATE OR ALTER PROCEDURE DEPT_BUDGET (
DNO CHAR(3))
RETURNS (
TOT DECIMAL(12,2))
AS
DECLARE VARIABLE SUMB DECIMAL(12,2);
DECLARE VARIABLE RDNO CHAR(3);
DECLARE VARIABLE CNT INTEGER;
BEGIN
TOT = 0;
SELECT
BUDGET
FROM
DEPARTMENT
WHERE DEPT_NO = :DNO
INTO :TOT;
SELECT
COUNT(BUDGET)
FROM
DEPARTMENT
WHERE HEAD_DEPT = :DNO
INTO :CNT;
IF (CNT = 0) THEN
SUSPEND;
FOR
SELECT
DEPT_NO
FROM
DEPARTMENT
WHERE HEAD_DEPT = :DNO
INTO :RDNO
DO
BEGIN
EXECUTE PROCEDURE DEPT_BUDGET(:RDNO)
RETURNING_VALUES :SUMB;
TOT = TOT + SUMB;
END
SUSPEND;
END
Apart from PSQL in Firebird there are more languages ("contexts"): DSQL (Dynamic SQL), ESQL (Embedded SQL) and pre-SQL native query language. Of those only DSQL is of any general use nowadays.
In DSQL you have no language-level variables, but you have functions to set/fetch parts of context: RDB$GET_CONTEXT() and RDB$SET_CONTEXT().
https://firebirdsql.org/file/documentation/reference_manuals/fblangref25-en/html/fblangref25-functions-scalarfuncs.html#fblangref25-functions-workcontext
select rdb$set_context('USER_SESSION', 'MyVar', 493) from rdb$database
and later
select rdb$get_context('USER_SESSION', 'MyVar') from rdb$database
You can not change 'USER_SESSION' here, as that is the only context you are allowed to write something, other contexts for reading only. But you are free to change the 2nd parameter as you like - that is the name of textual environment variable you set and retrieve.
UPD. I was wrong, there is one more writable context, 'USER_TRANSACTION', see 2.0.7 Release Notest at https://firebirdsql.org/file/documentation/release_notes/html/rlsnotes207.html#dml-dsql-context-ns
Read docs by the two links above and also read the file situated like
c:\Program Files (x86)\Firebird\Firebird_2_1\doc\sql.extensions\README.context_variables2.txt
adjust the path for specific Firebird version on your computer. You can see there full list of contexts (first parameter allowed values) available in your FB version.
However, since you want to use language-native variables, think about, using PSQL instead - see EXECUTE BLOCK in Firebird documentation and my first example. If you do not need to return more than one different datasets from your script, then wrapping it all into one EB for the sake of having variables may suit you better.
I would like to execute external program (such as .net c# console) when PostgreSQL trigger is fired. How can I achieve it?
Postgres cannot normally run external programs for security reasons.
The typical solution is to use NOTIFY and have a daemon LISTEN to it. There are solutions for every major scripting language out there ...
Examples for Java from #Craig: How to refresh JPA entities when backend database changes asynchronously?
Relevant manual page for PHP.
Since Postgres 9.3 there is a solution for invoking external programs. It is - for security reasons - limited to superusers and IMHO intended for exporting data, rather than doing a "notification on trigger":
COPY (SELECT 1) TO PROGRAM '/bin/touch /tmp/created_by_postgres'
If you want to actually export data to the invoked programm, you can provide any SELECT or a table name instead of SELECT 1. The query results will then be passed to the invoked program via its standard input.
You can find documentation of the feature in the Postgres docs:
http://www.postgresql.org/docs/9.3/static/sql-copy.html
You can execute external scripts from inside trigger function with an "untrusted" language, like plpythonu.
More details here: https://www.postgresql.org/docs/current/plpython.html
Trigger function example:
CREATE FUNCTION execute_python_script()
RETURNS trigger
AS $$
begin
import subprocess
result = subprocess.run(['/path/to/your/bin/python', '/some_folder/some_sub_folder/script.py'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
end;
$$
LANGUAGE plpythonu;
Trigger example:
CREATE TRIGGER trigger_name
AFTER INSERT ON table
EXECUTE PROCEDURE execute_python_script();
Is the default way of calling a function select * from my_function()?
I ask because I have built a function that doesn't return anything, just inserts data into a table and (coming from a SQL Server background) it "feels" strange to call it with select * from...
I was expecting something like exec my_function()
use PERFORM statement - http://www.postgresql.org/docs/current/static/plpgsql-statements.html
Sometimes it is useful to evaluate an expression or SELECT query but
discard the result, for example when calling a function that has
side-effects but no useful result value. To do this in PL/pgSQL, use
the PERFORM statement
so it's just
DO $$ BEGIN
PERFORM my_function();
END $$;
PostgreSQL 11:
PostgreSQL 11 supports true stored procedures as pointed out by #AbdisamadKhalif . They support in-procedure transaction control.
Older versions:
Yes, that's the standard way, and yes it's weird.
Usually you'd write such functions as stored procedures and invoke them with the CALL or EXECUTE command. PostgreSQL does not support true stored procedures (multiple result sets, autonomous transactions, and all that) though, only sql-callable user-defined functions.
So the workaround is to SELECT function_name() using the PostgreSQL extension syntax that omits FROM, or SELECT 1 FROM function_name(); to be (somewhat) more standard.
The ODBC driver, JDBC driver, etc understand the {call func_name()} escape syntax and automatically translate it to an underlying SELECT.
You will use from when the function returns a set. If the function returns void just do
select my_function();
I have developed an application using postgresql and it works well.
Now I need to create several instances of the same application but I have only one database. So I am thinking about using schemas, so that I can group each instance tables in a different schema.
Now, I wouldn't like to rewrite all my functions and script, thus I am wondering if I can just use some directive to instruct the database to operate on a specific schema. Just to try to make it clearer, do you know when in c++ you do
using namespace std;
so that you can use cout instead of std::cout ? I would like to use someting similar if possible.
The parameter you are looking for is search_path - that lists the schemas a query will look in. So, you can do something like:
CREATE TABLE schema1.tt ...
CREATE TABLE schema2.tt ...
CREATE FUNCTION schema1.foo() ...
CREATE FUNCTION schema2.foo() ...
SET search_path = schema1, something_else;
SELECT * FROM tt; -- schema1.tt
SELECT * FROM schema2.tt -- schema2.tt
SELECT foo(); -- calls schema1.foo
SELECT schema2.foo(); -- calls schema2.foo
Note that if a query's plan gets saved inside the body of foo() then you may get an unexpected results. I would recommend you always explicitly list schemas for referenced tables in plpgsql functions if you are using duplicated tables. If not, make sure you have testing in place to check behaviour with a chaning search_path.
Oh - you can explicitly set search_path for a function's body too - see the manual's CREATE FUNCTION reference for details.