Skip to content

Commit 3b925e9

Browse files
committed
tableam: Add pg_dump support.
This adds pg_dump support for table AMs in a similar manner to how tablespaces are handled. That is, instead of specifying the AM for every CREATE TABLE etc, emit SET default_table_access_method statements. That makes it easier to change the AM for all/most tables in a dump, and allows restore to succeed even if some AM is not available. This increases the dump archive version, as a tables/matview's AM needs to be tracked therein. Author: Dimitri Dolgov, Andres Freund Discussion: https://postgr.es/m/20180703070645.wchpu5muyto5n647@alap3.anarazel.de https://postgr.es/m/20190304234700.w5tmhducs5wxgzls@alap3.anarazel.de
1 parent 8586bf7 commit 3b925e9

File tree

5 files changed

+142
-4
lines changed

5 files changed

+142
-4
lines changed

src/bin/pg_dump/pg_backup_archiver.c

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ static void _becomeUser(ArchiveHandle *AH, const char *user);
8585
static void _becomeOwner(ArchiveHandle *AH, TocEntry *te);
8686
static void _selectOutputSchema(ArchiveHandle *AH, const char *schemaName);
8787
static void _selectTablespace(ArchiveHandle *AH, const char *tablespace);
88+
static void _selectTableAccessMethod(ArchiveHandle *AH, const char *tableam);
8889
static void processEncodingEntry(ArchiveHandle *AH, TocEntry *te);
8990
static void processStdStringsEntry(ArchiveHandle *AH, TocEntry *te);
9091
static void processSearchPathEntry(ArchiveHandle *AH, TocEntry *te);
@@ -1090,6 +1091,7 @@ ArchiveEntry(Archive *AHX, CatalogId catalogId, DumpId dumpId,
10901091
newToc->tag = pg_strdup(opts->tag);
10911092
newToc->namespace = opts->namespace ? pg_strdup(opts->namespace) : NULL;
10921093
newToc->tablespace = opts->tablespace ? pg_strdup(opts->tablespace) : NULL;
1094+
newToc->tableam = opts->tableam ? pg_strdup(opts->tableam) : NULL;
10931095
newToc->owner = pg_strdup(opts->owner);
10941096
newToc->desc = pg_strdup(opts->description);
10951097
newToc->defn = pg_strdup(opts->createStmt);
@@ -2350,6 +2352,7 @@ _allocAH(const char *FileSpec, const ArchiveFormat fmt,
23502352
AH->currUser = NULL; /* unknown */
23512353
AH->currSchema = NULL; /* ditto */
23522354
AH->currTablespace = NULL; /* ditto */
2355+
AH->currTableAm = NULL; /* ditto */
23532356

23542357
AH->toc = (TocEntry *) pg_malloc0(sizeof(TocEntry));
23552358

@@ -2576,6 +2579,7 @@ WriteToc(ArchiveHandle *AH)
25762579
WriteStr(AH, te->copyStmt);
25772580
WriteStr(AH, te->namespace);
25782581
WriteStr(AH, te->tablespace);
2582+
WriteStr(AH, te->tableam);
25792583
WriteStr(AH, te->owner);
25802584
WriteStr(AH, "false");
25812585

@@ -2678,6 +2682,9 @@ ReadToc(ArchiveHandle *AH)
26782682
if (AH->version >= K_VERS_1_10)
26792683
te->tablespace = ReadStr(AH);
26802684

2685+
if (AH->version >= K_VERS_1_14)
2686+
te->tableam = ReadStr(AH);
2687+
26812688
te->owner = ReadStr(AH);
26822689
if (AH->version < K_VERS_1_9 || strcmp(ReadStr(AH), "true") == 0)
26832690
write_msg(modulename,
@@ -3431,6 +3438,48 @@ _selectTablespace(ArchiveHandle *AH, const char *tablespace)
34313438
destroyPQExpBuffer(qry);
34323439
}
34333440

3441+
/*
3442+
* Set the proper default_table_access_method value for the table.
3443+
*/
3444+
static void
3445+
_selectTableAccessMethod(ArchiveHandle *AH, const char *tableam)
3446+
{
3447+
PQExpBuffer cmd;
3448+
const char *want, *have;
3449+
3450+
have = AH->currTableAm;
3451+
want = tableam;
3452+
3453+
if (!want)
3454+
return;
3455+
3456+
if (have && strcmp(want, have) == 0)
3457+
return;
3458+
3459+
cmd = createPQExpBuffer();
3460+
appendPQExpBuffer(cmd, "SET default_table_access_method = %s;", fmtId(want));
3461+
3462+
if (RestoringToDB(AH))
3463+
{
3464+
PGresult *res;
3465+
3466+
res = PQexec(AH->connection, cmd->data);
3467+
3468+
if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
3469+
warn_or_exit_horribly(AH, modulename,
3470+
"could not set default_table_access_method: %s",
3471+
PQerrorMessage(AH->connection));
3472+
3473+
PQclear(res);
3474+
}
3475+
else
3476+
ahprintf(AH, "%s\n\n", cmd->data);
3477+
3478+
destroyPQExpBuffer(cmd);
3479+
3480+
AH->currTableAm = pg_strdup(want);
3481+
}
3482+
34343483
/*
34353484
* Extract an object description for a TOC entry, and append it to buf.
34363485
*
@@ -3526,10 +3575,11 @@ _printTocEntry(ArchiveHandle *AH, TocEntry *te, bool isData)
35263575
{
35273576
RestoreOptions *ropt = AH->public.ropt;
35283577

3529-
/* Select owner, schema, and tablespace as necessary */
3578+
/* Select owner, schema, tablespace and default AM as necessary */
35303579
_becomeOwner(AH, te);
35313580
_selectOutputSchema(AH, te->namespace);
35323581
_selectTablespace(AH, te->tablespace);
3582+
_selectTableAccessMethod(AH, te->tableam);
35333583

35343584
/* Emit header comment for item */
35353585
if (!AH->noTocComments)
@@ -4006,6 +4056,9 @@ restore_toc_entries_prefork(ArchiveHandle *AH, TocEntry *pending_list)
40064056
if (AH->currTablespace)
40074057
free(AH->currTablespace);
40084058
AH->currTablespace = NULL;
4059+
if (AH->currTableAm)
4060+
free(AH->currTableAm);
4061+
AH->currTableAm = NULL;
40094062
}
40104063

40114064
/*
@@ -4891,6 +4944,8 @@ DeCloneArchive(ArchiveHandle *AH)
48914944
free(AH->currSchema);
48924945
if (AH->currTablespace)
48934946
free(AH->currTablespace);
4947+
if (AH->currTableAm)
4948+
free(AH->currTableAm);
48944949
if (AH->savedPassword)
48954950
free(AH->savedPassword);
48964951

src/bin/pg_dump/pg_backup_archiver.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ typedef z_stream *z_streamp;
9494
* entries */
9595
#define K_VERS_1_13 MAKE_ARCHIVE_VERSION(1, 13, 0) /* change search_path
9696
* behavior */
97+
#define K_VERS_1_14 MAKE_ARCHIVE_VERSION(1, 14, 0) /* add tableam */
9798

9899
/*
99100
* Current archive version number (the format we can output)
@@ -102,7 +103,7 @@ typedef z_stream *z_streamp;
102103
* https://postgr.es/m/20190227123217.GA27552@alvherre.pgsql
103104
*/
104105
#define K_VERS_MAJOR 1
105-
#define K_VERS_MINOR 13
106+
#define K_VERS_MINOR 14
106107
#define K_VERS_REV 0
107108
#define K_VERS_SELF MAKE_ARCHIVE_VERSION(K_VERS_MAJOR, K_VERS_MINOR, K_VERS_REV);
108109

@@ -352,6 +353,7 @@ struct _archiveHandle
352353
char *currUser; /* current username, or NULL if unknown */
353354
char *currSchema; /* current schema, or NULL */
354355
char *currTablespace; /* current tablespace, or NULL */
356+
char *currTableAm; /* current table access method, or NULL */
355357

356358
void *lo_buf;
357359
size_t lo_buf_used;
@@ -378,6 +380,7 @@ struct _tocEntry
378380
char *namespace; /* null or empty string if not in a schema */
379381
char *tablespace; /* null if not in a tablespace; empty string
380382
* means use database default */
383+
char *tableam; /* table access method, only for TABLE tags */
381384
char *owner;
382385
char *desc;
383386
char *defn;
@@ -416,6 +419,7 @@ typedef struct _archiveOpts
416419
const char *tag;
417420
const char *namespace;
418421
const char *tablespace;
422+
const char *tableam;
419423
const char *owner;
420424
const char *description;
421425
teSection section;

src/bin/pg_dump/pg_dump.c

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5856,6 +5856,7 @@ getTables(Archive *fout, int *numTables)
58565856
int i_partkeydef;
58575857
int i_ispartition;
58585858
int i_partbound;
5859+
int i_amname;
58595860

58605861
/*
58615862
* Find all the tables and table-like objects.
@@ -5941,7 +5942,7 @@ getTables(Archive *fout, int *numTables)
59415942
"tc.relfrozenxid AS tfrozenxid, "
59425943
"tc.relminmxid AS tminmxid, "
59435944
"c.relpersistence, c.relispopulated, "
5944-
"c.relreplident, c.relpages, "
5945+
"c.relreplident, c.relpages, am.amname, "
59455946
"CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
59465947
"d.refobjid AS owning_tab, "
59475948
"d.refobjsubid AS owning_col, "
@@ -5972,6 +5973,7 @@ getTables(Archive *fout, int *numTables)
59725973
"d.objsubid = 0 AND "
59735974
"d.refclassid = c.tableoid AND d.deptype IN ('a', 'i')) "
59745975
"LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
5976+
"LEFT JOIN pg_am am ON (c.relam = am.oid) "
59755977
"LEFT JOIN pg_init_privs pip ON "
59765978
"(c.oid = pip.objoid "
59775979
"AND pip.classoid = 'pg_class'::regclass "
@@ -6439,6 +6441,7 @@ getTables(Archive *fout, int *numTables)
64396441
i_partkeydef = PQfnumber(res, "partkeydef");
64406442
i_ispartition = PQfnumber(res, "ispartition");
64416443
i_partbound = PQfnumber(res, "partbound");
6444+
i_amname = PQfnumber(res, "amname");
64426445

64436446
if (dopt->lockWaitTimeout)
64446447
{
@@ -6508,6 +6511,10 @@ getTables(Archive *fout, int *numTables)
65086511
else
65096512
tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
65106513
tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
6514+
if (PQgetisnull(res, i, i_amname))
6515+
tblinfo[i].amname = NULL;
6516+
else
6517+
tblinfo[i].amname = pg_strdup(PQgetvalue(res, i, i_amname));
65116518

65126519
/* other fields were zeroed above */
65136520

@@ -12632,6 +12639,9 @@ dumpAccessMethod(Archive *fout, AccessMethodInfo *aminfo)
1263212639
case AMTYPE_INDEX:
1263312640
appendPQExpBuffer(q, "TYPE INDEX ");
1263412641
break;
12642+
case AMTYPE_TABLE:
12643+
appendPQExpBuffer(q, "TYPE TABLE ");
12644+
break;
1263512645
default:
1263612646
write_msg(NULL, "WARNING: invalid type \"%c\" of access method \"%s\"\n",
1263712647
aminfo->amtype, qamname);
@@ -16067,18 +16077,26 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
1606716077
tbinfo->dobj.namespace->dobj.name);
1606816078

1606916079
if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16080+
{
16081+
char *tableam = NULL;
16082+
16083+
if (tbinfo->relkind == RELKIND_RELATION ||
16084+
tbinfo->relkind == RELKIND_MATVIEW)
16085+
tableam = tbinfo->amname;
16086+
1607016087
ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
1607116088
ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
1607216089
.namespace = tbinfo->dobj.namespace->dobj.name,
1607316090
.tablespace = (tbinfo->relkind == RELKIND_VIEW) ?
1607416091
NULL : tbinfo->reltablespace,
16092+
.tableam = tableam,
1607516093
.owner = tbinfo->rolname,
1607616094
.description = reltypename,
1607716095
.section = tbinfo->postponed_def ?
1607816096
SECTION_POST_DATA : SECTION_PRE_DATA,
1607916097
.createStmt = q->data,
1608016098
.dropStmt = delq->data));
16081-
16099+
}
1608216100

1608316101
/* Dump Table Comments */
1608416102
if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)

src/bin/pg_dump/pg_dump.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@ typedef struct _tableInfo
324324
char *partkeydef; /* partition key definition */
325325
char *partbound; /* partition bound definition */
326326
bool needs_override; /* has GENERATED ALWAYS AS IDENTITY */
327+
char *amname; /* relation access method */
327328

328329
/*
329330
* Stuff computed only for dumpable tables.

src/bin/pg_dump/t/002_pg_dump.pl

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3070,6 +3070,66 @@
30703070
unlike => { no_privs => 1, },
30713071
},
30723072
3073+
3074+
'CREATE ACCESS METHOD regress_test_table_am' => {
3075+
create_order => 11,
3076+
create_sql => 'CREATE ACCESS METHOD regress_table_am TYPE TABLE HANDLER heap_tableam_handler;',
3077+
regexp => qr/^
3078+
\QCREATE ACCESS METHOD regress_table_am TYPE TABLE HANDLER heap_tableam_handler;\E
3079+
\n/xm,
3080+
like => {
3081+
%full_runs,
3082+
section_pre_data => 1,
3083+
},
3084+
},
3085+
3086+
# It's a bit tricky to ensure that the proper SET of default table
3087+
# AM occurs. To achieve that we create a table with the standard
3088+
# AM, test AM, standard AM. That guarantees that there needs to be
3089+
# a SET interspersed. Then use a regex that prevents interspersed
3090+
# SET ...; statements, followed by the exptected CREATE TABLE. Not
3091+
# pretty, but seems hard to do better in this framework.
3092+
'CREATE TABLE regress_pg_dump_table_am' => {
3093+
create_order => 12,
3094+
create_sql => '
3095+
CREATE TABLE dump_test.regress_pg_dump_table_am_0() USING heap;
3096+
CREATE TABLE dump_test.regress_pg_dump_table_am_1 (col1 int) USING regress_table_am;
3097+
CREATE TABLE dump_test.regress_pg_dump_table_am_2() USING heap;',
3098+
regexp => qr/^
3099+
\QSET default_table_access_method = regress_table_am;\E
3100+
(\n(?!SET[^;]+;)[^\n]*)*
3101+
\n\QCREATE TABLE dump_test.regress_pg_dump_table_am_1 (\E
3102+
\n\s+\Qcol1 integer\E
3103+
\n\);/xm,
3104+
like => {
3105+
%full_runs,
3106+
%dump_test_schema_runs,
3107+
section_pre_data => 1,
3108+
},
3109+
unlike => { exclude_dump_test_schema => 1},
3110+
},
3111+
3112+
'CREATE MATERIALIZED VIEW regress_pg_dump_matview_am' => {
3113+
create_order => 13,
3114+
create_sql => '
3115+
CREATE MATERIALIZED VIEW dump_test.regress_pg_dump_matview_am_0 USING heap AS SELECT 1;
3116+
CREATE MATERIALIZED VIEW dump_test.regress_pg_dump_matview_am_1
3117+
USING regress_table_am AS SELECT count(*) FROM pg_class;
3118+
CREATE MATERIALIZED VIEW dump_test.regress_pg_dump_matview_am_2 USING heap AS SELECT 1;',
3119+
regexp => qr/^
3120+
\QSET default_table_access_method = regress_table_am;\E
3121+
(\n(?!SET[^;]+;)[^\n]*)*
3122+
\QCREATE MATERIALIZED VIEW dump_test.regress_pg_dump_matview_am_1 AS\E
3123+
\n\s+\QSELECT count(*) AS count\E
3124+
\n\s+\QFROM pg_class\E
3125+
\n\s+\QWITH NO DATA;\E\n/xm,
3126+
like => {
3127+
%full_runs,
3128+
%dump_test_schema_runs,
3129+
section_pre_data => 1,
3130+
},
3131+
unlike => { exclude_dump_test_schema => 1},
3132+
}
30733133
);
30743134
30753135
#########################################

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy