From efb02b2bd83ab261f89d0f3b086e03304f17812d Mon Sep 17 00:00:00 2001 From: zhangwenchao <656540940@qq.com> Date: Wed, 18 Dec 2024 14:29:16 +0800 Subject: [PATCH] Support create directory table with location. When we create directory table with location, the file directory path will concat with location at beginning. Authored-by: Zhang Wenchao zwcpostgres@gmail.com --- src/backend/commands/dirtablecmds.c | 19 ++++++++++++++++++- src/backend/nodes/copyfuncs.c | 1 + src/backend/nodes/equalfuncs.c | 1 + src/backend/nodes/outfuncs.c | 1 + src/backend/nodes/readfast.c | 1 + src/backend/parser/gram.y | 16 ++++++++++++---- src/include/nodes/parsenodes.h | 1 + src/test/regress/input/directory_table.source | 8 ++++++++ .../regress/output/directory_table.source | 15 +++++++++++++++ .../output/directory_table_optimizer.source | 15 +++++++++++++++ 10 files changed, 73 insertions(+), 5 deletions(-) diff --git a/src/backend/commands/dirtablecmds.c b/src/backend/commands/dirtablecmds.c index 4efcf838003..3379c5802fa 100644 --- a/src/backend/commands/dirtablecmds.c +++ b/src/backend/commands/dirtablecmds.c @@ -135,7 +135,24 @@ CreateDirectoryTable(CreateDirectoryTableStmt *stmt, Oid relId) relFileNode.spcNode = spcId; relFileNode.dbNode = MyDatabaseId; relFileNode.relNode = pg_class_tuple->relfilenode; - dirTablePath = UFileFormatPathName(&relFileNode); + if (stmt->location) + { + if (spcId == InvalidOid || + spcId == DEFAULTTABLESPACE_OID) + dirTablePath = psprintf("base/%s", stmt->location); + else if (spcId == GLOBALTABLESPACE_OID) + dirTablePath = psprintf("global/%s", stmt->location); + else + dirTablePath = psprintf("pg_tblspc/%s", stmt->location); + } + else + dirTablePath = UFileFormatPathName(&relFileNode); + + if (UFileExists(spcId, dirTablePath) && GetTablespaceFileHandler(spcId) == &localFileAm) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("directory table path \"%s\" already exists", + dirTablePath))); ReleaseSysCache(class_tuple); diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 6715e5049c0..540677ff750 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -6290,6 +6290,7 @@ _copyCreateDirectoryTableStmt(const CreateDirectoryTableStmt *from) CopyCreateStmtFields((const CreateStmt *) from, (CreateStmt *) newnode); COPY_STRING_FIELD(tablespacename); + COPY_STRING_FIELD(location); return newnode; } diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 5a03f341aa3..1d548acfb80 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -3474,6 +3474,7 @@ _equalCreateDirectoryTableStmt(const CreateDirectoryTableStmt *a, const CreateDi return false; COMPARE_STRING_FIELD(tablespacename); + COMPARE_STRING_FIELD(location); return true; } diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index a0090d04057..505be4240eb 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -4094,6 +4094,7 @@ _outCreateDirectoryTableStmt(StringInfo str, const CreateDirectoryTableStmt *nod _outCreateStmtInfo(str, (const CreateStmt *) node); WRITE_STRING_FIELD(tablespacename); + WRITE_STRING_FIELD(location); } static void diff --git a/src/backend/nodes/readfast.c b/src/backend/nodes/readfast.c index abb3947f629..b6b3e1007e0 100644 --- a/src/backend/nodes/readfast.c +++ b/src/backend/nodes/readfast.c @@ -1853,6 +1853,7 @@ _readCreateDirectoryTableStmt(void) _readCreateStmt_common(&local_node->base); READ_STRING_FIELD(tablespacename); + READ_STRING_FIELD(location); READ_DONE(); } diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 06540bd2168..6741809d7c3 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -416,6 +416,7 @@ static void check_expressions_in_partition_key(PartitionSpec *spec, core_yyscan_ access_method_clause attr_name table_access_method_clause name cursor_name file_name opt_index_name cluster_index_specification opt_file_name +%type OptWithLocation %type func_name handler_name qual_Op qual_all_Op subquery_Op opt_class opt_inline_handler opt_validator validator_clause @@ -6013,6 +6014,11 @@ OptWith: | /*EMPTY*/ { $$ = NIL; } ; +OptWithLocation: + WITH LOCATION Sconst { $$ = $3; } + | /*EMPTY*/ { $$ = NULL; } + ; + OnCommitOption: ON COMMIT DROP { $$ = ONCOMMIT_DROP; } | ON COMMIT DELETE_P ROWS { $$ = ONCOMMIT_DELETE_ROWS; } | ON COMMIT PRESERVE ROWS { $$ = ONCOMMIT_PRESERVE_ROWS; } @@ -8530,7 +8536,7 @@ AlterStorageUserMappingStmt: CreateDirectoryTableStmt: CREATE DIRECTORY TABLE qualified_name - table_access_method_clause OptTableSpace OptTagOptList + table_access_method_clause OptTableSpace OptWithLocation OptTagOptList { CreateDirectoryTableStmt *n = makeNode(CreateDirectoryTableStmt); $4->relpersistence = RELPERSISTENCE_PERMANENT; @@ -8545,13 +8551,14 @@ CreateDirectoryTableStmt: n->base.if_not_exists = false; n->base.distributedBy = GetDirectoryTableDistributedBy(); n->base.relKind = RELKIND_DIRECTORY_TABLE; - n->base.tags = $7; n->tablespacename = $6; + n->location = $7; + n->base.tags = $8; $$ = (Node *) n; } | CREATE DIRECTORY TABLE IF_P NOT EXISTS qualified_name - table_access_method_clause OptTableSpace OptTagOptList + table_access_method_clause OptTableSpace OptWithLocation OptTagOptList { CreateDirectoryTableStmt *n = makeNode(CreateDirectoryTableStmt); $7->relpersistence = RELPERSISTENCE_PERMANENT; @@ -8566,8 +8573,9 @@ CreateDirectoryTableStmt: n->base.if_not_exists = true; n->base.distributedBy = GetDirectoryTableDistributedBy(); n->base.relKind = RELKIND_DIRECTORY_TABLE; - n->base.tags = $10; n->tablespacename = $9; + n->location = $10; + n->base.tags = $11; $$ = (Node *) n; } diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 2a3b3316c2a..04d7e811bf1 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -3412,6 +3412,7 @@ typedef struct CreateDirectoryTableStmt { CreateStmt base; char *tablespacename; + char *location; } CreateDirectoryTableStmt; typedef struct AlterDirectoryTableStmt diff --git a/src/test/regress/input/directory_table.source b/src/test/regress/input/directory_table.source index a027ae12348..664673919c2 100644 --- a/src/test/regress/input/directory_table.source +++ b/src/test/regress/input/directory_table.source @@ -648,6 +648,14 @@ SELECT relative_path, tag FROM dir_table4 ORDER BY 1; SAVEPOINT s2; ROLLBACK; +-- test create directory table with location +CREATE DIRECTORY TABLE dir_table_with_location TABLESPACE directory_tblspc WITH LOCATION '/test_dirtable'; +CREATE DIRECTORY TABLE dir_table_with_location2 TABLESPACE directory_tblspc WITH LOCATION '/test_dirtable'; -- error +CREATE DIRECTORY TABLE dir_table_with_location3 WITH LOCATION '/test_dirtable'; +SELECT count(*) FROM pg_directory_table; +DROP DIRECTORY TABLE dir_table_with_location WITH CONTENT; +DROP DIRECTORY TABLE dir_table_with_location3 WITH CONTENT; + -- clean up DROP DIRECTORY TABLE IF EXISTS dir_table1; DROP DIRECTORY TABLE IF EXISTS dir_table2; diff --git a/src/test/regress/output/directory_table.source b/src/test/regress/output/directory_table.source index 8915fba5131..332d8e17e17 100644 --- a/src/test/regress/output/directory_table.source +++ b/src/test/regress/output/directory_table.source @@ -2063,6 +2063,21 @@ SELECT relative_path, tag FROM dir_table4 ORDER BY 1; SAVEPOINT s2; ROLLBACK; +-- test create directory table with location +CREATE DIRECTORY TABLE dir_table_with_location TABLESPACE directory_tblspc WITH LOCATION '/test_dirtable'; +CREATE DIRECTORY TABLE dir_table_with_location2 TABLESPACE directory_tblspc WITH LOCATION '/test_dirtable'; -- error +ERROR: directory table path "pg_tblspc//test_dirtable" already exists +CREATE DIRECTORY TABLE dir_table_with_location3 WITH LOCATION '/test_dirtable'; +SELECT count(*) FROM pg_directory_table; + count +------- + 8 +(1 row) + +DROP DIRECTORY TABLE dir_table_with_location WITH CONTENT; +DROP +DROP DIRECTORY TABLE dir_table_with_location3 WITH CONTENT; +DROP -- clean up DROP DIRECTORY TABLE IF EXISTS dir_table1; DROP DIRECTORY TABLE IF EXISTS dir_table2; diff --git a/src/test/regress/output/directory_table_optimizer.source b/src/test/regress/output/directory_table_optimizer.source index 222c8244fa3..3d6c34e8af7 100644 --- a/src/test/regress/output/directory_table_optimizer.source +++ b/src/test/regress/output/directory_table_optimizer.source @@ -2063,6 +2063,21 @@ SELECT relative_path, tag FROM dir_table4 ORDER BY 1; SAVEPOINT s2; ROLLBACK; +-- test create directory table with location +CREATE DIRECTORY TABLE dir_table_with_location TABLESPACE directory_tblspc WITH LOCATION '/test_dirtable'; +CREATE DIRECTORY TABLE dir_table_with_location2 TABLESPACE directory_tblspc WITH LOCATION '/test_dirtable'; -- error +ERROR: directory table path "pg_tblspc//test_dirtable" already exists +CREATE DIRECTORY TABLE dir_table_with_location3 WITH LOCATION '/test_dirtable'; +SELECT count(*) FROM pg_directory_table; + count +------- + 8 +(1 row) + +DROP DIRECTORY TABLE dir_table_with_location WITH CONTENT; +DROP +DROP DIRECTORY TABLE dir_table_with_location3 WITH CONTENT; +DROP -- clean up DROP DIRECTORY TABLE IF EXISTS dir_table1; DROP DIRECTORY TABLE IF EXISTS dir_table2;