LCOV - code coverage report
Current view: top level - contrib/vacuumlo - vacuumlo.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 15.8 % 273 43
Test Date: 2026-07-03 19:57:34 Functions: 66.7 % 3 2
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 7.7 % 117 9

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * vacuumlo.c
       4                 :             :  *    This removes orphaned large objects from a database.
       5                 :             :  *
       6                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       7                 :             :  * Portions Copyright (c) 1994, Regents of the University of California
       8                 :             :  *
       9                 :             :  *
      10                 :             :  * IDENTIFICATION
      11                 :             :  *    contrib/vacuumlo/vacuumlo.c
      12                 :             :  *
      13                 :             :  *-------------------------------------------------------------------------
      14                 :             :  */
      15                 :             : #include "postgres_fe.h"
      16                 :             : 
      17                 :             : #include <sys/stat.h>
      18                 :             : #include <fcntl.h>
      19                 :             : #include <unistd.h>
      20                 :             : #ifdef HAVE_TERMIOS_H
      21                 :             : #include <termios.h>
      22                 :             : #endif
      23                 :             : 
      24                 :             : #include "catalog/pg_class_d.h"
      25                 :             : #include "common/connect.h"
      26                 :             : #include "common/logging.h"
      27                 :             : #include "common/string.h"
      28                 :             : #include "getopt_long.h"
      29                 :             : #include "libpq-fe.h"
      30                 :             : #include "pg_getopt.h"
      31                 :             : 
      32                 :             : #define BUFSIZE         1024
      33                 :             : 
      34                 :             : enum trivalue
      35                 :             : {
      36                 :             :     TRI_DEFAULT,
      37                 :             :     TRI_NO,
      38                 :             :     TRI_YES,
      39                 :             : };
      40                 :             : 
      41                 :             : struct _param
      42                 :             : {
      43                 :             :     char       *pg_user;
      44                 :             :     enum trivalue pg_prompt;
      45                 :             :     char       *pg_port;
      46                 :             :     char       *pg_host;
      47                 :             :     const char *progname;
      48                 :             :     int         verbose;
      49                 :             :     int         dry_run;
      50                 :             :     long        transaction_limit;
      51                 :             : };
      52                 :             : 
      53                 :             : static int  vacuumlo(const char *database, const struct _param *param);
      54                 :             : static void usage(const char *progname);
      55                 :             : 
      56                 :             : 
      57                 :             : 
      58                 :             : /*
      59                 :             :  * This vacuums LOs of one database. It returns 0 on success, -1 on failure.
      60                 :             :  */
      61                 :             : static int
      62                 :           0 : vacuumlo(const char *database, const struct _param *param)
      63                 :             : {
      64                 :             :     PGconn     *conn;
      65                 :             :     PGresult   *res,
      66                 :             :                *res2;
      67                 :             :     char        buf[BUFSIZE];
      68                 :             :     long        matched;
      69                 :             :     long        deleted;
      70                 :             :     int         i;
      71                 :             :     bool        new_pass;
      72                 :           0 :     bool        success = true;
      73                 :             :     static char *password = NULL;
      74                 :             : 
      75                 :             :     /* Note: password can be carried over from a previous call */
      76   [ #  #  #  # ]:           0 :     if (param->pg_prompt == TRI_YES && !password)
      77                 :           0 :         password = simple_prompt("Password: ", false);
      78                 :             : 
      79                 :             :     /*
      80                 :             :      * Start the connection.  Loop until we have a password if requested by
      81                 :             :      * backend.
      82                 :             :      */
      83                 :             :     do
      84                 :             :     {
      85                 :             : #define PARAMS_ARRAY_SIZE      7
      86                 :             : 
      87                 :             :         const char *keywords[PARAMS_ARRAY_SIZE];
      88                 :             :         const char *values[PARAMS_ARRAY_SIZE];
      89                 :             : 
      90                 :           0 :         keywords[0] = "host";
      91                 :           0 :         values[0] = param->pg_host;
      92                 :           0 :         keywords[1] = "port";
      93                 :           0 :         values[1] = param->pg_port;
      94                 :           0 :         keywords[2] = "user";
      95                 :           0 :         values[2] = param->pg_user;
      96                 :           0 :         keywords[3] = "password";
      97                 :           0 :         values[3] = password;
      98                 :           0 :         keywords[4] = "dbname";
      99                 :           0 :         values[4] = database;
     100                 :           0 :         keywords[5] = "fallback_application_name";
     101                 :           0 :         values[5] = param->progname;
     102                 :           0 :         keywords[6] = NULL;
     103                 :           0 :         values[6] = NULL;
     104                 :             : 
     105                 :           0 :         new_pass = false;
     106                 :           0 :         conn = PQconnectdbParams(keywords, values, true);
     107         [ #  # ]:           0 :         if (!conn)
     108                 :             :         {
     109                 :           0 :             pg_log_error("connection to database \"%s\" failed", database);
     110                 :           0 :             return -1;
     111                 :             :         }
     112                 :             : 
     113   [ #  #  #  # ]:           0 :         if (PQstatus(conn) == CONNECTION_BAD &&
     114                 :           0 :             PQconnectionNeedsPassword(conn) &&
     115         [ #  # ]:           0 :             !password &&
     116         [ #  # ]:           0 :             param->pg_prompt != TRI_NO)
     117                 :             :         {
     118                 :           0 :             PQfinish(conn);
     119                 :           0 :             password = simple_prompt("Password: ", false);
     120                 :           0 :             new_pass = true;
     121                 :             :         }
     122         [ #  # ]:           0 :     } while (new_pass);
     123                 :             : 
     124                 :             :     /* check to see that the backend connection was successfully made */
     125         [ #  # ]:           0 :     if (PQstatus(conn) == CONNECTION_BAD)
     126                 :             :     {
     127                 :           0 :         pg_log_error("%s", PQerrorMessage(conn));
     128                 :           0 :         PQfinish(conn);
     129                 :           0 :         return -1;
     130                 :             :     }
     131                 :             : 
     132         [ #  # ]:           0 :     if (param->verbose)
     133                 :             :     {
     134                 :           0 :         fprintf(stdout, "Connected to database \"%s\"\n", database);
     135         [ #  # ]:           0 :         if (param->dry_run)
     136                 :           0 :             fprintf(stdout, "Test run: no large objects will be removed!\n");
     137                 :             :     }
     138                 :             : 
     139                 :           0 :     res = PQexec(conn, ALWAYS_SECURE_SEARCH_PATH_SQL);
     140         [ #  # ]:           0 :     if (PQresultStatus(res) != PGRES_TUPLES_OK)
     141                 :             :     {
     142                 :           0 :         pg_log_error("failed to set \"search_path\": %s", PQerrorMessage(conn));
     143                 :           0 :         PQclear(res);
     144                 :           0 :         PQfinish(conn);
     145                 :           0 :         return -1;
     146                 :             :     }
     147                 :           0 :     PQclear(res);
     148                 :             : 
     149                 :             :     /*
     150                 :             :      * First we create and populate the LO temp table
     151                 :             :      */
     152                 :           0 :     buf[0] = '\0';
     153                 :           0 :     strcat(buf, "CREATE TEMP TABLE vacuum_l AS ");
     154         [ #  # ]:           0 :     if (PQserverVersion(conn) >= 90000)
     155                 :           0 :         strcat(buf, "SELECT oid AS lo FROM pg_largeobject_metadata");
     156                 :             :     else
     157                 :           0 :         strcat(buf, "SELECT DISTINCT loid AS lo FROM pg_largeobject");
     158                 :           0 :     res = PQexec(conn, buf);
     159         [ #  # ]:           0 :     if (PQresultStatus(res) != PGRES_COMMAND_OK)
     160                 :             :     {
     161                 :           0 :         pg_log_error("failed to create temp table: %s", PQerrorMessage(conn));
     162                 :           0 :         PQclear(res);
     163                 :           0 :         PQfinish(conn);
     164                 :           0 :         return -1;
     165                 :             :     }
     166                 :           0 :     PQclear(res);
     167                 :             : 
     168                 :             :     /*
     169                 :             :      * Analyze the temp table so that planner will generate decent plans for
     170                 :             :      * the DELETEs below.
     171                 :             :      */
     172                 :           0 :     buf[0] = '\0';
     173                 :           0 :     strcat(buf, "ANALYZE vacuum_l");
     174                 :           0 :     res = PQexec(conn, buf);
     175         [ #  # ]:           0 :     if (PQresultStatus(res) != PGRES_COMMAND_OK)
     176                 :             :     {
     177                 :           0 :         pg_log_error("failed to vacuum temp table: %s", PQerrorMessage(conn));
     178                 :           0 :         PQclear(res);
     179                 :           0 :         PQfinish(conn);
     180                 :           0 :         return -1;
     181                 :             :     }
     182                 :           0 :     PQclear(res);
     183                 :             : 
     184                 :             :     /*
     185                 :             :      * Now find any candidate tables that have columns of type oid.
     186                 :             :      *
     187                 :             :      * NOTE: we ignore system tables and temp tables by the expedient of
     188                 :             :      * rejecting tables in schemas named 'pg_*'.  In particular, the temp
     189                 :             :      * table formed above is ignored, and pg_largeobject will be too. If
     190                 :             :      * either of these were scanned, obviously we'd end up with nothing to
     191                 :             :      * delete...
     192                 :             :      */
     193                 :           0 :     buf[0] = '\0';
     194                 :           0 :     strcat(buf, "SELECT s.nspname, c.relname, a.attname ");
     195                 :           0 :     strcat(buf, "FROM pg_class c, pg_attribute a, pg_namespace s, pg_type t ");
     196                 :           0 :     strcat(buf, "WHERE a.attnum > 0 AND NOT a.attisdropped ");
     197                 :           0 :     strcat(buf, "      AND a.attrelid = c.oid ");
     198                 :           0 :     strcat(buf, "      AND a.atttypid = t.oid ");
     199                 :           0 :     strcat(buf, "      AND c.relnamespace = s.oid ");
     200                 :           0 :     strcat(buf, "      AND t.typname in ('oid', 'lo') ");
     201                 :           0 :     strcat(buf, "      AND c.relkind in (" CppAsString2(RELKIND_RELATION) ", " CppAsString2(RELKIND_MATVIEW) ")");
     202                 :           0 :     strcat(buf, "      AND s.nspname !~ '^pg_'");
     203                 :           0 :     res = PQexec(conn, buf);
     204         [ #  # ]:           0 :     if (PQresultStatus(res) != PGRES_TUPLES_OK)
     205                 :             :     {
     206                 :           0 :         pg_log_error("failed to find OID columns: %s", PQerrorMessage(conn));
     207                 :           0 :         PQclear(res);
     208                 :           0 :         PQfinish(conn);
     209                 :           0 :         return -1;
     210                 :             :     }
     211                 :             : 
     212         [ #  # ]:           0 :     for (i = 0; i < PQntuples(res); i++)
     213                 :             :     {
     214                 :             :         char       *schema,
     215                 :             :                    *table,
     216                 :             :                    *field;
     217                 :             : 
     218                 :           0 :         schema = PQgetvalue(res, i, 0);
     219                 :           0 :         table = PQgetvalue(res, i, 1);
     220                 :           0 :         field = PQgetvalue(res, i, 2);
     221                 :             : 
     222         [ #  # ]:           0 :         if (param->verbose)
     223                 :           0 :             fprintf(stdout, "Checking %s in %s.%s\n", field, schema, table);
     224                 :             : 
     225                 :           0 :         schema = PQescapeIdentifier(conn, schema, strlen(schema));
     226                 :           0 :         table = PQescapeIdentifier(conn, table, strlen(table));
     227                 :           0 :         field = PQescapeIdentifier(conn, field, strlen(field));
     228                 :             : 
     229   [ #  #  #  #  :           0 :         if (!schema || !table || !field)
                   #  # ]
     230                 :             :         {
     231                 :           0 :             pg_log_error("%s", PQerrorMessage(conn));
     232                 :           0 :             PQclear(res);
     233                 :           0 :             PQfinish(conn);
     234                 :           0 :             PQfreemem(schema);
     235                 :           0 :             PQfreemem(table);
     236                 :           0 :             PQfreemem(field);
     237                 :           0 :             return -1;
     238                 :             :         }
     239                 :             : 
     240                 :           0 :         snprintf(buf, BUFSIZE,
     241                 :             :                  "DELETE FROM vacuum_l "
     242                 :             :                  "WHERE lo IN (SELECT %s FROM %s.%s)",
     243                 :             :                  field, schema, table);
     244                 :           0 :         res2 = PQexec(conn, buf);
     245         [ #  # ]:           0 :         if (PQresultStatus(res2) != PGRES_COMMAND_OK)
     246                 :             :         {
     247                 :           0 :             pg_log_error("failed to check %s in table %s.%s: %s",
     248                 :             :                          field, schema, table, PQerrorMessage(conn));
     249                 :           0 :             PQclear(res2);
     250                 :           0 :             PQclear(res);
     251                 :           0 :             PQfinish(conn);
     252                 :           0 :             PQfreemem(schema);
     253                 :           0 :             PQfreemem(table);
     254                 :           0 :             PQfreemem(field);
     255                 :           0 :             return -1;
     256                 :             :         }
     257                 :           0 :         PQclear(res2);
     258                 :             : 
     259                 :           0 :         PQfreemem(schema);
     260                 :           0 :         PQfreemem(table);
     261                 :           0 :         PQfreemem(field);
     262                 :             :     }
     263                 :           0 :     PQclear(res);
     264                 :             : 
     265                 :             :     /*
     266                 :             :      * Now, those entries remaining in vacuum_l are orphans.  Delete 'em.
     267                 :             :      *
     268                 :             :      * We don't want to run each delete as an individual transaction, because
     269                 :             :      * the commit overhead would be high.  However, since 9.0 the backend will
     270                 :             :      * acquire a lock per deleted LO, so deleting too many LOs per transaction
     271                 :             :      * risks running out of room in the shared-memory lock table. Accordingly,
     272                 :             :      * we delete up to transaction_limit LOs per transaction.
     273                 :             :      */
     274                 :           0 :     res = PQexec(conn, "begin");
     275         [ #  # ]:           0 :     if (PQresultStatus(res) != PGRES_COMMAND_OK)
     276                 :             :     {
     277                 :           0 :         pg_log_error("failed to start transaction: %s", PQerrorMessage(conn));
     278                 :           0 :         PQclear(res);
     279                 :           0 :         PQfinish(conn);
     280                 :           0 :         return -1;
     281                 :             :     }
     282                 :           0 :     PQclear(res);
     283                 :             : 
     284                 :           0 :     buf[0] = '\0';
     285                 :           0 :     strcat(buf,
     286                 :             :            "DECLARE myportal CURSOR WITH HOLD FOR SELECT lo FROM vacuum_l");
     287                 :           0 :     res = PQexec(conn, buf);
     288         [ #  # ]:           0 :     if (PQresultStatus(res) != PGRES_COMMAND_OK)
     289                 :             :     {
     290                 :           0 :         pg_log_error("DECLARE CURSOR failed: %s", PQerrorMessage(conn));
     291                 :           0 :         PQclear(res);
     292                 :           0 :         PQfinish(conn);
     293                 :           0 :         return -1;
     294                 :             :     }
     295                 :           0 :     PQclear(res);
     296                 :             : 
     297                 :           0 :     snprintf(buf, BUFSIZE, "FETCH FORWARD %ld IN myportal",
     298         [ #  # ]:           0 :              param->transaction_limit > 0 ? param->transaction_limit : 1000L);
     299                 :             : 
     300                 :           0 :     deleted = 0;
     301                 :             : 
     302                 :             :     do
     303                 :             :     {
     304                 :           0 :         res = PQexec(conn, buf);
     305         [ #  # ]:           0 :         if (PQresultStatus(res) != PGRES_TUPLES_OK)
     306                 :             :         {
     307                 :           0 :             pg_log_error("FETCH FORWARD failed: %s", PQerrorMessage(conn));
     308                 :           0 :             PQclear(res);
     309                 :           0 :             PQfinish(conn);
     310                 :           0 :             return -1;
     311                 :             :         }
     312                 :             : 
     313                 :           0 :         matched = PQntuples(res);
     314         [ #  # ]:           0 :         if (matched <= 0)
     315                 :             :         {
     316                 :             :             /* at end of resultset */
     317                 :           0 :             PQclear(res);
     318                 :           0 :             break;
     319                 :             :         }
     320                 :             : 
     321         [ #  # ]:           0 :         for (i = 0; i < matched; i++)
     322                 :             :         {
     323                 :           0 :             Oid         lo = atooid(PQgetvalue(res, i, 0));
     324                 :             : 
     325         [ #  # ]:           0 :             if (param->verbose)
     326                 :             :             {
     327                 :           0 :                 fprintf(stdout, "\rRemoving lo %6u   ", lo);
     328                 :           0 :                 fflush(stdout);
     329                 :             :             }
     330                 :             : 
     331         [ #  # ]:           0 :             if (param->dry_run == 0)
     332                 :             :             {
     333         [ #  # ]:           0 :                 if (lo_unlink(conn, lo) < 0)
     334                 :             :                 {
     335                 :           0 :                     pg_log_error("failed to remove lo %u: %s", lo,
     336                 :             :                                  PQerrorMessage(conn));
     337         [ #  # ]:           0 :                     if (PQtransactionStatus(conn) == PQTRANS_INERROR)
     338                 :             :                     {
     339                 :           0 :                         success = false;
     340                 :           0 :                         break;  /* out of inner for-loop */
     341                 :             :                     }
     342                 :             :                 }
     343                 :             :                 else
     344                 :           0 :                     deleted++;
     345                 :             :             }
     346                 :             :             else
     347                 :           0 :                 deleted++;
     348                 :             : 
     349         [ #  # ]:           0 :             if (param->transaction_limit > 0 &&
     350         [ #  # ]:           0 :                 (deleted % param->transaction_limit) == 0)
     351                 :             :             {
     352                 :           0 :                 res2 = PQexec(conn, "commit");
     353         [ #  # ]:           0 :                 if (PQresultStatus(res2) != PGRES_COMMAND_OK)
     354                 :             :                 {
     355                 :           0 :                     pg_log_error("failed to commit transaction: %s",
     356                 :             :                                  PQerrorMessage(conn));
     357                 :           0 :                     PQclear(res2);
     358                 :           0 :                     PQclear(res);
     359                 :           0 :                     PQfinish(conn);
     360                 :           0 :                     return -1;
     361                 :             :                 }
     362                 :           0 :                 PQclear(res2);
     363                 :           0 :                 res2 = PQexec(conn, "begin");
     364         [ #  # ]:           0 :                 if (PQresultStatus(res2) != PGRES_COMMAND_OK)
     365                 :             :                 {
     366                 :           0 :                     pg_log_error("failed to start transaction: %s",
     367                 :             :                                  PQerrorMessage(conn));
     368                 :           0 :                     PQclear(res2);
     369                 :           0 :                     PQclear(res);
     370                 :           0 :                     PQfinish(conn);
     371                 :           0 :                     return -1;
     372                 :             :                 }
     373                 :           0 :                 PQclear(res2);
     374                 :             :             }
     375                 :             :         }
     376                 :             : 
     377                 :           0 :         PQclear(res);
     378         [ #  # ]:           0 :     } while (success);
     379                 :             : 
     380                 :             :     /*
     381                 :             :      * That's all folks!
     382                 :             :      */
     383                 :           0 :     res = PQexec(conn, "commit");
     384         [ #  # ]:           0 :     if (PQresultStatus(res) != PGRES_COMMAND_OK)
     385                 :             :     {
     386                 :           0 :         pg_log_error("failed to commit transaction: %s",
     387                 :             :                      PQerrorMessage(conn));
     388                 :           0 :         PQclear(res);
     389                 :           0 :         PQfinish(conn);
     390                 :           0 :         return -1;
     391                 :             :     }
     392                 :           0 :     PQclear(res);
     393                 :             : 
     394                 :           0 :     PQfinish(conn);
     395                 :             : 
     396         [ #  # ]:           0 :     if (param->verbose)
     397                 :             :     {
     398         [ #  # ]:           0 :         if (param->dry_run)
     399                 :           0 :             fprintf(stdout, "\rWould remove %ld large objects from database \"%s\".\n",
     400                 :             :                     deleted, database);
     401         [ #  # ]:           0 :         else if (success)
     402                 :           0 :             fprintf(stdout,
     403                 :             :                     "\rSuccessfully removed %ld large objects from database \"%s\".\n",
     404                 :             :                     deleted, database);
     405                 :             :         else
     406                 :           0 :             fprintf(stdout, "\rRemoval from database \"%s\" failed at object %ld of %ld.\n",
     407                 :             :                     database, deleted, matched);
     408                 :             :     }
     409                 :             : 
     410   [ #  #  #  # ]:           0 :     return ((param->dry_run || success) ? 0 : -1);
     411                 :             : }
     412                 :             : 
     413                 :             : static void
     414                 :           1 : usage(const char *progname)
     415                 :             : {
     416                 :           1 :     printf("%s removes unreferenced large objects from databases.\n\n", progname);
     417                 :           1 :     printf("Usage:\n  %s [OPTION]... DBNAME...\n\n", progname);
     418                 :           1 :     printf("Options:\n");
     419                 :           1 :     printf("  -l, --limit=LIMIT         commit after removing each LIMIT large objects\n");
     420                 :           1 :     printf("  -n, --dry-run             don't remove large objects, just show what would be done\n");
     421                 :           1 :     printf("  -v, --verbose             write a lot of progress messages\n");
     422                 :           1 :     printf("  -V, --version             output version information, then exit\n");
     423                 :           1 :     printf("  -?, --help                show this help, then exit\n");
     424                 :           1 :     printf("\nConnection options:\n");
     425                 :           1 :     printf("  -h, --host=HOSTNAME       database server host or socket directory\n");
     426                 :           1 :     printf("  -p, --port=PORT           database server port\n");
     427                 :           1 :     printf("  -U, --username=USERNAME   user name to connect as\n");
     428                 :           1 :     printf("  -w, --no-password         never prompt for password\n");
     429                 :           1 :     printf("  -W, --password            force password prompt\n");
     430                 :           1 :     printf("\n");
     431                 :           1 :     printf("Report bugs to <%s>.\n", PACKAGE_BUGREPORT);
     432                 :           1 :     printf("%s home page: <%s>\n", PACKAGE_NAME, PACKAGE_URL);
     433                 :           1 : }
     434                 :             : 
     435                 :             : 
     436                 :             : int
     437                 :           3 : main(int argc, char **argv)
     438                 :             : {
     439                 :             :     static struct option long_options[] = {
     440                 :             :         {"host", required_argument, NULL, 'h'},
     441                 :             :         {"limit", required_argument, NULL, 'l'},
     442                 :             :         {"dry-run", no_argument, NULL, 'n'},
     443                 :             :         {"port", required_argument, NULL, 'p'},
     444                 :             :         {"username", required_argument, NULL, 'U'},
     445                 :             :         {"verbose", no_argument, NULL, 'v'},
     446                 :             :         {"version", no_argument, NULL, 'V'},
     447                 :             :         {"no-password", no_argument, NULL, 'w'},
     448                 :             :         {"password", no_argument, NULL, 'W'},
     449                 :             :         {"help", no_argument, NULL, '?'},
     450                 :             :         {NULL, 0, NULL, 0}
     451                 :             :     };
     452                 :             : 
     453                 :           3 :     int         rc = 0;
     454                 :             :     struct _param param;
     455                 :             :     int         c;
     456                 :             :     int         port;
     457                 :             :     const char *progname;
     458                 :             :     int         optindex;
     459                 :             : 
     460                 :           3 :     pg_logging_init(argv[0]);
     461                 :           3 :     progname = get_progname(argv[0]);
     462                 :             : 
     463                 :             :     /* Set default parameter values */
     464                 :           3 :     param.pg_user = NULL;
     465                 :           3 :     param.pg_prompt = TRI_DEFAULT;
     466                 :           3 :     param.pg_host = NULL;
     467                 :           3 :     param.pg_port = NULL;
     468                 :           3 :     param.progname = progname;
     469                 :           3 :     param.verbose = 0;
     470                 :           3 :     param.dry_run = 0;
     471                 :           3 :     param.transaction_limit = 1000;
     472                 :             : 
     473                 :             :     /* Process command-line arguments */
     474         [ +  - ]:           3 :     if (argc > 1)
     475                 :             :     {
     476   [ +  +  -  + ]:           3 :         if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
     477                 :             :         {
     478                 :           1 :             usage(progname);
     479                 :           1 :             exit(0);
     480                 :             :         }
     481   [ +  +  -  + ]:           2 :         if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
     482                 :             :         {
     483                 :           1 :             puts("vacuumlo (PostgreSQL) " PG_VERSION);
     484                 :           1 :             exit(0);
     485                 :             :         }
     486                 :             :     }
     487                 :             : 
     488         [ +  - ]:           1 :     while ((c = getopt_long(argc, argv, "h:l:np:U:vwW", long_options, &optindex)) != -1)
     489                 :             :     {
     490   [ -  -  -  -  :           1 :         switch (c)
             -  -  -  -  
                      + ]
     491                 :             :         {
     492                 :           0 :             case 'h':
     493                 :           0 :                 param.pg_host = pg_strdup(optarg);
     494                 :           0 :                 break;
     495                 :           0 :             case 'l':
     496                 :           0 :                 param.transaction_limit = strtol(optarg, NULL, 10);
     497         [ #  # ]:           0 :                 if (param.transaction_limit < 0)
     498                 :           0 :                     pg_fatal("transaction limit must not be negative (0 disables)");
     499                 :           0 :                 break;
     500                 :           0 :             case 'n':
     501                 :           0 :                 param.dry_run = 1;
     502                 :           0 :                 param.verbose = 1;
     503                 :           0 :                 break;
     504                 :           0 :             case 'p':
     505                 :           0 :                 port = strtol(optarg, NULL, 10);
     506   [ #  #  #  # ]:           0 :                 if ((port < 1) || (port > 65535))
     507                 :           0 :                     pg_fatal("invalid port number: %s", optarg);
     508                 :           0 :                 param.pg_port = pg_strdup(optarg);
     509                 :           0 :                 break;
     510                 :           0 :             case 'U':
     511                 :           0 :                 param.pg_user = pg_strdup(optarg);
     512                 :           0 :                 break;
     513                 :           0 :             case 'v':
     514                 :           0 :                 param.verbose = 1;
     515                 :           0 :                 break;
     516                 :           0 :             case 'w':
     517                 :           0 :                 param.pg_prompt = TRI_NO;
     518                 :           0 :                 break;
     519                 :           0 :             case 'W':
     520                 :           0 :                 param.pg_prompt = TRI_YES;
     521                 :           0 :                 break;
     522                 :           1 :             default:
     523                 :             :                 /* getopt_long already emitted a complaint */
     524                 :           1 :                 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     525                 :           1 :                 exit(1);
     526                 :             :         }
     527                 :             :     }
     528                 :             : 
     529                 :             :     /* No database given? Show usage */
     530         [ #  # ]:           0 :     if (optind >= argc)
     531                 :             :     {
     532                 :           0 :         pg_log_error("missing required argument: database name");
     533                 :           0 :         pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     534                 :           0 :         exit(1);
     535                 :             :     }
     536                 :             : 
     537         [ #  # ]:           0 :     for (c = optind; c < argc; c++)
     538                 :             :     {
     539                 :             :         /* Work on selected database */
     540                 :           0 :         rc += (vacuumlo(argv[c], &param) != 0);
     541                 :             :     }
     542                 :             : 
     543                 :           0 :     return rc;
     544                 :             : }
        

Generated by: LCOV version 2.0-1