diff --git a/doc/src/sgml/queries.sgml b/doc/src/sgml/queries.sgml index b5b5542d51aedf5f33db356afcef085b6919a420..e3b6be4d97b277f8009f7cb04512699d07fd430c 100644 --- a/doc/src/sgml/queries.sgml +++ b/doc/src/sgml/queries.sgml @@ -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 diff --git a/doc/src/sgml/ref/delete.sgml b/doc/src/sgml/ref/delete.sgml index 6e3d9ff2c1fad9bb1790b01a504606dd86fb8dcc..89eaf264192b445ceb3b6cdbd0935072634a22d9 100644 --- a/doc/src/sgml/ref/delete.sgml +++ b/doc/src/sgml/ref/delete.sgml @@ -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> diff --git a/doc/src/sgml/ref/insert.sgml b/doc/src/sgml/ref/insert.sgml index 5dc1f6d7863ccb2c5832592a68efd502ea313c03..52a4a0e93788527c0c8cff64b0af30dfedee153e 100644 --- a/doc/src/sgml/ref/insert.sgml +++ b/doc/src/sgml/ref/insert.sgml @@ -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> diff --git a/doc/src/sgml/ref/select.sgml b/doc/src/sgml/ref/select.sgml index 2624630699f48ca54b5fbb4b2e7c30615d249d05..000b5614dd2854431bb57e5af2312ae98b8dd491 100644 --- a/doc/src/sgml/ref/select.sgml +++ b/doc/src/sgml/ref/select.sgml @@ -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</> 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 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 <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> diff --git a/doc/src/sgml/ref/select_into.sgml b/doc/src/sgml/ref/select_into.sgml index 8780771201f06cf12c67cc2a487482aa005ad85b..915e859ea988ce87c2daee540594561362b33ed4 100644 --- a/doc/src/sgml/ref/select_into.sgml +++ b/doc/src/sgml/ref/select_into.sgml @@ -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> ] diff --git a/doc/src/sgml/ref/update.sgml b/doc/src/sgml/ref/update.sgml index ce05150073a6ccb284bc3fdc273aca8f2ea6d386..2c8fed2a2f88a4afb916c705cb454c01b1056dea 100644 --- a/doc/src/sgml/ref/update.sgml +++ b/doc/src/sgml/ref/update.sgml @@ -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> diff --git a/doc/src/sgml/sql.sgml b/doc/src/sgml/sql.sgml index 98ed6e1331148e0f435e158ac0b00b6bb4dc2c2a..6c63708b0e80e34ebc7a88cc089198fdc86d8fe1 100644 --- a/doc/src/sgml/sql.sgml +++ b/doc/src/sgml/sql.sgml @@ -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 < 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> ] diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 2b992fab4a7d06e5f2d9ba659a8b29520ab970bd..4688bc797789ade8ec4b69b872feb5728912b0eb 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -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); diff --git a/src/interfaces/ecpg/preproc/preproc.y b/src/interfaces/ecpg/preproc/preproc.y index 6dd32b930b3e9f81039815b22025af21b312195e..43efc431dba1693cd5a4205c29389281228d1344 100644 --- a/src/interfaces/ecpg/preproc/preproc.y +++ b/src/interfaces/ecpg/preproc/preproc.y @@ -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; } | '*' diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out index 78466426f1c00b6ea8c72ded1e896da231a80af8..03204b66e6bc11953bca2d720a2b1e3a9f3dac7c 100644 --- a/src/test/regress/expected/plpgsql.out +++ b/src/test/regress/expected/plpgsql.out @@ -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