Implement function-local GUC parameter settings, as per recent discussion.
There are still some loose ends: I didn't do anything about the SET FROM CURRENT idea yet, and it's not real clear whether we are happy with the interaction of SET LOCAL with function-local settings. The documentation is a bit spartan, too.
This commit is contained in:
parent
fcfe801ab8
commit
2abae34a2e
@ -1,4 +1,4 @@
|
|||||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.155 2007/06/20 19:24:05 neilc Exp $ -->
|
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.156 2007/09/03 00:39:11 tgl Exp $ -->
|
||||||
<!--
|
<!--
|
||||||
Documentation of the system catalogs, directed toward PostgreSQL developers
|
Documentation of the system catalogs, directed toward PostgreSQL developers
|
||||||
-->
|
-->
|
||||||
@ -3635,6 +3635,13 @@
|
|||||||
</entry>
|
</entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><structfield>proconfig</structfield></entry>
|
||||||
|
<entry><type>text[]</type></entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>Function's local settings for run-time configuration variables</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry><structfield>proacl</structfield></entry>
|
<entry><structfield>proacl</structfield></entry>
|
||||||
<entry><type>aclitem[]</type></entry>
|
<entry><type>aclitem[]</type></entry>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$PostgreSQL: pgsql/doc/src/sgml/ref/alter_function.sgml,v 1.13 2007/01/22 01:35:19 tgl Exp $
|
$PostgreSQL: pgsql/doc/src/sgml/ref/alter_function.sgml,v 1.14 2007/09/03 00:39:12 tgl Exp $
|
||||||
PostgreSQL documentation
|
PostgreSQL documentation
|
||||||
-->
|
-->
|
||||||
|
|
||||||
@ -36,6 +36,8 @@ where <replaceable class="PARAMETER">action</replaceable> is one of:
|
|||||||
[ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER
|
[ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER
|
||||||
COST <replaceable class="parameter">execution_cost</replaceable>
|
COST <replaceable class="parameter">execution_cost</replaceable>
|
||||||
ROWS <replaceable class="parameter">result_rows</replaceable>
|
ROWS <replaceable class="parameter">result_rows</replaceable>
|
||||||
|
SET <replaceable class="parameter">parameter</replaceable> { TO | = } { <replaceable class="parameter">value</replaceable> | DEFAULT }
|
||||||
|
RESET <replaceable class="parameter">parameter</replaceable>
|
||||||
</synopsis>
|
</synopsis>
|
||||||
</refsynopsisdiv>
|
</refsynopsisdiv>
|
||||||
|
|
||||||
@ -212,6 +214,28 @@ where <replaceable class="PARAMETER">action</replaceable> is one of:
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><replaceable>parameter</replaceable></term>
|
||||||
|
<term><replaceable>value</replaceable></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Add or change the assignment to be made to a configuration parameter
|
||||||
|
when the function is called. If
|
||||||
|
<replaceable>value</replaceable> is <literal>DEFAULT</literal>
|
||||||
|
or, equivalently, <literal>RESET</literal> is used, the function-local
|
||||||
|
setting is removed, so that the function executes with the value
|
||||||
|
present in its environment. Use <literal>RESET
|
||||||
|
ALL</literal> to clear all function-local settings.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
See <xref linkend="sql-set" endterm="sql-set-title"> and
|
||||||
|
<xref linkend="runtime-config">
|
||||||
|
for more information about allowed parameter names and values.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><literal>RESTRICT</literal></term>
|
<term><literal>RESTRICT</literal></term>
|
||||||
|
|
||||||
@ -250,6 +274,22 @@ ALTER FUNCTION sqrt(integer) OWNER TO joe;
|
|||||||
ALTER FUNCTION sqrt(integer) SET SCHEMA maths;
|
ALTER FUNCTION sqrt(integer) SET SCHEMA maths;
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
To adjust the search path that is automatically set for a function:
|
||||||
|
<programlisting>
|
||||||
|
ALTER FUNCTION check_password(text) SET search_path = admin, pg_temp;
|
||||||
|
</programlisting>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
To disable automatic setting of <varname>search_path</> for a function:
|
||||||
|
<programlisting>
|
||||||
|
ALTER FUNCTION check_password(text) RESET search_path;
|
||||||
|
</programlisting>
|
||||||
|
The function will now execute with whatever search path is used by its
|
||||||
|
caller.
|
||||||
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
@ -260,6 +300,7 @@ ALTER FUNCTION sqrt(integer) SET SCHEMA maths;
|
|||||||
FUNCTION</> statement in the SQL standard. The standard allows more
|
FUNCTION</> statement in the SQL standard. The standard allows more
|
||||||
properties of a function to be modified, but does not provide the
|
properties of a function to be modified, but does not provide the
|
||||||
ability to rename a function, make a function a security definer,
|
ability to rename a function, make a function a security definer,
|
||||||
|
attach configuration parameter values to a function,
|
||||||
or change the owner, schema, or volatility of a function. The standard also
|
or change the owner, schema, or volatility of a function. The standard also
|
||||||
requires the <literal>RESTRICT</> key word, which is optional in
|
requires the <literal>RESTRICT</> key word, which is optional in
|
||||||
<productname>PostgreSQL</>.
|
<productname>PostgreSQL</>.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$PostgreSQL: pgsql/doc/src/sgml/ref/create_function.sgml,v 1.75 2007/04/23 16:52:53 neilc Exp $
|
$PostgreSQL: pgsql/doc/src/sgml/ref/create_function.sgml,v 1.76 2007/09/03 00:39:13 tgl Exp $
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<refentry id="SQL-CREATEFUNCTION">
|
<refentry id="SQL-CREATEFUNCTION">
|
||||||
@ -28,6 +28,7 @@ CREATE [ OR REPLACE ] FUNCTION
|
|||||||
| [ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER
|
| [ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER
|
||||||
| COST <replaceable class="parameter">execution_cost</replaceable>
|
| COST <replaceable class="parameter">execution_cost</replaceable>
|
||||||
| ROWS <replaceable class="parameter">result_rows</replaceable>
|
| ROWS <replaceable class="parameter">result_rows</replaceable>
|
||||||
|
| SET <replaceable class="parameter">parameter</replaceable> { TO | = } { <replaceable class="parameter">value</replaceable> | DEFAULT }
|
||||||
| AS '<replaceable class="parameter">definition</replaceable>'
|
| AS '<replaceable class="parameter">definition</replaceable>'
|
||||||
| AS '<replaceable class="parameter">obj_file</replaceable>', '<replaceable class="parameter">link_symbol</replaceable>'
|
| AS '<replaceable class="parameter">obj_file</replaceable>', '<replaceable class="parameter">link_symbol</replaceable>'
|
||||||
} ...
|
} ...
|
||||||
@ -71,6 +72,8 @@ CREATE [ OR REPLACE ] FUNCTION
|
|||||||
triggers, etc. that refer to the old function. Use
|
triggers, etc. that refer to the old function. Use
|
||||||
<command>CREATE OR REPLACE FUNCTION</command> to change a function
|
<command>CREATE OR REPLACE FUNCTION</command> to change a function
|
||||||
definition without breaking objects that refer to the function.
|
definition without breaking objects that refer to the function.
|
||||||
|
Also, <command>ALTER FUNCTION</> can be used to change most of the
|
||||||
|
auxiliary properties of an existing function.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@ -320,6 +323,24 @@ CREATE [ OR REPLACE ] FUNCTION
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><replaceable>parameter</replaceable></term>
|
||||||
|
<term><replaceable>value</replaceable></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The <literal>SET</> clause causes the specified configuration
|
||||||
|
parameter to be set to the specified value when the function is
|
||||||
|
entered, and then restored to its prior value when the function exits.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
See <xref linkend="sql-set" endterm="sql-set-title"> and
|
||||||
|
<xref linkend="runtime-config">
|
||||||
|
for more information about allowed parameter names and values.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><replaceable class="parameter">definition</replaceable></term>
|
<term><replaceable class="parameter">definition</replaceable></term>
|
||||||
|
|
||||||
@ -451,6 +472,18 @@ CREATE FUNCTION foo(int, out text) ...
|
|||||||
be escaped by doubling them.
|
be escaped by doubling them.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
If any <literal>SET</> clauses are attached to a function, then
|
||||||
|
the effects of a <command>SET LOCAL</> command executed inside the
|
||||||
|
function are restricted to the function: the configuration parameter's
|
||||||
|
value is restored at function exit. This is true even for parameters
|
||||||
|
not mentioned in the <literal>SET</> clause(s). However, an ordinary
|
||||||
|
<command>SET</> command (without <literal>LOCAL</>) overrides the
|
||||||
|
<literal>SET</> clause, much as it would do for a previous <command>SET
|
||||||
|
LOCAL</> command: the effects of such a command will persist after
|
||||||
|
function exit, unless the current transaction is rolled back.
|
||||||
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
To be able to define a function, the user must have the
|
To be able to define a function, the user must have the
|
||||||
<literal>USAGE</literal> privilege on the language.
|
<literal>USAGE</literal> privilege on the language.
|
||||||
@ -530,28 +563,45 @@ SELECT * FROM dup(42);
|
|||||||
CREATE FUNCTION check_password(uname TEXT, pass TEXT)
|
CREATE FUNCTION check_password(uname TEXT, pass TEXT)
|
||||||
RETURNS BOOLEAN AS $$
|
RETURNS BOOLEAN AS $$
|
||||||
DECLARE passed BOOLEAN;
|
DECLARE passed BOOLEAN;
|
||||||
old_path TEXT;
|
|
||||||
BEGIN
|
BEGIN
|
||||||
-- Save old search_path; notice we must qualify current_setting
|
|
||||||
-- to ensure we invoke the right function
|
|
||||||
old_path := pg_catalog.current_setting('search_path');
|
|
||||||
|
|
||||||
-- Set a secure search_path: trusted schemas, then 'pg_temp'.
|
|
||||||
-- We set is_local = true so that the old value will be restored
|
|
||||||
-- in event of an error before we reach the function end.
|
|
||||||
PERFORM pg_catalog.set_config('search_path', 'admin, pg_temp', true);
|
|
||||||
|
|
||||||
-- Do whatever secure work we came for.
|
|
||||||
SELECT (pwd = $2) INTO passed
|
SELECT (pwd = $2) INTO passed
|
||||||
FROM pwds
|
FROM pwds
|
||||||
WHERE username = $1;
|
WHERE username = $1;
|
||||||
|
|
||||||
-- Restore caller's search_path
|
|
||||||
PERFORM pg_catalog.set_config('search_path', old_path, true);
|
|
||||||
|
|
||||||
RETURN passed;
|
RETURN passed;
|
||||||
END;
|
END;
|
||||||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
$$ LANGUAGE plpgsql
|
||||||
|
SECURITY DEFINER
|
||||||
|
-- Set a secure search_path: trusted schema(s), then 'pg_temp'.
|
||||||
|
SET search_path = admin, pg_temp;
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Before <productname>PostgreSQL</productname> version 8.3, the
|
||||||
|
<literal>SET</> option was not available, and so older functions may
|
||||||
|
contain rather complicated logic to save, set, and restore
|
||||||
|
<varname>search_path</>. The <literal>SET</> option is far easier
|
||||||
|
to use for this purpose.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Another point to keep in mind is that by default, execute privilege
|
||||||
|
is granted to <literal>PUBLIC</> for newly created functions
|
||||||
|
(see <xref linkend="sql-grant" endterm="sql-grant-title"> for more
|
||||||
|
information). Frequently you will wish to restrict use of a security
|
||||||
|
definer function to only some users. To do that, you must revoke
|
||||||
|
the default <literal>PUBLIC</> privileges and then grant execute
|
||||||
|
privilege selectively. To avoid having a window where the new function
|
||||||
|
is accessible to all, create it and set the privileges within a single
|
||||||
|
transaction. For example:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<programlisting>
|
||||||
|
BEGIN;
|
||||||
|
CREATE FUNCTION check_password(uname TEXT, pass TEXT) ... SECURITY DEFINER;
|
||||||
|
REVOKE ALL ON FUNCTION check_password(uname TEXT, pass TEXT) FROM PUBLIC;
|
||||||
|
GRANT EXECUTE ON FUNCTION check_password(uname TEXT, pass TEXT) TO admins;
|
||||||
|
COMMIT;
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.246 2007/08/01 22:45:07 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.247 2007/09/03 00:39:13 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -117,7 +117,8 @@ typedef struct TransactionStateData
|
|||||||
int savepointLevel; /* savepoint level */
|
int savepointLevel; /* savepoint level */
|
||||||
TransState state; /* low-level state */
|
TransState state; /* low-level state */
|
||||||
TBlockState blockState; /* high-level state */
|
TBlockState blockState; /* high-level state */
|
||||||
int nestingLevel; /* nest depth */
|
int nestingLevel; /* transaction nesting depth */
|
||||||
|
int gucNestLevel; /* GUC context nesting depth */
|
||||||
MemoryContext curTransactionContext; /* my xact-lifetime context */
|
MemoryContext curTransactionContext; /* my xact-lifetime context */
|
||||||
ResourceOwner curTransactionOwner; /* my query resources */
|
ResourceOwner curTransactionOwner; /* my query resources */
|
||||||
List *childXids; /* subcommitted child XIDs */
|
List *childXids; /* subcommitted child XIDs */
|
||||||
@ -141,7 +142,8 @@ static TransactionStateData TopTransactionStateData = {
|
|||||||
TRANS_DEFAULT, /* transaction state */
|
TRANS_DEFAULT, /* transaction state */
|
||||||
TBLOCK_DEFAULT, /* transaction block state from the client
|
TBLOCK_DEFAULT, /* transaction block state from the client
|
||||||
* perspective */
|
* perspective */
|
||||||
0, /* nesting level */
|
0, /* transaction nesting depth */
|
||||||
|
0, /* GUC context nesting depth */
|
||||||
NULL, /* cur transaction context */
|
NULL, /* cur transaction context */
|
||||||
NULL, /* cur transaction resource owner */
|
NULL, /* cur transaction resource owner */
|
||||||
NIL, /* subcommitted child Xids */
|
NIL, /* subcommitted child Xids */
|
||||||
@ -1499,6 +1501,7 @@ StartTransaction(void)
|
|||||||
* initialize current transaction state fields
|
* initialize current transaction state fields
|
||||||
*/
|
*/
|
||||||
s->nestingLevel = 1;
|
s->nestingLevel = 1;
|
||||||
|
s->gucNestLevel = 1;
|
||||||
s->childXids = NIL;
|
s->childXids = NIL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1513,6 +1516,7 @@ StartTransaction(void)
|
|||||||
/*
|
/*
|
||||||
* initialize other subsystems for new transaction
|
* initialize other subsystems for new transaction
|
||||||
*/
|
*/
|
||||||
|
AtStart_GUC();
|
||||||
AtStart_Inval();
|
AtStart_Inval();
|
||||||
AtStart_Cache();
|
AtStart_Cache();
|
||||||
AfterTriggerBeginXact();
|
AfterTriggerBeginXact();
|
||||||
@ -1699,7 +1703,7 @@ CommitTransaction(void)
|
|||||||
/* Check we've released all catcache entries */
|
/* Check we've released all catcache entries */
|
||||||
AtEOXact_CatCache(true);
|
AtEOXact_CatCache(true);
|
||||||
|
|
||||||
AtEOXact_GUC(true, false);
|
AtEOXact_GUC(true, 1);
|
||||||
AtEOXact_SPI(true);
|
AtEOXact_SPI(true);
|
||||||
AtEOXact_on_commit_actions(true);
|
AtEOXact_on_commit_actions(true);
|
||||||
AtEOXact_Namespace(true);
|
AtEOXact_Namespace(true);
|
||||||
@ -1721,6 +1725,7 @@ CommitTransaction(void)
|
|||||||
s->transactionId = InvalidTransactionId;
|
s->transactionId = InvalidTransactionId;
|
||||||
s->subTransactionId = InvalidSubTransactionId;
|
s->subTransactionId = InvalidSubTransactionId;
|
||||||
s->nestingLevel = 0;
|
s->nestingLevel = 0;
|
||||||
|
s->gucNestLevel = 0;
|
||||||
s->childXids = NIL;
|
s->childXids = NIL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1920,7 +1925,7 @@ PrepareTransaction(void)
|
|||||||
AtEOXact_CatCache(true);
|
AtEOXact_CatCache(true);
|
||||||
|
|
||||||
/* PREPARE acts the same as COMMIT as far as GUC is concerned */
|
/* PREPARE acts the same as COMMIT as far as GUC is concerned */
|
||||||
AtEOXact_GUC(true, false);
|
AtEOXact_GUC(true, 1);
|
||||||
AtEOXact_SPI(true);
|
AtEOXact_SPI(true);
|
||||||
AtEOXact_on_commit_actions(true);
|
AtEOXact_on_commit_actions(true);
|
||||||
AtEOXact_Namespace(true);
|
AtEOXact_Namespace(true);
|
||||||
@ -1941,6 +1946,7 @@ PrepareTransaction(void)
|
|||||||
s->transactionId = InvalidTransactionId;
|
s->transactionId = InvalidTransactionId;
|
||||||
s->subTransactionId = InvalidSubTransactionId;
|
s->subTransactionId = InvalidSubTransactionId;
|
||||||
s->nestingLevel = 0;
|
s->nestingLevel = 0;
|
||||||
|
s->gucNestLevel = 0;
|
||||||
s->childXids = NIL;
|
s->childXids = NIL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2075,7 +2081,7 @@ AbortTransaction(void)
|
|||||||
false, true);
|
false, true);
|
||||||
AtEOXact_CatCache(false);
|
AtEOXact_CatCache(false);
|
||||||
|
|
||||||
AtEOXact_GUC(false, false);
|
AtEOXact_GUC(false, 1);
|
||||||
AtEOXact_SPI(false);
|
AtEOXact_SPI(false);
|
||||||
AtEOXact_on_commit_actions(false);
|
AtEOXact_on_commit_actions(false);
|
||||||
AtEOXact_Namespace(false);
|
AtEOXact_Namespace(false);
|
||||||
@ -2124,6 +2130,7 @@ CleanupTransaction(void)
|
|||||||
s->transactionId = InvalidTransactionId;
|
s->transactionId = InvalidTransactionId;
|
||||||
s->subTransactionId = InvalidSubTransactionId;
|
s->subTransactionId = InvalidSubTransactionId;
|
||||||
s->nestingLevel = 0;
|
s->nestingLevel = 0;
|
||||||
|
s->gucNestLevel = 0;
|
||||||
s->childXids = NIL;
|
s->childXids = NIL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3788,7 +3795,7 @@ CommitSubTransaction(void)
|
|||||||
RESOURCE_RELEASE_AFTER_LOCKS,
|
RESOURCE_RELEASE_AFTER_LOCKS,
|
||||||
true, false);
|
true, false);
|
||||||
|
|
||||||
AtEOXact_GUC(true, true);
|
AtEOXact_GUC(true, s->gucNestLevel);
|
||||||
AtEOSubXact_SPI(true, s->subTransactionId);
|
AtEOSubXact_SPI(true, s->subTransactionId);
|
||||||
AtEOSubXact_on_commit_actions(true, s->subTransactionId,
|
AtEOSubXact_on_commit_actions(true, s->subTransactionId,
|
||||||
s->parent->subTransactionId);
|
s->parent->subTransactionId);
|
||||||
@ -3901,7 +3908,7 @@ AbortSubTransaction(void)
|
|||||||
RESOURCE_RELEASE_AFTER_LOCKS,
|
RESOURCE_RELEASE_AFTER_LOCKS,
|
||||||
false, false);
|
false, false);
|
||||||
|
|
||||||
AtEOXact_GUC(false, true);
|
AtEOXact_GUC(false, s->gucNestLevel);
|
||||||
AtEOSubXact_SPI(false, s->subTransactionId);
|
AtEOSubXact_SPI(false, s->subTransactionId);
|
||||||
AtEOSubXact_on_commit_actions(false, s->subTransactionId,
|
AtEOSubXact_on_commit_actions(false, s->subTransactionId,
|
||||||
s->parent->subTransactionId);
|
s->parent->subTransactionId);
|
||||||
@ -4017,6 +4024,7 @@ PushTransaction(void)
|
|||||||
s->subTransactionId = currentSubTransactionId;
|
s->subTransactionId = currentSubTransactionId;
|
||||||
s->parent = p;
|
s->parent = p;
|
||||||
s->nestingLevel = p->nestingLevel + 1;
|
s->nestingLevel = p->nestingLevel + 1;
|
||||||
|
s->gucNestLevel = NewGUCNestLevel();
|
||||||
s->savepointLevel = p->savepointLevel;
|
s->savepointLevel = p->savepointLevel;
|
||||||
s->state = TRANS_DEFAULT;
|
s->state = TRANS_DEFAULT;
|
||||||
s->blockState = TBLOCK_SUBBEGIN;
|
s->blockState = TBLOCK_SUBBEGIN;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/catalog/pg_aggregate.c,v 1.86 2007/04/02 03:49:37 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/catalog/pg_aggregate.c,v 1.87 2007/09/03 00:39:14 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -212,6 +212,7 @@ AggregateCreate(const char *aggName,
|
|||||||
PointerGetDatum(NULL), /* allParamTypes */
|
PointerGetDatum(NULL), /* allParamTypes */
|
||||||
PointerGetDatum(NULL), /* parameterModes */
|
PointerGetDatum(NULL), /* parameterModes */
|
||||||
PointerGetDatum(NULL), /* parameterNames */
|
PointerGetDatum(NULL), /* parameterNames */
|
||||||
|
PointerGetDatum(NULL), /* proconfig */
|
||||||
1, /* procost */
|
1, /* procost */
|
||||||
0); /* prorows */
|
0); /* prorows */
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.145 2007/06/06 23:00:37 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.146 2007/09/03 00:39:14 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -49,9 +49,9 @@ static bool match_prosrc_to_literal(const char *prosrc, const char *literal,
|
|||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* ProcedureCreate
|
* ProcedureCreate
|
||||||
*
|
*
|
||||||
* Note: allParameterTypes, parameterModes, parameterNames are either arrays
|
* Note: allParameterTypes, parameterModes, parameterNames, and proconfig
|
||||||
* of the proper types or NULL. We declare them Datum, not "ArrayType *",
|
* are either arrays of the proper types or NULL. We declare them Datum,
|
||||||
* to avoid importing array.h into pg_proc.h.
|
* not "ArrayType *", to avoid importing array.h into pg_proc.h.
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
Oid
|
Oid
|
||||||
@ -72,6 +72,7 @@ ProcedureCreate(const char *procedureName,
|
|||||||
Datum allParameterTypes,
|
Datum allParameterTypes,
|
||||||
Datum parameterModes,
|
Datum parameterModes,
|
||||||
Datum parameterNames,
|
Datum parameterNames,
|
||||||
|
Datum proconfig,
|
||||||
float4 procost,
|
float4 procost,
|
||||||
float4 prorows)
|
float4 prorows)
|
||||||
{
|
{
|
||||||
@ -251,6 +252,10 @@ ProcedureCreate(const char *procedureName,
|
|||||||
CStringGetDatum(prosrc));
|
CStringGetDatum(prosrc));
|
||||||
values[Anum_pg_proc_probin - 1] = DirectFunctionCall1(textin,
|
values[Anum_pg_proc_probin - 1] = DirectFunctionCall1(textin,
|
||||||
CStringGetDatum(probin));
|
CStringGetDatum(probin));
|
||||||
|
if (proconfig != PointerGetDatum(NULL))
|
||||||
|
values[Anum_pg_proc_proconfig - 1] = proconfig;
|
||||||
|
else
|
||||||
|
nulls[Anum_pg_proc_proconfig - 1] = 'n';
|
||||||
/* start out with empty permissions */
|
/* start out with empty permissions */
|
||||||
nulls[Anum_pg_proc_proacl - 1] = 'n';
|
nulls[Anum_pg_proc_proacl - 1] = 'n';
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.83 2007/04/02 03:49:37 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.84 2007/09/03 00:39:15 tgl Exp $
|
||||||
*
|
*
|
||||||
* DESCRIPTION
|
* DESCRIPTION
|
||||||
* These routines take the parse tree and pick out the
|
* These routines take the parse tree and pick out the
|
||||||
@ -50,10 +50,14 @@
|
|||||||
#include "utils/acl.h"
|
#include "utils/acl.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/fmgroids.h"
|
#include "utils/fmgroids.h"
|
||||||
|
#include "utils/guc.h"
|
||||||
#include "utils/lsyscache.h"
|
#include "utils/lsyscache.h"
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
|
|
||||||
static void AlterFunctionOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId);
|
|
||||||
|
static void AlterFunctionOwner_internal(Relation rel, HeapTuple tup,
|
||||||
|
Oid newOwnerId);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Examine the RETURNS clause of the CREATE FUNCTION statement
|
* Examine the RETURNS clause of the CREATE FUNCTION statement
|
||||||
@ -267,13 +271,15 @@ examine_parameter_list(List *parameters, Oid languageOid,
|
|||||||
* FUNCTION and ALTER FUNCTION and return it via one of the out
|
* FUNCTION and ALTER FUNCTION and return it via one of the out
|
||||||
* parameters. Returns true if the passed option was recognized. If
|
* parameters. Returns true if the passed option was recognized. If
|
||||||
* the out parameter we were going to assign to points to non-NULL,
|
* the out parameter we were going to assign to points to non-NULL,
|
||||||
* raise a duplicate error.
|
* raise a duplicate-clause error. (We don't try to detect duplicate
|
||||||
|
* SET parameters though --- if you're redundant, the last one wins.)
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
compute_common_attribute(DefElem *defel,
|
compute_common_attribute(DefElem *defel,
|
||||||
DefElem **volatility_item,
|
DefElem **volatility_item,
|
||||||
DefElem **strict_item,
|
DefElem **strict_item,
|
||||||
DefElem **security_item,
|
DefElem **security_item,
|
||||||
|
List **set_items,
|
||||||
DefElem **cost_item,
|
DefElem **cost_item,
|
||||||
DefElem **rows_item)
|
DefElem **rows_item)
|
||||||
{
|
{
|
||||||
@ -298,6 +304,10 @@ compute_common_attribute(DefElem *defel,
|
|||||||
|
|
||||||
*security_item = defel;
|
*security_item = defel;
|
||||||
}
|
}
|
||||||
|
else if (strcmp(defel->defname, "set") == 0)
|
||||||
|
{
|
||||||
|
*set_items = lappend(*set_items, defel->arg);
|
||||||
|
}
|
||||||
else if (strcmp(defel->defname, "cost") == 0)
|
else if (strcmp(defel->defname, "cost") == 0)
|
||||||
{
|
{
|
||||||
if (*cost_item)
|
if (*cost_item)
|
||||||
@ -343,6 +353,51 @@ interpret_func_volatility(DefElem *defel)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Update a proconfig value according to a list of SET and RESET items.
|
||||||
|
*
|
||||||
|
* The input and result may be NULL to signify a null entry.
|
||||||
|
*/
|
||||||
|
static ArrayType *
|
||||||
|
update_proconfig_value(ArrayType *a, List *set_items)
|
||||||
|
{
|
||||||
|
ListCell *l;
|
||||||
|
|
||||||
|
foreach(l, set_items)
|
||||||
|
{
|
||||||
|
Node *sitem = (Node *) lfirst(l);
|
||||||
|
|
||||||
|
if (IsA(sitem, VariableSetStmt))
|
||||||
|
{
|
||||||
|
VariableSetStmt *sstmt = (VariableSetStmt *) sitem;
|
||||||
|
|
||||||
|
if (sstmt->args)
|
||||||
|
{
|
||||||
|
char *valuestr;
|
||||||
|
|
||||||
|
valuestr = flatten_set_variable_args(sstmt->name, sstmt->args);
|
||||||
|
a = GUCArrayAdd(a, sstmt->name, valuestr);
|
||||||
|
}
|
||||||
|
else /* SET TO DEFAULT */
|
||||||
|
a = GUCArrayDelete(a, sstmt->name);
|
||||||
|
}
|
||||||
|
else if (IsA(sitem, VariableResetStmt))
|
||||||
|
{
|
||||||
|
VariableResetStmt *rstmt = (VariableResetStmt *) sitem;
|
||||||
|
|
||||||
|
if (strcmp(rstmt->name, "all") == 0)
|
||||||
|
a = NULL; /* RESET ALL */
|
||||||
|
else
|
||||||
|
a = GUCArrayDelete(a, rstmt->name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
elog(ERROR, "unexpected node type: %d", nodeTag(sitem));
|
||||||
|
}
|
||||||
|
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Dissect the list of options assembled in gram.y into function
|
* Dissect the list of options assembled in gram.y into function
|
||||||
* attributes.
|
* attributes.
|
||||||
@ -354,6 +409,7 @@ compute_attributes_sql_style(List *options,
|
|||||||
char *volatility_p,
|
char *volatility_p,
|
||||||
bool *strict_p,
|
bool *strict_p,
|
||||||
bool *security_definer,
|
bool *security_definer,
|
||||||
|
ArrayType **proconfig,
|
||||||
float4 *procost,
|
float4 *procost,
|
||||||
float4 *prorows)
|
float4 *prorows)
|
||||||
{
|
{
|
||||||
@ -363,6 +419,7 @@ compute_attributes_sql_style(List *options,
|
|||||||
DefElem *volatility_item = NULL;
|
DefElem *volatility_item = NULL;
|
||||||
DefElem *strict_item = NULL;
|
DefElem *strict_item = NULL;
|
||||||
DefElem *security_item = NULL;
|
DefElem *security_item = NULL;
|
||||||
|
List *set_items = NIL;
|
||||||
DefElem *cost_item = NULL;
|
DefElem *cost_item = NULL;
|
||||||
DefElem *rows_item = NULL;
|
DefElem *rows_item = NULL;
|
||||||
|
|
||||||
@ -390,6 +447,7 @@ compute_attributes_sql_style(List *options,
|
|||||||
&volatility_item,
|
&volatility_item,
|
||||||
&strict_item,
|
&strict_item,
|
||||||
&security_item,
|
&security_item,
|
||||||
|
&set_items,
|
||||||
&cost_item,
|
&cost_item,
|
||||||
&rows_item))
|
&rows_item))
|
||||||
{
|
{
|
||||||
@ -429,6 +487,8 @@ compute_attributes_sql_style(List *options,
|
|||||||
*strict_p = intVal(strict_item->arg);
|
*strict_p = intVal(strict_item->arg);
|
||||||
if (security_item)
|
if (security_item)
|
||||||
*security_definer = intVal(security_item->arg);
|
*security_definer = intVal(security_item->arg);
|
||||||
|
if (set_items)
|
||||||
|
*proconfig = update_proconfig_value(NULL, set_items);
|
||||||
if (cost_item)
|
if (cost_item)
|
||||||
{
|
{
|
||||||
*procost = defGetNumeric(cost_item);
|
*procost = defGetNumeric(cost_item);
|
||||||
@ -557,6 +617,7 @@ CreateFunction(CreateFunctionStmt *stmt)
|
|||||||
bool isStrict,
|
bool isStrict,
|
||||||
security;
|
security;
|
||||||
char volatility;
|
char volatility;
|
||||||
|
ArrayType *proconfig;
|
||||||
float4 procost;
|
float4 procost;
|
||||||
float4 prorows;
|
float4 prorows;
|
||||||
HeapTuple languageTuple;
|
HeapTuple languageTuple;
|
||||||
@ -577,6 +638,7 @@ CreateFunction(CreateFunctionStmt *stmt)
|
|||||||
isStrict = false;
|
isStrict = false;
|
||||||
security = false;
|
security = false;
|
||||||
volatility = PROVOLATILE_VOLATILE;
|
volatility = PROVOLATILE_VOLATILE;
|
||||||
|
proconfig = NULL;
|
||||||
procost = -1; /* indicates not set */
|
procost = -1; /* indicates not set */
|
||||||
prorows = -1; /* indicates not set */
|
prorows = -1; /* indicates not set */
|
||||||
|
|
||||||
@ -584,7 +646,7 @@ CreateFunction(CreateFunctionStmt *stmt)
|
|||||||
compute_attributes_sql_style(stmt->options,
|
compute_attributes_sql_style(stmt->options,
|
||||||
&as_clause, &language,
|
&as_clause, &language,
|
||||||
&volatility, &isStrict, &security,
|
&volatility, &isStrict, &security,
|
||||||
&procost, &prorows);
|
&proconfig, &procost, &prorows);
|
||||||
|
|
||||||
/* Convert language name to canonical case */
|
/* Convert language name to canonical case */
|
||||||
languageName = case_translate_language_name(language);
|
languageName = case_translate_language_name(language);
|
||||||
@ -736,6 +798,7 @@ CreateFunction(CreateFunctionStmt *stmt)
|
|||||||
PointerGetDatum(allParameterTypes),
|
PointerGetDatum(allParameterTypes),
|
||||||
PointerGetDatum(parameterModes),
|
PointerGetDatum(parameterModes),
|
||||||
PointerGetDatum(parameterNames),
|
PointerGetDatum(parameterNames),
|
||||||
|
PointerGetDatum(proconfig),
|
||||||
procost,
|
procost,
|
||||||
prorows);
|
prorows);
|
||||||
}
|
}
|
||||||
@ -1084,6 +1147,7 @@ AlterFunction(AlterFunctionStmt *stmt)
|
|||||||
DefElem *volatility_item = NULL;
|
DefElem *volatility_item = NULL;
|
||||||
DefElem *strict_item = NULL;
|
DefElem *strict_item = NULL;
|
||||||
DefElem *security_def_item = NULL;
|
DefElem *security_def_item = NULL;
|
||||||
|
List *set_items = NIL;
|
||||||
DefElem *cost_item = NULL;
|
DefElem *cost_item = NULL;
|
||||||
DefElem *rows_item = NULL;
|
DefElem *rows_item = NULL;
|
||||||
|
|
||||||
@ -1121,6 +1185,7 @@ AlterFunction(AlterFunctionStmt *stmt)
|
|||||||
&volatility_item,
|
&volatility_item,
|
||||||
&strict_item,
|
&strict_item,
|
||||||
&security_def_item,
|
&security_def_item,
|
||||||
|
&set_items,
|
||||||
&cost_item,
|
&cost_item,
|
||||||
&rows_item) == false)
|
&rows_item) == false)
|
||||||
elog(ERROR, "option \"%s\" not recognized", defel->defname);
|
elog(ERROR, "option \"%s\" not recognized", defel->defname);
|
||||||
@ -1152,6 +1217,40 @@ AlterFunction(AlterFunctionStmt *stmt)
|
|||||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
errmsg("ROWS is not applicable when function does not return a set")));
|
errmsg("ROWS is not applicable when function does not return a set")));
|
||||||
}
|
}
|
||||||
|
if (set_items)
|
||||||
|
{
|
||||||
|
Datum datum;
|
||||||
|
bool isnull;
|
||||||
|
ArrayType *a;
|
||||||
|
Datum repl_val[Natts_pg_proc];
|
||||||
|
char repl_null[Natts_pg_proc];
|
||||||
|
char repl_repl[Natts_pg_proc];
|
||||||
|
|
||||||
|
/* extract existing proconfig setting */
|
||||||
|
datum = SysCacheGetAttr(PROCOID, tup, Anum_pg_proc_proconfig, &isnull);
|
||||||
|
a = isnull ? NULL : DatumGetArrayTypeP(datum);
|
||||||
|
|
||||||
|
/* update according to each SET or RESET item, left to right */
|
||||||
|
a = update_proconfig_value(a, set_items);
|
||||||
|
|
||||||
|
/* update the tuple */
|
||||||
|
memset(repl_repl, ' ', sizeof(repl_repl));
|
||||||
|
repl_repl[Anum_pg_proc_proconfig - 1] = 'r';
|
||||||
|
|
||||||
|
if (a == NULL)
|
||||||
|
{
|
||||||
|
repl_val[Anum_pg_proc_proconfig - 1] = (Datum) 0;
|
||||||
|
repl_null[Anum_pg_proc_proconfig - 1] = 'n';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
repl_val[Anum_pg_proc_proconfig - 1] = PointerGetDatum(a);
|
||||||
|
repl_null[Anum_pg_proc_proconfig - 1] = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
tup = heap_modifytuple(tup, RelationGetDescr(rel),
|
||||||
|
repl_val, repl_null, repl_repl);
|
||||||
|
}
|
||||||
|
|
||||||
/* Do the update */
|
/* Do the update */
|
||||||
simple_heap_update(rel, &tup->t_self, tup);
|
simple_heap_update(rel, &tup->t_self, tup);
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/commands/proclang.c,v 1.72 2007/03/26 16:58:38 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/commands/proclang.c,v 1.73 2007/09/03 00:39:15 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -142,6 +142,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
|
|||||||
PointerGetDatum(NULL),
|
PointerGetDatum(NULL),
|
||||||
PointerGetDatum(NULL),
|
PointerGetDatum(NULL),
|
||||||
PointerGetDatum(NULL),
|
PointerGetDatum(NULL),
|
||||||
|
PointerGetDatum(NULL),
|
||||||
1,
|
1,
|
||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
@ -174,6 +175,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
|
|||||||
PointerGetDatum(NULL),
|
PointerGetDatum(NULL),
|
||||||
PointerGetDatum(NULL),
|
PointerGetDatum(NULL),
|
||||||
PointerGetDatum(NULL),
|
PointerGetDatum(NULL),
|
||||||
|
PointerGetDatum(NULL),
|
||||||
1,
|
1,
|
||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.247 2007/06/23 22:12:50 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.248 2007/09/03 00:39:15 tgl Exp $
|
||||||
*
|
*
|
||||||
* HISTORY
|
* HISTORY
|
||||||
* AUTHOR DATE MAJOR EVENT
|
* AUTHOR DATE MAJOR EVENT
|
||||||
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include "access/heapam.h"
|
||||||
#include "catalog/pg_aggregate.h"
|
#include "catalog/pg_aggregate.h"
|
||||||
#include "catalog/pg_language.h"
|
#include "catalog/pg_language.h"
|
||||||
#include "catalog/pg_operator.h"
|
#include "catalog/pg_operator.h"
|
||||||
@ -2923,6 +2924,7 @@ inline_function(Oid funcid, Oid result_type, List *args,
|
|||||||
if (funcform->prolang != SQLlanguageId ||
|
if (funcform->prolang != SQLlanguageId ||
|
||||||
funcform->prosecdef ||
|
funcform->prosecdef ||
|
||||||
funcform->proretset ||
|
funcform->proretset ||
|
||||||
|
!heap_attisnull(func_tuple, Anum_pg_proc_proconfig) ||
|
||||||
funcform->pronargs != list_length(args))
|
funcform->pronargs != list_length(args))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.600 2007/08/22 05:13:50 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.601 2007/09/03 00:39:16 tgl Exp $
|
||||||
*
|
*
|
||||||
* HISTORY
|
* HISTORY
|
||||||
* AUTHOR DATE MAJOR EVENT
|
* AUTHOR DATE MAJOR EVENT
|
||||||
@ -4270,6 +4270,16 @@ common_func_opt_item:
|
|||||||
{
|
{
|
||||||
$$ = makeDefElem("rows", (Node *)$2);
|
$$ = makeDefElem("rows", (Node *)$2);
|
||||||
}
|
}
|
||||||
|
| SET set_rest
|
||||||
|
{
|
||||||
|
/* we abuse the normal content of a DefElem here */
|
||||||
|
$$ = makeDefElem("set", (Node *)$2);
|
||||||
|
}
|
||||||
|
| VariableResetStmt
|
||||||
|
{
|
||||||
|
/* we abuse the normal content of a DefElem here */
|
||||||
|
$$ = makeDefElem("set", $1);
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
createfunc_opt_item:
|
createfunc_opt_item:
|
||||||
@ -4564,13 +4574,13 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name
|
|||||||
n->newname = $6;
|
n->newname = $6;
|
||||||
$$ = (Node *)n;
|
$$ = (Node *)n;
|
||||||
}
|
}
|
||||||
| ALTER FUNCTION func_name func_args RENAME TO name
|
| ALTER FUNCTION function_with_argtypes RENAME TO name
|
||||||
{
|
{
|
||||||
RenameStmt *n = makeNode(RenameStmt);
|
RenameStmt *n = makeNode(RenameStmt);
|
||||||
n->renameType = OBJECT_FUNCTION;
|
n->renameType = OBJECT_FUNCTION;
|
||||||
n->object = $3;
|
n->object = $3->funcname;
|
||||||
n->objarg = extractArgTypes($4);
|
n->objarg = $3->funcargs;
|
||||||
n->newname = $7;
|
n->newname = $6;
|
||||||
$$ = (Node *)n;
|
$$ = (Node *)n;
|
||||||
}
|
}
|
||||||
| ALTER GROUP_P RoleId RENAME TO RoleId
|
| ALTER GROUP_P RoleId RENAME TO RoleId
|
||||||
@ -4755,13 +4765,13 @@ AlterObjectSchemaStmt:
|
|||||||
n->newschema = $6;
|
n->newschema = $6;
|
||||||
$$ = (Node *)n;
|
$$ = (Node *)n;
|
||||||
}
|
}
|
||||||
| ALTER FUNCTION func_name func_args SET SCHEMA name
|
| ALTER FUNCTION function_with_argtypes SET SCHEMA name
|
||||||
{
|
{
|
||||||
AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
|
AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
|
||||||
n->objectType = OBJECT_FUNCTION;
|
n->objectType = OBJECT_FUNCTION;
|
||||||
n->object = $3;
|
n->object = $3->funcname;
|
||||||
n->objarg = extractArgTypes($4);
|
n->objarg = $3->funcargs;
|
||||||
n->newschema = $7;
|
n->newschema = $6;
|
||||||
$$ = (Node *)n;
|
$$ = (Node *)n;
|
||||||
}
|
}
|
||||||
| ALTER SEQUENCE relation_expr SET SCHEMA name
|
| ALTER SEQUENCE relation_expr SET SCHEMA name
|
||||||
@ -4829,13 +4839,13 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
|
|||||||
n->newowner = $6;
|
n->newowner = $6;
|
||||||
$$ = (Node *)n;
|
$$ = (Node *)n;
|
||||||
}
|
}
|
||||||
| ALTER FUNCTION func_name func_args OWNER TO RoleId
|
| ALTER FUNCTION function_with_argtypes OWNER TO RoleId
|
||||||
{
|
{
|
||||||
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
|
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
|
||||||
n->objectType = OBJECT_FUNCTION;
|
n->objectType = OBJECT_FUNCTION;
|
||||||
n->object = $3;
|
n->object = $3->funcname;
|
||||||
n->objarg = extractArgTypes($4);
|
n->objarg = $3->funcargs;
|
||||||
n->newowner = $7;
|
n->newowner = $6;
|
||||||
$$ = (Node *)n;
|
$$ = (Node *)n;
|
||||||
}
|
}
|
||||||
| ALTER opt_procedural LANGUAGE name OWNER TO RoleId
|
| ALTER opt_procedural LANGUAGE name OWNER TO RoleId
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
#
|
#
|
||||||
#
|
#
|
||||||
# IDENTIFICATION
|
# IDENTIFICATION
|
||||||
# $PostgreSQL: pgsql/src/backend/utils/Gen_fmgrtab.sh,v 1.36 2007/06/05 21:31:06 tgl Exp $
|
# $PostgreSQL: pgsql/src/backend/utils/Gen_fmgrtab.sh,v 1.37 2007/09/03 00:39:17 tgl Exp $
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
|
|
||||||
@ -134,12 +134,12 @@ cat > "$$-$OIDSFILE" <<FuNkYfMgRsTuFf
|
|||||||
*/
|
*/
|
||||||
FuNkYfMgRsTuFf
|
FuNkYfMgRsTuFf
|
||||||
|
|
||||||
# Note assumption here that prosrc == $(NF-2).
|
# Note assumption here that prosrc == $(NF-3).
|
||||||
|
|
||||||
tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' < $SORTEDFILE | \
|
tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' < $SORTEDFILE | \
|
||||||
$AWK '
|
$AWK '
|
||||||
BEGIN { OFS = ""; }
|
BEGIN { OFS = ""; }
|
||||||
{ if (seenit[$(NF-2)]++ == 0) print "#define F_", $(NF-2), " ", $1; }' >> "$$-$OIDSFILE"
|
{ if (seenit[$(NF-3)]++ == 0) print "#define F_", $(NF-3), " ", $1; }' >> "$$-$OIDSFILE"
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
cleanup
|
cleanup
|
||||||
@ -184,9 +184,9 @@ cat > "$$-$TABLEFILE" <<FuNkYfMgRtAbStUfF
|
|||||||
|
|
||||||
FuNkYfMgRtAbStUfF
|
FuNkYfMgRtAbStUfF
|
||||||
|
|
||||||
# Note assumption here that prosrc == $(NF-2).
|
# Note assumption here that prosrc == $(NF-3).
|
||||||
|
|
||||||
$AWK '{ print "extern Datum", $(NF-2), "(PG_FUNCTION_ARGS);"; }' $SORTEDFILE >> "$$-$TABLEFILE"
|
$AWK '{ print "extern Datum", $(NF-3), "(PG_FUNCTION_ARGS);"; }' $SORTEDFILE >> "$$-$TABLEFILE"
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
cleanup
|
cleanup
|
||||||
@ -204,7 +204,7 @@ FuNkYfMgRtAbStUfF
|
|||||||
# may seem tedious, but avoid the temptation to write a quick x?y:z
|
# may seem tedious, but avoid the temptation to write a quick x?y:z
|
||||||
# conditional expression instead. Not all awks have conditional expressions.
|
# conditional expression instead. Not all awks have conditional expressions.
|
||||||
#
|
#
|
||||||
# Note assumptions here that prosrc == $(NF-2), pronargs == $13,
|
# Note assumptions here that prosrc == $(NF-3), pronargs == $13,
|
||||||
# proisstrict == $10, proretset == $11
|
# proisstrict == $10, proretset == $11
|
||||||
|
|
||||||
$AWK 'BEGIN {
|
$AWK 'BEGIN {
|
||||||
@ -212,7 +212,7 @@ $AWK 'BEGIN {
|
|||||||
Bool["f"] = "false"
|
Bool["f"] = "false"
|
||||||
}
|
}
|
||||||
{ printf (" { %d, \"%s\", %d, %s, %s, %s },\n"), \
|
{ printf (" { %d, \"%s\", %d, %s, %s, %s },\n"), \
|
||||||
$1, $(NF-2), $13, Bool[$10], Bool[$11], $(NF-2)
|
$1, $(NF-3), $13, Bool[$10], Bool[$11], $(NF-3)
|
||||||
}' $SORTEDFILE >> "$$-$TABLEFILE"
|
}' $SORTEDFILE >> "$$-$TABLEFILE"
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
|
@ -8,13 +8,14 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/utils/fmgr/fmgr.c,v 1.108 2007/07/31 15:49:49 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/fmgr/fmgr.c,v 1.109 2007/09/03 00:39:18 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include "access/heapam.h"
|
||||||
#include "access/tuptoaster.h"
|
#include "access/tuptoaster.h"
|
||||||
#include "catalog/pg_language.h"
|
#include "catalog/pg_language.h"
|
||||||
#include "catalog/pg_proc.h"
|
#include "catalog/pg_proc.h"
|
||||||
@ -23,9 +24,11 @@
|
|||||||
#include "parser/parse_expr.h"
|
#include "parser/parse_expr.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/fmgrtab.h"
|
#include "utils/fmgrtab.h"
|
||||||
|
#include "utils/guc.h"
|
||||||
#include "utils/lsyscache.h"
|
#include "utils/lsyscache.h"
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Declaration for old-style function pointer type. This is now used only
|
* Declaration for old-style function pointer type. This is now used only
|
||||||
* in fmgr_oldstyle() and is no longer exported.
|
* in fmgr_oldstyle() and is no longer exported.
|
||||||
@ -212,7 +215,13 @@ fmgr_info_cxt_security(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt,
|
|||||||
finfo->fn_strict = procedureStruct->proisstrict;
|
finfo->fn_strict = procedureStruct->proisstrict;
|
||||||
finfo->fn_retset = procedureStruct->proretset;
|
finfo->fn_retset = procedureStruct->proretset;
|
||||||
|
|
||||||
if (procedureStruct->prosecdef && !ignore_security)
|
/*
|
||||||
|
* If it has prosecdef set, or non-null proconfig, use
|
||||||
|
* fmgr_security_definer call handler.
|
||||||
|
*/
|
||||||
|
if (!ignore_security &&
|
||||||
|
(procedureStruct->prosecdef ||
|
||||||
|
!heap_attisnull(procedureTuple, Anum_pg_proc_proconfig)))
|
||||||
{
|
{
|
||||||
finfo->fn_addr = fmgr_security_definer;
|
finfo->fn_addr = fmgr_security_definer;
|
||||||
finfo->fn_oid = functionId;
|
finfo->fn_oid = functionId;
|
||||||
@ -826,34 +835,45 @@ fmgr_oldstyle(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Support for security definer functions
|
* Support for security-definer and proconfig-using functions. We support
|
||||||
|
* both of these features using the same call handler, because they are
|
||||||
|
* often used together and it would be inefficient (as well as notationally
|
||||||
|
* messy) to have two levels of call handler involved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct fmgr_security_definer_cache
|
struct fmgr_security_definer_cache
|
||||||
{
|
{
|
||||||
FmgrInfo flinfo;
|
FmgrInfo flinfo; /* lookup info for target function */
|
||||||
Oid userid;
|
Oid userid; /* userid to set, or InvalidOid */
|
||||||
|
ArrayType *proconfig; /* GUC values to set, or NULL */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Function handler for security definer functions. We extract the
|
* Function handler for security-definer/proconfig functions. We extract the
|
||||||
* OID of the actual function and do a fmgr lookup again. Then we
|
* OID of the actual function and do a fmgr lookup again. Then we fetch the
|
||||||
* look up the owner of the function and cache both the fmgr info and
|
* pg_proc row and copy the owner ID and proconfig fields. (All this info
|
||||||
* the owner ID. During the call we temporarily replace the flinfo
|
* is cached for the duration of the current query.) To execute a call,
|
||||||
* with the cached/looked-up one, while keeping the outer fcinfo
|
* we temporarily replace the flinfo with the cached/looked-up one, while
|
||||||
* (which contains all the actual arguments, etc.) intact.
|
* keeping the outer fcinfo (which contains all the actual arguments, etc.)
|
||||||
|
* intact. This is not re-entrant, but then the fcinfo itself can't be used
|
||||||
|
* re-entrantly anyway.
|
||||||
*/
|
*/
|
||||||
static Datum
|
static Datum
|
||||||
fmgr_security_definer(PG_FUNCTION_ARGS)
|
fmgr_security_definer(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
Datum result;
|
Datum result;
|
||||||
FmgrInfo *save_flinfo;
|
|
||||||
struct fmgr_security_definer_cache *volatile fcache;
|
struct fmgr_security_definer_cache *volatile fcache;
|
||||||
|
FmgrInfo *save_flinfo;
|
||||||
Oid save_userid;
|
Oid save_userid;
|
||||||
HeapTuple tuple;
|
volatile int save_nestlevel;
|
||||||
|
|
||||||
if (!fcinfo->flinfo->fn_extra)
|
if (!fcinfo->flinfo->fn_extra)
|
||||||
{
|
{
|
||||||
|
HeapTuple tuple;
|
||||||
|
Form_pg_proc procedureStruct;
|
||||||
|
Datum datum;
|
||||||
|
bool isnull;
|
||||||
|
MemoryContext oldcxt;
|
||||||
|
|
||||||
fcache = MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt,
|
fcache = MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt,
|
||||||
sizeof(*fcache));
|
sizeof(*fcache));
|
||||||
|
|
||||||
@ -867,7 +887,20 @@ fmgr_security_definer(PG_FUNCTION_ARGS)
|
|||||||
if (!HeapTupleIsValid(tuple))
|
if (!HeapTupleIsValid(tuple))
|
||||||
elog(ERROR, "cache lookup failed for function %u",
|
elog(ERROR, "cache lookup failed for function %u",
|
||||||
fcinfo->flinfo->fn_oid);
|
fcinfo->flinfo->fn_oid);
|
||||||
fcache->userid = ((Form_pg_proc) GETSTRUCT(tuple))->proowner;
|
procedureStruct = (Form_pg_proc) GETSTRUCT(tuple);
|
||||||
|
|
||||||
|
if (procedureStruct->prosecdef)
|
||||||
|
fcache->userid = procedureStruct->proowner;
|
||||||
|
|
||||||
|
datum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proconfig,
|
||||||
|
&isnull);
|
||||||
|
if (!isnull)
|
||||||
|
{
|
||||||
|
oldcxt = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt);
|
||||||
|
fcache->proconfig = DatumGetArrayTypePCopy(datum);
|
||||||
|
MemoryContextSwitchTo(oldcxt);
|
||||||
|
}
|
||||||
|
|
||||||
ReleaseSysCache(tuple);
|
ReleaseSysCache(tuple);
|
||||||
|
|
||||||
fcinfo->flinfo->fn_extra = fcache;
|
fcinfo->flinfo->fn_extra = fcache;
|
||||||
@ -876,25 +909,47 @@ fmgr_security_definer(PG_FUNCTION_ARGS)
|
|||||||
fcache = fcinfo->flinfo->fn_extra;
|
fcache = fcinfo->flinfo->fn_extra;
|
||||||
|
|
||||||
save_flinfo = fcinfo->flinfo;
|
save_flinfo = fcinfo->flinfo;
|
||||||
|
/* GetUserId is cheap enough that no harm in a wasted call */
|
||||||
save_userid = GetUserId();
|
save_userid = GetUserId();
|
||||||
|
if (fcache->proconfig) /* Need a new GUC nesting level */
|
||||||
|
save_nestlevel = NewGUCNestLevel();
|
||||||
|
else
|
||||||
|
save_nestlevel = 0; /* keep compiler quiet */
|
||||||
|
|
||||||
PG_TRY();
|
PG_TRY();
|
||||||
{
|
{
|
||||||
fcinfo->flinfo = &fcache->flinfo;
|
fcinfo->flinfo = &fcache->flinfo;
|
||||||
SetUserId(fcache->userid);
|
|
||||||
|
if (OidIsValid(fcache->userid))
|
||||||
|
SetUserId(fcache->userid);
|
||||||
|
|
||||||
|
if (fcache->proconfig)
|
||||||
|
{
|
||||||
|
/* The options are processed as if by SET LOCAL var = val */
|
||||||
|
ProcessGUCArray(fcache->proconfig,
|
||||||
|
(superuser() ? PGC_SUSET : PGC_USERSET),
|
||||||
|
PGC_S_SESSION,
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
|
||||||
result = FunctionCallInvoke(fcinfo);
|
result = FunctionCallInvoke(fcinfo);
|
||||||
}
|
}
|
||||||
PG_CATCH();
|
PG_CATCH();
|
||||||
{
|
{
|
||||||
fcinfo->flinfo = save_flinfo;
|
fcinfo->flinfo = save_flinfo;
|
||||||
SetUserId(save_userid);
|
if (fcache->proconfig)
|
||||||
|
AtEOXact_GUC(false, save_nestlevel);
|
||||||
|
if (OidIsValid(fcache->userid))
|
||||||
|
SetUserId(save_userid);
|
||||||
PG_RE_THROW();
|
PG_RE_THROW();
|
||||||
}
|
}
|
||||||
PG_END_TRY();
|
PG_END_TRY();
|
||||||
|
|
||||||
fcinfo->flinfo = save_flinfo;
|
fcinfo->flinfo = save_flinfo;
|
||||||
SetUserId(save_userid);
|
if (fcache->proconfig)
|
||||||
|
AtEOXact_GUC(true, save_nestlevel);
|
||||||
|
if (OidIsValid(fcache->userid))
|
||||||
|
SetUserId(save_userid);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/utils/init/miscinit.c,v 1.162 2007/02/15 23:23:23 alvherre Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/init/miscinit.c,v 1.163 2007/09/03 00:39:18 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -448,7 +448,12 @@ InitializeSessionUserId(const char *rolename)
|
|||||||
{
|
{
|
||||||
ArrayType *a = DatumGetArrayTypeP(datum);
|
ArrayType *a = DatumGetArrayTypeP(datum);
|
||||||
|
|
||||||
ProcessGUCArray(a, PGC_S_USER);
|
/*
|
||||||
|
* We process all the options at SUSET level. We assume that the
|
||||||
|
* right to insert an option into pg_authid was checked when it was
|
||||||
|
* inserted.
|
||||||
|
*/
|
||||||
|
ProcessGUCArray(a, PGC_SUSET, PGC_S_USER, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReleaseSysCache(roleTup);
|
ReleaseSysCache(roleTup);
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.176 2007/05/27 05:37:49 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.177 2007/09/03 00:39:18 tgl Exp $
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
@ -250,7 +250,12 @@ CheckMyDatabase(const char *name, bool am_superuser)
|
|||||||
{
|
{
|
||||||
ArrayType *a = DatumGetArrayTypeP(datum);
|
ArrayType *a = DatumGetArrayTypeP(datum);
|
||||||
|
|
||||||
ProcessGUCArray(a, PGC_S_DATABASE);
|
/*
|
||||||
|
* We process all the options at SUSET level. We assume that the
|
||||||
|
* right to insert an option into pg_database was checked when it
|
||||||
|
* was inserted.
|
||||||
|
*/
|
||||||
|
ProcessGUCArray(a, PGC_SUSET, PGC_S_DATABASE, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
* Written by Peter Eisentraut <peter_e@gmx.net>.
|
* Written by Peter Eisentraut <peter_e@gmx.net>.
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.414 2007/08/21 01:11:19 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.415 2007/09/03 00:39:19 tgl Exp $
|
||||||
*
|
*
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -2495,6 +2495,8 @@ static bool guc_dirty; /* TRUE if need to do commit/abort work */
|
|||||||
|
|
||||||
static bool reporting_enabled; /* TRUE to enable GUC_REPORT */
|
static bool reporting_enabled; /* TRUE to enable GUC_REPORT */
|
||||||
|
|
||||||
|
static int GUCNestLevel = 0; /* 1 when in main transaction */
|
||||||
|
|
||||||
|
|
||||||
static int guc_var_compare(const void *a, const void *b);
|
static int guc_var_compare(const void *a, const void *b);
|
||||||
static int guc_name_compare(const char *namea, const char *nameb);
|
static int guc_name_compare(const char *namea, const char *nameb);
|
||||||
@ -3388,17 +3390,16 @@ ResetAllOptions(void)
|
|||||||
static void
|
static void
|
||||||
push_old_value(struct config_generic * gconf)
|
push_old_value(struct config_generic * gconf)
|
||||||
{
|
{
|
||||||
int my_level = GetCurrentTransactionNestLevel();
|
|
||||||
GucStack *stack;
|
GucStack *stack;
|
||||||
|
|
||||||
/* If we're not inside a transaction, do nothing */
|
/* If we're not inside a transaction, do nothing */
|
||||||
if (my_level == 0)
|
if (GUCNestLevel == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
/* Done if we already pushed it at this nesting depth */
|
/* Done if we already pushed it at this nesting depth */
|
||||||
if (gconf->stack && gconf->stack->nest_level >= my_level)
|
if (gconf->stack && gconf->stack->nest_level >= GUCNestLevel)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3457,20 +3458,53 @@ push_old_value(struct config_generic * gconf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do GUC processing at transaction or subtransaction commit or abort.
|
* Do GUC processing at main transaction start.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
AtEOXact_GUC(bool isCommit, bool isSubXact)
|
AtStart_GUC(void)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* The nest level should be 0 between transactions; if it isn't,
|
||||||
|
* somebody didn't call AtEOXact_GUC, or called it with the wrong
|
||||||
|
* nestLevel. We throw a warning but make no other effort to clean up.
|
||||||
|
*/
|
||||||
|
if (GUCNestLevel != 0)
|
||||||
|
elog(WARNING, "GUC nest level = %d at transaction start",
|
||||||
|
GUCNestLevel);
|
||||||
|
GUCNestLevel = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enter a new nesting level for GUC values. This is called at subtransaction
|
||||||
|
* start and when entering a function that has proconfig settings. NOTE that
|
||||||
|
* we must not risk error here, else subtransaction start will be unhappy.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
NewGUCNestLevel(void)
|
||||||
|
{
|
||||||
|
return ++GUCNestLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Do GUC processing at transaction or subtransaction commit or abort, or
|
||||||
|
* when exiting a function that has proconfig settings. (The name is thus
|
||||||
|
* a bit of a misnomer; perhaps it should be ExitGUCNestLevel or some such.)
|
||||||
|
* During abort, we discard all GUC settings that were applied at nesting
|
||||||
|
* levels >= nestLevel. nestLevel == 1 corresponds to the main transaction.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
AtEOXact_GUC(bool isCommit, int nestLevel)
|
||||||
{
|
{
|
||||||
int my_level;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
Assert(nestLevel > 0 && nestLevel <= GUCNestLevel);
|
||||||
|
|
||||||
/* Quick exit if nothing's changed in this transaction */
|
/* Quick exit if nothing's changed in this transaction */
|
||||||
if (!guc_dirty)
|
if (!guc_dirty)
|
||||||
|
{
|
||||||
|
GUCNestLevel = nestLevel - 1;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
my_level = GetCurrentTransactionNestLevel();
|
|
||||||
Assert(isSubXact ? (my_level > 1) : (my_level == 1));
|
|
||||||
|
|
||||||
for (i = 0; i < num_guc_variables; i++)
|
for (i = 0; i < num_guc_variables; i++)
|
||||||
{
|
{
|
||||||
@ -3491,9 +3525,9 @@ AtEOXact_GUC(bool isCommit, bool isSubXact)
|
|||||||
/* Assert that we stacked old value before changing it */
|
/* Assert that we stacked old value before changing it */
|
||||||
Assert(stack != NULL && (my_status & GUC_HAVE_STACK));
|
Assert(stack != NULL && (my_status & GUC_HAVE_STACK));
|
||||||
/* However, the last change may have been at an outer xact level */
|
/* However, the last change may have been at an outer xact level */
|
||||||
if (stack->nest_level < my_level)
|
if (stack->nest_level < nestLevel)
|
||||||
continue;
|
continue;
|
||||||
Assert(stack->nest_level == my_level);
|
Assert(stack->nest_level == nestLevel);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We will pop the stack entry. Start by restoring outer xact status
|
* We will pop the stack entry. Start by restoring outer xact status
|
||||||
@ -3677,7 +3711,7 @@ AtEOXact_GUC(bool isCommit, bool isSubXact)
|
|||||||
set_string_field(conf, &stack->tentative_val.stringval,
|
set_string_field(conf, &stack->tentative_val.stringval,
|
||||||
NULL);
|
NULL);
|
||||||
/* Don't store tentative value separately after commit */
|
/* Don't store tentative value separately after commit */
|
||||||
if (!isSubXact)
|
if (nestLevel == 1)
|
||||||
set_string_field(conf, &conf->tentative_val, NULL);
|
set_string_field(conf, &conf->tentative_val, NULL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -3691,7 +3725,7 @@ AtEOXact_GUC(bool isCommit, bool isSubXact)
|
|||||||
* If we're now out of all xact levels, forget TENTATIVE status bit;
|
* If we're now out of all xact levels, forget TENTATIVE status bit;
|
||||||
* there's nothing tentative about the value anymore.
|
* there's nothing tentative about the value anymore.
|
||||||
*/
|
*/
|
||||||
if (!isSubXact)
|
if (nestLevel == 1)
|
||||||
{
|
{
|
||||||
Assert(gconf->stack == NULL);
|
Assert(gconf->stack == NULL);
|
||||||
gconf->status = 0;
|
gconf->status = 0;
|
||||||
@ -3708,8 +3742,11 @@ AtEOXact_GUC(bool isCommit, bool isSubXact)
|
|||||||
* that all outer transaction levels will have stacked values to deal
|
* that all outer transaction levels will have stacked values to deal
|
||||||
* with.)
|
* with.)
|
||||||
*/
|
*/
|
||||||
if (!isSubXact)
|
if (nestLevel == 1)
|
||||||
guc_dirty = false;
|
guc_dirty = false;
|
||||||
|
|
||||||
|
/* Update nesting level */
|
||||||
|
GUCNestLevel = nestLevel - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -6078,11 +6115,14 @@ ParseLongOption(const char *string, char **name, char **value)
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle options fetched from pg_database.datconfig or pg_authid.rolconfig.
|
* Handle options fetched from pg_database.datconfig, pg_authid.rolconfig,
|
||||||
|
* pg_proc.proconfig, etc. Caller must specify proper context/source/local.
|
||||||
|
*
|
||||||
* The array parameter must be an array of TEXT (it must not be NULL).
|
* The array parameter must be an array of TEXT (it must not be NULL).
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ProcessGUCArray(ArrayType *array, GucSource source)
|
ProcessGUCArray(ArrayType *array,
|
||||||
|
GucContext context, GucSource source, bool isLocal)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -6090,7 +6130,6 @@ ProcessGUCArray(ArrayType *array, GucSource source)
|
|||||||
Assert(ARR_ELEMTYPE(array) == TEXTOID);
|
Assert(ARR_ELEMTYPE(array) == TEXTOID);
|
||||||
Assert(ARR_NDIM(array) == 1);
|
Assert(ARR_NDIM(array) == 1);
|
||||||
Assert(ARR_LBOUND(array)[0] == 1);
|
Assert(ARR_LBOUND(array)[0] == 1);
|
||||||
Assert(source == PGC_S_DATABASE || source == PGC_S_USER);
|
|
||||||
|
|
||||||
for (i = 1; i <= ARR_DIMS(array)[0]; i++)
|
for (i = 1; i <= ARR_DIMS(array)[0]; i++)
|
||||||
{
|
{
|
||||||
@ -6117,17 +6156,13 @@ ProcessGUCArray(ArrayType *array, GucSource source)
|
|||||||
{
|
{
|
||||||
ereport(WARNING,
|
ereport(WARNING,
|
||||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||||
errmsg("could not parse setting for parameter \"%s\"", name)));
|
errmsg("could not parse setting for parameter \"%s\"",
|
||||||
|
name)));
|
||||||
free(name);
|
free(name);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
(void) set_config_option(name, value, context, source, isLocal, true);
|
||||||
* We process all these options at SUSET level. We assume that the
|
|
||||||
* right to insert an option into pg_database or pg_authid was checked
|
|
||||||
* when it was inserted.
|
|
||||||
*/
|
|
||||||
SetConfigOption(name, value, PGC_SUSET, source);
|
|
||||||
|
|
||||||
free(name);
|
free(name);
|
||||||
if (value)
|
if (value)
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
* by PostgreSQL
|
* by PostgreSQL
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.471 2007/08/22 01:39:45 tgl Exp $
|
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.472 2007/09/03 00:39:19 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -6420,6 +6420,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
|
|||||||
char *provolatile;
|
char *provolatile;
|
||||||
char *proisstrict;
|
char *proisstrict;
|
||||||
char *prosecdef;
|
char *prosecdef;
|
||||||
|
char *proconfig;
|
||||||
char *procost;
|
char *procost;
|
||||||
char *prorows;
|
char *prorows;
|
||||||
char *lanname;
|
char *lanname;
|
||||||
@ -6428,6 +6429,9 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
|
|||||||
char **allargtypes = NULL;
|
char **allargtypes = NULL;
|
||||||
char **argmodes = NULL;
|
char **argmodes = NULL;
|
||||||
char **argnames = NULL;
|
char **argnames = NULL;
|
||||||
|
char **configitems = NULL;
|
||||||
|
int nconfigitems = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
/* Skip if not to be dumped */
|
/* Skip if not to be dumped */
|
||||||
if (!finfo->dobj.dump || dataOnly)
|
if (!finfo->dobj.dump || dataOnly)
|
||||||
@ -6448,7 +6452,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
|
|||||||
"SELECT proretset, prosrc, probin, "
|
"SELECT proretset, prosrc, probin, "
|
||||||
"proallargtypes, proargmodes, proargnames, "
|
"proallargtypes, proargmodes, proargnames, "
|
||||||
"provolatile, proisstrict, prosecdef, "
|
"provolatile, proisstrict, prosecdef, "
|
||||||
"procost, prorows, "
|
"proconfig, procost, prorows, "
|
||||||
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
|
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
|
||||||
"FROM pg_catalog.pg_proc "
|
"FROM pg_catalog.pg_proc "
|
||||||
"WHERE oid = '%u'::pg_catalog.oid",
|
"WHERE oid = '%u'::pg_catalog.oid",
|
||||||
@ -6460,7 +6464,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
|
|||||||
"SELECT proretset, prosrc, probin, "
|
"SELECT proretset, prosrc, probin, "
|
||||||
"proallargtypes, proargmodes, proargnames, "
|
"proallargtypes, proargmodes, proargnames, "
|
||||||
"provolatile, proisstrict, prosecdef, "
|
"provolatile, proisstrict, prosecdef, "
|
||||||
"0 as procost, 0 as prorows, "
|
"null as proconfig, 0 as procost, 0 as prorows, "
|
||||||
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
|
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
|
||||||
"FROM pg_catalog.pg_proc "
|
"FROM pg_catalog.pg_proc "
|
||||||
"WHERE oid = '%u'::pg_catalog.oid",
|
"WHERE oid = '%u'::pg_catalog.oid",
|
||||||
@ -6474,7 +6478,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
|
|||||||
"null as proargmodes, "
|
"null as proargmodes, "
|
||||||
"proargnames, "
|
"proargnames, "
|
||||||
"provolatile, proisstrict, prosecdef, "
|
"provolatile, proisstrict, prosecdef, "
|
||||||
"0 as procost, 0 as prorows, "
|
"null as proconfig, 0 as procost, 0 as prorows, "
|
||||||
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
|
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
|
||||||
"FROM pg_catalog.pg_proc "
|
"FROM pg_catalog.pg_proc "
|
||||||
"WHERE oid = '%u'::pg_catalog.oid",
|
"WHERE oid = '%u'::pg_catalog.oid",
|
||||||
@ -6488,7 +6492,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
|
|||||||
"null as proargmodes, "
|
"null as proargmodes, "
|
||||||
"null as proargnames, "
|
"null as proargnames, "
|
||||||
"provolatile, proisstrict, prosecdef, "
|
"provolatile, proisstrict, prosecdef, "
|
||||||
"0 as procost, 0 as prorows, "
|
"null as proconfig, 0 as procost, 0 as prorows, "
|
||||||
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
|
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
|
||||||
"FROM pg_catalog.pg_proc "
|
"FROM pg_catalog.pg_proc "
|
||||||
"WHERE oid = '%u'::pg_catalog.oid",
|
"WHERE oid = '%u'::pg_catalog.oid",
|
||||||
@ -6504,7 +6508,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
|
|||||||
"case when proiscachable then 'i' else 'v' end as provolatile, "
|
"case when proiscachable then 'i' else 'v' end as provolatile, "
|
||||||
"proisstrict, "
|
"proisstrict, "
|
||||||
"'f'::boolean as prosecdef, "
|
"'f'::boolean as prosecdef, "
|
||||||
"0 as procost, 0 as prorows, "
|
"null as proconfig, 0 as procost, 0 as prorows, "
|
||||||
"(SELECT lanname FROM pg_language WHERE oid = prolang) as lanname "
|
"(SELECT lanname FROM pg_language WHERE oid = prolang) as lanname "
|
||||||
"FROM pg_proc "
|
"FROM pg_proc "
|
||||||
"WHERE oid = '%u'::oid",
|
"WHERE oid = '%u'::oid",
|
||||||
@ -6520,7 +6524,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
|
|||||||
"case when proiscachable then 'i' else 'v' end as provolatile, "
|
"case when proiscachable then 'i' else 'v' end as provolatile, "
|
||||||
"'f'::boolean as proisstrict, "
|
"'f'::boolean as proisstrict, "
|
||||||
"'f'::boolean as prosecdef, "
|
"'f'::boolean as prosecdef, "
|
||||||
"0 as procost, 0 as prorows, "
|
"null as proconfig, 0 as procost, 0 as prorows, "
|
||||||
"(SELECT lanname FROM pg_language WHERE oid = prolang) as lanname "
|
"(SELECT lanname FROM pg_language WHERE oid = prolang) as lanname "
|
||||||
"FROM pg_proc "
|
"FROM pg_proc "
|
||||||
"WHERE oid = '%u'::oid",
|
"WHERE oid = '%u'::oid",
|
||||||
@ -6548,6 +6552,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
|
|||||||
provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
|
provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
|
||||||
proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
|
proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
|
||||||
prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
|
prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
|
||||||
|
proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
|
||||||
procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
|
procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
|
||||||
prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
|
prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
|
||||||
lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
|
lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
|
||||||
@ -6634,6 +6639,18 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (proconfig && *proconfig)
|
||||||
|
{
|
||||||
|
if (!parsePGArray(proconfig, &configitems, &nconfigitems))
|
||||||
|
{
|
||||||
|
write_msg(NULL, "WARNING: could not parse proconfig array\n");
|
||||||
|
if (configitems)
|
||||||
|
free(configitems);
|
||||||
|
configitems = NULL;
|
||||||
|
nconfigitems = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
funcsig = format_function_arguments(finfo, nallargs, allargtypes,
|
funcsig = format_function_arguments(finfo, nallargs, allargtypes,
|
||||||
argmodes, argnames);
|
argmodes, argnames);
|
||||||
funcsig_tag = format_function_signature(finfo, false);
|
funcsig_tag = format_function_signature(finfo, false);
|
||||||
@ -6700,6 +6717,28 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
|
|||||||
strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
|
strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
|
||||||
appendPQExpBuffer(q, " ROWS %s", prorows);
|
appendPQExpBuffer(q, " ROWS %s", prorows);
|
||||||
|
|
||||||
|
for (i = 0; i < nconfigitems; i++)
|
||||||
|
{
|
||||||
|
/* we feel free to scribble on configitems[] here */
|
||||||
|
char *configitem = configitems[i];
|
||||||
|
char *pos;
|
||||||
|
|
||||||
|
pos = strchr(configitem, '=');
|
||||||
|
if (pos == NULL)
|
||||||
|
continue;
|
||||||
|
*pos++ = '\0';
|
||||||
|
appendPQExpBuffer(q, "\n SET %s TO ", fmtId(configitem));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some GUC variable names are 'LIST' type and hence must not be quoted.
|
||||||
|
*/
|
||||||
|
if (pg_strcasecmp(configitem, "DateStyle") == 0
|
||||||
|
|| pg_strcasecmp(configitem, "search_path") == 0)
|
||||||
|
appendPQExpBuffer(q, "%s", pos);
|
||||||
|
else
|
||||||
|
appendStringLiteralAH(q, pos, fout);
|
||||||
|
}
|
||||||
|
|
||||||
appendPQExpBuffer(q, ";\n");
|
appendPQExpBuffer(q, ";\n");
|
||||||
|
|
||||||
ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
|
ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
|
||||||
@ -6737,6 +6776,8 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
|
|||||||
free(argmodes);
|
free(argmodes);
|
||||||
if (argnames)
|
if (argnames)
|
||||||
free(argnames);
|
free(argnames);
|
||||||
|
if (configitems)
|
||||||
|
free(configitems);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.419 2007/08/27 01:39:24 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.420 2007/09/03 00:39:21 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -53,6 +53,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* yyyymmddN */
|
/* yyyymmddN */
|
||||||
#define CATALOG_VERSION_NO 200708261
|
#define CATALOG_VERSION_NO 200709011
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/catalog/pg_attribute.h,v 1.131 2007/05/11 17:57:13 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/pg_attribute.h,v 1.132 2007/09/03 00:39:21 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* the genbki.sh script reads this file and generates .bki
|
* the genbki.sh script reads this file and generates .bki
|
||||||
@ -307,7 +307,8 @@ DATA(insert ( 1247 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0));
|
|||||||
{ 1255, {"proargnames"}, 1009, -1, -1, 17, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
|
{ 1255, {"proargnames"}, 1009, -1, -1, 17, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
|
||||||
{ 1255, {"prosrc"}, 25, -1, -1, 18, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
|
{ 1255, {"prosrc"}, 25, -1, -1, 18, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
|
||||||
{ 1255, {"probin"}, 17, -1, -1, 19, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
|
{ 1255, {"probin"}, 17, -1, -1, 19, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
|
||||||
{ 1255, {"proacl"}, 1034, -1, -1, 20, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }
|
{ 1255, {"proconfig"}, 1009, -1, -1, 20, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
|
||||||
|
{ 1255, {"proacl"}, 1034, -1, -1, 21, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }
|
||||||
|
|
||||||
DATA(insert ( 1255 proname 19 -1 NAMEDATALEN 1 0 -1 -1 f p i t f f t 0));
|
DATA(insert ( 1255 proname 19 -1 NAMEDATALEN 1 0 -1 -1 f p i t f f t 0));
|
||||||
DATA(insert ( 1255 pronamespace 26 -1 4 2 0 -1 -1 t p i t f f t 0));
|
DATA(insert ( 1255 pronamespace 26 -1 4 2 0 -1 -1 t p i t f f t 0));
|
||||||
@ -328,7 +329,8 @@ DATA(insert ( 1255 proargmodes 1002 -1 -1 16 1 -1 -1 f x i f f f t 0));
|
|||||||
DATA(insert ( 1255 proargnames 1009 -1 -1 17 1 -1 -1 f x i f f f t 0));
|
DATA(insert ( 1255 proargnames 1009 -1 -1 17 1 -1 -1 f x i f f f t 0));
|
||||||
DATA(insert ( 1255 prosrc 25 -1 -1 18 0 -1 -1 f x i f f f t 0));
|
DATA(insert ( 1255 prosrc 25 -1 -1 18 0 -1 -1 f x i f f f t 0));
|
||||||
DATA(insert ( 1255 probin 17 -1 -1 19 0 -1 -1 f x i f f f t 0));
|
DATA(insert ( 1255 probin 17 -1 -1 19 0 -1 -1 f x i f f f t 0));
|
||||||
DATA(insert ( 1255 proacl 1034 -1 -1 20 1 -1 -1 f x i f f f t 0));
|
DATA(insert ( 1255 proconfig 1009 -1 -1 20 1 -1 -1 f x i f f f t 0));
|
||||||
|
DATA(insert ( 1255 proacl 1034 -1 -1 21 1 -1 -1 f x i f f f t 0));
|
||||||
DATA(insert ( 1255 ctid 27 0 6 -1 0 -1 -1 f p s t f f t 0));
|
DATA(insert ( 1255 ctid 27 0 6 -1 0 -1 -1 f p s t f f t 0));
|
||||||
DATA(insert ( 1255 oid 26 0 4 -2 0 -1 -1 t p i t f f t 0));
|
DATA(insert ( 1255 oid 26 0 4 -2 0 -1 -1 t p i t f f t 0));
|
||||||
DATA(insert ( 1255 xmin 28 0 4 -3 0 -1 -1 t p i t f f t 0));
|
DATA(insert ( 1255 xmin 28 0 4 -3 0 -1 -1 t p i t f f t 0));
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/catalog/pg_class.h,v 1.101 2007/05/11 17:57:13 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/pg_class.h,v 1.102 2007/09/03 00:39:21 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* the genbki.sh script reads this file and generates .bki
|
* the genbki.sh script reads this file and generates .bki
|
||||||
@ -136,7 +136,7 @@ DATA(insert OID = 1247 ( pg_type PGNSP 71 PGUID 0 1247 0 0 0 0 0 f f r 26 0 0
|
|||||||
DESCR("");
|
DESCR("");
|
||||||
DATA(insert OID = 1249 ( pg_attribute PGNSP 75 PGUID 0 1249 0 0 0 0 0 f f r 17 0 0 0 0 0 f f f f 3 _null_ _null_ ));
|
DATA(insert OID = 1249 ( pg_attribute PGNSP 75 PGUID 0 1249 0 0 0 0 0 f f r 17 0 0 0 0 0 f f f f 3 _null_ _null_ ));
|
||||||
DESCR("");
|
DESCR("");
|
||||||
DATA(insert OID = 1255 ( pg_proc PGNSP 81 PGUID 0 1255 0 0 0 0 0 f f r 20 0 0 0 0 0 t f f f 3 _null_ _null_ ));
|
DATA(insert OID = 1255 ( pg_proc PGNSP 81 PGUID 0 1255 0 0 0 0 0 f f r 21 0 0 0 0 0 t f f f 3 _null_ _null_ ));
|
||||||
DESCR("");
|
DESCR("");
|
||||||
DATA(insert OID = 1259 ( pg_class PGNSP 83 PGUID 0 1259 0 0 0 0 0 f f r 27 0 0 0 0 0 t f f f 3 _null_ _null_ ));
|
DATA(insert OID = 1259 ( pg_class PGNSP 83 PGUID 0 1259 0 0 0 0 0 f f r 27 0 0 0 0 0 t f f f 3 _null_ _null_ ));
|
||||||
DESCR("");
|
DESCR("");
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -7,7 +7,7 @@
|
|||||||
* Copyright (c) 2000-2007, PostgreSQL Global Development Group
|
* Copyright (c) 2000-2007, PostgreSQL Global Development Group
|
||||||
* Written by Peter Eisentraut <peter_e@gmx.net>.
|
* Written by Peter Eisentraut <peter_e@gmx.net>.
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.83 2007/07/25 12:22:54 mha Exp $
|
* $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.84 2007/09/03 00:39:25 tgl Exp $
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
#ifndef GUC_H
|
#ifndef GUC_H
|
||||||
@ -188,7 +188,9 @@ extern void ProcessConfigFile(GucContext context);
|
|||||||
extern void InitializeGUCOptions(void);
|
extern void InitializeGUCOptions(void);
|
||||||
extern bool SelectConfigFiles(const char *userDoption, const char *progname);
|
extern bool SelectConfigFiles(const char *userDoption, const char *progname);
|
||||||
extern void ResetAllOptions(void);
|
extern void ResetAllOptions(void);
|
||||||
extern void AtEOXact_GUC(bool isCommit, bool isSubXact);
|
extern void AtStart_GUC(void);
|
||||||
|
extern int NewGUCNestLevel(void);
|
||||||
|
extern void AtEOXact_GUC(bool isCommit, int nestLevel);
|
||||||
extern void BeginReportingGUCOptions(void);
|
extern void BeginReportingGUCOptions(void);
|
||||||
extern void ParseLongOption(const char *string, char **name, char **value);
|
extern void ParseLongOption(const char *string, char **name, char **value);
|
||||||
extern bool set_config_option(const char *name, const char *value,
|
extern bool set_config_option(const char *name, const char *value,
|
||||||
@ -205,7 +207,8 @@ extern void ResetPGVariable(const char *name, bool isTopLevel);
|
|||||||
|
|
||||||
extern char *flatten_set_variable_args(const char *name, List *args);
|
extern char *flatten_set_variable_args(const char *name, List *args);
|
||||||
|
|
||||||
extern void ProcessGUCArray(ArrayType *array, GucSource source);
|
extern void ProcessGUCArray(ArrayType *array,
|
||||||
|
GucContext context, GucSource source, bool isLocal);
|
||||||
extern ArrayType *GUCArrayAdd(ArrayType *array, const char *name, const char *value);
|
extern ArrayType *GUCArrayAdd(ArrayType *array, const char *name, const char *value);
|
||||||
extern ArrayType *GUCArrayDelete(ArrayType *array, const char *name);
|
extern ArrayType *GUCArrayDelete(ArrayType *array, const char *name);
|
||||||
|
|
||||||
|
@ -525,3 +525,36 @@ SELECT current_user = 'temp_reset_user';
|
|||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
DROP ROLE temp_reset_user;
|
DROP ROLE temp_reset_user;
|
||||||
|
--
|
||||||
|
-- Tests for function-local GUC settings
|
||||||
|
--
|
||||||
|
set regex_flavor = advanced;
|
||||||
|
create function report_guc(text) returns text as
|
||||||
|
$$ select current_setting($1) $$ language sql
|
||||||
|
set regex_flavor = basic;
|
||||||
|
select report_guc('regex_flavor'), current_setting('regex_flavor');
|
||||||
|
report_guc | current_setting
|
||||||
|
------------+-----------------
|
||||||
|
basic | advanced
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- this should draw only a warning
|
||||||
|
alter function report_guc(text) set search_path = no_such_schema;
|
||||||
|
NOTICE: schema "no_such_schema" does not exist
|
||||||
|
-- with error occurring here
|
||||||
|
select report_guc('regex_flavor'), current_setting('regex_flavor');
|
||||||
|
ERROR: schema "no_such_schema" does not exist
|
||||||
|
alter function report_guc(text) reset search_path set regex_flavor = extended;
|
||||||
|
select report_guc('regex_flavor'), current_setting('regex_flavor');
|
||||||
|
report_guc | current_setting
|
||||||
|
------------+-----------------
|
||||||
|
extended | advanced
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
alter function report_guc(text) reset all;
|
||||||
|
select report_guc('regex_flavor'), current_setting('regex_flavor');
|
||||||
|
report_guc | current_setting
|
||||||
|
------------+-----------------
|
||||||
|
advanced | advanced
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
@ -162,3 +162,28 @@ SELECT relname from pg_class where relname = 'tmp_foo';
|
|||||||
SELECT current_user = 'temp_reset_user';
|
SELECT current_user = 'temp_reset_user';
|
||||||
DROP ROLE temp_reset_user;
|
DROP ROLE temp_reset_user;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Tests for function-local GUC settings
|
||||||
|
--
|
||||||
|
|
||||||
|
set regex_flavor = advanced;
|
||||||
|
|
||||||
|
create function report_guc(text) returns text as
|
||||||
|
$$ select current_setting($1) $$ language sql
|
||||||
|
set regex_flavor = basic;
|
||||||
|
|
||||||
|
select report_guc('regex_flavor'), current_setting('regex_flavor');
|
||||||
|
|
||||||
|
-- this should draw only a warning
|
||||||
|
alter function report_guc(text) set search_path = no_such_schema;
|
||||||
|
|
||||||
|
-- with error occurring here
|
||||||
|
select report_guc('regex_flavor'), current_setting('regex_flavor');
|
||||||
|
|
||||||
|
alter function report_guc(text) reset search_path set regex_flavor = extended;
|
||||||
|
|
||||||
|
select report_guc('regex_flavor'), current_setting('regex_flavor');
|
||||||
|
|
||||||
|
alter function report_guc(text) reset all;
|
||||||
|
|
||||||
|
select report_guc('regex_flavor'), current_setting('regex_flavor');
|
||||||
|
Loading…
x
Reference in New Issue
Block a user