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 9c118d2be250e0ff9db2d80d6ed14a0ec36b9c14..43b6931fe18f27ad2861ca02e9d4199e0fed661b 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>
 
@@ -1189,6 +1189,69 @@ dynamic_library_path = '/usr/local/lib/postgresql:/home/my_project/lib:$libdir'
       </listitem>
      </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>
index 046f3d52aad9cd85d664a21c1dc10ab6143a3c82..ca66b0afafab8332918ac2f086d9f17e79cf1dfa 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 a1be64bd80e96f96572aad34b7199dd2ffffb212..fab1912b1b537f370378871441159836779bed60 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 4ebddde891bb9e920df30bcabf6191f838d6b278..64cc3d60ca7517b7fd4c19be2bcb2eec19002a09 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 ce3e8dc254dbab978ff36123768027f0c51ce937..5afaf398879eec0b382710230407b4993b07087c 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 9cd5b194d922535007e1e8319db2921a1b9fe3f0..0d36d70bea8f9bd2db28ae1716a5a6270e02358e 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
@@ -384,6 +380,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
index d1f6d2bdb00a63f8738fc5cc52f4c2d8003dc789..9c35f0949aa92c74199389b88ca88fc783314059 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"
@@ -574,6 +575,11 @@ static struct config_string
        "$libdir", NULL, NULL
    },
 
+   {
+       "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 a40b6ce7fac0e957aa180736119afc0c9b26a64a..01f55682b8800646224d2e5eefe0c345535ce62d 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 003ec9fe33667493b8df99751fb8b96a052bd201..f25a45ef622585a0ee6321ca0765e5b92b76b04f 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 796a05383607e8c0bb8926b1fa5cb300ec9d5966..0cfc1652f22ea032adcb95514a21415b9ed52abf 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 aed33a10b31d8d4fdcb1040e3f742a7f081686d2..a8a64bd7db1151f4ce6365e200cdb58422b0f271 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 fceee09fcb774689716524dd44cfc9f3b08c6bdc..d058206daec59dbae76f01b005e5f5c3058cc826 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 7bd111cd544ec7006aac37e8e1e74aad6735f8c4..342aa4e99f6375089cd398b646aa07a9d04c6a31 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);