Postgresql - Edit function signature - postgresql

POSTGRESQL 8.4.3 - i created a function with this signature
CREATE OR REPLACE FUNCTION logcountforlasthour()
RETURNS SETOF record AS
realised i wanted to change it to this
CREATE OR REPLACE FUNCTION logcountforlasthour()
RETURNS TABLE(ip bigint, count bigint) record AS
but when i apply that change in the query tool it isnt accepted or rather it is accepted, there is no syntax error, but the text of the function has not been changed.
even if i run "DROP FUNCTION logcountforlasthour()" between edits the old syntax comes back
if i edit the body of the function, thats fine, it changes but not the signature
is there something i'm missing
thanks

From the PostgreSQL 8.4 manual:
To replace the current definition of
an existing function, use CREATE OR
REPLACE FUNCTION. It is not possible
to change the name or argument types
of a function this way (if you tried,
you would actually be creating a new,
distinct function). Also, CREATE OR
REPLACE FUNCTION will not let you
change the return type of an existing
function. To do that, you must drop
and recreate the function. (When using
OUT parameters, that means you cannot
change the names or types of any OUT
parameters except by dropping the
function.)
If you drop and then recreate a
function, the new function is not the
same entity as the old; you will have
to drop existing rules, views,
triggers, etc. that refer to the old
function. Use CREATE OR REPLACE
FUNCTION to change a function
definition without breaking objects
that refer to the function. Also,
ALTER FUNCTION can be used to change
most of the auxiliary properties of an
existing function.
The user that creates the function
becomes the owner of the function.
and also note:
...
PostgreSQL allows function overloading; that is, the same name can be used for several
different functions so long as they have distinct argument types.

Related

How can I define a plpgsql function that accepts a parameter of a type that is not schema qualified and is not yet created

My database is structured with a schema per application user. In each schema there is an identical table named "entries" with the exact same DDL. I also have a common schema that hosts some functions that operate on those "entries" tables, and during execution the search path defines which schema's entries table the function operates on. I had a problem defining those functions before i create any user schema because they reference the non yet created tables in the user schemata. That problem was solved using set check_function_bodies = off; But now I have a similar problem with a function that references those tables as an inout parameter. I cannot create that function because a parameter that it accepts is of type "entries" and I get an error of "type entries does not exist". set check_function_bodies = off does not solve this problem. Is there a way to solve this problem?
The function signature is
create or replace function common.reconcile_user_entry(inout e entries) returns void
I really dont want to define this function in each user schema as it will always be the same, and i dont want to have to recompile it in every schema when I need to make a change.
You could use inheritance for that.
Define a table common.entries just like all other entries tables and change the other entries tables to inherit from it:
ALTER TABLE schema1.entries INHERIT common.entries;
Then define the function to have common.entries as parameter or return type, and you can use it with any of the inherited tables.
I think you could use table inheritance.
You would have to create a "parent" table in common schema for every table you have in users schema. Then inherit users tables from them. Use "parent" table names when defining function parameters. See example:
CREATE TABLE parent(id integer);
CREATE TABLE child() INHERITS (parent);
INSERT INTO child(id) VALUES (1);
CREATE FUNCTION get_id(IN prm_row parent) RETURNS integer
LANGUAGE SQL
AS $$
SELECT prm_row.id;
$$;
SELECT get_id((SELECT (child) FROM child WHERE id = 1));
Note, that parent table will containt the records from all the child tables, so you should use permission to prevent users accessing the parent tables.
Instead of going with inheritance I ended up solving it by circumventing the problem like this:
Instead of defining the function signature as
create or replace function common.reconcile_user_entry(inout e entries) returns void
I defined it as
create or replace function common.reconcile_user_entry(inout r record) returns void
and in the function code I declare a variable e entries; and then assign the record into the variable:
declare
e entries;
begin
select into e r.*
...
Regarding the inheritance solution, it works, but I found the above solution much simpler.
I know there must be caveats and hidden problems with my solution, if someone can point, please do.

Changing schema name within functions

I have schema1 in database1. I want to move all the functions of schema1 to schema2 which is present in database2. I have restored backup file of database1 into database2. And changed the schema name. The schema name for function call automatically got changed. But within function definition the schema name is not changed. for ex:
CREATE OR REPLACE FUNCTION schema2.execute(..)
BEGIN
select schema1."VALIDATE_SESSION"(....)
end
How can I change "schema1" to "schema2" automatically?
I have tried to store current schema name in variable and append it to table. But calling current_schema() returns "public". How to get current schema created by user? Because every time I need to change the schema name while generating script.
The essential detail that is missing in your dummy function are the single quotes (or dollar-quotes, all the same) around the function body. Meaning, function bodies are saved as strings. See:
What are '$$' used for in PL/pgSQL
To contrast, consider a reference to a table (or more verbosely: schema.table(column)) in a FK constraint. Object names are resolved to the internal OID of the table (and a column number) at creation time. "Early binding". When names (including schema names) are changed later, that has no effect on the FK at all. Feels like involved names are changed dynamically. But really, actual names just don't matter after the object has been created. So you can rename schemas all day without side effect for the FK.
Names in a function body are stored as strings and interpreted at call time. "Late binding". Those names are not changed dynamically.
Meaning, you'll have to actually edit all function bodies including a hard-coded schema name. A possible alternative is to rely on the search_path instead and not use schema names in function bodies to begin with. There are various. See:
How does the search_path influence identifier resolution and the "current schema"
But that's not always acceptable.
You could hack the dump. Or use sting manipulation inside Postgres to update affected function bodies. Find affected functions with a meta-query like:
SELECT *
FROM pg_catalog.pg_proc
WHERE prosrc ~ '\mschema1\M'; -- not bullet-proof!
Either way, be wary of false matches if the schema name can be part of other strings or pop up as column name etc. And dynamic SQL can concatenate strings in arbitrary ways. If you have such evil trickery in your functions, you need to deal with it appropriately.

Accessing dynamic column value in PostgreSQL Trigger

I am writing trigger for record updation in Postgresql using plpgsql . In trigger, I am accessing one value column value like below
NEW.mobileno -- This is usual way.
Now my requirement is , I will be having 'mobileno' text in one variable called dyn_columnname
Using this NEW and dyn_columnname , I should be access like NEW.mobileno value.
How can I achieve this..?
You need to use dynamic sql:
execute _dyn_sql_string into _dyn_col_value using _dyn_col_name;
http://www.postgresql.org/docs/current/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-EXECUTING-DYN
It's usually better to avoid ending up with this situation to begin with, that being said, because the resulting query plans cannot be cached as efficiently as the plans from non-dynamic triggers.
If you're simply iterating through columns, consider approaching this by using dynamic sql, not to write a dynamic trigger function, but to write a dynamic function that creates or replaces a non-dynamic trigger function instead.
If you're using this because of some kind of business logic, consider revisitng your schema to aboid the situation entirely.

Create global variable in Postgresql

I am creating trigger for log table. In that trigger i want to store xuserno to log table. xuserno is a argument of all function
example:
CREATE OR REPLACE FUNCTION fn_consume(xmode text, xuserno integer)
RETURNS text AS
....
.....
.....
END;
Each table have this type of function. So how can i access the xuserno in my trigger. How can i create global variable for this purpose? or any other solution is have achive this?
It is possible to use transaction-local custom GUCs for this purpose but it's not usually a great idea.
In most cases it is preferable to just use an ON COMMIT DROP temporary table with a single row containing the value of interest.
See:
Passing user id to PostgreSQL triggers
How do you use script variables in PostgreSQL?

Limit cast scope only to schema in PostgreSQL

Funambol in its administration documentation has that for running on newer PostgreSQL instances which are more strict with types and casting you have to add those casts:
CREATE FUNCTION pg_catalog.text(bigint) RETURNS text STRICT IMMUTABLE LANGUAGE SQL AS 'SELECT textin(int8out($1));';
CREATE CAST (bigint AS text) WITH FUNCTION pg_catalog.text(bigint) AS IMPLICIT;
CREATE FUNCTION pg_catalog.text(integer) RETURNS text STRICT IMMUTABLE LANGUAGE SQL AS 'SELECT textin(int4out($1));';
CREATE CAST (integer AS text) WITH FUNCTION pg_catalog.text(integer) AS IMPLICIT;
The problem is that in the same database (in PostgreSQL terminology) I have also other schemas which applications broke because of those casts (with "operator is not unique: unknown || integer" and hint "Could not choose a best candidate operator. You might need to add explicit type casts.") while they worked before.
So one solution is of course to define additional database and have only Funambol in there. But I am wondering if is there a way to define those casts so that they take effect only in Funambol's schema and not in whole database.
No, it's not possible in the way you imagine it. Casts are identified by source and target type, and so if both types are one of the built-in types, all users of the database will see the same casts between them. The only workaround along that line would be to create clones of the built-in data types, but don't go there. ;-)
So you either need to seek a fix with Funambol, or separate your applications into different databases, and perhaps link them back together with something like dblink.