How to make the extension relocatable? - postgresql

I don’t know how to make the extension relocatable. Question: how to make the extension move to another scheme. Below, the beginning is described. After that comes the creation of operators, functions, variances, mathematical expectation.
create schema IF NOT EXISTS complex;
--Mathematical expectation
--creating a complex data type
create type complex.complex as (re float, im float);
--creation of complex data type with the sum of complex numbers and the amount of numbers--
create type complex.complexSumAndCount as (complexSumVar complex.complex, complexCount integer);
--Creating the function of adding complex numbers
CREATE or REPLACE function complex.complexSumFunction (sum complex.complex, complexTempVar complex.complex)
RETURNS complex.complex as
$$
BEGIN
IF sum is not null and complexTempVar is not null then
sum.re := coalesce(sum.re, 0) + coalesce(complexTempVar.re, 0);
sum.im := coalesce(sum.im, 0) + coalesce(complexTempVar.im, 0);
end IF;
RETURN sum;
end; $$LANGUAGE plpgSQL;

OK, posting a link to a github repo is probably not the recommended way to improve your question. You also still haven't told me whether you are actually trying to write an extension or not.
I am going to guess that you are not since you don't seem to have a .control file.
If what you are trying to do instead is be able to write
select '(6,44)'::complex;
rather than
select '(6,44)'::complex.complex;
then what you need to know about is the search_path.
This controls what schemas will be searched for objects (types, tables, functions etc.) when you do not explicitly specify a schema.
So - you have two options. You can add your "complex" schema to your search_path when you want to run queries. Or you can put your "complex" type and functions in your current search_path.
You can set your search_path temporarily (for the current transaction or session) with:
SET search_path = public, complex;
You can change the default for your user or for your database with something like:
ALTER USER myuser SET search_path = public, complex;
ALTER USER mydatabase SET search_path = public complex;
The second option is to load your "complex" code into a schema that is already in your search_path. To do this you would remove all reference to a schema from your script1.sql file.
create type complex as (re float, im float);
create type complexSumAndCount as (complexSumVar complex.complex, complexCount integer);
...
Then, when you load it, your types and functions will be created in the first schema that can be found in your search_path. It is good practice to set this to exactly what you want.
SET search_path = public;
\i script1.sql
or from the command-line
PGOPTIONS="--search_path=public" psql -U myuser -d mydb -f script1.sql
I hope that helps. If it isn't what you are after then I'm afraid you will need to post a new question and explain precisely what you are trying to do. If you want to have a longer conversation about your problems then the postgresql mailing lists are probably a good place to try.

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.

Postgres 10 - Targeting schema's function on a multiple schema Database

I'm running PostgresSQL 10, and I have several schemas on my DB with multiple functions. I've created a schemaless script with all the functions on it (I've removed the schema prefix), with this, everytime i create a new schema, I ran the migration and create all the functions as well.
This was necessary/requested for a better data separation between customers. All the schemas are twins in terms of structure.
All was fine until I figured that SchemaA was calling a function from public. Even if I call:
SchemaA.myFunction(p_param1:= 'A', p_param2:= 'B').
If this "myFunction" calls another from the inside, it will target public schema by default.
The only way I made it work, was using an input parameter called p_user_schema myFunction(p_param1, p_param2, p_user_schema) and add the following statement as the first line of myFunction body.
EXECUTE FORMAT('SET search_path TO %L', p_user_schema);
I've 147 functions, I will need to adapt each of these, does anyone know a better way to target the callers schema, by callers I mean the prefix schema used on the main call.
You can set the search path at the function level with the current user as the 1st one
CREATE OR REPLACE FUNCTION schemaA.myfunction()
RETURNS ..
AS $$
...
$$ LANGUAGE SQL
SET SEARCH_PATH = "$user", public;

Selecting column name from other database table through function in PostgreSQL

Here i need to select a column name by using function(stored procedure) which is present in other database table using PostgreSQL.
I have sql server query as shown below.
Example:
create procedure sp_testing
as
if not exists ( select ssn from testdb..testtable) /*ssn is the column-name of testtable which exists in testdb database */
...
Q: Can i do the same in PostgreSQL?
Your question is not very clear, but if you want to know if a column by a certain name exists in a table by a certain name in a remote PostgreSQL database, then you should first set up a foreign data wrapper, which is a multi-stage process. Then to test the existence of a certain column in a table you need to formulate a query that conforms to the standards of the particular DBMS that you are connecting to. Use the remote information_schema.tables table for optimal compatibility (which is here specified as remote_tables which you must have defined with a prior CREATE FOREIGN TABLE command):
CREATE FUNCTION sp_testing () AS $$
BEGIN
PERFORM *
FROM remote_tables
WHERE table_name = 'testtable'
AND column_name = 'ssn';
IF NOT FOUND THEN
...
END IF;
END;
$$ LANGUAGE plpgsql;
If you want to connect to another type of DBMS, you need to write some custom function in f.i. C or perl and then call that from within a PostgreSQL function on your local machine. The test on the column is then best done inside the function which should therefore take connection parameters, table name and column name as parameters, and return a boolean to inform the result.
Before you start testing this, make sure that you read all the documentation on connecting to remote servers and learning PL/pgSQL first would also be a nice gesture to demonstrate your own efforts before you ask for help.

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.

Postgresql: is "public." an standard way to fully qualify table name in Postgresql?

If i don't qualify a "public." on account_category table, out account_category will have a conflict with account_category table name.
Does "public." also works on other rdbms?
CREATE OR REPLACE FUNCTION X_RAIN(x VARCHAR, OUT user_id VARCHAR, out account_category varchar, out depth int) returns setof record
AS
$$
BEGIN
return query
select uar.account_id, c.account_category, c.depth
from account_with_types_chart_of_account uar
inner join public.account_category c using(account_category_id);
END;
$$ LANGUAGE 'plpgsql';
Regarding public in PostgreSQL, public is defined as the default schema name when no schema name is specified. However, this can changed in the postgresql.conf file on the search_path = xxx line. To see what your current default schemas are set to issue the following SQL command:
SHOW_ search_path;
If you want to change your default schema path in your open query session, issue the following SQL command:
SET search_path = new_path;
However, in the example you posted I believe that the naming conflict you are having problems with is not with the schema name but with the function parameter name account_category and the table name account_category. You could rename your parameter name to avoid this conflict. In databases with many schemas, for clarities sake I often explicitly specify public at the start of database object names.
Regarding your second question, I don't think PostgreSQL is unique in its usage of public, but I do know that many other databases do their schemas in a different way.
Public is the default schema name.
For example, in MySQL it doesn't have schema (if I recall). Also, if you use another schema instead of public, your code will break.
http://www.postgresql.org/docs/8.3/interactive/ddl-schemas.html
I'd recommend using another variable name. There's probably another way too.
The conflict happens because you used the same name for your variable and table name.
This is a very bad choice of naming, and can lead to many problems.
For example:
create function x (somename TEXT) returns bool as $$
declare
tempbool int4;
begin
select true INTO tempbool from some_table where somename = somename;
return tempbool;
end;
$$ language plpgsql;
This code basically doesn't make any sense, because parser is not able to tell what "somename = somename" means. Same goes for table names (to some degree).
Generally you want your identifiers (table names, column names, variable names) to be unique.
I prefer to use "in_" prefix for arguments, but your choice of naming schema might be different.