1 /*-------------------------------------------------------------------------
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"
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.
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
))
48 if (inquotes
&& cp
[1] == '"')
49 cp
++; /* pair does not affect quoting */
55 cp
+= PQmblenBounded(cp
, encoding
);
57 *table
= pnstrdup(spec
, cp
- spec
);
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.
69 appendQualifiedRelation(PQExpBuffer buf
, const char *spec
,
70 PGconn
*conn
, bool echo
)
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
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
);
107 pg_log_error(ngettext("query returned %d row instead of one: %s",
108 "query returned %d rows instead of one: %s",
114 appendPQExpBufferStr(buf
,
115 fmtQualifiedId(PQgetvalue(res
, 0, 1),
116 PQgetvalue(res
, 0, 0)));
117 appendPQExpBufferStr(buf
, columns
);
119 termPQExpBuffer(&sql
);
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")
136 yesno_prompt(const char *question
)
141 translator: This is a question followed by the translated options for
143 snprintf(prompt
, sizeof(prompt
), _("%s (%s/%s) "),
144 _(question
), _(PG_YESLETTER
), _(PG_NOLETTER
));
150 resp
= simple_prompt(prompt
, true);
152 if (strcmp(resp
, _(PG_YESLETTER
)) == 0)
157 if (strcmp(resp
, _(PG_NOLETTER
)) == 0)
164 printf(_("Please answer \"%s\" or \"%s\".\n"),
165 _(PG_YESLETTER
), _(PG_NOLETTER
));