LCOV - differential code coverage report
Current view: top level - src/bin/scripts - common.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage HEAD vs 15 Lines: 68.1 % 47 32 15 32
Current Date: 2023-04-08 15:15:32 Functions: 66.7 % 3 2 1 2
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  *  common.c
       4                 :  *      Common support routines for bin/scripts/
       5                 :  *
       6                 :  *
       7                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
       8                 :  * Portions Copyright (c) 1994, Regents of the University of California
       9                 :  *
      10                 :  * src/bin/scripts/common.c
      11                 :  *
      12                 :  *-------------------------------------------------------------------------
      13                 :  */
      14                 : 
      15                 : #include "postgres_fe.h"
      16                 : 
      17                 : #include <signal.h>
      18                 : #include <unistd.h>
      19                 : 
      20                 : #include "common.h"
      21                 : #include "common/connect.h"
      22                 : #include "common/logging.h"
      23                 : #include "common/string.h"
      24                 : #include "fe_utils/cancel.h"
      25                 : #include "fe_utils/query_utils.h"
      26                 : #include "fe_utils/string_utils.h"
      27                 : 
      28                 : /*
      29                 :  * Split TABLE[(COLUMNS)] into TABLE and [(COLUMNS)] portions.  When you
      30                 :  * finish using them, pg_free(*table).  *columns is a pointer into "spec",
      31                 :  * possibly to its NUL terminator.
      32                 :  */
      33                 : void
      34 CBC          36 : splitTableColumnsSpec(const char *spec, int encoding,
      35                 :                       char **table, const char **columns)
      36                 : {
      37              36 :     bool        inquotes = false;
      38              36 :     const char *cp = spec;
      39                 : 
      40                 :     /*
      41                 :      * Find the first '(' not identifier-quoted.  Based on
      42                 :      * dequote_downcase_identifier().
      43                 :      */
      44             474 :     while (*cp && (*cp != '(' || inquotes))
      45                 :     {
      46             438 :         if (*cp == '"')
      47                 :         {
      48               3 :             if (inquotes && cp[1] == '"')
      49               1 :                 cp++;           /* pair does not affect quoting */
      50                 :             else
      51               2 :                 inquotes = !inquotes;
      52               3 :             cp++;
      53                 :         }
      54                 :         else
      55             435 :             cp += PQmblenBounded(cp, encoding);
      56                 :     }
      57              36 :     *table = pnstrdup(spec, cp - spec);
      58              36 :     *columns = cp;
      59              36 : }
      60                 : 
      61                 : /*
      62                 :  * Break apart TABLE[(COLUMNS)] of "spec".  With the reset_val of search_path
      63                 :  * in effect, have regclassin() interpret the TABLE portion.  Append to "buf"
      64                 :  * the qualified name of TABLE, followed by any (COLUMNS).  Exit on failure.
      65                 :  * We use this to interpret --table=foo under the search path psql would get,
      66                 :  * in advance of "ANALYZE public.foo" under the always-secure search path.
      67                 :  */
      68                 : void
      69              26 : appendQualifiedRelation(PQExpBuffer buf, const char *spec,
      70                 :                         PGconn *conn, bool echo)
      71                 : {
      72                 :     char       *table;
      73                 :     const char *columns;
      74                 :     PQExpBufferData sql;
      75                 :     PGresult   *res;
      76                 :     int         ntups;
      77                 : 
      78              26 :     splitTableColumnsSpec(spec, PQclientEncoding(conn), &table, &columns);
      79                 : 
      80                 :     /*
      81                 :      * Query must remain ABSOLUTELY devoid of unqualified names.  This would
      82                 :      * be unnecessary given a regclassin() variant taking a search_path
      83                 :      * argument.
      84                 :      */
      85              26 :     initPQExpBuffer(&sql);
      86              26 :     appendPQExpBufferStr(&sql,
      87                 :                          "SELECT c.relname, ns.nspname\n"
      88                 :                          " FROM pg_catalog.pg_class c,"
      89                 :                          " pg_catalog.pg_namespace ns\n"
      90                 :                          " WHERE c.relnamespace OPERATOR(pg_catalog.=) ns.oid\n"
      91                 :                          "  AND c.oid OPERATOR(pg_catalog.=) ");
      92              26 :     appendStringLiteralConn(&sql, table, conn);
      93              26 :     appendPQExpBufferStr(&sql, "::pg_catalog.regclass;");
      94                 : 
      95              26 :     executeCommand(conn, "RESET search_path;", echo);
      96                 : 
      97                 :     /*
      98                 :      * One row is a typical result, as is a nonexistent relation ERROR.
      99                 :      * regclassin() unconditionally accepts all-digits input as an OID; if no
     100                 :      * relation has that OID; this query returns no rows.  Catalog corruption
     101                 :      * might elicit other row counts.
     102                 :      */
     103              26 :     res = executeQuery(conn, sql.data, echo);
     104              25 :     ntups = PQntuples(res);
     105              25 :     if (ntups != 1)
     106                 :     {
     107 UBC           0 :         pg_log_error(ngettext("query returned %d row instead of one: %s",
     108                 :                               "query returned %d rows instead of one: %s",
     109                 :                               ntups),
     110                 :                      ntups, sql.data);
     111               0 :         PQfinish(conn);
     112               0 :         exit(1);
     113                 :     }
     114 CBC          25 :     appendPQExpBufferStr(buf,
     115              25 :                          fmtQualifiedId(PQgetvalue(res, 0, 1),
     116              25 :                                         PQgetvalue(res, 0, 0)));
     117              25 :     appendPQExpBufferStr(buf, columns);
     118              25 :     PQclear(res);
     119              25 :     termPQExpBuffer(&sql);
     120              25 :     pg_free(table);
     121                 : 
     122              25 :     PQclear(executeQuery(conn, ALWAYS_SECURE_SEARCH_PATH_SQL, echo));
     123              25 : }
     124                 : 
     125                 : 
     126                 : /*
     127                 :  * Check yes/no answer in a localized way.  1=yes, 0=no, -1=neither.
     128                 :  */
     129                 : 
     130                 : /* translator: abbreviation for "yes" */
     131                 : #define PG_YESLETTER gettext_noop("y")
     132                 : /* translator: abbreviation for "no" */
     133                 : #define PG_NOLETTER gettext_noop("n")
     134                 : 
     135                 : bool
     136 UBC           0 : yesno_prompt(const char *question)
     137                 : {
     138                 :     char        prompt[256];
     139                 : 
     140                 :     /*------
     141                 :        translator: This is a question followed by the translated options for
     142                 :        "yes" and "no". */
     143               0 :     snprintf(prompt, sizeof(prompt), _("%s (%s/%s) "),
     144                 :              _(question), _(PG_YESLETTER), _(PG_NOLETTER));
     145                 : 
     146                 :     for (;;)
     147               0 :     {
     148                 :         char       *resp;
     149                 : 
     150               0 :         resp = simple_prompt(prompt, true);
     151                 : 
     152               0 :         if (strcmp(resp, _(PG_YESLETTER)) == 0)
     153                 :         {
     154               0 :             free(resp);
     155               0 :             return true;
     156                 :         }
     157               0 :         if (strcmp(resp, _(PG_NOLETTER)) == 0)
     158                 :         {
     159               0 :             free(resp);
     160               0 :             return false;
     161                 :         }
     162               0 :         free(resp);
     163                 : 
     164               0 :         printf(_("Please answer \"%s\" or \"%s\".\n"),
     165                 :                _(PG_YESLETTER), _(PG_NOLETTER));
     166                 :     }
     167                 : }
        

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