Add GUC temp_tablespaces to provide a default location for temporary
authorBruce Momjian <bruce@momjian.us>
Thu, 25 Jan 2007 04:35:11 +0000 (04:35 +0000)
committerBruce Momjian <bruce@momjian.us>
Thu, 25 Jan 2007 04:35:11 +0000 (04:35 +0000)
objects.

Jaime Casanova

doc/src/sgml/config.sgml
src/backend/commands/indexcmds.c
src/backend/commands/tablecmds.c
src/backend/commands/tablespace.c
src/backend/executor/execMain.c
src/backend/storage/file/fd.c
src/backend/utils/misc/guc.c
src/backend/utils/misc/postgresql.conf.sample
src/include/commands/tablespace.h
src/include/utils/guc.h

index 7088c5e9d8ff41a0d0b6ee912d1fd9259402dcd6..94fc8fd79aa45388f73215f3466dd0f4e894d1f3 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.104 2007/01/20 21:30:26 momjian Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.105 2007/01/25 04:35:10 momjian Exp $ -->
 
 <chapter Id="runtime-config">
   <title>Server Configuration</title>
@@ -3398,6 +3398,35 @@ SELECT * FROM parent WHERE key = 2400;
       </listitem>
      </varlistentry>
 
+     <varlistentry id="guc-temp-tablespaces" xreflabel="temp_tablespaces">
+      <term><varname>temp_tablespaces</varname> (<type>string</type>)</term>
+      <indexterm>
+       <primary><varname>temp_tablespaces</> configuration parameter</primary>
+      </indexterm>
+      <indexterm><primary>tablespace</><secondary>temp</></>
+      <listitem>
+       <para>
+        This variable specifies tablespaces in which to create temp
+        objects (temp tables and indexes on temp tables) when a 
+        <command>CREATE</> command does not explicitly specify a tablespace 
+        and temp files when necessary (eg. for sorting operations).
+       </para>
+
+       <para>
+        The value is either a list of names of tablespaces, or an empty 
+        string to specify using the default tablespace of the current database.
+        If the value does not match the name of any existing tablespace,
+        <productname>PostgreSQL</> will automatically use the default
+        tablespace of the current database.
+       </para>
+
+       <para>
+        For more information on tablespaces,
+        see <xref linkend="manage-ag-tablespaces">.
+       </para>
+      </listitem>
+     </varlistentry>
+
      <varlistentry id="guc-check-function-bodies" xreflabel="check_function_bodies">
       <term><varname>check_function_bodies</varname> (<type>boolean</type>)</term>
       <indexterm>
index 2d51dfb11febd2e88a3d8d87943c92d87b65f889..a71831271101e801e7dfc0ef76a26c147e453c91 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.153 2007/01/20 23:13:01 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.154 2007/01/25 04:35:10 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -209,7 +209,13 @@ DefineIndex(RangeVar *heapRelation,
    }
    else
    {
-       tablespaceId = GetDefaultTablespace();
+       /*
+        * if the target table is temporary then use a temp_tablespace
+        */
+       if (!rel->rd_istemp)
+           tablespaceId = GetDefaultTablespace();
+       else
+           tablespaceId = GetTempTablespace();
        /* note InvalidOid is OK in this case */
    }
 
index ced08506bceb794432b3aac59e0528cccff23912..a11cde3647ef8880d2a05545b7cb45bc19f5ab30 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.211 2007/01/25 04:17:45 momjian Exp $
+ *   $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.212 2007/01/25 04:35:10 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -334,6 +334,10 @@ DefineRelation(CreateStmt *stmt, char relkind)
                     errmsg("tablespace \"%s\" does not exist",
                            stmt->tablespacename)));
    }
+   else if (stmt->relation->istemp)
+   {
+       tablespaceId = GetTempTablespace();
+   }
    else
    {
        tablespaceId = GetDefaultTablespace();
index cd86aef4019a401753727a33aecebc895d829910..d2cb245f150ad647e4bab5580b37b9bef42023ac 100644 (file)
@@ -37,7 +37,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.40 2007/01/05 22:19:26 momjian Exp $
+ *   $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.41 2007/01/25 04:35:10 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "utils/lsyscache.h"
 
 
-/* GUC variable */
+/* GUC variables */
 char      *default_tablespace = NULL;
+char       *temp_tablespaces = NULL;
 
+int       next_temp_tablespace;
+int       num_temp_tablespaces;
 
 static bool remove_tablespace_directories(Oid tablespaceoid, bool redo);
 static void set_short_version(const char *path);
@@ -930,6 +933,142 @@ GetDefaultTablespace(void)
    return result;
 }
 
+/*
+ * Routines for handling the GUC variable 'temp_tablespaces'.
+ */
+
+/* assign_hook: validate new temp_tablespaces, do extra actions as needed */
+const char *
+assign_temp_tablespaces(const char *newval, bool doit, GucSource source)
+{
+   char       *rawname;
+   List       *namelist;
+   ListCell   *l;
+
+   /* Need a modifiable copy of string */
+   rawname = pstrdup(newval);
+
+   /* Parse string into list of identifiers */
+   if (!SplitIdentifierString(rawname, ',', &namelist))
+   {
+       /* syntax error in name list */
+       pfree(rawname);
+       list_free(namelist);
+       return NULL;
+   }
+
+   num_temp_tablespaces = 0;
+   foreach(l, namelist)
+   {
+       char       *curname = (char *) lfirst(l);
+
+       /*
+        * If we aren't inside a transaction, we cannot do database access so
+        * cannot verify the individual names.  Must accept the list on faith.
+        */
+       if (source >= PGC_S_INTERACTIVE && IsTransactionState())
+       {
+           /*
+            * Verify that all the names are valid tablspace names 
+            * We do not check for USAGE rights should we?
+            */
+           if (get_tablespace_oid(curname) == InvalidOid)
+               ereport((source == PGC_S_TEST) ? NOTICE : ERROR,
+                       (errcode(ERRCODE_UNDEFINED_OBJECT),
+                       errmsg("tablespace \"%s\" does not exist", curname)));
+       }
+       num_temp_tablespaces++;
+   }
+
+   /*
+    * Select the first tablespace to use
+    */
+   next_temp_tablespace = MyProcPid % num_temp_tablespaces;
+
+   pfree(rawname);
+   list_free(namelist);
+   return newval;
+}
+
+/*
+ * GetTempTablespace -- get the OID of the tablespace for temporary objects
+ *
+ * May return InvalidOid to indicate "use the database's default tablespace"
+ *
+ * This exists to hide the temp_tablespace GUC variable.
+ */
+Oid
+GetTempTablespace(void)
+{
+   Oid         result;
+   char *curname = NULL;
+   char *rawname;
+   List *namelist;
+   ListCell *l;
+   int i = 0;
+   
+   if ( temp_tablespaces == NULL )
+       return InvalidOid;
+
+   /* Need a modifiable version of temp_tablespaces */
+   rawname = pstrdup(temp_tablespaces);
+
+   /* Parse string into list of identifiers */
+   if (!SplitIdentifierString(rawname, ',', &namelist))
+   {
+       /* syntax error in name list */
+       pfree(rawname);
+       list_free(namelist);
+       return InvalidOid;
+   }
+
+   /* 
+    * Iterate through the list of namespaces until the one we need 
+    * (next_temp_tablespace) 
+    */
+   foreach(l, namelist)
+   {
+       curname = (char *) lfirst(l);
+       if ( i == next_temp_tablespace )
+           break;
+       i++;
+   }
+
+
+   /* Prepare for the next time the function is called */
+   next_temp_tablespace++;
+   if (next_temp_tablespace == num_temp_tablespaces)
+       next_temp_tablespace = 0;
+
+   /* Fast path for temp_tablespaces == "" */
+   if ( curname == NULL || curname[0] == '\0') {
+       list_free(namelist);
+       pfree(rawname);
+       return InvalidOid;
+   }
+
+   /*
+    * It is tempting to cache this lookup for more speed, but then we would
+    * fail to detect the case where the tablespace was dropped since the GUC
+    * variable was set.  Note also that we don't complain if the value fails
+    * to refer to an existing tablespace; we just silently return InvalidOid,
+    * causing the new object to be created in the database's tablespace.
+    */
+   result = get_tablespace_oid(curname);
+
+   /* We don't free rawname before because curname points to a part of it */
+   pfree(rawname);
+
+   /*
+    * Allow explicit specification of database's default tablespace in
+    * default_tablespace without triggering permissions checks.
+    */
+   if (result == MyDatabaseTableSpace)
+       result = InvalidOid;
+   
+   list_free(namelist);
+   return result;
+}
 
 /*
  * get_tablespace_oid - given a tablespace name, look up the OID
index 06bc519dde3432484071471b0eb9568c05ae3c18..29916550af47dfdb0209ee0ea6bc67357702f296 100644 (file)
@@ -26,7 +26,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.284 2007/01/25 02:17:26 momjian Exp $
+ *   $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.285 2007/01/25 04:35:10 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2409,6 +2409,10 @@ OpenIntoRel(QueryDesc *queryDesc)
                     errmsg("tablespace \"%s\" does not exist",
                            parseTree->intoTableSpaceName)));
    }
+   else if (parseTree->into->istemp)
+   {
+       tablespaceId = GetTempTablespace();
+   }
    else
    {
        tablespaceId = GetDefaultTablespace();
index 53ba25115a275d76479fa7a845f995bf362db65b..486dd06bdc54952eac6ae8c3fab78c9bd59197c6 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/storage/file/fd.c,v 1.134 2007/01/09 22:03:51 momjian Exp $
+ *   $PostgreSQL: pgsql/src/backend/storage/file/fd.c,v 1.135 2007/01/25 04:35:10 momjian Exp $
  *
  * NOTES:
  *
@@ -46,6 +46,8 @@
 #include <unistd.h>
 #include <fcntl.h>
 
+#include "commands/tablespace.h"
+
 #include "miscadmin.h"
 #include "access/xact.h"
 #include "storage/fd.h"
@@ -76,6 +78,7 @@
  */
 #define FD_MINFREE             10
 
+#define OIDCHARS        10                      /* max chars printed by %u */
 
 /*
  * A number of platforms allow individual processes to open many more files
@@ -880,13 +883,51 @@ OpenTemporaryFile(bool interXact)
 {
    char        tempfilepath[MAXPGPATH];
    File        file;
+   Oid     oid;
+   char        *path;
+   int     pathlen;
 
    /*
-    * Generate a tempfile name that should be unique within the current
-    * database instance.
+    * Take a look what should be the path of the temporary file
     */
-   snprintf(tempfilepath, sizeof(tempfilepath),
-            "%s/%s%d.%ld", PG_TEMP_FILES_DIR, PG_TEMP_FILE_PREFIX,
+   oid = GetTempTablespace();
+   if (oid != InvalidOid)
+   {
+       /*
+        * As we got a valid tablespace, try to create the
+        * file there
+        */
+
+       pathlen = strlen("pg_tblspc/") + OIDCHARS + 1;
+       path = (char *) palloc(pathlen);
+       snprintf(path, pathlen, "pg_tblspc/%u", oid );
+
+       /*
+        * Generate a tempfile name that should be unique within the current
+        * database instance.
+        */
+       snprintf(tempfilepath, sizeof(tempfilepath),
+                "%s/%s%d.%ld", path, PG_TEMP_FILE_PREFIX,
+                MyProcPid, tempFileCounter++);
+       pfree(path);
+       file = PathNameOpenFile(tempfilepath,
+                           O_RDWR | O_CREAT | O_TRUNC | PG_BINARY,
+                           0600);
+   }
+
+   /*
+    * Create a normal temporary file if no tablespace returned or
+    * couldn't create the file in the tablespace "oid"
+    */
+   if (oid == InvalidOid || file <= 0) 
+   {
+       path = PG_TEMP_FILES_DIR;
+       /*
+        * Generate a tempfile name that should be unique within the current
+        * database instance.
+        */
+       snprintf(tempfilepath, sizeof(tempfilepath),
+                "%s/%s%d.%ld", path, PG_TEMP_FILE_PREFIX,
             MyProcPid, tempFileCounter++);
 
    /*
@@ -918,7 +959,8 @@ OpenTemporaryFile(bool interXact)
        if (file <= 0)
            elog(ERROR, "could not create temporary file \"%s\": %m",
                 tempfilepath);
-   }
+       }
+   }
 
    /* Mark it for deletion at close */
    VfdCache[file].fdstate |= FD_TEMPORARY;
@@ -1292,6 +1334,20 @@ TryAgain:
        errno = save_errno;
    }
 
+   /*
+    * TEMPORARY hack to log the Windows error code on fopen failures, in
+    * hopes of diagnosing some hard-to-reproduce problems.
+    */
+#ifdef WIN32
+   {
+       int         save_errno = errno;
+
+       elog(LOG, "Windows fopen(\"%s\",\"%s\") failed: code %lu, errno %d",
+            name, mode, GetLastError(), save_errno);
+       errno = save_errno;
+   }
+#endif
+
    return NULL;
 }
 
index 7962c992acc6c0ee5b96d2e7d3b28293fe8c5aa1..9f2cdc43f77130bd28be296cd6105e6f1b7b5c3d 100644 (file)
@@ -10,7 +10,7 @@
  * Written by Peter Eisentraut <peter_e@gmx.net>.
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.369 2007/01/19 16:58:46 petere Exp $
+ *   $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.370 2007/01/25 04:35:11 momjian Exp $
  *
  *--------------------------------------------------------------------
  */
@@ -99,6 +99,7 @@ extern bool Log_disconnections;
 extern int CommitDelay;
 extern int CommitSiblings;
 extern char *default_tablespace;
+extern char *temp_tablespaces;
 extern bool fullPageWrites;
 
 #ifdef TRACE_SORT
@@ -2291,6 +2292,16 @@ static struct config_string ConfigureNamesString[] =
        "base64", assign_xmlbinary, NULL
    },
 
+   {
+       {"temp_tablespaces", PGC_USERSET, PGC_S_FILE,
+           gettext_noop("Sets the tablespaces suitable for creating new objects and sort files."),
+           NULL,
+           GUC_LIST_INPUT | GUC_LIST_QUOTE 
+       },
+       &temp_tablespaces,
+       NULL, assign_temp_tablespaces, NULL
+   },
+
    /* End-of-list marker */
    {
        {NULL, 0, 0, NULL, NULL}, NULL, NULL, NULL, NULL
index 5e6ecacb74496dac71c0f3973d0054717d7c9ed7..3b9730c75bbf07ab3b0fad7ce330fbf713624c87 100644 (file)
 #search_path = '"$user",public'        # schema names
 #default_tablespace = ''       # a tablespace name, '' uses
                    # the default
+#temp_tablespaces = ''         # a list of tablespace names, 
+                   # '' uses default_tablespace
 #check_function_bodies = on
 #default_transaction_isolation = 'read committed'
 #default_transaction_read_only = off
index 7456eb2445e85d5b46b594b4371dc24c8c1912cd..6d3a333cf29cb4c9932416e05b5ba5795335e5b8 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/commands/tablespace.h,v 1.14 2007/01/05 22:19:54 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/commands/tablespace.h,v 1.15 2007/01/25 04:35:11 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -41,6 +41,7 @@ extern void AlterTableSpaceOwner(const char *name, Oid newOwnerId);
 extern void TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool isRedo);
 
 extern Oid GetDefaultTablespace(void);
+extern Oid GetTempTablespace(void);
 
 extern Oid get_tablespace_oid(const char *tablespacename);
 extern char *get_tablespace_name(Oid spc_oid);
index d324d66c22a84f1be388f8b60615047d9d11e5fe..51cc05a7a733a3b9e609a4f4de2ee36fb10aa714 100644 (file)
@@ -7,7 +7,7 @@
  * Copyright (c) 2000-2007, PostgreSQL Global Development Group
  * Written by Peter Eisentraut <peter_e@gmx.net>.
  *
- * $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.78 2007/01/09 21:31:17 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.79 2007/01/25 04:35:11 momjian Exp $
  *--------------------------------------------------------------------
  */
 #ifndef GUC_H
@@ -238,4 +238,8 @@ extern const char *assign_search_path(const char *newval,
 extern const char *assign_xlog_sync_method(const char *method,
                        bool doit, GucSource source);
 
+/* in commands/tablespace.c */
+extern const char *assign_temp_tablespaces(const char *newval,
+                         bool doit, GucSource source);
+
 #endif   /* GUC_H */