From 3229c65367f7547aa02118537c490f15a5f196be Mon Sep 17 00:00:00 2001 From: zhangwenchao <656540940@qq.com> Date: Tue, 20 Feb 2024 11:37:20 +0800 Subject: [PATCH] Implement Directory Table. Implement directory table feature in this commit. Directory table is a new relation which used to organize the unstructured data files in the specified tablespace. The date files are stored in the specified tablespace while the tuples recorded the metadata of the data files such as relative_path, md5 size etc. are stored in normal table. We support local directory table and remote directory table meanwhile. The local directory table uses the local tablespace while the remote directory table uses the DFS tablespace which implemented in our enterprise extension. We support copy binary from to upload file to directory table, directory_table UDF to get file content, remove_file UDF to remove file from directory table. What's more, we implement a tool called cbload used to upload file to direcotry table. Meanwhile, to support DFS directory table, we also import some catalog tables such as gp_storage_server, gp_storage_user_mapping which are shared in all databases. We will illustrage some examples for your convinence of usage as follow. -- Create an oss_server that points to endpoint: CREATE STORAGE SERVER oss_server OPTIONS (protocol 'qingstor', endpoint 'pek3b.qingstor.com', https 'true', virtual_host 'false'); -- Create a user mapping to access oss_server CREATE STORAGE USER MAPPING FOR CURRENT_USER STORAGE SERVER oss_server OPTIONS (accesskey 'KGCPPHVCHRDSYFEAWLLC', secretkey '0SJIWiIATh6jOlmAas23q6hOAGBI1BnsnvgJmTs'); -- Create a local tablespace CREATE TABLESPACE dirtable_spc location '/data/dirtable_spc'; -- Create a local directory table CREATE DIRECTORY TABLE dirtable TABLESPACE dirtable_spc; -- Copy binary from directory table COPY BINARY dirtable FROM '/data/file1.csv' 'file1'; -- Select directory table SELECT * FROM dirtable; SELECT * FROM directory_table('dirtable'); -- Remove file from directory table SELECT remove_file('dirtable', 'file1'); Co-authored-by: Mu Guoqing muguoqing@hashdata.cn Reviewd-by: Yang Yu yangyu@hashdata.cn Yang Jianghua yjhjstz@gmail.com --- contrib/amcheck/verify_heapam.c | 5 +- contrib/oid2name/oid2name.c | 3 +- contrib/pg_surgery/heap_surgery.c | 3 +- contrib/pg_visibility/pg_visibility.c | 3 +- contrib/pgstattuple/pgstatapprox.c | 5 +- contrib/pgstattuple/pgstatindex.c | 5 +- contrib/pgstattuple/pgstattuple.c | 1 + contrib/postgres_fdw/postgres_fdw.c | 1 + gpMgmt/bin/Makefile | 1 + gpMgmt/bin/cbload/Makefile | 25 + gpMgmt/bin/cbload/go.mod | 25 + gpMgmt/bin/cbload/go.sum | 173 ++ gpMgmt/bin/cbload/loader/loader.go | 261 +++ gpMgmt/bin/cbload/log/log.go | 59 + gpMgmt/bin/cbload/main.go | 20 + gpMgmt/bin/cbload/option/option.go | 286 +++ gpMgmt/bin/cbload/worker/worker.go | 168 ++ gpMgmt/bin/gpcheckcat | 6 +- .../gp_distribution_policy.c | 3 +- src/backend/access/aocs/aocsam_handler.c | 3 +- .../access/appendonly/appendonlyam_handler.c | 1 + src/backend/access/common/reloptions.c | 34 +- src/backend/access/heap/heapam_handler.c | 1 + src/backend/catalog/Makefile | 6 +- src/backend/catalog/aclchk.c | 122 ++ src/backend/catalog/catalog.c | 16 + src/backend/catalog/dependency.c | 17 + src/backend/catalog/heap.c | 21 + src/backend/catalog/objectaddress.c | 193 ++ src/backend/catalog/oid_dispatch.c | 36 + src/backend/catalog/pg_directory_table.c | 375 ++++ src/backend/catalog/pg_shdepend.c | 42 + src/backend/catalog/storage.c | 6 + src/backend/catalog/storage_directory_table.c | 240 +++ src/backend/catalog/system_views.sql | 2 + src/backend/commands/Makefile | 4 +- src/backend/commands/alter.c | 3 + src/backend/commands/analyze.c | 6 +- src/backend/commands/comment.c | 3 +- src/backend/commands/copy.c | 92 + src/backend/commands/copyfrom.c | 824 +++++++- src/backend/commands/dirtablecmds.c | 475 +++++ src/backend/commands/dropcmds.c | 4 + src/backend/commands/event_trigger.c | 14 + src/backend/commands/indexcmds.c | 7 + src/backend/commands/seclabel.c | 4 + src/backend/commands/statscmds.c | 1 + src/backend/commands/storagecmds.c | 957 +++++++++ src/backend/commands/tablecmds.c | 129 +- src/backend/commands/tablespace.c | 25 + src/backend/commands/trigger.c | 7 +- src/backend/commands/vacuum.c | 5 + src/backend/executor/execMain.c | 50 +- src/backend/executor/execPartition.c | 4 +- src/backend/executor/nodeModifyTable.c | 4 +- src/backend/gpopt/gpdbwrappers.cpp | 2 +- src/backend/nodes/copyfuncs.c | 108 + src/backend/nodes/equalfuncs.c | 93 + src/backend/nodes/outfast.c | 98 +- src/backend/nodes/outfuncs.c | 12 + src/backend/nodes/outfuncs_common.c | 2 + src/backend/nodes/readfast.c | 105 + src/backend/optimizer/util/appendinfo.c | 1 + src/backend/optimizer/util/plancat.c | 1 + src/backend/parser/gram.y | 305 ++- src/backend/parser/parse_clause.c | 3 +- src/backend/parser/parse_relation.c | 3 +- src/backend/parser/parse_utilcmd.c | 3 +- src/backend/postmaster/autovacuum.c | 5 +- src/backend/rewrite/rewriteDefine.c | 6 +- src/backend/rewrite/rewriteHandler.c | 1 + src/backend/storage/buffer/bufmgr.c | 1 + src/backend/storage/file/Makefile | 3 +- src/backend/storage/file/ufile.c | 470 +++++ src/backend/storage/ipc/procarray.c | 1 + src/backend/storage/lmgr/lwlocknames.txt | 1 + src/backend/tcop/postgres.c | 8 +- src/backend/tcop/utility.c | 100 + src/backend/utils/adt/acl.c | 4 + src/backend/utils/adt/dbsize.c | 3 + src/backend/utils/adt/pseudotypes.c | 1 + src/backend/utils/adt/xml.c | 2 + src/backend/utils/cache/relcache.c | 11 +- src/backend/utils/cache/spccache.c | 9 +- src/backend/utils/cache/syscache.c | 58 + src/bin/initdb/initdb.c | 6 +- src/bin/pg_dump/pg_dumpall.c | 54 +- src/bin/psql/command.c | 1 + src/bin/psql/describe.c | 22 +- src/bin/psql/tab-complete.c | 85 +- src/bin/scripts/reindexdb.c | 2 + src/bin/scripts/vacuumdb.c | 1 + src/common/md5_common.c | 2 +- src/include/catalog/catversion.h | 2 +- src/include/catalog/dependency.h | 10 + src/include/catalog/gp_storage_server.h | 51 + src/include/catalog/gp_storage_user_mapping.h | 54 + src/include/catalog/oid_dispatch.h | 4 + src/include/catalog/pg_class.h | 2 + src/include/catalog/pg_directory_table.h | 72 + src/include/catalog/pg_proc.dat | 14 + src/include/catalog/pg_tablespace.h | 2 + src/include/catalog/pg_type.dat | 7 + src/include/catalog/storage_directory_table.h | 25 + src/include/commands/copy.h | 2 + src/include/commands/defrem.h | 6 + src/include/commands/dirtablecmds.h | 24 + src/include/commands/storagecmds.h | 52 + src/include/commands/tablespace.h | 3 + src/include/common/md5.h | 1 + src/include/executor/executor.h | 2 +- src/include/nodes/nodes.h | 7 + src/include/nodes/parsenodes.h | 75 +- src/include/parser/kwlist.h | 2 + src/include/storage/ufile.h | 68 + src/include/tcop/cmdtaglist.h | 9 + src/include/utils/acl.h | 5 + src/include/utils/spccache.h | 10 + src/include/utils/syscache.h | 5 + src/interfaces/ecpg/preproc/ecpg.addons | 2 +- src/pl/plpgsql/src/pl_comp.c | 3 +- .../input/local_directory_table_mixed.source | 131 ++ src/test/isolation2/isolation2_schedule | 2 + .../output/local_directory_table_mixed.source | 374 ++++ src/test/regress/expected/create_index.out | 8 +- .../expected/create_index_optimizer.out | 8 +- .../regress/expected/create_table_like.out | 2 +- src/test/regress/expected/minirepro.out | 16 +- src/test/regress/expected/oidjoins.out | 5 + src/test/regress/expected/opr_sanity.out | 8 +- src/test/regress/expected/sanity_check.out | 1 + src/test/regress/greenplum_schedule | 3 + src/test/regress/input/directory_table.source | 647 ++++++ .../regress/output/directory_table.source | 1847 +++++++++++++++++ .../output/directory_table_optimizer.source | 1842 ++++++++++++++++ src/test/regress/output/external_table.source | 10 +- .../expected/create_index.out | 8 +- .../expected/create_table_like.out | 2 +- .../singlenode_regress/expected/oidjoins.out | 5 + .../expected/opr_sanity.out | 8 +- .../expected/sanity_check.out | 1 + src/tools/pgindent/typedefs.list | 6 + 142 files changed, 11686 insertions(+), 146 deletions(-) create mode 100644 gpMgmt/bin/cbload/Makefile create mode 100644 gpMgmt/bin/cbload/go.mod create mode 100644 gpMgmt/bin/cbload/go.sum create mode 100644 gpMgmt/bin/cbload/loader/loader.go create mode 100644 gpMgmt/bin/cbload/log/log.go create mode 100644 gpMgmt/bin/cbload/main.go create mode 100644 gpMgmt/bin/cbload/option/option.go create mode 100644 gpMgmt/bin/cbload/worker/worker.go create mode 100644 src/backend/catalog/pg_directory_table.c create mode 100644 src/backend/catalog/storage_directory_table.c create mode 100644 src/backend/commands/dirtablecmds.c create mode 100644 src/backend/commands/storagecmds.c create mode 100644 src/backend/storage/file/ufile.c create mode 100644 src/include/catalog/gp_storage_server.h create mode 100644 src/include/catalog/gp_storage_user_mapping.h create mode 100644 src/include/catalog/pg_directory_table.h create mode 100644 src/include/catalog/storage_directory_table.h create mode 100644 src/include/commands/dirtablecmds.h create mode 100644 src/include/commands/storagecmds.h create mode 100644 src/include/storage/ufile.h create mode 100644 src/test/isolation2/input/local_directory_table_mixed.source create mode 100644 src/test/isolation2/output/local_directory_table_mixed.source create mode 100644 src/test/regress/input/directory_table.source create mode 100644 src/test/regress/output/directory_table.source create mode 100644 src/test/regress/output/directory_table_optimizer.source diff --git a/contrib/amcheck/verify_heapam.c b/contrib/amcheck/verify_heapam.c index 30064d0aba9..9abeca607d7 100644 --- a/contrib/amcheck/verify_heapam.c +++ b/contrib/amcheck/verify_heapam.c @@ -549,10 +549,11 @@ sanity_check_relation(Relation rel) { if (rel->rd_rel->relkind != RELKIND_RELATION && rel->rd_rel->relkind != RELKIND_MATVIEW && - rel->rd_rel->relkind != RELKIND_TOASTVALUE) + rel->rd_rel->relkind != RELKIND_TOASTVALUE && + rel->rd_rel->relkind != RELKIND_DIRECTORY_TABLE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("\"%s\" is not a table, materialized view, or TOAST table", + errmsg("\"%s\" is not a table, directory table, materialized view, or TOAST table", RelationGetRelationName(rel)))); if (rel->rd_rel->relam != HEAP_TABLE_AM_OID) ereport(ERROR, diff --git a/contrib/oid2name/oid2name.c b/contrib/oid2name/oid2name.c index af198e87b89..4803fec9302 100644 --- a/contrib/oid2name/oid2name.c +++ b/contrib/oid2name/oid2name.c @@ -479,7 +479,7 @@ sql_exec_dumpalltables(PGconn *conn, struct options *opts) " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace " " LEFT JOIN pg_catalog.pg_database d ON d.datname = pg_catalog.current_database()," " pg_catalog.pg_tablespace t " - "WHERE relkind IN (" CppAsString2(RELKIND_RELATION) "," + "WHERE relkind IN (" CppAsString2(RELKIND_RELATION) "," CppAsString2(RELKIND_DIRECTORY_TABLE) "," CppAsString2(RELKIND_MATVIEW) "%s%s) AND " " %s" " t.oid = CASE" @@ -553,6 +553,7 @@ sql_exec_searchtables(PGconn *conn, struct options *opts) CppAsString2(RELKIND_MATVIEW) "," CppAsString2(RELKIND_INDEX) "," CppAsString2(RELKIND_SEQUENCE) "," + CppAsString2(RELKIND_DIRECTORY_TABLE) "," CppAsString2(RELKIND_TOASTVALUE) ") AND\n" " t.oid = CASE\n" " WHEN reltablespace <> 0 THEN reltablespace\n" diff --git a/contrib/pg_surgery/heap_surgery.c b/contrib/pg_surgery/heap_surgery.c index d31e5f31fd4..6ad14c6fcf1 100644 --- a/contrib/pg_surgery/heap_surgery.c +++ b/contrib/pg_surgery/heap_surgery.c @@ -374,7 +374,8 @@ sanity_check_relation(Relation rel) { if (rel->rd_rel->relkind != RELKIND_RELATION && rel->rd_rel->relkind != RELKIND_MATVIEW && - rel->rd_rel->relkind != RELKIND_TOASTVALUE) + rel->rd_rel->relkind != RELKIND_TOASTVALUE && + rel->rd_rel->relkind != RELKIND_DIRECTORY_TABLE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is not a table, materialized view, or TOAST table", diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c index 7d384d3e2ce..10baf368d3c 100644 --- a/contrib/pg_visibility/pg_visibility.c +++ b/contrib/pg_visibility/pg_visibility.c @@ -778,7 +778,8 @@ check_relation_relkind(Relation rel) { if (rel->rd_rel->relkind != RELKIND_RELATION && rel->rd_rel->relkind != RELKIND_MATVIEW && - rel->rd_rel->relkind != RELKIND_TOASTVALUE) + rel->rd_rel->relkind != RELKIND_TOASTVALUE && + rel->rd_rel->relkind != RELKIND_DIRECTORY_TABLE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is not a table, materialized view, or TOAST table", diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c index cf71af7a0ce..cebe6a6a6ac 100644 --- a/contrib/pgstattuple/pgstatapprox.c +++ b/contrib/pgstattuple/pgstatapprox.c @@ -289,10 +289,11 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo) rel->rd_rel->relkind == RELKIND_AOBLOCKDIR || rel->rd_rel->relkind == RELKIND_AOVISIMAP || rel->rd_rel->relkind == RELKIND_MATVIEW || - rel->rd_rel->relkind == RELKIND_TOASTVALUE)) + rel->rd_rel->relkind == RELKIND_TOASTVALUE || + rel->rd_rel->relkind == RELKIND_DIRECTORY_TABLE)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("\"%s\" is not a table, materialized view, or TOAST table", + errmsg("\"%s\" is not a table, directory table, materialized view, or TOAST table", RelationGetRelationName(rel)))); if (rel->rd_rel->relam != HEAP_TABLE_AM_OID) diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c index 5368bb30f0c..f7763b2e2fc 100644 --- a/contrib/pgstattuple/pgstatindex.c +++ b/contrib/pgstattuple/pgstatindex.c @@ -766,9 +766,10 @@ check_relation_relkind(Relation rel) rel->rd_rel->relkind != RELKIND_INDEX && rel->rd_rel->relkind != RELKIND_MATVIEW && rel->rd_rel->relkind != RELKIND_SEQUENCE && - rel->rd_rel->relkind != RELKIND_TOASTVALUE) + rel->rd_rel->relkind != RELKIND_TOASTVALUE && + rel->rd_rel->relkind != RELKIND_DIRECTORY_TABLE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("\"%s\" is not a table, index, materialized view, sequence, or TOAST table", + errmsg("\"%s\" is not a table, directory table, index, materialized view, sequence, or TOAST table", RelationGetRelationName(rel)))); } diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c index 9226e459a84..ae0f09fd05e 100644 --- a/contrib/pgstattuple/pgstattuple.c +++ b/contrib/pgstattuple/pgstattuple.c @@ -261,6 +261,7 @@ pgstat_relation(Relation rel, FunctionCallInfo fcinfo) case RELKIND_AOSEGMENTS: case RELKIND_AOBLOCKDIR: case RELKIND_AOVISIMAP: + case RELKIND_DIRECTORY_TABLE: return pgstat_heap(rel, fcinfo); case RELKIND_INDEX: switch (rel->rd_rel->relam) diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c index e5c5d6d927b..b68868d5472 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -5368,6 +5368,7 @@ postgresImportForeignSchema(ImportForeignSchemaStmt *stmt, Oid serverOid) CppAsString2(RELKIND_VIEW) "," CppAsString2(RELKIND_FOREIGN_TABLE) "," CppAsString2(RELKIND_MATVIEW) "," + CppAsString2(RELKIND_DIRECTORY_TABLE) "," CppAsString2(RELKIND_PARTITIONED_TABLE) ") " " AND n.nspname = "); deparseStringLiteral(&buf, stmt->remote_schema); diff --git a/gpMgmt/bin/Makefile b/gpMgmt/bin/Makefile index ea978e3f281..181b5c1bc87 100644 --- a/gpMgmt/bin/Makefile +++ b/gpMgmt/bin/Makefile @@ -9,6 +9,7 @@ endif SUBDIRS = stream gpcheckcat_modules gpconfig_modules gpssh_modules gppylib lib SUBDIRS += ifaddrs +SUBDIRS += cbload $(recurse) diff --git a/gpMgmt/bin/cbload/Makefile b/gpMgmt/bin/cbload/Makefile new file mode 100644 index 00000000000..d6226382ad3 --- /dev/null +++ b/gpMgmt/bin/cbload/Makefile @@ -0,0 +1,25 @@ +subdir = gpMgmt/bin/cbload +top_builddir = ../../.. +include $(top_builddir)/src/Makefile.global + +.DEFAULT_GOAL := all + +export GOPROXY ?= https://proxy.golang.org + +all: build + +build : + go mod download + go build -o cbload github.com/cloudberrydb/cbload + +clean : + rm -f cbload + +install: all + $(INSTALL_PROGRAM) 'cbload' $(bindir) + +uninstall: + rm -f $(bindir)/cbload + +distclean: + rm -f cbload diff --git a/gpMgmt/bin/cbload/go.mod b/gpMgmt/bin/cbload/go.mod new file mode 100644 index 00000000000..86c8b57390c --- /dev/null +++ b/gpMgmt/bin/cbload/go.mod @@ -0,0 +1,25 @@ +module github.com/cloudberrydb/cbload + +go 1.19 + +require ( + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/jackc/chunkreader/v2 v2.0.1 // indirect + github.com/jackc/pgconn v1.14.1 // indirect + github.com/jackc/pgio v1.0.0 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgproto3/v2 v2.3.2 // indirect + github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect + github.com/mattn/go-colorable v0.1.1 // indirect + github.com/mattn/go-isatty v0.0.7 // indirect + github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect + github.com/spf13/cobra v1.8.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/x-cray/logrus-prefixed-formatter v0.5.2 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/sys v0.16.0 // indirect + golang.org/x/term v0.16.0 // indirect + golang.org/x/text v0.7.0 // indirect +) diff --git a/gpMgmt/bin/cbload/go.sum b/gpMgmt/bin/cbload/go.sum new file mode 100644 index 00000000000..70bdf7b843c --- /dev/null +++ b/gpMgmt/bin/cbload/go.sum @@ -0,0 +1,173 @@ +github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0= +github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= +github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= +github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= +github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= +github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= +github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= +github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= +github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= +github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= +github.com/jackc/pgconn v1.14.1 h1:smbxIaZA08n6YuxEX1sDyjV/qkbtUtkH20qLkR9MUR4= +github.com/jackc/pgconn v1.14.1/go.mod h1:9mBNlny0UvkgJdCDvdVHYSjI+8tD2rnKK69Wz8ti++E= +github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= +github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= +github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= +github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= +github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A= +github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= +github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= +github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= +github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= +github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= +github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.3.2 h1:7eY55bdBeCz1F2fTzSz69QC+pG46jYq9/jtSPiJ5nn0= +github.com/jackc/pgproto3/v2 v2.3.2/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= +github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= +github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= +github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= +github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= +github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= +github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc= +github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI= +github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= +github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= +github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/x-cray/logrus-prefixed-formatter v0.5.2 h1:00txxvfBM9muc0jiLIEAkAcIMJzfthRT6usrui8uGmg= +github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/gpMgmt/bin/cbload/loader/loader.go b/gpMgmt/bin/cbload/loader/loader.go new file mode 100644 index 00000000000..05fa252bc69 --- /dev/null +++ b/gpMgmt/bin/cbload/loader/loader.go @@ -0,0 +1,261 @@ +package loader + +import ( + "context" + "fmt" + "os" + "os/signal" + "path/filepath" + "time" + + "github.com/cloudberrydb/cbload/log" + "github.com/cloudberrydb/cbload/option" + "github.com/cloudberrydb/cbload/worker" + "github.com/jackc/pgconn" + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +type Loader struct { + option *option.Option + conns []*pgconn.PgConn + workMgr *worker.WorkManager +} + +func NewLoader() *Loader { + l := &Loader{} + + l.option = option.NewOption() + + return l +} + +func (l *Loader) makeConnection() (*pgconn.PgConn, error) { + url := fmt.Sprintf("application_name=cbload user=%v password='%v' host=%v port=%v dbname=%v", + l.option.User, l.option.Password, l.option.Host, l.option.Port, l.option.Database) + + config, err := pgconn.ParseConfig(url) + if err != nil { + return nil, err + } + + conn, err := pgconn.ConnectConfig(context.Background(), config) + if err != nil { + return nil, err + } + + return conn, nil +} + +func (l *Loader) listFiles(prefix string, patterns []string) ([]string, []string, error) { + files := make(map[string]struct{}) + + for _, p := range patterns { + matches, err := filepath.Glob(p) + if err != nil { + return nil, nil, err + } + + for _, f := range matches { + files[f] = struct{}{} + } + } + + localFiles := make([]string, 0) + destFiles := make([]string, 0) + for k, _ := range files { + localFiles = append(localFiles, k) + destFiles = append(destFiles, filepath.Join(prefix, k)) + } + + return localFiles, destFiles, nil +} + +func (l *Loader) populateFiles(prefix string, files []string) ([]string, []string, error) { + isDirMode, err := l.option.IsDirectoryMode() + if err != nil { + return nil, nil, err + } + + if !isDirMode { + return l.listFiles(prefix, files) + } + + localFiles := make([]string, 0) + destFiles := make([]string, 0) + err = filepath.Walk(files[0], func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + if info.IsDir() { + return nil + } + + if info.Size() == 0 { + log.Logger.Infof("Ignore empty file: \"%v\"", path) + return nil + } + + localFiles = append(localFiles, path) + + relPath, _ := filepath.Rel(files[0], path) + destFiles = append(destFiles, filepath.Join(prefix, relPath)) + return nil + }) + + if err != nil { + return nil, nil, err + } + return localFiles, destFiles, nil +} + +func (l *Loader) dispatchFiles(localFiles, destFiles []string) ([][]string, [][]string) { + localTaskFiles := make([][]string, l.option.NumTasks) + destTaskFiles := make([][]string, l.option.NumTasks) + for i := 0; i < l.option.NumTasks; i++ { + localTaskFiles[i] = make([]string, 0) + destTaskFiles[i] = make([]string, 0) + } + + for i, file := range localFiles { + j := i % l.option.NumTasks + localTaskFiles[j] = append(localTaskFiles[j], file) + destTaskFiles[j] = append(destTaskFiles[j], destFiles[i]) + } + + return localTaskFiles, destTaskFiles +} + +func (l *Loader) start() (chan struct{}, chan struct{}, error) { + // step 0 retrieve files + lTotalFiles, rTotalFiles, err := l.populateFiles(l.option.DestPath, l.option.InputFile) + if err != nil { + return nil, nil, err + } + + if len(lTotalFiles) == 0 { + return nil, nil, nil + } + + // step 1 dispatch files + if len(lTotalFiles) < l.option.NumTasks { + l.option.NumTasks = len(lTotalFiles) + } + localTaskFiles, destTaskFiles := l.dispatchFiles(lTotalFiles, rTotalFiles) + + // step 2 making connection + l.conns = make([]*pgconn.PgConn, l.option.NumTasks) + log.Logger.Debug("Making database connection...") + for i := 0; i < len(l.conns); i++ { + conn, err := l.makeConnection() + if err != nil { + return nil, nil, err + } + + l.conns[i] = conn + } + log.Logger.Debug("Successfully connected to database") + + // step 3 create worker + log.Logger.Debug("Creating worker instance...") + l.workMgr = worker.NewWorkManager(l.option.Table, l.option.Tag, l.conns, localTaskFiles, destTaskFiles, l.option.StopOnError) + doneCh, quickDieCh := l.workMgr.Start() + log.Logger.Debug("Worker instances created successfully") + + return doneCh, quickDieCh, nil +} + +func (l *Loader) stop() { + // stop worker + log.Logger.Debug("Stopping worker instance...") + if l.workMgr != nil { + l.workMgr.Stop() + } + log.Logger.Debug("Worker instances have stopped") + + // closing connection + log.Logger.Debug("Closing database connection...") + for _, conn := range l.conns { + if conn != nil { + conn.Close(context.Background()) + } + } + log.Logger.Debug("Database connections have closed") +} + +func (l *Loader) Initialize(cmd *cobra.Command) { + flagSet := cmd.Flags() + + flagSet.StringVar(&l.option.Host, option.HOST, "", "Host to connect to (default localhost)") + flagSet.IntVar(&l.option.Port, option.PORT, 0, "Port to connect to (default 5432)") + flagSet.StringVar(&l.option.User, option.USER, "", "User to connect as (default gpadmin)") + flagSet.StringVar(&l.option.Database, option.DATABASE, "", "Database to connect to (default gpadmin)") + flagSet.BoolVar(&l.option.ForcePasswordAuth, option.FORCE_PASSWORD_AUTH, false, "Force a password prompt (default false)") + flagSet.StringVar(&l.option.Table, option.TABLE, "", "Table to load to") + flagSet.StringVar(&l.option.Tag, option.TAG, "", "File tag") + flagSet.StringVar(&l.option.DestPath, option.DEST_PATH, "", "Path relative to the table root directory (default: root directory of the table)") + flagSet.StringSliceVar(&l.option.InputFile, option.INPUT_FILE, []string{}, "Input files or directory") + flagSet.IntVar(&l.option.NumTasks, option.TASKS, 1, "The maximum number of files that concurrently loads") + flagSet.StringVar(&l.option.LogFile, option.LOGFILE, "", "Log output to logfile (default none)") + flagSet.BoolVar(&l.option.StopOnError, option.STOP_ON_ERROR, false, "Stop loading files when an error occurs (default false)") + flagSet.BoolVar(&l.option.Verbose, option.VERBOSE, false, "Indicates that the tool should generate verbose output (default false)") + flagSet.Bool("help", false, "Print help info and exit") + flagSet.Bool("version", false, "Print version info and exit") + + cmd.MarkFlagRequired(option.TABLE) + cmd.MarkFlagRequired(option.INPUT_FILE) +} + +func (l *Loader) GetVersion() string { + return "1.0.0" +} + +func (l *Loader) Run(cmd *cobra.Command, args []string) { + // initialize log + log.Initialize(l.option.LogFile, l.option.Verbose) + defer log.ShutDown() + + // parse options + err := l.option.Parse() + if err != nil { + log.Logger.Fatalf("%v", err) + } + + interrupt := make(chan os.Signal, 1) + signal.Notify(interrupt, os.Interrupt) + + // start loader + doneCh, quickDieCh, err := l.start() + if err != nil { + log.Logger.Fatalf("Failed to start loader: %v", err) + } + + if doneCh != nil { + loop: + for { + select { + case <-interrupt: + err = errors.New("Caught interrupt signal, exitting...") + log.Logger.Errorf("%v", err) + break loop + case <-quickDieCh: + err = errors.New("Caught internal error, exitting...") + log.Logger.Errorf("%v", err) + break loop + case <-doneCh: + log.Logger.Infof("successfully loaded %v files, failed %v files", + l.workMgr.GetNumSucceedFiles(), l.workMgr.GetNumFailedFiles()) + break loop + case <-time.After(25 * time.Millisecond): + log.Logger.Debug("Event loop") + } + } + } + + l.stop() + + if err != nil { + os.Exit(1) + } +} diff --git a/gpMgmt/bin/cbload/log/log.go b/gpMgmt/bin/cbload/log/log.go new file mode 100644 index 00000000000..4a0a45405be --- /dev/null +++ b/gpMgmt/bin/cbload/log/log.go @@ -0,0 +1,59 @@ +package log + +import ( + "io" + "os" + "strings" + + "github.com/sirupsen/logrus" + prefixed "github.com/x-cray/logrus-prefixed-formatter" +) + +var Logger = logrus.New() +var logFileHandle *os.File + +func Initialize(file string, verbose bool) (err error) { + formater := new(prefixed.TextFormatter) + formater.TimestampFormat = "2006-01-02 15:04:05" + formater.FullTimestamp = true + + Logger.Formatter = formater + + if len(file) > 0 { + logFileHandle, err = os.OpenFile(file, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644) + if err != nil { + return err + } + + Logger.Out = io.MultiWriter(logFileHandle, os.Stderr) + } + + if verbose { + setLogLevel("debug") + } else { + setLogLevel("info") + } + + return nil +} + +func setLogLevel(logLevelString string) { + switch strings.ToLower(logLevelString) { + case "debug": + Logger.SetLevel(logrus.DebugLevel) + case "info": + Logger.SetLevel(logrus.InfoLevel) + case "warning": + Logger.SetLevel(logrus.WarnLevel) + case "error": + Logger.SetLevel(logrus.ErrorLevel) + case "fatal": + Logger.SetLevel(logrus.FatalLevel) + default: + Logger.Warn("Unknown log level \"" + logLevelString + "\". Falling back to INFO.") + } +} + +func ShutDown() { + logFileHandle.Close() +} diff --git a/gpMgmt/bin/cbload/main.go b/gpMgmt/bin/cbload/main.go new file mode 100644 index 00000000000..12e4bbbdac5 --- /dev/null +++ b/gpMgmt/bin/cbload/main.go @@ -0,0 +1,20 @@ +package main + +import ( + "github.com/cloudberrydb/cbload/loader" + "github.com/spf13/cobra" +) + +func main() { + l := loader.NewLoader() + + var rootCmd = &cobra.Command{ + Use: "cbload", + Short: "load file(s) into Cloudberry Database", + Version: l.GetVersion(), + Run: l.Run, + } + + l.Initialize(rootCmd) + rootCmd.Execute() +} diff --git a/gpMgmt/bin/cbload/option/option.go b/gpMgmt/bin/cbload/option/option.go new file mode 100644 index 00000000000..a8f0720b76c --- /dev/null +++ b/gpMgmt/bin/cbload/option/option.go @@ -0,0 +1,286 @@ +package option + +import ( + "bufio" + "fmt" + "os" + "strconv" + "strings" + "syscall" + + "github.com/cloudberrydb/cbload/log" + "github.com/pkg/errors" + "golang.org/x/term" +) + +const ( + HOST = "host" + PORT = "port" + USER = "user" + DATABASE = "database" + FORCE_PASSWORD_AUTH = "force-password-auth" + TABLE = "table" + TAG = "tag" + DEST_PATH = "dest-path" + INPUT_FILE = "input-file" + TASKS = "tasks" + LOGFILE = "logfile" + STOP_ON_ERROR = "stop-on-error" + VERBOSE = "verbose" +) + +type Option struct { + Host string + Port int + User string + Database string + Password string + ForcePasswordAuth bool + Table string + Tag string + DestPath string + InputFile []string + LogFile string + NumTasks int + StopOnError bool + Verbose bool +} + +func NewOption() *Option { + o := &Option{} + + return o +} + +func (o *Option) Parse() error { + var err error + + o.Host = o.getHostOrDefault(o.Host) + o.Port = o.getPortOrDefault(o.Port) + o.User = o.getUserOrDefault(o.User) + o.Database = o.getDatabaseOrDefault(o.Database) + o.Password, err = o.getPasswordOrDefault(o.ForcePasswordAuth) + if err != nil { + return err + } + + if o.NumTasks > 256 || o.NumTasks < 1 { + return errors.Errorf("Invalid value: \"%v\" for --tasks option, the number of tasks must be in the range of 1 to 256", o.NumTasks) + } + + return nil +} + +func (o *Option) getHostOrDefault(host string) string { + result := host + + if len(result) == 0 { + result = os.Getenv("PGHOST") + } + + if len(result) == 0 { + result = "localhost" + } + + return result +} + +func (o *Option) getPortOrDefault(port int) int { + result := port + + if result == 0 { + p, err := strconv.Atoi(os.Getenv("PGPORT")) + if err == nil { + result = p + } + } + + if result == 0 { + result = 5432 + } + + return result +} + +func (o *Option) getUserOrDefault(user string) string { + result := user + + if len(result) == 0 { + result = os.Getenv("PGUSER") + } + + if len(result) == 0 { + result = os.Getenv("USER") + if len(o.User) == 0 { + result = os.Getenv("LOGNAME") + } + if len(o.User) == 0 { + result = os.Getenv("USERNAME") + } + } + + if len(result) == 0 { + result = "gpadmin" + } + + return result +} + +func (o *Option) getDatabaseOrDefault(database string) string { + result := database + + if len(result) == 0 { + result = os.Getenv("PGDATABASE") + } + + if len(result) == 0 { + result = o.User + } + + return result +} + +func (o *Option) getPasswordOrDefault(forcePasswordAuth bool) (string, error) { + result := "" + var err error + + if forcePasswordAuth { + fmt.Printf("Password: ") + bp, err := term.ReadPassword(int(syscall.Stdin)) + fmt.Printf("\n") + if err != nil { + return result, err + } + result = string(bp) + } + + if len(result) == 0 { + result = os.Getenv("PGPASSWORD") + } + + if len(result) == 0 { + passFile := os.Getenv("PGPASSFILE") + if len(passFile) == 0 { + dir := os.Getenv("HOME") + if len(dir) == 0 { + dir = "." + } + passFile = dir + "/.pgpass" + } + + result, err = o.readPGPass(passFile) + if err != nil { + return result, err + } + } + + return result, nil +} + +func (o *Option) readPGPass(file string) (string, error) { + password := "" + + f, err := os.Open(file) + if err != nil { + log.Logger.Debugf("%v", err) + return password, nil + } + + defer f.Close() + sc := bufio.NewScanner(f) + + for sc.Scan() { + elems := o.splitPGPassLine(sc.Text()) + if len(elems) != 5 { + return password, errors.Errorf("pgpass file: invalid line \"%v\":there should be 5 fields in a line, seperated by colon", sc.Text()) + } + + if elems[0] != "*" && strings.ToLower(elems[0]) != strings.ToLower(o.Host) { + continue + } + + if elems[1] != "*" { + p, err := strconv.Atoi(elems[1]) + + if err != nil { + return password, errors.Errorf("pgpass file: invalid line \"%v\":port number should be integer", sc.Text()) + } + + if p != o.Port { + continue + } + } + + if elems[2] != "*" && elems[2] != o.Database { + continue + } + + if elems[3] != "*" && elems[3] != o.User { + continue + } + + password = elems[4] + break + } + + return password, nil +} + +func (o *Option) splitPGPassLine(line string) []string { + escape := false + results := make([]string, 0) + elem := make([]byte, 0) + bline := []byte(line) + + for _, c := range bline { + if !escape && c == '\\' { + escape = true + } else if !escape && c == ':' { + results = append(results, string(elem)) + elem = make([]byte, 0) + } else { + elem = append(elem, c) + escape = false + } + } + + if escape { + elem = append(elem, '\\') + } + + results = append(results, string(elem)) + + return results +} + +func (o *Option) IsDirectoryMode() (bool, error) { + numDirs := 0 + for _, file := range o.InputFile { + stat, err := os.Stat(file) + if err != nil { + return false, err + } + + if stat.IsDir() { + numDirs++ + } + } + + if len(o.InputFile) == 1 { + if numDirs == 1 { + return true, nil + } + + return false, nil + } + + if numDirs == len(o.InputFile) { + return false, errors.Errorf("Only one directory can be specified") + } + + if numDirs > 0 { + return false, errors.Errorf("File and directory cannot be specified at the same time") + } + + return false, nil +} diff --git a/gpMgmt/bin/cbload/worker/worker.go b/gpMgmt/bin/cbload/worker/worker.go new file mode 100644 index 00000000000..0d0460b7af3 --- /dev/null +++ b/gpMgmt/bin/cbload/worker/worker.go @@ -0,0 +1,168 @@ +package worker + +import ( + "bufio" + "context" + "fmt" + "os" + "sync" + "sync/atomic" + + "github.com/cloudberrydb/cbload/log" + "github.com/jackc/pgconn" +) + +type Worker struct { + context context.Context + cancelContextFunc context.CancelFunc + conn *pgconn.PgConn + id int + localFiles []string + destFiles []string + manager *WorkManager +} + +type WorkManager struct { + sync.Mutex + waitGroup sync.WaitGroup + table string + tag string + conns []*pgconn.PgConn + localFiles [][]string + destFiles [][]string + workers []*Worker + doneCh chan struct{} + quickDieCh chan struct{} + syncCh chan struct{} + numFileSucceed atomic.Uint32 + numFileFailed atomic.Uint32 + stopOnError bool +} + +func NewWorkManager(table, tag string, conns []*pgconn.PgConn, localFiles, destFiles [][]string, stopOnError bool) *WorkManager { + wm := &WorkManager{ + table: table, + tag: tag, + conns: conns, + localFiles: localFiles, + destFiles: destFiles, + stopOnError: stopOnError, + workers: make([]*Worker, len(conns)), + doneCh: make(chan struct{}, 1), + quickDieCh: make(chan struct{}, 1), + syncCh: make(chan struct{}, 1), + } + return wm +} + +func (wm *WorkManager) Start() (chan struct{}, chan struct{}) { + log.Logger.Debug("WorkManager starting...") + numWorkers := len(wm.conns) + + wm.waitGroup.Add(numWorkers) + for i := 0; i < numWorkers; i++ { + wm.workers[i] = newWorker(wm, i, wm.conns[i], wm.localFiles[i], wm.destFiles[i]) + go wm.workers[i].Run() + } + + go func() { + wm.waitGroup.Wait() + log.Logger.Debug("All workers have completed") + wm.syncCh <- struct{}{} + wm.doneCh <- struct{}{} + log.Logger.Debug("The main thread has already been notified") + }() + + return wm.doneCh, wm.quickDieCh +} + +func (wm *WorkManager) GetNumSucceedFiles() uint32 { + return wm.numFileSucceed.Load() +} + +func (wm *WorkManager) GetNumFailedFiles() uint32 { + return wm.numFileFailed.Load() +} + +func (wm *WorkManager) Stop() { + log.Logger.Debug("WorkManager stopping...") + + numWorkers := len(wm.conns) + for i := 0; i < numWorkers; i++ { + wm.workers[i].Stop() + } + + <-wm.syncCh + log.Logger.Debug("WorkManager stopped") +} + +func newWorker(manager *WorkManager, id int, conn *pgconn.PgConn, localFiles, destFiles []string) *Worker { + ctx, cancelFunc := context.WithCancel(context.Background()) + worker := &Worker{ctx, cancelFunc, conn, id, localFiles, destFiles, manager} + return worker +} + +func (w *Worker) Run() { + defer w.manager.waitGroup.Done() + + log.Logger.Debugf("Worker [%v]: started", w.id) + +loop: + for i, file := range w.localFiles { + fh, err := os.Open(file) + if err != nil { + if w.handleError("unable to open file", file, err) { + break + } + continue + } + + log.Logger.Infof("Worker [%v]: loading file \"%v\" into \"%v:%v\"...", w.id, file, w.manager.table, w.destFiles[i]) + + _, err = w.conn.CopyFrom(w.context, + bufio.NewReader(fh), + w.formCopyStatement(w.destFiles[i])) + if err != nil { + if w.handleError("unable to upload file", file, err) { + break + } + continue + } + + w.manager.numFileSucceed.Add(1) + fh.Close() + log.Logger.Infof("Worker [%v]: successfully loaded", w.id) + + select { + case <-w.context.Done(): + break loop + default: + } + } + + log.Logger.Debugf("Worker [%v]: stopped", w.id) +} + +func (w *Worker) handleError(title, file string, err error) bool { + w.manager.numFileFailed.Add(1) + log.Logger.Errorf("Worker [%v]: %v \"%v\": %v", w.id, title, file, err) + if w.manager.stopOnError { + w.manager.quickDieCh <- struct{}{} + return true + } + + return false +} + +func (w *Worker) formCopyStatement(file string) string { + if len(w.manager.tag) == 0 { + return fmt.Sprintf("copy binary %s from stdin '%s';", w.manager.table, file) + } + + return fmt.Sprintf("copy binary %s from stdin '%s' with tag '%s';", w.manager.table, file, w.manager.tag) +} + +func (w *Worker) Stop() { + log.Logger.Debugf("Worker [%v]: stopping...", w.id) + w.cancelContextFunc() +} diff --git a/gpMgmt/bin/gpcheckcat b/gpMgmt/bin/gpcheckcat index b1e43728f14..ea8ed134180 100755 --- a/gpMgmt/bin/gpcheckcat +++ b/gpMgmt/bin/gpcheckcat @@ -1579,6 +1579,10 @@ def checkTableInconsistentEntry(cat): columns.remove("passhistpasswordsetat") castcols.remove("passhistpasswordsetat") + if catname == "pg_directory_table": + columns.remove("dtlocation") + castcols.remove("dtlocation") + if cat.tableHasConsistentOids(): qry = inconsistentEntryQuery(GV.max_content, catname, ['oid'], columns, castcols) else: @@ -2926,7 +2930,7 @@ class GPObject: # Report missing issues if len(self.missingIssues): - omitlist = ['pg_attribute', 'pg_attribute_encoding', 'pg_type', 'pg_appendonly', 'pg_index', 'pg_password_history'] + omitlist = ['pg_attribute', 'pg_attribute_encoding', 'pg_type', 'pg_appendonly', 'pg_index', 'pg_password_history', 'pg_directory_table'] if 'pg_class' in self.missingIssues: myprint(' Name of test which found this issue: missing_extraneous_pg_class') for name in omitlist: diff --git a/gpcontrib/gp_distribution_policy/gp_distribution_policy.c b/gpcontrib/gp_distribution_policy/gp_distribution_policy.c index 506f7aab7f2..04a79963625 100644 --- a/gpcontrib/gp_distribution_policy/gp_distribution_policy.c +++ b/gpcontrib/gp_distribution_policy/gp_distribution_policy.c @@ -62,7 +62,8 @@ gp_distribution_policy_table_check(PG_FUNCTION_ARGS) /* Validate that the relation is a table */ if (rel->rd_rel->relkind != RELKIND_RELATION && - rel->rd_rel->relkind != RELKIND_MATVIEW) + rel->rd_rel->relkind != RELKIND_MATVIEW && + rel->rd_rel->relkind != RELKIND_DIRECTORY_TABLE) { ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), diff --git a/src/backend/access/aocs/aocsam_handler.c b/src/backend/access/aocs/aocsam_handler.c index a310138cded..995d69ee712 100644 --- a/src/backend/access/aocs/aocsam_handler.c +++ b/src/backend/access/aocs/aocsam_handler.c @@ -1267,7 +1267,8 @@ aoco_relation_set_new_filenode(Relation rel, { Assert(rel->rd_rel->relkind == RELKIND_RELATION || rel->rd_rel->relkind == RELKIND_MATVIEW || - rel->rd_rel->relkind == RELKIND_TOASTVALUE); + rel->rd_rel->relkind == RELKIND_TOASTVALUE || + rel->rd_rel->relkind == RELKIND_DIRECTORY_TABLE); smgrcreate(srel, INIT_FORKNUM, false); log_smgrcreate(newrnode, INIT_FORKNUM, SMGR_AO); smgrimmedsync(srel, INIT_FORKNUM); diff --git a/src/backend/access/appendonly/appendonlyam_handler.c b/src/backend/access/appendonly/appendonlyam_handler.c index fea0028596b..c1d63e8e071 100644 --- a/src/backend/access/appendonly/appendonlyam_handler.c +++ b/src/backend/access/appendonly/appendonlyam_handler.c @@ -1142,6 +1142,7 @@ appendonly_relation_set_new_filenode(Relation rel, { Assert(rel->rd_rel->relkind == RELKIND_RELATION || rel->rd_rel->relkind == RELKIND_MATVIEW || + rel->rd_rel->relkind == RELKIND_DIRECTORY_TABLE || rel->rd_rel->relkind == RELKIND_TOASTVALUE); smgrcreate(srel, INIT_FORKNUM, false); log_smgrcreate(newrnode, INIT_FORKNUM, SMGR_AO); diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 0f3a1ed6bf4..fc9edaf7f7c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -166,6 +166,15 @@ static relopt_bool boolRelOpts[] = }, true }, + { + { + "stage", + "Declare a tablespace as a dfs staged tablespace", + RELOPT_KIND_TABLESPACE, + AccessExclusiveLock + }, + false + }, /* list terminator */ {{NULL}} }; @@ -546,6 +555,24 @@ static relopt_enum enumRelOpts[] = static relopt_string stringRelOpts[] = { + { + { + "server", + "the server used by the dfs tablespace", + RELOPT_KIND_TABLESPACE, + AccessExclusiveLock + }, + 0, true, NULL, NULL, NULL + }, + { + { + "path", + "the path of the dfs tablespace", + RELOPT_KIND_TABLESPACE, + AccessExclusiveLock + }, + 0, true, NULL, NULL, NULL + }, /* list terminator */ {{NULL}} }; @@ -1403,6 +1430,7 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc, case RELKIND_RELATION: case RELKIND_TOASTVALUE: case RELKIND_MATVIEW: + case RELKIND_DIRECTORY_TABLE: options = table_reloptions((tamoptions_function)amoptions, datum, classForm->relkind, false); break; case RELKIND_PARTITIONED_TABLE: @@ -2028,6 +2056,7 @@ bytea * table_reloptions(tamoptions_function amoptions, Datum reloptions, char relkind, bool validate) { Assert(relkind == RELKIND_RELATION || + relkind == RELKIND_DIRECTORY_TABLE || relkind == RELKIND_TOASTVALUE || relkind == RELKIND_MATVIEW); if (amoptions == NULL) @@ -2098,7 +2127,10 @@ tablespace_reloptions(Datum reloptions, bool validate) {"random_page_cost", RELOPT_TYPE_REAL, offsetof(TableSpaceOpts, random_page_cost)}, {"seq_page_cost", RELOPT_TYPE_REAL, offsetof(TableSpaceOpts, seq_page_cost)}, {"effective_io_concurrency", RELOPT_TYPE_INT, offsetof(TableSpaceOpts, effective_io_concurrency)}, - {"maintenance_io_concurrency", RELOPT_TYPE_INT, offsetof(TableSpaceOpts, maintenance_io_concurrency)} + {"maintenance_io_concurrency", RELOPT_TYPE_INT, offsetof(TableSpaceOpts, maintenance_io_concurrency)}, + {"stage", RELOPT_TYPE_BOOL, offsetof(TableSpaceOpts, stage)}, + {"server", RELOPT_TYPE_STRING, offsetof(TableSpaceOpts, serverOffset)}, + {"path", RELOPT_TYPE_STRING, offsetof(TableSpaceOpts, pathOffset)} }; return (bytea *) build_reloptions(reloptions, validate, diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c index c7b8fb0e86b..1f03527353f 100644 --- a/src/backend/access/heap/heapam_handler.c +++ b/src/backend/access/heap/heapam_handler.c @@ -621,6 +621,7 @@ heapam_relation_set_new_filenode(Relation rel, { Assert(rel->rd_rel->relkind == RELKIND_RELATION || rel->rd_rel->relkind == RELKIND_MATVIEW || + rel->rd_rel->relkind == RELKIND_DIRECTORY_TABLE || rel->rd_rel->relkind == RELKIND_TOASTVALUE || rel->rd_rel->relkind == RELKIND_AOSEGMENTS || rel->rd_rel->relkind == RELKIND_AOVISIMAP || diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile index e8b1560acc8..c3ccbdc18e4 100644 --- a/src/backend/catalog/Makefile +++ b/src/backend/catalog/Makefile @@ -52,7 +52,8 @@ OBJS += pg_extprotocol.o \ pg_appendonly.o \ oid_dispatch.o aocatalog.o storage_tablespace.o storage_database.o \ storage_tablespace_twophase.o storage_tablespace_xact.o \ - gp_partition_template.o pg_task.o pg_task_run_history.o + gp_partition_template.o pg_task.o pg_task_run_history.o \ + pg_directory_table.o storage_directory_table.o CATALOG_JSON:= $(addprefix $(top_srcdir)/gpMgmt/bin/gppylib/data/, $(addsuffix .json,$(GP_MAJORVERSION))) @@ -92,7 +93,8 @@ CATALOG_HEADERS := \ pg_collation.h pg_partitioned_table.h pg_range.h pg_transform.h \ pg_sequence.h pg_publication.h pg_publication_rel.h pg_subscription.h \ pg_subscription_rel.h gp_partition_template.h pg_task.h pg_task_run_history.h \ - pg_profile.h pg_password_history.h + pg_profile.h pg_password_history.h pg_directory_table.h gp_storage_server.h \ + gp_storage_user_mapping.h USE_INTERNAL_FTS_FOUND := $(if $(findstring USE_INTERNAL_FTS,$(CFLAGS)),true,false) diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index 066f8c75d63..c579dbffc52 100644 --- a/src/backend/catalog/aclchk.c +++ b/src/backend/catalog/aclchk.c @@ -27,6 +27,7 @@ #include "catalog/binary_upgrade.h" #include "catalog/catalog.h" #include "catalog/dependency.h" +#include "catalog/gp_storage_server.h" #include "catalog/heap.h" #include "catalog/indexing.h" #include "catalog/objectaccess.h" @@ -270,6 +271,9 @@ restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs, case OBJECT_FOREIGN_SERVER: whole_mask = ACL_ALL_RIGHTS_FOREIGN_SERVER; break; + case OBJECT_STORAGE_SERVER: + whole_mask = ACL_ALL_RIGHTS_STORAGE_SERVER; + break; case OBJECT_EVENT_TRIGGER: elog(ERROR, "grantable rights not supported for event triggers"); /* not reached, but keep compiler quiet */ @@ -528,6 +532,10 @@ ExecuteGrantStmt(GrantStmt *stmt) all_privileges = ACL_ALL_RIGHTS_FOREIGN_SERVER; errormsg = gettext_noop("invalid privilege type %s for foreign server"); break; + case OBJECT_STORAGE_SERVER: + all_privileges = ACL_ALL_RIGHTS_STORAGE_SERVER; + errormsg = gettext_noop("invalid privilege type %s from storage server"); + break; case OBJECT_EXTPROTOCOL: all_privileges = ACL_ALL_RIGHTS_EXTPROTOCOL; errormsg = gettext_noop("invalid privilege type %s for external protocol"); @@ -922,6 +930,8 @@ objectsInSchemaToOids(ObjectType objtype, List *nspnames) objects = list_concat(objects, objs); objs = getRelationsInNamespace(namespaceId, RELKIND_PARTITIONED_TABLE); objects = list_concat(objects, objs); + objs = getRelationsInNamespace(namespaceId, RELKIND_DIRECTORY_TABLE); + objects = list_concat(objects, objs); break; case OBJECT_SEQUENCE: objs = getRelationsInNamespace(namespaceId, RELKIND_SEQUENCE); @@ -3691,6 +3701,9 @@ aclcheck_error(AclResult aclerr, ObjectType objtype, case OBJECT_DOMAIN: msg = gettext_noop("permission denied for domain %s"); break; + case OBJECT_DIRECTORY_TABLE: + msg = gettext_noop("permission denied for directory table %s"); + break; case OBJECT_EVENT_TRIGGER: msg = gettext_noop("permission denied for event trigger %s"); break; @@ -3751,6 +3764,9 @@ aclcheck_error(AclResult aclerr, ObjectType objtype, case OBJECT_STATISTIC_EXT: msg = gettext_noop("permission denied for statistics object %s"); break; + case OBJECT_STORAGE_SERVER: + msg = gettext_noop("permission denied for storage server %s"); + break; case OBJECT_SUBSCRIPTION: msg = gettext_noop("permission denied for subscription %s"); break; @@ -3796,6 +3812,7 @@ aclcheck_error(AclResult aclerr, ObjectType objtype, case OBJECT_TSTEMPLATE: case OBJECT_USER_MAPPING: case OBJECT_PROFILE: + case OBJECT_STORAGE_USER_MAPPING: elog(ERROR, "unsupported object type %d", objtype); } @@ -3825,6 +3842,9 @@ aclcheck_error(AclResult aclerr, ObjectType objtype, case OBJECT_DOMAIN: msg = gettext_noop("must be owner of domain %s"); break; + case OBJECT_DIRECTORY_TABLE: + msg = gettext_noop("must be owner of directory table %s"); + break; case OBJECT_EVENT_TRIGGER: msg = gettext_noop("must be owner of event trigger %s"); break; @@ -3938,6 +3958,8 @@ aclcheck_error(AclResult aclerr, ObjectType objtype, case OBJECT_TSTEMPLATE: case OBJECT_USER_MAPPING: case OBJECT_PROFILE: + case OBJECT_STORAGE_SERVER: + case OBJECT_STORAGE_USER_MAPPING: elog(ERROR, "unsupported object type %d", objtype); } @@ -4828,6 +4850,65 @@ pg_foreign_server_aclmask(Oid srv_oid, Oid roleid, return result; } +/* + * Exported routine for examining a user's privileges for a storage + * server. + */ +AclMode +gp_storage_server_aclmask(Oid srv_oid, Oid roleid, + AclMode mask, AclMaskHow how) +{ + AclMode result; + HeapTuple tuple; + Datum aclDatum; + bool isNull; + Acl *acl; + Oid ownerId; + + Form_gp_storage_server srvForm; + + /* Bypass permission checks for superusers */ + if (superuser_arg(roleid)) + return mask; + + tuple = SearchSysCache1(STORAGESERVEROID, ObjectIdGetDatum(srv_oid)); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("storage server with OID %u does not exist", + srv_oid))); + srvForm = (Form_gp_storage_server) GETSTRUCT(tuple); + + /* + * Normal case: get the storage server's ACL from gp_storage_server + */ + ownerId = srvForm->srvowner; + + aclDatum = SysCacheGetAttr(STORAGESERVEROID, tuple, + Anum_gp_storage_server_srvacl, &isNull); + if (isNull) + { + /* No ACL, so build default ACL */ + acl = acldefault(OBJECT_STORAGE_SERVER, ownerId); + aclDatum = (Datum) 0; + } + else + { + /* detoast rel's ACL if necessary */ + acl = DatumGetAclP(aclDatum); + } + + result = aclmask(acl, roleid, ownerId, mask, how); + + /* if we have a detoasted copy, free it */ + if (acl && (Pointer) acl != DatumGetPointer(aclDatum)) + pfree(acl); + + ReleaseSysCache(tuple); + + return result; +} + /* * Exported routine for examining a user's privileges for a type. */ @@ -5245,6 +5326,19 @@ pg_foreign_server_aclcheck(Oid srv_oid, Oid roleid, AclMode mode) return ACLCHECK_NO_PRIV; } +/* + * Exported routine for checking a user's access privileges to a storage + * server + */ +AclResult +gp_storage_server_aclcheck(Oid srv_oid, Oid roleid, AclMode mode) +{ + if (gp_storage_server_aclmask(srv_oid, roleid, mode, ACLMASK_ANY) != 0) + return ACLCHECK_OK; + else + return ACLCHECK_NO_PRIV; +} + /* * Exported routine for checking a user's access privileges to a type */ @@ -5661,6 +5755,33 @@ pg_foreign_server_ownercheck(Oid srv_oid, Oid roleid) return has_privs_of_role(roleid, ownerId); } +/* + * Ownership check for a storage server (specified by OID). + */ +bool +gp_storage_server_ownercheck(Oid srv_oid, Oid roleid) +{ + HeapTuple tuple; + Oid ownerId; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(roleid)) + return true; + + tuple = SearchSysCache1(STORAGESERVEROID, ObjectIdGetDatum(srv_oid)); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("storage server with OID %u does not exist", + srv_oid))); + + ownerId = ((Form_gp_storage_server) GETSTRUCT(tuple))->srvowner; + + ReleaseSysCache(tuple); + + return has_privs_of_role(roleid, ownerId); +} + /* * Ownership check for an event trigger (specified by OID). */ @@ -6679,6 +6800,7 @@ CopyRelationAcls(Oid srcId, Oid destId) if (pg_class_tuple->relkind != RELKIND_RELATION && pg_class_tuple->relkind != RELKIND_PARTITIONED_TABLE && + pg_class_tuple->relkind != RELKIND_DIRECTORY_TABLE && pg_class_tuple->relkind != RELKIND_FOREIGN_TABLE) elog(ERROR, "unexpected relkind %c", pg_class_tuple->relkind); diff --git a/src/backend/catalog/catalog.c b/src/backend/catalog/catalog.c index 81b9ebf44ba..8c4c7023921 100644 --- a/src/backend/catalog/catalog.c +++ b/src/backend/catalog/catalog.c @@ -58,6 +58,8 @@ #include "catalog/gp_configuration_history.h" #include "catalog/gp_id.h" +#include "catalog/gp_storage_server.h" +#include "catalog/gp_storage_user_mapping.h" #include "catalog/gp_version_at_initdb.h" #include "catalog/gp_warehouse.h" #include "catalog/pg_event_trigger.h" @@ -439,6 +441,9 @@ IsSharedRelation(Oid relationId) #endif relationId == AuthTimeConstraintRelationId || + relationId == StorageUserMappingRelationId || + relationId == StorageServerRelationId || + relationId == ProfileRelationId || relationId == PasswordHistoryRelationId) return true; @@ -486,6 +491,10 @@ IsSharedRelation(Oid relationId) #endif relationId == AuthTimeConstraintAuthIdIndexId || relationId == AuthIdRolProfileIndexId || + relationId == StorageUserMappingOidIndexId || + relationId == StorageUserMappingServerIndexId || + relationId == StorageServerOidIndexId || + relationId == StorageServerNameIndexId || relationId == ProfilePrfnameIndexId || relationId == ProfileOidIndexId || relationId == ProfileVerifyFunctionIndexId || @@ -524,6 +533,13 @@ IsSharedRelation(Oid relationId) } #endif + /* GPDB added toast tables and toast indexes */ + if (relationId == GpStorageUserMappingToastTable || + relationId == GpStorageUserMappingToastIndex || + relationId == GpStorageServerToastTable || + relationId == GpStorageServerToastIndex) + return true; + /* GPDB added task tables and their indexes */ if (relationId == TaskRelationId || relationId == TaskJobNameUserNameIndexId || diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index d9f5ac7e23d..6be702e488b 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -20,6 +20,8 @@ #include "access/table.h" #include "access/xact.h" #include "catalog/dependency.h" +#include "catalog/gp_storage_server.h" +#include "catalog/gp_storage_user_mapping.h" #include "catalog/heap.h" #include "catalog/index.h" #include "catalog/namespace.h" @@ -36,6 +38,7 @@ #include "catalog/pg_database.h" #include "catalog/pg_default_acl.h" #include "catalog/pg_depend.h" +#include "catalog/pg_directory_table.h" #include "catalog/pg_event_trigger.h" #include "catalog/pg_extension.h" #include "catalog/pg_foreign_data_wrapper.h" @@ -202,6 +205,9 @@ static const Oid object_classes[] = { /* GPDB additions */ ProfileRelationId, /* OCLASS_PROFILE */ PasswordHistoryRelationId, /* OCLASS_PASSWORDHISTORY */ + DirectoryTableRelationId, /* OCLASS_DIRECTORY_TABLE */ + StorageServerRelationId, /* OCLASS_STORAGE_SERVER */ + StorageUserMappingRelationId, /* OCLASS_STORAGE_USER_MAPPING */ ExtprotocolRelationId, /* OCLASS_EXTPROTOCOL */ TaskRelationId /* OCLASS_TASK */ }; @@ -1579,6 +1585,8 @@ doDeletion(const ObjectAddress *object, int flags) case OCLASS_SUBSCRIPTION: case OCLASS_PROFILE: case OCLASS_PASSWORDHISTORY: + case OCLASS_STORAGE_SERVER: + case OCLASS_STORAGE_USER_MAPPING: elog(ERROR, "global objects cannot be deleted by doDeletion"); break; @@ -2970,6 +2978,15 @@ getObjectClass(const ObjectAddress *object) case TaskRelationId: return OCLASS_TASK; + case DirectoryTableRelationId: + return OCLASS_DIRTABLE; + + case StorageServerRelationId: + return OCLASS_STORAGE_SERVER; + + case StorageUserMappingRelationId: + return OCLASS_STORAGE_USER_MAPPING; + default: { struct CustomObjectClass *coc; diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 57b4de0ad90..3183d113696 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -60,6 +60,7 @@ #include "catalog/pg_collation.h" #include "catalog/pg_constraint.h" #include "catalog/pg_database.h" +#include "catalog/pg_directory_table.h" #include "catalog/pg_foreign_table.h" #include "catalog/pg_inherits.h" #include "catalog/pg_namespace.h" @@ -70,6 +71,7 @@ #include "catalog/pg_tablespace.h" #include "catalog/pg_type.h" #include "catalog/storage.h" +#include "catalog/storage_directory_table.h" #include "catalog/storage_xlog.h" #include "commands/tablecmds.h" #include "commands/typecmds.h" @@ -485,6 +487,7 @@ heap_create(const char *relname, case RELKIND_RELATION: case RELKIND_TOASTVALUE: case RELKIND_MATVIEW: + case RELKIND_DIRECTORY_TABLE: table_relation_set_new_filenode(rel, &rel->rd_node, relpersistence, relfrozenxid, relminmxid); @@ -1365,6 +1368,7 @@ AddNewRelationTuple(Relation pg_class_desc, case RELKIND_AOSEGMENTS: case RELKIND_AOBLOCKDIR: case RELKIND_AOVISIMAP: + case RELKIND_DIRECTORY_TABLE: /* The relation is real, but as yet empty */ new_rel_reltup->relpages = 0; new_rel_reltup->reltuples = -1; @@ -1599,6 +1603,7 @@ heap_create_with_catalog(const char *relname, case RELKIND_MATVIEW: case RELKIND_FOREIGN_TABLE: case RELKIND_PARTITIONED_TABLE: + case RELKIND_DIRECTORY_TABLE: relacl = get_user_default_acl(OBJECT_TABLE, ownerid, relnamespace); break; @@ -1852,6 +1857,7 @@ heap_create_with_catalog(const char *relname, * main table depends on it. */ if (relkind == RELKIND_RELATION || + relkind == RELKIND_DIRECTORY_TABLE || relkind == RELKIND_MATVIEW) { ObjectAddressSet(referenced, AccessMethodRelationId, accessmtd); @@ -1894,6 +1900,7 @@ heap_create_with_catalog(const char *relname, Assert(relkind == RELKIND_RELATION || relkind == RELKIND_PARTITIONED_TABLE || + relkind == RELKIND_DIRECTORY_TABLE || relkind == RELKIND_MATVIEW || relkind == RELKIND_FOREIGN_TABLE); @@ -1925,6 +1932,9 @@ heap_create_with_catalog(const char *relname, case RELKIND_MATVIEW: subtyp = "MATVIEW"; break; + case RELKIND_DIRECTORY_TABLE: + subtyp = "DIRECTORY TABLE"; + break; default: doIt = false; } @@ -2468,6 +2478,15 @@ heap_drop_with_catalog(Oid relid) if (relid == defaultPartOid) update_default_partition_oid(parentOid, InvalidOid); + /* + * Remove entry in pg_directory_table + */ + if (rel->rd_rel->relkind == RELKIND_DIRECTORY_TABLE) + { + RemoveDirectoryTableEntry(relid); + DirectoryTableDropStorage(rel); + } + /* * Schedule unlinking of the relation's physical files at commit. */ @@ -2480,6 +2499,7 @@ heap_drop_with_catalog(Oid relid) if (rel->rd_rel->relkind == RELKIND_RELATION || rel->rd_rel->relkind == RELKIND_MATVIEW || rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE || + rel->rd_rel->relkind == RELKIND_DIRECTORY_TABLE || rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) { GpPolicyRemove(relid); @@ -2489,6 +2509,7 @@ heap_drop_with_catalog(Oid relid) * Attribute encoding */ if (rel->rd_rel->relkind == RELKIND_RELATION || + rel->rd_rel->relkind == RELKIND_DIRECTORY_TABLE || rel->rd_rel->relkind == RELKIND_MATVIEW || rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) { diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index fb0fd99dda0..852af0f6759 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -22,6 +22,8 @@ #include "access/sysattr.h" #include "access/table.h" #include "catalog/catalog.h" +#include "catalog/gp_storage_server.h" +#include "catalog/gp_storage_user_mapping.h" #include "catalog/objectaddress.h" #include "catalog/pg_am.h" #include "catalog/pg_amop.h" @@ -76,6 +78,7 @@ #include "commands/proclang.h" #include "commands/queue.h" #include "commands/resgroupcmds.h" +#include "commands/storagecmds.h" #include "commands/tablespace.h" #include "commands/trigger.h" #include "foreign/foreign.h" @@ -297,6 +300,20 @@ static const ObjectPropertyType ObjectProperty[] = OBJECT_FOREIGN_SERVER, true }, + { + "storage server", + StorageServerRelationId, + StorageServerOidIndexId, + STORAGESERVEROID, + STORAGESERVERNAME, + Anum_gp_storage_server_oid, + Anum_gp_storage_server_srvname, + InvalidAttrNumber, + Anum_gp_storage_server_srvowner, + Anum_gp_storage_server_srvacl, + OBJECT_STORAGE_SERVER, + true + }, { "function", ProcedureRelationId, @@ -655,6 +672,20 @@ static const ObjectPropertyType ObjectProperty[] = OBJECT_USER_MAPPING, false }, + { + "storage user mapping", + StorageUserMappingRelationId, + StorageUserMappingOidIndexId, + STORAGEUSERMAPPINGOID, + -1, + Anum_gp_storage_user_mapping_oid, + InvalidAttrNumber, + InvalidAttrNumber, + InvalidAttrNumber, + InvalidAttrNumber, + OBJECT_STORAGE_USER_MAPPING, + false + }, /* GPDB additions */ { @@ -899,6 +930,18 @@ static const struct object_type_map /* OCLASS_PROFILE */ { "profile", OBJECT_PROFILE + }, + /* OCLASS_DIRECTORY_TABLE */ + { + "directory table", OBJECT_DIRECTORY_TABLE + }, + /* OCLASS_STORAGE_SERVER */ + { + "storage server", OBJECT_STORAGE_SERVER + }, + /* OCLASS_STORAGE_USER_MAPPING */ + { + "storage user mapping", OBJECT_STORAGE_USER_MAPPING } }; @@ -1014,6 +1057,7 @@ get_object_address(ObjectType objtype, Node *object, case OBJECT_VIEW: case OBJECT_MATVIEW: case OBJECT_FOREIGN_TABLE: + case OBJECT_DIRECTORY_TABLE: address = get_relation_by_qualified_name(objtype, castNode(List, object), &relation, lockmode, @@ -1073,6 +1117,8 @@ get_object_address(ObjectType objtype, Node *object, case OBJECT_RESQUEUE: case OBJECT_RESGROUP: case OBJECT_PROFILE: + case OBJECT_STORAGE_SERVER: + case OBJECT_STORAGE_USER_MAPPING: address = get_object_address_unqualified(objtype, (Value *) object, missing_ok); break; @@ -1397,6 +1443,11 @@ get_object_address_unqualified(ObjectType objtype, address.objectId = get_profile_oid(name, missing_ok); address.objectSubId = 0; break; + case OBJECT_STORAGE_SERVER: + address.classId = StorageServerRelationId; + address.objectId = get_storage_server_oid(name, missing_ok); + address.objectSubId = 0; + break; default: elog(ERROR, "unrecognized objtype: %d", (int) objtype); /* placate compiler, which doesn't know elog won't return */ @@ -1453,6 +1504,13 @@ get_relation_by_qualified_name(ObjectType objtype, List *object, errmsg("\"%s\" is not a table", RelationGetRelationName(relation)))); break; + case OBJECT_DIRECTORY_TABLE: + if (relation->rd_rel->relkind != RELKIND_DIRECTORY_TABLE) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("\"%s\" is not a directory table", + RelationGetRelationName(relation)))); + break; case OBJECT_VIEW: if (relation->rd_rel->relkind != RELKIND_VIEW) ereport(ERROR, @@ -2289,6 +2347,7 @@ pg_get_object_address(PG_FUNCTION_ARGS) case OBJECT_DOMCONSTRAINT: case OBJECT_CAST: case OBJECT_USER_MAPPING: + case OBJECT_STORAGE_USER_MAPPING: case OBJECT_PUBLICATION_REL: case OBJECT_DEFACL: case OBJECT_TRANSFORM: @@ -2350,6 +2409,7 @@ pg_get_object_address(PG_FUNCTION_ARGS) case OBJECT_TABCONSTRAINT: case OBJECT_OPCLASS: case OBJECT_OPFAMILY: + case OBJECT_DIRECTORY_TABLE: objnode = (Node *) name; break; case OBJECT_ACCESS_METHOD: @@ -2358,6 +2418,7 @@ pg_get_object_address(PG_FUNCTION_ARGS) case OBJECT_EXTENSION: case OBJECT_FDW: case OBJECT_FOREIGN_SERVER: + case OBJECT_STORAGE_SERVER: case OBJECT_LANGUAGE: case OBJECT_PUBLICATION: case OBJECT_ROLE: @@ -2389,6 +2450,9 @@ pg_get_object_address(PG_FUNCTION_ARGS) case OBJECT_USER_MAPPING: objnode = (Node *) list_make2(linitial(name), linitial(args)); break; + case OBJECT_STORAGE_USER_MAPPING: + objnode = (Node *) list_make2(linitial(name), linitial(args)); + break; case OBJECT_DEFACL: objnode = (Node *) lcons(linitial(args), name); break; @@ -2458,6 +2522,7 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address, case OBJECT_INDEX: case OBJECT_SEQUENCE: case OBJECT_TABLE: + case OBJECT_DIRECTORY_TABLE: case OBJECT_VIEW: case OBJECT_MATVIEW: case OBJECT_FOREIGN_TABLE: @@ -2547,6 +2612,11 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address, aclcheck_error(ACLCHECK_NOT_OWNER, objtype, strVal((Value *) object)); break; + case OBJECT_STORAGE_SERVER: + if (!gp_storage_server_ownercheck(address.objectId, roleid)) + aclcheck_error(ACLCHECK_NOT_OWNER, objtype, + strVal((Value *) object)); + break; case OBJECT_EVENT_TRIGGER: if (!pg_event_trigger_ownercheck(address.objectId, roleid)) aclcheck_error(ACLCHECK_NOT_OWNER, objtype, @@ -4080,6 +4150,50 @@ getObjectDescription(const ObjectAddress *object, bool missing_ok) break; } + case OCLASS_STORAGE_SERVER: + { + StorageServer *srv; + + srv = GetStorageServerExtended(object->objectId, missing_ok); + if (srv) + appendStringInfo(&buffer, _("storage server %s"), srv->servername); + break; + } + + case OCLASS_STORAGE_USER_MAPPING: + { + HeapTuple tup; + Oid useid; + char *usename; + Form_gp_storage_user_mapping umform; + StorageServer *srv; + + tup = SearchSysCache1(STORAGEUSERMAPPINGOID, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "cache lookup failed for storage user mapping %u", + object->objectId); + break; + } + + umform = (Form_gp_storage_user_mapping) GETSTRUCT(tup); + useid = umform->umuser; + srv = GetStorageServer(umform->umserver); + + ReleaseSysCache(tup); + + if (OidIsValid(useid)) + usename = GetUserNameFromId(useid, false); + else + usename = "public"; + + appendStringInfo(&buffer, _("storage user mapping for %s on storage server %s"), usename, + srv->servername); + break; + } + default: { struct CustomObjectClass *coc; @@ -4150,6 +4264,10 @@ getRelationDescription(StringInfo buffer, Oid relid, bool missing_ok) appendStringInfo(buffer, _("table %s"), relname); break; + case RELKIND_DIRECTORY_TABLE: + appendStringInfo(buffer, _("directory table %s"), + relname); + break; case RELKIND_INDEX: case RELKIND_PARTITIONED_INDEX: appendStringInfo(buffer, _("index %s"), @@ -4659,6 +4777,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "password_history"); break; + case OCLASS_DIRTABLE: + appendStringInfoString(&buffer, "directory table"); + break; + + case OCLASS_STORAGE_SERVER: + appendStringInfoString(&buffer, "storage server"); + break; + + case OCLASS_STORAGE_USER_MAPPING: + appendStringInfoString(&buffer, "storage user mapping"); + break; + default: { struct CustomObjectClass *coc; @@ -4709,6 +4839,9 @@ getRelationTypeDescription(StringInfo buffer, Oid relid, int32 objectSubId, case RELKIND_PARTITIONED_TABLE: appendStringInfoString(buffer, "table"); break; + case RELKIND_DIRECTORY_TABLE: + appendStringInfoString(buffer, "directory table"); + break; case RELKIND_INDEX: case RELKIND_PARTITIONED_INDEX: appendStringInfoString(buffer, "index"); @@ -5648,6 +5781,24 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case OCLASS_STORAGE_SERVER: + { + StorageServer *srv; + + srv = GetStorageServerExtended(object->objectId, + missing_ok); + + if (srv) + { + appendStringInfoString(&buffer, + quote_identifier(srv->servername)); + + if (objname) + *objname = list_make1(pstrdup(srv->servername)); + } + break; + } + case OCLASS_USER_MAPPING: { HeapTuple tup; @@ -5688,6 +5839,46 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case OCLASS_STORAGE_USER_MAPPING: + { + HeapTuple tup; + Oid useid; + Form_gp_storage_user_mapping umform; + StorageServer *srv; + const char *usename; + + tup = SearchSysCache1(STORAGEUSERMAPPINGOID, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "cache lookup failed for storage user mapping %u", + object->objectId); + break; + } + umform = (Form_gp_storage_user_mapping) GETSTRUCT(tup); + useid = umform->umuser; + srv = GetStorageServer(umform->umserver); + + ReleaseSysCache(tup); + + if (OidIsValid(useid)) + usename = GetUserNameFromId(useid, false); + else + usename = "public"; + + if (objname) + { + *objname = list_make1(pstrdup(usename)); + *objargs = list_make1(pstrdup(srv->servername)); + } + + appendStringInfo(&buffer, "%s on storage server %s", + quote_identifier(usename), + srv->servername); + break; + } + case OCLASS_DEFACL: { Relation defaclrel; @@ -6200,6 +6391,8 @@ get_relkind_objtype(char relkind) return OBJECT_FOREIGN_TABLE; case RELKIND_TOASTVALUE: return OBJECT_TABLE; + case RELKIND_DIRECTORY_TABLE: + return OBJECT_DIRECTORY_TABLE; default: /* Per above, don't raise an error */ return OBJECT_TABLE; diff --git a/src/backend/catalog/oid_dispatch.c b/src/backend/catalog/oid_dispatch.c index fe7bf12a8f2..01c95a4644a 100644 --- a/src/backend/catalog/oid_dispatch.c +++ b/src/backend/catalog/oid_dispatch.c @@ -81,6 +81,8 @@ #include "catalog/catalog.h" #include "catalog/indexing.h" +#include "catalog/gp_storage_server.h" +#include "catalog/gp_storage_user_mapping.h" #include "catalog/pg_am.h" #include "catalog/pg_amop.h" #include "catalog/pg_amproc.h" @@ -778,6 +780,23 @@ GetNewOidForForeignServer(Relation relation, Oid indexId, AttrNumber oidcolumn, } +Oid +GetNewOidForStorageServer(Relation relation, Oid indexId, AttrNumber oidcolumn, + char *srvname) +{ + OidAssignment key; + + Assert(RelationGetRelid(relation) == StorageServerRelationId); + Assert(indexId == StorageServerOidIndexId); + Assert(oidcolumn == Anum_gp_storage_server_oid); + + memset(&key, 0, sizeof(OidAssignment)); + key.type = T_OidAssignment; + key.objname = srvname; + return GetNewOrPreassignedOid(relation, indexId, oidcolumn, &key); + +} + Oid GetNewOidForLanguage(Relation relation, Oid indexId, AttrNumber oidcolumn, char *lanname) @@ -1161,6 +1180,23 @@ GetNewOidForUserMapping(Relation relation, Oid indexId, AttrNumber oidcolumn, return GetNewOrPreassignedOid(relation, indexId, oidcolumn, &key); } +Oid +GetNewOidForStorageUserMapping(Relation relation, Oid indexId, AttrNumber oidcolumn, + Oid umuser, Oid umserver) +{ + OidAssignment key; + + Assert(RelationGetRelid(relation) == StorageUserMappingRelationId); + Assert(indexId == StorageUserMappingOidIndexId); + Assert(oidcolumn == Anum_gp_storage_user_mapping_oid); + + memset(&key, 0, sizeof(OidAssignment)); + key.type = T_OidAssignment; + key.keyOid1 = umuser; + key.keyOid2 = umserver; + return GetNewOrPreassignedOid(relation, indexId, oidcolumn, &key); +} + Oid GetNewOidForPublication(Relation relation, Oid indexId, AttrNumber oidcolumn, char *pubname) diff --git a/src/backend/catalog/pg_directory_table.c b/src/backend/catalog/pg_directory_table.c new file mode 100644 index 00000000000..49df145148f --- /dev/null +++ b/src/backend/catalog/pg_directory_table.c @@ -0,0 +1,375 @@ +/*------------------------------------------------------------------------- + * + * pg_directory_table.c + * support for directory table. + * + * Copyright (c) 2016-Present Hashdata, Inc. + * + * IDENTIFICATION + * src/backend/catalog/pg_directory_table.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/htup_details.h" +#include "access/xact.h" +#include "catalog/index.h" +#include "catalog/indexing.h" +#include "catalog/pg_collation.h" +#include "catalog/pg_opclass.h" +#include "cdb/cdbhash.h" +#include "cdb/cdbutil.h" +#include "parser/parser.h" +#include "parser/parse_func.h" +#include "catalog/pg_directory_table.h" +#include "catalog/gp_distribution_policy.h" +#include "catalog/pg_tablespace.h" +#include "storage/lmgr.h" +#include "utils/builtins.h" +#include "utils/inval.h" +#include "utils/lsyscache.h" +#include "utils/syscache.h" +#include "utils/varlena.h" + +typedef FileAm* (*File_handler) (void); +/* Hash table for tablespace file handler */ +static HTAB *TableSpaceFileHandlerHash = NULL; + +typedef struct TableSpaceFileAmEntry +{ + Oid spcId; /* tablespace oid */ + FileAm *fileAm; /* tablespace file am */ +} TableSpaceFileAmEntry; + +static void +InvalidateTableSpaceFileAmCallBack(Datum arg, int cacheid, uint32 hashvalue) +{ + HASH_SEQ_STATUS status; + TableSpaceFileAmEntry *fileAmEntry; + + hash_seq_init(&status, TableSpaceFileHandlerHash); + while ((fileAmEntry = (TableSpaceFileAmEntry *) hash_seq_search(&status)) != NULL) + { + hash_search(TableSpaceFileHandlerHash, + (void *) &fileAmEntry->spcId, + HASH_REMOVE, + NULL); + } +} + +static void +InitializeTableSpaceFileHandlerHash(void) +{ + HASHCTL ctl; + + /* Initialize the hash table. */ + ctl.keysize = sizeof(Oid); + ctl.entrysize = sizeof(TableSpaceFileAmEntry); + TableSpaceFileHandlerHash = + hash_create("TableSpace File Handler hash", 8, &ctl, + HASH_ELEM | HASH_BLOBS); + + /* Make sure we've initialized CacheMemoryContext. */ + if (!CacheMemoryContext) + CreateCacheMemoryContext(); + + /* Watch for invalidation events. */ + CacheRegisterSyscacheCallback(TABLESPACEOID, + InvalidateTableSpaceFileAmCallBack, + (Datum) 0); +} + +FileAm * +GetTablespaceFileHandler(Oid spcId) +{ + HeapTuple tuple; + Datum datum; + bool isNull; + char *filehandlersrc; + char *filehandlerbin; + Form_pg_tablespace tblspcForm; + void *libraryhandle; + File_handler file_handler; + TableSpaceFileAmEntry *fileAmEntry; + FileAm *fileAm = NULL; + bool found; + + if (!TableSpaceFileHandlerHash) + InitializeTableSpaceFileHandlerHash(); + + fileAmEntry = (TableSpaceFileAmEntry *) hash_search(TableSpaceFileHandlerHash, + (void *) &spcId, + HASH_FIND, + &found); + + if (found) + return fileAmEntry->fileAm; + + tuple = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(spcId)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for table space %u", spcId); + + tblspcForm = (Form_pg_tablespace) GETSTRUCT(tuple); + datum = SysCacheGetAttr(TABLESPACEOID, + tuple, + Anum_pg_tablespace_spcfilehandlerbin, + &isNull); + if (!isNull) + { + filehandlerbin = TextDatumGetCString(datum); + + datum = SysCacheGetAttr(TABLESPACEOID, + tuple, + Anum_pg_tablespace_spcfilehandlersrc, + &isNull); + filehandlersrc = TextDatumGetCString(datum); + + file_handler = (File_handler) load_external_function(filehandlerbin, filehandlersrc, true, &libraryhandle); + + if (file_handler) + fileAm = (*file_handler) (); + + if (fileAm == NULL || fileAm == &localFileAm) + elog(ERROR, "tablespace file handler did not return a FileAm struct"); + } + else + { + fileAm = &localFileAm; + } + + ReleaseSysCache(tuple); + + Assert(fileAm != NULL); + Assert(fileAm->open != NULL); + Assert(fileAm->close != NULL); + Assert(fileAm->read != NULL); + Assert(fileAm->write != NULL); + Assert(fileAm->size != NULL); + Assert(fileAm->unlink != NULL); + Assert(fileAm->formatPathName != NULL); + Assert(fileAm->exists != NULL); + Assert(fileAm->name != NULL); + Assert(fileAm->getLastError != NULL); + + fileAmEntry = (TableSpaceFileAmEntry *) hash_search(TableSpaceFileHandlerHash, + (void *) &spcId, + HASH_ENTER, + &found); + if (found) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("extra tablespace oid \"%u\" already exists", spcId))); + + fileAmEntry->fileAm = fileAm; + + return fileAm; +} + +/* + * GetDirectoryTable - look up the directory table definition by relId. + */ +DirectoryTable * +GetDirectoryTable(Oid relId) +{ + Form_pg_directory_table dirtableForm; + HeapTuple tuple; + Datum datum; + bool isNull; + DirectoryTable *dirTable; + + tuple = SearchSysCache1(DIRECTORYTABLEREL, ObjectIdGetDatum(relId)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for directory table %u", relId); + + dirtableForm = (Form_pg_directory_table) GETSTRUCT(tuple); + + dirTable = (DirectoryTable *) palloc(sizeof(DirectoryTable)); + dirTable->relId = relId; + dirTable->spcId = dirtableForm->dttablespace; + GetTablespaceFileHandler(dirtableForm->dttablespace); + + datum = SysCacheGetAttr(DIRECTORYTABLEREL, + tuple, + Anum_pg_directory_table_dtlocation, + &isNull); + Assert(!isNull); + + dirTable->location = TextDatumGetCString(datum); + ReleaseSysCache(tuple); + + return dirTable; +} + +bool +RelationIsDirectoryTable(Oid relId) +{ + HeapTuple tuple; + + tuple = SearchSysCache1(DIRECTORYTABLEREL, ObjectIdGetDatum(relId)); + if (!HeapTupleIsValid(tuple)) + return false; + + ReleaseSysCache(tuple); + return true; +} + +List * +GetDirectoryTableSchema(void) +{ + List *result = NIL; + + ColumnDef *columnDef = makeNode(ColumnDef); + columnDef->colname = "relative_path"; + columnDef->typeName = SystemTypeName("text"); + columnDef->is_local = true; + result = lappend(result, columnDef); + + columnDef = makeNode(ColumnDef); + columnDef->colname = "size"; + columnDef->typeName = SystemTypeName("int8"); + columnDef->is_local = true; + result = lappend(result, columnDef); + + columnDef = makeNode(ColumnDef); + columnDef->colname = "last_modified"; + columnDef->typeName = SystemTypeName("timestamptz"); + columnDef->is_local =true; + result = lappend(result, columnDef); + + columnDef = makeNode(ColumnDef); + columnDef->colname = "md5"; + columnDef->typeName = SystemTypeName("text"); + columnDef->is_local = true; + result = lappend(result, columnDef); + + columnDef = makeNode(ColumnDef); + columnDef->colname = "tag"; + columnDef->typeName = SystemTypeName("text"); + columnDef->is_local = true; + result = lappend(result, columnDef); + + return result; +} + +DistributedBy * +GetDirectoryTableDistributedBy(void) +{ + Oid opclassoid = InvalidOid; + HeapTuple ht_opc; + Form_pg_opclass opcrec; + char *opcname; + char *nspname; + + DistributedBy *distributedBy = makeNode(DistributedBy); + distributedBy->ptype = POLICYTYPE_PARTITIONED; + distributedBy->numsegments = -1; + DistributionKeyElem *elem = makeNode(DistributionKeyElem); + elem->name = "relative_path"; + if (gp_use_legacy_hashops) + opclassoid = get_legacy_cdbhash_opclass_for_base_type(TEXTOID); + + if (!OidIsValid(opclassoid)) + opclassoid = cdb_default_distribution_opclass_for_type(TEXTOID); + + ht_opc = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid)); + if (!HeapTupleIsValid(ht_opc)) + elog(ERROR, "cache lookup failed for opclass %u", opclassoid); + opcrec = (Form_pg_opclass) GETSTRUCT(ht_opc); + nspname = get_namespace_name(opcrec->opcnamespace); + opcname = pstrdup(NameStr(opcrec->opcname)); + elem->opclass = list_make2(makeString(nspname), makeString(opcname)); + + elem->location = -1; + distributedBy->keyCols = lappend(distributedBy->keyCols, elem); + distributedBy->numsegments = GP_POLICY_DEFAULT_NUMSEGMENTS(); + + ReleaseSysCache(ht_opc); + + return distributedBy; +} + +Oid +CreateDirectoryTableIndex(Relation rel) +{ + char dirtable_idxname[NAMEDATALEN]; + Oid dirtable_idxid; + Oid collationObjectId; + IndexInfo *indexInfo; + List *indexColNames; + Oid classObjectId[1]; + int16 coloptions[1]; + HeapTuple tuple; + Datum collationDatum; + bool isNull; + + snprintf(dirtable_idxname, sizeof(dirtable_idxname), + "%s_pkey", RelationGetRelationName(rel)); + + classObjectId[0] = TEXT_BTREE_OPS_OID; + + coloptions[0] = 0; + + indexInfo = makeNode(IndexInfo); + indexInfo->ii_NumIndexAttrs = 1; + indexInfo->ii_NumIndexKeyAttrs = 1; + indexInfo->ii_IndexAttrNumbers[0] = 1; + indexInfo->ii_Expressions = NIL; + indexInfo->ii_ExpressionsState = NIL; + indexInfo->ii_Predicate = NIL; + indexInfo->ii_PredicateState = NULL; + indexInfo->ii_Unique = true; + indexInfo->ii_Concurrent = false; + indexColNames = list_make1("relative_path"); + + tuple = SearchSysCache2(ATTNUM, + ObjectIdGetDatum(RelationGetRelid(rel)), + Int16GetDatum(1)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for directory_table %u", + RelationGetRelid(rel)); + collationDatum = SysCacheGetAttr(ATTNUM, tuple, Anum_pg_attribute_attcollation, + &isNull); + collationObjectId = DatumGetObjectId(collationDatum); + + dirtable_idxid = index_create(rel, + dirtable_idxname, + InvalidOid, + InvalidOid, + InvalidOid, + InvalidOid, + indexInfo, + indexColNames, + BTREE_AM_OID, + InvalidOid, + &collationObjectId, classObjectId, coloptions, (Datum) 0, + INDEX_CREATE_IS_PRIMARY, 0, true, true, NULL); + + ReleaseSysCache(tuple); + + /* Make this table visible, else index creation will fail */ + CommandCounterIncrement(); + + /* Unlock the index -- no one can see it anyway */ + UnlockRelationOid(dirtable_idxid, AccessExclusiveLock); + + return dirtable_idxid; +} + +void +RemoveDirectoryTableEntry(Oid relId) +{ + Relation rel; + HeapTuple tuple; + + rel = table_open(DirectoryTableRelationId, RowExclusiveLock); + + tuple = SearchSysCache1(DIRECTORYTABLEREL, ObjectIdGetDatum(relId)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for directory table %u", relId); + + CatalogTupleDelete(rel, &tuple->t_self); + + ReleaseSysCache(tuple); + table_close(rel, RowExclusiveLock); +} diff --git a/src/backend/catalog/pg_shdepend.c b/src/backend/catalog/pg_shdepend.c index 730dc0ec3e2..9c101a9fdb0 100644 --- a/src/backend/catalog/pg_shdepend.c +++ b/src/backend/catalog/pg_shdepend.c @@ -21,6 +21,8 @@ #include "access/xact.h" #include "catalog/catalog.h" #include "catalog/dependency.h" +#include "catalog/gp_storage_server.h" +#include "catalog/gp_storage_user_mapping.h" #include "catalog/indexing.h" #include "catalog/pg_authid.h" #include "catalog/pg_collation.h" @@ -1221,6 +1223,26 @@ shdepLockAndCheckObject(Oid classId, Oid objectId) break; } + case StorageServerRelationId: + { + if (!SearchSysCacheExists1(STORAGESERVEROID, ObjectIdGetDatum(objectId))) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("storage server %u was concurrently dropped", + objectId))); + break; + } + + case StorageUserMappingRelationId: + { + if (!SearchSysCacheExists1(STORAGEUSERMAPPINGUSERSERVER, ObjectIdGetDatum(objectId))) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("storage user mapping %u was concurrently dropped", + objectId))); + break; + } + default: elog(ERROR, "unrecognized shared classId: %u", classId); @@ -1275,6 +1297,8 @@ storeObjectDescription(StringInfo descs, appendStringInfo(descs, _("tablespace for %s"), objdesc); else if (deptype == SHARED_DEPENDENCY_PROFILE) appendStringInfo(descs, _("profile of %s"), objdesc); + else if (deptype == SHARED_DEPENDENCY_STORAGE_SERVER) + appendStringInfo(descs, _("storage server of %s"), objdesc); else elog(ERROR, "unrecognized dependency type: %d", (int) deptype); @@ -1743,4 +1767,22 @@ changeProfileDependency(Oid roleId, Oid newprofileId) SHARED_DEPENDENCY_PROFILE); table_close(sdepRel, RowExclusiveLock); +} + +/* + * recordStorageServerDependency + * + * A convenient wrapper of recordSharedDependencyOn -- register the specified + * storage user mapping of attached to storage server. + */ +void +recordStorageServerDependency(Oid classId, Oid objectId, Oid srvId) +{ + ObjectAddress myself, + referenced; + + ObjectAddressSet(myself, classId, objectId); + ObjectAddressSet(referenced, StorageServerRelationId, srvId); + + recordSharedDependencyOn(&myself, &referenced, SHARED_DEPENDENCY_STORAGE_SERVER); } \ No newline at end of file diff --git a/src/backend/catalog/storage.c b/src/backend/catalog/storage.c index 1c4b56672be..6d80abce254 100644 --- a/src/backend/catalog/storage.c +++ b/src/backend/catalog/storage.c @@ -27,6 +27,7 @@ #include "access/xloginsert.h" #include "access/xlogutils.h" #include "catalog/storage.h" +#include "catalog/storage_directory_table.h" #include "catalog/storage_xlog.h" #include "common/relpath.h" #include "commands/dbcommands.h" @@ -637,6 +638,8 @@ smgrDoPendingDeletes(bool isCommit) maxrels = 0; SMgrRelation *srels = NULL; + UFileDoDeletesActions(isCommit); + prev = NULL; for (pending = pendingDeletes; pending != NULL; pending = next) { @@ -933,6 +936,8 @@ AtSubCommit_smgr(void) int nestLevel = GetCurrentTransactionNestLevel(); PendingRelDelete *pending; + UFileAtSubCommitSmgr(); + for (pending = pendingDeletes; pending != NULL; pending = pending->next) { if (pending->nestLevel >= nestLevel) @@ -950,6 +955,7 @@ AtSubCommit_smgr(void) void AtSubAbort_smgr(void) { + UFileAtSubAbortSmgr(); smgrDoPendingDeletes(false); } diff --git a/src/backend/catalog/storage_directory_table.c b/src/backend/catalog/storage_directory_table.c new file mode 100644 index 00000000000..8619e2b46e1 --- /dev/null +++ b/src/backend/catalog/storage_directory_table.c @@ -0,0 +1,240 @@ +/*------------------------------------------------------------------------- + * + * Storage manipulation for directory table. + * + * Copyright (c) 2016-Present Hashdata, Inc. + * + * src/backend/catalog/storage_directory_table.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "access/heapam.h" +#include "access/parallel.h" +#include "access/relscan.h" +#include "access/table.h" +#include "access/tableam.h" +#include "access/xact.h" +#include "catalog/pg_directory_table.h" +#include "catalog/pg_tablespace.h" +#include "catalog/storage_directory_table.h" +#include "storage/smgr.h" +#include "storage/ufile.h" +#include "utils/acl.h" +#include "utils/memutils.h" +#include "utils/rel.h" +#include "cdb/cdbvars.h" + +/* + * TODO: Redo pending delete + * + * We do not support deleteing files during WAL redo, this is because deleting + * files requires a connection to object storage system. In order to establish + * the connection to the object storage, we need to access the catalog table to + * retrieve the connection configuration info, which is impossible during WAL + * redo. + */ + +typedef struct UFileNodePendingDelete +{ + char relkind; + Oid spcId; /* directory table needs an extra tabpespace */ + char *relativePath; +} UFileNodePendingDelete; + +typedef struct PendingRelDeleteUFile +{ + UFileNodePendingDelete filenode; /* relation that may need to be deleted */ + bool atCommit; /* T=delete at commit; F=delete at abort */ + int nestLevel; /* xact nesting level of request */ + struct PendingRelDeleteUFile *next; /* linked-list link */ +} PendingRelDeleteUFile; + +static PendingRelDeleteUFile *pendingDeleteUFiles = NULL; /* head of linked list */ + +void +DirectoryTableDropStorage(Relation rel) +{ + char *filePath; + DirectoryTable *dirTable; + PendingRelDeleteUFile *pending; + TableScanDesc scandesc; + Relation spcrel; + HeapTuple tuple; + Form_pg_tablespace spcform; + ScanKeyData entry[1]; + Oid tablespaceoid; + char *tablespace_name; + + dirTable = GetDirectoryTable(RelationGetRelid(rel)); + + /* + * Find the tablespace by spaceId + */ + spcrel = table_open(TableSpaceRelationId, RowExclusiveLock); + + ScanKeyInit(&entry[0], + Anum_pg_tablespace_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(dirTable->spcId)); + scandesc = table_beginscan_catalog(spcrel, 1, entry); + tuple = heap_getnext(scandesc, ForwardScanDirection); + + if (!HeapTupleIsValid(tuple)) + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("tablespace \"%d\" does not exist", + dirTable->spcId))); + } + + spcform = (Form_pg_tablespace) GETSTRUCT(tuple); + tablespaceoid = spcform->oid; + tablespace_name = pstrdup(NameStr(((Form_pg_tablespace) GETSTRUCT(tuple))->spcname)); + + /* Must be tablespace owner */ + if (!pg_tablespace_ownercheck(tablespaceoid, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_TABLESPACE, + tablespace_name); + + table_endscan(scandesc); + table_close(spcrel, RowExclusiveLock); + + filePath = psprintf("%s", dirTable->location); + + /* Add the relation to the list of stuff to delete at commit */ + pending = (PendingRelDeleteUFile *) + MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDeleteUFile)); + pending->filenode.relkind = rel->rd_rel->relkind; + pending->filenode.relativePath = MemoryContextStrdup(TopMemoryContext, filePath); + pending->filenode.spcId = dirTable->spcId; + + pending->atCommit = true; /* delete if commit */ + pending->nestLevel = GetCurrentTransactionNestLevel(); + pending->next = pendingDeleteUFiles; + + pendingDeleteUFiles = pending; + + pfree(filePath); + + /* + * Make sure the connection to the corresponding tablespace has + * been cached. + * + * UFileDoDeletesActions->UFileUnlink is called outside of the + * transaction, if we don't establish a connection here. we may + * face the issus of accessing the catalog outside of the + * transaction. + */ + forceCacheUFileResource(dirTable->spcId); +} + +void +UFileAddCreatePendingEntry(Relation rel, Oid spcId, char *relativePath) +{ + PendingRelDeleteUFile *pending; + + /* Add the relation to the list of stuff to delete at abort */ + pending = (PendingRelDeleteUFile *) + MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDeleteUFile)); + pending->filenode.relkind = rel->rd_rel->relkind; + pending->filenode.relativePath = MemoryContextStrdup(TopMemoryContext, relativePath); + pending->filenode.spcId = spcId; + + pending->atCommit = false; /* delete if abort */ + pending->nestLevel = GetCurrentTransactionNestLevel(); + pending->next = pendingDeleteUFiles; + + pendingDeleteUFiles = pending; + + /* + * Make sure the spccache to the corresponding tablespace has + * been cached. + */ + forceCacheUFileResource(spcId); +} + +void +UFileAddDeletePendingEntry(Relation rel, Oid spcId, char *relativePath) +{ + PendingRelDeleteUFile *pending; + + /* Add the relation to the list of stuff to delete at abort */ + pending = (PendingRelDeleteUFile *) + MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDeleteUFile)); + pending->filenode.relkind = rel->rd_rel->relkind; + pending->filenode.relativePath = MemoryContextStrdup(TopMemoryContext, relativePath); + pending->filenode.spcId = spcId; + + pending->atCommit = true; /* delete if commit */ + pending->nestLevel = GetCurrentTransactionNestLevel(); + pending->next = pendingDeleteUFiles; + + pendingDeleteUFiles = pending; + + /* + * Make sure the spccache to the corresponding tablespace has + * been cached. + */ + forceCacheUFileResource(spcId); +} + +void +UFileDoDeletesActions(bool isCommit) +{ + int nestLevel = GetCurrentTransactionNestLevel(); + PendingRelDeleteUFile *pending; + PendingRelDeleteUFile *prev; + PendingRelDeleteUFile *next; + + prev = NULL; + for (pending = pendingDeleteUFiles; pending != NULL; pending = next) + { + next = pending->next; + if (pending->nestLevel < nestLevel) + { + /* outer-level entries should not be processed yet */ + prev = pending; + } + else + { + /* unlink list entry first, so we don't retry on failure */ + if (prev) + prev->next = next; + else + pendingDeleteUFiles = next; + + /* do deletion if called for */ + if (pending->atCommit == isCommit) + UFileUnlink(pending->filenode.spcId, pending->filenode.relativePath); + + /* must explicitly free the list entry */ + if (pending->filenode.relativePath) + pfree(pending->filenode.relativePath); + + pfree(pending); + /* prev does not change */ + } + } +} + +void +UFileAtSubCommitSmgr(void) +{ + int nestLevel = GetCurrentTransactionNestLevel(); + PendingRelDeleteUFile *pending; + + for (pending = pendingDeleteUFiles; pending != NULL; pending = pending->next) + { + if (pending->nestLevel >= nestLevel) + pending->nestLevel = nestLevel - 1; + } +} + +void +UFileAtSubAbortSmgr(void) +{ + UFileDoDeletesActions(false); +} diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index a077f595df0..c7c46d820f3 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -1702,6 +1702,8 @@ CREATE VIEW pg_user_mappings AS REVOKE ALL ON pg_user_mapping FROM public; +REVOKE ALL ON gp_storage_user_mapping FROM public; + CREATE VIEW pg_replication_origin_status AS SELECT * FROM pg_show_replication_origin_status(); diff --git a/src/backend/commands/Makefile b/src/backend/commands/Makefile index 94e0485ac13..2fe51b415ba 100644 --- a/src/backend/commands/Makefile +++ b/src/backend/commands/Makefile @@ -33,6 +33,7 @@ OBJS = \ createas.o \ dbcommands.o \ define.o \ + dirtablecmds.o \ discard.o \ dropcmds.o \ event_trigger.o \ @@ -64,7 +65,8 @@ OBJS = \ vacuum.o \ variable.o \ view.o \ - pg_profile.o + pg_profile.o \ + storagecmds.o OBJS += analyzefuncs.o analyzeutils.o extprotocolcmds.o exttablecmds.o queue.o OBJS += resgroupcmds.o tablecmds_gp.o vacuum_ao.o taskcmds.o diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c index 38ca72b479c..df43eb8e69b 100644 --- a/src/backend/commands/alter.c +++ b/src/backend/commands/alter.c @@ -555,6 +555,7 @@ ExecAlterObjectSchemaStmt_internal(AlterObjectSchemaStmt *stmt, case OBJECT_TABLE: case OBJECT_VIEW: case OBJECT_MATVIEW: + case OBJECT_DIRECTORY_TABLE: address = AlterTableNamespace(stmt, oldSchemaAddr ? &oldNspOid : NULL); break; @@ -733,6 +734,8 @@ AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid, case OCLASS_TASK: case OCLASS_PROFILE: case OCLASS_PASSWORDHISTORY: + case OCLASS_STORAGE_SERVER: + case OCLASS_STORAGE_USER_MAPPING: /* ignore object types that don't have schema-qualified names */ break; diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c index c2c93e6c3c4..6e6d6b03327 100644 --- a/src/backend/commands/analyze.c +++ b/src/backend/commands/analyze.c @@ -344,7 +344,8 @@ analyze_rel_internal(Oid relid, RangeVar *relation, * Check that it's of an analyzable relkind, and set up appropriately. */ if (onerel->rd_rel->relkind == RELKIND_RELATION || - onerel->rd_rel->relkind == RELKIND_MATVIEW) + onerel->rd_rel->relkind == RELKIND_MATVIEW || + onerel->rd_rel->relkind == RELKIND_DIRECTORY_TABLE) { /* Regular table, so we'll use the regular row acquisition function */ if (onerel->rd_tableam) @@ -1984,7 +1985,8 @@ acquire_inherited_sample_rows(Relation onerel, int elevel, /* Check table type (MATVIEW can't happen, but might as well allow) */ if (childrel->rd_rel->relkind == RELKIND_RELATION || - childrel->rd_rel->relkind == RELKIND_MATVIEW) + childrel->rd_rel->relkind == RELKIND_MATVIEW || + childrel->rd_rel->relkind == RELKIND_DIRECTORY_TABLE) { /* Regular table, so use the regular row acquisition function */ if (childrel->rd_tableam) diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c index b8e5f14ccbc..906405718e2 100644 --- a/src/backend/commands/comment.c +++ b/src/backend/commands/comment.c @@ -98,10 +98,11 @@ CommentObject(CommentStmt *stmt) relation->rd_rel->relkind != RELKIND_MATVIEW && relation->rd_rel->relkind != RELKIND_COMPOSITE_TYPE && relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE && + relation->rd_rel->relkind != RELKIND_DIRECTORY_TABLE && relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("\"%s\" is not a table, view, materialized view, composite type, or foreign table", + errmsg("\"%s\" is not a table, directory table, view, materialized view, composite type, or foreign table", RelationGetRelationName(relation)))); break; default: diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 7e1bf331326..daaca78cd7e 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -792,6 +792,15 @@ ProcessCopyOptions(ParseState *pstate, errmsg("conflicting or redundant options"))); opts_out->skip_foreign_partitions = true; } + else if (strcmp(defel->defname, "tag") == 0) + { + if (opts_out->tags) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); + opts_out->tags = defGetString(defel); + } else if (!rel_is_external_table(rel_oid)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), @@ -965,6 +974,11 @@ ProcessCopyOptions(ParseState *pstate, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("CSV quote character must not appear in the NULL specification"))); + if (opts_out->tags != NULL && !is_from) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("COPY with tag only available using COPY FROM"))); + /* * DELIMITER * @@ -1033,6 +1047,84 @@ ProcessCopyOptions(ParseState *pstate, } } +void +ProcessCopyDirectoryTableOptions(ParseState *pstate, + CopyFormatOptions *opts_out, + bool is_from, + List *options, + Oid rel_oid) +{ + bool format_specified = false; + ListCell *option; + + /* Support external use for option sanity checking */ + if (opts_out == NULL) + opts_out = (CopyFormatOptions *) palloc0(sizeof(CopyFormatOptions)); + + opts_out->file_encoding = -1; + + /* Extract options from the statement node tree */ + foreach(option, options) + { + DefElem *defel = lfirst_node(DefElem, option); + + if (strcmp(defel->defname, "format") == 0) + { + char *fmt = defGetString(defel); + + if (format_specified) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); + format_specified = true; + if (strcmp(fmt, "binary") == 0) + opts_out->binary = true; + else + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("format option is not allowed in copy binary from directory table."), + parser_errposition(pstate, defel->location))); + } + else if (strcmp(defel->defname, "tag") == 0) + { + if (opts_out->tags) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); + opts_out->tags = defGetString(defel); + } + else + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("option \"%s\" not recognized", + defel->defname), + parser_errposition(pstate, defel->location))); + } + + opts_out->eol_type = EOL_UNKNOWN; + + /* Set defaults for omitted options */ + if (!opts_out->delim) + opts_out->delim = opts_out->csv_mode ? "," : "\t"; + + if (!opts_out->null_print) + opts_out->null_print = opts_out->csv_mode ? "" : "\\N"; + opts_out->null_print_len = strlen(opts_out->null_print); + + if (opts_out->csv_mode) + { + if (!opts_out->quote) + opts_out->quote = "\""; + if (!opts_out->escape) + opts_out->escape = opts_out->quote; + } + + if (!opts_out->csv_mode && !opts_out->escape) + opts_out->escape = "\\"; /* default escape for text mode */ +} + /* * Dispatch a COPY ON SEGMENT statement to QEs. */ diff --git a/src/backend/commands/copyfrom.c b/src/backend/commands/copyfrom.c index acb01d91ec6..29de4e79fdd 100644 --- a/src/backend/commands/copyfrom.c +++ b/src/backend/commands/copyfrom.c @@ -31,13 +31,20 @@ #include "access/xact.h" #include "access/xlog.h" #include "catalog/namespace.h" +#include "catalog/pg_directory_table.h" +#include "catalog/storage_directory_table.h" #include "cdb/cdbaocsam.h" #include "cdb/cdbappendonlyam.h" +#include "cdb/cdbdisp.h" #include "cdb/cdbvars.h" #include "commands/copy.h" #include "commands/copyfrom_internal.h" #include "commands/progress.h" +#include "commands/tablespace.h" #include "commands/trigger.h" +#include "common/base64.h" +#include "common/cryptohash.h" +#include "common/md5.h" #include "executor/execPartition.h" #include "executor/executor.h" #include "executor/nodeModifyTable.h" @@ -50,7 +57,9 @@ #include "pgstat.h" #include "rewrite/rewriteHandler.h" #include "storage/fd.h" +#include "storage/ufile.h" #include "tcop/tcopprot.h" +#include "utils/builtins.h" #include "utils/lsyscache.h" #include "utils/memutils.h" #include "utils/portal.h" @@ -205,6 +214,10 @@ static void FreeDistributionData(GpDistributionData *distData); static void InitCopyFromDispatchSplit(CopyFromState cstate, GpDistributionData *distData, EState *estate); static unsigned int GetTargetSeg(GpDistributionData *distData, TupleTableSlot *slot); +static uint64 CopyFromDirectoryTable(CopyFromState cstate); +static CopyFromState BeginCopyFromDirectoryTable(ParseState *pstate, const char *fileName, + Relation rel, List *options); + /* * No more than this many tuples per CopyMultiInsertBuffer * @@ -225,6 +238,9 @@ static unsigned int GetTargetSeg(GpDistributionData *distData, TupleTableSlot *s /* Trim the list of buffers back down to this number after flushing */ #define MAX_PARTITION_BUFFERS 32 +/* The buffer size of directory table files */ +#define DIR_FILE_BUFF_SIZE 8192 + /* Stores multi-insert data related to a single relation in CopyFrom. */ typedef struct CopyMultiInsertBuffer { @@ -666,6 +682,779 @@ CopyMultiInsertInfoStore(CopyMultiInsertInfo *miinfo, ResultRelInfo *rri, miinfo->bufferedBytes += tuplen; } +static CopyStmt * +convertToCopyTextStmt(CopyStmt *stmt) +{ + CopyStmt *copiedStmt = copyObject(stmt); + + copiedStmt->options = NIL; + + return copiedStmt; +} + +static char * +trimFilePath(char *filePath, char c) +{ + char *end; + + while (*filePath == c) + filePath++; + + end = filePath + strlen(filePath) - 1; + while (end > filePath && *end == c) + end--; + + *(end + 1) = '\0'; + + return filePath; +} + +static void +formDirTableSlot(CopyFromState cstate, + Oid spcId, + char *relativePath, + int64 fileSize, + char *md5sum, + char *tags, + StringInfo buf, + Datum *values, + bool *nulls) +{ + TupleDesc tupDesc; + AttrNumber num_phys_attrs; + ListCell *cur; + char *field[6]; + FmgrInfo *in_functions = cstate->in_functions; + Oid *typioparams = cstate->typioparams; + List *attnumlist = cstate->qd_attnumlist; + pg_time_t stampTime = (pg_time_t) time(NULL); + char lastModified[128]; + char *encode_file; + int encode_file_len; + + encode_file_len = pg_b64_enc_len(buf->len); + encode_file = (char *) palloc0(encode_file_len + 1); + + encode_file_len = pg_b64_encode(buf->data, buf->len, encode_file, encode_file_len); + if (encode_file_len < 0) + { + elog(ERROR, "base 64 encode failed in copy from directory table"); + } + encode_file[encode_file_len] = '\0'; + if (buf->data) + { + pfree(buf->data); + } + + pg_strftime(lastModified, sizeof(lastModified), + "%Y-%m-%d %H:%M:%S", + pg_localtime(&stampTime, log_timezone)); + + tupDesc = RelationGetDescr(cstate->rel); + num_phys_attrs = tupDesc->natts; + + MemSet(values, 0, num_phys_attrs * sizeof(Datum)); + MemSet(nulls, false, num_phys_attrs * sizeof(bool)); + + field[0] = relativePath; /* relative_path */ + field[1] = psprintf(INT64_FORMAT, fileSize); /* size */ + field[2] = lastModified; /* last_modified */ + field[3] = md5sum; /* md5sum */ + field[4] = tags; /* tags */ + if (tags == NULL) + nulls[4] = true; + field[5] = encode_file; + + /* Loop to read the user attributes on the line. */ + foreach(cur, attnumlist) + { + int attnum = lfirst_int(cur); + int m = attnum - 1; + char *value; + Form_pg_attribute att = TupleDescAttr(tupDesc, m); + + value = field[m]; + + values[m] = InputFunctionCall(&in_functions[m], + value, + typioparams[m], + att->atttypmod); + } +} + +/* + * Copy From file to directory table. + */ +static uint64 +CopyFromDirectoryTable(CopyFromState cstate) +{ + ResultRelInfo *resultRelInfo; + ResultRelInfo *target_resultRelInfo; + EState *estate = CreateExecutorState(); + TupleTableSlot *myslot = NULL; + StringInfoData buf; + ExprContext *econtext; + int bytesRead; + char hexMd5Sum[256]; + char buffer[DIR_FILE_BUFF_SIZE]; + int64 processed = 0; + int64 fileSize = 0; + CdbCopy *cdbCopy = NULL; + char *dirTablePath; + char *orgiFileName; + char *relaFileDirPointer; + char relaFileDir[MAXPGPATH] = {0}; + char *orgiFileDir = NULL; + char *relaFileName; + TupleDesc tupdesc; + unsigned int targetSeg; + DirectoryTable *dirTable; + pg_cryptohash_ctx *hashCtx; + uint8 md5Sum[MD5_DIGEST_LENGTH]; + GpDistributionData *distData = NULL; /* distribution data used to compute target seg */ + + /* + * We need a ResultRelInfo so we can use the regular executor's + * index-entry-making machinery. (There used to be a huge amount of code + * here that basically duplicated execUtils.c ...) + */ + ExecInitRangeTable(estate, cstate->range_table); + resultRelInfo = target_resultRelInfo = makeNode(ResultRelInfo); + ExecInitResultRelation(estate, resultRelInfo, 1); + + ExecOpenIndices(resultRelInfo, false); + + /* Prepare to catch AFTER triggers. */ + AfterTriggerBeginQuery(); + + /* + * If there are any triggers with transition tables on the named relation, + * we need to be prepared to capture transition tuples. + */ + cstate->transition_capture = MakeTransitionCaptureState(cstate->rel->trigdesc, + RelationGetRelid(cstate->rel), + CMD_INSERT); + + /* + * Check BEFORE STATEMENT insertion triggers. It's debatable whether we + * should do this for COPY, since it's not really an "INSERT" statement as + * such. However, executing these triggers maintains consistency with the + * EACH ROW triggers that we already fire on COPY. + */ + ExecBSInsertTriggers(estate, resultRelInfo); + + /* Assemble directory table file location. */ + relaFileName = trimFilePath(glob_copystmt->dirfilename, '/'); + relaFileDirPointer = strrchr(relaFileName, '/'); + if (relaFileDirPointer) + { + memcpy(relaFileDir, relaFileName, relaFileDirPointer - relaFileName); + } + + dirTable = GetDirectoryTable(RelationGetRelid(cstate->rel)); + dirTablePath = dirTable->location; + orgiFileName = psprintf("%s/%s", dirTablePath, relaFileName); + if (relaFileDir[0] != '\0') + orgiFileDir = psprintf("%s/%s", dirTablePath, relaFileDir); + + /* + * build tupledesc and slot for copy from + */ + tupdesc = CreateTemplateTupleDesc(6); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "relative_path", + TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "size", + INT8OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 3, "last_modified", + TIMESTAMPTZOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 4, "md5", + TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 5, "tag", + TEXTOID, -1 ,0); + TupleDescInitEntry(tupdesc, (AttrNumber) 6, "file", + TEXTOID, -1, 0); + + myslot = MakeSingleTupleTableSlot(tupdesc, &TTSOpsVirtual); + + if (cstate->dispatch_mode == COPY_DISPATCH) + { + /* + * Initialize information about distribution keys, needed to compute target + * segment for each row. + */ + distData = InitDistributionData(cstate, estate); + + /* Determine which fields we need to parse in the QD. */ + InitCopyFromDispatchSplit(cstate, distData, estate); + } + + if (cstate->dispatch_mode == COPY_DISPATCH || + cstate->dispatch_mode == COPY_EXECUTOR) + { + /* + * Now split the attnumlist into the parts that are parsed in the QD, and + * in QE. + */ + ListCell *lc; + int i = 0; + List *qd_attnumlist = NIL; + List *qe_attnumlist = NIL; + int first_qe_processed_field; + + first_qe_processed_field = cstate->first_qe_processed_field; + + foreach(lc, cstate->attnumlist) + { + int attnum = lfirst_int(lc); + + if (i < first_qe_processed_field) + qd_attnumlist = lappend_int(qd_attnumlist, attnum); + else + qe_attnumlist = lappend_int(qe_attnumlist, attnum); + i++; + } + cstate->qd_attnumlist = qd_attnumlist; + cstate->qe_attnumlist = qe_attnumlist; + } + + if (cstate->dispatch_mode == COPY_DISPATCH) + { + /* + * We are the QD node, and we are receiving rows from client, or + * reading them from a file. We are not writing any data locally, + * instead, we determine the correct target segment for row, + * and forward each to the correct segment. + */ + + /* + * pre-allocate buffer for constructing a message. + */ + cstate->dispatch_msgbuf = makeStringInfo(); + enlargeStringInfo(cstate->dispatch_msgbuf, SizeOfCopyFromDispatchRow); + + /* + * prepare to COPY data into segDBs: + */ + cdbCopy = makeCdbCopyFrom(cstate); + + /* + * Dispatch the COPY command. + */ + elog(DEBUG5, "COPY command sent to segdbs"); + + cdbCopyStart(cdbCopy, convertToCopyTextStmt(glob_copystmt), cstate->file_encoding); + + /* + * Header processing. + */ + SendCopyFromForwardedHeader(cstate, cdbCopy); + + /* FIXME: + * + * Even if we use FileExist function, writing to the same file in two + * concurrent sessions can still cause the file content to be corrupted. + * + * 1. Some DFS don't support renaming files, which means we can't use + * the common technique of generating a random filename for upload and + * then renaming it to the final name once it's complete. + * + * 2. Seems like unique index could be a good solution to fix the issue, + * But unique indexes can cause concurrent sessions to wait for each + * other(see comments in _bt_doinsert), and uploads can take a long time, + * so transactions waiting for each other for a long time without releasing + * resources is also not ideal(I know that we can set lock timeout). + * + * Another reason for not using unique index is that the file is uploading + * in the copy context, based on the current copy protocol, we are not able + * to insert a record first, then, once the file is uploaded, we could update + * the record. + * + * 3. We should probably create a file status table in catalog service + * to keep track of files currrently being uploaded. + */ + initStringInfo(&buf); + + hashCtx = pg_cryptohash_create(PG_MD5); + if (hashCtx == NULL) + ereport(ERROR, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("failed to create md5hash context: out of memory"))); + pg_cryptohash_init(hashCtx); + + for (;;) + { + CHECK_FOR_INTERRUPTS(); + + bytesRead = CopyReadBinaryData(cstate, buffer, DIR_FILE_BUFF_SIZE); + + if (bytesRead > 0) + { + appendBinaryStringInfo(&buf, buffer, bytesRead); + + fileSize += bytesRead; + pg_cryptohash_update(hashCtx, (const uint8 *) buffer, bytesRead); + } + + if (bytesRead != DIR_FILE_BUFF_SIZE) + { + Assert(cstate->raw_reached_eof == true); + break; + } + } + + pg_cryptohash_final(hashCtx, md5Sum, sizeof(md5Sum)); + pg_cryptohash_free(hashCtx); + bytesToHex(md5Sum, hexMd5Sum); + + formDirTableSlot(cstate, + dirTable->spcId, + relaFileName, + fileSize, + hexMd5Sum, + cstate->opts.tags, + &buf, + myslot->tts_values, + myslot->tts_isnull); + ExecStoreVirtualTuple(myslot); + + targetSeg = GetTargetSeg(distData, myslot); + /* in the QD, forward the row to the correct segment(s). */ + SendCopyFromForwardedTuple(cstate, cdbCopy, false, + targetSeg, + resultRelInfo->ri_RelationDesc, + cstate->cur_lineno, + cstate->line_buf.data, + cstate->line_buf.len, + myslot->tts_values, + myslot->tts_isnull); + { + int64 total_completed_from_qes; + int64 total_rejected_from_qes; + + cdbCopyEnd(cdbCopy, + &total_completed_from_qes, + &total_rejected_from_qes); + + processed = total_completed_from_qes; + } + } + else if (cstate->dispatch_mode == COPY_EXECUTOR) + { +#define DIRECTORY_TABLE_COLUMNS 5 + List *recheckIndexes = NIL; + TupleTableSlot *tmpslot = NULL; + CommandId mycid = GetCurrentCommandId(true); + MemoryContext oldcontext = CurrentMemoryContext; + char errorMessage[256]; + UFile *file; + char *file_buf; + int i; + char *decode_file; + int decode_file_len; + + econtext = GetPerTupleExprContext(estate); + + if (NextCopyFromExecute(cstate, econtext, myslot->tts_values, myslot->tts_isnull)) + { + if (tupdesc) + pfree(tupdesc); + + tupdesc = CreateTemplateTupleDesc(DIRECTORY_TABLE_COLUMNS); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "relative_path", + TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "size", + INT8OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 3, "last_modified", + TIMESTAMPTZOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 4, "md5", + TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 5, "tag", + TEXTOID, -1 ,0); + + tmpslot = MakeSingleTupleTableSlot(tupdesc, &TTSOpsVirtual); + + for (i = 0; i < DIRECTORY_TABLE_COLUMNS; i++) + { + tmpslot->tts_values[i] = myslot->tts_values[i]; + tmpslot->tts_isnull[i] = myslot->tts_isnull[i]; + } + + cstate->rel->rd_att = CreateTupleDescCopy(tupdesc); + cstate->rel->rd_att->tdrefcount = 1; /* mark as refcounted */ + + /* + * Reset the per-tuple exprcontext. We do this after every tuple, to + * clean-up after expression evaluations etc. + */ + ResetPerTupleExprContext(estate); + + /* + * Switch to per-tuple context before calling NextCopyFrom, which does + * evaluate default expressions etc. and requires per-tuple context. + */ + MemoryContextSwitchTo(GetPerTupleMemoryContext(estate)); + + /* + * NextCopyFromExecute set up estate->es_result_relation_info, + * and stored the tuple in the correct slot. + */ + resultRelInfo = estate->es_result_relations[0]; + + ExecStoreVirtualTuple(tmpslot); + + /* + * Constraints and where clause might reference the tableoid column, + * so (re-)initialize tts_tableOid before evaluating them. + */ + tmpslot->tts_tableOid = RelationGetRelid(target_resultRelInfo->ri_RelationDesc); + + /* Triggers and stuff need to be invoked in query context. */ + MemoryContextSwitchTo(oldcontext); + + /* OK, store the tuple and create index entries for it */ + table_tuple_insert(resultRelInfo->ri_RelationDesc, + tmpslot, mycid, 0, NULL); + + recheckIndexes = ExecInsertIndexTuples(resultRelInfo, + tmpslot, + estate, + false, + false, + NULL, + NIL); + + /* AFTER ROW INSERT Triggers */ + ExecARInsertTriggers(estate, resultRelInfo, tmpslot, + recheckIndexes, cstate->transition_capture); + + list_free(recheckIndexes); + + if (tupdesc) + pfree(tupdesc); + + if (UFileExists(dirTable->spcId, orgiFileName)) + { + UFileUnlink(dirTable->spcId, orgiFileName); + } + + if (orgiFileDir) + UFileEnsurePath(dirTable->spcId, orgiFileDir); + + file = UFileOpen(dirTable->spcId, + orgiFileName, + O_CREAT | O_WRONLY, + errorMessage, + sizeof(errorMessage)); + if (file == NULL) + ereport(ERROR, + (errcode(ERRCODE_IO_ERROR), + errmsg("failed to open file \"%s\": %s", orgiFileName, errorMessage))); + + /* Delete uploaded file when the transaction fails */ + UFileAddCreatePendingEntry(cstate->rel, dirTable->spcId, orgiFileName); + + file_buf = TextDatumGetCString(myslot->tts_values[5]); + decode_file_len = strlen(file_buf); + decode_file = (char *) palloc0(decode_file_len); + decode_file_len = pg_b64_decode(file_buf, strlen(file_buf), decode_file, decode_file_len); + + if (decode_file_len < 0) + { + elog(ERROR, "can not decode in copy from directory table, b64_msg is empty"); + } + + if (UFileWrite(file, decode_file, decode_file_len) == -1) + ereport(ERROR, + (errcode(ERRCODE_IO_ERROR), + errmsg("failed to write file \"%s\": %s", orgiFileName, UFileGetLastError(file)))); + + if (UFileSync(file) != 0) + ereport(ERROR, + (errcode(ERRCODE_IO_ERROR), + errmsg("unable to sync file \"%s\": %s", glob_copystmt->dirfilename, UFileGetLastError(file)))); + + UFileClose(file); + + ExecClearTuple(myslot); + ExecClearTuple(tmpslot); + + /* + * We count only tuples not suppressed by a BEFORE INSERT trigger + * or FDW; this is the same definition used by nodeModifyTable.c + * for counting tuples inserted by an INSERT command. Update + * progress of the COPY command as well. + * + * MPP: incrementing this counter here only matters for utility + * mode. in dispatch mode only the dispatcher COPY collects row + * count, so this counter is meaningless. + */ + pgstat_progress_update_param(PROGRESS_COPY_TUPLES_PROCESSED, + ++processed); + } + } + else + { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("This copy from dispatch mode is not supported."))); + } + + cstate->filename = NULL; + + /* Execute AFTER STATEMENT insertion triggers */ + ExecASInsertTriggers(estate, resultRelInfo, cstate->transition_capture); + + /* Handle queued AFTER triggers */ + AfterTriggerEndQuery(estate); + + /* + * In QE, send the number of rejected rows to the client (QD COPY) if + * SREH is on, always send the number of completed rows. + */ + if (Gp_role == GP_ROLE_EXECUTE) + { + SendNumRows((cstate->errMode != ALL_OR_NOTHING) ? cstate->cdbsreh->rejectcount : 0, processed); + } + + ExecResetTupleTable(estate->es_tupleTable, false); + + /* Close the result relations, including any trigger target relations */ + ExecCloseResultRelations(estate); + ExecCloseRangeTableRelations(estate); + + FreeDistributionData(distData); + FreeExecutorState(estate); + + return processed; +} + +/* + * Setup to read tuple from a file for COPY FROM. + * + * 'rel': Used as a template for the tuples + * 'options': List of DefElem. See copy_opt_item in gram.y for selections. + * + * Returns a CopyFromState, to be passed to NextCopyFrom and related functions. + */ +static CopyFromState +BeginCopyFromDirectoryTable(ParseState *pstate, + const char *filename, + Relation rel, + List *options) +{ + CopyFromState cstate; + bool pipe; + MemoryContext oldcontext; + TupleDesc tupDesc; + AttrNumber num_phys_attrs; + FmgrInfo *in_functions; + Oid *typioparams; + int attnum; + Oid in_func_oid; + const int progress_cols[] = { + PROGRESS_COPY_COMMAND, + PROGRESS_COPY_TYPE, + PROGRESS_COPY_BYTES_TOTAL + }; + int64 progress_vals[] = { + PROGRESS_COPY_COMMAND_FROM, + 0, + 0 + }; + + if (!glob_copystmt->dirfilename) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("Copy from directory table file name can't be null."))); + + /* Allocate workspace and zero all fields */ + cstate = (CopyFromStateData *) palloc0(sizeof(CopyFromStateData)); + + /* + * We allocate everything used by a cstate in a new memory context. This + * avoids memory leaks during repeated use of COPY in a query. + */ + cstate->copycontext = AllocSetContextCreate(CurrentMemoryContext, + "COPY", + ALLOCSET_DEFAULT_SIZES); + + oldcontext = MemoryContextSwitchTo(cstate->copycontext); + + /* Process the target relation */ + cstate->rel = rel; + + /* Check whether copy directory table options allowed */ + ProcessCopyDirectoryTableOptions(pstate, &cstate->opts, true, options, rel->rd_id); + + if (Gp_role == GP_ROLE_DISPATCH && !cstate->opts.binary) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Only support copy binary from directory table."))); + + cstate->copy_src = COPY_FILE; /* default */ + + /* + * Determine the mode + */ + if (Gp_role == GP_ROLE_DISPATCH && + cstate->rel && cstate->rel->rd_cdbpolicy && + cstate->rel->rd_cdbpolicy->ptype != POLICYTYPE_ENTRY) + cstate->dispatch_mode = COPY_DISPATCH; + else if (Gp_role == GP_ROLE_EXECUTE) + cstate->dispatch_mode = COPY_EXECUTOR; + + cstate->cur_relname = RelationGetRelationName(cstate->rel); + cstate->cur_lineno = 0; + cstate->cur_attname = NULL; + cstate->cur_attval = NULL; + if (filename) + cstate->filename = pstrdup(filename); + cstate->file_encoding = GetDatabaseEncoding(); + + /* + * Allocate buffers for the input pipeline. + */ + cstate->raw_buf = palloc(RAW_BUF_SIZE + 1); + cstate->raw_buf_index = cstate->raw_buf_len = 0; + MemSet(cstate->raw_buf, ' ', RAW_BUF_SIZE * sizeof(char)); + cstate->raw_buf[RAW_BUF_SIZE] = '\0'; + cstate->raw_reached_eof = false; + + initStringInfo(&cstate->line_buf); + + /* Assign range table, we'll need it in CopyFrom. */ + if (pstate) + cstate->range_table = pstate->p_rtable; + + /* + * build tupledesc and slot for copy from + */ + tupDesc = CreateTemplateTupleDesc(6); + TupleDescInitEntry(tupDesc, (AttrNumber) 1, "relative_path", + TEXTOID, -1, 0); + TupleDescInitEntry(tupDesc, (AttrNumber) 2, "size", + INT8OID, -1, 0); + TupleDescInitEntry(tupDesc, (AttrNumber) 3, "last_modified", + TIMESTAMPTZOID, -1, 0); + TupleDescInitEntry(tupDesc, (AttrNumber) 4, "md5", + TEXTOID, -1, 0); + TupleDescInitEntry(tupDesc, (AttrNumber) 5, "tag", + TEXTOID, -1 ,0); + TupleDescInitEntry(tupDesc, (AttrNumber) 6, "file", + TEXTOID, -1, 0); + + num_phys_attrs = tupDesc->natts; + + cstate->rel->rd_att = CreateTupleDescCopy(tupDesc); + cstate->rel->rd_att->tdrefcount = 1; /* mark as refcounted */ + cstate->attnumlist = CopyGetAttnums(tupDesc, cstate->rel, NIL); + + /* + * Pick up the required catalog information for each attribute in the + * relation, including the input function, the element type (to pass to + * the input function), and info about defaults and constraints. (Which + * input function we use depends on text/binary format choice.) + */ + in_functions = (FmgrInfo *) palloc(num_phys_attrs * sizeof(FmgrInfo)); + typioparams = (Oid *) palloc(num_phys_attrs * sizeof(Oid)); + + for (attnum = 1; attnum <= num_phys_attrs; attnum++) + { + Form_pg_attribute att = TupleDescAttr(tupDesc, attnum - 1); + + /* Fetch the input function and typioparam info */ + getTypeInputInfo(att->atttypid, + &in_func_oid, &typioparams[attnum - 1]); + fmgr_info(in_func_oid, &in_functions[attnum - 1]); + } + + /* initialize progress */ + pgstat_progress_start_command(PROGRESS_COMMAND_COPY, + cstate->rel ? RelationGetRelid(cstate->rel) : InvalidOid); + cstate->bytes_processed = 0; + + /* We keep those variables in cstate. */ + cstate->in_functions = in_functions; + cstate->typioparams = typioparams; + cstate->is_program = false; + + pipe = (filename == NULL || cstate->dispatch_mode == COPY_EXECUTOR); + + if (pipe) + { + progress_vals[1] = PROGRESS_COPY_TYPE_PIPE; + if (whereToSendOutput == DestRemote) + ReceiveCopyBegin(cstate); + else + cstate->copy_file = stdin; + } + else + { + struct stat st; + + cstate->filename = pstrdup(filename); + + progress_vals[1] = PROGRESS_COPY_TYPE_FILE; + cstate->copy_file = AllocateFile(cstate->filename, PG_BINARY_R); + if (cstate->copy_file == NULL) + { + /* copy errno because ereport subfunctions might change it */ + int save_errno = errno; + + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not open file \"%s\" for reading: %m", + cstate->filename), + (save_errno == ENOENT || save_errno == EACCES) ? + errhint("COPY FROM instructs the PostgreSQL server process to read a file. " + "You may want a client-side facility such as psql's \\copy.") : 0)); + } + + // Increase buffer size to improve performance (cmcdevitt) + /* GPDB_14_MERGE_FIXME: Ret value process. */ + setvbuf(cstate->copy_file, NULL, _IOFBF, 393216); // 384 Kbytes + + if (fstat(fileno(cstate->copy_file), &st)) + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not stat file \"%s\": %m", + cstate->filename))); + + if (S_ISDIR(st.st_mode)) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("\"%s\" is a directory", cstate->filename))); + + progress_vals[2] = st.st_size; + } + + pgstat_progress_update_multi_param(3, progress_cols, progress_vals); + + if (cstate->dispatch_mode == COPY_EXECUTOR && cstate->copy_src != COPY_CALLBACK) + { + /* Read special header from QD */ + char readSig[sizeof(QDtoQESignature)]; + copy_from_dispatch_header header_frame; + + if (CopyGetData(cstate, &readSig, sizeof(QDtoQESignature), sizeof(QDtoQESignature)) != sizeof(QDtoQESignature) || + memcmp(readSig, QDtoQESignature, sizeof(QDtoQESignature)) != 0) + ereport(ERROR, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("QD->QE COPY communication signature not recognized"))); + + if (CopyGetData(cstate, &header_frame, sizeof(header_frame), sizeof(header_frame)) != sizeof(header_frame)) + ereport(ERROR, + (errcode(ERRCODE_BAD_COPY_FILE_FORMAT), + errmsg("invalid QD->QD COPY communication header"))); + + cstate->first_qe_processed_field = header_frame.first_qe_processed_field; + } + + MemoryContextSwitchTo(oldcontext); + + return cstate; +} + /* * Copy FROM file to relation. */ @@ -707,6 +1496,7 @@ CopyFrom(CopyFromState cstate) * allowed on views, so we only hint about them in the view case.) */ if (cstate->rel->rd_rel->relkind != RELKIND_RELATION && + cstate->rel->rd_rel->relkind != RELKIND_DIRECTORY_TABLE && cstate->rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE && cstate->rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE && !(cstate->rel->trigdesc && @@ -735,6 +1525,9 @@ CopyFrom(CopyFromState cstate) RelationGetRelationName(cstate->rel)))); } + if (cstate->rel->rd_rel->relkind == RELKIND_DIRECTORY_TABLE) + return CopyFromDirectoryTable(cstate); + /* * If the target file is new-in-transaction, we assume that checking FSM * for free space is a waste of time. This could possibly be wrong, but @@ -807,7 +1600,8 @@ CopyFrom(CopyFromState cstate) ExecInitResultRelation(estate, resultRelInfo, 1); /* Verify the named relation is a valid target for INSERT */ - CheckValidResultRel(resultRelInfo, CMD_INSERT); + if (!(cstate->rel->rd_rel->relkind == RELKIND_DIRECTORY_TABLE)) + CheckValidResultRel(resultRelInfo, CMD_INSERT, NULL); ExecOpenIndices(resultRelInfo, false); @@ -1689,6 +2483,9 @@ BeginCopyFrom(ParseState *pstate, 0 }; + if (rel->rd_rel->relkind == RELKIND_DIRECTORY_TABLE) + return BeginCopyFromDirectoryTable(pstate, filename, rel, options); + /* Allocate workspace and zero all fields */ cstate = (CopyFromStateData *) palloc0(sizeof(CopyFromStateData)); @@ -3109,12 +3906,37 @@ SendCopyFromForwardedError(CopyFromState cstate, CdbCopy *cdbCopy, char *errorms cdbCopySendData(cdbCopy, target_seg, msgbuf->data, msgbuf->len); } +static void +EndCopyFromDirectoryTable(CopyFromState cstate) +{ + /* No COPY FROM related resources except memory. */ + if (cstate->copy_file && FreeFile(cstate->copy_file)) + { + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not close file \"%s\": %m", + cstate->filename))); + } + + /* Clean up single row error handling related memory */ + if (cstate->cdbsreh) + destroyCdbSreh(cstate->cdbsreh); + + pgstat_progress_end_command(); + + MemoryContextDelete(cstate->copycontext); + pfree(cstate); +} + /* * Clean up storage and release resources for COPY FROM. */ void EndCopyFrom(CopyFromState cstate) { + if (cstate->rel->rd_rel->relkind == RELKIND_DIRECTORY_TABLE) + return EndCopyFromDirectoryTable(cstate); + /* No COPY FROM related resources except memory. */ if (cstate->is_program) { diff --git a/src/backend/commands/dirtablecmds.c b/src/backend/commands/dirtablecmds.c new file mode 100644 index 00000000000..e1d18938cff --- /dev/null +++ b/src/backend/commands/dirtablecmds.c @@ -0,0 +1,475 @@ +/*------------------------------------------------------------------------- + * + * directorycmds.c + * directory table creation/manipulation commands + * + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group + * + * + * IDENTIFICATION + * src/backend/commands/directorycmds.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include + +#include "access/htup_details.h" +#include "access/reloptions.h" +#include "access/table.h" +#include "access/xact.h" +#include "catalog/catalog.h" +#include "catalog/dependency.h" +#include "catalog/heap.h" +#include "catalog/index.h" +#include "catalog/indexing.h" +#include "catalog/objectaccess.h" +#include "catalog/oid_dispatch.h" +#include "catalog/pg_collation.h" +#include "catalog/pg_directory_table.h" +#include "catalog/pg_opclass.h" +#include "catalog/pg_proc.h" +#include "catalog/pg_tablespace.h" +#include "catalog/pg_type.h" +#include "catalog/pg_user_mapping.h" +#include "catalog/storage_directory_table.h" +#include "cdb/cdbdisp_query.h" +#include "cdb/cdbdispatchresult.h" +#include "cdb/cdboidsync.h" +#include "cdb/cdbvars.h" +#include "commands/defrem.h" +#include "commands/dirtablecmds.h" +#include "commands/tablespace.h" +#include "miscadmin.h" +#include "nodes/makefuncs.h" +#include "parser/parse_func.h" +#include "storage/ufile.h" +#include "tcop/utility.h" +#include "utils/acl.h" +#include "utils/builtins.h" +#include "utils/faultinjector.h" +#include "utils/lsyscache.h" +#include "utils/rel.h" +#include "utils/syscache.h" +#include "libpq-fe.h" +#include "cdb/cdbdisp_query.h" +#include "cdb/cdbdispatchresult.h" +#include "cdb/cdbvars.h" +#include "funcapi.h" + +typedef struct TableFunctionContext +{ + Relation relation; + TableScanDesc scanDesc; + TupleTableSlot *slot; + DirectoryTable *dirTable; +} TableFunctionContext; + +Datum directory_table(PG_FUNCTION_ARGS); + +static Oid +chooseTableSpace(CreateDirectoryTableStmt *stmt) +{ + Oid tablespaceId = InvalidOid; + + /* + * Select tablespace to use: an explicitly indicated one, or (in the case + * of a partitioned table) the parent's, if it has one. + */ + if (stmt->tablespacename) + { + /* + * Tablespace specified on the command line, or was passed down by + * dispatch. + */ + tablespaceId = get_tablespace_oid(stmt->tablespacename, false); + } + + /* still nothing? use the default */ + if (!OidIsValid(tablespaceId)) + tablespaceId = GetDefaultTablespace(stmt->base.relation->relpersistence, false); + + if (!OidIsValid(tablespaceId)) + tablespaceId = tablespaceId ? tablespaceId : MyDatabaseTableSpace; + + /* Check permissions except when using database's default */ + if (OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace) + { + AclResult aclresult; + + aclresult = pg_tablespace_aclcheck(tablespaceId, GetUserId(), + ACL_CREATE); + if (aclresult != ACLCHECK_OK) + aclcheck_error(aclresult, OBJECT_TABLESPACE, + get_tablespace_name(tablespaceId)); + } + + /* In all cases disallow placing user relations in pg_global */ + if (tablespaceId == GLOBALTABLESPACE_OID) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("only shared relations can be placed in pg_global tablespace"))); + + return tablespaceId; +} + +void +CreateDirectoryTable(CreateDirectoryTableStmt *stmt, Oid relId) +{ + Relation dirRelation; + Datum values[Natts_pg_directory_table]; + bool nulls[Natts_pg_directory_table]; + HeapTuple tuple; + char *dirTablePath; + Form_pg_class pg_class_tuple; + HeapTuple class_tuple; + Oid spcId = chooseTableSpace(stmt); + RelFileNode relFileNode = {0}; + + class_tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relId)); + if (!HeapTupleIsValid(class_tuple)) + elog(ERROR, "cache lookup failed for relation %u", relId); + pg_class_tuple = (Form_pg_class) GETSTRUCT(class_tuple); + + relFileNode.spcNode = spcId; + relFileNode.dbNode = MyDatabaseId; + relFileNode.relNode = pg_class_tuple->relfilenode; + dirTablePath = UFileFormatPathName(&relFileNode); + + ReleaseSysCache(class_tuple); + + /* + * Acquire DirectoryTableLock to ensure that no DROP DIRECTORY TABLE + * or CREATE DIRECTORY TABLE is running concurrently. + */ + LWLockAcquire(DirectoryTableLock, LW_EXCLUSIVE); + + UFileEnsurePath(spcId, dirTablePath); + + /* + * Advance command counter to ensure the pg_attribute tuple is visible; + * the tuple might be updated to add constraints in previous step. + */ + CommandCounterIncrement(); + + dirRelation = table_open(DirectoryTableRelationId, RowExclusiveLock); + /* + * Insert tuple into pg_directory_table. + */ + memset(values, 0, sizeof(values)); + memset(nulls, false, sizeof(nulls)); + + values[Anum_pg_directory_table_dttablespace - 1] = spcId; + values[Anum_pg_directory_table_dtrelid - 1] = ObjectIdGetDatum(relId); + values[Anum_pg_directory_table_dtlocation - 1] = CStringGetTextDatum(dirTablePath); + + tuple = heap_form_tuple(dirRelation->rd_att, values, nulls); + + CatalogTupleInsert(dirRelation, tuple); + + heap_freetuple(tuple); + + table_close(dirRelation, RowExclusiveLock); + + LWLockRelease(DirectoryTableLock); +} + +static Datum +getFileContent(Oid spcId, char *scopedFileUrl) +{ + char errorMessage[256]; + char buffer[4096]; + char *data; + int curPos = 0; + int bytesRead; + bytea *content; + UFile *file; + int64 fileSize; + + file = UFileOpen(spcId, + scopedFileUrl, + O_RDONLY, + errorMessage, + sizeof(errorMessage)); + + if (file == NULL) + ereport(ERROR, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("failed to open file \"%s\": %s,", scopedFileUrl, errorMessage))); + + fileSize = UFileSize(file); + if (fileSize > MaxAllocSize - VARHDRSZ) + ereport(ERROR, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("out of memory"))); + + content = (bytea *) palloc(fileSize + VARHDRSZ); + SET_VARSIZE(content, fileSize + VARHDRSZ); + data = VARDATA(content); + + while (true) + { + bytesRead = UFileRead(file, buffer, sizeof(buffer)); + if (bytesRead == -1) + ereport(ERROR, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("failed to read file \"%s\": %s", scopedFileUrl, UFileGetLastError(file)))); + + if (bytesRead == 0) + break; + + memcpy(data + curPos, buffer, bytesRead); + curPos += bytesRead; + } + + UFileClose(file); + + PG_RETURN_BYTEA_P(content); +} + +static char * +getScopedFileUrl(DirectoryTable *dirTable, char *relativePath) +{ + return psprintf("%s/%s", dirTable->location, relativePath); +} + +Datum +directory_table(PG_FUNCTION_ARGS) +{ +#define DIRECTORY_TABLE_FUNCTION_COLUMNS 7 + Oid relId = PG_GETARG_OID(0); + Datum values[DIRECTORY_TABLE_FUNCTION_COLUMNS]; + bool nulls[DIRECTORY_TABLE_FUNCTION_COLUMNS]; + HeapTuple tuple; + Datum result; + FuncCallContext *funcCtx; + TableFunctionContext *context; + + if (SRF_IS_FIRSTCALL()) + { + Snapshot snapshot; + TupleDesc newTupDesc; + MemoryContext oldContext; + + funcCtx = SRF_FIRSTCALL_INIT(); + + oldContext = MemoryContextSwitchTo(funcCtx->multi_call_memory_ctx); + + newTupDesc = CreateTemplateTupleDesc(DIRECTORY_TABLE_FUNCTION_COLUMNS); + TupleDescInitEntry(newTupDesc, (AttrNumber) 1, "scoped_file_url", TEXTOID, -1, 0); + TupleDescInitEntry(newTupDesc, (AttrNumber) 2, "relative_path", TEXTOID, -1, 0); + TupleDescInitEntry(newTupDesc, (AttrNumber) 3, "tag", TEXTOID, -1, 0); + TupleDescInitEntry(newTupDesc, (AttrNumber) 4, "size", INT8OID, -1, 0); + TupleDescInitEntry(newTupDesc, (AttrNumber) 5, "last_modified", TIMESTAMPTZOID, -1, 0); + TupleDescInitEntry(newTupDesc, (AttrNumber) 6, "md5", TEXTOID, -1, 0); + TupleDescInitEntry(newTupDesc, (AttrNumber) 7, "content", BYTEAOID, -1, 0); + + funcCtx->tuple_desc = BlessTupleDesc(newTupDesc); + + context = (TableFunctionContext *) palloc0(sizeof(TableFunctionContext)); + context->relation = table_open(relId, AccessShareLock); + + SIMPLE_FAULT_INJECTOR("directory_table_inject"); + + if (!RelationIsDirectoryTable(relId)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("'%s' is not a directory table", + RelationGetRelationName(context->relation)))); + + context->slot = MakeSingleTupleTableSlot(RelationGetDescr(context->relation), + table_slot_callbacks(context->relation)); + context->dirTable = GetDirectoryTable(RelationGetRelid(context->relation)); + + snapshot = GetLatestSnapshot(); + context->scanDesc = table_beginscan(context->relation, snapshot, 0, NULL); + + funcCtx->user_fctx = (void *) context; + + MemoryContextSwitchTo(oldContext); + } + + funcCtx = SRF_PERCALL_SETUP(); + context = (TableFunctionContext *) funcCtx->user_fctx; + + if (table_scan_getnextslot(context->scanDesc, ForwardScanDirection, context->slot)) + { + Datum attrRelativePath; + Datum attrSize; + Datum attrLastModified; + Datum attrMd5Sum; + Datum attrTags; + bool isNull; + char *scopedFileUrl; + + slot_getallattrs(context->slot); + + attrRelativePath = slot_getattr(context->slot, 1, &isNull); + Assert(isNull == false); + attrSize = slot_getattr(context->slot, 2, &isNull); + Assert(isNull == false); + attrLastModified = slot_getattr(context->slot, 3, &isNull); + Assert(isNull == false); + attrMd5Sum = slot_getattr(context->slot, 4, &isNull); + Assert(isNull == false); + attrTags = slot_getattr(context->slot, 5, &isNull); + + MemSet(values, 0, sizeof(values)); + MemSet(nulls, 0, sizeof(nulls)); + + scopedFileUrl = getScopedFileUrl(context->dirTable, TextDatumGetCString(attrRelativePath)); + + values[0] = PointerGetDatum(cstring_to_text(scopedFileUrl)); + values[1] = attrRelativePath; + values[2] = attrTags; + nulls[2] = isNull; + values[3] = attrSize; + values[4] = attrLastModified; + values[5] = attrMd5Sum; + values[6] = getFileContent(context->dirTable->spcId, scopedFileUrl); + + tuple = heap_form_tuple(funcCtx->tuple_desc, values, nulls); + result = HeapTupleGetDatum(tuple); + + SRF_RETURN_NEXT(funcCtx, result); + } + + table_endscan(context->scanDesc); + ExecDropSingleTupleTableSlot(context->slot); + table_close(context->relation, AccessShareLock); + + pfree(context); + funcCtx->user_fctx = NULL; + + SRF_RETURN_DONE(funcCtx); +} + +Datum +remove_file_segment(PG_FUNCTION_ARGS) +{ + Relation relation; + ScanKeyData scankey; + SysScanDesc scan; + HeapTuple tuple; + Oid indexOid; + List *indexOids; + Oid relId; + char *relativePath; + char *fullPathName; + bool exist = false; + DirectoryTable *dirTable; + + if (PG_ARGISNULL(0)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("relation name cannot be NULL"))); + relId = PG_GETARG_OID(0); + + if (PG_ARGISNULL(1)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("file path cannot be null"))); + relativePath = PG_GETARG_CSTRING(1); + + dirTable = GetDirectoryTable(relId); + relation = table_open(relId, AccessExclusiveLock); + + SIMPLE_FAULT_INJECTOR("remove_file_inject"); + + indexOids = RelationGetIndexList(relation); + Assert(list_length(indexOids) == 1); + + indexOid = list_nth_oid(indexOids, 0); + ScanKeyInit(&scankey, + 1, /* relative_path */ + BTEqualStrategyNumber, F_TEXTEQ, + CStringGetTextDatum(relativePath)); + + scan = systable_beginscan(relation, indexOid, true, NULL, 1, &scankey); + tuple = systable_getnext(scan); + if (HeapTupleIsValid(tuple)) + { + CatalogTupleDelete(relation, &tuple->t_self); + fullPathName = psprintf("%s/%s", dirTable->location, relativePath); + UFileAddDeletePendingEntry(relation, dirTable->spcId, fullPathName); + exist = true; + } + + systable_endscan(scan); + list_free(indexOids); + + table_close(relation, NoLock); + + PG_RETURN_BOOL(exist); +} + +Datum +remove_file(PG_FUNCTION_ARGS) +{ + Relation relation; + Oid relId; + char *relativePath; + char *query; + int numDeletes; + int i; + CdbPgResults cdbPgresults = {NULL, 0}; + + if (PG_ARGISNULL(0)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("relation name cannot be NULL"))); + relId = PG_GETARG_OID(0); + + if (PG_ARGISNULL(1)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("file path cannot be null"))); + relativePath = PG_GETARG_CSTRING(1); + + relation = table_open(relId, AccessExclusiveLock); + + if (Gp_role != GP_ROLE_DISPATCH) + ereport(ERROR, + (errcode(ERRCODE_GP_COMMAND_ERROR), + errmsg("remove_file() could only be called on QD"))); + + query = psprintf("select pg_catalog.remove_file_segment(%u, '%s')", relId, relativePath); + + CdbDispatchCommand(query, DF_WITH_SNAPSHOT | DF_CANCEL_ON_ERROR, &cdbPgresults); + + numDeletes = 0; + for (i = 0; i < cdbPgresults.numResults; i++) + { + Datum value; + struct pg_result *pgresult = cdbPgresults.pg_results[i]; + + if (PQresultStatus(pgresult) != PGRES_TUPLES_OK) + { + cdbdisp_clearCdbPgResults(&cdbPgresults); + ereport(ERROR, + (errmsg("unexpected result from segment: %d", PQresultStatus(pgresult)))); + } + + if (PQntuples(pgresult) != 1 || PQnfields(pgresult) != 1) + { + cdbdisp_clearCdbPgResults(&cdbPgresults); + ereport(ERROR, + (errmsg("unexpected shape of result from segment (%d rows, %d cols)", + PQntuples(pgresult), PQnfields(pgresult)))); + } + if (PQgetisnull(pgresult, 0, 0)) + value = 0; + else + value = DirectFunctionCall1(boolin, + CStringGetDatum(PQgetvalue(pgresult, 0, 0))); + + numDeletes += value; + } + + cdbdisp_clearCdbPgResults(&cdbPgresults); + + table_close(relation, NoLock); + + PG_RETURN_BOOL(numDeletes > 0); +} diff --git a/src/backend/commands/dropcmds.c b/src/backend/commands/dropcmds.c index a6ddfa17b39..8e39c30699a 100644 --- a/src/backend/commands/dropcmds.c +++ b/src/backend/commands/dropcmds.c @@ -456,6 +456,10 @@ does_not_exist_skipping(ObjectType objtype, Node *object) msg = gettext_noop("server \"%s\" does not exist, skipping"); name = strVal((Value *) object); break; + case OBJECT_STORAGE_SERVER: + msg = gettext_noop("storage server \"%s\" does not exist, skipping"); + name = strVal((Value *) object); + break; case OBJECT_OPCLASS: { List *opcname = list_copy_tail(castNode(List, object), 1); diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c index 8b2994a3448..0b984fbb431 100644 --- a/src/backend/commands/event_trigger.c +++ b/src/backend/commands/event_trigger.c @@ -942,6 +942,8 @@ EventTriggerSupportsObjectType(ObjectType obtype) case OBJECT_TABLESPACE: case OBJECT_ROLE: case OBJECT_PROFILE: + case OBJECT_STORAGE_SERVER: + case OBJECT_STORAGE_USER_MAPPING: /* no support for global objects */ return false; case OBJECT_EVENT_TRIGGER: @@ -958,6 +960,7 @@ EventTriggerSupportsObjectType(ObjectType obtype) case OBJECT_CONVERSION: case OBJECT_DEFACL: case OBJECT_DEFAULT: + case OBJECT_DIRECTORY_TABLE: case OBJECT_DOMAIN: case OBJECT_DOMCONSTRAINT: case OBJECT_EXTENSION: @@ -1025,6 +1028,8 @@ EventTriggerSupportsObjectClass(ObjectClass objclass) case OCLASS_ROLE: case OCLASS_PROFILE: case OCLASS_PASSWORDHISTORY: + case OCLASS_STORAGE_SERVER: + case OCLASS_STORAGE_USER_MAPPING: /* no support for global objects */ return false; case OCLASS_EVENT_TRIGGER: @@ -1064,6 +1069,7 @@ EventTriggerSupportsObjectClass(ObjectClass objclass) case OCLASS_PUBLICATION_REL: case OCLASS_SUBSCRIPTION: case OCLASS_TRANSFORM: + case OCLASS_DIRTABLE: return true; case OCLASS_EXTPROTOCOL: case OCLASS_TASK: @@ -2115,6 +2121,8 @@ stringify_grant_objtype(ObjectType objtype) return "FOREIGN DATA WRAPPER"; case OBJECT_FOREIGN_SERVER: return "FOREIGN SERVER"; + case OBJECT_STORAGE_SERVER: + return "STORAGE SERVER"; case OBJECT_FUNCTION: return "FUNCTION"; case OBJECT_LANGUAGE: @@ -2166,11 +2174,13 @@ stringify_grant_objtype(ObjectType objtype) case OBJECT_TSPARSER: case OBJECT_TSTEMPLATE: case OBJECT_USER_MAPPING: + case OBJECT_STORAGE_USER_MAPPING: case OBJECT_VIEW: case OBJECT_EXTPROTOCOL: case OBJECT_RESQUEUE: case OBJECT_RESGROUP: case OBJECT_PROFILE: + case OBJECT_DIRECTORY_TABLE: elog(ERROR, "unsupported object type: %d", (int) objtype); } @@ -2201,6 +2211,8 @@ stringify_adefprivs_objtype(ObjectType objtype) return "FOREIGN DATA WRAPPERS"; case OBJECT_FOREIGN_SERVER: return "FOREIGN SERVERS"; + case OBJECT_STORAGE_SERVER: + return "STORAGE SERVERS"; case OBJECT_FUNCTION: return "FUNCTIONS"; case OBJECT_LANGUAGE: @@ -2252,11 +2264,13 @@ stringify_adefprivs_objtype(ObjectType objtype) case OBJECT_TSPARSER: case OBJECT_TSTEMPLATE: case OBJECT_USER_MAPPING: + case OBJECT_STORAGE_USER_MAPPING: case OBJECT_VIEW: case OBJECT_EXTPROTOCOL: case OBJECT_RESQUEUE: case OBJECT_RESGROUP: case OBJECT_PROFILE: + case OBJECT_DIRECTORY_TABLE: elog(ERROR, "unsupported object type: %d", (int) objtype); } diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index a6db5e14fd9..9066ce3bb40 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -31,6 +31,7 @@ #include "catalog/indexing.h" #include "catalog/pg_am.h" #include "catalog/pg_constraint.h" +#include "catalog/pg_directory_table.h" #include "catalog/pg_inherits.h" #include "catalog/pg_opclass.h" #include "catalog/pg_opfamily.h" @@ -704,6 +705,9 @@ DefineIndex(Oid relationId, bool shouldDispatch; Oid blkdirrelid = InvalidOid; + if (RelationIsDirectoryTable(relationId)) + elog(ERROR, "Disallowed to create index on directory table \"%s\".", get_rel_name(relationId)); + shouldDispatch = (Gp_role == GP_ROLE_DISPATCH && ENABLE_DISPATCH() && !IsBootstrapProcessingMode()); @@ -847,6 +851,7 @@ DefineIndex(Oid relationId, case RELKIND_RELATION: case RELKIND_MATVIEW: case RELKIND_PARTITIONED_TABLE: + case RELKIND_DIRECTORY_TABLE: /* OK */ break; case RELKIND_FOREIGN_TABLE: @@ -3507,6 +3512,7 @@ ReindexMultipleTables(ReindexStmt *stmt, ReindexParams *params) * are processed. */ if (classtuple->relkind != RELKIND_RELATION && + classtuple->relkind != RELKIND_DIRECTORY_TABLE && classtuple->relkind != RELKIND_MATVIEW) continue; @@ -3967,6 +3973,7 @@ ReindexRelationConcurrently(ReindexStmt *stmt, Oid relationOid, ReindexParams *p case RELKIND_RELATION: case RELKIND_MATVIEW: case RELKIND_TOASTVALUE: + case RELKIND_DIRECTORY_TABLE: { /* * In the case of a relation, find all its indexes including diff --git a/src/backend/commands/seclabel.c b/src/backend/commands/seclabel.c index 487ef4417b2..a0dd92b2e04 100644 --- a/src/backend/commands/seclabel.c +++ b/src/backend/commands/seclabel.c @@ -41,6 +41,7 @@ SecLabelSupportsObjectType(ObjectType objtype) case OBJECT_AGGREGATE: case OBJECT_COLUMN: case OBJECT_DATABASE: + case OBJECT_DIRECTORY_TABLE: case OBJECT_DOMAIN: case OBJECT_EVENT_TRIGGER: case OBJECT_FOREIGN_TABLE: @@ -95,6 +96,8 @@ SecLabelSupportsObjectType(ObjectType objtype) case OBJECT_EXTPROTOCOL: case OBJECT_RESQUEUE: case OBJECT_RESGROUP: + case OBJECT_STORAGE_SERVER: + case OBJECT_STORAGE_USER_MAPPING: return false; /* @@ -190,6 +193,7 @@ ExecSecLabelStmt(SecLabelStmt *stmt) relation->rd_rel->relkind != RELKIND_MATVIEW && relation->rd_rel->relkind != RELKIND_COMPOSITE_TYPE && relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE && + relation->rd_rel->relkind != RELKIND_DIRECTORY_TABLE && relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), diff --git a/src/backend/commands/statscmds.c b/src/backend/commands/statscmds.c index fb2251b6291..00869b12115 100644 --- a/src/backend/commands/statscmds.c +++ b/src/backend/commands/statscmds.c @@ -135,6 +135,7 @@ CreateStatistics(CreateStatsStmt *stmt) /* Restrict to allowed relation types */ if (rel->rd_rel->relkind != RELKIND_RELATION && + rel->rd_rel->relkind != RELKIND_DIRECTORY_TABLE && rel->rd_rel->relkind != RELKIND_MATVIEW && rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE && rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE) diff --git a/src/backend/commands/storagecmds.c b/src/backend/commands/storagecmds.c new file mode 100644 index 00000000000..249cf56a812 --- /dev/null +++ b/src/backend/commands/storagecmds.c @@ -0,0 +1,957 @@ +/*------------------------------------------------------------------------- + * + * storagecmds.c + * storage server/user_mapping creation/manipulation commands + * + * Copyright (c) 2016-Present Hashdata, Inc. + * + * + * IDENTIFICATION + * src/backend/commands/storagecmds.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "access/htup_details.h" +#include "access/reloptions.h" +#include "access/table.h" +#include "catalog/dependency.h" +#include "catalog/gp_storage_server.h" +#include "catalog/gp_storage_user_mapping.h" +#include "catalog/objectaccess.h" +#include "catalog/oid_dispatch.h" +#include "cdb/cdbdisp_query.h" +#include "cdb/cdbvars.h" +#include "commands/defrem.h" +#include "commands/storagecmds.h" +#include "executor/execdesc.h" +#include "nodes/pg_list.h" +#include "utils/acl.h" +#include "utils/builtins.h" +#include "utils/syscache.h" + +Oid +get_storage_server_oid(const char *servername, bool missing_ok) +{ + Oid oid; + + oid = GetSysCacheOid1(STORAGESERVERNAME, Anum_gp_storage_server_oid, + CStringGetDatum(servername)); + + if (!OidIsValid(oid) && !missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("server \"%s\" does not exist", servername))); + return oid; +} + +/* + * GetStorageServerExtended - look up the storage server definition. If + * flags uses FSV_MISSING_OK, return NULL if the object cannot be found + * instead of raising an error. + */ +StorageServer * +GetStorageServerExtended(Oid serverid, bits16 flags) +{ + Form_gp_storage_server serverform; + StorageServer *server; + HeapTuple tp; + Datum datum; + bool isnull; + + tp = SearchSysCache1(STORAGESERVEROID, ObjectIdGetDatum(serverid)); + + if (!HeapTupleIsValid(tp)) + { + if ((flags & SSV_MISSING_OK) == 0) + elog(ERROR, "cache lookup failed for storage server %u", serverid); + return NULL; + } + + serverform = (Form_gp_storage_server) GETSTRUCT(tp); + + server = (StorageServer *) palloc(sizeof(StorageServer)); + server->serverid = serverid; + server->servername = pstrdup(NameStr(serverform->srvname)); + server->owner = serverform->srvowner; + + /* Extract the srvoptions */ + datum = SysCacheGetAttr(STORAGESERVEROID, + tp, + Anum_gp_storage_server_srvoptions, + &isnull); + if (isnull) + server->options = NIL; + else + server->options = untransformRelOptions(datum); + + ReleaseSysCache(tp); + + return server; +} + +/* + * GetStorageServer - look up the storage server definition. + */ +StorageServer * +GetStorageServer(Oid serverid) +{ + return GetStorageServerExtended(serverid, 0); +} + +/* + * GetStorageServerByName - look up the storage server definition by name. + */ +StorageServer * +GetStorageServerByName(const char *srvname, bool missing_ok) +{ + Oid serverid = get_storage_server_oid(srvname, missing_ok); + + if (!OidIsValid(serverid)) + return NULL; + + return GetStorageServer(serverid); +} + +/* + * GetStorgeUserMapping - look up the storage user mapping. + * + * If no mapping is found for the supplied user, we also look for + * PUBLIC mappings (userid == InvalidOid). + */ +StorageUserMapping * +GetStorageUserMapping(Oid userid, Oid serverid) +{ + Datum datum; + HeapTuple tp; + bool isnull; + StorageUserMapping *um; + + tp = SearchSysCache2(STORAGEUSERMAPPINGUSERSERVER, + ObjectIdGetDatum(userid), + ObjectIdGetDatum(serverid)); + + if (!HeapTupleIsValid(tp)) + { + /* Not found for the specific user -- try PUBLIC */ + tp = SearchSysCache2(STORAGEUSERMAPPINGUSERSERVER, + ObjectIdGetDatum(InvalidOid), + ObjectIdGetDatum(serverid)); + } + + if (!HeapTupleIsValid(tp)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("storage user mapping not found for \"%s\"", + StorageMappingUserName(userid)))); + + um = (StorageUserMapping *) palloc(sizeof(StorageUserMapping)); + um->umid = ((Form_gp_storage_user_mapping) GETSTRUCT(tp))->oid; + um->userid = userid; + um->serverid = serverid; + + /* Extract the umoptions */ + datum = SysCacheGetAttr(STORAGEUSERMAPPINGUSERSERVER, + tp, + Anum_gp_storage_user_mapping_umoptions, + &isnull); + if (isnull) + um->options = NIL; + else + um->options = untransformRelOptions(datum); + + ReleaseSysCache(tp); + + return um; +} + + +/* + * Convert a DefElem list to the text array format that is used in + * gp_storage_server, gp_storage_user_mapping. + * + * Returns the array in the form of a Datum, or PointerGetDatum(NULL) + * if the list is empty. + * + * Note: The array is usually stored to database without further + * processing, hence any validation should be done before this + * conversion. + */ +static Datum +optionListToArray(List *options) +{ + ArrayBuildState *astate = NULL; + ListCell *cell; + + foreach(cell, options) + { + DefElem *def = lfirst(cell); + const char *value; + Size len; + text *t; + + value = defGetString(def); + len = VARHDRSZ + strlen(def->defname) + 1 + strlen(value); + t = palloc(len + 1); + SET_VARSIZE(t, len); + sprintf(VARDATA(t), "%s=%s", def->defname, value); + + astate = accumArrayResult(astate, PointerGetDatum(t), + false, TEXTOID, + CurrentMemoryContext); + } + + if (astate) + return makeArrayResult(astate, CurrentMemoryContext); + + return PointerGetDatum(NULL); +} + +/* + * Transform a list of DefElem into text array format. This is substantially + * the same thing as optionListToArray(), except we recognize SET/ADD/DROP + * actions for modifying an existing list of options, which is passed in + * Datum form as oldOptions. + * + * Returns the array in the form of a Datum, or PointerGetDatum(NULL) + * if the list is empty. + * + * This is used by CREATE/ALTER of STORAGE SERVER/USER MAPPING + */ +Datum +transformStorageGenericOptions(Oid catalogId, + Datum oldOptions, + List *options) +{ + List *resultOptions = untransformRelOptions(oldOptions); + ListCell *optcell; + Datum result; + + foreach(optcell, options) + { + DefElem *od = lfirst(optcell); + ListCell *cell; + + /* + * Find the element in resultOptions. We need this for validation in + * all cases. + */ + foreach(cell, resultOptions) + { + DefElem *def = lfirst(cell); + + if (strcmp(def->defname, od->defname) == 0) + break; + } + + /* + * It is possible to perform multiple SET/DROP actions on the same + * option. The standard permits this, as long as the options to be + * added are unique. Note that an unspecified action is taken to be + * ADD. + */ + switch (od->defaction) + { + case DEFELEM_DROP: + if (!cell) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("option \"%s\" not found", + od->defname))); + resultOptions = list_delete_cell(resultOptions, cell); + break; + + case DEFELEM_SET: + if (!cell) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("option \"%s\" not found", + od->defname))); + lfirst(cell) = od; + break; + + case DEFELEM_ADD: + case DEFELEM_UNSPEC: + if (cell) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("option \"%s\" provided more than once", + od->defname))); + resultOptions = lappend(resultOptions, od); + break; + + default: + elog(ERROR, "unrecognized action %d on option \"%s\"", + (int) od->defaction, od->defname); + break; + } + } + + result = optionListToArray(resultOptions); + + return result; +} + +/* + * Common routine to check permission for storage-user-mapping-related DDL + * commands. We allow server owners to operate on any mapping, and + * users to operate on their own mapping. + */ +static void +storage_user_mapping_ddl_aclcheck(Oid umuserid, Oid serverid, const char *servername) +{ + Oid curuserid = GetUserId(); + + if (!gp_storage_server_ownercheck(serverid, curuserid)) + { + if (umuserid == curuserid) + { + AclResult aclresult; + + aclresult = gp_storage_server_aclcheck(serverid, curuserid, ACL_USAGE); + if (aclresult != ACLCHECK_OK) + aclcheck_error(aclresult, OBJECT_STORAGE_SERVER, servername); + } + else + aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_STORAGE_SERVER, + servername); + } +} + +/* + * Create a storage server + */ +ObjectAddress +CreateStorageServer(CreateStorageServerStmt *stmt) +{ + Relation rel; + Datum srvoptions; + Datum values[Natts_gp_storage_server]; + bool nulls[Natts_gp_storage_server]; + HeapTuple tuple; + Oid srvId; + Oid ownerId; + ObjectAddress myself = {0}; + + rel = table_open(StorageServerRelationId, RowExclusiveLock); + + /* For now the owner cannot be specified on create. Use effective user ID. */ + ownerId = GetUserId(); + + /* + * Check that there is no other storage server by this name. Do nothing if + * IF NOT EXISTS was enforced. + */ + if (GetStorageServerByName(stmt->servername, true) != NULL) + { + if (stmt->if_not_exists) + { + ereport(NOTICE, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("storage server \"%s\" already exists, skipping", + stmt->servername))); + table_close(rel, RowExclusiveLock); + return InvalidObjectAddress; + } + else + { + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("storage server \"%s\" already exists", + stmt->servername))); + } + } + + /* + * Insert tuple into gp_storage_server. + */ + memset(values, 0, sizeof(values)); + memset(nulls, false, sizeof(nulls)); + + srvId = GetNewOidForStorageServer(rel, StorageServerOidIndexId, + Anum_gp_storage_server_oid, + stmt->servername); + values[Anum_gp_storage_server_oid - 1] = ObjectIdGetDatum(srvId); + values[Anum_gp_storage_server_srvname - 1] = + DirectFunctionCall1(namein, CStringGetDatum(stmt->servername)); + values[Anum_gp_storage_server_srvowner -1] = ObjectIdGetDatum(ownerId); + /* Start with a blank acl */ + nulls[Anum_gp_storage_server_srvacl - 1] = true; + + /* Add storage server options */ + srvoptions = transformStorageGenericOptions(StorageServerRelationId, + PointerGetDatum(NULL), + stmt->options); + + if (PointerIsValid(DatumGetPointer(srvoptions))) + values[Anum_gp_storage_server_srvoptions - 1] = srvoptions; + else + nulls[Anum_gp_storage_server_srvoptions - 1] = true; + + tuple = heap_form_tuple(rel->rd_att, values, nulls); + + CatalogTupleInsert(rel, tuple); + + heap_freetuple(tuple); + + /* Post creation hook for new storage server */ + InvokeObjectPostCreateHook(StorageServerRelationId, srvId, 0); + + if (Gp_role == GP_ROLE_DISPATCH) + { + CdbDispatchUtilityStatement((Node *) stmt, + DF_WITH_SNAPSHOT | DF_CANCEL_ON_ERROR | DF_NEED_TWO_PHASE, + GetAssignedOidsForDispatch(), + NULL); + } + + table_close(rel, RowExclusiveLock); + + return myself; +} + +/* + * Alter Storage Server + */ +ObjectAddress +AlterStorageServer(AlterStorageServerStmt *stmt) +{ + Relation rel; + HeapTuple tp; + Datum repl_val[Natts_gp_storage_server]; + bool repl_null[Natts_gp_storage_server]; + bool repl_repl[Natts_gp_storage_server]; + Oid srvId; + Form_gp_storage_server srvForm; + ObjectAddress address = {0}; + + rel = table_open(StorageServerRelationId, RowExclusiveLock); + + tp = SearchSysCacheCopy1(STORAGESERVERNAME, + CStringGetDatum(stmt->servername)); + + if (!HeapTupleIsValid(tp)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("storage server \"%s\" does not exist", stmt->servername))); + + srvForm = (Form_gp_storage_server) GETSTRUCT(tp); + srvId = srvForm->oid; + + /* + * Only owner or a superuser can ALTER a STORAGE SERVER. + */ + if (!gp_storage_server_ownercheck(srvId, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_STORAGE_SERVER, + stmt->servername); + + memset(repl_val, 0, sizeof(repl_val)); + memset(repl_null, false, sizeof(repl_null)); + memset(repl_repl, false, sizeof(repl_repl)); + + if (stmt->options) + { + Datum datum; + bool isnull; + + /* Extract the current srvoptions */ + datum = SysCacheGetAttr(STORAGESERVEROID, + tp, + Anum_gp_storage_server_srvoptions, + &isnull); + if (isnull) + datum = PointerGetDatum(NULL); + + /* Prepare the options array */ + datum = transformStorageGenericOptions(StorageServerRelationId, + datum, + stmt->options); + if (PointerIsValid(DatumGetPointer(datum))) + repl_val[Anum_gp_storage_server_srvoptions - 1] = datum; + else + repl_null[Anum_gp_storage_server_srvoptions - 1] = true; + + repl_repl[Anum_gp_storage_server_srvoptions - 1] = true; + } + /* Everything looks good - update the tuple */ + tp = heap_modify_tuple(tp, RelationGetDescr(rel), + repl_val, repl_null, repl_repl); + + CatalogTupleUpdate(rel, &tp->t_self, tp); + + InvokeObjectPostAlterHook(StorageServerRelationId, srvId, 0); + + ObjectAddressSet(address, StorageServerRelationId, srvId); + + heap_freetuple(tp); + + if (Gp_role == GP_ROLE_DISPATCH) + { + CdbDispatchUtilityStatement((Node *) stmt, + DF_WITH_SNAPSHOT | DF_CANCEL_ON_ERROR | DF_NEED_TWO_PHASE, + GetAssignedOidsForDispatch(), + NULL); + } + + table_close(rel, RowExclusiveLock); + + return address; +} + +/* + * Remove Storage Server + */ +Oid +RemoveStorageServer(DropStorageServerStmt *stmt) +{ + Relation rel; + Oid serverId; + Oid srvOwnerId; + Oid curuserid; + ScanKeyData scankey; + SysScanDesc sscan; + HeapTuple tuple; + char *detail; + char *detail_log; + + curuserid = GetUserId(); + + rel = table_open(StorageServerRelationId, RowExclusiveLock); + /* + * Check that if the storage server exists. Do nothing if IF NOT + * EXISTS was enforced. + */ + serverId = GetSysCacheOid1(STORAGESERVERNAME, Anum_gp_storage_server_oid, + CStringGetDatum(stmt->servername)); + + if (!OidIsValid(serverId)) + { + if (stmt->missing_ok) + { + ereport(NOTICE, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("storage server \"%s\" not exists, skipping", + stmt->servername))); + table_close(rel, RowExclusiveLock); + return InvalidOid; + } + else + { + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("storage server \"%s\" not exists", + stmt->servername))); + } + } + + srvOwnerId = GetSysCacheOid1(STORAGESERVERNAME, Anum_gp_storage_server_srvowner, + CStringGetDatum(stmt->servername)); + + if (!gp_storage_server_ownercheck(serverId, curuserid)) + { + if (srvOwnerId == curuserid) + { + AclResult aclresult; + + aclresult = gp_storage_server_aclcheck(serverId, curuserid, ACL_USAGE); + if (aclresult != ACLCHECK_OK) + aclcheck_error(aclresult, OBJECT_STORAGE_SERVER, stmt->servername); + } + else + aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_STORAGE_SERVER, + stmt->servername); + } + + ScanKeyInit(&scankey, + Anum_gp_storage_server_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(serverId)); + sscan = systable_beginscan(rel, StorageServerOidIndexId, + true, NULL, 1, &scankey); + + tuple = systable_getnext(sscan); + + /* + * Lock the storage server, so nobody can add dependencies to her while we drop + * her. We keep the lock until the end of transaction. + */ + LockSharedObject(StorageServerRelationId, serverId, 0, AccessExclusiveLock); + + /* Check for pg_shdepend entries depending on this profile */ + if (checkSharedDependencies(StorageServerRelationId, serverId, + &detail, &detail_log)) + ereport(ERROR, + (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST), + errmsg("storage server \"%s\" cannot be dropped because some objects depend on it", + stmt->servername), + errdetail_internal("%s", detail), + errdetail_log("%s", detail_log))); + + CatalogTupleDelete(rel, &tuple->t_self); + + systable_endscan(sscan); + table_close(rel, RowExclusiveLock); + + /* + * Drop hook for the role being removed + */ + InvokeObjectDropHook(StorageServerRelationId, serverId, 0); + + /* + * Delete shared dependency references related to this server object. + */ + deleteSharedDependencyRecordsFor(StorageServerRelationId, serverId, 0); + + if (Gp_role == GP_ROLE_DISPATCH) + { + CdbDispatchUtilityStatement((Node *) stmt, + DF_WITH_SNAPSHOT | DF_CANCEL_ON_ERROR | DF_NEED_TWO_PHASE, + GetAssignedOidsForDispatch(), + NULL); + } + + return serverId; +} + +/* + * Create Storage User Mapping + */ +ObjectAddress +CreateStorageUserMapping(CreateStorageUserMappingStmt *stmt) +{ + Relation rel; + Datum useoptions; + Datum values[Natts_gp_storage_user_mapping]; + bool nulls[Natts_gp_storage_user_mapping]; + HeapTuple tuple; + Oid useId; + Oid umId; + StorageServer *srv; + ObjectAddress myself; + RoleSpec *role = (RoleSpec *) stmt->user; + + rel = table_open(StorageUserMappingRelationId, RowExclusiveLock); + + if (role->roletype == ROLESPEC_PUBLIC) + useId = ACL_ID_PUBLIC; + else + useId = get_rolespec_oid(stmt->user, false); + + /* Check that the server exists. */ + srv = GetStorageServerByName(stmt->servername, false); + + storage_user_mapping_ddl_aclcheck(useId, srv->serverid, stmt->servername); + + /* + * Check that the user mapping is unique within server. + */ + umId = GetSysCacheOid2(STORAGEUSERMAPPINGUSERSERVER, Anum_gp_storage_user_mapping_oid, + ObjectIdGetDatum(useId), + ObjectIdGetDatum(srv->serverid)); + + if (OidIsValid(umId)) + { + if (stmt->if_not_exists) + { + ereport(NOTICE, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("storage user mapping for \"%s\" already exists for storage server \"%s\", skipping", + StorageMappingUserName(useId), + stmt->servername))); + + table_close(rel, RowExclusiveLock); + return InvalidObjectAddress; + } + else + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("storage user mapping for \"%s\" already exists for storage server \"%s\"", + StorageMappingUserName(useId), + stmt->servername))); + } + + /* + * Insert tuple into gp_storage_user_mapping. + */ + memset(values, 0, sizeof(values)); + memset(nulls, 0, sizeof(nulls)); + + umId = GetNewOidForStorageUserMapping(rel, StorageUserMappingOidIndexId, + Anum_gp_storage_user_mapping_oid, + useId, srv->serverid); + values[Anum_gp_storage_user_mapping_oid -1] = ObjectIdGetDatum(umId); + values[Anum_gp_storage_user_mapping_umuser -1] = ObjectIdGetDatum(useId); + values[Anum_gp_storage_user_mapping_umserver - 1] = ObjectIdGetDatum(srv->serverid); + + /* Add user options */ + useoptions = transformStorageGenericOptions(StorageUserMappingRelationId, + PointerGetDatum(NULL), + stmt->options); + + if (PointerIsValid(DatumGetPointer(useoptions))) + values[Anum_gp_storage_user_mapping_umoptions - 1] = useoptions; + else + nulls[Anum_gp_storage_user_mapping_umoptions - 1] = true; + + tuple = heap_form_tuple(rel->rd_att, values, nulls); + + CatalogTupleInsert(rel, tuple); + + heap_freetuple(tuple); + + myself.classId = StorageUserMappingRelationId; + myself.objectId = umId; + myself.objectSubId = 0; + + recordStorageServerDependency(StorageUserMappingRelationId, umId, srv->serverid); + + if (OidIsValid(useId)) + { + /* Record the mapped user dependency */ + recordDependencyOnOwner(StorageUserMappingRelationId, umId, useId); + } + + /* + * Perhaps someday there should be a recordDependencyOnCurrentExtension + * call here; but since roles aren't members of extensions, it seems like + * storage user mappings shouldn't be either. Note that the grammar and pg_dump + * would need to be extended too if we change this. + */ + + /* Post creation hook for new storage user mapping */ + InvokeObjectPostCreateHook(StorageUserMappingRelationId, umId, 0); + + if (Gp_role == GP_ROLE_DISPATCH) + { + CdbDispatchUtilityStatement((Node *) stmt, + DF_WITH_SNAPSHOT | DF_CANCEL_ON_ERROR | DF_NEED_TWO_PHASE, + GetAssignedOidsForDispatch(), + NULL); + } + + table_close(rel, RowExclusiveLock); + + return myself; +} + +/* + * Alter storage user mapping + */ +ObjectAddress +AlterStorageUserMapping(AlterStorageUserMappingStmt *stmt) +{ + Relation rel; + HeapTuple tp; + Datum repl_val[Natts_gp_storage_user_mapping]; + bool repl_null[Natts_gp_storage_user_mapping]; + bool repl_repl[Natts_gp_storage_user_mapping]; + Oid useId; + Oid umId; + StorageServer *srv; + ObjectAddress address; + RoleSpec *role = (RoleSpec *) stmt->user; + + rel = table_open(StorageUserMappingRelationId, RowExclusiveLock); + + if (role->roletype == ROLESPEC_PUBLIC) + useId = ACL_ID_PUBLIC; + else + useId = get_rolespec_oid(stmt->user, false); + + srv = GetStorageServerByName(stmt->servername, false); + + umId = GetSysCacheOid2(STORAGEUSERMAPPINGUSERSERVER, Anum_gp_storage_user_mapping_oid, + ObjectIdGetDatum(useId), + ObjectIdGetDatum(srv->serverid)); + + if (!OidIsValid(umId)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("storage user mapping for \"%s\" does not exist for server \"%s\"", + StorageMappingUserName(useId), stmt->servername))); + + storage_user_mapping_ddl_aclcheck(useId, srv->serverid, stmt->servername); + + tp = SearchSysCacheCopy1(STORAGEUSERMAPPINGOID, ObjectIdGetDatum(umId)); + + if (!HeapTupleIsValid(tp)) + elog(ERROR, "cache lookup failed for storage user mapping %u", umId); + + memset(repl_val, 0, sizeof(repl_val)); + memset(repl_null, false, sizeof(repl_null)); + memset(repl_repl, false, sizeof(repl_repl)); + + if (stmt->options) + { + Datum datum; + bool isnull; + + /* + * Process the options. + */ + datum = SysCacheGetAttr(STORAGEUSERMAPPINGUSERSERVER, + tp, + Anum_gp_storage_user_mapping_umoptions, + &isnull); + + if (isnull) + datum = PointerGetDatum(NULL); + + /* Prepare the options array */ + datum = transformStorageGenericOptions(StorageUserMappingRelationId, + datum, + stmt->options); + + if (PointerIsValid(DatumGetPointer(datum))) + repl_val[Anum_gp_storage_user_mapping_umoptions - 1] = datum; + else + repl_null[Anum_gp_storage_user_mapping_umoptions - 1] = true; + + repl_repl[Anum_gp_storage_user_mapping_umoptions - 1] = true; + } + + /* Everything looks good - update the tuple */ + tp = heap_modify_tuple(tp, RelationGetDescr(rel), + repl_val, repl_null, repl_repl); + + CatalogTupleUpdate(rel, &tp->t_self, tp); + + InvokeObjectPostAlterHook(StorageUserMappingRelationId, + umId, 0); + + ObjectAddressSet(address, StorageUserMappingRelationId, umId); + + heap_freetuple(tp); + + if (Gp_role == GP_ROLE_DISPATCH) + { + CdbDispatchUtilityStatement((Node *) stmt, + DF_WITH_SNAPSHOT | DF_CANCEL_ON_ERROR | DF_NEED_TWO_PHASE, + GetAssignedOidsForDispatch(), + NULL); + } + + table_close(rel, RowExclusiveLock); + + return address; +} + +/* + * Drop storage user mapping + */ +Oid +RemoveStorageUserMapping(DropStorageUserMappingStmt *stmt) +{ + Oid useId; + Oid umId; + StorageServer *srv; + RoleSpec *role = (RoleSpec *) stmt->user; + Relation gp_storage_user_mapping_rel; + ScanKeyData scankey; + SysScanDesc sscan; + HeapTuple tuple; + + if (role->roletype == ROLESPEC_PUBLIC) + useId = ACL_ID_PUBLIC; + else + { + useId = get_rolespec_oid(stmt->user, stmt->missing_ok); + if (!OidIsValid(useId)) + { + /* + * IF EXISTS specified, role not found and not public. Notice this + * and leave. + */ + elog(NOTICE, "role \"%s\" does not exist, skipping", + role->rolename); + return InvalidOid; + } + } + + srv = GetStorageServerByName(stmt->servername, true); + + if (!srv) + { + if (!stmt->missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("storage server \"%s\" does not exist", + stmt->servername))); + /* IF EXISTS, just note it */ + ereport(NOTICE, + (errmsg("storage server \"%s\" does not exist, skipping", + stmt->servername))); + return InvalidOid; + } + + umId = GetSysCacheOid2(STORAGEUSERMAPPINGUSERSERVER, Anum_gp_storage_user_mapping_oid, + ObjectIdGetDatum(useId), + ObjectIdGetDatum(srv->serverid)); + + if (!OidIsValid(umId)) + { + if (!stmt->missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("storage user mapping for \"%s\" does not exist for storage server \"%s\"", + StorageMappingUserName(useId), stmt->servername))); + + /* IF EXISTS specified, just note it */ + ereport(NOTICE, + (errmsg("storage user mapping for \"%s\" does not exist for storage server \"%s\", skipping", + StorageMappingUserName(useId), stmt->servername))); + return InvalidOid; + } + + storage_user_mapping_ddl_aclcheck(useId, srv->serverid, srv->servername); + + gp_storage_user_mapping_rel = table_open(StorageUserMappingRelationId, RowExclusiveLock); + + ScanKeyInit(&scankey, + Anum_gp_storage_user_mapping_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(umId)); + sscan = systable_beginscan(gp_storage_user_mapping_rel, InvalidOid, + false, NULL, 1, &scankey); + + tuple = systable_getnext(sscan); + if (!HeapTupleIsValid(tuple)) + { + if (!stmt->missing_ok) + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("role \"%s\" does not exist", role->rolename))); + } + if (Gp_role != GP_ROLE_EXECUTE) + { + ereport(NOTICE, + (errmsg("role \"%s\" does not exist, skipping", + role->rolename))); + } + } + + CatalogTupleDelete(gp_storage_user_mapping_rel, &tuple->t_self); + + systable_endscan(sscan); + table_close(gp_storage_user_mapping_rel, RowExclusiveLock); + + /* DROP hook for the role being removed */ + InvokeObjectDropHook(StorageUserMappingRelationId, umId, 0); + + /* + * Delete shared dependency references related to this role object. + */ + deleteSharedDependencyRecordsFor(StorageUserMappingRelationId, umId, 0); + + if (Gp_role == GP_ROLE_DISPATCH) + { + CdbDispatchUtilityStatement((Node *) stmt, + DF_WITH_SNAPSHOT | DF_CANCEL_ON_ERROR | DF_NEED_TWO_PHASE, + GetAssignedOidsForDispatch(), + NULL); + } + return umId; +} diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index bfbfd36c904..d4041864640 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -43,6 +43,7 @@ #include "catalog/pg_compression.h" #include "catalog/pg_constraint.h" #include "catalog/pg_depend.h" +#include "catalog/pg_directory_table.h" #include "catalog/pg_foreign_table.h" #include "catalog/pg_inherits.h" #include "catalog/pg_namespace.h" @@ -186,6 +187,12 @@ static const struct dropmsgstrings dropmsgstringarray[] = { gettext_noop("table \"%s\" does not exist, skipping"), gettext_noop("\"%s\" is not a table"), gettext_noop("Use DROP TABLE to remove a table.")}, + {RELKIND_DIRECTORY_TABLE, + ERRCODE_UNDEFINED_TABLE, + gettext_noop("directory table \"%s\" does not exist"), + gettext_noop("directory table \"%s\" does not exist, skipping"), + gettext_noop("\"%s\" is not a directory table"), + gettext_noop("Use DROP DIRECTORY TABLE to remove a directory table.")}, {RELKIND_SEQUENCE, ERRCODE_UNDEFINED_TABLE, gettext_noop("sequence \"%s\" does not exist"), @@ -259,6 +266,7 @@ struct DropRelationCallbackState #define ATT_COMPOSITE_TYPE 0x0010 #define ATT_FOREIGN_TABLE 0x0020 #define ATT_PARTITIONED_INDEX 0x0040 +#define ATT_DIRECTORY_TABLE 0x0080 /* * ForeignTruncateInfo @@ -629,17 +637,25 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, */ schema = NIL; cooked_constraints = NIL; - foreach(listptr, stmt->tableElts) + if (relkind == RELKIND_DIRECTORY_TABLE) { - Node *node = lfirst(listptr); - - if (IsA(node, CookedConstraint)) + schema = GetDirectoryTableSchema(); + stmt->distributedBy = GetDirectoryTableDistributedBy(); + } + else + { + foreach(listptr, stmt->tableElts) { - Assert(Gp_role == GP_ROLE_EXECUTE); - cooked_constraints = lappend(cooked_constraints, node); + Node *node = lfirst(listptr); + + if (IsA(node, CookedConstraint)) + { + Assert(Gp_role == GP_ROLE_EXECUTE); + cooked_constraints = lappend(cooked_constraints, node); + } + else + schema = lappend(schema, node); } - else - schema = lappend(schema, node); } /* @@ -733,6 +749,12 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, inheritOids = lappend_oid(inheritOids, parentOid); } + /* + * Directory table never has partitions. + */ + AssertImply(relkind == RELKIND_DIRECTORY_TABLE, !partitioned); + AssertImply(relkind == RELKIND_DIRECTORY_TABLE, !stmt->inhRelations); + /* * Select tablespace to use: an explicitly indicated one, or (in the case * of a partitioned table) the parent's, if it has one. @@ -803,7 +825,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, * If the statement hasn't specified an access method, but we're defining * a type of relation that needs one, use the default. */ - if (stmt->accessMethod != NULL) + if (stmt->accessMethod != NULL && relkind != RELKIND_DIRECTORY_TABLE) { accessMethod = stmt->accessMethod; @@ -813,6 +835,8 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, errmsg("specifying a table access method is not supported on a partitioned table"))); } + else if (relkind == RELKIND_DIRECTORY_TABLE) + accessMethod = DEFAULT_TABLE_ACCESS_METHOD; else if (relkind == RELKIND_RELATION || relkind == RELKIND_TOASTVALUE || relkind == RELKIND_MATVIEW) @@ -838,7 +862,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, */ if (AMHandlerIsAO(amHandlerOid)) { - Assert(relkind == RELKIND_MATVIEW || relkind == RELKIND_RELATION ); + Assert(relkind == RELKIND_MATVIEW || relkind == RELKIND_RELATION || relkind == RELKIND_DIRECTORY_TABLE); /* * Extract and process any WITH options supplied, otherwise use defaults @@ -1021,7 +1045,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, * This is done in dispatcher (and in utility mode). In QE, we receive * the already-processed options from the QD. */ - if ((relkind == RELKIND_RELATION || relkind == RELKIND_MATVIEW) && + if ((relkind == RELKIND_RELATION || relkind == RELKIND_MATVIEW || relkind == RELKIND_DIRECTORY_TABLE) && Gp_role != GP_ROLE_EXECUTE) { const TableAmRoutine *tam = GetTableAmRoutineByAmId(accessMethodId); @@ -1152,6 +1176,11 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, */ rel = relation_open(relationId, AccessExclusiveLock); + if (relkind == RELKIND_DIRECTORY_TABLE) + { + CreateDirectoryTableIndex(rel); + } + /* * If this is an append-only relation, create the auxliary tables necessary */ @@ -1645,6 +1674,8 @@ RemoveRelations(DropStmt *drop) ListCell *cell; int flags = 0; LOCKMODE lockmode = AccessExclusiveLock; + HeapTuple indexTuple; + Form_pg_index index; /* DROP CONCURRENTLY uses a weaker lock, and has some restrictions */ if (drop->concurrent) @@ -1699,6 +1730,10 @@ RemoveRelations(DropStmt *drop) relkind = RELKIND_FOREIGN_TABLE; break; + case OBJECT_DIRECTORY_TABLE: + relkind = RELKIND_DIRECTORY_TABLE; + break; + default: elog(ERROR, "unrecognized drop object type: %d", (int) drop->removeType); @@ -1747,6 +1782,23 @@ RemoveRelations(DropStmt *drop) continue; } + if (relkind == RELKIND_INDEX) + { + indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(relOid)); + if (!HeapTupleIsValid(indexTuple) && !drop->missing_ok) /* should not happen */ + elog(ERROR, "cache lookup failed for index %u", relOid); + if (HeapTupleIsValid(indexTuple)) + { + index = (Form_pg_index) GETSTRUCT(indexTuple); + if (RelationIsDirectoryTable(index->indrelid)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Disallowed to drop index \"%s\" on directory table \"%s\"", + get_rel_name(index->indexrelid), get_rel_name(index->indrelid)))); + ReleaseSysCache(indexTuple); + } + } + /* * Decide if concurrent mode needs to be used here or not. The * callback retrieved the rel's persistence for us. @@ -2590,6 +2642,13 @@ truncate_check_rel(Oid relid, Form_pg_class reltuple) errmsg("cannot truncate foreign table \"%s\"", relname))); } + else if (reltuple->relkind == RELKIND_DIRECTORY_TABLE) + { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot truncate directory table \"%s\"", + relname))); + } else if (reltuple->relkind != RELKIND_RELATION && reltuple->relkind != RELKIND_PARTITIONED_TABLE && (!IsBinaryUpgrade || ( @@ -4262,6 +4321,11 @@ RenameRelation(RenameStmt *stmt) * if we already acquired AccessExclusiveLock with an index, however. */ relkind = get_rel_relkind(relid); + if (relkind == RELKIND_DIRECTORY_TABLE) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("Rename directory table is not allowed."))); + obj_is_index = (relkind == RELKIND_INDEX || relkind == RELKIND_PARTITIONED_INDEX); if (obj_is_index || is_index_stmt == obj_is_index) @@ -5181,7 +5245,7 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, pass = AT_PASS_DROP; break; case AT_SetStatistics: /* ALTER COLUMN SET STATISTICS */ - ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW | ATT_INDEX | ATT_PARTITIONED_INDEX | ATT_FOREIGN_TABLE); + ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW | ATT_INDEX | ATT_PARTITIONED_INDEX | ATT_FOREIGN_TABLE | ATT_DIRECTORY_TABLE); ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context); /* No command-specific prep needed */ pass = AT_PASS_MISC; @@ -5214,7 +5278,7 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, pass = AT_PASS_DROP; break; case AT_AddIndex: /* ADD INDEX */ - ATSimplePermissions(rel, ATT_TABLE); + ATSimplePermissions(rel, ATT_TABLE | ATT_DIRECTORY_TABLE); /* This command never recurses */ /* No command-specific prep needed */ pass = AT_PASS_ADD_INDEX; @@ -5341,7 +5405,7 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, pass = AT_PASS_MISC; break; } - ATSimplePermissions(rel, ATT_TABLE); + ATSimplePermissions(rel, ATT_TABLE | ATT_DIRECTORY_TABLE); if (!recursing) /* MPP-5772, MPP-5784 */ { @@ -5517,7 +5581,7 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, case AT_DisableTrig: /* DISABLE TRIGGER variants */ case AT_DisableTrigAll: case AT_DisableTrigUser: - ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE); + ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE | ATT_DIRECTORY_TABLE); if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context); pass = AT_PASS_MISC; @@ -5532,7 +5596,7 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, case AT_DisableRowSecurity: case AT_ForceRowSecurity: case AT_NoForceRowSecurity: - ATSimplePermissions(rel, ATT_TABLE); + ATSimplePermissions(rel, ATT_TABLE | ATT_DIRECTORY_TABLE); /* These commands never recurse */ /* No command-specific prep needed */ pass = AT_PASS_MISC; @@ -7399,6 +7463,9 @@ ATSimplePermissions(Relation rel, int allowed_targets) case RELKIND_FOREIGN_TABLE: actual_target = ATT_FOREIGN_TABLE; break; + case RELKIND_DIRECTORY_TABLE: + actual_target = ATT_DIRECTORY_TABLE; + break; case RELKIND_AOSEGMENTS: case RELKIND_AOBLOCKDIR: @@ -7468,7 +7535,7 @@ ATWrongRelkindError(Relation rel, int allowed_targets) case ATT_TABLE | ATT_MATVIEW | ATT_INDEX | ATT_PARTITIONED_INDEX: msg = _("\"%s\" is not a table, materialized view, index, or partitioned index"); break; - case ATT_TABLE | ATT_MATVIEW | ATT_INDEX | ATT_PARTITIONED_INDEX | ATT_FOREIGN_TABLE: + case ATT_TABLE | ATT_MATVIEW | ATT_INDEX | ATT_PARTITIONED_INDEX | ATT_FOREIGN_TABLE | ATT_DIRECTORY_TABLE: msg = _("\"%s\" is not a table, materialized view, index, partitioned index, or foreign table"); break; case ATT_TABLE | ATT_MATVIEW | ATT_FOREIGN_TABLE: @@ -7492,6 +7559,15 @@ ATWrongRelkindError(Relation rel, int allowed_targets) case ATT_FOREIGN_TABLE: msg = _("\"%s\" is not a foreign table"); break; + case ATT_TABLE | ATT_DIRECTORY_TABLE: + msg = _("\"%s\" is not a table or directory table"); + break; + case ATT_TABLE | ATT_FOREIGN_TABLE | ATT_DIRECTORY_TABLE: + msg = _("\"%s\" is not a table, foreign table, or directory table"); + break; + case ATT_DIRECTORY_TABLE: + msg = _("\"%s\" is not a directory table"); + break; default: /* shouldn't get here, add all necessary cases above */ msg = _("\"%s\" is of the wrong type"); @@ -14037,6 +14113,8 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, case OCLASS_TASK: case OCLASS_PROFILE: case OCLASS_PASSWORDHISTORY: + case OCLASS_STORAGE_SERVER: + case OCLASS_STORAGE_USER_MAPPING: /* * We don't expect any of these sorts of objects to depend on @@ -15117,6 +15195,7 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lock case RELKIND_MATVIEW: case RELKIND_FOREIGN_TABLE: case RELKIND_PARTITIONED_TABLE: + case RELKIND_DIRECTORY_TABLE: /* ok to change owner */ break; case RELKIND_INDEX: @@ -15292,6 +15371,7 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lock tuple_class->relkind == RELKIND_PARTITIONED_TABLE || tuple_class->relkind == RELKIND_MATVIEW || tuple_class->relkind == RELKIND_TOASTVALUE || + tuple_class->relkind == RELKIND_DIRECTORY_TABLE || tuple_class->relnamespace == PG_EXTAUX_NAMESPACE || IsAppendonlyMetadataRelkind(tuple_class->relkind)) { @@ -18515,6 +18595,7 @@ ATExecSetDistributedBy(Relation rel, Node *node, AlterTableCmd *cmd) ldistro = make_distributedby_for_rel(rel); if (rel->rd_rel->relkind == RELKIND_RELATION || + rel->rd_rel->relkind == RELKIND_DIRECTORY_TABLE || rel->rd_rel->relkind == RELKIND_MATVIEW) { need_reorg = true; @@ -19709,6 +19790,7 @@ AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid, /* Fix other dependent stuff */ if (rel->rd_rel->relkind == RELKIND_RELATION || + rel->rd_rel->relkind == RELKIND_DIRECTORY_TABLE || rel->rd_rel->relkind == RELKIND_MATVIEW || rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) { @@ -20183,10 +20265,11 @@ RangeVarCallbackOwnsTable(const RangeVar *relation, if (!relkind) return; if (relkind != RELKIND_RELATION && relkind != RELKIND_TOASTVALUE && - relkind != RELKIND_MATVIEW && relkind != RELKIND_PARTITIONED_TABLE) + relkind != RELKIND_MATVIEW && relkind != RELKIND_PARTITIONED_TABLE && + relkind != RELKIND_DIRECTORY_TABLE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("\"%s\" is not a table or materialized view", relation->relname))); + errmsg("\"%s\" is not a table, directory table or materialized view", relation->relname))); /* Check permissions */ if (!pg_class_ownercheck(relId, GetUserId())) @@ -20338,6 +20421,11 @@ RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is not a composite type", rv->relname))); + if (reltype == OBJECT_DIRECTORY_TABLE && relkind != RELKIND_DIRECTORY_TABLE) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("\"%s\" is not a directory table", rv->relname))); + if (reltype == OBJECT_INDEX && relkind != RELKIND_INDEX && relkind != RELKIND_PARTITIONED_INDEX && !IsA(stmt, RenameStmt)) @@ -20361,6 +20449,7 @@ RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, */ if (IsA(stmt, AlterObjectSchemaStmt) && relkind != RELKIND_RELATION && + relkind != RELKIND_DIRECTORY_TABLE && relkind != RELKIND_VIEW && relkind != RELKIND_MATVIEW && relkind != RELKIND_SEQUENCE && @@ -20368,7 +20457,7 @@ RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, relkind != RELKIND_PARTITIONED_TABLE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("\"%s\" is not a table, view, materialized view, sequence, or foreign table", + errmsg("\"%s\" is not a table, directory table, view, materialized view, sequence, or foreign table", rv->relname))); ReleaseSysCache(tuple); diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c index 811a2c17ab7..e5c53e7180b 100644 --- a/src/backend/commands/tablespace.c +++ b/src/backend/commands/tablespace.c @@ -83,6 +83,7 @@ #include "commands/tablespace.h" #include "common/file_perm.h" #include "miscadmin.h" +#include "parser/parse_func.h" #include "postmaster/bgwriter.h" #include "storage/bufmgr.h" #include "storage/fd.h" @@ -269,6 +270,7 @@ CreateTableSpace(CreateTableSpaceStmt *stmt) Oid ownerId; Datum newOptions; List *nonContentOptions = NIL; + char *fileHandler = NULL; /* Must be super user */ if (!superuser()) @@ -324,6 +326,9 @@ CreateTableSpace(CreateTableSpaceStmt *stmt) if (!location) location = pstrdup(stmt->location); + if (stmt->filehandler) + fileHandler = pstrdup(stmt->filehandler); + /* Unix-ify the offered path, and strip any trailing slashes */ canonicalize_path(location); @@ -420,6 +425,26 @@ CreateTableSpace(CreateTableSpaceStmt *stmt) ObjectIdGetDatum(ownerId); nulls[Anum_pg_tablespace_spcacl - 1] = true; + if (fileHandler) + { + List *fileHandler_list; + char *spcfilehandlerbin = NULL; + char *spcfilehandlersrc = NULL; + + SplitIdentifierString(fileHandler, ',', &fileHandler_list); + + spcfilehandlerbin = (char *) linitial(fileHandler_list); + spcfilehandlersrc = (char *) lsecond(fileHandler_list); + + values[Anum_pg_tablespace_spcfilehandlerbin - 1] = CStringGetTextDatum(spcfilehandlerbin); + values[Anum_pg_tablespace_spcfilehandlersrc - 1] = CStringGetTextDatum(spcfilehandlersrc); + } + else + { + nulls[Anum_pg_tablespace_spcfilehandlersrc - 1] = true; + nulls[Anum_pg_tablespace_spcfilehandlerbin - 1] = true; + } + /* Generate new proposed spcoptions (text array) */ newOptions = transformRelOptions((Datum) 0, nonContentOptions, diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index f60aa299fc0..147d724df3d 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -210,7 +210,8 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString, * Triggers must be on tables or views, and there are additional * relation-type-specific restrictions. */ - if (rel->rd_rel->relkind == RELKIND_RELATION) + if (rel->rd_rel->relkind == RELKIND_RELATION || + rel->rd_rel->relkind == RELKIND_DIRECTORY_TABLE) { /* Tables can't have INSTEAD OF triggers */ if (stmt->timing != TRIGGER_TYPE_BEFORE && @@ -1353,6 +1354,7 @@ RemoveTriggerById(Oid trigOid) rel = table_open(relid, AccessExclusiveLock); if (rel->rd_rel->relkind != RELKIND_RELATION && + rel->rd_rel->relkind != RELKIND_DIRECTORY_TABLE && rel->rd_rel->relkind != RELKIND_VIEW && rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE && rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE) @@ -1460,11 +1462,12 @@ RangeVarCallbackForRenameTrigger(const RangeVar *rv, Oid relid, Oid oldrelid, /* only tables and views can have triggers */ if (form->relkind != RELKIND_RELATION && form->relkind != RELKIND_VIEW && + form->relkind != RELKIND_DIRECTORY_TABLE && form->relkind != RELKIND_FOREIGN_TABLE && form->relkind != RELKIND_PARTITIONED_TABLE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("\"%s\" is not a table, view, or foreign table", + errmsg("\"%s\" is not a table, directory table, view, or foreign table", rv->relname))); /* you must own the table to rename one of its triggers */ diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 0d5f405fee6..7877659072b 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -1130,6 +1130,7 @@ get_all_vacuum_rels(int options) * them. */ if (classForm->relkind != RELKIND_RELATION && + classForm->relkind != RELKIND_DIRECTORY_TABLE && classForm->relkind != RELKIND_MATVIEW && classForm->relkind != RELKIND_PARTITIONED_TABLE) continue; @@ -1852,6 +1853,7 @@ vac_update_datfrozenxid(void) * should have InvalidTransactionId in relfrozenxid anyway). */ if (classForm->relkind != RELKIND_RELATION && + classForm->relkind != RELKIND_DIRECTORY_TABLE && classForm->relkind != RELKIND_MATVIEW && classForm->relkind != RELKIND_TOASTVALUE && classForm->relkind != RELKIND_AOSEGMENTS && @@ -2298,6 +2300,7 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params, * Check that it's of a vacuumable relkind. */ if (rel->rd_rel->relkind != RELKIND_RELATION && + rel->rd_rel->relkind != RELKIND_DIRECTORY_TABLE && rel->rd_rel->relkind != RELKIND_MATVIEW && rel->rd_rel->relkind != RELKIND_TOASTVALUE && rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE && @@ -2457,6 +2460,7 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params, */ if ((rel->rd_rel->relkind != RELKIND_RELATION && rel->rd_rel->relkind != RELKIND_MATVIEW && + rel->rd_rel->relkind != RELKIND_DIRECTORY_TABLE && rel->rd_rel->relkind != RELKIND_TOASTVALUE && rel->rd_rel->relkind != RELKIND_AOSEGMENTS && rel->rd_rel->relkind != RELKIND_AOBLOCKDIR && @@ -2558,6 +2562,7 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params, if (has_bitmap) LockRelation(rel, ShareLock); } + /* TODO: vacuum directory table's temp files */ if (!is_appendoptimized && (params->options & VACOPT_FULL)) { diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 189a6c9e31d..bdff0e8edd1 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -59,6 +59,7 @@ #include "jit/jit.h" #include "mb/pg_wchar.h" #include "miscadmin.h" +#include "nodes/plannodes.h" #include "parser/parsetree.h" #include "storage/bufmgr.h" #include "storage/lmgr.h" @@ -88,6 +89,7 @@ #include "catalog/pg_tablespace.h" #include "catalog/catalog.h" #include "catalog/oid_dispatch.h" +#include "catalog/pg_directory_table.h" #include "catalog/pg_type.h" #include "commands/copy.h" #include "commands/createas.h" @@ -1926,11 +1928,15 @@ InitPlan(QueryDesc *queryDesc, int eflags) * CheckValidRowMarkRel. */ void -CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation) +CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation, ModifyTableState *mtstate) { Relation resultRel = resultRelInfo->ri_RelationDesc; TriggerDesc *trigDesc = resultRel->trigdesc; FdwRoutine *fdwroutine; + ModifyTable *node; + int whichrel; + List *updateColnos; + ListCell *lc; switch (resultRel->rd_rel->relkind) { @@ -2088,6 +2094,40 @@ CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation) errmsg("cannot change AO visibility map relation \"%s\"", RelationGetRelationName(resultRel)))); break; + case RELKIND_DIRECTORY_TABLE: + switch(operation) + { + case CMD_INSERT: + case CMD_DELETE: + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot change directory table \"%s\"", + RelationGetRelationName(resultRel)))); + break; + case CMD_UPDATE: + if (mtstate) + { + node = (ModifyTable *) mtstate->ps.plan; + whichrel = mtstate->mt_lastResultIndex; + + updateColnos = (List *) list_nth(node->updateColnosLists, whichrel); + + foreach(lc, updateColnos) + { + AttrNumber targetattnum = lfirst_int(lc); + + if (targetattnum != DIRECTORY_TABLE_TAG_COLUMN_ATTNUM) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("Only allow to update directory \"tag\" column."))); + } + } + break; + default: + elog(ERROR, "unrecognized CmdType: %d", (int) operation); + break; + } + break; default: ereport(ERROR, @@ -2153,6 +2193,14 @@ CheckValidRowMarkRel(Relation rel, RowMarkType markType) errmsg("cannot lock rows in foreign table \"%s\"", RelationGetRelationName(rel)))); break; + case RELKIND_DIRECTORY_TABLE: + /* Allow referencing a directory table, but not actual locking clauses */ + if (markType != ROW_MARK_REFERENCE) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot lock rows in directory table \"%s\"", + RelationGetRelationName(rel)))); + break; default: ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c index fc2b4adb1f7..c8241f7ed64 100644 --- a/src/backend/executor/execPartition.c +++ b/src/backend/executor/execPartition.c @@ -360,7 +360,7 @@ ExecFindPartition(ModifyTableState *mtstate, if (rri) { /* Verify this ResultRelInfo allows INSERTs */ - CheckValidResultRel(rri, CMD_INSERT); + CheckValidResultRel(rri, CMD_INSERT, NULL); /* * Initialize information needed to insert this and @@ -526,7 +526,7 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate, * partition-key becomes a DELETE+INSERT operation, so this check is still * required when the operation is CMD_UPDATE. */ - CheckValidResultRel(leaf_part_rri, CMD_INSERT); + CheckValidResultRel(leaf_part_rri, CMD_INSERT, NULL); /* * Open partition indices. The user may have asked to check for conflicts diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index 0e76ca1f710..5ae87f1644a 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -2651,6 +2651,7 @@ ExecModifyTable(PlanState *pstate) relkind = resultRelInfo->ri_RelationDesc->rd_rel->relkind; if (relkind == RELKIND_RELATION || + relkind == RELKIND_DIRECTORY_TABLE || relkind == RELKIND_MATVIEW || relkind == RELKIND_PARTITIONED_TABLE) { @@ -3068,7 +3069,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) /* * Verify result relation is a valid target for the current operation */ - CheckValidResultRel(resultRelInfo, operation); + CheckValidResultRel(resultRelInfo, operation, mtstate); if (RelationIsAoRows(resultRelInfo->ri_RelationDesc)) appendonly_dml_init(resultRelInfo->ri_RelationDesc, operation); @@ -3131,6 +3132,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) relkind = resultRelInfo->ri_RelationDesc->rd_rel->relkind; if (relkind == RELKIND_RELATION || + relkind == RELKIND_DIRECTORY_TABLE || relkind == RELKIND_MATVIEW || relkind == RELKIND_PARTITIONED_TABLE) { diff --git a/src/backend/gpopt/gpdbwrappers.cpp b/src/backend/gpopt/gpdbwrappers.cpp index 16a0f060817..da5e774032a 100644 --- a/src/backend/gpopt/gpdbwrappers.cpp +++ b/src/backend/gpopt/gpdbwrappers.cpp @@ -66,7 +66,7 @@ using namespace gpos; void debug_gpos_assert(const char *filename, long line, const char *msg) { - elog(LOG, "[debug_gpos_assert]: '%s':%ld %s", filename, line, msg); + elog(DEBUG1, "[debug_gpos_assert]: '%s':%ld %s", filename, line, msg); } bool diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index cd5c0cadb7b..7fe3e7d0836 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -4089,6 +4089,7 @@ _copyCopyStmt(const CopyStmt *from) COPY_SCALAR_FIELD(is_from); COPY_SCALAR_FIELD(is_program); COPY_STRING_FIELD(filename); + COPY_STRING_FIELD(dirfilename); COPY_NODE_FIELD(options); COPY_NODE_FIELD(whereClause); COPY_NODE_FIELD(sreh); @@ -4870,6 +4871,7 @@ _copyCreateTableSpaceStmt(const CreateTableSpaceStmt *from) COPY_NODE_FIELD(owner); COPY_STRING_FIELD(location); COPY_NODE_FIELD(options); + COPY_STRING_FIELD(filehandler); return newnode; } @@ -5001,6 +5003,40 @@ _copyAlterForeignServerStmt(const AlterForeignServerStmt *from) return newnode; } +static CreateStorageServerStmt * +_copyCreateStorageServerStmt(const CreateStorageServerStmt *from) +{ + CreateStorageServerStmt *newnode = makeNode(CreateStorageServerStmt); + + COPY_STRING_FIELD(servername); + COPY_SCALAR_FIELD(if_not_exists); + COPY_NODE_FIELD(options); + + return newnode; +} + +static AlterStorageServerStmt * +_copyAlterStorageServerStmt(const AlterStorageServerStmt *from) +{ + AlterStorageServerStmt *newnode = makeNode(AlterStorageServerStmt); + + COPY_STRING_FIELD(servername); + COPY_NODE_FIELD(options); + + return newnode; +} + +static DropStorageServerStmt * +_copyDropStorageServerStmt(const DropStorageServerStmt *from) +{ + DropStorageServerStmt *newnode = makeNode(DropStorageServerStmt); + + COPY_STRING_FIELD(servername); + COPY_SCALAR_FIELD(missing_ok); + + return newnode; +} + static CreateUserMappingStmt * _copyCreateUserMappingStmt(const CreateUserMappingStmt *from) { @@ -5038,6 +5074,43 @@ _copyDropUserMappingStmt(const DropUserMappingStmt *from) return newnode; } +static CreateStorageUserMappingStmt * +_copyCreateStorageUserMappingStmt(const CreateStorageUserMappingStmt *from) +{ + CreateStorageUserMappingStmt *newnode = makeNode(CreateStorageUserMappingStmt); + + COPY_NODE_FIELD(user); + COPY_STRING_FIELD(servername); + COPY_SCALAR_FIELD(if_not_exists); + COPY_NODE_FIELD(options); + + return newnode; +} + +static AlterStorageUserMappingStmt * +_copyAlterStorageUserMappingStmt(const AlterStorageUserMappingStmt *from) +{ + AlterStorageUserMappingStmt *newnode = makeNode(AlterStorageUserMappingStmt); + + COPY_NODE_FIELD(user); + COPY_STRING_FIELD(servername); + COPY_NODE_FIELD(options); + + return newnode; +} + +static DropStorageUserMappingStmt * +_copyDropStorageUserMappingStmt(const DropStorageUserMappingStmt *from) +{ + DropStorageUserMappingStmt *newnode = makeNode(DropStorageUserMappingStmt); + + COPY_NODE_FIELD(user); + COPY_STRING_FIELD(servername); + COPY_SCALAR_FIELD(missing_ok); + + return newnode; +} + static CreateForeignTableStmt * _copyCreateForeignTableStmt(const CreateForeignTableStmt *from) { @@ -6027,6 +6100,18 @@ _copyAlteredTableInfo(const AlteredTableInfo *from) return newnode; } +static CreateDirectoryTableStmt * +_copyCreateDirectoryTableStmt(const CreateDirectoryTableStmt *from) +{ + CreateDirectoryTableStmt *newnode = makeNode(CreateDirectoryTableStmt); + + CopyCreateStmtFields((const CreateStmt *) from, (CreateStmt *) newnode); + + COPY_STRING_FIELD(tablespacename); + + return newnode; +} + static EphemeralNamedRelationInfo* _copyEphemeralNamedRelationInfo(const EphemeralNamedRelationInfo *from) { @@ -6771,6 +6856,15 @@ copyObjectImpl(const void *from) case T_AlterForeignServerStmt: retval = _copyAlterForeignServerStmt(from); break; + case T_CreateStorageServerStmt: + retval = _copyCreateStorageServerStmt(from); + break; + case T_AlterStorageServerStmt: + retval = _copyAlterStorageServerStmt(from); + break; + case T_DropStorageServerStmt: + retval = _copyDropStorageServerStmt(from); + break; case T_CreateUserMappingStmt: retval = _copyCreateUserMappingStmt(from); break; @@ -6780,6 +6874,15 @@ copyObjectImpl(const void *from) case T_DropUserMappingStmt: retval = _copyDropUserMappingStmt(from); break; + case T_CreateStorageUserMappingStmt: + retval = _copyCreateStorageUserMappingStmt(from); + break; + case T_AlterStorageUserMappingStmt: + retval = _copyAlterStorageUserMappingStmt(from); + break; + case T_DropStorageUserMappingStmt: + retval = _copyDropStorageUserMappingStmt(from); + break; case T_CreateForeignTableStmt: retval = _copyCreateForeignTableStmt(from); break; @@ -7149,6 +7252,11 @@ copyObjectImpl(const void *from) case T_AlteredTableInfo: retval = _copyAlteredTableInfo(from); break; + + case T_CreateDirectoryTableStmt: + retval = _copyCreateDirectoryTableStmt(from); + break; + case T_EphemeralNamedRelationInfo: retval = _copyEphemeralNamedRelationInfo(from); break; diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index d95179fb339..283a5c5d552 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -1359,6 +1359,7 @@ _equalCopyStmt(const CopyStmt *a, const CopyStmt *b) COMPARE_SCALAR_FIELD(is_from); COMPARE_SCALAR_FIELD(is_program); COMPARE_STRING_FIELD(filename); + COMPARE_STRING_FIELD(dirfilename); COMPARE_NODE_FIELD(options); COMPARE_NODE_FIELD(whereClause); COMPARE_NODE_FIELD(sreh); @@ -2031,6 +2032,7 @@ _equalCreateTableSpaceStmt(const CreateTableSpaceStmt *a, const CreateTableSpace COMPARE_NODE_FIELD(owner); COMPARE_STRING_FIELD(location); COMPARE_NODE_FIELD(options); + COMPARE_STRING_FIELD(filehandler); return true; } @@ -2144,6 +2146,34 @@ _equalAlterForeignServerStmt(const AlterForeignServerStmt *a, const AlterForeign return true; } +static bool +_equalCreateStorageServerStmt(const CreateStorageServerStmt *a, const CreateStorageServerStmt *b) +{ + COMPARE_STRING_FIELD(servername); + COMPARE_SCALAR_FIELD(if_not_exists); + COMPARE_NODE_FIELD(options); + + return true; +} + +static bool +_equalAlterStorageServerStmt(const AlterStorageServerStmt *a, const AlterStorageServerStmt *b) +{ + COMPARE_STRING_FIELD(servername); + COMPARE_NODE_FIELD(options); + + return true; +} + +static bool +_equalDropStorageServerStmt(const DropStorageServerStmt *a, const DropStorageServerStmt *b) +{ + COMPARE_STRING_FIELD(servername); + COMPARE_SCALAR_FIELD(missing_ok); + + return true; +} + static bool _equalCreateUserMappingStmt(const CreateUserMappingStmt *a, const CreateUserMappingStmt *b) { @@ -2175,6 +2205,37 @@ _equalDropUserMappingStmt(const DropUserMappingStmt *a, const DropUserMappingStm return true; } +static bool +_equalCreateStorageUserMappingStmt(const CreateStorageUserMappingStmt *a, const CreateStorageUserMappingStmt *b) +{ + COMPARE_NODE_FIELD(user); + COMPARE_STRING_FIELD(servername); + COMPARE_SCALAR_FIELD(if_not_exists); + COMPARE_NODE_FIELD(options); + + return true; +} + +static bool +_equalAlterStorageUserMappingStmt(const AlterStorageUserMappingStmt *a, const AlterStorageUserMappingStmt *b) +{ + COMPARE_NODE_FIELD(user); + COMPARE_STRING_FIELD(servername); + COMPARE_NODE_FIELD(options); + + return true; +} + +static bool +_equalDropStorageUserMappingStmt(const DropStorageUserMappingStmt *a, const DropStorageUserMappingStmt *b) +{ + COMPARE_NODE_FIELD(user); + COMPARE_STRING_FIELD(servername); + COMPARE_SCALAR_FIELD(missing_ok); + + return true; +} + static bool _equalCreateForeignTableStmt(const CreateForeignTableStmt *a, const CreateForeignTableStmt *b) { @@ -3334,6 +3395,17 @@ _equalPartitionCmd(const PartitionCmd *a, const PartitionCmd *b) return true; } +static bool +_equalCreateDirectoryTableStmt(const CreateDirectoryTableStmt *a, const CreateDirectoryTableStmt *b) +{ + if (!_equalCreateStmt(&a->base, &b->base)) + return false; + + COMPARE_STRING_FIELD(tablespacename); + + return true; +} + /* * Stuff from pg_list.h */ @@ -3934,6 +4006,15 @@ equal(const void *a, const void *b) case T_AlterForeignServerStmt: retval = _equalAlterForeignServerStmt(a, b); break; + case T_CreateStorageServerStmt: + retval = _equalCreateStorageServerStmt(a, b); + break; + case T_AlterStorageServerStmt: + retval = _equalAlterStorageServerStmt(a, b); + break; + case T_DropStorageServerStmt: + retval = _equalDropStorageServerStmt(a, b); + break; case T_CreateUserMappingStmt: retval = _equalCreateUserMappingStmt(a, b); break; @@ -3943,6 +4024,15 @@ equal(const void *a, const void *b) case T_DropUserMappingStmt: retval = _equalDropUserMappingStmt(a, b); break; + case T_CreateStorageUserMappingStmt: + retval = _equalCreateStorageUserMappingStmt(a, b); + break; + case T_AlterStorageUserMappingStmt: + retval = _equalAlterStorageUserMappingStmt(a, b); + break; + case T_DropStorageUserMappingStmt: + retval = _equalDropStorageUserMappingStmt(a, b); + break; case T_CreateForeignTableStmt: retval = _equalCreateForeignTableStmt(a, b); break; @@ -4249,6 +4339,9 @@ equal(const void *a, const void *b) case T_DistributionKeyElem: retval = _equalDistributionKeyElem(a, b); break; + case T_CreateDirectoryTableStmt: + retval = _equalCreateDirectoryTableStmt(a, b); + break; default: elog(ERROR, "unrecognized node type: %d", diff --git a/src/backend/nodes/outfast.c b/src/backend/nodes/outfast.c index 102e8a30c90..043a2b8af6c 100644 --- a/src/backend/nodes/outfast.c +++ b/src/backend/nodes/outfast.c @@ -651,6 +651,33 @@ _outAlterForeignServerStmt(StringInfo str, AlterForeignServerStmt *node) WRITE_BOOL_FIELD(has_version); } +static void +_outCreateStorageServerStmt(StringInfo str, CreateStorageServerStmt *node) +{ + WRITE_NODE_TYPE("CREATESTORAGESERVERSTMT"); + + WRITE_STRING_FIELD(servername); + WRITE_NODE_FIELD(options); +} + +static void +_outAlterStorageServerStmt(StringInfo str, AlterStorageServerStmt *node) +{ + WRITE_NODE_TYPE("ALTERSTORAGESERVERSTMT"); + + WRITE_STRING_FIELD(servername); + WRITE_NODE_FIELD(options); +} + +static void +_outDropStorageServerStmt(StringInfo str, DropStorageServerStmt *node) +{ + WRITE_NODE_TYPE("DROPSTORAGESERVERSTMT"); + + WRITE_STRING_FIELD(servername); + WRITE_BOOL_FIELD(missing_ok); +} + static void _outCreateUserMappingStmt(StringInfo str, CreateUserMappingStmt *node) { @@ -671,6 +698,46 @@ _outAlterUserMappingStmt(StringInfo str, AlterUserMappingStmt *node) WRITE_NODE_FIELD(options); } +static void +_outDropUserMappingStmt(StringInfo str, DropUserMappingStmt *node) +{ + WRITE_NODE_TYPE("DROPUSERMAPPINGSTMT"); + + WRITE_NODE_FIELD(user); + WRITE_STRING_FIELD(servername); + WRITE_BOOL_FIELD(missing_ok); +} + +static void +_outCreateStorageUserMappingStmt(StringInfo str, CreateStorageUserMappingStmt *node) +{ + WRITE_NODE_TYPE("CREATEUSERMAPPINGSTMT"); + + WRITE_NODE_FIELD(user); + WRITE_STRING_FIELD(servername); + WRITE_NODE_FIELD(options); +} + +static void +_outAlterStorageUserMappingStmt(StringInfo str, AlterStorageUserMappingStmt *node) +{ + WRITE_NODE_TYPE("ALTERSTORAGEUSERMAPPINGSTMT"); + + WRITE_NODE_FIELD(user); + WRITE_STRING_FIELD(servername); + WRITE_NODE_FIELD(options); +} + +static void +_outDropStorageUserMappingStmt(StringInfo str, DropStorageUserMappingStmt *node) +{ + WRITE_NODE_TYPE("DROPSTORAGEUSERMAPPINGSTMT"); + + WRITE_NODE_FIELD(user); + WRITE_STRING_FIELD(servername); + WRITE_BOOL_FIELD(missing_ok); +} + static void _outAlterObjectDependsStmt(StringInfo str, const AlterObjectDependsStmt *node) { @@ -698,16 +765,6 @@ _outCustomScan(StringInfo str, const CustomScan *node) WRITE_STRING_FIELD(methods->CustomName); } -static void -_outDropUserMappingStmt(StringInfo str, DropUserMappingStmt *node) -{ - WRITE_NODE_TYPE("DROPUSERMAPPINGSTMT"); - - WRITE_NODE_FIELD(user); - WRITE_STRING_FIELD(servername); - WRITE_BOOL_FIELD(missing_ok); -} - static void _outAccessPriv(StringInfo str, AccessPriv *node) { @@ -1672,6 +1729,15 @@ _outNode(StringInfo str, void *obj) case T_CreateUserMappingStmt: _outCreateUserMappingStmt(str, obj); break; + case T_CreateStorageUserMappingStmt: + _outCreateStorageUserMappingStmt(str, obj); + break; + case T_AlterStorageUserMappingStmt: + _outAlterStorageUserMappingStmt(str, obj); + break; + case T_DropStorageUserMappingStmt: + _outDropStorageUserMappingStmt(str, obj); + break; case T_AlterForeignServerStmt: _outAlterForeignServerStmt(str, obj); break; @@ -1681,6 +1747,15 @@ _outNode(StringInfo str, void *obj) case T_AlterFdwStmt: _outAlterFdwStmt(str, obj); break; + case T_CreateStorageServerStmt: + _outCreateStorageServerStmt(str, obj); + break; + case T_AlterStorageServerStmt: + _outAlterStorageServerStmt(str, obj); + break; + case T_DropStorageServerStmt: + _outDropStorageServerStmt(str, obj); + break; case T_CreateFdwStmt: _outCreateFdwStmt(str, obj); break; @@ -1785,6 +1860,9 @@ _outNode(StringInfo str, void *obj) case T_ReturnStmt: _outReturnStmt(str, obj); break; + case T_CreateDirectoryTableStmt: + _outCreateDirectoryTableStmt(str, obj); + break; case T_EphemeralNamedRelationInfo: _outEphemeralNamedRelationInfo(str, obj); break; diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 8900df8cd9c..4d0dee54f2c 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -4022,6 +4022,15 @@ _outPartitionRangeDatum(StringInfo str, const PartitionRangeDatum *node) WRITE_LOCATION_FIELD(location); } +static void +_outCreateDirectoryTableStmt(StringInfo str, const CreateDirectoryTableStmt *node) +{ + WRITE_NODE_TYPE("CREATEDIRECTORYTABLESTMT"); + + _outCreateStmtInfo(str, (const CreateStmt *) node); + WRITE_STRING_FIELD(tablespacename); +} + #include "outfuncs_common.c" #ifndef COMPILING_BINARY_FUNCS /* @@ -5157,6 +5166,9 @@ outNode(StringInfo str, const void *obj) case T_EphemeralNamedRelationInfo: _outEphemeralNamedRelationInfo(str, obj); break; + case T_CreateDirectoryTableStmt: + _outCreateDirectoryTableStmt(str, obj); + break; default: /* diff --git a/src/backend/nodes/outfuncs_common.c b/src/backend/nodes/outfuncs_common.c index 4d42f6e21bf..76e766e55d2 100644 --- a/src/backend/nodes/outfuncs_common.c +++ b/src/backend/nodes/outfuncs_common.c @@ -209,6 +209,7 @@ _outCopyStmt(StringInfo str, const CopyStmt *node) WRITE_BOOL_FIELD(is_from); WRITE_BOOL_FIELD(is_program); WRITE_STRING_FIELD(filename); + WRITE_STRING_FIELD(dirfilename); WRITE_NODE_FIELD(options); WRITE_NODE_FIELD(sreh); } @@ -1483,6 +1484,7 @@ _outCreateTableSpaceStmt(StringInfo str, const CreateTableSpaceStmt *node) WRITE_NODE_FIELD(owner); WRITE_STRING_FIELD(location); WRITE_NODE_FIELD(options); + WRITE_STRING_FIELD(filehandler); } static void diff --git a/src/backend/nodes/readfast.c b/src/backend/nodes/readfast.c index 0faa0c40f1e..96e42bff0cd 100644 --- a/src/backend/nodes/readfast.c +++ b/src/backend/nodes/readfast.c @@ -758,6 +758,7 @@ _readCreateStmt_common(CreateStmt *local_node) local_node->relKind == RELKIND_COMPOSITE_TYPE || local_node->relKind == RELKIND_FOREIGN_TABLE || local_node->relKind == RELKIND_MATVIEW || + local_node->relKind == RELKIND_DIRECTORY_TABLE || IsAppendonlyMetadataRelkind(local_node->relKind)); Assert(local_node->oncommit <= ONCOMMIT_DROP); } @@ -818,6 +819,7 @@ _readCopyStmt(void) READ_BOOL_FIELD(is_from); READ_BOOL_FIELD(is_program); READ_STRING_FIELD(filename); + READ_STRING_FIELD(dirfilename); READ_NODE_FIELD(options); READ_NODE_FIELD(sreh); @@ -1129,6 +1131,7 @@ _readCreateTableSpaceStmt(void) READ_NODE_FIELD(owner); READ_STRING_FIELD(location); READ_NODE_FIELD(options); + READ_STRING_FIELD(filehandler); READ_DONE(); } @@ -1447,6 +1450,39 @@ _readAlterForeignServerStmt(void) READ_DONE(); } +static CreateStorageServerStmt * +_readCreateStorageServerStmt(void) +{ + READ_LOCALS(CreateStorageServerStmt); + + READ_STRING_FIELD(servername); + READ_NODE_FIELD(options); + + READ_DONE(); +} + +static AlterStorageServerStmt * +_readAlterStorageServerStmt(void) +{ + READ_LOCALS(AlterStorageServerStmt); + + READ_STRING_FIELD(servername); + READ_NODE_FIELD(options); + + READ_DONE(); +} + +static DropStorageServerStmt * +_readDropStorageServerStmt(void) +{ + READ_LOCALS(DropStorageServerStmt); + + READ_STRING_FIELD(servername); + READ_BOOL_FIELD(missing_ok); + + READ_DONE(); +} + static CreateUserMappingStmt * _readCreateUserMappingStmt(void) { @@ -1483,6 +1519,42 @@ _readDropUserMappingStmt(void) READ_DONE(); } +static CreateStorageUserMappingStmt * +_readCreateStorageUserMappingStmt(void) +{ + READ_LOCALS(CreateStorageUserMappingStmt); + + READ_NODE_FIELD(user); + READ_STRING_FIELD(servername); + READ_NODE_FIELD(options); + + READ_DONE(); +} + +static AlterStorageUserMappingStmt * +_readAlterStorageUserMappingStmt(void) +{ + READ_LOCALS(AlterStorageUserMappingStmt); + + READ_NODE_FIELD(user); + READ_STRING_FIELD(servername); + READ_NODE_FIELD(options); + + READ_DONE(); +} + +static DropStorageUserMappingStmt * +_readDropStorageUserMappingStmt(void) +{ + READ_LOCALS(DropStorageUserMappingStmt); + + READ_NODE_FIELD(user); + READ_STRING_FIELD(servername); + READ_BOOL_FIELD(missing_ok); + + READ_DONE(); +} + static AccessPriv * _readAccessPriv(void) { @@ -1642,6 +1714,18 @@ _readCreateStatsStmt(void) READ_DONE(); } +static CreateDirectoryTableStmt * +_readCreateDirectoryTableStmt(void) +{ + READ_LOCALS(CreateDirectoryTableStmt); + + _readCreateStmt_common(&local_node->base); + + READ_STRING_FIELD(tablespacename); + + READ_DONE(); +} + static EphemeralNamedRelationInfo * _readEphemeralNamedRelationInfo(void) { @@ -2573,6 +2657,15 @@ readNodeBinary(void) case T_CreateUserMappingStmt: return_value = _readCreateUserMappingStmt(); break; + case T_CreateStorageUserMappingStmt: + return_value = _readCreateStorageUserMappingStmt(); + break; + case T_AlterStorageUserMappingStmt: + return_value = _readAlterStorageUserMappingStmt(); + break; + case T_DropStorageUserMappingStmt: + return_value = _readDropStorageUserMappingStmt(); + break; case T_AlterForeignServerStmt: return_value = _readAlterForeignServerStmt(); break; @@ -2582,6 +2675,15 @@ readNodeBinary(void) case T_AlterFdwStmt: return_value = _readAlterFdwStmt(); break; + case T_CreateStorageServerStmt: + return_value = _readCreateStorageServerStmt(); + break; + case T_AlterStorageServerStmt: + return_value = _readAlterStorageServerStmt(); + break; + case T_DropStorageServerStmt: + return_value = _readDropStorageServerStmt(); + break; case T_CreateFdwStmt: return_value = _readCreateFdwStmt(); break; @@ -2671,6 +2773,9 @@ readNodeBinary(void) case T_EphemeralNamedRelationInfo: return_value = _readEphemeralNamedRelationInfo(); break; + case T_CreateDirectoryTableStmt: + return_value = _readCreateDirectoryTableStmt(); + break; default: return_value = NULL; /* keep the compiler silent */ elog(ERROR, "could not deserialize unrecognized node type: %d", diff --git a/src/backend/optimizer/util/appendinfo.c b/src/backend/optimizer/util/appendinfo.c index 40b49d4d1b3..390ef9d0471 100644 --- a/src/backend/optimizer/util/appendinfo.c +++ b/src/backend/optimizer/util/appendinfo.c @@ -906,6 +906,7 @@ add_row_identity_columns(PlannerInfo *root, Index rtindex, Assert(commandType == CMD_UPDATE || commandType == CMD_DELETE); if (relkind == RELKIND_RELATION || + relkind == RELKIND_DIRECTORY_TABLE || relkind == RELKIND_MATVIEW || relkind == RELKIND_PARTITIONED_TABLE) { diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c index 832635cb981..27a88b9452e 100644 --- a/src/backend/optimizer/util/plancat.c +++ b/src/backend/optimizer/util/plancat.c @@ -1202,6 +1202,7 @@ estimate_rel_size(Relation rel, int32 *attr_widths, switch (rel->rd_rel->relkind) { case RELKIND_RELATION: + case RELKIND_DIRECTORY_TABLE: case RELKIND_MATVIEW: case RELKIND_TOASTVALUE: case RELKIND_AOSEGMENTS: diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index cdd1670c0f1..92a10d81a07 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -57,6 +57,7 @@ #include "catalog/pg_am.h" #include "catalog/pg_foreign_server.h" #include "catalog/pg_trigger.h" +#include "catalog/pg_directory_table.h" #include "commands/defrem.h" #include "commands/trigger.h" #include "nodes/makefuncs.h" @@ -67,6 +68,7 @@ #include "utils/date.h" #include "utils/datetime.h" #include "utils/numeric.h" +#include "utils/varlena.h" #include "utils/xml.h" #include "cdb/cdbutil.h" #include "cdb/cdbvars.h" @@ -281,17 +283,18 @@ static void check_expressions_in_partition_key(PartitionSpec *spec, core_yyscan_ AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterEnumStmt AlterFdwStmt AlterForeignServerStmt AlterGroupStmt AlterObjectDependsStmt AlterObjectSchemaStmt AlterOwnerStmt - AlterOperatorStmt AlterTypeStmt AlterSeqStmt AlterSystemStmt AlterTableStmt + AlterOperatorStmt AlterTypeStmt AlterSeqStmt AlterStorageServerStmt AlterSystemStmt AlterTableStmt AlterTblSpcStmt AlterExtensionStmt AlterExtensionContentsStmt - AlterCompositeTypeStmt AlterUserMappingStmt + AlterCompositeTypeStmt AlterUserMappingStmt AlterStorageUserMappingStmt AlterRoleStmt AlterRoleSetStmt AlterPolicyStmt AlterStatsStmt AlterDefaultPrivilegesStmt DefACLAction AnalyzeStmt CallStmt ClosePortalStmt ClusterStmt CommentStmt ConstraintsSetStmt CopyStmt CreateAsStmt CreateCastStmt CreateDomainStmt CreateExtensionStmt CreateGroupStmt CreateOpClassStmt CreateOpFamilyStmt AlterOpFamilyStmt CreatePLangStmt - CreateSchemaStmt CreateSeqStmt CreateStmt CreateStatsStmt CreateTableSpaceStmt - CreateFdwStmt CreateForeignServerStmt CreateForeignTableStmt + CreateSchemaStmt CreateSeqStmt CreateStmt CreateStatsStmt + CreateStorageServerStmt CreateStorageUserMappingStmt + CreateTableSpaceStmt CreateFdwStmt CreateForeignServerStmt CreateForeignTableStmt CreateDirectoryTableStmt CreateAssertionStmt CreateTransformStmt CreateTrigStmt CreateEventTrigStmt CreateUserStmt CreateUserMappingStmt CreateRoleStmt CreatePolicyStmt CreatedbStmt CreateWarehouseStmt DeclareCursorStmt DefineStmt DeleteStmt DiscardStmt DoStmt @@ -299,7 +302,7 @@ static void check_expressions_in_partition_key(PartitionSpec *spec, core_yyscan_ DropCastStmt DropRoleStmt DropdbStmt DropTableSpaceStmt DropTransformStmt - DropUserMappingStmt ExplainStmt FetchStmt + DropUserMappingStmt DropStorageServerStmt DropStorageUserMappingStmt ExplainStmt FetchStmt GrantStmt GrantRoleStmt ImportForeignSchemaStmt IndexStmt InsertStmt ListenStmt LoadStmt LockStmt NotifyStmt ExplainableStmt PreparableStmt CreateFunctionStmt AlterFunctionStmt ReindexStmt RemoveAggrStmt @@ -409,7 +412,7 @@ static void check_expressions_in_partition_key(PartitionSpec *spec, core_yyscan_ %type copy_file_name access_method_clause attr_name table_access_method_clause name cursor_name file_name - opt_index_name cluster_index_specification + opt_index_name cluster_index_specification opt_file_name %type func_name handler_name qual_Op qual_all_Op subquery_Op opt_class opt_inline_handler opt_validator validator_clause @@ -640,6 +643,9 @@ static void check_expressions_in_partition_key(PartitionSpec *spec, core_yyscan_ %type constraints_set_list %type constraints_set_mode %type OptTableSpace OptConsTableSpace +%type OptServer +%type OptFileHandler + %type OptTableSpaceOwner %type DistributedBy OptDistributedBy %type OptTabPartitionRangeInclusive @@ -755,7 +761,7 @@ static void check_expressions_in_partition_key(PartitionSpec *spec, core_yyscan_ DATA_P DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS DEPENDS DEPTH DESC - DETACH DICTIONARY DISABLE_P DISCARD DISTINCT DO DOCUMENT_P DOMAIN_P + DETACH DICTIONARY DIRECTORY DISABLE_P DISCARD DISTINCT DO DOCUMENT_P DOMAIN_P DOUBLE_P DROP EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ENDPOINT ENUM_P ESCAPE EVENT EXCEPT @@ -871,6 +877,8 @@ static void check_expressions_in_partition_key(PartitionSpec *spec, core_yyscan_ SCATTER SEGMENT SEGMENTS SPLIT SUBPARTITION + TAG + TASK SCHEDULE THRESHOLD @@ -1396,6 +1404,7 @@ stmt: | AlterQueueStmt | AlterResourceGroupStmt | AlterSeqStmt + | AlterStorageServerStmt | AlterSystemStmt | AlterTableStmt | AlterTblSpcStmt @@ -1408,6 +1417,7 @@ stmt: | AlterTSConfigurationStmt | AlterTSDictionaryStmt | AlterUserMappingStmt + | AlterStorageUserMappingStmt | AnalyzeStmt | CallStmt | CheckPointStmt @@ -1422,6 +1432,7 @@ stmt: | CreateCastStmt | CreateConversionStmt | CreateDomainStmt + | CreateDirectoryTableStmt | CreateExtensionStmt | CreateExternalStmt | CreateFdwStmt @@ -1445,6 +1456,8 @@ stmt: | CreateStmt | CreateSubscriptionStmt | CreateStatsStmt + | CreateStorageServerStmt + | CreateStorageUserMappingStmt | CreateTableSpaceStmt | CreateTaskStmt | CreateTransformStmt @@ -1475,6 +1488,8 @@ stmt: | DropRoleStmt | DropUserMappingStmt | DropdbStmt + | DropStorageServerStmt + | DropStorageUserMappingStmt | DropWarehouseStmt | ExecuteStmt | ExplainStmt @@ -4487,7 +4502,7 @@ ClosePortalStmt: *****************************************************************************/ CopyStmt: COPY opt_binary qualified_name opt_column_list - copy_from opt_program copy_file_name copy_delimiter opt_with + copy_from opt_program copy_file_name opt_file_name copy_delimiter opt_with copy_options where_clause OptSingleRowErrorHandling { CopyStmt *n = makeNode(CopyStmt); @@ -4497,8 +4512,9 @@ CopyStmt: COPY opt_binary qualified_name opt_column_list n->is_from = $5; n->is_program = $6; n->filename = $7; - n->whereClause = $11; - n->sreh = $12; + n->dirfilename = $8; + n->whereClause = $12; + n->sreh = $13; if (n->is_program && n->filename == NULL) ereport(ERROR, @@ -4510,16 +4526,16 @@ CopyStmt: COPY opt_binary qualified_name opt_column_list ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("WHERE clause not allowed with COPY TO"), - parser_errposition(@11))); + parser_errposition(@12))); n->options = NIL; /* Concatenate user-supplied flags */ if ($2) n->options = lappend(n->options, $2); - if ($8) - n->options = lappend(n->options, $8); - if ($10) - n->options = list_concat(n->options, $10); + if ($9) + n->options = lappend(n->options, $9); + if ($11) + n->options = list_concat(n->options, $11); $$ = (Node *)n; } | COPY '(' PreparableStmt ')' TO opt_program copy_file_name opt_with copy_options @@ -4573,6 +4589,11 @@ copy_file_name: | STDOUT { $$ = NULL; } ; +opt_file_name: + Sconst { $$ = $1; } + | /* EMPTY */ { $$ = NULL; } + ; + copy_options: copy_opt_list { $$ = $1; } | '(' copy_generic_opt_list ')' { $$ = $2; } ; @@ -4656,6 +4677,10 @@ copy_opt_item: { $$ = makeDefElem("skip_foreign_partitions", (Node *)makeInteger(true), @1); } + | TAG Sconst + { + $$ = makeDefElem("tag", (Node *)makeString($2), @1); + } ; /* The following exist for backward compatibility with very old versions */ @@ -7137,13 +7162,38 @@ opt_procedural: * *****************************************************************************/ -CreateTableSpaceStmt: CREATE TABLESPACE name OptTableSpaceOwner LOCATION Sconst opt_reloptions +CreateTableSpaceStmt: CREATE TABLESPACE name OptTableSpaceOwner LOCATION Sconst opt_reloptions OptServer OptFileHandler { CreateTableSpaceStmt *n = makeNode(CreateTableSpaceStmt); + List *fileHandler_list; + char *tmpfilehandler; n->tablespacename = $3; n->owner = $4; n->location = $6; n->options = $7; + + if ($8 != NULL) + { + n->options = lappend(n->options, $8); + n->options = lappend(n->options, + makeDefElem("path", (Node *)makeString($6), @6)); + } + n->filehandler = $9; + if (n->filehandler) + { + tmpfilehandler = pstrdup(n->filehandler); + if (tmpfilehandler && !SplitIdentifierString(tmpfilehandler, ',', &fileHandler_list)) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("invalid list syntax for \"handler\""), + parser_errposition(@9))); + if (tmpfilehandler && list_length(fileHandler_list) != 2) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("invalid list syntax for \"handler\""), + parser_errposition(@9))); + } + $$ = (Node *) n; } ; @@ -7152,6 +7202,16 @@ OptTableSpaceOwner: OWNER RoleSpec { $$ = $2; } | /*EMPTY */ { $$ = NULL; } ; +OptServer: SERVER name { $$ = makeDefElem("server", (Node *)makeString($2), @1); } + | /* EMPTY */ { $$ = NULL; } + ; + +OptFileHandler: + HANDLER Sconst { $$ = $2; } + | HANDLER { $$ = NULL; } + | /* EMPTY */ { $$ = NULL; } + ; + /***************************************************************************** * * QUERY: @@ -7589,7 +7649,7 @@ AlterFdwStmt: ALTER FOREIGN DATA_P WRAPPER name opt_fdw_options alter_generic_op } ; -/* Options definition for CREATE FDW, SERVER and USER MAPPING */ +/* Options definition for CREATE FDW, SERVER, STORAGE SERVER and USER MAPPING */ create_generic_options: OPTIONS '(' generic_option_list ')' { $$ = $3; } | /*EMPTY*/ { $$ = NIL; } @@ -7741,6 +7801,74 @@ AlterForeignServerStmt: ALTER SERVER name foreign_server_version alter_generic_o } ; +/***************************************************************************** + * + * QUERY: + * CREATE STORAGE SERVER name [OPTIONS] + * + *****************************************************************************/ + +CreateStorageServerStmt: + CREATE STORAGE SERVER name create_generic_options + { + CreateStorageServerStmt *n = makeNode(CreateStorageServerStmt); + n->servername = $4; + n->if_not_exists = false; + n->options = $5; + $$ = (Node *) n; + } + | CREATE STORAGE SERVER IF_P NOT EXISTS name create_generic_options + { + CreateStorageServerStmt *n = makeNode(CreateStorageServerStmt); + n->servername = $7; + n->if_not_exists = true; + n->options = $8; + $$ = (Node *) n; + } + ; + +/***************************************************************************** + * + * QUERY : + * ALTER STORAGE SERVER name OPTIONS + * + ****************************************************************************/ + +AlterStorageServerStmt: + ALTER STORAGE SERVER name alter_generic_options + { + AlterStorageServerStmt *n = makeNode(AlterStorageServerStmt); + n->servername = $4; + n->options = $5; + $$ = (Node *) n; + } + ; + +/***************************************************************************** + * + * QUERY : + * DROP STORAGE SERVER name + * + ****************************************************************************/ + +DropStorageServerStmt: + DROP STORAGE SERVER name + { + DropStorageServerStmt *n = makeNode(DropStorageServerStmt); + n->servername = $4; + n->missing_ok = false; + $$ = (Node *) n; + } + | DROP STORAGE SERVER IF_P EXISTS name + { + DropStorageServerStmt *n = makeNode(DropStorageServerStmt); + n->servername = $6; + n->missing_ok = true; + $$ = (Node *) n; + } + ; + + /***************************************************************************** * * QUERY: @@ -7962,6 +8090,141 @@ AlterUserMappingStmt: ALTER USER MAPPING FOR auth_ident SERVER name alter_generi } ; +/***************************************************************************** + * + * QUERY: + * CREAT STORAGE USER MAPPING FOR auth_ident STORAGE SERVER name [OPTIONS] + * + *****************************************************************************/ + +CreateStorageUserMappingStmt: + CREATE STORAGE USER MAPPING FOR auth_ident STORAGE SERVER name create_generic_options + { + CreateStorageUserMappingStmt *n = makeNode(CreateStorageUserMappingStmt); + n->user = $6; + n->servername = $9; + n->options = $10; + n->if_not_exists = false; + $$ = (Node *) n; + } + | CREATE STORAGE USER MAPPING IF_P NOT EXISTS FOR auth_ident + STORAGE SERVER name create_generic_options + { + CreateStorageUserMappingStmt *n = makeNode(CreateStorageUserMappingStmt); + n->user = $9; + n->servername = $12; + n->options = $13; + n->if_not_exists = true; + $$ = (Node *) n; + } + ; + +/***************************************************************************** + * + * QUERY : + * DROP STORAGE USER MAPPING FOR auth_ident STORAGE SERVER name + * + * XXX you'd think this should have a CASCADE/RESTRICT option, even if it's + * only pro forma; but the SQL standard doesn't show one. + ****************************************************************************/ + +DropStorageUserMappingStmt: + DROP STORAGE USER MAPPING FOR auth_ident STORAGE SERVER name + { + DropStorageUserMappingStmt *n = makeNode(DropStorageUserMappingStmt); + n->user = $6; + n->servername = $9; + n->missing_ok = false; + $$ = (Node *) n; + } + | DROP STORAGE USER MAPPING IF_P EXISTS FOR auth_ident STORAGE SERVER name + { + DropStorageUserMappingStmt *n = makeNode(DropStorageUserMappingStmt); + n->user = $8; + n->servername = $11; + n->missing_ok = true; + $$ = (Node *) n; + } + ; + +/***************************************************************************** + * + * QUERY : + * ALTER STORAGE USER MAPPING FOR auth_ident STORAGE SERVER name OPTIONS + * + ****************************************************************************/ + +AlterStorageUserMappingStmt: + ALTER STORAGE USER MAPPING FOR auth_ident STORAGE SERVER name alter_generic_options + { + AlterStorageUserMappingStmt *n = makeNode(AlterStorageUserMappingStmt); + n->user = $6; + n->servername = $9; + n->options = $10; + $$ = (Node *) n; + } + ; + +/***************************************************************************** + * + * QUERY: + * CREATE DIRECTORY TABLE relname SERVER name (...) + * + *****************************************************************************/ + +CreateDirectoryTableStmt: + CREATE DIRECTORY TABLE qualified_name + table_access_method_clause OptTableSpace OptDistributedBy + { + CreateDirectoryTableStmt *n = makeNode(CreateDirectoryTableStmt); + $4->relpersistence = RELPERSISTENCE_PERMANENT; + n->base.relation = $4; + n->base.inhRelations = NIL; + n->base.ofTypename = NULL; + n->base.constraints = NIL; + n->base.options = NIL; + n->base.oncommit = ONCOMMIT_NOOP; + /* TODO: support tablespace for data table ? */ + n->base.tablespacename = NULL; + n->base.if_not_exists = false; + n->base.distributedBy = (DistributedBy *) $7; + if (n->base.distributedBy != NULL) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("Create directory table is not allowed to set distributed by."), + parser_errposition(@7))); + n->base.relKind = RELKIND_DIRECTORY_TABLE; + n->tablespacename = $6; + + $$ = (Node *) n; + } + | CREATE DIRECTORY TABLE IF_P NOT EXISTS qualified_name + table_access_method_clause OptTableSpace OptDistributedBy + { + CreateDirectoryTableStmt *n = makeNode(CreateDirectoryTableStmt); + $7->relpersistence = RELPERSISTENCE_PERMANENT; + n->base.relation = $7; + n->base.inhRelations = NIL; + n->base.ofTypename = NULL; + n->base.constraints = NIL; + n->base.options = NIL; + n->base.oncommit = ONCOMMIT_NOOP; + /* TODO: support tablespace for data table? */ + n->base.tablespacename = NULL; + n->base.if_not_exists = true; + n->base.distributedBy = (DistributedBy *) $10; + if (n->base.distributedBy != NULL) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("Create directory table is not allowed to set distributed by."), + parser_errposition(@10))); + n->base.relKind = RELKIND_DIRECTORY_TABLE; + n->tablespacename = $9; + + $$ = (Node *) n; + } + ; + /***************************************************************************** * * QUERIES: @@ -9093,7 +9356,8 @@ object_type_any_name: | INDEX { $$ = OBJECT_INDEX; } | FOREIGN TABLE { $$ = OBJECT_FOREIGN_TABLE; } | EXTERNAL TABLE { $$ = OBJECT_FOREIGN_TABLE; } - | EXTERNAL WEB TABLE { $$ = OBJECT_FOREIGN_TABLE; } + | EXTERNAL WEB TABLE { $$ = OBJECT_FOREIGN_TABLE; } + | DIRECTORY TABLE { $$ = OBJECT_DIRECTORY_TABLE; } | COLLATION { $$ = OBJECT_COLLATION; } | CONVERSION_P { $$ = OBJECT_CONVERSION; } | STATISTICS { $$ = OBJECT_STATISTIC_EXT; } @@ -18742,6 +19006,7 @@ unreserved_keyword: | DEPTH | DETACH | DICTIONARY + | DIRECTORY | DISABLE_P | DISCARD | DOCUMENT_P @@ -18984,6 +19249,7 @@ unreserved_keyword: | SYSTEM_P | TABLES | TABLESPACE + | TAG | TASK | TEMP | TEMPLATE @@ -19112,6 +19378,7 @@ PartitionIdentKeyword: ABORT_P | DEPTH | DETACH | DICTIONARY + | DIRECTORY | DISABLE_P | DOMAIN_P | DOUBLE_P @@ -19663,6 +19930,7 @@ bare_label_keyword: | DESC | DETACH | DICTIONARY + | DIRECTORY | DISABLE_P | DISCARD | DISTINCT @@ -19967,6 +20235,7 @@ bare_label_keyword: | TABLES | TABLESAMPLE | TABLESPACE + | TAG | TASK | TEMP | TEMPLATE diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c index 7db57c7e106..de1f9626dfa 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -1319,7 +1319,8 @@ transformFromClauseItem(ParseState *pstate, Node *n, if (rte->rtekind != RTE_RELATION || (rte->relkind != RELKIND_RELATION && rte->relkind != RELKIND_MATVIEW && - rte->relkind != RELKIND_PARTITIONED_TABLE)) + rte->relkind != RELKIND_PARTITIONED_TABLE && + rte->relkind != RELKIND_DIRECTORY_TABLE)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("TABLESAMPLE clause can only be applied to tables and materialized views"), diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c index 7001a143134..87126e78517 100644 --- a/src/backend/parser/parse_relation.c +++ b/src/backend/parser/parse_relation.c @@ -1486,7 +1486,8 @@ addRangeTableEntry(ParseState *pstate, RelationIsAppendOptimized(rel)) pstate->p_canOptSelectLockingClause = false; - if (rel->rd_rel->relkind == RELKIND_MATVIEW) + if (rel->rd_rel->relkind == RELKIND_MATVIEW || + rel->rd_rel->relkind == RELKIND_DIRECTORY_TABLE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("cannot lock rows in materialized view \"%s\"", diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index b83ebc67524..446af6f3cf0 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -1081,6 +1081,7 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla relation = relation_openrv(table_like_clause->relation, AccessShareLock); if (relation->rd_rel->relkind != RELKIND_RELATION && + relation->rd_rel->relkind != RELKIND_DIRECTORY_TABLE && relation->rd_rel->relkind != RELKIND_VIEW && relation->rd_rel->relkind != RELKIND_MATVIEW && relation->rd_rel->relkind != RELKIND_COMPOSITE_TYPE && @@ -1088,7 +1089,7 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("\"%s\" is not a table, view, materialized view, composite type, or foreign table", + errmsg("\"%s\" is not a table, directory table, view, materialized view, composite type, or foreign table", RelationGetRelationName(relation)))); cancel_parser_errposition_callback(&pcbstate); diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index 7a10cc913a5..6a82a5ec3db 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -2173,6 +2173,7 @@ do_autovacuum(void) bool wraparound; if (classForm->relkind != RELKIND_RELATION && + classForm->relkind != RELKIND_DIRECTORY_TABLE && classForm->relkind != RELKIND_MATVIEW && classForm->relkind != RELKIND_AOSEGMENTS && classForm->relkind != RELKIND_AOBLOCKDIR && @@ -2362,7 +2363,8 @@ do_autovacuum(void) * completely unrelated to the one we saw before. */ if (!((classForm->relkind == RELKIND_RELATION || - classForm->relkind == RELKIND_MATVIEW) && + classForm->relkind == RELKIND_MATVIEW || + classForm->relkind == RELKIND_DIRECTORY_TABLE) && classForm->relpersistence == RELPERSISTENCE_TEMP)) { UnlockRelationOid(relid, AccessExclusiveLock); @@ -2859,6 +2861,7 @@ extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc) Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION || ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW || + ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_DIRECTORY_TABLE || ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE || ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_AOSEGMENTS || ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_AOBLOCKDIR || diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c index 6df8ffd2ead..19973c195da 100644 --- a/src/backend/rewrite/rewriteDefine.c +++ b/src/backend/rewrite/rewriteDefine.c @@ -295,12 +295,13 @@ DefineQueryRewrite(const char *rulename, * blocks them for users. Don't mention them in the error message. */ if (event_relation->rd_rel->relkind != RELKIND_RELATION && + event_relation->rd_rel->relkind != RELKIND_DIRECTORY_TABLE && event_relation->rd_rel->relkind != RELKIND_MATVIEW && event_relation->rd_rel->relkind != RELKIND_VIEW && event_relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("\"%s\" is not a table or view", + errmsg("\"%s\" is not a table, directory table or view", RelationGetRelationName(event_relation)))); if (!allowSystemTableMods && IsSystemRelation(event_relation)) @@ -468,7 +469,8 @@ DefineQueryRewrite(const char *rulename, RelationGetRelationName(event_relation)))); /* only case left: */ - Assert(event_relation->rd_rel->relkind == RELKIND_RELATION); + Assert(event_relation->rd_rel->relkind == RELKIND_RELATION || + event_relation->rd_rel->relkind == RELKIND_DIRECTORY_TABLE); if (event_relation->rd_rel->relispartition) ereport(ERROR, diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c index 6050794b6dd..7ba5f9a56bc 100644 --- a/src/backend/rewrite/rewriteHandler.c +++ b/src/backend/rewrite/rewriteHandler.c @@ -2685,6 +2685,7 @@ view_query_is_auto_updatable(Query *viewquery, bool check_cols) if (base_rte->rtekind != RTE_RELATION || (base_rte->relkind != RELKIND_RELATION && base_rte->relkind != RELKIND_FOREIGN_TABLE && + base_rte->relkind != RELKIND_DIRECTORY_TABLE && base_rte->relkind != RELKIND_VIEW && base_rte->relkind != RELKIND_PARTITIONED_TABLE)) return gettext_noop("Views that do not select from a single table or view are not automatically updatable."); diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index 33241bfdddc..577d120e21a 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -3137,6 +3137,7 @@ RelationGetNumberOfBlocksInFork(Relation relation, ForkNumber forkNum) return smgrnblocks(relation->rd_smgr, forkNum); case RELKIND_RELATION: + case RELKIND_DIRECTORY_TABLE: case RELKIND_TOASTVALUE: case RELKIND_MATVIEW: case RELKIND_AOSEGMENTS: diff --git a/src/backend/storage/file/Makefile b/src/backend/storage/file/Makefile index 7f07a740afa..07dfb28e0d2 100644 --- a/src/backend/storage/file/Makefile +++ b/src/backend/storage/file/Makefile @@ -17,7 +17,8 @@ OBJS = \ copydir.o \ fd.o \ reinit.o \ - sharedfileset.o + sharedfileset.o \ + ufile.o OBJS += execute_pipe.o gp_compress.o diff --git a/src/backend/storage/file/ufile.c b/src/backend/storage/file/ufile.c new file mode 100644 index 00000000000..66726a2c41f --- /dev/null +++ b/src/backend/storage/file/ufile.c @@ -0,0 +1,470 @@ +/*------------------------------------------------------------------------- + * + * Unified file abstraction and manipulation. + * + * Copyright (c) 2016-Present Hashdata, Inc. + * + * + * * IDENTIFICATION + * src/backend/storage/file/ufile.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include +#include +#include + +#include "catalog/pg_directory_table.h" +#include "catalog/pg_tablespace.h" +#include "cdb/cdbvars.h" +#include "commands/tablespace.h" +#include "common/relpath.h" +#include "storage/ufile.h" +#include "storage/fd.h" +#include "storage/lwlock.h" +#include "storage/relfilenode.h" +#include "utils/elog.h" +#include "utils/wait_event.h" + +typedef struct LocalFile +{ + FileAm * methods; + File file; + off_t offset; +} LocalFile; + +static UFile *localFileOpen(Oid spcId, const char *fileName, int fileFlags, + char *errorMessage, int errorMessageSize); +static void localFileClose(UFile *file); +static int localFileSync(UFile *file); +static int localFileRead(UFile *file, char *buffer, int amount); +static int localFileWrite(UFile *file, char *buffer, int amount); +static off_t localFileSize(UFile *file); +static void localFileUnlink(Oid spcId, const char *fileName); +static char *localFormatPathName(RelFileNode *relFileNode); +static bool localEnsurePath(Oid spcId, const char *PathName); +static bool localFileExists(Oid spcId, const char *fileName); +static const char *localFileName(UFile *file); +static const char *localGetLastError(void); +static void localGetConnection(Oid spcId); + +static char localFileErrorStr[UFILE_ERROR_SIZE]; + +struct FileAm localFileAm = { + .open = localFileOpen, + .close = localFileClose, + .sync = localFileSync, + .read = localFileRead, + .write = localFileWrite, + .size = localFileSize, + .unlink = localFileUnlink, + .formatPathName = localFormatPathName, + .ensurePath = localEnsurePath, + .exists = localFileExists, + .name = localFileName, + .getLastError = localGetLastError, + .getConnection = localGetConnection, +}; + +static UFile * +localFileOpen(Oid spcId, + const char *fileName, + int fileFlags, + char *errorMessage, + int errorMessageSize) +{ + LocalFile *result; + File file; + + file = PathNameOpenFile(fileName, fileFlags); + if (file < 0) + { + snprintf(errorMessage, errorMessageSize, "%s", strerror(errno)); + return NULL; + } + + result = palloc0(sizeof(LocalFile)); + result->methods = &localFileAm; + result->file = file; + result->offset = 0; + + return (UFile *) result; +} + +static void +localFileClose(UFile *file) +{ + LocalFile *localFile = (LocalFile *) file; + + FileClose(localFile->file); +} + +static int +localFileSync(UFile *file) +{ + int result; + LocalFile *localFile = (LocalFile *) file; + + result = FileSync(localFile->file, WAIT_EVENT_DATA_FILE_SYNC); + if (result == -1) + snprintf(localFileErrorStr, UFILE_ERROR_SIZE, "%s", strerror(errno)); + + return result; +} + +static int +localFilePread(UFile *file, char *buffer, int amount, off_t offset) +{ + int bytes; + LocalFile *localFile = (LocalFile *) file; + + localFile->offset = offset; + bytes = FileRead(localFile->file, buffer, amount, offset, WAIT_EVENT_DATA_FILE_READ); + if (bytes < 0) + { + snprintf(localFileErrorStr, UFILE_ERROR_SIZE, "%s", strerror(errno)); + return -1; + } + + localFile->offset += bytes; + return bytes; +} + +static int +localFileRead(UFile *file, char *buffer, int amount) +{ + LocalFile *localFile = (LocalFile *) file; + + return localFilePread(file, buffer, amount, localFile->offset); +} + +static int +localFilePwrite(UFile *file, char *buffer, int amount, off_t offset) +{ + int bytes; + LocalFile *localFile = (LocalFile *) file; + + localFile->offset = offset; + bytes = FileWrite(localFile->file, buffer, amount, offset, WAIT_EVENT_DATA_FILE_WRITE); + if (bytes < 0) + { + snprintf(localFileErrorStr, UFILE_ERROR_SIZE, "%s", strerror(errno)); + return -1; + } + + localFile->offset += bytes; + return bytes; +} + +static int +localFileWrite(UFile *file, char *buffer, int amount) +{ + LocalFile *localFile = (LocalFile *) file; + + return localFilePwrite(file, buffer, amount, localFile->offset); +} + +static off_t +localFileSize(UFile *file) +{ + LocalFile *localFile = (LocalFile *) file; + + return FileSize(localFile->file); +} + +static bool +destory_local_file_directories(const char* directoryName) +{ + DIR *dirdesc; + struct dirent *de; + char *subfile; + struct stat st; + + Assert(LWLockHeldByMe(DirectoryTableLock)); + + elog(DEBUG5, "destory_local_file_directories for directory %s", + directoryName); + + dirdesc = AllocateDir(directoryName); + if (dirdesc == NULL) + { + if (errno == ENOENT) + { + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not open directory \"%s\": %m", + directoryName))); + /* The symlink might still exist, so go try to remove it */ + return false; + } + } + + while ((de = ReadDir(dirdesc, directoryName)) != NULL) + { + if (strcmp(de->d_name, ".") == 0 || + strcmp(de->d_name, "..") == 0) + continue; + + subfile = psprintf("%s/%s", directoryName, de->d_name); + + if (stat(subfile, &st) == 0 && + S_ISDIR(st.st_mode)) + { + /* remove directory and file recursively */ + + if (!destory_local_file_directories(subfile)) + { + ereport(WARNING, + (errcode_for_file_access(), + errmsg("directories for directory table \"%s\" could not be removed: %m", + subfile), + errhint("You can remove the directories manually if necessary."))); + + FreeDir(dirdesc); + pfree(subfile); + + return false; + } + } + else + { + /* remove file */ + if (unlink(subfile) < 0) + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not remove files \"%s\": %m", + subfile))); + } + + pfree(subfile); + } + + FreeDir(dirdesc); + + /* remove directory */ + if (rmdir(directoryName) < 0) + { + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not remove directory \"%s\": %m", + directoryName))); + } + + return true; +} + +static void +localFileUnlink(Oid spcId, const char *fileName) +{ + struct stat st; + + LWLockAcquire(DirectoryTableLock, LW_EXCLUSIVE); + if (stat(fileName, &st) == 0 && + S_ISDIR(st.st_mode)) + { + /* remove directory and file recursively */ + if (!destory_local_file_directories(fileName)) + ereport(WARNING, + (errcode_for_file_access(), + errmsg("directories for directory table \"%s\" could not be removed: %m", + fileName), + errhint("You can remove the directories manually if necessary."))); + LWLockRelease(DirectoryTableLock); + } + else + { + LWLockRelease(DirectoryTableLock); + /* remove file */ + if (unlink(fileName) < 0) + { + if (errno != ENOENT) + ereport(WARNING, + (errcode_for_file_access(), + errmsg("could not remove file \"%s\": %m", fileName))); + } + } + +} + +static char * +localFormatPathName(RelFileNode *relFileNode) +{ + if (relFileNode->spcNode == DEFAULTTABLESPACE_OID) + return psprintf("base/%u/"UINT64_FORMAT"_dirtable", + relFileNode->dbNode, relFileNode->relNode); + else + return psprintf("pg_tblspc/%u/%s/%u/"UINT64_FORMAT"_dirtable", + relFileNode->spcNode, GP_TABLESPACE_VERSION_DIRECTORY, + relFileNode->dbNode, relFileNode->relNode); +} + +bool +localEnsurePath(Oid spcId, const char *PathName) +{ + struct stat st; + char *localPath; + + localPath = pstrdup(PathName); + + if (stat(localPath, &st) != 0 && pg_mkdir_p(localPath, S_IRWXU) != 0) + { + ereport(WARNING, + (errmsg("can not recursively create directory \"%s\"", + localPath))); + return false; + } + + return true; +} + +static bool +localFileExists(Oid spcId, const char *fileName) +{ + struct stat fileStats; + + if (stat(fileName, &fileStats) != 0) + { + if (errno == ENOENT) + return false; + + ereport(ERROR, + (errcode_for_file_access(), + errmsg("unable to stat file \"%s\": %m", fileName))); + } + + return true; +} + +static const char * +localFileName(UFile *file) +{ + LocalFile *localFile = (LocalFile *) file; + + return FilePathName(localFile->file); +} + +static const char * +localGetLastError(void) +{ + return localFileErrorStr; +} + +static void +localGetConnection(Oid spcId) +{ + return; +} + +UFile * +UFileOpen(Oid spcId, + const char *fileName, + int fileFlags, + char *errorMessage, + int errorMessageSize) +{ + UFile *ufile; + FileAm *fileAm; + + fileAm = GetTablespaceFileHandler(spcId); + ufile = fileAm->open(spcId, fileName, fileFlags, errorMessage, errorMessageSize); + + return ufile; +} + +void +UFileClose(UFile *file) +{ + file->methods->close(file); + //TODO pfree move to close + pfree(file); +} + +int +UFileSync(UFile *file) +{ + return file->methods->sync(file); +} + +int +UFileRead(UFile *file, char *buffer, int amount) +{ + return file->methods->read(file, buffer, amount); +} + +int +UFileWrite(UFile *file, char *buffer, int amount) +{ + return file->methods->write(file, buffer, amount); +} + +int64_t +UFileSize(UFile *file) +{ + return file->methods->size(file); +} + +const char * +UFileName(UFile *file) +{ + return file->methods->name(file); +} + +void +UFileUnlink(Oid spcId, const char *fileName) +{ + FileAm *fileAm; + + fileAm = GetTablespaceFileHandler(spcId); + + fileAm->unlink(spcId, fileName); +} + +char * +UFileFormatPathName(RelFileNode *relFileNode) +{ + FileAm *fileAm; + + fileAm = GetTablespaceFileHandler(relFileNode->spcNode); + + return fileAm->formatPathName(relFileNode); +} + +bool +UFileEnsurePath(Oid spcId, const char *pathName) +{ + FileAm *fileAm; + + fileAm = GetTablespaceFileHandler(spcId); + + return fileAm->ensurePath(spcId, pathName); +} + +bool +UFileExists(Oid spcId, const char *fileName) +{ + FileAm *fileAm; + + fileAm = GetTablespaceFileHandler(spcId); + + return fileAm->exists(spcId, fileName); +} + +const char * +UFileGetLastError(UFile *file) +{ + return file->methods->getLastError(); +} + +void +forceCacheUFileResource(Oid spcId) +{ + FileAm *fileAm; + + fileAm = GetTablespaceFileHandler(spcId); + + return fileAm->getConnection(spcId); +} + diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c index 93e6152ae84..3ff56accb7b 100644 --- a/src/backend/storage/ipc/procarray.c +++ b/src/backend/storage/ipc/procarray.c @@ -2079,6 +2079,7 @@ GlobalVisHorizonKindForRel(Relation rel) Assert(!rel || rel->rd_rel->relkind == RELKIND_RELATION || rel->rd_rel->relkind == RELKIND_MATVIEW || + rel->rd_rel->relkind == RELKIND_DIRECTORY_TABLE || rel->rd_rel->relkind == RELKIND_AOSEGMENTS || rel->rd_rel->relkind == RELKIND_AOVISIMAP || rel->rd_rel->relkind == RELKIND_AOBLOCKDIR || diff --git a/src/backend/storage/lmgr/lwlocknames.txt b/src/backend/storage/lmgr/lwlocknames.txt index a3496fc00c9..c8f283198ce 100644 --- a/src/backend/storage/lmgr/lwlocknames.txt +++ b/src/backend/storage/lmgr/lwlocknames.txt @@ -74,3 +74,4 @@ GpParallelDSMHashLock 64 LoginFailedControlLock 65 LoginFailedSharedMemoryLock 66 GPIVMResLock 67 +DirectoryTableLock 68 diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index c0f7b54a29f..21b27c2806d 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -5355,10 +5355,10 @@ PostgresMain(int argc, char *argv[], initStringInfo(&input_message); - /* Reset elog globals */ - currentSliceId = UNSET_SLICE_ID; - if (Gp_role == GP_ROLE_EXECUTE) - gp_command_count = 0; + /* Reset elog globals */ + currentSliceId = UNSET_SLICE_ID; + if (Gp_role == GP_ROLE_EXECUTE) + gp_command_count = 0; /* * Do deactiving and runaway detecting before ReadyForQuery(), diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 49d0dbce11b..55105efebd0 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -37,6 +37,7 @@ #include "commands/createas.h" #include "commands/dbcommands.h" #include "commands/defrem.h" +#include "commands/dirtablecmds.h" #include "commands/discard.h" #include "commands/event_trigger.h" #include "commands/explain.h" @@ -54,6 +55,7 @@ #include "commands/schemacmds.h" #include "commands/seclabel.h" #include "commands/sequence.h" +#include "commands/storagecmds.h" #include "commands/subscriptioncmds.h" #include "commands/tablecmds.h" #include "commands/tablespace.h" @@ -181,6 +183,7 @@ ClassifyUtilityCommandAsReadOnly(Node *parsetree) case T_AlterTableStmt: case T_AlterTypeStmt: case T_AlterUserMappingStmt: + case T_AlterStorageUserMappingStmt: case T_CommentStmt: case T_CompositeTypeStmt: case T_CreateAmStmt: @@ -210,7 +213,11 @@ ClassifyUtilityCommandAsReadOnly(Node *parsetree) case T_CreateTableSpaceStmt: case T_CreateTransformStmt: case T_CreateTrigStmt: + case T_CreateStorageServerStmt: + case T_AlterStorageServerStmt: + case T_DropStorageServerStmt: case T_CreateUserMappingStmt: + case T_CreateStorageUserMappingStmt: case T_CreatedbStmt: case T_DefineStmt: case T_DropOwnedStmt: @@ -219,6 +226,7 @@ ClassifyUtilityCommandAsReadOnly(Node *parsetree) case T_DropSubscriptionStmt: case T_DropTableSpaceStmt: case T_DropUserMappingStmt: + case T_DropStorageUserMappingStmt: case T_DropdbStmt: case T_GrantRoleStmt: case T_GrantStmt: @@ -236,6 +244,7 @@ ClassifyUtilityCommandAsReadOnly(Node *parsetree) case T_AlterProfileStmt: case T_AlterQueueStmt: case T_AlterResourceGroupStmt: + case T_CreateDirectoryTableStmt: case T_CreateProfileStmt: case T_CreateQueueStmt: case T_CreateResourceGroupStmt: @@ -1358,6 +1367,7 @@ ProcessUtilitySlow(ParseState *pstate, case T_CreateStmt: case T_CreateForeignTableStmt: + case T_CreateDirectoryTableStmt: { List *stmts; RangeVar *table_rv = NULL; @@ -1544,6 +1554,27 @@ ProcessUtilitySlow(ParseState *pstate, secondaryObject, stmt); } + else if (IsA(stmt, CreateDirectoryTableStmt)) + { + CreateDirectoryTableStmt *cstmt = (CreateDirectoryTableStmt *) stmt; + + /* Remember transformed RangeVar for LIKE */ + table_rv = cstmt->base.relation; + + /* Create the table itself */ + address = DefineRelation(&cstmt->base, + RELKIND_DIRECTORY_TABLE, + InvalidOid, NULL, + queryString, + true, + true, + cstmt->base.intoPolicy); + /* Create directory table tuple */ + CreateDirectoryTable(cstmt, address.objectId); + EventTriggerCollectSimpleCommand(address, + secondaryObject, + stmt); + } else if (IsA(stmt, TableLikeClause)) { /* @@ -2015,6 +2046,19 @@ ProcessUtilitySlow(ParseState *pstate, address = AlterForeignServer((AlterForeignServerStmt *) parsetree); break; + case T_CreateStorageServerStmt: + address = CreateStorageServer((CreateStorageServerStmt *) parsetree); + break; + + case T_AlterStorageServerStmt: + address = AlterStorageServer((AlterStorageServerStmt *) parsetree); + break; + + case T_DropStorageServerStmt: + RemoveStorageServer((DropStorageServerStmt *) parsetree); + commandCollected = true; + break; + case T_CreateUserMappingStmt: address = CreateUserMapping((CreateUserMappingStmt *) parsetree); break; @@ -2029,6 +2073,19 @@ ProcessUtilitySlow(ParseState *pstate, commandCollected = true; break; + case T_CreateStorageUserMappingStmt: + address = CreateStorageUserMapping((CreateStorageUserMappingStmt *) parsetree); + break; + + case T_AlterStorageUserMappingStmt: + address = AlterStorageUserMapping((AlterStorageUserMappingStmt *) parsetree); + break; + + case T_DropStorageUserMappingStmt: + RemoveStorageUserMapping((DropStorageUserMappingStmt *) parsetree); + commandCollected = true; + break; + case T_ImportForeignSchemaStmt: ImportForeignSchema((ImportForeignSchemaStmt *) parsetree); /* commands are stashed inside ImportForeignSchema */ @@ -2456,8 +2513,10 @@ ExecDropStmt(DropStmt *stmt, bool isTopLevel) case OBJECT_VIEW: case OBJECT_MATVIEW: case OBJECT_FOREIGN_TABLE: + case OBJECT_DIRECTORY_TABLE: RemoveRelations(stmt); break; + default: RemoveObjects(stmt); break; @@ -3026,6 +3085,18 @@ CreateCommandTag(Node *parsetree) tag = CMDTAG_ALTER_SERVER; break; + case T_CreateStorageServerStmt: + tag = CMDTAG_CREATE_STORAGE_SERVER; + break; + + case T_AlterStorageServerStmt: + tag = CMDTAG_ALTER_STORAGE_SERVER; + break; + + case T_DropStorageServerStmt: + tag = CMDTAG_DROP_STORAGE_SERVER; + break; + case T_CreateUserMappingStmt: tag = CMDTAG_CREATE_USER_MAPPING; break; @@ -3038,6 +3109,18 @@ CreateCommandTag(Node *parsetree) tag = CMDTAG_DROP_USER_MAPPING; break; + case T_CreateStorageUserMappingStmt: + tag = CMDTAG_CREATE_STORAGE_USER_MAPPING; + break; + + case T_AlterStorageUserMappingStmt: + tag = CMDTAG_ALTER_STORAGE_USER_MAPPING; + break; + + case T_DropStorageUserMappingStmt: + tag = CMDTAG_DROP_STORAGE_USER_MAPPING; + break; + case T_CreateForeignTableStmt: tag = CMDTAG_CREATE_FOREIGN_TABLE; break; @@ -3046,6 +3129,10 @@ CreateCommandTag(Node *parsetree) tag = CMDTAG_IMPORT_FOREIGN_SCHEMA; break; + case T_CreateDirectoryTableStmt: + tag = CMDTAG_CREATE_DIRECTORY_TABLE; + break; + case T_DropStmt: switch (((DropStmt *) parsetree)->removeType) { @@ -3139,6 +3226,9 @@ CreateCommandTag(Node *parsetree) case OBJECT_FOREIGN_SERVER: tag = CMDTAG_DROP_SERVER; break; + case OBJECT_STORAGE_SERVER: + tag = CMDTAG_DROP_STORAGE_SERVER; + break; case OBJECT_OPCLASS: tag = CMDTAG_DROP_OPERATOR_CLASS; break; @@ -3160,6 +3250,9 @@ CreateCommandTag(Node *parsetree) case OBJECT_STATISTIC_EXT: tag = CMDTAG_DROP_STATISTICS; break; + case OBJECT_DIRECTORY_TABLE: + tag = CMDTAG_DROP_DIRECTORY_TABLE; + break; default: tag = CMDTAG_UNKNOWN; } @@ -3891,10 +3984,17 @@ GetCommandLogLevel(Node *parsetree) case T_AlterFdwStmt: case T_CreateForeignServerStmt: case T_AlterForeignServerStmt: + case T_CreateStorageServerStmt: + case T_AlterStorageServerStmt: + case T_DropStorageServerStmt: case T_CreateUserMappingStmt: case T_AlterUserMappingStmt: case T_DropUserMappingStmt: + case T_CreateStorageUserMappingStmt: + case T_AlterStorageUserMappingStmt: + case T_DropStorageUserMappingStmt: case T_ImportForeignSchemaStmt: + case T_CreateDirectoryTableStmt: lev = LOGSTMT_DDL; break; diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c index ef8478c36da..714a536e93d 100644 --- a/src/backend/utils/adt/acl.c +++ b/src/backend/utils/adt/acl.c @@ -791,6 +791,10 @@ acldefault(ObjectType objtype, Oid ownerId) world_default = ACL_NO_RIGHTS; owner_default = ACL_ALL_RIGHTS_FOREIGN_SERVER; break; + case OBJECT_STORAGE_SERVER: + world_default = ACL_NO_RIGHTS; + owner_default = ACL_ALL_RIGHTS_STORAGE_SERVER; + break; case OBJECT_EXTPROTOCOL: world_default = ACL_NO_RIGHTS; owner_default = ACL_ALL_RIGHTS_EXTPROTOCOL; diff --git a/src/backend/utils/adt/dbsize.c b/src/backend/utils/adt/dbsize.c index 3d331afa0b3..ceec9a4afe3 100644 --- a/src/backend/utils/adt/dbsize.c +++ b/src/backend/utils/adt/dbsize.c @@ -549,6 +549,7 @@ pg_relation_size(PG_FUNCTION_ARGS) forkNumber = forkname_to_number(text_to_cstring(forkName)); + // TODO directory table size = calculate_relation_size(rel, forkNumber); if (Gp_role == GP_ROLE_DISPATCH) @@ -1176,6 +1177,7 @@ pg_relation_filenode(PG_FUNCTION_ARGS) case RELKIND_AOSEGMENTS: case RELKIND_AOBLOCKDIR: case RELKIND_AOVISIMAP: + case RELKIND_DIRECTORY_TABLE: /* okay, these have storage */ if (relform->relfilenode) result = relform->relfilenode; @@ -1260,6 +1262,7 @@ pg_relation_filepath(PG_FUNCTION_ARGS) case RELKIND_AOSEGMENTS: case RELKIND_AOVISIMAP: case RELKIND_AOBLOCKDIR: + case RELKIND_DIRECTORY_TABLE: /* okay, these have storage */ /* This logic should match RelationInitPhysicalAddr */ diff --git a/src/backend/utils/adt/pseudotypes.c b/src/backend/utils/adt/pseudotypes.c index c5da77791f6..39729db793c 100644 --- a/src/backend/utils/adt/pseudotypes.c +++ b/src/backend/utils/adt/pseudotypes.c @@ -407,6 +407,7 @@ PSEUDOTYPE_DUMMY_IO_FUNCS(trigger); PSEUDOTYPE_DUMMY_IO_FUNCS(event_trigger); PSEUDOTYPE_DUMMY_IO_FUNCS(language_handler); PSEUDOTYPE_DUMMY_IO_FUNCS(fdw_handler); +PSEUDOTYPE_DUMMY_IO_FUNCS(tblspc_handler); PSEUDOTYPE_DUMMY_IO_FUNCS(table_am_handler); PSEUDOTYPE_DUMMY_IO_FUNCS(index_am_handler); PSEUDOTYPE_DUMMY_IO_FUNCS(tsm_handler); diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c index e10ebdb77da..6d38a2d0de2 100644 --- a/src/backend/utils/adt/xml.c +++ b/src/backend/utils/adt/xml.c @@ -2488,6 +2488,7 @@ schema_get_xml_visible_tables(Oid nspid) appendStringInfo(&query, "SELECT oid FROM pg_catalog.pg_class" " WHERE relnamespace = %u AND relkind IN (" CppAsString2(RELKIND_RELATION) "," + CppAsString2(RELKIND_DIRECTORY_TABLE) "," CppAsString2(RELKIND_MATVIEW) "," CppAsString2(RELKIND_VIEW) ")" " AND pg_catalog.has_table_privilege (oid, 'SELECT')" @@ -2520,6 +2521,7 @@ database_get_xml_visible_tables(void) return query_to_oid_list("SELECT oid FROM pg_catalog.pg_class" " WHERE relkind IN (" CppAsString2(RELKIND_RELATION) "," + CppAsString2(RELKIND_DIRECTORY_TABLE) "," CppAsString2(RELKIND_MATVIEW) "," CppAsString2(RELKIND_VIEW) ")" " AND pg_catalog.has_table_privilege(pg_class.oid, 'SELECT')" diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 1cb10c8d7f5..ebec2de5f07 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -1238,6 +1238,7 @@ RelationBuildDesc(Oid targetRelId, bool insertIt) case RELKIND_RELATION: case RELKIND_TOASTVALUE: case RELKIND_MATVIEW: + case RELKIND_DIRECTORY_TABLE: Assert(relation->rd_rel->relam != InvalidOid); RelationInitTableAccessMethod(relation); break; @@ -1281,7 +1282,8 @@ RelationBuildDesc(Oid targetRelId, bool insertIt) if ((relation->rd_rel->relkind == RELKIND_RELATION && !IsSystemRelation(relation)) || relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE || relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE || - relation->rd_rel->relkind == RELKIND_MATVIEW) + relation->rd_rel->relkind == RELKIND_MATVIEW || + relation->rd_rel->relkind == RELKIND_DIRECTORY_TABLE) { /* * There are many memory allocations in GpPolicyFetch(), especially @@ -3714,6 +3716,7 @@ RelationBuildLocalRelation(const char *relname, if (!IsCatalogNamespace(relnamespace) && (relkind == RELKIND_RELATION || relkind == RELKIND_MATVIEW || + relkind == RELKIND_DIRECTORY_TABLE || relkind == RELKIND_PARTITIONED_TABLE)) rel->rd_rel->relreplident = REPLICA_IDENTITY_DEFAULT; else @@ -3785,6 +3788,7 @@ RelationBuildLocalRelation(const char *relname, MemoryContextSwitchTo(oldcxt); if (relkind == RELKIND_RELATION || + relkind == RELKIND_DIRECTORY_TABLE || relkind == RELKIND_SEQUENCE || relkind == RELKIND_TOASTVALUE || relkind == RELKIND_MATVIEW) @@ -3900,6 +3904,7 @@ RelationSetNewRelfilenode(Relation relation, char persistence) case RELKIND_RELATION: case RELKIND_TOASTVALUE: case RELKIND_MATVIEW: + case RELKIND_DIRECTORY_TABLE: table_relation_set_new_filenode(relation, &newrnode, persistence, &freezeXid, &minmulti); @@ -4395,7 +4400,8 @@ RelationCacheInitializePhase3(void) (relation->rd_rel->relkind == RELKIND_RELATION || relation->rd_rel->relkind == RELKIND_SEQUENCE || relation->rd_rel->relkind == RELKIND_TOASTVALUE || - relation->rd_rel->relkind == RELKIND_MATVIEW)) + relation->rd_rel->relkind == RELKIND_MATVIEW || + relation->rd_rel->relkind == RELKIND_DIRECTORY_TABLE)) { RelationInitTableAccessMethod(relation); Assert(relation->rd_tableam != NULL); @@ -6325,6 +6331,7 @@ load_relcache_init_file(bool shared) /* Load table AM data */ if (rel->rd_rel->relkind == RELKIND_RELATION || + rel->rd_rel->relkind == RELKIND_DIRECTORY_TABLE || rel->rd_rel->relkind == RELKIND_SEQUENCE || rel->rd_rel->relkind == RELKIND_TOASTVALUE || rel->rd_rel->relkind == RELKIND_MATVIEW) diff --git a/src/backend/utils/cache/spccache.c b/src/backend/utils/cache/spccache.c index 5870f436df8..afc784e8f3d 100644 --- a/src/backend/utils/cache/spccache.c +++ b/src/backend/utils/cache/spccache.c @@ -34,13 +34,6 @@ /* Hash table for information about each tablespace */ static HTAB *TableSpaceCacheHash = NULL; -typedef struct -{ - Oid oid; /* lookup key - must be first */ - TableSpaceOpts *opts; /* options, or NULL if none */ -} TableSpaceCacheEntry; - - /* * InvalidateTableSpaceCacheCallback * Flush all cache entries when pg_tablespace is updated. @@ -102,7 +95,7 @@ InitializeTableSpaceCache(void) * Pointers returned by this function should not be stored, since a cache * flush will invalidate them. */ -static TableSpaceCacheEntry * +TableSpaceCacheEntry * get_tablespace(Oid spcid) { TableSpaceCacheEntry *spc; diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c index 3f39c506a76..f81c922e3fc 100644 --- a/src/backend/utils/cache/syscache.c +++ b/src/backend/utils/cache/syscache.c @@ -40,6 +40,7 @@ #include "catalog/pg_default_acl.h" #include "catalog/pg_depend.h" #include "catalog/pg_description.h" +#include "catalog/pg_directory_table.h" #include "catalog/pg_enum.h" #include "catalog/pg_event_trigger.h" #include "catalog/pg_foreign_data_wrapper.h" @@ -78,6 +79,8 @@ #include "catalog/pg_ts_template.h" #include "catalog/pg_type.h" #include "catalog/pg_user_mapping.h" +#include "catalog/gp_storage_user_mapping.h" +#include "catalog/gp_storage_server.h" #include "lib/qunique.h" #include "utils/catcache.h" #include "utils/rel.h" @@ -497,6 +500,28 @@ static const struct cachedesc cacheinfo[] = { }, 2 }, + {StorageServerRelationId, /* STORAGESERVERNAME */ + StorageServerNameIndexId, + 1, + { + Anum_gp_storage_server_srvname, + 0, + 0, + 0 + }, + 2 + }, + {StorageServerRelationId, /* STORAGESERVEROID */ + StorageServerOidIndexId, + 1, + { + Anum_gp_storage_server_oid, + 0, + 0, + 0 + }, + 2 + }, {ForeignTableRelationId, /* FOREIGNTABLEREL */ ForeignTableRelidIndexId, 1, @@ -1070,6 +1095,39 @@ static const struct cachedesc cacheinfo[] = { }, 64 }, + {DirectoryTableRelationId, /* DIRECTORYTABLEREL */ + DirectoryTableRelidIndexId, + 1, + { + Anum_pg_directory_table_dtrelid, + 0, + 0, + 0 + }, + 4 + }, + {StorageUserMappingRelationId, /* STORAGEUSERMAPPINGOID */ + StorageUserMappingOidIndexId, + 1, + { + Anum_gp_storage_user_mapping_oid, + 0, + 0, + 0 + }, + 2 + }, + {StorageUserMappingRelationId, /* STORAGEUSERMAPPINGUSERSERVER */ + StorageUserMappingServerIndexId, + 2, + { + Anum_gp_storage_user_mapping_umuser, + Anum_gp_storage_user_mapping_umserver, + 0, + 0 + }, + 2 + }, {UserMappingRelationId, /* USERMAPPINGOID */ UserMappingOidIndexId, 1, diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c index a80f80aef6e..220e908ad3e 100644 --- a/src/bin/initdb/initdb.c +++ b/src/bin/initdb/initdb.c @@ -1797,7 +1797,7 @@ setup_privileges(FILE *cmdfd) " ) as a) " " WHERE relkind IN (" CppAsString2(RELKIND_RELATION) ", " CppAsString2(RELKIND_VIEW) ", " CppAsString2(RELKIND_MATVIEW) ", " - CppAsString2(RELKIND_SEQUENCE) ")" + CppAsString2(RELKIND_SEQUENCE) ", " CppAsString2(RELKIND_DIRECTORY_TABLE) ")" " AND relacl IS NULL;\n\n", "GRANT USAGE ON SCHEMA pg_catalog TO PUBLIC;\n\n", "GRANT CREATE, USAGE ON SCHEMA public TO PUBLIC;\n\n", @@ -1816,7 +1816,7 @@ setup_privileges(FILE *cmdfd) " relacl IS NOT NULL" " AND relkind IN (" CppAsString2(RELKIND_RELATION) ", " CppAsString2(RELKIND_VIEW) ", " CppAsString2(RELKIND_MATVIEW) ", " - CppAsString2(RELKIND_SEQUENCE) ");\n\n", + CppAsString2(RELKIND_SEQUENCE) ", " CppAsString2(RELKIND_DIRECTORY_TABLE) ");\n\n", "INSERT INTO pg_init_privs " " (objoid, classoid, objsubid, initprivs, privtype)" " SELECT" @@ -1832,7 +1832,7 @@ setup_privileges(FILE *cmdfd) " pg_attribute.attacl IS NOT NULL" " AND pg_class.relkind IN (" CppAsString2(RELKIND_RELATION) ", " CppAsString2(RELKIND_VIEW) ", " CppAsString2(RELKIND_MATVIEW) ", " - CppAsString2(RELKIND_SEQUENCE) ");\n\n", + CppAsString2(RELKIND_SEQUENCE) ", " CppAsString2(RELKIND_DIRECTORY_TABLE) ");\n\n", "INSERT INTO pg_init_privs " " (objoid, classoid, objsubid, initprivs, privtype)" " SELECT" diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c index 38e6d321b1c..1b2ba109c8e 100644 --- a/src/bin/pg_dump/pg_dumpall.c +++ b/src/bin/pg_dump/pg_dumpall.c @@ -1754,7 +1754,40 @@ dumpTablespaces(PGconn *conn) return; } - if (server_version >= 90600) + if (server_version >= 140000) + { + res = executeQuery(conn, "SELECT oid, spcname, " + "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, " + "pg_catalog.pg_tablespace_location(oid), " + "(SELECT array_agg(acl ORDER BY row_n) FROM " + " (SELECT acl, row_n FROM " + " unnest(coalesce(spcacl,acldefault('t',spcowner))) " + " WITH ORDINALITY AS perm(acl,row_n) " + " WHERE NOT EXISTS ( " + " SELECT 1 " + " FROM unnest(acldefault('t',spcowner)) " + " AS init(init_acl) " + " WHERE acl = init_acl)) AS spcacls) " + " AS spcacl, " + "(SELECT array_agg(acl ORDER BY row_n) FROM " + " (SELECT acl, row_n FROM " + " unnest(acldefault('t',spcowner)) " + " WITH ORDINALITY AS initp(acl,row_n) " + " WHERE NOT EXISTS ( " + " SELECT 1 " + " FROM unnest(coalesce(spcacl,acldefault('t',spcowner))) " + " AS permp(orig_acl) " + " WHERE acl = orig_acl)) AS rspcacls) " + " AS rspcacl, " + "array_to_string(spcoptions, ', ')," + "pg_catalog.shobj_description(oid, 'pg_tablespace'), " + "spcfilehandlersrc AS spchandlersrc, " + "spcfilehandlerbin AS spchandlerbin " + "FROM pg_catalog.pg_tablespace " + "WHERE spcname !~ '^pg_' " + "ORDER BY 1"); + } + else if (server_version >= 90600) res = executeQuery(conn, "SELECT oid, spcname, " "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, " "pg_catalog.pg_tablespace_location(oid), " @@ -1779,7 +1812,7 @@ dumpTablespaces(PGconn *conn) " WHERE acl = orig_acl)) AS rspcacls) " " AS rspcacl, " "array_to_string(spcoptions, ', ')," - "pg_catalog.shobj_description(oid, 'pg_tablespace') " + "pg_catalog.shobj_description(oid, 'pg_tablespace'), null " "FROM pg_catalog.pg_tablespace " "WHERE spcname !~ '^pg_' " "ORDER BY 1"); @@ -1789,7 +1822,7 @@ dumpTablespaces(PGconn *conn) "pg_catalog.pg_tablespace_location(oid), " "spcacl, '' as rspcacl, " "array_to_string(spcoptions, ', ')," - "pg_catalog.shobj_description(oid, 'pg_tablespace') " + "pg_catalog.shobj_description(oid, 'pg_tablespace'), null " "FROM pg_catalog.pg_tablespace " "WHERE spcname !~ '^pg_' " "ORDER BY 1"); @@ -1798,7 +1831,7 @@ dumpTablespaces(PGconn *conn) "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, " "spclocation, spcacl, '' as rspcacl, " "array_to_string(spcoptions, ', ')," - "pg_catalog.shobj_description(oid, 'pg_tablespace') " + "pg_catalog.shobj_description(oid, 'pg_tablespace'), null " "FROM pg_catalog.pg_tablespace " "WHERE spcname !~ '^pg_' " "ORDER BY 1"); @@ -1806,7 +1839,7 @@ dumpTablespaces(PGconn *conn) res = executeQuery(conn, "SELECT oid, spcname, " "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, " "spclocation, spcacl, '' as rspcacl, null, " - "pg_catalog.shobj_description(oid, 'pg_tablespace') " + "pg_catalog.shobj_description(oid, 'pg_tablespace'), null " "FROM pg_catalog.pg_tablespace " "WHERE spcname !~ '^pg_' " "ORDER BY 1"); @@ -1816,7 +1849,7 @@ dumpTablespaces(PGconn *conn) res = executeQuery(conn, "SELECT oid, spcname, " "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, " "spclocation, spcacl, '' as rspcacl, " - "null, null " + "null, null, null " "FROM pg_catalog.pg_tablespace " "WHERE spcname !~ '^pg_' " "ORDER BY 1"); @@ -1836,6 +1869,8 @@ dumpTablespaces(PGconn *conn) char *rspcacl = PQgetvalue(res, i, 5); char *spcoptions = PQgetvalue(res, i, 6); char *spccomment = PQgetvalue(res, i, 7); + char *spchandlersrc = PQgetvalue(res, i, 8); + char *spchandlerbin = PQgetvalue(res, i, 9); char *fspcname; /* needed for buildACLCommands() */ @@ -1846,6 +1881,13 @@ dumpTablespaces(PGconn *conn) appendPQExpBufferStr(buf, " LOCATION "); appendStringLiteralConn(buf, spclocation, conn); + if (spchandlerbin && spchandlerbin[0] != '\0') + { + appendPQExpBufferStr(buf, " HANDLER "); + appendStringLiteralConn(buf, spchandlerbin, conn); + appendPQExpBufferStr(buf, ", "); + appendStringLiteralConn(buf, spchandlersrc, conn); + } appendPQExpBufferStr(buf, ";\n"); if (spcoptions && spcoptions[0] != '\0') diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index fef6aa4c60a..61d23dade87 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -849,6 +849,7 @@ exec_command_d(PsqlScanState scan_state, bool active_branch, const char *cmd) case 'm': case 'i': case 's': + case 'Y': case 'E': /* PostgreSQL use dx for extension, change to dE for foreign table */ success = listTables(&cmd[1], pattern, show_verbose, show_system); break; diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index 303df0068c7..5de2cefdb75 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -1330,6 +1330,7 @@ permissionsList(const char *pattern) " c.relname as \"%s\",\n" " CASE c.relkind" " WHEN " CppAsString2(RELKIND_RELATION) " THEN '%s'" + " WHEN " CppAsString2(RELKIND_DIRECTORY_TABLE) " THEN '%s'" " WHEN " CppAsString2(RELKIND_VIEW) " THEN '%s'" " WHEN " CppAsString2(RELKIND_MATVIEW) " THEN '%s'" " WHEN " CppAsString2(RELKIND_SEQUENCE) " THEN '%s'" @@ -1340,6 +1341,7 @@ permissionsList(const char *pattern) gettext_noop("Schema"), gettext_noop("Name"), gettext_noop("table"), + gettext_noop("directory table"), gettext_noop("view"), gettext_noop("materialized view"), gettext_noop("sequence"), @@ -1427,6 +1429,7 @@ permissionsList(const char *pattern) " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n" "WHERE c.relkind IN (" CppAsString2(RELKIND_RELATION) "," + CppAsString2(RELKIND_DIRECTORY_TABLE) "," CppAsString2(RELKIND_VIEW) "," CppAsString2(RELKIND_MATVIEW) "," CppAsString2(RELKIND_SEQUENCE) "," @@ -2315,6 +2318,7 @@ describeOneTableDetails(const char *schemaname, /* Identify whether we should print collation, nullable, default vals */ if (tableinfo.relkind == RELKIND_RELATION || + tableinfo.relkind == RELKIND_DIRECTORY_TABLE || tableinfo.relkind == RELKIND_VIEW || tableinfo.relkind == RELKIND_MATVIEW || tableinfo.relkind == RELKIND_FOREIGN_TABLE || @@ -2403,6 +2407,7 @@ describeOneTableDetails(const char *schemaname, /* stats target, if relevant to relkind */ if (tableinfo.relkind == RELKIND_RELATION || + tableinfo.relkind == RELKIND_DIRECTORY_TABLE || tableinfo.relkind == RELKIND_INDEX || tableinfo.relkind == RELKIND_PARTITIONED_INDEX || tableinfo.relkind == RELKIND_MATVIEW || @@ -2427,6 +2432,7 @@ describeOneTableDetails(const char *schemaname, * types, and foreign tables (cf. CommentObject() in comment.c). */ if (tableinfo.relkind == RELKIND_RELATION || + tableinfo.relkind == RELKIND_DIRECTORY_TABLE || tableinfo.relkind == RELKIND_VIEW || tableinfo.relkind == RELKIND_MATVIEW || tableinfo.relkind == RELKIND_FOREIGN_TABLE || @@ -2463,6 +2469,10 @@ describeOneTableDetails(const char *schemaname, printfPQExpBuffer(&title, _("Table \"%s.%s\""), schemaname, relationname); break; + case RELKIND_DIRECTORY_TABLE: + printfPQExpBuffer(&title, _("Directory able \"%s.%s\""), + schemaname, relationname); + break; case RELKIND_VIEW: printfPQExpBuffer(&title, _("View \"%s.%s\""), schemaname, relationname); @@ -2917,6 +2927,7 @@ describeOneTableDetails(const char *schemaname, } /* If you add relkinds here, see also "Finish printing..." stanza below */ else if (tableinfo.relkind == RELKIND_RELATION || + tableinfo.relkind == RELKIND_DIRECTORY_TABLE || tableinfo.relkind == RELKIND_MATVIEW || tableinfo.relkind == RELKIND_FOREIGN_TABLE || tableinfo.relkind == RELKIND_PARTITIONED_TABLE || @@ -3859,6 +3870,7 @@ describeOneTableDetails(const char *schemaname, * Finish printing the footer information about a table. */ if (tableinfo.relkind == RELKIND_RELATION || + tableinfo.relkind == RELKIND_DIRECTORY_TABLE || tableinfo.relkind == RELKIND_MATVIEW || tableinfo.relkind == RELKIND_FOREIGN_TABLE || tableinfo.relkind == RELKIND_PARTITIONED_TABLE || @@ -4937,6 +4949,7 @@ listDbRoleSettings(const char *pattern, const char *pattern2) * m - materialized views * s - sequences * E - foreign table (Note: different from 'f', the relkind value) + * Y - directory table * (any order of the above is fine) */ bool @@ -4949,6 +4962,7 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys bool showMatViews = strchr(tabtypes, 'm') != NULL; bool showSeq = strchr(tabtypes, 's') != NULL; bool showForeign = strchr(tabtypes, 'E') != NULL; + bool showDirectory = strchr(tabtypes, 'Y') != NULL; PQExpBufferData buf; PGresult *res; @@ -4957,8 +4971,8 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys bool translate_columns[] = {false, false, true, false, false, false, false, false, false}; /* If tabtypes is empty, we default to \dtvmsE (but see also command.c) */ - if (!(showTables || showIndexes || showViews || showMatViews || showSeq || showForeign)) - showTables = showViews = showMatViews = showSeq = showForeign = true; + if (!(showTables || showIndexes || showViews || showMatViews || showSeq || showForeign || showDirectory)) + showTables = showViews = showMatViews = showSeq = showForeign = showDirectory = true; bool showExternal = showForeign; @@ -4979,6 +4993,7 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys " c.relname as \"%s\",\n" " CASE c.relkind" " WHEN " CppAsString2(RELKIND_RELATION) " THEN '%s'" + " WHEN " CppAsString2(RELKIND_DIRECTORY_TABLE) " THEN '%s'" " WHEN " CppAsString2(RELKIND_VIEW) " THEN '%s'" " WHEN " CppAsString2(RELKIND_MATVIEW) " THEN '%s'" " WHEN " CppAsString2(RELKIND_INDEX) " THEN '%s'" @@ -4992,6 +5007,7 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys gettext_noop("Schema"), gettext_noop("Name"), gettext_noop("table"), + gettext_noop("directory table"), gettext_noop("view"), gettext_noop("materialized view"), gettext_noop("index"), @@ -5113,6 +5129,8 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys if (showSystem || pattern) appendPQExpBufferStr(&buf, CppAsString2(RELKIND_TOASTVALUE) ","); } + if (showDirectory) + appendPQExpBufferStr(&buf, CppAsString2(RELKIND_DIRECTORY_TABLE) ","); if (showViews) appendPQExpBufferStr(&buf, CppAsString2(RELKIND_VIEW) ","); if (showMatViews) diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index 0da375e667c..20a59a6ee6f 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -470,6 +470,14 @@ static const SchemaQuery Query_for_list_of_tables = { .result = "pg_catalog.quote_ident(c.relname)", }; +static const SchemaQuery Query_for_list_of_directory_tables = { + .catname = "pg_catalog.pg_class c", + .selcondition = "c.relkind IN (" CppAsString2(RELKIND_DIRECTORY_TABLE) ")", + .viscondition = "pg_catalog.pg_table_is_visible(c.oid)", + .namespace = "c.relnamespace", + .result = "pg_catalog.quote_ident(c.relname)", +}; + static const SchemaQuery Query_for_list_of_partitioned_tables = { .catname = "pg_catalog.pg_class c", .selcondition = "c.relkind IN (" CppAsString2(RELKIND_PARTITIONED_TABLE) ")", @@ -556,6 +564,7 @@ static const SchemaQuery Query_for_list_of_selectables = { .catname = "pg_catalog.pg_class c", .selcondition = "c.relkind IN (" CppAsString2(RELKIND_RELATION) ", " + CppAsString2(RELKIND_DIRECTORY_TABLE) ", " CppAsString2(RELKIND_SEQUENCE) ", " CppAsString2(RELKIND_VIEW) ", " CppAsString2(RELKIND_MATVIEW) ", " @@ -586,6 +595,7 @@ static const SchemaQuery Query_for_list_of_analyzables = { .catname = "pg_catalog.pg_class c", .selcondition = "c.relkind IN (" CppAsString2(RELKIND_RELATION) ", " + CppAsString2(RELKIND_DIRECTORY_TABLE) ", " CppAsString2(RELKIND_PARTITIONED_TABLE) ", " CppAsString2(RELKIND_MATVIEW) ", " CppAsString2(RELKIND_FOREIGN_TABLE) ")", @@ -599,6 +609,7 @@ static const SchemaQuery Query_for_list_of_indexables = { .catname = "pg_catalog.pg_class c", .selcondition = "c.relkind IN (" CppAsString2(RELKIND_RELATION) ", " + CppAsString2(RELKIND_DIRECTORY_TABLE) ", " CppAsString2(RELKIND_PARTITIONED_TABLE) ", " CppAsString2(RELKIND_MATVIEW) ")", .viscondition = "pg_catalog.pg_table_is_visible(c.oid)", @@ -617,7 +628,7 @@ static const SchemaQuery Query_for_list_of_clusterables = { .catname = "pg_catalog.pg_class c", .selcondition = "c.relkind IN (" CppAsString2(RELKIND_RELATION) ", " - CppAsString2(RELKIND_MATVIEW) ")", + CppAsString2(RELKIND_MATVIEW) ", " CppAsString2(RELKIND_DIRECTORY_TABLE) ")", .viscondition = "pg_catalog.pg_table_is_visible(c.oid)", .namespace = "c.relnamespace", .result = "pg_catalog.quote_ident(c.relname)", @@ -919,6 +930,11 @@ static const SchemaQuery Query_for_list_of_collations = { " FROM pg_catalog.pg_user_mappings "\ " WHERE substring(pg_catalog.quote_ident(usename),1,%d)='%s'" +#define Query_for_list_of_storage_servers \ +" SELECT pg_catalog.quote_ident(srvname) "\ +" FROM pg_catalog.gp_storage_server "\ +" WHERE substring(pg_catalog.quote_ident(srvname),1,%d)='%s'" + #define Query_for_list_of_access_methods \ " SELECT pg_catalog.quote_ident(amname) "\ " FROM pg_catalog.pg_am "\ @@ -1099,6 +1115,7 @@ static const pgsql_thing_t words_after_create[] = { {"DATABASE", Query_for_list_of_databases}, {"DEFAULT PRIVILEGES", NULL, NULL, NULL, THING_NO_CREATE | THING_NO_DROP}, {"DICTIONARY", Query_for_list_of_ts_dictionaries, NULL, NULL, THING_NO_SHOW}, + {"DIRECTORY TABLE", NULL, NULL, &Query_for_list_of_directory_tables}, {"DOMAIN", NULL, NULL, &Query_for_list_of_domains}, {"EVENT TRIGGER", NULL, NULL, NULL}, {"EXTENSION", Query_for_list_of_extensions}, @@ -1127,6 +1144,7 @@ static const pgsql_thing_t words_after_create[] = { {"SCHEMA", Query_for_list_of_schemas}, {"SEQUENCE", NULL, NULL, &Query_for_list_of_sequences}, {"SERVER", Query_for_list_of_servers}, + {"STORAGE SERVER", Query_for_list_of_storage_servers}, {"STATISTICS", NULL, NULL, &Query_for_list_of_statistics}, {"SUBSCRIPTION", NULL, Query_for_list_of_subscriptions}, {"SYSTEM", NULL, NULL, NULL, THING_NO_CREATE | THING_NO_DROP}, @@ -1148,6 +1166,7 @@ static const pgsql_thing_t words_after_create[] = { * TABLE ... */ {"USER", Query_for_list_of_roles " UNION SELECT 'MAPPING FOR'"}, {"USER MAPPING FOR", NULL, NULL, NULL}, + {"STORAGE USER MAPPING FOR", NULL, NULL, NULL}, {"VIEW", NULL, NULL, &Query_for_list_of_views}, {"WAREHOUSE", NULL}, {NULL} /* end of list */ @@ -1808,6 +1827,20 @@ psql_completion(const char *text, int start, int end) "INHERIT", "NO INHERIT", "OPTIONS", "OWNER TO", "RENAME", "SET", "VALIDATE CONSTRAINT"); + /* ALTER STORAGE */ + else if (Matches("ALTER", "STORAGE")) + COMPLETE_WITH("SERVER", "USER MAPPING"); + + /* ALTER DIRECTORY */ + else if (Matches("ALTER", "DIRECTORY")) + COMPLETE_WITH("TABLE"); + + /* ALTER DIRECTORY TABLE */ + else if (Matches("ALTER", "DIRECTORY", "TABLE", MatchAny)) + COMPLETE_WITH("ALTER", "DISABLE TRIGGER", "ENABLE", + "OPTIONS", "OWNER TO", + "RENAME", "SET"); + /* ALTER INDEX */ else if (Matches("ALTER", "INDEX")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, @@ -1966,6 +1999,9 @@ psql_completion(const char *text, int start, int end) /* ALTER SERVER */ else if (Matches("ALTER", "SERVER", MatchAny)) COMPLETE_WITH("VERSION", "OPTIONS", "OWNER TO", "RENAME TO"); + /* ALTER STORAGE SERVER */ + else if (Matches("ALTER", "STORAGE", "SERVER", MatchAny)) + COMPLETE_WITH("OPTIONS", "RENAME TO"); /* ALTER SERVER VERSION */ else if (Matches("ALTER", "SERVER", MatchAny, "VERSION", MatchAny)) COMPLETE_WITH("OPTIONS"); @@ -2418,7 +2454,7 @@ psql_completion(const char *text, int start, int end) "INDEX", "LANGUAGE", "POLICY", "PUBLICATION", "RULE", "SCHEMA", "SEQUENCE", "STATISTICS", "SUBSCRIPTION", "TABLE", "TYPE", "VIEW", "MATERIALIZED VIEW", - "COLUMN", "AGGREGATE", "FUNCTION", + "COLUMN", "AGGREGATE", "FUNCTION", "STORAGE SERVER", "PROCEDURE", "PROFILE", "ROUTINE", "OPERATOR", "TRIGGER", "CONSTRAINT", "DOMAIN", "LARGE OBJECT", "TABLESPACE", "TEXT SEARCH", "ROLE"); @@ -2561,6 +2597,10 @@ psql_completion(const char *text, int start, int end) else if (TailMatches("CREATE", "UNIQUE")) COMPLETE_WITH("INDEX"); + /* CREATE STORAGE */ + else if (Matches("CREATE", "STORAGE")) + COMPLETE_WITH("SERVER", "USER MAPPING"); + /* * If we have CREATE|UNIQUE INDEX, then add "ON", "CONCURRENTLY", and * existing indexes @@ -2761,6 +2801,10 @@ psql_completion(const char *text, int start, int end) else if (Matches("CREATE", "SERVER", MatchAny)) COMPLETE_WITH("TYPE", "VERSION", "FOREIGN DATA WRAPPER"); +/* CREATE STORAGE SERVER */ + else if (Matches("CREATE", "STORAGE", "SERVER", MatchAny)) + COMPLETE_WITH("OPTIONS"); + /* CREATE STATISTICS */ else if (Matches("CREATE", "STATISTICS", MatchAny)) COMPLETE_WITH("(", "ON"); @@ -3230,6 +3274,7 @@ psql_completion(const char *text, int start, int end) Matches("DROP", "EVENT", "TRIGGER", MatchAny) || Matches("DROP", "FOREIGN", "DATA", "WRAPPER", MatchAny) || Matches("DROP", "FOREIGN", "TABLE", MatchAny) || + Matches("DROP", "DIRECTORY", "TABLE", MatchAny) || Matches("DROP", "TEXT", "SEARCH", "CONFIGURATION|DICTIONARY|PARSER|TEMPLATE", MatchAny)) COMPLETE_WITH("CASCADE", "RESTRICT"); @@ -3262,6 +3307,15 @@ psql_completion(const char *text, int start, int end) else if (Matches("DROP", "MATERIALIZED", "VIEW")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL); + /* DROP STORAGE */ + else if (Matches("DROP", "STORAGE")) + COMPLETE_WITH("SERVER", "USER MAPPING"); + /* DROP DIRECTORY TABLE */ + else if (Matches("DROP", "DIRECTORY")) + COMPLETE_WITH("TABLE"); + else if (Matches("DROP", "DIRECTORY", "TABLE")) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_directory_tables, NULL); + /* DROP OWNED BY */ else if (Matches("DROP", "OWNED")) COMPLETE_WITH("BY"); @@ -3423,6 +3477,10 @@ psql_completion(const char *text, int start, int end) else if (TailMatches("FOREIGN", "SERVER")) COMPLETE_WITH_QUERY(Query_for_list_of_servers); +/* STORAGE SERVER */ + else if (TailMatches("ALTER", "STORAGE", "SERVER")) + COMPLETE_WITH_QUERY(Query_for_list_of_storage_servers); + /* * GRANT and REVOKE are allowed inside CREATE SCHEMA and * ALTER DEFAULT PRIVILEGES, so use TailMatches @@ -3809,7 +3867,7 @@ psql_completion(const char *text, int start, int end) else if (Matches("SECURITY", "LABEL", "ON") || Matches("SECURITY", "LABEL", "FOR", MatchAny, "ON")) COMPLETE_WITH("TABLE", "COLUMN", "AGGREGATE", "DATABASE", "DOMAIN", - "EVENT TRIGGER", "FOREIGN TABLE", "FUNCTION", + "EVENT TRIGGER", "FOREIGN TABLE", "DIRECTORY TABLE", "FUNCTION", "LARGE OBJECT", "MATERIALIZED VIEW", "LANGUAGE", "PUBLICATION", "PROCEDURE", "ROLE", "ROUTINE", "SCHEMA", "SEQUENCE", "SUBSCRIPTION", "TABLESPACE", "TYPE", "VIEW"); @@ -4000,6 +4058,19 @@ psql_completion(const char *text, int start, int end) COMPLETE_WITH("SERVER"); else if (Matches("CREATE|ALTER", "USER", "MAPPING", "FOR", MatchAny, "SERVER", MatchAny)) COMPLETE_WITH("OPTIONS"); +/* STORAGE USER MAPPING */ + else if (Matches("ALTER|CREATE|DROP", "STORAGE", "USER", "MAPPING")) + COMPLETE_WITH("FOR"); + else if (Matches("CREATE", "STORAGE", "USER", "MAPPING", "FOR")) + COMPLETE_WITH_QUERY(Query_for_list_of_roles + " UNION SELECT 'CURRENT_ROLE'" + " UNION SELECT 'CURRENT_USER'" + " UNION SELECT 'PUBLIC'" + " UNION SELECT 'USER'"); + else if (Matches("CREATE|ALTER|DROP", "STORAGE", "USER", "MAPPING", "FOR", MatchAny)) + COMPLETE_WITH("STORAGE SERVER"); + else if (Matches("CREATE|ALTER", "STORAGE", "USER", "MAPPING", "FOR", MatchAny, "STORAGE", "SERVER", MatchAny)) + COMPLETE_WITH("OPTIONS"); /* * VACUUM [ ( option [, ...] ) ] [ table_and_columns [, ...] ] @@ -4157,6 +4228,8 @@ psql_completion(const char *text, int start, int end) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL); else if (TailMatchesCS("\\dE*")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_foreign_tables, NULL); + else if (TailMatchesCS("\\dY*")) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_directory_tables, NULL); else if (TailMatchesCS("\\dy*")) COMPLETE_WITH_QUERY(Query_for_list_of_event_triggers); @@ -4195,6 +4268,8 @@ psql_completion(const char *text, int start, int end) COMPLETE_WITH("TRIGGER"); else if (TailMatches("CREATE|ALTER|DROP", "FOREIGN")) COMPLETE_WITH("DATA WRAPPER", "TABLE"); + else if (TailMatches("CREATE|ALTER|DROP", "DIRECTORY")) + COMPLETE_WITH("TABLE"); else if (TailMatches("ALTER", "LARGE")) COMPLETE_WITH("OBJECT"); else if (TailMatches("CREATE|ALTER|DROP", "MATERIALIZED")) @@ -4203,6 +4278,8 @@ psql_completion(const char *text, int start, int end) COMPLETE_WITH("SEARCH"); else if (TailMatches("CREATE|ALTER|DROP", "USER")) COMPLETE_WITH("MAPPING FOR"); + else if (TailMatches("CREATE|ALTER|DROP", "STORAGE", "USER")) + COMPLETE_WITH("MAPPING FOR"); } else if (TailMatchesCS("\\h|\\help", MatchAny, MatchAny, MatchAny)) { @@ -4212,6 +4289,8 @@ psql_completion(const char *text, int start, int end) COMPLETE_WITH("CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE"); else if (TailMatches("CREATE|ALTER|DROP", "USER", "MAPPING")) COMPLETE_WITH("FOR"); + else if (TailMatches("CREATE|ALTER|DROP", "STORAGE", "USER", "MAPPING")) + COMPLETE_WITH("FOR"); } else if (TailMatchesCS("\\l*") && !TailMatchesCS("\\lo*")) COMPLETE_WITH_QUERY(Query_for_list_of_databases); diff --git a/src/bin/scripts/reindexdb.c b/src/bin/scripts/reindexdb.c index 7638b01fbdd..22355d38974 100644 --- a/src/bin/scripts/reindexdb.c +++ b/src/bin/scripts/reindexdb.c @@ -669,6 +669,7 @@ get_parallel_object_list(PGconn *conn, ReindexType type, " WHERE ns.nspname != 'pg_catalog'\n" " AND c.relkind IN (" CppAsString2(RELKIND_RELATION) ", " + CppAsString2(RELKIND_DIRECTORY_TABLE) ", " CppAsString2(RELKIND_MATVIEW) ")\n" " ORDER BY c.relpages DESC;"); break; @@ -691,6 +692,7 @@ get_parallel_object_list(PGconn *conn, ReindexType type, " ON c.relnamespace = ns.oid\n" " WHERE c.relkind IN (" CppAsString2(RELKIND_RELATION) ", " + CppAsString2(RELKIND_DIRECTORY_TABLE) ", " CppAsString2(RELKIND_MATVIEW) ")\n" " AND ns.nspname IN ("); diff --git a/src/bin/scripts/vacuumdb.c b/src/bin/scripts/vacuumdb.c index a85919c5c19..04a7273b0a0 100644 --- a/src/bin/scripts/vacuumdb.c +++ b/src/bin/scripts/vacuumdb.c @@ -627,6 +627,7 @@ vacuum_one_database(ConnParams *cparams, { appendPQExpBufferStr(&catalog_query, " WHERE c.relkind OPERATOR(pg_catalog.=) ANY (array[" CppAsString2(RELKIND_RELATION) ", " + CppAsString2(RELKIND_DIRECTORY_TABLE) ", " CppAsString2(RELKIND_MATVIEW) "])\n"); has_where = true; } diff --git a/src/common/md5_common.c b/src/common/md5_common.c index 2114890effe..2e03f893999 100644 --- a/src/common/md5_common.c +++ b/src/common/md5_common.c @@ -24,7 +24,7 @@ #include "common/cryptohash.h" #include "common/md5.h" -static void +void bytesToHex(uint8 b[16], char *s) { static const char *hex = "0123456789abcdef"; diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index fce6ebfd8ee..da23a4c701f 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -56,6 +56,6 @@ */ /* 3yyymmddN */ -#define CATALOG_VERSION_NO 302206171 +#define CATALOG_VERSION_NO 302402231 #endif diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h index a4090f0d2fa..c39c0edfa58 100644 --- a/src/include/catalog/dependency.h +++ b/src/include/catalog/dependency.h @@ -78,6 +78,10 @@ typedef enum DependencyType * is a profile mentioned in a role object. The referenced object must be * a pg_profile entry. * + * (g) a SHARED_DEPENDENCY_STORAGE_SERVER entry means that the referenced + * object is a storage server mentioned in a storage user mapping object. + * The referenced object must be a gp_storage_server entry. + * * SHARED_DEPENDENCY_INVALID is a value used as a parameter in internal * routines, and is not valid in the catalog itself. */ @@ -89,6 +93,7 @@ typedef enum SharedDependencyType SHARED_DEPENDENCY_POLICY = 'r', SHARED_DEPENDENCY_TABLESPACE = 't', SHARED_DEPENDENCY_PROFILE = 'f', + SHARED_DEPENDENCY_STORAGE_SERVER = 's', SHARED_DEPENDENCY_INVALID = 0 } SharedDependencyType; @@ -143,6 +148,9 @@ typedef enum ObjectClass /* GPDB additions */ OCLASS_PROFILE, /* pg_profile */ OCLASS_PASSWORDHISTORY, /* pg_password_history */ + OCLASS_DIRTABLE, /* pg_directory_table */ + OCLASS_STORAGE_SERVER, /* gp_storage_server */ + OCLASS_STORAGE_USER_MAPPING, /* gp_storage_user_mapping */ OCLASS_EXTPROTOCOL, /* pg_extprotocol */ OCLASS_TASK, /* pg_task */ } ObjectClass; @@ -290,6 +298,8 @@ extern void recordProfileDependency(Oid roleId, Oid profileId); extern void changeProfileDependency(Oid roleId, Oid profileId); +extern void recordStorageServerDependency(Oid classId, Oid objectId, Oid srvId); + /* Custom object class */ struct StringInfoData; struct CustomObjectClass { diff --git a/src/include/catalog/gp_storage_server.h b/src/include/catalog/gp_storage_server.h new file mode 100644 index 00000000000..391791ae36d --- /dev/null +++ b/src/include/catalog/gp_storage_server.h @@ -0,0 +1,51 @@ +/*------------------------------------------------------------------------- + * + * gp_storage_server.h + * + * Portions Copyright (c) 2024, HashData Technology Limited. + * + * IDENTIFICATION + * src/include/catalog/gp_storage_server.h + * + *------------------------------------------------------------------------- + */ +#ifndef GP_STORAGE_SERVER_H +#define GP_STORAGE_SERVER_H + +#include "catalog/genbki.h" +#include "catalog/gp_storage_server_d.h" + +/* ---------------- + * gp_storage_server definition. cpp turns this into + * typedef struct FormData_gp_storage_server + * ---------------- + */ +CATALOG(gp_storage_server,6015,StorageServerRelationId) BKI_SHARED_RELATION +{ + Oid oid; /* oid */ + NameData srvname; /* storage server name */ + Oid srvowner BKI_LOOKUP(pg_authid); /* server owner */ + +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + aclitem srvacl[1]; /* access permissions */ + text srvoptions[1]; /* FDW-specific options */ +#endif +} FormData_gp_storage_server; + +/* ---------------- + * Form_gp_storage_server corresponds to a pointer to a tuple with + * the format of gp_storage_server relation. + * ---------------- + */ +typedef FormData_gp_storage_server *Form_gp_storage_server; + +DECLARE_TOAST(gp_storage_server, 6016, 6017); +#define GpStorageServerToastTable 6016 +#define GpStorageServerToastIndex 6017 + +DECLARE_UNIQUE_INDEX_PKEY(gp_storage_server_oid_index, 6018, on gp_storage_server using btree(oid oid_ops)); +#define StorageServerOidIndexId 6018 +DECLARE_UNIQUE_INDEX(gp_storage_server_name_index, 6019, on gp_storage_server using btree(srvname name_ops)); +#define StorageServerNameIndexId 6019 + +#endif //GP_STORAGE_SERVER_H diff --git a/src/include/catalog/gp_storage_user_mapping.h b/src/include/catalog/gp_storage_user_mapping.h new file mode 100644 index 00000000000..a9a18ec1eae --- /dev/null +++ b/src/include/catalog/gp_storage_user_mapping.h @@ -0,0 +1,54 @@ +/*------------------------------------------------------------------------- + * + * gp_storage_user_mapping.h + * + * Portions Copyright (c) 2024, HashData Technology Limited. + * + * IDENTIFICATION + * src/include/catalog/gp_storage_user_mapping.h + * + *------------------------------------------------------------------------- + */ +#ifndef GP_STORAGE_USER_MAPPING_H +#define GP_STORAGE_USER_MAPPING_H + +#include "catalog/genbki.h" +#include "catalog/gp_storage_user_mapping_d.h" + +/* ---------------- + * gp_storage_user_mapping definition. cpp turns this into + * typedef struct FormData_gp_storage_user_mapping + * ---------------- + */ +CATALOG(gp_storage_user_mapping,6131,StorageUserMappingRelationId) BKI_SHARED_RELATION +{ + Oid oid; /* oid */ + + Oid umuser BKI_LOOKUP_OPT(pg_authid); /* Id of the user, + * InvalidOid if PUBLIC is + * wanted */ + Oid umserver BKI_LOOKUP(gp_storage_server); /* server of this + * mapping */ + +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + text umoptions[1]; /* user mapping options */ +#endif +} FormData_gp_storage_user_mapping; + +/* ---------------- + * Form_gp_storage_user_mapping corresponds to a pointer to a tuple with + * the format of gp_storage_user_mapping relation. + * ---------------- + */ +typedef FormData_gp_storage_user_mapping *Form_gp_storage_user_mapping; + +DECLARE_TOAST(gp_storage_user_mapping, 6132, 6133); +#define GpStorageUserMappingToastTable 6132 +#define GpStorageUserMappingToastIndex 6133 + +DECLARE_UNIQUE_INDEX_PKEY(gp_storage_user_mapping_oid_index, 6134, on gp_storage_user_mapping using btree(oid oid_ops)); +#define StorageUserMappingOidIndexId 6134 +DECLARE_UNIQUE_INDEX(gp_storage_user_mapping_server_index, 6135, on gp_storage_user_mapping using btree(umuser oid_ops, umserver oid_ops)); +#define StorageUserMappingServerIndexId 6135 + +#endif //GP_STORAGE_USER_MAPPING_H diff --git a/src/include/catalog/oid_dispatch.h b/src/include/catalog/oid_dispatch.h index bd2fbc261fe..90cc813c6a5 100644 --- a/src/include/catalog/oid_dispatch.h +++ b/src/include/catalog/oid_dispatch.h @@ -63,6 +63,8 @@ extern Oid GetNewOidForForeignDataWrapper(Relation relation, Oid indexId, AttrNu char *fdwname); extern Oid GetNewOidForForeignServer(Relation relation, Oid indexId, AttrNumber oidcolumn, char *srvname); +extern Oid GetNewOidForStorageServer(Relation relation, Oid indexId, AttrNumber oidcolumn, + char *srvname); extern Oid GetNewOidForLanguage(Relation relation, Oid indexId, AttrNumber oidcolumn, char *lanname); extern Oid GetNewOidForNamespace(Relation relation, Oid indexId, AttrNumber oidcolumn, @@ -107,6 +109,8 @@ extern Oid GetNewOidForResGroup(Relation relation, Oid indexId, AttrNumber oidco char *rsgname); extern Oid GetNewOidForUserMapping(Relation relation, Oid indexId, AttrNumber oidcolumn, Oid umuser, Oid umserver); +extern Oid GetNewOidForStorageUserMapping(Relation relation, Oid indexId, AttrNumber oidcolumn, + Oid umuser, Oid umserver); extern Oid GetNewOidForPublication(Relation relation, Oid indexId, AttrNumber oidcolumn, char *pubname); extern Oid GetNewOidForPublicationRel(Relation relation, Oid indexId, AttrNumber oidcolumn, diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h index 813d47fee83..ec525930d57 100644 --- a/src/include/catalog/pg_class.h +++ b/src/include/catalog/pg_class.h @@ -185,6 +185,7 @@ DECLARE_INDEX(pg_class_tblspc_relfilenode_index, 3455, on pg_class using btree(r #define RELKIND_AOSEGMENTS 'o' /* AO segment files and eof's */ #define RELKIND_AOBLOCKDIR 'b' /* AO block directory */ #define RELKIND_AOVISIMAP 'M' /* AO visibility map */ +#define RELKIND_DIRECTORY_TABLE 'd' /* directory table */ #define RELPERSISTENCE_PERMANENT 'p' /* regular table */ #define RELPERSISTENCE_UNLOGGED 'u' /* unlogged permanent table */ @@ -210,6 +211,7 @@ DECLARE_INDEX(pg_class_tblspc_relfilenode_index, 3455, on pg_class using btree(r */ #define RELKIND_HAS_STORAGE(relkind) \ ((relkind) == RELKIND_RELATION || \ + (relkind) == RELKIND_DIRECTORY_TABLE || \ (relkind) == RELKIND_INDEX || \ (relkind) == RELKIND_SEQUENCE || \ (relkind) == RELKIND_TOASTVALUE || \ diff --git a/src/include/catalog/pg_directory_table.h b/src/include/catalog/pg_directory_table.h new file mode 100644 index 00000000000..fb8c33d1711 --- /dev/null +++ b/src/include/catalog/pg_directory_table.h @@ -0,0 +1,72 @@ +/*------------------------------------------------------------------------- + * + * pg_directory_table.h + * definition of the "directory table" system catalog (pg_directory_table) + * + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_directory_table.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_DIRECTORY_TABLE_H +#define PG_DIRECTORY_TABLE_H + +#include "access/table.h" +#include "catalog/genbki.h" +#include "catalog/pg_directory_table_d.h" +#include "nodes/parsenodes.h" +#include "storage/ufile.h" + +/* ---------------- + * pg_directory_table definition. cpp turns this into + * typedef struct FormData_pg_directory_table + * ---------------- + */ +CATALOG(pg_directory_table,8545,DirectoryTableRelationId) +{ + /* OID of directory table */ + Oid dtrelid BKI_LOOKUP(pg_class); + + /* identifier of table space for relation (0 means default for database) */ + Oid dttablespace BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_tablespace); +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + text dtlocation; /* directory table location */ +#endif +} FormData_pg_directory_table; + +/* ---------------- + * Form_pg_directory_table corresponds to a pointer to a tuple with + * the format of pg_directory_table relation. + * ---------------- + */ +typedef FormData_pg_directory_table *Form_pg_directory_table; + +DECLARE_TOAST(pg_directory_table, 8546, 8547); + +DECLARE_UNIQUE_INDEX_PKEY(pg_directory_table_relid_index, 8548, on pg_directory_table using btree(dtrelid oid_ops)); +#define DirectoryTableRelidIndexId 8548 + +typedef struct DirectoryTable +{ + Oid relId; /* relation Oid */ + Oid spcId; /* tablespace Oid */ + char *location; /* location */ +} DirectoryTable; + +#define DIRECTORY_TABLE_TAG_COLUMN_ATTNUM 5 + +extern DirectoryTable *GetDirectoryTable(Oid relId); +extern bool RelationIsDirectoryTable(Oid relId); +extern List *GetDirectoryTableSchema(void); +extern DistributedBy *GetDirectoryTableDistributedBy(void); +extern Oid CreateDirectoryTableIndex(Relation rel); +extern void RemoveDirectoryTableEntry(Oid relId); +extern FileAm *GetTablespaceFileHandler(Oid spcId); + +#endif /* PG_DIRECTORY_TABLE_H */ diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index d0f32a6f433..67c37b223fd 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -7375,6 +7375,12 @@ { oid => '3117', descr => 'I/O', proname => 'fdw_handler_out', prorettype => 'cstring', proargtypes => 'fdw_handler', prosrc => 'fdw_handler_out' }, +{ oid => '6451', descr => 'I/O', + proname => 'tblspc_handler_in', proisstrict => 'f', prorettype => 'tblspc_handler', + proargtypes => 'cstring', prosrc => 'tblspc_handler_in' }, +{ oid => '6452', descr => 'I/O', + proname => 'tblspc_handler_out', prorettype => 'cstring', + proargtypes => 'tblspc_handler', prosrc => 'tblspc_handler_out'}, { oid => '326', descr => 'I/O', proname => 'index_am_handler_in', proisstrict => 'f', prorettype => 'index_am_handler', proargtypes => 'cstring', @@ -11968,6 +11974,14 @@ { oid => 7050, descr => 'bitmap(internal)', proname => 'bmhandler', provolatile => 'v', prorettype => 'index_am_handler', proargtypes => 'internal', prosrc => 'bmhandler' }, +{ oid => 8644, descr => 'table function for directory table', + proname => 'directory_table', prorows => '1000', proretset => 't', provolatile => 'v', proparallel => 'u', prorettype => 'record', proargtypes => 'regclass', proallargtypes => '{regclass,text,text,text,int8,timestamptz,text,bytea}', proargmodes => '{i,o,o,o,o,o,o,o}', proargnames => '{relid,scoped_file_url,relative_path,tag,size,last_modified,md5,content}', prosrc => 'directory_table', proexeclocation => 's' }, + +{ oid => 8996, descr => 'delete a file in a directory table', + proname => 'remove_file', provolatile => 'v', prorettype => 'bool', proargtypes => 'regclass cstring', prosrc => 'remove_file' }, + +{ oid => 9109, descr => 'delete a file in a directory table on segment', + proname => 'remove_file_segment', provolatile => 'v', prorettype => 'bool', proargtypes => 'regclass cstring', prosrc => 'remove_file_segment', proexeclocation => 's' }, # AOCS functions. { oid => 9900, descr => 'decode internal AOCSVPInfo struct', diff --git a/src/include/catalog/pg_tablespace.h b/src/include/catalog/pg_tablespace.h index 6791bf536fd..81545837c57 100644 --- a/src/include/catalog/pg_tablespace.h +++ b/src/include/catalog/pg_tablespace.h @@ -37,6 +37,8 @@ CATALOG(pg_tablespace,1213,TableSpaceRelationId) BKI_SHARED_RELATION #ifdef CATALOG_VARLEN /* variable-length fields start here */ aclitem spcacl[1]; /* access permissions */ text spcoptions[1]; /* per-tablespace options */ + text spcfilehandlersrc BKI_DEFAULT(_null_); /* handler function src path */ + text spcfilehandlerbin BKI_DEFAULT(_null_); /* handler function bin path */ #endif } FormData_pg_tablespace; diff --git a/src/include/catalog/pg_type.dat b/src/include/catalog/pg_type.dat index c762c59e16a..ba1afca03e3 100644 --- a/src/include/catalog/pg_type.dat +++ b/src/include/catalog/pg_type.dat @@ -620,6 +620,13 @@ typcategory => 'P', typinput => 'fdw_handler_in', typoutput => 'fdw_handler_out', typreceive => '-', typsend => '-', typalign => 'i' }, +{ + oid => '5102', + descr => 'pseudo-type for the result of a table space handler function', + typname => 'tblspc_handler', typlen => '4', typbyval => 't', typtype => 'p', + typcategory => 'P', typinput => 'tblspc_handler_in', + typoutput => 'tblspc_handler_out', typreceive => '-', typsend => '-', + typalign => 'i' }, { oid => '325', descr => 'pseudo-type for the result of an index AM handler function', typname => 'index_am_handler', typlen => '4', typbyval => 't', typtype => 'p', diff --git a/src/include/catalog/storage_directory_table.h b/src/include/catalog/storage_directory_table.h new file mode 100644 index 00000000000..a73cd8de75d --- /dev/null +++ b/src/include/catalog/storage_directory_table.h @@ -0,0 +1,25 @@ +/*------------------------------------------------------------------------- + * + * Storage manipulation for directory table. + * + * Copyright (c) 2016-Present Hashdata, Inc. + * + * src/include/catalog/storage_directory_table.h + * + *------------------------------------------------------------------------- + */ + +#ifndef STORAGE_DIRECTORY_TABLE_H +#define STORAGE_DIRECTORY_TABLE_H + +#include "utils/relcache.h" + +extern void UFileAddCreatePendingEntry(Relation rel, Oid spcId, char *relativePath); +extern void UFileAddDeletePendingEntry(Relation rel, Oid spcId, char *relativePath); + +extern void UFileDoDeletesActions(bool isCommit); +extern void UFileAtSubCommitSmgr(void); +extern void UFileAtSubAbortSmgr(void); +extern void DirectoryTableDropStorage(Relation rel); + +#endif //STORAGE_DIRECTORY_TABLE_H diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h index d2b51c6ce70..fb278d1329a 100644 --- a/src/include/commands/copy.h +++ b/src/include/commands/copy.h @@ -119,6 +119,7 @@ typedef struct CopyFormatOptions bool delim_off; /* delimiter is set to OFF? */ EolType eol_type; /* EOL type of input */ char *eol_str; /* optional NEWLINE from command. before eol_type is defined */ + char *tags; /* directory table */ SingleRowErrorDesc *sreh; /* end Cloudberry Database specific variables */ } CopyFormatOptions; @@ -143,6 +144,7 @@ extern void DoCopy(ParseState *state, const CopyStmt *stmt, uint64 *processed); extern void ProcessCopyOptions(ParseState *pstate, CopyFormatOptions *ops_out, bool is_from, List *options, Oid rel_oid); +extern void ProcessCopyDirectoryTableOptions(ParseState *pstate, CopyFormatOptions *ops_out, bool is_from, List *options, Oid rel_oid); extern CopyFromState BeginCopyFrom(ParseState *pstate, Relation rel, Node *whereClause, const char *filename, bool is_program, copy_data_source_cb data_source_cb, diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h index 949f8fa0375..f632b4291d1 100644 --- a/src/include/commands/defrem.h +++ b/src/include/commands/defrem.h @@ -131,9 +131,15 @@ extern ObjectAddress CreateForeignDataWrapper(CreateFdwStmt *stmt); extern ObjectAddress AlterForeignDataWrapper(AlterFdwStmt *stmt); extern ObjectAddress CreateForeignServer(CreateForeignServerStmt *stmt); extern ObjectAddress AlterForeignServer(AlterForeignServerStmt *stmt); +extern ObjectAddress CreateStorageServer(CreateStorageServerStmt *stmt); +extern ObjectAddress AlterStorageServer(AlterStorageServerStmt *stmt); +extern Oid RemoveStorageServer(DropStorageServerStmt *stmt); extern ObjectAddress CreateUserMapping(CreateUserMappingStmt *stmt); extern ObjectAddress AlterUserMapping(AlterUserMappingStmt *stmt); extern Oid RemoveUserMapping(DropUserMappingStmt *stmt); +extern ObjectAddress CreateStorageUserMapping(CreateStorageUserMappingStmt *stmt); +extern ObjectAddress AlterStorageUserMapping(AlterStorageUserMappingStmt *stmt); +extern Oid RemoveStorageUserMapping(DropStorageUserMappingStmt *stmt); extern void CreateForeignTable(CreateForeignTableStmt *stmt, Oid relid, bool skip_permission_check); extern void ImportForeignSchema(ImportForeignSchemaStmt *stmt); extern Datum transformGenericOptions(Oid catalogId, diff --git a/src/include/commands/dirtablecmds.h b/src/include/commands/dirtablecmds.h new file mode 100644 index 00000000000..b26043db867 --- /dev/null +++ b/src/include/commands/dirtablecmds.h @@ -0,0 +1,24 @@ +/*------------------------------------------------------------------------- + * + * dirtablecmds.h + * prototypes for dirtablecmds.c. + * + * + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/commands/dirtablecmds.h + * + *------------------------------------------------------------------------- + */ + +#ifndef DIRTABLECMDS_H +#define DIRTABLECMDS_H + +#include "catalog/objectaddress.h" +#include "nodes/params.h" +#include "parser/parse_node.h" + +void CreateDirectoryTable(CreateDirectoryTableStmt *stmt, Oid relId); + +#endif //DIRTABLECMDS_H diff --git a/src/include/commands/storagecmds.h b/src/include/commands/storagecmds.h new file mode 100644 index 00000000000..6bfd93d3327 --- /dev/null +++ b/src/include/commands/storagecmds.h @@ -0,0 +1,52 @@ +/*------------------------------------------------------------------------- + * + * storagecmds.h + * storage server/user_mapping creation/manipulation commands + * + * Copyright (c) 2016-Present Hashdata, Inc. + * + * + * IDENTIFICATION + * src/include/commands/storagecmds.h + * + *------------------------------------------------------------------------- + */ + +#ifndef STORAGECMDS_H +#define STORAGECMDS_H + +#include "catalog/objectaddress.h" +#include "nodes/parsenodes.h" + + +/* Flags for GetStorageServerExtended */ +#define SSV_MISSING_OK 0x01 + +/* Helper for obtaining username for user mapping */ +#define StorageMappingUserName(userid) \ + (OidIsValid(userid) ? GetUserNameFromId(userid, false) : "public") + +typedef struct StorageServer +{ + Oid serverid; /* storage server Oid */ + Oid owner; /* storage server owner user Oid */ + char *servername; /* name of the storage server */ + List *options; /* srvoptions as DefElem list */ +} StorageServer; + +typedef struct StorageUserMapping +{ + Oid umid; /* Oid of storage user mapping */ + Oid userid; /* local user Oid */ + Oid serverid; /* storage server Oid */ + List *options; /* useoptions as DefElem list */ +} StorageUserMapping; + +extern Oid get_storage_server_oid(const char *servername, bool missing_ok); +extern StorageServer *GetStorageServerExtended(Oid serverid, bits16 flags); +extern StorageServer *GetStorageServer(Oid serverid); +extern StorageServer *GetStorageServerByName(const char *srvname, bool missing_ok); +extern StorageUserMapping *GetStorageUserMapping(Oid userid, Oid serverid); +extern Datum transformStorageGenericOptions(Oid catalogId, Datum oldOptions, List *options); + +#endif //STORAGECMDS_H diff --git a/src/include/commands/tablespace.h b/src/include/commands/tablespace.h index 830c1f1c0c6..1f41964cf75 100644 --- a/src/include/commands/tablespace.h +++ b/src/include/commands/tablespace.h @@ -43,6 +43,9 @@ typedef struct TableSpaceOpts float8 seq_page_cost; int effective_io_concurrency; int maintenance_io_concurrency; + bool stage; + int serverOffset; + int pathOffset; } TableSpaceOpts; extern Oid CreateTableSpace(CreateTableSpaceStmt *stmt); diff --git a/src/include/common/md5.h b/src/include/common/md5.h index 62a31e6ed4e..9ef0b123c6d 100644 --- a/src/include/common/md5.h +++ b/src/include/common/md5.h @@ -30,5 +30,6 @@ extern bool pg_md5_hash(const void *buff, size_t len, char *hexsum); extern bool pg_md5_binary(const void *buff, size_t len, void *outbuf); extern bool pg_md5_encrypt(const char *passwd, const char *salt, size_t salt_len, char *buf); +extern void bytesToHex(uint8 b[16], char *s); #endif /* PG_MD5_H */ diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index 5181b66746d..331c4e7444f 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -217,7 +217,7 @@ extern void ExecutorEnd(QueryDesc *queryDesc); extern void standard_ExecutorEnd(QueryDesc *queryDesc); extern void ExecutorRewind(QueryDesc *queryDesc); extern bool ExecCheckRTPerms(List *rangeTable, bool ereport_on_violation); -extern void CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation); +extern void CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation, ModifyTableState *mtstate); extern void InitResultRelInfo(ResultRelInfo *resultRelInfo, Relation resultRelationDesc, Index resultRelationIndex, diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index 371beaf89b7..8496472faa8 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -490,9 +490,15 @@ typedef enum NodeTag T_AlterFdwStmt, T_CreateForeignServerStmt, T_AlterForeignServerStmt, + T_CreateStorageServerStmt, + T_AlterStorageServerStmt, + T_DropStorageServerStmt, T_CreateUserMappingStmt, T_AlterUserMappingStmt, T_DropUserMappingStmt, + T_CreateStorageUserMappingStmt, + T_AlterStorageUserMappingStmt, + T_DropStorageUserMappingStmt, T_AlterTableSpaceOptionsStmt, T_AlterTableMoveAllStmt, T_SecLabelStmt, @@ -527,6 +533,7 @@ typedef enum NodeTag T_PartitionBy, T_PartitionRangeItem, T_PartitionValuesSpec, + T_CreateDirectoryTableStmt, T_CreateFileSpaceStmt, T_FileSpaceEntry, T_DropFileSpaceStmt, diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index d9a278ede94..7ee9e7661ea 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -1921,6 +1921,7 @@ typedef enum ObjectType OBJECT_EXTENSION, OBJECT_FDW, OBJECT_FOREIGN_SERVER, + OBJECT_STORAGE_SERVER, OBJECT_FOREIGN_TABLE, OBJECT_FUNCTION, OBJECT_INDEX, @@ -1954,9 +1955,11 @@ typedef enum ObjectType OBJECT_TSTEMPLATE, OBJECT_TYPE, OBJECT_USER_MAPPING, + OBJECT_STORAGE_USER_MAPPING, OBJECT_VIEW, OBJECT_RESQUEUE, - OBJECT_RESGROUP + OBJECT_RESGROUP, + OBJECT_DIRECTORY_TABLE } ObjectType; /* Event triggers and extended statistics are only stored on the QD node.*/ @@ -2384,6 +2387,8 @@ typedef struct CopyStmt bool is_from; /* TO or FROM */ bool is_program; /* is 'filename' a program to popen? */ char *filename; /* filename, or NULL for STDIN/STDOUT */ + char *dirfilename; /* dirtable filename */ + List *options; /* List of DefElem nodes */ Node *whereClause; /* WHERE condition (or NULL) */ @@ -2711,6 +2716,7 @@ typedef struct CreateTableSpaceStmt RoleSpec *owner; char *location; List *options; + char *filehandler; } CreateTableSpaceStmt; typedef struct DropTableSpaceStmt @@ -2860,6 +2866,32 @@ typedef struct AlterForeignServerStmt bool has_version; /* version specified */ } AlterForeignServerStmt; +/* ---------------------- + * Create/Alter/Drop STORAGE SERVER Statements + * ---------------------- + */ +typedef struct CreateStorageServerStmt +{ + NodeTag type; + char *servername; /* server name */ + bool if_not_exists; /* just do nothing if it already exists? */ + List *options; /* generic options to server */ +} CreateStorageServerStmt; + +typedef struct AlterStorageServerStmt +{ + NodeTag type; + char *servername; /* server name */ + List *options; /* generic options to server */ +} AlterStorageServerStmt; + +typedef struct DropStorageServerStmt +{ + NodeTag type; + char *servername; /* server name */ + bool missing_ok; /* ignore missing storage server */ +} DropStorageServerStmt; + /* ---------------------- * Create FOREIGN TABLE Statement * ---------------------- @@ -2903,6 +2935,36 @@ typedef struct DropUserMappingStmt bool missing_ok; /* ignore missing mappings */ } DropUserMappingStmt; +/* ---------------------- + * Create/Drop STORAGE USER MAPPING Statements + * ---------------------- + */ + +typedef struct CreateStorageUserMappingStmt +{ + NodeTag type; + RoleSpec *user; /* user role */ + char *servername; /* server name */ + bool if_not_exists; /* just do nothing if it already exists? */ + List *options; /* generic options to server */ +} CreateStorageUserMappingStmt; + +typedef struct AlterStorageUserMappingStmt +{ + NodeTag type; + RoleSpec *user; /* user role */ + char *servername; /* server name */ + List *options; /* generic options to server */ +} AlterStorageUserMappingStmt; + +typedef struct DropStorageUserMappingStmt +{ + NodeTag type; + RoleSpec *user; /* user role */ + char *servername; /* server name */ + bool missing_ok; /* ignore missing mappings */ +} DropStorageUserMappingStmt; + /* ---------------------- * Import Foreign Schema Statement * ---------------------- @@ -3279,6 +3341,17 @@ typedef struct AlterOpFamilyStmt List *items; /* List of CreateOpClassItem nodes */ } AlterOpFamilyStmt; +/* ---------------------- + * Create/Alter Directory Table Statements + * ---------------------- + */ +typedef struct CreateDirectoryTableStmt +{ + CreateStmt base; + char *tablespacename; +} CreateDirectoryTableStmt; + + /* ---------------------- * DROP Statement, applies to: * Table, External Table, Sequence, View, Index, Type, Domain, diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h index d8aca8f4a43..f29ac9b900c 100644 --- a/src/include/parser/kwlist.h +++ b/src/include/parser/kwlist.h @@ -146,6 +146,7 @@ PG_KEYWORD("depth", DEPTH, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("desc", DESC, RESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("detach", DETACH, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("dictionary", DICTIONARY, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("directory", DIRECTORY, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("disable", DISABLE_P, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("discard", DISCARD, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("distinct", DISTINCT, RESERVED_KEYWORD, BARE_LABEL) @@ -476,6 +477,7 @@ PG_KEYWORD("table", TABLE, RESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("tables", TABLES, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("tablesample", TABLESAMPLE, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) PG_KEYWORD("tablespace", TABLESPACE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("tag", TAG, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("task", TASK, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("temp", TEMP, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("template", TEMPLATE, UNRESERVED_KEYWORD, BARE_LABEL) diff --git a/src/include/storage/ufile.h b/src/include/storage/ufile.h new file mode 100644 index 00000000000..8a76957eaf5 --- /dev/null +++ b/src/include/storage/ufile.h @@ -0,0 +1,68 @@ +/*------------------------------------------------------------------------- + * + * Unified file abstraction and manipulation. + * + * Copyright (c) 2016-Present Hashdata, Inc. + * + * src/include/storage/ufile.h + * + *------------------------------------------------------------------------- + */ + +#ifndef UFILE_H +#define UFILE_H + +#include "storage/relfilenode.h" + +#define UFILE_ERROR_SIZE 1024 + +struct UFile; + +typedef struct FileAm +{ + struct UFile* (*open) (Oid spcId, const char *fileName, int fileFlags, + char *errorMessage, int errorMessageSize); + void (*close) (struct UFile *file); + int (*sync) (struct UFile *file); + int (*read) (struct UFile *file, char *buffer, int amount); + int (*write) (struct UFile *file, char *buffer, int amount); + int64_t (*size) (struct UFile *file); + void (*unlink) (Oid spcId, const char *fileName); + char* (*formatPathName) (RelFileNode *relFileNode); + bool (*ensurePath) (Oid spcId, const char *pathName); + bool (*exists) (Oid spcId, const char *fileName); + const char *(*name) (struct UFile *file); + const char *(*getLastError) (void); + void (*getConnection) (Oid spcId); +} FileAm; + +typedef struct UFile +{ + FileAm *methods; +} UFile; + +extern UFile *UFileOpen(Oid spcId, + const char *fileName, + int fileFlags, + char *errorMessage, + int errorMessageSize); +extern void UFileClose(UFile *file); +extern int UFileSync(UFile *fiLe); + +extern int UFileRead(UFile *file, char *buffer, int amount); +extern int UFileWrite(UFile *file, char *buffer, int amount); + +extern off_t UFileSize(UFile *file); +extern const char *UFileName(UFile *file); + +extern void UFileUnlink(Oid spcId, const char *fileName); +extern char* UFileFormatPathName(RelFileNode *relFileNode); +extern bool UFileEnsurePath(Oid spcId, const char *pathName); +extern bool UFileExists(Oid spcId, const char *fileName); + +extern const char *UFileGetLastError(UFile *file); +extern void forceCacheUFileResource(Oid id); + +extern struct FileAm localFileAm; + +#endif //UFILE_H diff --git a/src/include/tcop/cmdtaglist.h b/src/include/tcop/cmdtaglist.h index 74285522d99..c97011262df 100644 --- a/src/include/tcop/cmdtaglist.h +++ b/src/include/tcop/cmdtaglist.h @@ -34,6 +34,7 @@ PG_CMDTAG(CMDTAG_ALTER_CONSTRAINT, "ALTER CONSTRAINT", true, false, false) PG_CMDTAG(CMDTAG_ALTER_CONVERSION, "ALTER CONVERSION", true, false, false) PG_CMDTAG(CMDTAG_ALTER_DATABASE, "ALTER DATABASE", false, false, false) PG_CMDTAG(CMDTAG_ALTER_DEFAULT_PRIVILEGES, "ALTER DEFAULT PRIVILEGES", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_DIRECTORY_TABLE, "ALTER DIRECTORY TABLE", true, false, false) PG_CMDTAG(CMDTAG_ALTER_DOMAIN, "ALTER DOMAIN", true, false, false) PG_CMDTAG(CMDTAG_ALTER_EVENT_TRIGGER, "ALTER EVENT TRIGGER", false, false, false) PG_CMDTAG(CMDTAG_ALTER_EXTENSION, "ALTER EXTENSION", true, false, false) @@ -61,6 +62,8 @@ PG_CMDTAG(CMDTAG_ALTER_SCHEMA, "ALTER SCHEMA", true, false, false) PG_CMDTAG(CMDTAG_ALTER_SEQUENCE, "ALTER SEQUENCE", true, false, false) PG_CMDTAG(CMDTAG_ALTER_SERVER, "ALTER SERVER", true, false, false) PG_CMDTAG(CMDTAG_ALTER_STATISTICS, "ALTER STATISTICS", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_STORAGE_SERVER, "ALTER STORAGE SERVER", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_STORAGE_USER_MAPPING, "ALTER STORAGE USER MAPPING", true, false, false) PG_CMDTAG(CMDTAG_ALTER_SUBSCRIPTION, "ALTER SUBSCRIPTION", true, false, false) PG_CMDTAG(CMDTAG_ALTER_SYSTEM, "ALTER SYSTEM", false, false, false) PG_CMDTAG(CMDTAG_ALTER_TABLE, "ALTER TABLE", true, true, false) @@ -96,6 +99,7 @@ PG_CMDTAG(CMDTAG_CREATE_COLLATION, "CREATE COLLATION", true, false, false) PG_CMDTAG(CMDTAG_CREATE_CONSTRAINT, "CREATE CONSTRAINT", true, false, false) PG_CMDTAG(CMDTAG_CREATE_CONVERSION, "CREATE CONVERSION", true, false, false) PG_CMDTAG(CMDTAG_CREATE_DATABASE, "CREATE DATABASE", false, false, false) +PG_CMDTAG(CMDTAG_CREATE_DIRECTORY_TABLE, "CREATE DIRECTORY TABLE", true, false, false) PG_CMDTAG(CMDTAG_CREATE_DOMAIN, "CREATE DOMAIN", true, false, false) PG_CMDTAG(CMDTAG_CREATE_EVENT_TRIGGER, "CREATE EVENT TRIGGER", false, false, false) PG_CMDTAG(CMDTAG_CREATE_EXTENSION, "CREATE EXTENSION", true, false, false) @@ -123,6 +127,8 @@ PG_CMDTAG(CMDTAG_CREATE_SCHEMA, "CREATE SCHEMA", true, false, false) PG_CMDTAG(CMDTAG_CREATE_SEQUENCE, "CREATE SEQUENCE", true, false, false) PG_CMDTAG(CMDTAG_CREATE_SERVER, "CREATE SERVER", true, false, false) PG_CMDTAG(CMDTAG_CREATE_STATISTICS, "CREATE STATISTICS", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_STORAGE_SERVER, "CREATE STORAGE SERVER", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_STORAGE_USER_MAPPING, "CREATE STORAGE USER MAPPING", true, false, false) PG_CMDTAG(CMDTAG_CREATE_SUBSCRIPTION, "CREATE SUBSCRIPTION", true, false, false) PG_CMDTAG(CMDTAG_CREATE_TABLE, "CREATE TABLE", true, false, false) PG_CMDTAG(CMDTAG_CREATE_TABLE_AS, "CREATE TABLE AS", true, false, false) @@ -162,6 +168,7 @@ PG_CMDTAG(CMDTAG_DROP_COLLATION, "DROP COLLATION", true, false, false) PG_CMDTAG(CMDTAG_DROP_CONSTRAINT, "DROP CONSTRAINT", true, false, false) PG_CMDTAG(CMDTAG_DROP_CONVERSION, "DROP CONVERSION", true, false, false) PG_CMDTAG(CMDTAG_DROP_DATABASE, "DROP DATABASE", false, false, false) +PG_CMDTAG(CMDTAG_DROP_DIRECTORY_TABLE, "DROP DIRECTORY TABLE", true, false, false) PG_CMDTAG(CMDTAG_DROP_DOMAIN, "DROP DOMAIN", true, false, false) PG_CMDTAG(CMDTAG_DROP_EVENT_TRIGGER, "DROP EVENT TRIGGER", false, false, false) PG_CMDTAG(CMDTAG_DROP_EXTENSION, "DROP EXTENSION", true, false, false) @@ -192,6 +199,8 @@ PG_CMDTAG(CMDTAG_DROP_SCHEMA, "DROP SCHEMA", true, false, false) PG_CMDTAG(CMDTAG_DROP_SEQUENCE, "DROP SEQUENCE", true, false, false) PG_CMDTAG(CMDTAG_DROP_SERVER, "DROP SERVER", true, false, false) PG_CMDTAG(CMDTAG_DROP_STATISTICS, "DROP STATISTICS", true, false, false) +PG_CMDTAG(CMDTAG_DROP_STORAGE_SERVER, "DROP STORAGE SERVER", true, false, false) +PG_CMDTAG(CMDTAG_DROP_STORAGE_USER_MAPPING, "DROP STORAGE USER MAPPING", true, false, false) PG_CMDTAG(CMDTAG_DROP_SUBSCRIPTION, "DROP SUBSCRIPTION", true, false, false) PG_CMDTAG(CMDTAG_DROP_TABLE, "DROP TABLE", true, false, false) PG_CMDTAG(CMDTAG_DROP_TABLESPACE, "DROP TABLESPACE", false, false, false) diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h index 6c42441aab8..bf47cd0a592 100644 --- a/src/include/utils/acl.h +++ b/src/include/utils/acl.h @@ -160,6 +160,7 @@ typedef struct ArrayType Acl; #define ACL_ALL_RIGHTS_EXTPROTOCOL (ACL_INSERT|ACL_SELECT) #define ACL_ALL_RIGHTS_FDW (ACL_USAGE) #define ACL_ALL_RIGHTS_FOREIGN_SERVER (ACL_USAGE) +#define ACL_ALL_RIGHTS_STORAGE_SERVER (ACL_USAGE) #define ACL_ALL_RIGHTS_FUNCTION (ACL_EXECUTE) #define ACL_ALL_RIGHTS_LANGUAGE (ACL_USAGE) #define ACL_ALL_RIGHTS_LARGEOBJECT (ACL_SELECT|ACL_UPDATE) @@ -260,6 +261,8 @@ extern AclMode pg_foreign_data_wrapper_aclmask(Oid fdw_oid, Oid roleid, AclMode mask, AclMaskHow how); extern AclMode pg_foreign_server_aclmask(Oid srv_oid, Oid roleid, AclMode mask, AclMaskHow how); +extern AclMode gp_storage_server_aclmask(Oid srv_oid, Oid roleid, + AclMode mask, AclMaskHow how); extern AclMode pg_extprotocol_aclmask(Oid ptc_oid, Oid roleid, AclMode mask, AclMaskHow how); extern AclMode pg_type_aclmask(Oid type_oid, Oid roleid, @@ -284,6 +287,7 @@ extern AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode); extern AclResult pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode); extern AclResult pg_foreign_data_wrapper_aclcheck(Oid fdw_oid, Oid roleid, AclMode mode); extern AclResult pg_foreign_server_aclcheck(Oid srv_oid, Oid roleid, AclMode mode); +extern AclResult gp_storage_server_aclcheck(Oid srv_oid, Oid roleid, AclMode mode); extern AclResult pg_extprotocol_aclcheck(Oid ptc_oid, Oid roleid, AclMode mode); extern AclResult pg_type_aclcheck(Oid type_oid, Oid roleid, AclMode mode); @@ -318,6 +322,7 @@ extern bool pg_ts_dict_ownercheck(Oid dict_oid, Oid roleid); extern bool pg_ts_config_ownercheck(Oid cfg_oid, Oid roleid); extern bool pg_foreign_data_wrapper_ownercheck(Oid srv_oid, Oid roleid); extern bool pg_foreign_server_ownercheck(Oid srv_oid, Oid roleid); +extern bool gp_storage_server_ownercheck(Oid srv_oid, Oid roleid); extern bool pg_event_trigger_ownercheck(Oid et_oid, Oid roleid); extern bool pg_extension_ownercheck(Oid ext_oid, Oid roleid); extern bool pg_publication_ownercheck(Oid pub_oid, Oid roleid); diff --git a/src/include/utils/spccache.h b/src/include/utils/spccache.h index 26ac680ff7a..47d733d742d 100644 --- a/src/include/utils/spccache.h +++ b/src/include/utils/spccache.h @@ -13,9 +13,19 @@ #ifndef SPCCACHE_H #define SPCCACHE_H +#include "commands/tablespace.h" + +typedef struct +{ + Oid oid; /* lookup key - must be first */ + TableSpaceOpts *opts; /* options, or NULL if none */ +} TableSpaceCacheEntry; + void get_tablespace_page_costs(Oid spcid, float8 *spc_random_page_cost, float8 *spc_seq_page_cost); int get_tablespace_io_concurrency(Oid spcid); int get_tablespace_maintenance_io_concurrency(Oid spcid); +extern TableSpaceCacheEntry *get_tablespace(Oid spcid); + #endif /* SPCCACHE_H */ diff --git a/src/include/utils/syscache.h b/src/include/utils/syscache.h index 67415775582..62f6b2a46e2 100644 --- a/src/include/utils/syscache.h +++ b/src/include/utils/syscache.h @@ -65,6 +65,8 @@ enum SysCacheIdentifier FOREIGNDATAWRAPPEROID, FOREIGNSERVERNAME, FOREIGNSERVEROID, + STORAGESERVERNAME, + STORAGESERVEROID, FOREIGNTABLEREL, GPPOLICYID, AORELID, @@ -117,6 +119,9 @@ enum SysCacheIdentifier TSTEMPLATEOID, TYPENAMENSP, TYPEOID, + DIRECTORYTABLEREL, + STORAGEUSERMAPPINGOID, + STORAGEUSERMAPPINGUSERSERVER, USERMAPPINGOID, USERMAPPINGUSERSERVER diff --git a/src/interfaces/ecpg/preproc/ecpg.addons b/src/interfaces/ecpg/preproc/ecpg.addons index a87886a2640..03fbe642b6f 100644 --- a/src/interfaces/ecpg/preproc/ecpg.addons +++ b/src/interfaces/ecpg/preproc/ecpg.addons @@ -247,7 +247,7 @@ ECPG: where_or_current_clauseWHERECURRENT_POFcursor_name block char *cursor_marker = $4[0] == ':' ? mm_strdup("$0") : $4; $$ = cat_str(2,mm_strdup("where current of"), cursor_marker); } -ECPG: CopyStmtCOPYopt_binaryqualified_nameopt_column_listcopy_fromopt_programcopy_file_namecopy_delimiteropt_withcopy_optionswhere_clauseOptSingleRowErrorHandling addon +ECPG: CopyStmtCOPYopt_binaryqualified_nameopt_column_listcopy_fromopt_programcopy_file_nameopt_file_namecopy_delimiteropt_withcopy_optionswhere_clauseOptSingleRowErrorHandling addon if (strcmp($6, "from") == 0 && (strcmp($7, "stdin") == 0 || strcmp($7, "stdout") == 0)) mmerror(PARSE_ERROR, ET_WARNING, "COPY FROM STDIN is not implemented"); diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c index a65c15ee688..76ea85d8be6 100644 --- a/src/pl/plpgsql/src/pl_comp.c +++ b/src/pl/plpgsql/src/pl_comp.c @@ -1772,7 +1772,8 @@ plpgsql_parse_cwordtype(List *idents) classStruct->relkind != RELKIND_MATVIEW && classStruct->relkind != RELKIND_COMPOSITE_TYPE && classStruct->relkind != RELKIND_FOREIGN_TABLE && - classStruct->relkind != RELKIND_PARTITIONED_TABLE) + classStruct->relkind != RELKIND_PARTITIONED_TABLE && + classStruct->relkind != RELKIND_DIRECTORY_TABLE) goto done; /* diff --git a/src/test/isolation2/input/local_directory_table_mixed.source b/src/test/isolation2/input/local_directory_table_mixed.source new file mode 100644 index 00000000000..90bbc62f03c --- /dev/null +++ b/src/test/isolation2/input/local_directory_table_mixed.source @@ -0,0 +1,131 @@ +-- Mixed test for local directory table +-- setup for temp tablespace +! rm -rf '@testtablespace@'; +! mkdir -p '@testtablespace@'; +CREATE TABLESPACE directory_tblspc LOCATION '@testtablespace@'; + +CREATE EXTENSION IF NOT EXISTS gp_inject_fault; + +-- Test create directory table and create directory table +1: BEGIN; +2: BEGIN; +1: CREATE DIRECTORY TABLE dir_table1 TABLESPACE directory_tblspc; +2: CREATE DIRECTORY TABLE dir_table2 TABLESPACE directory_tblspc; +1: COMMIT; +2: COMMIT; + +1: COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation1'; +2: COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation2'; +3: COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation3'; +4: COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation4'; + +-- Test copy binary from the same directory table in parallel session is allowed +1: BEGIN; +2: BEGIN; +1: COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation5'; +2: COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation6'; +1: COMMIT; +2: COMMIT; + +-- Test copy binary from and select directory table +1: BEGIN; +2: BEGIN; +1: COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation5'; +2: SELECT relative_path, size, tag, md5 FROM dir_table2 ORDER BY 1; +1: COMMIT; +2: COMMIT; + +1: BEGIN; +2: BEGIN; +1: COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation6'; +2: SELECT relative_path, size, tag, md5, content FROM directory_table('dir_table2') ORDER BY 1; +1: COMMIT; +2: COMMIT; + +-- Test copy binary from and remove_file() +1: BEGIN; +2: BEGIN; +1: COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation7'; +2&: SELECT remove_file('dir_table1', 'nation6'); +1: COMMIT; +2<: +2: COMMIT; + +-- Test select and select +1: BEGIN; +2: BEGIN; +1: SELECT relative_path, size, tag, md5 FROM dir_table1 ORDER BY 1; +2: SELECT relative_path, size, tag, md5, content FROM directory_table('dir_table2') ORDER BY 1; +1: SELECT relative_path, size, tag, md5, content FROM directory_table('dir_table2') ORDER BY 1; +2: SELECT relative_path, size, tag, md5 FROM dir_table1 ORDER BY 1; +2: COMMIT; +1: COMMIT; + +-- Test select and remove_file() +1: BEGIN; +2: BEGIN; +1: SELECT gp_inject_fault('directory_table_inject', 'suspend', dbid) FROM gp_segment_configuration WHERE role='p' and content >= 0; +1&: SELECT relative_path, size, tag, md5, content FROM directory_table('dir_table1') ORDER BY 1; +2&: SELECT remove_file('dir_table1', 'nation7'); +3: SELECT gp_wait_until_triggered_fault('directory_table_inject', 1, dbid) FROM gp_segment_configuration WHERE role='p' and content >= 0; +3: SELECT gp_inject_fault('directory_table_inject', 'resume', dbid) FROM gp_segment_configuration WHERE role='p' and content >= 0; +1<: +1: COMMIT; +2<: +2: COMMIT; + +1: SELECT gp_inject_fault('directory_table_inject', 'reset', dbid) FROM gp_segment_configuration WHERE role='p' and content >= 0; + +1: BEGIN; +2: BEGIN; +1: SELECT gp_inject_fault('remove_file_inject', 'suspend', dbid) FROM gp_segment_configuration WHERE role='p' and content >= 0; +1&: SELECT remove_file('dir_table1', 'nation5'); +2&: SELECT relative_path, size, tag, md5 FROM dir_table1 ORDER BY 1; +3: SELECT gp_wait_until_triggered_fault('remove_file_inject', 1, dbid) FROM gp_segment_configuration WHERE role='p' and content >= 0; +3: SELECT gp_inject_fault('remove_file_inject', 'resume', dbid) FROM gp_segment_configuration WHERE role='p' and content >= 0; +1<: +1: COMMIT; +2<: +2: COMMIT; + +1: SELECT gp_inject_fault('remove_file_inject', 'reset', dbid) FROM gp_segment_configuration WHERE role='p' and content >= 0; + +1: BEGIN; +2: BEGIN; +1: SELECT gp_inject_fault('remove_file_inject', 'suspend', dbid) FROM gp_segment_configuration WHERE role='p' and content >= 0; +1&: SELECT remove_file('dir_table2', 'nation6'); +2&: SELECT relative_path, size, tag, md5, content FROM directory_table('dir_table2') ORDER BY 1; +3: SELECT gp_wait_until_triggered_fault('remove_file_inject', 1, dbid) FROM gp_segment_configuration WHERE role='p' and content >= 0; +3: SELECT gp_inject_fault('remove_file_inject', 'resume', dbid) FROM gp_segment_configuration WHERE role='p' and content >= 0; +1<: +1: COMMIT; +2<: +2: COMMIT; + +1: SELECT gp_inject_fault('remove_file_inject', 'reset', dbid) FROM gp_segment_configuration WHERE role='p' and content >= 0; + +1: BEGIN; +2: BEGIN; +1: SELECT gp_inject_fault('directory_table_inject', 'suspend', dbid) FROM gp_segment_configuration WHERE role='p' and content >= 0; +1&: SELECT relative_path, size, tag, md5, content FROM directory_table('dir_table2') ORDER BY 1; +2&: SELECT remove_file('dir_table2', 'nation5'); +3: SELECT gp_wait_until_triggered_fault('directory_table_inject', 1, dbid) FROM gp_segment_configuration WHERE role='p' and content >= 0; +3: SELECT gp_inject_fault('directory_table_inject', 'resume', dbid) FROM gp_segment_configuration WHERE role='p' and content >= 0; +1<: +1: COMMIT; +2<: +2: COMMIT; + +1: SELECT gp_inject_fault('directory_table_inject', 'reset', dbid) FROM gp_segment_configuration WHERE role='p' and content >= 0; + +-- Test create directory table and drop directory table +1: BEGIN; +2: BEGIN; +1: CREATE DIRECTORY TABLE dir_table3 TABLESPACE directory_tblspc; +2: DROP DIRECTORY TABLE dir_table2; +2: CREATE DIRECTORY TABLE dir_table2 TABLESPACE directory_tblspc; +1: COMMIT; +2: COMMIT; + +! rm -rf '@testtablespace@'; +DROP TABLESPACE directory_tblspc; \ No newline at end of file diff --git a/src/test/isolation2/isolation2_schedule b/src/test/isolation2/isolation2_schedule index 3785ea21bea..806c62a4d7f 100644 --- a/src/test/isolation2/isolation2_schedule +++ b/src/test/isolation2/isolation2_schedule @@ -308,3 +308,5 @@ test: ao_unique_index test: aocs_unique_index test: uao/ao_unique_index_vacuum_row test: uao/ao_unique_index_vacuum_column + +test: local_directory_table_mixed \ No newline at end of file diff --git a/src/test/isolation2/output/local_directory_table_mixed.source b/src/test/isolation2/output/local_directory_table_mixed.source new file mode 100644 index 00000000000..f8f2994bfa6 --- /dev/null +++ b/src/test/isolation2/output/local_directory_table_mixed.source @@ -0,0 +1,374 @@ +-- Mixed test for local directory table +-- setup for temp tablespace +! rm -rf '@testtablespace@'; + +! mkdir -p '@testtablespace@'; + +CREATE TABLESPACE directory_tblspc LOCATION '@testtablespace@'; +CREATE + +CREATE EXTENSION IF NOT EXISTS gp_inject_fault; +CREATE + +-- Test create directory table and create directory table +1: BEGIN; +BEGIN +2: BEGIN; +BEGIN +1: CREATE DIRECTORY TABLE dir_table1 TABLESPACE directory_tblspc; +CREATE +2: CREATE DIRECTORY TABLE dir_table2 TABLESPACE directory_tblspc; +CREATE +1: COMMIT; +COMMIT +2: COMMIT; +COMMIT + +1: COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation1'; +COPY 1 +2: COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation2'; +COPY 1 +3: COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation3'; +COPY 1 +4: COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation4'; +COPY 1 + +-- Test copy binary from the same directory table in parallel session is allowed +1: BEGIN; +BEGIN +2: BEGIN; +BEGIN +1: COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation5'; +COPY 1 +2: COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation6'; +COPY 1 +1: COMMIT; +COMMIT +2: COMMIT; +COMMIT + +-- Test copy binary from and select directory table +1: BEGIN; +BEGIN +2: BEGIN; +BEGIN +1: COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation5'; +COPY 1 +2: SELECT relative_path, size, tag, md5 FROM dir_table2 ORDER BY 1; + relative_path | size | tag | md5 +---------------+------+-----+---------------------------------- + nation2 | 2199 | | 01ab9bc150261c9918ce9636be80ea15 + nation4 | 2199 | | 01ab9bc150261c9918ce9636be80ea15 +(2 rows) +1: COMMIT; +COMMIT +2: COMMIT; +COMMIT + +1: BEGIN; +BEGIN +2: BEGIN; +BEGIN +1: COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation6'; +COPY 1 +2: SELECT relative_path, size, tag, md5, content FROM directory_table('dir_table2') ORDER BY 1; + relative_path | size | tag | md5 | content +---------------+------+-----+----------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + nation2 | 2199 | | 01ab9bc150261c9918ce9636be80ea15 | b'0|ALGERIA|0| haggle. carefully final deposits detect slyly agai\n1|ARGENTINA|1|al foxes promise slyly according to the regular accounts. bold requests alon\n2|BRAZIL|1|y alongside of the pending deposits. carefully special packages are about the ironic forges. slyly special \n3|CANADA|1|eas hang ironic, silent packages. slyly regular packages are furiously over the tithes. fluffily bold\n4|EGYPT|4|y above the carefully unusual theodolites. final dugouts are quickly across the furiously regular d\n5|ETHIOPIA|0|ven packages wake quickly. regu\n6|FRANCE|3|refully final requests. regular, ironi\n7|GERMANY|3|l platelets. regular accounts x-ray: unusual, regular acco\n8|INDIA|2|ss excuses cajole slyly across the packages. deposits print aroun\n9|INDONESIA|2| slyly express asymptotes. regular deposits haggle slyly. carefully ironic hockey players sleep blithely. carefull\n10|IRAN|4|efully alongside of the slyly final dependencies. \n11|IRAQ|4|nic deposits boost atop the quickly final requests? quickly regula\n12|JAPAN|2|ously. final, express gifts cajole a\n13|JORDAN|4|ic deposits are blithely about the carefully regular pa\n14|KENYA|0| pending excuses haggle furiously deposits. pending, express pinto beans wake fluffily past t\n15|MOROCCO|0|rns. blithely bold courts among the closely regular packages use furiously bold platelets?\n16|MOZAMBIQUE|0|s. ironic, unusual asymptotes wake blithely r\n17|PERU|1|platelets. blithely pending dependencies use fluffily across the even pinto beans. carefully silent accoun\n18|CHINA|2|c dependencies. furiously express notornis sleep slyly regular accounts. ideas sleep. depos\n19|ROMANIA|3|ular asymptotes are about the furious multipliers. express dependencies nag above the ironically ironic account\n20|SAUDI ARABIA|4|ts. silent requests haggle. closely express packages sleep across the blithely\n21|VIETNAM|2|hely enticingly express accounts. even, final \n22|RUSSIA|3| requests against the platelets use never according to the quickly regular pint\n23|UNITED KINGDOM|3|eans boost carefully special requests. accounts are. carefull\n24|UNITED STATES|1|y final packages. slow foxes cajole quickly. quickly silent platelets breach ironic accounts. unusual pinto be\n' + nation4 | 2199 | | 01ab9bc150261c9918ce9636be80ea15 | b'0|ALGERIA|0| haggle. carefully final deposits detect slyly agai\n1|ARGENTINA|1|al foxes promise slyly according to the regular accounts. bold requests alon\n2|BRAZIL|1|y alongside of the pending deposits. carefully special packages are about the ironic forges. slyly special \n3|CANADA|1|eas hang ironic, silent packages. slyly regular packages are furiously over the tithes. fluffily bold\n4|EGYPT|4|y above the carefully unusual theodolites. final dugouts are quickly across the furiously regular d\n5|ETHIOPIA|0|ven packages wake quickly. regu\n6|FRANCE|3|refully final requests. regular, ironi\n7|GERMANY|3|l platelets. regular accounts x-ray: unusual, regular acco\n8|INDIA|2|ss excuses cajole slyly across the packages. deposits print aroun\n9|INDONESIA|2| slyly express asymptotes. regular deposits haggle slyly. carefully ironic hockey players sleep blithely. carefull\n10|IRAN|4|efully alongside of the slyly final dependencies. \n11|IRAQ|4|nic deposits boost atop the quickly final requests? quickly regula\n12|JAPAN|2|ously. final, express gifts cajole a\n13|JORDAN|4|ic deposits are blithely about the carefully regular pa\n14|KENYA|0| pending excuses haggle furiously deposits. pending, express pinto beans wake fluffily past t\n15|MOROCCO|0|rns. blithely bold courts among the closely regular packages use furiously bold platelets?\n16|MOZAMBIQUE|0|s. ironic, unusual asymptotes wake blithely r\n17|PERU|1|platelets. blithely pending dependencies use fluffily across the even pinto beans. carefully silent accoun\n18|CHINA|2|c dependencies. furiously express notornis sleep slyly regular accounts. ideas sleep. depos\n19|ROMANIA|3|ular asymptotes are about the furious multipliers. express dependencies nag above the ironically ironic account\n20|SAUDI ARABIA|4|ts. silent requests haggle. closely express packages sleep across the blithely\n21|VIETNAM|2|hely enticingly express accounts. even, final \n22|RUSSIA|3| requests against the platelets use never according to the quickly regular pint\n23|UNITED KINGDOM|3|eans boost carefully special requests. accounts are. carefull\n24|UNITED STATES|1|y final packages. slow foxes cajole quickly. quickly silent platelets breach ironic accounts. unusual pinto be\n' + nation5 | 2199 | | 01ab9bc150261c9918ce9636be80ea15 | b'0|ALGERIA|0| haggle. carefully final deposits detect slyly agai\n1|ARGENTINA|1|al foxes promise slyly according to the regular accounts. bold requests alon\n2|BRAZIL|1|y alongside of the pending deposits. carefully special packages are about the ironic forges. slyly special \n3|CANADA|1|eas hang ironic, silent packages. slyly regular packages are furiously over the tithes. fluffily bold\n4|EGYPT|4|y above the carefully unusual theodolites. final dugouts are quickly across the furiously regular d\n5|ETHIOPIA|0|ven packages wake quickly. regu\n6|FRANCE|3|refully final requests. regular, ironi\n7|GERMANY|3|l platelets. regular accounts x-ray: unusual, regular acco\n8|INDIA|2|ss excuses cajole slyly across the packages. deposits print aroun\n9|INDONESIA|2| slyly express asymptotes. regular deposits haggle slyly. carefully ironic hockey players sleep blithely. carefull\n10|IRAN|4|efully alongside of the slyly final dependencies. \n11|IRAQ|4|nic deposits boost atop the quickly final requests? quickly regula\n12|JAPAN|2|ously. final, express gifts cajole a\n13|JORDAN|4|ic deposits are blithely about the carefully regular pa\n14|KENYA|0| pending excuses haggle furiously deposits. pending, express pinto beans wake fluffily past t\n15|MOROCCO|0|rns. blithely bold courts among the closely regular packages use furiously bold platelets?\n16|MOZAMBIQUE|0|s. ironic, unusual asymptotes wake blithely r\n17|PERU|1|platelets. blithely pending dependencies use fluffily across the even pinto beans. carefully silent accoun\n18|CHINA|2|c dependencies. furiously express notornis sleep slyly regular accounts. ideas sleep. depos\n19|ROMANIA|3|ular asymptotes are about the furious multipliers. express dependencies nag above the ironically ironic account\n20|SAUDI ARABIA|4|ts. silent requests haggle. closely express packages sleep across the blithely\n21|VIETNAM|2|hely enticingly express accounts. even, final \n22|RUSSIA|3| requests against the platelets use never according to the quickly regular pint\n23|UNITED KINGDOM|3|eans boost carefully special requests. accounts are. carefull\n24|UNITED STATES|1|y final packages. slow foxes cajole quickly. quickly silent platelets breach ironic accounts. unusual pinto be\n' +(3 rows) +1: COMMIT; +COMMIT +2: COMMIT; +COMMIT + +-- Test copy binary from and remove_file() +1: BEGIN; +BEGIN +2: BEGIN; +BEGIN +1: COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation7'; +COPY 1 +2&: SELECT remove_file('dir_table1', 'nation6'); +1: COMMIT; +COMMIT +2<: <... completed> + remove_file +------------- + t +(1 row) +2: COMMIT; +COMMIT + +-- Test select and select +1: BEGIN; +BEGIN +2: BEGIN; +BEGIN +1: SELECT relative_path, size, tag, md5 FROM dir_table1 ORDER BY 1; + relative_path | size | tag | md5 +---------------+------+-----+---------------------------------- + nation1 | 2199 | | 01ab9bc150261c9918ce9636be80ea15 + nation3 | 2199 | | 01ab9bc150261c9918ce9636be80ea15 + nation5 | 2199 | | 01ab9bc150261c9918ce9636be80ea15 + nation7 | 2199 | | 01ab9bc150261c9918ce9636be80ea15 +(4 rows) +2: SELECT relative_path, size, tag, md5, content FROM directory_table('dir_table2') ORDER BY 1; + relative_path | size | tag | md5 | content +---------------+------+-----+----------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + nation2 | 2199 | | 01ab9bc150261c9918ce9636be80ea15 | b'0|ALGERIA|0| haggle. carefully final deposits detect slyly agai\n1|ARGENTINA|1|al foxes promise slyly according to the regular accounts. bold requests alon\n2|BRAZIL|1|y alongside of the pending deposits. carefully special packages are about the ironic forges. slyly special \n3|CANADA|1|eas hang ironic, silent packages. slyly regular packages are furiously over the tithes. fluffily bold\n4|EGYPT|4|y above the carefully unusual theodolites. final dugouts are quickly across the furiously regular d\n5|ETHIOPIA|0|ven packages wake quickly. regu\n6|FRANCE|3|refully final requests. regular, ironi\n7|GERMANY|3|l platelets. regular accounts x-ray: unusual, regular acco\n8|INDIA|2|ss excuses cajole slyly across the packages. deposits print aroun\n9|INDONESIA|2| slyly express asymptotes. regular deposits haggle slyly. carefully ironic hockey players sleep blithely. carefull\n10|IRAN|4|efully alongside of the slyly final dependencies. \n11|IRAQ|4|nic deposits boost atop the quickly final requests? quickly regula\n12|JAPAN|2|ously. final, express gifts cajole a\n13|JORDAN|4|ic deposits are blithely about the carefully regular pa\n14|KENYA|0| pending excuses haggle furiously deposits. pending, express pinto beans wake fluffily past t\n15|MOROCCO|0|rns. blithely bold courts among the closely regular packages use furiously bold platelets?\n16|MOZAMBIQUE|0|s. ironic, unusual asymptotes wake blithely r\n17|PERU|1|platelets. blithely pending dependencies use fluffily across the even pinto beans. carefully silent accoun\n18|CHINA|2|c dependencies. furiously express notornis sleep slyly regular accounts. ideas sleep. depos\n19|ROMANIA|3|ular asymptotes are about the furious multipliers. express dependencies nag above the ironically ironic account\n20|SAUDI ARABIA|4|ts. silent requests haggle. closely express packages sleep across the blithely\n21|VIETNAM|2|hely enticingly express accounts. even, final \n22|RUSSIA|3| requests against the platelets use never according to the quickly regular pint\n23|UNITED KINGDOM|3|eans boost carefully special requests. accounts are. carefull\n24|UNITED STATES|1|y final packages. slow foxes cajole quickly. quickly silent platelets breach ironic accounts. unusual pinto be\n' + nation4 | 2199 | | 01ab9bc150261c9918ce9636be80ea15 | b'0|ALGERIA|0| haggle. carefully final deposits detect slyly agai\n1|ARGENTINA|1|al foxes promise slyly according to the regular accounts. bold requests alon\n2|BRAZIL|1|y alongside of the pending deposits. carefully special packages are about the ironic forges. slyly special \n3|CANADA|1|eas hang ironic, silent packages. slyly regular packages are furiously over the tithes. fluffily bold\n4|EGYPT|4|y above the carefully unusual theodolites. final dugouts are quickly across the furiously regular d\n5|ETHIOPIA|0|ven packages wake quickly. regu\n6|FRANCE|3|refully final requests. regular, ironi\n7|GERMANY|3|l platelets. regular accounts x-ray: unusual, regular acco\n8|INDIA|2|ss excuses cajole slyly across the packages. deposits print aroun\n9|INDONESIA|2| slyly express asymptotes. regular deposits haggle slyly. carefully ironic hockey players sleep blithely. carefull\n10|IRAN|4|efully alongside of the slyly final dependencies. \n11|IRAQ|4|nic deposits boost atop the quickly final requests? quickly regula\n12|JAPAN|2|ously. final, express gifts cajole a\n13|JORDAN|4|ic deposits are blithely about the carefully regular pa\n14|KENYA|0| pending excuses haggle furiously deposits. pending, express pinto beans wake fluffily past t\n15|MOROCCO|0|rns. blithely bold courts among the closely regular packages use furiously bold platelets?\n16|MOZAMBIQUE|0|s. ironic, unusual asymptotes wake blithely r\n17|PERU|1|platelets. blithely pending dependencies use fluffily across the even pinto beans. carefully silent accoun\n18|CHINA|2|c dependencies. furiously express notornis sleep slyly regular accounts. ideas sleep. depos\n19|ROMANIA|3|ular asymptotes are about the furious multipliers. express dependencies nag above the ironically ironic account\n20|SAUDI ARABIA|4|ts. silent requests haggle. closely express packages sleep across the blithely\n21|VIETNAM|2|hely enticingly express accounts. even, final \n22|RUSSIA|3| requests against the platelets use never according to the quickly regular pint\n23|UNITED KINGDOM|3|eans boost carefully special requests. accounts are. carefull\n24|UNITED STATES|1|y final packages. slow foxes cajole quickly. quickly silent platelets breach ironic accounts. unusual pinto be\n' + nation5 | 2199 | | 01ab9bc150261c9918ce9636be80ea15 | b'0|ALGERIA|0| haggle. carefully final deposits detect slyly agai\n1|ARGENTINA|1|al foxes promise slyly according to the regular accounts. bold requests alon\n2|BRAZIL|1|y alongside of the pending deposits. carefully special packages are about the ironic forges. slyly special \n3|CANADA|1|eas hang ironic, silent packages. slyly regular packages are furiously over the tithes. fluffily bold\n4|EGYPT|4|y above the carefully unusual theodolites. final dugouts are quickly across the furiously regular d\n5|ETHIOPIA|0|ven packages wake quickly. regu\n6|FRANCE|3|refully final requests. regular, ironi\n7|GERMANY|3|l platelets. regular accounts x-ray: unusual, regular acco\n8|INDIA|2|ss excuses cajole slyly across the packages. deposits print aroun\n9|INDONESIA|2| slyly express asymptotes. regular deposits haggle slyly. carefully ironic hockey players sleep blithely. carefull\n10|IRAN|4|efully alongside of the slyly final dependencies. \n11|IRAQ|4|nic deposits boost atop the quickly final requests? quickly regula\n12|JAPAN|2|ously. final, express gifts cajole a\n13|JORDAN|4|ic deposits are blithely about the carefully regular pa\n14|KENYA|0| pending excuses haggle furiously deposits. pending, express pinto beans wake fluffily past t\n15|MOROCCO|0|rns. blithely bold courts among the closely regular packages use furiously bold platelets?\n16|MOZAMBIQUE|0|s. ironic, unusual asymptotes wake blithely r\n17|PERU|1|platelets. blithely pending dependencies use fluffily across the even pinto beans. carefully silent accoun\n18|CHINA|2|c dependencies. furiously express notornis sleep slyly regular accounts. ideas sleep. depos\n19|ROMANIA|3|ular asymptotes are about the furious multipliers. express dependencies nag above the ironically ironic account\n20|SAUDI ARABIA|4|ts. silent requests haggle. closely express packages sleep across the blithely\n21|VIETNAM|2|hely enticingly express accounts. even, final \n22|RUSSIA|3| requests against the platelets use never according to the quickly regular pint\n23|UNITED KINGDOM|3|eans boost carefully special requests. accounts are. carefull\n24|UNITED STATES|1|y final packages. slow foxes cajole quickly. quickly silent platelets breach ironic accounts. unusual pinto be\n' + nation6 | 2199 | | 01ab9bc150261c9918ce9636be80ea15 | b'0|ALGERIA|0| haggle. carefully final deposits detect slyly agai\n1|ARGENTINA|1|al foxes promise slyly according to the regular accounts. bold requests alon\n2|BRAZIL|1|y alongside of the pending deposits. carefully special packages are about the ironic forges. slyly special \n3|CANADA|1|eas hang ironic, silent packages. slyly regular packages are furiously over the tithes. fluffily bold\n4|EGYPT|4|y above the carefully unusual theodolites. final dugouts are quickly across the furiously regular d\n5|ETHIOPIA|0|ven packages wake quickly. regu\n6|FRANCE|3|refully final requests. regular, ironi\n7|GERMANY|3|l platelets. regular accounts x-ray: unusual, regular acco\n8|INDIA|2|ss excuses cajole slyly across the packages. deposits print aroun\n9|INDONESIA|2| slyly express asymptotes. regular deposits haggle slyly. carefully ironic hockey players sleep blithely. carefull\n10|IRAN|4|efully alongside of the slyly final dependencies. \n11|IRAQ|4|nic deposits boost atop the quickly final requests? quickly regula\n12|JAPAN|2|ously. final, express gifts cajole a\n13|JORDAN|4|ic deposits are blithely about the carefully regular pa\n14|KENYA|0| pending excuses haggle furiously deposits. pending, express pinto beans wake fluffily past t\n15|MOROCCO|0|rns. blithely bold courts among the closely regular packages use furiously bold platelets?\n16|MOZAMBIQUE|0|s. ironic, unusual asymptotes wake blithely r\n17|PERU|1|platelets. blithely pending dependencies use fluffily across the even pinto beans. carefully silent accoun\n18|CHINA|2|c dependencies. furiously express notornis sleep slyly regular accounts. ideas sleep. depos\n19|ROMANIA|3|ular asymptotes are about the furious multipliers. express dependencies nag above the ironically ironic account\n20|SAUDI ARABIA|4|ts. silent requests haggle. closely express packages sleep across the blithely\n21|VIETNAM|2|hely enticingly express accounts. even, final \n22|RUSSIA|3| requests against the platelets use never according to the quickly regular pint\n23|UNITED KINGDOM|3|eans boost carefully special requests. accounts are. carefull\n24|UNITED STATES|1|y final packages. slow foxes cajole quickly. quickly silent platelets breach ironic accounts. unusual pinto be\n' +(4 rows) +1: SELECT relative_path, size, tag, md5, content FROM directory_table('dir_table2') ORDER BY 1; + relative_path | size | tag | md5 | content +---------------+------+-----+----------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + nation2 | 2199 | | 01ab9bc150261c9918ce9636be80ea15 | b'0|ALGERIA|0| haggle. carefully final deposits detect slyly agai\n1|ARGENTINA|1|al foxes promise slyly according to the regular accounts. bold requests alon\n2|BRAZIL|1|y alongside of the pending deposits. carefully special packages are about the ironic forges. slyly special \n3|CANADA|1|eas hang ironic, silent packages. slyly regular packages are furiously over the tithes. fluffily bold\n4|EGYPT|4|y above the carefully unusual theodolites. final dugouts are quickly across the furiously regular d\n5|ETHIOPIA|0|ven packages wake quickly. regu\n6|FRANCE|3|refully final requests. regular, ironi\n7|GERMANY|3|l platelets. regular accounts x-ray: unusual, regular acco\n8|INDIA|2|ss excuses cajole slyly across the packages. deposits print aroun\n9|INDONESIA|2| slyly express asymptotes. regular deposits haggle slyly. carefully ironic hockey players sleep blithely. carefull\n10|IRAN|4|efully alongside of the slyly final dependencies. \n11|IRAQ|4|nic deposits boost atop the quickly final requests? quickly regula\n12|JAPAN|2|ously. final, express gifts cajole a\n13|JORDAN|4|ic deposits are blithely about the carefully regular pa\n14|KENYA|0| pending excuses haggle furiously deposits. pending, express pinto beans wake fluffily past t\n15|MOROCCO|0|rns. blithely bold courts among the closely regular packages use furiously bold platelets?\n16|MOZAMBIQUE|0|s. ironic, unusual asymptotes wake blithely r\n17|PERU|1|platelets. blithely pending dependencies use fluffily across the even pinto beans. carefully silent accoun\n18|CHINA|2|c dependencies. furiously express notornis sleep slyly regular accounts. ideas sleep. depos\n19|ROMANIA|3|ular asymptotes are about the furious multipliers. express dependencies nag above the ironically ironic account\n20|SAUDI ARABIA|4|ts. silent requests haggle. closely express packages sleep across the blithely\n21|VIETNAM|2|hely enticingly express accounts. even, final \n22|RUSSIA|3| requests against the platelets use never according to the quickly regular pint\n23|UNITED KINGDOM|3|eans boost carefully special requests. accounts are. carefull\n24|UNITED STATES|1|y final packages. slow foxes cajole quickly. quickly silent platelets breach ironic accounts. unusual pinto be\n' + nation4 | 2199 | | 01ab9bc150261c9918ce9636be80ea15 | b'0|ALGERIA|0| haggle. carefully final deposits detect slyly agai\n1|ARGENTINA|1|al foxes promise slyly according to the regular accounts. bold requests alon\n2|BRAZIL|1|y alongside of the pending deposits. carefully special packages are about the ironic forges. slyly special \n3|CANADA|1|eas hang ironic, silent packages. slyly regular packages are furiously over the tithes. fluffily bold\n4|EGYPT|4|y above the carefully unusual theodolites. final dugouts are quickly across the furiously regular d\n5|ETHIOPIA|0|ven packages wake quickly. regu\n6|FRANCE|3|refully final requests. regular, ironi\n7|GERMANY|3|l platelets. regular accounts x-ray: unusual, regular acco\n8|INDIA|2|ss excuses cajole slyly across the packages. deposits print aroun\n9|INDONESIA|2| slyly express asymptotes. regular deposits haggle slyly. carefully ironic hockey players sleep blithely. carefull\n10|IRAN|4|efully alongside of the slyly final dependencies. \n11|IRAQ|4|nic deposits boost atop the quickly final requests? quickly regula\n12|JAPAN|2|ously. final, express gifts cajole a\n13|JORDAN|4|ic deposits are blithely about the carefully regular pa\n14|KENYA|0| pending excuses haggle furiously deposits. pending, express pinto beans wake fluffily past t\n15|MOROCCO|0|rns. blithely bold courts among the closely regular packages use furiously bold platelets?\n16|MOZAMBIQUE|0|s. ironic, unusual asymptotes wake blithely r\n17|PERU|1|platelets. blithely pending dependencies use fluffily across the even pinto beans. carefully silent accoun\n18|CHINA|2|c dependencies. furiously express notornis sleep slyly regular accounts. ideas sleep. depos\n19|ROMANIA|3|ular asymptotes are about the furious multipliers. express dependencies nag above the ironically ironic account\n20|SAUDI ARABIA|4|ts. silent requests haggle. closely express packages sleep across the blithely\n21|VIETNAM|2|hely enticingly express accounts. even, final \n22|RUSSIA|3| requests against the platelets use never according to the quickly regular pint\n23|UNITED KINGDOM|3|eans boost carefully special requests. accounts are. carefull\n24|UNITED STATES|1|y final packages. slow foxes cajole quickly. quickly silent platelets breach ironic accounts. unusual pinto be\n' + nation5 | 2199 | | 01ab9bc150261c9918ce9636be80ea15 | b'0|ALGERIA|0| haggle. carefully final deposits detect slyly agai\n1|ARGENTINA|1|al foxes promise slyly according to the regular accounts. bold requests alon\n2|BRAZIL|1|y alongside of the pending deposits. carefully special packages are about the ironic forges. slyly special \n3|CANADA|1|eas hang ironic, silent packages. slyly regular packages are furiously over the tithes. fluffily bold\n4|EGYPT|4|y above the carefully unusual theodolites. final dugouts are quickly across the furiously regular d\n5|ETHIOPIA|0|ven packages wake quickly. regu\n6|FRANCE|3|refully final requests. regular, ironi\n7|GERMANY|3|l platelets. regular accounts x-ray: unusual, regular acco\n8|INDIA|2|ss excuses cajole slyly across the packages. deposits print aroun\n9|INDONESIA|2| slyly express asymptotes. regular deposits haggle slyly. carefully ironic hockey players sleep blithely. carefull\n10|IRAN|4|efully alongside of the slyly final dependencies. \n11|IRAQ|4|nic deposits boost atop the quickly final requests? quickly regula\n12|JAPAN|2|ously. final, express gifts cajole a\n13|JORDAN|4|ic deposits are blithely about the carefully regular pa\n14|KENYA|0| pending excuses haggle furiously deposits. pending, express pinto beans wake fluffily past t\n15|MOROCCO|0|rns. blithely bold courts among the closely regular packages use furiously bold platelets?\n16|MOZAMBIQUE|0|s. ironic, unusual asymptotes wake blithely r\n17|PERU|1|platelets. blithely pending dependencies use fluffily across the even pinto beans. carefully silent accoun\n18|CHINA|2|c dependencies. furiously express notornis sleep slyly regular accounts. ideas sleep. depos\n19|ROMANIA|3|ular asymptotes are about the furious multipliers. express dependencies nag above the ironically ironic account\n20|SAUDI ARABIA|4|ts. silent requests haggle. closely express packages sleep across the blithely\n21|VIETNAM|2|hely enticingly express accounts. even, final \n22|RUSSIA|3| requests against the platelets use never according to the quickly regular pint\n23|UNITED KINGDOM|3|eans boost carefully special requests. accounts are. carefull\n24|UNITED STATES|1|y final packages. slow foxes cajole quickly. quickly silent platelets breach ironic accounts. unusual pinto be\n' + nation6 | 2199 | | 01ab9bc150261c9918ce9636be80ea15 | b'0|ALGERIA|0| haggle. carefully final deposits detect slyly agai\n1|ARGENTINA|1|al foxes promise slyly according to the regular accounts. bold requests alon\n2|BRAZIL|1|y alongside of the pending deposits. carefully special packages are about the ironic forges. slyly special \n3|CANADA|1|eas hang ironic, silent packages. slyly regular packages are furiously over the tithes. fluffily bold\n4|EGYPT|4|y above the carefully unusual theodolites. final dugouts are quickly across the furiously regular d\n5|ETHIOPIA|0|ven packages wake quickly. regu\n6|FRANCE|3|refully final requests. regular, ironi\n7|GERMANY|3|l platelets. regular accounts x-ray: unusual, regular acco\n8|INDIA|2|ss excuses cajole slyly across the packages. deposits print aroun\n9|INDONESIA|2| slyly express asymptotes. regular deposits haggle slyly. carefully ironic hockey players sleep blithely. carefull\n10|IRAN|4|efully alongside of the slyly final dependencies. \n11|IRAQ|4|nic deposits boost atop the quickly final requests? quickly regula\n12|JAPAN|2|ously. final, express gifts cajole a\n13|JORDAN|4|ic deposits are blithely about the carefully regular pa\n14|KENYA|0| pending excuses haggle furiously deposits. pending, express pinto beans wake fluffily past t\n15|MOROCCO|0|rns. blithely bold courts among the closely regular packages use furiously bold platelets?\n16|MOZAMBIQUE|0|s. ironic, unusual asymptotes wake blithely r\n17|PERU|1|platelets. blithely pending dependencies use fluffily across the even pinto beans. carefully silent accoun\n18|CHINA|2|c dependencies. furiously express notornis sleep slyly regular accounts. ideas sleep. depos\n19|ROMANIA|3|ular asymptotes are about the furious multipliers. express dependencies nag above the ironically ironic account\n20|SAUDI ARABIA|4|ts. silent requests haggle. closely express packages sleep across the blithely\n21|VIETNAM|2|hely enticingly express accounts. even, final \n22|RUSSIA|3| requests against the platelets use never according to the quickly regular pint\n23|UNITED KINGDOM|3|eans boost carefully special requests. accounts are. carefull\n24|UNITED STATES|1|y final packages. slow foxes cajole quickly. quickly silent platelets breach ironic accounts. unusual pinto be\n' +(4 rows) +2: SELECT relative_path, size, tag, md5 FROM dir_table1 ORDER BY 1; + relative_path | size | tag | md5 +---------------+------+-----+---------------------------------- + nation1 | 2199 | | 01ab9bc150261c9918ce9636be80ea15 + nation3 | 2199 | | 01ab9bc150261c9918ce9636be80ea15 + nation5 | 2199 | | 01ab9bc150261c9918ce9636be80ea15 + nation7 | 2199 | | 01ab9bc150261c9918ce9636be80ea15 +(4 rows) +2: COMMIT; +COMMIT +1: COMMIT; +COMMIT + +-- Test select and remove_file() +1: BEGIN; +BEGIN +2: BEGIN; +BEGIN +1: SELECT gp_inject_fault('directory_table_inject', 'suspend', dbid) FROM gp_segment_configuration WHERE role='p' and content >= 0; + gp_inject_fault +----------------- + Success: + Success: + Success: +(3 rows) +1&: SELECT relative_path, size, tag, md5, content FROM directory_table('dir_table1') ORDER BY 1; +2&: SELECT remove_file('dir_table1', 'nation7'); +3: SELECT gp_wait_until_triggered_fault('directory_table_inject', 1, dbid) FROM gp_segment_configuration WHERE role='p' and content >= 0; + gp_wait_until_triggered_fault +------------------------------- + Success: + Success: + Success: +(3 rows) +3: SELECT gp_inject_fault('directory_table_inject', 'resume', dbid) FROM gp_segment_configuration WHERE role='p' and content >= 0; + gp_inject_fault +----------------- + Success: + Success: + Success: +(3 rows) +1<: <... completed> + relative_path | size | tag | md5 | content +---------------+------+-----+----------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + nation1 | 2199 | | 01ab9bc150261c9918ce9636be80ea15 | b'0|ALGERIA|0| haggle. carefully final deposits detect slyly agai\n1|ARGENTINA|1|al foxes promise slyly according to the regular accounts. bold requests alon\n2|BRAZIL|1|y alongside of the pending deposits. carefully special packages are about the ironic forges. slyly special \n3|CANADA|1|eas hang ironic, silent packages. slyly regular packages are furiously over the tithes. fluffily bold\n4|EGYPT|4|y above the carefully unusual theodolites. final dugouts are quickly across the furiously regular d\n5|ETHIOPIA|0|ven packages wake quickly. regu\n6|FRANCE|3|refully final requests. regular, ironi\n7|GERMANY|3|l platelets. regular accounts x-ray: unusual, regular acco\n8|INDIA|2|ss excuses cajole slyly across the packages. deposits print aroun\n9|INDONESIA|2| slyly express asymptotes. regular deposits haggle slyly. carefully ironic hockey players sleep blithely. carefull\n10|IRAN|4|efully alongside of the slyly final dependencies. \n11|IRAQ|4|nic deposits boost atop the quickly final requests? quickly regula\n12|JAPAN|2|ously. final, express gifts cajole a\n13|JORDAN|4|ic deposits are blithely about the carefully regular pa\n14|KENYA|0| pending excuses haggle furiously deposits. pending, express pinto beans wake fluffily past t\n15|MOROCCO|0|rns. blithely bold courts among the closely regular packages use furiously bold platelets?\n16|MOZAMBIQUE|0|s. ironic, unusual asymptotes wake blithely r\n17|PERU|1|platelets. blithely pending dependencies use fluffily across the even pinto beans. carefully silent accoun\n18|CHINA|2|c dependencies. furiously express notornis sleep slyly regular accounts. ideas sleep. depos\n19|ROMANIA|3|ular asymptotes are about the furious multipliers. express dependencies nag above the ironically ironic account\n20|SAUDI ARABIA|4|ts. silent requests haggle. closely express packages sleep across the blithely\n21|VIETNAM|2|hely enticingly express accounts. even, final \n22|RUSSIA|3| requests against the platelets use never according to the quickly regular pint\n23|UNITED KINGDOM|3|eans boost carefully special requests. accounts are. carefull\n24|UNITED STATES|1|y final packages. slow foxes cajole quickly. quickly silent platelets breach ironic accounts. unusual pinto be\n' + nation3 | 2199 | | 01ab9bc150261c9918ce9636be80ea15 | b'0|ALGERIA|0| haggle. carefully final deposits detect slyly agai\n1|ARGENTINA|1|al foxes promise slyly according to the regular accounts. bold requests alon\n2|BRAZIL|1|y alongside of the pending deposits. carefully special packages are about the ironic forges. slyly special \n3|CANADA|1|eas hang ironic, silent packages. slyly regular packages are furiously over the tithes. fluffily bold\n4|EGYPT|4|y above the carefully unusual theodolites. final dugouts are quickly across the furiously regular d\n5|ETHIOPIA|0|ven packages wake quickly. regu\n6|FRANCE|3|refully final requests. regular, ironi\n7|GERMANY|3|l platelets. regular accounts x-ray: unusual, regular acco\n8|INDIA|2|ss excuses cajole slyly across the packages. deposits print aroun\n9|INDONESIA|2| slyly express asymptotes. regular deposits haggle slyly. carefully ironic hockey players sleep blithely. carefull\n10|IRAN|4|efully alongside of the slyly final dependencies. \n11|IRAQ|4|nic deposits boost atop the quickly final requests? quickly regula\n12|JAPAN|2|ously. final, express gifts cajole a\n13|JORDAN|4|ic deposits are blithely about the carefully regular pa\n14|KENYA|0| pending excuses haggle furiously deposits. pending, express pinto beans wake fluffily past t\n15|MOROCCO|0|rns. blithely bold courts among the closely regular packages use furiously bold platelets?\n16|MOZAMBIQUE|0|s. ironic, unusual asymptotes wake blithely r\n17|PERU|1|platelets. blithely pending dependencies use fluffily across the even pinto beans. carefully silent accoun\n18|CHINA|2|c dependencies. furiously express notornis sleep slyly regular accounts. ideas sleep. depos\n19|ROMANIA|3|ular asymptotes are about the furious multipliers. express dependencies nag above the ironically ironic account\n20|SAUDI ARABIA|4|ts. silent requests haggle. closely express packages sleep across the blithely\n21|VIETNAM|2|hely enticingly express accounts. even, final \n22|RUSSIA|3| requests against the platelets use never according to the quickly regular pint\n23|UNITED KINGDOM|3|eans boost carefully special requests. accounts are. carefull\n24|UNITED STATES|1|y final packages. slow foxes cajole quickly. quickly silent platelets breach ironic accounts. unusual pinto be\n' + nation5 | 2199 | | 01ab9bc150261c9918ce9636be80ea15 | b'0|ALGERIA|0| haggle. carefully final deposits detect slyly agai\n1|ARGENTINA|1|al foxes promise slyly according to the regular accounts. bold requests alon\n2|BRAZIL|1|y alongside of the pending deposits. carefully special packages are about the ironic forges. slyly special \n3|CANADA|1|eas hang ironic, silent packages. slyly regular packages are furiously over the tithes. fluffily bold\n4|EGYPT|4|y above the carefully unusual theodolites. final dugouts are quickly across the furiously regular d\n5|ETHIOPIA|0|ven packages wake quickly. regu\n6|FRANCE|3|refully final requests. regular, ironi\n7|GERMANY|3|l platelets. regular accounts x-ray: unusual, regular acco\n8|INDIA|2|ss excuses cajole slyly across the packages. deposits print aroun\n9|INDONESIA|2| slyly express asymptotes. regular deposits haggle slyly. carefully ironic hockey players sleep blithely. carefull\n10|IRAN|4|efully alongside of the slyly final dependencies. \n11|IRAQ|4|nic deposits boost atop the quickly final requests? quickly regula\n12|JAPAN|2|ously. final, express gifts cajole a\n13|JORDAN|4|ic deposits are blithely about the carefully regular pa\n14|KENYA|0| pending excuses haggle furiously deposits. pending, express pinto beans wake fluffily past t\n15|MOROCCO|0|rns. blithely bold courts among the closely regular packages use furiously bold platelets?\n16|MOZAMBIQUE|0|s. ironic, unusual asymptotes wake blithely r\n17|PERU|1|platelets. blithely pending dependencies use fluffily across the even pinto beans. carefully silent accoun\n18|CHINA|2|c dependencies. furiously express notornis sleep slyly regular accounts. ideas sleep. depos\n19|ROMANIA|3|ular asymptotes are about the furious multipliers. express dependencies nag above the ironically ironic account\n20|SAUDI ARABIA|4|ts. silent requests haggle. closely express packages sleep across the blithely\n21|VIETNAM|2|hely enticingly express accounts. even, final \n22|RUSSIA|3| requests against the platelets use never according to the quickly regular pint\n23|UNITED KINGDOM|3|eans boost carefully special requests. accounts are. carefull\n24|UNITED STATES|1|y final packages. slow foxes cajole quickly. quickly silent platelets breach ironic accounts. unusual pinto be\n' + nation7 | 2199 | | 01ab9bc150261c9918ce9636be80ea15 | b'0|ALGERIA|0| haggle. carefully final deposits detect slyly agai\n1|ARGENTINA|1|al foxes promise slyly according to the regular accounts. bold requests alon\n2|BRAZIL|1|y alongside of the pending deposits. carefully special packages are about the ironic forges. slyly special \n3|CANADA|1|eas hang ironic, silent packages. slyly regular packages are furiously over the tithes. fluffily bold\n4|EGYPT|4|y above the carefully unusual theodolites. final dugouts are quickly across the furiously regular d\n5|ETHIOPIA|0|ven packages wake quickly. regu\n6|FRANCE|3|refully final requests. regular, ironi\n7|GERMANY|3|l platelets. regular accounts x-ray: unusual, regular acco\n8|INDIA|2|ss excuses cajole slyly across the packages. deposits print aroun\n9|INDONESIA|2| slyly express asymptotes. regular deposits haggle slyly. carefully ironic hockey players sleep blithely. carefull\n10|IRAN|4|efully alongside of the slyly final dependencies. \n11|IRAQ|4|nic deposits boost atop the quickly final requests? quickly regula\n12|JAPAN|2|ously. final, express gifts cajole a\n13|JORDAN|4|ic deposits are blithely about the carefully regular pa\n14|KENYA|0| pending excuses haggle furiously deposits. pending, express pinto beans wake fluffily past t\n15|MOROCCO|0|rns. blithely bold courts among the closely regular packages use furiously bold platelets?\n16|MOZAMBIQUE|0|s. ironic, unusual asymptotes wake blithely r\n17|PERU|1|platelets. blithely pending dependencies use fluffily across the even pinto beans. carefully silent accoun\n18|CHINA|2|c dependencies. furiously express notornis sleep slyly regular accounts. ideas sleep. depos\n19|ROMANIA|3|ular asymptotes are about the furious multipliers. express dependencies nag above the ironically ironic account\n20|SAUDI ARABIA|4|ts. silent requests haggle. closely express packages sleep across the blithely\n21|VIETNAM|2|hely enticingly express accounts. even, final \n22|RUSSIA|3| requests against the platelets use never according to the quickly regular pint\n23|UNITED KINGDOM|3|eans boost carefully special requests. accounts are. carefull\n24|UNITED STATES|1|y final packages. slow foxes cajole quickly. quickly silent platelets breach ironic accounts. unusual pinto be\n' +(4 rows) +1: COMMIT; +COMMIT +2<: <... completed> + remove_file +------------- + t +(1 row) +2: COMMIT; +COMMIT + +1: SELECT gp_inject_fault('directory_table_inject', 'reset', dbid) FROM gp_segment_configuration WHERE role='p' and content >= 0; + gp_inject_fault +----------------- + Success: + Success: + Success: +(3 rows) + +1: BEGIN; +BEGIN +2: BEGIN; +BEGIN +1: SELECT gp_inject_fault('remove_file_inject', 'suspend', dbid) FROM gp_segment_configuration WHERE role='p' and content >= 0; + gp_inject_fault +----------------- + Success: + Success: + Success: +(3 rows) +1&: SELECT remove_file('dir_table1', 'nation5'); +2&: SELECT relative_path, size, tag, md5 FROM dir_table1 ORDER BY 1; +3: SELECT gp_wait_until_triggered_fault('remove_file_inject', 1, dbid) FROM gp_segment_configuration WHERE role='p' and content >= 0; + gp_wait_until_triggered_fault +------------------------------- + Success: + Success: + Success: +(3 rows) +3: SELECT gp_inject_fault('remove_file_inject', 'resume', dbid) FROM gp_segment_configuration WHERE role='p' and content >= 0; + gp_inject_fault +----------------- + Success: + Success: + Success: +(3 rows) +1<: <... completed> + remove_file +------------- + t +(1 row) +1: COMMIT; +COMMIT +2<: <... completed> + relative_path | size | tag | md5 +---------------+------+-----+---------------------------------- + nation1 | 2199 | | 01ab9bc150261c9918ce9636be80ea15 + nation3 | 2199 | | 01ab9bc150261c9918ce9636be80ea15 +(2 rows) +2: COMMIT; +COMMIT + +1: SELECT gp_inject_fault('remove_file_inject', 'reset', dbid) FROM gp_segment_configuration WHERE role='p' and content >= 0; + gp_inject_fault +----------------- + Success: + Success: + Success: +(3 rows) + +1: BEGIN; +BEGIN +2: BEGIN; +BEGIN +1: SELECT gp_inject_fault('remove_file_inject', 'suspend', dbid) FROM gp_segment_configuration WHERE role='p' and content >= 0; + gp_inject_fault +----------------- + Success: + Success: + Success: +(3 rows) +1&: SELECT remove_file('dir_table2', 'nation6'); +2&: SELECT relative_path, size, tag, md5, content FROM directory_table('dir_table2') ORDER BY 1; +3: SELECT gp_wait_until_triggered_fault('remove_file_inject', 1, dbid) FROM gp_segment_configuration WHERE role='p' and content >= 0; + gp_wait_until_triggered_fault +------------------------------- + Success: + Success: + Success: +(3 rows) +3: SELECT gp_inject_fault('remove_file_inject', 'resume', dbid) FROM gp_segment_configuration WHERE role='p' and content >= 0; + gp_inject_fault +----------------- + Success: + Success: + Success: +(3 rows) +1<: <... completed> + remove_file +------------- + t +(1 row) +1: COMMIT; +COMMIT +2<: <... completed> + relative_path | size | tag | md5 | content +---------------+------+-----+----------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + nation2 | 2199 | | 01ab9bc150261c9918ce9636be80ea15 | b'0|ALGERIA|0| haggle. carefully final deposits detect slyly agai\n1|ARGENTINA|1|al foxes promise slyly according to the regular accounts. bold requests alon\n2|BRAZIL|1|y alongside of the pending deposits. carefully special packages are about the ironic forges. slyly special \n3|CANADA|1|eas hang ironic, silent packages. slyly regular packages are furiously over the tithes. fluffily bold\n4|EGYPT|4|y above the carefully unusual theodolites. final dugouts are quickly across the furiously regular d\n5|ETHIOPIA|0|ven packages wake quickly. regu\n6|FRANCE|3|refully final requests. regular, ironi\n7|GERMANY|3|l platelets. regular accounts x-ray: unusual, regular acco\n8|INDIA|2|ss excuses cajole slyly across the packages. deposits print aroun\n9|INDONESIA|2| slyly express asymptotes. regular deposits haggle slyly. carefully ironic hockey players sleep blithely. carefull\n10|IRAN|4|efully alongside of the slyly final dependencies. \n11|IRAQ|4|nic deposits boost atop the quickly final requests? quickly regula\n12|JAPAN|2|ously. final, express gifts cajole a\n13|JORDAN|4|ic deposits are blithely about the carefully regular pa\n14|KENYA|0| pending excuses haggle furiously deposits. pending, express pinto beans wake fluffily past t\n15|MOROCCO|0|rns. blithely bold courts among the closely regular packages use furiously bold platelets?\n16|MOZAMBIQUE|0|s. ironic, unusual asymptotes wake blithely r\n17|PERU|1|platelets. blithely pending dependencies use fluffily across the even pinto beans. carefully silent accoun\n18|CHINA|2|c dependencies. furiously express notornis sleep slyly regular accounts. ideas sleep. depos\n19|ROMANIA|3|ular asymptotes are about the furious multipliers. express dependencies nag above the ironically ironic account\n20|SAUDI ARABIA|4|ts. silent requests haggle. closely express packages sleep across the blithely\n21|VIETNAM|2|hely enticingly express accounts. even, final \n22|RUSSIA|3| requests against the platelets use never according to the quickly regular pint\n23|UNITED KINGDOM|3|eans boost carefully special requests. accounts are. carefull\n24|UNITED STATES|1|y final packages. slow foxes cajole quickly. quickly silent platelets breach ironic accounts. unusual pinto be\n' + nation4 | 2199 | | 01ab9bc150261c9918ce9636be80ea15 | b'0|ALGERIA|0| haggle. carefully final deposits detect slyly agai\n1|ARGENTINA|1|al foxes promise slyly according to the regular accounts. bold requests alon\n2|BRAZIL|1|y alongside of the pending deposits. carefully special packages are about the ironic forges. slyly special \n3|CANADA|1|eas hang ironic, silent packages. slyly regular packages are furiously over the tithes. fluffily bold\n4|EGYPT|4|y above the carefully unusual theodolites. final dugouts are quickly across the furiously regular d\n5|ETHIOPIA|0|ven packages wake quickly. regu\n6|FRANCE|3|refully final requests. regular, ironi\n7|GERMANY|3|l platelets. regular accounts x-ray: unusual, regular acco\n8|INDIA|2|ss excuses cajole slyly across the packages. deposits print aroun\n9|INDONESIA|2| slyly express asymptotes. regular deposits haggle slyly. carefully ironic hockey players sleep blithely. carefull\n10|IRAN|4|efully alongside of the slyly final dependencies. \n11|IRAQ|4|nic deposits boost atop the quickly final requests? quickly regula\n12|JAPAN|2|ously. final, express gifts cajole a\n13|JORDAN|4|ic deposits are blithely about the carefully regular pa\n14|KENYA|0| pending excuses haggle furiously deposits. pending, express pinto beans wake fluffily past t\n15|MOROCCO|0|rns. blithely bold courts among the closely regular packages use furiously bold platelets?\n16|MOZAMBIQUE|0|s. ironic, unusual asymptotes wake blithely r\n17|PERU|1|platelets. blithely pending dependencies use fluffily across the even pinto beans. carefully silent accoun\n18|CHINA|2|c dependencies. furiously express notornis sleep slyly regular accounts. ideas sleep. depos\n19|ROMANIA|3|ular asymptotes are about the furious multipliers. express dependencies nag above the ironically ironic account\n20|SAUDI ARABIA|4|ts. silent requests haggle. closely express packages sleep across the blithely\n21|VIETNAM|2|hely enticingly express accounts. even, final \n22|RUSSIA|3| requests against the platelets use never according to the quickly regular pint\n23|UNITED KINGDOM|3|eans boost carefully special requests. accounts are. carefull\n24|UNITED STATES|1|y final packages. slow foxes cajole quickly. quickly silent platelets breach ironic accounts. unusual pinto be\n' + nation5 | 2199 | | 01ab9bc150261c9918ce9636be80ea15 | b'0|ALGERIA|0| haggle. carefully final deposits detect slyly agai\n1|ARGENTINA|1|al foxes promise slyly according to the regular accounts. bold requests alon\n2|BRAZIL|1|y alongside of the pending deposits. carefully special packages are about the ironic forges. slyly special \n3|CANADA|1|eas hang ironic, silent packages. slyly regular packages are furiously over the tithes. fluffily bold\n4|EGYPT|4|y above the carefully unusual theodolites. final dugouts are quickly across the furiously regular d\n5|ETHIOPIA|0|ven packages wake quickly. regu\n6|FRANCE|3|refully final requests. regular, ironi\n7|GERMANY|3|l platelets. regular accounts x-ray: unusual, regular acco\n8|INDIA|2|ss excuses cajole slyly across the packages. deposits print aroun\n9|INDONESIA|2| slyly express asymptotes. regular deposits haggle slyly. carefully ironic hockey players sleep blithely. carefull\n10|IRAN|4|efully alongside of the slyly final dependencies. \n11|IRAQ|4|nic deposits boost atop the quickly final requests? quickly regula\n12|JAPAN|2|ously. final, express gifts cajole a\n13|JORDAN|4|ic deposits are blithely about the carefully regular pa\n14|KENYA|0| pending excuses haggle furiously deposits. pending, express pinto beans wake fluffily past t\n15|MOROCCO|0|rns. blithely bold courts among the closely regular packages use furiously bold platelets?\n16|MOZAMBIQUE|0|s. ironic, unusual asymptotes wake blithely r\n17|PERU|1|platelets. blithely pending dependencies use fluffily across the even pinto beans. carefully silent accoun\n18|CHINA|2|c dependencies. furiously express notornis sleep slyly regular accounts. ideas sleep. depos\n19|ROMANIA|3|ular asymptotes are about the furious multipliers. express dependencies nag above the ironically ironic account\n20|SAUDI ARABIA|4|ts. silent requests haggle. closely express packages sleep across the blithely\n21|VIETNAM|2|hely enticingly express accounts. even, final \n22|RUSSIA|3| requests against the platelets use never according to the quickly regular pint\n23|UNITED KINGDOM|3|eans boost carefully special requests. accounts are. carefull\n24|UNITED STATES|1|y final packages. slow foxes cajole quickly. quickly silent platelets breach ironic accounts. unusual pinto be\n' +(3 rows) +2: COMMIT; +COMMIT + +1: SELECT gp_inject_fault('remove_file_inject', 'reset', dbid) FROM gp_segment_configuration WHERE role='p' and content >= 0; + gp_inject_fault +----------------- + Success: + Success: + Success: +(3 rows) + +1: BEGIN; +BEGIN +2: BEGIN; +BEGIN +1: SELECT gp_inject_fault('directory_table_inject', 'suspend', dbid) FROM gp_segment_configuration WHERE role='p' and content >= 0; + gp_inject_fault +----------------- + Success: + Success: + Success: +(3 rows) +1&: SELECT relative_path, size, tag, md5, content FROM directory_table('dir_table2') ORDER BY 1; +2&: SELECT remove_file('dir_table2', 'nation5'); +3: SELECT gp_wait_until_triggered_fault('directory_table_inject', 1, dbid) FROM gp_segment_configuration WHERE role='p' and content >= 0; + gp_wait_until_triggered_fault +------------------------------- + Success: + Success: + Success: +(3 rows) +3: SELECT gp_inject_fault('directory_table_inject', 'resume', dbid) FROM gp_segment_configuration WHERE role='p' and content >= 0; + gp_inject_fault +----------------- + Success: + Success: + Success: +(3 rows) +1<: <... completed> + relative_path | size | tag | md5 | content +---------------+------+-----+----------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + nation2 | 2199 | | 01ab9bc150261c9918ce9636be80ea15 | b'0|ALGERIA|0| haggle. carefully final deposits detect slyly agai\n1|ARGENTINA|1|al foxes promise slyly according to the regular accounts. bold requests alon\n2|BRAZIL|1|y alongside of the pending deposits. carefully special packages are about the ironic forges. slyly special \n3|CANADA|1|eas hang ironic, silent packages. slyly regular packages are furiously over the tithes. fluffily bold\n4|EGYPT|4|y above the carefully unusual theodolites. final dugouts are quickly across the furiously regular d\n5|ETHIOPIA|0|ven packages wake quickly. regu\n6|FRANCE|3|refully final requests. regular, ironi\n7|GERMANY|3|l platelets. regular accounts x-ray: unusual, regular acco\n8|INDIA|2|ss excuses cajole slyly across the packages. deposits print aroun\n9|INDONESIA|2| slyly express asymptotes. regular deposits haggle slyly. carefully ironic hockey players sleep blithely. carefull\n10|IRAN|4|efully alongside of the slyly final dependencies. \n11|IRAQ|4|nic deposits boost atop the quickly final requests? quickly regula\n12|JAPAN|2|ously. final, express gifts cajole a\n13|JORDAN|4|ic deposits are blithely about the carefully regular pa\n14|KENYA|0| pending excuses haggle furiously deposits. pending, express pinto beans wake fluffily past t\n15|MOROCCO|0|rns. blithely bold courts among the closely regular packages use furiously bold platelets?\n16|MOZAMBIQUE|0|s. ironic, unusual asymptotes wake blithely r\n17|PERU|1|platelets. blithely pending dependencies use fluffily across the even pinto beans. carefully silent accoun\n18|CHINA|2|c dependencies. furiously express notornis sleep slyly regular accounts. ideas sleep. depos\n19|ROMANIA|3|ular asymptotes are about the furious multipliers. express dependencies nag above the ironically ironic account\n20|SAUDI ARABIA|4|ts. silent requests haggle. closely express packages sleep across the blithely\n21|VIETNAM|2|hely enticingly express accounts. even, final \n22|RUSSIA|3| requests against the platelets use never according to the quickly regular pint\n23|UNITED KINGDOM|3|eans boost carefully special requests. accounts are. carefull\n24|UNITED STATES|1|y final packages. slow foxes cajole quickly. quickly silent platelets breach ironic accounts. unusual pinto be\n' + nation4 | 2199 | | 01ab9bc150261c9918ce9636be80ea15 | b'0|ALGERIA|0| haggle. carefully final deposits detect slyly agai\n1|ARGENTINA|1|al foxes promise slyly according to the regular accounts. bold requests alon\n2|BRAZIL|1|y alongside of the pending deposits. carefully special packages are about the ironic forges. slyly special \n3|CANADA|1|eas hang ironic, silent packages. slyly regular packages are furiously over the tithes. fluffily bold\n4|EGYPT|4|y above the carefully unusual theodolites. final dugouts are quickly across the furiously regular d\n5|ETHIOPIA|0|ven packages wake quickly. regu\n6|FRANCE|3|refully final requests. regular, ironi\n7|GERMANY|3|l platelets. regular accounts x-ray: unusual, regular acco\n8|INDIA|2|ss excuses cajole slyly across the packages. deposits print aroun\n9|INDONESIA|2| slyly express asymptotes. regular deposits haggle slyly. carefully ironic hockey players sleep blithely. carefull\n10|IRAN|4|efully alongside of the slyly final dependencies. \n11|IRAQ|4|nic deposits boost atop the quickly final requests? quickly regula\n12|JAPAN|2|ously. final, express gifts cajole a\n13|JORDAN|4|ic deposits are blithely about the carefully regular pa\n14|KENYA|0| pending excuses haggle furiously deposits. pending, express pinto beans wake fluffily past t\n15|MOROCCO|0|rns. blithely bold courts among the closely regular packages use furiously bold platelets?\n16|MOZAMBIQUE|0|s. ironic, unusual asymptotes wake blithely r\n17|PERU|1|platelets. blithely pending dependencies use fluffily across the even pinto beans. carefully silent accoun\n18|CHINA|2|c dependencies. furiously express notornis sleep slyly regular accounts. ideas sleep. depos\n19|ROMANIA|3|ular asymptotes are about the furious multipliers. express dependencies nag above the ironically ironic account\n20|SAUDI ARABIA|4|ts. silent requests haggle. closely express packages sleep across the blithely\n21|VIETNAM|2|hely enticingly express accounts. even, final \n22|RUSSIA|3| requests against the platelets use never according to the quickly regular pint\n23|UNITED KINGDOM|3|eans boost carefully special requests. accounts are. carefull\n24|UNITED STATES|1|y final packages. slow foxes cajole quickly. quickly silent platelets breach ironic accounts. unusual pinto be\n' + nation5 | 2199 | | 01ab9bc150261c9918ce9636be80ea15 | b'0|ALGERIA|0| haggle. carefully final deposits detect slyly agai\n1|ARGENTINA|1|al foxes promise slyly according to the regular accounts. bold requests alon\n2|BRAZIL|1|y alongside of the pending deposits. carefully special packages are about the ironic forges. slyly special \n3|CANADA|1|eas hang ironic, silent packages. slyly regular packages are furiously over the tithes. fluffily bold\n4|EGYPT|4|y above the carefully unusual theodolites. final dugouts are quickly across the furiously regular d\n5|ETHIOPIA|0|ven packages wake quickly. regu\n6|FRANCE|3|refully final requests. regular, ironi\n7|GERMANY|3|l platelets. regular accounts x-ray: unusual, regular acco\n8|INDIA|2|ss excuses cajole slyly across the packages. deposits print aroun\n9|INDONESIA|2| slyly express asymptotes. regular deposits haggle slyly. carefully ironic hockey players sleep blithely. carefull\n10|IRAN|4|efully alongside of the slyly final dependencies. \n11|IRAQ|4|nic deposits boost atop the quickly final requests? quickly regula\n12|JAPAN|2|ously. final, express gifts cajole a\n13|JORDAN|4|ic deposits are blithely about the carefully regular pa\n14|KENYA|0| pending excuses haggle furiously deposits. pending, express pinto beans wake fluffily past t\n15|MOROCCO|0|rns. blithely bold courts among the closely regular packages use furiously bold platelets?\n16|MOZAMBIQUE|0|s. ironic, unusual asymptotes wake blithely r\n17|PERU|1|platelets. blithely pending dependencies use fluffily across the even pinto beans. carefully silent accoun\n18|CHINA|2|c dependencies. furiously express notornis sleep slyly regular accounts. ideas sleep. depos\n19|ROMANIA|3|ular asymptotes are about the furious multipliers. express dependencies nag above the ironically ironic account\n20|SAUDI ARABIA|4|ts. silent requests haggle. closely express packages sleep across the blithely\n21|VIETNAM|2|hely enticingly express accounts. even, final \n22|RUSSIA|3| requests against the platelets use never according to the quickly regular pint\n23|UNITED KINGDOM|3|eans boost carefully special requests. accounts are. carefull\n24|UNITED STATES|1|y final packages. slow foxes cajole quickly. quickly silent platelets breach ironic accounts. unusual pinto be\n' +(3 rows) +1: COMMIT; +COMMIT +2<: <... completed> + remove_file +------------- + t +(1 row) +2: COMMIT; +COMMIT + +1: SELECT gp_inject_fault('directory_table_inject', 'reset', dbid) FROM gp_segment_configuration WHERE role='p' and content >= 0; + gp_inject_fault +----------------- + Success: + Success: + Success: +(3 rows) + +-- Test create directory table and drop directory table +1: BEGIN; +BEGIN +2: BEGIN; +BEGIN +1: CREATE DIRECTORY TABLE dir_table3 TABLESPACE directory_tblspc; +CREATE +2: DROP DIRECTORY TABLE dir_table2; +DROP +2: CREATE DIRECTORY TABLE dir_table2 TABLESPACE directory_tblspc; +CREATE +1: COMMIT; +COMMIT +2: COMMIT; +COMMIT + +! rm -rf '@testtablespace@'; + +DROP TABLESPACE directory_tblspc; +DROP diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out index 8b77a2dbf51..4774b14722c 100644 --- a/src/test/regress/expected/create_index.out +++ b/src/test/regress/expected/create_index.out @@ -2530,14 +2530,14 @@ SELECT relid, parentrelid, level FROM pg_partition_tree('concur_reindex_part_ind -- REINDEX TABLE fails for partitioned indexes -- Top-most parent index REINDEX TABLE concur_reindex_part_index; -- error -ERROR: "concur_reindex_part_index" is not a table or materialized view +ERROR: "concur_reindex_part_index" is not a table, directory table or materialized view REINDEX TABLE concur_reindex_part_index; -- error -ERROR: "concur_reindex_part_index" is not a table or materialized view +ERROR: "concur_reindex_part_index" is not a table, directory table or materialized view -- Partitioned index with no leaves REINDEX TABLE concur_reindex_part_index_10; -- error -ERROR: "concur_reindex_part_index_10" is not a table or materialized view +ERROR: "concur_reindex_part_index_10" is not a table, directory table or materialized view REINDEX TABLE concur_reindex_part_index_10; -- error -ERROR: "concur_reindex_part_index_10" is not a table or materialized view +ERROR: "concur_reindex_part_index_10" is not a table, directory table or materialized view -- Cannot run in a transaction block BEGIN; REINDEX INDEX concur_reindex_part_index; diff --git a/src/test/regress/expected/create_index_optimizer.out b/src/test/regress/expected/create_index_optimizer.out index 385b3aeb9e1..c0a9e4b98c0 100644 --- a/src/test/regress/expected/create_index_optimizer.out +++ b/src/test/regress/expected/create_index_optimizer.out @@ -2569,14 +2569,14 @@ SELECT relid, parentrelid, level FROM pg_partition_tree('concur_reindex_part_ind -- REINDEX TABLE fails for partitioned indexes -- Top-most parent index REINDEX TABLE concur_reindex_part_index; -- error -ERROR: "concur_reindex_part_index" is not a table or materialized view +ERROR: "concur_reindex_part_index" is not a table, directory table or materialized view REINDEX TABLE concur_reindex_part_index; -- error -ERROR: "concur_reindex_part_index" is not a table or materialized view +ERROR: "concur_reindex_part_index" is not a table, directory table or materialized view -- Partitioned index with no leaves REINDEX TABLE concur_reindex_part_index_10; -- error -ERROR: "concur_reindex_part_index_10" is not a table or materialized view +ERROR: "concur_reindex_part_index_10" is not a table, directory table or materialized view REINDEX TABLE concur_reindex_part_index_10; -- error -ERROR: "concur_reindex_part_index_10" is not a table or materialized view +ERROR: "concur_reindex_part_index_10" is not a table, directory table or materialized view -- Cannot run in a transaction block BEGIN; REINDEX INDEX concur_reindex_part_index; diff --git a/src/test/regress/expected/create_table_like.out b/src/test/regress/expected/create_table_like.out index d8d973b2fd0..0018b38650b 100644 --- a/src/test/regress/expected/create_table_like.out +++ b/src/test/regress/expected/create_table_like.out @@ -517,7 +517,7 @@ DROP TABLE noinh_con_copy, noinh_con_copy1; CREATE TABLE ctlt4 (a int, b text); CREATE SEQUENCE ctlseq1; CREATE TABLE ctlt10 (LIKE ctlseq1); -- fail -ERROR: "ctlseq1" is not a table, view, materialized view, composite type, or foreign table +ERROR: "ctlseq1" is not a table, directory table, view, materialized view, composite type, or foreign table LINE 1: CREATE TABLE ctlt10 (LIKE ctlseq1); ^ CREATE VIEW ctlv1 AS SELECT * FROM ctlt4; diff --git a/src/test/regress/expected/minirepro.out b/src/test/regress/expected/minirepro.out index 32fb6aab6da..79d67481f91 100644 --- a/src/test/regress/expected/minirepro.out +++ b/src/test/regress/expected/minirepro.out @@ -283,10 +283,10 @@ SET SET SET SET -psql:data/minirepro.sql:44: ERROR: only shared relations can be placed in pg_global tablespace -psql:data/minirepro.sql:46: ERROR: permission denied: "pg_tablespace" is a system catalog -psql:data/minirepro.sql:54: ERROR: permission denied: "pg_tablespace" is a system catalog -psql:data/minirepro.sql:62: ERROR: permission denied: "pg_tablespace" is a system catalog +psql:data/minirepro.sql:46: ERROR: only shared relations can be placed in pg_global tablespace +psql:data/minirepro.sql:48: ERROR: permission denied: "pg_tablespace" is a system catalog +psql:data/minirepro.sql:56: ERROR: permission denied: "pg_tablespace" is a system catalog +psql:data/minirepro.sql:64: ERROR: permission denied: "pg_tablespace" is a system catalog SET UPDATE 1 DELETE 1 @@ -299,6 +299,10 @@ DELETE 1 INSERT 0 1 DELETE 1 INSERT 0 1 +DELETE 1 +INSERT 0 1 +DELETE 1 +INSERT 0 1 select staattnum, stainherit, @@ -338,6 +342,8 @@ from pg_statistic where starelid='pg_tablespace'::regclass; 3 | f | 0 | 4 | -0.5 | 1 | 3 | 0 | 0 | 0 | 607 | 609 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | {1} | {1} | | | | {10} | | | | 4 | f | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | | | | | | | | | | 5 | f | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | | | | | | | | | | -(5 rows) + 6 | f | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | | | | | | | | | | + 7 | f | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | | | | | | | | | | +(7 rows) \! rm data/minirepro_q.sql diff --git a/src/test/regress/expected/oidjoins.out b/src/test/regress/expected/oidjoins.out index 8ef30c843c7..4d6ad39fbb8 100644 --- a/src/test/regress/expected/oidjoins.out +++ b/src/test/regress/expected/oidjoins.out @@ -142,6 +142,9 @@ NOTICE: checking pg_largeobject {loid} => pg_largeobject_metadata {oid} NOTICE: checking pg_aggregate {aggfnoid} => pg_proc {oid} NOTICE: checking pg_aggregate {aggtransfn} => pg_proc {oid} NOTICE: checking pg_aggregate {aggfinalfn} => pg_proc {oid} +NOTICE: checking gp_storage_server {srvowner} => pg_authid {oid} +NOTICE: checking gp_storage_user_mapping {umserver} => gp_storage_server {oid} +NOTICE: checking gp_storage_user_mapping {umuser} => pg_authid {oid} NOTICE: checking pg_aggregate {aggcombinefn} => pg_proc {oid} NOTICE: checking pg_aggregate {aggserialfn} => pg_proc {oid} NOTICE: checking pg_aggregate {aggdeserialfn} => pg_proc {oid} @@ -179,6 +182,8 @@ NOTICE: checking pg_trigger {tgrelid,tgattr} => pg_attribute {attrelid,attnum} NOTICE: checking pg_event_trigger {evtowner} => pg_authid {oid} NOTICE: checking pg_event_trigger {evtfoid} => pg_proc {oid} NOTICE: checking pg_description {classoid} => pg_class {oid} +NOTICE: checking pg_directory_table {dtrelid} => pg_class {oid} +NOTICE: checking pg_directory_table {dttablespace} => pg_tablespace {oid} NOTICE: checking pg_cast {castsource} => pg_type {oid} NOTICE: checking pg_cast {casttarget} => pg_type {oid} NOTICE: checking pg_cast {castfunc} => pg_proc {oid} diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out index fbac24e2306..85b3ce33312 100644 --- a/src/test/regress/expected/opr_sanity.out +++ b/src/test/regress/expected/opr_sanity.out @@ -402,12 +402,14 @@ WHERE 'cstring'::regtype = ANY (p1.proargtypes) AND NOT EXISTS(SELECT 1 FROM pg_conversion WHERE conproc = p1.oid) AND p1.oid != 'shell_in(cstring)'::regprocedure ORDER BY 1; - oid | proname -------+----------------- + oid | proname +------+--------------------- 2293 | cstring_out 2501 | cstring_send 7060 | get_role_status -(3 rows) + 8996 | remove_file + 9109 | remove_file_segment +(5 rows) -- Likewise, look for functions that return cstring and aren't datatype output -- functions nor typmod output functions. diff --git a/src/test/regress/expected/sanity_check.out b/src/test/regress/expected/sanity_check.out index e70e4f17fa8..ca4b1db5320 100644 --- a/src/test/regress/expected/sanity_check.out +++ b/src/test/regress/expected/sanity_check.out @@ -128,6 +128,7 @@ pg_db_role_setting|t pg_default_acl|t pg_depend|t pg_description|t +pg_directory_table|t pg_enum|t pg_event_trigger|t pg_extension|t diff --git a/src/test/regress/greenplum_schedule b/src/test/regress/greenplum_schedule index 58fda7b5803..79ae4d04baa 100755 --- a/src/test/regress/greenplum_schedule +++ b/src/test/regress/greenplum_schedule @@ -313,4 +313,7 @@ test: aqumv # test access method with encoding options test: am_encoding +# tests of directory table +test: directory_table + # end of tests diff --git a/src/test/regress/input/directory_table.source b/src/test/regress/input/directory_table.source new file mode 100644 index 00000000000..089c3177310 --- /dev/null +++ b/src/test/regress/input/directory_table.source @@ -0,0 +1,647 @@ +-- +-- Test for directory table +-- + +-- Display pg_tablespace, pg_directory_table, gp_storage_server, gp_storage_user_mapping catalog +\d+ pg_tablespace; +\d+ pg_directory_table; +\d+ gp_storage_server; +\d+ gp_storage_user_mapping; + +SELECT relname, relisshared, relpersistence, relkind FROM pg_class WHERE relname = 'pg_directory_table'; +SELECT relname, relisshared, relpersistence, relkind FROM pg_class WHERE relname = 'gp_storage_server'; +SELECT relname, relisshared, relpersistence, relkind FROM pg_class WHERE relname = 'gp_storage_user_mapping'; + +-- CREATE TABLESPACE +CREATE TABLESPACE directory_tblspc LOCATION '@testtablespace@'; + +-- CREATE DATABASE +CREATE DATABASE dirtable_db; +\c dirtable_db +\d+ pg_directory_table; +\d+ gp_storage_server; +\d+ gp_storage_user_mapping; + +SELECT relname, relisshared, relpersistence, relkind FROM pg_class WHERE relname = 'pg_directory_table'; +SELECT relname, relisshared, relpersistence, relkind FROM pg_class WHERE relname = 'gp_storage_server'; +SELECT relname, relisshared, relpersistence, relkind FROM pg_class WHERE relname = 'gp_storage_user_mapping'; +\c regression + +-- CREATE USER for directory table +CREATE USER test_dirtable1; +CREATE USER test_dirtable2; +CREATE USER test_dirtable3; +CREATE USER test_dirtable4; + +-- Test CREATE STORAGE SERVER +SELECT srvname, srvacl, srvoptions from gp_storage_server ORDER BY 1; +CREATE STORAGE SERVER oss_server1; +CREATE STORAGE SERVER oss_server2 OPTIONS(protocal 'localhost'); +CREATE STORAGE SERVER oss_server3 OPTIONS(endpoint '127.0.0.1:9000'); +CREATE STORAGE SERVER oss_server4 OPTIONS(https 'true'); +CREATE STORAGE SERVER oss_server5 OPTIONS(virtual_host 'false'); +CREATE STORAGE SERVER oss_server6 OPTIONS(protocol 'qingstor', endpoint 'pek3b,qingstor.com'); +CREATE STORAGE SERVER oss_server7 OPTIONS(https 'false', virtual_host 'true'); +CREATE STORAGE SERVER oss_server8 OPTIONS(protocol 'hdfs', namenode '127.0.0.1:8020'); +CREATE STORAGE SERVER oss_server9 OWNER TO postgres; -- fail +CREATE STORAGE SERVER IF NOT EXISTS oss_server10; +CREATE STORAGE SERVER IF NOT EXISTS oss_server11 OPTIONS(protocol 's3av2'); +CREATE STORAGE SERVER IF NOT EXISTS oss_server12 OPTIONS(protocol 's3av2', endpoint '127.0.0.1:9000', https 'false'); +CREATE STORAGE SERVER IF NOT EXISTS oss_server13 OWNER TO postgres; -- fail + +SELECT srvname, srvacl, srvoptions from gp_storage_server ORDER BY 1; +\c dirtable_db +SELECT srvname, srvacl, srvoptions from gp_storage_server ORDER BY 1; +\c regression + +-- Test ALTER STORAGE SERVER +ALTER STORAGE SERVER oss_server1 OPTIONS(protocol 'aws'); +ALTER STORAGE SERVER oss_server1 OPTIONS(protocol 'test'); -- fail +ALTER STORAGE SERVER oss_server2 OPTIONS(https 'true'); +ALTER STORAGE SERVER oss_server2 OPTIONS(https 'false', virtual_host 'true'); -- fail +ALTER STORAGE SERVER oss_server2 OPTIONS(virtual_host 'true'); +ALTER STORAGE SERVER oss_server3 OPTIONS(endpoint '192.168.0.1'); -- fail +ALTER STORAGE SERVER oss_server4 OPTIONS(protocol 'localhost', virtual_host 'true'); +ALTER STORAGE SERVER oss_server4 OPTIONS(protocol 'qingstor'); -- fail +ALTER STORAGE SERVER oss_server5; -- fail +ALTER STORAGE SERVER oss_server6 OWNER TO postgres; -- fail +ALTER STORAGE SERVER IF EXISTS oss_server7 OPTIONS(endpoint '127.0.0.1:6555'); -- fail +ALTER STORAGE SERVER IF NOT EXISTS oss_server8 OPTIONS(virtual_host 'true'); -- fail + +SELECT srvname, srvacl, srvoptions from gp_storage_server ORDER BY 1; +\c dirtable_db +SELECT srvname, srvacl, srvoptions from gp_storage_server ORDER BY 1; +\c regression + +-- Test CREATE STORAGE USER MAPPING +CREATE STORAGE USER MAPPING FOR CURRENT_USER; -- fail + +CREATE STORAGE USER MAPPING FOR CURRENT_USER STORAGE SERVER oss_server1; + +CREATE STORAGE USER MAPPING FOR CURRENT_USER STORAGE SERVER oss_server1 +OPTIONS (accesskey 'KGFQWEFQQEFXVAEAWLLC', secretkey '0SJIWiIATh6jOlmAKr8DGq6hOAGBI1BnsnvgJmTs'); -- fail + +CREATE STORAGE USER MAPPING IF NOT EXISTS FOR CURRENT_USER STORAGE SERVER oss_server1; + +CREATE STORAGE USER MAPPING IF NOT EXISTS FOR CURRENT_USER STORAGE SERVER oss_server1 +OPTIONS (auth_method 'simple'); + +CREATE STORAGE USER MAPPING FOR CURRENT_ROLE STORAGE SERVER oss_server2 +OPTIONS (accesskey 'EQEJIOJFAKQWESQEJIWQ', secretkey '0ADQiAxcaUJ2lMHipis80hsUEhdiqui82JhduOKE'); + +CREATE STORAGE USER MAPPING FOR CURRENT_USER STORAGE SERVER oss_server2 +OPTIONS (accesskey 'KGFQWEFQQEFXVAEAWLLC', secretkey '0SJIWiIATh6jOlmAKr8DGq6hOAGBI1BnsnvgJmTs'); -- fail + +CREATE STORAGE USER MAPPING FOR CURRENT_ROLE STORAGE SERVER oss_server3 +OPTIONS (accesskey 'EQEJIOJFAKQWESQEJIWQ', secretkey '0ADQiAxcaUJ2lMHipis80hsUEhdiqui82JhduOKE'); + +CREATE STORAGE USER MAPPING FOR CURRENT_USER STORAGE SERVER oss_not_exits; -- fail + +CREATE STORAGE USER MAPPING FOR CURRENT_USER STORAGE SERVER oss_not_exits +OPTIONS (accesskey 'KGFQWEFQQEFXVAEAWLLC', secretkey '0SJIWiIATh6jOlmAKr8DGq6hOAGBI1BnsnvgJmTs'); -- fail + +CREATE STORAGE USER MAPPING FOR test_dirtable1 STORAGE SERVER oss_server1; + +CREATE STORAGE USER MAPPING FOR test_dirtable1 STORAGE SERVER oss_server1 +OPTIONS (accesskey 'EQEJIOJFAKQWESQEJIWQ', secretkey '7KieQKdu02jHEUEjsqUYE83mx9OE2kdj2SJ72h6H'); -- fail + +CREATE STORAGE USER MAPPING FOR test_dirtable1 STORAGE SERVER oss_server2 +OPTIONS (accesskey 'EQEJIOJFAKQWESQEJIWQ', secretkey '7KieQKdu02jHEUEjsqUYE83mx9OE2kdj2SJ72h6H'); + +CREATE STORAGE USER MAPPING FOR test_dirtable1 STORAGE SERVER oss_server3 +OPTIONS (accesskey 'EQEJIOJFAKQWESQEJIWQ', secretkey '7KieQKdu02jHEUEjsqUYE83mx9OE2kdj2SJ72h6H'); + +CREATE STORAGE USER MAPPING FOR no_exist_user STORAGE SERVER oss_server1; -- fail + +CREATE STORAGE USER MAPPING FOR no_exist_user STORAGE SERVER oss_server1 +OPTIONS (accesskey 'EQEJIOJFAKQWESQEJIWQ', secretkey '7KieQKdu02jHEUEjsqUYE83mx9OE2kdj2SJ72h6H'); -- fail + +CREATE STORAGE USER MAPPING IF NOT EXISTS FOR CURRENT_USER STORAGE SERVER oss_server1 +OPTIONS (accesskey 'KGFQWEFQQEFXVAEAWLLC', secretkey '0SJIWiIATh6jOlmAKr8DGq6hOAGBI1BnsnvgJmTs'); -- skip + +CREATE STORAGE USER MAPPING IF NOT EXISTS FOR test_dirtable2 STORAGE SERVER oss_server3 +OPTIONS (endpoint '127.0.0.1:6555'); + +CREATE STORAGE USER MAPPING IF NOT EXISTS FOR test_dirtable3 STORAGE SERVER oss_server8 +OPTIONS (auth_method 'simple'); + +CREATE STORAGE USER MAPPING IF NOT EXISTS FOR no_exist_user STORAGE SERVER oss_server1; -- fail + +SELECT umoptions FROM gp_storage_user_mapping ORDER BY 1; +\c dirtable_db +SELECT umoptions FROM gp_storage_user_mapping ORDER BY 1; +\c regression + +-- Test ALTER STORAGE USER MAPPING +ALTER STORAGE USER MAPPING FOR CURRENT_USER STORAGE SERVER oss_server1; -- fail + +ALTER STORAGE USER MAPPING FOR CURRENT_USER STORAGE SERVER oss_server1 +OPTIONS (accesskey 'KGFQWEFQQEFXVAEAWLLC', secretkey '0SJIWiIATh6jOlmAKr8DGq6hOAGBI1BnsnvgJmTs'); + +ALTER STORAGE USER MAPPING FOR CURRENT_ROLE STORAGE SERVER oss_server1 +OPTIONS (accesskey 'EQEJIOJFAKQWESQEJIWQ'); -- fail + +ALTER STORAGE USER MAPPING FOR CURRENT_USER STORAGE SERVER oss_server1 +OPTIONS (auth_method 'simple'); + +ALTER STORAGE USER MAPPING FOR CURRENT_USER STORAGE SERVER oss_server2 +OPTIONS (accesskey 'EQEJIOJFAKQWESQEJIWQ', secretkey '0ADQiAxcaUJ2lMHipis80hsUEhdiqui82JhduOKE'); -- fail + +ALTER STORAGE USER MAPPING IF EXISTS FOR CURRENT_USER STORAGE SERVER server_not_exists +OPTIONS (accesskey 'EQEJIOJFAKQWESQEJIWQ', secretkey '0ADQiAxcaUJ2lMHipis80hsUEhdiqui82JhduOKE'); -- fail + +ALTER STORAGE USER MAPPING IF EXISTS FOR no_exist_user STORAGE SERVER oss_server1 +OPTIONS (accesskey 'EQEJIOJFAKQWESQEJIWQ', secretkey '0ADQiAxcaUJ2lMHipis80hsUEhdiqui82JhduOKE'); -- fail + +ALTER STORAGE USER MAPPING IF NOT EXISTS FOR test_dirtable1 STORAGE SERVER oss_server3 +OPTIONS (auth_method 'simple'); -- fail + +SELECT umoptions FROM gp_storage_user_mapping ORDER BY 1; +\c dirtable_db +SELECT umoptions FROM gp_storage_user_mapping ORDER BY 1; +\c regression + +-- Test DROP STORAGE USER MAPPING +DROP STORAGE USER MAPPING FOR CURRENT_USER; -- fail +DROP STORAGE USER MAPPING FOR CURRENT_USER STORAGE SERVER oss_server2; +DROP STORAGE USER MAPPING IF EXISTS FOR test_dirtable1 STORAGE SERVER oss_server1; +DROP STORAGE USER MAPPING IF EXISTS FOR test_dirtable2 STORAGE SERVER no_exist_server; +DROP STORAGE USER MAPPING FOR test_dirtable3 STORAGE SERVER no_exist_server; -- fail +DROP STORAGE USER MAPPING FOR no_exist_user STORAGE SERVER oss_server1; -- fail +DROP STORAGE USER MAPPING IF EXISTS FOR no_exist_user STORAGE SERVER oss_server1; -- skip + +SELECT umoptions FROM gp_storage_user_mapping ORDER BY 1; +\c dirtable_db +SELECT umoptions FROM gp_storage_user_mapping ORDER BY 1; +\c regression + +-- Test DROP STOARGE SERVER +DROP STORAGE SERVER oss_server1; -- fail +DROP STORAGE SERVER oss_server2; -- fail +DROP STORAGE SERVER oss_server3; -- fail +DROP STORAGE SERVER oss_server4; -- fail +DROP STORAGE SERVER oss_server8; -- fail +DROP STORAGE SERVER oss_server9; -- fail +DROP STAROGE SERVER IF EXISTS oss_server9; -- fail +DROP STORAGE SERVER IF NOT EXISTS oss_server9; --fail +DROP STORAGE SERVER IF EXISTS oss_server10; + +SELECT srvname, srvacl, srvoptions from gp_storage_server ORDER BY 1; +\c dirtable_db +SELECT srvname, srvacl, srvoptions from gp_storage_server ORDER BY 1; +\c regression + +-- Test directory table +-- Test CREATE DIRECTORY TABLE +SELECT count(*) FROM pg_directory_table; +SELECT relname, relisshared, relpersistence, relkind FROM pg_class WHERE relname like '%dir_table%' ORDER BY 1; + +CREATE DIRECTORY TABLE dir_table1; +CREATE DIRECTORY TABLE dir_table2 TABLESPACE directory_tblspc; +CREATE DIRECTORY TABLE dir_table3 TABLESPACE directory_tblspc DISTRIBUTED BY(relative_path); -- fail +CREATE DIRECTORY TABLE dir_table3 TABLESPACE directory_tblspc DISTRIBUTED RANDOMLY; -- fail +CREATE DIRECTORY TABLE dir_table3 TABLESPACE directory_tblspc DISTRIBUTED REPLICATED; -- fail +CREATE DIRECTORY TABLE dir_table3 TABLESPACE directory_tblspc; +CREATE DIRECTORY TABLE IF NOT EXISTS dir_table4 TABLESPACE directory_tblspc; +CREATE DIRECTORY TABLE IF NOT EXISTS dir_table2 TABLESPACE directory_tblspc; -- fail +CREATE DIRECTORY TABLE dir_table5 TABLESPACE directory_tblspc; +CREATE DIRECTORY TABLE dir_table6 TABLESPACE pg_default; + +\dY +SELECT count(*) FROM pg_directory_table; +SELECT relname, relisshared, relpersistence, relkind FROM pg_class WHERE relname like '%dir_table%' ORDER BY 1; +\d+ dir_table1; +\d+ dir_table2; +\d+ dir_table3; +\c dirtable_db +\dY +SELECT count(*) FROM pg_directory_table; +SELECT relname, relisshared, relpersistence, relkind FROM pg_class WHERE relname like '%dir_table%' ORDER BY 1; +\c regression + +-- Test create table inherits directory table +CREATE TABLE test_inherits1 INHERITS(dir_table1); -- fail +CREATE TABLE test_inherits2(a int) INHERITS(dir_table2); -- fail +CREATE TABLE test_inherits3 INHERITS(dir_table2, dir_table3); -- fail +CREATE TABLE test_inherits4(b text) INHERITS(dir_table1, dir_table2); -- fail + +-- Test DROP DIRECTORY TABLE +DROP DIRECTORY TABLE dir_table4; +DROP DIRECTORY TABLE dir_table4; -- fail +DROP DIRECTORY TABLE IF EXISTS dir_table5; +DROP DIRECTORY TABLE IF EXISTS dir_table5; -- skip + +\dY +SELECT count(*) FROM pg_directory_table; +SELECT relname, relisshared, relpersistence, relkind FROM pg_class WHERE relname like '%dir_table%' ORDER BY 1; +\c dirtable_db +\dY +SELECT count(*) FROM pg_directory_table; +SELECT relname, relisshared, relpersistence, relkind FROM pg_class WHERE relname like '%dir_table%' ORDER BY 1; +\c regression + +-- Test CREATE/DROP/REINDEX on DIRECTORY SCHEMA TABLE +-- Test CREATE INDEX on DIRECTORY SCHEMA TABLE +CREATE INDEX dirtable1_relative_path_idx on dir_table1(relative_path); -- fail +CREATE INDEX dirtable1_size_idx on dir_table1(size); -- fail +CREATE INDEX dirtable1_last_modified_idx on dir_table1(last_modified); -- fail +CREATE INDEX dirtable1_md5_idx on dir_table1(md5); -- fail +CREATE INDEX dirtable1_tag_idx on dir_table1(tag); -- fail +\d+ dir_table1; + +-- Test DROP INDEX on DIRECTORY SCHEMA TABLE +DROP INDEX dir_table1_pkey; -- fail +DROP INDEX dir_table2_pkey; -- fail +DROP INDEX dir_table3_pkey; -- fail +DROP INDEX dir_table4_pkey; -- fail +DROP INDEX dir_table5_pkey; -- fail +DROP INDEX dir_table6_pkey; -- fail + +-- Test REINDEX on DIRECTORY SCHEMA TABLE +REINDEX INDEX dir_table1_pkey; +REINDEX INDEX dir_table2_pkey; +REINDEX INDEX dir_table3_pkey; +REINDEX INDEX dir_table4_pkey; +REINDEX INDEX dir_table5_pkey; +REINDEX INDEX dir_table6_pkey; + +REINDEX TABLE dir_table1; +REINDEX TABLE dir_table2; +REINDEX TABLE dir_table3; +REINDEX TABLE dir_table4; +REINDEX TABLE dir_table5; +REINDEX TABLE dir_table6; + +-- Test triggers +DROP FUNCTION IF EXISTS trigtest; +create function trigtest() returns trigger as $$ +begin + raise notice '% % % %', TG_TABLE_NAME, TG_OP, TG_WHEN, TG_LEVEL; + return new; +end;$$ language plpgsql; + +create trigger trigtest_b_row_tg_dirtable_1 before insert or update or delete on dir_table1 +for each row execute procedure trigtest(); +create trigger trigtest_a_row_tg_dirtable_1 after insert or update or delete on dir_table1 +for each row execute procedure trigtest(); +create trigger trigtest_b_stmt_tg_dirtable_1 before insert or update or delete on dir_table1 +for each statement execute procedure trigtest(); +create trigger trigtest_a_stmt_tg_dirtable_1 after insert or update or delete on dir_table1 +for each statement execute procedure trigtest(); + +-- Test COPY DIRECTORY TABLE syntax +SELECT relative_path, size, tag FROM dir_table1 ORDER BY 1; +SELECT relative_path, size, tag FROM dir_table2 ORDER BY 1; + +\COPY dir_table1 FROM '@abs_srcdir@/data/nation.csv'; -- fail +\COPY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation'; -- fail +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv'; -- fail +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation1'; +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation1'; -- fail +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation2' 'nation2'; -- fail +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation2'; +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation3' WITH TAG 'nation'; +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation3' WITH TAG 'nation'; -- fail +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation3' WITH TAG 'nation2'; -- fail +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation4' WITH TAG 'nation'; +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation5' WITH TAG 'nation' WITH TAG 'nation2'; -- fail +SELECT relative_path, size, tag FROM dir_table1 ORDER BY 1; +SELECT relative_path, content FROM directory_table('dir_table1') ORDER BY 1; + +COPY dir_table2 FROM '@abs_srcdir@/data/nation.csv'; -- fail +COPY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation'; -- fail +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv'; -- fail +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation1'; +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation1'; -- fail +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation2'; +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation3' WITH TAG 'nation'; +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation3' WITH TAG 'nation'; -- fail +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation3' WITH TAG 'nation2'; -- fail +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation4' WITH TAG 'nation'; +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation5' WITH TAG 'nation' WITH TAG 'nation2'; -- fail +SELECT relative_path, size, tag FROM dir_table2 ORDER BY 1; +SELECT relative_path, content FROM directory_table('dir_table2') ORDER BY 1; + +-- Test copy binary from directory table +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (format CSV); +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (freeze off); +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (freeze on); +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (delimiter ','); +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (null ' '); +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (header off); +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (header on); +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (quote ':'); +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (escape ':'); +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (force_quote (a)); +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (force_quote *); +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (force_not_null (a)); +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (force_null (a)); +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (convert_selectively (a)); +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (encoding 'sql_ascii'); + +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (format CSV); +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (freeze off); +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (freeze on); +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (delimiter ','); +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (null ' '); +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (header off); +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (header on); +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (quote ':'); +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (escape ':'); +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (force_quote (a)); +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (force_quote *); +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (force_not_null (a)); +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (force_null (a)); +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (convert_selectively (a)); +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (encoding 'sql_ascii'); + +-- Test copy file content md5 +CREATE OR REPLACE FUNCTION file_content(text, text) RETURNS BYTEA LANGUAGE SQL AS +'select content from directory_table($1) where relative_path = $2'; + +CREATE OR REPLACE FUNCTION file_md5(text, text) RETURNS TEXT LANGUAGE SQL AS +'select md5 from directory_table($1) where relative_path = $2'; + +CREATE OR REPLACE FUNCTION md5_equal(text, text) RETURNS BOOL LANGUAGE SQL AS +'SELECT md5(file_content($1, $2)) = (SELECT file_md5($1, $2))'; + +SELECT md5_equal('dir_table1', 'nation1'); +SELECT md5_equal('dir_table1', 'nation2'); +SELECT md5_equal('dir_table1', 'nation3'); +SELECT md5_equal('dir_table1', 'nation4'); + +SELECT md5_equal('dir_table2', 'nation1'); +SELECT md5_equal('dir_table2', 'nation2'); +SELECT md5_equal('dir_table2', 'nation3'); +SELECT md5_equal('dir_table2', 'nation4'); + +-- Does not support copy to +\COPY dir_table1 TO '@abs_srcdir@/data/dir_table1'; -- fail +\COPY BINARY dir_table1 TO '@abs_srcdir@/data/dir_table1'; -- fail +COPY dir_table1 TO '@abs_srcdir@/data/dir_table1'; -- fail +COPY BINARY dir_table1 TO '@abs_srcdir@/data/dir_table1'; -- fail +\COPY dir_table2 TO '@abs_srcdir@/data/dir_table2'; -- fail +\COPY BINARY dir_table2 TO '@abs_srcdir@/data/dir_table2'; -- fail +COPY dir_table2 TO '@abs_srcdir@/data/dir_table2'; -- fail +COPY BINARY dir_table2 TO '@abs_srcdir@/data/dir_table2'; -- fail +SELECT relative_path, size, tag FROM dir_table1 ORDER BY 1; +SELECT relative_path, size, tag FROM dir_table2 ORDER BY 1; + +-- Test join between two directory schema tables +ANALYZE dir_table1; +ANALYZE dir_table2; + +EXPLAIN (COSTS OFF) SELECT dir_table1.relative_path FROM dir_table1, dir_table2 +WHERE dir_table1.relative_path = dir_table2.relative_path ORDER BY 1; +SELECT dir_table1.relative_path FROM dir_table1, dir_table2 +WHERE dir_table1.relative_path = dir_table2.relative_path ORDER BY 1; + +EXPLAIN (COSTS OFF) SELECT dir_table1.relative_path FROM dir_table1, dir_table2 +WHERE dir_table1.size = dir_table2.size ORDER BY 1 LIMIT 1; +SELECT dir_table1.relative_path FROM dir_table1, dir_table2 +WHERE dir_table1.size = dir_table2.size ORDER BY 1 LIMIT 1; + +EXPLAIN (COSTS OFF) SELECT dir_table1.relative_path FROM dir_table1, dir_table2 +WHERE dir_table1.md5 = dir_table2.md5 ORDER BY 1 LIMIT 1; +SELECT dir_table1.relative_path FROM dir_table1, dir_table2 +WHERE dir_table1.md5 = dir_table2.md5 ORDER BY 1 LIMIT 1; + +EXPLAIN (COSTS OFF) SELECT dir_table1.relative_path FROM dir_table1, dir_table2 +WHERE dir_table1.tag = dir_table2.tag ORDER BY 1; +SELECT dir_table1.relative_path FROM dir_table1, dir_table2 +WHERE dir_table1.tag = dir_table2.tag ORDER BY 1; + +-- Test DML directory schema table, only allow to update tag +INSERT INTO dir_table1 VALUES('insert'); -- fail +INSERT INTO dir_table2 VALUES('insert', 512, '2000-03-21 17:13:27+08', '70f09140d1b83eb3ecf9a0e28494d2a4', 'insert'); -- fail +SELECT relative_path, size, tag FROM dir_table1 ORDER BY 1; +SELECT relative_path, size, tag FROM dir_table2 ORDER BY 1; + +DELETE FROM dir_table1; -- fail +DELETE FROM dir_table2 WHERE relative_path = 'nation1'; -- fail +SELECT relative_path, size, tag FROM dir_table1 ORDER BY 1; +SELECT relative_path, size, tag FROM dir_table2 ORDER BY 1; + +UPDATE dir_table1 SET relative_path = 'nation_updated'; -- fail +UPDATE dir_table2 SET relative_path = 'nation_updated' WHERE relative_path = 'nation2'; -- fail +UPDATE dir_table1 SET size = 512; -- fail +UPDATE dir_table2 SET size = 1024 WHERE relative_path = 'nation1'; -- fail +UPDATE dir_table1 SET last_modified = '2000-03-21 16:55:07+08'; -- fail +UPDATE dir_table2 SET last_modified = '2000-03-21 16:55:07+08' WHERE relative_path = 'nation3'; -- fail +UPDATE dir_table1 SET md5 = '70f09140d1b83eb3ecf9a0e28494d2a4'; -- fail +UPDATE dir_table2 SET md5 = '70f09140d1b83eb3ecf9a0e28494d2a4' WHERE relative_path = 'nation4'; -- fail +UPDATE dir_table1 SET tag = 'nation_new_tag'; -- ok +UPDATE dir_table1 SET tag = 'nation2_new_tag' WHERE relative_path = 'nation2'; -- ok +UPDATE dir_table2 SET tag = 'nation4_new_tag' WHERE relative_path = 'nation3'; -- ok +UPDATE dir_table1 SET tag = 'failed_tag' WHERE relative_path = 'not_exist_path'; +UPDATE dir_table2 SET tag = 'no_tag' WHERE relative_path = 'not_exist_path'; +SELECT relative_path, size, tag FROM dir_table1 ORDER BY 1; +SELECT relative_path, size, tag FROM dir_table2 ORDER BY 1; + +-- Test alter table directory schema table +ALTER TABLE dir_table1 ADD COLUMN a int; -- fail +ALTER DIRECTORY TABLE dir_table1 ADD COLUMN a int; -- fail +ALTER TABLE dir_table2 DROP COLUMN relative_path; -- fail +ALTER DIRECTORY TABLE dir_table2 DROP COLUMN relative_path; -- fail +ALTER TABLE dir_table1 RENAME TO dir_table_new; -- fail +ALTER DIRECTORY TABLE dir_table1 RENAME TO dir_table_new; -- fail +ALTER TABLE dir_table2 ADD CONSTRAINT dirtable_constraint UNIQUE (tag); -- fail +ALTER DIRECTORY TABLE dir_table2 ADD CONSTRAINT dirtable_constraint UNIQUE (tag); -- fail +ALTER TABLE dir_table1 DROP CONSTRAINT DROP CONSTRAINT test_pkey; -- fail +ALTER DIRECTORY TABLE dir_table1 DROP CONSTRAINT DROP CONSTRAINT test_pkey; -- fail + +-- Test remove_table +SELECT remove_file('dir_table1', 'nation5'); -- fail +SELECT remove_file('dir_table1', 'nation1'); +SELECT remove_file('dir_table2', 'nation1', 'nation2'); -- fail +SELECT remove_file('dir_table1', 'nation2'); +SELECT remove_file('dir_table3', 'nation1'); -- fail +SELECT remove_file('dir_table2', 'nation3'); +SELECT remove_file('dir_table1', 'nation1'); -- fail +SELECT relative_path, size, tag FROM dir_table1 ORDER BY 1; +SELECT relative_path, size, tag FROM dir_table2 ORDER BY 1; + +-- Test transaction commit of directory table manipulation +CREATE DIRECTORY TABLE dir_table4 TABLESPACE directory_tblspc; + +BEGIN; +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_commit'; +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_commit2' WITH TAG 'nation'; + +COMMIT; +SELECT relative_path, content FROM directory_table('dir_table4') ORDER BY 1; + +BEGIN; +SELECT remove_file('dir_table4', 'nation_commit'); +SELECT relative_path, content FROM directory_table('dir_table4') ORDER BY 1; +COMMIT; +SELECT relative_path, content FROM directory_table('dir_table4') ORDER BY 1; + +BEGIN; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; +UPDATE dir_table4 SET tag = 'nation_updated' WHERE relative_path = 'nation_commit2'; +COMMIT; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + +-- Test transaction rollback of directory table manipulation + +BEGIN; +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_rollback'; +SELECT relative_path, content FROM directory_table('dir_table4') ORDER BY 1; +ROLLBACK; +SELECT relative_path, content FROM directory_table('dir_table4') ORDER BY 1; + +BEGIN; +SELECT remove_file('dir_table4', 'nation_commit2'); +SELECT relative_path, content FROM directory_table('dir_table4') ORDER BY 1; +ROLLBACK; +SELECT relative_path, content FROM directory_table('dir_table4') ORDER BY 1; + +BEGIN; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_rollback2' WITH TAG 'nation'; +UPDATE dir_table4 SET tag = 'nation_updated' WHERE relative_path = 'nation_rollback2'; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; +ROLLBACK; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + +-- Test subtransaction commit of directory table manipulation +BEGIN; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_subcommit' WITH TAG 'nation'; +SAVEPOINT s1; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_subcommit2'; +SAVEPOINT s2; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_subcommit3'; +RELEASE SAVEPOINT s1; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; +COMMIT; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + +BEGIN; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; +SELECT remove_file('dir_table4', 'nation_subcommit'); +SAVEPOINT s1; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_subcommit'; +SAVEPOINT s2; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; +RELEASE SAVEPOINT s1; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; +COMMIT; + +BEGIN; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; +SELECT remove_file('dir_table4', 'nation_subcommit'); +SAVEPOINT s1; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; +SELECT remove_file('dir_table4', 'nation_subcommit2'); +SAVEPOINT s2; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; +RELEASE SAVEPOINT s2; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; +COMMIT; + +BEGIN; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; +SELECT remove_file('dir_table4', 'nation_subcommit2'); +SAVEPOINT s1; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_subcommit4'; +SAVEPOINT s2; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; +ROLLBACK TO SAVEPOINT s1; +COMMIT; + +-- Test subtransaction rollback of directory table manipulation +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_subrollback1'; +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_subrollback2'; +BEGIN; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_subrollback3'; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; +SAVEPOINT s1; +SELECT remove_file('dir_table4', 'nation_subrollback1'); +SAVEPOINT s2; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; +ROLLBACK; + +BEGIN; +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_subrollback4'; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; +SAVEPOINT s1; +SELECT remove_file('dir_table4', 'nation_subrollback4'); +SAVEPOINT s2; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; +RELEASE SAVEPOINT s1; +ROLLBACK; + +BEGIN; +SELECT remove_file('dir_table4', 'nation_subrollback2'); +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_subrollback5'; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; +SAVEPOINT s1; +SELECT remove_file('dir_table4', 'nation_subrollback5'); +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; +ROLLBACK TO SAVEPOINT s1; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_subrollback6'; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; +SAVEPOINT s2; +ROLLBACK; + +-- clean up +DROP DIRECTORY TABLE IF EXISTS dir_table1; +DROP DIRECTORY TABLE IF EXISTS dir_table2; +DROP DIRECTORY TABLE IF EXISTS dir_table3; +DROP DIRECTORY TABLE IF EXISTS dir_table4; +DROP DIRECTORY TABLE IF EXISTS dir_table5; +DROP DIRECTORY TABLE IF EXISTS dir_table6; + +DROP FUNCTION IF EXISTS trigtest; + +DROP STORAGE USER MAPPING IF EXISTS FOR CURRENT_USER STORAGE SERVER oss_server1; +DROP STORAGE USER MAPPING IF EXISTS FOR CURRENT_USER STORAGE SERVER oss_server2; +DROP STORAGE USER MAPPING IF EXISTS FOR CURRENT_USER STORAGE SERVER oss_server3; +DROP STORAGE USER MAPPING IF EXISTS FOR CURRENT_USER STORAGE SERVER oss_server4; +DROP STORAGE USER MAPPING IF EXISTS FOR test_dirtable1 STORAGE SERVER oss_server1; +DROP STORAGE USER MAPPING IF EXISTS FOR test_dirtable1 STORAGE SERVER oss_server2; +DROP STORAGE USER MAPPING IF EXISTS FOR test_dirtable1 STORAGE SERVER oss_server3; +DROP STORAGE USER MAPPING IF EXISTS FOR test_dirtable2 STORAGE SERVER oss_server3; +DROP STORAGE USER MAPPING IF EXISTS FOR test_dirtable3 STORAGE SERVER oss_server8; + +DROP STORAGE SERVER IF EXISTS oss_server1; +DROP STORAGE SERVER IF EXISTS oss_server2; +DROP STORAGE SERVER IF EXISTS oss_server3; +DROP STORAGE SERVER IF EXISTS oss_server4; +DROP STORAGE SERVER IF EXISTS oss_server5; +DROP STORAGE SERVER IF EXISTS oss_server6; +DROP STORAGE SERVER IF EXISTS oss_server7; +DROP STORAGE SERVER IF EXISTS oss_server8; +DROP STORAGE SERVER IF EXISTS oss_server9; +DROP STORAGE SERVER IF EXISTS oss_server10; +DROP STORAGE SERVER IF EXISTS oss_server11; +DROP STORAGE SERVER IF EXISTS oss_server12; +DROP STORAGE SERVER IF EXISTS oss_server13; + +SELECT srvname, srvacl, srvoptions FROM gp_storage_server; + +DROP USER test_dirtable1; +DROP USER test_dirtable2; +DROP USER test_dirtable3; +DROP USER test_dirtable4; + +DROP FUNCTION IF EXISTS file_content; +DROP FUNCTION IF EXISTS file_md5; +DROP FUNCTION IF EXISTS md5_equal; + +DROP DATABASE dirtable_db; + +DROP TRIGGER IF EXISTS trigtest_b_row_tg_dirtable_1 ON dir_table1; +DROP TRIGGER IF EXISTS trigtest_a_row_tg_dirtable_1 ON dir_table1; +DROP TRIGGER IF EXISTS trigtest_b_stmt_tg_dirtable_1 ON dir_table1; +DROP TRIGGER IF EXISTS trigtest_a_stmt_tg_dirtable_1 ON dir_table1; + +DROP TABLESPACE directory_tblspc; diff --git a/src/test/regress/output/directory_table.source b/src/test/regress/output/directory_table.source new file mode 100644 index 00000000000..196bd87b6fd --- /dev/null +++ b/src/test/regress/output/directory_table.source @@ -0,0 +1,1847 @@ +-- +-- Test for directory table +-- +-- Display pg_tablespace, pg_directory_table, gp_storage_server, gp_storage_user_mapping catalog +\d+ pg_tablespace; + Table "pg_catalog.pg_tablespace" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +-------------------+-----------+-----------+----------+---------+----------+--------------+------------- + oid | oid | | not null | | plain | | + spcname | name | | not null | | plain | | + spcowner | oid | | not null | | plain | | + spcacl | aclitem[] | | | | extended | | + spcoptions | text[] | C | | | extended | | + spcfilehandlersrc | text | C | | | extended | | + spcfilehandlerbin | text | C | | | extended | | +Indexes: + "pg_tablespace_oid_index" PRIMARY KEY, btree (oid), tablespace "pg_global" + "pg_tablespace_spcname_index" UNIQUE CONSTRAINT, btree (spcname), tablespace "pg_global" +Tablespace: "pg_global" + +\d+ pg_directory_table; + Table "pg_catalog.pg_directory_table" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------------+------+-----------+----------+---------+----------+--------------+------------- + dtrelid | oid | | not null | | plain | | + dttablespace | oid | | not null | | plain | | + dtlocation | text | C | | | extended | | +Indexes: + "pg_directory_table_relid_index" PRIMARY KEY, btree (dtrelid) + +\d+ gp_storage_server; + Table "pg_catalog.gp_storage_server" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +------------+-----------+-----------+----------+---------+----------+--------------+------------- + oid | oid | | not null | | plain | | + srvname | name | | not null | | plain | | + srvowner | oid | | not null | | plain | | + srvacl | aclitem[] | | | | extended | | + srvoptions | text[] | C | | | extended | | +Indexes: + "gp_storage_server_oid_index" PRIMARY KEY, btree (oid), tablespace "pg_global" + "gp_storage_server_name_index" UNIQUE CONSTRAINT, btree (srvname), tablespace "pg_global" +Tablespace: "pg_global" + +\d+ gp_storage_user_mapping; + Table "pg_catalog.gp_storage_user_mapping" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +-----------+--------+-----------+----------+---------+----------+--------------+------------- + oid | oid | | not null | | plain | | + umuser | oid | | not null | | plain | | + umserver | oid | | not null | | plain | | + umoptions | text[] | C | | | extended | | +Indexes: + "gp_storage_user_mapping_oid_index" PRIMARY KEY, btree (oid), tablespace "pg_global" + "gp_storage_user_mapping_server_index" UNIQUE CONSTRAINT, btree (umuser, umserver), tablespace "pg_global" +Tablespace: "pg_global" + +SELECT relname, relisshared, relpersistence, relkind FROM pg_class WHERE relname = 'pg_directory_table'; + relname | relisshared | relpersistence | relkind +--------------------+-------------+----------------+--------- + pg_directory_table | f | p | r +(1 row) + +SELECT relname, relisshared, relpersistence, relkind FROM pg_class WHERE relname = 'gp_storage_server'; + relname | relisshared | relpersistence | relkind +-------------------+-------------+----------------+--------- + gp_storage_server | t | p | r +(1 row) + +SELECT relname, relisshared, relpersistence, relkind FROM pg_class WHERE relname = 'gp_storage_user_mapping'; + relname | relisshared | relpersistence | relkind +-------------------------+-------------+----------------+--------- + gp_storage_user_mapping | t | p | r +(1 row) + +-- CREATE TABLESPACE +CREATE TABLESPACE directory_tblspc LOCATION '@testtablespace@'; +-- CREATE DATABASE +CREATE DATABASE dirtable_db; +\c dirtable_db +\d+ pg_directory_table; + Table "pg_catalog.pg_directory_table" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------------+------+-----------+----------+---------+----------+--------------+------------- + dtrelid | oid | | not null | | plain | | + dttablespace | oid | | not null | | plain | | + dtlocation | text | C | | | extended | | +Indexes: + "pg_directory_table_relid_index" PRIMARY KEY, btree (dtrelid) + +\d+ gp_storage_server; + Table "pg_catalog.gp_storage_server" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +------------+-----------+-----------+----------+---------+----------+--------------+------------- + oid | oid | | not null | | plain | | + srvname | name | | not null | | plain | | + srvowner | oid | | not null | | plain | | + srvacl | aclitem[] | | | | extended | | + srvoptions | text[] | C | | | extended | | +Indexes: + "gp_storage_server_oid_index" PRIMARY KEY, btree (oid), tablespace "pg_global" + "gp_storage_server_name_index" UNIQUE CONSTRAINT, btree (srvname), tablespace "pg_global" +Tablespace: "pg_global" + +\d+ gp_storage_user_mapping; + Table "pg_catalog.gp_storage_user_mapping" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +-----------+--------+-----------+----------+---------+----------+--------------+------------- + oid | oid | | not null | | plain | | + umuser | oid | | not null | | plain | | + umserver | oid | | not null | | plain | | + umoptions | text[] | C | | | extended | | +Indexes: + "gp_storage_user_mapping_oid_index" PRIMARY KEY, btree (oid), tablespace "pg_global" + "gp_storage_user_mapping_server_index" UNIQUE CONSTRAINT, btree (umuser, umserver), tablespace "pg_global" +Tablespace: "pg_global" + +SELECT relname, relisshared, relpersistence, relkind FROM pg_class WHERE relname = 'pg_directory_table'; + relname | relisshared | relpersistence | relkind +--------------------+-------------+----------------+--------- + pg_directory_table | f | p | r +(1 row) + +SELECT relname, relisshared, relpersistence, relkind FROM pg_class WHERE relname = 'gp_storage_server'; + relname | relisshared | relpersistence | relkind +-------------------+-------------+----------------+--------- + gp_storage_server | t | p | r +(1 row) + +SELECT relname, relisshared, relpersistence, relkind FROM pg_class WHERE relname = 'gp_storage_user_mapping'; + relname | relisshared | relpersistence | relkind +-------------------------+-------------+----------------+--------- + gp_storage_user_mapping | t | p | r +(1 row) + +\c regression +-- CREATE USER for directory table +CREATE USER test_dirtable1; +NOTICE: resource queue required -- using default resource queue "pg_default" +CREATE USER test_dirtable2; +NOTICE: resource queue required -- using default resource queue "pg_default" +CREATE USER test_dirtable3; +NOTICE: resource queue required -- using default resource queue "pg_default" +CREATE USER test_dirtable4; +NOTICE: resource queue required -- using default resource queue "pg_default" +-- Test CREATE STORAGE SERVER +SELECT srvname, srvacl, srvoptions from gp_storage_server ORDER BY 1; + srvname | srvacl | srvoptions +---------+--------+------------ +(0 rows) + +CREATE STORAGE SERVER oss_server1; +CREATE STORAGE SERVER oss_server2 OPTIONS(protocal 'localhost'); +CREATE STORAGE SERVER oss_server3 OPTIONS(endpoint '127.0.0.1:9000'); +CREATE STORAGE SERVER oss_server4 OPTIONS(https 'true'); +CREATE STORAGE SERVER oss_server5 OPTIONS(virtual_host 'false'); +CREATE STORAGE SERVER oss_server6 OPTIONS(protocol 'qingstor', endpoint 'pek3b,qingstor.com'); +CREATE STORAGE SERVER oss_server7 OPTIONS(https 'false', virtual_host 'true'); +CREATE STORAGE SERVER oss_server8 OPTIONS(protocol 'hdfs', namenode '127.0.0.1:8020'); +CREATE STORAGE SERVER oss_server9 OWNER TO postgres; -- fail +ERROR: syntax error at or near "OWNER" +LINE 1: CREATE STORAGE SERVER oss_server9 OWNER TO postgres; + ^ +CREATE STORAGE SERVER IF NOT EXISTS oss_server10; +CREATE STORAGE SERVER IF NOT EXISTS oss_server11 OPTIONS(protocol 's3av2'); +CREATE STORAGE SERVER IF NOT EXISTS oss_server12 OPTIONS(protocol 's3av2', endpoint '127.0.0.1:9000', https 'false'); +CREATE STORAGE SERVER IF NOT EXISTS oss_server13 OWNER TO postgres; -- fail +ERROR: syntax error at or near "OWNER" +LINE 1: CREATE STORAGE SERVER IF NOT EXISTS oss_server13 OWNER TO po... + ^ +SELECT srvname, srvacl, srvoptions from gp_storage_server ORDER BY 1; + srvname | srvacl | srvoptions +--------------+--------+------------------------------------------------------ + oss_server1 | | + oss_server10 | | + oss_server11 | | {protocol=s3av2} + oss_server12 | | {protocol=s3av2,endpoint=127.0.0.1:9000,https=false} + oss_server2 | | {protocal=localhost} + oss_server3 | | {endpoint=127.0.0.1:9000} + oss_server4 | | {https=true} + oss_server5 | | {virtual_host=false} + oss_server6 | | {protocol=qingstor,"endpoint=pek3b,qingstor.com"} + oss_server7 | | {https=false,virtual_host=true} + oss_server8 | | {protocol=hdfs,namenode=127.0.0.1:8020} +(11 rows) + +\c dirtable_db +SELECT srvname, srvacl, srvoptions from gp_storage_server ORDER BY 1; + srvname | srvacl | srvoptions +--------------+--------+------------------------------------------------------ + oss_server1 | | + oss_server10 | | + oss_server11 | | {protocol=s3av2} + oss_server12 | | {protocol=s3av2,endpoint=127.0.0.1:9000,https=false} + oss_server2 | | {protocal=localhost} + oss_server3 | | {endpoint=127.0.0.1:9000} + oss_server4 | | {https=true} + oss_server5 | | {virtual_host=false} + oss_server6 | | {protocol=qingstor,"endpoint=pek3b,qingstor.com"} + oss_server7 | | {https=false,virtual_host=true} + oss_server8 | | {protocol=hdfs,namenode=127.0.0.1:8020} +(11 rows) + +\c regression +-- Test ALTER STORAGE SERVER +ALTER STORAGE SERVER oss_server1 OPTIONS(protocol 'aws'); +ALTER STORAGE SERVER oss_server1 OPTIONS(protocol 'test'); -- fail +ERROR: option "protocol" provided more than once +ALTER STORAGE SERVER oss_server2 OPTIONS(https 'true'); +ALTER STORAGE SERVER oss_server2 OPTIONS(https 'false', virtual_host 'true'); -- fail +ERROR: option "https" provided more than once +ALTER STORAGE SERVER oss_server2 OPTIONS(virtual_host 'true'); +ALTER STORAGE SERVER oss_server3 OPTIONS(endpoint '192.168.0.1'); -- fail +ERROR: option "endpoint" provided more than once +ALTER STORAGE SERVER oss_server4 OPTIONS(protocol 'localhost', virtual_host 'true'); +ALTER STORAGE SERVER oss_server4 OPTIONS(protocol 'qingstor'); -- fail +ERROR: option "protocol" provided more than once +ALTER STORAGE SERVER oss_server5; -- fail +ERROR: syntax error at or near ";" +LINE 1: ALTER STORAGE SERVER oss_server5; + ^ +ALTER STORAGE SERVER oss_server6 OWNER TO postgres; -- fail +ERROR: syntax error at or near "OWNER" +LINE 1: ALTER STORAGE SERVER oss_server6 OWNER TO postgres; + ^ +ALTER STORAGE SERVER IF EXISTS oss_server7 OPTIONS(endpoint '127.0.0.1:6555'); -- fail +ERROR: syntax error at or near "EXISTS" +LINE 1: ALTER STORAGE SERVER IF EXISTS oss_server7 OPTIONS(endpoint ... + ^ +ALTER STORAGE SERVER IF NOT EXISTS oss_server8 OPTIONS(virtual_host 'true'); -- fail +ERROR: syntax error at or near "NOT" +LINE 1: ALTER STORAGE SERVER IF NOT EXISTS oss_server8 OPTIONS(virtu... + ^ +SELECT srvname, srvacl, srvoptions from gp_storage_server ORDER BY 1; + srvname | srvacl | srvoptions +--------------+--------+------------------------------------------------------ + oss_server1 | | {protocol=aws} + oss_server10 | | + oss_server11 | | {protocol=s3av2} + oss_server12 | | {protocol=s3av2,endpoint=127.0.0.1:9000,https=false} + oss_server2 | | {protocal=localhost,https=true,virtual_host=true} + oss_server3 | | {endpoint=127.0.0.1:9000} + oss_server4 | | {https=true,protocol=localhost,virtual_host=true} + oss_server5 | | {virtual_host=false} + oss_server6 | | {protocol=qingstor,"endpoint=pek3b,qingstor.com"} + oss_server7 | | {https=false,virtual_host=true} + oss_server8 | | {protocol=hdfs,namenode=127.0.0.1:8020} +(11 rows) + +\c dirtable_db +SELECT srvname, srvacl, srvoptions from gp_storage_server ORDER BY 1; + srvname | srvacl | srvoptions +--------------+--------+------------------------------------------------------ + oss_server1 | | {protocol=aws} + oss_server10 | | + oss_server11 | | {protocol=s3av2} + oss_server12 | | {protocol=s3av2,endpoint=127.0.0.1:9000,https=false} + oss_server2 | | {protocal=localhost,https=true,virtual_host=true} + oss_server3 | | {endpoint=127.0.0.1:9000} + oss_server4 | | {https=true,protocol=localhost,virtual_host=true} + oss_server5 | | {virtual_host=false} + oss_server6 | | {protocol=qingstor,"endpoint=pek3b,qingstor.com"} + oss_server7 | | {https=false,virtual_host=true} + oss_server8 | | {protocol=hdfs,namenode=127.0.0.1:8020} +(11 rows) + +\c regression +-- Test CREATE STORAGE USER MAPPING +CREATE STORAGE USER MAPPING FOR CURRENT_USER; -- fail +ERROR: syntax error at or near ";" +LINE 1: CREATE STORAGE USER MAPPING FOR CURRENT_USER; + ^ +CREATE STORAGE USER MAPPING FOR CURRENT_USER STORAGE SERVER oss_server1; +CREATE STORAGE USER MAPPING FOR CURRENT_USER STORAGE SERVER oss_server1 +OPTIONS (accesskey 'KGFQWEFQQEFXVAEAWLLC', secretkey '0SJIWiIATh6jOlmAKr8DGq6hOAGBI1BnsnvgJmTs'); -- fail +ERROR: storage user mapping for "gpadmin" already exists for storage server "oss_server1" +CREATE STORAGE USER MAPPING IF NOT EXISTS FOR CURRENT_USER STORAGE SERVER oss_server1; +NOTICE: storage user mapping for "gpadmin" already exists for storage server "oss_server1", skipping +CREATE STORAGE USER MAPPING IF NOT EXISTS FOR CURRENT_USER STORAGE SERVER oss_server1 +OPTIONS (auth_method 'simple'); +NOTICE: storage user mapping for "gpadmin" already exists for storage server "oss_server1", skipping +CREATE STORAGE USER MAPPING FOR CURRENT_ROLE STORAGE SERVER oss_server2 +OPTIONS (accesskey 'EQEJIOJFAKQWESQEJIWQ', secretkey '0ADQiAxcaUJ2lMHipis80hsUEhdiqui82JhduOKE'); +CREATE STORAGE USER MAPPING FOR CURRENT_USER STORAGE SERVER oss_server2 +OPTIONS (accesskey 'KGFQWEFQQEFXVAEAWLLC', secretkey '0SJIWiIATh6jOlmAKr8DGq6hOAGBI1BnsnvgJmTs'); -- fail +ERROR: storage user mapping for "gpadmin" already exists for storage server "oss_server2" +CREATE STORAGE USER MAPPING FOR CURRENT_ROLE STORAGE SERVER oss_server3 +OPTIONS (accesskey 'EQEJIOJFAKQWESQEJIWQ', secretkey '0ADQiAxcaUJ2lMHipis80hsUEhdiqui82JhduOKE'); +CREATE STORAGE USER MAPPING FOR CURRENT_USER STORAGE SERVER oss_not_exits; -- fail +ERROR: server "oss_not_exits" does not exist +CREATE STORAGE USER MAPPING FOR CURRENT_USER STORAGE SERVER oss_not_exits +OPTIONS (accesskey 'KGFQWEFQQEFXVAEAWLLC', secretkey '0SJIWiIATh6jOlmAKr8DGq6hOAGBI1BnsnvgJmTs'); -- fail +ERROR: server "oss_not_exits" does not exist +CREATE STORAGE USER MAPPING FOR test_dirtable1 STORAGE SERVER oss_server1; +CREATE STORAGE USER MAPPING FOR test_dirtable1 STORAGE SERVER oss_server1 +OPTIONS (accesskey 'EQEJIOJFAKQWESQEJIWQ', secretkey '7KieQKdu02jHEUEjsqUYE83mx9OE2kdj2SJ72h6H'); -- fail +ERROR: storage user mapping for "test_dirtable1" already exists for storage server "oss_server1" +CREATE STORAGE USER MAPPING FOR test_dirtable1 STORAGE SERVER oss_server2 +OPTIONS (accesskey 'EQEJIOJFAKQWESQEJIWQ', secretkey '7KieQKdu02jHEUEjsqUYE83mx9OE2kdj2SJ72h6H'); +CREATE STORAGE USER MAPPING FOR test_dirtable1 STORAGE SERVER oss_server3 +OPTIONS (accesskey 'EQEJIOJFAKQWESQEJIWQ', secretkey '7KieQKdu02jHEUEjsqUYE83mx9OE2kdj2SJ72h6H'); +CREATE STORAGE USER MAPPING FOR no_exist_user STORAGE SERVER oss_server1; -- fail +ERROR: role "no_exist_user" does not exist +CREATE STORAGE USER MAPPING FOR no_exist_user STORAGE SERVER oss_server1 +OPTIONS (accesskey 'EQEJIOJFAKQWESQEJIWQ', secretkey '7KieQKdu02jHEUEjsqUYE83mx9OE2kdj2SJ72h6H'); -- fail +ERROR: role "no_exist_user" does not exist +CREATE STORAGE USER MAPPING IF NOT EXISTS FOR CURRENT_USER STORAGE SERVER oss_server1 +OPTIONS (accesskey 'KGFQWEFQQEFXVAEAWLLC', secretkey '0SJIWiIATh6jOlmAKr8DGq6hOAGBI1BnsnvgJmTs'); -- skip +NOTICE: storage user mapping for "gpadmin" already exists for storage server "oss_server1", skipping +CREATE STORAGE USER MAPPING IF NOT EXISTS FOR test_dirtable2 STORAGE SERVER oss_server3 +OPTIONS (endpoint '127.0.0.1:6555'); +CREATE STORAGE USER MAPPING IF NOT EXISTS FOR test_dirtable3 STORAGE SERVER oss_server8 +OPTIONS (auth_method 'simple'); +CREATE STORAGE USER MAPPING IF NOT EXISTS FOR no_exist_user STORAGE SERVER oss_server1; -- fail +ERROR: role "no_exist_user" does not exist +SELECT umoptions FROM gp_storage_user_mapping ORDER BY 1; + umoptions +------------------------------------------------------------------------------------- + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=0ADQiAxcaUJ2lMHipis80hsUEhdiqui82JhduOKE} + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=0ADQiAxcaUJ2lMHipis80hsUEhdiqui82JhduOKE} + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=7KieQKdu02jHEUEjsqUYE83mx9OE2kdj2SJ72h6H} + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=7KieQKdu02jHEUEjsqUYE83mx9OE2kdj2SJ72h6H} + {auth_method=simple} + {endpoint=127.0.0.1:6555} + + +(8 rows) + +\c dirtable_db +SELECT umoptions FROM gp_storage_user_mapping ORDER BY 1; + umoptions +------------------------------------------------------------------------------------- + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=0ADQiAxcaUJ2lMHipis80hsUEhdiqui82JhduOKE} + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=0ADQiAxcaUJ2lMHipis80hsUEhdiqui82JhduOKE} + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=7KieQKdu02jHEUEjsqUYE83mx9OE2kdj2SJ72h6H} + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=7KieQKdu02jHEUEjsqUYE83mx9OE2kdj2SJ72h6H} + {auth_method=simple} + {endpoint=127.0.0.1:6555} + + +(8 rows) + +\c regression +-- Test ALTER STORAGE USER MAPPING +ALTER STORAGE USER MAPPING FOR CURRENT_USER STORAGE SERVER oss_server1; -- fail +ERROR: syntax error at or near ";" +LINE 1: ...GE USER MAPPING FOR CURRENT_USER STORAGE SERVER oss_server1; + ^ +ALTER STORAGE USER MAPPING FOR CURRENT_USER STORAGE SERVER oss_server1 +OPTIONS (accesskey 'KGFQWEFQQEFXVAEAWLLC', secretkey '0SJIWiIATh6jOlmAKr8DGq6hOAGBI1BnsnvgJmTs'); +ALTER STORAGE USER MAPPING FOR CURRENT_ROLE STORAGE SERVER oss_server1 +OPTIONS (accesskey 'EQEJIOJFAKQWESQEJIWQ'); -- fail +ERROR: option "accesskey" provided more than once +ALTER STORAGE USER MAPPING FOR CURRENT_USER STORAGE SERVER oss_server1 +OPTIONS (auth_method 'simple'); +ALTER STORAGE USER MAPPING FOR CURRENT_USER STORAGE SERVER oss_server2 +OPTIONS (accesskey 'EQEJIOJFAKQWESQEJIWQ', secretkey '0ADQiAxcaUJ2lMHipis80hsUEhdiqui82JhduOKE'); -- fail +ERROR: option "accesskey" provided more than once +ALTER STORAGE USER MAPPING IF EXISTS FOR CURRENT_USER STORAGE SERVER server_not_exists +OPTIONS (accesskey 'EQEJIOJFAKQWESQEJIWQ', secretkey '0ADQiAxcaUJ2lMHipis80hsUEhdiqui82JhduOKE'); -- fail +ERROR: syntax error at or near "IF" +LINE 1: ALTER STORAGE USER MAPPING IF EXISTS FOR CURRENT_USER STORAG... + ^ +ALTER STORAGE USER MAPPING IF EXISTS FOR no_exist_user STORAGE SERVER oss_server1 +OPTIONS (accesskey 'EQEJIOJFAKQWESQEJIWQ', secretkey '0ADQiAxcaUJ2lMHipis80hsUEhdiqui82JhduOKE'); -- fail +ERROR: syntax error at or near "IF" +LINE 1: ALTER STORAGE USER MAPPING IF EXISTS FOR no_exist_user STORA... + ^ +ALTER STORAGE USER MAPPING IF NOT EXISTS FOR test_dirtable1 STORAGE SERVER oss_server3 +OPTIONS (auth_method 'simple'); -- fail +ERROR: syntax error at or near "IF" +LINE 1: ALTER STORAGE USER MAPPING IF NOT EXISTS FOR test_dirtable1 ... + ^ +SELECT umoptions FROM gp_storage_user_mapping ORDER BY 1; + umoptions +-------------------------------------------------------------------------------------------------------- + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=0ADQiAxcaUJ2lMHipis80hsUEhdiqui82JhduOKE} + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=0ADQiAxcaUJ2lMHipis80hsUEhdiqui82JhduOKE} + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=7KieQKdu02jHEUEjsqUYE83mx9OE2kdj2SJ72h6H} + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=7KieQKdu02jHEUEjsqUYE83mx9OE2kdj2SJ72h6H} + {accesskey=KGFQWEFQQEFXVAEAWLLC,secretkey=0SJIWiIATh6jOlmAKr8DGq6hOAGBI1BnsnvgJmTs,auth_method=simple} + {auth_method=simple} + {endpoint=127.0.0.1:6555} + +(8 rows) + +\c dirtable_db +SELECT umoptions FROM gp_storage_user_mapping ORDER BY 1; + umoptions +-------------------------------------------------------------------------------------------------------- + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=0ADQiAxcaUJ2lMHipis80hsUEhdiqui82JhduOKE} + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=0ADQiAxcaUJ2lMHipis80hsUEhdiqui82JhduOKE} + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=7KieQKdu02jHEUEjsqUYE83mx9OE2kdj2SJ72h6H} + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=7KieQKdu02jHEUEjsqUYE83mx9OE2kdj2SJ72h6H} + {accesskey=KGFQWEFQQEFXVAEAWLLC,secretkey=0SJIWiIATh6jOlmAKr8DGq6hOAGBI1BnsnvgJmTs,auth_method=simple} + {auth_method=simple} + {endpoint=127.0.0.1:6555} + +(8 rows) + +\c regression +-- Test DROP STORAGE USER MAPPING +DROP STORAGE USER MAPPING FOR CURRENT_USER; -- fail +ERROR: syntax error at or near ";" +LINE 1: DROP STORAGE USER MAPPING FOR CURRENT_USER; + ^ +DROP STORAGE USER MAPPING FOR CURRENT_USER STORAGE SERVER oss_server2; +DROP STORAGE USER MAPPING IF EXISTS FOR test_dirtable1 STORAGE SERVER oss_server1; +DROP STORAGE USER MAPPING IF EXISTS FOR test_dirtable2 STORAGE SERVER no_exist_server; +NOTICE: storage server "no_exist_server" does not exist, skipping +DROP STORAGE USER MAPPING FOR test_dirtable3 STORAGE SERVER no_exist_server; -- fail +ERROR: storage server "no_exist_server" does not exist +DROP STORAGE USER MAPPING FOR no_exist_user STORAGE SERVER oss_server1; -- fail +ERROR: role "no_exist_user" does not exist +DROP STORAGE USER MAPPING IF EXISTS FOR no_exist_user STORAGE SERVER oss_server1; -- skip +NOTICE: role "no_exist_user" does not exist, skipping +SELECT umoptions FROM gp_storage_user_mapping ORDER BY 1; + umoptions +-------------------------------------------------------------------------------------------------------- + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=0ADQiAxcaUJ2lMHipis80hsUEhdiqui82JhduOKE} + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=7KieQKdu02jHEUEjsqUYE83mx9OE2kdj2SJ72h6H} + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=7KieQKdu02jHEUEjsqUYE83mx9OE2kdj2SJ72h6H} + {accesskey=KGFQWEFQQEFXVAEAWLLC,secretkey=0SJIWiIATh6jOlmAKr8DGq6hOAGBI1BnsnvgJmTs,auth_method=simple} + {auth_method=simple} + {endpoint=127.0.0.1:6555} +(6 rows) + +\c dirtable_db +SELECT umoptions FROM gp_storage_user_mapping ORDER BY 1; + umoptions +-------------------------------------------------------------------------------------------------------- + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=0ADQiAxcaUJ2lMHipis80hsUEhdiqui82JhduOKE} + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=7KieQKdu02jHEUEjsqUYE83mx9OE2kdj2SJ72h6H} + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=7KieQKdu02jHEUEjsqUYE83mx9OE2kdj2SJ72h6H} + {accesskey=KGFQWEFQQEFXVAEAWLLC,secretkey=0SJIWiIATh6jOlmAKr8DGq6hOAGBI1BnsnvgJmTs,auth_method=simple} + {auth_method=simple} + {endpoint=127.0.0.1:6555} +(6 rows) + +\c regression +-- Test DROP STOARGE SERVER +DROP STORAGE SERVER oss_server1; -- fail +ERROR: storage server "oss_server1" cannot be dropped because some objects depend on it +DETAIL: storage server of storage user mapping for gpadmin on storage server oss_server1 +DROP STORAGE SERVER oss_server2; -- fail +ERROR: storage server "oss_server2" cannot be dropped because some objects depend on it +DETAIL: storage server of storage user mapping for test_dirtable1 on storage server oss_server2 +DROP STORAGE SERVER oss_server3; -- fail +ERROR: storage server "oss_server3" cannot be dropped because some objects depend on it +DETAIL: storage server of storage user mapping for gpadmin on storage server oss_server3 +storage server of storage user mapping for test_dirtable1 on storage server oss_server3 +storage server of storage user mapping for test_dirtable2 on storage server oss_server3 +DROP STORAGE SERVER oss_server4; -- fail +DROP STORAGE SERVER oss_server8; -- fail +ERROR: storage server "oss_server8" cannot be dropped because some objects depend on it +DETAIL: storage server of storage user mapping for test_dirtable3 on storage server oss_server8 +DROP STORAGE SERVER oss_server9; -- fail +ERROR: storage server "oss_server9" not exists +DROP STAROGE SERVER IF EXISTS oss_server9; -- fail +ERROR: syntax error at or near "STAROGE" +LINE 1: DROP STAROGE SERVER IF EXISTS oss_server9; + ^ +DROP STORAGE SERVER IF NOT EXISTS oss_server9; --fail +ERROR: syntax error at or near "NOT" +LINE 1: DROP STORAGE SERVER IF NOT EXISTS oss_server9; + ^ +DROP STORAGE SERVER IF EXISTS oss_server10; +SELECT srvname, srvacl, srvoptions from gp_storage_server ORDER BY 1; + srvname | srvacl | srvoptions +--------------+--------+------------------------------------------------------ + oss_server1 | | {protocol=aws} + oss_server11 | | {protocol=s3av2} + oss_server12 | | {protocol=s3av2,endpoint=127.0.0.1:9000,https=false} + oss_server2 | | {protocal=localhost,https=true,virtual_host=true} + oss_server3 | | {endpoint=127.0.0.1:9000} + oss_server5 | | {virtual_host=false} + oss_server6 | | {protocol=qingstor,"endpoint=pek3b,qingstor.com"} + oss_server7 | | {https=false,virtual_host=true} + oss_server8 | | {protocol=hdfs,namenode=127.0.0.1:8020} +(9 rows) + +\c dirtable_db +SELECT srvname, srvacl, srvoptions from gp_storage_server ORDER BY 1; + srvname | srvacl | srvoptions +--------------+--------+------------------------------------------------------ + oss_server1 | | {protocol=aws} + oss_server11 | | {protocol=s3av2} + oss_server12 | | {protocol=s3av2,endpoint=127.0.0.1:9000,https=false} + oss_server2 | | {protocal=localhost,https=true,virtual_host=true} + oss_server3 | | {endpoint=127.0.0.1:9000} + oss_server5 | | {virtual_host=false} + oss_server6 | | {protocol=qingstor,"endpoint=pek3b,qingstor.com"} + oss_server7 | | {https=false,virtual_host=true} + oss_server8 | | {protocol=hdfs,namenode=127.0.0.1:8020} +(9 rows) + +\c regression +-- Test directory table +-- Test CREATE DIRECTORY TABLE +SELECT count(*) FROM pg_directory_table; + count +------- + 0 +(1 row) + +SELECT relname, relisshared, relpersistence, relkind FROM pg_class WHERE relname like '%dir_table%' ORDER BY 1; + relname | relisshared | relpersistence | relkind +---------+-------------+----------------+--------- +(0 rows) + +CREATE DIRECTORY TABLE dir_table1; +CREATE DIRECTORY TABLE dir_table2 TABLESPACE directory_tblspc; +CREATE DIRECTORY TABLE dir_table3 TABLESPACE directory_tblspc DISTRIBUTED BY(relative_path); -- fail +ERROR: Create directory table is not allowed to set distributed by. +LINE 1: ...TORY TABLE dir_table3 TABLESPACE directory_tblspc DISTRIBUTE... + ^ +CREATE DIRECTORY TABLE dir_table3 TABLESPACE directory_tblspc DISTRIBUTED RANDOMLY; -- fail +ERROR: Create directory table is not allowed to set distributed by. +LINE 1: ...TORY TABLE dir_table3 TABLESPACE directory_tblspc DISTRIBUTE... + ^ +CREATE DIRECTORY TABLE dir_table3 TABLESPACE directory_tblspc DISTRIBUTED REPLICATED; -- fail +ERROR: Create directory table is not allowed to set distributed by. +LINE 1: ...TORY TABLE dir_table3 TABLESPACE directory_tblspc DISTRIBUTE... + ^ +CREATE DIRECTORY TABLE dir_table3 TABLESPACE directory_tblspc; +CREATE DIRECTORY TABLE IF NOT EXISTS dir_table4 TABLESPACE directory_tblspc; +CREATE DIRECTORY TABLE IF NOT EXISTS dir_table2 TABLESPACE directory_tblspc; -- fail +NOTICE: relation "dir_table2" already exists, skipping +CREATE DIRECTORY TABLE dir_table5 TABLESPACE directory_tblspc; +CREATE DIRECTORY TABLE dir_table6 TABLESPACE pg_default; +\dY + List of relations + Schema | Name | Type | Owner +--------+------------+-----------------+--------- + public | dir_table1 | directory table | gpadmin + public | dir_table2 | directory table | gpadmin + public | dir_table3 | directory table | gpadmin + public | dir_table4 | directory table | gpadmin + public | dir_table5 | directory table | gpadmin + public | dir_table6 | directory table | gpadmin +(6 rows) + +SELECT count(*) FROM pg_directory_table; + count +------- + 6 +(1 row) + +SELECT relname, relisshared, relpersistence, relkind FROM pg_class WHERE relname like '%dir_table%' ORDER BY 1; + relname | relisshared | relpersistence | relkind +-----------------+-------------+----------------+--------- + dir_table1 | f | p | d + dir_table1_pkey | f | p | i + dir_table2 | f | p | d + dir_table2_pkey | f | p | i + dir_table3 | f | p | d + dir_table3_pkey | f | p | i + dir_table4 | f | p | d + dir_table4_pkey | f | p | i + dir_table5 | f | p | d + dir_table5_pkey | f | p | i + dir_table6 | f | p | d + dir_table6_pkey | f | p | i +(12 rows) + +\d+ dir_table1; + Directory able "public.dir_table1" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +---------------+--------------------------+-----------+----------+---------+----------+--------------+------------- + relative_path | text | | | | extended | | + size | bigint | | | | plain | | + last_modified | timestamp with time zone | | | | plain | | + md5 | text | | | | extended | | + tag | text | | | | extended | | +Indexes: + "dir_table1_pkey" PRIMARY KEY, btree (relative_path) +Distributed by: (relative_path) + +\d+ dir_table2; + Directory able "public.dir_table2" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +---------------+--------------------------+-----------+----------+---------+----------+--------------+------------- + relative_path | text | | | | extended | | + size | bigint | | | | plain | | + last_modified | timestamp with time zone | | | | plain | | + md5 | text | | | | extended | | + tag | text | | | | extended | | +Indexes: + "dir_table2_pkey" PRIMARY KEY, btree (relative_path) +Distributed by: (relative_path) + +\d+ dir_table3; + Directory able "public.dir_table3" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +---------------+--------------------------+-----------+----------+---------+----------+--------------+------------- + relative_path | text | | | | extended | | + size | bigint | | | | plain | | + last_modified | timestamp with time zone | | | | plain | | + md5 | text | | | | extended | | + tag | text | | | | extended | | +Indexes: + "dir_table3_pkey" PRIMARY KEY, btree (relative_path) +Distributed by: (relative_path) + +\c dirtable_db +\dY + List of relations + Schema | Name | Type | Owner +--------+------+------+------- +(0 rows) + +SELECT count(*) FROM pg_directory_table; + count +------- + 0 +(1 row) + +SELECT relname, relisshared, relpersistence, relkind FROM pg_class WHERE relname like '%dir_table%' ORDER BY 1; + relname | relisshared | relpersistence | relkind +---------+-------------+----------------+--------- +(0 rows) + +\c regression +-- Test create table inherits directory table +CREATE TABLE test_inherits1 INHERITS(dir_table1); -- fail +ERROR: syntax error at or near "INHERITS" +LINE 1: CREATE TABLE test_inherits1 INHERITS(dir_table1); + ^ +CREATE TABLE test_inherits2(a int) INHERITS(dir_table2); -- fail +NOTICE: table has parent, setting distribution columns to match parent table +ERROR: inherited relation "dir_table2" is not a table or foreign table +CREATE TABLE test_inherits3 INHERITS(dir_table2, dir_table3); -- fail +ERROR: syntax error at or near "INHERITS" +LINE 1: CREATE TABLE test_inherits3 INHERITS(dir_table2, dir_table3)... + ^ +CREATE TABLE test_inherits4(b text) INHERITS(dir_table1, dir_table2); -- fail +NOTICE: table has parent, setting distribution columns to match parent table +ERROR: inherited relation "dir_table1" is not a table or foreign table +-- Test DROP DIRECTORY TABLE +DROP DIRECTORY TABLE dir_table4; +DROP DIRECTORY TABLE dir_table4; -- fail +ERROR: directory table "dir_table4" does not exist +DROP DIRECTORY TABLE IF EXISTS dir_table5; +DROP DIRECTORY TABLE IF EXISTS dir_table5; -- skip +NOTICE: directory table "dir_table5" does not exist, skipping +\dY + List of relations + Schema | Name | Type | Owner +--------+------------+-----------------+--------- + public | dir_table1 | directory table | gpadmin + public | dir_table2 | directory table | gpadmin + public | dir_table3 | directory table | gpadmin + public | dir_table6 | directory table | gpadmin +(4 rows) + +SELECT count(*) FROM pg_directory_table; + count +------- + 4 +(1 row) + +SELECT relname, relisshared, relpersistence, relkind FROM pg_class WHERE relname like '%dir_table%' ORDER BY 1; + relname | relisshared | relpersistence | relkind +-----------------+-------------+----------------+--------- + dir_table1 | f | p | d + dir_table1_pkey | f | p | i + dir_table2 | f | p | d + dir_table2_pkey | f | p | i + dir_table3 | f | p | d + dir_table3_pkey | f | p | i + dir_table6 | f | p | d + dir_table6_pkey | f | p | i +(8 rows) + +\c dirtable_db +\dY + List of relations + Schema | Name | Type | Owner +--------+------+------+------- +(0 rows) + +SELECT count(*) FROM pg_directory_table; + count +------- + 0 +(1 row) + +SELECT relname, relisshared, relpersistence, relkind FROM pg_class WHERE relname like '%dir_table%' ORDER BY 1; + relname | relisshared | relpersistence | relkind +---------+-------------+----------------+--------- +(0 rows) + +\c regression +-- Test CREATE/DROP/REINDEX on DIRECTORY SCHEMA TABLE +-- Test CREATE INDEX on DIRECTORY SCHEMA TABLE +CREATE INDEX dirtable1_relative_path_idx on dir_table1(relative_path); -- fail +ERROR: Disallowed to create index on directory table "dir_table1". (indexcmds.c:709) +CREATE INDEX dirtable1_size_idx on dir_table1(size); -- fail +ERROR: Disallowed to create index on directory table "dir_table1". (indexcmds.c:709) +CREATE INDEX dirtable1_last_modified_idx on dir_table1(last_modified); -- fail +ERROR: Disallowed to create index on directory table "dir_table1". (indexcmds.c:709) +CREATE INDEX dirtable1_md5_idx on dir_table1(md5); -- fail +ERROR: Disallowed to create index on directory table "dir_table1". (indexcmds.c:709) +CREATE INDEX dirtable1_tag_idx on dir_table1(tag); -- fail +ERROR: Disallowed to create index on directory table "dir_table1". (indexcmds.c:709) +\d+ dir_table1; + Directory able "public.dir_table1" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +---------------+--------------------------+-----------+----------+---------+----------+--------------+------------- + relative_path | text | | | | extended | | + size | bigint | | | | plain | | + last_modified | timestamp with time zone | | | | plain | | + md5 | text | | | | extended | | + tag | text | | | | extended | | +Indexes: + "dir_table1_pkey" PRIMARY KEY, btree (relative_path) +Distributed by: (relative_path) + +-- Test DROP INDEX on DIRECTORY SCHEMA TABLE +DROP INDEX dir_table1_pkey; -- fail +ERROR: Disallowed to drop index "dir_table1_pkey" on directory table "dir_table1" +DROP INDEX dir_table2_pkey; -- fail +ERROR: Disallowed to drop index "dir_table2_pkey" on directory table "dir_table2" +DROP INDEX dir_table3_pkey; -- fail +ERROR: Disallowed to drop index "dir_table3_pkey" on directory table "dir_table3" +DROP INDEX dir_table4_pkey; -- fail +ERROR: index "dir_table4_pkey" does not exist +DROP INDEX dir_table5_pkey; -- fail +ERROR: index "dir_table5_pkey" does not exist +DROP INDEX dir_table6_pkey; -- fail +ERROR: Disallowed to drop index "dir_table6_pkey" on directory table "dir_table6" +-- Test REINDEX on DIRECTORY SCHEMA TABLE +REINDEX INDEX dir_table1_pkey; +REINDEX INDEX dir_table2_pkey; +REINDEX INDEX dir_table3_pkey; +REINDEX INDEX dir_table4_pkey; +ERROR: relation "dir_table4_pkey" does not exist +REINDEX INDEX dir_table5_pkey; +ERROR: relation "dir_table5_pkey" does not exist +REINDEX INDEX dir_table6_pkey; +REINDEX TABLE dir_table1; +REINDEX TABLE dir_table2; +REINDEX TABLE dir_table3; +REINDEX TABLE dir_table4; +ERROR: relation "dir_table4" does not exist +REINDEX TABLE dir_table5; +ERROR: relation "dir_table5" does not exist +REINDEX TABLE dir_table6; +-- Test triggers +DROP FUNCTION IF EXISTS trigtest; +create function trigtest() returns trigger as $$ +begin + raise notice '% % % %', TG_TABLE_NAME, TG_OP, TG_WHEN, TG_LEVEL; + return new; +end;$$ language plpgsql; +create trigger trigtest_b_row_tg_dirtable_1 before insert or update or delete on dir_table1 +for each row execute procedure trigtest(); +create trigger trigtest_a_row_tg_dirtable_1 after insert or update or delete on dir_table1 +for each row execute procedure trigtest(); +create trigger trigtest_b_stmt_tg_dirtable_1 before insert or update or delete on dir_table1 +for each statement execute procedure trigtest(); +ERROR: Triggers for statements are not yet supported +create trigger trigtest_a_stmt_tg_dirtable_1 after insert or update or delete on dir_table1 +for each statement execute procedure trigtest(); +ERROR: Triggers for statements are not yet supported +-- Test COPY DIRECTORY TABLE syntax +SELECT relative_path, size, tag FROM dir_table1 ORDER BY 1; + relative_path | size | tag +---------------+------+----- +(0 rows) + +SELECT relative_path, size, tag FROM dir_table2 ORDER BY 1; + relative_path | size | tag +---------------+------+----- +(0 rows) + +\COPY dir_table1 FROM '@abs_srcdir@/data/nation.csv'; -- fail +ERROR: Copy from directory table file name can't be null. +\COPY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation'; -- fail +ERROR: Only support copy binary from directory table. +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv'; -- fail +ERROR: Copy from directory table file name can't be null. +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation1'; +NOTICE: dir_table1 INSERT AFTER ROW (seg1 127.0.1.1:7003 pid=15072) +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation1'; -- fail +ERROR: duplicate key value violates unique constraint "dir_table1_pkey" +DETAIL: Key (relative_path)=(nation1) already exists. +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation2' 'nation2'; -- fail +ERROR: syntax error at or near "'nation2'" +LINE 1: COPY BINARY dir_table1 FROM STDIN 'nation2' 'nation2'; -- fa... + ^ +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation2'; +NOTICE: dir_table1 INSERT AFTER ROW (seg2 127.0.1.1:7004 pid=15073) +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation3' WITH TAG 'nation'; +NOTICE: dir_table1 INSERT AFTER ROW (seg1 127.0.1.1:7003 pid=15072) +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation3' WITH TAG 'nation'; -- fail +ERROR: duplicate key value violates unique constraint "dir_table1_pkey" +DETAIL: Key (relative_path)=(nation3) already exists. +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation3' WITH TAG 'nation2'; -- fail +ERROR: duplicate key value violates unique constraint "dir_table1_pkey" +DETAIL: Key (relative_path)=(nation3) already exists. +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation4' WITH TAG 'nation'; +NOTICE: dir_table1 INSERT AFTER ROW (seg2 127.0.1.1:7004 pid=15073) +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation5' WITH TAG 'nation' WITH TAG 'nation2'; -- fail +ERROR: syntax error at or near "WITH" +LINE 1: ...dir_table1 FROM STDIN 'nation5' WITH TAG 'nation' WITH TAG '... + ^ +SELECT relative_path, size, tag FROM dir_table1 ORDER BY 1; + relative_path | size | tag +---------------+------+-------- + nation1 | 2199 | + nation2 | 2199 | + nation3 | 2199 | nation + nation4 | 2199 | nation +(4 rows) + +SELECT relative_path, content FROM directory_table('dir_table1') ORDER BY 1; + relative_path | content +---------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + nation1 | \x307c414c47455249417c307c20686167676c652e206361726566756c6c792066696e616c206465706f736974732064657465637420736c796c7920616761690a317c415247454e54494e417c317c616c20666f7865732070726f6d69736520736c796c79206163636f7264696e6720746f2074686520726567756c6172206163636f756e74732e20626f6c6420726571756573747320616c6f6e0a327c4252415a494c7c317c7920616c6f6e6773696465206f66207468652070656e64696e67206465706f736974732e206361726566756c6c79207370656369616c207061636b61676573206172652061626f7574207468652069726f6e696320666f726765732e20736c796c79207370656369616c200a337c43414e4144417c317c6561732068616e672069726f6e69632c2073696c656e74207061636b616765732e20736c796c7920726567756c6172207061636b616765732061726520667572696f75736c79206f76657220746865207469746865732e20666c756666696c7920626f6c640a347c45475950547c347c792061626f766520746865206361726566756c6c7920756e757375616c207468656f646f6c697465732e2066696e616c206475676f7574732061726520717569636b6c79206163726f73732074686520667572696f75736c7920726567756c617220640a357c455448494f5049417c307c76656e207061636b616765732077616b6520717569636b6c792e20726567750a367c4652414e43457c337c726566756c6c792066696e616c2072657175657374732e20726567756c61722c2069726f6e690a377c4745524d414e597c337c6c20706c6174656c6574732e20726567756c6172206163636f756e747320782d7261793a20756e757375616c2c20726567756c6172206163636f0a387c494e4449417c327c737320657863757365732063616a6f6c6520736c796c79206163726f737320746865207061636b616765732e206465706f73697473207072696e742061726f756e0a397c494e444f4e455349417c327c20736c796c792065787072657373206173796d70746f7465732e20726567756c6172206465706f7369747320686167676c6520736c796c792e206361726566756c6c792069726f6e696320686f636b657920706c617965727320736c65657020626c697468656c792e206361726566756c6c0a31307c4952414e7c347c6566756c6c7920616c6f6e6773696465206f662074686520736c796c792066696e616c20646570656e64656e636965732e200a31317c495241517c347c6e6963206465706f7369747320626f6f73742061746f702074686520717569636b6c792066696e616c2072657175657374733f20717569636b6c7920726567756c610a31327c4a4150414e7c327c6f75736c792e2066696e616c2c20657870726573732067696674732063616a6f6c6520610a31337c4a4f5244414e7c347c6963206465706f736974732061726520626c697468656c792061626f757420746865206361726566756c6c7920726567756c61722070610a31347c4b454e59417c307c2070656e64696e67206578637573657320686167676c6520667572696f75736c79206465706f736974732e2070656e64696e672c20657870726573732070696e746f206265616e732077616b6520666c756666696c79207061737420740a31357c4d4f524f43434f7c307c726e732e20626c697468656c7920626f6c6420636f7572747320616d6f6e672074686520636c6f73656c7920726567756c6172207061636b616765732075736520667572696f75736c7920626f6c6420706c6174656c6574733f0a31367c4d4f5a414d42495155457c307c732e2069726f6e69632c20756e757375616c206173796d70746f7465732077616b6520626c697468656c7920720a31377c504552557c317c706c6174656c6574732e20626c697468656c792070656e64696e6720646570656e64656e636965732075736520666c756666696c79206163726f737320746865206576656e2070696e746f206265616e732e206361726566756c6c792073696c656e74206163636f756e0a31387c4348494e417c327c6320646570656e64656e636965732e20667572696f75736c792065787072657373206e6f746f726e697320736c65657020736c796c7920726567756c6172206163636f756e74732e20696465617320736c6565702e206465706f730a31397c524f4d414e49417c337c756c6172206173796d70746f746573206172652061626f75742074686520667572696f7573206d756c7469706c696572732e206578707265737320646570656e64656e63696573206e61672061626f7665207468652069726f6e6963616c6c792069726f6e6963206163636f756e740a32307c5341554449204152414249417c347c74732e2073696c656e7420726571756573747320686167676c652e20636c6f73656c792065787072657373207061636b6167657320736c656570206163726f73732074686520626c697468656c790a32317c564945544e414d7c327c68656c7920656e746963696e676c792065787072657373206163636f756e74732e206576656e2c2066696e616c200a32327c5255535349417c337c20726571756573747320616761696e73742074686520706c6174656c65747320757365206e65766572206163636f7264696e6720746f2074686520717569636b6c7920726567756c61722070696e740a32337c554e49544544204b494e47444f4d7c337c65616e7320626f6f7374206361726566756c6c79207370656369616c2072657175657374732e206163636f756e7473206172652e206361726566756c6c0a32347c554e49544544205354415445537c317c792066696e616c207061636b616765732e20736c6f7720666f7865732063616a6f6c6520717569636b6c792e20717569636b6c792073696c656e7420706c6174656c657473206272656163682069726f6e6963206163636f756e74732e20756e757375616c2070696e746f2062650a + nation2 | \x307c414c47455249417c307c20686167676c652e206361726566756c6c792066696e616c206465706f736974732064657465637420736c796c7920616761690a317c415247454e54494e417c317c616c20666f7865732070726f6d69736520736c796c79206163636f7264696e6720746f2074686520726567756c6172206163636f756e74732e20626f6c6420726571756573747320616c6f6e0a327c4252415a494c7c317c7920616c6f6e6773696465206f66207468652070656e64696e67206465706f736974732e206361726566756c6c79207370656369616c207061636b61676573206172652061626f7574207468652069726f6e696320666f726765732e20736c796c79207370656369616c200a337c43414e4144417c317c6561732068616e672069726f6e69632c2073696c656e74207061636b616765732e20736c796c7920726567756c6172207061636b616765732061726520667572696f75736c79206f76657220746865207469746865732e20666c756666696c7920626f6c640a347c45475950547c347c792061626f766520746865206361726566756c6c7920756e757375616c207468656f646f6c697465732e2066696e616c206475676f7574732061726520717569636b6c79206163726f73732074686520667572696f75736c7920726567756c617220640a357c455448494f5049417c307c76656e207061636b616765732077616b6520717569636b6c792e20726567750a367c4652414e43457c337c726566756c6c792066696e616c2072657175657374732e20726567756c61722c2069726f6e690a377c4745524d414e597c337c6c20706c6174656c6574732e20726567756c6172206163636f756e747320782d7261793a20756e757375616c2c20726567756c6172206163636f0a387c494e4449417c327c737320657863757365732063616a6f6c6520736c796c79206163726f737320746865207061636b616765732e206465706f73697473207072696e742061726f756e0a397c494e444f4e455349417c327c20736c796c792065787072657373206173796d70746f7465732e20726567756c6172206465706f7369747320686167676c6520736c796c792e206361726566756c6c792069726f6e696320686f636b657920706c617965727320736c65657020626c697468656c792e206361726566756c6c0a31307c4952414e7c347c6566756c6c7920616c6f6e6773696465206f662074686520736c796c792066696e616c20646570656e64656e636965732e200a31317c495241517c347c6e6963206465706f7369747320626f6f73742061746f702074686520717569636b6c792066696e616c2072657175657374733f20717569636b6c7920726567756c610a31327c4a4150414e7c327c6f75736c792e2066696e616c2c20657870726573732067696674732063616a6f6c6520610a31337c4a4f5244414e7c347c6963206465706f736974732061726520626c697468656c792061626f757420746865206361726566756c6c7920726567756c61722070610a31347c4b454e59417c307c2070656e64696e67206578637573657320686167676c6520667572696f75736c79206465706f736974732e2070656e64696e672c20657870726573732070696e746f206265616e732077616b6520666c756666696c79207061737420740a31357c4d4f524f43434f7c307c726e732e20626c697468656c7920626f6c6420636f7572747320616d6f6e672074686520636c6f73656c7920726567756c6172207061636b616765732075736520667572696f75736c7920626f6c6420706c6174656c6574733f0a31367c4d4f5a414d42495155457c307c732e2069726f6e69632c20756e757375616c206173796d70746f7465732077616b6520626c697468656c7920720a31377c504552557c317c706c6174656c6574732e20626c697468656c792070656e64696e6720646570656e64656e636965732075736520666c756666696c79206163726f737320746865206576656e2070696e746f206265616e732e206361726566756c6c792073696c656e74206163636f756e0a31387c4348494e417c327c6320646570656e64656e636965732e20667572696f75736c792065787072657373206e6f746f726e697320736c65657020736c796c7920726567756c6172206163636f756e74732e20696465617320736c6565702e206465706f730a31397c524f4d414e49417c337c756c6172206173796d70746f746573206172652061626f75742074686520667572696f7573206d756c7469706c696572732e206578707265737320646570656e64656e63696573206e61672061626f7665207468652069726f6e6963616c6c792069726f6e6963206163636f756e740a32307c5341554449204152414249417c347c74732e2073696c656e7420726571756573747320686167676c652e20636c6f73656c792065787072657373207061636b6167657320736c656570206163726f73732074686520626c697468656c790a32317c564945544e414d7c327c68656c7920656e746963696e676c792065787072657373206163636f756e74732e206576656e2c2066696e616c200a32327c5255535349417c337c20726571756573747320616761696e73742074686520706c6174656c65747320757365206e65766572206163636f7264696e6720746f2074686520717569636b6c7920726567756c61722070696e740a32337c554e49544544204b494e47444f4d7c337c65616e7320626f6f7374206361726566756c6c79207370656369616c2072657175657374732e206163636f756e7473206172652e206361726566756c6c0a32347c554e49544544205354415445537c317c792066696e616c207061636b616765732e20736c6f7720666f7865732063616a6f6c6520717569636b6c792e20717569636b6c792073696c656e7420706c6174656c657473206272656163682069726f6e6963206163636f756e74732e20756e757375616c2070696e746f2062650a + nation3 | \x307c414c47455249417c307c20686167676c652e206361726566756c6c792066696e616c206465706f736974732064657465637420736c796c7920616761690a317c415247454e54494e417c317c616c20666f7865732070726f6d69736520736c796c79206163636f7264696e6720746f2074686520726567756c6172206163636f756e74732e20626f6c6420726571756573747320616c6f6e0a327c4252415a494c7c317c7920616c6f6e6773696465206f66207468652070656e64696e67206465706f736974732e206361726566756c6c79207370656369616c207061636b61676573206172652061626f7574207468652069726f6e696320666f726765732e20736c796c79207370656369616c200a337c43414e4144417c317c6561732068616e672069726f6e69632c2073696c656e74207061636b616765732e20736c796c7920726567756c6172207061636b616765732061726520667572696f75736c79206f76657220746865207469746865732e20666c756666696c7920626f6c640a347c45475950547c347c792061626f766520746865206361726566756c6c7920756e757375616c207468656f646f6c697465732e2066696e616c206475676f7574732061726520717569636b6c79206163726f73732074686520667572696f75736c7920726567756c617220640a357c455448494f5049417c307c76656e207061636b616765732077616b6520717569636b6c792e20726567750a367c4652414e43457c337c726566756c6c792066696e616c2072657175657374732e20726567756c61722c2069726f6e690a377c4745524d414e597c337c6c20706c6174656c6574732e20726567756c6172206163636f756e747320782d7261793a20756e757375616c2c20726567756c6172206163636f0a387c494e4449417c327c737320657863757365732063616a6f6c6520736c796c79206163726f737320746865207061636b616765732e206465706f73697473207072696e742061726f756e0a397c494e444f4e455349417c327c20736c796c792065787072657373206173796d70746f7465732e20726567756c6172206465706f7369747320686167676c6520736c796c792e206361726566756c6c792069726f6e696320686f636b657920706c617965727320736c65657020626c697468656c792e206361726566756c6c0a31307c4952414e7c347c6566756c6c7920616c6f6e6773696465206f662074686520736c796c792066696e616c20646570656e64656e636965732e200a31317c495241517c347c6e6963206465706f7369747320626f6f73742061746f702074686520717569636b6c792066696e616c2072657175657374733f20717569636b6c7920726567756c610a31327c4a4150414e7c327c6f75736c792e2066696e616c2c20657870726573732067696674732063616a6f6c6520610a31337c4a4f5244414e7c347c6963206465706f736974732061726520626c697468656c792061626f757420746865206361726566756c6c7920726567756c61722070610a31347c4b454e59417c307c2070656e64696e67206578637573657320686167676c6520667572696f75736c79206465706f736974732e2070656e64696e672c20657870726573732070696e746f206265616e732077616b6520666c756666696c79207061737420740a31357c4d4f524f43434f7c307c726e732e20626c697468656c7920626f6c6420636f7572747320616d6f6e672074686520636c6f73656c7920726567756c6172207061636b616765732075736520667572696f75736c7920626f6c6420706c6174656c6574733f0a31367c4d4f5a414d42495155457c307c732e2069726f6e69632c20756e757375616c206173796d70746f7465732077616b6520626c697468656c7920720a31377c504552557c317c706c6174656c6574732e20626c697468656c792070656e64696e6720646570656e64656e636965732075736520666c756666696c79206163726f737320746865206576656e2070696e746f206265616e732e206361726566756c6c792073696c656e74206163636f756e0a31387c4348494e417c327c6320646570656e64656e636965732e20667572696f75736c792065787072657373206e6f746f726e697320736c65657020736c796c7920726567756c6172206163636f756e74732e20696465617320736c6565702e206465706f730a31397c524f4d414e49417c337c756c6172206173796d70746f746573206172652061626f75742074686520667572696f7573206d756c7469706c696572732e206578707265737320646570656e64656e63696573206e61672061626f7665207468652069726f6e6963616c6c792069726f6e6963206163636f756e740a32307c5341554449204152414249417c347c74732e2073696c656e7420726571756573747320686167676c652e20636c6f73656c792065787072657373207061636b6167657320736c656570206163726f73732074686520626c697468656c790a32317c564945544e414d7c327c68656c7920656e746963696e676c792065787072657373206163636f756e74732e206576656e2c2066696e616c200a32327c5255535349417c337c20726571756573747320616761696e73742074686520706c6174656c65747320757365206e65766572206163636f7264696e6720746f2074686520717569636b6c7920726567756c61722070696e740a32337c554e49544544204b494e47444f4d7c337c65616e7320626f6f7374206361726566756c6c79207370656369616c2072657175657374732e206163636f756e7473206172652e206361726566756c6c0a32347c554e49544544205354415445537c317c792066696e616c207061636b616765732e20736c6f7720666f7865732063616a6f6c6520717569636b6c792e20717569636b6c792073696c656e7420706c6174656c657473206272656163682069726f6e6963206163636f756e74732e20756e757375616c2070696e746f2062650a + nation4 | \x307c414c47455249417c307c20686167676c652e206361726566756c6c792066696e616c206465706f736974732064657465637420736c796c7920616761690a317c415247454e54494e417c317c616c20666f7865732070726f6d69736520736c796c79206163636f7264696e6720746f2074686520726567756c6172206163636f756e74732e20626f6c6420726571756573747320616c6f6e0a327c4252415a494c7c317c7920616c6f6e6773696465206f66207468652070656e64696e67206465706f736974732e206361726566756c6c79207370656369616c207061636b61676573206172652061626f7574207468652069726f6e696320666f726765732e20736c796c79207370656369616c200a337c43414e4144417c317c6561732068616e672069726f6e69632c2073696c656e74207061636b616765732e20736c796c7920726567756c6172207061636b616765732061726520667572696f75736c79206f76657220746865207469746865732e20666c756666696c7920626f6c640a347c45475950547c347c792061626f766520746865206361726566756c6c7920756e757375616c207468656f646f6c697465732e2066696e616c206475676f7574732061726520717569636b6c79206163726f73732074686520667572696f75736c7920726567756c617220640a357c455448494f5049417c307c76656e207061636b616765732077616b6520717569636b6c792e20726567750a367c4652414e43457c337c726566756c6c792066696e616c2072657175657374732e20726567756c61722c2069726f6e690a377c4745524d414e597c337c6c20706c6174656c6574732e20726567756c6172206163636f756e747320782d7261793a20756e757375616c2c20726567756c6172206163636f0a387c494e4449417c327c737320657863757365732063616a6f6c6520736c796c79206163726f737320746865207061636b616765732e206465706f73697473207072696e742061726f756e0a397c494e444f4e455349417c327c20736c796c792065787072657373206173796d70746f7465732e20726567756c6172206465706f7369747320686167676c6520736c796c792e206361726566756c6c792069726f6e696320686f636b657920706c617965727320736c65657020626c697468656c792e206361726566756c6c0a31307c4952414e7c347c6566756c6c7920616c6f6e6773696465206f662074686520736c796c792066696e616c20646570656e64656e636965732e200a31317c495241517c347c6e6963206465706f7369747320626f6f73742061746f702074686520717569636b6c792066696e616c2072657175657374733f20717569636b6c7920726567756c610a31327c4a4150414e7c327c6f75736c792e2066696e616c2c20657870726573732067696674732063616a6f6c6520610a31337c4a4f5244414e7c347c6963206465706f736974732061726520626c697468656c792061626f757420746865206361726566756c6c7920726567756c61722070610a31347c4b454e59417c307c2070656e64696e67206578637573657320686167676c6520667572696f75736c79206465706f736974732e2070656e64696e672c20657870726573732070696e746f206265616e732077616b6520666c756666696c79207061737420740a31357c4d4f524f43434f7c307c726e732e20626c697468656c7920626f6c6420636f7572747320616d6f6e672074686520636c6f73656c7920726567756c6172207061636b616765732075736520667572696f75736c7920626f6c6420706c6174656c6574733f0a31367c4d4f5a414d42495155457c307c732e2069726f6e69632c20756e757375616c206173796d70746f7465732077616b6520626c697468656c7920720a31377c504552557c317c706c6174656c6574732e20626c697468656c792070656e64696e6720646570656e64656e636965732075736520666c756666696c79206163726f737320746865206576656e2070696e746f206265616e732e206361726566756c6c792073696c656e74206163636f756e0a31387c4348494e417c327c6320646570656e64656e636965732e20667572696f75736c792065787072657373206e6f746f726e697320736c65657020736c796c7920726567756c6172206163636f756e74732e20696465617320736c6565702e206465706f730a31397c524f4d414e49417c337c756c6172206173796d70746f746573206172652061626f75742074686520667572696f7573206d756c7469706c696572732e206578707265737320646570656e64656e63696573206e61672061626f7665207468652069726f6e6963616c6c792069726f6e6963206163636f756e740a32307c5341554449204152414249417c347c74732e2073696c656e7420726571756573747320686167676c652e20636c6f73656c792065787072657373207061636b6167657320736c656570206163726f73732074686520626c697468656c790a32317c564945544e414d7c327c68656c7920656e746963696e676c792065787072657373206163636f756e74732e206576656e2c2066696e616c200a32327c5255535349417c337c20726571756573747320616761696e73742074686520706c6174656c65747320757365206e65766572206163636f7264696e6720746f2074686520717569636b6c7920726567756c61722070696e740a32337c554e49544544204b494e47444f4d7c337c65616e7320626f6f7374206361726566756c6c79207370656369616c2072657175657374732e206163636f756e7473206172652e206361726566756c6c0a32347c554e49544544205354415445537c317c792066696e616c207061636b616765732e20736c6f7720666f7865732063616a6f6c6520717569636b6c792e20717569636b6c792073696c656e7420706c6174656c657473206272656163682069726f6e6963206163636f756e74732e20756e757375616c2070696e746f2062650a +(4 rows) + +COPY dir_table2 FROM '@abs_srcdir@/data/nation.csv'; -- fail +ERROR: Copy from directory table file name can't be null. +COPY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation'; -- fail +ERROR: Only support copy binary from directory table. +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv'; -- fail +ERROR: Copy from directory table file name can't be null. +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation1'; +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation1'; -- fail +ERROR: duplicate key value violates unique constraint "dir_table2_pkey" +DETAIL: Key (relative_path)=(nation1) already exists. +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation2'; +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation3' WITH TAG 'nation'; +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation3' WITH TAG 'nation'; -- fail +ERROR: duplicate key value violates unique constraint "dir_table2_pkey" +DETAIL: Key (relative_path)=(nation3) already exists. +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation3' WITH TAG 'nation2'; -- fail +ERROR: duplicate key value violates unique constraint "dir_table2_pkey" +DETAIL: Key (relative_path)=(nation3) already exists. +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation4' WITH TAG 'nation'; +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation5' WITH TAG 'nation' WITH TAG 'nation2'; -- fail +ERROR: syntax error at or near "WITH" +LINE 1: ...ress/data/nation.csv' 'nation5' WITH TAG 'nation' WITH TAG '... + ^ +SELECT relative_path, size, tag FROM dir_table2 ORDER BY 1; + relative_path | size | tag +---------------+------+-------- + nation1 | 2199 | + nation2 | 2199 | + nation3 | 2199 | nation + nation4 | 2199 | nation +(4 rows) + +SELECT relative_path, content FROM directory_table('dir_table2') ORDER BY 1; + relative_path | content +---------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + nation1 | \x307c414c47455249417c307c20686167676c652e206361726566756c6c792066696e616c206465706f736974732064657465637420736c796c7920616761690a317c415247454e54494e417c317c616c20666f7865732070726f6d69736520736c796c79206163636f7264696e6720746f2074686520726567756c6172206163636f756e74732e20626f6c6420726571756573747320616c6f6e0a327c4252415a494c7c317c7920616c6f6e6773696465206f66207468652070656e64696e67206465706f736974732e206361726566756c6c79207370656369616c207061636b61676573206172652061626f7574207468652069726f6e696320666f726765732e20736c796c79207370656369616c200a337c43414e4144417c317c6561732068616e672069726f6e69632c2073696c656e74207061636b616765732e20736c796c7920726567756c6172207061636b616765732061726520667572696f75736c79206f76657220746865207469746865732e20666c756666696c7920626f6c640a347c45475950547c347c792061626f766520746865206361726566756c6c7920756e757375616c207468656f646f6c697465732e2066696e616c206475676f7574732061726520717569636b6c79206163726f73732074686520667572696f75736c7920726567756c617220640a357c455448494f5049417c307c76656e207061636b616765732077616b6520717569636b6c792e20726567750a367c4652414e43457c337c726566756c6c792066696e616c2072657175657374732e20726567756c61722c2069726f6e690a377c4745524d414e597c337c6c20706c6174656c6574732e20726567756c6172206163636f756e747320782d7261793a20756e757375616c2c20726567756c6172206163636f0a387c494e4449417c327c737320657863757365732063616a6f6c6520736c796c79206163726f737320746865207061636b616765732e206465706f73697473207072696e742061726f756e0a397c494e444f4e455349417c327c20736c796c792065787072657373206173796d70746f7465732e20726567756c6172206465706f7369747320686167676c6520736c796c792e206361726566756c6c792069726f6e696320686f636b657920706c617965727320736c65657020626c697468656c792e206361726566756c6c0a31307c4952414e7c347c6566756c6c7920616c6f6e6773696465206f662074686520736c796c792066696e616c20646570656e64656e636965732e200a31317c495241517c347c6e6963206465706f7369747320626f6f73742061746f702074686520717569636b6c792066696e616c2072657175657374733f20717569636b6c7920726567756c610a31327c4a4150414e7c327c6f75736c792e2066696e616c2c20657870726573732067696674732063616a6f6c6520610a31337c4a4f5244414e7c347c6963206465706f736974732061726520626c697468656c792061626f757420746865206361726566756c6c7920726567756c61722070610a31347c4b454e59417c307c2070656e64696e67206578637573657320686167676c6520667572696f75736c79206465706f736974732e2070656e64696e672c20657870726573732070696e746f206265616e732077616b6520666c756666696c79207061737420740a31357c4d4f524f43434f7c307c726e732e20626c697468656c7920626f6c6420636f7572747320616d6f6e672074686520636c6f73656c7920726567756c6172207061636b616765732075736520667572696f75736c7920626f6c6420706c6174656c6574733f0a31367c4d4f5a414d42495155457c307c732e2069726f6e69632c20756e757375616c206173796d70746f7465732077616b6520626c697468656c7920720a31377c504552557c317c706c6174656c6574732e20626c697468656c792070656e64696e6720646570656e64656e636965732075736520666c756666696c79206163726f737320746865206576656e2070696e746f206265616e732e206361726566756c6c792073696c656e74206163636f756e0a31387c4348494e417c327c6320646570656e64656e636965732e20667572696f75736c792065787072657373206e6f746f726e697320736c65657020736c796c7920726567756c6172206163636f756e74732e20696465617320736c6565702e206465706f730a31397c524f4d414e49417c337c756c6172206173796d70746f746573206172652061626f75742074686520667572696f7573206d756c7469706c696572732e206578707265737320646570656e64656e63696573206e61672061626f7665207468652069726f6e6963616c6c792069726f6e6963206163636f756e740a32307c5341554449204152414249417c347c74732e2073696c656e7420726571756573747320686167676c652e20636c6f73656c792065787072657373207061636b6167657320736c656570206163726f73732074686520626c697468656c790a32317c564945544e414d7c327c68656c7920656e746963696e676c792065787072657373206163636f756e74732e206576656e2c2066696e616c200a32327c5255535349417c337c20726571756573747320616761696e73742074686520706c6174656c65747320757365206e65766572206163636f7264696e6720746f2074686520717569636b6c7920726567756c61722070696e740a32337c554e49544544204b494e47444f4d7c337c65616e7320626f6f7374206361726566756c6c79207370656369616c2072657175657374732e206163636f756e7473206172652e206361726566756c6c0a32347c554e49544544205354415445537c317c792066696e616c207061636b616765732e20736c6f7720666f7865732063616a6f6c6520717569636b6c792e20717569636b6c792073696c656e7420706c6174656c657473206272656163682069726f6e6963206163636f756e74732e20756e757375616c2070696e746f2062650a + nation2 | \x307c414c47455249417c307c20686167676c652e206361726566756c6c792066696e616c206465706f736974732064657465637420736c796c7920616761690a317c415247454e54494e417c317c616c20666f7865732070726f6d69736520736c796c79206163636f7264696e6720746f2074686520726567756c6172206163636f756e74732e20626f6c6420726571756573747320616c6f6e0a327c4252415a494c7c317c7920616c6f6e6773696465206f66207468652070656e64696e67206465706f736974732e206361726566756c6c79207370656369616c207061636b61676573206172652061626f7574207468652069726f6e696320666f726765732e20736c796c79207370656369616c200a337c43414e4144417c317c6561732068616e672069726f6e69632c2073696c656e74207061636b616765732e20736c796c7920726567756c6172207061636b616765732061726520667572696f75736c79206f76657220746865207469746865732e20666c756666696c7920626f6c640a347c45475950547c347c792061626f766520746865206361726566756c6c7920756e757375616c207468656f646f6c697465732e2066696e616c206475676f7574732061726520717569636b6c79206163726f73732074686520667572696f75736c7920726567756c617220640a357c455448494f5049417c307c76656e207061636b616765732077616b6520717569636b6c792e20726567750a367c4652414e43457c337c726566756c6c792066696e616c2072657175657374732e20726567756c61722c2069726f6e690a377c4745524d414e597c337c6c20706c6174656c6574732e20726567756c6172206163636f756e747320782d7261793a20756e757375616c2c20726567756c6172206163636f0a387c494e4449417c327c737320657863757365732063616a6f6c6520736c796c79206163726f737320746865207061636b616765732e206465706f73697473207072696e742061726f756e0a397c494e444f4e455349417c327c20736c796c792065787072657373206173796d70746f7465732e20726567756c6172206465706f7369747320686167676c6520736c796c792e206361726566756c6c792069726f6e696320686f636b657920706c617965727320736c65657020626c697468656c792e206361726566756c6c0a31307c4952414e7c347c6566756c6c7920616c6f6e6773696465206f662074686520736c796c792066696e616c20646570656e64656e636965732e200a31317c495241517c347c6e6963206465706f7369747320626f6f73742061746f702074686520717569636b6c792066696e616c2072657175657374733f20717569636b6c7920726567756c610a31327c4a4150414e7c327c6f75736c792e2066696e616c2c20657870726573732067696674732063616a6f6c6520610a31337c4a4f5244414e7c347c6963206465706f736974732061726520626c697468656c792061626f757420746865206361726566756c6c7920726567756c61722070610a31347c4b454e59417c307c2070656e64696e67206578637573657320686167676c6520667572696f75736c79206465706f736974732e2070656e64696e672c20657870726573732070696e746f206265616e732077616b6520666c756666696c79207061737420740a31357c4d4f524f43434f7c307c726e732e20626c697468656c7920626f6c6420636f7572747320616d6f6e672074686520636c6f73656c7920726567756c6172207061636b616765732075736520667572696f75736c7920626f6c6420706c6174656c6574733f0a31367c4d4f5a414d42495155457c307c732e2069726f6e69632c20756e757375616c206173796d70746f7465732077616b6520626c697468656c7920720a31377c504552557c317c706c6174656c6574732e20626c697468656c792070656e64696e6720646570656e64656e636965732075736520666c756666696c79206163726f737320746865206576656e2070696e746f206265616e732e206361726566756c6c792073696c656e74206163636f756e0a31387c4348494e417c327c6320646570656e64656e636965732e20667572696f75736c792065787072657373206e6f746f726e697320736c65657020736c796c7920726567756c6172206163636f756e74732e20696465617320736c6565702e206465706f730a31397c524f4d414e49417c337c756c6172206173796d70746f746573206172652061626f75742074686520667572696f7573206d756c7469706c696572732e206578707265737320646570656e64656e63696573206e61672061626f7665207468652069726f6e6963616c6c792069726f6e6963206163636f756e740a32307c5341554449204152414249417c347c74732e2073696c656e7420726571756573747320686167676c652e20636c6f73656c792065787072657373207061636b6167657320736c656570206163726f73732074686520626c697468656c790a32317c564945544e414d7c327c68656c7920656e746963696e676c792065787072657373206163636f756e74732e206576656e2c2066696e616c200a32327c5255535349417c337c20726571756573747320616761696e73742074686520706c6174656c65747320757365206e65766572206163636f7264696e6720746f2074686520717569636b6c7920726567756c61722070696e740a32337c554e49544544204b494e47444f4d7c337c65616e7320626f6f7374206361726566756c6c79207370656369616c2072657175657374732e206163636f756e7473206172652e206361726566756c6c0a32347c554e49544544205354415445537c317c792066696e616c207061636b616765732e20736c6f7720666f7865732063616a6f6c6520717569636b6c792e20717569636b6c792073696c656e7420706c6174656c657473206272656163682069726f6e6963206163636f756e74732e20756e757375616c2070696e746f2062650a + nation3 | \x307c414c47455249417c307c20686167676c652e206361726566756c6c792066696e616c206465706f736974732064657465637420736c796c7920616761690a317c415247454e54494e417c317c616c20666f7865732070726f6d69736520736c796c79206163636f7264696e6720746f2074686520726567756c6172206163636f756e74732e20626f6c6420726571756573747320616c6f6e0a327c4252415a494c7c317c7920616c6f6e6773696465206f66207468652070656e64696e67206465706f736974732e206361726566756c6c79207370656369616c207061636b61676573206172652061626f7574207468652069726f6e696320666f726765732e20736c796c79207370656369616c200a337c43414e4144417c317c6561732068616e672069726f6e69632c2073696c656e74207061636b616765732e20736c796c7920726567756c6172207061636b616765732061726520667572696f75736c79206f76657220746865207469746865732e20666c756666696c7920626f6c640a347c45475950547c347c792061626f766520746865206361726566756c6c7920756e757375616c207468656f646f6c697465732e2066696e616c206475676f7574732061726520717569636b6c79206163726f73732074686520667572696f75736c7920726567756c617220640a357c455448494f5049417c307c76656e207061636b616765732077616b6520717569636b6c792e20726567750a367c4652414e43457c337c726566756c6c792066696e616c2072657175657374732e20726567756c61722c2069726f6e690a377c4745524d414e597c337c6c20706c6174656c6574732e20726567756c6172206163636f756e747320782d7261793a20756e757375616c2c20726567756c6172206163636f0a387c494e4449417c327c737320657863757365732063616a6f6c6520736c796c79206163726f737320746865207061636b616765732e206465706f73697473207072696e742061726f756e0a397c494e444f4e455349417c327c20736c796c792065787072657373206173796d70746f7465732e20726567756c6172206465706f7369747320686167676c6520736c796c792e206361726566756c6c792069726f6e696320686f636b657920706c617965727320736c65657020626c697468656c792e206361726566756c6c0a31307c4952414e7c347c6566756c6c7920616c6f6e6773696465206f662074686520736c796c792066696e616c20646570656e64656e636965732e200a31317c495241517c347c6e6963206465706f7369747320626f6f73742061746f702074686520717569636b6c792066696e616c2072657175657374733f20717569636b6c7920726567756c610a31327c4a4150414e7c327c6f75736c792e2066696e616c2c20657870726573732067696674732063616a6f6c6520610a31337c4a4f5244414e7c347c6963206465706f736974732061726520626c697468656c792061626f757420746865206361726566756c6c7920726567756c61722070610a31347c4b454e59417c307c2070656e64696e67206578637573657320686167676c6520667572696f75736c79206465706f736974732e2070656e64696e672c20657870726573732070696e746f206265616e732077616b6520666c756666696c79207061737420740a31357c4d4f524f43434f7c307c726e732e20626c697468656c7920626f6c6420636f7572747320616d6f6e672074686520636c6f73656c7920726567756c6172207061636b616765732075736520667572696f75736c7920626f6c6420706c6174656c6574733f0a31367c4d4f5a414d42495155457c307c732e2069726f6e69632c20756e757375616c206173796d70746f7465732077616b6520626c697468656c7920720a31377c504552557c317c706c6174656c6574732e20626c697468656c792070656e64696e6720646570656e64656e636965732075736520666c756666696c79206163726f737320746865206576656e2070696e746f206265616e732e206361726566756c6c792073696c656e74206163636f756e0a31387c4348494e417c327c6320646570656e64656e636965732e20667572696f75736c792065787072657373206e6f746f726e697320736c65657020736c796c7920726567756c6172206163636f756e74732e20696465617320736c6565702e206465706f730a31397c524f4d414e49417c337c756c6172206173796d70746f746573206172652061626f75742074686520667572696f7573206d756c7469706c696572732e206578707265737320646570656e64656e63696573206e61672061626f7665207468652069726f6e6963616c6c792069726f6e6963206163636f756e740a32307c5341554449204152414249417c347c74732e2073696c656e7420726571756573747320686167676c652e20636c6f73656c792065787072657373207061636b6167657320736c656570206163726f73732074686520626c697468656c790a32317c564945544e414d7c327c68656c7920656e746963696e676c792065787072657373206163636f756e74732e206576656e2c2066696e616c200a32327c5255535349417c337c20726571756573747320616761696e73742074686520706c6174656c65747320757365206e65766572206163636f7264696e6720746f2074686520717569636b6c7920726567756c61722070696e740a32337c554e49544544204b494e47444f4d7c337c65616e7320626f6f7374206361726566756c6c79207370656369616c2072657175657374732e206163636f756e7473206172652e206361726566756c6c0a32347c554e49544544205354415445537c317c792066696e616c207061636b616765732e20736c6f7720666f7865732063616a6f6c6520717569636b6c792e20717569636b6c792073696c656e7420706c6174656c657473206272656163682069726f6e6963206163636f756e74732e20756e757375616c2070696e746f2062650a + nation4 | \x307c414c47455249417c307c20686167676c652e206361726566756c6c792066696e616c206465706f736974732064657465637420736c796c7920616761690a317c415247454e54494e417c317c616c20666f7865732070726f6d69736520736c796c79206163636f7264696e6720746f2074686520726567756c6172206163636f756e74732e20626f6c6420726571756573747320616c6f6e0a327c4252415a494c7c317c7920616c6f6e6773696465206f66207468652070656e64696e67206465706f736974732e206361726566756c6c79207370656369616c207061636b61676573206172652061626f7574207468652069726f6e696320666f726765732e20736c796c79207370656369616c200a337c43414e4144417c317c6561732068616e672069726f6e69632c2073696c656e74207061636b616765732e20736c796c7920726567756c6172207061636b616765732061726520667572696f75736c79206f76657220746865207469746865732e20666c756666696c7920626f6c640a347c45475950547c347c792061626f766520746865206361726566756c6c7920756e757375616c207468656f646f6c697465732e2066696e616c206475676f7574732061726520717569636b6c79206163726f73732074686520667572696f75736c7920726567756c617220640a357c455448494f5049417c307c76656e207061636b616765732077616b6520717569636b6c792e20726567750a367c4652414e43457c337c726566756c6c792066696e616c2072657175657374732e20726567756c61722c2069726f6e690a377c4745524d414e597c337c6c20706c6174656c6574732e20726567756c6172206163636f756e747320782d7261793a20756e757375616c2c20726567756c6172206163636f0a387c494e4449417c327c737320657863757365732063616a6f6c6520736c796c79206163726f737320746865207061636b616765732e206465706f73697473207072696e742061726f756e0a397c494e444f4e455349417c327c20736c796c792065787072657373206173796d70746f7465732e20726567756c6172206465706f7369747320686167676c6520736c796c792e206361726566756c6c792069726f6e696320686f636b657920706c617965727320736c65657020626c697468656c792e206361726566756c6c0a31307c4952414e7c347c6566756c6c7920616c6f6e6773696465206f662074686520736c796c792066696e616c20646570656e64656e636965732e200a31317c495241517c347c6e6963206465706f7369747320626f6f73742061746f702074686520717569636b6c792066696e616c2072657175657374733f20717569636b6c7920726567756c610a31327c4a4150414e7c327c6f75736c792e2066696e616c2c20657870726573732067696674732063616a6f6c6520610a31337c4a4f5244414e7c347c6963206465706f736974732061726520626c697468656c792061626f757420746865206361726566756c6c7920726567756c61722070610a31347c4b454e59417c307c2070656e64696e67206578637573657320686167676c6520667572696f75736c79206465706f736974732e2070656e64696e672c20657870726573732070696e746f206265616e732077616b6520666c756666696c79207061737420740a31357c4d4f524f43434f7c307c726e732e20626c697468656c7920626f6c6420636f7572747320616d6f6e672074686520636c6f73656c7920726567756c6172207061636b616765732075736520667572696f75736c7920626f6c6420706c6174656c6574733f0a31367c4d4f5a414d42495155457c307c732e2069726f6e69632c20756e757375616c206173796d70746f7465732077616b6520626c697468656c7920720a31377c504552557c317c706c6174656c6574732e20626c697468656c792070656e64696e6720646570656e64656e636965732075736520666c756666696c79206163726f737320746865206576656e2070696e746f206265616e732e206361726566756c6c792073696c656e74206163636f756e0a31387c4348494e417c327c6320646570656e64656e636965732e20667572696f75736c792065787072657373206e6f746f726e697320736c65657020736c796c7920726567756c6172206163636f756e74732e20696465617320736c6565702e206465706f730a31397c524f4d414e49417c337c756c6172206173796d70746f746573206172652061626f75742074686520667572696f7573206d756c7469706c696572732e206578707265737320646570656e64656e63696573206e61672061626f7665207468652069726f6e6963616c6c792069726f6e6963206163636f756e740a32307c5341554449204152414249417c347c74732e2073696c656e7420726571756573747320686167676c652e20636c6f73656c792065787072657373207061636b6167657320736c656570206163726f73732074686520626c697468656c790a32317c564945544e414d7c327c68656c7920656e746963696e676c792065787072657373206163636f756e74732e206576656e2c2066696e616c200a32327c5255535349417c337c20726571756573747320616761696e73742074686520706c6174656c65747320757365206e65766572206163636f7264696e6720746f2074686520717569636b6c7920726567756c61722070696e740a32337c554e49544544204b494e47444f4d7c337c65616e7320626f6f7374206361726566756c6c79207370656369616c2072657175657374732e206163636f756e7473206172652e206361726566756c6c0a32347c554e49544544205354415445537c317c792066696e616c207061636b616765732e20736c6f7720666f7865732063616a6f6c6520717569636b6c792e20717569636b6c792073696c656e7420706c6174656c657473206272656163682069726f6e6963206163636f756e74732e20756e757375616c2070696e746f2062650a +(4 rows) + +-- Test copy binary from directory table +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (format CSV); +ERROR: conflicting or redundant options +LINE 1: ...OPY BINARY dir_table1 FROM STDIN 'nation_failed' (format CSV... + ^ +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (freeze off); +ERROR: option "freeze" not recognized +LINE 1: ...OPY BINARY dir_table1 FROM STDIN 'nation_failed' (freeze off... + ^ +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (freeze on); +ERROR: option "freeze" not recognized +LINE 1: ...OPY BINARY dir_table1 FROM STDIN 'nation_failed' (freeze on)... + ^ +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (delimiter ','); +ERROR: option "delimiter" not recognized +LINE 1: ...OPY BINARY dir_table1 FROM STDIN 'nation_failed' (delimiter ... + ^ +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (null ' '); +ERROR: option "null" not recognized +LINE 1: ...OPY BINARY dir_table1 FROM STDIN 'nation_failed' (null ' '); + ^ +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (header off); +ERROR: option "header" not recognized +LINE 1: ...OPY BINARY dir_table1 FROM STDIN 'nation_failed' (header off... + ^ +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (header on); +ERROR: option "header" not recognized +LINE 1: ...OPY BINARY dir_table1 FROM STDIN 'nation_failed' (header on)... + ^ +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (quote ':'); +ERROR: option "quote" not recognized +LINE 1: ...OPY BINARY dir_table1 FROM STDIN 'nation_failed' (quote ':')... + ^ +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (escape ':'); +ERROR: option "escape" not recognized +LINE 1: ...OPY BINARY dir_table1 FROM STDIN 'nation_failed' (escape ':'... + ^ +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (force_quote (a)); +ERROR: option "force_quote" not recognized +LINE 1: ...OPY BINARY dir_table1 FROM STDIN 'nation_failed' (force_quot... + ^ +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (force_quote *); +ERROR: option "force_quote" not recognized +LINE 1: ...OPY BINARY dir_table1 FROM STDIN 'nation_failed' (force_quot... + ^ +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (force_not_null (a)); +ERROR: option "force_not_null" not recognized +LINE 1: ...OPY BINARY dir_table1 FROM STDIN 'nation_failed' (force_not_... + ^ +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (force_null (a)); +ERROR: option "force_null" not recognized +LINE 1: ...OPY BINARY dir_table1 FROM STDIN 'nation_failed' (force_null... + ^ +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (convert_selectively (a)); +ERROR: option "convert_selectively" not recognized +LINE 1: ...OPY BINARY dir_table1 FROM STDIN 'nation_failed' (convert_se... + ^ +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (encoding 'sql_ascii'); +ERROR: option "encoding" not recognized +LINE 1: ...OPY BINARY dir_table1 FROM STDIN 'nation_failed' (encoding '... + ^ +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (format CSV); +ERROR: conflicting or redundant options +LINE 1: ...rc/test/regress/data/nation.csv' 'nation_failed' (format CSV... + ^ +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (freeze off); +ERROR: option "freeze" not recognized +LINE 1: ...rc/test/regress/data/nation.csv' 'nation_failed' (freeze off... + ^ +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (freeze on); +ERROR: option "freeze" not recognized +LINE 1: ...rc/test/regress/data/nation.csv' 'nation_failed' (freeze on)... + ^ +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (delimiter ','); +ERROR: option "delimiter" not recognized +LINE 1: ...rc/test/regress/data/nation.csv' 'nation_failed' (delimiter ... + ^ +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (null ' '); +ERROR: option "null" not recognized +LINE 1: ...rc/test/regress/data/nation.csv' 'nation_failed' (null ' '); + ^ +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (header off); +ERROR: option "header" not recognized +LINE 1: ...rc/test/regress/data/nation.csv' 'nation_failed' (header off... + ^ +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (header on); +ERROR: option "header" not recognized +LINE 1: ...rc/test/regress/data/nation.csv' 'nation_failed' (header on)... + ^ +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (quote ':'); +ERROR: option "quote" not recognized +LINE 1: ...rc/test/regress/data/nation.csv' 'nation_failed' (quote ':')... + ^ +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (escape ':'); +ERROR: option "escape" not recognized +LINE 1: ...rc/test/regress/data/nation.csv' 'nation_failed' (escape ':'... + ^ +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (force_quote (a)); +ERROR: option "force_quote" not recognized +LINE 1: ...rc/test/regress/data/nation.csv' 'nation_failed' (force_quot... + ^ +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (force_quote *); +ERROR: option "force_quote" not recognized +LINE 1: ...rc/test/regress/data/nation.csv' 'nation_failed' (force_quot... + ^ +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (force_not_null (a)); +ERROR: option "force_not_null" not recognized +LINE 1: ...rc/test/regress/data/nation.csv' 'nation_failed' (force_not_... + ^ +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (force_null (a)); +ERROR: option "force_null" not recognized +LINE 1: ...rc/test/regress/data/nation.csv' 'nation_failed' (force_null... + ^ +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (convert_selectively (a)); +ERROR: option "convert_selectively" not recognized +LINE 1: ...rc/test/regress/data/nation.csv' 'nation_failed' (convert_se... + ^ +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (encoding 'sql_ascii'); +ERROR: option "encoding" not recognized +LINE 1: ...rc/test/regress/data/nation.csv' 'nation_failed' (encoding '... + ^ +-- Test copy file content md5 +CREATE OR REPLACE FUNCTION file_content(text, text) RETURNS BYTEA LANGUAGE SQL AS +'select content from directory_table($1) where relative_path = $2'; +CREATE OR REPLACE FUNCTION file_md5(text, text) RETURNS TEXT LANGUAGE SQL AS +'select md5 from directory_table($1) where relative_path = $2'; +CREATE OR REPLACE FUNCTION md5_equal(text, text) RETURNS BOOL LANGUAGE SQL AS +'SELECT md5(file_content($1, $2)) = (SELECT file_md5($1, $2))'; +SELECT md5_equal('dir_table1', 'nation1'); + md5_equal +----------- + t +(1 row) + +SELECT md5_equal('dir_table1', 'nation2'); + md5_equal +----------- + t +(1 row) + +SELECT md5_equal('dir_table1', 'nation3'); + md5_equal +----------- + t +(1 row) + +SELECT md5_equal('dir_table1', 'nation4'); + md5_equal +----------- + t +(1 row) + +SELECT md5_equal('dir_table2', 'nation1'); + md5_equal +----------- + t +(1 row) + +SELECT md5_equal('dir_table2', 'nation2'); + md5_equal +----------- + t +(1 row) + +SELECT md5_equal('dir_table2', 'nation3'); + md5_equal +----------- + t +(1 row) + +SELECT md5_equal('dir_table2', 'nation4'); + md5_equal +----------- + t +(1 row) + +-- Does not support copy to +\COPY dir_table1 TO '@abs_srcdir@/data/dir_table1'; -- fail +ERROR: cannot copy from non-table relation "dir_table1" +\COPY BINARY dir_table1 TO '@abs_srcdir@/data/dir_table1'; -- fail +ERROR: cannot copy from non-table relation "dir_table1" +COPY dir_table1 TO '@abs_srcdir@/data/dir_table1'; -- fail +ERROR: cannot copy from non-table relation "dir_table1" +COPY BINARY dir_table1 TO '@abs_srcdir@/data/dir_table1'; -- fail +ERROR: cannot copy from non-table relation "dir_table1" +\COPY dir_table2 TO '@abs_srcdir@/data/dir_table2'; -- fail +ERROR: cannot copy from non-table relation "dir_table2" +\COPY BINARY dir_table2 TO '@abs_srcdir@/data/dir_table2'; -- fail +ERROR: cannot copy from non-table relation "dir_table2" +COPY dir_table2 TO '@abs_srcdir@/data/dir_table2'; -- fail +ERROR: cannot copy from non-table relation "dir_table2" +COPY BINARY dir_table2 TO '@abs_srcdir@/data/dir_table2'; -- fail +ERROR: cannot copy from non-table relation "dir_table2" +SELECT relative_path, size, tag FROM dir_table1 ORDER BY 1; + relative_path | size | tag +---------------+------+-------- + nation1 | 2199 | + nation2 | 2199 | + nation3 | 2199 | nation + nation4 | 2199 | nation +(4 rows) + +SELECT relative_path, size, tag FROM dir_table2 ORDER BY 1; + relative_path | size | tag +---------------+------+-------- + nation1 | 2199 | + nation2 | 2199 | + nation3 | 2199 | nation + nation4 | 2199 | nation +(4 rows) + +-- Test join between two directory schema tables +ANALYZE dir_table1; +ANALYZE dir_table2; +EXPLAIN (COSTS OFF) SELECT dir_table1.relative_path FROM dir_table1, dir_table2 +WHERE dir_table1.relative_path = dir_table2.relative_path ORDER BY 1; + QUERY PLAN +-------------------------------------------------------------------------------- + Gather Motion 3:1 (slice1; segments: 3) + Merge Key: dir_table1.relative_path + -> Sort + Sort Key: dir_table1.relative_path + -> Hash Join + Hash Cond: (dir_table1.relative_path = dir_table2.relative_path) + -> Seq Scan on dir_table1 + -> Hash + -> Seq Scan on dir_table2 + Optimizer: Postgres query optimizer +(10 rows) + +SELECT dir_table1.relative_path FROM dir_table1, dir_table2 +WHERE dir_table1.relative_path = dir_table2.relative_path ORDER BY 1; + relative_path +--------------- + nation1 + nation2 + nation3 + nation4 +(4 rows) + +EXPLAIN (COSTS OFF) SELECT dir_table1.relative_path FROM dir_table1, dir_table2 +WHERE dir_table1.size = dir_table2.size ORDER BY 1 LIMIT 1; + QUERY PLAN +------------------------------------------------------------------------------------ + Limit + -> Gather Motion 3:1 (slice1; segments: 3) + Merge Key: dir_table1.relative_path + -> Limit + -> Sort + Sort Key: dir_table1.relative_path + -> Hash Join + Hash Cond: (dir_table1.size = dir_table2.size) + -> Redistribute Motion 3:3 (slice2; segments: 3) + Hash Key: dir_table1.size + -> Seq Scan on dir_table1 + -> Hash + -> Redistribute Motion 3:3 (slice3; segments: 3) + Hash Key: dir_table2.size + -> Seq Scan on dir_table2 + Optimizer: Postgres query optimizer +(16 rows) + +SELECT dir_table1.relative_path FROM dir_table1, dir_table2 +WHERE dir_table1.size = dir_table2.size ORDER BY 1 LIMIT 1; + relative_path +--------------- + nation1 +(1 row) + +EXPLAIN (COSTS OFF) SELECT dir_table1.relative_path FROM dir_table1, dir_table2 +WHERE dir_table1.md5 = dir_table2.md5 ORDER BY 1 LIMIT 1; + QUERY PLAN +------------------------------------------------------------------------------------ + Limit + -> Gather Motion 3:1 (slice1; segments: 3) + Merge Key: dir_table1.relative_path + -> Limit + -> Sort + Sort Key: dir_table1.relative_path + -> Hash Join + Hash Cond: (dir_table1.md5 = dir_table2.md5) + -> Redistribute Motion 3:3 (slice2; segments: 3) + Hash Key: dir_table1.md5 + -> Seq Scan on dir_table1 + -> Hash + -> Redistribute Motion 3:3 (slice3; segments: 3) + Hash Key: dir_table2.md5 + -> Seq Scan on dir_table2 + Optimizer: Postgres query optimizer +(16 rows) + +SELECT dir_table1.relative_path FROM dir_table1, dir_table2 +WHERE dir_table1.md5 = dir_table2.md5 ORDER BY 1 LIMIT 1; + relative_path +--------------- + nation1 +(1 row) + +EXPLAIN (COSTS OFF) SELECT dir_table1.relative_path FROM dir_table1, dir_table2 +WHERE dir_table1.tag = dir_table2.tag ORDER BY 1; + QUERY PLAN +--------------------------------------------------------------- + Gather Motion 3:1 (slice1; segments: 3) + Merge Key: dir_table1.relative_path + -> Sort + Sort Key: dir_table1.relative_path + -> Hash Join + Hash Cond: (dir_table2.tag = dir_table1.tag) + -> Broadcast Motion 3:3 (slice2; segments: 3) + -> Seq Scan on dir_table2 + -> Hash + -> Seq Scan on dir_table1 + Optimizer: Postgres query optimizer +(11 rows) + +SELECT dir_table1.relative_path FROM dir_table1, dir_table2 +WHERE dir_table1.tag = dir_table2.tag ORDER BY 1; + relative_path +--------------- + nation3 + nation3 + nation4 + nation4 +(4 rows) + +-- Test DML directory schema table, only allow to update tag +INSERT INTO dir_table1 VALUES('insert'); -- fail +ERROR: cannot change directory table "dir_table1" +INSERT INTO dir_table2 VALUES('insert', 512, '2000-03-21 17:13:27+08', '70f09140d1b83eb3ecf9a0e28494d2a4', 'insert'); -- fail +ERROR: cannot change directory table "dir_table2" +SELECT relative_path, size, tag FROM dir_table1 ORDER BY 1; + relative_path | size | tag +---------------+------+-------- + nation1 | 2199 | + nation2 | 2199 | + nation3 | 2199 | nation + nation4 | 2199 | nation +(4 rows) + +SELECT relative_path, size, tag FROM dir_table2 ORDER BY 1; + relative_path | size | tag +---------------+------+-------- + nation1 | 2199 | + nation2 | 2199 | + nation3 | 2199 | nation + nation4 | 2199 | nation +(4 rows) + +DELETE FROM dir_table1; -- fail +ERROR: cannot change directory table "dir_table1" +DELETE FROM dir_table2 WHERE relative_path = 'nation1'; -- fail +ERROR: cannot change directory table "dir_table2" +SELECT relative_path, size, tag FROM dir_table1 ORDER BY 1; + relative_path | size | tag +---------------+------+-------- + nation1 | 2199 | + nation2 | 2199 | + nation3 | 2199 | nation + nation4 | 2199 | nation +(4 rows) + +SELECT relative_path, size, tag FROM dir_table2 ORDER BY 1; + relative_path | size | tag +---------------+------+-------- + nation1 | 2199 | + nation2 | 2199 | + nation3 | 2199 | nation + nation4 | 2199 | nation +(4 rows) + +UPDATE dir_table1 SET relative_path = 'nation_updated'; -- fail +ERROR: UPDATE on distributed key column not allowed on relation with update triggers +UPDATE dir_table2 SET relative_path = 'nation_updated' WHERE relative_path = 'nation2'; -- fail +ERROR: Only allow to update directory "tag" column. +UPDATE dir_table1 SET size = 512; -- fail +ERROR: Only allow to update directory "tag" column. +UPDATE dir_table2 SET size = 1024 WHERE relative_path = 'nation1'; -- fail +ERROR: Only allow to update directory "tag" column. +UPDATE dir_table1 SET last_modified = '2000-03-21 16:55:07+08'; -- fail +ERROR: Only allow to update directory "tag" column. +UPDATE dir_table2 SET last_modified = '2000-03-21 16:55:07+08' WHERE relative_path = 'nation3'; -- fail +ERROR: Only allow to update directory "tag" column. +UPDATE dir_table1 SET md5 = '70f09140d1b83eb3ecf9a0e28494d2a4'; -- fail +ERROR: Only allow to update directory "tag" column. +UPDATE dir_table2 SET md5 = '70f09140d1b83eb3ecf9a0e28494d2a4' WHERE relative_path = 'nation4'; -- fail +ERROR: Only allow to update directory "tag" column. +UPDATE dir_table1 SET tag = 'nation_new_tag'; -- ok +NOTICE: dir_table1 UPDATE BEFORE ROW (seg1 127.0.1.1:7003 pid=15072) +NOTICE: dir_table1 UPDATE BEFORE ROW (seg1 127.0.1.1:7003 pid=15072) +NOTICE: dir_table1 UPDATE BEFORE ROW (seg2 127.0.1.1:7004 pid=15073) +NOTICE: dir_table1 UPDATE AFTER ROW (seg1 127.0.1.1:7003 pid=15072) +NOTICE: dir_table1 UPDATE AFTER ROW (seg1 127.0.1.1:7003 pid=15072) +NOTICE: dir_table1 UPDATE BEFORE ROW (seg2 127.0.1.1:7004 pid=15073) +NOTICE: dir_table1 UPDATE AFTER ROW (seg2 127.0.1.1:7004 pid=15073) +NOTICE: dir_table1 UPDATE AFTER ROW (seg2 127.0.1.1:7004 pid=15073) +UPDATE dir_table1 SET tag = 'nation2_new_tag' WHERE relative_path = 'nation2'; -- ok +NOTICE: dir_table1 UPDATE BEFORE ROW (seg2 127.0.1.1:7004 pid=15073) +NOTICE: dir_table1 UPDATE AFTER ROW (seg2 127.0.1.1:7004 pid=15073) +UPDATE dir_table2 SET tag = 'nation4_new_tag' WHERE relative_path = 'nation3'; -- ok +UPDATE dir_table1 SET tag = 'failed_tag' WHERE relative_path = 'not_exist_path'; +UPDATE dir_table2 SET tag = 'no_tag' WHERE relative_path = 'not_exist_path'; +SELECT relative_path, size, tag FROM dir_table1 ORDER BY 1; + relative_path | size | tag +---------------+------+----------------- + nation1 | 2199 | nation_new_tag + nation2 | 2199 | nation2_new_tag + nation3 | 2199 | nation_new_tag + nation4 | 2199 | nation_new_tag +(4 rows) + +SELECT relative_path, size, tag FROM dir_table2 ORDER BY 1; + relative_path | size | tag +---------------+------+----------------- + nation1 | 2199 | + nation2 | 2199 | + nation3 | 2199 | nation4_new_tag + nation4 | 2199 | nation +(4 rows) + +-- Test alter table directory schema table +ALTER TABLE dir_table1 ADD COLUMN a int; -- fail +ERROR: "dir_table1" is not a table, composite type, or foreign table +ALTER DIRECTORY TABLE dir_table1 ADD COLUMN a int; -- fail +ERROR: syntax error at or near "DIRECTORY" +LINE 1: ALTER DIRECTORY TABLE dir_table1 ADD COLUMN a int; + ^ +ALTER TABLE dir_table2 DROP COLUMN relative_path; -- fail +ERROR: "dir_table2" is not a table, composite type, or foreign table +ALTER DIRECTORY TABLE dir_table2 DROP COLUMN relative_path; -- fail +ERROR: syntax error at or near "DIRECTORY" +LINE 1: ALTER DIRECTORY TABLE dir_table2 DROP COLUMN relative_path; + ^ +ALTER TABLE dir_table1 RENAME TO dir_table_new; -- fail +ERROR: Rename directory table is not allowed. +ALTER DIRECTORY TABLE dir_table1 RENAME TO dir_table_new; -- fail +ERROR: syntax error at or near "DIRECTORY" +LINE 1: ALTER DIRECTORY TABLE dir_table1 RENAME TO dir_table_new; + ^ +ALTER TABLE dir_table2 ADD CONSTRAINT dirtable_constraint UNIQUE (tag); -- fail +ERROR: "dir_table2" is not a table or foreign table +ALTER DIRECTORY TABLE dir_table2 ADD CONSTRAINT dirtable_constraint UNIQUE (tag); -- fail +ERROR: syntax error at or near "DIRECTORY" +LINE 1: ALTER DIRECTORY TABLE dir_table2 ADD CONSTRAINT dirtable_con... + ^ +ALTER TABLE dir_table1 DROP CONSTRAINT DROP CONSTRAINT test_pkey; -- fail +ERROR: syntax error at or near "CONSTRAINT" +LINE 1: ALTER TABLE dir_table1 DROP CONSTRAINT DROP CONSTRAINT test_... + ^ +ALTER DIRECTORY TABLE dir_table1 DROP CONSTRAINT DROP CONSTRAINT test_pkey; -- fail +ERROR: syntax error at or near "DIRECTORY" +LINE 1: ALTER DIRECTORY TABLE dir_table1 DROP CONSTRAINT DROP CONSTR... + ^ +-- Test remove_table +SELECT remove_file('dir_table1', 'nation5'); -- fail + remove_file +------------- + f +(1 row) + +SELECT remove_file('dir_table1', 'nation1'); + remove_file +------------- + t +(1 row) + +SELECT remove_file('dir_table2', 'nation1', 'nation2'); -- fail +ERROR: function remove_file(unknown, unknown, unknown) does not exist +LINE 1: SELECT remove_file('dir_table2', 'nation1', 'nation2'); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +SELECT remove_file('dir_table1', 'nation2'); + remove_file +------------- + t +(1 row) + +SELECT remove_file('dir_table3', 'nation1'); -- fail + remove_file +------------- + f +(1 row) + +SELECT remove_file('dir_table2', 'nation3'); + remove_file +------------- + t +(1 row) + +SELECT remove_file('dir_table1', 'nation1'); -- fail + remove_file +------------- + f +(1 row) + +SELECT relative_path, size, tag FROM dir_table1 ORDER BY 1; + relative_path | size | tag +---------------+------+---------------- + nation3 | 2199 | nation_new_tag + nation4 | 2199 | nation_new_tag +(2 rows) + +SELECT relative_path, size, tag FROM dir_table2 ORDER BY 1; + relative_path | size | tag +---------------+------+-------- + nation1 | 2199 | + nation2 | 2199 | + nation4 | 2199 | nation +(3 rows) + +-- Test transaction commit of directory table manipulation +CREATE DIRECTORY TABLE dir_table4 TABLESPACE directory_tblspc; +BEGIN; +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_commit'; +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_commit2' WITH TAG 'nation'; +COMMIT; +SELECT relative_path, content FROM directory_table('dir_table4') ORDER BY 1; + relative_path | content +----------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + nation_commit | \x307c414c47455249417c307c20686167676c652e206361726566756c6c792066696e616c206465706f736974732064657465637420736c796c7920616761690a317c415247454e54494e417c317c616c20666f7865732070726f6d69736520736c796c79206163636f7264696e6720746f2074686520726567756c6172206163636f756e74732e20626f6c6420726571756573747320616c6f6e0a327c4252415a494c7c317c7920616c6f6e6773696465206f66207468652070656e64696e67206465706f736974732e206361726566756c6c79207370656369616c207061636b61676573206172652061626f7574207468652069726f6e696320666f726765732e20736c796c79207370656369616c200a337c43414e4144417c317c6561732068616e672069726f6e69632c2073696c656e74207061636b616765732e20736c796c7920726567756c6172207061636b616765732061726520667572696f75736c79206f76657220746865207469746865732e20666c756666696c7920626f6c640a347c45475950547c347c792061626f766520746865206361726566756c6c7920756e757375616c207468656f646f6c697465732e2066696e616c206475676f7574732061726520717569636b6c79206163726f73732074686520667572696f75736c7920726567756c617220640a357c455448494f5049417c307c76656e207061636b616765732077616b6520717569636b6c792e20726567750a367c4652414e43457c337c726566756c6c792066696e616c2072657175657374732e20726567756c61722c2069726f6e690a377c4745524d414e597c337c6c20706c6174656c6574732e20726567756c6172206163636f756e747320782d7261793a20756e757375616c2c20726567756c6172206163636f0a387c494e4449417c327c737320657863757365732063616a6f6c6520736c796c79206163726f737320746865207061636b616765732e206465706f73697473207072696e742061726f756e0a397c494e444f4e455349417c327c20736c796c792065787072657373206173796d70746f7465732e20726567756c6172206465706f7369747320686167676c6520736c796c792e206361726566756c6c792069726f6e696320686f636b657920706c617965727320736c65657020626c697468656c792e206361726566756c6c0a31307c4952414e7c347c6566756c6c7920616c6f6e6773696465206f662074686520736c796c792066696e616c20646570656e64656e636965732e200a31317c495241517c347c6e6963206465706f7369747320626f6f73742061746f702074686520717569636b6c792066696e616c2072657175657374733f20717569636b6c7920726567756c610a31327c4a4150414e7c327c6f75736c792e2066696e616c2c20657870726573732067696674732063616a6f6c6520610a31337c4a4f5244414e7c347c6963206465706f736974732061726520626c697468656c792061626f757420746865206361726566756c6c7920726567756c61722070610a31347c4b454e59417c307c2070656e64696e67206578637573657320686167676c6520667572696f75736c79206465706f736974732e2070656e64696e672c20657870726573732070696e746f206265616e732077616b6520666c756666696c79207061737420740a31357c4d4f524f43434f7c307c726e732e20626c697468656c7920626f6c6420636f7572747320616d6f6e672074686520636c6f73656c7920726567756c6172207061636b616765732075736520667572696f75736c7920626f6c6420706c6174656c6574733f0a31367c4d4f5a414d42495155457c307c732e2069726f6e69632c20756e757375616c206173796d70746f7465732077616b6520626c697468656c7920720a31377c504552557c317c706c6174656c6574732e20626c697468656c792070656e64696e6720646570656e64656e636965732075736520666c756666696c79206163726f737320746865206576656e2070696e746f206265616e732e206361726566756c6c792073696c656e74206163636f756e0a31387c4348494e417c327c6320646570656e64656e636965732e20667572696f75736c792065787072657373206e6f746f726e697320736c65657020736c796c7920726567756c6172206163636f756e74732e20696465617320736c6565702e206465706f730a31397c524f4d414e49417c337c756c6172206173796d70746f746573206172652061626f75742074686520667572696f7573206d756c7469706c696572732e206578707265737320646570656e64656e63696573206e61672061626f7665207468652069726f6e6963616c6c792069726f6e6963206163636f756e740a32307c5341554449204152414249417c347c74732e2073696c656e7420726571756573747320686167676c652e20636c6f73656c792065787072657373207061636b6167657320736c656570206163726f73732074686520626c697468656c790a32317c564945544e414d7c327c68656c7920656e746963696e676c792065787072657373206163636f756e74732e206576656e2c2066696e616c200a32327c5255535349417c337c20726571756573747320616761696e73742074686520706c6174656c65747320757365206e65766572206163636f7264696e6720746f2074686520717569636b6c7920726567756c61722070696e740a32337c554e49544544204b494e47444f4d7c337c65616e7320626f6f7374206361726566756c6c79207370656369616c2072657175657374732e206163636f756e7473206172652e206361726566756c6c0a32347c554e49544544205354415445537c317c792066696e616c207061636b616765732e20736c6f7720666f7865732063616a6f6c6520717569636b6c792e20717569636b6c792073696c656e7420706c6174656c657473206272656163682069726f6e6963206163636f756e74732e20756e757375616c2070696e746f2062650a + nation_commit2 | \x307c414c47455249417c307c20686167676c652e206361726566756c6c792066696e616c206465706f736974732064657465637420736c796c7920616761690a317c415247454e54494e417c317c616c20666f7865732070726f6d69736520736c796c79206163636f7264696e6720746f2074686520726567756c6172206163636f756e74732e20626f6c6420726571756573747320616c6f6e0a327c4252415a494c7c317c7920616c6f6e6773696465206f66207468652070656e64696e67206465706f736974732e206361726566756c6c79207370656369616c207061636b61676573206172652061626f7574207468652069726f6e696320666f726765732e20736c796c79207370656369616c200a337c43414e4144417c317c6561732068616e672069726f6e69632c2073696c656e74207061636b616765732e20736c796c7920726567756c6172207061636b616765732061726520667572696f75736c79206f76657220746865207469746865732e20666c756666696c7920626f6c640a347c45475950547c347c792061626f766520746865206361726566756c6c7920756e757375616c207468656f646f6c697465732e2066696e616c206475676f7574732061726520717569636b6c79206163726f73732074686520667572696f75736c7920726567756c617220640a357c455448494f5049417c307c76656e207061636b616765732077616b6520717569636b6c792e20726567750a367c4652414e43457c337c726566756c6c792066696e616c2072657175657374732e20726567756c61722c2069726f6e690a377c4745524d414e597c337c6c20706c6174656c6574732e20726567756c6172206163636f756e747320782d7261793a20756e757375616c2c20726567756c6172206163636f0a387c494e4449417c327c737320657863757365732063616a6f6c6520736c796c79206163726f737320746865207061636b616765732e206465706f73697473207072696e742061726f756e0a397c494e444f4e455349417c327c20736c796c792065787072657373206173796d70746f7465732e20726567756c6172206465706f7369747320686167676c6520736c796c792e206361726566756c6c792069726f6e696320686f636b657920706c617965727320736c65657020626c697468656c792e206361726566756c6c0a31307c4952414e7c347c6566756c6c7920616c6f6e6773696465206f662074686520736c796c792066696e616c20646570656e64656e636965732e200a31317c495241517c347c6e6963206465706f7369747320626f6f73742061746f702074686520717569636b6c792066696e616c2072657175657374733f20717569636b6c7920726567756c610a31327c4a4150414e7c327c6f75736c792e2066696e616c2c20657870726573732067696674732063616a6f6c6520610a31337c4a4f5244414e7c347c6963206465706f736974732061726520626c697468656c792061626f757420746865206361726566756c6c7920726567756c61722070610a31347c4b454e59417c307c2070656e64696e67206578637573657320686167676c6520667572696f75736c79206465706f736974732e2070656e64696e672c20657870726573732070696e746f206265616e732077616b6520666c756666696c79207061737420740a31357c4d4f524f43434f7c307c726e732e20626c697468656c7920626f6c6420636f7572747320616d6f6e672074686520636c6f73656c7920726567756c6172207061636b616765732075736520667572696f75736c7920626f6c6420706c6174656c6574733f0a31367c4d4f5a414d42495155457c307c732e2069726f6e69632c20756e757375616c206173796d70746f7465732077616b6520626c697468656c7920720a31377c504552557c317c706c6174656c6574732e20626c697468656c792070656e64696e6720646570656e64656e636965732075736520666c756666696c79206163726f737320746865206576656e2070696e746f206265616e732e206361726566756c6c792073696c656e74206163636f756e0a31387c4348494e417c327c6320646570656e64656e636965732e20667572696f75736c792065787072657373206e6f746f726e697320736c65657020736c796c7920726567756c6172206163636f756e74732e20696465617320736c6565702e206465706f730a31397c524f4d414e49417c337c756c6172206173796d70746f746573206172652061626f75742074686520667572696f7573206d756c7469706c696572732e206578707265737320646570656e64656e63696573206e61672061626f7665207468652069726f6e6963616c6c792069726f6e6963206163636f756e740a32307c5341554449204152414249417c347c74732e2073696c656e7420726571756573747320686167676c652e20636c6f73656c792065787072657373207061636b6167657320736c656570206163726f73732074686520626c697468656c790a32317c564945544e414d7c327c68656c7920656e746963696e676c792065787072657373206163636f756e74732e206576656e2c2066696e616c200a32327c5255535349417c337c20726571756573747320616761696e73742074686520706c6174656c65747320757365206e65766572206163636f7264696e6720746f2074686520717569636b6c7920726567756c61722070696e740a32337c554e49544544204b494e47444f4d7c337c65616e7320626f6f7374206361726566756c6c79207370656369616c2072657175657374732e206163636f756e7473206172652e206361726566756c6c0a32347c554e49544544205354415445537c317c792066696e616c207061636b616765732e20736c6f7720666f7865732063616a6f6c6520717569636b6c792e20717569636b6c792073696c656e7420706c6174656c657473206272656163682069726f6e6963206163636f756e74732e20756e757375616c2070696e746f2062650a +(2 rows) + +BEGIN; +SELECT remove_file('dir_table4', 'nation_commit'); + remove_file +------------- + t +(1 row) + +SELECT relative_path, content FROM directory_table('dir_table4') ORDER BY 1; + relative_path | content +----------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + nation_commit2 | \x307c414c47455249417c307c20686167676c652e206361726566756c6c792066696e616c206465706f736974732064657465637420736c796c7920616761690a317c415247454e54494e417c317c616c20666f7865732070726f6d69736520736c796c79206163636f7264696e6720746f2074686520726567756c6172206163636f756e74732e20626f6c6420726571756573747320616c6f6e0a327c4252415a494c7c317c7920616c6f6e6773696465206f66207468652070656e64696e67206465706f736974732e206361726566756c6c79207370656369616c207061636b61676573206172652061626f7574207468652069726f6e696320666f726765732e20736c796c79207370656369616c200a337c43414e4144417c317c6561732068616e672069726f6e69632c2073696c656e74207061636b616765732e20736c796c7920726567756c6172207061636b616765732061726520667572696f75736c79206f76657220746865207469746865732e20666c756666696c7920626f6c640a347c45475950547c347c792061626f766520746865206361726566756c6c7920756e757375616c207468656f646f6c697465732e2066696e616c206475676f7574732061726520717569636b6c79206163726f73732074686520667572696f75736c7920726567756c617220640a357c455448494f5049417c307c76656e207061636b616765732077616b6520717569636b6c792e20726567750a367c4652414e43457c337c726566756c6c792066696e616c2072657175657374732e20726567756c61722c2069726f6e690a377c4745524d414e597c337c6c20706c6174656c6574732e20726567756c6172206163636f756e747320782d7261793a20756e757375616c2c20726567756c6172206163636f0a387c494e4449417c327c737320657863757365732063616a6f6c6520736c796c79206163726f737320746865207061636b616765732e206465706f73697473207072696e742061726f756e0a397c494e444f4e455349417c327c20736c796c792065787072657373206173796d70746f7465732e20726567756c6172206465706f7369747320686167676c6520736c796c792e206361726566756c6c792069726f6e696320686f636b657920706c617965727320736c65657020626c697468656c792e206361726566756c6c0a31307c4952414e7c347c6566756c6c7920616c6f6e6773696465206f662074686520736c796c792066696e616c20646570656e64656e636965732e200a31317c495241517c347c6e6963206465706f7369747320626f6f73742061746f702074686520717569636b6c792066696e616c2072657175657374733f20717569636b6c7920726567756c610a31327c4a4150414e7c327c6f75736c792e2066696e616c2c20657870726573732067696674732063616a6f6c6520610a31337c4a4f5244414e7c347c6963206465706f736974732061726520626c697468656c792061626f757420746865206361726566756c6c7920726567756c61722070610a31347c4b454e59417c307c2070656e64696e67206578637573657320686167676c6520667572696f75736c79206465706f736974732e2070656e64696e672c20657870726573732070696e746f206265616e732077616b6520666c756666696c79207061737420740a31357c4d4f524f43434f7c307c726e732e20626c697468656c7920626f6c6420636f7572747320616d6f6e672074686520636c6f73656c7920726567756c6172207061636b616765732075736520667572696f75736c7920626f6c6420706c6174656c6574733f0a31367c4d4f5a414d42495155457c307c732e2069726f6e69632c20756e757375616c206173796d70746f7465732077616b6520626c697468656c7920720a31377c504552557c317c706c6174656c6574732e20626c697468656c792070656e64696e6720646570656e64656e636965732075736520666c756666696c79206163726f737320746865206576656e2070696e746f206265616e732e206361726566756c6c792073696c656e74206163636f756e0a31387c4348494e417c327c6320646570656e64656e636965732e20667572696f75736c792065787072657373206e6f746f726e697320736c65657020736c796c7920726567756c6172206163636f756e74732e20696465617320736c6565702e206465706f730a31397c524f4d414e49417c337c756c6172206173796d70746f746573206172652061626f75742074686520667572696f7573206d756c7469706c696572732e206578707265737320646570656e64656e63696573206e61672061626f7665207468652069726f6e6963616c6c792069726f6e6963206163636f756e740a32307c5341554449204152414249417c347c74732e2073696c656e7420726571756573747320686167676c652e20636c6f73656c792065787072657373207061636b6167657320736c656570206163726f73732074686520626c697468656c790a32317c564945544e414d7c327c68656c7920656e746963696e676c792065787072657373206163636f756e74732e206576656e2c2066696e616c200a32327c5255535349417c337c20726571756573747320616761696e73742074686520706c6174656c65747320757365206e65766572206163636f7264696e6720746f2074686520717569636b6c7920726567756c61722070696e740a32337c554e49544544204b494e47444f4d7c337c65616e7320626f6f7374206361726566756c6c79207370656369616c2072657175657374732e206163636f756e7473206172652e206361726566756c6c0a32347c554e49544544205354415445537c317c792066696e616c207061636b616765732e20736c6f7720666f7865732063616a6f6c6520717569636b6c792e20717569636b6c792073696c656e7420706c6174656c657473206272656163682069726f6e6963206163636f756e74732e20756e757375616c2070696e746f2062650a +(1 row) + +COMMIT; +SELECT relative_path, content FROM directory_table('dir_table4') ORDER BY 1; + relative_path | content +----------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + nation_commit2 | \x307c414c47455249417c307c20686167676c652e206361726566756c6c792066696e616c206465706f736974732064657465637420736c796c7920616761690a317c415247454e54494e417c317c616c20666f7865732070726f6d69736520736c796c79206163636f7264696e6720746f2074686520726567756c6172206163636f756e74732e20626f6c6420726571756573747320616c6f6e0a327c4252415a494c7c317c7920616c6f6e6773696465206f66207468652070656e64696e67206465706f736974732e206361726566756c6c79207370656369616c207061636b61676573206172652061626f7574207468652069726f6e696320666f726765732e20736c796c79207370656369616c200a337c43414e4144417c317c6561732068616e672069726f6e69632c2073696c656e74207061636b616765732e20736c796c7920726567756c6172207061636b616765732061726520667572696f75736c79206f76657220746865207469746865732e20666c756666696c7920626f6c640a347c45475950547c347c792061626f766520746865206361726566756c6c7920756e757375616c207468656f646f6c697465732e2066696e616c206475676f7574732061726520717569636b6c79206163726f73732074686520667572696f75736c7920726567756c617220640a357c455448494f5049417c307c76656e207061636b616765732077616b6520717569636b6c792e20726567750a367c4652414e43457c337c726566756c6c792066696e616c2072657175657374732e20726567756c61722c2069726f6e690a377c4745524d414e597c337c6c20706c6174656c6574732e20726567756c6172206163636f756e747320782d7261793a20756e757375616c2c20726567756c6172206163636f0a387c494e4449417c327c737320657863757365732063616a6f6c6520736c796c79206163726f737320746865207061636b616765732e206465706f73697473207072696e742061726f756e0a397c494e444f4e455349417c327c20736c796c792065787072657373206173796d70746f7465732e20726567756c6172206465706f7369747320686167676c6520736c796c792e206361726566756c6c792069726f6e696320686f636b657920706c617965727320736c65657020626c697468656c792e206361726566756c6c0a31307c4952414e7c347c6566756c6c7920616c6f6e6773696465206f662074686520736c796c792066696e616c20646570656e64656e636965732e200a31317c495241517c347c6e6963206465706f7369747320626f6f73742061746f702074686520717569636b6c792066696e616c2072657175657374733f20717569636b6c7920726567756c610a31327c4a4150414e7c327c6f75736c792e2066696e616c2c20657870726573732067696674732063616a6f6c6520610a31337c4a4f5244414e7c347c6963206465706f736974732061726520626c697468656c792061626f757420746865206361726566756c6c7920726567756c61722070610a31347c4b454e59417c307c2070656e64696e67206578637573657320686167676c6520667572696f75736c79206465706f736974732e2070656e64696e672c20657870726573732070696e746f206265616e732077616b6520666c756666696c79207061737420740a31357c4d4f524f43434f7c307c726e732e20626c697468656c7920626f6c6420636f7572747320616d6f6e672074686520636c6f73656c7920726567756c6172207061636b616765732075736520667572696f75736c7920626f6c6420706c6174656c6574733f0a31367c4d4f5a414d42495155457c307c732e2069726f6e69632c20756e757375616c206173796d70746f7465732077616b6520626c697468656c7920720a31377c504552557c317c706c6174656c6574732e20626c697468656c792070656e64696e6720646570656e64656e636965732075736520666c756666696c79206163726f737320746865206576656e2070696e746f206265616e732e206361726566756c6c792073696c656e74206163636f756e0a31387c4348494e417c327c6320646570656e64656e636965732e20667572696f75736c792065787072657373206e6f746f726e697320736c65657020736c796c7920726567756c6172206163636f756e74732e20696465617320736c6565702e206465706f730a31397c524f4d414e49417c337c756c6172206173796d70746f746573206172652061626f75742074686520667572696f7573206d756c7469706c696572732e206578707265737320646570656e64656e63696573206e61672061626f7665207468652069726f6e6963616c6c792069726f6e6963206163636f756e740a32307c5341554449204152414249417c347c74732e2073696c656e7420726571756573747320686167676c652e20636c6f73656c792065787072657373207061636b6167657320736c656570206163726f73732074686520626c697468656c790a32317c564945544e414d7c327c68656c7920656e746963696e676c792065787072657373206163636f756e74732e206576656e2c2066696e616c200a32327c5255535349417c337c20726571756573747320616761696e73742074686520706c6174656c65747320757365206e65766572206163636f7264696e6720746f2074686520717569636b6c7920726567756c61722070696e740a32337c554e49544544204b494e47444f4d7c337c65616e7320626f6f7374206361726566756c6c79207370656369616c2072657175657374732e206163636f756e7473206172652e206361726566756c6c0a32347c554e49544544205354415445537c317c792066696e616c207061636b616765732e20736c6f7720666f7865732063616a6f6c6520717569636b6c792e20717569636b6c792073696c656e7420706c6174656c657473206272656163682069726f6e6963206163636f756e74732e20756e757375616c2070696e746f2062650a +(1 row) + +BEGIN; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +----------------+-------- + nation_commit2 | nation +(1 row) + +UPDATE dir_table4 SET tag = 'nation_updated' WHERE relative_path = 'nation_commit2'; +COMMIT; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +----------------+---------------- + nation_commit2 | nation_updated +(1 row) + +-- Test transaction rollback of directory table manipulation +BEGIN; +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_rollback'; +SELECT relative_path, content FROM directory_table('dir_table4') ORDER BY 1; + relative_path | content +-----------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + nation_commit2 | \x307c414c47455249417c307c20686167676c652e206361726566756c6c792066696e616c206465706f736974732064657465637420736c796c7920616761690a317c415247454e54494e417c317c616c20666f7865732070726f6d69736520736c796c79206163636f7264696e6720746f2074686520726567756c6172206163636f756e74732e20626f6c6420726571756573747320616c6f6e0a327c4252415a494c7c317c7920616c6f6e6773696465206f66207468652070656e64696e67206465706f736974732e206361726566756c6c79207370656369616c207061636b61676573206172652061626f7574207468652069726f6e696320666f726765732e20736c796c79207370656369616c200a337c43414e4144417c317c6561732068616e672069726f6e69632c2073696c656e74207061636b616765732e20736c796c7920726567756c6172207061636b616765732061726520667572696f75736c79206f76657220746865207469746865732e20666c756666696c7920626f6c640a347c45475950547c347c792061626f766520746865206361726566756c6c7920756e757375616c207468656f646f6c697465732e2066696e616c206475676f7574732061726520717569636b6c79206163726f73732074686520667572696f75736c7920726567756c617220640a357c455448494f5049417c307c76656e207061636b616765732077616b6520717569636b6c792e20726567750a367c4652414e43457c337c726566756c6c792066696e616c2072657175657374732e20726567756c61722c2069726f6e690a377c4745524d414e597c337c6c20706c6174656c6574732e20726567756c6172206163636f756e747320782d7261793a20756e757375616c2c20726567756c6172206163636f0a387c494e4449417c327c737320657863757365732063616a6f6c6520736c796c79206163726f737320746865207061636b616765732e206465706f73697473207072696e742061726f756e0a397c494e444f4e455349417c327c20736c796c792065787072657373206173796d70746f7465732e20726567756c6172206465706f7369747320686167676c6520736c796c792e206361726566756c6c792069726f6e696320686f636b657920706c617965727320736c65657020626c697468656c792e206361726566756c6c0a31307c4952414e7c347c6566756c6c7920616c6f6e6773696465206f662074686520736c796c792066696e616c20646570656e64656e636965732e200a31317c495241517c347c6e6963206465706f7369747320626f6f73742061746f702074686520717569636b6c792066696e616c2072657175657374733f20717569636b6c7920726567756c610a31327c4a4150414e7c327c6f75736c792e2066696e616c2c20657870726573732067696674732063616a6f6c6520610a31337c4a4f5244414e7c347c6963206465706f736974732061726520626c697468656c792061626f757420746865206361726566756c6c7920726567756c61722070610a31347c4b454e59417c307c2070656e64696e67206578637573657320686167676c6520667572696f75736c79206465706f736974732e2070656e64696e672c20657870726573732070696e746f206265616e732077616b6520666c756666696c79207061737420740a31357c4d4f524f43434f7c307c726e732e20626c697468656c7920626f6c6420636f7572747320616d6f6e672074686520636c6f73656c7920726567756c6172207061636b616765732075736520667572696f75736c7920626f6c6420706c6174656c6574733f0a31367c4d4f5a414d42495155457c307c732e2069726f6e69632c20756e757375616c206173796d70746f7465732077616b6520626c697468656c7920720a31377c504552557c317c706c6174656c6574732e20626c697468656c792070656e64696e6720646570656e64656e636965732075736520666c756666696c79206163726f737320746865206576656e2070696e746f206265616e732e206361726566756c6c792073696c656e74206163636f756e0a31387c4348494e417c327c6320646570656e64656e636965732e20667572696f75736c792065787072657373206e6f746f726e697320736c65657020736c796c7920726567756c6172206163636f756e74732e20696465617320736c6565702e206465706f730a31397c524f4d414e49417c337c756c6172206173796d70746f746573206172652061626f75742074686520667572696f7573206d756c7469706c696572732e206578707265737320646570656e64656e63696573206e61672061626f7665207468652069726f6e6963616c6c792069726f6e6963206163636f756e740a32307c5341554449204152414249417c347c74732e2073696c656e7420726571756573747320686167676c652e20636c6f73656c792065787072657373207061636b6167657320736c656570206163726f73732074686520626c697468656c790a32317c564945544e414d7c327c68656c7920656e746963696e676c792065787072657373206163636f756e74732e206576656e2c2066696e616c200a32327c5255535349417c337c20726571756573747320616761696e73742074686520706c6174656c65747320757365206e65766572206163636f7264696e6720746f2074686520717569636b6c7920726567756c61722070696e740a32337c554e49544544204b494e47444f4d7c337c65616e7320626f6f7374206361726566756c6c79207370656369616c2072657175657374732e206163636f756e7473206172652e206361726566756c6c0a32347c554e49544544205354415445537c317c792066696e616c207061636b616765732e20736c6f7720666f7865732063616a6f6c6520717569636b6c792e20717569636b6c792073696c656e7420706c6174656c657473206272656163682069726f6e6963206163636f756e74732e20756e757375616c2070696e746f2062650a + nation_rollback | \x307c414c47455249417c307c20686167676c652e206361726566756c6c792066696e616c206465706f736974732064657465637420736c796c7920616761690a317c415247454e54494e417c317c616c20666f7865732070726f6d69736520736c796c79206163636f7264696e6720746f2074686520726567756c6172206163636f756e74732e20626f6c6420726571756573747320616c6f6e0a327c4252415a494c7c317c7920616c6f6e6773696465206f66207468652070656e64696e67206465706f736974732e206361726566756c6c79207370656369616c207061636b61676573206172652061626f7574207468652069726f6e696320666f726765732e20736c796c79207370656369616c200a337c43414e4144417c317c6561732068616e672069726f6e69632c2073696c656e74207061636b616765732e20736c796c7920726567756c6172207061636b616765732061726520667572696f75736c79206f76657220746865207469746865732e20666c756666696c7920626f6c640a347c45475950547c347c792061626f766520746865206361726566756c6c7920756e757375616c207468656f646f6c697465732e2066696e616c206475676f7574732061726520717569636b6c79206163726f73732074686520667572696f75736c7920726567756c617220640a357c455448494f5049417c307c76656e207061636b616765732077616b6520717569636b6c792e20726567750a367c4652414e43457c337c726566756c6c792066696e616c2072657175657374732e20726567756c61722c2069726f6e690a377c4745524d414e597c337c6c20706c6174656c6574732e20726567756c6172206163636f756e747320782d7261793a20756e757375616c2c20726567756c6172206163636f0a387c494e4449417c327c737320657863757365732063616a6f6c6520736c796c79206163726f737320746865207061636b616765732e206465706f73697473207072696e742061726f756e0a397c494e444f4e455349417c327c20736c796c792065787072657373206173796d70746f7465732e20726567756c6172206465706f7369747320686167676c6520736c796c792e206361726566756c6c792069726f6e696320686f636b657920706c617965727320736c65657020626c697468656c792e206361726566756c6c0a31307c4952414e7c347c6566756c6c7920616c6f6e6773696465206f662074686520736c796c792066696e616c20646570656e64656e636965732e200a31317c495241517c347c6e6963206465706f7369747320626f6f73742061746f702074686520717569636b6c792066696e616c2072657175657374733f20717569636b6c7920726567756c610a31327c4a4150414e7c327c6f75736c792e2066696e616c2c20657870726573732067696674732063616a6f6c6520610a31337c4a4f5244414e7c347c6963206465706f736974732061726520626c697468656c792061626f757420746865206361726566756c6c7920726567756c61722070610a31347c4b454e59417c307c2070656e64696e67206578637573657320686167676c6520667572696f75736c79206465706f736974732e2070656e64696e672c20657870726573732070696e746f206265616e732077616b6520666c756666696c79207061737420740a31357c4d4f524f43434f7c307c726e732e20626c697468656c7920626f6c6420636f7572747320616d6f6e672074686520636c6f73656c7920726567756c6172207061636b616765732075736520667572696f75736c7920626f6c6420706c6174656c6574733f0a31367c4d4f5a414d42495155457c307c732e2069726f6e69632c20756e757375616c206173796d70746f7465732077616b6520626c697468656c7920720a31377c504552557c317c706c6174656c6574732e20626c697468656c792070656e64696e6720646570656e64656e636965732075736520666c756666696c79206163726f737320746865206576656e2070696e746f206265616e732e206361726566756c6c792073696c656e74206163636f756e0a31387c4348494e417c327c6320646570656e64656e636965732e20667572696f75736c792065787072657373206e6f746f726e697320736c65657020736c796c7920726567756c6172206163636f756e74732e20696465617320736c6565702e206465706f730a31397c524f4d414e49417c337c756c6172206173796d70746f746573206172652061626f75742074686520667572696f7573206d756c7469706c696572732e206578707265737320646570656e64656e63696573206e61672061626f7665207468652069726f6e6963616c6c792069726f6e6963206163636f756e740a32307c5341554449204152414249417c347c74732e2073696c656e7420726571756573747320686167676c652e20636c6f73656c792065787072657373207061636b6167657320736c656570206163726f73732074686520626c697468656c790a32317c564945544e414d7c327c68656c7920656e746963696e676c792065787072657373206163636f756e74732e206576656e2c2066696e616c200a32327c5255535349417c337c20726571756573747320616761696e73742074686520706c6174656c65747320757365206e65766572206163636f7264696e6720746f2074686520717569636b6c7920726567756c61722070696e740a32337c554e49544544204b494e47444f4d7c337c65616e7320626f6f7374206361726566756c6c79207370656369616c2072657175657374732e206163636f756e7473206172652e206361726566756c6c0a32347c554e49544544205354415445537c317c792066696e616c207061636b616765732e20736c6f7720666f7865732063616a6f6c6520717569636b6c792e20717569636b6c792073696c656e7420706c6174656c657473206272656163682069726f6e6963206163636f756e74732e20756e757375616c2070696e746f2062650a +(2 rows) + +ROLLBACK; +SELECT relative_path, content FROM directory_table('dir_table4') ORDER BY 1; + relative_path | content +----------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + nation_commit2 | \x307c414c47455249417c307c20686167676c652e206361726566756c6c792066696e616c206465706f736974732064657465637420736c796c7920616761690a317c415247454e54494e417c317c616c20666f7865732070726f6d69736520736c796c79206163636f7264696e6720746f2074686520726567756c6172206163636f756e74732e20626f6c6420726571756573747320616c6f6e0a327c4252415a494c7c317c7920616c6f6e6773696465206f66207468652070656e64696e67206465706f736974732e206361726566756c6c79207370656369616c207061636b61676573206172652061626f7574207468652069726f6e696320666f726765732e20736c796c79207370656369616c200a337c43414e4144417c317c6561732068616e672069726f6e69632c2073696c656e74207061636b616765732e20736c796c7920726567756c6172207061636b616765732061726520667572696f75736c79206f76657220746865207469746865732e20666c756666696c7920626f6c640a347c45475950547c347c792061626f766520746865206361726566756c6c7920756e757375616c207468656f646f6c697465732e2066696e616c206475676f7574732061726520717569636b6c79206163726f73732074686520667572696f75736c7920726567756c617220640a357c455448494f5049417c307c76656e207061636b616765732077616b6520717569636b6c792e20726567750a367c4652414e43457c337c726566756c6c792066696e616c2072657175657374732e20726567756c61722c2069726f6e690a377c4745524d414e597c337c6c20706c6174656c6574732e20726567756c6172206163636f756e747320782d7261793a20756e757375616c2c20726567756c6172206163636f0a387c494e4449417c327c737320657863757365732063616a6f6c6520736c796c79206163726f737320746865207061636b616765732e206465706f73697473207072696e742061726f756e0a397c494e444f4e455349417c327c20736c796c792065787072657373206173796d70746f7465732e20726567756c6172206465706f7369747320686167676c6520736c796c792e206361726566756c6c792069726f6e696320686f636b657920706c617965727320736c65657020626c697468656c792e206361726566756c6c0a31307c4952414e7c347c6566756c6c7920616c6f6e6773696465206f662074686520736c796c792066696e616c20646570656e64656e636965732e200a31317c495241517c347c6e6963206465706f7369747320626f6f73742061746f702074686520717569636b6c792066696e616c2072657175657374733f20717569636b6c7920726567756c610a31327c4a4150414e7c327c6f75736c792e2066696e616c2c20657870726573732067696674732063616a6f6c6520610a31337c4a4f5244414e7c347c6963206465706f736974732061726520626c697468656c792061626f757420746865206361726566756c6c7920726567756c61722070610a31347c4b454e59417c307c2070656e64696e67206578637573657320686167676c6520667572696f75736c79206465706f736974732e2070656e64696e672c20657870726573732070696e746f206265616e732077616b6520666c756666696c79207061737420740a31357c4d4f524f43434f7c307c726e732e20626c697468656c7920626f6c6420636f7572747320616d6f6e672074686520636c6f73656c7920726567756c6172207061636b616765732075736520667572696f75736c7920626f6c6420706c6174656c6574733f0a31367c4d4f5a414d42495155457c307c732e2069726f6e69632c20756e757375616c206173796d70746f7465732077616b6520626c697468656c7920720a31377c504552557c317c706c6174656c6574732e20626c697468656c792070656e64696e6720646570656e64656e636965732075736520666c756666696c79206163726f737320746865206576656e2070696e746f206265616e732e206361726566756c6c792073696c656e74206163636f756e0a31387c4348494e417c327c6320646570656e64656e636965732e20667572696f75736c792065787072657373206e6f746f726e697320736c65657020736c796c7920726567756c6172206163636f756e74732e20696465617320736c6565702e206465706f730a31397c524f4d414e49417c337c756c6172206173796d70746f746573206172652061626f75742074686520667572696f7573206d756c7469706c696572732e206578707265737320646570656e64656e63696573206e61672061626f7665207468652069726f6e6963616c6c792069726f6e6963206163636f756e740a32307c5341554449204152414249417c347c74732e2073696c656e7420726571756573747320686167676c652e20636c6f73656c792065787072657373207061636b6167657320736c656570206163726f73732074686520626c697468656c790a32317c564945544e414d7c327c68656c7920656e746963696e676c792065787072657373206163636f756e74732e206576656e2c2066696e616c200a32327c5255535349417c337c20726571756573747320616761696e73742074686520706c6174656c65747320757365206e65766572206163636f7264696e6720746f2074686520717569636b6c7920726567756c61722070696e740a32337c554e49544544204b494e47444f4d7c337c65616e7320626f6f7374206361726566756c6c79207370656369616c2072657175657374732e206163636f756e7473206172652e206361726566756c6c0a32347c554e49544544205354415445537c317c792066696e616c207061636b616765732e20736c6f7720666f7865732063616a6f6c6520717569636b6c792e20717569636b6c792073696c656e7420706c6174656c657473206272656163682069726f6e6963206163636f756e74732e20756e757375616c2070696e746f2062650a +(1 row) + +BEGIN; +SELECT remove_file('dir_table4', 'nation_commit2'); + remove_file +------------- + t +(1 row) + +SELECT relative_path, content FROM directory_table('dir_table4') ORDER BY 1; + relative_path | content +---------------+--------- +(0 rows) + +ROLLBACK; +SELECT relative_path, content FROM directory_table('dir_table4') ORDER BY 1; + relative_path | content +----------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + nation_commit2 | \x307c414c47455249417c307c20686167676c652e206361726566756c6c792066696e616c206465706f736974732064657465637420736c796c7920616761690a317c415247454e54494e417c317c616c20666f7865732070726f6d69736520736c796c79206163636f7264696e6720746f2074686520726567756c6172206163636f756e74732e20626f6c6420726571756573747320616c6f6e0a327c4252415a494c7c317c7920616c6f6e6773696465206f66207468652070656e64696e67206465706f736974732e206361726566756c6c79207370656369616c207061636b61676573206172652061626f7574207468652069726f6e696320666f726765732e20736c796c79207370656369616c200a337c43414e4144417c317c6561732068616e672069726f6e69632c2073696c656e74207061636b616765732e20736c796c7920726567756c6172207061636b616765732061726520667572696f75736c79206f76657220746865207469746865732e20666c756666696c7920626f6c640a347c45475950547c347c792061626f766520746865206361726566756c6c7920756e757375616c207468656f646f6c697465732e2066696e616c206475676f7574732061726520717569636b6c79206163726f73732074686520667572696f75736c7920726567756c617220640a357c455448494f5049417c307c76656e207061636b616765732077616b6520717569636b6c792e20726567750a367c4652414e43457c337c726566756c6c792066696e616c2072657175657374732e20726567756c61722c2069726f6e690a377c4745524d414e597c337c6c20706c6174656c6574732e20726567756c6172206163636f756e747320782d7261793a20756e757375616c2c20726567756c6172206163636f0a387c494e4449417c327c737320657863757365732063616a6f6c6520736c796c79206163726f737320746865207061636b616765732e206465706f73697473207072696e742061726f756e0a397c494e444f4e455349417c327c20736c796c792065787072657373206173796d70746f7465732e20726567756c6172206465706f7369747320686167676c6520736c796c792e206361726566756c6c792069726f6e696320686f636b657920706c617965727320736c65657020626c697468656c792e206361726566756c6c0a31307c4952414e7c347c6566756c6c7920616c6f6e6773696465206f662074686520736c796c792066696e616c20646570656e64656e636965732e200a31317c495241517c347c6e6963206465706f7369747320626f6f73742061746f702074686520717569636b6c792066696e616c2072657175657374733f20717569636b6c7920726567756c610a31327c4a4150414e7c327c6f75736c792e2066696e616c2c20657870726573732067696674732063616a6f6c6520610a31337c4a4f5244414e7c347c6963206465706f736974732061726520626c697468656c792061626f757420746865206361726566756c6c7920726567756c61722070610a31347c4b454e59417c307c2070656e64696e67206578637573657320686167676c6520667572696f75736c79206465706f736974732e2070656e64696e672c20657870726573732070696e746f206265616e732077616b6520666c756666696c79207061737420740a31357c4d4f524f43434f7c307c726e732e20626c697468656c7920626f6c6420636f7572747320616d6f6e672074686520636c6f73656c7920726567756c6172207061636b616765732075736520667572696f75736c7920626f6c6420706c6174656c6574733f0a31367c4d4f5a414d42495155457c307c732e2069726f6e69632c20756e757375616c206173796d70746f7465732077616b6520626c697468656c7920720a31377c504552557c317c706c6174656c6574732e20626c697468656c792070656e64696e6720646570656e64656e636965732075736520666c756666696c79206163726f737320746865206576656e2070696e746f206265616e732e206361726566756c6c792073696c656e74206163636f756e0a31387c4348494e417c327c6320646570656e64656e636965732e20667572696f75736c792065787072657373206e6f746f726e697320736c65657020736c796c7920726567756c6172206163636f756e74732e20696465617320736c6565702e206465706f730a31397c524f4d414e49417c337c756c6172206173796d70746f746573206172652061626f75742074686520667572696f7573206d756c7469706c696572732e206578707265737320646570656e64656e63696573206e61672061626f7665207468652069726f6e6963616c6c792069726f6e6963206163636f756e740a32307c5341554449204152414249417c347c74732e2073696c656e7420726571756573747320686167676c652e20636c6f73656c792065787072657373207061636b6167657320736c656570206163726f73732074686520626c697468656c790a32317c564945544e414d7c327c68656c7920656e746963696e676c792065787072657373206163636f756e74732e206576656e2c2066696e616c200a32327c5255535349417c337c20726571756573747320616761696e73742074686520706c6174656c65747320757365206e65766572206163636f7264696e6720746f2074686520717569636b6c7920726567756c61722070696e740a32337c554e49544544204b494e47444f4d7c337c65616e7320626f6f7374206361726566756c6c79207370656369616c2072657175657374732e206163636f756e7473206172652e206361726566756c6c0a32347c554e49544544205354415445537c317c792066696e616c207061636b616765732e20736c6f7720666f7865732063616a6f6c6520717569636b6c792e20717569636b6c792073696c656e7420706c6174656c657473206272656163682069726f6e6963206163636f756e74732e20756e757375616c2070696e746f2062650a +(1 row) + +BEGIN; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +----------------+---------------- + nation_commit2 | nation_updated +(1 row) + +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_rollback2' WITH TAG 'nation'; +UPDATE dir_table4 SET tag = 'nation_updated' WHERE relative_path = 'nation_rollback2'; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +------------------+---------------- + nation_commit2 | nation_updated + nation_rollback2 | nation_updated +(2 rows) + +ROLLBACK; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +----------------+---------------- + nation_commit2 | nation_updated +(1 row) + +-- Test subtransaction commit of directory table manipulation +BEGIN; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +----------------+---------------- + nation_commit2 | nation_updated +(1 row) + +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_subcommit' WITH TAG 'nation'; +SAVEPOINT s1; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit | nation +(2 rows) + +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_subcommit2'; +SAVEPOINT s2; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +-------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit | nation + nation_subcommit2 | +(3 rows) + +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_subcommit3'; +RELEASE SAVEPOINT s1; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +-------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit | nation + nation_subcommit2 | + nation_subcommit3 | +(4 rows) + +COMMIT; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +-------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit | nation + nation_subcommit2 | + nation_subcommit3 | +(4 rows) + +BEGIN; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +-------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit | nation + nation_subcommit2 | + nation_subcommit3 | +(4 rows) + +SELECT remove_file('dir_table4', 'nation_subcommit'); + remove_file +------------- + t +(1 row) + +SAVEPOINT s1; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +-------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit2 | + nation_subcommit3 | +(3 rows) + +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_subcommit'; +SAVEPOINT s2; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +-------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit | + nation_subcommit2 | + nation_subcommit3 | +(4 rows) + +RELEASE SAVEPOINT s1; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +-------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit | + nation_subcommit2 | + nation_subcommit3 | +(4 rows) + +COMMIT; +BEGIN; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +-------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit | + nation_subcommit2 | + nation_subcommit3 | +(4 rows) + +SELECT remove_file('dir_table4', 'nation_subcommit'); + remove_file +------------- + t +(1 row) + +SAVEPOINT s1; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +-------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit2 | + nation_subcommit3 | +(3 rows) + +SELECT remove_file('dir_table4', 'nation_subcommit2'); + remove_file +------------- + t +(1 row) + +SAVEPOINT s2; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +-------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit3 | +(2 rows) + +RELEASE SAVEPOINT s2; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +-------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit3 | +(2 rows) + +COMMIT; +BEGIN; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +-------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit3 | +(2 rows) + +SELECT remove_file('dir_table4', 'nation_subcommit2'); + remove_file +------------- + f +(1 row) + +SAVEPOINT s1; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +-------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit3 | +(2 rows) + +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_subcommit4'; +SAVEPOINT s2; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +-------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit3 | + nation_subcommit4 | +(3 rows) + +ROLLBACK TO SAVEPOINT s1; +COMMIT; +-- Test subtransaction rollback of directory table manipulation +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_subrollback1'; +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_subrollback2'; +BEGIN; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +---------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit3 | + nation_subrollback1 | + nation_subrollback2 | +(4 rows) + +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_subrollback3'; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +---------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit3 | + nation_subrollback1 | + nation_subrollback2 | + nation_subrollback3 | +(5 rows) + +SAVEPOINT s1; +SELECT remove_file('dir_table4', 'nation_subrollback1'); + remove_file +------------- + t +(1 row) + +SAVEPOINT s2; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +---------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit3 | + nation_subrollback2 | + nation_subrollback3 | +(4 rows) + +ROLLBACK; +BEGIN; +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_subrollback4'; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +---------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit3 | + nation_subrollback1 | + nation_subrollback2 | + nation_subrollback4 | +(5 rows) + +SAVEPOINT s1; +SELECT remove_file('dir_table4', 'nation_subrollback4'); + remove_file +------------- + t +(1 row) + +SAVEPOINT s2; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +---------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit3 | + nation_subrollback1 | + nation_subrollback2 | +(4 rows) + +RELEASE SAVEPOINT s1; +ROLLBACK; +BEGIN; +SELECT remove_file('dir_table4', 'nation_subrollback2'); + remove_file +------------- + t +(1 row) + +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_subrollback5'; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +---------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit3 | + nation_subrollback1 | + nation_subrollback5 | +(4 rows) + +SAVEPOINT s1; +SELECT remove_file('dir_table4', 'nation_subrollback5'); + remove_file +------------- + t +(1 row) + +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +---------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit3 | + nation_subrollback1 | +(3 rows) + +ROLLBACK TO SAVEPOINT s1; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +---------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit3 | + nation_subrollback1 | + nation_subrollback5 | +(4 rows) + +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_subrollback6'; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +---------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit3 | + nation_subrollback1 | + nation_subrollback5 | + nation_subrollback6 | +(5 rows) + +SAVEPOINT s2; +ROLLBACK; +-- clean up +DROP DIRECTORY TABLE IF EXISTS dir_table1; +DROP DIRECTORY TABLE IF EXISTS dir_table2; +DROP DIRECTORY TABLE IF EXISTS dir_table3; +DROP DIRECTORY TABLE IF EXISTS dir_table4; +DROP DIRECTORY TABLE IF EXISTS dir_table5; +NOTICE: directory table "dir_table5" does not exist, skipping +DROP DIRECTORY TABLE IF EXISTS dir_table6; +DROP FUNCTION IF EXISTS trigtest; +DROP STORAGE USER MAPPING IF EXISTS FOR CURRENT_USER STORAGE SERVER oss_server1; +DROP STORAGE USER MAPPING IF EXISTS FOR CURRENT_USER STORAGE SERVER oss_server2; +NOTICE: storage user mapping for "gpadmin" does not exist for storage server "oss_server2", skipping +DROP STORAGE USER MAPPING IF EXISTS FOR CURRENT_USER STORAGE SERVER oss_server3; +DROP STORAGE USER MAPPING IF EXISTS FOR CURRENT_USER STORAGE SERVER oss_server4; +NOTICE: storage server "oss_server4" does not exist, skipping +DROP STORAGE USER MAPPING IF EXISTS FOR test_dirtable1 STORAGE SERVER oss_server1; +NOTICE: storage user mapping for "test_dirtable1" does not exist for storage server "oss_server1", skipping +DROP STORAGE USER MAPPING IF EXISTS FOR test_dirtable1 STORAGE SERVER oss_server2; +DROP STORAGE USER MAPPING IF EXISTS FOR test_dirtable1 STORAGE SERVER oss_server3; +DROP STORAGE USER MAPPING IF EXISTS FOR test_dirtable2 STORAGE SERVER oss_server3; +DROP STORAGE USER MAPPING IF EXISTS FOR test_dirtable3 STORAGE SERVER oss_server8; +DROP STORAGE SERVER IF EXISTS oss_server1; +DROP STORAGE SERVER IF EXISTS oss_server2; +DROP STORAGE SERVER IF EXISTS oss_server3; +DROP STORAGE SERVER IF EXISTS oss_server4; +NOTICE: storage server "oss_server4" not exists, skipping +DROP STORAGE SERVER IF EXISTS oss_server5; +DROP STORAGE SERVER IF EXISTS oss_server6; +DROP STORAGE SERVER IF EXISTS oss_server7; +DROP STORAGE SERVER IF EXISTS oss_server8; +DROP STORAGE SERVER IF EXISTS oss_server9; +NOTICE: storage server "oss_server9" not exists, skipping +DROP STORAGE SERVER IF EXISTS oss_server10; +NOTICE: storage server "oss_server10" not exists, skipping +DROP STORAGE SERVER IF EXISTS oss_server11; +DROP STORAGE SERVER IF EXISTS oss_server12; +DROP STORAGE SERVER IF EXISTS oss_server13; +NOTICE: storage server "oss_server13" not exists, skipping +SELECT srvname, srvacl, srvoptions FROM gp_storage_server; + srvname | srvacl | srvoptions +---------+--------+------------ +(0 rows) + +DROP USER test_dirtable1; +DROP USER test_dirtable2; +DROP USER test_dirtable3; +DROP USER test_dirtable4; +DROP FUNCTION IF EXISTS file_content; +DROP FUNCTION IF EXISTS file_md5; +DROP FUNCTION IF EXISTS md5_equal; +DROP DATABASE dirtable_db; +DROP TRIGGER IF EXISTS trigtest_b_row_tg_dirtable_1 ON dir_table1; +NOTICE: relation "dir_table1" does not exist, skipping +DROP TRIGGER IF EXISTS trigtest_a_row_tg_dirtable_1 ON dir_table1; +NOTICE: relation "dir_table1" does not exist, skipping +DROP TRIGGER IF EXISTS trigtest_b_stmt_tg_dirtable_1 ON dir_table1; +NOTICE: relation "dir_table1" does not exist, skipping +DROP TRIGGER IF EXISTS trigtest_a_stmt_tg_dirtable_1 ON dir_table1; +NOTICE: relation "dir_table1" does not exist, skipping +DROP TABLESPACE directory_tblspc; diff --git a/src/test/regress/output/directory_table_optimizer.source b/src/test/regress/output/directory_table_optimizer.source new file mode 100644 index 00000000000..66fdb0a39cc --- /dev/null +++ b/src/test/regress/output/directory_table_optimizer.source @@ -0,0 +1,1842 @@ +-- +-- Test for directory table +-- +-- Display pg_tablespace, pg_directory_table, gp_storage_server, gp_storage_user_mapping catalog +\d+ pg_tablespace; + Table "pg_catalog.pg_tablespace" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +-------------------+-----------+-----------+----------+---------+----------+--------------+------------- + oid | oid | | not null | | plain | | + spcname | name | | not null | | plain | | + spcowner | oid | | not null | | plain | | + spcacl | aclitem[] | | | | extended | | + spcoptions | text[] | C | | | extended | | + spcfilehandlersrc | text | C | | | extended | | + spcfilehandlerbin | text | C | | | extended | | +Indexes: + "pg_tablespace_oid_index" PRIMARY KEY, btree (oid), tablespace "pg_global" + "pg_tablespace_spcname_index" UNIQUE CONSTRAINT, btree (spcname), tablespace "pg_global" +Tablespace: "pg_global" + +\d+ pg_directory_table; + Table "pg_catalog.pg_directory_table" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------------+------+-----------+----------+---------+----------+--------------+------------- + dtrelid | oid | | not null | | plain | | + dttablespace | oid | | not null | | plain | | + dtlocation | text | C | | | extended | | +Indexes: + "pg_directory_table_relid_index" PRIMARY KEY, btree (dtrelid) + +\d+ gp_storage_server; + Table "pg_catalog.gp_storage_server" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +------------+-----------+-----------+----------+---------+----------+--------------+------------- + oid | oid | | not null | | plain | | + srvname | name | | not null | | plain | | + srvowner | oid | | not null | | plain | | + srvacl | aclitem[] | | | | extended | | + srvoptions | text[] | C | | | extended | | +Indexes: + "gp_storage_server_oid_index" PRIMARY KEY, btree (oid), tablespace "pg_global" + "gp_storage_server_name_index" UNIQUE CONSTRAINT, btree (srvname), tablespace "pg_global" +Tablespace: "pg_global" + +\d+ gp_storage_user_mapping; + Table "pg_catalog.gp_storage_user_mapping" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +-----------+--------+-----------+----------+---------+----------+--------------+------------- + oid | oid | | not null | | plain | | + umuser | oid | | not null | | plain | | + umserver | oid | | not null | | plain | | + umoptions | text[] | C | | | extended | | +Indexes: + "gp_storage_user_mapping_oid_index" PRIMARY KEY, btree (oid), tablespace "pg_global" + "gp_storage_user_mapping_server_index" UNIQUE CONSTRAINT, btree (umuser, umserver), tablespace "pg_global" +Tablespace: "pg_global" + +SELECT relname, relisshared, relpersistence, relkind FROM pg_class WHERE relname = 'pg_directory_table'; + relname | relisshared | relpersistence | relkind +--------------------+-------------+----------------+--------- + pg_directory_table | f | p | r +(1 row) + +SELECT relname, relisshared, relpersistence, relkind FROM pg_class WHERE relname = 'gp_storage_server'; + relname | relisshared | relpersistence | relkind +-------------------+-------------+----------------+--------- + gp_storage_server | t | p | r +(1 row) + +SELECT relname, relisshared, relpersistence, relkind FROM pg_class WHERE relname = 'gp_storage_user_mapping'; + relname | relisshared | relpersistence | relkind +-------------------------+-------------+----------------+--------- + gp_storage_user_mapping | t | p | r +(1 row) + +-- CREATE TABLESPACE +CREATE TABLESPACE directory_tblspc LOCATION '@testtablespace@'; +-- CREATE DATABASE +CREATE DATABASE dirtable_db; +\c dirtable_db +\d+ pg_directory_table; + Table "pg_catalog.pg_directory_table" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +--------------+------+-----------+----------+---------+----------+--------------+------------- + dtrelid | oid | | not null | | plain | | + dttablespace | oid | | not null | | plain | | + dtlocation | text | C | | | extended | | +Indexes: + "pg_directory_table_relid_index" PRIMARY KEY, btree (dtrelid) + +\d+ gp_storage_server; + Table "pg_catalog.gp_storage_server" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +------------+-----------+-----------+----------+---------+----------+--------------+------------- + oid | oid | | not null | | plain | | + srvname | name | | not null | | plain | | + srvowner | oid | | not null | | plain | | + srvacl | aclitem[] | | | | extended | | + srvoptions | text[] | C | | | extended | | +Indexes: + "gp_storage_server_oid_index" PRIMARY KEY, btree (oid), tablespace "pg_global" + "gp_storage_server_name_index" UNIQUE CONSTRAINT, btree (srvname), tablespace "pg_global" +Tablespace: "pg_global" + +\d+ gp_storage_user_mapping; + Table "pg_catalog.gp_storage_user_mapping" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +-----------+--------+-----------+----------+---------+----------+--------------+------------- + oid | oid | | not null | | plain | | + umuser | oid | | not null | | plain | | + umserver | oid | | not null | | plain | | + umoptions | text[] | C | | | extended | | +Indexes: + "gp_storage_user_mapping_oid_index" PRIMARY KEY, btree (oid), tablespace "pg_global" + "gp_storage_user_mapping_server_index" UNIQUE CONSTRAINT, btree (umuser, umserver), tablespace "pg_global" +Tablespace: "pg_global" + +SELECT relname, relisshared, relpersistence, relkind FROM pg_class WHERE relname = 'pg_directory_table'; + relname | relisshared | relpersistence | relkind +--------------------+-------------+----------------+--------- + pg_directory_table | f | p | r +(1 row) + +SELECT relname, relisshared, relpersistence, relkind FROM pg_class WHERE relname = 'gp_storage_server'; + relname | relisshared | relpersistence | relkind +-------------------+-------------+----------------+--------- + gp_storage_server | t | p | r +(1 row) + +SELECT relname, relisshared, relpersistence, relkind FROM pg_class WHERE relname = 'gp_storage_user_mapping'; + relname | relisshared | relpersistence | relkind +-------------------------+-------------+----------------+--------- + gp_storage_user_mapping | t | p | r +(1 row) + +\c regression +-- CREATE USER for directory table +CREATE USER test_dirtable1; +NOTICE: resource queue required -- using default resource queue "pg_default" +CREATE USER test_dirtable2; +NOTICE: resource queue required -- using default resource queue "pg_default" +CREATE USER test_dirtable3; +NOTICE: resource queue required -- using default resource queue "pg_default" +CREATE USER test_dirtable4; +NOTICE: resource queue required -- using default resource queue "pg_default" +-- Test CREATE STORAGE SERVER +SELECT srvname, srvacl, srvoptions from gp_storage_server ORDER BY 1; + srvname | srvacl | srvoptions +---------+--------+------------ +(0 rows) + +CREATE STORAGE SERVER oss_server1; +CREATE STORAGE SERVER oss_server2 OPTIONS(protocal 'localhost'); +CREATE STORAGE SERVER oss_server3 OPTIONS(endpoint '127.0.0.1:9000'); +CREATE STORAGE SERVER oss_server4 OPTIONS(https 'true'); +CREATE STORAGE SERVER oss_server5 OPTIONS(virtual_host 'false'); +CREATE STORAGE SERVER oss_server6 OPTIONS(protocol 'qingstor', endpoint 'pek3b,qingstor.com'); +CREATE STORAGE SERVER oss_server7 OPTIONS(https 'false', virtual_host 'true'); +CREATE STORAGE SERVER oss_server8 OPTIONS(protocol 'hdfs', namenode '127.0.0.1:8020'); +CREATE STORAGE SERVER oss_server9 OWNER TO postgres; -- fail +ERROR: syntax error at or near "OWNER" +LINE 1: CREATE STORAGE SERVER oss_server9 OWNER TO postgres; + ^ +CREATE STORAGE SERVER IF NOT EXISTS oss_server10; +CREATE STORAGE SERVER IF NOT EXISTS oss_server11 OPTIONS(protocol 's3av2'); +CREATE STORAGE SERVER IF NOT EXISTS oss_server12 OPTIONS(protocol 's3av2', endpoint '127.0.0.1:9000', https 'false'); +CREATE STORAGE SERVER IF NOT EXISTS oss_server13 OWNER TO postgres; -- fail +ERROR: syntax error at or near "OWNER" +LINE 1: CREATE STORAGE SERVER IF NOT EXISTS oss_server13 OWNER TO po... + ^ +SELECT srvname, srvacl, srvoptions from gp_storage_server ORDER BY 1; + srvname | srvacl | srvoptions +--------------+--------+------------------------------------------------------ + oss_server1 | | + oss_server10 | | + oss_server11 | | {protocol=s3av2} + oss_server12 | | {protocol=s3av2,endpoint=127.0.0.1:9000,https=false} + oss_server2 | | {protocal=localhost} + oss_server3 | | {endpoint=127.0.0.1:9000} + oss_server4 | | {https=true} + oss_server5 | | {virtual_host=false} + oss_server6 | | {protocol=qingstor,"endpoint=pek3b,qingstor.com"} + oss_server7 | | {https=false,virtual_host=true} + oss_server8 | | {protocol=hdfs,namenode=127.0.0.1:8020} +(11 rows) + +\c dirtable_db +SELECT srvname, srvacl, srvoptions from gp_storage_server ORDER BY 1; + srvname | srvacl | srvoptions +--------------+--------+------------------------------------------------------ + oss_server1 | | + oss_server10 | | + oss_server11 | | {protocol=s3av2} + oss_server12 | | {protocol=s3av2,endpoint=127.0.0.1:9000,https=false} + oss_server2 | | {protocal=localhost} + oss_server3 | | {endpoint=127.0.0.1:9000} + oss_server4 | | {https=true} + oss_server5 | | {virtual_host=false} + oss_server6 | | {protocol=qingstor,"endpoint=pek3b,qingstor.com"} + oss_server7 | | {https=false,virtual_host=true} + oss_server8 | | {protocol=hdfs,namenode=127.0.0.1:8020} +(11 rows) + +\c regression +-- Test ALTER STORAGE SERVER +ALTER STORAGE SERVER oss_server1 OPTIONS(protocol 'aws'); +ALTER STORAGE SERVER oss_server1 OPTIONS(protocol 'test'); -- fail +ERROR: option "protocol" provided more than once +ALTER STORAGE SERVER oss_server2 OPTIONS(https 'true'); +ALTER STORAGE SERVER oss_server2 OPTIONS(https 'false', virtual_host 'true'); -- fail +ERROR: option "https" provided more than once +ALTER STORAGE SERVER oss_server2 OPTIONS(virtual_host 'true'); +ALTER STORAGE SERVER oss_server3 OPTIONS(endpoint '192.168.0.1'); -- fail +ERROR: option "endpoint" provided more than once +ALTER STORAGE SERVER oss_server4 OPTIONS(protocol 'localhost', virtual_host 'true'); +ALTER STORAGE SERVER oss_server4 OPTIONS(protocol 'qingstor'); -- fail +ERROR: option "protocol" provided more than once +ALTER STORAGE SERVER oss_server5; -- fail +ERROR: syntax error at or near ";" +LINE 1: ALTER STORAGE SERVER oss_server5; + ^ +ALTER STORAGE SERVER oss_server6 OWNER TO postgres; -- fail +ERROR: syntax error at or near "OWNER" +LINE 1: ALTER STORAGE SERVER oss_server6 OWNER TO postgres; + ^ +ALTER STORAGE SERVER IF EXISTS oss_server7 OPTIONS(endpoint '127.0.0.1:6555'); -- fail +ERROR: syntax error at or near "EXISTS" +LINE 1: ALTER STORAGE SERVER IF EXISTS oss_server7 OPTIONS(endpoint ... + ^ +ALTER STORAGE SERVER IF NOT EXISTS oss_server8 OPTIONS(virtual_host 'true'); -- fail +ERROR: syntax error at or near "NOT" +LINE 1: ALTER STORAGE SERVER IF NOT EXISTS oss_server8 OPTIONS(virtu... + ^ +SELECT srvname, srvacl, srvoptions from gp_storage_server ORDER BY 1; + srvname | srvacl | srvoptions +--------------+--------+------------------------------------------------------ + oss_server1 | | {protocol=aws} + oss_server10 | | + oss_server11 | | {protocol=s3av2} + oss_server12 | | {protocol=s3av2,endpoint=127.0.0.1:9000,https=false} + oss_server2 | | {protocal=localhost,https=true,virtual_host=true} + oss_server3 | | {endpoint=127.0.0.1:9000} + oss_server4 | | {https=true,protocol=localhost,virtual_host=true} + oss_server5 | | {virtual_host=false} + oss_server6 | | {protocol=qingstor,"endpoint=pek3b,qingstor.com"} + oss_server7 | | {https=false,virtual_host=true} + oss_server8 | | {protocol=hdfs,namenode=127.0.0.1:8020} +(11 rows) + +\c dirtable_db +SELECT srvname, srvacl, srvoptions from gp_storage_server ORDER BY 1; + srvname | srvacl | srvoptions +--------------+--------+------------------------------------------------------ + oss_server1 | | {protocol=aws} + oss_server10 | | + oss_server11 | | {protocol=s3av2} + oss_server12 | | {protocol=s3av2,endpoint=127.0.0.1:9000,https=false} + oss_server2 | | {protocal=localhost,https=true,virtual_host=true} + oss_server3 | | {endpoint=127.0.0.1:9000} + oss_server4 | | {https=true,protocol=localhost,virtual_host=true} + oss_server5 | | {virtual_host=false} + oss_server6 | | {protocol=qingstor,"endpoint=pek3b,qingstor.com"} + oss_server7 | | {https=false,virtual_host=true} + oss_server8 | | {protocol=hdfs,namenode=127.0.0.1:8020} +(11 rows) + +\c regression +-- Test CREATE STORAGE USER MAPPING +CREATE STORAGE USER MAPPING FOR CURRENT_USER; -- fail +ERROR: syntax error at or near ";" +LINE 1: CREATE STORAGE USER MAPPING FOR CURRENT_USER; + ^ +CREATE STORAGE USER MAPPING FOR CURRENT_USER STORAGE SERVER oss_server1; +CREATE STORAGE USER MAPPING FOR CURRENT_USER STORAGE SERVER oss_server1 +OPTIONS (accesskey 'KGFQWEFQQEFXVAEAWLLC', secretkey '0SJIWiIATh6jOlmAKr8DGq6hOAGBI1BnsnvgJmTs'); -- fail +ERROR: storage user mapping for "gpadmin" already exists for storage server "oss_server1" +CREATE STORAGE USER MAPPING IF NOT EXISTS FOR CURRENT_USER STORAGE SERVER oss_server1; +NOTICE: storage user mapping for "gpadmin" already exists for storage server "oss_server1", skipping +CREATE STORAGE USER MAPPING IF NOT EXISTS FOR CURRENT_USER STORAGE SERVER oss_server1 +OPTIONS (auth_method 'simple'); +NOTICE: storage user mapping for "gpadmin" already exists for storage server "oss_server1", skipping +CREATE STORAGE USER MAPPING FOR CURRENT_ROLE STORAGE SERVER oss_server2 +OPTIONS (accesskey 'EQEJIOJFAKQWESQEJIWQ', secretkey '0ADQiAxcaUJ2lMHipis80hsUEhdiqui82JhduOKE'); +CREATE STORAGE USER MAPPING FOR CURRENT_USER STORAGE SERVER oss_server2 +OPTIONS (accesskey 'KGFQWEFQQEFXVAEAWLLC', secretkey '0SJIWiIATh6jOlmAKr8DGq6hOAGBI1BnsnvgJmTs'); -- fail +ERROR: storage user mapping for "gpadmin" already exists for storage server "oss_server2" +CREATE STORAGE USER MAPPING FOR CURRENT_ROLE STORAGE SERVER oss_server3 +OPTIONS (accesskey 'EQEJIOJFAKQWESQEJIWQ', secretkey '0ADQiAxcaUJ2lMHipis80hsUEhdiqui82JhduOKE'); +CREATE STORAGE USER MAPPING FOR CURRENT_USER STORAGE SERVER oss_not_exits; -- fail +ERROR: server "oss_not_exits" does not exist +CREATE STORAGE USER MAPPING FOR CURRENT_USER STORAGE SERVER oss_not_exits +OPTIONS (accesskey 'KGFQWEFQQEFXVAEAWLLC', secretkey '0SJIWiIATh6jOlmAKr8DGq6hOAGBI1BnsnvgJmTs'); -- fail +ERROR: server "oss_not_exits" does not exist +CREATE STORAGE USER MAPPING FOR test_dirtable1 STORAGE SERVER oss_server1; +CREATE STORAGE USER MAPPING FOR test_dirtable1 STORAGE SERVER oss_server1 +OPTIONS (accesskey 'EQEJIOJFAKQWESQEJIWQ', secretkey '7KieQKdu02jHEUEjsqUYE83mx9OE2kdj2SJ72h6H'); -- fail +ERROR: storage user mapping for "test_dirtable1" already exists for storage server "oss_server1" +CREATE STORAGE USER MAPPING FOR test_dirtable1 STORAGE SERVER oss_server2 +OPTIONS (accesskey 'EQEJIOJFAKQWESQEJIWQ', secretkey '7KieQKdu02jHEUEjsqUYE83mx9OE2kdj2SJ72h6H'); +CREATE STORAGE USER MAPPING FOR test_dirtable1 STORAGE SERVER oss_server3 +OPTIONS (accesskey 'EQEJIOJFAKQWESQEJIWQ', secretkey '7KieQKdu02jHEUEjsqUYE83mx9OE2kdj2SJ72h6H'); +CREATE STORAGE USER MAPPING FOR no_exist_user STORAGE SERVER oss_server1; -- fail +ERROR: role "no_exist_user" does not exist +CREATE STORAGE USER MAPPING FOR no_exist_user STORAGE SERVER oss_server1 +OPTIONS (accesskey 'EQEJIOJFAKQWESQEJIWQ', secretkey '7KieQKdu02jHEUEjsqUYE83mx9OE2kdj2SJ72h6H'); -- fail +ERROR: role "no_exist_user" does not exist +CREATE STORAGE USER MAPPING IF NOT EXISTS FOR CURRENT_USER STORAGE SERVER oss_server1 +OPTIONS (accesskey 'KGFQWEFQQEFXVAEAWLLC', secretkey '0SJIWiIATh6jOlmAKr8DGq6hOAGBI1BnsnvgJmTs'); -- skip +NOTICE: storage user mapping for "gpadmin" already exists for storage server "oss_server1", skipping +CREATE STORAGE USER MAPPING IF NOT EXISTS FOR test_dirtable2 STORAGE SERVER oss_server3 +OPTIONS (endpoint '127.0.0.1:6555'); +CREATE STORAGE USER MAPPING IF NOT EXISTS FOR test_dirtable3 STORAGE SERVER oss_server8 +OPTIONS (auth_method 'simple'); +CREATE STORAGE USER MAPPING IF NOT EXISTS FOR no_exist_user STORAGE SERVER oss_server1; -- fail +ERROR: role "no_exist_user" does not exist +SELECT umoptions FROM gp_storage_user_mapping ORDER BY 1; + umoptions +------------------------------------------------------------------------------------- + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=0ADQiAxcaUJ2lMHipis80hsUEhdiqui82JhduOKE} + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=0ADQiAxcaUJ2lMHipis80hsUEhdiqui82JhduOKE} + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=7KieQKdu02jHEUEjsqUYE83mx9OE2kdj2SJ72h6H} + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=7KieQKdu02jHEUEjsqUYE83mx9OE2kdj2SJ72h6H} + {auth_method=simple} + {endpoint=127.0.0.1:6555} + + +(8 rows) + +\c dirtable_db +SELECT umoptions FROM gp_storage_user_mapping ORDER BY 1; + umoptions +------------------------------------------------------------------------------------- + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=0ADQiAxcaUJ2lMHipis80hsUEhdiqui82JhduOKE} + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=0ADQiAxcaUJ2lMHipis80hsUEhdiqui82JhduOKE} + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=7KieQKdu02jHEUEjsqUYE83mx9OE2kdj2SJ72h6H} + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=7KieQKdu02jHEUEjsqUYE83mx9OE2kdj2SJ72h6H} + {auth_method=simple} + {endpoint=127.0.0.1:6555} + + +(8 rows) + +\c regression +-- Test ALTER STORAGE USER MAPPING +ALTER STORAGE USER MAPPING FOR CURRENT_USER STORAGE SERVER oss_server1; -- fail +ERROR: syntax error at or near ";" +LINE 1: ...GE USER MAPPING FOR CURRENT_USER STORAGE SERVER oss_server1; + ^ +ALTER STORAGE USER MAPPING FOR CURRENT_USER STORAGE SERVER oss_server1 +OPTIONS (accesskey 'KGFQWEFQQEFXVAEAWLLC', secretkey '0SJIWiIATh6jOlmAKr8DGq6hOAGBI1BnsnvgJmTs'); +ALTER STORAGE USER MAPPING FOR CURRENT_ROLE STORAGE SERVER oss_server1 +OPTIONS (accesskey 'EQEJIOJFAKQWESQEJIWQ'); -- fail +ERROR: option "accesskey" provided more than once +ALTER STORAGE USER MAPPING FOR CURRENT_USER STORAGE SERVER oss_server1 +OPTIONS (auth_method 'simple'); +ALTER STORAGE USER MAPPING FOR CURRENT_USER STORAGE SERVER oss_server2 +OPTIONS (accesskey 'EQEJIOJFAKQWESQEJIWQ', secretkey '0ADQiAxcaUJ2lMHipis80hsUEhdiqui82JhduOKE'); -- fail +ERROR: option "accesskey" provided more than once +ALTER STORAGE USER MAPPING IF EXISTS FOR CURRENT_USER STORAGE SERVER server_not_exists +OPTIONS (accesskey 'EQEJIOJFAKQWESQEJIWQ', secretkey '0ADQiAxcaUJ2lMHipis80hsUEhdiqui82JhduOKE'); -- fail +ERROR: syntax error at or near "IF" +LINE 1: ALTER STORAGE USER MAPPING IF EXISTS FOR CURRENT_USER STORAG... + ^ +ALTER STORAGE USER MAPPING IF EXISTS FOR no_exist_user STORAGE SERVER oss_server1 +OPTIONS (accesskey 'EQEJIOJFAKQWESQEJIWQ', secretkey '0ADQiAxcaUJ2lMHipis80hsUEhdiqui82JhduOKE'); -- fail +ERROR: syntax error at or near "IF" +LINE 1: ALTER STORAGE USER MAPPING IF EXISTS FOR no_exist_user STORA... + ^ +ALTER STORAGE USER MAPPING IF NOT EXISTS FOR test_dirtable1 STORAGE SERVER oss_server3 +OPTIONS (auth_method 'simple'); -- fail +ERROR: syntax error at or near "IF" +LINE 1: ALTER STORAGE USER MAPPING IF NOT EXISTS FOR test_dirtable1 ... + ^ +SELECT umoptions FROM gp_storage_user_mapping ORDER BY 1; + umoptions +-------------------------------------------------------------------------------------------------------- + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=0ADQiAxcaUJ2lMHipis80hsUEhdiqui82JhduOKE} + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=0ADQiAxcaUJ2lMHipis80hsUEhdiqui82JhduOKE} + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=7KieQKdu02jHEUEjsqUYE83mx9OE2kdj2SJ72h6H} + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=7KieQKdu02jHEUEjsqUYE83mx9OE2kdj2SJ72h6H} + {accesskey=KGFQWEFQQEFXVAEAWLLC,secretkey=0SJIWiIATh6jOlmAKr8DGq6hOAGBI1BnsnvgJmTs,auth_method=simple} + {auth_method=simple} + {endpoint=127.0.0.1:6555} + +(8 rows) + +\c dirtable_db +SELECT umoptions FROM gp_storage_user_mapping ORDER BY 1; + umoptions +-------------------------------------------------------------------------------------------------------- + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=0ADQiAxcaUJ2lMHipis80hsUEhdiqui82JhduOKE} + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=0ADQiAxcaUJ2lMHipis80hsUEhdiqui82JhduOKE} + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=7KieQKdu02jHEUEjsqUYE83mx9OE2kdj2SJ72h6H} + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=7KieQKdu02jHEUEjsqUYE83mx9OE2kdj2SJ72h6H} + {accesskey=KGFQWEFQQEFXVAEAWLLC,secretkey=0SJIWiIATh6jOlmAKr8DGq6hOAGBI1BnsnvgJmTs,auth_method=simple} + {auth_method=simple} + {endpoint=127.0.0.1:6555} + +(8 rows) + +\c regression +-- Test DROP STORAGE USER MAPPING +DROP STORAGE USER MAPPING FOR CURRENT_USER; -- fail +ERROR: syntax error at or near ";" +LINE 1: DROP STORAGE USER MAPPING FOR CURRENT_USER; + ^ +DROP STORAGE USER MAPPING FOR CURRENT_USER STORAGE SERVER oss_server2; +DROP STORAGE USER MAPPING IF EXISTS FOR test_dirtable1 STORAGE SERVER oss_server1; +DROP STORAGE USER MAPPING IF EXISTS FOR test_dirtable2 STORAGE SERVER no_exist_server; +NOTICE: storage server "no_exist_server" does not exist, skipping +DROP STORAGE USER MAPPING FOR test_dirtable3 STORAGE SERVER no_exist_server; -- fail +ERROR: storage server "no_exist_server" does not exist +DROP STORAGE USER MAPPING FOR no_exist_user STORAGE SERVER oss_server1; -- fail +ERROR: role "no_exist_user" does not exist +DROP STORAGE USER MAPPING IF EXISTS FOR no_exist_user STORAGE SERVER oss_server1; -- skip +NOTICE: role "no_exist_user" does not exist, skipping +SELECT umoptions FROM gp_storage_user_mapping ORDER BY 1; + umoptions +-------------------------------------------------------------------------------------------------------- + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=0ADQiAxcaUJ2lMHipis80hsUEhdiqui82JhduOKE} + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=7KieQKdu02jHEUEjsqUYE83mx9OE2kdj2SJ72h6H} + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=7KieQKdu02jHEUEjsqUYE83mx9OE2kdj2SJ72h6H} + {accesskey=KGFQWEFQQEFXVAEAWLLC,secretkey=0SJIWiIATh6jOlmAKr8DGq6hOAGBI1BnsnvgJmTs,auth_method=simple} + {auth_method=simple} + {endpoint=127.0.0.1:6555} +(6 rows) + +\c dirtable_db +SELECT umoptions FROM gp_storage_user_mapping ORDER BY 1; + umoptions +-------------------------------------------------------------------------------------------------------- + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=0ADQiAxcaUJ2lMHipis80hsUEhdiqui82JhduOKE} + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=7KieQKdu02jHEUEjsqUYE83mx9OE2kdj2SJ72h6H} + {accesskey=EQEJIOJFAKQWESQEJIWQ,secretkey=7KieQKdu02jHEUEjsqUYE83mx9OE2kdj2SJ72h6H} + {accesskey=KGFQWEFQQEFXVAEAWLLC,secretkey=0SJIWiIATh6jOlmAKr8DGq6hOAGBI1BnsnvgJmTs,auth_method=simple} + {auth_method=simple} + {endpoint=127.0.0.1:6555} +(6 rows) + +\c regression +-- Test DROP STOARGE SERVER +DROP STORAGE SERVER oss_server1; -- fail +ERROR: storage server "oss_server1" cannot be dropped because some objects depend on it +DETAIL: storage server of storage user mapping for gpadmin on storage server oss_server1 +DROP STORAGE SERVER oss_server2; -- fail +ERROR: storage server "oss_server2" cannot be dropped because some objects depend on it +DETAIL: storage server of storage user mapping for test_dirtable1 on storage server oss_server2 +DROP STORAGE SERVER oss_server3; -- fail +ERROR: storage server "oss_server3" cannot be dropped because some objects depend on it +DETAIL: storage server of storage user mapping for gpadmin on storage server oss_server3 +storage server of storage user mapping for test_dirtable1 on storage server oss_server3 +storage server of storage user mapping for test_dirtable2 on storage server oss_server3 +DROP STORAGE SERVER oss_server4; -- fail +DROP STORAGE SERVER oss_server8; -- fail +ERROR: storage server "oss_server8" cannot be dropped because some objects depend on it +DETAIL: storage server of storage user mapping for test_dirtable3 on storage server oss_server8 +DROP STORAGE SERVER oss_server9; -- fail +ERROR: storage server "oss_server9" not exists +DROP STAROGE SERVER IF EXISTS oss_server9; -- fail +ERROR: syntax error at or near "STAROGE" +LINE 1: DROP STAROGE SERVER IF EXISTS oss_server9; + ^ +DROP STORAGE SERVER IF NOT EXISTS oss_server9; --fail +ERROR: syntax error at or near "NOT" +LINE 1: DROP STORAGE SERVER IF NOT EXISTS oss_server9; + ^ +DROP STORAGE SERVER IF EXISTS oss_server10; +SELECT srvname, srvacl, srvoptions from gp_storage_server ORDER BY 1; + srvname | srvacl | srvoptions +--------------+--------+------------------------------------------------------ + oss_server1 | | {protocol=aws} + oss_server11 | | {protocol=s3av2} + oss_server12 | | {protocol=s3av2,endpoint=127.0.0.1:9000,https=false} + oss_server2 | | {protocal=localhost,https=true,virtual_host=true} + oss_server3 | | {endpoint=127.0.0.1:9000} + oss_server5 | | {virtual_host=false} + oss_server6 | | {protocol=qingstor,"endpoint=pek3b,qingstor.com"} + oss_server7 | | {https=false,virtual_host=true} + oss_server8 | | {protocol=hdfs,namenode=127.0.0.1:8020} +(9 rows) + +\c dirtable_db +SELECT srvname, srvacl, srvoptions from gp_storage_server ORDER BY 1; + srvname | srvacl | srvoptions +--------------+--------+------------------------------------------------------ + oss_server1 | | {protocol=aws} + oss_server11 | | {protocol=s3av2} + oss_server12 | | {protocol=s3av2,endpoint=127.0.0.1:9000,https=false} + oss_server2 | | {protocal=localhost,https=true,virtual_host=true} + oss_server3 | | {endpoint=127.0.0.1:9000} + oss_server5 | | {virtual_host=false} + oss_server6 | | {protocol=qingstor,"endpoint=pek3b,qingstor.com"} + oss_server7 | | {https=false,virtual_host=true} + oss_server8 | | {protocol=hdfs,namenode=127.0.0.1:8020} +(9 rows) + +\c regression +-- Test directory table +-- Test CREATE DIRECTORY TABLE +SELECT count(*) FROM pg_directory_table; + count +------- + 0 +(1 row) + +SELECT relname, relisshared, relpersistence, relkind FROM pg_class WHERE relname like '%dir_table%' ORDER BY 1; + relname | relisshared | relpersistence | relkind +---------+-------------+----------------+--------- +(0 rows) + +CREATE DIRECTORY TABLE dir_table1; +CREATE DIRECTORY TABLE dir_table2 TABLESPACE directory_tblspc; +CREATE DIRECTORY TABLE dir_table3 TABLESPACE directory_tblspc DISTRIBUTED BY(relative_path); -- fail +ERROR: Create directory table is not allowed to set distributed by. +LINE 1: ...TORY TABLE dir_table3 TABLESPACE directory_tblspc DISTRIBUTE... + ^ +CREATE DIRECTORY TABLE dir_table3 TABLESPACE directory_tblspc DISTRIBUTED RANDOMLY; -- fail +ERROR: Create directory table is not allowed to set distributed by. +LINE 1: ...TORY TABLE dir_table3 TABLESPACE directory_tblspc DISTRIBUTE... + ^ +CREATE DIRECTORY TABLE dir_table3 TABLESPACE directory_tblspc DISTRIBUTED REPLICATED; -- fail +ERROR: Create directory table is not allowed to set distributed by. +LINE 1: ...TORY TABLE dir_table3 TABLESPACE directory_tblspc DISTRIBUTE... + ^ +CREATE DIRECTORY TABLE dir_table3 TABLESPACE directory_tblspc; +CREATE DIRECTORY TABLE IF NOT EXISTS dir_table4 TABLESPACE directory_tblspc; +CREATE DIRECTORY TABLE IF NOT EXISTS dir_table2 TABLESPACE directory_tblspc; -- fail +NOTICE: relation "dir_table2" already exists, skipping +CREATE DIRECTORY TABLE dir_table5 TABLESPACE directory_tblspc; +CREATE DIRECTORY TABLE dir_table6 TABLESPACE pg_default; +\dY + List of relations + Schema | Name | Type | Owner +--------+------------+-----------------+--------- + public | dir_table1 | directory table | gpadmin + public | dir_table2 | directory table | gpadmin + public | dir_table3 | directory table | gpadmin + public | dir_table4 | directory table | gpadmin + public | dir_table5 | directory table | gpadmin + public | dir_table6 | directory table | gpadmin +(6 rows) + +SELECT count(*) FROM pg_directory_table; + count +------- + 6 +(1 row) + +SELECT relname, relisshared, relpersistence, relkind FROM pg_class WHERE relname like '%dir_table%' ORDER BY 1; + relname | relisshared | relpersistence | relkind +-----------------+-------------+----------------+--------- + dir_table1 | f | p | d + dir_table1_pkey | f | p | i + dir_table2 | f | p | d + dir_table2_pkey | f | p | i + dir_table3 | f | p | d + dir_table3_pkey | f | p | i + dir_table4 | f | p | d + dir_table4_pkey | f | p | i + dir_table5 | f | p | d + dir_table5_pkey | f | p | i + dir_table6 | f | p | d + dir_table6_pkey | f | p | i +(12 rows) + +\d+ dir_table1; + Directory able "public.dir_table1" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +---------------+--------------------------+-----------+----------+---------+----------+--------------+------------- + relative_path | text | | | | extended | | + size | bigint | | | | plain | | + last_modified | timestamp with time zone | | | | plain | | + md5 | text | | | | extended | | + tag | text | | | | extended | | +Indexes: + "dir_table1_pkey" PRIMARY KEY, btree (relative_path) +Distributed by: (relative_path) + +\d+ dir_table2; + Directory able "public.dir_table2" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +---------------+--------------------------+-----------+----------+---------+----------+--------------+------------- + relative_path | text | | | | extended | | + size | bigint | | | | plain | | + last_modified | timestamp with time zone | | | | plain | | + md5 | text | | | | extended | | + tag | text | | | | extended | | +Indexes: + "dir_table2_pkey" PRIMARY KEY, btree (relative_path) +Distributed by: (relative_path) + +\d+ dir_table3; + Directory able "public.dir_table3" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +---------------+--------------------------+-----------+----------+---------+----------+--------------+------------- + relative_path | text | | | | extended | | + size | bigint | | | | plain | | + last_modified | timestamp with time zone | | | | plain | | + md5 | text | | | | extended | | + tag | text | | | | extended | | +Indexes: + "dir_table3_pkey" PRIMARY KEY, btree (relative_path) +Distributed by: (relative_path) + +\c dirtable_db +\dY + List of relations + Schema | Name | Type | Owner +--------+------+------+------- +(0 rows) + +SELECT count(*) FROM pg_directory_table; + count +------- + 0 +(1 row) + +SELECT relname, relisshared, relpersistence, relkind FROM pg_class WHERE relname like '%dir_table%' ORDER BY 1; + relname | relisshared | relpersistence | relkind +---------+-------------+----------------+--------- +(0 rows) + +\c regression +-- Test create table inherits directory table +CREATE TABLE test_inherits1 INHERITS(dir_table1); -- fail +ERROR: syntax error at or near "INHERITS" +LINE 1: CREATE TABLE test_inherits1 INHERITS(dir_table1); + ^ +CREATE TABLE test_inherits2(a int) INHERITS(dir_table2); -- fail +NOTICE: table has parent, setting distribution columns to match parent table +ERROR: inherited relation "dir_table2" is not a table or foreign table +CREATE TABLE test_inherits3 INHERITS(dir_table2, dir_table3); -- fail +ERROR: syntax error at or near "INHERITS" +LINE 1: CREATE TABLE test_inherits3 INHERITS(dir_table2, dir_table3)... + ^ +CREATE TABLE test_inherits4(b text) INHERITS(dir_table1, dir_table2); -- fail +NOTICE: table has parent, setting distribution columns to match parent table +ERROR: inherited relation "dir_table1" is not a table or foreign table +-- Test DROP DIRECTORY TABLE +DROP DIRECTORY TABLE dir_table4; +DROP DIRECTORY TABLE dir_table4; -- fail +ERROR: directory table "dir_table4" does not exist +DROP DIRECTORY TABLE IF EXISTS dir_table5; +DROP DIRECTORY TABLE IF EXISTS dir_table5; -- skip +NOTICE: directory table "dir_table5" does not exist, skipping +\dY + List of relations + Schema | Name | Type | Owner +--------+------------+-----------------+--------- + public | dir_table1 | directory table | gpadmin + public | dir_table2 | directory table | gpadmin + public | dir_table3 | directory table | gpadmin + public | dir_table6 | directory table | gpadmin +(4 rows) + +SELECT count(*) FROM pg_directory_table; + count +------- + 4 +(1 row) + +SELECT relname, relisshared, relpersistence, relkind FROM pg_class WHERE relname like '%dir_table%' ORDER BY 1; + relname | relisshared | relpersistence | relkind +-----------------+-------------+----------------+--------- + dir_table1 | f | p | d + dir_table1_pkey | f | p | i + dir_table2 | f | p | d + dir_table2_pkey | f | p | i + dir_table3 | f | p | d + dir_table3_pkey | f | p | i + dir_table6 | f | p | d + dir_table6_pkey | f | p | i +(8 rows) + +\c dirtable_db +\dY + List of relations + Schema | Name | Type | Owner +--------+------+------+------- +(0 rows) + +SELECT count(*) FROM pg_directory_table; + count +------- + 0 +(1 row) + +SELECT relname, relisshared, relpersistence, relkind FROM pg_class WHERE relname like '%dir_table%' ORDER BY 1; + relname | relisshared | relpersistence | relkind +---------+-------------+----------------+--------- +(0 rows) + +\c regression +-- Test CREATE/DROP/REINDEX on DIRECTORY SCHEMA TABLE +-- Test CREATE INDEX on DIRECTORY SCHEMA TABLE +CREATE INDEX dirtable1_relative_path_idx on dir_table1(relative_path); -- fail +ERROR: Disallowed to create index on directory table "dir_table1". (indexcmds.c:709) +CREATE INDEX dirtable1_size_idx on dir_table1(size); -- fail +ERROR: Disallowed to create index on directory table "dir_table1". (indexcmds.c:709) +CREATE INDEX dirtable1_last_modified_idx on dir_table1(last_modified); -- fail +ERROR: Disallowed to create index on directory table "dir_table1". (indexcmds.c:709) +CREATE INDEX dirtable1_md5_idx on dir_table1(md5); -- fail +ERROR: Disallowed to create index on directory table "dir_table1". (indexcmds.c:709) +CREATE INDEX dirtable1_tag_idx on dir_table1(tag); -- fail +ERROR: Disallowed to create index on directory table "dir_table1". (indexcmds.c:709) +\d+ dir_table1; + Directory able "public.dir_table1" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +---------------+--------------------------+-----------+----------+---------+----------+--------------+------------- + relative_path | text | | | | extended | | + size | bigint | | | | plain | | + last_modified | timestamp with time zone | | | | plain | | + md5 | text | | | | extended | | + tag | text | | | | extended | | +Indexes: + "dir_table1_pkey" PRIMARY KEY, btree (relative_path) +Distributed by: (relative_path) + +-- Test DROP INDEX on DIRECTORY SCHEMA TABLE +DROP INDEX dir_table1_pkey; -- fail +ERROR: Disallowed to drop index "dir_table1_pkey" on directory table "dir_table1" +DROP INDEX dir_table2_pkey; -- fail +ERROR: Disallowed to drop index "dir_table2_pkey" on directory table "dir_table2" +DROP INDEX dir_table3_pkey; -- fail +ERROR: Disallowed to drop index "dir_table3_pkey" on directory table "dir_table3" +DROP INDEX dir_table4_pkey; -- fail +ERROR: index "dir_table4_pkey" does not exist +DROP INDEX dir_table5_pkey; -- fail +ERROR: index "dir_table5_pkey" does not exist +DROP INDEX dir_table6_pkey; -- fail +ERROR: Disallowed to drop index "dir_table6_pkey" on directory table "dir_table6" +-- Test REINDEX on DIRECTORY SCHEMA TABLE +REINDEX INDEX dir_table1_pkey; +REINDEX INDEX dir_table2_pkey; +REINDEX INDEX dir_table3_pkey; +REINDEX INDEX dir_table4_pkey; +ERROR: relation "dir_table4_pkey" does not exist +REINDEX INDEX dir_table5_pkey; +ERROR: relation "dir_table5_pkey" does not exist +REINDEX INDEX dir_table6_pkey; +REINDEX TABLE dir_table1; +REINDEX TABLE dir_table2; +REINDEX TABLE dir_table3; +REINDEX TABLE dir_table4; +ERROR: relation "dir_table4" does not exist +REINDEX TABLE dir_table5; +ERROR: relation "dir_table5" does not exist +REINDEX TABLE dir_table6; +-- Test triggers +DROP FUNCTION IF EXISTS trigtest; +create function trigtest() returns trigger as $$ +begin + raise notice '% % % %', TG_TABLE_NAME, TG_OP, TG_WHEN, TG_LEVEL; + return new; +end;$$ language plpgsql; +create trigger trigtest_b_row_tg_dirtable_1 before insert or update or delete on dir_table1 +for each row execute procedure trigtest(); +create trigger trigtest_a_row_tg_dirtable_1 after insert or update or delete on dir_table1 +for each row execute procedure trigtest(); +create trigger trigtest_b_stmt_tg_dirtable_1 before insert or update or delete on dir_table1 +for each statement execute procedure trigtest(); +ERROR: Triggers for statements are not yet supported +create trigger trigtest_a_stmt_tg_dirtable_1 after insert or update or delete on dir_table1 +for each statement execute procedure trigtest(); +ERROR: Triggers for statements are not yet supported +-- Test COPY DIRECTORY TABLE syntax +SELECT relative_path, size, tag FROM dir_table1 ORDER BY 1; + relative_path | size | tag +---------------+------+----- +(0 rows) + +SELECT relative_path, size, tag FROM dir_table2 ORDER BY 1; + relative_path | size | tag +---------------+------+----- +(0 rows) + +\COPY dir_table1 FROM '@abs_srcdir@/data/nation.csv'; -- fail +ERROR: Copy from directory table file name can't be null. +\COPY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation'; -- fail +ERROR: Only support copy binary from directory table. +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv'; -- fail +ERROR: Copy from directory table file name can't be null. +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation1'; +NOTICE: dir_table1 INSERT AFTER ROW (seg1 127.0.1.1:7003 pid=31465) +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation1'; -- fail +ERROR: duplicate key value violates unique constraint "dir_table1_pkey" +DETAIL: Key (relative_path)=(nation1) already exists. +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation2' 'nation2'; -- fail +ERROR: syntax error at or near "'nation2'" +LINE 1: COPY BINARY dir_table1 FROM STDIN 'nation2' 'nation2'; -- fa... + ^ +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation2'; +NOTICE: dir_table1 INSERT AFTER ROW (seg2 127.0.1.1:7004 pid=31466) +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation3' WITH TAG 'nation'; +NOTICE: dir_table1 INSERT AFTER ROW (seg1 127.0.1.1:7003 pid=31465) +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation3' WITH TAG 'nation'; -- fail +ERROR: duplicate key value violates unique constraint "dir_table1_pkey" +DETAIL: Key (relative_path)=(nation3) already exists. +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation3' WITH TAG 'nation2'; -- fail +ERROR: duplicate key value violates unique constraint "dir_table1_pkey" +DETAIL: Key (relative_path)=(nation3) already exists. +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation4' WITH TAG 'nation'; +NOTICE: dir_table1 INSERT AFTER ROW (seg2 127.0.1.1:7004 pid=31466) +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation5' WITH TAG 'nation' WITH TAG 'nation2'; -- fail +ERROR: syntax error at or near "WITH" +LINE 1: ...dir_table1 FROM STDIN 'nation5' WITH TAG 'nation' WITH TAG '... + ^ +SELECT relative_path, size, tag FROM dir_table1 ORDER BY 1; + relative_path | size | tag +---------------+------+-------- + nation1 | 2199 | + nation2 | 2199 | + nation3 | 2199 | nation + nation4 | 2199 | nation +(4 rows) + +SELECT relative_path, content FROM directory_table('dir_table1') ORDER BY 1; + relative_path | content +---------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + nation1 | \x307c414c47455249417c307c20686167676c652e206361726566756c6c792066696e616c206465706f736974732064657465637420736c796c7920616761690a317c415247454e54494e417c317c616c20666f7865732070726f6d69736520736c796c79206163636f7264696e6720746f2074686520726567756c6172206163636f756e74732e20626f6c6420726571756573747320616c6f6e0a327c4252415a494c7c317c7920616c6f6e6773696465206f66207468652070656e64696e67206465706f736974732e206361726566756c6c79207370656369616c207061636b61676573206172652061626f7574207468652069726f6e696320666f726765732e20736c796c79207370656369616c200a337c43414e4144417c317c6561732068616e672069726f6e69632c2073696c656e74207061636b616765732e20736c796c7920726567756c6172207061636b616765732061726520667572696f75736c79206f76657220746865207469746865732e20666c756666696c7920626f6c640a347c45475950547c347c792061626f766520746865206361726566756c6c7920756e757375616c207468656f646f6c697465732e2066696e616c206475676f7574732061726520717569636b6c79206163726f73732074686520667572696f75736c7920726567756c617220640a357c455448494f5049417c307c76656e207061636b616765732077616b6520717569636b6c792e20726567750a367c4652414e43457c337c726566756c6c792066696e616c2072657175657374732e20726567756c61722c2069726f6e690a377c4745524d414e597c337c6c20706c6174656c6574732e20726567756c6172206163636f756e747320782d7261793a20756e757375616c2c20726567756c6172206163636f0a387c494e4449417c327c737320657863757365732063616a6f6c6520736c796c79206163726f737320746865207061636b616765732e206465706f73697473207072696e742061726f756e0a397c494e444f4e455349417c327c20736c796c792065787072657373206173796d70746f7465732e20726567756c6172206465706f7369747320686167676c6520736c796c792e206361726566756c6c792069726f6e696320686f636b657920706c617965727320736c65657020626c697468656c792e206361726566756c6c0a31307c4952414e7c347c6566756c6c7920616c6f6e6773696465206f662074686520736c796c792066696e616c20646570656e64656e636965732e200a31317c495241517c347c6e6963206465706f7369747320626f6f73742061746f702074686520717569636b6c792066696e616c2072657175657374733f20717569636b6c7920726567756c610a31327c4a4150414e7c327c6f75736c792e2066696e616c2c20657870726573732067696674732063616a6f6c6520610a31337c4a4f5244414e7c347c6963206465706f736974732061726520626c697468656c792061626f757420746865206361726566756c6c7920726567756c61722070610a31347c4b454e59417c307c2070656e64696e67206578637573657320686167676c6520667572696f75736c79206465706f736974732e2070656e64696e672c20657870726573732070696e746f206265616e732077616b6520666c756666696c79207061737420740a31357c4d4f524f43434f7c307c726e732e20626c697468656c7920626f6c6420636f7572747320616d6f6e672074686520636c6f73656c7920726567756c6172207061636b616765732075736520667572696f75736c7920626f6c6420706c6174656c6574733f0a31367c4d4f5a414d42495155457c307c732e2069726f6e69632c20756e757375616c206173796d70746f7465732077616b6520626c697468656c7920720a31377c504552557c317c706c6174656c6574732e20626c697468656c792070656e64696e6720646570656e64656e636965732075736520666c756666696c79206163726f737320746865206576656e2070696e746f206265616e732e206361726566756c6c792073696c656e74206163636f756e0a31387c4348494e417c327c6320646570656e64656e636965732e20667572696f75736c792065787072657373206e6f746f726e697320736c65657020736c796c7920726567756c6172206163636f756e74732e20696465617320736c6565702e206465706f730a31397c524f4d414e49417c337c756c6172206173796d70746f746573206172652061626f75742074686520667572696f7573206d756c7469706c696572732e206578707265737320646570656e64656e63696573206e61672061626f7665207468652069726f6e6963616c6c792069726f6e6963206163636f756e740a32307c5341554449204152414249417c347c74732e2073696c656e7420726571756573747320686167676c652e20636c6f73656c792065787072657373207061636b6167657320736c656570206163726f73732074686520626c697468656c790a32317c564945544e414d7c327c68656c7920656e746963696e676c792065787072657373206163636f756e74732e206576656e2c2066696e616c200a32327c5255535349417c337c20726571756573747320616761696e73742074686520706c6174656c65747320757365206e65766572206163636f7264696e6720746f2074686520717569636b6c7920726567756c61722070696e740a32337c554e49544544204b494e47444f4d7c337c65616e7320626f6f7374206361726566756c6c79207370656369616c2072657175657374732e206163636f756e7473206172652e206361726566756c6c0a32347c554e49544544205354415445537c317c792066696e616c207061636b616765732e20736c6f7720666f7865732063616a6f6c6520717569636b6c792e20717569636b6c792073696c656e7420706c6174656c657473206272656163682069726f6e6963206163636f756e74732e20756e757375616c2070696e746f2062650a + nation2 | \x307c414c47455249417c307c20686167676c652e206361726566756c6c792066696e616c206465706f736974732064657465637420736c796c7920616761690a317c415247454e54494e417c317c616c20666f7865732070726f6d69736520736c796c79206163636f7264696e6720746f2074686520726567756c6172206163636f756e74732e20626f6c6420726571756573747320616c6f6e0a327c4252415a494c7c317c7920616c6f6e6773696465206f66207468652070656e64696e67206465706f736974732e206361726566756c6c79207370656369616c207061636b61676573206172652061626f7574207468652069726f6e696320666f726765732e20736c796c79207370656369616c200a337c43414e4144417c317c6561732068616e672069726f6e69632c2073696c656e74207061636b616765732e20736c796c7920726567756c6172207061636b616765732061726520667572696f75736c79206f76657220746865207469746865732e20666c756666696c7920626f6c640a347c45475950547c347c792061626f766520746865206361726566756c6c7920756e757375616c207468656f646f6c697465732e2066696e616c206475676f7574732061726520717569636b6c79206163726f73732074686520667572696f75736c7920726567756c617220640a357c455448494f5049417c307c76656e207061636b616765732077616b6520717569636b6c792e20726567750a367c4652414e43457c337c726566756c6c792066696e616c2072657175657374732e20726567756c61722c2069726f6e690a377c4745524d414e597c337c6c20706c6174656c6574732e20726567756c6172206163636f756e747320782d7261793a20756e757375616c2c20726567756c6172206163636f0a387c494e4449417c327c737320657863757365732063616a6f6c6520736c796c79206163726f737320746865207061636b616765732e206465706f73697473207072696e742061726f756e0a397c494e444f4e455349417c327c20736c796c792065787072657373206173796d70746f7465732e20726567756c6172206465706f7369747320686167676c6520736c796c792e206361726566756c6c792069726f6e696320686f636b657920706c617965727320736c65657020626c697468656c792e206361726566756c6c0a31307c4952414e7c347c6566756c6c7920616c6f6e6773696465206f662074686520736c796c792066696e616c20646570656e64656e636965732e200a31317c495241517c347c6e6963206465706f7369747320626f6f73742061746f702074686520717569636b6c792066696e616c2072657175657374733f20717569636b6c7920726567756c610a31327c4a4150414e7c327c6f75736c792e2066696e616c2c20657870726573732067696674732063616a6f6c6520610a31337c4a4f5244414e7c347c6963206465706f736974732061726520626c697468656c792061626f757420746865206361726566756c6c7920726567756c61722070610a31347c4b454e59417c307c2070656e64696e67206578637573657320686167676c6520667572696f75736c79206465706f736974732e2070656e64696e672c20657870726573732070696e746f206265616e732077616b6520666c756666696c79207061737420740a31357c4d4f524f43434f7c307c726e732e20626c697468656c7920626f6c6420636f7572747320616d6f6e672074686520636c6f73656c7920726567756c6172207061636b616765732075736520667572696f75736c7920626f6c6420706c6174656c6574733f0a31367c4d4f5a414d42495155457c307c732e2069726f6e69632c20756e757375616c206173796d70746f7465732077616b6520626c697468656c7920720a31377c504552557c317c706c6174656c6574732e20626c697468656c792070656e64696e6720646570656e64656e636965732075736520666c756666696c79206163726f737320746865206576656e2070696e746f206265616e732e206361726566756c6c792073696c656e74206163636f756e0a31387c4348494e417c327c6320646570656e64656e636965732e20667572696f75736c792065787072657373206e6f746f726e697320736c65657020736c796c7920726567756c6172206163636f756e74732e20696465617320736c6565702e206465706f730a31397c524f4d414e49417c337c756c6172206173796d70746f746573206172652061626f75742074686520667572696f7573206d756c7469706c696572732e206578707265737320646570656e64656e63696573206e61672061626f7665207468652069726f6e6963616c6c792069726f6e6963206163636f756e740a32307c5341554449204152414249417c347c74732e2073696c656e7420726571756573747320686167676c652e20636c6f73656c792065787072657373207061636b6167657320736c656570206163726f73732074686520626c697468656c790a32317c564945544e414d7c327c68656c7920656e746963696e676c792065787072657373206163636f756e74732e206576656e2c2066696e616c200a32327c5255535349417c337c20726571756573747320616761696e73742074686520706c6174656c65747320757365206e65766572206163636f7264696e6720746f2074686520717569636b6c7920726567756c61722070696e740a32337c554e49544544204b494e47444f4d7c337c65616e7320626f6f7374206361726566756c6c79207370656369616c2072657175657374732e206163636f756e7473206172652e206361726566756c6c0a32347c554e49544544205354415445537c317c792066696e616c207061636b616765732e20736c6f7720666f7865732063616a6f6c6520717569636b6c792e20717569636b6c792073696c656e7420706c6174656c657473206272656163682069726f6e6963206163636f756e74732e20756e757375616c2070696e746f2062650a + nation3 | \x307c414c47455249417c307c20686167676c652e206361726566756c6c792066696e616c206465706f736974732064657465637420736c796c7920616761690a317c415247454e54494e417c317c616c20666f7865732070726f6d69736520736c796c79206163636f7264696e6720746f2074686520726567756c6172206163636f756e74732e20626f6c6420726571756573747320616c6f6e0a327c4252415a494c7c317c7920616c6f6e6773696465206f66207468652070656e64696e67206465706f736974732e206361726566756c6c79207370656369616c207061636b61676573206172652061626f7574207468652069726f6e696320666f726765732e20736c796c79207370656369616c200a337c43414e4144417c317c6561732068616e672069726f6e69632c2073696c656e74207061636b616765732e20736c796c7920726567756c6172207061636b616765732061726520667572696f75736c79206f76657220746865207469746865732e20666c756666696c7920626f6c640a347c45475950547c347c792061626f766520746865206361726566756c6c7920756e757375616c207468656f646f6c697465732e2066696e616c206475676f7574732061726520717569636b6c79206163726f73732074686520667572696f75736c7920726567756c617220640a357c455448494f5049417c307c76656e207061636b616765732077616b6520717569636b6c792e20726567750a367c4652414e43457c337c726566756c6c792066696e616c2072657175657374732e20726567756c61722c2069726f6e690a377c4745524d414e597c337c6c20706c6174656c6574732e20726567756c6172206163636f756e747320782d7261793a20756e757375616c2c20726567756c6172206163636f0a387c494e4449417c327c737320657863757365732063616a6f6c6520736c796c79206163726f737320746865207061636b616765732e206465706f73697473207072696e742061726f756e0a397c494e444f4e455349417c327c20736c796c792065787072657373206173796d70746f7465732e20726567756c6172206465706f7369747320686167676c6520736c796c792e206361726566756c6c792069726f6e696320686f636b657920706c617965727320736c65657020626c697468656c792e206361726566756c6c0a31307c4952414e7c347c6566756c6c7920616c6f6e6773696465206f662074686520736c796c792066696e616c20646570656e64656e636965732e200a31317c495241517c347c6e6963206465706f7369747320626f6f73742061746f702074686520717569636b6c792066696e616c2072657175657374733f20717569636b6c7920726567756c610a31327c4a4150414e7c327c6f75736c792e2066696e616c2c20657870726573732067696674732063616a6f6c6520610a31337c4a4f5244414e7c347c6963206465706f736974732061726520626c697468656c792061626f757420746865206361726566756c6c7920726567756c61722070610a31347c4b454e59417c307c2070656e64696e67206578637573657320686167676c6520667572696f75736c79206465706f736974732e2070656e64696e672c20657870726573732070696e746f206265616e732077616b6520666c756666696c79207061737420740a31357c4d4f524f43434f7c307c726e732e20626c697468656c7920626f6c6420636f7572747320616d6f6e672074686520636c6f73656c7920726567756c6172207061636b616765732075736520667572696f75736c7920626f6c6420706c6174656c6574733f0a31367c4d4f5a414d42495155457c307c732e2069726f6e69632c20756e757375616c206173796d70746f7465732077616b6520626c697468656c7920720a31377c504552557c317c706c6174656c6574732e20626c697468656c792070656e64696e6720646570656e64656e636965732075736520666c756666696c79206163726f737320746865206576656e2070696e746f206265616e732e206361726566756c6c792073696c656e74206163636f756e0a31387c4348494e417c327c6320646570656e64656e636965732e20667572696f75736c792065787072657373206e6f746f726e697320736c65657020736c796c7920726567756c6172206163636f756e74732e20696465617320736c6565702e206465706f730a31397c524f4d414e49417c337c756c6172206173796d70746f746573206172652061626f75742074686520667572696f7573206d756c7469706c696572732e206578707265737320646570656e64656e63696573206e61672061626f7665207468652069726f6e6963616c6c792069726f6e6963206163636f756e740a32307c5341554449204152414249417c347c74732e2073696c656e7420726571756573747320686167676c652e20636c6f73656c792065787072657373207061636b6167657320736c656570206163726f73732074686520626c697468656c790a32317c564945544e414d7c327c68656c7920656e746963696e676c792065787072657373206163636f756e74732e206576656e2c2066696e616c200a32327c5255535349417c337c20726571756573747320616761696e73742074686520706c6174656c65747320757365206e65766572206163636f7264696e6720746f2074686520717569636b6c7920726567756c61722070696e740a32337c554e49544544204b494e47444f4d7c337c65616e7320626f6f7374206361726566756c6c79207370656369616c2072657175657374732e206163636f756e7473206172652e206361726566756c6c0a32347c554e49544544205354415445537c317c792066696e616c207061636b616765732e20736c6f7720666f7865732063616a6f6c6520717569636b6c792e20717569636b6c792073696c656e7420706c6174656c657473206272656163682069726f6e6963206163636f756e74732e20756e757375616c2070696e746f2062650a + nation4 | \x307c414c47455249417c307c20686167676c652e206361726566756c6c792066696e616c206465706f736974732064657465637420736c796c7920616761690a317c415247454e54494e417c317c616c20666f7865732070726f6d69736520736c796c79206163636f7264696e6720746f2074686520726567756c6172206163636f756e74732e20626f6c6420726571756573747320616c6f6e0a327c4252415a494c7c317c7920616c6f6e6773696465206f66207468652070656e64696e67206465706f736974732e206361726566756c6c79207370656369616c207061636b61676573206172652061626f7574207468652069726f6e696320666f726765732e20736c796c79207370656369616c200a337c43414e4144417c317c6561732068616e672069726f6e69632c2073696c656e74207061636b616765732e20736c796c7920726567756c6172207061636b616765732061726520667572696f75736c79206f76657220746865207469746865732e20666c756666696c7920626f6c640a347c45475950547c347c792061626f766520746865206361726566756c6c7920756e757375616c207468656f646f6c697465732e2066696e616c206475676f7574732061726520717569636b6c79206163726f73732074686520667572696f75736c7920726567756c617220640a357c455448494f5049417c307c76656e207061636b616765732077616b6520717569636b6c792e20726567750a367c4652414e43457c337c726566756c6c792066696e616c2072657175657374732e20726567756c61722c2069726f6e690a377c4745524d414e597c337c6c20706c6174656c6574732e20726567756c6172206163636f756e747320782d7261793a20756e757375616c2c20726567756c6172206163636f0a387c494e4449417c327c737320657863757365732063616a6f6c6520736c796c79206163726f737320746865207061636b616765732e206465706f73697473207072696e742061726f756e0a397c494e444f4e455349417c327c20736c796c792065787072657373206173796d70746f7465732e20726567756c6172206465706f7369747320686167676c6520736c796c792e206361726566756c6c792069726f6e696320686f636b657920706c617965727320736c65657020626c697468656c792e206361726566756c6c0a31307c4952414e7c347c6566756c6c7920616c6f6e6773696465206f662074686520736c796c792066696e616c20646570656e64656e636965732e200a31317c495241517c347c6e6963206465706f7369747320626f6f73742061746f702074686520717569636b6c792066696e616c2072657175657374733f20717569636b6c7920726567756c610a31327c4a4150414e7c327c6f75736c792e2066696e616c2c20657870726573732067696674732063616a6f6c6520610a31337c4a4f5244414e7c347c6963206465706f736974732061726520626c697468656c792061626f757420746865206361726566756c6c7920726567756c61722070610a31347c4b454e59417c307c2070656e64696e67206578637573657320686167676c6520667572696f75736c79206465706f736974732e2070656e64696e672c20657870726573732070696e746f206265616e732077616b6520666c756666696c79207061737420740a31357c4d4f524f43434f7c307c726e732e20626c697468656c7920626f6c6420636f7572747320616d6f6e672074686520636c6f73656c7920726567756c6172207061636b616765732075736520667572696f75736c7920626f6c6420706c6174656c6574733f0a31367c4d4f5a414d42495155457c307c732e2069726f6e69632c20756e757375616c206173796d70746f7465732077616b6520626c697468656c7920720a31377c504552557c317c706c6174656c6574732e20626c697468656c792070656e64696e6720646570656e64656e636965732075736520666c756666696c79206163726f737320746865206576656e2070696e746f206265616e732e206361726566756c6c792073696c656e74206163636f756e0a31387c4348494e417c327c6320646570656e64656e636965732e20667572696f75736c792065787072657373206e6f746f726e697320736c65657020736c796c7920726567756c6172206163636f756e74732e20696465617320736c6565702e206465706f730a31397c524f4d414e49417c337c756c6172206173796d70746f746573206172652061626f75742074686520667572696f7573206d756c7469706c696572732e206578707265737320646570656e64656e63696573206e61672061626f7665207468652069726f6e6963616c6c792069726f6e6963206163636f756e740a32307c5341554449204152414249417c347c74732e2073696c656e7420726571756573747320686167676c652e20636c6f73656c792065787072657373207061636b6167657320736c656570206163726f73732074686520626c697468656c790a32317c564945544e414d7c327c68656c7920656e746963696e676c792065787072657373206163636f756e74732e206576656e2c2066696e616c200a32327c5255535349417c337c20726571756573747320616761696e73742074686520706c6174656c65747320757365206e65766572206163636f7264696e6720746f2074686520717569636b6c7920726567756c61722070696e740a32337c554e49544544204b494e47444f4d7c337c65616e7320626f6f7374206361726566756c6c79207370656369616c2072657175657374732e206163636f756e7473206172652e206361726566756c6c0a32347c554e49544544205354415445537c317c792066696e616c207061636b616765732e20736c6f7720666f7865732063616a6f6c6520717569636b6c792e20717569636b6c792073696c656e7420706c6174656c657473206272656163682069726f6e6963206163636f756e74732e20756e757375616c2070696e746f2062650a +(4 rows) + +COPY dir_table2 FROM '@abs_srcdir@/data/nation.csv'; -- fail +ERROR: Copy from directory table file name can't be null. +COPY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation'; -- fail +ERROR: Only support copy binary from directory table. +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv'; -- fail +ERROR: Copy from directory table file name can't be null. +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation1'; +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation1'; -- fail +ERROR: duplicate key value violates unique constraint "dir_table2_pkey" +DETAIL: Key (relative_path)=(nation1) already exists. +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation2'; +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation3' WITH TAG 'nation'; +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation3' WITH TAG 'nation'; -- fail +ERROR: duplicate key value violates unique constraint "dir_table2_pkey" +DETAIL: Key (relative_path)=(nation3) already exists. +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation3' WITH TAG 'nation2'; -- fail +ERROR: duplicate key value violates unique constraint "dir_table2_pkey" +DETAIL: Key (relative_path)=(nation3) already exists. +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation4' WITH TAG 'nation'; +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation5' WITH TAG 'nation' WITH TAG 'nation2'; -- fail +ERROR: syntax error at or near "WITH" +LINE 1: ...ress/data/nation.csv' 'nation5' WITH TAG 'nation' WITH TAG '... + ^ +SELECT relative_path, size, tag FROM dir_table2 ORDER BY 1; + relative_path | size | tag +---------------+------+-------- + nation1 | 2199 | + nation2 | 2199 | + nation3 | 2199 | nation + nation4 | 2199 | nation +(4 rows) + +SELECT relative_path, content FROM directory_table('dir_table2') ORDER BY 1; + relative_path | content +---------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + nation1 | \x307c414c47455249417c307c20686167676c652e206361726566756c6c792066696e616c206465706f736974732064657465637420736c796c7920616761690a317c415247454e54494e417c317c616c20666f7865732070726f6d69736520736c796c79206163636f7264696e6720746f2074686520726567756c6172206163636f756e74732e20626f6c6420726571756573747320616c6f6e0a327c4252415a494c7c317c7920616c6f6e6773696465206f66207468652070656e64696e67206465706f736974732e206361726566756c6c79207370656369616c207061636b61676573206172652061626f7574207468652069726f6e696320666f726765732e20736c796c79207370656369616c200a337c43414e4144417c317c6561732068616e672069726f6e69632c2073696c656e74207061636b616765732e20736c796c7920726567756c6172207061636b616765732061726520667572696f75736c79206f76657220746865207469746865732e20666c756666696c7920626f6c640a347c45475950547c347c792061626f766520746865206361726566756c6c7920756e757375616c207468656f646f6c697465732e2066696e616c206475676f7574732061726520717569636b6c79206163726f73732074686520667572696f75736c7920726567756c617220640a357c455448494f5049417c307c76656e207061636b616765732077616b6520717569636b6c792e20726567750a367c4652414e43457c337c726566756c6c792066696e616c2072657175657374732e20726567756c61722c2069726f6e690a377c4745524d414e597c337c6c20706c6174656c6574732e20726567756c6172206163636f756e747320782d7261793a20756e757375616c2c20726567756c6172206163636f0a387c494e4449417c327c737320657863757365732063616a6f6c6520736c796c79206163726f737320746865207061636b616765732e206465706f73697473207072696e742061726f756e0a397c494e444f4e455349417c327c20736c796c792065787072657373206173796d70746f7465732e20726567756c6172206465706f7369747320686167676c6520736c796c792e206361726566756c6c792069726f6e696320686f636b657920706c617965727320736c65657020626c697468656c792e206361726566756c6c0a31307c4952414e7c347c6566756c6c7920616c6f6e6773696465206f662074686520736c796c792066696e616c20646570656e64656e636965732e200a31317c495241517c347c6e6963206465706f7369747320626f6f73742061746f702074686520717569636b6c792066696e616c2072657175657374733f20717569636b6c7920726567756c610a31327c4a4150414e7c327c6f75736c792e2066696e616c2c20657870726573732067696674732063616a6f6c6520610a31337c4a4f5244414e7c347c6963206465706f736974732061726520626c697468656c792061626f757420746865206361726566756c6c7920726567756c61722070610a31347c4b454e59417c307c2070656e64696e67206578637573657320686167676c6520667572696f75736c79206465706f736974732e2070656e64696e672c20657870726573732070696e746f206265616e732077616b6520666c756666696c79207061737420740a31357c4d4f524f43434f7c307c726e732e20626c697468656c7920626f6c6420636f7572747320616d6f6e672074686520636c6f73656c7920726567756c6172207061636b616765732075736520667572696f75736c7920626f6c6420706c6174656c6574733f0a31367c4d4f5a414d42495155457c307c732e2069726f6e69632c20756e757375616c206173796d70746f7465732077616b6520626c697468656c7920720a31377c504552557c317c706c6174656c6574732e20626c697468656c792070656e64696e6720646570656e64656e636965732075736520666c756666696c79206163726f737320746865206576656e2070696e746f206265616e732e206361726566756c6c792073696c656e74206163636f756e0a31387c4348494e417c327c6320646570656e64656e636965732e20667572696f75736c792065787072657373206e6f746f726e697320736c65657020736c796c7920726567756c6172206163636f756e74732e20696465617320736c6565702e206465706f730a31397c524f4d414e49417c337c756c6172206173796d70746f746573206172652061626f75742074686520667572696f7573206d756c7469706c696572732e206578707265737320646570656e64656e63696573206e61672061626f7665207468652069726f6e6963616c6c792069726f6e6963206163636f756e740a32307c5341554449204152414249417c347c74732e2073696c656e7420726571756573747320686167676c652e20636c6f73656c792065787072657373207061636b6167657320736c656570206163726f73732074686520626c697468656c790a32317c564945544e414d7c327c68656c7920656e746963696e676c792065787072657373206163636f756e74732e206576656e2c2066696e616c200a32327c5255535349417c337c20726571756573747320616761696e73742074686520706c6174656c65747320757365206e65766572206163636f7264696e6720746f2074686520717569636b6c7920726567756c61722070696e740a32337c554e49544544204b494e47444f4d7c337c65616e7320626f6f7374206361726566756c6c79207370656369616c2072657175657374732e206163636f756e7473206172652e206361726566756c6c0a32347c554e49544544205354415445537c317c792066696e616c207061636b616765732e20736c6f7720666f7865732063616a6f6c6520717569636b6c792e20717569636b6c792073696c656e7420706c6174656c657473206272656163682069726f6e6963206163636f756e74732e20756e757375616c2070696e746f2062650a + nation2 | \x307c414c47455249417c307c20686167676c652e206361726566756c6c792066696e616c206465706f736974732064657465637420736c796c7920616761690a317c415247454e54494e417c317c616c20666f7865732070726f6d69736520736c796c79206163636f7264696e6720746f2074686520726567756c6172206163636f756e74732e20626f6c6420726571756573747320616c6f6e0a327c4252415a494c7c317c7920616c6f6e6773696465206f66207468652070656e64696e67206465706f736974732e206361726566756c6c79207370656369616c207061636b61676573206172652061626f7574207468652069726f6e696320666f726765732e20736c796c79207370656369616c200a337c43414e4144417c317c6561732068616e672069726f6e69632c2073696c656e74207061636b616765732e20736c796c7920726567756c6172207061636b616765732061726520667572696f75736c79206f76657220746865207469746865732e20666c756666696c7920626f6c640a347c45475950547c347c792061626f766520746865206361726566756c6c7920756e757375616c207468656f646f6c697465732e2066696e616c206475676f7574732061726520717569636b6c79206163726f73732074686520667572696f75736c7920726567756c617220640a357c455448494f5049417c307c76656e207061636b616765732077616b6520717569636b6c792e20726567750a367c4652414e43457c337c726566756c6c792066696e616c2072657175657374732e20726567756c61722c2069726f6e690a377c4745524d414e597c337c6c20706c6174656c6574732e20726567756c6172206163636f756e747320782d7261793a20756e757375616c2c20726567756c6172206163636f0a387c494e4449417c327c737320657863757365732063616a6f6c6520736c796c79206163726f737320746865207061636b616765732e206465706f73697473207072696e742061726f756e0a397c494e444f4e455349417c327c20736c796c792065787072657373206173796d70746f7465732e20726567756c6172206465706f7369747320686167676c6520736c796c792e206361726566756c6c792069726f6e696320686f636b657920706c617965727320736c65657020626c697468656c792e206361726566756c6c0a31307c4952414e7c347c6566756c6c7920616c6f6e6773696465206f662074686520736c796c792066696e616c20646570656e64656e636965732e200a31317c495241517c347c6e6963206465706f7369747320626f6f73742061746f702074686520717569636b6c792066696e616c2072657175657374733f20717569636b6c7920726567756c610a31327c4a4150414e7c327c6f75736c792e2066696e616c2c20657870726573732067696674732063616a6f6c6520610a31337c4a4f5244414e7c347c6963206465706f736974732061726520626c697468656c792061626f757420746865206361726566756c6c7920726567756c61722070610a31347c4b454e59417c307c2070656e64696e67206578637573657320686167676c6520667572696f75736c79206465706f736974732e2070656e64696e672c20657870726573732070696e746f206265616e732077616b6520666c756666696c79207061737420740a31357c4d4f524f43434f7c307c726e732e20626c697468656c7920626f6c6420636f7572747320616d6f6e672074686520636c6f73656c7920726567756c6172207061636b616765732075736520667572696f75736c7920626f6c6420706c6174656c6574733f0a31367c4d4f5a414d42495155457c307c732e2069726f6e69632c20756e757375616c206173796d70746f7465732077616b6520626c697468656c7920720a31377c504552557c317c706c6174656c6574732e20626c697468656c792070656e64696e6720646570656e64656e636965732075736520666c756666696c79206163726f737320746865206576656e2070696e746f206265616e732e206361726566756c6c792073696c656e74206163636f756e0a31387c4348494e417c327c6320646570656e64656e636965732e20667572696f75736c792065787072657373206e6f746f726e697320736c65657020736c796c7920726567756c6172206163636f756e74732e20696465617320736c6565702e206465706f730a31397c524f4d414e49417c337c756c6172206173796d70746f746573206172652061626f75742074686520667572696f7573206d756c7469706c696572732e206578707265737320646570656e64656e63696573206e61672061626f7665207468652069726f6e6963616c6c792069726f6e6963206163636f756e740a32307c5341554449204152414249417c347c74732e2073696c656e7420726571756573747320686167676c652e20636c6f73656c792065787072657373207061636b6167657320736c656570206163726f73732074686520626c697468656c790a32317c564945544e414d7c327c68656c7920656e746963696e676c792065787072657373206163636f756e74732e206576656e2c2066696e616c200a32327c5255535349417c337c20726571756573747320616761696e73742074686520706c6174656c65747320757365206e65766572206163636f7264696e6720746f2074686520717569636b6c7920726567756c61722070696e740a32337c554e49544544204b494e47444f4d7c337c65616e7320626f6f7374206361726566756c6c79207370656369616c2072657175657374732e206163636f756e7473206172652e206361726566756c6c0a32347c554e49544544205354415445537c317c792066696e616c207061636b616765732e20736c6f7720666f7865732063616a6f6c6520717569636b6c792e20717569636b6c792073696c656e7420706c6174656c657473206272656163682069726f6e6963206163636f756e74732e20756e757375616c2070696e746f2062650a + nation3 | \x307c414c47455249417c307c20686167676c652e206361726566756c6c792066696e616c206465706f736974732064657465637420736c796c7920616761690a317c415247454e54494e417c317c616c20666f7865732070726f6d69736520736c796c79206163636f7264696e6720746f2074686520726567756c6172206163636f756e74732e20626f6c6420726571756573747320616c6f6e0a327c4252415a494c7c317c7920616c6f6e6773696465206f66207468652070656e64696e67206465706f736974732e206361726566756c6c79207370656369616c207061636b61676573206172652061626f7574207468652069726f6e696320666f726765732e20736c796c79207370656369616c200a337c43414e4144417c317c6561732068616e672069726f6e69632c2073696c656e74207061636b616765732e20736c796c7920726567756c6172207061636b616765732061726520667572696f75736c79206f76657220746865207469746865732e20666c756666696c7920626f6c640a347c45475950547c347c792061626f766520746865206361726566756c6c7920756e757375616c207468656f646f6c697465732e2066696e616c206475676f7574732061726520717569636b6c79206163726f73732074686520667572696f75736c7920726567756c617220640a357c455448494f5049417c307c76656e207061636b616765732077616b6520717569636b6c792e20726567750a367c4652414e43457c337c726566756c6c792066696e616c2072657175657374732e20726567756c61722c2069726f6e690a377c4745524d414e597c337c6c20706c6174656c6574732e20726567756c6172206163636f756e747320782d7261793a20756e757375616c2c20726567756c6172206163636f0a387c494e4449417c327c737320657863757365732063616a6f6c6520736c796c79206163726f737320746865207061636b616765732e206465706f73697473207072696e742061726f756e0a397c494e444f4e455349417c327c20736c796c792065787072657373206173796d70746f7465732e20726567756c6172206465706f7369747320686167676c6520736c796c792e206361726566756c6c792069726f6e696320686f636b657920706c617965727320736c65657020626c697468656c792e206361726566756c6c0a31307c4952414e7c347c6566756c6c7920616c6f6e6773696465206f662074686520736c796c792066696e616c20646570656e64656e636965732e200a31317c495241517c347c6e6963206465706f7369747320626f6f73742061746f702074686520717569636b6c792066696e616c2072657175657374733f20717569636b6c7920726567756c610a31327c4a4150414e7c327c6f75736c792e2066696e616c2c20657870726573732067696674732063616a6f6c6520610a31337c4a4f5244414e7c347c6963206465706f736974732061726520626c697468656c792061626f757420746865206361726566756c6c7920726567756c61722070610a31347c4b454e59417c307c2070656e64696e67206578637573657320686167676c6520667572696f75736c79206465706f736974732e2070656e64696e672c20657870726573732070696e746f206265616e732077616b6520666c756666696c79207061737420740a31357c4d4f524f43434f7c307c726e732e20626c697468656c7920626f6c6420636f7572747320616d6f6e672074686520636c6f73656c7920726567756c6172207061636b616765732075736520667572696f75736c7920626f6c6420706c6174656c6574733f0a31367c4d4f5a414d42495155457c307c732e2069726f6e69632c20756e757375616c206173796d70746f7465732077616b6520626c697468656c7920720a31377c504552557c317c706c6174656c6574732e20626c697468656c792070656e64696e6720646570656e64656e636965732075736520666c756666696c79206163726f737320746865206576656e2070696e746f206265616e732e206361726566756c6c792073696c656e74206163636f756e0a31387c4348494e417c327c6320646570656e64656e636965732e20667572696f75736c792065787072657373206e6f746f726e697320736c65657020736c796c7920726567756c6172206163636f756e74732e20696465617320736c6565702e206465706f730a31397c524f4d414e49417c337c756c6172206173796d70746f746573206172652061626f75742074686520667572696f7573206d756c7469706c696572732e206578707265737320646570656e64656e63696573206e61672061626f7665207468652069726f6e6963616c6c792069726f6e6963206163636f756e740a32307c5341554449204152414249417c347c74732e2073696c656e7420726571756573747320686167676c652e20636c6f73656c792065787072657373207061636b6167657320736c656570206163726f73732074686520626c697468656c790a32317c564945544e414d7c327c68656c7920656e746963696e676c792065787072657373206163636f756e74732e206576656e2c2066696e616c200a32327c5255535349417c337c20726571756573747320616761696e73742074686520706c6174656c65747320757365206e65766572206163636f7264696e6720746f2074686520717569636b6c7920726567756c61722070696e740a32337c554e49544544204b494e47444f4d7c337c65616e7320626f6f7374206361726566756c6c79207370656369616c2072657175657374732e206163636f756e7473206172652e206361726566756c6c0a32347c554e49544544205354415445537c317c792066696e616c207061636b616765732e20736c6f7720666f7865732063616a6f6c6520717569636b6c792e20717569636b6c792073696c656e7420706c6174656c657473206272656163682069726f6e6963206163636f756e74732e20756e757375616c2070696e746f2062650a + nation4 | \x307c414c47455249417c307c20686167676c652e206361726566756c6c792066696e616c206465706f736974732064657465637420736c796c7920616761690a317c415247454e54494e417c317c616c20666f7865732070726f6d69736520736c796c79206163636f7264696e6720746f2074686520726567756c6172206163636f756e74732e20626f6c6420726571756573747320616c6f6e0a327c4252415a494c7c317c7920616c6f6e6773696465206f66207468652070656e64696e67206465706f736974732e206361726566756c6c79207370656369616c207061636b61676573206172652061626f7574207468652069726f6e696320666f726765732e20736c796c79207370656369616c200a337c43414e4144417c317c6561732068616e672069726f6e69632c2073696c656e74207061636b616765732e20736c796c7920726567756c6172207061636b616765732061726520667572696f75736c79206f76657220746865207469746865732e20666c756666696c7920626f6c640a347c45475950547c347c792061626f766520746865206361726566756c6c7920756e757375616c207468656f646f6c697465732e2066696e616c206475676f7574732061726520717569636b6c79206163726f73732074686520667572696f75736c7920726567756c617220640a357c455448494f5049417c307c76656e207061636b616765732077616b6520717569636b6c792e20726567750a367c4652414e43457c337c726566756c6c792066696e616c2072657175657374732e20726567756c61722c2069726f6e690a377c4745524d414e597c337c6c20706c6174656c6574732e20726567756c6172206163636f756e747320782d7261793a20756e757375616c2c20726567756c6172206163636f0a387c494e4449417c327c737320657863757365732063616a6f6c6520736c796c79206163726f737320746865207061636b616765732e206465706f73697473207072696e742061726f756e0a397c494e444f4e455349417c327c20736c796c792065787072657373206173796d70746f7465732e20726567756c6172206465706f7369747320686167676c6520736c796c792e206361726566756c6c792069726f6e696320686f636b657920706c617965727320736c65657020626c697468656c792e206361726566756c6c0a31307c4952414e7c347c6566756c6c7920616c6f6e6773696465206f662074686520736c796c792066696e616c20646570656e64656e636965732e200a31317c495241517c347c6e6963206465706f7369747320626f6f73742061746f702074686520717569636b6c792066696e616c2072657175657374733f20717569636b6c7920726567756c610a31327c4a4150414e7c327c6f75736c792e2066696e616c2c20657870726573732067696674732063616a6f6c6520610a31337c4a4f5244414e7c347c6963206465706f736974732061726520626c697468656c792061626f757420746865206361726566756c6c7920726567756c61722070610a31347c4b454e59417c307c2070656e64696e67206578637573657320686167676c6520667572696f75736c79206465706f736974732e2070656e64696e672c20657870726573732070696e746f206265616e732077616b6520666c756666696c79207061737420740a31357c4d4f524f43434f7c307c726e732e20626c697468656c7920626f6c6420636f7572747320616d6f6e672074686520636c6f73656c7920726567756c6172207061636b616765732075736520667572696f75736c7920626f6c6420706c6174656c6574733f0a31367c4d4f5a414d42495155457c307c732e2069726f6e69632c20756e757375616c206173796d70746f7465732077616b6520626c697468656c7920720a31377c504552557c317c706c6174656c6574732e20626c697468656c792070656e64696e6720646570656e64656e636965732075736520666c756666696c79206163726f737320746865206576656e2070696e746f206265616e732e206361726566756c6c792073696c656e74206163636f756e0a31387c4348494e417c327c6320646570656e64656e636965732e20667572696f75736c792065787072657373206e6f746f726e697320736c65657020736c796c7920726567756c6172206163636f756e74732e20696465617320736c6565702e206465706f730a31397c524f4d414e49417c337c756c6172206173796d70746f746573206172652061626f75742074686520667572696f7573206d756c7469706c696572732e206578707265737320646570656e64656e63696573206e61672061626f7665207468652069726f6e6963616c6c792069726f6e6963206163636f756e740a32307c5341554449204152414249417c347c74732e2073696c656e7420726571756573747320686167676c652e20636c6f73656c792065787072657373207061636b6167657320736c656570206163726f73732074686520626c697468656c790a32317c564945544e414d7c327c68656c7920656e746963696e676c792065787072657373206163636f756e74732e206576656e2c2066696e616c200a32327c5255535349417c337c20726571756573747320616761696e73742074686520706c6174656c65747320757365206e65766572206163636f7264696e6720746f2074686520717569636b6c7920726567756c61722070696e740a32337c554e49544544204b494e47444f4d7c337c65616e7320626f6f7374206361726566756c6c79207370656369616c2072657175657374732e206163636f756e7473206172652e206361726566756c6c0a32347c554e49544544205354415445537c317c792066696e616c207061636b616765732e20736c6f7720666f7865732063616a6f6c6520717569636b6c792e20717569636b6c792073696c656e7420706c6174656c657473206272656163682069726f6e6963206163636f756e74732e20756e757375616c2070696e746f2062650a +(4 rows) + +-- Test copy binary from directory table +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (format CSV); +ERROR: conflicting or redundant options +LINE 1: ...OPY BINARY dir_table1 FROM STDIN 'nation_failed' (format CSV... + ^ +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (freeze off); +ERROR: option "freeze" not recognized +LINE 1: ...OPY BINARY dir_table1 FROM STDIN 'nation_failed' (freeze off... + ^ +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (freeze on); +ERROR: option "freeze" not recognized +LINE 1: ...OPY BINARY dir_table1 FROM STDIN 'nation_failed' (freeze on)... + ^ +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (delimiter ','); +ERROR: option "delimiter" not recognized +LINE 1: ...OPY BINARY dir_table1 FROM STDIN 'nation_failed' (delimiter ... + ^ +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (null ' '); +ERROR: option "null" not recognized +LINE 1: ...OPY BINARY dir_table1 FROM STDIN 'nation_failed' (null ' '); + ^ +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (header off); +ERROR: option "header" not recognized +LINE 1: ...OPY BINARY dir_table1 FROM STDIN 'nation_failed' (header off... + ^ +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (header on); +ERROR: option "header" not recognized +LINE 1: ...OPY BINARY dir_table1 FROM STDIN 'nation_failed' (header on)... + ^ +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (quote ':'); +ERROR: option "quote" not recognized +LINE 1: ...OPY BINARY dir_table1 FROM STDIN 'nation_failed' (quote ':')... + ^ +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (escape ':'); +ERROR: option "escape" not recognized +LINE 1: ...OPY BINARY dir_table1 FROM STDIN 'nation_failed' (escape ':'... + ^ +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (force_quote (a)); +ERROR: option "force_quote" not recognized +LINE 1: ...OPY BINARY dir_table1 FROM STDIN 'nation_failed' (force_quot... + ^ +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (force_quote *); +ERROR: option "force_quote" not recognized +LINE 1: ...OPY BINARY dir_table1 FROM STDIN 'nation_failed' (force_quot... + ^ +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (force_not_null (a)); +ERROR: option "force_not_null" not recognized +LINE 1: ...OPY BINARY dir_table1 FROM STDIN 'nation_failed' (force_not_... + ^ +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (force_null (a)); +ERROR: option "force_null" not recognized +LINE 1: ...OPY BINARY dir_table1 FROM STDIN 'nation_failed' (force_null... + ^ +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (convert_selectively (a)); +ERROR: option "convert_selectively" not recognized +LINE 1: ...OPY BINARY dir_table1 FROM STDIN 'nation_failed' (convert_se... + ^ +\COPY BINARY dir_table1 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (encoding 'sql_ascii'); +ERROR: option "encoding" not recognized +LINE 1: ...OPY BINARY dir_table1 FROM STDIN 'nation_failed' (encoding '... + ^ +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (format CSV); +ERROR: conflicting or redundant options +LINE 1: ...rc/test/regress/data/nation.csv' 'nation_failed' (format CSV... + ^ +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (freeze off); +ERROR: option "freeze" not recognized +LINE 1: ...rc/test/regress/data/nation.csv' 'nation_failed' (freeze off... + ^ +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (freeze on); +ERROR: option "freeze" not recognized +LINE 1: ...rc/test/regress/data/nation.csv' 'nation_failed' (freeze on)... + ^ +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (delimiter ','); +ERROR: option "delimiter" not recognized +LINE 1: ...rc/test/regress/data/nation.csv' 'nation_failed' (delimiter ... + ^ +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (null ' '); +ERROR: option "null" not recognized +LINE 1: ...rc/test/regress/data/nation.csv' 'nation_failed' (null ' '); + ^ +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (header off); +ERROR: option "header" not recognized +LINE 1: ...rc/test/regress/data/nation.csv' 'nation_failed' (header off... + ^ +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (header on); +ERROR: option "header" not recognized +LINE 1: ...rc/test/regress/data/nation.csv' 'nation_failed' (header on)... + ^ +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (quote ':'); +ERROR: option "quote" not recognized +LINE 1: ...rc/test/regress/data/nation.csv' 'nation_failed' (quote ':')... + ^ +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (escape ':'); +ERROR: option "escape" not recognized +LINE 1: ...rc/test/regress/data/nation.csv' 'nation_failed' (escape ':'... + ^ +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (force_quote (a)); +ERROR: option "force_quote" not recognized +LINE 1: ...rc/test/regress/data/nation.csv' 'nation_failed' (force_quot... + ^ +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (force_quote *); +ERROR: option "force_quote" not recognized +LINE 1: ...rc/test/regress/data/nation.csv' 'nation_failed' (force_quot... + ^ +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (force_not_null (a)); +ERROR: option "force_not_null" not recognized +LINE 1: ...rc/test/regress/data/nation.csv' 'nation_failed' (force_not_... + ^ +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (force_null (a)); +ERROR: option "force_null" not recognized +LINE 1: ...rc/test/regress/data/nation.csv' 'nation_failed' (force_null... + ^ +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (convert_selectively (a)); +ERROR: option "convert_selectively" not recognized +LINE 1: ...rc/test/regress/data/nation.csv' 'nation_failed' (convert_se... + ^ +COPY BINARY dir_table2 FROM '@abs_srcdir@/data/nation.csv' 'nation_failed' (encoding 'sql_ascii'); +ERROR: option "encoding" not recognized +LINE 1: ...rc/test/regress/data/nation.csv' 'nation_failed' (encoding '... + ^ +-- Test copy file content md5 +CREATE OR REPLACE FUNCTION file_content(text, text) RETURNS BYTEA LANGUAGE SQL AS +'select content from directory_table($1) where relative_path = $2'; +CREATE OR REPLACE FUNCTION file_md5(text, text) RETURNS TEXT LANGUAGE SQL AS +'select md5 from directory_table($1) where relative_path = $2'; +CREATE OR REPLACE FUNCTION md5_equal(text, text) RETURNS BOOL LANGUAGE SQL AS +'SELECT md5(file_content($1, $2)) = (SELECT file_md5($1, $2))'; +SELECT md5_equal('dir_table1', 'nation1'); + md5_equal +----------- + t +(1 row) + +SELECT md5_equal('dir_table1', 'nation2'); + md5_equal +----------- + t +(1 row) + +SELECT md5_equal('dir_table1', 'nation3'); + md5_equal +----------- + t +(1 row) + +SELECT md5_equal('dir_table1', 'nation4'); + md5_equal +----------- + t +(1 row) + +SELECT md5_equal('dir_table2', 'nation1'); + md5_equal +----------- + t +(1 row) + +SELECT md5_equal('dir_table2', 'nation2'); + md5_equal +----------- + t +(1 row) + +SELECT md5_equal('dir_table2', 'nation3'); + md5_equal +----------- + t +(1 row) + +SELECT md5_equal('dir_table2', 'nation4'); + md5_equal +----------- + t +(1 row) + +-- Does not support copy to +\COPY dir_table1 TO '@abs_srcdir@/data/dir_table1'; -- fail +ERROR: cannot copy from non-table relation "dir_table1" +\COPY BINARY dir_table1 TO '@abs_srcdir@/data/dir_table1'; -- fail +ERROR: cannot copy from non-table relation "dir_table1" +COPY dir_table1 TO '@abs_srcdir@/data/dir_table1'; -- fail +ERROR: cannot copy from non-table relation "dir_table1" +COPY BINARY dir_table1 TO '@abs_srcdir@/data/dir_table1'; -- fail +ERROR: cannot copy from non-table relation "dir_table1" +\COPY dir_table2 TO '@abs_srcdir@/data/dir_table2'; -- fail +ERROR: cannot copy from non-table relation "dir_table2" +\COPY BINARY dir_table2 TO '@abs_srcdir@/data/dir_table2'; -- fail +ERROR: cannot copy from non-table relation "dir_table2" +COPY dir_table2 TO '@abs_srcdir@/data/dir_table2'; -- fail +ERROR: cannot copy from non-table relation "dir_table2" +COPY BINARY dir_table2 TO '@abs_srcdir@/data/dir_table2'; -- fail +ERROR: cannot copy from non-table relation "dir_table2" +SELECT relative_path, size, tag FROM dir_table1 ORDER BY 1; + relative_path | size | tag +---------------+------+-------- + nation1 | 2199 | + nation2 | 2199 | + nation3 | 2199 | nation + nation4 | 2199 | nation +(4 rows) + +SELECT relative_path, size, tag FROM dir_table2 ORDER BY 1; + relative_path | size | tag +---------------+------+-------- + nation1 | 2199 | + nation2 | 2199 | + nation3 | 2199 | nation + nation4 | 2199 | nation +(4 rows) + +-- Test join between two directory schema tables +ANALYZE dir_table1; +ANALYZE dir_table2; +EXPLAIN (COSTS OFF) SELECT dir_table1.relative_path FROM dir_table1, dir_table2 +WHERE dir_table1.relative_path = dir_table2.relative_path ORDER BY 1; + QUERY PLAN +---------------------------------------------------------------------------- + Gather Motion 3:1 (slice1; segments: 3) + Merge Key: dir_table1.relative_path + -> Sort + Sort Key: dir_table1.relative_path + -> Nested Loop + Join Filter: true + -> Seq Scan on dir_table1 + -> Index Scan using dir_table2_pkey on dir_table2 + Index Cond: (relative_path = dir_table1.relative_path) + Optimizer: Pivotal Optimizer (GPORCA) +(10 rows) + +SELECT dir_table1.relative_path FROM dir_table1, dir_table2 +WHERE dir_table1.relative_path = dir_table2.relative_path ORDER BY 1; + relative_path +--------------- + nation1 + nation2 + nation3 + nation4 +(4 rows) + +EXPLAIN (COSTS OFF) SELECT dir_table1.relative_path FROM dir_table1, dir_table2 +WHERE dir_table1.size = dir_table2.size ORDER BY 1 LIMIT 1; + QUERY PLAN +--------------------------------------------------------------------------------- + Limit + -> Gather Motion 3:1 (slice1; segments: 3) + Merge Key: dir_table1.relative_path + -> Limit + -> Sort + Sort Key: dir_table1.relative_path + -> Hash Join + Hash Cond: (dir_table1.size = dir_table2.size) + -> Seq Scan on dir_table1 + -> Hash + -> Broadcast Motion 3:3 (slice2; segments: 3) + -> Seq Scan on dir_table2 + Optimizer: Pivotal Optimizer (GPORCA) +(13 rows) + +SELECT dir_table1.relative_path FROM dir_table1, dir_table2 +WHERE dir_table1.size = dir_table2.size ORDER BY 1 LIMIT 1; + relative_path +--------------- + nation1 +(1 row) + +EXPLAIN (COSTS OFF) SELECT dir_table1.relative_path FROM dir_table1, dir_table2 +WHERE dir_table1.md5 = dir_table2.md5 ORDER BY 1 LIMIT 1; + QUERY PLAN +------------------------------------------------------------------ + Limit + -> Sort + Sort Key: dir_table1.relative_path + -> Hash Join + Hash Cond: (dir_table1.md5 = dir_table2.md5) + -> Gather Motion 3:1 (slice1; segments: 3) + -> Seq Scan on dir_table1 + -> Hash + -> Gather Motion 3:1 (slice2; segments: 3) + -> Seq Scan on dir_table2 + Optimizer: Pivotal Optimizer (GPORCA) +(11 rows) + +SELECT dir_table1.relative_path FROM dir_table1, dir_table2 +WHERE dir_table1.md5 = dir_table2.md5 ORDER BY 1 LIMIT 1; + relative_path +--------------- + nation1 +(1 row) + +EXPLAIN (COSTS OFF) SELECT dir_table1.relative_path FROM dir_table1, dir_table2 +WHERE dir_table1.tag = dir_table2.tag ORDER BY 1; + QUERY PLAN +------------------------------------------------------------------------ + Gather Motion 3:1 (slice1; segments: 3) + Merge Key: dir_table1.relative_path + -> Sort + Sort Key: dir_table1.relative_path + -> Hash Join + Hash Cond: (dir_table1.tag = dir_table2.tag) + -> Redistribute Motion 3:3 (slice2; segments: 3) + Hash Key: dir_table1.tag + -> Seq Scan on dir_table1 + -> Hash + -> Redistribute Motion 3:3 (slice3; segments: 3) + Hash Key: dir_table2.tag + -> Seq Scan on dir_table2 + Optimizer: Pivotal Optimizer (GPORCA) +(14 rows) + +SELECT dir_table1.relative_path FROM dir_table1, dir_table2 +WHERE dir_table1.tag = dir_table2.tag ORDER BY 1; + relative_path +--------------- + nation3 + nation3 + nation4 + nation4 +(4 rows) + +-- Test DML directory schema table, only allow to update tag +INSERT INTO dir_table1 VALUES('insert'); -- fail +ERROR: cannot change directory table "dir_table1" +INSERT INTO dir_table2 VALUES('insert', 512, '2000-03-21 17:13:27+08', '70f09140d1b83eb3ecf9a0e28494d2a4', 'insert'); -- fail +ERROR: cannot change directory table "dir_table2" +SELECT relative_path, size, tag FROM dir_table1 ORDER BY 1; + relative_path | size | tag +---------------+------+-------- + nation1 | 2199 | + nation2 | 2199 | + nation3 | 2199 | nation + nation4 | 2199 | nation +(4 rows) + +SELECT relative_path, size, tag FROM dir_table2 ORDER BY 1; + relative_path | size | tag +---------------+------+-------- + nation1 | 2199 | + nation2 | 2199 | + nation3 | 2199 | nation + nation4 | 2199 | nation +(4 rows) + +DELETE FROM dir_table1; -- fail +ERROR: cannot change directory table "dir_table1" +DELETE FROM dir_table2 WHERE relative_path = 'nation1'; -- fail +ERROR: cannot change directory table "dir_table2" +SELECT relative_path, size, tag FROM dir_table1 ORDER BY 1; + relative_path | size | tag +---------------+------+-------- + nation1 | 2199 | + nation2 | 2199 | + nation3 | 2199 | nation + nation4 | 2199 | nation +(4 rows) + +SELECT relative_path, size, tag FROM dir_table2 ORDER BY 1; + relative_path | size | tag +---------------+------+-------- + nation1 | 2199 | + nation2 | 2199 | + nation3 | 2199 | nation + nation4 | 2199 | nation +(4 rows) + +UPDATE dir_table1 SET relative_path = 'nation_updated'; -- fail +ERROR: UPDATE on distributed key column not allowed on relation with update triggers +UPDATE dir_table2 SET relative_path = 'nation_updated' WHERE relative_path = 'nation2'; -- fail +ERROR: Only allow to update directory "tag" column. +UPDATE dir_table1 SET size = 512; -- fail +ERROR: Only allow to update directory "tag" column. +UPDATE dir_table2 SET size = 1024 WHERE relative_path = 'nation1'; -- fail +ERROR: Only allow to update directory "tag" column. +UPDATE dir_table1 SET last_modified = '2000-03-21 16:55:07+08'; -- fail +ERROR: Only allow to update directory "tag" column. +UPDATE dir_table2 SET last_modified = '2000-03-21 16:55:07+08' WHERE relative_path = 'nation3'; -- fail +ERROR: Only allow to update directory "tag" column. +UPDATE dir_table1 SET md5 = '70f09140d1b83eb3ecf9a0e28494d2a4'; -- fail +ERROR: Only allow to update directory "tag" column. +UPDATE dir_table2 SET md5 = '70f09140d1b83eb3ecf9a0e28494d2a4' WHERE relative_path = 'nation4'; -- fail +ERROR: Only allow to update directory "tag" column. +UPDATE dir_table1 SET tag = 'nation_new_tag'; -- ok +NOTICE: dir_table1 UPDATE BEFORE ROW (seg1 127.0.1.1:7003 pid=31465) +NOTICE: dir_table1 UPDATE BEFORE ROW (seg1 127.0.1.1:7003 pid=31465) +NOTICE: dir_table1 UPDATE BEFORE ROW (seg2 127.0.1.1:7004 pid=31466) +NOTICE: dir_table1 UPDATE BEFORE ROW (seg2 127.0.1.1:7004 pid=31466) +NOTICE: dir_table1 UPDATE AFTER ROW (seg2 127.0.1.1:7004 pid=31466) +NOTICE: dir_table1 UPDATE AFTER ROW (seg1 127.0.1.1:7003 pid=31465) +NOTICE: dir_table1 UPDATE AFTER ROW (seg1 127.0.1.1:7003 pid=31465) +NOTICE: dir_table1 UPDATE AFTER ROW (seg2 127.0.1.1:7004 pid=31466) +UPDATE dir_table1 SET tag = 'nation2_new_tag' WHERE relative_path = 'nation2'; -- ok +NOTICE: dir_table1 UPDATE BEFORE ROW (seg2 127.0.1.1:7004 pid=31466) +NOTICE: dir_table1 UPDATE AFTER ROW (seg2 127.0.1.1:7004 pid=31466) +UPDATE dir_table2 SET tag = 'nation4_new_tag' WHERE relative_path = 'nation3'; -- ok +UPDATE dir_table1 SET tag = 'failed_tag' WHERE relative_path = 'not_exist_path'; +UPDATE dir_table2 SET tag = 'no_tag' WHERE relative_path = 'not_exist_path'; +SELECT relative_path, size, tag FROM dir_table1 ORDER BY 1; + relative_path | size | tag +---------------+------+----------------- + nation1 | 2199 | nation_new_tag + nation2 | 2199 | nation2_new_tag + nation3 | 2199 | nation_new_tag + nation4 | 2199 | nation_new_tag +(4 rows) + +SELECT relative_path, size, tag FROM dir_table2 ORDER BY 1; + relative_path | size | tag +---------------+------+----------------- + nation1 | 2199 | + nation2 | 2199 | + nation3 | 2199 | nation4_new_tag + nation4 | 2199 | nation +(4 rows) + +-- Test alter table directory schema table +ALTER TABLE dir_table1 ADD COLUMN a int; -- fail +ERROR: "dir_table1" is not a table, composite type, or foreign table +ALTER DIRECTORY TABLE dir_table1 ADD COLUMN a int; -- fail +ERROR: syntax error at or near "DIRECTORY" +LINE 1: ALTER DIRECTORY TABLE dir_table1 ADD COLUMN a int; + ^ +ALTER TABLE dir_table2 DROP COLUMN relative_path; -- fail +ERROR: "dir_table2" is not a table, composite type, or foreign table +ALTER DIRECTORY TABLE dir_table2 DROP COLUMN relative_path; -- fail +ERROR: syntax error at or near "DIRECTORY" +LINE 1: ALTER DIRECTORY TABLE dir_table2 DROP COLUMN relative_path; + ^ +ALTER TABLE dir_table1 RENAME TO dir_table_new; -- fail +ERROR: Rename directory table is not allowed. +ALTER DIRECTORY TABLE dir_table1 RENAME TO dir_table_new; -- fail +ERROR: syntax error at or near "DIRECTORY" +LINE 1: ALTER DIRECTORY TABLE dir_table1 RENAME TO dir_table_new; + ^ +ALTER TABLE dir_table2 ADD CONSTRAINT dirtable_constraint UNIQUE (tag); -- fail +ERROR: "dir_table2" is not a table or foreign table +ALTER DIRECTORY TABLE dir_table2 ADD CONSTRAINT dirtable_constraint UNIQUE (tag); -- fail +ERROR: syntax error at or near "DIRECTORY" +LINE 1: ALTER DIRECTORY TABLE dir_table2 ADD CONSTRAINT dirtable_con... + ^ +ALTER TABLE dir_table1 DROP CONSTRAINT DROP CONSTRAINT test_pkey; -- fail +ERROR: syntax error at or near "CONSTRAINT" +LINE 1: ALTER TABLE dir_table1 DROP CONSTRAINT DROP CONSTRAINT test_... + ^ +ALTER DIRECTORY TABLE dir_table1 DROP CONSTRAINT DROP CONSTRAINT test_pkey; -- fail +ERROR: syntax error at or near "DIRECTORY" +LINE 1: ALTER DIRECTORY TABLE dir_table1 DROP CONSTRAINT DROP CONSTR... + ^ +-- Test remove_table +SELECT remove_file('dir_table1', 'nation5'); -- fail + remove_file +------------- + f +(1 row) + +SELECT remove_file('dir_table1', 'nation1'); + remove_file +------------- + t +(1 row) + +SELECT remove_file('dir_table2', 'nation1', 'nation2'); -- fail +ERROR: function remove_file(unknown, unknown, unknown) does not exist +LINE 1: SELECT remove_file('dir_table2', 'nation1', 'nation2'); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +SELECT remove_file('dir_table1', 'nation2'); + remove_file +------------- + t +(1 row) + +SELECT remove_file('dir_table3', 'nation1'); -- fail + remove_file +------------- + f +(1 row) + +SELECT remove_file('dir_table2', 'nation3'); + remove_file +------------- + t +(1 row) + +SELECT remove_file('dir_table1', 'nation1'); -- fail + remove_file +------------- + f +(1 row) + +SELECT relative_path, size, tag FROM dir_table1 ORDER BY 1; + relative_path | size | tag +---------------+------+---------------- + nation3 | 2199 | nation_new_tag + nation4 | 2199 | nation_new_tag +(2 rows) + +SELECT relative_path, size, tag FROM dir_table2 ORDER BY 1; + relative_path | size | tag +---------------+------+-------- + nation1 | 2199 | + nation2 | 2199 | + nation4 | 2199 | nation +(3 rows) + +-- Test transaction commit of directory table manipulation +CREATE DIRECTORY TABLE dir_table4 TABLESPACE directory_tblspc; +BEGIN; +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_commit'; +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_commit2' WITH TAG 'nation'; +COMMIT; +SELECT relative_path, content FROM directory_table('dir_table4') ORDER BY 1; + relative_path | content +----------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + nation_commit | \x307c414c47455249417c307c20686167676c652e206361726566756c6c792066696e616c206465706f736974732064657465637420736c796c7920616761690a317c415247454e54494e417c317c616c20666f7865732070726f6d69736520736c796c79206163636f7264696e6720746f2074686520726567756c6172206163636f756e74732e20626f6c6420726571756573747320616c6f6e0a327c4252415a494c7c317c7920616c6f6e6773696465206f66207468652070656e64696e67206465706f736974732e206361726566756c6c79207370656369616c207061636b61676573206172652061626f7574207468652069726f6e696320666f726765732e20736c796c79207370656369616c200a337c43414e4144417c317c6561732068616e672069726f6e69632c2073696c656e74207061636b616765732e20736c796c7920726567756c6172207061636b616765732061726520667572696f75736c79206f76657220746865207469746865732e20666c756666696c7920626f6c640a347c45475950547c347c792061626f766520746865206361726566756c6c7920756e757375616c207468656f646f6c697465732e2066696e616c206475676f7574732061726520717569636b6c79206163726f73732074686520667572696f75736c7920726567756c617220640a357c455448494f5049417c307c76656e207061636b616765732077616b6520717569636b6c792e20726567750a367c4652414e43457c337c726566756c6c792066696e616c2072657175657374732e20726567756c61722c2069726f6e690a377c4745524d414e597c337c6c20706c6174656c6574732e20726567756c6172206163636f756e747320782d7261793a20756e757375616c2c20726567756c6172206163636f0a387c494e4449417c327c737320657863757365732063616a6f6c6520736c796c79206163726f737320746865207061636b616765732e206465706f73697473207072696e742061726f756e0a397c494e444f4e455349417c327c20736c796c792065787072657373206173796d70746f7465732e20726567756c6172206465706f7369747320686167676c6520736c796c792e206361726566756c6c792069726f6e696320686f636b657920706c617965727320736c65657020626c697468656c792e206361726566756c6c0a31307c4952414e7c347c6566756c6c7920616c6f6e6773696465206f662074686520736c796c792066696e616c20646570656e64656e636965732e200a31317c495241517c347c6e6963206465706f7369747320626f6f73742061746f702074686520717569636b6c792066696e616c2072657175657374733f20717569636b6c7920726567756c610a31327c4a4150414e7c327c6f75736c792e2066696e616c2c20657870726573732067696674732063616a6f6c6520610a31337c4a4f5244414e7c347c6963206465706f736974732061726520626c697468656c792061626f757420746865206361726566756c6c7920726567756c61722070610a31347c4b454e59417c307c2070656e64696e67206578637573657320686167676c6520667572696f75736c79206465706f736974732e2070656e64696e672c20657870726573732070696e746f206265616e732077616b6520666c756666696c79207061737420740a31357c4d4f524f43434f7c307c726e732e20626c697468656c7920626f6c6420636f7572747320616d6f6e672074686520636c6f73656c7920726567756c6172207061636b616765732075736520667572696f75736c7920626f6c6420706c6174656c6574733f0a31367c4d4f5a414d42495155457c307c732e2069726f6e69632c20756e757375616c206173796d70746f7465732077616b6520626c697468656c7920720a31377c504552557c317c706c6174656c6574732e20626c697468656c792070656e64696e6720646570656e64656e636965732075736520666c756666696c79206163726f737320746865206576656e2070696e746f206265616e732e206361726566756c6c792073696c656e74206163636f756e0a31387c4348494e417c327c6320646570656e64656e636965732e20667572696f75736c792065787072657373206e6f746f726e697320736c65657020736c796c7920726567756c6172206163636f756e74732e20696465617320736c6565702e206465706f730a31397c524f4d414e49417c337c756c6172206173796d70746f746573206172652061626f75742074686520667572696f7573206d756c7469706c696572732e206578707265737320646570656e64656e63696573206e61672061626f7665207468652069726f6e6963616c6c792069726f6e6963206163636f756e740a32307c5341554449204152414249417c347c74732e2073696c656e7420726571756573747320686167676c652e20636c6f73656c792065787072657373207061636b6167657320736c656570206163726f73732074686520626c697468656c790a32317c564945544e414d7c327c68656c7920656e746963696e676c792065787072657373206163636f756e74732e206576656e2c2066696e616c200a32327c5255535349417c337c20726571756573747320616761696e73742074686520706c6174656c65747320757365206e65766572206163636f7264696e6720746f2074686520717569636b6c7920726567756c61722070696e740a32337c554e49544544204b494e47444f4d7c337c65616e7320626f6f7374206361726566756c6c79207370656369616c2072657175657374732e206163636f756e7473206172652e206361726566756c6c0a32347c554e49544544205354415445537c317c792066696e616c207061636b616765732e20736c6f7720666f7865732063616a6f6c6520717569636b6c792e20717569636b6c792073696c656e7420706c6174656c657473206272656163682069726f6e6963206163636f756e74732e20756e757375616c2070696e746f2062650a + nation_commit2 | \x307c414c47455249417c307c20686167676c652e206361726566756c6c792066696e616c206465706f736974732064657465637420736c796c7920616761690a317c415247454e54494e417c317c616c20666f7865732070726f6d69736520736c796c79206163636f7264696e6720746f2074686520726567756c6172206163636f756e74732e20626f6c6420726571756573747320616c6f6e0a327c4252415a494c7c317c7920616c6f6e6773696465206f66207468652070656e64696e67206465706f736974732e206361726566756c6c79207370656369616c207061636b61676573206172652061626f7574207468652069726f6e696320666f726765732e20736c796c79207370656369616c200a337c43414e4144417c317c6561732068616e672069726f6e69632c2073696c656e74207061636b616765732e20736c796c7920726567756c6172207061636b616765732061726520667572696f75736c79206f76657220746865207469746865732e20666c756666696c7920626f6c640a347c45475950547c347c792061626f766520746865206361726566756c6c7920756e757375616c207468656f646f6c697465732e2066696e616c206475676f7574732061726520717569636b6c79206163726f73732074686520667572696f75736c7920726567756c617220640a357c455448494f5049417c307c76656e207061636b616765732077616b6520717569636b6c792e20726567750a367c4652414e43457c337c726566756c6c792066696e616c2072657175657374732e20726567756c61722c2069726f6e690a377c4745524d414e597c337c6c20706c6174656c6574732e20726567756c6172206163636f756e747320782d7261793a20756e757375616c2c20726567756c6172206163636f0a387c494e4449417c327c737320657863757365732063616a6f6c6520736c796c79206163726f737320746865207061636b616765732e206465706f73697473207072696e742061726f756e0a397c494e444f4e455349417c327c20736c796c792065787072657373206173796d70746f7465732e20726567756c6172206465706f7369747320686167676c6520736c796c792e206361726566756c6c792069726f6e696320686f636b657920706c617965727320736c65657020626c697468656c792e206361726566756c6c0a31307c4952414e7c347c6566756c6c7920616c6f6e6773696465206f662074686520736c796c792066696e616c20646570656e64656e636965732e200a31317c495241517c347c6e6963206465706f7369747320626f6f73742061746f702074686520717569636b6c792066696e616c2072657175657374733f20717569636b6c7920726567756c610a31327c4a4150414e7c327c6f75736c792e2066696e616c2c20657870726573732067696674732063616a6f6c6520610a31337c4a4f5244414e7c347c6963206465706f736974732061726520626c697468656c792061626f757420746865206361726566756c6c7920726567756c61722070610a31347c4b454e59417c307c2070656e64696e67206578637573657320686167676c6520667572696f75736c79206465706f736974732e2070656e64696e672c20657870726573732070696e746f206265616e732077616b6520666c756666696c79207061737420740a31357c4d4f524f43434f7c307c726e732e20626c697468656c7920626f6c6420636f7572747320616d6f6e672074686520636c6f73656c7920726567756c6172207061636b616765732075736520667572696f75736c7920626f6c6420706c6174656c6574733f0a31367c4d4f5a414d42495155457c307c732e2069726f6e69632c20756e757375616c206173796d70746f7465732077616b6520626c697468656c7920720a31377c504552557c317c706c6174656c6574732e20626c697468656c792070656e64696e6720646570656e64656e636965732075736520666c756666696c79206163726f737320746865206576656e2070696e746f206265616e732e206361726566756c6c792073696c656e74206163636f756e0a31387c4348494e417c327c6320646570656e64656e636965732e20667572696f75736c792065787072657373206e6f746f726e697320736c65657020736c796c7920726567756c6172206163636f756e74732e20696465617320736c6565702e206465706f730a31397c524f4d414e49417c337c756c6172206173796d70746f746573206172652061626f75742074686520667572696f7573206d756c7469706c696572732e206578707265737320646570656e64656e63696573206e61672061626f7665207468652069726f6e6963616c6c792069726f6e6963206163636f756e740a32307c5341554449204152414249417c347c74732e2073696c656e7420726571756573747320686167676c652e20636c6f73656c792065787072657373207061636b6167657320736c656570206163726f73732074686520626c697468656c790a32317c564945544e414d7c327c68656c7920656e746963696e676c792065787072657373206163636f756e74732e206576656e2c2066696e616c200a32327c5255535349417c337c20726571756573747320616761696e73742074686520706c6174656c65747320757365206e65766572206163636f7264696e6720746f2074686520717569636b6c7920726567756c61722070696e740a32337c554e49544544204b494e47444f4d7c337c65616e7320626f6f7374206361726566756c6c79207370656369616c2072657175657374732e206163636f756e7473206172652e206361726566756c6c0a32347c554e49544544205354415445537c317c792066696e616c207061636b616765732e20736c6f7720666f7865732063616a6f6c6520717569636b6c792e20717569636b6c792073696c656e7420706c6174656c657473206272656163682069726f6e6963206163636f756e74732e20756e757375616c2070696e746f2062650a +(2 rows) + +BEGIN; +SELECT remove_file('dir_table4', 'nation_commit'); + remove_file +------------- + t +(1 row) + +SELECT relative_path, content FROM directory_table('dir_table4') ORDER BY 1; + relative_path | content +----------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + nation_commit2 | \x307c414c47455249417c307c20686167676c652e206361726566756c6c792066696e616c206465706f736974732064657465637420736c796c7920616761690a317c415247454e54494e417c317c616c20666f7865732070726f6d69736520736c796c79206163636f7264696e6720746f2074686520726567756c6172206163636f756e74732e20626f6c6420726571756573747320616c6f6e0a327c4252415a494c7c317c7920616c6f6e6773696465206f66207468652070656e64696e67206465706f736974732e206361726566756c6c79207370656369616c207061636b61676573206172652061626f7574207468652069726f6e696320666f726765732e20736c796c79207370656369616c200a337c43414e4144417c317c6561732068616e672069726f6e69632c2073696c656e74207061636b616765732e20736c796c7920726567756c6172207061636b616765732061726520667572696f75736c79206f76657220746865207469746865732e20666c756666696c7920626f6c640a347c45475950547c347c792061626f766520746865206361726566756c6c7920756e757375616c207468656f646f6c697465732e2066696e616c206475676f7574732061726520717569636b6c79206163726f73732074686520667572696f75736c7920726567756c617220640a357c455448494f5049417c307c76656e207061636b616765732077616b6520717569636b6c792e20726567750a367c4652414e43457c337c726566756c6c792066696e616c2072657175657374732e20726567756c61722c2069726f6e690a377c4745524d414e597c337c6c20706c6174656c6574732e20726567756c6172206163636f756e747320782d7261793a20756e757375616c2c20726567756c6172206163636f0a387c494e4449417c327c737320657863757365732063616a6f6c6520736c796c79206163726f737320746865207061636b616765732e206465706f73697473207072696e742061726f756e0a397c494e444f4e455349417c327c20736c796c792065787072657373206173796d70746f7465732e20726567756c6172206465706f7369747320686167676c6520736c796c792e206361726566756c6c792069726f6e696320686f636b657920706c617965727320736c65657020626c697468656c792e206361726566756c6c0a31307c4952414e7c347c6566756c6c7920616c6f6e6773696465206f662074686520736c796c792066696e616c20646570656e64656e636965732e200a31317c495241517c347c6e6963206465706f7369747320626f6f73742061746f702074686520717569636b6c792066696e616c2072657175657374733f20717569636b6c7920726567756c610a31327c4a4150414e7c327c6f75736c792e2066696e616c2c20657870726573732067696674732063616a6f6c6520610a31337c4a4f5244414e7c347c6963206465706f736974732061726520626c697468656c792061626f757420746865206361726566756c6c7920726567756c61722070610a31347c4b454e59417c307c2070656e64696e67206578637573657320686167676c6520667572696f75736c79206465706f736974732e2070656e64696e672c20657870726573732070696e746f206265616e732077616b6520666c756666696c79207061737420740a31357c4d4f524f43434f7c307c726e732e20626c697468656c7920626f6c6420636f7572747320616d6f6e672074686520636c6f73656c7920726567756c6172207061636b616765732075736520667572696f75736c7920626f6c6420706c6174656c6574733f0a31367c4d4f5a414d42495155457c307c732e2069726f6e69632c20756e757375616c206173796d70746f7465732077616b6520626c697468656c7920720a31377c504552557c317c706c6174656c6574732e20626c697468656c792070656e64696e6720646570656e64656e636965732075736520666c756666696c79206163726f737320746865206576656e2070696e746f206265616e732e206361726566756c6c792073696c656e74206163636f756e0a31387c4348494e417c327c6320646570656e64656e636965732e20667572696f75736c792065787072657373206e6f746f726e697320736c65657020736c796c7920726567756c6172206163636f756e74732e20696465617320736c6565702e206465706f730a31397c524f4d414e49417c337c756c6172206173796d70746f746573206172652061626f75742074686520667572696f7573206d756c7469706c696572732e206578707265737320646570656e64656e63696573206e61672061626f7665207468652069726f6e6963616c6c792069726f6e6963206163636f756e740a32307c5341554449204152414249417c347c74732e2073696c656e7420726571756573747320686167676c652e20636c6f73656c792065787072657373207061636b6167657320736c656570206163726f73732074686520626c697468656c790a32317c564945544e414d7c327c68656c7920656e746963696e676c792065787072657373206163636f756e74732e206576656e2c2066696e616c200a32327c5255535349417c337c20726571756573747320616761696e73742074686520706c6174656c65747320757365206e65766572206163636f7264696e6720746f2074686520717569636b6c7920726567756c61722070696e740a32337c554e49544544204b494e47444f4d7c337c65616e7320626f6f7374206361726566756c6c79207370656369616c2072657175657374732e206163636f756e7473206172652e206361726566756c6c0a32347c554e49544544205354415445537c317c792066696e616c207061636b616765732e20736c6f7720666f7865732063616a6f6c6520717569636b6c792e20717569636b6c792073696c656e7420706c6174656c657473206272656163682069726f6e6963206163636f756e74732e20756e757375616c2070696e746f2062650a +(1 row) + +COMMIT; +SELECT relative_path, content FROM directory_table('dir_table4') ORDER BY 1; + relative_path | content +----------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + nation_commit2 | \x307c414c47455249417c307c20686167676c652e206361726566756c6c792066696e616c206465706f736974732064657465637420736c796c7920616761690a317c415247454e54494e417c317c616c20666f7865732070726f6d69736520736c796c79206163636f7264696e6720746f2074686520726567756c6172206163636f756e74732e20626f6c6420726571756573747320616c6f6e0a327c4252415a494c7c317c7920616c6f6e6773696465206f66207468652070656e64696e67206465706f736974732e206361726566756c6c79207370656369616c207061636b61676573206172652061626f7574207468652069726f6e696320666f726765732e20736c796c79207370656369616c200a337c43414e4144417c317c6561732068616e672069726f6e69632c2073696c656e74207061636b616765732e20736c796c7920726567756c6172207061636b616765732061726520667572696f75736c79206f76657220746865207469746865732e20666c756666696c7920626f6c640a347c45475950547c347c792061626f766520746865206361726566756c6c7920756e757375616c207468656f646f6c697465732e2066696e616c206475676f7574732061726520717569636b6c79206163726f73732074686520667572696f75736c7920726567756c617220640a357c455448494f5049417c307c76656e207061636b616765732077616b6520717569636b6c792e20726567750a367c4652414e43457c337c726566756c6c792066696e616c2072657175657374732e20726567756c61722c2069726f6e690a377c4745524d414e597c337c6c20706c6174656c6574732e20726567756c6172206163636f756e747320782d7261793a20756e757375616c2c20726567756c6172206163636f0a387c494e4449417c327c737320657863757365732063616a6f6c6520736c796c79206163726f737320746865207061636b616765732e206465706f73697473207072696e742061726f756e0a397c494e444f4e455349417c327c20736c796c792065787072657373206173796d70746f7465732e20726567756c6172206465706f7369747320686167676c6520736c796c792e206361726566756c6c792069726f6e696320686f636b657920706c617965727320736c65657020626c697468656c792e206361726566756c6c0a31307c4952414e7c347c6566756c6c7920616c6f6e6773696465206f662074686520736c796c792066696e616c20646570656e64656e636965732e200a31317c495241517c347c6e6963206465706f7369747320626f6f73742061746f702074686520717569636b6c792066696e616c2072657175657374733f20717569636b6c7920726567756c610a31327c4a4150414e7c327c6f75736c792e2066696e616c2c20657870726573732067696674732063616a6f6c6520610a31337c4a4f5244414e7c347c6963206465706f736974732061726520626c697468656c792061626f757420746865206361726566756c6c7920726567756c61722070610a31347c4b454e59417c307c2070656e64696e67206578637573657320686167676c6520667572696f75736c79206465706f736974732e2070656e64696e672c20657870726573732070696e746f206265616e732077616b6520666c756666696c79207061737420740a31357c4d4f524f43434f7c307c726e732e20626c697468656c7920626f6c6420636f7572747320616d6f6e672074686520636c6f73656c7920726567756c6172207061636b616765732075736520667572696f75736c7920626f6c6420706c6174656c6574733f0a31367c4d4f5a414d42495155457c307c732e2069726f6e69632c20756e757375616c206173796d70746f7465732077616b6520626c697468656c7920720a31377c504552557c317c706c6174656c6574732e20626c697468656c792070656e64696e6720646570656e64656e636965732075736520666c756666696c79206163726f737320746865206576656e2070696e746f206265616e732e206361726566756c6c792073696c656e74206163636f756e0a31387c4348494e417c327c6320646570656e64656e636965732e20667572696f75736c792065787072657373206e6f746f726e697320736c65657020736c796c7920726567756c6172206163636f756e74732e20696465617320736c6565702e206465706f730a31397c524f4d414e49417c337c756c6172206173796d70746f746573206172652061626f75742074686520667572696f7573206d756c7469706c696572732e206578707265737320646570656e64656e63696573206e61672061626f7665207468652069726f6e6963616c6c792069726f6e6963206163636f756e740a32307c5341554449204152414249417c347c74732e2073696c656e7420726571756573747320686167676c652e20636c6f73656c792065787072657373207061636b6167657320736c656570206163726f73732074686520626c697468656c790a32317c564945544e414d7c327c68656c7920656e746963696e676c792065787072657373206163636f756e74732e206576656e2c2066696e616c200a32327c5255535349417c337c20726571756573747320616761696e73742074686520706c6174656c65747320757365206e65766572206163636f7264696e6720746f2074686520717569636b6c7920726567756c61722070696e740a32337c554e49544544204b494e47444f4d7c337c65616e7320626f6f7374206361726566756c6c79207370656369616c2072657175657374732e206163636f756e7473206172652e206361726566756c6c0a32347c554e49544544205354415445537c317c792066696e616c207061636b616765732e20736c6f7720666f7865732063616a6f6c6520717569636b6c792e20717569636b6c792073696c656e7420706c6174656c657473206272656163682069726f6e6963206163636f756e74732e20756e757375616c2070696e746f2062650a +(1 row) + +BEGIN; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +----------------+-------- + nation_commit2 | nation +(1 row) + +UPDATE dir_table4 SET tag = 'nation_updated' WHERE relative_path = 'nation_commit2'; +COMMIT; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +----------------+---------------- + nation_commit2 | nation_updated +(1 row) + +-- Test transaction rollback of directory table manipulation +BEGIN; +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_rollback'; +SELECT relative_path, content FROM directory_table('dir_table4') ORDER BY 1; + relative_path | content +-----------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + nation_commit2 | \x307c414c47455249417c307c20686167676c652e206361726566756c6c792066696e616c206465706f736974732064657465637420736c796c7920616761690a317c415247454e54494e417c317c616c20666f7865732070726f6d69736520736c796c79206163636f7264696e6720746f2074686520726567756c6172206163636f756e74732e20626f6c6420726571756573747320616c6f6e0a327c4252415a494c7c317c7920616c6f6e6773696465206f66207468652070656e64696e67206465706f736974732e206361726566756c6c79207370656369616c207061636b61676573206172652061626f7574207468652069726f6e696320666f726765732e20736c796c79207370656369616c200a337c43414e4144417c317c6561732068616e672069726f6e69632c2073696c656e74207061636b616765732e20736c796c7920726567756c6172207061636b616765732061726520667572696f75736c79206f76657220746865207469746865732e20666c756666696c7920626f6c640a347c45475950547c347c792061626f766520746865206361726566756c6c7920756e757375616c207468656f646f6c697465732e2066696e616c206475676f7574732061726520717569636b6c79206163726f73732074686520667572696f75736c7920726567756c617220640a357c455448494f5049417c307c76656e207061636b616765732077616b6520717569636b6c792e20726567750a367c4652414e43457c337c726566756c6c792066696e616c2072657175657374732e20726567756c61722c2069726f6e690a377c4745524d414e597c337c6c20706c6174656c6574732e20726567756c6172206163636f756e747320782d7261793a20756e757375616c2c20726567756c6172206163636f0a387c494e4449417c327c737320657863757365732063616a6f6c6520736c796c79206163726f737320746865207061636b616765732e206465706f73697473207072696e742061726f756e0a397c494e444f4e455349417c327c20736c796c792065787072657373206173796d70746f7465732e20726567756c6172206465706f7369747320686167676c6520736c796c792e206361726566756c6c792069726f6e696320686f636b657920706c617965727320736c65657020626c697468656c792e206361726566756c6c0a31307c4952414e7c347c6566756c6c7920616c6f6e6773696465206f662074686520736c796c792066696e616c20646570656e64656e636965732e200a31317c495241517c347c6e6963206465706f7369747320626f6f73742061746f702074686520717569636b6c792066696e616c2072657175657374733f20717569636b6c7920726567756c610a31327c4a4150414e7c327c6f75736c792e2066696e616c2c20657870726573732067696674732063616a6f6c6520610a31337c4a4f5244414e7c347c6963206465706f736974732061726520626c697468656c792061626f757420746865206361726566756c6c7920726567756c61722070610a31347c4b454e59417c307c2070656e64696e67206578637573657320686167676c6520667572696f75736c79206465706f736974732e2070656e64696e672c20657870726573732070696e746f206265616e732077616b6520666c756666696c79207061737420740a31357c4d4f524f43434f7c307c726e732e20626c697468656c7920626f6c6420636f7572747320616d6f6e672074686520636c6f73656c7920726567756c6172207061636b616765732075736520667572696f75736c7920626f6c6420706c6174656c6574733f0a31367c4d4f5a414d42495155457c307c732e2069726f6e69632c20756e757375616c206173796d70746f7465732077616b6520626c697468656c7920720a31377c504552557c317c706c6174656c6574732e20626c697468656c792070656e64696e6720646570656e64656e636965732075736520666c756666696c79206163726f737320746865206576656e2070696e746f206265616e732e206361726566756c6c792073696c656e74206163636f756e0a31387c4348494e417c327c6320646570656e64656e636965732e20667572696f75736c792065787072657373206e6f746f726e697320736c65657020736c796c7920726567756c6172206163636f756e74732e20696465617320736c6565702e206465706f730a31397c524f4d414e49417c337c756c6172206173796d70746f746573206172652061626f75742074686520667572696f7573206d756c7469706c696572732e206578707265737320646570656e64656e63696573206e61672061626f7665207468652069726f6e6963616c6c792069726f6e6963206163636f756e740a32307c5341554449204152414249417c347c74732e2073696c656e7420726571756573747320686167676c652e20636c6f73656c792065787072657373207061636b6167657320736c656570206163726f73732074686520626c697468656c790a32317c564945544e414d7c327c68656c7920656e746963696e676c792065787072657373206163636f756e74732e206576656e2c2066696e616c200a32327c5255535349417c337c20726571756573747320616761696e73742074686520706c6174656c65747320757365206e65766572206163636f7264696e6720746f2074686520717569636b6c7920726567756c61722070696e740a32337c554e49544544204b494e47444f4d7c337c65616e7320626f6f7374206361726566756c6c79207370656369616c2072657175657374732e206163636f756e7473206172652e206361726566756c6c0a32347c554e49544544205354415445537c317c792066696e616c207061636b616765732e20736c6f7720666f7865732063616a6f6c6520717569636b6c792e20717569636b6c792073696c656e7420706c6174656c657473206272656163682069726f6e6963206163636f756e74732e20756e757375616c2070696e746f2062650a + nation_rollback | \x307c414c47455249417c307c20686167676c652e206361726566756c6c792066696e616c206465706f736974732064657465637420736c796c7920616761690a317c415247454e54494e417c317c616c20666f7865732070726f6d69736520736c796c79206163636f7264696e6720746f2074686520726567756c6172206163636f756e74732e20626f6c6420726571756573747320616c6f6e0a327c4252415a494c7c317c7920616c6f6e6773696465206f66207468652070656e64696e67206465706f736974732e206361726566756c6c79207370656369616c207061636b61676573206172652061626f7574207468652069726f6e696320666f726765732e20736c796c79207370656369616c200a337c43414e4144417c317c6561732068616e672069726f6e69632c2073696c656e74207061636b616765732e20736c796c7920726567756c6172207061636b616765732061726520667572696f75736c79206f76657220746865207469746865732e20666c756666696c7920626f6c640a347c45475950547c347c792061626f766520746865206361726566756c6c7920756e757375616c207468656f646f6c697465732e2066696e616c206475676f7574732061726520717569636b6c79206163726f73732074686520667572696f75736c7920726567756c617220640a357c455448494f5049417c307c76656e207061636b616765732077616b6520717569636b6c792e20726567750a367c4652414e43457c337c726566756c6c792066696e616c2072657175657374732e20726567756c61722c2069726f6e690a377c4745524d414e597c337c6c20706c6174656c6574732e20726567756c6172206163636f756e747320782d7261793a20756e757375616c2c20726567756c6172206163636f0a387c494e4449417c327c737320657863757365732063616a6f6c6520736c796c79206163726f737320746865207061636b616765732e206465706f73697473207072696e742061726f756e0a397c494e444f4e455349417c327c20736c796c792065787072657373206173796d70746f7465732e20726567756c6172206465706f7369747320686167676c6520736c796c792e206361726566756c6c792069726f6e696320686f636b657920706c617965727320736c65657020626c697468656c792e206361726566756c6c0a31307c4952414e7c347c6566756c6c7920616c6f6e6773696465206f662074686520736c796c792066696e616c20646570656e64656e636965732e200a31317c495241517c347c6e6963206465706f7369747320626f6f73742061746f702074686520717569636b6c792066696e616c2072657175657374733f20717569636b6c7920726567756c610a31327c4a4150414e7c327c6f75736c792e2066696e616c2c20657870726573732067696674732063616a6f6c6520610a31337c4a4f5244414e7c347c6963206465706f736974732061726520626c697468656c792061626f757420746865206361726566756c6c7920726567756c61722070610a31347c4b454e59417c307c2070656e64696e67206578637573657320686167676c6520667572696f75736c79206465706f736974732e2070656e64696e672c20657870726573732070696e746f206265616e732077616b6520666c756666696c79207061737420740a31357c4d4f524f43434f7c307c726e732e20626c697468656c7920626f6c6420636f7572747320616d6f6e672074686520636c6f73656c7920726567756c6172207061636b616765732075736520667572696f75736c7920626f6c6420706c6174656c6574733f0a31367c4d4f5a414d42495155457c307c732e2069726f6e69632c20756e757375616c206173796d70746f7465732077616b6520626c697468656c7920720a31377c504552557c317c706c6174656c6574732e20626c697468656c792070656e64696e6720646570656e64656e636965732075736520666c756666696c79206163726f737320746865206576656e2070696e746f206265616e732e206361726566756c6c792073696c656e74206163636f756e0a31387c4348494e417c327c6320646570656e64656e636965732e20667572696f75736c792065787072657373206e6f746f726e697320736c65657020736c796c7920726567756c6172206163636f756e74732e20696465617320736c6565702e206465706f730a31397c524f4d414e49417c337c756c6172206173796d70746f746573206172652061626f75742074686520667572696f7573206d756c7469706c696572732e206578707265737320646570656e64656e63696573206e61672061626f7665207468652069726f6e6963616c6c792069726f6e6963206163636f756e740a32307c5341554449204152414249417c347c74732e2073696c656e7420726571756573747320686167676c652e20636c6f73656c792065787072657373207061636b6167657320736c656570206163726f73732074686520626c697468656c790a32317c564945544e414d7c327c68656c7920656e746963696e676c792065787072657373206163636f756e74732e206576656e2c2066696e616c200a32327c5255535349417c337c20726571756573747320616761696e73742074686520706c6174656c65747320757365206e65766572206163636f7264696e6720746f2074686520717569636b6c7920726567756c61722070696e740a32337c554e49544544204b494e47444f4d7c337c65616e7320626f6f7374206361726566756c6c79207370656369616c2072657175657374732e206163636f756e7473206172652e206361726566756c6c0a32347c554e49544544205354415445537c317c792066696e616c207061636b616765732e20736c6f7720666f7865732063616a6f6c6520717569636b6c792e20717569636b6c792073696c656e7420706c6174656c657473206272656163682069726f6e6963206163636f756e74732e20756e757375616c2070696e746f2062650a +(2 rows) + +ROLLBACK; +SELECT relative_path, content FROM directory_table('dir_table4') ORDER BY 1; + relative_path | content +----------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + nation_commit2 | \x307c414c47455249417c307c20686167676c652e206361726566756c6c792066696e616c206465706f736974732064657465637420736c796c7920616761690a317c415247454e54494e417c317c616c20666f7865732070726f6d69736520736c796c79206163636f7264696e6720746f2074686520726567756c6172206163636f756e74732e20626f6c6420726571756573747320616c6f6e0a327c4252415a494c7c317c7920616c6f6e6773696465206f66207468652070656e64696e67206465706f736974732e206361726566756c6c79207370656369616c207061636b61676573206172652061626f7574207468652069726f6e696320666f726765732e20736c796c79207370656369616c200a337c43414e4144417c317c6561732068616e672069726f6e69632c2073696c656e74207061636b616765732e20736c796c7920726567756c6172207061636b616765732061726520667572696f75736c79206f76657220746865207469746865732e20666c756666696c7920626f6c640a347c45475950547c347c792061626f766520746865206361726566756c6c7920756e757375616c207468656f646f6c697465732e2066696e616c206475676f7574732061726520717569636b6c79206163726f73732074686520667572696f75736c7920726567756c617220640a357c455448494f5049417c307c76656e207061636b616765732077616b6520717569636b6c792e20726567750a367c4652414e43457c337c726566756c6c792066696e616c2072657175657374732e20726567756c61722c2069726f6e690a377c4745524d414e597c337c6c20706c6174656c6574732e20726567756c6172206163636f756e747320782d7261793a20756e757375616c2c20726567756c6172206163636f0a387c494e4449417c327c737320657863757365732063616a6f6c6520736c796c79206163726f737320746865207061636b616765732e206465706f73697473207072696e742061726f756e0a397c494e444f4e455349417c327c20736c796c792065787072657373206173796d70746f7465732e20726567756c6172206465706f7369747320686167676c6520736c796c792e206361726566756c6c792069726f6e696320686f636b657920706c617965727320736c65657020626c697468656c792e206361726566756c6c0a31307c4952414e7c347c6566756c6c7920616c6f6e6773696465206f662074686520736c796c792066696e616c20646570656e64656e636965732e200a31317c495241517c347c6e6963206465706f7369747320626f6f73742061746f702074686520717569636b6c792066696e616c2072657175657374733f20717569636b6c7920726567756c610a31327c4a4150414e7c327c6f75736c792e2066696e616c2c20657870726573732067696674732063616a6f6c6520610a31337c4a4f5244414e7c347c6963206465706f736974732061726520626c697468656c792061626f757420746865206361726566756c6c7920726567756c61722070610a31347c4b454e59417c307c2070656e64696e67206578637573657320686167676c6520667572696f75736c79206465706f736974732e2070656e64696e672c20657870726573732070696e746f206265616e732077616b6520666c756666696c79207061737420740a31357c4d4f524f43434f7c307c726e732e20626c697468656c7920626f6c6420636f7572747320616d6f6e672074686520636c6f73656c7920726567756c6172207061636b616765732075736520667572696f75736c7920626f6c6420706c6174656c6574733f0a31367c4d4f5a414d42495155457c307c732e2069726f6e69632c20756e757375616c206173796d70746f7465732077616b6520626c697468656c7920720a31377c504552557c317c706c6174656c6574732e20626c697468656c792070656e64696e6720646570656e64656e636965732075736520666c756666696c79206163726f737320746865206576656e2070696e746f206265616e732e206361726566756c6c792073696c656e74206163636f756e0a31387c4348494e417c327c6320646570656e64656e636965732e20667572696f75736c792065787072657373206e6f746f726e697320736c65657020736c796c7920726567756c6172206163636f756e74732e20696465617320736c6565702e206465706f730a31397c524f4d414e49417c337c756c6172206173796d70746f746573206172652061626f75742074686520667572696f7573206d756c7469706c696572732e206578707265737320646570656e64656e63696573206e61672061626f7665207468652069726f6e6963616c6c792069726f6e6963206163636f756e740a32307c5341554449204152414249417c347c74732e2073696c656e7420726571756573747320686167676c652e20636c6f73656c792065787072657373207061636b6167657320736c656570206163726f73732074686520626c697468656c790a32317c564945544e414d7c327c68656c7920656e746963696e676c792065787072657373206163636f756e74732e206576656e2c2066696e616c200a32327c5255535349417c337c20726571756573747320616761696e73742074686520706c6174656c65747320757365206e65766572206163636f7264696e6720746f2074686520717569636b6c7920726567756c61722070696e740a32337c554e49544544204b494e47444f4d7c337c65616e7320626f6f7374206361726566756c6c79207370656369616c2072657175657374732e206163636f756e7473206172652e206361726566756c6c0a32347c554e49544544205354415445537c317c792066696e616c207061636b616765732e20736c6f7720666f7865732063616a6f6c6520717569636b6c792e20717569636b6c792073696c656e7420706c6174656c657473206272656163682069726f6e6963206163636f756e74732e20756e757375616c2070696e746f2062650a +(1 row) + +BEGIN; +SELECT remove_file('dir_table4', 'nation_commit2'); + remove_file +------------- + t +(1 row) + +SELECT relative_path, content FROM directory_table('dir_table4') ORDER BY 1; + relative_path | content +---------------+--------- +(0 rows) + +ROLLBACK; +SELECT relative_path, content FROM directory_table('dir_table4') ORDER BY 1; + relative_path | content +----------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + nation_commit2 | \x307c414c47455249417c307c20686167676c652e206361726566756c6c792066696e616c206465706f736974732064657465637420736c796c7920616761690a317c415247454e54494e417c317c616c20666f7865732070726f6d69736520736c796c79206163636f7264696e6720746f2074686520726567756c6172206163636f756e74732e20626f6c6420726571756573747320616c6f6e0a327c4252415a494c7c317c7920616c6f6e6773696465206f66207468652070656e64696e67206465706f736974732e206361726566756c6c79207370656369616c207061636b61676573206172652061626f7574207468652069726f6e696320666f726765732e20736c796c79207370656369616c200a337c43414e4144417c317c6561732068616e672069726f6e69632c2073696c656e74207061636b616765732e20736c796c7920726567756c6172207061636b616765732061726520667572696f75736c79206f76657220746865207469746865732e20666c756666696c7920626f6c640a347c45475950547c347c792061626f766520746865206361726566756c6c7920756e757375616c207468656f646f6c697465732e2066696e616c206475676f7574732061726520717569636b6c79206163726f73732074686520667572696f75736c7920726567756c617220640a357c455448494f5049417c307c76656e207061636b616765732077616b6520717569636b6c792e20726567750a367c4652414e43457c337c726566756c6c792066696e616c2072657175657374732e20726567756c61722c2069726f6e690a377c4745524d414e597c337c6c20706c6174656c6574732e20726567756c6172206163636f756e747320782d7261793a20756e757375616c2c20726567756c6172206163636f0a387c494e4449417c327c737320657863757365732063616a6f6c6520736c796c79206163726f737320746865207061636b616765732e206465706f73697473207072696e742061726f756e0a397c494e444f4e455349417c327c20736c796c792065787072657373206173796d70746f7465732e20726567756c6172206465706f7369747320686167676c6520736c796c792e206361726566756c6c792069726f6e696320686f636b657920706c617965727320736c65657020626c697468656c792e206361726566756c6c0a31307c4952414e7c347c6566756c6c7920616c6f6e6773696465206f662074686520736c796c792066696e616c20646570656e64656e636965732e200a31317c495241517c347c6e6963206465706f7369747320626f6f73742061746f702074686520717569636b6c792066696e616c2072657175657374733f20717569636b6c7920726567756c610a31327c4a4150414e7c327c6f75736c792e2066696e616c2c20657870726573732067696674732063616a6f6c6520610a31337c4a4f5244414e7c347c6963206465706f736974732061726520626c697468656c792061626f757420746865206361726566756c6c7920726567756c61722070610a31347c4b454e59417c307c2070656e64696e67206578637573657320686167676c6520667572696f75736c79206465706f736974732e2070656e64696e672c20657870726573732070696e746f206265616e732077616b6520666c756666696c79207061737420740a31357c4d4f524f43434f7c307c726e732e20626c697468656c7920626f6c6420636f7572747320616d6f6e672074686520636c6f73656c7920726567756c6172207061636b616765732075736520667572696f75736c7920626f6c6420706c6174656c6574733f0a31367c4d4f5a414d42495155457c307c732e2069726f6e69632c20756e757375616c206173796d70746f7465732077616b6520626c697468656c7920720a31377c504552557c317c706c6174656c6574732e20626c697468656c792070656e64696e6720646570656e64656e636965732075736520666c756666696c79206163726f737320746865206576656e2070696e746f206265616e732e206361726566756c6c792073696c656e74206163636f756e0a31387c4348494e417c327c6320646570656e64656e636965732e20667572696f75736c792065787072657373206e6f746f726e697320736c65657020736c796c7920726567756c6172206163636f756e74732e20696465617320736c6565702e206465706f730a31397c524f4d414e49417c337c756c6172206173796d70746f746573206172652061626f75742074686520667572696f7573206d756c7469706c696572732e206578707265737320646570656e64656e63696573206e61672061626f7665207468652069726f6e6963616c6c792069726f6e6963206163636f756e740a32307c5341554449204152414249417c347c74732e2073696c656e7420726571756573747320686167676c652e20636c6f73656c792065787072657373207061636b6167657320736c656570206163726f73732074686520626c697468656c790a32317c564945544e414d7c327c68656c7920656e746963696e676c792065787072657373206163636f756e74732e206576656e2c2066696e616c200a32327c5255535349417c337c20726571756573747320616761696e73742074686520706c6174656c65747320757365206e65766572206163636f7264696e6720746f2074686520717569636b6c7920726567756c61722070696e740a32337c554e49544544204b494e47444f4d7c337c65616e7320626f6f7374206361726566756c6c79207370656369616c2072657175657374732e206163636f756e7473206172652e206361726566756c6c0a32347c554e49544544205354415445537c317c792066696e616c207061636b616765732e20736c6f7720666f7865732063616a6f6c6520717569636b6c792e20717569636b6c792073696c656e7420706c6174656c657473206272656163682069726f6e6963206163636f756e74732e20756e757375616c2070696e746f2062650a +(1 row) + +BEGIN; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +----------------+---------------- + nation_commit2 | nation_updated +(1 row) + +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_rollback2' WITH TAG 'nation'; +UPDATE dir_table4 SET tag = 'nation_updated' WHERE relative_path = 'nation_rollback2'; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +------------------+---------------- + nation_commit2 | nation_updated + nation_rollback2 | nation_updated +(2 rows) + +ROLLBACK; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +----------------+---------------- + nation_commit2 | nation_updated +(1 row) + +-- Test subtransaction commit of directory table manipulation +BEGIN; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +----------------+---------------- + nation_commit2 | nation_updated +(1 row) + +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_subcommit' WITH TAG 'nation'; +SAVEPOINT s1; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit | nation +(2 rows) + +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_subcommit2'; +SAVEPOINT s2; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +-------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit | nation + nation_subcommit2 | +(3 rows) + +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_subcommit3'; +RELEASE SAVEPOINT s1; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +-------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit | nation + nation_subcommit2 | + nation_subcommit3 | +(4 rows) + +COMMIT; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +-------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit | nation + nation_subcommit2 | + nation_subcommit3 | +(4 rows) + +BEGIN; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +-------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit | nation + nation_subcommit2 | + nation_subcommit3 | +(4 rows) + +SELECT remove_file('dir_table4', 'nation_subcommit'); + remove_file +------------- + t +(1 row) + +SAVEPOINT s1; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +-------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit2 | + nation_subcommit3 | +(3 rows) + +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_subcommit'; +SAVEPOINT s2; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +-------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit | + nation_subcommit2 | + nation_subcommit3 | +(4 rows) + +RELEASE SAVEPOINT s1; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +-------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit | + nation_subcommit2 | + nation_subcommit3 | +(4 rows) + +COMMIT; +BEGIN; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +-------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit | + nation_subcommit2 | + nation_subcommit3 | +(4 rows) + +SELECT remove_file('dir_table4', 'nation_subcommit'); + remove_file +------------- + t +(1 row) + +SAVEPOINT s1; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +-------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit2 | + nation_subcommit3 | +(3 rows) + +SELECT remove_file('dir_table4', 'nation_subcommit2'); + remove_file +------------- + t +(1 row) + +SAVEPOINT s2; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +-------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit3 | +(2 rows) + +RELEASE SAVEPOINT s2; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +-------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit3 | +(2 rows) + +COMMIT; +BEGIN; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +-------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit3 | +(2 rows) + +SELECT remove_file('dir_table4', 'nation_subcommit2'); + remove_file +------------- + f +(1 row) + +SAVEPOINT s1; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +-------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit3 | +(2 rows) + +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_subcommit4'; +SAVEPOINT s2; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +-------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit3 | + nation_subcommit4 | +(3 rows) + +ROLLBACK TO SAVEPOINT s1; +COMMIT; +-- Test subtransaction rollback of directory table manipulation +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_subrollback1'; +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_subrollback2'; +BEGIN; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +---------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit3 | + nation_subrollback1 | + nation_subrollback2 | +(4 rows) + +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_subrollback3'; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +---------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit3 | + nation_subrollback1 | + nation_subrollback2 | + nation_subrollback3 | +(5 rows) + +SAVEPOINT s1; +SELECT remove_file('dir_table4', 'nation_subrollback1'); + remove_file +------------- + t +(1 row) + +SAVEPOINT s2; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +---------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit3 | + nation_subrollback2 | + nation_subrollback3 | +(4 rows) + +ROLLBACK; +BEGIN; +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_subrollback4'; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +---------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit3 | + nation_subrollback1 | + nation_subrollback2 | + nation_subrollback4 | +(5 rows) + +SAVEPOINT s1; +SELECT remove_file('dir_table4', 'nation_subrollback4'); + remove_file +------------- + t +(1 row) + +SAVEPOINT s2; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +---------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit3 | + nation_subrollback1 | + nation_subrollback2 | +(4 rows) + +RELEASE SAVEPOINT s1; +ROLLBACK; +BEGIN; +SELECT remove_file('dir_table4', 'nation_subrollback2'); + remove_file +------------- + t +(1 row) + +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_subrollback5'; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +---------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit3 | + nation_subrollback1 | + nation_subrollback5 | +(4 rows) + +SAVEPOINT s1; +SELECT remove_file('dir_table4', 'nation_subrollback5'); + remove_file +------------- + t +(1 row) + +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +---------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit3 | + nation_subrollback1 | +(3 rows) + +ROLLBACK TO SAVEPOINT s1; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +---------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit3 | + nation_subrollback1 | + nation_subrollback5 | +(4 rows) + +COPY BINARY dir_table4 FROM '@abs_srcdir@/data/nation.csv' 'nation_subrollback6'; +SELECT relative_path, tag FROM dir_table4 ORDER BY 1; + relative_path | tag +---------------------+---------------- + nation_commit2 | nation_updated + nation_subcommit3 | + nation_subrollback1 | + nation_subrollback5 | + nation_subrollback6 | +(5 rows) + +SAVEPOINT s2; +ROLLBACK; +-- clean up +DROP DIRECTORY TABLE IF EXISTS dir_table1; +DROP DIRECTORY TABLE IF EXISTS dir_table2; +DROP DIRECTORY TABLE IF EXISTS dir_table3; +DROP DIRECTORY TABLE IF EXISTS dir_table4; +DROP DIRECTORY TABLE IF EXISTS dir_table5; +NOTICE: directory table "dir_table5" does not exist, skipping +DROP DIRECTORY TABLE IF EXISTS dir_table6; +DROP FUNCTION IF EXISTS trigtest; +DROP STORAGE USER MAPPING IF EXISTS FOR CURRENT_USER STORAGE SERVER oss_server1; +DROP STORAGE USER MAPPING IF EXISTS FOR CURRENT_USER STORAGE SERVER oss_server2; +NOTICE: storage user mapping for "gpadmin" does not exist for storage server "oss_server2", skipping +DROP STORAGE USER MAPPING IF EXISTS FOR CURRENT_USER STORAGE SERVER oss_server3; +DROP STORAGE USER MAPPING IF EXISTS FOR CURRENT_USER STORAGE SERVER oss_server4; +NOTICE: storage server "oss_server4" does not exist, skipping +DROP STORAGE USER MAPPING IF EXISTS FOR test_dirtable1 STORAGE SERVER oss_server1; +NOTICE: storage user mapping for "test_dirtable1" does not exist for storage server "oss_server1", skipping +DROP STORAGE USER MAPPING IF EXISTS FOR test_dirtable1 STORAGE SERVER oss_server2; +DROP STORAGE USER MAPPING IF EXISTS FOR test_dirtable1 STORAGE SERVER oss_server3; +DROP STORAGE USER MAPPING IF EXISTS FOR test_dirtable2 STORAGE SERVER oss_server3; +DROP STORAGE USER MAPPING IF EXISTS FOR test_dirtable3 STORAGE SERVER oss_server8; +DROP STORAGE SERVER IF EXISTS oss_server1; +DROP STORAGE SERVER IF EXISTS oss_server2; +DROP STORAGE SERVER IF EXISTS oss_server3; +DROP STORAGE SERVER IF EXISTS oss_server4; +NOTICE: storage server "oss_server4" not exists, skipping +DROP STORAGE SERVER IF EXISTS oss_server5; +DROP STORAGE SERVER IF EXISTS oss_server6; +DROP STORAGE SERVER IF EXISTS oss_server7; +DROP STORAGE SERVER IF EXISTS oss_server8; +DROP STORAGE SERVER IF EXISTS oss_server9; +NOTICE: storage server "oss_server9" not exists, skipping +DROP STORAGE SERVER IF EXISTS oss_server10; +NOTICE: storage server "oss_server10" not exists, skipping +DROP STORAGE SERVER IF EXISTS oss_server11; +DROP STORAGE SERVER IF EXISTS oss_server12; +DROP STORAGE SERVER IF EXISTS oss_server13; +NOTICE: storage server "oss_server13" not exists, skipping +SELECT srvname, srvacl, srvoptions FROM gp_storage_server; + srvname | srvacl | srvoptions +---------+--------+------------ +(0 rows) + +DROP USER test_dirtable1; +DROP USER test_dirtable2; +DROP USER test_dirtable3; +DROP USER test_dirtable4; +DROP FUNCTION IF EXISTS file_content; +DROP FUNCTION IF EXISTS file_md5; +DROP FUNCTION IF EXISTS md5_equal; +DROP DATABASE dirtable_db; +DROP TRIGGER IF EXISTS trigtest_b_row_tg_dirtable_1 ON dir_table1; +NOTICE: relation "dir_table1" does not exist, skipping +DROP TRIGGER IF EXISTS trigtest_a_row_tg_dirtable_1 ON dir_table1; +NOTICE: relation "dir_table1" does not exist, skipping +DROP TRIGGER IF EXISTS trigtest_b_stmt_tg_dirtable_1 ON dir_table1; +NOTICE: relation "dir_table1" does not exist, skipping +DROP TRIGGER IF EXISTS trigtest_a_stmt_tg_dirtable_1 ON dir_table1; +NOTICE: relation "dir_table1" does not exist, skipping +DROP TABLESPACE directory_tblspc; diff --git a/src/test/regress/output/external_table.source b/src/test/regress/output/external_table.source index 61ea2c938af..bcea4533111 100644 --- a/src/test/regress/output/external_table.source +++ b/src/test/regress/output/external_table.source @@ -4896,7 +4896,7 @@ DROP TABLE test_part_integrity; -- Testing altering the distribution policy of external tables. CREATE WRITABLE EXTERNAL WEB TABLE ext_w_dist(a int, b int) EXECUTE 'cat > @abs_srcdir@/data/ext_w_dist.tbl' FORMAT 'TEXT' (DELIMITER AS '|' NULL AS 'null' ESCAPE AS ' ') DISTRIBUTED BY (a); ALTER TABLE ext_w_dist SET WITH (reorganize=true); -- should error out if forcing reorganize -ERROR: "ext_w_dist" is not a table +ERROR: "ext_w_dist" is not a table or directory table SELECT policytype, distkey FROM gp_distribution_policy WHERE localoid = 'ext_w_dist'::regclass; policytype | distkey ------------+--------- @@ -4904,7 +4904,7 @@ SELECT policytype, distkey FROM gp_distribution_policy WHERE localoid = 'ext_w_d (1 row) ALTER TABLE ext_w_dist SET DISTRIBUTED BY (b); -ERROR: "ext_w_dist" is not a table +ERROR: "ext_w_dist" is not a table or directory table SELECT policytype, distkey FROM gp_distribution_policy WHERE localoid = 'ext_w_dist'::regclass; policytype | distkey ------------+--------- @@ -4912,7 +4912,7 @@ SELECT policytype, distkey FROM gp_distribution_policy WHERE localoid = 'ext_w_d (1 row) ALTER TABLE ext_w_dist SET DISTRIBUTED RANDOMLY; -ERROR: "ext_w_dist" is not a table +ERROR: "ext_w_dist" is not a table or directory table SELECT policytype, distkey FROM gp_distribution_policy WHERE localoid = 'ext_w_dist'::regclass; policytype | distkey ------------+--------- @@ -4923,7 +4923,7 @@ CREATE EXTERNAL WEB TABLE ext_r_dist(a int) EXECUTE 'printf ${GP_SEGMENT_ID}' FO ERROR: readable external tables can't specify a DISTRIBUTED BY clause CREATE EXTERNAL WEB TABLE ext_r_dist(a int) EXECUTE 'printf ${GP_SEGMENT_ID}' FORMAT 'TEXT'; ALTER TABLE ext_r_dist SET DISTRIBUTED BY (a); -- should error out altering readable external tables' distribution policy -ERROR: "ext_r_dist" is not a table +ERROR: "ext_r_dist" is not a table or directory table -- Testing external table as the partition child. CREATE TABLE part_root(a int) PARTITION BY RANGE(a); CREATE TABLE part_child (LIKE part_root); @@ -4941,7 +4941,7 @@ SELECT policytype, distkey FROM gp_distribution_policy WHERE localoid = 'part_ex (1 row) ALTER TABLE part_root SET DISTRIBUTED BY (b); -ERROR: "part_ext_w" is not a table +ERROR: "part_ext_w" is not a table or directory table SELECT policytype, distkey FROM gp_distribution_policy WHERE localoid = 'part_ext_w'::regclass; policytype | distkey ------------+--------- diff --git a/src/test/singlenode_regress/expected/create_index.out b/src/test/singlenode_regress/expected/create_index.out index 60cc25a1609..3e561402a61 100644 --- a/src/test/singlenode_regress/expected/create_index.out +++ b/src/test/singlenode_regress/expected/create_index.out @@ -2372,14 +2372,14 @@ SELECT relid, parentrelid, level FROM pg_partition_tree('concur_reindex_part_ind -- REINDEX TABLE fails for partitioned indexes -- Top-most parent index REINDEX TABLE concur_reindex_part_index; -- error -ERROR: "concur_reindex_part_index" is not a table or materialized view +ERROR: "concur_reindex_part_index" is not a table, directory table or materialized view REINDEX TABLE CONCURRENTLY concur_reindex_part_index; -- error -ERROR: "concur_reindex_part_index" is not a table or materialized view +ERROR: "concur_reindex_part_index" is not a table, directory table or materialized view -- Partitioned index with no leaves REINDEX TABLE concur_reindex_part_index_10; -- error -ERROR: "concur_reindex_part_index_10" is not a table or materialized view +ERROR: "concur_reindex_part_index_10" is not a table, directory table or materialized view REINDEX TABLE CONCURRENTLY concur_reindex_part_index_10; -- error -ERROR: "concur_reindex_part_index_10" is not a table or materialized view +ERROR: "concur_reindex_part_index_10" is not a table, directory table or materialized view -- Cannot run in a transaction block BEGIN; REINDEX INDEX concur_reindex_part_index; diff --git a/src/test/singlenode_regress/expected/create_table_like.out b/src/test/singlenode_regress/expected/create_table_like.out index e308771620e..f7544b7e2d1 100644 --- a/src/test/singlenode_regress/expected/create_table_like.out +++ b/src/test/singlenode_regress/expected/create_table_like.out @@ -504,7 +504,7 @@ DROP TABLE noinh_con_copy, noinh_con_copy1; CREATE TABLE ctlt4 (a int, b text); CREATE SEQUENCE ctlseq1; CREATE TABLE ctlt10 (LIKE ctlseq1); -- fail -ERROR: "ctlseq1" is not a table, view, materialized view, composite type, or foreign table +ERROR: "ctlseq1" is not a table, directory table, view, materialized view, composite type, or foreign table LINE 1: CREATE TABLE ctlt10 (LIKE ctlseq1); ^ CREATE VIEW ctlv1 AS SELECT * FROM ctlt4; diff --git a/src/test/singlenode_regress/expected/oidjoins.out b/src/test/singlenode_regress/expected/oidjoins.out index 8ef30c843c7..4d6ad39fbb8 100644 --- a/src/test/singlenode_regress/expected/oidjoins.out +++ b/src/test/singlenode_regress/expected/oidjoins.out @@ -142,6 +142,9 @@ NOTICE: checking pg_largeobject {loid} => pg_largeobject_metadata {oid} NOTICE: checking pg_aggregate {aggfnoid} => pg_proc {oid} NOTICE: checking pg_aggregate {aggtransfn} => pg_proc {oid} NOTICE: checking pg_aggregate {aggfinalfn} => pg_proc {oid} +NOTICE: checking gp_storage_server {srvowner} => pg_authid {oid} +NOTICE: checking gp_storage_user_mapping {umserver} => gp_storage_server {oid} +NOTICE: checking gp_storage_user_mapping {umuser} => pg_authid {oid} NOTICE: checking pg_aggregate {aggcombinefn} => pg_proc {oid} NOTICE: checking pg_aggregate {aggserialfn} => pg_proc {oid} NOTICE: checking pg_aggregate {aggdeserialfn} => pg_proc {oid} @@ -179,6 +182,8 @@ NOTICE: checking pg_trigger {tgrelid,tgattr} => pg_attribute {attrelid,attnum} NOTICE: checking pg_event_trigger {evtowner} => pg_authid {oid} NOTICE: checking pg_event_trigger {evtfoid} => pg_proc {oid} NOTICE: checking pg_description {classoid} => pg_class {oid} +NOTICE: checking pg_directory_table {dtrelid} => pg_class {oid} +NOTICE: checking pg_directory_table {dttablespace} => pg_tablespace {oid} NOTICE: checking pg_cast {castsource} => pg_type {oid} NOTICE: checking pg_cast {casttarget} => pg_type {oid} NOTICE: checking pg_cast {castfunc} => pg_proc {oid} diff --git a/src/test/singlenode_regress/expected/opr_sanity.out b/src/test/singlenode_regress/expected/opr_sanity.out index fbac24e2306..85b3ce33312 100644 --- a/src/test/singlenode_regress/expected/opr_sanity.out +++ b/src/test/singlenode_regress/expected/opr_sanity.out @@ -402,12 +402,14 @@ WHERE 'cstring'::regtype = ANY (p1.proargtypes) AND NOT EXISTS(SELECT 1 FROM pg_conversion WHERE conproc = p1.oid) AND p1.oid != 'shell_in(cstring)'::regprocedure ORDER BY 1; - oid | proname -------+----------------- + oid | proname +------+--------------------- 2293 | cstring_out 2501 | cstring_send 7060 | get_role_status -(3 rows) + 8996 | remove_file + 9109 | remove_file_segment +(5 rows) -- Likewise, look for functions that return cstring and aren't datatype output -- functions nor typmod output functions. diff --git a/src/test/singlenode_regress/expected/sanity_check.out b/src/test/singlenode_regress/expected/sanity_check.out index 94b31962a9b..b47c31bc7e6 100644 --- a/src/test/singlenode_regress/expected/sanity_check.out +++ b/src/test/singlenode_regress/expected/sanity_check.out @@ -128,6 +128,7 @@ pg_db_role_setting|t pg_default_acl|t pg_depend|t pg_description|t +pg_directory_table|t pg_enum|t pg_event_trigger|t pg_extension|t diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index 7a0216ff100..9cecc124ce3 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -86,6 +86,8 @@ AlterRoleSetStmt AlterRoleStmt AlterSeqStmt AlterStatsStmt +AlterStorageServer +AlterStorageUserMappingStmt AlterSubscriptionStmt AlterSubscriptionType AlterSystemStmt @@ -484,6 +486,8 @@ CreateSeqStmt CreateStatsStmt CreateStmt CreateStmtContext +CreateStorageServerStmt +CreateStorageUserMappingStmt CreateSubscriptionStmt CreateTableAsStmt CreateTableSpaceStmt @@ -572,6 +576,8 @@ DropProfileStmt DropReplicationSlotCmd DropRoleStmt DropStmt +DropStorageServer +DropStorageUserMappingStmt DropSubscriptionStmt DropTableSpaceStmt DropUserMappingStmt