]> granicus.if.org Git - postgresql/blob - src/bin/pg_dump/pg_backup_db.c
Fix pg_restore's direct-to-database mode for standard_conforming_strings.
[postgresql] / src / bin / pg_dump / pg_backup_db.c
1 /*-------------------------------------------------------------------------
2  *
3  * pg_backup_db.c
4  *
5  *      Implements the basic DB functions used by the archiver.
6  *
7  * IDENTIFICATION
8  *        src/bin/pg_dump/pg_backup_db.c
9  *
10  *-------------------------------------------------------------------------
11  */
12
13 #include "pg_backup_db.h"
14 #include "dumputils.h"
15
16 #include <unistd.h>
17 #include <ctype.h>
18 #ifdef HAVE_TERMIOS_H
19 #include <termios.h>
20 #endif
21
22
23 #define DB_MAX_ERR_STMT 128
24
25 static const char *modulename = gettext_noop("archiver (db)");
26
27 static void _check_database_version(ArchiveHandle *AH);
28 static PGconn *_connectDB(ArchiveHandle *AH, const char *newdbname, const char *newUser);
29 static void notice_processor(void *arg, const char *message);
30
31 static int
32 _parse_version(ArchiveHandle *AH, const char *versionString)
33 {
34         int                     v;
35
36         v = parse_version(versionString);
37         if (v < 0)
38                 die_horribly(AH, modulename, "could not parse version string \"%s\"\n", versionString);
39
40         return v;
41 }
42
43 static void
44 _check_database_version(ArchiveHandle *AH)
45 {
46         int                     myversion;
47         const char *remoteversion_str;
48         int                     remoteversion;
49
50         myversion = _parse_version(AH, PG_VERSION);
51
52         remoteversion_str = PQparameterStatus(AH->connection, "server_version");
53         if (!remoteversion_str)
54                 die_horribly(AH, modulename, "could not get server_version from libpq\n");
55
56         remoteversion = _parse_version(AH, remoteversion_str);
57
58         AH->public.remoteVersionStr = strdup(remoteversion_str);
59         AH->public.remoteVersion = remoteversion;
60         if (!AH->archiveRemoteVersion)
61                 AH->archiveRemoteVersion = AH->public.remoteVersionStr;
62
63         if (myversion != remoteversion
64                 && (remoteversion < AH->public.minRemoteVersion ||
65                         remoteversion > AH->public.maxRemoteVersion))
66         {
67                 write_msg(NULL, "server version: %s; %s version: %s\n",
68                                   remoteversion_str, progname, PG_VERSION);
69                 die_horribly(AH, NULL, "aborting because of server version mismatch\n");
70         }
71 }
72
73 /*
74  * Reconnect to the server.  If dbname is not NULL, use that database,
75  * else the one associated with the archive handle.  If username is
76  * not NULL, use that user name, else the one from the handle.  If
77  * both the database and the user match the existing connection already,
78  * nothing will be done.
79  *
80  * Returns 1 in any case.
81  */
82 int
83 ReconnectToServer(ArchiveHandle *AH, const char *dbname, const char *username)
84 {
85         PGconn     *newConn;
86         const char *newdbname;
87         const char *newusername;
88
89         if (!dbname)
90                 newdbname = PQdb(AH->connection);
91         else
92                 newdbname = dbname;
93
94         if (!username)
95                 newusername = PQuser(AH->connection);
96         else
97                 newusername = username;
98
99         /* Let's see if the request is already satisfied */
100         if (strcmp(newdbname, PQdb(AH->connection)) == 0 &&
101                 strcmp(newusername, PQuser(AH->connection)) == 0)
102                 return 1;
103
104         newConn = _connectDB(AH, newdbname, newusername);
105
106         PQfinish(AH->connection);
107         AH->connection = newConn;
108
109         return 1;
110 }
111
112 /*
113  * Connect to the db again.
114  *
115  * Note: it's not really all that sensible to use a single-entry password
116  * cache if the username keeps changing.  In current usage, however, the
117  * username never does change, so one savedPassword is sufficient.      We do
118  * update the cache on the off chance that the password has changed since the
119  * start of the run.
120  */
121 static PGconn *
122 _connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser)
123 {
124         PGconn     *newConn;
125         const char *newdb;
126         const char *newuser;
127         char       *password = AH->savedPassword;
128         bool            new_pass;
129
130         if (!reqdb)
131                 newdb = PQdb(AH->connection);
132         else
133                 newdb = reqdb;
134
135         if (!requser || strlen(requser) == 0)
136                 newuser = PQuser(AH->connection);
137         else
138                 newuser = requser;
139
140         ahlog(AH, 1, "connecting to database \"%s\" as user \"%s\"\n",
141                   newdb, newuser);
142
143         if (AH->promptPassword == TRI_YES && password == NULL)
144         {
145                 password = simple_prompt("Password: ", 100, false);
146                 if (password == NULL)
147                         die_horribly(AH, modulename, "out of memory\n");
148         }
149
150         do
151         {
152 #define PARAMS_ARRAY_SIZE       7
153                 const char **keywords = malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords));
154                 const char **values = malloc(PARAMS_ARRAY_SIZE * sizeof(*values));
155
156                 if (!keywords || !values)
157                         die_horribly(AH, modulename, "out of memory\n");
158
159                 keywords[0] = "host";
160                 values[0] = PQhost(AH->connection);
161                 keywords[1] = "port";
162                 values[1] = PQport(AH->connection);
163                 keywords[2] = "user";
164                 values[2] = newuser;
165                 keywords[3] = "password";
166                 values[3] = password;
167                 keywords[4] = "dbname";
168                 values[4] = newdb;
169                 keywords[5] = "fallback_application_name";
170                 values[5] = progname;
171                 keywords[6] = NULL;
172                 values[6] = NULL;
173
174                 new_pass = false;
175                 newConn = PQconnectdbParams(keywords, values, true);
176
177                 free(keywords);
178                 free(values);
179
180                 if (!newConn)
181                         die_horribly(AH, modulename, "failed to reconnect to database\n");
182
183                 if (PQstatus(newConn) == CONNECTION_BAD)
184                 {
185                         if (!PQconnectionNeedsPassword(newConn))
186                                 die_horribly(AH, modulename, "could not reconnect to database: %s",
187                                                          PQerrorMessage(newConn));
188                         PQfinish(newConn);
189
190                         if (password)
191                                 fprintf(stderr, "Password incorrect\n");
192
193                         fprintf(stderr, "Connecting to %s as %s\n",
194                                         newdb, newuser);
195
196                         if (password)
197                                 free(password);
198
199                         if (AH->promptPassword != TRI_NO)
200                                 password = simple_prompt("Password: ", 100, false);
201                         else
202                                 die_horribly(AH, modulename, "connection needs password\n");
203
204                         if (password == NULL)
205                                 die_horribly(AH, modulename, "out of memory\n");
206                         new_pass = true;
207                 }
208         } while (new_pass);
209
210         AH->savedPassword = password;
211
212         /* check for version mismatch */
213         _check_database_version(AH);
214
215         PQsetNoticeProcessor(newConn, notice_processor, NULL);
216
217         return newConn;
218 }
219
220
221 /*
222  * Make a database connection with the given parameters.  The
223  * connection handle is returned, the parameters are stored in AHX.
224  * An interactive password prompt is automatically issued if required.
225  *
226  * Note: it's not really all that sensible to use a single-entry password
227  * cache if the username keeps changing.  In current usage, however, the
228  * username never does change, so one savedPassword is sufficient.
229  */
230 PGconn *
231 ConnectDatabase(Archive *AHX,
232                                 const char *dbname,
233                                 const char *pghost,
234                                 const char *pgport,
235                                 const char *username,
236                                 enum trivalue prompt_password)
237 {
238         ArchiveHandle *AH = (ArchiveHandle *) AHX;
239         char       *password = AH->savedPassword;
240         bool            new_pass;
241
242         if (AH->connection)
243                 die_horribly(AH, modulename, "already connected to a database\n");
244
245         if (prompt_password == TRI_YES && password == NULL)
246         {
247                 password = simple_prompt("Password: ", 100, false);
248                 if (password == NULL)
249                         die_horribly(AH, modulename, "out of memory\n");
250         }
251         AH->promptPassword = prompt_password;
252
253         /*
254          * Start the connection.  Loop until we have a password if requested by
255          * backend.
256          */
257         do
258         {
259 #define PARAMS_ARRAY_SIZE       7
260                 const char **keywords = malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords));
261                 const char **values = malloc(PARAMS_ARRAY_SIZE * sizeof(*values));
262
263                 if (!keywords || !values)
264                         die_horribly(AH, modulename, "out of memory\n");
265
266                 keywords[0] = "host";
267                 values[0] = pghost;
268                 keywords[1] = "port";
269                 values[1] = pgport;
270                 keywords[2] = "user";
271                 values[2] = username;
272                 keywords[3] = "password";
273                 values[3] = password;
274                 keywords[4] = "dbname";
275                 values[4] = dbname;
276                 keywords[5] = "fallback_application_name";
277                 values[5] = progname;
278                 keywords[6] = NULL;
279                 values[6] = NULL;
280
281                 new_pass = false;
282                 AH->connection = PQconnectdbParams(keywords, values, true);
283
284                 free(keywords);
285                 free(values);
286
287                 if (!AH->connection)
288                         die_horribly(AH, modulename, "failed to connect to database\n");
289
290                 if (PQstatus(AH->connection) == CONNECTION_BAD &&
291                         PQconnectionNeedsPassword(AH->connection) &&
292                         password == NULL &&
293                         prompt_password != TRI_NO)
294                 {
295                         PQfinish(AH->connection);
296                         password = simple_prompt("Password: ", 100, false);
297                         if (password == NULL)
298                                 die_horribly(AH, modulename, "out of memory\n");
299                         new_pass = true;
300                 }
301         } while (new_pass);
302
303         AH->savedPassword = password;
304
305         /* check to see that the backend connection was successfully made */
306         if (PQstatus(AH->connection) == CONNECTION_BAD)
307                 die_horribly(AH, modulename, "connection to database \"%s\" failed: %s",
308                                          PQdb(AH->connection), PQerrorMessage(AH->connection));
309
310         /* check for version mismatch */
311         _check_database_version(AH);
312
313         PQsetNoticeProcessor(AH->connection, notice_processor, NULL);
314
315         return AH->connection;
316 }
317
318
319 static void
320 notice_processor(void *arg, const char *message)
321 {
322         write_msg(NULL, "%s", message);
323 }
324
325
326 /*
327  * Convenience function to send a query.
328  * Monitors result to detect COPY statements
329  */
330 static void
331 ExecuteSqlCommand(ArchiveHandle *AH, const char *qry, const char *desc)
332 {
333         PGconn     *conn = AH->connection;
334         PGresult   *res;
335         char            errStmt[DB_MAX_ERR_STMT];
336
337 #ifdef NOT_USED
338         fprintf(stderr, "Executing: '%s'\n\n", qry);
339 #endif
340         res = PQexec(conn, qry);
341
342         switch (PQresultStatus(res))
343         {
344                 case PGRES_COMMAND_OK:
345                 case PGRES_TUPLES_OK:
346                 case PGRES_EMPTY_QUERY:
347                         /* A-OK */
348                         break;
349                 case PGRES_COPY_IN:
350                         /* Assume this is an expected result */
351                         AH->pgCopyIn = true;
352                         break;
353                 default:
354                         /* trouble */
355                         strncpy(errStmt, qry, DB_MAX_ERR_STMT);
356                         if (errStmt[DB_MAX_ERR_STMT - 1] != '\0')
357                         {
358                                 errStmt[DB_MAX_ERR_STMT - 4] = '.';
359                                 errStmt[DB_MAX_ERR_STMT - 3] = '.';
360                                 errStmt[DB_MAX_ERR_STMT - 2] = '.';
361                                 errStmt[DB_MAX_ERR_STMT - 1] = '\0';
362                         }
363                         warn_or_die_horribly(AH, modulename, "%s: %s    Command was: %s\n",
364                                                                  desc, PQerrorMessage(conn), errStmt);
365                         break;
366         }
367
368         PQclear(res);
369 }
370
371
372 /*
373  * Implement ahwrite() for direct-to-DB restore
374  */
375 int
376 ExecuteSqlCommandBuf(ArchiveHandle *AH, const char *buf, size_t bufLen)
377 {
378         if (AH->writingCopyData)
379         {
380                 /*
381                  * We drop the data on the floor if libpq has failed to enter COPY
382                  * mode; this allows us to behave reasonably when trying to continue
383                  * after an error in a COPY command.
384                  */
385                 if (AH->pgCopyIn &&
386                         PQputCopyData(AH->connection, buf, bufLen) <= 0)
387                         die_horribly(AH, modulename, "error returned by PQputCopyData: %s",
388                                                  PQerrorMessage(AH->connection));
389         }
390         else
391         {
392                 /*
393                  * In most cases the data passed to us will be a null-terminated
394                  * string, but if it's not, we have to add a trailing null.
395                  */
396                 if (buf[bufLen] == '\0')
397                         ExecuteSqlCommand(AH, buf, "could not execute query");
398                 else
399                 {
400                         char   *str = (char *) malloc(bufLen + 1);
401
402                         if (!str)
403                                 die_horribly(AH, modulename, "out of memory\n");
404                         memcpy(str, buf, bufLen);
405                         str[bufLen] = '\0';
406                         ExecuteSqlCommand(AH, str, "could not execute query");
407                         free(str);
408                 }
409         }
410
411         return 1;
412 }
413
414 /*
415  * Terminate a COPY operation during direct-to-DB restore
416  */
417 void
418 EndDBCopyMode(ArchiveHandle *AH, TocEntry *te)
419 {
420         if (AH->pgCopyIn)
421         {
422                 PGresult   *res;
423
424                 if (PQputCopyEnd(AH->connection, NULL) <= 0)
425                         die_horribly(AH, modulename, "error returned by PQputCopyEnd: %s",
426                                                  PQerrorMessage(AH->connection));
427
428                 /* Check command status and return to normal libpq state */
429                 res = PQgetResult(AH->connection);
430                 if (PQresultStatus(res) != PGRES_COMMAND_OK)
431                         warn_or_die_horribly(AH, modulename, "COPY failed for table \"%s\": %s",
432                                                                  te->tag, PQerrorMessage(AH->connection));
433                 PQclear(res);
434
435                 AH->pgCopyIn = false;
436         }
437 }
438
439 void
440 StartTransaction(ArchiveHandle *AH)
441 {
442         ExecuteSqlCommand(AH, "BEGIN", "could not start database transaction");
443 }
444
445 void
446 CommitTransaction(ArchiveHandle *AH)
447 {
448         ExecuteSqlCommand(AH, "COMMIT", "could not commit database transaction");
449 }
450
451 void
452 DropBlobIfExists(ArchiveHandle *AH, Oid oid)
453 {
454         /*
455          * If we are not restoring to a direct database connection, we have to
456          * guess about how to detect whether the blob exists.  Assume new-style.
457          */
458         if (AH->connection == NULL ||
459                 PQserverVersion(AH->connection) >= 90000)
460         {
461                 ahprintf(AH,
462                                  "SELECT pg_catalog.lo_unlink(oid) "
463                                  "FROM pg_catalog.pg_largeobject_metadata "
464                                  "WHERE oid = '%u';\n",
465                                  oid);
466         }
467         else
468         {
469                 /* Restoring to pre-9.0 server, so do it the old way */
470                 ahprintf(AH,
471                                  "SELECT CASE WHEN EXISTS("
472                                  "SELECT 1 FROM pg_catalog.pg_largeobject WHERE loid = '%u'"
473                                  ") THEN pg_catalog.lo_unlink('%u') END;\n",
474                                  oid, oid);
475         }
476 }