v16-0002-fix-up-completion-info.patch
text/x-diff
Filename: v16-0002-fix-up-completion-info.patch
Type: text/x-diff
Part: 1
Patch
Format: unified
Series: patch v16-0002
| File | + | − |
|---|---|---|
| src/bin/psql/tab-complete.c | 425 | 377 |
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index e2026275b0..176f7e74c2 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -110,6 +110,12 @@ typedef struct VersionedQuery
* time. So we put the components of each query into this struct and
* assemble them with the common boilerplate in _complete_from_query().
*
+ * We also use this struct to define queries that use completion_info_object,
+ * which is some object related to the one(s) we want to get the names of
+ * (for example, the table we want the indexes of). In that usage the
+ * objects we're completing might not have a schema of their own, but the
+ * related object almost always does (passed in completion_info_schema).
+ *
* As with VersionedQuery, we can use an array of these if the query details
* must vary across versions.
*/
@@ -123,8 +129,9 @@ typedef struct SchemaQuery
int min_server_version;
/*
- * Name of catalog or catalogs to be queried, with alias, eg.
- * "pg_catalog.pg_class c". Note that "pg_namespace n" will be added.
+ * Name of catalog or catalogs to be queried, with alias(es), eg.
+ * "pg_catalog.pg_class c". Note that "pg_namespace n" and/or
+ * "pg_namespace ni" will be added automatically when needed.
*/
const char *catname;
@@ -140,12 +147,15 @@ typedef struct SchemaQuery
/*
* Visibility condition --- which rows are visible without schema
* qualification? For example, "pg_catalog.pg_table_is_visible(c.oid)".
+ * NULL if not needed.
*/
const char *viscondition;
/*
- * Namespace --- name of field to join to pg_namespace.oid. For example,
- * "c.relnamespace".
+ * Namespace --- name of field to join to pg_namespace.oid when there is
+ * schema qualification. For example, "c.relnamespace". NULL if we don't
+ * want to join to pg_namespace (then any schema part in the input word
+ * will be ignored).
*/
const char *namespace;
@@ -154,12 +164,43 @@ typedef struct SchemaQuery
*/
const char *result;
+ /*
+ * In some cases, it's difficult to keep the query from returning the same
+ * object multiple times. Specify use_distinct to filter out duplicates.
+ */
+ bool use_distinct;
+
/*
* Additional literal strings (usually keywords) to be offered along with
* the query results. Provide a NULL-terminated array of constant
* strings, or NULL if none.
*/
const char *const *keywords;
+
+ /*
+ * If this query uses completion_info_object/completion_info_schema,
+ * populate the remaining fields, else leave them NULL. When using this
+ * capability, catname must include the catalog that defines the
+ * completion_info_object, and selcondition must include the join
+ * condition that connects it to the result's catalog.
+ *
+ * infoname is the field that should be equated to completion_info_object,
+ * for example "ci.relname".
+ */
+ const char *infoname;
+
+ /*
+ * Visibility condition to use when completion_info_schema is not set. For
+ * example, "pg_catalog.pg_table_is_visible(ci.oid)". NULL if not needed.
+ */
+ const char *infoviscondition;
+
+ /*
+ * Name of field to join to pg_namespace.oid when completion_info_schema
+ * is set. For example, "ci.relnamespace". NULL if we don't want to
+ * consider completion_info_schema.
+ */
+ const char *infonamespace;
} SchemaQuery;
@@ -176,10 +217,10 @@ static int completion_max_records;
static char completion_last_char; /* last char of input word */
static const char *completion_charp; /* to pass a string */
static const char *const *completion_charpp; /* to pass a list of strings */
-static const char *completion_info_charp; /* to pass a second string */
-static const char *completion_info_charp2; /* to pass a third string */
static const VersionedQuery *completion_vquery; /* to pass a VersionedQuery */
static const SchemaQuery *completion_squery; /* to pass a SchemaQuery */
+static char *completion_info_object; /* name of a related object */
+static char *completion_info_schema; /* schema name of a related object */
static bool completion_case_sensitive; /* completion is case sensitive */
static bool completion_verbatim; /* completion is verbatim */
static bool completion_force_quote; /* true to force-quote filenames */
@@ -257,6 +298,14 @@ do { \
COMPLETE_WITH_SCHEMA_QUERY_LIST(query, list); \
} while (0)
+#define COMPLETE_WITH_SCHEMA_QUERY_VERBATIM(query) \
+do { \
+ completion_squery = &(query); \
+ completion_charpp = NULL; \
+ completion_verbatim = true; \
+ matches = rl_completion_matches(text, complete_from_schema_query); \
+} while (0)
+
#define COMPLETE_WITH_VERSIONED_SCHEMA_QUERY(query) \
COMPLETE_WITH_VERSIONED_SCHEMA_QUERY_LIST(query, NULL)
@@ -312,29 +361,11 @@ do { \
#define COMPLETE_WITH_ATTR_LIST(relation, list) \
do { \
- char *_completion_schema; \
- char *_completion_table; \
-\
- _completion_schema = strtokx(relation, " \t\n\r", ".", "\"", 0, \
- false, false, pset.encoding); \
- (void) strtokx(NULL, " \t\n\r", ".", "\"", 0, \
- false, false, pset.encoding); \
- _completion_table = strtokx(NULL, " \t\n\r", ".", "\"", 0, \
- false, false, pset.encoding); \
- if (_completion_table == NULL) \
- { \
- completion_charp = Query_for_list_of_attributes; \
- completion_info_charp = relation; \
- } \
- else \
- { \
- completion_charp = Query_for_list_of_attributes_with_schema; \
- completion_info_charp = _completion_table; \
- completion_info_charp2 = _completion_schema; \
- } \
+ setup_completion_info(relation); \
+ completion_squery = &(Query_for_list_of_attributes); \
completion_charpp = list; \
completion_verbatim = false; \
- matches = rl_completion_matches(text, complete_from_query); \
+ matches = rl_completion_matches(text, complete_from_schema_query); \
} while (0)
#define COMPLETE_WITH_ATTR_PLUS(relation, ...) \
@@ -351,65 +382,24 @@ do { \
*/
#define COMPLETE_WITH_ENUM_VALUE(type) \
do { \
- char *_completion_schema; \
- char *_completion_type; \
- bool use_quotes; \
-\
- _completion_schema = strtokx(type, " \t\n\r", ".", "\"", 0, \
- false, false, pset.encoding); \
- (void) strtokx(NULL, " \t\n\r", ".", "\"", 0, \
- false, false, pset.encoding); \
- _completion_type = strtokx(NULL, " \t\n\r", ".", "\"", 0, \
- false, false, pset.encoding); \
- use_quotes = (text[0] == '\'' || \
- start == 0 || rl_line_buffer[start - 1] != '\''); \
- if (_completion_type == NULL) \
- { \
- if (use_quotes) \
- completion_charp = Query_for_list_of_enum_values_quoted; \
- else \
- completion_charp = Query_for_list_of_enum_values_unquoted; \
- completion_info_charp = type; \
- } \
+ setup_completion_info(type); \
+ if (text[0] == '\'' || \
+ start == 0 || rl_line_buffer[start - 1] != '\'') \
+ completion_squery = &(Query_for_list_of_enum_values_quoted); \
else \
- { \
- if (use_quotes) \
- completion_charp = Query_for_list_of_enum_values_with_schema_quoted; \
- else \
- completion_charp = Query_for_list_of_enum_values_with_schema_unquoted; \
- completion_info_charp = _completion_type; \
- completion_info_charp2 = _completion_schema; \
- } \
+ completion_squery = &(Query_for_list_of_enum_values_unquoted); \
completion_charpp = NULL; \
completion_verbatim = true; \
- matches = rl_completion_matches(text, complete_from_query); \
+ matches = rl_completion_matches(text, complete_from_schema_query); \
} while (0)
#define COMPLETE_WITH_FUNCTION_ARG(function) \
do { \
- char *_completion_schema; \
- char *_completion_function; \
-\
- _completion_schema = strtokx(function, " \t\n\r", ".", "\"", 0, \
- false, false, pset.encoding); \
- (void) strtokx(NULL, " \t\n\r", ".", "\"", 0, \
- false, false, pset.encoding); \
- _completion_function = strtokx(NULL, " \t\n\r", ".", "\"", 0, \
- false, false, pset.encoding); \
- if (_completion_function == NULL) \
- { \
- completion_charp = Query_for_list_of_arguments; \
- completion_info_charp = function; \
- } \
- else \
- { \
- completion_charp = Query_for_list_of_arguments_with_schema; \
- completion_info_charp = _completion_function; \
- completion_info_charp2 = _completion_schema; \
- } \
+ setup_completion_info(function); \
+ completion_squery = &(Query_for_list_of_arguments); \
completion_charpp = NULL; \
completion_verbatim = true; \
- matches = rl_completion_matches(text, complete_from_query); \
+ matches = rl_completion_matches(text, complete_from_schema_query); \
} while (0)
/*
@@ -419,6 +409,51 @@ do { \
* unnecessary bloat in the completions generated.
*/
+static const SchemaQuery Query_for_constraint_of_table = {
+ .catname = "pg_catalog.pg_constraint con, pg_catalog.pg_class c1",
+ .selcondition = "con.conrelid=c1.oid",
+ .result = "con.conname",
+ .infoname = "c1.relname",
+ .infoviscondition = "pg_catalog.pg_table_is_visible(c1.oid)",
+ .infonamespace = "c1.relnamespace",
+};
+
+static const SchemaQuery Query_for_constraint_of_table_not_validated = {
+ .catname = "pg_catalog.pg_constraint con, pg_catalog.pg_class c1",
+ .selcondition = "con.conrelid=c1.oid and not con.convalidated",
+ .result = "con.conname",
+ .infoname = "c1.relname",
+ .infoviscondition = "pg_catalog.pg_table_is_visible(c1.oid)",
+ .infonamespace = "c1.relnamespace",
+};
+
+static const SchemaQuery Query_for_constraint_of_type = {
+ .catname = "pg_catalog.pg_constraint con, pg_catalog.pg_type t",
+ .selcondition = "con.contypid=t.oid",
+ .result = "con.conname",
+ .infoname = "t.typname",
+ .infoviscondition = "pg_catalog.pg_type_is_visible(t.oid)",
+ .infonamespace = "t.typnamespace",
+};
+
+static const SchemaQuery Query_for_index_of_table = {
+ .catname = "pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i",
+ .selcondition = "c1.oid=i.indrelid and i.indexrelid=c2.oid",
+ .result = "c2.relname",
+ .infoname = "c1.relname",
+ .infoviscondition = "pg_catalog.pg_table_is_visible(c1.oid)",
+ .infonamespace = "c1.relnamespace",
+};
+
+static const SchemaQuery Query_for_unique_index_of_table = {
+ .catname = "pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i",
+ .selcondition = "c1.oid=i.indrelid and i.indexrelid=c2.oid and i.indisunique",
+ .result = "c2.relname",
+ .infoname = "c1.relname",
+ .infoviscondition = "pg_catalog.pg_table_is_visible(c1.oid)",
+ .infonamespace = "c1.relnamespace",
+};
+
static const SchemaQuery Query_for_list_of_aggregates[] = {
{
.min_server_version = 110000,
@@ -437,6 +472,32 @@ static const SchemaQuery Query_for_list_of_aggregates[] = {
}
};
+static const SchemaQuery Query_for_list_of_arguments = {
+ .catname = "pg_catalog.pg_proc p",
+ .result = "pg_catalog.oidvectortypes(p.proargtypes)||')'",
+ .infoname = "p.proname",
+ .infoviscondition = "pg_catalog.pg_function_is_visible(p.oid)",
+ .infonamespace = "p.pronamespace",
+};
+
+static const SchemaQuery Query_for_list_of_attributes = {
+ .catname = "pg_catalog.pg_attribute a, pg_catalog.pg_class c",
+ .selcondition = "c.oid = a.attrelid and a.attnum > 0 and not a.attisdropped",
+ .result = "a.attname",
+ .infoname = "c.relname",
+ .infoviscondition = "pg_catalog.pg_table_is_visible(c.oid)",
+ .infonamespace = "c.relnamespace",
+};
+
+static const SchemaQuery Query_for_list_of_attribute_numbers = {
+ .catname = "pg_catalog.pg_attribute a, pg_catalog.pg_class c",
+ .selcondition = "c.oid = a.attrelid and a.attnum > 0 and not a.attisdropped",
+ .result = "a.attnum::pg_catalog.text",
+ .infoname = "c.relname",
+ .infoviscondition = "pg_catalog.pg_table_is_visible(c.oid)",
+ .infonamespace = "c.relnamespace",
+};
+
static const char *const Keywords_for_list_of_datatypes[] = {
"bigint",
"boolean",
@@ -497,6 +558,24 @@ static const SchemaQuery Query_for_list_of_domains = {
.result = "t.typname",
};
+static const SchemaQuery Query_for_list_of_enum_values_quoted = {
+ .catname = "pg_catalog.pg_enum e, pg_catalog.pg_type t",
+ .selcondition = "t.oid = e.enumtypid",
+ .result = "pg_catalog.quote_literal(enumlabel)",
+ .infoname = "t.typname",
+ .infoviscondition = "pg_catalog.pg_type_is_visible(t.oid)",
+ .infonamespace = "t.typnamespace",
+};
+
+static const SchemaQuery Query_for_list_of_enum_values_unquoted = {
+ .catname = "pg_catalog.pg_enum e, pg_catalog.pg_type t",
+ .selcondition = "t.oid = e.enumtypid",
+ .result = "e.enumlabel",
+ .infoname = "t.typname",
+ .infoviscondition = "pg_catalog.pg_type_is_visible(t.oid)",
+ .infonamespace = "t.typnamespace",
+};
+
/* Note: this intentionally accepts aggregates as well as plain functions */
static const SchemaQuery Query_for_list_of_functions[] = {
{
@@ -571,6 +650,48 @@ static const SchemaQuery Query_for_list_of_partitioned_tables = {
.result = "c.relname",
};
+static const SchemaQuery Query_for_list_of_tables_for_constraint = {
+ .catname = "pg_catalog.pg_class c, pg_catalog.pg_constraint con",
+ .selcondition = "c.oid=con.conrelid and c.relkind IN ("
+ CppAsString2(RELKIND_RELATION) ", "
+ CppAsString2(RELKIND_PARTITIONED_TABLE) ")",
+ .viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
+ .namespace = "c.relnamespace",
+ .result = "c.relname",
+ .use_distinct = true,
+ .infoname = "con.conname",
+};
+
+static const SchemaQuery Query_for_list_of_tables_for_policy = {
+ .catname = "pg_catalog.pg_class c, pg_catalog.pg_policy p",
+ .selcondition = "c.oid=p.polrelid",
+ .viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
+ .namespace = "c.relnamespace",
+ .result = "c.relname",
+ .use_distinct = true,
+ .infoname = "p.polname",
+};
+
+static const SchemaQuery Query_for_list_of_tables_for_rule = {
+ .catname = "pg_catalog.pg_class c, pg_catalog.pg_rewrite r",
+ .selcondition = "c.oid=r.ev_class",
+ .viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
+ .namespace = "c.relnamespace",
+ .result = "c.relname",
+ .use_distinct = true,
+ .infoname = "r.rulename",
+};
+
+static const SchemaQuery Query_for_list_of_tables_for_trigger = {
+ .catname = "pg_catalog.pg_class c, pg_catalog.pg_trigger t",
+ .selcondition = "c.oid=t.tgrelid",
+ .viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
+ .namespace = "c.relnamespace",
+ .result = "c.relname",
+ .use_distinct = true,
+ .infoname = "t.tgname",
+};
+
static const SchemaQuery Query_for_list_of_views = {
.catname = "pg_catalog.pg_class c",
.selcondition = "c.relkind IN (" CppAsString2(RELKIND_VIEW) ")",
@@ -719,7 +840,6 @@ static const SchemaQuery Query_for_list_of_clusterables = {
static const SchemaQuery Query_for_list_of_constraints_with_schema = {
.catname = "pg_catalog.pg_constraint c",
.selcondition = "c.conrelid <> 0",
- .viscondition = "true", /* there is no pg_constraint_is_visible */
.namespace = "c.connamespace",
.result = "c.conname",
};
@@ -739,96 +859,56 @@ static const SchemaQuery Query_for_list_of_collations = {
.result = "c.collname",
};
+static const SchemaQuery Query_for_partition_of_table = {
+ .catname = "pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_inherits i",
+ .selcondition = "c1.oid=i.inhparent and i.inhrelid=c2.oid and c2.relispartition",
+ .viscondition = "pg_catalog.pg_table_is_visible(c2.oid)",
+ .namespace = "c2.relnamespace",
+ .result = "c2.relname",
+ .infoname = "c1.relname",
+ .infoviscondition = "pg_catalog.pg_table_is_visible(c1.oid)",
+ .infonamespace = "c1.relnamespace",
+};
+
+static const SchemaQuery Query_for_rule_of_table = {
+ .catname = "pg_catalog.pg_rewrite r, pg_catalog.pg_class c1",
+ .selcondition = "r.ev_class=c1.oid",
+ .result = "r.rulename",
+ .infoname = "c1.relname",
+ .infoviscondition = "pg_catalog.pg_table_is_visible(c1.oid)",
+ .infonamespace = "c1.relnamespace",
+};
+
+static const SchemaQuery Query_for_trigger_of_table = {
+ .catname = "pg_catalog.pg_trigger t, pg_catalog.pg_class c1",
+ .selcondition = "t.tgrelid=c1.oid and not t.tgisinternal",
+ .result = "t.tgname",
+ .infoname = "c1.relname",
+ .infoviscondition = "pg_catalog.pg_table_is_visible(c1.oid)",
+ .infonamespace = "c1.relnamespace",
+};
+
/*
* Queries to get lists of names of various kinds of things, possibly
- * restricted to names matching a partially entered name. In these queries,
- * the first %s will be replaced by the text entered so far (suitably escaped
- * to become a SQL literal string). %d will be replaced by the length of the
- * string (in unescaped form). A second and third %s, if present, will be
- * replaced by a suitably-escaped version of the string provided in
- * completion_info_charp. A fourth and fifth %s are similarly replaced by
- * completion_info_charp2.
+ * restricted to names matching a partially entered name. Don't use
+ * this method where the user might wish to enter a schema-qualified
+ * name; make a SchemaQuery instead.
+ *
+ * In these queries, there must be a restriction clause of the form
+ * substring(OUTPUT,1,%d)='%s'
+ * where "OUTPUT" is the same string that the query returns. The %d and %s
+ * will be replaced by the string length of the text and the text itself,
+ * causing the results to be limited to those matching the already-typed text.
*
- * Beware that the allowed sequences of %s and %d are determined by
- * _complete_from_query().
+ * There can be a second '%s', which will be replaced by a suitably-escaped
+ * version of the string provided in completion_info_object. If there is a
+ * third '%s', it will be replaced by a suitably-escaped version of the string
+ * provided in completion_info_schema. NOTE: using completion_info_object
+ * that way is usually the wrong thing, and using completion_info_schema
+ * that way is always the wrong thing. Make a SchemaQuery instead.
*/
-#define Query_for_list_of_attributes \
-"SELECT 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 substring(attname,1,%d)='%s' "\
-" AND (relname='%s' "\
-" OR '\"' || relname || '\"'='%s') "\
-" AND pg_catalog.pg_table_is_visible(c.oid)"
-
-#define Query_for_list_of_attribute_numbers \
-"SELECT attnum "\
-" 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 substring(attnum::pg_catalog.text,1,%d)='%s' "\
-" AND (relname='%s' "\
-" OR '\"' || relname || '\"'='%s') "\
-" AND pg_catalog.pg_table_is_visible(c.oid)"
-
-#define Query_for_list_of_attributes_with_schema \
-"SELECT attname "\
-" FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
-" WHERE c.oid = a.attrelid "\
-" AND n.oid = c.relnamespace "\
-" AND a.attnum > 0 "\
-" AND NOT a.attisdropped "\
-" AND substring(attname,1,%d)='%s' "\
-" AND (relname='%s' "\
-" OR '\"' || relname || '\"' ='%s') "\
-" AND (nspname='%s' "\
-" OR '\"' || nspname || '\"' ='%s') "
-
-#define Query_for_list_of_enum_values_quoted \
-"SELECT pg_catalog.quote_literal(enumlabel) "\
-" FROM pg_catalog.pg_enum e, pg_catalog.pg_type t "\
-" WHERE t.oid = e.enumtypid "\
-" AND substring(pg_catalog.quote_literal(enumlabel),1,%d)='%s' "\
-" AND (typname='%s' "\
-" OR '\"' || typname || '\"'='%s') "\
-" AND pg_catalog.pg_type_is_visible(t.oid)"
-
-#define Query_for_list_of_enum_values_unquoted \
-"SELECT enumlabel "\
-" FROM pg_catalog.pg_enum e, pg_catalog.pg_type t "\
-" WHERE t.oid = e.enumtypid "\
-" AND substring(enumlabel,1,%d)='%s' "\
-" AND (typname='%s' "\
-" OR '\"' || typname || '\"'='%s') "\
-" AND pg_catalog.pg_type_is_visible(t.oid)"
-
-#define Query_for_list_of_enum_values_with_schema_quoted \
-"SELECT pg_catalog.quote_literal(enumlabel) "\
-" FROM pg_catalog.pg_enum e, pg_catalog.pg_type t, pg_catalog.pg_namespace n "\
-" WHERE t.oid = e.enumtypid "\
-" AND n.oid = t.typnamespace "\
-" AND substring(pg_catalog.quote_literal(enumlabel),1,%d)='%s' "\
-" AND (typname='%s' "\
-" OR '\"' || typname || '\"'='%s') "\
-" AND (nspname='%s' "\
-" OR '\"' || nspname || '\"' ='%s') "
-
-#define Query_for_list_of_enum_values_with_schema_unquoted \
-"SELECT enumlabel "\
-" FROM pg_catalog.pg_enum e, pg_catalog.pg_type t, pg_catalog.pg_namespace n "\
-" WHERE t.oid = e.enumtypid "\
-" AND n.oid = t.typnamespace "\
-" AND substring(enumlabel,1,%d)='%s' "\
-" AND (typname='%s' "\
-" OR '\"' || typname || '\"'='%s') "\
-" AND (nspname='%s' "\
-" OR '\"' || nspname || '\"' ='%s') "
-
#define Query_for_list_of_template_databases \
"SELECT d.datname "\
" FROM pg_catalog.pg_database d "\
@@ -887,81 +967,12 @@ static const SchemaQuery Query_for_list_of_collations = {
#define Keywords_for_list_of_grant_roles \
"PUBLIC", "CURRENT_ROLE", "CURRENT_USER", "SESSION_USER"
-#define Query_for_index_of_table \
-"SELECT c2.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 substring(c2.relname,1,%d)='%s'"\
-" and c1.relname='%s'"\
-" and pg_catalog.pg_table_is_visible(c2.oid)"
-
-#define Query_for_unique_index_of_table \
-Query_for_index_of_table \
-" and i.indisunique"
-
-#define Query_for_constraint_of_table \
-"SELECT conname "\
-" FROM pg_catalog.pg_class c1, pg_catalog.pg_constraint con "\
-" WHERE c1.oid=conrelid and substring(conname,1,%d)='%s'"\
-" and c1.relname='%s'"\
-" and pg_catalog.pg_table_is_visible(c1.oid)"
-
-#define Query_for_constraint_of_table_not_validated \
-Query_for_constraint_of_table \
-" and not con.convalidated"
-
#define Query_for_all_table_constraints \
"SELECT conname "\
" FROM pg_catalog.pg_constraint c "\
" WHERE c.conrelid <> 0 "\
" and substring(conname,1,%d)='%s'"
-#define Query_for_constraint_of_type \
-"SELECT conname "\
-" FROM pg_catalog.pg_type t, pg_catalog.pg_constraint con "\
-" WHERE t.oid=contypid and substring(conname,1,%d)='%s'"\
-" and t.typname='%s'"\
-" and pg_catalog.pg_type_is_visible(t.oid)"
-
-#define Query_for_list_of_tables_for_constraint \
-"SELECT relname "\
-" FROM pg_catalog.pg_class"\
-" WHERE substring(relname,1,%d)='%s'"\
-" AND oid IN "\
-" (SELECT conrelid FROM pg_catalog.pg_constraint "\
-" WHERE conname='%s')"
-
-#define Query_for_rule_of_table \
-"SELECT rulename "\
-" FROM pg_catalog.pg_class c1, pg_catalog.pg_rewrite "\
-" WHERE c1.oid=ev_class and substring(rulename,1,%d)='%s'"\
-" and c1.relname='%s'"\
-" and pg_catalog.pg_table_is_visible(c1.oid)"
-
-#define Query_for_list_of_tables_for_rule \
-"SELECT relname "\
-" FROM pg_catalog.pg_class"\
-" WHERE substring(relname,1,%d)='%s'"\
-" AND oid IN "\
-" (SELECT ev_class FROM pg_catalog.pg_rewrite "\
-" WHERE rulename='%s')"
-
-#define Query_for_trigger_of_table \
-"SELECT tgname "\
-" FROM pg_catalog.pg_class c1, pg_catalog.pg_trigger "\
-" WHERE c1.oid=tgrelid and substring(tgname,1,%d)='%s'"\
-" and c1.relname='%s'"\
-" and pg_catalog.pg_table_is_visible(c1.oid)"\
-" and not tgisinternal"
-
-#define Query_for_list_of_tables_for_trigger \
-"SELECT relname "\
-" FROM pg_catalog.pg_class"\
-" WHERE substring(relname,1,%d)='%s'"\
-" AND oid IN "\
-" (SELECT tgrelid FROM pg_catalog.pg_trigger "\
-" WHERE tgname='%s')"
-
#define Query_for_list_of_ts_configurations \
"SELECT cfgname FROM pg_catalog.pg_ts_config "\
" WHERE substring(cfgname,1,%d)='%s'"
@@ -1010,24 +1021,6 @@ Query_for_constraint_of_table \
" WHERE substring(amname,1,%d)='%s' AND "\
" amtype=" CppAsString2(AMTYPE_TABLE)
-#define Query_for_list_of_arguments \
-"SELECT pg_catalog.oidvectortypes(proargtypes)||')' "\
-" FROM pg_catalog.pg_proc "\
-" WHERE substring(pg_catalog.oidvectortypes(proargtypes)||')',1,%d)='%s'"\
-" AND (proname='%s'"\
-" OR '\"' || proname || '\"'='%s') "\
-" AND (pg_catalog.pg_function_is_visible(pg_proc.oid))"
-
-#define Query_for_list_of_arguments_with_schema \
-"SELECT pg_catalog.oidvectortypes(proargtypes)||')' "\
-" FROM pg_catalog.pg_proc p, pg_catalog.pg_namespace n "\
-" WHERE substring(pg_catalog.oidvectortypes(proargtypes)||')',1,%d)='%s'"\
-" AND n.oid = p.pronamespace "\
-" AND (proname='%s' "\
-" OR '\"' || proname || '\"' ='%s') "\
-" AND (nspname='%s' "\
-" OR '\"' || nspname || '\"' ='%s') "
-
#define Query_for_list_of_extensions \
" SELECT extname "\
" FROM pg_catalog.pg_extension "\
@@ -1074,30 +1067,18 @@ Query_for_constraint_of_table \
" FROM pg_catalog.pg_policy "\
" WHERE substring(polname,1,%d)='%s'"
-#define Query_for_list_of_tables_for_policy \
-"SELECT relname "\
-" FROM pg_catalog.pg_class"\
-" WHERE substring(relname,1,%d)='%s'"\
-" AND oid IN "\
-" (SELECT polrelid FROM pg_catalog.pg_policy "\
-" WHERE polname='%s')"
-
-#define Query_for_enum \
-" SELECT name FROM ( "\
-" SELECT pg_catalog.unnest(enumvals) AS name "\
+#define Query_for_values_of_enum_GUC \
+" SELECT val FROM ( "\
+" SELECT name, pg_catalog.unnest(enumvals) AS val "\
" FROM pg_catalog.pg_settings "\
-" WHERE pg_catalog.lower(name)=pg_catalog.lower('%s') "\
" ) ss "\
-" WHERE pg_catalog.substring(name,1,%%d)='%%s'"
+" WHERE substring(val,1,%d)='%s'"\
+" and pg_catalog.lower(name)=pg_catalog.lower('%s')"
-#define Query_for_partition_of_table \
-"SELECT c2.relname "\
-" FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_inherits i"\
-" WHERE c1.oid=i.inhparent and i.inhrelid=c2.oid"\
-" and substring(c2.relname,1,%d)='%s'"\
-" and c1.relname='%s'"\
-" and pg_catalog.pg_table_is_visible(c2.oid)"\
-" and c2.relispartition = 'true'"
+#define Query_for_list_of_channels \
+" SELECT channel "\
+" FROM pg_catalog.pg_listening_channels() AS channel "\
+" WHERE substring(channel,1,%d)='%s'"
#define Query_for_list_of_cursors \
" SELECT name "\
@@ -1280,6 +1261,7 @@ static char *_complete_from_query(const char *simple_query,
const char *const *keywords,
bool verbatim,
const char *text, int state);
+static void setup_completion_info(const char *word);
static char *complete_from_list(const char *text, int state);
static char *complete_from_const(const char *text, int state);
static void append_variable_names(char ***varnames, int *nvars,
@@ -1685,8 +1667,10 @@ psql_completion(const char *text, int start, int end)
/* Clear a few things. */
completion_charp = NULL;
completion_charpp = NULL;
- completion_info_charp = NULL;
- completion_info_charp2 = NULL;
+ completion_vquery = NULL;
+ completion_squery = NULL;
+ completion_info_object = NULL;
+ completion_info_schema = NULL;
/*
* Scan the input line to extract the words before our current position.
@@ -1872,14 +1856,14 @@ psql_completion(const char *text, int start, int end)
/* ALTER EXTENSION <name> UPDATE */
else if (Matches("ALTER", "EXTENSION", MatchAny, "UPDATE"))
{
- completion_info_charp = prev2_wd;
+ setup_completion_info(prev2_wd);
COMPLETE_WITH_QUERY_VERBATIM(Query_for_list_of_available_extension_versions_with_TO);
}
/* ALTER EXTENSION <name> UPDATE TO */
else if (Matches("ALTER", "EXTENSION", MatchAny, "UPDATE", "TO"))
{
- completion_info_charp = prev3_wd;
+ setup_completion_info(prev3_wd);
COMPLETE_WITH_QUERY_VERBATIM(Query_for_list_of_available_extension_versions);
}
@@ -1919,8 +1903,8 @@ psql_completion(const char *text, int start, int end)
/* ALTER INDEX <name> ALTER COLUMN */
else if (Matches("ALTER", "INDEX", MatchAny, "ALTER", "COLUMN"))
{
- completion_info_charp = prev3_wd;
- COMPLETE_WITH_QUERY(Query_for_list_of_attribute_numbers);
+ setup_completion_info(prev3_wd);
+ COMPLETE_WITH_SCHEMA_QUERY_VERBATIM(Query_for_list_of_attribute_numbers);
}
/* ALTER INDEX <name> ALTER COLUMN <colnum> */
else if (Matches("ALTER", "INDEX", MatchAny, "ALTER", "COLUMN", MatchAny))
@@ -2030,8 +2014,8 @@ psql_completion(const char *text, int start, int end)
/* ALTER DOMAIN <sth> DROP|RENAME|VALIDATE CONSTRAINT */
else if (Matches("ALTER", "DOMAIN", MatchAny, "DROP|RENAME|VALIDATE", "CONSTRAINT"))
{
- completion_info_charp = prev3_wd;
- COMPLETE_WITH_QUERY(Query_for_constraint_of_type);
+ setup_completion_info(prev3_wd);
+ COMPLETE_WITH_SCHEMA_QUERY(Query_for_constraint_of_type);
}
/* ALTER DOMAIN <sth> RENAME */
else if (Matches("ALTER", "DOMAIN", MatchAny, "RENAME"))
@@ -2116,8 +2100,8 @@ psql_completion(const char *text, int start, int end)
/* ALTER POLICY <name> ON <table> */
else if (Matches("ALTER", "POLICY", MatchAny, "ON"))
{
- completion_info_charp = prev2_wd;
- COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_policy);
+ setup_completion_info(prev2_wd);
+ COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables_for_policy);
}
/* ALTER POLICY <name> ON <table> - show options */
else if (Matches("ALTER", "POLICY", MatchAny, "ON", MatchAny))
@@ -2140,8 +2124,8 @@ psql_completion(const char *text, int start, int end)
/* If we have ALTER RULE <name> ON, then add the correct tablename */
else if (Matches("ALTER", "RULE", MatchAny, "ON"))
{
- completion_info_charp = prev2_wd;
- COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_rule);
+ setup_completion_info(prev2_wd);
+ COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables_for_rule);
}
/* ALTER RULE <name> ON <name> */
@@ -2156,18 +2140,12 @@ psql_completion(const char *text, int start, int end)
else if (Matches("ALTER", "TRIGGER", MatchAny))
COMPLETE_WITH("ON");
- else if (Matches("ALTER", "TRIGGER", MatchAny, MatchAny))
+ else if (Matches("ALTER", "TRIGGER", MatchAny, "ON"))
{
- completion_info_charp = prev2_wd;
- COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_trigger);
+ setup_completion_info(prev2_wd);
+ COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables_for_trigger);
}
- /*
- * If we have ALTER TRIGGER <sth> ON, then add the correct tablename
- */
- else if (Matches("ALTER", "TRIGGER", MatchAny, "ON"))
- COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
-
/* ALTER TRIGGER <name> ON <name> */
else if (Matches("ALTER", "TRIGGER", MatchAny, "ON", MatchAny))
COMPLETE_WITH("RENAME TO", "DEPENDS ON EXTENSION",
@@ -2206,28 +2184,28 @@ psql_completion(const char *text, int start, int end)
/* ALTER TABLE xxx ADD PRIMARY KEY USING INDEX */
else if (Matches("ALTER", "TABLE", MatchAny, "ADD", "PRIMARY", "KEY", "USING", "INDEX"))
{
- completion_info_charp = prev6_wd;
- COMPLETE_WITH_QUERY(Query_for_unique_index_of_table);
+ setup_completion_info(prev6_wd);
+ COMPLETE_WITH_SCHEMA_QUERY(Query_for_unique_index_of_table);
}
/* ALTER TABLE xxx ADD UNIQUE USING INDEX */
else if (Matches("ALTER", "TABLE", MatchAny, "ADD", "UNIQUE", "USING", "INDEX"))
{
- completion_info_charp = prev5_wd;
- COMPLETE_WITH_QUERY(Query_for_unique_index_of_table);
+ setup_completion_info(prev5_wd);
+ COMPLETE_WITH_SCHEMA_QUERY(Query_for_unique_index_of_table);
}
/* ALTER TABLE xxx ADD CONSTRAINT yyy PRIMARY KEY USING INDEX */
else if (Matches("ALTER", "TABLE", MatchAny, "ADD", "CONSTRAINT", MatchAny,
"PRIMARY", "KEY", "USING", "INDEX"))
{
- completion_info_charp = prev8_wd;
- COMPLETE_WITH_QUERY(Query_for_unique_index_of_table);
+ setup_completion_info(prev8_wd);
+ COMPLETE_WITH_SCHEMA_QUERY(Query_for_unique_index_of_table);
}
/* ALTER TABLE xxx ADD CONSTRAINT yyy UNIQUE USING INDEX */
else if (Matches("ALTER", "TABLE", MatchAny, "ADD", "CONSTRAINT", MatchAny,
"UNIQUE", "USING", "INDEX"))
{
- completion_info_charp = prev7_wd;
- COMPLETE_WITH_QUERY(Query_for_unique_index_of_table);
+ setup_completion_info(prev7_wd);
+ COMPLETE_WITH_SCHEMA_QUERY(Query_for_unique_index_of_table);
}
/* ALTER TABLE xxx ENABLE */
else if (Matches("ALTER", "TABLE", MatchAny, "ENABLE"))
@@ -2237,23 +2215,23 @@ psql_completion(const char *text, int start, int end)
COMPLETE_WITH("RULE", "TRIGGER");
else if (Matches("ALTER", "TABLE", MatchAny, "ENABLE", "RULE"))
{
- completion_info_charp = prev3_wd;
- COMPLETE_WITH_QUERY(Query_for_rule_of_table);
+ setup_completion_info(prev3_wd);
+ COMPLETE_WITH_SCHEMA_QUERY(Query_for_rule_of_table);
}
else if (Matches("ALTER", "TABLE", MatchAny, "ENABLE", MatchAny, "RULE"))
{
- completion_info_charp = prev4_wd;
- COMPLETE_WITH_QUERY(Query_for_rule_of_table);
+ setup_completion_info(prev4_wd);
+ COMPLETE_WITH_SCHEMA_QUERY(Query_for_rule_of_table);
}
else if (Matches("ALTER", "TABLE", MatchAny, "ENABLE", "TRIGGER"))
{
- completion_info_charp = prev3_wd;
- COMPLETE_WITH_QUERY(Query_for_trigger_of_table);
+ setup_completion_info(prev3_wd);
+ COMPLETE_WITH_SCHEMA_QUERY(Query_for_trigger_of_table);
}
else if (Matches("ALTER", "TABLE", MatchAny, "ENABLE", MatchAny, "TRIGGER"))
{
- completion_info_charp = prev4_wd;
- COMPLETE_WITH_QUERY(Query_for_trigger_of_table);
+ setup_completion_info(prev4_wd);
+ COMPLETE_WITH_SCHEMA_QUERY(Query_for_trigger_of_table);
}
/* ALTER TABLE xxx INHERIT */
else if (Matches("ALTER", "TABLE", MatchAny, "INHERIT"))
@@ -2269,13 +2247,13 @@ psql_completion(const char *text, int start, int end)
COMPLETE_WITH("ROW LEVEL SECURITY", "RULE", "TRIGGER");
else if (Matches("ALTER", "TABLE", MatchAny, "DISABLE", "RULE"))
{
- completion_info_charp = prev3_wd;
- COMPLETE_WITH_QUERY(Query_for_rule_of_table);
+ setup_completion_info(prev3_wd);
+ COMPLETE_WITH_SCHEMA_QUERY(Query_for_rule_of_table);
}
else if (Matches("ALTER", "TABLE", MatchAny, "DISABLE", "TRIGGER"))
{
- completion_info_charp = prev3_wd;
- COMPLETE_WITH_QUERY(Query_for_trigger_of_table);
+ setup_completion_info(prev3_wd);
+ COMPLETE_WITH_SCHEMA_QUERY(Query_for_trigger_of_table);
}
/* ALTER TABLE xxx ALTER */
@@ -2305,14 +2283,14 @@ psql_completion(const char *text, int start, int end)
/* ALTER TABLE <sth> ALTER|DROP|RENAME CONSTRAINT <constraint> */
else if (Matches("ALTER", "TABLE", MatchAny, "ALTER|DROP|RENAME", "CONSTRAINT"))
{
- completion_info_charp = prev3_wd;
- COMPLETE_WITH_QUERY(Query_for_constraint_of_table);
+ setup_completion_info(prev3_wd);
+ COMPLETE_WITH_SCHEMA_QUERY(Query_for_constraint_of_table);
}
/* ALTER TABLE <sth> VALIDATE CONSTRAINT <non-validated constraint> */
else if (Matches("ALTER", "TABLE", MatchAny, "VALIDATE", "CONSTRAINT"))
{
- completion_info_charp = prev3_wd;
- COMPLETE_WITH_QUERY(Query_for_constraint_of_table_not_validated);
+ setup_completion_info(prev3_wd);
+ COMPLETE_WITH_SCHEMA_QUERY(Query_for_constraint_of_table_not_validated);
}
/* ALTER TABLE ALTER [COLUMN] <foo> */
else if (Matches("ALTER", "TABLE", MatchAny, "ALTER", "COLUMN", MatchAny) ||
@@ -2344,8 +2322,8 @@ psql_completion(const char *text, int start, int end)
COMPLETE_WITH("ON");
else if (Matches("ALTER", "TABLE", MatchAny, "CLUSTER", "ON"))
{
- completion_info_charp = prev3_wd;
- COMPLETE_WITH_QUERY(Query_for_index_of_table);
+ setup_completion_info(prev3_wd);
+ COMPLETE_WITH_SCHEMA_QUERY(Query_for_index_of_table);
}
/* If we have ALTER TABLE <sth> SET, provide list of attributes and '(' */
else if (Matches("ALTER", "TABLE", MatchAny, "SET"))
@@ -2376,8 +2354,8 @@ psql_completion(const char *text, int start, int end)
COMPLETE_WITH_LIST(table_storage_parameters);
else if (Matches("ALTER", "TABLE", MatchAny, "REPLICA", "IDENTITY", "USING", "INDEX"))
{
- completion_info_charp = prev5_wd;
- COMPLETE_WITH_QUERY(Query_for_index_of_table);
+ setup_completion_info(prev5_wd);
+ COMPLETE_WITH_SCHEMA_QUERY(Query_for_index_of_table);
}
else if (Matches("ALTER", "TABLE", MatchAny, "REPLICA", "IDENTITY", "USING"))
COMPLETE_WITH("INDEX");
@@ -2404,8 +2382,8 @@ psql_completion(const char *text, int start, int end)
*/
else if (Matches("ALTER", "TABLE", MatchAny, "DETACH", "PARTITION"))
{
- completion_info_charp = prev3_wd;
- COMPLETE_WITH_QUERY(Query_for_partition_of_table);
+ setup_completion_info(prev3_wd);
+ COMPLETE_WITH_SCHEMA_QUERY(Query_for_partition_of_table);
}
else if (Matches("ALTER", "TABLE", MatchAny, "DETACH", "PARTITION", MatchAny))
COMPLETE_WITH("CONCURRENTLY", "FINALIZE");
@@ -2542,8 +2520,8 @@ psql_completion(const char *text, int start, int end)
else if (Matches("CLUSTER", MatchAny, "USING") ||
Matches("CLUSTER", "VERBOSE|(*)", MatchAny, "USING"))
{
- completion_info_charp = prev2_wd;
- COMPLETE_WITH_QUERY(Query_for_index_of_table);
+ setup_completion_info(prev2_wd);
+ COMPLETE_WITH_SCHEMA_QUERY(Query_for_index_of_table);
}
else if (HeadMatches("CLUSTER", "(*") &&
!HeadMatches("CLUSTER", "(*)"))
@@ -2580,9 +2558,9 @@ psql_completion(const char *text, int start, int end)
COMPLETE_WITH("ON");
else if (Matches("COMMENT", "ON", "CONSTRAINT", MatchAny, "ON"))
{
- completion_info_charp = prev2_wd;
- COMPLETE_WITH_QUERY_PLUS(Query_for_list_of_tables_for_constraint,
- "DOMAIN");
+ setup_completion_info(prev2_wd);
+ COMPLETE_WITH_SCHEMA_QUERY_PLUS(Query_for_list_of_tables_for_constraint,
+ "DOMAIN");
}
else if (Matches("COMMENT", "ON", "CONSTRAINT", MatchAny, "ON", "DOMAIN"))
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains);
@@ -2600,8 +2578,8 @@ psql_completion(const char *text, int start, int end)
COMPLETE_WITH("ON");
else if (Matches("COMMENT", "ON", "POLICY", MatchAny, "ON"))
{
- completion_info_charp = prev2_wd;
- COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_policy);
+ setup_completion_info(prev2_wd);
+ COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables_for_policy);
}
else if (Matches("COMMENT", "ON", "PROCEDURAL", "LANGUAGE"))
COMPLETE_WITH_QUERY(Query_for_list_of_languages);
@@ -2609,8 +2587,8 @@ psql_completion(const char *text, int start, int end)
COMPLETE_WITH("ON");
else if (Matches("COMMENT", "ON", "RULE", MatchAny, "ON"))
{
- completion_info_charp = prev2_wd;
- COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_rule);
+ setup_completion_info(prev2_wd);
+ COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables_for_rule);
}
else if (Matches("COMMENT", "ON", "TEXT", "SEARCH"))
COMPLETE_WITH("CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE");
@@ -2628,15 +2606,15 @@ psql_completion(const char *text, int start, int end)
COMPLETE_WITH("LANGUAGE");
else if (Matches("COMMENT", "ON", "TRANSFORM", "FOR", MatchAny, "LANGUAGE"))
{
- completion_info_charp = prev2_wd;
+ setup_completion_info(prev2_wd);
COMPLETE_WITH_QUERY(Query_for_list_of_languages);
}
else if (Matches("COMMENT", "ON", "TRIGGER", MatchAny))
COMPLETE_WITH("ON");
else if (Matches("COMMENT", "ON", "TRIGGER", MatchAny, "ON"))
{
- completion_info_charp = prev2_wd;
- COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_trigger);
+ setup_completion_info(prev2_wd);
+ COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables_for_trigger);
}
else if (Matches("COMMENT", "ON", MatchAny, MatchAnyExcept("IS")) ||
Matches("COMMENT", "ON", MatchAny, MatchAny, MatchAnyExcept("IS")) ||
@@ -2752,7 +2730,7 @@ psql_completion(const char *text, int start, int end)
/* CREATE EXTENSION <name> VERSION */
else if (Matches("CREATE", "EXTENSION", MatchAny, "VERSION"))
{
- completion_info_charp = prev2_wd;
+ setup_completion_info(prev2_wd);
COMPLETE_WITH_QUERY_VERBATIM(Query_for_list_of_available_extension_versions);
}
@@ -3063,7 +3041,7 @@ psql_completion(const char *text, int start, int end)
else if (Matches("CREATE", "TRANSFORM", "FOR", MatchAny, "LANGUAGE") ||
Matches("CREATE", "OR", "REPLACE", "TRANSFORM", "FOR", MatchAny, "LANGUAGE"))
{
- completion_info_charp = prev2_wd;
+ setup_completion_info(prev2_wd);
COMPLETE_WITH_QUERY(Query_for_list_of_languages);
}
@@ -3486,8 +3464,8 @@ psql_completion(const char *text, int start, int end)
COMPLETE_WITH("ON");
else if (Matches("DROP", "TRIGGER", MatchAny, "ON"))
{
- completion_info_charp = prev2_wd;
- COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_trigger);
+ setup_completion_info(prev2_wd);
+ COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables_for_trigger);
}
else if (Matches("DROP", "TRIGGER", MatchAny, "ON", MatchAny))
COMPLETE_WITH("CASCADE", "RESTRICT");
@@ -3513,8 +3491,8 @@ psql_completion(const char *text, int start, int end)
/* DROP POLICY <name> ON <table> */
else if (Matches("DROP", "POLICY", MatchAny, "ON"))
{
- completion_info_charp = prev2_wd;
- COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_policy);
+ setup_completion_info(prev2_wd);
+ COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables_for_policy);
}
else if (Matches("DROP", "POLICY", MatchAny, "ON", MatchAny))
COMPLETE_WITH("CASCADE", "RESTRICT");
@@ -3524,8 +3502,8 @@ psql_completion(const char *text, int start, int end)
COMPLETE_WITH("ON");
else if (Matches("DROP", "RULE", MatchAny, "ON"))
{
- completion_info_charp = prev2_wd;
- COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_rule);
+ setup_completion_info(prev2_wd);
+ COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables_for_rule);
}
else if (Matches("DROP", "RULE", MatchAny, "ON", MatchAny))
COMPLETE_WITH("CASCADE", "RESTRICT");
@@ -3539,7 +3517,7 @@ psql_completion(const char *text, int start, int end)
COMPLETE_WITH("LANGUAGE");
else if (Matches("DROP", "TRANSFORM", "FOR", MatchAny, "LANGUAGE"))
{
- completion_info_charp = prev2_wd;
+ setup_completion_info(prev2_wd);
COMPLETE_WITH_QUERY(Query_for_list_of_languages);
}
else if (Matches("DROP", "TRANSFORM", "FOR", MatchAny, "LANGUAGE", MatchAny))
@@ -3923,7 +3901,7 @@ psql_completion(const char *text, int start, int end)
/* NOTIFY --- can be inside EXPLAIN, RULE, etc */
else if (TailMatches("NOTIFY"))
- COMPLETE_WITH_QUERY("SELECT channel FROM pg_catalog.pg_listening_channels() AS channel WHERE substring(channel,1,%d)='%s'");
+ COMPLETE_WITH_QUERY(Query_for_list_of_channels);
/* OPTIONS */
else if (TailMatches("OPTIONS"))
@@ -4159,11 +4137,9 @@ psql_completion(const char *text, int start, int end)
{
if (strcmp(guctype, "enum") == 0)
{
- char querybuf[1024];
-
- snprintf(querybuf, sizeof(querybuf),
- Query_for_enum, prev2_wd);
- COMPLETE_WITH_QUERY_PLUS(querybuf, "DEFAULT");
+ setup_completion_info(prev2_wd);
+ COMPLETE_WITH_QUERY_PLUS(Query_for_values_of_enum_GUC,
+ "DEFAULT");
}
else if (strcmp(guctype, "bool") == 0)
COMPLETE_WITH("on", "off", "true", "false", "yes", "no",
@@ -4208,9 +4184,7 @@ psql_completion(const char *text, int start, int end)
/* UNLISTEN */
else if (Matches("UNLISTEN"))
- COMPLETE_WITH_QUERY_PLUS("SELECT channel FROM pg_catalog.pg_listening_channels() AS channel"
- " WHERE substring(channel,1,%d)='%s'",
- "*");
+ COMPLETE_WITH_QUERY_PLUS(Query_for_list_of_channels, "*");
/* UPDATE --- can be inside EXPLAIN, RULE, etc */
/* If prev. word is UPDATE suggest a list of tables */
@@ -4411,7 +4385,7 @@ psql_completion(const char *text, int start, int end)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views);
else if (TailMatchesCS("\\encoding"))
- COMPLETE_WITH_QUERY(Query_for_list_of_encodings);
+ COMPLETE_WITH_QUERY_VERBATIM(Query_for_list_of_encodings);
else if (TailMatchesCS("\\h|\\help"))
COMPLETE_WITH_LIST(sql_commands);
else if (TailMatchesCS("\\h|\\help", MatchAny))
@@ -4570,6 +4544,12 @@ psql_completion(const char *text, int start, int end)
free(previous_words);
free(words_buffer);
free(text_copy);
+ if (completion_info_object)
+ free(completion_info_object);
+ completion_info_object = NULL;
+ if (completion_info_schema)
+ free(completion_info_schema);
+ completion_info_schema = NULL;
/* Return our Grand List O' Matches */
return matches;
@@ -4713,10 +4693,11 @@ complete_from_versioned_schema_query(const char *text, int state)
* where "OUTPUT" is the same string that the query returns. The %d and %s
* will be replaced by the string length of the text and the text itself,
* causing the results to be limited to those matching the already-typed text.
- * The query may also have up to four more %s in it; the first two such will
- * be replaced by the value of completion_info_charp, the next two by the
- * value of completion_info_charp2. (These strings will be escaped to
- * become SQL literals, so what is actually in the query should be '%s'.)
+ * There can be a second '%s', which will be replaced by a suitably-escaped
+ * version of the string provided in completion_info_object. If there is a
+ * third '%s', it will be replaced by a suitably-escaped version of the string
+ * provided in completion_info_schema. Those strings should be set up
+ * by calling setup_completion_info().
* Simple queries should return a single column of matches. If "verbatim"
* is true, the matches are returned as-is; otherwise, they are taken to
* be SQL identifiers and quoted if necessary.
@@ -4769,8 +4750,8 @@ _complete_from_query(const char *simple_query,
int object_length = 0;
char *e_schemaname;
char *e_objectname;
- char *e_info_charp;
- char *e_info_charp2;
+ char *e_info_object;
+ char *e_info_schema;
/* Reset static state, ensuring no memory leaks */
list_index = 0;
@@ -4812,15 +4793,15 @@ _complete_from_query(const char *simple_query,
e_objectname = escape_string(objectname);
- if (completion_info_charp)
- e_info_charp = escape_string(completion_info_charp);
+ if (completion_info_object)
+ e_info_object = escape_string(completion_info_object);
else
- e_info_charp = NULL;
+ e_info_object = NULL;
- if (completion_info_charp2)
- e_info_charp2 = escape_string(completion_info_charp2);
+ if (completion_info_schema)
+ e_info_schema = escape_string(completion_info_schema);
else
- e_info_charp2 = NULL;
+ e_info_schema = NULL;
initPQExpBuffer(&query_buffer);
@@ -4833,20 +4814,44 @@ _complete_from_query(const char *simple_query,
* already qualified or not. schema_query gives us the pieces to
* assemble.
*/
- if (schemaname == NULL)
+ if (schemaname == NULL || schema_query->namespace == NULL)
{
/* Get unqualified names matching the input-so-far */
- appendPQExpBuffer(&query_buffer, "SELECT %s, NULL::pg_catalog.text FROM %s WHERE ",
+ appendPQExpBufferStr(&query_buffer, "SELECT ");
+ if (schema_query->use_distinct)
+ appendPQExpBufferStr(&query_buffer, "DISTINCT ");
+ appendPQExpBuffer(&query_buffer,
+ "%s, NULL::pg_catalog.text FROM %s",
schema_query->result,
schema_query->catname);
+ if (schema_query->infonamespace && completion_info_schema)
+ appendPQExpBufferStr(&query_buffer,
+ ", pg_catalog.pg_namespace ni");
+ appendPQExpBufferStr(&query_buffer, " WHERE ");
if (schema_query->selcondition)
appendPQExpBuffer(&query_buffer, "%s AND ",
schema_query->selcondition);
appendPQExpBuffer(&query_buffer, "substring(%s,1,%d)='%s'",
schema_query->result,
object_length, e_objectname);
+ if (schema_query->viscondition)
appendPQExpBuffer(&query_buffer, " AND %s",
schema_query->viscondition);
+ if (schema_query->infoname)
+ {
+ Assert(completion_info_object);
+ appendPQExpBuffer(&query_buffer, " AND %s = '%s'",
+ schema_query->infoname, e_info_object);
+ if (schema_query->infonamespace && completion_info_schema)
+ appendPQExpBuffer(&query_buffer,
+ " AND %s = ni.oid AND ni.nspname = '%s'",
+ schema_query->infonamespace,
+ e_info_schema);
+ else if (schema_query->infoviscondition)
+ appendPQExpBuffer(&query_buffer,
+ " AND %s",
+ schema_query->infoviscondition);
+ }
/*
* When fetching relation names, suppress system catalogs unless
@@ -4863,7 +4868,12 @@ _complete_from_query(const char *simple_query,
" pg_catalog.pg_namespace WHERE nspname = 'pg_catalog')");
}
- /* Add in schema names matching the input-so-far */
+ /*
+ * If the target object type can be schema-qualified, add in
+ * schema names matching the input-so-far.
+ */
+ if (schema_query->namespace)
+ {
appendPQExpBuffer(&query_buffer, "\nUNION ALL\n"
"SELECT NULL::pg_catalog.text, n.nspname "
"FROM pg_catalog.pg_namespace n "
@@ -4884,14 +4894,21 @@ _complete_from_query(const char *simple_query,
*/
schemaquoted = objectquoted;
}
+ }
else
{
/* Input is qualified, so produce only qualified names */
- appendPQExpBuffer(&query_buffer, "SELECT %s, n.nspname "
- "FROM %s, pg_catalog.pg_namespace n "
- "WHERE %s = n.oid AND ",
+ appendPQExpBufferStr(&query_buffer, "SELECT ");
+ if (schema_query->use_distinct)
+ appendPQExpBufferStr(&query_buffer, "DISTINCT ");
+ appendPQExpBuffer(&query_buffer, "%s, n.nspname "
+ "FROM %s, pg_catalog.pg_namespace n",
schema_query->result,
- schema_query->catname,
+ schema_query->catname);
+ if (schema_query->infonamespace && completion_info_schema)
+ appendPQExpBufferStr(&query_buffer,
+ ", pg_catalog.pg_namespace ni");
+ appendPQExpBuffer(&query_buffer, " WHERE %s = n.oid AND ",
schema_query->namespace);
if (schema_query->selcondition)
appendPQExpBuffer(&query_buffer, "%s AND ",
@@ -4901,6 +4918,21 @@ _complete_from_query(const char *simple_query,
object_length, e_objectname);
appendPQExpBuffer(&query_buffer, "n.nspname = '%s'",
e_schemaname);
+ if (schema_query->infoname)
+ {
+ Assert(completion_info_object);
+ appendPQExpBuffer(&query_buffer, " AND %s = '%s'",
+ schema_query->infoname, e_info_object);
+ if (schema_query->infonamespace && completion_info_schema)
+ appendPQExpBuffer(&query_buffer,
+ " AND %s = ni.oid AND ni.nspname = '%s'",
+ schema_query->infonamespace,
+ e_info_schema);
+ else if (schema_query->infoviscondition)
+ appendPQExpBuffer(&query_buffer,
+ " AND %s",
+ schema_query->infoviscondition);
+ }
}
}
else
@@ -4909,8 +4941,7 @@ _complete_from_query(const char *simple_query,
/* simple_query is an sprintf-style format string */
appendPQExpBuffer(&query_buffer, simple_query,
object_length, e_objectname,
- e_info_charp, e_info_charp,
- e_info_charp2, e_info_charp2);
+ e_info_object, e_info_schema);
}
/* Limit the number of records in the result */
@@ -4925,10 +4956,10 @@ _complete_from_query(const char *simple_query,
if (e_schemaname)
free(e_schemaname);
free(e_objectname);
- if (e_info_charp)
- free(e_info_charp);
- if (e_info_charp2)
- free(e_info_charp2);
+ if (e_info_object)
+ free(e_info_object);
+ if (e_info_schema)
+ free(e_info_schema);
}
/* Return the next result, if any, but not if the query failed */
@@ -5037,6 +5068,23 @@ _complete_from_query(const char *simple_query,
}
+/*
+ * Set up completion_info_object and completion_info_schema
+ * by parsing the given word. These variables can then be
+ * used in a query passed to _complete_from_query.
+ */
+static void
+setup_completion_info(const char *word)
+{
+ bool schemaquoted,
+ objectquoted;
+
+ parse_identifier(word,
+ &completion_info_schema, &completion_info_object,
+ &schemaquoted, &objectquoted);
+}
+
+
/*
* This function returns in order one of a fixed, NULL pointer terminated list
* of strings (if matching). This can be used if there are only a fixed number