37
37
*
38
38
*
39
39
* 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 $
41
41
*
42
42
*-------------------------------------------------------------------------
43
43
*/
63
63
#include "utils/fmgroids.h"
64
64
#include "utils/guc.h"
65
65
#include "utils/lsyscache.h"
66
+ #include "utils/memutils.h"
66
67
67
68
68
69
/* GUC variables */
@@ -72,7 +73,6 @@ char *temp_tablespaces = NULL;
72
73
73
74
static bool remove_tablespace_directories (Oid tablespaceoid , bool redo );
74
75
static void set_short_version (const char * path );
75
- static Oid getTempTablespace (void );
76
76
77
77
78
78
/*
@@ -921,9 +921,12 @@ GetDefaultTablespace(bool forTemp)
921
921
{
922
922
Oid result ;
923
923
924
- /* The temp-table case is handled by getTempTablespace() */
924
+ /* The temp-table case is handled elsewhere */
925
925
if (forTemp )
926
- return getTempTablespace ();
926
+ {
927
+ PrepareTempTablespaces ();
928
+ return GetNextTempTableSpace ();
929
+ }
927
930
928
931
/* Fast path for default_tablespace == "" */
929
932
if (default_tablespace == NULL || default_tablespace [0 ] == '\0' )
@@ -958,7 +961,6 @@ assign_temp_tablespaces(const char *newval, bool doit, GucSource source)
958
961
{
959
962
char * rawname ;
960
963
List * namelist ;
961
- ListCell * l ;
962
964
963
965
/* Need a modifiable copy of string */
964
966
rawname = pstrdup (newval );
@@ -975,24 +977,79 @@ assign_temp_tablespaces(const char *newval, bool doit, GucSource source)
975
977
/*
976
978
* If we aren't inside a transaction, we cannot do database access so
977
979
* 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.
978
981
*/
979
- if (source >= PGC_S_INTERACTIVE && IsTransactionState ())
982
+ if (IsTransactionState ())
980
983
{
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 ;
981
996
foreach (l , namelist )
982
997
{
983
998
char * curname = (char * ) lfirst (l );
999
+ Oid curoid ;
1000
+ AclResult aclresult ;
984
1001
985
1002
/* Allow an empty string (signifying database default) */
986
1003
if (curname [0 ] == '\0' )
1004
+ {
1005
+ tblSpcs [numSpcs ++ ] = InvalidOid ;
987
1006
continue ;
1007
+ }
988
1008
989
1009
/* 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 ;
995
1046
}
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 );
996
1053
}
997
1054
998
1055
pfree (rawname );
@@ -1002,69 +1059,34 @@ assign_temp_tablespaces(const char *newval, bool doit, GucSource source)
1002
1059
}
1003
1060
1004
1061
/*
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
1008
1063
*
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.
1014
1067
*/
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 )
1053
1070
{
1054
- Oid result ;
1055
1071
char * rawname ;
1056
1072
List * namelist ;
1057
- int nnames ;
1058
- char * curname ;
1073
+ Oid * tblSpcs ;
1074
+ int numSpcs ;
1075
+ ListCell * l ;
1059
1076
1060
- if (temp_tablespaces == NULL )
1061
- return InvalidOid ;
1077
+ /* No work if already done in current transaction */
1078
+ if (TempTablespacesAreSet ())
1079
+ return ;
1062
1080
1063
1081
/*
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.
1067
1087
*/
1088
+ if (!IsTransactionState ())
1089
+ return ;
1068
1090
1069
1091
/* Need a modifiable copy of string */
1070
1092
rawname = pstrdup (temp_tablespaces );
@@ -1073,51 +1095,60 @@ getTempTablespace(void)
1073
1095
if (!SplitIdentifierString (rawname , ',' , & namelist ))
1074
1096
{
1075
1097
/* syntax error in name list */
1098
+ SetTempTablespaces (NULL , 0 );
1076
1099
pfree (rawname );
1077
1100
list_free (namelist );
1078
- return InvalidOid ;
1101
+ return ;
1079
1102
}
1080
- nnames = list_length (namelist );
1081
1103
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 )
1084
1109
{
1085
- pfree (rawname );
1086
- list_free (namelist );
1087
- return InvalidOid ;
1088
- }
1110
+ char * curname = (char * ) lfirst (l );
1111
+ Oid curoid ;
1112
+ AclResult aclresult ;
1089
1113
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
+ }
1095
1120
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
+ }
1109
1128
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 );
1116
1149
1117
1150
pfree (rawname );
1118
1151
list_free (namelist );
1119
-
1120
- return result ;
1121
1152
}
1122
1153
1123
1154
0 commit comments