OSDN Git Service

Create a new GUC variable search_path to control the namespace search
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 1 Apr 2002 03:34:27 +0000 (03:34 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 1 Apr 2002 03:34:27 +0000 (03:34 +0000)
path.  The default behavior if no per-user schemas are created is that
all users share a 'public' namespace, thus providing behavior backwards
compatible with 7.2 and earlier releases.  Probably the semantics and
default setting will need to be fine-tuned, but this is a start.

13 files changed:
doc/src/sgml/runtime.sgml
src/backend/access/transam/xact.c
src/backend/catalog/namespace.c
src/backend/parser/gram.y
src/backend/utils/adt/varlena.c
src/backend/utils/init/postinit.c
src/backend/utils/misc/guc.c
src/backend/utils/misc/postgresql.conf.sample
src/bin/psql/tab-complete.c
src/include/access/xact.h
src/include/catalog/namespace.h
src/include/catalog/pg_namespace.h
src/include/utils/builtins.h

index 9c118d2..43b6931 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.110 2002/03/24 04:31:06 tgl Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.111 2002/04/01 03:34:24 tgl Exp $
 -->
 
 <Chapter Id="runtime">
@@ -1174,7 +1174,7 @@ dynamic_library_path = '/usr/local/lib/postgresql:/home/my_project/lib:$libdir'
 
        <para>
         The default value for this parameter is
-        <literal>$libdir</literal>. If the value is set to an empty
+        <literal>'$libdir'</literal>. If the value is set to an empty
         string, the automatic path search is turned off.
        </para>
 
@@ -1190,6 +1190,69 @@ dynamic_library_path = '/usr/local/lib/postgresql:/home/my_project/lib:$libdir'
      </varlistentry>
 
      <varlistentry>
+      <term><varname>SEARCH_PATH</varname> (<type>string</type>)</term>
+      <indexterm><primary>search_path</></>
+      <indexterm><primary>namespaces</></>
+      <listitem>
+       <para>
+        This variable specifies the order in which namespaces are searched
+       when an object (table, datatype, function, etc) is referenced by a
+       simple name with no schema component.  When there are objects of
+       identical names in different namespaces, the one found first
+       in the search path is used.  An object that is not in any of the
+       namespaces in the search path can only be referenced by specifying
+       its containing namespace with a qualified (dotted) name.
+       </para>
+
+       <para>
+        The value for search_path has to be a comma-separated
+        list of namespace (schema) names.  If one of the list items is
+        the special value <literal>$user</literal>, then the namespace
+       having the same name as the SESSION_USER is substituted, if there
+       is such a namespace.  (If not, <literal>$user</literal> is ignored.)
+       </para>
+
+       <para>
+        The system catalog namespace, <literal>pg_catalog</>, is always
+       searched, whether it is mentioned in the path or not.  If it is
+       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 namespace,
+       <literal>pg_temp_nnn</>, is implicitly searched before any of
+       these.
+       </para>
+
+       <para>
+        When objects are created without specifying a particular target
+       namespace, they will be placed in the first namespace listed
+       in the search path, or in <literal>pg_catalog</> if the search
+       path list is empty.  (Note that users do not normally have
+       permission to write in <literal>pg_catalog</>, so an empty search
+       path is not a very useful setting.)
+       </para>
+
+       <para>
+        The default value for this parameter is
+        <literal>'$user, public'</literal> (where the second part will be
+       ignored if there is no namespace named <literal>public</>).
+       This supports shared use of a database (where no users
+       have private namespaces, and all share use of <literal>public</>),
+       private per-user namespaces, and combinations of these.  Other
+       effects can be obtained by altering the default search path
+       setting, either globally or per-user.
+       </para>
+
+       <para>
+        By default, a newly created database will contain a world-writable
+       namespace named <literal>public</>, but no private namespaces.
+       The administrator may choose to restrict permissions on
+       <literal>public</> or even remove it, if that suits his purposes.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
       <indexterm>
        <primary>fsync</primary>
       </indexterm>
index 046f3d5..ca66b0a 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.119 2002/03/31 06:26:29 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.120 2002/04/01 03:34:25 tgl Exp $
  *
  * NOTES
  *             Transaction aborts can now occur two ways:
@@ -241,8 +241,10 @@ bool               AMI_OVERRIDE = false;
  * ----------------------------------------------------------------
  */
 
+#ifdef NOT_USED
+
 /* --------------------------------
- *             TranactionFlushEnabled()
+ *             TransactionFlushEnabled()
  *             SetTransactionFlushEnabled()
  *
  *             These are used to test and set the "TransactionFlushState"
@@ -261,13 +263,14 @@ TransactionFlushEnabled(void)
        return TransactionFlushState;
 }
 
-#ifdef NOT_USED
 void
 SetTransactionFlushEnabled(bool state)
 {
        TransactionFlushState = (state == true);
 }
 
+#endif
+
 
 /* --------------------------------
  *             IsTransactionState
@@ -300,7 +303,6 @@ IsTransactionState(void)
         */
        return false;
 }
-#endif
 
 /* --------------------------------
  *             IsAbortedTransactionBlockState
index a1be64b..fab1912 100644 (file)
@@ -13,7 +13,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.4 2002/03/31 06:26:30 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.5 2002/04/01 03:34:25 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -30,7 +30,9 @@
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
 #include "storage/backendid.h"
+#include "utils/builtins.h"
 #include "utils/fmgroids.h"
+#include "utils/guc.h"
 #include "utils/lsyscache.h"
 #include "utils/syscache.h"
 
@@ -71,6 +73,12 @@ static Oid   defaultCreationNamespace = PG_CATALOG_NAMESPACE;
  */
 static Oid     myTempNamespace = InvalidOid;
 
+/*
+ * This is the text equivalent of the search path --- it's the value
+ * of the GUC variable 'search_path'.
+ */
+char *namespace_search_path = NULL;
+
 
 /*
  * Deletion ordering constraint item.
@@ -702,3 +710,202 @@ RemoveTempRelationsCallback(void)
                CommitTransactionCommand();
        }
 }
+
+/*
+ * Routines for handling the GUC variable 'search_path'.
+ */
+
+/* parse_hook: is proposed value valid? */
+bool
+check_search_path(const char *proposed)
+{
+       char       *rawname;
+       List       *namelist;
+       List       *l;
+
+       /* Need a modifiable copy of string */
+       rawname = pstrdup(proposed);
+
+       /* Parse string into list of identifiers */
+       if (!SplitIdentifierString(rawname, ',', &namelist))
+       {
+               /* syntax error in name list */
+               pfree(rawname);
+               freeList(namelist);
+               return false;
+       }
+
+       /*
+        * If we aren't inside a transaction, we cannot do database access so
+        * cannot verify the individual names.  Must accept the list on faith.
+        * (This case can happen, for example, when the postmaster reads a
+        * search_path setting from postgresql.conf.)
+        */
+       if (!IsTransactionState())
+       {
+               pfree(rawname);
+               freeList(namelist);
+               return true;
+       }
+
+       /*
+        * Verify that all the names are either valid namespace names or "$user".
+        * (We do not require $user to correspond to a valid namespace; should we?)
+        */
+       foreach(l, namelist)
+       {
+               char   *curname = (char *) lfirst(l);
+
+               if (strcmp(curname, "$user") == 0)
+                       continue;
+               if (!SearchSysCacheExists(NAMESPACENAME,
+                                                                 CStringGetDatum(curname),
+                                                                 0, 0, 0))
+               {
+                       pfree(rawname);
+                       freeList(namelist);
+                       return false;
+               }
+       }
+
+       pfree(rawname);
+       freeList(namelist);
+
+       return true;
+}
+
+/* assign_hook: do extra actions needed when assigning to search_path */
+void
+assign_search_path(const char *newval)
+{
+       char       *rawname;
+       List       *namelist;
+       List       *oidlist;
+       List       *newpath;
+       List       *l;
+       MemoryContext oldcxt;
+
+       /*
+        * If we aren't inside a transaction, we cannot do database access so
+        * cannot look up the names.  In this case, do nothing; the internal
+        * search path will be fixed later by InitializeSearchPath.  (We assume
+        * this situation can only happen in the postmaster or early in backend
+        * startup.)
+        */
+       if (!IsTransactionState())
+               return;
+
+       /* Need a modifiable copy of string */
+       rawname = pstrdup(newval);
+
+       /* Parse string into list of identifiers */
+       if (!SplitIdentifierString(rawname, ',', &namelist))
+       {
+               /* syntax error in name list */
+               /* this should not happen if GUC checked check_search_path */
+               elog(ERROR, "assign_search_path: invalid list syntax");
+       }
+
+       /*
+        * Convert the list of names to a list of OIDs.  If any names are not
+        * recognizable, just leave them out of the list.  (This is our only
+        * reasonable recourse when the already-accepted default is bogus.)
+        */
+       oidlist = NIL;
+       foreach(l, namelist)
+       {
+               char   *curname = (char *) lfirst(l);
+               Oid             namespaceId;
+
+               if (strcmp(curname, "$user") == 0)
+               {
+                       /* $user --- substitute namespace matching user name, if any */
+                       HeapTuple       tuple;
+
+                       tuple = SearchSysCache(SHADOWSYSID,
+                                                                  ObjectIdGetDatum(GetSessionUserId()),
+                                                                  0, 0, 0);
+                       if (HeapTupleIsValid(tuple))
+                       {
+                               char   *uname;
+
+                               uname = NameStr(((Form_pg_shadow) GETSTRUCT(tuple))->usename);
+                               namespaceId = GetSysCacheOid(NAMESPACENAME,
+                                                                                        CStringGetDatum(uname),
+                                                                                        0, 0, 0);
+                               if (OidIsValid(namespaceId))
+                                       oidlist = lappendi(oidlist, namespaceId);
+                               ReleaseSysCache(tuple);
+                       }
+               }
+               else
+               {
+                       /* normal namespace reference */
+                       namespaceId = GetSysCacheOid(NAMESPACENAME,
+                                                                                CStringGetDatum(curname),
+                                                                                0, 0, 0);
+                       if (OidIsValid(namespaceId))
+                               oidlist = lappendi(oidlist, namespaceId);
+               }
+       }
+
+       /*
+        * Now that we've successfully built the new list of namespace OIDs,
+        * save it in permanent storage.
+        */
+       oldcxt = MemoryContextSwitchTo(TopMemoryContext);
+       newpath = listCopy(oidlist);
+       MemoryContextSwitchTo(oldcxt);
+
+       /* Now safe to assign to state variable. */
+       freeList(namespaceSearchPath);
+       namespaceSearchPath = newpath;
+
+       /*
+        * Update info derived from search path.
+        */
+       pathContainsSystemNamespace = intMember(PG_CATALOG_NAMESPACE,
+                                                                                       namespaceSearchPath);
+
+       if (namespaceSearchPath == NIL)
+               defaultCreationNamespace = PG_CATALOG_NAMESPACE;
+       else
+               defaultCreationNamespace = (Oid) lfirsti(namespaceSearchPath);
+
+       /* Clean up. */
+       pfree(rawname);
+       freeList(namelist);
+       freeList(oidlist);
+}
+
+/*
+ * InitializeSearchPath: initialize module during InitPostgres.
+ *
+ * This is called after we are up enough to be able to do catalog lookups.
+ */
+void
+InitializeSearchPath(void)
+{
+       /*
+        * In normal multi-user mode, we want the default search path to be
+        * '$user,public' (or as much of that as exists, anyway; see the
+        * error handling in assign_search_path); which is what guc.c has as
+        * the wired-in default value.  But in bootstrap or standalone-backend
+        * mode, the default search path must be empty so that initdb correctly
+        * creates everything in PG_CATALOG_NAMESPACE.  Accordingly, adjust the
+        * default setting if we are not running under postmaster.  (If a
+        * non-default setting has been supplied, this will not overwrite it.)
+        */
+       if (!IsUnderPostmaster)
+       {
+               SetConfigOption("search_path", "",
+                                               PGC_POSTMASTER, PGC_S_DEFAULT);
+       }
+       /*
+        * If a search path setting was provided before we were able to execute
+        * lookups, establish the internal search path now.
+        */
+       if (namespace_search_path && *namespace_search_path &&
+               namespaceSearchPath == NIL)
+               assign_search_path(namespace_search_path);
+}
index 4ebddde..64cc3d6 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.297 2002/03/29 19:06:10 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.298 2002/04/01 03:34:25 tgl Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -94,6 +94,7 @@ static void insertSelectOptions(SelectStmt *stmt,
 static Node *makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg);
 static Node *doNegate(Node *n);
 static void doNegateFloat(Value *v);
+static bool set_name_needs_quotes(const char *name);
 
 #define MASK(b) (1 << (b))
 
@@ -909,19 +910,26 @@ var_value:  opt_boolean                                           { $$ = $1; }
                                if ($1 == NIL)
                                        elog(ERROR, "SET must have at least one argument");
 
+                               /* compute space needed; allow for quotes and comma */
                                foreach (n, $1)
                                {
                                        Value *p = (Value *) lfirst(n);
                                        Assert(IsA(p, String));
-                                       /* keep track of room for string and trailing comma */
-                                       slen += (strlen(p->val.str) + 1);
+                                       slen += (strlen(p->val.str) + 3);
                                }
                                result = palloc(slen + 1);
                                *result = '\0';
                                foreach (n, $1)
                                {
                                        Value *p = (Value *) lfirst(n);
-                                       strcat(result, p->val.str);
+                                       if (set_name_needs_quotes(p->val.str))
+                                       {
+                                               strcat(result, "\"");
+                                               strcat(result, p->val.str);
+                                               strcat(result, "\"");
+                                       }
+                                       else
+                                               strcat(result, p->val.str);
                                        strcat(result, ",");
                                }
                                /* remove the trailing comma from the last element */
@@ -6568,3 +6576,25 @@ doNegateFloat(Value *v)
                v->val.str = newval;
        }
 }
+
+/*
+ * Decide whether to put double quotes around a name appearing in a SET
+ * name_list.  Presently, do so if the name contains whitespace, commas,
+ * or uppercase characters.  (This is correct assuming that the result
+ * will be deparsed by SplitIdentifierString or similar logic.)
+ */
+static bool
+set_name_needs_quotes(const char *name)
+{
+       if (*name == '\0')
+               return true;                    /* empty name does need quotes */
+       while (*name)
+       {
+               if (*name == ',' ||
+                       isspace((unsigned char) *name) ||
+                       isupper((unsigned char) *name))
+                       return true;
+               name++;
+       }
+       return false;
+}
index ce3e8dc..5afaf39 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/adt/varlena.c,v 1.80 2002/03/30 01:02:42 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/adt/varlena.c,v 1.81 2002/04/01 03:34:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1046,28 +1046,82 @@ name_text(PG_FUNCTION_ARGS)
  * functions that take a text parameter representing a qualified name.
  * We split the name at dots, downcase if not double-quoted, and
  * truncate names if they're too long.
- *
- * This is a kluge, really, and exists only for historical reasons.
- * A better notation for such functions would be nextval(relname).
  */
 List *
 textToQualifiedNameList(text *textval, const char *caller)
 {
        char       *rawname;
-       char       *nextp;
        List       *result = NIL;
+       List       *namelist;
+       List       *l;
 
        /* Convert to C string (handles possible detoasting). */
        /* Note we rely on being able to modify rawname below. */
        rawname = DatumGetCString(DirectFunctionCall1(textout,
                                                                                                  PointerGetDatum(textval)));
-       nextp = rawname;
 
+       if (!SplitIdentifierString(rawname, '.', &namelist))
+               elog(ERROR, "%s: invalid name syntax", caller);
+
+       if (namelist == NIL)
+               elog(ERROR, "%s: invalid name syntax", caller);
+
+       foreach(l, namelist)
+       {
+               char   *curname = (char *) lfirst(l);
+
+               result = lappend(result, makeString(pstrdup(curname)));
+       }
+
+       pfree(rawname);
+       freeList(namelist);
+
+       return result;
+}
+
+/*
+ * SplitIdentifierString --- parse a string containing identifiers
+ *
+ * This is the guts of textToQualifiedNameList, and is exported for use in
+ * other situations such as parsing GUC variables.  In the GUC case, it's
+ * important to avoid memory leaks, so the API is designed to minimize the
+ * amount of stuff that needs to be allocated and freed.
+ *
+ * Inputs:
+ *     rawstring: the input string; must be overwritable!  On return, it's
+ *                        been modified to contain the separated identifiers.
+ *     separator: the separator punctuation expected between identifiers
+ *                        (typically '.' or ',').  Whitespace may also appear around
+ *                        identifiers.
+ * Outputs:
+ *     namelist: filled with a palloc'd list of pointers to identifiers within
+ *                       rawstring.  Caller should freeList() this even on error return.
+ *
+ * Returns TRUE if okay, FALSE if there is a syntax error in the string.
+ *
+ * Note that an empty string is considered okay here, though not in
+ * textToQualifiedNameList.
+ */
+bool
+SplitIdentifierString(char *rawstring, char separator,
+                                         List **namelist)
+{
+       char       *nextp = rawstring;
+       bool            done = false;
+
+       *namelist = NIL;
+
+       while (isspace((unsigned char) *nextp))
+               nextp++;                                /* skip leading whitespace */
+
+       if (*nextp == '\0')
+               return true;                    /* allow empty string */
+
+       /* At the top of the loop, we are at start of a new identifier. */
        do
        {
                char       *curname;
                char       *endp;
-               char       *cp;
                int                     curlen;
 
                if (*nextp == '\"')
@@ -1078,56 +1132,54 @@ textToQualifiedNameList(text *textval, const char *caller)
                        {
                                endp = strchr(nextp + 1, '\"');
                                if (endp == NULL)
-                                       elog(ERROR, "%s: invalid quoted name: mismatched quotes",
-                                                caller);
+                                       return false; /* mismatched quotes */
                                if (endp[1] != '\"')
                                        break;          /* found end of quoted name */
                                /* Collapse adjacent quotes into one quote, and look again */
                                memmove(endp, endp+1, strlen(endp));
                                nextp = endp;
                        }
-                       *endp = '\0';
+                       /* endp now points at the terminating quote */
                        nextp = endp + 1;
-                       if (*nextp)
-                       {
-                               if (*nextp != '.')
-                                       elog(ERROR, "%s: invalid name syntax",
-                                                caller);
-                               nextp++;
-                               if (*nextp == '\0')
-                                       elog(ERROR, "%s: invalid name syntax",
-                                                caller);
-                       }
                }
                else
                {
-                       /* Unquoted name --- extends to next dot */
-                       if (*nextp == '\0')                             /* empty name not okay here */
-                               elog(ERROR, "%s: invalid name syntax",
-                                        caller);
+                       /* Unquoted name --- extends to separator or whitespace */
                        curname = nextp;
-                       endp = strchr(nextp, '.');
-                       if (endp)
+                       while (*nextp && *nextp != separator &&
+                                  !isspace((unsigned char) *nextp))
                        {
-                               *endp = '\0';
-                               nextp = endp + 1;
-                               if (*nextp == '\0')
-                                       elog(ERROR, "%s: invalid name syntax",
-                                                caller);
-                       }
-                       else
-                               nextp = nextp + strlen(nextp);
-                       /*
-                        * It's important that this match the identifier downcasing code
-                        * used by backend/parser/scan.l.
-                        */
-                       for (cp = curname; *cp; cp++)
-                       {
-                               if (isupper((unsigned char) *cp))
-                                       *cp = tolower((unsigned char) *cp);
+                               /*
+                                * It's important that this match the identifier downcasing
+                                * code used by backend/parser/scan.l.
+                                */
+                               if (isupper((unsigned char) *nextp))
+                                       *nextp = tolower((unsigned char) *nextp);
+                               nextp++;
                        }
+                       endp = nextp;
+                       if (curname == nextp)
+                               return false;   /* empty unquoted name not allowed */
                }
 
+               while (isspace((unsigned char) *nextp))
+                       nextp++;                        /* skip trailing whitespace */
+
+               if (*nextp == separator)
+               {
+                       nextp++;
+                       while (isspace((unsigned char) *nextp))
+                               nextp++;                /* skip leading whitespace for next */
+                       /* we expect another name, so done remains false */
+               }
+               else if (*nextp == '\0')
+                       done = true;
+               else
+                       return false;           /* invalid syntax */
+
+               /* Now safe to overwrite separator with a null */
+               *endp = '\0';
+
                /* Truncate name if it's overlength; again, should match scan.l */
                curlen = strlen(curname);
                if (curlen >= NAMEDATALEN)
@@ -1143,15 +1195,12 @@ textToQualifiedNameList(text *textval, const char *caller)
                /*
                 * Finished isolating current name --- add it to list
                 */
-               result = lappend(result, makeString(pstrdup(curname)));
-               /*
-                * Loop back if we found a dot
-                */
-       } while (*nextp);
+               *namelist = lappend(*namelist, curname);
 
-       pfree(rawname);
+               /* Loop back if we didn't reach end of string */
+       } while (!done);
 
-       return result;
+       return true;
 }
 
 
index 9cd5b19..0d36d70 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.101 2002/03/31 06:26:32 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.102 2002/04/01 03:34:26 tgl Exp $
  *
  *
  *-------------------------------------------------------------------------
 #include "catalog/catalog.h"
 #include "access/heapam.h"
 #include "catalog/catname.h"
+#include "catalog/namespace.h"
 #include "catalog/pg_database.h"
 #include "catalog/pg_shadow.h"
 #include "commands/trigger.h"
-#include "commands/variable.h" /* for set_default_client_encoding() */
+#include "commands/variable.h"
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
 #include "storage/backendid.h"
@@ -372,11 +373,6 @@ InitPostgres(const char *dbname, const char *username)
        if (!bootstrap)
                ReverifyMyDatabase(dbname);
 
-#ifdef MULTIBYTE
-       /* set default client encoding --- uses info from ReverifyMyDatabase */
-       set_default_client_encoding();
-#endif
-
        /*
         * Final phase of relation cache startup: write a new cache file
         * if necessary.  This is done after ReverifyMyDatabase to avoid
@@ -385,6 +381,19 @@ InitPostgres(const char *dbname, const char *username)
        RelationCacheInitializePhase3();
 
        /*
+        * Initialize various default states that can't be set up until
+        * we've selected the active user and done ReverifyMyDatabase.
+        */
+
+       /* set default namespace search path */
+       InitializeSearchPath();
+
+#ifdef MULTIBYTE
+       /* set default client encoding --- uses info from ReverifyMyDatabase */
+       set_default_client_encoding();
+#endif
+
+       /*
         * Set up process-exit callback to do pre-shutdown cleanup.  This should
         * be last because we want shmem_exit to call this routine before the exit
         * callbacks that are registered by buffer manager, lock manager, etc.
index d1f6d2b..9c35f09 100644 (file)
@@ -4,7 +4,7 @@
  * Support for grand unified configuration scheme, including SET
  * command, configuration file, and command line options.
  *
- * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.63 2002/03/24 04:31:08 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.64 2002/04/01 03:34:26 tgl Exp $
  *
  * Copyright 2000 by PostgreSQL Global Development Group
  * Written by Peter Eisentraut <peter_e@gmx.net>.
@@ -21,6 +21,7 @@
 #include "utils/guc.h"
 
 #include "access/xlog.h"
+#include "catalog/namespace.h"
 #include "commands/async.h"
 #include "fmgr.h"
 #include "libpq/auth.h"
@@ -575,6 +576,11 @@ static struct config_string
        },
 
        {
+               "search_path", PGC_USERSET, PGC_S_DEFAULT, &namespace_search_path,
+               "$user,public", check_search_path, assign_search_path
+       },
+
+       {
                "krb_server_keyfile", PGC_POSTMASTER, PGC_S_DEFAULT, &pg_krb_server_keyfile,
                PG_KRB_SRVTAB, NULL, NULL
        },
@@ -899,7 +905,7 @@ set_config_option(const char *name, const char *value,
        int                     elevel;
        bool            makeDefault;
 
-       if (context == PGC_SIGHUP)
+       if (context == PGC_SIGHUP || source == PGC_S_DEFAULT)
                elevel = DEBUG1;
        else if (guc_session_init)
                elevel = INFO;
@@ -1414,7 +1420,7 @@ ProcessGUCArray(ArrayType *array, GucSource source)
                ParseLongOption(s, &name, &value);
                if (!value)
                {
-                       elog(WARNING, "cannot to parse setting \"%s\"", name);
+                       elog(WARNING, "cannot parse setting \"%s\"", name);
                        continue;
                }
 
index a40b6ce..01f5568 100644 (file)
 #      Misc
 #
 #dynamic_library_path = '$libdir'
+#search_path = '$user,public'
 #australian_timezones = false
 #authentication_timeout = 60   # min 1, max 600
 #deadlock_timeout = 1000
index 003ec9f..f25a45e 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright 2000 by PostgreSQL Global Development Group
  *
- * $Header: /cvsroot/pgsql/src/bin/psql/tab-complete.c,v 1.46 2002/03/24 04:31:08 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/bin/psql/tab-complete.c,v 1.47 2002/04/01 03:34:27 tgl Exp $
  */
 
 /*----------------------------------------------------------------------
@@ -267,6 +267,7 @@ psql_completion(char *text, int start, int end)
                "geqo_selection_bias",
 
                "default_transaction_isolation",
+               "search_path",
 
                NULL
        };
index 796a053..0cfc165 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: xact.h,v 1.41 2001/11/05 17:46:31 momjian Exp $
+ * $Id: xact.h,v 1.42 2002/04/01 03:34:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -97,9 +97,7 @@ typedef struct xl_xact_abort
  *             extern definitions
  * ----------------
  */
-extern int     TransactionFlushEnabled(void);
-extern void SetTransactionFlushEnabled(bool state);
-
+extern bool IsTransactionState(void);
 extern bool IsAbortedTransactionBlockState(void);
 extern TransactionId GetCurrentTransactionId(void);
 extern CommandId GetCurrentCommandId(void);
index aed33a1..a8a64bd 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: namespace.h,v 1.4 2002/03/31 06:26:32 tgl Exp $
+ * $Id: namespace.h,v 1.5 2002/04/01 03:34:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -31,4 +31,11 @@ extern RangeVar *makeRangeVarFromNameList(List *names);
 
 extern bool isTempNamespace(Oid namespaceId);
 
+/* stuff for search_path GUC variable */
+extern char *namespace_search_path;
+
+extern bool check_search_path(const char *proposed);
+extern void assign_search_path(const char *newval);
+extern void InitializeSearchPath(void);
+
 #endif   /* NAMESPACE_H */
index fceee09..d058206 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_namespace.h,v 1.3 2002/03/31 06:26:32 tgl Exp $
+ * $Id: pg_namespace.h,v 1.4 2002/04/01 03:34:27 tgl Exp $
  *
  * NOTES
  *       the genbki.sh script reads this file and generates .bki
@@ -72,7 +72,7 @@ DESCR("System catalog namespace");
 DATA(insert OID = 99 ( "pg_toast" PGUID "{=}" ));
 DESCR("Reserved namespace for TOAST tables");
 #define PG_TOAST_NAMESPACE 99
-DATA(insert OID = 2071 ( "pg_public" PGUID "{=rw}" ));
+DATA(insert OID = 2071 ( "public" PGUID "{=rw}" ));
 DESCR("Standard public namespace");
 #define PG_PUBLIC_NAMESPACE 2071
 
index 7bd111c..342aa4e 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: builtins.h,v 1.174 2002/03/30 01:02:42 tgl Exp $
+ * $Id: builtins.h,v 1.175 2002/04/01 03:34:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -411,6 +411,8 @@ extern Datum name_text(PG_FUNCTION_ARGS);
 extern Datum text_name(PG_FUNCTION_ARGS);
 extern int     varstr_cmp(char *arg1, int len1, char *arg2, int len2);
 extern List *textToQualifiedNameList(text *textval, const char *caller);
+extern bool SplitIdentifierString(char *rawstring, char separator,
+                                                                 List **namelist);
 
 extern Datum byteain(PG_FUNCTION_ARGS);
 extern Datum byteaout(PG_FUNCTION_ARGS);