diff options
| author | Andres Freund <andres@anarazel.de> | 2015-09-08 20:57:35 +0200 | 
|---|---|---|
| committer | Andres Freund <andres@anarazel.de> | 2015-09-08 20:57:35 +0200 | 
| commit | 3ae16798f0f9d2d941e50062b579c28c9b946c9e (patch) | |
| tree | dac30a39004b84a449b6933a78daeb5f9b5018cd /src/bin/psql/tab-complete.c | |
| parent | 043113e7982942279d940f9bf0e3a5a4b66b9aa7 (diff) | |
psql: Generic tab completion support for enum and bool GUCs.
Author: Pavel Stehule
Reviewed-By: Andres Freund
Discussion: 5594FE7A.5050205@iki.fi
Diffstat (limited to 'src/bin/psql/tab-complete.c')
| -rw-r--r-- | src/bin/psql/tab-complete.c | 132 | 
1 files changed, 97 insertions, 35 deletions
| diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index bdee0d509d4..0cb34640ede 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -759,6 +759,15 @@ static const SchemaQuery Query_for_list_of_matviews = {  "       (SELECT polrelid FROM pg_catalog.pg_policy "\  "         WHERE pg_catalog.quote_ident(polname)='%s')" +#define Query_for_enum \ +" SELECT name FROM ( "\ +"   SELECT pg_catalog.quote_ident(pg_catalog.unnest(enumvals)) AS name "\ +"     FROM pg_catalog.pg_settings "\ +"    WHERE pg_catalog.lower(name)=pg_catalog.lower('%s') "\ +"    UNION ALL " \ +"   SELECT 'DEFAULT' ) ss "\ +"  WHERE pg_catalog.substring(name,1,%%d)='%%s'" +  /*   * This is a list of all "things" in Pgsql, which can show up after CREATE or   * DROP; and there is also a query to get a list of them. @@ -845,10 +854,13 @@ static char **complete_from_variables(const char *text,  static char *complete_from_files(const char *text, int state);  static char *pg_strdup_keyword_case(const char *s, const char *ref); +static char *escape_string(const char *text);  static PGresult *exec_query(const char *query);  static void get_previous_words(int point, char **previous_words, int nwords); +static char *get_guctype(const char *varname); +  #ifdef NOT_USED  static char *quote_file_name(char *text, int match_type, char *quote_pointer);  static char *dequote_file_name(char *text, char quote_char); @@ -3684,6 +3696,7 @@ psql_completion(const char *text, int start, int end)  	else if (pg_strcasecmp(prev3_wd, "SET") == 0 &&  			 (pg_strcasecmp(prev_wd, "TO") == 0 || strcmp(prev_wd, "=") == 0))  	{ +		/* special cased code for individual GUCs */  		if (pg_strcasecmp(prev2_wd, "DateStyle") == 0)  		{  			static const char *const my_list[] = @@ -3694,20 +3707,6 @@ psql_completion(const char *text, int start, int end)  			COMPLETE_WITH_LIST(my_list);  		} -		else if (pg_strcasecmp(prev2_wd, "IntervalStyle") == 0) -		{ -			static const char *const my_list[] = -			{"postgres", "postgres_verbose", "sql_standard", "iso_8601", NULL}; - -			COMPLETE_WITH_LIST(my_list); -		} -		else if (pg_strcasecmp(prev2_wd, "GEQO") == 0) -		{ -			static const char *const my_list[] = -			{"ON", "OFF", "DEFAULT", NULL}; - -			COMPLETE_WITH_LIST(my_list); -		}  		else if (pg_strcasecmp(prev2_wd, "search_path") == 0)  		{  			COMPLETE_WITH_QUERY(Query_for_list_of_schemas @@ -3717,10 +3716,34 @@ psql_completion(const char *text, int start, int end)  		}  		else  		{ -			static const char *const my_list[] = -			{"DEFAULT", NULL}; +			/* generic, type based, GUC support */ -			COMPLETE_WITH_LIST(my_list); +			char	   *guctype = get_guctype(prev2_wd); + +			if (guctype && strcmp(guctype, "enum") == 0) +			{ +				char		querybuf[1024]; + +				snprintf(querybuf, 1024, Query_for_enum, prev2_wd); +				COMPLETE_WITH_QUERY(querybuf); +			} +			else if (guctype && strcmp(guctype, "bool") == 0) +			{ +				static const char *const my_list[] = +				{"on", "off", "true", "false", "yes", "no", "1", "0", "DEFAULT", NULL}; + +				COMPLETE_WITH_LIST(my_list); +			} +			else +			{ +				static const char *const my_list[] = +				{"DEFAULT", NULL}; + +				COMPLETE_WITH_LIST(my_list); +			} + +			if (guctype) +				free(guctype);  		}  	} @@ -4263,30 +4286,15 @@ _complete_from_query(int is_schema_query, const char *text, int state)  		result = NULL;  		/* Set up suitably-escaped copies of textual inputs */ -		e_text = pg_malloc(string_length * 2 + 1); -		PQescapeString(e_text, text, string_length); +		e_text = escape_string(text);  		if (completion_info_charp) -		{ -			size_t		charp_len; - -			charp_len = strlen(completion_info_charp); -			e_info_charp = pg_malloc(charp_len * 2 + 1); -			PQescapeString(e_info_charp, completion_info_charp, -						   charp_len); -		} +			e_info_charp = escape_string(completion_info_charp);  		else  			e_info_charp = NULL;  		if (completion_info_charp2) -		{ -			size_t		charp_len; - -			charp_len = strlen(completion_info_charp2); -			e_info_charp2 = pg_malloc(charp_len * 2 + 1); -			PQescapeString(e_info_charp2, completion_info_charp2, -						   charp_len); -		} +			e_info_charp2 = escape_string(completion_info_charp2);  		else  			e_info_charp2 = NULL; @@ -4678,6 +4686,26 @@ pg_strdup_keyword_case(const char *s, const char *ref)  /* + * escape_string - Escape argument for use as string literal. + * + * The returned value has to be freed. + */ +static char * +escape_string(const char *text) +{ +	size_t		text_length; +	char	   *result; + +	text_length = strlen(text); + +	result = pg_malloc(text_length * 2 + 1); +	PQescapeStringConn(pset.db, result, text, text_length, NULL); + +	return result; +} + + +/*   * Execute a query and report any errors. This should be the preferred way of   * talking to the database in this file.   */ @@ -4790,6 +4818,40 @@ get_previous_words(int point, char **previous_words, int nwords)  	}  } +/* + * Look up the type for the GUC variable with the passed name. + * + * Returns NULL if the variable is unknown. Otherwise the returned string, + * containing the type, has to be freed. + */ +static char * +get_guctype(const char *varname) +{ +	PQExpBufferData query_buffer; +	char	   *e_varname; +	PGresult   *result; +	char	   *guctype = NULL; + +	e_varname = escape_string(varname); + +	initPQExpBuffer(&query_buffer); +	appendPQExpBuffer(&query_buffer, +					  "SELECT vartype FROM pg_catalog.pg_settings " +					  "WHERE pg_catalog.lower(name) = pg_catalog.lower('%s')", +					  e_varname); + +	result = exec_query(query_buffer.data); +	termPQExpBuffer(&query_buffer); +	free(e_varname); + +	if (PQresultStatus(result) == PGRES_TUPLES_OK && PQntuples(result) > 0) +		guctype = pg_strdup(PQgetvalue(result, 0, 0)); + +	PQclear(result); + +	return guctype; +} +  #ifdef NOT_USED  /* | 
