From 2ec74435cdbc6f6d46e9348c579543f0151242e9 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Thu, 16 Oct 2003 20:03:09 +0000
Subject: [PATCH] Cause tab completion to do something moderately reasonable
 with mixed-case identifiers --- it will now complete these correctly with
 double quoting. Fix a few other issues in passing.

---
 src/bin/psql/tab-complete.c | 247 ++++++++++++++++++------------------
 1 file changed, 126 insertions(+), 121 deletions(-)

diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index f000c327b9..4e12621e4c 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2000-2003, PostgreSQL Global Development Group
  *
- * $Header: /cvsroot/pgsql/src/bin/psql/tab-complete.c,v 1.86 2003/10/14 22:47:12 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/bin/psql/tab-complete.c,v 1.87 2003/10/16 20:03:09 tgl Exp $
  */
 
 /*----------------------------------------------------------------------
@@ -15,8 +15,8 @@
  * the programmer felt most like implementing.
  *
  * CAVEAT: Tab completion causes queries to be sent to the backend.
- * The number tuples returned gets limited, in most default
- * installations to 101, but if you still don't like this prospect,
+ * The number of tuples returned gets limited, in most default
+ * installations to 1000, but if you still don't like this prospect,
  * you can turn off tab completion in your ~/.inputrc (or else
  * ${INPUTRC}) file so:
  *
@@ -29,7 +29,7 @@
  *
  * BUGS:
  *
- * - If you split your queries across lines, this whole things gets
+ * - If you split your queries across lines, this whole thing gets
  *	 confused. (To fix this, one would have to read psql's query
  *	 buffer rather than readline's line buffer, which would require
  *	 some major revisions of things.)
@@ -115,7 +115,7 @@ initialize_readline(void)
 
 	rl_basic_word_break_characters = "\t\n@$><=;|&{( ";
 
-	completion_max_records = 100;
+	completion_max_records = 1000;
 
 	/*
 	 * There is a variable rl_completion_query_items for this but
@@ -134,38 +134,40 @@ initialize_readline(void)
  */
 
 #define Query_for_list_of_aggregates \
-" SELECT DISTINCT proname " \
-"   FROM pg_catalog.pg_proc" \
+" SELECT pg_catalog.quote_ident(proname) " \
+"   FROM pg_catalog.pg_proc p" \
 "  WHERE proisagg " \
-"    AND substr(proname,1,%d)='%s'" \
+"    AND substring(pg_catalog.quote_ident(proname),1,%d)='%s'" \
+"    AND pg_catalog.pg_function_is_visible(p.oid) "\
 "        UNION" \
-" SELECT nspname || '.' AS relname" \
+" SELECT pg_catalog.quote_ident(nspname) || '.'" \
 "   FROM pg_catalog.pg_namespace" \
-"  WHERE substr(nspname,1,%d)='%s'" \
+"  WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d)='%s'" \
 "        UNION" \
-" SELECT DISTINCT nspname || '.' || proname AS relname" \
+" SELECT pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(proname)" \
 "   FROM pg_catalog.pg_proc p, pg_catalog.pg_namespace n" \
 "  WHERE proisagg  " \
-"    AND substr(nspname || '.' || proname,1,%d)='%s'" \
+"    AND substring(pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(proname),1,%d)='%s'" \
 "    AND pronamespace = n.oid" \
-"    AND ('%s' ~ '^.*\\\\.' "\
+"    AND ('%s' ~ '\\\\.' "\
 "     OR (SELECT TRUE "\
 "           FROM pg_catalog.pg_namespace "\
-"          WHERE substr(nspname,1,%d)='%s' "\
+"          WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s' "\
 "         HAVING COUNT(nspname)=1))"
 
 #define Query_for_list_of_attributes \
-"SELECT a.attname FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c "\
+"SELECT pg_catalog.quote_ident(attname) "\
+"  FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c "\
 " WHERE c.oid = a.attrelid "\
 "   AND a.attnum > 0 "\
 "   AND NOT a.attisdropped "\
-"   AND substr(a.attname,1,%d)='%s' "\
-"   AND c.relname='%s' "\
+"   AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' "\
+"   AND pg_catalog.quote_ident(relname)='%s' "\
 "   AND pg_catalog.pg_table_is_visible(c.oid)"
 
 #define Query_for_list_of_databases \
-"SELECT datname FROM pg_catalog.pg_database "\
-" WHERE substr(datname,1,%d)='%s'"
+"SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database "\
+" WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s'"
 
 #define Query_for_list_of_datatypes \
 " SELECT pg_catalog.format_type(t.oid, NULL) "\
@@ -173,247 +175,249 @@ initialize_readline(void)
 "  WHERE (t.typrelid = 0 "\
 "     OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid)) "\
 "    AND t.typname !~ '^_' "\
-"    AND substr(pg_catalog.format_type(t.oid, NULL),1,%d)='%s' "\
+"    AND substring(pg_catalog.format_type(t.oid, NULL),1,%d)='%s' "\
+"    AND pg_catalog.pg_type_is_visible(t.oid) "\
 "        UNION "\
-" SELECT nspname || '.' AS relname "\
+" SELECT pg_catalog.quote_ident(nspname) || '.'"\
 "   FROM pg_catalog.pg_namespace "\
-"  WHERE substr(nspname,1,%d)='%s' "\
+"  WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d)='%s' "\
 "        UNION "\
-" SELECT nspname || '.' || pg_catalog.format_type(t.oid, NULL) AS relname "\
+" SELECT pg_catalog.quote_ident(nspname) || '.' || pg_catalog.format_type(t.oid, NULL)"\
 "   FROM pg_catalog.pg_type t, pg_catalog.pg_namespace n "\
 "  WHERE(t.typrelid = 0 "\
 "     OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid)) "\
 "    AND t.typname !~ '^_' "\
-"    AND substr(nspname || '.' || pg_catalog.format_type(t.oid, NULL),1,%d)='%s' "\
+"    AND substring(pg_catalog.quote_ident(nspname) || '.' || pg_catalog.format_type(t.oid, NULL),1,%d)='%s' "\
 "    AND typnamespace = n.oid "\
-"    AND ('%s' ~ '^.*\\\\.' "\
+"    AND ('%s' ~ '\\\\.' "\
 "     OR (SELECT TRUE "\
 "           FROM pg_catalog.pg_namespace "\
-"          WHERE substr(nspname,1,%d)='%s' "\
+"          WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s' "\
 "         HAVING COUNT(nspname)=1))"
 
 #define Query_for_list_of_domains \
-" SELECT typname "\
+" SELECT pg_catalog.quote_ident(typname) "\
 "   FROM pg_catalog.pg_type t "\
 "  WHERE typtype = 'd' "\
-"    AND substr(typname,1,%d)='%s' "\
+"    AND substring(pg_catalog.quote_ident(typname),1,%d)='%s' "\
+"    AND pg_catalog.pg_type_is_visible(t.oid) "\
 "        UNION" \
-" SELECT nspname || '.' "\
+" SELECT pg_catalog.quote_ident(nspname) || '.'"\
 "   FROM pg_catalog.pg_namespace "\
-"  WHERE substr(nspname,1,%d)='%s' "\
+"  WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d)='%s' "\
 "        UNION "\
-" SELECT nspname || '.' || pg_catalog.format_type(t.oid, NULL) "\
+" SELECT pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(typname)"\
 "   FROM pg_catalog.pg_type t, pg_catalog.pg_namespace n "\
 "  WHERE typtype = 'd' "\
-"    AND substr(nspname || '.' || typname,1,%d)='%s' "\
+"    AND substring(pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(typname),1,%d)='%s' "\
 "    AND typnamespace = n.oid "\
-"    AND ('%s' ~ '^.*\\\\.' "\
+"    AND ('%s' ~ '\\\\.' "\
 "     OR (SELECT TRUE "\
 "           FROM pg_catalog.pg_namespace "\
-"          WHERE substr(nspname,1,%d)='%s' "\
+"          WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s' "\
 "         HAVING COUNT(nspname)=1))"
 
 #define Query_for_list_of_encodings \
 " SELECT DISTINCT pg_catalog.pg_encoding_to_char(conforencoding) "\
 "   FROM pg_catalog.pg_conversion "\
-"  WHERE substr(pg_catalog.pg_encoding_to_char(conforencoding),1,%d)=UPPER('%s')"
+"  WHERE substring(pg_catalog.pg_encoding_to_char(conforencoding),1,%d)=UPPER('%s')"
 
 #define Query_for_list_of_functions \
-" SELECT DISTINCT proname || '()' "\
-"   FROM pg_catalog.pg_proc p, pg_catalog.pg_namespace n "\
-"  WHERE substr(proname,1,%d)='%s'"\
+" SELECT pg_catalog.quote_ident(proname) || '()' "\
+"   FROM pg_catalog.pg_proc p "\
+"  WHERE substring(pg_catalog.quote_ident(proname),1,%d)='%s'"\
 "    AND pg_catalog.pg_function_is_visible(p.oid) "\
-"    AND pronamespace = n.oid "\
 "        UNION "\
-" SELECT nspname || '.' "\
+" SELECT pg_catalog.quote_ident(nspname) || '.' "\
 "   FROM pg_catalog.pg_namespace "\
-"  WHERE substr(nspname,1,%d)='%s' "\
+"  WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d)='%s' "\
 "        UNION "\
-" SELECT nspname || '.' || proname "\
+" SELECT pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(proname) || '()' "\
 "   FROM pg_catalog.pg_proc p, pg_catalog.pg_namespace n "\
-"  WHERE substr(nspname || '.' || proname,1,%d)='%s' "\
+"  WHERE substring(pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(proname),1,%d)='%s' "\
 "    AND pronamespace = n.oid "\
-"    AND ('%s' ~ '^.*\\\\.' "\
+"    AND ('%s' ~ '\\\\.' "\
 "     OR (SELECT TRUE "\
 "           FROM pg_catalog.pg_namespace "\
-"          WHERE substr(nspname,1,%d)='%s' "\
+"          WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s' "\
 "         HAVING COUNT(nspname)=1))"
 
 #define Query_for_list_of_indexes \
-" SELECT relname "\
+" SELECT pg_catalog.quote_ident(relname) "\
 "   FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
 "  WHERE relkind='i' "\
-"    AND substr(relname,1,%d)='%s' "\
+"    AND substring(pg_catalog.quote_ident(relname),1,%d)='%s' "\
 "    AND pg_catalog.pg_table_is_visible(c.oid) "\
 "    AND relnamespace = n.oid "\
 "    AND n.nspname NOT IN ('pg_catalog', 'pg_toast') "\
 "        UNION "\
-" SELECT nspname || '.' "\
+" SELECT pg_catalog.quote_ident(nspname) || '.' "\
 "   FROM pg_catalog.pg_namespace "\
-"  WHERE substr(nspname,1,%d)='%s' "\
+"  WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d)='%s' "\
 "        UNION "\
-" SELECT nspname || '.' || relname "\
+" SELECT pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(relname) "\
 "   FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
 "  WHERE relkind='i' "\
-"    AND substr(nspname || '.' || relname,1,%d)='%s' "\
+"    AND substring(pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(relname),1,%d)='%s' "\
 "    AND relnamespace = n.oid "\
-"    AND ('%s' ~ '^.*\\\\.' "\
+"    AND ('%s' ~ '\\\\.' "\
 "     OR (SELECT TRUE "\
 "           FROM pg_catalog.pg_namespace "\
-"          WHERE substr(nspname,1,%d)='%s' "\
+"          WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s' "\
 "         HAVING COUNT(nspname)=1))"
 
 
 #define Query_for_list_of_languages \
-"SELECT lanname "\
+"SELECT pg_catalog.quote_ident(lanname) "\
 "  FROM pg_language "\
 " WHERE lanname != 'internal' "\
-"   AND substr(lanname,1,%d)='%s' "
+"   AND substring(pg_catalog.quote_ident(lanname),1,%d)='%s' "
 
 #define Query_for_list_of_schemas \
-"SELECT nspname FROM pg_catalog.pg_namespace "\
-" WHERE substr(nspname,1,%d)='%s'"
+"SELECT pg_catalog.quote_ident(nspname) FROM pg_catalog.pg_namespace "\
+" WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s'"
 
 #define Query_for_list_of_sequences \
-" SELECT relname "\
+" SELECT pg_catalog.quote_ident(relname) "\
 "   FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
 "  WHERE relkind='S' "\
-"    AND substr(relname,1,%d)='%s' "\
+"    AND substring(pg_catalog.quote_ident(relname),1,%d)='%s' "\
 "    AND pg_catalog.pg_table_is_visible(c.oid) "\
 "    AND relnamespace = n.oid "\
 "    AND n.nspname NOT IN ('pg_catalog', 'pg_toast') "\
 "        UNION "\
-" SELECT nspname || '.' "\
+" SELECT pg_catalog.quote_ident(nspname) || '.' "\
 "   FROM pg_catalog.pg_namespace "\
-"  WHERE substr(nspname,1,%d)='%s' "\
+"  WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d)='%s' "\
 "        UNION "\
-" SELECT nspname || '.' || relname "\
+" SELECT pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(relname) "\
 "   FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
 "  WHERE relkind='S' "\
-"    AND substr(nspname || '.' || relname,1,%d)='%s' "\
+"    AND substring(pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(relname),1,%d)='%s' "\
 "    AND relnamespace = n.oid "\
-"    AND ('%s' ~ '^.*\\\\.' "\
+"    AND ('%s' ~ '\\\\.' "\
 "     OR (SELECT TRUE "\
 "           FROM pg_catalog.pg_namespace "\
-"          WHERE substr(nspname,1,%d)='%s' "\
+"          WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s' "\
 "         HAVING COUNT(nspname)=1))"
 
 #define Query_for_list_of_system_relations \
-"SELECT c.relname FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
+"SELECT pg_catalog.quote_ident(relname) "\
+"  FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
 " WHERE (c.relkind='r' OR c.relkind='v' OR c.relkind='s' OR c.relkind='S') "\
-"   AND substr(c.relname,1,%d)='%s' "\
+"   AND substring(pg_catalog.quote_ident(relname),1,%d)='%s' "\
 "   AND pg_catalog.pg_table_is_visible(c.oid)"\
 "   AND relnamespace = n.oid "\
 "   AND n.nspname = 'pg_catalog'"
 
 #define Query_for_list_of_tables \
-" SELECT relname "\
+" SELECT pg_catalog.quote_ident(relname) "\
 "   FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
 "  WHERE relkind='r' "\
-"    AND substr(relname,1,%d)='%s' "\
+"    AND substring(pg_catalog.quote_ident(relname),1,%d)='%s' "\
 "    AND pg_catalog.pg_table_is_visible(c.oid) "\
 "    AND relnamespace = n.oid "\
 "    AND n.nspname NOT IN ('pg_catalog', 'pg_toast') "\
 "        UNION "\
-" SELECT nspname || '.' "\
+" SELECT pg_catalog.quote_ident(nspname) || '.' "\
 "   FROM pg_catalog.pg_namespace "\
-"  WHERE substr(nspname  || '.',1,%d)='%s' "\
+"  WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d)='%s' "\
 "        UNION "\
-" SELECT nspname || '.' || relname "\
+" SELECT pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(relname) "\
 "   FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
 "  WHERE relkind='r' "\
-"    AND substr(nspname || '.' || relname,1,%d)='%s' "\
+"    AND substring(pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(relname),1,%d)='%s' "\
 "    AND relnamespace = n.oid "\
-"    AND ('%s' ~ '^.*\\\\.' "\
+"    AND ('%s' ~ '\\\\.' "\
 "     OR (SELECT TRUE "\
-"           FROM pg_catalog.pg_namespace n1 "\
-"          WHERE substr(nspname ||'.',1,%d)='%s' "\
+"           FROM pg_catalog.pg_namespace "\
+"          WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s' "\
 "         HAVING COUNT(nspname)=1))"
 
 #define Query_for_list_of_tisv \
-" SELECT relname "\
+" SELECT pg_catalog.quote_ident(relname) "\
 "   FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
 "  WHERE (relkind='r' OR relkind='i' OR relkind='S' OR relkind='v') "\
-"    AND substr(relname,1,%d)='%s' "\
+"    AND substring(pg_catalog.quote_ident(relname),1,%d)='%s' "\
 "    AND pg_catalog.pg_table_is_visible(c.oid) "\
 "    AND relnamespace = n.oid "\
 "    AND n.nspname NOT IN ('pg_catalog', 'pg_toast') "\
 "        UNION "\
-" SELECT nspname || '.' "\
+" SELECT pg_catalog.quote_ident(nspname) || '.' "\
 "   FROM pg_catalog.pg_namespace "\
-"  WHERE substr(nspname,1,%d)='%s' "\
+"  WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d)='%s' "\
 "        UNION "\
-" SELECT nspname || '.' || relname "\
+" SELECT pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(relname) "\
 "   FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
 "  WHERE (relkind='r' OR relkind='i' OR relkind='S' OR relkind='v') "\
-"    AND substr(nspname || '.' || relname,1,%d)='%s' "\
+"    AND substring(pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(relname),1,%d)='%s' "\
 "    AND relnamespace = n.oid "\
-"    AND ('%s' ~ '^.*\\\\.' "\
+"    AND ('%s' ~ '\\\\.' "\
 "     OR (SELECT TRUE "\
 "           FROM pg_catalog.pg_namespace "\
-"          WHERE substr(nspname,1,%d)='%s' "\
+"          WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s' "\
 "         HAVING COUNT(nspname)=1))"
 
 #define Query_for_list_of_tsv \
-" SELECT relname "\
+" SELECT pg_catalog.quote_ident(relname) "\
 "   FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
 "  WHERE (relkind='r' OR relkind='S' OR relkind='v') "\
-"    AND substr(relname,1,%d)='%s' "\
+"    AND substring(pg_catalog.quote_ident(relname),1,%d)='%s' "\
 "    AND pg_catalog.pg_table_is_visible(c.oid) "\
 "    AND relnamespace = n.oid "\
 "    AND n.nspname NOT IN ('pg_catalog', 'pg_toast') "\
 "        UNION "\
-" SELECT nspname || '.' "\
+" SELECT pg_catalog.quote_ident(nspname) || '.' "\
 "   FROM pg_catalog.pg_namespace "\
-"  WHERE substr(nspname,1,%d)='%s' "\
+"  WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d)='%s' "\
 "        UNION "\
-" SELECT nspname || '.' || relname "\
+" SELECT pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(relname) "\
 "   FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
 "  WHERE (relkind='r' OR relkind='S' OR relkind='v') "\
-"    AND substr(nspname || '.' || relname,1,%d)='%s' "\
+"    AND substring(pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(relname),1,%d)='%s' "\
 "    AND relnamespace = n.oid "\
-"    AND ('%s' ~ '^.*\\\\.' "\
+"    AND ('%s' ~ '\\\\.' "\
 "     OR (SELECT TRUE "\
 "           FROM pg_catalog.pg_namespace "\
-"          WHERE substr(nspname,1,%d)='%s' "\
+"          WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s' "\
 "         HAVING COUNT(nspname)=1))"
 
 #define Query_for_list_of_views \
-" SELECT relname "\
+" SELECT pg_catalog.quote_ident(relname) "\
 "   FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
 "  WHERE relkind='v'"\
-"    AND substr(relname,1,%d)='%s' "\
+"    AND substring(pg_catalog.quote_ident(relname),1,%d)='%s' "\
 "    AND pg_catalog.pg_table_is_visible(c.oid) "\
 "    AND relnamespace = n.oid "\
 "    AND n.nspname NOT IN ('pg_catalog', 'pg_toast') "\
 "        UNION "\
-" SELECT nspname || '.' "\
+" SELECT pg_catalog.quote_ident(nspname) || '.' "\
 "   FROM pg_catalog.pg_namespace "\
-"  WHERE substr(nspname,1,%d)='%s' "\
+"  WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d)='%s' "\
 "        UNION "\
-" SELECT nspname || '.' || relname "\
+" SELECT pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(relname) "\
 "   FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
 "  WHERE relkind='v' "\
-"    AND substr(nspname || '.' || relname,1,%d)='%s' "\
+"    AND substring(pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(relname),1,%d)='%s' "\
 "    AND relnamespace = n.oid "\
-"    AND ('%s' ~ '^.*\\\\.' "\
+"    AND ('%s' ~ '\\\\.' "\
 "     OR (SELECT TRUE "\
 "           FROM pg_catalog.pg_namespace "\
-"          WHERE substr(nspname,1,%d)='%s' "\
+"          WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s' "\
 "         HAVING COUNT(nspname)=1))"
 
 #define Query_for_list_of_users \
-" SELECT usename "\
+" SELECT pg_catalog.quote_ident(usename) "\
 "   FROM pg_catalog.pg_user "\
-"  WHERE substr(usename,1,%d)='%s'"
+"  WHERE substring(pg_catalog.quote_ident(usename),1,%d)='%s'"
 
 /* the silly-looking length condition is just to eat up the current word */
 #define Query_for_table_owning_index \
-"SELECT c1.relname "\
+"SELECT pg_catalog.quote_ident(c1.relname) "\
 "  FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i"\
 " WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid"\
 "       and (%d = length('%s'))"\
-"       and c2.relname='%s'"\
+"       and pg_catalog.quote_ident(c2.relname)='%s'"\
 "       and pg_catalog.pg_table_is_visible(c2.oid)"
 
 /* This is a list of all "things" in Pgsql, which can show up after CREATE or
@@ -434,21 +438,21 @@ pgsql_thing_t words_after_create[] = {
 	{"AGGREGATE", WITH_SCHEMA, Query_for_list_of_aggregates},
 	{"CAST", NO_SCHEMA, NULL},	/* Casts have complex structures for
 								 * namees, so skip it */
-	{"CONVERSION", NO_SCHEMA, "SELECT conname FROM pg_catalog.pg_conversion WHERE substr(conname,1,%d)='%s'"},
+	{"CONVERSION", NO_SCHEMA, "SELECT pg_catalog.quote_ident(conname) FROM pg_catalog.pg_conversion WHERE substring(pg_catalog.quote_ident(conname),1,%d)='%s'"},
 	{"DATABASE", NO_SCHEMA, Query_for_list_of_databases},
 	{"DOMAIN", WITH_SCHEMA, Query_for_list_of_domains},
 	{"FUNCTION", WITH_SCHEMA, Query_for_list_of_functions},
-	{"GROUP", NO_SCHEMA, "SELECT groname FROM pg_catalog.pg_group WHERE substr(groname,1,%d)='%s'"},
+	{"GROUP", NO_SCHEMA, "SELECT pg_catalog.quote_ident(groname) FROM pg_catalog.pg_group WHERE substring(pg_catalog.quote_ident(groname),1,%d)='%s'"},
 	{"LANGUAGE", NO_SCHEMA, Query_for_list_of_languages},
 	{"INDEX", WITH_SCHEMA, Query_for_list_of_indexes},
 	{"OPERATOR", NO_SCHEMA, NULL},		/* Querying for this is probably
 										 * not such a good idea. */
-	{"RULE", NO_SCHEMA, "SELECT rulename FROM pg_catalog.pg_rules WHERE substr(rulename,1,%d)='%s'"},
+	{"RULE", NO_SCHEMA, "SELECT pg_catalog.quote_ident(rulename) FROM pg_catalog.pg_rules WHERE substring(pg_catalog.quote_ident(rulename),1,%d)='%s'"},
 	{"SCHEMA", NO_SCHEMA, Query_for_list_of_schemas},
 	{"SEQUENCE", WITH_SCHEMA, Query_for_list_of_sequences},
 	{"TABLE", WITH_SCHEMA, Query_for_list_of_tables},
 	{"TEMP", NO_SCHEMA, NULL},	/* for CREATE TEMP TABLE ... */
-	{"TRIGGER", NO_SCHEMA, "SELECT tgname FROM pg_catalog.pg_trigger WHERE substr(tgname,1,%d)='%s'"},
+	{"TRIGGER", NO_SCHEMA, "SELECT pg_catalog.quote_ident(tgname) FROM pg_catalog.pg_trigger WHERE substring(pg_catalog.quote_ident(tgname),1,%d)='%s'"},
 	{"TYPE", WITH_SCHEMA, Query_for_list_of_datatypes},
 	{"UNIQUE", NO_SCHEMA, NULL},	/* for CREATE UNIQUE INDEX ... */
 	{"USER", NO_SCHEMA, Query_for_list_of_users},
@@ -987,20 +991,20 @@ psql_completion(char *text, int start, int end)
 	else if ((strcasecmp(prev3_wd, "GRANT") == 0 ||
 			  strcasecmp(prev3_wd, "REVOKE") == 0) &&
 			 strcasecmp(prev_wd, "ON") == 0)
-		COMPLETE_WITH_QUERY("SELECT relname FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "
+		COMPLETE_WITH_QUERY("SELECT pg_catalog.quote_ident(relname) FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "
 							" WHERE relkind in ('r','S','v')  "
-							"   AND substr(relname,1,%d)='%s' "
+							"   AND substring(pg_catalog.quote_ident(relname),1,%d)='%s' "
 						  "   AND pg_catalog.pg_table_is_visible(c.oid) "
 							"   AND relnamespace = n.oid "
 					"   AND n.nspname NOT IN ('pg_catalog', 'pg_toast') "
 							" UNION "
-							"SELECT 'DATABASE' AS relname "
+							"SELECT 'DATABASE' "
 							" UNION "
-							"SELECT 'FUNCTION' AS relname "
+							"SELECT 'FUNCTION' "
 							" UNION "
-							"SELECT 'LANGUAGE' AS relname "
+							"SELECT 'LANGUAGE' "
 							" UNION "
-							"SELECT 'SCHEMA' AS relname ");
+							"SELECT 'SCHEMA' ");
 
 	/* Complete "GRANT/REVOKE * ON * " with "TO" */
 	else if ((strcasecmp(prev4_wd, "GRANT") == 0 ||
@@ -1098,7 +1102,7 @@ psql_completion(char *text, int start, int end)
 
 /* NOTIFY */
 	else if (strcasecmp(prev_wd, "NOTIFY") == 0)
-		COMPLETE_WITH_QUERY("SELECT relname FROM pg_catalog.pg_listener WHERE substr(relname,1,%d)='%s'");
+		COMPLETE_WITH_QUERY("SELECT pg_catalog.quote_ident(relname) FROM pg_catalog.pg_listener WHERE substring(pg_catalog.quote_ident(relname),1,%d)='%s'");
 
 /* REINDEX */
 	else if (strcasecmp(prev_wd, "REINDEX") == 0)
@@ -1227,7 +1231,7 @@ psql_completion(char *text, int start, int end)
 
 /* UNLISTEN */
 	else if (strcasecmp(prev_wd, "UNLISTEN") == 0)
-		COMPLETE_WITH_QUERY("SELECT relname FROM pg_catalog.pg_listener WHERE substr(relname,1,%d)='%s' UNION SELECT '*'::name");
+		COMPLETE_WITH_QUERY("SELECT pg_catalog.quote_ident(relname) FROM pg_catalog.pg_listener WHERE substring(pg_catalog.quote_ident(relname),1,%d)='%s' UNION SELECT '*'");
 
 /* UPDATE */
 	/* If prev. word is UPDATE suggest a list of tables */
@@ -1247,10 +1251,11 @@ psql_completion(char *text, int start, int end)
 
 /* VACUUM */
 	else if (strcasecmp(prev_wd, "VACUUM") == 0)
-		COMPLETE_WITH_QUERY("SELECT relname FROM pg_catalog.pg_class WHERE relkind='r' and substr(relname,1,%d)='%s' and pg_catalog.pg_table_is_visible(oid) UNION SELECT 'FULL'::name UNION SELECT 'ANALYZE'::name");
+		COMPLETE_WITH_QUERY("SELECT pg_catalog.quote_ident(relname) FROM pg_catalog.pg_class WHERE relkind='r' and substring(pg_catalog.quote_ident(relname),1,%d)='%s' and pg_catalog.pg_table_is_visible(oid) UNION SELECT 'FULL' UNION SELECT 'ANALYZE' UNION SELECT 'VERBOSE'");
 	else if (strcasecmp(prev2_wd, "VACUUM") == 0 &&
 			 (strcasecmp(prev_wd, "FULL") == 0 ||
-			  strcasecmp(prev_wd, "ANALYZE") == 0))
+			  strcasecmp(prev_wd, "ANALYZE") == 0 ||
+			  strcasecmp(prev_wd, "VERBOSE") == 0))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
 
 /* WHERE */
@@ -1641,20 +1646,20 @@ exec_query(char *query)
 	assert(query[strlen(query) - 1] != ';');
 #endif
 
-	if (snprintf(query_buffer, BUF_SIZE, "%s LIMIT %d;",
+	if (snprintf(query_buffer, BUF_SIZE, "%s LIMIT %d",
 				 query, completion_max_records) == -1)
 	{
 		ERROR_QUERY_TOO_LONG;
 		return NULL;
 	}
 
-	result = PQexec(pset.db, query);
+	result = PQexec(pset.db, query_buffer);
 
 	if (result != NULL && PQresultStatus(result) != PGRES_TUPLES_OK)
 	{
 #if 0
 		psql_error("tab completion: %s failed - %s\n",
-				   query, PQresStatus(PQresultStatus(result)));
+				   query_buffer, PQresStatus(PQresultStatus(result)));
 #endif
 		PQclear(result);
 		result = NULL;
-- 
2.24.1