Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 77c1791

Browse files
committed
Use PQescapeString to ensure that tab-completion queries are not messed
up by quotes or backslashes in words that are being matched to database names (per gripe from Ian Barwick, though I didn't use his patch). Also fix possible memory leakage if _complete_with_query isn't run to completion (not clear if that can happen or not, but be safe).
1 parent 2a0f1c0 commit 77c1791

File tree

1 file changed

+85
-28
lines changed

1 file changed

+85
-28
lines changed

src/bin/psql/tab-complete.c

+85-28
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* Copyright (c) 2000-2003, PostgreSQL Global Development Group
55
*
6-
* $Header: /cvsroot/pgsql/src/bin/psql/tab-complete.c,v 1.85 2003/09/07 15:26:54 tgl Exp $
6+
* $Header: /cvsroot/pgsql/src/bin/psql/tab-complete.c,v 1.86 2003/10/14 22:47:12 tgl Exp $
77
*/
88

99
/*----------------------------------------------------------------------
@@ -85,17 +85,20 @@ static char *complete_from_const(const char *text, int state);
8585
static char *complete_from_list(const char *text, int state);
8686

8787
static PGresult *exec_query(char *query);
88-
char *quote_file_name(char *text, int match_type, char *quote_pointer);
8988

90-
/*static char * dequote_file_name(char *text, char quote_char);*/
9189
static char *previous_word(int point, int skip);
9290

91+
#if 0
92+
static char *quote_file_name(char *text, int match_type, char *quote_pointer);
93+
static char *dequote_file_name(char *text, char quote_char);
94+
#endif
95+
9396
/* These variables are used to pass information into the completion functions.
9497
Realizing that this is the cardinal sin of programming, I don't see a better
9598
way. */
96-
char *completion_charp; /* if you need to pass a string */
97-
char **completion_charpp; /* if you need to pass a list of strings */
98-
char *completion_info_charp; /* if you need to pass another
99+
static char *completion_charp; /* if you need to pass a string */
100+
static char **completion_charpp; /* if you need to pass a list of strings */
101+
static char *completion_info_charp; /* if you need to pass another
99102
* string */
100103

101104
/* Store how many records from a database query we want to return at most
@@ -124,7 +127,10 @@ initialize_readline(void)
124127
/*
125128
* Queries to get lists of names of various kinds of things, possibly
126129
* restricted to names matching a partially entered name. In these queries,
127-
* the %s will be replaced by the text entered so far, the %d by its length.
130+
* %s will be replaced by the text entered so far (suitably escaped to
131+
* become a SQL literal string). %d will be replaced by the length of the
132+
* string (in unescaped form). Beware that the allowed sequences of %s and
133+
* %d are determined by _complete_from_query().
128134
*/
129135

130136
#define Query_for_list_of_aggregates \
@@ -401,6 +407,15 @@ initialize_readline(void)
401407
" FROM pg_catalog.pg_user "\
402408
" WHERE substr(usename,1,%d)='%s'"
403409

410+
/* the silly-looking length condition is just to eat up the current word */
411+
#define Query_for_table_owning_index \
412+
"SELECT c1.relname "\
413+
" FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i"\
414+
" WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid"\
415+
" and (%d = length('%s'))"\
416+
" and c2.relname='%s'"\
417+
" and pg_catalog.pg_table_is_visible(c2.oid)"
418+
404419
/* This is a list of all "things" in Pgsql, which can show up after CREATE or
405420
DROP; and there is also a query to get a list of them.
406421
*/
@@ -754,15 +769,8 @@ psql_completion(char *text, int start, int end)
754769
else if (strcasecmp(prev3_wd, "CLUSTER") == 0 &&
755770
strcasecmp(prev_wd, "ON") == 0)
756771
{
757-
char query_buffer[BUF_SIZE]; /* Some room to build
758-
* queries. */
759-
760-
if (snprintf(query_buffer, BUF_SIZE,
761-
"SELECT 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 c2.relname='%s' and pg_catalog.pg_table_is_visible(c2.oid)",
762-
prev2_wd) == -1)
763-
ERROR_QUERY_TOO_LONG;
764-
else
765-
COMPLETE_WITH_QUERY(query_buffer);
772+
completion_info_charp = prev2_wd;
773+
COMPLETE_WITH_QUERY(Query_for_table_owning_index);
766774
}
767775

768776
/* COMMENT */
@@ -1425,6 +1433,9 @@ complete_from_schema_query(const char *text, int state)
14251433
%d %s %d %s %d %s %s %d %s
14261434
where %d is the string length of the text and %s the text itself.
14271435
1436+
It is assumed that strings should be escaped to become SQL literals
1437+
(that is, what is in the query is actually ... '%s' ...)
1438+
14281439
See top of file for examples of both kinds of query.
14291440
*/
14301441

@@ -1434,48 +1445,93 @@ _complete_from_query(int is_schema_query, const char *text, int state)
14341445
static int list_index,
14351446
string_length;
14361447
static PGresult *result = NULL;
1437-
char query_buffer[BUF_SIZE];
1438-
const char *item;
14391448

14401449
/*
14411450
* If this is the first time for this completion, we fetch a list of
14421451
* our "things" from the backend.
14431452
*/
14441453
if (state == 0)
14451454
{
1455+
char query_buffer[BUF_SIZE];
1456+
char *e_text;
1457+
char *e_info_charp;
1458+
14461459
list_index = 0;
14471460
string_length = strlen(text);
14481461

1462+
/* Free any prior result */
1463+
PQclear(result);
1464+
result = NULL;
1465+
14491466
/* Need to have a query */
14501467
if (completion_charp == NULL)
14511468
return NULL;
14521469

1453-
if (is_schema_query)
1470+
/* Set up suitably-escaped copies of textual inputs */
1471+
if (text)
14541472
{
1455-
if (snprintf(query_buffer, BUF_SIZE, completion_charp, string_length, text, string_length, text, string_length, text, text, string_length, text, string_length, text) == -1)
1456-
{
1457-
ERROR_QUERY_TOO_LONG;
1473+
e_text = (char *) malloc(strlen(text) * 2 + 1);
1474+
if (!e_text)
14581475
return NULL;
1459-
}
1476+
PQescapeString(e_text, text, strlen(text));
14601477
}
14611478
else
1479+
e_text = NULL;
1480+
1481+
if (completion_info_charp)
14621482
{
1463-
if (snprintf(query_buffer, BUF_SIZE, completion_charp, string_length, text, completion_info_charp) == -1)
1483+
e_info_charp = (char *)
1484+
malloc(strlen(completion_info_charp) * 2 + 1);
1485+
if (!e_info_charp)
14641486
{
1465-
ERROR_QUERY_TOO_LONG;
1487+
if (e_text)
1488+
free(e_text);
14661489
return NULL;
14671490
}
1491+
PQescapeString(e_info_charp, completion_info_charp,
1492+
strlen(completion_info_charp));
1493+
}
1494+
else
1495+
e_info_charp = NULL;
1496+
1497+
if (is_schema_query)
1498+
{
1499+
if (snprintf(query_buffer, BUF_SIZE, completion_charp,
1500+
string_length, e_text,
1501+
string_length, e_text,
1502+
string_length, e_text,
1503+
e_text,
1504+
string_length, e_text,
1505+
string_length, e_text) == -1)
1506+
ERROR_QUERY_TOO_LONG;
1507+
else
1508+
result = exec_query(query_buffer);
1509+
}
1510+
else
1511+
{
1512+
if (snprintf(query_buffer, BUF_SIZE, completion_charp,
1513+
string_length, e_text, e_info_charp) == -1)
1514+
ERROR_QUERY_TOO_LONG;
1515+
else
1516+
result = exec_query(query_buffer);
14681517
}
14691518

1470-
result = exec_query(query_buffer);
1519+
if (e_text)
1520+
free(e_text);
1521+
if (e_info_charp)
1522+
free(e_info_charp);
14711523
}
14721524

14731525
/* Find something that matches */
14741526
if (result && PQresultStatus(result) == PGRES_TUPLES_OK)
1527+
{
1528+
const char *item;
1529+
14751530
while (list_index < PQntuples(result) &&
14761531
(item = PQgetvalue(result, list_index++, 0)))
14771532
if (strncasecmp(text, item, string_length) == 0)
14781533
return xstrdup(item);
1534+
}
14791535

14801536
/* If nothing matches, free the db structure and return null */
14811537
PQclear(result);
@@ -1585,7 +1641,8 @@ exec_query(char *query)
15851641
assert(query[strlen(query) - 1] != ';');
15861642
#endif
15871643

1588-
if (snprintf(query_buffer, BUF_SIZE, "%s LIMIT %d;", query, completion_max_records) == -1)
1644+
if (snprintf(query_buffer, BUF_SIZE, "%s LIMIT %d;",
1645+
query, completion_max_records) == -1)
15891646
{
15901647
ERROR_QUERY_TOO_LONG;
15911648
return NULL;
@@ -1684,7 +1741,7 @@ previous_word(int point, int skip)
16841741
* psql internal. Currently disable because it is reported not to
16851742
* cooperate with certain versions of readline.
16861743
*/
1687-
char *
1744+
static char *
16881745
quote_file_name(char *text, int match_type, char *quote_pointer)
16891746
{
16901747
char *s;

0 commit comments

Comments
 (0)