aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/parser/check_keywords.pl92
-rw-r--r--src/backend/parser/gram.y440
-rw-r--r--src/backend/parser/scan.l2
-rw-r--r--src/backend/utils/adt/misc.c31
4 files changed, 526 insertions, 39 deletions
diff --git a/src/backend/parser/check_keywords.pl b/src/backend/parser/check_keywords.pl
index 702c97bba2a..3862db07278 100644
--- a/src/backend/parser/check_keywords.pl
+++ b/src/backend/parser/check_keywords.pl
@@ -21,6 +21,28 @@ sub error
return;
}
+# Check alphabetical order of a set of keyword symbols
+# (note these are NOT the actual keyword strings)
+sub check_alphabetical_order
+{
+ my ($listname, $list) = @_;
+ my $prevkword = '';
+
+ foreach my $kword (@$list)
+ {
+ # Some symbols have a _P suffix. Remove it for the comparison.
+ my $bare_kword = $kword;
+ $bare_kword =~ s/_P$//;
+ if ($bare_kword le $prevkword)
+ {
+ error
+ "'$bare_kword' after '$prevkword' in $listname list is misplaced";
+ }
+ $prevkword = $bare_kword;
+ }
+ return;
+}
+
$, = ' '; # set output field separator
$\ = "\n"; # set output record separator
@@ -33,9 +55,11 @@ $keyword_categories{'reserved_keyword'} = 'RESERVED_KEYWORD';
open(my $gram, '<', $gram_filename) || die("Could not open : $gram_filename");
my $kcat;
+my $in_bare_labels;
my $comment;
my @arr;
my %keywords;
+my @bare_label_keywords;
line: while (my $S = <$gram>)
{
@@ -51,7 +75,7 @@ line: while (my $S = <$gram>)
$s = '[/][*]', $S =~ s#$s# /* #g;
$s = '[*][/]', $S =~ s#$s# */ #g;
- if (!($kcat))
+ if (!($kcat) && !($in_bare_labels))
{
# Is this the beginning of a keyword list?
@@ -63,6 +87,10 @@ line: while (my $S = <$gram>)
next line;
}
}
+
+ # Is this the beginning of the bare_label_keyword list?
+ $in_bare_labels = 1 if ($S =~ m/^bare_label_keyword:/);
+
next line;
}
@@ -97,7 +125,8 @@ line: while (my $S = <$gram>)
{
# end of keyword list
- $kcat = '';
+ undef $kcat;
+ undef $in_bare_labels;
next;
}
@@ -107,31 +136,21 @@ line: while (my $S = <$gram>)
}
# Put this keyword into the right list
- push @{ $keywords{$kcat} }, $arr[$fieldIndexer];
+ if ($in_bare_labels)
+ {
+ push @bare_label_keywords, $arr[$fieldIndexer];
+ }
+ else
+ {
+ push @{ $keywords{$kcat} }, $arr[$fieldIndexer];
+ }
}
}
close $gram;
# Check that each keyword list is in alphabetical order (just for neatnik-ism)
-my ($prevkword, $bare_kword);
-foreach my $kcat (keys %keyword_categories)
-{
- $prevkword = '';
-
- foreach my $kword (@{ $keywords{$kcat} })
- {
-
- # Some keyword have a _P suffix. Remove it for the comparison.
- $bare_kword = $kword;
- $bare_kword =~ s/_P$//;
- if ($bare_kword le $prevkword)
- {
- error
- "'$bare_kword' after '$prevkword' in $kcat list is misplaced";
- }
- $prevkword = $bare_kword;
- }
-}
+check_alphabetical_order($_, $keywords{$_}) for (keys %keyword_categories);
+check_alphabetical_order('bare_label_keyword', \@bare_label_keywords);
# Transform the keyword lists into hashes.
# kwhashes is a hash of hashes, keyed by keyword category id,
@@ -147,6 +166,7 @@ while (my ($kcat, $kcat_id) = each(%keyword_categories))
$kwhashes{$kcat_id} = $hash;
}
+my %bare_label_keywords = map { $_ => 1 } @bare_label_keywords;
# Now read in kwlist.h
@@ -160,11 +180,12 @@ kwlist_line: while (<$kwlist>)
{
my ($line) = $_;
- if ($line =~ /^PG_KEYWORD\(\"(.*)\", (.*), (.*)\)/)
+ if ($line =~ /^PG_KEYWORD\(\"(.*)\", (.*), (.*), (.*)\)/)
{
my ($kwstring) = $1;
my ($kwname) = $2;
my ($kwcat_id) = $3;
+ my ($collabel) = $4;
# Check that the list is in alphabetical order (critical!)
if ($kwstring le $prevkwstring)
@@ -197,7 +218,7 @@ kwlist_line: while (<$kwlist>)
"keyword name '$kwname' doesn't match keyword string '$kwstring'";
}
- # Check that the keyword is present in the grammar
+ # Check that the keyword is present in the right category list
%kwhash = %{ $kwhashes{$kwcat_id} };
if (!(%kwhash))
@@ -219,6 +240,29 @@ kwlist_line: while (<$kwlist>)
delete $kwhashes{$kwcat_id}->{$kwname};
}
}
+
+ # Check that the keyword's collabel property matches gram.y
+ if ($collabel eq 'BARE_LABEL')
+ {
+ unless ($bare_label_keywords{$kwname})
+ {
+ error
+ "'$kwname' is marked as BARE_LABEL in kwlist.h, but it is missing from gram.y's bare_label_keyword rule";
+ }
+ }
+ elsif ($collabel eq 'AS_LABEL')
+ {
+ if ($bare_label_keywords{$kwname})
+ {
+ error
+ "'$kwname' is marked as AS_LABEL in kwlist.h, but it is listed in gram.y's bare_label_keyword rule";
+ }
+ }
+ else
+ {
+ error
+ "'$collabel' not recognized in kwlist.h. Expected either 'BARE_LABEL' or 'AS_LABEL'";
+ }
}
}
close $kwlist;
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index b16ffb9bf7f..017940bdcd6 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -540,14 +540,16 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <str> Sconst comment_text notify_payload
%type <str> RoleId opt_boolean_or_string
%type <list> var_list
-%type <str> ColId ColLabel var_name type_function_name param_name
+%type <str> ColId ColLabel BareColLabel
%type <str> NonReservedWord NonReservedWord_or_Sconst
+%type <str> var_name type_function_name param_name
%type <str> createdb_opt_name
%type <node> var_value zone_value
%type <rolespec> auth_ident RoleSpec opt_granted_by
%type <keyword> unreserved_keyword type_func_name_keyword
%type <keyword> col_name_keyword reserved_keyword
+%type <keyword> bare_label_keyword
%type <node> TableConstraint TableLikeClause
%type <ival> TableLikeOptionList TableLikeOption
@@ -14658,11 +14660,7 @@ 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.
- */
- | a_expr IDENT
+ | a_expr BareColLabel
{
$$ = makeNode(ResTarget);
$$->name = $2;
@@ -15011,6 +15009,13 @@ ColLabel: IDENT { $$ = $1; }
| reserved_keyword { $$ = pstrdup($1); }
;
+/* Bare column label --- names that can be column labels without writing "AS".
+ * This classification is orthogonal to the other keyword categories.
+ */
+BareColLabel: IDENT { $$ = $1; }
+ | bare_label_keyword { $$ = pstrdup($1); }
+ ;
+
/*
* Keyword category lists. Generally, every keyword present in
@@ -15515,6 +15520,429 @@ reserved_keyword:
| WITH
;
+/*
+ * While all keywords can be used as column labels when preceded by AS,
+ * not all of them can be used as a "bare" column label without AS.
+ * Those that can be used as a bare label must be listed here,
+ * in addition to appearing in one of the category lists above.
+ *
+ * Always add a new keyword to this list if possible. Mark it BARE_LABEL
+ * in kwlist.h if it is included here, or AS_LABEL if it is not.
+ */
+bare_label_keyword:
+ ABORT_P
+ | ABSOLUTE_P
+ | ACCESS
+ | ACTION
+ | ADD_P
+ | ADMIN
+ | AFTER
+ | AGGREGATE
+ | ALL
+ | ALSO
+ | ALTER
+ | ALWAYS
+ | ANALYSE
+ | ANALYZE
+ | AND
+ | ANY
+ | ASC
+ | ASSERTION
+ | ASSIGNMENT
+ | ASYMMETRIC
+ | AT
+ | ATTACH
+ | ATTRIBUTE
+ | AUTHORIZATION
+ | BACKWARD
+ | BEFORE
+ | BEGIN_P
+ | BETWEEN
+ | BIGINT
+ | BINARY
+ | BIT
+ | BOOLEAN_P
+ | BOTH
+ | BY
+ | CACHE
+ | CALL
+ | CALLED
+ | CASCADE
+ | CASCADED
+ | CASE
+ | CAST
+ | CATALOG_P
+ | CHAIN
+ | CHARACTERISTICS
+ | CHECK
+ | CHECKPOINT
+ | CLASS
+ | CLOSE
+ | CLUSTER
+ | COALESCE
+ | COLLATE
+ | COLLATION
+ | COLUMN
+ | COLUMNS
+ | COMMENT
+ | COMMENTS
+ | COMMIT
+ | COMMITTED
+ | CONCURRENTLY
+ | CONFIGURATION
+ | CONFLICT
+ | CONNECTION
+ | CONSTRAINT
+ | CONSTRAINTS
+ | CONTENT_P
+ | CONTINUE_P
+ | CONVERSION_P
+ | COPY
+ | COST
+ | CROSS
+ | CSV
+ | CUBE
+ | CURRENT_P
+ | CURRENT_CATALOG
+ | CURRENT_DATE
+ | CURRENT_ROLE
+ | CURRENT_SCHEMA
+ | CURRENT_TIME
+ | CURRENT_TIMESTAMP
+ | CURRENT_USER
+ | CURSOR
+ | CYCLE
+ | DATA_P
+ | DATABASE
+ | DEALLOCATE
+ | DEC
+ | DECIMAL_P
+ | DECLARE
+ | DEFAULT
+ | DEFAULTS
+ | DEFERRABLE
+ | DEFERRED
+ | DEFINER
+ | DELETE_P
+ | DELIMITER
+ | DELIMITERS
+ | DEPENDS
+ | DESC
+ | DETACH
+ | DICTIONARY
+ | DISABLE_P
+ | DISCARD
+ | DISTINCT
+ | DO
+ | DOCUMENT_P
+ | DOMAIN_P
+ | DOUBLE_P
+ | DROP
+ | EACH
+ | ELSE
+ | ENABLE_P
+ | ENCODING
+ | ENCRYPTED
+ | END_P
+ | ENUM_P
+ | ESCAPE
+ | EVENT
+ | EXCLUDE
+ | EXCLUDING
+ | EXCLUSIVE
+ | EXECUTE
+ | EXISTS
+ | EXPLAIN
+ | EXPRESSION
+ | EXTENSION
+ | EXTERNAL
+ | EXTRACT
+ | FALSE_P
+ | FAMILY
+ | FIRST_P
+ | FLOAT_P
+ | FOLLOWING
+ | FORCE
+ | FOREIGN
+ | FORWARD
+ | FREEZE
+ | FULL
+ | FUNCTION
+ | FUNCTIONS
+ | GENERATED
+ | GLOBAL
+ | GRANTED
+ | GREATEST
+ | GROUPING
+ | GROUPS
+ | HANDLER
+ | HEADER_P
+ | HOLD
+ | IDENTITY_P
+ | IF_P
+ | ILIKE
+ | IMMEDIATE
+ | IMMUTABLE
+ | IMPLICIT_P
+ | IMPORT_P
+ | IN_P
+ | INCLUDE
+ | INCLUDING
+ | INCREMENT
+ | INDEX
+ | INDEXES
+ | INHERIT
+ | INHERITS
+ | INITIALLY
+ | INLINE_P
+ | INNER_P
+ | INOUT
+ | INPUT_P
+ | INSENSITIVE
+ | INSERT
+ | INSTEAD
+ | INT_P
+ | INTEGER
+ | INTERVAL
+ | INVOKER
+ | IS
+ | ISOLATION
+ | JOIN
+ | KEY
+ | LABEL
+ | LANGUAGE
+ | LARGE_P
+ | LAST_P
+ | LATERAL_P
+ | LEADING
+ | LEAKPROOF
+ | LEAST
+ | LEFT
+ | LEVEL
+ | LIKE
+ | LISTEN
+ | LOAD
+ | LOCAL
+ | LOCALTIME
+ | LOCALTIMESTAMP
+ | LOCATION
+ | LOCK_P
+ | LOCKED
+ | LOGGED
+ | MAPPING
+ | MATCH
+ | MATERIALIZED
+ | MAXVALUE
+ | METHOD
+ | MINVALUE
+ | MODE
+ | MOVE
+ | NAME_P
+ | NAMES
+ | NATIONAL
+ | NATURAL
+ | NCHAR
+ | NEW
+ | NEXT
+ | NFC
+ | NFD
+ | NFKC
+ | NFKD
+ | NO
+ | NONE
+ | NORMALIZE
+ | NORMALIZED
+ | NOT
+ | NOTHING
+ | NOTIFY
+ | NOWAIT
+ | NULL_P
+ | NULLIF
+ | NULLS_P
+ | NUMERIC
+ | OBJECT_P
+ | OF
+ | OFF
+ | OIDS
+ | OLD
+ | ONLY
+ | OPERATOR
+ | OPTION
+ | OPTIONS
+ | OR
+ | ORDINALITY
+ | OTHERS
+ | OUT_P
+ | OUTER_P
+ | OVERLAY
+ | OVERRIDING
+ | OWNED
+ | OWNER
+ | PARALLEL
+ | PARSER
+ | PARTIAL
+ | PARTITION
+ | PASSING
+ | PASSWORD
+ | PLACING
+ | PLANS
+ | POLICY
+ | POSITION
+ | PRECEDING
+ | PREPARE
+ | PREPARED
+ | PRESERVE
+ | PRIMARY
+ | PRIOR
+ | PRIVILEGES
+ | PROCEDURAL
+ | PROCEDURE
+ | PROCEDURES
+ | PROGRAM
+ | PUBLICATION
+ | QUOTE
+ | RANGE
+ | READ
+ | REAL
+ | REASSIGN
+ | RECHECK
+ | RECURSIVE
+ | REF
+ | REFERENCES
+ | REFERENCING
+ | REFRESH
+ | REINDEX
+ | RELATIVE_P
+ | RELEASE
+ | RENAME
+ | REPEATABLE
+ | REPLACE
+ | REPLICA
+ | RESET
+ | RESTART
+ | RESTRICT
+ | RETURNS
+ | REVOKE
+ | RIGHT
+ | ROLE
+ | ROLLBACK
+ | ROLLUP
+ | ROUTINE
+ | ROUTINES
+ | ROW
+ | ROWS
+ | RULE
+ | SAVEPOINT
+ | SCHEMA
+ | SCHEMAS
+ | SCROLL
+ | SEARCH
+ | SECURITY
+ | SELECT
+ | SEQUENCE
+ | SEQUENCES
+ | SERIALIZABLE
+ | SERVER
+ | SESSION
+ | SESSION_USER
+ | SET
+ | SETOF
+ | SETS
+ | SHARE
+ | SHOW
+ | SIMILAR
+ | SIMPLE
+ | SKIP
+ | SMALLINT
+ | SNAPSHOT
+ | SOME
+ | SQL_P
+ | STABLE
+ | STANDALONE_P
+ | START
+ | STATEMENT
+ | STATISTICS
+ | STDIN
+ | STDOUT
+ | STORAGE
+ | STORED
+ | STRICT_P
+ | STRIP_P
+ | SUBSCRIPTION
+ | SUBSTRING
+ | SUPPORT
+ | SYMMETRIC
+ | SYSID
+ | SYSTEM_P
+ | TABLE
+ | TABLES
+ | TABLESAMPLE
+ | TABLESPACE
+ | TEMP
+ | TEMPLATE
+ | TEMPORARY
+ | TEXT_P
+ | THEN
+ | TIES
+ | TIME
+ | TIMESTAMP
+ | TRAILING
+ | TRANSACTION
+ | TRANSFORM
+ | TREAT
+ | TRIGGER
+ | TRIM
+ | TRUE_P
+ | TRUNCATE
+ | TRUSTED
+ | TYPE_P
+ | TYPES_P
+ | UESCAPE
+ | UNBOUNDED
+ | UNCOMMITTED
+ | UNENCRYPTED
+ | UNIQUE
+ | UNKNOWN
+ | UNLISTEN
+ | UNLOGGED
+ | UNTIL
+ | UPDATE
+ | USER
+ | USING
+ | VACUUM
+ | VALID
+ | VALIDATE
+ | VALIDATOR
+ | VALUE_P
+ | VALUES
+ | VARCHAR
+ | VARIADIC
+ | VERBOSE
+ | VERSION_P
+ | VIEW
+ | VIEWS
+ | VOLATILE
+ | WHEN
+ | WHITESPACE_P
+ | WORK
+ | WRAPPER
+ | WRITE
+ | XML_P
+ | XMLATTRIBUTES
+ | XMLCONCAT
+ | XMLELEMENT
+ | XMLEXISTS
+ | XMLFOREST
+ | XMLNAMESPACES
+ | XMLPARSE
+ | XMLPI
+ | XMLROOT
+ | XMLSERIALIZE
+ | XMLTABLE
+ | YES_P
+ | ZONE
+ ;
+
%%
/*
diff --git a/src/backend/parser/scan.l b/src/backend/parser/scan.l
index b1ea0cb5384..4eab2980c99 100644
--- a/src/backend/parser/scan.l
+++ b/src/backend/parser/scan.l
@@ -73,7 +73,7 @@ bool standard_conforming_strings = true;
* callers need to pass it to scanner_init, if they are using the
* standard keyword list ScanKeywords.
*/
-#define PG_KEYWORD(kwname, value, category) value,
+#define PG_KEYWORD(kwname, value, category, collabel) value,
const uint16 ScanKeywordTokens[] = {
#include "parser/kwlist.h"
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 37c23c9155a..b2bf9fa8cbc 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -416,12 +416,16 @@ pg_get_keywords(PG_FUNCTION_ARGS)
funcctx = SRF_FIRSTCALL_INIT();
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
- tupdesc = CreateTemplateTupleDesc(3);
+ tupdesc = CreateTemplateTupleDesc(5);
TupleDescInitEntry(tupdesc, (AttrNumber) 1, "word",
TEXTOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber) 2, "catcode",
CHAROID, -1, 0);
- TupleDescInitEntry(tupdesc, (AttrNumber) 3, "catdesc",
+ TupleDescInitEntry(tupdesc, (AttrNumber) 3, "barelabel",
+ BOOLOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 4, "catdesc",
+ TEXTOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 5, "baredesc",
TEXTOID, -1, 0);
funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
@@ -433,7 +437,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
if (funcctx->call_cntr < ScanKeywords.num_keywords)
{
- char *values[3];
+ char *values[5];
HeapTuple tuple;
/* cast-away-const is ugly but alternatives aren't much better */
@@ -445,26 +449,37 @@ pg_get_keywords(PG_FUNCTION_ARGS)
{
case UNRESERVED_KEYWORD:
values[1] = "U";
- values[2] = _("unreserved");
+ values[3] = _("unreserved");
break;
case COL_NAME_KEYWORD:
values[1] = "C";
- values[2] = _("unreserved (cannot be function or type name)");
+ values[3] = _("unreserved (cannot be function or type name)");
break;
case TYPE_FUNC_NAME_KEYWORD:
values[1] = "T";
- values[2] = _("reserved (can be function or type name)");
+ values[3] = _("reserved (can be function or type name)");
break;
case RESERVED_KEYWORD:
values[1] = "R";
- values[2] = _("reserved");
+ values[3] = _("reserved");
break;
default: /* shouldn't be possible */
values[1] = NULL;
- values[2] = NULL;
+ values[3] = NULL;
break;
}
+ if (ScanKeywordBareLabel[funcctx->call_cntr])
+ {
+ values[2] = "true";
+ values[4] = _("can be bare label");
+ }
+ else
+ {
+ values[2] = "false";
+ values[4] = _("requires AS");
+ }
+
tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));