Commit 4c310eca authored by Tom Lane's avatar Tom Lane

Arrange for quote_identifier() and pg_dump to not quote keywords that are

unreserved according to the grammar.  The list of unreserved words has gotten
extensive enough that the unnecessary quoting is becoming a bit of an eyesore.
To do this, add knowledge of the keyword category to keywords.c's table.
(Someday we might be able to generate keywords.c's table and the keyword lists
in gram.y from a common source.)  For the moment, lie about WITH's status in
the table so it will still get quoted --- this is because of the expectation
that WITH will become reserved when the SQL recursive-queries patch gets done.

I didn't force initdb because this affects nothing on-disk; but note that a
few regression tests have changed expected output.
parent 53283408
......@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.594 2007/06/15 20:56:49 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.595 2007/06/18 21:40:57 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
......@@ -8787,12 +8787,16 @@ ColLabel: IDENT { $$ = $1; }
/*
* Keyword classification lists. Generally, every keyword present in
* Keyword category lists. Generally, every keyword present in
* the Postgres grammar should appear in exactly one of these lists.
*
* Put a new keyword into the first list that it can go into without causing
* shift or reduce conflicts. The earlier lists define "less reserved"
* categories of keywords.
*
* Make sure that each keyword's category in keywords.c matches where
* it is listed here. (Someday we may be able to generate these lists and
* keywords.c's table from a common master list.)
*/
/* "Unreserved" keywords --- available for use as any kind of name.
......
This diff is collapsed.
......@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.261 2007/06/11 22:22:42 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.262 2007/06/18 21:40:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -5175,15 +5175,16 @@ quote_identifier(const char *ident)
if (safe)
{
/*
* Check for keyword. This test is overly strong, since many of the
* "keywords" known to the parser are usable as column names, but the
* parser doesn't provide any easy way to test for whether an
* identifier is safe or not... so be safe not sorry.
* Check for keyword. We quote keywords except for unreserved ones.
* (In some cases we could avoid quoting a col_name or type_func_name
* keyword, but it seems much harder than it's worth to tell that.)
*
* Note: ScanKeywordLookup() does case-insensitive comparison, but
* that's fine, since we already know we have all-lower-case.
*/
if (ScanKeywordLookup(ident) != NULL)
const ScanKeyword *keyword = ScanKeywordLookup(ident);
if (keyword != NULL && keyword->category != UNRESERVED_KEYWORD)
safe = false;
}
......
......@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.c,v 1.35 2007/01/05 22:19:48 momjian Exp $
* $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.c,v 1.36 2007/06/18 21:40:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -53,11 +53,8 @@ fmtId(const char *rawid)
* These checks need to match the identifier production in scan.l. Don't
* use islower() etc.
*/
if (ScanKeywordLookup(rawid))
need_quotes = true;
/* slightly different rules for first character */
else if (!((rawid[0] >= 'a' && rawid[0] <= 'z') || rawid[0] == '_'))
if (!((rawid[0] >= 'a' && rawid[0] <= 'z') || rawid[0] == '_'))
need_quotes = true;
else
{
......@@ -74,6 +71,22 @@ fmtId(const char *rawid)
}
}
if (!need_quotes)
{
/*
* Check for keyword. We quote keywords except for unreserved ones.
* (In some cases we could avoid quoting a col_name or type_func_name
* keyword, but it seems much harder than it's worth to tell that.)
*
* Note: ScanKeywordLookup() does case-insensitive comparison, but
* that's fine, since we already know we have all-lower-case.
*/
const ScanKeyword *keyword = ScanKeywordLookup(rawid);
if (keyword != NULL && keyword->category != UNRESERVED_KEYWORD)
need_quotes = true;
}
if (!need_quotes)
{
/* no quoting needed */
......
/*-------------------------------------------------------------------------
*
* keywords.h
* lexical token lookup for reserved words in postgres SQL
* lexical token lookup for key words in PostgreSQL
*
*
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/parser/keywords.h,v 1.22 2007/01/05 22:19:56 momjian Exp $
* $PostgreSQL: pgsql/src/include/parser/keywords.h,v 1.23 2007/06/18 21:40:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef KEYWORDS_H
#define KEYWORDS_H
/* Keyword categories --- should match lists in gram.y */
#define UNRESERVED_KEYWORD 0
#define COL_NAME_KEYWORD 1
#define TYPE_FUNC_NAME_KEYWORD 2
#define RESERVED_KEYWORD 3
typedef struct ScanKeyword
{
const char *name;
int value;
const char *name; /* in lower case */
int16 value; /* grammar's token code */
int16 category; /* see codes above */
} ScanKeyword;
extern const ScanKeyword *ScanKeywordLookup(const char *text);
......
......@@ -164,7 +164,7 @@ SELECT name, statement, parameter_types FROM pg_prepared_statements
q5 | PREPARE q5(int, text) AS | {integer,text}
: \x09SELECT * FROM tenk1 WHERE unique1 = $1 OR stringu1 = $2
: \x09ORDER BY unique1;
q6 | PREPARE q6 AS | {integer,"\"name\""}
q6 | PREPARE q6 AS | {integer,name}
: SELECT * FROM tenk1 WHERE unique1 = $1 AND stringu1 = $2;
q7 | PREPARE q7(unknown) AS | {path}
: SELECT * FROM road WHERE thepath = $1;
......
This diff is collapsed.
......@@ -53,7 +53,7 @@ SELECT xmlconcat('hello', 'you');
(1 row)
SELECT xmlconcat(1, 2);
ERROR: argument of XMLCONCAT must be type "xml", not type integer
ERROR: argument of XMLCONCAT must be type xml, not type integer
SELECT xmlconcat('bad', '<syntax');
ERROR: invalid XML content
DETAIL: Entity: line 1: parser error : Couldn't find end of Start Tag syntax line 1
......@@ -389,16 +389,16 @@ CREATE VIEW xmlview9 AS SELECT xmlserialize(content 'good' as text);
SELECT table_name, view_definition FROM information_schema.views
WHERE table_name LIKE 'xmlview%' ORDER BY 1;
table_name | view_definition
------------+--------------------------------------------------------------------------------------------------------------------------------
------------+----------------------------------------------------------------------------------------------------------------------------
xmlview1 | SELECT xmlcomment('test'::text) AS xmlcomment;
xmlview2 | SELECT XMLCONCAT('hello'::"xml", 'you'::"xml") AS "xmlconcat";
xmlview2 | SELECT XMLCONCAT('hello'::xml, 'you'::xml) AS "xmlconcat";
xmlview3 | SELECT XMLELEMENT(NAME element, XMLATTRIBUTES(1 AS ":one:", 'deuce' AS two), 'content&') AS "xmlelement";
xmlview4 | SELECT XMLELEMENT(NAME employee, XMLFOREST(emp."name" AS "name", emp.age AS age, emp.salary AS pay)) AS "xmlelement" FROM emp;
xmlview4 | SELECT XMLELEMENT(NAME employee, XMLFOREST(emp.name AS name, emp.age AS age, emp.salary AS pay)) AS "xmlelement" FROM emp;
xmlview5 | SELECT XMLPARSE(CONTENT '<abc>x</abc>'::text STRIP WHITESPACE) AS "xmlparse";
xmlview6 | SELECT XMLPI(NAME foo, 'bar'::text) AS "xmlpi";
xmlview7 | SELECT XMLROOT('<foo/>'::"xml", VERSION NO VALUE, STANDALONE YES) AS "xmlroot";
xmlview8 | SELECT (XMLSERIALIZE(CONTENT 'good'::"xml" AS character(10)))::character(10) AS "xmlserialize";
xmlview9 | SELECT XMLSERIALIZE(CONTENT 'good'::"xml" AS text) AS "xmlserialize";
xmlview7 | SELECT XMLROOT('<foo/>'::xml, VERSION NO VALUE, STANDALONE YES) AS "xmlroot";
xmlview8 | SELECT (XMLSERIALIZE(CONTENT 'good'::xml AS character(10)))::character(10) AS "xmlserialize";
xmlview9 | SELECT XMLSERIALIZE(CONTENT 'good'::xml AS text) AS "xmlserialize";
(9 rows)
-- Text XPath expressions evaluation
......
......@@ -50,7 +50,7 @@ ERROR: unsupported XML feature
DETAIL: This functionality requires libxml support.
HINT: You need to re-compile PostgreSQL using --with-libxml.
SELECT xmlconcat(1, 2);
ERROR: argument of XMLCONCAT must be type "xml", not type integer
ERROR: argument of XMLCONCAT must be type xml, not type integer
SELECT xmlconcat('bad', '<syntax');
ERROR: unsupported XML feature
DETAIL: This functionality requires libxml support.
......
......@@ -51,7 +51,7 @@ CREATE FUNCTION set_ttdummy (int4)
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE SQL
AS 'SELECT ''not an integer'';';
ERROR: return type mismatch in function declared to return integer
DETAIL: Actual return type is "unknown".
DETAIL: Actual return type is unknown.
CONTEXT: SQL function "test1"
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE SQL
AS 'not even SQL';
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment