Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1kuO6A-0000gi-14 for pgsql-hackers@arkaria.postgresql.org; Tue, 29 Dec 2020 23:08:14 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1kuO69-0006CV-0M for pgsql-hackers@arkaria.postgresql.org; Tue, 29 Dec 2020 23:08:13 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1kuO68-0006CO-Ky for pgsql-hackers@lists.postgresql.org; Tue, 29 Dec 2020 23:08:12 +0000 Received: from mail-io1-xd2d.google.com ([2607:f8b0:4864:20::d2d]) by magus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.92) (envelope-from ) id 1kuO65-0002UY-UJ for pgsql-hackers@postgresql.org; Tue, 29 Dec 2020 23:08:12 +0000 Received: by mail-io1-xd2d.google.com with SMTP id i18so13385394ioa.1 for ; Tue, 29 Dec 2020 15:08:09 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=telsasoft-com.20150623.gappssmtp.com; s=20150623; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to:user-agent; bh=2Zj/uftl251ZfWBQfNuwqERsVsXnJz+ytRSglW64iQ0=; b=hCEBteoY2iPtLwVNK/MXOchESAJCTF7YEpGgwIp4dnkn0RhbcrPYji9MCtIvg4HcWP JlCnOh1dOHmJQFhk8ZoNfQwLOo2rjoe1BZsScXQIiFb1/y9qJ5VXZ24pkxF/GYBq/VBJ dlq54QwJUjQMdNtJQOps3y5eKVEU+kCEZZ/MQhnQJLpeUoPqvLUq+eDXBhavWhxtLbcG 1fyL9eMYNtnYttdVXji/T7mBsxh7RVcbZJ2hoGAYXmoQZE7MnbVrZDiVU4OV9/ilstnT CkItE1/9jgOJ5qa4fZX+FrO/BqZQg2Fjwxmqm83S3JRvDoCHPcvyNuDZzvEX02raAZ3M gj/A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to:user-agent; bh=2Zj/uftl251ZfWBQfNuwqERsVsXnJz+ytRSglW64iQ0=; b=BMKnjunobAcQ0fEe2agtnZA4uaZAeIqz5hMorSOS5si9sIiZNtVXf43CMoJr3kvDvA 6nCqYHxC5oZgLUwh+ywWisVwjq3zfoCAczgWj5NHH2liFurY1UAWic5p2vUS6N24gu3K 6fzxBqqRhDKBE8d5+ejuWF4riFMGcSBRMmKptLqltEnFHH2AjpaXgtDUMeXbGF2H64TY 3GLeggySTMVRA0KNfpdLuBr+KkYYAtEqK4zXEcylHlTuMP9FurSk1Lu76rQtsxz/w2Tq XntAytv0bHbv6DgroIjBuUWvf+shxYh+W39yq3YAeGkePvqYw660vxxX8JUMRBfHEl6D ValQ== X-Gm-Message-State: AOAM530jZ7rco0/QSgsA12Dk3G4n9CUyCa2pOOqctcB3Ht/CQzwzHA2r gBegkA/3vPA5Zvbny1DhNGBbGQ== X-Google-Smtp-Source: ABdhPJxV/K6w95FucWrSN2ddsxiID41/77mtDLRGrq+uXOBFOlHbSMxH2TnKCRr5O5AGGgoZ+vINPA== X-Received: by 2002:a05:6638:34e:: with SMTP id x14mr43922444jap.39.1609283287705; Tue, 29 Dec 2020 15:08:07 -0800 (PST) Received: from pryzbyj.telsasoft (charmander.telsasoft.com. [50.244.222.1]) by smtp.gmail.com with ESMTPSA id t14sm25154604iof.23.2020.12.29.15.08.06 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Tue, 29 Dec 2020 15:08:06 -0800 (PST) Received: by pryzbyj.telsasoft (Postfix, from userid 1000) id 7DDC28006CE; Tue, 29 Dec 2020 17:08:05 -0600 (CST) Date: Tue, 29 Dec 2020 17:08:05 -0600 From: Justin Pryzby To: Michael Paquier Cc: pgsql-hackers@postgresql.org, Jacob Champion , Heikki Linnakangas , Ashwin Agrawal , Ashutosh Sharma , Andres Freund , Robert Haas , Amit Kapila , Alvaro Herrera Subject: Re: create table like: ACCESS METHOD Message-ID: <20201229230805.GE25152@telsasoft.com> References: <20201209201328.GT24052@telsasoft.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="3V7upXqbjpZ4EhLz" Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.9.4 (2018-02-28) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk --3V7upXqbjpZ4EhLz Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Fri, Dec 25, 2020 at 03:41:46PM +0900, Michael Paquier wrote: > On Wed, Dec 09, 2020 at 02:13:29PM -0600, Justin Pryzby wrote: > > I thought this was a good idea, but didn't hear back when I raised it before. > > > > Failing to preserve access method is arguably a bug, reminiscent of CREATE > > STATISTICS and 5564c1181. But maybe it's not important to backpatch a fix in > > this case, since access methods are still evolving. > > Interesting. Access methods for tables are released for more than one > year now, so my take about a backpatch is that this boat has already > sailed. This may give a reason to actually not introduce this > feature. Are you saying that since v12/13 didn't preserve the access method, it might be preferred to never do it ? I think it's reasonable to to not change v12/13 but the behavior seems like an omission going forward. It's not so important right now, since AMs aren't widely used. This might be important for a few cases I can think of easily: If an readonly AM doesn't support DDL, and table needs to be rebuilt, we'd handle that by creating a new table LIKE the existing table, preserving its AM, and then INSERT into it. Like for column type promotion. That's much better than querying amname FROM pg_class JOIN relam. ALTER TABLE..ATTACH PARTITION requires a less strong lock than CREATE TABLE..PARTITION OF, so it's nice to be able to CREATE TABLE LIKE. To use an alternate AM for historic data, we'd CREATE TABLE LIKE an existing, populated table before inserting into it. This would support re-creating on a new AM, or re-creating on the same AM, say, to get rid of dropped columns, or to re-arrange columns. > -- fail, as partitioned tables don't allow NO INHERIT constraints > -CREATE TABLE noinh_con_copy1_parted (LIKE noinh_con_copy INCLUDING ALL) > +CREATE TABLE noinh_con_copy1_parted (LIKE noinh_con_copy INCLUDING ALL EXCLUDING ACCESS METHOD) > PARTITION BY LIST (a); > This diff means that you are introducing an incompatible change by > forcing any application using CREATE TABLE LIKE for a partitioned > table to exclude access methods. This is not acceptable, and it may > be better to just ignore this clause instead in this context. Ok. This means that CREATE TABLE (LIKE x INCLUDING ACCESS METHOD) PARTITION BY ... silently ignores the INCLUDING AM. Is that ok ? I think the alternative is for INCLUDING to be "ternary" options, defaulting to UNSET=0, when it's ok to ignore options in contexts where they're not useful. Maybe we'd need to specially handle INCLUDING ALL, to make options "soft"/implied rather than explicit. > This patch should have more tests. Something could be added in > create_am.sql where there is a fake heap2 as table AM. Yes, I had already done that locally. -- Justin --3V7upXqbjpZ4EhLz Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v2-0001-create-table-like-.-including-ACCESS-METHOD.patch" From c4c4570f90623aa8508a2749f5ca5e2780ab10df Mon Sep 17 00:00:00 2001 From: Justin Pryzby Date: Sun, 15 Nov 2020 16:54:53 -0600 Subject: [PATCH v2] create table (like .. including ACCESS METHOD) --- doc/src/sgml/ref/create_table.sgml | 12 +++++++++++- src/backend/parser/gram.y | 3 ++- src/backend/parser/parse_utilcmd.c | 10 ++++++++++ src/include/nodes/parsenodes.h | 17 +++++++++-------- src/test/regress/expected/create_table_like.out | 12 ++++++++++++ src/test/regress/sql/create_table_like.sql | 8 ++++++++ 6 files changed, 52 insertions(+), 10 deletions(-) diff --git a/doc/src/sgml/ref/create_table.sgml b/doc/src/sgml/ref/create_table.sgml index 569f4c9da7..cb95177e92 100644 --- a/doc/src/sgml/ref/create_table.sgml +++ b/doc/src/sgml/ref/create_table.sgml @@ -87,7 +87,7 @@ class="parameter">referential_action ] [ ON UPDATE and like_option is: -{ INCLUDING | EXCLUDING } { COMMENTS | CONSTRAINTS | DEFAULTS | GENERATED | IDENTITY | INDEXES | STATISTICS | STORAGE | ALL } +{ INCLUDING | EXCLUDING } { ACCESS METHOD | COMMENTS | CONSTRAINTS | DEFAULTS | GENERATED | IDENTITY | INDEXES | STATISTICS | STORAGE | ALL } and partition_bound_spec is: @@ -593,6 +593,16 @@ WITH ( MODULUS numeric_literal, REM available options are: + + INCLUDING ACCESS METHOD + + + The table's access method will be copied. By default, the + default_table_access_method is used. + + + + INCLUDING COMMENTS diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 8f341ac006..fee0aceb65 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -3651,7 +3651,8 @@ TableLikeOptionList: ; TableLikeOption: - COMMENTS { $$ = CREATE_TABLE_LIKE_COMMENTS; } + ACCESS METHOD { $$ = CREATE_TABLE_LIKE_ACCESS_METHOD; } + | COMMENTS { $$ = CREATE_TABLE_LIKE_COMMENTS; } | CONSTRAINTS { $$ = CREATE_TABLE_LIKE_CONSTRAINTS; } | DEFAULTS { $$ = CREATE_TABLE_LIKE_DEFAULTS; } | IDENTITY_P { $$ = CREATE_TABLE_LIKE_IDENTITY; } diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index 89ee990599..4eed7e3ea2 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -96,6 +96,7 @@ typedef struct bool ispartitioned; /* true if table is partitioned */ PartitionBoundSpec *partbound; /* transformed FOR VALUES */ bool ofType; /* true if statement contains OF typename */ + char *accessMethod; /* table access method */ } CreateStmtContext; /* State shared by transformCreateSchemaStmt and its subroutines */ @@ -252,6 +253,7 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString) cxt.ispartitioned = stmt->partspec != NULL; cxt.partbound = stmt->partbound; cxt.ofType = (stmt->ofTypename != NULL); + cxt.accessMethod = NULL; Assert(!stmt->ofTypename || !stmt->inhRelations); /* grammar enforces */ @@ -346,6 +348,9 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString) stmt->tableElts = cxt.columns; stmt->constraints = cxt.ckconstraints; + if (cxt.accessMethod != NULL) + stmt->accessMethod = cxt.accessMethod; + result = lappend(cxt.blist, stmt); result = list_concat(result, cxt.alist); result = list_concat(result, save_alist); @@ -1118,6 +1123,11 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla cxt->likeclauses = lappend(cxt->likeclauses, table_like_clause); } + /* CREATE TABLE LIKE ACCESS METHOD is not copied for partitioned table */ + if ((table_like_clause->options & CREATE_TABLE_LIKE_ACCESS_METHOD) != 0 && + !cxt->ispartitioned) + cxt->accessMethod = get_am_name(relation->rd_rel->relam); + /* * We may copy extended statistics if requested, since the representation * of CreateStatsStmt doesn't depend on column numbers. diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 48a79a7657..2d5dfe487e 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -677,14 +677,15 @@ typedef struct TableLikeClause typedef enum TableLikeOption { - CREATE_TABLE_LIKE_COMMENTS = 1 << 0, - CREATE_TABLE_LIKE_CONSTRAINTS = 1 << 1, - CREATE_TABLE_LIKE_DEFAULTS = 1 << 2, - CREATE_TABLE_LIKE_GENERATED = 1 << 3, - CREATE_TABLE_LIKE_IDENTITY = 1 << 4, - CREATE_TABLE_LIKE_INDEXES = 1 << 5, - CREATE_TABLE_LIKE_STATISTICS = 1 << 6, - CREATE_TABLE_LIKE_STORAGE = 1 << 7, + CREATE_TABLE_LIKE_ACCESS_METHOD = 1 << 0, + CREATE_TABLE_LIKE_COMMENTS = 1 << 1, + CREATE_TABLE_LIKE_CONSTRAINTS = 1 << 2, + CREATE_TABLE_LIKE_DEFAULTS = 1 << 3, + CREATE_TABLE_LIKE_GENERATED = 1 << 4, + CREATE_TABLE_LIKE_IDENTITY = 1 << 5, + CREATE_TABLE_LIKE_INDEXES = 1 << 6, + CREATE_TABLE_LIKE_STATISTICS = 1 << 7, + CREATE_TABLE_LIKE_STORAGE = 1 << 8, CREATE_TABLE_LIKE_ALL = PG_INT32_MAX } TableLikeOption; diff --git a/src/test/regress/expected/create_table_like.out b/src/test/regress/expected/create_table_like.out index 10d17be23c..a09cd48ed0 100644 --- a/src/test/regress/expected/create_table_like.out +++ b/src/test/regress/expected/create_table_like.out @@ -429,6 +429,18 @@ SELECT s.stxname, objsubid, description FROM pg_description, pg_statistic_ext s ctlt_all_a_b_stat | 0 | ab stats (1 row) +CREATE ACCESS METHOD heapdup TYPE TABLE HANDLER heap_tableam_handler; +CREATE TABLE likeam() USING heapdup; +CREATE TABLE likeamlike(LIKE likeam INCLUDING ALL); +-- pg_regress helpfully hides the Access Method output, which we need: +SELECT a.amname FROM pg_class c JOIN pg_am a ON c.relam=a.oid WHERE c.oid='likeamlike'::regclass; + amname +--------- + heapdup +(1 row) + +DROP TABLE likeam, likeamlike; +DROP ACCESS METHOD heapdup; CREATE TABLE inh_error1 () INHERITS (ctlt1, ctlt4); NOTICE: merging multiple inherited definitions of column "a" ERROR: inherited column "a" has a storage parameter conflict diff --git a/src/test/regress/sql/create_table_like.sql b/src/test/regress/sql/create_table_like.sql index 06b76f949d..ee6c464851 100644 --- a/src/test/regress/sql/create_table_like.sql +++ b/src/test/regress/sql/create_table_like.sql @@ -165,6 +165,14 @@ CREATE TABLE ctlt_all (LIKE ctlt1 INCLUDING ALL); SELECT c.relname, objsubid, description FROM pg_description, pg_index i, pg_class c WHERE classoid = 'pg_class'::regclass AND objoid = i.indexrelid AND c.oid = i.indexrelid AND i.indrelid = 'ctlt_all'::regclass ORDER BY c.relname, objsubid; SELECT s.stxname, objsubid, description FROM pg_description, pg_statistic_ext s WHERE classoid = 'pg_statistic_ext'::regclass AND objoid = s.oid AND s.stxrelid = 'ctlt_all'::regclass ORDER BY s.stxname, objsubid; +CREATE ACCESS METHOD heapdup TYPE TABLE HANDLER heap_tableam_handler; +CREATE TABLE likeam() USING heapdup; +CREATE TABLE likeamlike(LIKE likeam INCLUDING ALL); +-- pg_regress helpfully hides the Access Method output, which we need: +SELECT a.amname FROM pg_class c JOIN pg_am a ON c.relam=a.oid WHERE c.oid='likeamlike'::regclass; +DROP TABLE likeam, likeamlike; +DROP ACCESS METHOD heapdup; + CREATE TABLE inh_error1 () INHERITS (ctlt1, ctlt4); CREATE TABLE inh_error2 (LIKE ctlt4 INCLUDING STORAGE) INHERITS (ctlt1); -- 2.17.0 --3V7upXqbjpZ4EhLz--