Consider these two PostgreSQL functions:
CREATE OR REPLACE FUNCTION f_1 (v1 INTEGER, v2 OUT INTEGER) AS $$ BEGIN v2 := v1; END $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION f_2 (v1 INTEGER) RETURNS TABLE(v2 INTEGER) AS $$ BEGIN v2 := v1; END $$ LANGUAGE plpgsql;
In any "normal" procedural SQL language (such as Transact-SQL), the two types of functions will be completely different. f_1 will actually be a procedure, while f_2 will be a table function. In SQL Server, the latter is returned from INFORMATION_SCHEMA.ROUTINES as follows:
SELECT r.routine_schema, r.routine_name FROM information_schema.routines r WHERE r.routine_type = 'FUNCTION' AND r.data_type = 'TABLE'
In PostgreSQL, this does not work. The following query shows that there is no significant difference between the signatures f_1 and f_2 :
SELECT r.routine_name, r.data_type, p.parameter_name, p.data_type FROM information_schema.routines r JOIN information_schema.parameters p USING (specific_catalog, specific_schema, specific_name);
The above gives:
routine_name | data_type | parameter_name | data_type -------------+-----------+----------------+---------- f_1 | integer | v1 | integer f_1 | integer | v2 | integer f_2 | integer | v1 | integer f_2 | integer | v2 | integer
Not everything gets better if I have several columns returned from functions, in which case I don't even have a formal return type anymore. Just record :
CREATE OR REPLACE FUNCTION f_3 (v1 INTEGER, v2 OUT INTEGER, v3 OUT INTEGER) AS $$ BEGIN v2 := v1; END $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION f_4 (v1 INTEGER) RETURNS TABLE(v2 INTEGER, v3 INTEGER) AS $$ BEGIN v2 := v1; END $$ LANGUAGE plpgsql;
... I will get:
routine_name | data_type | parameter_name | data_type -------------+-----------+----------------+---------- f_3 | record | v1 | integer f_3 | record | v2 | integer f_3 | record | v3 | integer f_4 | record | v1 | integer f_4 | record | v2 | integer f_4 | record | v3 | integer
If they come from other databases, it is obvious that the meaning of the lexical signature is completely different. As an Oracle person, I expect PROCEDURES to have side effects, while FUNCTIONS has no side effects (if only in a stand-alone transaction) and can be safely embedded in SQL. I know that PostgreSQL skillfully treats all functions as tables, but I don't think it is a good idea to develop OUT parameters as table columns in any query ...
My question is:
Are there any formal differences between the two ways of declaring functions? If so, how can I detect it from INFORMATION_SCHEMA or from PG_CATALOG ?