Add ArchiveOpts to pass options to ArchiveEntry

The ArchiveEntry function has a number of arguments that can be
considered optional.  Split them out into a separate struct, to make the
API more flexible for changes.

Author: Dmitry Dolgov
Discussion: https://postgr.es/m/CA+q6zcXRxPE+qp6oerQWJ3zS061WPOhdxeMrdc-Yf-2V5vsrEw@mail.gmail.com
This commit is contained in:
Alvaro Herrera 2019-02-01 11:29:42 -03:00
parent 456e3718e7
commit f831d4accd
3 changed files with 520 additions and 575 deletions

View File

@ -77,7 +77,7 @@ static ArchiveHandle *_allocAH(const char *FileSpec, const ArchiveFormat fmt,
static void _getObjectDescription(PQExpBuffer buf, TocEntry *te,
ArchiveHandle *AH);
static void _printTocEntry(ArchiveHandle *AH, TocEntry *te, bool isData);
static char *replace_line_endings(const char *str);
static char *sanitize_line(const char *str, bool want_hyphen);
static void _doSetFixedOutputState(ArchiveHandle *AH);
static void _doSetSessionAuth(ArchiveHandle *AH, const char *user);
static void _reconnectToDB(ArchiveHandle *AH, const char *dbname);
@ -1066,17 +1066,8 @@ WriteData(Archive *AHX, const void *data, size_t dLen)
/* Public */
TocEntry *
ArchiveEntry(Archive *AHX,
CatalogId catalogId, DumpId dumpId,
const char *tag,
const char *namespace,
const char *tablespace,
const char *owner,
const char *desc, teSection section,
const char *defn,
const char *dropStmt, const char *copyStmt,
const DumpId *deps, int nDeps,
DataDumperPtr dumpFn, void *dumpArg)
ArchiveEntry(Archive *AHX, CatalogId catalogId, DumpId dumpId,
ArchiveOpts *opts)
{
ArchiveHandle *AH = (ArchiveHandle *) AHX;
TocEntry *newToc;
@ -1094,22 +1085,22 @@ ArchiveEntry(Archive *AHX,
newToc->catalogId = catalogId;
newToc->dumpId = dumpId;
newToc->section = section;
newToc->section = opts->section;
newToc->tag = pg_strdup(tag);
newToc->namespace = namespace ? pg_strdup(namespace) : NULL;
newToc->tablespace = tablespace ? pg_strdup(tablespace) : NULL;
newToc->owner = pg_strdup(owner);
newToc->desc = pg_strdup(desc);
newToc->defn = pg_strdup(defn);
newToc->dropStmt = pg_strdup(dropStmt);
newToc->copyStmt = copyStmt ? pg_strdup(copyStmt) : NULL;
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->owner = opts->owner ? pg_strdup(opts->owner) : NULL;
newToc->desc = pg_strdup(opts->description);
newToc->defn = opts->createStmt ? pg_strdup(opts->createStmt) : NULL;
newToc->dropStmt = opts->dropStmt ? pg_strdup(opts->dropStmt) : NULL;
newToc->copyStmt = opts->copyStmt ? pg_strdup(opts->copyStmt) : NULL;
if (nDeps > 0)
if (opts->nDeps > 0)
{
newToc->dependencies = (DumpId *) pg_malloc(nDeps * sizeof(DumpId));
memcpy(newToc->dependencies, deps, nDeps * sizeof(DumpId));
newToc->nDeps = nDeps;
newToc->dependencies = (DumpId *) pg_malloc(opts->nDeps * sizeof(DumpId));
memcpy(newToc->dependencies, opts->deps, opts->nDeps * sizeof(DumpId));
newToc->nDeps = opts->nDeps;
}
else
{
@ -1117,9 +1108,9 @@ ArchiveEntry(Archive *AHX,
newToc->nDeps = 0;
}
newToc->dataDumper = dumpFn;
newToc->dataDumperArg = dumpArg;
newToc->hadDumper = dumpFn ? true : false;
newToc->dataDumper = opts->dumpFn;
newToc->dataDumperArg = opts->dumpArg;
newToc->hadDumper = opts->dumpFn ? true : false;
newToc->formatData = NULL;
newToc->dataLength = 0;
@ -1152,7 +1143,7 @@ PrintTOCSummary(Archive *AHX)
ahprintf(AH, ";\n; Archive created at %s\n", stamp_str);
ahprintf(AH, "; dbname: %s\n; TOC Entries: %d\n; Compression: %d\n",
replace_line_endings(AH->archdbname),
sanitize_line(AH->archdbname, false),
AH->tocCount, AH->compression);
switch (AH->format)
@ -1197,21 +1188,10 @@ PrintTOCSummary(Archive *AHX)
char *sanitized_owner;
/*
* As in _printTocEntry(), sanitize strings that might contain
* newlines, to ensure that each logical output line is in fact
* one physical output line. This prevents confusion when the
* file is read by "pg_restore -L". Note that we currently don't
* bother to quote names, meaning that the name fields aren't
* automatically parseable. "pg_restore -L" doesn't care because
* it only examines the dumpId field, but someday we might want to
* try harder.
*/
sanitized_name = replace_line_endings(te->tag);
if (te->namespace)
sanitized_schema = replace_line_endings(te->namespace);
else
sanitized_schema = pg_strdup("-");
sanitized_owner = replace_line_endings(te->owner);
sanitized_name = sanitize_line(te->tag, false);
sanitized_schema = sanitize_line(te->namespace, true);
sanitized_owner = sanitize_line(te->owner, false);
ahprintf(AH, "%d; %u %u %s %s %s %s\n", te->dumpId,
te->catalogId.tableoid, te->catalogId.oid,
@ -3577,21 +3557,9 @@ _printTocEntry(ArchiveHandle *AH, TocEntry *te, bool isData)
}
}
/*
* Zap any line endings embedded in user-supplied fields, to prevent
* corruption of the dump (which could, in the worst case, present an
* SQL injection vulnerability if someone were to incautiously load a
* dump containing objects with maliciously crafted names).
*/
sanitized_name = replace_line_endings(te->tag);
if (te->namespace)
sanitized_schema = replace_line_endings(te->namespace);
else
sanitized_schema = pg_strdup("-");
if (!ropt->noOwner)
sanitized_owner = replace_line_endings(te->owner);
else
sanitized_owner = pg_strdup("-");
sanitized_name = sanitize_line(te->tag, false);
sanitized_schema = sanitize_line(te->namespace, true);
sanitized_owner = sanitize_line(ropt->noOwner ? NULL : te->owner, true);
ahprintf(AH, "-- %sName: %s; Type: %s; Schema: %s; Owner: %s",
pfx, sanitized_name, te->desc, sanitized_schema,
@ -3605,7 +3573,7 @@ _printTocEntry(ArchiveHandle *AH, TocEntry *te, bool isData)
{
char *sanitized_tablespace;
sanitized_tablespace = replace_line_endings(te->tablespace);
sanitized_tablespace = sanitize_line(te->tablespace, false);
ahprintf(AH, "; Tablespace: %s", sanitized_tablespace);
free(sanitized_tablespace);
}
@ -3629,7 +3597,7 @@ _printTocEntry(ArchiveHandle *AH, TocEntry *te, bool isData)
}
else
{
if (strlen(te->defn) > 0)
if (te->defn && strlen(te->defn) > 0)
ahprintf(AH, "%s\n\n", te->defn);
}
@ -3640,7 +3608,8 @@ _printTocEntry(ArchiveHandle *AH, TocEntry *te, bool isData)
* with DROP commands must appear in one list or the other.
*/
if (!ropt->noOwner && !ropt->use_setsessauth &&
strlen(te->owner) > 0 && strlen(te->dropStmt) > 0)
te->owner && strlen(te->owner) > 0 &&
te->dropStmt && strlen(te->dropStmt) > 0)
{
if (strcmp(te->desc, "AGGREGATE") == 0 ||
strcmp(te->desc, "BLOB") == 0 ||
@ -3713,16 +3682,30 @@ _printTocEntry(ArchiveHandle *AH, TocEntry *te, bool isData)
}
/*
* Sanitize a string to be included in an SQL comment or TOC listing,
* by replacing any newlines with spaces.
* The result is a freshly malloc'd string.
* Sanitize a string to be included in an SQL comment or TOC listing, by
* replacing any newlines with spaces. This ensures each logical output line
* is in fact one physical output line, to prevent corruption of the dump
* (which could, in the worst case, present an SQL injection vulnerability
* if someone were to incautiously load a dump containing objects with
* maliciously crafted names).
*
* The result is a freshly malloc'd string. If the input string is NULL,
* return a malloc'ed empty string, unless want_hyphen, in which case return a
* malloc'ed hyphen.
*
* Note that we currently don't bother to quote names, meaning that the name
* fields aren't automatically parseable. "pg_restore -L" doesn't care because
* it only examines the dumpId field, but someday we might want to try harder.
*/
static char *
replace_line_endings(const char *str)
sanitize_line(const char *str, bool want_hyphen)
{
char *result;
char *s;
if (!str)
return pg_strdup(want_hyphen ? "-" : "");
result = pg_strdup(str);
for (s = result; *s != '\0'; s++)

View File

@ -405,17 +405,27 @@ extern void on_exit_close_archive(Archive *AHX);
extern void warn_or_exit_horribly(ArchiveHandle *AH, const char *modulename, const char *fmt,...) pg_attribute_printf(3, 4);
/* Options for ArchiveEntry */
typedef struct _archiveOpts
{
const char *tag;
const char *namespace;
const char *tablespace;
const char *owner;
const char *description;
teSection section;
const char *createStmt;
const char *dropStmt;
const char *copyStmt;
const DumpId *deps;
int nDeps;
DataDumperPtr dumpFn;
void *dumpArg;
} ArchiveOpts;
#define ARCHIVE_OPTS(...) &(ArchiveOpts){__VA_ARGS__}
/* Called to add a TOC entry */
extern TocEntry *ArchiveEntry(Archive *AHX,
CatalogId catalogId, DumpId dumpId,
const char *tag,
const char *namespace, const char *tablespace,
const char *owner,
const char *desc, teSection section,
const char *defn,
const char *dropStmt, const char *copyStmt,
const DumpId *deps, int nDeps,
DataDumperPtr dumpFn, void *dumpArg);
extern TocEntry *ArchiveEntry(Archive *AHX, CatalogId catalogId,
DumpId dumpId, ArchiveOpts *opts);
extern void WriteTOC(ArchiveHandle *AH);
extern void ReadTOC(ArchiveHandle *AH);

File diff suppressed because it is too large Load Diff