static void _becomeOwner(ArchiveHandle *AH, TocEntry *te);
static void _selectOutputSchema(ArchiveHandle *AH, const char *schemaName);
static void _selectTablespace(ArchiveHandle *AH, const char *tablespace);
+static void _selectTableAccessMethod(ArchiveHandle *AH, const char *tableam);
static void processEncodingEntry(ArchiveHandle *AH, TocEntry *te);
static void processStdStringsEntry(ArchiveHandle *AH, TocEntry *te);
static void processSearchPathEntry(ArchiveHandle *AH, TocEntry *te);
newToc->tag = pg_strdup(opts->tag);
newToc->namespace = opts->namespace ? pg_strdup(opts->namespace) : NULL;
newToc->tablespace = opts->tablespace ? pg_strdup(opts->tablespace) : NULL;
+ newToc->tableam = opts->tableam ? pg_strdup(opts->tableam) : NULL;
newToc->owner = pg_strdup(opts->owner);
newToc->desc = pg_strdup(opts->description);
newToc->defn = pg_strdup(opts->createStmt);
AH->currUser = NULL; /* unknown */
AH->currSchema = NULL; /* ditto */
AH->currTablespace = NULL; /* ditto */
+ AH->currTableAm = NULL; /* ditto */
AH->toc = (TocEntry *) pg_malloc0(sizeof(TocEntry));
WriteStr(AH, te->copyStmt);
WriteStr(AH, te->namespace);
WriteStr(AH, te->tablespace);
+ WriteStr(AH, te->tableam);
WriteStr(AH, te->owner);
WriteStr(AH, "false");
if (AH->version >= K_VERS_1_10)
te->tablespace = ReadStr(AH);
+ if (AH->version >= K_VERS_1_14)
+ te->tableam = ReadStr(AH);
+
te->owner = ReadStr(AH);
if (AH->version < K_VERS_1_9 || strcmp(ReadStr(AH), "true") == 0)
write_msg(modulename,
destroyPQExpBuffer(qry);
}
+/*
+ * Set the proper default_table_access_method value for the table.
+ */
+static void
+_selectTableAccessMethod(ArchiveHandle *AH, const char *tableam)
+{
+ PQExpBuffer cmd;
+ const char *want, *have;
+
+ have = AH->currTableAm;
+ want = tableam;
+
+ if (!want)
+ return;
+
+ if (have && strcmp(want, have) == 0)
+ return;
+
+ cmd = createPQExpBuffer();
+ appendPQExpBuffer(cmd, "SET default_table_access_method = %s;", fmtId(want));
+
+ if (RestoringToDB(AH))
+ {
+ PGresult *res;
+
+ res = PQexec(AH->connection, cmd->data);
+
+ if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
+ warn_or_exit_horribly(AH, modulename,
+ "could not set default_table_access_method: %s",
+ PQerrorMessage(AH->connection));
+
+ PQclear(res);
+ }
+ else
+ ahprintf(AH, "%s\n\n", cmd->data);
+
+ destroyPQExpBuffer(cmd);
+
+ AH->currTableAm = pg_strdup(want);
+}
+
/*
* Extract an object description for a TOC entry, and append it to buf.
*
{
RestoreOptions *ropt = AH->public.ropt;
- /* Select owner, schema, and tablespace as necessary */
+ /* Select owner, schema, tablespace and default AM as necessary */
_becomeOwner(AH, te);
_selectOutputSchema(AH, te->namespace);
_selectTablespace(AH, te->tablespace);
+ _selectTableAccessMethod(AH, te->tableam);
/* Emit header comment for item */
if (!AH->noTocComments)
if (AH->currTablespace)
free(AH->currTablespace);
AH->currTablespace = NULL;
+ if (AH->currTableAm)
+ free(AH->currTableAm);
+ AH->currTableAm = NULL;
}
/*
free(AH->currSchema);
if (AH->currTablespace)
free(AH->currTablespace);
+ if (AH->currTableAm)
+ free(AH->currTableAm);
if (AH->savedPassword)
free(AH->savedPassword);
* entries */
#define K_VERS_1_13 MAKE_ARCHIVE_VERSION(1, 13, 0) /* change search_path
* behavior */
+#define K_VERS_1_14 MAKE_ARCHIVE_VERSION(1, 14, 0) /* add tableam */
/*
* Current archive version number (the format we can output)
*/
#define K_VERS_MAJOR 1
-#define K_VERS_MINOR 13
+#define K_VERS_MINOR 14
#define K_VERS_REV 0
#define K_VERS_SELF MAKE_ARCHIVE_VERSION(K_VERS_MAJOR, K_VERS_MINOR, K_VERS_REV);
char *currUser; /* current username, or NULL if unknown */
char *currSchema; /* current schema, or NULL */
char *currTablespace; /* current tablespace, or NULL */
+ char *currTableAm; /* current table access method, or NULL */
void *lo_buf;
size_t lo_buf_used;
char *namespace; /* null or empty string if not in a schema */
char *tablespace; /* null if not in a tablespace; empty string
* means use database default */
+ char *tableam; /* table access method, only for TABLE tags */
char *owner;
char *desc;
char *defn;
const char *tag;
const char *namespace;
const char *tablespace;
+ const char *tableam;
const char *owner;
const char *description;
teSection section;
int i_partkeydef;
int i_ispartition;
int i_partbound;
+ int i_amname;
/*
* Find all the tables and table-like objects.
"tc.relfrozenxid AS tfrozenxid, "
"tc.relminmxid AS tminmxid, "
"c.relpersistence, c.relispopulated, "
- "c.relreplident, c.relpages, "
+ "c.relreplident, c.relpages, am.amname, "
"CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"d.objsubid = 0 AND "
"d.refclassid = c.tableoid AND d.deptype IN ('a', 'i')) "
"LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
+ "LEFT JOIN pg_am am ON (c.relam = am.oid) "
"LEFT JOIN pg_init_privs pip ON "
"(c.oid = pip.objoid "
"AND pip.classoid = 'pg_class'::regclass "
i_partkeydef = PQfnumber(res, "partkeydef");
i_ispartition = PQfnumber(res, "ispartition");
i_partbound = PQfnumber(res, "partbound");
+ i_amname = PQfnumber(res, "amname");
if (dopt->lockWaitTimeout)
{
else
tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
+ if (PQgetisnull(res, i, i_amname))
+ tblinfo[i].amname = NULL;
+ else
+ tblinfo[i].amname = pg_strdup(PQgetvalue(res, i, i_amname));
/* other fields were zeroed above */
case AMTYPE_INDEX:
appendPQExpBuffer(q, "TYPE INDEX ");
break;
+ case AMTYPE_TABLE:
+ appendPQExpBuffer(q, "TYPE TABLE ");
+ break;
default:
write_msg(NULL, "WARNING: invalid type \"%c\" of access method \"%s\"\n",
aminfo->amtype, qamname);
tbinfo->dobj.namespace->dobj.name);
if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+ {
+ char *tableam = NULL;
+
+ if (tbinfo->relkind == RELKIND_RELATION ||
+ tbinfo->relkind == RELKIND_MATVIEW)
+ tableam = tbinfo->amname;
+
ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
.namespace = tbinfo->dobj.namespace->dobj.name,
.tablespace = (tbinfo->relkind == RELKIND_VIEW) ?
NULL : tbinfo->reltablespace,
+ .tableam = tableam,
.owner = tbinfo->rolname,
.description = reltypename,
.section = tbinfo->postponed_def ?
SECTION_POST_DATA : SECTION_PRE_DATA,
.createStmt = q->data,
.dropStmt = delq->data));
-
+ }
/* Dump Table Comments */
if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
char *partkeydef; /* partition key definition */
char *partbound; /* partition bound definition */
bool needs_override; /* has GENERATED ALWAYS AS IDENTITY */
+ char *amname; /* relation access method */
/*
* Stuff computed only for dumpable tables.
unlike => { no_privs => 1, },
},
+
+ 'CREATE ACCESS METHOD regress_test_table_am' => {
+ create_order => 11,
+ create_sql => 'CREATE ACCESS METHOD regress_table_am TYPE TABLE HANDLER heap_tableam_handler;',
+ regexp => qr/^
+ \QCREATE ACCESS METHOD regress_table_am TYPE TABLE HANDLER heap_tableam_handler;\E
+ \n/xm,
+ like => {
+ %full_runs,
+ section_pre_data => 1,
+ },
+ },
+
+ # It's a bit tricky to ensure that the proper SET of default table
+ # AM occurs. To achieve that we create a table with the standard
+ # AM, test AM, standard AM. That guarantees that there needs to be
+ # a SET interspersed. Then use a regex that prevents interspersed
+ # SET ...; statements, followed by the exptected CREATE TABLE. Not
+ # pretty, but seems hard to do better in this framework.
+ 'CREATE TABLE regress_pg_dump_table_am' => {
+ create_order => 12,
+ create_sql => '
+ CREATE TABLE dump_test.regress_pg_dump_table_am_0() USING heap;
+ CREATE TABLE dump_test.regress_pg_dump_table_am_1 (col1 int) USING regress_table_am;
+ CREATE TABLE dump_test.regress_pg_dump_table_am_2() USING heap;',
+ regexp => qr/^
+ \QSET default_table_access_method = regress_table_am;\E
+ (\n(?!SET[^;]+;)[^\n]*)*
+ \n\QCREATE TABLE dump_test.regress_pg_dump_table_am_1 (\E
+ \n\s+\Qcol1 integer\E
+ \n\);/xm,
+ like => {
+ %full_runs,
+ %dump_test_schema_runs,
+ section_pre_data => 1,
+ },
+ unlike => { exclude_dump_test_schema => 1},
+ },
+
+ 'CREATE MATERIALIZED VIEW regress_pg_dump_matview_am' => {
+ create_order => 13,
+ create_sql => '
+ CREATE MATERIALIZED VIEW dump_test.regress_pg_dump_matview_am_0 USING heap AS SELECT 1;
+ CREATE MATERIALIZED VIEW dump_test.regress_pg_dump_matview_am_1
+ USING regress_table_am AS SELECT count(*) FROM pg_class;
+ CREATE MATERIALIZED VIEW dump_test.regress_pg_dump_matview_am_2 USING heap AS SELECT 1;',
+ regexp => qr/^
+ \QSET default_table_access_method = regress_table_am;\E
+ (\n(?!SET[^;]+;)[^\n]*)*
+ \QCREATE MATERIALIZED VIEW dump_test.regress_pg_dump_matview_am_1 AS\E
+ \n\s+\QSELECT count(*) AS count\E
+ \n\s+\QFROM pg_class\E
+ \n\s+\QWITH NO DATA;\E\n/xm,
+ like => {
+ %full_runs,
+ %dump_test_schema_runs,
+ section_pre_data => 1,
+ },
+ unlike => { exclude_dump_test_schema => 1},
+ }
);
#########################################