From 53b349d84947ee624800b23db06115def2d10280 Mon Sep 17 00:00:00 2001 From: Hemny Date: Mon, 5 Aug 2024 15:49:59 +0800 Subject: [PATCH] =?UTF-8?q?=E9=80=BB=E8=BE=91=E5=A4=8D=E5=88=B6=E6=94=AF?= =?UTF-8?q?=E6=8C=81Alter=20table=E7=9A=84DDL=E8=AF=AD=E5=8F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contrib/mppdb_decoding/mppdb_decoding.cpp | 14 +- contrib/sql_decoding/sql_decoding.cpp | 126 + contrib/test_decoding/test_decoding.cpp | 65 +- src/bin/pg_dump/pg_dump.cpp | 32 +- src/bin/pg_dump/pg_dump.h | 1 + src/common/backend/catalog/builtin_funcs.ini | 4 + src/common/backend/catalog/heap.cpp | 25 +- src/common/backend/catalog/pg_publication.cpp | 1 + src/common/backend/nodes/copyfuncs.cpp | 13 + src/common/backend/nodes/equalfuncs.cpp | 12 + src/common/backend/nodes/outfuncs.cpp | 3 + src/common/backend/nodes/readfuncs.cpp | 3 + src/common/backend/parser/gram.y | 1 + src/common/backend/parser/parse_utilcmd.cpp | 1 + src/common/backend/utils/adt/regproc.cpp | 2 +- src/common/backend/utils/adt/ruleutils.cpp | 111 +- src/common/backend/utils/cache/relcache.cpp | 12 +- src/common/backend/utils/init/globals.cpp | 3 +- .../optimizer/commands/cluster.cpp | 14 +- .../optimizer/commands/ddldeparse.cpp | 4035 +++++++++++++++-- .../optimizer/commands/event_trigger.cpp | 189 +- .../optimizer/commands/eventcmds.cpp | 60 +- .../optimizer/commands/publicationcmds.cpp | 85 +- .../optimizer/commands/subscriptioncmds.cpp | 160 + .../optimizer/commands/tablecmds.cpp | 742 ++- src/gausskernel/process/tcop/utility.cpp | 24 +- .../storage/access/common/reloptions.cpp | 8 +- .../storage/access/heap/heapam.cpp | 7 + .../storage/access/redo/redo_heapam.cpp | 4 + .../storage/access/rmgrdesc/heapdesc.cpp | 15 + .../access/transam/extreme_rto/dispatcher.cpp | 2 +- .../ondemand_extreme_rto/dispatcher.cpp | 2 +- .../transam/parallel_recovery/dispatcher.cpp | 2 +- .../replication/logical/ddlmessage.cpp | 2 +- .../replication/logical/ddltrigger.cpp | 286 +- .../storage/replication/logical/decode.cpp | 42 + .../storage/replication/logical/logical.cpp | 49 + .../replication/logical/logical_parse.cpp | 2 + .../storage/replication/logical/proto.cpp | 53 + .../replication/logical/reorderbuffer.cpp | 42 +- .../storage/replication/logical/worker.cpp | 74 +- .../storage/replication/pgoutput/pgoutput.cpp | 164 +- src/include/access/htup.h | 22 + src/include/catalog/heap.h | 47 +- src/include/catalog/pg_publication.h | 8 +- .../rollback-post_catalog_maindb_92_949.sql | 1 + .../rollback-post_catalog_otherdb_92_949.sql | 1 + .../upgrade-post_catalog_maindb_92_949.sql | 6 + .../upgrade-post_catalog_otherdb_92_949.sql | 6 + src/include/commands/defrem.h | 8 +- src/include/commands/event_trigger.h | 7 +- src/include/commands/tablecmds.h | 5 + src/include/knl/knl_session.h | 1 + src/include/miscadmin.h | 1 + src/include/nodes/parsenodes.h | 1 + src/include/nodes/parsenodes_common.h | 3 + src/include/replication/ddlmessage.h | 9 +- src/include/replication/logicalproto.h | 4 + src/include/replication/output_plugin.h | 12 + src/include/replication/reorderbuffer.h | 26 +- src/include/tcop/ddldeparse.h | 65 + src/include/tcop/deparse_utility.h | 2 + src/include/utils/rel.h | 3 + src/test/regress/expected/object_address.out | 4 +- .../regress/expected/on_update_session2.out | 2 +- src/test/regress/output/publication.source | 4 +- src/test/regress/pg_regress.cpp | 2 +- src/test/subscription/schedule | 2 +- .../A/acceptable_diff/create_table.diff | 25 - .../ddl_replication_sql/A/create_table.sql | 21 + .../A/ddl_alter_function.setup | 9 + .../A/ddl_alter_function.sql | 55 + .../A/ddl_alter_function.teardown | 8 + .../ddl_replication_sql/A/ddl_alter_table.sql | 2418 ++++++++++ .../A/ddl_alter_table_001.sql | 785 ++++ .../A/ddl_alter_table_002.sql | 2011 ++++++++ .../A/ddl_alter_table_fastcheck.setup | 11 + .../A/ddl_alter_table_fastcheck.sql | 692 +++ .../A/ddl_alter_table_fastcheck.teardown | 19 + .../A/ddl_alter_table_rewrite.setup | 9 + .../A/ddl_alter_table_rewrite.sql | 26 + .../A/ddl_alter_table_rewrite.teardown | 8 + .../A/ddl_alter_table_subpartition.setup | 24 + .../A/ddl_alter_table_subpartition.sql | 2156 +++++++++ .../A/ddl_create_trigger.sql | 100 + .../ddl_replication_sql/A/ddl_create_type.sql | 5 + .../ddl_replication_sql/A/ddl_drop_type.sql | 13 + .../A/ddl_subpartition_tablespace.setup | 20 + .../A/ddl_subpartition_tablespace.sql | 1013 +++++ .../ddl_replication_sql/A/ddl_view_def.sql | 36 + .../acceptable_diff/ddl_alter_table_002.diff | 4 + .../ddl_alter_table_rewrite.diff | 4 + .../ddl_replication_sql/B/create_table.sql | 8 +- .../B/ddl_alter_function.setup | 9 + .../B/ddl_alter_function.sql | 67 + .../B/ddl_alter_function.teardown | 8 + .../B/ddl_alter_schema.setup | 9 + .../B/ddl_alter_schema.sql | 15 + .../B/ddl_alter_schema.teardown | 8 + .../ddl_replication_sql/B/ddl_alter_table.sql | 2358 ++++++++++ .../B/ddl_alter_table_001.sql | 789 ++++ .../B/ddl_alter_table_002.sql | 2011 ++++++++ .../B/ddl_alter_table_fastcheck.setup | 15 + .../B/ddl_alter_table_fastcheck.sql | 930 ++++ .../B/ddl_alter_table_fastcheck.teardown | 19 + .../B/ddl_alter_table_rewrite.setup | 9 + .../B/ddl_alter_table_rewrite.sql | 26 + .../B/ddl_alter_table_rewrite.teardown | 8 + .../B/ddl_alter_table_subpartition.setup | 24 + .../B/ddl_alter_table_subpartition.sql | 2242 +++++++++ .../B/ddl_create_trigger.sql | 109 + .../ddl_replication_sql/B/ddl_create_type.sql | 2 + .../ddl_replication_sql/B/ddl_drop_type.sql | 13 + .../B/ddl_subpartition_tablespace.setup | 20 + .../B/ddl_subpartition_tablespace.sql | 1052 +++++ .../ddl_replication_sql/B/ddl_view_def.sql | 36 + .../testcase/dump_expected/dump_db_puball.pub | 3 +- .../testcase/dump_expected/dump_db_puball.sub | 1 - .../dump_expected/dump_db_pubtable.pub | 1 - .../dump_expected/dump_db_pubtable.sub | 1 - 120 files changed, 25361 insertions(+), 648 deletions(-) create mode 100644 src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback-post_catalog_maindb_92_949.sql create mode 100644 src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback-post_catalog_otherdb_92_949.sql create mode 100644 src/include/catalog/upgrade_sql/upgrade_catalog_maindb/upgrade-post_catalog_maindb_92_949.sql create mode 100644 src/include/catalog/upgrade_sql/upgrade_catalog_otherdb/upgrade-post_catalog_otherdb_92_949.sql delete mode 100644 src/test/subscription/testcase/ddl_replication_sql/A/acceptable_diff/create_table.diff create mode 100644 src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_function.setup create mode 100644 src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_function.sql create mode 100644 src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_function.teardown create mode 100644 src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table.sql create mode 100644 src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_001.sql create mode 100644 src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_002.sql create mode 100644 src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_fastcheck.setup create mode 100644 src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_fastcheck.sql create mode 100644 src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_fastcheck.teardown create mode 100644 src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_rewrite.setup create mode 100644 src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_rewrite.sql create mode 100644 src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_rewrite.teardown create mode 100644 src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_subpartition.setup create mode 100644 src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_subpartition.sql create mode 100644 src/test/subscription/testcase/ddl_replication_sql/A/ddl_create_trigger.sql create mode 100644 src/test/subscription/testcase/ddl_replication_sql/A/ddl_create_type.sql create mode 100644 src/test/subscription/testcase/ddl_replication_sql/A/ddl_drop_type.sql create mode 100644 src/test/subscription/testcase/ddl_replication_sql/A/ddl_subpartition_tablespace.setup create mode 100644 src/test/subscription/testcase/ddl_replication_sql/A/ddl_subpartition_tablespace.sql create mode 100644 src/test/subscription/testcase/ddl_replication_sql/A/ddl_view_def.sql create mode 100644 src/test/subscription/testcase/ddl_replication_sql/B/acceptable_diff/ddl_alter_table_002.diff create mode 100644 src/test/subscription/testcase/ddl_replication_sql/B/acceptable_diff/ddl_alter_table_rewrite.diff create mode 100644 src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_function.setup create mode 100644 src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_function.sql create mode 100644 src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_function.teardown create mode 100644 src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_schema.setup create mode 100644 src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_schema.sql create mode 100644 src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_schema.teardown create mode 100644 src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table.sql create mode 100644 src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_001.sql create mode 100644 src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_002.sql create mode 100644 src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_fastcheck.setup create mode 100644 src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_fastcheck.sql create mode 100644 src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_fastcheck.teardown create mode 100644 src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_rewrite.setup create mode 100644 src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_rewrite.sql create mode 100644 src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_rewrite.teardown create mode 100644 src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_subpartition.setup create mode 100644 src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_subpartition.sql create mode 100644 src/test/subscription/testcase/ddl_replication_sql/B/ddl_create_trigger.sql create mode 100644 src/test/subscription/testcase/ddl_replication_sql/B/ddl_create_type.sql create mode 100644 src/test/subscription/testcase/ddl_replication_sql/B/ddl_drop_type.sql create mode 100644 src/test/subscription/testcase/ddl_replication_sql/B/ddl_subpartition_tablespace.setup create mode 100644 src/test/subscription/testcase/ddl_replication_sql/B/ddl_subpartition_tablespace.sql create mode 100644 src/test/subscription/testcase/ddl_replication_sql/B/ddl_view_def.sql diff --git a/contrib/mppdb_decoding/mppdb_decoding.cpp b/contrib/mppdb_decoding/mppdb_decoding.cpp index 2734c3e1c..4953f24e5 100644 --- a/contrib/mppdb_decoding/mppdb_decoding.cpp +++ b/contrib/mppdb_decoding/mppdb_decoding.cpp @@ -438,9 +438,19 @@ static char *mppdb_deparse_command_type(DeparsedCommandType cmdtype) case DCT_SimpleCmd: return "Simple"; case DCT_TableDropStart: - return "Drop table"; + return "Drop Table"; case DCT_TableDropEnd: return "Drop Table End"; + case DCT_TableAlter: + return "Alter Table"; + case DCT_ObjectCreate: + return "Create Object"; + case DCT_ObjectDrop: + return "Drop Object"; + case DCT_TypeDropStart: + return "Drop Type"; + case DCT_TypeDropEnd: + return "Drop Type End"; default: Assert(false); } @@ -476,7 +486,7 @@ static void pg_decode_ddl(LogicalDecodingContext *ctx, sz, message); - if (cmdtype != DCT_TableDropStart) { + if (cmdtype != DCT_TableDropStart && cmdtype != DCT_TypeDropStart) { char *tmp = pstrdup(message); char *owner = NULL; char *decodestring = deparse_ddl_json_to_string(tmp, &owner); diff --git a/contrib/sql_decoding/sql_decoding.cpp b/contrib/sql_decoding/sql_decoding.cpp index 065d8466f..f545ec6a7 100644 --- a/contrib/sql_decoding/sql_decoding.cpp +++ b/contrib/sql_decoding/sql_decoding.cpp @@ -44,6 +44,7 @@ #include "utils/typcache.h" #include "replication/output_plugin.h" #include "replication/logical.h" +#include "tcop/ddldeparse.h" PG_MODULE_MAGIC; @@ -59,6 +60,15 @@ static void pg_decode_abort_txn(LogicalDecodingContext* ctx, ReorderBufferTXN* t static void pg_decode_change( LogicalDecodingContext* ctx, ReorderBufferTXN* txn, Relation rel, ReorderBufferChange* change); static bool pg_decode_filter(LogicalDecodingContext* ctx, RepOriginId origin_id); +static void pg_decode_truncate(LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, + int nrelations, Relation relations[], + ReorderBufferChange *change); +static void pg_decode_ddl(LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, XLogRecPtr message_lsn, + const char *prefix, Oid relid, + DeparsedCommandType cmdtype, + Size sz, const char *message); typedef struct { MemoryContext context; @@ -78,6 +88,8 @@ void _PG_output_plugin_init(OutputPluginCallbacks* cb) cb->begin_cb = pg_decode_begin_txn; cb->change_cb = pg_decode_change; cb->commit_cb = pg_decode_commit_txn; + cb->truncate_cb = pg_decode_truncate; + cb->ddl_cb = pg_decode_ddl; cb->abort_cb = pg_decode_abort_txn; cb->filter_by_origin_cb = pg_decode_filter; cb->shutdown_cb = pg_decode_shutdown; @@ -507,3 +519,117 @@ static void pg_decode_change( OutputPluginWrite(ctx, true); } + + +static void pg_decode_truncate(LogicalDecodingContext *ctx, ReorderBufferTXN *txn, + int nrelations, Relation relations[], ReorderBufferChange *change) +{ + TestDecodingData *data; + MemoryContext old; + int i; + + data = (TestDecodingData*)ctx->output_plugin_private; + + /* output BEGIN if we haven't yet */ + if (data->skip_empty_xacts && !data->xact_wrote_changes) { + pg_output_begin(ctx, data, txn, false); + } + data->xact_wrote_changes = true; + + /* Avoid leaking memory by using and resetting our own context */ + old = MemoryContextSwitchTo(data->context); + + OutputPluginPrepareWrite(ctx, true); + + appendStringInfoString(ctx->out, "table "); + + for (i = 0; i < nrelations; i++) { + if (i > 0) + appendStringInfoString(ctx->out, ", "); + + appendStringInfoString(ctx->out, + quote_qualified_identifier(get_namespace_name(relations[i]->rd_rel->relnamespace), + NameStr(relations[i]->rd_rel->relname))); + } + + appendStringInfoString(ctx->out, ": TRUNCATE:"); + + if (change->data.truncate.restart_seqs + || change->data.truncate.cascade) { + if (change->data.truncate.restart_seqs) + appendStringInfo(ctx->out, " restart_seqs"); + if (change->data.truncate.cascade) + appendStringInfo(ctx->out, " cascade"); + } else + appendStringInfoString(ctx->out, " (no-flags)"); + + MemoryContextSwitchTo(old); + MemoryContextReset(data->context); + + OutputPluginWrite(ctx, true); +} + +static char* deparse_command_type(DeparsedCommandType cmdtype) +{ + switch (cmdtype) { + case DCT_SimpleCmd: + return "Simple"; + case DCT_TableDropStart: + return "Drop Table"; + case DCT_TableDropEnd: + return "Drop Table End"; + case DCT_TableAlter: + return "Alter Table"; + case DCT_ObjectCreate: + return "Create Object"; + case DCT_ObjectDrop: + return "Drop Object"; + case DCT_TypeDropStart: + return "Drop Type"; + case DCT_TypeDropEnd: + return "Drop Type End"; + default: + Assert(false); + } + return NULL; +} + +static void pg_decode_ddl(LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, XLogRecPtr message_lsn, + const char *prefix, Oid relid, + DeparsedCommandType cmdtype, + Size sz, const char *message) +{ + TestDecodingData *data; + MemoryContext old; + + data = (TestDecodingData*)ctx->output_plugin_private; + + if (data->skip_empty_xacts && !data->xact_wrote_changes) { + pg_output_begin(ctx, data, txn, false); + } + data->xact_wrote_changes = true; + + /* Avoid leaking memory by using and resetting our own context */ + old = MemoryContextSwitchTo(data->context); + OutputPluginPrepareWrite(ctx, true); + + appendStringInfo(ctx->out, "message: prefix %s, relid %u, cmdtype: %s, sz: %lu content: %s", + prefix, + relid, + deparse_command_type(cmdtype), + sz, + message); + if (cmdtype != DCT_TableDropStart) { + char *tmp = pstrdup(message); + char* owner = NULL; + char* decodestring = deparse_ddl_json_to_string(tmp, &owner); + appendStringInfo(ctx->out, "\ndecode to : %s, [owner %s]", decodestring, owner ? owner : "none"); + pfree(tmp); + } + + MemoryContextSwitchTo(old); + MemoryContextReset(data->context); + + OutputPluginWrite(ctx, true); +} \ No newline at end of file diff --git a/contrib/test_decoding/test_decoding.cpp b/contrib/test_decoding/test_decoding.cpp index 7f5dacfb9..2b82504d5 100644 --- a/contrib/test_decoding/test_decoding.cpp +++ b/contrib/test_decoding/test_decoding.cpp @@ -49,6 +49,10 @@ static void pg_decode_prepare_txn(LogicalDecodingContext* ctx, ReorderBufferTXN* static void pg_decode_change( LogicalDecodingContext* ctx, ReorderBufferTXN* txn, Relation rel, ReorderBufferChange* change); static bool pg_decode_filter(LogicalDecodingContext* ctx, RepOriginId origin_id); +static void pg_decode_truncate(LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, + int nrelations, Relation relations[], + ReorderBufferChange *change); static void pg_decode_ddl(LogicalDecodingContext* ctx, ReorderBufferTXN* txn, XLogRecPtr message_lsn, const char *prefix, Oid relid, DeparsedCommandType cmdtype, Size sz, const char *message); @@ -65,6 +69,7 @@ void _PG_output_plugin_init(OutputPluginCallbacks* cb) cb->startup_cb = pg_decode_startup; cb->begin_cb = pg_decode_begin_txn; cb->change_cb = pg_decode_change; + cb->truncate_cb = pg_decode_truncate; cb->commit_cb = pg_decode_commit_txn; cb->abort_cb = pg_decode_abort_txn; cb->prepare_cb = pg_decode_prepare_txn; @@ -312,15 +317,73 @@ static void pg_decode_change( OutputPluginWrite(ctx, true); } +static void pg_decode_truncate(LogicalDecodingContext *ctx, ReorderBufferTXN *txn, + int nrelations, Relation relations[], ReorderBufferChange *change) +{ + PluginTestDecodingData *data; + MemoryContext old; + int i; + + data = (PluginTestDecodingData*)ctx->output_plugin_private; + + /* output BEGIN if we haven't yet */ + if (data->skip_empty_xacts && !data->xact_wrote_changes) { + pg_output_begin(ctx, data, txn, false); + } + data->xact_wrote_changes = true; + + /* Avoid leaking memory by using and resetting our own context */ + old = MemoryContextSwitchTo(data->context); + + OutputPluginPrepareWrite(ctx, true); + + appendStringInfoString(ctx->out, "table "); + + for (i = 0; i < nrelations; i++) { + if (i > 0) + appendStringInfoString(ctx->out, ", "); + + appendStringInfoString(ctx->out, + quote_qualified_identifier(get_namespace_name(relations[i]->rd_rel->relnamespace), + NameStr(relations[i]->rd_rel->relname))); + } + + appendStringInfoString(ctx->out, ": TRUNCATE:"); + + if (change->data.truncate.restart_seqs + || change->data.truncate.cascade) { + if (change->data.truncate.restart_seqs) + appendStringInfo(ctx->out, " restart_seqs"); + if (change->data.truncate.cascade) + appendStringInfo(ctx->out, " cascade"); + } else + appendStringInfoString(ctx->out, " (no-flags)"); + + MemoryContextSwitchTo(old); + MemoryContextReset(data->context); + + OutputPluginWrite(ctx, true); +} + static char *deparse_command_type(DeparsedCommandType cmdtype) { switch (cmdtype) { case DCT_SimpleCmd: return "Simple"; case DCT_TableDropStart: - return "Drop table"; + return "Drop Table"; case DCT_TableDropEnd: return "Drop Table End"; + case DCT_TableAlter: + return "Alter Table"; + case DCT_ObjectCreate: + return "Create Object"; + case DCT_ObjectDrop: + return "Drop Object"; + case DCT_TypeDropStart: + return "Drop Type"; + case DCT_TypeDropEnd: + return "Drop Type End"; default: Assert(false); } diff --git a/src/bin/pg_dump/pg_dump.cpp b/src/bin/pg_dump/pg_dump.cpp index 9d44a2739..c82db4637 100644 --- a/src/bin/pg_dump/pg_dump.cpp +++ b/src/bin/pg_dump/pg_dump.cpp @@ -302,6 +302,7 @@ const uint32 EVENT_VERSION = 92844; const uint32 EVENT_TRIGGER_VERSION_NUM = 92845; const uint32 RB_OBJECT_VERSION_NUM = 92831; const uint32 PUBLICATION_DDL_VERSION_NUM = 92921; +const uint32 PUBLICATION_DDL_AT_VERSION_NUM = 92949; #ifdef DUMPSYSLOG char* syslogpath = NULL; @@ -4411,6 +4412,7 @@ void getPublications(Archive *fout) int i_pubinsert; int i_pubupdate; int i_pubdelete; + int i_pubtruncate = 0; int i_pubddl = 0; int i, ntups; @@ -4423,7 +4425,14 @@ void getPublications(Archive *fout) resetPQExpBuffer(query); /* Get the publications. */ - if (GetVersionNum(fout) >= PUBLICATION_DDL_VERSION_NUM) { + if (GetVersionNum(fout) >= PUBLICATION_DDL_AT_VERSION_NUM) { + appendPQExpBuffer(query, + "SELECT p.tableoid, p.oid, p.pubname, " + "(%s p.pubowner) AS rolname, " + "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete, p.pubtruncate, p.pubddl " + "FROM pg_catalog.pg_publication p", + username_subquery); + } else if (GetVersionNum(fout) >= PUBLICATION_DDL_VERSION_NUM) { appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, p.pubname, " "(%s p.pubowner) AS rolname, " @@ -4456,7 +4465,10 @@ void getPublications(Archive *fout) i_pubinsert = PQfnumber(res, "pubinsert"); i_pubupdate = PQfnumber(res, "pubupdate"); i_pubdelete = PQfnumber(res, "pubdelete"); - if (GetVersionNum(fout) >= PUBLICATION_DDL_VERSION_NUM) { + if (GetVersionNum(fout) >= PUBLICATION_DDL_AT_VERSION_NUM) { + i_pubtruncate = PQfnumber(res, "pubtruncate"); + i_pubddl = PQfnumber(res, "pubddl"); + } else if (GetVersionNum(fout) >= PUBLICATION_DDL_VERSION_NUM) { i_pubddl = PQfnumber(res, "pubddl"); } @@ -4473,7 +4485,10 @@ void getPublications(Archive *fout) pubinfo[i].pubinsert = (strcmp(PQgetvalue(res, i, i_pubinsert), "t") == 0); pubinfo[i].pubupdate = (strcmp(PQgetvalue(res, i, i_pubupdate), "t") == 0); pubinfo[i].pubdelete = (strcmp(PQgetvalue(res, i, i_pubdelete), "t") == 0); - if (GetVersionNum(fout) >= PUBLICATION_DDL_VERSION_NUM) { + if (GetVersionNum(fout) >= PUBLICATION_DDL_AT_VERSION_NUM) { + pubinfo[i].pubtruncate = (strcmp(PQgetvalue(res, i, i_pubtruncate), "t") == 0); + pubinfo[i].pubddl = atoxid(PQgetvalue(res, i, i_pubddl)); + } else if (GetVersionNum(fout) >= PUBLICATION_DDL_VERSION_NUM) { pubinfo[i].pubddl = atol(PQgetvalue(res, i, i_pubddl)); } @@ -4539,6 +4554,14 @@ static void dumpPublication(Archive *fout, const PublicationInfo *pubinfo) first = false; } + if (pubinfo->pubtruncate) { + if (!first) { + appendPQExpBufferStr(query, ", "); + } + appendPQExpBufferStr(query, "truncate"); + first = false; + } + if (GetVersionNum(fout) >= PUBLICATION_DDL_VERSION_NUM && pubinfo->pubddl != 0) { if (!first) { appendPQExpBufferStr(query, "',"); @@ -23698,7 +23721,8 @@ getEventTriggers(Archive *fout, int *numEventTriggers) static bool eventtrigger_filter(EventTriggerInfo *evtinfo) { static char *reserved_trigger_prefix[] = {PUB_EVENT_TRIG_PREFIX PUB_TRIG_DDL_CMD_END, - PUB_EVENT_TRIG_PREFIX PUB_TRIG_DDL_CMD_START}; + PUB_EVENT_TRIG_PREFIX PUB_TRIG_DDL_CMD_START, + PUB_EVENT_TRIG_PREFIX PUB_TRIG_TBL_REWRITE}; static const size_t triggerPrefixLength = sizeof(reserved_trigger_prefix) / sizeof(reserved_trigger_prefix[0]); for (size_t i = 0; i < triggerPrefixLength; ++i) { diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h index 0aca8de73..d32cf51f4 100644 --- a/src/bin/pg_dump/pg_dump.h +++ b/src/bin/pg_dump/pg_dump.h @@ -517,6 +517,7 @@ typedef struct _PublicationInfo { bool pubinsert; bool pubupdate; bool pubdelete; + bool pubtruncate; int64 pubddl; } PublicationInfo; diff --git a/src/common/backend/catalog/builtin_funcs.ini b/src/common/backend/catalog/builtin_funcs.ini index 9c535f431..f8c0ec6aa 100644 --- a/src/common/backend/catalog/builtin_funcs.ini +++ b/src/common/backend/catalog/builtin_funcs.ini @@ -9842,6 +9842,10 @@ AddFuncGroup( "publication_deparse_ddl_command_start", 1, AddBuiltinFunc(_0(4643), _1("publication_deparse_ddl_command_start"), _2(2), _3(true), _4(false), _5(publication_deparse_ddl_command_start), _6(3838), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('v'), _19(0), _20(0), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("publication_deparse_ddl_command_start"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) ), + AddFuncGroup( + "publication_deparse_table_rewrite", 1, + AddBuiltinFunc(_0(4644), _1("publication_deparse_table_rewrite"), _2(2), _3(true), _4(false), _5(publication_deparse_table_rewrite), _6(3838), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('v'), _19(0), _20(0), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("publication_deparse_table_rewrite"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) + ), AddFuncGroup( "pv_builtin_functions", 1, AddBuiltinFunc(_0(5345), _1("pv_builtin_functions"), _2(0), _3(false), _4(true), _5(pv_builtin_functions), _6(2249), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(3100), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('s'), _19(0), _20(0), _21(32, 19, 26, 26, 26, 700, 700, 26, 24, 16, 16, 16, 16, 16, 16, 18, 21, 21, 26, 30, 1007, 1002, 1009, 194, 25, 25, 1009, 1034, 22, 16, 16, 16, 26), _22(32, 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o'), _23(32, "proname", "pronamespace", "proowner", "prolang", "procost", "prorows", "provariadic", "protransform", "proisagg", "proiswindow", "prosecdef", "proleakproof", "proisstrict", "proretset", "provolatile", "pronargs", "pronargdefaults", "prorettype", "proargtypes", "proallargtypes", "proargmodes", "proargnames", "proargdefaults", "prosrc", "probin", "proconfig", "proacl", "prodefaultargpos", "fencedmode", "proshippable", "propackage", "oid"), _24(NULL), _25("pv_builtin_functions"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) diff --git a/src/common/backend/catalog/heap.cpp b/src/common/backend/catalog/heap.cpp index 59c61da5d..927fee18e 100644 --- a/src/common/backend/catalog/heap.cpp +++ b/src/common/backend/catalog/heap.cpp @@ -1284,6 +1284,10 @@ void InsertPgClassTuple( else values[Anum_pg_class_relreplident - 1] = REPLICA_IDENTITY_NOTHING; + if (new_rel_desc->relreplident && new_rel_desc->relreplident != REPLICA_IDENTITY_NOTHING) { + values[Anum_pg_class_relreplident - 1] = new_rel_desc->relreplident; + } + if (OidIsValid(new_rel_desc->rd_bucketoid)) { Assert(new_rel_desc->storage_type == SEGMENT_PAGE); values[Anum_pg_class_relbucket - 1] = ObjectIdGetDatum(new_rel_desc->rd_bucketoid); @@ -2590,6 +2594,15 @@ static Datum AddSegmentOption(Datum relOptions) return transformRelOptions((Datum)0, optsList, NULL, NULL, false, false); } +static Datum AddRelrewriteOption(Datum relOptions, Oid relrewrite) +{ + DefElem *def = makeDefElem(pstrdup("relrewrite"), (Node *)makeInteger(relrewrite)); + List* optsList = untransformRelOptions(relOptions); + optsList = lappend(optsList, def); + + return transformRelOptions((Datum)0, optsList, NULL, NULL, false, false); +} + Node* GetColumnRef(Node* key, bool* isExpr, bool* isFunc) { Node* result = NULL; @@ -2680,7 +2693,7 @@ Oid heap_create_with_catalog(const char *relname, Oid relnamespace, Oid reltable int oidinhcount, OnCommitAction oncommit, Datum reloptions, bool use_user_acl, bool allow_system_table_mods, PartitionState *partTableState, int8 row_compress, HashBucketInfo *bucketinfo, bool record_dependce, List *ceLst, StorageType storage_type, - LOCKMODE partLockMode, ObjectAddress *typaddress, List* depend_extend) + LOCKMODE partLockMode, ObjectAddress *typaddress, List* depend_extend, Oid relrewrite) { Relation pg_class_desc; Relation new_rel_desc; @@ -2879,6 +2892,10 @@ Oid heap_create_with_catalog(const char *relname, Oid relnamespace, Oid reltable relhasbucket = true; } + if (OidIsValid(relrewrite)) { + reloptions = AddRelrewriteOption(reloptions, relrewrite); + } + /* Get tableAmType from reloptions and relkind */ bytea* hreloptions = heap_reloptions(relkind, reloptions, false); TableAmType tam = get_tableam_from_reloptions(hreloptions, relkind, InvalidOid); @@ -2924,6 +2941,12 @@ Oid heap_create_with_catalog(const char *relname, Oid relnamespace, Oid reltable storage_type ); + if (OidIsValid(relrewrite)) { + Relation OldHeap = heap_open(relrewrite, AccessExclusiveLock); + new_rel_desc->relreplident = OldHeap->relreplident; + heap_close(OldHeap, AccessExclusiveLock); + } + /* Recode the table or other object in pg_class create time. */ PgObjectType objectType = GetPgObjectTypePgClass(relkind); if (objectType != OBJECT_TYPE_INVALID) { diff --git a/src/common/backend/catalog/pg_publication.cpp b/src/common/backend/catalog/pg_publication.cpp index c13abc28f..55a31a453 100644 --- a/src/common/backend/catalog/pg_publication.cpp +++ b/src/common/backend/catalog/pg_publication.cpp @@ -144,6 +144,7 @@ static Publication *GetPublication(Oid pubid) pub->pubactions.pubinsert = pubform->pubinsert; pub->pubactions.pubupdate = pubform->pubupdate; pub->pubactions.pubdelete = pubform->pubdelete; + pub->pubactions.pubtruncate = pubform->pubtruncate; pub->pubactions.pubddl = pubform->pubddl; ReleaseSysCache(tup); diff --git a/src/common/backend/nodes/copyfuncs.cpp b/src/common/backend/nodes/copyfuncs.cpp index 1bf48d267..fdb4eda87 100644 --- a/src/common/backend/nodes/copyfuncs.cpp +++ b/src/common/backend/nodes/copyfuncs.cpp @@ -4456,6 +4456,10 @@ static ColumnDef* _copyColumnDef(const ColumnDef* from) COPY_NODE_FIELD(clientLogicColumnRef); COPY_NODE_FIELD(position); COPY_NODE_FIELD(update_default); + if (t_thrd.proc->workingVersionNum >= PUBLICATION_DDL_AT_VERSION_NUM) { + COPY_STRING_FIELD(initdefval); + } + return newnode; } @@ -5214,6 +5218,9 @@ static AlterTableCmd* _copyAlterTableCmd(const AlterTableCmd* from) COPY_SCALAR_FIELD(alterGPI); COPY_SCALAR_FIELD(is_first); COPY_STRING_FIELD(after_name); + if (t_thrd.proc->workingVersionNum >= PUBLICATION_DDL_AT_VERSION_NUM) { + COPY_SCALAR_FIELD(recursing); + } return newnode; } @@ -5683,6 +5690,9 @@ static AlterFunctionStmt* _copyAlterFunctionStmt(const AlterFunctionStmt* from) COPY_NODE_FIELD(func); COPY_NODE_FIELD(actions); + if (t_thrd.proc->workingVersionNum >= PUBLICATION_DDL_AT_VERSION_NUM) { + COPY_SCALAR_FIELD(isProcedure); + } return newnode; } @@ -5733,6 +5743,9 @@ static RenameStmt* _copyRenameStmt(const RenameStmt* from) COPY_SCALAR_FIELD(missing_ok); COPY_NODE_FIELD(renameTargetList); COPY_SCALAR_FIELD(renameTableflag); + if (t_thrd.proc->workingVersionNum >= PUBLICATION_DDL_AT_VERSION_NUM) { + COPY_SCALAR_FIELD(is_modifycolumn); + } return newnode; } diff --git a/src/common/backend/nodes/equalfuncs.cpp b/src/common/backend/nodes/equalfuncs.cpp index 9bce5df97..81c433b45 100644 --- a/src/common/backend/nodes/equalfuncs.cpp +++ b/src/common/backend/nodes/equalfuncs.cpp @@ -1167,6 +1167,9 @@ static bool _equalAlterTableCmd(const AlterTableCmd* a, const AlterTableCmd* b) COMPARE_SCALAR_FIELD(alterGPI); COMPARE_SCALAR_FIELD(is_first); COMPARE_STRING_FIELD(after_name); + if (t_thrd.proc->workingVersionNum >= PUBLICATION_DDL_AT_VERSION_NUM) { + COMPARE_SCALAR_FIELD(recursing); + } return true; } @@ -1617,6 +1620,9 @@ static bool _equalAlterFunctionStmt(const AlterFunctionStmt* a, const AlterFunct { COMPARE_NODE_FIELD(func); COMPARE_NODE_FIELD(actions); + if (t_thrd.proc->workingVersionNum >= PUBLICATION_DDL_AT_VERSION_NUM) { + COMPARE_SCALAR_FIELD(isProcedure); + } return true; } @@ -1659,6 +1665,9 @@ static bool _equalRenameStmt(const RenameStmt* a, const RenameStmt* b) COMPARE_SCALAR_FIELD(missing_ok); COMPARE_NODE_FIELD(renameTargetList); COMPARE_SCALAR_FIELD(renameTableflag); + if (t_thrd.proc->workingVersionNum >= PUBLICATION_DDL_AT_VERSION_NUM) { + COMPARE_SCALAR_FIELD(is_modifycolumn); + } return true; } @@ -2913,6 +2922,9 @@ static bool _equalColumnDef(const ColumnDef* a, const ColumnDef* b) COMPARE_NODE_FIELD(fdwoptions); COMPARE_NODE_FIELD(columnOptions); COMPARE_NODE_FIELD(update_default); + if (t_thrd.proc->workingVersionNum >= PUBLICATION_DDL_AT_VERSION_NUM) { + COMPARE_STRING_FIELD(initdefval); + } return true; } diff --git a/src/common/backend/nodes/outfuncs.cpp b/src/common/backend/nodes/outfuncs.cpp index 0f3be412e..e70984e91 100755 --- a/src/common/backend/nodes/outfuncs.cpp +++ b/src/common/backend/nodes/outfuncs.cpp @@ -4358,6 +4358,9 @@ static void _outColumnDef(StringInfo str, ColumnDef* node) if (t_thrd.proc->workingVersionNum >= ON_UPDATE_TIMESTAMP_VERSION_NUM) { WRITE_NODE_FIELD(update_default); } + if (t_thrd.proc->workingVersionNum >= PUBLICATION_DDL_AT_VERSION_NUM) { + WRITE_STRING_FIELD(initdefval); + } } static void _outTypeName(StringInfo str, TypeName* node) diff --git a/src/common/backend/nodes/readfuncs.cpp b/src/common/backend/nodes/readfuncs.cpp index f4973a3a3..bb52f82a6 100755 --- a/src/common/backend/nodes/readfuncs.cpp +++ b/src/common/backend/nodes/readfuncs.cpp @@ -5889,6 +5889,9 @@ static ColumnDef* _readColumnDef() IF_EXIST(update_default) { READ_NODE_FIELD(update_default); } + IF_EXIST(initdefval) { + READ_STRING_FIELD(initdefval); + } READ_DONE(); } diff --git a/src/common/backend/parser/gram.y b/src/common/backend/parser/gram.y index f31301087..d63e9923c 100644 --- a/src/common/backend/parser/gram.y +++ b/src/common/backend/parser/gram.y @@ -17457,6 +17457,7 @@ AlterProcedureStmt: ALTER PROCEDURE function_with_argtypes alterfunc_opt_list opt_restrict { AlterFunctionStmt *n = makeNode(AlterFunctionStmt); + n->isProcedure = true; n->func = $3; n->actions = $4; $$ = (Node *) n; diff --git a/src/common/backend/parser/parse_utilcmd.cpp b/src/common/backend/parser/parse_utilcmd.cpp index 060f0731c..773f66ec6 100644 --- a/src/common/backend/parser/parse_utilcmd.cpp +++ b/src/common/backend/parser/parse_utilcmd.cpp @@ -8569,6 +8569,7 @@ static void TransformModifyColumndef(CreateStmtContext* cxt, AlterTableCmd* cmd) rename->subname = cmd->name; rename->newname = def->colname; rename->missing_ok = false; + rename->is_modifycolumn = true; cxt->blist = lappend(cxt->blist, rename); } } diff --git a/src/common/backend/utils/adt/regproc.cpp b/src/common/backend/utils/adt/regproc.cpp index bf0d63699..ed86ec942 100644 --- a/src/common/backend/utils/adt/regproc.cpp +++ b/src/common/backend/utils/adt/regproc.cpp @@ -426,7 +426,7 @@ format_procedure_internal(Oid procedure_oid, bool force_qualify) * Would this proc be found (given the right args) by regprocedurein? * If not, we need to qualify it. */ - if (FunctionIsVisible(procedure_oid)) + if (FunctionIsVisible(procedure_oid) && !force_qualify) nspname = NULL; else nspname = get_namespace_name(procform->pronamespace); diff --git a/src/common/backend/utils/adt/ruleutils.cpp b/src/common/backend/utils/adt/ruleutils.cpp index 74732fedb..663c59c20 100644 --- a/src/common/backend/utils/adt/ruleutils.cpp +++ b/src/common/backend/utils/adt/ruleutils.cpp @@ -121,6 +121,11 @@ #define PRETTYFLAG_PAREN 1 #define PRETTYFLAG_INDENT 2 +/* Standard conversion of a "bool pretty" option to detailed flags */ +#define GET_PRETTY_FLAGS(pretty) \ + ((pretty) ? (PRETTYFLAG_PAREN | PRETTYFLAG_INDENT) \ + : PRETTYFLAG_INDENT) + /* Default line length for pretty-print wrapping */ #define WRAP_COLUMN_DEFAULT 79 @@ -244,10 +249,11 @@ static char* deparse_expression_pretty( bool no_alias = false); extern char* pg_get_viewdef_worker(Oid viewoid, int prettyFlags, int wrapColumn); extern char* pg_get_functiondef_worker(Oid funcid, int* headerlines); +extern char* pg_get_trigger_whenclause(Form_pg_trigger trigrec,Node* whenClause, bool pretty); static char* pg_get_triggerdef_worker(Oid trigid, bool pretty); static void decompile_column_index_array(Datum column_index_array, Oid relId, StringInfo buf); static char* pg_get_ruledef_worker(Oid ruleoid, int prettyFlags); -static char *pg_get_indexdef_worker(Oid indexrelid, int colno, const Oid *excludeOps, bool attrsOnly, bool showTblSpc, +static char* pg_get_indexdef_worker(Oid indexrelid, int colno, const Oid* excludeOps, bool attrsOnly, bool showTblSpc, int prettyFlags, bool dumpSchemaOnly = false, bool showPartitionLocal = true, bool showSubpartitionLocal = true); void pg_get_indexdef_partitions(Oid indexrelid, Form_pg_index idxrec, bool showTblSpc, StringInfoData *buf, bool dumpSchemaOnly, bool showPartitionLocal, bool showSubpartitionLocal); @@ -623,7 +629,27 @@ char* pg_get_viewdef_worker(Oid viewoid, int prettyFlags, int wrapColumn) char* pg_get_viewdef_string(Oid viewid) { - return pg_get_viewdef_worker(viewid, 0, -1); + StringInfoData buf; + Relation pg_rewrite; + HeapTuple ruletup; + TupleDesc rulettc; + + initStringInfo(&buf); + pg_rewrite = relation_open(RewriteRelationId, AccessShareLock); + + ruletup = SearchSysCache2(RULERELNAME, + ObjectIdGetDatum(viewid), + PointerGetDatum(ViewSelectRuleName)); + if (!HeapTupleIsValid(ruletup)) { + elog(ERROR, "cache lookup failed for rewrite rule for view with OID %u", viewid); + } + + rulettc = pg_rewrite->rd_att; + make_viewdef(&buf, ruletup, rulettc, 0, WRAP_COLUMN_DEFAULT); + ReleaseSysCache(ruletup); + relation_close(pg_rewrite, AccessShareLock); + + return buf.data; } /* @@ -3318,6 +3344,76 @@ static char* pg_get_triggerdef_worker(Oid trigid, bool pretty) return buf.data; } +/* + * Pass back the TriggerWhen clause of a trigger given the pg_trigger record and + * the expression tree (in nodeToString() representation) from pg_trigger.tgqual + * for the trigger's WHEN condition. + */ +char* pg_get_trigger_whenclause(Form_pg_trigger trigrec, Node* whenClause, bool pretty) +{ + StringInfoData buf; + char relkind; + deparse_context context; + deparse_namespace dpns; + RangeTblEntry *oldrte; + RangeTblEntry *newrte; + + initStringInfo(&buf); + + relkind = get_rel_relkind(trigrec->tgrelid); + + /* Build minimal OLD and NEW RTEs for the rel */ + oldrte = makeNode(RangeTblEntry); + oldrte->rtekind = RTE_RELATION; + oldrte->relid = trigrec->tgrelid; + oldrte->relkind = relkind; + oldrte->alias = makeAlias("old", NIL); + oldrte->eref = oldrte->alias; + oldrte->lateral = false; + oldrte->inh = false; + oldrte->inFromCl = true; + + newrte = makeNode(RangeTblEntry); + newrte->rtekind = RTE_RELATION; + newrte->relid = trigrec->tgrelid; + newrte->relkind = relkind; + newrte->alias = makeAlias("new", NIL); + newrte->eref = newrte->alias; + newrte->lateral = false; + newrte->inh = false; + newrte->inFromCl = true; + + /* Build two-element rtable */ + errno_t rc = memset_s(&dpns, sizeof(dpns), 0, sizeof(dpns)); + securec_check(rc, "\0", "\0"); + dpns.rtable = list_make2(oldrte, newrte); + dpns.ctes = NIL; + + + /* Set up context with one-deep namespace stack */ + context.buf = &buf; + context.namespaces = list_make1(&dpns); + context.windowClause = NIL; + context.windowTList = NIL; + context.varprefix = true; + context.prettyFlags = GET_PRETTY_FLAGS(pretty); +#ifdef PGXC + context.finalise_aggs = false; + context.sortgroup_colno = false; + context.parser_arg = NULL; +#endif /* PGXC */ + context.viewdef = false; + context.is_fqs = false; + context.wrapColumn = WRAP_COLUMN_DEFAULT; + context.indentLevel = PRETTYINDENT_STD; + context.qrw_phase = false; + context.is_upsert_clause = false; + + get_rule_expr(whenClause, &context, false); + + return buf.data; +} + /* ---------- * get_indexdef - Get the definition of an index * @@ -4560,6 +4656,17 @@ Datum pg_get_functiondef(PG_FUNCTION_ARGS) PG_RETURN_DATUM(HeapTupleGetDatum(tuple)); } + +char* pg_get_functiondef_string(Oid funcid) +{ + char* funcdef = NULL; + int headerlines = 0; + + funcdef = pg_get_functiondef_worker(funcid, &headerlines); + + return funcdef; +} + /* * pg_get_function_arguments * Get a nicely-formatted list of arguments for a function. diff --git a/src/common/backend/utils/cache/relcache.cpp b/src/common/backend/utils/cache/relcache.cpp index f40a3db4f..0909332a2 100755 --- a/src/common/backend/utils/cache/relcache.cpp +++ b/src/common/backend/utils/cache/relcache.cpp @@ -2312,6 +2312,7 @@ static Relation RelationBuildDescExtended(Oid targetRelId, bool insertIt, bool b } else { relation->relreplident = CharGetDatum(datum); } + /* * initialize the relation's relation id (relation->rd_id) */ @@ -5428,6 +5429,8 @@ void RelationCacheInvalidOid(Relation relation) HeapTuple htup; Form_pg_class relp; int natts = 0; + Datum datum; + bool isnull = false; htup = SearchSysCache1(RELOID, ObjectIdGetDatum(RelationGetRelid(relation))); if (!HeapTupleIsValid(htup)) @@ -7283,6 +7286,10 @@ struct PublicationActions* GetRelationPublicationActions(Relation relation) pubactions->pubinsert |= pubform->pubinsert; pubactions->pubupdate |= pubform->pubupdate; pubactions->pubdelete |= pubform->pubdelete; + pubactions->pubtruncate |= pubform->pubtruncate; + + if (pubactions->pubddl != PUBDDL_ALL) + pubactions->pubddl |= pubform->pubddl; ReleaseSysCache(tup); @@ -7290,7 +7297,9 @@ struct PublicationActions* GetRelationPublicationActions(Relation relation) * If we know everything is replicated, there is no point to check * for other publications. */ - if (pubactions->pubinsert && pubactions->pubupdate && pubactions->pubdelete) + if (pubactions->pubinsert && pubactions->pubupdate && + pubactions->pubdelete && pubactions->pubtruncate && + pubactions->pubddl == PUBDDL_ALL) break; } @@ -8763,6 +8772,7 @@ Relation tuple_get_rel(HeapTuple pg_class_tuple, LOCKMODE lockmode, TupleDesc tu } else { relation->relreplident = CharGetDatum(datum); } + /* * If it's an index, initialize index-related information. * We modify RelationInitIndexAccessInfo interface to input index tuple which cached by ourself. diff --git a/src/common/backend/utils/init/globals.cpp b/src/common/backend/utils/init/globals.cpp index 42231d92f..71b73d9e4 100644 --- a/src/common/backend/utils/init/globals.cpp +++ b/src/common/backend/utils/init/globals.cpp @@ -76,12 +76,13 @@ bool will_shutdown = false; * ********************************************/ -const uint32 GRAND_VERSION_NUM = 92947; +const uint32 GRAND_VERSION_NUM = 92949; /******************************************** * 2.VERSION NUM FOR EACH FEATURE * Please write indescending order. ********************************************/ +const uint32 PUBLICATION_DDL_AT_VERSION_NUM = 92949; const uint32 MINMAXEXPR_CMPTYPE_VERSION_NUM = 92948; const uint32 PARTITION_NAME_VERSION_NUM = 92947; const uint32 AUDIT_SHA_VERSION_NUM = 92946; diff --git a/src/gausskernel/optimizer/commands/cluster.cpp b/src/gausskernel/optimizer/commands/cluster.cpp index ecac42c7c..94f7d41e2 100755 --- a/src/gausskernel/optimizer/commands/cluster.cpp +++ b/src/gausskernel/optimizer/commands/cluster.cpp @@ -1474,7 +1474,11 @@ Oid make_new_heap(Oid OIDOldHeap, Oid NewTableSpace, int lockMode) RELATION_CREATE_BUCKET(OldHeap) ? &bucketinfo : NULL, true, NULL, - RelationGetStorageType(OldHeap)); + RelationGetStorageType(OldHeap), + AccessExclusiveLock, + NULL, + NIL, + OIDOldHeap); Assert(OIDNewHeap != InvalidOid); ReleaseSysCache(tuple); @@ -3545,6 +3549,14 @@ void finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap, bool is_system_catalog, bo rc = snprintf_s(NewToastName, NAMEDATALEN, NAMEDATALEN - 1, "pg_toast_%u_index", OIDOldHeap); securec_check_ss(rc, "\0", "\0"); RenameRelationInternal(toastidx, NewToastName); + + /* + * Reset the relrewrite for the toast. The command-counter + * increment is required here as we are about to update the tuple + * that is updated as part of RenameRelationInternal. + */ + CommandCounterIncrement(); + ResetRelRewrite(newrel->rd_rel->reltoastrelid); } relation_close(newrel, NoLock); } diff --git a/src/gausskernel/optimizer/commands/ddldeparse.cpp b/src/gausskernel/optimizer/commands/ddldeparse.cpp index 6ad8717d7..548f7f6f9 100644 --- a/src/gausskernel/optimizer/commands/ddldeparse.cpp +++ b/src/gausskernel/optimizer/commands/ddldeparse.cpp @@ -58,6 +58,7 @@ #include "catalog/pg_range.h" #include "catalog/pg_rewrite.h" #include "catalog/pg_statistic_ext.h" +#include "catalog/pg_trigger.h" #include "catalog/pg_ts_config.h" #include "catalog/pg_ts_dict.h" #include "catalog/pg_ts_parser.h" @@ -79,61 +80,72 @@ #include "tcop/utility.h" #include "utils/builtins.h" #include "utils/fmgroids.h" +#include "utils/guc_tables.h" #include "utils/guc.h" #include "utils/jsonb.h" #include "utils/lsyscache.h" #include "utils/rel.h" +#include "utils/partitionkey.h" #include "utils/syscache.h" +#include "optimizer/clauses.h" /* Estimated length of the generated jsonb string */ static const int JSONB_ESTIMATED_LEN = 128; -/* - * Before they are turned into JSONB representation, each command is - * represented as an object tree, using the structs below. - */ -typedef enum -{ - ObjTypeNull, - ObjTypeBool, - ObjTypeString, - ObjTypeArray, - ObjTypeInteger, - ObjTypeFloat, - ObjTypeObject -} ObjType; +/* copy from ruleutils.cpp */ +#define BEGIN_P_STR " BEGIN_B_PROC " /* used in dolphin type proc body */ +#define BEGIN_P_LEN 14 +#define BEGIN_N_STR " BEGIN " /* BEGIN_P_STR to same length */ /* - * Represent the command as an object tree. + * Mark the max_volatility flag for an expression in the command. */ -typedef struct ObjTree +static void mark_function_volatile(ddl_deparse_context* context, Node* expr) { - slist_head params; /* Object tree parameters */ - int numParams; /* Number of parameters in the object tree */ - StringInfo fmtinfo; /* Format string of the ObjTree */ - bool present; /* Indicates if boolean value should be stored */ -} ObjTree; + if (context->max_volatility == PROVOLATILE_VOLATILE) { + return; + } -/* - * An element of an object tree (ObjTree). - */ -typedef struct ObjElem + if (contain_volatile_functions(expr)) { + context->max_volatility = PROVOLATILE_VOLATILE; + return; + } + + if (context->max_volatility == PROVOLATILE_IMMUTABLE && + contain_mutable_functions(expr)) { + context->max_volatility = PROVOLATILE_STABLE; + } +} + +static void check_alter_table_rewrite_replident_change(Relation r, int attno, const char *cmd) { - char *name; /* Name of object element */ - ObjType objtype; /* Object type */ + Oid replidindex = RelationGetReplicaIndex(r); + if (!OidIsValid(replidindex)) { + ereport(ERROR, + (errmsg("cannot use %s command without replident index because it cannot be replicated in DDL replication", + cmd))); + } - union { - bool boolean; - char *string; - int64 integer; - float8 flt; - ObjTree *object; - List *array; - } value; /* Store the object value based on the object - * type */ - slist_node node; /* Used in converting back to ObjElem - * structure */ -} ObjElem; + if (IsRelationReplidentKey(r, attno)) { + ereport(ERROR, + (errmsg("cannot use %s command to replica index attr because it cannot be replicated in DDL replication", + cmd))); + } +} + +static void check_alter_table_replident(Relation rel) +{ + if (rel->relreplident != REPLICA_IDENTITY_FULL && + !OidIsValid(RelationGetReplicaIndex(rel))) { + elog(ERROR, "this ALTER TABLE command will cause a table rewritting, " + "but the table does not have a replica identity, it cannot be replicated in DDL replication"); + } +} + +void table_close(Relation relation, LOCKMODE lockmode) +{ + relation_close(relation, lockmode); +} /* * Reduce some unnecessary strings from the output json when verbose @@ -141,25 +153,22 @@ typedef struct ObjElem * the last DDL command. */ -static void append_format_string(ObjTree *tree, char *sub_fmt); -static void append_array_object(ObjTree *tree, char *sub_fmt, List *array); -static void append_object_object(ObjTree *tree, char *sub_fmt, ObjTree *value); -static char *append_object_to_format_string(ObjTree *tree, const char *sub_fmt); +static char* append_object_to_format_string(ObjTree *tree, const char *sub_fmt); static void append_premade_object(ObjTree *tree, ObjElem *elem); -static void append_string_object(ObjTree *tree, char *sub_fmt, char *name, - const char *value); static void append_int_object(ObjTree *tree, char *sub_fmt, int32 value); +static void append_float_object(ObjTree *tree, char *sub_fmt, float8 value); static void format_type_detailed(Oid type_oid, int32 typemod, Oid *nspid, char **typname, char **typemodstr, bool *typarray); -static ObjElem *new_object(ObjType type, char *name); -static ObjTree *new_objtree_for_qualname_id(Oid classId, Oid objectId); -static ObjTree *new_objtree(const char *fmt); -static ObjElem *new_object_object(ObjTree *value); +static ObjElem* new_object(ObjType type, char *name); +static ObjTree* new_objtree_for_qualname_id(Oid classId, Oid objectId); +static ObjTree* new_objtree(const char *fmt); +static ObjElem* new_object_object(ObjTree *value); -static ObjTree *new_objtree_VA(const char *fmt, int numobjs,...); +ObjTree* new_objtree_VA(const char *fmt, int numobjs, ...); +ObjElem* new_string_object(char *value); -static JsonbValue *objtree_to_jsonb_rec(ObjTree *tree, JsonbParseState *state, char *owner); +static JsonbValue* objtree_to_jsonb_rec(ObjTree *tree, JsonbParseState *state, char *owner); static void pg_get_indexdef_detailed(Oid indexrelid, bool global, char **index_am, char **definition, @@ -167,32 +176,76 @@ static void pg_get_indexdef_detailed(Oid indexrelid, bool global, char **tablespace, char **whereClause, bool *invisible); -static char *RelationGetColumnDefault(Relation rel, AttrNumber attno, +static char* RelationGetColumnDefault(Relation rel, AttrNumber attno, List *dpcontext, List **exprs); -static ObjTree *deparse_ColumnDef(Relation relation, List *dpcontext, - ColumnDef *coldef, List **exprs); +static ObjTree* deparse_ColumnDef(Relation relation, List *dpcontext, bool composite, + ColumnDef *coldef, bool is_alter, List **exprs); +static ObjTree* deparse_ColumnSetOptions(AlterTableCmd *subcmd); -static ObjTree *deparse_DefElem(DefElem *elem, bool is_reset); +static ObjTree* deparse_DefElem(DefElem *elem, bool is_reset); +static ObjTree* deparse_OnCommitClause(OnCommitAction option); +static ObjTree* deparse_add_subpartition(ObjTree* ret, Oid partoid, + List *subPartitionDefState, int parkeynum, Oid* partkey_types); +static List* deparse_partition_boudaries(Oid parentoid, char reltype, char strategy, const char* partition_name, + Oid* partoid, int parkeynum, Oid* partkey_types); +static int get_partition_key_types(Oid reloid, char parttype, Oid **partkey_types); +static List* get_range_partition_maxvalues(List *boundary); +static List* get_list_partition_maxvalues(List *boundary); +static ObjTree* deparse_RelSetOptions(AlterTableCmd *subcmd); -static inline ObjElem *deparse_Seq_Cache(sequence_values *seqdata, bool alter_table); -static inline ObjElem *deparse_Seq_Cycle(sequence_values * seqdata, bool alter_table); -static inline ObjElem *deparse_Seq_IncrementBy(sequence_values * seqdata, bool alter_table); -static inline ObjElem *deparse_Seq_Minvalue(sequence_values * seqdata, bool alter_table); -static inline ObjElem *deparse_Seq_Maxvalue(sequence_values * seqdata, bool alter_table); -static inline ObjElem *deparse_Seq_Restart(char *last_value); -static inline ObjElem *deparse_Seq_Startwith(sequence_values * seqdata, bool alter_table); -static ObjElem *deparse_Seq_OwnedBy(Oid sequenceId); -static inline ObjElem *deparse_Seq_Order(DefElem *elem); -static inline ObjElem *deparse_Seq_As(DefElem *elem); +static inline ObjElem* deparse_Seq_Cache(sequence_values *seqdata, bool alter_table); +static inline ObjElem* deparse_Seq_Cycle(sequence_values *seqdata, bool alter_table); +static inline ObjElem* deparse_Seq_IncrementBy(sequence_values *seqdata, bool alter_table); +static inline ObjElem* deparse_Seq_Minvalue(sequence_values *seqdata, bool alter_table); +static inline ObjElem* deparse_Seq_Maxvalue(sequence_values *seqdata, bool alter_table); +static inline ObjElem* deparse_Seq_Restart(char *last_value); +static inline ObjElem* deparse_Seq_Startwith(sequence_values *seqdata, bool alter_table); +static ObjElem* deparse_Seq_OwnedBy(Oid sequenceId); +static inline ObjElem* deparse_Seq_Order(DefElem *elem); +static inline ObjElem* deparse_Seq_As(DefElem *elem); +static ObjTree* deparse_CreateFunction(Oid objectId, Node *parsetree); +static ObjTree* deparse_FunctionSet(VariableSetKind kind, char *name, char *value); +static ObjTree* deparse_CreateTrigStmt(Oid objectId, Node *parsetree); +static ObjTree* deparse_AlterTrigStmt(Oid objectId, Node *parsetree); +static ObjTree* deparse_AlterFunction(Oid objectId, Node *parsetree); -static List *deparse_TableElements(Relation relation, List *tableElements, List *dpcontext); +static List* deparse_TableElements(Relation relation, List *tableElements, List *dpcontext, bool composite); +extern char* pg_get_trigger_whenclause(Form_pg_trigger trigrec, Node* whenClause, bool pretty); +extern char* pg_get_functiondef_string(Oid funcid); + +/* + * Append a boolean parameter to a tree. + */ +static void append_bool_object(ObjTree *tree, char *sub_fmt, bool value) +{ + ObjElem *param; + char *object_name = sub_fmt; + bool is_present_flag = false; + + Assert(sub_fmt); + + /* + * Check if the format string is 'present' and if yes, store the boolean + * value + */ + if (strcmp(sub_fmt, "present") == 0) { + is_present_flag = true; + tree->present = value; + } + + if (!is_present_flag) + object_name = append_object_to_format_string(tree, sub_fmt); + + param = new_object(ObjTypeBool, object_name); + param->value.boolean = value; + append_premade_object(tree, param); +} /* * Append an int32 parameter to a tree. */ -static void -append_int_object(ObjTree *tree, char *sub_fmt, int32 value) +static void append_int_object(ObjTree *tree, char *sub_fmt, int32 value) { ObjElem *param; char *object_name; @@ -206,29 +259,47 @@ append_int_object(ObjTree *tree, char *sub_fmt, int32 value) append_premade_object(tree, param); } +/* + * Append a float8 parameter to a tree. + */ +static void append_float_object(ObjTree *tree, char *sub_fmt, float8 value) +{ + ObjElem *param; + char *object_name; + + Assert(sub_fmt); + + object_name = append_object_to_format_string(tree, sub_fmt); + + param = new_object(ObjTypeFloat, object_name); + param->value.flt = value; + append_premade_object(tree, param); +} + /* * Append a NULL-or-quoted-literal clause. Userful for COMMENT and SECURITY * LABEL. - * + * * Verbose syntax * %{null}s %{literal}s */ -static void -append_literal_or_null(ObjTree *parent, char *elemname, char *value) +static void append_literal_or_null(ObjTree *parent, char *elemname, char *value) { ObjTree *top; ObjTree *part; top = new_objtree(""); part = new_objtree_VA("NULL", 1, - "present", ObjTypeBool, !value); + "present", ObjTypeBool, !value); append_object_object(top, "%{null}s", part); part = new_objtree_VA("", 1, - "present", ObjTypeBool, value != NULL); + "present", ObjTypeBool, value != NULL); - if (value) + if (value) { append_string_object(part, "%{value}L", "value", value); + } + append_object_object(top, "%{literal}s", part); append_object_object(parent, elemname, top); @@ -237,16 +308,16 @@ append_literal_or_null(ObjTree *parent, char *elemname, char *value) /* * Append an array parameter to a tree. */ -static void -append_array_object(ObjTree *tree, char *sub_fmt, List *array) +void append_array_object(ObjTree *tree, char *sub_fmt, List *array) { ObjElem *param; char *object_name; Assert(sub_fmt); - if (!array || list_length(array) == 0) + if (!array || list_length(array) == 0) { return; + } ListCell *lc; @@ -270,30 +341,49 @@ append_array_object(ObjTree *tree, char *sub_fmt, List *array) /* * Append the input format string to the ObjTree. */ -static void -append_format_string(ObjTree *tree, char *sub_fmt) +void append_format_string(ObjTree *tree, char *sub_fmt) { int len; char *fmt; - if (tree->fmtinfo == NULL) + if (tree->fmtinfo == NULL) { return; + } fmt = tree->fmtinfo->data; len = tree->fmtinfo->len; /* Add a separator if necessary */ - if (len > 0 && fmt[len - 1] != ' ') + if (len > 0 && fmt[len - 1] != ' ') { appendStringInfoSpaces(tree->fmtinfo, 1); - + } appendStringInfoString(tree->fmtinfo, sub_fmt); } +/* + * Append present as false to a tree. + * If sub_fmt is passed and verbose mode is ON, + * append sub_fmt as well to tree. + * + * Example: + * in non-verbose mode, element will be like: + * "collation": {"fmt": "COLLATE", "present": false} + * in verbose mode: + * "collation": {"fmt": "COLLATE %{name}D", "present": false} + */ +static void append_not_present(ObjTree *tree, char *sub_fmt) +{ + if (sub_fmt) { + append_format_string(tree, sub_fmt); + } + + append_bool_object(tree, "present", false); +} + /* * Append an object parameter to a tree. */ -static void -append_object_object(ObjTree *tree, char *sub_fmt, ObjTree *value) +void append_object_object(ObjTree *tree, char *sub_fmt, ObjTree *value) { ObjElem *param; char *object_name; @@ -314,8 +404,7 @@ append_object_object(ObjTree *tree, char *sub_fmt, ObjTree *value) * Return the object name which is extracted from the input "*%{name[:.]}*" * style string. And append the input format string to the ObjTree. */ -static char * -append_object_to_format_string(ObjTree *tree, const char *sub_fmt) +static char* append_object_to_format_string(ObjTree *tree, const char *sub_fmt) { StringInfoData object_name; const char *end_ptr, *start_ptr; @@ -354,8 +443,7 @@ append_object_to_format_string(ObjTree *tree, const char *sub_fmt) /* * Append a preallocated parameter to a tree. */ -static inline void -append_premade_object(ObjTree *tree, ObjElem *elem) +static inline void append_premade_object(ObjTree *tree, ObjElem *elem) { slist_push_head(&tree->params, &elem->node); tree->numParams++; @@ -364,9 +452,8 @@ append_premade_object(ObjTree *tree, ObjElem *elem) /* * Append a string parameter to a tree. */ -static void -append_string_object(ObjTree *tree, char *sub_fmt, char *name, - const char *value) +void append_string_object(ObjTree *tree, char *sub_fmt, char *name, + const char *value) { ObjElem *param; @@ -398,10 +485,9 @@ append_string_object(ObjTree *tree, char *sub_fmt, char *name, * We don't try to decode type names to their standard-mandated names, except * in the cases of types with unusual typmod rules. */ -static void -format_type_detailed(Oid type_oid, int32 typemod, - Oid *nspid, char **typname, char **typemodstr, - bool *typearray) +static void format_type_detailed(Oid type_oid, int32 typemod, + Oid *nspid, char **typname, char **typemodstr, + bool *typearray) { HeapTuple tuple; Form_pg_type typeform; @@ -484,8 +570,7 @@ format_type_detailed(Oid type_oid, int32 typemod, /* * Return the string representation of the given RELPERSISTENCE value. */ -static inline char * -get_persistence_str(char persistence) +static inline char* get_persistence_str(char persistence) { switch (persistence) { case RELPERSISTENCE_TEMP: @@ -505,8 +590,7 @@ get_persistence_str(char persistence) /* * Return the string representation of the given storagetype value. */ -static inline char * -get_type_storage(char storagetype) +static inline char* get_type_storage(char storagetype) { switch (storagetype) { case 'p': @@ -525,8 +609,7 @@ get_type_storage(char storagetype) /* * Allocate a new parameter. */ -static ObjElem * -new_object(ObjType type, char *name) +static ObjElem* new_object(ObjType type, char *name) { ObjElem *param; @@ -540,8 +623,7 @@ new_object(ObjType type, char *name) /* * Allocate a new object parameter. */ -static ObjElem * -new_object_object(ObjTree *value) +static ObjElem* new_object_object(ObjTree *value) { ObjElem *param; @@ -554,8 +636,7 @@ new_object_object(ObjTree *value) /* * Allocate a new object tree to store parameter values. */ -static ObjTree * -new_objtree(const char *fmt) +static ObjTree* new_objtree(const char *fmt) { ObjTree *params; @@ -581,8 +662,7 @@ new_objtree(const char *fmt) * be quoted as an identifier or not, which is not something that this routine * concerns itself with; that will be up to the expand function. */ -static ObjTree * -new_objtree_for_qualname(Oid nspid, char *name) +static ObjTree* new_objtree_for_qualname(Oid nspid, char *name) { ObjTree *qualified; char *namespc; @@ -603,8 +683,7 @@ new_objtree_for_qualname(Oid nspid, char *name) * A helper routine to set up %{}D and %{}O elements, with the object specified * by classId/objId. */ -static ObjTree * -new_objtree_for_qualname_id(Oid classId, Oid objectId) +static ObjTree* new_objtree_for_qualname_id(Oid classId, Oid objectId) { ObjTree *qualified; Relation catalog; @@ -625,12 +704,12 @@ new_objtree_for_qualname_id(Oid classId, Oid objectId) Anum_namespace = get_object_attnum_namespace(classId); obj_nsp = heap_getattr(catobj, Anum_namespace, RelationGetDescr(catalog), - &isnull); + &isnull); if (isnull) elog(ERROR, "null namespace for object %u", objectId); obj_name = heap_getattr(catobj, Anum_name, RelationGetDescr(catalog), - &isnull); + &isnull); if (isnull) elog(ERROR, "null attribute name for object %u", objectId); @@ -641,11 +720,25 @@ new_objtree_for_qualname_id(Oid classId, Oid objectId) return qualified; } +static ObjTree* new_objtree_for_qualname_rangevar(RangeVar* rv) +{ + ObjTree *qualified = NULL; + if (rv->schemaname) { + qualified = new_objtree_VA(NULL, 2, + "schemaname", ObjTypeString, rv->schemaname, + "objname", ObjTypeString, pstrdup(rv->relname)); + } else { + /* serachpath has no schema set in deparse_utility_command */ + Oid reloid = RangeVarGetRelid(rv, AccessExclusiveLock, false); + qualified = new_objtree_for_qualname_id(RelationRelationId, reloid); + } + return qualified; +} + /* * A helper routine to setup %{}T elements. */ -static ObjTree * -new_objtree_for_type(Oid typeId, int32 typmod) +static ObjTree* new_objtree_for_type(Oid typeId, int32 typmod) { Oid typnspid; char *type_nsp; @@ -683,8 +776,7 @@ new_objtree_for_type(Oid typeId, int32 typmod) * Note we don't have the luxury of sprintf-like compiler warnings for * malformed argument lists. */ -static ObjTree * -new_objtree_VA(const char *fmt, int numobjs,...) +ObjTree* new_objtree_VA(const char *fmt, int numobjs, ...) { ObjTree *tree; va_list args; @@ -743,30 +835,125 @@ new_objtree_VA(const char *fmt, int numobjs,...) return tree; } +/* + * Allocate a new string object. + */ +ObjElem* new_string_object(char *value) +{ + ObjElem *param; + + Assert(value); + + param = new_object(ObjTypeString, NULL); + param->value.string = value; + + return param; +} + +static ObjTree* deparse_AlterSchemaStmt(Oid objectId, Node *parsetree) +{ + ObjTree *ret; + AlterSchemaStmt *stmt = (AlterSchemaStmt *) parsetree; + + bool setblockchain = false; + + if (stmt->charset == PG_INVALID_ENCODING && !stmt->collate) { + setblockchain = true; + } + + ret = new_objtree_VA("ALTER SCHEMA %{schemaname}I", 1, + "schemaname", ObjTypeString, stmt->schemaname); + + if (setblockchain) { + append_string_object(ret, "%{with}s BLOCKCHAIN", "with", stmt->hasBlockChain ? + "WITH" : "WITHOUT"); + } else { + if (stmt->charset != PG_INVALID_ENCODING) { + append_string_object(ret, "CHARACTER SET = %{charset}s", "charset", + pg_encoding_to_char(stmt->charset)); + } + + if (stmt->collate) { + append_string_object(ret, "COLLATE = %{collate}s", "collate", stmt->collate); + } + } + + return ret; +} + + +/* + * Deparse a CreateSchemaStmt. + * + * Given a schema OID and the parse tree that created it, return an ObjTree + * representing the creation command. + * + * Verbose syntax + * CREATE SCHEMA %{if_not_exists}s %{name}I %{authorization}s +*/ +static ObjTree* deparse_CreateSchemaStmt(Oid objectId, Node *parsetree) +{ + CreateSchemaStmt *node = (CreateSchemaStmt *) parsetree; + ObjTree *ret; + ObjTree *auth; + ObjTree *blockchain; + ret = new_objtree_VA("CREATE SCHEMA %{if_not_exists}s %{name}I", 2, + "if_not_exists", ObjTypeString, + node->missing_ok ? "IF NOT EXISTS" : "", + "name", ObjTypeString, + node->schemaname ? node->schemaname : ""); + + auth = new_objtree("AUTHORIZATION"); + if (node->authid) + append_string_object(auth, "%{authorization_role}I", + "authorization_role", + node->authid); + else + append_not_present(auth, "%{authorization_role}I"); + + append_object_object(ret, "%{authorization}s", auth); + + blockchain = new_objtree("WITH BLOCKCHAIN"); + if (!node->hasBlockChain) + append_not_present(blockchain, "%{blockchain}s"); + append_object_object(ret, "%{blockchain}s", blockchain); + + return ret; +} + /* * Return the given object type as a string. * * If isgrant is true, then this function is called while deparsing GRANT * statement and some object names are replaced. */ -static const char * -string_objtype(ObjectType objtype, bool isgrant) +static const char* string_objtype(ObjectType objtype, bool isgrant) { switch (objtype) { case OBJECT_COLUMN: return isgrant ? "TABLE" : "COLUMN"; case OBJECT_DOMAIN: return "DOMAIN"; + case OBJECT_FUNCTION: + return "FUNCTION"; case OBJECT_INDEX: return "INDEX"; + case OBJECT_SCHEMA: + return "SCHEMA"; case OBJECT_SEQUENCE: return "SEQUENCE"; case OBJECT_LARGE_SEQUENCE: return "LARGE SEQUENCE"; case OBJECT_TABLE: return "TABLE"; + case OBJECT_TABLESPACE: + return "TABLESPACE"; + case OBJECT_TRIGGER: + return "TRIGGER"; case OBJECT_TYPE: return "TYPE"; + case OBJECT_VIEW: + return "VIEW"; default: elog(WARNING, "unsupported object type %d for string", objtype); } @@ -778,8 +965,7 @@ string_objtype(ObjectType objtype, bool isgrant) * Process the pre-built format string from the ObjTree into the output parse * state. */ -static void -objtree_fmt_to_jsonb_element(JsonbParseState *state, ObjTree *tree) +static void objtree_fmt_to_jsonb_element(JsonbParseState *state, ObjTree *tree) { JsonbValue key; JsonbValue val; @@ -805,8 +991,7 @@ objtree_fmt_to_jsonb_element(JsonbParseState *state, ObjTree *tree) /* * Process the role string into the output parse state. */ -static void -role_to_jsonb_element(JsonbParseState *state, char *owner) +static void role_to_jsonb_element(JsonbParseState *state, char *owner) { JsonbValue key; JsonbValue val; @@ -832,8 +1017,7 @@ role_to_jsonb_element(JsonbParseState *state, char *owner) /* * Create a JSONB representation from an ObjTree and its owner (if given). */ -static Jsonb * -objtree_to_jsonb(ObjTree *tree, char *owner) +static Jsonb* objtree_to_jsonb(ObjTree *tree, char *owner) { JsonbValue *value; @@ -845,9 +1029,8 @@ objtree_to_jsonb(ObjTree *tree, char *owner) * Helper for objtree_to_jsonb: process an individual element from an object or * an array into the output parse state. */ -static void -objtree_to_jsonb_element(JsonbParseState *state, ObjElem *object, - int elem_token) +static void objtree_to_jsonb_element(JsonbParseState *state, ObjElem *object, + int elem_token) { JsonbValue val; @@ -926,8 +1109,7 @@ objtree_to_jsonb_element(JsonbParseState *state, ObjElem *object, /* * Recursive helper for objtree_to_jsonb. */ -static JsonbValue * -objtree_to_jsonb_rec(ObjTree *tree, JsonbParseState *state, char *owner) +static JsonbValue* objtree_to_jsonb_rec(ObjTree *tree, JsonbParseState *state, char *owner) { slist_iter iter; @@ -964,8 +1146,7 @@ objtree_to_jsonb_rec(ObjTree *tree, JsonbParseState *state, char *owner) * * Note that CONSTRAINT_FOREIGN constraints are always ignored. */ -static List * -obtainConstraints(List *elements, Oid relationId) +static List* obtainConstraints(List *elements, Oid relationId) { Relation conRel; ScanKeyData skey[1]; @@ -981,8 +1162,8 @@ obtainConstraints(List *elements, Oid relationId) * relation. */ conRel = relation_open(ConstraintRelationId, AccessShareLock); - ScanKeyInit(&skey[0], Anum_pg_constraint_conrelid, BTEqualStrategyNumber, - F_OIDEQ, ObjectIdGetDatum(relationId)); + ScanKeyInit(&skey[0], Anum_pg_constraint_conrelid, BTEqualStrategyNumber, + F_OIDEQ, ObjectIdGetDatum(relationId)); scan = systable_beginscan(conRel, ConstraintRelidIndexId, true, NULL, 1, skey); /* @@ -1067,14 +1248,13 @@ obtainConstraints(List *elements, Oid relationId) * control flow is different enough that it doesn't seem worth keeping them * together. */ -static void -pg_get_indexdef_detailed(Oid indexrelid, bool global, - char **index_am, - char **definition, - char **reloptions, - char **tablespace, - char **whereClause, - bool *invisible) +static void pg_get_indexdef_detailed(Oid indexrelid, bool global, + char **index_am, + char **definition, + char **reloptions, + char **tablespace, + char **whereClause, + bool *invisible) { HeapTuple ht_idx; HeapTuple ht_idxrel; @@ -1221,6 +1401,8 @@ pg_get_indexdef_detailed(Oid indexrelid, bool global, if (indexkey && IsA(indexkey, FuncExpr) && ((FuncExpr *) indexkey)->funcformat == COERCE_EXPLICIT_CALL) { appendStringInfoString(&definitionBuf, str); + } else if (indexkey && IsA(indexkey, PrefixKey)) { + appendStringInfoString(&definitionBuf, str); } else { appendStringInfo(&definitionBuf, "(%s)", str); } @@ -1234,7 +1416,7 @@ pg_get_indexdef_detailed(Oid indexrelid, bool global, Oid indcoll = indcollation->values[keyno]; if (OidIsValid(indcoll)) appendStringInfo(&definitionBuf, " COLLATE %s", - generate_collation_name((indcoll))); + generate_collation_name((indcoll))); /* Add the operator class name, even if default */ get_opclass_name(indclass->values[keyno], InvalidOid, &definitionBuf); @@ -1316,9 +1498,8 @@ pg_get_indexdef_detailed(Oid indexrelid, bool global, * * Caller must have set a correct deparse context. */ -static char * -RelationGetColumnDefault(Relation rel, AttrNumber attno, List *dpcontext, - List **exprs) +static char* RelationGetColumnDefault(Relation rel, AttrNumber attno, List *dpcontext, + List **exprs) { Node *defval; char *defstr; @@ -1390,6 +1571,90 @@ static char *RelationGetColumnOnUpdate(Node *update_expr, List *dpcontext, List return buf.data; } +/* used by AT_ModifyColumn */ +static ObjTree* deparse_ColumnDef_constraints(ObjTree *ret, Relation relation, + ColumnDef *coldef, List *dpcontext, List **exprs) +{ + ObjTree *tmp_obj; + Oid relid = RelationGetRelid(relation); + ListCell *cell; + HeapTuple attrTup; + Form_pg_attribute attrForm; + + bool saw_notnull = false; + bool saw_autoincrement = false; + char* onupdate = NULL; + attrTup = SearchSysCacheAttName(relid, coldef->colname); + if (!HeapTupleIsValid(attrTup)) + elog(ERROR, "could not find cache entry for column \"%s\" of relation %u", + coldef->colname, relid); + attrForm = (Form_pg_attribute) GETSTRUCT(attrTup); + + foreach(cell, coldef->constraints) { + Constraint *constr = (Constraint *) lfirst(cell); + + if (constr->contype == CONSTR_NOTNULL) { + saw_notnull = true; + } else if (constr->contype == CONSTR_AUTO_INCREMENT) { + saw_autoincrement = true; + check_alter_table_rewrite_replident_change(relation, attrForm->attnum, "MODIFY COLUMN AUTO_INCREMENT"); + } else if (constr->contype == CONSTR_DEFAULT && constr->update_expr) { + onupdate = RelationGetColumnOnUpdate(constr->update_expr, dpcontext, exprs); + } + } + + if (coldef->is_not_null) + saw_notnull = true; + + if (saw_autoincrement) { + ReleaseSysCache(attrTup); + return ret; + } + + append_string_object(ret, "%{auto_increment}s", "auto_increment", + saw_autoincrement ? "AUTO_INCREMENT" : ""); + + /* ON UPDATE */ + append_string_object(ret, "ON UPDATE %{on_update}s", "on_update", onupdate ? onupdate : ""); + + append_string_object(ret, "%{not_null}s", "not_null", + saw_notnull ? "NOT NULL" : saw_autoincrement ? "NULL" : ""); + + /* GENERATED COLUMN EXPRESSION */ + tmp_obj = new_objtree("GENERATED ALWAYS AS"); + if (coldef->generatedCol == ATTRIBUTE_GENERATED_STORED) { + char *defstr; + + defstr = RelationGetColumnDefault(relation, attrForm->attnum, dpcontext, exprs); + append_string_object(tmp_obj, "(%{generation_expr}s) STORED", "generation_expr", defstr); + } else { + append_not_present(tmp_obj, "(%{generation_expr}s) STORED"); + } + + append_object_object(ret, "%{generated_column}s", tmp_obj); + + tmp_obj = new_objtree("DEFAULT"); + + if (attrForm->atthasdef && + coldef->generatedCol != ATTRIBUTE_GENERATED_STORED && + !saw_autoincrement && + !onupdate) { + char *defstr; + + defstr = RelationGetColumnDefault(relation, attrForm->attnum, + dpcontext, exprs); + + append_string_object(tmp_obj, "%{default}s", "default", defstr); + } else { + append_not_present(tmp_obj, "%{default}s"); + } + append_object_object(ret, "%{default}s", tmp_obj); + + ReleaseSysCache(attrTup); + return ret; +} + +static bool istypestring(Oid typid); /* * Deparse a ColumnDef node within a regular (non-typed) table creation. * @@ -1398,23 +1663,23 @@ static char *RelationGetColumnOnUpdate(Node *update_expr, List *dpcontext, List * elsewhere (the info in the parse node is incomplete anyway). * * Verbose syntax - * %{name}I %{coltype}T %{compression}s %{default}s %{not_null}s %{collation}s + * %{name}I %{coltype}T %{auto_increment} %{default}s %{not_null}s %{collation}s */ -static ObjTree * -deparse_ColumnDef(Relation relation, List *dpcontext, - ColumnDef *coldef, List **exprs) +static ObjTree* deparse_ColumnDef(Relation relation, List *dpcontext, bool composite, + ColumnDef *coldef, bool is_alter, List **exprs) { - ObjTree *ret; - Oid relid = RelationGetRelid(relation); - HeapTuple attrTup; + ObjTree *ret; + ObjTree *tmp_obj; + Oid relid = RelationGetRelid(relation); + HeapTuple attrTup; Form_pg_attribute attrForm; - Oid typid; - int32 typmod; - Oid typcollation; - bool saw_notnull; - bool saw_autoincrement; - char *onupdate = NULL; - ListCell *cell; + Oid typid; + int32 typmod; + Oid typcollation; + bool saw_notnull; + bool saw_autoincrement; + char* onupdate = NULL; + ListCell *cell; /* * Inherited columns without local definitions must not be emitted. @@ -1440,69 +1705,125 @@ deparse_ColumnDef(Relation relation, List *dpcontext, "coltype", ObjTypeObject, new_objtree_for_type(typid, typmod)); - - + tmp_obj = new_objtree("COLLATE"); if (OidIsValid(typcollation)) { - append_object_object(ret, "COLLATE %{collate}D", + append_object_object(tmp_obj, "%{name}D", new_objtree_for_qualname_id(CollationRelationId, typcollation)); + } else { + append_not_present(tmp_obj, "%{name}D"); } - - /* - * Emit a NOT NULL declaration if necessary. Note that we cannot - * trust pg_attribute.attnotnull here, because that bit is also set - * when primary keys are specified; we must not emit a NOT NULL - * constraint in that case, unless explicitly specified. Therefore, - * we scan the list of constraints attached to this column to - * determine whether we need to emit anything. (Fortunately, NOT NULL - * constraints cannot be table constraints.) - * - * In the ALTER TABLE cases, we also add a NOT NULL if the colDef is - * marked is_not_null. - */ - saw_notnull = false; - saw_autoincrement = false; + append_object_object(ret, "%{collation}s", tmp_obj); - foreach(cell, coldef->constraints) { - Constraint *constr = (Constraint *) lfirst(cell); + if (!composite) { + /* + * Emit a NOT NULL declaration if necessary. Note that we cannot + * trust pg_attribute.attnotnull here, because that bit is also set + * when primary keys are specified; we must not emit a NOT NULL + * constraint in that case, unless explicitly specified. Therefore, + * we scan the list of constraints attached to this column to + * determine whether we need to emit anything. (Fortunately, NOT NULL + * constraints cannot be table constraints.) + * + * In the ALTER TABLE cases, we also add a NOT NULL if the colDef is + * marked is_not_null. + */ + saw_notnull = false; + saw_autoincrement = false; + foreach(cell, coldef->constraints) { + Constraint *constr = (Constraint *) lfirst(cell); - if (constr->contype == CONSTR_NOTNULL) { - saw_notnull = true; - } else if (constr->contype == CONSTR_AUTO_INCREMENT) { - saw_autoincrement = true; - } else if (constr->contype == CONSTR_DEFAULT && constr->update_expr) { - onupdate = RelationGetColumnOnUpdate(constr->update_expr, dpcontext, exprs); + if (constr->contype == CONSTR_NOTNULL) { + saw_notnull = true; + } else if (constr->contype == CONSTR_AUTO_INCREMENT) { + saw_autoincrement = true; + } else if (constr->contype == CONSTR_DEFAULT && constr->update_expr) { + onupdate = RelationGetColumnOnUpdate(constr->update_expr, dpcontext, exprs); + } } + + if (is_alter && coldef->is_not_null) + saw_notnull = true; + + if (is_alter && !saw_autoincrement && coldef->raw_default && + IsA(coldef->raw_default, AutoIncrement)) { + saw_autoincrement = true; + } + + if (is_alter && saw_autoincrement) { + check_alter_table_rewrite_replident_change(relation, attrForm->attnum, "ADD COLUMN AUTO_INCREMENT"); + /* auto_increment will be set with constraint when rewrite finish */ + ReleaseSysCache(attrTup); + return ret; + } + + append_string_object(ret, "%{auto_increment}s", "auto_increment", + saw_autoincrement ? "AUTO_INCREMENT" : ""); + + tmp_obj = new_objtree("DEFAULT"); + + if (attrForm->atthasdef && + coldef->generatedCol != ATTRIBUTE_GENERATED_STORED && + !saw_autoincrement) { + char *defstr = NULL; + + /* initdefval intend that default value is a constant expr, + * if the default can not get from initdefval, then need output dml change + * and set default after rewrite + */ + if (is_alter) { + if (coldef->initdefval) { + StringInfoData defvalbuf; + initStringInfo(&defvalbuf); + if (istypestring(typid)) + appendStringInfo(&defvalbuf, "\'%s\'", coldef->initdefval); + else + appendStringInfo(&defvalbuf, "%s", coldef->initdefval); + defstr = pstrdup(defvalbuf.data); + } else { + /* if coldef->initdefval not exist, then default is not a constant + * handle it after rewrite finish + */ + append_not_present(tmp_obj, "%{default}s"); + } + append_string_object(tmp_obj, "%{default}s", "default", defstr); + } else { + defstr = RelationGetColumnDefault(relation, attrForm->attnum, dpcontext, exprs); + if (defstr == NULL || defstr[0] == '\0') { + append_not_present(tmp_obj, "%{default}s"); + } else { + append_string_object(tmp_obj, "%{default}s", "default", defstr); + } + } + } else { + append_not_present(tmp_obj, "%{default}s"); + } + append_object_object(ret, "%{default}s", tmp_obj); + + /* ON UPDATE */ + if ((!onupdate || !strlen(onupdate)) && coldef->update_default) { + onupdate = RelationGetColumnOnUpdate(coldef->update_default, dpcontext, exprs); + } + append_string_object(ret, "ON UPDATE %{on_update}s", "on_update", onupdate ? onupdate : ""); + + if (!is_alter || saw_autoincrement) + append_string_object(ret, "%{not_null}s", "not_null", saw_notnull ? "NOT NULL" : ""); + + /* GENERATED COLUMN EXPRESSION */ + tmp_obj = new_objtree("GENERATED ALWAYS AS"); + if (coldef->generatedCol == ATTRIBUTE_GENERATED_STORED) { + char *defstr; + + defstr = RelationGetColumnDefault(relation, attrForm->attnum, + dpcontext, exprs); + append_string_object(tmp_obj, "(%{generation_expr}s) STORED", + "generation_expr", defstr); + } else { + append_not_present(tmp_obj, "(%{generation_expr}s) STORED"); + } + append_object_object(ret, "%{generated_column}s", tmp_obj); } - append_string_object(ret, "%{auto_increment}s", "auto_increment", - saw_autoincrement ? "AUTO_INCREMENT" : ""); - - - - append_string_object(ret, "%{not_null}s", "not_null", - saw_notnull ? "NOT NULL" : ""); - - /* GENERATED COLUMN EXPRESSION */ - if (coldef->generatedCol == ATTRIBUTE_GENERATED_STORED) { - char *defstr = RelationGetColumnDefault(relation, attrForm->attnum, dpcontext, exprs); - append_string_object(ret, "GENERATED ALWAYS AS (%{generation_expr}s) STORED", - "generation_expr", defstr); - } - - if (attrForm->atthasdef && - coldef->generatedCol != ATTRIBUTE_GENERATED_STORED && - !saw_autoincrement) { - char *defstr; - - defstr = RelationGetColumnDefault(relation, attrForm->attnum, - dpcontext, exprs); - - append_string_object(ret, "DEFAULT %{default}s", "default", defstr); - } - - append_string_object(ret, "ON UPDATE %{on_update}s", "on_update", onupdate ? onupdate : ""); - ReleaseSysCache(attrTup); return ret; @@ -1515,8 +1836,7 @@ deparse_ColumnDef(Relation relation, List *dpcontext, * Verbose syntax * %{label}s = %{value}L */ -static ObjTree * -deparse_DefElem(DefElem *elem, bool is_reset) +static ObjTree* deparse_DefElem(DefElem *elem, bool is_reset) { ObjTree *ret; ObjTree *optname = new_objtree(""); @@ -1550,8 +1870,7 @@ deparse_DefElem(DefElem *elem, bool is_reset) * Verbose syntax * ON COMMIT %{on_commit_value}s */ -static ObjTree * -deparse_OnCommitClause(OnCommitAction option) +static ObjTree* deparse_OnCommitClause(OnCommitAction option) { ObjTree *ret = new_objtree("ON COMMIT"); switch (option) { @@ -1586,14 +1905,13 @@ deparse_OnCommitClause(OnCommitAction option) * OR * CACHE %{value} */ -static inline ObjElem * -deparse_Seq_Cache(sequence_values * seqdata, bool alter_table) +static inline ObjElem* deparse_Seq_Cache(sequence_values *seqdata, bool alter_table) { ObjTree *ret; const char *fmt; fmt = alter_table ? "SET CACHE %{value}s" : "CACHE %{value}s"; - + ret = new_objtree_VA(fmt, 2, "clause", ObjTypeString, "cache", "value", ObjTypeString, seqdata->cache_value); @@ -1609,14 +1927,13 @@ deparse_Seq_Cache(sequence_values * seqdata, bool alter_table) * OR * %{no}s CYCLE */ -static inline ObjElem * -deparse_Seq_Cycle(sequence_values * seqdata, bool alter_table) +static inline ObjElem* deparse_Seq_Cycle(sequence_values *seqdata, bool alter_table) { ObjTree *ret; const char *fmt; fmt = alter_table ? "SET %{no}s CYCLE" : "%{no}s CYCLE"; - + ret = new_objtree_VA(fmt, 2, "clause", ObjTypeString, "cycle", "no", ObjTypeString, @@ -1633,13 +1950,12 @@ deparse_Seq_Cycle(sequence_values * seqdata, bool alter_table) * OR * INCREMENT BY %{value}s */ -static inline ObjElem * -deparse_Seq_IncrementBy(sequence_values * seqdata, bool alter_table) +static inline ObjElem* deparse_Seq_IncrementBy(sequence_values *seqdata, bool alter_table) { ObjTree *ret; const char *fmt; - fmt = alter_table ? "SET INCREMENT BY %{value}s" : "INCREMENT BY %{value}s"; + fmt = alter_table ? "SET INCREMENT BY %{value}s" : "INCREMENT BY %{value}s"; ret = new_objtree_VA(fmt, 2, "clause", ObjTypeString, "seqincrement", @@ -1656,8 +1972,7 @@ deparse_Seq_IncrementBy(sequence_values * seqdata, bool alter_table) * OR * MAXVALUE %{value}s */ -static inline ObjElem * -deparse_Seq_Maxvalue(sequence_values * seqdata, bool alter_table) +static inline ObjElem* deparse_Seq_Maxvalue(sequence_values *seqdata, bool alter_table) { ObjTree *ret; const char *fmt; @@ -1679,13 +1994,12 @@ deparse_Seq_Maxvalue(sequence_values * seqdata, bool alter_table) * OR * MINVALUE %{value}s */ -static inline ObjElem * -deparse_Seq_Minvalue(sequence_values * seqdata, bool alter_table) +static inline ObjElem* deparse_Seq_Minvalue(sequence_values *seqdata, bool alter_table) { ObjTree *ret; const char *fmt; - fmt = alter_table ? "SET MINVALUE %{value}s" : "MINVALUE %{value}s"; + fmt = alter_table ? "SET MINVALUE %{value}s" : "MINVALUE %{value}s"; ret = new_objtree_VA(fmt, 2, "clause", ObjTypeString, "minvalue", @@ -1696,12 +2010,11 @@ deparse_Seq_Minvalue(sequence_values * seqdata, bool alter_table) /* * Deparse the sequence OWNED BY command. - * + * * Verbose syntax * OWNED BY %{owner}D */ -static ObjElem * -deparse_Seq_OwnedBy(Oid sequenceId) +static ObjElem* deparse_Seq_OwnedBy(Oid sequenceId) { ObjTree *ret = NULL; Relation depRel; @@ -1723,7 +2036,7 @@ deparse_Seq_OwnedBy(Oid sequenceId) BTEqualStrategyNumber, F_INT4EQ, Int32GetDatum(0)); - scan = systable_beginscan(depRel, DependDependerIndexId, true, + scan = systable_beginscan(depRel, DependDependerIndexId, true, NULL, 3, keys); while (HeapTupleIsValid(tuple = systable_getnext(scan))) { @@ -1731,7 +2044,7 @@ deparse_Seq_OwnedBy(Oid sequenceId) Form_pg_depend depform; ObjTree *tmp_obj; char *colname; - + depform = (Form_pg_depend) GETSTRUCT(tuple); /* Only consider AUTO dependencies on pg_class */ @@ -1749,11 +2062,11 @@ deparse_Seq_OwnedBy(Oid sequenceId) tmp_obj = new_objtree_for_qualname_id(RelationRelationId, ownerId); append_string_object(tmp_obj, "attrname", "attrname", colname); - ret = new_objtree_VA("OWNED BY %{owner}D", 2, - "clause", ObjTypeString, "owned", - "owner", ObjTypeObject, tmp_obj); + ret = new_objtree_VA("OWNED BY %{owner}D", 2, + "clause", ObjTypeString, "owned", + "owner", ObjTypeObject, tmp_obj); } - + systable_endscan(scan); relation_close(depRel, AccessShareLock); @@ -1764,21 +2077,20 @@ deparse_Seq_OwnedBy(Oid sequenceId) if (!ret) /* XXX this shouldn't happen */ ret = new_objtree_VA("OWNED BY %{owner}D", 3, - "clause", ObjTypeString, "owned", - "owner", ObjTypeNull, - "present", ObjTypeBool, false); + "clause", ObjTypeString, "owned", + "owner", ObjTypeNull, + "present", ObjTypeBool, false); - return new_object_object(ret); + return new_object_object(ret); } /* * Deparse the sequence ORDER option. */ -static inline ObjElem * -deparse_Seq_Order(DefElem *elem) +static inline ObjElem* deparse_Seq_Order(DefElem *elem) { ObjTree *ret; - + ret = new_objtree_VA("%{order}s", 2, "clause", ObjTypeString, "order", "order", ObjTypeString, defGetBoolean(elem) ? "ORDER" : "NOORDER"); @@ -1793,8 +2105,7 @@ deparse_Seq_Order(DefElem *elem) * Verbose syntax * RESTART %{value}s */ -static inline ObjElem * -deparse_Seq_Restart(char *last_value) +static inline ObjElem* deparse_Seq_Restart(char *last_value) { ObjTree *ret; ret = new_objtree_VA("RESTART %{value}s", 2, @@ -1810,8 +2121,7 @@ deparse_Seq_Restart(char *last_value) * Verbose syntax * AS %{identity}D */ -static inline ObjElem * -deparse_Seq_As(DefElem *elem) +static inline ObjElem* deparse_Seq_As(DefElem *elem) { ObjTree *ret; Type likeType; @@ -1837,13 +2147,12 @@ deparse_Seq_As(DefElem *elem) * OR * START WITH %{value}s */ -static inline ObjElem * -deparse_Seq_Startwith(sequence_values *seqdata, bool alter_table) +static inline ObjElem* deparse_Seq_Startwith(sequence_values *seqdata, bool alter_table) { ObjTree *ret; const char *fmt; - fmt = alter_table ? "SET START WITH %{value}s" : "START WITH %{value}s"; + fmt = alter_table ? "SET START WITH %{value}s" : "START WITH %{value}s"; ret = new_objtree_VA(fmt, 2, "clause", ObjTypeString, "start", @@ -1852,6 +2161,62 @@ deparse_Seq_Startwith(sequence_values *seqdata, bool alter_table) return new_object_object(ret); } +static bool istypestring(Oid typid) +{ + switch (typid) { + case INT2OID: + case INT4OID: + case INT8OID: + case FLOAT4OID: + case FLOAT8OID: + case NUMERICOID: + /* Here we ignore infinity and NaN */ + return false; + default: + /* All other types are regarded as string. */ + return true; + } +} + +/* + * Deparse the INHERITS relations. + * + * Given a table OID, return a schema-qualified table list representing + * the parent tables. + */ +static List* deparse_InhRelations(Oid objectId) +{ + List *parents = NIL; + Relation inhRel; + SysScanDesc scan; + ScanKeyData key; + HeapTuple tuple; + + inhRel = table_open(InheritsRelationId, RowExclusiveLock); + + ScanKeyInit(&key, + Anum_pg_inherits_inhrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(objectId)); + + scan = systable_beginscan(inhRel, InheritsRelidSeqnoIndexId, + true, NULL, 1, &key); + + while (HeapTupleIsValid(tuple = systable_getnext(scan))) { + ObjTree *parent; + Form_pg_inherits formInh = (Form_pg_inherits) GETSTRUCT(tuple); + + parent = new_objtree_for_qualname_id(RelationRelationId, + formInh->inhparent); + parents = lappend(parents, new_object_object(parent)); + } + + systable_endscan(scan); + table_close(inhRel, RowExclusiveLock); + + return parents; +} + /* * Subroutine for CREATE TABLE deparsing. * @@ -1860,8 +2225,7 @@ deparse_Seq_Startwith(sequence_values *seqdata, bool alter_table) * Note we ignore constraints in the parse node here; they are extracted from * system catalogs instead. */ -static List * -deparse_TableElements(Relation relation, List *tableElements, List *dpcontext) +static List* deparse_TableElements(Relation relation, List *tableElements, List *dpcontext, bool composite) { List *elements = NIL; ListCell *lc; @@ -1872,7 +2236,9 @@ deparse_TableElements(Relation relation, List *tableElements, List *dpcontext) switch (nodeTag(elt)) { case T_ColumnDef: { ObjTree *tree; - tree = deparse_ColumnDef(relation, dpcontext, (ColumnDef *) elt, NULL); + tree = deparse_ColumnDef(relation, dpcontext, + composite, (ColumnDef *) elt, + false, NULL); if (tree != NULL) elements = lappend(elements, new_object_object(tree)); } @@ -1896,8 +2262,7 @@ deparse_TableElements(Relation relation, List *tableElements, List *dpcontext) * Verbose syntax * CREATE %{persistence}s SEQUENCE %{identity}D */ -static ObjTree * -deparse_CreateSeqStmt(Oid objectId, Node *parsetree) +static ObjTree* deparse_CreateSeqStmt(Oid objectId, Node *parsetree) { ObjTree *ret; Relation relation; @@ -1927,7 +2292,7 @@ deparse_CreateSeqStmt(Oid objectId, Node *parsetree) "persistence", ObjTypeString, get_persistence_str(relation->rd_rel->relpersistence), "large", ObjTypeString, seqvalues->large ? "LARGE" : "", "identity", ObjTypeObject, new_objtree_for_qualname(relation->rd_rel->relnamespace, - RelationGetRelationName(relation)), + RelationGetRelationName(relation)), "definition", ObjTypeArray, elems); relation_close(relation, AccessShareLock); @@ -1943,8 +2308,7 @@ deparse_CreateSeqStmt(Oid objectId, Node *parsetree) * Verbose syntax * ALTER SEQUENCE %{identity}D %{definition: }s */ -static ObjTree * -deparse_AlterSeqStmt(Oid objectId, Node *parsetree) +static ObjTree* deparse_AlterSeqStmt(Oid objectId, Node *parsetree) { ObjTree *ret; Relation relation; @@ -1999,12 +2363,234 @@ deparse_AlterSeqStmt(Oid objectId, Node *parsetree) "large", ObjTypeString, seqvalues->large ? "LARGE" : "", "identity", ObjTypeObject, new_objtree_for_qualname(relation->rd_rel->relnamespace, - RelationGetRelationName(relation)), + RelationGetRelationName(relation)), "definition", ObjTypeArray, elems); relation_close(relation, AccessShareLock); - return ret; + return ret; +} + +/* + * deparse_ViewStmt + * deparse a ViewStmt + * + * Given a view OID and the parse tree that created it, return an ObjTree + * representing the creation command. + * + * Verbose syntax + * CREATE %{or_replace}s %{persistence}s VIEW %{identity}D AS %{query}s + */ +static ObjTree* deparse_ViewStmt(Oid objectId, Node *parsetree) +{ + ViewStmt *node = (ViewStmt *) parsetree; + ObjTree *ret; + Relation relation; + + relation = relation_open(objectId, AccessShareLock); + + ret = new_objtree_VA("CREATE %{or_replace}s %{persistence}s VIEW %{identity}D AS %{query}s", 4, + "or_replace", ObjTypeString, + node->replace ? "OR REPLACE" : "", + "persistence", ObjTypeString, + get_persistence_str(relation->rd_rel->relpersistence), + "identity", ObjTypeObject, + new_objtree_for_qualname(relation->rd_rel->relnamespace, + RelationGetRelationName(relation)), + "query", ObjTypeString, + pg_get_viewdef_string(objectId)); + + relation_close(relation, AccessShareLock); + return ret; +} + +/* + * Deparse a RenameStmt. + */ +static ObjTree* deparse_RenameStmt(ObjectAddress address, Node *parsetree) +{ + RenameStmt *node = (RenameStmt *) parsetree; + ObjTree *ret; + Relation relation; + Oid schemaId; + + if (node->is_modifycolumn) { + /* modify column in dbcompatibility B */ + return NULL; + } + + if (node->renameTableflag) { + /* rename table syntax in dbcompatibility B */ + ListCell *cell = NULL; + List *renamelist = NIL; + foreach (cell, node->renameTargetList) { + RenameCell* renameInfo = (RenameCell*)lfirst(cell); + RangeVar *cur = NULL; + RangeVar *ori = NULL; + Oid nspoid = InvalidOid; + Oid tbloid = InvalidOid; + ObjTree *tmp_obj = NULL; + + ori = renameInfo->original_name; + cur = renameInfo->modify_name; + + if (!cur->schemaname || !ori->schemaname) { + continue; + } + + nspoid = get_namespace_oid(cur->schemaname, false); + tbloid = get_relname_relid(cur->relname, nspoid); + if (!OidIsValid(tbloid)) { + elog(ERROR, "can not find the table %s.%s for deparse rename table", + cur->schemaname, cur->relname); + } + if (!relation_support_ddl_replication(tbloid, false)) { + continue; + } + + tmp_obj = new_objtree_VA("%{ori}D TO %{modify}D", 2, + "ori", ObjTypeObject, new_objtree_for_qualname_rangevar(ori), + "modify", ObjTypeObject, new_objtree_for_qualname_rangevar(cur)); + + renamelist = lappend(renamelist, new_object_object(tmp_obj)); + } + + if (renamelist) { + ret = new_objtree_VA("RENAME TABLE %{renamelist:, }s", 1, + "renamelist", ObjTypeArray, renamelist); + return ret; + } else { + return NULL; + } + } + + /* + * In an ALTER .. RENAME command, we don't have the original name of the + * object in system catalogs: since we inspect them after the command has + * executed, the old name is already gone. Therefore, we extract it from + * the parse node. Note we still extract the schema name from the catalog + * (it might not be present in the parse node); it cannot possibly have + * changed anyway. + */ + switch (node->renameType) { + case OBJECT_TABLE: + case OBJECT_INDEX: + case OBJECT_SEQUENCE: + case OBJECT_LARGE_SEQUENCE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + relation = relation_open(address.objectId, AccessShareLock); + schemaId = RelationGetNamespace(relation); + ret = new_objtree_VA("ALTER %{objtype}s %{if_exists}s %{identity}D RENAME TO %{newname}I", 4, + "objtype", ObjTypeString, + string_objtype(node->renameType, false), + "if_exists", ObjTypeString, + node->missing_ok ? "IF EXISTS" : "", + "identity", ObjTypeObject, + new_objtree_for_qualname(schemaId, + node->relation->relname), + "newname", ObjTypeString, + node->newname); + relation_close(relation, AccessShareLock); + break; + + case OBJECT_ATTRIBUTE: + case OBJECT_COLUMN: + relation = relation_open(address.objectId, AccessShareLock); + schemaId = RelationGetNamespace(relation); + + if (node->renameType == OBJECT_ATTRIBUTE) { + ret = new_objtree_VA("ALTER TYPE %{identity}D RENAME ATTRIBUTE %{colname}I", 2, + "identity", ObjTypeObject, + new_objtree_for_qualname(schemaId, + node->relation->relname), + "colname", ObjTypeString, node->subname); + } else { + ret = new_objtree_VA("ALTER %{objtype}s", 1, + "objtype", ObjTypeString, + string_objtype(node->relationType, false)); + + /* Composite types do not support IF EXISTS */ + if (node->renameType == OBJECT_COLUMN) + append_string_object(ret, "%{if_exists}s", + "if_exists", + node->missing_ok ? "IF EXISTS" : ""); + + append_object_object(ret, "%{identity}D", + new_objtree_for_qualname(schemaId, + node->relation->relname)); + append_string_object(ret, "RENAME COLUMN %{colname}I", + "colname", node->subname); + } + + append_string_object(ret, "TO %{newname}I", "newname", node->newname); + + if (node->renameType == OBJECT_ATTRIBUTE) + append_object_object(ret, "%{cascade}s", + new_objtree_VA("CASCADE", 1, + "present", ObjTypeBool, + node->behavior == DROP_CASCADE)); + + relation_close(relation, AccessShareLock); + break; + + case OBJECT_SCHEMA: + ret = new_objtree_VA("ALTER SCHEMA %{identity}I RENAME TO %{newname}I", 2, + "identity", ObjTypeString, node->subname, + "newname", ObjTypeString, node->newname); + break; + case OBJECT_TABCONSTRAINT: { + HeapTuple constrtup; + Form_pg_constraint constform; + + constrtup = SearchSysCache1(CONSTROID, + ObjectIdGetDatum(address.objectId)); + if (!HeapTupleIsValid(constrtup)) + elog(ERROR, "cache lookup failed for constraint with OID %u", + address.objectId); + constform = (Form_pg_constraint) GETSTRUCT(constrtup); + + ret = new_objtree_VA("ALTER TABLE %{identity}D RENAME CONSTRAINT %{oldname}I TO %{newname}I", 3, + "identity", ObjTypeObject, + new_objtree_for_qualname_id(RelationRelationId, + constform->conrelid), + "oldname", ObjTypeString, node->subname, + "newname", ObjTypeString, node->newname); + ReleaseSysCache(constrtup); + } + break; + case OBJECT_TYPE: { + HeapTuple typtup; + Form_pg_type typform; + Oid nspid; + + List* names = node->object; + char *typeName; + char *schemaname; + char *pkgName; + DeconstructQualifiedName(names, &schemaname, &typeName, &pkgName); + + typtup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(address.objectId)); + if (!HeapTupleIsValid(typtup)) + elog(ERROR, "cache lookup failed for type with OID %u", address.objectId); + typform = (Form_pg_type) GETSTRUCT(typtup); + nspid = typform->typnamespace; + + ret = new_objtree_VA("ALTER TYPE %{identity}D RENAME TO %{newname}I", 2, + "identity", ObjTypeObject, + new_objtree_for_qualname(nspid, + typeName), + "newname", ObjTypeString, node->newname); + + ReleaseSysCache(typtup); + } + break; + default: + elog(WARNING, "unsupported RenameStmt object type %d", node->renameType); + return NULL; + } + + return ret; } /* @@ -2013,8 +2599,7 @@ deparse_AlterSeqStmt(Oid objectId, Node *parsetree) * Verbose syntax * COMMENT ON CONSTRAINT %{identity}s ON [DOMAIN] %{parentobj}s IS %{comment}s */ -static ObjTree * -deparse_CommentOnConstraintSmt(Oid objectId, Node *parsetree) +static ObjTree* deparse_CommentOnConstraintSmt(Oid objectId, Node *parsetree) { CommentStmt *node = (CommentStmt *) parsetree; ObjTree *ret; @@ -2035,11 +2620,11 @@ deparse_CommentOnConstraintSmt(Oid objectId, Node *parsetree) ObjectAddressSet(addr, TypeRelationId, constrForm->contypid); ret = new_objtree_VA("COMMENT ON CONSTRAINT %{identity}s ON %{domain}s %{parentobj}s", 3, - "identity", ObjTypeString, pstrdup(NameStr(constrForm->conname)), - "domain", ObjTypeString, - (node->objtype == OBJECT_DOMCONSTRAINT) ? "DOMAIN" : "", - "parentobj", ObjTypeString, - getObjectIdentity(&addr)); + "identity", ObjTypeString, pstrdup(NameStr(constrForm->conname)), + "domain", ObjTypeString, + (node->objtype == OBJECT_DOMCONSTRAINT) ? "DOMAIN" : "", + "parentobj", ObjTypeString, + getObjectIdentity(&addr)); /* Add the comment clause */ append_literal_or_null(ret, "IS %{comment}s", node->comment); @@ -2057,8 +2642,7 @@ deparse_CommentOnConstraintSmt(Oid objectId, Node *parsetree) * Verbose syntax * COMMENT ON %{objtype}s %{identity}s IS %{comment}s */ -static ObjTree * -deparse_CommentStmt(ObjectAddress address, Node *parsetree) +static ObjTree* deparse_CommentStmt(ObjectAddress address, Node *parsetree) { CommentStmt *node = (CommentStmt *) parsetree; ObjTree *ret; @@ -2079,8 +2663,8 @@ deparse_CommentStmt(ObjectAddress address, Node *parsetree) } ret = new_objtree_VA("COMMENT ON %{objtype}s", 1, - "objtype", ObjTypeString, - (char *) string_objtype(node->objtype, false)); + "objtype", ObjTypeString, + (char *) string_objtype(node->objtype, false)); /* * Add the object identity clause. For zero argument aggregates we need @@ -2097,12 +2681,12 @@ deparse_CommentStmt(ObjectAddress address, Node *parsetree) procTup = SearchSysCache1(PROCOID, ObjectIdGetDatum(address.objectId)); if (!HeapTupleIsValid(procTup)) elog(ERROR, "cache lookup failed for procedure with OID %u", - address.objectId); + address.objectId); procForm = (Form_pg_proc) GETSTRUCT(procTup); if (procForm->pronargs == 0) identity = psprintf("%s(*)", quote_qualified_identifier(get_namespace_name(procForm->pronamespace), - NameStr(procForm->proname))); + NameStr(procForm->proname))); else identity = getObjectIdentity(&address); ReleaseSysCache(procTup); @@ -2118,6 +2702,47 @@ deparse_CommentStmt(ObjectAddress address, Node *parsetree) return ret; } +/* + * Deparse a CompositeTypeStmt (CREATE TYPE AS) + * + * Given a Composite type OID and the parse tree that created it, return an + * ObjTree representing the creation command. + * + * Verbose syntax + * CREATE TYPE %{identity}D AS (%{columns:, }s) + */ +static ObjTree* deparse_CompositeTypeStmt(Oid objectId, Node *parsetree) +{ + CompositeTypeStmt *node = (CompositeTypeStmt *) parsetree; + HeapTuple typtup; + Form_pg_type typform; + Relation typerel; + List *dpcontext; + List *tableelts = NIL; + + /* Find the pg_type entry and open the corresponding relation */ + typtup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(objectId)); + if (!HeapTupleIsValid(typtup)) + elog(ERROR, "cache lookup failed for type with OID %u", objectId); + + typform = (Form_pg_type) GETSTRUCT(typtup); + typerel = relation_open(typform->typrelid, AccessShareLock); + + dpcontext = deparse_context_for(RelationGetRelationName(typerel), + RelationGetRelid(typerel)); + + tableelts = deparse_TableElements(typerel, node->coldeflist, dpcontext, + true); /* composite type */ + + table_close(typerel, AccessShareLock); + ReleaseSysCache(typtup); + + return new_objtree_VA("CREATE TYPE %{identity}D AS (%{columns:, }s)", 2, + "identity", ObjTypeObject, + new_objtree_for_qualname_id(TypeRelationId, objectId), + "columns", ObjTypeArray, tableelts); +} + /* * Deparse an IndexStmt. * @@ -2131,8 +2756,7 @@ deparse_CommentStmt(ObjectAddress address, Node *parsetree) * %{table}D USING %{index_am}s %{definition}s %{with}s %{tablespace}s * %{where_clause}s */ -static ObjTree * -deparse_IndexStmt(Oid objectId, Node *parsetree) +static ObjTree* deparse_IndexStmt(Oid objectId, Node *parsetree) { IndexStmt *node = (IndexStmt *) parsetree; ObjTree *ret; @@ -2161,14 +2785,15 @@ deparse_IndexStmt(Oid objectId, Node *parsetree) &index_am, &definition, &reloptions, &tablespace, &whereClause, &invisible); - ret = new_objtree_VA("CREATE %{unique}s INDEX %{concurrently}s %{name}I ON %{table}D USING %{index_am}s %{definition}s", 6, - "unique", ObjTypeString, node->unique ? "UNIQUE" : "", - "concurrently", ObjTypeString, node->concurrent ? "CONCURRENTLY" : "", - "name", ObjTypeString, RelationGetRelationName(idxrel), - "table", ObjTypeObject, - new_objtree_for_qualname(heaprel->rd_rel->relnamespace, RelationGetRelationName(heaprel)), - "index_am", ObjTypeString, index_am, - "definition", ObjTypeString, definition); + ret = new_objtree_VA( + "CREATE %{unique}s INDEX %{concurrently}s %{name}I ON %{table}D USING %{index_am}s %{definition}s", 6, + "unique", ObjTypeString, node->unique ? "UNIQUE" : "", + "concurrently", ObjTypeString, node->concurrent ? "CONCURRENTLY" : "", + "name", ObjTypeString, RelationGetRelationName(idxrel), + "table", ObjTypeObject, + new_objtree_for_qualname(heaprel->rd_rel->relnamespace, RelationGetRelationName(heaprel)), + "index_am", ObjTypeString, index_am, + "definition", ObjTypeString, definition); /* reloptions */ if (reloptions) @@ -2204,8 +2829,7 @@ deparse_IndexStmt(Oid objectId, Node *parsetree) * %{inherits}s %{partition_by}s %{access_method}s %{with_clause}s * %{on_commit}s %{tablespace}s */ -static ObjTree * -deparse_CreateStmt(Oid objectId, Node *parsetree) +static ObjTree* deparse_CreateStmt(Oid objectId, Node *parsetree) { CreateStmt *node = (CreateStmt *) parsetree; Relation relation = relation_open(objectId, AccessShareLock); @@ -2219,7 +2843,7 @@ deparse_CreateStmt(Oid objectId, Node *parsetree) "persistence", ObjTypeString, get_persistence_str(relation->rd_rel->relpersistence), "if_not_exists", ObjTypeString, node->if_not_exists ? "IF NOT EXISTS" : "", "identity", ObjTypeObject, new_objtree_for_qualname(relation->rd_rel->relnamespace, - RelationGetRelationName(relation))); + RelationGetRelationName(relation))); dpcontext = deparse_context_for(RelationGetRelationName(relation), objectId); @@ -2241,13 +2865,32 @@ deparse_CreateStmt(Oid objectId, Node *parsetree) * get constraints we rely on pg_constraint, because the parse node * might be missing some things such as the name of the constraints. */ - tableelts = deparse_TableElements(relation, node->tableElts, dpcontext); + tableelts = deparse_TableElements(relation, node->tableElts, dpcontext, + false); /* not composite */ tableelts = obtainConstraints(tableelts, objectId); + tmp_obj = new_objtree(""); if (tableelts) - append_array_object(ret, "(%{table_elements:, }s)", tableelts); + append_array_object(tmp_obj, "(%{elements:, }s)", tableelts); else - append_format_string(ret, "()"); + append_format_string(tmp_obj, "()"); + + append_object_object(ret, "%{table_elements}s", tmp_obj); + + /* + * Add inheritance specification. We cannot simply scan the list of + * parents from the parser node, because that may lack the actual + * qualified names of the parent relations. Rather than trying to + * re-resolve them from the information in the parse node, it seems + * more accurate and convenient to grab it from pg_inherits. + */ + tmp_obj = new_objtree("INHERITS"); + if (node->inhRelations != NIL) { + append_array_object(tmp_obj, "(%{parents:, }D)", deparse_InhRelations(objectId)); + } else { + append_not_present(tmp_obj, "(%{parents:, }D)"); + } + append_object_object(ret, "%{inherits}s", tmp_obj); } /* AUTO_INCREMENT */ @@ -2279,7 +2922,7 @@ deparse_CreateStmt(Oid objectId, Node *parsetree) if (node->oncommit != ONCOMMIT_NOOP) append_object_object(ret, "%{on_commit}s", - deparse_OnCommitClause(node->oncommit)); + deparse_OnCommitClause(node->oncommit)); if (node->tablespacename) append_string_object(ret, "TABLESPACE %{tablespace}I", "tablespace", @@ -2298,7 +2941,7 @@ deparse_CreateStmt(Oid objectId, Node *parsetree) } } } - if (table_options) + if (table_options) append_array_object(ret, "%{options:, }s", table_options); /* opt_table_partitioning_clause */ @@ -2311,15 +2954,407 @@ deparse_CreateStmt(Oid objectId, Node *parsetree) return ret; } +/* + * +declare +null_cnt int; +start_num int; +sql text; +begin +select count(*) from %{identity}D where %{colname}I is null into null_cnt; +start_num := intmax - null_cnt; +sql := 'create large sequence %{seqname}D start with ' || start_num; +execute sql; +update %{identity}D set %{colname}I=pg_catalog.nextval('%{seqname}D') WEHRE %{colname}I IS NULL; +DROP large SEQUENCE %{seqname}D; +end; +/ + */ + +static char ADAPT_SUBSCTIPTION_AUTOINCREMENT_FMT[] = +"DECLARE\n" +"null_cnt pg_catalog.%{typname}s;\n" +"start_num pg_catalog.%{typname}s;\n" +"sql pg_catalog.text;\n" +"BEGIN\n" +"SELECT COUNT(*) FROM %{identity}D WHERE %{colname}I IS NULL INTO null_cnt;\n" +"SELECT pg_catalog.min(%{colname}I) - 1 - null_cnt FROM %{identity}D INTO start_num;\n" +"sql := 'CREATE LARGE SEQUENCE %{seqname}D START WITH ' || start_num || ' MINVALUE ' || start_num;\n" +"EXECUTE sql;\n" +"UPDATE %{identity}D SET %{colname}I = pg_catalog.nextval('%{seqname}D') WHERE %{colname}I IS NULL;\n" +"DROP LARGE SEQUENCE %{seqname}D;\n" +"END;\n"; + +static ObjTree* adapt_subscription_autoincrement_null_value(Relation rel, ColumnDef *coldef, Oid typid) +{ + ObjTree *tmp_obj = NULL; + char *maxvalue = NULL; + char *seqname = NULL; + char *typname = NULL; + sequence_values *seqvalues = get_sequence_values(RelAutoIncSeqOid(rel)); + StringInfoData string_buf; + + initStringInfo(&string_buf); + appendStringInfo(&string_buf, "ddl_replication_%s", seqvalues->sequence_name); + seqname = pstrdup(string_buf.data); + + resetStringInfo(&string_buf); + + switch (typid) { + case BOOLOID: + maxvalue = pstrdup("1"); + typname = pstrdup("bool"); + break; + case INT1OID: + appendStringInfo(&string_buf, "%u", UCHAR_MAX); + maxvalue = pstrdup(string_buf.data); + typname = pstrdup("int1"); + break; + case INT2OID: + appendStringInfo(&string_buf, "%d", SHRT_MAX); + maxvalue = pstrdup(string_buf.data); + typname = pstrdup("int2"); + break; + case INT4OID: + appendStringInfo(&string_buf, "%d", INT_MAX); + maxvalue = pstrdup(string_buf.data); + typname = pstrdup("int4"); + break; + case INT8OID : + case FLOAT4OID : + case FLOAT8OID : { + char buf[MAXINT8LEN + 1]; + pg_lltoa(PG_INT64_MAX, buf); + maxvalue = pstrdup(buf); + /* just use int8 for create sequence */ + typname = pstrdup("int8"); + } + break; + case INT16OID: { + const int MAXINT16LEN = 45; + char buf[MAXINT16LEN + 1]; + pg_i128toa(PG_INT128_MAX, buf, MAXINT16LEN + 1); + maxvalue = pstrdup(buf); + typname = pstrdup("int16"); + } + break; + default : { + appendStringInfo(&string_buf, "%d", INT_MAX); + maxvalue = pstrdup(string_buf.data); + typname = pstrdup("int4"); + break; + } + } + + tmp_obj = new_objtree_VA(ADAPT_SUBSCTIPTION_AUTOINCREMENT_FMT, 4, + "seqname", ObjTypeObject, new_objtree_for_qualname(rel->rd_rel->relnamespace, seqname), + "identity", ObjTypeObject, new_objtree_for_qualname(rel->rd_rel->relnamespace, RelationGetRelationName(rel)), + "colname", ObjTypeString, coldef->colname, + "typname", ObjTypeString, typname); + + FreeStringInfo(&string_buf); + return tmp_obj; +} + +static List* deparse_AlterRelation_add_column_default(CollectedCommand *cmd) +{ + ObjTree *ret = NULL; + ObjTree *tmp_obj = NULL; + List *dpcontext; + Relation rel; + List *subcmds = NIL; + ListCell *cell; + List *exprs = NIL; + Oid relId = cmd->d.alterTable.objectId; + AlterTableStmt *stmt = NULL; + bool isonly = false; + bool isrewrite = false; + + List *tree_list = NIL; + List *not_null_list = NIL; + List *constraint_list = NIL; + + isrewrite = cmd->d.alterTable.rewrite; + + rel = relation_open(relId, AccessShareLock); + dpcontext = deparse_context_for(RelationGetRelationName(rel), + relId); + stmt = (AlterTableStmt *) cmd->parsetree; + + if (rel->rd_rel->relkind != RELKIND_RELATION || + rel->rd_rel->relpersistence != RELPERSISTENCE_PERMANENT) { + relation_close(rel, AccessShareLock); + return NIL; + } + + if (stmt->relation && stmt->relation->inhOpt == INH_NO) { + isonly = true; + } + + foreach(cell, cmd->d.alterTable.subcmds) { + CollectedATSubcmd *sub = (CollectedATSubcmd *) lfirst(cell); + AlterTableCmd *subcmd = (AlterTableCmd *) sub->parsetree; + + if (subcmd->recursing) + continue; + + switch (subcmd->subtype) { + case AT_AddColumn: + case AT_AddColumnRecurse: { + ColumnDef *coldef = (ColumnDef*)subcmd->def; + HeapTuple attrTup; + Form_pg_attribute attrForm; + Oid typid; + int32 typmod; + Oid typcollation; + + /* do nothing */ + if (coldef->generatedCol == ATTRIBUTE_GENERATED_STORED) { + break; + } + + attrTup = SearchSysCacheAttName(relId, coldef->colname); + if (!HeapTupleIsValid(attrTup)) + elog(ERROR, "could not find cache entry for column \"%s\" of relation %u", + coldef->colname, relId); + attrForm = (Form_pg_attribute) GETSTRUCT(attrTup); + if (!attrForm->atthasdef) { + ReleaseSysCache(attrTup); + break; + } + + get_atttypetypmodcoll(relId, attrForm->attnum, &typid, &typmod, &typcollation); + + /* for auto_increment, construct the modify column clause after rewrite */ + if (coldef->raw_default && IsA(coldef->raw_default, AutoIncrement)) { + if (attrForm->attnotnull) { + tmp_obj = adapt_subscription_autoincrement_null_value(rel, coldef, typid); + if (tmp_obj) { + tree_list = lappend(tree_list, tmp_obj); + } + } + + tmp_obj = new_objtree_VA("MODIFY COLUMN %{colname}I %{coltype}T AUTO_INCREMENT", 2, + "colname", ObjTypeString, coldef->colname, + "coltype", ObjTypeObject, new_objtree_for_type(typid, typmod)); + if (!coldef->is_not_null) { + append_format_string(tmp_obj, "NULL"); + } + constraint_list = lappend(constraint_list, new_object_object(tmp_obj)); + ReleaseSysCache(attrTup); + + break; + } + + if (coldef->is_not_null) { + tmp_obj = new_objtree_VA( + "ALTER TABLE %{only}s %{identity}D ALTER COLUMN %{name}I SET NOT NULL", 3, + "only", ObjTypeString, isonly ? "ONLY" : "", + "identity", ObjTypeObject, + new_objtree_for_qualname(rel->rd_rel->relnamespace, + RelationGetRelationName(rel)), + "name", ObjTypeString, coldef->colname); + not_null_list = lappend(not_null_list, tmp_obj); + } + + char *defstr = NULL; + char *initdefval = NULL; + + if (coldef->initdefval) { + StringInfoData defvalbuf; + initStringInfo(&defvalbuf); + appendStringInfo(&defvalbuf, "\'%s\'", coldef->initdefval); + initdefval = pstrdup(defvalbuf.data); + } + defstr = RelationGetColumnDefault(rel, attrForm->attnum, dpcontext, &exprs); + if (!coldef->initdefval) { + check_alter_table_replident(rel); + ObjTree *update_ret = new_objtree_VA( + "UPDATE %{identity}D SET %{name}I = %{default}s WHERE %{name}I IS NULL", 3, + "identity", ObjTypeObject, new_objtree_for_qualname(rel->rd_rel->relnamespace, + RelationGetRelationName(rel)), + "name", ObjTypeString, coldef->colname, + "default", ObjTypeString, initdefval ? initdefval : defstr); + tree_list = lappend(tree_list, update_ret); + } + + ret = new_objtree_VA( + "ALTER TABLE %{only}s %{identity}D", 2, "only", ObjTypeString, isonly ? "ONLY" : "", "identity", + ObjTypeObject, + new_objtree_for_qualname(rel->rd_rel->relnamespace, RelationGetRelationName(rel))); + tmp_obj = new_objtree_VA("ALTER COLUMN %{name}I SET DEFAULT %{default}s", 2, "name", ObjTypeString, + coldef->colname, "default", ObjTypeString, defstr); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + append_array_object(ret, "%{subcmds:, }s", subcmds); + tree_list = lappend(tree_list, ret); + + ReleaseSysCache(attrTup); + } + break; + case AT_ModifyColumn: { + /* handle auto_increment attribute */ + AttrNumber attnum; + Oid typid; + int32 typmod; + Oid typcollation; + ColumnDef *coldef = (ColumnDef *) subcmd->def; + ListCell *lc2 = NULL; + + HeapTuple attrTup; + Form_pg_attribute attrForm; + + bool saw_autoincrement = false; + bool saw_null = false; + attrTup = SearchSysCacheAttName(relId, coldef->colname); + if (!HeapTupleIsValid(attrTup)) + elog(ERROR, "could not find cache entry for column \"%s\" of relation %u", + coldef->colname, relId); + attrForm = (Form_pg_attribute) GETSTRUCT(attrTup); + if (!attrForm->atthasdef) { + ReleaseSysCache(attrTup); + break; + } + attnum = attrForm->attnum; + get_atttypetypmodcoll(RelationGetRelid(rel), attnum, &typid, &typmod, &typcollation); + + foreach(lc2, coldef->constraints) { + Constraint *constr = (Constraint *) lfirst(lc2); + + if (constr->contype == CONSTR_AUTO_INCREMENT) { + saw_autoincrement = true; + } else if (constr->contype == CONSTR_NULL) { + saw_null = true; + } + } + + if (!saw_autoincrement) { + break; + } + + if (attrForm->attnotnull) { + tmp_obj = adapt_subscription_autoincrement_null_value(rel, coldef, typid); + if (tmp_obj) + tree_list = lappend(tree_list, tmp_obj); + } + + tmp_obj = new_objtree_VA("MODIFY COLUMN %{colname}I %{coltype}T AUTO_INCREMENT", 2, + "colname", ObjTypeString, coldef->colname, + "coltype", ObjTypeObject, new_objtree_for_type(typid, typmod)); + if (saw_null) { + append_format_string(tmp_obj, "NULL"); + } + constraint_list = lappend(constraint_list, new_object_object(tmp_obj)); + ReleaseSysCache(attrTup); + } + break; + case AT_AddIndex: { + Oid idxOid = sub->address.objectId; + IndexStmt *istmt; + Relation idx; + const char *idxname; + Oid constrOid; + istmt = (IndexStmt *) subcmd->def; + if (!istmt->isconstraint || !isrewrite) + break; + + idx = relation_open(idxOid, AccessShareLock); + idxname = RelationGetRelationName(idx); + + constrOid = get_relation_constraint_oid(cmd->d.alterTable.objectId, idxname, false); + + tmp_obj = new_objtree_VA("ADD CONSTRAINT %{name}I %{definition}s", 3, + "type", ObjTypeString, "add constraint", + "name", ObjTypeString, idxname, + "definition", ObjTypeString, + pg_get_constraintdef_part_string(constrOid)); + constraint_list = lappend(constraint_list, new_object_object(tmp_obj)); + + relation_close(idx, AccessShareLock); + } + break; + default: + break; + } + } + + if (not_null_list) { + tree_list = list_concat(tree_list, not_null_list); + } + + if (constraint_list) { + tmp_obj = new_objtree_VA("ALTER TABLE %{only}s %{identity}D", 2, + "only", ObjTypeString, isonly ? "ONLY" : "", + "identity", ObjTypeObject, + new_objtree_for_qualname(rel->rd_rel->relnamespace, + RelationGetRelationName(rel))); + append_array_object(tmp_obj, "%{subcmds:, }s", constraint_list); + tree_list = lappend(tree_list, tmp_obj); + } + + relation_close(rel, AccessShareLock); + return tree_list; +} + +List* deparse_altertable_end(CollectedCommand *cmd) +{ + OverrideSearchPath *overridePath; + MemoryContext oldcxt; + MemoryContext tmpcxt; + ObjTree *tree; + + List *command_list = NIL; + List *tree_list = NIL; + List *res = NIL; + StringInfoData str; + + if (cmd->type != SCT_AlterTable || !IsA(cmd->parsetree, AlterTableStmt)) { + return NIL; + } + + initStringInfo(&str); + tmpcxt = AllocSetContextCreate(CurrentMemoryContext, + "deparse ctx", + ALLOCSET_DEFAULT_MINSIZE, + ALLOCSET_DEFAULT_INITSIZE, + ALLOCSET_DEFAULT_MAXSIZE); + oldcxt = MemoryContextSwitchTo(tmpcxt); + overridePath = GetOverrideSearchPath(CurrentMemoryContext); + overridePath->schemas = NIL; + overridePath->addCatalog = false; + overridePath->addTemp = true; + PushOverrideSearchPath(overridePath); + + tree_list = deparse_AlterRelation_add_column_default(cmd); + ListCell* lc = NULL; + foreach(lc, tree_list) { + tree = (ObjTree*)lfirst(lc); + Jsonb *jsonb; + char *command = NULL; + jsonb = objtree_to_jsonb(tree, NULL); + command = JsonbToCString(&str, VARDATA(jsonb), JSONB_ESTIMATED_LEN); + + command_list = lappend(command_list, MemoryContextStrdup(oldcxt, command)); + resetStringInfo(&str); + } + + PopOverrideSearchPath(); + + MemoryContextSwitchTo(oldcxt); + res = list_copy(command_list); + MemoryContextDelete(tmpcxt); + + return res; +} + + /* * Handle deparsing of DROP commands. * * Verbose syntax * DROP %s IF EXISTS %%{objidentity}s %{cascade}s */ -char * -deparse_drop_command(const char *objidentity, const char *objecttype, - Node *parsetree) +char* deparse_drop_command(const char *objidentity, const char *objecttype, + Node *parsetree) { DropStmt *node = (DropStmt*)parsetree; StringInfoData str; @@ -2347,13 +3382,239 @@ deparse_drop_command(const char *objidentity, const char *objecttype, return command; } +/* + * Deparse a CreateEnumStmt (CREATE TYPE AS ENUM) + * + * Given a Enum type OID and the parse tree that created it, return an ObjTree + * representing the creation command. + * + * Verbose syntax + * CREATE TYPE %{identity}D AS ENUM (%{values:, }L) + */ +static ObjTree* deparse_CreateEnumStmt(Oid objectId, Node *parsetree) +{ + CreateEnumStmt *node = (CreateEnumStmt *) parsetree; + List *values = NIL; + ListCell *cell; + + foreach(cell, node->vals) { + Value *val = (Value*)lfirst(cell); + values = lappend(values, new_string_object(strVal(val))); + } + + return new_objtree_VA("CREATE TYPE %{identity}D AS ENUM (%{values:, }L)", 2, + "identity", ObjTypeObject, + new_objtree_for_qualname_id(TypeRelationId, objectId), + "values", ObjTypeArray, values); +} + +/* + * Deparse an AlterObjectSchemaStmt (ALTER ... SET SCHEMA command) + * + * Given the object address and the parse tree that created it, return an + * ObjTree representing the alter command. + * + * Verbose syntax + * ALTER %s %{identity}s SET SCHEMA %{newschema}I + */ +static ObjTree* deparse_AlterObjectSchemaStmt(ObjectAddress address, Node *parsetree, + ObjectAddress old_schema) +{ + AlterObjectSchemaStmt *node = (AlterObjectSchemaStmt *) parsetree; + char *identity; + char *new_schema = node->newschema; + char *old_schname; + char *ident; + + /* + * Since the command has already taken place from the point of view of + * catalogs, getObjectIdentity returns the object name with the already + * changed schema. The output of our deparsing must return the original + * schema name, however, so we chop the schema name off the identity + * string and then prepend the quoted schema name. + * + * XXX This is pretty clunky. Can we do better? + */ + identity = getObjectIdentity(&address); + old_schname = get_namespace_name(old_schema.objectId); + if (!old_schname) + elog(ERROR, "cache lookup failed for schema with OID %u", + old_schema.objectId); + + ident = psprintf("%s%s", quote_identifier(old_schname), + identity + strlen(quote_identifier(new_schema))); + + return new_objtree_VA("ALTER %{objtype}s %{identity}s SET SCHEMA %{newschema}I", 3, + "objtype", ObjTypeString, + string_objtype(node->objectType, false), + "identity", ObjTypeString, ident, + "newschema", ObjTypeString, new_schema); +} + + +static ObjTree* deparse_CreateEventStmt(Oid objectId, Node *parsetree) +{ + ObjTree *ret; + ObjTree *tmp_obj; + CreateEventStmt *stmt = (CreateEventStmt *) parsetree; + StringInfoData string_buf; + initStringInfo(&string_buf); + + char *ev_status = NULL; + if (stmt->def_name) { + appendStringInfo(&string_buf, "DEFINER = %s", stmt->def_name); + } + + if (stmt->event_status == EVENT_DISABLE) { + ev_status = pstrdup("DISABLE"); + } else if (stmt->event_status == EVENT_DISABLE_ON_SLAVE) { + ev_status = pstrdup("DISABLE ON SLAVE"); + } + + char *event_name_str = stmt->event_name->relname; + char *schema_name_str = stmt->event_name->schemaname; + + if (stmt->interval_time) { + ret = new_objtree_VA( + "CREATE %{definer_opt}s EVENT %{if_not_exits}s %{schema}s.%{eventname}s " + "ON SCHEDULE EVERY %{every_interval}s STARTS '%{start_expr}s'", 6, + "definer_opt", ObjTypeString, stmt->def_name ? pstrdup(string_buf.data) : "", + "if_not_exits", ObjTypeString, stmt->if_not_exists ? "IF NOT EXISTS" : "", + "schema", ObjTypeString, schema_name_str, + "eventname", ObjTypeString, event_name_str, + "every_interval", ObjTypeString, parseIntervalExprString(stmt->interval_time), + "start_expr", ObjTypeString, parseTimeExprString(stmt->start_time_expr)); + } else { + ret = new_objtree_VA( + "CREATE %{definer_opt}s EVENT %{if_not_exits}s %{schema}s.%{eventname}s " + "ON SCHEDULE STARTS '%{start_expr}s'", 5, + "definer_opt", ObjTypeString, stmt->def_name ? pstrdup(string_buf.data) : "", + "if_not_exits", ObjTypeString, stmt->if_not_exists ? "IF NOT EXISTS" : "", + "schema", ObjTypeString, schema_name_str, + "eventname", ObjTypeString, event_name_str, + "start_expr", ObjTypeString, parseTimeExprString(stmt->start_time_expr)); + } + if (stmt->end_time_expr) { + append_string_object(ret, "ENDS '%{end_expr}s'", + "end_expr", parseTimeExprString(stmt->end_time_expr)); + } + + tmp_obj = new_objtree_VA("%{opt_ev_on_completion}s %{opt_ev_status}s COMMENT '%{comment_opt}s' DO %{ev_body}s", 4, + "opt_ev_on_completion", ObjTypeString, + stmt->complete_preserve ? "ON COMPLETION NOT PRESERVE" : "ON COMPLETION PRESERVE", + "opt_ev_status", ObjTypeString, ev_status ? ev_status : "", + "comment_opt", ObjTypeString, stmt->event_comment_str ? stmt->event_comment_str : "", + "ev_body", ObjTypeString, stmt->event_query_str); + + append_object_object(ret, "%{event_body}s", tmp_obj); + + FreeStringInfo(&string_buf); + return ret; +} + +static ObjTree* deparse_AlterEventStmt(Oid objectId, Node *parsetree) +{ + ObjTree *ret; + AlterEventStmt *stmt = (AlterEventStmt *) parsetree; + StringInfoData string_buf; + initStringInfo(&string_buf); + + char *event_name_str = stmt->event_name->relname; + char *schema_name_str = stmt->event_name->schemaname; + + if (stmt->def_name) { + Value *definerVal = (Value *)stmt->def_name->arg; + appendStringInfo(&string_buf, "DEFINER = %s", strVal(definerVal)); + } + + ret = new_objtree_VA("ALTER %{definer_opt}s EVENT %{schema}s.%{eventname}s ", 3, + "definer_opt", ObjTypeString, stmt->def_name ? pstrdup(string_buf.data) : "", + "schema", ObjTypeString, schema_name_str, + "eventname", ObjTypeString, event_name_str); + + if (stmt->interval_time || stmt->start_time_expr || stmt->end_time_expr) { + append_format_string(ret, "ON SCHEDULE "); + if (stmt->interval_time && stmt->interval_time->arg) { + append_string_object(ret, "EVERY %{every_interval}s ", + "every_interval", parseIntervalExprString(stmt->interval_time->arg)); + } + if (stmt->start_time_expr && stmt->start_time_expr->arg) { + if (stmt->interval_time && stmt->interval_time->arg) { + append_string_object(ret, "STARTS '%{start_expr}s' ", + "start_expr", parseTimeExprString(stmt->start_time_expr->arg)); + } else { + append_string_object(ret, "AT '%{start_expr}s' ", + "start_expr", parseTimeExprString(stmt->start_time_expr->arg)); + } + } + if (stmt->end_time_expr && stmt->end_time_expr->arg) { + append_string_object(ret, "ENDS '%{end_expr}s' ", + "end_expr", parseTimeExprString(stmt->end_time_expr->arg)); + } + } + + /* preserve_opt rename_opt status_opt comments_opt action_opt */ + if (stmt->complete_preserve && stmt->complete_preserve->arg) { + Value *arg = (Value *)stmt->complete_preserve->arg; + if (!intVal(arg)) { + append_format_string(ret, "ON COMPLETION PRESERVE "); + } else { + append_format_string(ret, "ON COMPLETION NOT PRESERVE "); + } + } + + if (stmt->new_name && stmt->new_name->arg) { + Value *arg = (Value *)stmt->new_name->arg; + append_string_object(ret, "RENAME TO %{new_name}s ", + "new_name", strVal(arg)); + } + + if (stmt->event_status && stmt->event_status->arg) { + Value *arg = (Value *)stmt->event_status->arg; + EventStatus ev_status = (EventStatus)intVal(arg); + if (ev_status == EVENT_ENABLE) { + append_format_string(ret, "ENABLE "); + } else if (ev_status == EVENT_DISABLE) { + append_format_string(ret, "DISABLE "); + } else if (ev_status == EVENT_DISABLE_ON_SLAVE) { + append_format_string(ret, "DISABLE ON SLAVE "); + } + } + if (stmt->event_comment_str && stmt->event_comment_str->arg) { + Value *arg = (Value *)stmt->event_comment_str->arg; + append_string_object(ret, "COMMENT '%{comment}s' ", + "comment", strVal(arg)); + } + if (stmt->event_query_str && stmt->event_query_str) { + Value *arg = (Value *)stmt->event_query_str->arg; + append_string_object(ret, "DO %{action}s ", + "action", strVal(arg)); + } + + return ret; +} + +static ObjTree* deparse_DropEventStmt(Oid objectId, Node *parsetree) +{ + ObjTree *ret; + DropEventStmt *stmt = (DropEventStmt *) parsetree; + char *event_name_str = stmt->event_name->relname; + char *schema_name_str = stmt->event_name->schemaname; + + ret = new_objtree_VA("DROP EVENT %{if_exists}s %{schema}s.%{eventname}s", 3, + "if_exists", ObjTypeString, stmt->missing_ok ? "IF EXISTS" : "", + "schema", ObjTypeString, schema_name_str, + "eventname", ObjTypeString, event_name_str); + + return ret; +} + /* * Handle deparsing of simple commands. * * This function should cover all cases handled in ProcessUtilitySlow. */ -static ObjTree * -deparse_simple_command(CollectedCommand *cmd, bool *include_owner) +static ObjTree* deparse_simple_command(CollectedCommand *cmd, bool *include_owner) { Oid objectId; Node *parsetree; @@ -2368,15 +3629,17 @@ deparse_simple_command(CollectedCommand *cmd, bool *include_owner) /* This switch needs to handle everything that ProcessUtilitySlow does */ switch (nodeTag(parsetree)) { - case T_CreateStmt: - return deparse_CreateStmt(objectId, parsetree); - - case T_IndexStmt: - return deparse_IndexStmt(objectId, parsetree); - - case T_CreateSeqStmt: - return deparse_CreateSeqStmt(objectId, parsetree); - + case T_AlterFunctionStmt: + *include_owner = false; + return deparse_AlterFunction(objectId, parsetree); + case T_AlterObjectSchemaStmt: + *include_owner = false; + return deparse_AlterObjectSchemaStmt(cmd->d.simple.address, + parsetree, + cmd->d.simple.secondaryObject); + case T_AlterSchemaStmt: + *include_owner = false; + return deparse_AlterSchemaStmt(objectId, parsetree); case T_AlterSeqStmt: *include_owner = false; return deparse_AlterSeqStmt(objectId, parsetree); @@ -2385,7 +3648,43 @@ deparse_simple_command(CollectedCommand *cmd, bool *include_owner) *include_owner = false; return deparse_CommentStmt(cmd->d.simple.address, parsetree); + case T_CompositeTypeStmt: + return deparse_CompositeTypeStmt(objectId, parsetree); + + case T_CreateEnumStmt: /* CREATE TYPE AS ENUM */ + return deparse_CreateEnumStmt(objectId, parsetree); + + case T_CreateFunctionStmt: + return deparse_CreateFunction(objectId, parsetree); + + case T_CreateSchemaStmt: + return deparse_CreateSchemaStmt(objectId, parsetree); + + case T_CreateSeqStmt: + return deparse_CreateSeqStmt(objectId, parsetree); + case T_CreateStmt: + return deparse_CreateStmt(objectId, parsetree); + case T_CreateTrigStmt: + return deparse_CreateTrigStmt(objectId, parsetree); + + case T_IndexStmt: + return deparse_IndexStmt(objectId, parsetree); + case T_RenameStmt: + *include_owner = false; + return deparse_RenameStmt(cmd->d.simple.address, parsetree); + case T_ViewStmt: + return deparse_ViewStmt(objectId, parsetree); + case T_CreateEventStmt: + return deparse_CreateEventStmt(objectId, parsetree); + case T_AlterEventStmt: + return deparse_AlterEventStmt(objectId, parsetree); + case T_DropEventStmt: + return deparse_DropEventStmt(objectId, parsetree); default: + if (u_sess->hook_cxt.deparseCollectedCommandHook != NULL) { + return (ObjTree*)((deparseCollectedCommand)(u_sess->hook_cxt.deparseCollectedCommandHook)) + (DEPARSE_SIMPLE_COMMAND, cmd, NULL, NULL); + } elog(INFO, "unrecognized node type in deparse command: %d", (int) nodeTag(parsetree)); } @@ -2393,11 +3692,1366 @@ deparse_simple_command(CollectedCommand *cmd, bool *include_owner) return NULL; } + +/* + * ... ALTER COLUMN ... SET/RESET (...) + * + * Verbose syntax + * ALTER COLUMN %{column}I RESET|SET (%{options:, }s) + */ +static ObjTree* deparse_ColumnSetOptions(AlterTableCmd *subcmd) +{ + List *sets = NIL; + ListCell *cell; + ObjTree *ret; + bool is_reset = subcmd->subtype == AT_ResetOptions; + + ret = new_objtree_VA("ALTER COLUMN %{column}I %{option}s", 2, + "column", ObjTypeString, subcmd->name, + "option", ObjTypeString, is_reset ? "RESET" : "SET"); + + foreach(cell, (List *) subcmd->def) { + DefElem *elem; + ObjTree *set; + + elem = (DefElem *) lfirst(cell); + set = deparse_DefElem(elem, is_reset); + sets = lappend(sets, new_object_object(set)); + } + + Assert(sets); + append_array_object(ret, "(%{options:, }s)", sets); + + return ret; +} + +/* + * ... ALTER COLUMN ... SET/RESET (...) + * + * Verbose syntax + * RESET|SET (%{options:, }s) + */ +static ObjTree* deparse_RelSetOptions(AlterTableCmd *subcmd) +{ + List *sets = NIL; + ListCell *cell; + bool is_reset = subcmd->subtype == AT_ResetRelOptions; + + foreach(cell, (List *) subcmd->def) { + DefElem *elem; + ObjTree *set; + + elem = (DefElem *) lfirst(cell); + set = deparse_DefElem(elem, is_reset); + sets = lappend(sets, new_object_object(set)); + } + + Assert(sets); + + return new_objtree_VA("%{set_reset}s (%{options:, }s)", 2, + "set_reset", ObjTypeString, is_reset ? "RESET" : "SET", + "options", ObjTypeArray, sets); +} + +/* + * Deparse all the collected subcommands and return an ObjTree representing the + * alter command. + * + * Verbose syntax + * ALTER reltype %{only}s %{identity}D %{subcmds:, }s + */ +static ObjTree* deparse_AlterRelation(CollectedCommand *cmd, ddl_deparse_context *context) +{ + ObjTree *ret; + ObjTree *tmp_obj = NULL; + ObjTree *tmp_obj2; + List *dpcontext; + Relation rel; + List *subcmds = NIL; + ListCell *cell; + const char *reltype = NULL; + bool istype = false; + bool istable = false; + bool isrewrite = false; + List *exprs = NIL; + Oid relId = cmd->d.alterTable.objectId; + AlterTableStmt *stmt = NULL; + bool isonly = false; + ObjTree *loc_obj; + + Assert(cmd->type == SCT_AlterTable); + + stmt = (AlterTableStmt *) cmd->parsetree; + if (stmt && !IsA(stmt, AlterTableStmt)) { + return NULL; + } + + isrewrite = cmd->d.alterTable.rewrite; + + /* + * ALTER TABLE subcommands generated for TableLikeClause is processed in + * the top level CREATE TABLE command; return empty here. + */ + rel = relation_open(relId, AccessShareLock); + dpcontext = deparse_context_for(RelationGetRelationName(rel), + relId); + + switch (rel->rd_rel->relkind) { + case RELKIND_RELATION: + reltype = "TABLE"; + istable = true; + if (stmt->relation->inhOpt == INH_NO) { + isonly = true; + } + break; + case RELKIND_INDEX: + case RELKIND_GLOBAL_INDEX: + reltype = "INDEX"; + break; + case RELKIND_VIEW: + reltype = "VIEW"; + break; + case RELKIND_COMPOSITE_TYPE: + reltype = "TYPE"; + istype = true; + break; + case RELKIND_FOREIGN_TABLE: + reltype = "FOREIGN TABLE"; + break; + case RELKIND_MATVIEW: + reltype = "MATERIALIZED VIEW"; + break; + + case RELKIND_SEQUENCE: + reltype = "SEQUENCE"; + break; + case RELKIND_LARGE_SEQUENCE: + reltype = "LARGE SEQUENCE"; + break; + default: + elog(ERROR, "unexpected relkind %d", rel->rd_rel->relkind); + } + + ret = new_objtree_VA("ALTER %{objtype}s %{only}s %{identity}D", 3, + "objtype", ObjTypeString, reltype, + "only", ObjTypeString, isonly ? "ONLY" : "", + "identity", ObjTypeObject, + new_objtree_for_qualname(rel->rd_rel->relnamespace, + RelationGetRelationName(rel))); + + foreach(cell, cmd->d.alterTable.subcmds) { + CollectedATSubcmd *sub = (CollectedATSubcmd *) lfirst(cell); + AlterTableCmd *subcmd = (AlterTableCmd *) sub->parsetree; + ObjTree *tree; + + Assert(IsA(subcmd, AlterTableCmd)); + + /* + * Skip deparse of the subcommand if the objectId doesn't match the + * target relation ID. It can happen for inherited tables when + * subcommands for inherited tables and the parent table are both + * collected in the ALTER TABLE command for the parent table. With the + * exception of the internally generated AddConstraint (for + * ALTER TABLE ADD CONSTRAINT FOREIGN KEY REFERENCES) where the + * objectIds could mismatch (forein table id and the referenced table + * id). + */ + if (subcmd->recursing) + continue; + + switch (subcmd->subtype) { + case AT_AddColumn: + case AT_AddColumnRecurse: + /* XXX need to set the "recurse" bit somewhere? */ + Assert(IsA(subcmd->def, ColumnDef)); + + if (istype && subcmd->subtype == AT_AddColumnRecurse) { + /* maybe is recurse subcmd for alter type command */ + break; + } + + tree = deparse_ColumnDef(rel, dpcontext, false, + (ColumnDef *) subcmd->def, true, &exprs); + mark_function_volatile(context, (Node*)exprs); + tmp_obj = new_objtree_VA("ADD %{objtype}s %{if_not_exists}s %{definition}s %{cascade}s", 5, + "objtype", ObjTypeString, + istype ? "ATTRIBUTE" : "COLUMN", + "type", ObjTypeString, "add column", + "if_not_exists", ObjTypeString, + subcmd->missing_ok ? "IF NOT EXISTS" : "", + "definition", ObjTypeObject, tree, + "cascade", ObjTypeString, subcmd->behavior == DROP_CASCADE ? "CASCADE" : ""); + + if (subcmd->is_first) { + loc_obj = new_objtree("FIRST"); + append_object_object(tmp_obj, "%{add_first}s", loc_obj); + } else if (subcmd->after_name) { + loc_obj = new_objtree_VA("AFTER %{name}I", 1, "name", ObjTypeString, subcmd->after_name); + append_object_object(tmp_obj, "%{add_after_name}s", loc_obj); + } + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + + break; + case AT_AddIndex: { + Oid idxOid = sub->address.objectId; + IndexStmt *istmt; + Relation idx; + const char *idxname; + Oid constrOid; + + Assert(IsA(subcmd->def, IndexStmt)); + istmt = (IndexStmt *) subcmd->def; + + if (!istmt->isconstraint) + break; + + if (isrewrite) + break; + + idx = relation_open(idxOid, AccessShareLock); + idxname = RelationGetRelationName(idx); + + constrOid = get_relation_constraint_oid(cmd->d.alterTable.objectId, idxname, false); + + tmp_obj = new_objtree_VA("ADD CONSTRAINT %{name}I %{definition}s", 3, + "type", ObjTypeString, "add constraint", + "name", ObjTypeString, idxname, + "definition", ObjTypeString, + pg_get_constraintdef_part_string(constrOid)); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + + relation_close(idx, AccessShareLock); + } + break; + case AT_AddIndexConstraint: { + IndexStmt *istmt; + Relation idx; + Oid constrOid = sub->address.objectId; + char *indexname = NULL; + ListCell *lcell; + Assert(IsA(subcmd->def, IndexStmt)); + istmt = (IndexStmt *) subcmd->def; + + Assert(istmt->isconstraint && istmt->unique); + + idx = relation_open(istmt->indexOid, AccessShareLock); + + foreach (lcell, istmt->options) { + DefElem* def = (DefElem*)lfirst(lcell); + if (pg_strcasecmp(def->defname, "origin_indexname") == 0) { + indexname = defGetString(def); + break; + } + } + + /* + * Verbose syntax + * + * ADD CONSTRAINT %{name}I %{constraint_type}s USING INDEX + * %index_name}I %{deferrable}s %{init_deferred}s + */ + tmp_obj = new_objtree_VA( + "ADD CONSTRAINT %{name}I %{constraint_type}s " + "USING INDEX %{index_name}I %{deferrable}s %{init_deferred}s", 6, + "type", ObjTypeString, "add constraint using index", + "name", ObjTypeString, get_constraint_name(constrOid), + "constraint_type", ObjTypeString, + istmt->primary ? "PRIMARY KEY" : "UNIQUE", + "index_name", ObjTypeString, + indexname ? indexname : RelationGetRelationName(idx), + "deferrable", ObjTypeString, + istmt->deferrable ? "DEFERRABLE" : "NOT DEFERRABLE", + "init_deferred", ObjTypeString, + istmt->initdeferred ? "INITIALLY DEFERRED" : "INITIALLY IMMEDIATE"); + + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + + relation_close(idx, AccessShareLock); + } + break; + + case AT_ReAddIndex: + case AT_ReAddConstraint: + case AT_ReplaceRelOptions: + /* Subtypes used for internal operations; nothing to do here */ + break; + + case AT_AddColumnToView: + /* CREATE OR REPLACE VIEW -- nothing to do here */ + break; + + case AT_ColumnDefault: + if (subcmd->def == NULL) { + tmp_obj = new_objtree_VA("ALTER COLUMN %{column}I DROP DEFAULT", 2, + "type", ObjTypeString, "drop default", + "column", ObjTypeString, subcmd->name); + } else { + List *dpcontext_rel; + HeapTuple attrtup; + AttrNumber attno; + + tmp_obj = new_objtree_VA("ALTER COLUMN %{column}I SET DEFAULT", 2, + "type", ObjTypeString, "set default", + "column", ObjTypeString, subcmd->name); + + dpcontext_rel = deparse_context_for(RelationGetRelationName(rel), + RelationGetRelid(rel)); + attrtup = SearchSysCacheAttName(RelationGetRelid(rel), subcmd->name); + attno = ((Form_pg_attribute) GETSTRUCT(attrtup))->attnum; + append_string_object(tmp_obj, "%{definition}s", "definition", + RelationGetColumnDefault(rel, attno, + dpcontext_rel, + NULL)); + ReleaseSysCache(attrtup); + } + + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + + case AT_DropNotNull: + tmp_obj = new_objtree_VA("ALTER COLUMN %{column}I DROP NOT NULL", 2, + "type", ObjTypeString, "drop not null", + "column", ObjTypeString, subcmd->name); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + + case AT_SetNotNull: + tmp_obj = new_objtree_VA("ALTER COLUMN %{column}I SET NOT NULL", 2, + "type", ObjTypeString, "set not null", + "column", ObjTypeString, subcmd->name); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + + case AT_SetStatistics: { + Assert(IsA(subcmd->def, Integer)); + if (subcmd->additional_property) { + tmp_obj = new_objtree_VA("ALTER COLUMN %{column}I SET STATISTICS %{statistics}n", 3, + "type", ObjTypeString, "set statistics", + "column", ObjTypeString, subcmd->name, + "statistics", ObjTypeInteger, + intVal((Value *)subcmd->def)); + } else { + tmp_obj = new_objtree_VA("ALTER COLUMN %{column}n SET STATISTICS PERCENT %{statistics}n", 4, + "type", ObjTypeString, "set statistics", + "column", ObjTypeString, subcmd->name, + "statistics", ObjTypeInteger, + intVal((Value *)subcmd->def)); + } + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + } + break; + case AT_SetOptions: + case AT_ResetOptions: + subcmds = lappend(subcmds, new_object_object(deparse_ColumnSetOptions(subcmd))); + break; + + case AT_SetStorage: + Assert(IsA(subcmd->def, String)); + tmp_obj = new_objtree_VA("ALTER COLUMN %{column}I SET STORAGE %{storage}s", 3, + "type", ObjTypeString, "set storage", + "column", ObjTypeString, subcmd->name, + "storage", ObjTypeString, + strVal((Value *)subcmd->def)); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + + case AT_SET_COMPRESS: + tmp_obj = new_objtree_VA("SET %{compression}s", 2, + "type", ObjTypeString, "set compression", + "compression", ObjTypeString, subcmd->name); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + case AT_EnableRowMoveMent: + tmp_obj = new_objtree_VA("ENABLE ROW MOVEMENT", 1, + "type", ObjTypeString, "enable row movement"); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + case AT_DisableRowMoveMent: + tmp_obj = new_objtree_VA("DISABLE ROW MOVEMENT", 1, + "type", ObjTypeString, "disable row movement"); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + case AT_SetAutoIncrement: + tmp_obj = new_objtree_VA("AUTO_INCREMENT", 1, + "type", ObjTypeString, "auto_increment"); + if (subcmd->def && IsA(subcmd->def, Integer)) { + append_int_object(tmp_obj, "%{autoincstart}n", (int32)intVal(subcmd->def)); + } else { + append_string_object(tmp_obj, "%{autoincstart}s", "autoincstart", strVal(subcmd->def)); + } + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + case AT_COMMENTS: + tmp_obj = new_objtree_VA("COMMENT=%{comment}L", 2, + "type", ObjTypeString, "comment", + "comment", ObjTypeString, subcmd->name); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + case AT_DropColumn: + case AT_DropColumnRecurse: + if (istype && subcmd->subtype == AT_DropColumnRecurse) { + /* maybe is recurse subcmd for alter type command */ + break; + } + tmp_obj = new_objtree_VA("DROP %{objtype}s %{if_exists}s %{column}I", 4, + "objtype", ObjTypeString, + istype ? "ATTRIBUTE" : "COLUMN", + "type", ObjTypeString, "drop column", + "if_exists", ObjTypeString, + subcmd->missing_ok ? "IF EXISTS" : "", + "column", ObjTypeString, subcmd->name); + tmp_obj2 = new_objtree_VA("CASCADE", 1, + "present", ObjTypeBool, subcmd->behavior); + append_object_object(tmp_obj, "%{cascade}s", tmp_obj2); + + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + + case AT_AddConstraint: + case AT_AddConstraintRecurse: { + /* XXX need to set the "recurse" bit somewhere? */ + Oid constrOid = sub->address.objectId; + bool isnull; + HeapTuple tup; + Datum val; + Constraint *constr; + + /* Skip adding constraint for inherits table sub command */ + if (!constrOid) + continue; + + Assert(IsA(subcmd->def, Constraint)); + constr = castNode(Constraint, subcmd->def); + if (!constr->skip_validation) { + tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constrOid)); + if (HeapTupleIsValid(tup)) { + char *conbin; + + /* Fetch constraint expression in parsetree form */ + val = SysCacheGetAttr(CONSTROID, tup, + Anum_pg_constraint_conbin, &isnull); + + if (!isnull) { + conbin = TextDatumGetCString(val); + exprs = lappend(exprs, stringToNode(conbin)); + mark_function_volatile(context, (Node *)exprs); + } + + ReleaseSysCache(tup); + } + } + + tmp_obj = new_objtree_VA("ADD CONSTRAINT %{name}I %{definition}s", 3, + "type", ObjTypeString, "add constraint", + "name", ObjTypeString, get_constraint_name(constrOid), + "definition", ObjTypeString, + pg_get_constraintdef_part_string(constrOid)); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + } + break; + + case AT_ValidateConstraint: + case AT_ValidateConstraintRecurse: + tmp_obj = new_objtree_VA("VALIDATE CONSTRAINT %{constraint}I", 2, + "type", ObjTypeString, "validate constraint", + "constraint", ObjTypeString, subcmd->name); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + + case AT_DropConstraint: + case AT_DropConstraintRecurse: + if (subcmd->name == NULL && u_sess->attr.attr_sql.dolphin) { + tmp_obj = new_objtree_VA("DROP PRIMARY KEY", 1, + "type", ObjTypeString, "drop primary key"); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + } else { + tmp_obj = new_objtree_VA("DROP CONSTRAINT %{if_exists}s %{constraint}I %{cascade}s", 4, + "type", ObjTypeString, "drop constraint", + "if_exists", ObjTypeString, + subcmd->missing_ok ? "IF EXISTS" : "", + "constraint", ObjTypeString, subcmd->name, + "cascade", ObjTypeString, + subcmd->behavior == DROP_CASCADE ? "CASCADE" : ""); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + } + break; + + case AT_AlterColumnType: { + Form_pg_attribute att; + ColumnDef *def; + HeapTuple heapTup; + int attnum = 0; + if (istype && (relId != sub->address.objectId)) { + /* recurse to cascade table for alter type */ + break; + } + /* attrnum may be change by modify */ + heapTup = SearchSysCacheCopyAttName(RelationGetRelid(rel), subcmd->name); + if (!HeapTupleIsValid(heapTup)) /* shouldn't happen */ + ereport(ERROR, + (errmsg("column \"%s\" of relation \"%s\" does not exist", + subcmd->name, RelationGetRelationName(rel)))); + att = (Form_pg_attribute) GETSTRUCT(heapTup); + attnum = att->attnum; + + def = (ColumnDef *) subcmd->def; + Assert(IsA(def, ColumnDef)); + + /* + * Verbose syntax + * + * Composite types: ALTER reltype %{column}I SET DATA TYPE + * %{datatype}T %{collation}s ATTRIBUTE %{cascade}s + * + * Normal types: ALTER reltype %{column}I SET DATA TYPE + * %{datatype}T %{collation}s COLUMN %{using}s + */ + tmp_obj = new_objtree_VA("ALTER %{objtype}s %{column}I SET DATA TYPE %{datatype}T", 4, + "objtype", ObjTypeString, + istype ? "ATTRIBUTE" : "COLUMN", + "type", ObjTypeString, "alter column type", + "column", ObjTypeString, subcmd->name, + "datatype", ObjTypeObject, + new_objtree_for_type(att->atttypid, + att->atttypmod)); + + /* Add a COLLATE clause, if needed */ + tmp_obj2 = new_objtree("COLLATE"); + if (OidIsValid(att->attcollation)) { + ObjTree *collname; + + collname = new_objtree_for_qualname_id(CollationRelationId, + att->attcollation); + append_object_object(tmp_obj2, "%{name}D", collname); + } else { + append_not_present(tmp_obj2, "%{name}D"); + } + append_object_object(tmp_obj, "%{collation}s", tmp_obj2); + + /* If not a composite type, add the USING clause */ + if (!istype) { + /* + * If there's a USING clause, transformAlterTableStmt + * ran it through transformExpr and stored the + * resulting node in cooked_default, which we can use + * here. + */ + tmp_obj2 = new_objtree("USING"); + if (def->raw_default && sub->usingexpr) { + mark_function_volatile(context, def->cooked_default); + + if (contain_mutable_functions(def->cooked_default)) { + /* + * allow using modify the idntity value only if + * the value is stable, or need to use replident identity + * attr dml change to output change. + */ + check_alter_table_rewrite_replident_change(rel, attnum, "ALTER TYPE USING"); + } + append_string_object(tmp_obj2, "%{expression}s", + "expression", + sub->usingexpr); + } else { + append_not_present(tmp_obj2, "%{expression}s"); + } + + append_object_object(tmp_obj, "%{using}s", tmp_obj2); + } + + /* If it's a composite type, add the CASCADE clause */ + if (istype) { + tmp_obj2 = new_objtree("CASCADE"); + if (subcmd->behavior != DROP_CASCADE) + append_not_present(tmp_obj2, NULL); + append_object_object(tmp_obj, "%{cascade}s", tmp_obj2); + } + + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + } + break; + +#ifdef TODOLIST + case AT_AlterColumnGenericOptions: + tmp_obj = deparse_FdwOptions((List *) subcmd->def, + subcmd->name); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; +#endif + case AT_ChangeOwner: + tmp_obj = new_objtree_VA("OWNER TO %{owner}I", 2, + "type", ObjTypeString, "change owner", + "owner", ObjTypeString, + "subcmd->newowner"); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + + case AT_ClusterOn: + tmp_obj = new_objtree_VA("CLUSTER ON %{index}I", 2, + "type", ObjTypeString, "cluster on", + "index", ObjTypeString, subcmd->name); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + + case AT_DropCluster: + tmp_obj = new_objtree_VA("SET WITHOUT CLUSTER", 1, + "type", ObjTypeString, "set without cluster"); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + + case AT_DropOids: + tmp_obj = new_objtree_VA("SET WITHOUT OIDS", 1, + "type", ObjTypeString, "set without oids"); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + + case AT_SetTableSpace: + tmp_obj = new_objtree_VA("SET TABLESPACE %{tablespace}I", 2, + "type", ObjTypeString, "set tablespace", + "tablespace", ObjTypeString, subcmd->name); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + + case AT_SetRelOptions: + case AT_ResetRelOptions: + subcmds = lappend(subcmds, new_object_object(deparse_RelSetOptions(subcmd))); + break; + + case AT_EnableTrig: + tmp_obj = new_objtree_VA("ENABLE TRIGGER %{trigger}I", 2, + "type", ObjTypeString, "enable trigger", + "trigger", ObjTypeString, subcmd->name); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + + case AT_EnableAlwaysTrig: + tmp_obj = new_objtree_VA("ENABLE ALWAYS TRIGGER %{trigger}I", 2, + "type", ObjTypeString, "enable always trigger", + "trigger", ObjTypeString, subcmd->name); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + + case AT_EnableReplicaTrig: + tmp_obj = new_objtree_VA("ENABLE REPLICA TRIGGER %{trigger}I", 2, + "type", ObjTypeString, "enable replica trigger", + "trigger", ObjTypeString, subcmd->name); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + + case AT_DisableTrig: + tmp_obj = new_objtree_VA("DISABLE TRIGGER %{trigger}I", 2, + "type", ObjTypeString, "disable trigger", + "trigger", ObjTypeString, subcmd->name); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + + case AT_EnableTrigAll: + tmp_obj = new_objtree_VA("ENABLE TRIGGER ALL", 1, + "type", ObjTypeString, "enable trigger all"); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + + case AT_DisableTrigAll: + tmp_obj = new_objtree_VA("DISABLE TRIGGER ALL", 1, + "type", ObjTypeString, "disable trigger all"); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + + case AT_EnableTrigUser: + tmp_obj = new_objtree_VA("ENABLE TRIGGER USER", 1, + "type", ObjTypeString, "enable trigger user"); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + + case AT_DisableTrigUser: + tmp_obj = new_objtree_VA("DISABLE TRIGGER USER", 1, + "type", ObjTypeString, "disable trigger user"); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + + case AT_EnableRule: + tmp_obj = new_objtree_VA("ENABLE RULE %{rule}I", 2, + "type", ObjTypeString, "enable rule", + "rule", ObjTypeString, subcmd->name); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + + case AT_EnableAlwaysRule: + tmp_obj = new_objtree_VA("ENABLE ALWAYS RULE %{rule}I", 2, + "type", ObjTypeString, "enable always rule", + "rule", ObjTypeString, subcmd->name); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + + case AT_EnableReplicaRule: + tmp_obj = new_objtree_VA("ENABLE REPLICA RULE %{rule}I", 2, + "type", ObjTypeString, "enable replica rule", + "rule", ObjTypeString, subcmd->name); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + + case AT_DisableRule: + tmp_obj = new_objtree_VA("DISABLE RULE %{rule}I", 2, + "type", ObjTypeString, "disable rule", + "rule", ObjTypeString, subcmd->name); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + + case AT_AddInherit: + tmp_obj = new_objtree_VA("INHERIT %{parent}D", 2, + "type", ObjTypeString, "inherit", + "parent", ObjTypeObject, + new_objtree_for_qualname_id(RelationRelationId, + sub->address.objectId)); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + + case AT_DropInherit: + tmp_obj = new_objtree_VA("NO INHERIT %{parent}D", 2, + "type", ObjTypeString, "drop inherit", + "parent", ObjTypeObject, + new_objtree_for_qualname_id(RelationRelationId, + sub->address.objectId)); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + + case AT_AddOf: + tmp_obj = new_objtree_VA("OF %{type_of}T", 2, + "type", ObjTypeString, "add of", + "type_of", ObjTypeObject, + new_objtree_for_type(sub->address.objectId, -1)); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + + case AT_DropOf: + tmp_obj = new_objtree_VA("NOT OF", 1, + "type", ObjTypeString, "not of"); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + + case AT_ReplicaIdentity: + tmp_obj = new_objtree_VA("REPLICA IDENTITY", 1, "type", ObjTypeString, "replica identity"); + switch (((ReplicaIdentityStmt *)subcmd->def)->identity_type) { + case REPLICA_IDENTITY_DEFAULT: + append_string_object(tmp_obj, "%{ident}s", "ident", "DEFAULT"); + break; + case REPLICA_IDENTITY_FULL: + append_string_object(tmp_obj, "%{ident}s", "ident", "FULL"); + break; + case REPLICA_IDENTITY_NOTHING: + append_string_object(tmp_obj, "%{ident}s", "ident", "NOTHING"); + break; + case REPLICA_IDENTITY_INDEX: + tmp_obj2 = new_objtree_VA("USING INDEX %{index}I", 1, "index", ObjTypeString, + ((ReplicaIdentityStmt *)subcmd->def)->name); + append_object_object(tmp_obj, "%{ident}s", tmp_obj2); + break; + } + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + case AT_EnableRls: + tmp_obj = new_objtree_VA("ENABLE ROW LEVEL SECURITY", 1, + "type", ObjTypeString, "enable row security"); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + case AT_DisableRls: + tmp_obj = new_objtree_VA("DISABLE ROW LEVEL SECURITY", 1, + "type", ObjTypeString, "disable row security"); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + + case AT_ForceRls: + tmp_obj = new_objtree_VA("FORCE ROW LEVEL SECURITY", 1, + "type", ObjTypeString, "disable row security"); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + + case AT_NoForceRls: + tmp_obj = new_objtree_VA("NO FORCE ROW LEVEL SECURITY", 1, + "type", ObjTypeString, "disable row security"); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + case AT_InvisibleIndex: + tmp_obj = new_objtree_VA("ALTER INDEX %{name}I INVISIBLE", 2, + "type", ObjTypeString, "alter index invisible", + "name", ObjTypeString, subcmd->name); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + case AT_VisibleIndex: + tmp_obj = new_objtree_VA("ALTER INDEX %{name}I VISIBLE", 2, + "type", ObjTypeString, "alter index visible", + "name", ObjTypeString, subcmd->name); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + case AT_SetCharsetCollate: { + CharsetCollateOptions *n = (CharsetCollateOptions *) subcmd->def; + if (n->charset != PG_INVALID_ENCODING) { + tmp_obj = new_objtree_VA("DEFAULT CHARACTER SET = %{charset}s", 2, "type", ObjTypeString, + "default character set", "charset", ObjTypeString, + pg_encoding_to_char(n->charset)); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + } + if (n->collate) { + tmp_obj = new_objtree_VA("COLLATE = %{collate}s", 2, "type", ObjTypeString, "collate", + "collate", ObjTypeString, n->collate); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + } + } + break; + case AT_ConvertCharset: { + CharsetCollateOptions *cc = (CharsetCollateOptions *)subcmd->def; + if (cc->charset != PG_INVALID_ENCODING) { + tmp_obj = + new_objtree_VA("CONVERT TO CHARACTER SET %{charset}s", 2, "type", ObjTypeString, + "convert charset", "charset", ObjTypeString, pg_encoding_to_char(cc->charset)); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + } + if (cc->collate) { + tmp_obj = new_objtree_VA("COLLATE = %{collate}s", 2, + "type", ObjTypeString, "collate", + "collate", ObjTypeString, cc->collate); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + } + } + break; + case AT_ModifyColumn: { + AttrNumber attnum; + Oid typid; + int32 typmod; + Oid typcollation; + ColumnDef *def = (ColumnDef *) subcmd->def; + + attnum = get_attnum(RelationGetRelid(rel), def->colname); + if (attnum == InvalidAttrNumber) { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("column \"%s\" of relation \"%s\" does not exist", + def->colname, RelationGetRelationName(rel)))); + } + + get_atttypetypmodcoll(RelationGetRelid(rel), attnum, &typid, &typmod, &typcollation); + + /* MODIFY_P COLUMN ColId Typename opt_charset ColQualList opt_column_options add_column_first_after + */ + if (pg_strcasecmp(subcmd->name, def->colname) == 0) { + tmp_obj = new_objtree_VA("MODIFY COLUMN %{column}I", 2, + "type", ObjTypeString, "modify column", + "column", ObjTypeString, def->colname); + } else { + tmp_obj = new_objtree_VA("CHANGE %{ori_column}I %{column}I", 3, + "type", ObjTypeString, "change coulumn", + "ori_column", ObjTypeString, subcmd->name, + "column", ObjTypeString, def->colname); + } + append_object_object(tmp_obj, "%{datatype}T", + new_objtree_for_type(typid, typmod)); + + if (def->typname->charset != PG_INVALID_ENCODING) + append_string_object(tmp_obj, "CHARACTER SET %{charset}s", "charset", + pg_encoding_to_char(def->typname->charset)); + + deparse_ColumnDef_constraints(tmp_obj, rel, def, dpcontext, &exprs); + + if (def->collClause) { + append_object_object(tmp_obj, "COLLATE %{name}D", + new_objtree_for_qualname_id(CollationRelationId, typcollation)); + } + + /* column_options comment will be set by commentStmt in alist */ + + if (subcmd->is_first) { + append_format_string(tmp_obj, "FIRST"); + } else if (subcmd->after_name) { + append_string_object(tmp_obj, "AFTER %{col}I", "col", subcmd->after_name); + } + + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + } + break; + case AT_AddPartition: { + /* ADD PARTITION name */ + AddPartitionState *s = (AddPartitionState*)subcmd->def; + ListCell *lc; + + Oid *partkey_types = NULL; + Oid *subpartkey_types = NULL; + int partkey_num, subpartkey_num = 0; + partkey_num = get_partition_key_types(relId, RELKIND_RELATION, &partkey_types); + + foreach (lc, s->partitionList) { + Node* partition = (Node*)lfirst(lc); + + if (IsA(partition, RangePartitionDefState)) { + /* RangePartitionStartEndDefState will transform the RangePartitionDefState list */ + RangePartitionDefState *p = (RangePartitionDefState *)partition; + + tmp_obj = new_objtree_VA("ADD PARTITION %{name}I VALUES LESS THAN", 2, + "type", ObjTypeString, "add partition", + "name", ObjTypeString, p->partitionName); + + //----------- parse for maxValueList expr + Oid partoid = InvalidOid; + List *boundlist = deparse_partition_boudaries( + relId, PARTTYPE_PARTITIONED_RELATION, PART_STRATEGY_RANGE, + p->partitionName, &partoid, partkey_num, partkey_types); + + append_array_object(tmp_obj, "(%{maxvalues:, }s)", boundlist); + + if (p->tablespacename) { + append_string_object(tmp_obj, "TABLESPACE %{tblspc}s", "tblspc", p->tablespacename); + } + + if (p->subPartitionDefState) { + int subpartkey_num = get_partition_key_types(relId, + PARTTYPE_PARTITIONED_RELATION, &subpartkey_types); + + deparse_add_subpartition(tmp_obj, partoid, p->subPartitionDefState, + subpartkey_num, subpartkey_types); + } + } else if (IsA(partition, ListPartitionDefState)) { + ListPartitionDefState *p = (ListPartitionDefState*)partition; + tmp_obj = new_objtree_VA("ADD PARTITION %{name}I VALUES", 2, + "type", ObjTypeString, "add partition", + "name", ObjTypeString, p->partitionName); + Oid partoid = InvalidOid; + + List *boundlist = + deparse_partition_boudaries(relId, PARTTYPE_PARTITIONED_RELATION, PART_STRATEGY_LIST, + p->partitionName, &partoid, partkey_num, partkey_types); + append_array_object(tmp_obj, "(%{maxvalues:, }s)", boundlist); + + if (p->tablespacename) { + append_string_object(tmp_obj, "TABLESPACE %{tblspc}s", "tblspc", p->tablespacename); + } + if (p->subPartitionDefState) { + subpartkey_num = get_partition_key_types(relId, PARTTYPE_PARTITIONED_RELATION, + &subpartkey_types); + + deparse_add_subpartition(tmp_obj, partoid, p->subPartitionDefState, + subpartkey_num, subpartkey_types); + } + } else if (IsA(partition, HashPartitionDefState)) { + HashPartitionDefState* p = (HashPartitionDefState*)partition; + tmp_obj = new_objtree_VA("ADD PARTITION %{name}I", 2, + "type", ObjTypeString, "add partition", + "name", ObjTypeString, p->partitionName); + if (p->tablespacename) { + append_string_object(tmp_obj, "TABLESPACE %{tblspc}s", "tblspc", p->tablespacename); + } + } else { + elog(WARNING, "unsupported AddPartitionState %d for partition table", nodeTag(partition)); + break; + } + + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + } + } + break; + case AT_AddSubPartition: { + AddSubPartitionState *s = (AddSubPartitionState*)subcmd->def; + ListCell* lc; + + tmp_obj = new_objtree_VA("MODIFY PARTITION %{name}I", 2, + "type", ObjTypeString, "modify partition add subpartition", + "name", ObjTypeString, s->partitionName); + foreach(lc, s->subPartitionList) { + if (IsA(lfirst(lc), RangePartitionDefState)) { + RangePartitionDefState *p = (RangePartitionDefState*)lfirst(lc); + append_string_object(tmp_obj, "ADD SUBPARTITION %{subpart}I", "subpart", p->partitionName); + List *maxvalues = get_range_partition_maxvalues(p->boundary); + append_array_object(tmp_obj, "VALUES LESS THAN (%{maxvalues:, }s)", maxvalues); + if (p->tablespacename) { + append_string_object(tmp_obj, "TABLESPACE %{tblspc}s", "tblspc", p->tablespacename); + } + } else { + ListPartitionDefState *p = (ListPartitionDefState*)lfirst(lc); + append_string_object(tmp_obj, "ADD SUBPARTITION %{subpart}I", "subpart", p->partitionName); + List *maxvalues = get_list_partition_maxvalues(p->boundary); + append_array_object(tmp_obj, "VALUES (%{maxvalues:, }s)", maxvalues); + if (p->tablespacename) { + append_string_object(tmp_obj, "TABLESPACE %{tblspc}s", "tblspc", p->tablespacename); + } + } + + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + } + } + break; + + case AT_DropPartition: + case AT_DropSubPartition: { + tmp_obj = new_objtree_VA(subcmd->subtype == AT_DropPartition ? + "DROP PARTITION" : "DROP SUBPARTITION", 1, + "type", ObjTypeString, "drop partition"); + if (subcmd->name) { + append_string_object(tmp_obj, "%{name}I", "name", subcmd->name); + } else { + RangePartitionDefState* state = (RangePartitionDefState*)subcmd->def; + /* transformPartitionValue for maxvalues const */ + List *maxvalues = get_range_partition_maxvalues(state->boundary); + + append_array_object(tmp_obj, "FOR (%{maxvalues:, }s)", maxvalues); + } + + if (subcmd->alterGPI) { + append_format_string(tmp_obj, "UPDATE GLOBAL INDEX"); + } + + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + } + break; + case AT_SetPartitionTableSpace: { + if (!subcmd->def) { + break; + } + if (IsA(subcmd->def, RangePartitionDefState)) { + RangePartitionDefState *p = (RangePartitionDefState*)subcmd->def; + List *maxvalues = get_range_partition_maxvalues(p->boundary); + tmp_obj = new_objtree_VA("MOVE PARTITION FOR (%{maxvalues:, }s) TABLESPACE %{tblspc}s", 3, + "type", ObjTypeString, "move partition", + "maxvalues", ObjTypeArray, maxvalues, + "tblspc", ObjTypeString, subcmd->name); + } else if (IsA(subcmd->def, RangeVar)) { + tmp_obj = new_objtree_VA("MOVE PARTITION %{partition}I TABLESPACE %{tblspc}s", 3, + "type", ObjTypeString, "move partition", + "partition", ObjTypeString, ((RangeVar*)subcmd->def)->relname, + "tblspc", ObjTypeString, subcmd->name); + } + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + } + break; + case AT_TruncatePartition: { + if (subcmd->def) { + RangePartitionDefState *p = (RangePartitionDefState*)subcmd->def; + List *maxvalues = get_range_partition_maxvalues(p->boundary); + tmp_obj = new_objtree_VA("TRUNCATE PARTITION FOR (%{maxvalues:, }s)", 2, + "type", ObjTypeString, "truncate partition", + "maxvalues", ObjTypeArray, maxvalues); + } else { + tmp_obj = new_objtree_VA("TRUNCATE PARTITION %{partition}s", 2, + "type", ObjTypeString, "truncate partition", + "partition", ObjTypeString, subcmd->name); + } + + if (subcmd->alterGPI) { + append_format_string(tmp_obj, "UPDATE GLOBAL INDEX"); + } + + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + } + break; + case AT_TruncateSubPartition: { + if (subcmd->def && IsA(subcmd->def, RangePartitionDefState)) { + RangePartitionDefState *p = (RangePartitionDefState*)subcmd->def; + List *maxvalues = get_range_partition_maxvalues(p->boundary); + + tmp_obj = new_objtree_VA("TRUNCATE SUBPARTITION FOR (%{maxvalues:, }s) %{gpi}s", 3, + "type", ObjTypeString, "truncate subpartition", + "maxvalues", ObjTypeArray, maxvalues, + "gpi", ObjTypeString, subcmd->alterGPI ? "UPDATE GLOBAL INDEX" : ""); + } else { + tmp_obj = new_objtree_VA("TRUNCATE SUBPARTITION %{partition}s %{gpi}s", 3, + "type", ObjTypeString, "truncate subpartition", + "partition", ObjTypeString, subcmd->name, + "gpi", ObjTypeString, subcmd->alterGPI ? "UPDATE GLOBAL INDEX" : ""); + } + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + } + break; + case AT_ExchangePartition: { + if (subcmd->def) { + RangePartitionDefState *p = (RangePartitionDefState*)subcmd->def; + List *maxvalues = get_range_partition_maxvalues(p->boundary); + tmp_obj = new_objtree_VA( + "EXCHANGE %{issub}s FOR (%{maxvalues:, }s) WITH TABLE %{exchange_tbl}D", 4, + "type", ObjTypeString, "exchange partition", + "issub", ObjTypeString, + "PARTITION", + "maxvalues", ObjTypeArray, maxvalues, + "exchange_tbl", ObjTypeObject, + new_objtree_for_qualname_rangevar(subcmd->exchange_with_rel)); + } else { + tmp_obj = new_objtree_VA( + "EXCHANGE %{issub}s (%{partition}I) WITH TABLE %{exchange_tbl}D", 4, + "type", ObjTypeString, "exchange partition", + "issub", ObjTypeString, + "PARTITION", + "partition", ObjTypeString, subcmd->name, + "exchange_tbl", ObjTypeObject, + new_objtree_for_qualname_rangevar(subcmd->exchange_with_rel)); + } + + if (!subcmd->check_validation) { + append_format_string(tmp_obj, "WITHOUT VALIDATION"); + } + + if (subcmd->exchange_verbose) { + append_format_string(tmp_obj, "VERBOSE"); + } + if (subcmd->alterGPI) { + append_format_string(tmp_obj, "UPDATE GLOBAL INDEX"); + } + + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + } + break; + case AT_MergePartition: { + ListCell *lc; + List *name_list = NIL; + foreach(lc, (List*)subcmd->def) { + Value* v = (Value*)lfirst(lc); + char *name = pstrdup(v->val.str); + name_list = lappend(name_list, new_string_object(name)); + } + + tmp_obj = new_objtree_VA("MERGE PARTITIONS %{name_list:, }s INTO PARTITION %{partition}s", 3, + "type", ObjTypeString, "merge partition", + "name_list", ObjTypeArray, name_list, + "partition", ObjTypeString, subcmd->name); + if (subcmd->target_partition_tablespace) { + append_string_object(tmp_obj, "TABLESPACE %{tblspc}s", + "tblspc", subcmd->target_partition_tablespace); + } + if (subcmd->alterGPI) { + append_format_string(tmp_obj, "UPDATE GLOBAL INDEX"); + } + + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + } + break; + + case AT_SplitPartition: { + SplitPartitionState *s = (SplitPartitionState*)subcmd->def; + bool two_partiiton = false; + + tmp_obj = new_objtree_VA("SPLIT PARTITION", 1, + "type", ObjTypeString, "split partition"); + if (s->src_partition_name) { + append_string_object(tmp_obj, "%{partition}s", "partition", + s->src_partition_name); + } else if (s->partition_for_values) { + List *maxvalues = get_range_partition_maxvalues(s->partition_for_values); + append_array_object(tmp_obj, "FOR (%{maxvalues:, }s)", maxvalues); + } + + if (s->split_point) { + List *maxvalues = get_range_partition_maxvalues(s->split_point); + append_array_object(tmp_obj, "AT (%{maxvalues:, }s)", maxvalues); + + if (list_length(s->dest_partition_define_list) == 2) { + RangePartitionDefState *p1 = + (RangePartitionDefState*)linitial(s->dest_partition_define_list); + RangePartitionDefState *p2 = + (RangePartitionDefState*)lsecond(s->dest_partition_define_list); + + ObjTree *split_obj = new_objtree_VA( + "PARTITION %{name1}s %{tblspc1}s, PARTITION %{name2}s %{tblspc2}s", 4, + "name1", ObjTypeString, p1->partitionName, + "tblspc1", ObjTypeString, p1->tablespacename ? p1->tablespacename : "", + "name2", ObjTypeString, p2->partitionName, + "tblspc2", ObjTypeString, p2->tablespacename ? p2->tablespacename : ""); + + append_object_object(tmp_obj, "INTO (%{split_list}s)", split_obj); + two_partiiton = true; + } + } + + if (!two_partiiton) { + ListCell *lc; + List *partlist = NIL; + Oid *partkey_types = NULL; + int partkey_num = get_partition_key_types(relId, RELKIND_RELATION, &partkey_types); + + foreach(lc, s->dest_partition_define_list) { + ObjTree *part_obj; + RangePartitionDefState *p = (RangePartitionDefState*)lfirst(lc); + Oid partoid = InvalidOid; + part_obj = new_objtree_VA("PARTITION %{partname}s", 1, + "partname", ObjTypeString, p->partitionName); + + List *boundlist = deparse_partition_boudaries(relId, PARTTYPE_PARTITIONED_RELATION, + PART_STRATEGY_RANGE, p->partitionName, &partoid, partkey_num, partkey_types); + + append_array_object(part_obj, "VALUES LESS THAN (%{maxvalues:, }s)", boundlist); + if (p->tablespacename) { + append_string_object(part_obj, "TABLESPACE %{tblspc}s", "tblspc", p->tablespacename); + } + + partlist = lappend(partlist, new_object_object(part_obj)); + } + + append_array_object(tmp_obj, "INTO (%{partlist:, }s)", partlist); + } + + if (subcmd->alterGPI) { + append_format_string(tmp_obj, "UPDATE GLOBAL INDEX"); + } + + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + } + break; + case AT_SplitSubPartition: { + SplitPartitionState *s = (SplitPartitionState*)subcmd->def; + ObjTree *define_list = NULL; + tmp_obj = new_objtree_VA("SPLIT SUBPARTITION %{name}s", 2, + "type", ObjTypeString, "split subpartition", + "name", ObjTypeString, s->src_partition_name); + + if (s->splitType == LISTSUBPARTITIION) { + List *maxvalues = get_list_partition_maxvalues(s->newListSubPartitionBoundry); + + append_array_object(tmp_obj, "VALUES (%{maxvalues:, }s)", maxvalues); + + if (list_length(s->dest_partition_define_list) == 2) { + ListPartitionDefState *p1 = (ListPartitionDefState*)linitial(s->dest_partition_define_list); + ListPartitionDefState *p2 = (ListPartitionDefState*)lsecond(s->dest_partition_define_list); + + define_list = new_objtree_VA( + "SUBPARTITION %{name1}s %{tblspc1}s, SUBPARTITION %{name2}s %{tblspc2}s", 4, + "name1", ObjTypeString, p1->partitionName, + "tblspc1", ObjTypeString, p1->tablespacename ? p1->tablespacename : "", + "name2", ObjTypeString, p2->partitionName, + "tblspc2", ObjTypeString, p2->tablespacename ? p2->tablespacename : ""); + } + if (define_list) { + append_object_object(tmp_obj, "INTO (%{define_list}s)", define_list); + } + } else if (s->splitType == RANGESUBPARTITIION) { + List *maxvalues = get_range_partition_maxvalues(s->split_point); + append_array_object(tmp_obj, "AT (%{maxvalues:, }s)", maxvalues); + + if (list_length(s->dest_partition_define_list) == 2) { + RangePartitionDefState *p1 = + (RangePartitionDefState*)linitial(s->dest_partition_define_list); + RangePartitionDefState *p2 = + (RangePartitionDefState*)lsecond(s->dest_partition_define_list); + + define_list = new_objtree_VA( + "SUBPARTITION %{name1}s %{tblspc1}s, SUBPARTITION %{name2}s %{tblspc2}s", 4, + "name1", ObjTypeString, p1->partitionName, + "tblspc1", ObjTypeString, p1->tablespacename ? p1->tablespacename : "", + "name2", ObjTypeString, p2->partitionName, + "tblspc2", ObjTypeString, p2->tablespacename ? p2->tablespacename : ""); + if (define_list) { + append_object_object(tmp_obj, "INTO (%{define_list}s)", define_list); + } + } + } + + if (subcmd->alterGPI) { + append_format_string(tmp_obj, "UPDATE GLOBAL INDEX"); + } + + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + } + break; + case AT_ResetPartitionno: { + tmp_obj = new_objtree_VA("RESET PARTITION", 1, + "type", ObjTypeString, "reset partition"); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + } + break; + case AT_UnusableIndex: + tmp_obj = new_objtree_VA("UNUSABLE", 1, + "type", ObjTypeString, "unusable index"); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + + break; + case AT_UnusableIndexPartition: + tmp_obj = new_objtree_VA("MODIFY PARTITION %{partition_identity}I UNUSABLE ", 2, + "type", ObjTypeString, "unusable partition index", + "partition_identity", ObjTypeString, subcmd->name); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + case AT_UnusableAllIndexOnPartition: { + if (!subcmd->def) { + tmp_obj = new_objtree_VA("MODIFY %{parttype} %{partition_identity}I UNUSABLE LOCAL INDEXES ", 3, + "type", ObjTypeString, "unusable all partition index", + "parttype", ObjTypeString, "PARTITION", + "partition_identity", ObjTypeString, subcmd->name); + } else if (IsA(subcmd->def, RangePartitionDefState)) { + RangePartitionDefState *p = (RangePartitionDefState *)subcmd->def; + List *maxvalues = get_range_partition_maxvalues(p->boundary); + + tmp_obj = new_objtree_VA("MODIFY %{parttype} FOR (%{maxvalues:, }s) UNUSABLE LOCAL INDEXES ", 3, + "type", ObjTypeString, "unusable all partition index", + "parttype", ObjTypeString, "PARTITION", + "maxvalues", ObjTypeArray, maxvalues); + } + } + break; + case AT_RebuildIndex: + tmp_obj = new_objtree_VA("REBUILD", 1, + "type", ObjTypeString, "rebuild index"); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + case AT_RebuildIndexPartition: + tmp_obj = new_objtree_VA("REBUILD PARTITION %{partition_identity}I", 2, + "type", ObjTypeString, "rebuild partition index", + "partition_identity", ObjTypeString, subcmd->name); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + case AT_RebuildAllIndexOnPartition: + tmp_obj = new_objtree_VA("MODIFY PARTITION %{partition_identity}I REBUILD ALL INDEX", 2, + "type", ObjTypeString, "rebuild partition all index", + "partition_identity", ObjTypeString, subcmd->name); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; +#ifdef TODOLIST + case AT_GenericOptions: + tmp_obj = deparse_FdwOptions((List *) subcmd->def, NULL); + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; +#endif + default: + if (u_sess->hook_cxt.deparseCollectedCommandHook != NULL) { + tmp_obj = (ObjTree*)((deparseCollectedCommand)(u_sess->hook_cxt.deparseCollectedCommandHook)) + (ALTER_RELATION_SUBCMD, cmd, sub, context); + if (tmp_obj) { + subcmds = lappend(subcmds, new_object_object(tmp_obj)); + break; + } + } + + elog(WARNING, "unsupported alter table subtype %d for ddl logical replication", + subcmd->subtype); + + break; + } + + /* + * We don't support replicating ALTER TABLE which contains volatile + * functions because It's possible the functions contain DDL/DML in + * which case these operations will be executed twice and cause + * duplicate data. In addition, we don't know whether the tables being + * accessed by these DDL/DML are published or not. So blindly allowing + * such functions can allow unintended clauses like the tables + * accessed in those functions may not even exist on the subscriber. + */ + if (contain_volatile_functions((Node *) exprs)) + elog(ERROR, "ALTER TABLE command using volatile function cannot be replicated"); + + /* + * Clean the list as we already confirmed there is no volatile + * function. + */ + list_free(exprs); + exprs = NIL; + } + + table_close(rel, AccessShareLock); + + if (list_length(subcmds) == 0) + return NULL; + + append_array_object(ret, "%{subcmds:, }s", subcmds); + + return ret; +} + /* * Workhorse to deparse a CollectedCommand. */ -char * -deparse_utility_command(CollectedCommand *cmd, ddl_deparse_context *context) +char* deparse_utility_command(CollectedCommand *cmd, ddl_deparse_context *context) { OverrideSearchPath *overridePath; MemoryContext oldcxt; @@ -2437,7 +5091,10 @@ deparse_utility_command(CollectedCommand *cmd, ddl_deparse_context *context) case SCT_Simple: tree = deparse_simple_command(cmd, &context->include_owner); break; - + case SCT_AlterTable: + tree = deparse_AlterRelation(cmd, context); + context->include_owner = false; + break; default: elog(ERROR, "unexpected deparse node type %d", cmd->type); } @@ -2460,3 +5117,759 @@ deparse_utility_command(CollectedCommand *cmd, ddl_deparse_context *context) return command; } + + +static char* get_maxvalue_from_const(Const* maxvalue_item, char* default_str) +{ + int16 typlen = 0; + bool typbyval = false; + char typalign; + char typdelim; + Oid typioparam = InvalidOid; + Oid outfunc = InvalidOid; + char* maxvalue; + char* maxvalue_out; + + if (constIsNull(maxvalue_item)) { + maxvalue = pstrdup("NULL"); + } else if (constIsMaxValue(maxvalue_item)) { + maxvalue = pstrdup(default_str); + } else { + get_type_io_data(maxvalue_item->consttype, + IOFunc_output, + &typlen, + &typbyval, + &typalign, + &typdelim, + &typioparam, + &outfunc); + maxvalue_out = + DatumGetCString(OidFunctionCall1Coll(outfunc, maxvalue_item->constcollid, maxvalue_item->constvalue)); + + if (istypestring(maxvalue_item->consttype)) { + int nret = 0; + size_t len = strlen(maxvalue_out) + 3; + maxvalue = (char*)palloc0(len * sizeof(char)); + nret = snprintf_s(maxvalue, len, len - 1, "\'%s\'", maxvalue_out); + securec_check_ss(nret, "\0", "\0"); + } else { + maxvalue = pstrdup(maxvalue_out); + } + } + + return maxvalue; +} + +static List *get_range_partition_maxvalues(List* boundary) +{ + ListCell *lc; + List *maxvalues = NIL; + + foreach (lc, boundary) { + Const *maxvalue_item = (Const*)lfirst(lc); + char *maxvalue = get_maxvalue_from_const(maxvalue_item, "MAXVALUE"); + if (maxvalue) + maxvalues = lappend(maxvalues, new_string_object(maxvalue)); + } + + return maxvalues; +} + +/* see transformListPartitionValue */ +static List *get_list_partition_maxvalues(List *boundary) +{ + ListCell *lc; + List *maxvalues = NIL; + + foreach (lc, boundary) { + if (IsA(lfirst(lc), RowExpr)) { + /* for multi-keys list partition boundary, ((xx,xx),(xx,xx)) + * subpartition's partition key's length should be 1 + */ + RowExpr *r = (RowExpr*)lfirst(lc); + ListCell *lc2; + + StringInfoData tmpbuf; + int i = 0; + initStringInfo(&tmpbuf); + + foreach(lc2, r->args) { + Const *maxvalue_item = (Const*)lfirst(lc); + + if (i++ > 0) { + appendStringInfo(&tmpbuf, ","); + } + + char *maxvalue = get_maxvalue_from_const(maxvalue_item, "NULL"); + if (maxvalue) { + appendStringInfo(&tmpbuf, "%s", maxvalue); + } + } + appendStringInfo(&tmpbuf, ")"); + char* rowstr = pstrdup(tmpbuf.data); + maxvalues = lappend(maxvalues, new_string_object(rowstr)); + } else { + /* singel key */ + Const *maxvalue_item = (Const*)lfirst(lc); + char *maxvalue = get_maxvalue_from_const(maxvalue_item, "DEFAULT"); + if (maxvalue) + maxvalues = lappend(maxvalues, new_string_object(maxvalue)); + } + } + + return maxvalues; +} + +static int get_partition_key_types(Oid reloid, char parttype, Oid **partkey_types) +{ + Relation relation = NULL; + ScanKeyData key[2]; + SysScanDesc scan = NULL; + HeapTuple tuple = NULL; + bool isnull = false; + bool isPartExprKeyNull = false; + int partkeynum = 0; + + relation = heap_open(PartitionRelationId, AccessShareLock); + + ScanKeyInit(&key[0], Anum_pg_partition_parttype, BTEqualStrategyNumber, F_CHAREQ, CharGetDatum(parttype)); + ScanKeyInit(&key[1], Anum_pg_partition_parentid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(reloid)); + + scan = systable_beginscan(relation, PartitionParentOidIndexId, true, NULL, 2, key); + if (HeapTupleIsValid(tuple = systable_getnext(scan))) { + Datum datum = 0; + datum = SysCacheGetAttr(PARTRELID, tuple, Anum_pg_partition_partkeyexpr, &isPartExprKeyNull); + + if (!isPartExprKeyNull) { + Node *partkeyexpr = NULL; + char *partkeystr = pstrdup(TextDatumGetCString(datum)); + if (partkeystr) + partkeyexpr = (Node *)stringToNode_skip_extern_fields(partkeystr); + else + ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("The partkeystr can't be NULL while getting partition key types"))); + if (!partkeyexpr) + ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("The partkeyexpr can't be NULL while getting partition key types"))); + + partkeynum = 1; + *partkey_types = (Oid*)palloc0(partkeynum * sizeof(Oid)); + if (partkeyexpr->type == T_OpExpr) + (*partkey_types)[0] = ((OpExpr*)partkeyexpr)->opresulttype; + else if (partkeyexpr->type == T_FuncExpr) + (*partkey_types)[0] = ((FuncExpr*)partkeyexpr)->funcresulttype; + else + ereport(ERROR, + (errcode(ERRCODE_NODE_ID_MISSMATCH), + errmsg("The node type %d is wrong, it must be T_OpExpr or T_FuncExpr", partkeyexpr->type))); + } else { + Oid *iPartboundary = NULL; + datum = SysCacheGetAttr(PARTRELID, tuple, Anum_pg_partition_partkey, &isnull); + + if (isnull) { + ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("can not find partkey while getting partition key types"))); + } else { + int2vector *partVec = (int2vector *)DatumGetPointer(datum); + partkeynum = partVec->dim1; + iPartboundary = (Oid *)palloc0(partkeynum * sizeof(Oid)); + for (int i = 0; i < partVec->dim1; i++) { + iPartboundary[i] = get_atttype(reloid, partVec->values[i]); + } + *partkey_types = iPartboundary; + } + } + } else { + systable_endscan(scan); + heap_close(relation, AccessShareLock); + ereport(ERROR, (errcode(ERRCODE_CACHE_LOOKUP_FAILED), + errmsg("could not find tuple for partition relation %u", reloid))); + } + + systable_endscan(scan); + heap_close(relation, AccessShareLock); + + return partkeynum; +} + +static ObjTree *deparse_add_subpartition(ObjTree *ret, Oid partoid, List *subPartitionDefState, int partkeynum, + Oid *partkey_types) +{ + ListCell *subcell; + List *sublist = NIL; + ObjTree *subobj = NULL; + Oid suboid = InvalidOid; + + foreach(subcell, subPartitionDefState) { + if (IsA((Node*)lfirst(subcell), ListPartitionDefState)) { + ListPartitionDefState *n = (ListPartitionDefState*)lfirst(subcell); + + List *subboundlist = + deparse_partition_boudaries(partoid, PARTTYPE_SUBPARTITIONED_RELATION, PART_STRATEGY_LIST, + n->partitionName, &suboid, partkeynum, partkey_types); + + subobj = new_objtree_VA("SUBPARTITION %{name}I VALUES (%{maxvalue:, }s)", 2, + "name", ObjTypeString, n->partitionName, + "maxvalue", ObjTypeArray, subboundlist); + if (n->tablespacename) { + append_string_object(subobj, "TABLESPACE %{tblspc}s", "tblspc", n->tablespacename); + } + } else if (IsA((Node*)lfirst(subcell), HashPartitionDefState)) { + HashPartitionDefState *n = (HashPartitionDefState*)lfirst(subcell); + + subobj = new_objtree_VA("SUBPARTITION %{name}I", 1, + "name", ObjTypeString, n->partitionName); + if (n->tablespacename) { + append_string_object(subobj, "TABLESPACE %{tblspc}s", "tblspc", n->tablespacename); + } + } else if (IsA((Node*)lfirst(subcell), RangePartitionDefState)) { + RangePartitionDefState *n = (RangePartitionDefState*)lfirst(subcell); + + List *subboundlist = + deparse_partition_boudaries(partoid, PARTTYPE_SUBPARTITIONED_RELATION, PART_STRATEGY_RANGE, + n->partitionName, &suboid, partkeynum, partkey_types); + + subobj = new_objtree_VA("SUBPARTITION %{name}I VALUES LESS THAN (%{maxvalue:, }s)", 2, + "name", ObjTypeString, n->partitionName, + "maxvalue", ObjTypeArray, subboundlist); + if (n->tablespacename) { + append_string_object(subobj, "TABLESPACE %{tblspc}s", "tblspc", n->tablespacename); + } + } else { + elog(ERROR, "unrecognize subpartiiton definition type %d", nodeTag((Node*)lfirst(subcell))); + } + sublist = lappend(sublist, new_object_object(subobj)); + } + + append_array_object(ret, "(%{subpartitions:, }s)", sublist); + return ret; +} + +static List *deparse_partition_boudaries(Oid parentoid, char reltype, char strategy, const char *partition_name, + Oid *partoid, int partkeynum, Oid *partkey_types) +{ + List *boundlist = NIL; + Relation relation = NULL; + ScanKeyData key[2]; + SysScanDesc scan = NULL; + HeapTuple tuple = NULL; + Oid thisoid = InvalidOid; + char *maxvalue_str = NULL; + + relation = heap_open(PartitionRelationId, AccessShareLock); + + ScanKeyInit(&key[0], Anum_pg_partition_parttype, BTEqualStrategyNumber, F_CHAREQ, CharGetDatum(reltype)); + ScanKeyInit(&key[1], Anum_pg_partition_parentid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(parentoid)); + scan = systable_beginscan(relation, PartitionParentOidIndexId, true, NULL, 2, key); + while (HeapTupleIsValid(tuple = systable_getnext(scan))) { + bool datum_is_null; + Form_pg_partition foundpart = (Form_pg_partition)GETSTRUCT(tuple); + if (pg_strcasecmp(foundpart->relname.data, partition_name)) { + continue; + } + + Datum boundary_datum = SysCacheGetAttr(PARTRELID, tuple, Anum_pg_partition_boundaries, &datum_is_null); + if (datum_is_null) { + if (strategy == PART_STRATEGY_LIST) { + maxvalue_str = pstrdup("DEFAULT"); + boundlist = lappend(boundlist, new_string_object(maxvalue_str)); + thisoid = HeapTupleGetOid(tuple); + break; + } else { + systable_endscan(scan); + heap_close(relation, AccessShareLock); + ereport(ERROR, (errcode(ERRCODE_CACHE_LOOKUP_FAILED), + errmsg("could not find boundaries for partition %s", partition_name))); + } + } + + if (strategy == PART_STRATEGY_LIST && partkeynum > 1) { + /* see unnest function */ + ArrayType* arr = DatumGetArrayTypeP(boundary_datum); + + Datum dt = 0; + bool isnull = false; + + ArrayIterator it = array_create_iterator(arr, 0); + while (array_iterate(it, &dt, &isnull)) { + if (isnull) { + // default + maxvalue_str = pstrdup("DEFAULT"); + boundlist = lappend(boundlist, new_string_object(maxvalue_str)); + continue; + } + + StringInfoData tmpbuf; + initStringInfo(&tmpbuf); + + char* partvalue_str = TextDatumGetCString(dt); + Type targetType = typeidType(TEXTARRAYOID); + Datum partvalue_array_datum = stringTypeDatum(targetType, partvalue_str, TEXTOID, true); + ReleaseSysCache(targetType); + + ArrayType* partvalue_array = DatumGetArrayTypeP(partvalue_array_datum); + + Datum partkey_dt = 0; + bool partkey_isnull = false; + int it_index = 0; + + appendStringInfo(&tmpbuf, "("); + ArrayIterator partkey_it = array_create_iterator(partvalue_array, 0); + while (array_iterate(partkey_it, &partkey_dt, &partkey_isnull)) { + // OidInputFunctionCall + if (it_index > 0) { + appendStringInfo(&tmpbuf, ","); + } + + if (partkey_isnull) { + appendStringInfo(&tmpbuf, "NULL"); + continue; + } + + char *svalue = TextDatumGetCString(partkey_dt); + + if (istypestring(partkey_types[it_index])) { + appendStringInfo(&tmpbuf, "'%s'", svalue); + } else { + appendStringInfo(&tmpbuf, "%s", svalue); + } + ++it_index; + } + appendStringInfo(&tmpbuf, ")"); + maxvalue_str = pstrdup(tmpbuf.data); + if (maxvalue_str) { + boundlist = lappend(boundlist, new_string_object(maxvalue_str)); + } + } + } else { + List* boundary = untransformPartitionBoundary(boundary_datum); + ListCell *bcell; + int i = 0; + foreach (bcell, boundary) { + Value* maxvalue = (Value*)lfirst(bcell); + + if (i >= partkeynum) { + break; + } + + if (!PointerIsValid(maxvalue->val.str)) { + if (strategy == PART_STRATEGY_RANGE) { + maxvalue_str = pstrdup("MAXVALUE"); + } else { + maxvalue_str = pstrdup("DEFAULT"); + } + } else if (istypestring(partkey_types[i])) { + int nret = 0; + size_t len = strlen(maxvalue->val.str) + 3; + maxvalue_str = (char *)palloc0(len * sizeof(char)); + nret = snprintf_s(maxvalue_str, len, len - 1, "\'%s\'", maxvalue->val.str); + securec_check_ss(nret, "\0", "\0"); + } else { + maxvalue_str = pstrdup(maxvalue->val.str); + } + if (strategy == PART_STRATEGY_RANGE) + ++i; + + if (maxvalue_str) + boundlist = lappend(boundlist, new_string_object(maxvalue_str)); + } + } + + thisoid = HeapTupleGetOid(tuple); + break; + } + + systable_endscan(scan); + heap_close(relation, AccessShareLock); + + if (!OidIsValid(thisoid)) { + ereport(ERROR, (errcode(ERRCODE_CACHE_LOOKUP_FAILED), + errmsg("could not find subpartition tuple for partition relation %s", partition_name))); + } + + if (partoid) + *partoid = thisoid; + + return boundlist; +} + +/* + * Handle deparsing setting of Function + * + * Verbose syntax + * RESET ALL + * OR + * SET %{set_name}I TO %{set_value}s + * OR + * RESET %{set_name}I + */ +static ObjTree* deparse_FunctionSet(VariableSetKind kind, char *name, char *value) +{ + ObjTree *ret; + struct config_generic *record; + + if (kind == VAR_RESET_ALL) { + ret = new_objtree("RESET ALL"); + } else if (kind == VAR_SET_VALUE) { + ret = new_objtree_VA("SET %{set_name}I", 1, + "set_name", ObjTypeString, name); + + /* + * Some GUC variable names are 'LIST' type and hence must not be + * quoted. + */ + record = find_option(name, false, ERROR); + if (record && (record->flags & GUC_LIST_QUOTE)) + append_string_object(ret, "TO %{set_value}s", "set_value", value); + else + append_string_object(ret, "TO %{set_value}L", "set_value", value); + } else { + ret = new_objtree_VA("RESET %{set_name}I", 1, + "set_name", ObjTypeString, name); + } + + return ret; +} + +/* + * Deparse a CreateFunctionStmt (CREATE FUNCTION) + * + * Given a function OID and the parse tree that created it, return an ObjTree + * representing the creation command. + * + * Verbose syntax + * + * CREATE %{or_replace}s FUNCTION %{signature}s RETURNS %{return_type}s + * LANGUAGE %{transform_type}s %{language}I %{window}s %{volatility}s + * %{parallel_safety}s %{leakproof}s %{strict}s %{security_definer}s + * %{cost}s %{rows}s %{support}s %{set_options: }s AS %{objfile}L, + * %{symbol}L + */ +static ObjTree* deparse_CreateFunction(Oid objectId, Node *parsetree) +{ + ObjTree *ret; + char *func_str; + size_t len; + + func_str = pg_get_functiondef_string(objectId); + len = strlen(func_str); + if (func_str[len - 1] == '\n' && func_str[len - 2] == '/' + && func_str[len - 3] == '\n' && func_str[len - 4] == ';') { + func_str[len - 2] = '\0'; + func_str[len - 1] = '\0'; + } + + ret = new_objtree_VA("%{function}s", 1, + "function", ObjTypeString, + func_str); + + return ret; +} + +/* + * Deparse an AlterFunctionStmt (ALTER FUNCTION/ROUTINE/PROCEDURE) + * + * Given a function OID and the parse tree that created it, return an ObjTree + * representing the alter command. + * + * Verbose syntax: + * ALTER FUNCTION/ROUTINE/PROCEDURE %{signature}s %{definition: }s + */ +static ObjTree* deparse_AlterFunction(Oid objectId, Node *parsetree) +{ + AlterFunctionStmt *node = (AlterFunctionStmt *) parsetree; + ObjTree *ret; + ObjTree *sign; + HeapTuple procTup; + Form_pg_proc procForm; + List *params = NIL; + List *elems = NIL; + ListCell *cell; + int i; + + /* Get the pg_proc tuple */ + procTup = SearchSysCache1(PROCOID, objectId); + if (!HeapTupleIsValid(procTup)) + elog(ERROR, "cache lookup failed for function with OID %u", objectId); + procForm = (Form_pg_proc) GETSTRUCT(procTup); + + if (node->isProcedure) + ret = new_objtree("ALTER PROCEDURE"); + else + ret = new_objtree("ALTER FUNCTION"); + + /* + * ALTER FUNCTION does not change signature so we can use catalog to get + * input type Oids. + */ + for (i = 0; i < procForm->pronargs; i++) { + ObjTree *tmp_obj; + + tmp_obj = new_objtree_VA("%{type}T", 1, + "type", ObjTypeObject, + new_objtree_for_type(procForm->proargtypes.values[i], -1)); + params = lappend(params, new_object_object(tmp_obj)); + } + + sign = new_objtree_VA("%{identity}D (%{arguments:, }s)", 2, + "identity", ObjTypeObject, + new_objtree_for_qualname_id(ProcedureRelationId, objectId), + "arguments", ObjTypeArray, params); + + append_object_object(ret, "%{signature}s", sign); + + foreach(cell, node->actions) { + DefElem *defel = (DefElem *) lfirst(cell); + ObjTree *tmp_obj = NULL; + + if (strcmp(defel->defname, "volatility") == 0) { + tmp_obj = new_objtree(strVal(defel->arg)); + } else if (strcmp(defel->defname, "strict") == 0) { + tmp_obj = new_objtree(intVal(defel->arg) ? + "RETURNS NULL ON NULL INPUT" : + "CALLED ON NULL INPUT"); + } else if (strcmp(defel->defname, "security") == 0) { + tmp_obj = PLSQL_SECURITY_DEFINER ? new_objtree(intVal(defel->arg) ? + "AUTHID DEFINER" : "AUTHID CURRENT_USER") : + new_objtree(intVal(defel->arg) ? + "SECURITY DEFINER" : "SECURITY INVOKER"); + } else if (strcmp(defel->defname, "leakproof") == 0) { + tmp_obj = new_objtree(intVal(defel->arg) ? + "LEAKPROOF" : "NOT LEAKPROOF"); + } else if (strcmp(defel->defname, "cost") == 0) { + tmp_obj = new_objtree_VA("COST %{cost}n", 1, + "cost", ObjTypeFloat, + defGetNumeric(defel)); + } else if (strcmp(defel->defname, "rows") == 0) { + tmp_obj = new_objtree("ROWS"); + if (defGetNumeric(defel) == 0) + append_not_present(tmp_obj, "%{rows}n"); + else + append_float_object(tmp_obj, "%{rows}n", + defGetNumeric(defel)); + } else if (strcmp(defel->defname, "set") == 0) { + VariableSetStmt *sstmt = (VariableSetStmt *) defel->arg; + char *value = ExtractSetVariableArgs(sstmt); + + tmp_obj = deparse_FunctionSet(sstmt->kind, sstmt->name, value); + } else if (strcmp(defel->defname, "parallel") == 0) { + tmp_obj = new_objtree_VA("PARALLEL %{value}s", 1, + "value", ObjTypeString, strVal(defel->arg)); + } + + elems = lappend(elems, new_object_object(tmp_obj)); + } + + append_array_object(ret, "%{definition: }s", elems); + + ReleaseSysCache(procTup); + + return ret; +} + +/* + * Deparse a CreateTrigStmt (CREATE TRIGGER) + * + * Given a trigger OID and the parse tree that created it, return an ObjTree + * representing the creation command. + * + * Verbose syntax + * CREATE %{constraint}s TRIGGER %{name}I %{time}s %{events: OR }s ON + * %{relation}D %{from_table}s %{constraint_attrs: }s %{referencing: }s + * FOR EACH %{for_each}s %{when}s EXECUTE PROCEDURE %{function}s + */ +static ObjTree* deparse_CreateTrigStmt(Oid objectId, Node *parsetree) +{ + CreateTrigStmt *node = (CreateTrigStmt *) parsetree; + Relation pg_trigger; + HeapTuple trigTup; + Form_pg_trigger trigForm; + ObjTree *ret; + ObjTree *tmp_obj; + int tgnargs; + List *list = NIL; + List *events; + char *trigtiming; + Datum value; + bool isnull; + char *bodySrc; + + pg_trigger = table_open(TriggerRelationId, AccessShareLock); + + trigTup = get_catalog_object_by_oid(pg_trigger, objectId); + trigForm = (Form_pg_trigger) GETSTRUCT(trigTup); + + trigtiming = (char*)(node->timing == TRIGGER_TYPE_BEFORE ? "BEFORE" : + node->timing == TRIGGER_TYPE_AFTER ? "AFTER" : + node->timing == TRIGGER_TYPE_INSTEAD ? "INSTEAD OF" : + NULL); + if (!trigtiming) + elog(ERROR, "unrecognized trigger timing type %d", node->timing); + + /* DEFINER clause */ + tmp_obj = new_objtree("DEFINER"); + if (node->definer) + append_string_object(tmp_obj, "=%{definer}s", "definer", + node->definer); + else + append_not_present(tmp_obj, "=%{definer}s"); + + ret = new_objtree_VA("CREATE %{definer}s %{constraint}s TRIGGER %{if_not_exists}s %{name}I %{time}s", 5, + "definer", ObjTypeObject, tmp_obj, + "constraint", ObjTypeString, node->isconstraint ? "CONSTRAINT" : "", + "if_not_exists", ObjTypeString, node->if_not_exists ? "IF NOT EXISTS" : "", + "name", ObjTypeString, node->trigname, + "time", ObjTypeString, trigtiming); + + /* + * Decode the events that the trigger fires for. The output is a list; in + * most cases it will just be a string with the event name, but when + * there's an UPDATE with a list of columns, we return a JSON object. + */ + events = NIL; + if (node->events & TRIGGER_TYPE_INSERT) + events = lappend(events, new_string_object("INSERT")); + if (node->events & TRIGGER_TYPE_DELETE) + events = lappend(events, new_string_object("DELETE")); + if (node->events & TRIGGER_TYPE_TRUNCATE) + events = lappend(events, new_string_object("TRUNCATE")); + if (node->events & TRIGGER_TYPE_UPDATE) { + if (node->columns == NIL) { + events = lappend(events, new_string_object("UPDATE")); + } else { + ObjTree *update; + ListCell *cell; + List *cols = NIL; + + /* + * Currently only UPDATE OF can be objects in the output JSON, but + * we add a "kind" element so that user code can distinguish + * possible future new event types. + */ + update = new_objtree_VA("UPDATE OF", 1, + "kind", ObjTypeString, "update_of"); + + foreach(cell, node->columns) { + char *colname = strVal(lfirst(cell)); + + cols = lappend(cols, new_string_object(colname)); + } + + append_array_object(update, "%{columns:, }I", cols); + + events = lappend(events, new_object_object(update)); + } + } + append_array_object(ret, "%{events: OR }s", events); + + tmp_obj = new_objtree_for_qualname_id(RelationRelationId, + trigForm->tgrelid); + append_object_object(ret, "ON %{relation}D", tmp_obj); + + tmp_obj = new_objtree("FROM"); + if (trigForm->tgconstrrelid) { + ObjTree *rel; + + rel = new_objtree_for_qualname_id(RelationRelationId, + trigForm->tgconstrrelid); + append_object_object(tmp_obj, "%{relation}D", rel); + } else { + append_not_present(tmp_obj, "%{relation}D"); + } + append_object_object(ret, "%{from_table}s", tmp_obj); + + if (node->isconstraint) { + if (!node->deferrable) + list = lappend(list, new_string_object("NOT")); + list = lappend(list, new_string_object("DEFERRABLE INITIALLY")); + if (node->initdeferred) + list = lappend(list, new_string_object("DEFERRED")); + else + list = lappend(list, new_string_object("IMMEDIATE")); + } + append_array_object(ret, "%{constraint_attrs: }s", list); + + append_string_object(ret, "FOR EACH %{for_each}s", "for_each", + node->row ? "ROW" : "STATEMENT"); + + tmp_obj = new_objtree("WHEN"); + if (node->whenClause) { + Node *whenClause; + + value = fastgetattr(trigTup, Anum_pg_trigger_tgqual, + RelationGetDescr(pg_trigger), &isnull); + if (isnull) + elog(ERROR, "null tgqual for trigger \"%s\"", + NameStr(trigForm->tgname)); + + whenClause = (Node*)stringToNode(TextDatumGetCString(value)); + + append_string_object(tmp_obj, "(%{clause}s)", "clause", + pg_get_trigger_whenclause(trigForm, whenClause, false)); + } else { + append_not_present(tmp_obj, "%{clause}s"); + } + append_object_object(ret, "%{when}s", tmp_obj); + + if (node->funcname && !node->funcSource) { + tmp_obj = new_objtree_VA("%{funcname}D", 1, "funcname", ObjTypeObject, + new_objtree_for_qualname_id(ProcedureRelationId, trigForm->tgfoid)); + list = NIL; + tgnargs = trigForm->tgnargs; + if (tgnargs > 0) { + bytea *tgargs; + char *argstr; + int findx; + int lentgargs; + char *p; + + tgargs = DatumGetByteaP(fastgetattr(trigTup, + Anum_pg_trigger_tgargs, + RelationGetDescr(pg_trigger), + &isnull)); + if (isnull) + elog(ERROR, "null tgargs for trigger \"%s\"", NameStr(trigForm->tgname)); + argstr = (char *)VARDATA(tgargs); + lentgargs = VARSIZE_ANY_EXHDR(tgargs); + + p = argstr; + for (findx = 0; findx < tgnargs; findx++) { + size_t tlen; + + /* Verify that the argument encoding is correct */ + tlen = strlen(p); + if (p + tlen >= argstr + lentgargs) { + elog(ERROR, "invalid argument string (%s) for trigger \"%s\"", argstr, NameStr(trigForm->tgname)); + } + list = lappend(list, new_string_object(p)); + p += tlen + 1; + } + } + + append_format_string(tmp_obj, "("); + append_array_object(tmp_obj, "%{args:, }L", list); /* might be NIL */ + append_format_string(tmp_obj, ")"); + + append_object_object(ret, "EXECUTE PROCEDURE %{function}s", tmp_obj); + } + + if (node->funcSource && node->funcSource->bodySrc) { + bodySrc = pstrdup(node->funcSource->bodySrc); + if (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT + && strlen(bodySrc) > BEGIN_P_LEN + && pg_strncasecmp(bodySrc, BEGIN_P_STR, BEGIN_P_LEN) == 0) { + errno_t rc = memcpy_s(bodySrc, strlen(bodySrc), BEGIN_N_STR, BEGIN_P_LEN); + securec_check(rc, "\0", "\0") + } + tmp_obj = new_objtree_VA("%{bodysrc}s", 1, + "bodysrc", ObjTypeString, bodySrc); + } else { + tmp_obj = new_objtree_VA("", 1, + "present", ObjTypeBool, false); + } + append_object_object(ret, "%{bodysrc}s", tmp_obj); + + table_close(pg_trigger, AccessShareLock); + + return ret; +} \ No newline at end of file diff --git a/src/gausskernel/optimizer/commands/event_trigger.cpp b/src/gausskernel/optimizer/commands/event_trigger.cpp index 4e40b89ca..a522c97b9 100644 --- a/src/gausskernel/optimizer/commands/event_trigger.cpp +++ b/src/gausskernel/optimizer/commands/event_trigger.cpp @@ -33,6 +33,7 @@ #include "parser/parse_func.h" #include "parser/parser.h" #include "parser/parse_relation.h" +#include "parser/parse_expr.h" #include "pgstat.h" #include "miscadmin.h" #include "utils/acl.h" @@ -111,6 +112,7 @@ static const event_trigger_support_data event_trigger_support[] = { {"PACKAGE SPECIFICATION", true}, {"ROW LEVEL SECURITY POLICY", true}, {"SYNONYM", true}, + {"EVENT", true}, { NULL, false } }; @@ -1614,6 +1616,7 @@ void EventTriggerAlterTableStart(Node *parsetree) command->d.alterTable.classId = RelationRelationId; command->d.alterTable.objectId = InvalidOid; + command->d.alterTable.rewrite = false; command->d.alterTable.subcmds = NIL; command->parsetree = (Node*)copyObject(parsetree); command->parent = currentEventTriggerState->currentCommand; @@ -1645,7 +1648,7 @@ void EventTriggerAlterTableRelid(Oid objectId) * itself, they are all concerned with AlterTableCmd nodes that are generated * internally, so that's all that this code needs to handle at the moment. */ -void EventTriggerCollectAlterTableSubcmd(Node *subcmd, ObjectAddress address) +void EventTriggerCollectAlterTableSubcmd(Node *subcmd, ObjectAddress address, bool rewrite) { MemoryContext oldcxt; CollectedATSubcmd *newsub; @@ -1664,13 +1667,193 @@ void EventTriggerCollectAlterTableSubcmd(Node *subcmd, ObjectAddress address) newsub = (CollectedATSubcmd*) palloc(sizeof(CollectedATSubcmd)); newsub->address = address; newsub->parsetree = (Node*)copyObject(subcmd); - + + currentEventTriggerState->currentCommand->d.alterTable.rewrite |= rewrite; currentEventTriggerState->currentCommand->d.alterTable.subcmds = lappend(currentEventTriggerState->currentCommand->d.alterTable.subcmds, newsub); MemoryContextSwitchTo(oldcxt); } - + +/* + * EventTriggerAlterTypeStart + * Save data about a single part of an ALTER TYPE. + * + * ALTER TABLE can have multiple subcommands which might include DROP COLUMN + * command and ALTER TYPE referring the drop column in USING expression. + * As the dropped column cannot be accessed after the execution of DROP COLUMN, + * a special trigger is required to handle this case before the drop column is + * executed. + */ +void EventTriggerAlterTypeStart(AlterTableCmd *subcmd, Relation rel) +{ + MemoryContext oldcxt; + CollectedATSubcmd *newsub; + ColumnDef *def; + Relation attrelation; + HeapTuple heapTup; + Form_pg_attribute attTup; + AttrNumber attnum; + ObjectAddress address; + + /* ignore if event trigger context not set, or collection disabled */ + if (!currentEventTriggerState || currentEventTriggerState->commandCollectionInhibited) { + return; + } + + Assert(IsA(subcmd, AlterTableCmd)); + Assert(subcmd->subtype == AT_AlterColumnType); + Assert(currentEventTriggerState->currentCommand != NULL); + Assert(OidIsValid(currentEventTriggerState->currentCommand->d.alterTable.objectId)); + + def = (ColumnDef *) subcmd->def; + Assert(IsA(def, ColumnDef)); + + oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt); + + newsub = (CollectedATSubcmd*) palloc(sizeof(CollectedATSubcmd)); + newsub->parsetree = (Node *)copyObject(subcmd); + + attrelation = table_open(AttributeRelationId, RowExclusiveLock); + + /* Look up the target column */ + heapTup = SearchSysCacheCopyAttName(RelationGetRelid(rel), subcmd->name); + if (!HeapTupleIsValid(heapTup)) /* shouldn't happen */ + ereport(ERROR, + ( + errmsg("column \"%s\" of relation \"%s\" does not exist", + subcmd->name, RelationGetRelationName(rel)))); + + attTup = (Form_pg_attribute) GETSTRUCT(heapTup); + attnum = attTup->attnum; + + ObjectAddressSubSet(address, RelationRelationId, + RelationGetRelid(rel), attnum); + heap_freetuple(heapTup); + table_close(attrelation, RowExclusiveLock); + newsub->address = address; + newsub->usingexpr = NULL; + + if (def->raw_default) { + OverrideSearchPath *overridePath; + char *defexpr; + + /* + * We want all object names to be qualified when deparsing the + * expression, so that results are "portable" to environments with + * different search_path settings. Rather than inject what would be + * repetitive calls to override search path all over the place, we do + * it centrally here. + */ + if (def->cooked_default) { + defexpr = nodeToString(def->cooked_default); + } else { + ParseState* pstate = make_parsestate(NULL); + RangeTblEntry* rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true); + addRTEtoQuery(pstate, rte, false, true, true); + Node* transform = transformExpr(pstate, def->raw_default, EXPR_KIND_ALTER_COL_TRANSFORM); + + AlterTableCmd *curcmd = (AlterTableCmd*)(newsub->parsetree); + ColumnDef *curdef = (ColumnDef *) curcmd->def; + curdef->cooked_default = transform; + + defexpr = nodeToString(transform); + } + + overridePath = GetOverrideSearchPath(CurrentMemoryContext); + overridePath->schemas = NIL; + overridePath->addCatalog = false; + overridePath->addTemp = true; + PushOverrideSearchPath(overridePath); + + newsub->usingexpr = + TextDatumGetCString(DirectFunctionCall2(pg_get_expr, CStringGetTextDatum(defexpr), RelationGetRelid(rel))); + PopOverrideSearchPath(); + } + + currentEventTriggerState->currentCommand->d.alterTable.subcmds = + lappend(currentEventTriggerState->currentCommand->d.alterTable.subcmds, newsub); + + MemoryContextSwitchTo(oldcxt); +} + +/* + * EventTriggerAlterTypeEnd + * Finish up saving an ALTER TYPE command, and add it to command list. + */ +void EventTriggerAlterTypeEnd(Node *subcmd, ObjectAddress address, int rewrite) +{ + MemoryContext oldcxt; + CollectedATSubcmd *newsub; + ListCell *cell; + CollectedCommand *cmd; + AlterTableCmd *altsubcmd = (AlterTableCmd *)subcmd; + + /* ignore if event trigger context not set, or collection disabled */ + if (!currentEventTriggerState || currentEventTriggerState->commandCollectionInhibited) { + return; + } + + cmd = currentEventTriggerState->currentCommand; + + Assert(IsA(subcmd, AlterTableCmd)); + Assert(cmd != NULL); + Assert(OidIsValid(cmd->d.alterTable.objectId)); + + foreach(cell, cmd->d.alterTable.subcmds) { + CollectedATSubcmd *sub = (CollectedATSubcmd *) lfirst(cell); + AlterTableCmd *collcmd = (AlterTableCmd *) sub->parsetree; + + if (collcmd->subtype == altsubcmd->subtype && + address.classId == sub->address.classId && + address.objectId == sub->address.objectId && + address.objectSubId == sub->address.objectSubId) { + cmd->d.alterTable.rewrite |= rewrite; + return; + } + } + + oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt); + + newsub = (CollectedATSubcmd*)palloc(sizeof(CollectedATSubcmd)); + newsub->address = address; + newsub->parsetree = (Node *) copyObject(subcmd); + + cmd->d.alterTable.rewrite |= rewrite; + cmd->d.alterTable.subcmds = lappend(cmd->d.alterTable.subcmds, newsub); + + MemoryContextSwitchTo(oldcxt); +} + +void EventTriggerAlterTypeUpdate(ObjectAddress address, AttrNumber old_attnum) +{ + ListCell *cell; + CollectedCommand *cmd; + + /* ignore if event trigger context not set, or collection disabled */ + if (!currentEventTriggerState || currentEventTriggerState->commandCollectionInhibited) { + return; + } + + cmd = currentEventTriggerState->currentCommand; + + Assert(cmd != NULL); + Assert(OidIsValid(cmd->d.alterTable.objectId)); + + foreach(cell, cmd->d.alterTable.subcmds) { + CollectedATSubcmd *sub = (CollectedATSubcmd *) lfirst(cell); + AlterTableCmd *collcmd = (AlterTableCmd *) sub->parsetree; + + if (collcmd->subtype == AT_AlterColumnType&& + address.classId == sub->address.classId && + address.objectId == sub->address.objectId && + old_attnum == sub->address.objectSubId) { + sub->address.objectSubId = address.objectSubId; + return; + } + } +} + /* * EventTriggerAlterTableEnd * Finish up saving an ALTER TABLE command, and add it to command list. diff --git a/src/gausskernel/optimizer/commands/eventcmds.cpp b/src/gausskernel/optimizer/commands/eventcmds.cpp index 6324eab3e..258e50ca0 100755 --- a/src/gausskernel/optimizer/commands/eventcmds.cpp +++ b/src/gausskernel/optimizer/commands/eventcmds.cpp @@ -199,6 +199,28 @@ Datum ParseIntevalExpr(Node *intervalNode) return CStringGetTextDatum(buf.data); } +char* parseIntervalExprString(Node *intervalNode) +{ + char *res; + StringInfoData buf; + initStringInfo(&buf); + + TypeCast *tc = (TypeCast *)intervalNode; + A_Const *ac = (A_Const *)tc->arg; + A_Const *tm = (A_Const *)lfirst(list_head(tc->typname->typmods)); + const char *tm_str = NULL; + tm_str = IntervalTypmodParse(tm); + if (IsA(&ac->val, Integer)) { + char *quantity_str = (char *)palloc(INTERVAL_QUALITY_LENGTH); + pg_itoa((int)ac->val.val.ival, quantity_str); + appendStringInfo(&buf, " \'%s\' ", quantity_str); + } else if (IsA(&ac->val, String) || IsA(&ac->val, Float)) { + appendStringInfo(&buf, " \'%s\' ", (char *)ac->val.val.str); + } + appendStringInfo(&buf, "%s", tm_str); + return pstrdup(buf.data); +} + Datum ExecTimeExpr(Node *node) { /* Check whether the execution result of the time expression is of the timestamp type */ @@ -232,6 +254,14 @@ Datum ExecTimeExpr(Node *node) return result; } +char* parseTimeExprString(Node* timeEexpr) +{ + Datum timeres; + + timeres = ExecTimeExpr(timeEexpr); + return DatumGetCString(DirectFunctionCall1(timestamp_out, timeres)); +} + void GetTimeExecResult(CreateEventStmt *stmt, Datum &start_time, Datum &interval_time, Datum &end_time) { /* Parse Interval Expression */ @@ -453,19 +483,28 @@ void CheckEventPrivilege(char* schema_name, char* event_name, AclMode mode, bool ReleaseSysCache(tup); } -void CreateEventCommand(CreateEventStmt *stmt) +ObjectAddress CreateEventCommand(CreateEventStmt *stmt) { + ObjectAddress myself; + char *event_name_str = stmt->event_name->relname; char *schema_name_str = (stmt->event_name->schemaname) ? stmt->event_name->schemaname : get_real_search_schema(); + if (!stmt->event_name->schemaname) { + stmt->event_name->schemaname = pstrdup(schema_name_str); + } CheckEventPrivilege(schema_name_str, event_name_str, ACL_CREATE, true); + myself.classId = PgJobRelationId; + myself.objectId = 0; + myself.objectSubId = 0; + Datum schema_name = DirectFunctionCall1(namein, CStringGetDatum(schema_name_str)); Datum ev_name = CStringGetTextDatum(event_name_str); FunctionCallInfoData ev_arg; const short nrgs_job = ARG_19; if (CheckEventExists(ev_name, stmt->if_not_exists)) { - return; + return myself; } InitFunctionCallInfoData(ev_arg, NULL, nrgs_job, InvalidOid, NULL, NULL); @@ -478,6 +517,8 @@ void CreateEventCommand(CreateEventStmt *stmt) PrepareFuncArg(stmt, ev_name, schema_name, &ev_arg); create_job_raw(&ev_arg); + + return myself; } Datum GetInlineJobName(Datum ev_name) @@ -837,10 +878,14 @@ void UpdatePgJobParam(AlterEventStmt *stmt, Datum ev_name) UpdateMultiJob(ev_name, values, nulls, replaces); } -void AlterEventCommand(AlterEventStmt *stmt) +ObjectAddress AlterEventCommand(AlterEventStmt *stmt) { + ObjectAddress myself; char *event_name_str = stmt->event_name->relname; char *schema_name_str = (stmt->event_name->schemaname) ? stmt->event_name->schemaname : get_real_search_schema(); + if (!stmt->event_name->schemaname) { + stmt->event_name->schemaname = pstrdup(schema_name_str); + } Datum ev_name = CStringGetTextDatum(event_name_str); CheckEventPrivilege(schema_name_str, event_name_str, ACL_USAGE, false); @@ -859,13 +904,20 @@ void AlterEventCommand(AlterEventStmt *stmt) UpdateAttributeParam(stmt, ev_name); UpdatePgJobProcParam(stmt, ev_name); UpdatePgJobParam(stmt, ev_name); + + myself.classId = PgJobRelationId; + myself.objectId = 0; + myself.objectSubId = 0; + return myself; } void DropEventCommand(DropEventStmt *stmt) { char *event_name_str = stmt->event_name->relname; char *schema_name_str = (stmt->event_name->schemaname) ? stmt->event_name->schemaname : get_real_search_schema(); - + if (!stmt->event_name->schemaname) { + stmt->event_name->schemaname = pstrdup(schema_name_str); + } Datum ev_name = CStringGetTextDatum(event_name_str); if (CheckEventNotExists(ev_name, stmt->missing_ok)) { return; diff --git a/src/gausskernel/optimizer/commands/publicationcmds.cpp b/src/gausskernel/optimizer/commands/publicationcmds.cpp index 9b771e41e..4ff29d90c 100644 --- a/src/gausskernel/optimizer/commands/publicationcmds.cpp +++ b/src/gausskernel/optimizer/commands/publicationcmds.cpp @@ -59,13 +59,14 @@ static void CloseTableList(List *rels); static void PublicationAddTables(Oid pubid, List *rels, bool if_not_exists, AlterPublicationStmt *stmt); static void PublicationDropTables(Oid pubid, List *rels, bool missing_ok); -static void parse_publication_options(List *options, - bool *publish_given, - bool *publish_insert, - bool *publish_update, - bool *publish_delete, - bool *publish_ddl_given, - int64 *pubddl) +static void parse_publication_options(List *options, + bool *publish_given, + bool *publish_insert, + bool *publish_update, + bool *publish_delete, + bool *publish_truncate, + bool *publish_ddl_given, + int64 *pubddl) { ListCell *lc; @@ -76,6 +77,7 @@ static void parse_publication_options(List *options, *publish_insert = true; *publish_update = true; *publish_delete = true; + *publish_truncate = true; *pubddl = 0; /* Parse options */ @@ -97,6 +99,7 @@ static void parse_publication_options(List *options, *publish_insert = false; *publish_update = false; *publish_delete = false; + *publish_truncate = false; *publish_given = true; publish = defGetString(defel); @@ -113,6 +116,8 @@ static void parse_publication_options(List *options, *publish_update = true; else if (strcmp(publish_opt, "delete") == 0) *publish_delete = true; + else if (strcmp(publish_opt, "truncate") == 0) + *publish_truncate = true; else ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("unrecognized \"publish\" value: \"%s\"", publish_opt))); @@ -200,23 +205,51 @@ CreateDDLReplicaEventTrigger(char *eventname, List *commands, ObjectAddress puba recordDependencyOn(&referenced, &pubaddress, DEPENDENCY_INTERNAL); } -static void -AddAllDDLReplicaEventTriggers(List *end_commands) +static void AddAllDDLReplicaEventTriggers(List *end_commands) { end_commands = lappend(end_commands, makeString("CREATE INDEX")); end_commands = lappend(end_commands, makeString("DROP INDEX")); + end_commands = lappend(end_commands, makeString("ALTER INDEX")); + end_commands = lappend(end_commands, makeString("CREATE SEQUENCE")); + end_commands = lappend(end_commands, makeString("ALTER SEQUENCE")); + end_commands = lappend(end_commands, makeString("DROP SEQUENCE")); + end_commands = lappend(end_commands, makeString("CREATE SCHEMA")); + end_commands = lappend(end_commands, makeString("ALTER SCHEMA")); + end_commands = lappend(end_commands, makeString("DROP SCHEMA")); + end_commands = lappend(end_commands, makeString("COMMENT")); + end_commands = lappend(end_commands, makeString("CREATE VIEW")); + end_commands = lappend(end_commands, makeString("ALTER VIEW")); + end_commands = lappend(end_commands, makeString("DROP VIEW")); + end_commands = lappend(end_commands, makeString("CREATE FUNCTION")); + end_commands = lappend(end_commands, makeString("ALTER FUNCTION")); + end_commands = lappend(end_commands, makeString("DROP FUNCTION")); + end_commands = lappend(end_commands, makeString("CREATE TRIGGER")); + end_commands = lappend(end_commands, makeString("ALTER TRIGGER")); + end_commands = lappend(end_commands, makeString("DROP TRIGGER")); + end_commands = lappend(end_commands, makeString("CREATE TYPE")); + end_commands = lappend(end_commands, makeString("ALTER TYPE")); + end_commands = lappend(end_commands, makeString("DROP TYPE")); + if(DB_IS_CMPT(B_FORMAT)) { + end_commands = lappend(end_commands, makeString("CREATE EVENT")); + end_commands = lappend(end_commands, makeString("ALTER EVENT")); + end_commands = lappend(end_commands, makeString("DROP EVENT")); + } } /* * If DDL replication is enabled, create event triggers to capture and log any * relevant events. */ -static void -CreateDDLReplicaEventTriggers(ObjectAddress pubaddress, Oid puboid) +static void CreateDDLReplicaEventTriggers(ObjectAddress pubaddress, Oid puboid) { List *start_commands = list_make1(makeString("DROP TABLE")); - List *end_commands = NIL; - end_commands = lappend(end_commands, makeString("CREATE TABLE")); + start_commands = lappend(start_commands, makeString("DROP INDEX")); + start_commands = lappend(start_commands, makeString("DROP TYPE")); + + List *rewrite_commands = list_make1(makeString("ALTER TABLE")); + + List *end_commands = list_make1(makeString("CREATE TABLE")); + end_commands = lappend(end_commands, makeString("ALTER TABLE")); end_commands = lappend(end_commands, makeString("DROP TABLE")); AddAllDDLReplicaEventTriggers(end_commands); @@ -225,13 +258,15 @@ CreateDDLReplicaEventTriggers(ObjectAddress pubaddress, Oid puboid) /* Create the ddl_command_start event trigger */ CreateDDLReplicaEventTrigger(PUB_TRIG_DDL_CMD_START, start_commands, pubaddress, puboid); + + /* Create the table_rewrite event trigger */ + CreateDDLReplicaEventTrigger(PUB_TRIG_TBL_REWRITE, rewrite_commands, pubaddress, puboid); } /* * Helper function to drop an event trigger for DDL replication. */ -static void -DropDDLReplicaEventTrigger(char *eventname, Oid puboid) +static void DropDDLReplicaEventTrigger(char *eventname, Oid puboid) { char trigger_name[NAMEDATALEN]; Oid evtoid; @@ -260,11 +295,11 @@ DropDDLReplicaEventTrigger(char *eventname, Oid puboid) /* * Drop all the event triggers which are used for DDL replication. */ -static void -DropDDLReplicaEventTriggers(Oid puboid) +static void DropDDLReplicaEventTriggers(Oid puboid) { DropDDLReplicaEventTrigger(PUB_TRIG_DDL_CMD_START, puboid); DropDDLReplicaEventTrigger(PUB_TRIG_DDL_CMD_END, puboid); + DropDDLReplicaEventTrigger(PUB_TRIG_TBL_REWRITE, puboid); } /* @@ -287,6 +322,7 @@ ObjectAddress CreatePublication(CreatePublicationStmt *stmt) bool publish_insert; bool publish_update; bool publish_delete; + bool publish_truncate; bool publish_ddl_given; int64 pubddl; AclResult aclresult; @@ -319,15 +355,15 @@ ObjectAddress CreatePublication(CreatePublicationStmt *stmt) values[Anum_pg_publication_pubname - 1] = DirectFunctionCall1(namein, CStringGetDatum(stmt->pubname)); values[Anum_pg_publication_pubowner - 1] = ObjectIdGetDatum(GetUserId()); - parse_publication_options(stmt->options, &publish_given, - &publish_insert, &publish_update, &publish_delete, - &publish_ddl_given, &pubddl); + parse_publication_options(stmt->options, &publish_given, &publish_insert, &publish_update, &publish_delete, + &publish_truncate, &publish_ddl_given, &pubddl); values[Anum_pg_publication_puballtables - 1] = BoolGetDatum(stmt->for_all_tables); values[Anum_pg_publication_pubinsert - 1] = BoolGetDatum(publish_insert); values[Anum_pg_publication_pubupdate - 1] = BoolGetDatum(publish_update); values[Anum_pg_publication_pubdelete - 1] = BoolGetDatum(publish_delete); values[Anum_pg_publication_pubddl - 1] = Int64GetDatum(pubddl); + values[Anum_pg_publication_pubtruncate - 1] = BoolGetDatum(publish_truncate); tup = heap_form_tuple(RelationGetDescr(rel), values, nulls); @@ -396,6 +432,7 @@ static void AlterPublicationOptions(AlterPublicationStmt *stmt, Relation rel, He bool publish_insert; bool publish_update; bool publish_delete; + bool publish_truncate; bool publish_ddl_given; int64 pubddl; bool pubddl_change = false; @@ -404,9 +441,8 @@ static void AlterPublicationOptions(AlterPublicationStmt *stmt, Relation rel, He Form_pg_publication pubform; pubform = (Form_pg_publication)GETSTRUCT(tup); - parse_publication_options(stmt->options, &publish_given, - &publish_insert, &publish_update, &publish_delete, - &publish_ddl_given, &pubddl); + parse_publication_options(stmt->options, &publish_given, &publish_insert, &publish_update, &publish_delete, + &publish_truncate, &publish_ddl_given, &pubddl); /* Everything ok, form a new tuple. */ rc = memset_s(values, sizeof(values), 0, sizeof(values)); @@ -425,6 +461,9 @@ static void AlterPublicationOptions(AlterPublicationStmt *stmt, Relation rel, He values[Anum_pg_publication_pubdelete - 1] = BoolGetDatum(publish_delete); replaces[Anum_pg_publication_pubdelete - 1] = true; + + values[Anum_pg_publication_pubtruncate - 1] = BoolGetDatum(publish_truncate); + replaces[Anum_pg_publication_pubtruncate - 1] = true; } if (publish_ddl_given) { diff --git a/src/gausskernel/optimizer/commands/subscriptioncmds.cpp b/src/gausskernel/optimizer/commands/subscriptioncmds.cpp index 440eb0a96..b0c32e6c5 100644 --- a/src/gausskernel/optimizer/commands/subscriptioncmds.cpp +++ b/src/gausskernel/optimizer/commands/subscriptioncmds.cpp @@ -94,6 +94,8 @@ static void ValidateReplicationSlot(char *slotname, List *publications); static List *fetch_table_list(List *publications); static void ReportSlotConnectionError(List *rstates, Oid subid, char *slotname); static bool CheckPublicationsExistOnPublisher(List *publications); +static bool CheckCompatibilityForDDLPublications(const char* conninfo, List *publications); +static bool CheckDDLPublicationsExists(List *publications); /* * Common option parsing function for CREATE and ALTER SUBSCRIPTION commands. @@ -617,6 +619,14 @@ ObjectAddress CreateSubscription(CreateSubscriptionStmt *stmt, bool isTopLevel) ereport(ERROR, (errmsg("There are some publications not exist on the publisher."))); } + if (!CheckCompatibilityForDDLPublications(encryptConninfo, publications)) { + (WalReceiverFuncTable[GET_FUNC_IDX]).walrcv_disconnect(); + ereport( + ERROR, + (errmsg( + "There are some publications replicate ddl but dbcompatibility is different with subscriptor"))); + } + /* * If requested, create the replication slot on remote side for our * newly created subscription. @@ -1007,6 +1017,15 @@ ObjectAddress AlterSubscription(AlterSubscriptionStmt *stmt, bool isTopLevel) (WalReceiverFuncTable[GET_FUNC_IDX]).walrcv_disconnect(); ereport(ERROR, (errmsg("There are some publications not exist on the publisher."))); } + + if (!CheckCompatibilityForDDLPublications(encryptConninfo, opts.publications)) { + (WalReceiverFuncTable[GET_FUNC_IDX]).walrcv_disconnect(); + ereport( + ERROR, + (errmsg( + "There are some publications replicate ddl but dbcompatibility is different with subscriptor"))); + } + (WalReceiverFuncTable[GET_FUNC_IDX]).walrcv_disconnect(); } @@ -1029,6 +1048,14 @@ ObjectAddress AlterSubscription(AlterSubscriptionStmt *stmt, bool isTopLevel) ereport(ERROR, (errmsg("There are some publications not exist on the publisher."))); } + if (!CheckCompatibilityForDDLPublications(encryptConninfo, opts.publications)) { + (WalReceiverFuncTable[GET_FUNC_IDX]).walrcv_disconnect(); + ereport( + ERROR, + (errmsg( + "There are some publications replicate ddl but dbcompatibility is different with subscriptor"))); + } + if (createSlot) { CreateSlotInPublisherAndInsertSubRel(finalSlotName, subid, opts.publications, NULL, true); } @@ -1718,3 +1745,136 @@ static bool CheckPublicationsExistOnPublisher(List *publications) return exists; } + + +static bool CheckCompatibilityForDDLPublications(const char* conninfo, List *publications) +{ + Assert(list_length(publications) > 0); + bool checkres = false; + char *datname = NULL; + List* conninfoList = ConninfoToDefList(conninfo); + ListCell* l = NULL; + foreach (l, conninfoList) { + DefElem* defel = (DefElem*)lfirst(l); + if (pg_strcasecmp(defel->defname, "dbname") == 0) { + datname = defGetString(defel); + } + } + + if (!datname) { + ereport(ERROR, (errmsg("Failed to get dbname from the conninfo."))); + } + + StringInfoData cmd; + initStringInfo(&cmd); + appendStringInfo(&cmd, + "SELECT d.datcompatibility FROM pg_catalog.pg_attribute a JOIN pg_database d " + "ON a.attrelid=pg_catalog.regclass('pg_publication') AND a.attname='pubddl' " + "AND d.datname='%s'", + datname); + + WalRcvExecResult *res; + Oid tableRow[1] = {NAMEOID}; + res = (WalReceiverFuncTable[GET_FUNC_IDX]).walrcv_exec(cmd.data, 1, tableRow); + + FreeStringInfo(&cmd); + ClearListContent(conninfoList); + list_free_ext(conninfoList); + + if (res->status != WALRCV_OK_TUPLES) { + ereport(ERROR, (errmsg("Failed to get publication datcompatibility from the publisher."))); + } + + if (tuplestore_get_memtupcount(res->tuplestore) > 0) { + checkres = true; + char *datcompatibility = NULL; + bool isnull = false; + int expected_db_cmpt = u_sess->attr.attr_sql.sql_compatibility; + TupleTableSlot *slot = MakeSingleTupleTableSlot(res->tupledesc); + if (tuplestore_gettupleslot(res->tuplestore, true, false, slot)) { + Datum datum = tableam_tslot_getattr(slot, 1, &isnull); + Assert(!isnull); + + datcompatibility = pstrdup(NameStr(*(DatumGetName(datum)))); + + switch (expected_db_cmpt) { + case A_FORMAT: + checkres = !pg_strcasecmp(datcompatibility, g_dbCompatArray[DB_CMPT_A].name); + break; + case B_FORMAT: + checkres = !pg_strcasecmp(datcompatibility, g_dbCompatArray[DB_CMPT_B].name); + break; + case C_FORMAT: + checkres = !pg_strcasecmp(datcompatibility, g_dbCompatArray[DB_CMPT_C].name); + break; + case PG_FORMAT: + checkres = !pg_strcasecmp(datcompatibility, g_dbCompatArray[DB_CMPT_PG].name); + break; + default: + checkres = false; + } + + ExecClearTuple(slot); + walrcv_clear_result(res); + pfree(datcompatibility); + + /* now check if the publications have ddl publications + * if there is no ddl replication, the different dbcompatibility + * is acceptable + */ + if (!checkres) { + if (!CheckDDLPublicationsExists(publications)) { + checkres = true; + } + } + } else { + /* can not get tupleslot */ + checkres = false; + } + } else { + /* there is no pubddl column in pg_publication, + * maybe publisher have not support ddl replication yet + */ + walrcv_clear_result(res); + checkres = true; + } + + return checkres; +} + +static bool CheckDDLPublicationsExists(List *publications) +{ + StringInfoData cmd; + initStringInfo(&cmd); + appendStringInfo(&cmd, "SELECT 1 FROM pg_catalog.pg_publication t" + " WHERE t.pubddl != 0 AND t.pubname IN ("); + ListCell *lc; + bool first = true; + foreach (lc, publications) { + char *pubname = strVal(lfirst(lc)); + if (first) { + first = false; + } else { + appendStringInfoString(&cmd, ", "); + } + appendStringInfo(&cmd, "%s", quote_literal_cstr(pubname)); + } + appendStringInfoString(&cmd, ")"); + + WalRcvExecResult *res; + Oid tableRow[1] = {INT4OID}; + res = (WalReceiverFuncTable[GET_FUNC_IDX]).walrcv_exec(cmd.data, 1, tableRow); + FreeStringInfo(&cmd); + + if (res->status != WALRCV_OK_TUPLES) { + ereport(ERROR, (errmsg("Failed to get DDL publication list from the publisher."))); + } + bool exists = false; + if (tuplestore_get_memtupcount(res->tuplestore) > 0) { + exists = true; + } + + walrcv_clear_result(res); + + return exists; +} diff --git a/src/gausskernel/optimizer/commands/tablecmds.cpp b/src/gausskernel/optimizer/commands/tablecmds.cpp index 7e038b65a..4fe2a236c 100755 --- a/src/gausskernel/optimizer/commands/tablecmds.cpp +++ b/src/gausskernel/optimizer/commands/tablecmds.cpp @@ -139,6 +139,7 @@ #include "storage/tcap.h" #include "streaming/streaming_catalog.h" #include "tcop/utility.h" +#include "tcop/ddldeparse.h" #include "utils/acl.h" #include "utils/aiomem.h" #include "utils/builtins.h" @@ -278,6 +279,8 @@ typedef struct NewColumnValue { bool is_generated; /* is it a GENERATED expression? */ bool is_autoinc; bool is_addloc; /* is add column first or after */ + bool is_alter_using; /* have alter type using clause */ + bool make_dml_change; AttrNumber newattnum; /* is modify column first or after -1 denote add; 0 denote modify without first|after; @@ -797,6 +800,37 @@ static void check_unsupported_charset_for_column(Oid collation, const char* col_ static void AlterTableNamespaceDependentProcess(Relation classRel ,Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses* objsMoved, char* newrelname); + +static inline void validate_relation_kind(Relation r) +{ + if (r->rd_rel->relkind == RELKIND_INDEX || + // r->rd_rel->relkind == RELKIND_PARTITIONED_INDEX || + r->rd_rel->relkind == RELKIND_COMPOSITE_TYPE) + elog(ERROR, + "cannot open relation \"%s\"", + RelationGetRelationName(r)); +} + +/* ---------------- + * table_open - open a table relation by relation OID + * + * This is essentially relation_open plus check that the relation + * is not an index nor a composite type. (The caller should also + * check that it's not a view or foreign table before assuming it has + * storage.) + * ---------------- + */ +Relation table_open(Oid relationId, LOCKMODE lockmode) +{ + Relation r; + + r = relation_open(relationId, lockmode); + + validate_relation_kind(r); + + return r; +} + inline static bool CStoreSupportATCmd(AlterTableType cmdtype) { bool ret = false; @@ -4292,15 +4326,9 @@ void ExecuteTruncate(TruncateStmt* stmt) { List* rels = NIL; List* relids = NIL; - List* seq_relids = NIL; - List* autoinc_seqoids = NIL; + List* relids_logged = NIL; List* rels_in_redis = NIL; - EState* estate = NULL; - ResultRelInfo* resultRelInfos = NULL; - ResultRelInfo* resultRelInfo = NULL; - SubTransactionId mySubid; ListCell* cell = NULL; - bool isDfsTruncate = false; #ifdef PGXC char* FirstExecNode = NULL; bool isFirstNode = false; @@ -4430,6 +4458,10 @@ void ExecuteTruncate(TruncateStmt* stmt) rels = lappend(rels, rel); relids = lappend_oid(relids, myrelid); + /* Log this relation only if needed for logical decoding */ + if (RelationIsLogicallyLogged(rel)) + relids_logged = lappend_oid(relids_logged, myrelid); + if (recurse) { ListCell* child = NULL; List* children = NIL; @@ -4447,6 +4479,9 @@ void ExecuteTruncate(TruncateStmt* stmt) truncate_check_rel(rel); rels = lappend(rels, rel); relids = lappend_oid(relids, childrelid); + /* Log this relation only if needed for logical decoding */ + if (RelationIsLogicallyLogged(rel)) + relids_logged = lappend_oid(relids_logged, childrelid); } } @@ -4518,21 +4553,66 @@ void ExecuteTruncate(TruncateStmt* stmt) #endif } + ExecuteTruncateGuts(rels, relids, relids_logged, rels_in_redis, + stmt->behavior, stmt->restart_seqs, stmt); + + /* And close the rels */ + foreach(cell, rels) + { + Relation rel = (Relation) lfirst(cell); + + heap_close(rel, NoLock); + } +} + + +/* + * ExecuteTruncateGuts + * + * Internal implementation of TRUNCATE. This is called by the actual TRUNCATE + * command (see above) as well as replication subscribers that execute a + * replicated TRUNCATE action. + * + * explicit_rels is the list of Relations to truncate that the command + * specified. relids is the list of Oids corresponding to explicit_rels. + * relids_logged is the list of Oids (a subset of relids) that require + * WAL-logging. This is all a bit redundant, but the existing callers have + * this information handy in this form. + */ +void ExecuteTruncateGuts( + List *explicit_rels, List *relids, List *relids_logged, List *rels_in_redis, + DropBehavior behavior, bool restart_seqs, TruncateStmt* stmt) +{ + List *rels; + List *seq_relids = NIL; + EState *estate; + ResultRelInfo *resultRelInfos; + ResultRelInfo *resultRelInfo; + SubTransactionId mySubid; + ListCell *cell; + Oid *logrelids; + List* autoinc_seqoids = NIL; + bool isDfsTruncate = false; + /* - * In CASCADE mode, suck in all referencing relations as well. This + * Open, exclusive-lock, and check all the explicitly-specified relations + * + * In CASCADE mode, suck in all referencing relations as well. This * requires multiple iterations to find indirectly-dependent relations. At * each phase, we need to exclusive-lock new rels before looking for their - * dependencies, else we might miss something. Also, we check each rel as + * dependencies, else we might miss something. Also, we check each rel as * soon as we open it, to avoid a faux pas such as holding lock for a long * time on a rel we have no permissions for. */ - if (stmt->behavior == DROP_CASCADE) { + rels = list_copy(explicit_rels); + if (behavior == DROP_CASCADE) { for (;;) { List* newrelids = NIL; newrelids = heap_truncate_find_FKs(relids); - if (newrelids == NIL) + if (newrelids == NIL) { break; /* nothing else to add */ + } foreach (cell, newrelids) { Oid relid = lfirst_oid(cell); @@ -4547,6 +4627,9 @@ void ExecuteTruncate(TruncateStmt* stmt) truncate_check_rel(rel); rels = lappend(rels, rel); relids = lappend_oid(relids, relid); + /* Log this relation only if needed for logical decoding */ + if (RelationIsLogicallyLogged(rel)) + relids_logged = lappend_oid(relids_logged, relid); } } } @@ -4559,7 +4642,7 @@ void ExecuteTruncate(TruncateStmt* stmt) #ifdef USE_ASSERT_CHECKING heap_truncate_check_FKs(rels, false); #else - if (stmt->behavior == DROP_RESTRICT) + if (behavior == DROP_RESTRICT) heap_truncate_check_FKs(rels, false); #endif @@ -4569,7 +4652,7 @@ void ExecuteTruncate(TruncateStmt* stmt) * We want to do this early since it's pointless to do all the truncation * work only to fail on sequence permissions. */ - if (stmt->restart_seqs) { + if (restart_seqs) { foreach (cell, rels) { Relation rel = (Relation)lfirst(cell); List* seqlist = getOwnedSequences(RelationGetRelid(rel)); @@ -4787,6 +4870,41 @@ void ExecuteTruncate(TruncateStmt* stmt) ResetSequence(seq_relid, true); } + /* + * Write a WAL record to allow this set of actions to be logically decoded. + * + * Assemble an array of relids so we can write a single WAL record for the + * whole action. + */ + if (list_length(relids_logged) > 0) + { + xl_heap_truncate xlrec; + int i = 0; + + /* should only get here if wal_level >= logical */ + Assert(XLogLogicalInfoActive()); + + logrelids = (Oid*)palloc(list_length(relids_logged) * sizeof(Oid)); + foreach (cell, relids_logged) + logrelids[i++] = lfirst_oid(cell); + + xlrec.dbId = u_sess->proc_cxt.MyDatabaseId; + xlrec.nrelids = list_length(relids_logged); + xlrec.flags = 0; + if (behavior == DROP_CASCADE) + xlrec.flags |= XLH_TRUNCATE_CASCADE; + if (restart_seqs) + xlrec.flags |= XLH_TRUNCATE_RESTART_SEQS; + + XLogBeginInsert(); + XLogRegisterData((char *) &xlrec, SizeOfHeapTruncate); + XLogRegisterData((char *) logrelids, list_length(relids_logged) * sizeof(Oid)); + + // XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN); + + (void) XLogInsert(RM_HEAP3_ID, XLOG_HEAP3_TRUNCATE); + } + /* * Process all AFTER STATEMENT TRUNCATE triggers. */ @@ -4798,86 +4916,88 @@ void ExecuteTruncate(TruncateStmt* stmt) } #ifdef ENABLE_MULTIPLE_NODES - /* - * In Postgres-XC, TRUNCATE needs to be launched to remote nodes before the - * AFTER triggers are launched. This insures that the triggers are being fired - * by correct events. - */ - if (IS_PGXC_COORDINATOR && !IsConnFromCoord()) { - if (u_sess->attr.attr_sql.enable_parallel_ddl && !isFirstNode) { - bool is_temp = false; - RemoteQuery* step = makeNode(RemoteQuery); - ExecNodes* exec_nodes = NULL; + if (stmt) { + /* + * In Postgres-XC, TRUNCATE needs to be launched to remote nodes before the + * AFTER triggers are launched. This insures that the triggers are being fired + * by correct events. + */ + if (IS_PGXC_COORDINATOR && !IsConnFromCoord()) { + if (u_sess->attr.attr_sql.enable_parallel_ddl && !isFirstNode) { + bool is_temp = false; + RemoteQuery* step = makeNode(RemoteQuery); + ExecNodes* exec_nodes = NULL; - /* Check un-allowed case where truncate tables from different node groups */ - if (!ObjectsInSameNodeGroup(stmt->relations, T_TruncateStmt)) { - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("NOT-SUPPORT: Not support TRUNCATE multiple objects different nodegroup"))); - } - - foreach (cell, stmt->relations) { - Oid relid; - RangeVar* rel = (RangeVar*)lfirst(cell); - - relid = RangeVarGetRelid(rel, NoLock, false); - - if (exec_nodes == NULL) { - exec_nodes = RelidGetExecNodes(relid); + /* Check un-allowed case where truncate tables from different node groups */ + if (!ObjectsInSameNodeGroup(stmt->relations, T_TruncateStmt)) { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("NOT-SUPPORT: Not support TRUNCATE multiple objects different nodegroup"))); } - if (IsTempTable(relid)) { - is_temp = true; - break; - } - } + foreach (cell, stmt->relations) { + Oid relid; + RangeVar* rel = (RangeVar*)lfirst(cell); - step->combine_type = COMBINE_TYPE_SAME; - step->exec_nodes = exec_nodes; - step->sql_statement = pstrdup(sql_statement); - step->force_autocommit = false; - step->exec_type = EXEC_ON_DATANODES; - step->is_temp = is_temp; - ExecRemoteUtility_ParallelDDLMode(step, FirstExecNode); - pfree_ext(step->sql_statement); - pfree_ext(step); - } else { - bool is_temp = false; - RemoteQuery* step = makeNode(RemoteQuery); - ExecNodes* exec_nodes = NULL; + relid = RangeVarGetRelid(rel, NoLock, false); - /* Check un-allowed case where truncate tables from different node groups */ - if (!ObjectsInSameNodeGroup(stmt->relations, T_TruncateStmt)) { - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("NOT-SUPPORT: Not support TRUNCATE multiple objects different nodegroup"))); - } + if (exec_nodes == NULL) { + exec_nodes = RelidGetExecNodes(relid); + } - foreach (cell, stmt->relations) { - Oid relid; - RangeVar* rel = (RangeVar*)lfirst(cell); - - relid = RangeVarGetRelid(rel, NoLock, false); - - if (exec_nodes == NULL) { - exec_nodes = RelidGetExecNodes(relid); + if (IsTempTable(relid)) { + is_temp = true; + break; + } } - if (IsTempTable(relid)) { - is_temp = true; - break; - } - } + step->combine_type = COMBINE_TYPE_SAME; + step->exec_nodes = exec_nodes; + step->sql_statement = pstrdup(sql_statement); + step->force_autocommit = false; + step->exec_type = EXEC_ON_DATANODES; + step->is_temp = is_temp; + ExecRemoteUtility_ParallelDDLMode(step, FirstExecNode); + pfree_ext(step->sql_statement); + pfree_ext(step); + } else { + bool is_temp = false; + RemoteQuery* step = makeNode(RemoteQuery); + ExecNodes* exec_nodes = NULL; - step->combine_type = COMBINE_TYPE_SAME; - step->exec_nodes = exec_nodes; - step->sql_statement = pstrdup(sql_statement); - step->force_autocommit = false; - step->exec_type = is_temp ? EXEC_ON_DATANODES : EXEC_ON_ALL_NODES; - step->is_temp = is_temp; - ExecRemoteUtility(step); - pfree_ext(step->sql_statement); - pfree_ext(step); + /* Check un-allowed case where truncate tables from different node groups */ + if (!ObjectsInSameNodeGroup(stmt->relations, T_TruncateStmt)) { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("NOT-SUPPORT: Not support TRUNCATE multiple objects different nodegroup"))); + } + + foreach (cell, stmt->relations) { + Oid relid; + RangeVar* rel = (RangeVar*)lfirst(cell); + + relid = RangeVarGetRelid(rel, NoLock, false); + + if (exec_nodes == NULL) { + exec_nodes = RelidGetExecNodes(relid); + } + + if (IsTempTable(relid)) { + is_temp = true; + break; + } + } + + step->combine_type = COMBINE_TYPE_SAME; + step->exec_nodes = exec_nodes; + step->sql_statement = pstrdup(sql_statement); + step->force_autocommit = false; + step->exec_type = is_temp ? EXEC_ON_DATANODES : EXEC_ON_ALL_NODES; + step->is_temp = is_temp; + ExecRemoteUtility(step); + pfree_ext(step->sql_statement); + pfree_ext(step); + } } } #endif @@ -4904,7 +5024,11 @@ void ExecuteTruncate(TruncateStmt* stmt) /* We can clean up the EState now */ FreeExecutorState(estate); - /* And close the rels (can't do this while EState still holds refs) */ + /* + * Close any rels opened by CASCADE (can't do this while EState still + * holds refs) + */ + rels = list_difference_ptr(rels, explicit_rels); foreach (cell, rels) { Relation rel = (Relation)lfirst(cell); @@ -6418,6 +6542,14 @@ static ObjectAddress RenameTableFeature(RenameStmt* stmt) storageTable[tableName_Count].schemaname = pstrdup(orgiSchema); storageTable[tableName_Count].relname = pstrdup(orgitable); tableName_Count++; + + if (temp_name->schemaname == NULL) { + if (t_thrd.mem_cxt.msg_mem_cxt) { + temp_name->schemaname = MemoryContextStrdup(t_thrd.mem_cxt.msg_mem_cxt, orgiSchema); + } else { + temp_name->schemaname = pstrdup(orgiSchema); + } + } } if (stmt->renameTargetList->length >= 2) { @@ -6489,6 +6621,10 @@ static ObjectAddress RenameTableFeature(RenameStmt* stmt) modfyNameSpace = orgiNameSpace; } + if (temp_name->schemaname == NULL) { + temp_name->schemaname = MemoryContextStrdup(t_thrd.mem_cxt.msg_mem_cxt, orgiSchema); + } + /* Check whether exist Synonym on old table name and new table name */ if (orgiSchema == NULL) { orgiSchema = get_namespace_name(relnamespace); @@ -6962,6 +7098,67 @@ void RenameRelationInternal(Oid myrelid, const char* newrelname, char* newschema relation_close(targetrelation, NoLock); } +/* + * ResetRelRewrite - reset relrewrite + */ +void ResetRelRewrite(Oid myrelid) +{ + HeapTuple newTuple; + Relation pg_class; + HeapTuple tuple; + Datum relOptions; + Datum newOptions; + List* defList = NIL; + Datum replVal[Natts_pg_class]; + bool replNull[Natts_pg_class]; + bool replRepl[Natts_pg_class]; + bool isNull = false; + bool removed = false; + errno_t rc; + + /* + * Find relation's pg_class tuple. + */ + pg_class = heap_open(RelationRelationId, RowExclusiveLock); + tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid)); + if (!HeapTupleIsValid(tuple)) { + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("could not find tuple for relation %u", myrelid))); + } + + relOptions = fastgetattr(tuple, Anum_pg_class_reloptions, RelationGetDescr(pg_class), &isNull); + if (!isNull) { + defList = untransformRelOptions(relOptions); + defList = RemoveRelOption(defList, "relrewrite", &removed); + if (removed) { + newOptions = transformRelOptions((Datum)0, defList, NULL, NULL, false, false); + + rc = memset_s(replVal, sizeof(replVal), 0, sizeof(replVal)); + securec_check(rc, "\0", "\0"); + rc = memset_s(replNull, sizeof(replNull), false, sizeof(replNull)); + securec_check(rc, "\0", "\0"); + rc = memset_s(replRepl, sizeof(replRepl), false, sizeof(replRepl)); + securec_check(rc, "\0", "\0"); + if (PointerIsValid(newOptions)) { + replVal[Anum_pg_class_reloptions - 1] = newOptions; + replNull[Anum_pg_class_reloptions - 1] = false; + } else { + replNull[Anum_pg_class_reloptions - 1] = true; + } + replRepl[Anum_pg_class_reloptions - 1] = true; + newTuple = heap_modify_tuple(tuple, RelationGetDescr(pg_class), replVal, replNull, replRepl); + simple_heap_update(pg_class, &newTuple->t_self, newTuple); + CatalogUpdateIndexes(pg_class, newTuple); + + heap_freetuple_ext(newTuple); + } + list_free_ext(defList); + } + heap_freetuple_ext(tuple); + + heap_close(pg_class, RowExclusiveLock); +} + /* * @@GaussDB@@ * Target : data distributed by range or list @@ -7534,7 +7731,7 @@ typedef enum { * 4. the default value is actually null */ static AT_INSTANT_DEFAULT_VALUE shouldUpdateAllTuples( - Expr* defaultExpr, Oid typeOid, int attLen, bool attByVal, bytea** defaultVal) + Expr* defaultExpr, Oid typeOid, int attLen, bool attByVal, bytea** defaultVal, char** initdefval) { bool isNull = false; int i; @@ -7609,6 +7806,13 @@ static AT_INSTANT_DEFAULT_VALUE shouldUpdateAllTuples( (void)MemoryContextSwitchTo(oldcxt); if (!isNull) { + if (initdefval) { + Oid typoutput = 0; + bool typisvarlena = false; + getTypeOutputInfo(typeOid, &typoutput, &typisvarlena); + *initdefval = pstrdup(OidOutputFunctionCall(typoutput, value)); + } + if (attByVal) { result = (bytea*)palloc(attLen + VARHDRSZ); SET_VARSIZE(result, attLen + VARHDRSZ); @@ -8258,6 +8462,8 @@ static void ATPrepCmd(List** wqueue, Relation rel, AlterTableCmd* cmd, bool recu * numbers in different children). */ cmd = (AlterTableCmd*)copyObject(cmd); + + cmd->recursing = recursing; /* * Do permissions checking, recursion to child tables if needed, and any * additional phase-1 processing needed. @@ -8409,6 +8615,7 @@ static void ATPrepCmd(List** wqueue, Relation rel, AlterTableCmd* cmd, bool recu break; case AT_AlterColumnType: /* ALTER COLUMN TYPE */ ATSimplePermissions(rel, ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE); + EventTriggerAlterTypeStart(cmd, rel); /* Performs own recursion */ ATPrepAlterColumnType(wqueue, tab, rel, recurse, recursing, cmd, lockmode); pass = AT_PASS_ALTER_TYPE; @@ -9060,6 +9267,7 @@ static void ATCreateColumComments(Oid relOid, ColumnDef* columnDef) static void ATExecCmd(List** wqueue, AlteredTableInfo* tab, Relation rel, AlterTableCmd* cmd, LOCKMODE lockmode, bool fromReplace) { ObjectAddress address = InvalidObjectAddress; + bool commandCollected = false; elog(ES_LOGLEVEL, "[ATExecCmd] cmd subtype: %d", cmd->subtype); if (PARTITION_DDL_CMD(cmd->subtype) && RELATION_IS_PARTITIONED(rel)) { @@ -9107,9 +9315,12 @@ static void ATExecCmd(List** wqueue, AlteredTableInfo* tab, Relation rel, AlterT break; case AT_AddStatistics: /* ADD STATISTICS */ ATExecAddStatistics(rel, cmd->def, lockmode); + /* prepare work es_check_alter_table_statistics broken the cmd->def, don't pass to event trigger */ + commandCollected = true; break; case AT_DeleteStatistics: /* DELETE STATISTICS */ ATExecDeleteStatistics(rel, cmd->def, lockmode); + commandCollected = true; break; case AT_SetOptions: /* ALTER COLUMN SET ( options ) */ address = ATExecSetOptions(rel, cmd->name, cmd->def, false, lockmode); @@ -9204,6 +9415,8 @@ static void ATExecCmd(List** wqueue, AlteredTableInfo* tab, Relation rel, AlterT break; case AT_AlterColumnType: /* ALTER COLUMN TYPE */ address = ATExecAlterColumnType(tab, rel, cmd, lockmode); + EventTriggerAlterTypeEnd((Node *) cmd, address, tab->rewrite); + commandCollected = true; break; case AT_AlterColumnGenericOptions: /* ALTER COLUMN OPTIONS */ address = ATExecAlterColumnGenericOptions(rel, cmd->name, (List*)cmd->def, lockmode); @@ -9398,12 +9611,6 @@ static void ATExecCmd(List** wqueue, AlteredTableInfo* tab, Relation rel, AlterT UpdatePgObjectMtime(tab->relid, objectType); } - /* - * Report the subcommand to interested event triggers. - */ - EventTriggerCollectAlterTableSubcmd((Node *) cmd, address); - - /* take ExclusiveLock to avoid PARTITION DDL COMMIT until we finish the InitPlan. Oid info will be masked here, and * be locked in CommitTransaction. Distribute mode doesn't support partition DDL/DML parallel work, no need this * action */ @@ -9413,6 +9620,12 @@ static void ATExecCmd(List** wqueue, AlteredTableInfo* tab, Relation rel, AlterT } #endif + /* + * Report the subcommand to interested event triggers. + */ + if (cmd && !commandCollected) + EventTriggerCollectAlterTableSubcmd((Node *) cmd, address, tab->rewrite); + /* * Bump the command counter to ensure the next subcommand in the sequence * can see the changes so far @@ -9759,6 +9972,185 @@ static void UpdateGeneratedColumnIsnull(AlteredTableInfo* tab, bool* isnull, boo } } +static void repl_update_addcolumn_default(AlteredTableInfo* tab, Relation oldrel, Relation newrel, List* notnull_attrs) +{ + TupleDesc newTupDesc; + int i; + ListCell* l = NULL; + EState* estate = NULL; + CommandId mycid; + BulkInsertState bistate; + uint32 hi_options; + newTupDesc = RelationGetDescr(oldrel); /* includes all mods */ + + CommandCounterIncrement(); + + mycid = GetCurrentCommandId(true); + + bistate = GetBulkInsertState(); + hi_options = TABLE_INSERT_SKIP_FSM; + + estate = CreateExecutorState(); + + ExprContext* econtext = NULL; + Datum* values = NULL; + bool* isnull = NULL; + bool* repl = NULL; + TupleTableSlot* newslot = NULL; + TableScanDesc scan; + HeapTuple tuple; + HeapTuple htup; + MemoryContext oldCxt; + errno_t rc = EOK; + + /* estate has been freed, prepare again */ + foreach (l, tab->constraints) { + NewConstraint* con = (NewConstraint*)lfirst(l); + if (con->isdisable) + continue; + + switch (con->contype) { + case CONSTR_CHECK: + if (estate->es_is_flt_frame){ + con->qualstate = (List*)ExecPrepareExprList((List*)con->qual, estate); + } else { + con->qualstate = (List*)ExecPrepareExpr((Expr*)con->qual, estate); + } + break; + case CONSTR_FOREIGN: + /* Nothing to do here */ + break; + default: { + ereport(ERROR, + (errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE), + errmsg("unrecognized constraint type: %d", (int)con->contype))); + } break; + } + } + + econtext = GetPerTupleExprContext(estate); + newslot = MakeSingleTupleTableSlot(newTupDesc, false, oldrel->rd_tam_ops); + + i = newTupDesc->natts; + values = (Datum*)palloc(i * sizeof(Datum)); + isnull = (bool*)palloc(i * sizeof(bool)); + repl = (bool*)palloc(i * sizeof(bool)); + rc = memset_s(values, i * sizeof(Datum), 0, i * sizeof(Datum)); + securec_check(rc, "\0", "\0"); + rc = memset_s(isnull, i * sizeof(bool), true, i * sizeof(bool)); + securec_check(rc, "\0", "\0"); + rc = memset_s(repl, i * sizeof(bool), false, i * sizeof(bool)); + securec_check(rc, "\0", "\0"); + + + scan = tableam_scan_begin(newrel, SnapshotNow, 0, NULL); + oldCxt = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate)); + + ((HeapScanDesc) scan)->rs_tupdesc = newTupDesc; + while ((tuple = (HeapTuple) tableam_scan_getnexttuple(scan, ForwardScanDirection)) != NULL) { + ItemPointer searchSlotTid; + searchSlotTid = tableam_tops_get_t_self(newrel, tuple); + tableam_tops_deform_tuple(tuple, newTupDesc, values, isnull); + + (void)ExecStoreTuple(tuple, newslot, InvalidBuffer, false); + econtext->ecxt_scantuple = newslot; + + foreach (l, tab->newvals) { + NewColumnValue* ex = (NewColumnValue*)lfirst(l); + /* ex->attnum 鍙兘涓嶆槸鏈缁堢殑瀛楁涓嬫爣 */ + if (ex->make_dml_change) { + int attnum = -1; + for (int n = 0; n < newTupDesc->natts; ++n) { + Form_pg_attribute thisattr = &newTupDesc->attrs[n]; + + /* skip the dropped and rewritted columns */ + if (!thisattr->attisdropped && ex->col_name && + pg_strcasecmp(ex->col_name, NameStr(thisattr->attname)) == 0) { + attnum = thisattr->attnum; + break; + } + } + + if (attnum <= 0) { + ereport(ERROR, ( + errmsg("can not find column \"%s\"", ex->col_name))); + } + + values[attnum - 1] = ExecEvalExpr(ex->exprstate, econtext, &isnull[attnum - 1], NULL); + repl[attnum - 1] = true; + } + } + + htup = heap_modify_tuple(tuple, newTupDesc, values, isnull, repl); + + /* Now check any constraints on the possibly-changed tuple */ + (void)ExecStoreTuple(htup, newslot, InvalidBuffer, false); + econtext->ecxt_scantuple = newslot; + + foreach (l, notnull_attrs) { + int attn = lfirst_int(l); + + /* replace heap_attisnull with relationAttIsNull + * due to altering table instantly + */ + if (relationAttIsNull(htup, attn + 1, newTupDesc)) + ereport(ERROR, (errcode(ERRCODE_NOT_NULL_VIOLATION), + errmsg("column \"%s\" contains null values", NameStr(newTupDesc->attrs[attn].attname)))); + } + + foreach (l, tab->constraints) { + NewConstraint* con = (NewConstraint*)lfirst(l); + + switch (con->contype) { + case CONSTR_CHECK: + if (!ExecQual(con->qualstate, econtext, true)) + ereport(ERROR, + (errcode(ERRCODE_CHECK_VIOLATION), + errmsg("check constraint \"%s\" is violated by some row", con->name))); + break; + case CONSTR_FOREIGN: + /* Nothing to do here */ + break; + default: { + ereport(ERROR, + (errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE), + errmsg("unrecognized constraint type: %d", (int)con->contype))); + } + } + } + + + TM_FailureData tmfd; + bool updateIndexes = false; + Bitmapset *modifiedIdxAttrs = NULL; + bool allowInplaceUpdate = true; + + (void)tableam_tuple_update(newrel, NULL, searchSlotTid, htup, mycid, InvalidSnapshot, estate->es_snapshot, true, &newslot, &tmfd, &updateIndexes, &modifiedIdxAttrs, + false, allowInplaceUpdate); + + ResetExprContext(econtext); + + CHECK_FOR_INTERRUPTS(); + } + + MemoryContextSwitchTo(oldCxt); + tableam_scan_end(scan); + ExecDropSingleTupleTableSlot(newslot); + + FreeExecutorState(estate); + FreeBulkInsertState(bistate); + if (((hi_options & TABLE_INSERT_SKIP_WAL) || enable_heap_bcm_data_replication()) && + !RelationIsSegmentTable(newrel)) + heap_sync(newrel); + /* + * After the temporary table is rewritten, the relfilenode changes. + * We need to find new TmptableCacheEntry with new relfilenode. + * Then set new auto_increment counter value in new TmptableCacheEntry. + */ + CopyTempAutoIncrement(oldrel, newrel); + +} + /* * change ATRewriteTable() input: oid->rel */ @@ -9783,6 +10175,9 @@ static void ATRewriteTableInternal(AlteredTableInfo* tab, Relation oldrel, Relat oldTupDesc = tab->oldDesc; newTupDesc = RelationGetDescr(oldrel); /* includes all mods */ + bool repl_modify = false; + bool need_dml_change_col = false; + /* * Prepare a BulkInsertState and options for heap_insert. Because we're * building a new heap, we can skip WAL-logging and fsync it to disk at @@ -9834,11 +10229,27 @@ static void ATRewriteTableInternal(AlteredTableInfo* tab, Relation oldrel, Relat } } + if (newrel && RelationIsRowFormat(oldrel) && + tab->rewrite > 0 && XLogLogicalInfoActive() && + oldrel->rd_rel->relpersistence != RELPERSISTENCE_TEMP && + oldrel->relreplident == REPLICA_IDENTITY_FULL) { + + repl_modify = true; + } + foreach (l, tab->newvals) { NewColumnValue* ex = (NewColumnValue*)lfirst(l); /* expr already planned */ ex->exprstate = ExecInitExpr((Expr*)ex->expr, NULL); + + if (ex->is_generated || ex->is_alter_using) { + repl_modify = false; + } + + if (ex->make_dml_change) { + need_dml_change_col = true; + } } notnull_attrs = NIL; @@ -10184,7 +10595,13 @@ static void ATRewriteTableInternal(AlteredTableInfo* tab, Relation oldrel, Relat continue; } - values[ex->attnum - 1] = ExecEvalExpr(ex->exprstate, econtext, &isnull[ex->attnum - 1]); + if (repl_modify && ex->make_dml_change) { + isnull[ex->attnum - 1] = true; + } else { + values[ex->attnum - 1] = ExecEvalExpr(ex->exprstate, econtext, &isnull[ex->attnum - 1]); + } + + if (ex->is_autoinc) { need_autoinc = (autoinc_attnum > 0); } @@ -10230,61 +10647,74 @@ static void ATRewriteTableInternal(AlteredTableInfo* tab, Relation oldrel, Relat */ tuple = EvaluateGenExpr(tab, tuple, newTupDesc, econtext, values, isnull); - foreach (l, notnull_attrs) { - int attn = lfirst_int(l); + if (!repl_modify) { + foreach (l, notnull_attrs) { + int attn = lfirst_int(l); - /* replace heap_attisnull with relationAttIsNull - * due to altering table instantly - */ - if (relationAttIsNull(tuple, attn + 1, newTupDesc)) - ereport(ERROR, (errcode(ERRCODE_NOT_NULL_VIOLATION), - errmsg("column \"%s\" contains null values", NameStr(newTupDesc->attrs[attn].attname)))); - } + /* replace heap_attisnull with relationAttIsNull + * due to altering table instantly + */ + if (relationAttIsNull(tuple, attn + 1, newTupDesc)) + ereport(ERROR, (errcode(ERRCODE_NOT_NULL_VIOLATION), + errmsg("column \"%s\" contains null values", NameStr(newTupDesc->attrs[attn].attname)))); + } - foreach (l, tab->constraints) { - NewConstraint* con = (NewConstraint*)lfirst(l); - ListCell* lc = NULL; + foreach (l, tab->constraints) { + NewConstraint* con = (NewConstraint*)lfirst(l); + ListCell* lc = NULL; - switch (con->contype) { - case CONSTR_CHECK: - { - if (estate->es_is_flt_frame){ - foreach (lc, con->qualstate) { - ExprState* exprState = (ExprState*)lfirst(lc); + switch (con->contype) { + case CONSTR_CHECK: + { + if (estate->es_is_flt_frame){ + foreach (lc, con->qualstate) { + ExprState* exprState = (ExprState*)lfirst(lc); - if (!ExecCheckByFlatten(exprState, econtext)) + if (!ExecCheckByFlatten(exprState, econtext)) + ereport(ERROR, + (errcode(ERRCODE_CHECK_VIOLATION), + errmsg("check constraint \"%s\" is violated by some row", + con->name))); + } + } else { + if (!ExecQualByRecursion(con->qualstate, econtext, true)){ ereport(ERROR, - (errcode(ERRCODE_CHECK_VIOLATION), - errmsg("check constraint \"%s\" is violated by some row", - con->name))); + (errcode(ERRCODE_CHECK_VIOLATION), + errmsg("check constraint \"%s\" is violated by some row", + con->name))); + } } - } else { - if (!ExecQualByRecursion(con->qualstate, econtext, true)){ - ereport(ERROR, - (errcode(ERRCODE_CHECK_VIOLATION), - errmsg("check constraint \"%s\" is violated by some row", - con->name))); } - } - } + break; + case CONSTR_FOREIGN: + /* Nothing to do here */ break; - case CONSTR_FOREIGN: - /* Nothing to do here */ - break; - default: { - ereport(ERROR, - (errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE), - errmsg("unrecognized constraint type: %d", (int)con->contype))); + default: { + ereport(ERROR, + (errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE), + errmsg("unrecognized constraint type: %d", (int)con->contype))); + } } } } /* Write the tuple out to the new relation */ if (newrel) { - (void)tableam_tuple_insert(newrel, tuple, mycid, hi_options, bistate); + if (repl_modify) { + /* deal with "add column c1 mytyp default expr" + */ + tuple = (HeapTuple)heap_form_tuple(newTupDesc, values, isnull); + (void)tableam_tuple_insert(newrel, tuple, mycid, hi_options, bistate); - if (autoinc > 0) { - SetRelAutoIncrement(oldrel, newTupDesc, autoinc); + if (autoinc > 0) { + SetRelAutoIncrement(oldrel, newTupDesc, autoinc); + } + } else { + (void)tableam_tuple_insert(newrel, tuple, mycid, hi_options, bistate); + + if (autoinc > 0) { + SetRelAutoIncrement(oldrel, newTupDesc, autoinc); + } } } ResetExprContext(econtext); @@ -10322,6 +10752,10 @@ static void ATRewriteTableInternal(AlteredTableInfo* tab, Relation oldrel, Relat */ CopyTempAutoIncrement(oldrel, newrel); } + + if (repl_modify) { + repl_update_addcolumn_default(tab, oldrel, newrel, notnull_attrs); + } } static void ATRewriteTable(AlteredTableInfo* tab, Relation oldrel, Relation newrel) @@ -10913,7 +11347,7 @@ static void ATPrepCheckDefault(Node* node) } static FORCE_INLINE void ATExecAppendDefValExpr(_in_ AttrNumber attnum, _in_ Expr* defval, _out_ AlteredTableInfo* tab, - ColumnDef *colDef, bool is_autoinc, bool is_addloc) + ColumnDef *colDef, bool is_autoinc, bool is_addloc, bool make_dml_change = false) { NewColumnValue* newval; @@ -10928,6 +11362,7 @@ static FORCE_INLINE void ATExecAppendDefValExpr(_in_ AttrNumber attnum, _in_ Exp newval->is_generated = (colDef->generatedCol != '\0'); newval->col_name = pstrdup(colDef->colname); newval->is_autoinc = is_autoinc; + newval->make_dml_change = make_dml_change; tab->rewrite |= AT_REWRITE_ALTER_PERSISTENCE; } @@ -13017,13 +13452,40 @@ static ObjectAddress ATExecAddColumn(List** wqueue, AlteredTableInfo* tab, Relat errmsg("It's not supported to alter table add column default with nextval expression."))); } else if (RelationIsCUFormat(rel)) { ATExecAppendDefValExpr(attribute.attnum, defval, tab, colDef, false, false); - } else if (tab->rewrite>0 || colDef->generatedCol || - RelationUsesSpaceType(rel->rd_rel->relpersistence) == SP_TEMP) { + } else if (colDef->generatedCol ) { ATExecAppendDefValExpr(attribute.attnum, defval, tab, colDef, false, true); + } else if (RelationUsesSpaceType(rel->rd_rel->relpersistence) == SP_TEMP) { + bytea* value = NULL; + colDef->initdefval = NULL; + (void)shouldUpdateAllTuples(defval, attribute.atttypid, attribute.attlen, attribute.attbyval, &value, &colDef->initdefval); + ATExecAppendDefValExpr(attribute.attnum, defval, tab, colDef, false, true); + } else if (tab->rewrite) { + bytea* value = NULL; + bool addcolumndef = false; + + if (XLogLogicalInfoActive() && RelationIsRowFormat(rel)) { + if (IsA(defval, Const) && constIsNull((Const*)defval)) { + ATExecAppendDefValExpr(attribute.attnum, defval, tab, colDef, false, true); + } else { + colDef->initdefval = NULL; + AT_INSTANT_DEFAULT_VALUE ret = + shouldUpdateAllTuples(defval, attribute.atttypid, attribute.attlen, attribute.attbyval, &value, &colDef->initdefval); + + if (ret == DEFAULT_OTHER) { + addcolumndef = true; + colDef->initdefval = NULL; + } + + ATExecAppendDefValExpr(attribute.attnum, defval, tab, colDef, false, true, addcolumndef); + } + } else { + ATExecAppendDefValExpr(attribute.attnum, defval, tab, colDef, false, true); + } } else { bytea* value = NULL; + colDef->initdefval = NULL; AT_INSTANT_DEFAULT_VALUE ret = - shouldUpdateAllTuples(defval, attribute.atttypid, attribute.attlen, attribute.attbyval, &value); + shouldUpdateAllTuples(defval, attribute.atttypid, attribute.attlen, attribute.attbyval, &value, &colDef->initdefval); if (ret == DEFAULT_NOT_NULL_CONST) { Assert(value != NULL); @@ -13035,6 +13497,7 @@ static ObjectAddress ATExecAddColumn(List** wqueue, AlteredTableInfo* tab, Relat */ testNotNull = false; } else if (ret == DEFAULT_OTHER) { + colDef->initdefval = NULL; if (isDfsTable) { ereport(ERROR, (errcode(ERRCODE_INVALID_TABLE_DEFINITION), @@ -13044,7 +13507,7 @@ static ObjectAddress ATExecAddColumn(List** wqueue, AlteredTableInfo* tab, Relat "2. the storage length of default value may be greater than 127.\n" "3. the data type of new column is not supported.")))); } - ATExecAppendDefValExpr(attribute.attnum, defval, tab, colDef, false, false); + ATExecAppendDefValExpr(attribute.attnum, defval, tab, colDef, false, false, true); } /* nothing to do if ret is DEFAULT_NULL */ } @@ -16604,6 +17067,7 @@ static void ATPrepAlterColumnType(List** wqueue, AlteredTableInfo* tab, Relation newval->newattnum = 0; newval->col_name = pstrdup(colName); newval->generate_attnum = 0; + newval->is_alter_using = (def->raw_default ? true : false); newval->is_updated = false; tab->newvals = lappend(tab->newvals, newval); @@ -18045,7 +18509,7 @@ static void AttachEachCommandInQueue( con = (Constraint*)cmd->def; con->old_pktable_oid = refRelId; /* rewriting neither side of a FK */ - if (con->contype == CONSTR_FOREIGN && !rewrite && tab->rewrite <= 0) + if (con->contype == CONSTR_FOREIGN && !rewrite && tab->rewrite == 0) TryReuseForeignKey(oldId, con); cmd->subtype = AT_ReAddConstraint; tab->subcmds[AT_PASS_OLD_CONSTR] = lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd); diff --git a/src/gausskernel/process/tcop/utility.cpp b/src/gausskernel/process/tcop/utility.cpp index 2b5dd2d8b..5000fc019 100755 --- a/src/gausskernel/process/tcop/utility.cpp +++ b/src/gausskernel/process/tcop/utility.cpp @@ -1671,7 +1671,8 @@ bool isAllTempObjects(Node* parse_tree, const char* query_string, bool sent_to_r foreach (cell, ((DropStmt*)parse_tree)->objects) { List* obj_name = (List*)lfirst(cell); char* name = NameListToString(obj_name); - if (isTempNamespaceName(name) || isToastTempNamespaceName(name)) + if (isTempNamespaceName(name) || isToastTempNamespaceName(name) + || strcmp(name, "pg_temp") == 0) return true; } @@ -3394,15 +3395,6 @@ void standard_ProcessUtility(processutility_context* processutility_cxt, GrantRole((GrantRoleStmt*)parse_tree); #endif break; - case T_CreateEventStmt: /* CREATE EVENT */ - CreateEventCommand((CreateEventStmt*)parse_tree); - break; - case T_AlterEventStmt: /* CREATE EVENT */ - AlterEventCommand((AlterEventStmt*)parse_tree); - break; - case T_DropEventStmt: /* DROP EVENT */ - DropEventCommand((DropEventStmt*)parse_tree); - break; case T_ShowEventStmt: /* SHOW EVENTS */ ShowEventCommand((ShowEventStmt*)parse_tree, dest); break; @@ -6841,6 +6833,18 @@ ProcessUtilitySlow(Node *parse_tree, commandCollected = true; break; + case T_CreateEventStmt: /* CREATE EVENT */ + address = CreateEventCommand((CreateEventStmt*)parse_tree); + + break; + case T_AlterEventStmt: /* CREATE EVENT */ + address = AlterEventCommand((AlterEventStmt*)parse_tree); + break; + case T_DropEventStmt: /* DROP EVENT */ + DropEventCommand((DropEventStmt*)parse_tree); + break; + + case T_TableOfTypeStmt: /* CREATE TYPE AS TABLE OF */ { TableOfTypeStmt* stmt = (TableOfTypeStmt*)parse_tree; diff --git a/src/gausskernel/storage/access/common/reloptions.cpp b/src/gausskernel/storage/access/common/reloptions.cpp index 8ebd16f04..3e433f5c7 100644 --- a/src/gausskernel/storage/access/common/reloptions.cpp +++ b/src/gausskernel/storage/access/common/reloptions.cpp @@ -254,6 +254,7 @@ static relopt_int intRelOpts[] = { 0, 7}, {{ "collate", "set relation default collation", RELOPT_KIND_HEAP }, 0, 0, 2000000000 }, + {{ "relrewrite", "set relation relrewrite", RELOPT_KIND_HEAP | RELOPT_KIND_TOAST }, 0, 0, 2000000000 }, /* list terminator */ {{NULL}} }; @@ -2048,7 +2049,8 @@ bytea *default_reloptions(Datum reloptions, bool validate, relopt_kind kind) /* SPQ index B-Tree build: btree index build use spq */ {"spq_build", RELOPT_TYPE_STRING, offsetof(StdRdOptions, spq_bt_build_offset)}, #endif - { "deduplication", RELOPT_TYPE_BOOL, offsetof(StdRdOptions, deduplication)} + { "deduplication", RELOPT_TYPE_BOOL, offsetof(StdRdOptions, deduplication)}, + { "relrewrite", RELOPT_TYPE_INT, offsetof(StdRdOptions, relrewrite)}, }; options = parseRelOptions(reloptions, validate, kind, &numoptions); @@ -2757,8 +2759,8 @@ void check_collate_in_options(List *user_options) */ void ForbidOutUsersToSetInnerOptions(List *userOptions) { - static const char* innnerOpts[] = { - "internal_mask", "start_ctid_internal", "end_ctid_internal", "append_mode_internal", "wait_clean_gpi"}; + static const char *innnerOpts[] = {"internal_mask", "start_ctid_internal", "end_ctid_internal", + "append_mode_internal", "wait_clean_gpi", "relrewrite"}; if (userOptions != NULL) { int firstInvalidOpt = -1; diff --git a/src/gausskernel/storage/access/heap/heapam.cpp b/src/gausskernel/storage/access/heap/heapam.cpp index 1f0f55f65..02385ea1d 100755 --- a/src/gausskernel/storage/access/heap/heapam.cpp +++ b/src/gausskernel/storage/access/heap/heapam.cpp @@ -9550,6 +9550,13 @@ void heap3_redo(XLogReaderState* record) case XLOG_HEAP3_INVALID: heap_xlog_invalid(record); break; + case XLOG_HEAP3_TRUNCATE: + /* + * TRUNCATE is a no-op because the actions are already logged as + * SMGR WAL records. TRUNCATE WAL record only exists for logical + * decoding. + */ + break; default: ereport(PANIC, (errmsg("heap3_redo: unknown op code %hhu", info))); } diff --git a/src/gausskernel/storage/access/redo/redo_heapam.cpp b/src/gausskernel/storage/access/redo/redo_heapam.cpp index 28ce6f532..bd9df2490 100755 --- a/src/gausskernel/storage/access/redo/redo_heapam.cpp +++ b/src/gausskernel/storage/access/redo/redo_heapam.cpp @@ -1631,6 +1631,8 @@ XLogRecParseState *Heap3RedoParseToBlock(XLogReaderState *record, uint32 *blockn case XLOG_HEAP3_INVALID: recordblockstate = HeapXlogInvalidParseBlock(record, blocknum); break; + case XLOG_HEAP3_TRUNCATE: + break; default: ereport(PANIC, (errmsg("Heap3RedoParseToBlock: unknown op code %u", info))); } @@ -1650,6 +1652,8 @@ void Heap3RedoDataBlock(XLogBlockHead *blockhead, XLogBlockDataParse *blockdatar case XLOG_HEAP3_INVALID: HeapXlogInvalidBlock(blockhead, blockdatarec, bufferinfo); break; + case XLOG_HEAP3_TRUNCATE: + break; default: ereport(PANIC, (errmsg("heap3_redo_block: unknown op code %u", info))); } diff --git a/src/gausskernel/storage/access/rmgrdesc/heapdesc.cpp b/src/gausskernel/storage/access/rmgrdesc/heapdesc.cpp index f72e292e5..8ad4427bd 100644 --- a/src/gausskernel/storage/access/rmgrdesc/heapdesc.cpp +++ b/src/gausskernel/storage/access/rmgrdesc/heapdesc.cpp @@ -167,6 +167,17 @@ void heap_desc(StringInfo buf, XLogReaderState *record) xl_heap_base_shift *xlrec = (xl_heap_base_shift *)rec; appendStringInfo(buf, "base_shift delta %ld multi %d", xlrec->delta, xlrec->multi); + } else if (info == XLOG_HEAP3_TRUNCATE) { + xl_heap_truncate *xlrec = (xl_heap_truncate *) rec; + int i; + + if (xlrec->flags & XLH_TRUNCATE_CASCADE) + appendStringInfo(buf, "cascade "); + if (xlrec->flags & XLH_TRUNCATE_RESTART_SEQS) + appendStringInfo(buf, "restart_seqs "); + appendStringInfo(buf, "nrelids %u relids", xlrec->nrelids); + for (i = 0; i < (int)xlrec->nrelids; i++) + appendStringInfo(buf, " %u", xlrec->relids[i]); } else appendStringInfo(buf, "UNKNOWN"); } @@ -339,6 +350,8 @@ const char* heap3_type_name(uint8 subtype) return "heap3_rewrite"; } else if (info == XLOG_HEAP3_INVALID) { return "heap3_invalid"; + } else if (info == XLOG_HEAP3_TRUNCATE) { + return "heap3_truncate"; } else { return "unkown_type"; } @@ -371,6 +384,8 @@ void heap3_desc(StringInfo buf, XLogReaderState *record) appendStringInfo(buf, "]"); } } + } else if (info == XLOG_HEAP3_TRUNCATE) { + appendStringInfo(buf, "XLOG_HEAP_TRUNCATE"); } else { appendStringInfo(buf, "UNKNOWN"); } diff --git a/src/gausskernel/storage/access/transam/extreme_rto/dispatcher.cpp b/src/gausskernel/storage/access/transam/extreme_rto/dispatcher.cpp index e05c555f2..c63c0aea7 100755 --- a/src/gausskernel/storage/access/transam/extreme_rto/dispatcher.cpp +++ b/src/gausskernel/storage/access/transam/extreme_rto/dispatcher.cpp @@ -204,7 +204,7 @@ static const RmgrDispatchData g_dispatchTable[RM_MAX_ID + 1] = { { DispatchSeqRecord, RmgrRecordInfoValid, RM_SEQ_ID, XLOG_SEQ_LOG, XLOG_SEQ_LOG }, { DispatchSpgistRecord, RmgrRecordInfoValid, RM_SPGIST_ID, XLOG_SPGIST_CREATE_INDEX, XLOG_SPGIST_VACUUM_REDIRECT }, { DispatchRepSlotRecord, RmgrRecordInfoValid, RM_SLOT_ID, XLOG_SLOT_CREATE, XLOG_TERM_LOG }, - { DispatchHeap3Record, RmgrRecordInfoValid, RM_HEAP3_ID, XLOG_HEAP3_NEW_CID, XLOG_HEAP3_INVALID }, + { DispatchHeap3Record, RmgrRecordInfoValid, RM_HEAP3_ID, XLOG_HEAP3_NEW_CID, XLOG_HEAP3_TRUNCATE }, { DispatchBarrierRecord, RmgrRecordInfoValid, RM_BARRIER_ID, XLOG_BARRIER_CREATE, XLOG_BARRIER_SWITCHOVER }, #ifdef ENABLE_MOT {DispatchMotRecord, NULL, RM_MOT_ID, 0, 0}, diff --git a/src/gausskernel/storage/access/transam/ondemand_extreme_rto/dispatcher.cpp b/src/gausskernel/storage/access/transam/ondemand_extreme_rto/dispatcher.cpp index 95e3a4271..2e308b823 100644 --- a/src/gausskernel/storage/access/transam/ondemand_extreme_rto/dispatcher.cpp +++ b/src/gausskernel/storage/access/transam/ondemand_extreme_rto/dispatcher.cpp @@ -203,7 +203,7 @@ static const RmgrDispatchData g_dispatchTable[RM_MAX_ID + 1] = { { DispatchSeqRecord, RmgrRecordInfoValid, RM_SEQ_ID, XLOG_SEQ_LOG, XLOG_SEQ_LOG }, { DispatchSpgistRecord, RmgrRecordInfoValid, RM_SPGIST_ID, XLOG_SPGIST_CREATE_INDEX, XLOG_SPGIST_VACUUM_REDIRECT }, { DispatchRepSlotRecord, RmgrRecordInfoValid, RM_SLOT_ID, XLOG_SLOT_CREATE, XLOG_TERM_LOG }, - { DispatchHeap3Record, RmgrRecordInfoValid, RM_HEAP3_ID, XLOG_HEAP3_NEW_CID, XLOG_HEAP3_INVALID }, + { DispatchHeap3Record, RmgrRecordInfoValid, RM_HEAP3_ID, XLOG_HEAP3_NEW_CID, XLOG_HEAP3_TRUNCATE }, { DispatchBarrierRecord, RmgrRecordInfoValid, RM_BARRIER_ID, XLOG_BARRIER_CREATE, XLOG_BARRIER_SWITCHOVER }, #ifdef ENABLE_MOT {DispatchMotRecord, NULL, RM_MOT_ID, 0, 0}, diff --git a/src/gausskernel/storage/access/transam/parallel_recovery/dispatcher.cpp b/src/gausskernel/storage/access/transam/parallel_recovery/dispatcher.cpp index 2be3f9147..81151b609 100755 --- a/src/gausskernel/storage/access/transam/parallel_recovery/dispatcher.cpp +++ b/src/gausskernel/storage/access/transam/parallel_recovery/dispatcher.cpp @@ -196,7 +196,7 @@ static const RmgrDispatchData g_dispatchTable[RM_MAX_ID + 1] = { { DispatchSeqRecord, RmgrRecordInfoValid, RM_SEQ_ID, XLOG_SEQ_LOG, XLOG_SEQ_LOG }, { DispatchSpgistRecord, RmgrRecordInfoValid, RM_SPGIST_ID, XLOG_SPGIST_CREATE_INDEX, XLOG_SPGIST_VACUUM_REDIRECT }, { DispatchRepSlotRecord, RmgrRecordInfoValid, RM_SLOT_ID, XLOG_SLOT_CREATE, XLOG_TERM_LOG }, - { DispatchHeap3Record, RmgrRecordInfoValid, RM_HEAP3_ID, XLOG_HEAP3_NEW_CID, XLOG_HEAP3_INVALID }, + { DispatchHeap3Record, RmgrRecordInfoValid, RM_HEAP3_ID, XLOG_HEAP3_NEW_CID, XLOG_HEAP3_TRUNCATE }, { DispatchBarrierRecord, RmgrRecordInfoValid, RM_BARRIER_ID, XLOG_BARRIER_CREATE, XLOG_BARRIER_SWITCHOVER }, #ifdef ENABLE_MOT diff --git a/src/gausskernel/storage/replication/logical/ddlmessage.cpp b/src/gausskernel/storage/replication/logical/ddlmessage.cpp index c4d7982a3..4bd89c592 100644 --- a/src/gausskernel/storage/replication/logical/ddlmessage.cpp +++ b/src/gausskernel/storage/replication/logical/ddlmessage.cpp @@ -55,7 +55,7 @@ LogLogicalDDLMessage(const char *prefix, Oid relid, DeparsedCommandType cmdtype, char *tmp = pstrdup(message); char *owner = NULL; - if (cmdtype != DCT_TableDropStart) { + if (cmdtype != DCT_TableDropStart && cmdtype != DCT_TypeDropStart) { char *decodestring = deparse_ddl_json_to_string(tmp, &owner); elog(LOG, "will decode to : %s, [owner %s]", decodestring, owner ? owner : "none"); } diff --git a/src/gausskernel/storage/replication/logical/ddltrigger.cpp b/src/gausskernel/storage/replication/logical/ddltrigger.cpp index 71f6cc760..0a19ffc02 100644 --- a/src/gausskernel/storage/replication/logical/ddltrigger.cpp +++ b/src/gausskernel/storage/replication/logical/ddltrigger.cpp @@ -22,6 +22,8 @@ #include "commands/event_trigger.h" #include "funcapi.h" #include "lib/ilist.h" +#include "nodes/makefuncs.h" +#include "parser/parse_type.h" #include "replication/ddlmessage.h" #include "tcop/ddldeparse.h" #include "utils/lsyscache.h" @@ -45,7 +47,7 @@ * accessed in those functions may not even exist on the subscriber. */ static void -check_command_publishable(ddl_deparse_context context) +check_command_publishable(ddl_deparse_context context, bool rewrite) { if (context.max_volatility == PROVOLATILE_VOLATILE) ereport(ERROR, @@ -53,24 +55,24 @@ check_command_publishable(ddl_deparse_context context) errmsg("cannot use volatile function in this command because it cannot be replicated in DDL replication"))); } -bool relation_support_ddl_replication(Oid relid) +bool relation_support_ddl_replication(Oid relid, bool rewrite) { - bool support = false; - + bool support = true; + Relation rel = relation_open(relid, AccessShareLock); - /* if relpersistence is 'p', not support */ + Oid relrewrite = RelationGetRelrewriteOption(rel); if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP) { - return false; - } - if (RelationIsRowFormat(rel) && RelationIsAstoreFormat(rel)) { - support = true; - } else if (RelationIsIndex(rel)) { - if(IS_BTREE(rel) && !RelationAmIsBtree(rel)) { - return false; + support = false; + } else if (rel->rd_rel->relkind == RELKIND_RELATION) { + if (pg_strcasecmp(RelationGetOrientation(rel), ORIENTATION_ROW)) { + support = false; + } else if (OidIsValid(relrewrite)) { + support = false; + } else if (!RelationIsAstoreFormat(rel)) { + support = false; } - support = true; - } else if(RelationIsSequnce(rel)) { - support = true; + } else if (rel->rd_rel->relkind == RELKIND_INDEX && RelationIsUstoreIndex(rel)) { + support = false; } relation_close(rel, AccessShareLock); @@ -78,6 +80,25 @@ bool relation_support_ddl_replication(Oid relid) return support; } +bool type_support_ddl_replication(Oid typid) +{ + bool support = false; + HeapTuple typtup; + Form_pg_type typform; + + typtup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid)); + if (!HeapTupleIsValid(typtup)) + elog(ERROR, "cache lookup failed for type with OID %u", typid); + + typform = (Form_pg_type) GETSTRUCT(typtup); + if (typform->typtype == TYPTYPE_COMPOSITE || typform->typtype == TYPTYPE_ENUM) { + support = true; + } + + ReleaseSysCache(typtup); + return support; +} + /* * Deparse the ddl command and log it prior to * execution. Currently only used for DROP TABLE command @@ -105,6 +126,25 @@ publication_deparse_ddl_command_start(PG_FUNCTION_ARGS) Node *object = (Node*)lfirst(cell1); ObjectAddress address; Relation relation = NULL; + char *schemaname = NULL; + char *objname = NULL; + TypeName *typname = NULL; + Node *ptype = NULL; + + if (stmt->removeType == OBJECT_TYPE) { + /* for DROP TYPE */ + Assert(IsA(object, List) && list_length((List*)object) >= 1); + ptype = (Node *) linitial((List*)object); + if (ptype->type == T_String) + typname = makeTypeNameFromNameList((List*)object); + else if (ptype->type == T_TypeName) + typname = (TypeName *)ptype; + + objname = TypeNameToString(typname); + } else { + /* for DROP TABLE/DROP IDNEX/DROP MATERIALIZED VIEW */ + DeconstructQualifiedName((List*)object, &schemaname, &objname); + } address = get_object_address(stmt->removeType, IsA(object, List) ? (List*)object : list_make1(object), @@ -114,38 +154,107 @@ publication_deparse_ddl_command_start(PG_FUNCTION_ARGS) true); /* Object does not exist, nothing to do */ - if (!relation) - continue; + if (relation) { + if (get_rel_relkind(address.objectId)) + support = relation_support_ddl_replication(address.objectId, false); - if (get_rel_relkind(address.objectId)) - support = relation_support_ddl_replication(address.objectId); + /* + * Do not generate wal log for commands whose target table is a + * temporary or unlogged table. + * + * XXX We may generate wal logs for unlogged tables in the future so + * that unlogged tables can also be created and altered on the + * subscriber side. This makes it possible to directly replay the SET + * LOGGED command and the incoming rewrite message without creating a + * new table. + */ + if (support) + LogLogicalDDLMessage("deparse", address.objectId, DCT_TableDropStart, + command, strlen(command) + 1); - /* - * Do not generate wal log for commands whose target table is a - * temporary or unlogged table. - * - * XXX We may generate wal logs for unlogged tables in the future so - * that unlogged tables can also be created and altered on the - * subscriber side. This makes it possible to directly replay the SET - * LOGGED command and the incoming rewrite message without creating a - * new table. - */ - if (support) - LogLogicalDDLMessage("deparse", address.objectId, DCT_TableDropStart, - command, strlen(command) + 1); - - relation_close(relation, NoLock); + relation_close(relation, NoLock); + } else if (stmt->removeType == OBJECT_TYPE) { + support = type_support_ddl_replication(address.objectId); + if (support) + LogLogicalDDLMessage("deparse", address.objectId, + DCT_TypeDropStart, command, strlen(command) + 1); + } } return PointerGetDatum(NULL); } +static void finish_alter_table_ddl_command(CollectedCommand* cmd) +{ + ListCell *lc; + List *cmds; + Oid relid; + DeparsedCommandType type; + + relid = cmd->d.alterTable.objectId; + type = DCT_TableAlter; + + cmds = deparse_altertable_end(cmd); + foreach(lc, cmds) { + char* json_string = (char*)lfirst(lc); + if (json_string) { + LogLogicalDDLMessage("deparse", relid, type, json_string, + strlen(json_string) + 1); + } + } +} + +/* + * publication_deparse_table_rewrite + * + * Deparse the ddl table rewrite command and log it. + */ +Datum publication_deparse_table_rewrite(PG_FUNCTION_ARGS) +{ + bool support = false; + CollectedCommand *cmd; + char *json_string; + + if (!CALLED_AS_EVENT_TRIGGER(fcinfo)) + elog(ERROR, "not fired by event trigger manager"); + + cmd = currentEventTriggerState->currentCommand; + Assert(cmd && cmd->d.alterTable.rewrite); + + if (get_rel_relkind(cmd->d.alterTable.objectId)) + support = relation_support_ddl_replication(cmd->d.alterTable.objectId, true); + + /* + * Do not generate wal log for commands whose target table is a temporary + * or unlogged table. + * + * XXX We may generate wal logs for unlogged tables in the future so that + * unlogged tables can also be created and altered on the subscriber side. + * This makes it possible to directly replay the SET LOGGED command and the + * incoming rewrite message without creating a new table. + */ + if (support) { + ddl_deparse_context context; + context.verbose_mode = false; + context.include_owner = true; + context.max_volatility = PROVOLATILE_IMMUTABLE; + /* Deparse the DDL command and WAL log it to allow decoding of the same. */ + json_string = deparse_utility_command(cmd, &context); + if (json_string != NULL) { + check_command_publishable(context, true); + LogLogicalDDLMessage("deparse", cmd->d.alterTable.objectId, DCT_TableAlter, + json_string, strlen(json_string) + 1); + } + } + + return PointerGetDatum(NULL); +} + /* * Deparse the ddl command and log it. This function * is called after the execution of the command but before the * transaction commits. */ -Datum -publication_deparse_ddl_command_end(PG_FUNCTION_ARGS) +Datum publication_deparse_ddl_command_end(PG_FUNCTION_ARGS) { ListCell *lc; slist_iter iter; @@ -162,33 +271,94 @@ publication_deparse_ddl_command_end(PG_FUNCTION_ARGS) CollectedCommand *cmd = (CollectedCommand*)lfirst(lc); char *json_string; - if (cmd->type == SCT_Simple && - !OidIsValid(cmd->d.simple.address.objectId)) - continue; + /* Rewrite DDL has been handled in table_rewrite trigger */ + if (cmd->d.alterTable.rewrite) { + if (cmd->type == SCT_AlterTable) { + relid = cmd->d.alterTable.objectId; + support = relation_support_ddl_replication(relid, true); + if (support) { + finish_alter_table_ddl_command(cmd); + } + continue; + } else if (cmd->parsetree && IsA(cmd->parsetree, RenameStmt)) { + RenameStmt *renameStmt = (RenameStmt *) cmd->parsetree; - /* Only SCT_Simple for now */ - relid = cmd->d.simple.address.objectId; - type = DCT_SimpleCmd; - - if (get_rel_relkind(relid)) { - support = relation_support_ddl_replication(relid); + if (renameStmt && renameStmt->relationType != OBJECT_TYPE && + renameStmt->relationType != OBJECT_TABLE) + continue; + } } + if (cmd->type == SCT_Simple && cmd->parsetree && + !OidIsValid(cmd->d.simple.address.objectId)) { + relid = cmd->d.simple.address.objectId; + type = DCT_SimpleCmd; + /* + * handle some syntax which can not be capture by event trigger + * like rename table in dbcompatibility B + */ + if (IsA(cmd->parsetree, RenameStmt)) { + RenameStmt *renameStmt = (RenameStmt *) cmd->parsetree; + if (renameStmt->renameTableflag && renameStmt->renameTargetList) { + context.verbose_mode = false; + context.include_owner = true; + context.max_volatility = PROVOLATILE_IMMUTABLE; + json_string = deparse_utility_command(cmd, &context); + + if (json_string != NULL) { + check_command_publishable(context, false); + LogLogicalDDLMessage("deparse", relid, type, json_string, strlen(json_string) + 1); + } + } + } else if (DB_IS_CMPT(B_FORMAT) && (IsA(cmd->parsetree, CreateEventStmt) || + IsA(cmd->parsetree, AlterEventStmt) || + IsA(cmd->parsetree, DropEventStmt))) { + context.verbose_mode = false; + context.include_owner = true; + context.max_volatility = PROVOLATILE_IMMUTABLE; + json_string = deparse_utility_command(cmd, &context); + if (json_string != NULL) { + LogLogicalDDLMessage("deparse", relid, type, json_string, + strlen(json_string) + 1); + } + } + + continue; + } + + if (cmd->type == SCT_AlterTable) { + relid = cmd->d.alterTable.objectId; + type = DCT_TableAlter; + } else { + /* Only SCT_Simple for now */ + relid = cmd->d.simple.address.objectId; + type = DCT_SimpleCmd; + } + + if (get_rel_relkind(relid)) + support = relation_support_ddl_replication(relid); + else if (cmd->d.simple.address.classId == TypeRelationId) + support = type_support_ddl_replication(relid); + if (support) { /* * Deparse the DDL command and WAL log it to allow decoding of the * same. */ + context.verbose_mode = false; context.include_owner = true; context.max_volatility = PROVOLATILE_IMMUTABLE; json_string = deparse_utility_command(cmd, &context); if (json_string != NULL) { - check_command_publishable(context); + check_command_publishable(context, false); LogLogicalDDLMessage("deparse", relid, type, json_string, strlen(json_string) + 1); } + if (cmd->type == SCT_AlterTable) { + finish_alter_table_ddl_command(cmd); + } } } @@ -207,14 +377,34 @@ publication_deparse_ddl_command_end(PG_FUNCTION_ARGS) continue; } - if (strcmp(obj->objecttype, "table") == 0) { + if (strcmp(obj->objecttype, "table") == 0 || + strcmp(obj->objecttype, "index") == 0) { cmdtype = DCT_TableDropEnd; - } else if (strcmp(obj->objecttype, "index") == 0) { + } else if (strcmp(obj->objecttype, "type") == 0) { + cmdtype = DCT_TypeDropEnd; + } else if (strcmp(obj->objecttype, "schema") == 0 || + strcmp(obj->objecttype, "index") == 0 || + strcmp(obj->objecttype, "sequence") == 0 || + strcmp(obj->objecttype, "large sequence") == 0 || + strcmp(obj->objecttype, "view") == 0 || + strcmp(obj->objecttype, "function") == 0 || + strcmp(obj->objecttype, "trigger") == 0 || + strcmp(obj->objecttype, "function") == 0) { cmdtype = DCT_ObjectDrop; } else { continue; } + if (strcmp(obj->objecttype, "schema") == 0 && + (isTempNamespaceName(obj->objname) || isToastTempNamespaceName(obj->objname) + || strcmp(obj->objidentity, "pg_temp") == 0)) { + continue; + } + + if (!IsA((Node*)trigdata->parsetree, DropStmt)) { + continue; + } + command = deparse_drop_command(obj->objidentity, obj->objecttype, (Node*)trigdata->parsetree); if (command) diff --git a/src/gausskernel/storage/replication/logical/decode.cpp b/src/gausskernel/storage/replication/logical/decode.cpp index d6ebef543..e69e33636 100644 --- a/src/gausskernel/storage/replication/logical/decode.cpp +++ b/src/gausskernel/storage/replication/logical/decode.cpp @@ -82,6 +82,8 @@ static void AreaDecodeUUpdate(LogicalDecodingContext *ctx, XLogRecordBuffer *buf static void DecodeDelete(LogicalDecodingContext *ctx, XLogRecordBuffer *buf); static void AreaDecodeDelete(LogicalDecodingContext *ctx, XLogRecordBuffer *buf); +static void DecodeTruncate(LogicalDecodingContext *ctx, XLogRecordBuffer *buf); + static void DecodeUDelete(LogicalDecodingContext *ctx, XLogRecordBuffer *buf); static void AreaDecodeUDelete(LogicalDecodingContext *ctx, XLogRecordBuffer *buf); @@ -749,6 +751,10 @@ static void DecodeHeap3Op(LogicalDecodingContext *ctx, XLogRecordBuffer *buf) break; case XLOG_HEAP3_REWRITE: break; + case XLOG_HEAP3_TRUNCATE: + if (SnapBuildProcessChange(builder, xid, buf->origptr)) + DecodeTruncate(ctx, buf); + break; default: ereport(WARNING, (errmodule(MOD_LOGICAL_DECODE), errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE), errmsg("unexpected RM_HEAP3_ID record type: %u", info))); @@ -1930,6 +1936,42 @@ static void AreaDecodeUDelete(LogicalDecodingContext *ctx, XLogRecordBuffer *buf } } + +/* + * Parse XLOG_HEAP_TRUNCATE from wal + */ +static void DecodeTruncate(LogicalDecodingContext *ctx, XLogRecordBuffer *buf) +{ + XLogReaderState *r = buf->record; + xl_heap_truncate *xlrec; + ReorderBufferChange *change; + int rc = 0; + xlrec = (xl_heap_truncate *) XLogRecGetData(r); + /* only interested in our database */ + if (xlrec->dbId != ctx->slot->data.database) { + return; + } + + /* output plugin doesn't look for this origin, no need to queue */ + if (FilterByOrigin(ctx, XLogRecGetOrigin(r))) { + return; + } + + change = ReorderBufferGetChange(ctx->reorder); + change->action = REORDER_BUFFER_CHANGE_TRUNCATE; + change->origin_id = XLogRecGetOrigin(r); + if (xlrec->flags & XLH_TRUNCATE_CASCADE) + change->data.truncate.cascade = true; + if (xlrec->flags & XLH_TRUNCATE_RESTART_SEQS) + change->data.truncate.restart_seqs = true; + change->data.truncate.nrelids = xlrec->nrelids; + change->data.truncate.relids = (Oid*)palloc(xlrec->nrelids * sizeof(Oid)); + rc = memcpy_s(change->data.truncate.relids, xlrec->nrelids * sizeof(Oid), xlrec->relids, + xlrec->nrelids * sizeof(Oid)); + securec_check(rc, "", ""); + ReorderBufferQueueChange(ctx, XLogRecGetXid(r), buf->origptr, change); +} + /* * Decode XLOG_HEAP2_MULTI_INSERT_insert record into multiple tuplebufs. * diff --git a/src/gausskernel/storage/replication/logical/logical.cpp b/src/gausskernel/storage/replication/logical/logical.cpp index 211690175..e9fc32a0a 100644 --- a/src/gausskernel/storage/replication/logical/logical.cpp +++ b/src/gausskernel/storage/replication/logical/logical.cpp @@ -82,6 +82,9 @@ static void change_cb_wrapper(ReorderBuffer *cache, ReorderBufferTXN *txn, Relat static void parallel_change_cb_wrapper(ParallelReorderBuffer *cache, ReorderBufferTXN *txn, Relation relation, ParallelReorderBufferChange *change); +static void truncate_cb_wrapper(ReorderBuffer *cache, ReorderBufferTXN *txn, + int nrelations, Relation relations[], ReorderBufferChange *change); + static void LoadOutputPlugin(OutputPluginCallbacks *callbacks, const char *plugin); static void LoadOutputPlugin(ParallelOutputPluginCallbacks *callbacks, const char *plugin); static void ddl_cb_wrapper(ReorderBuffer *cache, ReorderBufferTXN *txn, @@ -183,6 +186,7 @@ static LogicalDecodingContext *StartupDecodingContext(List *output_plugin_option /* wrap output plugin callbacks, so we can add error context information */ ctx->reorder->begin = begin_cb_wrapper; ctx->reorder->apply_change = change_cb_wrapper; + ctx->reorder->apply_truncate = truncate_cb_wrapper; ctx->reorder->commit = commit_cb_wrapper; ctx->reorder->ddl = ddl_cb_wrapper; @@ -453,6 +457,8 @@ LogicalDecodingContext *CreateInitDecodingContext(const char *plugin, List *outp startup_cb_wrapper(ctx, &ctx->options, true); (void)MemoryContextSwitchTo(old_context); + ctx->reorder->output_rewrites = ctx->options.receive_rewrites; + return ctx; } @@ -525,6 +531,7 @@ LogicalDecodingContext *CreateDecodingContext(XLogRecPtr start_lsn, List *output if (ctx->callbacks.startup_cb != NULL) startup_cb_wrapper(ctx, &ctx->options, false); (void)MemoryContextSwitchTo(old_context); + ctx->reorder->output_rewrites = ctx->options.receive_rewrites; ereport(LOG, (errmodule(MOD_LOGICAL_DECODE), errmsg("starting logical decoding for slot %s", NameStr(slot->data.name)), @@ -1008,6 +1015,48 @@ static void change_cb_wrapper(ReorderBuffer *cache, ReorderBufferTXN *txn, Relat t_thrd.log_cxt.error_context_stack = errcallback.previous; } +static void truncate_cb_wrapper(ReorderBuffer *cache, ReorderBufferTXN *txn, + int nrelations, Relation relations[], ReorderBufferChange *change) +{ + LogicalDecodingContext *ctx = (LogicalDecodingContext *)cache->private_data; + LogicalErrorCallbackState state; + ErrorContextCallback errcallback; + + Assert(!ctx->fast_forward); + + if (!ctx->callbacks.truncate_cb) { + return; + } + + /* Push callback + info on the error context stack */ + state.ctx = ctx; + state.callback_name = "truncate"; + state.report_location = change->lsn; + errcallback.callback = output_plugin_error_callback; + errcallback.arg = (void *) &state; + errcallback.previous = t_thrd.log_cxt.error_context_stack; + t_thrd.log_cxt.error_context_stack = &errcallback; + + /* set output state */ + ctx->accept_writes = true; + if (txn != NULL) { + ctx->write_xid = txn->xid; + } + + /* + * report this change's lsn so replies from clients can give an up2date + * answer. This won't ever be enough (and shouldn't be!) to confirm + * receipt of this transaction, but it might allow another transaction's + * commit to be confirmed with one message. + */ + ctx->write_location = change->lsn; + + ctx->callbacks.truncate_cb(ctx, txn, nrelations, relations, change); + + /* Pop the error context stack */ + t_thrd.log_cxt.error_context_stack = errcallback.previous; +} + bool filter_by_origin_cb_wrapper(LogicalDecodingContext *ctx, RepOriginId origin_id) { LogicalErrorCallbackState state; diff --git a/src/gausskernel/storage/replication/logical/logical_parse.cpp b/src/gausskernel/storage/replication/logical/logical_parse.cpp index cc3745183..9f0972ec8 100644 --- a/src/gausskernel/storage/replication/logical/logical_parse.cpp +++ b/src/gausskernel/storage/replication/logical/logical_parse.cpp @@ -487,6 +487,8 @@ void ParseHeap3Op(ParallelLogicalDecodingContext *ctx, XLogRecordBuffer *buf, Pa break; case XLOG_HEAP3_INVALID: break; + case XLOG_HEAP3_TRUNCATE: + break; default: ereport(WARNING, (errmodule(MOD_LOGICAL_DECODE), errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE), errmsg("unexpected RM_HEAP3_ID record type: %u", info))); diff --git a/src/gausskernel/storage/replication/logical/proto.cpp b/src/gausskernel/storage/replication/logical/proto.cpp index 03920cba3..dc3d45c38 100644 --- a/src/gausskernel/storage/replication/logical/proto.cpp +++ b/src/gausskernel/storage/replication/logical/proto.cpp @@ -26,6 +26,9 @@ */ static const int LOGICALREP_IS_REPLICA_IDENTITY = 1; +#define TRUNCATE_CASCADE (1<<0) +#define TRUNCATE_RESTART_SEQS (1<<1) + static void logicalrep_write_attrs(StringInfo out, Relation rel); static void logicalrep_write_tuple(StringInfo out, Relation rel, HeapTuple tuple, bool binary); @@ -260,6 +263,56 @@ LogicalRepRelId logicalrep_read_delete(StringInfo in, LogicalRepTupleData *oldtu return relid; } +/* + * Write TRUNCATE to the output stream. + */ +void logicalrep_write_truncate(StringInfo out, + int nrelids, + Oid relids[], + bool cascade, bool restart_seqs) +{ + int i; + uint8 flags = 0; + + pq_sendbyte(out, 'T'); /* action TRUNCATE */ + + pq_sendint32(out, nrelids); + + /* encode and send truncate flags */ + if (cascade) + flags |= TRUNCATE_CASCADE; + if (restart_seqs) + flags |= TRUNCATE_RESTART_SEQS; + pq_sendint8(out, flags); + + for (i = 0; i < nrelids; i++) + pq_sendint32(out, relids[i]); +} + +/* + * Read TRUNCATE from stream. + */ +List *logicalrep_read_truncate(StringInfo in, + bool *cascade, bool *restart_seqs) +{ + int i; + int nrelids; + List *relids = NIL; + uint8 flags; + + nrelids = pq_getmsgint(in, 4); + + /* read and decode truncate flags */ + flags = pq_getmsgint(in, 1); + *cascade = (flags & TRUNCATE_CASCADE) > 0; + *restart_seqs = (flags & TRUNCATE_RESTART_SEQS) > 0; + + for (i = 0; i < nrelids; i++) + relids = lappend_oid(relids, pq_getmsgint(in, 4)); + + return relids; +} + /* * Write relation description to the output stream. */ diff --git a/src/gausskernel/storage/replication/logical/reorderbuffer.cpp b/src/gausskernel/storage/replication/logical/reorderbuffer.cpp index f386df2bf..326a505c8 100644 --- a/src/gausskernel/storage/replication/logical/reorderbuffer.cpp +++ b/src/gausskernel/storage/replication/logical/reorderbuffer.cpp @@ -353,6 +353,8 @@ static Size ReorderBufferChangeSize(ReorderBufferChange *change) break; } + case REORDER_BUFFER_CHANGE_TRUNCATE: + break; } return sz; } @@ -434,6 +436,8 @@ void ReorderBufferReturnChange(ReorderBuffer *rb, ReorderBufferChange *change) change->data.utp.oldtuple = NULL; } break; + case REORDER_BUFFER_CHANGE_TRUNCATE: + break; } pfree(change); @@ -1453,6 +1457,7 @@ void ReorderBufferCommit(ReorderBuffer *rb, TransactionId xid, XLogRecPtr commit Oid reloid; Oid partitionReltoastrelid = InvalidOid; bool isSegment = false; + Oid relrewrite = InvalidOid; switch (change->action) { case REORDER_BUFFER_CHANGE_INSERT: @@ -1503,8 +1508,10 @@ void ReorderBufferCommit(ReorderBuffer *rb, TransactionId xid, XLogRecPtr commit RelationClose(relation); continue; } - - if (RelationIsLogicallyLogged(relation)) { + + relrewrite = RelationGetRelrewriteOption(relation); + if (RelationIsLogicallyLogged(relation) && + (!OidIsValid(relrewrite) || rb->output_rewrites)) { /* * For now ignore sequence changes entirely. Most of * the time they don't log changes using records we @@ -1593,6 +1600,35 @@ void ReorderBufferCommit(ReorderBuffer *rb, TransactionId xid, XLogRecPtr commit case REORDER_BUFFER_CHANGE_DDL: ReorderBufferApplyDDLMessage(rb, txn, change); break; + case REORDER_BUFFER_CHANGE_TRUNCATE: { + int i; + int nrelids = change->data.truncate.nrelids; + int nrelations = 0; + Relation *relations; + + relations = (Relation *)palloc0(nrelids * sizeof(Relation)); + for (i = 0; i < nrelids; i++) { + Oid relid = change->data.truncate.relids[i]; + Relation relation; + + relation = RelationIdGetRelation(relid); + if (relation == NULL) { + elog(ERROR, "could not open relation with OID %u", relid); + } + + if (!RelationIsLogicallyLogged(relation)) { + continue; + } + + relations[nrelations++] = relation; + } + + rb->apply_truncate(rb, txn, nrelations, relations, change); + + for (i = 0; i < nrelations; i++) + RelationClose(relations[i]); + + } break; case REORDER_BUFFER_CHANGE_UINSERT: case REORDER_BUFFER_CHANGE_UDELETE: case REORDER_BUFFER_CHANGE_UUPDATE: @@ -2322,6 +2358,7 @@ static void ReorderBufferSerializeChange(ReorderBuffer *rb, ReorderBufferTXN *tx break; } + case REORDER_BUFFER_CHANGE_TRUNCATE: case REORDER_BUFFER_CHANGE_INTERNAL_COMMAND_ID: /* ReorderBufferChange contains everything important */ break; @@ -2539,6 +2576,7 @@ static void ReorderBufferRestoreChange(ReorderBuffer *rb, ReorderBufferTXN *txn, break; } /* the base struct contains all the data, easy peasy */ + case REORDER_BUFFER_CHANGE_TRUNCATE: case REORDER_BUFFER_CHANGE_INTERNAL_COMMAND_ID: case REORDER_BUFFER_CHANGE_INTERNAL_TUPLECID: break; diff --git a/src/gausskernel/storage/replication/logical/worker.cpp b/src/gausskernel/storage/replication/logical/worker.cpp index 1431b74e4..4c416cc9b 100644 --- a/src/gausskernel/storage/replication/logical/worker.cpp +++ b/src/gausskernel/storage/replication/logical/worker.cpp @@ -943,7 +943,7 @@ static void apply_handle_update(StringInfo s) int remoteattnum = rel->attrmap[i]; if (!att->attisdropped && remoteattnum >= 0) { Assert(remoteattnum < newtup.ncols); - if (newtup.colstatus[i] != LOGICALREP_COLUMN_UNCHANGED) { + if (newtup.colstatus[remoteattnum] != LOGICALREP_COLUMN_UNCHANGED) { target_rte->updatedCols = bms_add_member(target_rte->updatedCols, i + 1 - FirstLowInvalidHeapAttributeNumber); } @@ -1167,6 +1167,66 @@ static void apply_handle_delete(StringInfo s) } +/* + * Handle TRUNCATE message. + */ +static void apply_handle_truncate(StringInfo s) +{ + bool cascade = false; + bool restart_seqs = false; + List *remote_relids = NIL; + List *remote_rels = NIL; + List *rels = NIL; + List *relids = NIL; + List *relids_logged = NIL; + ListCell *lc; + LOCKMODE lockmode = AccessExclusiveLock; + + ensure_transaction(); + + remote_relids = logicalrep_read_truncate(s, &cascade, &restart_seqs); + + foreach(lc, remote_relids) + { + LogicalRepRelId relid = lfirst_oid(lc); + LogicalRepRelMapEntry *rel; + + rel = logicalrep_rel_open(relid, lockmode); + if (!should_apply_changes_for_rel(rel)) { + /* + * The relation can't become interesting in the middle of the + * transaction so it's safe to unlock it. + */ + logicalrep_rel_close(rel, lockmode); + continue; + } + + ereport(LOG, (errmsg("apply [truncate] for %s", RelationGetRelationName(rel->localrel)))); + + remote_rels = lappend(remote_rels, rel); + rels = lappend(rels, rel->localrel); + relids = lappend_oid(relids, rel->localreloid); + if (RelationIsLogicallyLogged(rel->localrel)) + relids_logged = lappend_oid(relids_logged, rel->localreloid); + } + + /* + * Even if we used CASCADE on the upstream master we explicitly + * default to replaying changes without further cascading. + * This might be later changeable with a user specified option. + */ + ExecuteTruncateGuts(rels, relids, relids_logged, NIL, DROP_RESTRICT, restart_seqs, NULL); + + foreach(lc, remote_rels) + { + LogicalRepRelMapEntry *rel = (LogicalRepRelMapEntry*)lfirst(lc); + + logicalrep_rel_close(rel, NoLock); + } + + CommandCounterIncrement(); +} + /* * Handle CREATE TABLE command * @@ -1430,6 +1490,9 @@ static void apply_dispatch(StringInfo s) case 'D': apply_handle_delete(s); break; + case 'T': + apply_handle_truncate(s); + break; /* RELATION */ case 'R': apply_handle_relation(s); @@ -1909,6 +1972,7 @@ void ApplyWorkerMain() { MemoryContext oldctx; char originname[NAMEDATALEN]; + char dbname[NAMEDATALEN]; XLogRecPtr origin_startpos; char *myslotname; int rc = 0; @@ -2033,6 +2097,14 @@ void ApplyWorkerMain() t_thrd.proc_cxt.PostInit->SetDatabaseAndUser(NULL, t_thrd.applyworker_cxt.curWorker->dbid, NULL, t_thrd.applyworker_cxt.curWorker->userid); t_thrd.proc_cxt.PostInit->InitApplyWorker(); + /* has setDatabase and LockDatabase in InitApplyWorker */ + t_thrd.proc_cxt.PostInit->GetDatabaseName(dbname); + oldctx = MemoryContextSwitchTo(SESS_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_STORAGE)); + if (u_sess->proc_cxt.MyProcPort->database_name) + pfree_ext(u_sess->proc_cxt.MyProcPort->database_name); + u_sess->proc_cxt.MyProcPort->database_name = pstrdup(dbname); + (void)MemoryContextSwitchTo(oldctx); + pgstat_report_appname("ApplyWorker"); pgstat_report_activity(STATE_IDLE, NULL); #if (!defined(ENABLE_MULTIPLE_NODES)) && (!defined(ENABLE_PRIVATEGAUSS)) diff --git a/src/gausskernel/storage/replication/pgoutput/pgoutput.cpp b/src/gausskernel/storage/replication/pgoutput/pgoutput.cpp index 44cbed1f8..c6305fada 100644 --- a/src/gausskernel/storage/replication/pgoutput/pgoutput.cpp +++ b/src/gausskernel/storage/replication/pgoutput/pgoutput.cpp @@ -43,6 +43,9 @@ static void pgoutput_commit_txn(LogicalDecodingContext *ctx, ReorderBufferTXN *t static void pgoutput_abort_txn(LogicalDecodingContext* ctx, ReorderBufferTXN* txn); static void pgoutput_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn, Relation rel, ReorderBufferChange *change); +static void pgoutput_truncate(LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, int nrelations, Relation relations[], + ReorderBufferChange *change); static void pgoutput_ddl(LogicalDecodingContext *ctx, ReorderBufferTXN *txn, XLogRecPtr message_lsn, const char *prefix, Oid relid, @@ -60,6 +63,7 @@ typedef struct PGOutputTxnData { bool sent_begin_txn; /* flag indicating where BEGIN has been set */ List *deleted_relids; /* maintain list of deleted table oids */ + List *deleted_typeids; /* maintain list of deleted type oids */ } PGOutputTxnData; /* Entry in the map used to remember which relation schemas we sent. */ @@ -86,6 +90,7 @@ void _PG_output_plugin_init(OutputPluginCallbacks *cb) cb->startup_cb = pgoutput_startup; cb->begin_cb = pgoutput_begin_txn; cb->change_cb = pgoutput_change; + cb->truncate_cb = pgoutput_truncate; cb->commit_cb = pgoutput_commit_txn; cb->abort_cb = pgoutput_abort_txn; cb->filter_by_origin_cb = pgoutput_origin_filter; @@ -163,6 +168,7 @@ static void pgoutput_startup(LogicalDecodingContext *ctx, OutputPluginOptions *o /* This plugin uses binary protocol. */ opt->output_type = OUTPUT_PLUGIN_BINARY_OUTPUT; + opt->receive_rewrites = true; /* * This is replication start and not slot initialization. @@ -225,6 +231,7 @@ clean_txn_data(ReorderBufferTXN *txn) return; list_free(txndata->deleted_relids); + list_free(txndata->deleted_typeids); pfree(txndata); txn->output_plugin_private = NULL; } @@ -368,6 +375,22 @@ static void pgoutput_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn, PGOutputData *data = (PGOutputData *)ctx->output_plugin_private; MemoryContext old; RelationSyncEntry *relentry; + Oid relrewrite = RelationGetRelrewriteOption(relation); + bool table_rewrite = false; + + if (OidIsValid(relrewrite)) { + table_rewrite = true; + relation = RelationIdGetRelation(relrewrite); + + if (REORDER_BUFFER_CHANGE_INSERT == change->action) { + Oid replidindex = RelationGetReplicaIndex(relation); + if (!OidIsValid(replidindex)) { + return; + } + } else if (REORDER_BUFFER_CHANGE_UPDATE != change->action) { + return; + } + } if (!is_publishable_relation(relation)) return; @@ -378,6 +401,14 @@ static void pgoutput_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn, return; } + /* + * We don't publish table rewrite change unless we publish the rewrite ddl + * message. + */ + if (table_rewrite && relentry->pubactions.pubddl == PUBDDL_NONE) { + return; + } + /* Avoid leaking memory by using and resetting our own context */ old = MemoryContextSwitchTo(data->common.context); @@ -391,7 +422,17 @@ static void pgoutput_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn, case REORDER_BUFFER_CHANGE_INSERT: if (change->data.tp.newtuple != NULL) { OutputPluginPrepareWrite(ctx, true); - logicalrep_write_insert(ctx->out, relation, &change->data.tp.newtuple->tuple, data->binary); + /* + * Convert the rewrite inserts to updates so that the subscriber + * can replay it. This is needed to make sure the data between + * publisher and subscriber is consistent. + */ + if (table_rewrite) { + logicalrep_write_update(ctx->out, relation, + NULL, &change->data.tp.newtuple->tuple, data->binary); + } else { + logicalrep_write_insert(ctx->out, relation, &change->data.tp.newtuple->tuple, data->binary); + } OutputPluginWrite(ctx, true); } break; @@ -450,10 +491,53 @@ static void pgoutput_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn, MemoryContextReset(data->common.context); } +static void pgoutput_truncate(LogicalDecodingContext *ctx, ReorderBufferTXN *txn, + int nrelations, Relation relations[], ReorderBufferChange *change) +{ + PGOutputData *data = (PGOutputData *) ctx->output_plugin_private; + MemoryContext old; + RelationSyncEntry *relentry; + int i; + int nrelids; + Oid *relids; + + old = MemoryContextSwitchTo(data->common.context); + + relids = (Oid*)palloc0(nrelations * sizeof(Oid)); + nrelids = 0; + + for (i = 0; i < nrelations; i++) { + Relation relation = relations[i]; + Oid relid = RelationGetRelid(relation); + + if (!is_publishable_relation(relation)) { + continue; + } + + relentry = get_rel_sync_entry(data, relid); + if (!relentry->pubactions.pubtruncate) { + continue; + } + + relids[nrelids++] = relid; + MaybeSendSchema(ctx, relation, relentry); + } + + if (nrelids > 0) { + OutputPluginPrepareWrite(ctx, true); + logicalrep_write_truncate(ctx->out, + nrelids, + relids, + change->data.truncate.cascade, + change->data.truncate.restart_seqs); + OutputPluginWrite(ctx, true); + } + MemoryContextSwitchTo(old); + MemoryContextReset(data->common.context); +} /* Check if the given object is published. */ -static bool -is_object_published_ddl(LogicalDecodingContext *ctx, Oid objid) +static bool is_object_published_ddl(LogicalDecodingContext *ctx, Oid objid) { RelationSyncEntry *relentry; PGOutputData *data = (PGOutputData *) ctx->output_plugin_private; @@ -483,11 +567,8 @@ is_object_published_ddl(LogicalDecodingContext *ctx, Oid objid) /* * Send the decoded DDL message. */ -static void -pgoutput_ddl(LogicalDecodingContext *ctx, ReorderBufferTXN *txn, - XLogRecPtr message_lsn, - const char *prefix, Oid relid, DeparsedCommandType cmdtype, - Size sz, const char *message) +static void pgoutput_ddl(LogicalDecodingContext *ctx, ReorderBufferTXN *txn, XLogRecPtr message_lsn, const char *prefix, + Oid relid, DeparsedCommandType cmdtype, Size sz, const char *message) { PGOutputTxnData *txndata = (PGOutputTxnData *) txn->output_plugin_private; @@ -496,7 +577,7 @@ pgoutput_ddl(LogicalDecodingContext *ctx, ReorderBufferTXN *txn, * we cannot get the required information from the catalog, so we skip the * check for them. */ - if (cmdtype != DCT_TableDropEnd && !is_object_published_ddl(ctx, relid)) { + if (cmdtype != DCT_TableDropEnd && cmdtype != DCT_TypeDropEnd && !is_object_published_ddl(ctx, relid)) { return; } @@ -530,6 +611,61 @@ pgoutput_ddl(LogicalDecodingContext *ctx, ReorderBufferTXN *txn, relid); break; + case DCT_TableAlter: + + /* + * For table rewrite ddl, we first send the original ddl message + * to subscriber, then convert the upcoming rewrite INSERT to + * UPDATE and send them to subscriber so that the data between + * publisher and subscriber can always be consistent. + * + * We do this way because of two reason: + * + * (1) The data before the rewrite ddl could already be different + * among publisher and subscriber. To make sure the extra data in + * subscriber which doesn't exist in publisher also get rewritten, + * we need to let the subscriber execute the original rewrite ddl + * to rewrite all the data at first. + * + * (2) the data after executing rewrite ddl could be different + * among publisher and subscriber(due to different + * functions/operators used during rewrite), so we need to + * replicate the rewrite UPDATEs to keep the data consistent. + * + * TO IMPROVE: We could improve this by letting the subscriber + * only rewrite the extra data instead of doing fully rewrite and + * use the upcoming rewrite UPDATEs to rewrite the rest data. + * Besides, we may not need to send rewrite changes for all type + * of rewrite ddl, for example, it seems fine to skip sending + * rewrite changes for ALTER TABLE SET LOGGED as the data in the + * table doesn't actually be changed. + */ + break; + + case DCT_TypeDropStart: { + MemoryContext old; + + init_txn_data(ctx, txn); + + txndata = (PGOutputTxnData *) txn->output_plugin_private; + + old = MemoryContextSwitchTo(ctx->context); + + txndata->deleted_typeids = lappend_oid(txndata->deleted_typeids, + relid); + + MemoryContextSwitchTo(old); + } + return; + + case DCT_TypeDropEnd: + if (!list_member_oid(txndata->deleted_typeids, relid)) { + return; + } + txndata->deleted_typeids = list_delete_oid(txndata->deleted_typeids, + relid); + break; + case DCT_SimpleCmd: case DCT_ObjectDrop: case DCT_ObjectCreate: @@ -691,6 +827,7 @@ static void RefreshRelationEntry(RelationSyncEntry *entry, PGOutputData *data, O entry->pubactions.pubinsert = false; entry->pubactions.pubupdate = false; entry->pubactions.pubdelete = false; + entry->pubactions.pubtruncate = false; entry->pubactions.pubddl = 0; foreach (lc, data->publications) { @@ -722,14 +859,17 @@ static void RefreshRelationEntry(RelationSyncEntry *entry, PGOutputData *data, O entry->pubactions.pubinsert |= pub->pubactions.pubinsert; entry->pubactions.pubupdate |= pub->pubactions.pubupdate; entry->pubactions.pubdelete |= pub->pubactions.pubdelete; + entry->pubactions.pubtruncate |= pub->pubactions.pubtruncate; if (entry->pubactions.pubddl != PUBDDL_ALL) { entry->pubactions.pubddl |= pub->pubactions.pubddl; } } - if (entry->pubactions.pubinsert && entry->pubactions.pubupdate && entry->pubactions.pubdelete && - pub->pubactions.pubddl == PUBDDL_ALL) - break; + if (entry->pubactions.pubinsert && entry->pubactions.pubupdate && + entry->pubactions.pubdelete && entry->pubactions.pubtruncate && + pub->pubactions.pubddl == PUBDDL_ALL) { + break; + } } list_free_ext(pubids); diff --git a/src/include/access/htup.h b/src/include/access/htup.h index 298d46334..252e0af8d 100644 --- a/src/include/access/htup.h +++ b/src/include/access/htup.h @@ -751,6 +751,8 @@ inline HeapTuple heaptup_alloc(Size size) #define XLOG_HEAP3_NEW_CID 0x00 #define XLOG_HEAP3_REWRITE 0x10 #define XLOG_HEAP3_INVALID 0x20 +/* XLOG_HEAP_TRUNCATE with 0x30 in heap in PG14 */ +#define XLOG_HEAP3_TRUNCATE 0x30 /* we used to put all xl_heap_* together, which made us run out of opcodes (quickly) * when trying to add a DELETE_IS_SUPER operation. Thus we split the codes carefully @@ -806,6 +808,26 @@ typedef struct xl_heap_delete { #define SizeOfOldHeapDelete (offsetof(xl_heap_delete, flags) + sizeof(uint8)) #define SizeOfHeapDelete (offsetof(xl_heap_delete, infobits_set) + sizeof(uint8)) +/* + * xl_heap_delete flag values, 8 bits are available. + */ +#define XLH_TRUNCATE_CASCADE (1<<0) +#define XLH_TRUNCATE_RESTART_SEQS (1<<1) + +/* + * For truncate we list all truncated relids in an array, followed by all + * sequence relids that need to be restarted, if any. + * All rels are always within the same database, so we just list dbid once. + */ +typedef struct xl_heap_truncate { + Oid dbId; + uint32 nrelids; + uint8 flags; + Oid relids[FLEXIBLE_ARRAY_MEMBER]; +} xl_heap_truncate; + +#define SizeOfHeapTruncate (offsetof(xl_heap_truncate, relids)) + /* * We don't store the whole fixed part (HeapTupleHeaderData) of an inserted * or updated tuple in WAL; we can save a few bytes by reconstructing the diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h index 01c4788eb..3e883a7db 100644 --- a/src/include/catalog/heap.h +++ b/src/include/catalog/heap.h @@ -118,30 +118,31 @@ extern Oid heap_create_with_catalog(const char *relname, Oid relnamespace, Oid reltablespace, Oid relid, - Oid reltypeid, - Oid reloftypeid, - Oid ownerid, - TupleDesc tupdesc, - List *cooked_constraints, - char relkind, - char relpersistence, - bool shared_relation, - bool mapped_relation, - bool oidislocal, - int oidinhcount, - OnCommitAction oncommit, - Datum reloptions, - bool use_user_acl, - bool allow_system_table_mods, - PartitionState *partTableState, - int8 row_compress, - HashBucketInfo *bucketinfo, - bool record_dependce = true, - List* ceLst = NULL, - StorageType storage_type = HEAP_DISK, - LOCKMODE partLockMode = AccessExclusiveLock, + Oid reltypeid, + Oid reloftypeid, + Oid ownerid, + TupleDesc tupdesc, + List *cooked_constraints, + char relkind, + char relpersistence, + bool shared_relation, + bool mapped_relation, + bool oidislocal, + int oidinhcount, + OnCommitAction oncommit, + Datum reloptions, + bool use_user_acl, + bool allow_system_table_mods, + PartitionState *partTableState, + int8 row_compress, + HashBucketInfo *bucketinfo, + bool record_dependce = true, + List* ceLst = NULL, + StorageType storage_type = HEAP_DISK, + LOCKMODE partLockMode = AccessExclusiveLock, ObjectAddress *typaddress= NULL, - List* depend_extend = NIL); + List* depend_extend = NIL, + Oid relrewrite = InvalidOid); extern void heap_create_init_fork(Relation rel); diff --git a/src/include/catalog/pg_publication.h b/src/include/catalog/pg_publication.h index 6a71b9eae..07387d058 100644 --- a/src/include/catalog/pg_publication.h +++ b/src/include/catalog/pg_publication.h @@ -24,6 +24,7 @@ /* Publication trigger events */ #define PUB_TRIG_DDL_CMD_END "ddl_command_end" #define PUB_TRIG_DDL_CMD_START "ddl_command_start" +#define PUB_TRIG_TBL_REWRITE "table_rewrite" /* Publication event trigger prefix */ #define PUB_EVENT_TRIG_FORMAT "pg_deparse_trig_%s_%u" @@ -62,6 +63,9 @@ CATALOG(pg_publication,6130) BKI_ROWTYPE_OID(6141) BKI_SCHEMA_MACRO bool pubdelete; int8 pubddl; + + /* true if truncates are published */ + bool pubtruncate; } FormData_pg_publication; #undef int8 @@ -78,7 +82,7 @@ typedef FormData_pg_publication *Form_pg_publication; * ---------------- */ -#define Natts_pg_publication 7 +#define Natts_pg_publication 8 #define Anum_pg_publication_pubname 1 #define Anum_pg_publication_pubowner 2 #define Anum_pg_publication_puballtables 3 @@ -86,11 +90,13 @@ typedef FormData_pg_publication *Form_pg_publication; #define Anum_pg_publication_pubupdate 5 #define Anum_pg_publication_pubdelete 6 #define Anum_pg_publication_pubddl 7 +#define Anum_pg_publication_pubtruncate 8 typedef struct PublicationActions { bool pubinsert; bool pubupdate; bool pubdelete; + bool pubtruncate; int64 pubddl; } PublicationActions; diff --git a/src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback-post_catalog_maindb_92_949.sql b/src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback-post_catalog_maindb_92_949.sql new file mode 100644 index 000000000..07a9f6307 --- /dev/null +++ b/src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback-post_catalog_maindb_92_949.sql @@ -0,0 +1 @@ +DROP FUNCTION IF EXISTS pg_catalog.publication_deparse_table_rewrite() CASCADE; diff --git a/src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback-post_catalog_otherdb_92_949.sql b/src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback-post_catalog_otherdb_92_949.sql new file mode 100644 index 000000000..07a9f6307 --- /dev/null +++ b/src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback-post_catalog_otherdb_92_949.sql @@ -0,0 +1 @@ +DROP FUNCTION IF EXISTS pg_catalog.publication_deparse_table_rewrite() CASCADE; diff --git a/src/include/catalog/upgrade_sql/upgrade_catalog_maindb/upgrade-post_catalog_maindb_92_949.sql b/src/include/catalog/upgrade_sql/upgrade_catalog_maindb/upgrade-post_catalog_maindb_92_949.sql new file mode 100644 index 000000000..6e9fc0e40 --- /dev/null +++ b/src/include/catalog/upgrade_sql/upgrade_catalog_maindb/upgrade-post_catalog_maindb_92_949.sql @@ -0,0 +1,6 @@ +DROP FUNCTION IF EXISTS pg_catalog.publication_deparse_table_rewrite() CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids = IUO_PROC, 4644; +CREATE FUNCTION pg_catalog.publication_deparse_table_rewrite () +RETURNS event_trigger +LANGUAGE INTERNAL VOLATILE STRICT NOT FENCED +AS 'publication_deparse_table_rewrite'; diff --git a/src/include/catalog/upgrade_sql/upgrade_catalog_otherdb/upgrade-post_catalog_otherdb_92_949.sql b/src/include/catalog/upgrade_sql/upgrade_catalog_otherdb/upgrade-post_catalog_otherdb_92_949.sql new file mode 100644 index 000000000..6e9fc0e40 --- /dev/null +++ b/src/include/catalog/upgrade_sql/upgrade_catalog_otherdb/upgrade-post_catalog_otherdb_92_949.sql @@ -0,0 +1,6 @@ +DROP FUNCTION IF EXISTS pg_catalog.publication_deparse_table_rewrite() CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids = IUO_PROC, 4644; +CREATE FUNCTION pg_catalog.publication_deparse_table_rewrite () +RETURNS event_trigger +LANGUAGE INTERNAL VOLATILE STRICT NOT FENCED +AS 'publication_deparse_table_rewrite'; diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h index cb0efcb41..4827c16a6 100644 --- a/src/include/commands/defrem.h +++ b/src/include/commands/defrem.h @@ -210,10 +210,12 @@ extern Oid GetFunctionNodeGroupByFuncid(Oid funcid); extern Oid GetFunctionNodeGroup(AlterFunctionStmt* stmt); /* commands/eventcmds.c */ -extern void CreateEventCommand(CreateEventStmt* stmt); -extern void AlterEventCommand(AlterEventStmt* stmt); +extern ObjectAddress CreateEventCommand(CreateEventStmt* stmt); +extern ObjectAddress AlterEventCommand(AlterEventStmt* stmt); extern void DropEventCommand(DropEventStmt* stmt); - +extern char* parseIntervalExprString(Node *intervalNode); +extern char* parseTimeExprString(Node* timeExpr); + #endif /* !FRONTEND_PARSER */ extern DefElem* defWithOids(bool value); #endif /* DEFREM_H */ diff --git a/src/include/commands/event_trigger.h b/src/include/commands/event_trigger.h index a4f817fff..3e5251048 100644 --- a/src/include/commands/event_trigger.h +++ b/src/include/commands/event_trigger.h @@ -110,8 +110,7 @@ extern void EventTriggerCollectSimpleCommand(ObjectAddress address, extern void EventTriggerAlterTableStart(Node *parsetree); extern void EventTriggerAlterTableRelid(Oid objectId); -extern void EventTriggerCollectAlterTableSubcmd(Node *subcmd, - ObjectAddress address); +extern void EventTriggerCollectAlterTableSubcmd(Node *subcmd, ObjectAddress address, bool rewrite); extern void EventTriggerAlterTableEnd(void); extern void EventTriggerCollectGrant(InternalGrant *istmt); @@ -124,6 +123,8 @@ extern void EventTriggerCollectCreateOpClass(CreateOpClassStmt *stmt, extern void EventTriggerCollectAlterTSConfig(AlterTSConfigurationStmt *stmt, Oid cfgId, Oid *dictIds, int ndicts); extern void EventTriggerCollectAlterDefPrivs(AlterDefaultPrivilegesStmt *stmt); - +extern void EventTriggerAlterTypeStart(AlterTableCmd *subcmd, Relation rel); +extern void EventTriggerAlterTypeEnd(Node *subcmd, ObjectAddress address, int rewrite); +extern void EventTriggerAlterTypeUpdate(ObjectAddress address, AttrNumber old_attnum); #endif /* EVENT_TRIGGER_H */ diff --git a/src/include/commands/tablecmds.h b/src/include/commands/tablecmds.h index bd86680b1..df2c4ed18 100644 --- a/src/include/commands/tablecmds.h +++ b/src/include/commands/tablecmds.h @@ -159,6 +159,10 @@ extern void ExecuteTruncate(TruncateStmt* stmt, const char* sql_statement); extern void ExecuteTruncate(TruncateStmt* stmt); #endif +extern void ExecuteTruncateGuts( + List *explicit_rels, List *relids, List *relids_logged, List *rels_in_redis, + DropBehavior behavior, bool restart_seqs, TruncateStmt* stmt); + extern void SetRelationHasSubclass(Oid relationId, bool relhassubclass); extern ObjectAddress renameatt(RenameStmt* stmt); @@ -169,6 +173,7 @@ extern ObjectAddress RenameRelation(RenameStmt* stmt); extern void RenameRelationInternal(Oid myrelid, const char* newrelname, char* newschema = NULL); +extern void ResetRelRewrite(Oid myrelid); extern void find_composite_type_dependencies(Oid typeOid, Relation origRelation, const char* origTypeName); extern void check_of_type(HeapTuple typetuple); diff --git a/src/include/knl/knl_session.h b/src/include/knl/knl_session.h index 9a9b00b8f..0f078c144 100644 --- a/src/include/knl/knl_session.h +++ b/src/include/knl/knl_session.h @@ -2956,6 +2956,7 @@ typedef struct knl_u_hook_context { void *nullsMinimalPolicyHook; void *getIgnoreKeywordTokenHook; void *modifyTypeForPartitionKeyHook; + void *deparseCollectedCommandHook; } knl_u_hook_context; typedef struct knl_u_libsw_context { diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h index c2bafe7b1..72284dc63 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -37,6 +37,7 @@ /***************************************************************************** * Backend version and inplace upgrade staffs *****************************************************************************/ +extern const uint32 PUBLICATION_DDL_AT_VERSION_NUM; extern const uint32 PIPELINED_FUNCTION_VERSION_NUM; extern const uint32 DISABLE_CONSTRAINT_VERSION_NUM; extern const uint32 SUPPORT_GS_DEPENDENCY_VERSION_NUM; diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index be0c43840..b6fff9b1f 100755 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -1409,6 +1409,7 @@ typedef struct AlterFunctionStmt { NodeTag type; FuncWithArgs* func; /* name and args of function */ List* actions; /* list of DefElem */ + bool isProcedure = false; } AlterFunctionStmt; enum CompileEntry { diff --git a/src/include/nodes/parsenodes_common.h b/src/include/nodes/parsenodes_common.h index 0a000d37b..b818ba8fa 100644 --- a/src/include/nodes/parsenodes_common.h +++ b/src/include/nodes/parsenodes_common.h @@ -1002,6 +1002,7 @@ typedef struct AlterTableCmd { /* one subcommand of an ALTER TABLE */ bool alterGPI; /* check whether is global partition index alter statement */ bool is_first; /* a flag of ALTER TABLE ... ADD ... FIRST */ char *after_name; /* column name of ALTER TABLE ... ADD ... AFTER column_name */ + bool recursing; } AlterTableCmd; typedef struct AddTableIntoCBIState { @@ -1166,6 +1167,7 @@ typedef struct ColumnDef { Form_pg_attribute dropped_attr; /* strcuture for dropped attribute during create table like OE */ char generatedCol; /* generated column setting */ Node *update_default; + char *initdefval; } ColumnDef; /* @@ -2473,6 +2475,7 @@ typedef struct RenameStmt { bool missing_ok; /* skip error if missing? */ List* renameTargetList = NULL; bool renameTableflag = false; + bool is_modifycolumn = false; } RenameStmt; /* ---------------------- diff --git a/src/include/replication/ddlmessage.h b/src/include/replication/ddlmessage.h index 60135e9e6..82a5f5e69 100644 --- a/src/include/replication/ddlmessage.h +++ b/src/include/replication/ddlmessage.h @@ -21,11 +21,14 @@ */ typedef enum DeparsedCommandType { - DCT_ObjectCreate, - DCT_ObjectDrop, DCT_SimpleCmd, DCT_TableDropEnd, - DCT_TableDropStart + DCT_TableDropStart, + DCT_TableAlter, + DCT_ObjectCreate, + DCT_ObjectDrop, + DCT_TypeDropStart, + DCT_TypeDropEnd } DeparsedCommandType; /* diff --git a/src/include/replication/logicalproto.h b/src/include/replication/logicalproto.h index aab505b16..a1d646396 100644 --- a/src/include/replication/logicalproto.h +++ b/src/include/replication/logicalproto.h @@ -103,6 +103,10 @@ extern LogicalRepRelId logicalrep_read_update(StringInfo in, bool *has_oldtuple, LogicalRepTupleData *newtup); extern void logicalrep_write_delete(StringInfo out, Relation rel, HeapTuple oldtuple, bool binary); extern LogicalRepRelId logicalrep_read_delete(StringInfo in, LogicalRepTupleData *oldtup); +extern void logicalrep_write_truncate(StringInfo out, int nrelids, Oid relids[], + bool cascade, bool restart_seqs); +extern List *logicalrep_read_truncate(StringInfo in, + bool *cascade, bool *restart_seqs); extern void logicalrep_write_rel(StringInfo out, Relation rel); extern LogicalRepRelation *logicalrep_read_rel(StringInfo in); extern void logicalrep_write_typ(StringInfo out, Oid typoid); diff --git a/src/include/replication/output_plugin.h b/src/include/replication/output_plugin.h index 0b19a8713..b64cb085f 100644 --- a/src/include/replication/output_plugin.h +++ b/src/include/replication/output_plugin.h @@ -30,6 +30,7 @@ typedef enum OutputPluginOutputType { */ typedef struct OutputPluginOptions { OutputPluginOutputType output_type; + bool receive_rewrites; } OutputPluginOptions; /* @@ -75,6 +76,15 @@ typedef void (*LogicalDecodeChangeCB)( typedef void (*ParallelLogicalDecodeChangeCB)( struct ParallelLogicalDecodingContext* ctx, ReorderBufferTXN* txn, Relation relation, ParallelReorderBufferChange* change); +/* + * Callback for every TRUNCATE in a successful transaction. + */ +typedef void (*LogicalDecodeTruncateCB) (struct LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, + int nrelations, + Relation relations[], + ReorderBufferChange *change); + /* * Called for every (explicit or implicit) COMMIT of a successful transaction. */ @@ -107,6 +117,7 @@ typedef struct OutputPluginCallbacks { LogicalDecodeStartupCB startup_cb; LogicalDecodeBeginCB begin_cb; LogicalDecodeChangeCB change_cb; + LogicalDecodeTruncateCB truncate_cb; LogicalDecodeCommitCB commit_cb; LogicalDecodeAbortCB abort_cb; LogicalDecodePrepareCB prepare_cb; @@ -119,6 +130,7 @@ typedef struct ParallelOutputPluginCallbacks { LogicalDecodeStartupCB startup_cb; LogicalDecodeBeginCB begin_cb; ParallelLogicalDecodeChangeCB change_cb; + LogicalDecodeTruncateCB truncate_cb; LogicalDecodeCommitCB commit_cb; LogicalDecodeShutdownCB shutdown_cb; LogicalDecodeFilterByOriginCB filter_by_origin_cb; diff --git a/src/include/replication/reorderbuffer.h b/src/include/replication/reorderbuffer.h index 8c8319bd3..fa802d617 100644 --- a/src/include/replication/reorderbuffer.h +++ b/src/include/replication/reorderbuffer.h @@ -73,6 +73,7 @@ enum ReorderBufferChangeType { REORDER_BUFFER_CHANGE_INTERNAL_COMMAND_ID, REORDER_BUFFER_CHANGE_INTERNAL_TUPLECID, REORDER_BUFFER_CHANGE_DDL, + REORDER_BUFFER_CHANGE_TRUNCATE, REORDER_BUFFER_CHANGE_UINSERT, REORDER_BUFFER_CHANGE_UUPDATE, REORDER_BUFFER_CHANGE_UDELETE @@ -115,6 +116,17 @@ typedef struct ReorderBufferChange { CommitSeqNo snapshotcsn; } tp; + /* + * Truncate data for REORDER_BUFFER_CHANGE_TRUNCATE representing + * one set of relations to be truncated. + */ + struct { + Size nrelids; + bool cascade; + bool restart_seqs; + Oid *relids; + } truncate; + /* Old, new utuples when action == UHEAP_INSERT|UPDATE|DELETE */ struct { /* relation that has been changed */ @@ -213,8 +225,8 @@ typedef struct ReorderBufferTXN { XLogRecPtr restart_decoding_lsn; /* origin of the change that caused this transaction */ - RepOriginId origin_id; - XLogRecPtr origin_lsn; + RepOriginId origin_id; + XLogRecPtr origin_lsn; /* The csn of the transaction */ CommitSeqNo csn; @@ -317,7 +329,9 @@ typedef struct ReorderBuffer ReorderBuffer; /* change callback signature */ typedef void (*ReorderBufferApplyChangeCB)( ReorderBuffer* rb, ReorderBufferTXN* txn, Relation relation, ReorderBufferChange* change); - +/* truncate callback signature */ +typedef void (*ReorderBufferApplyTruncateCB) ( + ReorderBuffer *rb, ReorderBufferTXN *txn, int nrelations, Relation relations[], ReorderBufferChange *change); /* begin callback signature */ typedef void (*ReorderBufferBeginCB)(ReorderBuffer* rb, ReorderBufferTXN* txn); @@ -374,6 +388,7 @@ struct ReorderBuffer { */ ReorderBufferBeginCB begin; ReorderBufferApplyChangeCB apply_change; + ReorderBufferApplyTruncateCB apply_truncate; ReorderBufferCommitCB commit; ReorderBufferAbortCB abort; ReorderBufferPrepareCB prepare; @@ -384,6 +399,11 @@ struct ReorderBuffer { */ void* private_data; + /* + * Saved output plugin option + */ + bool output_rewrites; + /* * Private memory context. */ diff --git a/src/include/tcop/ddldeparse.h b/src/include/tcop/ddldeparse.h index 4f44aabe9..325344a8a 100644 --- a/src/include/tcop/ddldeparse.h +++ b/src/include/tcop/ddldeparse.h @@ -16,6 +16,7 @@ /* Context info needed for deparsing ddl command */ typedef struct { + bool verbose_mode; /* * include_owner indicates if the owner/role of the command should be * included in the deparsed Json output. It is set to false for any commands @@ -29,9 +30,73 @@ typedef struct char max_volatility; } ddl_deparse_context; +extern Relation table_open(Oid relationId, LOCKMODE lockmode); +extern void table_close(Relation relation, LOCKMODE lockmode); extern char *deparse_utility_command(CollectedCommand *cmd, ddl_deparse_context * context); extern char *deparse_ddl_json_to_string(char *jsonb, char** owner); extern char *deparse_drop_command(const char *objidentity, const char *objecttype, Node *parsetree); +extern List *deparse_altertable_end(CollectedCommand *cmd); +extern bool relation_support_ddl_replication(Oid relid, bool rewrite = false); +/* + * Before they are turned into JSONB representation, each command is + * represented as an object tree, using the structs below. + */ +typedef enum +{ + ObjTypeNull, + ObjTypeBool, + ObjTypeString, + ObjTypeArray, + ObjTypeInteger, + ObjTypeFloat, + ObjTypeObject +} ObjType; + +/* + * Represent the command as an object tree. + */ +typedef struct ObjTree +{ + slist_head params; /* Object tree parameters */ + int numParams; /* Number of parameters in the object tree */ + StringInfo fmtinfo; /* Format string of the ObjTree */ + bool present; /* Indicates if boolean value should be stored */ +} ObjTree; + +/* + * An element of an object tree (ObjTree). + */ +typedef struct ObjElem +{ + char *name; /* Name of object element */ + ObjType objtype; /* Object type */ + + union { + bool boolean; + char *string; + int64 integer; + float8 flt; + ObjTree *object; + List *array; + } value; /* Store the object value based on the object + * type */ + slist_node node; /* Used in converting back to ObjElem + * structure */ +} ObjElem; + +ObjTree *new_objtree_VA(const char *fmt, int numobjs, ...); +ObjElem *new_string_object(char *value); +void append_format_string(ObjTree *tree, char *sub_fmt); +void append_object_object(ObjTree *tree, char *sub_fmt, ObjTree *value); +void append_string_object(ObjTree *tree, char *sub_fmt, char *name, + const char *value); +void append_array_object(ObjTree *tree, char *sub_fmt, List *array); +typedef enum { + DEPARSE_SIMPLE_COMMAND, + ALTER_RELATION_SUBCMD +} collectCmdHookType; +typedef void *(*deparseCollectedCommand)(int type, CollectedCommand *cmd, CollectedATSubcmd *sub, + ddl_deparse_context *context); #endif /* DDL_DEPARSE_H */ diff --git a/src/include/tcop/deparse_utility.h b/src/include/tcop/deparse_utility.h index 8bd7f3926..347836053 100644 --- a/src/include/tcop/deparse_utility.h +++ b/src/include/tcop/deparse_utility.h @@ -38,6 +38,7 @@ typedef struct CollectedATSubcmd { ObjectAddress address; /* affected column, constraint, index, ... */ Node *parsetree; + char *usingexpr; } CollectedATSubcmd; typedef struct CollectedCommand @@ -61,6 +62,7 @@ typedef struct CollectedCommand { Oid objectId; Oid classId; + bool rewrite; List *subcmds; } alterTable; diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index f0f15ecd8..35039ff72 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -416,6 +416,7 @@ typedef struct StdRdOptions { /* SPQ OPTIONS */ int spq_bt_build_offset; #endif + Oid relrewrite; } StdRdOptions; #define HEAP_MIN_FILLFACTOR 10 @@ -543,6 +544,8 @@ typedef struct StdRdOptions { ((relation)->rd_options ? \ ((StdRdOptions *) (relation)->rd_options)->parallel_workers : (defaultpw)) +#define RelationGetRelrewriteOption(relation) \ + ((relation)->rd_options ? ((StdRdOptions*)(relation)->rd_options)->relrewrite : InvalidOid) /* * RelationIsValid * True iff relation descriptor is valid. diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 946c248c1..d2dcc4041 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -569,8 +569,8 @@ SELECT (pg_identify_object(addr1.classid, addr1.objid, addr1.subobjid)).* type | addr_nsp | gencomptype | addr_nsp.gencomptype type | addr_nsp | genenum | addr_nsp.genenum type | addr_nsp | gendomain | addr_nsp.gendomain - function | pg_catalog | | pg_identify_object(oid,oid,integer) - function | addr_nsp | | genaggr(integer) + function | pg_catalog | | pg_catalog.pg_identify_object(oid,oid,integer) + function | addr_nsp | | addr_nsp.genaggr(integer) sequence | addr_nsp | gentable_a_seq | addr_nsp.gentable_a_seq table | addr_nsp | gentable | addr_nsp.gentable table column | addr_nsp | gentable | addr_nsp.gentable.b diff --git a/src/test/regress/expected/on_update_session2.out b/src/test/regress/expected/on_update_session2.out index fef93c808..88a23239f 100644 --- a/src/test/regress/expected/on_update_session2.out +++ b/src/test/regress/expected/on_update_session2.out @@ -8,7 +8,7 @@ select pg_sleep(2); update tb666 set c2 = 3; select * from tb666; c1 | c2 | c3 ----------------------------------+----+--------------------------------- +--?.*-----------------+----+------------------.* --?.* (1 row) diff --git a/src/test/regress/output/publication.source b/src/test/regress/output/publication.source index c7234d93c..09058f5c2 100644 --- a/src/test/regress/output/publication.source +++ b/src/test/regress/output/publication.source @@ -200,8 +200,8 @@ select pubname, tablename from pg_publication_tables where tablename='testpub_tb --- drop publication DROP PUBLICATION testpub_foralltables_rename; select * from pg_publication where pubname='testpub_foralltables_rename'; - pubname | pubowner | puballtables | pubinsert | pubupdate | pubdelete | pubddl ----------+----------+--------------+-----------+-----------+-----------+-------- + pubname | pubowner | puballtables | pubinsert | pubupdate | pubdelete | pubddl | pubtruncate +---------+----------+--------------+-----------+-----------+-----------+--------+------------- (0 rows) DROP PUBLICATION IF EXISTS testpub_nonexists; diff --git a/src/test/regress/pg_regress.cpp b/src/test/regress/pg_regress.cpp index 2e06a819a..c4bc35f71 100644 --- a/src/test/regress/pg_regress.cpp +++ b/src/test/regress/pg_regress.cpp @@ -5516,7 +5516,7 @@ static void check_global_variables() } } -#define BASE_PGXC_LIKE_MACRO_NUM 1381 +#define BASE_PGXC_LIKE_MACRO_NUM 1382 static void check_pgxc_like_macros() { #ifdef BUILD_BY_CMAKE diff --git a/src/test/subscription/schedule b/src/test/subscription/schedule index 77099239b..d39f9cd7d 100644 --- a/src/test/subscription/schedule +++ b/src/test/subscription/schedule @@ -1,4 +1,5 @@ rep_changes +ddl_replication pub_switchover types constraints @@ -15,5 +16,4 @@ skiplsn disable pub_subconflict bugs -ddl_replication dump \ No newline at end of file diff --git a/src/test/subscription/testcase/ddl_replication_sql/A/acceptable_diff/create_table.diff b/src/test/subscription/testcase/ddl_replication_sql/A/acceptable_diff/create_table.diff deleted file mode 100644 index 3d25e9feb..000000000 --- a/src/test/subscription/testcase/ddl_replication_sql/A/acceptable_diff/create_table.diff +++ /dev/null @@ -1,25 +0,0 @@ -6109,6132d6108 -< -- Name: tab_foreign_child_col_a_fkey; Type: FK CONSTRAINT; Schema: public; Owner: ddl_test_user -< -- -< -< ALTER TABLE tab_foreign_child -< ADD CONSTRAINT tab_foreign_child_col_a_fkey FOREIGN KEY (col_a, col_b) REFERENCES tab_foreign_parent(col_1, col_2); -< -< -< -- -< -- Name: tab_product2_currency_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: ddl_test_user -< -- -< -< ALTER TABLE tab_product2 -< ADD CONSTRAINT tab_product2_currency_id_fkey FOREIGN KEY (currency_id) REFERENCES tab_currency(col_id); -< -< -< -- -< -- Name: tab_product_currency_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: ddl_test_user -< -- -< -< ALTER TABLE tab_product -< ADD CONSTRAINT tab_product_currency_id_fkey FOREIGN KEY (currency_id) REFERENCES tab_currency(col_id); -< -< -< -- diff --git a/src/test/subscription/testcase/ddl_replication_sql/A/create_table.sql b/src/test/subscription/testcase/ddl_replication_sql/A/create_table.sql index 39fa0676e..be55e3ed9 100644 --- a/src/test/subscription/testcase/ddl_replication_sql/A/create_table.sql +++ b/src/test/subscription/testcase/ddl_replication_sql/A/create_table.sql @@ -767,6 +767,15 @@ INSERT INTO func_index_heap VALUES('ABCD', 'EF'); -- but this shouldn't: INSERT INTO func_index_heap VALUES('QWERTY'); +DROP TABLE if exists tb_truncate; +CREATE TABLE tb_truncate (f1 text primary key, f2 text); +INSERT INTO tb_truncate VALUES('ABC','DEF'); +INSERT INTO tb_truncate VALUES('AB','CDEFG'); +INSERT INTO tb_truncate VALUES('QWE','RTY'); +INSERT INTO tb_truncate VALUES('ABCD', 'EF'); +INSERT INTO tb_truncate VALUES('QWERTY','IJBN'); +truncate TABLE tb_truncate; + -- -- Also try building functional, expressional, and partial indexes on -- tables that already contain data. @@ -820,3 +829,15 @@ DROP INDEX CONCURRENTLY "concur_index4"; DROP INDEX CONCURRENTLY "concur_index5"; DROP INDEX CONCURRENTLY "concur_index1"; DROP INDEX CONCURRENTLY "concur_heap_expr_idx"; + + +CREATE TABLE Ctlt1 (a text CHECK (length(a) > 2) PRIMARY KEY, b text); +CREATE INDEX ctlt1_b_key ON Ctlt1 (b); +CREATE INDEX ctlt1_fnidx ON Ctlt1 ((a || b)); +COMMENT ON COLUMN Ctlt1.a IS 'A'; +COMMENT ON COLUMN Ctlt1.b IS 'B'; +COMMENT ON CONSTRAINT ctlt1_a_check ON Ctlt1 IS 't1_a_check'; +COMMENT ON INDEX ctlt1_pkey IS 'index pkey'; +COMMENT ON INDEX ctlt1_b_key IS 'index b_key'; +ALTER TABLE Ctlt1 ALTER COLUMN a SET STORAGE MAIN; + diff --git a/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_function.setup b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_function.setup new file mode 100644 index 000000000..234cbb4cd --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_function.setup @@ -0,0 +1,9 @@ +#!/bin/sh + +source $1/env_utils.sh $1 $2 +subscription_dir=$1 +case_use_db=$3 + +exec_sql_with_user $case_use_db $pub_node1_port "CREATE USER regtest_unpriv_user PASSWORD 'gauss@123'" + +exec_sql_with_user $case_use_db $sub_node1_port "CREATE USER regtest_unpriv_user PASSWORD 'gauss@123'" \ No newline at end of file diff --git a/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_function.sql b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_function.sql new file mode 100644 index 000000000..c1c47769c --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_function.sql @@ -0,0 +1,55 @@ +-- +-- IMMUTABLE | STABLE | VOLATILE +-- +CREATE FUNCTION functest_B_1(int) RETURNS bool LANGUAGE 'sql' + AS 'SELECT $1 > 0'; +CREATE FUNCTION functest_B_2(int) RETURNS bool LANGUAGE 'sql' + IMMUTABLE AS 'SELECT $1 > 0'; +CREATE FUNCTION functest_B_3(int) RETURNS bool LANGUAGE 'sql' + STABLE AS 'SELECT $1 = 0'; +CREATE FUNCTION functest_B_4(int) RETURNS bool LANGUAGE 'sql' + VOLATILE AS 'SELECT $1 < 0'; +ALTER FUNCTION functest_B_2(int) VOLATILE; + +-- +-- SECURITY DEFINER | INVOKER +-- +CREATE FUNCTION functest_C_1(int) RETURNS bool LANGUAGE 'sql' + AS 'SELECT $1 > 0'; +CREATE FUNCTION functest_C_2(int) RETURNS bool LANGUAGE 'sql' + SECURITY DEFINER AS 'SELECT $1 = 0'; +CREATE FUNCTION functest_C_3(int) RETURNS bool LANGUAGE 'sql' + SECURITY INVOKER AS 'SELECT $1 < 0'; +ALTER FUNCTION functest_C_1(int) IMMUTABLE; -- unrelated change, no effect +ALTER FUNCTION functest_C_2(int) SECURITY INVOKER; +ALTER FUNCTION functest_C_3(int) SECURITY DEFINER; + +-- +-- LEAKPROOF +-- +CREATE FUNCTION functest_E_1(int) RETURNS bool LANGUAGE 'sql' + AS 'SELECT $1 > 100'; +CREATE FUNCTION functest_E_2(int) RETURNS bool LANGUAGE 'sql' + LEAKPROOF AS 'SELECT $1 > 100'; +ALTER FUNCTION functest_E_1(int) LEAKPROOF; +ALTER FUNCTION functest_E_2(int) STABLE; -- unrelated change, no effect +ALTER FUNCTION functest_E_2(int) NOT LEAKPROOF; -- remove leakproog attribute +-- it takes superuser privilege to turn on leakproof, but not for turn off +--ALTER FUNCTION functest_E_1(int) OWNER TO regtest_unpriv_user; +--ALTER FUNCTION functest_E_2(int) OWNER TO regtest_unpriv_user; + + +-- +-- CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT +-- +CREATE FUNCTION functest_F_1(int) RETURNS bool LANGUAGE 'sql' + AS 'SELECT $1 > 50'; +CREATE FUNCTION functest_F_2(int) RETURNS bool LANGUAGE 'sql' + CALLED ON NULL INPUT AS 'SELECT $1 = 50'; +CREATE FUNCTION functest_F_3(int) RETURNS bool LANGUAGE 'sql' + RETURNS NULL ON NULL INPUT AS 'SELECT $1 < 50'; +CREATE FUNCTION functest_F_4(int) RETURNS bool LANGUAGE 'sql' + STRICT AS 'SELECT $1 = 50'; +ALTER FUNCTION functest_F_1(int) IMMUTABLE; -- unrelated change, no effect +ALTER FUNCTION functest_F_2(int) STRICT; +ALTER FUNCTION functest_F_3(int) CALLED ON NULL INPUT; \ No newline at end of file diff --git a/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_function.teardown b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_function.teardown new file mode 100644 index 000000000..4e450e63b --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_function.teardown @@ -0,0 +1,8 @@ +#!/bin/sh + +source $1/env_utils.sh $1 $2 +subscription_dir=$1 +case_use_db=$3 + +exec_sql_with_user $case_use_db $sub_node1_port "DROP USER regtest_unpriv_user" +exec_sql_with_user $case_use_db $pub_node1_port "DROP USER regtest_unpriv_user" \ No newline at end of file diff --git a/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table.sql b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table.sql new file mode 100644 index 000000000..5c8d7126b --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table.sql @@ -0,0 +1,2418 @@ +-- +--FOR BLACKLIST FEATURE: REFERENCES/INHERITS/WITH OIDS/RULE/CREATE TYPE/DOMAIN is not supported. +-- +-- test inheritance + +create table dropColumn (a int, b int, e int); +create table dropColumnChild (c int) inherits (dropColumn); +create table dropColumnAnother (d int) inherits (dropColumnChild); + +-- these two should fail +alter table dropColumnchild drop column a; +alter table only dropColumnChild drop column b; + + + +-- these three should work +alter table only dropColumn drop column e; +alter table dropColumnChild drop column c; +alter table dropColumn drop column a; + +create table renameColumn (a int); +create table renameColumnChild (b int) inherits (renameColumn); +create table renameColumnAnother (c int) inherits (renameColumnChild); + +-- these three should fail +alter table renameColumnChild rename column a to d; +alter table only renameColumnChild rename column a to d; +alter table only renameColumn rename column a to d; + +-- these should work +alter table renameColumn rename column a to d; +alter table renameColumnChild rename column b to a; + +-- these should work +alter table if exists doesnt_exist_tab rename column a to d; +alter table if exists doesnt_exist_tab rename column b to a; + +-- this should work +alter table renameColumn add column w int; + +-- this should fail +alter table only renameColumn add column x int; + + +-- Test corner cases in dropping of inherited columns + +create table p1 (f1 int, f2 int); +create table c1 (f1 int not null) inherits(p1); + +-- should be rejected since c1.f1 is inherited +alter table c1 drop column f1; +-- should work +alter table p1 drop column f1; +-- c1.f1 is still there, but no longer inherited +select f1 from c1; +alter table c1 drop column f1; +select f1 from c1; + +drop table p1 cascade; + +create table p1 (f1 int, f2 int); +create table c1 () inherits(p1); + +-- should be rejected since c1.f1 is inherited +alter table c1 drop column f1; +alter table p1 drop column f1; +-- c1.f1 is dropped now, since there is no local definition for it +select f1 from c1; + +drop table p1 cascade; + +create table p1 (f1 int, f2 int); +create table c1 () inherits(p1); + +-- should be rejected since c1.f1 is inherited +alter table c1 drop column f1; +alter table only p1 drop column f1; +-- c1.f1 is NOT dropped, but must now be considered non-inherited +alter table c1 drop column f1; + +drop table p1 cascade; + +create table p1 (f1 int, f2 int); +create table c1 (f1 int not null) inherits(p1); + +-- should be rejected since c1.f1 is inherited +alter table c1 drop column f1; +alter table only p1 drop column f1; +-- c1.f1 is still there, but no longer inherited +alter table c1 drop column f1; + +drop table p1 cascade; + +create table p1(id int, name text); +create table p2(id2 int, name text, height int); +create table c1(age int) inherits(p1,p2); +create table gc1() inherits (c1); + +select relname, attname, attinhcount, attislocal +from pg_class join pg_attribute on (pg_class.oid = pg_attribute.attrelid) +where relname in ('p1','p2','c1','gc1') and attnum > 0 and not attisdropped +order by relname, attnum; + +-- should work +alter table only p1 drop column name; +-- should work. Now c1.name is local and inhcount is 0. +alter table p2 drop column name; +-- should be rejected since its inherited +alter table gc1 drop column name; +-- should work, and drop gc1.name along +alter table c1 drop column name; +-- should fail: column does not exist +alter table gc1 drop column name; +-- should work and drop the attribute in all tables +alter table p2 drop column height; + +select relname, attname, attinhcount, attislocal +from pg_class join pg_attribute on (pg_class.oid = pg_attribute.attrelid) +where relname in ('p1','p2','c1','gc1') and attnum > 0 and not attisdropped +order by relname, attnum; + +drop table p1, p2 cascade; + +-- +-- Test the ALTER TABLE SET WITH/WITHOUT OIDS command +-- +create table altstartwith (col integer) with oids; + +insert into altstartwith values (1); + +select oid > 0, * from altstartwith; + +alter table altstartwith set without oids; + +select oid > 0, * from altstartwith; -- fails +select * from altstartwith; + +alter table altstartwith set with oids; + +select oid > 0, * from altstartwith; + +drop table altstartwith; + +-- Check inheritance cases +create table altwithoid (col integer) with oids; + +-- Inherits parents oid column anyway +create table altinhoid () inherits (altwithoid) without oids; + +insert into altinhoid values (1); + +select oid > 0, * from altwithoid; +select oid > 0, * from altinhoid; + +alter table altwithoid set without oids; + +select oid > 0, * from altwithoid; -- fails +select oid > 0, * from altinhoid; -- fails +select * from altwithoid; +select * from altinhoid; + +alter table altwithoid set with oids; + +select oid > 0, * from altwithoid; +select oid > 0, * from altinhoid; + +drop table altwithoid cascade; + +create table altwithoid (col integer) without oids; + +-- child can have local oid column +create table altinhoid () inherits (altwithoid) with oids; + +insert into altinhoid values (1); + +select oid > 0, * from altwithoid; -- fails +select oid > 0, * from altinhoid; + +alter table altwithoid set with oids; + +select oid > 0, * from altwithoid; +select oid > 0, * from altinhoid; + +-- the child's local definition should remain +alter table altwithoid set without oids; + +select oid > 0, * from altwithoid; -- fails +select oid > 0, * from altinhoid; + +drop table altwithoid cascade; + +-- test renumbering of child-table columns in inherited operations + +create table p1 (f1 int); +create table c1 (f2 text, f3 int) inherits (p1); + +alter table p1 add column a1 int check (a1 > 0); +alter table p1 add column f2 text; + +insert into p1 values (1,2,'abc'); +insert into c1 values(11,'xyz',33,0); -- should fail +insert into c1 values(11,'xyz',33,22); + +select * from p1 order by f1; +update p1 set a1 = a1 + 1, f2 = upper(f2); +select * from p1 order by f1; + +drop table p1 cascade; + +-- test that operations with a dropped column do not try to reference +-- its datatype + +--create domain mytype as text; +--create table foo (f1 text, f2 mytype, f3 text);; + +insert into foo values('bb','cc','dd'); +select * from foo order by f1; + +--drop domain mytype cascade; + +--select * from foo order by f1; +--insert into foo values('qq','rr'); +--select * from foo order by f1; +--update foo set f3 = 'zz'; +--select * from foo order by f1; +--select f3,max(f1) from foo group by f3; + +-- Simple tests for alter table column type +--delete from foo where f1 = 'qq'; +--alter table foo alter f1 TYPE integer; -- fails +--alter table foo alter f1 TYPE varchar(10); +--drop table foo; + +create table anothertab (atcol1 serial8, atcol2 boolean, + constraint anothertab_chk check (atcol1 <= 3));; +alter table anothertab replica identity full; +insert into anothertab (atcol1, atcol2) values (1, true); +insert into anothertab (atcol1, atcol2) values (3, false); +select * from anothertab order by atcol1, atcol2; + +alter table anothertab alter column atcol1 type boolean; -- we cannot support this cast with numeric nextval +alter table anothertab alter column atcol1 type integer; + +select * from anothertab order by atcol1, atcol2; + +insert into anothertab (atcol1, atcol2) values (45, null); -- fails +--insert into anothertab (atcol1, atcol2) values (default, null); + +select * from anothertab order by atcol1, atcol2; + +alter table anothertab alter column atcol2 type text + using case when atcol2 is true then 'IT WAS TRUE' + when atcol2 is false then 'IT WAS FALSE' + else 'IT WAS NULL!' end; + +select * from anothertab order by atcol1, atcol2; +alter table anothertab alter column atcol1 type boolean + using case when atcol1 % 2 = 0 then true else false end; -- fails +alter table anothertab alter column atcol1 drop default; +alter table anothertab alter column atcol1 type boolean + using case when atcol1 % 2 = 0 then true else false end; -- fails +alter table anothertab drop constraint anothertab_chk; +alter table anothertab drop constraint anothertab_chk; -- fails +alter table anothertab drop constraint IF EXISTS anothertab_chk; -- succeeds + +alter table anothertab alter column atcol1 type boolean + using case when atcol1 % 2 = 0 then true else false end; + +select * from anothertab order by atcol1, atcol2; + +-- drop table anothertab; + +create table another (f1 int, f2 text);; +alter table another replica identity full; +insert into another values(1, 'one'); +insert into another values(2, 'two'); +insert into another values(3, 'three'); + +select * from another order by f1, f2; + +alter table another + alter f1 type text using f2 || ' more', + alter f2 type bigint using f1 * 10; + +select * from another order by f1, f2; + +-- drop table another; + +-- table's row type +create table tab1 (a int, b text); +create table tab2 (x int, y tab1); +alter table tab1 alter column b type varchar; -- fails + +-- disallow recursive containment of row types +create table recur1 (f1 int); +alter table recur1 add column f2 recur1; -- fails +alter table recur1 add column f2 recur1[]; -- fails +--create domain array_of_recur1 as recur1[]; +--alter table recur1 add column f2 array_of_recur1; -- fails +create table recur2 (f1 int, f2 recur1); +alter table recur1 add column f2 recur2; -- fails +alter table recur1 add column f2 int; +alter table recur1 alter column f2 type recur2; -- fails + +-- SET STORAGE may need to add a TOAST table +create table test_storage (a text); +alter table test_storage alter a set storage plain; +alter table test_storage add b int default 0; -- rewrite table to remove its TOAST table +alter table test_storage alter a set storage extended; -- re-add TOAST table + +select reltoastrelid <> 0 as has_toast_table +from pg_class +where oid = 'test_storage'::regclass; + +-- ALTER TYPE with a check constraint and a child table (bug before Nov 2012) +CREATE TABLE test_inh_check (a float check (a > 10.2)); +CREATE TABLE test_inh_check_child() INHERITS(test_inh_check); +ALTER TABLE test_inh_check ALTER COLUMN a TYPE numeric; +\d test_inh_check +\d test_inh_check_child + +-- +-- lock levels +-- +drop type lockmodes; +create type lockmodes as enum ( + 'AccessShareLock' +,'RowShareLock' +,'RowExclusiveLock' +,'ShareUpdateExclusiveLock' +,'ShareLock' +,'ShareRowExclusiveLock' +,'ExclusiveLock' +,'AccessExclusiveLock' +); + +drop view my_locks; +create or replace view my_locks as +select case when c.relname like 'pg_toast%' then 'pg_toast' else c.relname end, max(mode::lockmodes) as max_lockmode +from pg_locks l join pg_class c on l.relation = c.oid +where virtualtransaction = ( + select virtualtransaction + from pg_locks + where transactionid = txid_current()::integer) +and locktype = 'relation' +and relnamespace != (select oid from pg_namespace where nspname = 'pg_catalog') +and c.relname != 'my_locks' +group by c.relname; + +create table alterlock (f1 int primary key, f2 text); + +start transaction; alter table alterlock alter column f2 set statistics 150; +select * from my_locks order by 1; +rollback; + +start transaction; alter table alterlock cluster on alterlock_pkey; +select * from my_locks order by 1; +commit; + +start transaction; alter table alterlock set without cluster; +select * from my_locks order by 1; +commit; + +start transaction; alter table alterlock set (fillfactor = 100); +select * from my_locks order by 1; +commit; + +start transaction; alter table alterlock reset (fillfactor); +select * from my_locks order by 1; +commit; + +start transaction; alter table alterlock set (toast.autovacuum_enabled = off); +select * from my_locks order by 1; +commit; + +start transaction; alter table alterlock set (autovacuum_enabled = off); +select * from my_locks order by 1; +commit; + +start transaction; alter table alterlock alter column f2 set (n_distinct = 1); +select * from my_locks order by 1; +rollback; + +start transaction; alter table alterlock alter column f2 set storage extended; +select * from my_locks order by 1; +rollback; + +start transaction; alter table alterlock alter column f2 set default 'x'; +select * from my_locks order by 1; +rollback; + +-- cleanup +drop table alterlock; +drop view my_locks; +drop type lockmodes; + +-- +-- alter function +-- +-- create function test_strict(text) returns text as +-- 'select coalesce($1, ''got passed a null'');' +-- language sql returns null on null input; +-- select test_strict(NULL); +-- alter function test_strict(text) called on null input; +-- select test_strict(NULL); + +-- create function non_strict(text) returns text as +-- 'select coalesce($1, ''got passed a null'');' +-- language sql called on null input; +-- select non_strict(NULL); +-- alter function non_strict(text) returns null on null input; +-- select non_strict(NULL); + +-- +-- alter object set schema +-- + +create schema alter1; +create schema alter2; + +create table alter1.t1(f1 serial primary key, f2 int check (f2 > 0)); + +create view alter1.v1 as select * from alter1.t1; + +create function alter1.plus1(int) returns int as 'select $1+1' language sql; + +--create domain alter1.posint integer check (value > 0); + +create type alter1.ctype as (f1 int, f2 text); + +create function alter1.same(alter1.ctype, alter1.ctype) returns boolean language sql +as 'select $1.f1 is not distinct from $2.f1 and $1.f2 is not distinct from $2.f2'; + +create operator alter1.=(procedure = alter1.same, leftarg = alter1.ctype, rightarg = alter1.ctype); + +create operator class alter1.ctype_hash_ops default for type alter1.ctype using hash as + operator 1 alter1.=(alter1.ctype, alter1.ctype); + +create conversion alter1.ascii_to_utf8 for 'sql_ascii' to 'utf8' from ascii_to_utf8; + +create text search parser alter1.prs(start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype); +create text search configuration alter1.cfg(parser = alter1.prs); +create text search template alter1.tmpl(init = dsimple_init, lexize = dsimple_lexize); +create text search dictionary alter1.dict(template = alter1.tmpl); + +insert into alter1.t1(f2) values(11); +insert into alter1.t1(f2) values(12); + +alter table alter1.t1 set schema alter2; +alter table alter1.v1 set schema alter2; +alter function alter1.plus1(int) set schema alter2; +--alter domain alter1.posint set schema alter2; +alter operator class alter1.ctype_hash_ops using hash set schema alter2; +alter operator family alter1.ctype_hash_ops using hash set schema alter2; +alter operator alter1.=(alter1.ctype, alter1.ctype) set schema alter2; +alter function alter1.same(alter1.ctype, alter1.ctype) set schema alter2; +alter type alter1.ctype set schema alter2; +alter conversion alter1.ascii_to_utf8 set schema alter2; +alter text search parser alter1.prs set schema alter2; +alter text search configuration alter1.cfg set schema alter2; +alter text search template alter1.tmpl set schema alter2; +alter text search dictionary alter1.dict set schema alter2; + +-- this should succeed because nothing is left in alter1 +drop schema alter1; + +insert into alter2.t1(f2) values(13); +insert into alter2.t1(f2) values(14); + +select * from alter2.t1 order by f1, f2; + +select * from alter2.v1 order by f1, f2; + +select alter2.plus1(41); + +-- clean up +drop schema alter2 cascade; +drop schema alter1 cascade; + +-- +-- composite types +-- + +CREATE TYPE test_type AS (a int); +\d test_type + +ALTER TYPE nosuchtype ADD ATTRIBUTE b text; -- fails + +ALTER TYPE test_type ADD ATTRIBUTE b text; +\d test_type + +ALTER TYPE test_type ADD ATTRIBUTE b text; -- fails + +ALTER TYPE test_type ALTER ATTRIBUTE b SET DATA TYPE varchar; +\d test_type + +ALTER TYPE test_type ALTER ATTRIBUTE b SET DATA TYPE integer; +\d test_type + +ALTER TYPE test_type DROP ATTRIBUTE b; +\d test_type + +ALTER TYPE test_type DROP ATTRIBUTE c; -- fails + +ALTER TYPE test_type DROP ATTRIBUTE IF EXISTS c; + +ALTER TYPE test_type DROP ATTRIBUTE a, ADD ATTRIBUTE d boolean; +\d test_type + +ALTER TYPE test_type RENAME ATTRIBUTE a TO aa; +ALTER TYPE test_type RENAME ATTRIBUTE d TO dd; +\d test_type + +DROP TYPE test_type; + +CREATE TYPE test_type1 AS (a int, b text); +CREATE TABLE test_tbl1 (x int, y test_type1); +ALTER TYPE test_type1 ALTER ATTRIBUTE b TYPE varchar; -- fails + +CREATE TYPE test_type2 AS (a int, b text); +CREATE TABLE test_tbl2 OF test_type2; +CREATE TABLE test_tbl2_subclass () INHERITS (test_tbl2); +\d test_type2 +\d test_tbl2 + +ALTER TYPE test_type2 ADD ATTRIBUTE c text; -- fails +ALTER TYPE test_type2 ADD ATTRIBUTE c text CASCADE; +\d test_type2 +\d test_tbl2 + +ALTER TYPE test_type2 ALTER ATTRIBUTE b TYPE varchar; -- fails +ALTER TYPE test_type2 ALTER ATTRIBUTE b TYPE varchar CASCADE; +\d test_type2 +\d test_tbl2 + +ALTER TYPE test_type2 DROP ATTRIBUTE b; -- fails +ALTER TYPE test_type2 DROP ATTRIBUTE b CASCADE; +\d test_type2 +\d test_tbl2 + +ALTER TYPE test_type2 RENAME ATTRIBUTE a TO aa; -- fails +ALTER TYPE test_type2 RENAME ATTRIBUTE a TO aa CASCADE; +\d test_type2 +\d test_tbl2 +\d test_tbl2_subclass + +DROP TABLE test_tbl2_subclass; +alter table test_tbl2 not of; +-- This test isn't that interesting on its own, but the purpose is to leave +-- behind a table to test pg_upgrade with. The table has a composite type +-- column in it, and the composite type has a dropped attribute. +CREATE TYPE test_type3 AS (a int); +CREATE TABLE test_tbl3 (c) AS SELECT '(1)'::test_type3; +ALTER TYPE test_type3 DROP ATTRIBUTE a, ADD ATTRIBUTE b int; + +CREATE TYPE test_type_empty AS (); + +-- +-- typed tables: OF / NOT OF +-- + +CREATE TYPE tt_t0 AS (z inet, x int, y numeric(8,2)); +ALTER TYPE tt_t0 DROP ATTRIBUTE z; +CREATE TABLE tt0 (x int NOT NULL, y numeric(8,2)); -- OK +CREATE TABLE tt1 (x int, y bigint); -- wrong base type +CREATE TABLE tt2 (x int, y numeric(9,2)); -- wrong typmod +CREATE TABLE tt3 (y numeric(8,2), x int); -- wrong column order +CREATE TABLE tt4 (x int); -- too few columns +CREATE TABLE tt5 (x int, y numeric(8,2), z int); -- too few columns +CREATE TABLE tt6 () INHERITS (tt0); -- can't have a parent +CREATE TABLE tt7 (x int, q text, y numeric(8,2)) WITH OIDS; +ALTER TABLE tt7 DROP q; -- OK + +ALTER TABLE tt0 OF tt_t0; +ALTER TABLE tt1 OF tt_t0; +ALTER TABLE tt2 OF tt_t0; +ALTER TABLE tt3 OF tt_t0; +ALTER TABLE tt4 OF tt_t0; +ALTER TABLE tt5 OF tt_t0; +ALTER TABLE tt6 OF tt_t0; +ALTER TABLE tt7 OF tt_t0; + +CREATE TYPE tt_t1 AS (x int, y numeric(8,2)); +ALTER TABLE tt7 OF tt_t1; -- reassign an already-typed table +ALTER TABLE tt7 NOT OF; +\d tt7 +alter table tt0 not of; +-- make sure we can drop a constraint on the parent but it remains on the child +CREATE TABLE test_drop_constr_parent (c text CHECK (c IS NOT NULL)); +CREATE TABLE test_drop_constr_child () INHERITS (test_drop_constr_parent); +ALTER TABLE ONLY test_drop_constr_parent DROP CONSTRAINT "test_drop_constr_parent_c_check"; +-- should fail +INSERT INTO test_drop_constr_child (c) VALUES (NULL); +DROP TABLE test_drop_constr_parent CASCADE; + +-- +-- IF EXISTS test +-- +ALTER TABLE IF EXISTS tt8 ADD COLUMN f int; +ALTER TABLE IF EXISTS tt8 ADD CONSTRAINT xxx PRIMARY KEY(f); +ALTER TABLE IF EXISTS tt8 ADD CHECK (f BETWEEN 0 AND 10); +ALTER TABLE IF EXISTS tt8 ALTER COLUMN f SET DEFAULT 0; +ALTER TABLE IF EXISTS tt8 RENAME COLUMN f TO f1; +ALTER TABLE IF EXISTS tt8 SET SCHEMA alter2; + +CREATE TABLE tt8(a int); +CREATE SCHEMA alter2; + +ALTER TABLE IF EXISTS tt8 ADD COLUMN f int; +ALTER TABLE IF EXISTS tt8 ADD CONSTRAINT xxx PRIMARY KEY(f); +ALTER TABLE IF EXISTS tt8 ADD CHECK (f BETWEEN 0 AND 10); +ALTER TABLE IF EXISTS tt8 ALTER COLUMN f SET DEFAULT 0; +ALTER TABLE IF EXISTS tt8 RENAME COLUMN f TO f1; +ALTER TABLE IF EXISTS tt8 SET SCHEMA alter2; + +\d alter2.tt8 + +DROP TABLE alter2.tt8; +DROP SCHEMA alter2; + +-- create database test_first_after_A dbcompatibility 'A'; +-- \c test_first_after_A + +-- test add column ... first | after columnname +-- common scenatios +drop table if exists t1 cascade; +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 add f6 clob first, add f7 blob after f2; +alter table t1 add f8 int, add f9 text first, add f10 float after f3; +\d+ t1 +select * from t1; + +-- 1 primary key +drop table if exists t1 cascade; +create table t1(f1 int primary key, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 add f6 blob first, add f7 clob after f2; +alter table t1 add f8 int, add f9 text first, add f10 float after f3; +select * from t1; +------------------------------------------------------------------------------------------- +drop table if exists t1 cascade; +create table t1(f1 int primary key, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 drop f1, add f6 text, add f7 int primary key first, add f8 float after f3; +\d+ t1; + +-- 2 unique index +drop table if exists t1 cascade; +create table t1(f1 int unique, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 drop f1, add f6 int unique first, add f7 float unique after f3; +select * from t1; + +-- 3 default and generated column +drop table if exists t1 cascade; +create table t1(f1 int default 1, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 drop f1, add f6 int default 1 first, add f7 float default 7 after f3; +select * from t1; + +drop table if exists t1 cascade; +create table t1(f1 int, f2 int default 2, f3 int default 3, f4 int generated always as (f1 + f2) stored); +insert into t1 values(1, 2, 3), (11, 22, 33); +alter table t1 add f5 int generated always as (f2 + f3) stored first, add f6 int generated always as (f1 + f3) stored after f5; +select * from t1; + +-- 5 NULL and NOT NULL +drop table if exists t1 cascade; +create table t1(f1 int null, f2 varchar(20) not null, f3 timestamp, f4 bit(8), f5 bool); +alter table t1 drop f1, drop f2, add f6 int null first, add f7 float not null after f3; +\d+ t1 + +-- 6 check constraint +drop table if exists t1 cascade; +create table t1(f1 int check(f1 = 1), f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (1, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 drop f2, add f6 text check (f1 > 0) first, add f7 int check(f7 - f1 > 0) after f3; +select * from t1; + +-- 7 foreign key +drop table if exists t1 cascade; +drop table if exists t_pri1 cascade; +drop table if exists t_pri2 cascade; +create table t_pri1(f1 text, f2 int primary key); +insert into t_pri1 values('a', 1), ('b', 2); +create table t_pri2(f1 text, f2 bool, f4 int primary key); +insert into t_pri2 values('a', true, 1), ('b', false, 2); +create table t1(f1 int, f2 int references t_pri1(f2), f3 bool); +insert into t1 values(1, 2, true), (2, 2, false); +alter table t1 drop f2, add f4 int references t_pri2(f4) first; +select * from t1; +alter table t1 drop f4, add f4 int references t_pri2(f4) after f1; +select * from t1; + +-- partition table +drop table if exists t1 cascade; +create table t1 +(f1 int, f2 int, f3 int) +partition by range(f1, f2) +( + partition t1_p0 values less than (10, 0), + partition t1_p1 values less than (20, 0), + partition t1_p2 values less than (30, 0) +); +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='t1') order by relname; + +alter table t1 add f4 int first, add f5 int after f1; +\d+ t1 +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='t1') order by relname; + +-- subpartition table +drop table if exists range_range cascade; +create table range_range(id int, gender varchar not null, birthday date not null) +partition by range (id) subpartition by range (birthday) +( + partition p_1 values less than(100) + ( + subpartition p_1_a values less than('2022-01-01'), + subpartition p_1_b values less than(MAXVALUE) + ), + partition p_2 values less than(200) + ( + subpartition p_2_a values less than('2022-01-01'), + subpartition p_2_b values less than(MAXVALUE) + ), + partition p_3 values less than(MAXVALUE) + ( + subpartition p_3_a values less than('2022-01-01'), + subpartition p_3_b values less than(MAXVALUE) + ) +); +insert into range_range values(198,'boy','2010-02-15'),(33,'boy','2003-08-11'),(78,'girl','2014-06-24'); +insert into range_range values(233,'girl','2010-01-01'),(360,'boy','2007-05-14'),(146,'girl','2005-03-08'); +insert into range_range values(111,'girl','2013-11-19'),(15,'girl','2009-01-12'),(156,'boy','2011-05-21'); + +-- test pg_partition +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='range_range') order by relname; +alter table range_range add f1 int default 1 first, add f2 text after id; +\d+ range_range +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='range_range') order by relname; +select * from range_range; + +-- pg_index test +drop table if exists t1 cascade; +create table t1 +( + f1 int, f2 int, f3 varchar(20), f4 int, f5 int, f6 int, f7 int, + primary key(f1, f2), + unique(f3, f4), + check(f5 = 10) +); +create unique index partial_t1_idx on t1(f5, abs(f6)) where f5 + f6 - abs(f7) > 0; + +select indkey, indexprs, indpred from pg_index where indrelid = (select oid from pg_class where relname = 't1') order by 1, 2, 3; + +alter table t1 add f8 int first, add f9 int unique after f1; +\d+ t1 +select indkey, indexprs, indpred from pg_index where indrelid = (select oid from pg_class where relname = 't1') order by 1, 2, 3; + +-- pg_attribute test +drop table if exists t1 cascade; +create table t1(f1 int, f2 int, f3 int); +select attname, attnum, atthasdef, attisdropped from pg_attribute where attrelid = (select oid from pg_class where relname = 't1') and attnum > 0 order by attnum; + +alter table t1 add f4 int default 4 first; +\d+ t1 +select attname, attnum, atthasdef, attisdropped from pg_attribute where attrelid = (select oid from pg_class where relname = 't1') and attnum > 0 order by attnum; + +alter table t1 drop f2, add f5 int default 5 after f1; +\d+ t1 +select attname, attnum, atthasdef, attisdropped from pg_attribute where attrelid = (select oid from pg_class where relname = 't1') and attnum > 0 order by attnum; + +-- pg_attrdef test +drop table if exists t1 cascade; +create table t1(f1 int primary key, f2 int, f3 int default 3, f4 int generated always as (f2 + f3) stored); +select adnum, adsrc, adgencol from pg_attrdef where adrelid = (select oid from pg_class where relname = 't1') order by adnum; + +alter table t1 add f5 text default 'aaa' first; +\d+ t1 +select adnum, adsrc, adgencol from pg_attrdef where adrelid = (select oid from pg_class where relname = 't1') order by adnum; + +alter table t1 drop f2, add f6 int generated always as (f1 + abs(f3)) stored after f1; +\d+ t1 +select adnum, adsrc, adgencol from pg_attrdef where adrelid = (select oid from pg_class where relname = 't1') order by adnum; + +-- pg_depend test +drop table if exists t1 cascade; +create table t1(f1 int default 10, f2 int primary key, f3 int generated always as (f1 + f2) stored); +select classid, objsubid, refclassid, refobjsubid, deptype from pg_depend + where refobjid = (select oid from pg_class where relname='t1') or objid = (select oid from pg_class where relname='t1') order by 1, 2, 3, 4, 5; + +alter table t1 add t1 add f4 int first; +\d+ t1 +select classid, objsubid, refclassid, refobjsubid, deptype from pg_depend + where refobjid = (select oid from pg_class where relname='t1') or objid = (select oid from pg_class where relname='t1') order by 1, 2, 3, 4, 5; +alter table t1 drop f2, add f6 int, add f7 int generated always as (f1 + f6) stored after f1; +\d+ t1 +select classid, objsubid, refclassid, refobjsubid, deptype from pg_depend + where refobjid = (select oid from pg_class where relname='t1') or objid = (select oid from pg_class where relname='t1') order by 1, 2, 3, 4, 5; + +-- pg_rewrite test +drop table if exists t1 cascade; +create table t1(f1 int, f2 int, f3 int); +insert into t1 values(1, 2, 3), (11, 22, 33); +create view t1_view1 as select * from t1; +create view t1_view2 as select f1, f2 from t1; +\d+ t1_view1 +\d+ t1_view2 +\d+ t1 +select pg_get_viewdef('t1_view1'); +select pg_get_viewdef('t1_view2'); +select * from t1_view1; +select * from t1_view2; +select * from t1; +alter table t1 add f4 int first, add f5 int after f1; +\d+ t1_view1 +\d+ t1_view2 +\d+ t1 +select pg_get_viewdef('t1_view1'); +select pg_get_viewdef('t1_view2'); +select * from t1_view1; +select * from t1_view2; +select * from t1; + +-- pg_trigger test +drop table if exists t1 cascade; +create table t1(f1 boolean not null, f2 text, f3 int, f4 date); +alter table t1 add primary key(f1); +create or replace function dummy_update_func() returns trigger as $$ +begin + raise notice 'dummy_update_func(%) called: action = %, oid = %, new = %', TG_ARGV[0], TG_OP, OLD, NEW; + return new; +end; +$$ language plpgsql; + +drop trigger if exists f1_trig_update on t1; +drop trigger if exists f1_trig_insert on t1; + +create trigger f1_trig_update after update of f1 on t1 for each row + when (not old.f1 and new.f1) execute procedure dummy_update_func('update'); +create trigger f1_trig_insert after insert on t1 for each row + when (not new.f1) execute procedure dummy_update_func('insert'); + +select tgname, tgattr, tgqual from pg_trigger where tgrelid = (select oid from pg_class where relname='t1') order by tgname; + +alter table t1 add f5 int after f1, add f6 boolean first; +\d+ t1 +select tgname, tgattr, tgqual from pg_trigger where tgrelid = (select oid from pg_class where relname='t1') order by tgname; + +-- pg_rlspolicy test +drop table if exists t1 cascade; +drop role if exists test_rlspolicy; +create role test_rlspolicy nologin password 'Gauss_234'; +create table t1 (f1 int, f2 int, f3 text) partition by range (f1) +( + partition t1_p0 values less than(10), + partition t1_p1 values less than(50), + partition t1_p2 values less than(100), + partition t1_p3 values less than(MAXVALUE) +); + +INSERT INTO t1 VALUES (generate_series(1, 150) % 24, generate_series(1, 150), 'huawei'); +grant select on t1 to public; + +create row level security policy t1_rls1 on t1 as permissive to public using (f2 <= 20); +create row level security policy t1_rls2 on t1 as restrictive to test_rlspolicy using (f1 < 30); + +\d+ t1 +select * from t1 limit 10; +select polname, polqual from pg_rlspolicy where polrelid = (select oid from pg_class where relname='t1'); + +alter table t1 add f4 int generated always as (f1 + 100) stored after f1, add f5 int generated always as (f2 + 100) stored first; +\d+ t1 +select * from t1 limit 10; +select polname, polqual from pg_rlspolicy where polrelid = (select oid from pg_class where relname='t1'); +drop table if exists t1 cascade; + +-- \c postgres +-- drop database test_first_after_A; + +-- test add column ... first | after columnname in B compatibility +-- create database test_first_after_B dbcompatibility 'b'; +-- \c test_first_after_B + +-- test add column ... first | after columnname in astore table +-- ASTORE table +-- common scenatios +drop table if exists t1 cascade; +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 add f6 clob first, add f7 blob after f2; +alter table t1 add f8 int, add f9 text first, add f10 float after f3; +\d+ t1 +select * from t1; + +-- 1 primary key +-- 1.1.1 primary key in original table without data, add column without constraints +drop table if exists t1 cascade; +create table t1(f1 int primary key, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 add f6 clob first, add f7 blob after f2; +alter table t1 add f8 int, add f9 text first, add f10 float after f3; +\d+ t1 + +-- 1.1.2 primary key in original table with data, add column without constraints +drop table if exists t1 cascade; +create table t1(f1 int primary key, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 add f6 blob first, add f7 clob after f2; +alter table t1 add f8 int, add f9 text first, add f10 float after f3; +select * from t1; + +-- 1.2.1 primary key in a table without data, add column with primary key +drop table if exists t1 cascade; +create table t1(f1 int primary key, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +-- error +alter table t1 add f6 text, add f7 int primary key first, add f8 float after f3; +select * from t1; + +-- 1.2.2 primary key in a table with data, add column with primary key +drop table if exists t1 cascade; +create table t1(f1 int primary key, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +-- error +alter table t1 add f6 text, add f7 int primary key first, add f8 float after f3; +select * from t1; + +-- 1.3.1 primary key in a table without data, drop primary key, then add column with primary key +drop table if exists t1 cascade; +create table t1(f1 int primary key, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 drop f1, add f6 text, add f7 int primary key first, add f8 float after f3; +\d+ t1; + +-- 1.3.2 primary key in a table with data, drop primary key, then add column with primary key +drop table if exists t1 cascade; +create table t1(f1 int primary key, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 drop f1; +-- error +alter table t1 add f6 text, add f7 int primary key first, add f8 float after f3; +select * from t1; + +-- 1.4.1 primary key in a table without data, drop primary key, the add column with primary key and default +drop table if exists t1 cascade; +create table t1(f1 int primary key, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 drop f1, add f6 text, add f7 int primary key default 7 first, add f8 float after f3; +\d+ t1 + +-- 1.4.2 primary key in a table with data, drop primary key, then add column with primary key and default +drop table if exists t1 cascade; +create table t1(f1 int primary key, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 drop f1; +-- error +alter table t1 add f6 text, add f7 int primary key default 7 first, add f8 float after f3; +select * from t1; + +-- 1.5.1 primary key in a table without data, drop primary key, the add column with primary key and auto_increment +drop table if exists t1 cascade; +create table t1(f1 int primary key, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 drop f1, add f6 text, add f7 int primary key auto_increment first, add f8 float after f3; +\d+ t1 + +-- 1.5.2 primary key in a table with data, drop primary key, the add column with primary key and auto_increment +drop table if exists t1 cascade; +create table t1(f1 int primary key, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 drop f1, add f6 text, add f7 int primary key auto_increment first, add f8 float after f3; +select * from t1; + +-- 2 unique index +-- 2.1.1 unique index in a table without data, add column without constraints +drop table if exists t1 cascade; +create table t1(f1 int unique, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 add f6 int first, add f7 float after f3; +\d+ t1 + +-- 2.1.2 unique index in a table with data, add column without constraints +drop table if exists t1 cascade; +create table t1(f1 int unique, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 add f6 int first, add f7 float after f3; +select * from t1; + +-- 2.2.1 unique index in a table without data, add column with unique index +drop table if exists t1 cascade; +create table t1(f1 int unique, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 add f6 int unique first, add f7 float unique after f3; +\d+ t1 + +-- 2.2.2 unique index in a table with data, add column with unique index +drop table if exists t1 cascade; +create table t1(f1 int unique, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 add f6 int unique first, add f7 float unique after f3; +select * from t1; + +-- 2.3.1 unique index in a table without data, drop unique index, add column with unique index +drop table if exists t1 cascade; +create table t1(f1 int unique, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 drop f1, add f6 int unique first, add f7 float unique after f3; +\d+ t1 + +-- 2.3.2 unique index in a table with data, drop unique index, add column with unique index +drop table if exists t1 cascade; +create table t1(f1 int unique, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 drop f1, add f6 int unique first, add f7 float unique after f3; +select * from t1; + +-- 2.4.1 unique index in a table without data, drop unique index, add column with unique index and default +drop table if exists t1 cascade; +create table t1(f1 int unique, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 add f6 int unique default 6 first; +alter table t1 drop f1, add f7 float unique default 7 after f3; +\d+ t1 + +-- 2.4.2 unique index in a table with data, drop unique index, add column with unique index and default +drop table if exists t1 cascade; +create table t1(f1 int unique, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +-- error +alter table t1 add f6 int unique default 6 first; +alter table t1 drop f1; +-- error +alter table t1 add f7 float unique default 7 after f3; +select * from t1; + +-- 3 default and generated column +-- 3.1.1 default in a table without data, add column without constraints +drop table if exists t1 cascade; +create table t1(f1 int default 1, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 add f6 int first, add f7 float after f3; +\d+ t1 + +-- 3.1.2 default in a table with data, add column without constraints +drop table if exists t1 cascade; +create table t1(f1 int default 1, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 add f6 int first, add f7 float after f3; +select * from t1; + +-- 3.2.1 default in a table without data, add column with default +drop table if exists t1 cascade; +create table t1(f1 int default 1, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 add f6 int default 6 first, add f7 float default 7 after f3; +\d+ t1 + +-- 3.2.2 default in a table with data, add column with default +drop table if exists t1 cascade; +create table t1(f1 int default 1, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 add f6 int default 6 first, add f7 float default 7 after f3; +select * from t1; + +-- 3.3.1 default in a table without data, drop default, add column with default +drop table if exists t1 cascade; +create table t1(f1 int default 1, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 drop f1, add f6 int default 6 first, add f7 float default 7 after f3; +\d+ t1 + +-- 3.3.2 default in a table with data, drop default, add column with default +drop table if exists t1 cascade; +create table t1(f1 int default 1, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 drop f1, add f6 int default 1 first, add f7 float default 7 after f3; +select * from t1; + +-- 3.4.1 generated column in a table without data, drop generated column +drop table if exists t1 cascade; +create table t1(f1 int, f2 int default 2, f3 int default 3, f4 int generated always as (f1 + f2) stored); +alter table t1 drop f1, add f5 int generated always as (f2 + f3) stored first, add f6 int generated always as (f3*10) stored after f5; +\d+ t1 + +-- 3.4.1 generated column in a table with data, drop generated column +drop table if exists t1 cascade; +create table t1(f1 int, f2 int default 2, f3 int default 3, f4 int generated always as (f1 + f2) stored); +insert into t1 values(1, 2, 3), (11, 22, 33); +alter table t1 drop f1, add f5 int generated always as (f2 + f3) stored first, add f6 int generated always as (f3*10) stored after f5; +select * from t1; + +-- 3.5.1 generated column in a table without data, add generated column +drop table if exists t1 cascade; +create table t1(f1 int, f2 int default 2, f3 int default 3, f4 int generated always as (f1 + f2) stored); +alter table t1 add f5 int generated always as (f2 + f3) stored first, add f6 int generated always as (f2 + f3) stored after f5; +\d+ t1; + +-- 3.5.2 generated column in table with data, add generated column +drop table if exists t1 cascade; +create table t1(f1 int, f2 int default 2, f3 int default 3, f4 int generated always as (f1 + f2) stored); +insert into t1 values(1, 2, 3), (11, 22, 33); +alter table t1 add f5 int generated always as (f2 + f3) stored first, add f6 int generated always as (f1 + f3) stored after f5; +select * from t1; + +-- 4 auto_increment +-- 4.1.1 auto_increment in a table without data, add column without constraints +drop table if exists t1 cascade; +create table t1(f1 int primary key auto_increment, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 add f6 text first, add f7 float after f3; +\d+ t1 + +-- 4.1.2 auto_increment in a table with data, add column without constraints +drop table if exists t1 cascade; +create table t1(f1 int primary key auto_increment, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 add f6 text first, add f7 float after f3; +select * from t1; + +-- 4.2.1 auto_increment in a table without data, add column with auto_increment +drop table if exists t1 cascade; +create table t1(f1 int primary key auto_increment, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +-- error +alter table t1 add f6 int primary key auto_increment first; +-- error +alter table t1 add f7 int primary key auto_increment after f3; +\d+ t1 + +-- 4.2.2 auto_increment in a table with data, add column with auto_increment +drop table if exists t1 cascade; +create table t1(f1 int primary key auto_increment, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +-- error +alter table t1 add f6 int primary key auto_increment first; +-- error +alter table t1 add f7 int primary key auto_increment after f3; +select * from t1; + +-- 4.3.1 auto_increment in a table without data, drop auto_increment, add column with auto_increment +drop table if exists t1 cascade; +create table t1(f1 int primary key auto_increment, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 drop f1, add f6 int primary key auto_increment first; +\d+ t1 + +-- 4.3.2 auto_increment in a table with data, drop auto_increment, add column with auto_increment +drop table if exists t1 cascade; +create table t1(f1 int primary key auto_increment, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 drop f1, add f6 int primary key auto_increment first; + +-- 4.4.1 auto_increment in a table without data, drop auto_increment, add column with auto_increment and default +drop table if exists t1 cascade; +create table t1(f1 int primary key auto_increment, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 drop f1; +-- error +alter table t1 add f6 int primary key auto_increment default 6 first; +\d+ t1 + +-- 4.4.2 auto_increment in a table with data, drop auto_increment, add column with auto_increment and default +drop table if exists t1 cascade; +create table t1(f1 int primary key auto_increment, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 drop f1; +-- error +alter table t1 add f6 int primary key auto_increment default 6 first; +select * from t1; + +-- 5 NULL and NOT NULL +-- 5.1.1 null and not null in a table without data, add column without constraints +drop table if exists t1 cascade; +alter table t1(f1 int null, f2 varchar(20) not null, f3 timestamp, f4 bit(8), f5 bool); +alter table t1 add f6 text first, add f7 float after f3; +\d+ t1 + +-- 5.1.2 null and not null in a table with data, add column without constraints +drop table if exists t1 cascade; +alter table t1(f1 int null, f2 varchar(20) not null, f3 timestamp, f4 bit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 add f6 text first, add f7 float after f3; +select * from t1; + +-- 5.2.1 null and not null in table without data, add column with null or not null +drop table if exists t1 cascade; +alter table t1(f1 int null, f2 varchar(20) not null, f3 timestamp, f4 bit(8), f5 bool); +alter table t1 add f6 int null first; +alter table t1 add f7 float not null after f3; +\d+ t1 + +-- 5.2.2 null and not null in a table with data, add column with null or not null +drop table if exists t1 cascade; +create table t1(f1 int null, f2 varchar(20) not null, f3 timestamp, f4 bit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 add f6 int null first; +-- error +alter table t1 add f7 float not null after f3; +select * from t1; + +-- 5.3.1 null and not null in a table without data, drop null, add column with null or not null +drop table if exists t1 cascade; +create table t1(f1 int null, f2 varchar(20) not null, f3 timestamp, f4 bit(8), f5 bool); +alter table t1 drop f1, add f6 int null first, add f7 float not null after f3; +\d+ t1 + +-- 5.3.2 null and not null in a table with data, drop null, add column with null or not null +drop table if exists t1 cascade; +create table t1(f1 int null, f2 varchar(20) not null, f3 timestamp, f4 bit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 drop f1, add f6 int null first; +-- error +alter table t1 add f7 float not null after f3; +select * from t1; + +-- 5.4.1 null and not null in a table without data, drop null and not null, add column with null or not null +drop table if exists t1 cascade; +create table t1(f1 int null, f2 varchar(20) not null, f3 timestamp, f4 bit(8), f5 bool); +alter table t1 drop f1, drop f2, add f6 int null first, add f7 float not null after f3; +\d+ t1 + +-- 5.4.2 null and not null in a table without data, drop null and not null, add column with null or not null +drop table if exists t1 cascade; +create table t1(f1 int null, f2 varchar(20) not null, f3 timestamp, f4 bit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 drop f1, drop f2, add f6 int null first; +-- error +alter table t1 add f7 float not null after f3; +select * from t1; + +-- 6 check constraint +-- 6.1.1 check constraint in a table without data, add column without constraint +drop table if exists t1 cascade; +create table t1(f1 int check(f1 = 1), f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 add f6 text first, add f7 float after f3; +\d+ t1 + +-- 6.1.2 check constraint in a table with data, add column without constraint +drop table if exists t1 cascade; +create table t1(f1 int check(f1 = 1), f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 add f6 text first, add f7 float after f3; +select * from t1; + +-- 6.2.1 check constraint in a table without data, add column with check +drop table if exists t1 cascade; +create table t1(f1 int check(f1 = 1), f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 add f6 int default 6, add f7 text check(f6 = 6) first, add f8 float check(f1 + f2 == 7); +\d+ t1 + +-- 6.2.2 check constraint in a table with data, add column with check +drop table if exists t1 cascade; +create table t1(f1 int check(f1 = 1), f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (1, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 add f6 int default 6, add f7 text check(f6 = 6) first, add f8 float check(f1 + f2 == 7) after f3; +select * from t1; + +-- 6.3.1 check constraint in a table without data, drop check, add column with check +drop table if exists t1 cascade; +create table t1(f1 int check(f1 = 1), f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 drop f2, add f6 text check (f1 > 0) first, add f7 int check (f7 - f1 > 0) after f3; +\d+ t1 + +-- 6.3.2 check constraint in a table with data, drop check, add column with with check +drop table if exists t1 cascade; +create table t1(f1 int check(f1 = 1), f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (1, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 drop f2, add f6 text check (f1 > 0) first, add f7 int check(f7 - f1 > 0) after f3; +select * from t1; + +-- 7 foreign key +-- 7.1.1 foreign key constraint in a table without data, add column without constraint +drop table if exists t_pri1 cascade; +create table t_pri1(f1 int, f2 int primary key); +drop table if exists t1 cascade; +create table t1(f1 int, f2 int references t_pri1(f2), f3 bool); +alter table t1 add f4 int, add f5 text first, f6 float after f2; +\d+ t1 + +-- 7.1.2 foreign key constraint in a table with data, add column without constraint +drop table if exists t1 cascade; +drop table if exists t_pri1 cascade; +create table t_pri1(f1 text, f2 int primary key); +insert into t_pri1 values('a', 1), ('b', 2); +create table t1(f1 text, f2 int references t_pri1(f2), f3 bool); +insert into t1 values('a', 1, true), ('b', 2, false); +alter table t1 add f4 int, add f5 text first, f6 float after f2; +select * from t1; + +-- 7.2.1 foreign key constraint in a table without data, add column with foreign key +drop table if exists t1 cascade; +drop table if exists t_pri1 cascade; +drop table if exists t_pri2 cascade; +create table t_pri1(f1 text, f2 int primary key); +create table t_pri2(f1 int, f2 int, f4 int primary key); +create table t1(f1 int, f2 int references t_pri1(f2), f3 bool); +alter table t1 add f4 int references t_pri2(f4) first; +\d+ t1 +alter table t1 drop f4, add f4 int references t_pri2(f4) after f2; +\d+ t1 + +-- 7.2.2 foreign key constraint in a table with data, add column with foreign key +drop table if exists t1 cascade; +drop table if exists t_pri1 cascade; +drop table if exists t_pri2 cascade; +create table t_pri1(f1 text, f2 int primary key); +insert into t_pri1 values('a', 1), ('b', 2); +create table t_pri2(f1 int, f2 bool, f4 int primary key); +insert into t_pri2 values(11, true, 1), (22, false, 2); +create table t1(f1 int, f2 int references t_pri1(f2), f3 bool); +insert into t1 values(1, 1, true), (2, 2, false); +alter table t1 add f4 int references t_pri2(f4) first; +select * from t1; +alter table t1 drop f4, add f4 int references t_pri2(f4) after f2; +select * from t1; + +-- 7.3.1 foreign key constraint in a table without data, drop foreign key, add column with foreign key +drop table if exists t1 cascade; +drop table if exists t_pri1 cascade; +drop table if exists t_pri2 cascade; +create table t_pri1(f1 int, f2 int primary key); +create table t_pri2(f1 int, f2 int, f4 int primary key); +create table t1(f1 int, f2 int references t_pri1(f2), f3 bool); +alter table t1 drop f2, add f4 int references t_pri2(f4) first; +\d+ t1 +alter table t1 drop f4, add f4 int references t_pri2(f4) after f1; +\d+ t1 + +-- 7.3.2 foreign key constraint in a table with data, drop foreign key, add column with foreign key +drop table if exists t1 cascade; +drop table if exists t_pri1 cascade; +drop table if exists t_pri2 cascade; +create table t_pri1(f1 text, f2 int primary key); +insert into t_pri1 values('a', 1), ('b', 2); +create table t_pri2(f1 text, f2 bool, f4 int primary key); +insert into t_pri2 values('a', true, 1), ('b', false, 2); +create table t1(f1 int, f2 int references t_pri1(f2), f3 bool); +insert into t1 values(1, 2, true), (2, 2, false); +alter table t1 drop f2, add f4 int references t_pri2(f4) first; +select * from t1; +alter table t1 drop f4, add f4 int references t_pri2(f4) after f1; +select * from t1; + +-- partition table +drop table if exists t1 cascade; +create table t1 +(f1 int, f2 int, f3 int) +partition by range(f1, f2) +( + partition t1_p0 values less than (10, 0), + partition t1_p1 values less than (20, 0), + partition t1_p2 values less than (30, 0) +); +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='t1') order by relname; + +alter table t1 add f4 int first, add f5 int after f1; +\d+ t1 +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='t1') order by relname; + +-- subpartition table +drop table if exists range_range cascade; +create table range_range(id int, gender varchar not null, birthday date not null) +partition by range (id) subpartition by range (birthday) +( + partition p_1 values less than(100) + ( + subpartition p_1_a values less than('2022-01-01'), + subpartition p_1_b values less than(MAXVALUE) + ), + partition p_2 values less than(200) + ( + subpartition p_2_a values less than('2022-01-01'), + subpartition p_2_b values less than(MAXVALUE) + ), + partition p_3 values less than(MAXVALUE) + ( + subpartition p_3_a values less than('2022-01-01'), + subpartition p_3_b values less than(MAXVALUE) + ) +); +insert into range_range values(198,'boy','2010-02-15'),(33,'boy','2003-08-11'),(78,'girl','2014-06-24'); +insert into range_range values(233,'girl','2010-01-01'),(360,'boy','2007-05-14'),(146,'girl','2005-03-08'); +insert into range_range values(111,'girl','2013-11-19'),(15,'girl','2009-01-12'),(156,'boy','2011-05-21'); + +-- test pg_partition +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='range_range') order by relname; +alter table range_range add f1 int default 1 first, add f2 text after id; +\d+ range_range +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='range_range') order by relname; +select * from range_range; + + +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool) with (orientation = column); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +-- error +alter table t1 add f6 text first; +-- error +alter table t1 add f6 text after f1; + +-- pg_index test +drop table if exists t1 cascade; +create table t1 +( + f1 int, f2 int, f3 varchar(20), f4 int, f5 int, f6 int, f7 int, + primary key(f1, f2), + unique((lower(f3)), (abs(f4))), + check(f5 = 10) +); +create unique index partial_t1_idx on t1(f5, abs(f6)) where f5 + f6 - abs(f7) > 0; + +select indkey, indexprs, indpred from pg_index where indrelid = (select oid from pg_class where relname = 't1') order by 1, 2, 3; + +alter table t1 add f8 int first, add f9 int unique after f1; +\d+ t1 +select indkey, indexprs, indpred from pg_index where indrelid = (select oid from pg_class where relname = 't1') order by 1, 2, 3; + +-- pg_attribute test +drop table if exists t1 cascade; +create table t1(f1 int, f2 int, f3 int); +select attname, attnum, atthasdef, attisdropped from pg_attribute where attrelid = (select oid from pg_class where relname = 't1') and attnum > 0 order by attnum; + +alter table t1 add f4 int default 4 first; +\d+ t1 +select attname, attnum, atthasdef, attisdropped from pg_attribute where attrelid = (select oid from pg_class where relname = 't1') and attnum > 0 order by attnum; + +alter table t1 drop f2, add f5 int default 5 after f1; +\d+ t1 +select attname, attnum, atthasdef, attisdropped from pg_attribute where attrelid = (select oid from pg_class where relname = 't1') and attnum > 0 order by attnum; + +-- pg_attrdef test +drop table if exists t1 cascade; +create table t1(f1 int primary key auto_increment, f2 int, f3 int default 3, f4 int generated always as (f2 + f3) stored); +select adnum, adsrc, adgencol from pg_attrdef where adrelid = (select oid from pg_class where relname = 't1') order by adnum; + +alter table t1 add f5 text default 'aaa' first; +\d+ t1 +select adnum, adsrc, adgencol from pg_attrdef where adrelid = (select oid from pg_class where relname = 't1') order by adnum; + +alter table t1 drop f2, add f6 int generated always as (f1 + abs(f3)) stored after f1; -- ERROR + +-- pg_rewrite test +drop table if exists t1 cascade; +create table t1(f1 int, f2 int, f3 int); +insert into t1 values(1, 2, 3), (11, 22, 33); +create view t1_view1 as select * from t1; +create view t1_view2 as select f1, f2 from t1; +\d+ t1_view1 +\d+ t1_view2 +\d+ t1 +select pg_get_viewdef('t1_view1'); +select pg_get_viewdef('t1_view2'); +select * from t1_view1; +select * from t1_view2; +select * from t1; +alter table t1 add f4 int first, add f5 int after f1; +\d+ t1_view1 +\d+ t1_view2 +\d+ t1 +select pg_get_viewdef('t1_view1'); +select pg_get_viewdef('t1_view2'); +select * from t1_view1; +select * from t1_view2; +select * from t1; + +-- pg_trigger test +drop table if exists t1 cascade; +create table t1(f1 boolean not null, f2 text, f3 int, f4 date); +alter table t1 add primary key(f1); +create or replace function dummy_update_func() returns trigger as $$ +begin + raise notice 'dummy_update_func(%) called: action = %, oid = %, new = %', TG_ARGV[0], TG_OP, OLD, NEW; + return new; +end; +$$ language plpgsql; + +drop trigger if exists f1_trig_update on t1; +drop trigger if exists f1_trig_insert on t1; + +create trigger f1_trig_update after update of f1 on t1 for each row + when (not old.f1 and new.f1) execute procedure dummy_update_func('update'); +create trigger f1_trig_insert after insert on t1 for each row + when (not new.f1) execute procedure dummy_update_func('insert'); + +select tgname, tgattr, tgqual from pg_trigger where tgrelid = (select oid from pg_class where relname='t1') order by tgname; + +alter table t1 add f5 int after f1, add f6 boolean first; +\d+ t1 +select tgname, tgattr, tgqual from pg_trigger where tgrelid = (select oid from pg_class where relname='t1') order by tgname; + +-- pg_rlspolicy test +drop table if exists t1 cascade; +drop role if exists test_rlspolicy2; +create role test_rlspolicy2 nologin password 'Gauss_234'; +create table t1 (f1 int, f2 int, f3 text) partition by range (f1) +( + partition t1_p0 values less than(10), + partition t1_p1 values less than(50), + partition t1_p2 values less than(100), + partition t1_p3 values less than(MAXVALUE) +); + +INSERT INTO t1 VALUES (generate_series(1, 150) % 24, generate_series(1, 150), 'huawei'); +grant select on t1 to public; + +create row level security policy t1_rls1 on t1 as permissive to public using (f2 <= 20); +create row level security policy t1_rls2 on t1 as restrictive to test_rlspolicy2 using (f1 < 30); + +\d+ t1 +select * from t1 limit 10; +select polname, polqual from pg_rlspolicy where polrelid = (select oid from pg_class where relname='t1'); + +alter table t1 add f4 int generated always as (f1 + 100) stored after f1, add f5 int generated always as (f2 + 100) stored first; +\d+ t1 +select * from t1 limit 10; +select polname, polqual from pg_rlspolicy where polrelid = (select oid from pg_class where relname='t1'); + +-- expression test +drop table if exists t1 cascade; +create table t1(f1 int, f2 int, f3 int, f4 bool, f5 text, f6 text); +insert into t1 values(1, 2, 3, true, 'nanjin', 'huawei'); +-- T_FuncExpr +create index t1_idx1 on t1(abs(f1), f2); +-- T_OpExpr +create index t1_idx2 on t1((f1 + f2), (f1 - f3)); +-- T_BooleanTest +create index t1_idx3 on t1((f4 is true)); +-- T_CaseExpr and T_CaseWhen +create index t1_idx4 on t1((case f1 when f2 then 'yes' when f3 then 'no' else 'unknow' end)); +-- T_ArrayExpr +create index t1_idx5 on t1((array[f1, f2, f3])); +-- T_TypeCast +create index t1_idx6 on t1(((f1 + f2 + 1) :: text)); +-- T_BoolExpr +create index t1_idx7 on t1((f1 and f2), (f2 or f3)); +-- T_ArrayRef +create index t1_idx8 on t1((f1 = (array[f1, f2, 3])[1])); +-- T_ScalarArrayOpExpr +create index t1_idx9 on t1((f1 = ANY(ARRAY[f2, 1, f1 + 10]))); +-- T_RowCompareExpr +create index t1_idx10 on t1((row(f1, f5) < row(f2, f6))); +-- T_MinMaxExpr +create index t1_idx11 on t1(greatest(f1, f2, f3), least(f1, f2, f3)); +-- T_RowExpr +drop table if exists mytable cascade; +create table mytable(f1 int, f2 int, f3 text); +-- create function getf1(mytable) returns int as 'select $1.f1' language sql; +-- create index t1_idx12 on t1(getf1(row(f1, 2, 'a'))); +-- T_CoalesceExpr +create index t1_idx13 on t1(nvl(f1, f2)); +-- T_NullTest +create index t1_idx14 on t1((f1 is null)); +-- T_ScalarArrayOpExpr +create index t1_idx16 on t1((f1 in (1,2,3))); +-- T_NullIfExpr +create index t1_idx17 on t1(nullif(f5,f6)); +-- T_RelabelType +alter table t1 add f7 oid; +create index t1_idx18 on t1((f7::int4)); +-- T_CoerceViaIO +alter table t1 add f8 json; +create index t1_idx19 on t1((f8::jsonb)); +-- T_ArrayCoerceExpr +alter table t1 add f9 float[]; +create index t1_idx20 on t1((f9::int[])); +-- T_PrefixKey +create index t1_idx21 on t1(f6(5)); + +\d+ t1 +select * from t1; + +alter table t1 add f10 int primary key auto_increment after f4, + add f11 int generated always as (f1 + f2) stored after f1, + add f12 date default '2023-01-05' first, + add f13 int not null default 13 first; + +\d+ t1 +select * from t1; + +-- test modify column ... first | after column in astore table +-- ASTORE table +-- common scenatios +drop table if exists t1 cascade; +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 modify f3 timestamp first, modify f1 int after f4, modify f5 bool after f2; +\d+ t1 +select * from t1; +alter table t1 modify + +-- 1 primary key +drop table if exists t1 cascade; +create table t1(f1 int primary key, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 modify f3 timestamp first, modify f1 int after f4; +\d+ t1 +alter table t1 modify f1 int after f3; +\d+ t1 +alter table t1 drop f1, modify f5 bool first; +\d+ t1 + +drop table if exists t1 cascade; +create table t1(f1 int primary key, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 modify f3 timestamp first, modify f1 int after f4; +\d+ t1 +select * from t1; +alter table t1 modify f1 int after f3; +\d+ t1 +select * from t1; +alter table t1 drop f1, modify f5 bool first; +\d+ t1 +select * from t1; + +-- 2 unique index +drop table if exists t1 cascade; +create table t1(f1 int unique, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 modify f3 timestamp first, modify f1 int after f4; +\d+ t1 +alter table t1 modify f1 int after f3; +\d+ t1 +alter table t1 drop f1, modify f5 bool first; +\d+ t1 + +drop table if exists t1 cascade; +create table t1(f1 int unique, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 modify f3 timestamp first, modify f1 int after f4; +\d+ t1 +select * from t1; +alter table t1 modify f1 int after f3; +\d+ t1 +select * from t1; +alter table t1 drop f1, modify f5 bool first; +\d+ t1 +select * from t1; + +-- 3 default and generated column +drop table if exists t1 cascade; +create table t1(f1 int default 1, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 modify f3 timestamp first, modify f1 int after f4; +\d+ t1 +alter table t1 modify f1 int after f3; +\d+ t1 +alter table t1 drop f1, modify f5 bool first; +\d+ t1 + +drop table if exists t1 cascade; +create table t1(f1 int default 1, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 modify f3 timestamp first, modify f1 int after f4; +\d+ t1 +select * from t1; +alter table t1 modify f1 int after f3; +\d+ t1 +select * from t1; +alter table t1 drop f1, modify f5 bool first; +\d+ t1 +select * from t1; + +drop table if exists t1 cascade; +create table t1(f1 int, f2 int default 2, f3 int default 3, f4 int generated always as (f1 + f2) stored); +alter table t1 modify f4 int after f2, modify f1 int after f3, modify f3 int first; +\d+ t1 +alter table t1 drop f1; +\d+ t1 + +drop table if exists t1 cascade; +create table t1(f1 int, f2 int default 2, f3 int default 3, f4 int generated always as (f1 + f2) stored); +insert into t1 values(1,2,3),(11,22,33); +alter table t1 modify f4 int after f2, modify f1 int after f3, modify f3 int first; +\d+ t1 +select * from t1; +alter table t1 drop f1; +\d+ t1 +select * from t1; + +-- 4 auto_increment +drop table if exists t1 cascade; +create table t1(f1 int primary key auto_increment, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +\d+ t1 +alter table t1 modify f3 timestamp first, modify f1 int after f4; +\d+ t1 + +drop table if exists t1 cascade; +create table t1(f1 int primary key auto_increment, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +insert into t1(f2, f3, f4, f5) values('a', '2022-11-08 19:56:10.158564', x'41', true), ('b', '2022-11-09 19:56:10.158564', x'42', false); +\d+ t1 +select * from t1; +alter table t1 modify f3 timestamp first, modify f1 int after f4; +\d+ t1 +select * from t1; +insert into t1(f3, f2, f4, f5, f1) values('2022-11-10 19:56:10.158564', 'c', x'43', false, 3); +select f1 from t1; + +-- 5 NULL and NOT NULL +drop table if exists t1 cascade; +alter table t1(f1 int null, f2 varchar(20) not null, f3 timestamp, f4 bit(8), f5 bool); +alter table t1 modify f3 timestamp first, modify f1 int after f4; +\d+ t1 +alter table t1 modify f1 int after f3; +\d+ t1 +alter table t1 drop f1, modify f5 bool first; +\d+ t1 +alter table t1 modify f2 varchar(20) after f3; +\d+ t1 + +drop table if exists t1 cascade; +alter table t1(f1 int null, f2 varchar(20) not null, f3 timestamp, f4 bit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 modify f3 timestamp first, modify f1 int after f4; +\d+ t1 +select * from t1; +alter table t1 modify f1 int after f3; +\d+ t1 +select * from t1; +alter table t1 drop f1, modify f5 bool first; +\d+ t1 +select * from t1; +alter table t1 modify f2 varchar(20) after f3; +\d+ t1 +select * from t1; + +-- 6 check constraint +drop table if exists t1 cascade; +create table t1(f1 int check(f1 = 1), f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 modify f3 timestamp first, modify f1 int after f4; +\d+ t1 +alter table t1 modify f1 int after f3; +\d+ t1 +alter table t1 drop f1, modify f5 bool first; +\d+ t1 + +drop table if exists t1 cascade; +create table t1(f1 int check(f1 = 1), f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 modify f3 timestamp first, modify f1 int after f4; +\d+ t1 +select * from t1; +alter table t1 modify f1 int after f3; +\d+ t1 +select * from t1; +alter table t1 drop f1, modify f5 bool first; +\d+ t1 +select * from t1; + +-- 7 foreign key +drop table if exists t_pri1 cascade; +create table t_pri1(f1 int, f2 int primary key); +drop table if exists t1 cascade; +create table t1(f1 int, f2 int references t_pri1(f2), f3 bool); +alter table t1 modify f2 int first; +\d+ t1 +alter table t1 modify f2 int after f3; +\d+ t1 + +drop table if exists t_pri1 cascade; +create table t_pri1(f1 int, f2 int primary key); +insert into t_pri1 values(1,1),(2,2); +drop table if exists t1 cascade; +create table t1(f1 int, f2 int references t_pri1(f2), f3 bool); +insert into t1 values(1, 1, true), (2, 2, false); +alter table t1 modify f2 int first; +\d+ t1 +select * from t1; +alter table t1 modify f2 int after f3; +\d+ t1 +select * from t1; + +-- partition table +drop table if exists t1 cascade; +create table t1 +(f1 int, f2 int, f3 int, primary key (f1, f2)) +partition by range(f1, f2) +( + partition t1_p0 values less than (10, 0), + partition t1_p1 values less than (20, 0), + partition t1_p2 values less than (30, 0) +); +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='t1') order by relname; + +alter table t1 modify f1 int after f2, modify f3 int first, modify f2 int first; +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='t1') order by relname; + +alter table t1 modify f1 int after f2; +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='t1') order by relname; + +-- modify operation before add +alter table t1 add f4 int after f2, modify f1 int after f2; +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='t1'); + +drop table if exists t1 cascade; +create table t1 +(f1 int, f2 int, f3 int, primary key (f1, f2)) +partition by range(f1, f2) +( + partition t1_p0 values less than (10, 0), + partition t1_p1 values less than (20, 0), + partition t1_p2 values less than (30, 0) +); +insert into t1 values(9, -1, 1), (19, -1, 2), (29, -1, 3); +\d+ t1 +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='t1'); +select * from t1 partition (t1_p0); +select * from t1 partition (t1_p1); +select * from t1 partition (t1_p2); + +alter table t1 modify f1 int after f2, modify f3 int first, modify f2 int first; +\d+ t1 +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='t1'); +select * from t1 partition (t1_p0); +select * from t1 partition (t1_p1); +select * from t1 partition (t1_p2); + +alter table t1 modify f1 int after f2; +\d+ t1 +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='t1'); +select * from t1 partition (t1_p0); +select * from t1 partition (t1_p1); +select * from t1 partition (t1_p2); + +alter table t1 add f4 int after f2, modify f1 int after f2; +\d+ t1 +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='t1'); +select * from t1 partition (t1_p0); +select * from t1 partition (t1_p1); +select * from t1 partition (t1_p2); + +-- subpartition table +drop table if exists range_range cascade; +create table range_range(id int, gender varchar not null, birthday date not null, primary key(id, birthday)) +partition by range (id) subpartition by range (birthday) +( + partition p_1 values less than(100) + ( + subpartition p_1_a values less than('2022-01-01'), + subpartition p_1_b values less than(MAXVALUE) + ), + partition p_2 values less than(200) + ( + subpartition p_2_a values less than('2022-01-01'), + subpartition p_2_b values less than(MAXVALUE) + ), + partition p_3 values less than(MAXVALUE) + ( + subpartition p_3_a values less than('2022-01-01'), + subpartition p_3_b values less than(MAXVALUE) + ) +); +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='range_range') order by relname; + +alter table range_range modify birthday date first, modify id int after gender; +\d+ range_range +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='range_range') order by relname; + + +drop table if exists range_range cascade; +create table range_range(id int, gender varchar not null, birthday date not null, primary key(id, birthday)) +partition by range (id) subpartition by range (birthday) +( + partition p_1 values less than(100) + ( + subpartition p_1_a values less than('2022-01-01'), + subpartition p_1_b values less than(MAXVALUE) + ), + partition p_2 values less than(200) + ( + subpartition p_2_a values less than('2022-01-01'), + subpartition p_2_b values less than(MAXVALUE) + ), + partition p_3 values less than(MAXVALUE) + ( + subpartition p_3_a values less than('2022-01-01'), + subpartition p_3_b values less than(MAXVALUE) + ) +); + +insert into range_range values(198,'boy','2010-02-15'),(33,'boy','2003-08-11'),(78,'girl','2014-06-24'); +insert into range_range values(233,'girl','2010-01-01'),(360,'boy','2007-05-14'),(146,'girl','2005-03-08'); +insert into range_range values(111,'girl','2013-11-19'),(15,'girl','2009-01-12'),(156,'boy','2011-05-21'); + +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='range_range') order by relname; + +alter table range_range modify birthday date first, modify id int after gender; +\d+ range_range +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='range_range') order by relname; + +select * from range_range; + +-- pg_index test +drop table if exists t1 cascade; +create table t1 +( + f1 int, f2 int, f3 varchar(20), f4 int, f5 int, f6 int, f7 int, + primary key(f1, f2), + unique((lower(f3)), (abs(f4))), + check(f5 = 10) +); +create unique index partial_t1_idx on t1(f5, abs(f6)) where f5 + f6 - abs(f7) > 0; + +\d+ t1 +select indkey, indexprs, indpred from pg_index where indrelid = (select oid from pg_class where relname = 't1'); + +alter table t1 modify f1 int after f2, modify f4 int after f6, modify f5 int first; +\d+ t1 +select indkey, indexprs, indpred from pg_index where indrelid = (select oid from pg_class where relname = 't1'); + +-- pg_attribute test +drop table if exists t1 cascade; +create table t1(f1 int, f2 int, f3 int); +\d+ t1 +select attname, attnum, atthasdef, attisdropped from pg_attribute where attrelid = (select oid from pg_class where relname = 't1') and attnum > 0 order by attnum; + +alter table t1 modify f3 int first, modify f1 int after f2; +\d+ t1 +select attname, attnum, atthasdef, attisdropped from pg_attribute where attrelid = (select oid from pg_class where relname = 't1') and attnum > 0 order by attnum; + +-- pg_attrdef test +drop table if exists t1 cascade; +create table t1(f1 int primary key auto_increment, f2 int, f3 int default 3, f4 int generated always as (f2 + f3) stored); +\d+ t1 +select adnum, adsrc, adgencol from pg_attrdef where adrelid = (select oid from pg_class where relname = 't1') order by adnum; + +alter table t1 modify f3 int first, modify f1 int after f4, modify f4 int first; +\d+ t1 +select adnum, adsrc, adgencol from pg_attrdef where adrelid = (select oid from pg_class where relname = 't1') order by adnum; + +-- pg_depend test +drop table if exists t1 cascade; +create table t1(f1 int default 10, f2 int primary key, f3 int generated always as (f1 + f2) stored, f4 int, unique ((abs(f4)))); +\d+ t1 +select classid, objsubid, refclassid, refobjsubid, deptype from pg_depend + where refobjid = (select oid from pg_class where relname='t1') or objid = (select oid from pg_class where relname='t1') order by 1, 2, 3, 4, 5; + +alter table t1 modify f4 int first, modify f3 int after f1, modify f1 int after f2; +\d+ t1 +select classid, objsubid, refclassid, refobjsubid, deptype from pg_depend + where refobjid = (select oid from pg_class where relname='t1') or objid = (select oid from pg_class where relname='t1') order by 1, 2, 3, 4, 5; + +-- pg_partition test +drop table if exists range_range cascade; +create table range_range(id int, gender varchar not null, birthday date not null) +partition by range (id) subpartition by range (birthday) +( + partition p_1 values less than(100) + ( + subpartition p_1_a values less than('2022-01-01'), + subpartition p_1_b values less than(MAXVALUE) + ), + partition p_2 values less than(200) + ( + subpartition p_2_a values less than('2022-01-01'), + subpartition p_2_b values less than(MAXVALUE) + ), + partition p_3 values less than(MAXVALUE) + ( + subpartition p_3_a values less than('2022-01-01'), + subpartition p_3_b values less than(MAXVALUE) + ) +); +insert into range_range values(198,'boy','2010-02-15'),(33,'boy','2003-08-11'),(78,'girl','2014-06-24'); +insert into range_range values(233,'girl','2010-01-01'),(360,'boy','2007-05-14'),(146,'girl','2005-03-08'); +insert into range_range values(111,'girl','2013-11-19'),(15,'girl','2009-01-12'),(156,'boy','2011-05-21'); + +\d+ range_range +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='range_range') order by relname; + +alter table range_range modify gender varchar after birthday; +\d+ range_range +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='range_range') order by relname; + +alter table range_range modify birthday date first, modify id int after gender; +\d+ range_range +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='range_range') order by relname; + + +-- pg_rewrite test +drop table if exists t1 cascade; +create table t1(f1 int, f2 int, f3 int, f4 int); +insert into t1 values(1, 2, 3, 4), (11, 22, 33, 44); +create view t1_view1 as select * from t1; +create view t1_view2 as select f1, f4 from t1; +\d+ t1_view1 +\d+ t1_view2 +\d+ t1 +select pg_get_viewdef('t1_view1'); +select pg_get_viewdef('t1_view2'); +select * from t1_view1; +select * from t1_view2; +select * from t1; +alter table t1 modify f2 int first, modify f1 int after f4, add f5 int after f4; +\d+ t1_view1 +\d+ t1_view2 +\d+ t1 +select pg_get_viewdef('t1_view1'); +select pg_get_viewdef('t1_view2'); +select * from t1_view1; +select * from t1_view2; +select * from t1; + +-- pg_trigger test +drop table if exists t1 cascade; +create table t1(f1 boolean not null, f2 text, f3 int, f4 date); +alter table t1 add primary key(f1); +create or replace function dummy_update_func() returns trigger as $$ +begin + raise notice 'dummy_update_func(%) called: action = %, oid = %, new = %', TG_ARGV[0], TG_OP, OLD, NEW; + return new; +end; +$$ language plpgsql; +drop function dummy_update_func; +drop trigger if exists f1_trig_update on t1; +drop trigger if exists f1_trig_insert on t1; + +create trigger f1_trig_update after update of f1 on t1 for each row + when (not old.f1 and new.f1) execute procedure dummy_update_func('update'); +create trigger f1_trig_insert after insert on t1 for each row + when (not new.f1) execute procedure dummy_update_func('insert'); + +\d+ t1 +select tgname, tgattr, tgqual from pg_trigger where tgrelid = (select oid from pg_class where relname='t1') order by tgname; + +alter table t1 modify f3 int first, modify f1 boolean after f4; +\d+ t1 +select tgname, tgattr, tgqual from pg_trigger where tgrelid = (select oid from pg_class where relname='t1') order by tgname; + +-- pg_rlspolicy test +drop table if exists t1 cascade; +drop role if exists test_rlspolicy3; +create role test_rlspolicy3 nologin password 'Gauss_234'; +create table t1 (f1 int, f2 int, f3 text) partition by range (f1) +( + partition t1_p0 values less than(10), + partition t1_p1 values less than(50), + partition t1_p2 values less than(100), + partition t1_p3 values less than(MAXVALUE) +); + +INSERT INTO t1 VALUES (generate_series(1, 150) % 24, generate_series(1, 150), 'huawei'); +grant select on t1 to public; + +create row level security policy t1_rls1 on t1 as permissive to public using (f2 <= 20); +create row level security policy t1_rls2 on t1 as restrictive to test_rlspolicy3 using (f1 < 30); + +\d+ t1 +select * from t1 limit 10; +select polname, polqual from pg_rlspolicy where polrelid = (select oid from pg_class where relname='t1'); + +alter table t1 modify f2 int first, modify f1 int after f3; + +\d+ t1 +select * from t1 limit 10; +select polname, polqual from pg_rlspolicy where polrelid = (select oid from pg_class where relname='t1'); + + +-- expression test +drop table if exists t1 cascade; +create table t1(f1 int, f2 int, f3 int, f4 bool, f5 text, f6 text); +insert into t1 values(1, 2, 3, true, 'nanjin', 'huawei'); +-- T_FuncExpr +create index t1_idx1 on t1(abs(f1), f2); +-- T_OpExpr +create index t1_idx2 on t1((f1 + f2), (f1 - f3)); +-- T_BooleanTest +create index t1_idx3 on t1((f4 is true)); +-- T_CaseExpr and T_CaseWhen +create index t1_idx4 on t1((case f1 when f2 then 'yes' when f3 then 'no' else 'unknow' end)); +-- T_ArrayExpr +create index t1_idx5 on t1((array[f1, f2, f3])); +-- T_TypeCast +create index t1_idx6 on t1(((f1 + f2 + 1) :: text)); +-- T_BoolExpr +create index t1_idx7 on t1((f1 and f2), (f2 or f3)); +-- T_ArrayRef +create index t1_idx8 on t1((f1 = (array[f1, f2, 3])[1])); +-- T_ScalarArrayOpExpr +create index t1_idx9 on t1((f1 = ANY(ARRAY[f2, 1, f1 + 10]))); +-- T_RowCompareExpr +create index t1_idx10 on t1((row(f1, f5) < row(f2, f6))); +-- T_MinMaxExpr +create index t1_idx11 on t1(greatest(f1, f2, f3), least(f1, f2, f3)); +-- T_RowExpr +drop table if exists mytable cascade; +create table mytable(f1 int, f2 int, f3 text); +-- create function getf1(mytable) returns int as 'select $1.f1' language sql; +-- create index t1_idx12 on t1(getf1(row(f1, 2, 'a'))); +-- T_CoalesceExpr +create index t1_idx13 on t1(nvl(f1, f2)); +-- T_NullTest +create index t1_idx14 on t1((f1 is null)); +-- T_ScalarArrayOpExpr +create index t1_idx16 on t1((f1 in (1,2,3))); +-- T_NullIfExpr +create index t1_idx17 on t1(nullif(f5,f6)); +-- T_RelabelType +alter table t1 add f7 oid; +create index t1_idx18 on t1((f7::int4)); +-- T_CoerceViaIO +alter table t1 add f8 json; +create index t1_idx19 on t1((f8::jsonb)); +-- T_ArrayCoerceExpr +alter table t1 add f9 float[]; +create index t1_idx20 on t1((f9::int[])); + +\d+ t1 +select * from t1; + +alter table t1 modify f8 json first, modify f2 int after f6, modify f7 oid after f3; + +\d+ t1 +select * from t1; + +drop table if exists t1; +create table t1(f1 int, f2 int); +insert into t1 values(1,2); +alter table t1 add f3 int default 3, add f4 int default 4 after f3, add f5 int default 5, add f6 int default 6 after f3; +select * from t1; + +drop table if exists t1; +create table t1(f1 int, f2 int); +insert into t1 values(1,2); +alter table t1 add f3 int default 3, add f4 int default 4 after f1, add f5 int default 5, add f6 int default 6 after f5; +select * from t1; + +drop table if exists t1; +create table t1(f1 int, f2 int); +insert into t1 values(1,2); +alter table t1 add f3 int, add f4 int after f3, add f5 int, add f6 int first; +select * from t1; + +drop table if exists t1; +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); + +alter table t1 drop f5, + add f6 int default 6 , add f7 int first, add f8 int default 8 after f3, + modify f3 timestamp first, modify f6 int after f2, modify f1 text, modify f2 text after f4; + +drop table if exists t1 cascade; +create table t1(f1 int, f2 int, f3 int, primary key(f1, f3)); +insert into t1 values(1, 2, 3), (11, 22, 33); +\d+ t1 +select * from t1; +alter table t1 modify f3 int first, modify f1 int after f2; +\d+ t1 +select * from t1; + +drop table if exists t1 cascade; +create table t1(f1 int, f2 int, f3 int); +insert into t1 values(1, 2, 3), (11, 12, 13), (21, 22, 23); +select * from t1; +alter table t1 add f4 int generated always as (f1 + 100) stored after f1, add f5 int generated always as (f2 * 10) stored first; +select * from t1; + +drop table if exists t1 cascade; +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool, f6 int generated always as (f1 * 10) stored, primary key(f1, f2)); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +select * from t1; + +alter table t1 drop f4, + add f7 int default 7 , add f8 int first, add f9 int default 9 after f3, + modify f3 timestamp first, modify f6 int after f2, modify f5 int, modify f2 text after f5, + add f10 timestamp generated always as (f3) stored after f3, + add f11 int generated always as (f1 * 100) stored first; + +\d+ t1 +select * from t1; + +drop table if exists t1 cascade; +create table t1(f1 int, f2 varchar(20), f3 int, primary key(f1, f3)); +insert into t1 values(1, 'a', 1), (2, 'b', 2); +\d+ t1 +select * from t1; + +alter table t1 modify f1 text after f3, add f10 int default 10 after f2; +\d+ t1 +select * from t1; + +-- unlogged table +drop table if exists t1 cascade; +create unlogged table t1(f1 int, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool, f6 int generated always as (f1 * 10) stored, primary key(f1, f2)); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +\d+ t1 +select * from t1; + +alter table t1 drop f4, + add f7 int default 7 , add f8 int first, add f9 int default 9 after f3, + modify f3 timestamp first, modify f6 int after f2, modify f5 int, modify f2 text after f5, + add f10 timestamp generated always as (f3) stored after f3, + add f11 int generated always as (f1 * 100) stored first; + +\d+ t1 +select * from t1; + +-- temp table +drop table if exists t1 cascade; +create temp table t1(f1 int, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool, f6 int generated always as (f1 * 10) stored, primary key(f1, f2)); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +select * from t1; + +alter table t1 drop f4, + add f7 int default 7 , add f8 int first, add f9 int default 9 after f3, + modify f3 timestamp first, modify f6 int after f2, modify f5 int, modify f2 text after f5, + add f10 timestamp generated always as (f3) stored after f3, + add f11 int generated always as (f1 * 100) stored first; +select * from t1; + +drop table if exists t1 cascade; +create table t1(f1 int, f2 SET('beijing','shanghai','nanjing','wuhan')); +insert into t1 values(1, 'shanghai,beijing'), (2, 'wuhan'); +\d+ t1 +select * from t1; +alter table t1 add f3 int default 3 first, add f4 int default 4 after f3, + add f5 SET('beijing','shanghai','nanjing','wuhan') default 'nanjing' first; +\d+ t1 +select * from t1; + +drop table if exists t1 cascade; +create table t1(f1 int, f2 SET('beijing','shanghai','nanjing','wuhan')); +-- error +alter table t1 modify f2 SET('beijing','shanghai','nanjing','wuhan') first; +alter table t1 modify f2 SET('beijing','shanghai','nanjing','wuhan') after f1; + +drop table if exists t1 cascade; + +--DTS +drop table if exists unit cascade; +CREATE TABLE unit +( + f11 INTEGER CHECK (f11 >=2), + f12 bool, + f13 text, + f14 varchar(20), + primary key (f11,f12) +); + +insert into unit values(2,3,4,5); +insert into unit values(3,4,5,6); +ALTER TABLE unit ADD f1 int CHECK (f1 >=10) FIRST; +insert into unit values (10,6,1,1,1); +insert into unit values (11,7,1,1,1); +ALTER TABLE unit ADD f2 int CHECK (f2 >=10) after f11; +select * from unit; +ALTER TABLE unit MODIFY f12 int FIRST; +select * from unit; +drop table if exists unit cascade; + +-- dts for set +drop table if exists test_s1 cascade; +create table test_s1 (c1 int,c2 SET('aaa','bbb','ccc'), c3 bool, primary key(c1)); +insert into test_s1 values(1,2,1), (2,'aaa',3), (3,4,4), (4,5,5), (5,1,6), (6,3,7); +alter table test_s1 add f1 text after c1; +alter table test_s1 modify c2 int first; +select * from test_s1; +drop table if exists test_s1 cascade; + +drop table if exists test_s2 cascade; +create table test_s2 (c1 int,c2 SET('aaa','bbb','ccc'), c3 bool, primary key(c1)); +insert into test_s2 values(1,2,1), (2,'aaa',3), (3,4,4), (4,5,5), (5,1,6), (6,3,7); +alter table test_s2 add f1 text check(f1 >= 2) after c1; +alter table test_s2 add f2 SET('w','ww','www','wwww') first; +alter table test_s2 modify f2 text after c1; +alter table test_s2 modify c2 int first; +select * from test_s2; +drop table if exists test_s2 cascade; + +drop table if exists t1 cascade; +create table t1(f1 set('aaa','bbb','ccc'), f2 set('1','2','3'), f3 set('beijing','shannghai','nanjing'), + f4 set('aaa','bbb','ccc') generated always as(f1+f2+f3) stored, + f5 set('1','2','3') generated always as(f1+f2+f3) stored, + f6 set('beijing','shannghai','nanjing') generated always as(f1+f2+f3) stored); +\d+ t1 +alter table t1 modify f1 int after f6; +\d+ t1 +alter table t1 drop f1; +\d+ t1 +drop table if exists t1 cascade; + +drop table t1 cascade; +create table t1(f1 int, f2 text, f3 int, f4 bool, f5 int generated always as (f1 + f3) stored); +insert into t1 values(1, 'aaa', 3, true); +insert into t1 values(11, 'bbb', 33, false); +insert into t1 values(111, 'ccc', 333, true); +insert into t1 values(1111, 'ddd', 3333, true); + +create view t1_view1 as select * from t1; +select * from t1_view1; +alter table t1 modify f1 int after f2, modify f3 int first; +drop view t1_view1; +create view t1_view1 as select * from t1; +alter table t1 modify f1 int after f2, modify f3 int first; +drop table t1 cascade; + +create table t1(f1 int, f2 text, f3 int, f4 bigint, f5 int generated always as (f1 + f3) stored); +insert into t1 values(1, 'aaa', 3, 1); +insert into t1 values(11, 'bbb', 33, 2); +insert into t1 values(111, 'ccc', 333, 3); +insert into t1 values(1111, 'ddd', 3333, 4); + +create view t1_view1 as select * from t1; +select * from t1_view1; +alter table t1 add f6 int first, add f7 int after f4, modify f1 int after f2, modify f3 int first; +select * from t1_view1; +drop view t1_view1; + +create view t1_view2 as select f1, f3, f5 from t1 where f2='aaa'; +select * from t1_view2; +alter table t1 add f8 int first, add f9 int after f4, modify f1 int after f2, modify f3 int first, modify f2 varchar(20) first; +select * from t1_view2; +drop view t1_view2; + +create view t1_view3 as select * from (select f1+f3, f5 from t1); +select * from t1_view3; +alter table t1 add f10 int first, add f11 int after f4, modify f1 int after f2, modify f3 int first, modify f2 varchar(20) first; +select * from t1_view3; +drop view t1_view3; + +create view t1_view4 as select * from (select abs(f1+f3) as col1, abs(f5) as col2 from t1); +select * from t1_view4; +alter table t1 add f12 int first, add f13 int after f4, modify f1 int after f2, modify f3 int first, modify f2 varchar(20) first; +select * from t1_view4; +drop view t1_view4; + +create view t1_view5 as select * from (select * from t1); +select * from t1_view5; +alter table t1 add f14 int first, add f15 int after f4, modify f1 int after f2, modify f3 int first; +select * from t1_view5; +drop view t1_view5; + +create view t1_view6 as select f1, f3, f5 from t1 where f2='aaa'; +select * from t1_view6; +alter table t1 modify f1 int after f2, modify f3 int first, modify f2 varchar(20) first; +select * from t1_view6; +drop view t1_view6; +drop table t1 cascade; + +-- dts for add +drop table if exists test_d; +create table test_d (f2 int primary key, f3 bool, f5 text); +insert into test_d values(1,2,3), (2,3,4), (3,4,5); +select * from test_d; +alter table test_d add f1 int default 1,add f11 text check (f11 >=2) first; +select * from test_d; + +drop table if exists test_d; +create table test_d (f2 int primary key, f3 bool, f5 text); +insert into test_d values(1,2,3), (2,3,4), (3,4,5); +select * from test_d; +alter table test_d add f1 int default 1; +alter table test_d add f11 text check (f11 >=2) first; +select * from test_d; +drop table if exists test_d; + +drop table if exists t1 cascade; +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +select * from t1; +alter table t1 add f6 int generated always as (f1 * 10) stored, add f7 text default '777' first, + add f8 int default 8, add f9 int primary key auto_increment after f6; +select * from t1; + +drop table if exists t1 cascade; +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +select * from t1; +alter table t1 add f6 int generated always as (f1 * 10) stored, add f7 text default '7' first, + add f8 int default 8, add f9 int primary key auto_increment after f1, + add f10 bool default true, add f11 timestamp after f2, + add f12 text after f3, add f14 int default '14', add f15 int default 15 check(f15 = 15) after f9; +select * from t1; +drop table if exists t1 cascade; + +drop table if exists t1 cascade; +create table t1(f1 int comment 'f1 is int', f2 varchar(20), f3 timestamp comment 'f3 is timestamp', f4 bit(8), f5 bool comment 'f5 is boolean'); +SELECT pg_get_tabledef('t1'); +alter table t1 add f6 int generated always as (f1 * 10) stored, add f7 text default '7' first, add f8 int primary key auto_increment after f2; +SELECT pg_get_tabledef('t1'); +alter table t1 modify f1 int after f3, modify f5 bool first, modify f3 timestamp after f4; +SELECT pg_get_tabledef('t1'); +drop table if exists t1 cascade; + + +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 add f6 int2 primary key auto_increment not null; +drop table if exists t1 cascade; + +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 add f6 boolean primary key auto_increment not null; +drop table if exists t1 cascade; + +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 add f6 int8 primary key auto_increment not null; +drop table if exists t1 cascade; + +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 add f6 float4 primary key auto_increment not null; +drop table if exists t1 cascade; + +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 add f6 float8 primary key auto_increment not null; +drop table if exists t1 cascade; + +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 modify column f1 boolean primary key auto_increment not null; +drop table if exists t1 cascade; + +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 modify column f1 int1 primary key auto_increment not null; +drop table if exists t1 cascade; + +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 modify column f1 int2 primary key auto_increment not null; +drop table if exists t1 cascade; + +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 modify column f1 int4 primary key auto_increment not null; +drop table if exists t1 cascade; + +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 modify column f1 int8 primary key auto_increment not null; +drop table if exists t1 cascade; + +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 modify column f1 float4 primary key auto_increment not null; +drop table if exists t1 cascade; + +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 modify column f1 float8 primary key auto_increment not null; +drop table if exists t1 cascade; + + + + +-- \c postgres +-- drop database test_first_after_B; \ No newline at end of file diff --git a/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_001.sql b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_001.sql new file mode 100644 index 000000000..9a52816f5 --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_001.sql @@ -0,0 +1,785 @@ +create table altertable_rangeparttable +( + c1 int, + c2 float, + c3 real, + c4 text +) +partition by range (c1, c2, c3, c4) +( + partition altertable_rangeparttable_p1 values less than (10, 10.00, 19.156, 'h'), + partition altertable_rangeparttable_p2 values less than (20, 20.89, 23.75, 'k'), + partition altertable_rangeparttable_p3 values less than (30, 30.45, 32.706, 's') +); + +alter table altertable_rangeparttable add partition altertable_rangeparttable_p4 values less than (36, 45.25, 37.39, 'u'); + +create table altertable_rangeparttable2 +( + c1 int, + c2 float, + c3 real, + c4 text +) +partition by range (abs(c1)) +( + partition altertable_rangeparttable_p1 values less than (10), + partition altertable_rangeparttable_p2 values less than (20), + partition altertable_rangeparttable_p3 values less than (30) +); +alter table altertable_rangeparttable2 add partition altertable_rangeparttable_p4 values less than (36); + + +CREATE TABLE range_range +( + month_code VARCHAR2 ( 30 ) NOT NULL , + dept_code VARCHAR2 ( 30 ) NOT NULL , + user_no VARCHAR2 ( 30 ) NOT NULL , + sales_amt int +) +PARTITION BY RANGE (month_code) SUBPARTITION BY RANGE (dept_code) +( + PARTITION p_201901 VALUES LESS THAN( '201903' ) + ( + SUBPARTITION p_201901_a VALUES LESS THAN( '2' ), + SUBPARTITION p_201901_b VALUES LESS THAN( '3' ) + ), + PARTITION p_201902 VALUES LESS THAN( '201904' ) + ( + SUBPARTITION p_201902_a VALUES LESS THAN( '2' ), + SUBPARTITION p_201902_b VALUES LESS THAN( '3' ) + ) +); + +alter table range_range add partition p_202001 values less than ('202002') (subpartition p_202001_a values less than('2') , subpartition p_202001_b values less than('3') ); + +-- comes from function_get_table_def.sql +create table table_range4 (id int primary key, a date, b varchar) +partition by range (id) +( + partition table_range4_p1 start (10) end (40) every (10), + partition table_range4_p2 end (70), + partition table_range4_p3 start (70), + partition table_range4_p4 start (100) end (150) every (20) +); + +alter table table_range4 add partition table_range4_p5 start (150) end (300) every (20); +alter table table_range4 add partition table_range4_p6 values less than (310), add partition table_range4_p7 values less than (320); + +create table table_interval1 (id int, a date, b varchar) +partition by range (a) +interval ('1 day') +( + partition table_interval1_p1 values less than('2020-03-01'), + partition table_interval1_p2 values less than('2020-05-01'), + partition table_interval1_p3 values less than('2020-07-01'), + partition table_interval1_p4 values less than(maxvalue) +); +alter table table_interval1 add partition table_interval1_p5 start ('2020-08-01') end ('2020-09-01'); + +create table table_list1 (id int, a date, b varchar) +partition by list (id) +( + partition table_list1_p1 values (1, 2, 3, 4), + partition table_list1_p2 values (5, 6, 7, 8), + partition table_list1_p3 values (9, 10, 11, 12) +); +alter table table_list1 add partition table_list1_p4 values (13, 14, 15, 16); +alter table table_list1 add partition table_list1_p5 values (default); + +create table table_list2 (id int, a date, b varchar) +partition by list (b) +( + partition table_list2_p1 values ('1', '2', '3', '4'), + partition table_list2_p2 values ('5', '6', '7', '8'), + partition table_list2_p3 values ('9', '10', '11', '12') +); +alter table table_list2 add partition table_list2_p4 values ('13', '14', '15', '16'); +alter table table_list2 add partition table_list2_p5 values ('DEFAULT'); +alter table table_list2 add partition table_list2_p6 values ('default'); +alter table table_list2 add partition table_list2_p7 values (default); + + +create table table_list3 (id int, a date, b varchar) +partition by list (id, b) +( + partition table_list3_p1 values ((1, 'a'), (2,'b'), (3,'c'), (4,'d')) , + partition table_list3_p2 values ((5, 'a'), (6,'b'), (7,'c'), (8,'d')) + +); +alter table table_list3 add partition table_list3_p3 values ((15, 'a'), (16,'b'), (17,'c'), (18,'d')); +alter table table_list3 add partition table_list3_p4 values (default); + +create table table_hash1 (id int, a date, b varchar) +partition by hash (id) +( + partition table_hash1_p1, + partition table_hash1_p2, + partition table_hash1_p3 +); + + +CREATE TABLE list_hash_2 ( + col_1 integer primary key, + col_2 integer, + col_3 character varying(30) unique, + col_4 integer +) +WITH (orientation=row, compression=no) +PARTITION BY LIST (col_2) SUBPARTITION BY HASH (col_3) +( + PARTITION p_list_1 VALUES (-1,-2,-3,-4,-5,-6,-7,-8,-9,-10) + ( + SUBPARTITION p_hash_1_1, + SUBPARTITION p_hash_1_2, + SUBPARTITION p_hash_1_3 + ), + PARTITION p_list_2 VALUES (1,2,3,4,5,6,7,8,9,10), + PARTITION p_list_3 VALUES (11,12,13,14,15,16,17,18,19,20) + ( + SUBPARTITION p_hash_3_1, + SUBPARTITION p_hash_3_2 + ), + PARTITION p_list_4 VALUES (21,22,23,24,25,26,27,28,29,30) + ( + SUBPARTITION p_hash_4_1, + SUBPARTITION p_hash_4_2, + SUBPARTITION p_hash_4_3, + SUBPARTITION p_hash_4_4, + SUBPARTITION p_hash_4_5 + ), + PARTITION p_list_5 VALUES (31,32,33,34,35,36,37,38,39,40), + PARTITION p_list_6 VALUES (41,42,43,44,45,46,47,48,49,50) + ( + SUBPARTITION p_hash_6_1, + SUBPARTITION p_hash_6_2, + SUBPARTITION p_hash_6_3, + SUBPARTITION p_hash_6_4, + SUBPARTITION p_hash_6_5 + ), + PARTITION p_list_7 VALUES (DEFAULT) +); + +alter table list_hash_2 add partition p_list_8 values (51,52,53,54,55,56,57,58,59,60) (subpartition p_hash_8_1, subpartition p_hash_8_2, subpartition p_hash_8_3); + +-- drop table table_list3; +create table table_list3 (id int, a date, b varchar) +partition by list (id, b) +( + partition table_list3_p1 values ((1, 'a'), (2,'b'), (3,'c'), (4,'d')) , + partition table_list3_p2 values ((5,'a'), (6,'b'), (7,'NULL'), (8,NULL)) +); + +alter table table_list3 add partition table_list3_p3 values ((15, 'a'), (16,'default'), (17,'NULL'), (18,NULL)); + +alter table table_list3 add partition table_list3_p4 values (default); + +CREATE TABLE range_range_sales +( + product_id INT4 NOT NULL, + customer_id INT4 PRIMARY KEY, + time_id DATE, + channel_id CHAR(1), + type_id INT4, + quantity_sold NUMERIC(3), + amount_sold NUMERIC(10,2) +) +PARTITION BY RANGE (customer_id) SUBPARTITION BY RANGE (time_id) +( + PARTITION customer1 VALUES LESS THAN (200) + ( + SUBPARTITION customer1_2008 VALUES LESS THAN ('2009-01-01'), + SUBPARTITION customer1_2009 VALUES LESS THAN ('2010-01-01'), + SUBPARTITION customer1_2010 VALUES LESS THAN ('2011-01-01'), + SUBPARTITION customer1_2011 VALUES LESS THAN ('2012-01-01') + ), + PARTITION customer2 VALUES LESS THAN (500) + ( + SUBPARTITION customer2_2008 VALUES LESS THAN ('2009-01-01'), + SUBPARTITION customer2_2009 VALUES LESS THAN ('2010-01-01'), + SUBPARTITION customer2_2010 VALUES LESS THAN ('2011-01-01'), + SUBPARTITION customer2_2011 VALUES LESS THAN ('2012-01-01') + ), + PARTITION customer3 VALUES LESS THAN (800), + PARTITION customer4 VALUES LESS THAN (1200) + ( + SUBPARTITION customer4_all VALUES LESS THAN ('2012-01-01') + ) +); + +INSERT INTO range_range_sales SELECT generate_series(1,1000), + generate_series(1,1000), + date_pli('2008-01-01', generate_series(1,1000)), + generate_series(1,1000)%10, + generate_series(1,1000)%10, + generate_series(1,1000)%1000, + generate_series(1,1000); +CREATE INDEX range_range_sales_idx ON range_range_sales(product_id) LOCAL; +ALTER TABLE range_range_sales ADD PARTITION customer5 VALUES LESS THAN (1500) + ( + SUBPARTITION customer5_2008 VALUES LESS THAN ('2009-01-01'), + SUBPARTITION customer5_2009 VALUES LESS THAN ('2010-01-01'), + SUBPARTITION customer5_2010 VALUES LESS THAN ('2011-01-01'), + SUBPARTITION customer5_2011 VALUES LESS THAN ('2012-01-01') + ); +ALTER TABLE range_range_sales MODIFY PARTITION customer1 ADD SUBPARTITION customer1_2012 VALUES LESS THAN ('2013-01-01'); + +CREATE TABLE range2_sales +( + product_id INT4 NOT NULL, + customer_id INT4 PRIMARY KEY, + time_id DATE, + channel_id CHAR(1), + type_id INT4, + quantity_sold NUMERIC(3), + amount_sold NUMERIC(10,2) +) +PARTITION BY RANGE (time_id, product_id) +( + PARTITION time_2008 VALUES LESS THAN ('2009-01-01', 200), + PARTITION time_2009 VALUES LESS THAN ('2010-01-01', 500), + PARTITION time_2010 VALUES LESS THAN ('2011-01-01', 800), + PARTITION time_2011 VALUES LESS THAN ('2012-01-01', 1200) +); + +INSERT INTO range2_sales SELECT generate_series(1,1000), + generate_series(1,1000), + date_pli('2008-01-01', generate_series(1,1000)), + generate_series(1,1000)%10, + generate_series(1,1000)%10, + generate_series(1,1000)%1000, + generate_series(1,1000); +CREATE INDEX range2_sales_idx ON range2_sales(product_id) LOCAL; + +ALTER TABLE range2_sales TRUNCATE PARTITION time_2008; +ALTER TABLE range2_sales TRUNCATE PARTITION FOR VALUES('2011-04-01', 700) ; + +ALTER TABLE range2_sales DROP PARTITION time_2009; +ALTER TABLE range2_sales DROP PARTITION FOR ('2011-06-01', 600); + +CREATE TABLE range_list_sales +( + product_id INT4 NOT NULL, + customer_id INT4 PRIMARY KEY, + time_id DATE, + channel_id CHAR(100), + type_id INT4, + quantity_sold NUMERIC(3), + amount_sold NUMERIC(10,2) +) +PARTITION BY RANGE (customer_id) SUBPARTITION BY LIST (channel_id) +( + PARTITION customer1 VALUES LESS THAN (200) + ( + SUBPARTITION customer1_channel1 VALUES ('0', '1', '2'), + SUBPARTITION customer1_channel2 VALUES ('3', '4', '5'), + SUBPARTITION customer1_channel3 VALUES ('6', '7', '8'), + SUBPARTITION customer1_channel4 VALUES ('9') + ), + PARTITION customer2 VALUES LESS THAN (500) + ( + SUBPARTITION customer2_channel1 VALUES ('0', '1', '2', '3', '4'), + SUBPARTITION customer2_channel2 VALUES (DEFAULT) + ), + PARTITION customer3 VALUES LESS THAN (800), + PARTITION customer4 VALUES LESS THAN (1200) + ( + SUBPARTITION customer4_channel1 VALUES ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9') + ) +); + +INSERT INTO range_list_sales SELECT generate_series(1,1000), + generate_series(1,1000), + date_pli('2008-01-01', generate_series(1,1000)), + generate_series(1,1000)%10, + generate_series(1,1000)%10, + generate_series(1,1000)%1000, + generate_series(1,1000); +CREATE INDEX range_list_sales_idx ON range_list_sales(product_id) LOCAL; +ALTER TABLE range_list_sales ADD PARTITION customer5 VALUES LESS THAN (1500) + ( + SUBPARTITION customer5_channel1 VALUES ('0', '1', '2'), + SUBPARTITION customer5_channel2 VALUES ('3', '4', '5'), + SUBPARTITION customer5_channel3 VALUES ('6', '7', '8'), + SUBPARTITION customer5_channel4 VALUES ('9') + ); +ALTER TABLE range_list_sales MODIFY PARTITION customer1 ADD SUBPARTITION customer1_channel5 VALUES ('X', 'A', 'bbb'); +ALTER TABLE range_list_sales MODIFY PARTITION customer1 ADD SUBPARTITION customer1_channel6 VALUES ('NULL', 'asdasd', 'hahaha'); +ALTER TABLE range_list_sales MODIFY PARTITION customer1 ADD SUBPARTITION customer1_channel7 VALUES (NULL); +ALTER TABLE range_list_sales MODIFY PARTITION customer1 ADD SUBPARTITION customer1_channel8 VALUES ('DEFAULT', 'wawawa'); +ALTER TABLE range_list_sales MODIFY PARTITION customer1 ADD SUBPARTITION customer1_channel9 VALUES (DEFAULT); +ALTER TABLE range_list_sales DROP SUBPARTITION customer1_channel9; + +ALTER TABLE range_list_sales SPLIT partition customer4 INTO ( + partition customer4_p1 values less than (900) + ( + subpartition customer4_p1_s1 VALUES ('11'), + subpartition customer4_p1_s2 VALUES ('12') + ), + partition customer4_p2 values less than (1000) + ( + subpartition customer4_p2_s1 VALUES ('11'), + subpartition customer4_p2_s2 VALUES ('12') + ) +); + +ALTER TABLE range_list_sales truncate partition customer2 update global index; +ALTER TABLE range_list_sales truncate partition for (300); +ALTER TABLE range_list_sales truncate partition customer5_channel3; + +ALTER TABLE range_list_sales DROP PARTITION customer2; +ALTER TABLE range_list_sales DROP SUBPARTITION customer1_channel1; + + +create table test_list (col1 int, col2 int) +partition by list(col1) +( +partition p1 values (2000), +partition p2 values (3000), +partition p3 values (4000), +partition p4 values (5000) +); + +INSERT INTO test_list VALUES(2000, 2000); +INSERT INTO test_list VALUES(3000, 3000); +alter table test_list add partition p5 values (6000); +INSERT INTO test_list VALUES(6000, 6000); + +create table t1 (col1 int, col2 int); + +alter table test_list exchange partition (p1) with table t1 VERBOSE; +alter table test_list truncate partition p2; +alter table test_list drop partition p5; + + +create table test_hash (col1 int, col2 int) +partition by hash(col1) +( +partition p1, +partition p2 +); + +INSERT INTO test_hash VALUES(1, 1); +INSERT INTO test_hash VALUES(2, 2); +INSERT INTO test_hash VALUES(3, 3); +INSERT INTO test_hash VALUES(4, 4); + +alter table test_hash exchange partition (p1) with table t1 WITHOUT VALIDATION; + +alter table test_hash truncate partition p2; + + +CREATE TABLE interval_sales +( + prod_id NUMBER(6), + cust_id NUMBER, + time_id DATE, + channel_id CHAR(1), + promo_id NUMBER(6), + quantity_sold NUMBER(3), + amount_sold NUMBER(10, 2) +) + PARTITION BY RANGE (time_id) + INTERVAL + ('1 MONTH') +( + PARTITION p0 VALUES LESS THAN (TO_DATE('1-1-2008', 'DD-MM-YYYY')), + PARTITION p1 VALUES LESS THAN (TO_DATE('6-5-2008', 'DD-MM-YYYY')) +); + +alter table interval_sales split partition p0 at (to_date('2007-02-10', 'YYYY-MM-DD')) into (partition p0_1, partition p0_2); + +alter table interval_sales split partition p0_1 into (partition p0_1_1 values less than (TO_DATE('1-1-2005', 'DD-MM-YYYY')), partition p0_1_2 values less than(TO_DATE('1-1-2006', 'DD-MM-YYYY')) ); + +alter table interval_sales split partition p0_2 into (partition p0_2_1 START (TO_DATE('8-5-2007', 'DD-MM-YYYY'), partition p0_2_2 START (TO_DATE('9-5-2007', 'DD-MM-YYYY')); + + +insert into interval_sales +values (1, 1, to_date('9-2-2007', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales +values (1, 1, to_date('11-2-2007', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales +values (1, 1, to_date('11-2-2008', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales +values (1, 1, to_date('20-2-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales +values (1, 1, to_date('05-2-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales +values (1, 1, to_date('08-2-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales +values (1, 1, to_date('05-4-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales +values (1, 1, to_date('05-8-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales +values (1, 1, to_date('04-8-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales +values (1, 1, to_date('04-9-2008', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales +values (1, 1, to_date('04-11-2008', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales +values (1, 1, to_date('04-12-2008', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales +values (1, 1, to_date('04-01-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales +values (1, 1, to_date('04-5-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales +values (1, 1, to_date('04-6-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales +values (1, 1, to_date('04-7-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales +values (1, 1, to_date('04-8-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales +values (1, 1, to_date('04-9-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); + +alter table interval_sales merge partitions p0_1, p0_2, p1 into partition p01; +alter table interval_sales merge partitions sys_p6, sys_p7, sys_p8 into partition sys_p6_p7_p8; +ALTER TABLE interval_sales RESET PARTITION; + +CREATE TABLE interval_sales1 +( + prod_id NUMBER(6), + cust_id NUMBER, + time_id DATE, + channel_id CHAR(1), + promo_id NUMBER(6), + quantity_sold NUMBER(3), + amount_sold NUMBER(10, 2) +) + PARTITION BY RANGE (time_id) + INTERVAL +('1 MONTH') +(PARTITION p0 VALUES LESS THAN (TO_DATE('1-1-2008', 'DD-MM-YYYY')), + PARTITION p1 VALUES LESS THAN (TO_DATE('6-5-2008', 'DD-MM-YYYY')) +); +create index interval_sales1_time_id_idx on interval_sales1 (time_id) local; +create index interval_sales1_quantity_sold_idx on interval_sales1 (quantity_sold) local; +alter table interval_sales1 split partition p0 at (to_date('2007-02-10', 'YYYY-MM-DD')) into (partition p0_1, partition p0_2); + +insert into interval_sales1 +values (1, 1, to_date('9-2-2007', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales1 +values (1, 1, to_date('11-2-2007', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales1 +values (1, 1, to_date('11-2-2008', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales1 +values (1, 1, to_date('20-2-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales1 +values (1, 1, to_date('05-2-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales1 +values (1, 1, to_date('08-2-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales1 +values (1, 1, to_date('05-4-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales1 +values (1, 1, to_date('05-8-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales1 +values (1, 1, to_date('04-8-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales1 +values (1, 1, to_date('04-9-2008', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales1 +values (1, 1, to_date('04-11-2008', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales1 +values (1, 1, to_date('04-12-2008', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales1 +values (1, 1, to_date('04-01-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales1 +values (1, 1, to_date('04-5-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales1 +values (1, 1, to_date('04-6-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales1 +values (1, 1, to_date('04-7-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales1 +values (1, 1, to_date('04-8-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales1 +values (1, 1, to_date('04-9-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); + +alter table interval_sales1 merge partitions p0_1, p0_2, p1 into partition p01 UPDATE GLOBAL INDEX; + + +CREATE TABLE range_range +( + month_code VARCHAR2 ( 30 ) NOT NULL , + dept_code VARCHAR2 ( 30 ) NOT NULL , + user_no VARCHAR2 ( 30 ) NOT NULL , + sales_amt int +) +PARTITION BY RANGE (month_code) SUBPARTITION BY RANGE (dept_code) +( + PARTITION p_201901 VALUES LESS THAN( '201903' ) + ( + SUBPARTITION p_201901_a VALUES LESS THAN( '2' ), + SUBPARTITION p_201901_b VALUES LESS THAN( MAXVALUE ) + ), + PARTITION p_201902 VALUES LESS THAN( '201904' ) + ( + SUBPARTITION p_201902_a VALUES LESS THAN( '2' ), + SUBPARTITION p_201902_b VALUES LESS THAN( '6' ) + ) +); +insert into range_range values('201902', '1', '1', 1); +insert into range_range values('201902', '2', '1', 1); +insert into range_range values('201902', '3', '1', 1); +insert into range_range values('201903', '1', '1', 1); +insert into range_range values('201903', '2', '1', 1); +insert into range_range values('201903', '5', '1', 1); + +alter table range_range split subpartition p_201901_b at (3) into +( + subpartition p_201901_c, + subpartition p_201901_d +); + +alter table range_range split subpartition p_201902_b at (3) into +( + subpartition p_201902_c, + subpartition p_201902_d +); + +CREATE TABLE list_list +( + month_code VARCHAR2 ( 30 ) NOT NULL , + dept_code VARCHAR2 ( 30 ) NOT NULL , + user_no VARCHAR2 ( 30 ) NOT NULL , + sales_amt int +) +PARTITION BY LIST (month_code) SUBPARTITION BY LIST (dept_code) +( + PARTITION p_201901 VALUES ( '201902' ) + ( + SUBPARTITION p_201901_a VALUES ( '1' ), + SUBPARTITION p_201901_b VALUES ( default ) + ), + PARTITION p_201902 VALUES ( '201903' ) + ( + SUBPARTITION p_201902_a VALUES ( '1' ), + SUBPARTITION p_201902_b VALUES ( default ) + ) +); +insert into list_list values('201902', '1', '1', 1); +insert into list_list values('201902', '2', '1', 1); +insert into list_list values('201902', '1', '1', 1); +insert into list_list values('201903', '1', '1', 1); +insert into list_list values('201903', '2', '1', 1); +insert into list_list values('201903', '3', '1', 1); + +alter table list_list split subpartition p_201901_b values (2) into +( + subpartition p_201901_b, + subpartition p_201901_c +); + +alter table list_list split subpartition p_201902_b values (2, 3) into +( + subpartition p_201902_b, + subpartition p_201902_c +); + + +CREATE TABLE range_sales +( + product_id INT4 NOT NULL, + customer_id INT4 PRIMARY KEY, + time_id DATE, + channel_id CHAR(1), + type_id INT4, + quantity_sold NUMERIC(3), + amount_sold NUMERIC(10,2) +) +PARTITION BY RANGE (time_id) +( + PARTITION time_2008 VALUES LESS THAN ('2009-01-01'), + PARTITION time_2009 VALUES LESS THAN ('2010-01-01'), + PARTITION time_2010 VALUES LESS THAN ('2011-01-01'), + PARTITION time_2011 VALUES LESS THAN ('2012-01-01') +); +CREATE INDEX range_sales_idx1 ON range_sales(product_id) LOCAL; +CREATE INDEX range_sales_idx2 ON range_sales(time_id) GLOBAL; +EXECUTE partition_get_partitionno('range_sales'); +ALTER TABLE range_sales ADD PARTITION time_default VALUES LESS THAN (MAXVALUE); +ALTER TABLE range_sales DROP PARTITION time_2008; +ALTER TABLE range_sales SPLIT PARTITION time_default AT ('2013-01-01') INTO (PARTITION time_2012, PARTITION time_default_temp); +ALTER TABLE range_sales RENAME PARTITION time_default_temp TO time_default; +ALTER TABLE range_sales MERGE PARTITIONS time_2009, time_2010 INTO PARTITION time_2010_old UPDATE GLOBAL INDEX; +ALTER TABLE range_sales TRUNCATE PARTITION time_2011 UPDATE GLOBAL INDEX; +ALTER TABLE range_sales disable row movement; +ALTER TABLE range_sales enable row movement; + +CREATE TABLE interval_sales2 +( + product_id INT4 NOT NULL, + customer_id INT4 PRIMARY KEY, + time_id DATE, + channel_id CHAR(1), + type_id INT4, + quantity_sold NUMERIC(3), + amount_sold NUMERIC(10,2)DEFAULT CHARACTER SET +) +PARTITION BY RANGE (time_id) INTERVAL ('1 year') +( + PARTITION time_2008 VALUES LESS THAN ('2009-01-01'), + PARTITION time_2009 VALUES LESS THAN ('2010-01-01'), + PARTITION time_2010 VALUES LESS THAN ('2011-01-01') +); +CREATE INDEX interval_sales2_idx1 ON interval_sales2(product_id) LOCAL; +CREATE INDEX interval_sales2_idx2 ON interval_sales2(time_id) GLOBAL; + +-- add/drop partition +INSERT INTO interval_sales2 VALUES (1,1,'2013-01-01','A',1,1,1); +INSERT INTO interval_sales2 VALUES (2,2,'2012-01-01','B',2,2,2); +ALTER TABLE interval_sales2 DROP PARTITION time_2008; + + +-- merge/split partition +ALTER TABLE interval_sales2 SPLIT PARTITION time_2009 AT ('2009-01-01') INTO (PARTITION time_2008, PARTITION time_2009_temp); +ALTER TABLE interval_sales2 RENAME PARTITION time_2009_temp TO time_2009; +ALTER TABLE interval_sales2 MERGE PARTITIONS time_2009, time_2010 INTO PARTITION time_2010_old UPDATE GLOBAL INDEX; + + +-- truncate partition with gpi +ALTER TABLE interval_sales2 TRUNCATE PARTITION time_2008 UPDATE GLOBAL INDEX; + + +--reset +ALTER TABLE interval_sales2 RESET PARTITION; +ALTER TABLE interval_sales2 disable row movement; + +create table unit_varchar(a1 varchar default '1', a2 varchar(2), a3 varchar(2 byte) default 'ye', a4 varchar(2 character) default '你好', a5 varchar(2 char) default '默认'); +create table unit_varchar2(a1 varchar2 default '1', a2 varchar2(2) default 'ha', a3 varchar2(2 byte), a4 varchar2(2 character) default '你好', a5 varchar2(2 char) default '默认'); +create table unit_char(a1 char default '1', a2 char(2) default 'ha', a3 char(2 byte) default 'ye', a4 char(2 character), a5 char(2 char) default '默认'); +create table unit_nchar(a1 nchar default '1', a2 nchar(2) default 'ha', a3 nchar(2) default 'ye', a4 nchar(2) default '你好', a5 nchar(2)); +create table unit_nvarchar2(a1 nvarchar2 default '1', a2 nvarchar2(2) default 'ha', a3 nvarchar2(2) default 'ye', a4 nvarchar2(2) default '你好', a5 nvarchar2(2)); + +insert into unit_varchar (a1) values ('1111111111123大苏打撒旦11111111111111111111111111111111阿三大苏打实打实1'); +insert into unit_varchar (a2) values ('12 '); +-- exceed +insert into unit_varchar (a2) values ('啊'); +insert into unit_varchar (a3) values ('12 '); +-- exceed +insert into unit_varchar (a3) values ('啊'); +insert into unit_varchar (a4) values ('啊2 '); +-- exceed +insert into unit_varchar (a4) values ('啊23 '); +-- exceed +insert into unit_varchar (a4) values ('223 '); +insert into unit_varchar (a5) values ('啊2 '); +-- exceed +insert into unit_varchar (a5) values ('啊23 '); +-- exceed +insert into unit_varchar (a5) values ('223 '); +-- exceed +update unit_varchar set a2='啊 '; +update unit_varchar set a3='啊a '; +-- exceed +update unit_varchar set a5='啊啊啊'; +update unit_varchar set a5='啊啊'; +select * from unit_varchar; + +insert into unit_varchar2 (a1) values ('啊111111111123大苏打撒旦11111111111111111111111111111111阿三大苏打实打实1'); +insert into unit_varchar2 (a2) values ('12 '); +-- exceed +insert into unit_varchar2 (a2) values ('啊'); +insert into unit_varchar2 (a3) values ('12 '); +-- exceed +insert into unit_varchar2 (a3) values ('啊'); +insert into unit_varchar2 (a4) values ('啊2 '); +-- exceed +insert into unit_varchar2 (a4) values ('啊23 '); +-- exceed +insert into unit_varchar2 (a4) values ('223 '); +insert into unit_varchar2 (a5) values ('啊2 '); +-- exceed +insert into unit_varchar2 (a5) values ('啊23 '); +-- exceed +insert into unit_varchar2 (a5) values ('223 '); +ALTER TABLE unit_varchar2 ALTER COLUMN a2 SET data TYPE char(1 char) USING a2::char(1 char); +insert into unit_varchar2 (a2) values ('一 '); +alter table unit_varchar2 modify column a3 varchar2(2 char) default '黑黑'; +-- exceed +insert into unit_varchar2 (a2) values ('一e'); +insert into unit_varchar2 (a1) values(default); +select * from unit_varchar2; + +-- exceed +insert into unit_char (a1) values ('1111111111123大苏打撒旦11111111111111111111111111111111阿三大苏打实打实1'); +-- exceed +insert into unit_nchar (a1) values ('啊 '); +insert into unit_nchar (a1) values ('1 '); +insert into unit_char (a2) values ('12 '); +-- exceed +insert into unit_char (a2) values ('啊'); +insert into unit_char (a3) values ('12 '); +-- exceed +insert into unit_char (a3) values ('啊'); +insert into unit_char (a4) values ('啊2 '); +-- exceed +insert into unit_char (a4) values ('啊23 '); +-- exceed +insert into unit_char (a4) values ('223 '); +insert into unit_char (a5) values ('啊2 '); +-- exceed +insert into unit_char (a5) values ('啊23 '); +-- exceed +insert into unit_char (a5) values ('223 '); +ALTER table unit_char ADD COLUMN a6 varchar(3 char) default '默认值'; +insert into unit_char (a6) values ('啊1a '); +-- exceed +insert into unit_char (a6) values ('1234'); +update unit_char set a4='啊'; +-- execeed +update unit_char set a5='一二3'; +select * from unit_char; + +-- exceed +insert into unit_nchar (a1) values ('1111111111123大苏打撒旦11111111111111111111111111111111阿三大苏打实打实1'); +insert into unit_nchar (a1) values ('啊 '); +insert into unit_nchar (a2) values ('啊啊 '); +-- exceed +insert into unit_nchar (a2) values ('123 '); +-- exceed +insert into unit_nchar (a2) values ('啊'); +insert into unit_nchar (a3) values ('12 '); +insert into unit_nchar (a3) values ('啊'); +insert into unit_nchar (a4) values ('啊2 '); +-- exceed +insert into unit_nchar (a4) values ('啊23 '); +-- exceed +insert into unit_nchar (a4) values ('223 '); +insert into unit_nchar (a5) values ('啊2 '); +-- exceed +insert into unit_nchar (a5) values ('啊23 '); +-- exceed +insert into unit_nchar (a5) values ('223 '); + +-- exceed +insert into unit_nvarchar2 (a1) values ('1111111111123大苏打撒旦11111111111111111111111111111111阿三大苏打实打实1'); +insert into unit_nvarchar2 (a1) values ('啊 '); +insert into unit_nvarchar2 (a2) values ('啊啊 '); +-- exceed +insert into unit_nvarchar2 (a2) values ('123 '); +-- exceed +insert into unit_nvarchar2 (a2) values ('啊'); +insert into unit_nvarchar2 (a3) values ('12 '); +insert into unit_nvarchar2 (a3) values ('啊'); +insert into unit_nvarchar2 (a4) values ('啊2 '); +insert into unit_nvarchar2 (a5) values ('啊2 '); +-- exceed +insert into unit_nvarchar2 (a5) values ('啊23 '); +-- exceed +insert into unit_nvarchar2 (a5) values ('223 '); + + + +create table test_char(col char(20 char)); +insert into test_char values ('这是一个测试'), ('asd一二三四五bsd'), ('一二三四五六七八九十一二三四五六七八九十 '), ('一2 '); +select col, length(col), lengthb(col) from test_char; + +create table test_varchar(col varchar(20 char)); +insert into test_varchar values ('这是一个测试'), ('asd一二三四五bsd'), ('一二三四五六七八九十一二三四五六七八九十 '), ('一2 '); +select col, length(col), lengthb(col) from test_varchar; + +create table test_charb(col char(20)); +insert into test_charb values ('这是一个测试'), ('asd一二三四五bs '), ('一二三四五六 '), ('一2 '); +select col, length(col), lengthb(col) from test_charb; + +create table test_varcharb(col varchar(20)); +insert into test_varcharb values ('这是一个测试'), ('asd一二三四五bs '), ('一二三四五六 '), ('一2 '); +select col, length(col), lengthb(col) from test_varcharb; \ No newline at end of file diff --git a/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_002.sql b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_002.sql new file mode 100644 index 000000000..53940da92 --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_002.sql @@ -0,0 +1,2011 @@ +-- +--FOR BLACKLIST FEATURE: REFERENCES/INHERITS/WITH OIDS/RULE/CREATE TYPE/DOMAIN is not supported. +-- + +-- +-- ALTER_TABLE +-- add attribute +-- + +CREATE TABLE atmp1 (initial int4); + +COMMENT ON TABLE tmp_wrong IS 'table comment'; +COMMENT ON TABLE atmp1 IS 'table comment'; +COMMENT ON TABLE atmp1 IS NULL; + +ALTER TABLE atmp1 ADD COLUMN xmin integer; -- fails + +ALTER TABLE atmp1 ADD COLUMN a int4 default 3; + +ALTER TABLE atmp1 ADD COLUMN b name; + +ALTER TABLE atmp1 ADD COLUMN c text; + +ALTER TABLE atmp1 ADD COLUMN d float8; + +ALTER TABLE atmp1 ADD COLUMN e float4; + +ALTER TABLE atmp1 ADD COLUMN f int2; + +ALTER TABLE atmp1 ADD COLUMN g polygon; + +ALTER TABLE atmp1 ADD COLUMN h abstime; + +ALTER TABLE atmp1 ADD COLUMN i char; + +ALTER TABLE atmp1 ADD COLUMN j abstime[]; + +ALTER TABLE atmp1 ADD COLUMN k int4; + +ALTER TABLE atmp1 ADD COLUMN l tid; + +ALTER TABLE atmp1 ADD COLUMN m xid; + +ALTER TABLE atmp1 ADD COLUMN n oidvector; + +--ALTER TABLE atmp1 ADD COLUMN o lock; +ALTER TABLE atmp1 ADD COLUMN p smgr; + +ALTER TABLE atmp1 ADD COLUMN q point; + +ALTER TABLE atmp1 ADD COLUMN r lseg; + +ALTER TABLE atmp1 ADD COLUMN s path; + +ALTER TABLE atmp1 ADD COLUMN t box; + +ALTER TABLE atmp1 ADD COLUMN u tinterval; + +ALTER TABLE atmp1 ADD COLUMN v timestamp; + +ALTER TABLE atmp1 ADD COLUMN w interval; + +ALTER TABLE atmp1 ADD COLUMN x float8[]; + +ALTER TABLE atmp1 ADD COLUMN y float4[]; + +ALTER TABLE atmp1 ADD COLUMN z int2[]; + +INSERT INTO atmp1 (a, b, c, d, e, f, g, h, i, j, k, l, m, n, p, q, r, s, t, u, + v, w, x, y, z) + VALUES (4, 'name', 'text', 4.1, 4.1, 2, '(4.1,4.1,3.1,3.1)', + 'Mon May 1 00:30:30 1995', 'c', '{Mon May 1 00:30:30 1995, Monday Aug 24 14:43:07 1992, epoch}', + 314159, '(1,1)', '512', + '1 2 3 4 5 6 7 8', 'magnetic disk', '(1.1,1.1)', '(4.1,4.1,3.1,3.1)', + '(0,2,4.1,4.1,3.1,3.1)', '(4.1,4.1,3.1,3.1)', '["epoch" "infinity"]', + 'epoch', '01:00:10', '{1.0,2.0,3.0,4.0}', '{1.0,2.0,3.0,4.0}', '{1,2,3,4}'); + +SELECT * FROM atmp1; + +----drop table tmp; + +-- the wolf bug - schema mods caused inconsistent row descriptors +CREATE TABLE atmp2 ( + initial int4 +); + +ALTER TABLE atmp2 ADD COLUMN a int4; + +ALTER TABLE atmp2 ADD COLUMN b name; + +ALTER TABLE atmp2 ADD COLUMN c text; + +ALTER TABLE atmp2 ADD COLUMN d float8; + +ALTER TABLE atmp2 ADD COLUMN e float4; + +ALTER TABLE atmp2 ADD COLUMN f int2; + +ALTER TABLE atmp2 ADD COLUMN g polygon; + +ALTER TABLE atmp2 ADD COLUMN h abstime; + +ALTER TABLE atmp2 ADD COLUMN i char; + +ALTER TABLE atmp2 ADD COLUMN j abstime[]; + +ALTER TABLE atmp2 ADD COLUMN k int4; + +ALTER TABLE atmp2 ADD COLUMN l tid; + +ALTER TABLE atmp2 ADD COLUMN m xid; + +ALTER TABLE atmp2 ADD COLUMN n oidvector; + +--ALTER TABLE atmp2 ADD COLUMN o lock; +ALTER TABLE atmp2 ADD COLUMN p smgr; + +ALTER TABLE atmp2 ADD COLUMN q point; + +ALTER TABLE atmp2 ADD COLUMN r lseg; + +ALTER TABLE atmp2 ADD COLUMN s path; + +ALTER TABLE atmp2 ADD COLUMN t box; + +ALTER TABLE atmp2 ADD COLUMN u tinterval; + +ALTER TABLE atmp2 ADD COLUMN v timestamp; + +ALTER TABLE atmp2 ADD COLUMN w interval; + +ALTER TABLE atmp2 ADD COLUMN x float8[]; + +ALTER TABLE atmp2 ADD COLUMN y float4[]; + +ALTER TABLE atmp2 ADD COLUMN z int2[]; + +INSERT INTO atmp2 (a, b, c, d, e, f, g, h, i, j, k, l, m, n, p, q, r, s, t, u, + v, w, x, y, z) + VALUES (4, 'name', 'text', 4.1, 4.1, 2, '(4.1,4.1,3.1,3.1)', + 'Mon May 1 00:30:30 1995', 'c', '{Mon May 1 00:30:30 1995, Monday Aug 24 14:43:07 1992, epoch}', + 314159, '(1,1)', '512', + '1 2 3 4 5 6 7 8', 'magnetic disk', '(1.1,1.1)', '(4.1,4.1,3.1,3.1)', + '(0,2,4.1,4.1,3.1,3.1)', '(4.1,4.1,3.1,3.1)', '["epoch" "infinity"]', + 'epoch', '01:00:10', '{1.0,2.0,3.0,4.0}', '{1.0,2.0,3.0,4.0}', '{1,2,3,4}'); + +SELECT * FROM atmp2; + +----drop table tmp; + + +-- +-- rename - check on both non-temp and temp tables +-- +CREATE TABLE atmp3 (regtable int); +-- Enforce use of COMMIT instead of 2PC for temporary objects +\set VERBOSITY verbose +-- CREATE TEMP TABLE tmp (tmptable int); + +ALTER TABLE atmp3 RENAME TO tmp_new; + +-- SELECT * FROM tmp; +-- SELECT * FROM tmp_new; + +-- ALTER TABLE tmp RENAME TO tmp_new2; + +SELECT * FROM tmp_new; +-- SELECT * FROM tmp_new2; + +----drop table tmp_new; +-- ----drop table tmp_new2; +CREATE TABLE atmp4 (ch1 character(1)); +insert into atmp4 values ('asdv'); +----drop table tmp; +\set VERBOSITY default + + +CREATE TABLE onek ( + unique1 int4, + unique2 int4, + two int4, + four int4, + ten int4, + twenty int4, + hundred int4, + thousand int4, + twothousand int4, + fivethous int4, + tenthous int4, + odd int4, + even int4, + stringu1 name, + stringu2 name, + string4 name +) with(autovacuum_enabled = off); +CREATE INDEX onek_unique1 ON onek USING btree(unique1 int4_ops); + +CREATE TABLE tenk1 ( + unique1 int4, + unique2 int4, + two int4, + four int4, + ten int4, + twenty int4, + hundred int4, + thousand int4, + twothousand int4, + fivethous int4, + tenthous int4, + odd int4, + even int4, + stringu1 name, + stringu2 name, + string4 name +) with(autovacuum_enabled = off); + +CREATE TABLE stud_emp ( + name text, + age int4, + location point, + salary int4, + manager name, + gpa float8, + percent int4 +) with(autovacuum_enabled = off); + +-- ALTER TABLE ... RENAME on non-table relations +-- renaming indexes (FIXME: this should probably test the index's functionality) +ALTER INDEX IF EXISTS __onek_unique1 RENAME TO tmp_onek_unique1; +ALTER INDEX IF EXISTS __tmp_onek_unique1 RENAME TO onek_unique1; + +ALTER INDEX onek_unique1 RENAME TO tmp_onek_unique1; +ALTER INDEX tmp_onek_unique1 RENAME TO onek_unique1; + +-- renaming views +CREATE VIEW tmp_view (unique1) AS SELECT unique1 FROM tenk1; +ALTER TABLE tmp_view RENAME TO tmp_view_new; + +-- hack to ensure we get an indexscan here +ANALYZE tenk1; +set enable_seqscan to off; +set enable_bitmapscan to off; +-- 5 values, sorted +SELECT unique1 FROM tenk1 WHERE unique1 < 5 ORDER BY unique1; +reset enable_seqscan; +reset enable_bitmapscan; + +DROP VIEW tmp_view_new; +-- toast-like relation name +alter table stud_emp rename to pg_toast_stud_emp; +alter table pg_toast_stud_emp rename to stud_emp; + +-- renaming index should rename constraint as well +ALTER TABLE onek ADD CONSTRAINT onek_unique1_constraint UNIQUE (unique1); +ALTER INDEX onek_unique1_constraint RENAME TO onek_unique1_constraint_foo; +ALTER TABLE onek DROP CONSTRAINT onek_unique1_constraint_foo; + +-- renaming constraint +ALTER TABLE onek ADD CONSTRAINT onek_check_constraint CHECK (unique1 >= 0); +ALTER TABLE onek RENAME CONSTRAINT onek_check_constraint TO onek_check_constraint_foo; +ALTER TABLE onek DROP CONSTRAINT onek_check_constraint_foo; + +-- renaming constraint should rename index as well +ALTER TABLE onek ADD CONSTRAINT onek_unique1_constraint UNIQUE (unique1); +DROP INDEX onek_unique1_constraint; -- to see whether it's there +ALTER TABLE onek RENAME CONSTRAINT onek_unique1_constraint TO onek_unique1_constraint_foo; +DROP INDEX onek_unique1_constraint_foo; -- to see whether it's there +ALTER TABLE onek DROP CONSTRAINT onek_unique1_constraint_foo; + +-- renaming constraints vs. inheritance +CREATE TABLE constraint_rename_test (a int CONSTRAINT con1 CHECK (a > 0), b int, c int); +\d constraint_rename_test +CREATE TABLE constraint_rename_test2 (a int CONSTRAINT con1 CHECK (a > 0), d int) INHERITS (constraint_rename_test); +create table constraint_rename_test2 (like constraint_rename_test ); +\d constraint_rename_test2 +ALTER TABLE constraint_rename_test2 RENAME CONSTRAINT con1 TO con1foo; -- fail +ALTER TABLE ONLY constraint_rename_test RENAME CONSTRAINT con1 TO con1foo; -- fail +ALTER TABLE constraint_rename_test RENAME CONSTRAINT con1 TO con1foo; -- ok +\d constraint_rename_test +\d constraint_rename_test2 +ALTER TABLE constraint_rename_test ADD CONSTRAINT con2 CHECK (b > 0) NO INHERIT; +ALTER TABLE ONLY constraint_rename_test RENAME CONSTRAINT con2 TO con2foo; -- ok +ALTER TABLE constraint_rename_test RENAME CONSTRAINT con2foo TO con2bar; -- ok +\d constraint_rename_test +\d constraint_rename_test2 +ALTER TABLE constraint_rename_test ADD CONSTRAINT con3 PRIMARY KEY (a); +ALTER TABLE constraint_rename_test RENAME CONSTRAINT con3 TO con3foo; -- ok +\d constraint_rename_test +\d constraint_rename_test2 +----drop table constraint_rename_test2; +----drop table constraint_rename_test; +ALTER TABLE IF EXISTS constraint_rename_test ADD CONSTRAINT con4 UNIQUE (a); + +-- FOREIGN KEY CONSTRAINT adding TEST + +CREATE TABLE tmp2 (a int primary key); + +CREATE TABLE tmp3 (a int, b int); + +CREATE TABLE tmp4 (a int, b int, unique(a,b)); + +CREATE TABLE tmp5 (a int, b int); + +-- Insert rows into tmp2 (pktable) +INSERT INTO tmp2 values (1); +INSERT INTO tmp2 values (2); +INSERT INTO tmp2 values (3); +INSERT INTO tmp2 values (4); + +-- Insert rows into tmp3 +INSERT INTO tmp3 values (1,10); +INSERT INTO tmp3 values (1,20); +INSERT INTO tmp3 values (5,50); + +-- Try (and fail) to add constraint due to invalid source columns +ALTER TABLE tmp3 add constraint tmpconstr foreign key(c) references tmp2 match full; + +-- Try (and fail) to add constraint due to invalide destination columns explicitly given +ALTER TABLE tmp3 add constraint tmpconstr foreign key(a) references tmp2(b) match full; + +-- Try (and fail) to add constraint due to invalid data +ALTER TABLE tmp3 add constraint tmpconstr foreign key (a) references tmp2 match full; + +-- Delete failing row +alter table tmp3 replica identity full; +DELETE FROM tmp3 where a=5; + +-- Try (and succeed) +ALTER TABLE tmp3 add constraint tmpconstr foreign key (a) references tmp2 match full; +ALTER TABLE tmp3 drop constraint tmpconstr; + +INSERT INTO tmp3 values (5,50); + +-- Try NOT VALID and then VALIDATE CONSTRAINT, but fails. Delete failure then re-validate +ALTER TABLE tmp3 add constraint tmpconstr foreign key (a) references tmp2 match full NOT VALID; +ALTER TABLE tmp3 validate constraint tmpconstr; + +-- Delete failing row +DELETE FROM tmp3 where a=5; + +-- Try (and succeed) and repeat to show it works on already valid constraint +ALTER TABLE tmp3 validate constraint tmpconstr; +ALTER TABLE tmp3 validate constraint tmpconstr; + +-- Try a non-verified CHECK constraint +ALTER TABLE tmp3 ADD CONSTRAINT b_greater_than_ten CHECK (b > 10); -- fail +ALTER TABLE tmp3 ADD CONSTRAINT b_greater_than_ten CHECK (b > 10) NOT VALID; -- succeeds +ALTER TABLE tmp3 VALIDATE CONSTRAINT b_greater_than_ten; -- fails +DELETE FROM tmp3 WHERE NOT b > 10; +ALTER TABLE tmp3 VALIDATE CONSTRAINT b_greater_than_ten; -- succeeds +ALTER TABLE tmp3 VALIDATE CONSTRAINT b_greater_than_ten; -- succeeds + +-- Test inherited NOT VALID CHECK constraints +select * from tmp3; + +-- Try (and fail) to create constraint from tmp5(a) to tmp4(a) - unique constraint on +-- tmp4 is a,b + +ALTER TABLE tmp5 add constraint tmpconstr foreign key(a) references tmp4(a) match full; + +----drop table tmp5; + +----drop table tmp4; + +----drop table tmp3; + +----drop table tmp2; + +-- NOT VALID with plan invalidation -- ensure we don't use a constraint for +-- exclusion until validated +set constraint_exclusion TO 'partition'; +create table nv_parent (d date); +create table nv_child_2010 () inherits (nv_parent); +create table nv_child_2010 (like nv_parent); +create table nv_child_2011 () inherits (nv_parent); +create table nv_child_2011 (like nv_parent including all); +alter table nv_child_2010 add check (d between '2010-01-01'::date and '2010-12-31'::date) not valid; +alter table nv_child_2011 add check (d between '2011-01-01'::date and '2011-12-31'::date) not valid; +explain (costs off) select * from nv_parent where d between '2011-08-01' and '2011-08-31'; +create table nv_child_2009 (check (d between '2009-01-01'::date and '2009-12-31'::date)) inherits (nv_parent); +explain (costs off) select * from nv_parent where d between '2011-08-01'::date and '2011-08-31'::date; +explain (costs off) select * from nv_parent where d between '2009-08-01'::date and '2009-08-31'::date; +-- after validation, the constraint should be used +alter table nv_child_2011 VALIDATE CONSTRAINT nv_child_2011_d_check; +explain (costs off) select * from nv_parent where d between '2009-08-01'::date and '2009-08-31'::date; + + +-- Foreign key adding test with mixed types + +-- Note: these tables are TEMP to avoid name conflicts when this test +-- is run in parallel with foreign_key.sql. + +CREATE TABLE PKTABLE (ptest1 int PRIMARY KEY); +INSERT INTO PKTABLE VALUES(42); +CREATE TABLE FKTABLE (ftest1 inet); +-- This next should fail, because int=inet does not exist +ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references pktable; +-- This should also fail for the same reason, but here we +-- give the column name +ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references pktable(ptest1); +----drop table FKTABLE; +-- This should succeed, even though they are different types, +-- because int=int8 exists and is a member of the integer opfamily +CREATE TABLE FKTABLE1 (ftest1 int8); +ALTER TABLE FKTABLE1 ADD FOREIGN KEY(ftest1) references pktable; +-- Check it actually works +INSERT INTO FKTABLE1 VALUES(42); -- should succeed +INSERT INTO FKTABLE1 VALUES(43); -- should fail +----drop table FKTABLE; +-- This should fail, because we'd have to cast numeric to int which is +-- not an implicit coercion (or use numeric=numeric, but that's not part +-- of the integer opfamily) +CREATE TABLE FKTABLE2 (ftest1 numeric); +ALTER TABLE FKTABLE2 ADD FOREIGN KEY(ftest1) references pktable; +----drop table FKTABLE; +----drop table PKTABLE; +-- On the other hand, this should work because int implicitly promotes to +-- numeric, and we allow promotion on the FK side +CREATE TABLE PKTABLE1 (ptest1 numeric PRIMARY KEY); +INSERT INTO PKTABLE1 VALUES(42); +CREATE TABLE FKTABLE3 (ftest1 int); +ALTER TABLE FKTABLE3 ADD FOREIGN KEY(ftest1) references pktable1; +-- Check it actually works +INSERT INTO FKTABLE3 VALUES(42); -- should succeed +INSERT INTO FKTABLE3 VALUES(43); -- should fail +----drop table FKTABLE; +----drop table PKTABLE; + +CREATE TABLE PKTABLE2 (ptest1 int, ptest2 inet, + PRIMARY KEY(ptest1, ptest2)); +-- This should fail, because we just chose really odd types +CREATE TABLE FKTABLE4 (ftest1 cidr, ftest2 timestamp); +ALTER TABLE FKTABLE4 ADD FOREIGN KEY(ftest1, ftest2) references pktable2; +----drop table FKTABLE; +-- Again, so should this... +CREATE TABLE FKTABLE5 (ftest1 cidr, ftest2 timestamp); +ALTER TABLE FKTABLE5 ADD FOREIGN KEY(ftest1, ftest2) + references pktable2(ptest1, ptest2); +----drop table FKTABLE; +-- This fails because we mixed up the column ordering +CREATE TABLE FKTABLE6 (ftest1 int, ftest2 inet); +ALTER TABLE FKTABLE6 ADD FOREIGN KEY(ftest1, ftest2) + references pktable2(ptest2, ptest1); +-- As does this... +ALTER TABLE FKTABLE6 ADD FOREIGN KEY(ftest2, ftest1) + references pktable2(ptest1, ptest2); + +-- temp tables should go away by themselves, need not drop them. + +-- test check constraint adding + +create table at1acc1 ( test int ); +-- add a check constraint +alter table at1acc1 add constraint at1acc_test1 check (test>3); +-- should fail +insert into at1acc1 (test) values (2); +-- should succeed +insert into at1acc1 (test) values (4); +----drop table atacc1; + +-- let's do one where the check fails when added +create table at2acc1 ( test int ); +-- insert a soon to be failing row +insert into at2acc1 (test) values (2); +-- add a check constraint (fails) +alter table at2acc1 add constraint at2acc_test1 check (test>3); +insert into at2acc1 (test) values (4); +----drop table atacc1; + +-- let's do one where the check fails because the column doesn't exist +create table at3acc1 ( test int ); +-- add a check constraint (fails) +alter table at3acc1 add constraint at3acc_test1 check (test1>3); +----drop table atacc1; + +-- something a little more complicated +create table at4acc1 ( test int, test2 int, test3 int); +-- add a check constraint (fails) +alter table at4acc1 add constraint at4acc_test1 check (test+test23), test2 int); +alter table at5acc1 add check (test2>test); +-- should fail for $2 +insert into at5acc1 (test2, test) values (3, 4); +----drop table atacc1; + +-- inheritance related tests +create table at6acc1 (test int); +create table at6acc2 (test2 int); +create table at6acc3 (test3 int) inherits (at6acc1, at6acc2); +alter table at6acc2 add constraint foo check (test2>0); +-- fail and then succeed on atacc2 +insert into at6acc2 (test2) values (-3); +insert into at6acc2 (test2) values (3); +-- fail and then succeed on atacc3 +insert into at6acc3 (test2) values (-3); +insert into at6acc3 (test2) values (3); +----drop table atacc3; +----drop table atacc2; +----drop table atacc1; + +-- same things with one created with INHERIT +create table at7acc1 (test int); +create table at7acc2 (test2 int); +create table at7acc3 (test3 int) inherits (at7acc1, at7acc2); +alter table at7acc3 no inherit at7acc2; +-- fail +alter table at7acc3 no inherit at7acc2; +-- make sure it really isn't a child +insert into at7acc3 (test2) values (3); +select test2 from atacc2; +-- fail due to missing constraint +alter table at7acc2 add constraint foo check (test2>0); +alter table at7acc3 inherit atacc2; +-- fail due to missing column +alter table at7acc3 rename test2 to testx; +alter table at7acc3 inherit atacc2; +-- fail due to mismatched data type +alter table at7acc3 add test2 bool; +alter table at7acc3 inherit atacc2; +alter table at7acc3 drop test2; +-- succeed +alter table at7acc3 add test2 int; +alter table at7acc3 replica identity full; +update at7acc3 set test2 = 4 where test2 is null; +alter table at7acc3 add constraint foo check (test2>0); +alter table at7acc3 inherit at7acc2; +-- fail due to duplicates and circular inheritance +alter table at7acc3 inherit at7acc2; +alter table at7acc2 inherit at7acc3; +alter table at7acc2 inherit at7acc2; +-- test that we really are a child now (should see 4 not 3 and cascade should go through) +select test2 from at7acc2; +----drop table atacc2 cascade; +----drop table atacc1; + +-- adding only to a parent is allowed as of 9.2 + +create table at8acc1 (test int); +create table at8acc2 (test2 int) inherits (at8acc1); +-- ok: +alter table at8acc1 add constraint foo check (test>0) no inherit; +-- check constraint is not there on child +insert into at8acc2 (test) values (-3); +-- check constraint is there on parent +insert into at8acc1 (test) values (-3); +insert into at8acc1 (test) values (3); +-- fail, violating row: +alter table at8acc2 add constraint foo check (test>0) no inherit; +----drop table atacc2; +----drop table atacc1; + +-- test unique constraint adding + +create table at9acc1 ( test int ) with oids; +-- add a unique constraint +alter table at9acc1 add constraint at9acc_test1 unique (test); +-- insert first value +insert into at9acc1 (test) values (2); +-- should fail +insert into at9acc1 (test) values (2); +-- should succeed +insert into at9acc1 (test) values (4); +-- try adding a unique oid constraint +alter table at9acc1 add constraint atacc_oid1 unique(oid); +-- try to create duplicates via alter table using - should fail +alter table at9acc1 alter column test type integer using 0; +----drop table atacc1; + +-- let's do one where the unique constraint fails when added +create table a1tacc1 ( test int ); +-- insert soon to be failing rows +insert into a1tacc1 (test) values (2); +insert into a1tacc1 (test) values (2); +-- add a unique constraint (fails) +alter table a1tacc1 add constraint a1tacc_test1 unique (test); +insert into a1tacc1 (test) values (3); +--drop table atacc1; + +-- let's do one where the unique constraint fails +-- because the column doesn't exist +create table a2tacc1 ( test int ); +-- add a unique constraint (fails) +alter table a2tacc1 add constraint a2tacc_test1 unique (test1); +--drop table atacc1; + +-- something a little more complicated +create table a2tacc1 ( test int, test2 int); +-- add a unique constraint +alter table a2tacc1 add constraint a2tacc_test1 unique (test, test2); +-- insert initial value +insert into a2tacc1 (test,test2) values (4,4); +-- should fail +insert into a2tacc1 (test,test2) values (4,4); +-- should all succeed +insert into a2tacc1 (test,test2) values (4,5); +insert into a2tacc1 (test,test2) values (5,4); +insert into a2tacc1 (test,test2) values (5,5); +--drop table atacc1; + +-- lets do some naming tests +create table a3tacc1 (test int, test2 int, unique(test)); +alter table a3tacc1 add unique (test2); +-- should fail for @@ second one @@ +insert into a3tacc1 (test2, test) values (3, 3); +insert into a3tacc1 (test2, test) values (2, 3); +--drop table atacc1; + +-- test primary key constraint adding + +create table a4tacc1 ( test int ) with oids; +-- add a primary key constraint +alter table a4tacc1 add constraint a4tacc_test1 primary key (test); +-- insert first value +insert into a4tacc1 (test) values (2); +-- should fail +insert into a4tacc1 (test) values (2); +-- should succeed +insert into a4tacc1 (test) values (4); +-- inserting NULL should fail +insert into a4tacc1 (test) values(NULL); +-- try adding a second primary key (should fail) +alter table a4tacc1 add constraint atacc_oid1 primary key(oid); +-- drop first primary key constraint +alter table a4tacc1 drop constraint a4tacc_test1 restrict; +-- try adding a primary key on oid (should succeed) +alter table a4tacc1 add constraint atacc_oid1 primary key(oid); +--drop table a4tacc1; + +-- let's do one where the primary key constraint fails when added +create table a5tacc1 ( test int ); +-- insert soon to be failing rows +insert into a5tacc1 (test) values (2); +insert into a5tacc1 (test) values (2); +-- add a primary key (fails) +alter table a5tacc1 add constraint a5tacc_test1 primary key (test); +insert into a5tacc1 (test) values (3); +--drop table a5tacc1; + +-- let's do another one where the primary key constraint fails when added +create table a6tacc1 ( test int ); +-- insert soon to be failing row +insert into a6tacc1 (test) values (NULL); +-- add a primary key (fails) +alter table a6tacc1 add constraint a6tacc_test1 primary key (test); +insert into a6tacc1 (test) values (3); +--drop table atacc1; + +-- let's do one where the primary key constraint fails +-- because the column doesn't exist +create table a7tacc1 ( test int ); +-- add a primary key constraint (fails) +alter table a7tacc1 add constraint a7tacc_test1 primary key (test1); +--drop table atacc1; + +-- adding a new column as primary key to a non-empty table. +-- should fail unless the column has a non-null default value. +create table a8tacc1 ( test int ); +insert into a8tacc1 (test) values (0); +-- add a primary key column without a default (fails). +alter table a8tacc1 add column test2 int primary key; +-- now add a primary key column with a default (succeeds). +alter table a8tacc1 add column test2 int default 0 primary key; +--drop table atacc1; + +-- something a little more complicated +create table a9tacc1 ( test int, test2 int); +-- add a primary key constraint +alter table a9tacc1 add constraint a9tacc_test1 primary key (test, test2); +-- try adding a second primary key - should fail +alter table a9tacc1 add constraint atacc_test2 primary key (test); +-- insert initial value +insert into a9tacc1 (test,test2) values (4,4); +-- should fail +insert into a9tacc1 (test,test2) values (4,4); +insert into a9tacc1 (test,test2) values (NULL,3); +insert into a9tacc1 (test,test2) values (3, NULL); +insert into a9tacc1 (test,test2) values (NULL,NULL); +-- should all succeed +insert into a9tacc1 (test,test2) values (4,5); +insert into a9tacc1 (test,test2) values (5,4); +insert into a9tacc1 (test,test2) values (5,5); +--drop table atacc1; + +-- lets do some naming tests +create table at10acc1 (test int, test2 int, primary key(test)); +-- only first should succeed +insert into at10acc1 (test2, test) values (3, 3); +insert into at10acc1 (test2, test) values (2, 3); +insert into at10acc1 (test2, test) values (1, NULL); +--drop table atacc1; + +-- alter table modify not null +-- try altering syscatlog should fail +alter table pg_class modify (relname not null enable); +alter table pg_class modify relname not null enable; +-- try altering non-existent table should fail +alter table non_existent modify (bar not null enable); +-- test alter table +create table test_modify (a int, b int); +alter table test_modify replica identity full; +alter table test_modify modify (b not null enable); +insert into test_modify(b) values (null); +insert into test_modify values (1, null); +alter table test_modify modify(b null); +insert into test_modify values (1, null); +alter table test_modify modify (b not null enable); +alter table test_modify replica identity full; +delete from test_modify; +alter table test_modify modify (a not null, b not null); +insert into test_modify values (1,null); +insert into test_modify values (null,1); +alter table test_modify modify (a null, b null); +insert into test_modify values (1,null); +insert into test_modify values (null,1); +alter table test_modify modify (b constraint ak not null); +delete from test_modify; +alter table test_modify modify (b constraint ak not null); +insert into test_modify values(1,1); +insert into test_modify values(1,null); +alter table test_modify modify (b constraint ak null); +insert into test_modify values(1,null); +alter table test_modify modify (a null, a not null); +-- try alter view should fail +create view test_modify_view as select * from test_modify; +alter table test_modify_view modify (a not null enable); +drop view test_modify_view; +--drop table test_modify; + +-- alter table / alter column [set/drop] not null tests +-- try altering system catalogs, should fail +alter table pg_class alter column relname drop not null; +alter table pg_class alter relname set not null; + +-- try altering non-existent table, should fail +alter table non_existent alter column bar set not null; +alter table non_existent alter column bar drop not null; + +-- test setting columns to null and not null and vice versa +-- test checking for null values and primary key +create table at11acc1 (test int not null) with oids; +alter table at11acc1 add constraint "atacc1_pkey" primary key (test); +alter table at11acc1 alter column test drop not null; +alter table at11acc1 drop constraint "atacc1_pkey"; +alter table at11acc1 alter column test drop not null; +insert into at11acc1 values (null); +alter table at11acc1 alter test set not null; +atler table at11acc1 replica identity full; +delete from at11acc1; +alter table at11acc1 alter test set not null; + +-- try altering a non-existent column, should fail +alter table at11acc1 alter bar set not null; +alter table at11acc1 alter bar drop not null; + +-- try altering the oid column, should fail +alter table at11acc1 alter oid set not null; +alter table at11acc1 alter oid drop not null; + +-- try creating a view and altering that, should fail +create view myview as select * from at11acc1; +alter table myview alter column test drop not null; +alter table myview alter column test set not null; +drop view myview; + +--drop table atacc1; + +-- test inheritance +create table parent (a int); +create table child1 (b varchar(255)) inherits (parent); +create table child1 (like parent); +alter table child1 add column (b varchar(255)); + +alter table parent alter a set not null; +insert into parent values (NULL); +insert into child1 (a, b) values (NULL, 'foo'); +alter table parent alter a drop not null; +insert into parent values (NULL); +insert into child1 (a, b) values (NULL, 'foo'); +alter table only parent alter a set not null; +alter table child1 alter a set not null; +alter table parent replica identity full; +alter table child1 replica identity full; +delete from parent; +alter table only parent alter a set not null; +insert into parent values (NULL); +alter table child1 alter a set not null; +insert into child1 (a, b) values (NULL, 'foo'); +delete from child1; +alter table child1 alter a set not null; +insert into child1 (a, b) values (NULL, 'foo'); +--drop table child; +--drop table parent; + +-- test setting and removing default values +create table def_test ( + c1 int4 default 5, + c2 text default 'initial_default' +); +insert into def_test default values; +alter table def_test alter column c1 drop default; +insert into def_test default values; +alter table def_test alter column c2 drop default; +insert into def_test default values; +alter table def_test alter column c1 set default 10; +alter table def_test alter column c2 set default 'new_default'; +insert into def_test default values; +select * from def_test order by 1, 2; + +-- set defaults to an incorrect type: this should fail +alter table def_test alter column c1 set default 'wrong_datatype'; +alter table def_test alter column c2 set default 20; + +-- set defaults on a non-existent column: this should fail +alter table def_test alter column c3 set default 30; + +-- set defaults on views: we need to create a view, add a rule +-- to allow insertions into it, and then alter the view to add +-- a default +create view def_view_test as select * from def_test; +create rule def_view_test_ins as + on insert to def_view_test + do instead insert into def_test select new.*; +insert into def_view_test default values; +alter table def_view_test alter column c1 set default 45; +insert into def_view_test default values; +alter table def_view_test alter column c2 set default 'view_default'; +insert into def_view_test default values; +select * from def_view_test order by 1, 2; + +drop rule def_view_test_ins on def_view_test; +drop view def_view_test; +--drop table def_test; + +-- alter table / drop column tests +-- try altering system catalogs, should fail +alter table pg_class drop column relname; + +-- try altering non-existent table, should fail +alter table nosuchtable drop column bar; + +-- test dropping columns +create table at12acc1 (a int4 not null, b int4, c int4 not null, d int4) with oids; +insert into at12acc1 values (1, 2, 3, 4); +alter table at12acc1 drop a; +alter table at12acc1 drop a; + +-- SELECTs +select * from at12acc1; +select * from at12acc1 order by a; +select * from at12acc1 order by "........pg.dropped.1........"; +select * from at12acc1 group by a; +select * from at12acc1 group by "........pg.dropped.1........"; +select at12acc1.* from at12acc1; +select a from at12acc1; +select at12acc1.a from at12acc1; +select b,c,d from at12acc1; +select a,b,c,d from at12acc1; +select * from at12acc1 where a = 1; +select "........pg.dropped.1........" from at12acc1; +select at12acc1."........pg.dropped.1........" from at12acc1; +select "........pg.dropped.1........",b,c,d from at12acc1; +select * from at12acc1 where "........pg.dropped.1........" = 1; +alter table at12acc1 replica identity full; +-- UPDATEs +update at12acc1 set a = 3; +update at12acc1 set b = 2 where a = 3; +update at12acc1 set "........pg.dropped.1........" = 3; +update at12acc1 set b = 2 where "........pg.dropped.1........" = 3; + +-- INSERTs +insert into at12acc1 values (10, 11, 12, 13); +insert into at12acc1 values (default, 11, 12, 13); +insert into at12acc1 values (11, 12, 13); +insert into at12acc1 (a) values (10); +insert into at12acc1 (a) values (default); +insert into at12acc1 (a,b,c,d) values (10,11,12,13); +insert into at12acc1 (a,b,c,d) values (default,11,12,13); +insert into at12acc1 (b,c,d) values (11,12,13); +insert into at12acc1 ("........pg.dropped.1........") values (10); +insert into at12acc1 ("........pg.dropped.1........") values (default); +insert into at12acc1 ("........pg.dropped.1........",b,c,d) values (10,11,12,13); +insert into at12acc1 ("........pg.dropped.1........",b,c,d) values (default,11,12,13); + +-- DELETEs +alter table at12acc1 replica identity full; +delete from at12acc1 where a = 3; +delete from at12acc1 where "........pg.dropped.1........" = 3; +delete from at12acc1; + +-- try dropping a non-existent column, should fail +alter table at12acc1 drop bar; + +-- try dropping the oid column, should succeed +alter table at12acc1 drop oid; + +-- try dropping the xmin column, should fail +alter table at12acc1 drop xmin; + +-- try creating a view and altering that, should fail +create view myview as select * from at12acc1; +select * from myview; +alter table myview drop d; +drop view myview; + +-- test some commands to make sure they fail on the dropped column +analyze at12acc1(a); +analyze at12acc1("........pg.dropped.1........"); +vacuum analyze at12acc1(a); +vacuum analyze at12acc1("........pg.dropped.1........"); +comment on column at12acc1.a is 'testing'; +comment on column at12acc1."........pg.dropped.1........" is 'testing'; +alter table at12acc1 alter a set storage plain; +alter table at12acc1 alter "........pg.dropped.1........" set storage plain; +alter table at12acc1 alter a set statistics 0; +alter table at12acc1 alter "........pg.dropped.1........" set statistics 0; +alter table at12acc1 alter a set default 3; +alter table at12acc1 alter "........pg.dropped.1........" set default 3; +alter table at12acc1 alter a drop default; +alter table at12acc1 alter "........pg.dropped.1........" drop default; +alter table at12acc1 alter a set not null; +alter table at12acc1 alter "........pg.dropped.1........" set not null; +alter table at12acc1 alter a drop not null; +alter table at12acc1 alter "........pg.dropped.1........" drop not null; +alter table at12acc1 rename a to x; +alter table at12acc1 rename "........pg.dropped.1........" to x; +alter table at12acc1 add primary key(a); +alter table at12acc1 add primary key("........pg.dropped.1........"); +alter table at12acc1 add unique(a); +alter table at12acc1 add unique("........pg.dropped.1........"); +alter table at12acc1 add check (a > 3); +alter table at12acc1 add check ("........pg.dropped.1........" > 3); +create table atacc2 (id int4 unique); +alter table at12acc1 add foreign key (a) references atacc2(id); +alter table at12acc1 add foreign key ("........pg.dropped.1........") references atacc2(id); +alter table atacc2 add foreign key (id) references at12acc1(a); +alter table atacc2 add foreign key (id) references at12acc1("........pg.dropped.1........"); +--drop table atacc2; +create index "testing_idx" on at12acc1(a); +create index "testing_idx" on at12acc1("........pg.dropped.1........"); + +-- test create as and select into +insert into at12acc1 values (21, 22, 23); +create table test1 as select * from at12acc1; +select * from test1; +--drop table test1; +select * into test2 from at12acc1; +select * from test2; +--drop table test2; + +-- try dropping all columns +alter table at12acc1 drop c; +alter table at12acc1 drop d; +alter table at12acc1 drop b; +select * from at12acc1; + +--drop table atacc1; +-- test constraint error reporting in presence of dropped columns +create table at13acc1 (id serial primary key, value int check (value < 10)); +insert into at13acc1(value) values (100); +alter table at13acc1 drop column value; +alter table at13acc1 add column value int check (value < 10); +insert into at13acc1(value) values (100); +insert into at13acc1(id, value) values (null, 0); +alter table at13acc1 alter column id set default 10; +drop sequence at13acc1_id_seq; + +-- test inheritance +create table parent (a int, b int, c int); +insert into parent values (1, 2, 3); +alter table parent drop a; +create table child (d varchar(255)) inherits (parent); +create table child2 as select * from parent; +alter table child2 add column d varchar(255); +insert into child2 values (12, 13, 'testing'); + +select * from parent order by b; +select * from child2; +alter table parent drop c; +select * from parent order by b; +select * from child2; + +--drop table child; +--drop table parent; + +-- test copy in/out +create table test (a int4, b int4, c int4); +insert into test values (1,2,3); +alter table test drop a; +copy test to stdout; +copy test(a) to stdout; +copy test("........pg.dropped.1........") to stdout; +copy test from stdin; +10 11 12 +\. +select * from test order by b; +copy test from stdin; +21 22 +\. +select * from test order by b; +copy test(a) from stdin; +copy test("........pg.dropped.1........") from stdin; +copy test(b,c) from stdin; +31 32 +\. +select * from test order by b; +--drop table test; + +-- test inheritance + +create table dropColumn (a int, b int, e int); +create table dropColumnChild (c int) inherits (dropColumn); +select * into dropColumnChild from dropColumn; +alter table dropColumnChild add column c int; +create table dropColumnAnother (d int) inherits (dropColumnChild); +select * into dropColumnAnother from dropColumnChild; +alter table dropColumnAnother add column d int; +-- these two should fail +alter table dropColumnchild drop column a; +alter table only dropColumnChild drop column b; + + + +-- these three should work +alter table only dropColumn drop column e; +alter table dropColumnChild drop column c; +alter table dropColumn drop column a; + +create table renameColumn (a int); +create table renameColumnChild (b int) inherits (renameColumn); +create table renameColumnChild as select * from renameColumn; +create table renameColumnAnother (c int) inherits (renameColumnChild); +select * into renameColumnAnother from renameColumnChild; +alter table renameColumnAnother add column b int; + +-- these three should fail +alter table renameColumnChild rename column a to d; +alter table only renameColumnChild rename column a to d; +alter table only renameColumn rename column a to d; + +-- these should work +alter table renameColumn rename column a to d; +alter table renameColumnChild rename column b to a; + +-- these should work +alter table if exists doesnt_exist_tab rename column a to d; +alter table if exists doesnt_exist_tab rename column b to a; + +-- this should work +alter table renameColumn add column w int; + +-- this should fail +alter table only renameColumn add column x int; + + +-- Test corner cases in dropping of inherited columns + +create table p1 (f1 int, f2 int); +create table c1 (f1 int not null) inherits(p1); +create table c1 (like p1); +-- should be rejected since c1.f1 is inherited +alter table c1 drop column f1; +-- should work +alter table p1 drop column f1; +-- c1.f1 is still there, but no longer inherited +select f1 from c1; +alter table c1 drop column f1; +select f1 from c1; + +--drop table p1 cascade; + +create table p11 (f1 int, f2 int); +create table c11 () inherits(p11); +create table c11 (like p11); +-- should be rejected since c1.f1 is inherited +alter table c11 drop column f1; +alter table p11 drop column f1; +-- c1.f1 is dropped now, since there is no local definition for it +select f1 from c11; + +--drop table p1 cascade; + +create table p12 (f1 int, f2 int); +create table c12 () inherits(p12); +create table c12 as select * from p12; +-- should be rejected since c1.f1 is inherited +alter table c12 drop column f1; +alter table only p1 drop column f1; +-- c1.f1 is NOT dropped, but must now be considered non-inherited +alter table c12 drop column f1; + +--drop table p1 cascade; + +create table p13 (f1 int, f2 int); +create table c13 (f1 int not null) inherits(p1); +create table c13 as select * from p13; +-- should be rejected since c1.f1 is inherited +alter table c13 drop column f1; +alter table only p13 drop column f1; +-- c1.f1 is still there, but no longer inherited +alter table c13 drop column f1; + +--drop table p1 cascade; + +create table p14(id int, name text); +create table p24(id2 int, name text, height int); +create table c14(age int) inherits(p1,p2); +create table c14 as select * from p1,p2; +alter table c14 add column age int; +create table gc1() inherits (c14); +select * into gc1 from c14; + +select relname, attname, attinhcount, attislocal +from pg_class join pg_attribute on (pg_class.oid = pg_attribute.attrelid) +where relname in ('p1','p2','c1','gc1') and attnum > 0 and not attisdropped +order by relname, attnum; + +-- should work +alter table only p14 drop column name; +-- should work. Now c1.name is local and inhcount is 0. +alter table p24 drop column name; +-- should be rejected since its inherited +alter table gc1 drop column name; +-- should work, and drop gc1.name along +alter table c14 drop column name; +-- should fail: column does not exist +alter table gc1 drop column name; +-- should work and drop the attribute in all tables +alter table p24 drop column height; + +select relname, attname, attinhcount, attislocal +from pg_class join pg_attribute on (pg_class.oid = pg_attribute.attrelid) +where relname in ('p1','p2','c1','gc1') and attnum > 0 and not attisdropped +order by relname, attnum; + +--drop table p1, p2 cascade; + +-- +-- Test the ALTER TABLE SET WITH/WITHOUT OIDS command +-- +create table altstartwith (col integer) with oids; + +insert into altstartwith values (1); + +select oid > 0, * from altstartwith; + +alter table altstartwith set without oids; + +select oid > 0, * from altstartwith; -- fails +select * from altstartwith; + +alter table altstartwith set with oids; + +select oid > 0, * from altstartwith; + +--drop table altstartwith; + +-- Check inheritance cases +create table altwithoid (col integer) with oids; + +-- Inherits parents oid column anyway +create table altinhoid () inherits (altwithoid) without oids; + +insert into altinhoid values (1); + +select oid > 0, * from altwithoid; +select oid > 0, * from altinhoid; + +alter table altwithoid set without oids; + +select oid > 0, * from altwithoid; -- fails +select oid > 0, * from altinhoid; -- fails +select * from altwithoid; +select * from altinhoid; + +alter table altwithoid set with oids; + +select oid > 0, * from altwithoid; +select oid > 0, * from altinhoid; + +--drop table altwithoid cascade; + +create table altwithoid1 (col integer) without oids; + +-- child can have local oid column +create table altinhoid1 () inherits (altwithoid1) with oids; + +insert into altinhoid1 values (1); + +select oid > 0, * from altwithoid1; -- fails +select oid > 0, * from altinhoid1; + +alter table altwithoid1 set with oids; + +select oid > 0, * from altwithoid1; +select oid > 0, * from altinhoid1; + +-- the child's local definition should remain +alter table altwithoid1 set without oids; + +select oid > 0, * from altwithoid1; -- fails +select oid > 0, * from altinhoid1; + +--drop table altwithoid cascade; + +-- test renumbering of child-table columns in inherited operations + +create table p15 (f1 int); +create table c15 (f2 text, f3 int) inherits (p1); +create table c15 as select * from p15; +alter table c15 add column f2 text, add column f3 int; +alter table p15 add column a1 int check (a1 > 0); +alter table p15 add column f2 text; + +insert into p15 values (1,2,'abc'); +insert into c15 values(11,'xyz',33,0); -- should fail +insert into c15 values(11,'xyz',33,22); + +select * from p15 order by f1; +alter table p15 replica identity full; +update p15 set a1 = a1 + 1, f2 = upper(f2); +select * from p15 order by f1; + +--drop table p1 cascade; + +-- test that operations with a dropped column do not try to reference +-- its datatype + +-- create domain mytype as text; +create type mytype as (a text); +create table foo (f1 text, f2 mytype, f3 text); + +insert into foo values('bb','cc','dd'); +select * from foo order by f1; + +-- drop domain mytype cascade; + +select * from foo order by f1; +insert into foo values('qq','rr'); +select * from foo order by f1; +alter table foo replica identity full; +update foo set f3 = 'zz'; +select * from foo order by f1; +select f3,max(f1) from foo group by f3; + +-- Simple tests for alter table column type +alter table foo replica identity full; +delete from foo where f1 = 'qq'; +alter table foo alter f1 TYPE integer; -- fails +alter table foo alter f1 TYPE varchar(10); +--drop table foo; + +create table anothertab (atcol1 serial8, atcol2 boolean, + constraint anothertab_chk check (atcol1 <= 3));; + +insert into anothertab (atcol1, atcol2) values (default, true); +insert into anothertab (atcol1, atcol2) values (default, false); +select * from anothertab order by atcol1, atcol2; + +alter table anothertab alter column atcol1 type boolean; -- we could support this cast +alter table anothertab alter column atcol1 type integer; + +select * from anothertab order by atcol1, atcol2; + +insert into anothertab (atcol1, atcol2) values (45, null); -- fails +insert into anothertab (atcol1, atcol2) values (default, null); + +select * from anothertab order by atcol1, atcol2; + +alter table anothertab alter column atcol2 type text + using case when atcol2 is true then 'IT WAS TRUE' + when atcol2 is false then 'IT WAS FALSE' + else 'IT WAS NULL!' end; + +select * from anothertab order by atcol1, atcol2; +alter table anothertab alter column atcol1 type boolean + using case when atcol1 % 2 = 0 then true else false end; -- fails +alter table anothertab alter column atcol1 drop default; +alter table anothertab alter column atcol1 type boolean + using case when atcol1 % 2 = 0 then true else false end; -- fails +alter table anothertab drop constraint anothertab_chk; +alter table anothertab drop constraint anothertab_chk; -- fails +alter table anothertab drop constraint IF EXISTS anothertab_chk; -- succeeds + +alter table anothertab alter column atcol1 type boolean + using case when atcol1 % 2 = 0 then true else false end; + +select * from anothertab order by atcol1, atcol2; + +--drop table anothertab; +-- alter table anothertab alter column atcol1 default false; +drop sequence anothertab_atcol1_seq; + +create table another (f1 int, f2 text);; + +insert into another values(1, 'one'); +insert into another values(2, 'two'); +insert into another values(3, 'three'); + +select * from another order by f1, f2; + +alter table another + alter f1 type text using f2 || ' more', + alter f2 type bigint using f1 * 10; + +select * from another order by f1, f2; + +--drop table another; + +-- table's row type +create table tab1 (a int, b text); +create table tab2 (x int, y tab1); +alter table tab1 alter column b type varchar; -- fails + +-- disallow recursive containment of row types +-- create table recur1 (f1 int); +-- alter table recur1 add column f2 recur1; -- fails +-- alter table recur1 add column f2 recur1[]; -- fails +-- create domain array_of_recur1 as recur1[]; +-- alter table recur1 add column f2 array_of_recur1; -- fails +-- create table recur2 (f1 int, f2 recur1); +-- alter table recur1 add column f2 recur2; -- fails +-- alter table recur1 add column f2 int; +-- alter table recur1 alter column f2 type recur2; -- fails + +-- SET STORAGE may need to add a TOAST table +create table test_storage (a text); +alter table test_storage alter a set storage plain; +alter table test_storage add b int default 0; -- rewrite table to remove its TOAST table +alter table test_storage alter a set storage extended; -- re-add TOAST table + +select reltoastrelid <> 0 as has_toast_table +from pg_class +where oid = 'test_storage'::regclass; + +-- ALTER TYPE with a check constraint and a child table (bug before Nov 2012) +CREATE TABLE test_inh_check (a float check (a > 10.2)); +CREATE TABLE test_inh_check_child() INHERITS(test_inh_check); +ALTER TABLE test_inh_check ALTER COLUMN a TYPE numeric; +\d test_inh_check +\d test_inh_check_child + +-- +-- lock levels +-- +drop type lockmodes; +create type lockmodes as enum ( + 'AccessShareLock' +,'RowShareLock' +,'RowExclusiveLock' +,'ShareUpdateExclusiveLock' +,'ShareLock' +,'ShareRowExclusiveLock' +,'ExclusiveLock' +,'AccessExclusiveLock' +); + +drop view my_locks; +create or replace view my_locks as +select case when c.relname like 'pg_toast%' then 'pg_toast' else c.relname end, max(mode::lockmodes) as max_lockmode +from pg_locks l join pg_class c on l.relation = c.oid +where virtualtransaction = ( + select virtualtransaction + from pg_locks + where transactionid = txid_current()::integer) +and locktype = 'relation' +and relnamespace != (select oid from pg_namespace where nspname = 'pg_catalog') +and c.relname != 'my_locks' +group by c.relname; + +create table alterlock (f1 int primary key, f2 text); + +start transaction; alter table alterlock alter column f2 set statistics 150; +select * from my_locks order by 1; +rollback; + +start transaction; alter table alterlock cluster on alterlock_pkey; +select * from my_locks order by 1; +commit; + +start transaction; alter table alterlock set without cluster; +select * from my_locks order by 1; +commit; + +start transaction; alter table alterlock set (fillfactor = 100); +select * from my_locks order by 1; +commit; + +start transaction; alter table alterlock reset (fillfactor); +select * from my_locks order by 1; +commit; + +start transaction; alter table alterlock set (toast.autovacuum_enabled = off); +select * from my_locks order by 1; +commit; + +start transaction; alter table alterlock set (autovacuum_enabled = off); +select * from my_locks order by 1; +commit; + +start transaction; alter table alterlock alter column f2 set (n_distinct = 1); +select * from my_locks order by 1; +rollback; + +start transaction; alter table alterlock alter column f2 set storage extended; +select * from my_locks order by 1; +rollback; + +start transaction; alter table alterlock alter column f2 set default 'x'; +select * from my_locks order by 1; +rollback; + +-- cleanup +--drop table alterlock; +drop view my_locks; +-- drop type lockmodes; + +-- +-- --alter function +-- +--create function test_strict(text) returns text as + 'select coalesce($1, ''got passed a null'');' + language sql returns null on null input; +select test_strict(NULL); +--alter function test_strict(text) called on null input; +select test_strict(NULL); + +--create function non_strict(text) returns text as + 'select coalesce($1, ''got passed a null'');' + language sql called on null input; +select non_strict(NULL); +--alter function non_strict(text) returns null on null input; +select non_strict(NULL); + +-- +-- alter object set schema +-- + +create schema alter1; +create schema alter2; + +-- cannot move table into system built-in schema +create table test1(a int); +alter table test1 set schema dbms_random; +alter table test1 set schema utl_file; + +create table alter1.t1(f1 serial primary key, f2 int check (f2 > 0)); + +create view alter1.v1 as select * from alter1.t1; + +-- --create function alter1.plus1(int) returns int as 'select $1+1' language sql; + +-- create domain alter1.posint integer check (value > 0); + +create type alter1.ctype as (f1 int, f2 text); + +--create function alter1.same(alter1.ctype, alter1.ctype) returns boolean language sql +as 'select $1.f1 is not distinct from $2.f1 and $1.f2 is not distinct from $2.f2'; + +--create operator alter1.=(procedure = alter1.same, leftarg = alter1.ctype, rightarg = alter1.ctype); + +--create operator class alter1.ctype_hash_ops default for type alter1.ctype using hash as + -- operator 1 alter1.=(alter1.ctype, alter1.ctype); + +-- create conversion alter1.ascii_to_utf8 for 'sql_ascii' to 'utf8' from ascii_to_utf8; + +--create text search parser alter1.prs(start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype); +--create text search configuration alter1.cfg(parser = alter1.prs); +--create text search template alter1.tmpl(init = dsimple_init, lexize = dsimple_lexize); +--create text search dictionary alter1.dict(template = alter1.tmpl); + +insert into alter1.t1(f2) values(11); +insert into alter1.t1(f2) values(12); + +alter table alter1.t1 set schema alter2; +alter table alter1.v1 set schema alter2; +--alter function alter1.plus1(int) set schema alter2; +-- alter domain alter1.posint set schema alter2; +--alter operator class alter1.ctype_hash_ops using hash set schema alter2; +--alter operator family alter1.ctype_hash_ops using hash set schema alter2; +--alter operator alter1.=(alter1.ctype, alter1.ctype) set schema alter2; +--alter function alter1.same(alter1.ctype, alter1.ctype) set schema alter2; +alter type alter1.ctype set schema alter2; +--alter conversion alter1.ascii_to_utf8 set schema alter2; +--alter text search parser alter1.prs set schema alter2; +--alter text search configuration alter1.cfg set schema alter2; +--alter text search template alter1.tmpl set schema alter2; +--alter text search dictionary alter1.dict set schema alter2; + +-- this should succeed because nothing is left in alter1 +-- drop schema alter1; + +insert into alter2.t1(f2) values(13); +insert into alter2.t1(f2) values(14); + +select * from alter2.t1 order by f1, f2; + +alter table alter1.t1 alter column f1 drop default; +drop sequence alter1.t1_f1_seq; + +select * from alter2.v1 order by f1, f2; +drop view alter2.v1; + +select alter2.plus1(41); + +-- clean up +-- drop schema alter2 cascade; +-- drop schema alter1 cascade; + +-- +-- composite types +-- + +CREATE TYPE test_type AS (a int); +\d test_type + +ALTER TYPE nosuchtype ADD ATTRIBUTE b text; -- fails + +ALTER TYPE test_type ADD ATTRIBUTE b text; +\d test_type + +ALTER TYPE test_type ADD ATTRIBUTE b text; -- fails + +ALTER TYPE test_type ALTER ATTRIBUTE b SET DATA TYPE varchar; +\d test_type + +ALTER TYPE test_type ALTER ATTRIBUTE b SET DATA TYPE integer; +\d test_type + +ALTER TYPE test_type DROP ATTRIBUTE b; +\d test_type + +ALTER TYPE test_type DROP ATTRIBUTE c; -- fails + +ALTER TYPE test_type DROP ATTRIBUTE IF EXISTS c; + +ALTER TYPE test_type DROP ATTRIBUTE a, ADD ATTRIBUTE d boolean; +\d test_type + +ALTER TYPE test_type RENAME ATTRIBUTE a TO aa; +ALTER TYPE test_type RENAME ATTRIBUTE d TO dd; +\d test_type + +-- DROP TYPE test_type; + +CREATE TYPE test_type1 AS (a int, b text); +CREATE TABLE test_tbl1 (x int, y test_type1); +ALTER TYPE test_type1 ALTER ATTRIBUTE b TYPE varchar; -- fails + +CREATE TYPE test_type2 AS (a int, b text); +-- CREATE TABLE test_tbl2 OF test_type2; +CREATE TABLE test_tbl2_subclass () INHERITS (test_tbl2); +\d test_type2 +\d test_tbl2 + +ALTER TYPE test_type2 ADD ATTRIBUTE c text; -- fails +ALTER TYPE test_type2 ADD ATTRIBUTE c text CASCADE; +\d test_type2 +\d test_tbl2 + +ALTER TYPE test_type2 ALTER ATTRIBUTE b TYPE varchar; -- fails +ALTER TYPE test_type2 ALTER ATTRIBUTE b TYPE varchar CASCADE; +\d test_type2 +\d test_tbl2 + +ALTER TYPE test_type2 DROP ATTRIBUTE b; -- fails +ALTER TYPE test_type2 DROP ATTRIBUTE b CASCADE; +\d test_type2 +\d test_tbl2 + +ALTER TYPE test_type2 RENAME ATTRIBUTE a TO aa; -- fails +ALTER TYPE test_type2 RENAME ATTRIBUTE a TO aa CASCADE; +\d test_type2 +\d test_tbl2 +\d test_tbl2_subclass + +--drop table test_tbl2_subclass; + +-- This test isn't that interesting on its own, but the purpose is to leave +-- behind a table to test pg_upgrade with. The table has a composite type +-- column in it, and the composite type has a dropped attribute. +CREATE TYPE test_type3 AS (a int); +CREATE TABLE test_tbl3 (c) AS SELECT '(1)'::test_type3; +ALTER TYPE test_type3 DROP ATTRIBUTE a, ADD ATTRIBUTE b int; + +CREATE TYPE test_type_empty AS (); + +-- +-- typed tables: OF / NOT OF +-- + +CREATE TYPE tt_t0 AS (z inet, x int, y numeric(8,2)); +ALTER TYPE tt_t0 DROP ATTRIBUTE z; +CREATE TABLE tt0 (x int NOT NULL, y numeric(8,2)); -- OK +CREATE TABLE tt1 (x int, y bigint); -- wrong base type +CREATE TABLE tt2 (x int, y numeric(9,2)); -- wrong typmod +CREATE TABLE tt3 (y numeric(8,2), x int); -- wrong column order +CREATE TABLE tt4 (x int); -- too few columns +CREATE TABLE tt5 (x int, y numeric(8,2), z int); -- too few columns +CREATE TABLE tt6 () INHERITS (tt0); -- can't have a parent +CREATE TABLE tt7 (x int, q text, y numeric(8,2)) WITH OIDS; +ALTER TABLE tt7 DROP q; -- OK + +ALTER TABLE tt0 OF tt_t0; +ALTER TABLE tt1 OF tt_t0; +ALTER TABLE tt2 OF tt_t0; +ALTER TABLE tt3 OF tt_t0; +ALTER TABLE tt4 OF tt_t0; +ALTER TABLE tt5 OF tt_t0; +ALTER TABLE tt6 OF tt_t0; +ALTER TABLE tt7 OF tt_t0; + +CREATE TYPE tt_t1 AS (x int, y numeric(8,2)); +ALTER TABLE tt7 OF tt_t1; -- reassign an already-typed table +ALTER TABLE tt7 NOT OF; +\d tt7 +drop table tt0; +-- make sure we can drop a constraint on the parent but it remains on the child +CREATE TABLE test_drop_constr_parent (c text CHECK (c IS NOT NULL)); +CREATE TABLE test_drop_constr_child () INHERITS (test_drop_constr_parent); +ALTER TABLE ONLY test_drop_constr_parent DROP CONSTRAINT "test_drop_constr_parent_c_check"; +-- should fail +INSERT INTO test_drop_constr_child (c) VALUES (NULL); +--drop table test_drop_constr_parent CASCADE; + +-- +-- IF EXISTS test +-- +ALTER TABLE IF EXISTS tt8 ADD COLUMN f int; +ALTER TABLE IF EXISTS tt8 ADD CONSTRAINT xxx PRIMARY KEY(f); +ALTER TABLE IF EXISTS tt8 ADD CHECK (f BETWEEN 0 AND 10); +ALTER TABLE IF EXISTS tt8 ALTER COLUMN f SET DEFAULT 0; +ALTER TABLE IF EXISTS tt8 RENAME COLUMN f TO f1; +ALTER TABLE IF EXISTS tt8 SET SCHEMA alter2; + +CREATE TABLE tt8(a int); +CREATE SCHEMA alter2; + +ALTER TABLE IF EXISTS tt8 ADD COLUMN f int; +ALTER TABLE IF EXISTS tt8 ADD CONSTRAINT xxx PRIMARY KEY(f); +ALTER TABLE IF EXISTS tt8 ADD CHECK (f BETWEEN 0 AND 10); +ALTER TABLE IF EXISTS tt8 ALTER COLUMN f SET DEFAULT 0; +ALTER TABLE IF EXISTS tt8 RENAME COLUMN f TO f1; +ALTER TABLE IF EXISTS tt8 SET SCHEMA alter2; + +\d alter2.tt8 + +--drop table alter2.tt8; +DROP SCHEMA alter2; +--custom script +--create table +CREATE TABLE TBL_DOMAIN +( + IDOMAINID NUMBER(10) NOT NULL, + SDOMAINNAME VARCHAR2(30) NOT NULL +); +--create/recreate primary, unique and foreign key constraints +ALTER TABLE TBL_DOMAIN + ADD CONSTRAINT PK_TBL_DOMAIN PRIMARY KEY (IDOMAINID) + USING INDEX ; + +ALTER TABLE TBL_DOMAIN + ADD CONSTRAINT IX_TBL_DOMAIN UNIQUE (SDOMAINNAME) + USING INDEX ; +\d+ TBL_DOMAIN +--drop table TBL_DOMAIN; + +--create table +CREATE TABLE TBL_CM_MAXTSENDTOHOST +( + I_MODULETYPE NUMBER(38) NOT NULL, + I_MODULENO NUMBER(38) NOT NULL, + I_PLAMODULENO NUMBER(38) NOT NULL, + I_TABLEID NUMBER(38) NOT NULL, + I_OLDMAXTUPLE NUMBER(38) NOT NULL, + I_NEWMAXTUPLE NUMBER(38) NOT NULL, + I_RESERVED1 NUMBER(38) DEFAULT 0, + I_RESERVED2 NUMBER(38) DEFAULT 0, + I_RESERVED3 NUMBER(38) DEFAULT 0, + I_RESERVED4 NUMBER(38) DEFAULT 0, + I_RESERVED5 NUMBER(38) DEFAULT 0, + I_RESERVED6 NUMBER(38) DEFAULT 0, + I_RESERVED7 NUMBER(38) DEFAULT 0, + SV_RESERVED8 VARCHAR2(32) DEFAULT '', + SV_RESERVED9 VARCHAR2(32) DEFAULT '', + SV_RESERVED10 VARCHAR2(32) DEFAULT '' +) + PCTFREE 10 + INITRANS 1 + MAXTRANS 255 + STORAGE + ( + INITIAL 64K + MINEXTENTS 1 + MAXEXTENTS UNLIMITED + ) + ; +--add primary key +ALTER TABLE TBL_CM_MAXTSENDTOHOST + ADD PRIMARY KEY (I_PLAMODULENO, I_TABLEID) + USING INDEX + PCTFREE 10 + INITRANS 2 + MAXTRANS 255 + STORAGE + ( + INITIAL 64K + MINEXTENTS 1 + MAXEXTENTS UNLIMITED + ); + \d+ TBL_CM_MAXTSENDTOHOST + --drop table TBL_CM_MAXTSENDTOHOST; + +--create table +CREATE TABLE TBL_LICCTRLDESC_DEFAULT +( + I_INDEX NUMBER(38) NOT NULL, + SV_FEATURENAME VARCHAR2(64) NOT NULL, + SV_ITEMNAME VARCHAR2(64) NOT NULL, + I_ITEMTYPE NUMBER(38) NOT NULL, + I_ITEMVALUEMIN NUMBER(38) NOT NULL, + I_ITEMVALUEMAX NUMBER(38) NOT NULL, + I_RESERVED1 NUMBER(38) DEFAULT 0, + I_RESERVED2 NUMBER(38) DEFAULT 0, + I_RESERVED3 NUMBER(38) DEFAULT 0, + I_RESERVED4 NUMBER(38) DEFAULT 0, + I_RESERVED5 NUMBER(38) DEFAULT 0, + I_RESERVED6 NUMBER(38) DEFAULT 0, + I_RESERVED7 NUMBER(38) DEFAULT 0, + SV_RESERVED8 VARCHAR2(32) DEFAULT '', + SV_RESERVED9 VARCHAR2(32) DEFAULT '', + SV_RESERVED10 VARCHAR2(32) DEFAULT '', + I_STATUS NUMBER(38) NOT NULL +) + PCTFREE 10 + INITRANS 1 + MAXTRANS 255 + STORAGE + ( + INITIAL 64K + MINEXTENTS 1 + MAXEXTENTS UNLIMITED + ) + ; +--add primary key +ALTER TABLE TBL_LICCTRLDESC_DEFAULT + ADD PRIMARY KEY (I_INDEX) + USING INDEX + PCTFREE 10 + INITRANS 2 + MAXTRANS 255 + STORAGE + ( + INITIAL 64K + MINEXTENTS 1 + MAXEXTENTS UNLIMITED + ); +--add unique index +CREATE UNIQUE INDEX IDX_TBL_LICCTRL_DEF ON TBL_LICCTRLDESC_DEFAULT (I_INDEX DESC, I_STATUS) + PCTFREE 10 + INITRANS 2 + MAXTRANS 255 + STORAGE + ( + INITIAL 64K + MINEXTENTS 1 + MAXEXTENTS UNLIMITED + ); +\d+ TBL_LICCTRLDESC_DEFAULT + --drop table TBL_LICCTRLDESC_DEFAULT; +--using index clause +CREATE TABLE STUDENTS +( + ID INT, + NAME VARCHAR2(20), + AGE INT, + ADDRESS VARCHAR(30) +); + --alter table to add unique index or primary key +ALTER TABLE STUDENTS ADD UNIQUE (ID) +USING INDEX +PCTFREE 10 +INITRANS 2 +MAXTRANS 255 +STORAGE +( + INITIAL 64K + MINEXTENTS 1 + MAXEXTENTS UNLIMITED +); + +ALTER TABLE STUDENTS ADD CONSTRAINT ZHANGYG UNIQUE (AGE, ADDRESS) +USING INDEX +PCTFREE 10 +INITRANS 2 +MAXTRANS 255 +STORAGE +( + INITIAL 64K + MINEXTENTS 1 + MAXEXTENTS UNLIMITED +); + +ALTER TABLE STUDENTS ADD PRIMARY KEY (AGE) +USING INDEX +PCTFREE 10 +INITRANS 2 +MAXTRANS 255 +STORAGE +( + INITIAL 64K + MINEXTENTS 1 + MAXEXTENTS UNLIMITED +); +\d+ STUDENTS +--drop table STUDENTS; +--simulate A db's ALTER TABLE gram +CREATE TABLE MODIFY_TABLE_A(I INTEGER); +ALTER TABLE MODIFY_TABLE_A ADD (mychar CHAR); +ALTER TABLE MODIFY_TABLE_A ADD (myint1 INT, mychar1 CHAR); +ALTER TABLE MODIFY_TABLE_A ADD (myint2 INT, mychar2 CHAR, mychar3 CHAR); +ALTER TABLE MODIFY_TABLE_A ADD a CHAR, ADD b CHAR; +\d MODIFY_TABLE_A +ALTER TABLE MODIFY_TABLE_A ADD mychar4 CHAR; +\d MODIFY_TABLE_A +ALTER TABLE MODIFY_TABLE_A MODIFY I VARCHAR2(64); +\d MODIFY_TABLE_A +ALTER TABLE MODIFY_TABLE_A MODIFY I CHAR, MODIFY myint1 CHAR; +\d MODIFY_TABLE_A +ALTER TABLE MODIFY_TABLE_A MODIFY (myint1 VARCHAR(12)); +\d MODIFY_TABLE_A +ALTER TABLE MODIFY_TABLE_A MODIFY (myint1 VARCHAR(13), mychar1 INT); +\d MODIFY_TABLE_A +ALTER TABLE MODIFY_TABLE_A MODIFY (myint1 VARCHAR(13), myint1 INT); +--drop table MODIFY_TABLE_A; + +create table test_alter_type(a int,b text); +alter table test_alter_type alter column a type regclass; +--drop table test_alter_type; + +create table test_mod(a int,b text); +alter table test_mod alter column a type regclass; +alter table test_mod alter column a set default "d"; +alter table test_mod alter column a set default "d"::int; +alter table test_mod alter column a set default "d"::int + 1; +--drop table test_mod; + +--simulate A db and postgresql, ALTER TABLE IF EXISTS table_name ADD( { element_list_clause } [, ...] ) +--simulate A db and postgresql, ALTER TABLE IF EXISTS table_name MODIFY( { element_list_clause } [, ...] ) +create schema columnar_storage; +create table columnar_storage.create_columnar_add_common_008 (c_tinyint tinyint,c_smallint smallint,c_int integer,c_bigint bigint,c_money money,c_numeric numeric,c_real real,c_double double precision,c_decimal decimal,c_varchar varchar,c_char char(30),c_nvarchar2 nvarchar2,c_text text,c_timestamp timestamp with time zone,c_timestamptz timestamp without time zone,c_date date,c_time time without time zone,c_timetz time with time zone,c_interval interval,c_tinterval tinterval,c_smalldatetime smalldatetime,c_bytea bytea,c_boolean boolean,c_inet inet,c_cidr cidr,c_bit bit(10),c_varbit varbit(10),c_oid oid) with (orientation=column); +alter table if exists columnar_storage.create_columnar_add_common_007 modify (c_int varchar(20)); +alter table if exists columnar_storage.create_columnar_add_common_008 modify (c_int varchar(20), c_double varchar(20)); +select * from columnar_storage.create_columnar_add_common_008; +--drop table columnar_storage.create_columnar_add_common_008; +create table columnar_storage.create_columnar_add_common_008 (c_tinyint tinyint,c_smallint smallint,c_int integer,c_bigint bigint,c_money money,c_numeric numeric,c_real real,c_double double precision,c_decimal decimal,c_varchar varchar,c_char char(30),c_nvarchar2 nvarchar2,c_text text,c_timestamp timestamp with time zone,c_timestamptz timestamp without time zone,c_date date,c_time time without time zone,c_timetz time with time zone,c_interval interval,c_tinterval tinterval,c_smalldatetime smalldatetime,c_bytea bytea,c_boolean boolean,c_inet inet,c_cidr cidr,c_bit bit(10),c_varbit varbit(10),c_oid oid) with (orientation=column); +alter table if exists columnar_storage.create_columnar_add_common_007 add (c_time_008 time without time zone,c_timetz_008 time with time zone); +alter table if exists columnar_storage.create_columnar_add_common_008 add (c_time_008 time without time zone,c_timetz_008 time with time zone); +select * from columnar_storage.create_columnar_add_common_008; +--drop table columnar_storage.create_columnar_add_common_008; +drop schema columnar_storage cascade; + +create table test_drop_column_1 (a int, b int, c int); +create table test_drop_column_2 (a int, b int); +create table test_drop_column_3 (a int, b int); +alter table test_drop_column_1 drop column c; +explain (verbose true, costs false) insert into test_drop_column_1 select * from test_drop_column_2; +insert into test_drop_column_1 select * from test_drop_column_2; +explain (verbose true, costs false) insert into test_drop_column_1 select * from test_drop_column_2 order by 2; +insert into test_drop_column_1 select * from test_drop_column_2 order by 2; +explain (verbose true, costs false) insert into test_drop_column_1 select test_drop_column_2.a, test_drop_column_3.a from test_drop_column_2, test_drop_column_3 where test_drop_column_2.a = test_drop_column_3.a; +insert into test_drop_column_1 select test_drop_column_2.a, test_drop_column_3.a from test_drop_column_2, test_drop_column_3 where test_drop_column_2.a = test_drop_column_3.a; +explain (verbose true, costs false) insert into test_drop_column_1 select test_drop_column_2.a, test_drop_column_3.a from test_drop_column_2, test_drop_column_3 where test_drop_column_2.a = test_drop_column_3.b; +insert into test_drop_column_1 select test_drop_column_2.a, test_drop_column_3.a from test_drop_column_2, test_drop_column_3 where test_drop_column_2.a = test_drop_column_3.b; +explain (verbose true, costs false) insert into test_drop_column_1 select test_drop_column_2.a, test_drop_column_3.a from test_drop_column_2, test_drop_column_3 where test_drop_column_2.a = test_drop_column_3.b order by 1, 2; +insert into test_drop_column_1 select test_drop_column_2.a, test_drop_column_3.a from test_drop_column_2, test_drop_column_3 where test_drop_column_2.a = test_drop_column_3.b order by 1, 2; +alter table test_drop_column2 replica identity full; +explain (verbose true, costs false) update test_drop_column_1 set a=test_drop_column_2.a from test_drop_column_2; +update test_drop_column_1 set a=test_drop_column_2.a from test_drop_column_2; +explain (verbose true, costs false) delete from test_drop_column_1 where a in (select a from test_drop_column_2); +alter table test_drop_column_1 replica identity full; +delete from test_drop_column_1 where a in (select a from test_drop_column_2); + +create table test_drop_column_cstore_1 (a int, b int, c int) with (orientation = column); +create table test_drop_column_cstore_2 (a int, b int) with (orientation = column); +create table test_drop_column_cstore_3 (a int) with (orientation = column); +alter table test_drop_column_cstore_1 drop column c; +insert into test_drop_column_cstore_1 select * from test_drop_column_cstore_2; +insert into test_drop_column_cstore_1 select * from test_drop_column_cstore_2 order by 2; +insert into test_drop_column_cstore_1 select test_drop_column_cstore_2.a, test_drop_column_cstore_3.a from test_drop_column_cstore_2, test_drop_column_cstore_3 where test_drop_column_cstore_2.a = test_drop_column_cstore_3.a; + +drop table test_drop_column_1; +drop table test_drop_column_2; +drop table test_drop_column_3; +drop table test_drop_column_cstore_1; +drop table test_drop_column_cstore_2; +drop table test_drop_column_cstore_3; + +create table test_hash (a int, b int); +create sequence test_seq1; +alter table test_hash alter column a type serial; --fail +alter table test_hash alter column a set default nextval('test_seq1'); +insert into test_hash(b) values(generate_series(1,10)); +alter table test_hash add column c serial; --not supported +alter table test_hash add column d int default nextval('test_seq1'); --not supported +alter table test_hash add column e int default nextval('test_seq1')*10; --not supported +--drop table test_hash; +alter table test_hash alter column a drop default; +drop sequence test_seq1; + +-- check column addition within a view (bug #14876) +create table at_base_table(id int, stuff text); +insert into at_base_table values (23, 'skidoo'); +create view at_view_1 as select * from at_base_table bt; +create view at_view_2 as select *, v1 as j from at_view_1 v1; +\d+ at_view_1 +\d+ at_view_2 +explain (verbose, costs off) select * from at_view_2; +select * from at_view_2; + +create or replace view at_view_1 as select *, 2+2 as more from at_base_table bt; +\d+ at_view_1 +\d+ at_view_2 +explain (verbose, costs off) select * from at_view_2; +select * from at_view_2; + +drop view at_view_2; +drop view at_view_1; +--drop table at_base_table; + +create table tt_row_rep_1(a int); +alter table tt_row_rep_1 drop column a; + +create table tt_row_rep_2(a int, b int); +alter table tt_row_rep_2 drop column b; +alter table tt_row_rep_2 drop column a; + +create table tt_col_rep_1(a int) with(orientation=column); +alter table tt_col_rep_1 drop column a; + +create table tt_col_rep_2(a int, b int) with(orientation=column); +alter table tt_col_rep_2 drop column b; +alter table tt_col_rep_2 drop column a; + +--drop table tt_row_rep_1; +--drop table tt_row_rep_2; +drop table tt_col_rep_1; +drop table tt_col_rep_2; + +-- renaming constraints with cache reset of target relation +CREATE TABLE constraint_rename_cache (a int, + CONSTRAINT chk_a CHECK (a > 0), + PRIMARY KEY (a)); +ALTER TABLE constraint_rename_cache + RENAME CONSTRAINT chk_a TO chk_a_new; +ALTER TABLE constraint_rename_cache + RENAME CONSTRAINT constraint_rename_cache_pkey TO constraint_rename_pkey_new; +CREATE TABLE like_constraint_rename_cache + (LIKE constraint_rename_cache INCLUDING ALL); +\d like_constraint_rename_cache +--drop table constraint_rename_cache; +--drop table like_constraint_rename_cache; + + + +create table t_alter_type(c0 int4range Unique, foreign key(c0) references t_alter_type(c0)); +alter table t_alter_type alter c0 set data type int4range; + +----drop table t_alter_type; + +CREATE TABLE MODIFY_TABLE_A(I INTEGER); +\d MODIFY_TABLE_A +create table aaa(a integer); +\d aaa +create table bbb(B integer); +\d bbb +create table CCC(c integer); +\d CCC +create table DDD(D integer); +\d DDD +create table EEE("E" integer); +\d EEE +create table FFF("FF" integer); +\d FFF +create table HHH("HH" integer); + +alter table aaa rename a to AA; +\d aaa +create table GGG("GdGG" integer); +alter table CCC rename c to "CC"; +alter table FFF rename FF to ff; -- differnt in b compatibility +alter table HHH rename "HH" to gg; + +rename table public.HHH to public.hhh; +rename table public.hhh to public.hhh1; + +create table aaaaa (b int generated by default as identity,c int); +\dS aaaaa_b_seq +insert into aaaaa(c) values(213); +insert into aaaaa(c) values(21); +insert into aaaaa values(3,121); +insert into aaaaa(c) values(111); +insert into aaaaa values(null,212); +alter table aaaaa alter column b drop default; +drop sequence aaaaa_b_seq; diff --git a/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_fastcheck.setup b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_fastcheck.setup new file mode 100644 index 000000000..db2469581 --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_fastcheck.setup @@ -0,0 +1,11 @@ +#!/bin/sh + +source $1/env_utils.sh $1 $2 +subscription_dir=$1 +case_use_db=$3 + +exec_sql_with_user $case_use_db $pub_node1_port "create schema fastcheck;set search_path=fastcheck;create table t1_full (a int, b text);insert into t1_full values (1, 'a'), (2, 'b'), (3, 'c');alter table t1_full replica identity full;" +exec_sql_with_user $case_use_db $sub_node1_port "create schema fastcheck;set search_path=fastcheck;create table t1_full (a int, b text, myc int); insert into t1_full values (101, 'a', 1), (102, 'b', 2);" + +exec_sql_with_user $case_use_db $pub_node1_port "set search_path=fastcheck;create table tkey1 (a int primary key, b text);insert into tkey1 values (1, 'a'), (2, 'b'), (3, 'c');alter table tkey1 replica identity default;" +exec_sql_with_user $case_use_db $sub_node1_port "set search_path=fastcheck;create table tkey1 (a int primary key, b text, myc int); insert into tkey1 values (101, '101a', 1), (102, '102b', 2);" \ No newline at end of file diff --git a/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_fastcheck.sql b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_fastcheck.sql new file mode 100644 index 000000000..32fe5b270 --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_fastcheck.sql @@ -0,0 +1,692 @@ +-- +--FOR BLACKLIST FEATURE: REFERENCES/WITH OIDS/RULE/CREATE TYPE/DOMAIN is not supported. +-- + +-- +-- ALTER_TABLE +-- add attribute +-- +set search_path=fastcheck; +CREATE TABLE atmp1 (initial int4); + +COMMENT ON TABLE tmp_wrong IS 'table comment'; +COMMENT ON TABLE atmp1 IS 'table comment'; +COMMENT ON TABLE atmp1 IS NULL; + +ALTER TABLE atmp1 ADD COLUMN xmin integer; -- fails + +ALTER TABLE atmp1 ADD COLUMN a int4 default 3; + +ALTER TABLE atmp1 ADD COLUMN b name; + +ALTER TABLE atmp1 ADD COLUMN c text; + +ALTER TABLE atmp1 ADD COLUMN d float8; + +ALTER TABLE atmp1 ADD COLUMN e float4; + +ALTER TABLE atmp1 ADD COLUMN f int2; + +ALTER TABLE atmp1 ADD COLUMN g polygon; + +ALTER TABLE atmp1 ADD COLUMN h abstime; + +ALTER TABLE atmp1 ADD COLUMN i char; + +ALTER TABLE atmp1 ADD COLUMN j abstime[]; + +ALTER TABLE atmp1 ADD COLUMN k int4; + +ALTER TABLE atmp1 ADD COLUMN l tid; + +ALTER TABLE atmp1 ADD COLUMN m xid; + +ALTER TABLE atmp1 ADD COLUMN n oidvector; + +--ALTER TABLE atmp1 ADD COLUMN o lock; +ALTER TABLE atmp1 ADD COLUMN p smgr; + +ALTER TABLE atmp1 ADD COLUMN q point; + +ALTER TABLE atmp1 ADD COLUMN r lseg; + +ALTER TABLE atmp1 ADD COLUMN s path; + +ALTER TABLE atmp1 ADD COLUMN t box; + +ALTER TABLE atmp1 ADD COLUMN u tinterval; + +ALTER TABLE atmp1 ADD COLUMN v timestamp; + +ALTER TABLE atmp1 ADD COLUMN w interval; + +ALTER TABLE atmp1 ADD COLUMN x float8[]; + +ALTER TABLE atmp1 ADD COLUMN y float4[]; + +ALTER TABLE atmp1 ADD COLUMN z int2[]; + +INSERT INTO atmp1 (a, b, c, d, e, f, g, h, i, j, k, l, m, n, p, q, r, s, t, u, + v, w, x, y, z) + VALUES (4, 'name', 'text', 4.1, 4.1, 2, '(4.1,4.1,3.1,3.1)', + 'Mon May 1 00:30:30 1995', 'c', '{Mon May 1 00:30:30 1995, Monday Aug 24 14:43:07 1992, epoch}', + 314159, '(1,1)', '512', + '1 2 3 4 5 6 7 8', 'magnetic disk', '(1.1,1.1)', '(4.1,4.1,3.1,3.1)', + '(0,2,4.1,4.1,3.1,3.1)', '(4.1,4.1,3.1,3.1)', '["epoch" "infinity"]', + 'epoch', '01:00:10', '{1.0,2.0,3.0,4.0}', '{1.0,2.0,3.0,4.0}', '{1,2,3,4}'); + +SELECT * FROM atmp1; + +----drop table tmp; + +-- the wolf bug - schema mods caused inconsistent row descriptors +CREATE TABLE atmp2 ( + initial int4 +); + +ALTER TABLE atmp2 ADD COLUMN a int4; + +ALTER TABLE atmp2 ADD COLUMN b name; + +ALTER TABLE atmp2 ADD COLUMN c text; + +ALTER TABLE atmp2 ADD COLUMN d float8; + +ALTER TABLE atmp2 ADD COLUMN e float4; + +ALTER TABLE atmp2 ADD COLUMN f int2; + +ALTER TABLE atmp2 ADD COLUMN g polygon; + +ALTER TABLE atmp2 ADD COLUMN h abstime; + +ALTER TABLE atmp2 ADD COLUMN i char; + +ALTER TABLE atmp2 ADD COLUMN j abstime[]; + +ALTER TABLE atmp2 ADD COLUMN k int4; + +ALTER TABLE atmp2 ADD COLUMN l tid; + +ALTER TABLE atmp2 ADD COLUMN m xid; + +ALTER TABLE atmp2 ADD COLUMN n oidvector; + +--ALTER TABLE atmp2 ADD COLUMN o lock; +ALTER TABLE atmp2 ADD COLUMN p smgr; + +ALTER TABLE atmp2 ADD COLUMN q point; + +ALTER TABLE atmp2 ADD COLUMN r lseg; + +ALTER TABLE atmp2 ADD COLUMN s path; + +ALTER TABLE atmp2 ADD COLUMN t box; + +ALTER TABLE atmp2 ADD COLUMN u tinterval; + +ALTER TABLE atmp2 ADD COLUMN v timestamp; + +ALTER TABLE atmp2 ADD COLUMN w interval; + +ALTER TABLE atmp2 ADD COLUMN x float8[]; + +ALTER TABLE atmp2 ADD COLUMN y float4[]; + +ALTER TABLE atmp2 ADD COLUMN z int2[]; + +INSERT INTO atmp2 (a, b, c, d, e, f, g, h, i, j, k, l, m, n, p, q, r, s, t, u, + v, w, x, y, z) + VALUES (4, 'name', 'text', 4.1, 4.1, 2, '(4.1,4.1,3.1,3.1)', + 'Mon May 1 00:30:30 1995', 'c', '{Mon May 1 00:30:30 1995, Monday Aug 24 14:43:07 1992, epoch}', + 314159, '(1,1)', '512', + '1 2 3 4 5 6 7 8', 'magnetic disk', '(1.1,1.1)', '(4.1,4.1,3.1,3.1)', + '(0,2,4.1,4.1,3.1,3.1)', '(4.1,4.1,3.1,3.1)', '["epoch" "infinity"]', + 'epoch', '01:00:10', '{1.0,2.0,3.0,4.0}', '{1.0,2.0,3.0,4.0}', '{1,2,3,4}'); + +SELECT * FROM atmp2; + +----drop table tmp; + + +-- +-- rename - check on both non-temp and temp tables +-- +CREATE TABLE atmp3 (regtable int); +-- Enforce use of COMMIT instead of 2PC for temporary objects + + +CREATE TABLE onek ( + unique1 int4, + unique2 int4, + two int4, + four int4, + ten int4, + twenty int4, + hundred int4, + thousand int4, + twothousand int4, + fivethous int4, + tenthous int4, + odd int4, + even int4, + stringu1 name, + stringu2 name, + string4 name +) with(autovacuum_enabled = off); +CREATE INDEX onek_unique1 ON onek USING btree(unique1 int4_ops); + +CREATE TABLE tenk1 ( + unique1 int4, + unique2 int4, + two int4, + four int4, + ten int4, + twenty int4, + hundred int4, + thousand int4, + twothousand int4, + fivethous int4, + tenthous int4, + odd int4, + even int4, + stringu1 name, + stringu2 name, + string4 name +) with(autovacuum_enabled = off); + +CREATE TABLE stud_emp ( + name text, + age int4, + location point, + salary int4, + manager name, + gpa float8, + percent int4 +) with(autovacuum_enabled = off); + +-- ALTER TABLE ... RENAME on non-table relations +-- renaming indexes (FIXME: this should probably test the index's functionality) +ALTER INDEX IF EXISTS __onek_unique1 RENAME TO tmp_onek_unique1; +ALTER INDEX IF EXISTS __tmp_onek_unique1 RENAME TO onek_unique1; + +ALTER INDEX onek_unique1 RENAME TO tmp_onek_unique1; +ALTER INDEX tmp_onek_unique1 RENAME TO onek_unique1; + +-- renaming views +CREATE VIEW tmp_view (unique1) AS SELECT unique1 FROM tenk1; +ALTER TABLE tmp_view RENAME TO tmp_view_new; + +DROP VIEW tmp_view_new; +-- toast-like relation name +alter table stud_emp rename to pg_toast_stud_emp; +alter table pg_toast_stud_emp rename to stud_emp; + +-- renaming index should rename constraint as well +ALTER TABLE onek ADD CONSTRAINT onek_unique1_constraint UNIQUE (unique1); +ALTER INDEX onek_unique1_constraint RENAME TO onek_unique1_constraint_foo; +ALTER TABLE onek DROP CONSTRAINT onek_unique1_constraint_foo; + +-- renaming constraint +ALTER TABLE onek ADD CONSTRAINT onek_check_constraint CHECK (unique1 >= 0); +ALTER TABLE onek RENAME CONSTRAINT onek_check_constraint TO onek_check_constraint_foo; +ALTER TABLE onek DROP CONSTRAINT onek_check_constraint_foo; + +-- renaming constraint should rename index as well +ALTER TABLE onek ADD CONSTRAINT onek_unique1_constraint UNIQUE (unique1); +DROP INDEX onek_unique1_constraint; -- to see whether it's there +ALTER TABLE onek RENAME CONSTRAINT onek_unique1_constraint TO onek_unique1_constraint_foo; +DROP INDEX onek_unique1_constraint_foo; -- to see whether it's there +ALTER TABLE onek DROP CONSTRAINT onek_unique1_constraint_foo; + +-- renaming constraints vs. inheritance +CREATE TABLE constraint_rename_test (a int CONSTRAINT con1 CHECK (a > 0), b int, c int); +\d constraint_rename_test + +create table test_modify (a int, b int); +alter table test_modify replica identity full; +alter table test_modify modify (b not null enable); +insert into test_modify(b) values (null); +insert into test_modify values (1, null); +alter table test_modify modify(b null); +insert into test_modify values (1, null); +alter table test_modify modify (b not null enable); +alter table test_modify replica identity full; +delete from test_modify; +alter table test_modify modify (a not null, b not null); +insert into test_modify values (1,null); +insert into test_modify values (null,1); +alter table test_modify modify (a null, b null); +insert into test_modify values (1,null); +insert into test_modify values (null,1); +alter table test_modify modify (b constraint ak not null); +delete from test_modify; +alter table test_modify modify (b constraint ak not null); +insert into test_modify values(1,1); +insert into test_modify values(1,null); +alter table test_modify modify (b constraint ak null); +insert into test_modify values(1,null); +alter table test_modify modify (a null, a not null); +-- try alter view should fail +create view test_modify_view as select * from test_modify; +alter table test_modify_view modify (a not null enable); +drop view test_modify_view; +--drop table test_modify; + + +-- test setting and removing default values +create table def_test ( + c1 int4 default 5, + c2 text default 'initial_default' +); +insert into def_test default values; +alter table def_test alter column c1 drop default; +insert into def_test default values; +alter table def_test alter column c2 drop default; +insert into def_test default values; +alter table def_test alter column c1 set default 10; +alter table def_test alter column c2 set default 'new_default'; +insert into def_test default values; +select * from def_test order by 1, 2; + +-- set defaults to an incorrect type: this should fail +alter table def_test alter column c1 set default 'wrong_datatype'; +alter table def_test alter column c2 set default 20; + +-- set defaults on a non-existent column: this should fail +alter table def_test alter column c3 set default 30; + +create type mytype as (a text); +create table foo (f1 text, f2 mytype, f3 text); + +insert into foo values('bb','cc','dd'); +select * from foo order by f1; + +-- drop domain mytype cascade; + +select * from foo order by f1; +insert into foo values('qq','rr'); +select * from foo order by f1; +alter table foo replica identity full; +update foo set f3 = 'zz'; +select * from foo order by f1; +select f3,max(f1) from foo group by f3; + +-- Simple tests for alter table column type +alter table foo replica identity full; +delete from foo where f1 = 'qq'; +alter table foo alter f1 TYPE integer; -- fails +alter table foo alter f1 TYPE varchar(10); +--drop table foo; + + +CREATE TABLE TBL_DOMAIN +( + IDOMAINID NUMBER(10) NOT NULL, + SDOMAINNAME VARCHAR2(30) NOT NULL +); +--create/recreate primary, unique and foreign key constraints +ALTER TABLE TBL_DOMAIN + ADD CONSTRAINT PK_TBL_DOMAIN PRIMARY KEY (IDOMAINID) + USING INDEX ; + +ALTER TABLE TBL_DOMAIN + ADD CONSTRAINT IX_TBL_DOMAIN UNIQUE (SDOMAINNAME) + USING INDEX ; +\d+ TBL_DOMAIN +--drop table TBL_DOMAIN; + +--create table +CREATE TABLE TBL_CM_MAXTSENDTOHOST +( + I_MODULETYPE NUMBER(38) NOT NULL, + I_MODULENO NUMBER(38) NOT NULL, + I_PLAMODULENO NUMBER(38) NOT NULL, + I_TABLEID NUMBER(38) NOT NULL, + I_OLDMAXTUPLE NUMBER(38) NOT NULL, + I_NEWMAXTUPLE NUMBER(38) NOT NULL, + I_RESERVED1 NUMBER(38) DEFAULT 0, + I_RESERVED2 NUMBER(38) DEFAULT 0, + I_RESERVED3 NUMBER(38) DEFAULT 0, + I_RESERVED4 NUMBER(38) DEFAULT 0, + I_RESERVED5 NUMBER(38) DEFAULT 0, + I_RESERVED6 NUMBER(38) DEFAULT 0, + I_RESERVED7 NUMBER(38) DEFAULT 0, + SV_RESERVED8 VARCHAR2(32) DEFAULT '', + SV_RESERVED9 VARCHAR2(32) DEFAULT '', + SV_RESERVED10 VARCHAR2(32) DEFAULT '' +) + PCTFREE 10 + INITRANS 1 + MAXTRANS 255 + STORAGE + ( + INITIAL 64K + MINEXTENTS 1 + MAXEXTENTS UNLIMITED + ) + ; +--add primary key +ALTER TABLE TBL_CM_MAXTSENDTOHOST + ADD PRIMARY KEY (I_PLAMODULENO, I_TABLEID) + USING INDEX + PCTFREE 10 + INITRANS 2 + MAXTRANS 255 + STORAGE + ( + INITIAL 64K + MINEXTENTS 1 + MAXEXTENTS UNLIMITED + ); + \d+ TBL_CM_MAXTSENDTOHOST + --drop table TBL_CM_MAXTSENDTOHOST; + +--create table +CREATE TABLE TBL_LICCTRLDESC_DEFAULT +( + I_INDEX NUMBER(38) NOT NULL, + SV_FEATURENAME VARCHAR2(64) NOT NULL, + SV_ITEMNAME VARCHAR2(64) NOT NULL, + I_ITEMTYPE NUMBER(38) NOT NULL, + I_ITEMVALUEMIN NUMBER(38) NOT NULL, + I_ITEMVALUEMAX NUMBER(38) NOT NULL, + I_RESERVED1 NUMBER(38) DEFAULT 0, + I_RESERVED2 NUMBER(38) DEFAULT 0, + I_RESERVED3 NUMBER(38) DEFAULT 0, + I_RESERVED4 NUMBER(38) DEFAULT 0, + I_RESERVED5 NUMBER(38) DEFAULT 0, + I_RESERVED6 NUMBER(38) DEFAULT 0, + I_RESERVED7 NUMBER(38) DEFAULT 0, + SV_RESERVED8 VARCHAR2(32) DEFAULT '', + SV_RESERVED9 VARCHAR2(32) DEFAULT '', + SV_RESERVED10 VARCHAR2(32) DEFAULT '', + I_STATUS NUMBER(38) NOT NULL +) + PCTFREE 10 + INITRANS 1 + MAXTRANS 255 + STORAGE + ( + INITIAL 64K + MINEXTENTS 1 + MAXEXTENTS UNLIMITED + ) + ; +--add primary key +ALTER TABLE TBL_LICCTRLDESC_DEFAULT + ADD PRIMARY KEY (I_INDEX) + USING INDEX + PCTFREE 10 + INITRANS 2 + MAXTRANS 255 + STORAGE + ( + INITIAL 64K + MINEXTENTS 1 + MAXEXTENTS UNLIMITED + ); +--add unique index +CREATE UNIQUE INDEX IDX_TBL_LICCTRL_DEF ON TBL_LICCTRLDESC_DEFAULT (I_INDEX DESC, I_STATUS) + PCTFREE 10 + INITRANS 2 + MAXTRANS 255 + STORAGE + ( + INITIAL 64K + MINEXTENTS 1 + MAXEXTENTS UNLIMITED + ); +\d+ TBL_LICCTRLDESC_DEFAULT + --drop table TBL_LICCTRLDESC_DEFAULT; +--using index clause +CREATE TABLE STUDENTS +( + ID INT, + NAME VARCHAR2(20), + AGE INT, + ADDRESS VARCHAR(30) +); + --alter table to add unique index or primary key +ALTER TABLE STUDENTS ADD UNIQUE (ID) +USING INDEX +PCTFREE 10 +INITRANS 2 +MAXTRANS 255 +STORAGE +( + INITIAL 64K + MINEXTENTS 1 + MAXEXTENTS UNLIMITED +); + +ALTER TABLE STUDENTS ADD CONSTRAINT ZHANGYG UNIQUE (AGE, ADDRESS) +USING INDEX +PCTFREE 10 +INITRANS 2 +MAXTRANS 255 +STORAGE +( + INITIAL 64K + MINEXTENTS 1 + MAXEXTENTS UNLIMITED +); + +ALTER TABLE STUDENTS ADD PRIMARY KEY (AGE) +USING INDEX +PCTFREE 10 +INITRANS 2 +MAXTRANS 255 +STORAGE +( + INITIAL 64K + MINEXTENTS 1 + MAXEXTENTS UNLIMITED +); +\d+ STUDENTS +--drop table STUDENTS; +--simulate A db's ALTER TABLE gram +CREATE TABLE MODIFY_TABLE_A(I INTEGER); +ALTER TABLE MODIFY_TABLE_A ADD (mychar CHAR); +ALTER TABLE MODIFY_TABLE_A ADD (myint1 INT, mychar1 CHAR); +ALTER TABLE MODIFY_TABLE_A ADD (myint2 INT, mychar2 CHAR, mychar3 CHAR); +ALTER TABLE MODIFY_TABLE_A ADD a CHAR, ADD b CHAR; +\d MODIFY_TABLE_A +ALTER TABLE MODIFY_TABLE_A ADD mychar4 CHAR; +\d MODIFY_TABLE_A +ALTER TABLE MODIFY_TABLE_A MODIFY I VARCHAR2(64); +\d MODIFY_TABLE_A +ALTER TABLE MODIFY_TABLE_A MODIFY I CHAR, MODIFY myint1 CHAR; +\d MODIFY_TABLE_A +ALTER TABLE MODIFY_TABLE_A MODIFY (myint1 VARCHAR(12)); +\d MODIFY_TABLE_A +ALTER TABLE MODIFY_TABLE_A MODIFY (myint1 VARCHAR(13), mychar1 INT); +\d MODIFY_TABLE_A +ALTER TABLE MODIFY_TABLE_A MODIFY (myint1 VARCHAR(13), myint1 INT); +--drop table MODIFY_TABLE_A; + + +CREATE SCHEMA test_sche; +CREATE TABLE test_sche.logical_TB1( +c1 integer, +c2 date, +c3 text) +partition by system +( +partition p1, +partition p2, +partition p3); + +insert into test_sche.logical_TB1 partition(p1) values(1,'2022-01-01','p1'); +insert into test_sche.logical_TB1 partition(p2) values(2,'2022-02-01','p2'); +insert into test_sche.logical_TB1 partition(p2) values(3,'2022-02-01','p3'); +truncate test_sche.logical_TB1; +--drop table test_sche.logical_TB1; + +CREATE TABLE MODIFY_TABLE_A(I INTEGER); +\d MODIFY_TABLE_A +create table aaa(a integer); +\d aaa +create table bbb(B integer); +\d bbb +create table CCC(c integer); +\d CCC +create table DDD(D integer); +\d DDD +create table EEE("E" integer); +\d EEE +create table FFF("FF" integer); +\d FFF +create table HHH("HH" integer); + +alter table aaa rename a to AA; +\d aaa +create table GGG("GdGG" integer); +alter table CCC rename c to "CC"; +alter table FFF rename FF to ff; -- differnt in b compatibility +alter table HHH rename "HH" to gg; + +rename table public.HHH to public.hhh; +rename table public.hhh to public.hhh1; + +insert into t1_full values (4,'d'); +insert into t1_full values (5, 'e'); +create type mytyp as (a int, b text); +alter table t1_full add column c timestamp default now() not null first; +alter table t1_full add column d timestamp on update current_timestamp; + +alter table t1_full add column e int auto_increment unique; +alter table t1_full alter column b set data type timestamp using now(); +alter table t1_full add column ff mytyp default(1, now()::text); +alter table t1_full add column ff33 mytyp default(1, current_timestamp(3)::text); + +alter table t1_full rename to t1_repl_index; +alter table t1_repl_index add constraint t1_pkey_a primary key (a); +alter table t1_repl_index replica identity default; +alter table t1_repl_index add column f int auto_increment unique; +alter table t1_repl_index add column f int auto_increment null unique; +alter table t1_repl_index alter column b set data type timestamp using now(); +alter table t1_repl_index add column e timestamp default now() not null; +alter table t1_repl_index alter column e set data type float using random(); +alter table t1_repl_index add column h int default random(); +alter table t1_repl_index add column h int; +alter table t1_repl_index alter column h set data type float; +update t1_repl_index set h=random(); +alter table t1_repl_index add column g timestamp generated always as (b + '1 year'); +insert into t1_repl_index (a) values (200), (201), (202); +alter table t1_repl_index modify column f int; + +insert into tkey1 values (10), (12); +alter table tkey1 modify column b float4 auto_increment unique; +alter table tkey1 modify column b int auto_increment null unique; +alter table tkey1 modify column b int; + +create table blobtbl (id int primary key, a blob, b raw, c clob, d bytea); +alter table blobtbl replica identity default; +insert into blobtbl values (1, utl_raw.cast_to_raw('this is blob'), utl_raw.cast_to_raw('this is raw'), 'this is clob', decode('this is bytea', 'escape')); +insert into blobtbl values (2, utl_raw.cast_to_raw('this is blob2'), utl_raw.cast_to_raw('this is raw2'), 'this is clob2', decode('this is bytea2', 'escape')); +insert into blobtbl values (3, utl_raw.cast_to_raw('this is blob3'), utl_raw.cast_to_raw('this is raw3'), 'this is clob3', decode('this is bytea3', 'escape')); + +update blobtbl set a=utl_raw.cast_to_raw('this is blob after update'), b=utl_raw.cast_to_raw('this is raw after update'), c='this is clob after update', d=decode('this is bytea after i[date]', 'escape') where id=2; +delete from blobtbl where id=3; + +select utl_raw.cast_to_varchar2(a) as blob_col, utl_raw.cast_to_varchar2(b) as raw_col, cast(c as varchar) as clob_col, encode(d, 'escape') as bytea_col into blobtbl_1 from blobtbl; + +create table blobtbl_2 as (select utl_raw.cast_to_varchar2(a) as blob_col, utl_raw.cast_to_varchar2(b) as raw_col, cast(c as varchar) as clob_col, encode(d, 'escape') as bytea_col from blobtbl); + +create schema testb; +set search_path='testb'; +create table t1 (a int, b timestamp without time zone); +alter table t1 alter column b set default now(); +alter table t1 modify column b timestamp on update current_timestamp; +insert into t1 (a,b) values (1,default), (2,default),(3,'1900-01-01 1:00:00'); +alter table t1 replica identity full; +create type typ1 as (a int, b text); + +alter table t1 add column c typ1 default(1, now()::text); +alter type typ1 add attribute c timestamp; +alter table t1 add constraint t1_pkey primary key (a); +alter table t1 replica identity default; +alter table t1 alter column b set data type timestamp using now() - a; +create type typ2; +create type typ2 as (a int, b int); +alter type typ2 drop attribute a; +drop type typ2; + +create table tab1_1163900(id int not null,a1 text) partition by range(id); +create table tab2_1163900(id int not null,a1 text) partition by list(id); +create table tab3_1163900(id int not null,a1 text) partition by hash(id); + +create table t1_1163900(id int not null,a1 text); +create table t2_1163900(id int not null,a1 text); +create table t3_1163900(id int not null,a1 text); +--insert; +insert into t1_1163900(id,a1) select generate_series(1,100),'a'; +--t3_1163900; +insert into t3_1163900(id,a1) select generate_series(1,100),'a'; +--t2_1163900; +do $$ +declare +begin +for i in 1..100 loop +insert into t2_1163900 values(20,'a'); +end loop; +end $$; + +--attach; +alter table tab1_1163900 attach partition t1_1163900 for values from (1) to (1000); +alter table tab2_1163900 attach partition t2_1163900 for values in(20); +alter table tab3_1163900 attach partition t3_1163900 for values with(modulus 1,remainder 0); + +create table aaaaa1 (b int generated by default as identity (cycle increment by 10),c int); +-- \dS aaaaa_b_seq +-- insert into aaaaa(c) values(213); +-- insert into aaaaa(c) values(21); +-- insert into aaaaa values(3,121); +-- insert into aaaaa(c) values(111); +-- insert into aaaaa values(null,212); +-- alter table aaaaa alter column b drop default; +-- drop sequence aaaaa_b_seq; + +create table bbbb (a int not null); +alter table bbbb alter column a add generated by default as identity; + +create table genalways(id bigint generated always as identity (start 68 cycle maxvalue 70),name varchar(40)); + +create table genalways2(id smallint generated always as identity (start 68 cycle maxvalue 70),name varchar(40)); + +drop table if exists gentest; +create table gentest(id integer PRIMARY KEY, name varchar(40)); +/* AT_AddIdentity */ +ALTER TABLE gentest ALTER id ADD GENERATED ALWAYS AS IDENTITY (start 12 maxvalue 322); +/* AT_SetIdentity in pg compatibility */ +ALTER TABLE gentest ALTER id SET GENERATED ALWAYS; +ALTER TABLE gentest ALTER id DROP IDENTITY; +ALTER TABLE gentest ALTER id ADD GENERATED BY DEFAULT AS IDENTITY (start 99 maxvalue 1000); +ALTER TABLE gentest ALTER id DROP IDENTITY IF EXISTS; +ALTER TABLE gentest ALTER id ADD GENERATED ALWAYS AS IDENTITY (start 33 maxvalue 333); +ALTER TABLE gentest ALTER id SET GENERATED BY DEFAULT; +ALTER TABLE gentest ALTER id RESTART WITH 123; +ALTER TABLE gentest ALTER id RESTART; + +create table test_tab1(id int, c1 text, c2 text); +alter table test_tab1 alter column c1 SET STATISTICS 50; +alter table test_tab1 alter column c2 SET STATISTICS PERCENT 50; +alter table test_tab1 SET COMPRESS; +alter table test_tab1 SET NOCOMPRESS; +alter table test_tab1 COMMENT = 'test_tab1 COMMENT'; +drop table if exists test_tab1; + +create table t1_z (col1 int primary key auto_increment , col2 text,col3 bigint); +insert into t1_z(col1,col2) values(3, 'aaa'); +alter table t1_z auto_increment = 3; + +alter table t1_z OWNER TO regtest_unpriv_user; + +CREATE RULE test_at_modify_rule AS ON INSERT TO t1_z WHERE (col2 is null) DO INSTEAD UPDATE t1_z SET col2='dsgs'; +CREATE RULE test_at_modify_rule AS ON UPDATE TO t1_z DO ALSO NOTIFY regtest_unpriv_user; +alter table t1_z DISABLE RULE test_at_modify_rule; +alter table t1_z ENABLE RULE test_at_modify_rule; +alter table t1_z DISABLE RULE test_at_modify_rule; +alter table t1_z ENABLE ALWAYS RULE test_at_modify_rule; +drop table if exists t1_z; \ No newline at end of file diff --git a/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_fastcheck.teardown b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_fastcheck.teardown new file mode 100644 index 000000000..7b0d5e6eb --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_fastcheck.teardown @@ -0,0 +1,19 @@ +#!/bin/sh + +source $1/env_utils.sh $1 $2 +subscription_dir=$1 +case_use_db=$3 + +exec_sql_with_user $case_use_db $sub_node1_port "set search_path=fastcheck;alter table t1_repl_index drop column myc; alter table tkey1 drop column myc" + +exec_sql_with_user $case_use_db $sub_node1_port "set search_path=fastcheck;delete from t1_repl_index where a in (101,102); delete from tkey1 where a in (101,102);" + +exec_sql_with_user $case_use_db $pub_node1_port "set search_path=fastcheck;select utl_raw.cast_to_varchar2(a) as blob_col, utl_raw.cast_to_varchar2(b) as raw_col, cast(c as varchar) as clob_col, encode(d, 'escape') as bytea_col into blobtbl_pub_1 from blobtbl;" + +exec_sql_with_user $case_use_db $pub_node1_port "set search_path=fastcheck;create table blobtbl_pub_2 as (select utl_raw.cast_to_varchar2(a) as blob_col, utl_raw.cast_to_varchar2(b) as raw_col, cast(c as varchar) as clob_col, encode(d, 'escape') as bytea_col from blobtbl);" + +exec_sql_with_user $case_use_db $sub_node1_port "set search_path=fastcheck;drop table blobtbl_pub_1, blobtbl_pub_2" + +exec_sql_with_user $case_use_db $sub_node1_port "set search_path=fastcheck;select utl_raw.cast_to_varchar2(a) as blob_col, utl_raw.cast_to_varchar2(b) as raw_col, cast(c as varchar) as clob_col, encode(d, 'escape') as bytea_col into blobtbl_pub_1 from blobtbl;" + +exec_sql_with_user $case_use_db $sub_node1_port "set search_path=fastcheck;create table blobtbl_pub_2 as (select utl_raw.cast_to_varchar2(a) as blob_col, utl_raw.cast_to_varchar2(b) as raw_col, cast(c as varchar) as clob_col, encode(d, 'escape') as bytea_col from blobtbl);" diff --git a/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_rewrite.setup b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_rewrite.setup new file mode 100644 index 000000000..61d578e9a --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_rewrite.setup @@ -0,0 +1,9 @@ +#!/bin/sh + +source $1/env_utils.sh $1 $2 +subscription_dir=$1 +case_use_db=$3 + +exec_sql $case_use_db $pub_node1_port "create schema rewrite; set search_path=rewrite;create table t1_full (a int, b text);insert into t1_full values (1, 'a'), (2, 'b'), (3, 'c');alter table t1_full replica identity full;" + +exec_sql $case_use_db $sub_node1_port "create schema rewrite; set search_path=rewrite;create table t1_full (a int, b text, myc int); insert into t1_full values (101, 'a', 1), (102, 'b', 2);" diff --git a/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_rewrite.sql b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_rewrite.sql new file mode 100644 index 000000000..d91d9d0bf --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_rewrite.sql @@ -0,0 +1,26 @@ +set search_path=rewrite; +insert into t1_full values (4,'d'); +alter table t1_full add column c timestamp default now() not null first; +alter table t1_full add column d timestamp; + +alter table t1_full add column e int unique; +alter table t1_full alter column b set data type timestamp using now(); + +alter table t1_full rename to t1_repl_index; +alter table t1_repl_index add constraint t1_pkey_a primary key (a); +alter table t1_repl_index replica identity default; +alter table t1_repl_index add column f int auto_increment unique; +alter table t1_repl_index alter column b set data type timestamp using now(); +alter table t1_repl_index add column e timestamp default now() not null; +alter table t1_repl_index alter column e set data type float using random(); +alter table t1_repl_index add column h int default random(); +alter table t1_repl_index alter column h set data type float; +update t1_repl_index set h=random(); +alter table t1_repl_index add column g timestamp generated always as (b + '1 year'); + +create table t1 (a int, b timestamp without time zone); +alter table t1 alter column b set default now(); +alter table t1 modify column b timestamp on update current_timestamp; +insert into t1 (a,b) values (1,default), (2,default),(3,'1900-01-01 1:00:00'); +alter table t1 replica identity full; +alter table t1 alter column b set data type timestamp using now() - a; diff --git a/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_rewrite.teardown b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_rewrite.teardown new file mode 100644 index 000000000..efb719a1f --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_rewrite.teardown @@ -0,0 +1,8 @@ +#!/bin/sh + +source $1/env_utils.sh $1 $2 +subscription_dir=$1 +case_use_db=$3 + +exec_sql $case_use_db $sub_node1_port "set search_path=rewrite;alter table t1_repl_index drop column myc" +exec_sql $case_use_db $sub_node1_port "set search_path=rewrite;delete from t1_repl_index where a in (101,102)" diff --git a/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_subpartition.setup b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_subpartition.setup new file mode 100644 index 000000000..853b24cd5 --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_subpartition.setup @@ -0,0 +1,24 @@ +#!/bin/sh + +source $1/env_utils.sh $1 $2 +subscription_dir=$1 +case_use_db=$3 + +exec_sql $case_use_db $pub_node1_port "create tablespace ts_subpart_hash_1 relative location 'test/ts_subpart_hash_1'"; + +exec_sql $case_use_db $pub_node1_port "create tablespace ts_subpart_hash_2 relative location 'test/ts_subpart_hash_2'"; +exec_sql $case_use_db $pub_node1_port "create tablespace ts_subpart_hash_test_user relative location 'test/ts_subpart_hash_test_user';" +exec_sql $case_use_db $pub_node1_port "create user user_subpart_hash password 'Test@123';" + +exec_sql $case_use_db $pub_node1_port "grant CREATE, USAGE on schema schema_vastbase_subpartition_hash to user_subpart_hash"; +exec_sql $case_use_db $pub_node1_port "grant CREATE on tablespace ts_subpart_hash_test_user to user_subpart_hash;" + +exec_sql $case_use_db $sub_node1_port "create tablespace ts_subpart_hash_1 relative location 'test/ts_subpart_hash_1'"; + +exec_sql $case_use_db $sub_node1_port "create tablespace ts_subpart_hash_2 relative location 'test/ts_subpart_hash_2'"; +exec_sql $case_use_db $sub_node1_port "create tablespace ts_subpart_hash_test_user relative location 'test/ts_subpart_hash_test_user';" +exec_sql $case_use_db $sub_node1_port "create user user_subpart_hash password 'Test@123';" + +exec_sql $case_use_db $sub_node1_port "grant CREATE, USAGE on schema schema_vastbase_subpartition_hash to user_subpart_hash"; +exec_sql $case_use_db $sub_node1_port "grant CREATE on tablespace ts_subpart_hash_test_user to user_subpart_hash;" + diff --git a/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_subpartition.sql b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_subpartition.sql new file mode 100644 index 000000000..779a26745 --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_alter_table_subpartition.sql @@ -0,0 +1,2156 @@ +CREATE schema schema_vastbase_subpartition_hash; +set search_path to schema_vastbase_subpartition_hash; +-- init +set datestyle = 'ISO, MDY'; +set behavior_compat_options = ''; + +create table t_subpart_normal_table_hash(id int); +create table t_subpart_part_table_hash(id int) +partition by hash(id) +( + partition p1 +); + + + +---------------------------- +-- Hash subpartition syntax +---------------------------- +create table t_subpart_range_hash_1 (id integer, age integer, name varchar(30), sale integer) +partition by range(age) +subpartition by hash(age) +( +partition p1 values less than (10), +partition p2 values less than (100) + ( + subpartition sp1, + subpartition sp2 + ), +partition p3 values less than (200) +); + +create table t_subpart_list_hash_1 (id integer, age integer, name varchar(30), sale integer) +partition by list(age) +subpartition by hash(age) +( +partition p1 values (1, 2, 3, 4, 5), +partition p2 values (10, 20, 30, 40, 50) + ( + subpartition sp1, + subpartition sp2 + ), +partition p3 values (111, 222, 333) +); + +create table t_subpart_hash_hash_1 (id integer, age integer, name varchar(30), sale integer) +partition by hash(age) +subpartition by hash(age) +( +partition p1, +partition p2 + ( + subpartition sp1, + subpartition sp2 + ), +partition p3 +); + +create table t_subpart_range_hash_2 (id integer, age numeric, name varchar(30), bd date) +partition by range(age) +subpartition by hash(id) + subpartition template + ( + subpartition sp1, + subpartition sp2 + ) +( +partition p1 values less than (10), +partition p2 values less than (100) + ( + subpartition sp1, + subpartition sp2 + ), +partition p3 values less than (MAXVALUE) + ( + subpartition sp3, + subpartition sp4 + ) +); + +create table t_subpart_list_hash_2 (id integer, age numeric, name varchar(30), bd date) +partition by list(age) +subpartition by hash(id) + subpartition template + ( + subpartition sp1, + subpartition sp2 + ) +( +partition p1 values (1, 2, 3, 4, 5), +partition p2 values (10, 20, 30, 40, 50) + ( + subpartition sp1, + subpartition sp2 + ), +partition p3 values (100, 200) + ( + subpartition sp3, + subpartition sp4 + ) +); + +create table t_subpart_hash_hash_2 (id integer, age numeric, name varchar(30), bd date) +partition by hash(age) +subpartition by hash(id) + subpartition template + ( + subpartition sp1, + subpartition sp2 + ) +( +partition p1, +partition p2 + ( + subpartition sp1, + subpartition sp2 + ), +partition p3 + ( + subpartition sp3, + subpartition sp4 + ) +); + +create table t_subpart_range_hash_3 (id integer, age numeric, name text, bd timestamp) +partition by range(id, age) +subpartition by hash(id) + subpartitions 2 +( +partition p1 values less than (10, 10.6789), +partition p2 values less than (100, 12345.6789) + subpartitions 3, +partition p3 values less than (MAXVALUE, MAXVALUE) + ( + subpartition sp1, + subpartition sp2 + ) +); + +create table t_subpart_list_hash_3 (id integer, age numeric, name text, bd timestamp) +partition by list(age) +subpartition by hash(id) + subpartitions 2 +( +partition p1 values (10, 10.6789), +partition p2 values (100, 12345.6789) + subpartitions 3, +partition p3 values (DEFAULT) + ( + subpartition sp1, + subpartition sp2 + ) +); + +create table t_subpart_hash_hash_3 (id integer, age numeric, name text, bd timestamp) +partition by hash(age) +subpartition by hash(id) + subpartitions 2 +( +partition p1, +partition p2 + subpartitions 3, +partition p3 + ( + subpartition sp1, + subpartition sp2 + ) +); + +create table t_subpart_hash_hash_4 (id integer, age numeric, name text, bd timestamp) +partition by hash(age) +subpartition by hash(id) + subpartitions 2 +partitions 3; + +select p1.tablename, p1.relname, p1.parttype, p1.partstrategy, p1.subpartstrategy, +p1.parentid, p1.boundaries, p1.relfilenode, p1.reltoastrelid +from schema_subpartition.v_subpartition p1 +where p1.tablename like 't_subpart_range_hash_%' + or p1.tablename like 't_subpart_list_hash_%' + or p1.tablename like 't_subpart_hash_hash_%'; + +select p1.tablename, p1.subparttemplate +from schema_subpartition.v_subpartition p1 +where p1.subparttemplate is not null + and (p1.tablename like 't_subpart_range_hash_%' + or p1.tablename like 't_subpart_list_hash_%' + or p1.tablename like 't_subpart_hash_hash_%'); + +select get_subpart_template('t_subpart_range_hash_1'::regclass, 0) is null; +select pg_get_tabledef('t_subpart_range_hash_1'); +select get_subpart_template('t_subpart_range_hash_2'::regclass, 0); +select get_subpart_template('t_subpart_list_hash_3'::regclass, 2); +select get_subpart_template('t_subpart_hash_hash_4'::regclass, 4); +select pg_get_tabledef('t_subpart_range_hash_2'); +select pg_get_tabledef('t_subpart_list_hash_3'); +select pg_get_tabledef('t_subpart_hash_hash_4'); + +create table t_subpart_range_hash_float4 (col1 float4) +partition by range(col1) +subpartition by hash(col1) + subpartition template + ( + subpartition sp1, + subpartition sp2 + ) +( +partition p1 values less than (-34.84), +partition p2 values less than (0), +partition p3 values less than (1004.3) + ( + subpartition sp1, + subpartition sp2 + ), +partition p4 values less than (1.2345678901234e+20) +); + +create table t_subpart_list_hash_float4 (col1 float4) +partition by list(col1) +subpartition by hash(col1) + subpartition template + ( + subpartition sp1, + subpartition sp2 + ) +( +partition p1 values (-3.1, -3.14, -3.141, -3.1415, -3.14159, -3.141592, -3.1415926), +partition p2 values (0, 10, 100, 1000, 10000) + ( + subpartition sp1, + subpartition sp2 + ), +partition p3 values (1.2345678901234e-20, 1.2345678901234e-10, 1.2345678901234e+10, 1.2345678901234e+20) +); + +create table t_subpart_hash_hash_float4 (col1 float4) +partition by hash(col1) +subpartition by hash(col1) + subpartition template + ( + subpartition sp1, + subpartition sp2 + ) +( +partition p1, +partition p2 + ( + subpartition sp1, + subpartition sp2 + ), +partition p3 +); + +create table t_subpart_range_hash_float8 (col1 float8) +partition by range(col1) +subpartition by hash(col1) + subpartition template + ( + subpartition sp1, + subpartition sp2 + ) +( +partition p1 values less than (-34.84), +partition p2 values less than (0), +partition p3 values less than (1004.3) + ( + subpartition sp1, + subpartition sp2 + ), +partition p4 values less than (1.2345678901234e+200) +); + +create table t_subpart_list_hash_float8 (col1 float8) +partition by list(col1) +subpartition by hash(col1) + subpartition template + ( + subpartition sp1, + subpartition sp2 + ) +( +partition p1 values (-3.1, -3.14, -3.141, -3.1415, -3.14159, -3.141592, -3.1415926), +partition p2 values (0, 10, 100, 1000, 10000) + ( + subpartition sp1, + subpartition sp2 + ), +partition p3 values (1.2345678901234e-200, 1.2345678901234e-100, 1.2345678901234e+100, 1.2345678901234e+200) +); + +create table t_subpart_hash_hash_float8 (col1 float8) +partition by hash(col1) +subpartition by hash(col1) + subpartition template + ( + subpartition sp1, + subpartition sp2 + ) +( +partition p1, +partition p2 + ( + subpartition sp1, + subpartition sp2 + ), +partition p3 +); + +select p1.tablename, p1.relname, p1.parttype, p1.partstrategy, p1.subpartstrategy, +p1.parentid, p1.boundaries, p1.relfilenode, p1.reltoastrelid +from schema_subpartition.v_subpartition p1 +where p1.tablename like 't_subpart_range_hash_float%' + or p1.tablename like 't_subpart_list_hash_float%' + or p1.tablename like 't_subpart_hash_hash_float%'; + +select p1.tablename, p1.subparttemplate +from schema_subpartition.v_subpartition p1 +where p1.subparttemplate is not null + and (p1.tablename like 't_subpart_range_hash_float%' + or p1.tablename like 't_subpart_list_hash_float%' + or p1.tablename like 't_subpart_hash_hash_float%'); + +create table t_subpart_range_hash_7 (id integer primary key, age numeric, name varchar(30), bd date) +partition by range(id) +subpartition by hash(id) + subpartition template + ( + subpartition sp1, + subpartition sp2 + ) +( +partition p1 values less than (100), +partition p2 values less than (500) + ( + subpartition sp1, + subpartition sp2 + ) +); + +create table t_subpart_list_hash_7 (id integer primary key, age numeric, name varchar(30), bd date) +partition by list(id) +subpartition by hash(id) + subpartition template + ( + subpartition sp1, + subpartition sp2 + ) +( +partition p1 values (100), +partition p2 values (500) + ( + subpartition sp1, + subpartition sp2 + ) +); + +create table t_subpart_hash_hash_7 (id integer primary key, age numeric, name varchar(30), bd date) +partition by hash(id) +subpartition by hash(id) + subpartition template + ( + subpartition sp1, + subpartition sp2 + ) +( +partition p1, +partition p2 + ( + subpartition sp1, + subpartition sp2 + ) +); + + +create table t_subpart_range_hash_8 (id integer, age numeric, name char(30), bd date, + CONSTRAINT i_t_subpart_range_hash_8 PRIMARY KEY (id, age, name)) +partition by range(age, name) +subpartition by hash(id) +( +partition p1 values less than (20, 'AAA') +); + +create table t_subpart_list_hash_8 (id integer, age numeric, name char(30), bd date, + CONSTRAINT i_t_subpart_list_hash_8 PRIMARY KEY (id, age, name)) +partition by list(age) +subpartition by hash(id) +( +partition p1 values (20) +); + +create table t_subpart_hash_hash_8 (id integer, age integer, name char(30), bd date, + CONSTRAINT i_t_subpart_hash_hash_8 PRIMARY KEY (id, age, name)) +partition by hash(age) +subpartition by hash(id) +( +partition p1 +); + +create table t_subpart_range_hash_9 (id integer, age numeric, name char(30), bd date, + CONSTRAINT i_t_subpart_range_hash_9 PRIMARY KEY (age, name)) +partition by range(age, name) +subpartition by hash(id) +( +partition p1 values less than (100, 'AAA') +); + +create table t_subpart_list_hash_9 (id integer, age numeric, name char(30), bd date, + CONSTRAINT i_t_subpart_list_hash_9 PRIMARY KEY (id, name)) +partition by list(age) +subpartition by hash(id) +( +partition p1 values (100) +); + +create table t_subpart_hash_hash_9 (id integer, age numeric, name char(30), bd date, + CONSTRAINT i_t_subpart_hash_hash_9 PRIMARY KEY (bd, name)) +partition by hash(age) +subpartition by hash(id) +( +partition p1 +); + +create unique index i_t_subpart_range_hash_8_1 on t_subpart_range_hash_8 (id, bd); +create unique index i_t_subpart_list_hash_8_1 on t_subpart_list_hash_8 (id, bd); +create unique index i_t_subpart_hash_hash_8_1 on t_subpart_hash_hash_8 (id, bd); + + +create table t_subpart_range_hash_10 (id integer, age numeric, name char(30), bd date) +partition by range(age, name) +subpartition by hash(id) +( +partition p1 values less than (10, 'AAA') + ( + subpartition sp1 + ), +partition p2 values less than (100, 'MAXVALUE') + ( + subpartition sp2, + subpartition sp3 + ) +); + +create table t_subpart_list_hash_10 (id integer, age numeric, name char(30), bd date) +partition by list(age) +subpartition by hash(id) +( +partition p1 values (10) + ( + subpartition sp1 + ), +partition p2 values (100) + ( + subpartition sp2, + subpartition sp3 + ) +); + +create table t_subpart_hash_hash_10 (id integer, age integer, name char(30), bd date) +partition by hash(age) +subpartition by hash(id) +( +partition p1 + ( + subpartition sp1 + ), +partition p2 + ( + subpartition sp2, + subpartition sp3 + ) +); + +create unique index i_t_subpart_range_hash_10_1 on t_subpart_range_hash_10 (id) local; -- error +create unique index i_t_subpart_range_hash_10_1 on t_subpart_range_hash_10 (name, age) local; -- error +create unique index i_t_subpart_range_hash_10_1 on t_subpart_range_hash_10 (age, name, id) local; +create index i_t_subpart_range_hash_10_2 on t_subpart_range_hash_10 (name, age) local; + +create unique index i_t_subpart_list_hash_10_1 on t_subpart_list_hash_10 (age) local; -- error +create unique index i_t_subpart_list_hash_10_1 on t_subpart_list_hash_10 (name, bd) local; -- error +create unique index i_t_subpart_list_hash_10_1 on t_subpart_list_hash_10 (age, id) local; +create index i_t_subpart_list_hash_10_2 on t_subpart_list_hash_10 (name, age) local; + +create unique index i_t_subpart_hash_hash_10_1 on t_subpart_hash_hash_10 (bd) local; -- error +create unique index i_t_subpart_hash_hash_10_1 on t_subpart_hash_hash_10 (name, bd) local; -- error +create unique index i_t_subpart_hash_hash_10_1 on t_subpart_hash_hash_10 (age, id, bd) local; +create index i_t_subpart_hash_hash_10_2 on t_subpart_hash_hash_10 (age, bd) local; + +create index i_t_subpart_range_hash_10_3 on t_subpart_range_hash_10 (bd) local +( +partition p1_idx + ( + subpartition subp1_index_local + ), +partition p2_idx + ( + subpartition subp2_index_local + ) +); -- error +create index i_t_subpart_range_hash_10_3 on t_subpart_range_hash_10 (bd) local +( +partition p1_idx + ( + subpartition subp1_bd_idx_local + ), +partition p2_idx + ( + subpartition subp2_bd_idx_local, + subpartition subp3_bd_idx_local + ) +); + +create index i_t_subpart_list_hash_10_3 on t_subpart_list_hash_10 (bd) local +( +partition p1_idx + ( + subpartition subp1_index_local + ), +partition p2_idx + ( + subpartition subp2_index_local + ) +); -- error +create index i_t_subpart_list_hash_10_3 on t_subpart_list_hash_10 (bd) local +( +partition p1_idx + ( + subpartition subp1_bd_idx_local + ), +partition p2_idx + ( + subpartition subp2_bd_idx_local, + subpartition subp3_bd_idx_local + ) +); + +create index i_t_subpart_hash_hash_10_3 on t_subpart_hash_hash_10 (bd) local +( +partition p1_idx + ( + subpartition subp1_index_local + ), +partition p2_idx + ( + subpartition subp2_index_local + ) +); -- error +create index i_t_subpart_hash_hash_10_3 on t_subpart_hash_hash_10 (bd) local +( +partition p1_idx + ( + subpartition subp1_bd_idx_local + ), +partition p2_idx + ( + subpartition subp2_bd_idx_local, + subpartition subp3_bd_idx_local + ) +); + +create unique index i_t_subpart_range_hash_10_4 on t_subpart_range_hash_10 (name, age) global; -- error +create unique index i_t_subpart_range_hash_10_4 on t_subpart_range_hash_10 (age, bd) global; +drop index i_t_subpart_range_hash_10_2; +create unique index i_t_subpart_range_hash_10_5 on t_subpart_range_hash_10 (name, age) global; + +create unique index i_t_subpart_list_hash_10_4 on t_subpart_list_hash_10 (name, age) global; -- error +create unique index i_t_subpart_list_hash_10_4 on t_subpart_list_hash_10 (name, bd) global; +drop index i_t_subpart_list_hash_10_2; +create unique index i_t_subpart_list_hash_10_5 on t_subpart_list_hash_10 (name, age) global; + +create unique index i_t_subpart_hash_hash_10_4 on t_subpart_hash_hash_10 (bd, age) global; -- error +create unique index i_t_subpart_hash_hash_10_4 on t_subpart_hash_hash_10 (name, id) global; +drop index i_t_subpart_hash_hash_10_2; +create unique index i_t_subpart_hash_hash_10_5 on t_subpart_hash_hash_10 (bd, age) global; + + +select p1.tablename, p1.relname, p1.reltoastidxid, p1.indextblid +from schema_subpartition.v_subpartition p1 +where p1.tablename in ('t_subpart_range_hash_7', 't_subpart_range_hash_8', 't_subpart_range_hash_10'); + +select p1.tablename, p1.relname, p1.reltoastidxid, p1.indextblid +from schema_subpartition.v_subpartition p1 +where p1.tablename in ('t_subpart_list_hash_7', 't_subpart_list_hash_8', 't_subpart_list_hash_10'); + +select p1.tablename, p1.relname, p1.reltoastidxid, p1.indextblid +from schema_subpartition.v_subpartition p1 +where p1.tablename in ('t_subpart_hash_hash_7', 't_subpart_hash_hash_8', 't_subpart_hash_hash_10'); + + +select * from pg_indexes where tablename like 't_subpart_range_hash_%' order by tablename, indexname; +select * from pg_indexes where tablename like 't_subpart_list_hash_%' order by tablename, indexname; +select * from pg_indexes where tablename like 't_subpart_hash_hash_%' order by tablename, indexname; + + +-- \d +\d t_subpart_range_hash_8 +\d t_subpart_list_hash_8 +\d t_subpart_hash_hash_8 +\d t_subpart_range_hash_10 +\d t_subpart_list_hash_10 +\d t_subpart_hash_hash_10 + + + +create table t_subpart_range_hash_11 (id integer, age numeric, name varchar(30), bd date) +partition by range(age) +subpartition by hash(id) + subpartition template + ( + subpartition sp1 tablespace ts_subpart_hash_1, + subpartition sp2 + ) +( +partition p1 values less than (10), +partition p2 values less than (100) tablespace ts_subpart_hash_2, +partition p3 values less than (1000) + ( + subpartition sp1 tablespace ts_subpart_hash_1, + subpartition sp2 + ), +partition p4 values less than (MAXVALUE) tablespace ts_subpart_hash_2 + ( + subpartition sp3 tablespace ts_subpart_hash_1, + subpartition sp4 + ) +); + +create table t_subpart_list_hash_11 (id integer, age numeric, name varchar(30), bd date) +partition by list(age) +subpartition by hash(id) + subpartition template + ( + subpartition sp1 tablespace ts_subpart_hash_1, + subpartition sp2 + ) +( +partition p1 values (10), +partition p2 values (20) tablespace ts_subpart_hash_2, +partition p3 values (30) + ( + subpartition sp1 tablespace ts_subpart_hash_1, + subpartition sp2 + ), +partition p4 values (DEFAULT) tablespace ts_subpart_hash_2 + ( + subpartition sp3 tablespace ts_subpart_hash_1, + subpartition sp4 + ) +); + +create table t_subpart_hash_hash_11 (id integer, age numeric, name varchar(30), bd date) +partition by hash(age) +subpartition by hash(id) + subpartition template + ( + subpartition sp1 tablespace ts_subpart_hash_1, + subpartition sp2 + ) +( +partition p1, +partition p2 tablespace ts_subpart_hash_2, +partition p3 + ( + subpartition sp1 tablespace ts_subpart_hash_1, + subpartition sp2 + ), +partition p4 tablespace ts_subpart_hash_2 + ( + subpartition sp3 tablespace ts_subpart_hash_1, + subpartition sp4 + ) +); + +create table t_subpart_hash_hash_11_2 (id integer, age numeric, name varchar(30), bd date) +partition by hash(age) +subpartition by hash(id) + subpartitions 3 store in (ts_subpart_hash_1, ts_subpart_hash_2) +partitions 5 store in (ts_subpart_hash_2, ts_subpart_hash_1); + +alter table t_subpart_hash_hash_11_2 add partition p6; +alter table t_subpart_hash_hash_11_2 modify partition p6 add subpartition p6_sp3; + +select p1.tablename, p1.relname, p1.parttype, p2.spcname tablespace_name +from schema_subpartition.v_subpartition p1 left join pg_tablespace p2 on p1.reltablespace = p2.oid +where p1.tablename in ('t_subpart_range_hash_11', 't_subpart_list_hash_11', 't_subpart_hash_hash_11', 't_subpart_hash_hash_11_2') +order by p1.parentid, p1.oid; + +select p1.tablename, p1.subparttemplate +from schema_subpartition.v_subpartition p1 +where p1.subparttemplate is not null + and p1.tablename in ('t_subpart_range_hash_11', 't_subpart_list_hash_11', 't_subpart_hash_hash_11', 't_subpart_hash_hash_11_2'); + + +SET SESSION AUTHORIZATION user_subpart_hash PASSWORD 'Test@123'; +create table t_subpart_hash_hash_12 (id integer, age numeric, name varchar(30), bd date) +partition by hash(age) +subpartition by hash(id) + subpartition template + ( + subpartition sp1 tablespace ts_subpart_hash_test_user, + subpartition sp2 tablespace ts_subpart_hash_1 + ) +( +partition p1 +); + +create table t_subpart_hash_hash_12 (id integer, age numeric, name varchar(30), bd date) +partition by hash(age) +subpartition by hash(id) +( +partition p1 tablespace ts_subpart_hash_test_user, +partition p2 tablespace ts_subpart_hash_1 +); + +create table t_subpart_hash_hash_12 (id integer, age numeric, name varchar(30), bd date) +partition by hash(age) +subpartition by hash(id) +( +partition p1 + ( + subpartition sp1 tablespace ts_subpart_hash_test_user, + subpartition sp2 tablespace ts_subpart_hash_1 + ) +); + +create table t_subpart_hash_hash_12 (id integer, age numeric, name varchar(30), bd date) +partition by hash(age) +subpartition by hash(id) + subpartitions 2 store in (ts_subpart_hash_test_user, ts_subpart_hash_1) +( +partition p1 +); + +create table t_subpart_hash_hash_12 (id integer, age numeric, name varchar(30), bd date) +partition by hash(age) +subpartition by hash(id) +partitions 2 store in (ts_subpart_hash_test_user, ts_subpart_hash_1); + +create table t_subpart_hash_hash_12 (id integer, age numeric, name varchar(30), bd date) +partition by hash(age) +subpartition by hash(id) +( +partition p1 + subpartitions 2 store in (ts_subpart_hash_test_user, ts_subpart_hash_1) +); + +RESET SESSION AUTHORIZATION; + + + +---------------------------- +-- syntax error +---------------------------- +create table t_subpart_error (id integer, name varchar(30)) +partition by range(id) +( +partition p1 values less than (10) + ( + subpartition sp1 + ) +); + +create table t_subpart_error (id integer, name varchar(30)) +partition by list(id) +( +partition p1 values (10) + ( + subpartition sp1 + ) +); + +create table t_subpart_error (id integer, name varchar(30)) +partition by hash(id) +( +partition p1 + ( + subpartition sp1 + ) +); + + +create table t_subpart_error (id integer, name varchar(30)) +partition by range(name) +subpartition by hash(id) +( +partition p1 values less than ('a') + ( + subpartition sp1 + ), +partition p2 values less than ('A') + ( + subpartition sp1 + ) +); + +create table t_subpart_error (id integer, name varchar(30)) +partition by list(name) +subpartition by hash(id) +( +partition p1 values ('a') + ( + subpartition sp1 + ), +partition p2 values ('A') + ( + subpartition sp1 + ) +); + +create table t_subpart_error (id integer, name int8) +partition by hash(name) +subpartition by hash(id) +( +partition p1 + ( + subpartition sp1 + ), +partition p2 + ( + subpartition sp1 + ) +); + + +create table t_subpart_error (id integer, name varchar(30)) +partition by range(name) +subpartition by hash(id) + subpartition template + ( + subpartition sp1, + subpartition sp1 + ) +( +partition p1 values less than ('a') +); + +create table t_subpart_error (id integer, name varchar(30)) +partition by list(name) +subpartition by hash(id) + subpartition template + ( + subpartition sp1, + subpartition sp1 + ) +( +partition p1 values ('a') +); + +create table t_subpart_error (id integer, name int2) +partition by hash(name) +subpartition by hash(id) + subpartition template + ( + subpartition sp1, + subpartition sp1 + ) +( +partition p1 +); + + + +create table t_subpart_error (id integer, name varchar(30)) +partition by range(name) +subpartition by hash(id) +( +partition p1 values less than ('10') + ( + subpartition sp1 + ), +partition p2 values less than ('100') + ( + subpartition p1 + ) +); + +create table t_subpart_error (id integer, name varchar(30)) +partition by list(id) +subpartition by hash(id) +( +partition p1 values ('10') + ( + subpartition sp1 + ), +partition p2 values ('100') + ( + subpartition p1 + ) +); + +create table t_subpart_error (id integer, name int4) +partition by hash(name) +subpartition by hash(id) +( +partition p1 + ( + subpartition sp1 + ), +partition p2 + ( + subpartition p1 + ) +); +create table t_subpart_error (id integer, name int4) +partition by hash(name) +subpartition by hash(id) +( +partition p1 + ( + subpartition sp1 + ), +partition sp1 + ( + subpartition sp2 + ) +); + + + +create table t_subpart_error (id integer, name text) +partition by range(name) +subpartition by hash(id) +( +partition p1 values less than ('10') + ( + subpartition p2_subpartdefault1 + ), +partition p2 values less than ('100') +); +drop table t_subpart_error; +create table t_subpart_error (id integer, name text) +partition by list(name) +subpartition by hash(id) +( +partition p1 values ('10') + ( + subpartition p2_subpartdefault1 + ), +partition p2 values ('100') +); +drop table t_subpart_error; +create table t_subpart_error (id integer, name integer) +partition by hash(name) +subpartition by hash(id) +( +partition p1 + ( + subpartition p2_subpartdefault1 + ), +partition p2 +); +drop table t_subpart_error; +create table t_subpart_error (id integer, name varchar(30)) +partition by hash(id) +subpartition by hash(id) +( +partition p1, +partition p2 + ( + subpartition p1_subpartdefault1 + ) +); +drop table t_subpart_error; + + +create table t_subpart_error (id integer, name varchar(30), age int, bd varchar(30), addr varchar(30)) +partition by hash(id) +subpartition by hash(id, name, age, bd, addr) +( +partition p1 +); + + +create table t_subpart_error (id integer, name varchar(30), m money) +partition by hash(id) +subpartition by hash(m) +( +partition p1 +); +create table t_subpart_error (id integer, name varchar(30), m money) -- now is ok +partition by hash(id) +subpartition by hash(name) +( +partition p1 +); +drop table t_subpart_error; +create table t_subpart_error (id integer, name varchar(30), bd date) -- now is ok +partition by hash(id) +subpartition by hash(bd) +( +partition p1 +); +drop table t_subpart_error; + + +create table t_subpart_error (id integer, name varchar(30), age int) +partition by hash(id) +subpartition by hash(age) +( +partition p1 + ( + subpartition sp1 values less than (1) + ) +); +create table t_subpart_error (id integer, name varchar(30), age int) +partition by hash(id) +subpartition by hash(age) +( +partition p1 + ( + subpartition sp1 end (1) + ) +); + +create table t_subpart_error (id integer, name varchar(30)) +partition by hash(id) +subpartition by hash(name) +( +partition p1 + ( + subpartition sp1 values ('a', 'b') + ) +); + +create table t_subpart_error (id integer, name varchar(30)) +partition by hash(id) +subpartition by hash(name) + subpartition template + ( + subpartition sp1 values less than (1) + ) +( +partition p1 +); +create table t_subpart_error (id integer, name varchar(30)) +partition by hash(id) +subpartition by hash(name) + subpartition template + ( + subpartition sp1 end (1) + ) +( +partition p1 +); +create table t_subpart_error (id integer, name varchar(30)) +partition by hash(id) +subpartition by hash(name) + subpartition template + ( + subpartition sp1 values ('a') + ) +( +partition p1 +); + + +create table t_subpart_error (id integer, name integer) +partition by hash(id) +subpartition by hash(name) + subpartition template + ( + subpartition sp1 + ( + subpartition ssp1 values (DEFAULT) + ) + ) +( +partition p1 +); + + +create table t_subpart_error (id integer, name integer) +partition by hash(id) +subpartition by hash(name) + subpartition template + ( + subpartition sp1 values (DEFAULT) + ) +( +partition p1 +); +create table t_subpart_error (id integer, name integer) +partition by hash(id) +subpartition by hash(name) + subpartition template + ( + subpartition sp1 values (DEFAULT), + subpartition sp2 + ) +( +partition p1 +); +create table t_subpart_error (id integer, name integer) +partition by hash(id) +subpartition by hash(name) +( +partition p1 + ( + subpartition sp1 values (DEFAULT) + ) +); +create table t_subpart_error (id integer, name integer) +partition by hash(id) +subpartition by hash(name) +( +partition p1 + ( + subpartition sp1 values (DEFAULT), + subpartition sp2 + ) +); + + + +alter table t_subpart_hash_hash_2 drop column age; +alter table t_subpart_hash_hash_2 drop column id; +alter table t_subpart_hash_hash_2 modify (age numeric(6,1)); +alter table t_subpart_hash_hash_2 modify (id text); + + +alter table t_subpart_range_hash_1 add partition p4 values less than (300); +alter table t_subpart_range_hash_1 add partition p5 start (300) end (400) +( + subpartition sp3, + subpartition sp4, + subpartition sp5 +); +alter table t_subpart_range_hash_1 add partition p6 values less than (500) +( + subpartition sp6, + subpartition sys_subp4294967295 +); + +alter table t_subpart_list_hash_1 add partition p4 values (300); +alter table t_subpart_list_hash_1 add partition p5 values (400) +( + subpartition sp3, + subpartition sp4, + subpartition sp5 +); +alter table t_subpart_list_hash_1 add partition p6 values (500) +( + subpartition sp6, + subpartition sys_subp4294967295 +); + +alter table t_subpart_hash_hash_1 add partition p4; +alter table t_subpart_hash_hash_1 add partition p5 +( + subpartition sp3, + subpartition sp4, + subpartition sp5 +); +alter table t_subpart_hash_hash_1 add partition p6 +( + subpartition sp6, + subpartition sys_subp4294967295 +); + + +alter table t_subpart_range_hash_7 add partition p3 end (1000); +alter table t_subpart_range_hash_7 add partition p4 values less than (2000) +( + subpartition sp3, + subpartition p5_sp2 +); +alter table t_subpart_range_hash_10 add partition p3 values less than (MAXVALUE, MAXVALUE) +( + subpartition sp4, + subpartition sp5 +); + +alter table t_subpart_list_hash_7 add partition p3 values (1000); +alter table t_subpart_list_hash_7 add partition p4 values (2000) +( + subpartition sp3, + subpartition p5_sp2 +); +alter table t_subpart_list_hash_10 add partition p3 values (DEFAULT) +( + subpartition sp4, + subpartition sp5 +); +alter table t_subpart_hash_hash_7 add partition p3; +alter table t_subpart_hash_hash_7 add partition p4 +( + subpartition sp3, + subpartition p5_sp2 +); +alter table t_subpart_hash_hash_10 add partition p3 +( + subpartition sp4, + subpartition sp5 +); + + + +alter table t_subpart_normal_table_hash add partition p1; +alter table t_subpart_normal_table_hash add partition p2 +( + subpartition sp1, + subpartition sp2 +); + +alter table t_subpart_part_table_hash add partition p2 +( + subpartition sp1, + subpartition sp2 +); + + +alter table t_subpart_range_hash_1 add partition p_error values (500); +alter table t_subpart_range_hash_1 add partition p_error; +alter table t_subpart_range_hash_1 add partition p7 end (500) +( + subpartition sp_error values less than (100) +); +alter table t_subpart_range_hash_1 add partition p7 end (500) +( + subpartition sp_error start (100) +); +alter table t_subpart_range_hash_1 add partition p7 end (500) +( + subpartition sp_error values (0) +); + +alter table t_subpart_list_hash_1 add partition p_error values less than (500); +alter table t_subpart_list_hash_1 add partition p_error; +alter table t_subpart_list_hash_1 add partition p7 values (700) +( + subpartition sp_error end (100) +); +alter table t_subpart_list_hash_1 add partition p7 values (700) +( + subpartition sp_error values (0) +); + +alter table t_subpart_hash_hash_1 add partition p_error values less than (500); +alter table t_subpart_hash_hash_1 add partition p_error end (500); +alter table t_subpart_hash_hash_1 add partition p_error values (0); +alter table t_subpart_hash_hash_1 add partition p7 +( + subpartition sp_error values less than (100) +); +alter table t_subpart_hash_hash_1 add partition p7 +( + subpartition sp_error end (100) +); +alter table t_subpart_hash_hash_1 add partition p7 +( + subpartition sp_error values (1) +); +alter table t_subpart_hash_hash_1 add partition p7 +( + subpartition sp_error +); +alter table t_subpart_hash_hash_1 add partitions 1; +alter table t_subpart_hash_hash_1 add partition p7 +( + subpartitions 2 +); + + + +alter table t_subpart_hash_hash_1 add partition p_error +( + subpartition sp3, + subpartition sp3 +); +alter table t_subpart_hash_hash_1 add partition p_error +( + subpartition sp3, + subpartition p_error +); +alter table t_subpart_hash_hash_1 add partition p_error +( + subpartition sp1, + subpartition sp22 +); +alter table t_subpart_hash_hash_1 add partition p_error +( + subpartition p1 +); +alter table t_subpart_hash_hash_7 add partition p3; +alter table t_subpart_hash_hash_7 add partition sp1; + + +alter table t_subpart_range_hash_7 add partition p5 values less than (MAXVALUE); +alter table t_subpart_list_hash_7 add partition p5 values (DEFAULT); +alter table t_subpart_hash_hash_7 add partition p5; + + + +alter table t_subpart_range_hash_10 add partition p_error values less than (9999, 9999); +alter table t_subpart_list_hash_10 add partition p_error values (9999); +alter table t_subpart_hash_hash_10 add partition p_error; + + + + +alter table t_subpart_range_hash_1 modify partition p2 add subpartition p2_sp20; +alter table t_subpart_range_hash_10 modify partition p1 add subpartition p1_sp22; + +alter table t_subpart_list_hash_1 modify partition p2 add subpartition p2_sp20; +alter table t_subpart_list_hash_10 modify partition p1 add subpartition p1_sp22; + +alter table t_subpart_hash_hash_1 modify partition p2 add subpartition p2_sp20; +alter table t_subpart_hash_hash_10 modify partition p1 add subpartition p1_sp22; + + +alter table t_subpart_normal_table_hash modify partition p1 add subpartition sp1; +alter table t_subpart_normal_table_hash modify partition p1 add subpartition sp1 +( + subpartition sp3, + subpartition sp4 +); + +alter table t_subpart_part_table_hash modify partition p1 add subpartition sp1; +alter table t_subpart_part_table_hash modify partition p1 add subpartition sp1 +( + subpartition sp3, + subpartition sp4 +); + + +alter table t_subpart_hash_hash_1 modify partition p2 add subpartition sp_error values less than (10); +alter table t_subpart_hash_hash_1 modify partition p2 add subpartition sp_error end (10); +alter table t_subpart_hash_hash_1 modify partition p2 add subpartition sp_error values (1000); + + +alter table t_subpart_range_hash_1 modify partition p_error add subpartition sp_error; +alter table t_subpart_range_hash_1 modify partition for (999) add subpartition sp_error; +alter table t_subpart_list_hash_1 modify partition p_error add subpartition sp_error; +alter table t_subpart_list_hash_1 modify partition for (999) add subpartition sp_error; +alter table t_subpart_hash_hash_1 modify partition p_error add subpartition sp21; +alter table t_subpart_hash_hash_1 modify partition for (999) add subpartition sp_error; + + +alter table t_subpart_range_hash_1 modify partition p2 add subpartition sp1; +alter table t_subpart_range_hash_1 modify partition p2 add subpartition sp3; +alter table t_subpart_range_hash_1 modify partition p2 add subpartition p1; + +alter table t_subpart_list_hash_1 modify partition p2 add subpartition sp1; +alter table t_subpart_list_hash_1 modify partition p2 add subpartition sp3; +alter table t_subpart_list_hash_1 modify partition p2 add subpartition p1; + +alter table t_subpart_hash_hash_1 modify partition p2 add subpartition sp1; +alter table t_subpart_hash_hash_1 modify partition p2 add subpartition sp3; +alter table t_subpart_hash_hash_1 modify partition p2 add subpartition p1; + +alter table t_subpart_hash_hash_1 modify partition p2 add subpartitions 1; + + +select p1.tablename, p1.relname, p1.parttype, p1.partstrategy, +p1.parentid, p1.boundaries, p1.relfilenode, p1.reltoastrelid +from schema_subpartition.v_subpartition p1 +where p1.tablename in ('t_subpart_range_hash_1', 't_subpart_range_hash_7', 't_subpart_range_hash_10', + 't_subpart_list_hash_1', 't_subpart_list_hash_7', 't_subpart_list_hash_10', + 't_subpart_hash_hash_1', 't_subpart_hash_hash_7', 't_subpart_hash_hash_10'); + + + + +create table t_subpart_hash_hash_13 (id integer, age int) +partition by hash(id) +subpartition by hash(age) + subpartition template + ( + subpartition sp1 tablespace ts_subpart_hash_1, + subpartition sp2 + ) +( +partition p1, +partition p2 tablespace ts_subpart_hash_2, +partition p3 + ( + subpartition sp1 tablespace ts_subpart_hash_1, + subpartition sp2 + ), +partition p4 tablespace ts_subpart_hash_2 + ( + subpartition sp3 tablespace ts_subpart_hash_1, + subpartition sp4 + ) +); + +alter table t_subpart_hash_hash_13 add partition p5; +alter table t_subpart_hash_hash_13 add partition p6 tablespace ts_subpart_hash_2; +alter table t_subpart_hash_hash_13 add partition p7 tablespace ts_subpart_hash_2 +( + subpartition sp5, + subpartition sp6 tablespace ts_subpart_hash_1 +); +alter table t_subpart_hash_hash_13 add partition p8 +( + subpartition sp7, + subpartition sp8 tablespace ts_subpart_hash_1 +); + +alter table t_subpart_hash_hash_13 modify partition p1 add subpartition p1_sp20; +alter table t_subpart_hash_hash_13 modify partition p1 add subpartition p1_sp21 tablespace ts_subpart_hash_1; +alter table t_subpart_hash_hash_13 modify partition p2 add subpartition p2_sp22; +alter table t_subpart_hash_hash_13 modify partition p2 add subpartition p2_sp23 tablespace ts_subpart_hash_1; + + +SET SESSION AUTHORIZATION user_subpart_hash PASSWORD 'Test@123'; +create table t_subpart_hash_hash_14 (id integer, age integer) +partition by hash (id) +subpartition by hash (age) +( +partition p1 + ( + subpartition sp1 + ) +); + +alter table t_subpart_hash_hash_14 add partition p2 tablespace ts_subpart_hash_1; +alter table t_subpart_hash_hash_14 add partition p2 +( + subpartition sp2, + subpartition sp3 tablespace ts_subpart_hash_1 +); +alter table t_subpart_hash_hash_14 modify partition p1 add subpartition p1_sp2 tablespace ts_subpart_hash_1; + +drop table t_subpart_hash_hash_14; +RESET SESSION AUTHORIZATION; + +select p1.tablename, p1.relname, p1.parttype, p2.spcname tablespace_name +from schema_subpartition.v_subpartition p1 left join pg_tablespace p2 on p1.reltablespace = p2.oid +where p1.tablename = 't_subpart_hash_hash_13' +order by p1.parentid, p1.oid; + + + +alter table t_subpart_range_hash_1 drop partition p6; +alter table t_subpart_range_hash_1 drop partition for (350); -- drop p5 +alter table t_subpart_range_hash_7 drop partition p3; +alter table t_subpart_range_hash_10 drop partition for (1, 'A'); -- drop p1 + +alter table t_subpart_list_hash_1 drop partition p6; +alter table t_subpart_list_hash_1 drop partition for (400); -- drop p5 +alter table t_subpart_list_hash_7 drop partition p3; +alter table t_subpart_list_hash_10 drop partition for (10); -- drop p1 + +alter table t_subpart_hash_hash_1 drop partition p6; +alter table t_subpart_hash_hash_1 drop partition for (4); -- drop p5 +alter table t_subpart_hash_hash_7 drop partition p3; +alter table t_subpart_hash_hash_10 drop partition for (10); -- drop p1 +alter table t_subpart_hash_hash_13 drop partition p4; + + + +alter table t_subpart_range_hash_1 drop partition p_error; +alter table t_subpart_range_hash_7 drop partition for (9999); + +alter table t_subpart_list_hash_1 drop partition p_error; +alter table t_subpart_list_hash_7 drop partition for (9999); + +alter table t_subpart_hash_hash_1 drop partition p_error; +alter table t_subpart_hash_hash_7 drop partition for (9999); + + + +alter table t_subpart_list_hash_10 drop partition p2; + + + +alter table t_subpart_range_hash_10 drop partition p3; -- ok +alter table t_subpart_range_hash_10 drop partition p2; -- error + +alter table t_subpart_list_hash_10 drop partition p3; -- ok +alter table t_subpart_list_hash_10 drop partition p2; -- error + +alter table t_subpart_hash_hash_10 drop partition p3; -- error +alter table t_subpart_hash_hash_10 drop partition p2; + + + +alter table t_subpart_range_hash_1 drop subpartition sp1; +alter table t_subpart_range_hash_7 drop subpartition for (100, 101); -- drop sp2 + +alter table t_subpart_list_hash_1 drop subpartition sp1; +alter table t_subpart_list_hash_7 drop subpartition for (500, 101); -- drop sp2 + +alter table t_subpart_hash_hash_1 drop subpartition sp1; +alter table t_subpart_hash_hash_7 drop subpartition for (1, 9); -- drop sp2 +alter table t_subpart_hash_hash_13 drop subpartition sp2; +alter table t_subpart_hash_hash_13 drop subpartition for (4, 100); -- drop p5_sp1 + +alter table t_subpart_range_hash_1 drop subpartition sp_error; +alter table t_subpart_range_hash_7 drop subpartition for (100, 1); + +alter table t_subpart_list_hash_1 drop subpartition sp_error; +alter table t_subpart_list_hash_7 drop subpartition for (500, 1); + +alter table t_subpart_hash_hash_1 drop subpartition sp_error; +alter table t_subpart_hash_hash_7 drop subpartition for (501, 1); + + +alter table t_subpart_range_hash_7 drop subpartition sp1; +alter table t_subpart_list_hash_7 drop subpartition sp1; +alter table t_subpart_hash_hash_7 drop subpartition sp1; + + + +select p1.tablename, p1.relname, p1.parttype, p1.partstrategy, +p1.parentid, p1.boundaries, p1.relfilenode, p1.reltoastrelid +from schema_subpartition.v_subpartition p1 +where p1.tablename in ('t_subpart_range_hash_1', 't_subpart_range_hash_7', 't_subpart_range_hash_10', + 't_subpart_list_hash_1', 't_subpart_list_hash_7', 't_subpart_list_hash_10', + 't_subpart_hash_hash_1', 't_subpart_hash_hash_7', 't_subpart_hash_hash_10'); + + +select p1.tablename, p1.relname, p1.parttype, p2.spcname tablespace_name +from schema_subpartition.v_subpartition p1 left join pg_tablespace p2 on p1.reltablespace = p2.oid +where p1.tablename = 't_subpart_hash_hash_13' +order by p1.parentid, p1.oid; + + + + +select * from t_subpart_range_hash_1 partition (p2); +select * from t_subpart_range_hash_1 partition for (10); +select * from t_subpart_range_hash_1 subpartition (sp2); +select * from t_subpart_range_hash_1 subpartition for (50, 51); + +select * from t_subpart_list_hash_1 partition (p2); +select * from t_subpart_list_hash_1 partition for (10); +select * from t_subpart_list_hash_1 subpartition (sp2); +select * from t_subpart_list_hash_1 subpartition for (50, 51); + +select * from t_subpart_hash_hash_1 partition (p2); +select * from t_subpart_hash_hash_1 partition for (1); +select * from t_subpart_hash_hash_1 subpartition (sp2); +select * from t_subpart_hash_hash_1 subpartition for (51, 51); + + + +update t_subpart_range_hash_1 partition (p2) set id = id + 10; +update t_subpart_range_hash_1 partition for (10) set id = id + 10; +update t_subpart_range_hash_1 subpartition (sp2) set id = id + 10; +update t_subpart_range_hash_1 subpartition for (50, 51) set id = id + 10; + +update t_subpart_list_hash_1 partition (p2) set id = id + 10; +update t_subpart_list_hash_1 partition for (10) set id = id + 10; +update t_subpart_list_hash_1 subpartition (sp2) set id = id + 10; +update t_subpart_list_hash_1 subpartition for (50, 51) set id = id + 10; + +update t_subpart_hash_hash_1 partition (p2) set id = id + 10; +update t_subpart_hash_hash_1 partition for (1) set id = id + 10; +update t_subpart_hash_hash_1 subpartition (sp2) set id = id + 10; +update t_subpart_hash_hash_1 subpartition for (51, 51) set id = id + 10; + + + + +delete from t_subpart_range_hash_1 partition (p2); +delete from t_subpart_range_hash_1 partition for (10); +delete from t_subpart_range_hash_1 subpartition (sp2); +delete from t_subpart_range_hash_1 subpartition for (50, 51); + +delete from t_subpart_list_hash_1 partition (p2); +delete from t_subpart_list_hash_1 partition for (10); +delete from t_subpart_list_hash_1 subpartition (sp2); +delete from t_subpart_list_hash_1 subpartition for (50, 51); + +delete from t_subpart_hash_hash_1 partition (p2); +delete from t_subpart_hash_hash_1 partition for (1); +delete from t_subpart_hash_hash_1 subpartition (sp2); +delete from t_subpart_hash_hash_1 subpartition for (51, 51); + + + +-- range-hash +create table t_subpart_range_hash_20 (id integer, name text) +partition by range(name) +subpartition by hash(name) +( +partition p1 values less than ('e'), +partition p2 values less than ('k') + ( + subpartition sp1, + subpartition sp2 + ), +partition p3 values less than (MAXVALUE) + ( + subpartition sp3, + subpartition sp4 + ) +); +insert into t_subpart_range_hash_20 values (1,'a'); +insert into t_subpart_range_hash_20 values (2,'e'); +insert into t_subpart_range_hash_20 values (3,'g'); +insert into t_subpart_range_hash_20 values (4,'m'); +insert into t_subpart_range_hash_20 values (5,'r'); +insert into t_subpart_range_hash_20 values (6,NULL); + +explain(costs off) select * from t_subpart_range_hash_20; + +explain(costs off) select * from t_subpart_range_hash_20 where name is null; +select * from t_subpart_range_hash_20 where name is null; +explain(costs off) select * from t_subpart_range_hash_20 where name is not null; +select * from t_subpart_range_hash_20 where name is not null; + +explain(costs off) select * from t_subpart_range_hash_20 where name = 'e'; +select * from t_subpart_range_hash_20 where name = 'e'; +explain(costs off) select * from t_subpart_range_hash_20 where name > 'e'; +select * from t_subpart_range_hash_20 where name > 'e'; +explain(costs off) select * from t_subpart_range_hash_20 where name >= 'e'; +select * from t_subpart_range_hash_20 where name >= 'e'; +explain(costs off) select * from t_subpart_range_hash_20 where name < 'e'; +select * from t_subpart_range_hash_20 where name < 'e'; +explain(costs off) select * from t_subpart_range_hash_20 where name <= 'e'; +select * from t_subpart_range_hash_20 where name <= 'e'; +explain(costs off) select * from t_subpart_range_hash_20 where name <> 'e'; +select * from t_subpart_range_hash_20 where name <> 'e'; + +explain(costs off) select * from t_subpart_range_hash_20 where name = 'e' and name is null; +select * from t_subpart_range_hash_20 where name = 'e' and name is null; +explain(costs off) select * from t_subpart_range_hash_20 where name = 'e' or name is null; +select * from t_subpart_range_hash_20 where name = 'e' or name is null; + +explain(costs off) select * from t_subpart_range_hash_20 where name in ('r', NULL); +select * from t_subpart_range_hash_20 where name in ('r', NULL); +explain(costs off) select * from t_subpart_range_hash_20 where name = any(array['e', 'g']) or name in ('r', NULL); +select * from t_subpart_range_hash_20 where name = any(array['e', 'g']) or name in ('r', NULL); + + +-- list-hash +create table t_subpart_list_hash_20 (id integer, age integer, name text) +partition by list(age) +subpartition by hash(name) +( +partition p1 values (1, 2, 3), +partition p2 values (10, 20, 50, 60) + ( + subpartition sp1, + subpartition sp2 + ), +partition p3 values (DEFAULT) + ( + subpartition sp3, + subpartition sp4 + ) +); +insert into t_subpart_list_hash_20 values (1, 1, NULL); +insert into t_subpart_list_hash_20 values (2, 20, 'b'); +insert into t_subpart_list_hash_20 values (3, 50, 'f'); +insert into t_subpart_list_hash_20 values (4, 100, NULL); +insert into t_subpart_list_hash_20 values (5, NULL, 'g'); +insert into t_subpart_list_hash_20 values (6, NULL, NULL); + +explain(costs off) select * from t_subpart_list_hash_20; + +explain(costs off) select * from t_subpart_list_hash_20 where age is null; +select * from t_subpart_list_hash_20 where age is null; +explain(costs off) select * from t_subpart_list_hash_20 where age is not null; +select * from t_subpart_list_hash_20 where age is not null; +explain(costs off) select * from t_subpart_list_hash_20 where name is null; +select * from t_subpart_list_hash_20 where name is null; +explain(costs off) select * from t_subpart_list_hash_20 where name is not null; +select * from t_subpart_list_hash_20 where name is not null; + +explain(costs off) select * from t_subpart_list_hash_20 where age is null and name is null; +select * from t_subpart_list_hash_20 where age is null and name is null; +explain(costs off) select * from t_subpart_list_hash_20 where age is null or name is null; +select * from t_subpart_list_hash_20 where age is null or name is null; + +explain(costs off) select * from t_subpart_list_hash_20 where age = 20; +select * from t_subpart_list_hash_20 where age = 20; +explain(costs off) select * from t_subpart_list_hash_20 where name = 'b'; +select * from t_subpart_list_hash_20 where name = 'b'; +explain(costs off) select * from t_subpart_list_hash_20 where age = 20 and name = 'b'; +select * from t_subpart_list_hash_20 where age = 20 and name = 'b'; +explain(costs off) select * from t_subpart_list_hash_20 where age = 20 or name = 'b'; +select * from t_subpart_list_hash_20 where age = 20 or name = 'b'; + +explain(costs off) select * from t_subpart_list_hash_20 where age is null and name = 'b'; +select * from t_subpart_list_hash_20 where age is null and name = 'b'; +explain(costs off) select * from t_subpart_list_hash_20 where age is null or name = 'b'; +select * from t_subpart_list_hash_20 where age is null or name = 'b'; +explain(costs off) select * from t_subpart_list_hash_20 where age = 20 and name is null; +select * from t_subpart_list_hash_20 where age = 20 and name is null; +explain(costs off) select * from t_subpart_list_hash_20 where age = 20 or name is null; +select * from t_subpart_list_hash_20 where age = 20 or name is null; + +explain(costs off) select * from t_subpart_list_hash_20 where name = any(array['g', NULL]); +select * from t_subpart_list_hash_20 where name = any(array['g', NULL]); +explain(costs off) select * from t_subpart_list_hash_20 where age in (20, 200) and name = any(array['g', NULL]); +select * from t_subpart_list_hash_20 where age in (20, 200) and name = any(array['g', NULL]); + + +-- hash-hash +create table t_subpart_hash_hash_20 (id integer, name text, bd time) +partition by hash(name) +subpartition by hash(bd) +( +partition p1, +partition p2 + ( + subpartition sp1, + subpartition sp2 + ), +partition p3 + ( + subpartition sp3, + subpartition sp4 + ) +); +insert into t_subpart_hash_hash_20 values (1, 'a', '1:2:3'); +insert into t_subpart_hash_hash_20 values (2, 'g', NULL); +insert into t_subpart_hash_hash_20 values (3, 'h', '11:2:3'); +insert into t_subpart_hash_hash_20 values (4, 'o', NULL); +insert into t_subpart_hash_hash_20 values (5, 't', '21:0:0'); +insert into t_subpart_hash_hash_20 values (6, NULL, NULL); + +explain(costs off) select * from t_subpart_hash_hash_20; + +explain(costs off) select * from t_subpart_hash_hash_20 where name is null; +select * from t_subpart_hash_hash_20 where name is null; +explain(costs off) select * from t_subpart_hash_hash_20 where name is not null; +select * from t_subpart_hash_hash_20 where name is not null; +explain(costs off) select * from t_subpart_hash_hash_20 where bd is null; +select * from t_subpart_hash_hash_20 where bd is null; +explain(costs off) select * from t_subpart_hash_hash_20 where bd is not null; +select * from t_subpart_hash_hash_20 where bd is not null; +explain(costs off) select * from t_subpart_hash_hash_20 where name is null and bd is null; +select * from t_subpart_hash_hash_20 where name is null and bd is null; + +explain(costs off) select * from t_subpart_hash_hash_20 where name = 'g'; +select * from t_subpart_hash_hash_20 where name = 'g'; +explain(costs off) select * from t_subpart_hash_hash_20 where bd = '11:2:3'; +select * from t_subpart_hash_hash_20 where bd = '11:2:3'; +explain(costs off) select * from t_subpart_hash_hash_20 where name = 'g' and bd = '11:2:3'; +select * from t_subpart_hash_hash_20 where name = 'g' and bd = '11:2:3'; +explain(costs off) select * from t_subpart_hash_hash_20 where name = 'g' or bd = '11:2:3'; +select * from t_subpart_hash_hash_20 where name = 'g' or bd = '11:2:3'; + +explain(costs off) select * from t_subpart_hash_hash_20 where name is null and bd = '11:2:3'; +select * from t_subpart_hash_hash_20 where name is null and bd = '11:2:3'; +explain(costs off) select * from t_subpart_hash_hash_20 where name is null or bd = '11:2:3'; +select * from t_subpart_hash_hash_20 where name is null or bd = '11:2:3'; +explain(costs off) select * from t_subpart_hash_hash_20 where name = 'g' and bd is null; +select * from t_subpart_hash_hash_20 where name = 'g' and bd is null; +explain(costs off) select * from t_subpart_hash_hash_20 where name = 'g' or bd is null; +select * from t_subpart_hash_hash_20 where name = 'g' or bd is null; + +explain(costs off) select * from t_subpart_hash_hash_20 where bd = any(array['11:2:3'::time, '21:0:0'::time]); +select * from t_subpart_hash_hash_20 where bd = any(array['11:2:3'::time, '21:0:0'::time]); +explain(costs off) select * from t_subpart_hash_hash_20 where name in ('g','o') and bd = any(array['11:2:3'::time, '21:0:0'::time]); +select * from t_subpart_hash_hash_20 where name in ('g','o') and bd = any(array['11:2:3'::time, '21:0:0'::time]); + + + +---------------------------- +-- truncate partition & subpartition +---------------------------- +-- PARTITION [FOR] +alter table t_subpart_range_hash_1 truncate partition p1; +alter table t_subpart_range_hash_1 truncate partition for (10); +alter table t_subpart_range_hash_10 truncate partition p2; +alter table t_subpart_range_hash_10 truncate partition for (10, 'MAXVALUE'); + +alter table t_subpart_list_hash_1 truncate partition p1; +alter table t_subpart_list_hash_1 truncate partition for (10); +alter table t_subpart_list_hash_10 truncate partition p2; +alter table t_subpart_list_hash_10 truncate partition for (100); + +alter table t_subpart_hash_hash_1 truncate partition p1; +alter table t_subpart_hash_hash_1 truncate partition for (0); +alter table t_subpart_hash_hash_7 truncate partition p1; +alter table t_subpart_hash_hash_7 truncate partition for (100); +alter table t_subpart_hash_hash_10 truncate partition p2; +alter table t_subpart_hash_hash_10 truncate partition for (1); + +-- SUBPARTITION [FOR] +alter table t_subpart_range_hash_1 truncate subpartition p1_subpartdefault1; +alter table t_subpart_range_hash_1 truncate subpartition for (100, 51); +alter table t_subpart_range_hash_10 truncate subpartition sp2; +alter table t_subpart_range_hash_10 truncate subpartition for (10, 'MAXVALUE', 9); + +alter table t_subpart_list_hash_1 truncate subpartition p1_subpartdefault1; +alter table t_subpart_list_hash_1 truncate subpartition for (10, 51); +alter table t_subpart_list_hash_10 truncate subpartition sp2; +alter table t_subpart_list_hash_10 truncate subpartition for (100, 9); + +alter table t_subpart_hash_hash_1 truncate subpartition p1_subpartdefault1; +alter table t_subpart_hash_hash_1 truncate subpartition for (11, 51); +alter table t_subpart_hash_hash_7 truncate subpartition sp1; +alter table t_subpart_hash_hash_7 truncate subpartition for (101, 10); +alter table t_subpart_hash_hash_10 truncate subpartition sp2; +alter table t_subpart_hash_hash_10 truncate subpartition for (1, 7); + +alter table t_subpart_range_hash_1 truncate partition p_error; +alter table t_subpart_range_hash_1 truncate partition for (300); +alter table t_subpart_range_hash_1 truncate subpartition sp_error; +alter table t_subpart_range_hash_1 truncate subpartition for (10, 4); -- ok + +alter table t_subpart_list_hash_1 truncate partition p_error; +alter table t_subpart_list_hash_1 truncate partition for (999); +alter table t_subpart_list_hash_1 truncate subpartition sp_error; +alter table t_subpart_list_hash_1 truncate subpartition for (10, 4); -- ok + +alter table t_subpart_hash_hash_1 truncate partition p_error; +alter table t_subpart_hash_hash_1 truncate partition for (4); -- ok +alter table t_subpart_hash_hash_1 truncate subpartition sp_error; +alter table t_subpart_hash_hash_1 truncate subpartition for (11, 4); -- ok + + + + +alter table t_subpart_range_hash_1 set subpartition template +( + subpartition sp1, + subpartition sp2 +); + +alter table t_subpart_list_hash_1 set subpartition template +( + subpartition sp1, + subpartition sp2 +); + +alter table t_subpart_hash_hash_1 set subpartition template +( + subpartition sp1, + subpartition sp2 +); + + + +---------------------------- +-- TODO SPLIT [SUB]PARTITION [FOR] +---------------------------- +-- TODO SPLIT RANGE PARTITION [FOR] +alter table t_subpart_range_hash_2 split partition p1 at (5) into (partition p1_1, partition p1_2); +alter table t_subpart_range_hash_2 split partition for (50) at (50) into (partition p2_1, partition p2_2); + +alter table t_subpart_range_hash_2 split partition p3 into (partition p3_1 end (200), partition p3_2 end (300), partition p3_3 end (400), partition p3_4 end (500), partition p3_5 end (MAXVALUE)); +alter table t_subpart_range_hash_2 split partition for (50) into (partition p2_2_1 values less than (60), partition p2_2_2 values less than (100)); + + +alter table t_subpart_range_hash_2 split partition p1_1 values (5) into (partition p1_1_1, partition p1_1_2); + + +-- TODO SPLIT LIST PARTITION [FOR] +alter table t_subpart_list_hash_2 split partition p1 values (5) into (partition p1_1, partition p1_2); +alter table t_subpart_list_hash_2 split partition for (100) values (200) into (partition p1_1, partition p1_2); +alter table t_subpart_list_hash_2 split partition p2 into (partition p3_1 values (10), partition p3_2 values (20), partition p3_3 values (30), partition p3_4 values (40), partition p3_5 values (50)); + +-- error, LIST partition not support AT ... INTO +alter table t_subpart_list_hash_2 split partition p1 at (3) into (partition p1_1, partition p1_2); +alter table t_subpart_list_hash_2 split partition for (3) at (3) into (partition p1_1 values (10), partition p1_2 values (20.6789)); + + +-- HASH partition not support SPLIT +alter table t_subpart_hash_hash_2 split partition p1 at (5) into (partition p1_1, partition p1_2); +alter table t_subpart_hash_hash_2 split partition for (0) at (5) into (partition p1_1, partition p1_2); +alter table t_subpart_hash_hash_2 split partition p2 values (5) into (partition p1_1, partition p1_2); +alter table t_subpart_hash_hash_2 split partition p3 into (partition p3_1 values less than (100), partition p3_2 values less than (200)); + +-- HASH subpartition not support SPLIT +alter table t_subpart_hash_hash_3 split subpartition sp1 at ('a') into (subpartition sp1_1, subpartition sp1_2); +alter table t_subpart_hash_hash_3 split subpartition for (100, '1') at ('a') into (subpartition sp2_1, subpartition sp2_2 ); +alter table t_subpart_hash_hash_3 split subpartition sp1 values ('a') into (subpartition sp1_1, subpartition sp1_2); +alter table t_subpart_hash_hash_3 split subpartition for (100, '1') values ('1', '2') into (subpartition sp2_1, subpartition sp2_2 ); +alter table t_subpart_hash_hash_3 split subpartition sp3 into (subpartition sp3_1 values ('A'), subpartition sp3_2 values ('B'), subpartition sp3_3 values ('C'), subpartition sp3_4 values ('D', 'E')); +alter table t_subpart_hash_hash_3 split subpartition for (300, '1') into (subpartition sp5_1 values ('1', '2', '3', '4', '5'), subpartition sp5_2 values ('A', 'B', 'C', 'D', 'E'), subpartition sp5_3 values (DEFAULT)); + + + + + +-- TODO MERGE RANGE PARTITIONS [FOR] +alter table t_subpart_range_hash_1 merge partitions p1,p2 into partition p12; +alter table t_subpart_range_hash_1 merge partitions for (1), for (10), for (100), for (200) into partition p1234; +alter table t_subpart_range_hash_1 merge partitions p1 to p4 into partition p1234; + +-- TODO MERGE LIST PARTITION [FOR] +alter table t_subpart_list_hash_1 merge partitions p1,p2 into partition p12; +alter table t_subpart_list_hash_1 merge partitions for (1), for (10), for (70), for (222) into partition p1234; + +alter table t_subpart_list_hash_1 merge partitions p1 to p4 into partition p1234; -- error + + +alter table t_subpart_hash_hash_1 merge partitions p1,p1 into partition p12; +alter table t_subpart_hash_hash_1 merge partitions for (0), for (1) into partition p12; +alter table t_subpart_hash_hash_1 merge partitions p1 to p3 into partition p123; + +alter table t_subpart_hash_hash_1 merge subpartitions sp1,sp1 into subpartition sp12; +alter table t_subpart_hash_hash_1 merge subpartitions for (1, 0), for (1, 1) into subpartition p12; +alter table t_subpart_hash_hash_1 merge subpartitions sp1 to sp2 into subpartition sp12; + + + + + +---------------------------- +-- TODO EXCHANGE PARTITION [FOR] +---------------------------- +create table t_subpart_range_hash_8_exchange (like t_subpart_range_hash_8); +alter table t_subpart_range_hash_8_exchange add primary key (id, age, name); +create table t_subpart_list_hash_8_exchange (like t_subpart_list_hash_8); +alter table t_subpart_list_hash_8_exchange add primary key (id, age, name); +create table t_subpart_hash_hash_8_exchange (like t_subpart_hash_hash_8); +alter table t_subpart_hash_hash_8_exchange add primary key (id, age, name); + +alter table t_subpart_range_hash_8 EXCHANGE PARTITION (p1) with table t_subpart_range_hash_8_exchange WITHOUT VALIDATION; +alter table t_subpart_range_hash_8 EXCHANGE PARTITION (p1) with table t_subpart_range_hash_8_exchange; +alter table t_subpart_range_hash_8 EXCHANGE PARTITION p1 with table t_subpart_range_hash_8_exchange WITH VALIDATION; +alter table t_subpart_range_hash_8 EXCHANGE PARTITION for (20, 'A') with table t_subpart_range_hash_8_exchange VERBOSE; +alter table t_subpart_range_hash_8 EXCHANGE PARTITION for (19, 'BBB') with table t_subpart_range_hash_8_exchange WITH VALIDATION VERBOSE; + +alter table t_subpart_list_hash_8 EXCHANGE PARTITION (p1) with table t_subpart_list_hash_8_exchange WITHOUT VALIDATION; +alter table t_subpart_list_hash_8 EXCHANGE PARTITION (p1) with table t_subpart_list_hash_8_exchange; +alter table t_subpart_list_hash_8 EXCHANGE PARTITION p1 with table t_subpart_list_hash_8_exchange WITH VALIDATION; +alter table t_subpart_list_hash_8 EXCHANGE PARTITION for (20) with table t_subpart_list_hash_8_exchange VERBOSE; +alter table t_subpart_list_hash_8 EXCHANGE PARTITION for (20)with table t_subpart_list_hash_8_exchange WITH VALIDATION VERBOSE; + +alter table t_subpart_hash_hash_8 EXCHANGE PARTITION (p1) with table t_subpart_hash_hash_8_exchange WITHOUT VALIDATION; +alter table t_subpart_hash_hash_8 EXCHANGE PARTITION (p1) with table t_subpart_hash_hash_8_exchange; +alter table t_subpart_hash_hash_8 EXCHANGE PARTITION p1 with table t_subpart_hash_hash_8_exchange WITH VALIDATION; +alter table t_subpart_hash_hash_8 EXCHANGE PARTITION for (10) with table t_subpart_hash_hash_8_exchange VERBOSE; +alter table t_subpart_hash_hash_8 EXCHANGE PARTITION for (10) with table t_subpart_hash_hash_8_exchange WITH VALIDATION VERBOSE; + + + +---------------------------- +-- EXCHANGE SUBPARTITION [FOR] +---------------------------- +alter table t_subpart_range_hash_8 EXCHANGE SUBPARTITION p1_subpartdefault1 with table t_subpart_range_hash_8_exchange WITHOUT VALIDATION; +alter table t_subpart_range_hash_8 EXCHANGE SUBPARTITION p1_subpartdefault1 with table t_subpart_range_hash_8_exchange; +alter table t_subpart_range_hash_8 EXCHANGE SUBPARTITION p1_subpartdefault1 with table t_subpart_range_hash_8_exchange WITH VALIDATION; +alter table t_subpart_range_hash_8 EXCHANGE SUBPARTITION for (20, 'A', '10') with table t_subpart_range_hash_8_exchange VERBOSE; +alter table t_subpart_range_hash_8 EXCHANGE SUBPARTITION for (19, 'BBB', '10') with table t_subpart_range_hash_8_exchange WITH VALIDATION VERBOSE; + +alter table t_subpart_list_hash_8 EXCHANGE SUBPARTITION p1_subpartdefault1 with table t_subpart_list_hash_8_exchange WITHOUT VALIDATION; +alter table t_subpart_list_hash_8 EXCHANGE SUBPARTITION p1_subpartdefault1 with table t_subpart_list_hash_8_exchange; +alter table t_subpart_list_hash_8 EXCHANGE SUBPARTITION p1_subpartdefault1 with table t_subpart_list_hash_8_exchange WITH VALIDATION; +alter table t_subpart_list_hash_8 EXCHANGE SUBPARTITION for (20, '20') with table t_subpart_list_hash_8_exchange VERBOSE; +alter table t_subpart_list_hash_8 EXCHANGE SUBPARTITION for (20, '20') with table t_subpart_list_hash_8_exchange WITH VALIDATION VERBOSE; + +alter table t_subpart_hash_hash_8 EXCHANGE SUBPARTITION p1_subpartdefault1 with table t_subpart_hash_hash_8_exchange WITHOUT VALIDATION; +alter table t_subpart_hash_hash_8 EXCHANGE SUBPARTITION p1_subpartdefault1 with table t_subpart_hash_hash_8_exchange; +alter table t_subpart_hash_hash_8 EXCHANGE SUBPARTITION p1_subpartdefault1 with table t_subpart_hash_hash_8_exchange WITH VALIDATION; +alter table t_subpart_hash_hash_8 EXCHANGE SUBPARTITION for (10, '20') with table t_subpart_hash_hash_8_exchange VERBOSE; +alter table t_subpart_hash_hash_8 EXCHANGE SUBPARTITION for (10, '20') with table t_subpart_hash_hash_8_exchange WITH VALIDATION VERBOSE; + + +drop table t_subpart_range_hash_8_exchange; +drop table t_subpart_list_hash_8_exchange; +drop table t_subpart_hash_hash_8_exchange; + + + +-- TODO List partition MODIFY ADD/DROP VALUES (...) +-- alter table xxx modify partition p1 add values (); +-- alter table xxx modify partition p1 drop values (); +-- alter table xxx modify subpartition p1 add values (); +-- alter table xxx modify subpartition p1 addropd values (); + + + +---------------------------- +-- TODO MOVE [SUB]PARTITION [FOR] +---------------------------- +alter table t_subpart_range_hash_10 move partition p1 tablespace ts_subpart_hash_1; +alter table t_subpart_range_hash_10 move partition for (10, 'MAXVALUE') tablespace ts_subpart_hash_1; +alter table t_subpart_range_hash_10 move subpartition sp2 tablespace ts_subpart_hash_2; +alter table t_subpart_range_hash_10 move subpartition for (10, 'MAXVALUE', '1') tablespace ts_subpart_hash_2; + +alter table t_subpart_list_hash_10 move partition p1 tablespace ts_subpart_hash_1; +alter table t_subpart_list_hash_10 move partition for (100) tablespace ts_subpart_hash_1; +alter table t_subpart_list_hash_10 move subpartition sp2 tablespace ts_subpart_hash_2; +alter table t_subpart_list_hash_10 move subpartition for (100, '1') tablespace ts_subpart_hash_2; + +alter table t_subpart_hash_hash_10 move partition p1 tablespace ts_subpart_hash_1; +alter table t_subpart_hash_hash_10 move partition for (1) tablespace ts_subpart_hash_1; +alter table t_subpart_hash_hash_10 move subpartition sp2 tablespace ts_subpart_hash_2; +alter table t_subpart_hash_hash_10 move subpartition for (1, '1') tablespace ts_subpart_hash_2; + + + +---------------------------- +-- TODO ROW MOVEMENT +---------------------------- +alter table t_subpart_range_hash_10 enable row movement; +alter table t_subpart_range_hash_10 disable row movement; + +alter table t_subpart_list_hash_10 enable row movement; +alter table t_subpart_list_hash_10 disable row movement; + +alter table t_subpart_hash_hash_10 enable row movement; +alter table t_subpart_hash_hash_10 disable row movement; + + + +---------------------------- +-- ALTER INDEX ... UNUSABLE +-- ALTER INDEX ... REBUILD +-- ALTER INDEX ... MODIFY [SUB]PARTITION name UNUSABLE +-- ALTER INDEX ... REBUILD [SUB]PARTITION name +---------------------------- +alter index i_t_subpart_hash_hash_10_3 UNUSABLE; + +alter index i_t_subpart_hash_hash_10_3 REBUILD partition subp1_bd_idx_local; +alter index i_t_subpart_hash_hash_10_3 REBUILD subpartition subp3_bd_idx_local; + +alter index i_t_subpart_hash_hash_10_4 UNUSABLE; +alter index i_t_subpart_hash_hash_10_4 REBUILD partition subp1_index_local; -- error +alter index i_t_subpart_hash_hash_10_4 REBUILD subpartition subp3_index_local; -- error + +select relname, parttype, indisusable from pg_partition where parentid='i_t_subpart_hash_hash_10_3'::regclass order by relname; +select relname, relkind, parttype, indisusable from pg_class left join pg_index on pg_class.oid=indexrelid where pg_class.oid in ('i_t_subpart_hash_hash_10_3'::regclass, 'i_t_subpart_hash_hash_10_4'::regclass) order by relname; + +explain (costs off) +select * from t_subpart_hash_hash_10 where bd = '2999-01-01'; + +-- alter index i_t_subpart_hash_hash_10_3 REBUILD; +-- alter index i_t_subpart_hash_hash_10_4 REBUILD; + +explain (costs off) +select * from t_subpart_hash_hash_10 where bd = '2999-01-01'; + +alter index i_t_subpart_hash_hash_10_3 modify partition subp1_bd_idx_local unusable; +alter index i_t_subpart_hash_hash_10_3 modify subpartition subp3_bd_idx_local unusable; + +explain (costs off) +select * from t_subpart_hash_hash_10 where bd = '2999-01-01'; + +select relname, parttype, indisusable from pg_partition where parentid='i_t_subpart_hash_hash_10_3'::regclass order by relname; +select relname, relkind, parttype, indisusable from pg_class left join pg_index on pg_class.oid=indexrelid where pg_class.oid in ('i_t_subpart_hash_hash_10_3'::regclass, 'i_t_subpart_hash_hash_10_4'::regclass) order by relname; + + + +---------------------------- +-- ALTER TABLE ... MODIFY [SUB]PARTITION [FOR] ... [REBUILD] UNUSABLE LOCAL INDEXES +---------------------------- +alter table t_subpart_hash_hash_10 modify partition p1 unusable local indexes; +alter table t_subpart_hash_hash_10 modify partition for (3) unusable local indexes; +select relname, parttype, indisusable from pg_partition where parentid='i_t_subpart_hash_hash_10_3'::regclass order by relname; + +explain (costs off) +select * from t_subpart_hash_hash_10 where bd = '2999-01-01'; + +alter table t_subpart_hash_hash_10 modify partition p1 REBUILD unusable local indexes; +alter table t_subpart_hash_hash_10 modify partition for (3) REBUILD unusable local indexes; +select relname, parttype, indisusable from pg_partition where parentid='i_t_subpart_hash_hash_10_3'::regclass order by relname; + +explain (costs off) +select * from t_subpart_hash_hash_10 where bd = '2999-01-01'; + +alter table t_subpart_hash_hash_10 modify subpartition sp1 unusable local indexes; +alter table t_subpart_hash_hash_10 modify subpartition for (3, NULL) unusable local indexes; +select relname, parttype, indisusable from pg_partition where parentid='i_t_subpart_hash_hash_10_3'::regclass order by relname; + +explain (costs off) +select * from t_subpart_hash_hash_10 where bd = '2999-01-01'; + +alter table t_subpart_hash_hash_10 modify subpartition sp1 REBUILD unusable local indexes; +alter table t_subpart_hash_hash_10 modify subpartition for (3, NULL) REBUILD unusable local indexes; +select relname, parttype, indisusable from pg_partition where parentid='i_t_subpart_hash_hash_10_3'::regclass order by relname; + +explain (costs off) +select * from t_subpart_hash_hash_10 where bd = '2999-01-01'; + + + +---------------------------- +-- TODO RENAME +---------------------------- +alter table t_subpart_hash_hash_10 rename partition p2 to p0; +alter table t_subpart_hash_hash_10 rename partition p0 to p2; + +alter table t_subpart_hash_hash_10 rename subpartition sp2 to sp0; +alter table t_subpart_hash_hash_10 rename subpartition sp0 to sp2; + + + + +select table_name,partitioning_type,subpartitioning_type,partition_count, +def_subpartition_count,partitioning_key_count,subpartitioning_key_count +from all_part_tables where lower(table_name) in ('t_subpart_range_hash_11', 't_subpart_list_hash_11', 't_subpart_hash_hash_11') order by table_name; + +select (table_owner is not null) as has_owner,table_name,partition_name,subpartition_name from all_tab_subpartitions where lower(table_name) in ('t_subpart_range_hash_11', 't_subpart_list_hash_11', 't_subpart_hash_hash_11') order by table_name,partition_name,subpartition_name; + +select (table_owner is not null) as has_owner,table_name,partition_name,subpartition_count from all_tab_partitions where lower(table_name) in ('t_subpart_range_hash_11', 't_subpart_list_hash_11', 't_subpart_hash_hash_11') order by table_name,partition_name; + + + + +CREATE TABLE t_subpart_cstore_hh (id integer, name varchar(30), db date) +with ( orientation = column ) +partition by hash(id) +subpartition by hash(db) +( +partition p1 +); + + + +---------------------------- +-- ERROR +---------------------------- + +create table t_subpart_error (id integer, name varchar(30)) +partition by VALUES(id) +subpartition by hash(id); + +create table t_subpart_error (id integer, name varchar(30)) +partition by hash(id) +subpartition by VALUES(name) +( +partition p1 +); + +create table t_subpart_interval (id integer, name varchar(30), db date) +partition by range(db) +INTERVAL ('1 day') +subpartition by hash(id) +( +partition p1 values less than ('2000-01-01') +); + +create table t_subpart_error (id integer, name varchar(30), db date) +partition by hash(id) +subpartition by range(db) +INTERVAL ('1 day') +( +partition p1 +); + + + + +select oid,relname from pg_class +where (relkind = 'r' and parttype != 'n' and oid not in (select distinct parentid from pg_partition where parttype='r')) + or (relkind = 'i' and parttype != 'n' and oid not in (select distinct parentid from pg_partition where parttype='x')); + +select p1.relname, p1.parttype, p1.parentid, p1.boundaries +from pg_partition p1 +where (p1.parttype = 'r' and p1.parentid not in (select oid from pg_class where relkind = 'r' and parttype != 'n')) + or (p1.parttype = 'r' and not exists (select oid from pg_partition where parttype='p' and parentid=p1.parentid)) + or (p1.parttype = 'p' and not exists (select oid from pg_partition where parttype='r' and parentid=p1.parentid)) + or (p1.parttype = 'p' and exists (select oid from pg_class where parttype='s' and oid=p1.parentid) and not exists (select oid from pg_partition where parttype='s' and parentid=p1.oid)) + or (p1.parttype = 's' and not exists (select oid from pg_partition where parttype='p' and oid=p1.parentid)) + or (p1.parttype = 'x' and p1.parentid not in (select oid from pg_class where relkind = 'i' and parttype != 'n')) + or (p1.indextblid != 0 and p1.indextblid not in (select oid from pg_partition where parttype != 'r')); + +drop index i_t_subpart_hash_hash_10_3, i_t_subpart_hash_hash_10_4; + + +-- drop table t_subpart_normal_table_hash, t_subpart_part_table_hash; +-- drop schema schema_vastbase_subpartition_hash cascade; +-- drop tablespace ts_subpart_hash_1; +-- drop tablespace ts_subpart_hash_2; +-- drop tablespace ts_subpart_hash_test_user; +-- drop user user_subpart_hash; diff --git a/src/test/subscription/testcase/ddl_replication_sql/A/ddl_create_trigger.sql b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_create_trigger.sql new file mode 100644 index 000000000..09babf23a --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_create_trigger.sql @@ -0,0 +1,100 @@ +create table employees(id int,salary int); + +create or replace trigger t +before insert or update of salary,id +or delete on employees +begin +case +when inserting then +dbms_output.put_line('inserting'); +when updating ('salary') then +dbms_output.put_line('updating salary'); +when updating ('id') then +dbms_output.put_line('updating id'); +when deleting then +dbms_output.put_line('deleting'); +end case; +end; +/ + +create table oldtab(id int,c1 char(8)); +create table newtab(id int,c1 int); + +create or replace trigger tri1 +after insert on oldtab +for each statement +begin +insert into newtab values(1,1),(2,2),(3,3); +end; +/ + +create or replace trigger tri2 +after update on oldtab +for each statement +begin +update newtab set c1=4 where id=2; +end; +/ + +create or replace trigger tri4 +after truncate on oldtab +for each statement +begin +insert into newtab values(4,4); +end; +/ + +create table oldtab2(id int,c1 char(8)); +create table newtab2(id int,c1 int); + +CREATE OR REPLACE FUNCTION func_tri21() +RETURNS TRIGGER AS $$ +BEGIN +insert into newtab2 values(1,1),(2,2),(3,3); +RETURN OLD; +END; +$$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION func_tri22() +RETURNS TRIGGER AS $$ +BEGIN +update newtab2 set c1=4 where id=2; +RETURN OLD; +END; +$$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION func_tri24() +RETURNS TRIGGER AS $$ +BEGIN +insert into newtab2 values(4,4); +RETURN OLD; +END; +$$ +LANGUAGE plpgsql; + +create trigger tri21 +after insert on oldtab2 +for each statement +execute procedure func_tri21(); + +create trigger tri22 +after update on oldtab2 +for each statement +execute procedure func_tri22(); + +create trigger tri24 +after truncate on oldtab2 +for each statement +execute procedure func_tri24(); + +create table t_trig_when(f1 boolean primary key, f2 text, f3 int, f4 date); +create or replace function dummy_update_func() returns trigger as $$ +begin + raise notice 'dummy_update_func(%) called: action = %, oid = %, new = %', TG_ARGV[0], TG_OP, OLD, NEW; + return new; +end; +$$ language plpgsql; + +create trigger f1_trig_update after update of f1 on t_trig_when for each row when (not old.f1 and new.f1) execute procedure dummy_update_func('update'); \ No newline at end of file diff --git a/src/test/subscription/testcase/ddl_replication_sql/A/ddl_create_type.sql b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_create_type.sql new file mode 100644 index 000000000..5e52956f8 --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_create_type.sql @@ -0,0 +1,5 @@ +create type atype as (id int, name text); +create type btype as object (id int, name text); +create type ctype as (id int, name text); +alter type ctype rename to dtype; +drop type dtype; \ No newline at end of file diff --git a/src/test/subscription/testcase/ddl_replication_sql/A/ddl_drop_type.sql b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_drop_type.sql new file mode 100644 index 000000000..348f77685 --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_drop_type.sql @@ -0,0 +1,13 @@ +create table atable (id int, age int); + +create type atype as (id int, name text); +drop type atype; + +create type btype as object (id int, name text); +drop type btype; + +drop type typ_not_exit; + +drop type public.typ_not_exit; + +drop type schema_not_exit.typ_not_exit; \ No newline at end of file diff --git a/src/test/subscription/testcase/ddl_replication_sql/A/ddl_subpartition_tablespace.setup b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_subpartition_tablespace.setup new file mode 100644 index 000000000..9a92a4a50 --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_subpartition_tablespace.setup @@ -0,0 +1,20 @@ +source $1/env_utils.sh $1 $2 +subscription_dir=$1 +case_use_db=$3 + +tblspace="$subscription_dir/tmp_tblspace" +rm -rf $tblspace +mkdir -p $tblspace + + +tblspace_sub="$subscription_dir/tmp_tblspace_sub" +rm -rf $tblspace_sub +mkdir -p $tblspace_sub + +exec_sql $case_use_db $pub_node1_port "CREATE TABLESPACE hw_subpartition_tablespace_ts1 LOCATION '$tblspace/hw_subpartition_tablespace_ts1';" +exec_sql $case_use_db $pub_node1_port "CREATE TABLESPACE hw_subpartition_tablespace_ts2 LOCATION '$tblspace/hw_subpartition_tablespace_ts2';" +exec_sql $case_use_db $pub_node1_port "CREATE TABLESPACE hw_subpartition_tablespace_ts3 LOCATION '$tblspace/hw_subpartition_tablespace_ts3';" + +exec_sql $case_use_db $sub_node1_port "CREATE TABLESPACE hw_subpartition_tablespace_ts1 LOCATION '$tblspace_sub/hw_subpartition_tablespace_ts1';" +exec_sql $case_use_db $sub_node1_port "CREATE TABLESPACE hw_subpartition_tablespace_ts2 LOCATION '$tblspace_sub/hw_subpartition_tablespace_ts2';" +exec_sql $case_use_db $sub_node1_port "CREATE TABLESPACE hw_subpartition_tablespace_ts3 LOCATION '$tblspace_sub/hw_subpartition_tablespace_ts3';" \ No newline at end of file diff --git a/src/test/subscription/testcase/ddl_replication_sql/A/ddl_subpartition_tablespace.sql b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_subpartition_tablespace.sql new file mode 100644 index 000000000..a2fc39751 --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_subpartition_tablespace.sql @@ -0,0 +1,1013 @@ +--DROP SCHEMA hw_subpartition_tablespace CASCADE; +CREATE SCHEMA hw_subpartition_tablespace; +SET CURRENT_SCHEMA TO hw_subpartition_tablespace; + +-- +----test create subpartition with tablespace---- +-- +--range-range +CREATE TABLE t_range_range1(c1 int, c2 int, c3 int) +PARTITION BY RANGE (c1) SUBPARTITION BY RANGE (c2) +( + PARTITION P_RANGE1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_RANGE1_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE1_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE1_3 VALUES LESS THAN (15) + ), + PARTITION P_RANGE2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_RANGE2_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE2_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE2_3 VALUES LESS THAN (15) + ), + PARTITION P_RANGE3 VALUES LESS THAN (15) + ( + SUBPARTITION P_RANGE3_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE3_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE3_3 VALUES LESS THAN (15) + ), + PARTITION P_RANGE4 VALUES LESS THAN (20) TABLESPACE hw_subpartition_tablespace_ts1, + PARTITION P_RANGE5 VALUES LESS THAN (25) +); +SELECT pg_get_tabledef('t_range_range1'); +-- DROP TABLEt_range_range1; + +CREATE TABLE t_range_range2(c1 int, c2 int, c3 int) TABLESPACE hw_subpartition_tablespace_ts1 +PARTITION BY RANGE (c1) SUBPARTITION BY RANGE (c2) +( + PARTITION P_RANGE1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_RANGE1_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE1_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE1_3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_RANGE1_4 VALUES LESS THAN (20) + ), + PARTITION P_RANGE2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_RANGE2_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE2_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE2_3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_RANGE2_4 VALUES LESS THAN (20) + ), + PARTITION P_RANGE3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3 + ( + SUBPARTITION P_RANGE3_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE3_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE3_3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_RANGE3_4 VALUES LESS THAN (20) + ), + PARTITION P_RANGE4 VALUES LESS THAN (20) + ( + SUBPARTITION P_RANGE4_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE4_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE4_3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_RANGE4_4 VALUES LESS THAN (20) + ), + PARTITION P_RANGE5 VALUES LESS THAN (25) TABLESPACE hw_subpartition_tablespace_ts3, + PARTITION P_RANGE6 VALUES LESS THAN (30) +); +SELECT pg_get_tabledef('t_range_range2'); +-- DROP TABLEt_range_range2; + +--range-list +CREATE TABLE t_range_list1(c1 int, c2 int, c3 int) +PARTITION BY RANGE (c1) SUBPARTITION BY LIST (c2) +( + PARTITION P_RANGE1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_RANGE1_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE1_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE1_3 VALUES (11,12,13,14,15) + ), + PARTITION P_RANGE2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_RANGE2_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE2_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE2_3 VALUES (11,12,13,14,15) + ), + PARTITION P_RANGE3 VALUES LESS THAN (15) + ( + SUBPARTITION P_RANGE3_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE3_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE3_3 VALUES (11,12,13,14,15) + ), + PARTITION P_RANGE4 VALUES LESS THAN (20) TABLESPACE hw_subpartition_tablespace_ts1, + PARTITION P_RANGE5 VALUES LESS THAN (25) +); +SELECT pg_get_tabledef('t_range_list1'); +-- DROP TABLEt_range_list1; + +CREATE TABLE t_range_list2(c1 int, c2 int, c3 int) TABLESPACE hw_subpartition_tablespace_ts1 +PARTITION BY RANGE (c1) SUBPARTITION BY LIST (c2) +( + PARTITION P_RANGE1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_RANGE1_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE1_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE1_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_RANGE1_4 VALUES (16,17,18,19,20) + ), + PARTITION P_RANGE2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_RANGE2_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE2_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE2_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_RANGE2_4 VALUES (16,17,18,19,20) + ), + PARTITION P_RANGE3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3 + ( + SUBPARTITION P_RANGE3_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE3_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE3_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_RANGE3_4 VALUES (16,17,18,19,20) + ), + PARTITION P_RANGE4 VALUES LESS THAN (20) + ( + SUBPARTITION P_RANGE4_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE4_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE4_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_RANGE4_4 VALUES (16,17,18,19,20) + ), + PARTITION P_RANGE5 VALUES LESS THAN (25) TABLESPACE hw_subpartition_tablespace_ts3, + PARTITION P_RANGE6 VALUES LESS THAN (30) +); +SELECT pg_get_tabledef('t_range_list2'); +-- DROP TABLEt_range_list2; + +--range-hash +CREATE TABLE t_range_hash1(c1 int, c2 int, c3 int) +PARTITION BY RANGE (c1) SUBPARTITION BY HASH (c2) +( + PARTITION P_RANGE1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_RANGE1_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE1_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE1_3 + ), + PARTITION P_RANGE2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_RANGE2_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE2_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE2_3 + ), + PARTITION P_RANGE3 VALUES LESS THAN (15) + ( + SUBPARTITION P_RANGE3_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE3_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE3_3 + ), + PARTITION P_RANGE4 VALUES LESS THAN (20) TABLESPACE hw_subpartition_tablespace_ts1, + PARTITION P_RANGE5 VALUES LESS THAN (25) +); +SELECT pg_get_tabledef('t_range_hash1'); +-- DROP TABLEt_range_hash1; + +CREATE TABLE t_range_hash2(c1 int, c2 int, c3 int) TABLESPACE hw_subpartition_tablespace_ts1 +PARTITION BY RANGE (c1) SUBPARTITION BY HASH (c2) +( + PARTITION P_RANGE1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_RANGE1_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE1_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE1_3 TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_RANGE1_4 + ), + PARTITION P_RANGE2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_RANGE2_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE2_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE2_3 TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_RANGE2_4 + ), + PARTITION P_RANGE3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3 + ( + SUBPARTITION P_RANGE3_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE3_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE3_3 TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_RANGE3_4 + ), + PARTITION P_RANGE4 VALUES LESS THAN (20) + ( + SUBPARTITION P_RANGE4_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE4_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE4_3 TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_RANGE4_4 + ), + PARTITION P_RANGE5 VALUES LESS THAN (25) TABLESPACE hw_subpartition_tablespace_ts3, + PARTITION P_RANGE6 VALUES LESS THAN (30) +); +SELECT pg_get_tabledef('t_range_hash2'); +-- DROP TABLEt_range_hash2; + +--list-range +CREATE TABLE t_list_range1(c1 int, c2 int, c3 int) +PARTITION BY LIST (c1) SUBPARTITION BY RANGE (c2) +( + PARTITION P_LIST1 VALUES (1,2,3,4,5) TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_LIST1_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST1_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST1_3 VALUES LESS THAN (15) + ), + PARTITION P_LIST2 VALUES (6,7,8,9,10) TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_LIST2_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST2_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST2_3 VALUES LESS THAN (15) + ), + PARTITION P_LIST3 VALUES (11,12,13,14,15) + ( + SUBPARTITION P_LIST3_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST3_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST3_3 VALUES LESS THAN (15) + ), + PARTITION P_LIST4 VALUES (16,17,18,19,20) TABLESPACE hw_subpartition_tablespace_ts1, + PARTITION P_LIST5 VALUES (21,22,23,24,25) +); +SELECT pg_get_tabledef('t_list_range1'); +-- DROP TABLEt_list_range1; + +CREATE TABLE t_list_range2(c1 int, c2 int, c3 int) TABLESPACE hw_subpartition_tablespace_ts1 +PARTITION BY LIST (c1) SUBPARTITION BY RANGE (c2) +( + PARTITION P_LIST1 VALUES (1,2,3,4,5) TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_LIST1_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST1_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST1_3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST1_4 VALUES LESS THAN (20) + ), + PARTITION P_LIST2 VALUES (6,7,8,9,10) TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_LIST2_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST2_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST2_3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST2_4 VALUES LESS THAN (20) + ), + PARTITION P_LIST3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3 + ( + SUBPARTITION P_LIST3_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST3_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST3_3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST3_4 VALUES LESS THAN (20) + ), + PARTITION P_LIST4 VALUES (16,17,18,19,20) + ( + SUBPARTITION P_LIST4_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST4_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST4_3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST4_4 VALUES LESS THAN (20) + ), + PARTITION P_LIST5 VALUES (21,22,23,24,25) TABLESPACE hw_subpartition_tablespace_ts3, + PARTITION P_LIST6 VALUES (26,27,28,29,30) +); +SELECT pg_get_tabledef('t_list_range2'); +-- DROP TABLEt_list_range2; + +--list-list +CREATE TABLE t_list_list1(c1 int, c2 int, c3 int) +PARTITION BY LIST (c1) SUBPARTITION BY LIST (c2) +( + PARTITION P_LIST1 VALUES (1,2,3,4,5) TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_LIST1_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST1_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST1_3 VALUES (11,12,13,14,15) + ), + PARTITION P_LIST2 VALUES (6,7,8,9,10) TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_LIST2_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST2_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST2_3 VALUES (11,12,13,14,15) + ), + PARTITION P_LIST3 VALUES (11,12,13,14,15) + ( + SUBPARTITION P_LIST3_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST3_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST3_3 VALUES (11,12,13,14,15) + ), + PARTITION P_LIST4 VALUES (16,17,18,19,20) TABLESPACE hw_subpartition_tablespace_ts1, + PARTITION P_LIST5 VALUES (21,22,23,24,25) +); +SELECT pg_get_tabledef('t_list_list1'); +-- DROP TABLEt_list_list1; + +CREATE TABLE t_list_list2(c1 int, c2 int, c3 int) TABLESPACE hw_subpartition_tablespace_ts1 +PARTITION BY LIST (c1) SUBPARTITION BY LIST (c2) +( + PARTITION P_LIST1 VALUES (1,2,3,4,5) TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_LIST1_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST1_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST1_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST1_4 VALUES (16,17,18,19,20) + ), + PARTITION P_LIST2 VALUES (6,7,8,9,10) TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_LIST2_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST2_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST2_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST2_4 VALUES (16,17,18,19,20) + ), + PARTITION P_LIST3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3 + ( + SUBPARTITION P_LIST3_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST3_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST3_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST3_4 VALUES (16,17,18,19,20) + ), + PARTITION P_LIST4 VALUES (16,17,18,19,20) + ( + SUBPARTITION P_LIST4_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST4_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST4_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST4_4 VALUES (16,17,18,19,20) + ), + PARTITION P_LIST5 VALUES (21,22,23,24,25) TABLESPACE hw_subpartition_tablespace_ts3, + PARTITION P_LIST6 VALUES (26,27,28,29,30) +); +SELECT pg_get_tabledef('t_list_list2'); +-- DROP TABLEt_list_list2; + +--list-hash +CREATE TABLE t_list_hash1(c1 int, c2 int, c3 int) +PARTITION BY LIST (c1) SUBPARTITION BY HASH (c2) +( + PARTITION P_LIST1 VALUES (1,2,3,4,5) TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_LIST1_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST1_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST1_3 + ), + PARTITION P_LIST2 VALUES (6,7,8,9,10) TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_LIST2_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST2_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST2_3 + ), + PARTITION P_LIST3 VALUES (11,12,13,14,15) + ( + SUBPARTITION P_LIST3_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST3_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST3_3 + ), + PARTITION P_LIST4 VALUES (16,17,18,19,20) TABLESPACE hw_subpartition_tablespace_ts1, + PARTITION P_LIST5 VALUES (21,22,23,24,25) +); +SELECT pg_get_tabledef('t_list_hash1'); +-- DROP TABLEt_list_hash1; + +CREATE TABLE t_list_hash2(c1 int, c2 int, c3 int) TABLESPACE hw_subpartition_tablespace_ts1 +PARTITION BY LIST (c1) SUBPARTITION BY HASH (c2) +( + PARTITION P_LIST1 VALUES (1,2,3,4,5) TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_LIST1_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST1_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST1_3 TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST1_4 + ), + PARTITION P_LIST2 VALUES (6,7,8,9,10) TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_LIST2_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST2_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST2_3 TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST2_4 + ), + PARTITION P_LIST3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3 + ( + SUBPARTITION P_LIST3_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST3_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST3_3 TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST3_4 + ), + PARTITION P_LIST4 VALUES (16,17,18,19,20) + ( + SUBPARTITION P_LIST4_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST4_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST4_3 TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST4_4 + ), + PARTITION P_LIST5 VALUES (21,22,23,24,25) TABLESPACE hw_subpartition_tablespace_ts3, + PARTITION P_LIST6 VALUES (26,27,28,29,30) +); +SELECT pg_get_tabledef('t_list_hash2'); +-- DROP TABLEt_list_hash2; + +--hash-range +CREATE TABLE t_hash_range1(c1 int, c2 int, c3 int) +PARTITION BY HASH (c1) SUBPARTITION BY RANGE (c2) +( + PARTITION P_HASH1 TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_HASH1_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH1_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH1_3 VALUES LESS THAN (15) + ), + PARTITION P_HASH2 TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_HASH2_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH2_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH2_3 VALUES LESS THAN (15) + ), + PARTITION P_HASH3 + ( + SUBPARTITION P_HASH3_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH3_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH3_3 VALUES LESS THAN (15) + ), + PARTITION P_HASH4 TABLESPACE hw_subpartition_tablespace_ts1, + PARTITION P_HASH5 +); +SELECT pg_get_tabledef('t_hash_range1'); +-- DROP TABLEt_hash_range1; + +CREATE TABLE t_hash_range2(c1 int, c2 int, c3 int) TABLESPACE hw_subpartition_tablespace_ts1 +PARTITION BY HASH (c1) SUBPARTITION BY RANGE (c2) +( + PARTITION P_HASH1 TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_HASH1_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH1_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH1_3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_HASH1_4 VALUES LESS THAN (20) + ), + PARTITION P_HASH2 TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_HASH2_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH2_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH2_3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_HASH2_4 VALUES LESS THAN (20) + ), + PARTITION P_HASH3 TABLESPACE hw_subpartition_tablespace_ts3 + ( + SUBPARTITION P_HASH3_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH3_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH3_3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_HASH3_4 VALUES LESS THAN (20) + ), + PARTITION P_HASH4 + ( + SUBPARTITION P_HASH4_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH4_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH4_3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_HASH4_4 VALUES LESS THAN (20) + ), + PARTITION P_HASH5 TABLESPACE hw_subpartition_tablespace_ts3, + PARTITION P_HASH6 +); +SELECT pg_get_tabledef('t_hash_range2'); +-- DROP TABLEt_hash_range2; + +--hash-list +CREATE TABLE t_hash_list1(c1 int, c2 int, c3 int) +PARTITION BY HASH (c1) SUBPARTITION BY LIST (c2) +( + PARTITION P_HASH1 TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_HASH1_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH1_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH1_3 VALUES (11,12,13,14,15) + ), + PARTITION P_HASH2 TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_HASH2_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH2_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH2_3 VALUES (11,12,13,14,15) + ), + PARTITION P_HASH3 + ( + SUBPARTITION P_HASH3_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH3_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH3_3 VALUES (11,12,13,14,15) + ), + PARTITION P_HASH4 TABLESPACE hw_subpartition_tablespace_ts1, + PARTITION P_HASH5 +); +SELECT pg_get_tabledef('t_hash_list1'); +-- DROP TABLEt_hash_list1; + +CREATE TABLE t_hash_list2(c1 int, c2 int, c3 int) TABLESPACE hw_subpartition_tablespace_ts1 +PARTITION BY HASH (c1) SUBPARTITION BY LIST (c2) +( + PARTITION P_HASH1 TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_HASH1_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH1_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH1_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_HASH1_4 VALUES (16,17,18,19,20) + ), + PARTITION P_HASH2 TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_HASH2_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH2_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH2_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_HASH2_4 VALUES (16,17,18,19,20) + ), + PARTITION P_HASH3 TABLESPACE hw_subpartition_tablespace_ts3 + ( + SUBPARTITION P_HASH3_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH3_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH3_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_HASH3_4 VALUES (16,17,18,19,20) + ), + PARTITION P_HASH4 + ( + SUBPARTITION P_HASH4_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH4_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH4_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_HASH4_4 VALUES (16,17,18,19,20) + ), + PARTITION P_HASH5 TABLESPACE hw_subpartition_tablespace_ts3, + PARTITION P_HASH6 +); +SELECT pg_get_tabledef('t_hash_list2'); +-- DROP TABLEt_hash_list2; + +--hash-hash +CREATE TABLE t_hash_hash1(c1 int, c2 int, c3 int) +PARTITION BY HASH (c1) SUBPARTITION BY HASH (c2) +( + PARTITION P_HASH1 TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_HASH1_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH1_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH1_3 + ), + PARTITION P_HASH2 TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_HASH2_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH2_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH2_3 + ), + PARTITION P_HASH3 + ( + SUBPARTITION P_HASH3_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH3_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH3_3 + ), + PARTITION P_HASH4 TABLESPACE hw_subpartition_tablespace_ts1, + PARTITION P_HASH5 +); +SELECT pg_get_tabledef('t_hash_hash1'); +-- DROP TABLEt_hash_hash1; + +CREATE TABLE t_hash_hash2(c1 int, c2 int, c3 int) TABLESPACE hw_subpartition_tablespace_ts1 +PARTITION BY HASH (c1) SUBPARTITION BY HASH (c2) +( + PARTITION P_HASH1 TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_HASH1_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH1_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH1_3 TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_HASH1_4 + ), + PARTITION P_HASH2 TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_HASH2_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH2_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH2_3 TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_HASH2_4 + ), + PARTITION P_HASH3 TABLESPACE hw_subpartition_tablespace_ts3 + ( + SUBPARTITION P_HASH3_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH3_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH3_3 TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_HASH3_4 + ), + PARTITION P_HASH4 + ( + SUBPARTITION P_HASH4_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH4_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH4_3 TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_HASH4_4 + ), + PARTITION P_HASH5 TABLESPACE hw_subpartition_tablespace_ts3, + PARTITION P_HASH6 +); +SELECT pg_get_tabledef('t_hash_hash2'); +-- DROP TABLEt_hash_hash2; + +-- +----test add partition with tablespace---- +-- +--since the add subpartition define use the same code, we only test different partition type: range/list +--range-list +CREATE TABLE t_range_list3(c1 int, c2 int, c3 int) +PARTITION BY RANGE (c1) SUBPARTITION BY LIST (c2) +( + PARTITION P_RANGE1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_RANGE1_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE1_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE1_3 VALUES (11,12,13,14,15) + ), + PARTITION P_RANGE2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_RANGE2_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE2_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE2_3 VALUES (11,12,13,14,15) + ) +); +ALTER TABLE t_range_list3 ADD PARTITION P_RANGE3 VALUES LESS THAN (15) + ( + SUBPARTITION P_RANGE3_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE3_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE3_3 VALUES (11,12,13,14,15) + ); +ALTER TABLE t_range_list3 ADD PARTITION P_RANGE4 VALUES LESS THAN (20) TABLESPACE hw_subpartition_tablespace_ts1; +ALTER TABLE t_range_list3 ADD PARTITION P_RANGE5 VALUES LESS THAN (25); +SELECT pg_get_tabledef('t_range_list3'); +-- DROP TABLEt_range_list3; + + +CREATE TABLE t_range_list4(c1 int, c2 int, c3 int) TABLESPACE hw_subpartition_tablespace_ts1 +PARTITION BY RANGE (c1) SUBPARTITION BY LIST (c2) +( + PARTITION P_RANGE1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_RANGE1_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE1_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE1_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_RANGE1_4 VALUES (16,17,18,19,20) + ), + PARTITION P_RANGE2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_RANGE2_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE2_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE2_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_RANGE2_4 VALUES (16,17,18,19,20) + ) +); +ALTER TABLE t_range_list4 ADD PARTITION P_RANGE3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3 + ( + SUBPARTITION P_RANGE3_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE3_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE3_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_RANGE3_4 VALUES (16,17,18,19,20) + ); +ALTER TABLE t_range_list4 ADD PARTITION P_RANGE4 VALUES LESS THAN (20) + ( + SUBPARTITION P_RANGE4_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE4_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE4_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_RANGE4_4 VALUES (16,17,18,19,20) + ); +ALTER TABLE t_range_list4 ADD PARTITION P_RANGE5 VALUES LESS THAN (25) TABLESPACE hw_subpartition_tablespace_ts3; +ALTER TABLE t_range_list4 ADD PARTITION P_RANGE6 VALUES LESS THAN (30); +SELECT pg_get_tabledef('t_range_list4'); +-- DROP TABLEt_range_list4; + +--list-hash +CREATE TABLE t_list_hash3(c1 int, c2 int, c3 int) +PARTITION BY LIST (c1) SUBPARTITION BY HASH (c2) +( + PARTITION P_LIST1 VALUES (1,2,3,4,5) TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_LIST1_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST1_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST1_3 + ), + PARTITION P_LIST2 VALUES (6,7,8,9,10) TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_LIST2_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST2_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST2_3 + ) +); + +ALTER TABLE t_list_hash3 ADD PARTITION P_LIST3 VALUES (11,12,13,14,15) + ( + SUBPARTITION P_LIST3_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST3_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST3_3 + ); +ALTER TABLE t_list_hash3 ADD PARTITION P_LIST4 VALUES (16,17,18,19,20) TABLESPACE hw_subpartition_tablespace_ts1; +ALTER TABLE t_list_hash3 ADD PARTITION P_LIST5 VALUES (21,22,23,24,25); +SELECT pg_get_tabledef('t_list_hash3'); +-- DROP TABLEt_list_hash3; + +CREATE TABLE t_list_hash4(c1 int, c2 int, c3 int) TABLESPACE hw_subpartition_tablespace_ts1 +PARTITION BY LIST (c1) SUBPARTITION BY HASH (c2) +( + PARTITION P_LIST1 VALUES (1,2,3,4,5) TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_LIST1_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST1_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST1_3 TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST1_4 + ), + PARTITION P_LIST2 VALUES (6,7,8,9,10) TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_LIST2_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST2_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST2_3 TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST2_4 + ) +); +ALTER TABLE t_list_hash4 ADD PARTITION P_LIST3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3 + ( + SUBPARTITION P_LIST3_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST3_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST3_3 TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST3_4 + ); +ALTER TABLE t_list_hash4 ADD PARTITION P_LIST4 VALUES (16,17,18,19,20) + ( + SUBPARTITION P_LIST4_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST4_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST4_3 TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST4_4 + ); +ALTER TABLE t_list_hash4 ADD PARTITION P_LIST5 VALUES (21,22,23,24,25) TABLESPACE hw_subpartition_tablespace_ts3; +ALTER TABLE t_list_hash4 ADD PARTITION P_LIST6 VALUES (26,27,28,29,30); +SELECT pg_get_tabledef('t_list_hash4'); +-- DROP TABLEt_list_hash4; + +-- +----test add subpartition with tablespace---- +-- +--list-range +CREATE TABLE t_list_range3(c1 int, c2 int, c3 int) +PARTITION BY LIST (c1) SUBPARTITION BY RANGE (c2) +( + PARTITION P_LIST1 VALUES (1,2,3,4,5) TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_LIST1_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST1_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST1_3 VALUES LESS THAN (15) + ), + PARTITION P_LIST2 VALUES (6,7,8,9,10) TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_LIST2_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST2_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST2_3 VALUES LESS THAN (15) + ), + PARTITION P_LIST3 VALUES (11,12,13,14,15) + ( + SUBPARTITION P_LIST3_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST3_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST3_3 VALUES LESS THAN (15) + ), + PARTITION P_LIST4 VALUES (16,17,18,19,20) TABLESPACE hw_subpartition_tablespace_ts1, + PARTITION P_LIST5 VALUES (21,22,23,24,25) +); +ALTER TABLE t_list_range3 MODIFY PARTITION P_LIST1 ADD SUBPARTITION P_LIST1_4 VALUES LESS THAN (20) TABLESPACE hw_subpartition_tablespace_ts3; +ALTER TABLE t_list_range3 MODIFY PARTITION P_LIST2 ADD SUBPARTITION P_LIST2_4 VALUES LESS THAN (20); +ALTER TABLE t_list_range3 MODIFY PARTITION P_LIST3 ADD SUBPARTITION P_LIST3_4 VALUES LESS THAN (20); +SELECT pg_get_tabledef('t_list_range3'); +-- DROP TABLEt_list_range3; + +CREATE TABLE t_list_range4(c1 int, c2 int, c3 int) TABLESPACE hw_subpartition_tablespace_ts1 +PARTITION BY LIST (c1) SUBPARTITION BY RANGE (c2) +( + PARTITION P_LIST1 VALUES (1,2,3,4,5) TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_LIST1_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST1_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST1_3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST1_4 VALUES LESS THAN (20) + ), + PARTITION P_LIST2 VALUES (6,7,8,9,10) TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_LIST2_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST2_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST2_3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST2_4 VALUES LESS THAN (20) + ), + PARTITION P_LIST3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3 + ( + SUBPARTITION P_LIST3_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST3_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST3_3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST3_4 VALUES LESS THAN (20) + ), + PARTITION P_LIST4 VALUES (16,17,18,19,20) + ( + SUBPARTITION P_LIST4_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST4_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST4_3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST4_4 VALUES LESS THAN (20) + ), + PARTITION P_LIST5 VALUES (21,22,23,24,25) TABLESPACE hw_subpartition_tablespace_ts3, + PARTITION P_LIST6 VALUES (26,27,28,29,30) +); +ALTER TABLE t_list_range4 MODIFY PARTITION P_LIST1 ADD SUBPARTITION P_LIST1_5 VALUES LESS THAN (25) TABLESPACE hw_subpartition_tablespace_ts3; +ALTER TABLE t_list_range4 MODIFY PARTITION P_LIST2 ADD SUBPARTITION P_LIST2_5 VALUES LESS THAN (25) TABLESPACE hw_subpartition_tablespace_ts2; +ALTER TABLE t_list_range4 MODIFY PARTITION P_LIST3 ADD SUBPARTITION P_LIST3_5 VALUES LESS THAN (25); +ALTER TABLE t_list_range4 MODIFY PARTITION P_LIST4 ADD SUBPARTITION P_LIST4_5 VALUES LESS THAN (25); +SELECT pg_get_tabledef('t_list_range4'); +-- DROP TABLEt_list_range4; + +--hash-list +CREATE TABLE t_hash_list3(c1 int, c2 int, c3 int) +PARTITION BY HASH (c1) SUBPARTITION BY LIST (c2) +( + PARTITION P_HASH1 TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_HASH1_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH1_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH1_3 VALUES (11,12,13,14,15) + ), + PARTITION P_HASH2 TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_HASH2_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH2_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH2_3 VALUES (11,12,13,14,15) + ), + PARTITION P_HASH3 + ( + SUBPARTITION P_HASH3_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH3_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH3_3 VALUES (11,12,13,14,15) + ), + PARTITION P_HASH4 TABLESPACE hw_subpartition_tablespace_ts1, + PARTITION P_HASH5 +); +ALTER TABLE t_hash_list3 MODIFY PARTITION P_HASH1 ADD SUBPARTITION P_HASH1_4 VALUES (16,17,18,19,20) TABLESPACE hw_subpartition_tablespace_ts3; +ALTER TABLE t_hash_list3 MODIFY PARTITION P_HASH2 ADD SUBPARTITION P_HASH2_4 VALUES (16,17,18,19,20); +ALTER TABLE t_hash_list3 MODIFY PARTITION P_HASH3 ADD SUBPARTITION P_HASH3_4 VALUES (16,17,18,19,20); +SELECT pg_get_tabledef('t_hash_list3'); +-- DROP TABLEt_hash_list3; + +CREATE TABLE t_hash_list4(c1 int, c2 int, c3 int) TABLESPACE hw_subpartition_tablespace_ts1 +PARTITION BY HASH (c1) SUBPARTITION BY LIST (c2) +( + PARTITION P_HASH1 TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_HASH1_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH1_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH1_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_HASH1_4 VALUES (16,17,18,19,20) + ), + PARTITION P_HASH2 TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_HASH2_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH2_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH2_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_HASH2_4 VALUES (16,17,18,19,20) + ), + PARTITION P_HASH3 TABLESPACE hw_subpartition_tablespace_ts3 + ( + SUBPARTITION P_HASH3_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH3_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH3_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_HASH3_4 VALUES (16,17,18,19,20) + ), + PARTITION P_HASH4 + ( + SUBPARTITION P_HASH4_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH4_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH4_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_HASH4_4 VALUES (16,17,18,19,20) + ), + PARTITION P_HASH5 TABLESPACE hw_subpartition_tablespace_ts3, + PARTITION P_HASH6 +); +ALTER TABLE t_hash_list4 MODIFY PARTITION P_HASH1 ADD SUBPARTITION P_HASH1_5 VALUES(21,22,23,24,25) TABLESPACE hw_subpartition_tablespace_ts3; +ALTER TABLE t_hash_list4 MODIFY PARTITION P_HASH2 ADD SUBPARTITION P_HASH2_5 VALUES(21,22,23,24,25) TABLESPACE hw_subpartition_tablespace_ts2; +ALTER TABLE t_hash_list4 MODIFY PARTITION P_HASH3 ADD SUBPARTITION P_HASH3_5 VALUES(21,22,23,24,25); +ALTER TABLE t_hash_list4 MODIFY PARTITION P_HASH4 ADD SUBPARTITION P_HASH4_5 VALUES(21,22,23,24,25); +SELECT pg_get_tabledef('t_hash_list4'); +-- DROP TABLEt_hash_list4; + +-- +----test create index with tablespace---- +-- +CREATE TABLE t_range_list(c1 int, c2 int, c3 int) TABLESPACE hw_subpartition_tablespace_ts1 +PARTITION BY RANGE (c1) SUBPARTITION BY LIST (c2) +( + PARTITION P_RANGE1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_RANGE1_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE1_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE1_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_RANGE1_4 VALUES (16,17,18,19,20) + ), + PARTITION P_RANGE2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_RANGE2_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE2_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE2_3 VALUES (DEFAULT) + ), + PARTITION P_RANGE3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3 + ( + SUBPARTITION P_RANGE3_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE3_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE3_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_RANGE3_4 VALUES (16,17,18,19,20) + ), + PARTITION P_RANGE4 VALUES LESS THAN (20) + ( + SUBPARTITION P_RANGE4_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE4_2 VALUES (DEFAULT) TABLESPACE hw_subpartition_tablespace_ts2 + ), + PARTITION P_RANGE5 VALUES LESS THAN (25) TABLESPACE hw_subpartition_tablespace_ts3, + PARTITION P_RANGE6 VALUES LESS THAN (30) +); + +CREATE INDEX t_range_list_idx ON t_range_list(c1,c2) LOCAL +( + PARTITION idx_p1( + SUBPARTITION idx_p1_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION idx_p1_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION idx_p1_3 TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION idx_p1_4 + ), + PARTITION idx_p2 TABLESPACE hw_subpartition_tablespace_ts2( + SUBPARTITION idx_p2_1, + SUBPARTITION idx_p2_2, + SUBPARTITION idx_p2_3 + ), + PARTITION idx_p3 TABLESPACE hw_subpartition_tablespace_ts2( + SUBPARTITION idx_p3_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION idx_p3_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION idx_p3_3 TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION idx_p3_4 + ), + PARTITION idx_p4( + SUBPARTITION idx_p4_1, + SUBPARTITION idx_p4_2 TABLESPACE hw_subpartition_tablespace_ts2 + ), + PARTITION idx_p5 TABLESPACE hw_subpartition_tablespace_ts3( + SUBPARTITION idx_p5_1 + ), + PARTITION idx_p6( + SUBPARTITION idx_p6_1 TABLESPACE hw_subpartition_tablespace_ts2 + ) +) TABLESPACE hw_subpartition_tablespace_ts1; + +ALTER TABLE t_range_list TRUNCATE SUBPARTITION P_RANGE1_1; + +SELECT p.relname, t.spcname FROM pg_partition p, pg_class c, pg_namespace n, pg_tablespace t +WHERE p.parentid = c.oid + AND c.relname='t_range_list_idx' + AND c.relnamespace=n.oid + AND n.nspname=CURRENT_SCHEMA + AND p.reltablespace = t.oid +ORDER BY p.relname; + +SELECT pg_get_indexdef('hw_subpartition_tablespace.t_range_list_idx'::regclass); + +CREATE TABLE range_sales +( + product_id INT4 NOT NULL, + customer_id INT4 PRIMARY KEY, + time_id DATE, + channel_id CHAR(1), + type_id INT4, + quantity_sold NUMERIC(3), + amount_sold NUMERIC(10,2) +) +PARTITION BY RANGE (time_id) +( + PARTITION time_2008 VALUES LESS THAN ('2009-01-01'), + PARTITION time_2009 VALUES LESS THAN ('2010-01-01'), + PARTITION time_2010 VALUES LESS THAN ('2011-01-01'), + PARTITION time_2011 VALUES LESS THAN ('2012-01-01') +); +INSERT INTO range_sales SELECT generate_series(1,1000), + generate_series(1,1000), + date_pli('2008-01-01', generate_series(1,1000)), + generate_series(1,1000)%10, + generate_series(1,1000)%10, + generate_series(1,1000)%1000, + generate_series(1,1000); +CREATE INDEX range_sales_idx ON range_sales(product_id) LOCAL; +--success, add 1 partition +ALTER TABLE range_sales ADD PARTITION time_2012 VALUES LESS THAN ('2013-01-01') TABLESPACE hw_subpartition_tablespace_ts3; +--success, add 1 partition +ALTER TABLE range_sales ADD PARTITION time_end VALUES LESS THAN (MAXVALUE) TABLESPACE hw_subpartition_tablespace_ts3; + +create table test_index_lt (a int, b int, c int) +partition by list(a) +( + PARTITION p1 VALUES (3, 4, 5), + PARTITION p2 VALUES (1, 2) +); + +ALTER TABLE test_index_lt ADD PARTITION p3 VALUES (6) TABLESPACE hw_subpartition_tablespace_ts2; +ALTER TABLE test_index_lt MOVE PARTITION FOR (5) TABLESPACE hw_subpartition_tablespace_ts3; + +ALTER TABLE test_index_lt MOVE PARTITION p3 TABLESPACE hw_subpartition_tablespace_ts3; + +create index test_index_lt_idx on test_index_lt(a) local; + +ALTER TABLE test_index_lt MODIFY PARTITION p1 UNUSABLE LOCAL INDEXES ; + +ALTER TABLE test_index_lt MODIFY PARTITION p1 rebuild UNUSABLE LOCAL INDEXES ; + +-- DROP TABLEt_range_list; + +--finish +drop tablespace hw_subpartition_tablespace_ts1; +drop tablespace hw_subpartition_tablespace_ts2; +drop tablespace hw_subpartition_tablespace_ts3; +\! rm -fr '@testtablespace@/hw_subpartition_tablespace_ts1' +\! rm -fr '@testtablespace@/hw_subpartition_tablespace_ts2' +\! rm -fr '@testtablespace@/hw_subpartition_tablespace_ts3' + +DROP SCHEMA hw_subpartition_tablespace CASCADE; +RESET CURRENT_SCHEMA; diff --git a/src/test/subscription/testcase/ddl_replication_sql/A/ddl_view_def.sql b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_view_def.sql new file mode 100644 index 000000000..1a5917bad --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/A/ddl_view_def.sql @@ -0,0 +1,36 @@ +CREATE TABLE tb_class (id INT,class_name TEXT); +INSERT INTO tb_class (id,class_name) VALUES (1,'class_1'); +INSERT INTO tb_class (id,class_name) VALUES (2,'class_2'); + +CREATE TABLE tb_student (id INT,student_name TEXT,class_id INT); +INSERT INTO tb_student (id,student_name,class_id) VALUES (1,'li lei',1); +INSERT INTO tb_student (id,student_name,class_id) VALUES (2,'han meimei',1); +INSERT INTO tb_student (id,student_name,class_id) VALUES (3,'zhang xiaoming',2); +INSERT INTO tb_student (id,student_name,class_id) VALUES (4,'wang peng',2); + +CREATE VIEW vw_class AS SELECT * FROM tb_class; +CREATE VIEW vw_student AS SELECT * FROM tb_student; +CREATE VIEW vw_class_student AS SELECT c.class_name,s.student_name FROM tb_class c JOIN tb_student s ON c.id = s.class_id; +CREATE VIEW vw_class_1_student AS SELECT c.class_name,s.student_name FROM tb_class c JOIN tb_student s ON c.id = s.class_id WHERE c.id = 1; + +CREATE TABLE tb_order (id INT,order_product TEXT,order_time timestamptz); +INSERT INTO tb_order (id,order_product) VALUES (1,'football'); +INSERT INTO tb_order (id,order_product) VALUES (2,'baskball'); + +CREATE VIEW vw_order AS SELECT * FROM tb_order; +ALTER VIEW vw_order ALTER COLUMN order_time SET DEFAULT now(); + + +CREATE TABLE tb_address (id INT,address TEXT); +INSERT INTO tb_address (id,address) VALUES (1,'a_address'); +INSERT INTO tb_address (id,address) VALUES (2,'b_address'); + +CREATE VIEW vw_address AS SELECT * FROM tb_address; +ALTER VIEW vw_address RENAME TO vw_address_new; + +CREATE TABLE tb_book (id INT,book_name TEXT); +INSERT INTO tb_book (id,book_name) VALUES (1,'englisen'); +INSERT INTO tb_book (id,book_name) VALUES (2,'math'); + +CREATE VIEW vw_book AS SELECT * FROM tb_book; +DROP VIEW vw_book; \ No newline at end of file diff --git a/src/test/subscription/testcase/ddl_replication_sql/B/acceptable_diff/ddl_alter_table_002.diff b/src/test/subscription/testcase/ddl_replication_sql/B/acceptable_diff/ddl_alter_table_002.diff new file mode 100644 index 000000000..a36570ea8 --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/B/acceptable_diff/ddl_alter_table_002.diff @@ -0,0 +1,4 @@ +386c386 +< CONSTRAINT at4acc_test1 CHECK (((test OPERATOR(dolphin_catalog.+) test2) < (test3 OPERATOR(dolphin_catalog.*) 4))) +--- +> CONSTRAINT at4acc_test1 CHECK ((((test)::bigint + (test2)::bigint) < ((test3)::bigint * (4)::bigint))) diff --git a/src/test/subscription/testcase/ddl_replication_sql/B/acceptable_diff/ddl_alter_table_rewrite.diff b/src/test/subscription/testcase/ddl_replication_sql/B/acceptable_diff/ddl_alter_table_rewrite.diff new file mode 100644 index 000000000..109bd6b00 --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/B/acceptable_diff/ddl_alter_table_rewrite.diff @@ -0,0 +1,4 @@ +47c47 +< g timestamp(0) with time zone GENERATED ALWAYS AS (((b)::double precision + 1::double precision)) STORED, +--- +> g timestamp(0) with time zone GENERATED ALWAYS AS (((b)::double precision + (1)::double precision)) STORED, diff --git a/src/test/subscription/testcase/ddl_replication_sql/B/create_table.sql b/src/test/subscription/testcase/ddl_replication_sql/B/create_table.sql index 60fb85d61..060850d2d 100644 --- a/src/test/subscription/testcase/ddl_replication_sql/B/create_table.sql +++ b/src/test/subscription/testcase/ddl_replication_sql/B/create_table.sql @@ -91,4 +91,10 @@ CREATE TABLE tab_on_update12 ( col_name TEXT, upd_time TIME DEFAULT LOCALTIMESTAMP(2) ON UPDATE LOCALTIMESTAMP(2) COMMENT 'update record local timestamp(2)', PRIMARY KEY (col_id) -); \ No newline at end of file +); + +alter table tab_on_update12 MODIFY COLUMN col_name text CHARSET 'utf8' COLLATE utf8mb4_bin; +alter table tab_on_update12 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin; +alter table tab_on_update12 CONVERT TO CHARACTER SET 'utf8' COLLATE utf8mb4_bin; + +alter table tab_on_update12 CHANGE COLUMN col_name col_name2 text CHARSET 'utf8' COLLATE utf8mb4_bin FIRST; diff --git a/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_function.setup b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_function.setup new file mode 100644 index 000000000..234cbb4cd --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_function.setup @@ -0,0 +1,9 @@ +#!/bin/sh + +source $1/env_utils.sh $1 $2 +subscription_dir=$1 +case_use_db=$3 + +exec_sql_with_user $case_use_db $pub_node1_port "CREATE USER regtest_unpriv_user PASSWORD 'gauss@123'" + +exec_sql_with_user $case_use_db $sub_node1_port "CREATE USER regtest_unpriv_user PASSWORD 'gauss@123'" \ No newline at end of file diff --git a/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_function.sql b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_function.sql new file mode 100644 index 000000000..31dfb7d2e --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_function.sql @@ -0,0 +1,67 @@ +-- +-- IMMUTABLE | STABLE | VOLATILE +-- +CREATE FUNCTION functest_B_1(int) RETURNS bool LANGUAGE 'sql' + AS 'SELECT $1 > 0'; +CREATE FUNCTION functest_B_2(int) RETURNS bool LANGUAGE 'sql' + IMMUTABLE AS 'SELECT $1 > 0'; +CREATE FUNCTION functest_B_3(int) RETURNS bool LANGUAGE 'sql' + STABLE AS 'SELECT $1 = 0'; +CREATE FUNCTION functest_B_4(int) RETURNS bool LANGUAGE 'sql' + VOLATILE AS 'SELECT $1 < 0'; +ALTER FUNCTION functest_B_2(int) VOLATILE; + +-- +-- SECURITY DEFINER | INVOKER +-- +CREATE FUNCTION functest_C_1(int) RETURNS bool LANGUAGE 'sql' + AS 'SELECT $1 > 0'; +CREATE FUNCTION functest_C_2(int) RETURNS bool LANGUAGE 'sql' + SECURITY DEFINER AS 'SELECT $1 = 0'; +CREATE FUNCTION functest_C_3(int) RETURNS bool LANGUAGE 'sql' + SECURITY INVOKER AS 'SELECT $1 < 0'; +ALTER FUNCTION functest_C_1(int) IMMUTABLE; -- unrelated change, no effect +ALTER FUNCTION functest_C_2(int) SECURITY INVOKER; +ALTER FUNCTION functest_C_3(int) SECURITY DEFINER; + +-- +-- LEAKPROOF +-- +CREATE FUNCTION functest_E_1(int) RETURNS bool LANGUAGE 'sql' + AS 'SELECT $1 > 100'; +CREATE FUNCTION functest_E_2(int) RETURNS bool LANGUAGE 'sql' + LEAKPROOF AS 'SELECT $1 > 100'; +ALTER FUNCTION functest_E_1(int) LEAKPROOF; +ALTER FUNCTION functest_E_2(int) STABLE; -- unrelated change, no effect +ALTER FUNCTION functest_E_2(int) NOT LEAKPROOF; -- remove leakproog attribute +-- it takes superuser privilege to turn on leakproof, but not for turn off +--ALTER FUNCTION functest_E_1(int) OWNER TO regtest_unpriv_user; +--ALTER FUNCTION functest_E_2(int) OWNER TO regtest_unpriv_user; + + +-- +-- CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT +-- +CREATE FUNCTION functest_F_1(int) RETURNS bool LANGUAGE 'sql' + AS 'SELECT $1 > 50'; +CREATE FUNCTION functest_F_2(int) RETURNS bool LANGUAGE 'sql' + CALLED ON NULL INPUT AS 'SELECT $1 = 50'; +CREATE FUNCTION functest_F_3(int) RETURNS bool LANGUAGE 'sql' + RETURNS NULL ON NULL INPUT AS 'SELECT $1 < 50'; +CREATE FUNCTION functest_F_4(int) RETURNS bool LANGUAGE 'sql' + STRICT AS 'SELECT $1 = 50'; +ALTER FUNCTION functest_F_1(int) IMMUTABLE; -- unrelated change, no effect +ALTER FUNCTION functest_F_2(int) STRICT; +ALTER FUNCTION functest_F_3(int) CALLED ON NULL INPUT; + +--ALTER FUNCTION functest_F_3(int) COST 2; + +ALTER FUNCTION functest_F_3(int) set query_dop to 2; +ALTER FUNCTION functest_F_3(int) set work_mem to '2MB'; +ALTER FUNCTION functest_F_3(int) RESET work_mem; +ALTER FUNCTION functest_F_3(int) RESET ALL; + +CREATE FUNCTION select3 () RETURNS setof int LANGUAGE SQL +AS 'select generate_series(1, 10);'; +ALTER FUNCTION select3() ROWS 1; +ALTER FUNCTION select3() ROWS 33.3; diff --git a/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_function.teardown b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_function.teardown new file mode 100644 index 000000000..4e450e63b --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_function.teardown @@ -0,0 +1,8 @@ +#!/bin/sh + +source $1/env_utils.sh $1 $2 +subscription_dir=$1 +case_use_db=$3 + +exec_sql_with_user $case_use_db $sub_node1_port "DROP USER regtest_unpriv_user" +exec_sql_with_user $case_use_db $pub_node1_port "DROP USER regtest_unpriv_user" \ No newline at end of file diff --git a/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_schema.setup b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_schema.setup new file mode 100644 index 000000000..234cbb4cd --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_schema.setup @@ -0,0 +1,9 @@ +#!/bin/sh + +source $1/env_utils.sh $1 $2 +subscription_dir=$1 +case_use_db=$3 + +exec_sql_with_user $case_use_db $pub_node1_port "CREATE USER regtest_unpriv_user PASSWORD 'gauss@123'" + +exec_sql_with_user $case_use_db $sub_node1_port "CREATE USER regtest_unpriv_user PASSWORD 'gauss@123'" \ No newline at end of file diff --git a/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_schema.sql b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_schema.sql new file mode 100644 index 000000000..ef95d030d --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_schema.sql @@ -0,0 +1,15 @@ +create SCHEMA test_sche; + +ALTER SCHEMA test_sche WITH BLOCKCHAIN; +ALTER SCHEMA test_sche WITHOUT BLOCKCHAIN; + +ALTER SCHEMA test_sche RENAME TO test_sche1; +ALTER SCHEMA test_sche1 OWNER TO regtest_unpriv_user; + +ALTER SCHEMA test_sche1 CHARACTER SET utf8mb4 COLLATE utf8mb4_bin; + +create SCHEMA test_sche2; + +create table t1(id int); +ALTER table t1 set SCHEMA test_sche2; + diff --git a/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_schema.teardown b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_schema.teardown new file mode 100644 index 000000000..4e450e63b --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_schema.teardown @@ -0,0 +1,8 @@ +#!/bin/sh + +source $1/env_utils.sh $1 $2 +subscription_dir=$1 +case_use_db=$3 + +exec_sql_with_user $case_use_db $sub_node1_port "DROP USER regtest_unpriv_user" +exec_sql_with_user $case_use_db $pub_node1_port "DROP USER regtest_unpriv_user" \ No newline at end of file diff --git a/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table.sql b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table.sql new file mode 100644 index 000000000..2fc4e77b5 --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table.sql @@ -0,0 +1,2358 @@ +-- +--FOR BLACKLIST FEATURE: REFERENCES/INHERITS/WITH OIDS/RULE/CREATE TYPE/DOMAIN is not supported. +-- +-- test inheritance + +create table dropColumn (a int, b int, e int); +create table dropColumnChild (c int) inherits (dropColumn); +create table dropColumnAnother (d int) inherits (dropColumnChild); + +-- these two should fail +alter table dropColumnchild drop column a; +alter table only dropColumnChild drop column b; + + + +-- these three should work +alter table only dropColumn drop column e; +alter table dropColumnChild drop column c; +alter table dropColumn drop column a; + +create table renameColumn (a int); +create table renameColumnChild (b int) inherits (renameColumn); +create table renameColumnAnother (c int) inherits (renameColumnChild); + +-- these three should fail +alter table renameColumnChild rename column a to d; +alter table only renameColumnChild rename column a to d; +alter table only renameColumn rename column a to d; + +-- these should work +alter table renameColumn rename column a to d; +alter table renameColumnChild rename column b to a; + +-- these should work +alter table if exists doesnt_exist_tab rename column a to d; +alter table if exists doesnt_exist_tab rename column b to a; + +-- this should work +alter table renameColumn add column w int; + +-- this should fail +alter table only renameColumn add column x int; + + +-- Test corner cases in dropping of inherited columns + +create table p1 (f1 int, f2 int); +create table c1 (f1 int not null) inherits(p1); + +-- should be rejected since c1.f1 is inherited +alter table c1 drop column f1; +-- should work +alter table p1 drop column f1; +-- c1.f1 is still there, but no longer inherited +select f1 from c1; +alter table c1 drop column f1; +select f1 from c1; + +drop table p1 cascade; + +create table p1 (f1 int, f2 int); +create table c1 () inherits(p1); + +-- should be rejected since c1.f1 is inherited +alter table c1 drop column f1; +alter table p1 drop column f1; +-- c1.f1 is dropped now, since there is no local definition for it +select f1 from c1; + +drop table p1 cascade; + +create table p1 (f1 int, f2 int); +create table c1 () inherits(p1); + +-- should be rejected since c1.f1 is inherited +alter table c1 drop column f1; +alter table only p1 drop column f1; +-- c1.f1 is NOT dropped, but must now be considered non-inherited +alter table c1 drop column f1; + +drop table p1 cascade; + +create table p1 (f1 int, f2 int); +create table c1 (f1 int not null) inherits(p1); + +-- should be rejected since c1.f1 is inherited +alter table c1 drop column f1; +alter table only p1 drop column f1; +-- c1.f1 is still there, but no longer inherited +alter table c1 drop column f1; + +drop table p1 cascade; + +create table p1(id int, name text); +create table p2(id2 int, name text, height int); +create table c1(age int) inherits(p1,p2); +create table gc1() inherits (c1); + +select relname, attname, attinhcount, attislocal +from pg_class join pg_attribute on (pg_class.oid = pg_attribute.attrelid) +where relname in ('p1','p2','c1','gc1') and attnum > 0 and not attisdropped +order by relname, attnum; + +-- should work +alter table only p1 drop column name; +-- should work. Now c1.name is local and inhcount is 0. +alter table p2 drop column name; +-- should be rejected since its inherited +alter table gc1 drop column name; +-- should work, and drop gc1.name along +alter table c1 drop column name; +-- should fail: column does not exist +alter table gc1 drop column name; +-- should work and drop the attribute in all tables +alter table p2 drop column height; + +select relname, attname, attinhcount, attislocal +from pg_class join pg_attribute on (pg_class.oid = pg_attribute.attrelid) +where relname in ('p1','p2','c1','gc1') and attnum > 0 and not attisdropped +order by relname, attnum; + +drop table p1, p2 cascade; + +-- +-- Test the ALTER TABLE SET WITH/WITHOUT OIDS command +-- +create table altstartwith (col integer) with oids; + +insert into altstartwith values (1); + +select oid > 0, * from altstartwith; + +alter table altstartwith set without oids; + +select oid > 0, * from altstartwith; -- fails +select * from altstartwith; + +alter table altstartwith set with oids; + +select oid > 0, * from altstartwith; + +drop table altstartwith; + +-- Check inheritance cases +create table altwithoid (col integer) with oids; + +-- Inherits parents oid column anyway +create table altinhoid () inherits (altwithoid) without oids; + +insert into altinhoid values (1); + +select oid > 0, * from altwithoid; +select oid > 0, * from altinhoid; + +alter table altwithoid set without oids; + +select oid > 0, * from altwithoid; -- fails +select oid > 0, * from altinhoid; -- fails +select * from altwithoid; +select * from altinhoid; + +alter table altwithoid set with oids; + +select oid > 0, * from altwithoid; +select oid > 0, * from altinhoid; + +drop table altwithoid cascade; + +create table altwithoid (col integer) without oids; + +-- child can have local oid column +create table altinhoid () inherits (altwithoid) with oids; + +insert into altinhoid values (1); + +select oid > 0, * from altwithoid; -- fails +select oid > 0, * from altinhoid; + +alter table altwithoid set with oids; + +select oid > 0, * from altwithoid; +select oid > 0, * from altinhoid; + +-- the child's local definition should remain +alter table altwithoid set without oids; + +select oid > 0, * from altwithoid; -- fails +select oid > 0, * from altinhoid; + +drop table altwithoid cascade; + +-- test renumbering of child-table columns in inherited operations + +create table p1 (f1 int); +create table c1 (f2 text, f3 int) inherits (p1); + +alter table p1 add column a1 int check (a1 > 0); +alter table p1 add column f2 text; + +insert into p1 values (1,2,'abc'); +insert into c1 values(11,'xyz',33,0); -- should fail +insert into c1 values(11,'xyz',33,22); + +select * from p1 order by f1; +update p1 set a1 = a1 + 1, f2 = upper(f2); +select * from p1 order by f1; + +drop table p1 cascade; + +-- test that operations with a dropped column do not try to reference +-- its datatype + +--create domain mytype as text; +--create table foo (f1 text, f2 mytype, f3 text);; + +insert into foo values('bb','cc','dd'); +select * from foo order by f1; + +--drop domain mytype cascade; + +--select * from foo order by f1; +--insert into foo values('qq','rr'); +--select * from foo order by f1; +--update foo set f3 = 'zz'; +--select * from foo order by f1; +--select f3,max(f1) from foo group by f3; + +-- Simple tests for alter table column type +--delete from foo where f1 = 'qq'; +--alter table foo alter f1 TYPE integer; -- fails +--alter table foo alter f1 TYPE varchar(10); +--drop table foo; + +create table anothertab (atcol1 serial8, atcol2 boolean, + constraint anothertab_chk check (atcol1 <= 3));; +alter table anothertab replica identity full; +insert into anothertab (atcol1, atcol2) values (1, true); +insert into anothertab (atcol1, atcol2) values (3, false); +select * from anothertab order by atcol1, atcol2; + +alter table anothertab alter column atcol1 type boolean; -- we cannot support this cast with numeric nextval +alter table anothertab alter column atcol1 type integer; + +select * from anothertab order by atcol1, atcol2; + +insert into anothertab (atcol1, atcol2) values (45, null); -- fails +--insert into anothertab (atcol1, atcol2) values (default, null); + +select * from anothertab order by atcol1, atcol2; + +alter table anothertab alter column atcol2 type text + using case when atcol2 is true then 'IT WAS TRUE' + when atcol2 is false then 'IT WAS FALSE' + else 'IT WAS NULL!' end; + +select * from anothertab order by atcol1, atcol2; +alter table anothertab alter column atcol1 type boolean + using case when atcol1 % 2 = 0 then true else false end; -- fails +alter table anothertab alter column atcol1 drop default; +alter table anothertab alter column atcol1 type boolean + using case when atcol1 % 2 = 0 then true else false end; -- fails +alter table anothertab drop constraint anothertab_chk; +alter table anothertab drop constraint anothertab_chk; -- fails +alter table anothertab drop constraint IF EXISTS anothertab_chk; -- succeeds + +alter table anothertab alter column atcol1 type boolean + using case when atcol1 % 2 = 0 then true else false end; + +select * from anothertab order by atcol1, atcol2; + +-- drop table anothertab; + +create table another (f1 int, f2 text);; +alter table another replica identity full; +insert into another values(1, 'one'); +insert into another values(2, 'two'); +insert into another values(3, 'three'); + +select * from another order by f1, f2; + +alter table another + alter f1 type text using f2 || ' more', + alter f2 type bigint using f1 * 10; + +select * from another order by f1, f2; + +-- drop table another; + +-- table's row type +create table tab1 (a int, b text); +create table tab2 (x int, y tab1); +alter table tab1 alter column b type varchar; -- fails + +-- disallow recursive containment of row types +create table recur1 (f1 int); +alter table recur1 add column f2 recur1; -- fails +alter table recur1 add column f2 recur1[]; -- fails +--create domain array_of_recur1 as recur1[]; +--alter table recur1 add column f2 array_of_recur1; -- fails +create table recur2 (f1 int, f2 recur1); +alter table recur1 add column f2 recur2; -- fails +alter table recur1 add column f2 int; +alter table recur1 alter column f2 type recur2; -- fails + +-- SET STORAGE may need to add a TOAST table +create table test_storage (a text); +alter table test_storage alter a set storage plain; +alter table test_storage add b int default 0; -- rewrite table to remove its TOAST table +alter table test_storage alter a set storage extended; -- re-add TOAST table + +select reltoastrelid <> 0 as has_toast_table +from pg_class +where oid = 'test_storage'::regclass; + +-- ALTER TYPE with a check constraint and a child table (bug before Nov 2012) +CREATE TABLE test_inh_check (a float check (a > 10.2)); +CREATE TABLE test_inh_check_child() INHERITS(test_inh_check); +ALTER TABLE test_inh_check ALTER COLUMN a TYPE numeric; +\d test_inh_check +\d test_inh_check_child + +-- +-- lock levels +-- +drop type lockmodes; +create type lockmodes as enum ( + 'AccessShareLock' +,'RowShareLock' +,'RowExclusiveLock' +,'ShareUpdateExclusiveLock' +,'ShareLock' +,'ShareRowExclusiveLock' +,'ExclusiveLock' +,'AccessExclusiveLock' +); + +drop view my_locks; +create view my_locks as +select case when c.relname like 'pg_toast%' then 'pg_toast' else c.relname end, max(mode::lockmodes) as max_lockmode +from pg_locks l join pg_class c on l.relation = c.oid +where virtualtransaction = ( + select virtualtransaction + from pg_locks + where transactionid = txid_current()::integer) +and locktype = 'relation' +and relnamespace != (select oid from pg_namespace where nspname = 'pg_catalog') +and c.relname != 'my_locks' +group by c.relname; + +create table alterlock (f1 int primary key, f2 text); + +start transaction; alter table alterlock alter column f2 set statistics 150; +select * from my_locks order by 1; +rollback; + +start transaction; alter table alterlock cluster on alterlock_pkey; +select * from my_locks order by 1; +commit; + +start transaction; alter table alterlock set without cluster; +select * from my_locks order by 1; +commit; + +start transaction; alter table alterlock set (fillfactor = 100); +select * from my_locks order by 1; +commit; + +start transaction; alter table alterlock reset (fillfactor); +select * from my_locks order by 1; +commit; + +start transaction; alter table alterlock set (toast.autovacuum_enabled = off); +select * from my_locks order by 1; +commit; + +start transaction; alter table alterlock set (autovacuum_enabled = off); +select * from my_locks order by 1; +commit; + +start transaction; alter table alterlock alter column f2 set (n_distinct = 1); +select * from my_locks order by 1; +rollback; + +start transaction; alter table alterlock alter column f2 set storage extended; +select * from my_locks order by 1; +rollback; + +start transaction; alter table alterlock alter column f2 set default 'x'; +select * from my_locks order by 1; +rollback; + +-- cleanup +drop table alterlock; +drop view my_locks; +drop type lockmodes; + +-- +-- alter function +-- +-- create function test_strict(text) returns text as +-- 'select coalesce($1, ''got passed a null'');' +-- language sql returns null on null input; +-- select test_strict(NULL); +-- alter function test_strict(text) called on null input; +-- select test_strict(NULL); + +-- create function non_strict(text) returns text as +-- 'select coalesce($1, ''got passed a null'');' +-- language sql called on null input; +-- select non_strict(NULL); +-- alter function non_strict(text) returns null on null input; +-- select non_strict(NULL); + +-- +-- alter object set schema +-- + +create schema alter1; +create schema alter2; + +create table alter1.t1(f1 serial primary key, f2 int check (f2 > 0)); + +create view alter1.v1 as select * from alter1.t1; + +create function alter1.plus1(int) returns int as 'select $1+1' language sql; + +--create domain alter1.posint integer check (value > 0); + +create type alter1.ctype as (f1 int, f2 text); + +create function alter1.same(alter1.ctype, alter1.ctype) returns boolean language sql +as 'select $1.f1 is not distinct from $2.f1 and $1.f2 is not distinct from $2.f2'; + +create operator alter1.=(procedure = alter1.same, leftarg = alter1.ctype, rightarg = alter1.ctype); + +create operator class alter1.ctype_hash_ops default for type alter1.ctype using hash as + operator 1 alter1.=(alter1.ctype, alter1.ctype); + +create conversion alter1.ascii_to_utf8 for 'sql_ascii' to 'utf8' from ascii_to_utf8; + +create text search parser alter1.prs(start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype); +create text search configuration alter1.cfg(parser = alter1.prs); +create text search template alter1.tmpl(init = dsimple_init, lexize = dsimple_lexize); +create text search dictionary alter1.dict(template = alter1.tmpl); + +insert into alter1.t1(f2) values(11); +insert into alter1.t1(f2) values(12); + +alter table alter1.t1 set schema alter2; +alter table alter1.v1 set schema alter2; +alter function alter1.plus1(int) set schema alter2; +--alter domain alter1.posint set schema alter2; +alter operator class alter1.ctype_hash_ops using hash set schema alter2; +alter operator family alter1.ctype_hash_ops using hash set schema alter2; +alter operator alter1.=(alter1.ctype, alter1.ctype) set schema alter2; +alter function alter1.same(alter1.ctype, alter1.ctype) set schema alter2; +alter type alter1.ctype set schema alter2; +alter conversion alter1.ascii_to_utf8 set schema alter2; +alter text search parser alter1.prs set schema alter2; +alter text search configuration alter1.cfg set schema alter2; +alter text search template alter1.tmpl set schema alter2; +alter text search dictionary alter1.dict set schema alter2; + +-- this should succeed because nothing is left in alter1 +drop schema alter1; + +insert into alter2.t1(f2) values(13); +insert into alter2.t1(f2) values(14); + +select * from alter2.t1 order by f1, f2; + +select * from alter2.v1 order by f1, f2; + +select alter2.plus1(41); + +-- clean up +drop schema alter2 cascade; +drop schema alter1 cascade; + +-- +-- composite types +-- + +CREATE TYPE test_type AS (a int); +\d test_type + +ALTER TYPE nosuchtype ADD ATTRIBUTE b text; -- fails + +ALTER TYPE test_type ADD ATTRIBUTE b text; +\d test_type + +ALTER TYPE test_type ADD ATTRIBUTE b text; -- fails + +ALTER TYPE test_type ALTER ATTRIBUTE b SET DATA TYPE varchar; +\d test_type + +ALTER TYPE test_type ALTER ATTRIBUTE b SET DATA TYPE integer; +\d test_type + +ALTER TYPE test_type DROP ATTRIBUTE b; +\d test_type + +ALTER TYPE test_type DROP ATTRIBUTE c; -- fails + +ALTER TYPE test_type DROP ATTRIBUTE IF EXISTS c; + +ALTER TYPE test_type DROP ATTRIBUTE a, ADD ATTRIBUTE d boolean; +\d test_type + +ALTER TYPE test_type RENAME ATTRIBUTE a TO aa; +ALTER TYPE test_type RENAME ATTRIBUTE d TO dd; +\d test_type + +DROP TYPE test_type; + +CREATE TYPE test_type1 AS (a int, b text); +CREATE TABLE test_tbl1 (x int, y test_type1); +ALTER TYPE test_type1 ALTER ATTRIBUTE b TYPE varchar; -- fails + +CREATE TYPE test_type2 AS (a int, b text); +CREATE TABLE test_tbl2 OF test_type2; +CREATE TABLE test_tbl2_subclass () INHERITS (test_tbl2); +\d test_type2 +\d test_tbl2 + +ALTER TYPE test_type2 ADD ATTRIBUTE c text; -- fails +ALTER TYPE test_type2 ADD ATTRIBUTE c text CASCADE; +\d test_type2 +\d test_tbl2 + +ALTER TYPE test_type2 ALTER ATTRIBUTE b TYPE varchar; -- fails +ALTER TYPE test_type2 ALTER ATTRIBUTE b TYPE varchar CASCADE; +\d test_type2 +\d test_tbl2 + +ALTER TYPE test_type2 DROP ATTRIBUTE b; -- fails +ALTER TYPE test_type2 DROP ATTRIBUTE b CASCADE; +\d test_type2 +\d test_tbl2 + +ALTER TYPE test_type2 RENAME ATTRIBUTE a TO aa; -- fails +ALTER TYPE test_type2 RENAME ATTRIBUTE a TO aa CASCADE; +\d test_type2 +\d test_tbl2 +\d test_tbl2_subclass + +DROP TABLE test_tbl2_subclass; +alter table test_tbl2 not of; +-- This test isn't that interesting on its own, but the purpose is to leave +-- behind a table to test pg_upgrade with. The table has a composite type +-- column in it, and the composite type has a dropped attribute. +CREATE TYPE test_type3 AS (a int); +CREATE TABLE test_tbl3 (c) AS SELECT '(1)'::test_type3; +ALTER TYPE test_type3 DROP ATTRIBUTE a, ADD ATTRIBUTE b int; + +CREATE TYPE test_type_empty AS (); + +-- +-- typed tables: OF / NOT OF +-- + +CREATE TYPE tt_t0 AS (z inet, x int, y numeric(8,2)); +ALTER TYPE tt_t0 DROP ATTRIBUTE z; +CREATE TABLE tt0 (x int NOT NULL, y numeric(8,2)); -- OK +CREATE TABLE tt1 (x int, y bigint); -- wrong base type +CREATE TABLE tt2 (x int, y numeric(9,2)); -- wrong typmod +CREATE TABLE tt3 (y numeric(8,2), x int); -- wrong column order +CREATE TABLE tt4 (x int); -- too few columns +CREATE TABLE tt5 (x int, y numeric(8,2), z int); -- too few columns +CREATE TABLE tt6 () INHERITS (tt0); -- can't have a parent +CREATE TABLE tt7 (x int, q text, y numeric(8,2)) WITH OIDS; +ALTER TABLE tt7 DROP q; -- OK + +ALTER TABLE tt0 OF tt_t0; +ALTER TABLE tt1 OF tt_t0; +ALTER TABLE tt2 OF tt_t0; +ALTER TABLE tt3 OF tt_t0; +ALTER TABLE tt4 OF tt_t0; +ALTER TABLE tt5 OF tt_t0; +ALTER TABLE tt6 OF tt_t0; +ALTER TABLE tt7 OF tt_t0; + +CREATE TYPE tt_t1 AS (x int, y numeric(8,2)); +ALTER TABLE tt7 OF tt_t1; -- reassign an already-typed table +ALTER TABLE tt7 NOT OF; +\d tt7 +alter table tt0 not of; +-- make sure we can drop a constraint on the parent but it remains on the child +CREATE TABLE test_drop_constr_parent (c text CHECK (c IS NOT NULL)); +CREATE TABLE test_drop_constr_child () INHERITS (test_drop_constr_parent); +ALTER TABLE ONLY test_drop_constr_parent DROP CONSTRAINT "test_drop_constr_parent_c_check"; +-- should fail +INSERT INTO test_drop_constr_child (c) VALUES (NULL); +DROP TABLE test_drop_constr_parent CASCADE; + +-- +-- IF EXISTS test +-- +ALTER TABLE IF EXISTS tt8 ADD COLUMN f int; +ALTER TABLE IF EXISTS tt8 ADD CONSTRAINT xxx PRIMARY KEY(f); +ALTER TABLE IF EXISTS tt8 ADD CHECK (f BETWEEN 0 AND 10); +ALTER TABLE IF EXISTS tt8 ALTER COLUMN f SET DEFAULT 0; +ALTER TABLE IF EXISTS tt8 RENAME COLUMN f TO f1; +ALTER TABLE IF EXISTS tt8 SET SCHEMA alter2; + +CREATE TABLE tt8(a int); +CREATE SCHEMA alter2; + +ALTER TABLE IF EXISTS tt8 ADD COLUMN f int; +ALTER TABLE IF EXISTS tt8 ADD CONSTRAINT xxx PRIMARY KEY(f); +ALTER TABLE IF EXISTS tt8 ADD CHECK (f BETWEEN 0 AND 10); +ALTER TABLE IF EXISTS tt8 ALTER COLUMN f SET DEFAULT 0; +ALTER TABLE IF EXISTS tt8 RENAME COLUMN f TO f1; +ALTER TABLE IF EXISTS tt8 SET SCHEMA alter2; + +\d alter2.tt8 + +DROP TABLE alter2.tt8; +DROP SCHEMA alter2; + +-- create database test_first_after_A dbcompatibility 'A'; +-- \c test_first_after_A + +-- test add column ... first | after columnname +-- common scenatios +drop table if exists t1 cascade; +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 add f6 clob first, add f7 blob after f2; +alter table t1 add f8 int, add f9 text first, add f10 float after f3; +\d+ t1 +select * from t1; + +-- 1 primary key +drop table if exists t1 cascade; +create table t1(f1 int primary key, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 add f6 blob first, add f7 clob after f2; +alter table t1 add f8 int, add f9 text first, add f10 float after f3; +select * from t1; +------------------------------------------------------------------------------------------- +drop table if exists t1 cascade; +create table t1(f1 int primary key, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +alter table t1 drop f1, add f6 text, add f7 int primary key first, add f8 float after f3; +\d+ t1; + +-- 2 unique index +drop table if exists t1 cascade; +create table t1(f1 int unique, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 drop f1, add f6 int unique first, add f7 float unique after f3; +select * from t1; + +-- 3 default and generated column +drop table if exists t1 cascade; +create table t1(f1 int default 1, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 drop f1, add f6 int default 1 first, add f7 float default 7 after f3; +select * from t1; + +drop table if exists t1 cascade; +create table t1(f1 int, f2 int default 2, f3 int default 3, f4 int generated always as (f1 + f2) stored); +insert into t1 values(1, 2, 3), (11, 22, 33); +alter table t1 add f5 int generated always as (f2 + f3) stored first, add f6 int generated always as (f1 + f3) stored after f5; +select * from t1; + +-- 5 NULL and NOT NULL +drop table if exists t1 cascade; +create table t1(f1 int null, f2 varchar(20) not null, f3 timestamp, f4 varbit(8), f5 bool); +alter table t1 drop f1, drop f2, add f6 int null first, add f7 float not null after f3; +\d+ t1 + +-- 6 check constraint +drop table if exists t1 cascade; +create table t1(f1 int check(f1 = 1), f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (1, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 drop f2, add f6 text check (f1 > 0) first, add f7 int check(f7 - f1 > 0) after f3; +select * from t1; + +-- 7 foreign key +drop table if exists t1 cascade; +drop table if exists t_pri1 cascade; +drop table if exists t_pri2 cascade; +create table t_pri1(f1 text, f2 int primary key); +insert into t_pri1 values('a', 1), ('b', 2); +create table t_pri2(f1 text, f2 bool, f4 int primary key); +insert into t_pri2 values('a', true, 1), ('b', false, 2); +create table t1(f1 int, f2 int references t_pri1(f2), f3 bool); +insert into t1 values(1, 2, true), (2, 2, false); +alter table t1 drop f2, add f4 int references t_pri2(f4) first; +select * from t1; +alter table t1 drop f4, add f4 int references t_pri2(f4) after f1; +select * from t1; + +-- partition table +drop table if exists t1 cascade; +create table t1 +(f1 int, f2 int, f3 int) +partition by range(f1, f2) +( + partition t1_p0 values less than (10, 0), + partition t1_p1 values less than (20, 0), + partition t1_p2 values less than (30, 0) +); +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='t1') order by relname; + +alter table t1 add f4 int first, add f5 int after f1; +\d+ t1 +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='t1') order by relname; + +-- subpartition table +drop table if exists range_range cascade; +create table range_range(id int, gender varchar not null, birthday date not null) +partition by range (id) subpartition by range (birthday) +( + partition p_1 values less than(100) + ( + subpartition p_1_a values less than('2022-01-01'), + subpartition p_1_b values less than(MAXVALUE) + ), + partition p_2 values less than(200) + ( + subpartition p_2_a values less than('2022-01-01'), + subpartition p_2_b values less than(MAXVALUE) + ), + partition p_3 values less than(MAXVALUE) + ( + subpartition p_3_a values less than('2022-01-01'), + subpartition p_3_b values less than(MAXVALUE) + ) +); +insert into range_range values(198,'boy','2010-02-15'),(33,'boy','2003-08-11'),(78,'girl','2014-06-24'); +insert into range_range values(233,'girl','2010-01-01'),(360,'boy','2007-05-14'),(146,'girl','2005-03-08'); +insert into range_range values(111,'girl','2013-11-19'),(15,'girl','2009-01-12'),(156,'boy','2011-05-21'); + +-- test pg_partition +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='range_range') order by relname; +alter table range_range add f1 int default 1 first, add f2 text after id; +\d+ range_range +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='range_range') order by relname; +select * from range_range; + +-- pg_index test +drop table if exists t1 cascade; +create table t1 +( + f1 int, f2 int, f3 varchar(20), f4 int, f5 int, f6 int, f7 int, + primary key(f1, f2), + unique(f3, f4), + check(f5 = 10) +); +create unique index partial_t1_idx on t1(f5, abs(f6)) where f5 + f6 - abs(f7) > 0; + +select indkey, indexprs, indpred from pg_index where indrelid = (select oid from pg_class where relname = 't1') order by 1, 2, 3; + +alter table t1 add f8 int first, add f9 int unique after f1; +\d+ t1 +select indkey, indexprs, indpred from pg_index where indrelid = (select oid from pg_class where relname = 't1') order by 1, 2, 3; + +-- pg_attribute test +drop table if exists t1 cascade; +create table t1(f1 int, f2 int, f3 int); +select attname, attnum, atthasdef, attisdropped from pg_attribute where attrelid = (select oid from pg_class where relname = 't1') and attnum > 0 order by attnum; + +alter table t1 add f4 int default 4 first; +\d+ t1 +select attname, attnum, atthasdef, attisdropped from pg_attribute where attrelid = (select oid from pg_class where relname = 't1') and attnum > 0 order by attnum; + +alter table t1 drop f2, add f5 int default 5 after f1; +\d+ t1 +select attname, attnum, atthasdef, attisdropped from pg_attribute where attrelid = (select oid from pg_class where relname = 't1') and attnum > 0 order by attnum; + +-- pg_attrdef test +drop table if exists t1 cascade; +create table t1(f1 int primary key, f2 int, f3 int default 3, f4 int generated always as (f2 + f3) stored); +select adnum, adsrc, adgencol from pg_attrdef where adrelid = (select oid from pg_class where relname = 't1') order by adnum; + +alter table t1 add f5 text default 'aaa' first; +\d+ t1 +select adnum, adsrc, adgencol from pg_attrdef where adrelid = (select oid from pg_class where relname = 't1') order by adnum; + +alter table t1 drop f2, add f6 int generated always as (f1 + abs(f3)) stored after f1; +\d+ t1 +select adnum, adsrc, adgencol from pg_attrdef where adrelid = (select oid from pg_class where relname = 't1') order by adnum; + +-- pg_depend test +drop table if exists t1 cascade; +create table t1(f1 int default 10, f2 int primary key, f3 int generated always as (f1 + f2) stored); +select classid, objsubid, refclassid, refobjsubid, deptype from pg_depend + where refobjid = (select oid from pg_class where relname='t1') or objid = (select oid from pg_class where relname='t1') order by 1, 2, 3, 4, 5; + +alter table t1 add t1 add f4 int first; +\d+ t1 +select classid, objsubid, refclassid, refobjsubid, deptype from pg_depend + where refobjid = (select oid from pg_class where relname='t1') or objid = (select oid from pg_class where relname='t1') order by 1, 2, 3, 4, 5; +alter table t1 drop f2, add f6 int, add f7 int generated always as (f1 + f6) stored after f1; +\d+ t1 +select classid, objsubid, refclassid, refobjsubid, deptype from pg_depend + where refobjid = (select oid from pg_class where relname='t1') or objid = (select oid from pg_class where relname='t1') order by 1, 2, 3, 4, 5; + +-- pg_rewrite test +drop table if exists t1 cascade; +create table t1(f1 int, f2 int, f3 int); +insert into t1 values(1, 2, 3), (11, 22, 33); +create view t1_view1 as select * from t1; +create view t1_view2 as select f1, f2 from t1; +\d+ t1_view1 +\d+ t1_view2 +\d+ t1 +select pg_get_viewdef('t1_view1'); +select pg_get_viewdef('t1_view2'); +select * from t1_view1; +select * from t1_view2; +select * from t1; +alter table t1 add f4 int first, add f5 int after f1; +\d+ t1_view1 +\d+ t1_view2 +\d+ t1 +select pg_get_viewdef('t1_view1'); +select pg_get_viewdef('t1_view2'); +select * from t1_view1; +select * from t1_view2; +select * from t1; + +-- pg_trigger test +drop table if exists t1 cascade; +create table t1(f1 boolean not null, f2 text, f3 int, f4 date); +alter table t1 add primary key(f1); +drop function if exists dummy_update_func; +create function dummy_update_func() returns trigger as $$ +begin + raise notice 'dummy_update_func(%) called: action = %, oid = %, new = %', TG_ARGV[0], TG_OP, OLD, NEW; + return new; +end; +$$ language plpgsql; + +drop trigger if exists f1_trig_update on t1; +drop trigger if exists f1_trig_insert on t1; + +create trigger f1_trig_update after update of f1 on t1 for each row + when (not old.f1 and new.f1) execute procedure dummy_update_func('update'); +create trigger f1_trig_insert after insert on t1 for each row + when (not new.f1) execute procedure dummy_update_func('insert'); + +select tgname, tgattr, tgqual from pg_trigger where tgrelid = (select oid from pg_class where relname='t1') order by tgname; + +alter table t1 add f5 int after f1, add f6 boolean first; +\d+ t1 +select tgname, tgattr, tgqual from pg_trigger where tgrelid = (select oid from pg_class where relname='t1') order by tgname; + +-- pg_rlspolicy test +drop table if exists t1 cascade; +drop role if exists test_rlspolicy; +create role test_rlspolicy nologin password 'Gauss_234'; +create table t1 (f1 int, f2 int, f3 text) partition by range (f1) +( + partition t1_p0 values less than(10), + partition t1_p1 values less than(50), + partition t1_p2 values less than(100), + partition t1_p3 values less than(MAXVALUE) +); + +INSERT INTO t1 VALUES (generate_series(1, 150) % 24, generate_series(1, 150), 'huawei'); +grant select on t1 to public; + +create row level security policy t1_rls1 on t1 as permissive to public using (f2 <= 20); +create row level security policy t1_rls2 on t1 as restrictive to test_rlspolicy using (f1 < 30); + +\d+ t1 +select * from t1 limit 10; +select polname, polqual from pg_rlspolicy where polrelid = (select oid from pg_class where relname='t1'); + +alter table t1 add f4 int generated always as (f1 + 100) stored after f1, add f5 int generated always as (f2 + 100) stored first; +\d+ t1 +select * from t1 limit 10; +select polname, polqual from pg_rlspolicy where polrelid = (select oid from pg_class where relname='t1'); +drop table if exists t1 cascade; + +-- \c postgres +-- drop database test_first_after_A; + +-- test add column ... first | after columnname in B compatibility +-- create database test_first_after_B dbcompatibility 'b'; +-- \c test_first_after_B + +-- test add column ... first | after columnname in astore table +-- ASTORE table +-- common scenatios +drop table if exists t1 cascade; +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 add f6 clob first, add f7 blob after f2; +alter table t1 add f8 int, add f9 text first, add f10 float after f3; +\d+ t1 +select * from t1; + +-- 1 primary key +-- 1.1.1 primary key in original table without data, add column without constraints +drop table if exists t1 cascade; +create table t1(f1 int primary key, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +alter table t1 add f6 clob first, add f7 blob after f2; +alter table t1 add f8 int, add f9 text first, add f10 float after f3; +\d+ t1 + +-- 1.1.2 primary key in original table with data, add column without constraints +drop table if exists t1 cascade; +create table t1(f1 int primary key, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 add f6 blob first, add f7 clob after f2; +alter table t1 add f8 int, add f9 text first, add f10 float after f3; +select * from t1; + +-- 1.2.1 primary key in a table without data, add column with primary key +drop table if exists t1 cascade; +create table t1(f1 int primary key, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +-- error +alter table t1 add f6 text, add f7 int primary key first, add f8 float after f3; +select * from t1; + +-- 1.2.2 primary key in a table with data, add column with primary key +drop table if exists t1 cascade; +create table t1(f1 int primary key, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +-- error +alter table t1 add f6 text, add f7 int primary key first, add f8 float after f3; +select * from t1; + +-- 1.3.1 primary key in a table without data, drop primary key, then add column with primary key +drop table if exists t1 cascade; +create table t1(f1 int primary key, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +alter table t1 drop f1, add f6 text, add f7 int primary key first, add f8 float after f3; +\d+ t1; + +-- 1.3.2 primary key in a table with data, drop primary key, then add column with primary key +drop table if exists t1 cascade; +create table t1(f1 int primary key, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 drop f1; +-- error +alter table t1 add f6 text, add f7 int primary key first, add f8 float after f3; +select * from t1; + +-- 1.4.1 primary key in a table without data, drop primary key, the add column with primary key and default +drop table if exists t1 cascade; +create table t1(f1 int primary key, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +alter table t1 drop f1, add f6 text, add f7 int primary key default 7 first, add f8 float after f3; +\d+ t1 + +-- 1.4.2 primary key in a table with data, drop primary key, then add column with primary key and default +drop table if exists t1 cascade; +create table t1(f1 int primary key, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 drop f1; +-- error +alter table t1 add f6 text, add f7 int primary key default 7 first, add f8 float after f3; +select * from t1; + +-- 1.5.1 primary key in a table without data, drop primary key, the add column with primary key and auto_increment +drop table if exists t1 cascade; +create table t1(f1 int primary key, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +alter table t1 drop f1, add f6 text, add f7 int primary key auto_increment first, add f8 float after f3; +\d+ t1 + +-- 1.5.2 primary key in a table with data, drop primary key, the add column with primary key and auto_increment +drop table if exists t1 cascade; +create table t1(f1 int primary key, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 drop f1, add f6 text, add f7 int primary key auto_increment first, add f8 float after f3; +select * from t1; + +-- 2 unique index +-- 2.1.1 unique index in a table without data, add column without constraints +drop table if exists t1 cascade; +create table t1(f1 int unique, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +alter table t1 add f6 int first, add f7 float after f3; +\d+ t1 + +-- 2.1.2 unique index in a table with data, add column without constraints +drop table if exists t1 cascade; +create table t1(f1 int unique, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 add f6 int first, add f7 float after f3; +select * from t1; + +-- 2.2.1 unique index in a table without data, add column with unique index +drop table if exists t1 cascade; +create table t1(f1 int unique, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +alter table t1 add f6 int unique first, add f7 float unique after f3; +\d+ t1 + +-- 2.2.2 unique index in a table with data, add column with unique index +drop table if exists t1 cascade; +create table t1(f1 int unique, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 add f6 int unique first, add f7 float unique after f3; +select * from t1; + +-- 2.3.1 unique index in a table without data, drop unique index, add column with unique index +drop table if exists t1 cascade; +create table t1(f1 int unique, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +alter table t1 drop f1, add f6 int unique first, add f7 float unique after f3; +\d+ t1 + +-- 2.3.2 unique index in a table with data, drop unique index, add column with unique index +drop table if exists t1 cascade; +create table t1(f1 int unique, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 drop f1, add f6 int unique first, add f7 float unique after f3; +select * from t1; + +-- 2.4.1 unique index in a table without data, drop unique index, add column with unique index and default +drop table if exists t1 cascade; +create table t1(f1 int unique, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +alter table t1 add f6 int unique default 6 first; +alter table t1 drop f1, add f7 float unique default 7 after f3; +\d+ t1 + +-- 2.4.2 unique index in a table with data, drop unique index, add column with unique index and default +drop table if exists t1 cascade; +create table t1(f1 int unique, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +-- error +alter table t1 add f6 int unique default 6 first; +alter table t1 drop f1; +-- error +alter table t1 add f7 float unique default 7 after f3; +select * from t1; + +-- 3 default and generated column +-- 3.1.1 default in a table without data, add column without constraints +drop table if exists t1 cascade; +create table t1(f1 int default 1, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +alter table t1 add f6 int first, add f7 float after f3; +\d+ t1 + +-- 3.1.2 default in a table with data, add column without constraints +drop table if exists t1 cascade; +create table t1(f1 int default 1, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 add f6 int first, add f7 float after f3; +select * from t1; + +-- 3.2.1 default in a table without data, add column with default +drop table if exists t1 cascade; +create table t1(f1 int default 1, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +alter table t1 add f6 int default 6 first, add f7 float default 7 after f3; +\d+ t1 + +-- 3.2.2 default in a table with data, add column with default +drop table if exists t1 cascade; +create table t1(f1 int default 1, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 add f6 int default 6 first, add f7 float default 7 after f3; +select * from t1; + +-- 3.3.1 default in a table without data, drop default, add column with default +drop table if exists t1 cascade; +create table t1(f1 int default 1, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +alter table t1 drop f1, add f6 int default 6 first, add f7 float default 7 after f3; +\d+ t1 + +-- 3.3.2 default in a table with data, drop default, add column with default +drop table if exists t1 cascade; +create table t1(f1 int default 1, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 drop f1, add f6 int default 1 first, add f7 float default 7 after f3; +select * from t1; + +-- 3.4.1 generated column in a table without data, drop generated column +drop table if exists t1 cascade; +create table t1(f1 int, f2 int default 2, f3 int default 3, f4 int generated always as (f1 + f2) stored); +alter table t1 drop f1, add f5 int generated always as (f2 + f3) stored first, add f6 int generated always as (f3*10) stored after f5; +\d+ t1 + +-- 3.4.1 generated column in a table with data, drop generated column +drop table if exists t1 cascade; +create table t1(f1 int, f2 int default 2, f3 int default 3, f4 int generated always as (f1 + f2) stored); +insert into t1 values(1, 2, 3), (11, 22, 33); +alter table t1 drop f1, add f5 int generated always as (f2 + f3) stored first, add f6 int generated always as (f3*10) stored after f5; +select * from t1; + +-- 3.5.1 generated column in a table without data, add generated column +drop table if exists t1 cascade; +create table t1(f1 int, f2 int default 2, f3 int default 3, f4 int generated always as (f1 + f2) stored); +alter table t1 add f5 int generated always as (f2 + f3) stored first, add f6 int generated always as (f2 + f3) stored after f5; +\d+ t1; + +-- 3.5.2 generated column in table with data, add generated column +drop table if exists t1 cascade; +create table t1(f1 int, f2 int default 2, f3 int default 3, f4 int generated always as (f1 + f2) stored); +insert into t1 values(1, 2, 3), (11, 22, 33); +alter table t1 add f5 int generated always as (f2 + f3) stored first, add f6 int generated always as (f1 + f3) stored after f5; +select * from t1; + +-- 4 auto_increment +-- 4.1.1 auto_increment in a table without data, add column without constraints +drop table if exists t1 cascade; +create table t1(f1 int primary key auto_increment, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +alter table t1 add f6 text first, add f7 float after f3; +\d+ t1 + +-- 4.1.2 auto_increment in a table with data, add column without constraints +drop table if exists t1 cascade; +create table t1(f1 int primary key auto_increment, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 add f6 text first, add f7 float after f3; +select * from t1; + +-- 4.2.1 auto_increment in a table without data, add column with auto_increment +drop table if exists t1 cascade; +create table t1(f1 int primary key auto_increment, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +-- error +alter table t1 add f6 int primary key auto_increment first; +-- error +alter table t1 add f7 int primary key auto_increment after f3; +\d+ t1 + +-- 4.2.2 auto_increment in a table with data, add column with auto_increment +drop table if exists t1 cascade; +create table t1(f1 int primary key auto_increment, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +-- error +alter table t1 add f6 int primary key auto_increment first; +-- error +alter table t1 add f7 int primary key auto_increment after f3; +select * from t1; + +-- 4.3.1 auto_increment in a table without data, drop auto_increment, add column with auto_increment +drop table if exists t1 cascade; +create table t1(f1 int primary key auto_increment, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +alter table t1 drop f1, add f6 int primary key auto_increment first; +\d+ t1 + +-- 4.3.2 auto_increment in a table with data, drop auto_increment, add column with auto_increment +drop table if exists t1 cascade; +create table t1(f1 int primary key auto_increment, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 drop f1, add f6 int primary key auto_increment first; + +-- 4.4.1 auto_increment in a table without data, drop auto_increment, add column with auto_increment and default +drop table if exists t1 cascade; +create table t1(f1 int primary key auto_increment, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +alter table t1 drop f1; +-- error +alter table t1 add f6 int primary key auto_increment default 6 first; +\d+ t1 + +-- 4.4.2 auto_increment in a table with data, drop auto_increment, add column with auto_increment and default +drop table if exists t1 cascade; +create table t1(f1 int primary key auto_increment, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 drop f1; +-- error +alter table t1 add f6 int primary key auto_increment default 6 first; +select * from t1; + +-- 5 NULL and NOT NULL +-- 5.1.1 null and not null in a table without data, add column without constraints +drop table if exists t1 cascade; +alter table t1(f1 int null, f2 varchar(20) not null, f3 timestamp, f4 varbit(8), f5 bool); +alter table t1 add f6 text first, add f7 float after f3; +\d+ t1 + +-- 5.1.2 null and not null in a table with data, add column without constraints +drop table if exists t1 cascade; +alter table t1(f1 int null, f2 varchar(20) not null, f3 timestamp, f4 varbit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 add f6 text first, add f7 float after f3; +select * from t1; + +-- 5.2.1 null and not null in table without data, add column with null or not null +drop table if exists t1 cascade; +alter table t1(f1 int null, f2 varchar(20) not null, f3 timestamp, f4 varbit(8), f5 bool); +alter table t1 add f6 int null first; +alter table t1 add f7 float not null after f3; +\d+ t1 + +-- 5.2.2 null and not null in a table with data, add column with null or not null +drop table if exists t1 cascade; +create table t1(f1 int null, f2 varchar(20) not null, f3 timestamp, f4 varbit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 add f6 int null first; +-- error +alter table t1 add f7 float not null after f3; +select * from t1; + +-- 5.3.1 null and not null in a table without data, drop null, add column with null or not null +drop table if exists t1 cascade; +create table t1(f1 int null, f2 varchar(20) not null, f3 timestamp, f4 varbit(8), f5 bool); +alter table t1 drop f1, add f6 int null first, add f7 float not null after f3; +\d+ t1 + +-- 5.3.2 null and not null in a table with data, drop null, add column with null or not null +drop table if exists t1 cascade; +create table t1(f1 int null, f2 varchar(20) not null, f3 timestamp, f4 varbit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 drop f1, add f6 int null first; +-- error +alter table t1 add f7 float not null after f3; +select * from t1; + +-- 5.4.1 null and not null in a table without data, drop null and not null, add column with null or not null +drop table if exists t1 cascade; +create table t1(f1 int null, f2 varchar(20) not null, f3 timestamp, f4 varbit(8), f5 bool); +alter table t1 drop f1, drop f2, add f6 int null first, add f7 float not null after f3; +\d+ t1 + +-- 5.4.2 null and not null in a table without data, drop null and not null, add column with null or not null +drop table if exists t1 cascade; +create table t1(f1 int null, f2 varchar(20) not null, f3 timestamp, f4 varbit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 drop f1, drop f2, add f6 int null first; +-- error +alter table t1 add f7 float not null after f3; +select * from t1; + +-- 6 check constraint +-- 6.1.1 check constraint in a table without data, add column without constraint +drop table if exists t1 cascade; +create table t1(f1 int check(f1 = 1), f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +alter table t1 add f6 text first, add f7 float after f3; +\d+ t1 + +-- 6.1.2 check constraint in a table with data, add column without constraint +drop table if exists t1 cascade; +create table t1(f1 int check(f1 = 1), f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 add f6 text first, add f7 float after f3; +select * from t1; + +-- 6.2.1 check constraint in a table without data, add column with check +drop table if exists t1 cascade; +create table t1(f1 int check(f1 = 1), f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +alter table t1 add f6 int default 6, add f7 text check(f6 = 6) first, add f8 float check(f1 + f2 == 7); +\d+ t1 + +-- 6.2.2 check constraint in a table with data, add column with check +drop table if exists t1 cascade; +create table t1(f1 int check(f1 = 1), f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (1, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 add f6 int default 6, add f7 text check(f6 = 6) first, add f8 float check(f1 + f2 == 7) after f3; +select * from t1; + +-- 6.3.1 check constraint in a table without data, drop check, add column with check +drop table if exists t1 cascade; +create table t1(f1 int check(f1 = 1), f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +alter table t1 drop f2, add f6 text check (f1 > 0) first, add f7 int check (f7 - f1 > 0) after f3; +\d+ t1 + +-- 6.3.2 check constraint in a table with data, drop check, add column with with check +drop table if exists t1 cascade; +create table t1(f1 int check(f1 = 1), f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (1, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 drop f2, add f6 text check (f1 > 0) first, add f7 int check(f7 - f1 > 0) after f3; +select * from t1; + +-- 7 foreign key +-- 7.1.1 foreign key constraint in a table without data, add column without constraint +drop table if exists t_pri1 cascade; +create table t_pri1(f1 int, f2 int primary key); +drop table if exists t1 cascade; +create table t1(f1 int, f2 int references t_pri1(f2), f3 bool); +alter table t1 add f4 int, add f5 text first, f6 float after f2; +\d+ t1 + +-- 7.1.2 foreign key constraint in a table with data, add column without constraint +drop table if exists t1 cascade; +drop table if exists t_pri1 cascade; +create table t_pri1(f1 text, f2 int primary key); +insert into t_pri1 values('a', 1), ('b', 2); +create table t1(f1 text, f2 int references t_pri1(f2), f3 bool); +insert into t1 values('a', 1, true), ('b', 2, false); +alter table t1 add f4 int, add f5 text first, f6 float after f2; +select * from t1; + +-- 7.2.1 foreign key constraint in a table without data, add column with foreign key +drop table if exists t1 cascade; +drop table if exists t_pri1 cascade; +drop table if exists t_pri2 cascade; +create table t_pri1(f1 text, f2 int primary key); +create table t_pri2(f1 int, f2 int, f4 int primary key); +create table t1(f1 int, f2 int references t_pri1(f2), f3 bool); +alter table t1 add f4 int references t_pri2(f4) first; +\d+ t1 +alter table t1 drop f4, add f4 int references t_pri2(f4) after f2; +\d+ t1 + +-- 7.2.2 foreign key constraint in a table with data, add column with foreign key +drop table if exists t1 cascade; +drop table if exists t_pri1 cascade; +drop table if exists t_pri2 cascade; +create table t_pri1(f1 text, f2 int primary key); +insert into t_pri1 values('a', 1), ('b', 2); +create table t_pri2(f1 int, f2 bool, f4 int primary key); +insert into t_pri2 values(11, true, 1), (22, false, 2); +create table t1(f1 int, f2 int references t_pri1(f2), f3 bool); +insert into t1 values(1, 1, true), (2, 2, false); +alter table t1 add f4 int references t_pri2(f4) first; +select * from t1; +alter table t1 drop f4, add f4 int references t_pri2(f4) after f2; +select * from t1; + +-- 7.3.1 foreign key constraint in a table without data, drop foreign key, add column with foreign key +drop table if exists t1 cascade; +drop table if exists t_pri1 cascade; +drop table if exists t_pri2 cascade; +create table t_pri1(f1 int, f2 int primary key); +create table t_pri2(f1 int, f2 int, f4 int primary key); +create table t1(f1 int, f2 int references t_pri1(f2), f3 bool); +alter table t1 drop f2, add f4 int references t_pri2(f4) first; +\d+ t1 +alter table t1 drop f4, add f4 int references t_pri2(f4) after f1; +\d+ t1 + +-- 7.3.2 foreign key constraint in a table with data, drop foreign key, add column with foreign key +drop table if exists t1 cascade; +drop table if exists t_pri1 cascade; +drop table if exists t_pri2 cascade; +create table t_pri1(f1 text, f2 int primary key); +insert into t_pri1 values('a', 1), ('b', 2); +create table t_pri2(f1 text, f2 bool, f4 int primary key); +insert into t_pri2 values('a', true, 1), ('b', false, 2); +create table t1(f1 int, f2 int references t_pri1(f2), f3 bool); +insert into t1 values(1, 2, true), (2, 2, false); +alter table t1 drop f2, add f4 int references t_pri2(f4) first; +select * from t1; +alter table t1 drop f4, add f4 int references t_pri2(f4) after f1; +select * from t1; + +-- partition table +drop table if exists t1 cascade; +create table t1 +(f1 int, f2 int, f3 int) +partition by range(f1, f2) +( + partition t1_p0 values less than (10, 0), + partition t1_p1 values less than (20, 0), + partition t1_p2 values less than (30, 0) +); +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='t1') order by relname; + +alter table t1 add f4 int first, add f5 int after f1; +\d+ t1 +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='t1') order by relname; + +-- subpartition table +drop table if exists range_range cascade; +create table range_range(id int, gender varchar not null, birthday date not null) +partition by range (id) subpartition by range (birthday) +( + partition p_1 values less than(100) + ( + subpartition p_1_a values less than('2022-01-01'), + subpartition p_1_b values less than(MAXVALUE) + ), + partition p_2 values less than(200) + ( + subpartition p_2_a values less than('2022-01-01'), + subpartition p_2_b values less than(MAXVALUE) + ), + partition p_3 values less than(MAXVALUE) + ( + subpartition p_3_a values less than('2022-01-01'), + subpartition p_3_b values less than(MAXVALUE) + ) +); +insert into range_range values(198,'boy','2010-02-15'),(33,'boy','2003-08-11'),(78,'girl','2014-06-24'); +insert into range_range values(233,'girl','2010-01-01'),(360,'boy','2007-05-14'),(146,'girl','2005-03-08'); +insert into range_range values(111,'girl','2013-11-19'),(15,'girl','2009-01-12'),(156,'boy','2011-05-21'); + +-- test pg_partition +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='range_range') order by relname; +alter table range_range add f1 int default 1 first, add f2 text after id; +\d+ range_range +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='range_range') order by relname; +select * from range_range; + + +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool) with (orientation = column); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +-- error +alter table t1 add f6 text first; +-- error +alter table t1 add f6 text after f1; + +-- pg_index test +drop table if exists t1 cascade; +create table t1 +( + f1 int, f2 int, f3 varchar(20), f4 int, f5 int, f6 int, f7 int, + primary key(f1, f2), + unique((lower(f3)), (abs(f4))), + check(f5 = 10) +); +create unique index partial_t1_idx on t1(f5, abs(f6)) where f5 + f6 - abs(f7) > 0; + +select indkey, indexprs, indpred from pg_index where indrelid = (select oid from pg_class where relname = 't1') order by 1, 2, 3; + +alter table t1 add f8 int first, add f9 int unique after f1; +\d+ t1 +select indkey, indexprs, indpred from pg_index where indrelid = (select oid from pg_class where relname = 't1') order by 1, 2, 3; + +-- pg_attribute test +drop table if exists t1 cascade; +create table t1(f1 int, f2 int, f3 int); +select attname, attnum, atthasdef, attisdropped from pg_attribute where attrelid = (select oid from pg_class where relname = 't1') and attnum > 0 order by attnum; + +alter table t1 add f4 int default 4 first; +\d+ t1 +select attname, attnum, atthasdef, attisdropped from pg_attribute where attrelid = (select oid from pg_class where relname = 't1') and attnum > 0 order by attnum; + +alter table t1 drop f2, add f5 int default 5 after f1; +\d+ t1 +select attname, attnum, atthasdef, attisdropped from pg_attribute where attrelid = (select oid from pg_class where relname = 't1') and attnum > 0 order by attnum; + +-- pg_attrdef test +drop table if exists t1 cascade; +create table t1(f1 int primary key auto_increment, f2 int, f3 int default 3, f4 int generated always as (f2 + f3) stored); +select adnum, adsrc, adgencol from pg_attrdef where adrelid = (select oid from pg_class where relname = 't1') order by adnum; + +alter table t1 add f5 text default 'aaa' first; +\d+ t1 +select adnum, adsrc, adgencol from pg_attrdef where adrelid = (select oid from pg_class where relname = 't1') order by adnum; + +alter table t1 drop f2, add f6 int generated always as (f1 + abs(f3)) stored after f1; -- ERROR + +-- pg_rewrite test +drop table if exists t1 cascade; +create table t1(f1 int, f2 int, f3 int); +insert into t1 values(1, 2, 3), (11, 22, 33); +create view t1_view1 as select * from t1; +create view t1_view2 as select f1, f2 from t1; +\d+ t1_view1 +\d+ t1_view2 +\d+ t1 +select pg_get_viewdef('t1_view1'); +select pg_get_viewdef('t1_view2'); +select * from t1_view1; +select * from t1_view2; +select * from t1; +alter table t1 add f4 int first, add f5 int after f1; +\d+ t1_view1 +\d+ t1_view2 +\d+ t1 +select pg_get_viewdef('t1_view1'); +select pg_get_viewdef('t1_view2'); +select * from t1_view1; +select * from t1_view2; +select * from t1; + +-- pg_trigger test +drop table if exists t1 cascade; +create table t1(f1 boolean not null, f2 text, f3 int, f4 date); +alter table t1 add primary key(f1); +drop function if exists dummy_update_func; +create function dummy_update_func() returns trigger as $$ +begin + raise notice 'dummy_update_func(%) called: action = %, oid = %, new = %', TG_ARGV[0], TG_OP, OLD, NEW; + return new; +end; +$$ language plpgsql; + +drop trigger if exists f1_trig_update on t1; +drop trigger if exists f1_trig_insert on t1; + +create trigger f1_trig_update after update of f1 on t1 for each row + when (not old.f1 and new.f1) execute procedure dummy_update_func('update'); +create trigger f1_trig_insert after insert on t1 for each row + when (not new.f1) execute procedure dummy_update_func('insert'); + +select tgname, tgattr, tgqual from pg_trigger where tgrelid = (select oid from pg_class where relname='t1') order by tgname; + +alter table t1 add f5 int after f1, add f6 boolean first; +\d+ t1 +select tgname, tgattr, tgqual from pg_trigger where tgrelid = (select oid from pg_class where relname='t1') order by tgname; + +-- pg_rlspolicy test +drop table if exists t1 cascade; +drop role if exists test_rlspolicy2; +create role test_rlspolicy2 nologin password 'Gauss_234'; +create table t1 (f1 int, f2 int, f3 text) partition by range (f1) +( + partition t1_p0 values less than(10), + partition t1_p1 values less than(50), + partition t1_p2 values less than(100), + partition t1_p3 values less than(MAXVALUE) +); + +INSERT INTO t1 VALUES (generate_series(1, 150) % 24, generate_series(1, 150), 'huawei'); +grant select on t1 to public; + +create row level security policy t1_rls1 on t1 as permissive to public using (f2 <= 20); +create row level security policy t1_rls2 on t1 as restrictive to test_rlspolicy2 using (f1 < 30); + +\d+ t1 +select * from t1 limit 10; +select polname, polqual from pg_rlspolicy where polrelid = (select oid from pg_class where relname='t1'); + +alter table t1 add f4 int generated always as (f1 + 100) stored after f1, add f5 int generated always as (f2 + 100) stored first; +\d+ t1 +select * from t1 limit 10; +select polname, polqual from pg_rlspolicy where polrelid = (select oid from pg_class where relname='t1'); + +-- expression test +drop table if exists t1 cascade; +create table t1(f1 int, f2 int, f3 int, f4 bool, f5 text, f6 text); +insert into t1 values(1, 2, 3, true, 'nanjin', 'huawei'); +-- T_FuncExpr +create index t1_idx1 on t1(abs(f1), f2); +-- T_OpExpr +create index t1_idx2 on t1((f1 + f2), (f1 - f3)); +-- T_BooleanTest +create index t1_idx3 on t1((f4 is true)); +-- T_CaseExpr and T_CaseWhen +create index t1_idx4 on t1((case f1 when f2 then 'yes' when f3 then 'no' else 'unknow' end)); +-- T_ArrayExpr +create index t1_idx5 on t1((array[f1, f2, f3])); +-- T_TypeCast +create index t1_idx6 on t1(((f1 + f2 + 1) :: text)); +-- T_BoolExpr +create index t1_idx7 on t1((f1 and f2), (f2 or f3)); +-- T_ArrayRef +create index t1_idx8 on t1((f1 = (array[f1, f2, 3])[1])); +-- T_ScalarArrayOpExpr +create index t1_idx9 on t1((f1 = ANY(ARRAY[f2, 1, f1 + 10]))); +-- T_RowCompareExpr +create index t1_idx10 on t1((row(f1, f5) < row(f2, f6))); +-- T_MinMaxExpr +create index t1_idx11 on t1(greatest(f1, f2, f3), least(f1, f2, f3)); +-- T_RowExpr +drop table if exists mytable cascade; +create table mytable(f1 int, f2 int, f3 text); +-- create function getf1(mytable) returns int as 'select $1.f1' language sql; +-- create index t1_idx12 on t1(getf1(row(f1, 2, 'a'))); +-- T_CoalesceExpr +create index t1_idx13 on t1(nvl(f1, f2)); +-- T_NullTest +create index t1_idx14 on t1((f1 is null)); +-- T_ScalarArrayOpExpr +create index t1_idx16 on t1((f1 in (1,2,3))); +-- T_NullIfExpr +create index t1_idx17 on t1(nullif(f5,f6)); +-- T_RelabelType +alter table t1 add f7 oid; +create index t1_idx18 on t1((f7::int4)); +-- T_CoerceViaIO +alter table t1 add f8 json; +create index t1_idx19 on t1((f8::jsonb)); +-- T_ArrayCoerceExpr +alter table t1 add f9 float[]; +create index t1_idx20 on t1((f9::int[])); +-- T_PrefixKey +create index t1_idx21 on t1(f6(5)); + +\d+ t1 +select * from t1; + +alter table t1 add f10 int primary key auto_increment after f4, + add f11 int generated always as (f1 + f2) stored after f1, + add f12 date default '2023-01-05' first, + add f13 int not null default 13 first; + +\d+ t1 +select * from t1; + +-- test modify column ... first | after column in astore table +-- ASTORE table +-- common scenatios +drop table if exists t1 cascade; +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 modify f3 timestamp first, modify f1 int after f4, modify f5 bool after f2; +\d+ t1 +select * from t1; +alter table t1 modify + +-- 1 primary key +drop table if exists t1 cascade; +create table t1(f1 int primary key, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +alter table t1 modify f3 timestamp first, modify f1 int after f4; +\d+ t1 +alter table t1 modify f1 int after f3; +\d+ t1 +alter table t1 drop f1, modify f5 bool first; +\d+ t1 + +drop table if exists t1 cascade; +create table t1(f1 int primary key, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 modify f3 timestamp first, modify f1 int after f4; +\d+ t1 +select * from t1; +alter table t1 modify f1 int after f3; +\d+ t1 +select * from t1; +alter table t1 drop f1, modify f5 bool first; +\d+ t1 +select * from t1; + +-- 2 unique index +drop table if exists t1 cascade; +create table t1(f1 int unique, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +alter table t1 modify f3 timestamp first, modify f1 int after f4; +\d+ t1 +alter table t1 modify f1 int after f3; +\d+ t1 +alter table t1 drop f1, modify f5 bool first; +\d+ t1 + +drop table if exists t1 cascade; +create table t1(f1 int unique, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 modify f3 timestamp first, modify f1 int after f4; +\d+ t1 +select * from t1; +alter table t1 modify f1 int after f3; +\d+ t1 +select * from t1; +alter table t1 drop f1, modify f5 bool first; +\d+ t1 +select * from t1; + +-- 3 default and generated column +drop table if exists t1 cascade; +create table t1(f1 int default 1, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +alter table t1 modify f3 timestamp first, modify f1 int after f4; +\d+ t1 +alter table t1 modify f1 int after f3; +\d+ t1 +alter table t1 drop f1, modify f5 bool first; +\d+ t1 + +drop table if exists t1 cascade; +create table t1(f1 int default 1, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 modify f3 timestamp first, modify f1 int after f4; +\d+ t1 +select * from t1; +alter table t1 modify f1 int after f3; +\d+ t1 +select * from t1; +alter table t1 drop f1, modify f5 bool first; +\d+ t1 +select * from t1; + +drop table if exists t1 cascade; +create table t1(f1 int, f2 int default 2, f3 int default 3, f4 int generated always as (f1 + f2) stored); +alter table t1 modify f4 int after f2, modify f1 int after f3, modify f3 int first; +\d+ t1 +alter table t1 drop f1; +\d+ t1 + +drop table if exists t1 cascade; +create table t1(f1 int, f2 int default 2, f3 int default 3, f4 int generated always as (f1 + f2) stored); +insert into t1 values(1,2,3),(11,22,33); +alter table t1 modify f4 int after f2, modify f1 int after f3, modify f3 int first; +\d+ t1 +select * from t1; +alter table t1 drop f1; +\d+ t1 +select * from t1; + +-- 4 auto_increment +drop table if exists t1 cascade; +create table t1(f1 int primary key auto_increment, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +\d+ t1 +alter table t1 modify f3 timestamp first, modify f1 int after f4; +\d+ t1 + +drop table if exists t1 cascade; +create table t1(f1 int primary key auto_increment, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +insert into t1(f2, f3, f4, f5) values('a', '2022-11-08 19:56:10.158564', x'41', true), ('b', '2022-11-09 19:56:10.158564', x'42', false); +\d+ t1 +select * from t1; +alter table t1 modify f3 timestamp first, modify f1 int after f4; +\d+ t1 +select * from t1; +insert into t1(f3, f2, f4, f5, f1) values('2022-11-10 19:56:10.158564', 'c', x'43', false, 3); +select f1 from t1; + +-- 5 NULL and NOT NULL +drop table if exists t1 cascade; +alter table t1(f1 int null, f2 varchar(20) not null, f3 timestamp, f4 varbit(8), f5 bool); +alter table t1 modify f3 timestamp first, modify f1 int after f4; +\d+ t1 +alter table t1 modify f1 int after f3; +\d+ t1 +alter table t1 drop f1, modify f5 bool first; +\d+ t1 +alter table t1 modify f2 varchar(20) after f3; +\d+ t1 + +drop table if exists t1 cascade; +alter table t1(f1 int null, f2 varchar(20) not null, f3 timestamp, f4 varbit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 modify f3 timestamp first, modify f1 int after f4; +\d+ t1 +select * from t1; +alter table t1 modify f1 int after f3; +\d+ t1 +select * from t1; +alter table t1 drop f1, modify f5 bool first; +\d+ t1 +select * from t1; +alter table t1 modify f2 varchar(20) after f3; +\d+ t1 +select * from t1; + +-- 6 check constraint +drop table if exists t1 cascade; +create table t1(f1 int check(f1 = 1), f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +alter table t1 modify f3 timestamp first, modify f1 int after f4; +\d+ t1 +alter table t1 modify f1 int after f3; +\d+ t1 +alter table t1 drop f1, modify f5 bool first; +\d+ t1 + +drop table if exists t1 cascade; +create table t1(f1 int check(f1 = 1), f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +alter table t1 modify f3 timestamp first, modify f1 int after f4; +\d+ t1 +select * from t1; +alter table t1 modify f1 int after f3; +\d+ t1 +select * from t1; +alter table t1 drop f1, modify f5 bool first; +\d+ t1 +select * from t1; + +-- 7 foreign key +drop table if exists t_pri1 cascade; +create table t_pri1(f1 int, f2 int primary key); +drop table if exists t1 cascade; +create table t1(f1 int, f2 int references t_pri1(f2), f3 bool); +alter table t1 modify f2 int first; +\d+ t1 +alter table t1 modify f2 int after f3; +\d+ t1 + +drop table if exists t_pri1 cascade; +create table t_pri1(f1 int, f2 int primary key); +insert into t_pri1 values(1,1),(2,2); +drop table if exists t1 cascade; +create table t1(f1 int, f2 int references t_pri1(f2), f3 bool); +insert into t1 values(1, 1, true), (2, 2, false); +alter table t1 modify f2 int first; +\d+ t1 +select * from t1; +alter table t1 modify f2 int after f3; +\d+ t1 +select * from t1; + +-- partition table +drop table if exists t1 cascade; +create table t1 +(f1 int, f2 int, f3 int, primary key (f1, f2)) +partition by range(f1, f2) +( + partition t1_p0 values less than (10, 0), + partition t1_p1 values less than (20, 0), + partition t1_p2 values less than (30, 0) +); +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='t1') order by relname; + +alter table t1 modify f1 int after f2, modify f3 int first, modify f2 int first; +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='t1') order by relname; + +alter table t1 modify f1 int after f2; +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='t1') order by relname; + +-- modify operation before add +alter table t1 add f4 int after f2, modify f1 int after f2; +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='t1'); + +drop table if exists t1 cascade; +create table t1 +(f1 int, f2 int, f3 int, primary key (f1, f2)) +partition by range(f1, f2) +( + partition t1_p0 values less than (10, 0), + partition t1_p1 values less than (20, 0), + partition t1_p2 values less than (30, 0) +); +insert into t1 values(9, -1, 1), (19, -1, 2), (29, -1, 3); +\d+ t1 +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='t1'); +select * from t1 partition (t1_p0); +select * from t1 partition (t1_p1); +select * from t1 partition (t1_p2); + +alter table t1 modify f1 int after f2, modify f3 int first, modify f2 int first; +\d+ t1 +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='t1'); +select * from t1 partition (t1_p0); +select * from t1 partition (t1_p1); +select * from t1 partition (t1_p2); + +alter table t1 modify f1 int after f2; +\d+ t1 +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='t1'); +select * from t1 partition (t1_p0); +select * from t1 partition (t1_p1); +select * from t1 partition (t1_p2); + +alter table t1 add f4 int after f2, modify f1 int after f2; +\d+ t1 +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='t1'); +select * from t1 partition (t1_p0); +select * from t1 partition (t1_p1); +select * from t1 partition (t1_p2); + +-- subpartition table +drop table if exists range_range cascade; +create table range_range(id int, gender varchar not null, birthday date not null, primary key(id, birthday)) +partition by range (id) subpartition by range (birthday) +( + partition p_1 values less than(100) + ( + subpartition p_1_a values less than('2022-01-01'), + subpartition p_1_b values less than(MAXVALUE) + ), + partition p_2 values less than(200) + ( + subpartition p_2_a values less than('2022-01-01'), + subpartition p_2_b values less than(MAXVALUE) + ), + partition p_3 values less than(MAXVALUE) + ( + subpartition p_3_a values less than('2022-01-01'), + subpartition p_3_b values less than(MAXVALUE) + ) +); +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='range_range') order by relname; + +alter table range_range modify birthday date first, modify id int after gender; +\d+ range_range +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='range_range') order by relname; + + +drop table if exists range_range cascade; +create table range_range(id int, gender varchar not null, birthday date not null, primary key(id, birthday)) +partition by range (id) subpartition by range (birthday) +( + partition p_1 values less than(100) + ( + subpartition p_1_a values less than('2022-01-01'), + subpartition p_1_b values less than(MAXVALUE) + ), + partition p_2 values less than(200) + ( + subpartition p_2_a values less than('2022-01-01'), + subpartition p_2_b values less than(MAXVALUE) + ), + partition p_3 values less than(MAXVALUE) + ( + subpartition p_3_a values less than('2022-01-01'), + subpartition p_3_b values less than(MAXVALUE) + ) +); + +insert into range_range values(198,'boy','2010-02-15'),(33,'boy','2003-08-11'),(78,'girl','2014-06-24'); +insert into range_range values(233,'girl','2010-01-01'),(360,'boy','2007-05-14'),(146,'girl','2005-03-08'); +insert into range_range values(111,'girl','2013-11-19'),(15,'girl','2009-01-12'),(156,'boy','2011-05-21'); + +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='range_range') order by relname; + +alter table range_range modify birthday date first, modify id int after gender; +\d+ range_range +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='range_range') order by relname; + +select * from range_range; + +-- pg_index test +drop table if exists t1 cascade; +create table t1 +( + f1 int, f2 int, f3 varchar(20), f4 int, f5 int, f6 int, f7 int, + primary key(f1, f2), + unique((lower(f3)), (abs(f4))), + check(f5 = 10) +); +create unique index partial_t1_idx on t1(f5, abs(f6)) where f5 + f6 - abs(f7) > 0; + +\d+ t1 +select indkey, indexprs, indpred from pg_index where indrelid = (select oid from pg_class where relname = 't1'); + +alter table t1 modify f1 int after f2, modify f4 int after f6, modify f5 int first; +\d+ t1 +select indkey, indexprs, indpred from pg_index where indrelid = (select oid from pg_class where relname = 't1'); + +-- pg_attribute test +drop table if exists t1 cascade; +create table t1(f1 int, f2 int, f3 int); +\d+ t1 +select attname, attnum, atthasdef, attisdropped from pg_attribute where attrelid = (select oid from pg_class where relname = 't1') and attnum > 0 order by attnum; + +alter table t1 modify f3 int first, modify f1 int after f2; +\d+ t1 +select attname, attnum, atthasdef, attisdropped from pg_attribute where attrelid = (select oid from pg_class where relname = 't1') and attnum > 0 order by attnum; + +-- pg_attrdef test +drop table if exists t1 cascade; +create table t1(f1 int primary key auto_increment, f2 int, f3 int default 3, f4 int generated always as (f2 + f3) stored); +\d+ t1 +select adnum, adsrc, adgencol from pg_attrdef where adrelid = (select oid from pg_class where relname = 't1') order by adnum; + +alter table t1 modify f3 int first, modify f1 int after f4, modify f4 int first; +\d+ t1 +select adnum, adsrc, adgencol from pg_attrdef where adrelid = (select oid from pg_class where relname = 't1') order by adnum; + +-- pg_depend test +drop table if exists t1 cascade; +create table t1(f1 int default 10, f2 int primary key, f3 int generated always as (f1 + f2) stored, f4 int, unique ((abs(f4)))); +\d+ t1 +select classid, objsubid, refclassid, refobjsubid, deptype from pg_depend + where refobjid = (select oid from pg_class where relname='t1') or objid = (select oid from pg_class where relname='t1') order by 1, 2, 3, 4, 5; + +alter table t1 modify f4 int first, modify f3 int after f1, modify f1 int after f2; +\d+ t1 +select classid, objsubid, refclassid, refobjsubid, deptype from pg_depend + where refobjid = (select oid from pg_class where relname='t1') or objid = (select oid from pg_class where relname='t1') order by 1, 2, 3, 4, 5; + +-- pg_partition test +drop table if exists range_range cascade; +create table range_range(id int, gender varchar not null, birthday date not null) +partition by range (id) subpartition by range (birthday) +( + partition p_1 values less than(100) + ( + subpartition p_1_a values less than('2022-01-01'), + subpartition p_1_b values less than(MAXVALUE) + ), + partition p_2 values less than(200) + ( + subpartition p_2_a values less than('2022-01-01'), + subpartition p_2_b values less than(MAXVALUE) + ), + partition p_3 values less than(MAXVALUE) + ( + subpartition p_3_a values less than('2022-01-01'), + subpartition p_3_b values less than(MAXVALUE) + ) +); +insert into range_range values(198,'boy','2010-02-15'),(33,'boy','2003-08-11'),(78,'girl','2014-06-24'); +insert into range_range values(233,'girl','2010-01-01'),(360,'boy','2007-05-14'),(146,'girl','2005-03-08'); +insert into range_range values(111,'girl','2013-11-19'),(15,'girl','2009-01-12'),(156,'boy','2011-05-21'); + +\d+ range_range +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='range_range') order by relname; + +alter table range_range modify gender varchar after birthday; +\d+ range_range +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='range_range') order by relname; + +alter table range_range modify birthday date first, modify id int after gender; +\d+ range_range +select relname, parttype, partkey from pg_partition where parentid=(select oid from pg_class where relname='range_range') order by relname; + + +-- pg_rewrite test +drop table if exists t1 cascade; +create table t1(f1 int, f2 int, f3 int, f4 int); +insert into t1 values(1, 2, 3, 4), (11, 22, 33, 44); +create view t1_view1 as select * from t1; +create view t1_view2 as select f1, f4 from t1; +\d+ t1_view1 +\d+ t1_view2 +\d+ t1 +select pg_get_viewdef('t1_view1'); +select pg_get_viewdef('t1_view2'); +select * from t1_view1; +select * from t1_view2; +select * from t1; +alter table t1 modify f2 int first, modify f1 int after f4, add f5 int after f4; +\d+ t1_view1 +\d+ t1_view2 +\d+ t1 +select pg_get_viewdef('t1_view1'); +select pg_get_viewdef('t1_view2'); +select * from t1_view1; +select * from t1_view2; +select * from t1; + +-- pg_trigger test +drop table if exists t1 cascade; +create table t1(f1 boolean not null, f2 text, f3 int, f4 date); +alter table t1 add primary key(f1); +drop function if exists dummy_update_func; +create function dummy_update_func() returns trigger as $$ +begin + raise notice 'dummy_update_func(%) called: action = %, oid = %, new = %', TG_ARGV[0], TG_OP, OLD, NEW; + return new; +end; +$$ language plpgsql; +drop function dummy_update_func; +drop trigger if exists f1_trig_update on t1; +drop trigger if exists f1_trig_insert on t1; + +create trigger f1_trig_update after update of f1 on t1 for each row + when (not old.f1 and new.f1) execute procedure dummy_update_func('update'); +create trigger f1_trig_insert after insert on t1 for each row + when (not new.f1) execute procedure dummy_update_func('insert'); + +\d+ t1 +select tgname, tgattr, tgqual from pg_trigger where tgrelid = (select oid from pg_class where relname='t1') order by tgname; + +alter table t1 modify f3 int first, modify f1 boolean after f4; +\d+ t1 +select tgname, tgattr, tgqual from pg_trigger where tgrelid = (select oid from pg_class where relname='t1') order by tgname; + +-- pg_rlspolicy test +drop table if exists t1 cascade; +drop role if exists test_rlspolicy3; +create role test_rlspolicy3 nologin password 'Gauss_234'; +create table t1 (f1 int, f2 int, f3 text) partition by range (f1) +( + partition t1_p0 values less than(10), + partition t1_p1 values less than(50), + partition t1_p2 values less than(100), + partition t1_p3 values less than(MAXVALUE) +); + +INSERT INTO t1 VALUES (generate_series(1, 150) % 24, generate_series(1, 150), 'huawei'); +grant select on t1 to public; + +create row level security policy t1_rls1 on t1 as permissive to public using (f2 <= 20); +create row level security policy t1_rls2 on t1 as restrictive to test_rlspolicy3 using (f1 < 30); + +\d+ t1 +select * from t1 limit 10; +select polname, polqual from pg_rlspolicy where polrelid = (select oid from pg_class where relname='t1'); + +alter table t1 modify f2 int first, modify f1 int after f3; + +\d+ t1 +select * from t1 limit 10; +select polname, polqual from pg_rlspolicy where polrelid = (select oid from pg_class where relname='t1'); + + +-- expression test +drop table if exists t1 cascade; +create table t1(f1 int, f2 int, f3 int, f4 bool, f5 text, f6 text); +insert into t1 values(1, 2, 3, true, 'nanjin', 'huawei'); +-- T_FuncExpr +create index t1_idx1 on t1(abs(f1), f2); +-- T_OpExpr +create index t1_idx2 on t1((f1 + f2), (f1 - f3)); +-- T_BooleanTest +create index t1_idx3 on t1((f4 is true)); +-- T_CaseExpr and T_CaseWhen +create index t1_idx4 on t1((case f1 when f2 then 'yes' when f3 then 'no' else 'unknow' end)); +-- T_ArrayExpr +create index t1_idx5 on t1((array[f1, f2, f3])); +-- T_TypeCast +create index t1_idx6 on t1(((f1 + f2 + 1) :: text)); +-- T_BoolExpr +create index t1_idx7 on t1((f1 and f2), (f2 or f3)); +-- T_ArrayRef +create index t1_idx8 on t1((f1 = (array[f1, f2, 3])[1])); +-- T_ScalarArrayOpExpr +create index t1_idx9 on t1((f1 = ANY(ARRAY[f2, 1, f1 + 10]))); +-- T_RowCompareExpr +create index t1_idx10 on t1((row(f1, f5) < row(f2, f6))); +-- T_MinMaxExpr +create index t1_idx11 on t1(greatest(f1, f2, f3), least(f1, f2, f3)); +-- T_RowExpr +drop table if exists mytable cascade; +create table mytable(f1 int, f2 int, f3 text); +-- create function getf1(mytable) returns int as 'select $1.f1' language sql; +-- create index t1_idx12 on t1(getf1(row(f1, 2, 'a'))); +-- T_CoalesceExpr +create index t1_idx13 on t1(nvl(f1, f2)); +-- T_NullTest +create index t1_idx14 on t1((f1 is null)); +-- T_ScalarArrayOpExpr +create index t1_idx16 on t1((f1 in (1,2,3))); +-- T_NullIfExpr +create index t1_idx17 on t1(nullif(f5,f6)); +-- T_RelabelType +alter table t1 add f7 oid; +create index t1_idx18 on t1((f7::int4)); +-- T_CoerceViaIO +alter table t1 add f8 json; +create index t1_idx19 on t1((f8::jsonb)); +-- T_ArrayCoerceExpr +alter table t1 add f9 float[]; +create index t1_idx20 on t1((f9::int[])); + +\d+ t1 +select * from t1; + +alter table t1 modify f8 json first, modify f2 int after f6, modify f7 oid after f3; + +\d+ t1 +select * from t1; + +drop table if exists t1; +create table t1(f1 int, f2 int); +insert into t1 values(1,2); +alter table t1 add f3 int default 3, add f4 int default 4 after f3, add f5 int default 5, add f6 int default 6 after f3; +select * from t1; + +drop table if exists t1; +create table t1(f1 int, f2 int); +insert into t1 values(1,2); +alter table t1 add f3 int default 3, add f4 int default 4 after f1, add f5 int default 5, add f6 int default 6 after f5; +select * from t1; + +drop table if exists t1; +create table t1(f1 int, f2 int); +insert into t1 values(1,2); +alter table t1 add f3 int, add f4 int after f3, add f5 int, add f6 int first; +select * from t1; + +drop table if exists t1; +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); + +alter table t1 drop f5, + add f6 int default 6 , add f7 int first, add f8 int default 8 after f3, + modify f3 timestamp first, modify f6 int after f2, modify f1 text, modify f2 text after f4; + +drop table if exists t1 cascade; +create table t1(f1 int, f2 int, f3 int, primary key(f1, f3)); +insert into t1 values(1, 2, 3), (11, 22, 33); +\d+ t1 +select * from t1; +alter table t1 modify f3 int first, modify f1 int after f2; +\d+ t1 +select * from t1; + +drop table if exists t1 cascade; +create table t1(f1 int, f2 int, f3 int); +insert into t1 values(1, 2, 3), (11, 12, 13), (21, 22, 23); +select * from t1; +alter table t1 add f4 int generated always as (f1 + 100) stored after f1, add f5 int generated always as (f2 * 10) stored first; +select * from t1; + +drop table if exists t1 cascade; +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool, f6 int generated always as (f1 * 10) stored, primary key(f1, f2)); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +select * from t1; +\d+ t1 +select * from t1; + +drop table if exists t1 cascade; +create table t1(f1 int, f2 varchar(20), f3 int, primary key(f1, f3)); +insert into t1 values(1, 'a', 1), (2, 'b', 2); +\d+ t1 +select * from t1; + +alter table t1 modify f1 text after f3, add f10 int default 10 after f2; +\d+ t1 +select * from t1; + +-- unlogged table +drop table if exists t1 cascade; +create unlogged table t1(f1 int, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool, f6 int generated always as (f1 * 10) stored, primary key(f1, f2)); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +\d+ t1 +select * from t1; + +\d+ t1 +select * from t1; + +--DTS +drop table if exists unit cascade; +CREATE TABLE unit +( + f11 INTEGER CHECK (f11 >=2), + f12 bool, + f13 text, + f14 varchar(20), + primary key (f11,f12) +); + +insert into unit values(2,3,4,5); +insert into unit values(3,4,5,6); +ALTER TABLE unit ADD f1 int CHECK (f1 >=10) FIRST; +insert into unit values (10,6,1,1,1); +insert into unit values (11,7,1,1,1); +ALTER TABLE unit ADD f2 int CHECK (f2 >=10) after f11; +select * from unit; +ALTER TABLE unit MODIFY f12 int FIRST; +select * from unit; +drop table if exists unit cascade; + +drop table t1 cascade; +create table t1(f1 int, f2 text, f3 int, f4 bool, f5 int generated always as (f1 + f3) stored); +insert into t1 values(1, 'aaa', 3, true); +insert into t1 values(11, 'bbb', 33, false); +insert into t1 values(111, 'ccc', 333, true); +insert into t1 values(1111, 'ddd', 3333, true); + +create view t1_view1 as select * from t1; +select * from t1_view1; +alter table t1 modify f1 int after f2, modify f3 int first; +drop view t1_view1; +create view t1_view1 as select * from t1; +alter table t1 modify f1 int after f2, modify f3 int first; +drop table t1 cascade; + +create table t1(f1 int, f2 text, f3 int, f4 bigint, f5 int generated always as (f1 + f3) stored); +insert into t1 values(1, 'aaa', 3, 1); +insert into t1 values(11, 'bbb', 33, 2); +insert into t1 values(111, 'ccc', 333, 3); +insert into t1 values(1111, 'ddd', 3333, 4); + +create view t1_view1 as select * from t1; +select * from t1_view1; +alter table t1 add f6 int first, add f7 int after f4, modify f1 int after f2, modify f3 int first; +select * from t1_view1; +drop view t1_view1; + +create view t1_view2 as select f1, f3, f5 from t1 where f2='aaa'; +select * from t1_view2; +alter table t1 add f8 int first, add f9 int after f4, modify f1 int after f2, modify f3 int first, modify f2 varchar(20) first; +select * from t1_view2; +drop view t1_view2; + +create view t1_view3 as select * from (select f1+f3, f5 from t1); +select * from t1_view3; +alter table t1 add f10 int first, add f11 int after f4, modify f1 int after f2, modify f3 int first, modify f2 varchar(20) first; +select * from t1_view3; +drop view t1_view3; + +create view t1_view4 as select * from (select abs(f1+f3) as col1, abs(f5) as col2 from t1); +select * from t1_view4; +alter table t1 add f12 int first, add f13 int after f4, modify f1 int after f2, modify f3 int first, modify f2 varchar(20) first; +select * from t1_view4; +drop view t1_view4; + +create view t1_view5 as select * from (select * from t1); +select * from t1_view5; +alter table t1 add f14 int first, add f15 int after f4, modify f1 int after f2, modify f3 int first; +select * from t1_view5; +drop view t1_view5; + +create view t1_view6 as select f1, f3, f5 from t1 where f2='aaa'; +select * from t1_view6; +alter table t1 modify f1 int after f2, modify f3 int first, modify f2 varchar(20) first; +select * from t1_view6; +drop view t1_view6; +drop table t1 cascade; + +-- dts for add +drop table if exists test_d; +create table test_d (f2 int primary key, f3 bool, f5 text); +insert into test_d values(1,2,3), (2,3,4), (3,4,5); +select * from test_d; +alter table test_d add f1 int default 1,add f11 text check (f11 >=2) first; +select * from test_d; + +drop table if exists test_d; +create table test_d (f2 int primary key, f3 bool, f5 text); +insert into test_d values(1,2,3), (2,3,4), (3,4,5); +select * from test_d; +alter table test_d add f1 int default 1; +alter table test_d add f11 text check (f11 >=2) first; +select * from test_d; +drop table if exists test_d; + +drop table if exists t1 cascade; +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +select * from t1; +alter table t1 add f6 int generated always as (f1 * 10) stored, add f7 text default '777' first, + add f8 int default 8, add f9 int primary key auto_increment after f6; +select * from t1; + +drop table if exists t1 cascade; +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 varbit(8), f5 bool); +insert into t1 values(1, 'a', '2022-11-08 19:56:10.158564', x'41', true), (2, 'b', '2022-11-09 19:56:10.158564', x'42', false); +select * from t1; +select * from t1; +drop table if exists t1 cascade; + +drop table if exists t1 cascade; +create table t1(f1 int comment 'f1 is int', f2 varchar(20), f3 timestamp comment 'f3 is timestamp', f4 varbit(8), f5 bool comment 'f5 is boolean'); +SELECT pg_get_tabledef('t1'); +alter table t1 add f6 int generated always as (f1 * 10) stored, add f7 text default '7' first, add f8 int primary key auto_increment after f2; +SELECT pg_get_tabledef('t1'); +alter table t1 modify f1 int after f3, modify f5 bool first, modify f3 timestamp after f4; +SELECT pg_get_tabledef('t1'); +drop table if exists t1 cascade; + + + + +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 add f6 boolean primary key auto_increment not null; +drop table if exists t1 cascade; + +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 add f6 int1 primary key auto_increment not null; +drop table if exists t1 cascade; + +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 add f6 int2 primary key auto_increment not null; +drop table if exists t1 cascade; + +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 add f6 int4 primary key auto_increment ; +drop table if exists t1 cascade; + +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 add f6 int8 primary key auto_increment not null; +drop table if exists t1 cascade; + +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 add f6 int16 primary key auto_increment not null; +drop table if exists t1 cascade; + +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 add f6 float4 primary key auto_increment not null; +drop table if exists t1 cascade; + +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 add f6 float8 primary key auto_increment not null; +drop table if exists t1 cascade; + +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 modify column f1 boolean primary key auto_increment not null; +drop table if exists t1 cascade; + +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 modify column f1 int1 primary key auto_increment not null; +drop table if exists t1 cascade; + +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 modify column f1 int2 primary key auto_increment not null; +drop table if exists t1 cascade; + +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 modify column f1 int4 primary key auto_increment not null; +drop table if exists t1 cascade; + +create table t1(f1 int not null, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 modify column f1 int8 primary key auto_increment; +drop table if exists t1 cascade; + +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 modify column f1 int16 primary key auto_increment not null; +drop table if exists t1 cascade; + +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 modify column f1 float4 primary key auto_increment not null; +drop table if exists t1 cascade; + +create table t1(f1 int, f2 varchar(20), f3 timestamp, f4 bit(8), f5 bool); +alter table t1 modify column f1 float8 primary key auto_increment not null; +drop table if exists t1 cascade; + + +-- \c postgres +-- drop database test_first_after_B; \ No newline at end of file diff --git a/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_001.sql b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_001.sql new file mode 100644 index 000000000..eae044df9 --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_001.sql @@ -0,0 +1,789 @@ +create table altertable_rangeparttable +( + c1 int, + c2 float, + c3 real, + c4 text +) +partition by range (c1, c2, c3, c4) +( + partition altertable_rangeparttable_p1 values less than (10, 10.00, 19.156, 'h'), + partition altertable_rangeparttable_p2 values less than (20, 20.89, 23.75, 'k'), + partition altertable_rangeparttable_p3 values less than (30, 30.45, 32.706, 's') +); + +alter table altertable_rangeparttable add partition altertable_rangeparttable_p4 values less than (36, 45.25, 37.39, 'u'); + +create table altertable_rangeparttable2 +( + c1 int, + c2 float, + c3 real, + c4 text +) +partition by range (abs(c1)) +( + partition altertable_rangeparttable_p1 values less than (10), + partition altertable_rangeparttable_p2 values less than (20), + partition altertable_rangeparttable_p3 values less than (30) +); +alter table altertable_rangeparttable2 add partition altertable_rangeparttable_p4 values less than (36); + + +CREATE TABLE range_range +( + month_code VARCHAR2 ( 30 ) NOT NULL , + dept_code VARCHAR2 ( 30 ) NOT NULL , + user_no VARCHAR2 ( 30 ) NOT NULL , + sales_amt int +) +PARTITION BY RANGE (month_code) SUBPARTITION BY RANGE (dept_code) +( + PARTITION p_201901 VALUES LESS THAN( '201903' ) + ( + SUBPARTITION p_201901_a VALUES LESS THAN( '2' ), + SUBPARTITION p_201901_b VALUES LESS THAN( '3' ) + ), + PARTITION p_201902 VALUES LESS THAN( '201904' ) + ( + SUBPARTITION p_201902_a VALUES LESS THAN( '2' ), + SUBPARTITION p_201902_b VALUES LESS THAN( '3' ) + ) +); + +alter table range_range add partition p_202001 values less than ('202002') (subpartition p_202001_a values less than('2') , subpartition p_202001_b values less than('3') ); + +-- comes from function_get_table_def.sql +create table table_range4 (id int primary key, a date, b varchar) +partition by range (id) +( + partition table_range4_p1 start (10) end (40) every (10), + partition table_range4_p2 end (70), + partition table_range4_p3 start (70), + partition table_range4_p4 start (100) end (150) every (20) +); + +alter table table_range4 add partition table_range4_p5 start (150) end (300) every (20); +alter table table_range4 add partition table_range4_p6 values less than (310), add partition table_range4_p7 values less than (320); + +create table table_interval1 (id int, a date, b varchar) +partition by range (a) +interval ('1 day') +( + partition table_interval1_p1 values less than('2020-03-01'), + partition table_interval1_p2 values less than('2020-05-01'), + partition table_interval1_p3 values less than('2020-07-01'), + partition table_interval1_p4 values less than(maxvalue) +); +alter table table_interval1 add partition table_interval1_p5 start ('2020-08-01') end ('2020-09-01'); + +create table table_list1 (id int, a date, b varchar) +partition by list (id) +( + partition table_list1_p1 values (1, 2, 3, 4), + partition table_list1_p2 values (5, 6, 7, 8), + partition table_list1_p3 values (9, 10, 11, 12) +); +alter table table_list1 add partition table_list1_p4 values (13, 14, 15, 16); +alter table table_list1 add partition table_list1_p5 values (default); + +create table table_list2 (id int, a date, b varchar) +partition by list (b) +( + partition table_list2_p1 values ('1', '2', '3', '4'), + partition table_list2_p2 values ('5', '6', '7', '8'), + partition table_list2_p3 values ('9', '10', '11', '12') +); +alter table table_list2 add partition table_list2_p4 values ('13', '14', '15', '16'); +alter table table_list2 add partition table_list2_p5 values ('DEFAULT'); +alter table table_list2 add partition table_list2_p6 values ('default'); +alter table table_list2 add partition table_list2_p7 values (default); + + +create table table_list3 (id int, a date, b varchar) +partition by list (id, b) +( + partition table_list3_p1 values ((1, 'a'), (2,'b'), (3,'c'), (4,'d')) , + partition table_list3_p2 values ((5, 'a'), (6,'b'), (7,'c'), (8,'d')) + +); +alter table table_list3 add partition table_list3_p3 values ((15, 'a'), (16,'b'), (17,'c'), (18,'d')); +alter table table_list3 add partition table_list3_p4 values (default); + +create table table_hash1 (id int, a date, b varchar) +partition by hash (id) +( + partition table_hash1_p1, + partition table_hash1_p2, + partition table_hash1_p3 +); + + +CREATE TABLE list_hash_2 ( + col_1 integer primary key, + col_2 integer, + col_3 character varying(30) unique, + col_4 integer +) +WITH (orientation=row, compression=no) +PARTITION BY LIST (col_2) SUBPARTITION BY HASH (col_3) +( + PARTITION p_list_1 VALUES (-1,-2,-3,-4,-5,-6,-7,-8,-9,-10) + ( + SUBPARTITION p_hash_1_1, + SUBPARTITION p_hash_1_2, + SUBPARTITION p_hash_1_3 + ), + PARTITION p_list_2 VALUES (1,2,3,4,5,6,7,8,9,10), + PARTITION p_list_3 VALUES (11,12,13,14,15,16,17,18,19,20) + ( + SUBPARTITION p_hash_3_1, + SUBPARTITION p_hash_3_2 + ), + PARTITION p_list_4 VALUES (21,22,23,24,25,26,27,28,29,30) + ( + SUBPARTITION p_hash_4_1, + SUBPARTITION p_hash_4_2, + SUBPARTITION p_hash_4_3, + SUBPARTITION p_hash_4_4, + SUBPARTITION p_hash_4_5 + ), + PARTITION p_list_5 VALUES (31,32,33,34,35,36,37,38,39,40), + PARTITION p_list_6 VALUES (41,42,43,44,45,46,47,48,49,50) + ( + SUBPARTITION p_hash_6_1, + SUBPARTITION p_hash_6_2, + SUBPARTITION p_hash_6_3, + SUBPARTITION p_hash_6_4, + SUBPARTITION p_hash_6_5 + ), + PARTITION p_list_7 VALUES (DEFAULT) +); + +alter table list_hash_2 add partition p_list_8 values (51,52,53,54,55,56,57,58,59,60) (subpartition p_hash_8_1, subpartition p_hash_8_2, subpartition p_hash_8_3); + +-- drop table table_list3; +create table table_list3 (id int, a date, b varchar) +partition by list (id, b) +( + partition table_list3_p1 values ((1, 'a'), (2,'b'), (3,'c'), (4,'d')) , + partition table_list3_p2 values ((5,'a'), (6,'b'), (7,'NULL'), (8,NULL)) +); + +alter table table_list3 add partition table_list3_p3 values ((15, 'a'), (16,'default'), (17,'NULL'), (18,NULL)); + +alter table table_list3 add partition table_list3_p4 values (default); + +CREATE TABLE range_range_sales +( + product_id INT4 NOT NULL, + customer_id INT4 PRIMARY KEY, + time_id DATE, + channel_id CHAR(1), + type_id INT4, + quantity_sold NUMERIC(3), + amount_sold NUMERIC(10,2) +) +PARTITION BY RANGE (customer_id) SUBPARTITION BY RANGE (time_id) +( + PARTITION customer1 VALUES LESS THAN (200) + ( + SUBPARTITION customer1_2008 VALUES LESS THAN ('2009-01-01'), + SUBPARTITION customer1_2009 VALUES LESS THAN ('2010-01-01'), + SUBPARTITION customer1_2010 VALUES LESS THAN ('2011-01-01'), + SUBPARTITION customer1_2011 VALUES LESS THAN ('2012-01-01') + ), + PARTITION customer2 VALUES LESS THAN (500) + ( + SUBPARTITION customer2_2008 VALUES LESS THAN ('2009-01-01'), + SUBPARTITION customer2_2009 VALUES LESS THAN ('2010-01-01'), + SUBPARTITION customer2_2010 VALUES LESS THAN ('2011-01-01'), + SUBPARTITION customer2_2011 VALUES LESS THAN ('2012-01-01') + ), + PARTITION customer3 VALUES LESS THAN (800), + PARTITION customer4 VALUES LESS THAN (1200) + ( + SUBPARTITION customer4_all VALUES LESS THAN ('2012-01-01') + ) +); + +INSERT INTO range_range_sales SELECT generate_series(1,1000), + generate_series(1,1000), + date_pli('2008-01-01', generate_series(1,1000)), + generate_series(1,1000)%10, + generate_series(1,1000)%10, + generate_series(1,1000)%1000, + generate_series(1,1000); +CREATE INDEX range_range_sales_idx ON range_range_sales(product_id) LOCAL; +ALTER TABLE range_range_sales ADD PARTITION customer5 VALUES LESS THAN (1500) + ( + SUBPARTITION customer5_2008 VALUES LESS THAN ('2009-01-01'), + SUBPARTITION customer5_2009 VALUES LESS THAN ('2010-01-01'), + SUBPARTITION customer5_2010 VALUES LESS THAN ('2011-01-01'), + SUBPARTITION customer5_2011 VALUES LESS THAN ('2012-01-01') + ); +ALTER TABLE range_range_sales MODIFY PARTITION customer1 ADD SUBPARTITION customer1_2012 VALUES LESS THAN ('2013-01-01'); + +CREATE TABLE range2_sales +( + product_id INT4 NOT NULL, + customer_id INT4 PRIMARY KEY, + time_id DATE, + channel_id CHAR(1), + type_id INT4, + quantity_sold NUMERIC(3), + amount_sold NUMERIC(10,2) +) +PARTITION BY RANGE (time_id, product_id) +( + PARTITION time_2008 VALUES LESS THAN ('2009-01-01', 200), + PARTITION time_2009 VALUES LESS THAN ('2010-01-01', 500), + PARTITION time_2010 VALUES LESS THAN ('2011-01-01', 800), + PARTITION time_2011 VALUES LESS THAN ('2012-01-01', 1200) +); + +INSERT INTO range2_sales SELECT generate_series(1,1000), + generate_series(1,1000), + date_pli('2008-01-01', generate_series(1,1000)), + generate_series(1,1000)%10, + generate_series(1,1000)%10, + generate_series(1,1000)%1000, + generate_series(1,1000); +CREATE INDEX range2_sales_idx ON range2_sales(product_id) LOCAL; + +ALTER TABLE range2_sales TRUNCATE PARTITION time_2008; +ALTER TABLE range2_sales TRUNCATE PARTITION FOR VALUES('2011-04-01', 700) ; + +ALTER TABLE range2_sales DROP PARTITION time_2009; +ALTER TABLE range2_sales DROP PARTITION FOR ('2011-06-01', 600); + +CREATE TABLE range_list_sales +( + product_id INT4 NOT NULL, + customer_id INT4 PRIMARY KEY, + time_id DATE, + channel_id CHAR(100), + type_id INT4, + quantity_sold NUMERIC(3), + amount_sold NUMERIC(10,2) +) +PARTITION BY RANGE (customer_id) SUBPARTITION BY LIST (channel_id) +( + PARTITION customer1 VALUES LESS THAN (200) + ( + SUBPARTITION customer1_channel1 VALUES ('0', '1', '2'), + SUBPARTITION customer1_channel2 VALUES ('3', '4', '5'), + SUBPARTITION customer1_channel3 VALUES ('6', '7', '8'), + SUBPARTITION customer1_channel4 VALUES ('9') + ), + PARTITION customer2 VALUES LESS THAN (500) + ( + SUBPARTITION customer2_channel1 VALUES ('0', '1', '2', '3', '4'), + SUBPARTITION customer2_channel2 VALUES (DEFAULT) + ), + PARTITION customer3 VALUES LESS THAN (800), + PARTITION customer4 VALUES LESS THAN (1200) + ( + SUBPARTITION customer4_channel1 VALUES ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9') + ) +); + +INSERT INTO range_list_sales SELECT generate_series(1,1000), + generate_series(1,1000), + date_pli('2008-01-01', generate_series(1,1000)), + generate_series(1,1000)%10, + generate_series(1,1000)%10, + generate_series(1,1000)%1000, + generate_series(1,1000); +CREATE INDEX range_list_sales_idx ON range_list_sales(product_id) LOCAL; +ALTER TABLE range_list_sales ADD PARTITION customer5 VALUES LESS THAN (1500) + ( + SUBPARTITION customer5_channel1 VALUES ('0', '1', '2'), + SUBPARTITION customer5_channel2 VALUES ('3', '4', '5'), + SUBPARTITION customer5_channel3 VALUES ('6', '7', '8'), + SUBPARTITION customer5_channel4 VALUES ('9') + ); +ALTER TABLE range_list_sales MODIFY PARTITION customer1 ADD SUBPARTITION customer1_channel5 VALUES ('X', 'A', 'bbb'); +ALTER TABLE range_list_sales MODIFY PARTITION customer1 ADD SUBPARTITION customer1_channel6 VALUES ('NULL', 'asdasd', 'hahaha'); +ALTER TABLE range_list_sales MODIFY PARTITION customer1 ADD SUBPARTITION customer1_channel7 VALUES (NULL); +ALTER TABLE range_list_sales MODIFY PARTITION customer1 ADD SUBPARTITION customer1_channel8 VALUES ('DEFAULT', 'wawawa'); +ALTER TABLE range_list_sales MODIFY PARTITION customer1 ADD SUBPARTITION customer1_channel9 VALUES (DEFAULT); +ALTER TABLE range_list_sales DROP SUBPARTITION customer1_channel9; + +ALTER TABLE range_list_sales SPLIT partition customer4 INTO ( + partition customer4_p1 values less than (900) + ( + subpartition customer4_p1_s1 VALUES ('11'), + subpartition customer4_p1_s2 VALUES ('12') + ), + partition customer4_p2 values less than (1000) + ( + subpartition customer4_p2_s1 VALUES ('11'), + subpartition customer4_p2_s2 VALUES ('12') + ) +); + +ALTER TABLE range_list_sales truncate partition customer2 update global index; +ALTER TABLE range_list_sales truncate partition for (300); +ALTER TABLE range_list_sales truncate partition customer5_channel3; + +ALTER TABLE range_list_sales DROP PARTITION customer2; +ALTER TABLE range_list_sales DROP SUBPARTITION customer1_channel1; + + +create table test_list (col1 int, col2 int) +partition by list(col1) +( +partition p1 values (2000), +partition p2 values (3000), +partition p3 values (4000), +partition p4 values (5000) +); + +INSERT INTO test_list VALUES(2000, 2000); +INSERT INTO test_list VALUES(3000, 3000); +alter table test_list add partition p5 values (6000); +INSERT INTO test_list VALUES(6000, 6000); + +create table t1 (col1 int, col2 int); + +alter table test_list exchange partition (p1) with table t1 VERBOSE; +alter table test_list truncate partition p2; +alter table test_list drop partition p5; + + +create table test_hash (col1 int, col2 int) +partition by hash(col1) +( +partition p1, +partition p2 +); + +INSERT INTO test_hash VALUES(1, 1); +INSERT INTO test_hash VALUES(2, 2); +INSERT INTO test_hash VALUES(3, 3); +INSERT INTO test_hash VALUES(4, 4); + +alter table test_hash exchange partition (p1) with table t1 WITHOUT VALIDATION; + +alter table test_hash truncate partition p2; + + +CREATE TABLE interval_sales +( + prod_id NUMBER(6), + cust_id NUMBER, + time_id DATE, + channel_id CHAR(1), + promo_id NUMBER(6), + quantity_sold NUMBER(3), + amount_sold NUMBER(10, 2) +) + PARTITION BY RANGE (time_id) + INTERVAL + ('1 MONTH') +( + PARTITION p0 VALUES LESS THAN (TO_DATE('1-1-2008', 'DD-MM-YYYY')), + PARTITION p1 VALUES LESS THAN (TO_DATE('6-5-2008', 'DD-MM-YYYY')) +); + +alter table interval_sales split partition p0 at (to_date('2007-02-10', 'YYYY-MM-DD')) into (partition p0_1, partition p0_2); + +alter table interval_sales split partition p0_1 into (partition p0_1_1 values less than (TO_DATE('1-1-2005', 'DD-MM-YYYY')), partition p0_1_2 values less than(TO_DATE('1-1-2006', 'DD-MM-YYYY')) ); + +alter table interval_sales split partition p0_2 into (partition p0_2_1 START (TO_DATE('8-5-2007', 'DD-MM-YYYY'), partition p0_2_2 START (TO_DATE('9-5-2007', 'DD-MM-YYYY')); + + +insert into interval_sales +values (1, 1, to_date('9-2-2007', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales +values (1, 1, to_date('11-2-2007', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales +values (1, 1, to_date('11-2-2008', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales +values (1, 1, to_date('20-2-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales +values (1, 1, to_date('05-2-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales +values (1, 1, to_date('08-2-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales +values (1, 1, to_date('05-4-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales +values (1, 1, to_date('05-8-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales +values (1, 1, to_date('04-8-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales +values (1, 1, to_date('04-9-2008', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales +values (1, 1, to_date('04-11-2008', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales +values (1, 1, to_date('04-12-2008', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales +values (1, 1, to_date('04-01-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales +values (1, 1, to_date('04-5-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales +values (1, 1, to_date('04-6-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales +values (1, 1, to_date('04-7-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales +values (1, 1, to_date('04-8-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales +values (1, 1, to_date('04-9-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); + +alter table interval_sales merge partitions p0_1, p0_2, p1 into partition p01; +alter table interval_sales merge partitions sys_p6, sys_p7, sys_p8 into partition sys_p6_p7_p8; +ALTER TABLE interval_sales RESET PARTITION; + +CREATE TABLE interval_sales1 +( + prod_id NUMBER(6), + cust_id NUMBER, + time_id DATE, + channel_id CHAR(1), + promo_id NUMBER(6), + quantity_sold NUMBER(3), + amount_sold NUMBER(10, 2) +) + PARTITION BY RANGE (time_id) + INTERVAL +('1 MONTH') +(PARTITION p0 VALUES LESS THAN (TO_DATE('1-1-2008', 'DD-MM-YYYY')), + PARTITION p1 VALUES LESS THAN (TO_DATE('6-5-2008', 'DD-MM-YYYY')) +); +create index interval_sales1_time_id_idx on interval_sales1 (time_id) local; +create index interval_sales1_quantity_sold_idx on interval_sales1 (quantity_sold) local; +alter table interval_sales1 split partition p0 at (to_date('2007-02-10', 'YYYY-MM-DD')) into (partition p0_1, partition p0_2); + +insert into interval_sales1 +values (1, 1, to_date('9-2-2007', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales1 +values (1, 1, to_date('11-2-2007', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales1 +values (1, 1, to_date('11-2-2008', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales1 +values (1, 1, to_date('20-2-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales1 +values (1, 1, to_date('05-2-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales1 +values (1, 1, to_date('08-2-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales1 +values (1, 1, to_date('05-4-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales1 +values (1, 1, to_date('05-8-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales1 +values (1, 1, to_date('04-8-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales1 +values (1, 1, to_date('04-9-2008', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales1 +values (1, 1, to_date('04-11-2008', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales1 +values (1, 1, to_date('04-12-2008', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales1 +values (1, 1, to_date('04-01-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales1 +values (1, 1, to_date('04-5-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales1 +values (1, 1, to_date('04-6-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales1 +values (1, 1, to_date('04-7-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales1 +values (1, 1, to_date('04-8-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); +insert into interval_sales1 +values (1, 1, to_date('04-9-2009', 'DD-MM-YYYY'), 'a', 1, 1, 1); + +alter table interval_sales1 merge partitions p0_1, p0_2, p1 into partition p01 UPDATE GLOBAL INDEX; + + +CREATE TABLE range_range +( + month_code VARCHAR2 ( 30 ) NOT NULL , + dept_code VARCHAR2 ( 30 ) NOT NULL , + user_no VARCHAR2 ( 30 ) NOT NULL , + sales_amt int +) +PARTITION BY RANGE (month_code) SUBPARTITION BY RANGE (dept_code) +( + PARTITION p_201901 VALUES LESS THAN( '201903' ) + ( + SUBPARTITION p_201901_a VALUES LESS THAN( '2' ), + SUBPARTITION p_201901_b VALUES LESS THAN( MAXVALUE ) + ), + PARTITION p_201902 VALUES LESS THAN( '201904' ) + ( + SUBPARTITION p_201902_a VALUES LESS THAN( '2' ), + SUBPARTITION p_201902_b VALUES LESS THAN( '6' ) + ) +); +insert into range_range values('201902', '1', '1', 1); +insert into range_range values('201902', '2', '1', 1); +insert into range_range values('201902', '3', '1', 1); +insert into range_range values('201903', '1', '1', 1); +insert into range_range values('201903', '2', '1', 1); +insert into range_range values('201903', '5', '1', 1); + +alter table range_range split subpartition p_201901_b at (3) into +( + subpartition p_201901_c, + subpartition p_201901_d +); + +alter table range_range split subpartition p_201902_b at (3) into +( + subpartition p_201902_c, + subpartition p_201902_d +); + +CREATE TABLE list_list +( + month_code VARCHAR2 ( 30 ) NOT NULL , + dept_code VARCHAR2 ( 30 ) NOT NULL , + user_no VARCHAR2 ( 30 ) NOT NULL , + sales_amt int +) +PARTITION BY LIST (month_code) SUBPARTITION BY LIST (dept_code) +( + PARTITION p_201901 VALUES ( '201902' ) + ( + SUBPARTITION p_201901_a VALUES ( '1' ), + SUBPARTITION p_201901_b VALUES ( default ) + ), + PARTITION p_201902 VALUES ( '201903' ) + ( + SUBPARTITION p_201902_a VALUES ( '1' ), + SUBPARTITION p_201902_b VALUES ( default ) + ) +); +insert into list_list values('201902', '1', '1', 1); +insert into list_list values('201902', '2', '1', 1); +insert into list_list values('201902', '1', '1', 1); +insert into list_list values('201903', '1', '1', 1); +insert into list_list values('201903', '2', '1', 1); +insert into list_list values('201903', '3', '1', 1); + +alter table list_list split subpartition p_201901_b values (2) into +( + subpartition p_201901_b, + subpartition p_201901_c +); + +alter table list_list split subpartition p_201902_b values (2, 3) into +( + subpartition p_201902_b, + subpartition p_201902_c +); + + +CREATE TABLE range_sales +( + product_id INT4 NOT NULL, + customer_id INT4 PRIMARY KEY, + time_id DATE, + channel_id CHAR(1), + type_id INT4, + quantity_sold NUMERIC(3), + amount_sold NUMERIC(10,2) +) +PARTITION BY RANGE (time_id) +( + PARTITION time_2008 VALUES LESS THAN ('2009-01-01'), + PARTITION time_2009 VALUES LESS THAN ('2010-01-01'), + PARTITION time_2010 VALUES LESS THAN ('2011-01-01'), + PARTITION time_2011 VALUES LESS THAN ('2012-01-01') +); +CREATE INDEX range_sales_idx1 ON range_sales(product_id) LOCAL; +CREATE INDEX range_sales_idx2 ON range_sales(time_id) GLOBAL; +EXECUTE partition_get_partitionno('range_sales'); +ALTER TABLE range_sales ADD PARTITION time_default VALUES LESS THAN (MAXVALUE); +ALTER TABLE range_sales DROP PARTITION time_2008; +ALTER TABLE range_sales SPLIT PARTITION time_default AT ('2013-01-01') INTO (PARTITION time_2012, PARTITION time_default_temp); +ALTER TABLE range_sales RENAME PARTITION time_default_temp TO time_default; +ALTER TABLE range_sales SPLIT PARTITION time_default +INTO (PARTITION time_2013 VALUES LESS THAN ('2014-01-01'), + PARTITION time_2014 VALUES LESS THAN ('2015-01-01'), + PARTITION time_default_temp VALUES LESS THAN (MAXVALUE)); +ALTER TABLE range_sales MERGE PARTITIONS time_2009, time_2010 INTO PARTITION time_2010_old UPDATE GLOBAL INDEX; +ALTER TABLE range_sales TRUNCATE PARTITION time_2011 UPDATE GLOBAL INDEX; +ALTER TABLE range_sales disable row movement; +ALTER TABLE range_sales enable row movement; + +CREATE TABLE interval_sales2 +( + product_id INT4 NOT NULL, + customer_id INT4 PRIMARY KEY, + time_id DATE, + channel_id CHAR(1), + type_id INT4, + quantity_sold NUMERIC(3), + amount_sold NUMERIC(10,2)DEFAULT CHARACTER SET +) +PARTITION BY RANGE (time_id) INTERVAL ('1 year') +( + PARTITION time_2008 VALUES LESS THAN ('2009-01-01'), + PARTITION time_2009 VALUES LESS THAN ('2010-01-01'), + PARTITION time_2010 VALUES LESS THAN ('2011-01-01') +); +CREATE INDEX interval_sales2_idx1 ON interval_sales2(product_id) LOCAL; +CREATE INDEX interval_sales2_idx2 ON interval_sales2(time_id) GLOBAL; + +-- add/drop partition +INSERT INTO interval_sales2 VALUES (1,1,'2013-01-01','A',1,1,1); +INSERT INTO interval_sales2 VALUES (2,2,'2012-01-01','B',2,2,2); +ALTER TABLE interval_sales2 DROP PARTITION time_2008; + + +-- merge/split partition +ALTER TABLE interval_sales2 SPLIT PARTITION time_2009 AT ('2009-01-01') INTO (PARTITION time_2008, PARTITION time_2009_temp); +ALTER TABLE interval_sales2 RENAME PARTITION time_2009_temp TO time_2009; +ALTER TABLE interval_sales2 MERGE PARTITIONS time_2009, time_2010 INTO PARTITION time_2010_old UPDATE GLOBAL INDEX; + + +-- truncate partition with gpi +ALTER TABLE interval_sales2 TRUNCATE PARTITION time_2008 UPDATE GLOBAL INDEX; + + +--reset +ALTER TABLE interval_sales2 RESET PARTITION; +ALTER TABLE interval_sales2 disable row movement; + +create table unit_varchar(a1 varchar default '1', a2 varchar(2), a3 varchar(2 byte) default 'ye', a4 varchar(2 character) default '锟斤拷锟', a5 varchar(2 char) default '默锟斤拷'); +create table unit_varchar2(a1 varchar2 default '1', a2 varchar2(2) default 'ha', a3 varchar2(2 byte), a4 varchar2(2 character) default '锟斤拷锟', a5 varchar2(2 char) default '默锟斤拷'); +create table unit_char(a1 char default '1', a2 char(2) default 'ha', a3 char(2 byte) default 'ye', a4 char(2 character), a5 char(2 char) default '默锟斤拷'); +create table unit_nchar(a1 nchar default '1', a2 nchar(2) default 'ha', a3 nchar(2) default 'ye', a4 nchar(2) default '锟斤拷锟', a5 nchar(2)); +create table unit_nvarchar2(a1 nvarchar2 default '1', a2 nvarchar2(2) default 'ha', a3 nvarchar2(2) default 'ye', a4 nvarchar2(2) default '锟斤拷锟', a5 nvarchar2(2)); + +insert into unit_varchar (a1) values ('1111111111123锟斤拷锟秸达拷锟斤拷锟斤拷11111111111111111111111111111111锟斤拷锟斤拷锟斤拷锟秸达拷实锟斤拷实1'); +insert into unit_varchar (a2) values ('12 '); +-- exceed +insert into unit_varchar (a2) values ('锟斤拷'); +insert into unit_varchar (a3) values ('12 '); +-- exceed +insert into unit_varchar (a3) values ('锟斤拷'); +insert into unit_varchar (a4) values ('锟斤拷2 '); +-- exceed +insert into unit_varchar (a4) values ('锟斤拷23 '); +-- exceed +insert into unit_varchar (a4) values ('223 '); +insert into unit_varchar (a5) values ('锟斤拷2 '); +-- exceed +insert into unit_varchar (a5) values ('锟斤拷23 '); +-- exceed +insert into unit_varchar (a5) values ('223 '); +-- exceed +update unit_varchar set a2='锟斤拷 '; +update unit_varchar set a3='锟斤拷a '; +-- exceed +update unit_varchar set a5='锟斤拷锟斤拷锟斤拷'; +update unit_varchar set a5='锟斤拷锟斤拷'; +select * from unit_varchar; + +insert into unit_varchar2 (a1) values ('锟斤拷111111111123锟斤拷锟秸达拷锟斤拷锟斤拷11111111111111111111111111111111锟斤拷锟斤拷锟斤拷锟秸达拷实锟斤拷实1'); +insert into unit_varchar2 (a2) values ('12 '); +-- exceed +insert into unit_varchar2 (a2) values ('锟斤拷'); +insert into unit_varchar2 (a3) values ('12 '); +-- exceed +insert into unit_varchar2 (a3) values ('锟斤拷'); +insert into unit_varchar2 (a4) values ('锟斤拷2 '); +-- exceed +insert into unit_varchar2 (a4) values ('锟斤拷23 '); +-- exceed +insert into unit_varchar2 (a4) values ('223 '); +insert into unit_varchar2 (a5) values ('锟斤拷2 '); +-- exceed +insert into unit_varchar2 (a5) values ('锟斤拷23 '); +-- exceed +insert into unit_varchar2 (a5) values ('223 '); +ALTER TABLE unit_varchar2 ALTER COLUMN a2 SET data TYPE char(1 char) USING a2::char(1 char); +insert into unit_varchar2 (a2) values ('一 '); +alter table unit_varchar2 modify column a3 varchar2(2 char) default '锟节猴拷'; +-- exceed +insert into unit_varchar2 (a2) values ('一e'); +insert into unit_varchar2 (a1) values(default); +select * from unit_varchar2; + +-- exceed +insert into unit_char (a1) values ('1111111111123锟斤拷锟秸达拷锟斤拷锟斤拷11111111111111111111111111111111锟斤拷锟斤拷锟斤拷锟秸达拷实锟斤拷实1'); +-- exceed +insert into unit_nchar (a1) values ('锟斤拷 '); +insert into unit_nchar (a1) values ('1 '); +insert into unit_char (a2) values ('12 '); +-- exceed +insert into unit_char (a2) values ('锟斤拷'); +insert into unit_char (a3) values ('12 '); +-- exceed +insert into unit_char (a3) values ('锟斤拷'); +insert into unit_char (a4) values ('锟斤拷2 '); +-- exceed +insert into unit_char (a4) values ('锟斤拷23 '); +-- exceed +insert into unit_char (a4) values ('223 '); +insert into unit_char (a5) values ('锟斤拷2 '); +-- exceed +insert into unit_char (a5) values ('锟斤拷23 '); +-- exceed +insert into unit_char (a5) values ('223 '); +ALTER table unit_char ADD COLUMN a6 varchar(3 char) default '默锟斤拷值'; +insert into unit_char (a6) values ('锟斤拷1a '); +-- exceed +insert into unit_char (a6) values ('1234'); +update unit_char set a4='锟斤拷'; +-- execeed +update unit_char set a5='一锟斤拷3'; +select * from unit_char; + +-- exceed +insert into unit_nchar (a1) values ('1111111111123锟斤拷锟秸达拷锟斤拷锟斤拷11111111111111111111111111111111锟斤拷锟斤拷锟斤拷锟秸达拷实锟斤拷实1'); +insert into unit_nchar (a1) values ('锟斤拷 '); +insert into unit_nchar (a2) values ('锟斤拷锟斤拷 '); +-- exceed +insert into unit_nchar (a2) values ('123 '); +-- exceed +insert into unit_nchar (a2) values ('锟斤拷'); +insert into unit_nchar (a3) values ('12 '); +insert into unit_nchar (a3) values ('锟斤拷'); +insert into unit_nchar (a4) values ('锟斤拷2 '); +-- exceed +insert into unit_nchar (a4) values ('锟斤拷23 '); +-- exceed +insert into unit_nchar (a4) values ('223 '); +insert into unit_nchar (a5) values ('锟斤拷2 '); +-- exceed +insert into unit_nchar (a5) values ('锟斤拷23 '); +-- exceed +insert into unit_nchar (a5) values ('223 '); + +-- exceed +insert into unit_nvarchar2 (a1) values ('1111111111123锟斤拷锟秸达拷锟斤拷锟斤拷11111111111111111111111111111111锟斤拷锟斤拷锟斤拷锟秸达拷实锟斤拷实1'); +insert into unit_nvarchar2 (a1) values ('锟斤拷 '); +insert into unit_nvarchar2 (a2) values ('锟斤拷锟斤拷 '); +-- exceed +insert into unit_nvarchar2 (a2) values ('123 '); +-- exceed +insert into unit_nvarchar2 (a2) values ('锟斤拷'); +insert into unit_nvarchar2 (a3) values ('12 '); +insert into unit_nvarchar2 (a3) values ('锟斤拷'); +insert into unit_nvarchar2 (a4) values ('锟斤拷2 '); +insert into unit_nvarchar2 (a5) values ('锟斤拷2 '); +-- exceed +insert into unit_nvarchar2 (a5) values ('锟斤拷23 '); +-- exceed +insert into unit_nvarchar2 (a5) values ('223 '); + + + +create table test_char(col char(20 char)); +insert into test_char values ('锟斤拷锟斤拷一锟斤拷锟斤拷锟斤拷'), ('asd一锟斤拷锟斤拷锟斤拷锟斤拷bsd'), ('一锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟竭八撅拷十一锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟竭八撅拷十 '), ('一2 '); +select col, length(col), lengthb(col) from test_char; + +create table test_varchar(col varchar(20 char)); +insert into test_varchar values ('锟斤拷锟斤拷一锟斤拷锟斤拷锟斤拷'), ('asd一锟斤拷锟斤拷锟斤拷锟斤拷bsd'), ('一锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟竭八撅拷十一锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟竭八撅拷十 '), ('一2 '); +select col, length(col), lengthb(col) from test_varchar; + +create table test_charb(col char(20)); +insert into test_charb values ('锟斤拷锟斤拷一锟斤拷锟斤拷锟斤拷'), ('asd一锟斤拷锟斤拷锟斤拷锟斤拷bs '), ('一锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷 '), ('一2 '); +select col, length(col), lengthb(col) from test_charb; + +create table test_varcharb(col varchar(20)); +insert into test_varcharb values ('锟斤拷锟斤拷一锟斤拷锟斤拷锟斤拷'), ('asd一锟斤拷锟斤拷锟斤拷锟斤拷bs '), ('一锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷 '), ('一2 '); +select col, length(col), lengthb(col) from test_varcharb; \ No newline at end of file diff --git a/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_002.sql b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_002.sql new file mode 100644 index 000000000..53940da92 --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_002.sql @@ -0,0 +1,2011 @@ +-- +--FOR BLACKLIST FEATURE: REFERENCES/INHERITS/WITH OIDS/RULE/CREATE TYPE/DOMAIN is not supported. +-- + +-- +-- ALTER_TABLE +-- add attribute +-- + +CREATE TABLE atmp1 (initial int4); + +COMMENT ON TABLE tmp_wrong IS 'table comment'; +COMMENT ON TABLE atmp1 IS 'table comment'; +COMMENT ON TABLE atmp1 IS NULL; + +ALTER TABLE atmp1 ADD COLUMN xmin integer; -- fails + +ALTER TABLE atmp1 ADD COLUMN a int4 default 3; + +ALTER TABLE atmp1 ADD COLUMN b name; + +ALTER TABLE atmp1 ADD COLUMN c text; + +ALTER TABLE atmp1 ADD COLUMN d float8; + +ALTER TABLE atmp1 ADD COLUMN e float4; + +ALTER TABLE atmp1 ADD COLUMN f int2; + +ALTER TABLE atmp1 ADD COLUMN g polygon; + +ALTER TABLE atmp1 ADD COLUMN h abstime; + +ALTER TABLE atmp1 ADD COLUMN i char; + +ALTER TABLE atmp1 ADD COLUMN j abstime[]; + +ALTER TABLE atmp1 ADD COLUMN k int4; + +ALTER TABLE atmp1 ADD COLUMN l tid; + +ALTER TABLE atmp1 ADD COLUMN m xid; + +ALTER TABLE atmp1 ADD COLUMN n oidvector; + +--ALTER TABLE atmp1 ADD COLUMN o lock; +ALTER TABLE atmp1 ADD COLUMN p smgr; + +ALTER TABLE atmp1 ADD COLUMN q point; + +ALTER TABLE atmp1 ADD COLUMN r lseg; + +ALTER TABLE atmp1 ADD COLUMN s path; + +ALTER TABLE atmp1 ADD COLUMN t box; + +ALTER TABLE atmp1 ADD COLUMN u tinterval; + +ALTER TABLE atmp1 ADD COLUMN v timestamp; + +ALTER TABLE atmp1 ADD COLUMN w interval; + +ALTER TABLE atmp1 ADD COLUMN x float8[]; + +ALTER TABLE atmp1 ADD COLUMN y float4[]; + +ALTER TABLE atmp1 ADD COLUMN z int2[]; + +INSERT INTO atmp1 (a, b, c, d, e, f, g, h, i, j, k, l, m, n, p, q, r, s, t, u, + v, w, x, y, z) + VALUES (4, 'name', 'text', 4.1, 4.1, 2, '(4.1,4.1,3.1,3.1)', + 'Mon May 1 00:30:30 1995', 'c', '{Mon May 1 00:30:30 1995, Monday Aug 24 14:43:07 1992, epoch}', + 314159, '(1,1)', '512', + '1 2 3 4 5 6 7 8', 'magnetic disk', '(1.1,1.1)', '(4.1,4.1,3.1,3.1)', + '(0,2,4.1,4.1,3.1,3.1)', '(4.1,4.1,3.1,3.1)', '["epoch" "infinity"]', + 'epoch', '01:00:10', '{1.0,2.0,3.0,4.0}', '{1.0,2.0,3.0,4.0}', '{1,2,3,4}'); + +SELECT * FROM atmp1; + +----drop table tmp; + +-- the wolf bug - schema mods caused inconsistent row descriptors +CREATE TABLE atmp2 ( + initial int4 +); + +ALTER TABLE atmp2 ADD COLUMN a int4; + +ALTER TABLE atmp2 ADD COLUMN b name; + +ALTER TABLE atmp2 ADD COLUMN c text; + +ALTER TABLE atmp2 ADD COLUMN d float8; + +ALTER TABLE atmp2 ADD COLUMN e float4; + +ALTER TABLE atmp2 ADD COLUMN f int2; + +ALTER TABLE atmp2 ADD COLUMN g polygon; + +ALTER TABLE atmp2 ADD COLUMN h abstime; + +ALTER TABLE atmp2 ADD COLUMN i char; + +ALTER TABLE atmp2 ADD COLUMN j abstime[]; + +ALTER TABLE atmp2 ADD COLUMN k int4; + +ALTER TABLE atmp2 ADD COLUMN l tid; + +ALTER TABLE atmp2 ADD COLUMN m xid; + +ALTER TABLE atmp2 ADD COLUMN n oidvector; + +--ALTER TABLE atmp2 ADD COLUMN o lock; +ALTER TABLE atmp2 ADD COLUMN p smgr; + +ALTER TABLE atmp2 ADD COLUMN q point; + +ALTER TABLE atmp2 ADD COLUMN r lseg; + +ALTER TABLE atmp2 ADD COLUMN s path; + +ALTER TABLE atmp2 ADD COLUMN t box; + +ALTER TABLE atmp2 ADD COLUMN u tinterval; + +ALTER TABLE atmp2 ADD COLUMN v timestamp; + +ALTER TABLE atmp2 ADD COLUMN w interval; + +ALTER TABLE atmp2 ADD COLUMN x float8[]; + +ALTER TABLE atmp2 ADD COLUMN y float4[]; + +ALTER TABLE atmp2 ADD COLUMN z int2[]; + +INSERT INTO atmp2 (a, b, c, d, e, f, g, h, i, j, k, l, m, n, p, q, r, s, t, u, + v, w, x, y, z) + VALUES (4, 'name', 'text', 4.1, 4.1, 2, '(4.1,4.1,3.1,3.1)', + 'Mon May 1 00:30:30 1995', 'c', '{Mon May 1 00:30:30 1995, Monday Aug 24 14:43:07 1992, epoch}', + 314159, '(1,1)', '512', + '1 2 3 4 5 6 7 8', 'magnetic disk', '(1.1,1.1)', '(4.1,4.1,3.1,3.1)', + '(0,2,4.1,4.1,3.1,3.1)', '(4.1,4.1,3.1,3.1)', '["epoch" "infinity"]', + 'epoch', '01:00:10', '{1.0,2.0,3.0,4.0}', '{1.0,2.0,3.0,4.0}', '{1,2,3,4}'); + +SELECT * FROM atmp2; + +----drop table tmp; + + +-- +-- rename - check on both non-temp and temp tables +-- +CREATE TABLE atmp3 (regtable int); +-- Enforce use of COMMIT instead of 2PC for temporary objects +\set VERBOSITY verbose +-- CREATE TEMP TABLE tmp (tmptable int); + +ALTER TABLE atmp3 RENAME TO tmp_new; + +-- SELECT * FROM tmp; +-- SELECT * FROM tmp_new; + +-- ALTER TABLE tmp RENAME TO tmp_new2; + +SELECT * FROM tmp_new; +-- SELECT * FROM tmp_new2; + +----drop table tmp_new; +-- ----drop table tmp_new2; +CREATE TABLE atmp4 (ch1 character(1)); +insert into atmp4 values ('asdv'); +----drop table tmp; +\set VERBOSITY default + + +CREATE TABLE onek ( + unique1 int4, + unique2 int4, + two int4, + four int4, + ten int4, + twenty int4, + hundred int4, + thousand int4, + twothousand int4, + fivethous int4, + tenthous int4, + odd int4, + even int4, + stringu1 name, + stringu2 name, + string4 name +) with(autovacuum_enabled = off); +CREATE INDEX onek_unique1 ON onek USING btree(unique1 int4_ops); + +CREATE TABLE tenk1 ( + unique1 int4, + unique2 int4, + two int4, + four int4, + ten int4, + twenty int4, + hundred int4, + thousand int4, + twothousand int4, + fivethous int4, + tenthous int4, + odd int4, + even int4, + stringu1 name, + stringu2 name, + string4 name +) with(autovacuum_enabled = off); + +CREATE TABLE stud_emp ( + name text, + age int4, + location point, + salary int4, + manager name, + gpa float8, + percent int4 +) with(autovacuum_enabled = off); + +-- ALTER TABLE ... RENAME on non-table relations +-- renaming indexes (FIXME: this should probably test the index's functionality) +ALTER INDEX IF EXISTS __onek_unique1 RENAME TO tmp_onek_unique1; +ALTER INDEX IF EXISTS __tmp_onek_unique1 RENAME TO onek_unique1; + +ALTER INDEX onek_unique1 RENAME TO tmp_onek_unique1; +ALTER INDEX tmp_onek_unique1 RENAME TO onek_unique1; + +-- renaming views +CREATE VIEW tmp_view (unique1) AS SELECT unique1 FROM tenk1; +ALTER TABLE tmp_view RENAME TO tmp_view_new; + +-- hack to ensure we get an indexscan here +ANALYZE tenk1; +set enable_seqscan to off; +set enable_bitmapscan to off; +-- 5 values, sorted +SELECT unique1 FROM tenk1 WHERE unique1 < 5 ORDER BY unique1; +reset enable_seqscan; +reset enable_bitmapscan; + +DROP VIEW tmp_view_new; +-- toast-like relation name +alter table stud_emp rename to pg_toast_stud_emp; +alter table pg_toast_stud_emp rename to stud_emp; + +-- renaming index should rename constraint as well +ALTER TABLE onek ADD CONSTRAINT onek_unique1_constraint UNIQUE (unique1); +ALTER INDEX onek_unique1_constraint RENAME TO onek_unique1_constraint_foo; +ALTER TABLE onek DROP CONSTRAINT onek_unique1_constraint_foo; + +-- renaming constraint +ALTER TABLE onek ADD CONSTRAINT onek_check_constraint CHECK (unique1 >= 0); +ALTER TABLE onek RENAME CONSTRAINT onek_check_constraint TO onek_check_constraint_foo; +ALTER TABLE onek DROP CONSTRAINT onek_check_constraint_foo; + +-- renaming constraint should rename index as well +ALTER TABLE onek ADD CONSTRAINT onek_unique1_constraint UNIQUE (unique1); +DROP INDEX onek_unique1_constraint; -- to see whether it's there +ALTER TABLE onek RENAME CONSTRAINT onek_unique1_constraint TO onek_unique1_constraint_foo; +DROP INDEX onek_unique1_constraint_foo; -- to see whether it's there +ALTER TABLE onek DROP CONSTRAINT onek_unique1_constraint_foo; + +-- renaming constraints vs. inheritance +CREATE TABLE constraint_rename_test (a int CONSTRAINT con1 CHECK (a > 0), b int, c int); +\d constraint_rename_test +CREATE TABLE constraint_rename_test2 (a int CONSTRAINT con1 CHECK (a > 0), d int) INHERITS (constraint_rename_test); +create table constraint_rename_test2 (like constraint_rename_test ); +\d constraint_rename_test2 +ALTER TABLE constraint_rename_test2 RENAME CONSTRAINT con1 TO con1foo; -- fail +ALTER TABLE ONLY constraint_rename_test RENAME CONSTRAINT con1 TO con1foo; -- fail +ALTER TABLE constraint_rename_test RENAME CONSTRAINT con1 TO con1foo; -- ok +\d constraint_rename_test +\d constraint_rename_test2 +ALTER TABLE constraint_rename_test ADD CONSTRAINT con2 CHECK (b > 0) NO INHERIT; +ALTER TABLE ONLY constraint_rename_test RENAME CONSTRAINT con2 TO con2foo; -- ok +ALTER TABLE constraint_rename_test RENAME CONSTRAINT con2foo TO con2bar; -- ok +\d constraint_rename_test +\d constraint_rename_test2 +ALTER TABLE constraint_rename_test ADD CONSTRAINT con3 PRIMARY KEY (a); +ALTER TABLE constraint_rename_test RENAME CONSTRAINT con3 TO con3foo; -- ok +\d constraint_rename_test +\d constraint_rename_test2 +----drop table constraint_rename_test2; +----drop table constraint_rename_test; +ALTER TABLE IF EXISTS constraint_rename_test ADD CONSTRAINT con4 UNIQUE (a); + +-- FOREIGN KEY CONSTRAINT adding TEST + +CREATE TABLE tmp2 (a int primary key); + +CREATE TABLE tmp3 (a int, b int); + +CREATE TABLE tmp4 (a int, b int, unique(a,b)); + +CREATE TABLE tmp5 (a int, b int); + +-- Insert rows into tmp2 (pktable) +INSERT INTO tmp2 values (1); +INSERT INTO tmp2 values (2); +INSERT INTO tmp2 values (3); +INSERT INTO tmp2 values (4); + +-- Insert rows into tmp3 +INSERT INTO tmp3 values (1,10); +INSERT INTO tmp3 values (1,20); +INSERT INTO tmp3 values (5,50); + +-- Try (and fail) to add constraint due to invalid source columns +ALTER TABLE tmp3 add constraint tmpconstr foreign key(c) references tmp2 match full; + +-- Try (and fail) to add constraint due to invalide destination columns explicitly given +ALTER TABLE tmp3 add constraint tmpconstr foreign key(a) references tmp2(b) match full; + +-- Try (and fail) to add constraint due to invalid data +ALTER TABLE tmp3 add constraint tmpconstr foreign key (a) references tmp2 match full; + +-- Delete failing row +alter table tmp3 replica identity full; +DELETE FROM tmp3 where a=5; + +-- Try (and succeed) +ALTER TABLE tmp3 add constraint tmpconstr foreign key (a) references tmp2 match full; +ALTER TABLE tmp3 drop constraint tmpconstr; + +INSERT INTO tmp3 values (5,50); + +-- Try NOT VALID and then VALIDATE CONSTRAINT, but fails. Delete failure then re-validate +ALTER TABLE tmp3 add constraint tmpconstr foreign key (a) references tmp2 match full NOT VALID; +ALTER TABLE tmp3 validate constraint tmpconstr; + +-- Delete failing row +DELETE FROM tmp3 where a=5; + +-- Try (and succeed) and repeat to show it works on already valid constraint +ALTER TABLE tmp3 validate constraint tmpconstr; +ALTER TABLE tmp3 validate constraint tmpconstr; + +-- Try a non-verified CHECK constraint +ALTER TABLE tmp3 ADD CONSTRAINT b_greater_than_ten CHECK (b > 10); -- fail +ALTER TABLE tmp3 ADD CONSTRAINT b_greater_than_ten CHECK (b > 10) NOT VALID; -- succeeds +ALTER TABLE tmp3 VALIDATE CONSTRAINT b_greater_than_ten; -- fails +DELETE FROM tmp3 WHERE NOT b > 10; +ALTER TABLE tmp3 VALIDATE CONSTRAINT b_greater_than_ten; -- succeeds +ALTER TABLE tmp3 VALIDATE CONSTRAINT b_greater_than_ten; -- succeeds + +-- Test inherited NOT VALID CHECK constraints +select * from tmp3; + +-- Try (and fail) to create constraint from tmp5(a) to tmp4(a) - unique constraint on +-- tmp4 is a,b + +ALTER TABLE tmp5 add constraint tmpconstr foreign key(a) references tmp4(a) match full; + +----drop table tmp5; + +----drop table tmp4; + +----drop table tmp3; + +----drop table tmp2; + +-- NOT VALID with plan invalidation -- ensure we don't use a constraint for +-- exclusion until validated +set constraint_exclusion TO 'partition'; +create table nv_parent (d date); +create table nv_child_2010 () inherits (nv_parent); +create table nv_child_2010 (like nv_parent); +create table nv_child_2011 () inherits (nv_parent); +create table nv_child_2011 (like nv_parent including all); +alter table nv_child_2010 add check (d between '2010-01-01'::date and '2010-12-31'::date) not valid; +alter table nv_child_2011 add check (d between '2011-01-01'::date and '2011-12-31'::date) not valid; +explain (costs off) select * from nv_parent where d between '2011-08-01' and '2011-08-31'; +create table nv_child_2009 (check (d between '2009-01-01'::date and '2009-12-31'::date)) inherits (nv_parent); +explain (costs off) select * from nv_parent where d between '2011-08-01'::date and '2011-08-31'::date; +explain (costs off) select * from nv_parent where d between '2009-08-01'::date and '2009-08-31'::date; +-- after validation, the constraint should be used +alter table nv_child_2011 VALIDATE CONSTRAINT nv_child_2011_d_check; +explain (costs off) select * from nv_parent where d between '2009-08-01'::date and '2009-08-31'::date; + + +-- Foreign key adding test with mixed types + +-- Note: these tables are TEMP to avoid name conflicts when this test +-- is run in parallel with foreign_key.sql. + +CREATE TABLE PKTABLE (ptest1 int PRIMARY KEY); +INSERT INTO PKTABLE VALUES(42); +CREATE TABLE FKTABLE (ftest1 inet); +-- This next should fail, because int=inet does not exist +ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references pktable; +-- This should also fail for the same reason, but here we +-- give the column name +ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references pktable(ptest1); +----drop table FKTABLE; +-- This should succeed, even though they are different types, +-- because int=int8 exists and is a member of the integer opfamily +CREATE TABLE FKTABLE1 (ftest1 int8); +ALTER TABLE FKTABLE1 ADD FOREIGN KEY(ftest1) references pktable; +-- Check it actually works +INSERT INTO FKTABLE1 VALUES(42); -- should succeed +INSERT INTO FKTABLE1 VALUES(43); -- should fail +----drop table FKTABLE; +-- This should fail, because we'd have to cast numeric to int which is +-- not an implicit coercion (or use numeric=numeric, but that's not part +-- of the integer opfamily) +CREATE TABLE FKTABLE2 (ftest1 numeric); +ALTER TABLE FKTABLE2 ADD FOREIGN KEY(ftest1) references pktable; +----drop table FKTABLE; +----drop table PKTABLE; +-- On the other hand, this should work because int implicitly promotes to +-- numeric, and we allow promotion on the FK side +CREATE TABLE PKTABLE1 (ptest1 numeric PRIMARY KEY); +INSERT INTO PKTABLE1 VALUES(42); +CREATE TABLE FKTABLE3 (ftest1 int); +ALTER TABLE FKTABLE3 ADD FOREIGN KEY(ftest1) references pktable1; +-- Check it actually works +INSERT INTO FKTABLE3 VALUES(42); -- should succeed +INSERT INTO FKTABLE3 VALUES(43); -- should fail +----drop table FKTABLE; +----drop table PKTABLE; + +CREATE TABLE PKTABLE2 (ptest1 int, ptest2 inet, + PRIMARY KEY(ptest1, ptest2)); +-- This should fail, because we just chose really odd types +CREATE TABLE FKTABLE4 (ftest1 cidr, ftest2 timestamp); +ALTER TABLE FKTABLE4 ADD FOREIGN KEY(ftest1, ftest2) references pktable2; +----drop table FKTABLE; +-- Again, so should this... +CREATE TABLE FKTABLE5 (ftest1 cidr, ftest2 timestamp); +ALTER TABLE FKTABLE5 ADD FOREIGN KEY(ftest1, ftest2) + references pktable2(ptest1, ptest2); +----drop table FKTABLE; +-- This fails because we mixed up the column ordering +CREATE TABLE FKTABLE6 (ftest1 int, ftest2 inet); +ALTER TABLE FKTABLE6 ADD FOREIGN KEY(ftest1, ftest2) + references pktable2(ptest2, ptest1); +-- As does this... +ALTER TABLE FKTABLE6 ADD FOREIGN KEY(ftest2, ftest1) + references pktable2(ptest1, ptest2); + +-- temp tables should go away by themselves, need not drop them. + +-- test check constraint adding + +create table at1acc1 ( test int ); +-- add a check constraint +alter table at1acc1 add constraint at1acc_test1 check (test>3); +-- should fail +insert into at1acc1 (test) values (2); +-- should succeed +insert into at1acc1 (test) values (4); +----drop table atacc1; + +-- let's do one where the check fails when added +create table at2acc1 ( test int ); +-- insert a soon to be failing row +insert into at2acc1 (test) values (2); +-- add a check constraint (fails) +alter table at2acc1 add constraint at2acc_test1 check (test>3); +insert into at2acc1 (test) values (4); +----drop table atacc1; + +-- let's do one where the check fails because the column doesn't exist +create table at3acc1 ( test int ); +-- add a check constraint (fails) +alter table at3acc1 add constraint at3acc_test1 check (test1>3); +----drop table atacc1; + +-- something a little more complicated +create table at4acc1 ( test int, test2 int, test3 int); +-- add a check constraint (fails) +alter table at4acc1 add constraint at4acc_test1 check (test+test23), test2 int); +alter table at5acc1 add check (test2>test); +-- should fail for $2 +insert into at5acc1 (test2, test) values (3, 4); +----drop table atacc1; + +-- inheritance related tests +create table at6acc1 (test int); +create table at6acc2 (test2 int); +create table at6acc3 (test3 int) inherits (at6acc1, at6acc2); +alter table at6acc2 add constraint foo check (test2>0); +-- fail and then succeed on atacc2 +insert into at6acc2 (test2) values (-3); +insert into at6acc2 (test2) values (3); +-- fail and then succeed on atacc3 +insert into at6acc3 (test2) values (-3); +insert into at6acc3 (test2) values (3); +----drop table atacc3; +----drop table atacc2; +----drop table atacc1; + +-- same things with one created with INHERIT +create table at7acc1 (test int); +create table at7acc2 (test2 int); +create table at7acc3 (test3 int) inherits (at7acc1, at7acc2); +alter table at7acc3 no inherit at7acc2; +-- fail +alter table at7acc3 no inherit at7acc2; +-- make sure it really isn't a child +insert into at7acc3 (test2) values (3); +select test2 from atacc2; +-- fail due to missing constraint +alter table at7acc2 add constraint foo check (test2>0); +alter table at7acc3 inherit atacc2; +-- fail due to missing column +alter table at7acc3 rename test2 to testx; +alter table at7acc3 inherit atacc2; +-- fail due to mismatched data type +alter table at7acc3 add test2 bool; +alter table at7acc3 inherit atacc2; +alter table at7acc3 drop test2; +-- succeed +alter table at7acc3 add test2 int; +alter table at7acc3 replica identity full; +update at7acc3 set test2 = 4 where test2 is null; +alter table at7acc3 add constraint foo check (test2>0); +alter table at7acc3 inherit at7acc2; +-- fail due to duplicates and circular inheritance +alter table at7acc3 inherit at7acc2; +alter table at7acc2 inherit at7acc3; +alter table at7acc2 inherit at7acc2; +-- test that we really are a child now (should see 4 not 3 and cascade should go through) +select test2 from at7acc2; +----drop table atacc2 cascade; +----drop table atacc1; + +-- adding only to a parent is allowed as of 9.2 + +create table at8acc1 (test int); +create table at8acc2 (test2 int) inherits (at8acc1); +-- ok: +alter table at8acc1 add constraint foo check (test>0) no inherit; +-- check constraint is not there on child +insert into at8acc2 (test) values (-3); +-- check constraint is there on parent +insert into at8acc1 (test) values (-3); +insert into at8acc1 (test) values (3); +-- fail, violating row: +alter table at8acc2 add constraint foo check (test>0) no inherit; +----drop table atacc2; +----drop table atacc1; + +-- test unique constraint adding + +create table at9acc1 ( test int ) with oids; +-- add a unique constraint +alter table at9acc1 add constraint at9acc_test1 unique (test); +-- insert first value +insert into at9acc1 (test) values (2); +-- should fail +insert into at9acc1 (test) values (2); +-- should succeed +insert into at9acc1 (test) values (4); +-- try adding a unique oid constraint +alter table at9acc1 add constraint atacc_oid1 unique(oid); +-- try to create duplicates via alter table using - should fail +alter table at9acc1 alter column test type integer using 0; +----drop table atacc1; + +-- let's do one where the unique constraint fails when added +create table a1tacc1 ( test int ); +-- insert soon to be failing rows +insert into a1tacc1 (test) values (2); +insert into a1tacc1 (test) values (2); +-- add a unique constraint (fails) +alter table a1tacc1 add constraint a1tacc_test1 unique (test); +insert into a1tacc1 (test) values (3); +--drop table atacc1; + +-- let's do one where the unique constraint fails +-- because the column doesn't exist +create table a2tacc1 ( test int ); +-- add a unique constraint (fails) +alter table a2tacc1 add constraint a2tacc_test1 unique (test1); +--drop table atacc1; + +-- something a little more complicated +create table a2tacc1 ( test int, test2 int); +-- add a unique constraint +alter table a2tacc1 add constraint a2tacc_test1 unique (test, test2); +-- insert initial value +insert into a2tacc1 (test,test2) values (4,4); +-- should fail +insert into a2tacc1 (test,test2) values (4,4); +-- should all succeed +insert into a2tacc1 (test,test2) values (4,5); +insert into a2tacc1 (test,test2) values (5,4); +insert into a2tacc1 (test,test2) values (5,5); +--drop table atacc1; + +-- lets do some naming tests +create table a3tacc1 (test int, test2 int, unique(test)); +alter table a3tacc1 add unique (test2); +-- should fail for @@ second one @@ +insert into a3tacc1 (test2, test) values (3, 3); +insert into a3tacc1 (test2, test) values (2, 3); +--drop table atacc1; + +-- test primary key constraint adding + +create table a4tacc1 ( test int ) with oids; +-- add a primary key constraint +alter table a4tacc1 add constraint a4tacc_test1 primary key (test); +-- insert first value +insert into a4tacc1 (test) values (2); +-- should fail +insert into a4tacc1 (test) values (2); +-- should succeed +insert into a4tacc1 (test) values (4); +-- inserting NULL should fail +insert into a4tacc1 (test) values(NULL); +-- try adding a second primary key (should fail) +alter table a4tacc1 add constraint atacc_oid1 primary key(oid); +-- drop first primary key constraint +alter table a4tacc1 drop constraint a4tacc_test1 restrict; +-- try adding a primary key on oid (should succeed) +alter table a4tacc1 add constraint atacc_oid1 primary key(oid); +--drop table a4tacc1; + +-- let's do one where the primary key constraint fails when added +create table a5tacc1 ( test int ); +-- insert soon to be failing rows +insert into a5tacc1 (test) values (2); +insert into a5tacc1 (test) values (2); +-- add a primary key (fails) +alter table a5tacc1 add constraint a5tacc_test1 primary key (test); +insert into a5tacc1 (test) values (3); +--drop table a5tacc1; + +-- let's do another one where the primary key constraint fails when added +create table a6tacc1 ( test int ); +-- insert soon to be failing row +insert into a6tacc1 (test) values (NULL); +-- add a primary key (fails) +alter table a6tacc1 add constraint a6tacc_test1 primary key (test); +insert into a6tacc1 (test) values (3); +--drop table atacc1; + +-- let's do one where the primary key constraint fails +-- because the column doesn't exist +create table a7tacc1 ( test int ); +-- add a primary key constraint (fails) +alter table a7tacc1 add constraint a7tacc_test1 primary key (test1); +--drop table atacc1; + +-- adding a new column as primary key to a non-empty table. +-- should fail unless the column has a non-null default value. +create table a8tacc1 ( test int ); +insert into a8tacc1 (test) values (0); +-- add a primary key column without a default (fails). +alter table a8tacc1 add column test2 int primary key; +-- now add a primary key column with a default (succeeds). +alter table a8tacc1 add column test2 int default 0 primary key; +--drop table atacc1; + +-- something a little more complicated +create table a9tacc1 ( test int, test2 int); +-- add a primary key constraint +alter table a9tacc1 add constraint a9tacc_test1 primary key (test, test2); +-- try adding a second primary key - should fail +alter table a9tacc1 add constraint atacc_test2 primary key (test); +-- insert initial value +insert into a9tacc1 (test,test2) values (4,4); +-- should fail +insert into a9tacc1 (test,test2) values (4,4); +insert into a9tacc1 (test,test2) values (NULL,3); +insert into a9tacc1 (test,test2) values (3, NULL); +insert into a9tacc1 (test,test2) values (NULL,NULL); +-- should all succeed +insert into a9tacc1 (test,test2) values (4,5); +insert into a9tacc1 (test,test2) values (5,4); +insert into a9tacc1 (test,test2) values (5,5); +--drop table atacc1; + +-- lets do some naming tests +create table at10acc1 (test int, test2 int, primary key(test)); +-- only first should succeed +insert into at10acc1 (test2, test) values (3, 3); +insert into at10acc1 (test2, test) values (2, 3); +insert into at10acc1 (test2, test) values (1, NULL); +--drop table atacc1; + +-- alter table modify not null +-- try altering syscatlog should fail +alter table pg_class modify (relname not null enable); +alter table pg_class modify relname not null enable; +-- try altering non-existent table should fail +alter table non_existent modify (bar not null enable); +-- test alter table +create table test_modify (a int, b int); +alter table test_modify replica identity full; +alter table test_modify modify (b not null enable); +insert into test_modify(b) values (null); +insert into test_modify values (1, null); +alter table test_modify modify(b null); +insert into test_modify values (1, null); +alter table test_modify modify (b not null enable); +alter table test_modify replica identity full; +delete from test_modify; +alter table test_modify modify (a not null, b not null); +insert into test_modify values (1,null); +insert into test_modify values (null,1); +alter table test_modify modify (a null, b null); +insert into test_modify values (1,null); +insert into test_modify values (null,1); +alter table test_modify modify (b constraint ak not null); +delete from test_modify; +alter table test_modify modify (b constraint ak not null); +insert into test_modify values(1,1); +insert into test_modify values(1,null); +alter table test_modify modify (b constraint ak null); +insert into test_modify values(1,null); +alter table test_modify modify (a null, a not null); +-- try alter view should fail +create view test_modify_view as select * from test_modify; +alter table test_modify_view modify (a not null enable); +drop view test_modify_view; +--drop table test_modify; + +-- alter table / alter column [set/drop] not null tests +-- try altering system catalogs, should fail +alter table pg_class alter column relname drop not null; +alter table pg_class alter relname set not null; + +-- try altering non-existent table, should fail +alter table non_existent alter column bar set not null; +alter table non_existent alter column bar drop not null; + +-- test setting columns to null and not null and vice versa +-- test checking for null values and primary key +create table at11acc1 (test int not null) with oids; +alter table at11acc1 add constraint "atacc1_pkey" primary key (test); +alter table at11acc1 alter column test drop not null; +alter table at11acc1 drop constraint "atacc1_pkey"; +alter table at11acc1 alter column test drop not null; +insert into at11acc1 values (null); +alter table at11acc1 alter test set not null; +atler table at11acc1 replica identity full; +delete from at11acc1; +alter table at11acc1 alter test set not null; + +-- try altering a non-existent column, should fail +alter table at11acc1 alter bar set not null; +alter table at11acc1 alter bar drop not null; + +-- try altering the oid column, should fail +alter table at11acc1 alter oid set not null; +alter table at11acc1 alter oid drop not null; + +-- try creating a view and altering that, should fail +create view myview as select * from at11acc1; +alter table myview alter column test drop not null; +alter table myview alter column test set not null; +drop view myview; + +--drop table atacc1; + +-- test inheritance +create table parent (a int); +create table child1 (b varchar(255)) inherits (parent); +create table child1 (like parent); +alter table child1 add column (b varchar(255)); + +alter table parent alter a set not null; +insert into parent values (NULL); +insert into child1 (a, b) values (NULL, 'foo'); +alter table parent alter a drop not null; +insert into parent values (NULL); +insert into child1 (a, b) values (NULL, 'foo'); +alter table only parent alter a set not null; +alter table child1 alter a set not null; +alter table parent replica identity full; +alter table child1 replica identity full; +delete from parent; +alter table only parent alter a set not null; +insert into parent values (NULL); +alter table child1 alter a set not null; +insert into child1 (a, b) values (NULL, 'foo'); +delete from child1; +alter table child1 alter a set not null; +insert into child1 (a, b) values (NULL, 'foo'); +--drop table child; +--drop table parent; + +-- test setting and removing default values +create table def_test ( + c1 int4 default 5, + c2 text default 'initial_default' +); +insert into def_test default values; +alter table def_test alter column c1 drop default; +insert into def_test default values; +alter table def_test alter column c2 drop default; +insert into def_test default values; +alter table def_test alter column c1 set default 10; +alter table def_test alter column c2 set default 'new_default'; +insert into def_test default values; +select * from def_test order by 1, 2; + +-- set defaults to an incorrect type: this should fail +alter table def_test alter column c1 set default 'wrong_datatype'; +alter table def_test alter column c2 set default 20; + +-- set defaults on a non-existent column: this should fail +alter table def_test alter column c3 set default 30; + +-- set defaults on views: we need to create a view, add a rule +-- to allow insertions into it, and then alter the view to add +-- a default +create view def_view_test as select * from def_test; +create rule def_view_test_ins as + on insert to def_view_test + do instead insert into def_test select new.*; +insert into def_view_test default values; +alter table def_view_test alter column c1 set default 45; +insert into def_view_test default values; +alter table def_view_test alter column c2 set default 'view_default'; +insert into def_view_test default values; +select * from def_view_test order by 1, 2; + +drop rule def_view_test_ins on def_view_test; +drop view def_view_test; +--drop table def_test; + +-- alter table / drop column tests +-- try altering system catalogs, should fail +alter table pg_class drop column relname; + +-- try altering non-existent table, should fail +alter table nosuchtable drop column bar; + +-- test dropping columns +create table at12acc1 (a int4 not null, b int4, c int4 not null, d int4) with oids; +insert into at12acc1 values (1, 2, 3, 4); +alter table at12acc1 drop a; +alter table at12acc1 drop a; + +-- SELECTs +select * from at12acc1; +select * from at12acc1 order by a; +select * from at12acc1 order by "........pg.dropped.1........"; +select * from at12acc1 group by a; +select * from at12acc1 group by "........pg.dropped.1........"; +select at12acc1.* from at12acc1; +select a from at12acc1; +select at12acc1.a from at12acc1; +select b,c,d from at12acc1; +select a,b,c,d from at12acc1; +select * from at12acc1 where a = 1; +select "........pg.dropped.1........" from at12acc1; +select at12acc1."........pg.dropped.1........" from at12acc1; +select "........pg.dropped.1........",b,c,d from at12acc1; +select * from at12acc1 where "........pg.dropped.1........" = 1; +alter table at12acc1 replica identity full; +-- UPDATEs +update at12acc1 set a = 3; +update at12acc1 set b = 2 where a = 3; +update at12acc1 set "........pg.dropped.1........" = 3; +update at12acc1 set b = 2 where "........pg.dropped.1........" = 3; + +-- INSERTs +insert into at12acc1 values (10, 11, 12, 13); +insert into at12acc1 values (default, 11, 12, 13); +insert into at12acc1 values (11, 12, 13); +insert into at12acc1 (a) values (10); +insert into at12acc1 (a) values (default); +insert into at12acc1 (a,b,c,d) values (10,11,12,13); +insert into at12acc1 (a,b,c,d) values (default,11,12,13); +insert into at12acc1 (b,c,d) values (11,12,13); +insert into at12acc1 ("........pg.dropped.1........") values (10); +insert into at12acc1 ("........pg.dropped.1........") values (default); +insert into at12acc1 ("........pg.dropped.1........",b,c,d) values (10,11,12,13); +insert into at12acc1 ("........pg.dropped.1........",b,c,d) values (default,11,12,13); + +-- DELETEs +alter table at12acc1 replica identity full; +delete from at12acc1 where a = 3; +delete from at12acc1 where "........pg.dropped.1........" = 3; +delete from at12acc1; + +-- try dropping a non-existent column, should fail +alter table at12acc1 drop bar; + +-- try dropping the oid column, should succeed +alter table at12acc1 drop oid; + +-- try dropping the xmin column, should fail +alter table at12acc1 drop xmin; + +-- try creating a view and altering that, should fail +create view myview as select * from at12acc1; +select * from myview; +alter table myview drop d; +drop view myview; + +-- test some commands to make sure they fail on the dropped column +analyze at12acc1(a); +analyze at12acc1("........pg.dropped.1........"); +vacuum analyze at12acc1(a); +vacuum analyze at12acc1("........pg.dropped.1........"); +comment on column at12acc1.a is 'testing'; +comment on column at12acc1."........pg.dropped.1........" is 'testing'; +alter table at12acc1 alter a set storage plain; +alter table at12acc1 alter "........pg.dropped.1........" set storage plain; +alter table at12acc1 alter a set statistics 0; +alter table at12acc1 alter "........pg.dropped.1........" set statistics 0; +alter table at12acc1 alter a set default 3; +alter table at12acc1 alter "........pg.dropped.1........" set default 3; +alter table at12acc1 alter a drop default; +alter table at12acc1 alter "........pg.dropped.1........" drop default; +alter table at12acc1 alter a set not null; +alter table at12acc1 alter "........pg.dropped.1........" set not null; +alter table at12acc1 alter a drop not null; +alter table at12acc1 alter "........pg.dropped.1........" drop not null; +alter table at12acc1 rename a to x; +alter table at12acc1 rename "........pg.dropped.1........" to x; +alter table at12acc1 add primary key(a); +alter table at12acc1 add primary key("........pg.dropped.1........"); +alter table at12acc1 add unique(a); +alter table at12acc1 add unique("........pg.dropped.1........"); +alter table at12acc1 add check (a > 3); +alter table at12acc1 add check ("........pg.dropped.1........" > 3); +create table atacc2 (id int4 unique); +alter table at12acc1 add foreign key (a) references atacc2(id); +alter table at12acc1 add foreign key ("........pg.dropped.1........") references atacc2(id); +alter table atacc2 add foreign key (id) references at12acc1(a); +alter table atacc2 add foreign key (id) references at12acc1("........pg.dropped.1........"); +--drop table atacc2; +create index "testing_idx" on at12acc1(a); +create index "testing_idx" on at12acc1("........pg.dropped.1........"); + +-- test create as and select into +insert into at12acc1 values (21, 22, 23); +create table test1 as select * from at12acc1; +select * from test1; +--drop table test1; +select * into test2 from at12acc1; +select * from test2; +--drop table test2; + +-- try dropping all columns +alter table at12acc1 drop c; +alter table at12acc1 drop d; +alter table at12acc1 drop b; +select * from at12acc1; + +--drop table atacc1; +-- test constraint error reporting in presence of dropped columns +create table at13acc1 (id serial primary key, value int check (value < 10)); +insert into at13acc1(value) values (100); +alter table at13acc1 drop column value; +alter table at13acc1 add column value int check (value < 10); +insert into at13acc1(value) values (100); +insert into at13acc1(id, value) values (null, 0); +alter table at13acc1 alter column id set default 10; +drop sequence at13acc1_id_seq; + +-- test inheritance +create table parent (a int, b int, c int); +insert into parent values (1, 2, 3); +alter table parent drop a; +create table child (d varchar(255)) inherits (parent); +create table child2 as select * from parent; +alter table child2 add column d varchar(255); +insert into child2 values (12, 13, 'testing'); + +select * from parent order by b; +select * from child2; +alter table parent drop c; +select * from parent order by b; +select * from child2; + +--drop table child; +--drop table parent; + +-- test copy in/out +create table test (a int4, b int4, c int4); +insert into test values (1,2,3); +alter table test drop a; +copy test to stdout; +copy test(a) to stdout; +copy test("........pg.dropped.1........") to stdout; +copy test from stdin; +10 11 12 +\. +select * from test order by b; +copy test from stdin; +21 22 +\. +select * from test order by b; +copy test(a) from stdin; +copy test("........pg.dropped.1........") from stdin; +copy test(b,c) from stdin; +31 32 +\. +select * from test order by b; +--drop table test; + +-- test inheritance + +create table dropColumn (a int, b int, e int); +create table dropColumnChild (c int) inherits (dropColumn); +select * into dropColumnChild from dropColumn; +alter table dropColumnChild add column c int; +create table dropColumnAnother (d int) inherits (dropColumnChild); +select * into dropColumnAnother from dropColumnChild; +alter table dropColumnAnother add column d int; +-- these two should fail +alter table dropColumnchild drop column a; +alter table only dropColumnChild drop column b; + + + +-- these three should work +alter table only dropColumn drop column e; +alter table dropColumnChild drop column c; +alter table dropColumn drop column a; + +create table renameColumn (a int); +create table renameColumnChild (b int) inherits (renameColumn); +create table renameColumnChild as select * from renameColumn; +create table renameColumnAnother (c int) inherits (renameColumnChild); +select * into renameColumnAnother from renameColumnChild; +alter table renameColumnAnother add column b int; + +-- these three should fail +alter table renameColumnChild rename column a to d; +alter table only renameColumnChild rename column a to d; +alter table only renameColumn rename column a to d; + +-- these should work +alter table renameColumn rename column a to d; +alter table renameColumnChild rename column b to a; + +-- these should work +alter table if exists doesnt_exist_tab rename column a to d; +alter table if exists doesnt_exist_tab rename column b to a; + +-- this should work +alter table renameColumn add column w int; + +-- this should fail +alter table only renameColumn add column x int; + + +-- Test corner cases in dropping of inherited columns + +create table p1 (f1 int, f2 int); +create table c1 (f1 int not null) inherits(p1); +create table c1 (like p1); +-- should be rejected since c1.f1 is inherited +alter table c1 drop column f1; +-- should work +alter table p1 drop column f1; +-- c1.f1 is still there, but no longer inherited +select f1 from c1; +alter table c1 drop column f1; +select f1 from c1; + +--drop table p1 cascade; + +create table p11 (f1 int, f2 int); +create table c11 () inherits(p11); +create table c11 (like p11); +-- should be rejected since c1.f1 is inherited +alter table c11 drop column f1; +alter table p11 drop column f1; +-- c1.f1 is dropped now, since there is no local definition for it +select f1 from c11; + +--drop table p1 cascade; + +create table p12 (f1 int, f2 int); +create table c12 () inherits(p12); +create table c12 as select * from p12; +-- should be rejected since c1.f1 is inherited +alter table c12 drop column f1; +alter table only p1 drop column f1; +-- c1.f1 is NOT dropped, but must now be considered non-inherited +alter table c12 drop column f1; + +--drop table p1 cascade; + +create table p13 (f1 int, f2 int); +create table c13 (f1 int not null) inherits(p1); +create table c13 as select * from p13; +-- should be rejected since c1.f1 is inherited +alter table c13 drop column f1; +alter table only p13 drop column f1; +-- c1.f1 is still there, but no longer inherited +alter table c13 drop column f1; + +--drop table p1 cascade; + +create table p14(id int, name text); +create table p24(id2 int, name text, height int); +create table c14(age int) inherits(p1,p2); +create table c14 as select * from p1,p2; +alter table c14 add column age int; +create table gc1() inherits (c14); +select * into gc1 from c14; + +select relname, attname, attinhcount, attislocal +from pg_class join pg_attribute on (pg_class.oid = pg_attribute.attrelid) +where relname in ('p1','p2','c1','gc1') and attnum > 0 and not attisdropped +order by relname, attnum; + +-- should work +alter table only p14 drop column name; +-- should work. Now c1.name is local and inhcount is 0. +alter table p24 drop column name; +-- should be rejected since its inherited +alter table gc1 drop column name; +-- should work, and drop gc1.name along +alter table c14 drop column name; +-- should fail: column does not exist +alter table gc1 drop column name; +-- should work and drop the attribute in all tables +alter table p24 drop column height; + +select relname, attname, attinhcount, attislocal +from pg_class join pg_attribute on (pg_class.oid = pg_attribute.attrelid) +where relname in ('p1','p2','c1','gc1') and attnum > 0 and not attisdropped +order by relname, attnum; + +--drop table p1, p2 cascade; + +-- +-- Test the ALTER TABLE SET WITH/WITHOUT OIDS command +-- +create table altstartwith (col integer) with oids; + +insert into altstartwith values (1); + +select oid > 0, * from altstartwith; + +alter table altstartwith set without oids; + +select oid > 0, * from altstartwith; -- fails +select * from altstartwith; + +alter table altstartwith set with oids; + +select oid > 0, * from altstartwith; + +--drop table altstartwith; + +-- Check inheritance cases +create table altwithoid (col integer) with oids; + +-- Inherits parents oid column anyway +create table altinhoid () inherits (altwithoid) without oids; + +insert into altinhoid values (1); + +select oid > 0, * from altwithoid; +select oid > 0, * from altinhoid; + +alter table altwithoid set without oids; + +select oid > 0, * from altwithoid; -- fails +select oid > 0, * from altinhoid; -- fails +select * from altwithoid; +select * from altinhoid; + +alter table altwithoid set with oids; + +select oid > 0, * from altwithoid; +select oid > 0, * from altinhoid; + +--drop table altwithoid cascade; + +create table altwithoid1 (col integer) without oids; + +-- child can have local oid column +create table altinhoid1 () inherits (altwithoid1) with oids; + +insert into altinhoid1 values (1); + +select oid > 0, * from altwithoid1; -- fails +select oid > 0, * from altinhoid1; + +alter table altwithoid1 set with oids; + +select oid > 0, * from altwithoid1; +select oid > 0, * from altinhoid1; + +-- the child's local definition should remain +alter table altwithoid1 set without oids; + +select oid > 0, * from altwithoid1; -- fails +select oid > 0, * from altinhoid1; + +--drop table altwithoid cascade; + +-- test renumbering of child-table columns in inherited operations + +create table p15 (f1 int); +create table c15 (f2 text, f3 int) inherits (p1); +create table c15 as select * from p15; +alter table c15 add column f2 text, add column f3 int; +alter table p15 add column a1 int check (a1 > 0); +alter table p15 add column f2 text; + +insert into p15 values (1,2,'abc'); +insert into c15 values(11,'xyz',33,0); -- should fail +insert into c15 values(11,'xyz',33,22); + +select * from p15 order by f1; +alter table p15 replica identity full; +update p15 set a1 = a1 + 1, f2 = upper(f2); +select * from p15 order by f1; + +--drop table p1 cascade; + +-- test that operations with a dropped column do not try to reference +-- its datatype + +-- create domain mytype as text; +create type mytype as (a text); +create table foo (f1 text, f2 mytype, f3 text); + +insert into foo values('bb','cc','dd'); +select * from foo order by f1; + +-- drop domain mytype cascade; + +select * from foo order by f1; +insert into foo values('qq','rr'); +select * from foo order by f1; +alter table foo replica identity full; +update foo set f3 = 'zz'; +select * from foo order by f1; +select f3,max(f1) from foo group by f3; + +-- Simple tests for alter table column type +alter table foo replica identity full; +delete from foo where f1 = 'qq'; +alter table foo alter f1 TYPE integer; -- fails +alter table foo alter f1 TYPE varchar(10); +--drop table foo; + +create table anothertab (atcol1 serial8, atcol2 boolean, + constraint anothertab_chk check (atcol1 <= 3));; + +insert into anothertab (atcol1, atcol2) values (default, true); +insert into anothertab (atcol1, atcol2) values (default, false); +select * from anothertab order by atcol1, atcol2; + +alter table anothertab alter column atcol1 type boolean; -- we could support this cast +alter table anothertab alter column atcol1 type integer; + +select * from anothertab order by atcol1, atcol2; + +insert into anothertab (atcol1, atcol2) values (45, null); -- fails +insert into anothertab (atcol1, atcol2) values (default, null); + +select * from anothertab order by atcol1, atcol2; + +alter table anothertab alter column atcol2 type text + using case when atcol2 is true then 'IT WAS TRUE' + when atcol2 is false then 'IT WAS FALSE' + else 'IT WAS NULL!' end; + +select * from anothertab order by atcol1, atcol2; +alter table anothertab alter column atcol1 type boolean + using case when atcol1 % 2 = 0 then true else false end; -- fails +alter table anothertab alter column atcol1 drop default; +alter table anothertab alter column atcol1 type boolean + using case when atcol1 % 2 = 0 then true else false end; -- fails +alter table anothertab drop constraint anothertab_chk; +alter table anothertab drop constraint anothertab_chk; -- fails +alter table anothertab drop constraint IF EXISTS anothertab_chk; -- succeeds + +alter table anothertab alter column atcol1 type boolean + using case when atcol1 % 2 = 0 then true else false end; + +select * from anothertab order by atcol1, atcol2; + +--drop table anothertab; +-- alter table anothertab alter column atcol1 default false; +drop sequence anothertab_atcol1_seq; + +create table another (f1 int, f2 text);; + +insert into another values(1, 'one'); +insert into another values(2, 'two'); +insert into another values(3, 'three'); + +select * from another order by f1, f2; + +alter table another + alter f1 type text using f2 || ' more', + alter f2 type bigint using f1 * 10; + +select * from another order by f1, f2; + +--drop table another; + +-- table's row type +create table tab1 (a int, b text); +create table tab2 (x int, y tab1); +alter table tab1 alter column b type varchar; -- fails + +-- disallow recursive containment of row types +-- create table recur1 (f1 int); +-- alter table recur1 add column f2 recur1; -- fails +-- alter table recur1 add column f2 recur1[]; -- fails +-- create domain array_of_recur1 as recur1[]; +-- alter table recur1 add column f2 array_of_recur1; -- fails +-- create table recur2 (f1 int, f2 recur1); +-- alter table recur1 add column f2 recur2; -- fails +-- alter table recur1 add column f2 int; +-- alter table recur1 alter column f2 type recur2; -- fails + +-- SET STORAGE may need to add a TOAST table +create table test_storage (a text); +alter table test_storage alter a set storage plain; +alter table test_storage add b int default 0; -- rewrite table to remove its TOAST table +alter table test_storage alter a set storage extended; -- re-add TOAST table + +select reltoastrelid <> 0 as has_toast_table +from pg_class +where oid = 'test_storage'::regclass; + +-- ALTER TYPE with a check constraint and a child table (bug before Nov 2012) +CREATE TABLE test_inh_check (a float check (a > 10.2)); +CREATE TABLE test_inh_check_child() INHERITS(test_inh_check); +ALTER TABLE test_inh_check ALTER COLUMN a TYPE numeric; +\d test_inh_check +\d test_inh_check_child + +-- +-- lock levels +-- +drop type lockmodes; +create type lockmodes as enum ( + 'AccessShareLock' +,'RowShareLock' +,'RowExclusiveLock' +,'ShareUpdateExclusiveLock' +,'ShareLock' +,'ShareRowExclusiveLock' +,'ExclusiveLock' +,'AccessExclusiveLock' +); + +drop view my_locks; +create or replace view my_locks as +select case when c.relname like 'pg_toast%' then 'pg_toast' else c.relname end, max(mode::lockmodes) as max_lockmode +from pg_locks l join pg_class c on l.relation = c.oid +where virtualtransaction = ( + select virtualtransaction + from pg_locks + where transactionid = txid_current()::integer) +and locktype = 'relation' +and relnamespace != (select oid from pg_namespace where nspname = 'pg_catalog') +and c.relname != 'my_locks' +group by c.relname; + +create table alterlock (f1 int primary key, f2 text); + +start transaction; alter table alterlock alter column f2 set statistics 150; +select * from my_locks order by 1; +rollback; + +start transaction; alter table alterlock cluster on alterlock_pkey; +select * from my_locks order by 1; +commit; + +start transaction; alter table alterlock set without cluster; +select * from my_locks order by 1; +commit; + +start transaction; alter table alterlock set (fillfactor = 100); +select * from my_locks order by 1; +commit; + +start transaction; alter table alterlock reset (fillfactor); +select * from my_locks order by 1; +commit; + +start transaction; alter table alterlock set (toast.autovacuum_enabled = off); +select * from my_locks order by 1; +commit; + +start transaction; alter table alterlock set (autovacuum_enabled = off); +select * from my_locks order by 1; +commit; + +start transaction; alter table alterlock alter column f2 set (n_distinct = 1); +select * from my_locks order by 1; +rollback; + +start transaction; alter table alterlock alter column f2 set storage extended; +select * from my_locks order by 1; +rollback; + +start transaction; alter table alterlock alter column f2 set default 'x'; +select * from my_locks order by 1; +rollback; + +-- cleanup +--drop table alterlock; +drop view my_locks; +-- drop type lockmodes; + +-- +-- --alter function +-- +--create function test_strict(text) returns text as + 'select coalesce($1, ''got passed a null'');' + language sql returns null on null input; +select test_strict(NULL); +--alter function test_strict(text) called on null input; +select test_strict(NULL); + +--create function non_strict(text) returns text as + 'select coalesce($1, ''got passed a null'');' + language sql called on null input; +select non_strict(NULL); +--alter function non_strict(text) returns null on null input; +select non_strict(NULL); + +-- +-- alter object set schema +-- + +create schema alter1; +create schema alter2; + +-- cannot move table into system built-in schema +create table test1(a int); +alter table test1 set schema dbms_random; +alter table test1 set schema utl_file; + +create table alter1.t1(f1 serial primary key, f2 int check (f2 > 0)); + +create view alter1.v1 as select * from alter1.t1; + +-- --create function alter1.plus1(int) returns int as 'select $1+1' language sql; + +-- create domain alter1.posint integer check (value > 0); + +create type alter1.ctype as (f1 int, f2 text); + +--create function alter1.same(alter1.ctype, alter1.ctype) returns boolean language sql +as 'select $1.f1 is not distinct from $2.f1 and $1.f2 is not distinct from $2.f2'; + +--create operator alter1.=(procedure = alter1.same, leftarg = alter1.ctype, rightarg = alter1.ctype); + +--create operator class alter1.ctype_hash_ops default for type alter1.ctype using hash as + -- operator 1 alter1.=(alter1.ctype, alter1.ctype); + +-- create conversion alter1.ascii_to_utf8 for 'sql_ascii' to 'utf8' from ascii_to_utf8; + +--create text search parser alter1.prs(start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype); +--create text search configuration alter1.cfg(parser = alter1.prs); +--create text search template alter1.tmpl(init = dsimple_init, lexize = dsimple_lexize); +--create text search dictionary alter1.dict(template = alter1.tmpl); + +insert into alter1.t1(f2) values(11); +insert into alter1.t1(f2) values(12); + +alter table alter1.t1 set schema alter2; +alter table alter1.v1 set schema alter2; +--alter function alter1.plus1(int) set schema alter2; +-- alter domain alter1.posint set schema alter2; +--alter operator class alter1.ctype_hash_ops using hash set schema alter2; +--alter operator family alter1.ctype_hash_ops using hash set schema alter2; +--alter operator alter1.=(alter1.ctype, alter1.ctype) set schema alter2; +--alter function alter1.same(alter1.ctype, alter1.ctype) set schema alter2; +alter type alter1.ctype set schema alter2; +--alter conversion alter1.ascii_to_utf8 set schema alter2; +--alter text search parser alter1.prs set schema alter2; +--alter text search configuration alter1.cfg set schema alter2; +--alter text search template alter1.tmpl set schema alter2; +--alter text search dictionary alter1.dict set schema alter2; + +-- this should succeed because nothing is left in alter1 +-- drop schema alter1; + +insert into alter2.t1(f2) values(13); +insert into alter2.t1(f2) values(14); + +select * from alter2.t1 order by f1, f2; + +alter table alter1.t1 alter column f1 drop default; +drop sequence alter1.t1_f1_seq; + +select * from alter2.v1 order by f1, f2; +drop view alter2.v1; + +select alter2.plus1(41); + +-- clean up +-- drop schema alter2 cascade; +-- drop schema alter1 cascade; + +-- +-- composite types +-- + +CREATE TYPE test_type AS (a int); +\d test_type + +ALTER TYPE nosuchtype ADD ATTRIBUTE b text; -- fails + +ALTER TYPE test_type ADD ATTRIBUTE b text; +\d test_type + +ALTER TYPE test_type ADD ATTRIBUTE b text; -- fails + +ALTER TYPE test_type ALTER ATTRIBUTE b SET DATA TYPE varchar; +\d test_type + +ALTER TYPE test_type ALTER ATTRIBUTE b SET DATA TYPE integer; +\d test_type + +ALTER TYPE test_type DROP ATTRIBUTE b; +\d test_type + +ALTER TYPE test_type DROP ATTRIBUTE c; -- fails + +ALTER TYPE test_type DROP ATTRIBUTE IF EXISTS c; + +ALTER TYPE test_type DROP ATTRIBUTE a, ADD ATTRIBUTE d boolean; +\d test_type + +ALTER TYPE test_type RENAME ATTRIBUTE a TO aa; +ALTER TYPE test_type RENAME ATTRIBUTE d TO dd; +\d test_type + +-- DROP TYPE test_type; + +CREATE TYPE test_type1 AS (a int, b text); +CREATE TABLE test_tbl1 (x int, y test_type1); +ALTER TYPE test_type1 ALTER ATTRIBUTE b TYPE varchar; -- fails + +CREATE TYPE test_type2 AS (a int, b text); +-- CREATE TABLE test_tbl2 OF test_type2; +CREATE TABLE test_tbl2_subclass () INHERITS (test_tbl2); +\d test_type2 +\d test_tbl2 + +ALTER TYPE test_type2 ADD ATTRIBUTE c text; -- fails +ALTER TYPE test_type2 ADD ATTRIBUTE c text CASCADE; +\d test_type2 +\d test_tbl2 + +ALTER TYPE test_type2 ALTER ATTRIBUTE b TYPE varchar; -- fails +ALTER TYPE test_type2 ALTER ATTRIBUTE b TYPE varchar CASCADE; +\d test_type2 +\d test_tbl2 + +ALTER TYPE test_type2 DROP ATTRIBUTE b; -- fails +ALTER TYPE test_type2 DROP ATTRIBUTE b CASCADE; +\d test_type2 +\d test_tbl2 + +ALTER TYPE test_type2 RENAME ATTRIBUTE a TO aa; -- fails +ALTER TYPE test_type2 RENAME ATTRIBUTE a TO aa CASCADE; +\d test_type2 +\d test_tbl2 +\d test_tbl2_subclass + +--drop table test_tbl2_subclass; + +-- This test isn't that interesting on its own, but the purpose is to leave +-- behind a table to test pg_upgrade with. The table has a composite type +-- column in it, and the composite type has a dropped attribute. +CREATE TYPE test_type3 AS (a int); +CREATE TABLE test_tbl3 (c) AS SELECT '(1)'::test_type3; +ALTER TYPE test_type3 DROP ATTRIBUTE a, ADD ATTRIBUTE b int; + +CREATE TYPE test_type_empty AS (); + +-- +-- typed tables: OF / NOT OF +-- + +CREATE TYPE tt_t0 AS (z inet, x int, y numeric(8,2)); +ALTER TYPE tt_t0 DROP ATTRIBUTE z; +CREATE TABLE tt0 (x int NOT NULL, y numeric(8,2)); -- OK +CREATE TABLE tt1 (x int, y bigint); -- wrong base type +CREATE TABLE tt2 (x int, y numeric(9,2)); -- wrong typmod +CREATE TABLE tt3 (y numeric(8,2), x int); -- wrong column order +CREATE TABLE tt4 (x int); -- too few columns +CREATE TABLE tt5 (x int, y numeric(8,2), z int); -- too few columns +CREATE TABLE tt6 () INHERITS (tt0); -- can't have a parent +CREATE TABLE tt7 (x int, q text, y numeric(8,2)) WITH OIDS; +ALTER TABLE tt7 DROP q; -- OK + +ALTER TABLE tt0 OF tt_t0; +ALTER TABLE tt1 OF tt_t0; +ALTER TABLE tt2 OF tt_t0; +ALTER TABLE tt3 OF tt_t0; +ALTER TABLE tt4 OF tt_t0; +ALTER TABLE tt5 OF tt_t0; +ALTER TABLE tt6 OF tt_t0; +ALTER TABLE tt7 OF tt_t0; + +CREATE TYPE tt_t1 AS (x int, y numeric(8,2)); +ALTER TABLE tt7 OF tt_t1; -- reassign an already-typed table +ALTER TABLE tt7 NOT OF; +\d tt7 +drop table tt0; +-- make sure we can drop a constraint on the parent but it remains on the child +CREATE TABLE test_drop_constr_parent (c text CHECK (c IS NOT NULL)); +CREATE TABLE test_drop_constr_child () INHERITS (test_drop_constr_parent); +ALTER TABLE ONLY test_drop_constr_parent DROP CONSTRAINT "test_drop_constr_parent_c_check"; +-- should fail +INSERT INTO test_drop_constr_child (c) VALUES (NULL); +--drop table test_drop_constr_parent CASCADE; + +-- +-- IF EXISTS test +-- +ALTER TABLE IF EXISTS tt8 ADD COLUMN f int; +ALTER TABLE IF EXISTS tt8 ADD CONSTRAINT xxx PRIMARY KEY(f); +ALTER TABLE IF EXISTS tt8 ADD CHECK (f BETWEEN 0 AND 10); +ALTER TABLE IF EXISTS tt8 ALTER COLUMN f SET DEFAULT 0; +ALTER TABLE IF EXISTS tt8 RENAME COLUMN f TO f1; +ALTER TABLE IF EXISTS tt8 SET SCHEMA alter2; + +CREATE TABLE tt8(a int); +CREATE SCHEMA alter2; + +ALTER TABLE IF EXISTS tt8 ADD COLUMN f int; +ALTER TABLE IF EXISTS tt8 ADD CONSTRAINT xxx PRIMARY KEY(f); +ALTER TABLE IF EXISTS tt8 ADD CHECK (f BETWEEN 0 AND 10); +ALTER TABLE IF EXISTS tt8 ALTER COLUMN f SET DEFAULT 0; +ALTER TABLE IF EXISTS tt8 RENAME COLUMN f TO f1; +ALTER TABLE IF EXISTS tt8 SET SCHEMA alter2; + +\d alter2.tt8 + +--drop table alter2.tt8; +DROP SCHEMA alter2; +--custom script +--create table +CREATE TABLE TBL_DOMAIN +( + IDOMAINID NUMBER(10) NOT NULL, + SDOMAINNAME VARCHAR2(30) NOT NULL +); +--create/recreate primary, unique and foreign key constraints +ALTER TABLE TBL_DOMAIN + ADD CONSTRAINT PK_TBL_DOMAIN PRIMARY KEY (IDOMAINID) + USING INDEX ; + +ALTER TABLE TBL_DOMAIN + ADD CONSTRAINT IX_TBL_DOMAIN UNIQUE (SDOMAINNAME) + USING INDEX ; +\d+ TBL_DOMAIN +--drop table TBL_DOMAIN; + +--create table +CREATE TABLE TBL_CM_MAXTSENDTOHOST +( + I_MODULETYPE NUMBER(38) NOT NULL, + I_MODULENO NUMBER(38) NOT NULL, + I_PLAMODULENO NUMBER(38) NOT NULL, + I_TABLEID NUMBER(38) NOT NULL, + I_OLDMAXTUPLE NUMBER(38) NOT NULL, + I_NEWMAXTUPLE NUMBER(38) NOT NULL, + I_RESERVED1 NUMBER(38) DEFAULT 0, + I_RESERVED2 NUMBER(38) DEFAULT 0, + I_RESERVED3 NUMBER(38) DEFAULT 0, + I_RESERVED4 NUMBER(38) DEFAULT 0, + I_RESERVED5 NUMBER(38) DEFAULT 0, + I_RESERVED6 NUMBER(38) DEFAULT 0, + I_RESERVED7 NUMBER(38) DEFAULT 0, + SV_RESERVED8 VARCHAR2(32) DEFAULT '', + SV_RESERVED9 VARCHAR2(32) DEFAULT '', + SV_RESERVED10 VARCHAR2(32) DEFAULT '' +) + PCTFREE 10 + INITRANS 1 + MAXTRANS 255 + STORAGE + ( + INITIAL 64K + MINEXTENTS 1 + MAXEXTENTS UNLIMITED + ) + ; +--add primary key +ALTER TABLE TBL_CM_MAXTSENDTOHOST + ADD PRIMARY KEY (I_PLAMODULENO, I_TABLEID) + USING INDEX + PCTFREE 10 + INITRANS 2 + MAXTRANS 255 + STORAGE + ( + INITIAL 64K + MINEXTENTS 1 + MAXEXTENTS UNLIMITED + ); + \d+ TBL_CM_MAXTSENDTOHOST + --drop table TBL_CM_MAXTSENDTOHOST; + +--create table +CREATE TABLE TBL_LICCTRLDESC_DEFAULT +( + I_INDEX NUMBER(38) NOT NULL, + SV_FEATURENAME VARCHAR2(64) NOT NULL, + SV_ITEMNAME VARCHAR2(64) NOT NULL, + I_ITEMTYPE NUMBER(38) NOT NULL, + I_ITEMVALUEMIN NUMBER(38) NOT NULL, + I_ITEMVALUEMAX NUMBER(38) NOT NULL, + I_RESERVED1 NUMBER(38) DEFAULT 0, + I_RESERVED2 NUMBER(38) DEFAULT 0, + I_RESERVED3 NUMBER(38) DEFAULT 0, + I_RESERVED4 NUMBER(38) DEFAULT 0, + I_RESERVED5 NUMBER(38) DEFAULT 0, + I_RESERVED6 NUMBER(38) DEFAULT 0, + I_RESERVED7 NUMBER(38) DEFAULT 0, + SV_RESERVED8 VARCHAR2(32) DEFAULT '', + SV_RESERVED9 VARCHAR2(32) DEFAULT '', + SV_RESERVED10 VARCHAR2(32) DEFAULT '', + I_STATUS NUMBER(38) NOT NULL +) + PCTFREE 10 + INITRANS 1 + MAXTRANS 255 + STORAGE + ( + INITIAL 64K + MINEXTENTS 1 + MAXEXTENTS UNLIMITED + ) + ; +--add primary key +ALTER TABLE TBL_LICCTRLDESC_DEFAULT + ADD PRIMARY KEY (I_INDEX) + USING INDEX + PCTFREE 10 + INITRANS 2 + MAXTRANS 255 + STORAGE + ( + INITIAL 64K + MINEXTENTS 1 + MAXEXTENTS UNLIMITED + ); +--add unique index +CREATE UNIQUE INDEX IDX_TBL_LICCTRL_DEF ON TBL_LICCTRLDESC_DEFAULT (I_INDEX DESC, I_STATUS) + PCTFREE 10 + INITRANS 2 + MAXTRANS 255 + STORAGE + ( + INITIAL 64K + MINEXTENTS 1 + MAXEXTENTS UNLIMITED + ); +\d+ TBL_LICCTRLDESC_DEFAULT + --drop table TBL_LICCTRLDESC_DEFAULT; +--using index clause +CREATE TABLE STUDENTS +( + ID INT, + NAME VARCHAR2(20), + AGE INT, + ADDRESS VARCHAR(30) +); + --alter table to add unique index or primary key +ALTER TABLE STUDENTS ADD UNIQUE (ID) +USING INDEX +PCTFREE 10 +INITRANS 2 +MAXTRANS 255 +STORAGE +( + INITIAL 64K + MINEXTENTS 1 + MAXEXTENTS UNLIMITED +); + +ALTER TABLE STUDENTS ADD CONSTRAINT ZHANGYG UNIQUE (AGE, ADDRESS) +USING INDEX +PCTFREE 10 +INITRANS 2 +MAXTRANS 255 +STORAGE +( + INITIAL 64K + MINEXTENTS 1 + MAXEXTENTS UNLIMITED +); + +ALTER TABLE STUDENTS ADD PRIMARY KEY (AGE) +USING INDEX +PCTFREE 10 +INITRANS 2 +MAXTRANS 255 +STORAGE +( + INITIAL 64K + MINEXTENTS 1 + MAXEXTENTS UNLIMITED +); +\d+ STUDENTS +--drop table STUDENTS; +--simulate A db's ALTER TABLE gram +CREATE TABLE MODIFY_TABLE_A(I INTEGER); +ALTER TABLE MODIFY_TABLE_A ADD (mychar CHAR); +ALTER TABLE MODIFY_TABLE_A ADD (myint1 INT, mychar1 CHAR); +ALTER TABLE MODIFY_TABLE_A ADD (myint2 INT, mychar2 CHAR, mychar3 CHAR); +ALTER TABLE MODIFY_TABLE_A ADD a CHAR, ADD b CHAR; +\d MODIFY_TABLE_A +ALTER TABLE MODIFY_TABLE_A ADD mychar4 CHAR; +\d MODIFY_TABLE_A +ALTER TABLE MODIFY_TABLE_A MODIFY I VARCHAR2(64); +\d MODIFY_TABLE_A +ALTER TABLE MODIFY_TABLE_A MODIFY I CHAR, MODIFY myint1 CHAR; +\d MODIFY_TABLE_A +ALTER TABLE MODIFY_TABLE_A MODIFY (myint1 VARCHAR(12)); +\d MODIFY_TABLE_A +ALTER TABLE MODIFY_TABLE_A MODIFY (myint1 VARCHAR(13), mychar1 INT); +\d MODIFY_TABLE_A +ALTER TABLE MODIFY_TABLE_A MODIFY (myint1 VARCHAR(13), myint1 INT); +--drop table MODIFY_TABLE_A; + +create table test_alter_type(a int,b text); +alter table test_alter_type alter column a type regclass; +--drop table test_alter_type; + +create table test_mod(a int,b text); +alter table test_mod alter column a type regclass; +alter table test_mod alter column a set default "d"; +alter table test_mod alter column a set default "d"::int; +alter table test_mod alter column a set default "d"::int + 1; +--drop table test_mod; + +--simulate A db and postgresql, ALTER TABLE IF EXISTS table_name ADD( { element_list_clause } [, ...] ) +--simulate A db and postgresql, ALTER TABLE IF EXISTS table_name MODIFY( { element_list_clause } [, ...] ) +create schema columnar_storage; +create table columnar_storage.create_columnar_add_common_008 (c_tinyint tinyint,c_smallint smallint,c_int integer,c_bigint bigint,c_money money,c_numeric numeric,c_real real,c_double double precision,c_decimal decimal,c_varchar varchar,c_char char(30),c_nvarchar2 nvarchar2,c_text text,c_timestamp timestamp with time zone,c_timestamptz timestamp without time zone,c_date date,c_time time without time zone,c_timetz time with time zone,c_interval interval,c_tinterval tinterval,c_smalldatetime smalldatetime,c_bytea bytea,c_boolean boolean,c_inet inet,c_cidr cidr,c_bit bit(10),c_varbit varbit(10),c_oid oid) with (orientation=column); +alter table if exists columnar_storage.create_columnar_add_common_007 modify (c_int varchar(20)); +alter table if exists columnar_storage.create_columnar_add_common_008 modify (c_int varchar(20), c_double varchar(20)); +select * from columnar_storage.create_columnar_add_common_008; +--drop table columnar_storage.create_columnar_add_common_008; +create table columnar_storage.create_columnar_add_common_008 (c_tinyint tinyint,c_smallint smallint,c_int integer,c_bigint bigint,c_money money,c_numeric numeric,c_real real,c_double double precision,c_decimal decimal,c_varchar varchar,c_char char(30),c_nvarchar2 nvarchar2,c_text text,c_timestamp timestamp with time zone,c_timestamptz timestamp without time zone,c_date date,c_time time without time zone,c_timetz time with time zone,c_interval interval,c_tinterval tinterval,c_smalldatetime smalldatetime,c_bytea bytea,c_boolean boolean,c_inet inet,c_cidr cidr,c_bit bit(10),c_varbit varbit(10),c_oid oid) with (orientation=column); +alter table if exists columnar_storage.create_columnar_add_common_007 add (c_time_008 time without time zone,c_timetz_008 time with time zone); +alter table if exists columnar_storage.create_columnar_add_common_008 add (c_time_008 time without time zone,c_timetz_008 time with time zone); +select * from columnar_storage.create_columnar_add_common_008; +--drop table columnar_storage.create_columnar_add_common_008; +drop schema columnar_storage cascade; + +create table test_drop_column_1 (a int, b int, c int); +create table test_drop_column_2 (a int, b int); +create table test_drop_column_3 (a int, b int); +alter table test_drop_column_1 drop column c; +explain (verbose true, costs false) insert into test_drop_column_1 select * from test_drop_column_2; +insert into test_drop_column_1 select * from test_drop_column_2; +explain (verbose true, costs false) insert into test_drop_column_1 select * from test_drop_column_2 order by 2; +insert into test_drop_column_1 select * from test_drop_column_2 order by 2; +explain (verbose true, costs false) insert into test_drop_column_1 select test_drop_column_2.a, test_drop_column_3.a from test_drop_column_2, test_drop_column_3 where test_drop_column_2.a = test_drop_column_3.a; +insert into test_drop_column_1 select test_drop_column_2.a, test_drop_column_3.a from test_drop_column_2, test_drop_column_3 where test_drop_column_2.a = test_drop_column_3.a; +explain (verbose true, costs false) insert into test_drop_column_1 select test_drop_column_2.a, test_drop_column_3.a from test_drop_column_2, test_drop_column_3 where test_drop_column_2.a = test_drop_column_3.b; +insert into test_drop_column_1 select test_drop_column_2.a, test_drop_column_3.a from test_drop_column_2, test_drop_column_3 where test_drop_column_2.a = test_drop_column_3.b; +explain (verbose true, costs false) insert into test_drop_column_1 select test_drop_column_2.a, test_drop_column_3.a from test_drop_column_2, test_drop_column_3 where test_drop_column_2.a = test_drop_column_3.b order by 1, 2; +insert into test_drop_column_1 select test_drop_column_2.a, test_drop_column_3.a from test_drop_column_2, test_drop_column_3 where test_drop_column_2.a = test_drop_column_3.b order by 1, 2; +alter table test_drop_column2 replica identity full; +explain (verbose true, costs false) update test_drop_column_1 set a=test_drop_column_2.a from test_drop_column_2; +update test_drop_column_1 set a=test_drop_column_2.a from test_drop_column_2; +explain (verbose true, costs false) delete from test_drop_column_1 where a in (select a from test_drop_column_2); +alter table test_drop_column_1 replica identity full; +delete from test_drop_column_1 where a in (select a from test_drop_column_2); + +create table test_drop_column_cstore_1 (a int, b int, c int) with (orientation = column); +create table test_drop_column_cstore_2 (a int, b int) with (orientation = column); +create table test_drop_column_cstore_3 (a int) with (orientation = column); +alter table test_drop_column_cstore_1 drop column c; +insert into test_drop_column_cstore_1 select * from test_drop_column_cstore_2; +insert into test_drop_column_cstore_1 select * from test_drop_column_cstore_2 order by 2; +insert into test_drop_column_cstore_1 select test_drop_column_cstore_2.a, test_drop_column_cstore_3.a from test_drop_column_cstore_2, test_drop_column_cstore_3 where test_drop_column_cstore_2.a = test_drop_column_cstore_3.a; + +drop table test_drop_column_1; +drop table test_drop_column_2; +drop table test_drop_column_3; +drop table test_drop_column_cstore_1; +drop table test_drop_column_cstore_2; +drop table test_drop_column_cstore_3; + +create table test_hash (a int, b int); +create sequence test_seq1; +alter table test_hash alter column a type serial; --fail +alter table test_hash alter column a set default nextval('test_seq1'); +insert into test_hash(b) values(generate_series(1,10)); +alter table test_hash add column c serial; --not supported +alter table test_hash add column d int default nextval('test_seq1'); --not supported +alter table test_hash add column e int default nextval('test_seq1')*10; --not supported +--drop table test_hash; +alter table test_hash alter column a drop default; +drop sequence test_seq1; + +-- check column addition within a view (bug #14876) +create table at_base_table(id int, stuff text); +insert into at_base_table values (23, 'skidoo'); +create view at_view_1 as select * from at_base_table bt; +create view at_view_2 as select *, v1 as j from at_view_1 v1; +\d+ at_view_1 +\d+ at_view_2 +explain (verbose, costs off) select * from at_view_2; +select * from at_view_2; + +create or replace view at_view_1 as select *, 2+2 as more from at_base_table bt; +\d+ at_view_1 +\d+ at_view_2 +explain (verbose, costs off) select * from at_view_2; +select * from at_view_2; + +drop view at_view_2; +drop view at_view_1; +--drop table at_base_table; + +create table tt_row_rep_1(a int); +alter table tt_row_rep_1 drop column a; + +create table tt_row_rep_2(a int, b int); +alter table tt_row_rep_2 drop column b; +alter table tt_row_rep_2 drop column a; + +create table tt_col_rep_1(a int) with(orientation=column); +alter table tt_col_rep_1 drop column a; + +create table tt_col_rep_2(a int, b int) with(orientation=column); +alter table tt_col_rep_2 drop column b; +alter table tt_col_rep_2 drop column a; + +--drop table tt_row_rep_1; +--drop table tt_row_rep_2; +drop table tt_col_rep_1; +drop table tt_col_rep_2; + +-- renaming constraints with cache reset of target relation +CREATE TABLE constraint_rename_cache (a int, + CONSTRAINT chk_a CHECK (a > 0), + PRIMARY KEY (a)); +ALTER TABLE constraint_rename_cache + RENAME CONSTRAINT chk_a TO chk_a_new; +ALTER TABLE constraint_rename_cache + RENAME CONSTRAINT constraint_rename_cache_pkey TO constraint_rename_pkey_new; +CREATE TABLE like_constraint_rename_cache + (LIKE constraint_rename_cache INCLUDING ALL); +\d like_constraint_rename_cache +--drop table constraint_rename_cache; +--drop table like_constraint_rename_cache; + + + +create table t_alter_type(c0 int4range Unique, foreign key(c0) references t_alter_type(c0)); +alter table t_alter_type alter c0 set data type int4range; + +----drop table t_alter_type; + +CREATE TABLE MODIFY_TABLE_A(I INTEGER); +\d MODIFY_TABLE_A +create table aaa(a integer); +\d aaa +create table bbb(B integer); +\d bbb +create table CCC(c integer); +\d CCC +create table DDD(D integer); +\d DDD +create table EEE("E" integer); +\d EEE +create table FFF("FF" integer); +\d FFF +create table HHH("HH" integer); + +alter table aaa rename a to AA; +\d aaa +create table GGG("GdGG" integer); +alter table CCC rename c to "CC"; +alter table FFF rename FF to ff; -- differnt in b compatibility +alter table HHH rename "HH" to gg; + +rename table public.HHH to public.hhh; +rename table public.hhh to public.hhh1; + +create table aaaaa (b int generated by default as identity,c int); +\dS aaaaa_b_seq +insert into aaaaa(c) values(213); +insert into aaaaa(c) values(21); +insert into aaaaa values(3,121); +insert into aaaaa(c) values(111); +insert into aaaaa values(null,212); +alter table aaaaa alter column b drop default; +drop sequence aaaaa_b_seq; diff --git a/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_fastcheck.setup b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_fastcheck.setup new file mode 100644 index 000000000..4db8109ca --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_fastcheck.setup @@ -0,0 +1,15 @@ +#!/bin/sh + +source $1/env_utils.sh $1 $2 +subscription_dir=$1 +case_use_db=$3 + +exec_sql_with_user $case_use_db $pub_node1_port "create schema fastcheck;set search_path=fastcheck;create table t1_full (a int, b text);insert into t1_full values (1, 'a'), (2, 'b'), (3, 'c');alter table t1_full replica identity full;" +exec_sql_with_user $case_use_db $sub_node1_port "create schema fastcheck;set search_path=fastcheck;create table t1_full (a int, b text, myc int); insert into t1_full values (101, 'a', 1), (102, 'b', 2);" + +exec_sql_with_user $case_use_db $pub_node1_port "set search_path=fastcheck;create table tkey1 (a int primary key, b text);insert into tkey1 values (1, 'a'), (2, 'b'), (3, 'c');alter table tkey1 replica identity default;" +exec_sql_with_user $case_use_db $sub_node1_port "set search_path=fastcheck;create table tkey1 (a int primary key, b text, myc int); insert into tkey1 values (101, '101a', 1), (102, '102b', 2);" + +exec_sql_with_user $case_use_db $pub_node1_port "CREATE USER regtest_unpriv_user PASSWORD 'gauss@123'" + +exec_sql_with_user $case_use_db $sub_node1_port "CREATE USER regtest_unpriv_user PASSWORD 'gauss@123'" \ No newline at end of file diff --git a/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_fastcheck.sql b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_fastcheck.sql new file mode 100644 index 000000000..1fe374b88 --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_fastcheck.sql @@ -0,0 +1,930 @@ +-- +--FOR BLACKLIST FEATURE: REFERENCES/WITH OIDS/RULE/CREATE TYPE/DOMAIN is not supported. +-- + +-- +-- ALTER_TABLE +-- add attribute +-- +set search_path=fastcheck; +CREATE TABLE atmp1 (initial int4); + +COMMENT ON TABLE tmp_wrong IS 'table comment'; +COMMENT ON TABLE atmp1 IS 'table comment'; +COMMENT ON TABLE atmp1 IS NULL; + +ALTER TABLE atmp1 ADD COLUMN xmin integer; -- fails + +ALTER TABLE atmp1 ADD COLUMN a int4 default 3; + +ALTER TABLE atmp1 ADD COLUMN b name; + +ALTER TABLE atmp1 ADD COLUMN c text; + +ALTER TABLE atmp1 ADD COLUMN d float8; + +ALTER TABLE atmp1 ADD COLUMN e float4; + +ALTER TABLE atmp1 ADD COLUMN f int2; + +ALTER TABLE atmp1 ADD COLUMN g polygon; + +ALTER TABLE atmp1 ADD COLUMN h abstime; + +ALTER TABLE atmp1 ADD COLUMN i char; + +ALTER TABLE atmp1 ADD COLUMN j abstime[]; + +ALTER TABLE atmp1 ADD COLUMN k int4; + +ALTER TABLE atmp1 ADD COLUMN l tid; + +ALTER TABLE atmp1 ADD COLUMN m xid; + +ALTER TABLE atmp1 ADD COLUMN n oidvector; + +--ALTER TABLE atmp1 ADD COLUMN o lock; +ALTER TABLE atmp1 ADD COLUMN p smgr; + +ALTER TABLE atmp1 ADD COLUMN q point; + +ALTER TABLE atmp1 ADD COLUMN r lseg; + +ALTER TABLE atmp1 ADD COLUMN s path; + +ALTER TABLE atmp1 ADD COLUMN t box; + +ALTER TABLE atmp1 ADD COLUMN u tinterval; + +ALTER TABLE atmp1 ADD COLUMN v timestamp; + +ALTER TABLE atmp1 ADD COLUMN w interval; + +ALTER TABLE atmp1 ADD COLUMN x float8[]; + +ALTER TABLE atmp1 ADD COLUMN y float4[]; + +ALTER TABLE atmp1 ADD COLUMN z int2[]; + +INSERT INTO atmp1 (a, b, c, d, e, f, g, h, i, j, k, l, m, n, p, q, r, s, t, u, + v, w, x, y, z) + VALUES (4, 'name', 'text', 4.1, 4.1, 2, '(4.1,4.1,3.1,3.1)', + 'Mon May 1 00:30:30 1995', 'c', '{Mon May 1 00:30:30 1995, Monday Aug 24 14:43:07 1992, epoch}', + 314159, '(1,1)', '512', + '1 2 3 4 5 6 7 8', 'magnetic disk', '(1.1,1.1)', '(4.1,4.1,3.1,3.1)', + '(0,2,4.1,4.1,3.1,3.1)', '(4.1,4.1,3.1,3.1)', '["epoch" "infinity"]', + 'epoch', '01:00:10', '{1.0,2.0,3.0,4.0}', '{1.0,2.0,3.0,4.0}', '{1,2,3,4}'); + +SELECT * FROM atmp1; + +----drop table tmp; + +-- the wolf bug - schema mods caused inconsistent row descriptors +CREATE TABLE atmp2 ( + initial int4 +); + +ALTER TABLE atmp2 ADD COLUMN a int4; + +ALTER TABLE atmp2 ADD COLUMN b name; + +ALTER TABLE atmp2 ADD COLUMN c text; + +ALTER TABLE atmp2 ADD COLUMN d float8; + +ALTER TABLE atmp2 ADD COLUMN e float4; + +ALTER TABLE atmp2 ADD COLUMN f int2; + +ALTER TABLE atmp2 ADD COLUMN g polygon; + +ALTER TABLE atmp2 ADD COLUMN h abstime; + +ALTER TABLE atmp2 ADD COLUMN i char; + +ALTER TABLE atmp2 ADD COLUMN j abstime[]; + +ALTER TABLE atmp2 ADD COLUMN k int4; + +ALTER TABLE atmp2 ADD COLUMN l tid; + +ALTER TABLE atmp2 ADD COLUMN m xid; + +ALTER TABLE atmp2 ADD COLUMN n oidvector; + +--ALTER TABLE atmp2 ADD COLUMN o lock; +ALTER TABLE atmp2 ADD COLUMN p smgr; + +ALTER TABLE atmp2 ADD COLUMN q point; + +ALTER TABLE atmp2 ADD COLUMN r lseg; + +ALTER TABLE atmp2 ADD COLUMN s path; + +ALTER TABLE atmp2 ADD COLUMN t box; + +ALTER TABLE atmp2 ADD COLUMN u tinterval; + +ALTER TABLE atmp2 ADD COLUMN v timestamp; + +ALTER TABLE atmp2 ADD COLUMN w interval; + +ALTER TABLE atmp2 ADD COLUMN x float8[]; + +ALTER TABLE atmp2 ADD COLUMN y float4[]; + +ALTER TABLE atmp2 ADD COLUMN z int2[]; + +INSERT INTO atmp2 (a, b, c, d, e, f, g, h, i, j, k, l, m, n, p, q, r, s, t, u, + v, w, x, y, z) + VALUES (4, 'name', 'text', 4.1, 4.1, 2, '(4.1,4.1,3.1,3.1)', + 'Mon May 1 00:30:30 1995', 'c', '{Mon May 1 00:30:30 1995, Monday Aug 24 14:43:07 1992, epoch}', + 314159, '(1,1)', '512', + '1 2 3 4 5 6 7 8', 'magnetic disk', '(1.1,1.1)', '(4.1,4.1,3.1,3.1)', + '(0,2,4.1,4.1,3.1,3.1)', '(4.1,4.1,3.1,3.1)', '["epoch" "infinity"]', + 'epoch', '01:00:10', '{1.0,2.0,3.0,4.0}', '{1.0,2.0,3.0,4.0}', '{1,2,3,4}'); + +SELECT * FROM atmp2; + +----drop table tmp; + + +-- +-- rename - check on both non-temp and temp tables +-- +CREATE TABLE atmp3 (regtable int); +-- Enforce use of COMMIT instead of 2PC for temporary objects + + +CREATE TABLE onek ( + unique1 int4, + unique2 int4, + two int4, + four int4, + ten int4, + twenty int4, + hundred int4, + thousand int4, + twothousand int4, + fivethous int4, + tenthous int4, + odd int4, + even int4, + stringu1 name, + stringu2 name, + string4 name +) with(autovacuum_enabled = off); +CREATE INDEX onek_unique1 ON onek USING btree(unique1 int4_ops); + +CREATE TABLE tenk1 ( + unique1 int4, + unique2 int4, + two int4, + four int4, + ten int4, + twenty int4, + hundred int4, + thousand int4, + twothousand int4, + fivethous int4, + tenthous int4, + odd int4, + even int4, + stringu1 name, + stringu2 name, + string4 name +) with(autovacuum_enabled = off); + +CREATE TABLE stud_emp ( + name text, + age int4, + location point, + salary int4, + manager name, + gpa float8, + percent int4 +) with(autovacuum_enabled = off); + +-- ALTER TABLE ... RENAME on non-table relations +-- renaming indexes (FIXME: this should probably test the index's functionality) +ALTER INDEX IF EXISTS __onek_unique1 RENAME TO tmp_onek_unique1; +ALTER INDEX IF EXISTS __tmp_onek_unique1 RENAME TO onek_unique1; + +ALTER INDEX onek_unique1 RENAME TO tmp_onek_unique1; +ALTER INDEX tmp_onek_unique1 RENAME TO onek_unique1; + +-- renaming views +CREATE VIEW tmp_view (unique1) AS SELECT unique1 FROM tenk1; +ALTER TABLE tmp_view RENAME TO tmp_view_new; + +DROP VIEW tmp_view_new; +-- toast-like relation name +alter table stud_emp rename to pg_toast_stud_emp; +alter table pg_toast_stud_emp rename to stud_emp; + +-- renaming index should rename constraint as well +ALTER TABLE onek ADD CONSTRAINT onek_unique1_constraint UNIQUE (unique1); +ALTER INDEX onek_unique1_constraint RENAME TO onek_unique1_constraint_foo; +ALTER TABLE onek DROP CONSTRAINT onek_unique1_constraint_foo; + +-- renaming constraint +ALTER TABLE onek ADD CONSTRAINT onek_check_constraint CHECK (unique1 >= 0); +ALTER TABLE onek RENAME CONSTRAINT onek_check_constraint TO onek_check_constraint_foo; +ALTER TABLE onek DROP CONSTRAINT onek_check_constraint_foo; + +-- renaming constraint should rename index as well +ALTER TABLE onek ADD CONSTRAINT onek_unique1_constraint UNIQUE (unique1); +DROP INDEX onek_unique1_constraint; -- to see whether it's there +ALTER TABLE onek RENAME CONSTRAINT onek_unique1_constraint TO onek_unique1_constraint_foo; +DROP INDEX onek_unique1_constraint_foo; -- to see whether it's there +ALTER TABLE onek DROP CONSTRAINT onek_unique1_constraint_foo; + +-- renaming constraints vs. inheritance +CREATE TABLE constraint_rename_test (a int CONSTRAINT con1 CHECK (a > 0), b int, c int); +\d constraint_rename_test + +create table test_modify (a int, b int); +alter table test_modify replica identity full; +alter table test_modify modify (b not null enable); +insert into test_modify(b) values (null); +insert into test_modify values (1, null); +alter table test_modify modify(b null); +insert into test_modify values (1, null); +alter table test_modify modify (b not null enable); +alter table test_modify replica identity full; +delete from test_modify; +alter table test_modify modify (a not null, b not null); +insert into test_modify values (1,null); +insert into test_modify values (null,1); +alter table test_modify modify (a null, b null); +insert into test_modify values (1,null); +insert into test_modify values (null,1); +alter table test_modify modify (b constraint ak not null); +delete from test_modify; +alter table test_modify modify (b constraint ak not null); +insert into test_modify values(1,1); +insert into test_modify values(1,null); +alter table test_modify modify (b constraint ak null); +insert into test_modify values(1,null); +alter table test_modify modify (a null, a not null); +-- try alter view should fail +create view test_modify_view as select * from test_modify; +alter table test_modify_view modify (a not null enable); +drop view test_modify_view; +--drop table test_modify; + + +-- test setting and removing default values +create table def_test ( + c1 int4 default 5, + c2 text default 'initial_default' +); +insert into def_test default values; +alter table def_test alter column c1 drop default; +insert into def_test default values; +alter table def_test alter column c2 drop default; +insert into def_test default values; +alter table def_test alter column c1 set default 10; +alter table def_test alter column c2 set default 'new_default'; +insert into def_test default values; +select * from def_test order by 1, 2; + +-- set defaults to an incorrect type: this should fail +alter table def_test alter column c1 set default 'wrong_datatype'; +alter table def_test alter column c2 set default 20; + +-- set defaults on a non-existent column: this should fail +alter table def_test alter column c3 set default 30; + +create type mytype as (a text); +create table foo (f1 text, f2 mytype, f3 text); + +insert into foo values('bb','cc','dd'); +select * from foo order by f1; + +-- drop domain mytype cascade; + +select * from foo order by f1; +insert into foo values('qq','rr'); +select * from foo order by f1; +alter table foo replica identity full; +update foo set f3 = 'zz'; +select * from foo order by f1; +select f3,max(f1) from foo group by f3; + +-- Simple tests for alter table column type +alter table foo replica identity full; +delete from foo where f1 = 'qq'; +alter table foo alter f1 TYPE integer; -- fails +alter table foo alter f1 TYPE varchar(10); +--drop table foo; + + +CREATE TABLE TBL_DOMAIN +( + IDOMAINID NUMBER(10) NOT NULL, + SDOMAINNAME VARCHAR2(30) NOT NULL +); +--create/recreate primary, unique and foreign key constraints +ALTER TABLE TBL_DOMAIN + ADD CONSTRAINT PK_TBL_DOMAIN PRIMARY KEY (IDOMAINID) + USING INDEX ; + +ALTER TABLE TBL_DOMAIN + ADD CONSTRAINT IX_TBL_DOMAIN UNIQUE (SDOMAINNAME) + USING INDEX ; +\d+ TBL_DOMAIN +--drop table TBL_DOMAIN; + +--create table +CREATE TABLE TBL_CM_MAXTSENDTOHOST +( + I_MODULETYPE NUMBER(38) NOT NULL, + I_MODULENO NUMBER(38) NOT NULL, + I_PLAMODULENO NUMBER(38) NOT NULL, + I_TABLEID NUMBER(38) NOT NULL, + I_OLDMAXTUPLE NUMBER(38) NOT NULL, + I_NEWMAXTUPLE NUMBER(38) NOT NULL, + I_RESERVED1 NUMBER(38) DEFAULT 0, + I_RESERVED2 NUMBER(38) DEFAULT 0, + I_RESERVED3 NUMBER(38) DEFAULT 0, + I_RESERVED4 NUMBER(38) DEFAULT 0, + I_RESERVED5 NUMBER(38) DEFAULT 0, + I_RESERVED6 NUMBER(38) DEFAULT 0, + I_RESERVED7 NUMBER(38) DEFAULT 0, + SV_RESERVED8 VARCHAR2(32) DEFAULT '', + SV_RESERVED9 VARCHAR2(32) DEFAULT '', + SV_RESERVED10 VARCHAR2(32) DEFAULT '' +) + PCTFREE 10 + INITRANS 1 + MAXTRANS 255 + STORAGE + ( + INITIAL 64K + MINEXTENTS 1 + MAXEXTENTS UNLIMITED + ) + ; +--add primary key +ALTER TABLE TBL_CM_MAXTSENDTOHOST + ADD PRIMARY KEY (I_PLAMODULENO, I_TABLEID) + USING INDEX + PCTFREE 10 + INITRANS 2 + MAXTRANS 255 + STORAGE + ( + INITIAL 64K + MINEXTENTS 1 + MAXEXTENTS UNLIMITED + ); + \d+ TBL_CM_MAXTSENDTOHOST + --drop table TBL_CM_MAXTSENDTOHOST; + +--create table +CREATE TABLE TBL_LICCTRLDESC_DEFAULT +( + I_INDEX NUMBER(38) NOT NULL, + SV_FEATURENAME VARCHAR2(64) NOT NULL, + SV_ITEMNAME VARCHAR2(64) NOT NULL, + I_ITEMTYPE NUMBER(38) NOT NULL, + I_ITEMVALUEMIN NUMBER(38) NOT NULL, + I_ITEMVALUEMAX NUMBER(38) NOT NULL, + I_RESERVED1 NUMBER(38) DEFAULT 0, + I_RESERVED2 NUMBER(38) DEFAULT 0, + I_RESERVED3 NUMBER(38) DEFAULT 0, + I_RESERVED4 NUMBER(38) DEFAULT 0, + I_RESERVED5 NUMBER(38) DEFAULT 0, + I_RESERVED6 NUMBER(38) DEFAULT 0, + I_RESERVED7 NUMBER(38) DEFAULT 0, + SV_RESERVED8 VARCHAR2(32) DEFAULT '', + SV_RESERVED9 VARCHAR2(32) DEFAULT '', + SV_RESERVED10 VARCHAR2(32) DEFAULT '', + I_STATUS NUMBER(38) NOT NULL +) + PCTFREE 10 + INITRANS 1 + MAXTRANS 255 + STORAGE + ( + INITIAL 64K + MINEXTENTS 1 + MAXEXTENTS UNLIMITED + ) + ; +--add primary key +ALTER TABLE TBL_LICCTRLDESC_DEFAULT + ADD PRIMARY KEY (I_INDEX) + USING INDEX + PCTFREE 10 + INITRANS 2 + MAXTRANS 255 + STORAGE + ( + INITIAL 64K + MINEXTENTS 1 + MAXEXTENTS UNLIMITED + ); +--add unique index +CREATE UNIQUE INDEX IDX_TBL_LICCTRL_DEF ON TBL_LICCTRLDESC_DEFAULT (I_INDEX DESC, I_STATUS) + PCTFREE 10 + INITRANS 2 + MAXTRANS 255 + STORAGE + ( + INITIAL 64K + MINEXTENTS 1 + MAXEXTENTS UNLIMITED + ); +\d+ TBL_LICCTRLDESC_DEFAULT + --drop table TBL_LICCTRLDESC_DEFAULT; +--using index clause +CREATE TABLE STUDENTS +( + ID INT, + NAME VARCHAR2(20), + AGE INT, + ADDRESS VARCHAR(30) +); + --alter table to add unique index or primary key +ALTER TABLE STUDENTS ADD UNIQUE (ID) +USING INDEX +PCTFREE 10 +INITRANS 2 +MAXTRANS 255 +STORAGE +( + INITIAL 64K + MINEXTENTS 1 + MAXEXTENTS UNLIMITED +); + +ALTER TABLE STUDENTS ADD CONSTRAINT ZHANGYG UNIQUE (AGE, ADDRESS) +USING INDEX +PCTFREE 10 +INITRANS 2 +MAXTRANS 255 +STORAGE +( + INITIAL 64K + MINEXTENTS 1 + MAXEXTENTS UNLIMITED +); + +ALTER TABLE STUDENTS ADD PRIMARY KEY (AGE) +USING INDEX +PCTFREE 10 +INITRANS 2 +MAXTRANS 255 +STORAGE +( + INITIAL 64K + MINEXTENTS 1 + MAXEXTENTS UNLIMITED +); +\d+ STUDENTS +--drop table STUDENTS; +--simulate A db's ALTER TABLE gram +CREATE TABLE MODIFY_TABLE_A(I INTEGER); +ALTER TABLE MODIFY_TABLE_A ADD (mychar CHAR); +ALTER TABLE MODIFY_TABLE_A ADD (myint1 INT, mychar1 CHAR); +ALTER TABLE MODIFY_TABLE_A ADD (myint2 INT, mychar2 CHAR, mychar3 CHAR); +ALTER TABLE MODIFY_TABLE_A ADD a CHAR, ADD b CHAR; +\d MODIFY_TABLE_A +ALTER TABLE MODIFY_TABLE_A ADD mychar4 CHAR; +\d MODIFY_TABLE_A +ALTER TABLE MODIFY_TABLE_A MODIFY I VARCHAR2(64); +\d MODIFY_TABLE_A +ALTER TABLE MODIFY_TABLE_A MODIFY I CHAR, MODIFY myint1 CHAR; +\d MODIFY_TABLE_A +ALTER TABLE MODIFY_TABLE_A MODIFY (myint1 VARCHAR(12)); +\d MODIFY_TABLE_A +ALTER TABLE MODIFY_TABLE_A MODIFY (myint1 VARCHAR(13), mychar1 INT); +\d MODIFY_TABLE_A +ALTER TABLE MODIFY_TABLE_A MODIFY (myint1 VARCHAR(13), myint1 INT); +--drop table MODIFY_TABLE_A; + + +CREATE SCHEMA test_sche; +CREATE TABLE test_sche.logical_TB1( +c1 integer, +c2 date, +c3 text) +partition by system +( +partition p1, +partition p2, +partition p3); + +insert into test_sche.logical_TB1 partition(p1) values(1,'2022-01-01','p1'); +insert into test_sche.logical_TB1 partition(p2) values(2,'2022-02-01','p2'); +insert into test_sche.logical_TB1 partition(p2) values(3,'2022-02-01','p3'); +truncate test_sche.logical_TB1; +--drop table test_sche.logical_TB1; + +CREATE TABLE MODIFY_TABLE_A(I INTEGER); +\d MODIFY_TABLE_A +create table aaa(a integer); +\d aaa +create table bbb(B integer); +\d bbb +create table CCC(c integer); +\d CCC +create table DDD(D integer); +\d DDD +create table EEE("E" integer); +\d EEE +create table FFF("FF" integer); +\d FFF +create table HHH("HH" integer); + +alter table aaa rename a to AA; +\d aaa +create table GGG("GdGG" integer); +alter table CCC rename c to "CC"; +alter table FFF rename FF to ff; -- differnt in b compatibility +alter table HHH rename "HH" to gg; + +rename table public.HHH to public.hhh; +rename table public.hhh to public.hhh1; + +insert into t1_full values (4,'d'); +insert into t1_full values (5, 'e'); +create type mytyp as (a int, b text); +alter table t1_full add column c timestamp default now() not null first; +alter table t1_full add column d timestamp on update current_timestamp; + +alter table t1_full add column e int auto_increment unique; +alter table t1_full alter column b set data type timestamp using now(); +alter table t1_full add column ff mytyp default(1, now()::text); +alter table t1_full add column ff33 mytyp default(1, current_timestamp(3)::text); + +alter table t1_full rename to t1_repl_index; +alter table t1_repl_index add constraint t1_pkey_a primary key (a); +alter table t1_repl_index replica identity default; +alter table t1_repl_index add column f int auto_increment unique; +alter table t1_repl_index add column f int auto_increment null unique; +alter table t1_repl_index alter column b set data type timestamp using now(); +alter table t1_repl_index add column e timestamp default now() not null; +alter table t1_repl_index alter column e set data type float using random(); +alter table t1_repl_index add column h int default random(); +alter table t1_repl_index add column h int; +alter table t1_repl_index alter column h set data type float; +update t1_repl_index set h=random(); +alter table t1_repl_index add column g timestamp generated always as (b + '1 year'); +insert into t1_repl_index (a) values (200), (201), (202); +-- drop table t1_repl_index; + +insert into tkey1 values (10), (12); +alter table tkey1 modify column b float4 auto_increment unique; +alter table tkey1 modify column b int auto_increment null unique; +drop table tkey1; + +create table blobtbl (id int primary key, a blob, b raw, c clob, d bytea); +alter table blobtbl replica identity default; +insert into blobtbl values (1, utl_raw.cast_to_raw('this is blob'), utl_raw.cast_to_raw('this is raw'), 'this is clob', decode('this is bytea', 'escape')); +insert into blobtbl values (2, utl_raw.cast_to_raw('this is blob2'), utl_raw.cast_to_raw('this is raw2'), 'this is clob2', decode('this is bytea2', 'escape')); +insert into blobtbl values (3, utl_raw.cast_to_raw('this is blob3'), utl_raw.cast_to_raw('this is raw3'), 'this is clob3', decode('this is bytea3', 'escape')); + +update blobtbl set a=utl_raw.cast_to_raw('this is blob after update'), b=utl_raw.cast_to_raw('this is raw after update'), c='this is clob after update', d=decode('this is bytea after i[date]', 'escape') where id=2; +delete from blobtbl where id=3; + +select utl_raw.cast_to_varchar2(a) as blob_col, utl_raw.cast_to_varchar2(b) as raw_col, cast(c as varchar) as clob_col, encode(d, 'escape') as bytea_col into blobtbl_1 from blobtbl; + +create table blobtbl_2 as (select utl_raw.cast_to_varchar2(a) as blob_col, utl_raw.cast_to_varchar2(b) as raw_col, cast(c as varchar) as clob_col, encode(d, 'escape') as bytea_col from blobtbl); + +create schema testb; +set search_path='testb'; +create table t1 (a int, b timestamp without time zone); +alter table t1 alter column b set default now(); +alter table t1 modify column b timestamp on update current_timestamp; +insert into t1 (a,b) values (1,default), (2,default),(3,'1900-01-01 1:00:00'); +alter table t1 replica identity full; +create type typ1 as (a int, b text); + +alter table t1 add column c typ1 default(1, now()::text); +alter type typ1 add attribute c timestamp; +alter table t1 add constraint t1_pkey primary key (a); +alter table t1 replica identity default; +alter table t1 alter column b set data type timestamp using now() - a; +create type typ2; +create type typ2 as (a int, b int); +alter type typ2 drop attribute a; +drop type typ2; + +create table tab1_1163900(id int not null,a1 text) partition by range(id); +create table tab2_1163900(id int not null,a1 text) partition by list(id); +create table tab3_1163900(id int not null,a1 text) partition by hash(id); +--create table; +create table t1_1163900(id int not null,a1 text); +create table t2_1163900(id int not null,a1 text); +create table t3_1163900(id int not null,a1 text); +--insert; +insert into t1_1163900(id,a1) select generate_series(1,100),'a'; +--t3_1163900; +insert into t3_1163900(id,a1) select generate_series(1,100),'a'; +--t2_1163900; +do $$ +declare +begin +for i in 1..100 loop +insert into t2_1163900 values(20,'a'); +end loop; +end $$; + +--attach; +alter table tab1_1163900 attach partition t1_1163900 for values from (1) to (1000); +alter table tab2_1163900 attach partition t2_1163900 for values in(20); +alter table tab3_1163900 attach partition t3_1163900 for values with(modulus 1,remainder 0); + +create table aaaaa1 (b int generated by default as identity (cycle increment by 10),c int); +-- \dS aaaaa_b_seq +-- insert into aaaaa(c) values(213); +-- insert into aaaaa(c) values(21); +-- insert into aaaaa values(3,121); +-- insert into aaaaa(c) values(111); +-- insert into aaaaa values(null,212); +-- alter table aaaaa alter column b drop default; +-- drop sequence aaaaa_b_seq; + +create table bbbb (a int not null); +alter table bbbb alter column a add generated by default as identity; + +create table genalways(id bigint generated always as identity (start 68 cycle maxvalue 70),name varchar(40)); + +create table genalways2(id smallint generated always as identity (start 68 cycle maxvalue 70),name varchar(40)); + +drop table if exists gentest; +create table gentest(id integer PRIMARY KEY, name varchar(40)); +/* AT_AddIdentity */ +ALTER TABLE gentest ALTER id ADD GENERATED ALWAYS AS IDENTITY (start 12 maxvalue 322); +/* AT_SetIdentity in pg compatibility */ +ALTER TABLE gentest ALTER id SET GENERATED ALWAYS; +ALTER TABLE gentest ALTER id DROP IDENTITY; +ALTER TABLE gentest ALTER id ADD GENERATED BY DEFAULT AS IDENTITY (start 99 maxvalue 1000); +ALTER TABLE gentest ALTER id DROP IDENTITY IF EXISTS; +ALTER TABLE gentest ALTER id ADD GENERATED ALWAYS AS IDENTITY (start 33 maxvalue 333); +ALTER TABLE gentest ALTER id SET GENERATED BY DEFAULT; +ALTER TABLE gentest ALTER id RESTART WITH 123; +ALTER TABLE gentest ALTER id RESTART; + + + +CREATE TABLE range_sales +( + product_id INT4 NOT NULL, + customer_id INT4 PRIMARY KEY, + time_id DATE, + channel_id CHAR(1), + type_id INT4, + quantity_sold NUMERIC(3), + amount_sold NUMERIC(10,2) +) +PARTITION BY RANGE (time_id) +( + PARTITION time_2008 VALUES LESS THAN ('2009-01-01'), + PARTITION time_2009 VALUES LESS THAN ('2010-01-01'), + PARTITION time_2010 VALUES LESS THAN ('2011-01-01'), + PARTITION time_2011 VALUES LESS THAN ('2012-01-01') +); +INSERT INTO range_sales SELECT generate_series(1,1000), + generate_series(1,1000), + date_pli('2008-01-01', generate_series(1,1000)), + generate_series(1,1000)%10, + generate_series(1,1000)%10, + generate_series(1,1000)%1000, + generate_series(1,1000); +CREATE INDEX range_sales_idx ON range_sales(product_id) LOCAL; +--success, add 1 partition +ALTER TABLE range_sales ADD PARTITION time_2012 VALUES LESS THAN ('2013-01-01'); +--success, add 1 partition +ALTER TABLE range_sales ADD PARTITION time_end VALUES LESS THAN (MAXVALUE); + +ALTER TABLE range_sales DROP PARTITION time_2009; +--success, drop partition time_2011 +ALTER TABLE range_sales DROP PARTITION FOR ('2011-06-01'); +ALTER TABLE range_sales DROP PARTITION time_2012 update global index; + + +create table t_tinyint0018 ( + c1 tinyint, + c2 tinyint(1) default null, + c3 tinyint(10) not null default '0', + c4 tinyint default '0', + c5 text +); +alter table t_tinyint0018 add unique index i_tinyint0018(c1, c2, c5(10)); + +create table t1_addkey (a int, b int, c int, d int); +alter table t1_addkey add primary key (a, b); +alter table t1_addkey add unique (c); + + + +CREATE TABLE test_alter_autoinc_col(col int unsigned primary key); +INSERT INTO test_alter_autoinc_col VALUES(1); +ALTER TABLE test_alter_autoinc_col ADD COLUMN id int unsigned AUTO_INCREMENT unique; + + + +create table alter_table_tbl1 (a int primary key, b int); +create table alter_table_tbl2 (c int primary key, d int); +alter table alter_table_tbl2 add constraint alter_table_tbl_fk foreign key (d) references alter_table_tbl1 (a); + +create index alter_table_tbl_b_ind on alter_table_tbl1(b); + +-- disbale/enable keys +alter table alter_table_tbl1 disable keys; + + +alter table alter_table_tbl1 enable keys; + +-- drop index/key index_name +alter table alter_table_tbl1 drop index alter_table_tbl_b_ind; + +create index alter_table_tbl_b_ind on alter_table_tbl1(b); +alter table alter_table_tbl1 drop key alter_table_tbl_b_ind; +alter table alter_table_tbl2 drop primary key; + +alter table alter_table_tbl2 drop foreign key alter_table_tbl_fk; + +create index alter_table_tbl_b_ind on alter_table_tbl1(b); +alter table alter_table_tbl1 rename index alter_table_tbl_b_ind to new_alter_table_tbl_b_ind; + + +alter table alter_table_tbl1 rename to new_alter_table_tbl1; +alter table new_alter_table_tbl1 rename as new_new_alter_table_tbl1; +alter table new_new_alter_table_tbl1 rename new_new_new_alter_table_tbl1; +alter table if exists new_new_new_alter_table_tbl1 rename alter_table_tbl1; +alter table if exists not_exists_tbl rename new_not_exists_tbl; + + +alter table alter_table_tbl1 add column key int, rename index new_alter_table_tbl_b_ind to alter_table_tbl_b_ind; +alter table alter_table_tbl1 drop column key, drop key alter_table_tbl_b_ind; + +ALTER TABLE alter_table_tbl1 RENAME COLUMN a TO AB; +ALTER TABLE alter_table_tbl1 RENAME COLUMN ab TO Ab; +ALTER TABLE alter_table_tbl1 RENAME AB TO AB; +ALTER TABLE alter_table_tbl1 RENAME ab TO ab; +ALTER TABLE if exists alter_table_tbl1 RENAME COLUMN AB TO Ab; +ALTER TABLE if exists alter_table_tbl1 RENAME COLUMN Ab TO ab; +ALTER TABLE if exists alter_table_tbl1 RENAME AB TO ab; +ALTER TABLE if exists alter_table_tbl1 RENAME Ab TO AB; +ALTER TABLE if exists alter_table_tbl1 RENAME Ab AS AB; + + +ALTER TABLE alter_table_tbl1 CHANGE AB ab int; +ALTER TABLE alter_table_tbl1 CHANGE COLUMN AB ABCC int; +ALTER TABLE alter_table_tbl1 CHANGE COLUMN ABCCC AB varchar; + + +CREATE TABLE t_alter_test(c text); +ALTER TABLE t_alter_test DEFAULT COLLATE = test_collate; +ALTER TABLE t_alter_test DEFAULT CHARACTER SET = test_charset; +ALTER TABLE t_alter_test DEFAULT CHARSET = test_charset; +ALTER TABLE t_alter_test default CHARACTER SET = utf_8; +ALTER TABLE t_alter_test CHARACTER SET = utf_8; +ALTER TABLE t_alter_test convert to CHARACTER SET utf_8; + +CREATE TABLE IF NOT EXISTS test_part +( +a int primary key not null default 5, +b int, +c int, +d int +) +PARTITION BY RANGE(a) +( + PARTITION p0 VALUES LESS THAN (1000), + PARTITION p1 VALUES LESS THAN (2000), + PARTITION p2 VALUES LESS THAN (3000) +); + +create unique index idx_c on test_part (c); +create index idx_b on test_part using btree(b) local; +alter table test_part add constraint uidx_d unique(d); +alter table test_part add constraint uidx_c unique using index idx_c; + +insert into test_part (with RECURSIVE t_r(i,j,k,m) as(values(0,1,2,3) union all select i+1,j+2,k+3,m+4 from t_r where i < 2500) select * from t_r); + +ALTER TABLE test_part REBUILD PARTITION p0, p1; +ALTER TABLE test_part REBUILD PARTITION all; + +ALTER TABLE test_part ANALYZE PARTITION p0, p1; +ALTER TABLE test_part ANALYZE PARTITION all; + + +ALTER TABLE test_part remove PARTITIONING; + + +CREATE TABLE bcomp_t1(id int, t text, ref int); +CREATE TABLE bcomp_t2(id int, t text); + +alter table bcomp_t2 add constraint unique_id unique(id); +alter table bcomp_t1 add foreign key(ref) references bcomp_t2(id); +alter table bcomp_t1 drop foreign key bcomp_t1_ref_fkey; + +CREATE TABLE bcomp_test_table_1 ( + id INT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(255), + age INT +); +ALTER TABLE bcomp_test_table_1 ADD INDEX idx_age (age); +ALTER TABLE bcomp_test_table_1 rename index idx_age to index_age; +ALTER TABLE bcomp_test_table_1 DROP INDEX index_age; + +CREATE TABLE test ( +id int unsigned auto_increment not null primary key, +title varchar, +boby text, +name name +); +CREATE FULLTEXT INDEX test_index_1 ON test (title, boby) WITH PARSER ngram; +CREATE FULLTEXT INDEX test_index_2 ON test (title, boby, name); +ALTER TABLE test ADD FULLTEXT INDEX test_index_1 (title, boby) WITH PARSER ngram; + +CREATE TABLE bcomp_test_table_2 ( + id INT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(255), + age INT +); +ALTER TABLE bcomp_test_table_2 ADD CONSTRAINT chk_age_range CHECK (age BETWEEN 18 AND 65); +ALTER TABLE bcomp_test_table_2 DROP CONSTRAINT chk_age_range; + +CREATE TABLE bcomp_test_table_3 ( + id INT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(255), + age INT +); +CREATE INDEX idx_age ON bcomp_test_table_3(age); +ALTER TABLE bcomp_test_table_3 ADD KEY idx_age (age); +ALTER TABLE bcomp_test_table_3 DROP KEY idx_age; + +CREATE TABLE tt (a int primary key); +alter table tt drop primary key; + +CREATE TABLE bcomp_test_table_4 ( + id INT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(255), + age INT); +ALTER TABLE bcomp_test_table_4 DISABLE KEYS; +ALTER TABLE bcomp_test_table_4 ENABLE KEYS; + +CREATE TABLE bcomp_test_table_5 ( + id INT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(255), + age INT); +CREATE INDEX idx_age ON bcomp_test_table_5(age); +ALTER TABLE bcomp_test_table_5 RENAME INDEX idx_age TO idx_age_1; +ALTER TABLE bcomp_test_table_5 DROP INDEX idx_age_1; + +CREATE TABLE bcomp_test_table_6 ( + id INT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(255), + created_at DATE +) PARTITION BY RANGE COLUMNS(id) ( + PARTITION p0 VALUES LESS THAN (100), + PARTITION p1 VALUES LESS THAN (200), + PARTITION p2 VALUES LESS THAN (MAXVALUE) +); +ALTER TABLE bcomp_test_table_6 REMOVE PARTITIONING; + +CREATE DATABASE test_db; +ALTER DATABASE test_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +CREATE TABLE t(num int); + + +create definer = ddl_test_user event IF NOT EXISTS ee11 on schedule EVERY 1 day at '2022-12-09 17:24:11' disable do insert into t values(0); + +create event IF NOT EXISTS ee12 on schedule EVERY 2 day at '2022-12-09 17:24:11' ends '2028-12-09 17:24:11' disable do insert into t values(0); + +create event IF NOT EXISTS ee13 on schedule EVERY 2 day at '2022-12-09 17:24:11' disable do insert into t values(0); + +alter definer = ddl_test_user event ee13 on schedule AT '2099-12-11 17:24:11' comment 'jhhh' do insert into t values(1); + +alter definer = ddl_test_user event ee13 on schedule EVERY 1 day starts '2022-12-09 17:24:11' ends '2028-12-09 17:24:11' ON COMPLETION PRESERVE enable do insert into t values(1); + +alter event ee13 on schedule AT '2055-12-11 17:24:11' enable comment 'jhhh' do insert into t values(1); + +alter event ee12 on schedule at '2055-12-09 17:24:11' enable; + + +select job_name, nspname from pg_job where dbname='event_b'; +drop event if exists ee11; +drop event if exists ee13; + +create event IF NOT EXISTS ee14 on schedule EVERY 2 day at '2022-12-09 17:24:11' disable do insert into t values(0); + +alter event ee14 on schedule at '2055-12-09 17:24:11' disable; +alter event ee14 on schedule at '2055-12-09 17:24:11' enable; +alter event ee14 on schedule at '2055-12-09 17:24:11' DISABLE ON SLAVE; +alter event ee14 rename to ee142; +drop event if exists ee142; + +create table t1_z (col1 int primary key auto_increment , col2 text,col3 bigint); +insert into t1_z(col1,col2) values(3, 'aaa'); +alter table t1_z auto_increment = 3; + +drop table t1_z; \ No newline at end of file diff --git a/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_fastcheck.teardown b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_fastcheck.teardown new file mode 100644 index 000000000..7b0d5e6eb --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_fastcheck.teardown @@ -0,0 +1,19 @@ +#!/bin/sh + +source $1/env_utils.sh $1 $2 +subscription_dir=$1 +case_use_db=$3 + +exec_sql_with_user $case_use_db $sub_node1_port "set search_path=fastcheck;alter table t1_repl_index drop column myc; alter table tkey1 drop column myc" + +exec_sql_with_user $case_use_db $sub_node1_port "set search_path=fastcheck;delete from t1_repl_index where a in (101,102); delete from tkey1 where a in (101,102);" + +exec_sql_with_user $case_use_db $pub_node1_port "set search_path=fastcheck;select utl_raw.cast_to_varchar2(a) as blob_col, utl_raw.cast_to_varchar2(b) as raw_col, cast(c as varchar) as clob_col, encode(d, 'escape') as bytea_col into blobtbl_pub_1 from blobtbl;" + +exec_sql_with_user $case_use_db $pub_node1_port "set search_path=fastcheck;create table blobtbl_pub_2 as (select utl_raw.cast_to_varchar2(a) as blob_col, utl_raw.cast_to_varchar2(b) as raw_col, cast(c as varchar) as clob_col, encode(d, 'escape') as bytea_col from blobtbl);" + +exec_sql_with_user $case_use_db $sub_node1_port "set search_path=fastcheck;drop table blobtbl_pub_1, blobtbl_pub_2" + +exec_sql_with_user $case_use_db $sub_node1_port "set search_path=fastcheck;select utl_raw.cast_to_varchar2(a) as blob_col, utl_raw.cast_to_varchar2(b) as raw_col, cast(c as varchar) as clob_col, encode(d, 'escape') as bytea_col into blobtbl_pub_1 from blobtbl;" + +exec_sql_with_user $case_use_db $sub_node1_port "set search_path=fastcheck;create table blobtbl_pub_2 as (select utl_raw.cast_to_varchar2(a) as blob_col, utl_raw.cast_to_varchar2(b) as raw_col, cast(c as varchar) as clob_col, encode(d, 'escape') as bytea_col from blobtbl);" diff --git a/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_rewrite.setup b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_rewrite.setup new file mode 100644 index 000000000..61d578e9a --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_rewrite.setup @@ -0,0 +1,9 @@ +#!/bin/sh + +source $1/env_utils.sh $1 $2 +subscription_dir=$1 +case_use_db=$3 + +exec_sql $case_use_db $pub_node1_port "create schema rewrite; set search_path=rewrite;create table t1_full (a int, b text);insert into t1_full values (1, 'a'), (2, 'b'), (3, 'c');alter table t1_full replica identity full;" + +exec_sql $case_use_db $sub_node1_port "create schema rewrite; set search_path=rewrite;create table t1_full (a int, b text, myc int); insert into t1_full values (101, 'a', 1), (102, 'b', 2);" diff --git a/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_rewrite.sql b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_rewrite.sql new file mode 100644 index 000000000..d91d9d0bf --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_rewrite.sql @@ -0,0 +1,26 @@ +set search_path=rewrite; +insert into t1_full values (4,'d'); +alter table t1_full add column c timestamp default now() not null first; +alter table t1_full add column d timestamp; + +alter table t1_full add column e int unique; +alter table t1_full alter column b set data type timestamp using now(); + +alter table t1_full rename to t1_repl_index; +alter table t1_repl_index add constraint t1_pkey_a primary key (a); +alter table t1_repl_index replica identity default; +alter table t1_repl_index add column f int auto_increment unique; +alter table t1_repl_index alter column b set data type timestamp using now(); +alter table t1_repl_index add column e timestamp default now() not null; +alter table t1_repl_index alter column e set data type float using random(); +alter table t1_repl_index add column h int default random(); +alter table t1_repl_index alter column h set data type float; +update t1_repl_index set h=random(); +alter table t1_repl_index add column g timestamp generated always as (b + '1 year'); + +create table t1 (a int, b timestamp without time zone); +alter table t1 alter column b set default now(); +alter table t1 modify column b timestamp on update current_timestamp; +insert into t1 (a,b) values (1,default), (2,default),(3,'1900-01-01 1:00:00'); +alter table t1 replica identity full; +alter table t1 alter column b set data type timestamp using now() - a; diff --git a/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_rewrite.teardown b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_rewrite.teardown new file mode 100644 index 000000000..efb719a1f --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_rewrite.teardown @@ -0,0 +1,8 @@ +#!/bin/sh + +source $1/env_utils.sh $1 $2 +subscription_dir=$1 +case_use_db=$3 + +exec_sql $case_use_db $sub_node1_port "set search_path=rewrite;alter table t1_repl_index drop column myc" +exec_sql $case_use_db $sub_node1_port "set search_path=rewrite;delete from t1_repl_index where a in (101,102)" diff --git a/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_subpartition.setup b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_subpartition.setup new file mode 100644 index 000000000..853b24cd5 --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_subpartition.setup @@ -0,0 +1,24 @@ +#!/bin/sh + +source $1/env_utils.sh $1 $2 +subscription_dir=$1 +case_use_db=$3 + +exec_sql $case_use_db $pub_node1_port "create tablespace ts_subpart_hash_1 relative location 'test/ts_subpart_hash_1'"; + +exec_sql $case_use_db $pub_node1_port "create tablespace ts_subpart_hash_2 relative location 'test/ts_subpart_hash_2'"; +exec_sql $case_use_db $pub_node1_port "create tablespace ts_subpart_hash_test_user relative location 'test/ts_subpart_hash_test_user';" +exec_sql $case_use_db $pub_node1_port "create user user_subpart_hash password 'Test@123';" + +exec_sql $case_use_db $pub_node1_port "grant CREATE, USAGE on schema schema_vastbase_subpartition_hash to user_subpart_hash"; +exec_sql $case_use_db $pub_node1_port "grant CREATE on tablespace ts_subpart_hash_test_user to user_subpart_hash;" + +exec_sql $case_use_db $sub_node1_port "create tablespace ts_subpart_hash_1 relative location 'test/ts_subpart_hash_1'"; + +exec_sql $case_use_db $sub_node1_port "create tablespace ts_subpart_hash_2 relative location 'test/ts_subpart_hash_2'"; +exec_sql $case_use_db $sub_node1_port "create tablespace ts_subpart_hash_test_user relative location 'test/ts_subpart_hash_test_user';" +exec_sql $case_use_db $sub_node1_port "create user user_subpart_hash password 'Test@123';" + +exec_sql $case_use_db $sub_node1_port "grant CREATE, USAGE on schema schema_vastbase_subpartition_hash to user_subpart_hash"; +exec_sql $case_use_db $sub_node1_port "grant CREATE on tablespace ts_subpart_hash_test_user to user_subpart_hash;" + diff --git a/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_subpartition.sql b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_subpartition.sql new file mode 100644 index 000000000..52b3c2328 --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_alter_table_subpartition.sql @@ -0,0 +1,2242 @@ +CREATE schema schema_vastbase_subpartition_hash; +set search_path to schema_vastbase_subpartition_hash; +-- init +set datestyle = 'ISO, MDY'; +set behavior_compat_options = ''; + +create table t_subpart_normal_table_hash(id int); +create table t_subpart_part_table_hash(id int) +partition by hash(id) +( + partition p1 +); + + + +---------------------------- +-- Hash subpartition syntax +---------------------------- +-- 二级分区、二级分区键相同、自动创建子分区、手动指定子分区 +create table t_subpart_range_hash_1 (id integer, age integer, name varchar(30), sale integer) +partition by range(age) +subpartition by hash(age) +( +partition p1 values less than (10), +partition p2 values less than (100) + ( + subpartition sp1, + subpartition sp2 + ), +partition p3 values less than (200) +); + +create table t_subpart_list_hash_1 (id integer, age integer, name varchar(30), sale integer) +partition by list(age) +subpartition by hash(age) +( +partition p1 values (1, 2, 3, 4, 5), +partition p2 values (10, 20, 30, 40, 50) + ( + subpartition sp1, + subpartition sp2 + ), +partition p3 values (111, 222, 333) +); + +create table t_subpart_hash_hash_1 (id integer, age integer, name varchar(30), sale integer) +partition by hash(age) +subpartition by hash(age) +( +partition p1, +partition p2 + ( + subpartition sp1, + subpartition sp2 + ), +partition p3 +); + +-- 二级分区,子分区模板、用模板创建子分区、DEFAULT +create table t_subpart_range_hash_2 (id integer, age numeric, name varchar(30), bd date) +partition by range(age) +subpartition by hash(id) + subpartition template + ( + subpartition sp1, + subpartition sp2 + ) +( +partition p1 values less than (10), +partition p2 values less than (100) + ( + subpartition sp1, + subpartition sp2 + ), +partition p3 values less than (MAXVALUE) + ( + subpartition sp3, + subpartition sp4 + ) +); + +create table t_subpart_list_hash_2 (id integer, age numeric, name varchar(30), bd date) +partition by list(age) +subpartition by hash(id) + subpartition template + ( + subpartition sp1, + subpartition sp2 + ) +( +partition p1 values (1, 2, 3, 4, 5), +partition p2 values (10, 20, 30, 40, 50) + ( + subpartition sp1, + subpartition sp2 + ), +partition p3 values (100, 200) + ( + subpartition sp3, + subpartition sp4 + ) +); + +create table t_subpart_hash_hash_2 (id integer, age numeric, name varchar(30), bd date) +partition by hash(age) +subpartition by hash(id) + subpartition template + ( + subpartition sp1, + subpartition sp2 + ) +( +partition p1, +partition p2 + ( + subpartition sp1, + subpartition sp2 + ), +partition p3 + ( + subpartition sp3, + subpartition sp4 + ) +); + +-- 指定Hash分区或子分区个数 +create table t_subpart_range_hash_3 (id integer, age numeric, name text, bd timestamp) +partition by range(id, age) +subpartition by hash(id) + subpartitions 2 +( +partition p1 values less than (10, 10.6789), +partition p2 values less than (100, 12345.6789) + subpartitions 3, +partition p3 values less than (MAXVALUE, MAXVALUE) + ( + subpartition sp1, + subpartition sp2 + ) +); + +create table t_subpart_list_hash_3 (id integer, age numeric, name text, bd timestamp) +partition by list(age) +subpartition by hash(id) + subpartitions 2 +( +partition p1 values (10, 10.6789), +partition p2 values (100, 12345.6789) + subpartitions 3, +partition p3 values (DEFAULT) + ( + subpartition sp1, + subpartition sp2 + ) +); + +create table t_subpart_hash_hash_3 (id integer, age numeric, name text, bd timestamp) +partition by hash(age) +subpartition by hash(id) + subpartitions 2 +( +partition p1, +partition p2 + subpartitions 3, +partition p3 + ( + subpartition sp1, + subpartition sp2 + ) +); + +create table t_subpart_hash_hash_4 (id integer, age numeric, name text, bd timestamp) +partition by hash(age) +subpartition by hash(id) + subpartitions 2 +partitions 3; + +-- 检查:分区/子分区数量、分区/子分区类型、分区与子分区关系、分区范围、relfilenode、Toast +select p1.tablename, p1.relname, p1.parttype, p1.partstrategy, p1.subpartstrategy, +p1.parentid, p1.boundaries, p1.relfilenode, p1.reltoastrelid +from schema_subpartition.v_subpartition p1 +where p1.tablename like 't_subpart_range_hash_%' + or p1.tablename like 't_subpart_list_hash_%' + or p1.tablename like 't_subpart_hash_hash_%'; + +-- 检查子分区模板 +select p1.tablename, p1.subparttemplate +from schema_subpartition.v_subpartition p1 +where p1.subparttemplate is not null + and (p1.tablename like 't_subpart_range_hash_%' + or p1.tablename like 't_subpart_list_hash_%' + or p1.tablename like 't_subpart_hash_hash_%'); + +select get_subpart_template('t_subpart_range_hash_1'::regclass, 0) is null; +select pg_get_tabledef('t_subpart_range_hash_1'); +select get_subpart_template('t_subpart_range_hash_2'::regclass, 0); +select get_subpart_template('t_subpart_list_hash_3'::regclass, 2); +select get_subpart_template('t_subpart_hash_hash_4'::regclass, 4); +select pg_get_tabledef('t_subpart_range_hash_2'); +select pg_get_tabledef('t_subpart_list_hash_3'); +select pg_get_tabledef('t_subpart_hash_hash_4'); + +-- 分区键为float4 +create table t_subpart_range_hash_float4 (col1 float4) +partition by range(col1) +subpartition by hash(col1) + subpartition template + ( + subpartition sp1, + subpartition sp2 + ) +( +partition p1 values less than (-34.84), +partition p2 values less than (0), +partition p3 values less than (1004.3) + ( + subpartition sp1, + subpartition sp2 + ), +partition p4 values less than (1.2345678901234e+20) +); + +create table t_subpart_list_hash_float4 (col1 float4) +partition by list(col1) +subpartition by hash(col1) + subpartition template + ( + subpartition sp1, + subpartition sp2 + ) +( +partition p1 values (-3.1, -3.14, -3.141, -3.1415, -3.14159, -3.141592, -3.1415926), +partition p2 values (0, 10, 100, 1000, 10000) + ( + subpartition sp1, + subpartition sp2 + ), +partition p3 values (1.2345678901234e-20, 1.2345678901234e-10, 1.2345678901234e+10, 1.2345678901234e+20) +); + +create table t_subpart_hash_hash_float4 (col1 float4) +partition by hash(col1) +subpartition by hash(col1) + subpartition template + ( + subpartition sp1, + subpartition sp2 + ) +( +partition p1, +partition p2 + ( + subpartition sp1, + subpartition sp2 + ), +partition p3 +); + +-- 分区键为float8 +create table t_subpart_range_hash_float8 (col1 float8) +partition by range(col1) +subpartition by hash(col1) + subpartition template + ( + subpartition sp1, + subpartition sp2 + ) +( +partition p1 values less than (-34.84), +partition p2 values less than (0), +partition p3 values less than (1004.3) + ( + subpartition sp1, + subpartition sp2 + ), +partition p4 values less than (1.2345678901234e+200) +); + +create table t_subpart_list_hash_float8 (col1 float8) +partition by list(col1) +subpartition by hash(col1) + subpartition template + ( + subpartition sp1, + subpartition sp2 + ) +( +partition p1 values (-3.1, -3.14, -3.141, -3.1415, -3.14159, -3.141592, -3.1415926), +partition p2 values (0, 10, 100, 1000, 10000) + ( + subpartition sp1, + subpartition sp2 + ), +partition p3 values (1.2345678901234e-200, 1.2345678901234e-100, 1.2345678901234e+100, 1.2345678901234e+200) +); + +create table t_subpart_hash_hash_float8 (col1 float8) +partition by hash(col1) +subpartition by hash(col1) + subpartition template + ( + subpartition sp1, + subpartition sp2 + ) +( +partition p1, +partition p2 + ( + subpartition sp1, + subpartition sp2 + ), +partition p3 +); + +-- 检查:分区/子分区数量、分区/子分区类型、分区与子分区关系、分区范围、relfilenode、Toast +select p1.tablename, p1.relname, p1.parttype, p1.partstrategy, p1.subpartstrategy, +p1.parentid, p1.boundaries, p1.relfilenode, p1.reltoastrelid +from schema_subpartition.v_subpartition p1 +where p1.tablename like 't_subpart_range_hash_float%' + or p1.tablename like 't_subpart_list_hash_float%' + or p1.tablename like 't_subpart_hash_hash_float%'; + +-- 检查子分区模板 +select p1.tablename, p1.subparttemplate +from schema_subpartition.v_subpartition p1 +where p1.subparttemplate is not null + and (p1.tablename like 't_subpart_range_hash_float%' + or p1.tablename like 't_subpart_list_hash_float%' + or p1.tablename like 't_subpart_hash_hash_float%'); + +---------------------------- +-- 主键、索引 +---------------------------- +create table t_subpart_range_hash_7 (id integer primary key, age numeric, name varchar(30), bd date) +partition by range(id) +subpartition by hash(id) + subpartition template + ( + subpartition sp1, + subpartition sp2 + ) +( +partition p1 values less than (100), +partition p2 values less than (500) + ( + subpartition sp1, + subpartition sp2 + ) +); + +create table t_subpart_list_hash_7 (id integer primary key, age numeric, name varchar(30), bd date) +partition by list(id) +subpartition by hash(id) + subpartition template + ( + subpartition sp1, + subpartition sp2 + ) +( +partition p1 values (100), +partition p2 values (500) + ( + subpartition sp1, + subpartition sp2 + ) +); + +create table t_subpart_hash_hash_7 (id integer primary key, age numeric, name varchar(30), bd date) +partition by hash(id) +subpartition by hash(id) + subpartition template + ( + subpartition sp1, + subpartition sp2 + ) +( +partition p1, +partition p2 + ( + subpartition sp1, + subpartition sp2 + ) +); + + +create table t_subpart_range_hash_8 (id integer, age numeric, name char(30), bd date, + CONSTRAINT i_t_subpart_range_hash_8 PRIMARY KEY (id, age, name)) +partition by range(age, name) +subpartition by hash(id) +( +partition p1 values less than (20, 'AAA') +); + +create table t_subpart_list_hash_8 (id integer, age numeric, name char(30), bd date, + CONSTRAINT i_t_subpart_list_hash_8 PRIMARY KEY (id, age, name)) +partition by list(age) +subpartition by hash(id) +( +partition p1 values (20) +); + +create table t_subpart_hash_hash_8 (id integer, age integer, name char(30), bd date, + CONSTRAINT i_t_subpart_hash_hash_8 PRIMARY KEY (id, age, name)) +partition by hash(age) +subpartition by hash(id) +( +partition p1 +); + +-- 建表时指定PRIMARY KEY/UNIQUE索引(分区索引),索引键必须包含所有分区键,否则变为全局索引 +create table t_subpart_range_hash_9 (id integer, age numeric, name char(30), bd date, + CONSTRAINT i_t_subpart_range_hash_9 PRIMARY KEY (age, name)) +partition by range(age, name) +subpartition by hash(id) +( +partition p1 values less than (100, 'AAA') +); + +create table t_subpart_list_hash_9 (id integer, age numeric, name char(30), bd date, + CONSTRAINT i_t_subpart_list_hash_9 PRIMARY KEY (id, name)) +partition by list(age) +subpartition by hash(id) +( +partition p1 values (100) +); + +create table t_subpart_hash_hash_9 (id integer, age numeric, name char(30), bd date, + CONSTRAINT i_t_subpart_hash_hash_9 PRIMARY KEY (bd, name)) +partition by hash(age) +subpartition by hash(id) +( +partition p1 +); + +-- 为二级分区添加全局UNIQUE索引,可以不用包含所有分区键 +create unique index i_t_subpart_range_hash_8_1 on t_subpart_range_hash_8 (id, bd); +create unique index i_t_subpart_list_hash_8_1 on t_subpart_list_hash_8 (id, bd); +create unique index i_t_subpart_hash_hash_8_1 on t_subpart_hash_hash_8 (id, bd); + + +create table t_subpart_range_hash_10 (id integer, age numeric, name char(30), bd date) +partition by range(age, name) +subpartition by hash(id) +( +partition p1 values less than (10, 'AAA') + ( + subpartition sp1 + ), +partition p2 values less than (100, 'MAXVALUE') + ( + subpartition sp2, + subpartition sp3 + ) +); + +create table t_subpart_list_hash_10 (id integer, age numeric, name char(30), bd date) +partition by list(age) +subpartition by hash(id) +( +partition p1 values (10) + ( + subpartition sp1 + ), +partition p2 values (100) + ( + subpartition sp2, + subpartition sp3 + ) +); + +create table t_subpart_hash_hash_10 (id integer, age integer, name char(30), bd date) +partition by hash(age) +subpartition by hash(id) +( +partition p1 + ( + subpartition sp1 + ), +partition p2 + ( + subpartition sp2, + subpartition sp3 + ) +); + +-- 为二级分区添加本地分区索引 +create unique index i_t_subpart_range_hash_10_1 on t_subpart_range_hash_10 (id) local; -- error +create unique index i_t_subpart_range_hash_10_1 on t_subpart_range_hash_10 (name, age) local; -- error +create unique index i_t_subpart_range_hash_10_1 on t_subpart_range_hash_10 (age, name, id) local; +create index i_t_subpart_range_hash_10_2 on t_subpart_range_hash_10 (name, age) local; + +create unique index i_t_subpart_list_hash_10_1 on t_subpart_list_hash_10 (age) local; -- error +create unique index i_t_subpart_list_hash_10_1 on t_subpart_list_hash_10 (name, bd) local; -- error +create unique index i_t_subpart_list_hash_10_1 on t_subpart_list_hash_10 (age, id) local; +create index i_t_subpart_list_hash_10_2 on t_subpart_list_hash_10 (name, age) local; + +create unique index i_t_subpart_hash_hash_10_1 on t_subpart_hash_hash_10 (bd) local; -- error +create unique index i_t_subpart_hash_hash_10_1 on t_subpart_hash_hash_10 (name, bd) local; -- error +create unique index i_t_subpart_hash_hash_10_1 on t_subpart_hash_hash_10 (age, id, bd) local; +create index i_t_subpart_hash_hash_10_2 on t_subpart_hash_hash_10 (age, bd) local; + +-- 为二级分区添加本地分区索引,指定索引分区名 +create index i_t_subpart_range_hash_10_3 on t_subpart_range_hash_10 (bd) local +( +partition p1_idx + ( + subpartition subp1_index_local + ), +partition p2_idx + ( + subpartition subp2_index_local + ) +); -- error +create index i_t_subpart_range_hash_10_3 on t_subpart_range_hash_10 (bd) local +( +partition p1_idx + ( + subpartition subp1_bd_idx_local + ), +partition p2_idx + ( + subpartition subp2_bd_idx_local, + subpartition subp3_bd_idx_local + ) +); + +create index i_t_subpart_list_hash_10_3 on t_subpart_list_hash_10 (bd) local +( +partition p1_idx + ( + subpartition subp1_index_local + ), +partition p2_idx + ( + subpartition subp2_index_local + ) +); -- error +create index i_t_subpart_list_hash_10_3 on t_subpart_list_hash_10 (bd) local +( +partition p1_idx + ( + subpartition subp1_bd_idx_local + ), +partition p2_idx + ( + subpartition subp2_bd_idx_local, + subpartition subp3_bd_idx_local + ) +); + +create index i_t_subpart_hash_hash_10_3 on t_subpart_hash_hash_10 (bd) local +( +partition p1_idx + ( + subpartition subp1_index_local + ), +partition p2_idx + ( + subpartition subp2_index_local + ) +); -- error +create index i_t_subpart_hash_hash_10_3 on t_subpart_hash_hash_10 (bd) local +( +partition p1_idx + ( + subpartition subp1_bd_idx_local + ), +partition p2_idx + ( + subpartition subp2_bd_idx_local, + subpartition subp3_bd_idx_local + ) +); + +-- 为二级分区添加全局索引(目前跟普通索引没发现有什么区别) +create unique index i_t_subpart_range_hash_10_4 on t_subpart_range_hash_10 (name, age) global; -- error +create unique index i_t_subpart_range_hash_10_4 on t_subpart_range_hash_10 (age, bd) global; +drop index i_t_subpart_range_hash_10_2; +create unique index i_t_subpart_range_hash_10_5 on t_subpart_range_hash_10 (name, age) global; + +create unique index i_t_subpart_list_hash_10_4 on t_subpart_list_hash_10 (name, age) global; -- error +create unique index i_t_subpart_list_hash_10_4 on t_subpart_list_hash_10 (name, bd) global; +drop index i_t_subpart_list_hash_10_2; +create unique index i_t_subpart_list_hash_10_5 on t_subpart_list_hash_10 (name, age) global; + +create unique index i_t_subpart_hash_hash_10_4 on t_subpart_hash_hash_10 (bd, age) global; -- error +create unique index i_t_subpart_hash_hash_10_4 on t_subpart_hash_hash_10 (name, id) global; +drop index i_t_subpart_hash_hash_10_2; +create unique index i_t_subpart_hash_hash_10_5 on t_subpart_hash_hash_10 (bd, age) global; + + +-- 分区索引检查 +select p1.tablename, p1.relname, p1.reltoastidxid, p1.indextblid +from schema_subpartition.v_subpartition p1 +where p1.tablename in ('t_subpart_range_hash_7', 't_subpart_range_hash_8', 't_subpart_range_hash_10'); + +select p1.tablename, p1.relname, p1.reltoastidxid, p1.indextblid +from schema_subpartition.v_subpartition p1 +where p1.tablename in ('t_subpart_list_hash_7', 't_subpart_list_hash_8', 't_subpart_list_hash_10'); + +select p1.tablename, p1.relname, p1.reltoastidxid, p1.indextblid +from schema_subpartition.v_subpartition p1 +where p1.tablename in ('t_subpart_hash_hash_7', 't_subpart_hash_hash_8', 't_subpart_hash_hash_10'); + + +-- 索引查看 +select * from pg_indexes where tablename like 't_subpart_range_hash_%' order by tablename, indexname; +select * from pg_indexes where tablename like 't_subpart_list_hash_%' order by tablename, indexname; +select * from pg_indexes where tablename like 't_subpart_hash_hash_%' order by tablename, indexname; + + +-- \d +\d t_subpart_range_hash_8 +\d t_subpart_list_hash_8 +\d t_subpart_hash_hash_8 +\d t_subpart_range_hash_10 +\d t_subpart_list_hash_10 +\d t_subpart_hash_hash_10 + + + +---------------------------- +-- 测试[子]分区表空间 +---------------------------- +create table t_subpart_range_hash_11 (id integer, age numeric, name varchar(30), bd date) +partition by range(age) +subpartition by hash(id) + subpartition template + ( + subpartition sp1 tablespace ts_subpart_hash_1, + subpartition sp2 + ) +( +partition p1 values less than (10), +partition p2 values less than (100) tablespace ts_subpart_hash_2, +partition p3 values less than (1000) + ( + subpartition sp1 tablespace ts_subpart_hash_1, + subpartition sp2 + ), +partition p4 values less than (MAXVALUE) tablespace ts_subpart_hash_2 + ( + subpartition sp3 tablespace ts_subpart_hash_1, + subpartition sp4 + ) +); + +create table t_subpart_list_hash_11 (id integer, age numeric, name varchar(30), bd date) +partition by list(age) +subpartition by hash(id) + subpartition template + ( + subpartition sp1 tablespace ts_subpart_hash_1, + subpartition sp2 + ) +( +partition p1 values (10), +partition p2 values (20) tablespace ts_subpart_hash_2, +partition p3 values (30) + ( + subpartition sp1 tablespace ts_subpart_hash_1, + subpartition sp2 + ), +partition p4 values (DEFAULT) tablespace ts_subpart_hash_2 + ( + subpartition sp3 tablespace ts_subpart_hash_1, + subpartition sp4 + ) +); + +create table t_subpart_hash_hash_11 (id integer, age numeric, name varchar(30), bd date) +partition by hash(age) +subpartition by hash(id) + subpartition template + ( + subpartition sp1 tablespace ts_subpart_hash_1, + subpartition sp2 + ) +( +partition p1, +partition p2 tablespace ts_subpart_hash_2, +partition p3 + ( + subpartition sp1 tablespace ts_subpart_hash_1, + subpartition sp2 + ), +partition p4 tablespace ts_subpart_hash_2 + ( + subpartition sp3 tablespace ts_subpart_hash_1, + subpartition sp4 + ) +); + +create table t_subpart_hash_hash_11_2 (id integer, age numeric, name varchar(30), bd date) +partition by hash(age) +subpartition by hash(id) + subpartitions 3 store in (ts_subpart_hash_1, ts_subpart_hash_2) +partitions 5 store in (ts_subpart_hash_2, ts_subpart_hash_1); + +-- TODO 目前不支持添加Hash分区或Hash子分区 +alter table t_subpart_hash_hash_11_2 add partition p6; +alter table t_subpart_hash_hash_11_2 modify partition p6 add subpartition p6_sp3; + +-- 检查子分区的表空间 +select p1.tablename, p1.relname, p1.parttype, p2.spcname tablespace_name +from schema_subpartition.v_subpartition p1 left join pg_tablespace p2 on p1.reltablespace = p2.oid +where p1.tablename in ('t_subpart_range_hash_11', 't_subpart_list_hash_11', 't_subpart_hash_hash_11', 't_subpart_hash_hash_11_2') +order by p1.parentid, p1.oid; + +-- 检查子分区模板 +select p1.tablename, p1.subparttemplate +from schema_subpartition.v_subpartition p1 +where p1.subparttemplate is not null + and p1.tablename in ('t_subpart_range_hash_11', 't_subpart_list_hash_11', 't_subpart_hash_hash_11', 't_subpart_hash_hash_11_2'); + + +-- error, 没有表空间权限 +SET SESSION AUTHORIZATION user_subpart_hash PASSWORD 'Test@123'; +create table t_subpart_hash_hash_12 (id integer, age numeric, name varchar(30), bd date) +partition by hash(age) +subpartition by hash(id) + subpartition template + ( + subpartition sp1 tablespace ts_subpart_hash_test_user, + subpartition sp2 tablespace ts_subpart_hash_1 + ) +( +partition p1 +); + +create table t_subpart_hash_hash_12 (id integer, age numeric, name varchar(30), bd date) +partition by hash(age) +subpartition by hash(id) +( +partition p1 tablespace ts_subpart_hash_test_user, +partition p2 tablespace ts_subpart_hash_1 +); + +create table t_subpart_hash_hash_12 (id integer, age numeric, name varchar(30), bd date) +partition by hash(age) +subpartition by hash(id) +( +partition p1 + ( + subpartition sp1 tablespace ts_subpart_hash_test_user, + subpartition sp2 tablespace ts_subpart_hash_1 + ) +); + +create table t_subpart_hash_hash_12 (id integer, age numeric, name varchar(30), bd date) +partition by hash(age) +subpartition by hash(id) + subpartitions 2 store in (ts_subpart_hash_test_user, ts_subpart_hash_1) +( +partition p1 +); + +create table t_subpart_hash_hash_12 (id integer, age numeric, name varchar(30), bd date) +partition by hash(age) +subpartition by hash(id) +partitions 2 store in (ts_subpart_hash_test_user, ts_subpart_hash_1); + +create table t_subpart_hash_hash_12 (id integer, age numeric, name varchar(30), bd date) +partition by hash(age) +subpartition by hash(id) +( +partition p1 + subpartitions 2 store in (ts_subpart_hash_test_user, ts_subpart_hash_1) +); + +RESET SESSION AUTHORIZATION; + + + +---------------------------- +-- syntax error +---------------------------- +-- 分区定义中包含了多余的子分区定义 +create table t_subpart_error (id integer, name varchar(30)) +partition by range(id) +( +partition p1 values less than (10) + ( + subpartition sp1 + ) +); + +create table t_subpart_error (id integer, name varchar(30)) +partition by list(id) +( +partition p1 values (10) + ( + subpartition sp1 + ) +); + +create table t_subpart_error (id integer, name varchar(30)) +partition by hash(id) +( +partition p1 + ( + subpartition sp1 + ) +); + + +-- 子分区名重复 +create table t_subpart_error (id integer, name varchar(30)) +partition by range(name) +subpartition by hash(id) +( +partition p1 values less than ('a') + ( + subpartition sp1 + ), +partition p2 values less than ('A') + ( + subpartition sp1 + ) +); + +create table t_subpart_error (id integer, name varchar(30)) +partition by list(name) +subpartition by hash(id) +( +partition p1 values ('a') + ( + subpartition sp1 + ), +partition p2 values ('A') + ( + subpartition sp1 + ) +); + +create table t_subpart_error (id integer, name int8) +partition by hash(name) +subpartition by hash(id) +( +partition p1 + ( + subpartition sp1 + ), +partition p2 + ( + subpartition sp1 + ) +); + + +-- 子分区模板中子分区名重复 +create table t_subpart_error (id integer, name varchar(30)) +partition by range(name) +subpartition by hash(id) + subpartition template + ( + subpartition sp1, + subpartition sp1 + ) +( +partition p1 values less than ('a') +); + +create table t_subpart_error (id integer, name varchar(30)) +partition by list(name) +subpartition by hash(id) + subpartition template + ( + subpartition sp1, + subpartition sp1 + ) +( +partition p1 values ('a') +); + +create table t_subpart_error (id integer, name int2) +partition by hash(name) +subpartition by hash(id) + subpartition template + ( + subpartition sp1, + subpartition sp1 + ) +( +partition p1 +); + + +-- 分区名与子分区名重复 +create table t_subpart_error (id integer, name varchar(30)) +partition by range(name) +subpartition by hash(id) +( +partition p1 values less than ('10') + ( + subpartition sp1 + ), +partition p2 values less than ('100') + ( + subpartition p1 + ) +); + +create table t_subpart_error (id integer, name varchar(30)) +partition by list(id) +subpartition by hash(id) +( +partition p1 values ('10') + ( + subpartition sp1 + ), +partition p2 values ('100') + ( + subpartition p1 + ) +); + +create table t_subpart_error (id integer, name int4) +partition by hash(name) +subpartition by hash(id) +( +partition p1 + ( + subpartition sp1 + ), +partition p2 + ( + subpartition p1 + ) +); +create table t_subpart_error (id integer, name int4) +partition by hash(name) +subpartition by hash(id) +( +partition p1 + ( + subpartition sp1 + ), +partition sp1 + ( + subpartition sp2 + ) +); + + +-- 自动生成的子分区名重复 +create table t_subpart_error (id integer, name text) +partition by range(name) +subpartition by hash(id) +( +partition p1 values less than ('10') + ( + subpartition p2_subpartdefault1 + ), +partition p2 values less than ('100') +); +drop table t_subpart_error; +create table t_subpart_error (id integer, name text) +partition by list(name) +subpartition by hash(id) +( +partition p1 values ('10') + ( + subpartition p2_subpartdefault1 + ), +partition p2 values ('100') +); +drop table t_subpart_error; +create table t_subpart_error (id integer, name integer) +partition by hash(name) +subpartition by hash(id) +( +partition p1 + ( + subpartition p2_subpartdefault1 + ), +partition p2 +); +drop table t_subpart_error; +create table t_subpart_error (id integer, name varchar(30)) +partition by hash(id) +subpartition by hash(id) +( +partition p1, +partition p2 + ( + subpartition p1_subpartdefault1 + ) +); +drop table t_subpart_error; + +-- 子分区键个数错误 +create table t_subpart_error (id integer, name varchar(30), age int, bd varchar(30), addr varchar(30)) +partition by hash(id) +subpartition by hash(id, name, age, bd, addr) +( +partition p1 +); + + +-- 子分区键类型错误 +create table t_subpart_error (id integer, name varchar(30), m money) +partition by hash(id) +subpartition by hash(m) +( +partition p1 +); +create table t_subpart_error (id integer, name varchar(30), m money) -- now is ok +partition by hash(id) +subpartition by hash(name) +( +partition p1 +); +drop table t_subpart_error; +create table t_subpart_error (id integer, name varchar(30), bd date) -- now is ok +partition by hash(id) +subpartition by hash(bd) +( +partition p1 +); +drop table t_subpart_error; + + +-- Hash子分区使用了Range分区定义语法 +create table t_subpart_error (id integer, name varchar(30), age int) +partition by hash(id) +subpartition by hash(age) +( +partition p1 + ( + subpartition sp1 values less than (1) + ) +); +create table t_subpart_error (id integer, name varchar(30), age int) +partition by hash(id) +subpartition by hash(age) +( +partition p1 + ( + subpartition sp1 end (1) + ) +); + +-- Hash子分区使用了List分区定义语法 +create table t_subpart_error (id integer, name varchar(30)) +partition by hash(id) +subpartition by hash(name) +( +partition p1 + ( + subpartition sp1 values ('a', 'b') + ) +); + +-- Hash子分区模板,使用了Range/List分区定义语法 +create table t_subpart_error (id integer, name varchar(30)) +partition by hash(id) +subpartition by hash(name) + subpartition template + ( + subpartition sp1 values less than (1) + ) +( +partition p1 +); +create table t_subpart_error (id integer, name varchar(30)) +partition by hash(id) +subpartition by hash(name) + subpartition template + ( + subpartition sp1 end (1) + ) +( +partition p1 +); +create table t_subpart_error (id integer, name varchar(30)) +partition by hash(id) +subpartition by hash(name) + subpartition template + ( + subpartition sp1 values ('a') + ) +( +partition p1 +); + + +-- 子分区模板语法有误 +create table t_subpart_error (id integer, name integer) +partition by hash(id) +subpartition by hash(name) + subpartition template + ( + subpartition sp1 + ( + subpartition ssp1 values (DEFAULT) + ) + ) +( +partition p1 +); + + +-- DEFAULT[子]分区定义异常情况: +---- 不能只有一个DEFAULT分区(是从语法上限制) +---- 第一个[子]分区不能为DEFAULT +-- 注:但是自动生成的子分区可以只有一个DEFAULT子分区 +create table t_subpart_error (id integer, name integer) +partition by hash(id) +subpartition by hash(name) + subpartition template + ( + subpartition sp1 values (DEFAULT) + ) +( +partition p1 +); +create table t_subpart_error (id integer, name integer) +partition by hash(id) +subpartition by hash(name) + subpartition template + ( + subpartition sp1 values (DEFAULT), + subpartition sp2 + ) +( +partition p1 +); +create table t_subpart_error (id integer, name integer) +partition by hash(id) +subpartition by hash(name) +( +partition p1 + ( + subpartition sp1 values (DEFAULT) + ) +); +create table t_subpart_error (id integer, name integer) +partition by hash(id) +subpartition by hash(name) +( +partition p1 + ( + subpartition sp1 values (DEFAULT), + subpartition sp2 + ) +); + + + +---------------------------- +-- 不允许[子]分区键修改 +---------------------------- +alter table t_subpart_hash_hash_2 drop column age; +alter table t_subpart_hash_hash_2 drop column id; +alter table t_subpart_hash_hash_2 modify (age numeric(6,1)); +alter table t_subpart_hash_hash_2 modify (id text); + + + +---------------------------- +-- 新增分区 +---------------------------- +alter table t_subpart_range_hash_1 add partition p4 values less than (300); +alter table t_subpart_range_hash_1 add partition p5 start (300) end (400) +( + subpartition sp3, + subpartition sp4, + subpartition sp5 +); +alter table t_subpart_range_hash_1 add partition p6 values less than (500) +( + subpartition sp6, + subpartition sys_subp4294967295 +); + +alter table t_subpart_list_hash_1 add partition p4 values (300); +alter table t_subpart_list_hash_1 add partition p5 values (400) +( + subpartition sp3, + subpartition sp4, + subpartition sp5 +); +alter table t_subpart_list_hash_1 add partition p6 values (500) +( + subpartition sp6, + subpartition sys_subp4294967295 +); + +alter table t_subpart_hash_hash_1 add partition p4; +alter table t_subpart_hash_hash_1 add partition p5 +( + subpartition sp3, + subpartition sp4, + subpartition sp5 +); +alter table t_subpart_hash_hash_1 add partition p6 +( + subpartition sp6, + subpartition sys_subp4294967295 +); + + +alter table t_subpart_range_hash_7 add partition p3 end (1000); +alter table t_subpart_range_hash_7 add partition p4 values less than (2000) +( + subpartition sp3, + subpartition p5_sp2 +); +alter table t_subpart_range_hash_10 add partition p3 values less than (MAXVALUE, MAXVALUE) +( + subpartition sp4, + subpartition sp5 +); + +alter table t_subpart_list_hash_7 add partition p3 values (1000); +alter table t_subpart_list_hash_7 add partition p4 values (2000) +( + subpartition sp3, + subpartition p5_sp2 +); +alter table t_subpart_list_hash_10 add partition p3 values (DEFAULT) +( + subpartition sp4, + subpartition sp5 +); +alter table t_subpart_hash_hash_7 add partition p3; +alter table t_subpart_hash_hash_7 add partition p4 +( + subpartition sp3, + subpartition p5_sp2 +); +alter table t_subpart_hash_hash_10 add partition p3 +( + subpartition sp4, + subpartition sp5 +); + + +---- 普通表不能添加分区 +alter table t_subpart_normal_table_hash add partition p1; +alter table t_subpart_normal_table_hash add partition p2 +( + subpartition sp1, + subpartition sp2 +); + +---- 一级分区表不能添加子分区 +alter table t_subpart_part_table_hash add partition p2 +( + subpartition sp1, + subpartition sp2 +); + + +---- [子]分区类型与[子]分区定义不匹配 +alter table t_subpart_range_hash_1 add partition p_error values (500); +alter table t_subpart_range_hash_1 add partition p_error; +alter table t_subpart_range_hash_1 add partition p7 end (500) +( + subpartition sp_error values less than (100) +); +alter table t_subpart_range_hash_1 add partition p7 end (500) +( + subpartition sp_error start (100) +); +alter table t_subpart_range_hash_1 add partition p7 end (500) +( + subpartition sp_error values (0) +); + +alter table t_subpart_list_hash_1 add partition p_error values less than (500); +alter table t_subpart_list_hash_1 add partition p_error; +alter table t_subpart_list_hash_1 add partition p7 values (700) +( + subpartition sp_error end (100) +); +alter table t_subpart_list_hash_1 add partition p7 values (700) +( + subpartition sp_error values (0) +); + +alter table t_subpart_hash_hash_1 add partition p_error values less than (500); +alter table t_subpart_hash_hash_1 add partition p_error end (500); +alter table t_subpart_hash_hash_1 add partition p_error values (0); +alter table t_subpart_hash_hash_1 add partition p7 +( + subpartition sp_error values less than (100) +); +alter table t_subpart_hash_hash_1 add partition p7 +( + subpartition sp_error end (100) +); +alter table t_subpart_hash_hash_1 add partition p7 +( + subpartition sp_error values (1) +); +alter table t_subpart_hash_hash_1 add partition p7 +( + subpartition sp_error +); +alter table t_subpart_hash_hash_1 add partitions 1; +alter table t_subpart_hash_hash_1 add partition p7 +( + subpartitions 2 +); + + +---- 名称重复 +alter table t_subpart_hash_hash_1 add partition p_error +( + subpartition sp3, + subpartition sp3 +); +alter table t_subpart_hash_hash_1 add partition p_error +( + subpartition sp3, + subpartition p_error +); +alter table t_subpart_hash_hash_1 add partition p_error +( + subpartition sp1, + subpartition sp22 +); +alter table t_subpart_hash_hash_1 add partition p_error +( + subpartition p1 +); +alter table t_subpart_hash_hash_7 add partition p3; +alter table t_subpart_hash_hash_7 add partition sp1; + +---- 生成子分区名已经存在 +alter table t_subpart_range_hash_7 add partition p5 values less than (MAXVALUE); +alter table t_subpart_list_hash_7 add partition p5 values (DEFAULT); +alter table t_subpart_hash_hash_7 add partition p5; + + +---- 存在MAXVALUE/DEFAULT分区,不能再添加 +alter table t_subpart_range_hash_10 add partition p_error values less than (9999, 9999); +alter table t_subpart_list_hash_10 add partition p_error values (9999); +alter table t_subpart_hash_hash_10 add partition p_error; + + + +---------------------------- +-- 新增子分区 +---------------------------- +alter table t_subpart_range_hash_1 modify partition p2 add subpartition p2_sp20; +alter table t_subpart_range_hash_10 modify partition p1 add subpartition p1_sp22; + +alter table t_subpart_list_hash_1 modify partition p2 add subpartition p2_sp20; +alter table t_subpart_list_hash_10 modify partition p1 add subpartition p1_sp22; + +alter table t_subpart_hash_hash_1 modify partition p2 add subpartition p2_sp20; +alter table t_subpart_hash_hash_10 modify partition p1 add subpartition p1_sp22; + + +---- 普通表不能添加子分区 +alter table t_subpart_normal_table_hash modify partition p1 add subpartition sp1; +alter table t_subpart_normal_table_hash modify partition p1 add subpartition sp1 +( + subpartition sp3, + subpartition sp4 +); + +---- 一级分区表不能添加子分区 +alter table t_subpart_part_table_hash modify partition p1 add subpartition sp1; +alter table t_subpart_part_table_hash modify partition p1 add subpartition sp1 +( + subpartition sp3, + subpartition sp4 +); + +---- 子分区类型与子分区定义不匹配 +alter table t_subpart_hash_hash_1 modify partition p2 add subpartition sp_error values less than (10); +alter table t_subpart_hash_hash_1 modify partition p2 add subpartition sp_error end (10); +alter table t_subpart_hash_hash_1 modify partition p2 add subpartition sp_error values (1000); + +---- 分区不存在 +alter table t_subpart_range_hash_1 modify partition p_error add subpartition sp_error; +alter table t_subpart_range_hash_1 modify partition for (999) add subpartition sp_error; +alter table t_subpart_list_hash_1 modify partition p_error add subpartition sp_error; +alter table t_subpart_list_hash_1 modify partition for (999) add subpartition sp_error; +alter table t_subpart_hash_hash_1 modify partition p_error add subpartition sp21; +alter table t_subpart_hash_hash_1 modify partition for (999) add subpartition sp_error; + +---- 名称重复 +alter table t_subpart_range_hash_1 modify partition p2 add subpartition sp1; +alter table t_subpart_range_hash_1 modify partition p2 add subpartition sp3; +alter table t_subpart_range_hash_1 modify partition p2 add subpartition p1; + +alter table t_subpart_list_hash_1 modify partition p2 add subpartition sp1; +alter table t_subpart_list_hash_1 modify partition p2 add subpartition sp3; +alter table t_subpart_list_hash_1 modify partition p2 add subpartition p1; + +alter table t_subpart_hash_hash_1 modify partition p2 add subpartition sp1; +alter table t_subpart_hash_hash_1 modify partition p2 add subpartition sp3; +alter table t_subpart_hash_hash_1 modify partition p2 add subpartition p1; + +alter table t_subpart_hash_hash_1 modify partition p2 add subpartitions 1; + +-- 检查,新增分区和子分区后的情况 +select p1.tablename, p1.relname, p1.parttype, p1.partstrategy, +p1.parentid, p1.boundaries, p1.relfilenode, p1.reltoastrelid +from schema_subpartition.v_subpartition p1 +where p1.tablename in ('t_subpart_range_hash_1', 't_subpart_range_hash_7', 't_subpart_range_hash_10', + 't_subpart_list_hash_1', 't_subpart_list_hash_7', 't_subpart_list_hash_10', + 't_subpart_hash_hash_1', 't_subpart_hash_hash_7', 't_subpart_hash_hash_10'); + + + +-- 检查,新增分区、子分区的表空间情况 +create table t_subpart_hash_hash_13 (id integer, age int) +partition by hash(id) +subpartition by hash(age) + subpartition template + ( + subpartition sp1 tablespace ts_subpart_hash_1, + subpartition sp2 + ) +( +partition p1, +partition p2 tablespace ts_subpart_hash_2, +partition p3 + ( + subpartition sp1 tablespace ts_subpart_hash_1, + subpartition sp2 + ), +partition p4 tablespace ts_subpart_hash_2 + ( + subpartition sp3 tablespace ts_subpart_hash_1, + subpartition sp4 + ) +); + +alter table t_subpart_hash_hash_13 add partition p5; +alter table t_subpart_hash_hash_13 add partition p6 tablespace ts_subpart_hash_2; +alter table t_subpart_hash_hash_13 add partition p7 tablespace ts_subpart_hash_2 +( + subpartition sp5, + subpartition sp6 tablespace ts_subpart_hash_1 +); +alter table t_subpart_hash_hash_13 add partition p8 +( + subpartition sp7, + subpartition sp8 tablespace ts_subpart_hash_1 +); + +alter table t_subpart_hash_hash_13 modify partition p1 add subpartition p1_sp20; +alter table t_subpart_hash_hash_13 modify partition p1 add subpartition p1_sp21 tablespace ts_subpart_hash_1; +alter table t_subpart_hash_hash_13 modify partition p2 add subpartition p2_sp22; +alter table t_subpart_hash_hash_13 modify partition p2 add subpartition p2_sp23 tablespace ts_subpart_hash_1; + + +-- error, 新增分区/子分区没有表空间权限 +SET SESSION AUTHORIZATION user_subpart_hash PASSWORD 'Test@123'; +create table t_subpart_hash_hash_14 (id integer, age integer) +partition by hash (id) +subpartition by hash (age) +( +partition p1 + ( + subpartition sp1 + ) +); + +alter table t_subpart_hash_hash_14 add partition p2 tablespace ts_subpart_hash_1; +alter table t_subpart_hash_hash_14 add partition p2 +( + subpartition sp2, + subpartition sp3 tablespace ts_subpart_hash_1 +); +alter table t_subpart_hash_hash_14 modify partition p1 add subpartition p1_sp2 tablespace ts_subpart_hash_1; + +drop table t_subpart_hash_hash_14; +RESET SESSION AUTHORIZATION; + +select p1.tablename, p1.relname, p1.parttype, p2.spcname tablespace_name +from schema_subpartition.v_subpartition p1 left join pg_tablespace p2 on p1.reltablespace = p2.oid +where p1.tablename = 't_subpart_hash_hash_13' +order by p1.parentid, p1.oid; + + + +---------------------------- +-- 删除分区 +---------------------------- +alter table t_subpart_range_hash_1 drop partition p6; +alter table t_subpart_range_hash_1 drop partition for (350); -- drop p5 +alter table t_subpart_range_hash_7 drop partition p3; +alter table t_subpart_range_hash_10 drop partition for (1, 'A'); -- drop p1 + +alter table t_subpart_list_hash_1 drop partition p6; +alter table t_subpart_list_hash_1 drop partition for (400); -- drop p5 +alter table t_subpart_list_hash_7 drop partition p3; +alter table t_subpart_list_hash_10 drop partition for (10); -- drop p1 + +alter table t_subpart_hash_hash_1 drop partition p6; +alter table t_subpart_hash_hash_1 drop partition for (4); -- drop p5 +alter table t_subpart_hash_hash_7 drop partition p3; +alter table t_subpart_hash_hash_10 drop partition for (10); -- drop p1 +alter table t_subpart_hash_hash_13 drop partition p4; + + +-- 删除分区不存在 +alter table t_subpart_range_hash_1 drop partition p_error; +alter table t_subpart_range_hash_7 drop partition for (9999); + +alter table t_subpart_list_hash_1 drop partition p_error; +alter table t_subpart_list_hash_7 drop partition for (9999); + +alter table t_subpart_hash_hash_1 drop partition p_error; +alter table t_subpart_hash_hash_7 drop partition for (9999); + + +-- 不能只保留DEFAULT分区 +alter table t_subpart_list_hash_10 drop partition p2; + + +-- 至少保留1个分区 +alter table t_subpart_range_hash_10 drop partition p3; -- ok +alter table t_subpart_range_hash_10 drop partition p2; -- error + +alter table t_subpart_list_hash_10 drop partition p3; -- ok +alter table t_subpart_list_hash_10 drop partition p2; -- error + +alter table t_subpart_hash_hash_10 drop partition p3; -- error +alter table t_subpart_hash_hash_10 drop partition p2; + + + +---------------------------- +-- 删除子分区 +---------------------------- +alter table t_subpart_range_hash_1 drop subpartition sp1; +alter table t_subpart_range_hash_7 drop subpartition for (100, 101); -- drop sp2 + +alter table t_subpart_list_hash_1 drop subpartition sp1; +alter table t_subpart_list_hash_7 drop subpartition for (500, 101); -- drop sp2 + +alter table t_subpart_hash_hash_1 drop subpartition sp1; +alter table t_subpart_hash_hash_7 drop subpartition for (1, 9); -- drop sp2 +alter table t_subpart_hash_hash_13 drop subpartition sp2; +alter table t_subpart_hash_hash_13 drop subpartition for (4, 100); -- drop p5_sp1 + +-- 删除子分区不存在 +alter table t_subpart_range_hash_1 drop subpartition sp_error; +alter table t_subpart_range_hash_7 drop subpartition for (100, 1); + +alter table t_subpart_list_hash_1 drop subpartition sp_error; +alter table t_subpart_list_hash_7 drop subpartition for (500, 1); + +alter table t_subpart_hash_hash_1 drop subpartition sp_error; +alter table t_subpart_hash_hash_7 drop subpartition for (501, 1); + +-- 至少保留1个子分区 +alter table t_subpart_range_hash_7 drop subpartition sp1; +alter table t_subpart_list_hash_7 drop subpartition sp1; +alter table t_subpart_hash_hash_7 drop subpartition sp1; + + +-- 检查,删除分区和子分区后的情况 +select p1.tablename, p1.relname, p1.parttype, p1.partstrategy, +p1.parentid, p1.boundaries, p1.relfilenode, p1.reltoastrelid +from schema_subpartition.v_subpartition p1 +where p1.tablename in ('t_subpart_range_hash_1', 't_subpart_range_hash_7', 't_subpart_range_hash_10', + 't_subpart_list_hash_1', 't_subpart_list_hash_7', 't_subpart_list_hash_10', + 't_subpart_hash_hash_1', 't_subpart_hash_hash_7', 't_subpart_hash_hash_10'); + +-- 检查,删除分区和子分区后的表空间情况 +select p1.tablename, p1.relname, p1.parttype, p2.spcname tablespace_name +from schema_subpartition.v_subpartition p1 left join pg_tablespace p2 on p1.reltablespace = p2.oid +where p1.tablename = 't_subpart_hash_hash_13' +order by p1.parentid, p1.oid; + + + +---------------------------- +-- 数据查 +---------------------------- +select * from t_subpart_range_hash_1 partition (p2); +select * from t_subpart_range_hash_1 partition for (10); +select * from t_subpart_range_hash_1 subpartition (sp2); +select * from t_subpart_range_hash_1 subpartition for (50, 51); + +select * from t_subpart_list_hash_1 partition (p2); +select * from t_subpart_list_hash_1 partition for (10); +select * from t_subpart_list_hash_1 subpartition (sp2); +select * from t_subpart_list_hash_1 subpartition for (50, 51); + +select * from t_subpart_hash_hash_1 partition (p2); +select * from t_subpart_hash_hash_1 partition for (1); +select * from t_subpart_hash_hash_1 subpartition (sp2); +select * from t_subpart_hash_hash_1 subpartition for (51, 51); + + + +---------------------------- +-- 数据改 +---------------------------- +update t_subpart_range_hash_1 partition (p2) set id = id + 10; +update t_subpart_range_hash_1 partition for (10) set id = id + 10; +update t_subpart_range_hash_1 subpartition (sp2) set id = id + 10; +update t_subpart_range_hash_1 subpartition for (50, 51) set id = id + 10; + +update t_subpart_list_hash_1 partition (p2) set id = id + 10; +update t_subpart_list_hash_1 partition for (10) set id = id + 10; +update t_subpart_list_hash_1 subpartition (sp2) set id = id + 10; +update t_subpart_list_hash_1 subpartition for (50, 51) set id = id + 10; + +update t_subpart_hash_hash_1 partition (p2) set id = id + 10; +update t_subpart_hash_hash_1 partition for (1) set id = id + 10; +update t_subpart_hash_hash_1 subpartition (sp2) set id = id + 10; +update t_subpart_hash_hash_1 subpartition for (51, 51) set id = id + 10; + + + +---------------------------- +-- 数据删 +---------------------------- +delete from t_subpart_range_hash_1 partition (p2); +delete from t_subpart_range_hash_1 partition for (10); +delete from t_subpart_range_hash_1 subpartition (sp2); +delete from t_subpart_range_hash_1 subpartition for (50, 51); + +delete from t_subpart_list_hash_1 partition (p2); +delete from t_subpart_list_hash_1 partition for (10); +delete from t_subpart_list_hash_1 subpartition (sp2); +delete from t_subpart_list_hash_1 subpartition for (50, 51); + +delete from t_subpart_hash_hash_1 partition (p2); +delete from t_subpart_hash_hash_1 partition for (1); +delete from t_subpart_hash_hash_1 subpartition (sp2); +delete from t_subpart_hash_hash_1 subpartition for (51, 51); + + + +---------------------------- +-- 分区执行计划 +---------------------------- +-- range-hash +create table t_subpart_range_hash_20 (id integer, name text) +partition by range(name) +subpartition by hash(name) +( +partition p1 values less than ('e'), +partition p2 values less than ('k') + ( + subpartition sp1, + subpartition sp2 + ), +partition p3 values less than (MAXVALUE) + ( + subpartition sp3, + subpartition sp4 + ) +); +insert into t_subpart_range_hash_20 values (1,'a'); +insert into t_subpart_range_hash_20 values (2,'e'); +insert into t_subpart_range_hash_20 values (3,'g'); +insert into t_subpart_range_hash_20 values (4,'m'); +insert into t_subpart_range_hash_20 values (5,'r'); +insert into t_subpart_range_hash_20 values (6,NULL); + +explain(costs off) select * from t_subpart_range_hash_20; + +explain(costs off) select * from t_subpart_range_hash_20 where name is null; +select * from t_subpart_range_hash_20 where name is null; +explain(costs off) select * from t_subpart_range_hash_20 where name is not null; +select * from t_subpart_range_hash_20 where name is not null; + +explain(costs off) select * from t_subpart_range_hash_20 where name = 'e'; +select * from t_subpart_range_hash_20 where name = 'e'; +explain(costs off) select * from t_subpart_range_hash_20 where name > 'e'; +select * from t_subpart_range_hash_20 where name > 'e'; +explain(costs off) select * from t_subpart_range_hash_20 where name >= 'e'; +select * from t_subpart_range_hash_20 where name >= 'e'; +explain(costs off) select * from t_subpart_range_hash_20 where name < 'e'; +select * from t_subpart_range_hash_20 where name < 'e'; +explain(costs off) select * from t_subpart_range_hash_20 where name <= 'e'; +select * from t_subpart_range_hash_20 where name <= 'e'; +explain(costs off) select * from t_subpart_range_hash_20 where name <> 'e'; +select * from t_subpart_range_hash_20 where name <> 'e'; + +explain(costs off) select * from t_subpart_range_hash_20 where name = 'e' and name is null; +select * from t_subpart_range_hash_20 where name = 'e' and name is null; +explain(costs off) select * from t_subpart_range_hash_20 where name = 'e' or name is null; +select * from t_subpart_range_hash_20 where name = 'e' or name is null; + +explain(costs off) select * from t_subpart_range_hash_20 where name in ('r', NULL); +select * from t_subpart_range_hash_20 where name in ('r', NULL); +explain(costs off) select * from t_subpart_range_hash_20 where name = any(array['e', 'g']) or name in ('r', NULL); +select * from t_subpart_range_hash_20 where name = any(array['e', 'g']) or name in ('r', NULL); + + +-- list-hash +create table t_subpart_list_hash_20 (id integer, age integer, name text) +partition by list(age) +subpartition by hash(name) +( +partition p1 values (1, 2, 3), +partition p2 values (10, 20, 50, 60) + ( + subpartition sp1, + subpartition sp2 + ), +partition p3 values (DEFAULT) + ( + subpartition sp3, + subpartition sp4 + ) +); +insert into t_subpart_list_hash_20 values (1, 1, NULL); +insert into t_subpart_list_hash_20 values (2, 20, 'b'); +insert into t_subpart_list_hash_20 values (3, 50, 'f'); +insert into t_subpart_list_hash_20 values (4, 100, NULL); +insert into t_subpart_list_hash_20 values (5, NULL, 'g'); +insert into t_subpart_list_hash_20 values (6, NULL, NULL); + +explain(costs off) select * from t_subpart_list_hash_20; + +explain(costs off) select * from t_subpart_list_hash_20 where age is null; +select * from t_subpart_list_hash_20 where age is null; +explain(costs off) select * from t_subpart_list_hash_20 where age is not null; +select * from t_subpart_list_hash_20 where age is not null; +explain(costs off) select * from t_subpart_list_hash_20 where name is null; +select * from t_subpart_list_hash_20 where name is null; +explain(costs off) select * from t_subpart_list_hash_20 where name is not null; +select * from t_subpart_list_hash_20 where name is not null; + +explain(costs off) select * from t_subpart_list_hash_20 where age is null and name is null; +select * from t_subpart_list_hash_20 where age is null and name is null; +explain(costs off) select * from t_subpart_list_hash_20 where age is null or name is null; +select * from t_subpart_list_hash_20 where age is null or name is null; + +explain(costs off) select * from t_subpart_list_hash_20 where age = 20; +select * from t_subpart_list_hash_20 where age = 20; +explain(costs off) select * from t_subpart_list_hash_20 where name = 'b'; +select * from t_subpart_list_hash_20 where name = 'b'; +explain(costs off) select * from t_subpart_list_hash_20 where age = 20 and name = 'b'; +select * from t_subpart_list_hash_20 where age = 20 and name = 'b'; +explain(costs off) select * from t_subpart_list_hash_20 where age = 20 or name = 'b'; +select * from t_subpart_list_hash_20 where age = 20 or name = 'b'; + +explain(costs off) select * from t_subpart_list_hash_20 where age is null and name = 'b'; +select * from t_subpart_list_hash_20 where age is null and name = 'b'; +explain(costs off) select * from t_subpart_list_hash_20 where age is null or name = 'b'; +select * from t_subpart_list_hash_20 where age is null or name = 'b'; +explain(costs off) select * from t_subpart_list_hash_20 where age = 20 and name is null; +select * from t_subpart_list_hash_20 where age = 20 and name is null; +explain(costs off) select * from t_subpart_list_hash_20 where age = 20 or name is null; +select * from t_subpart_list_hash_20 where age = 20 or name is null; + +explain(costs off) select * from t_subpart_list_hash_20 where name = any(array['g', NULL]); +select * from t_subpart_list_hash_20 where name = any(array['g', NULL]); +explain(costs off) select * from t_subpart_list_hash_20 where age in (20, 200) and name = any(array['g', NULL]); +select * from t_subpart_list_hash_20 where age in (20, 200) and name = any(array['g', NULL]); + + +-- hash-hash +create table t_subpart_hash_hash_20 (id integer, name text, bd time) +partition by hash(name) +subpartition by hash(bd) +( +partition p1, +partition p2 + ( + subpartition sp1, + subpartition sp2 + ), +partition p3 + ( + subpartition sp3, + subpartition sp4 + ) +); +insert into t_subpart_hash_hash_20 values (1, 'a', '1:2:3'); +insert into t_subpart_hash_hash_20 values (2, 'g', NULL); +insert into t_subpart_hash_hash_20 values (3, 'h', '11:2:3'); +insert into t_subpart_hash_hash_20 values (4, 'o', NULL); +insert into t_subpart_hash_hash_20 values (5, 't', '21:0:0'); +insert into t_subpart_hash_hash_20 values (6, NULL, NULL); + +explain(costs off) select * from t_subpart_hash_hash_20; + +explain(costs off) select * from t_subpart_hash_hash_20 where name is null; +select * from t_subpart_hash_hash_20 where name is null; +explain(costs off) select * from t_subpart_hash_hash_20 where name is not null; +select * from t_subpart_hash_hash_20 where name is not null; +explain(costs off) select * from t_subpart_hash_hash_20 where bd is null; +select * from t_subpart_hash_hash_20 where bd is null; +explain(costs off) select * from t_subpart_hash_hash_20 where bd is not null; +select * from t_subpart_hash_hash_20 where bd is not null; +explain(costs off) select * from t_subpart_hash_hash_20 where name is null and bd is null; +select * from t_subpart_hash_hash_20 where name is null and bd is null; + +explain(costs off) select * from t_subpart_hash_hash_20 where name = 'g'; +select * from t_subpart_hash_hash_20 where name = 'g'; +explain(costs off) select * from t_subpart_hash_hash_20 where bd = '11:2:3'; +select * from t_subpart_hash_hash_20 where bd = '11:2:3'; +explain(costs off) select * from t_subpart_hash_hash_20 where name = 'g' and bd = '11:2:3'; +select * from t_subpart_hash_hash_20 where name = 'g' and bd = '11:2:3'; +explain(costs off) select * from t_subpart_hash_hash_20 where name = 'g' or bd = '11:2:3'; +select * from t_subpart_hash_hash_20 where name = 'g' or bd = '11:2:3'; + +explain(costs off) select * from t_subpart_hash_hash_20 where name is null and bd = '11:2:3'; +select * from t_subpart_hash_hash_20 where name is null and bd = '11:2:3'; +explain(costs off) select * from t_subpart_hash_hash_20 where name is null or bd = '11:2:3'; +select * from t_subpart_hash_hash_20 where name is null or bd = '11:2:3'; +explain(costs off) select * from t_subpart_hash_hash_20 where name = 'g' and bd is null; +select * from t_subpart_hash_hash_20 where name = 'g' and bd is null; +explain(costs off) select * from t_subpart_hash_hash_20 where name = 'g' or bd is null; +select * from t_subpart_hash_hash_20 where name = 'g' or bd is null; + +explain(costs off) select * from t_subpart_hash_hash_20 where bd = any(array['11:2:3'::time, '21:0:0'::time]); +select * from t_subpart_hash_hash_20 where bd = any(array['11:2:3'::time, '21:0:0'::time]); +explain(costs off) select * from t_subpart_hash_hash_20 where name in ('g','o') and bd = any(array['11:2:3'::time, '21:0:0'::time]); +select * from t_subpart_hash_hash_20 where name in ('g','o') and bd = any(array['11:2:3'::time, '21:0:0'::time]); + + + +---------------------------- +-- TRUNCATE 分区、子分区 +---------------------------- +-- PARTITION [FOR] +alter table t_subpart_range_hash_1 truncate partition p1; +alter table t_subpart_range_hash_1 truncate partition for (10); +alter table t_subpart_range_hash_10 truncate partition p2; +alter table t_subpart_range_hash_10 truncate partition for (10, 'MAXVALUE'); + +alter table t_subpart_list_hash_1 truncate partition p1; +alter table t_subpart_list_hash_1 truncate partition for (10); +alter table t_subpart_list_hash_10 truncate partition p2; +alter table t_subpart_list_hash_10 truncate partition for (100); + +alter table t_subpart_hash_hash_1 truncate partition p1; +alter table t_subpart_hash_hash_1 truncate partition for (0); +alter table t_subpart_hash_hash_7 truncate partition p1; +alter table t_subpart_hash_hash_7 truncate partition for (100); +alter table t_subpart_hash_hash_10 truncate partition p2; +alter table t_subpart_hash_hash_10 truncate partition for (1); + +-- SUBPARTITION [FOR] +alter table t_subpart_range_hash_1 truncate subpartition p1_subpartdefault1; +alter table t_subpart_range_hash_1 truncate subpartition for (100, 51); +alter table t_subpart_range_hash_10 truncate subpartition sp2; +alter table t_subpart_range_hash_10 truncate subpartition for (10, 'MAXVALUE', 9); + +alter table t_subpart_list_hash_1 truncate subpartition p1_subpartdefault1; +alter table t_subpart_list_hash_1 truncate subpartition for (10, 51); +alter table t_subpart_list_hash_10 truncate subpartition sp2; +alter table t_subpart_list_hash_10 truncate subpartition for (100, 9); + +alter table t_subpart_hash_hash_1 truncate subpartition p1_subpartdefault1; +alter table t_subpart_hash_hash_1 truncate subpartition for (11, 51); +alter table t_subpart_hash_hash_7 truncate subpartition sp1; +alter table t_subpart_hash_hash_7 truncate subpartition for (101, 10); +alter table t_subpart_hash_hash_10 truncate subpartition sp2; +alter table t_subpart_hash_hash_10 truncate subpartition for (1, 7); + + +-- 分区或子分区不存在 +alter table t_subpart_range_hash_1 truncate partition p_error; +alter table t_subpart_range_hash_1 truncate partition for (300); +alter table t_subpart_range_hash_1 truncate subpartition sp_error; +alter table t_subpart_range_hash_1 truncate subpartition for (10, 4); -- ok + +alter table t_subpart_list_hash_1 truncate partition p_error; +alter table t_subpart_list_hash_1 truncate partition for (999); +alter table t_subpart_list_hash_1 truncate subpartition sp_error; +alter table t_subpart_list_hash_1 truncate subpartition for (10, 4); -- ok + +alter table t_subpart_hash_hash_1 truncate partition p_error; +alter table t_subpart_hash_hash_1 truncate partition for (4); -- ok +alter table t_subpart_hash_hash_1 truncate subpartition sp_error; +alter table t_subpart_hash_hash_1 truncate subpartition for (11, 4); -- ok + + + +---------------------------- +-- 下面部分只做了语法的简单检查,避免coredump,具体功能还不支持 +---------------------------- +-- TODO SET 子分区模板 +alter table t_subpart_range_hash_1 set subpartition template +( + subpartition sp1, + subpartition sp2 +); + +alter table t_subpart_list_hash_1 set subpartition template +( + subpartition sp1, + subpartition sp2 +); + +alter table t_subpart_hash_hash_1 set subpartition template +( + subpartition sp1, + subpartition sp2 +); + + + +---------------------------- +-- TODO SPLIT [SUB]PARTITION [FOR] +---------------------------- +-- TODO SPLIT RANGE PARTITION [FOR] +alter table t_subpart_range_hash_2 split partition p1 at (5) into (partition p1_1, partition p1_2); +alter table t_subpart_range_hash_2 split partition for (50) at (50) into (partition p2_1, partition p2_2); +-- oracle中最后一个分区的范围不用指定 +alter table t_subpart_range_hash_2 split partition p3 into (partition p3_1 end (200), partition p3_2 end (300), partition p3_3 end (400), partition p3_4 end (500), partition p3_5 end (MAXVALUE)); +alter table t_subpart_range_hash_2 split partition for (50) into (partition p2_2_1 values less than (60), partition p2_2_2 values less than (100)); + +-- error, RANGE 不支持 VALUES ... INTO +alter table t_subpart_range_hash_2 split partition p1_1 values (5) into (partition p1_1_1, partition p1_1_2); + + +-- TODO SPLIT LIST PARTITION [FOR] +alter table t_subpart_list_hash_2 split partition p1 values (5) into (partition p1_1, partition p1_2); +alter table t_subpart_list_hash_2 split partition for (100) values (200) into (partition p1_1, partition p1_2); +alter table t_subpart_list_hash_2 split partition p2 into (partition p3_1 values (10), partition p3_2 values (20), partition p3_3 values (30), partition p3_4 values (40), partition p3_5 values (50)); + +-- error, LIST 不支持 AT ... INTO +alter table t_subpart_list_hash_2 split partition p1 at (3) into (partition p1_1, partition p1_2); +alter table t_subpart_list_hash_2 split partition for (3) at (3) into (partition p1_1 values (10), partition p1_2 values (20.6789)); + + +-- HASH 分区不支持SPLIT +alter table t_subpart_hash_hash_2 split partition p1 at (5) into (partition p1_1, partition p1_2); +alter table t_subpart_hash_hash_2 split partition for (0) at (5) into (partition p1_1, partition p1_2); +alter table t_subpart_hash_hash_2 split partition p2 values (5) into (partition p1_1, partition p1_2); +alter table t_subpart_hash_hash_2 split partition p3 into (partition p3_1 values less than (100), partition p3_2 values less than (200)); + +-- HASH 子分区不支持SPLIT +alter table t_subpart_hash_hash_3 split subpartition sp1 at ('a') into (subpartition sp1_1, subpartition sp1_2); +alter table t_subpart_hash_hash_3 split subpartition for (100, '1') at ('a') into (subpartition sp2_1, subpartition sp2_2 ); +alter table t_subpart_hash_hash_3 split subpartition sp1 values ('a') into (subpartition sp1_1, subpartition sp1_2); +alter table t_subpart_hash_hash_3 split subpartition for (100, '1') values ('1', '2') into (subpartition sp2_1, subpartition sp2_2 ); +alter table t_subpart_hash_hash_3 split subpartition sp3 into (subpartition sp3_1 values ('A'), subpartition sp3_2 values ('B'), subpartition sp3_3 values ('C'), subpartition sp3_4 values ('D', 'E')); +alter table t_subpart_hash_hash_3 split subpartition for (300, '1') into (subpartition sp5_1 values ('1', '2', '3', '4', '5'), subpartition sp5_2 values ('A', 'B', 'C', 'D', 'E'), subpartition sp5_3 values (DEFAULT)); + + +-- TODO HASH分区也有对应的拆分分区语法 + + +-- TODO SPLIT INDEX PARTITION + + + +---------------------------- +-- TODO MERGE [SUB]PARTITIONS [FOR] +-- MERGE TO 只支持Range分区,合并相邻的所有分区 +---------------------------- +-- TODO MERGE RANGE PARTITIONS [FOR] +alter table t_subpart_range_hash_1 merge partitions p1,p2 into partition p12; +alter table t_subpart_range_hash_1 merge partitions for (1), for (10), for (100), for (200) into partition p1234; +alter table t_subpart_range_hash_1 merge partitions p1 to p4 into partition p1234; + +-- TODO MERGE LIST PARTITION [FOR] +alter table t_subpart_list_hash_1 merge partitions p1,p2 into partition p12; +alter table t_subpart_list_hash_1 merge partitions for (1), for (10), for (70), for (222) into partition p1234; + +alter table t_subpart_list_hash_1 merge partitions p1 to p4 into partition p1234; -- error + +-- TODO Hash分区不支持MERGE语法 +alter table t_subpart_hash_hash_1 merge partitions p1,p1 into partition p12; +alter table t_subpart_hash_hash_1 merge partitions for (0), for (1) into partition p12; +alter table t_subpart_hash_hash_1 merge partitions p1 to p3 into partition p123; + +alter table t_subpart_hash_hash_1 merge subpartitions sp1,sp1 into subpartition sp12; +alter table t_subpart_hash_hash_1 merge subpartitions for (1, 0), for (1, 1) into subpartition p12; +alter table t_subpart_hash_hash_1 merge subpartitions sp1 to sp2 into subpartition sp12; + + +-- TODO HASH分区也有对应的合并分区语法 + + + +---------------------------- +-- TODO EXCHANGE PARTITION [FOR] +---------------------------- +create table t_subpart_range_hash_8_exchange (like t_subpart_range_hash_8); +alter table t_subpart_range_hash_8_exchange add primary key (id, age, name); +create table t_subpart_list_hash_8_exchange (like t_subpart_list_hash_8); +alter table t_subpart_list_hash_8_exchange add primary key (id, age, name); +create table t_subpart_hash_hash_8_exchange (like t_subpart_hash_hash_8); +alter table t_subpart_hash_hash_8_exchange add primary key (id, age, name); + +alter table t_subpart_range_hash_8 EXCHANGE PARTITION (p1) with table t_subpart_range_hash_8_exchange WITHOUT VALIDATION; +alter table t_subpart_range_hash_8 EXCHANGE PARTITION (p1) with table t_subpart_range_hash_8_exchange; +alter table t_subpart_range_hash_8 EXCHANGE PARTITION p1 with table t_subpart_range_hash_8_exchange WITH VALIDATION; +alter table t_subpart_range_hash_8 EXCHANGE PARTITION for (20, 'A') with table t_subpart_range_hash_8_exchange VERBOSE; +alter table t_subpart_range_hash_8 EXCHANGE PARTITION for (19, 'BBB') with table t_subpart_range_hash_8_exchange WITH VALIDATION VERBOSE; + +alter table t_subpart_list_hash_8 EXCHANGE PARTITION (p1) with table t_subpart_list_hash_8_exchange WITHOUT VALIDATION; +alter table t_subpart_list_hash_8 EXCHANGE PARTITION (p1) with table t_subpart_list_hash_8_exchange; +alter table t_subpart_list_hash_8 EXCHANGE PARTITION p1 with table t_subpart_list_hash_8_exchange WITH VALIDATION; +alter table t_subpart_list_hash_8 EXCHANGE PARTITION for (20) with table t_subpart_list_hash_8_exchange VERBOSE; +alter table t_subpart_list_hash_8 EXCHANGE PARTITION for (20)with table t_subpart_list_hash_8_exchange WITH VALIDATION VERBOSE; + +alter table t_subpart_hash_hash_8 EXCHANGE PARTITION (p1) with table t_subpart_hash_hash_8_exchange WITHOUT VALIDATION; +alter table t_subpart_hash_hash_8 EXCHANGE PARTITION (p1) with table t_subpart_hash_hash_8_exchange; +alter table t_subpart_hash_hash_8 EXCHANGE PARTITION p1 with table t_subpart_hash_hash_8_exchange WITH VALIDATION; +alter table t_subpart_hash_hash_8 EXCHANGE PARTITION for (10) with table t_subpart_hash_hash_8_exchange VERBOSE; +alter table t_subpart_hash_hash_8 EXCHANGE PARTITION for (10) with table t_subpart_hash_hash_8_exchange WITH VALIDATION VERBOSE; + + + +---------------------------- +-- EXCHANGE SUBPARTITION [FOR] +---------------------------- +alter table t_subpart_range_hash_8 EXCHANGE SUBPARTITION p1_subpartdefault1 with table t_subpart_range_hash_8_exchange WITHOUT VALIDATION; +alter table t_subpart_range_hash_8 EXCHANGE SUBPARTITION p1_subpartdefault1 with table t_subpart_range_hash_8_exchange; +alter table t_subpart_range_hash_8 EXCHANGE SUBPARTITION p1_subpartdefault1 with table t_subpart_range_hash_8_exchange WITH VALIDATION; +alter table t_subpart_range_hash_8 EXCHANGE SUBPARTITION for (20, 'A', '10') with table t_subpart_range_hash_8_exchange VERBOSE; +alter table t_subpart_range_hash_8 EXCHANGE SUBPARTITION for (19, 'BBB', '10') with table t_subpart_range_hash_8_exchange WITH VALIDATION VERBOSE; + +alter table t_subpart_list_hash_8 EXCHANGE SUBPARTITION p1_subpartdefault1 with table t_subpart_list_hash_8_exchange WITHOUT VALIDATION; +alter table t_subpart_list_hash_8 EXCHANGE SUBPARTITION p1_subpartdefault1 with table t_subpart_list_hash_8_exchange; +alter table t_subpart_list_hash_8 EXCHANGE SUBPARTITION p1_subpartdefault1 with table t_subpart_list_hash_8_exchange WITH VALIDATION; +alter table t_subpart_list_hash_8 EXCHANGE SUBPARTITION for (20, '20') with table t_subpart_list_hash_8_exchange VERBOSE; +alter table t_subpart_list_hash_8 EXCHANGE SUBPARTITION for (20, '20') with table t_subpart_list_hash_8_exchange WITH VALIDATION VERBOSE; + +alter table t_subpart_hash_hash_8 EXCHANGE SUBPARTITION p1_subpartdefault1 with table t_subpart_hash_hash_8_exchange WITHOUT VALIDATION; +alter table t_subpart_hash_hash_8 EXCHANGE SUBPARTITION p1_subpartdefault1 with table t_subpart_hash_hash_8_exchange; +alter table t_subpart_hash_hash_8 EXCHANGE SUBPARTITION p1_subpartdefault1 with table t_subpart_hash_hash_8_exchange WITH VALIDATION; +alter table t_subpart_hash_hash_8 EXCHANGE SUBPARTITION for (10, '20') with table t_subpart_hash_hash_8_exchange VERBOSE; +alter table t_subpart_hash_hash_8 EXCHANGE SUBPARTITION for (10, '20') with table t_subpart_hash_hash_8_exchange WITH VALIDATION VERBOSE; + + +drop table t_subpart_range_hash_8_exchange; +drop table t_subpart_list_hash_8_exchange; +drop table t_subpart_hash_hash_8_exchange; + + + +-- TODO List分区 MODIFY ADD/DROP VALUES (...) +-- alter table xxx modify partition p1 add values (); +-- alter table xxx modify partition p1 drop values (); +-- alter table xxx modify subpartition p1 add values (); +-- alter table xxx modify subpartition p1 addropd values (); + + + +---------------------------- +-- TODO MOVE [SUB]PARTITION [FOR] +---------------------------- +alter table t_subpart_range_hash_10 move partition p1 tablespace ts_subpart_hash_1; +alter table t_subpart_range_hash_10 move partition for (10, 'MAXVALUE') tablespace ts_subpart_hash_1; +alter table t_subpart_range_hash_10 move subpartition sp2 tablespace ts_subpart_hash_2; +alter table t_subpart_range_hash_10 move subpartition for (10, 'MAXVALUE', '1') tablespace ts_subpart_hash_2; + +alter table t_subpart_list_hash_10 move partition p1 tablespace ts_subpart_hash_1; +alter table t_subpart_list_hash_10 move partition for (100) tablespace ts_subpart_hash_1; +alter table t_subpart_list_hash_10 move subpartition sp2 tablespace ts_subpart_hash_2; +alter table t_subpart_list_hash_10 move subpartition for (100, '1') tablespace ts_subpart_hash_2; + +alter table t_subpart_hash_hash_10 move partition p1 tablespace ts_subpart_hash_1; +alter table t_subpart_hash_hash_10 move partition for (1) tablespace ts_subpart_hash_1; +alter table t_subpart_hash_hash_10 move subpartition sp2 tablespace ts_subpart_hash_2; +alter table t_subpart_hash_hash_10 move subpartition for (1, '1') tablespace ts_subpart_hash_2; + + + +---------------------------- +-- TODO ROW MOVEMENT +---------------------------- +alter table t_subpart_range_hash_10 enable row movement; +alter table t_subpart_range_hash_10 disable row movement; + +alter table t_subpart_list_hash_10 enable row movement; +alter table t_subpart_list_hash_10 disable row movement; + +alter table t_subpart_hash_hash_10 enable row movement; +alter table t_subpart_hash_hash_10 disable row movement; + + + +---------------------------- +-- ALTER INDEX ... UNUSABLE +-- ALTER INDEX ... REBUILD +-- ALTER INDEX ... MODIFY [SUB]PARTITION name UNUSABLE +-- ALTER INDEX ... REBUILD [SUB]PARTITION name +---------------------------- +alter index i_t_subpart_hash_hash_10_3 UNUSABLE; +-- 本地分区索引,索引只有一级分区,可以混用关键字PARTITION和SUBPARTITION, +-- 后面指定的是索引的分区名,而不是表的分区名(与oracle有差别) +alter index i_t_subpart_hash_hash_10_3 REBUILD partition subp1_bd_idx_local; +alter index i_t_subpart_hash_hash_10_3 REBUILD subpartition subp3_bd_idx_local; + +alter index i_t_subpart_hash_hash_10_4 UNUSABLE; +alter index i_t_subpart_hash_hash_10_4 REBUILD partition subp1_index_local; -- error +alter index i_t_subpart_hash_hash_10_4 REBUILD subpartition subp3_index_local; -- error + +select relname, parttype, indisusable from pg_partition where parentid='i_t_subpart_hash_hash_10_3'::regclass order by relname; +select relname, relkind, parttype, indisusable from pg_class left join pg_index on pg_class.oid=indexrelid where pg_class.oid in ('i_t_subpart_hash_hash_10_3'::regclass, 'i_t_subpart_hash_hash_10_4'::regclass) order by relname; + +explain (costs off) +select * from t_subpart_hash_hash_10 where bd = '2999-01-01'; + +-- alter index i_t_subpart_hash_hash_10_3 REBUILD; +-- alter index i_t_subpart_hash_hash_10_4 REBUILD; + +explain (costs off) +select * from t_subpart_hash_hash_10 where bd = '2999-01-01'; + +alter index i_t_subpart_hash_hash_10_3 modify partition subp1_bd_idx_local unusable; +alter index i_t_subpart_hash_hash_10_3 modify subpartition subp3_bd_idx_local unusable; + +explain (costs off) +select * from t_subpart_hash_hash_10 where bd = '2999-01-01'; + +select relname, parttype, indisusable from pg_partition where parentid='i_t_subpart_hash_hash_10_3'::regclass order by relname; +select relname, relkind, parttype, indisusable from pg_class left join pg_index on pg_class.oid=indexrelid where pg_class.oid in ('i_t_subpart_hash_hash_10_3'::regclass, 'i_t_subpart_hash_hash_10_4'::regclass) order by relname; + + + +---------------------------- +-- ALTER TABLE ... MODIFY [SUB]PARTITION [FOR] ... [REBUILD] UNUSABLE LOCAL INDEXES +---------------------------- +alter table t_subpart_hash_hash_10 modify partition p1 unusable local indexes; +alter table t_subpart_hash_hash_10 modify partition for (3) unusable local indexes; +select relname, parttype, indisusable from pg_partition where parentid='i_t_subpart_hash_hash_10_3'::regclass order by relname; + +explain (costs off) +select * from t_subpart_hash_hash_10 where bd = '2999-01-01'; + +alter table t_subpart_hash_hash_10 modify partition p1 REBUILD unusable local indexes; +alter table t_subpart_hash_hash_10 modify partition for (3) REBUILD unusable local indexes; +select relname, parttype, indisusable from pg_partition where parentid='i_t_subpart_hash_hash_10_3'::regclass order by relname; + +explain (costs off) +select * from t_subpart_hash_hash_10 where bd = '2999-01-01'; + +alter table t_subpart_hash_hash_10 modify subpartition sp1 unusable local indexes; +alter table t_subpart_hash_hash_10 modify subpartition for (3, NULL) unusable local indexes; +select relname, parttype, indisusable from pg_partition where parentid='i_t_subpart_hash_hash_10_3'::regclass order by relname; + +explain (costs off) +select * from t_subpart_hash_hash_10 where bd = '2999-01-01'; + +alter table t_subpart_hash_hash_10 modify subpartition sp1 REBUILD unusable local indexes; +alter table t_subpart_hash_hash_10 modify subpartition for (3, NULL) REBUILD unusable local indexes; +select relname, parttype, indisusable from pg_partition where parentid='i_t_subpart_hash_hash_10_3'::regclass order by relname; + +explain (costs off) +select * from t_subpart_hash_hash_10 where bd = '2999-01-01'; + + + +---------------------------- +-- TODO RENAME +---------------------------- +alter table t_subpart_hash_hash_10 rename partition p2 to p0; +alter table t_subpart_hash_hash_10 rename partition p0 to p2; + +alter table t_subpart_hash_hash_10 rename subpartition sp2 to sp0; +alter table t_subpart_hash_hash_10 rename subpartition sp0 to sp2; + + + +-- TODO 大批量创建分区、子分区 + +-- TODO 分区系统视图 +select table_name,partitioning_type,subpartitioning_type,partition_count, +def_subpartition_count,partitioning_key_count,subpartitioning_key_count +from all_part_tables where lower(table_name) in ('t_subpart_range_hash_11', 't_subpart_list_hash_11', 't_subpart_hash_hash_11') order by table_name; + +select (table_owner is not null) as has_owner,table_name,partition_name,subpartition_name from all_tab_subpartitions where lower(table_name) in ('t_subpart_range_hash_11', 't_subpart_list_hash_11', 't_subpart_hash_hash_11') order by table_name,partition_name,subpartition_name; + +select (table_owner is not null) as has_owner,table_name,partition_name,subpartition_count from all_tab_partitions where lower(table_name) in ('t_subpart_range_hash_11', 't_subpart_list_hash_11', 't_subpart_hash_hash_11') order by table_name,partition_name; + + + +-- TODO 列存二级分区表 +CREATE TABLE t_subpart_cstore_hh (id integer, name varchar(30), db date) +with ( orientation = column ) +partition by hash(id) +subpartition by hash(db) +( +partition p1 +); + + + +---------------------------- +-- ERROR +---------------------------- +-- VALUES分区不支持子分区 +create table t_subpart_error (id integer, name varchar(30)) +partition by VALUES(id) +subpartition by hash(id); +-- 不支持VALUES子分区 +create table t_subpart_error (id integer, name varchar(30)) +partition by hash(id) +subpartition by VALUES(name) +( +partition p1 +); + +create table t_subpart_interval (id integer, name varchar(30), db date) +partition by range(db) +INTERVAL ('1 day') +subpartition by hash(id) +( +partition p1 values less than ('2000-01-01') +); +-- 二级分区暂不支持interval子分区 +create table t_subpart_error (id integer, name varchar(30), db date) +partition by hash(id) +subpartition by range(db) +INTERVAL ('1 day') +( +partition p1 +); + + + +-- 检查“游离”的分区、子分区和分区索引,期望为0 +select oid,relname from pg_class +where (relkind = 'r' and parttype != 'n' and oid not in (select distinct parentid from pg_partition where parttype='r')) + or (relkind = 'i' and parttype != 'n' and oid not in (select distinct parentid from pg_partition where parttype='x')); + +select p1.relname, p1.parttype, p1.parentid, p1.boundaries +from pg_partition p1 +where (p1.parttype = 'r' and p1.parentid not in (select oid from pg_class where relkind = 'r' and parttype != 'n')) -- 分区表不存在pg_class条目 + or (p1.parttype = 'r' and not exists (select oid from pg_partition where parttype='p' and parentid=p1.parentid)) -- 分区表不存在分区 + or (p1.parttype = 'p' and not exists (select oid from pg_partition where parttype='r' and parentid=p1.parentid)) -- 表分区不存在主表 + or (p1.parttype = 'p' and exists (select oid from pg_class where parttype='s' and oid=p1.parentid) and not exists (select oid from pg_partition where parttype='s' and parentid=p1.oid)) -- 二级分区表的分区不存在子分区 + or (p1.parttype = 's' and not exists (select oid from pg_partition where parttype='p' and oid=p1.parentid)) -- 二级分区不存在父分区 + or (p1.parttype = 'x' and p1.parentid not in (select oid from pg_class where relkind = 'i' and parttype != 'n')) -- 分区索引不存在主索引 + or (p1.indextblid != 0 and p1.indextblid not in (select oid from pg_partition where parttype != 'r')); -- 分区索引不存在主表 + +drop index i_t_subpart_hash_hash_10_3, i_t_subpart_hash_hash_10_4; + +-- 清理环境 +-- drop table t_subpart_normal_table_hash, t_subpart_part_table_hash; +-- drop schema schema_vastbase_subpartition_hash cascade; +-- drop tablespace ts_subpart_hash_1; +-- drop tablespace ts_subpart_hash_2; +-- drop tablespace ts_subpart_hash_test_user; +-- drop user user_subpart_hash; diff --git a/src/test/subscription/testcase/ddl_replication_sql/B/ddl_create_trigger.sql b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_create_trigger.sql new file mode 100644 index 000000000..0c11b1e25 --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_create_trigger.sql @@ -0,0 +1,109 @@ +create table employees(id int,salary int); + +create or replace trigger t +before insert or update of salary,id +or delete on employees +begin +case +when inserting then +dbms_output.put_line('inserting'); +when updating ('salary') then +dbms_output.put_line('updating salary'); +when updating ('id') then +dbms_output.put_line('updating id'); +when deleting then +dbms_output.put_line('deleting'); +end case; +end; +/ + +create table oldtab(id int,c1 char(8)); +create table newtab(id int,c1 int); + +create or replace trigger tri1 +after insert on oldtab +for each statement +begin +insert into newtab values(1,1),(2,2),(3,3); +end; +/ + +create or replace trigger tri2 +after update on oldtab +for each statement +begin +update newtab set c1=4 where id=2; +end; +/ + +create or replace trigger tri4 +after truncate on oldtab +for each statement +begin +insert into newtab values(4,4); +end; +/ + +create table oldtab2(id int,c1 char(8)); +create table newtab2(id int,c1 int); + +CREATE OR REPLACE FUNCTION func_tri21() +RETURNS TRIGGER AS $$ +BEGIN +insert into newtab2 values(1,1),(2,2),(3,3); +RETURN OLD; +END; +$$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION func_tri22() +RETURNS TRIGGER AS $$ +BEGIN +update newtab2 set c1=4 where id=2; +RETURN OLD; +END; +$$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION func_tri24() +RETURNS TRIGGER AS $$ +BEGIN +insert into newtab2 values(4,4); +RETURN OLD; +END; +$$ +LANGUAGE plpgsql; + +create trigger tri21 +after insert on oldtab2 +for each statement +execute procedure func_tri21(); + +create trigger tri22 +after update on oldtab2 +for each statement +execute procedure func_tri22(); + +create trigger tri24 +after truncate on oldtab2 +for each statement +execute procedure func_tri24(); + +create table t_trig_when(f1 boolean primary key, f2 text, f3 int, f4 date); +create or replace function dummy_update_func() returns trigger as $$ +begin + raise notice 'dummy_update_func(%) called: action = %, oid = %, new = %', TG_ARGV[0], TG_OP, OLD, NEW; + return new; +end; +$$ language plpgsql; + +create trigger f1_trig_update after update of f1 on t_trig_when for each row when (not old.f1 and new.f1) execute procedure dummy_update_func('update'); + +alter table t_trig_when DISABLE TRIGGER f1_trig_update; +alter table t_trig_when ENABLE TRIGGER f1_trig_update; +alter table t_trig_when DISABLE TRIGGER f1_trig_update; +alter table t_trig_when ENABLE ALWAYS TRIGGER f1_trig_update; +alter table t_trig_when DISABLE TRIGGER ALL; +alter table t_trig_when ENABLE TRIGGER ALL; +alter table t_trig_when DISABLE TRIGGER USER ; +alter table t_trig_when ENABLE TRIGGER USER ; \ No newline at end of file diff --git a/src/test/subscription/testcase/ddl_replication_sql/B/ddl_create_type.sql b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_create_type.sql new file mode 100644 index 000000000..458bf97c1 --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_create_type.sql @@ -0,0 +1,2 @@ +create type atype as (id int, name text); +create type btype as object (id int, name text); \ No newline at end of file diff --git a/src/test/subscription/testcase/ddl_replication_sql/B/ddl_drop_type.sql b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_drop_type.sql new file mode 100644 index 000000000..348f77685 --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_drop_type.sql @@ -0,0 +1,13 @@ +create table atable (id int, age int); + +create type atype as (id int, name text); +drop type atype; + +create type btype as object (id int, name text); +drop type btype; + +drop type typ_not_exit; + +drop type public.typ_not_exit; + +drop type schema_not_exit.typ_not_exit; \ No newline at end of file diff --git a/src/test/subscription/testcase/ddl_replication_sql/B/ddl_subpartition_tablespace.setup b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_subpartition_tablespace.setup new file mode 100644 index 000000000..9a92a4a50 --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_subpartition_tablespace.setup @@ -0,0 +1,20 @@ +source $1/env_utils.sh $1 $2 +subscription_dir=$1 +case_use_db=$3 + +tblspace="$subscription_dir/tmp_tblspace" +rm -rf $tblspace +mkdir -p $tblspace + + +tblspace_sub="$subscription_dir/tmp_tblspace_sub" +rm -rf $tblspace_sub +mkdir -p $tblspace_sub + +exec_sql $case_use_db $pub_node1_port "CREATE TABLESPACE hw_subpartition_tablespace_ts1 LOCATION '$tblspace/hw_subpartition_tablespace_ts1';" +exec_sql $case_use_db $pub_node1_port "CREATE TABLESPACE hw_subpartition_tablespace_ts2 LOCATION '$tblspace/hw_subpartition_tablespace_ts2';" +exec_sql $case_use_db $pub_node1_port "CREATE TABLESPACE hw_subpartition_tablespace_ts3 LOCATION '$tblspace/hw_subpartition_tablespace_ts3';" + +exec_sql $case_use_db $sub_node1_port "CREATE TABLESPACE hw_subpartition_tablespace_ts1 LOCATION '$tblspace_sub/hw_subpartition_tablespace_ts1';" +exec_sql $case_use_db $sub_node1_port "CREATE TABLESPACE hw_subpartition_tablespace_ts2 LOCATION '$tblspace_sub/hw_subpartition_tablespace_ts2';" +exec_sql $case_use_db $sub_node1_port "CREATE TABLESPACE hw_subpartition_tablespace_ts3 LOCATION '$tblspace_sub/hw_subpartition_tablespace_ts3';" \ No newline at end of file diff --git a/src/test/subscription/testcase/ddl_replication_sql/B/ddl_subpartition_tablespace.sql b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_subpartition_tablespace.sql new file mode 100644 index 000000000..cf2588ea6 --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_subpartition_tablespace.sql @@ -0,0 +1,1052 @@ +--DROP SCHEMA hw_subpartition_tablespace CASCADE; +CREATE SCHEMA hw_subpartition_tablespace; +SET CURRENT_SCHEMA TO hw_subpartition_tablespace; + +-- +----test create subpartition with tablespace---- +-- +--range-range +CREATE TABLE t_range_range1(c1 int, c2 int, c3 int) +PARTITION BY RANGE (c1) SUBPARTITION BY RANGE (c2) +( + PARTITION P_RANGE1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_RANGE1_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE1_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE1_3 VALUES LESS THAN (15) + ), + PARTITION P_RANGE2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_RANGE2_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE2_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE2_3 VALUES LESS THAN (15) + ), + PARTITION P_RANGE3 VALUES LESS THAN (15) + ( + SUBPARTITION P_RANGE3_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE3_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE3_3 VALUES LESS THAN (15) + ), + PARTITION P_RANGE4 VALUES LESS THAN (20) TABLESPACE hw_subpartition_tablespace_ts1, + PARTITION P_RANGE5 VALUES LESS THAN (25) +); +SELECT pg_get_tabledef('t_range_range1'); +-- DROP TABLEt_range_range1; + +CREATE TABLE t_range_range2(c1 int, c2 int, c3 int) TABLESPACE hw_subpartition_tablespace_ts1 +PARTITION BY RANGE (c1) SUBPARTITION BY RANGE (c2) +( + PARTITION P_RANGE1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_RANGE1_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE1_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE1_3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_RANGE1_4 VALUES LESS THAN (20) + ), + PARTITION P_RANGE2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_RANGE2_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE2_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE2_3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_RANGE2_4 VALUES LESS THAN (20) + ), + PARTITION P_RANGE3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3 + ( + SUBPARTITION P_RANGE3_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE3_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE3_3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_RANGE3_4 VALUES LESS THAN (20) + ), + PARTITION P_RANGE4 VALUES LESS THAN (20) + ( + SUBPARTITION P_RANGE4_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE4_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE4_3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_RANGE4_4 VALUES LESS THAN (20) + ), + PARTITION P_RANGE5 VALUES LESS THAN (25) TABLESPACE hw_subpartition_tablespace_ts3, + PARTITION P_RANGE6 VALUES LESS THAN (30) +); +SELECT pg_get_tabledef('t_range_range2'); +-- DROP TABLEt_range_range2; + +--range-list +CREATE TABLE t_range_list1(c1 int, c2 int, c3 int) +PARTITION BY RANGE (c1) SUBPARTITION BY LIST (c2) +( + PARTITION P_RANGE1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_RANGE1_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE1_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE1_3 VALUES (11,12,13,14,15) + ), + PARTITION P_RANGE2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_RANGE2_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE2_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE2_3 VALUES (11,12,13,14,15) + ), + PARTITION P_RANGE3 VALUES LESS THAN (15) + ( + SUBPARTITION P_RANGE3_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE3_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE3_3 VALUES (11,12,13,14,15) + ), + PARTITION P_RANGE4 VALUES LESS THAN (20) TABLESPACE hw_subpartition_tablespace_ts1, + PARTITION P_RANGE5 VALUES LESS THAN (25) +); +SELECT pg_get_tabledef('t_range_list1'); +-- DROP TABLEt_range_list1; + +CREATE TABLE t_range_list2(c1 int, c2 int, c3 int) TABLESPACE hw_subpartition_tablespace_ts1 +PARTITION BY RANGE (c1) SUBPARTITION BY LIST (c2) +( + PARTITION P_RANGE1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_RANGE1_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE1_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE1_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_RANGE1_4 VALUES (16,17,18,19,20) + ), + PARTITION P_RANGE2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_RANGE2_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE2_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE2_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_RANGE2_4 VALUES (16,17,18,19,20) + ), + PARTITION P_RANGE3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3 + ( + SUBPARTITION P_RANGE3_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE3_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE3_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_RANGE3_4 VALUES (16,17,18,19,20) + ), + PARTITION P_RANGE4 VALUES LESS THAN (20) + ( + SUBPARTITION P_RANGE4_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE4_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE4_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_RANGE4_4 VALUES (16,17,18,19,20) + ), + PARTITION P_RANGE5 VALUES LESS THAN (25) TABLESPACE hw_subpartition_tablespace_ts3, + PARTITION P_RANGE6 VALUES LESS THAN (30) +); +SELECT pg_get_tabledef('t_range_list2'); +-- DROP TABLEt_range_list2; + +--range-hash +CREATE TABLE t_range_hash1(c1 int, c2 int, c3 int) +PARTITION BY RANGE (c1) SUBPARTITION BY HASH (c2) +( + PARTITION P_RANGE1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_RANGE1_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE1_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE1_3 + ), + PARTITION P_RANGE2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_RANGE2_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE2_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE2_3 + ), + PARTITION P_RANGE3 VALUES LESS THAN (15) + ( + SUBPARTITION P_RANGE3_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE3_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE3_3 + ), + PARTITION P_RANGE4 VALUES LESS THAN (20) TABLESPACE hw_subpartition_tablespace_ts1, + PARTITION P_RANGE5 VALUES LESS THAN (25) +); +SELECT pg_get_tabledef('t_range_hash1'); +-- DROP TABLEt_range_hash1; + +CREATE TABLE t_range_hash2(c1 int, c2 int, c3 int) TABLESPACE hw_subpartition_tablespace_ts1 +PARTITION BY RANGE (c1) SUBPARTITION BY HASH (c2) +( + PARTITION P_RANGE1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_RANGE1_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE1_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE1_3 TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_RANGE1_4 + ), + PARTITION P_RANGE2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_RANGE2_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE2_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE2_3 TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_RANGE2_4 + ), + PARTITION P_RANGE3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3 + ( + SUBPARTITION P_RANGE3_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE3_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE3_3 TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_RANGE3_4 + ), + PARTITION P_RANGE4 VALUES LESS THAN (20) + ( + SUBPARTITION P_RANGE4_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE4_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE4_3 TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_RANGE4_4 + ), + PARTITION P_RANGE5 VALUES LESS THAN (25) TABLESPACE hw_subpartition_tablespace_ts3, + PARTITION P_RANGE6 VALUES LESS THAN (30) +); +SELECT pg_get_tabledef('t_range_hash2'); +-- DROP TABLEt_range_hash2; + +--list-range +CREATE TABLE t_list_range1(c1 int, c2 int, c3 int) +PARTITION BY LIST (c1) SUBPARTITION BY RANGE (c2) +( + PARTITION P_LIST1 VALUES (1,2,3,4,5) TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_LIST1_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST1_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST1_3 VALUES LESS THAN (15) + ), + PARTITION P_LIST2 VALUES (6,7,8,9,10) TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_LIST2_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST2_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST2_3 VALUES LESS THAN (15) + ), + PARTITION P_LIST3 VALUES (11,12,13,14,15) + ( + SUBPARTITION P_LIST3_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST3_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST3_3 VALUES LESS THAN (15) + ), + PARTITION P_LIST4 VALUES (16,17,18,19,20) TABLESPACE hw_subpartition_tablespace_ts1, + PARTITION P_LIST5 VALUES (21,22,23,24,25) +); +SELECT pg_get_tabledef('t_list_range1'); +-- DROP TABLEt_list_range1; + +CREATE TABLE t_list_range2(c1 int, c2 int, c3 int) TABLESPACE hw_subpartition_tablespace_ts1 +PARTITION BY LIST (c1) SUBPARTITION BY RANGE (c2) +( + PARTITION P_LIST1 VALUES (1,2,3,4,5) TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_LIST1_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST1_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST1_3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST1_4 VALUES LESS THAN (20) + ), + PARTITION P_LIST2 VALUES (6,7,8,9,10) TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_LIST2_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST2_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST2_3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST2_4 VALUES LESS THAN (20) + ), + PARTITION P_LIST3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3 + ( + SUBPARTITION P_LIST3_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST3_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST3_3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST3_4 VALUES LESS THAN (20) + ), + PARTITION P_LIST4 VALUES (16,17,18,19,20) + ( + SUBPARTITION P_LIST4_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST4_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST4_3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST4_4 VALUES LESS THAN (20) + ), + PARTITION P_LIST5 VALUES (21,22,23,24,25) TABLESPACE hw_subpartition_tablespace_ts3, + PARTITION P_LIST6 VALUES (26,27,28,29,30) +); +SELECT pg_get_tabledef('t_list_range2'); +-- DROP TABLEt_list_range2; + +--list-list +CREATE TABLE t_list_list1(c1 int, c2 int, c3 int) +PARTITION BY LIST (c1) SUBPARTITION BY LIST (c2) +( + PARTITION P_LIST1 VALUES (1,2,3,4,5) TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_LIST1_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST1_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST1_3 VALUES (11,12,13,14,15) + ), + PARTITION P_LIST2 VALUES (6,7,8,9,10) TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_LIST2_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST2_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST2_3 VALUES (11,12,13,14,15) + ), + PARTITION P_LIST3 VALUES (11,12,13,14,15) + ( + SUBPARTITION P_LIST3_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST3_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST3_3 VALUES (11,12,13,14,15) + ), + PARTITION P_LIST4 VALUES (16,17,18,19,20) TABLESPACE hw_subpartition_tablespace_ts1, + PARTITION P_LIST5 VALUES (21,22,23,24,25) +); +SELECT pg_get_tabledef('t_list_list1'); +-- DROP TABLEt_list_list1; + +CREATE TABLE t_list_list2(c1 int, c2 int, c3 int) TABLESPACE hw_subpartition_tablespace_ts1 +PARTITION BY LIST (c1) SUBPARTITION BY LIST (c2) +( + PARTITION P_LIST1 VALUES (1,2,3,4,5) TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_LIST1_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST1_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST1_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST1_4 VALUES (16,17,18,19,20) + ), + PARTITION P_LIST2 VALUES (6,7,8,9,10) TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_LIST2_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST2_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST2_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST2_4 VALUES (16,17,18,19,20) + ), + PARTITION P_LIST3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3 + ( + SUBPARTITION P_LIST3_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST3_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST3_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST3_4 VALUES (16,17,18,19,20) + ), + PARTITION P_LIST4 VALUES (16,17,18,19,20) + ( + SUBPARTITION P_LIST4_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST4_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST4_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST4_4 VALUES (16,17,18,19,20) + ), + PARTITION P_LIST5 VALUES (21,22,23,24,25) TABLESPACE hw_subpartition_tablespace_ts3, + PARTITION P_LIST6 VALUES (26,27,28,29,30) +); +SELECT pg_get_tabledef('t_list_list2'); +-- DROP TABLEt_list_list2; + +--list-hash +CREATE TABLE t_list_hash1(c1 int, c2 int, c3 int) +PARTITION BY LIST (c1) SUBPARTITION BY HASH (c2) +( + PARTITION P_LIST1 VALUES (1,2,3,4,5) TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_LIST1_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST1_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST1_3 + ), + PARTITION P_LIST2 VALUES (6,7,8,9,10) TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_LIST2_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST2_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST2_3 + ), + PARTITION P_LIST3 VALUES (11,12,13,14,15) + ( + SUBPARTITION P_LIST3_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST3_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST3_3 + ), + PARTITION P_LIST4 VALUES (16,17,18,19,20) TABLESPACE hw_subpartition_tablespace_ts1, + PARTITION P_LIST5 VALUES (21,22,23,24,25) +); +SELECT pg_get_tabledef('t_list_hash1'); +-- DROP TABLEt_list_hash1; + +CREATE TABLE t_list_hash2(c1 int, c2 int, c3 int) TABLESPACE hw_subpartition_tablespace_ts1 +PARTITION BY LIST (c1) SUBPARTITION BY HASH (c2) +( + PARTITION P_LIST1 VALUES (1,2,3,4,5) TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_LIST1_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST1_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST1_3 TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST1_4 + ), + PARTITION P_LIST2 VALUES (6,7,8,9,10) TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_LIST2_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST2_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST2_3 TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST2_4 + ), + PARTITION P_LIST3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3 + ( + SUBPARTITION P_LIST3_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST3_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST3_3 TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST3_4 + ), + PARTITION P_LIST4 VALUES (16,17,18,19,20) + ( + SUBPARTITION P_LIST4_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST4_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST4_3 TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST4_4 + ), + PARTITION P_LIST5 VALUES (21,22,23,24,25) TABLESPACE hw_subpartition_tablespace_ts3, + PARTITION P_LIST6 VALUES (26,27,28,29,30) +); +SELECT pg_get_tabledef('t_list_hash2'); +-- DROP TABLEt_list_hash2; + +--hash-range +CREATE TABLE t_hash_range1(c1 int, c2 int, c3 int) +PARTITION BY HASH (c1) SUBPARTITION BY RANGE (c2) +( + PARTITION P_HASH1 TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_HASH1_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH1_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH1_3 VALUES LESS THAN (15) + ), + PARTITION P_HASH2 TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_HASH2_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH2_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH2_3 VALUES LESS THAN (15) + ), + PARTITION P_HASH3 + ( + SUBPARTITION P_HASH3_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH3_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH3_3 VALUES LESS THAN (15) + ), + PARTITION P_HASH4 TABLESPACE hw_subpartition_tablespace_ts1, + PARTITION P_HASH5 +); +SELECT pg_get_tabledef('t_hash_range1'); +-- DROP TABLEt_hash_range1; + +CREATE TABLE t_hash_range2(c1 int, c2 int, c3 int) TABLESPACE hw_subpartition_tablespace_ts1 +PARTITION BY HASH (c1) SUBPARTITION BY RANGE (c2) +( + PARTITION P_HASH1 TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_HASH1_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH1_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH1_3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_HASH1_4 VALUES LESS THAN (20) + ), + PARTITION P_HASH2 TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_HASH2_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH2_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH2_3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_HASH2_4 VALUES LESS THAN (20) + ), + PARTITION P_HASH3 TABLESPACE hw_subpartition_tablespace_ts3 + ( + SUBPARTITION P_HASH3_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH3_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH3_3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_HASH3_4 VALUES LESS THAN (20) + ), + PARTITION P_HASH4 + ( + SUBPARTITION P_HASH4_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH4_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH4_3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_HASH4_4 VALUES LESS THAN (20) + ), + PARTITION P_HASH5 TABLESPACE hw_subpartition_tablespace_ts3, + PARTITION P_HASH6 +); +SELECT pg_get_tabledef('t_hash_range2'); +-- DROP TABLEt_hash_range2; + +--hash-list +CREATE TABLE t_hash_list1(c1 int, c2 int, c3 int) +PARTITION BY HASH (c1) SUBPARTITION BY LIST (c2) +( + PARTITION P_HASH1 TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_HASH1_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH1_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH1_3 VALUES (11,12,13,14,15) + ), + PARTITION P_HASH2 TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_HASH2_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH2_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH2_3 VALUES (11,12,13,14,15) + ), + PARTITION P_HASH3 + ( + SUBPARTITION P_HASH3_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH3_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH3_3 VALUES (11,12,13,14,15) + ), + PARTITION P_HASH4 TABLESPACE hw_subpartition_tablespace_ts1, + PARTITION P_HASH5 +); +SELECT pg_get_tabledef('t_hash_list1'); +-- DROP TABLEt_hash_list1; + +CREATE TABLE t_hash_list2(c1 int, c2 int, c3 int) TABLESPACE hw_subpartition_tablespace_ts1 +PARTITION BY HASH (c1) SUBPARTITION BY LIST (c2) +( + PARTITION P_HASH1 TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_HASH1_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH1_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH1_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_HASH1_4 VALUES (16,17,18,19,20) + ), + PARTITION P_HASH2 TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_HASH2_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH2_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH2_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_HASH2_4 VALUES (16,17,18,19,20) + ), + PARTITION P_HASH3 TABLESPACE hw_subpartition_tablespace_ts3 + ( + SUBPARTITION P_HASH3_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH3_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH3_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_HASH3_4 VALUES (16,17,18,19,20) + ), + PARTITION P_HASH4 + ( + SUBPARTITION P_HASH4_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH4_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH4_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_HASH4_4 VALUES (16,17,18,19,20) + ), + PARTITION P_HASH5 TABLESPACE hw_subpartition_tablespace_ts3, + PARTITION P_HASH6 +); +SELECT pg_get_tabledef('t_hash_list2'); +-- DROP TABLEt_hash_list2; + +--hash-hash +CREATE TABLE t_hash_hash1(c1 int, c2 int, c3 int) +PARTITION BY HASH (c1) SUBPARTITION BY HASH (c2) +( + PARTITION P_HASH1 TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_HASH1_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH1_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH1_3 + ), + PARTITION P_HASH2 TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_HASH2_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH2_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH2_3 + ), + PARTITION P_HASH3 + ( + SUBPARTITION P_HASH3_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH3_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH3_3 + ), + PARTITION P_HASH4 TABLESPACE hw_subpartition_tablespace_ts1, + PARTITION P_HASH5 +); +SELECT pg_get_tabledef('t_hash_hash1'); +-- DROP TABLEt_hash_hash1; + +CREATE TABLE t_hash_hash2(c1 int, c2 int, c3 int) TABLESPACE hw_subpartition_tablespace_ts1 +PARTITION BY HASH (c1) SUBPARTITION BY HASH (c2) +( + PARTITION P_HASH1 TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_HASH1_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH1_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH1_3 TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_HASH1_4 + ), + PARTITION P_HASH2 TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_HASH2_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH2_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH2_3 TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_HASH2_4 + ), + PARTITION P_HASH3 TABLESPACE hw_subpartition_tablespace_ts3 + ( + SUBPARTITION P_HASH3_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH3_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH3_3 TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_HASH3_4 + ), + PARTITION P_HASH4 + ( + SUBPARTITION P_HASH4_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH4_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH4_3 TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_HASH4_4 + ), + PARTITION P_HASH5 TABLESPACE hw_subpartition_tablespace_ts3, + PARTITION P_HASH6 +); +SELECT pg_get_tabledef('t_hash_hash2'); +-- DROP TABLEt_hash_hash2; + +-- +----test add partition with tablespace---- +-- +--since the add subpartition define use the same code, we only test different partition type: range/list +--range-list +CREATE TABLE t_range_list3(c1 int, c2 int, c3 int) +PARTITION BY RANGE (c1) SUBPARTITION BY LIST (c2) +( + PARTITION P_RANGE1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_RANGE1_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE1_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE1_3 VALUES (11,12,13,14,15) + ), + PARTITION P_RANGE2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_RANGE2_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE2_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE2_3 VALUES (11,12,13,14,15) + ) +); +ALTER TABLE t_range_list3 ADD PARTITION P_RANGE3 VALUES LESS THAN (15) + ( + SUBPARTITION P_RANGE3_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE3_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE3_3 VALUES (11,12,13,14,15) + ); +ALTER TABLE t_range_list3 ADD PARTITION P_RANGE4 VALUES LESS THAN (20) TABLESPACE hw_subpartition_tablespace_ts1; +ALTER TABLE t_range_list3 ADD PARTITION P_RANGE5 VALUES LESS THAN (25); +SELECT pg_get_tabledef('t_range_list3'); +-- DROP TABLEt_range_list3; + + +CREATE TABLE t_range_list4(c1 int, c2 int, c3 int) TABLESPACE hw_subpartition_tablespace_ts1 +PARTITION BY RANGE (c1) SUBPARTITION BY LIST (c2) +( + PARTITION P_RANGE1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_RANGE1_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE1_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE1_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_RANGE1_4 VALUES (16,17,18,19,20) + ), + PARTITION P_RANGE2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_RANGE2_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE2_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE2_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_RANGE2_4 VALUES (16,17,18,19,20) + ) +); +ALTER TABLE t_range_list4 ADD PARTITION P_RANGE3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3 + ( + SUBPARTITION P_RANGE3_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE3_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE3_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_RANGE3_4 VALUES (16,17,18,19,20) + ); +ALTER TABLE t_range_list4 ADD PARTITION P_RANGE4 VALUES LESS THAN (20) + ( + SUBPARTITION P_RANGE4_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE4_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE4_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_RANGE4_4 VALUES (16,17,18,19,20) + ); +ALTER TABLE t_range_list4 ADD PARTITION P_RANGE5 VALUES LESS THAN (25) TABLESPACE hw_subpartition_tablespace_ts3; +ALTER TABLE t_range_list4 ADD PARTITION P_RANGE6 VALUES LESS THAN (30); +SELECT pg_get_tabledef('t_range_list4'); +-- DROP TABLEt_range_list4; + +--list-hash +CREATE TABLE t_list_hash3(c1 int, c2 int, c3 int) +PARTITION BY LIST (c1) SUBPARTITION BY HASH (c2) +( + PARTITION P_LIST1 VALUES (1,2,3,4,5) TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_LIST1_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST1_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST1_3 + ), + PARTITION P_LIST2 VALUES (6,7,8,9,10) TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_LIST2_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST2_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST2_3 + ) +); + +ALTER TABLE t_list_hash3 ADD PARTITION P_LIST3 VALUES (11,12,13,14,15) + ( + SUBPARTITION P_LIST3_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST3_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST3_3 + ); +ALTER TABLE t_list_hash3 ADD PARTITION P_LIST4 VALUES (16,17,18,19,20) TABLESPACE hw_subpartition_tablespace_ts1; +ALTER TABLE t_list_hash3 ADD PARTITION P_LIST5 VALUES (21,22,23,24,25); +SELECT pg_get_tabledef('t_list_hash3'); +-- DROP TABLEt_list_hash3; + +CREATE TABLE t_list_hash4(c1 int, c2 int, c3 int) TABLESPACE hw_subpartition_tablespace_ts1 +PARTITION BY LIST (c1) SUBPARTITION BY HASH (c2) +( + PARTITION P_LIST1 VALUES (1,2,3,4,5) TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_LIST1_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST1_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST1_3 TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST1_4 + ), + PARTITION P_LIST2 VALUES (6,7,8,9,10) TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_LIST2_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST2_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST2_3 TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST2_4 + ) +); +ALTER TABLE t_list_hash4 ADD PARTITION P_LIST3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3 + ( + SUBPARTITION P_LIST3_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST3_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST3_3 TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST3_4 + ); +ALTER TABLE t_list_hash4 ADD PARTITION P_LIST4 VALUES (16,17,18,19,20) + ( + SUBPARTITION P_LIST4_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST4_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST4_3 TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST4_4 + ); +ALTER TABLE t_list_hash4 ADD PARTITION P_LIST5 VALUES (21,22,23,24,25) TABLESPACE hw_subpartition_tablespace_ts3; +ALTER TABLE t_list_hash4 ADD PARTITION P_LIST6 VALUES (26,27,28,29,30); +SELECT pg_get_tabledef('t_list_hash4'); +-- DROP TABLEt_list_hash4; + +-- +----test add subpartition with tablespace---- +-- +--list-range +CREATE TABLE t_list_range3(c1 int, c2 int, c3 int) +PARTITION BY LIST (c1) SUBPARTITION BY RANGE (c2) +( + PARTITION P_LIST1 VALUES (1,2,3,4,5) TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_LIST1_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST1_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST1_3 VALUES LESS THAN (15) + ), + PARTITION P_LIST2 VALUES (6,7,8,9,10) TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_LIST2_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST2_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST2_3 VALUES LESS THAN (15) + ), + PARTITION P_LIST3 VALUES (11,12,13,14,15) + ( + SUBPARTITION P_LIST3_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST3_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST3_3 VALUES LESS THAN (15) + ), + PARTITION P_LIST4 VALUES (16,17,18,19,20) TABLESPACE hw_subpartition_tablespace_ts1, + PARTITION P_LIST5 VALUES (21,22,23,24,25) +); +ALTER TABLE t_list_range3 MODIFY PARTITION P_LIST1 ADD SUBPARTITION P_LIST1_4 VALUES LESS THAN (20) TABLESPACE hw_subpartition_tablespace_ts3; +ALTER TABLE t_list_range3 MODIFY PARTITION P_LIST2 ADD SUBPARTITION P_LIST2_4 VALUES LESS THAN (20); +ALTER TABLE t_list_range3 MODIFY PARTITION P_LIST3 ADD SUBPARTITION P_LIST3_4 VALUES LESS THAN (20); +SELECT pg_get_tabledef('t_list_range3'); +-- DROP TABLEt_list_range3; + +CREATE TABLE t_list_range4(c1 int, c2 int, c3 int) TABLESPACE hw_subpartition_tablespace_ts1 +PARTITION BY LIST (c1) SUBPARTITION BY RANGE (c2) +( + PARTITION P_LIST1 VALUES (1,2,3,4,5) TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_LIST1_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST1_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST1_3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST1_4 VALUES LESS THAN (20) + ), + PARTITION P_LIST2 VALUES (6,7,8,9,10) TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_LIST2_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST2_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST2_3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST2_4 VALUES LESS THAN (20) + ), + PARTITION P_LIST3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3 + ( + SUBPARTITION P_LIST3_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST3_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST3_3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST3_4 VALUES LESS THAN (20) + ), + PARTITION P_LIST4 VALUES (16,17,18,19,20) + ( + SUBPARTITION P_LIST4_1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_LIST4_2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_LIST4_3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_LIST4_4 VALUES LESS THAN (20) + ), + PARTITION P_LIST5 VALUES (21,22,23,24,25) TABLESPACE hw_subpartition_tablespace_ts3, + PARTITION P_LIST6 VALUES (26,27,28,29,30) +); +ALTER TABLE t_list_range4 MODIFY PARTITION P_LIST1 ADD SUBPARTITION P_LIST1_5 VALUES LESS THAN (25) TABLESPACE hw_subpartition_tablespace_ts3; +ALTER TABLE t_list_range4 MODIFY PARTITION P_LIST2 ADD SUBPARTITION P_LIST2_5 VALUES LESS THAN (25) TABLESPACE hw_subpartition_tablespace_ts2; +ALTER TABLE t_list_range4 MODIFY PARTITION P_LIST3 ADD SUBPARTITION P_LIST3_5 VALUES LESS THAN (25); +ALTER TABLE t_list_range4 MODIFY PARTITION P_LIST4 ADD SUBPARTITION P_LIST4_5 VALUES LESS THAN (25); +SELECT pg_get_tabledef('t_list_range4'); +-- DROP TABLEt_list_range4; + +--hash-list +CREATE TABLE t_hash_list3(c1 int, c2 int, c3 int) +PARTITION BY HASH (c1) SUBPARTITION BY LIST (c2) +( + PARTITION P_HASH1 TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_HASH1_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH1_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH1_3 VALUES (11,12,13,14,15) + ), + PARTITION P_HASH2 TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_HASH2_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH2_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH2_3 VALUES (11,12,13,14,15) + ), + PARTITION P_HASH3 + ( + SUBPARTITION P_HASH3_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH3_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH3_3 VALUES (11,12,13,14,15) + ), + PARTITION P_HASH4 TABLESPACE hw_subpartition_tablespace_ts1, + PARTITION P_HASH5 +); +ALTER TABLE t_hash_list3 MODIFY PARTITION P_HASH1 ADD SUBPARTITION P_HASH1_4 VALUES (16,17,18,19,20) TABLESPACE hw_subpartition_tablespace_ts3; +ALTER TABLE t_hash_list3 MODIFY PARTITION P_HASH2 ADD SUBPARTITION P_HASH2_4 VALUES (16,17,18,19,20); +ALTER TABLE t_hash_list3 MODIFY PARTITION P_HASH3 ADD SUBPARTITION P_HASH3_4 VALUES (16,17,18,19,20); +SELECT pg_get_tabledef('t_hash_list3'); +-- DROP TABLEt_hash_list3; + +CREATE TABLE t_hash_list4(c1 int, c2 int, c3 int) TABLESPACE hw_subpartition_tablespace_ts1 +PARTITION BY HASH (c1) SUBPARTITION BY LIST (c2) +( + PARTITION P_HASH1 TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_HASH1_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH1_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH1_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_HASH1_4 VALUES (16,17,18,19,20) + ), + PARTITION P_HASH2 TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_HASH2_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH2_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH2_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_HASH2_4 VALUES (16,17,18,19,20) + ), + PARTITION P_HASH3 TABLESPACE hw_subpartition_tablespace_ts3 + ( + SUBPARTITION P_HASH3_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH3_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH3_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_HASH3_4 VALUES (16,17,18,19,20) + ), + PARTITION P_HASH4 + ( + SUBPARTITION P_HASH4_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_HASH4_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_HASH4_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_HASH4_4 VALUES (16,17,18,19,20) + ), + PARTITION P_HASH5 TABLESPACE hw_subpartition_tablespace_ts3, + PARTITION P_HASH6 +); +ALTER TABLE t_hash_list4 MODIFY PARTITION P_HASH1 ADD SUBPARTITION P_HASH1_5 VALUES(21,22,23,24,25) TABLESPACE hw_subpartition_tablespace_ts3; +ALTER TABLE t_hash_list4 MODIFY PARTITION P_HASH2 ADD SUBPARTITION P_HASH2_5 VALUES(21,22,23,24,25) TABLESPACE hw_subpartition_tablespace_ts2; +ALTER TABLE t_hash_list4 MODIFY PARTITION P_HASH3 ADD SUBPARTITION P_HASH3_5 VALUES(21,22,23,24,25); +ALTER TABLE t_hash_list4 MODIFY PARTITION P_HASH4 ADD SUBPARTITION P_HASH4_5 VALUES(21,22,23,24,25); +SELECT pg_get_tabledef('t_hash_list4'); +-- DROP TABLEt_hash_list4; + +-- +----test create index with tablespace---- +-- +CREATE TABLE t_range_list(c1 int, c2 int, c3 int) TABLESPACE hw_subpartition_tablespace_ts1 +PARTITION BY RANGE (c1) SUBPARTITION BY LIST (c2) +( + PARTITION P_RANGE1 VALUES LESS THAN (5) TABLESPACE hw_subpartition_tablespace_ts1 + ( + SUBPARTITION P_RANGE1_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE1_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE1_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_RANGE1_4 VALUES (16,17,18,19,20) + ), + PARTITION P_RANGE2 VALUES LESS THAN (10) TABLESPACE hw_subpartition_tablespace_ts2 + ( + SUBPARTITION P_RANGE2_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE2_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE2_3 VALUES (DEFAULT) + ), + PARTITION P_RANGE3 VALUES LESS THAN (15) TABLESPACE hw_subpartition_tablespace_ts3 + ( + SUBPARTITION P_RANGE3_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE3_2 VALUES ( 6, 7, 8, 9,10) TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION P_RANGE3_3 VALUES (11,12,13,14,15) TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION P_RANGE3_4 VALUES (16,17,18,19,20) + ), + PARTITION P_RANGE4 VALUES LESS THAN (20) + ( + SUBPARTITION P_RANGE4_1 VALUES ( 1, 2, 3, 4, 5) TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION P_RANGE4_2 VALUES (DEFAULT) TABLESPACE hw_subpartition_tablespace_ts2 + ), + PARTITION P_RANGE5 VALUES LESS THAN (25) TABLESPACE hw_subpartition_tablespace_ts3, + PARTITION P_RANGE6 VALUES LESS THAN (30) +); + +CREATE INDEX t_range_list_idx ON t_range_list(c1,c2) LOCAL +( + PARTITION idx_p1( + SUBPARTITION idx_p1_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION idx_p1_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION idx_p1_3 TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION idx_p1_4 + ), + PARTITION idx_p2 TABLESPACE hw_subpartition_tablespace_ts2( + SUBPARTITION idx_p2_1, + SUBPARTITION idx_p2_2, + SUBPARTITION idx_p2_3 + ), + PARTITION idx_p3 TABLESPACE hw_subpartition_tablespace_ts2( + SUBPARTITION idx_p3_1 TABLESPACE hw_subpartition_tablespace_ts1, + SUBPARTITION idx_p3_2 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION idx_p3_3 TABLESPACE hw_subpartition_tablespace_ts3, + SUBPARTITION idx_p3_4 + ), + PARTITION idx_p4( + SUBPARTITION idx_p4_1, + SUBPARTITION idx_p4_2 TABLESPACE hw_subpartition_tablespace_ts2 + ), + PARTITION idx_p5 TABLESPACE hw_subpartition_tablespace_ts3( + SUBPARTITION idx_p5_1 + ), + PARTITION idx_p6( + SUBPARTITION idx_p6_1 TABLESPACE hw_subpartition_tablespace_ts2 + ) +) TABLESPACE hw_subpartition_tablespace_ts1; + + +SELECT p.relname, t.spcname FROM pg_partition p, pg_class c, pg_namespace n, pg_tablespace t +WHERE p.parentid = c.oid + AND c.relname='t_range_list_idx' + AND c.relnamespace=n.oid + AND n.nspname=CURRENT_SCHEMA + AND p.reltablespace = t.oid +ORDER BY p.relname; + +SELECT pg_get_indexdef('hw_subpartition_tablespace.t_range_list_idx'::regclass); + +alter index t_range_list_idx rebuild; +alter index t_range_list_idx rebuild PARTITION idx_p2_1; + +create table t_settbs(id int,c1 text,c2 text); +create index idx_t_settbs_id on t_settbs(id); +alter table t_settbs SET TABLESPACE hw_subpartition_tablespace_ts1; + +alter table t_settbs ALTER INDEX idx_t_settbs_id INVISIBLE; +alter table t_settbs ALTER INDEX idx_t_settbs_id VISIBLE; + +alter table t_settbs ENABLE ROW LEVEL SECURITY; +alter table t_settbs DISABLE ROW LEVEL SECURITY; + +alter table t_settbs FORCE ROW LEVEL SECURITY; +alter table t_settbs NO FORCE ROW LEVEL SECURITY; + +drop TABLE if exists list_range_sales; +CREATE TABLE list_range_sales +( + product_id INT4 NOT NULL, + customer_id INT4 PRIMARY KEY, + time_id DATE, + channel_id CHAR(1), + type_id INT4, + quantity_sold NUMERIC(3), + amount_sold NUMERIC(10,2) +) +PARTITION BY LIST (channel_id) SUBPARTITION BY RANGE (customer_id) +( + PARTITION channel1 VALUES ('0', '1', '2') + ( + SUBPARTITION channel1_customer1 VALUES LESS THAN (200), + SUBPARTITION channel1_customer2 VALUES LESS THAN (500), + SUBPARTITION channel1_customer3 VALUES LESS THAN (800), + SUBPARTITION channel1_customer4 VALUES LESS THAN (1200) + ), + PARTITION channel2 VALUES ('3', '4', '5') + ( + SUBPARTITION channel2_customer1 VALUES LESS THAN (500), + SUBPARTITION channel2_customer2 VALUES LESS THAN (MAXVALUE) + ), + PARTITION channel3 VALUES ('6', '7'), + PARTITION channel4 VALUES ('8', '9') + ( + SUBPARTITION channel4_customer1 VALUES LESS THAN (1200) + ) +); + +ALTER TABLE list_range_sales SPLIT SUBPARTITION channel2_customer2 AT (800) +INTO (SUBPARTITION channel2_customer3 TABLESPACE hw_subpartition_tablespace_ts2, + SUBPARTITION channel2_customer4 TABLESPACE hw_subpartition_tablespace_ts2); + +drop TABLE if exists range_list_sales; +CREATE TABLE range_list_sales +( + product_id INT4 NOT NULL, + customer_id INT4 NOT NULL, + time_id DATE, + channel_id CHAR(1), + type_id INT4, + quantity_sold NUMERIC(3), + amount_sold NUMERIC(10,2) +) WITH (STORAGE_TYPE=USTORE) +PARTITION BY RANGE (customer_id) SUBPARTITION BY LIST (channel_id) +( + PARTITION customer1 VALUES LESS THAN (200) + ( + SUBPARTITION customer1_channel1 VALUES ('0', '1', '2'), + SUBPARTITION customer1_channel2 VALUES ('3', '4', '5'), + SUBPARTITION customer1_channel3 VALUES ('6', '7', '8'), + SUBPARTITION customer1_channel4 VALUES (DEFAULT) + ), + PARTITION customer2 VALUES LESS THAN (500) + ( + SUBPARTITION customer2_channel1 VALUES ('0', '1', '2', '3', '4'), + SUBPARTITION customer2_channel2 VALUES (DEFAULT) + ), + PARTITION customer3 VALUES LESS THAN (800), + PARTITION customer4 VALUES LESS THAN (1200) + ( + SUBPARTITION customer4_channel1 VALUES ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9') + ) +); + +ALTER TABLE range_list_sales SPLIT SUBPARTITION customer2_channel2 VALUES (7) +INTO (SUBPARTITION customer2_channel2_0 TABLESPACE hw_subpartition_tablespace_ts2 , + SUBPARTITION customer2_channel2_1 TABLESPACE hw_subpartition_tablespace_ts2); + +-- DROP TABLEt_range_list; + +--finish +drop tablespace hw_subpartition_tablespace_ts1; +drop tablespace hw_subpartition_tablespace_ts2; +drop tablespace hw_subpartition_tablespace_ts3; +\! rm -fr '@testtablespace@/hw_subpartition_tablespace_ts1' +\! rm -fr '@testtablespace@/hw_subpartition_tablespace_ts2' +\! rm -fr '@testtablespace@/hw_subpartition_tablespace_ts3' + +DROP SCHEMA hw_subpartition_tablespace CASCADE; +RESET CURRENT_SCHEMA; diff --git a/src/test/subscription/testcase/ddl_replication_sql/B/ddl_view_def.sql b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_view_def.sql new file mode 100644 index 000000000..1a5917bad --- /dev/null +++ b/src/test/subscription/testcase/ddl_replication_sql/B/ddl_view_def.sql @@ -0,0 +1,36 @@ +CREATE TABLE tb_class (id INT,class_name TEXT); +INSERT INTO tb_class (id,class_name) VALUES (1,'class_1'); +INSERT INTO tb_class (id,class_name) VALUES (2,'class_2'); + +CREATE TABLE tb_student (id INT,student_name TEXT,class_id INT); +INSERT INTO tb_student (id,student_name,class_id) VALUES (1,'li lei',1); +INSERT INTO tb_student (id,student_name,class_id) VALUES (2,'han meimei',1); +INSERT INTO tb_student (id,student_name,class_id) VALUES (3,'zhang xiaoming',2); +INSERT INTO tb_student (id,student_name,class_id) VALUES (4,'wang peng',2); + +CREATE VIEW vw_class AS SELECT * FROM tb_class; +CREATE VIEW vw_student AS SELECT * FROM tb_student; +CREATE VIEW vw_class_student AS SELECT c.class_name,s.student_name FROM tb_class c JOIN tb_student s ON c.id = s.class_id; +CREATE VIEW vw_class_1_student AS SELECT c.class_name,s.student_name FROM tb_class c JOIN tb_student s ON c.id = s.class_id WHERE c.id = 1; + +CREATE TABLE tb_order (id INT,order_product TEXT,order_time timestamptz); +INSERT INTO tb_order (id,order_product) VALUES (1,'football'); +INSERT INTO tb_order (id,order_product) VALUES (2,'baskball'); + +CREATE VIEW vw_order AS SELECT * FROM tb_order; +ALTER VIEW vw_order ALTER COLUMN order_time SET DEFAULT now(); + + +CREATE TABLE tb_address (id INT,address TEXT); +INSERT INTO tb_address (id,address) VALUES (1,'a_address'); +INSERT INTO tb_address (id,address) VALUES (2,'b_address'); + +CREATE VIEW vw_address AS SELECT * FROM tb_address; +ALTER VIEW vw_address RENAME TO vw_address_new; + +CREATE TABLE tb_book (id INT,book_name TEXT); +INSERT INTO tb_book (id,book_name) VALUES (1,'englisen'); +INSERT INTO tb_book (id,book_name) VALUES (2,'math'); + +CREATE VIEW vw_book AS SELECT * FROM tb_book; +DROP VIEW vw_book; \ No newline at end of file diff --git a/src/test/subscription/testcase/dump_expected/dump_db_puball.pub b/src/test/subscription/testcase/dump_expected/dump_db_puball.pub index db2ca2f77..31a00f689 100644 --- a/src/test/subscription/testcase/dump_expected/dump_db_puball.pub +++ b/src/test/subscription/testcase/dump_expected/dump_db_puball.pub @@ -9,7 +9,6 @@ SET standard_conforming_strings = on; SET check_function_bodies = false; SET session_replication_role = replica; SET client_min_messages = warning; -SET dolphin.sql_mode = 'sql_mode_full_group,pipes_as_concat,ansi_quotes,pad_char_to_full_length'; SET search_path = public; @@ -44,7 +43,7 @@ COPY public.test1 (a, b) FROM stdin; -- Name: mypub; Type: PUBLICATION; Schema: -; Owner: gauss -- -CREATE PUBLICATION mypub FOR ALL TABLES WITH (publish = 'insert, update, delete',ddl = 'all'); +CREATE PUBLICATION mypub FOR ALL TABLES WITH (publish = 'insert, update, delete, truncate',ddl = 'all'); ALTER PUBLICATION mypub OWNER TO gauss; diff --git a/src/test/subscription/testcase/dump_expected/dump_db_puball.sub b/src/test/subscription/testcase/dump_expected/dump_db_puball.sub index 197bc05ea..94bafc448 100644 --- a/src/test/subscription/testcase/dump_expected/dump_db_puball.sub +++ b/src/test/subscription/testcase/dump_expected/dump_db_puball.sub @@ -9,7 +9,6 @@ SET standard_conforming_strings = on; SET check_function_bodies = false; SET session_replication_role = replica; SET client_min_messages = warning; -SET dolphin.sql_mode = 'sql_mode_full_group,pipes_as_concat,ansi_quotes,pad_char_to_full_length'; SET search_path = public; diff --git a/src/test/subscription/testcase/dump_expected/dump_db_pubtable.pub b/src/test/subscription/testcase/dump_expected/dump_db_pubtable.pub index 52c1c4415..f129e0789 100644 --- a/src/test/subscription/testcase/dump_expected/dump_db_pubtable.pub +++ b/src/test/subscription/testcase/dump_expected/dump_db_pubtable.pub @@ -9,7 +9,6 @@ SET standard_conforming_strings = on; SET check_function_bodies = false; SET session_replication_role = replica; SET client_min_messages = warning; -SET dolphin.sql_mode = 'sql_mode_full_group,pipes_as_concat,ansi_quotes,pad_char_to_full_length'; SET search_path = public; diff --git a/src/test/subscription/testcase/dump_expected/dump_db_pubtable.sub b/src/test/subscription/testcase/dump_expected/dump_db_pubtable.sub index 197bc05ea..94bafc448 100644 --- a/src/test/subscription/testcase/dump_expected/dump_db_pubtable.sub +++ b/src/test/subscription/testcase/dump_expected/dump_db_pubtable.sub @@ -9,7 +9,6 @@ SET standard_conforming_strings = on; SET check_function_bodies = false; SET session_replication_role = replica; SET client_min_messages = warning; -SET dolphin.sql_mode = 'sql_mode_full_group,pipes_as_concat,ansi_quotes,pad_char_to_full_length'; SET search_path = public;