PostgreSQL Source Code  git master
common.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * common.c
4  * Common support routines for bin/scripts/
5  *
6  *
7  * Portions Copyright (c) 1996-2024, 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 splitTableColumnsSpec(const char *spec, int encoding,
35  char **table, const char **columns)
36 {
37  bool inquotes = false;
38  const char *cp = spec;
39 
40  /*
41  * Find the first '(' not identifier-quoted. Based on
42  * dequote_downcase_identifier().
43  */
44  while (*cp && (*cp != '(' || inquotes))
45  {
46  if (*cp == '"')
47  {
48  if (inquotes && cp[1] == '"')
49  cp++; /* pair does not affect quoting */
50  else
51  inquotes = !inquotes;
52  cp++;
53  }
54  else
55  cp += PQmblenBounded(cp, encoding);
56  }
57  *table = pnstrdup(spec, cp - spec);
58  *columns = cp;
59 }
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
70  PGconn *conn, bool echo)
71 {
72  char *table;
73  const char *columns;
74  PQExpBufferData sql;
75  PGresult *res;
76  int ntups;
77 
78  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  initPQExpBuffer(&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  appendStringLiteralConn(&sql, table, conn);
93  appendPQExpBufferStr(&sql, "::pg_catalog.regclass;");
94 
95  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  res = executeQuery(conn, sql.data, echo);
104  ntups = PQntuples(res);
105  if (ntups != 1)
106  {
107  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  PQfinish(conn);
112  exit(1);
113  }
116  PQgetvalue(res, 0, 0)));
117  appendPQExpBufferStr(buf, columns);
118  PQclear(res);
119  termPQExpBuffer(&sql);
120  pg_free(table);
121 
123 }
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 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  snprintf(prompt, sizeof(prompt), _("%s (%s/%s) "),
145 
146  for (;;)
147  {
148  char *resp;
149 
150  resp = simple_prompt(prompt, true);
151 
152  if (strcmp(resp, _(PG_YESLETTER)) == 0)
153  {
154  free(resp);
155  return true;
156  }
157  if (strcmp(resp, _(PG_NOLETTER)) == 0)
158  {
159  free(resp);
160  return false;
161  }
162  free(resp);
163 
164  printf(_("Please answer \"%s\" or \"%s\".\n"),
166  }
167 }
bool yesno_prompt(const char *question)
Definition: common.c:136
void splitTableColumnsSpec(const char *spec, int encoding, char **table, const char **columns)
Definition: common.c:34
void appendQualifiedRelation(PQExpBuffer buf, const char *spec, PGconn *conn, bool echo)
Definition: common.c:69
#define PG_YESLETTER
Definition: common.c:131
#define PG_NOLETTER
Definition: common.c:133
#define ngettext(s, p, n)
Definition: c.h:1168
#define ALWAYS_SECURE_SEARCH_PATH_SQL
Definition: connect.h:25
#define _(x)
Definition: elog.c:90
int PQclientEncoding(const PGconn *conn)
Definition: fe-connect.c:7036
void PQfinish(PGconn *conn)
Definition: fe-connect.c:4669
int PQntuples(const PGresult *res)
Definition: fe-exec.c:3441
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3836
int PQmblenBounded(const char *s, int encoding)
Definition: fe-misc.c:1187
void pg_free(void *ptr)
Definition: fe_memutils.c:105
#define free(a)
Definition: header.h:65
#define question
Definition: indent_codes.h:41
exit(1)
#define pg_log_error(...)
Definition: logging.h:106
char * pnstrdup(const char *in, Size len)
Definition: mcxt.c:1694
int32 encoding
Definition: pg_database.h:41
static void executeCommand(PGconn *conn, const char *query)
Definition: pg_dumpall.c:1905
static PGresult * executeQuery(PGconn *conn, const char *query)
Definition: pg_dumpall.c:1882
static char * buf
Definition: pg_test_fsync.c:73
#define snprintf
Definition: port.h:238
#define printf(...)
Definition: port.h:244
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:90
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:367
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:129
char * simple_prompt(const char *prompt, bool echo)
Definition: sprompt.c:38
PGconn * conn
Definition: streamutil.c:54
void appendStringLiteralConn(PQExpBuffer buf, const char *str, PGconn *conn)
Definition: string_utils.c:293
const char * fmtQualifiedId(const char *schema, const char *id)
Definition: string_utils.c:145