LCOV - differential code coverage report
Current view: top level - src/bin/pg_dump - pg_backup_db.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB
Current: Differential Code Coverage HEAD vs 15 Lines: 79.4 % 209 166 1 1 19 22 9 69 1 87 10 78 2
Current Date: 2023-04-08 15:15:32 Functions: 94.1 % 17 16 1 12 2 2 1 13
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           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
      33 CBC         186 : _check_database_version(ArchiveHandle *AH)
      34                 : {
      35                 :     const char *remoteversion_str;
      36                 :     int         remoteversion;
      37                 :     PGresult   *res;
      38                 : 
      39             186 :     remoteversion_str = PQparameterStatus(AH->connection, "server_version");
      40             186 :     remoteversion = PQserverVersion(AH->connection);
      41             186 :     if (remoteversion == 0 || !remoteversion_str)
      42 UBC           0 :         pg_fatal("could not get server_version from libpq");
      43                 : 
      44 CBC         186 :     AH->public.remoteVersionStr = pg_strdup(remoteversion_str);
      45             186 :     AH->public.remoteVersion = remoteversion;
      46             186 :     if (!AH->archiveRemoteVersion)
      47             131 :         AH->archiveRemoteVersion = AH->public.remoteVersionStr;
      48                 : 
      49             186 :     if (remoteversion != PG_VERSION_NUM
      50 UBC           0 :         && (remoteversion < AH->public.minRemoteVersion ||
      51               0 :             remoteversion > AH->public.maxRemoteVersion))
      52                 :     {
      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                 :      */
      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);
      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
      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);
      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
     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                 : 
     119             187 :     if (AH->connection)
     120 UBC           0 :         pg_fatal("already connected to a database");
     121                 : 
     122                 :     /* Never prompt for a password during a reconnection */
     123 CBC         187 :     prompt_password = isReconnect ? TRI_NO : cparams->promptPassword;
     124                 : 
     125             187 :     password = AH->savedPassword;
     126                 : 
     127             187 :     if (prompt_password == TRI_YES && password == NULL)
     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];
     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                 : 
     166             187 :         new_pass = false;
     167             187 :         AH->connection = PQconnectdbParams(keywords, values, true);
     168                 : 
     169             187 :         if (!AH->connection)
     170 UBC           0 :             pg_fatal("could not connect to database");
     171                 : 
     172 CBC         188 :         if (PQstatus(AH->connection) == CONNECTION_BAD &&
     173               1 :             PQconnectionNeedsPassword(AH->connection) &&
     174 UBC           0 :             password == NULL &&
     175                 :             prompt_password != TRI_NO)
     176                 :         {
     177               0 :             PQfinish(AH->connection);
     178               0 :             password = simple_prompt("Password: ", false);
     179               0 :             new_pass = true;
     180                 :         }
     181 CBC         187 :     } while (new_pass);
     182                 : 
     183                 :     /* check to see that the backend connection was successfully made */
     184             187 :     if (PQstatus(AH->connection) == CONNECTION_BAD)
     185                 :     {
     186               1 :         if (isReconnect)
     187 UBC           0 :             pg_fatal("reconnection failed: %s",
     188                 :                      PQerrorMessage(AH->connection));
     189                 :         else
     190 CBC           1 :             pg_fatal("%s",
     191                 :                      PQerrorMessage(AH->connection));
     192                 :     }
     193                 : 
     194                 :     /* Start strict; later phases may override this. */
     195             186 :     PQclear(ExecuteSqlQueryForSingleRow((Archive *) AH,
     196                 :                                         ALWAYS_SECURE_SEARCH_PATH_SQL));
     197                 : 
     198             186 :     if (password && password != AH->savedPassword)
     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                 :      */
     205 CBC         186 :     if (PQconnectionUsedPassword(AH->connection))
     206                 :     {
     207 UNC           0 :         free(AH->savedPassword);
     208 UIC           0 :         AH->savedPassword = pg_strdup(PQpass(AH->connection));
     209                 :     }
     210                 : 
     211 ECB             :     /* check for version mismatch */
     212 GIC         186 :     _check_database_version(AH);
     213 ECB             : 
     214 GIC         186 :     PQsetNoticeProcessor(AH->connection, notice_processor, NULL);
     215                 : 
     216 ECB             :     /* arrange for SIGINT to issue a query cancel on this connection */
     217 CBC         186 :     set_archive_cancel_info(AH, AH->connection);
     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                 :  */
     224 ECB             : void
     225 GIC         172 : DisconnectDatabase(Archive *AHX)
     226 ECB             : {
     227 GIC         172 :     ArchiveHandle *AH = (ArchiveHandle *) AHX;
     228                 :     char        errbuf[1];
     229 ECB             : 
     230 GBC         172 :     if (!AH->connection)
     231 UIC           0 :         return;
     232 ECB             : 
     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().
     239 ECB             :          */
     240 GBC         171 :         if (PQtransactionStatus(AH->connection) == PQTRANS_ACTIVE)
     241 UIC           0 :             (void) PQcancel(AH->connCancel, errbuf, sizeof(errbuf));
     242                 : 
     243                 :         /*
     244                 :          * Prevent signal handler from sending a cancel after this.
     245 ECB             :          */
     246 GIC         171 :         set_archive_cancel_info(AH, NULL);
     247                 :     }
     248 ECB             : 
     249 CBC         172 :     PQfinish(AH->connection);
     250 GIC         172 :     AH->connection = NULL;
     251                 : }
     252                 : 
     253 ECB             : PGconn *
     254 GIC        3311 : GetConnection(Archive *AHX)
     255 ECB             : {
     256 GIC        3311 :     ArchiveHandle *AH = (ArchiveHandle *) AHX;
     257 ECB             : 
     258 GIC        3311 :     return AH->connection;
     259                 : }
     260                 : 
     261 EUB             : static void
     262 UIC           0 : notice_processor(void *arg, const char *message)
     263 EUB             : {
     264 UBC           0 :     pg_log_info("%s", message);
     265 UIC           0 : }
     266                 : 
     267                 : /* Like pg_fatal(), but with a complaint about a particular query. */
     268 ECB             : static void
     269 GIC           2 : die_on_query_failure(ArchiveHandle *AH, const char *query)
     270 ECB             : {
     271 GIC           2 :     pg_log_error("query failed: %s",
     272 ECB             :                  PQerrorMessage(AH->connection));
     273 CBC           2 :     pg_log_error_detail("Query was: %s", query);
     274 GIC           2 :     exit(1);
     275                 : }
     276                 : 
     277 ECB             : void
     278 GIC        2338 : ExecuteSqlStatement(Archive *AHX, const char *query)
     279 ECB             : {
     280 GIC        2338 :     ArchiveHandle *AH = (ArchiveHandle *) AHX;
     281                 :     PGresult   *res;
     282 ECB             : 
     283 CBC        2338 :     res = PQexec(AH->connection, query);
     284            2338 :     if (PQresultStatus(res) != PGRES_COMMAND_OK)
     285               1 :         die_on_query_failure(AH, query);
     286            2337 :     PQclear(res);
     287 GIC        2337 : }
     288                 : 
     289 ECB             : PGresult *
     290 GIC       19417 : ExecuteSqlQuery(Archive *AHX, const char *query, ExecStatusType status)
     291 ECB             : {
     292 GIC       19417 :     ArchiveHandle *AH = (ArchiveHandle *) AHX;
     293                 :     PGresult   *res;
     294 ECB             : 
     295 CBC       19417 :     res = PQexec(AH->connection, query);
     296           19417 :     if (PQresultStatus(res) != status)
     297               1 :         die_on_query_failure(AH, query);
     298 GIC       19416 :     return res;
     299                 : }
     300                 : 
     301                 : /*
     302                 :  * Execute an SQL query and verify that we got exactly one row back.
     303                 :  */
     304 ECB             : PGresult *
     305 GIC        7913 : ExecuteSqlQueryForSingleRow(Archive *fout, const char *query)
     306                 : {
     307                 :     PGresult   *res;
     308                 :     int         ntups;
     309 ECB             : 
     310 GIC        7913 :     res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
     311                 : 
     312 ECB             :     /* Expecting a single result only */
     313 CBC        7913 :     ntups = PQntuples(res);
     314 GBC        7913 :     if (ntups != 1)
     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);
     319 ECB             : 
     320 GIC        7913 :     return res;
     321                 : }
     322                 : 
     323                 : /*
     324                 :  * Convenience function to send a query.
     325                 :  * Monitors result to detect COPY statements
     326                 :  */
     327 ECB             : static void
     328 GIC        6576 : ExecuteSqlCommand(ArchiveHandle *AH, const char *qry, const char *desc)
     329 ECB             : {
     330 GIC        6576 :     PGconn     *conn = AH->connection;
     331                 :     PGresult   *res;
     332                 : 
     333                 : #ifdef NOT_USED
     334                 :     fprintf(stderr, "Executing: '%s'\n\n", qry);
     335 ECB             : #endif
     336 GIC        6576 :     res = PQexec(conn, qry);
     337 ECB             : 
     338 GIC        6576 :     switch (PQresultStatus(res))
     339 ECB             :     {
     340 GIC        6567 :         case PGRES_COMMAND_OK:
     341                 :         case PGRES_TUPLES_OK:
     342                 :         case PGRES_EMPTY_QUERY:
     343 ECB             :             /* A-OK */
     344 CBC        6567 :             break;
     345 GIC           9 :         case PGRES_COPY_IN:
     346 ECB             :             /* Assume this is an expected result */
     347 CBC           9 :             AH->pgCopyIn = true;
     348 GBC           9 :             break;
     349 UIC           0 :         default:
     350 EUB             :             /* trouble */
     351 UIC           0 :             warn_or_exit_horribly(AH, "%s: %sCommand was: %s",
     352 EUB             :                                   desc, PQerrorMessage(conn), qry);
     353 UIC           0 :             break;
     354                 :     }
     355 ECB             : 
     356 CBC        6576 :     PQclear(res);
     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                 :  */
     379 ECB             : static void
     380 GIC          37 : ExecuteSimpleCommands(ArchiveHandle *AH, const char *buf, size_t bufLen)
     381 ECB             : {
     382 CBC          37 :     const char *qry = buf;
     383 GIC          37 :     const char *eos = buf + bufLen;
     384                 : 
     385 ECB             :     /* initialize command buffer if first time through */
     386 CBC          37 :     if (AH->sqlparse.curCmd == NULL)
     387 GIC           3 :         AH->sqlparse.curCmd = createPQExpBuffer();
     388 ECB             : 
     389 GIC      129730 :     for (; qry < eos; qry++)
     390 ECB             :     {
     391 GIC      129693 :         char        ch = *qry;
     392                 : 
     393 ECB             :         /* For neatness, we skip any newlines between commands */
     394 CBC      129693 :         if (!(ch == '\n' && AH->sqlparse.curCmd->len == 0))
     395 GIC      126679 :             appendPQExpBufferChar(AH->sqlparse.curCmd, ch);
     396 ECB             : 
     397 GIC      129693 :         switch (AH->sqlparse.state)
     398 ECB             :         {
     399 CBC      125693 :             case SQL_SCAN:      /* Default state == 0, set in _allocAH */
     400 GIC      125693 :                 if (ch == ';')
     401                 :                 {
     402                 :                     /*
     403                 :                      * We've found the end of a statement. Send it and reset
     404                 :                      * the buffer.
     405 ECB             :                      */
     406 GIC        3000 :                     ExecuteSqlCommand(AH, AH->sqlparse.curCmd->data,
     407 ECB             :                                       "could not execute query");
     408 GIC        3000 :                     resetPQExpBuffer(AH->sqlparse.curCmd);
     409 ECB             :                 }
     410 GIC      122693 :                 else if (ch == '\'')
     411 ECB             :                 {
     412 CBC        2000 :                     AH->sqlparse.state = SQL_IN_SINGLE_QUOTE;
     413 GIC        2000 :                     AH->sqlparse.backSlash = false;
     414 ECB             :                 }
     415 GIC      120693 :                 else if (ch == '"')
     416 EUB             :                 {
     417 UIC           0 :                     AH->sqlparse.state = SQL_IN_DOUBLE_QUOTE;
     418 ECB             :                 }
     419 GIC      125693 :                 break;
     420 ECB             : 
     421 GIC        4000 :             case SQL_IN_SINGLE_QUOTE:
     422 ECB             :                 /* We needn't handle '' specially */
     423 CBC        4000 :                 if (ch == '\'' && !AH->sqlparse.backSlash)
     424            2000 :                     AH->sqlparse.state = SQL_SCAN;
     425 GBC        2000 :                 else if (ch == '\\' && !AH->public.std_strings)
     426 UIC           0 :                     AH->sqlparse.backSlash = !AH->sqlparse.backSlash;
     427 ECB             :                 else
     428 CBC        2000 :                     AH->sqlparse.backSlash = false;
     429 GIC        4000 :                 break;
     430 EUB             : 
     431 UIC           0 :             case SQL_IN_DOUBLE_QUOTE:
     432 EUB             :                 /* We needn't handle "" specially */
     433 UBC           0 :                 if (ch == '"')
     434               0 :                     AH->sqlparse.state = SQL_SCAN;
     435 UIC           0 :                 break;
     436                 :         }
     437 ECB             :     }
     438 GIC          37 : }
     439                 : 
     440                 : 
     441                 : /*
     442                 :  * Implement ahwrite() for direct-to-DB restore
     443                 :  */
     444 ECB             : int
     445 GIC        3603 : ExecuteSqlCommandBuf(Archive *AHX, const char *buf, size_t bufLen)
     446 ECB             : {
     447 GIC        3603 :     ArchiveHandle *AH = (ArchiveHandle *) AHX;
     448 ECB             : 
     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.
     457 ECB             :          */
     458 CBC          20 :         if (AH->pgCopyIn &&
     459 GBC          10 :             PQputCopyData(AH->connection, buf, bufLen) <= 0)
     460 UIC           0 :             pg_fatal("error returned by PQputCopyData: %s",
     461                 :                      PQerrorMessage(AH->connection));
     462 ECB             :     }
     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).
     468 ECB             :          */
     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.
     479 ECB             :          */
     480 CBC        3556 :         if (buf[bufLen] == '\0')
     481 GIC        3556 :             ExecuteSqlCommand(AH, buf, "could not execute query");
     482                 :         else
     483 EUB             :         {
     484 UIC           0 :             char       *str = (char *) pg_malloc(bufLen + 1);
     485 EUB             : 
     486 UBC           0 :             memcpy(str, buf, bufLen);
     487               0 :             str[bufLen] = '\0';
     488               0 :             ExecuteSqlCommand(AH, str, "could not execute query");
     489 UIC           0 :             free(str);
     490                 :         }
     491                 :     }
     492 ECB             : 
     493 GIC        3603 :     return bufLen;
     494                 : }
     495                 : 
     496                 : /*
     497                 :  * Terminate a COPY operation during direct-to-DB restore
     498                 :  */
     499 ECB             : void
     500 GIC           9 : EndDBCopyMode(Archive *AHX, const char *tocEntryTag)
     501 ECB             : {
     502 GIC           9 :     ArchiveHandle *AH = (ArchiveHandle *) AHX;
     503 ECB             : 
     504 GIC           9 :     if (AH->pgCopyIn)
     505                 :     {
     506                 :         PGresult   *res;
     507 ECB             : 
     508 GBC           9 :         if (PQputCopyEnd(AH->connection, NULL) <= 0)
     509 UIC           0 :             pg_fatal("error returned by PQputCopyEnd: %s",
     510                 :                      PQerrorMessage(AH->connection));
     511                 : 
     512 ECB             :         /* Check command status and return to normal libpq state */
     513 CBC           9 :         res = PQgetResult(AH->connection);
     514 GBC           9 :         if (PQresultStatus(res) != PGRES_COMMAND_OK)
     515 UBC           0 :             warn_or_exit_horribly(AH, "COPY failed for table \"%s\": %s",
     516 LBC           0 :                                   tocEntryTag, PQerrorMessage(AH->connection));
     517 GIC           9 :         PQclear(res);
     518                 : 
     519 ECB             :         /* Do this to ensure we've pumped libpq back to idle state */
     520 GBC           9 :         if (PQgetResult(AH->connection) != NULL)
     521 UIC           0 :             pg_log_warning("unexpected extra results during COPY of table \"%s\"",
     522                 :                            tocEntryTag);
     523 ECB             : 
     524 GIC           9 :         AH->pgCopyIn = false;
     525 ECB             :     }
     526 GIC           9 : }
     527                 : 
     528 ECB             : void
     529 GIC          10 : StartTransaction(Archive *AHX)
     530 ECB             : {
     531 GIC          10 :     ArchiveHandle *AH = (ArchiveHandle *) AHX;
     532 ECB             : 
     533 CBC          10 :     ExecuteSqlCommand(AH, "BEGIN", "could not start database transaction");
     534 GIC          10 : }
     535                 : 
     536 ECB             : void
     537 GIC          10 : CommitTransaction(Archive *AHX)
     538 ECB             : {
     539 GIC          10 :     ArchiveHandle *AH = (ArchiveHandle *) AHX;
     540 ECB             : 
     541 CBC          10 :     ExecuteSqlCommand(AH, "COMMIT", "could not commit database transaction");
     542 GIC          10 : }
     543                 : 
     544 ECB             : void
     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.
     550 ECB             :      */
     551 CBC           4 :     if (AH->connection == NULL ||
     552 GIC           2 :         PQserverVersion(AH->connection) >= 90000)
     553 ECB             :     {
     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                 :     {
     562 EUB             :         /* Restoring to pre-9.0 server, so do it the old way */
     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);
     568 ECB             :     }
     569 GIC           2 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a