Allow AS to be omitted when specifying an output column name in SELECT

(or RETURNING), but only when the output name is not any SQL keyword.
This seems as close as we can get to the standard's syntax without a
great deal of thrashing.  Original patch by Hiroshi Saito, amended by me.
This commit is contained in:
Tom Lane 2008-02-15 22:17:06 +00:00
parent cc80f0a340
commit e67867b26c
10 changed files with 119 additions and 51 deletions

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/queries.sgml,v 1.44 2007/02/01 19:10:24 momjian Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/queries.sgml,v 1.45 2008/02/15 22:17:06 tgl Exp $ -->
<chapter id="queries">
<title>Queries</title>
@ -491,7 +491,7 @@ FROM <replaceable>table_reference</replaceable> AS <replaceable>alias</replaceab
<synopsis>
FROM <replaceable>table_reference</replaceable> <replaceable>alias</replaceable>
</synopsis>
The <literal>AS</literal> key word is noise.
The <literal>AS</literal> key word is optional noise.
<replaceable>alias</replaceable> can be any identifier.
</para>
@ -1040,13 +1040,32 @@ SELECT a AS value, b + c AS sum FROM ...
</para>
<para>
If no output column name is specified using <literal>AS</>, the system assigns a
default name. For simple column references, this is the name of the
referenced column. For function
If no output column name is specified using <literal>AS</>,
the system assigns a default column name. For simple column references,
this is the name of the referenced column. For function
calls, this is the name of the function. For complex expressions,
the system will generate a generic name.
</para>
<para>
The <literal>AS</> keyword is optional, but only if the new column
name does not match any
<productname>PostgreSQL</productname> keyword (see <xref
linkend="sql-keywords-appendix">). To avoid an accidental match to
a keyword, you can double-quote the column name. For example,
<literal>VALUE</> is a keyword, so this does not work:
<programlisting>
SELECT a value, b + c AS sum FROM ...
</programlisting>
but this does:
<programlisting>
SELECT a "value", b + c AS sum FROM ...
</programlisting>
For protection against possible
future keyword additions, it is recommended that you always either
write <literal>AS</literal> or double-quote the output column name.
</para>
<note>
<para>
The naming of output columns here is different from that done in

View File

@ -1,5 +1,5 @@
<!--
$PostgreSQL: pgsql/doc/src/sgml/ref/delete.sgml,v 1.32 2007/11/28 15:42:31 petere Exp $
$PostgreSQL: pgsql/doc/src/sgml/ref/delete.sgml,v 1.33 2008/02/15 22:17:06 tgl Exp $
PostgreSQL documentation
-->
@ -23,7 +23,7 @@ PostgreSQL documentation
DELETE FROM [ ONLY ] <replaceable class="PARAMETER">table</replaceable> [ [ AS ] <replaceable class="parameter">alias</replaceable> ]
[ USING <replaceable class="PARAMETER">usinglist</replaceable> ]
[ WHERE <replaceable class="PARAMETER">condition</replaceable> | WHERE CURRENT OF <replaceable class="PARAMETER">cursor_name</replaceable> ]
[ RETURNING * | <replaceable class="parameter">output_expression</replaceable> [ AS <replaceable class="parameter">output_name</replaceable> ] [, ...] ]
[ RETURNING * | <replaceable class="parameter">output_expression</replaceable> [ [ AS ] <replaceable class="parameter">output_name</replaceable> ] [, ...] ]
</synopsis>
</refsynopsisdiv>

View File

@ -1,5 +1,5 @@
<!--
$PostgreSQL: pgsql/doc/src/sgml/ref/insert.sgml,v 1.35 2007/01/31 23:26:04 momjian Exp $
$PostgreSQL: pgsql/doc/src/sgml/ref/insert.sgml,v 1.36 2008/02/15 22:17:06 tgl Exp $
PostgreSQL documentation
-->
@ -22,7 +22,7 @@ PostgreSQL documentation
<synopsis>
INSERT INTO <replaceable class="PARAMETER">table</replaceable> [ ( <replaceable class="PARAMETER">column</replaceable> [, ...] ) ]
{ DEFAULT VALUES | VALUES ( { <replaceable class="PARAMETER">expression</replaceable> | DEFAULT } [, ...] ) [, ...] | <replaceable class="PARAMETER">query</replaceable> }
[ RETURNING * | <replaceable class="parameter">output_expression</replaceable> [ AS <replaceable class="parameter">output_name</replaceable> ] [, ...] ]
[ RETURNING * | <replaceable class="parameter">output_expression</replaceable> [ [ AS ] <replaceable class="parameter">output_name</replaceable> ] [, ...] ]
</synopsis>
</refsynopsisdiv>

View File

@ -1,5 +1,5 @@
<!--
$PostgreSQL: pgsql/doc/src/sgml/ref/select.sgml,v 1.102 2007/11/28 15:42:31 petere Exp $
$PostgreSQL: pgsql/doc/src/sgml/ref/select.sgml,v 1.103 2008/02/15 22:17:06 tgl Exp $
PostgreSQL documentation
-->
@ -21,7 +21,7 @@ PostgreSQL documentation
<refsynopsisdiv>
<synopsis>
SELECT [ ALL | DISTINCT [ ON ( <replaceable class="parameter">expression</replaceable> [, ...] ) ] ]
* | <replaceable class="parameter">expression</replaceable> [ AS <replaceable class="parameter">output_name</replaceable> ] [, ...]
* | <replaceable class="parameter">expression</replaceable> [ [ AS ] <replaceable class="parameter">output_name</replaceable> ] [, ...]
[ FROM <replaceable class="parameter">from_item</replaceable> [, ...] ]
[ WHERE <replaceable class="parameter">condition</replaceable> ]
[ GROUP BY <replaceable class="parameter">expression</replaceable> [, ...] ]
@ -477,23 +477,45 @@ HAVING <replaceable class="parameter">condition</replaceable>
<literal>SELECT</> and <literal>FROM</>) specifies expressions
that form the output rows of the <command>SELECT</command>
statement. The expressions can (and usually do) refer to columns
computed in the <literal>FROM</> clause. Using the clause
<literal>AS <replaceable
class="parameter">output_name</replaceable></literal>, another
name can be specified for an output column. This name is
primarily used to label the column for display. It can also be
used to refer to the column's value in <literal>ORDER BY</> and
<literal>GROUP BY</> clauses, but not in the <literal>WHERE</> or
<literal>HAVING</> clauses; there you must write out the
expression instead.
computed in the <literal>FROM</> clause.
</para>
<para>
Just as in a table, every output column of a <command>SELECT</command>
has a name. In a simple <command>SELECT</command> this name is just
used to label the column for display, but when the <command>SELECT</>
is a sub-query of a larger query, the name is seen by the larger query
as the column name of the virtual table produced by the sub-query.
To specify the name to use for an output column, write
<literal>AS</> <replaceable class="parameter">output_name</replaceable>
after the column's expression. (You can omit <literal>AS</literal>,
but only if the desired output name does not match any
<productname>PostgreSQL</productname> keyword (see <xref
linkend="sql-keywords-appendix">). For protection against possible
future keyword additions, it is recommended that you always either
write <literal>AS</literal> or double-quote the output name.)
If you do not specify a column name, a name is chosen automatically
by <productname>PostgreSQL</productname>. If the column's expression
is a simple column reference then the chosen name is the same as that
column's name; in more complex cases a generated name looking like
<literal>?column<replaceable>N</>?</literal> is usually chosen.
</para>
<para>
An output column's name can be used to refer to the column's value in
<literal>ORDER BY</> and <literal>GROUP BY</> clauses, but not in the
<literal>WHERE</> or <literal>HAVING</> clauses; there you must write
out the expression instead.
</para>
<para>
Instead of an expression, <literal>*</literal> can be written in
the output list as a shorthand for all the columns of the selected
rows. Also, one can write <literal><replaceable
rows. Also, you can write <literal><replaceable
class="parameter">table_name</replaceable>.*</literal> as a
shorthand for the columns coming from just that table.
shorthand for the columns coming from just that table. In these
cases it is not possible to specify new names with <literal>AS</>;
the output column names will be the same as the table columns' names.
</para>
</refsect2>
@ -661,17 +683,17 @@ ORDER BY <replaceable class="parameter">expression</replaceable> [ ASC | DESC |
<para>
The ordinal number refers to the ordinal (left-to-right) position
of the result column. This feature makes it possible to define an
of the output column. This feature makes it possible to define an
ordering on the basis of a column that does not have a unique
name. This is never absolutely necessary because it is always
possible to assign a name to a result column using the
possible to assign a name to an output column using the
<literal>AS</> clause.
</para>
<para>
It is also possible to use arbitrary expressions in the
<literal>ORDER BY</literal> clause, including columns that do not
appear in the <command>SELECT</command> result list. Thus the
appear in the <command>SELECT</command> output list. Thus the
following statement is valid:
<programlisting>
SELECT name FROM distributors ORDER BY code;
@ -684,8 +706,8 @@ SELECT name FROM distributors ORDER BY code;
<para>
If an <literal>ORDER BY</> expression is a simple name that
matches both a result column name and an input column name,
<literal>ORDER BY</> will interpret it as the result column name.
matches both an output column name and an input column name,
<literal>ORDER BY</> will interpret it as the output column name.
This is the opposite of the choice that <literal>GROUP BY</> will
make in the same situation. This inconsistency is made to be
compatible with the SQL standard.
@ -1135,16 +1157,25 @@ SELECT distributors.* WHERE distributors.name = 'Westward';
</refsect2>
<refsect2>
<title>The <literal>AS</literal> Key Word</title>
<title>Omitting the <literal>AS</literal> Key Word</title>
<para>
In the SQL standard, the optional key word <literal>AS</> is just
noise and can be omitted without affecting the meaning. The
<productname>PostgreSQL</productname> parser requires this key
word when renaming output columns because the type extensibility
features lead to parsing ambiguities without it.
<literal>AS</literal> is optional in <literal>FROM</literal>
items, however.
In the SQL standard, the optional key word <literal>AS</> can be
omitted before an output column name whenever the new column name
is a valid column name (that is, not the same as any reserved
keyword). <productname>PostgreSQL</productname> is slightly more
restrictive: <literal>AS</> is required if the new column name
matches any keyword at all, reserved or not. Recommended practice is
to use <literal>AS</> or double-quote output column names, to prevent
any possible conflict against future keyword additions.
</para>
<para>
In <literal>FROM</literal> items, both the standard and
<productname>PostgreSQL</productname> allow <literal>AS</> to
be omitted before an alias that is an unreserved keyword. But
this is impractical for output column names, because of syntactic
ambiguities.
</para>
</refsect2>
@ -1153,7 +1184,7 @@ SELECT distributors.* WHERE distributors.name = 'Westward';
<para>
In the SQL-92 standard, an <literal>ORDER BY</literal> clause can
only use result column names or numbers, while a <literal>GROUP
only use output column names or numbers, while a <literal>GROUP
BY</literal> clause can only use expressions based on input column
names. <productname>PostgreSQL</productname> extends each of
these clauses to allow the other choice as well (but it uses the
@ -1161,7 +1192,7 @@ SELECT distributors.* WHERE distributors.name = 'Westward';
<productname>PostgreSQL</productname> also allows both clauses to
specify arbitrary expressions. Note that names appearing in an
expression will always be taken as input-column names, not as
result-column names.
output-column names.
</para>
<para>

View File

@ -1,5 +1,5 @@
<!--
$PostgreSQL: pgsql/doc/src/sgml/ref/select_into.sgml,v 1.39 2007/01/09 02:14:10 tgl Exp $
$PostgreSQL: pgsql/doc/src/sgml/ref/select_into.sgml,v 1.40 2008/02/15 22:17:06 tgl Exp $
PostgreSQL documentation
-->
@ -21,7 +21,7 @@ PostgreSQL documentation
<refsynopsisdiv>
<synopsis>
SELECT [ ALL | DISTINCT [ ON ( <replaceable class="PARAMETER">expression</replaceable> [, ...] ) ] ]
* | <replaceable class="PARAMETER">expression</replaceable> [ AS <replaceable class="PARAMETER">output_name</replaceable> ] [, ...]
* | <replaceable class="PARAMETER">expression</replaceable> [ [ AS ] <replaceable class="PARAMETER">output_name</replaceable> ] [, ...]
INTO [ TEMPORARY | TEMP ] [ TABLE ] <replaceable class="PARAMETER">new_table</replaceable>
[ FROM <replaceable class="PARAMETER">from_item</replaceable> [, ...] ]
[ WHERE <replaceable class="PARAMETER">condition</replaceable> ]

View File

@ -1,5 +1,5 @@
<!--
$PostgreSQL: pgsql/doc/src/sgml/ref/update.sgml,v 1.45 2007/11/28 15:42:31 petere Exp $
$PostgreSQL: pgsql/doc/src/sgml/ref/update.sgml,v 1.46 2008/02/15 22:17:06 tgl Exp $
PostgreSQL documentation
-->
@ -25,7 +25,7 @@ UPDATE [ ONLY ] <replaceable class="PARAMETER">table</replaceable> [ [ AS ] <rep
( <replaceable class="PARAMETER">column</replaceable> [, ...] ) = ( { <replaceable class="PARAMETER">expression</replaceable> | DEFAULT } [, ...] ) } [, ...]
[ FROM <replaceable class="PARAMETER">fromlist</replaceable> ]
[ WHERE <replaceable class="PARAMETER">condition</replaceable> | WHERE CURRENT OF <replaceable class="PARAMETER">cursor_name</replaceable> ]
[ RETURNING * | <replaceable class="parameter">output_expression</replaceable> [ AS <replaceable class="parameter">output_name</replaceable> ] [, ...] ]
[ RETURNING * | <replaceable class="parameter">output_expression</replaceable> [ [ AS ] <replaceable class="parameter">output_name</replaceable> ] [, ...] ]
</synopsis>
</refsynopsisdiv>

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/sql.sgml,v 1.46 2007/02/16 03:50:29 momjian Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/sql.sgml,v 1.47 2008/02/15 22:17:06 tgl Exp $ -->
<chapter id="sql-intro">
<title>SQL</title>
@ -853,7 +853,7 @@ A &lt; B + 3.
<synopsis>
SELECT [ ALL | DISTINCT [ ON ( <replaceable class="PARAMETER">expression</replaceable> [, ...] ) ] ]
* | <replaceable class="PARAMETER">expression</replaceable> [ AS <replaceable class="PARAMETER">output_name</replaceable> ] [, ...]
* | <replaceable class="PARAMETER">expression</replaceable> [ [ AS ] <replaceable class="PARAMETER">output_name</replaceable> ] [, ...]
[ INTO [ TEMPORARY | TEMP ] [ TABLE ] <replaceable class="PARAMETER">new_table</replaceable> ]
[ FROM <replaceable class="PARAMETER">from_item</replaceable> [, ...] ]
[ WHERE <replaceable class="PARAMETER">condition</replaceable> ]

View File

@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.606 2008/02/07 21:07:55 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.607 2008/02/15 22:17:06 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@ -477,6 +477,7 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
%nonassoc BETWEEN
%nonassoc IN_P
%left POSTFIXOP /* dummy for postfix Op rules */
%nonassoc IDENT /* to support target_el without AS */
%left Op OPERATOR /* multi-character ops and user-defined operators */
%nonassoc NOTNULL
%nonassoc ISNULL
@ -8705,7 +8706,6 @@ target_list:
| target_list ',' target_el { $$ = lappend($1, $3); }
;
/* AS is not optional because shift/red conflict with unary ops */
target_el: a_expr AS ColLabel
{
$$ = makeNode(ResTarget);
@ -8714,6 +8714,22 @@ target_el: a_expr AS ColLabel
$$->val = (Node *)$1;
$$->location = @1;
}
/*
* We support omitting AS only for column labels that aren't
* any known keyword. There is an ambiguity against postfix
* operators: is "a ! b" an infix expression, or a postfix
* expression and a column label? We prefer to resolve this
* as an infix expression, which we accomplish by assigning
* IDENT a precedence higher than POSTFIXOP.
*/
| a_expr IDENT
{
$$ = makeNode(ResTarget);
$$->name = $2;
$$->indirection = NIL;
$$->val = (Node *)$1;
$$->location = @1;
}
| a_expr
{
$$ = makeNode(ResTarget);

View File

@ -1,4 +1,4 @@
/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/preproc.y,v 1.360 2008/02/14 14:54:48 meskes Exp $ */
/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/preproc.y,v 1.361 2008/02/15 22:17:06 tgl Exp $ */
/* Copyright comment */
%{
@ -521,8 +521,9 @@ add_typedef(char *name, char * dimension, char * length, enum ECPGttype type_enu
%nonassoc OVERLAPS
%nonassoc BETWEEN
%nonassoc IN_P
%left POSTFIXOP /* dummy for postfix Op rules */
%left Op OPERATOR /* multi-character ops and user-defined operators */
%left POSTFIXOP /* dummy for postfix Op rules */
%nonassoc IDENT /* to support target_el without AS */
%left Op OPERATOR /* multi-character ops and user-defined operators */
%nonassoc NOTNULL
%nonassoc ISNULL
%nonassoc IS NULL_P TRUE_P FALSE_P UNKNOWN
@ -4695,9 +4696,10 @@ target_list: target_list ',' target_el
{ $$ = $1; }
;
/* AS is not optional because shift/red conflict with unary ops */
target_el: a_expr AS ColLabel
{ $$ = cat_str(3, $1, make_str("as"), $3); }
| a_expr IDENT
{ $$ = cat_str(3, $1, make_str("as"), $2); }
| a_expr
{ $$ = $1; }
| '*'

View File

@ -2337,9 +2337,9 @@ begin
end loop;
return 5;
end;$$ language plpgsql;
ERROR: syntax error at or near "fought"
ERROR: syntax error at or near "the"
LINE 1: select I fought the law, the law won
^
^
QUERY: select I fought the law, the law won
CONTEXT: SQL statement in PL/PgSQL function "bad_sql2" near line 3
-- a RETURN expression is mandatory, except for void-returning