psql: handle tab completion of timezone names after "SET TIMEZONE TO".
authorTom Lane
Sun, 20 Mar 2022 20:06:41 +0000 (16:06 -0400)
committerTom Lane
Sun, 20 Mar 2022 20:06:48 +0000 (16:06 -0400)
Dagfinn Ilmari Mannsåker and Tom Lane

Discussion: https://postgr.es/m/[email protected]

src/bin/psql/t/010_tab_completion.pl
src/bin/psql/tab-complete.c

index a54910680e57565d3d90b64aaee0d34c00422093..2711935a2cc9dd127154681aa2702ba0dcd02fc9 100644 (file)
@@ -338,6 +338,19 @@ check_completion(
 
 clear_line();
 
+# check timezone name completion
+check_completion(
+   "SET timezone TO am\t",
+   qr|'America/|,
+   "offer partial timezone name");
+
+check_completion(
+   "new_\t",
+   qr|New_York|,
+   "complete partial timezone name");
+
+clear_line();
+
 # check completion of a keyword offered in addition to object names;
 # such a keyword should obey COMP_KEYWORD_CASE
 foreach (
index 7b331a38ae0027660f1440b7d7f6163e2da8d02b..183abcc2753108224c735cac2405454508de9a89 100644 (file)
@@ -402,6 +402,24 @@ do { \
    matches = rl_completion_matches(text, complete_from_schema_query); \
 } while (0)
 
+/*
+ * Timezone completion is mostly like enum label completion, but we work
+ * a little harder since this is a more common use-case.
+ */
+#define COMPLETE_WITH_TIMEZONE_NAME() \
+do { \
+   static const char *const list[] = { "DEFAULT", NULL }; \
+   if (text[0] == '\'') \
+       completion_charp = Query_for_list_of_timezone_names_quoted_in; \
+   else if (start == 0 || rl_line_buffer[start - 1] != '\'') \
+       completion_charp = Query_for_list_of_timezone_names_quoted_out; \
+   else \
+       completion_charp = Query_for_list_of_timezone_names_unquoted; \
+   completion_charpp = list;                             \
+   completion_verbatim = true; \
+   matches = rl_completion_matches(text, complete_from_query); \
+} while (0)
+
 #define COMPLETE_WITH_FUNCTION_ARG(function) \
 do { \
    set_completion_reference(function); \
@@ -1105,6 +1123,21 @@ static const SchemaQuery Query_for_trigger_of_table = {
 "   FROM pg_catalog.pg_cursors "\
 "  WHERE name LIKE '%s'"
 
+#define Query_for_list_of_timezone_names_unquoted \
+" SELECT name "\
+"   FROM pg_catalog.pg_timezone_names() "\
+"  WHERE pg_catalog.lower(name) LIKE pg_catalog.lower('%s')"
+
+#define Query_for_list_of_timezone_names_quoted_out \
+"SELECT pg_catalog.quote_literal(name) AS name "\
+"  FROM pg_catalog.pg_timezone_names() "\
+" WHERE pg_catalog.lower(name) LIKE pg_catalog.lower('%s')"
+
+#define Query_for_list_of_timezone_names_quoted_in \
+"SELECT pg_catalog.quote_literal(name) AS name "\
+"  FROM pg_catalog.pg_timezone_names() "\
+" WHERE pg_catalog.quote_literal(pg_catalog.lower(name)) LIKE pg_catalog.lower('%s')"
+
 /*
  * These object types were introduced later than our support cutoff of
  * server version 9.2.  We use the VersionedQuery infrastructure so that
@@ -4176,6 +4209,8 @@ psql_completion(const char *text, int start, int end)
                                     " AND nspname NOT LIKE E'pg\\\\_temp%%'",
                                     "DEFAULT");
        }
+       else if (TailMatches("TimeZone", "TO|="))
+           COMPLETE_WITH_TIMEZONE_NAME();
        else
        {
            /* generic, type based, GUC support */