Age Owner TLA Line data Source code
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 : #include "postgres_fe.h"
13 :
14 : #include <unistd.h>
15 : #include <ctype.h>
16 : #ifdef HAVE_TERMIOS_H
17 : #include <termios.h>
18 : #endif
19 :
20 : #include "common/connect.h"
21 : #include "common/string.h"
22 : #include "dumputils.h"
23 : #include "fe_utils/string_utils.h"
24 : #include "parallel.h"
25 : #include "pg_backup_archiver.h"
26 : #include "pg_backup_db.h"
27 : #include "pg_backup_utils.h"
28 :
29 : static void _check_database_version(ArchiveHandle *AH);
30 : static void notice_processor(void *arg, const char *message);
31 :
32 : static void
5474 tgl 33 CBC 186 : _check_database_version(ArchiveHandle *AH)
34 : {
35 : const char *remoteversion_str;
36 : int remoteversion;
37 : PGresult *res;
38 :
7231 39 186 : remoteversion_str = PQparameterStatus(AH->connection, "server_version");
3666 heikki.linnakangas 40 186 : remoteversion = PQserverVersion(AH->connection);
41 186 : if (remoteversion == 0 || !remoteversion_str)
366 tgl 42 UBC 0 : pg_fatal("could not get server_version from libpq");
43 :
4153 bruce 44 CBC 186 : AH->public.remoteVersionStr = pg_strdup(remoteversion_str);
8019 pjw 45 186 : AH->public.remoteVersion = remoteversion;
4792 tgl 46 186 : if (!AH->archiveRemoteVersion)
47 131 : AH->archiveRemoteVersion = AH->public.remoteVersionStr;
48 :
3666 heikki.linnakangas 49 186 : if (remoteversion != PG_VERSION_NUM
7231 tgl 50 UBC 0 : && (remoteversion < AH->public.minRemoteVersion ||
51 0 : remoteversion > AH->public.maxRemoteVersion))
52 : {
366 53 0 : pg_log_error("aborting because of server version mismatch");
54 0 : pg_log_error_detail("server version: %s; %s version: %s",
55 : remoteversion_str, progname, PG_VERSION);
56 0 : exit(1);
57 : }
58 :
59 : /*
60 : * Check if server is in recovery mode, which means we are on a hot
61 : * standby.
62 : */
479 tgl 63 CBC 186 : res = ExecuteSqlQueryForSingleRow((Archive *) AH,
64 : "SELECT pg_catalog.pg_is_in_recovery()");
65 186 : AH->public.isStandby = (strcmp(PQgetvalue(res, 0, 0), "t") == 0);
66 186 : PQclear(res);
8297 pjw 67 186 : }
68 :
69 : /*
70 : * Reconnect to the server. If dbname is not NULL, use that database,
71 : * else the one associated with the archive handle.
72 : */
73 : void
927 tgl 74 13 : ReconnectToServer(ArchiveHandle *AH, const char *dbname)
75 : {
76 13 : PGconn *oldConn = AH->connection;
77 13 : RestoreOptions *ropt = AH->public.ropt;
78 :
79 : /*
80 : * Save the dbname, if given, in override_dbname so that it will also
81 : * affect any later reconnection attempt.
82 : */
83 13 : if (dbname)
84 13 : ropt->cparams.override_dbname = pg_strdup(dbname);
85 :
86 : /*
87 : * Note: we want to establish the new connection, and in particular update
88 : * ArchiveHandle's connCancel, before closing old connection. Otherwise
89 : * an ill-timed SIGINT could try to access a dead connection.
90 : */
91 13 : AH->connection = NULL; /* dodge error check in ConnectDatabase */
92 :
93 13 : ConnectDatabase((Archive *) AH, &ropt->cparams, true);
94 :
95 13 : PQfinish(oldConn);
8294 pjw 96 13 : }
97 :
98 : /*
99 : * Make, or remake, a database connection with the given parameters.
100 : *
101 : * The resulting connection handle is stored in AHX->connection.
102 : *
103 : * An interactive password prompt is automatically issued if required.
104 : * We store the results of that in AHX->savedPassword.
105 : * Note: it's not really all that sensible to use a single-entry password
106 : * cache if the username keeps changing. In current usage, however, the
107 : * username never does change, so one savedPassword is sufficient.
108 : */
109 : void
8053 bruce 110 187 : ConnectDatabase(Archive *AHX,
111 : const ConnParams *cparams,
112 : bool isReconnect)
113 : {
114 187 : ArchiveHandle *AH = (ArchiveHandle *) AHX;
115 : trivalue prompt_password;
116 : char *password;
117 : bool new_pass;
118 :
8297 pjw 119 187 : if (AH->connection)
366 tgl 120 UBC 0 : pg_fatal("already connected to a database");
121 :
122 : /* Never prompt for a password during a reconnection */
927 tgl 123 CBC 187 : prompt_password = isReconnect ? TRI_NO : cparams->promptPassword;
124 :
2413 125 187 : password = AH->savedPassword;
126 :
5155 peter_e 127 187 : if (prompt_password == TRI_YES && password == NULL)
948 tgl 128 UBC 0 : password = simple_prompt("Password: ", false);
129 :
130 : /*
131 : * Start the connection. Loop until we have a password if requested by
132 : * backend.
133 : */
134 : do
135 : {
136 : const char *keywords[8];
137 : const char *values[8];
927 tgl 138 CBC 187 : int i = 0;
139 :
140 : /*
141 : * If dbname is a connstring, its entries can override the other
142 : * values obtained from cparams; but in turn, override_dbname can
143 : * override the dbname component of it.
144 : */
145 187 : keywords[i] = "host";
146 187 : values[i++] = cparams->pghost;
147 187 : keywords[i] = "port";
148 187 : values[i++] = cparams->pgport;
149 187 : keywords[i] = "user";
150 187 : values[i++] = cparams->username;
151 187 : keywords[i] = "password";
152 187 : values[i++] = password;
153 187 : keywords[i] = "dbname";
154 187 : values[i++] = cparams->dbname;
155 187 : if (cparams->override_dbname)
156 : {
157 16 : keywords[i] = "dbname";
158 16 : values[i++] = cparams->override_dbname;
159 : }
160 187 : keywords[i] = "fallback_application_name";
161 187 : values[i++] = progname;
162 187 : keywords[i] = NULL;
163 187 : values[i++] = NULL;
164 187 : Assert(i <= lengthof(keywords));
165 :
5754 166 187 : new_pass = false;
4811 mail 167 187 : AH->connection = PQconnectdbParams(keywords, values, true);
168 :
7997 peter_e 169 187 : if (!AH->connection)
366 tgl 170 UBC 0 : pg_fatal("could not connect to database");
171 :
7997 peter_e 172 CBC 188 : if (PQstatus(AH->connection) == CONNECTION_BAD &&
5600 tgl 173 1 : PQconnectionNeedsPassword(AH->connection) &&
5155 peter_e 174 UBC 0 : password == NULL &&
175 : prompt_password != TRI_NO)
176 : {
7997 177 0 : PQfinish(AH->connection);
948 tgl 178 0 : password = simple_prompt("Password: ", false);
5754 179 0 : new_pass = true;
180 : }
5754 tgl 181 CBC 187 : } while (new_pass);
182 :
183 : /* check to see that the backend connection was successfully made */
8297 pjw 184 187 : if (PQstatus(AH->connection) == CONNECTION_BAD)
185 : {
927 tgl 186 1 : if (isReconnect)
366 tgl 187 UBC 0 : pg_fatal("reconnection failed: %s",
188 : PQerrorMessage(AH->connection));
189 : else
366 tgl 190 CBC 1 : pg_fatal("%s",
191 : PQerrorMessage(AH->connection));
192 : }
193 :
194 : /* Start strict; later phases may override this. */
1868 noah 195 186 : PQclear(ExecuteSqlQueryForSingleRow((Archive *) AH,
196 : ALWAYS_SECURE_SEARCH_PATH_SQL));
197 :
948 tgl 198 186 : if (password && password != AH->savedPassword)
948 tgl 199 UBC 0 : free(password);
200 :
201 : /*
202 : * We want to remember connection's actual password, whether or not we got
203 : * it by prompting. So we don't just store the password variable.
204 : */
2664 tgl 205 CBC 186 : if (PQconnectionUsedPassword(AH->connection))
206 : {
297 peter 207 UNC 0 : free(AH->savedPassword);
2664 tgl 208 UIC 0 : AH->savedPassword = pg_strdup(PQpass(AH->connection));
209 : }
210 :
8297 pjw 211 ECB : /* check for version mismatch */
5474 tgl 212 GIC 186 : _check_database_version(AH);
8297 pjw 213 ECB :
7910 peter_e 214 GIC 186 : PQsetNoticeProcessor(AH->connection, notice_processor, NULL);
215 :
2502 tgl 216 ECB : /* arrange for SIGINT to issue a query cancel on this connection */
2502 tgl 217 CBC 186 : set_archive_cancel_info(AH, AH->connection);
8297 pjw 218 GIC 186 : }
219 :
220 : /*
221 : * Close the connection to the database and also cancel off the query if we
222 : * have one running.
223 : */
4070 rhaas 224 ECB : void
4070 rhaas 225 GIC 172 : DisconnectDatabase(Archive *AHX)
4070 rhaas 226 ECB : {
4070 rhaas 227 GIC 172 : ArchiveHandle *AH = (ArchiveHandle *) AHX;
228 : char errbuf[1];
3668 andrew 229 ECB :
3668 andrew 230 GBC 172 : if (!AH->connection)
3668 andrew 231 UIC 0 : return;
4070 rhaas 232 ECB :
2502 tgl 233 GIC 172 : if (AH->connCancel)
234 : {
235 : /*
236 : * If we have an active query, send a cancel before closing, ignoring
237 : * any errors. This is of no use for a normal exit, but might be
238 : * helpful during pg_fatal().
2502 tgl 239 ECB : */
2502 tgl 240 GBC 171 : if (PQtransactionStatus(AH->connection) == PQTRANS_ACTIVE)
2161 alvherre 241 UIC 0 : (void) PQcancel(AH->connCancel, errbuf, sizeof(errbuf));
242 :
243 : /*
244 : * Prevent signal handler from sending a cancel after this.
2502 tgl 245 ECB : */
2502 tgl 246 GIC 171 : set_archive_cancel_info(AH, NULL);
247 : }
3668 andrew 248 ECB :
3668 andrew 249 CBC 172 : PQfinish(AH->connection);
4070 rhaas 250 GIC 172 : AH->connection = NULL;
251 : }
252 :
4070 rhaas 253 ECB : PGconn *
4070 rhaas 254 GIC 3311 : GetConnection(Archive *AHX)
4070 rhaas 255 ECB : {
4070 rhaas 256 GIC 3311 : ArchiveHandle *AH = (ArchiveHandle *) AHX;
4070 rhaas 257 ECB :
4070 rhaas 258 GIC 3311 : return AH->connection;
259 : }
260 :
7836 bruce 261 EUB : static void
7836 bruce 262 UIC 0 : notice_processor(void *arg, const char *message)
7910 peter_e 263 EUB : {
366 tgl 264 UBC 0 : pg_log_info("%s", message);
7910 peter_e 265 UIC 0 : }
266 :
267 : /* Like pg_fatal(), but with a complaint about a particular query. */
4037 alvherre 268 ECB : static void
1469 peter 269 GIC 2 : die_on_query_failure(ArchiveHandle *AH, const char *query)
4037 alvherre 270 ECB : {
1469 peter 271 GIC 2 : pg_log_error("query failed: %s",
1418 tgl 272 ECB : PQerrorMessage(AH->connection));
366 tgl 273 CBC 2 : pg_log_error_detail("Query was: %s", query);
366 tgl 274 GIC 2 : exit(1);
275 : }
276 :
4079 rhaas 277 ECB : void
4079 rhaas 278 GIC 2338 : ExecuteSqlStatement(Archive *AHX, const char *query)
4079 rhaas 279 ECB : {
3955 bruce 280 GIC 2338 : ArchiveHandle *AH = (ArchiveHandle *) AHX;
281 : PGresult *res;
4079 rhaas 282 ECB :
4079 rhaas 283 CBC 2338 : res = PQexec(AH->connection, query);
284 2338 : if (PQresultStatus(res) != PGRES_COMMAND_OK)
1469 peter 285 1 : die_on_query_failure(AH, query);
4079 rhaas 286 2337 : PQclear(res);
4079 rhaas 287 GIC 2337 : }
288 :
4079 rhaas 289 ECB : PGresult *
4079 rhaas 290 GIC 19417 : ExecuteSqlQuery(Archive *AHX, const char *query, ExecStatusType status)
4079 rhaas 291 ECB : {
3955 bruce 292 GIC 19417 : ArchiveHandle *AH = (ArchiveHandle *) AHX;
293 : PGresult *res;
4079 rhaas 294 ECB :
4079 rhaas 295 CBC 19417 : res = PQexec(AH->connection, query);
296 19417 : if (PQresultStatus(res) != status)
1469 peter 297 1 : die_on_query_failure(AH, query);
4079 rhaas 298 GIC 19416 : return res;
299 : }
300 :
301 : /*
302 : * Execute an SQL query and verify that we got exactly one row back.
303 : */
2509 magnus 304 ECB : PGresult *
1986 peter_e 305 GIC 7913 : ExecuteSqlQueryForSingleRow(Archive *fout, const char *query)
306 : {
307 : PGresult *res;
308 : int ntups;
2509 magnus 309 ECB :
2509 magnus 310 GIC 7913 : res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
311 :
2509 magnus 312 ECB : /* Expecting a single result only */
2509 magnus 313 CBC 7913 : ntups = PQntuples(res);
2509 magnus 314 GBC 7913 : if (ntups != 1)
366 tgl 315 UIC 0 : pg_fatal(ngettext("query returned %d row instead of one: %s",
316 : "query returned %d rows instead of one: %s",
317 : ntups),
318 : ntups, query);
2509 magnus 319 ECB :
2509 magnus 320 GIC 7913 : return res;
321 : }
322 :
323 : /*
324 : * Convenience function to send a query.
325 : * Monitors result to detect COPY statements
326 : */
5349 tgl 327 ECB : static void
5349 tgl 328 GIC 6576 : ExecuteSqlCommand(ArchiveHandle *AH, const char *qry, const char *desc)
8297 pjw 329 ECB : {
6501 tgl 330 GIC 6576 : PGconn *conn = AH->connection;
331 : PGresult *res;
332 :
333 : #ifdef NOT_USED
334 : fprintf(stderr, "Executing: '%s'\n\n", qry);
5349 tgl 335 ECB : #endif
5349 tgl 336 GIC 6576 : res = PQexec(conn, qry);
8297 pjw 337 ECB :
5349 tgl 338 GIC 6576 : switch (PQresultStatus(res))
8297 pjw 339 ECB : {
5349 tgl 340 GIC 6567 : case PGRES_COMMAND_OK:
341 : case PGRES_TUPLES_OK:
342 : case PGRES_EMPTY_QUERY:
5349 tgl 343 ECB : /* A-OK */
5349 tgl 344 CBC 6567 : break;
5349 tgl 345 GIC 9 : case PGRES_COPY_IN:
5349 tgl 346 ECB : /* Assume this is an expected result */
6272 tgl 347 CBC 9 : AH->pgCopyIn = true;
5349 tgl 348 GBC 9 : break;
5349 tgl 349 UIC 0 : default:
5349 tgl 350 EUB : /* trouble */
1469 peter 351 UIC 0 : warn_or_exit_horribly(AH, "%s: %sCommand was: %s",
2202 peter_e 352 EUB : desc, PQerrorMessage(conn), qry);
5349 tgl 353 UIC 0 : break;
354 : }
8297 pjw 355 ECB :
8297 pjw 356 CBC 6576 : PQclear(res);
8297 pjw 357 GIC 6576 : }
358 :
359 :
360 : /*
361 : * Process non-COPY table data (that is, INSERT commands).
362 : *
363 : * The commands have been run together as one long string for compressibility,
364 : * and we are receiving them in bufferloads with arbitrary boundaries, so we
365 : * have to locate command boundaries and save partial commands across calls.
366 : * All state must be kept in AH->sqlparse, not in local variables of this
367 : * routine. We assume that AH->sqlparse was filled with zeroes when created.
368 : *
369 : * We have to lex the data to the extent of identifying literals and quoted
370 : * identifiers, so that we can recognize statement-terminating semicolons.
371 : * We assume that INSERT data will not contain SQL comments, E'' literals,
372 : * or dollar-quoted strings, so this is much simpler than a full SQL lexer.
373 : *
374 : * Note: when restoring from a pre-9.0 dump file, this code is also used to
375 : * process BLOB COMMENTS data, which has the same problem of containing
376 : * multiple SQL commands that might be split across bufferloads. Fortunately,
377 : * that data won't contain anything complicated to lex either.
378 : */
4111 tgl 379 ECB : static void
3223 tgl 380 GIC 37 : ExecuteSimpleCommands(ArchiveHandle *AH, const char *buf, size_t bufLen)
4111 tgl 381 ECB : {
4111 tgl 382 CBC 37 : const char *qry = buf;
4111 tgl 383 GIC 37 : const char *eos = buf + bufLen;
384 :
4111 tgl 385 ECB : /* initialize command buffer if first time through */
4111 tgl 386 CBC 37 : if (AH->sqlparse.curCmd == NULL)
4111 tgl 387 GIC 3 : AH->sqlparse.curCmd = createPQExpBuffer();
4111 tgl 388 ECB :
4111 tgl 389 GIC 129730 : for (; qry < eos; qry++)
4111 tgl 390 ECB : {
3955 bruce 391 GIC 129693 : char ch = *qry;
392 :
4111 tgl 393 ECB : /* For neatness, we skip any newlines between commands */
4111 tgl 394 CBC 129693 : if (!(ch == '\n' && AH->sqlparse.curCmd->len == 0))
4111 tgl 395 GIC 126679 : appendPQExpBufferChar(AH->sqlparse.curCmd, ch);
4111 tgl 396 ECB :
4111 tgl 397 GIC 129693 : switch (AH->sqlparse.state)
4111 tgl 398 ECB : {
4111 tgl 399 CBC 125693 : case SQL_SCAN: /* Default state == 0, set in _allocAH */
4111 tgl 400 GIC 125693 : if (ch == ';')
401 : {
402 : /*
403 : * We've found the end of a statement. Send it and reset
404 : * the buffer.
4111 tgl 405 ECB : */
4111 tgl 406 GIC 3000 : ExecuteSqlCommand(AH, AH->sqlparse.curCmd->data,
4111 tgl 407 ECB : "could not execute query");
4111 tgl 408 GIC 3000 : resetPQExpBuffer(AH->sqlparse.curCmd);
4111 tgl 409 ECB : }
4111 tgl 410 GIC 122693 : else if (ch == '\'')
4111 tgl 411 ECB : {
4111 tgl 412 CBC 2000 : AH->sqlparse.state = SQL_IN_SINGLE_QUOTE;
4111 tgl 413 GIC 2000 : AH->sqlparse.backSlash = false;
4111 tgl 414 ECB : }
4111 tgl 415 GIC 120693 : else if (ch == '"')
4111 tgl 416 EUB : {
4111 tgl 417 UIC 0 : AH->sqlparse.state = SQL_IN_DOUBLE_QUOTE;
4111 tgl 418 ECB : }
4111 tgl 419 GIC 125693 : break;
4111 tgl 420 ECB :
4111 tgl 421 GIC 4000 : case SQL_IN_SINGLE_QUOTE:
4111 tgl 422 ECB : /* We needn't handle '' specially */
4111 tgl 423 CBC 4000 : if (ch == '\'' && !AH->sqlparse.backSlash)
424 2000 : AH->sqlparse.state = SQL_SCAN;
4111 tgl 425 GBC 2000 : else if (ch == '\\' && !AH->public.std_strings)
4111 tgl 426 UIC 0 : AH->sqlparse.backSlash = !AH->sqlparse.backSlash;
4111 tgl 427 ECB : else
4111 tgl 428 CBC 2000 : AH->sqlparse.backSlash = false;
4111 tgl 429 GIC 4000 : break;
4111 tgl 430 EUB :
4111 tgl 431 UIC 0 : case SQL_IN_DOUBLE_QUOTE:
4111 tgl 432 EUB : /* We needn't handle "" specially */
4111 tgl 433 UBC 0 : if (ch == '"')
434 0 : AH->sqlparse.state = SQL_SCAN;
4111 tgl 435 UIC 0 : break;
436 : }
4111 tgl 437 ECB : }
4111 tgl 438 GIC 37 : }
439 :
440 :
441 : /*
442 : * Implement ahwrite() for direct-to-DB restore
443 : */
4273 tgl 444 ECB : int
3099 alvherre 445 GIC 3603 : ExecuteSqlCommandBuf(Archive *AHX, const char *buf, size_t bufLen)
8297 pjw 446 ECB : {
3099 alvherre 447 GIC 3603 : ArchiveHandle *AH = (ArchiveHandle *) AHX;
3099 alvherre 448 ECB :
4111 tgl 449 GIC 3603 : if (AH->outputKind == OUTPUT_COPYDATA)
450 : {
451 : /*
452 : * COPY data.
453 : *
454 : * We drop the data on the floor if libpq has failed to enter COPY
455 : * mode; this allows us to behave reasonably when trying to continue
456 : * after an error in a COPY command.
7751 tgl 457 ECB : */
4273 tgl 458 CBC 20 : if (AH->pgCopyIn &&
4273 tgl 459 GBC 10 : PQputCopyData(AH->connection, buf, bufLen) <= 0)
366 tgl 460 UIC 0 : pg_fatal("error returned by PQputCopyData: %s",
461 : PQerrorMessage(AH->connection));
4273 tgl 462 ECB : }
4111 tgl 463 GIC 3593 : else if (AH->outputKind == OUTPUT_OTHERDATA)
464 : {
465 : /*
466 : * Table data expressed as INSERT commands; or, in old dump files,
467 : * BLOB COMMENTS data (which is expressed as COMMENT ON commands).
4111 tgl 468 ECB : */
3223 tgl 469 GIC 37 : ExecuteSimpleCommands(AH, buf, bufLen);
470 : }
471 : else
472 : {
473 : /*
474 : * General SQL commands; we assume that commands will not be split
475 : * across calls.
476 : *
477 : * In most cases the data passed to us will be a null-terminated
478 : * string, but if it's not, we have to add a trailing null.
7751 tgl 479 ECB : */
4273 tgl 480 CBC 3556 : if (buf[bufLen] == '\0')
4273 tgl 481 GIC 3556 : ExecuteSqlCommand(AH, buf, "could not execute query");
482 : else
7751 tgl 483 EUB : {
3955 bruce 484 UIC 0 : char *str = (char *) pg_malloc(bufLen + 1);
4273 tgl 485 EUB :
4273 tgl 486 UBC 0 : memcpy(str, buf, bufLen);
487 0 : str[bufLen] = '\0';
488 0 : ExecuteSqlCommand(AH, str, "could not execute query");
4273 tgl 489 UIC 0 : free(str);
490 : }
491 : }
8297 pjw 492 ECB :
3261 bruce 493 GIC 3603 : return bufLen;
494 : }
495 :
496 : /*
497 : * Terminate a COPY operation during direct-to-DB restore
498 : */
4273 tgl 499 ECB : void
3099 alvherre 500 GIC 9 : EndDBCopyMode(Archive *AHX, const char *tocEntryTag)
4273 tgl 501 ECB : {
3099 alvherre 502 GIC 9 : ArchiveHandle *AH = (ArchiveHandle *) AHX;
3099 alvherre 503 ECB :
4273 tgl 504 GIC 9 : if (AH->pgCopyIn)
505 : {
506 : PGresult *res;
6246 tgl 507 ECB :
6246 tgl 508 GBC 9 : if (PQputCopyEnd(AH->connection, NULL) <= 0)
366 tgl 509 UIC 0 : pg_fatal("error returned by PQputCopyEnd: %s",
510 : PQerrorMessage(AH->connection));
511 :
6246 tgl 512 ECB : /* Check command status and return to normal libpq state */
6246 tgl 513 CBC 9 : res = PQgetResult(AH->connection);
6246 tgl 514 GBC 9 : if (PQresultStatus(res) != PGRES_COMMAND_OK)
1469 peter 515 UBC 0 : warn_or_exit_horribly(AH, "COPY failed for table \"%s\": %s",
2118 tgl 516 LBC 0 : tocEntryTag, PQerrorMessage(AH->connection));
6246 tgl 517 GIC 9 : PQclear(res);
518 :
2502 tgl 519 ECB : /* Do this to ensure we've pumped libpq back to idle state */
2502 tgl 520 GBC 9 : if (PQgetResult(AH->connection) != NULL)
1469 peter 521 UIC 0 : pg_log_warning("unexpected extra results during COPY of table \"%s\"",
522 : tocEntryTag);
2502 tgl 523 ECB :
6272 tgl 524 GIC 9 : AH->pgCopyIn = false;
7751 tgl 525 ECB : }
8297 pjw 526 GIC 9 : }
527 :
8053 bruce 528 ECB : void
3099 alvherre 529 GIC 10 : StartTransaction(Archive *AHX)
8297 pjw 530 ECB : {
3099 alvherre 531 GIC 10 : ArchiveHandle *AH = (ArchiveHandle *) AHX;
3099 alvherre 532 ECB :
5349 tgl 533 CBC 10 : ExecuteSqlCommand(AH, "BEGIN", "could not start database transaction");
8297 pjw 534 GIC 10 : }
535 :
8053 bruce 536 ECB : void
3099 alvherre 537 GIC 10 : CommitTransaction(Archive *AHX)
8297 pjw 538 ECB : {
3099 alvherre 539 GIC 10 : ArchiveHandle *AH = (ArchiveHandle *) AHX;
3099 alvherre 540 ECB :
5349 tgl 541 CBC 10 : ExecuteSqlCommand(AH, "COMMIT", "could not commit database transaction");
8195 pjw 542 GIC 10 : }
543 :
4864 itagaki.takahiro 544 ECB : void
125 peter 545 GNC 2 : DropLOIfExists(ArchiveHandle *AH, Oid oid)
546 : {
547 : /*
548 : * If we are not restoring to a direct database connection, we have to
549 : * guess about how to detect whether the LO exists. Assume new-style.
4798 tgl 550 ECB : */
4798 tgl 551 CBC 4 : if (AH->connection == NULL ||
4798 tgl 552 GIC 2 : PQserverVersion(AH->connection) >= 90000)
4864 itagaki.takahiro 553 ECB : {
4798 tgl 554 GIC 2 : ahprintf(AH,
555 : "SELECT pg_catalog.lo_unlink(oid) "
556 : "FROM pg_catalog.pg_largeobject_metadata "
557 : "WHERE oid = '%u';\n",
558 : oid);
559 : }
560 : else
561 : {
4798 tgl 562 EUB : /* Restoring to pre-9.0 server, so do it the old way */
4798 tgl 563 UIC 0 : ahprintf(AH,
564 : "SELECT CASE WHEN EXISTS("
565 : "SELECT 1 FROM pg_catalog.pg_largeobject WHERE loid = '%u'"
566 : ") THEN pg_catalog.lo_unlink('%u') END;\n",
567 : oid, oid);
4864 itagaki.takahiro 568 ECB : }
4864 itagaki.takahiro 569 GIC 2 : }
|