1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-27 12:41:57 +03:00

Allow most keywords to be used as column labels without requiring AS.

Up to now, if you tried to omit "AS" before a column label in a SELECT
list, it would only work if the column label was an IDENT, that is not
any known keyword.  This is rather unfriendly considering that we have
so many keywords and are constantly growing more.  In the wake of commit
1ed6b8956 it's possible to improve matters quite a bit.

We'd originally tried to make this work by having some of the existing
keyword categories be allowed without AS, but that didn't work too well,
because each category contains a few special cases that don't work
without AS.  Instead, invent an entirely orthogonal keyword property
"can be bare column label", and mark all keywords that way for which
we don't get shift/reduce errors by doing so.

It turns out that of our 450 current keywords, all but 39 can be made
bare column labels, improving the situation by over 90%.  This number
might move around a little depending on future grammar work, but it's
a pretty nice improvement.

Mark Dilger, based on work by myself and Robert Haas;
review by John Naylor

Discussion: https://postgr.es/m/38ca86db-42ab-9b48-2902-337a0d6b8311@2ndquadrant.com
This commit is contained in:
Tom Lane
2020-09-18 16:46:26 -04:00
parent 0811f766fd
commit 06a7c3154f
14 changed files with 1055 additions and 520 deletions

View File

@ -22173,7 +22173,9 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
<returnvalue>setof record</returnvalue>
( <parameter>word</parameter> <type>text</type>,
<parameter>catcode</parameter> <type>"char"</type>,
<parameter>catdesc</parameter> <type>text</type> )
<parameter>barelabel</parameter> <type>boolean</type>,
<parameter>catdesc</parameter> <type>text</type>,
<parameter>baredesc</parameter> <type>text</type> )
</para>
<para>
Returns a set of records describing the SQL keywords recognized by the
@ -22183,8 +22185,15 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
keyword, <literal>C</literal> for a keyword that can be a column
name, <literal>T</literal> for a keyword that can be a type or
function name, or <literal>R</literal> for a fully reserved keyword.
The <parameter>barelabel</parameter> column
contains <literal>true</literal> if the keyword can be used as
a <quote>bare</quote> column label in <command>SELECT</command> lists,
or <literal>false</literal> if it can only be used
after <literal>AS</literal>.
The <parameter>catdesc</parameter> column contains a
possibly-localized string describing the category.
possibly-localized string describing the keyword's category.
The <parameter>baredesc</parameter> column contains a
possibly-localized string describing the keyword's column label status.
</para></entry>
</row>

View File

@ -1,6 +1,7 @@
#!/usr/bin/perl
#
# Generate the keywords table file
# Generate the keywords table for the documentation's SQL Key Words appendix
#
# Copyright (c) 2019-2020, PostgreSQL Global Development Group
use strict;
@ -11,8 +12,9 @@ my @sql_versions = reverse sort ('1992', '2011', '2016');
my $srcdir = $ARGV[0];
my %keywords;
my %as_keywords;
# read SQL keywords
# read SQL-spec keywords
foreach my $ver (@sql_versions)
{
@ -39,9 +41,10 @@ open my $fh, '<', "$srcdir/../../../src/include/parser/kwlist.h" or die;
while (<$fh>)
{
if (/^PG_KEYWORD\("(\w+)", \w+, (\w+)_KEYWORD\)/)
if (/^PG_KEYWORD\("(\w+)", \w+, (\w+)_KEYWORD\, (\w+)\)/)
{
$keywords{ uc $1 }{'pg'}{ lc $2 } = 1;
$as_keywords{ uc $1 } = 1 if $3 eq 'AS_LABEL';
}
}
@ -107,6 +110,10 @@ foreach my $word (sort keys %keywords)
{
print "reserved";
}
if ($as_keywords{$word})
{
print ", requires <literal>AS</literal>";
}
print "</entry>\n";
foreach my $ver (@sql_versions)

View File

@ -32,11 +32,11 @@
</para>
<para>
In the <productname>PostgreSQL</productname> parser life is a bit
In the <productname>PostgreSQL</productname> parser, life is a bit
more complicated. There are several different classes of tokens
ranging from those that can never be used as an identifier to those
that have absolutely no special status in the parser as compared to
an ordinary identifier. (The latter is usually the case for
that have absolutely no special status in the parser, but are considered
ordinary identifiers. (The latter is usually the case for
functions specified by SQL.) Even reserved key words are not
completely reserved in <productname>PostgreSQL</productname>, but
can be used as column labels (for example, <literal>SELECT 55 AS
@ -57,14 +57,24 @@
<quote>reserved</quote> are those tokens that are not allowed as
column or table names. Some reserved key words are
allowable as names for functions or data types; this is also shown in the
table. If not so marked, a reserved key word is only allowed as an
<quote>AS</quote> column label name.
table. If not so marked, a reserved key word is only allowed as a
column label.
A blank entry in this column means that the word is treated as an
ordinary identifier by <productname>PostgreSQL</productname>.
</para>
<para>
Furthermore, while most key words can be used as <quote>bare</quote>
column labels without writing <literal>AS</literal> before them (as
described in <xref linkend="queries-column-labels"/>), there are a few
that require a leading <literal>AS</literal> to avoid ambiguity. These
are marked in the table as <quote>requires <literal>AS</literal></quote>.
</para>
<para>
As a general rule, if you get spurious parser errors for commands
that contain any of the listed key words as an identifier you should
try to quote the identifier to see if the problem goes away.
that use any of the listed key words as an identifier, you should
try quoting the identifier to see if the problem goes away.
</para>
<para>

View File

@ -1496,21 +1496,25 @@ SELECT a AS value, b + c AS sum FROM ...
</para>
<para>
The <literal>AS</literal> 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</literal> is a keyword, so this does not work:
The <literal>AS</literal> key word is usually optional, but in some
cases where the desired column name matches a
<productname>PostgreSQL</productname> key word, you must write
<literal>AS</literal> or double-quote the column name in order to
avoid ambiguity.
(<xref linkend="sql-keywords-appendix"/> shows which key words
require <literal>AS</literal> to be used as a column label.)
For example, <literal>FROM</literal> is one such key word, so this
does not work:
<programlisting>
SELECT a value, b + c AS sum FROM ...
SELECT a from, b + c AS sum FROM ...
</programlisting>
but this does:
but either of these do:
<programlisting>
SELECT a "value", b + c AS sum FROM ...
SELECT a AS from, b + c AS sum FROM ...
SELECT a "from", b + c AS sum FROM ...
</programlisting>
For protection against possible
future keyword additions, it is recommended that you always either
For greatest safety against possible
future key word additions, it is recommended that you always either
write <literal>AS</literal> or double-quote the output column name.
</para>