From 51dfdf276e1c8bdef1ea6710b6e7887650d2567a Mon Sep 17 00:00:00 2001 From: Thomas Munro Date: Wed, 4 Aug 2021 17:20:48 +1200 Subject: [PATCH v5 2/6] CREATE TABLESPACE ... NEW LOCATION. Allow tablespace directories to be created on demand. This allows the regression test suite to be run without knowing the path of, or having access to, the server's data directory. Discussion: https://postgr.es/m/CA%2BhUKGKpRWQ9SxdxxDmTBCJoR0YnFpMBe7kyzY8SUQk%2BHeskxg%40mail.gmail.com --- doc/src/sgml/ref/create_tablespace.sgml | 14 ++++++---- src/backend/commands/tablespace.c | 36 ++++++++++++++++++------- src/backend/parser/gram.y | 13 ++++++--- src/include/commands/tablespace.h | 1 + src/include/nodes/parsenodes.h | 1 + 5 files changed, 47 insertions(+), 18 deletions(-) diff --git a/doc/src/sgml/ref/create_tablespace.sgml b/doc/src/sgml/ref/create_tablespace.sgml index 84fa7ee5e2..497b2568fb 100644 --- a/doc/src/sgml/ref/create_tablespace.sgml +++ b/doc/src/sgml/ref/create_tablespace.sgml @@ -23,7 +23,7 @@ PostgreSQL documentation CREATE TABLESPACE tablespace_name [ OWNER { new_owner | CURRENT_ROLE | CURRENT_USER | SESSION_USER } ] - LOCATION 'directory' + [ NEW ] LOCATION 'directory' [ WITH ( tablespace_option = value [, ... ] ) ] @@ -92,10 +92,14 @@ CREATE TABLESPACE tablespace_name The directory that will be used for the tablespace. The directory - must exist (CREATE TABLESPACE will not create it), - should be empty, and must be owned by the - PostgreSQL system user. The directory must be - specified by an absolute path name. + must exist, be empty, and be owned by the + PostgreSQL system user unless + NEW is specified. If + NEW is specified it will be created, and the parent + directory must exist. + The directory must be specified by an absolute path name, or a path + name that is relative to the data directory and begins with + pg_user_files/. diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c index adfbde6b29..b2a1a12fbc 100644 --- a/src/backend/commands/tablespace.c +++ b/src/backend/commands/tablespace.c @@ -91,7 +91,8 @@ char *temp_tablespaces = NULL; static void create_tablespace_directories(const char *location, - const Oid tablespaceoid); + const Oid tablespaceoid, + bool missing_ok); static bool destroy_tablespace_directories(Oid tablespaceoid, bool redo); @@ -369,13 +370,14 @@ CreateTableSpace(CreateTableSpaceStmt *stmt) /* Post creation hook for new tablespace */ InvokeObjectPostCreateHook(TableSpaceRelationId, tablespaceoid, 0); - create_tablespace_directories(location, tablespaceoid); + create_tablespace_directories(location, tablespaceoid, stmt->missing_ok); /* Record the filesystem change in XLOG */ { xl_tblspc_create_rec xlrec; xlrec.ts_id = tablespaceoid; + xlrec.ts_missing_ok = stmt->missing_ok; XLogBeginInsert(); XLogRegisterData((char *) &xlrec, @@ -588,7 +590,8 @@ DropTableSpace(DropTableSpaceStmt *stmt) * to the specified directory */ static void -create_tablespace_directories(const char *location, const Oid tablespaceoid) +create_tablespace_directories(const char *location, const Oid tablespaceoid, + bool missing_ok) { char buffer[MAXPGPATH]; char *linkloc; @@ -601,16 +604,28 @@ create_tablespace_directories(const char *location, const Oid tablespaceoid) /* * Attempt to coerce target directory to safe permissions. If this fails, - * it doesn't exist or has the wrong owner. + * it doesn't exist or has the wrong owner. If NEW LOCATION, we'll create + * the directory. */ if (chmod(location, pg_dir_create_mode) != 0) { if (errno == ENOENT) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_FILE), - errmsg("directory \"%s\" does not exist", location), - InRecovery ? errhint("Create this directory for the tablespace before " - "restarting the server.") : 0)); + { + if (missing_ok) + { + if (mkdir(location, pg_dir_create_mode) != 0) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FILE), + errmsg("could not create directory \"%s\"", + location))); + } + else + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FILE), + errmsg("directory \"%s\" does not exist", location), + InRecovery ? errhint("Create this directory for the tablespace before " + "restarting the server.") : 0)); + } else ereport(ERROR, (errcode_for_file_access(), @@ -1537,8 +1552,9 @@ tblspc_redo(XLogReaderState *record) { xl_tblspc_create_rec *xlrec = (xl_tblspc_create_rec *) XLogRecGetData(record); char *location = xlrec->ts_path; + bool missing_ok = xlrec->ts_missing_ok; - create_tablespace_directories(location, xlrec->ts_id); + create_tablespace_directories(location, xlrec->ts_id, missing_ok); } else if (info == XLOG_TBLSPC_DROP) { diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 08f1bf1031..3a30d299f8 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -571,6 +571,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type constraints_set_mode %type OptTableSpace OptConsTableSpace %type OptTableSpaceOwner +%type OptTableSpaceNew %type opt_check_option %type opt_provider security_label @@ -4552,13 +4553,14 @@ opt_procedural: * *****************************************************************************/ -CreateTableSpaceStmt: CREATE TABLESPACE name OptTableSpaceOwner LOCATION Sconst opt_reloptions +CreateTableSpaceStmt: CREATE TABLESPACE name OptTableSpaceOwner OptTableSpaceNew LOCATION Sconst opt_reloptions { CreateTableSpaceStmt *n = makeNode(CreateTableSpaceStmt); n->tablespacename = $3; n->owner = $4; - n->location = $6; - n->options = $7; + n->missing_ok = $5; + n->location = $7; + n->options = $8; $$ = (Node *) n; } ; @@ -4567,6 +4569,11 @@ OptTableSpaceOwner: OWNER RoleSpec { $$ = $2; } | /*EMPTY */ { $$ = NULL; } ; +OptTableSpaceNew: + NEW { $$ = true; } + | /*EMPTY*/ { $$ = false; } + ; + /***************************************************************************** * * QUERY : diff --git a/src/include/commands/tablespace.h b/src/include/commands/tablespace.h index 49cfc8479a..7a53c886c0 100644 --- a/src/include/commands/tablespace.h +++ b/src/include/commands/tablespace.h @@ -26,6 +26,7 @@ typedef struct xl_tblspc_create_rec { Oid ts_id; + bool ts_missing_ok; char ts_path[FLEXIBLE_ARRAY_MEMBER]; /* null-terminated string */ } xl_tblspc_create_rec; diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 3138877553..6ab32e0786 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -2321,6 +2321,7 @@ typedef struct CreateTableSpaceStmt RoleSpec *owner; char *location; List *options; + bool missing_ok; } CreateTableSpaceStmt; typedef struct DropTableSpaceStmt -- 2.30.2