#include "pg_backup_db.h"#include "pg_backup_utils.h"#include "dumputils.h"#include "parallel.h"#include <unistd.h>#include <ctype.h>
Go to the source code of this file.
Defines | |
| #define | DB_MAX_ERR_STMT 128 |
| #define | PARAMS_ARRAY_SIZE 7 |
| #define | PARAMS_ARRAY_SIZE 7 |
Functions | |
| static void | _check_database_version (ArchiveHandle *AH) |
| static PGconn * | _connectDB (ArchiveHandle *AH, const char *newdbname, const char *newUser) |
| static void | notice_processor (void *arg, const char *message) |
| int | ReconnectToServer (ArchiveHandle *AH, const char *dbname, const char *username) |
| void | ConnectDatabase (Archive *AHX, const char *dbname, const char *pghost, const char *pgport, const char *username, enum trivalue prompt_password) |
| void | DisconnectDatabase (Archive *AHX) |
| PGconn * | GetConnection (Archive *AHX) |
| static void | die_on_query_failure (ArchiveHandle *AH, const char *modulename, const char *query) |
| void | ExecuteSqlStatement (Archive *AHX, const char *query) |
| PGresult * | ExecuteSqlQuery (Archive *AHX, const char *query, ExecStatusType status) |
| static void | ExecuteSqlCommand (ArchiveHandle *AH, const char *qry, const char *desc) |
| static void | ExecuteInsertCommands (ArchiveHandle *AH, const char *buf, size_t bufLen) |
| int | ExecuteSqlCommandBuf (ArchiveHandle *AH, const char *buf, size_t bufLen) |
| void | EndDBCopyMode (ArchiveHandle *AH, TocEntry *te) |
| void | StartTransaction (ArchiveHandle *AH) |
| void | CommitTransaction (ArchiveHandle *AH) |
| void | DropBlobIfExists (ArchiveHandle *AH, Oid oid) |
Variables | |
| static const char * | modulename = gettext_noop("archiver (db)") |
| #define DB_MAX_ERR_STMT 128 |
Definition at line 25 of file pg_backup_db.c.
Referenced by ExecuteSqlCommand().
| #define PARAMS_ARRAY_SIZE 7 |
| #define PARAMS_ARRAY_SIZE 7 |
| static void _check_database_version | ( | ArchiveHandle * | AH | ) | [static] |
Definition at line 35 of file pg_backup_db.c.
References _archiveHandle::archiveRemoteVersion, _archiveHandle::connection, exit_horribly(), Archive::maxRemoteVersion, modulename, NULL, pg_strdup(), PQparameterStatus(), PQserverVersion(), progname, _archiveHandle::public, Archive::remoteVersion, Archive::remoteVersionStr, and write_msg().
Referenced by _connectDB(), and ConnectDatabase().
{
const char *remoteversion_str;
int remoteversion;
remoteversion_str = PQparameterStatus(AH->connection, "server_version");
remoteversion = PQserverVersion(AH->connection);
if (remoteversion == 0 || !remoteversion_str)
exit_horribly(modulename, "could not get server_version from libpq\n");
AH->public.remoteVersionStr = pg_strdup(remoteversion_str);
AH->public.remoteVersion = remoteversion;
if (!AH->archiveRemoteVersion)
AH->archiveRemoteVersion = AH->public.remoteVersionStr;
if (remoteversion != PG_VERSION_NUM
&& (remoteversion < AH->public.minRemoteVersion ||
remoteversion > AH->public.maxRemoteVersion))
{
write_msg(NULL, "server version: %s; %s version: %s\n",
remoteversion_str, progname, PG_VERSION);
exit_horribly(NULL, "aborting because of server version mismatch\n");
}
}
| static PGconn * _connectDB | ( | ArchiveHandle * | AH, | |
| const char * | newdbname, | |||
| const char * | newUser | |||
| ) | [static] |
Definition at line 109 of file pg_backup_db.c.
References _check_database_version(), ahlog(), _archiveHandle::connection, CONNECTION_BAD, exit_horribly(), free, modulename, notice_processor(), NULL, PARAMS_ARRAY_SIZE, pg_malloc(), PQconnectdbParams(), PQconnectionNeedsPassword(), PQdb(), PQerrorMessage(), PQfinish(), PQhost(), PQport(), PQsetNoticeProcessor(), PQstatus(), PQuser(), progname, _archiveHandle::promptPassword, _archiveHandle::savedPassword, simple_prompt(), TRI_NO, TRI_YES, and values.
Referenced by ReconnectToServer().
{
PGconn *newConn;
const char *newdb;
const char *newuser;
char *password = AH->savedPassword;
bool new_pass;
if (!reqdb)
newdb = PQdb(AH->connection);
else
newdb = reqdb;
if (!requser || strlen(requser) == 0)
newuser = PQuser(AH->connection);
else
newuser = requser;
ahlog(AH, 1, "connecting to database \"%s\" as user \"%s\"\n",
newdb, newuser);
if (AH->promptPassword == TRI_YES && password == NULL)
{
password = simple_prompt("Password: ", 100, false);
if (password == NULL)
exit_horribly(modulename, "out of memory\n");
}
do
{
#define PARAMS_ARRAY_SIZE 7
const char **keywords = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords));
const char **values = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*values));
keywords[0] = "host";
values[0] = PQhost(AH->connection);
keywords[1] = "port";
values[1] = PQport(AH->connection);
keywords[2] = "user";
values[2] = newuser;
keywords[3] = "password";
values[3] = password;
keywords[4] = "dbname";
values[4] = newdb;
keywords[5] = "fallback_application_name";
values[5] = progname;
keywords[6] = NULL;
values[6] = NULL;
new_pass = false;
newConn = PQconnectdbParams(keywords, values, true);
free(keywords);
free(values);
if (!newConn)
exit_horribly(modulename, "failed to reconnect to database\n");
if (PQstatus(newConn) == CONNECTION_BAD)
{
if (!PQconnectionNeedsPassword(newConn))
exit_horribly(modulename, "could not reconnect to database: %s",
PQerrorMessage(newConn));
PQfinish(newConn);
if (password)
fprintf(stderr, "Password incorrect\n");
fprintf(stderr, "Connecting to %s as %s\n",
newdb, newuser);
if (password)
free(password);
if (AH->promptPassword != TRI_NO)
password = simple_prompt("Password: ", 100, false);
else
exit_horribly(modulename, "connection needs password\n");
if (password == NULL)
exit_horribly(modulename, "out of memory\n");
new_pass = true;
}
} while (new_pass);
AH->savedPassword = password;
/* check for version mismatch */
_check_database_version(AH);
PQsetNoticeProcessor(newConn, notice_processor, NULL);
return newConn;
}
| void CommitTransaction | ( | ArchiveHandle * | AH | ) |
Definition at line 578 of file pg_backup_db.c.
References ExecuteSqlCommand().
{
ExecuteSqlCommand(AH, "COMMIT", "could not commit database transaction");
}
| void ConnectDatabase | ( | Archive * | AHX, | |
| const char * | dbname, | |||
| const char * | pghost, | |||
| const char * | pgport, | |||
| const char * | username, | |||
| enum trivalue | prompt_password | |||
| ) |
Definition at line 215 of file pg_backup_db.c.
References _check_database_version(), _archiveHandle::connection, CONNECTION_BAD, exit_horribly(), free, modulename, notice_processor(), NULL, PARAMS_ARRAY_SIZE, pg_malloc(), PQconnectdbParams(), PQconnectionNeedsPassword(), PQdb(), PQerrorMessage(), PQfinish(), PQsetNoticeProcessor(), PQstatus(), progname, _archiveHandle::promptPassword, _archiveHandle::savedPassword, simple_prompt(), TRI_NO, TRI_YES, and values.
Referenced by CloneArchive(), main(), restore_toc_entries_postfork(), and RestoreArchive().
{
ArchiveHandle *AH = (ArchiveHandle *) AHX;
char *password = AH->savedPassword;
bool new_pass;
if (AH->connection)
exit_horribly(modulename, "already connected to a database\n");
if (prompt_password == TRI_YES && password == NULL)
{
password = simple_prompt("Password: ", 100, false);
if (password == NULL)
exit_horribly(modulename, "out of memory\n");
}
AH->promptPassword = prompt_password;
/*
* Start the connection. Loop until we have a password if requested by
* backend.
*/
do
{
#define PARAMS_ARRAY_SIZE 7
const char **keywords = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords));
const char **values = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*values));
keywords[0] = "host";
values[0] = pghost;
keywords[1] = "port";
values[1] = pgport;
keywords[2] = "user";
values[2] = username;
keywords[3] = "password";
values[3] = password;
keywords[4] = "dbname";
values[4] = dbname;
keywords[5] = "fallback_application_name";
values[5] = progname;
keywords[6] = NULL;
values[6] = NULL;
new_pass = false;
AH->connection = PQconnectdbParams(keywords, values, true);
free(keywords);
free(values);
if (!AH->connection)
exit_horribly(modulename, "failed to connect to database\n");
if (PQstatus(AH->connection) == CONNECTION_BAD &&
PQconnectionNeedsPassword(AH->connection) &&
password == NULL &&
prompt_password != TRI_NO)
{
PQfinish(AH->connection);
password = simple_prompt("Password: ", 100, false);
if (password == NULL)
exit_horribly(modulename, "out of memory\n");
new_pass = true;
}
} while (new_pass);
AH->savedPassword = password;
/* check to see that the backend connection was successfully made */
if (PQstatus(AH->connection) == CONNECTION_BAD)
exit_horribly(modulename, "connection to database \"%s\" failed: %s",
PQdb(AH->connection) ? PQdb(AH->connection) : "",
PQerrorMessage(AH->connection));
/* check for version mismatch */
_check_database_version(AH);
PQsetNoticeProcessor(AH->connection, notice_processor, NULL);
}
| static void die_on_query_failure | ( | ArchiveHandle * | AH, | |
| const char * | modulename, | |||
| const char * | query | |||
| ) | [static] |
Definition at line 341 of file pg_backup_db.c.
References _archiveHandle::connection, exit_horribly(), PQerrorMessage(), and write_msg().
Referenced by ExecuteSqlQuery(), and ExecuteSqlStatement().
{
write_msg(modulename, "query failed: %s",
PQerrorMessage(AH->connection));
exit_horribly(modulename, "query was: %s\n", query);
}
| void DisconnectDatabase | ( | Archive * | AHX | ) |
Definition at line 303 of file pg_backup_db.c.
References _archiveHandle::connection, PQcancel(), PQfinish(), PQfreeCancel(), PQgetCancel(), and PQtransactionStatus().
Referenced by archive_close_connection(), restore_toc_entries_prefork(), and RestoreArchive().
{
ArchiveHandle *AH = (ArchiveHandle *) AHX;
PGcancel *cancel;
char errbuf[1];
if (!AH->connection)
return;
if (PQtransactionStatus(AH->connection) == PQTRANS_ACTIVE)
{
if ((cancel = PQgetCancel(AH->connection)))
{
PQcancel(cancel, errbuf, sizeof(errbuf));
PQfreeCancel(cancel);
}
}
PQfinish(AH->connection);
AH->connection = NULL;
}
| void DropBlobIfExists | ( | ArchiveHandle * | AH, | |
| Oid | oid | |||
| ) |
Definition at line 584 of file pg_backup_db.c.
References ahprintf(), _archiveHandle::connection, NULL, and PQserverVersion().
Referenced by _StartBlob(), and StartRestoreBlob().
{
/*
* If we are not restoring to a direct database connection, we have to
* guess about how to detect whether the blob exists. Assume new-style.
*/
if (AH->connection == NULL ||
PQserverVersion(AH->connection) >= 90000)
{
ahprintf(AH,
"SELECT pg_catalog.lo_unlink(oid) "
"FROM pg_catalog.pg_largeobject_metadata "
"WHERE oid = '%u';\n",
oid);
}
else
{
/* Restoring to pre-9.0 server, so do it the old way */
ahprintf(AH,
"SELECT CASE WHEN EXISTS("
"SELECT 1 FROM pg_catalog.pg_largeobject WHERE loid = '%u'"
") THEN pg_catalog.lo_unlink('%u') END;\n",
oid, oid);
}
}
| void EndDBCopyMode | ( | ArchiveHandle * | AH, | |
| TocEntry * | te | |||
| ) |
Definition at line 550 of file pg_backup_db.c.
References _archiveHandle::connection, exit_horribly(), modulename, NULL, _archiveHandle::pgCopyIn, PGRES_COMMAND_OK, PQclear(), PQerrorMessage(), PQgetResult(), PQputCopyEnd(), PQresultStatus(), _tocEntry::tag, and warn_or_exit_horribly().
Referenced by restore_toc_entry().
{
if (AH->pgCopyIn)
{
PGresult *res;
if (PQputCopyEnd(AH->connection, NULL) <= 0)
exit_horribly(modulename, "error returned by PQputCopyEnd: %s",
PQerrorMessage(AH->connection));
/* Check command status and return to normal libpq state */
res = PQgetResult(AH->connection);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
warn_or_exit_horribly(AH, modulename, "COPY failed for table \"%s\": %s",
te->tag, PQerrorMessage(AH->connection));
PQclear(res);
AH->pgCopyIn = false;
}
}
| static void ExecuteInsertCommands | ( | ArchiveHandle * | AH, | |
| const char * | buf, | |||
| size_t | bufLen | |||
| ) | [static] |
Definition at line 433 of file pg_backup_db.c.
References appendPQExpBufferChar(), sqlparseInfo::backSlash, createPQExpBuffer(), sqlparseInfo::curCmd, PQExpBufferData::data, ExecuteSqlCommand(), PQExpBufferData::len, NULL, _archiveHandle::public, resetPQExpBuffer(), SQL_IN_DOUBLE_QUOTE, SQL_IN_SINGLE_QUOTE, SQL_SCAN, _archiveHandle::sqlparse, sqlparseInfo::state, and Archive::std_strings.
Referenced by ExecuteSqlCommandBuf().
{
const char *qry = buf;
const char *eos = buf + bufLen;
/* initialize command buffer if first time through */
if (AH->sqlparse.curCmd == NULL)
AH->sqlparse.curCmd = createPQExpBuffer();
for (; qry < eos; qry++)
{
char ch = *qry;
/* For neatness, we skip any newlines between commands */
if (!(ch == '\n' && AH->sqlparse.curCmd->len == 0))
appendPQExpBufferChar(AH->sqlparse.curCmd, ch);
switch (AH->sqlparse.state)
{
case SQL_SCAN: /* Default state == 0, set in _allocAH */
if (ch == ';')
{
/*
* We've found the end of a statement. Send it and reset
* the buffer.
*/
ExecuteSqlCommand(AH, AH->sqlparse.curCmd->data,
"could not execute query");
resetPQExpBuffer(AH->sqlparse.curCmd);
}
else if (ch == '\'')
{
AH->sqlparse.state = SQL_IN_SINGLE_QUOTE;
AH->sqlparse.backSlash = false;
}
else if (ch == '"')
{
AH->sqlparse.state = SQL_IN_DOUBLE_QUOTE;
}
break;
case SQL_IN_SINGLE_QUOTE:
/* We needn't handle '' specially */
if (ch == '\'' && !AH->sqlparse.backSlash)
AH->sqlparse.state = SQL_SCAN;
else if (ch == '\\' && !AH->public.std_strings)
AH->sqlparse.backSlash = !AH->sqlparse.backSlash;
else
AH->sqlparse.backSlash = false;
break;
case SQL_IN_DOUBLE_QUOTE:
/* We needn't handle "" specially */
if (ch == '"')
AH->sqlparse.state = SQL_SCAN;
break;
}
}
}
| static void ExecuteSqlCommand | ( | ArchiveHandle * | AH, | |
| const char * | qry, | |||
| const char * | desc | |||
| ) | [static] |
Definition at line 377 of file pg_backup_db.c.
References conn, _archiveHandle::connection, DB_MAX_ERR_STMT, modulename, _archiveHandle::pgCopyIn, PGRES_COMMAND_OK, PGRES_COPY_IN, PGRES_EMPTY_QUERY, PGRES_TUPLES_OK, PQclear(), PQerrorMessage(), PQexec(), PQresultStatus(), and warn_or_exit_horribly().
Referenced by CommitTransaction(), ExecuteInsertCommands(), ExecuteSqlCommandBuf(), and StartTransaction().
{
PGconn *conn = AH->connection;
PGresult *res;
char errStmt[DB_MAX_ERR_STMT];
#ifdef NOT_USED
fprintf(stderr, "Executing: '%s'\n\n", qry);
#endif
res = PQexec(conn, qry);
switch (PQresultStatus(res))
{
case PGRES_COMMAND_OK:
case PGRES_TUPLES_OK:
case PGRES_EMPTY_QUERY:
/* A-OK */
break;
case PGRES_COPY_IN:
/* Assume this is an expected result */
AH->pgCopyIn = true;
break;
default:
/* trouble */
strncpy(errStmt, qry, DB_MAX_ERR_STMT);
if (errStmt[DB_MAX_ERR_STMT - 1] != '\0')
{
errStmt[DB_MAX_ERR_STMT - 4] = '.';
errStmt[DB_MAX_ERR_STMT - 3] = '.';
errStmt[DB_MAX_ERR_STMT - 2] = '.';
errStmt[DB_MAX_ERR_STMT - 1] = '\0';
}
warn_or_exit_horribly(AH, modulename, "%s: %s Command was: %s\n",
desc, PQerrorMessage(conn), errStmt);
break;
}
PQclear(res);
}
| int ExecuteSqlCommandBuf | ( | ArchiveHandle * | AH, | |
| const char * | buf, | |||
| size_t | bufLen | |||
| ) |
Definition at line 498 of file pg_backup_db.c.
References _archiveHandle::connection, ExecuteInsertCommands(), ExecuteSqlCommand(), exit_horribly(), free, modulename, OUTPUT_COPYDATA, OUTPUT_OTHERDATA, _archiveHandle::outputKind, pg_malloc(), _archiveHandle::pgCopyIn, PQerrorMessage(), and PQputCopyData().
Referenced by ahwrite().
{
if (AH->outputKind == OUTPUT_COPYDATA)
{
/*
* COPY data.
*
* We drop the data on the floor if libpq has failed to enter COPY
* mode; this allows us to behave reasonably when trying to continue
* after an error in a COPY command.
*/
if (AH->pgCopyIn &&
PQputCopyData(AH->connection, buf, bufLen) <= 0)
exit_horribly(modulename, "error returned by PQputCopyData: %s",
PQerrorMessage(AH->connection));
}
else if (AH->outputKind == OUTPUT_OTHERDATA)
{
/*
* Table data expressed as INSERT commands.
*/
ExecuteInsertCommands(AH, buf, bufLen);
}
else
{
/*
* General SQL commands; we assume that commands will not be split
* across calls.
*
* In most cases the data passed to us will be a null-terminated
* string, but if it's not, we have to add a trailing null.
*/
if (buf[bufLen] == '\0')
ExecuteSqlCommand(AH, buf, "could not execute query");
else
{
char *str = (char *) pg_malloc(bufLen + 1);
memcpy(str, buf, bufLen);
str[bufLen] = '\0';
ExecuteSqlCommand(AH, str, "could not execute query");
free(str);
}
}
return 1;
}
| PGresult* ExecuteSqlQuery | ( | Archive * | AHX, | |
| const char * | query, | |||
| ExecStatusType | status | |||
| ) |
Definition at line 361 of file pg_backup_db.c.
References _archiveHandle::connection, die_on_query_failure(), modulename, PQexec(), and PQresultStatus().
Referenced by buildMatViewRefreshDependencies(), collectComments(), collectSecLabels(), createViewAsClause(), dumpBlobs(), dumpCompositeType(), dumpCompositeTypeColComments(), dumpDatabase(), dumpEnumType(), dumpOpclass(), dumpOpfamily(), dumpRule(), dumpSequence(), dumpSequenceData(), dumpTable(), dumpTableData_copy(), dumpTableData_insert(), dumpTSConfig(), dumpUserMappings(), ExecuteSqlQueryForSingleRow(), expand_schema_name_patterns(), expand_table_name_patterns(), getAggregates(), getBlobs(), getCasts(), getCollations(), getConstraints(), getConversions(), getDefaultACLs(), getDependencies(), getDomainConstraints(), getEventTriggers(), getExtensionMembership(), getExtensions(), getForeignDataWrappers(), getForeignServers(), getFuncs(), getIndexes(), getInherits(), getNamespaces(), getOpclasses(), getOperators(), getOpfamilies(), getProcLangs(), getRules(), getTableAttrs(), getTables(), getTriggers(), getTSConfigurations(), getTSDictionaries(), getTSParsers(), getTSTemplates(), and getTypes().
{
ArchiveHandle *AH = (ArchiveHandle *) AHX;
PGresult *res;
res = PQexec(AH->connection, query);
if (PQresultStatus(res) != status)
die_on_query_failure(AH, modulename, query);
return res;
}
| void ExecuteSqlStatement | ( | Archive * | AHX, | |
| const char * | query | |||
| ) |
Definition at line 349 of file pg_backup_db.c.
References _archiveHandle::connection, die_on_query_failure(), modulename, PGRES_COMMAND_OK, PQclear(), PQexec(), and PQresultStatus().
Referenced by dumpBlobs(), dumpTableData_insert(), getTables(), selectSourceSchema(), and setup_connection().
{
ArchiveHandle *AH = (ArchiveHandle *) AHX;
PGresult *res;
res = PQexec(AH->connection, query);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
die_on_query_failure(AH, modulename, query);
PQclear(res);
}
Definition at line 326 of file pg_backup_db.c.
References _archiveHandle::connection.
{
ArchiveHandle *AH = (ArchiveHandle *) AHX;
return AH->connection;
}
| static void notice_processor | ( | void * | arg, | |
| const char * | message | |||
| ) | [static] |
Definition at line 334 of file pg_backup_db.c.
References NULL, and write_msg().
Referenced by _connectDB(), and ConnectDatabase().
| int ReconnectToServer | ( | ArchiveHandle * | AH, | |
| const char * | dbname, | |||
| const char * | username | |||
| ) |
Definition at line 70 of file pg_backup_db.c.
References _connectDB(), _archiveHandle::connection, PQdb(), PQfinish(), and PQuser().
Referenced by _reconnectToDB().
{
PGconn *newConn;
const char *newdbname;
const char *newusername;
if (!dbname)
newdbname = PQdb(AH->connection);
else
newdbname = dbname;
if (!username)
newusername = PQuser(AH->connection);
else
newusername = username;
/* Let's see if the request is already satisfied */
if (strcmp(newdbname, PQdb(AH->connection)) == 0 &&
strcmp(newusername, PQuser(AH->connection)) == 0)
return 1;
newConn = _connectDB(AH, newdbname, newusername);
PQfinish(AH->connection);
AH->connection = newConn;
return 1;
}
| void StartTransaction | ( | ArchiveHandle * | AH | ) |
Definition at line 572 of file pg_backup_db.c.
References ExecuteSqlCommand().
{
ExecuteSqlCommand(AH, "BEGIN", "could not start database transaction");
}
const char* modulename = gettext_noop("archiver (db)") [static] |
Definition at line 28 of file pg_backup_db.c.
Referenced by _check_database_version(), _connectDB(), ConnectDatabase(), EndDBCopyMode(), ExecuteSqlCommand(), ExecuteSqlCommandBuf(), ExecuteSqlQuery(), and ExecuteSqlStatement().
1.7.1