mirror of
				https://github.com/postgres/postgres.git
				synced 2025-10-31 00:03:57 -04:00 
			
		
		
		
	Support explicit placement of the temporary-table schema within search_path.
This is needed to allow a security-definer function to set a truly secure value of search_path. Without it, a malicious user can use temporary objects to execute code with the privileges of the security-definer function. Even pushing the temp schema to the back of the search path is not quite good enough, because a function or operator at the back of the path might still capture control from one nearer the front due to having a more exact datatype match. Hence, disable searching the temp schema altogether for functions and operators. Security: CVE-2007-2138
This commit is contained in:
		
							parent
							
								
									9350056eaa
								
							
						
					
					
						commit
						aa27977fe2
					
				| @ -1,4 +1,4 @@ | ||||
| <!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.121 2007/04/18 16:44:17 alvherre Exp $ --> | ||||
| <!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.122 2007/04/20 02:37:37 tgl Exp $ --> | ||||
| 
 | ||||
| <chapter Id="runtime-config"> | ||||
|   <title>Server Configuration</title> | ||||
| @ -3405,9 +3405,17 @@ SELECT * FROM parent WHERE key = 2400; | ||||
|         mentioned in the path then it will be searched in the specified | ||||
|         order.  If <literal>pg_catalog</> is not in the path then it will | ||||
|         be searched <emphasis>before</> searching any of the path items. | ||||
|         It should also be noted that the temporary-table schema, | ||||
|         <literal>pg_temp_<replaceable>nnn</></>, is implicitly searched before any of | ||||
|         these. | ||||
|        </para> | ||||
| 
 | ||||
|        <para> | ||||
|         Likewise, the current session's temporary-table schema, | ||||
|         <literal>pg_temp_<replaceable>nnn</></>, is always searched if it | ||||
|         exists.  It can be explicitly listed in the path by using the | ||||
|         alias <literal>pg_temp</>.  If it is not listed in the path then | ||||
|         it is searched first (before even <literal>pg_catalog</>).  However, | ||||
|         the temporary schema is only searched for relation (table, view, | ||||
|         sequence, etc) and data type names.  It will never be searched for | ||||
|         function or operator names. | ||||
|        </para> | ||||
| 
 | ||||
|        <para> | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| <!-- | ||||
| $PostgreSQL: pgsql/doc/src/sgml/ref/create_function.sgml,v 1.73 2007/02/01 19:10:24 momjian Exp $ | ||||
| $PostgreSQL: pgsql/doc/src/sgml/ref/create_function.sgml,v 1.74 2007/04/20 02:37:37 tgl Exp $ | ||||
| --> | ||||
| 
 | ||||
| <refentry id="SQL-CREATEFUNCTION"> | ||||
| @ -508,6 +508,54 @@ SELECT * FROM dup(42); | ||||
|   </para> | ||||
|  </refsect1> | ||||
| 
 | ||||
|  <refsect1 id="sql-createfunction-security"> | ||||
|   <title>Writing <literal>SECURITY DEFINER</literal> Functions Safely</title> | ||||
| 
 | ||||
|    <para> | ||||
|     Because a <literal>SECURITY DEFINER</literal> function is executed | ||||
|     with the privileges of the user that created it, care is needed to | ||||
|     ensure that the function cannot be misused.  For security, | ||||
|     <xref linkend="guc-search-path"> should be set to exclude any schemas | ||||
|     writable by untrusted users.  This prevents | ||||
|     malicious users from creating objects that mask objects used by the | ||||
|     function.  Particularly important is in this regard is the | ||||
|     temporary-table schema, which is searched first by default, and | ||||
|     is normally writable by anyone.  A secure arrangement can be had | ||||
|     by forcing the temporary schema to be searched last.  To do this, | ||||
|     write <literal>pg_temp</> as the last entry in <varname>search_path</>. | ||||
|     This function illustrates safe usage: | ||||
|    </para> | ||||
| 
 | ||||
| <programlisting> | ||||
| CREATE FUNCTION check_password(uname TEXT, pass TEXT) | ||||
| RETURNS BOOLEAN AS $$ | ||||
| DECLARE passed BOOLEAN; | ||||
|         old_path TEXT; | ||||
| 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 | ||||
|         FROM    pwds | ||||
|         WHERE   username = $1; | ||||
| 
 | ||||
|         -- Restore caller's search_path | ||||
|         PERFORM pg_catalog.set_config('search_path', old_path, true); | ||||
| 
 | ||||
|         RETURN passed; | ||||
| END; | ||||
| $$ LANGUAGE plpgsql SECURITY DEFINER; | ||||
| </programlisting> | ||||
| 
 | ||||
|  </refsect1> | ||||
| 
 | ||||
|   | ||||
|  <refsect1 id="sql-createfunction-compat"> | ||||
|   <title>Compatibility</title> | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| <!-- $PostgreSQL: pgsql/doc/src/sgml/release.sgml,v 1.500 2007/04/19 13:02:49 momjian Exp $ --> | ||||
| <!-- $PostgreSQL: pgsql/doc/src/sgml/release.sgml,v 1.501 2007/04/20 02:37:37 tgl Exp $ --> | ||||
| <!-- | ||||
| 
 | ||||
| Typical markup: | ||||
| @ -44,7 +44,8 @@ do it for earlier branch release files. | ||||
|    </note> | ||||
| 
 | ||||
|    <para> | ||||
|     This release contains fixes from 8.2.3. | ||||
|     This release contains a variety of fixes from 8.2.3, | ||||
|     including a security fix. | ||||
|    </para> | ||||
| 
 | ||||
|    <sect2> | ||||
| @ -63,8 +64,24 @@ do it for earlier branch release files. | ||||
| 
 | ||||
|      <listitem> | ||||
|      <para> | ||||
|       Fix <varname>shared_preload_libraries</> for Win32 by forcing reload in each backend | ||||
|       (Korry Douglas) | ||||
|       Support explicit placement of the temporary-table schema within | ||||
|       <varname>search_path</>, and disable searching it for functions | ||||
|       and operators (Tom) | ||||
|      </para> | ||||
|      <para> | ||||
|       This is needed to allow a security-definer function to set a | ||||
|       truly secure value of <varname>search_path</>.  Without it, | ||||
|       an unprivileged SQL user can use temporary objects to execute code | ||||
|       with the privileges of the security-definer function (CVE-2007-2138). | ||||
|       See <xref linkend="sql-createfunction" | ||||
|       endterm="sql-createfunction-title"> for more information. | ||||
|      </para> | ||||
|      </listitem> | ||||
| 
 | ||||
|      <listitem> | ||||
|      <para> | ||||
|       Fix <varname>shared_preload_libraries</> for Windows | ||||
|       by forcing reload in each backend (Korry Douglas) | ||||
|      </para> | ||||
|      </listitem> | ||||
| 
 | ||||
| @ -77,20 +94,21 @@ do it for earlier branch release files. | ||||
| 
 | ||||
|      <listitem> | ||||
|      <para> | ||||
|       <filename>/contrib/tsearch2</> fixes (Teodor) | ||||
|       <filename>/contrib/tsearch2</> crash fixes (Teodor) | ||||
|      </para> | ||||
|      </listitem> | ||||
| 
 | ||||
|      <listitem> | ||||
|      <para> | ||||
|       Require <command>COMMIT TRANSACTION</> to be executed in the same database as | ||||
|       it was prepared (Heikki) | ||||
|       Require <command>COMMIT PREPARED</> to be executed in the same | ||||
|       database as the transaction was prepared in (Heikki) | ||||
|      </para> | ||||
|      </listitem> | ||||
| 
 | ||||
|      <listitem> | ||||
|      <para> | ||||
|       Allow Win32 <command>pg_dump</> to do binary backups larger than two gigabytes (Magnus) | ||||
|       Allow <command>pg_dump</> to do binary backups larger than two gigabytes | ||||
|       on Windows (Magnus) | ||||
|      </para> | ||||
|      </listitem> | ||||
| 
 | ||||
| @ -108,13 +126,8 @@ do it for earlier branch release files. | ||||
| 
 | ||||
|      <listitem> | ||||
|      <para> | ||||
|       Improve detection of <acronym>POSIX</>-style time zone names (Tom) | ||||
|      </para> | ||||
|      </listitem> | ||||
| 
 | ||||
|      <listitem> | ||||
|      <para> | ||||
|       Fix bug in how <command>VACUUM FULL</> handles <command>UPDATE</> chains (Tom, Pavan Deolasee) | ||||
|       Fix potential-data-corruption bug in how <command>VACUUM FULL</> handles | ||||
|       <command>UPDATE</> chains (Tom, Pavan Deolasee) | ||||
|      </para> | ||||
|      </listitem> | ||||
| 
 | ||||
| @ -126,14 +139,36 @@ do it for earlier branch release files. | ||||
| 
 | ||||
|      <listitem> | ||||
|      <para> | ||||
|       Fix <command>pg_dump</> so it can dump a sequence using <option>-t</> when not also dumping the owning table | ||||
|       Fix <command>pg_dump</> so it can dump a serial column's sequence | ||||
|       using <option>-t</> when not also dumping the owning table | ||||
|       (Tom) | ||||
|      </para> | ||||
|      </listitem> | ||||
| 
 | ||||
|      <listitem> | ||||
|      <para> | ||||
|       Improve outer join and bitmap join selection logic (Tom) | ||||
|       Planner fixes, including improving outer join and bitmap scan | ||||
|       selection logic (Tom) | ||||
|      </para> | ||||
|      </listitem> | ||||
| 
 | ||||
|      <listitem> | ||||
|      <para> | ||||
|       Fix possible wrong answers or crash when a PL/pgSQL function tries | ||||
|       to <literal>RETURN</> from within an <literal>EXCEPTION</> block | ||||
|       (Tom) | ||||
|      </para> | ||||
|      </listitem> | ||||
| 
 | ||||
|      <listitem> | ||||
|      <para> | ||||
|       Fix PANIC during enlargement of a hash index (Tom) | ||||
|      </para> | ||||
|      </listitem> | ||||
| 
 | ||||
|      <listitem> | ||||
|      <para> | ||||
|       Fix POSIX-style timezone specs to follow new USA DST rules (Tom) | ||||
|      </para> | ||||
|      </listitem> | ||||
| 
 | ||||
| @ -3040,7 +3075,8 @@ do it for earlier branch release files. | ||||
|    </note> | ||||
| 
 | ||||
|    <para> | ||||
|     This release contains fixes from 8.1.8. | ||||
|     This release contains a variety of fixes from 8.1.8, | ||||
|     including a security fix. | ||||
|    </para> | ||||
| 
 | ||||
|    <sect2> | ||||
| @ -3061,39 +3097,57 @@ do it for earlier branch release files. | ||||
| 
 | ||||
|      <listitem> | ||||
|      <para> | ||||
|       Fix <function>to_char()</> so it properly upper/lower cases localized day or month | ||||
|       names (Pavel Stehule) | ||||
|       Support explicit placement of the temporary-table schema within | ||||
|       <varname>search_path</>, and disable searching it for functions | ||||
|       and operators (Tom) | ||||
|      </para> | ||||
|      <para> | ||||
|       This is needed to allow a security-definer function to set a | ||||
|       truly secure value of <varname>search_path</>.  Without it, | ||||
|       an unprivileged SQL user can use temporary objects to execute code | ||||
|       with the privileges of the security-definer function (CVE-2007-2138). | ||||
|       See <xref linkend="sql-createfunction" | ||||
|       endterm="sql-createfunction-title"> for more information. | ||||
|      </para> | ||||
|      </listitem> | ||||
| 
 | ||||
|      <listitem> | ||||
|      <para> | ||||
|       <filename>/contrib/tsearch2</> fixes (Teodor) | ||||
|       <filename>/contrib/tsearch2</> crash fixes (Teodor) | ||||
|      </para> | ||||
|      </listitem> | ||||
| 
 | ||||
|      <listitem> | ||||
|      <para> | ||||
|       Require <command>COMMIT TRANSACTION</> to be executed in the same database as | ||||
|       it was prepared (Heikki) | ||||
|       Require <command>COMMIT PREPARED</> to be executed in the same | ||||
|       database as the transaction was prepared in (Heikki) | ||||
|      </para> | ||||
|      </listitem> | ||||
| 
 | ||||
|      <listitem> | ||||
|      <para> | ||||
|       Improve detection of <acronym>POSIX</>-style time zone names (Tom) | ||||
|       Fix potential-data-corruption bug in how <command>VACUUM FULL</> handles | ||||
|       <command>UPDATE</> chains (Tom, Pavan Deolasee) | ||||
|      </para> | ||||
|      </listitem> | ||||
| 
 | ||||
|      <listitem> | ||||
|      <para> | ||||
|       Fix bug in how <command>VACUUM FULL</> handles <command>UPDATE</> chains (Tom, Pavan Deolasee) | ||||
|       Planner fixes, including improving outer join and bitmap scan | ||||
|       selection logic (Tom) | ||||
|      </para> | ||||
|      </listitem> | ||||
| 
 | ||||
|      <listitem> | ||||
|      <para> | ||||
|       Improve outer join and bitmap join selection logic (Tom) | ||||
|       Fix PANIC during enlargement of a hash index (bug introduced in 8.1.6) | ||||
|       (Tom) | ||||
|      </para> | ||||
|      </listitem> | ||||
| 
 | ||||
|      <listitem> | ||||
|      <para> | ||||
|       Fix POSIX-style timezone specs to follow new USA DST rules (Tom) | ||||
|      </para> | ||||
|      </listitem> | ||||
| 
 | ||||
| @ -6061,7 +6115,8 @@ psql -t -f fixseq.sql db1 | psql -e db1 | ||||
|    </note> | ||||
| 
 | ||||
|    <para> | ||||
|     This release contains fixes from 8.0.12. | ||||
|     This release contains a variety of fixes from 8.0.12, | ||||
|     including a security fix. | ||||
|    </para> | ||||
| 
 | ||||
|    <sect2> | ||||
| @ -6082,25 +6137,43 @@ psql -t -f fixseq.sql db1 | psql -e db1 | ||||
| 
 | ||||
|      <listitem> | ||||
|      <para> | ||||
|       <filename>/contrib/tsearch2</> fixes (Teodor) | ||||
|       Support explicit placement of the temporary-table schema within | ||||
|       <varname>search_path</>, and disable searching it for functions | ||||
|       and operators (Tom) | ||||
|      </para> | ||||
|      <para> | ||||
|       This is needed to allow a security-definer function to set a | ||||
|       truly secure value of <varname>search_path</>.  Without it, | ||||
|       an unprivileged SQL user can use temporary objects to execute code | ||||
|       with the privileges of the security-definer function (CVE-2007-2138). | ||||
|       See <xref linkend="sql-createfunction" | ||||
|       endterm="sql-createfunction-title"> for more information. | ||||
|      </para> | ||||
|      </listitem> | ||||
| 
 | ||||
|      <listitem> | ||||
|      <para> | ||||
|       Improve detection of <acronym>POSIX</>-style time zone names (Tom) | ||||
|       <filename>/contrib/tsearch2</> crash fixes (Teodor) | ||||
|      </para> | ||||
|      </listitem> | ||||
| 
 | ||||
|      <listitem> | ||||
|      <para> | ||||
|       Fix bug in how <command>VACUUM FULL</> handles <command>UPDATE</> chains (Tom, Pavan Deolasee) | ||||
|       Fix potential-data-corruption bug in how <command>VACUUM FULL</> handles | ||||
|       <command>UPDATE</> chains (Tom, Pavan Deolasee) | ||||
|      </para> | ||||
|      </listitem> | ||||
| 
 | ||||
|      <listitem> | ||||
|      <para> | ||||
|       <filename>/contrib/tsearch2</> fixes (Teodor) | ||||
|       Fix PANIC during enlargement of a hash index (bug introduced in 8.0.10) | ||||
|       (Tom) | ||||
|      </para> | ||||
|      </listitem> | ||||
| 
 | ||||
|      <listitem> | ||||
|      <para> | ||||
|       Fix POSIX-style timezone specs to follow new USA DST rules (Tom) | ||||
|      </para> | ||||
|      </listitem> | ||||
| 
 | ||||
| @ -9552,7 +9625,8 @@ typedefs (Michael)</para></listitem> | ||||
|    </note> | ||||
| 
 | ||||
|    <para> | ||||
|     This release contains a variety of fixes from 7.4.16. | ||||
|     This release contains fixes from 7.4.16, | ||||
|     including a security fix. | ||||
|    </para> | ||||
| 
 | ||||
|    <sect2> | ||||
| @ -9573,13 +9647,37 @@ typedefs (Michael)</para></listitem> | ||||
| 
 | ||||
|      <listitem> | ||||
|      <para> | ||||
|       <filename>/contrib/tsearch2</> fixes (Teodor) | ||||
|       Support explicit placement of the temporary-table schema within | ||||
|       <varname>search_path</>, and disable searching it for functions | ||||
|       and operators (Tom) | ||||
|      </para> | ||||
|      <para> | ||||
|       This is needed to allow a security-definer function to set a | ||||
|       truly secure value of <varname>search_path</>.  Without it, | ||||
|       an unprivileged SQL user can use temporary objects to execute code | ||||
|       with the privileges of the security-definer function (CVE-2007-2138). | ||||
|       See <xref linkend="sql-createfunction" | ||||
|       endterm="sql-createfunction-title"> for more information. | ||||
|      </para> | ||||
|      </listitem> | ||||
| 
 | ||||
|      <listitem> | ||||
|      <para> | ||||
|       Fix bug in how <command>VACUUM FULL</> handles <command>UPDATE</> chains (Tom, Pavan Deolasee) | ||||
|       <filename>/contrib/tsearch2</> crash fixes (Teodor) | ||||
|      </para> | ||||
|      </listitem> | ||||
| 
 | ||||
|      <listitem> | ||||
|      <para> | ||||
|       Fix potential-data-corruption bug in how <command>VACUUM FULL</> handles | ||||
|       <command>UPDATE</> chains (Tom, Pavan Deolasee) | ||||
|      </para> | ||||
|      </listitem> | ||||
| 
 | ||||
|      <listitem> | ||||
|      <para> | ||||
|       Fix PANIC during enlargement of a hash index (bug introduced in 7.4.15) | ||||
|       (Tom) | ||||
|      </para> | ||||
|      </listitem> | ||||
| 
 | ||||
| @ -12714,7 +12812,8 @@ DROP SCHEMA information_schema CASCADE; | ||||
|    </note> | ||||
| 
 | ||||
|    <para> | ||||
|     This release contains a variety of fixes from 7.3.18. | ||||
|     This release contains fixes from 7.3.18, | ||||
|     including a security fix. | ||||
|    </para> | ||||
| 
 | ||||
|    <sect2> | ||||
| @ -12735,7 +12834,24 @@ DROP SCHEMA information_schema CASCADE; | ||||
| 
 | ||||
|      <listitem> | ||||
|      <para> | ||||
|       Fix bug in how <command>VACUUM FULL</> handles <command>UPDATE</> chains (Tom, Pavan Deolasee) | ||||
|       Support explicit placement of the temporary-table schema within | ||||
|       <varname>search_path</>, and disable searching it for functions | ||||
|       and operators (Tom) | ||||
|      </para> | ||||
|      <para> | ||||
|       This is needed to allow a security-definer function to set a | ||||
|       truly secure value of <varname>search_path</>.  Without it, | ||||
|       an unprivileged SQL user can use temporary objects to execute code | ||||
|       with the privileges of the security-definer function (CVE-2007-2138). | ||||
|       See <xref linkend="sql-createfunction" | ||||
|       endterm="sql-createfunction-title"> for more information. | ||||
|      </para> | ||||
|      </listitem> | ||||
| 
 | ||||
|      <listitem> | ||||
|      <para> | ||||
|       Fix potential-data-corruption bug in how <command>VACUUM FULL</> handles | ||||
|       <command>UPDATE</> chains (Tom, Pavan Deolasee) | ||||
|      </para> | ||||
|      </listitem> | ||||
| 
 | ||||
|  | ||||
| @ -8,7 +8,7 @@ | ||||
|  * | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.138 2007/03/26 16:58:38 tgl Exp $ | ||||
|  *	  $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.139 2007/04/20 02:37:37 tgl Exp $ | ||||
|  * | ||||
|  * NOTES | ||||
|  *	  See acl.h. | ||||
| @ -1833,7 +1833,7 @@ pg_namespace_aclmask(Oid nsp_oid, Oid roleid, | ||||
| 	 */ | ||||
| 	if (isTempNamespace(nsp_oid)) | ||||
| 	{ | ||||
| 		if (pg_database_aclcheck(MyDatabaseId, GetUserId(), | ||||
| 		if (pg_database_aclcheck(MyDatabaseId, roleid, | ||||
| 								 ACL_CREATE_TEMP) == ACLCHECK_OK) | ||||
| 			return mask & ACL_ALL_RIGHTS_NAMESPACE; | ||||
| 		else | ||||
|  | ||||
| @ -13,7 +13,7 @@ | ||||
|  * Portions Copyright (c) 1994, Regents of the University of California | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.95 2007/04/12 22:34:45 neilc Exp $ | ||||
|  *	  $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.96 2007/04/20 02:37:37 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -62,12 +62,30 @@ | ||||
|  * SQL99.  Also, this provides a way to search the system namespace first | ||||
|  * without thereby making it the default creation target namespace.) | ||||
|  * | ||||
|  * For security reasons, searches using the search path will ignore the temp | ||||
|  * namespace when searching for any object type other than relations and | ||||
|  * types.  (We must allow types since temp tables have rowtypes.) | ||||
|  * | ||||
|  * The default creation target namespace is always the first element of the | ||||
|  * explicit list.  If the explicit list is empty, there is no default target. | ||||
|  * | ||||
|  * In bootstrap mode, the search path is set equal to 'pg_catalog', so that | ||||
|  * The textual specification of search_path can include "$user" to refer to | ||||
|  * the namespace named the same as the current user, if any.  (This is just | ||||
|  * ignored if there is no such namespace.)  Also, it can include "pg_temp" | ||||
|  * to refer to the current backend's temp namespace.  This is usually also | ||||
|  * ignorable if the temp namespace hasn't been set up, but there's a special | ||||
|  * case: if "pg_temp" appears first then it should be the default creation | ||||
|  * target.  We kluge this case a little bit so that the temp namespace isn't | ||||
|  * set up until the first attempt to create something in it.  (The reason for | ||||
|  * klugery is that we can't create the temp namespace outside a transaction, | ||||
|  * but initial GUC processing of search_path happens outside a transaction.) | ||||
|  * activeTempCreationPending is TRUE if "pg_temp" appears first in the string | ||||
|  * but is not reflected in activeCreationNamespace because the namespace isn't | ||||
|  * set up yet. | ||||
|  * | ||||
|  * In bootstrap mode, the search path is set equal to "pg_catalog", so that | ||||
|  * the system namespace is the only one searched or inserted into. | ||||
|  * initdb is also careful to set search_path to 'pg_catalog' for its | ||||
|  * initdb is also careful to set search_path to "pg_catalog" for its | ||||
|  * post-bootstrap standalone backend runs.	Otherwise the default search | ||||
|  * path is determined by GUC.  The factory default path contains the PUBLIC | ||||
|  * namespace (if it exists), preceded by the user's personal namespace | ||||
| @ -102,15 +120,20 @@ static List *activeSearchPath = NIL; | ||||
| /* default place to create stuff; if InvalidOid, no default */ | ||||
| static Oid	activeCreationNamespace = InvalidOid; | ||||
| 
 | ||||
| /* if TRUE, activeCreationNamespace is wrong, it should be temp namespace */ | ||||
| static bool activeTempCreationPending = false; | ||||
| 
 | ||||
| /* These variables are the values last derived from namespace_search_path: */ | ||||
| 
 | ||||
| static List *baseSearchPath = NIL; | ||||
| 
 | ||||
| static Oid	baseCreationNamespace = InvalidOid; | ||||
| 
 | ||||
| static bool baseTempCreationPending = false; | ||||
| 
 | ||||
| static Oid	namespaceUser = InvalidOid; | ||||
| 
 | ||||
| /* The above three values are valid only if baseSearchPathValid */ | ||||
| /* The above four values are valid only if baseSearchPathValid */ | ||||
| static bool baseSearchPathValid = true; | ||||
| 
 | ||||
| /* Override requests are remembered in a stack of OverrideStackEntry structs */ | ||||
| @ -262,6 +285,14 @@ RangeVarGetCreationNamespace(const RangeVar *newRelation) | ||||
| 
 | ||||
| 	if (newRelation->schemaname) | ||||
| 	{ | ||||
| 		/* check for pg_temp alias */ | ||||
| 		if (strcmp(newRelation->schemaname, "pg_temp") == 0) | ||||
| 		{ | ||||
| 			/* Initialize temp namespace if first time through */ | ||||
| 			if (!OidIsValid(myTempNamespace)) | ||||
| 				InitTempTableNamespace(); | ||||
| 			return myTempNamespace; | ||||
| 		} | ||||
| 		/* use exact schema given */ | ||||
| 		namespaceId = GetSysCacheOid(NAMESPACENAME, | ||||
| 									 CStringGetDatum(newRelation->schemaname), | ||||
| @ -277,6 +308,12 @@ RangeVarGetCreationNamespace(const RangeVar *newRelation) | ||||
| 	{ | ||||
| 		/* use the default creation namespace */ | ||||
| 		recomputeNamespacePath(); | ||||
| 		if (activeTempCreationPending) | ||||
| 		{ | ||||
| 			/* Need to initialize temp namespace */ | ||||
| 			InitTempTableNamespace(); | ||||
| 			return myTempNamespace; | ||||
| 		} | ||||
| 		namespaceId = activeCreationNamespace; | ||||
| 		if (!OidIsValid(namespaceId)) | ||||
| 			ereport(ERROR, | ||||
| @ -549,12 +586,16 @@ FuncnameGetCandidates(List *names, int nargs) | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			/* Consider only procs that are in the search path */ | ||||
| 			/*
 | ||||
| 			 * Consider only procs that are in the search path and are not | ||||
| 			 * in the temp namespace. | ||||
| 			 */ | ||||
| 			ListCell   *nsp; | ||||
| 
 | ||||
| 			foreach(nsp, activeSearchPath) | ||||
| 			{ | ||||
| 				if (procform->pronamespace == lfirst_oid(nsp)) | ||||
| 				if (procform->pronamespace == lfirst_oid(nsp) && | ||||
| 					procform->pronamespace != myTempNamespace) | ||||
| 					break; | ||||
| 				pathpos++; | ||||
| 			} | ||||
| @ -770,6 +811,9 @@ OpernameGetOprid(List *names, Oid oprleft, Oid oprright) | ||||
| 		Oid			namespaceId = lfirst_oid(l); | ||||
| 		int			i; | ||||
| 
 | ||||
| 		if (namespaceId == myTempNamespace) | ||||
| 			continue;			/* do not look in temp namespace */ | ||||
| 
 | ||||
| 		for (i = 0; i < catlist->n_members; i++) | ||||
| 		{ | ||||
| 			HeapTuple	opertup = &catlist->members[i]->tuple; | ||||
| @ -872,12 +916,16 @@ OpernameGetCandidates(List *names, char oprkind) | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			/* Consider only opers that are in the search path */ | ||||
| 			/*
 | ||||
| 			 * Consider only opers that are in the search path and are not | ||||
| 			 * in the temp namespace. | ||||
| 			 */ | ||||
| 			ListCell   *nsp; | ||||
| 
 | ||||
| 			foreach(nsp, activeSearchPath) | ||||
| 			{ | ||||
| 				if (operform->oprnamespace == lfirst_oid(nsp)) | ||||
| 				if (operform->oprnamespace == lfirst_oid(nsp) && | ||||
| 					operform->oprnamespace != myTempNamespace) | ||||
| 					break; | ||||
| 				pathpos++; | ||||
| 			} | ||||
| @ -1025,6 +1073,9 @@ OpclassnameGetOpcid(Oid amid, const char *opcname) | ||||
| 	{ | ||||
| 		Oid			namespaceId = lfirst_oid(l); | ||||
| 
 | ||||
| 		if (namespaceId == myTempNamespace) | ||||
| 			continue;			/* do not look in temp namespace */ | ||||
| 
 | ||||
| 		opcid = GetSysCacheOid(CLAAMNAMENSP, | ||||
| 							   ObjectIdGetDatum(amid), | ||||
| 							   PointerGetDatum(opcname), | ||||
| @ -1108,6 +1159,9 @@ OpfamilynameGetOpfid(Oid amid, const char *opfname) | ||||
| 	{ | ||||
| 		Oid			namespaceId = lfirst_oid(l); | ||||
| 
 | ||||
| 		if (namespaceId == myTempNamespace) | ||||
| 			continue;			/* do not look in temp namespace */ | ||||
| 
 | ||||
| 		opfid = GetSysCacheOid(OPFAMILYAMNAMENSP, | ||||
| 							   ObjectIdGetDatum(amid), | ||||
| 							   PointerGetDatum(opfname), | ||||
| @ -1190,6 +1244,9 @@ ConversionGetConid(const char *conname) | ||||
| 	{ | ||||
| 		Oid			namespaceId = lfirst_oid(l); | ||||
| 
 | ||||
| 		if (namespaceId == myTempNamespace) | ||||
| 			continue;			/* do not look in temp namespace */ | ||||
| 
 | ||||
| 		conid = GetSysCacheOid(CONNAMENSP, | ||||
| 							   PointerGetDatum(conname), | ||||
| 							   ObjectIdGetDatum(namespaceId), | ||||
| @ -1316,6 +1373,19 @@ LookupExplicitNamespace(const char *nspname) | ||||
| 	Oid			namespaceId; | ||||
| 	AclResult	aclresult; | ||||
| 
 | ||||
| 	/* check for pg_temp alias */ | ||||
| 	if (strcmp(nspname, "pg_temp") == 0) | ||||
| 	{ | ||||
| 		if (OidIsValid(myTempNamespace)) | ||||
| 			return myTempNamespace; | ||||
| 		/*
 | ||||
| 		 * Since this is used only for looking up existing objects, there | ||||
| 		 * is no point in trying to initialize the temp namespace here; | ||||
| 		 * and doing so might create problems for some callers. | ||||
| 		 * Just fall through and give the "does not exist" error. | ||||
| 		 */ | ||||
| 	} | ||||
| 
 | ||||
| 	namespaceId = GetSysCacheOid(NAMESPACENAME, | ||||
| 								 CStringGetDatum(nspname), | ||||
| 								 0, 0, 0); | ||||
| @ -1336,7 +1406,11 @@ LookupExplicitNamespace(const char *nspname) | ||||
|  * LookupCreationNamespace | ||||
|  *		Look up the schema and verify we have CREATE rights on it. | ||||
|  * | ||||
|  * This is just like LookupExplicitNamespace except for the permission check. | ||||
|  * This is just like LookupExplicitNamespace except for the permission check, | ||||
|  * and that we are willing to create pg_temp if needed. | ||||
|  * | ||||
|  * Note: calling this may result in a CommandCounterIncrement operation, | ||||
|  * if we have to create or clean out the temp namespace. | ||||
|  */ | ||||
| Oid | ||||
| LookupCreationNamespace(const char *nspname) | ||||
| @ -1344,6 +1418,15 @@ LookupCreationNamespace(const char *nspname) | ||||
| 	Oid			namespaceId; | ||||
| 	AclResult	aclresult; | ||||
| 
 | ||||
| 	/* check for pg_temp alias */ | ||||
| 	if (strcmp(nspname, "pg_temp") == 0) | ||||
| 	{ | ||||
| 		/* Initialize temp namespace if first time through */ | ||||
| 		if (!OidIsValid(myTempNamespace)) | ||||
| 			InitTempTableNamespace(); | ||||
| 		return myTempNamespace; | ||||
| 	} | ||||
| 
 | ||||
| 	namespaceId = GetSysCacheOid(NAMESPACENAME, | ||||
| 								 CStringGetDatum(nspname), | ||||
| 								 0, 0, 0); | ||||
| @ -1369,21 +1452,28 @@ LookupCreationNamespace(const char *nspname) | ||||
|  * Note: this does not apply any permissions check.  Callers must check | ||||
|  * for CREATE rights on the selected namespace when appropriate. | ||||
|  * | ||||
|  * This is *not* used for tables.  Hence, the TEMP table namespace is | ||||
|  * never selected as the creation target. | ||||
|  * Note: calling this may result in a CommandCounterIncrement operation, | ||||
|  * if we have to create or clean out the temp namespace. | ||||
|  */ | ||||
| Oid | ||||
| QualifiedNameGetCreationNamespace(List *names, char **objname_p) | ||||
| { | ||||
| 	char	   *schemaname; | ||||
| 	char	   *objname; | ||||
| 	Oid			namespaceId; | ||||
| 
 | ||||
| 	/* deconstruct the name list */ | ||||
| 	DeconstructQualifiedName(names, &schemaname, &objname); | ||||
| 	DeconstructQualifiedName(names, &schemaname, objname_p); | ||||
| 
 | ||||
| 	if (schemaname) | ||||
| 	{ | ||||
| 		/* check for pg_temp alias */ | ||||
| 		if (strcmp(schemaname, "pg_temp") == 0) | ||||
| 		{ | ||||
| 			/* Initialize temp namespace if first time through */ | ||||
| 			if (!OidIsValid(myTempNamespace)) | ||||
| 				InitTempTableNamespace(); | ||||
| 			return myTempNamespace; | ||||
| 		} | ||||
| 		/* use exact schema given */ | ||||
| 		namespaceId = GetSysCacheOid(NAMESPACENAME, | ||||
| 									 CStringGetDatum(schemaname), | ||||
| @ -1398,6 +1488,12 @@ QualifiedNameGetCreationNamespace(List *names, char **objname_p) | ||||
| 	{ | ||||
| 		/* use the default creation namespace */ | ||||
| 		recomputeNamespacePath(); | ||||
| 		if (activeTempCreationPending) | ||||
| 		{ | ||||
| 			/* Need to initialize temp namespace */ | ||||
| 			InitTempTableNamespace(); | ||||
| 			return myTempNamespace; | ||||
| 		} | ||||
| 		namespaceId = activeCreationNamespace; | ||||
| 		if (!OidIsValid(namespaceId)) | ||||
| 			ereport(ERROR, | ||||
| @ -1405,7 +1501,6 @@ QualifiedNameGetCreationNamespace(List *names, char **objname_p) | ||||
| 					 errmsg("no schema has been selected to create in"))); | ||||
| 	} | ||||
| 
 | ||||
| 	*objname_p = objname; | ||||
| 	return namespaceId; | ||||
| } | ||||
| 
 | ||||
| @ -1634,6 +1729,7 @@ PushOverrideSearchPath(OverrideSearchPath *newpath) | ||||
| 	/* And make it active. */ | ||||
| 	activeSearchPath = entry->searchPath; | ||||
| 	activeCreationNamespace = entry->creationNamespace; | ||||
| 	activeTempCreationPending = false;			/* XXX is this OK? */ | ||||
| 
 | ||||
| 	MemoryContextSwitchTo(oldcxt); | ||||
| } | ||||
| @ -1667,12 +1763,14 @@ PopOverrideSearchPath(void) | ||||
| 		entry = (OverrideStackEntry *) linitial(overrideStack); | ||||
| 		activeSearchPath = entry->searchPath; | ||||
| 		activeCreationNamespace = entry->creationNamespace; | ||||
| 		activeTempCreationPending = false;			/* XXX is this OK? */ | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		/* If not baseSearchPathValid, this is useless but harmless */ | ||||
| 		activeSearchPath = baseSearchPath; | ||||
| 		activeCreationNamespace = baseCreationNamespace; | ||||
| 		activeTempCreationPending = baseTempCreationPending; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -1706,6 +1804,10 @@ FindConversionByName(List *name) | ||||
| 		foreach(l, activeSearchPath) | ||||
| 		{ | ||||
| 			namespaceId = lfirst_oid(l); | ||||
| 
 | ||||
| 			if (namespaceId == myTempNamespace) | ||||
| 				continue;			/* do not look in temp namespace */ | ||||
| 
 | ||||
| 			conoid = FindConversion(conversion_name, namespaceId); | ||||
| 			if (OidIsValid(conoid)) | ||||
| 				return conoid; | ||||
| @ -1731,6 +1833,9 @@ FindDefaultConversionProc(int4 for_encoding, int4 to_encoding) | ||||
| 	{ | ||||
| 		Oid			namespaceId = lfirst_oid(l); | ||||
| 
 | ||||
| 		if (namespaceId == myTempNamespace) | ||||
| 			continue;			/* do not look in temp namespace */ | ||||
| 
 | ||||
| 		proc = FindDefaultConversion(namespaceId, for_encoding, to_encoding); | ||||
| 		if (OidIsValid(proc)) | ||||
| 			return proc; | ||||
| @ -1752,6 +1857,7 @@ recomputeNamespacePath(void) | ||||
| 	List	   *oidlist; | ||||
| 	List	   *newpath; | ||||
| 	ListCell   *l; | ||||
| 	bool		temp_missing; | ||||
| 	Oid			firstNS; | ||||
| 	MemoryContext oldcxt; | ||||
| 
 | ||||
| @ -1781,6 +1887,7 @@ recomputeNamespacePath(void) | ||||
| 	 * already been accepted.)	Don't make duplicate entries, either. | ||||
| 	 */ | ||||
| 	oidlist = NIL; | ||||
| 	temp_missing = false; | ||||
| 	foreach(l, namelist) | ||||
| 	{ | ||||
| 		char	   *curname = (char *) lfirst(l); | ||||
| @ -1810,6 +1917,21 @@ recomputeNamespacePath(void) | ||||
| 					oidlist = lappend_oid(oidlist, namespaceId); | ||||
| 			} | ||||
| 		} | ||||
| 		else if (strcmp(curname, "pg_temp") == 0) | ||||
| 		{ | ||||
| 			/* pg_temp --- substitute temp namespace, if any */ | ||||
| 			if (OidIsValid(myTempNamespace)) | ||||
| 			{ | ||||
| 				if (!list_member_oid(oidlist, myTempNamespace)) | ||||
| 					oidlist = lappend_oid(oidlist, myTempNamespace); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				/* If it ought to be the creation namespace, set flag */ | ||||
| 				if (oidlist == NIL) | ||||
| 					temp_missing = true; | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			/* normal namespace reference */ | ||||
| @ -1825,7 +1947,9 @@ recomputeNamespacePath(void) | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Remember the first member of the explicit list. | ||||
| 	 * Remember the first member of the explicit list.  (Note: this is | ||||
| 	 * nominally wrong if temp_missing, but we need it anyway to distinguish | ||||
| 	 * explicit from implicit mention of pg_catalog.) | ||||
| 	 */ | ||||
| 	if (oidlist == NIL) | ||||
| 		firstNS = InvalidOid; | ||||
| @ -1856,6 +1980,7 @@ recomputeNamespacePath(void) | ||||
| 	list_free(baseSearchPath); | ||||
| 	baseSearchPath = newpath; | ||||
| 	baseCreationNamespace = firstNS; | ||||
| 	baseTempCreationPending = temp_missing; | ||||
| 
 | ||||
| 	/* Mark the path valid. */ | ||||
| 	baseSearchPathValid = true; | ||||
| @ -1864,6 +1989,7 @@ recomputeNamespacePath(void) | ||||
| 	/* And make it active. */ | ||||
| 	activeSearchPath = baseSearchPath; | ||||
| 	activeCreationNamespace = baseCreationNamespace; | ||||
| 	activeTempCreationPending = baseTempCreationPending; | ||||
| 
 | ||||
| 	/* Clean up. */ | ||||
| 	pfree(rawname); | ||||
| @ -1881,6 +2007,8 @@ InitTempTableNamespace(void) | ||||
| 	char		namespaceName[NAMEDATALEN]; | ||||
| 	Oid			namespaceId; | ||||
| 
 | ||||
| 	Assert(!OidIsValid(myTempNamespace)); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * First, do permission check to see if we are authorized to make temp | ||||
| 	 * tables.	We use a nonstandard error message here since "databasename: | ||||
| @ -1940,16 +2068,6 @@ InitTempTableNamespace(void) | ||||
| 	baseSearchPathValid = false;	/* need to rebuild list */ | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Remove all temp tables from the temporary namespace. | ||||
|  */ | ||||
| void | ||||
| ResetTempTableNamespace(void) | ||||
| { | ||||
| 	if (OidIsValid(myTempNamespace)) | ||||
| 		RemoveTempRelations(myTempNamespace); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * End-of-transaction cleanup for namespaces. | ||||
|  */ | ||||
| @ -1995,6 +2113,7 @@ AtEOXact_Namespace(bool isCommit) | ||||
| 		/* If not baseSearchPathValid, this is useless but harmless */ | ||||
| 		activeSearchPath = baseSearchPath; | ||||
| 		activeCreationNamespace = baseCreationNamespace; | ||||
| 		activeTempCreationPending = baseTempCreationPending; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -2046,12 +2165,14 @@ AtEOSubXact_Namespace(bool isCommit, SubTransactionId mySubid, | ||||
| 		entry = (OverrideStackEntry *) linitial(overrideStack); | ||||
| 		activeSearchPath = entry->searchPath; | ||||
| 		activeCreationNamespace = entry->creationNamespace; | ||||
| 		activeTempCreationPending = false;			/* XXX is this OK? */ | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		/* If not baseSearchPathValid, this is useless but harmless */ | ||||
| 		activeSearchPath = baseSearchPath; | ||||
| 		activeCreationNamespace = baseCreationNamespace; | ||||
| 		activeTempCreationPending = baseTempCreationPending; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -2099,6 +2220,16 @@ RemoveTempRelationsCallback(int code, Datum arg) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Remove all temp tables from the temporary namespace. | ||||
|  */ | ||||
| void | ||||
| ResetTempTableNamespace(void) | ||||
| { | ||||
| 	if (OidIsValid(myTempNamespace)) | ||||
| 		RemoveTempRelations(myTempNamespace); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|  * Routines for handling the GUC variable 'search_path'. | ||||
| @ -2132,8 +2263,9 @@ assign_search_path(const char *newval, bool doit, GucSource source) | ||||
| 	{ | ||||
| 		/*
 | ||||
| 		 * Verify that all the names are either valid namespace names or | ||||
| 		 * "$user".  We do not require $user to correspond to a valid | ||||
| 		 * namespace.  We do not check for USAGE rights, either; should we? | ||||
| 		 * "$user" or "pg_temp".  We do not require $user to correspond to a | ||||
| 		 * valid namespace, and pg_temp might not exist yet.  We do not check | ||||
| 		 * for USAGE rights, either; should we? | ||||
| 		 * | ||||
| 		 * When source == PGC_S_TEST, we are checking the argument of an ALTER | ||||
| 		 * DATABASE SET or ALTER USER SET command.	It could be that the | ||||
| @ -2147,6 +2279,8 @@ assign_search_path(const char *newval, bool doit, GucSource source) | ||||
| 
 | ||||
| 			if (strcmp(curname, "$user") == 0) | ||||
| 				continue; | ||||
| 			if (strcmp(curname, "pg_temp") == 0) | ||||
| 				continue; | ||||
| 			if (!SearchSysCacheExists(NAMESPACENAME, | ||||
| 									  CStringGetDatum(curname), | ||||
| 									  0, 0, 0)) | ||||
| @ -2190,10 +2324,12 @@ InitializeSearchPath(void) | ||||
| 		baseSearchPath = list_make1_oid(PG_CATALOG_NAMESPACE); | ||||
| 		MemoryContextSwitchTo(oldcxt); | ||||
| 		baseCreationNamespace = PG_CATALOG_NAMESPACE; | ||||
| 		baseTempCreationPending = false; | ||||
| 		baseSearchPathValid = true; | ||||
| 		namespaceUser = GetUserId(); | ||||
| 		activeSearchPath = baseSearchPath; | ||||
| 		activeCreationNamespace = baseCreationNamespace; | ||||
| 		activeTempCreationPending = baseTempCreationPending; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| @ -2227,6 +2363,9 @@ NamespaceCallback(Datum arg, Oid relid) | ||||
|  * | ||||
|  * The returned list includes the implicitly-prepended namespaces only if | ||||
|  * includeImplicit is true. | ||||
|  * | ||||
|  * Note: calling this may result in a CommandCounterIncrement operation, | ||||
|  * if we have to create or clean out the temp namespace. | ||||
|  */ | ||||
| List * | ||||
| fetch_search_path(bool includeImplicit) | ||||
| @ -2235,6 +2374,19 @@ fetch_search_path(bool includeImplicit) | ||||
| 
 | ||||
| 	recomputeNamespacePath(); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * If the temp namespace should be first, force it to exist.  This is | ||||
| 	 * so that callers can trust the result to reflect the actual default | ||||
| 	 * creation namespace.  It's a bit bogus to do this here, since | ||||
| 	 * current_schema() is supposedly a stable function without side-effects, | ||||
| 	 * but the alternatives seem worse. | ||||
| 	 */ | ||||
| 	if (activeTempCreationPending) | ||||
| 	{ | ||||
| 		InitTempTableNamespace(); | ||||
| 		recomputeNamespacePath(); | ||||
| 	} | ||||
| 
 | ||||
| 	result = list_copy(activeSearchPath); | ||||
| 	if (!includeImplicit) | ||||
| 	{ | ||||
|  | ||||
| @ -137,3 +137,61 @@ CREATE TEMP TABLE temptest4(col int REFERENCES temptest3); | ||||
| COMMIT; | ||||
| ERROR:  unsupported ON COMMIT and foreign key combination | ||||
| DETAIL:  Table "temptest4" references "temptest3", but they do not have the same ON COMMIT setting. | ||||
| -- Test manipulation of temp schema's placement in search path | ||||
| create table public.whereami (f1 text); | ||||
| insert into public.whereami values ('public'); | ||||
| create temp table whereami (f1 text); | ||||
| insert into whereami values ('temp'); | ||||
| create function public.whoami() returns text | ||||
|   as $$select 'public'::text$$ language sql; | ||||
| create function pg_temp.whoami() returns text | ||||
|   as $$select 'temp'::text$$ language sql; | ||||
| -- default should have pg_temp implicitly first, but only for tables | ||||
| select * from whereami; | ||||
|   f1   | ||||
| ------ | ||||
|  temp | ||||
| (1 row) | ||||
| 
 | ||||
| select whoami(); | ||||
|  whoami  | ||||
| -------- | ||||
|  public | ||||
| (1 row) | ||||
| 
 | ||||
| -- can list temp first explicitly, but it still doesn't affect functions | ||||
| set search_path = pg_temp, public; | ||||
| select * from whereami; | ||||
|   f1   | ||||
| ------ | ||||
|  temp | ||||
| (1 row) | ||||
| 
 | ||||
| select whoami(); | ||||
|  whoami  | ||||
| -------- | ||||
|  public | ||||
| (1 row) | ||||
| 
 | ||||
| -- or put it last for security | ||||
| set search_path = public, pg_temp; | ||||
| select * from whereami; | ||||
|    f1    | ||||
| -------- | ||||
|  public | ||||
| (1 row) | ||||
| 
 | ||||
| select whoami(); | ||||
|  whoami  | ||||
| -------- | ||||
|  public | ||||
| (1 row) | ||||
| 
 | ||||
| -- you can invoke a temp function explicitly, though | ||||
| select pg_temp.whoami(); | ||||
|  whoami  | ||||
| -------- | ||||
|  temp | ||||
| (1 row) | ||||
| 
 | ||||
| drop table public.whereami; | ||||
|  | ||||
| @ -118,3 +118,36 @@ BEGIN; | ||||
| CREATE TEMP TABLE temptest3(col int PRIMARY KEY) ON COMMIT DELETE ROWS; | ||||
| CREATE TEMP TABLE temptest4(col int REFERENCES temptest3); | ||||
| COMMIT; | ||||
| 
 | ||||
| -- Test manipulation of temp schema's placement in search path | ||||
| 
 | ||||
| create table public.whereami (f1 text); | ||||
| insert into public.whereami values ('public'); | ||||
| 
 | ||||
| create temp table whereami (f1 text); | ||||
| insert into whereami values ('temp'); | ||||
| 
 | ||||
| create function public.whoami() returns text | ||||
|   as $$select 'public'::text$$ language sql; | ||||
| 
 | ||||
| create function pg_temp.whoami() returns text | ||||
|   as $$select 'temp'::text$$ language sql; | ||||
| 
 | ||||
| -- default should have pg_temp implicitly first, but only for tables | ||||
| select * from whereami; | ||||
| select whoami(); | ||||
| 
 | ||||
| -- can list temp first explicitly, but it still doesn't affect functions | ||||
| set search_path = pg_temp, public; | ||||
| select * from whereami; | ||||
| select whoami(); | ||||
| 
 | ||||
| -- or put it last for security | ||||
| set search_path = public, pg_temp; | ||||
| select * from whereami; | ||||
| select whoami(); | ||||
| 
 | ||||
| -- you can invoke a temp function explicitly, though | ||||
| select pg_temp.whoami(); | ||||
| 
 | ||||
| drop table public.whereami; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user