1 /*-------------------------------------------------------------------------
5 * Implements the basic DB functions used by the archiver.
8 * src/bin/pg_dump/pg_backup_db.c
10 *-------------------------------------------------------------------------
12 #include "postgres_fe.h"
14 #include "dumputils.h"
15 #include "pg_backup_archiver.h"
16 #include "pg_backup_db.h"
17 #include "pg_backup_utils.h"
26 #define DB_MAX_ERR_STMT 128
28 /* translator: this is a module name */
29 static const char *modulename = gettext_noop("archiver (db)");
31 static void _check_database_version(ArchiveHandle *AH);
32 static PGconn *_connectDB(ArchiveHandle *AH, const char *newdbname, const char *newUser);
33 static void notice_processor(void *arg, const char *message);
36 _check_database_version(ArchiveHandle *AH)
38 const char *remoteversion_str;
41 remoteversion_str = PQparameterStatus(AH->connection, "server_version");
42 remoteversion = PQserverVersion(AH->connection);
43 if (remoteversion == 0 || !remoteversion_str)
44 exit_horribly(modulename, "could not get server_version from libpq\n");
46 AH->public.remoteVersionStr = pg_strdup(remoteversion_str);
47 AH->public.remoteVersion = remoteversion;
48 if (!AH->archiveRemoteVersion)
49 AH->archiveRemoteVersion = AH->public.remoteVersionStr;
51 if (remoteversion != PG_VERSION_NUM
52 && (remoteversion < AH->public.minRemoteVersion ||
53 remoteversion > AH->public.maxRemoteVersion))
55 write_msg(NULL, "server version: %s; %s version: %s\n",
56 remoteversion_str, progname, PG_VERSION);
57 exit_horribly(NULL, "aborting because of server version mismatch\n");
62 * Reconnect to the server. If dbname is not NULL, use that database,
63 * else the one associated with the archive handle. If username is
64 * not NULL, use that user name, else the one from the handle. If
65 * both the database and the user match the existing connection already,
66 * nothing will be done.
68 * Returns 1 in any case.
71 ReconnectToServer(ArchiveHandle *AH, const char *dbname, const char *username)
74 const char *newdbname;
75 const char *newusername;
78 newdbname = PQdb(AH->connection);
83 newusername = PQuser(AH->connection);
85 newusername = username;
87 /* Let's see if the request is already satisfied */
88 if (strcmp(newdbname, PQdb(AH->connection)) == 0 &&
89 strcmp(newusername, PQuser(AH->connection)) == 0)
92 newConn = _connectDB(AH, newdbname, newusername);
94 PQfinish(AH->connection);
95 AH->connection = newConn;
101 * Connect to the db again.
103 * Note: it's not really all that sensible to use a single-entry password
104 * cache if the username keeps changing. In current usage, however, the
105 * username never does change, so one savedPassword is sufficient. We do
106 * update the cache on the off chance that the password has changed since the
110 _connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser)
115 char *password = AH->savedPassword;
119 newdb = PQdb(AH->connection);
123 if (!requser || strlen(requser) == 0)
124 newuser = PQuser(AH->connection);
128 ahlog(AH, 1, "connecting to database \"%s\" as user \"%s\"\n",
131 if (AH->promptPassword == TRI_YES && password == NULL)
133 password = simple_prompt("Password: ", 100, false);
134 if (password == NULL)
135 exit_horribly(modulename, "out of memory\n");
140 #define PARAMS_ARRAY_SIZE 7
141 const char **keywords = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords));
142 const char **values = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*values));
144 keywords[0] = "host";
145 values[0] = PQhost(AH->connection);
146 keywords[1] = "port";
147 values[1] = PQport(AH->connection);
148 keywords[2] = "user";
150 keywords[3] = "password";
151 values[3] = password;
152 keywords[4] = "dbname";
154 keywords[5] = "fallback_application_name";
155 values[5] = progname;
160 newConn = PQconnectdbParams(keywords, values, true);
166 exit_horribly(modulename, "failed to reconnect to database\n");
168 if (PQstatus(newConn) == CONNECTION_BAD)
170 if (!PQconnectionNeedsPassword(newConn))
171 exit_horribly(modulename, "could not reconnect to database: %s",
172 PQerrorMessage(newConn));
176 fprintf(stderr, "Password incorrect\n");
178 fprintf(stderr, "Connecting to %s as %s\n",
184 if (AH->promptPassword != TRI_NO)
185 password = simple_prompt("Password: ", 100, false);
187 exit_horribly(modulename, "connection needs password\n");
189 if (password == NULL)
190 exit_horribly(modulename, "out of memory\n");
195 AH->savedPassword = password;
197 /* check for version mismatch */
198 _check_database_version(AH);
200 PQsetNoticeProcessor(newConn, notice_processor, NULL);
207 * Make a database connection with the given parameters. The
208 * connection handle is returned, the parameters are stored in AHX.
209 * An interactive password prompt is automatically issued if required.
211 * Note: it's not really all that sensible to use a single-entry password
212 * cache if the username keeps changing. In current usage, however, the
213 * username never does change, so one savedPassword is sufficient.
216 ConnectDatabase(Archive *AHX,
220 const char *username,
221 trivalue prompt_password)
223 ArchiveHandle *AH = (ArchiveHandle *) AHX;
224 char *password = AH->savedPassword;
228 exit_horribly(modulename, "already connected to a database\n");
230 if (prompt_password == TRI_YES && password == NULL)
232 password = simple_prompt("Password: ", 100, false);
233 if (password == NULL)
234 exit_horribly(modulename, "out of memory\n");
236 AH->promptPassword = prompt_password;
239 * Start the connection. Loop until we have a password if requested by
244 #define PARAMS_ARRAY_SIZE 7
245 const char **keywords = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords));
246 const char **values = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*values));
248 keywords[0] = "host";
250 keywords[1] = "port";
252 keywords[2] = "user";
253 values[2] = username;
254 keywords[3] = "password";
255 values[3] = password;
256 keywords[4] = "dbname";
258 keywords[5] = "fallback_application_name";
259 values[5] = progname;
264 AH->connection = PQconnectdbParams(keywords, values, true);
270 exit_horribly(modulename, "failed to connect to database\n");
272 if (PQstatus(AH->connection) == CONNECTION_BAD &&
273 PQconnectionNeedsPassword(AH->connection) &&
275 prompt_password != TRI_NO)
277 PQfinish(AH->connection);
278 password = simple_prompt("Password: ", 100, false);
279 if (password == NULL)
280 exit_horribly(modulename, "out of memory\n");
285 AH->savedPassword = password;
287 /* check to see that the backend connection was successfully made */
288 if (PQstatus(AH->connection) == CONNECTION_BAD)
289 exit_horribly(modulename, "connection to database \"%s\" failed: %s",
290 PQdb(AH->connection) ? PQdb(AH->connection) : "",
291 PQerrorMessage(AH->connection));
293 /* check for version mismatch */
294 _check_database_version(AH);
296 PQsetNoticeProcessor(AH->connection, notice_processor, NULL);
300 * Close the connection to the database and also cancel off the query if we
304 DisconnectDatabase(Archive *AHX)
306 ArchiveHandle *AH = (ArchiveHandle *) AHX;
313 if (PQtransactionStatus(AH->connection) == PQTRANS_ACTIVE)
315 if ((cancel = PQgetCancel(AH->connection)))
317 PQcancel(cancel, errbuf, sizeof(errbuf));
318 PQfreeCancel(cancel);
322 PQfinish(AH->connection);
323 AH->connection = NULL;
327 GetConnection(Archive *AHX)
329 ArchiveHandle *AH = (ArchiveHandle *) AHX;
331 return AH->connection;
335 notice_processor(void *arg, const char *message)
337 write_msg(NULL, "%s", message);
340 /* Like exit_horribly(), but with a complaint about a particular query. */
342 die_on_query_failure(ArchiveHandle *AH, const char *modulename, const char *query)
344 write_msg(modulename, "query failed: %s",
345 PQerrorMessage(AH->connection));
346 exit_horribly(modulename, "query was: %s\n", query);
350 ExecuteSqlStatement(Archive *AHX, const char *query)
352 ArchiveHandle *AH = (ArchiveHandle *) AHX;
355 res = PQexec(AH->connection, query);
356 if (PQresultStatus(res) != PGRES_COMMAND_OK)
357 die_on_query_failure(AH, modulename, query);
362 ExecuteSqlQuery(Archive *AHX, const char *query, ExecStatusType status)
364 ArchiveHandle *AH = (ArchiveHandle *) AHX;
367 res = PQexec(AH->connection, query);
368 if (PQresultStatus(res) != status)
369 die_on_query_failure(AH, modulename, query);
374 * Convenience function to send a query.
375 * Monitors result to detect COPY statements
378 ExecuteSqlCommand(ArchiveHandle *AH, const char *qry, const char *desc)
380 PGconn *conn = AH->connection;
382 char errStmt[DB_MAX_ERR_STMT];
385 fprintf(stderr, "Executing: '%s'\n\n", qry);
387 res = PQexec(conn, qry);
389 switch (PQresultStatus(res))
391 case PGRES_COMMAND_OK:
392 case PGRES_TUPLES_OK:
393 case PGRES_EMPTY_QUERY:
397 /* Assume this is an expected result */
402 strncpy(errStmt, qry, DB_MAX_ERR_STMT);
403 if (errStmt[DB_MAX_ERR_STMT - 1] != '\0')
405 errStmt[DB_MAX_ERR_STMT - 4] = '.';
406 errStmt[DB_MAX_ERR_STMT - 3] = '.';
407 errStmt[DB_MAX_ERR_STMT - 2] = '.';
408 errStmt[DB_MAX_ERR_STMT - 1] = '\0';
410 warn_or_exit_horribly(AH, modulename, "%s: %s Command was: %s\n",
411 desc, PQerrorMessage(conn), errStmt);
420 * Process non-COPY table data (that is, INSERT commands).
422 * The commands have been run together as one long string for compressibility,
423 * and we are receiving them in bufferloads with arbitrary boundaries, so we
424 * have to locate command boundaries and save partial commands across calls.
425 * All state must be kept in AH->sqlparse, not in local variables of this
426 * routine. We assume that AH->sqlparse was filled with zeroes when created.
428 * We have to lex the data to the extent of identifying literals and quoted
429 * identifiers, so that we can recognize statement-terminating semicolons.
430 * We assume that INSERT data will not contain SQL comments, E'' literals,
431 * or dollar-quoted strings, so this is much simpler than a full SQL lexer.
433 * Note: when restoring from a pre-9.0 dump file, this code is also used to
434 * process BLOB COMMENTS data, which has the same problem of containing
435 * multiple SQL commands that might be split across bufferloads. Fortunately,
436 * that data won't contain anything complicated to lex either.
439 ExecuteSimpleCommands(ArchiveHandle *AH, const char *buf, size_t bufLen)
441 const char *qry = buf;
442 const char *eos = buf + bufLen;
444 /* initialize command buffer if first time through */
445 if (AH->sqlparse.curCmd == NULL)
446 AH->sqlparse.curCmd = createPQExpBuffer();
448 for (; qry < eos; qry++)
452 /* For neatness, we skip any newlines between commands */
453 if (!(ch == '\n' && AH->sqlparse.curCmd->len == 0))
454 appendPQExpBufferChar(AH->sqlparse.curCmd, ch);
456 switch (AH->sqlparse.state)
458 case SQL_SCAN: /* Default state == 0, set in _allocAH */
462 * We've found the end of a statement. Send it and reset
465 ExecuteSqlCommand(AH, AH->sqlparse.curCmd->data,
466 "could not execute query");
467 resetPQExpBuffer(AH->sqlparse.curCmd);
471 AH->sqlparse.state = SQL_IN_SINGLE_QUOTE;
472 AH->sqlparse.backSlash = false;
476 AH->sqlparse.state = SQL_IN_DOUBLE_QUOTE;
480 case SQL_IN_SINGLE_QUOTE:
481 /* We needn't handle '' specially */
482 if (ch == '\'' && !AH->sqlparse.backSlash)
483 AH->sqlparse.state = SQL_SCAN;
484 else if (ch == '\\' && !AH->public.std_strings)
485 AH->sqlparse.backSlash = !AH->sqlparse.backSlash;
487 AH->sqlparse.backSlash = false;
490 case SQL_IN_DOUBLE_QUOTE:
491 /* We needn't handle "" specially */
493 AH->sqlparse.state = SQL_SCAN;
501 * Implement ahwrite() for direct-to-DB restore
504 ExecuteSqlCommandBuf(Archive *AHX, const char *buf, size_t bufLen)
506 ArchiveHandle *AH = (ArchiveHandle *) AHX;
508 if (AH->outputKind == OUTPUT_COPYDATA)
513 * We drop the data on the floor if libpq has failed to enter COPY
514 * mode; this allows us to behave reasonably when trying to continue
515 * after an error in a COPY command.
518 PQputCopyData(AH->connection, buf, bufLen) <= 0)
519 exit_horribly(modulename, "error returned by PQputCopyData: %s",
520 PQerrorMessage(AH->connection));
522 else if (AH->outputKind == OUTPUT_OTHERDATA)
525 * Table data expressed as INSERT commands; or, in old dump files,
526 * BLOB COMMENTS data (which is expressed as COMMENT ON commands).
528 ExecuteSimpleCommands(AH, buf, bufLen);
533 * General SQL commands; we assume that commands will not be split
536 * In most cases the data passed to us will be a null-terminated
537 * string, but if it's not, we have to add a trailing null.
539 if (buf[bufLen] == '\0')
540 ExecuteSqlCommand(AH, buf, "could not execute query");
543 char *str = (char *) pg_malloc(bufLen + 1);
545 memcpy(str, buf, bufLen);
547 ExecuteSqlCommand(AH, str, "could not execute query");
556 * Terminate a COPY operation during direct-to-DB restore
559 EndDBCopyMode(Archive *AHX, const char *tocEntryTag)
561 ArchiveHandle *AH = (ArchiveHandle *) AHX;
567 if (PQputCopyEnd(AH->connection, NULL) <= 0)
568 exit_horribly(modulename, "error returned by PQputCopyEnd: %s",
569 PQerrorMessage(AH->connection));
571 /* Check command status and return to normal libpq state */
572 res = PQgetResult(AH->connection);
573 if (PQresultStatus(res) != PGRES_COMMAND_OK)
574 warn_or_exit_horribly(AH, modulename, "COPY failed for table \"%s\": %s",
575 tocEntryTag, PQerrorMessage(AH->connection));
578 AH->pgCopyIn = false;
583 StartTransaction(Archive *AHX)
585 ArchiveHandle *AH = (ArchiveHandle *) AHX;
587 ExecuteSqlCommand(AH, "BEGIN", "could not start database transaction");
591 CommitTransaction(Archive *AHX)
593 ArchiveHandle *AH = (ArchiveHandle *) AHX;
595 ExecuteSqlCommand(AH, "COMMIT", "could not commit database transaction");
599 DropBlobIfExists(ArchiveHandle *AH, Oid oid)
602 * If we are not restoring to a direct database connection, we have to
603 * guess about how to detect whether the blob exists. Assume new-style.
605 if (AH->connection == NULL ||
606 PQserverVersion(AH->connection) >= 90000)
609 "SELECT pg_catalog.lo_unlink(oid) "
610 "FROM pg_catalog.pg_largeobject_metadata "
611 "WHERE oid = '%u';\n",
616 /* Restoring to pre-9.0 server, so do it the old way */
618 "SELECT CASE WHEN EXISTS("
619 "SELECT 1 FROM pg_catalog.pg_largeobject WHERE loid = '%u'"
620 ") THEN pg_catalog.lo_unlink('%u') END;\n",