3737 *
3838 *
3939 * IDENTIFICATION
40- * $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.47 2007/06/03 17:06:59 tgl Exp $
40+ * $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.48 2007/06/07 19:19:56 tgl Exp $
4141 *
4242 *-------------------------------------------------------------------------
4343 */
6363#include "utils/fmgroids.h"
6464#include "utils/guc.h"
6565#include "utils/lsyscache.h"
66+ #include "utils/memutils.h"
6667
6768
6869/* GUC variables */
@@ -72,7 +73,6 @@ char *temp_tablespaces = NULL;
7273
7374static bool remove_tablespace_directories (Oid tablespaceoid ,bool redo );
7475static void set_short_version (const char * path );
75- static Oid getTempTablespace (void );
7676
7777
7878/*
@@ -921,9 +921,12 @@ GetDefaultTablespace(bool forTemp)
921921{
922922Oid result ;
923923
924- /* The temp-table case is handledby getTempTablespace() */
924+ /* The temp-table case is handledelsewhere */
925925if (forTemp )
926- return getTempTablespace ();
926+ {
927+ PrepareTempTablespaces ();
928+ return GetNextTempTableSpace ();
929+ }
927930
928931/* Fast path for default_tablespace == "" */
929932if (default_tablespace == NULL || default_tablespace [0 ]== '\0' )
@@ -958,7 +961,6 @@ assign_temp_tablespaces(const char *newval, bool doit, GucSource source)
958961{
959962char * rawname ;
960963List * namelist ;
961- ListCell * l ;
962964
963965/* Need a modifiable copy of string */
964966rawname = pstrdup (newval );
@@ -975,24 +977,79 @@ assign_temp_tablespaces(const char *newval, bool doit, GucSource source)
975977/*
976978 * If we aren't inside a transaction, we cannot do database access so
977979 * cannot verify the individual names.Must accept the list on faith.
980+ * Fortunately, there's then also no need to pass the data to fd.c.
978981 */
979- if (source >= PGC_S_INTERACTIVE && IsTransactionState ())
982+ if (IsTransactionState ())
980983{
984+ /*
985+ * If we error out below, or if we are called multiple times in one
986+ * transaction, we'll leak a bit of TopTransactionContext memory.
987+ * Doesn't seem worth worrying about.
988+ */
989+ Oid * tblSpcs ;
990+ int numSpcs ;
991+ ListCell * l ;
992+
993+ tblSpcs = (Oid * )MemoryContextAlloc (TopTransactionContext ,
994+ list_length (namelist )* sizeof (Oid ));
995+ numSpcs = 0 ;
981996foreach (l ,namelist )
982997{
983998char * curname = (char * )lfirst (l );
999+ Oid curoid ;
1000+ AclResult aclresult ;
9841001
9851002/* Allow an empty string (signifying database default) */
9861003if (curname [0 ]== '\0' )
1004+ {
1005+ tblSpcs [numSpcs ++ ]= InvalidOid ;
9871006continue ;
1007+ }
9881008
9891009/* Else verify that name is a valid tablespace name */
990- if (get_tablespace_oid (curname )== InvalidOid )
991- ereport (ERROR ,
992- (errcode (ERRCODE_UNDEFINED_OBJECT ),
993- errmsg ("tablespace \"%s\" does not exist" ,
994- curname )));
1010+ curoid = get_tablespace_oid (curname );
1011+ if (curoid == InvalidOid )
1012+ {
1013+ /*
1014+ * In an interactive SET command, we ereport for bad info.
1015+ * Otherwise, silently ignore any bad list elements.
1016+ */
1017+ if (source >=PGC_S_INTERACTIVE )
1018+ ereport (ERROR ,
1019+ (errcode (ERRCODE_UNDEFINED_OBJECT ),
1020+ errmsg ("tablespace \"%s\" does not exist" ,
1021+ curname )));
1022+ continue ;
1023+ }
1024+
1025+ /*
1026+ * Allow explicit specification of database's default tablespace
1027+ * in temp_tablespaces without triggering permissions checks.
1028+ */
1029+ if (curoid == MyDatabaseTableSpace )
1030+ {
1031+ tblSpcs [numSpcs ++ ]= InvalidOid ;
1032+ continue ;
1033+ }
1034+
1035+ /* Check permissions similarly */
1036+ aclresult = pg_tablespace_aclcheck (curoid ,GetUserId (),
1037+ ACL_CREATE );
1038+ if (aclresult != ACLCHECK_OK )
1039+ {
1040+ if (source >=PGC_S_INTERACTIVE )
1041+ aclcheck_error (aclresult ,ACL_KIND_TABLESPACE ,curname );
1042+ continue ;
1043+ }
1044+
1045+ tblSpcs [numSpcs ++ ]= curoid ;
9951046}
1047+
1048+ /* If actively "doing it", give the new list to fd.c */
1049+ if (doit )
1050+ SetTempTablespaces (tblSpcs ,numSpcs );
1051+ else
1052+ pfree (tblSpcs );
9961053}
9971054
9981055pfree (rawname );
@@ -1002,69 +1059,34 @@ assign_temp_tablespaces(const char *newval, bool doit, GucSource source)
10021059}
10031060
10041061/*
1005- * GetTempTablespace -- get the OID of the next temp tablespace to use
1006- *
1007- * May return InvalidOid to indicate "use the database's default tablespace".
1062+ * PrepareTempTablespaces -- prepare to use temp tablespaces
10081063 *
1009- * This is different from GetDefaultTablespace(true) in just two ways:
1010- * 1. We check privileges here instead of leaving it to the caller.
1011- * 2. It's safe to call this outside a transaction (we just return InvalidOid).
1012- * The transaction state check is used so that this can be called from
1013- * low-level places that might conceivably run outside a transaction.
1064+ * If we have not already done so in the current transaction, parse the
1065+ * temp_tablespaces GUC variable and tell fd.c which tablespace(s) to use
1066+ * for temp files.
10141067 */
1015- Oid
1016- GetTempTablespace (void )
1017- {
1018- Oid result ;
1019-
1020- /* Can't do catalog access unless within a transaction */
1021- if (!IsTransactionState ())
1022- return InvalidOid ;
1023-
1024- /* OK, select a temp tablespace */
1025- result = getTempTablespace ();
1026-
1027- /* Check permissions except when using database's default */
1028- if (OidIsValid (result ))
1029- {
1030- AclResult aclresult ;
1031-
1032- aclresult = pg_tablespace_aclcheck (result ,GetUserId (),
1033- ACL_CREATE );
1034- if (aclresult != ACLCHECK_OK )
1035- aclcheck_error (aclresult ,ACL_KIND_TABLESPACE ,
1036- get_tablespace_name (result ));
1037- }
1038-
1039- return result ;
1040- }
1041-
1042- /*
1043- * getTempTablespace -- get the OID of the next temp tablespace to use
1044- *
1045- * This has exactly the API defined for GetDefaultTablespace(true),
1046- * in particular that caller is responsible for permissions checks.
1047- *
1048- * This exists to hide (and possibly optimize the use of) the
1049- * temp_tablespaces GUC variable.
1050- */
1051- static Oid
1052- getTempTablespace (void )
1068+ void
1069+ PrepareTempTablespaces (void )
10531070{
1054- Oid result ;
10551071char * rawname ;
10561072List * namelist ;
1057- int nnames ;
1058- char * curname ;
1073+ Oid * tblSpcs ;
1074+ int numSpcs ;
1075+ ListCell * l ;
10591076
1060- if (temp_tablespaces == NULL )
1061- return InvalidOid ;
1077+ /* No work if already done in current transaction */
1078+ if (TempTablespacesAreSet ())
1079+ return ;
10621080
10631081/*
1064- * We re-parse the string on each call; this is a bit expensive, but
1065- * we don't expect this function will be called many times per query,
1066- * so it's probably not worth being tenser.
1082+ * Can't do catalog access unless within a transaction. This is just
1083+ * a safety check in case this function is called by low-level code that
1084+ * could conceivably execute outside a transaction. Note that in such
1085+ * a scenario, fd.c will fall back to using the current database's default
1086+ * tablespace, which should always be OK.
10671087 */
1088+ if (!IsTransactionState ())
1089+ return ;
10681090
10691091/* Need a modifiable copy of string */
10701092rawname = pstrdup (temp_tablespaces );
@@ -1073,51 +1095,60 @@ getTempTablespace(void)
10731095if (!SplitIdentifierString (rawname ,',' ,& namelist ))
10741096{
10751097/* syntax error in name list */
1098+ SetTempTablespaces (NULL ,0 );
10761099pfree (rawname );
10771100list_free (namelist );
1078- return InvalidOid ;
1101+ return ;
10791102}
1080- nnames = list_length (namelist );
10811103
1082- /* Fast path for temp_tablespaces == "" */
1083- if (nnames == 0 )
1104+ /* Store tablespace OIDs in an array in TopTransactionContext */
1105+ tblSpcs = (Oid * )MemoryContextAlloc (TopTransactionContext ,
1106+ list_length (namelist )* sizeof (Oid ));
1107+ numSpcs = 0 ;
1108+ foreach (l ,namelist )
10841109{
1085- pfree (rawname );
1086- list_free (namelist );
1087- return InvalidOid ;
1088- }
1110+ char * curname = (char * )lfirst (l );
1111+ Oid curoid ;
1112+ AclResult aclresult ;
10891113
1090- /* Select a random element */
1091- if (nnames == 1 )/* no need for a random() call */
1092- curname = (char * )linitial (namelist );
1093- else
1094- curname = (char * )list_nth (namelist ,random () %nnames );
1114+ /* Allow an empty string (signifying database default) */
1115+ if (curname [0 ]== '\0' )
1116+ {
1117+ tblSpcs [numSpcs ++ ]= InvalidOid ;
1118+ continue ;
1119+ }
10951120
1096- /*
1097- * Empty string means "database's default", else look up the tablespace.
1098- *
1099- * It is tempting to cache this lookup for more speed, but then we would
1100- * fail to detect the case where the tablespace was dropped since the GUC
1101- * variable was set. Note also that we don't complain if the value fails
1102- * to refer to an existing tablespace; we just silently return InvalidOid,
1103- * causing the new object to be created in the database's tablespace.
1104- */
1105- if (curname [0 ]== '\0' )
1106- result = InvalidOid ;
1107- else
1108- result = get_tablespace_oid (curname );
1121+ /* Else verify that name is a valid tablespace name */
1122+ curoid = get_tablespace_oid (curname );
1123+ if (curoid == InvalidOid )
1124+ {
1125+ /* Silently ignore any bad list elements */
1126+ continue ;
1127+ }
11091128
1110- /*
1111- * Allow explicit specification of database's default tablespace in
1112- * temp_tablespaces without triggering permissions checks.
1113- */
1114- if (result == MyDatabaseTableSpace )
1115- result = InvalidOid ;
1129+ /*
1130+ * Allow explicit specification of database's default tablespace
1131+ * in temp_tablespaces without triggering permissions checks.
1132+ */
1133+ if (curoid == MyDatabaseTableSpace )
1134+ {
1135+ tblSpcs [numSpcs ++ ]= InvalidOid ;
1136+ continue ;
1137+ }
1138+
1139+ /* Check permissions similarly */
1140+ aclresult = pg_tablespace_aclcheck (curoid ,GetUserId (),
1141+ ACL_CREATE );
1142+ if (aclresult != ACLCHECK_OK )
1143+ continue ;
1144+
1145+ tblSpcs [numSpcs ++ ]= curoid ;
1146+ }
1147+
1148+ SetTempTablespaces (tblSpcs ,numSpcs );
11161149
11171150pfree (rawname );
11181151list_free (namelist );
1119-
1120- return result ;
11211152}
11221153
11231154