#include "pg_backup_db.h"
#include "pg_backup_utils.h"
#include "parallel.h"
#include <ctype.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "libpq/libpq-fs.h"
Go to the source code of this file.
#define TEXT_DUMP_HEADER "--\n-- PostgreSQL database dump\n--\n\n" |
Definition at line 40 of file pg_backup_archiver.c.
Referenced by _discoverArchiveFormat().
#define TEXT_DUMPALL_HEADER "--\n-- PostgreSQL database cluster dump\n--\n\n" |
Definition at line 41 of file pg_backup_archiver.c.
Referenced by _discoverArchiveFormat().
typedef struct _outputContext OutputContext |
static ArchiveHandle * _allocAH | ( | const char * | FileSpec, | |
const ArchiveFormat | fmt, | |||
const int | compression, | |||
ArchiveMode | mode, | |||
SetupWorkerPtr | setupWorkerPtr | |||
) | [static] |
Definition at line 1979 of file pg_backup_archiver.c.
References _discoverArchiveFormat(), archCustom, archDirectory, _archiveHandle::archiveDumpVersion, archModeWrite, archNull, archTar, archUnknown, _archiveHandle::compression, _archiveHandle::createDate, _archiveHandle::currSchema, _archiveHandle::currTablespace, _archiveHandle::currUser, _archiveHandle::currWithOids, Archive::encoding, exit_horribly(), Archive::exit_on_error, _archiveHandle::format, _archiveHandle::fSpec, _archiveHandle::gzOut, InitArchiveFmt_Custom(), InitArchiveFmt_Directory(), InitArchiveFmt_Null(), InitArchiveFmt_Tar(), _archiveHandle::intSize, _archiveHandle::mode, modulename, Archive::n_errors, _tocEntry::next, NULL, _archiveHandle::OF, _archiveHandle::offSize, pg_malloc0(), pg_strdup(), _tocEntry::prev, _archiveHandle::promptPassword, _archiveHandle::public, _archiveHandle::SetupWorkerPtr, _archiveHandle::sqlparse, Archive::std_strings, _archiveHandle::toc, _archiveHandle::version, _archiveHandle::vmaj, _archiveHandle::vmin, _archiveHandle::vrev, and write_msg().
Referenced by CreateArchive(), and OpenArchive().
{ ArchiveHandle *AH; #if 0 write_msg(modulename, "allocating AH for %s, format %d\n", FileSpec, fmt); #endif AH = (ArchiveHandle *) pg_malloc0(sizeof(ArchiveHandle)); /* AH->debugLevel = 100; */ AH->vmaj = K_VERS_MAJOR; AH->vmin = K_VERS_MINOR; AH->vrev = K_VERS_REV; /* Make a convenient integer <maj><min><rev>00 */ AH->version = ((AH->vmaj * 256 + AH->vmin) * 256 + AH->vrev) * 256 + 0; /* initialize for backwards compatible string processing */ AH->public.encoding = 0; /* PG_SQL_ASCII */ AH->public.std_strings = false; /* sql error handling */ AH->public.exit_on_error = true; AH->public.n_errors = 0; AH->archiveDumpVersion = PG_VERSION; AH->createDate = time(NULL); AH->intSize = sizeof(int); AH->offSize = sizeof(pgoff_t); if (FileSpec) { AH->fSpec = pg_strdup(FileSpec); /* * Not used; maybe later.... * * AH->workDir = pg_strdup(FileSpec); for(i=strlen(FileSpec) ; i > 0 ; * i--) if (AH->workDir[i-1] == '/') */ } else AH->fSpec = NULL; AH->currUser = NULL; /* unknown */ AH->currSchema = NULL; /* ditto */ AH->currTablespace = NULL; /* ditto */ AH->currWithOids = -1; /* force SET */ AH->toc = (TocEntry *) pg_malloc0(sizeof(TocEntry)); AH->toc->next = AH->toc; AH->toc->prev = AH->toc; AH->mode = mode; AH->compression = compression; memset(&(AH->sqlparse), 0, sizeof(AH->sqlparse)); /* Open stdout with no compression for AH output handle */ AH->gzOut = 0; AH->OF = stdout; /* * On Windows, we need to use binary mode to read/write non-text archive * formats. Force stdin/stdout into binary mode if that is what we are * using. */ #ifdef WIN32 if (fmt != archNull && (AH->fSpec == NULL || strcmp(AH->fSpec, "") == 0)) { if (mode == archModeWrite) setmode(fileno(stdout), O_BINARY); else setmode(fileno(stdin), O_BINARY); } #endif AH->SetupWorkerPtr = setupWorkerPtr; if (fmt == archUnknown) AH->format = _discoverArchiveFormat(AH); else AH->format = fmt; AH->promptPassword = TRI_DEFAULT; switch (AH->format) { case archCustom: InitArchiveFmt_Custom(AH); break; case archNull: InitArchiveFmt_Null(AH); break; case archDirectory: InitArchiveFmt_Directory(AH); break; case archTar: InitArchiveFmt_Tar(AH); break; default: exit_horribly(modulename, "unrecognized file format \"%d\"\n", fmt); } return AH; }
static void _becomeOwner | ( | ArchiveHandle * | AH, | |
TocEntry * | te | |||
) | [static] |
Definition at line 2749 of file pg_backup_archiver.c.
References _becomeUser(), _restoreOptions::noOwner, _tocEntry::owner, _archiveHandle::ropt, and _restoreOptions::use_setsessauth.
Referenced by _printTocEntry(), restore_toc_entry(), and RestoreArchive().
{ if (AH->ropt && (AH->ropt->noOwner || !AH->ropt->use_setsessauth)) return; _becomeUser(AH, te->owner); }
static void _becomeUser | ( | ArchiveHandle * | AH, | |
const char * | user | |||
) | [static] |
Definition at line 2725 of file pg_backup_archiver.c.
References _doSetSessionAuth(), _archiveHandle::currUser, free, and pg_strdup().
Referenced by _becomeOwner(), _disableTriggersIfNecessary(), and _enableTriggersIfNecessary().
{ if (!user) user = ""; /* avoid null pointers */ if (AH->currUser && strcmp(AH->currUser, user) == 0) return; /* no need to do anything */ _doSetSessionAuth(AH, user); /* * NOTE: currUser keeps track of what the imaginary session user in our * script is */ if (AH->currUser) free(AH->currUser); AH->currUser = pg_strdup(user); }
static void _disableTriggersIfNecessary | ( | ArchiveHandle * | AH, | |
TocEntry * | te, | |||
RestoreOptions * | ropt | |||
) | [static] |
Definition at line 729 of file pg_backup_archiver.c.
References _becomeUser(), _selectOutputSchema(), ahlog(), ahprintf(), _restoreOptions::dataOnly, _restoreOptions::disable_triggers, fmtId(), _restoreOptions::superuser, and _tocEntry::tag.
Referenced by restore_toc_entry().
{ /* This hack is only needed in a data-only restore */ if (!ropt->dataOnly || !ropt->disable_triggers) return; ahlog(AH, 1, "disabling triggers for %s\n", te->tag); /* * Become superuser if possible, since they are the only ones who can * disable constraint triggers. If -S was not given, assume the initial * user identity is a superuser. (XXX would it be better to become the * table owner?) */ _becomeUser(AH, ropt->superuser); /* * Disable them. */ _selectOutputSchema(AH, te->namespace); ahprintf(AH, "ALTER TABLE %s DISABLE TRIGGER ALL;\n\n", fmtId(te->tag)); }
static int _discoverArchiveFormat | ( | ArchiveHandle * | AH | ) | [static] |
Definition at line 1797 of file pg_backup_archiver.c.
References buf, exit_horribly(), _archiveHandle::format, free, fseeko, _archiveHandle::fSpec, _archiveHandle::intSize, isValidTarHeader(), K_VERS_1_7, _archiveHandle::lookahead, _archiveHandle::lookaheadLen, _archiveHandle::lookaheadPos, _archiveHandle::lookaheadSize, MAXPGPATH, modulename, _archiveHandle::offSize, PG_BINARY_R, pg_malloc0(), _archiveHandle::readHeader, sig, snprintf(), strerror(), TEXT_DUMP_HEADER, TEXT_DUMPALL_HEADER, _archiveHandle::version, _archiveHandle::vmaj, _archiveHandle::vmin, _archiveHandle::vrev, and write_msg().
Referenced by _allocAH().
{ FILE *fh; char sig[6]; /* More than enough */ size_t cnt; int wantClose = 0; #if 0 write_msg(modulename, "attempting to ascertain archive format\n"); #endif if (AH->lookahead) free(AH->lookahead); AH->lookaheadSize = 512; AH->lookahead = pg_malloc0(512); AH->lookaheadLen = 0; AH->lookaheadPos = 0; if (AH->fSpec) { struct stat st; wantClose = 1; /* * Check if the specified archive is a directory. If so, check if * there's a "toc.dat" (or "toc.dat.gz") file in it. */ if (stat(AH->fSpec, &st) == 0 && S_ISDIR(st.st_mode)) { char buf[MAXPGPATH]; if (snprintf(buf, MAXPGPATH, "%s/toc.dat", AH->fSpec) >= MAXPGPATH) exit_horribly(modulename, "directory name too long: \"%s\"\n", AH->fSpec); if (stat(buf, &st) == 0 && S_ISREG(st.st_mode)) { AH->format = archDirectory; return AH->format; } #ifdef HAVE_LIBZ if (snprintf(buf, MAXPGPATH, "%s/toc.dat.gz", AH->fSpec) >= MAXPGPATH) exit_horribly(modulename, "directory name too long: \"%s\"\n", AH->fSpec); if (stat(buf, &st) == 0 && S_ISREG(st.st_mode)) { AH->format = archDirectory; return AH->format; } #endif exit_horribly(modulename, "directory \"%s\" does not appear to be a valid archive (\"toc.dat\" does not exist)\n", AH->fSpec); fh = NULL; /* keep compiler quiet */ } else { fh = fopen(AH->fSpec, PG_BINARY_R); if (!fh) exit_horribly(modulename, "could not open input file \"%s\": %s\n", AH->fSpec, strerror(errno)); } } else { fh = stdin; if (!fh) exit_horribly(modulename, "could not open input file: %s\n", strerror(errno)); } cnt = fread(sig, 1, 5, fh); if (cnt != 5) { if (ferror(fh)) exit_horribly(modulename, "could not read input file: %s\n", strerror(errno)); else exit_horribly(modulename, "input file is too short (read %lu, expected 5)\n", (unsigned long) cnt); } /* Save it, just in case we need it later */ strncpy(&AH->lookahead[0], sig, 5); AH->lookaheadLen = 5; if (strncmp(sig, "PGDMP", 5) == 0) { /* * Finish reading (most of) a custom-format header. * * NB: this code must agree with ReadHead(). */ AH->vmaj = fgetc(fh); AH->vmin = fgetc(fh); /* Save these too... */ AH->lookahead[AH->lookaheadLen++] = AH->vmaj; AH->lookahead[AH->lookaheadLen++] = AH->vmin; /* Check header version; varies from V1.0 */ if (AH->vmaj > 1 || ((AH->vmaj == 1) && (AH->vmin > 0))) /* Version > 1.0 */ { AH->vrev = fgetc(fh); AH->lookahead[AH->lookaheadLen++] = AH->vrev; } else AH->vrev = 0; /* Make a convenient integer <maj><min><rev>00 */ AH->version = ((AH->vmaj * 256 + AH->vmin) * 256 + AH->vrev) * 256 + 0; AH->intSize = fgetc(fh); AH->lookahead[AH->lookaheadLen++] = AH->intSize; if (AH->version >= K_VERS_1_7) { AH->offSize = fgetc(fh); AH->lookahead[AH->lookaheadLen++] = AH->offSize; } else AH->offSize = AH->intSize; AH->format = fgetc(fh); AH->lookahead[AH->lookaheadLen++] = AH->format; } else { /* * *Maybe* we have a tar archive format file or a text dump ... So, * read first 512 byte header... */ cnt = fread(&AH->lookahead[AH->lookaheadLen], 1, 512 - AH->lookaheadLen, fh); AH->lookaheadLen += cnt; if (AH->lookaheadLen >= strlen(TEXT_DUMPALL_HEADER) && (strncmp(AH->lookahead, TEXT_DUMP_HEADER, strlen(TEXT_DUMP_HEADER)) == 0 || strncmp(AH->lookahead, TEXT_DUMPALL_HEADER, strlen(TEXT_DUMPALL_HEADER)) == 0)) { /* * looks like it's probably a text format dump. so suggest they * try psql */ exit_horribly(modulename, "input file appears to be a text format dump. Please use psql.\n"); } if (AH->lookaheadLen != 512) exit_horribly(modulename, "input file does not appear to be a valid archive (too short?)\n"); if (!isValidTarHeader(AH->lookahead)) exit_horribly(modulename, "input file does not appear to be a valid archive\n"); AH->format = archTar; } /* If we can't seek, then mark the header as read */ if (fseeko(fh, 0, SEEK_SET) != 0) { /* * NOTE: Formats that use the lookahead buffer can unset this in their * Init routine. */ AH->readHeader = 1; } else AH->lookaheadLen = 0; /* Don't bother since we've reset the file */ /* Close the file */ if (wantClose) if (fclose(fh) != 0) exit_horribly(modulename, "could not close input file: %s\n", strerror(errno)); return AH->format; }
static void _doSetFixedOutputState | ( | ArchiveHandle * | AH | ) | [static] |
Definition at line 2570 of file pg_backup_archiver.c.
References ahprintf(), Archive::encoding, fmtId(), pg_encoding_to_char(), _archiveHandle::public, _archiveHandle::ropt, Archive::std_strings, and _restoreOptions::use_role.
Referenced by _reconnectToDB(), parallel_restore(), restore_toc_entries_postfork(), and RestoreArchive().
{ /* Disable statement_timeout since restore is probably slow */ ahprintf(AH, "SET statement_timeout = 0;\n"); /* Likewise for lock_timeout */ ahprintf(AH, "SET lock_timeout = 0;\n"); /* Select the correct character set encoding */ ahprintf(AH, "SET client_encoding = '%s';\n", pg_encoding_to_char(AH->public.encoding)); /* Select the correct string literal syntax */ ahprintf(AH, "SET standard_conforming_strings = %s;\n", AH->public.std_strings ? "on" : "off"); /* Select the role to be used during restore */ if (AH->ropt && AH->ropt->use_role) ahprintf(AH, "SET ROLE %s;\n", fmtId(AH->ropt->use_role)); /* Make sure function checking is disabled */ ahprintf(AH, "SET check_function_bodies = false;\n"); /* Avoid annoying notices etc */ ahprintf(AH, "SET client_min_messages = warning;\n"); if (!AH->public.std_strings) ahprintf(AH, "SET escape_string_warning = off;\n"); ahprintf(AH, "\n"); }
static void _doSetSessionAuth | ( | ArchiveHandle * | AH, | |
const char * | user | |||
) | [static] |
Definition at line 2607 of file pg_backup_archiver.c.
References ahprintf(), appendPQExpBuffer(), appendStringLiteralAHX, _archiveHandle::connection, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), exit_horribly(), modulename, PGRES_COMMAND_OK, PQclear(), PQerrorMessage(), PQexec(), PQresultStatus(), and RestoringToDB().
Referenced by _becomeUser().
{ PQExpBuffer cmd = createPQExpBuffer(); appendPQExpBuffer(cmd, "SET SESSION AUTHORIZATION "); /* * SQL requires a string literal here. Might as well be correct. */ if (user && *user) appendStringLiteralAHX(cmd, user, AH); else appendPQExpBuffer(cmd, "DEFAULT"); appendPQExpBuffer(cmd, ";"); if (RestoringToDB(AH)) { PGresult *res; res = PQexec(AH->connection, cmd->data); if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) /* NOT warn_or_exit_horribly... use -O instead to skip this. */ exit_horribly(modulename, "could not set session user to \"%s\": %s", user, PQerrorMessage(AH->connection)); PQclear(res); } else ahprintf(AH, "%s\n\n", cmd->data); destroyPQExpBuffer(cmd); }
static void _doSetWithOids | ( | ArchiveHandle * | AH, | |
const bool | withOids | |||
) | [static] |
Definition at line 2647 of file pg_backup_archiver.c.
References ahprintf(), appendPQExpBuffer(), _archiveHandle::connection, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), modulename, PGRES_COMMAND_OK, PQclear(), PQerrorMessage(), PQexec(), PQresultStatus(), RestoringToDB(), and warn_or_exit_horribly().
Referenced by _setWithOids().
{ PQExpBuffer cmd = createPQExpBuffer(); appendPQExpBuffer(cmd, "SET default_with_oids = %s;", withOids ? "true" : "false"); 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_with_oids: %s", PQerrorMessage(AH->connection)); PQclear(res); } else ahprintf(AH, "%s\n\n", cmd->data); destroyPQExpBuffer(cmd); }
static void _enableTriggersIfNecessary | ( | ArchiveHandle * | AH, | |
TocEntry * | te, | |||
RestoreOptions * | ropt | |||
) | [static] |
Definition at line 755 of file pg_backup_archiver.c.
References _becomeUser(), _selectOutputSchema(), ahlog(), ahprintf(), _restoreOptions::dataOnly, _restoreOptions::disable_triggers, fmtId(), _restoreOptions::superuser, and _tocEntry::tag.
Referenced by restore_toc_entry().
{ /* This hack is only needed in a data-only restore */ if (!ropt->dataOnly || !ropt->disable_triggers) return; ahlog(AH, 1, "enabling triggers for %s\n", te->tag); /* * Become superuser if possible, since they are the only ones who can * disable constraint triggers. If -S was not given, assume the initial * user identity is a superuser. (XXX would it be better to become the * table owner?) */ _becomeUser(AH, ropt->superuser); /* * Enable them. */ _selectOutputSchema(AH, te->namespace); ahprintf(AH, "ALTER TABLE %s ENABLE TRIGGER ALL;\n\n", fmtId(te->tag)); }
static void _getObjectDescription | ( | PQExpBuffer | buf, | |
TocEntry * | te, | |||
ArchiveHandle * | AH | |||
) | [static] |
Definition at line 2886 of file pg_backup_archiver.c.
References appendPQExpBuffer(), appendPQExpBufferStr(), _tocEntry::desc, _tocEntry::dropStmt, fmtId(), free, K_VERS_1_7, modulename, pg_strdup(), _tocEntry::tag, _archiveHandle::version, and write_msg().
Referenced by _printTocEntry().
{ const char *type = te->desc; /* Use ALTER TABLE for views and sequences */ if (strcmp(type, "VIEW") == 0 || strcmp(type, "SEQUENCE") == 0 || strcmp(type, "MATERIALIZED VIEW") == 0) type = "TABLE"; /* objects named by a schema and name */ if (strcmp(type, "COLLATION") == 0 || strcmp(type, "CONVERSION") == 0 || strcmp(type, "DOMAIN") == 0 || strcmp(type, "TABLE") == 0 || strcmp(type, "TYPE") == 0 || strcmp(type, "FOREIGN TABLE") == 0 || strcmp(type, "TEXT SEARCH DICTIONARY") == 0 || strcmp(type, "TEXT SEARCH CONFIGURATION") == 0) { appendPQExpBuffer(buf, "%s ", type); if (te->namespace && te->namespace[0]) /* is null pre-7.3 */ appendPQExpBuffer(buf, "%s.", fmtId(te->namespace)); /* * Pre-7.3 pg_dump would sometimes (not always) put a fmtId'd name * into te->tag for an index. This check is heuristic, so make its * scope as narrow as possible. */ if (AH->version < K_VERS_1_7 && te->tag[0] == '"' && te->tag[strlen(te->tag) - 1] == '"' && strcmp(type, "INDEX") == 0) appendPQExpBuffer(buf, "%s", te->tag); else appendPQExpBuffer(buf, "%s", fmtId(te->tag)); return; } /* objects named by just a name */ if (strcmp(type, "DATABASE") == 0 || strcmp(type, "PROCEDURAL LANGUAGE") == 0 || strcmp(type, "SCHEMA") == 0 || strcmp(type, "FOREIGN DATA WRAPPER") == 0 || strcmp(type, "SERVER") == 0 || strcmp(type, "USER MAPPING") == 0) { appendPQExpBuffer(buf, "%s %s", type, fmtId(te->tag)); return; } /* BLOBs just have a name, but it's numeric so must not use fmtId */ if (strcmp(type, "BLOB") == 0) { appendPQExpBuffer(buf, "LARGE OBJECT %s", te->tag); return; } /* * These object types require additional decoration. Fortunately, the * information needed is exactly what's in the DROP command. */ if (strcmp(type, "AGGREGATE") == 0 || strcmp(type, "FUNCTION") == 0 || strcmp(type, "OPERATOR") == 0 || strcmp(type, "OPERATOR CLASS") == 0 || strcmp(type, "OPERATOR FAMILY") == 0) { /* Chop "DROP " off the front and make a modifiable copy */ char *first = pg_strdup(te->dropStmt + 5); char *last; /* point to last character in string */ last = first + strlen(first) - 1; /* Strip off any ';' or '\n' at the end */ while (last >= first && (*last == '\n' || *last == ';')) last--; *(last + 1) = '\0'; appendPQExpBufferStr(buf, first); free(first); return; } write_msg(modulename, "WARNING: don't know how to set owner for object type %s\n", type); }
static void _moveBefore | ( | ArchiveHandle * | AH, | |
TocEntry * | pos, | |||
TocEntry * | te | |||
) | [static] |
Definition at line 1531 of file pg_backup_archiver.c.
References _tocEntry::next, and _tocEntry::prev.
Referenced by SortTocFromFile().
static void _printTocEntry | ( | ArchiveHandle * | AH, | |
TocEntry * | te, | |||
RestoreOptions * | ropt, | |||
bool | isData, | |||
bool | acl_pass | |||
) | [static] |
Definition at line 2976 of file pg_backup_archiver.c.
References _becomeOwner(), _getObjectDescription(), _selectOutputSchema(), _selectTablespace(), _setWithOids(), _tocEntryIsACL(), ahprintf(), appendPQExpBuffer(), _tocEntry::catalogId, createPQExpBuffer(), _archiveHandle::currUser, PQExpBufferData::data, _tocEntry::defn, _tocEntry::dependencies, _tocEntry::desc, destroyPQExpBuffer(), _restoreOptions::dropSchema, _tocEntry::dropStmt, _tocEntry::dumpId, fmtId(), free, i, modulename, _tocEntry::nDeps, _restoreOptions::noOwner, _restoreOptions::noTablespace, _archiveHandle::noTocComments, NULL, CatalogId::oid, _tocEntry::owner, pg_strdup(), _archiveHandle::PrintExtraTocPtr, _archiveHandle::public, replace_line_endings(), CatalogId::tableoid, _tocEntry::tablespace, _tocEntry::tag, _restoreOptions::use_setsessauth, Archive::verbose, and write_msg().
Referenced by restore_toc_entry(), and RestoreArchive().
{ /* ACLs are dumped only during acl pass */ if (acl_pass) { if (!_tocEntryIsACL(te)) return; } else { if (_tocEntryIsACL(te)) return; } /* * Avoid dumping the public schema, as it will already be created ... * unless we are using --clean mode, in which case it's been deleted and * we'd better recreate it. Likewise for its comment, if any. */ if (!ropt->dropSchema) { if (strcmp(te->desc, "SCHEMA") == 0 && strcmp(te->tag, "public") == 0) return; /* The comment restore would require super-user privs, so avoid it. */ if (strcmp(te->desc, "COMMENT") == 0 && strcmp(te->tag, "SCHEMA public") == 0) return; } /* Select owner, schema, and tablespace as necessary */ _becomeOwner(AH, te); _selectOutputSchema(AH, te->namespace); _selectTablespace(AH, te->tablespace); /* Set up OID mode too */ if (strcmp(te->desc, "TABLE") == 0) _setWithOids(AH, te); /* Emit header comment for item */ if (!AH->noTocComments) { const char *pfx; char *sanitized_name; char *sanitized_schema; char *sanitized_owner; if (isData) pfx = "Data for "; else pfx = ""; ahprintf(AH, "--\n"); if (AH->public.verbose) { ahprintf(AH, "-- TOC entry %d (class %u OID %u)\n", te->dumpId, te->catalogId.tableoid, te->catalogId.oid); if (te->nDeps > 0) { int i; ahprintf(AH, "-- Dependencies:"); for (i = 0; i < te->nDeps; i++) ahprintf(AH, " %d", te->dependencies[i]); ahprintf(AH, "\n"); } } /* * 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("-"); ahprintf(AH, "-- %sName: %s; Type: %s; Schema: %s; Owner: %s", pfx, sanitized_name, te->desc, sanitized_schema, sanitized_owner); free(sanitized_name); free(sanitized_schema); free(sanitized_owner); if (te->tablespace && !ropt->noTablespace) { char *sanitized_tablespace; sanitized_tablespace = replace_line_endings(te->tablespace); ahprintf(AH, "; Tablespace: %s", sanitized_tablespace); free(sanitized_tablespace); } ahprintf(AH, "\n"); if (AH->PrintExtraTocPtr !=NULL) (*AH->PrintExtraTocPtr) (AH, te); ahprintf(AH, "--\n\n"); } /* * Actually print the definition. * * Really crude hack for suppressing AUTHORIZATION clause that old pg_dump * versions put into CREATE SCHEMA. We have to do this when --no-owner * mode is selected. This is ugly, but I see no other good way ... */ if (ropt->noOwner && strcmp(te->desc, "SCHEMA") == 0) { ahprintf(AH, "CREATE SCHEMA %s;\n\n\n", fmtId(te->tag)); } else { if (strlen(te->defn) > 0) ahprintf(AH, "%s\n\n", te->defn); } /* * If we aren't using SET SESSION AUTH to determine ownership, we must * instead issue an ALTER OWNER command. We assume that anything without * a DROP command is not a separately ownable object. All the categories * 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) { if (strcmp(te->desc, "AGGREGATE") == 0 || strcmp(te->desc, "BLOB") == 0 || strcmp(te->desc, "COLLATION") == 0 || strcmp(te->desc, "CONVERSION") == 0 || strcmp(te->desc, "DATABASE") == 0 || strcmp(te->desc, "DOMAIN") == 0 || strcmp(te->desc, "FUNCTION") == 0 || strcmp(te->desc, "OPERATOR") == 0 || strcmp(te->desc, "OPERATOR CLASS") == 0 || strcmp(te->desc, "OPERATOR FAMILY") == 0 || strcmp(te->desc, "PROCEDURAL LANGUAGE") == 0 || strcmp(te->desc, "SCHEMA") == 0 || strcmp(te->desc, "TABLE") == 0 || strcmp(te->desc, "TYPE") == 0 || strcmp(te->desc, "VIEW") == 0 || strcmp(te->desc, "MATERIALIZED VIEW") == 0 || strcmp(te->desc, "SEQUENCE") == 0 || strcmp(te->desc, "FOREIGN TABLE") == 0 || strcmp(te->desc, "TEXT SEARCH DICTIONARY") == 0 || strcmp(te->desc, "TEXT SEARCH CONFIGURATION") == 0 || strcmp(te->desc, "FOREIGN DATA WRAPPER") == 0 || strcmp(te->desc, "SERVER") == 0) { PQExpBuffer temp = createPQExpBuffer(); appendPQExpBuffer(temp, "ALTER "); _getObjectDescription(temp, te, AH); appendPQExpBuffer(temp, " OWNER TO %s;", fmtId(te->owner)); ahprintf(AH, "%s\n\n", temp->data); destroyPQExpBuffer(temp); } else if (strcmp(te->desc, "CAST") == 0 || strcmp(te->desc, "CHECK CONSTRAINT") == 0 || strcmp(te->desc, "CONSTRAINT") == 0 || strcmp(te->desc, "DEFAULT") == 0 || strcmp(te->desc, "FK CONSTRAINT") == 0 || strcmp(te->desc, "INDEX") == 0 || strcmp(te->desc, "RULE") == 0 || strcmp(te->desc, "TRIGGER") == 0 || strcmp(te->desc, "USER MAPPING") == 0) { /* these object types don't have separate owners */ } else { write_msg(modulename, "WARNING: don't know how to set owner for object type %s\n", te->desc); } } /* * If it's an ACL entry, it might contain SET SESSION AUTHORIZATION * commands, so we can no longer assume we know the current auth setting. */ if (acl_pass) { if (AH->currUser) free(AH->currUser); AH->currUser = NULL; } }
static void _reconnectToDB | ( | ArchiveHandle * | AH, | |
const char * | dbname | |||
) | [static] |
Definition at line 2684 of file pg_backup_archiver.c.
References _doSetFixedOutputState(), ahprintf(), appendPQExpBuffer(), createPQExpBuffer(), _archiveHandle::currSchema, _archiveHandle::currTablespace, _archiveHandle::currUser, _archiveHandle::currWithOids, PQExpBufferData::data, destroyPQExpBuffer(), fmtId(), free, NULL, ReconnectToServer(), and RestoringToDB().
Referenced by restore_toc_entry().
{ if (RestoringToDB(AH)) ReconnectToServer(AH, dbname, NULL); else { PQExpBuffer qry = createPQExpBuffer(); appendPQExpBuffer(qry, "\\connect %s\n\n", dbname ? fmtId(dbname) : "-"); ahprintf(AH, "%s", qry->data); destroyPQExpBuffer(qry); } /* * NOTE: currUser keeps track of what the imaginary session user in our * script is. It's now effectively reset to the original userID. */ if (AH->currUser) free(AH->currUser); AH->currUser = NULL; /* don't assume we still know the output schema, tablespace, etc either */ if (AH->currSchema) free(AH->currSchema); AH->currSchema = NULL; if (AH->currTablespace) free(AH->currTablespace); AH->currTablespace = NULL; AH->currWithOids = -1; /* re-establish fixed state */ _doSetFixedOutputState(AH); }
static void _selectOutputSchema | ( | ArchiveHandle * | AH, | |
const char * | schemaName | |||
) | [static] |
Definition at line 2777 of file pg_backup_archiver.c.
References ahprintf(), appendPQExpBuffer(), _archiveHandle::connection, createPQExpBuffer(), _archiveHandle::currSchema, PQExpBufferData::data, destroyPQExpBuffer(), fmtId(), free, modulename, pg_strdup(), PGRES_COMMAND_OK, PQclear(), PQerrorMessage(), PQexec(), PQresultStatus(), RestoringToDB(), and warn_or_exit_horribly().
Referenced by _disableTriggersIfNecessary(), _enableTriggersIfNecessary(), _printTocEntry(), restore_toc_entry(), and RestoreArchive().
{ PQExpBuffer qry; if (!schemaName || *schemaName == '\0' || (AH->currSchema && strcmp(AH->currSchema, schemaName) == 0)) return; /* no need to do anything */ qry = createPQExpBuffer(); appendPQExpBuffer(qry, "SET search_path = %s", fmtId(schemaName)); if (strcmp(schemaName, "pg_catalog") != 0) appendPQExpBuffer(qry, ", pg_catalog"); if (RestoringToDB(AH)) { PGresult *res; res = PQexec(AH->connection, qry->data); if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) warn_or_exit_horribly(AH, modulename, "could not set search_path to \"%s\": %s", schemaName, PQerrorMessage(AH->connection)); PQclear(res); } else ahprintf(AH, "%s;\n\n", qry->data); if (AH->currSchema) free(AH->currSchema); AH->currSchema = pg_strdup(schemaName); destroyPQExpBuffer(qry); }
static void _selectTablespace | ( | ArchiveHandle * | AH, | |
const char * | tablespace | |||
) | [static] |
Definition at line 2820 of file pg_backup_archiver.c.
References ahprintf(), appendPQExpBuffer(), _archiveHandle::connection, createPQExpBuffer(), _archiveHandle::currTablespace, PQExpBufferData::data, destroyPQExpBuffer(), fmtId(), free, modulename, _restoreOptions::noTablespace, pg_strdup(), PGRES_COMMAND_OK, PQclear(), PQerrorMessage(), PQexec(), PQresultStatus(), RestoringToDB(), _archiveHandle::ropt, and warn_or_exit_horribly().
Referenced by _printTocEntry().
{ PQExpBuffer qry; const char *want, *have; /* do nothing in --no-tablespaces mode */ if (AH->ropt->noTablespace) return; have = AH->currTablespace; want = tablespace; /* no need to do anything for non-tablespace object */ if (!want) return; if (have && strcmp(want, have) == 0) return; /* no need to do anything */ qry = createPQExpBuffer(); if (strcmp(want, "") == 0) { /* We want the tablespace to be the database's default */ appendPQExpBuffer(qry, "SET default_tablespace = ''"); } else { /* We want an explicit tablespace */ appendPQExpBuffer(qry, "SET default_tablespace = %s", fmtId(want)); } if (RestoringToDB(AH)) { PGresult *res; res = PQexec(AH->connection, qry->data); if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) warn_or_exit_horribly(AH, modulename, "could not set default_tablespace to %s: %s", fmtId(want), PQerrorMessage(AH->connection)); PQclear(res); } else ahprintf(AH, "%s;\n\n", qry->data); if (AH->currTablespace) free(AH->currTablespace); AH->currTablespace = pg_strdup(want); destroyPQExpBuffer(qry); }
static void _setWithOids | ( | ArchiveHandle * | AH, | |
TocEntry * | te | |||
) | [static] |
Definition at line 2762 of file pg_backup_archiver.c.
References _doSetWithOids(), _archiveHandle::currWithOids, and _tocEntry::withOids.
Referenced by _printTocEntry().
{ if (AH->currWithOids != te->withOids) { _doSetWithOids(AH, te->withOids); AH->currWithOids = te->withOids; } }
Definition at line 2555 of file pg_backup_archiver.c.
References _tocEntry::desc.
Referenced by _printTocEntry(), _tocEntryRequired(), restore_toc_entries_parallel(), and restore_toc_entry().
static teReqs _tocEntryRequired | ( | TocEntry * | te, | |
teSection | curSection, | |||
RestoreOptions * | ropt | |||
) | [static] |
Definition at line 2418 of file pg_backup_archiver.c.
References _tocEntryIsACL(), _restoreOptions::aclsSkip, _restoreOptions::dataOnly, _tocEntry::defn, _tocEntry::desc, DUMP_DATA, DUMP_POST_DATA, DUMP_PRE_DATA, _tocEntry::dumpId, _restoreOptions::dumpSections, _restoreOptions::functionNames, _tocEntry::hadDumper, SimpleStringList::head, _restoreOptions::idWanted, _restoreOptions::indexNames, _restoreOptions::no_security_labels, NULL, REQ_SCHEMA, _restoreOptions::schemaNames, _restoreOptions::schemaOnly, SECTION_DATA, SECTION_POST_DATA, SECTION_PRE_DATA, _restoreOptions::selFunction, _restoreOptions::selIndex, _restoreOptions::selTable, _restoreOptions::selTrigger, _restoreOptions::selTypes, simple_string_list_member(), _restoreOptions::tableNames, _tocEntry::tag, and _restoreOptions::triggerNames.
Referenced by PrintTOCSummary(), and SetArchiveRestoreOptions().
{ teReqs res = REQ_SCHEMA | REQ_DATA; /* ENCODING and STDSTRINGS items are treated specially */ if (strcmp(te->desc, "ENCODING") == 0 || strcmp(te->desc, "STDSTRINGS") == 0) return REQ_SPECIAL; /* If it's an ACL, maybe ignore it */ if (ropt->aclsSkip && _tocEntryIsACL(te)) return 0; /* If it's security labels, maybe ignore it */ if (ropt->no_security_labels && strcmp(te->desc, "SECURITY LABEL") == 0) return 0; /* Ignore it if section is not to be dumped/restored */ switch (curSection) { case SECTION_PRE_DATA: if (!(ropt->dumpSections & DUMP_PRE_DATA)) return 0; break; case SECTION_DATA: if (!(ropt->dumpSections & DUMP_DATA)) return 0; break; case SECTION_POST_DATA: if (!(ropt->dumpSections & DUMP_POST_DATA)) return 0; break; default: /* shouldn't get here, really, but ignore it */ return 0; } /* Check options for selective dump/restore */ if (ropt->schemaNames) { /* If no namespace is specified, it means all. */ if (!te->namespace) return 0; if (strcmp(ropt->schemaNames, te->namespace) != 0) return 0; } if (ropt->selTypes) { if (strcmp(te->desc, "TABLE") == 0 || strcmp(te->desc, "TABLE DATA") == 0) { if (!ropt->selTable) return 0; if (ropt->tableNames.head != NULL && (!(simple_string_list_member(&ropt->tableNames, te->tag)))) return 0; } else if (strcmp(te->desc, "INDEX") == 0) { if (!ropt->selIndex) return 0; if (ropt->indexNames && strcmp(ropt->indexNames, te->tag) != 0) return 0; } else if (strcmp(te->desc, "FUNCTION") == 0) { if (!ropt->selFunction) return 0; if (ropt->functionNames && strcmp(ropt->functionNames, te->tag) != 0) return 0; } else if (strcmp(te->desc, "TRIGGER") == 0) { if (!ropt->selTrigger) return 0; if (ropt->triggerNames && strcmp(ropt->triggerNames, te->tag) != 0) return 0; } else return 0; } /* * Check if we had a dataDumper. Indicates if the entry is schema or data */ if (!te->hadDumper) { /* * Special Case: If 'SEQUENCE SET' or anything to do with BLOBs, then * it is considered a data entry. We don't need to check for the * BLOBS entry or old-style BLOB COMMENTS, because they will have * hadDumper = true ... but we do need to check new-style BLOB * comments. */ if (strcmp(te->desc, "SEQUENCE SET") == 0 || strcmp(te->desc, "BLOB") == 0 || (strcmp(te->desc, "ACL") == 0 && strncmp(te->tag, "LARGE OBJECT ", 13) == 0) || (strcmp(te->desc, "COMMENT") == 0 && strncmp(te->tag, "LARGE OBJECT ", 13) == 0) || (strcmp(te->desc, "SECURITY LABEL") == 0 && strncmp(te->tag, "LARGE OBJECT ", 13) == 0)) res = res & REQ_DATA; else res = res & ~REQ_DATA; } /* * Special case: <Init> type with <Max OID> tag; this is obsolete and we * always ignore it. */ if ((strcmp(te->desc, "<Init>") == 0) && (strcmp(te->tag, "Max OID") == 0)) return 0; /* Mask it if we only want schema */ if (ropt->schemaOnly) res = res & REQ_SCHEMA; /* Mask it if we only want data */ if (ropt->dataOnly) res = res & REQ_DATA; /* Mask it if we don't have a schema contribution */ if (!te->defn || strlen(te->defn) == 0) res = res & ~REQ_SCHEMA; /* Finally, if there's a per-ID filter, limit based on that as well */ if (ropt->idWanted && !ropt->idWanted[te->dumpId - 1]) return 0; return res; }
void ahlog | ( | ArchiveHandle * | AH, | |
int | level, | |||
const char * | fmt, | |||
... | ||||
) |
Definition at line 1338 of file pg_backup_archiver.c.
References _archiveHandle::debugLevel, NULL, _archiveHandle::public, Archive::verbose, and vwrite_msg().
Referenced by _connectDB(), _disableTriggersIfNecessary(), _enableTriggersIfNecessary(), _LoadBlobs(), _tarGetHeader(), _tarPositionTo(), dump_lo_buf(), EndRestoreBlobs(), get_next_work_item(), inhibit_data_for_failed_table(), mark_work_done(), ReadToc(), reduce_dependencies(), repoint_table_dependencies(), restore_toc_entries_parallel(), restore_toc_entries_postfork(), restore_toc_entries_prefork(), restore_toc_entry(), RestoreArchive(), and StartRestoreBlob().
{ va_list ap; if (AH->debugLevel < level && (!AH->public.verbose || level > 1)) return; va_start(ap, fmt); vwrite_msg(NULL, fmt, ap); va_end(ap); }
int ahprintf | ( | ArchiveHandle * | AH, | |
const char * | fmt, | |||
... | ||||
) |
Definition at line 1310 of file pg_backup_archiver.c.
References ahwrite(), free, NULL, pg_malloc(), and vsnprintf().
Referenced by _disableTriggersIfNecessary(), _doSetFixedOutputState(), _doSetSessionAuth(), _doSetWithOids(), _enableTriggersIfNecessary(), _EndBlob(), _EndBlobs(), _EndData(), _PrintExtraToc(), _PrintTocData(), _printTocEntry(), _reconnectToDB(), _selectOutputSchema(), _selectTablespace(), _StartBlob(), _StartBlobs(), _WriteBlobData(), DropBlobIfExists(), dump_lo_buf(), dumpTimestamp(), EndRestoreBlob(), EndRestoreBlobs(), PrintTOCSummary(), restore_toc_entry(), RestoreArchive(), StartRestoreBlob(), and StartRestoreBlobs().
{ char *p = NULL; va_list ap; int bSize = strlen(fmt) + 256; /* Usually enough */ int cnt = -1; /* * This is paranoid: deal with the possibility that vsnprintf is willing * to ignore trailing null or returns > 0 even if string does not fit. It * may be the case that it returns cnt = bufsize. */ while (cnt < 0 || cnt >= (bSize - 1)) { if (p != NULL) free(p); bSize *= 2; p = (char *) pg_malloc(bSize); va_start(ap, fmt); cnt = vsnprintf(p, bSize, fmt, ap); va_end(ap); } ahwrite(p, 1, cnt, AH); free(p); return cnt; }
int ahwrite | ( | const void * | ptr, | |
size_t | size, | |||
size_t | nmemb, | |||
ArchiveHandle * | AH | |||
) |
Definition at line 1406 of file pg_backup_archiver.c.
References _archiveHandle::CustomOutPtr, dump_lo_buf(), ExecuteSqlCommandBuf(), exit_horribly(), _archiveHandle::gzOut, GZWRITE, _archiveHandle::lo_buf, _archiveHandle::lo_buf_size, _archiveHandle::lo_buf_used, modulename, _archiveHandle::OF, remaining, RestoringToDB(), strerror(), and _archiveHandle::writingBlob.
Referenced by _LoadBlobs(), _PrintFileData(), _PrintTocData(), _WriteData(), ahprintf(), and ReadDataFromArchiveNone().
{ size_t res; if (AH->writingBlob) { size_t remaining = size * nmemb; while (AH->lo_buf_used + remaining > AH->lo_buf_size) { size_t avail = AH->lo_buf_size - AH->lo_buf_used; memcpy((char *) AH->lo_buf + AH->lo_buf_used, ptr, avail); ptr = (const void *) ((const char *) ptr + avail); remaining -= avail; AH->lo_buf_used += avail; dump_lo_buf(AH); } memcpy((char *) AH->lo_buf + AH->lo_buf_used, ptr, remaining); AH->lo_buf_used += remaining; return size * nmemb; } else if (AH->gzOut) { res = GZWRITE(ptr, size, nmemb, AH->OF); if (res != (nmemb * size)) exit_horribly(modulename, "could not write to output file: %s\n", strerror(errno)); return res; } else if (AH->CustomOutPtr) { res = AH->CustomOutPtr (AH, ptr, size * nmemb); if (res != (nmemb * size)) exit_horribly(modulename, "could not write to custom output routine\n"); return res; } else { /* * If we're doing a restore, and it's direct to DB, and we're * connected then send it to the DB. */ if (RestoringToDB(AH)) return ExecuteSqlCommandBuf(AH, (const char *) ptr, size * nmemb); else { res = fwrite(ptr, size, nmemb, AH->OF); if (res != nmemb) exit_horribly(modulename, "could not write to output file: %s\n", strerror(errno)); return res; } } }
void ArchiveEntry | ( | Archive * | AHX, | |
CatalogId | catalogId, | |||
DumpId | dumpId, | |||
const char * | tag, | |||
const char * | namespace, | |||
const char * | tablespace, | |||
const char * | owner, | |||
bool | withOids, | |||
const char * | desc, | |||
teSection | section, | |||
const char * | defn, | |||
const char * | dropStmt, | |||
const char * | copyStmt, | |||
const DumpId * | deps, | |||
int | nDeps, | |||
DataDumperPtr | dumpFn, | |||
void * | dumpArg | |||
) |
Definition at line 803 of file pg_backup_archiver.c.
References _archiveHandle::ArchiveEntryPtr, _tocEntry::catalogId, _tocEntry::dataDumper, _tocEntry::dataDumperArg, _tocEntry::dependencies, _tocEntry::dumpId, _tocEntry::formatData, _tocEntry::hadDumper, _archiveHandle::maxDumpId, _tocEntry::nDeps, _tocEntry::next, NULL, pg_malloc(), pg_malloc0(), pg_strdup(), _tocEntry::prev, _tocEntry::section, _tocEntry::tag, _archiveHandle::toc, and _archiveHandle::tocCount.
Referenced by dumpACL(), dumpAgg(), dumpAttrDef(), dumpBaseType(), dumpBlob(), dumpCast(), dumpCollation(), dumpComment(), dumpCompositeType(), dumpCompositeTypeColComments(), dumpConstraint(), dumpConversion(), dumpDatabase(), dumpDefaultACL(), dumpDomain(), dumpDumpableObject(), dumpEncoding(), dumpEnumType(), dumpEventTrigger(), dumpExtension(), dumpForeignDataWrapper(), dumpForeignServer(), dumpFunc(), dumpIndex(), dumpNamespace(), dumpOpclass(), dumpOpfamily(), dumpOpr(), dumpProcLang(), dumpRangeType(), dumpRule(), dumpSecLabel(), dumpSequence(), dumpSequenceData(), dumpShellType(), dumpStdStrings(), dumpTableComment(), dumpTableData(), dumpTableSchema(), dumpTableSecLabel(), dumpTrigger(), dumpTSConfig(), dumpTSDictionary(), dumpTSParser(), dumpTSTemplate(), dumpUserMappings(), and refreshMatViewData().
{ ArchiveHandle *AH = (ArchiveHandle *) AHX; TocEntry *newToc; newToc = (TocEntry *) pg_malloc0(sizeof(TocEntry)); AH->tocCount++; if (dumpId > AH->maxDumpId) AH->maxDumpId = dumpId; newToc->prev = AH->toc->prev; newToc->next = AH->toc; AH->toc->prev->next = newToc; AH->toc->prev = newToc; newToc->catalogId = catalogId; newToc->dumpId = dumpId; newToc->section = 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->withOids = withOids; newToc->desc = pg_strdup(desc); newToc->defn = pg_strdup(defn); newToc->dropStmt = pg_strdup(dropStmt); newToc->copyStmt = copyStmt ? pg_strdup(copyStmt) : NULL; if (nDeps > 0) { newToc->dependencies = (DumpId *) pg_malloc(nDeps * sizeof(DumpId)); memcpy(newToc->dependencies, deps, nDeps * sizeof(DumpId)); newToc->nDeps = nDeps; } else { newToc->dependencies = NULL; newToc->nDeps = 0; } newToc->dataDumper = dumpFn; newToc->dataDumperArg = dumpArg; newToc->hadDumper = dumpFn ? true : false; newToc->formatData = NULL; if (AH->ArchiveEntryPtr !=NULL) (*AH->ArchiveEntryPtr) (AH, newToc); }
int archprintf | ( | Archive * | AH, | |
const char * | fmt, | |||
... | ||||
) |
Definition at line 1181 of file pg_backup_archiver.c.
References free, NULL, pg_malloc(), vsnprintf(), and WriteData().
{ char *p = NULL; va_list ap; int bSize = strlen(fmt) + 256; int cnt = -1; /* * This is paranoid: deal with the possibility that vsnprintf is willing * to ignore trailing null or returns > 0 even if string does not fit. It * may be the case that it returns cnt = bufsize */ while (cnt < 0 || cnt >= (bSize - 1)) { if (p != NULL) free(p); bSize *= 2; p = (char *) pg_malloc(bSize); va_start(ap, fmt); cnt = vsnprintf(p, bSize, fmt, ap); va_end(ap); } WriteData(AH, p, cnt); free(p); return cnt; }
int archputs | ( | const char * | s, | |
Archive * | AH | |||
) |
Definition at line 1174 of file pg_backup_archiver.c.
References WriteData().
Referenced by dumpTableData_insert().
{ return WriteData(AH, s, strlen(s)); }
static void buildTocEntryArrays | ( | ArchiveHandle * | AH | ) | [static] |
Definition at line 1556 of file pg_backup_archiver.c.
References _tocEntry::dependencies, _tocEntry::desc, _tocEntry::dumpId, exit_horribly(), _archiveHandle::maxDumpId, modulename, _tocEntry::nDeps, _tocEntry::next, pg_malloc0(), _archiveHandle::tableDataId, _archiveHandle::toc, and _archiveHandle::tocsByDumpId.
Referenced by getTocEntryByDumpId(), and RestoreArchive().
{ DumpId maxDumpId = AH->maxDumpId; TocEntry *te; AH->tocsByDumpId = (TocEntry **) pg_malloc0((maxDumpId + 1) * sizeof(TocEntry *)); AH->tableDataId = (DumpId *) pg_malloc0((maxDumpId + 1) * sizeof(DumpId)); for (te = AH->toc->next; te != AH->toc; te = te->next) { /* this check is purely paranoia, maxDumpId should be correct */ if (te->dumpId <= 0 || te->dumpId > maxDumpId) exit_horribly(modulename, "bad dumpId\n"); /* tocsByDumpId indexes all TOCs by their dump ID */ AH->tocsByDumpId[te->dumpId] = te; /* * tableDataId provides the TABLE DATA item's dump ID for each TABLE * TOC entry that has a DATA item. We compute this by reversing the * TABLE DATA item's dependency, knowing that a TABLE DATA item has * just one dependency and it is the TABLE item. */ if (strcmp(te->desc, "TABLE DATA") == 0 && te->nDeps > 0) { DumpId tableId = te->dependencies[0]; /* * The TABLE item might not have been in the archive, if this was * a data-only dump; but its dump ID should be less than its data * item's dump ID, so there should be a place for it in the array. */ if (tableId <= 0 || tableId > maxDumpId) exit_horribly(modulename, "bad table dumpId for TABLE DATA item\n"); AH->tableDataId[tableId] = te->dumpId; } } }
bool checkSeek | ( | FILE * | fp | ) |
Definition at line 3329 of file pg_backup_archiver.c.
References fseeko, ftello, and pgoff_t.
Referenced by InitArchiveFmt_Custom(), and InitArchiveFmt_Tar().
{ pgoff_t tpos; /* * If pgoff_t is wider than long, we must have "real" fseeko and not an * emulation using fseek. Otherwise report no seek capability. */ #ifndef HAVE_FSEEKO if (sizeof(pgoff_t) > sizeof(long)) return false; #endif /* Check that ftello works on this file */ errno = 0; tpos = ftello(fp); if (errno) return false; /* * Check that fseeko(SEEK_SET) works, too. NB: we used to try to test * this with fseeko(fp, 0, SEEK_CUR). But some platforms treat that as a * successful no-op even on files that are otherwise unseekable. */ if (fseeko(fp, tpos, SEEK_SET) != 0) return false; return true; }
ArchiveHandle* CloneArchive | ( | ArchiveHandle * | AH | ) |
Definition at line 4154 of file pg_backup_archiver.c.
References archModeRead, Assert, _archiveHandle::ClonePtr, ConnectDatabase(), _archiveHandle::connection, _archiveHandle::currSchema, _archiveHandle::currTablespace, _archiveHandle::currUser, _archiveHandle::currWithOids, _restoreOptions::dbname, Archive::encoding, _archiveHandle::mode, Archive::n_errors, NULL, pg_encoding_to_char(), pg_malloc(), pg_strdup(), pghost, _restoreOptions::pghost, pgport, _restoreOptions::pgport, PQdb(), PQhost(), PQport(), PQsetClientEncoding(), PQuser(), _restoreOptions::promptPassword, _archiveHandle::public, _archiveHandle::ropt, _archiveHandle::savedPassword, _archiveHandle::sqlparse, TRI_NO, username, and _restoreOptions::username.
Referenced by ParallelBackupStart().
{ ArchiveHandle *clone; /* Make a "flat" copy */ clone = (ArchiveHandle *) pg_malloc(sizeof(ArchiveHandle)); memcpy(clone, AH, sizeof(ArchiveHandle)); /* Handle format-independent fields */ memset(&(clone->sqlparse), 0, sizeof(clone->sqlparse)); /* The clone will have its own connection, so disregard connection state */ clone->connection = NULL; clone->currUser = NULL; clone->currSchema = NULL; clone->currTablespace = NULL; clone->currWithOids = -1; /* savedPassword must be local in case we change it while connecting */ if (clone->savedPassword) clone->savedPassword = pg_strdup(clone->savedPassword); /* clone has its own error count, too */ clone->public.n_errors = 0; /* * Connect our new clone object to the database: In parallel restore the * parent is already disconnected, because we can connect the worker * processes independently to the database (no snapshot sync required). In * parallel backup we clone the parent's existing connection. */ if (AH->mode == archModeRead) { RestoreOptions *ropt = AH->ropt; Assert(AH->connection == NULL); /* this also sets clone->connection */ ConnectDatabase((Archive *) clone, ropt->dbname, ropt->pghost, ropt->pgport, ropt->username, ropt->promptPassword); } else { char *dbname; char *pghost; char *pgport; char *username; const char *encname; Assert(AH->connection != NULL); /* * Even though we are technically accessing the parent's database * object here, these functions are fine to be called like that * because all just return a pointer and do not actually send/receive * any data to/from the database. */ dbname = PQdb(AH->connection); pghost = PQhost(AH->connection); pgport = PQport(AH->connection); username = PQuser(AH->connection); encname = pg_encoding_to_char(AH->public.encoding); /* this also sets clone->connection */ ConnectDatabase((Archive *) clone, dbname, pghost, pgport, username, TRI_NO); /* * Set the same encoding, whatever we set here is what we got from * pg_encoding_to_char(), so we really shouldn't run into an error * setting that very same value. Also see the comment in * SetupConnection(). */ PQsetClientEncoding(clone->connection, encname); } /* Let the format-specific code have a chance too */ (clone->ClonePtr) (clone); Assert(clone->connection != NULL); return clone; }
void CloseArchive | ( | Archive * | AHX | ) |
Definition at line 155 of file pg_backup_archiver.c.
References _archiveHandle::ClosePtr, exit_horribly(), GZCLOSE, _archiveHandle::gzOut, modulename, _archiveHandle::OF, and strerror().
Referenced by main().
{ int res = 0; ArchiveHandle *AH = (ArchiveHandle *) AHX; (*AH->ClosePtr) (AH); /* Close the output */ if (AH->gzOut) res = GZCLOSE(AH->OF); else if (AH->OF != stdout) res = fclose(AH->OF); if (res != 0) exit_horribly(modulename, "could not close output file: %s\n", strerror(errno)); }
Archive* CreateArchive | ( | const char * | FileSpec, | |
const ArchiveFormat | fmt, | |||
const int | compression, | |||
ArchiveMode | mode, | |||
SetupWorkerPtr | setupDumpWorker | |||
) |
Definition at line 134 of file pg_backup_archiver.c.
References _allocAH().
Referenced by main().
{ ArchiveHandle *AH = _allocAH(FileSpec, fmt, compression, mode, setupDumpWorker); return (Archive *) AH; }
void DeCloneArchive | ( | ArchiveHandle * | AH | ) |
Definition at line 4242 of file pg_backup_archiver.c.
References sqlparseInfo::curCmd, _archiveHandle::currSchema, _archiveHandle::currTablespace, _archiveHandle::currUser, _archiveHandle::DeClonePtr, destroyPQExpBuffer(), free, _archiveHandle::savedPassword, and _archiveHandle::sqlparse.
{ /* Clear format-specific state */ (AH->DeClonePtr) (AH); /* Clear state allocated by CloneArchive */ if (AH->sqlparse.curCmd) destroyPQExpBuffer(AH->sqlparse.curCmd); /* Clear any connection-local state */ if (AH->currUser) free(AH->currUser); if (AH->currSchema) free(AH->currSchema); if (AH->currTablespace) free(AH->currTablespace); if (AH->savedPassword) free(AH->savedPassword); free(AH); }
static void dump_lo_buf | ( | ArchiveHandle * | AH | ) | [static] |
Definition at line 1363 of file pg_backup_archiver.c.
References ahlog(), ahprintf(), appendByteaLiteralAHX, buf, _archiveHandle::connection, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), exit_horribly(), _archiveHandle::lo_buf, _archiveHandle::lo_buf_used, lo_write(), _archiveHandle::loFd, modulename, ngettext, and _archiveHandle::writingBlob.
Referenced by ahwrite(), and EndRestoreBlob().
{ if (AH->connection) { size_t res; res = lo_write(AH->connection, AH->loFd, AH->lo_buf, AH->lo_buf_used); ahlog(AH, 5, ngettext("wrote %lu byte of large object data (result = %lu)\n", "wrote %lu bytes of large object data (result = %lu)\n", AH->lo_buf_used), (unsigned long) AH->lo_buf_used, (unsigned long) res); if (res != AH->lo_buf_used) exit_horribly(modulename, "could not write to large object (result: %lu, expected: %lu)\n", (unsigned long) res, (unsigned long) AH->lo_buf_used); } else { PQExpBuffer buf = createPQExpBuffer(); appendByteaLiteralAHX(buf, (const unsigned char *) AH->lo_buf, AH->lo_buf_used, AH); /* Hack: turn off writingBlob so ahwrite doesn't recurse to here */ AH->writingBlob = 0; ahprintf(AH, "SELECT pg_catalog.lowrite(0, %s);\n", buf->data); AH->writingBlob = 1; destroyPQExpBuffer(buf); } AH->lo_buf_used = 0; }
static void dumpTimestamp | ( | ArchiveHandle * | AH, | |
const char * | msg, | |||
time_t | tim | |||
) | [static] |
Definition at line 3364 of file pg_backup_archiver.c.
References ahprintf(), and buf.
Referenced by RestoreArchive().
{ char buf[256]; /* * We don't print the timezone on Win32, because the names are long and * localized, which means they may contain characters in various random * encodings; this has been seen to cause encoding errors when reading the * dump script. */ if (strftime(buf, sizeof(buf), #ifndef WIN32 "%Y-%m-%d %H:%M:%S %Z", #else "%Y-%m-%d %H:%M:%S", #endif localtime(&tim)) != 0) ahprintf(AH, "-- %s %s\n\n", msg, buf); }
Definition at line 954 of file pg_backup_archiver.c.
References _archiveHandle::currToc, and _archiveHandle::EndBlobPtr.
Referenced by dumpBlobs().
{ ArchiveHandle *AH = (ArchiveHandle *) AHX; if (AH->EndBlobPtr) (*AH->EndBlobPtr) (AH, AH->currToc, oid); return 1; }
void EndRestoreBlob | ( | ArchiveHandle * | AH, | |
Oid | oid | |||
) |
Definition at line 1054 of file pg_backup_archiver.c.
References ahprintf(), _archiveHandle::connection, dump_lo_buf(), _archiveHandle::lo_buf_used, lo_close(), _archiveHandle::loFd, and _archiveHandle::writingBlob.
Referenced by _LoadBlobs().
{ if (AH->lo_buf_used > 0) { /* Write remaining bytes from the LO buffer */ dump_lo_buf(AH); } AH->writingBlob = 0; if (AH->connection) { lo_close(AH->connection, AH->loFd); AH->loFd = -1; } else { ahprintf(AH, "SELECT pg_catalog.lo_close(0);\n\n"); } }
void EndRestoreBlobs | ( | ArchiveHandle * | AH | ) |
Definition at line 989 of file pg_backup_archiver.c.
References ahlog(), ahprintf(), _archiveHandle::blobCount, CommitTransaction(), _archiveHandle::connection, ngettext, _archiveHandle::ropt, and _restoreOptions::single_txn.
Referenced by _LoadBlobs().
{ if (!AH->ropt->single_txn) { if (AH->connection) CommitTransaction(AH); else ahprintf(AH, "COMMIT;\n\n"); } ahlog(AH, 1, ngettext("restored %d large object\n", "restored %d large objects\n", AH->blobCount), AH->blobCount); }
static void fix_dependencies | ( | ArchiveHandle * | AH | ) | [static] |
Definition at line 3887 of file pg_backup_archiver.c.
References _tocEntry::depCount, _tocEntry::dependencies, _tocEntry::desc, _tocEntry::dumpId, i, identify_locking_dependencies(), K_VERS_1_11, _tocEntry::lockDeps, _tocEntry::nDeps, _tocEntry::next, _tocEntry::nLockDeps, _tocEntry::nRevDeps, NULL, _tocEntry::par_next, _tocEntry::par_prev, pg_malloc(), repoint_table_dependencies(), _tocEntry::revDeps, _archiveHandle::toc, _archiveHandle::tocsByDumpId, and _archiveHandle::version.
Referenced by restore_toc_entries_prefork().
{ TocEntry *te; int i; /* * Initialize the depCount/revDeps/nRevDeps fields, and make sure the TOC * items are marked as not being in any parallel-processing list. */ for (te = AH->toc->next; te != AH->toc; te = te->next) { te->depCount = te->nDeps; te->revDeps = NULL; te->nRevDeps = 0; te->par_prev = NULL; te->par_next = NULL; } /* * POST_DATA items that are shown as depending on a table need to be * re-pointed to depend on that table's data, instead. This ensures they * won't get scheduled until the data has been loaded. */ repoint_table_dependencies(AH); /* * Pre-8.4 versions of pg_dump neglected to set up a dependency from BLOB * COMMENTS to BLOBS. Cope. (We assume there's only one BLOBS and only * one BLOB COMMENTS in such files.) */ if (AH->version < K_VERS_1_11) { for (te = AH->toc->next; te != AH->toc; te = te->next) { if (strcmp(te->desc, "BLOB COMMENTS") == 0 && te->nDeps == 0) { TocEntry *te2; for (te2 = AH->toc->next; te2 != AH->toc; te2 = te2->next) { if (strcmp(te2->desc, "BLOBS") == 0) { te->dependencies = (DumpId *) pg_malloc(sizeof(DumpId)); te->dependencies[0] = te2->dumpId; te->nDeps++; te->depCount++; break; } } break; } } } /* * At this point we start to build the revDeps reverse-dependency arrays, * so all changes of dependencies must be complete. */ /* * Count the incoming dependencies for each item. Also, it is possible * that the dependencies list items that are not in the archive at all * (that should not happen in 9.2 and later, but is highly likely in older * archives). Subtract such items from the depCounts. */ for (te = AH->toc->next; te != AH->toc; te = te->next) { for (i = 0; i < te->nDeps; i++) { DumpId depid = te->dependencies[i]; if (depid <= AH->maxDumpId && AH->tocsByDumpId[depid] != NULL) AH->tocsByDumpId[depid]->nRevDeps++; else te->depCount--; } } /* * Allocate space for revDeps[] arrays, and reset nRevDeps so we can use * it as a counter below. */ for (te = AH->toc->next; te != AH->toc; te = te->next) { if (te->nRevDeps > 0) te->revDeps = (DumpId *) pg_malloc(te->nRevDeps * sizeof(DumpId)); te->nRevDeps = 0; } /* * Build the revDeps[] arrays of incoming-dependency dumpIds. This had * better agree with the loops above. */ for (te = AH->toc->next; te != AH->toc; te = te->next) { for (i = 0; i < te->nDeps; i++) { DumpId depid = te->dependencies[i]; if (depid <= AH->maxDumpId && AH->tocsByDumpId[depid] != NULL) { TocEntry *otherte = AH->tocsByDumpId[depid]; otherte->revDeps[otherte->nRevDeps++] = te->dumpId; } } } /* * Lastly, work out the locking dependencies. */ for (te = AH->toc->next; te != AH->toc; te = te->next) { te->lockDeps = NULL; te->nLockDeps = 0; identify_locking_dependencies(AH, te); } }
static TocEntry * get_next_work_item | ( | ArchiveHandle * | AH, | |
TocEntry * | ready_list, | |||
ParallelState * | pstate | |||
) | [static] |
Definition at line 3732 of file pg_backup_archiver.c.
References ahlog(), ParallelSlot::args, has_lock_conflicts(), i, NULL, ParallelState::numWorkers, _tocEntry::par_next, ParallelState::parallelSlot, _tocEntry::section, SECTION_DATA, ParallelArgs::te, ParallelSlot::workerStatus, and WRKR_WORKING.
Referenced by restore_toc_entries_parallel().
{ bool pref_non_data = false; /* or get from AH->ropt */ TocEntry *data_te = NULL; TocEntry *te; int i, k; /* * Bogus heuristics for pref_non_data */ if (pref_non_data) { int count = 0; for (k = 0; k < pstate->numWorkers; k++) if (pstate->parallelSlot[k].args->te != NULL && pstate->parallelSlot[k].args->te->section == SECTION_DATA) count++; if (pstate->numWorkers == 0 || count * 4 < pstate->numWorkers) pref_non_data = false; } /* * Search the ready_list until we find a suitable item. */ for (te = ready_list->par_next; te != ready_list; te = te->par_next) { bool conflicts = false; /* * Check to see if the item would need exclusive lock on something * that a currently running item also needs lock on, or vice versa. If * so, we don't want to schedule them together. */ for (i = 0; i < pstate->numWorkers && !conflicts; i++) { TocEntry *running_te; if (pstate->parallelSlot[i].workerStatus != WRKR_WORKING) continue; running_te = pstate->parallelSlot[i].args->te; if (has_lock_conflicts(te, running_te) || has_lock_conflicts(running_te, te)) { conflicts = true; break; } } if (conflicts) continue; if (pref_non_data && te->section == SECTION_DATA) { if (data_te == NULL) data_te = te; continue; } /* passed all tests, so this item can run */ return te; } if (data_te != NULL) return data_te; ahlog(AH, 2, "no item ready\n"); return NULL; }
TocEntry* getTocEntryByDumpId | ( | ArchiveHandle * | AH, | |
DumpId | id | |||
) |
Definition at line 1597 of file pg_backup_archiver.c.
References buildTocEntryArrays(), NULL, and _archiveHandle::tocsByDumpId.
Referenced by SortTocFromFile(), TocIDRequired(), and WaitForCommands().
{ /* build index arrays if we didn't already */ if (AH->tocsByDumpId == NULL) buildTocEntryArrays(AH); if (id > 0 && id <= AH->maxDumpId) return AH->tocsByDumpId[id]; return NULL; }
Definition at line 3665 of file pg_backup_archiver.c.
References _tocEntry::dependencies, _tocEntry::lockDeps, _tocEntry::nDeps, and _tocEntry::nLockDeps.
Referenced by get_next_work_item().
{ int j, k; for (j = 0; j < te1->nLockDeps; j++) { for (k = 0; k < te2->nDeps; k++) { if (te1->lockDeps[j] == te2->dependencies[k]) return true; } } return false; }
static void identify_locking_dependencies | ( | ArchiveHandle * | AH, | |
TocEntry * | te | |||
) | [static] |
Definition at line 4041 of file pg_backup_archiver.c.
References _tocEntry::dependencies, _tocEntry::desc, free, i, _tocEntry::lockDeps, _tocEntry::nDeps, _tocEntry::nLockDeps, NULL, pg_malloc(), pg_realloc(), and _archiveHandle::tocsByDumpId.
Referenced by fix_dependencies().
{ DumpId *lockids; int nlockids; int i; /* Quick exit if no dependencies at all */ if (te->nDeps == 0) return; /* Exit if this entry doesn't need exclusive lock on other objects */ if (!(strcmp(te->desc, "CONSTRAINT") == 0 || strcmp(te->desc, "CHECK CONSTRAINT") == 0 || strcmp(te->desc, "FK CONSTRAINT") == 0 || strcmp(te->desc, "RULE") == 0 || strcmp(te->desc, "TRIGGER") == 0)) return; /* * We assume the item requires exclusive lock on each TABLE DATA item * listed among its dependencies. (This was originally a dependency on * the TABLE, but fix_dependencies repointed it to the data item. Note * that all the entry types we are interested in here are POST_DATA, so * they will all have been changed this way.) */ lockids = (DumpId *) pg_malloc(te->nDeps * sizeof(DumpId)); nlockids = 0; for (i = 0; i < te->nDeps; i++) { DumpId depid = te->dependencies[i]; if (depid <= AH->maxDumpId && AH->tocsByDumpId[depid] != NULL && strcmp(AH->tocsByDumpId[depid]->desc, "TABLE DATA") == 0) lockids[nlockids++] = depid; } if (nlockids == 0) { free(lockids); return; } te->lockDeps = pg_realloc(lockids, nlockids * sizeof(DumpId)); te->nLockDeps = nlockids; }
static void inhibit_data_for_failed_table | ( | ArchiveHandle * | AH, | |
TocEntry * | te | |||
) | [static] |
Definition at line 4134 of file pg_backup_archiver.c.
References ahlog(), _tocEntry::dumpId, _tocEntry::reqs, _archiveHandle::tableDataId, _tocEntry::tag, and _archiveHandle::tocsByDumpId.
Referenced by mark_work_done(), and restore_toc_entry().
{ ahlog(AH, 1, "table \"%s\" could not be created, will not restore its data\n", te->tag); if (AH->tableDataId[te->dumpId] != 0) { TocEntry *ted = AH->tocsByDumpId[AH->tableDataId[te->dumpId]]; ted->reqs = 0; } }
static void mark_create_done | ( | ArchiveHandle * | AH, | |
TocEntry * | te | |||
) | [static] |
Definition at line 4119 of file pg_backup_archiver.c.
References _tocEntry::created, _tocEntry::dumpId, _archiveHandle::tableDataId, and _archiveHandle::tocsByDumpId.
Referenced by mark_work_done(), and restore_toc_entry().
{ if (AH->tableDataId[te->dumpId] != 0) { TocEntry *ted = AH->tocsByDumpId[AH->tableDataId[te->dumpId]]; ted->created = true; } }
static void mark_work_done | ( | ArchiveHandle * | AH, | |
TocEntry * | ready_list, | |||
int | worker, | |||
int | status, | |||
ParallelState * | pstate | |||
) | [static] |
Definition at line 3842 of file pg_backup_archiver.c.
References ahlog(), ParallelSlot::args, _tocEntry::desc, _tocEntry::dumpId, exit_horribly(), inhibit_data_for_failed_table(), mark_create_done(), modulename, Archive::n_errors, NULL, ParallelState::parallelSlot, _archiveHandle::public, reduce_dependencies(), _tocEntry::tag, ParallelArgs::te, WORKER_CREATE_DONE, WORKER_IGNORED_ERRORS, and WORKER_INHIBIT_DATA.
Referenced by restore_toc_entries_parallel().
{ TocEntry *te = NULL; te = pstate->parallelSlot[worker].args->te; if (te == NULL) exit_horribly(modulename, "could not find slot of finished worker\n"); ahlog(AH, 1, "finished item %d %s %s\n", te->dumpId, te->desc, te->tag); if (status == WORKER_CREATE_DONE) mark_create_done(AH, te); else if (status == WORKER_INHIBIT_DATA) { inhibit_data_for_failed_table(AH, te); AH->public.n_errors++; } else if (status == WORKER_IGNORED_ERRORS) AH->public.n_errors++; else if (status != 0) exit_horribly(modulename, "worker process failed: exit code %d\n", status); reduce_dependencies(AH, te, ready_list); }
RestoreOptions* NewRestoreOptions | ( | void | ) |
Definition at line 714 of file pg_backup_archiver.c.
References _restoreOptions::dumpSections, _restoreOptions::format, pg_malloc0(), and _restoreOptions::promptPassword.
Referenced by _CloseArchive(), and main().
{ RestoreOptions *opts; opts = (RestoreOptions *) pg_malloc0(sizeof(RestoreOptions)); /* set any fields that shouldn't default to zeroes */ opts->format = archUnknown; opts->promptPassword = TRI_DEFAULT; opts->dumpSections = DUMP_UNSECTIONED; return opts; }
Archive* OpenArchive | ( | const char * | FileSpec, | |
const ArchiveFormat | fmt | |||
) |
Definition at line 146 of file pg_backup_archiver.c.
References _allocAH(), archModeRead, and setupRestoreWorker().
Referenced by main().
{ ArchiveHandle *AH = _allocAH(FileSpec, fmt, 0, archModeRead, setupRestoreWorker); return (Archive *) AH; }
Definition at line 3697 of file pg_backup_archiver.c.
References _tocEntry::par_next, and _tocEntry::par_prev.
Referenced by reduce_dependencies(), and restore_toc_entries_parallel().
static void par_list_header_init | ( | TocEntry * | l | ) | [static] |
Definition at line 3690 of file pg_backup_archiver.c.
References _tocEntry::par_next, and _tocEntry::par_prev.
Referenced by restore_toc_entries_parallel(), and RestoreArchive().
static void par_list_remove | ( | TocEntry * | te | ) | [static] |
Definition at line 3707 of file pg_backup_archiver.c.
References _tocEntry::par_next, and _tocEntry::par_prev.
Referenced by reduce_dependencies(), and restore_toc_entries_parallel().
int parallel_restore | ( | ParallelArgs * | args | ) |
Definition at line 3815 of file pg_backup_archiver.c.
References _doSetFixedOutputState(), ParallelArgs::AH, Assert, _archiveHandle::connection, Archive::n_errors, NULL, _archiveHandle::public, restore_toc_entry(), _archiveHandle::ropt, and ParallelArgs::te.
Referenced by _WorkerJobRestoreCustom(), and _WorkerJobRestoreDirectory().
{ ArchiveHandle *AH = args->AH; TocEntry *te = args->te; RestoreOptions *ropt = AH->ropt; int status; _doSetFixedOutputState(AH); Assert(AH->connection != NULL); AH->public.n_errors = 0; /* Restore the TOC item */ status = restore_toc_entry(AH, te, ropt, true); return status; }
void PrintTOCSummary | ( | Archive * | AHX, | |
RestoreOptions * | ropt | |||
) |
Definition at line 867 of file pg_backup_archiver.c.
References _tocEntryRequired(), ahprintf(), archCustom, _archiveHandle::archdbname, _archiveHandle::archiveDumpVersion, _archiveHandle::archiveRemoteVersion, archTar, _tocEntry::catalogId, _archiveHandle::compression, _archiveHandle::createDate, _tocEntry::dependencies, _tocEntry::desc, _tocEntry::dumpId, _restoreOptions::filename, _archiveHandle::format, i, _archiveHandle::intSize, _tocEntry::nDeps, _tocEntry::next, _archiveHandle::offSize, CatalogId::oid, _tocEntry::owner, REQ_DATA, REQ_SCHEMA, RestoreOutput(), SaveOutput(), _tocEntry::section, SECTION_NONE, SetOutput(), CatalogId::tableoid, _tocEntry::tag, _archiveHandle::toc, _archiveHandle::tocCount, _restoreOptions::verbose, _archiveHandle::vmaj, _archiveHandle::vmin, and _archiveHandle::vrev.
Referenced by main().
{ ArchiveHandle *AH = (ArchiveHandle *) AHX; TocEntry *te; teSection curSection; OutputContext sav; const char *fmtName; sav = SaveOutput(AH); if (ropt->filename) SetOutput(AH, ropt->filename, 0 /* no compression */ ); ahprintf(AH, ";\n; Archive created at %s", ctime(&AH->createDate)); ahprintf(AH, "; dbname: %s\n; TOC Entries: %d\n; Compression: %d\n", AH->archdbname, AH->tocCount, AH->compression); switch (AH->format) { case archCustom: fmtName = "CUSTOM"; break; case archTar: fmtName = "TAR"; break; default: fmtName = "UNKNOWN"; } ahprintf(AH, "; Dump Version: %d.%d-%d\n", AH->vmaj, AH->vmin, AH->vrev); ahprintf(AH, "; Format: %s\n", fmtName); ahprintf(AH, "; Integer: %d bytes\n", (int) AH->intSize); ahprintf(AH, "; Offset: %d bytes\n", (int) AH->offSize); if (AH->archiveRemoteVersion) ahprintf(AH, "; Dumped from database version: %s\n", AH->archiveRemoteVersion); if (AH->archiveDumpVersion) ahprintf(AH, "; Dumped by pg_dump version: %s\n", AH->archiveDumpVersion); ahprintf(AH, ";\n;\n; Selected TOC Entries:\n;\n"); curSection = SECTION_PRE_DATA; for (te = AH->toc->next; te != AH->toc; te = te->next) { if (te->section != SECTION_NONE) curSection = te->section; if (ropt->verbose || (_tocEntryRequired(te, curSection, ropt) & (REQ_SCHEMA | REQ_DATA)) != 0) ahprintf(AH, "%d; %u %u %s %s %s %s\n", te->dumpId, te->catalogId.tableoid, te->catalogId.oid, te->desc, te->namespace ? te->namespace : "-", te->tag, te->owner); if (ropt->verbose && te->nDeps > 0) { int i; ahprintf(AH, ";\tdepends on:"); for (i = 0; i < te->nDeps; i++) ahprintf(AH, " %d", te->dependencies[i]); ahprintf(AH, "\n"); } } if (ropt->filename) RestoreOutput(AH, sav); }
static void processEncodingEntry | ( | ArchiveHandle * | AH, | |
TocEntry * | te | |||
) | [static] |
Definition at line 2374 of file pg_backup_archiver.c.
References _tocEntry::defn, Archive::encoding, encoding, exit_horribly(), free, modulename, pg_char_to_encoding(), pg_strdup(), and _archiveHandle::public.
Referenced by ReadToc().
{ /* te->defn should have the form SET client_encoding = 'foo'; */ char *defn = pg_strdup(te->defn); char *ptr1; char *ptr2 = NULL; int encoding; ptr1 = strchr(defn, '\''); if (ptr1) ptr2 = strchr(++ptr1, '\''); if (ptr2) { *ptr2 = '\0'; encoding = pg_char_to_encoding(ptr1); if (encoding < 0) exit_horribly(modulename, "unrecognized encoding \"%s\"\n", ptr1); AH->public.encoding = encoding; } else exit_horribly(modulename, "invalid ENCODING item: %s\n", te->defn); free(defn); }
static void processStdStringsEntry | ( | ArchiveHandle * | AH, | |
TocEntry * | te | |||
) | [static] |
Definition at line 2402 of file pg_backup_archiver.c.
References _tocEntry::defn, exit_horribly(), modulename, _archiveHandle::public, and Archive::std_strings.
Referenced by ReadToc().
{ /* te->defn should have the form SET standard_conforming_strings = 'x'; */ char *ptr1; ptr1 = strchr(te->defn, '\''); if (ptr1 && strncmp(ptr1, "'on'", 4) == 0) AH->public.std_strings = true; else if (ptr1 && strncmp(ptr1, "'off'", 5) == 0) AH->public.std_strings = false; else exit_horribly(modulename, "invalid STDSTRINGS item: %s\n", te->defn); }
void ReadHead | ( | ArchiveHandle * | AH | ) |
Definition at line 3229 of file pg_backup_archiver.c.
References _archiveHandle::archdbname, _archiveHandle::archiveDumpVersion, _archiveHandle::archiveRemoteVersion, _archiveHandle::compression, _archiveHandle::createDate, exit_horribly(), _archiveHandle::format, _archiveHandle::intSize, K_VERS_1_0, K_VERS_1_10, K_VERS_1_2, K_VERS_1_4, K_VERS_1_7, K_VERS_MAX, modulename, _archiveHandle::offSize, _archiveHandle::ReadBufPtr, _archiveHandle::ReadBytePtr, _archiveHandle::readHeader, ReadInt(), ReadStr(), tm, _archiveHandle::version, _archiveHandle::vmaj, _archiveHandle::vmin, _archiveHandle::vrev, and write_msg().
Referenced by InitArchiveFmt_Custom(), InitArchiveFmt_Directory(), and InitArchiveFmt_Tar().
{ char tmpMag[7]; int fmt; struct tm crtm; /* * If we haven't already read the header, do so. * * NB: this code must agree with _discoverArchiveFormat(). Maybe find a * way to unify the cases? */ if (!AH->readHeader) { if ((*AH->ReadBufPtr) (AH, tmpMag, 5) != 5) exit_horribly(modulename, "unexpected end of file\n"); if (strncmp(tmpMag, "PGDMP", 5) != 0) exit_horribly(modulename, "did not find magic string in file header\n"); AH->vmaj = (*AH->ReadBytePtr) (AH); AH->vmin = (*AH->ReadBytePtr) (AH); if (AH->vmaj > 1 || ((AH->vmaj == 1) && (AH->vmin > 0))) /* Version > 1.0 */ AH->vrev = (*AH->ReadBytePtr) (AH); else AH->vrev = 0; AH->version = ((AH->vmaj * 256 + AH->vmin) * 256 + AH->vrev) * 256 + 0; if (AH->version < K_VERS_1_0 || AH->version > K_VERS_MAX) exit_horribly(modulename, "unsupported version (%d.%d) in file header\n", AH->vmaj, AH->vmin); AH->intSize = (*AH->ReadBytePtr) (AH); if (AH->intSize > 32) exit_horribly(modulename, "sanity check on integer size (%lu) failed\n", (unsigned long) AH->intSize); if (AH->intSize > sizeof(int)) write_msg(modulename, "WARNING: archive was made on a machine with larger integers, some operations might fail\n"); if (AH->version >= K_VERS_1_7) AH->offSize = (*AH->ReadBytePtr) (AH); else AH->offSize = AH->intSize; fmt = (*AH->ReadBytePtr) (AH); if (AH->format != fmt) exit_horribly(modulename, "expected format (%d) differs from format found in file (%d)\n", AH->format, fmt); } if (AH->version >= K_VERS_1_2) { if (AH->version < K_VERS_1_4) AH->compression = (*AH->ReadBytePtr) (AH); else AH->compression = ReadInt(AH); } else AH->compression = Z_DEFAULT_COMPRESSION; #ifndef HAVE_LIBZ if (AH->compression != 0) write_msg(modulename, "WARNING: archive is compressed, but this installation does not support compression -- no data will be available\n"); #endif if (AH->version >= K_VERS_1_4) { crtm.tm_sec = ReadInt(AH); crtm.tm_min = ReadInt(AH); crtm.tm_hour = ReadInt(AH); crtm.tm_mday = ReadInt(AH); crtm.tm_mon = ReadInt(AH); crtm.tm_year = ReadInt(AH); crtm.tm_isdst = ReadInt(AH); AH->archdbname = ReadStr(AH); AH->createDate = mktime(&crtm); if (AH->createDate == (time_t) -1) write_msg(modulename, "WARNING: invalid creation date in header\n"); } if (AH->version >= K_VERS_1_10) { AH->archiveRemoteVersion = ReadStr(AH); AH->archiveDumpVersion = ReadStr(AH); } }
int ReadInt | ( | ArchiveHandle * | AH | ) |
Definition at line 1733 of file pg_backup_archiver.c.
References _archiveHandle::intSize, K_VERS_1_0, _archiveHandle::ReadBytePtr, sign, and _archiveHandle::version.
Referenced by _CustomReadFunc(), _LoadBlobs(), _readBlockHeader(), _ReadExtraToc(), _skipBlobs(), _skipData(), ReadHead(), ReadOffset(), ReadStr(), and ReadToc().
{ int res = 0; int bv, b; int sign = 0; /* Default positive */ int bitShift = 0; if (AH->version > K_VERS_1_0) /* Read a sign byte */ sign = (*AH->ReadBytePtr) (AH); for (b = 0; b < AH->intSize; b++) { bv = (*AH->ReadBytePtr) (AH) & 0xFF; if (bv != 0) res = res + (bv << bitShift); bitShift += 8; } if (sign) res = -res; return res; }
int ReadOffset | ( | ArchiveHandle * | AH, | |
pgoff_t * | o | |||
) |
Definition at line 1638 of file pg_backup_archiver.c.
References exit_horribly(), i, K_OFFSET_NO_DATA, K_OFFSET_POS_NOT_SET, K_OFFSET_POS_SET, K_VERS_1_7, modulename, _archiveHandle::offSize, pgoff_t, _archiveHandle::ReadBytePtr, ReadInt(), and _archiveHandle::version.
Referenced by _ReadExtraToc().
{ int i; int off; int offsetFlg; /* Initialize to zero */ *o = 0; /* Check for old version */ if (AH->version < K_VERS_1_7) { /* Prior versions wrote offsets using WriteInt */ i = ReadInt(AH); /* -1 means not set */ if (i < 0) return K_OFFSET_POS_NOT_SET; else if (i == 0) return K_OFFSET_NO_DATA; /* Cast to pgoff_t because it was written as an int. */ *o = (pgoff_t) i; return K_OFFSET_POS_SET; } /* * Read the flag indicating the state of the data pointer. Check if valid * and die if not. * * This used to be handled by a negative or zero pointer, now we use an * extra byte specifically for the state. */ offsetFlg = (*AH->ReadBytePtr) (AH) & 0xFF; switch (offsetFlg) { case K_OFFSET_POS_NOT_SET: case K_OFFSET_NO_DATA: case K_OFFSET_POS_SET: break; default: exit_horribly(modulename, "unexpected data offset flag %d\n", offsetFlg); } /* * Read the bytes */ for (off = 0; off < AH->offSize; off++) { if (off < sizeof(pgoff_t)) *o |= ((pgoff_t) ((*AH->ReadBytePtr) (AH))) << (off * 8); else { if ((*AH->ReadBytePtr) (AH) != 0) exit_horribly(modulename, "file offset in dump file is too large\n"); } } return offsetFlg; }
char* ReadStr | ( | ArchiveHandle * | AH | ) |
Definition at line 1776 of file pg_backup_archiver.c.
References buf, exit_horribly(), modulename, pg_malloc(), _archiveHandle::ReadBufPtr, and ReadInt().
Referenced by _ReadExtraToc(), ReadHead(), and ReadToc().
{ char *buf; int l; l = ReadInt(AH); if (l < 0) buf = NULL; else { buf = (char *) pg_malloc(l + 1); if ((*AH->ReadBufPtr) (AH, (void *) buf, l) != l) exit_horribly(modulename, "unexpected end of file\n"); buf[l] = '\0'; } return buf; }
void ReadToc | ( | ArchiveHandle * | AH | ) |
Definition at line 2217 of file pg_backup_archiver.c.
References ahlog(), _tocEntry::catalogId, _tocEntry::copyStmt, _tocEntry::defn, _tocEntry::dependencies, _tocEntry::desc, _tocEntry::dropStmt, _tocEntry::dumpId, exit_horribly(), free, _tocEntry::hadDumper, i, K_VERS_1_10, K_VERS_1_11, K_VERS_1_3, K_VERS_1_5, K_VERS_1_6, K_VERS_1_8, K_VERS_1_9, _archiveHandle::maxDumpId, modulename, _tocEntry::nDeps, _tocEntry::next, CatalogId::oid, _tocEntry::owner, pg_malloc(), pg_malloc0(), pg_realloc(), _tocEntry::prev, processEncodingEntry(), processStdStringsEntry(), _archiveHandle::ReadExtraTocPtr, ReadInt(), ReadStr(), _tocEntry::section, CatalogId::tableoid, _tocEntry::tablespace, _tocEntry::tag, _archiveHandle::toc, _archiveHandle::tocCount, _archiveHandle::version, and _tocEntry::withOids.
Referenced by InitArchiveFmt_Custom(), InitArchiveFmt_Directory(), and InitArchiveFmt_Tar().
{ int i; char *tmp; DumpId *deps; int depIdx; int depSize; TocEntry *te; AH->tocCount = ReadInt(AH); AH->maxDumpId = 0; for (i = 0; i < AH->tocCount; i++) { te = (TocEntry *) pg_malloc0(sizeof(TocEntry)); te->dumpId = ReadInt(AH); if (te->dumpId > AH->maxDumpId) AH->maxDumpId = te->dumpId; /* Sanity check */ if (te->dumpId <= 0) exit_horribly(modulename, "entry ID %d out of range -- perhaps a corrupt TOC\n", te->dumpId); te->hadDumper = ReadInt(AH); if (AH->version >= K_VERS_1_8) { tmp = ReadStr(AH); sscanf(tmp, "%u", &te->catalogId.tableoid); free(tmp); } else te->catalogId.tableoid = InvalidOid; tmp = ReadStr(AH); sscanf(tmp, "%u", &te->catalogId.oid); free(tmp); te->tag = ReadStr(AH); te->desc = ReadStr(AH); if (AH->version >= K_VERS_1_11) { te->section = ReadInt(AH); } else { /* * Rules for pre-8.4 archives wherein pg_dump hasn't classified * the entries into sections. This list need not cover entry * types added later than 8.4. */ if (strcmp(te->desc, "COMMENT") == 0 || strcmp(te->desc, "ACL") == 0 || strcmp(te->desc, "ACL LANGUAGE") == 0) te->section = SECTION_NONE; else if (strcmp(te->desc, "TABLE DATA") == 0 || strcmp(te->desc, "BLOBS") == 0 || strcmp(te->desc, "BLOB COMMENTS") == 0) te->section = SECTION_DATA; else if (strcmp(te->desc, "CONSTRAINT") == 0 || strcmp(te->desc, "CHECK CONSTRAINT") == 0 || strcmp(te->desc, "FK CONSTRAINT") == 0 || strcmp(te->desc, "INDEX") == 0 || strcmp(te->desc, "RULE") == 0 || strcmp(te->desc, "TRIGGER") == 0) te->section = SECTION_POST_DATA; else te->section = SECTION_PRE_DATA; } te->defn = ReadStr(AH); te->dropStmt = ReadStr(AH); if (AH->version >= K_VERS_1_3) te->copyStmt = ReadStr(AH); if (AH->version >= K_VERS_1_6) te->namespace = ReadStr(AH); if (AH->version >= K_VERS_1_10) te->tablespace = ReadStr(AH); te->owner = ReadStr(AH); if (AH->version >= K_VERS_1_9) { if (strcmp(ReadStr(AH), "true") == 0) te->withOids = true; else te->withOids = false; } else te->withOids = true; /* Read TOC entry dependencies */ if (AH->version >= K_VERS_1_5) { depSize = 100; deps = (DumpId *) pg_malloc(sizeof(DumpId) * depSize); depIdx = 0; for (;;) { tmp = ReadStr(AH); if (!tmp) break; /* end of list */ if (depIdx >= depSize) { depSize *= 2; deps = (DumpId *) pg_realloc(deps, sizeof(DumpId) * depSize); } sscanf(tmp, "%d", &deps[depIdx]); free(tmp); depIdx++; } if (depIdx > 0) /* We have a non-null entry */ { deps = (DumpId *) pg_realloc(deps, sizeof(DumpId) * depIdx); te->dependencies = deps; te->nDeps = depIdx; } else { free(deps); te->dependencies = NULL; te->nDeps = 0; } } else { te->dependencies = NULL; te->nDeps = 0; } if (AH->ReadExtraTocPtr) (*AH->ReadExtraTocPtr) (AH, te); ahlog(AH, 3, "read TOC entry %d (ID %d) for %s %s\n", i, te->dumpId, te->desc, te->tag); /* link completed entry into TOC circular list */ te->prev = AH->toc->prev; AH->toc->prev->next = te; AH->toc->prev = te; te->next = AH->toc; /* special processing immediately upon read for some items */ if (strcmp(te->desc, "ENCODING") == 0) processEncodingEntry(AH, te); else if (strcmp(te->desc, "STDSTRINGS") == 0) processStdStringsEntry(AH, te); } }
static void reduce_dependencies | ( | ArchiveHandle * | AH, | |
TocEntry * | te, | |||
TocEntry * | ready_list | |||
) | [static] |
Definition at line 4093 of file pg_backup_archiver.c.
References ahlog(), _tocEntry::depCount, _tocEntry::dumpId, i, _tocEntry::nRevDeps, NULL, par_list_append(), par_list_remove(), _tocEntry::par_prev, _tocEntry::revDeps, and _archiveHandle::tocsByDumpId.
Referenced by mark_work_done(), restore_toc_entries_parallel(), and restore_toc_entries_prefork().
{ int i; ahlog(AH, 2, "reducing dependencies for %d\n", te->dumpId); for (i = 0; i < te->nRevDeps; i++) { TocEntry *otherte = AH->tocsByDumpId[te->revDeps[i]]; otherte->depCount--; if (otherte->depCount == 0 && otherte->par_prev != NULL) { /* It must be in the pending list, so remove it ... */ par_list_remove(otherte); /* ... and add to ready_list */ par_list_append(ready_list, otherte); } } }
static char * replace_line_endings | ( | const char * | str | ) | [static] |
Definition at line 3176 of file pg_backup_archiver.c.
References pg_strdup().
Referenced by _printTocEntry().
{ char *result; char *s; result = pg_strdup(str); for (s = result; *s != '\0'; s++) { if (*s == '\n' || *s == '\r') *s = ' '; } return result; }
static void repoint_table_dependencies | ( | ArchiveHandle * | AH | ) | [static] |
Definition at line 4011 of file pg_backup_archiver.c.
References ahlog(), _tocEntry::dependencies, _tocEntry::dumpId, i, _tocEntry::nDeps, _tocEntry::next, _tocEntry::section, SECTION_POST_DATA, _archiveHandle::tableDataId, and _archiveHandle::toc.
Referenced by fix_dependencies().
{ TocEntry *te; int i; DumpId olddep; for (te = AH->toc->next; te != AH->toc; te = te->next) { if (te->section != SECTION_POST_DATA) continue; for (i = 0; i < te->nDeps; i++) { olddep = te->dependencies[i]; if (olddep <= AH->maxDumpId && AH->tableDataId[olddep] != 0) { te->dependencies[i] = AH->tableDataId[olddep]; ahlog(AH, 2, "transferring dependency %d -> %d to %d\n", te->dumpId, olddep, AH->tableDataId[olddep]); } } } }
static void restore_toc_entries_parallel | ( | ArchiveHandle * | AH, | |
ParallelState * | pstate, | |||
TocEntry * | pending_list | |||
) | [static] |
Definition at line 3489 of file pg_backup_archiver.c.
References _tocEntryIsACL(), ACT_RESTORE, ahlog(), Assert, _tocEntry::depCount, _tocEntry::desc, DispatchJobForTocEntry(), _tocEntry::dumpId, get_next_work_item(), GetIdleWorker(), IsEveryWorkerIdle(), ListenToWorkers(), mark_work_done(), _tocEntry::next, NO_SLOT, NULL, par_list_append(), par_list_header_init(), par_list_remove(), ReapWorkerStatus(), reduce_dependencies(), REQ_DATA, REQ_SCHEMA, _tocEntry::reqs, _tocEntry::section, SECTION_DATA, SECTION_POST_DATA, SECTION_PRE_DATA, _tocEntry::tag, and _archiveHandle::toc.
Referenced by RestoreArchive().
{ int work_status; bool skipped_some; TocEntry ready_list; TocEntry *next_work_item; int ret_child; ahlog(AH, 2, "entering restore_toc_entries_parallel\n"); /* * Initialize the lists of ready items, the list for pending items has * already been initialized in the caller. After this setup, the pending * list is everything that needs to be done but is blocked by one or more * dependencies, while the ready list contains items that have no * remaining dependencies. Note: we don't yet filter out entries that * aren't going to be restored. They might participate in dependency * chains connecting entries that should be restored, so we treat them as * live until we actually process them. */ par_list_header_init(&ready_list); skipped_some = false; for (next_work_item = AH->toc->next; next_work_item != AH->toc; next_work_item = next_work_item->next) { /* NB: process-or-continue logic must be the inverse of loop above */ if (next_work_item->section == SECTION_PRE_DATA) { /* All PRE_DATA items were dealt with above */ continue; } if (next_work_item->section == SECTION_DATA || next_work_item->section == SECTION_POST_DATA) { /* set this flag at same point that previous loop did */ skipped_some = true; } else { /* SECTION_NONE items must be processed if previous loop didn't */ if (!skipped_some) continue; } if (next_work_item->depCount > 0) par_list_append(pending_list, next_work_item); else par_list_append(&ready_list, next_work_item); } /* * main parent loop * * Keep going until there is no worker still running AND there is no work * left to be done. */ ahlog(AH, 1, "entering main parallel loop\n"); while ((next_work_item = get_next_work_item(AH, &ready_list, pstate)) != NULL || !IsEveryWorkerIdle(pstate)) { if (next_work_item != NULL) { /* If not to be restored, don't waste time launching a worker */ if ((next_work_item->reqs & (REQ_SCHEMA | REQ_DATA)) == 0 || _tocEntryIsACL(next_work_item)) { ahlog(AH, 1, "skipping item %d %s %s\n", next_work_item->dumpId, next_work_item->desc, next_work_item->tag); par_list_remove(next_work_item); reduce_dependencies(AH, next_work_item, &ready_list); continue; } ahlog(AH, 1, "launching item %d %s %s\n", next_work_item->dumpId, next_work_item->desc, next_work_item->tag); par_list_remove(next_work_item); Assert(GetIdleWorker(pstate) != NO_SLOT); DispatchJobForTocEntry(AH, pstate, next_work_item, ACT_RESTORE); } else { /* at least one child is working and we have nothing ready. */ Assert(!IsEveryWorkerIdle(pstate)); } for (;;) { int nTerm = 0; /* * In order to reduce dependencies as soon as possible and * especially to reap the status of workers who are working on * items that pending items depend on, we do a non-blocking check * for ended workers first. * * However, if we do not have any other work items currently that * workers can work on, we do not busy-loop here but instead * really wait for at least one worker to terminate. Hence we call * ListenToWorkers(..., ..., do_wait = true) in this case. */ ListenToWorkers(AH, pstate, !next_work_item); while ((ret_child = ReapWorkerStatus(pstate, &work_status)) != NO_SLOT) { nTerm++; mark_work_done(AH, &ready_list, ret_child, work_status, pstate); } /* * We need to make sure that we have an idle worker before * re-running the loop. If nTerm > 0 we already have that (quick * check). */ if (nTerm > 0) break; /* if nobody terminated, explicitly check for an idle worker */ if (GetIdleWorker(pstate) != NO_SLOT) break; /* * If we have no idle worker, read the result of one or more * workers and loop the loop to call ReapWorkerStatus() on them. */ ListenToWorkers(AH, pstate, true); } } ahlog(AH, 1, "finished main parallel loop\n"); }
static void restore_toc_entries_postfork | ( | ArchiveHandle * | AH, | |
TocEntry * | pending_list | |||
) | [static] |
Definition at line 3629 of file pg_backup_archiver.c.
References _doSetFixedOutputState(), ahlog(), ConnectDatabase(), _restoreOptions::dbname, _tocEntry::desc, _tocEntry::dumpId, _tocEntry::par_next, _restoreOptions::pghost, _restoreOptions::pgport, _restoreOptions::promptPassword, restore_toc_entry(), _archiveHandle::ropt, _tocEntry::tag, and _restoreOptions::username.
Referenced by RestoreArchive().
{ RestoreOptions *ropt = AH->ropt; TocEntry *te; ahlog(AH, 2, "entering restore_toc_entries_postfork\n"); /* * Now reconnect the single parent connection. */ ConnectDatabase((Archive *) AH, ropt->dbname, ropt->pghost, ropt->pgport, ropt->username, ropt->promptPassword); _doSetFixedOutputState(AH); /* * Make sure there is no non-ACL work left due to, say, circular * dependencies, or some other pathological condition. If so, do it in the * single parent connection. */ for (te = pending_list->par_next; te != pending_list; te = te->par_next) { ahlog(AH, 1, "processing missed item %d %s %s\n", te->dumpId, te->desc, te->tag); (void) restore_toc_entry(AH, te, ropt, false); } /* The ACLs will be handled back in RestoreArchive. */ }
static void restore_toc_entries_prefork | ( | ArchiveHandle * | AH | ) | [static] |
Definition at line 3396 of file pg_backup_archiver.c.
References ahlog(), _archiveHandle::currSchema, _archiveHandle::currTablespace, _archiveHandle::currUser, _archiveHandle::currWithOids, _tocEntry::desc, DisconnectDatabase(), _tocEntry::dumpId, fix_dependencies(), free, _tocEntry::next, NULL, _archiveHandle::public, reduce_dependencies(), restore_toc_entry(), _archiveHandle::ropt, _tocEntry::section, SECTION_DATA, SECTION_POST_DATA, SECTION_PRE_DATA, _tocEntry::tag, and _archiveHandle::toc.
Referenced by RestoreArchive().
{ RestoreOptions *ropt = AH->ropt; bool skipped_some; TocEntry *next_work_item; ahlog(AH, 2, "entering restore_toc_entries_prefork\n"); /* Adjust dependency information */ fix_dependencies(AH); /* * Do all the early stuff in a single connection in the parent. There's no * great point in running it in parallel, in fact it will actually run * faster in a single connection because we avoid all the connection and * setup overhead. Also, pre-9.2 pg_dump versions were not very good * about showing all the dependencies of SECTION_PRE_DATA items, so we do * not risk trying to process them out-of-order. * * Note: as of 9.2, it should be guaranteed that all PRE_DATA items appear * before DATA items, and all DATA items before POST_DATA items. That is * not certain to be true in older archives, though, so this loop is coded * to not assume it. */ skipped_some = false; for (next_work_item = AH->toc->next; next_work_item != AH->toc; next_work_item = next_work_item->next) { /* NB: process-or-continue logic must be the inverse of loop below */ if (next_work_item->section != SECTION_PRE_DATA) { /* DATA and POST_DATA items are just ignored for now */ if (next_work_item->section == SECTION_DATA || next_work_item->section == SECTION_POST_DATA) { skipped_some = true; continue; } else { /* * SECTION_NONE items, such as comments, can be processed now * if we are still in the PRE_DATA part of the archive. Once * we've skipped any items, we have to consider whether the * comment's dependencies are satisfied, so skip it for now. */ if (skipped_some) continue; } } ahlog(AH, 1, "processing item %d %s %s\n", next_work_item->dumpId, next_work_item->desc, next_work_item->tag); (void) restore_toc_entry(AH, next_work_item, ropt, false); /* there should be no touch of ready_list here, so pass NULL */ reduce_dependencies(AH, next_work_item, NULL); } /* * Now close parent connection in prep for parallel steps. We do this * mainly to ensure that we don't exceed the specified number of parallel * connections. */ DisconnectDatabase(&AH->public); /* blow away any transient state from the old connection */ if (AH->currUser) free(AH->currUser); AH->currUser = NULL; if (AH->currSchema) free(AH->currSchema); AH->currSchema = NULL; if (AH->currTablespace) free(AH->currTablespace); AH->currTablespace = NULL; AH->currWithOids = -1; }
static int restore_toc_entry | ( | ArchiveHandle * | AH, | |
TocEntry * | te, | |||
RestoreOptions * | ropt, | |||
bool | is_parallel | |||
) | [static] |
Definition at line 514 of file pg_backup_archiver.c.
References _becomeOwner(), _disableTriggersIfNecessary(), _enableTriggersIfNecessary(), _printTocEntry(), _reconnectToDB(), _selectOutputSchema(), _tocEntryIsACL(), ahlog(), ahprintf(), CommitTransaction(), _archiveHandle::connection, _tocEntry::copyStmt, _tocEntry::created, _restoreOptions::createDB, _archiveHandle::currentTE, _restoreOptions::dataOnly, _restoreOptions::dbname, _tocEntry::defn, _tocEntry::desc, EndDBCopyMode(), fmtId(), _tocEntry::hadDumper, inhibit_data_for_failed_table(), _archiveHandle::lastErrorTE, mark_create_done(), modulename, Archive::n_errors, _restoreOptions::noDataForFailedTables, NULL, OUTPUT_COPYDATA, _archiveHandle::outputKind, pg_strdup(), PQserverVersion(), _archiveHandle::PrintTocDataPtr, _archiveHandle::public, REQ_DATA, REQ_SCHEMA, _tocEntry::reqs, RestoringToDB(), StartTransaction(), status(), _restoreOptions::suppressDumpWarnings, _tocEntry::tag, WORKER_OK, and write_msg().
Referenced by parallel_restore(), restore_toc_entries_postfork(), restore_toc_entries_prefork(), and RestoreArchive().
{ int status = WORKER_OK; teReqs reqs; bool defnDumped; AH->currentTE = te; /* Work out what, if anything, we want from this entry */ if (_tocEntryIsACL(te)) reqs = 0; /* ACLs are never restored here */ else reqs = te->reqs; /* * Ignore DATABASE entry unless we should create it. We must check this * here, not in _tocEntryRequired, because the createDB option should not * affect emitting a DATABASE entry to an archive file. */ if (!ropt->createDB && strcmp(te->desc, "DATABASE") == 0) reqs = 0; /* Dump any relevant dump warnings to stderr */ if (!ropt->suppressDumpWarnings && strcmp(te->desc, "WARNING") == 0) { if (!ropt->dataOnly && te->defn != NULL && strlen(te->defn) != 0) write_msg(modulename, "warning from original dump file: %s\n", te->defn); else if (te->copyStmt != NULL && strlen(te->copyStmt) != 0) write_msg(modulename, "warning from original dump file: %s\n", te->copyStmt); } defnDumped = false; if ((reqs & REQ_SCHEMA) != 0) /* We want the schema */ { ahlog(AH, 1, "creating %s %s\n", te->desc, te->tag); _printTocEntry(AH, te, ropt, false, false); defnDumped = true; if (strcmp(te->desc, "TABLE") == 0) { if (AH->lastErrorTE == te) { /* * We failed to create the table. If * --no-data-for-failed-tables was given, mark the * corresponding TABLE DATA to be ignored. * * In the parallel case this must be done in the parent, so we * just set the return value. */ if (ropt->noDataForFailedTables) { if (is_parallel) status = WORKER_INHIBIT_DATA; else inhibit_data_for_failed_table(AH, te); } } else { /* * We created the table successfully. Mark the corresponding * TABLE DATA for possible truncation. * * In the parallel case this must be done in the parent, so we * just set the return value. */ if (is_parallel) status = WORKER_CREATE_DONE; else mark_create_done(AH, te); } } /* If we created a DB, connect to it... */ if (strcmp(te->desc, "DATABASE") == 0) { ahlog(AH, 1, "connecting to new database \"%s\"\n", te->tag); _reconnectToDB(AH, te->tag); ropt->dbname = pg_strdup(te->tag); } } /* * If we have a data component, then process it */ if ((reqs & REQ_DATA) != 0) { /* * hadDumper will be set if there is genuine data component for this * node. Otherwise, we need to check the defn field for statements * that need to be executed in data-only restores. */ if (te->hadDumper) { /* * If we can output the data, then restore it. */ if (AH->PrintTocDataPtr !=NULL) { _printTocEntry(AH, te, ropt, true, false); if (strcmp(te->desc, "BLOBS") == 0 || strcmp(te->desc, "BLOB COMMENTS") == 0) { ahlog(AH, 1, "processing %s\n", te->desc); _selectOutputSchema(AH, "pg_catalog"); (*AH->PrintTocDataPtr) (AH, te, ropt); } else { _disableTriggersIfNecessary(AH, te, ropt); /* Select owner and schema as necessary */ _becomeOwner(AH, te); _selectOutputSchema(AH, te->namespace); ahlog(AH, 1, "processing data for table \"%s\"\n", te->tag); /* * In parallel restore, if we created the table earlier in * the run then we wrap the COPY in a transaction and * precede it with a TRUNCATE. If archiving is not on * this prevents WAL-logging the COPY. This obtains a * speedup similar to that from using single_txn mode in * non-parallel restores. */ if (is_parallel && te->created) { /* * Parallel restore is always talking directly to a * server, so no need to see if we should issue BEGIN. */ StartTransaction(AH); /* * If the server version is >= 8.4, make sure we issue * TRUNCATE with ONLY so that child tables are not * wiped. */ ahprintf(AH, "TRUNCATE TABLE %s%s;\n\n", (PQserverVersion(AH->connection) >= 80400 ? "ONLY " : ""), fmtId(te->tag)); } /* * If we have a copy statement, use it. */ if (te->copyStmt && strlen(te->copyStmt) > 0) { ahprintf(AH, "%s", te->copyStmt); AH->outputKind = OUTPUT_COPYDATA; } else AH->outputKind = OUTPUT_OTHERDATA; (*AH->PrintTocDataPtr) (AH, te, ropt); /* * Terminate COPY if needed. */ if (AH->outputKind == OUTPUT_COPYDATA && RestoringToDB(AH)) EndDBCopyMode(AH, te); AH->outputKind = OUTPUT_SQLCMDS; /* close out the transaction started above */ if (is_parallel && te->created) CommitTransaction(AH); _enableTriggersIfNecessary(AH, te, ropt); } } } else if (!defnDumped) { /* If we haven't already dumped the defn part, do so now */ ahlog(AH, 1, "executing %s %s\n", te->desc, te->tag); _printTocEntry(AH, te, ropt, false, false); } } if (AH->public.n_errors > 0 && status == WORKER_OK) status = WORKER_IGNORED_ERRORS; return status; }
void RestoreArchive | ( | Archive * | AHX | ) |
Definition at line 230 of file pg_backup_archiver.c.
References _becomeOwner(), _doSetFixedOutputState(), _printTocEntry(), _selectOutputSchema(), ahlog(), ahprintf(), _archiveHandle::archiveDumpVersion, _archiveHandle::archiveRemoteVersion, Assert, buildTocEntryArrays(), _archiveHandle::ClonePtr, CommitTransaction(), _restoreOptions::compression, _archiveHandle::compression, ConnectDatabase(), _archiveHandle::connection, _archiveHandle::createDate, _restoreOptions::createDB, _archiveHandle::currentTE, _archiveHandle::currSchema, _restoreOptions::dataOnly, _restoreOptions::dbname, _tocEntry::desc, DisconnectDatabase(), _restoreOptions::dropSchema, _tocEntry::dropStmt, dumpTimestamp(), exit_horribly(), _restoreOptions::filename, free, _tocEntry::hadDumper, K_VERS_1_3, K_VERS_1_8, Archive::maxRemoteVersion, Archive::minRemoteVersion, modulename, _tocEntry::next, _archiveHandle::noTocComments, NULL, Archive::numWorkers, par_list_header_init(), ParallelBackupEnd(), ParallelBackupStart(), _restoreOptions::pghost, _restoreOptions::pgport, _tocEntry::prev, _archiveHandle::PrintTocDataPtr, _restoreOptions::promptPassword, _archiveHandle::public, _archiveHandle::ReopenPtr, REQ_DATA, REQ_SCHEMA, _tocEntry::reqs, restore_toc_entries_parallel(), restore_toc_entries_postfork(), restore_toc_entries_prefork(), restore_toc_entry(), RestoreOutput(), _archiveHandle::ropt, SaveOutput(), SetOutput(), _restoreOptions::single_txn, _archiveHandle::stage, StartTransaction(), _tocEntry::tag, _archiveHandle::toc, _archiveHandle::tocsByDumpId, _restoreOptions::useDB, _restoreOptions::username, Archive::verbose, and _archiveHandle::version.
Referenced by _CloseArchive(), and main().
{ ArchiveHandle *AH = (ArchiveHandle *) AHX; RestoreOptions *ropt = AH->ropt; bool parallel_mode; TocEntry *te; OutputContext sav; AH->stage = STAGE_INITIALIZING; /* * Check for nonsensical option combinations. * * -C is not compatible with -1, because we can't create a database inside * a transaction block. */ if (ropt->createDB && ropt->single_txn) exit_horribly(modulename, "-C and -1 are incompatible options\n"); /* * If we're going to do parallel restore, there are some restrictions. */ parallel_mode = (AH->public.numWorkers > 1 && ropt->useDB); if (parallel_mode) { /* We haven't got round to making this work for all archive formats */ if (AH->ClonePtr == NULL || AH->ReopenPtr == NULL) exit_horribly(modulename, "parallel restore is not supported with this archive file format\n"); /* Doesn't work if the archive represents dependencies as OIDs */ if (AH->version < K_VERS_1_8) exit_horribly(modulename, "parallel restore is not supported with archives made by pre-8.0 pg_dump\n"); /* * It's also not gonna work if we can't reopen the input file, so * let's try that immediately. */ (AH->ReopenPtr) (AH); } /* * Make sure we won't need (de)compression we haven't got */ #ifndef HAVE_LIBZ if (AH->compression != 0 && AH->PrintTocDataPtr !=NULL) { for (te = AH->toc->next; te != AH->toc; te = te->next) { if (te->hadDumper && (te->reqs & REQ_DATA) != 0) exit_horribly(modulename, "cannot restore from compressed archive (compression not supported in this installation)\n"); } } #endif /* * Prepare index arrays, so we can assume we have them throughout restore. * It's possible we already did this, though. */ if (AH->tocsByDumpId == NULL) buildTocEntryArrays(AH); /* * If we're using a DB connection, then connect it. */ if (ropt->useDB) { ahlog(AH, 1, "connecting to database for restore\n"); if (AH->version < K_VERS_1_3) exit_horribly(modulename, "direct database connections are not supported in pre-1.3 archives\n"); /* XXX Should get this from the archive */ AHX->minRemoteVersion = 070100; AHX->maxRemoteVersion = 999999; ConnectDatabase(AHX, ropt->dbname, ropt->pghost, ropt->pgport, ropt->username, ropt->promptPassword); /* * If we're talking to the DB directly, don't send comments since they * obscure SQL when displaying errors */ AH->noTocComments = 1; } /* * Work out if we have an implied data-only restore. This can happen if * the dump was data only or if the user has used a toc list to exclude * all of the schema data. All we do is look for schema entries - if none * are found then we set the dataOnly flag. * * We could scan for wanted TABLE entries, but that is not the same as * dataOnly. At this stage, it seems unnecessary (6-Mar-2001). */ if (!ropt->dataOnly) { int impliedDataOnly = 1; for (te = AH->toc->next; te != AH->toc; te = te->next) { if ((te->reqs & REQ_SCHEMA) != 0) { /* It's schema, and it's wanted */ impliedDataOnly = 0; break; } } if (impliedDataOnly) { ropt->dataOnly = impliedDataOnly; ahlog(AH, 1, "implied data-only restore\n"); } } /* * Setup the output file if necessary. */ sav = SaveOutput(AH); if (ropt->filename || ropt->compression) SetOutput(AH, ropt->filename, ropt->compression); ahprintf(AH, "--\n-- PostgreSQL database dump\n--\n\n"); if (AH->public.verbose) { if (AH->archiveRemoteVersion) ahprintf(AH, "-- Dumped from database version %s\n", AH->archiveRemoteVersion); if (AH->archiveDumpVersion) ahprintf(AH, "-- Dumped by pg_dump version %s\n", AH->archiveDumpVersion); dumpTimestamp(AH, "Started on", AH->createDate); } if (ropt->single_txn) { if (AH->connection) StartTransaction(AH); else ahprintf(AH, "BEGIN;\n\n"); } /* * Establish important parameter values right away. */ _doSetFixedOutputState(AH); AH->stage = STAGE_PROCESSING; /* * Drop the items at the start, in reverse order */ if (ropt->dropSchema) { for (te = AH->toc->prev; te != AH->toc; te = te->prev) { AH->currentTE = te; /* * In createDB mode, issue a DROP *only* for the database as a * whole. Issuing drops against anything else would be wrong, * because at this point we're connected to the wrong database. * Conversely, if we're not in createDB mode, we'd better not * issue a DROP against the database at all. */ if (ropt->createDB) { if (strcmp(te->desc, "DATABASE") != 0) continue; } else { if (strcmp(te->desc, "DATABASE") == 0) continue; } /* Otherwise, drop anything that's selected and has a dropStmt */ if (((te->reqs & (REQ_SCHEMA | REQ_DATA)) != 0) && te->dropStmt) { ahlog(AH, 1, "dropping %s %s\n", te->desc, te->tag); /* Select owner and schema as necessary */ _becomeOwner(AH, te); _selectOutputSchema(AH, te->namespace); /* Drop it */ ahprintf(AH, "%s", te->dropStmt); } } /* * _selectOutputSchema may have set currSchema to reflect the effect * of a "SET search_path" command it emitted. However, by now we may * have dropped that schema; or it might not have existed in the first * place. In either case the effective value of search_path will not * be what we think. Forcibly reset currSchema so that we will * re-establish the search_path setting when needed (after creating * the schema). * * If we treated users as pg_dump'able objects then we'd need to reset * currUser here too. */ if (AH->currSchema) free(AH->currSchema); AH->currSchema = NULL; } /* * In serial mode, we now process each non-ACL TOC entry. * * In parallel mode, turn control over to the parallel-restore logic. */ if (parallel_mode) { ParallelState *pstate; TocEntry pending_list; par_list_header_init(&pending_list); /* This runs PRE_DATA items and then disconnects from the database */ restore_toc_entries_prefork(AH); Assert(AH->connection == NULL); /* ParallelBackupStart() will actually fork the processes */ pstate = ParallelBackupStart(AH, ropt); restore_toc_entries_parallel(AH, pstate, &pending_list); ParallelBackupEnd(AH, pstate); /* reconnect the master and see if we missed something */ restore_toc_entries_postfork(AH, &pending_list); Assert(AH->connection != NULL); } else { for (te = AH->toc->next; te != AH->toc; te = te->next) (void) restore_toc_entry(AH, te, ropt, false); } /* * Scan TOC again to output ownership commands and ACLs */ for (te = AH->toc->next; te != AH->toc; te = te->next) { AH->currentTE = te; /* Both schema and data objects might now have ownership/ACLs */ if ((te->reqs & (REQ_SCHEMA | REQ_DATA)) != 0) { ahlog(AH, 1, "setting owner and privileges for %s %s\n", te->desc, te->tag); _printTocEntry(AH, te, ropt, false, true); } } if (ropt->single_txn) { if (AH->connection) CommitTransaction(AH); else ahprintf(AH, "COMMIT;\n\n"); } if (AH->public.verbose) dumpTimestamp(AH, "Completed on", time(NULL)); ahprintf(AH, "--\n-- PostgreSQL database dump complete\n--\n\n"); /* * Clean up & we're done. */ AH->stage = STAGE_FINALIZING; if (ropt->filename || ropt->compression) RestoreOutput(AH, sav); if (ropt->useDB) DisconnectDatabase(&AH->public); }
static void RestoreOutput | ( | ArchiveHandle * | AH, | |
OutputContext | savedContext | |||
) | [static] |
Definition at line 1287 of file pg_backup_archiver.c.
References exit_horribly(), GZCLOSE, _outputContext::gzOut, _archiveHandle::gzOut, modulename, _outputContext::OF, _archiveHandle::OF, and strerror().
Referenced by PrintTOCSummary(), and RestoreArchive().
static int RestoringToDB | ( | ArchiveHandle * | AH | ) | [static] |
Definition at line 1354 of file pg_backup_archiver.c.
References _archiveHandle::connection, _archiveHandle::ropt, and _restoreOptions::useDB.
Referenced by _doSetSessionAuth(), _doSetWithOids(), _reconnectToDB(), _selectOutputSchema(), _selectTablespace(), ahwrite(), and restore_toc_entry().
{ return (AH->ropt && AH->ropt->useDB && AH->connection); }
static OutputContext SaveOutput | ( | ArchiveHandle * | AH | ) | [static] |
Definition at line 1276 of file pg_backup_archiver.c.
References _archiveHandle::gzOut, _outputContext::gzOut, _archiveHandle::OF, and _outputContext::OF.
Referenced by PrintTOCSummary(), and RestoreArchive().
{ OutputContext sav; sav.OF = AH->OF; sav.gzOut = AH->gzOut; return sav; }
void SetArchiveRestoreOptions | ( | Archive * | AHX, | |
RestoreOptions * | ropt | |||
) |
Definition at line 175 of file pg_backup_archiver.c.
References _tocEntryRequired(), archModeRead, exit_horribly(), _archiveHandle::mode, modulename, _tocEntry::next, _tocEntry::reqs, _archiveHandle::ropt, _tocEntry::section, SECTION_DATA, SECTION_NONE, SECTION_POST_DATA, SECTION_PRE_DATA, _archiveHandle::toc, and write_msg().
Referenced by main().
{ ArchiveHandle *AH = (ArchiveHandle *) AHX; TocEntry *te; teSection curSection; /* Save options for later access */ AH->ropt = ropt; /* Decide which TOC entries will be dumped/restored, and mark them */ curSection = SECTION_PRE_DATA; for (te = AH->toc->next; te != AH->toc; te = te->next) { /* * When writing an archive, we also take this opportunity to check * that we have generated the entries in a sane order that respects * the section divisions. When reading, don't complain, since buggy * old versions of pg_dump might generate out-of-order archives. */ if (AH->mode != archModeRead) { switch (te->section) { case SECTION_NONE: /* ok to be anywhere */ break; case SECTION_PRE_DATA: if (curSection != SECTION_PRE_DATA) write_msg(modulename, "WARNING: archive items not in correct section order\n"); break; case SECTION_DATA: if (curSection == SECTION_POST_DATA) write_msg(modulename, "WARNING: archive items not in correct section order\n"); break; case SECTION_POST_DATA: /* ok no matter which section we were in */ break; default: exit_horribly(modulename, "unexpected section code %d\n", (int) te->section); break; } } if (te->section != SECTION_NONE) curSection = te->section; te->reqs = _tocEntryRequired(te, curSection, ropt); } }
static void SetOutput | ( | ArchiveHandle * | AH, | |
const char * | filename, | |||
int | compression | |||
) | [static] |
Definition at line 1214 of file pg_backup_archiver.c.
References archModeAppend, exit_horribly(), _archiveHandle::FH, _archiveHandle::fSpec, _archiveHandle::gzOut, _archiveHandle::mode, modulename, _archiveHandle::OF, PG_BINARY_A, PG_BINARY_W, and strerror().
Referenced by PrintTOCSummary(), and RestoreArchive().
{ int fn; if (filename) fn = -1; else if (AH->FH) fn = fileno(AH->FH); else if (AH->fSpec) { fn = -1; filename = AH->fSpec; } else fn = fileno(stdout); /* If compression explicitly requested, use gzopen */ #ifdef HAVE_LIBZ if (compression != 0) { char fmode[10]; /* Don't use PG_BINARY_x since this is zlib */ sprintf(fmode, "wb%d", compression); if (fn >= 0) AH->OF = gzdopen(dup(fn), fmode); else AH->OF = gzopen(filename, fmode); AH->gzOut = 1; } else #endif { /* Use fopen */ if (AH->mode == archModeAppend) { if (fn >= 0) AH->OF = fdopen(dup(fn), PG_BINARY_A); else AH->OF = fopen(filename, PG_BINARY_A); } else { if (fn >= 0) AH->OF = fdopen(dup(fn), PG_BINARY_W); else AH->OF = fopen(filename, PG_BINARY_W); } AH->gzOut = 0; } if (!AH->OF) { if (filename) exit_horribly(modulename, "could not open output file \"%s\": %s\n", filename, strerror(errno)); else exit_horribly(modulename, "could not open output file: %s\n", strerror(errno)); } }
static void setupRestoreWorker | ( | Archive * | AHX, | |
RestoreOptions * | ropt | |||
) | [static] |
Definition at line 123 of file pg_backup_archiver.c.
References _archiveHandle::ReopenPtr.
Referenced by OpenArchive().
{ ArchiveHandle *AH = (ArchiveHandle *) AHX; (AH->ReopenPtr) (AH); }
void SortTocFromFile | ( | Archive * | AHX, | |
RestoreOptions * | ropt | |||
) |
Definition at line 1080 of file pg_backup_archiver.c.
References _moveBefore(), buf, exit_horribly(), getTocEntryByDumpId(), _restoreOptions::idWanted, _archiveHandle::maxDumpId, modulename, NULL, PG_BINARY_R, pg_malloc(), strerror(), _archiveHandle::toc, _restoreOptions::tocFile, and write_msg().
Referenced by main().
{ ArchiveHandle *AH = (ArchiveHandle *) AHX; FILE *fh; char buf[100]; bool incomplete_line; /* Allocate space for the 'wanted' array, and init it */ ropt->idWanted = (bool *) pg_malloc(sizeof(bool) * AH->maxDumpId); memset(ropt->idWanted, 0, sizeof(bool) * AH->maxDumpId); /* Setup the file */ fh = fopen(ropt->tocFile, PG_BINARY_R); if (!fh) exit_horribly(modulename, "could not open TOC file \"%s\": %s\n", ropt->tocFile, strerror(errno)); incomplete_line = false; while (fgets(buf, sizeof(buf), fh) != NULL) { bool prev_incomplete_line = incomplete_line; int buflen; char *cmnt; char *endptr; DumpId id; TocEntry *te; /* * Some lines in the file might be longer than sizeof(buf). This is * no problem, since we only care about the leading numeric ID which * can be at most a few characters; but we have to skip continuation * bufferloads when processing a long line. */ buflen = strlen(buf); if (buflen > 0 && buf[buflen - 1] == '\n') incomplete_line = false; else incomplete_line = true; if (prev_incomplete_line) continue; /* Truncate line at comment, if any */ cmnt = strchr(buf, ';'); if (cmnt != NULL) cmnt[0] = '\0'; /* Ignore if all blank */ if (strspn(buf, " \t\r\n") == strlen(buf)) continue; /* Get an ID, check it's valid and not already seen */ id = strtol(buf, &endptr, 10); if (endptr == buf || id <= 0 || id > AH->maxDumpId || ropt->idWanted[id - 1]) { write_msg(modulename, "WARNING: line ignored: %s\n", buf); continue; } /* Find TOC entry */ te = getTocEntryByDumpId(AH, id); if (!te) exit_horribly(modulename, "could not find entry for ID %d\n", id); /* Mark it wanted */ ropt->idWanted[id - 1] = true; /* * Move each item to the end of the list as it is selected, so that * they are placed in the desired order. Any unwanted items will end * up at the front of the list, which may seem unintuitive but it's * what we need. In an ordinary serial restore that makes no * difference, but in a parallel restore we need to mark unrestored * items' dependencies as satisfied before we start examining * restorable items. Otherwise they could have surprising * side-effects on the order in which restorable items actually get * restored. */ _moveBefore(AH, AH->toc, te); } if (fclose(fh) != 0) exit_horribly(modulename, "could not close TOC file: %s\n", strerror(errno)); }
Definition at line 940 of file pg_backup_archiver.c.
References _archiveHandle::currToc, exit_horribly(), modulename, and _archiveHandle::StartBlobPtr.
Referenced by dumpBlobs().
{ ArchiveHandle *AH = (ArchiveHandle *) AHX; if (!AH->StartBlobPtr) exit_horribly(modulename, "large-object output not supported in chosen format\n"); (*AH->StartBlobPtr) (AH, AH->currToc, oid); return 1; }
void StartRestoreBlob | ( | ArchiveHandle * | AH, | |
Oid | oid, | |||
bool | drop | |||
) |
Definition at line 1010 of file pg_backup_archiver.c.
References ahlog(), ahprintf(), _archiveHandle::blobCount, _archiveHandle::connection, DropBlobIfExists(), exit_horribly(), INV_WRITE, _archiveHandle::lo_buf_used, lo_create(), lo_open(), _archiveHandle::loFd, modulename, PQerrorMessage(), _archiveHandle::version, and _archiveHandle::writingBlob.
Referenced by _LoadBlobs().
{ bool old_blob_style = (AH->version < K_VERS_1_12); Oid loOid; AH->blobCount++; /* Initialize the LO Buffer */ AH->lo_buf_used = 0; ahlog(AH, 1, "restoring large object with OID %u\n", oid); /* With an old archive we must do drop and create logic here */ if (old_blob_style && drop) DropBlobIfExists(AH, oid); if (AH->connection) { if (old_blob_style) { loOid = lo_create(AH->connection, oid); if (loOid == 0 || loOid != oid) exit_horribly(modulename, "could not create large object %u: %s", oid, PQerrorMessage(AH->connection)); } AH->loFd = lo_open(AH->connection, oid, INV_WRITE); if (AH->loFd == -1) exit_horribly(modulename, "could not open large object %u: %s", oid, PQerrorMessage(AH->connection)); } else { if (old_blob_style) ahprintf(AH, "SELECT pg_catalog.lo_open(pg_catalog.lo_create('%u'), %d);\n", oid, INV_WRITE); else ahprintf(AH, "SELECT pg_catalog.lo_open('%u', %d);\n", oid, INV_WRITE); } AH->writingBlob = 1; }
void StartRestoreBlobs | ( | ArchiveHandle * | AH | ) |
Definition at line 972 of file pg_backup_archiver.c.
References ahprintf(), _archiveHandle::blobCount, _archiveHandle::connection, _archiveHandle::ropt, _restoreOptions::single_txn, and StartTransaction().
Referenced by _LoadBlobs().
{ if (!AH->ropt->single_txn) { if (AH->connection) StartTransaction(AH); else ahprintf(AH, "BEGIN;\n\n"); } AH->blobCount = 0; }
teReqs TocIDRequired | ( | ArchiveHandle * | AH, | |
DumpId | id | |||
) |
Definition at line 1610 of file pg_backup_archiver.c.
References getTocEntryByDumpId(), and _tocEntry::reqs.
Referenced by _tarPositionTo(), and findDumpableDependencies().
{ TocEntry *te = getTocEntryByDumpId(AH, id); if (!te) return 0; return te->reqs; }
void warn_or_exit_horribly | ( | ArchiveHandle * | AH, | |
const char * | modulename, | |||
const char * | fmt, | |||
... | ||||
) |
Definition at line 1466 of file pg_backup_archiver.c.
References _tocEntry::catalogId, _archiveHandle::currentTE, _tocEntry::desc, _tocEntry::dumpId, exit_nicely, Archive::exit_on_error, _archiveHandle::lastErrorStage, _archiveHandle::lastErrorTE, Archive::n_errors, NULL, CatalogId::oid, _tocEntry::owner, _archiveHandle::public, _archiveHandle::stage, STAGE_FINALIZING, STAGE_INITIALIZING, STAGE_NONE, STAGE_PROCESSING, CatalogId::tableoid, _tocEntry::tag, vwrite_msg(), and write_msg().
Referenced by _doSetWithOids(), _selectOutputSchema(), _selectTablespace(), EndDBCopyMode(), and ExecuteSqlCommand().
{ va_list ap; switch (AH->stage) { case STAGE_NONE: /* Do nothing special */ break; case STAGE_INITIALIZING: if (AH->stage != AH->lastErrorStage) write_msg(modulename, "Error while INITIALIZING:\n"); break; case STAGE_PROCESSING: if (AH->stage != AH->lastErrorStage) write_msg(modulename, "Error while PROCESSING TOC:\n"); break; case STAGE_FINALIZING: if (AH->stage != AH->lastErrorStage) write_msg(modulename, "Error while FINALIZING:\n"); break; } if (AH->currentTE != NULL && AH->currentTE != AH->lastErrorTE) { write_msg(modulename, "Error from TOC entry %d; %u %u %s %s %s\n", AH->currentTE->dumpId, AH->currentTE->catalogId.tableoid, AH->currentTE->catalogId.oid, AH->currentTE->desc, AH->currentTE->tag, AH->currentTE->owner); } AH->lastErrorStage = AH->stage; AH->lastErrorTE = AH->currentTE; va_start(ap, fmt); vwrite_msg(modulename, fmt, ap); va_end(ap); if (AH->public.exit_on_error) exit_nicely(1); else AH->public.n_errors++; }
size_t WriteData | ( | Archive * | AHX, | |
const void * | data, | |||
size_t | dLen | |||
) |
Definition at line 786 of file pg_backup_archiver.c.
References _archiveHandle::currToc, exit_horribly(), modulename, and _archiveHandle::WriteDataPtr.
Referenced by archprintf(), archputs(), dumpBlobs(), and dumpTableData_copy().
{ ArchiveHandle *AH = (ArchiveHandle *) AHX; if (!AH->currToc) exit_horribly(modulename, "internal error -- WriteData cannot be called outside the context of a DataDumper routine\n"); return (*AH->WriteDataPtr) (AH, data, dLen); }
void WriteDataChunks | ( | ArchiveHandle * | AH, | |
ParallelState * | pstate | |||
) |
Definition at line 2097 of file pg_backup_archiver.c.
References ACT_DUMP, Assert, _tocEntry::dataDumper, DispatchJobForTocEntry(), EnsureIdleWorker(), EnsureWorkersFinished(), GetIdleWorker(), _tocEntry::next, NO_SLOT, ParallelState::numWorkers, REQ_DATA, _tocEntry::reqs, _archiveHandle::toc, and WriteDataChunksForTocEntry().
Referenced by _CloseArchive().
{ TocEntry *te; for (te = AH->toc->next; te != AH->toc; te = te->next) { if (!te->dataDumper) continue; if ((te->reqs & REQ_DATA) == 0) continue; if (pstate && pstate->numWorkers > 1) { /* * If we are in a parallel backup, then we are always the master * process. */ EnsureIdleWorker(AH, pstate); Assert(GetIdleWorker(pstate) != NO_SLOT); DispatchJobForTocEntry(AH, pstate, te, ACT_DUMP); } else WriteDataChunksForTocEntry(AH, te); } EnsureWorkersFinished(AH, pstate); }
void WriteDataChunksForTocEntry | ( | ArchiveHandle * | AH, | |
TocEntry * | te | |||
) |
Definition at line 2126 of file pg_backup_archiver.c.
References _archiveHandle::currToc, _tocEntry::dataDumper, _tocEntry::dataDumperArg, _tocEntry::desc, _archiveHandle::EndBlobsPtr, _archiveHandle::EndDataPtr, NULL, _archiveHandle::StartBlobsPtr, and _archiveHandle::StartDataPtr.
Referenced by _WorkerJobDumpDirectory(), and WriteDataChunks().
{ StartDataPtr startPtr; EndDataPtr endPtr; AH->currToc = te; if (strcmp(te->desc, "BLOBS") == 0) { startPtr = AH->StartBlobsPtr; endPtr = AH->EndBlobsPtr; } else { startPtr = AH->StartDataPtr; endPtr = AH->EndDataPtr; } if (startPtr != NULL) (*startPtr) (AH, te); /* * The user-provided DataDumper routine needs to call AH->WriteData */ (*te->dataDumper) ((Archive *) AH, te->dataDumperArg); if (endPtr != NULL) (*endPtr) (AH, te); AH->currToc = NULL; }
void WriteHead | ( | ArchiveHandle * | AH | ) |
Definition at line 3193 of file pg_backup_archiver.c.
References _archiveHandle::compression, _archiveHandle::connection, _archiveHandle::createDate, _archiveHandle::format, _archiveHandle::intSize, modulename, _archiveHandle::offSize, PQdb(), _archiveHandle::public, Archive::remoteVersionStr, tm, _archiveHandle::vmaj, _archiveHandle::vmin, _archiveHandle::vrev, write_msg(), _archiveHandle::WriteBufPtr, _archiveHandle::WriteBytePtr, WriteInt(), and WriteStr().
Referenced by _CloseArchive().
{ struct tm crtm; (*AH->WriteBufPtr) (AH, "PGDMP", 5); /* Magic code */ (*AH->WriteBytePtr) (AH, AH->vmaj); (*AH->WriteBytePtr) (AH, AH->vmin); (*AH->WriteBytePtr) (AH, AH->vrev); (*AH->WriteBytePtr) (AH, AH->intSize); (*AH->WriteBytePtr) (AH, AH->offSize); (*AH->WriteBytePtr) (AH, AH->format); #ifndef HAVE_LIBZ if (AH->compression != 0) write_msg(modulename, "WARNING: requested compression not available in this " "installation -- archive will be uncompressed\n"); AH->compression = 0; #endif WriteInt(AH, AH->compression); crtm = *localtime(&AH->createDate); WriteInt(AH, crtm.tm_sec); WriteInt(AH, crtm.tm_min); WriteInt(AH, crtm.tm_hour); WriteInt(AH, crtm.tm_mday); WriteInt(AH, crtm.tm_mon); WriteInt(AH, crtm.tm_year); WriteInt(AH, crtm.tm_isdst); WriteStr(AH, PQdb(AH->connection)); WriteStr(AH, AH->public.remoteVersionStr); WriteStr(AH, PG_VERSION); }
size_t WriteInt | ( | ArchiveHandle * | AH, | |
int | i | |||
) |
Definition at line 1702 of file pg_backup_archiver.c.
References _archiveHandle::intSize, and _archiveHandle::WriteBytePtr.
Referenced by _CustomWriteFunc(), _EndBlob(), _EndBlobs(), _EndData(), _StartBlob(), _StartBlobs(), _StartData(), WriteHead(), WriteStr(), and WriteToc().
{ int b; /* * This is a bit yucky, but I don't want to make the binary format very * dependent on representation, and not knowing much about it, I write out * a sign byte. If you change this, don't forget to change the file * version #, and modify readInt to read the new format AS WELL AS the old * formats. */ /* SIGN byte */ if (i < 0) { (*AH->WriteBytePtr) (AH, 1); i = -i; } else (*AH->WriteBytePtr) (AH, 0); for (b = 0; b < AH->intSize; b++) { (*AH->WriteBytePtr) (AH, i & 0xFF); i >>= 8; } return AH->intSize + 1; }
size_t WriteOffset | ( | ArchiveHandle * | AH, | |
pgoff_t | o, | |||
int | wasSet | |||
) |
Definition at line 1621 of file pg_backup_archiver.c.
References _archiveHandle::WriteBytePtr.
Referenced by _WriteExtraToc().
{ int off; /* Save the flag */ (*AH->WriteBytePtr) (AH, wasSet); /* Write out pgoff_t smallest byte first, prevents endian mismatch */ for (off = 0; off < sizeof(pgoff_t); off++) { (*AH->WriteBytePtr) (AH, o & 0xFF); o >>= 8; } return sizeof(pgoff_t) + 1; }
size_t WriteStr | ( | ArchiveHandle * | AH, | |
const char * | c | |||
) |
Definition at line 1760 of file pg_backup_archiver.c.
References _archiveHandle::WriteBufPtr, and WriteInt().
Referenced by _WriteExtraToc(), WriteHead(), and WriteToc().
void WriteToc | ( | ArchiveHandle * | AH | ) |
Definition at line 2159 of file pg_backup_archiver.c.
References _tocEntry::catalogId, _tocEntry::copyStmt, _tocEntry::dataDumper, _tocEntry::defn, _tocEntry::dependencies, _tocEntry::desc, _tocEntry::dropStmt, _tocEntry::dumpId, i, _tocEntry::nDeps, _tocEntry::next, NULL, CatalogId::oid, _tocEntry::owner, REQ_DATA, REQ_SCHEMA, REQ_SPECIAL, _tocEntry::reqs, _tocEntry::section, CatalogId::tableoid, _tocEntry::tablespace, _tocEntry::tag, _archiveHandle::toc, _tocEntry::withOids, _archiveHandle::WriteExtraTocPtr, WriteInt(), and WriteStr().
Referenced by _CloseArchive().
{ TocEntry *te; char workbuf[32]; int tocCount; int i; /* count entries that will actually be dumped */ tocCount = 0; for (te = AH->toc->next; te != AH->toc; te = te->next) { if ((te->reqs & (REQ_SCHEMA | REQ_DATA | REQ_SPECIAL)) != 0) tocCount++; } /* printf("%d TOC Entries to save\n", tocCount); */ WriteInt(AH, tocCount); for (te = AH->toc->next; te != AH->toc; te = te->next) { if ((te->reqs & (REQ_SCHEMA | REQ_DATA | REQ_SPECIAL)) == 0) continue; WriteInt(AH, te->dumpId); WriteInt(AH, te->dataDumper ? 1 : 0); /* OID is recorded as a string for historical reasons */ sprintf(workbuf, "%u", te->catalogId.tableoid); WriteStr(AH, workbuf); sprintf(workbuf, "%u", te->catalogId.oid); WriteStr(AH, workbuf); WriteStr(AH, te->tag); WriteStr(AH, te->desc); WriteInt(AH, te->section); WriteStr(AH, te->defn); WriteStr(AH, te->dropStmt); WriteStr(AH, te->copyStmt); WriteStr(AH, te->namespace); WriteStr(AH, te->tablespace); WriteStr(AH, te->owner); WriteStr(AH, te->withOids ? "true" : "false"); /* Dump list of dependencies */ for (i = 0; i < te->nDeps; i++) { sprintf(workbuf, "%d", te->dependencies[i]); WriteStr(AH, workbuf); } WriteStr(AH, NULL); /* Terminate List */ if (AH->WriteExtraTocPtr) (*AH->WriteExtraTocPtr) (AH, te); } }
const char* modulename = gettext_noop("archiver") [static] |
Definition at line 51 of file pg_backup_archiver.c.
Referenced by _allocAH(), _discoverArchiveFormat(), _doSetSessionAuth(), _doSetWithOids(), _getObjectDescription(), _printTocEntry(), _selectOutputSchema(), _selectTablespace(), ahwrite(), buildTocEntryArrays(), CloseArchive(), dump_lo_buf(), mark_work_done(), processEncodingEntry(), processStdStringsEntry(), ReadHead(), ReadOffset(), ReadStr(), ReadToc(), restore_toc_entry(), RestoreArchive(), RestoreOutput(), SetArchiveRestoreOptions(), SetOutput(), SortTocFromFile(), StartBlob(), StartRestoreBlob(), WriteData(), and WriteHead().