1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-30 11:03:19 +03:00

Use PREPARE/EXECUTE for repetitive per-object queries in pg_dump.

For objects such as functions, pg_dump issues the same secondary
data-collection query against each object to be dumped.  This can't
readily be refactored to avoid the repetitive queries, but we can
PREPARE these queries to reduce planning costs.

This patch applies the idea to functions, aggregates, operators, and
data types.  While it could be carried further, the remaining sorts of
objects aren't likely to appear in typical databases enough times to
be worth worrying over.  Moreover, doing the PREPARE is likely to be a
net loss if there aren't at least some dozens of objects to apply the
prepared query to.

Discussion: https://postgr.es/m/7d7eb6128f40401d81b3b7a898b6b4de@W2012-02.nidsa.loc
This commit is contained in:
Tom Lane
2021-12-06 13:14:29 -05:00
parent 9895961529
commit be85727a3d
2 changed files with 540 additions and 374 deletions

View File

@ -58,6 +58,23 @@ typedef enum _teSection
SECTION_POST_DATA /* stuff to be processed after data */ SECTION_POST_DATA /* stuff to be processed after data */
} teSection; } teSection;
/* We need one enum entry per prepared query in pg_dump */
enum _dumpPreparedQueries
{
PREPQUERY_DUMPAGG,
PREPQUERY_DUMPBASETYPE,
PREPQUERY_DUMPCOMPOSITETYPE,
PREPQUERY_DUMPDOMAIN,
PREPQUERY_DUMPENUMTYPE,
PREPQUERY_DUMPFUNC,
PREPQUERY_DUMPOPR,
PREPQUERY_DUMPRANGETYPE,
PREPQUERY_DUMPTABLEATTACH,
PREPQUERY_GETCOLUMNACLS,
PREPQUERY_GETDOMAINCONSTRAINTS,
NUM_PREP_QUERIES /* must be last */
};
/* Parameters needed by ConnectDatabase; same for dump and restore */ /* Parameters needed by ConnectDatabase; same for dump and restore */
typedef struct _connParams typedef struct _connParams
{ {
@ -214,6 +231,9 @@ typedef struct Archive
bool exit_on_error; /* whether to exit on SQL errors... */ bool exit_on_error; /* whether to exit on SQL errors... */
int n_errors; /* number of errors (if no die) */ int n_errors; /* number of errors (if no die) */
/* prepared-query status */
bool *is_prepared; /* indexed by enum _dumpPreparedQueries */
/* The rest is private */ /* The rest is private */
} Archive; } Archive;

View File

@ -1208,6 +1208,12 @@ setup_connection(Archive *AH, const char *dumpencoding,
ExecuteSqlStatement(AH, "SET row_security = off"); ExecuteSqlStatement(AH, "SET row_security = off");
} }
/*
* Initialize prepared-query state to "nothing prepared". We do this here
* so that a parallel dump worker will have its own state.
*/
AH->is_prepared = (bool *) pg_malloc0(NUM_PREP_QUERIES * sizeof(bool));
/* /*
* Start transaction-snapshot mode transaction to dump consistent data. * Start transaction-snapshot mode transaction to dump consistent data.
*/ */
@ -7477,7 +7483,7 @@ getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
{ {
int i; int i;
ConstraintInfo *constrinfo; ConstraintInfo *constrinfo;
PQExpBuffer query; PQExpBuffer query = createPQExpBuffer();
PGresult *res; PGresult *res;
int i_tableoid, int i_tableoid,
i_oid, i_oid,
@ -7485,24 +7491,34 @@ getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
i_consrc; i_consrc;
int ntups; int ntups;
query = createPQExpBuffer(); if (!fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS])
{
/* Set up query for constraint-specific details */
appendPQExpBufferStr(query,
"PREPARE getDomainConstraints(pg_catalog.oid) AS\n");
if (fout->remoteVersion >= 90100) if (fout->remoteVersion >= 90100)
appendPQExpBuffer(query, "SELECT tableoid, oid, conname, " appendPQExpBufferStr(query, "SELECT tableoid, oid, conname, "
"pg_catalog.pg_get_constraintdef(oid) AS consrc, " "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
"convalidated " "convalidated "
"FROM pg_catalog.pg_constraint " "FROM pg_catalog.pg_constraint "
"WHERE contypid = '%u'::pg_catalog.oid " "WHERE contypid = $1 "
"ORDER BY conname", "ORDER BY conname");
tyinfo->dobj.catId.oid);
else else
appendPQExpBuffer(query, "SELECT tableoid, oid, conname, " appendPQExpBufferStr(query, "SELECT tableoid, oid, conname, "
"pg_catalog.pg_get_constraintdef(oid) AS consrc, " "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
"true as convalidated " "true as convalidated "
"FROM pg_catalog.pg_constraint " "FROM pg_catalog.pg_constraint "
"WHERE contypid = '%u'::pg_catalog.oid " "WHERE contypid = $1 "
"ORDER BY conname", "ORDER BY conname");
ExecuteSqlStatement(fout, query->data);
fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS] = true;
}
printfPQExpBuffer(query,
"EXECUTE getDomainConstraints('%u')",
tyinfo->dobj.catId.oid); tyinfo->dobj.catId.oid);
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
@ -10676,17 +10692,30 @@ dumpEnumType(Archive *fout, const TypeInfo *tyinfo)
int i_enumlabel; int i_enumlabel;
int i_oid; int i_oid;
if (!fout->is_prepared[PREPQUERY_DUMPENUMTYPE])
{
/* Set up query for enum-specific details */
appendPQExpBufferStr(query,
"PREPARE dumpEnumType(pg_catalog.oid) AS\n");
if (fout->remoteVersion >= 90100) if (fout->remoteVersion >= 90100)
appendPQExpBuffer(query, "SELECT oid, enumlabel " appendPQExpBufferStr(query, "SELECT oid, enumlabel "
"FROM pg_catalog.pg_enum " "FROM pg_catalog.pg_enum "
"WHERE enumtypid = '%u'" "WHERE enumtypid = $1 "
"ORDER BY enumsortorder", "ORDER BY enumsortorder");
tyinfo->dobj.catId.oid);
else else
appendPQExpBuffer(query, "SELECT oid, enumlabel " appendPQExpBufferStr(query, "SELECT oid, enumlabel "
"FROM pg_catalog.pg_enum " "FROM pg_catalog.pg_enum "
"WHERE enumtypid = '%u'" "WHERE enumtypid = $1 "
"ORDER BY oid", "ORDER BY oid");
ExecuteSqlStatement(fout, query->data);
fout->is_prepared[PREPQUERY_DUMPENUMTYPE] = true;
}
printfPQExpBuffer(query,
"EXECUTE dumpEnumType('%u')",
tyinfo->dobj.catId.oid); tyinfo->dobj.catId.oid);
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
@ -10806,17 +10835,23 @@ dumpRangeType(Archive *fout, const TypeInfo *tyinfo)
char *qualtypname; char *qualtypname;
char *procname; char *procname;
appendPQExpBuffer(query, if (!fout->is_prepared[PREPQUERY_DUMPRANGETYPE])
{
/* Set up query for range-specific details */
appendPQExpBufferStr(query,
"PREPARE dumpRangeType(pg_catalog.oid) AS\n");
appendPQExpBufferStr(query,
"SELECT "); "SELECT ");
if (fout->remoteVersion >= 140000) if (fout->remoteVersion >= 140000)
appendPQExpBuffer(query, appendPQExpBufferStr(query,
"pg_catalog.format_type(rngmultitypid, NULL) AS rngmultitype, "); "pg_catalog.format_type(rngmultitypid, NULL) AS rngmultitype, ");
else else
appendPQExpBuffer(query, appendPQExpBufferStr(query,
"NULL AS rngmultitype, "); "NULL AS rngmultitype, ");
appendPQExpBuffer(query, appendPQExpBufferStr(query,
"pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, " "pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
"opc.opcname AS opcname, " "opc.opcname AS opcname, "
"(SELECT nspname FROM pg_catalog.pg_namespace nsp " "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
@ -10828,7 +10863,15 @@ dumpRangeType(Archive *fout, const TypeInfo *tyinfo)
"FROM pg_catalog.pg_range r, pg_catalog.pg_type st, " "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
" pg_catalog.pg_opclass opc " " pg_catalog.pg_opclass opc "
"WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND " "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
"rngtypid = '%u'", "rngtypid = $1");
ExecuteSqlStatement(fout, query->data);
fout->is_prepared[PREPQUERY_DUMPRANGETYPE] = true;
}
printfPQExpBuffer(query,
"EXECUTE dumpRangeType('%u')",
tyinfo->dobj.catId.oid); tyinfo->dobj.catId.oid);
res = ExecuteSqlQueryForSingleRow(fout, query->data); res = ExecuteSqlQueryForSingleRow(fout, query->data);
@ -11036,7 +11079,12 @@ dumpBaseType(Archive *fout, const TypeInfo *tyinfo)
char *typdefault; char *typdefault;
bool typdefault_is_literal = false; bool typdefault_is_literal = false;
/* Fetch type-specific details */ if (!fout->is_prepared[PREPQUERY_DUMPBASETYPE])
{
/* Set up query for type-specific details */
appendPQExpBufferStr(query,
"PREPARE dumpBaseType(pg_catalog.oid) AS\n");
appendPQExpBufferStr(query, "SELECT typlen, " appendPQExpBufferStr(query, "SELECT typlen, "
"typinput, typoutput, typreceive, typsend, " "typinput, typoutput, typreceive, typsend, "
"typreceive::pg_catalog.oid AS typreceiveoid, " "typreceive::pg_catalog.oid AS typreceiveoid, "
@ -11083,8 +11131,16 @@ dumpBaseType(Archive *fout, const TypeInfo *tyinfo)
appendPQExpBufferStr(query, appendPQExpBufferStr(query,
"pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "); "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault ");
appendPQExpBuffer(query, "FROM pg_catalog.pg_type " appendPQExpBufferStr(query, "FROM pg_catalog.pg_type "
"WHERE oid = '%u'::pg_catalog.oid", "WHERE oid = $1");
ExecuteSqlStatement(fout, query->data);
fout->is_prepared[PREPQUERY_DUMPBASETYPE] = true;
}
printfPQExpBuffer(query,
"EXECUTE dumpBaseType('%u')",
tyinfo->dobj.catId.oid); tyinfo->dobj.catId.oid);
res = ExecuteSqlQueryForSingleRow(fout, query->data); res = ExecuteSqlQueryForSingleRow(fout, query->data);
@ -11279,11 +11335,16 @@ dumpDomain(Archive *fout, const TypeInfo *tyinfo)
Oid typcollation; Oid typcollation;
bool typdefault_is_literal = false; bool typdefault_is_literal = false;
/* Fetch domain specific details */ if (!fout->is_prepared[PREPQUERY_DUMPDOMAIN])
{
/* Set up query for domain-specific details */
appendPQExpBufferStr(query,
"PREPARE dumpDomain(pg_catalog.oid) AS\n");
if (fout->remoteVersion >= 90100) if (fout->remoteVersion >= 90100)
{ {
/* typcollation is new in 9.1 */ /* typcollation is new in 9.1 */
appendPQExpBuffer(query, "SELECT t.typnotnull, " appendPQExpBufferStr(query, "SELECT t.typnotnull, "
"pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, " "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
"pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, " "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
"t.typdefault, " "t.typdefault, "
@ -11291,20 +11352,27 @@ dumpDomain(Archive *fout, const TypeInfo *tyinfo)
"THEN t.typcollation ELSE 0 END AS typcollation " "THEN t.typcollation ELSE 0 END AS typcollation "
"FROM pg_catalog.pg_type t " "FROM pg_catalog.pg_type t "
"LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) " "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
"WHERE t.oid = '%u'::pg_catalog.oid", "WHERE t.oid = $1");
tyinfo->dobj.catId.oid);
} }
else else
{ {
appendPQExpBuffer(query, "SELECT typnotnull, " appendPQExpBufferStr(query, "SELECT typnotnull, "
"pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, " "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, "
"pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, " "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
"typdefault, 0 AS typcollation " "typdefault, 0 AS typcollation "
"FROM pg_catalog.pg_type " "FROM pg_catalog.pg_type "
"WHERE oid = '%u'::pg_catalog.oid", "WHERE oid = $1");
tyinfo->dobj.catId.oid);
} }
ExecuteSqlStatement(fout, query->data);
fout->is_prepared[PREPQUERY_DUMPDOMAIN] = true;
}
printfPQExpBuffer(query,
"EXECUTE dumpDomain('%u')",
tyinfo->dobj.catId.oid);
res = ExecuteSqlQueryForSingleRow(fout, query->data); res = ExecuteSqlQueryForSingleRow(fout, query->data);
typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull")); typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
@ -11457,7 +11525,12 @@ dumpCompositeType(Archive *fout, const TypeInfo *tyinfo)
int i; int i;
int actual_atts; int actual_atts;
/* Fetch type specific details */ if (!fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE])
{
/* Set up query for type-specific details */
appendPQExpBufferStr(query,
"PREPARE dumpCompositeType(pg_catalog.oid) AS\n");
if (fout->remoteVersion >= 90100) if (fout->remoteVersion >= 90100)
{ {
/* /*
@ -11467,7 +11540,7 @@ dumpCompositeType(Archive *fout, const TypeInfo *tyinfo)
* attcollations cheaply. atttypid will be 0 for dropped columns; * attcollations cheaply. atttypid will be 0 for dropped columns;
* collation does not matter for those. * collation does not matter for those.
*/ */
appendPQExpBuffer(query, "SELECT a.attname, " appendPQExpBufferStr(query, "SELECT a.attname, "
"pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, " "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
"a.attlen, a.attalign, a.attisdropped, " "a.attlen, a.attalign, a.attisdropped, "
"CASE WHEN a.attcollation <> at.typcollation " "CASE WHEN a.attcollation <> at.typcollation "
@ -11475,9 +11548,8 @@ dumpCompositeType(Archive *fout, const TypeInfo *tyinfo)
"FROM pg_catalog.pg_type ct " "FROM pg_catalog.pg_type ct "
"JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid " "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
"LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid " "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
"WHERE ct.oid = '%u'::pg_catalog.oid " "WHERE ct.oid = $1 "
"ORDER BY a.attnum ", "ORDER BY a.attnum");
tyinfo->dobj.catId.oid);
} }
else else
{ {
@ -11485,17 +11557,25 @@ dumpCompositeType(Archive *fout, const TypeInfo *tyinfo)
* Since ALTER TYPE could not drop columns until 9.1, attisdropped * Since ALTER TYPE could not drop columns until 9.1, attisdropped
* should always be false. * should always be false.
*/ */
appendPQExpBuffer(query, "SELECT a.attname, " appendPQExpBufferStr(query, "SELECT a.attname, "
"pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, " "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
"a.attlen, a.attalign, a.attisdropped, " "a.attlen, a.attalign, a.attisdropped, "
"0 AS attcollation " "0 AS attcollation "
"FROM pg_catalog.pg_type ct, pg_catalog.pg_attribute a " "FROM pg_catalog.pg_type ct, pg_catalog.pg_attribute a "
"WHERE ct.oid = '%u'::pg_catalog.oid " "WHERE ct.oid = $1 "
"AND a.attrelid = ct.typrelid " "AND a.attrelid = ct.typrelid "
"ORDER BY a.attnum ", "ORDER BY a.attnum");
tyinfo->dobj.catId.oid);
} }
ExecuteSqlStatement(fout, query->data);
fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE] = true;
}
printfPQExpBuffer(query,
"EXECUTE dumpCompositeType('%u')",
tyinfo->dobj.catId.oid);
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
ntups = PQntuples(res); ntups = PQntuples(res);
@ -12114,7 +12194,12 @@ dumpFunc(Archive *fout, const FuncInfo *finfo)
delqry = createPQExpBuffer(); delqry = createPQExpBuffer();
asPart = createPQExpBuffer(); asPart = createPQExpBuffer();
/* Fetch function-specific details */ if (!fout->is_prepared[PREPQUERY_DUMPFUNC])
{
/* Set up query for function-specific details */
appendPQExpBufferStr(query,
"PREPARE dumpFunc(pg_catalog.oid) AS\n");
appendPQExpBufferStr(query, appendPQExpBufferStr(query,
"SELECT\n" "SELECT\n"
"proretset,\n" "proretset,\n"
@ -12200,10 +12285,18 @@ dumpFunc(Archive *fout, const FuncInfo *finfo)
appendPQExpBufferStr(query, appendPQExpBufferStr(query,
"NULL AS prosqlbody\n"); "NULL AS prosqlbody\n");
appendPQExpBuffer(query, appendPQExpBufferStr(query,
"FROM pg_catalog.pg_proc p, pg_catalog.pg_language l\n" "FROM pg_catalog.pg_proc p, pg_catalog.pg_language l\n"
"WHERE p.oid = '%u'::pg_catalog.oid " "WHERE p.oid = $1 "
"AND l.oid = p.prolang", "AND l.oid = p.prolang");
ExecuteSqlStatement(fout, query->data);
fout->is_prepared[PREPQUERY_DUMPFUNC] = true;
}
printfPQExpBuffer(query,
"EXECUTE dumpFunc('%u')",
finfo->dobj.catId.oid); finfo->dobj.catId.oid);
res = ExecuteSqlQueryForSingleRow(fout, query->data); res = ExecuteSqlQueryForSingleRow(fout, query->data);
@ -12870,9 +12963,15 @@ dumpOpr(Archive *fout, const OprInfo *oprinfo)
oprid = createPQExpBuffer(); oprid = createPQExpBuffer();
details = createPQExpBuffer(); details = createPQExpBuffer();
if (!fout->is_prepared[PREPQUERY_DUMPOPR])
{
/* Set up query for operator-specific details */
appendPQExpBufferStr(query,
"PREPARE dumpOpr(pg_catalog.oid) AS\n");
if (fout->remoteVersion >= 80300) if (fout->remoteVersion >= 80300)
{ {
appendPQExpBuffer(query, "SELECT oprkind, " appendPQExpBufferStr(query, "SELECT oprkind, "
"oprcode::pg_catalog.regprocedure, " "oprcode::pg_catalog.regprocedure, "
"oprleft::pg_catalog.regtype, " "oprleft::pg_catalog.regtype, "
"oprright::pg_catalog.regtype, " "oprright::pg_catalog.regtype, "
@ -12882,12 +12981,11 @@ dumpOpr(Archive *fout, const OprInfo *oprinfo)
"oprjoin::pg_catalog.regprocedure, " "oprjoin::pg_catalog.regprocedure, "
"oprcanmerge, oprcanhash " "oprcanmerge, oprcanhash "
"FROM pg_catalog.pg_operator " "FROM pg_catalog.pg_operator "
"WHERE oid = '%u'::pg_catalog.oid", "WHERE oid = $1");
oprinfo->dobj.catId.oid);
} }
else else
{ {
appendPQExpBuffer(query, "SELECT oprkind, " appendPQExpBufferStr(query, "SELECT oprkind, "
"oprcode::pg_catalog.regprocedure, " "oprcode::pg_catalog.regprocedure, "
"oprleft::pg_catalog.regtype, " "oprleft::pg_catalog.regtype, "
"oprright::pg_catalog.regtype, " "oprright::pg_catalog.regtype, "
@ -12898,10 +12996,18 @@ dumpOpr(Archive *fout, const OprInfo *oprinfo)
"(oprlsortop != 0) AS oprcanmerge, " "(oprlsortop != 0) AS oprcanmerge, "
"oprcanhash " "oprcanhash "
"FROM pg_catalog.pg_operator " "FROM pg_catalog.pg_operator "
"WHERE oid = '%u'::pg_catalog.oid", "WHERE oid = $1");
oprinfo->dobj.catId.oid);
} }
ExecuteSqlStatement(fout, query->data);
fout->is_prepared[PREPQUERY_DUMPOPR] = true;
}
printfPQExpBuffer(query,
"EXECUTE dumpOpr('%u')",
oprinfo->dobj.catId.oid);
res = ExecuteSqlQueryForSingleRow(fout, query->data); res = ExecuteSqlQueryForSingleRow(fout, query->data);
i_oprkind = PQfnumber(res, "oprkind"); i_oprkind = PQfnumber(res, "oprkind");
@ -14167,9 +14273,14 @@ dumpAgg(Archive *fout, const AggInfo *agginfo)
delq = createPQExpBuffer(); delq = createPQExpBuffer();
details = createPQExpBuffer(); details = createPQExpBuffer();
/* Get aggregate-specific details */ if (!fout->is_prepared[PREPQUERY_DUMPAGG])
{
/* Set up query for aggregate-specific details */
appendPQExpBufferStr(query, appendPQExpBufferStr(query,
"SELECT\n" "PREPARE dumpAgg(pg_catalog.oid) AS\n");
appendPQExpBufferStr(query,
"SELECT "
"aggtransfn,\n" "aggtransfn,\n"
"aggfinalfn,\n" "aggfinalfn,\n"
"aggtranstype::pg_catalog.regtype,\n" "aggtranstype::pg_catalog.regtype,\n"
@ -14234,10 +14345,18 @@ dumpAgg(Archive *fout, const AggInfo *agginfo)
"'0' AS aggfinalmodify,\n" "'0' AS aggfinalmodify,\n"
"'0' AS aggmfinalmodify\n"); "'0' AS aggmfinalmodify\n");
appendPQExpBuffer(query, appendPQExpBufferStr(query,
"FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p " "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
"WHERE a.aggfnoid = p.oid " "WHERE a.aggfnoid = p.oid "
"AND p.oid = '%u'::pg_catalog.oid", "AND p.oid = $1");
ExecuteSqlStatement(fout, query->data);
fout->is_prepared[PREPQUERY_DUMPAGG] = true;
}
printfPQExpBuffer(query,
"EXECUTE dumpAgg('%u')",
agginfo->aggfn.dobj.catId.oid); agginfo->aggfn.dobj.catId.oid);
res = ExecuteSqlQueryForSingleRow(fout, query->data); res = ExecuteSqlQueryForSingleRow(fout, query->data);
@ -15651,19 +15770,25 @@ dumpTable(Archive *fout, const TableInfo *tbinfo)
PGresult *res; PGresult *res;
int i; int i;
if (!fout->is_prepared[PREPQUERY_GETCOLUMNACLS])
{
/* Set up query for column ACLs */
appendPQExpBufferStr(query,
"PREPARE getColumnACLs(pg_catalog.oid) AS\n");
if (fout->remoteVersion >= 90600) if (fout->remoteVersion >= 90600)
{ {
/* /*
* In principle we should call acldefault('c', relowner) to get * In principle we should call acldefault('c', relowner) to
* the default ACL for a column. However, we don't currently * get the default ACL for a column. However, we don't
* store the numeric OID of the relowner in TableInfo. We could * currently store the numeric OID of the relowner in
* convert the owner name using regrole, but that creates a risk * TableInfo. We could convert the owner name using regrole,
* of failure due to concurrent role renames. Given that the * but that creates a risk of failure due to concurrent role
* default ACL for columns is empty and is likely to stay that * renames. Given that the default ACL for columns is empty
* way, it's not worth extra cycles and risk to avoid hard-wiring * and is likely to stay that way, it's not worth extra cycles
* that knowledge here. * and risk to avoid hard-wiring that knowledge here.
*/ */
appendPQExpBuffer(query, appendPQExpBufferStr(query,
"SELECT at.attname, " "SELECT at.attname, "
"at.attacl, " "at.attacl, "
"'{}' AS acldefault, " "'{}' AS acldefault, "
@ -15673,24 +15798,31 @@ dumpTable(Archive *fout, const TableInfo *tbinfo)
"(at.attrelid = pip.objoid " "(at.attrelid = pip.objoid "
"AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass " "AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass "
"AND at.attnum = pip.objsubid) " "AND at.attnum = pip.objsubid) "
"WHERE at.attrelid = '%u'::pg_catalog.oid AND " "WHERE at.attrelid = $1 AND "
"NOT at.attisdropped " "NOT at.attisdropped "
"AND (at.attacl IS NOT NULL OR pip.initprivs IS NOT NULL) " "AND (at.attacl IS NOT NULL OR pip.initprivs IS NOT NULL) "
"ORDER BY at.attnum", "ORDER BY at.attnum");
tbinfo->dobj.catId.oid);
} }
else else
{ {
appendPQExpBuffer(query, appendPQExpBufferStr(query,
"SELECT attname, attacl, '{}' AS acldefault, " "SELECT attname, attacl, '{}' AS acldefault, "
"NULL AS privtype, NULL AS initprivs " "NULL AS privtype, NULL AS initprivs "
"FROM pg_catalog.pg_attribute " "FROM pg_catalog.pg_attribute "
"WHERE attrelid = '%u'::pg_catalog.oid AND NOT attisdropped " "WHERE attrelid = $1 AND NOT attisdropped "
"AND attacl IS NOT NULL " "AND attacl IS NOT NULL "
"ORDER BY attnum", "ORDER BY attnum");
tbinfo->dobj.catId.oid);
} }
ExecuteSqlStatement(fout, query->data);
fout->is_prepared[PREPQUERY_GETCOLUMNACLS] = true;
}
printfPQExpBuffer(query,
"EXECUTE getColumnACLs('%u')",
tbinfo->dobj.catId.oid);
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
for (i = 0; i < PQntuples(res); i++) for (i = 0; i < PQntuples(res); i++)
@ -16639,12 +16771,26 @@ dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)
q = createPQExpBuffer(); q = createPQExpBuffer();
/* Fetch the partition's partbound */ if (!fout->is_prepared[PREPQUERY_DUMPTABLEATTACH])
appendPQExpBuffer(q, {
/* Set up query for partbound details */
appendPQExpBufferStr(q,
"PREPARE dumpTableAttach(pg_catalog.oid) AS\n");
appendPQExpBufferStr(q,
"SELECT pg_get_expr(c.relpartbound, c.oid) " "SELECT pg_get_expr(c.relpartbound, c.oid) "
"FROM pg_class c " "FROM pg_class c "
"WHERE c.oid = '%u'", "WHERE c.oid = $1");
ExecuteSqlStatement(fout, q->data);
fout->is_prepared[PREPQUERY_DUMPTABLEATTACH] = true;
}
printfPQExpBuffer(q,
"EXECUTE dumpTableAttach('%u')",
attachinfo->partitionTbl->dobj.catId.oid); attachinfo->partitionTbl->dobj.catId.oid);
res = ExecuteSqlQueryForSingleRow(fout, q->data); res = ExecuteSqlQueryForSingleRow(fout, q->data);
partbound = PQgetvalue(res, 0, 0); partbound = PQgetvalue(res, 0, 0);