Add empty placeholder LINGUAS file for pg_combinebackup.
[pgsql.git] / src / bin / scripts / common.c
blob4c52fb6a3e436b9229484573b8b89dd92713dfe2
1 /*-------------------------------------------------------------------------
3 * common.c
4 * Common support routines for bin/scripts/
7 * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
10 * src/bin/scripts/common.c
12 *-------------------------------------------------------------------------
15 #include "postgres_fe.h"
17 #include <signal.h>
18 #include <unistd.h>
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"
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.
33 void
34 splitTableColumnsSpec(const char *spec, int encoding,
35 char **table, const char **columns)
37 bool inquotes = false;
38 const char *cp = spec;
41 * Find the first '(' not identifier-quoted. Based on
42 * dequote_downcase_identifier().
44 while (*cp && (*cp != '(' || inquotes))
46 if (*cp == '"')
48 if (inquotes && cp[1] == '"')
49 cp++; /* pair does not affect quoting */
50 else
51 inquotes = !inquotes;
52 cp++;
54 else
55 cp += PQmblenBounded(cp, encoding);
57 *table = pnstrdup(spec, cp - spec);
58 *columns = cp;
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.
68 void
69 appendQualifiedRelation(PQExpBuffer buf, const char *spec,
70 PGconn *conn, bool echo)
72 char *table;
73 const char *columns;
74 PQExpBufferData sql;
75 PGresult *res;
76 int ntups;
78 splitTableColumnsSpec(spec, PQclientEncoding(conn), &table, &columns);
81 * Query must remain ABSOLUTELY devoid of unqualified names. This would
82 * be unnecessary given a regclassin() variant taking a search_path
83 * argument.
85 initPQExpBuffer(&sql);
86 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 appendStringLiteralConn(&sql, table, conn);
93 appendPQExpBufferStr(&sql, "::pg_catalog.regclass;");
95 executeCommand(conn, "RESET search_path;", echo);
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.
103 res = executeQuery(conn, sql.data, echo);
104 ntups = PQntuples(res);
105 if (ntups != 1)
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);
114 appendPQExpBufferStr(buf,
115 fmtQualifiedId(PQgetvalue(res, 0, 1),
116 PQgetvalue(res, 0, 0)));
117 appendPQExpBufferStr(buf, columns);
118 PQclear(res);
119 termPQExpBuffer(&sql);
120 pg_free(table);
122 PQclear(executeQuery(conn, ALWAYS_SECURE_SEARCH_PATH_SQL, echo));
127 * Check yes/no answer in a localized way. 1=yes, 0=no, -1=neither.
130 /* translator: abbreviation for "yes" */
131 #define PG_YESLETTER gettext_noop("y")
132 /* translator: abbreviation for "no" */
133 #define PG_NOLETTER gettext_noop("n")
135 bool
136 yesno_prompt(const char *question)
138 char prompt[256];
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) "),
144 _(question), _(PG_YESLETTER), _(PG_NOLETTER));
146 for (;;)
148 char *resp;
150 resp = simple_prompt(prompt, true);
152 if (strcmp(resp, _(PG_YESLETTER)) == 0)
154 free(resp);
155 return true;
157 if (strcmp(resp, _(PG_NOLETTER)) == 0)
159 free(resp);
160 return false;
162 free(resp);
164 printf(_("Please answer \"%s\" or \"%s\".\n"),
165 _(PG_YESLETTER), _(PG_NOLETTER));