factorial function/phase out postfix operators?

Started by Peter Eisentrautover 5 years ago73 messages
#1Peter Eisentraut
peter.eisentraut@2ndquadrant.com

There have been occasional discussions about deprecating or phasing out
postfix operators, to make various things easier in the parser.

The first step would in any case be to provide alternatives for the
existing postfix operators. There is currently one, namely the numeric
factorial operator "!". A sensible alternative for that would be
providing a function factorial(numeric) -- and that already exists but
is not documented. (Note that the operator is mapped to proname
"numeric_fac". The function "factorial" maps to the same prosrc but is
otherwise independent of the operator.)

So I suggest that we add that function to the documentation.

(Some adjacent cleanup work might also be in order. The test cases for
factorial are currently in int4.sql, but all the factorial functionality
was moved to numeric a long time ago.)

What are the thoughts about then marking the postfix operator deprecated
and eventually removing it?

--
Peter Eisentraut http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

#2Vik Fearing
vik@postgresfriends.org
In reply to: Peter Eisentraut (#1)
Re: factorial function/phase out postfix operators?

On 5/18/20 4:42 PM, Peter Eisentraut wrote:

There have been occasional discussions about deprecating or phasing out
postfix operators, to make various things easier in the parser.

The first step would in any case be to provide alternatives for the
existing postfix operators.  There is currently one, namely the numeric
factorial operator "!".  A sensible alternative for that would be
providing a function factorial(numeric) -- and that already exists but
is not documented.  (Note that the operator is mapped to proname
"numeric_fac".  The function "factorial" maps to the same prosrc but is
otherwise independent of the operator.)

So I suggest that we add that function to the documentation.

I think this should be done regardless.

(Some adjacent cleanup work might also be in order.  The test cases for
factorial are currently in int4.sql, but all the factorial functionality
was moved to numeric a long time ago.)

What are the thoughts about then marking the postfix operator deprecated
and eventually removing it?

I am greatly in favor of removing postfix operators as soon as possible.
--
Vik Fearing

#3Bruce Momjian
bruce@momjian.us
In reply to: Vik Fearing (#2)
Re: factorial function/phase out postfix operators?

On Mon, May 18, 2020 at 05:02:34PM +0200, Vik Fearing wrote:

On 5/18/20 4:42 PM, Peter Eisentraut wrote:

There have been occasional discussions about deprecating or phasing out
postfix operators, to make various things easier in the parser.

The first step would in any case be to provide alternatives for the
existing postfix operators.� There is currently one, namely the numeric
factorial operator "!".� A sensible alternative for that would be
providing a function factorial(numeric) -- and that already exists but
is not documented.� (Note that the operator is mapped to proname
"numeric_fac".� The function "factorial" maps to the same prosrc but is
otherwise independent of the operator.)

So I suggest that we add that function to the documentation.

I think this should be done regardless.

(Some adjacent cleanup work might also be in order.� The test cases for
factorial are currently in int4.sql, but all the factorial functionality
was moved to numeric a long time ago.)

What are the thoughts about then marking the postfix operator deprecated
and eventually removing it?

I am greatly in favor of removing postfix operators as soon as possible.

Agreed.

--
Bruce Momjian <bruce@momjian.us> https://momjian.us
EnterpriseDB https://enterprisedb.com

+ As you are, so once was I.  As I am, so you will be. +
+                      Ancient Roman grave inscription +
#4Tom Lane
tgl@sss.pgh.pa.us
In reply to: Peter Eisentraut (#1)
Re: factorial function/phase out postfix operators?

Peter Eisentraut <peter.eisentraut@2ndquadrant.com> writes:

What are the thoughts about then marking the postfix operator deprecated
and eventually removing it?

If we do this it'd require a plan. We'd have to also warn about the
feature deprecation in (at least) the CREATE OPERATOR man page, and
we'd have to decide how many release cycles the deprecation notices
need to stand for.

If that's the intention, though, it'd be good to get those deprecation
notices published in v13 not v14.

regards, tom lane

#5David Fetter
david@fetter.org
In reply to: Tom Lane (#4)
Re: factorial function/phase out postfix operators?

On Mon, May 18, 2020 at 10:03:13PM -0400, Tom Lane wrote:

Peter Eisentraut <peter.eisentraut@2ndquadrant.com> writes:

What are the thoughts about then marking the postfix operator deprecated
and eventually removing it?

If we do this it'd require a plan. We'd have to also warn about the
feature deprecation in (at least) the CREATE OPERATOR man page, and
we'd have to decide how many release cycles the deprecation notices
need to stand for.

If that's the intention, though, it'd be good to get those deprecation
notices published in v13 not v14.

+1 for deprecating in v13.

Best,
David.
--
David Fetter <david(at)fetter(dot)org> http://fetter.org/
Phone: +1 415 235 3778

Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate

#6Vik Fearing
vik@postgresfriends.org
In reply to: Tom Lane (#4)
Re: factorial function/phase out postfix operators?

On 5/19/20 4:03 AM, Tom Lane wrote:

Peter Eisentraut <peter.eisentraut@2ndquadrant.com> writes:

What are the thoughts about then marking the postfix operator deprecated
and eventually removing it?

If we do this it'd require a plan. We'd have to also warn about the
feature deprecation in (at least) the CREATE OPERATOR man page, and
we'd have to decide how many release cycles the deprecation notices
need to stand for.

I have never come across any custom postfix operators in the wild, and
I've never even seen ! used in practice.

So I would suggest a very short deprecation period. Deprecate now in
13, let 14 go by, and rip it all out for 15. That should give us enough
time to extend the deprecation period if we need to, or go back on it
entirely (like I seem to remember we did with VACUUM FREEZE).

If that's the intention, though, it'd be good to get those deprecation
notices published in v13 not v14.

+1
-- 
Vik Fearing
#7Robert Haas
robertmhaas@gmail.com
In reply to: Peter Eisentraut (#1)
Re: factorial function/phase out postfix operators?

On Mon, May 18, 2020 at 10:42 AM Peter Eisentraut
<peter.eisentraut@2ndquadrant.com> wrote:

What are the thoughts about then marking the postfix operator deprecated
and eventually removing it?

I wrote a little bit about this last year:

/messages/by-id/CA+TgmoarLfSQcLCh7jx0737SZ28qwbuy+rUWT6rSHAO=B-6xdw@mail.gmail.com

I think it's generally a good idea, though perhaps we should consider
continuing to allow '!' as a postfix operator and just removing
support for any other. That would probably allow us to have a very
short deprecation period, since real-world use of user-defined postfix
operators seems to be nil -- and it would also make this into a change
that only affects the lexer and parser, which might make it simpler.

I won't lose a lot of sleep if we decide to rip out '!' as well, but I
don't think that continuing to support it would cost us much.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#8Pavel Stehule
pavel.stehule@gmail.com
In reply to: Robert Haas (#7)
Re: factorial function/phase out postfix operators?

út 19. 5. 2020 v 14:27 odesílatel Robert Haas <robertmhaas@gmail.com>
napsal:

On Mon, May 18, 2020 at 10:42 AM Peter Eisentraut
<peter.eisentraut@2ndquadrant.com> wrote:

What are the thoughts about then marking the postfix operator deprecated
and eventually removing it?

I wrote a little bit about this last year:

/messages/by-id/CA+TgmoarLfSQcLCh7jx0737SZ28qwbuy+rUWT6rSHAO=B-6xdw@mail.gmail.com

I think it's generally a good idea, though perhaps we should consider
continuing to allow '!' as a postfix operator and just removing
support for any other. That would probably allow us to have a very
short deprecation period, since real-world use of user-defined postfix
operators seems to be nil -- and it would also make this into a change
that only affects the lexer and parser, which might make it simpler.

I won't lose a lot of sleep if we decide to rip out '!' as well, but I
don't think that continuing to support it would cost us much.

This is little bit obscure feature. It can be removed and relative quickly.
Maybe some warning if somebody use it can be good (for Postgres 13)

Pavel

Show quoted text

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#9Kenneth Marshall
ktm@rice.edu
In reply to: Robert Haas (#7)
Re: factorial function/phase out postfix operators?

I won't lose a lot of sleep if we decide to rip out '!' as well, but I
don't think that continuing to support it would cost us much.

+1 for keeping ! and nuking the rest, if possible.

Regards,
Ken

#10Tom Lane
tgl@sss.pgh.pa.us
In reply to: Robert Haas (#7)
Re: factorial function/phase out postfix operators?

Robert Haas <robertmhaas@gmail.com> writes:

I think it's generally a good idea, though perhaps we should consider
continuing to allow '!' as a postfix operator and just removing
support for any other.

Uh ... what exactly would be the point of that? The real reason to do
this at all is not that we have it in for '!', but that we want to
drop the possibility of postfix operators from the grammar altogether,
which will remove a boatload of ambiguity.

I won't lose a lot of sleep if we decide to rip out '!' as well, but I
don't think that continuing to support it would cost us much.

AFAICS, it would cost us the entire point of this change.

In my non-caffeinated state, I don't recall exactly which things are
blocked by the existence of postfix ops; but I think for instance it might
become possible to remove the restriction of requiring AS before column
aliases that happen to be unreserved keywords.

If we lobotomize CREATE OPERATOR but don't remove built-in postfix
ops, then none of those improvements will be available. That seems
like the worst possible choice.

I would also argue that having a feature that is available to
built-in operators but not user-defined ones is pretty antithetical
to Postgres philosophy.

regards, tom lane

#11Robert Haas
robertmhaas@gmail.com
In reply to: Tom Lane (#10)
Re: factorial function/phase out postfix operators?

On Tue, May 19, 2020 at 9:51 AM Tom Lane <tgl@sss.pgh.pa.us> wrote:

Uh ... what exactly would be the point of that? The real reason to do
this at all is not that we have it in for '!', but that we want to
drop the possibility of postfix operators from the grammar altogether,
which will remove a boatload of ambiguity.

The ambiguity doesn't come from the mere existence of postfix
operators. It comes from the fact that, when we lex the input, we
can't tell whether a particular operator that we happen to encounter
is prefix, infix, or postfix. So hard-coding, for example, a rule that
'!' is always a postfix operator and anything else is never a postfix
operator is sufficient to solve the key problems. Then "SELECT a ! b"
can only be a postfix operator application followed by a column
labeling, a "SELECT a + b" can only be the application of an infix
operator.

The parser ambiguities could also be removed if the source of the
information where a GUC or a catalog lookup; there are good reasons
not to go that way, but my point is that the problem is not that
postfix operators are per se evil, but that the information we need is
not available at the right phase of the process. We can only make use
of the information in pg_operator after we start assigning type
information, which has to happen after we parse, but to avoid the
ambiguity here, we need the information before we parse - i.e. at the
lexing stage.

In my non-caffeinated state, I don't recall exactly which things are
blocked by the existence of postfix ops; but I think for instance it might
become possible to remove the restriction of requiring AS before column
aliases that happen to be unreserved keywords.

Right - which would be a huge win.

I would also argue that having a feature that is available to
built-in operators but not user-defined ones is pretty antithetical
to Postgres philosophy.

That I think is the policy question before us. I believe that any rule
that tells us which operators are postfix and which are not at the
lexing stage is good enough. I think here you are arguing for the
empty set, which will work, but I believe any other fixed set also
works, such as { '!' }. I don't think we're going to break a ton of
user code no matter which one we pick, but I do think that it's
possible to pick either one and still achieve our goals here, so
that's the issue that I wanted to raise.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#12Vik Fearing
vik@postgresfriends.org
In reply to: Robert Haas (#11)
Re: factorial function/phase out postfix operators?

On 5/19/20 4:22 PM, Robert Haas wrote:

On Tue, May 19, 2020 at 9:51 AM Tom Lane <tgl@sss.pgh.pa.us> wrote:

Uh ... what exactly would be the point of that? The real reason to do
this at all is not that we have it in for '!', but that we want to
drop the possibility of postfix operators from the grammar altogether,
which will remove a boatload of ambiguity.

The ambiguity doesn't come from the mere existence of postfix
operators. It comes from the fact that, when we lex the input, we
can't tell whether a particular operator that we happen to encounter
is prefix, infix, or postfix. So hard-coding, for example, a rule that
'!' is always a postfix operator and anything else is never a postfix
operator is sufficient to solve the key problems. Then "SELECT a ! b"
can only be a postfix operator application followed by a column
labeling, a "SELECT a + b" can only be the application of an infix
operator.

So if I make a complex UDT where a NOT operator makes a lot of sense[*],
why wouldn't I be allowed to make a prefix operator ! for it? All for
what? That one person in the corner over there who doesn't want to
rewrite their query to use factorial() instead?

I'm -1 on keeping ! around as a hard-coded postfix operator.

[*] I don't have a concrete example in mind, just this abstract one.
--
Vik Fearing

#13Robert Haas
robertmhaas@gmail.com
In reply to: Vik Fearing (#12)
Re: factorial function/phase out postfix operators?

On Tue, May 19, 2020 at 10:36 AM Vik Fearing <vik@postgresfriends.org> wrote:

So if I make a complex UDT where a NOT operator makes a lot of sense[*],
why wouldn't I be allowed to make a prefix operator ! for it? All for
what? That one person in the corner over there who doesn't want to
rewrite their query to use factorial() instead?

I'm -1 on keeping ! around as a hard-coded postfix operator.

Fair enough. I think you may be in the majority on that one, too. I
just wanted to raise the issue, and we'll see if anyone else agrees.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#14Tom Lane
tgl@sss.pgh.pa.us
In reply to: Robert Haas (#11)
Re: factorial function/phase out postfix operators?

Robert Haas <robertmhaas@gmail.com> writes:

The ambiguity doesn't come from the mere existence of postfix
operators. It comes from the fact that, when we lex the input, we
can't tell whether a particular operator that we happen to encounter
is prefix, infix, or postfix. So hard-coding, for example, a rule that
'!' is always a postfix operator and anything else is never a postfix
operator is sufficient to solve the key problems.

If we were willing to say that '!' could *only* be a postfix operator,
then maybe the ambiguity would go away. Or maybe it wouldn't; if
you're seriously proposing this, I think it'd be incumbent on you
to demonstrate that we could still simplify the grammar to the same
extent. But that will incur its own set of compatibility problems,
because there's no reason to assume that nobody has made prefix or
infix '!' operators.

In any case, it's hard to decide that that's a less klugy solution
than getting rid of postfix ops altogether. There's a reason why
few programming languages have those.

In general, I put this on about the same level as when we decided
to remove ';' and ':' as operators (cf 259489bab, 766fb7f70).
Somebody thought it was cute that it was possible to have that,
which maybe it was, but it wasn't really sane in the big picture.
And as I recall, the amount of pushback we got was nil.

regards, tom lane

#15Stephen Frost
sfrost@snowman.net
In reply to: Vik Fearing (#6)
Re: factorial function/phase out postfix operators?

Greetings,

* Vik Fearing (vik@postgresfriends.org) wrote:

On 5/19/20 4:03 AM, Tom Lane wrote:

Peter Eisentraut <peter.eisentraut@2ndquadrant.com> writes:

What are the thoughts about then marking the postfix operator deprecated
and eventually removing it?

If we do this it'd require a plan. We'd have to also warn about the
feature deprecation in (at least) the CREATE OPERATOR man page, and
we'd have to decide how many release cycles the deprecation notices
need to stand for.

I have never come across any custom postfix operators in the wild, and
I've never even seen ! used in practice.

So I would suggest a very short deprecation period. Deprecate now in
13, let 14 go by, and rip it all out for 15. That should give us enough
time to extend the deprecation period if we need to, or go back on it
entirely (like I seem to remember we did with VACUUM FREEZE).

If that's the intention, though, it'd be good to get those deprecation
notices published in v13 not v14.

+1

I agree with putting notices into v13 saying they're deprecated, but
then actually removing them in v14. For that matter, I'd vote that we
generally accept a system whereby when we commit something that removes
a feature in the next major version, we put out some kind of notice that
it's been deprecated and won't be in v14. We don't want to run the risk
of saying XYZ has been deprecated and then it staying around for a few
years, nor trying to say "it'll be removed in v14" before we actually
know that it's been committed for v14.

In other words, wait to deprecate until the commit has happened for v14
(and maybe wait a couple days in case someone wasn't watching and argues
to revert, but not longer than any normal commit), and then go back and
mark it as "deprecated and removed in v14" for all back-branches. Users
will continue to have 5 years (by upgrading to v13, or whatever the last
release was before their favorite feature was removed, if they really
need to) to update their systems to deal with the change.

We do not do ourselves nor our users a real service by carrying forward
deprecated code/interfaces/views/etc, across major versions; instead
they tend to live on in infamy, with some users actually updating and
some not, ever, and then complaining when we suggest actually removing
it (we have lots of good examples of that too) and then we have to have
the debate again about removing it and, in some cases, we end up
un-deprecating it, which is confusing for users and a bit ridiculous.

Let's not do that.

Thanks,

Stephen

#16Tom Lane
tgl@sss.pgh.pa.us
In reply to: Vik Fearing (#12)
Re: factorial function/phase out postfix operators?

Vik Fearing <vik@postgresfriends.org> writes:

I'm -1 on keeping ! around as a hard-coded postfix operator.

Before we go much further on this, we should have some proof
that there's actually material benefit to be gained. I spent some
time just now trying to relax the AS restriction by ripping out
postfix ops, and the results were not too promising. Indeed the
postfix-ops problem goes away, but then you find out that SQL's
random syntax choices for type names become the stumbling block.
An example here is that given

SELECT 'foo'::character varying

it's not clear if "varying" is supposed to be part of the type name or a
column label. It looks to me like we'd have to increase the reserved-ness
of VARYING, PRECISION, and about half a dozen currently-unreserved
keywords involved in INTERVAL syntax, including such popular column names
as "month", "day", and "year".

Plus I got conflicts on WITHIN, GROUP, and FILTER from ordered-set
aggregate syntax; those are currently unreserved keywords, but they
can't be allowed as AS-less column labels.

We could possibly minimize the damage by inventing another keyword
classification besides the four we have now. Or maybe we should
think harder about using more lookahead between the lexer and grammar.
But this is going to be a lot more ticklish than I would've hoped,
and possibly not cost-free, so we might well end up never pulling
the trigger on such a change.

So right at the moment I'm agreeing with Stephen's nearby opinion:
let's not deprecate these until we've got a patch that gets some
concrete benefit from removing them.

regards, tom lane

#17Robert Haas
robertmhaas@gmail.com
In reply to: Tom Lane (#16)
Re: factorial function/phase out postfix operators?

On Tue, May 19, 2020 at 11:32 AM Tom Lane <tgl@sss.pgh.pa.us> wrote:

Before we go much further on this, we should have some proof
that there's actually material benefit to be gained. I spent some
time just now trying to relax the AS restriction by ripping out
postfix ops, and the results were not too promising. Indeed the
postfix-ops problem goes away, but then you find out that SQL's
random syntax choices for type names become the stumbling block.
An example here is that given

SELECT 'foo'::character varying

it's not clear if "varying" is supposed to be part of the type name or a
column label. It looks to me like we'd have to increase the reserved-ness
of VARYING, PRECISION, and about half a dozen currently-unreserved
keywords involved in INTERVAL syntax, including such popular column names
as "month", "day", and "year".

Plus I got conflicts on WITHIN, GROUP, and FILTER from ordered-set
aggregate syntax; those are currently unreserved keywords, but they
can't be allowed as AS-less column labels.

I came to similar conclusions a couple of years ago:

/messages/by-id/CA+TgmoYzPvT7uiHjWgKtyTivHHLNCp0yLavCoipE-LyG3w2wOQ@mail.gmail.com

What I proposed at the time was creating a new category of keywords.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#18Tom Lane
tgl@sss.pgh.pa.us
In reply to: Robert Haas (#17)
Re: factorial function/phase out postfix operators?

Robert Haas <robertmhaas@gmail.com> writes:

On Tue, May 19, 2020 at 11:32 AM Tom Lane <tgl@sss.pgh.pa.us> wrote:

Before we go much further on this, we should have some proof
that there's actually material benefit to be gained. I spent some
time just now trying to relax the AS restriction by ripping out
postfix ops, and the results were not too promising.

I came to similar conclusions a couple of years ago:
/messages/by-id/CA+TgmoYzPvT7uiHjWgKtyTivHHLNCp0yLavCoipE-LyG3w2wOQ@mail.gmail.com

Ah, right.

What I proposed at the time was creating a new category of keywords.

Might work. My main concern would be if we have to forbid those keywords
as column names --- for words like "year", in particular, that'd be a
disaster. If the net effect is only that they can't be AS-less col labels,
it won't break any cases that worked before.

Our existing four-way keyword classification is not something that was
handed down on stone tablets. I wonder whether postfix-ectomy changes
the situation enough that a complete rethinking would be helpful.

I also continue to think that more lookahead and token-merging would
be interesting to pursue. It'd hardly surprise anybody if the
token pair "character varying" were always treated as a type name,
for instance.

Anyway, the bottom-line conclusion remains the same: let's make sure
we know what we'd do after getting rid of postfix ops, before we do
that.

regards, tom lane

#19Robert Haas
robertmhaas@gmail.com
In reply to: Tom Lane (#18)
Re: factorial function/phase out postfix operators?

On Tue, May 19, 2020 at 2:30 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:

Might work. My main concern would be if we have to forbid those keywords
as column names --- for words like "year", in particular, that'd be a
disaster. If the net effect is only that they can't be AS-less col labels,
it won't break any cases that worked before.

ISTM that all we have to do to avoid that is switch from a four-way
classification to a five-way classification: just split
unreserved_keyword into totally_unreserved_keyword and
very_slightly_reserved_keyword.

Our existing four-way keyword classification is not something that was
handed down on stone tablets. I wonder whether postfix-ectomy changes
the situation enough that a complete rethinking would be helpful.

I don't see that they do, but I might be missing something. I think
there's an excellent argument for adding one new category, but it's
not clear to me why it should reshape the landscape any more than
that.

I also continue to think that more lookahead and token-merging would
be interesting to pursue. It'd hardly surprise anybody if the
token pair "character varying" were always treated as a type name,
for instance.

I think that line of attack will not buy very much. The ability to
avoid unexpected consequences is entirely contingent on the
unlikeliness of the keywords appearing adjacent to each other in some
other context, and the only argument for that here is that neither of
those words is a terribly likely column name. I think that when you
try to solve interesting problems with this, though, you very quickly
run into problems where that's not the case, and you'll need a
technique that has some knowledge of the parser state to actually do
something that works well. I read a paper some years ago that proposed
a solution to this problem: if the parser generator sees a
shift/reduce conflict, it checks whether the conflict can be resolve
by looking ahead one or more additional tokens. If so, it can build a
little DFA that gets run when you enter that state, with edges labeled
with lookahead tokens, and it runs that DFA whenever you reach the
problematic state. Since, hopefully, such states are relatively rarely
encountered, the overhead is low, yet it still gives you a way out of
conflicts in many practical cases. Unfortunately, the chances of bison
implementing such a thing do not seem very good.

Anyway, the bottom-line conclusion remains the same: let's make sure
we know what we'd do after getting rid of postfix ops, before we do
that.

Well, I don't think we really need to get too conservative here. I've
studied this issue enough over the years to be pretty darn sure that
this is a necessary prerequisite to doing something about the "AS
unreserved_keyword" issue, and that it is by far the most significant
issue in doing something about that problem. Sure, there are other
issues, but I think they are basically matters of politics or policy.
For example, if some key people DID think that the four-way keyword
classification was handed down on stone tablets, that could be quite a
problem, but if we're willing to take the view that solving the "AS
unreserved_keyword" problem is pretty important and we need to find a
way to get it done, then I think we an do that. It seems to me that
the first thing that we need to do here is get a deprecation notice
out, so that people know that we're planning to break this. I think we
should go ahead and make that happen now, or at least pretty soon.

I'm still interested in hearing what people think about hard-coding !
as a postfix operator vs. removing postfix operators altogether. I
think Vik and Tom are against keeping just !, Kenneth Marshall are for
it, and I'm not sure I understand Pavel's position. I'm about +0.3 for
keeping just ! myself. Maybe we'll get some other votes. If you're
willing to be persuaded that keeping only ! is a sensible thing to
consider, I could probably draft a very rough patch showing that it
would still be sufficient to get us out from under the "AS
unreserved_keyword" problem, but if you and/or enough other people
hate that direction with a fiery passion, I won't bother. I'm pretty
sure it's technically possible, but the issue is more about what
people actually want.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#20Tom Lane
tgl@sss.pgh.pa.us
In reply to: Robert Haas (#19)
Re: factorial function/phase out postfix operators?

Robert Haas <robertmhaas@gmail.com> writes:

On Tue, May 19, 2020 at 2:30 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:

Anyway, the bottom-line conclusion remains the same: let's make sure
we know what we'd do after getting rid of postfix ops, before we do
that.

Well, I don't think we really need to get too conservative here.
... It seems to me that
the first thing that we need to do here is get a deprecation notice
out, so that people know that we're planning to break this.

No, I disagree with that, because from what I've seen so far it's
not really clear to me that we have a full solution to the AS
problem excepting only postfix ops. I don't want to deprecate
postfix ops before it's completely clear that we can get something
out of it. Otherwise, we'll either end up un-deprecating them,
which makes us look silly, or removing a feature for zero benefit.

Stephen's nearby proposal to deprecate only after a patch has been
committed doesn't seem all that unreasonable, if you're only intending
to allow one cycle's worth of notice. In particular, I could easily
see us committing a fix sometime this summer and then sticking
deprecation notices into the back branches before v13 goes gold.
But let's have the complete fix in hand first.

I'm still interested in hearing what people think about hard-coding !
as a postfix operator vs. removing postfix operators altogether. I
think Vik and Tom are against keeping just !, Kenneth Marshall are for
it, and I'm not sure I understand Pavel's position.

Yes, I'm VERY strongly against keeping just !. I think it'd be a
ridiculous, and probably very messy, backwards-compatibility hack; and the
fact that it will break valid use-cases that we don't need to break seems
to me to well outweigh the possibility that someone would rather not
change their queries to use factorial() or !!.

However, we do have to have a benefit to show those people whose
queries we break. Hence my insistence on having a working AS fix
(or some other benefit) before not after.

regards, tom lane

#21Tom Lane
tgl@sss.pgh.pa.us
In reply to: Tom Lane (#20)
1 attachment(s)
Re: factorial function/phase out postfix operators?

I wrote:

However, we do have to have a benefit to show those people whose
queries we break. Hence my insistence on having a working AS fix
(or some other benefit) before not after.

I experimented with this a bit more, and came up with the attached.
It's not a working patch, just a set of grammar changes that Bison
is happy with. (Getting to a working patch would require fixing the
various build infrastructure that knows about the keyword classification,
which seems straightforward but tedious.)

As Robert theorized, it works to move a fairly-small number of unreserved
keywords into a new slightly-reserved category. However, as the patch
stands, only the remaining fully-unreserved keywords can be used as bare
column labels. I'd hoped to be able to also use col_name keywords in that
way (which'd make the set of legal bare column labels mostly the same as
ColId). The col_name keywords that cause problems are, it appears,
only PRECISION, CHARACTER, and CHAR_P. So in principle we could move
those three into yet another keyword category and then let the remaining
col_name keywords be included in BareColLabel. I kind of think that
that's more complication than it's worth, though.

regards, tom lane

Attachments:

bison-hack-for-optional-AS.patchtext/x-diff; charset=us-ascii; name=bison-hack-for-optional-AS.patchDownload
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index a24b30f..0b034b6 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -542,13 +542,14 @@ 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> unreserved_keyword non_label_keyword type_func_name_keyword
 %type <keyword> col_name_keyword reserved_keyword
 
 %type <node>	TableConstraint TableLikeClause
@@ -744,7 +745,6 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 %nonassoc	'<' '>' '=' LESS_EQUALS GREATER_EQUALS NOT_EQUALS
 %nonassoc	BETWEEN IN_P LIKE ILIKE SIMILAR NOT_LA
 %nonassoc	ESCAPE			/* ESCAPE must be just above LIKE/ILIKE/SIMILAR */
-%left		POSTFIXOP		/* dummy for postfix Op rules */
 /*
  * To support target_el without AS, we must give IDENT an explicit priority
  * between POSTFIXOP and Op.  We can safely assign the same priority to
@@ -3908,6 +3908,7 @@ PartitionSpec: PARTITION BY part_strategy '(' part_params ')'
 
 part_strategy:	IDENT					{ $$ = $1; }
 				| unreserved_keyword	{ $$ = pstrdup($1); }
+				| non_label_keyword		{ $$ = pstrdup($1); }
 		;
 
 part_params:	part_elem						{ $$ = list_make1($1); }
@@ -13230,8 +13231,6 @@ a_expr:		c_expr									{ $$ = $1; }
 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3, @2); }
 			| qual_Op a_expr					%prec Op
 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $1, NULL, $2, @1); }
-			| a_expr qual_Op					%prec POSTFIXOP
-				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, NULL, @2); }
 
 			| a_expr AND a_expr
 				{ $$ = makeAndExpr($1, $3, @2); }
@@ -13645,8 +13644,6 @@ b_expr:		c_expr
 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3, @2); }
 			| qual_Op b_expr					%prec Op
 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $1, NULL, $2, @1); }
-			| b_expr qual_Op					%prec POSTFIXOP
-				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, NULL, @2); }
 			| b_expr IS DISTINCT FROM b_expr		%prec IS
 				{
 					$$ = (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $5, @2);
@@ -14910,7 +14907,7 @@ target_el:	a_expr AS ColLabel
 			 * as an infix expression, which we accomplish by assigning
 			 * IDENT a precedence higher than POSTFIXOP.
 			 */
-			| a_expr IDENT
+			| a_expr BareColLabel
 				{
 					$$ = makeNode(ResTarget);
 					$$->name = $2;
@@ -15228,6 +15225,7 @@ role_list:	RoleSpec
  */
 ColId:		IDENT									{ $$ = $1; }
 			| unreserved_keyword					{ $$ = pstrdup($1); }
+			| non_label_keyword						{ $$ = pstrdup($1); }
 			| col_name_keyword						{ $$ = pstrdup($1); }
 		;
 
@@ -15235,6 +15233,7 @@ ColId:		IDENT									{ $$ = $1; }
  */
 type_function_name:	IDENT							{ $$ = $1; }
 			| unreserved_keyword					{ $$ = pstrdup($1); }
+			| non_label_keyword						{ $$ = pstrdup($1); }
 			| type_func_name_keyword				{ $$ = pstrdup($1); }
 		;
 
@@ -15242,15 +15241,23 @@ type_function_name:	IDENT							{ $$ = $1; }
  */
 NonReservedWord:	IDENT							{ $$ = $1; }
 			| unreserved_keyword					{ $$ = pstrdup($1); }
+			| non_label_keyword						{ $$ = pstrdup($1); }
 			| col_name_keyword						{ $$ = pstrdup($1); }
 			| type_func_name_keyword				{ $$ = pstrdup($1); }
 		;
 
+/* Bare column label --- names that can be column labels without writing "AS".
+ */
+BareColLabel:	IDENT								{ $$ = $1; }
+			| unreserved_keyword					{ $$ = pstrdup($1); }
+		;
+
 /* Column label --- allowed labels in "AS" clauses.
  * This presently includes *all* Postgres keywords.
  */
 ColLabel:	IDENT									{ $$ = $1; }
 			| unreserved_keyword					{ $$ = pstrdup($1); }
+			| non_label_keyword						{ $$ = pstrdup($1); }
 			| col_name_keyword						{ $$ = pstrdup($1); }
 			| type_func_name_keyword				{ $$ = pstrdup($1); }
 			| reserved_keyword						{ $$ = pstrdup($1); }
@@ -15326,7 +15333,6 @@ unreserved_keyword:
 			| CYCLE
 			| DATA_P
 			| DATABASE
-			| DAY_P
 			| DEALLOCATE
 			| DECLARE
 			| DEFAULTS
@@ -15360,7 +15366,6 @@ unreserved_keyword:
 			| EXTENSION
 			| EXTERNAL
 			| FAMILY
-			| FILTER
 			| FIRST_P
 			| FOLLOWING
 			| FORCE
@@ -15374,7 +15379,6 @@ unreserved_keyword:
 			| HANDLER
 			| HEADER_P
 			| HOLD
-			| HOUR_P
 			| IDENTITY_P
 			| IF_P
 			| IMMEDIATE
@@ -15414,10 +15418,8 @@ unreserved_keyword:
 			| MATERIALIZED
 			| MAXVALUE
 			| METHOD
-			| MINUTE_P
 			| MINVALUE
 			| MODE
-			| MONTH_P
 			| MOVE
 			| NAME_P
 			| NAMES
@@ -15443,7 +15445,6 @@ unreserved_keyword:
 			| OPTIONS
 			| ORDINALITY
 			| OTHERS
-			| OVER
 			| OVERRIDING
 			| OWNED
 			| OWNER
@@ -15499,7 +15500,6 @@ unreserved_keyword:
 			| SCHEMAS
 			| SCROLL
 			| SEARCH
-			| SECOND_P
 			| SECURITY
 			| SEQUENCE
 			| SEQUENCES
@@ -15557,23 +15557,36 @@ unreserved_keyword:
 			| VALIDATE
 			| VALIDATOR
 			| VALUE_P
-			| VARYING
 			| VERSION_P
 			| VIEW
 			| VIEWS
 			| VOLATILE
 			| WHITESPACE_P
-			| WITHIN
-			| WITHOUT
 			| WORK
 			| WRAPPER
 			| WRITE
 			| XML_P
-			| YEAR_P
 			| YES_P
 			| ZONE
 		;
 
+/* "Non label" keywords --- cannot be a bare column label in a SELECT list
+ * (you have to write AS in front).  Otherwise usable for anything.
+ */
+non_label_keyword:
+			DAY_P
+			| FILTER
+			| HOUR_P
+			| MINUTE_P
+			| MONTH_P
+			| OVER
+			| SECOND_P
+			| VARYING
+			| WITHIN
+			| WITHOUT
+			| YEAR_P
+		;
+
 /* Column identifier --- keywords that can be column, table, etc names.
  *
  * Many of these keywords will in fact be recognized as type or function
#22Robert Haas
robertmhaas@gmail.com
In reply to: Tom Lane (#21)
Re: factorial function/phase out postfix operators?

On Tue, May 19, 2020 at 7:47 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:

As Robert theorized, it works to move a fairly-small number of unreserved
keywords into a new slightly-reserved category.

It wasn't entirely a theoretical argument, since I'm pretty sure I did
spend some time experimenting with gram.y back in the day, but
possibly not to the extent that you've done here. And I seem not to
have saved my work, either...

However, as the patch
stands, only the remaining fully-unreserved keywords can be used as bare
column labels. I'd hoped to be able to also use col_name keywords in that
way (which'd make the set of legal bare column labels mostly the same as
ColId). The col_name keywords that cause problems are, it appears,
only PRECISION, CHARACTER, and CHAR_P. So in principle we could move
those three into yet another keyword category and then let the remaining
col_name keywords be included in BareColLabel. I kind of think that
that's more complication than it's worth, though.

I think it's a judgement call. If all we do is what you have in the
patch, we can make 288 keywords that currently aren't usable as column
labels without AS, plus future unreserved keywords that get similar
treatment. If we also split the column-name keywords, then we can buy
ourselves another 48 keywords that can be used as column labels
without AS. Presumably everybody is going to agree that allowing more
keywords to be used this way is better than fewer, but also that
having fewer keyword classifications is better than having more, and
those goals are in tension in this case.

I believe that most, possibly all, of the examples of this problem
that I have seen involve unreserved keywords, but that might just
because there are a lot more unreserved keywords than there are
keywords of any other sort. Things like TIME, POSITION, and VALUES
don't seem like particularly unlikely choices for a column label. I
mean, someone who knows SQL well and is a good programmer might not
choose these things, either because they're kind of generic, or
because they're known to have special meaning in SQL. However, SQL is
used by many people who don't know it well and aren't good
programmers, and people coming from other database systems generally
don't have to worry much about their choice of column labels and then
get sad when their migration fails. So I'd be somewhat inclined to see
how far we can reasonably push this, but I'm also entirely willing to
accept that 85% of a loaf is better than none.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#23Tom Lane
tgl@sss.pgh.pa.us
In reply to: Robert Haas (#22)
Re: factorial function/phase out postfix operators?

Robert Haas <robertmhaas@gmail.com> writes:

On Tue, May 19, 2020 at 7:47 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:

However, as the patch
stands, only the remaining fully-unreserved keywords can be used as bare
column labels. I'd hoped to be able to also use col_name keywords in that
way (which'd make the set of legal bare column labels mostly the same as
ColId). The col_name keywords that cause problems are, it appears,
only PRECISION, CHARACTER, and CHAR_P. So in principle we could move
those three into yet another keyword category and then let the remaining
col_name keywords be included in BareColLabel. I kind of think that
that's more complication than it's worth, though.

I think it's a judgement call. If all we do is what you have in the
patch, we can make 288 keywords that currently aren't usable as column
labels without AS, plus future unreserved keywords that get similar
treatment. If we also split the column-name keywords, then we can buy
ourselves another 48 keywords that can be used as column labels
without AS. Presumably everybody is going to agree that allowing more
keywords to be used this way is better than fewer, but also that
having fewer keyword classifications is better than having more, and
those goals are in tension in this case.

Right; I'd done the same arithmetic. Since we currently have a total
of 450 keywords of all flavors, that means we can make either 64%
of them or 74.6% of them be safe to use as bare column labels. While
that's surely better than today, it doesn't seem like it's going to
make for any sort of sea change in the extent of the problem. So I was
feeling a bit discouraged by these results.

I too failed to save the results of some experimentation, but I'd
also poked at the type_func_name_keyword category, and it has a similar
situation where only about three keywords cause problems if included
in BareColLabel. So we could possibly get another twenty-ish keywords
into that set with yet a third new keyword category. But (a) we'd still
only be at 79% coverage and (b) this is *really* making things messy
keyword-category-wise. I feel like we'd be better advised to somehow
treat can-be-bare-col-label as an independent classification.

(I did not look at whether any of the fully-reserved keywords could
be made safe to use, but it seems likely that at least some of them
could be, if we accept even more classification mess.)

Bottom line is that we can reduce the scope of the col-label problem
this way, but we can't make it go away entirely. Is a partial solution
to that worth a full drop of postfix operators? Possibly, but I'm not
sure. I still feel like it'd be worth investigating some other solution
technology, ie lookahead, though I concede your point that that has
pitfalls too.

regards, tom lane

#24Mark Dilger
mark.dilger@enterprisedb.com
In reply to: Tom Lane (#23)
Re: factorial function/phase out postfix operators?

On May 20, 2020, at 11:24 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Bottom line is that we can reduce the scope of the col-label problem
this way, but we can't make it go away entirely. Is a partial solution
to that worth a full drop of postfix operators? Possibly, but I'm not
sure. I still feel like it'd be worth investigating some other solution
technology, ie lookahead, though I concede your point that that has
pitfalls too.

I should think a lot of the problem stems from allowing the same characters to be used in postfix operators as in other operators. The ! character is already not allowed as a column alias:

+SELECT 1 AS ! ORDER BY !;
+ERROR:  syntax error at or near "!"
+LINE 1: SELECT 1 AS ! ORDER BY !;
+                    ^

But you can use it as a prefix or infix operator, which creates the confusion about whether

SELECT 5 ! x

Means "x" as an alias or as the right argument to the ! infix operator. But if we made a clean distinction between the characters that are allowed in postfix operators vs. those allowed for infix operators, then we'd get to have postfix operators without the ambiguity, right?

When thinking about postfix operators, the subscript and superscript character ranges come to my mind, such as

SELECT Σ₂(x² + y³ + z⁴);

These also come to mind as prefix operators, but I don't recall seeing them as infix operators, so maybe it would be ok to disallow that? As for the ! infix operator, it doesn't exist by default:

+SELECT x ! y from (select 5 AS x, 3 AS y) AS ss;
+ERROR:  operator does not exist: integer ! integer
+LINE 1: SELECT x ! y from (select 5 AS x, 3 AS y) AS ss;
+                 ^
+HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.

So if we put that in the set of characters disallowed for infix operators, we would only be breaking custom infix operators named that, which seems like less breakage to me than removing postfix operators of all kinds.


Mark Dilger
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#25Tom Lane
tgl@sss.pgh.pa.us
In reply to: Mark Dilger (#24)
Re: factorial function/phase out postfix operators?

Mark Dilger <mark.dilger@enterprisedb.com> writes:

... But if we made a clean distinction between the characters that are allowed in postfix operators vs. those allowed for infix operators, then we'd get to have postfix operators without the ambiguity, right?

I continue to see little point in half-baked compatibility measures
like that. You'd be much more likely to break working setups (that
might not even involve any postfix operators) than to accomplish
anything useful. In particular, if Joe DBA out there has a postfix
operator, and it's not named according to whatever rule you chose,
then you haven't done anything to fix his compatibility problem.

When thinking about postfix operators, the subscript and superscript character ranges come to my mind, such as
SELECT Σ₂(x² + y³ + z⁴);

We already have a convention about non-ASCII characters, and it is that
they are identifier characters not operator characters. Changing that
would break yet a different set of applications. (That is to say,
the above SELECT already has a well-defined lexical interpretation.)

regards, tom lane

#26Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Tom Lane (#23)
Re: factorial function/phase out postfix operators?

On 2020-May-20, Tom Lane wrote:

I too failed to save the results of some experimentation, but I'd
also poked at the type_func_name_keyword category, and it has a similar
situation where only about three keywords cause problems if included
in BareColLabel. So we could possibly get another twenty-ish keywords
into that set with yet a third new keyword category. But (a) we'd still
only be at 79% coverage and (b) this is *really* making things messy
keyword-category-wise. I feel like we'd be better advised to somehow
treat can-be-bare-col-label as an independent classification.

(I did not look at whether any of the fully-reserved keywords could
be made safe to use, but it seems likely that at least some of them
could be, if we accept even more classification mess.)

Would it make sense (and possible) to have a keyword category that is
not disjoint wrt. the others? Maybe that ends up being easier than
a solution that ends up with six or seven categories.

--
�lvaro Herrera https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

#27Tom Lane
tgl@sss.pgh.pa.us
In reply to: Alvaro Herrera (#26)
Re: factorial function/phase out postfix operators?

Alvaro Herrera <alvherre@2ndquadrant.com> writes:

On 2020-May-20, Tom Lane wrote:

I feel like we'd be better advised to somehow
treat can-be-bare-col-label as an independent classification.

Would it make sense (and possible) to have a keyword category that is
not disjoint wrt. the others? Maybe that ends up being easier than
a solution that ends up with six or seven categories.

Yeah, that's the same thing I was vaguely imagining -- an independent
flag on each keyword as to whether it can be used as a bare column
alias.

regards, tom lane

#28Robert Haas
robertmhaas@gmail.com
In reply to: Tom Lane (#23)
Re: factorial function/phase out postfix operators?

On Wed, May 20, 2020 at 2:24 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:

Right; I'd done the same arithmetic. Since we currently have a total
of 450 keywords of all flavors, that means we can make either 64%
of them or 74.6% of them be safe to use as bare column labels. While
that's surely better than today, it doesn't seem like it's going to
make for any sort of sea change in the extent of the problem. So I was
feeling a bit discouraged by these results.

I don't think you should feel discouraged by these results. They
assume that people are just as likely to have a problem with a
reserved keyword as an unreserved keyword, and I don't think that's
actually true. The 25.4% of keywords that aren't handled this way
include, to take a particularly egregious example, "AS" itself. And I
don't think many people are going to be sad if "select 1 as;" fails to
treat "as" as a column label.

Also, even if we only made 74.6% of these safe to use as bare column
labels, or even 64%, I think that's actually pretty significant. If I
could reduce my mortgage payment by 64%, I would be pretty happy. For
many people, that would be a sufficiently large economic impact that
it actually would be a sea change in terms of their quality of life. I
don't see a reason to suppose that's not also true here.[1]On the other hand, if I had 64% fewer ants in my picnic basket, I would probably still be unhappy with the number of ants in my picnic basket, so it all depends on context and perspective.

I do like the idea of considering "can be a bare column label" as an
independent dimension from the existing keyword classification.
Presumably we would then have, in addition to the four existing
keyword productions, but then also a separate
bare_column_label_keyword: production that would include many of the
same keywords. One nice thing about that approach is that we would
then have a clear list of exactly which keywords can't be given that
treatment, and if somebody wanted to go investigate possible
improvements for any of those, they could do so. I think we'd want a
cross-check: check_keywords.pl should contain the list of keywords
that are expected to be excluded from this new production, so that any
time someone adds a new keyword, they've either got to add it to the
new production or add it to the exception list.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

[1]: On the other hand, if I had 64% fewer ants in my picnic basket, I would probably still be unhappy with the number of ants in my picnic basket, so it all depends on context and perspective.
would probably still be unhappy with the number of ants in my picnic
basket, so it all depends on context and perspective.

#29Peter Eisentraut
peter.eisentraut@2ndquadrant.com
In reply to: Tom Lane (#21)
Re: factorial function/phase out postfix operators?

On 2020-05-20 01:47, Tom Lane wrote:

I wrote:

However, we do have to have a benefit to show those people whose
queries we break. Hence my insistence on having a working AS fix
(or some other benefit) before not after.

I experimented with this a bit more, and came up with the attached.
It's not a working patch, just a set of grammar changes that Bison
is happy with. (Getting to a working patch would require fixing the
various build infrastructure that knows about the keyword classification,
which seems straightforward but tedious.)

What I was hoping to get out of this was to resolve some of the weird
precedence hacks that were blamed on postfix operators. But building on
your patch, the best I could achieve was

-%nonassoc  IDENT GENERATED NULL_P PARTITION RANGE ROWS GROUPS PRECEDING 
FOLLOWING CUBE ROLLUP
+%nonassoc  IDENT PARTITION RANGE ROWS GROUPS PRECEDING FOLLOWING CUBE 
ROLLUP

which is a pretty poor yield.

Maybe this isn't worth it after all.

--
Peter Eisentraut http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

#30Tom Lane
tgl@sss.pgh.pa.us
In reply to: Peter Eisentraut (#29)
Re: factorial function/phase out postfix operators?

Peter Eisentraut <peter.eisentraut@2ndquadrant.com> writes:

What I was hoping to get out of this was to resolve some of the weird
precedence hacks that were blamed on postfix operators.

Yeah, I was thinking about that too, but hadn't gotten to it.

But building on your patch, the best I could achieve was

-%nonassoc  IDENT GENERATED NULL_P PARTITION RANGE ROWS GROUPS PRECEDING 
FOLLOWING CUBE ROLLUP
+%nonassoc  IDENT PARTITION RANGE ROWS GROUPS PRECEDING FOLLOWING CUBE 
ROLLUP

which is a pretty poor yield.

I'd hoped for better as well. Still, it's possible this would save us
from greater pain in the future, seeing that the SQL committee seems
resolutely uninterested in whether the syntax they invent is parsable.

(Also, there are other factors here: I think at least some of those
precedence hacks are there to avoid fully reserving the associated
keywords.)

Maybe this isn't worth it after all.

It'd be nice to have a better yield from removing a user-visible
feature. Perhaps there would be no complaints about removing
postfix ops, but if there are I want to be able to point to some
substantial benefit that users get from it. (Which is why I focused
on the optional-AS business to start with ... users don't care
about how many precedence hacks we need.)

regards, tom lane

#31Mark Dilger
mark.dilger@enterprisedb.com
In reply to: Tom Lane (#21)
2 attachment(s)
Re: factorial function/phase out postfix operators?

On May 19, 2020, at 4:47 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

I wrote:

However, we do have to have a benefit to show those people whose
queries we break. Hence my insistence on having a working AS fix
(or some other benefit) before not after.

I experimented with this a bit more, and came up with the attached.
It's not a working patch, just a set of grammar changes that Bison
is happy with. (Getting to a working patch would require fixing the
various build infrastructure that knows about the keyword classification,
which seems straightforward but tedious.)

I built a patch on top of yours that does much of that tedious work.

As Robert theorized, it works to move a fairly-small number of unreserved
keywords into a new slightly-reserved category. However, as the patch
stands, only the remaining fully-unreserved keywords can be used as bare
column labels. I'd hoped to be able to also use col_name keywords in that
way (which'd make the set of legal bare column labels mostly the same as
ColId). The col_name keywords that cause problems are, it appears,
only PRECISION, CHARACTER, and CHAR_P. So in principle we could move
those three into yet another keyword category and then let the remaining
col_name keywords be included in BareColLabel. I kind of think that
that's more complication than it's worth, though.

By my count, 288 more keywords can be used as column aliases without the AS keyword after the patch. That exactly matches what Robert said upthread.

Tom and Álvaro discussed upthread:

Would it make sense (and possible) to have a keyword category that is
not disjoint wrt. the others? Maybe that ends up being easier than
a solution that ends up with six or seven categories.

I didn't see much point in that. The way Tom had it in his patch was easy to work with. Maybe I'm missing something?

The patch, attached, still needs documentation updates and an update to pg_upgrade. Users upgrading to v14 may have custom postfix operators. Should pg_upgrade leave them untouched? They wouldn't be reachable through the grammar any longer. Should pg_upgrade delete them? I'm generally not in favor of deleting user data as part of an upgrade, and rows in the catalog tables corresponding to custom postfix operators are sort of user data, if you squint and look at them just right. Thoughts?

Attachments:

v1-0001-Adding-keyword-alias-test.patchapplication/octet-stream; name=v1-0001-Adding-keyword-alias-test.patch; x-unix-mode=0644Download
From 63ac8e1e468293698a0867287ef03e7acdc4e085 Mon Sep 17 00:00:00 2001
From: Mark Dilger <mark.dilger@enterprisedb.com>
Date: Tue, 30 Jun 2020 10:30:53 -0700
Subject: [PATCH v1 1/2] Adding keyword alias test.

This new test checks, for each keyword, whether it can be used as
a bare column alias (without the AS keyword.)  The main purpose of
this test is to detect changes in the list of keywords that can be
used thus.
---
 src/test/regress/expected/as.out   | 5253 ++++++++++++++++++++++++++++
 src/test/regress/parallel_schedule |    2 +-
 src/test/regress/serial_schedule   |    2 +
 src/test/regress/sql/as.sql        | 1029 ++++++
 4 files changed, 6285 insertions(+), 1 deletion(-)
 create mode 100644 src/test/regress/expected/as.out
 create mode 100644 src/test/regress/sql/as.sql

diff --git a/src/test/regress/expected/as.out b/src/test/regress/expected/as.out
new file mode 100644
index 0000000000..697bfb5ca4
--- /dev/null
+++ b/src/test/regress/expected/as.out
@@ -0,0 +1,5253 @@
+-- COL_NAME_KEYWORD keywords
+SELECT 1234 AS between;
+ between 
+---------
+    1234
+(1 row)
+
+SELECT 1234 between;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 1234 between;
+                           ^
+SELECT 1234 AS bigint;
+ bigint 
+--------
+   1234
+(1 row)
+
+SELECT 1234 bigint;
+ERROR:  syntax error at or near "bigint"
+LINE 1: SELECT 1234 bigint;
+                    ^
+SELECT 1234 AS bit;
+ bit  
+------
+ 1234
+(1 row)
+
+SELECT 1234 bit;
+ERROR:  syntax error at or near "bit"
+LINE 1: SELECT 1234 bit;
+                    ^
+SELECT 1234 AS boolean;
+ boolean 
+---------
+    1234
+(1 row)
+
+SELECT 1234 boolean;
+ERROR:  syntax error at or near "boolean"
+LINE 1: SELECT 1234 boolean;
+                    ^
+SELECT 1234 AS char;
+ char 
+------
+ 1234
+(1 row)
+
+SELECT 1234 char;
+ERROR:  syntax error at or near "char"
+LINE 1: SELECT 1234 char;
+                    ^
+SELECT 1234 AS character;
+ character 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 character;
+ERROR:  syntax error at or near "character"
+LINE 1: SELECT 1234 character;
+                    ^
+SELECT 1234 AS coalesce;
+ coalesce 
+----------
+     1234
+(1 row)
+
+SELECT 1234 coalesce;
+ERROR:  syntax error at or near "coalesce"
+LINE 1: SELECT 1234 coalesce;
+                    ^
+SELECT 1234 AS dec;
+ dec  
+------
+ 1234
+(1 row)
+
+SELECT 1234 dec;
+ERROR:  syntax error at or near "dec"
+LINE 1: SELECT 1234 dec;
+                    ^
+SELECT 1234 AS decimal;
+ decimal 
+---------
+    1234
+(1 row)
+
+SELECT 1234 decimal;
+ERROR:  syntax error at or near "decimal"
+LINE 1: SELECT 1234 decimal;
+                    ^
+SELECT 1234 AS exists;
+ exists 
+--------
+   1234
+(1 row)
+
+SELECT 1234 exists;
+ERROR:  syntax error at or near "exists"
+LINE 1: SELECT 1234 exists;
+                    ^
+SELECT 1234 AS extract;
+ extract 
+---------
+    1234
+(1 row)
+
+SELECT 1234 extract;
+ERROR:  syntax error at or near "extract"
+LINE 1: SELECT 1234 extract;
+                    ^
+SELECT 1234 AS float;
+ float 
+-------
+  1234
+(1 row)
+
+SELECT 1234 float;
+ERROR:  syntax error at or near "float"
+LINE 1: SELECT 1234 float;
+                    ^
+SELECT 1234 AS greatest;
+ greatest 
+----------
+     1234
+(1 row)
+
+SELECT 1234 greatest;
+ERROR:  syntax error at or near "greatest"
+LINE 1: SELECT 1234 greatest;
+                    ^
+SELECT 1234 AS grouping;
+ grouping 
+----------
+     1234
+(1 row)
+
+SELECT 1234 grouping;
+ERROR:  syntax error at or near "grouping"
+LINE 1: SELECT 1234 grouping;
+                    ^
+SELECT 1234 AS inout;
+ inout 
+-------
+  1234
+(1 row)
+
+SELECT 1234 inout;
+ERROR:  syntax error at or near "inout"
+LINE 1: SELECT 1234 inout;
+                    ^
+SELECT 1234 AS int;
+ int  
+------
+ 1234
+(1 row)
+
+SELECT 1234 int;
+ERROR:  syntax error at or near "int"
+LINE 1: SELECT 1234 int;
+                    ^
+SELECT 1234 AS integer;
+ integer 
+---------
+    1234
+(1 row)
+
+SELECT 1234 integer;
+ERROR:  syntax error at or near "integer"
+LINE 1: SELECT 1234 integer;
+                    ^
+SELECT 1234 AS interval;
+ interval 
+----------
+     1234
+(1 row)
+
+SELECT 1234 interval;
+ERROR:  syntax error at or near "interval"
+LINE 1: SELECT 1234 interval;
+                    ^
+SELECT 1234 AS least;
+ least 
+-------
+  1234
+(1 row)
+
+SELECT 1234 least;
+ERROR:  syntax error at or near "least"
+LINE 1: SELECT 1234 least;
+                    ^
+SELECT 1234 AS national;
+ national 
+----------
+     1234
+(1 row)
+
+SELECT 1234 national;
+ERROR:  syntax error at or near "national"
+LINE 1: SELECT 1234 national;
+                    ^
+SELECT 1234 AS nchar;
+ nchar 
+-------
+  1234
+(1 row)
+
+SELECT 1234 nchar;
+ERROR:  syntax error at or near "nchar"
+LINE 1: SELECT 1234 nchar;
+                    ^
+SELECT 1234 AS none;
+ none 
+------
+ 1234
+(1 row)
+
+SELECT 1234 none;
+ERROR:  syntax error at or near "none"
+LINE 1: SELECT 1234 none;
+                    ^
+SELECT 1234 AS normalize;
+ normalize 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 normalize;
+ERROR:  syntax error at or near "normalize"
+LINE 1: SELECT 1234 normalize;
+                    ^
+SELECT 1234 AS nullif;
+ nullif 
+--------
+   1234
+(1 row)
+
+SELECT 1234 nullif;
+ERROR:  syntax error at or near "nullif"
+LINE 1: SELECT 1234 nullif;
+                    ^
+SELECT 1234 AS numeric;
+ numeric 
+---------
+    1234
+(1 row)
+
+SELECT 1234 numeric;
+ERROR:  syntax error at or near "numeric"
+LINE 1: SELECT 1234 numeric;
+                    ^
+SELECT 1234 AS out;
+ out  
+------
+ 1234
+(1 row)
+
+SELECT 1234 out;
+ERROR:  syntax error at or near "out"
+LINE 1: SELECT 1234 out;
+                    ^
+SELECT 1234 AS overlay;
+ overlay 
+---------
+    1234
+(1 row)
+
+SELECT 1234 overlay;
+ERROR:  syntax error at or near "overlay"
+LINE 1: SELECT 1234 overlay;
+                    ^
+SELECT 1234 AS position;
+ position 
+----------
+     1234
+(1 row)
+
+SELECT 1234 position;
+ERROR:  syntax error at or near "position"
+LINE 1: SELECT 1234 position;
+                    ^
+SELECT 1234 AS precision;
+ precision 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 precision;
+ERROR:  syntax error at or near "precision"
+LINE 1: SELECT 1234 precision;
+                    ^
+SELECT 1234 AS real;
+ real 
+------
+ 1234
+(1 row)
+
+SELECT 1234 real;
+ERROR:  syntax error at or near "real"
+LINE 1: SELECT 1234 real;
+                    ^
+SELECT 1234 AS row;
+ row  
+------
+ 1234
+(1 row)
+
+SELECT 1234 row;
+ERROR:  syntax error at or near "row"
+LINE 1: SELECT 1234 row;
+                    ^
+SELECT 1234 AS setof;
+ setof 
+-------
+  1234
+(1 row)
+
+SELECT 1234 setof;
+ERROR:  syntax error at or near "setof"
+LINE 1: SELECT 1234 setof;
+                    ^
+SELECT 1234 AS smallint;
+ smallint 
+----------
+     1234
+(1 row)
+
+SELECT 1234 smallint;
+ERROR:  syntax error at or near "smallint"
+LINE 1: SELECT 1234 smallint;
+                    ^
+SELECT 1234 AS substring;
+ substring 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 substring;
+ERROR:  syntax error at or near "substring"
+LINE 1: SELECT 1234 substring;
+                    ^
+SELECT 1234 AS time;
+ time 
+------
+ 1234
+(1 row)
+
+SELECT 1234 time;
+ERROR:  syntax error at or near "time"
+LINE 1: SELECT 1234 time;
+                    ^
+SELECT 1234 AS timestamp;
+ timestamp 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 timestamp;
+ERROR:  syntax error at or near "timestamp"
+LINE 1: SELECT 1234 timestamp;
+                    ^
+SELECT 1234 AS treat;
+ treat 
+-------
+  1234
+(1 row)
+
+SELECT 1234 treat;
+ERROR:  syntax error at or near "treat"
+LINE 1: SELECT 1234 treat;
+                    ^
+SELECT 1234 AS trim;
+ trim 
+------
+ 1234
+(1 row)
+
+SELECT 1234 trim;
+ERROR:  syntax error at or near "trim"
+LINE 1: SELECT 1234 trim;
+                    ^
+SELECT 1234 AS values;
+ values 
+--------
+   1234
+(1 row)
+
+SELECT 1234 values;
+ERROR:  syntax error at or near "values"
+LINE 1: SELECT 1234 values;
+                    ^
+SELECT 1234 AS varchar;
+ varchar 
+---------
+    1234
+(1 row)
+
+SELECT 1234 varchar;
+ERROR:  syntax error at or near "varchar"
+LINE 1: SELECT 1234 varchar;
+                    ^
+SELECT 1234 AS xmlattributes;
+ xmlattributes 
+---------------
+          1234
+(1 row)
+
+SELECT 1234 xmlattributes;
+ERROR:  syntax error at or near "xmlattributes"
+LINE 1: SELECT 1234 xmlattributes;
+                    ^
+SELECT 1234 AS xmlconcat;
+ xmlconcat 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 xmlconcat;
+ERROR:  syntax error at or near "xmlconcat"
+LINE 1: SELECT 1234 xmlconcat;
+                    ^
+SELECT 1234 AS xmlelement;
+ xmlelement 
+------------
+       1234
+(1 row)
+
+SELECT 1234 xmlelement;
+ERROR:  syntax error at or near "xmlelement"
+LINE 1: SELECT 1234 xmlelement;
+                    ^
+SELECT 1234 AS xmlexists;
+ xmlexists 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 xmlexists;
+ERROR:  syntax error at or near "xmlexists"
+LINE 1: SELECT 1234 xmlexists;
+                    ^
+SELECT 1234 AS xmlforest;
+ xmlforest 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 xmlforest;
+ERROR:  syntax error at or near "xmlforest"
+LINE 1: SELECT 1234 xmlforest;
+                    ^
+SELECT 1234 AS xmlnamespaces;
+ xmlnamespaces 
+---------------
+          1234
+(1 row)
+
+SELECT 1234 xmlnamespaces;
+ERROR:  syntax error at or near "xmlnamespaces"
+LINE 1: SELECT 1234 xmlnamespaces;
+                    ^
+SELECT 1234 AS xmlparse;
+ xmlparse 
+----------
+     1234
+(1 row)
+
+SELECT 1234 xmlparse;
+ERROR:  syntax error at or near "xmlparse"
+LINE 1: SELECT 1234 xmlparse;
+                    ^
+SELECT 1234 AS xmlpi;
+ xmlpi 
+-------
+  1234
+(1 row)
+
+SELECT 1234 xmlpi;
+ERROR:  syntax error at or near "xmlpi"
+LINE 1: SELECT 1234 xmlpi;
+                    ^
+SELECT 1234 AS xmlroot;
+ xmlroot 
+---------
+    1234
+(1 row)
+
+SELECT 1234 xmlroot;
+ERROR:  syntax error at or near "xmlroot"
+LINE 1: SELECT 1234 xmlroot;
+                    ^
+SELECT 1234 AS xmlserialize;
+ xmlserialize 
+--------------
+         1234
+(1 row)
+
+SELECT 1234 xmlserialize;
+ERROR:  syntax error at or near "xmlserialize"
+LINE 1: SELECT 1234 xmlserialize;
+                    ^
+SELECT 1234 AS xmltable;
+ xmltable 
+----------
+     1234
+(1 row)
+
+SELECT 1234 xmltable;
+ERROR:  syntax error at or near "xmltable"
+LINE 1: SELECT 1234 xmltable;
+                    ^
+-- PL keywords
+SELECT 1234 AS alias;
+ alias 
+-------
+  1234
+(1 row)
+
+SELECT 1234 alias;
+ alias 
+-------
+  1234
+(1 row)
+
+SELECT 1234 AS assert;
+ assert 
+--------
+   1234
+(1 row)
+
+SELECT 1234 assert;
+ assert 
+--------
+   1234
+(1 row)
+
+SELECT 1234 AS auto;
+ auto 
+------
+ 1234
+(1 row)
+
+SELECT 1234 auto;
+ auto 
+------
+ 1234
+(1 row)
+
+SELECT 1234 AS bool;
+ bool 
+------
+ 1234
+(1 row)
+
+SELECT 1234 bool;
+ bool 
+------
+ 1234
+(1 row)
+
+SELECT 1234 AS column_name;
+ column_name 
+-------------
+        1234
+(1 row)
+
+SELECT 1234 column_name;
+ column_name 
+-------------
+        1234
+(1 row)
+
+SELECT 1234 AS const;
+ const 
+-------
+  1234
+(1 row)
+
+SELECT 1234 const;
+ const 
+-------
+  1234
+(1 row)
+
+SELECT 1234 AS constant;
+ constant 
+----------
+     1234
+(1 row)
+
+SELECT 1234 constant;
+ constant 
+----------
+     1234
+(1 row)
+
+SELECT 1234 AS constraint_name;
+ constraint_name 
+-----------------
+            1234
+(1 row)
+
+SELECT 1234 constraint_name;
+ constraint_name 
+-----------------
+            1234
+(1 row)
+
+SELECT 1234 AS datatype;
+ datatype 
+----------
+     1234
+(1 row)
+
+SELECT 1234 datatype;
+ datatype 
+----------
+     1234
+(1 row)
+
+SELECT 1234 AS debug;
+ debug 
+-------
+  1234
+(1 row)
+
+SELECT 1234 debug;
+ debug 
+-------
+  1234
+(1 row)
+
+SELECT 1234 AS detail;
+ detail 
+--------
+   1234
+(1 row)
+
+SELECT 1234 detail;
+ detail 
+--------
+   1234
+(1 row)
+
+SELECT 1234 AS diagnostics;
+ diagnostics 
+-------------
+        1234
+(1 row)
+
+SELECT 1234 diagnostics;
+ diagnostics 
+-------------
+        1234
+(1 row)
+
+SELECT 1234 AS dump;
+ dump 
+------
+ 1234
+(1 row)
+
+SELECT 1234 dump;
+ dump 
+------
+ 1234
+(1 row)
+
+SELECT 1234 AS elseif;
+ elseif 
+--------
+   1234
+(1 row)
+
+SELECT 1234 elseif;
+ elseif 
+--------
+   1234
+(1 row)
+
+SELECT 1234 AS elsif;
+ elsif 
+-------
+  1234
+(1 row)
+
+SELECT 1234 elsif;
+ elsif 
+-------
+  1234
+(1 row)
+
+SELECT 1234 AS errcode;
+ errcode 
+---------
+    1234
+(1 row)
+
+SELECT 1234 errcode;
+ errcode 
+---------
+    1234
+(1 row)
+
+SELECT 1234 AS error;
+ error 
+-------
+  1234
+(1 row)
+
+SELECT 1234 error;
+ error 
+-------
+  1234
+(1 row)
+
+SELECT 1234 AS exception;
+ exception 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 exception;
+ exception 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 AS exit;
+ exit 
+------
+ 1234
+(1 row)
+
+SELECT 1234 exit;
+ exit 
+------
+ 1234
+(1 row)
+
+SELECT 1234 AS extern;
+ extern 
+--------
+   1234
+(1 row)
+
+SELECT 1234 extern;
+ extern 
+--------
+   1234
+(1 row)
+
+SELECT 1234 AS foreach;
+ foreach 
+---------
+    1234
+(1 row)
+
+SELECT 1234 foreach;
+ foreach 
+---------
+    1234
+(1 row)
+
+SELECT 1234 AS get;
+ get  
+------
+ 1234
+(1 row)
+
+SELECT 1234 get;
+ get  
+------
+ 1234
+(1 row)
+
+SELECT 1234 AS hint;
+ hint 
+------
+ 1234
+(1 row)
+
+SELECT 1234 hint;
+ hint 
+------
+ 1234
+(1 row)
+
+SELECT 1234 AS info;
+ info 
+------
+ 1234
+(1 row)
+
+SELECT 1234 info;
+ info 
+------
+ 1234
+(1 row)
+
+SELECT 1234 AS log;
+ log  
+------
+ 1234
+(1 row)
+
+SELECT 1234 log;
+ log  
+------
+ 1234
+(1 row)
+
+SELECT 1234 AS long;
+ long 
+------
+ 1234
+(1 row)
+
+SELECT 1234 long;
+ long 
+------
+ 1234
+(1 row)
+
+SELECT 1234 AS loop;
+ loop 
+------
+ 1234
+(1 row)
+
+SELECT 1234 loop;
+ loop 
+------
+ 1234
+(1 row)
+
+SELECT 1234 AS message;
+ message 
+---------
+    1234
+(1 row)
+
+SELECT 1234 message;
+ message 
+---------
+    1234
+(1 row)
+
+SELECT 1234 AS message_text;
+ message_text 
+--------------
+         1234
+(1 row)
+
+SELECT 1234 message_text;
+ message_text 
+--------------
+         1234
+(1 row)
+
+SELECT 1234 AS notice;
+ notice 
+--------
+   1234
+(1 row)
+
+SELECT 1234 notice;
+ notice 
+--------
+   1234
+(1 row)
+
+SELECT 1234 AS open;
+ open 
+------
+ 1234
+(1 row)
+
+SELECT 1234 open;
+ open 
+------
+ 1234
+(1 row)
+
+SELECT 1234 AS perform;
+ perform 
+---------
+    1234
+(1 row)
+
+SELECT 1234 perform;
+ perform 
+---------
+    1234
+(1 row)
+
+SELECT 1234 AS pg_context;
+ pg_context 
+------------
+       1234
+(1 row)
+
+SELECT 1234 pg_context;
+ pg_context 
+------------
+       1234
+(1 row)
+
+SELECT 1234 AS pg_datatype_name;
+ pg_datatype_name 
+------------------
+             1234
+(1 row)
+
+SELECT 1234 pg_datatype_name;
+ pg_datatype_name 
+------------------
+             1234
+(1 row)
+
+SELECT 1234 AS pg_exception_context;
+ pg_exception_context 
+----------------------
+                 1234
+(1 row)
+
+SELECT 1234 pg_exception_context;
+ pg_exception_context 
+----------------------
+                 1234
+(1 row)
+
+SELECT 1234 AS pg_exception_detail;
+ pg_exception_detail 
+---------------------
+                1234
+(1 row)
+
+SELECT 1234 pg_exception_detail;
+ pg_exception_detail 
+---------------------
+                1234
+(1 row)
+
+SELECT 1234 AS pg_exception_hint;
+ pg_exception_hint 
+-------------------
+              1234
+(1 row)
+
+SELECT 1234 pg_exception_hint;
+ pg_exception_hint 
+-------------------
+              1234
+(1 row)
+
+SELECT 1234 AS print_strict_params;
+ print_strict_params 
+---------------------
+                1234
+(1 row)
+
+SELECT 1234 print_strict_params;
+ print_strict_params 
+---------------------
+                1234
+(1 row)
+
+SELECT 1234 AS query;
+ query 
+-------
+  1234
+(1 row)
+
+SELECT 1234 query;
+ query 
+-------
+  1234
+(1 row)
+
+SELECT 1234 AS raise;
+ raise 
+-------
+  1234
+(1 row)
+
+SELECT 1234 raise;
+ raise 
+-------
+  1234
+(1 row)
+
+SELECT 1234 AS register;
+ register 
+----------
+     1234
+(1 row)
+
+SELECT 1234 register;
+ register 
+----------
+     1234
+(1 row)
+
+SELECT 1234 AS return;
+ return 
+--------
+   1234
+(1 row)
+
+SELECT 1234 return;
+ return 
+--------
+   1234
+(1 row)
+
+SELECT 1234 AS returned_sqlstate;
+ returned_sqlstate 
+-------------------
+              1234
+(1 row)
+
+SELECT 1234 returned_sqlstate;
+ returned_sqlstate 
+-------------------
+              1234
+(1 row)
+
+SELECT 1234 AS reverse;
+ reverse 
+---------
+    1234
+(1 row)
+
+SELECT 1234 reverse;
+ reverse 
+---------
+    1234
+(1 row)
+
+SELECT 1234 AS row_count;
+ row_count 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 row_count;
+ row_count 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 AS rowtype;
+ rowtype 
+---------
+    1234
+(1 row)
+
+SELECT 1234 rowtype;
+ rowtype 
+---------
+    1234
+(1 row)
+
+SELECT 1234 AS schema_name;
+ schema_name 
+-------------
+        1234
+(1 row)
+
+SELECT 1234 schema_name;
+ schema_name 
+-------------
+        1234
+(1 row)
+
+SELECT 1234 AS short;
+ short 
+-------
+  1234
+(1 row)
+
+SELECT 1234 short;
+ short 
+-------
+  1234
+(1 row)
+
+SELECT 1234 AS signed;
+ signed 
+--------
+   1234
+(1 row)
+
+SELECT 1234 signed;
+ signed 
+--------
+   1234
+(1 row)
+
+SELECT 1234 AS slice;
+ slice 
+-------
+  1234
+(1 row)
+
+SELECT 1234 slice;
+ slice 
+-------
+  1234
+(1 row)
+
+SELECT 1234 AS sqlstate;
+ sqlstate 
+----------
+     1234
+(1 row)
+
+SELECT 1234 sqlstate;
+ sqlstate 
+----------
+     1234
+(1 row)
+
+SELECT 1234 AS stacked;
+ stacked 
+---------
+    1234
+(1 row)
+
+SELECT 1234 stacked;
+ stacked 
+---------
+    1234
+(1 row)
+
+SELECT 1234 AS static;
+ static 
+--------
+   1234
+(1 row)
+
+SELECT 1234 static;
+ static 
+--------
+   1234
+(1 row)
+
+SELECT 1234 AS struct;
+ struct 
+--------
+   1234
+(1 row)
+
+SELECT 1234 struct;
+ struct 
+--------
+   1234
+(1 row)
+
+SELECT 1234 AS table_name;
+ table_name 
+------------
+       1234
+(1 row)
+
+SELECT 1234 table_name;
+ table_name 
+------------
+       1234
+(1 row)
+
+SELECT 1234 AS typedef;
+ typedef 
+---------
+    1234
+(1 row)
+
+SELECT 1234 typedef;
+ typedef 
+---------
+    1234
+(1 row)
+
+SELECT 1234 AS unsigned;
+ unsigned 
+----------
+     1234
+(1 row)
+
+SELECT 1234 unsigned;
+ unsigned 
+----------
+     1234
+(1 row)
+
+SELECT 1234 AS use_column;
+ use_column 
+------------
+       1234
+(1 row)
+
+SELECT 1234 use_column;
+ use_column 
+------------
+       1234
+(1 row)
+
+SELECT 1234 AS use_variable;
+ use_variable 
+--------------
+         1234
+(1 row)
+
+SELECT 1234 use_variable;
+ use_variable 
+--------------
+         1234
+(1 row)
+
+SELECT 1234 AS variable_conflict;
+ variable_conflict 
+-------------------
+              1234
+(1 row)
+
+SELECT 1234 variable_conflict;
+ variable_conflict 
+-------------------
+              1234
+(1 row)
+
+SELECT 1234 AS warning;
+ warning 
+---------
+    1234
+(1 row)
+
+SELECT 1234 warning;
+ warning 
+---------
+    1234
+(1 row)
+
+SELECT 1234 AS while;
+ while 
+-------
+  1234
+(1 row)
+
+SELECT 1234 while;
+ while 
+-------
+  1234
+(1 row)
+
+-- RESERVED_KEYWORD keywords
+SELECT 1234 AS all;
+ all  
+------
+ 1234
+(1 row)
+
+SELECT 1234 all;
+ERROR:  syntax error at or near "all"
+LINE 1: SELECT 1234 all;
+                    ^
+SELECT 1234 AS analyse;
+ analyse 
+---------
+    1234
+(1 row)
+
+SELECT 1234 analyse;
+ERROR:  syntax error at or near "analyse"
+LINE 1: SELECT 1234 analyse;
+                    ^
+SELECT 1234 AS analyze;
+ analyze 
+---------
+    1234
+(1 row)
+
+SELECT 1234 analyze;
+ERROR:  syntax error at or near "analyze"
+LINE 1: SELECT 1234 analyze;
+                    ^
+SELECT 1234 AS and;
+ and  
+------
+ 1234
+(1 row)
+
+SELECT 1234 and;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 1234 and;
+                       ^
+SELECT 1234 AS any;
+ any  
+------
+ 1234
+(1 row)
+
+SELECT 1234 any;
+ERROR:  syntax error at or near "any"
+LINE 1: SELECT 1234 any;
+                    ^
+SELECT 1234 AS array;
+ array 
+-------
+  1234
+(1 row)
+
+SELECT 1234 array;
+ERROR:  syntax error at or near "array"
+LINE 1: SELECT 1234 array;
+                    ^
+SELECT 1234 AS as;
+  as  
+------
+ 1234
+(1 row)
+
+SELECT 1234 as;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 1234 as;
+                      ^
+SELECT 1234 AS asc;
+ asc  
+------
+ 1234
+(1 row)
+
+SELECT 1234 asc;
+ERROR:  syntax error at or near "asc"
+LINE 1: SELECT 1234 asc;
+                    ^
+SELECT 1234 AS asymmetric;
+ asymmetric 
+------------
+       1234
+(1 row)
+
+SELECT 1234 asymmetric;
+ERROR:  syntax error at or near "asymmetric"
+LINE 1: SELECT 1234 asymmetric;
+                    ^
+SELECT 1234 AS both;
+ both 
+------
+ 1234
+(1 row)
+
+SELECT 1234 both;
+ERROR:  syntax error at or near "both"
+LINE 1: SELECT 1234 both;
+                    ^
+SELECT 1234 AS case;
+ case 
+------
+ 1234
+(1 row)
+
+SELECT 1234 case;
+ERROR:  syntax error at or near "case"
+LINE 1: SELECT 1234 case;
+                    ^
+SELECT 1234 AS cast;
+ cast 
+------
+ 1234
+(1 row)
+
+SELECT 1234 cast;
+ERROR:  syntax error at or near "cast"
+LINE 1: SELECT 1234 cast;
+                    ^
+SELECT 1234 AS check;
+ check 
+-------
+  1234
+(1 row)
+
+SELECT 1234 check;
+ERROR:  syntax error at or near "check"
+LINE 1: SELECT 1234 check;
+                    ^
+SELECT 1234 AS collate;
+ collate 
+---------
+    1234
+(1 row)
+
+SELECT 1234 collate;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 1234 collate;
+                           ^
+SELECT 1234 AS column;
+ column 
+--------
+   1234
+(1 row)
+
+SELECT 1234 column;
+ERROR:  syntax error at or near "column"
+LINE 1: SELECT 1234 column;
+                    ^
+SELECT 1234 AS constraint;
+ constraint 
+------------
+       1234
+(1 row)
+
+SELECT 1234 constraint;
+ERROR:  syntax error at or near "constraint"
+LINE 1: SELECT 1234 constraint;
+                    ^
+SELECT 1234 AS create;
+ create 
+--------
+   1234
+(1 row)
+
+SELECT 1234 create;
+ERROR:  syntax error at or near "create"
+LINE 1: SELECT 1234 create;
+                    ^
+SELECT 1234 AS current_catalog;
+ current_catalog 
+-----------------
+            1234
+(1 row)
+
+SELECT 1234 current_catalog;
+ERROR:  syntax error at or near "current_catalog"
+LINE 1: SELECT 1234 current_catalog;
+                    ^
+SELECT 1234 AS current_date;
+ current_date 
+--------------
+         1234
+(1 row)
+
+SELECT 1234 current_date;
+ERROR:  syntax error at or near "current_date"
+LINE 1: SELECT 1234 current_date;
+                    ^
+SELECT 1234 AS current_role;
+ current_role 
+--------------
+         1234
+(1 row)
+
+SELECT 1234 current_role;
+ERROR:  syntax error at or near "current_role"
+LINE 1: SELECT 1234 current_role;
+                    ^
+SELECT 1234 AS current_time;
+ current_time 
+--------------
+         1234
+(1 row)
+
+SELECT 1234 current_time;
+ERROR:  syntax error at or near "current_time"
+LINE 1: SELECT 1234 current_time;
+                    ^
+SELECT 1234 AS current_timestamp;
+ current_timestamp 
+-------------------
+              1234
+(1 row)
+
+SELECT 1234 current_timestamp;
+ERROR:  syntax error at or near "current_timestamp"
+LINE 1: SELECT 1234 current_timestamp;
+                    ^
+SELECT 1234 AS current_user;
+ current_user 
+--------------
+         1234
+(1 row)
+
+SELECT 1234 current_user;
+ERROR:  syntax error at or near "current_user"
+LINE 1: SELECT 1234 current_user;
+                    ^
+SELECT 1234 AS default;
+ default 
+---------
+    1234
+(1 row)
+
+SELECT 1234 default;
+ERROR:  syntax error at or near "default"
+LINE 1: SELECT 1234 default;
+                    ^
+SELECT 1234 AS deferrable;
+ deferrable 
+------------
+       1234
+(1 row)
+
+SELECT 1234 deferrable;
+ERROR:  syntax error at or near "deferrable"
+LINE 1: SELECT 1234 deferrable;
+                    ^
+SELECT 1234 AS desc;
+ desc 
+------
+ 1234
+(1 row)
+
+SELECT 1234 desc;
+ERROR:  syntax error at or near "desc"
+LINE 1: SELECT 1234 desc;
+                    ^
+SELECT 1234 AS distinct;
+ distinct 
+----------
+     1234
+(1 row)
+
+SELECT 1234 distinct;
+ERROR:  syntax error at or near "distinct"
+LINE 1: SELECT 1234 distinct;
+                    ^
+SELECT 1234 AS do;
+  do  
+------
+ 1234
+(1 row)
+
+SELECT 1234 do;
+ERROR:  syntax error at or near "do"
+LINE 1: SELECT 1234 do;
+                    ^
+SELECT 1234 AS else;
+ else 
+------
+ 1234
+(1 row)
+
+SELECT 1234 else;
+ERROR:  syntax error at or near "else"
+LINE 1: SELECT 1234 else;
+                    ^
+SELECT 1234 AS end;
+ end  
+------
+ 1234
+(1 row)
+
+SELECT 1234 end;
+ERROR:  syntax error at or near "end"
+LINE 1: SELECT 1234 end;
+                    ^
+SELECT 1234 AS except;
+ except 
+--------
+   1234
+(1 row)
+
+SELECT 1234 except;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 1234 except;
+                          ^
+SELECT 1234 AS false;
+ false 
+-------
+  1234
+(1 row)
+
+SELECT 1234 false;
+ERROR:  syntax error at or near "false"
+LINE 1: SELECT 1234 false;
+                    ^
+SELECT 1234 AS fetch;
+ fetch 
+-------
+  1234
+(1 row)
+
+SELECT 1234 fetch;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 1234 fetch;
+                         ^
+SELECT 1234 AS for;
+ for  
+------
+ 1234
+(1 row)
+
+SELECT 1234 for;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 1234 for;
+                       ^
+SELECT 1234 AS foreign;
+ foreign 
+---------
+    1234
+(1 row)
+
+SELECT 1234 foreign;
+ERROR:  syntax error at or near "foreign"
+LINE 1: SELECT 1234 foreign;
+                    ^
+SELECT 1234 AS from;
+ from 
+------
+ 1234
+(1 row)
+
+SELECT 1234 from;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 1234 from;
+                        ^
+SELECT 1234 AS grant;
+ grant 
+-------
+  1234
+(1 row)
+
+SELECT 1234 grant;
+ERROR:  syntax error at or near "grant"
+LINE 1: SELECT 1234 grant;
+                    ^
+SELECT 1234 AS group;
+ group 
+-------
+  1234
+(1 row)
+
+SELECT 1234 group;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 1234 group;
+                         ^
+SELECT 1234 AS having;
+ having 
+--------
+   1234
+(1 row)
+
+SELECT 1234 having;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 1234 having;
+                          ^
+SELECT 1234 AS in;
+  in  
+------
+ 1234
+(1 row)
+
+SELECT 1234 in;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 1234 in;
+                      ^
+SELECT 1234 AS initially;
+ initially 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 initially;
+ERROR:  syntax error at or near "initially"
+LINE 1: SELECT 1234 initially;
+                    ^
+SELECT 1234 AS intersect;
+ intersect 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 intersect;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 1234 intersect;
+                             ^
+SELECT 1234 AS into;
+ into 
+------
+ 1234
+(1 row)
+
+SELECT 1234 into;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 1234 into;
+                        ^
+SELECT 1234 AS lateral;
+ lateral 
+---------
+    1234
+(1 row)
+
+SELECT 1234 lateral;
+ERROR:  syntax error at or near "lateral"
+LINE 1: SELECT 1234 lateral;
+                    ^
+SELECT 1234 AS leading;
+ leading 
+---------
+    1234
+(1 row)
+
+SELECT 1234 leading;
+ERROR:  syntax error at or near "leading"
+LINE 1: SELECT 1234 leading;
+                    ^
+SELECT 1234 AS limit;
+ limit 
+-------
+  1234
+(1 row)
+
+SELECT 1234 limit;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 1234 limit;
+                         ^
+SELECT 1234 AS localtime;
+ localtime 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 localtime;
+ERROR:  syntax error at or near "localtime"
+LINE 1: SELECT 1234 localtime;
+                    ^
+SELECT 1234 AS localtimestamp;
+ localtimestamp 
+----------------
+           1234
+(1 row)
+
+SELECT 1234 localtimestamp;
+ERROR:  syntax error at or near "localtimestamp"
+LINE 1: SELECT 1234 localtimestamp;
+                    ^
+SELECT 1234 AS not;
+ not  
+------
+ 1234
+(1 row)
+
+SELECT 1234 not;
+ERROR:  syntax error at or near "not"
+LINE 1: SELECT 1234 not;
+                    ^
+SELECT 1234 AS null;
+ null 
+------
+ 1234
+(1 row)
+
+SELECT 1234 null;
+ERROR:  syntax error at or near "null"
+LINE 1: SELECT 1234 null;
+                    ^
+SELECT 1234 AS offset;
+ offset 
+--------
+   1234
+(1 row)
+
+SELECT 1234 offset;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 1234 offset;
+                          ^
+SELECT 1234 AS on;
+  on  
+------
+ 1234
+(1 row)
+
+SELECT 1234 on;
+ERROR:  syntax error at or near "on"
+LINE 1: SELECT 1234 on;
+                    ^
+SELECT 1234 AS only;
+ only 
+------
+ 1234
+(1 row)
+
+SELECT 1234 only;
+ERROR:  syntax error at or near "only"
+LINE 1: SELECT 1234 only;
+                    ^
+SELECT 1234 AS or;
+  or  
+------
+ 1234
+(1 row)
+
+SELECT 1234 or;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 1234 or;
+                      ^
+SELECT 1234 AS order;
+ order 
+-------
+  1234
+(1 row)
+
+SELECT 1234 order;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 1234 order;
+                         ^
+SELECT 1234 AS placing;
+ placing 
+---------
+    1234
+(1 row)
+
+SELECT 1234 placing;
+ERROR:  syntax error at or near "placing"
+LINE 1: SELECT 1234 placing;
+                    ^
+SELECT 1234 AS primary;
+ primary 
+---------
+    1234
+(1 row)
+
+SELECT 1234 primary;
+ERROR:  syntax error at or near "primary"
+LINE 1: SELECT 1234 primary;
+                    ^
+SELECT 1234 AS references;
+ references 
+------------
+       1234
+(1 row)
+
+SELECT 1234 references;
+ERROR:  syntax error at or near "references"
+LINE 1: SELECT 1234 references;
+                    ^
+SELECT 1234 AS returning;
+ returning 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 returning;
+ERROR:  syntax error at or near "returning"
+LINE 1: SELECT 1234 returning;
+                    ^
+SELECT 1234 AS select;
+ select 
+--------
+   1234
+(1 row)
+
+SELECT 1234 select;
+ERROR:  syntax error at or near "select"
+LINE 1: SELECT 1234 select;
+                    ^
+SELECT 1234 AS session_user;
+ session_user 
+--------------
+         1234
+(1 row)
+
+SELECT 1234 session_user;
+ERROR:  syntax error at or near "session_user"
+LINE 1: SELECT 1234 session_user;
+                    ^
+SELECT 1234 AS some;
+ some 
+------
+ 1234
+(1 row)
+
+SELECT 1234 some;
+ERROR:  syntax error at or near "some"
+LINE 1: SELECT 1234 some;
+                    ^
+SELECT 1234 AS symmetric;
+ symmetric 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 symmetric;
+ERROR:  syntax error at or near "symmetric"
+LINE 1: SELECT 1234 symmetric;
+                    ^
+SELECT 1234 AS table;
+ table 
+-------
+  1234
+(1 row)
+
+SELECT 1234 table;
+ERROR:  syntax error at or near "table"
+LINE 1: SELECT 1234 table;
+                    ^
+SELECT 1234 AS then;
+ then 
+------
+ 1234
+(1 row)
+
+SELECT 1234 then;
+ERROR:  syntax error at or near "then"
+LINE 1: SELECT 1234 then;
+                    ^
+SELECT 1234 AS to;
+  to  
+------
+ 1234
+(1 row)
+
+SELECT 1234 to;
+ERROR:  syntax error at or near "to"
+LINE 1: SELECT 1234 to;
+                    ^
+SELECT 1234 AS trailing;
+ trailing 
+----------
+     1234
+(1 row)
+
+SELECT 1234 trailing;
+ERROR:  syntax error at or near "trailing"
+LINE 1: SELECT 1234 trailing;
+                    ^
+SELECT 1234 AS true;
+ true 
+------
+ 1234
+(1 row)
+
+SELECT 1234 true;
+ERROR:  syntax error at or near "true"
+LINE 1: SELECT 1234 true;
+                    ^
+SELECT 1234 AS union;
+ union 
+-------
+  1234
+(1 row)
+
+SELECT 1234 union;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 1234 union;
+                         ^
+SELECT 1234 AS unique;
+ unique 
+--------
+   1234
+(1 row)
+
+SELECT 1234 unique;
+ERROR:  syntax error at or near "unique"
+LINE 1: SELECT 1234 unique;
+                    ^
+SELECT 1234 AS user;
+ user 
+------
+ 1234
+(1 row)
+
+SELECT 1234 user;
+ERROR:  syntax error at or near "user"
+LINE 1: SELECT 1234 user;
+                    ^
+SELECT 1234 AS using;
+ using 
+-------
+  1234
+(1 row)
+
+SELECT 1234 using;
+ERROR:  syntax error at or near "using"
+LINE 1: SELECT 1234 using;
+                    ^
+SELECT 1234 AS variadic;
+ variadic 
+----------
+     1234
+(1 row)
+
+SELECT 1234 variadic;
+ERROR:  syntax error at or near "variadic"
+LINE 1: SELECT 1234 variadic;
+                    ^
+SELECT 1234 AS when;
+ when 
+------
+ 1234
+(1 row)
+
+SELECT 1234 when;
+ERROR:  syntax error at or near "when"
+LINE 1: SELECT 1234 when;
+                    ^
+SELECT 1234 AS where;
+ where 
+-------
+  1234
+(1 row)
+
+SELECT 1234 where;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 1234 where;
+                         ^
+SELECT 1234 AS window;
+ window 
+--------
+   1234
+(1 row)
+
+SELECT 1234 window;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 1234 window;
+                          ^
+SELECT 1234 AS with;
+ with 
+------
+ 1234
+(1 row)
+
+SELECT 1234 with;
+ERROR:  syntax error at or near "with"
+LINE 1: SELECT 1234 with;
+                    ^
+-- TYPE_FUNC_NAME_KEYWORD keywords
+SELECT 1234 AS authorization;
+ authorization 
+---------------
+          1234
+(1 row)
+
+SELECT 1234 authorization;
+ERROR:  syntax error at or near "authorization"
+LINE 1: SELECT 1234 authorization;
+                    ^
+SELECT 1234 AS binary;
+ binary 
+--------
+   1234
+(1 row)
+
+SELECT 1234 binary;
+ERROR:  syntax error at or near "binary"
+LINE 1: SELECT 1234 binary;
+                    ^
+SELECT 1234 AS collation;
+ collation 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 collation;
+ERROR:  syntax error at or near "collation"
+LINE 1: SELECT 1234 collation;
+                    ^
+SELECT 1234 AS concurrently;
+ concurrently 
+--------------
+         1234
+(1 row)
+
+SELECT 1234 concurrently;
+ERROR:  syntax error at or near "concurrently"
+LINE 1: SELECT 1234 concurrently;
+                    ^
+SELECT 1234 AS cross;
+ cross 
+-------
+  1234
+(1 row)
+
+SELECT 1234 cross;
+ERROR:  syntax error at or near "cross"
+LINE 1: SELECT 1234 cross;
+                    ^
+SELECT 1234 AS current_schema;
+ current_schema 
+----------------
+           1234
+(1 row)
+
+SELECT 1234 current_schema;
+ERROR:  syntax error at or near "current_schema"
+LINE 1: SELECT 1234 current_schema;
+                    ^
+SELECT 1234 AS freeze;
+ freeze 
+--------
+   1234
+(1 row)
+
+SELECT 1234 freeze;
+ERROR:  syntax error at or near "freeze"
+LINE 1: SELECT 1234 freeze;
+                    ^
+SELECT 1234 AS full;
+ full 
+------
+ 1234
+(1 row)
+
+SELECT 1234 full;
+ERROR:  syntax error at or near "full"
+LINE 1: SELECT 1234 full;
+                    ^
+SELECT 1234 AS ilike;
+ ilike 
+-------
+  1234
+(1 row)
+
+SELECT 1234 ilike;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 1234 ilike;
+                         ^
+SELECT 1234 AS inner;
+ inner 
+-------
+  1234
+(1 row)
+
+SELECT 1234 inner;
+ERROR:  syntax error at or near "inner"
+LINE 1: SELECT 1234 inner;
+                    ^
+SELECT 1234 AS is;
+  is  
+------
+ 1234
+(1 row)
+
+SELECT 1234 is;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 1234 is;
+                      ^
+SELECT 1234 AS isnull;
+ isnull 
+--------
+   1234
+(1 row)
+
+SELECT 1234 isnull;
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT 1234 AS join;
+ join 
+------
+ 1234
+(1 row)
+
+SELECT 1234 join;
+ERROR:  syntax error at or near "join"
+LINE 1: SELECT 1234 join;
+                    ^
+SELECT 1234 AS left;
+ left 
+------
+ 1234
+(1 row)
+
+SELECT 1234 left;
+ERROR:  syntax error at or near "left"
+LINE 1: SELECT 1234 left;
+                    ^
+SELECT 1234 AS like;
+ like 
+------
+ 1234
+(1 row)
+
+SELECT 1234 like;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 1234 like;
+                        ^
+SELECT 1234 AS natural;
+ natural 
+---------
+    1234
+(1 row)
+
+SELECT 1234 natural;
+ERROR:  syntax error at or near "natural"
+LINE 1: SELECT 1234 natural;
+                    ^
+SELECT 1234 AS notnull;
+ notnull 
+---------
+    1234
+(1 row)
+
+SELECT 1234 notnull;
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT 1234 AS outer;
+ outer 
+-------
+  1234
+(1 row)
+
+SELECT 1234 outer;
+ERROR:  syntax error at or near "outer"
+LINE 1: SELECT 1234 outer;
+                    ^
+SELECT 1234 AS overlaps;
+ overlaps 
+----------
+     1234
+(1 row)
+
+SELECT 1234 overlaps;
+ERROR:  syntax error at or near "overlaps"
+LINE 1: SELECT 1234 overlaps;
+                    ^
+SELECT 1234 AS right;
+ right 
+-------
+  1234
+(1 row)
+
+SELECT 1234 right;
+ERROR:  syntax error at or near "right"
+LINE 1: SELECT 1234 right;
+                    ^
+SELECT 1234 AS similar;
+ similar 
+---------
+    1234
+(1 row)
+
+SELECT 1234 similar;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 1234 similar;
+                           ^
+SELECT 1234 AS tablesample;
+ tablesample 
+-------------
+        1234
+(1 row)
+
+SELECT 1234 tablesample;
+ERROR:  syntax error at or near "tablesample"
+LINE 1: SELECT 1234 tablesample;
+                    ^
+SELECT 1234 AS verbose;
+ verbose 
+---------
+    1234
+(1 row)
+
+SELECT 1234 verbose;
+ERROR:  syntax error at or near "verbose"
+LINE 1: SELECT 1234 verbose;
+                    ^
+-- UNRESERVED_KEYWORD keywords
+SELECT 1234 AS abort;
+ abort 
+-------
+  1234
+(1 row)
+
+SELECT 1234 abort;
+ERROR:  syntax error at or near "abort"
+LINE 1: SELECT 1234 abort;
+                    ^
+SELECT 1234 AS absolute;
+ absolute 
+----------
+     1234
+(1 row)
+
+SELECT 1234 absolute;
+ERROR:  syntax error at or near "absolute"
+LINE 1: SELECT 1234 absolute;
+                    ^
+SELECT 1234 AS access;
+ access 
+--------
+   1234
+(1 row)
+
+SELECT 1234 access;
+ERROR:  syntax error at or near "access"
+LINE 1: SELECT 1234 access;
+                    ^
+SELECT 1234 AS action;
+ action 
+--------
+   1234
+(1 row)
+
+SELECT 1234 action;
+ERROR:  syntax error at or near "action"
+LINE 1: SELECT 1234 action;
+                    ^
+SELECT 1234 AS add;
+ add  
+------
+ 1234
+(1 row)
+
+SELECT 1234 add;
+ERROR:  syntax error at or near "add"
+LINE 1: SELECT 1234 add;
+                    ^
+SELECT 1234 AS admin;
+ admin 
+-------
+  1234
+(1 row)
+
+SELECT 1234 admin;
+ERROR:  syntax error at or near "admin"
+LINE 1: SELECT 1234 admin;
+                    ^
+SELECT 1234 AS after;
+ after 
+-------
+  1234
+(1 row)
+
+SELECT 1234 after;
+ERROR:  syntax error at or near "after"
+LINE 1: SELECT 1234 after;
+                    ^
+SELECT 1234 AS aggregate;
+ aggregate 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 aggregate;
+ERROR:  syntax error at or near "aggregate"
+LINE 1: SELECT 1234 aggregate;
+                    ^
+SELECT 1234 AS also;
+ also 
+------
+ 1234
+(1 row)
+
+SELECT 1234 also;
+ERROR:  syntax error at or near "also"
+LINE 1: SELECT 1234 also;
+                    ^
+SELECT 1234 AS alter;
+ alter 
+-------
+  1234
+(1 row)
+
+SELECT 1234 alter;
+ERROR:  syntax error at or near "alter"
+LINE 1: SELECT 1234 alter;
+                    ^
+SELECT 1234 AS always;
+ always 
+--------
+   1234
+(1 row)
+
+SELECT 1234 always;
+ERROR:  syntax error at or near "always"
+LINE 1: SELECT 1234 always;
+                    ^
+SELECT 1234 AS assertion;
+ assertion 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 assertion;
+ERROR:  syntax error at or near "assertion"
+LINE 1: SELECT 1234 assertion;
+                    ^
+SELECT 1234 AS assignment;
+ assignment 
+------------
+       1234
+(1 row)
+
+SELECT 1234 assignment;
+ERROR:  syntax error at or near "assignment"
+LINE 1: SELECT 1234 assignment;
+                    ^
+SELECT 1234 AS at;
+  at  
+------
+ 1234
+(1 row)
+
+SELECT 1234 at;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 1234 at;
+                      ^
+SELECT 1234 AS attach;
+ attach 
+--------
+   1234
+(1 row)
+
+SELECT 1234 attach;
+ERROR:  syntax error at or near "attach"
+LINE 1: SELECT 1234 attach;
+                    ^
+SELECT 1234 AS attribute;
+ attribute 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 attribute;
+ERROR:  syntax error at or near "attribute"
+LINE 1: SELECT 1234 attribute;
+                    ^
+SELECT 1234 AS backward;
+ backward 
+----------
+     1234
+(1 row)
+
+SELECT 1234 backward;
+ERROR:  syntax error at or near "backward"
+LINE 1: SELECT 1234 backward;
+                    ^
+SELECT 1234 AS before;
+ before 
+--------
+   1234
+(1 row)
+
+SELECT 1234 before;
+ERROR:  syntax error at or near "before"
+LINE 1: SELECT 1234 before;
+                    ^
+SELECT 1234 AS begin;
+ begin 
+-------
+  1234
+(1 row)
+
+SELECT 1234 begin;
+ERROR:  syntax error at or near "begin"
+LINE 1: SELECT 1234 begin;
+                    ^
+SELECT 1234 AS by;
+  by  
+------
+ 1234
+(1 row)
+
+SELECT 1234 by;
+ERROR:  syntax error at or near "by"
+LINE 1: SELECT 1234 by;
+                    ^
+SELECT 1234 AS cache;
+ cache 
+-------
+  1234
+(1 row)
+
+SELECT 1234 cache;
+ERROR:  syntax error at or near "cache"
+LINE 1: SELECT 1234 cache;
+                    ^
+SELECT 1234 AS call;
+ call 
+------
+ 1234
+(1 row)
+
+SELECT 1234 call;
+ERROR:  syntax error at or near "call"
+LINE 1: SELECT 1234 call;
+                    ^
+SELECT 1234 AS called;
+ called 
+--------
+   1234
+(1 row)
+
+SELECT 1234 called;
+ERROR:  syntax error at or near "called"
+LINE 1: SELECT 1234 called;
+                    ^
+SELECT 1234 AS cascade;
+ cascade 
+---------
+    1234
+(1 row)
+
+SELECT 1234 cascade;
+ERROR:  syntax error at or near "cascade"
+LINE 1: SELECT 1234 cascade;
+                    ^
+SELECT 1234 AS cascaded;
+ cascaded 
+----------
+     1234
+(1 row)
+
+SELECT 1234 cascaded;
+ERROR:  syntax error at or near "cascaded"
+LINE 1: SELECT 1234 cascaded;
+                    ^
+SELECT 1234 AS catalog;
+ catalog 
+---------
+    1234
+(1 row)
+
+SELECT 1234 catalog;
+ERROR:  syntax error at or near "catalog"
+LINE 1: SELECT 1234 catalog;
+                    ^
+SELECT 1234 AS chain;
+ chain 
+-------
+  1234
+(1 row)
+
+SELECT 1234 chain;
+ERROR:  syntax error at or near "chain"
+LINE 1: SELECT 1234 chain;
+                    ^
+SELECT 1234 AS characteristics;
+ characteristics 
+-----------------
+            1234
+(1 row)
+
+SELECT 1234 characteristics;
+ERROR:  syntax error at or near "characteristics"
+LINE 1: SELECT 1234 characteristics;
+                    ^
+SELECT 1234 AS checkpoint;
+ checkpoint 
+------------
+       1234
+(1 row)
+
+SELECT 1234 checkpoint;
+ERROR:  syntax error at or near "checkpoint"
+LINE 1: SELECT 1234 checkpoint;
+                    ^
+SELECT 1234 AS class;
+ class 
+-------
+  1234
+(1 row)
+
+SELECT 1234 class;
+ERROR:  syntax error at or near "class"
+LINE 1: SELECT 1234 class;
+                    ^
+SELECT 1234 AS close;
+ close 
+-------
+  1234
+(1 row)
+
+SELECT 1234 close;
+ERROR:  syntax error at or near "close"
+LINE 1: SELECT 1234 close;
+                    ^
+SELECT 1234 AS cluster;
+ cluster 
+---------
+    1234
+(1 row)
+
+SELECT 1234 cluster;
+ERROR:  syntax error at or near "cluster"
+LINE 1: SELECT 1234 cluster;
+                    ^
+SELECT 1234 AS columns;
+ columns 
+---------
+    1234
+(1 row)
+
+SELECT 1234 columns;
+ERROR:  syntax error at or near "columns"
+LINE 1: SELECT 1234 columns;
+                    ^
+SELECT 1234 AS comment;
+ comment 
+---------
+    1234
+(1 row)
+
+SELECT 1234 comment;
+ERROR:  syntax error at or near "comment"
+LINE 1: SELECT 1234 comment;
+                    ^
+SELECT 1234 AS comments;
+ comments 
+----------
+     1234
+(1 row)
+
+SELECT 1234 comments;
+ERROR:  syntax error at or near "comments"
+LINE 1: SELECT 1234 comments;
+                    ^
+SELECT 1234 AS commit;
+ commit 
+--------
+   1234
+(1 row)
+
+SELECT 1234 commit;
+ERROR:  syntax error at or near "commit"
+LINE 1: SELECT 1234 commit;
+                    ^
+SELECT 1234 AS committed;
+ committed 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 committed;
+ERROR:  syntax error at or near "committed"
+LINE 1: SELECT 1234 committed;
+                    ^
+SELECT 1234 AS configuration;
+ configuration 
+---------------
+          1234
+(1 row)
+
+SELECT 1234 configuration;
+ERROR:  syntax error at or near "configuration"
+LINE 1: SELECT 1234 configuration;
+                    ^
+SELECT 1234 AS conflict;
+ conflict 
+----------
+     1234
+(1 row)
+
+SELECT 1234 conflict;
+ERROR:  syntax error at or near "conflict"
+LINE 1: SELECT 1234 conflict;
+                    ^
+SELECT 1234 AS connection;
+ connection 
+------------
+       1234
+(1 row)
+
+SELECT 1234 connection;
+ERROR:  syntax error at or near "connection"
+LINE 1: SELECT 1234 connection;
+                    ^
+SELECT 1234 AS constraints;
+ constraints 
+-------------
+        1234
+(1 row)
+
+SELECT 1234 constraints;
+ERROR:  syntax error at or near "constraints"
+LINE 1: SELECT 1234 constraints;
+                    ^
+SELECT 1234 AS content;
+ content 
+---------
+    1234
+(1 row)
+
+SELECT 1234 content;
+ERROR:  syntax error at or near "content"
+LINE 1: SELECT 1234 content;
+                    ^
+SELECT 1234 AS continue;
+ continue 
+----------
+     1234
+(1 row)
+
+SELECT 1234 continue;
+ERROR:  syntax error at or near "continue"
+LINE 1: SELECT 1234 continue;
+                    ^
+SELECT 1234 AS conversion;
+ conversion 
+------------
+       1234
+(1 row)
+
+SELECT 1234 conversion;
+ERROR:  syntax error at or near "conversion"
+LINE 1: SELECT 1234 conversion;
+                    ^
+SELECT 1234 AS copy;
+ copy 
+------
+ 1234
+(1 row)
+
+SELECT 1234 copy;
+ERROR:  syntax error at or near "copy"
+LINE 1: SELECT 1234 copy;
+                    ^
+SELECT 1234 AS cost;
+ cost 
+------
+ 1234
+(1 row)
+
+SELECT 1234 cost;
+ERROR:  syntax error at or near "cost"
+LINE 1: SELECT 1234 cost;
+                    ^
+SELECT 1234 AS csv;
+ csv  
+------
+ 1234
+(1 row)
+
+SELECT 1234 csv;
+ERROR:  syntax error at or near "csv"
+LINE 1: SELECT 1234 csv;
+                    ^
+SELECT 1234 AS cube;
+ cube 
+------
+ 1234
+(1 row)
+
+SELECT 1234 cube;
+ERROR:  syntax error at or near "cube"
+LINE 1: SELECT 1234 cube;
+                    ^
+SELECT 1234 AS current;
+ current 
+---------
+    1234
+(1 row)
+
+SELECT 1234 current;
+ERROR:  syntax error at or near "current"
+LINE 1: SELECT 1234 current;
+                    ^
+SELECT 1234 AS cursor;
+ cursor 
+--------
+   1234
+(1 row)
+
+SELECT 1234 cursor;
+ERROR:  syntax error at or near "cursor"
+LINE 1: SELECT 1234 cursor;
+                    ^
+SELECT 1234 AS cycle;
+ cycle 
+-------
+  1234
+(1 row)
+
+SELECT 1234 cycle;
+ERROR:  syntax error at or near "cycle"
+LINE 1: SELECT 1234 cycle;
+                    ^
+SELECT 1234 AS data;
+ data 
+------
+ 1234
+(1 row)
+
+SELECT 1234 data;
+ERROR:  syntax error at or near "data"
+LINE 1: SELECT 1234 data;
+                    ^
+SELECT 1234 AS database;
+ database 
+----------
+     1234
+(1 row)
+
+SELECT 1234 database;
+ERROR:  syntax error at or near "database"
+LINE 1: SELECT 1234 database;
+                    ^
+SELECT 1234 AS day;
+ day  
+------
+ 1234
+(1 row)
+
+SELECT 1234 day;
+ERROR:  syntax error at or near "day"
+LINE 1: SELECT 1234 day;
+                    ^
+SELECT 1234 AS deallocate;
+ deallocate 
+------------
+       1234
+(1 row)
+
+SELECT 1234 deallocate;
+ERROR:  syntax error at or near "deallocate"
+LINE 1: SELECT 1234 deallocate;
+                    ^
+SELECT 1234 AS declare;
+ declare 
+---------
+    1234
+(1 row)
+
+SELECT 1234 declare;
+ERROR:  syntax error at or near "declare"
+LINE 1: SELECT 1234 declare;
+                    ^
+SELECT 1234 AS defaults;
+ defaults 
+----------
+     1234
+(1 row)
+
+SELECT 1234 defaults;
+ERROR:  syntax error at or near "defaults"
+LINE 1: SELECT 1234 defaults;
+                    ^
+SELECT 1234 AS deferred;
+ deferred 
+----------
+     1234
+(1 row)
+
+SELECT 1234 deferred;
+ERROR:  syntax error at or near "deferred"
+LINE 1: SELECT 1234 deferred;
+                    ^
+SELECT 1234 AS definer;
+ definer 
+---------
+    1234
+(1 row)
+
+SELECT 1234 definer;
+ERROR:  syntax error at or near "definer"
+LINE 1: SELECT 1234 definer;
+                    ^
+SELECT 1234 AS delete;
+ delete 
+--------
+   1234
+(1 row)
+
+SELECT 1234 delete;
+ERROR:  syntax error at or near "delete"
+LINE 1: SELECT 1234 delete;
+                    ^
+SELECT 1234 AS delimiter;
+ delimiter 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 delimiter;
+ERROR:  syntax error at or near "delimiter"
+LINE 1: SELECT 1234 delimiter;
+                    ^
+SELECT 1234 AS delimiters;
+ delimiters 
+------------
+       1234
+(1 row)
+
+SELECT 1234 delimiters;
+ERROR:  syntax error at or near "delimiters"
+LINE 1: SELECT 1234 delimiters;
+                    ^
+SELECT 1234 AS depends;
+ depends 
+---------
+    1234
+(1 row)
+
+SELECT 1234 depends;
+ERROR:  syntax error at or near "depends"
+LINE 1: SELECT 1234 depends;
+                    ^
+SELECT 1234 AS detach;
+ detach 
+--------
+   1234
+(1 row)
+
+SELECT 1234 detach;
+ERROR:  syntax error at or near "detach"
+LINE 1: SELECT 1234 detach;
+                    ^
+SELECT 1234 AS dictionary;
+ dictionary 
+------------
+       1234
+(1 row)
+
+SELECT 1234 dictionary;
+ERROR:  syntax error at or near "dictionary"
+LINE 1: SELECT 1234 dictionary;
+                    ^
+SELECT 1234 AS disable;
+ disable 
+---------
+    1234
+(1 row)
+
+SELECT 1234 disable;
+ERROR:  syntax error at or near "disable"
+LINE 1: SELECT 1234 disable;
+                    ^
+SELECT 1234 AS discard;
+ discard 
+---------
+    1234
+(1 row)
+
+SELECT 1234 discard;
+ERROR:  syntax error at or near "discard"
+LINE 1: SELECT 1234 discard;
+                    ^
+SELECT 1234 AS document;
+ document 
+----------
+     1234
+(1 row)
+
+SELECT 1234 document;
+ERROR:  syntax error at or near "document"
+LINE 1: SELECT 1234 document;
+                    ^
+SELECT 1234 AS domain;
+ domain 
+--------
+   1234
+(1 row)
+
+SELECT 1234 domain;
+ERROR:  syntax error at or near "domain"
+LINE 1: SELECT 1234 domain;
+                    ^
+SELECT 1234 AS double;
+ double 
+--------
+   1234
+(1 row)
+
+SELECT 1234 double;
+ERROR:  syntax error at or near "double"
+LINE 1: SELECT 1234 double;
+                    ^
+SELECT 1234 AS drop;
+ drop 
+------
+ 1234
+(1 row)
+
+SELECT 1234 drop;
+ERROR:  syntax error at or near "drop"
+LINE 1: SELECT 1234 drop;
+                    ^
+SELECT 1234 AS each;
+ each 
+------
+ 1234
+(1 row)
+
+SELECT 1234 each;
+ERROR:  syntax error at or near "each"
+LINE 1: SELECT 1234 each;
+                    ^
+SELECT 1234 AS enable;
+ enable 
+--------
+   1234
+(1 row)
+
+SELECT 1234 enable;
+ERROR:  syntax error at or near "enable"
+LINE 1: SELECT 1234 enable;
+                    ^
+SELECT 1234 AS encoding;
+ encoding 
+----------
+     1234
+(1 row)
+
+SELECT 1234 encoding;
+ERROR:  syntax error at or near "encoding"
+LINE 1: SELECT 1234 encoding;
+                    ^
+SELECT 1234 AS encrypted;
+ encrypted 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 encrypted;
+ERROR:  syntax error at or near "encrypted"
+LINE 1: SELECT 1234 encrypted;
+                    ^
+SELECT 1234 AS enum;
+ enum 
+------
+ 1234
+(1 row)
+
+SELECT 1234 enum;
+ERROR:  syntax error at or near "enum"
+LINE 1: SELECT 1234 enum;
+                    ^
+SELECT 1234 AS escape;
+ escape 
+--------
+   1234
+(1 row)
+
+SELECT 1234 escape;
+ERROR:  syntax error at or near "escape"
+LINE 1: SELECT 1234 escape;
+                    ^
+SELECT 1234 AS event;
+ event 
+-------
+  1234
+(1 row)
+
+SELECT 1234 event;
+ERROR:  syntax error at or near "event"
+LINE 1: SELECT 1234 event;
+                    ^
+SELECT 1234 AS exclude;
+ exclude 
+---------
+    1234
+(1 row)
+
+SELECT 1234 exclude;
+ERROR:  syntax error at or near "exclude"
+LINE 1: SELECT 1234 exclude;
+                    ^
+SELECT 1234 AS excluding;
+ excluding 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 excluding;
+ERROR:  syntax error at or near "excluding"
+LINE 1: SELECT 1234 excluding;
+                    ^
+SELECT 1234 AS exclusive;
+ exclusive 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 exclusive;
+ERROR:  syntax error at or near "exclusive"
+LINE 1: SELECT 1234 exclusive;
+                    ^
+SELECT 1234 AS execute;
+ execute 
+---------
+    1234
+(1 row)
+
+SELECT 1234 execute;
+ERROR:  syntax error at or near "execute"
+LINE 1: SELECT 1234 execute;
+                    ^
+SELECT 1234 AS explain;
+ explain 
+---------
+    1234
+(1 row)
+
+SELECT 1234 explain;
+ERROR:  syntax error at or near "explain"
+LINE 1: SELECT 1234 explain;
+                    ^
+SELECT 1234 AS expression;
+ expression 
+------------
+       1234
+(1 row)
+
+SELECT 1234 expression;
+ERROR:  syntax error at or near "expression"
+LINE 1: SELECT 1234 expression;
+                    ^
+SELECT 1234 AS extension;
+ extension 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 extension;
+ERROR:  syntax error at or near "extension"
+LINE 1: SELECT 1234 extension;
+                    ^
+SELECT 1234 AS external;
+ external 
+----------
+     1234
+(1 row)
+
+SELECT 1234 external;
+ERROR:  syntax error at or near "external"
+LINE 1: SELECT 1234 external;
+                    ^
+SELECT 1234 AS family;
+ family 
+--------
+   1234
+(1 row)
+
+SELECT 1234 family;
+ERROR:  syntax error at or near "family"
+LINE 1: SELECT 1234 family;
+                    ^
+SELECT 1234 AS filter;
+ filter 
+--------
+   1234
+(1 row)
+
+SELECT 1234 filter;
+ERROR:  syntax error at or near "filter"
+LINE 1: SELECT 1234 filter;
+                    ^
+SELECT 1234 AS first;
+ first 
+-------
+  1234
+(1 row)
+
+SELECT 1234 first;
+ERROR:  syntax error at or near "first"
+LINE 1: SELECT 1234 first;
+                    ^
+SELECT 1234 AS following;
+ following 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 following;
+ERROR:  syntax error at or near "following"
+LINE 1: SELECT 1234 following;
+                    ^
+SELECT 1234 AS force;
+ force 
+-------
+  1234
+(1 row)
+
+SELECT 1234 force;
+ERROR:  syntax error at or near "force"
+LINE 1: SELECT 1234 force;
+                    ^
+SELECT 1234 AS forward;
+ forward 
+---------
+    1234
+(1 row)
+
+SELECT 1234 forward;
+ERROR:  syntax error at or near "forward"
+LINE 1: SELECT 1234 forward;
+                    ^
+SELECT 1234 AS function;
+ function 
+----------
+     1234
+(1 row)
+
+SELECT 1234 function;
+ERROR:  syntax error at or near "function"
+LINE 1: SELECT 1234 function;
+                    ^
+SELECT 1234 AS functions;
+ functions 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 functions;
+ERROR:  syntax error at or near "functions"
+LINE 1: SELECT 1234 functions;
+                    ^
+SELECT 1234 AS generated;
+ generated 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 generated;
+ERROR:  syntax error at or near "generated"
+LINE 1: SELECT 1234 generated;
+                    ^
+SELECT 1234 AS global;
+ global 
+--------
+   1234
+(1 row)
+
+SELECT 1234 global;
+ERROR:  syntax error at or near "global"
+LINE 1: SELECT 1234 global;
+                    ^
+SELECT 1234 AS granted;
+ granted 
+---------
+    1234
+(1 row)
+
+SELECT 1234 granted;
+ERROR:  syntax error at or near "granted"
+LINE 1: SELECT 1234 granted;
+                    ^
+SELECT 1234 AS groups;
+ groups 
+--------
+   1234
+(1 row)
+
+SELECT 1234 groups;
+ERROR:  syntax error at or near "groups"
+LINE 1: SELECT 1234 groups;
+                    ^
+SELECT 1234 AS handler;
+ handler 
+---------
+    1234
+(1 row)
+
+SELECT 1234 handler;
+ERROR:  syntax error at or near "handler"
+LINE 1: SELECT 1234 handler;
+                    ^
+SELECT 1234 AS header;
+ header 
+--------
+   1234
+(1 row)
+
+SELECT 1234 header;
+ERROR:  syntax error at or near "header"
+LINE 1: SELECT 1234 header;
+                    ^
+SELECT 1234 AS hold;
+ hold 
+------
+ 1234
+(1 row)
+
+SELECT 1234 hold;
+ERROR:  syntax error at or near "hold"
+LINE 1: SELECT 1234 hold;
+                    ^
+SELECT 1234 AS hour;
+ hour 
+------
+ 1234
+(1 row)
+
+SELECT 1234 hour;
+ERROR:  syntax error at or near "hour"
+LINE 1: SELECT 1234 hour;
+                    ^
+SELECT 1234 AS identity;
+ identity 
+----------
+     1234
+(1 row)
+
+SELECT 1234 identity;
+ERROR:  syntax error at or near "identity"
+LINE 1: SELECT 1234 identity;
+                    ^
+SELECT 1234 AS if;
+  if  
+------
+ 1234
+(1 row)
+
+SELECT 1234 if;
+ERROR:  syntax error at or near "if"
+LINE 1: SELECT 1234 if;
+                    ^
+SELECT 1234 AS immediate;
+ immediate 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 immediate;
+ERROR:  syntax error at or near "immediate"
+LINE 1: SELECT 1234 immediate;
+                    ^
+SELECT 1234 AS immutable;
+ immutable 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 immutable;
+ERROR:  syntax error at or near "immutable"
+LINE 1: SELECT 1234 immutable;
+                    ^
+SELECT 1234 AS implicit;
+ implicit 
+----------
+     1234
+(1 row)
+
+SELECT 1234 implicit;
+ERROR:  syntax error at or near "implicit"
+LINE 1: SELECT 1234 implicit;
+                    ^
+SELECT 1234 AS import;
+ import 
+--------
+   1234
+(1 row)
+
+SELECT 1234 import;
+ERROR:  syntax error at or near "import"
+LINE 1: SELECT 1234 import;
+                    ^
+SELECT 1234 AS include;
+ include 
+---------
+    1234
+(1 row)
+
+SELECT 1234 include;
+ERROR:  syntax error at or near "include"
+LINE 1: SELECT 1234 include;
+                    ^
+SELECT 1234 AS including;
+ including 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 including;
+ERROR:  syntax error at or near "including"
+LINE 1: SELECT 1234 including;
+                    ^
+SELECT 1234 AS increment;
+ increment 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 increment;
+ERROR:  syntax error at or near "increment"
+LINE 1: SELECT 1234 increment;
+                    ^
+SELECT 1234 AS index;
+ index 
+-------
+  1234
+(1 row)
+
+SELECT 1234 index;
+ERROR:  syntax error at or near "index"
+LINE 1: SELECT 1234 index;
+                    ^
+SELECT 1234 AS indexes;
+ indexes 
+---------
+    1234
+(1 row)
+
+SELECT 1234 indexes;
+ERROR:  syntax error at or near "indexes"
+LINE 1: SELECT 1234 indexes;
+                    ^
+SELECT 1234 AS inherit;
+ inherit 
+---------
+    1234
+(1 row)
+
+SELECT 1234 inherit;
+ERROR:  syntax error at or near "inherit"
+LINE 1: SELECT 1234 inherit;
+                    ^
+SELECT 1234 AS inherits;
+ inherits 
+----------
+     1234
+(1 row)
+
+SELECT 1234 inherits;
+ERROR:  syntax error at or near "inherits"
+LINE 1: SELECT 1234 inherits;
+                    ^
+SELECT 1234 AS inline;
+ inline 
+--------
+   1234
+(1 row)
+
+SELECT 1234 inline;
+ERROR:  syntax error at or near "inline"
+LINE 1: SELECT 1234 inline;
+                    ^
+SELECT 1234 AS input;
+ input 
+-------
+  1234
+(1 row)
+
+SELECT 1234 input;
+ERROR:  syntax error at or near "input"
+LINE 1: SELECT 1234 input;
+                    ^
+SELECT 1234 AS insensitive;
+ insensitive 
+-------------
+        1234
+(1 row)
+
+SELECT 1234 insensitive;
+ERROR:  syntax error at or near "insensitive"
+LINE 1: SELECT 1234 insensitive;
+                    ^
+SELECT 1234 AS insert;
+ insert 
+--------
+   1234
+(1 row)
+
+SELECT 1234 insert;
+ERROR:  syntax error at or near "insert"
+LINE 1: SELECT 1234 insert;
+                    ^
+SELECT 1234 AS instead;
+ instead 
+---------
+    1234
+(1 row)
+
+SELECT 1234 instead;
+ERROR:  syntax error at or near "instead"
+LINE 1: SELECT 1234 instead;
+                    ^
+SELECT 1234 AS invoker;
+ invoker 
+---------
+    1234
+(1 row)
+
+SELECT 1234 invoker;
+ERROR:  syntax error at or near "invoker"
+LINE 1: SELECT 1234 invoker;
+                    ^
+SELECT 1234 AS isolation;
+ isolation 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 isolation;
+ERROR:  syntax error at or near "isolation"
+LINE 1: SELECT 1234 isolation;
+                    ^
+SELECT 1234 AS key;
+ key  
+------
+ 1234
+(1 row)
+
+SELECT 1234 key;
+ERROR:  syntax error at or near "key"
+LINE 1: SELECT 1234 key;
+                    ^
+SELECT 1234 AS label;
+ label 
+-------
+  1234
+(1 row)
+
+SELECT 1234 label;
+ERROR:  syntax error at or near "label"
+LINE 1: SELECT 1234 label;
+                    ^
+SELECT 1234 AS language;
+ language 
+----------
+     1234
+(1 row)
+
+SELECT 1234 language;
+ERROR:  syntax error at or near "language"
+LINE 1: SELECT 1234 language;
+                    ^
+SELECT 1234 AS large;
+ large 
+-------
+  1234
+(1 row)
+
+SELECT 1234 large;
+ERROR:  syntax error at or near "large"
+LINE 1: SELECT 1234 large;
+                    ^
+SELECT 1234 AS last;
+ last 
+------
+ 1234
+(1 row)
+
+SELECT 1234 last;
+ERROR:  syntax error at or near "last"
+LINE 1: SELECT 1234 last;
+                    ^
+SELECT 1234 AS leakproof;
+ leakproof 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 leakproof;
+ERROR:  syntax error at or near "leakproof"
+LINE 1: SELECT 1234 leakproof;
+                    ^
+SELECT 1234 AS level;
+ level 
+-------
+  1234
+(1 row)
+
+SELECT 1234 level;
+ERROR:  syntax error at or near "level"
+LINE 1: SELECT 1234 level;
+                    ^
+SELECT 1234 AS listen;
+ listen 
+--------
+   1234
+(1 row)
+
+SELECT 1234 listen;
+ERROR:  syntax error at or near "listen"
+LINE 1: SELECT 1234 listen;
+                    ^
+SELECT 1234 AS load;
+ load 
+------
+ 1234
+(1 row)
+
+SELECT 1234 load;
+ERROR:  syntax error at or near "load"
+LINE 1: SELECT 1234 load;
+                    ^
+SELECT 1234 AS local;
+ local 
+-------
+  1234
+(1 row)
+
+SELECT 1234 local;
+ERROR:  syntax error at or near "local"
+LINE 1: SELECT 1234 local;
+                    ^
+SELECT 1234 AS location;
+ location 
+----------
+     1234
+(1 row)
+
+SELECT 1234 location;
+ERROR:  syntax error at or near "location"
+LINE 1: SELECT 1234 location;
+                    ^
+SELECT 1234 AS lock;
+ lock 
+------
+ 1234
+(1 row)
+
+SELECT 1234 lock;
+ERROR:  syntax error at or near "lock"
+LINE 1: SELECT 1234 lock;
+                    ^
+SELECT 1234 AS locked;
+ locked 
+--------
+   1234
+(1 row)
+
+SELECT 1234 locked;
+ERROR:  syntax error at or near "locked"
+LINE 1: SELECT 1234 locked;
+                    ^
+SELECT 1234 AS logged;
+ logged 
+--------
+   1234
+(1 row)
+
+SELECT 1234 logged;
+ERROR:  syntax error at or near "logged"
+LINE 1: SELECT 1234 logged;
+                    ^
+SELECT 1234 AS mapping;
+ mapping 
+---------
+    1234
+(1 row)
+
+SELECT 1234 mapping;
+ERROR:  syntax error at or near "mapping"
+LINE 1: SELECT 1234 mapping;
+                    ^
+SELECT 1234 AS match;
+ match 
+-------
+  1234
+(1 row)
+
+SELECT 1234 match;
+ERROR:  syntax error at or near "match"
+LINE 1: SELECT 1234 match;
+                    ^
+SELECT 1234 AS materialized;
+ materialized 
+--------------
+         1234
+(1 row)
+
+SELECT 1234 materialized;
+ERROR:  syntax error at or near "materialized"
+LINE 1: SELECT 1234 materialized;
+                    ^
+SELECT 1234 AS maxvalue;
+ maxvalue 
+----------
+     1234
+(1 row)
+
+SELECT 1234 maxvalue;
+ERROR:  syntax error at or near "maxvalue"
+LINE 1: SELECT 1234 maxvalue;
+                    ^
+SELECT 1234 AS method;
+ method 
+--------
+   1234
+(1 row)
+
+SELECT 1234 method;
+ERROR:  syntax error at or near "method"
+LINE 1: SELECT 1234 method;
+                    ^
+SELECT 1234 AS minute;
+ minute 
+--------
+   1234
+(1 row)
+
+SELECT 1234 minute;
+ERROR:  syntax error at or near "minute"
+LINE 1: SELECT 1234 minute;
+                    ^
+SELECT 1234 AS minvalue;
+ minvalue 
+----------
+     1234
+(1 row)
+
+SELECT 1234 minvalue;
+ERROR:  syntax error at or near "minvalue"
+LINE 1: SELECT 1234 minvalue;
+                    ^
+SELECT 1234 AS mode;
+ mode 
+------
+ 1234
+(1 row)
+
+SELECT 1234 mode;
+ERROR:  syntax error at or near "mode"
+LINE 1: SELECT 1234 mode;
+                    ^
+SELECT 1234 AS month;
+ month 
+-------
+  1234
+(1 row)
+
+SELECT 1234 month;
+ERROR:  syntax error at or near "month"
+LINE 1: SELECT 1234 month;
+                    ^
+SELECT 1234 AS move;
+ move 
+------
+ 1234
+(1 row)
+
+SELECT 1234 move;
+ERROR:  syntax error at or near "move"
+LINE 1: SELECT 1234 move;
+                    ^
+SELECT 1234 AS name;
+ name 
+------
+ 1234
+(1 row)
+
+SELECT 1234 name;
+ERROR:  syntax error at or near "name"
+LINE 1: SELECT 1234 name;
+                    ^
+SELECT 1234 AS names;
+ names 
+-------
+  1234
+(1 row)
+
+SELECT 1234 names;
+ERROR:  syntax error at or near "names"
+LINE 1: SELECT 1234 names;
+                    ^
+SELECT 1234 AS new;
+ new  
+------
+ 1234
+(1 row)
+
+SELECT 1234 new;
+ERROR:  syntax error at or near "new"
+LINE 1: SELECT 1234 new;
+                    ^
+SELECT 1234 AS next;
+ next 
+------
+ 1234
+(1 row)
+
+SELECT 1234 next;
+ERROR:  syntax error at or near "next"
+LINE 1: SELECT 1234 next;
+                    ^
+SELECT 1234 AS nfc;
+ nfc  
+------
+ 1234
+(1 row)
+
+SELECT 1234 nfc;
+ERROR:  syntax error at or near "nfc"
+LINE 1: SELECT 1234 nfc;
+                    ^
+SELECT 1234 AS nfd;
+ nfd  
+------
+ 1234
+(1 row)
+
+SELECT 1234 nfd;
+ERROR:  syntax error at or near "nfd"
+LINE 1: SELECT 1234 nfd;
+                    ^
+SELECT 1234 AS nfkc;
+ nfkc 
+------
+ 1234
+(1 row)
+
+SELECT 1234 nfkc;
+ERROR:  syntax error at or near "nfkc"
+LINE 1: SELECT 1234 nfkc;
+                    ^
+SELECT 1234 AS nfkd;
+ nfkd 
+------
+ 1234
+(1 row)
+
+SELECT 1234 nfkd;
+ERROR:  syntax error at or near "nfkd"
+LINE 1: SELECT 1234 nfkd;
+                    ^
+SELECT 1234 AS no;
+  no  
+------
+ 1234
+(1 row)
+
+SELECT 1234 no;
+ERROR:  syntax error at or near "no"
+LINE 1: SELECT 1234 no;
+                    ^
+SELECT 1234 AS normalized;
+ normalized 
+------------
+       1234
+(1 row)
+
+SELECT 1234 normalized;
+ERROR:  syntax error at or near "normalized"
+LINE 1: SELECT 1234 normalized;
+                    ^
+SELECT 1234 AS nothing;
+ nothing 
+---------
+    1234
+(1 row)
+
+SELECT 1234 nothing;
+ERROR:  syntax error at or near "nothing"
+LINE 1: SELECT 1234 nothing;
+                    ^
+SELECT 1234 AS notify;
+ notify 
+--------
+   1234
+(1 row)
+
+SELECT 1234 notify;
+ERROR:  syntax error at or near "notify"
+LINE 1: SELECT 1234 notify;
+                    ^
+SELECT 1234 AS nowait;
+ nowait 
+--------
+   1234
+(1 row)
+
+SELECT 1234 nowait;
+ERROR:  syntax error at or near "nowait"
+LINE 1: SELECT 1234 nowait;
+                    ^
+SELECT 1234 AS nulls;
+ nulls 
+-------
+  1234
+(1 row)
+
+SELECT 1234 nulls;
+ERROR:  syntax error at or near "nulls"
+LINE 1: SELECT 1234 nulls;
+                    ^
+SELECT 1234 AS object;
+ object 
+--------
+   1234
+(1 row)
+
+SELECT 1234 object;
+ERROR:  syntax error at or near "object"
+LINE 1: SELECT 1234 object;
+                    ^
+SELECT 1234 AS of;
+  of  
+------
+ 1234
+(1 row)
+
+SELECT 1234 of;
+ERROR:  syntax error at or near "of"
+LINE 1: SELECT 1234 of;
+                    ^
+SELECT 1234 AS off;
+ off  
+------
+ 1234
+(1 row)
+
+SELECT 1234 off;
+ERROR:  syntax error at or near "off"
+LINE 1: SELECT 1234 off;
+                    ^
+SELECT 1234 AS oids;
+ oids 
+------
+ 1234
+(1 row)
+
+SELECT 1234 oids;
+ERROR:  syntax error at or near "oids"
+LINE 1: SELECT 1234 oids;
+                    ^
+SELECT 1234 AS old;
+ old  
+------
+ 1234
+(1 row)
+
+SELECT 1234 old;
+ERROR:  syntax error at or near "old"
+LINE 1: SELECT 1234 old;
+                    ^
+SELECT 1234 AS operator;
+ operator 
+----------
+     1234
+(1 row)
+
+SELECT 1234 operator;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 1234 operator;
+                            ^
+SELECT 1234 AS option;
+ option 
+--------
+   1234
+(1 row)
+
+SELECT 1234 option;
+ERROR:  syntax error at or near "option"
+LINE 1: SELECT 1234 option;
+                    ^
+SELECT 1234 AS options;
+ options 
+---------
+    1234
+(1 row)
+
+SELECT 1234 options;
+ERROR:  syntax error at or near "options"
+LINE 1: SELECT 1234 options;
+                    ^
+SELECT 1234 AS ordinality;
+ ordinality 
+------------
+       1234
+(1 row)
+
+SELECT 1234 ordinality;
+ERROR:  syntax error at or near "ordinality"
+LINE 1: SELECT 1234 ordinality;
+                    ^
+SELECT 1234 AS others;
+ others 
+--------
+   1234
+(1 row)
+
+SELECT 1234 others;
+ERROR:  syntax error at or near "others"
+LINE 1: SELECT 1234 others;
+                    ^
+SELECT 1234 AS over;
+ over 
+------
+ 1234
+(1 row)
+
+SELECT 1234 over;
+ERROR:  syntax error at or near "over"
+LINE 1: SELECT 1234 over;
+                    ^
+SELECT 1234 AS overriding;
+ overriding 
+------------
+       1234
+(1 row)
+
+SELECT 1234 overriding;
+ERROR:  syntax error at or near "overriding"
+LINE 1: SELECT 1234 overriding;
+                    ^
+SELECT 1234 AS owned;
+ owned 
+-------
+  1234
+(1 row)
+
+SELECT 1234 owned;
+ERROR:  syntax error at or near "owned"
+LINE 1: SELECT 1234 owned;
+                    ^
+SELECT 1234 AS owner;
+ owner 
+-------
+  1234
+(1 row)
+
+SELECT 1234 owner;
+ERROR:  syntax error at or near "owner"
+LINE 1: SELECT 1234 owner;
+                    ^
+SELECT 1234 AS parallel;
+ parallel 
+----------
+     1234
+(1 row)
+
+SELECT 1234 parallel;
+ERROR:  syntax error at or near "parallel"
+LINE 1: SELECT 1234 parallel;
+                    ^
+SELECT 1234 AS parser;
+ parser 
+--------
+   1234
+(1 row)
+
+SELECT 1234 parser;
+ERROR:  syntax error at or near "parser"
+LINE 1: SELECT 1234 parser;
+                    ^
+SELECT 1234 AS partial;
+ partial 
+---------
+    1234
+(1 row)
+
+SELECT 1234 partial;
+ERROR:  syntax error at or near "partial"
+LINE 1: SELECT 1234 partial;
+                    ^
+SELECT 1234 AS partition;
+ partition 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 partition;
+ERROR:  syntax error at or near "partition"
+LINE 1: SELECT 1234 partition;
+                    ^
+SELECT 1234 AS passing;
+ passing 
+---------
+    1234
+(1 row)
+
+SELECT 1234 passing;
+ERROR:  syntax error at or near "passing"
+LINE 1: SELECT 1234 passing;
+                    ^
+SELECT 1234 AS password;
+ password 
+----------
+     1234
+(1 row)
+
+SELECT 1234 password;
+ERROR:  syntax error at or near "password"
+LINE 1: SELECT 1234 password;
+                    ^
+SELECT 1234 AS plans;
+ plans 
+-------
+  1234
+(1 row)
+
+SELECT 1234 plans;
+ERROR:  syntax error at or near "plans"
+LINE 1: SELECT 1234 plans;
+                    ^
+SELECT 1234 AS policy;
+ policy 
+--------
+   1234
+(1 row)
+
+SELECT 1234 policy;
+ERROR:  syntax error at or near "policy"
+LINE 1: SELECT 1234 policy;
+                    ^
+SELECT 1234 AS preceding;
+ preceding 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 preceding;
+ERROR:  syntax error at or near "preceding"
+LINE 1: SELECT 1234 preceding;
+                    ^
+SELECT 1234 AS prepare;
+ prepare 
+---------
+    1234
+(1 row)
+
+SELECT 1234 prepare;
+ERROR:  syntax error at or near "prepare"
+LINE 1: SELECT 1234 prepare;
+                    ^
+SELECT 1234 AS prepared;
+ prepared 
+----------
+     1234
+(1 row)
+
+SELECT 1234 prepared;
+ERROR:  syntax error at or near "prepared"
+LINE 1: SELECT 1234 prepared;
+                    ^
+SELECT 1234 AS preserve;
+ preserve 
+----------
+     1234
+(1 row)
+
+SELECT 1234 preserve;
+ERROR:  syntax error at or near "preserve"
+LINE 1: SELECT 1234 preserve;
+                    ^
+SELECT 1234 AS prior;
+ prior 
+-------
+  1234
+(1 row)
+
+SELECT 1234 prior;
+ERROR:  syntax error at or near "prior"
+LINE 1: SELECT 1234 prior;
+                    ^
+SELECT 1234 AS privileges;
+ privileges 
+------------
+       1234
+(1 row)
+
+SELECT 1234 privileges;
+ERROR:  syntax error at or near "privileges"
+LINE 1: SELECT 1234 privileges;
+                    ^
+SELECT 1234 AS procedural;
+ procedural 
+------------
+       1234
+(1 row)
+
+SELECT 1234 procedural;
+ERROR:  syntax error at or near "procedural"
+LINE 1: SELECT 1234 procedural;
+                    ^
+SELECT 1234 AS procedure;
+ procedure 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 procedure;
+ERROR:  syntax error at or near "procedure"
+LINE 1: SELECT 1234 procedure;
+                    ^
+SELECT 1234 AS procedures;
+ procedures 
+------------
+       1234
+(1 row)
+
+SELECT 1234 procedures;
+ERROR:  syntax error at or near "procedures"
+LINE 1: SELECT 1234 procedures;
+                    ^
+SELECT 1234 AS program;
+ program 
+---------
+    1234
+(1 row)
+
+SELECT 1234 program;
+ERROR:  syntax error at or near "program"
+LINE 1: SELECT 1234 program;
+                    ^
+SELECT 1234 AS publication;
+ publication 
+-------------
+        1234
+(1 row)
+
+SELECT 1234 publication;
+ERROR:  syntax error at or near "publication"
+LINE 1: SELECT 1234 publication;
+                    ^
+SELECT 1234 AS quote;
+ quote 
+-------
+  1234
+(1 row)
+
+SELECT 1234 quote;
+ERROR:  syntax error at or near "quote"
+LINE 1: SELECT 1234 quote;
+                    ^
+SELECT 1234 AS range;
+ range 
+-------
+  1234
+(1 row)
+
+SELECT 1234 range;
+ERROR:  syntax error at or near "range"
+LINE 1: SELECT 1234 range;
+                    ^
+SELECT 1234 AS read;
+ read 
+------
+ 1234
+(1 row)
+
+SELECT 1234 read;
+ERROR:  syntax error at or near "read"
+LINE 1: SELECT 1234 read;
+                    ^
+SELECT 1234 AS reassign;
+ reassign 
+----------
+     1234
+(1 row)
+
+SELECT 1234 reassign;
+ERROR:  syntax error at or near "reassign"
+LINE 1: SELECT 1234 reassign;
+                    ^
+SELECT 1234 AS recheck;
+ recheck 
+---------
+    1234
+(1 row)
+
+SELECT 1234 recheck;
+ERROR:  syntax error at or near "recheck"
+LINE 1: SELECT 1234 recheck;
+                    ^
+SELECT 1234 AS recursive;
+ recursive 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 recursive;
+ERROR:  syntax error at or near "recursive"
+LINE 1: SELECT 1234 recursive;
+                    ^
+SELECT 1234 AS ref;
+ ref  
+------
+ 1234
+(1 row)
+
+SELECT 1234 ref;
+ERROR:  syntax error at or near "ref"
+LINE 1: SELECT 1234 ref;
+                    ^
+SELECT 1234 AS referencing;
+ referencing 
+-------------
+        1234
+(1 row)
+
+SELECT 1234 referencing;
+ERROR:  syntax error at or near "referencing"
+LINE 1: SELECT 1234 referencing;
+                    ^
+SELECT 1234 AS refresh;
+ refresh 
+---------
+    1234
+(1 row)
+
+SELECT 1234 refresh;
+ERROR:  syntax error at or near "refresh"
+LINE 1: SELECT 1234 refresh;
+                    ^
+SELECT 1234 AS reindex;
+ reindex 
+---------
+    1234
+(1 row)
+
+SELECT 1234 reindex;
+ERROR:  syntax error at or near "reindex"
+LINE 1: SELECT 1234 reindex;
+                    ^
+SELECT 1234 AS relative;
+ relative 
+----------
+     1234
+(1 row)
+
+SELECT 1234 relative;
+ERROR:  syntax error at or near "relative"
+LINE 1: SELECT 1234 relative;
+                    ^
+SELECT 1234 AS release;
+ release 
+---------
+    1234
+(1 row)
+
+SELECT 1234 release;
+ERROR:  syntax error at or near "release"
+LINE 1: SELECT 1234 release;
+                    ^
+SELECT 1234 AS rename;
+ rename 
+--------
+   1234
+(1 row)
+
+SELECT 1234 rename;
+ERROR:  syntax error at or near "rename"
+LINE 1: SELECT 1234 rename;
+                    ^
+SELECT 1234 AS repeatable;
+ repeatable 
+------------
+       1234
+(1 row)
+
+SELECT 1234 repeatable;
+ERROR:  syntax error at or near "repeatable"
+LINE 1: SELECT 1234 repeatable;
+                    ^
+SELECT 1234 AS replace;
+ replace 
+---------
+    1234
+(1 row)
+
+SELECT 1234 replace;
+ERROR:  syntax error at or near "replace"
+LINE 1: SELECT 1234 replace;
+                    ^
+SELECT 1234 AS replica;
+ replica 
+---------
+    1234
+(1 row)
+
+SELECT 1234 replica;
+ERROR:  syntax error at or near "replica"
+LINE 1: SELECT 1234 replica;
+                    ^
+SELECT 1234 AS reset;
+ reset 
+-------
+  1234
+(1 row)
+
+SELECT 1234 reset;
+ERROR:  syntax error at or near "reset"
+LINE 1: SELECT 1234 reset;
+                    ^
+SELECT 1234 AS restart;
+ restart 
+---------
+    1234
+(1 row)
+
+SELECT 1234 restart;
+ERROR:  syntax error at or near "restart"
+LINE 1: SELECT 1234 restart;
+                    ^
+SELECT 1234 AS restrict;
+ restrict 
+----------
+     1234
+(1 row)
+
+SELECT 1234 restrict;
+ERROR:  syntax error at or near "restrict"
+LINE 1: SELECT 1234 restrict;
+                    ^
+SELECT 1234 AS returns;
+ returns 
+---------
+    1234
+(1 row)
+
+SELECT 1234 returns;
+ERROR:  syntax error at or near "returns"
+LINE 1: SELECT 1234 returns;
+                    ^
+SELECT 1234 AS revoke;
+ revoke 
+--------
+   1234
+(1 row)
+
+SELECT 1234 revoke;
+ERROR:  syntax error at or near "revoke"
+LINE 1: SELECT 1234 revoke;
+                    ^
+SELECT 1234 AS role;
+ role 
+------
+ 1234
+(1 row)
+
+SELECT 1234 role;
+ERROR:  syntax error at or near "role"
+LINE 1: SELECT 1234 role;
+                    ^
+SELECT 1234 AS rollback;
+ rollback 
+----------
+     1234
+(1 row)
+
+SELECT 1234 rollback;
+ERROR:  syntax error at or near "rollback"
+LINE 1: SELECT 1234 rollback;
+                    ^
+SELECT 1234 AS rollup;
+ rollup 
+--------
+   1234
+(1 row)
+
+SELECT 1234 rollup;
+ERROR:  syntax error at or near "rollup"
+LINE 1: SELECT 1234 rollup;
+                    ^
+SELECT 1234 AS routine;
+ routine 
+---------
+    1234
+(1 row)
+
+SELECT 1234 routine;
+ERROR:  syntax error at or near "routine"
+LINE 1: SELECT 1234 routine;
+                    ^
+SELECT 1234 AS routines;
+ routines 
+----------
+     1234
+(1 row)
+
+SELECT 1234 routines;
+ERROR:  syntax error at or near "routines"
+LINE 1: SELECT 1234 routines;
+                    ^
+SELECT 1234 AS rows;
+ rows 
+------
+ 1234
+(1 row)
+
+SELECT 1234 rows;
+ERROR:  syntax error at or near "rows"
+LINE 1: SELECT 1234 rows;
+                    ^
+SELECT 1234 AS rule;
+ rule 
+------
+ 1234
+(1 row)
+
+SELECT 1234 rule;
+ERROR:  syntax error at or near "rule"
+LINE 1: SELECT 1234 rule;
+                    ^
+SELECT 1234 AS savepoint;
+ savepoint 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 savepoint;
+ERROR:  syntax error at or near "savepoint"
+LINE 1: SELECT 1234 savepoint;
+                    ^
+SELECT 1234 AS schema;
+ schema 
+--------
+   1234
+(1 row)
+
+SELECT 1234 schema;
+ERROR:  syntax error at or near "schema"
+LINE 1: SELECT 1234 schema;
+                    ^
+SELECT 1234 AS schemas;
+ schemas 
+---------
+    1234
+(1 row)
+
+SELECT 1234 schemas;
+ERROR:  syntax error at or near "schemas"
+LINE 1: SELECT 1234 schemas;
+                    ^
+SELECT 1234 AS scroll;
+ scroll 
+--------
+   1234
+(1 row)
+
+SELECT 1234 scroll;
+ERROR:  syntax error at or near "scroll"
+LINE 1: SELECT 1234 scroll;
+                    ^
+SELECT 1234 AS search;
+ search 
+--------
+   1234
+(1 row)
+
+SELECT 1234 search;
+ERROR:  syntax error at or near "search"
+LINE 1: SELECT 1234 search;
+                    ^
+SELECT 1234 AS second;
+ second 
+--------
+   1234
+(1 row)
+
+SELECT 1234 second;
+ERROR:  syntax error at or near "second"
+LINE 1: SELECT 1234 second;
+                    ^
+SELECT 1234 AS security;
+ security 
+----------
+     1234
+(1 row)
+
+SELECT 1234 security;
+ERROR:  syntax error at or near "security"
+LINE 1: SELECT 1234 security;
+                    ^
+SELECT 1234 AS sequence;
+ sequence 
+----------
+     1234
+(1 row)
+
+SELECT 1234 sequence;
+ERROR:  syntax error at or near "sequence"
+LINE 1: SELECT 1234 sequence;
+                    ^
+SELECT 1234 AS sequences;
+ sequences 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 sequences;
+ERROR:  syntax error at or near "sequences"
+LINE 1: SELECT 1234 sequences;
+                    ^
+SELECT 1234 AS serializable;
+ serializable 
+--------------
+         1234
+(1 row)
+
+SELECT 1234 serializable;
+ERROR:  syntax error at or near "serializable"
+LINE 1: SELECT 1234 serializable;
+                    ^
+SELECT 1234 AS server;
+ server 
+--------
+   1234
+(1 row)
+
+SELECT 1234 server;
+ERROR:  syntax error at or near "server"
+LINE 1: SELECT 1234 server;
+                    ^
+SELECT 1234 AS session;
+ session 
+---------
+    1234
+(1 row)
+
+SELECT 1234 session;
+ERROR:  syntax error at or near "session"
+LINE 1: SELECT 1234 session;
+                    ^
+SELECT 1234 AS set;
+ set  
+------
+ 1234
+(1 row)
+
+SELECT 1234 set;
+ERROR:  syntax error at or near "set"
+LINE 1: SELECT 1234 set;
+                    ^
+SELECT 1234 AS sets;
+ sets 
+------
+ 1234
+(1 row)
+
+SELECT 1234 sets;
+ERROR:  syntax error at or near "sets"
+LINE 1: SELECT 1234 sets;
+                    ^
+SELECT 1234 AS share;
+ share 
+-------
+  1234
+(1 row)
+
+SELECT 1234 share;
+ERROR:  syntax error at or near "share"
+LINE 1: SELECT 1234 share;
+                    ^
+SELECT 1234 AS show;
+ show 
+------
+ 1234
+(1 row)
+
+SELECT 1234 show;
+ERROR:  syntax error at or near "show"
+LINE 1: SELECT 1234 show;
+                    ^
+SELECT 1234 AS simple;
+ simple 
+--------
+   1234
+(1 row)
+
+SELECT 1234 simple;
+ERROR:  syntax error at or near "simple"
+LINE 1: SELECT 1234 simple;
+                    ^
+SELECT 1234 AS skip;
+ skip 
+------
+ 1234
+(1 row)
+
+SELECT 1234 skip;
+ERROR:  syntax error at or near "skip"
+LINE 1: SELECT 1234 skip;
+                    ^
+SELECT 1234 AS snapshot;
+ snapshot 
+----------
+     1234
+(1 row)
+
+SELECT 1234 snapshot;
+ERROR:  syntax error at or near "snapshot"
+LINE 1: SELECT 1234 snapshot;
+                    ^
+SELECT 1234 AS sql;
+ sql  
+------
+ 1234
+(1 row)
+
+SELECT 1234 sql;
+ERROR:  syntax error at or near "sql"
+LINE 1: SELECT 1234 sql;
+                    ^
+SELECT 1234 AS stable;
+ stable 
+--------
+   1234
+(1 row)
+
+SELECT 1234 stable;
+ERROR:  syntax error at or near "stable"
+LINE 1: SELECT 1234 stable;
+                    ^
+SELECT 1234 AS standalone;
+ standalone 
+------------
+       1234
+(1 row)
+
+SELECT 1234 standalone;
+ERROR:  syntax error at or near "standalone"
+LINE 1: SELECT 1234 standalone;
+                    ^
+SELECT 1234 AS start;
+ start 
+-------
+  1234
+(1 row)
+
+SELECT 1234 start;
+ERROR:  syntax error at or near "start"
+LINE 1: SELECT 1234 start;
+                    ^
+SELECT 1234 AS statement;
+ statement 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 statement;
+ERROR:  syntax error at or near "statement"
+LINE 1: SELECT 1234 statement;
+                    ^
+SELECT 1234 AS statistics;
+ statistics 
+------------
+       1234
+(1 row)
+
+SELECT 1234 statistics;
+ERROR:  syntax error at or near "statistics"
+LINE 1: SELECT 1234 statistics;
+                    ^
+SELECT 1234 AS stdin;
+ stdin 
+-------
+  1234
+(1 row)
+
+SELECT 1234 stdin;
+ERROR:  syntax error at or near "stdin"
+LINE 1: SELECT 1234 stdin;
+                    ^
+SELECT 1234 AS stdout;
+ stdout 
+--------
+   1234
+(1 row)
+
+SELECT 1234 stdout;
+ERROR:  syntax error at or near "stdout"
+LINE 1: SELECT 1234 stdout;
+                    ^
+SELECT 1234 AS storage;
+ storage 
+---------
+    1234
+(1 row)
+
+SELECT 1234 storage;
+ERROR:  syntax error at or near "storage"
+LINE 1: SELECT 1234 storage;
+                    ^
+SELECT 1234 AS stored;
+ stored 
+--------
+   1234
+(1 row)
+
+SELECT 1234 stored;
+ERROR:  syntax error at or near "stored"
+LINE 1: SELECT 1234 stored;
+                    ^
+SELECT 1234 AS strict;
+ strict 
+--------
+   1234
+(1 row)
+
+SELECT 1234 strict;
+ERROR:  syntax error at or near "strict"
+LINE 1: SELECT 1234 strict;
+                    ^
+SELECT 1234 AS strip;
+ strip 
+-------
+  1234
+(1 row)
+
+SELECT 1234 strip;
+ERROR:  syntax error at or near "strip"
+LINE 1: SELECT 1234 strip;
+                    ^
+SELECT 1234 AS subscription;
+ subscription 
+--------------
+         1234
+(1 row)
+
+SELECT 1234 subscription;
+ERROR:  syntax error at or near "subscription"
+LINE 1: SELECT 1234 subscription;
+                    ^
+SELECT 1234 AS support;
+ support 
+---------
+    1234
+(1 row)
+
+SELECT 1234 support;
+ERROR:  syntax error at or near "support"
+LINE 1: SELECT 1234 support;
+                    ^
+SELECT 1234 AS sysid;
+ sysid 
+-------
+  1234
+(1 row)
+
+SELECT 1234 sysid;
+ERROR:  syntax error at or near "sysid"
+LINE 1: SELECT 1234 sysid;
+                    ^
+SELECT 1234 AS system;
+ system 
+--------
+   1234
+(1 row)
+
+SELECT 1234 system;
+ERROR:  syntax error at or near "system"
+LINE 1: SELECT 1234 system;
+                    ^
+SELECT 1234 AS tables;
+ tables 
+--------
+   1234
+(1 row)
+
+SELECT 1234 tables;
+ERROR:  syntax error at or near "tables"
+LINE 1: SELECT 1234 tables;
+                    ^
+SELECT 1234 AS tablespace;
+ tablespace 
+------------
+       1234
+(1 row)
+
+SELECT 1234 tablespace;
+ERROR:  syntax error at or near "tablespace"
+LINE 1: SELECT 1234 tablespace;
+                    ^
+SELECT 1234 AS temp;
+ temp 
+------
+ 1234
+(1 row)
+
+SELECT 1234 temp;
+ERROR:  syntax error at or near "temp"
+LINE 1: SELECT 1234 temp;
+                    ^
+SELECT 1234 AS template;
+ template 
+----------
+     1234
+(1 row)
+
+SELECT 1234 template;
+ERROR:  syntax error at or near "template"
+LINE 1: SELECT 1234 template;
+                    ^
+SELECT 1234 AS temporary;
+ temporary 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 temporary;
+ERROR:  syntax error at or near "temporary"
+LINE 1: SELECT 1234 temporary;
+                    ^
+SELECT 1234 AS text;
+ text 
+------
+ 1234
+(1 row)
+
+SELECT 1234 text;
+ERROR:  syntax error at or near "text"
+LINE 1: SELECT 1234 text;
+                    ^
+SELECT 1234 AS ties;
+ ties 
+------
+ 1234
+(1 row)
+
+SELECT 1234 ties;
+ERROR:  syntax error at or near "ties"
+LINE 1: SELECT 1234 ties;
+                    ^
+SELECT 1234 AS transaction;
+ transaction 
+-------------
+        1234
+(1 row)
+
+SELECT 1234 transaction;
+ERROR:  syntax error at or near "transaction"
+LINE 1: SELECT 1234 transaction;
+                    ^
+SELECT 1234 AS transform;
+ transform 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 transform;
+ERROR:  syntax error at or near "transform"
+LINE 1: SELECT 1234 transform;
+                    ^
+SELECT 1234 AS trigger;
+ trigger 
+---------
+    1234
+(1 row)
+
+SELECT 1234 trigger;
+ERROR:  syntax error at or near "trigger"
+LINE 1: SELECT 1234 trigger;
+                    ^
+SELECT 1234 AS truncate;
+ truncate 
+----------
+     1234
+(1 row)
+
+SELECT 1234 truncate;
+ERROR:  syntax error at or near "truncate"
+LINE 1: SELECT 1234 truncate;
+                    ^
+SELECT 1234 AS trusted;
+ trusted 
+---------
+    1234
+(1 row)
+
+SELECT 1234 trusted;
+ERROR:  syntax error at or near "trusted"
+LINE 1: SELECT 1234 trusted;
+                    ^
+SELECT 1234 AS type;
+ type 
+------
+ 1234
+(1 row)
+
+SELECT 1234 type;
+ERROR:  syntax error at or near "type"
+LINE 1: SELECT 1234 type;
+                    ^
+SELECT 1234 AS types;
+ types 
+-------
+  1234
+(1 row)
+
+SELECT 1234 types;
+ERROR:  syntax error at or near "types"
+LINE 1: SELECT 1234 types;
+                    ^
+SELECT 1234 AS uescape;
+ uescape 
+---------
+    1234
+(1 row)
+
+SELECT 1234 uescape;
+ERROR:  syntax error at or near "uescape"
+LINE 1: SELECT 1234 uescape;
+                    ^
+SELECT 1234 AS unbounded;
+ unbounded 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 unbounded;
+ERROR:  syntax error at or near "unbounded"
+LINE 1: SELECT 1234 unbounded;
+                    ^
+SELECT 1234 AS uncommitted;
+ uncommitted 
+-------------
+        1234
+(1 row)
+
+SELECT 1234 uncommitted;
+ERROR:  syntax error at or near "uncommitted"
+LINE 1: SELECT 1234 uncommitted;
+                    ^
+SELECT 1234 AS unencrypted;
+ unencrypted 
+-------------
+        1234
+(1 row)
+
+SELECT 1234 unencrypted;
+ERROR:  syntax error at or near "unencrypted"
+LINE 1: SELECT 1234 unencrypted;
+                    ^
+SELECT 1234 AS unknown;
+ unknown 
+---------
+    1234
+(1 row)
+
+SELECT 1234 unknown;
+ERROR:  syntax error at or near "unknown"
+LINE 1: SELECT 1234 unknown;
+                    ^
+SELECT 1234 AS unlisten;
+ unlisten 
+----------
+     1234
+(1 row)
+
+SELECT 1234 unlisten;
+ERROR:  syntax error at or near "unlisten"
+LINE 1: SELECT 1234 unlisten;
+                    ^
+SELECT 1234 AS unlogged;
+ unlogged 
+----------
+     1234
+(1 row)
+
+SELECT 1234 unlogged;
+ERROR:  syntax error at or near "unlogged"
+LINE 1: SELECT 1234 unlogged;
+                    ^
+SELECT 1234 AS until;
+ until 
+-------
+  1234
+(1 row)
+
+SELECT 1234 until;
+ERROR:  syntax error at or near "until"
+LINE 1: SELECT 1234 until;
+                    ^
+SELECT 1234 AS update;
+ update 
+--------
+   1234
+(1 row)
+
+SELECT 1234 update;
+ERROR:  syntax error at or near "update"
+LINE 1: SELECT 1234 update;
+                    ^
+SELECT 1234 AS vacuum;
+ vacuum 
+--------
+   1234
+(1 row)
+
+SELECT 1234 vacuum;
+ERROR:  syntax error at or near "vacuum"
+LINE 1: SELECT 1234 vacuum;
+                    ^
+SELECT 1234 AS valid;
+ valid 
+-------
+  1234
+(1 row)
+
+SELECT 1234 valid;
+ERROR:  syntax error at or near "valid"
+LINE 1: SELECT 1234 valid;
+                    ^
+SELECT 1234 AS validate;
+ validate 
+----------
+     1234
+(1 row)
+
+SELECT 1234 validate;
+ERROR:  syntax error at or near "validate"
+LINE 1: SELECT 1234 validate;
+                    ^
+SELECT 1234 AS validator;
+ validator 
+-----------
+      1234
+(1 row)
+
+SELECT 1234 validator;
+ERROR:  syntax error at or near "validator"
+LINE 1: SELECT 1234 validator;
+                    ^
+SELECT 1234 AS value;
+ value 
+-------
+  1234
+(1 row)
+
+SELECT 1234 value;
+ERROR:  syntax error at or near "value"
+LINE 1: SELECT 1234 value;
+                    ^
+SELECT 1234 AS varying;
+ varying 
+---------
+    1234
+(1 row)
+
+SELECT 1234 varying;
+ERROR:  syntax error at or near "varying"
+LINE 1: SELECT 1234 varying;
+                    ^
+SELECT 1234 AS version;
+ version 
+---------
+    1234
+(1 row)
+
+SELECT 1234 version;
+ERROR:  syntax error at or near "version"
+LINE 1: SELECT 1234 version;
+                    ^
+SELECT 1234 AS view;
+ view 
+------
+ 1234
+(1 row)
+
+SELECT 1234 view;
+ERROR:  syntax error at or near "view"
+LINE 1: SELECT 1234 view;
+                    ^
+SELECT 1234 AS views;
+ views 
+-------
+  1234
+(1 row)
+
+SELECT 1234 views;
+ERROR:  syntax error at or near "views"
+LINE 1: SELECT 1234 views;
+                    ^
+SELECT 1234 AS volatile;
+ volatile 
+----------
+     1234
+(1 row)
+
+SELECT 1234 volatile;
+ERROR:  syntax error at or near "volatile"
+LINE 1: SELECT 1234 volatile;
+                    ^
+SELECT 1234 AS whitespace;
+ whitespace 
+------------
+       1234
+(1 row)
+
+SELECT 1234 whitespace;
+ERROR:  syntax error at or near "whitespace"
+LINE 1: SELECT 1234 whitespace;
+                    ^
+SELECT 1234 AS within;
+ within 
+--------
+   1234
+(1 row)
+
+SELECT 1234 within;
+ERROR:  syntax error at or near "within"
+LINE 1: SELECT 1234 within;
+                    ^
+SELECT 1234 AS without;
+ without 
+---------
+    1234
+(1 row)
+
+SELECT 1234 without;
+ERROR:  syntax error at or near "without"
+LINE 1: SELECT 1234 without;
+                    ^
+SELECT 1234 AS work;
+ work 
+------
+ 1234
+(1 row)
+
+SELECT 1234 work;
+ERROR:  syntax error at or near "work"
+LINE 1: SELECT 1234 work;
+                    ^
+SELECT 1234 AS wrapper;
+ wrapper 
+---------
+    1234
+(1 row)
+
+SELECT 1234 wrapper;
+ERROR:  syntax error at or near "wrapper"
+LINE 1: SELECT 1234 wrapper;
+                    ^
+SELECT 1234 AS write;
+ write 
+-------
+  1234
+(1 row)
+
+SELECT 1234 write;
+ERROR:  syntax error at or near "write"
+LINE 1: SELECT 1234 write;
+                    ^
+SELECT 1234 AS xml;
+ xml  
+------
+ 1234
+(1 row)
+
+SELECT 1234 xml;
+ERROR:  syntax error at or near "xml"
+LINE 1: SELECT 1234 xml;
+                    ^
+SELECT 1234 AS year;
+ year 
+------
+ 1234
+(1 row)
+
+SELECT 1234 year;
+ERROR:  syntax error at or near "year"
+LINE 1: SELECT 1234 year;
+                    ^
+SELECT 1234 AS yes;
+ yes  
+------
+ 1234
+(1 row)
+
+SELECT 1234 yes;
+ERROR:  syntax error at or near "yes"
+LINE 1: SELECT 1234 yes;
+                    ^
+SELECT 1234 AS zone;
+ zone 
+------
+ 1234
+(1 row)
+
+SELECT 1234 zone;
+ERROR:  syntax error at or near "zone"
+LINE 1: SELECT 1234 zone;
+                    ^
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 026ea880cd..2c10fbb830 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -43,7 +43,7 @@ test: create_function_2
 # execute two copy tests parallel, to check that copy itself
 # is concurrent safe.
 # ----------
-test: copy copyselect copydml insert insert_conflict
+test: as copy copyselect copydml insert insert_conflict
 
 # ----------
 # More groups of parallel tests
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index 979d926119..21a372f2b1 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -1,6 +1,7 @@
 # src/test/regress/serial_schedule
 # This should probably be in an order similar to parallel_schedule.
 test: tablespace
+test: as
 test: boolean
 test: char
 test: name
@@ -55,6 +56,7 @@ test: create_function_1
 test: create_type
 test: create_table
 test: create_function_2
+test: as
 test: copy
 test: copyselect
 test: copydml
diff --git a/src/test/regress/sql/as.sql b/src/test/regress/sql/as.sql
new file mode 100644
index 0000000000..a11a5de272
--- /dev/null
+++ b/src/test/regress/sql/as.sql
@@ -0,0 +1,1029 @@
+-- COL_NAME_KEYWORD keywords
+SELECT 1234 AS between;
+SELECT 1234 between;
+SELECT 1234 AS bigint;
+SELECT 1234 bigint;
+SELECT 1234 AS bit;
+SELECT 1234 bit;
+SELECT 1234 AS boolean;
+SELECT 1234 boolean;
+SELECT 1234 AS char;
+SELECT 1234 char;
+SELECT 1234 AS character;
+SELECT 1234 character;
+SELECT 1234 AS coalesce;
+SELECT 1234 coalesce;
+SELECT 1234 AS dec;
+SELECT 1234 dec;
+SELECT 1234 AS decimal;
+SELECT 1234 decimal;
+SELECT 1234 AS exists;
+SELECT 1234 exists;
+SELECT 1234 AS extract;
+SELECT 1234 extract;
+SELECT 1234 AS float;
+SELECT 1234 float;
+SELECT 1234 AS greatest;
+SELECT 1234 greatest;
+SELECT 1234 AS grouping;
+SELECT 1234 grouping;
+SELECT 1234 AS inout;
+SELECT 1234 inout;
+SELECT 1234 AS int;
+SELECT 1234 int;
+SELECT 1234 AS integer;
+SELECT 1234 integer;
+SELECT 1234 AS interval;
+SELECT 1234 interval;
+SELECT 1234 AS least;
+SELECT 1234 least;
+SELECT 1234 AS national;
+SELECT 1234 national;
+SELECT 1234 AS nchar;
+SELECT 1234 nchar;
+SELECT 1234 AS none;
+SELECT 1234 none;
+SELECT 1234 AS normalize;
+SELECT 1234 normalize;
+SELECT 1234 AS nullif;
+SELECT 1234 nullif;
+SELECT 1234 AS numeric;
+SELECT 1234 numeric;
+SELECT 1234 AS out;
+SELECT 1234 out;
+SELECT 1234 AS overlay;
+SELECT 1234 overlay;
+SELECT 1234 AS position;
+SELECT 1234 position;
+SELECT 1234 AS precision;
+SELECT 1234 precision;
+SELECT 1234 AS real;
+SELECT 1234 real;
+SELECT 1234 AS row;
+SELECT 1234 row;
+SELECT 1234 AS setof;
+SELECT 1234 setof;
+SELECT 1234 AS smallint;
+SELECT 1234 smallint;
+SELECT 1234 AS substring;
+SELECT 1234 substring;
+SELECT 1234 AS time;
+SELECT 1234 time;
+SELECT 1234 AS timestamp;
+SELECT 1234 timestamp;
+SELECT 1234 AS treat;
+SELECT 1234 treat;
+SELECT 1234 AS trim;
+SELECT 1234 trim;
+SELECT 1234 AS values;
+SELECT 1234 values;
+SELECT 1234 AS varchar;
+SELECT 1234 varchar;
+SELECT 1234 AS xmlattributes;
+SELECT 1234 xmlattributes;
+SELECT 1234 AS xmlconcat;
+SELECT 1234 xmlconcat;
+SELECT 1234 AS xmlelement;
+SELECT 1234 xmlelement;
+SELECT 1234 AS xmlexists;
+SELECT 1234 xmlexists;
+SELECT 1234 AS xmlforest;
+SELECT 1234 xmlforest;
+SELECT 1234 AS xmlnamespaces;
+SELECT 1234 xmlnamespaces;
+SELECT 1234 AS xmlparse;
+SELECT 1234 xmlparse;
+SELECT 1234 AS xmlpi;
+SELECT 1234 xmlpi;
+SELECT 1234 AS xmlroot;
+SELECT 1234 xmlroot;
+SELECT 1234 AS xmlserialize;
+SELECT 1234 xmlserialize;
+SELECT 1234 AS xmltable;
+SELECT 1234 xmltable;
+-- PL keywords
+SELECT 1234 AS alias;
+SELECT 1234 alias;
+SELECT 1234 AS assert;
+SELECT 1234 assert;
+SELECT 1234 AS auto;
+SELECT 1234 auto;
+SELECT 1234 AS bool;
+SELECT 1234 bool;
+SELECT 1234 AS column_name;
+SELECT 1234 column_name;
+SELECT 1234 AS const;
+SELECT 1234 const;
+SELECT 1234 AS constant;
+SELECT 1234 constant;
+SELECT 1234 AS constraint_name;
+SELECT 1234 constraint_name;
+SELECT 1234 AS datatype;
+SELECT 1234 datatype;
+SELECT 1234 AS debug;
+SELECT 1234 debug;
+SELECT 1234 AS detail;
+SELECT 1234 detail;
+SELECT 1234 AS diagnostics;
+SELECT 1234 diagnostics;
+SELECT 1234 AS dump;
+SELECT 1234 dump;
+SELECT 1234 AS elseif;
+SELECT 1234 elseif;
+SELECT 1234 AS elsif;
+SELECT 1234 elsif;
+SELECT 1234 AS errcode;
+SELECT 1234 errcode;
+SELECT 1234 AS error;
+SELECT 1234 error;
+SELECT 1234 AS exception;
+SELECT 1234 exception;
+SELECT 1234 AS exit;
+SELECT 1234 exit;
+SELECT 1234 AS extern;
+SELECT 1234 extern;
+SELECT 1234 AS foreach;
+SELECT 1234 foreach;
+SELECT 1234 AS get;
+SELECT 1234 get;
+SELECT 1234 AS hint;
+SELECT 1234 hint;
+SELECT 1234 AS info;
+SELECT 1234 info;
+SELECT 1234 AS log;
+SELECT 1234 log;
+SELECT 1234 AS long;
+SELECT 1234 long;
+SELECT 1234 AS loop;
+SELECT 1234 loop;
+SELECT 1234 AS message;
+SELECT 1234 message;
+SELECT 1234 AS message_text;
+SELECT 1234 message_text;
+SELECT 1234 AS notice;
+SELECT 1234 notice;
+SELECT 1234 AS open;
+SELECT 1234 open;
+SELECT 1234 AS perform;
+SELECT 1234 perform;
+SELECT 1234 AS pg_context;
+SELECT 1234 pg_context;
+SELECT 1234 AS pg_datatype_name;
+SELECT 1234 pg_datatype_name;
+SELECT 1234 AS pg_exception_context;
+SELECT 1234 pg_exception_context;
+SELECT 1234 AS pg_exception_detail;
+SELECT 1234 pg_exception_detail;
+SELECT 1234 AS pg_exception_hint;
+SELECT 1234 pg_exception_hint;
+SELECT 1234 AS print_strict_params;
+SELECT 1234 print_strict_params;
+SELECT 1234 AS query;
+SELECT 1234 query;
+SELECT 1234 AS raise;
+SELECT 1234 raise;
+SELECT 1234 AS register;
+SELECT 1234 register;
+SELECT 1234 AS return;
+SELECT 1234 return;
+SELECT 1234 AS returned_sqlstate;
+SELECT 1234 returned_sqlstate;
+SELECT 1234 AS reverse;
+SELECT 1234 reverse;
+SELECT 1234 AS row_count;
+SELECT 1234 row_count;
+SELECT 1234 AS rowtype;
+SELECT 1234 rowtype;
+SELECT 1234 AS schema_name;
+SELECT 1234 schema_name;
+SELECT 1234 AS short;
+SELECT 1234 short;
+SELECT 1234 AS signed;
+SELECT 1234 signed;
+SELECT 1234 AS slice;
+SELECT 1234 slice;
+SELECT 1234 AS sqlstate;
+SELECT 1234 sqlstate;
+SELECT 1234 AS stacked;
+SELECT 1234 stacked;
+SELECT 1234 AS static;
+SELECT 1234 static;
+SELECT 1234 AS struct;
+SELECT 1234 struct;
+SELECT 1234 AS table_name;
+SELECT 1234 table_name;
+SELECT 1234 AS typedef;
+SELECT 1234 typedef;
+SELECT 1234 AS unsigned;
+SELECT 1234 unsigned;
+SELECT 1234 AS use_column;
+SELECT 1234 use_column;
+SELECT 1234 AS use_variable;
+SELECT 1234 use_variable;
+SELECT 1234 AS variable_conflict;
+SELECT 1234 variable_conflict;
+SELECT 1234 AS warning;
+SELECT 1234 warning;
+SELECT 1234 AS while;
+SELECT 1234 while;
+-- RESERVED_KEYWORD keywords
+SELECT 1234 AS all;
+SELECT 1234 all;
+SELECT 1234 AS analyse;
+SELECT 1234 analyse;
+SELECT 1234 AS analyze;
+SELECT 1234 analyze;
+SELECT 1234 AS and;
+SELECT 1234 and;
+SELECT 1234 AS any;
+SELECT 1234 any;
+SELECT 1234 AS array;
+SELECT 1234 array;
+SELECT 1234 AS as;
+SELECT 1234 as;
+SELECT 1234 AS asc;
+SELECT 1234 asc;
+SELECT 1234 AS asymmetric;
+SELECT 1234 asymmetric;
+SELECT 1234 AS both;
+SELECT 1234 both;
+SELECT 1234 AS case;
+SELECT 1234 case;
+SELECT 1234 AS cast;
+SELECT 1234 cast;
+SELECT 1234 AS check;
+SELECT 1234 check;
+SELECT 1234 AS collate;
+SELECT 1234 collate;
+SELECT 1234 AS column;
+SELECT 1234 column;
+SELECT 1234 AS constraint;
+SELECT 1234 constraint;
+SELECT 1234 AS create;
+SELECT 1234 create;
+SELECT 1234 AS current_catalog;
+SELECT 1234 current_catalog;
+SELECT 1234 AS current_date;
+SELECT 1234 current_date;
+SELECT 1234 AS current_role;
+SELECT 1234 current_role;
+SELECT 1234 AS current_time;
+SELECT 1234 current_time;
+SELECT 1234 AS current_timestamp;
+SELECT 1234 current_timestamp;
+SELECT 1234 AS current_user;
+SELECT 1234 current_user;
+SELECT 1234 AS default;
+SELECT 1234 default;
+SELECT 1234 AS deferrable;
+SELECT 1234 deferrable;
+SELECT 1234 AS desc;
+SELECT 1234 desc;
+SELECT 1234 AS distinct;
+SELECT 1234 distinct;
+SELECT 1234 AS do;
+SELECT 1234 do;
+SELECT 1234 AS else;
+SELECT 1234 else;
+SELECT 1234 AS end;
+SELECT 1234 end;
+SELECT 1234 AS except;
+SELECT 1234 except;
+SELECT 1234 AS false;
+SELECT 1234 false;
+SELECT 1234 AS fetch;
+SELECT 1234 fetch;
+SELECT 1234 AS for;
+SELECT 1234 for;
+SELECT 1234 AS foreign;
+SELECT 1234 foreign;
+SELECT 1234 AS from;
+SELECT 1234 from;
+SELECT 1234 AS grant;
+SELECT 1234 grant;
+SELECT 1234 AS group;
+SELECT 1234 group;
+SELECT 1234 AS having;
+SELECT 1234 having;
+SELECT 1234 AS in;
+SELECT 1234 in;
+SELECT 1234 AS initially;
+SELECT 1234 initially;
+SELECT 1234 AS intersect;
+SELECT 1234 intersect;
+SELECT 1234 AS into;
+SELECT 1234 into;
+SELECT 1234 AS lateral;
+SELECT 1234 lateral;
+SELECT 1234 AS leading;
+SELECT 1234 leading;
+SELECT 1234 AS limit;
+SELECT 1234 limit;
+SELECT 1234 AS localtime;
+SELECT 1234 localtime;
+SELECT 1234 AS localtimestamp;
+SELECT 1234 localtimestamp;
+SELECT 1234 AS not;
+SELECT 1234 not;
+SELECT 1234 AS null;
+SELECT 1234 null;
+SELECT 1234 AS offset;
+SELECT 1234 offset;
+SELECT 1234 AS on;
+SELECT 1234 on;
+SELECT 1234 AS only;
+SELECT 1234 only;
+SELECT 1234 AS or;
+SELECT 1234 or;
+SELECT 1234 AS order;
+SELECT 1234 order;
+SELECT 1234 AS placing;
+SELECT 1234 placing;
+SELECT 1234 AS primary;
+SELECT 1234 primary;
+SELECT 1234 AS references;
+SELECT 1234 references;
+SELECT 1234 AS returning;
+SELECT 1234 returning;
+SELECT 1234 AS select;
+SELECT 1234 select;
+SELECT 1234 AS session_user;
+SELECT 1234 session_user;
+SELECT 1234 AS some;
+SELECT 1234 some;
+SELECT 1234 AS symmetric;
+SELECT 1234 symmetric;
+SELECT 1234 AS table;
+SELECT 1234 table;
+SELECT 1234 AS then;
+SELECT 1234 then;
+SELECT 1234 AS to;
+SELECT 1234 to;
+SELECT 1234 AS trailing;
+SELECT 1234 trailing;
+SELECT 1234 AS true;
+SELECT 1234 true;
+SELECT 1234 AS union;
+SELECT 1234 union;
+SELECT 1234 AS unique;
+SELECT 1234 unique;
+SELECT 1234 AS user;
+SELECT 1234 user;
+SELECT 1234 AS using;
+SELECT 1234 using;
+SELECT 1234 AS variadic;
+SELECT 1234 variadic;
+SELECT 1234 AS when;
+SELECT 1234 when;
+SELECT 1234 AS where;
+SELECT 1234 where;
+SELECT 1234 AS window;
+SELECT 1234 window;
+SELECT 1234 AS with;
+SELECT 1234 with;
+-- TYPE_FUNC_NAME_KEYWORD keywords
+SELECT 1234 AS authorization;
+SELECT 1234 authorization;
+SELECT 1234 AS binary;
+SELECT 1234 binary;
+SELECT 1234 AS collation;
+SELECT 1234 collation;
+SELECT 1234 AS concurrently;
+SELECT 1234 concurrently;
+SELECT 1234 AS cross;
+SELECT 1234 cross;
+SELECT 1234 AS current_schema;
+SELECT 1234 current_schema;
+SELECT 1234 AS freeze;
+SELECT 1234 freeze;
+SELECT 1234 AS full;
+SELECT 1234 full;
+SELECT 1234 AS ilike;
+SELECT 1234 ilike;
+SELECT 1234 AS inner;
+SELECT 1234 inner;
+SELECT 1234 AS is;
+SELECT 1234 is;
+SELECT 1234 AS isnull;
+SELECT 1234 isnull;
+SELECT 1234 AS join;
+SELECT 1234 join;
+SELECT 1234 AS left;
+SELECT 1234 left;
+SELECT 1234 AS like;
+SELECT 1234 like;
+SELECT 1234 AS natural;
+SELECT 1234 natural;
+SELECT 1234 AS notnull;
+SELECT 1234 notnull;
+SELECT 1234 AS outer;
+SELECT 1234 outer;
+SELECT 1234 AS overlaps;
+SELECT 1234 overlaps;
+SELECT 1234 AS right;
+SELECT 1234 right;
+SELECT 1234 AS similar;
+SELECT 1234 similar;
+SELECT 1234 AS tablesample;
+SELECT 1234 tablesample;
+SELECT 1234 AS verbose;
+SELECT 1234 verbose;
+-- UNRESERVED_KEYWORD keywords
+SELECT 1234 AS abort;
+SELECT 1234 abort;
+SELECT 1234 AS absolute;
+SELECT 1234 absolute;
+SELECT 1234 AS access;
+SELECT 1234 access;
+SELECT 1234 AS action;
+SELECT 1234 action;
+SELECT 1234 AS add;
+SELECT 1234 add;
+SELECT 1234 AS admin;
+SELECT 1234 admin;
+SELECT 1234 AS after;
+SELECT 1234 after;
+SELECT 1234 AS aggregate;
+SELECT 1234 aggregate;
+SELECT 1234 AS also;
+SELECT 1234 also;
+SELECT 1234 AS alter;
+SELECT 1234 alter;
+SELECT 1234 AS always;
+SELECT 1234 always;
+SELECT 1234 AS assertion;
+SELECT 1234 assertion;
+SELECT 1234 AS assignment;
+SELECT 1234 assignment;
+SELECT 1234 AS at;
+SELECT 1234 at;
+SELECT 1234 AS attach;
+SELECT 1234 attach;
+SELECT 1234 AS attribute;
+SELECT 1234 attribute;
+SELECT 1234 AS backward;
+SELECT 1234 backward;
+SELECT 1234 AS before;
+SELECT 1234 before;
+SELECT 1234 AS begin;
+SELECT 1234 begin;
+SELECT 1234 AS by;
+SELECT 1234 by;
+SELECT 1234 AS cache;
+SELECT 1234 cache;
+SELECT 1234 AS call;
+SELECT 1234 call;
+SELECT 1234 AS called;
+SELECT 1234 called;
+SELECT 1234 AS cascade;
+SELECT 1234 cascade;
+SELECT 1234 AS cascaded;
+SELECT 1234 cascaded;
+SELECT 1234 AS catalog;
+SELECT 1234 catalog;
+SELECT 1234 AS chain;
+SELECT 1234 chain;
+SELECT 1234 AS characteristics;
+SELECT 1234 characteristics;
+SELECT 1234 AS checkpoint;
+SELECT 1234 checkpoint;
+SELECT 1234 AS class;
+SELECT 1234 class;
+SELECT 1234 AS close;
+SELECT 1234 close;
+SELECT 1234 AS cluster;
+SELECT 1234 cluster;
+SELECT 1234 AS columns;
+SELECT 1234 columns;
+SELECT 1234 AS comment;
+SELECT 1234 comment;
+SELECT 1234 AS comments;
+SELECT 1234 comments;
+SELECT 1234 AS commit;
+SELECT 1234 commit;
+SELECT 1234 AS committed;
+SELECT 1234 committed;
+SELECT 1234 AS configuration;
+SELECT 1234 configuration;
+SELECT 1234 AS conflict;
+SELECT 1234 conflict;
+SELECT 1234 AS connection;
+SELECT 1234 connection;
+SELECT 1234 AS constraints;
+SELECT 1234 constraints;
+SELECT 1234 AS content;
+SELECT 1234 content;
+SELECT 1234 AS continue;
+SELECT 1234 continue;
+SELECT 1234 AS conversion;
+SELECT 1234 conversion;
+SELECT 1234 AS copy;
+SELECT 1234 copy;
+SELECT 1234 AS cost;
+SELECT 1234 cost;
+SELECT 1234 AS csv;
+SELECT 1234 csv;
+SELECT 1234 AS cube;
+SELECT 1234 cube;
+SELECT 1234 AS current;
+SELECT 1234 current;
+SELECT 1234 AS cursor;
+SELECT 1234 cursor;
+SELECT 1234 AS cycle;
+SELECT 1234 cycle;
+SELECT 1234 AS data;
+SELECT 1234 data;
+SELECT 1234 AS database;
+SELECT 1234 database;
+SELECT 1234 AS day;
+SELECT 1234 day;
+SELECT 1234 AS deallocate;
+SELECT 1234 deallocate;
+SELECT 1234 AS declare;
+SELECT 1234 declare;
+SELECT 1234 AS defaults;
+SELECT 1234 defaults;
+SELECT 1234 AS deferred;
+SELECT 1234 deferred;
+SELECT 1234 AS definer;
+SELECT 1234 definer;
+SELECT 1234 AS delete;
+SELECT 1234 delete;
+SELECT 1234 AS delimiter;
+SELECT 1234 delimiter;
+SELECT 1234 AS delimiters;
+SELECT 1234 delimiters;
+SELECT 1234 AS depends;
+SELECT 1234 depends;
+SELECT 1234 AS detach;
+SELECT 1234 detach;
+SELECT 1234 AS dictionary;
+SELECT 1234 dictionary;
+SELECT 1234 AS disable;
+SELECT 1234 disable;
+SELECT 1234 AS discard;
+SELECT 1234 discard;
+SELECT 1234 AS document;
+SELECT 1234 document;
+SELECT 1234 AS domain;
+SELECT 1234 domain;
+SELECT 1234 AS double;
+SELECT 1234 double;
+SELECT 1234 AS drop;
+SELECT 1234 drop;
+SELECT 1234 AS each;
+SELECT 1234 each;
+SELECT 1234 AS enable;
+SELECT 1234 enable;
+SELECT 1234 AS encoding;
+SELECT 1234 encoding;
+SELECT 1234 AS encrypted;
+SELECT 1234 encrypted;
+SELECT 1234 AS enum;
+SELECT 1234 enum;
+SELECT 1234 AS escape;
+SELECT 1234 escape;
+SELECT 1234 AS event;
+SELECT 1234 event;
+SELECT 1234 AS exclude;
+SELECT 1234 exclude;
+SELECT 1234 AS excluding;
+SELECT 1234 excluding;
+SELECT 1234 AS exclusive;
+SELECT 1234 exclusive;
+SELECT 1234 AS execute;
+SELECT 1234 execute;
+SELECT 1234 AS explain;
+SELECT 1234 explain;
+SELECT 1234 AS expression;
+SELECT 1234 expression;
+SELECT 1234 AS extension;
+SELECT 1234 extension;
+SELECT 1234 AS external;
+SELECT 1234 external;
+SELECT 1234 AS family;
+SELECT 1234 family;
+SELECT 1234 AS filter;
+SELECT 1234 filter;
+SELECT 1234 AS first;
+SELECT 1234 first;
+SELECT 1234 AS following;
+SELECT 1234 following;
+SELECT 1234 AS force;
+SELECT 1234 force;
+SELECT 1234 AS forward;
+SELECT 1234 forward;
+SELECT 1234 AS function;
+SELECT 1234 function;
+SELECT 1234 AS functions;
+SELECT 1234 functions;
+SELECT 1234 AS generated;
+SELECT 1234 generated;
+SELECT 1234 AS global;
+SELECT 1234 global;
+SELECT 1234 AS granted;
+SELECT 1234 granted;
+SELECT 1234 AS groups;
+SELECT 1234 groups;
+SELECT 1234 AS handler;
+SELECT 1234 handler;
+SELECT 1234 AS header;
+SELECT 1234 header;
+SELECT 1234 AS hold;
+SELECT 1234 hold;
+SELECT 1234 AS hour;
+SELECT 1234 hour;
+SELECT 1234 AS identity;
+SELECT 1234 identity;
+SELECT 1234 AS if;
+SELECT 1234 if;
+SELECT 1234 AS immediate;
+SELECT 1234 immediate;
+SELECT 1234 AS immutable;
+SELECT 1234 immutable;
+SELECT 1234 AS implicit;
+SELECT 1234 implicit;
+SELECT 1234 AS import;
+SELECT 1234 import;
+SELECT 1234 AS include;
+SELECT 1234 include;
+SELECT 1234 AS including;
+SELECT 1234 including;
+SELECT 1234 AS increment;
+SELECT 1234 increment;
+SELECT 1234 AS index;
+SELECT 1234 index;
+SELECT 1234 AS indexes;
+SELECT 1234 indexes;
+SELECT 1234 AS inherit;
+SELECT 1234 inherit;
+SELECT 1234 AS inherits;
+SELECT 1234 inherits;
+SELECT 1234 AS inline;
+SELECT 1234 inline;
+SELECT 1234 AS input;
+SELECT 1234 input;
+SELECT 1234 AS insensitive;
+SELECT 1234 insensitive;
+SELECT 1234 AS insert;
+SELECT 1234 insert;
+SELECT 1234 AS instead;
+SELECT 1234 instead;
+SELECT 1234 AS invoker;
+SELECT 1234 invoker;
+SELECT 1234 AS isolation;
+SELECT 1234 isolation;
+SELECT 1234 AS key;
+SELECT 1234 key;
+SELECT 1234 AS label;
+SELECT 1234 label;
+SELECT 1234 AS language;
+SELECT 1234 language;
+SELECT 1234 AS large;
+SELECT 1234 large;
+SELECT 1234 AS last;
+SELECT 1234 last;
+SELECT 1234 AS leakproof;
+SELECT 1234 leakproof;
+SELECT 1234 AS level;
+SELECT 1234 level;
+SELECT 1234 AS listen;
+SELECT 1234 listen;
+SELECT 1234 AS load;
+SELECT 1234 load;
+SELECT 1234 AS local;
+SELECT 1234 local;
+SELECT 1234 AS location;
+SELECT 1234 location;
+SELECT 1234 AS lock;
+SELECT 1234 lock;
+SELECT 1234 AS locked;
+SELECT 1234 locked;
+SELECT 1234 AS logged;
+SELECT 1234 logged;
+SELECT 1234 AS mapping;
+SELECT 1234 mapping;
+SELECT 1234 AS match;
+SELECT 1234 match;
+SELECT 1234 AS materialized;
+SELECT 1234 materialized;
+SELECT 1234 AS maxvalue;
+SELECT 1234 maxvalue;
+SELECT 1234 AS method;
+SELECT 1234 method;
+SELECT 1234 AS minute;
+SELECT 1234 minute;
+SELECT 1234 AS minvalue;
+SELECT 1234 minvalue;
+SELECT 1234 AS mode;
+SELECT 1234 mode;
+SELECT 1234 AS month;
+SELECT 1234 month;
+SELECT 1234 AS move;
+SELECT 1234 move;
+SELECT 1234 AS name;
+SELECT 1234 name;
+SELECT 1234 AS names;
+SELECT 1234 names;
+SELECT 1234 AS new;
+SELECT 1234 new;
+SELECT 1234 AS next;
+SELECT 1234 next;
+SELECT 1234 AS nfc;
+SELECT 1234 nfc;
+SELECT 1234 AS nfd;
+SELECT 1234 nfd;
+SELECT 1234 AS nfkc;
+SELECT 1234 nfkc;
+SELECT 1234 AS nfkd;
+SELECT 1234 nfkd;
+SELECT 1234 AS no;
+SELECT 1234 no;
+SELECT 1234 AS normalized;
+SELECT 1234 normalized;
+SELECT 1234 AS nothing;
+SELECT 1234 nothing;
+SELECT 1234 AS notify;
+SELECT 1234 notify;
+SELECT 1234 AS nowait;
+SELECT 1234 nowait;
+SELECT 1234 AS nulls;
+SELECT 1234 nulls;
+SELECT 1234 AS object;
+SELECT 1234 object;
+SELECT 1234 AS of;
+SELECT 1234 of;
+SELECT 1234 AS off;
+SELECT 1234 off;
+SELECT 1234 AS oids;
+SELECT 1234 oids;
+SELECT 1234 AS old;
+SELECT 1234 old;
+SELECT 1234 AS operator;
+SELECT 1234 operator;
+SELECT 1234 AS option;
+SELECT 1234 option;
+SELECT 1234 AS options;
+SELECT 1234 options;
+SELECT 1234 AS ordinality;
+SELECT 1234 ordinality;
+SELECT 1234 AS others;
+SELECT 1234 others;
+SELECT 1234 AS over;
+SELECT 1234 over;
+SELECT 1234 AS overriding;
+SELECT 1234 overriding;
+SELECT 1234 AS owned;
+SELECT 1234 owned;
+SELECT 1234 AS owner;
+SELECT 1234 owner;
+SELECT 1234 AS parallel;
+SELECT 1234 parallel;
+SELECT 1234 AS parser;
+SELECT 1234 parser;
+SELECT 1234 AS partial;
+SELECT 1234 partial;
+SELECT 1234 AS partition;
+SELECT 1234 partition;
+SELECT 1234 AS passing;
+SELECT 1234 passing;
+SELECT 1234 AS password;
+SELECT 1234 password;
+SELECT 1234 AS plans;
+SELECT 1234 plans;
+SELECT 1234 AS policy;
+SELECT 1234 policy;
+SELECT 1234 AS preceding;
+SELECT 1234 preceding;
+SELECT 1234 AS prepare;
+SELECT 1234 prepare;
+SELECT 1234 AS prepared;
+SELECT 1234 prepared;
+SELECT 1234 AS preserve;
+SELECT 1234 preserve;
+SELECT 1234 AS prior;
+SELECT 1234 prior;
+SELECT 1234 AS privileges;
+SELECT 1234 privileges;
+SELECT 1234 AS procedural;
+SELECT 1234 procedural;
+SELECT 1234 AS procedure;
+SELECT 1234 procedure;
+SELECT 1234 AS procedures;
+SELECT 1234 procedures;
+SELECT 1234 AS program;
+SELECT 1234 program;
+SELECT 1234 AS publication;
+SELECT 1234 publication;
+SELECT 1234 AS quote;
+SELECT 1234 quote;
+SELECT 1234 AS range;
+SELECT 1234 range;
+SELECT 1234 AS read;
+SELECT 1234 read;
+SELECT 1234 AS reassign;
+SELECT 1234 reassign;
+SELECT 1234 AS recheck;
+SELECT 1234 recheck;
+SELECT 1234 AS recursive;
+SELECT 1234 recursive;
+SELECT 1234 AS ref;
+SELECT 1234 ref;
+SELECT 1234 AS referencing;
+SELECT 1234 referencing;
+SELECT 1234 AS refresh;
+SELECT 1234 refresh;
+SELECT 1234 AS reindex;
+SELECT 1234 reindex;
+SELECT 1234 AS relative;
+SELECT 1234 relative;
+SELECT 1234 AS release;
+SELECT 1234 release;
+SELECT 1234 AS rename;
+SELECT 1234 rename;
+SELECT 1234 AS repeatable;
+SELECT 1234 repeatable;
+SELECT 1234 AS replace;
+SELECT 1234 replace;
+SELECT 1234 AS replica;
+SELECT 1234 replica;
+SELECT 1234 AS reset;
+SELECT 1234 reset;
+SELECT 1234 AS restart;
+SELECT 1234 restart;
+SELECT 1234 AS restrict;
+SELECT 1234 restrict;
+SELECT 1234 AS returns;
+SELECT 1234 returns;
+SELECT 1234 AS revoke;
+SELECT 1234 revoke;
+SELECT 1234 AS role;
+SELECT 1234 role;
+SELECT 1234 AS rollback;
+SELECT 1234 rollback;
+SELECT 1234 AS rollup;
+SELECT 1234 rollup;
+SELECT 1234 AS routine;
+SELECT 1234 routine;
+SELECT 1234 AS routines;
+SELECT 1234 routines;
+SELECT 1234 AS rows;
+SELECT 1234 rows;
+SELECT 1234 AS rule;
+SELECT 1234 rule;
+SELECT 1234 AS savepoint;
+SELECT 1234 savepoint;
+SELECT 1234 AS schema;
+SELECT 1234 schema;
+SELECT 1234 AS schemas;
+SELECT 1234 schemas;
+SELECT 1234 AS scroll;
+SELECT 1234 scroll;
+SELECT 1234 AS search;
+SELECT 1234 search;
+SELECT 1234 AS second;
+SELECT 1234 second;
+SELECT 1234 AS security;
+SELECT 1234 security;
+SELECT 1234 AS sequence;
+SELECT 1234 sequence;
+SELECT 1234 AS sequences;
+SELECT 1234 sequences;
+SELECT 1234 AS serializable;
+SELECT 1234 serializable;
+SELECT 1234 AS server;
+SELECT 1234 server;
+SELECT 1234 AS session;
+SELECT 1234 session;
+SELECT 1234 AS set;
+SELECT 1234 set;
+SELECT 1234 AS sets;
+SELECT 1234 sets;
+SELECT 1234 AS share;
+SELECT 1234 share;
+SELECT 1234 AS show;
+SELECT 1234 show;
+SELECT 1234 AS simple;
+SELECT 1234 simple;
+SELECT 1234 AS skip;
+SELECT 1234 skip;
+SELECT 1234 AS snapshot;
+SELECT 1234 snapshot;
+SELECT 1234 AS sql;
+SELECT 1234 sql;
+SELECT 1234 AS stable;
+SELECT 1234 stable;
+SELECT 1234 AS standalone;
+SELECT 1234 standalone;
+SELECT 1234 AS start;
+SELECT 1234 start;
+SELECT 1234 AS statement;
+SELECT 1234 statement;
+SELECT 1234 AS statistics;
+SELECT 1234 statistics;
+SELECT 1234 AS stdin;
+SELECT 1234 stdin;
+SELECT 1234 AS stdout;
+SELECT 1234 stdout;
+SELECT 1234 AS storage;
+SELECT 1234 storage;
+SELECT 1234 AS stored;
+SELECT 1234 stored;
+SELECT 1234 AS strict;
+SELECT 1234 strict;
+SELECT 1234 AS strip;
+SELECT 1234 strip;
+SELECT 1234 AS subscription;
+SELECT 1234 subscription;
+SELECT 1234 AS support;
+SELECT 1234 support;
+SELECT 1234 AS sysid;
+SELECT 1234 sysid;
+SELECT 1234 AS system;
+SELECT 1234 system;
+SELECT 1234 AS tables;
+SELECT 1234 tables;
+SELECT 1234 AS tablespace;
+SELECT 1234 tablespace;
+SELECT 1234 AS temp;
+SELECT 1234 temp;
+SELECT 1234 AS template;
+SELECT 1234 template;
+SELECT 1234 AS temporary;
+SELECT 1234 temporary;
+SELECT 1234 AS text;
+SELECT 1234 text;
+SELECT 1234 AS ties;
+SELECT 1234 ties;
+SELECT 1234 AS transaction;
+SELECT 1234 transaction;
+SELECT 1234 AS transform;
+SELECT 1234 transform;
+SELECT 1234 AS trigger;
+SELECT 1234 trigger;
+SELECT 1234 AS truncate;
+SELECT 1234 truncate;
+SELECT 1234 AS trusted;
+SELECT 1234 trusted;
+SELECT 1234 AS type;
+SELECT 1234 type;
+SELECT 1234 AS types;
+SELECT 1234 types;
+SELECT 1234 AS uescape;
+SELECT 1234 uescape;
+SELECT 1234 AS unbounded;
+SELECT 1234 unbounded;
+SELECT 1234 AS uncommitted;
+SELECT 1234 uncommitted;
+SELECT 1234 AS unencrypted;
+SELECT 1234 unencrypted;
+SELECT 1234 AS unknown;
+SELECT 1234 unknown;
+SELECT 1234 AS unlisten;
+SELECT 1234 unlisten;
+SELECT 1234 AS unlogged;
+SELECT 1234 unlogged;
+SELECT 1234 AS until;
+SELECT 1234 until;
+SELECT 1234 AS update;
+SELECT 1234 update;
+SELECT 1234 AS vacuum;
+SELECT 1234 vacuum;
+SELECT 1234 AS valid;
+SELECT 1234 valid;
+SELECT 1234 AS validate;
+SELECT 1234 validate;
+SELECT 1234 AS validator;
+SELECT 1234 validator;
+SELECT 1234 AS value;
+SELECT 1234 value;
+SELECT 1234 AS varying;
+SELECT 1234 varying;
+SELECT 1234 AS version;
+SELECT 1234 version;
+SELECT 1234 AS view;
+SELECT 1234 view;
+SELECT 1234 AS views;
+SELECT 1234 views;
+SELECT 1234 AS volatile;
+SELECT 1234 volatile;
+SELECT 1234 AS whitespace;
+SELECT 1234 whitespace;
+SELECT 1234 AS within;
+SELECT 1234 within;
+SELECT 1234 AS without;
+SELECT 1234 without;
+SELECT 1234 AS work;
+SELECT 1234 work;
+SELECT 1234 AS wrapper;
+SELECT 1234 wrapper;
+SELECT 1234 AS write;
+SELECT 1234 write;
+SELECT 1234 AS xml;
+SELECT 1234 xml;
+SELECT 1234 AS year;
+SELECT 1234 year;
+SELECT 1234 AS yes;
+SELECT 1234 yes;
+SELECT 1234 AS zone;
+SELECT 1234 zone;
-- 
2.21.1 (Apple Git-122.3)

v1-0002-Desupporting-postfix-operators.patchapplication/octet-stream; name=v1-0002-Desupporting-postfix-operators.patch; x-unix-mode=0644Download
From fbaac39256c63a6aeadd609f33b98cb264e6e532 Mon Sep 17 00:00:00 2001
From: Mark Dilger <mark.dilger@enterprisedb.com>
Date: Tue, 30 Jun 2020 11:49:07 -0700
Subject: [PATCH v1 2/2] Desupporting postfix operators.

This applies Tom's patch submitted to -hackers in message
https://www.postgresql.org/message-id/28461.1589932031%40sss.pgh.pa.us

By Tom's own admission, his patch only adjusted the grammar and not
the rest of the related issues in the code, so I have added in most
of what I think remains.

I still need to modify the docs to reflect that postfix operators
are no longer supported.

I still need to modify pg_upgrade to deal with existing postfix
operators.  What exactly should be done is not yet clear, as
dropping postfix operators from the catalogs seems the cleanest, but
not necessarily the most polite behavior in the case of user created
postfix operators that they might prefer to deal with without us
first nuking them.
---
 .../postgres_fdw/expected/postgres_fdw.out    |    8 +-
 contrib/postgres_fdw/sql/postgres_fdw.sql     |    2 +-
 src/backend/commands/operatorcmds.c           |   18 +-
 src/backend/parser/check_keywords.pl          |    1 +
 src/backend/parser/gram.y                     |   50 +-
 src/backend/utils/adt/misc.c                  |    4 +
 src/include/common/keywords.h                 |    7 +-
 src/include/parser/kwlist.h                   |   22 +-
 src/test/regress/expected/as.out              | 2310 ++++++++++-------
 src/test/regress/expected/create_operator.out |   20 +-
 src/test/regress/expected/numeric.out         |   27 +-
 src/test/regress/sql/create_operator.sql      |    2 +-
 src/test/regress/sql/numeric.sql              |   16 +-
 13 files changed, 1565 insertions(+), 922 deletions(-)

diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index 82fc1290ef..4306ae31c9 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -653,12 +653,12 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 = -c1;          -- Op
    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = (- "C 1")))
 (3 rows)
 
-EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE 1 = c1!;           -- OpExpr(r)
-                                                QUERY PLAN                                                
-----------------------------------------------------------------------------------------------------------
+EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE 1 = !!c1;          -- OpExpr(r)
+                                                QUERY PLAN                                                 
+-----------------------------------------------------------------------------------------------------------
  Foreign Scan on public.ft1 t1
    Output: c1, c2, c3, c4, c5, c6, c7, c8
-   Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE ((1::numeric = ("C 1" !)))
+   Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE ((1::numeric = (!! "C 1")))
 (3 rows)
 
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE (c1 IS NOT NULL) IS DISTINCT FROM (c1 IS NOT NULL); -- DistinctExpr
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index 83971665e3..a8e58a8f24 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -307,7 +307,7 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 IS NULL;        -- Nu
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 IS NOT NULL;    -- NullTest
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE round(abs(c1), 0) = 1; -- FuncExpr
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 = -c1;          -- OpExpr(l)
-EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE 1 = c1!;           -- OpExpr(r)
+EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE 1 = !!c1;          -- OpExpr(r)
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE (c1 IS NOT NULL) IS DISTINCT FROM (c1 IS NOT NULL); -- DistinctExpr
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 = ANY(ARRAY[c2, 1, c1 + 0]); -- ScalarArrayOpExpr
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 = (ARRAY[c1,c2,3])[1]; -- SubscriptingRef
diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c
index 0a53e9b93e..cb7ffda4bd 100644
--- a/src/backend/commands/operatorcmds.c
+++ b/src/backend/commands/operatorcmds.c
@@ -168,10 +168,26 @@ DefineOperator(List *names, List *parameters)
 	if (typeName2)
 		typeId2 = typenameTypeId(NULL, typeName2);
 
+	/*
+	 * If neither argument is specified, do not mention postfix operator
+	 * discontinuation, as the user is unlikely to have meant to create a
+	 * postfix operator.  It is more likely they simply neglected to mention
+	 * the args.
+	 */
 	if (!OidIsValid(typeId1) && !OidIsValid(typeId2))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
-				 errmsg("at least one of leftarg or rightarg must be specified")));
+				 errmsg("at least rightarg must be specified")));
+
+	/*
+	 * But if only the right arg is missing, they probably do intend to create
+	 * a postfix operator, so give them a hint about why that no longer works.
+	 */
+	if (!OidIsValid(typeId2))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+				 errmsg("rightarg must be specified"),
+				 errhint("postfix operator support has been discontinued")));
 
 	if (typeName1)
 	{
diff --git a/src/backend/parser/check_keywords.pl b/src/backend/parser/check_keywords.pl
index 702c97bba2..178f38ef6d 100644
--- a/src/backend/parser/check_keywords.pl
+++ b/src/backend/parser/check_keywords.pl
@@ -26,6 +26,7 @@ $\ = "\n";    # set output record separator
 
 my %keyword_categories;
 $keyword_categories{'unreserved_keyword'}     = 'UNRESERVED_KEYWORD';
+$keyword_categories{'non_label_keyword'}      = 'NON_LABEL_KEYWORD';
 $keyword_categories{'col_name_keyword'}       = 'COL_NAME_KEYWORD';
 $keyword_categories{'type_func_name_keyword'} = 'TYPE_FUNC_NAME_KEYWORD';
 $keyword_categories{'reserved_keyword'}       = 'RESERVED_KEYWORD';
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 4ff35095b8..a11ebebe04 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -540,13 +540,14 @@ 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> unreserved_keyword non_label_keyword type_func_name_keyword
 %type <keyword> col_name_keyword reserved_keyword
 
 %type <node>	TableConstraint TableLikeClause
@@ -741,7 +742,6 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 %nonassoc	'<' '>' '=' LESS_EQUALS GREATER_EQUALS NOT_EQUALS
 %nonassoc	BETWEEN IN_P LIKE ILIKE SIMILAR NOT_LA
 %nonassoc	ESCAPE			/* ESCAPE must be just above LIKE/ILIKE/SIMILAR */
-%left		POSTFIXOP		/* dummy for postfix Op rules */
 /*
  * To support target_el without AS, we must give IDENT an explicit priority
  * between POSTFIXOP and Op.  We can safely assign the same priority to
@@ -12989,8 +12989,6 @@ a_expr:		c_expr									{ $$ = $1; }
 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3, @2); }
 			| qual_Op a_expr					%prec Op
 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $1, NULL, $2, @1); }
-			| a_expr qual_Op					%prec POSTFIXOP
-				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, NULL, @2); }
 
 			| a_expr AND a_expr
 				{ $$ = makeAndExpr($1, $3, @2); }
@@ -13404,8 +13402,6 @@ b_expr:		c_expr
 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3, @2); }
 			| qual_Op b_expr					%prec Op
 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $1, NULL, $2, @1); }
-			| b_expr qual_Op					%prec POSTFIXOP
-				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, NULL, @2); }
 			| b_expr IS DISTINCT FROM b_expr		%prec IS
 				{
 					$$ = (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $5, @2);
@@ -14667,7 +14663,7 @@ target_el:	a_expr AS ColLabel
 			 * as an infix expression, which we accomplish by assigning
 			 * IDENT a precedence higher than POSTFIXOP.
 			 */
-			| a_expr IDENT
+			| a_expr BareColLabel
 				{
 					$$ = makeNode(ResTarget);
 					$$->name = $2;
@@ -14977,6 +14973,7 @@ role_list:	RoleSpec
  */
 ColId:		IDENT									{ $$ = $1; }
 			| unreserved_keyword					{ $$ = pstrdup($1); }
+			| non_label_keyword						{ $$ = pstrdup($1); }
 			| col_name_keyword						{ $$ = pstrdup($1); }
 		;
 
@@ -14984,6 +14981,7 @@ ColId:		IDENT									{ $$ = $1; }
  */
 type_function_name:	IDENT							{ $$ = $1; }
 			| unreserved_keyword					{ $$ = pstrdup($1); }
+			| non_label_keyword						{ $$ = pstrdup($1); }
 			| type_func_name_keyword				{ $$ = pstrdup($1); }
 		;
 
@@ -14991,15 +14989,23 @@ type_function_name:	IDENT							{ $$ = $1; }
  */
 NonReservedWord:	IDENT							{ $$ = $1; }
 			| unreserved_keyword					{ $$ = pstrdup($1); }
+			| non_label_keyword						{ $$ = pstrdup($1); }
 			| col_name_keyword						{ $$ = pstrdup($1); }
 			| type_func_name_keyword				{ $$ = pstrdup($1); }
 		;
 
+/* Bare column label --- names that can be column labels without writing "AS".
+ */
+BareColLabel:	IDENT								{ $$ = $1; }
+			| unreserved_keyword					{ $$ = pstrdup($1); }
+		;
+
 /* Column label --- allowed labels in "AS" clauses.
  * This presently includes *all* Postgres keywords.
  */
 ColLabel:	IDENT									{ $$ = $1; }
 			| unreserved_keyword					{ $$ = pstrdup($1); }
+			| non_label_keyword						{ $$ = pstrdup($1); }
 			| col_name_keyword						{ $$ = pstrdup($1); }
 			| type_func_name_keyword				{ $$ = pstrdup($1); }
 			| reserved_keyword						{ $$ = pstrdup($1); }
@@ -15075,7 +15081,6 @@ unreserved_keyword:
 			| CYCLE
 			| DATA_P
 			| DATABASE
-			| DAY_P
 			| DEALLOCATE
 			| DECLARE
 			| DEFAULTS
@@ -15109,7 +15114,6 @@ unreserved_keyword:
 			| EXTENSION
 			| EXTERNAL
 			| FAMILY
-			| FILTER
 			| FIRST_P
 			| FOLLOWING
 			| FORCE
@@ -15123,7 +15127,6 @@ unreserved_keyword:
 			| HANDLER
 			| HEADER_P
 			| HOLD
-			| HOUR_P
 			| IDENTITY_P
 			| IF_P
 			| IMMEDIATE
@@ -15163,10 +15166,8 @@ unreserved_keyword:
 			| MATERIALIZED
 			| MAXVALUE
 			| METHOD
-			| MINUTE_P
 			| MINVALUE
 			| MODE
-			| MONTH_P
 			| MOVE
 			| NAME_P
 			| NAMES
@@ -15192,7 +15193,6 @@ unreserved_keyword:
 			| OPTIONS
 			| ORDINALITY
 			| OTHERS
-			| OVER
 			| OVERRIDING
 			| OWNED
 			| OWNER
@@ -15248,7 +15248,6 @@ unreserved_keyword:
 			| SCHEMAS
 			| SCROLL
 			| SEARCH
-			| SECOND_P
 			| SECURITY
 			| SEQUENCE
 			| SEQUENCES
@@ -15306,23 +15305,36 @@ unreserved_keyword:
 			| VALIDATE
 			| VALIDATOR
 			| VALUE_P
-			| VARYING
 			| VERSION_P
 			| VIEW
 			| VIEWS
 			| VOLATILE
 			| WHITESPACE_P
-			| WITHIN
-			| WITHOUT
 			| WORK
 			| WRAPPER
 			| WRITE
 			| XML_P
-			| YEAR_P
 			| YES_P
 			| ZONE
 		;
 
+/* "Non label" keywords --- cannot be a bare column label in a SELECT list
+ * (you have to write AS in front).  Otherwise usable for anything.
+ */
+non_label_keyword:
+			DAY_P
+			| FILTER
+			| HOUR_P
+			| MINUTE_P
+			| MONTH_P
+			| OVER
+			| SECOND_P
+			| VARYING
+			| WITHIN
+			| WITHOUT
+			| YEAR_P
+		;
+
 /* Column identifier --- keywords that can be column, table, etc names.
  *
  * Many of these keywords will in fact be recognized as type or function
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index ee340fb0f0..b6d0b83fdd 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -446,6 +446,10 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 				values[1] = "U";
 				values[2] = _("unreserved");
 				break;
+			case NON_LABEL_KEYWORD:
+				values[1] = "N";
+				values[2] = _("unreserved (cannot be used as an implicit alias)");
+				break;
 			case COL_NAME_KEYWORD:
 				values[1] = "C";
 				values[2] = _("unreserved (cannot be function or type name)");
diff --git a/src/include/common/keywords.h b/src/include/common/keywords.h
index 257c050903..835126c599 100644
--- a/src/include/common/keywords.h
+++ b/src/include/common/keywords.h
@@ -18,9 +18,10 @@
 
 /* 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
+#define NON_LABEL_KEYWORD		1
+#define COL_NAME_KEYWORD		2
+#define TYPE_FUNC_NAME_KEYWORD	3
+#define RESERVED_KEYWORD		4
 
 #ifndef FRONTEND
 extern PGDLLIMPORT const ScanKeywordList ScanKeywords;
diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h
index 08f22ce211..7ab3d45fd3 100644
--- a/src/include/parser/kwlist.h
+++ b/src/include/parser/kwlist.h
@@ -114,7 +114,7 @@ PG_KEYWORD("cursor", CURSOR, UNRESERVED_KEYWORD)
 PG_KEYWORD("cycle", CYCLE, UNRESERVED_KEYWORD)
 PG_KEYWORD("data", DATA_P, UNRESERVED_KEYWORD)
 PG_KEYWORD("database", DATABASE, UNRESERVED_KEYWORD)
-PG_KEYWORD("day", DAY_P, UNRESERVED_KEYWORD)
+PG_KEYWORD("day", DAY_P, NON_LABEL_KEYWORD)
 PG_KEYWORD("deallocate", DEALLOCATE, UNRESERVED_KEYWORD)
 PG_KEYWORD("dec", DEC, COL_NAME_KEYWORD)
 PG_KEYWORD("decimal", DECIMAL_P, COL_NAME_KEYWORD)
@@ -162,7 +162,7 @@ PG_KEYWORD("extract", EXTRACT, COL_NAME_KEYWORD)
 PG_KEYWORD("false", FALSE_P, RESERVED_KEYWORD)
 PG_KEYWORD("family", FAMILY, UNRESERVED_KEYWORD)
 PG_KEYWORD("fetch", FETCH, RESERVED_KEYWORD)
-PG_KEYWORD("filter", FILTER, UNRESERVED_KEYWORD)
+PG_KEYWORD("filter", FILTER, NON_LABEL_KEYWORD)
 PG_KEYWORD("first", FIRST_P, UNRESERVED_KEYWORD)
 PG_KEYWORD("float", FLOAT_P, COL_NAME_KEYWORD)
 PG_KEYWORD("following", FOLLOWING, UNRESERVED_KEYWORD)
@@ -187,7 +187,7 @@ PG_KEYWORD("handler", HANDLER, UNRESERVED_KEYWORD)
 PG_KEYWORD("having", HAVING, RESERVED_KEYWORD)
 PG_KEYWORD("header", HEADER_P, UNRESERVED_KEYWORD)
 PG_KEYWORD("hold", HOLD, UNRESERVED_KEYWORD)
-PG_KEYWORD("hour", HOUR_P, UNRESERVED_KEYWORD)
+PG_KEYWORD("hour", HOUR_P, NON_LABEL_KEYWORD)
 PG_KEYWORD("identity", IDENTITY_P, UNRESERVED_KEYWORD)
 PG_KEYWORD("if", IF_P, UNRESERVED_KEYWORD)
 PG_KEYWORD("ilike", ILIKE, TYPE_FUNC_NAME_KEYWORD)
@@ -248,10 +248,10 @@ PG_KEYWORD("match", MATCH, UNRESERVED_KEYWORD)
 PG_KEYWORD("materialized", MATERIALIZED, UNRESERVED_KEYWORD)
 PG_KEYWORD("maxvalue", MAXVALUE, UNRESERVED_KEYWORD)
 PG_KEYWORD("method", METHOD, UNRESERVED_KEYWORD)
-PG_KEYWORD("minute", MINUTE_P, UNRESERVED_KEYWORD)
+PG_KEYWORD("minute", MINUTE_P, NON_LABEL_KEYWORD)
 PG_KEYWORD("minvalue", MINVALUE, UNRESERVED_KEYWORD)
 PG_KEYWORD("mode", MODE, UNRESERVED_KEYWORD)
-PG_KEYWORD("month", MONTH_P, UNRESERVED_KEYWORD)
+PG_KEYWORD("month", MONTH_P, NON_LABEL_KEYWORD)
 PG_KEYWORD("move", MOVE, UNRESERVED_KEYWORD)
 PG_KEYWORD("name", NAME_P, UNRESERVED_KEYWORD)
 PG_KEYWORD("names", NAMES, UNRESERVED_KEYWORD)
@@ -294,7 +294,7 @@ PG_KEYWORD("ordinality", ORDINALITY, UNRESERVED_KEYWORD)
 PG_KEYWORD("others", OTHERS, UNRESERVED_KEYWORD)
 PG_KEYWORD("out", OUT_P, COL_NAME_KEYWORD)
 PG_KEYWORD("outer", OUTER_P, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("over", OVER, UNRESERVED_KEYWORD)
+PG_KEYWORD("over", OVER, NON_LABEL_KEYWORD)
 PG_KEYWORD("overlaps", OVERLAPS, TYPE_FUNC_NAME_KEYWORD)
 PG_KEYWORD("overlay", OVERLAY, COL_NAME_KEYWORD)
 PG_KEYWORD("overriding", OVERRIDING, UNRESERVED_KEYWORD)
@@ -361,7 +361,7 @@ PG_KEYWORD("schema", SCHEMA, UNRESERVED_KEYWORD)
 PG_KEYWORD("schemas", SCHEMAS, UNRESERVED_KEYWORD)
 PG_KEYWORD("scroll", SCROLL, UNRESERVED_KEYWORD)
 PG_KEYWORD("search", SEARCH, UNRESERVED_KEYWORD)
-PG_KEYWORD("second", SECOND_P, UNRESERVED_KEYWORD)
+PG_KEYWORD("second", SECOND_P, NON_LABEL_KEYWORD)
 PG_KEYWORD("security", SECURITY, UNRESERVED_KEYWORD)
 PG_KEYWORD("select", SELECT, RESERVED_KEYWORD)
 PG_KEYWORD("sequence", SEQUENCE, UNRESERVED_KEYWORD)
@@ -444,7 +444,7 @@ PG_KEYWORD("value", VALUE_P, UNRESERVED_KEYWORD)
 PG_KEYWORD("values", VALUES, COL_NAME_KEYWORD)
 PG_KEYWORD("varchar", VARCHAR, COL_NAME_KEYWORD)
 PG_KEYWORD("variadic", VARIADIC, RESERVED_KEYWORD)
-PG_KEYWORD("varying", VARYING, UNRESERVED_KEYWORD)
+PG_KEYWORD("varying", VARYING, NON_LABEL_KEYWORD)
 PG_KEYWORD("verbose", VERBOSE, TYPE_FUNC_NAME_KEYWORD)
 PG_KEYWORD("version", VERSION_P, UNRESERVED_KEYWORD)
 PG_KEYWORD("view", VIEW, UNRESERVED_KEYWORD)
@@ -455,8 +455,8 @@ PG_KEYWORD("where", WHERE, RESERVED_KEYWORD)
 PG_KEYWORD("whitespace", WHITESPACE_P, UNRESERVED_KEYWORD)
 PG_KEYWORD("window", WINDOW, RESERVED_KEYWORD)
 PG_KEYWORD("with", WITH, RESERVED_KEYWORD)
-PG_KEYWORD("within", WITHIN, UNRESERVED_KEYWORD)
-PG_KEYWORD("without", WITHOUT, UNRESERVED_KEYWORD)
+PG_KEYWORD("within", WITHIN, NON_LABEL_KEYWORD)
+PG_KEYWORD("without", WITHOUT, NON_LABEL_KEYWORD)
 PG_KEYWORD("work", WORK, UNRESERVED_KEYWORD)
 PG_KEYWORD("wrapper", WRAPPER, UNRESERVED_KEYWORD)
 PG_KEYWORD("write", WRITE, UNRESERVED_KEYWORD)
@@ -472,6 +472,6 @@ PG_KEYWORD("xmlpi", XMLPI, COL_NAME_KEYWORD)
 PG_KEYWORD("xmlroot", XMLROOT, COL_NAME_KEYWORD)
 PG_KEYWORD("xmlserialize", XMLSERIALIZE, COL_NAME_KEYWORD)
 PG_KEYWORD("xmltable", XMLTABLE, COL_NAME_KEYWORD)
-PG_KEYWORD("year", YEAR_P, UNRESERVED_KEYWORD)
+PG_KEYWORD("year", YEAR_P, NON_LABEL_KEYWORD)
 PG_KEYWORD("yes", YES_P, UNRESERVED_KEYWORD)
 PG_KEYWORD("zone", ZONE, UNRESERVED_KEYWORD)
diff --git a/src/test/regress/expected/as.out b/src/test/regress/expected/as.out
index 697bfb5ca4..31f1d87757 100644
--- a/src/test/regress/expected/as.out
+++ b/src/test/regress/expected/as.out
@@ -2268,9 +2268,11 @@ SELECT 1234 AS abort;
 (1 row)
 
 SELECT 1234 abort;
-ERROR:  syntax error at or near "abort"
-LINE 1: SELECT 1234 abort;
-                    ^
+ abort 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS absolute;
  absolute 
 ----------
@@ -2278,9 +2280,11 @@ SELECT 1234 AS absolute;
 (1 row)
 
 SELECT 1234 absolute;
-ERROR:  syntax error at or near "absolute"
-LINE 1: SELECT 1234 absolute;
-                    ^
+ absolute 
+----------
+     1234
+(1 row)
+
 SELECT 1234 AS access;
  access 
 --------
@@ -2288,9 +2292,11 @@ SELECT 1234 AS access;
 (1 row)
 
 SELECT 1234 access;
-ERROR:  syntax error at or near "access"
-LINE 1: SELECT 1234 access;
-                    ^
+ access 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS action;
  action 
 --------
@@ -2298,9 +2304,11 @@ SELECT 1234 AS action;
 (1 row)
 
 SELECT 1234 action;
-ERROR:  syntax error at or near "action"
-LINE 1: SELECT 1234 action;
-                    ^
+ action 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS add;
  add  
 ------
@@ -2308,9 +2316,11 @@ SELECT 1234 AS add;
 (1 row)
 
 SELECT 1234 add;
-ERROR:  syntax error at or near "add"
-LINE 1: SELECT 1234 add;
-                    ^
+ add  
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS admin;
  admin 
 -------
@@ -2318,9 +2328,11 @@ SELECT 1234 AS admin;
 (1 row)
 
 SELECT 1234 admin;
-ERROR:  syntax error at or near "admin"
-LINE 1: SELECT 1234 admin;
-                    ^
+ admin 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS after;
  after 
 -------
@@ -2328,9 +2340,11 @@ SELECT 1234 AS after;
 (1 row)
 
 SELECT 1234 after;
-ERROR:  syntax error at or near "after"
-LINE 1: SELECT 1234 after;
-                    ^
+ after 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS aggregate;
  aggregate 
 -----------
@@ -2338,9 +2352,11 @@ SELECT 1234 AS aggregate;
 (1 row)
 
 SELECT 1234 aggregate;
-ERROR:  syntax error at or near "aggregate"
-LINE 1: SELECT 1234 aggregate;
-                    ^
+ aggregate 
+-----------
+      1234
+(1 row)
+
 SELECT 1234 AS also;
  also 
 ------
@@ -2348,9 +2364,11 @@ SELECT 1234 AS also;
 (1 row)
 
 SELECT 1234 also;
-ERROR:  syntax error at or near "also"
-LINE 1: SELECT 1234 also;
-                    ^
+ also 
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS alter;
  alter 
 -------
@@ -2358,9 +2376,11 @@ SELECT 1234 AS alter;
 (1 row)
 
 SELECT 1234 alter;
-ERROR:  syntax error at or near "alter"
-LINE 1: SELECT 1234 alter;
-                    ^
+ alter 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS always;
  always 
 --------
@@ -2368,9 +2388,11 @@ SELECT 1234 AS always;
 (1 row)
 
 SELECT 1234 always;
-ERROR:  syntax error at or near "always"
-LINE 1: SELECT 1234 always;
-                    ^
+ always 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS assertion;
  assertion 
 -----------
@@ -2378,9 +2400,11 @@ SELECT 1234 AS assertion;
 (1 row)
 
 SELECT 1234 assertion;
-ERROR:  syntax error at or near "assertion"
-LINE 1: SELECT 1234 assertion;
-                    ^
+ assertion 
+-----------
+      1234
+(1 row)
+
 SELECT 1234 AS assignment;
  assignment 
 ------------
@@ -2388,9 +2412,11 @@ SELECT 1234 AS assignment;
 (1 row)
 
 SELECT 1234 assignment;
-ERROR:  syntax error at or near "assignment"
-LINE 1: SELECT 1234 assignment;
-                    ^
+ assignment 
+------------
+       1234
+(1 row)
+
 SELECT 1234 AS at;
   at  
 ------
@@ -2398,9 +2424,11 @@ SELECT 1234 AS at;
 (1 row)
 
 SELECT 1234 at;
-ERROR:  syntax error at or near ";"
-LINE 1: SELECT 1234 at;
-                      ^
+  at  
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS attach;
  attach 
 --------
@@ -2408,9 +2436,11 @@ SELECT 1234 AS attach;
 (1 row)
 
 SELECT 1234 attach;
-ERROR:  syntax error at or near "attach"
-LINE 1: SELECT 1234 attach;
-                    ^
+ attach 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS attribute;
  attribute 
 -----------
@@ -2418,9 +2448,11 @@ SELECT 1234 AS attribute;
 (1 row)
 
 SELECT 1234 attribute;
-ERROR:  syntax error at or near "attribute"
-LINE 1: SELECT 1234 attribute;
-                    ^
+ attribute 
+-----------
+      1234
+(1 row)
+
 SELECT 1234 AS backward;
  backward 
 ----------
@@ -2428,9 +2460,11 @@ SELECT 1234 AS backward;
 (1 row)
 
 SELECT 1234 backward;
-ERROR:  syntax error at or near "backward"
-LINE 1: SELECT 1234 backward;
-                    ^
+ backward 
+----------
+     1234
+(1 row)
+
 SELECT 1234 AS before;
  before 
 --------
@@ -2438,9 +2472,11 @@ SELECT 1234 AS before;
 (1 row)
 
 SELECT 1234 before;
-ERROR:  syntax error at or near "before"
-LINE 1: SELECT 1234 before;
-                    ^
+ before 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS begin;
  begin 
 -------
@@ -2448,9 +2484,11 @@ SELECT 1234 AS begin;
 (1 row)
 
 SELECT 1234 begin;
-ERROR:  syntax error at or near "begin"
-LINE 1: SELECT 1234 begin;
-                    ^
+ begin 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS by;
   by  
 ------
@@ -2458,9 +2496,11 @@ SELECT 1234 AS by;
 (1 row)
 
 SELECT 1234 by;
-ERROR:  syntax error at or near "by"
-LINE 1: SELECT 1234 by;
-                    ^
+  by  
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS cache;
  cache 
 -------
@@ -2468,9 +2508,11 @@ SELECT 1234 AS cache;
 (1 row)
 
 SELECT 1234 cache;
-ERROR:  syntax error at or near "cache"
-LINE 1: SELECT 1234 cache;
-                    ^
+ cache 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS call;
  call 
 ------
@@ -2478,9 +2520,11 @@ SELECT 1234 AS call;
 (1 row)
 
 SELECT 1234 call;
-ERROR:  syntax error at or near "call"
-LINE 1: SELECT 1234 call;
-                    ^
+ call 
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS called;
  called 
 --------
@@ -2488,9 +2532,11 @@ SELECT 1234 AS called;
 (1 row)
 
 SELECT 1234 called;
-ERROR:  syntax error at or near "called"
-LINE 1: SELECT 1234 called;
-                    ^
+ called 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS cascade;
  cascade 
 ---------
@@ -2498,9 +2544,11 @@ SELECT 1234 AS cascade;
 (1 row)
 
 SELECT 1234 cascade;
-ERROR:  syntax error at or near "cascade"
-LINE 1: SELECT 1234 cascade;
-                    ^
+ cascade 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS cascaded;
  cascaded 
 ----------
@@ -2508,9 +2556,11 @@ SELECT 1234 AS cascaded;
 (1 row)
 
 SELECT 1234 cascaded;
-ERROR:  syntax error at or near "cascaded"
-LINE 1: SELECT 1234 cascaded;
-                    ^
+ cascaded 
+----------
+     1234
+(1 row)
+
 SELECT 1234 AS catalog;
  catalog 
 ---------
@@ -2518,9 +2568,11 @@ SELECT 1234 AS catalog;
 (1 row)
 
 SELECT 1234 catalog;
-ERROR:  syntax error at or near "catalog"
-LINE 1: SELECT 1234 catalog;
-                    ^
+ catalog 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS chain;
  chain 
 -------
@@ -2528,9 +2580,11 @@ SELECT 1234 AS chain;
 (1 row)
 
 SELECT 1234 chain;
-ERROR:  syntax error at or near "chain"
-LINE 1: SELECT 1234 chain;
-                    ^
+ chain 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS characteristics;
  characteristics 
 -----------------
@@ -2538,9 +2592,11 @@ SELECT 1234 AS characteristics;
 (1 row)
 
 SELECT 1234 characteristics;
-ERROR:  syntax error at or near "characteristics"
-LINE 1: SELECT 1234 characteristics;
-                    ^
+ characteristics 
+-----------------
+            1234
+(1 row)
+
 SELECT 1234 AS checkpoint;
  checkpoint 
 ------------
@@ -2548,9 +2604,11 @@ SELECT 1234 AS checkpoint;
 (1 row)
 
 SELECT 1234 checkpoint;
-ERROR:  syntax error at or near "checkpoint"
-LINE 1: SELECT 1234 checkpoint;
-                    ^
+ checkpoint 
+------------
+       1234
+(1 row)
+
 SELECT 1234 AS class;
  class 
 -------
@@ -2558,9 +2616,11 @@ SELECT 1234 AS class;
 (1 row)
 
 SELECT 1234 class;
-ERROR:  syntax error at or near "class"
-LINE 1: SELECT 1234 class;
-                    ^
+ class 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS close;
  close 
 -------
@@ -2568,9 +2628,11 @@ SELECT 1234 AS close;
 (1 row)
 
 SELECT 1234 close;
-ERROR:  syntax error at or near "close"
-LINE 1: SELECT 1234 close;
-                    ^
+ close 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS cluster;
  cluster 
 ---------
@@ -2578,9 +2640,11 @@ SELECT 1234 AS cluster;
 (1 row)
 
 SELECT 1234 cluster;
-ERROR:  syntax error at or near "cluster"
-LINE 1: SELECT 1234 cluster;
-                    ^
+ cluster 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS columns;
  columns 
 ---------
@@ -2588,9 +2652,11 @@ SELECT 1234 AS columns;
 (1 row)
 
 SELECT 1234 columns;
-ERROR:  syntax error at or near "columns"
-LINE 1: SELECT 1234 columns;
-                    ^
+ columns 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS comment;
  comment 
 ---------
@@ -2598,9 +2664,11 @@ SELECT 1234 AS comment;
 (1 row)
 
 SELECT 1234 comment;
-ERROR:  syntax error at or near "comment"
-LINE 1: SELECT 1234 comment;
-                    ^
+ comment 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS comments;
  comments 
 ----------
@@ -2608,9 +2676,11 @@ SELECT 1234 AS comments;
 (1 row)
 
 SELECT 1234 comments;
-ERROR:  syntax error at or near "comments"
-LINE 1: SELECT 1234 comments;
-                    ^
+ comments 
+----------
+     1234
+(1 row)
+
 SELECT 1234 AS commit;
  commit 
 --------
@@ -2618,9 +2688,11 @@ SELECT 1234 AS commit;
 (1 row)
 
 SELECT 1234 commit;
-ERROR:  syntax error at or near "commit"
-LINE 1: SELECT 1234 commit;
-                    ^
+ commit 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS committed;
  committed 
 -----------
@@ -2628,9 +2700,11 @@ SELECT 1234 AS committed;
 (1 row)
 
 SELECT 1234 committed;
-ERROR:  syntax error at or near "committed"
-LINE 1: SELECT 1234 committed;
-                    ^
+ committed 
+-----------
+      1234
+(1 row)
+
 SELECT 1234 AS configuration;
  configuration 
 ---------------
@@ -2638,9 +2712,11 @@ SELECT 1234 AS configuration;
 (1 row)
 
 SELECT 1234 configuration;
-ERROR:  syntax error at or near "configuration"
-LINE 1: SELECT 1234 configuration;
-                    ^
+ configuration 
+---------------
+          1234
+(1 row)
+
 SELECT 1234 AS conflict;
  conflict 
 ----------
@@ -2648,9 +2724,11 @@ SELECT 1234 AS conflict;
 (1 row)
 
 SELECT 1234 conflict;
-ERROR:  syntax error at or near "conflict"
-LINE 1: SELECT 1234 conflict;
-                    ^
+ conflict 
+----------
+     1234
+(1 row)
+
 SELECT 1234 AS connection;
  connection 
 ------------
@@ -2658,9 +2736,11 @@ SELECT 1234 AS connection;
 (1 row)
 
 SELECT 1234 connection;
-ERROR:  syntax error at or near "connection"
-LINE 1: SELECT 1234 connection;
-                    ^
+ connection 
+------------
+       1234
+(1 row)
+
 SELECT 1234 AS constraints;
  constraints 
 -------------
@@ -2668,9 +2748,11 @@ SELECT 1234 AS constraints;
 (1 row)
 
 SELECT 1234 constraints;
-ERROR:  syntax error at or near "constraints"
-LINE 1: SELECT 1234 constraints;
-                    ^
+ constraints 
+-------------
+        1234
+(1 row)
+
 SELECT 1234 AS content;
  content 
 ---------
@@ -2678,9 +2760,11 @@ SELECT 1234 AS content;
 (1 row)
 
 SELECT 1234 content;
-ERROR:  syntax error at or near "content"
-LINE 1: SELECT 1234 content;
-                    ^
+ content 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS continue;
  continue 
 ----------
@@ -2688,9 +2772,11 @@ SELECT 1234 AS continue;
 (1 row)
 
 SELECT 1234 continue;
-ERROR:  syntax error at or near "continue"
-LINE 1: SELECT 1234 continue;
-                    ^
+ continue 
+----------
+     1234
+(1 row)
+
 SELECT 1234 AS conversion;
  conversion 
 ------------
@@ -2698,9 +2784,11 @@ SELECT 1234 AS conversion;
 (1 row)
 
 SELECT 1234 conversion;
-ERROR:  syntax error at or near "conversion"
-LINE 1: SELECT 1234 conversion;
-                    ^
+ conversion 
+------------
+       1234
+(1 row)
+
 SELECT 1234 AS copy;
  copy 
 ------
@@ -2708,9 +2796,11 @@ SELECT 1234 AS copy;
 (1 row)
 
 SELECT 1234 copy;
-ERROR:  syntax error at or near "copy"
-LINE 1: SELECT 1234 copy;
-                    ^
+ copy 
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS cost;
  cost 
 ------
@@ -2718,9 +2808,11 @@ SELECT 1234 AS cost;
 (1 row)
 
 SELECT 1234 cost;
-ERROR:  syntax error at or near "cost"
-LINE 1: SELECT 1234 cost;
-                    ^
+ cost 
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS csv;
  csv  
 ------
@@ -2728,9 +2820,11 @@ SELECT 1234 AS csv;
 (1 row)
 
 SELECT 1234 csv;
-ERROR:  syntax error at or near "csv"
-LINE 1: SELECT 1234 csv;
-                    ^
+ csv  
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS cube;
  cube 
 ------
@@ -2738,9 +2832,11 @@ SELECT 1234 AS cube;
 (1 row)
 
 SELECT 1234 cube;
-ERROR:  syntax error at or near "cube"
-LINE 1: SELECT 1234 cube;
-                    ^
+ cube 
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS current;
  current 
 ---------
@@ -2748,9 +2844,11 @@ SELECT 1234 AS current;
 (1 row)
 
 SELECT 1234 current;
-ERROR:  syntax error at or near "current"
-LINE 1: SELECT 1234 current;
-                    ^
+ current 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS cursor;
  cursor 
 --------
@@ -2758,9 +2856,11 @@ SELECT 1234 AS cursor;
 (1 row)
 
 SELECT 1234 cursor;
-ERROR:  syntax error at or near "cursor"
-LINE 1: SELECT 1234 cursor;
-                    ^
+ cursor 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS cycle;
  cycle 
 -------
@@ -2768,9 +2868,11 @@ SELECT 1234 AS cycle;
 (1 row)
 
 SELECT 1234 cycle;
-ERROR:  syntax error at or near "cycle"
-LINE 1: SELECT 1234 cycle;
-                    ^
+ cycle 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS data;
  data 
 ------
@@ -2778,9 +2880,11 @@ SELECT 1234 AS data;
 (1 row)
 
 SELECT 1234 data;
-ERROR:  syntax error at or near "data"
-LINE 1: SELECT 1234 data;
-                    ^
+ data 
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS database;
  database 
 ----------
@@ -2788,9 +2892,11 @@ SELECT 1234 AS database;
 (1 row)
 
 SELECT 1234 database;
-ERROR:  syntax error at or near "database"
-LINE 1: SELECT 1234 database;
-                    ^
+ database 
+----------
+     1234
+(1 row)
+
 SELECT 1234 AS day;
  day  
 ------
@@ -2808,9 +2914,11 @@ SELECT 1234 AS deallocate;
 (1 row)
 
 SELECT 1234 deallocate;
-ERROR:  syntax error at or near "deallocate"
-LINE 1: SELECT 1234 deallocate;
-                    ^
+ deallocate 
+------------
+       1234
+(1 row)
+
 SELECT 1234 AS declare;
  declare 
 ---------
@@ -2818,9 +2926,11 @@ SELECT 1234 AS declare;
 (1 row)
 
 SELECT 1234 declare;
-ERROR:  syntax error at or near "declare"
-LINE 1: SELECT 1234 declare;
-                    ^
+ declare 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS defaults;
  defaults 
 ----------
@@ -2828,9 +2938,11 @@ SELECT 1234 AS defaults;
 (1 row)
 
 SELECT 1234 defaults;
-ERROR:  syntax error at or near "defaults"
-LINE 1: SELECT 1234 defaults;
-                    ^
+ defaults 
+----------
+     1234
+(1 row)
+
 SELECT 1234 AS deferred;
  deferred 
 ----------
@@ -2838,9 +2950,11 @@ SELECT 1234 AS deferred;
 (1 row)
 
 SELECT 1234 deferred;
-ERROR:  syntax error at or near "deferred"
-LINE 1: SELECT 1234 deferred;
-                    ^
+ deferred 
+----------
+     1234
+(1 row)
+
 SELECT 1234 AS definer;
  definer 
 ---------
@@ -2848,9 +2962,11 @@ SELECT 1234 AS definer;
 (1 row)
 
 SELECT 1234 definer;
-ERROR:  syntax error at or near "definer"
-LINE 1: SELECT 1234 definer;
-                    ^
+ definer 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS delete;
  delete 
 --------
@@ -2858,9 +2974,11 @@ SELECT 1234 AS delete;
 (1 row)
 
 SELECT 1234 delete;
-ERROR:  syntax error at or near "delete"
-LINE 1: SELECT 1234 delete;
-                    ^
+ delete 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS delimiter;
  delimiter 
 -----------
@@ -2868,9 +2986,11 @@ SELECT 1234 AS delimiter;
 (1 row)
 
 SELECT 1234 delimiter;
-ERROR:  syntax error at or near "delimiter"
-LINE 1: SELECT 1234 delimiter;
-                    ^
+ delimiter 
+-----------
+      1234
+(1 row)
+
 SELECT 1234 AS delimiters;
  delimiters 
 ------------
@@ -2878,9 +2998,11 @@ SELECT 1234 AS delimiters;
 (1 row)
 
 SELECT 1234 delimiters;
-ERROR:  syntax error at or near "delimiters"
-LINE 1: SELECT 1234 delimiters;
-                    ^
+ delimiters 
+------------
+       1234
+(1 row)
+
 SELECT 1234 AS depends;
  depends 
 ---------
@@ -2888,9 +3010,11 @@ SELECT 1234 AS depends;
 (1 row)
 
 SELECT 1234 depends;
-ERROR:  syntax error at or near "depends"
-LINE 1: SELECT 1234 depends;
-                    ^
+ depends 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS detach;
  detach 
 --------
@@ -2898,9 +3022,11 @@ SELECT 1234 AS detach;
 (1 row)
 
 SELECT 1234 detach;
-ERROR:  syntax error at or near "detach"
-LINE 1: SELECT 1234 detach;
-                    ^
+ detach 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS dictionary;
  dictionary 
 ------------
@@ -2908,9 +3034,11 @@ SELECT 1234 AS dictionary;
 (1 row)
 
 SELECT 1234 dictionary;
-ERROR:  syntax error at or near "dictionary"
-LINE 1: SELECT 1234 dictionary;
-                    ^
+ dictionary 
+------------
+       1234
+(1 row)
+
 SELECT 1234 AS disable;
  disable 
 ---------
@@ -2918,9 +3046,11 @@ SELECT 1234 AS disable;
 (1 row)
 
 SELECT 1234 disable;
-ERROR:  syntax error at or near "disable"
-LINE 1: SELECT 1234 disable;
-                    ^
+ disable 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS discard;
  discard 
 ---------
@@ -2928,9 +3058,11 @@ SELECT 1234 AS discard;
 (1 row)
 
 SELECT 1234 discard;
-ERROR:  syntax error at or near "discard"
-LINE 1: SELECT 1234 discard;
-                    ^
+ discard 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS document;
  document 
 ----------
@@ -2938,9 +3070,11 @@ SELECT 1234 AS document;
 (1 row)
 
 SELECT 1234 document;
-ERROR:  syntax error at or near "document"
-LINE 1: SELECT 1234 document;
-                    ^
+ document 
+----------
+     1234
+(1 row)
+
 SELECT 1234 AS domain;
  domain 
 --------
@@ -2948,9 +3082,11 @@ SELECT 1234 AS domain;
 (1 row)
 
 SELECT 1234 domain;
-ERROR:  syntax error at or near "domain"
-LINE 1: SELECT 1234 domain;
-                    ^
+ domain 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS double;
  double 
 --------
@@ -2958,9 +3094,11 @@ SELECT 1234 AS double;
 (1 row)
 
 SELECT 1234 double;
-ERROR:  syntax error at or near "double"
-LINE 1: SELECT 1234 double;
-                    ^
+ double 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS drop;
  drop 
 ------
@@ -2968,9 +3106,11 @@ SELECT 1234 AS drop;
 (1 row)
 
 SELECT 1234 drop;
-ERROR:  syntax error at or near "drop"
-LINE 1: SELECT 1234 drop;
-                    ^
+ drop 
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS each;
  each 
 ------
@@ -2978,9 +3118,11 @@ SELECT 1234 AS each;
 (1 row)
 
 SELECT 1234 each;
-ERROR:  syntax error at or near "each"
-LINE 1: SELECT 1234 each;
-                    ^
+ each 
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS enable;
  enable 
 --------
@@ -2988,9 +3130,11 @@ SELECT 1234 AS enable;
 (1 row)
 
 SELECT 1234 enable;
-ERROR:  syntax error at or near "enable"
-LINE 1: SELECT 1234 enable;
-                    ^
+ enable 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS encoding;
  encoding 
 ----------
@@ -2998,9 +3142,11 @@ SELECT 1234 AS encoding;
 (1 row)
 
 SELECT 1234 encoding;
-ERROR:  syntax error at or near "encoding"
-LINE 1: SELECT 1234 encoding;
-                    ^
+ encoding 
+----------
+     1234
+(1 row)
+
 SELECT 1234 AS encrypted;
  encrypted 
 -----------
@@ -3008,9 +3154,11 @@ SELECT 1234 AS encrypted;
 (1 row)
 
 SELECT 1234 encrypted;
-ERROR:  syntax error at or near "encrypted"
-LINE 1: SELECT 1234 encrypted;
-                    ^
+ encrypted 
+-----------
+      1234
+(1 row)
+
 SELECT 1234 AS enum;
  enum 
 ------
@@ -3018,19 +3166,23 @@ SELECT 1234 AS enum;
 (1 row)
 
 SELECT 1234 enum;
-ERROR:  syntax error at or near "enum"
-LINE 1: SELECT 1234 enum;
-                    ^
+ enum 
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS escape;
  escape 
 --------
    1234
 (1 row)
 
-SELECT 1234 escape;
-ERROR:  syntax error at or near "escape"
-LINE 1: SELECT 1234 escape;
-                    ^
+SELECT 1234 escape;
+ escape 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS event;
  event 
 -------
@@ -3038,9 +3190,11 @@ SELECT 1234 AS event;
 (1 row)
 
 SELECT 1234 event;
-ERROR:  syntax error at or near "event"
-LINE 1: SELECT 1234 event;
-                    ^
+ event 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS exclude;
  exclude 
 ---------
@@ -3048,9 +3202,11 @@ SELECT 1234 AS exclude;
 (1 row)
 
 SELECT 1234 exclude;
-ERROR:  syntax error at or near "exclude"
-LINE 1: SELECT 1234 exclude;
-                    ^
+ exclude 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS excluding;
  excluding 
 -----------
@@ -3058,9 +3214,11 @@ SELECT 1234 AS excluding;
 (1 row)
 
 SELECT 1234 excluding;
-ERROR:  syntax error at or near "excluding"
-LINE 1: SELECT 1234 excluding;
-                    ^
+ excluding 
+-----------
+      1234
+(1 row)
+
 SELECT 1234 AS exclusive;
  exclusive 
 -----------
@@ -3068,9 +3226,11 @@ SELECT 1234 AS exclusive;
 (1 row)
 
 SELECT 1234 exclusive;
-ERROR:  syntax error at or near "exclusive"
-LINE 1: SELECT 1234 exclusive;
-                    ^
+ exclusive 
+-----------
+      1234
+(1 row)
+
 SELECT 1234 AS execute;
  execute 
 ---------
@@ -3078,9 +3238,11 @@ SELECT 1234 AS execute;
 (1 row)
 
 SELECT 1234 execute;
-ERROR:  syntax error at or near "execute"
-LINE 1: SELECT 1234 execute;
-                    ^
+ execute 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS explain;
  explain 
 ---------
@@ -3088,9 +3250,11 @@ SELECT 1234 AS explain;
 (1 row)
 
 SELECT 1234 explain;
-ERROR:  syntax error at or near "explain"
-LINE 1: SELECT 1234 explain;
-                    ^
+ explain 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS expression;
  expression 
 ------------
@@ -3098,9 +3262,11 @@ SELECT 1234 AS expression;
 (1 row)
 
 SELECT 1234 expression;
-ERROR:  syntax error at or near "expression"
-LINE 1: SELECT 1234 expression;
-                    ^
+ expression 
+------------
+       1234
+(1 row)
+
 SELECT 1234 AS extension;
  extension 
 -----------
@@ -3108,9 +3274,11 @@ SELECT 1234 AS extension;
 (1 row)
 
 SELECT 1234 extension;
-ERROR:  syntax error at or near "extension"
-LINE 1: SELECT 1234 extension;
-                    ^
+ extension 
+-----------
+      1234
+(1 row)
+
 SELECT 1234 AS external;
  external 
 ----------
@@ -3118,9 +3286,11 @@ SELECT 1234 AS external;
 (1 row)
 
 SELECT 1234 external;
-ERROR:  syntax error at or near "external"
-LINE 1: SELECT 1234 external;
-                    ^
+ external 
+----------
+     1234
+(1 row)
+
 SELECT 1234 AS family;
  family 
 --------
@@ -3128,9 +3298,11 @@ SELECT 1234 AS family;
 (1 row)
 
 SELECT 1234 family;
-ERROR:  syntax error at or near "family"
-LINE 1: SELECT 1234 family;
-                    ^
+ family 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS filter;
  filter 
 --------
@@ -3148,9 +3320,11 @@ SELECT 1234 AS first;
 (1 row)
 
 SELECT 1234 first;
-ERROR:  syntax error at or near "first"
-LINE 1: SELECT 1234 first;
-                    ^
+ first 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS following;
  following 
 -----------
@@ -3158,9 +3332,11 @@ SELECT 1234 AS following;
 (1 row)
 
 SELECT 1234 following;
-ERROR:  syntax error at or near "following"
-LINE 1: SELECT 1234 following;
-                    ^
+ following 
+-----------
+      1234
+(1 row)
+
 SELECT 1234 AS force;
  force 
 -------
@@ -3168,9 +3344,11 @@ SELECT 1234 AS force;
 (1 row)
 
 SELECT 1234 force;
-ERROR:  syntax error at or near "force"
-LINE 1: SELECT 1234 force;
-                    ^
+ force 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS forward;
  forward 
 ---------
@@ -3178,9 +3356,11 @@ SELECT 1234 AS forward;
 (1 row)
 
 SELECT 1234 forward;
-ERROR:  syntax error at or near "forward"
-LINE 1: SELECT 1234 forward;
-                    ^
+ forward 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS function;
  function 
 ----------
@@ -3188,9 +3368,11 @@ SELECT 1234 AS function;
 (1 row)
 
 SELECT 1234 function;
-ERROR:  syntax error at or near "function"
-LINE 1: SELECT 1234 function;
-                    ^
+ function 
+----------
+     1234
+(1 row)
+
 SELECT 1234 AS functions;
  functions 
 -----------
@@ -3198,9 +3380,11 @@ SELECT 1234 AS functions;
 (1 row)
 
 SELECT 1234 functions;
-ERROR:  syntax error at or near "functions"
-LINE 1: SELECT 1234 functions;
-                    ^
+ functions 
+-----------
+      1234
+(1 row)
+
 SELECT 1234 AS generated;
  generated 
 -----------
@@ -3208,9 +3392,11 @@ SELECT 1234 AS generated;
 (1 row)
 
 SELECT 1234 generated;
-ERROR:  syntax error at or near "generated"
-LINE 1: SELECT 1234 generated;
-                    ^
+ generated 
+-----------
+      1234
+(1 row)
+
 SELECT 1234 AS global;
  global 
 --------
@@ -3218,9 +3404,11 @@ SELECT 1234 AS global;
 (1 row)
 
 SELECT 1234 global;
-ERROR:  syntax error at or near "global"
-LINE 1: SELECT 1234 global;
-                    ^
+ global 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS granted;
  granted 
 ---------
@@ -3228,9 +3416,11 @@ SELECT 1234 AS granted;
 (1 row)
 
 SELECT 1234 granted;
-ERROR:  syntax error at or near "granted"
-LINE 1: SELECT 1234 granted;
-                    ^
+ granted 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS groups;
  groups 
 --------
@@ -3238,9 +3428,11 @@ SELECT 1234 AS groups;
 (1 row)
 
 SELECT 1234 groups;
-ERROR:  syntax error at or near "groups"
-LINE 1: SELECT 1234 groups;
-                    ^
+ groups 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS handler;
  handler 
 ---------
@@ -3248,9 +3440,11 @@ SELECT 1234 AS handler;
 (1 row)
 
 SELECT 1234 handler;
-ERROR:  syntax error at or near "handler"
-LINE 1: SELECT 1234 handler;
-                    ^
+ handler 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS header;
  header 
 --------
@@ -3258,9 +3452,11 @@ SELECT 1234 AS header;
 (1 row)
 
 SELECT 1234 header;
-ERROR:  syntax error at or near "header"
-LINE 1: SELECT 1234 header;
-                    ^
+ header 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS hold;
  hold 
 ------
@@ -3268,9 +3464,11 @@ SELECT 1234 AS hold;
 (1 row)
 
 SELECT 1234 hold;
-ERROR:  syntax error at or near "hold"
-LINE 1: SELECT 1234 hold;
-                    ^
+ hold 
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS hour;
  hour 
 ------
@@ -3288,9 +3486,11 @@ SELECT 1234 AS identity;
 (1 row)
 
 SELECT 1234 identity;
-ERROR:  syntax error at or near "identity"
-LINE 1: SELECT 1234 identity;
-                    ^
+ identity 
+----------
+     1234
+(1 row)
+
 SELECT 1234 AS if;
   if  
 ------
@@ -3298,9 +3498,11 @@ SELECT 1234 AS if;
 (1 row)
 
 SELECT 1234 if;
-ERROR:  syntax error at or near "if"
-LINE 1: SELECT 1234 if;
-                    ^
+  if  
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS immediate;
  immediate 
 -----------
@@ -3308,9 +3510,11 @@ SELECT 1234 AS immediate;
 (1 row)
 
 SELECT 1234 immediate;
-ERROR:  syntax error at or near "immediate"
-LINE 1: SELECT 1234 immediate;
-                    ^
+ immediate 
+-----------
+      1234
+(1 row)
+
 SELECT 1234 AS immutable;
  immutable 
 -----------
@@ -3318,9 +3522,11 @@ SELECT 1234 AS immutable;
 (1 row)
 
 SELECT 1234 immutable;
-ERROR:  syntax error at or near "immutable"
-LINE 1: SELECT 1234 immutable;
-                    ^
+ immutable 
+-----------
+      1234
+(1 row)
+
 SELECT 1234 AS implicit;
  implicit 
 ----------
@@ -3328,9 +3534,11 @@ SELECT 1234 AS implicit;
 (1 row)
 
 SELECT 1234 implicit;
-ERROR:  syntax error at or near "implicit"
-LINE 1: SELECT 1234 implicit;
-                    ^
+ implicit 
+----------
+     1234
+(1 row)
+
 SELECT 1234 AS import;
  import 
 --------
@@ -3338,9 +3546,11 @@ SELECT 1234 AS import;
 (1 row)
 
 SELECT 1234 import;
-ERROR:  syntax error at or near "import"
-LINE 1: SELECT 1234 import;
-                    ^
+ import 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS include;
  include 
 ---------
@@ -3348,9 +3558,11 @@ SELECT 1234 AS include;
 (1 row)
 
 SELECT 1234 include;
-ERROR:  syntax error at or near "include"
-LINE 1: SELECT 1234 include;
-                    ^
+ include 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS including;
  including 
 -----------
@@ -3358,9 +3570,11 @@ SELECT 1234 AS including;
 (1 row)
 
 SELECT 1234 including;
-ERROR:  syntax error at or near "including"
-LINE 1: SELECT 1234 including;
-                    ^
+ including 
+-----------
+      1234
+(1 row)
+
 SELECT 1234 AS increment;
  increment 
 -----------
@@ -3368,9 +3582,11 @@ SELECT 1234 AS increment;
 (1 row)
 
 SELECT 1234 increment;
-ERROR:  syntax error at or near "increment"
-LINE 1: SELECT 1234 increment;
-                    ^
+ increment 
+-----------
+      1234
+(1 row)
+
 SELECT 1234 AS index;
  index 
 -------
@@ -3378,9 +3594,11 @@ SELECT 1234 AS index;
 (1 row)
 
 SELECT 1234 index;
-ERROR:  syntax error at or near "index"
-LINE 1: SELECT 1234 index;
-                    ^
+ index 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS indexes;
  indexes 
 ---------
@@ -3388,9 +3606,11 @@ SELECT 1234 AS indexes;
 (1 row)
 
 SELECT 1234 indexes;
-ERROR:  syntax error at or near "indexes"
-LINE 1: SELECT 1234 indexes;
-                    ^
+ indexes 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS inherit;
  inherit 
 ---------
@@ -3398,9 +3618,11 @@ SELECT 1234 AS inherit;
 (1 row)
 
 SELECT 1234 inherit;
-ERROR:  syntax error at or near "inherit"
-LINE 1: SELECT 1234 inherit;
-                    ^
+ inherit 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS inherits;
  inherits 
 ----------
@@ -3408,9 +3630,11 @@ SELECT 1234 AS inherits;
 (1 row)
 
 SELECT 1234 inherits;
-ERROR:  syntax error at or near "inherits"
-LINE 1: SELECT 1234 inherits;
-                    ^
+ inherits 
+----------
+     1234
+(1 row)
+
 SELECT 1234 AS inline;
  inline 
 --------
@@ -3418,9 +3642,11 @@ SELECT 1234 AS inline;
 (1 row)
 
 SELECT 1234 inline;
-ERROR:  syntax error at or near "inline"
-LINE 1: SELECT 1234 inline;
-                    ^
+ inline 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS input;
  input 
 -------
@@ -3428,9 +3654,11 @@ SELECT 1234 AS input;
 (1 row)
 
 SELECT 1234 input;
-ERROR:  syntax error at or near "input"
-LINE 1: SELECT 1234 input;
-                    ^
+ input 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS insensitive;
  insensitive 
 -------------
@@ -3438,9 +3666,11 @@ SELECT 1234 AS insensitive;
 (1 row)
 
 SELECT 1234 insensitive;
-ERROR:  syntax error at or near "insensitive"
-LINE 1: SELECT 1234 insensitive;
-                    ^
+ insensitive 
+-------------
+        1234
+(1 row)
+
 SELECT 1234 AS insert;
  insert 
 --------
@@ -3448,9 +3678,11 @@ SELECT 1234 AS insert;
 (1 row)
 
 SELECT 1234 insert;
-ERROR:  syntax error at or near "insert"
-LINE 1: SELECT 1234 insert;
-                    ^
+ insert 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS instead;
  instead 
 ---------
@@ -3458,9 +3690,11 @@ SELECT 1234 AS instead;
 (1 row)
 
 SELECT 1234 instead;
-ERROR:  syntax error at or near "instead"
-LINE 1: SELECT 1234 instead;
-                    ^
+ instead 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS invoker;
  invoker 
 ---------
@@ -3468,9 +3702,11 @@ SELECT 1234 AS invoker;
 (1 row)
 
 SELECT 1234 invoker;
-ERROR:  syntax error at or near "invoker"
-LINE 1: SELECT 1234 invoker;
-                    ^
+ invoker 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS isolation;
  isolation 
 -----------
@@ -3478,9 +3714,11 @@ SELECT 1234 AS isolation;
 (1 row)
 
 SELECT 1234 isolation;
-ERROR:  syntax error at or near "isolation"
-LINE 1: SELECT 1234 isolation;
-                    ^
+ isolation 
+-----------
+      1234
+(1 row)
+
 SELECT 1234 AS key;
  key  
 ------
@@ -3488,9 +3726,11 @@ SELECT 1234 AS key;
 (1 row)
 
 SELECT 1234 key;
-ERROR:  syntax error at or near "key"
-LINE 1: SELECT 1234 key;
-                    ^
+ key  
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS label;
  label 
 -------
@@ -3498,9 +3738,11 @@ SELECT 1234 AS label;
 (1 row)
 
 SELECT 1234 label;
-ERROR:  syntax error at or near "label"
-LINE 1: SELECT 1234 label;
-                    ^
+ label 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS language;
  language 
 ----------
@@ -3508,9 +3750,11 @@ SELECT 1234 AS language;
 (1 row)
 
 SELECT 1234 language;
-ERROR:  syntax error at or near "language"
-LINE 1: SELECT 1234 language;
-                    ^
+ language 
+----------
+     1234
+(1 row)
+
 SELECT 1234 AS large;
  large 
 -------
@@ -3518,9 +3762,11 @@ SELECT 1234 AS large;
 (1 row)
 
 SELECT 1234 large;
-ERROR:  syntax error at or near "large"
-LINE 1: SELECT 1234 large;
-                    ^
+ large 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS last;
  last 
 ------
@@ -3528,9 +3774,11 @@ SELECT 1234 AS last;
 (1 row)
 
 SELECT 1234 last;
-ERROR:  syntax error at or near "last"
-LINE 1: SELECT 1234 last;
-                    ^
+ last 
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS leakproof;
  leakproof 
 -----------
@@ -3538,9 +3786,11 @@ SELECT 1234 AS leakproof;
 (1 row)
 
 SELECT 1234 leakproof;
-ERROR:  syntax error at or near "leakproof"
-LINE 1: SELECT 1234 leakproof;
-                    ^
+ leakproof 
+-----------
+      1234
+(1 row)
+
 SELECT 1234 AS level;
  level 
 -------
@@ -3548,9 +3798,11 @@ SELECT 1234 AS level;
 (1 row)
 
 SELECT 1234 level;
-ERROR:  syntax error at or near "level"
-LINE 1: SELECT 1234 level;
-                    ^
+ level 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS listen;
  listen 
 --------
@@ -3558,9 +3810,11 @@ SELECT 1234 AS listen;
 (1 row)
 
 SELECT 1234 listen;
-ERROR:  syntax error at or near "listen"
-LINE 1: SELECT 1234 listen;
-                    ^
+ listen 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS load;
  load 
 ------
@@ -3568,9 +3822,11 @@ SELECT 1234 AS load;
 (1 row)
 
 SELECT 1234 load;
-ERROR:  syntax error at or near "load"
-LINE 1: SELECT 1234 load;
-                    ^
+ load 
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS local;
  local 
 -------
@@ -3578,9 +3834,11 @@ SELECT 1234 AS local;
 (1 row)
 
 SELECT 1234 local;
-ERROR:  syntax error at or near "local"
-LINE 1: SELECT 1234 local;
-                    ^
+ local 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS location;
  location 
 ----------
@@ -3588,9 +3846,11 @@ SELECT 1234 AS location;
 (1 row)
 
 SELECT 1234 location;
-ERROR:  syntax error at or near "location"
-LINE 1: SELECT 1234 location;
-                    ^
+ location 
+----------
+     1234
+(1 row)
+
 SELECT 1234 AS lock;
  lock 
 ------
@@ -3598,9 +3858,11 @@ SELECT 1234 AS lock;
 (1 row)
 
 SELECT 1234 lock;
-ERROR:  syntax error at or near "lock"
-LINE 1: SELECT 1234 lock;
-                    ^
+ lock 
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS locked;
  locked 
 --------
@@ -3608,9 +3870,11 @@ SELECT 1234 AS locked;
 (1 row)
 
 SELECT 1234 locked;
-ERROR:  syntax error at or near "locked"
-LINE 1: SELECT 1234 locked;
-                    ^
+ locked 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS logged;
  logged 
 --------
@@ -3618,9 +3882,11 @@ SELECT 1234 AS logged;
 (1 row)
 
 SELECT 1234 logged;
-ERROR:  syntax error at or near "logged"
-LINE 1: SELECT 1234 logged;
-                    ^
+ logged 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS mapping;
  mapping 
 ---------
@@ -3628,9 +3894,11 @@ SELECT 1234 AS mapping;
 (1 row)
 
 SELECT 1234 mapping;
-ERROR:  syntax error at or near "mapping"
-LINE 1: SELECT 1234 mapping;
-                    ^
+ mapping 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS match;
  match 
 -------
@@ -3638,9 +3906,11 @@ SELECT 1234 AS match;
 (1 row)
 
 SELECT 1234 match;
-ERROR:  syntax error at or near "match"
-LINE 1: SELECT 1234 match;
-                    ^
+ match 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS materialized;
  materialized 
 --------------
@@ -3648,9 +3918,11 @@ SELECT 1234 AS materialized;
 (1 row)
 
 SELECT 1234 materialized;
-ERROR:  syntax error at or near "materialized"
-LINE 1: SELECT 1234 materialized;
-                    ^
+ materialized 
+--------------
+         1234
+(1 row)
+
 SELECT 1234 AS maxvalue;
  maxvalue 
 ----------
@@ -3658,9 +3930,11 @@ SELECT 1234 AS maxvalue;
 (1 row)
 
 SELECT 1234 maxvalue;
-ERROR:  syntax error at or near "maxvalue"
-LINE 1: SELECT 1234 maxvalue;
-                    ^
+ maxvalue 
+----------
+     1234
+(1 row)
+
 SELECT 1234 AS method;
  method 
 --------
@@ -3668,9 +3942,11 @@ SELECT 1234 AS method;
 (1 row)
 
 SELECT 1234 method;
-ERROR:  syntax error at or near "method"
-LINE 1: SELECT 1234 method;
-                    ^
+ method 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS minute;
  minute 
 --------
@@ -3688,9 +3964,11 @@ SELECT 1234 AS minvalue;
 (1 row)
 
 SELECT 1234 minvalue;
-ERROR:  syntax error at or near "minvalue"
-LINE 1: SELECT 1234 minvalue;
-                    ^
+ minvalue 
+----------
+     1234
+(1 row)
+
 SELECT 1234 AS mode;
  mode 
 ------
@@ -3698,9 +3976,11 @@ SELECT 1234 AS mode;
 (1 row)
 
 SELECT 1234 mode;
-ERROR:  syntax error at or near "mode"
-LINE 1: SELECT 1234 mode;
-                    ^
+ mode 
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS month;
  month 
 -------
@@ -3718,9 +3998,11 @@ SELECT 1234 AS move;
 (1 row)
 
 SELECT 1234 move;
-ERROR:  syntax error at or near "move"
-LINE 1: SELECT 1234 move;
-                    ^
+ move 
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS name;
  name 
 ------
@@ -3728,9 +4010,11 @@ SELECT 1234 AS name;
 (1 row)
 
 SELECT 1234 name;
-ERROR:  syntax error at or near "name"
-LINE 1: SELECT 1234 name;
-                    ^
+ name 
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS names;
  names 
 -------
@@ -3738,9 +4022,11 @@ SELECT 1234 AS names;
 (1 row)
 
 SELECT 1234 names;
-ERROR:  syntax error at or near "names"
-LINE 1: SELECT 1234 names;
-                    ^
+ names 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS new;
  new  
 ------
@@ -3748,9 +4034,11 @@ SELECT 1234 AS new;
 (1 row)
 
 SELECT 1234 new;
-ERROR:  syntax error at or near "new"
-LINE 1: SELECT 1234 new;
-                    ^
+ new  
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS next;
  next 
 ------
@@ -3758,9 +4046,11 @@ SELECT 1234 AS next;
 (1 row)
 
 SELECT 1234 next;
-ERROR:  syntax error at or near "next"
-LINE 1: SELECT 1234 next;
-                    ^
+ next 
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS nfc;
  nfc  
 ------
@@ -3768,9 +4058,11 @@ SELECT 1234 AS nfc;
 (1 row)
 
 SELECT 1234 nfc;
-ERROR:  syntax error at or near "nfc"
-LINE 1: SELECT 1234 nfc;
-                    ^
+ nfc  
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS nfd;
  nfd  
 ------
@@ -3778,9 +4070,11 @@ SELECT 1234 AS nfd;
 (1 row)
 
 SELECT 1234 nfd;
-ERROR:  syntax error at or near "nfd"
-LINE 1: SELECT 1234 nfd;
-                    ^
+ nfd  
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS nfkc;
  nfkc 
 ------
@@ -3788,9 +4082,11 @@ SELECT 1234 AS nfkc;
 (1 row)
 
 SELECT 1234 nfkc;
-ERROR:  syntax error at or near "nfkc"
-LINE 1: SELECT 1234 nfkc;
-                    ^
+ nfkc 
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS nfkd;
  nfkd 
 ------
@@ -3798,9 +4094,11 @@ SELECT 1234 AS nfkd;
 (1 row)
 
 SELECT 1234 nfkd;
-ERROR:  syntax error at or near "nfkd"
-LINE 1: SELECT 1234 nfkd;
-                    ^
+ nfkd 
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS no;
   no  
 ------
@@ -3808,9 +4106,11 @@ SELECT 1234 AS no;
 (1 row)
 
 SELECT 1234 no;
-ERROR:  syntax error at or near "no"
-LINE 1: SELECT 1234 no;
-                    ^
+  no  
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS normalized;
  normalized 
 ------------
@@ -3818,9 +4118,11 @@ SELECT 1234 AS normalized;
 (1 row)
 
 SELECT 1234 normalized;
-ERROR:  syntax error at or near "normalized"
-LINE 1: SELECT 1234 normalized;
-                    ^
+ normalized 
+------------
+       1234
+(1 row)
+
 SELECT 1234 AS nothing;
  nothing 
 ---------
@@ -3828,9 +4130,11 @@ SELECT 1234 AS nothing;
 (1 row)
 
 SELECT 1234 nothing;
-ERROR:  syntax error at or near "nothing"
-LINE 1: SELECT 1234 nothing;
-                    ^
+ nothing 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS notify;
  notify 
 --------
@@ -3838,9 +4142,11 @@ SELECT 1234 AS notify;
 (1 row)
 
 SELECT 1234 notify;
-ERROR:  syntax error at or near "notify"
-LINE 1: SELECT 1234 notify;
-                    ^
+ notify 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS nowait;
  nowait 
 --------
@@ -3848,9 +4154,11 @@ SELECT 1234 AS nowait;
 (1 row)
 
 SELECT 1234 nowait;
-ERROR:  syntax error at or near "nowait"
-LINE 1: SELECT 1234 nowait;
-                    ^
+ nowait 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS nulls;
  nulls 
 -------
@@ -3858,9 +4166,11 @@ SELECT 1234 AS nulls;
 (1 row)
 
 SELECT 1234 nulls;
-ERROR:  syntax error at or near "nulls"
-LINE 1: SELECT 1234 nulls;
-                    ^
+ nulls 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS object;
  object 
 --------
@@ -3868,9 +4178,11 @@ SELECT 1234 AS object;
 (1 row)
 
 SELECT 1234 object;
-ERROR:  syntax error at or near "object"
-LINE 1: SELECT 1234 object;
-                    ^
+ object 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS of;
   of  
 ------
@@ -3878,9 +4190,11 @@ SELECT 1234 AS of;
 (1 row)
 
 SELECT 1234 of;
-ERROR:  syntax error at or near "of"
-LINE 1: SELECT 1234 of;
-                    ^
+  of  
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS off;
  off  
 ------
@@ -3888,9 +4202,11 @@ SELECT 1234 AS off;
 (1 row)
 
 SELECT 1234 off;
-ERROR:  syntax error at or near "off"
-LINE 1: SELECT 1234 off;
-                    ^
+ off  
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS oids;
  oids 
 ------
@@ -3898,9 +4214,11 @@ SELECT 1234 AS oids;
 (1 row)
 
 SELECT 1234 oids;
-ERROR:  syntax error at or near "oids"
-LINE 1: SELECT 1234 oids;
-                    ^
+ oids 
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS old;
  old  
 ------
@@ -3908,19 +4226,23 @@ SELECT 1234 AS old;
 (1 row)
 
 SELECT 1234 old;
-ERROR:  syntax error at or near "old"
-LINE 1: SELECT 1234 old;
-                    ^
+ old  
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS operator;
  operator 
 ----------
      1234
 (1 row)
 
-SELECT 1234 operator;
-ERROR:  syntax error at or near ";"
-LINE 1: SELECT 1234 operator;
-                            ^
+SELECT 1234 operator;
+ operator 
+----------
+     1234
+(1 row)
+
 SELECT 1234 AS option;
  option 
 --------
@@ -3928,9 +4250,11 @@ SELECT 1234 AS option;
 (1 row)
 
 SELECT 1234 option;
-ERROR:  syntax error at or near "option"
-LINE 1: SELECT 1234 option;
-                    ^
+ option 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS options;
  options 
 ---------
@@ -3938,9 +4262,11 @@ SELECT 1234 AS options;
 (1 row)
 
 SELECT 1234 options;
-ERROR:  syntax error at or near "options"
-LINE 1: SELECT 1234 options;
-                    ^
+ options 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS ordinality;
  ordinality 
 ------------
@@ -3948,9 +4274,11 @@ SELECT 1234 AS ordinality;
 (1 row)
 
 SELECT 1234 ordinality;
-ERROR:  syntax error at or near "ordinality"
-LINE 1: SELECT 1234 ordinality;
-                    ^
+ ordinality 
+------------
+       1234
+(1 row)
+
 SELECT 1234 AS others;
  others 
 --------
@@ -3958,9 +4286,11 @@ SELECT 1234 AS others;
 (1 row)
 
 SELECT 1234 others;
-ERROR:  syntax error at or near "others"
-LINE 1: SELECT 1234 others;
-                    ^
+ others 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS over;
  over 
 ------
@@ -3978,9 +4308,11 @@ SELECT 1234 AS overriding;
 (1 row)
 
 SELECT 1234 overriding;
-ERROR:  syntax error at or near "overriding"
-LINE 1: SELECT 1234 overriding;
-                    ^
+ overriding 
+------------
+       1234
+(1 row)
+
 SELECT 1234 AS owned;
  owned 
 -------
@@ -3988,9 +4320,11 @@ SELECT 1234 AS owned;
 (1 row)
 
 SELECT 1234 owned;
-ERROR:  syntax error at or near "owned"
-LINE 1: SELECT 1234 owned;
-                    ^
+ owned 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS owner;
  owner 
 -------
@@ -3998,9 +4332,11 @@ SELECT 1234 AS owner;
 (1 row)
 
 SELECT 1234 owner;
-ERROR:  syntax error at or near "owner"
-LINE 1: SELECT 1234 owner;
-                    ^
+ owner 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS parallel;
  parallel 
 ----------
@@ -4008,9 +4344,11 @@ SELECT 1234 AS parallel;
 (1 row)
 
 SELECT 1234 parallel;
-ERROR:  syntax error at or near "parallel"
-LINE 1: SELECT 1234 parallel;
-                    ^
+ parallel 
+----------
+     1234
+(1 row)
+
 SELECT 1234 AS parser;
  parser 
 --------
@@ -4018,9 +4356,11 @@ SELECT 1234 AS parser;
 (1 row)
 
 SELECT 1234 parser;
-ERROR:  syntax error at or near "parser"
-LINE 1: SELECT 1234 parser;
-                    ^
+ parser 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS partial;
  partial 
 ---------
@@ -4028,9 +4368,11 @@ SELECT 1234 AS partial;
 (1 row)
 
 SELECT 1234 partial;
-ERROR:  syntax error at or near "partial"
-LINE 1: SELECT 1234 partial;
-                    ^
+ partial 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS partition;
  partition 
 -----------
@@ -4038,9 +4380,11 @@ SELECT 1234 AS partition;
 (1 row)
 
 SELECT 1234 partition;
-ERROR:  syntax error at or near "partition"
-LINE 1: SELECT 1234 partition;
-                    ^
+ partition 
+-----------
+      1234
+(1 row)
+
 SELECT 1234 AS passing;
  passing 
 ---------
@@ -4048,9 +4392,11 @@ SELECT 1234 AS passing;
 (1 row)
 
 SELECT 1234 passing;
-ERROR:  syntax error at or near "passing"
-LINE 1: SELECT 1234 passing;
-                    ^
+ passing 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS password;
  password 
 ----------
@@ -4058,9 +4404,11 @@ SELECT 1234 AS password;
 (1 row)
 
 SELECT 1234 password;
-ERROR:  syntax error at or near "password"
-LINE 1: SELECT 1234 password;
-                    ^
+ password 
+----------
+     1234
+(1 row)
+
 SELECT 1234 AS plans;
  plans 
 -------
@@ -4068,9 +4416,11 @@ SELECT 1234 AS plans;
 (1 row)
 
 SELECT 1234 plans;
-ERROR:  syntax error at or near "plans"
-LINE 1: SELECT 1234 plans;
-                    ^
+ plans 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS policy;
  policy 
 --------
@@ -4078,9 +4428,11 @@ SELECT 1234 AS policy;
 (1 row)
 
 SELECT 1234 policy;
-ERROR:  syntax error at or near "policy"
-LINE 1: SELECT 1234 policy;
-                    ^
+ policy 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS preceding;
  preceding 
 -----------
@@ -4088,9 +4440,11 @@ SELECT 1234 AS preceding;
 (1 row)
 
 SELECT 1234 preceding;
-ERROR:  syntax error at or near "preceding"
-LINE 1: SELECT 1234 preceding;
-                    ^
+ preceding 
+-----------
+      1234
+(1 row)
+
 SELECT 1234 AS prepare;
  prepare 
 ---------
@@ -4098,9 +4452,11 @@ SELECT 1234 AS prepare;
 (1 row)
 
 SELECT 1234 prepare;
-ERROR:  syntax error at or near "prepare"
-LINE 1: SELECT 1234 prepare;
-                    ^
+ prepare 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS prepared;
  prepared 
 ----------
@@ -4108,9 +4464,11 @@ SELECT 1234 AS prepared;
 (1 row)
 
 SELECT 1234 prepared;
-ERROR:  syntax error at or near "prepared"
-LINE 1: SELECT 1234 prepared;
-                    ^
+ prepared 
+----------
+     1234
+(1 row)
+
 SELECT 1234 AS preserve;
  preserve 
 ----------
@@ -4118,9 +4476,11 @@ SELECT 1234 AS preserve;
 (1 row)
 
 SELECT 1234 preserve;
-ERROR:  syntax error at or near "preserve"
-LINE 1: SELECT 1234 preserve;
-                    ^
+ preserve 
+----------
+     1234
+(1 row)
+
 SELECT 1234 AS prior;
  prior 
 -------
@@ -4128,9 +4488,11 @@ SELECT 1234 AS prior;
 (1 row)
 
 SELECT 1234 prior;
-ERROR:  syntax error at or near "prior"
-LINE 1: SELECT 1234 prior;
-                    ^
+ prior 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS privileges;
  privileges 
 ------------
@@ -4138,9 +4500,11 @@ SELECT 1234 AS privileges;
 (1 row)
 
 SELECT 1234 privileges;
-ERROR:  syntax error at or near "privileges"
-LINE 1: SELECT 1234 privileges;
-                    ^
+ privileges 
+------------
+       1234
+(1 row)
+
 SELECT 1234 AS procedural;
  procedural 
 ------------
@@ -4148,9 +4512,11 @@ SELECT 1234 AS procedural;
 (1 row)
 
 SELECT 1234 procedural;
-ERROR:  syntax error at or near "procedural"
-LINE 1: SELECT 1234 procedural;
-                    ^
+ procedural 
+------------
+       1234
+(1 row)
+
 SELECT 1234 AS procedure;
  procedure 
 -----------
@@ -4158,9 +4524,11 @@ SELECT 1234 AS procedure;
 (1 row)
 
 SELECT 1234 procedure;
-ERROR:  syntax error at or near "procedure"
-LINE 1: SELECT 1234 procedure;
-                    ^
+ procedure 
+-----------
+      1234
+(1 row)
+
 SELECT 1234 AS procedures;
  procedures 
 ------------
@@ -4168,9 +4536,11 @@ SELECT 1234 AS procedures;
 (1 row)
 
 SELECT 1234 procedures;
-ERROR:  syntax error at or near "procedures"
-LINE 1: SELECT 1234 procedures;
-                    ^
+ procedures 
+------------
+       1234
+(1 row)
+
 SELECT 1234 AS program;
  program 
 ---------
@@ -4178,9 +4548,11 @@ SELECT 1234 AS program;
 (1 row)
 
 SELECT 1234 program;
-ERROR:  syntax error at or near "program"
-LINE 1: SELECT 1234 program;
-                    ^
+ program 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS publication;
  publication 
 -------------
@@ -4188,9 +4560,11 @@ SELECT 1234 AS publication;
 (1 row)
 
 SELECT 1234 publication;
-ERROR:  syntax error at or near "publication"
-LINE 1: SELECT 1234 publication;
-                    ^
+ publication 
+-------------
+        1234
+(1 row)
+
 SELECT 1234 AS quote;
  quote 
 -------
@@ -4198,9 +4572,11 @@ SELECT 1234 AS quote;
 (1 row)
 
 SELECT 1234 quote;
-ERROR:  syntax error at or near "quote"
-LINE 1: SELECT 1234 quote;
-                    ^
+ quote 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS range;
  range 
 -------
@@ -4208,9 +4584,11 @@ SELECT 1234 AS range;
 (1 row)
 
 SELECT 1234 range;
-ERROR:  syntax error at or near "range"
-LINE 1: SELECT 1234 range;
-                    ^
+ range 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS read;
  read 
 ------
@@ -4218,9 +4596,11 @@ SELECT 1234 AS read;
 (1 row)
 
 SELECT 1234 read;
-ERROR:  syntax error at or near "read"
-LINE 1: SELECT 1234 read;
-                    ^
+ read 
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS reassign;
  reassign 
 ----------
@@ -4228,9 +4608,11 @@ SELECT 1234 AS reassign;
 (1 row)
 
 SELECT 1234 reassign;
-ERROR:  syntax error at or near "reassign"
-LINE 1: SELECT 1234 reassign;
-                    ^
+ reassign 
+----------
+     1234
+(1 row)
+
 SELECT 1234 AS recheck;
  recheck 
 ---------
@@ -4238,9 +4620,11 @@ SELECT 1234 AS recheck;
 (1 row)
 
 SELECT 1234 recheck;
-ERROR:  syntax error at or near "recheck"
-LINE 1: SELECT 1234 recheck;
-                    ^
+ recheck 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS recursive;
  recursive 
 -----------
@@ -4248,9 +4632,11 @@ SELECT 1234 AS recursive;
 (1 row)
 
 SELECT 1234 recursive;
-ERROR:  syntax error at or near "recursive"
-LINE 1: SELECT 1234 recursive;
-                    ^
+ recursive 
+-----------
+      1234
+(1 row)
+
 SELECT 1234 AS ref;
  ref  
 ------
@@ -4258,9 +4644,11 @@ SELECT 1234 AS ref;
 (1 row)
 
 SELECT 1234 ref;
-ERROR:  syntax error at or near "ref"
-LINE 1: SELECT 1234 ref;
-                    ^
+ ref  
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS referencing;
  referencing 
 -------------
@@ -4268,9 +4656,11 @@ SELECT 1234 AS referencing;
 (1 row)
 
 SELECT 1234 referencing;
-ERROR:  syntax error at or near "referencing"
-LINE 1: SELECT 1234 referencing;
-                    ^
+ referencing 
+-------------
+        1234
+(1 row)
+
 SELECT 1234 AS refresh;
  refresh 
 ---------
@@ -4278,9 +4668,11 @@ SELECT 1234 AS refresh;
 (1 row)
 
 SELECT 1234 refresh;
-ERROR:  syntax error at or near "refresh"
-LINE 1: SELECT 1234 refresh;
-                    ^
+ refresh 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS reindex;
  reindex 
 ---------
@@ -4288,9 +4680,11 @@ SELECT 1234 AS reindex;
 (1 row)
 
 SELECT 1234 reindex;
-ERROR:  syntax error at or near "reindex"
-LINE 1: SELECT 1234 reindex;
-                    ^
+ reindex 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS relative;
  relative 
 ----------
@@ -4298,9 +4692,11 @@ SELECT 1234 AS relative;
 (1 row)
 
 SELECT 1234 relative;
-ERROR:  syntax error at or near "relative"
-LINE 1: SELECT 1234 relative;
-                    ^
+ relative 
+----------
+     1234
+(1 row)
+
 SELECT 1234 AS release;
  release 
 ---------
@@ -4308,9 +4704,11 @@ SELECT 1234 AS release;
 (1 row)
 
 SELECT 1234 release;
-ERROR:  syntax error at or near "release"
-LINE 1: SELECT 1234 release;
-                    ^
+ release 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS rename;
  rename 
 --------
@@ -4318,9 +4716,11 @@ SELECT 1234 AS rename;
 (1 row)
 
 SELECT 1234 rename;
-ERROR:  syntax error at or near "rename"
-LINE 1: SELECT 1234 rename;
-                    ^
+ rename 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS repeatable;
  repeatable 
 ------------
@@ -4328,9 +4728,11 @@ SELECT 1234 AS repeatable;
 (1 row)
 
 SELECT 1234 repeatable;
-ERROR:  syntax error at or near "repeatable"
-LINE 1: SELECT 1234 repeatable;
-                    ^
+ repeatable 
+------------
+       1234
+(1 row)
+
 SELECT 1234 AS replace;
  replace 
 ---------
@@ -4338,9 +4740,11 @@ SELECT 1234 AS replace;
 (1 row)
 
 SELECT 1234 replace;
-ERROR:  syntax error at or near "replace"
-LINE 1: SELECT 1234 replace;
-                    ^
+ replace 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS replica;
  replica 
 ---------
@@ -4348,9 +4752,11 @@ SELECT 1234 AS replica;
 (1 row)
 
 SELECT 1234 replica;
-ERROR:  syntax error at or near "replica"
-LINE 1: SELECT 1234 replica;
-                    ^
+ replica 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS reset;
  reset 
 -------
@@ -4358,9 +4764,11 @@ SELECT 1234 AS reset;
 (1 row)
 
 SELECT 1234 reset;
-ERROR:  syntax error at or near "reset"
-LINE 1: SELECT 1234 reset;
-                    ^
+ reset 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS restart;
  restart 
 ---------
@@ -4368,9 +4776,11 @@ SELECT 1234 AS restart;
 (1 row)
 
 SELECT 1234 restart;
-ERROR:  syntax error at or near "restart"
-LINE 1: SELECT 1234 restart;
-                    ^
+ restart 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS restrict;
  restrict 
 ----------
@@ -4378,9 +4788,11 @@ SELECT 1234 AS restrict;
 (1 row)
 
 SELECT 1234 restrict;
-ERROR:  syntax error at or near "restrict"
-LINE 1: SELECT 1234 restrict;
-                    ^
+ restrict 
+----------
+     1234
+(1 row)
+
 SELECT 1234 AS returns;
  returns 
 ---------
@@ -4388,9 +4800,11 @@ SELECT 1234 AS returns;
 (1 row)
 
 SELECT 1234 returns;
-ERROR:  syntax error at or near "returns"
-LINE 1: SELECT 1234 returns;
-                    ^
+ returns 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS revoke;
  revoke 
 --------
@@ -4398,9 +4812,11 @@ SELECT 1234 AS revoke;
 (1 row)
 
 SELECT 1234 revoke;
-ERROR:  syntax error at or near "revoke"
-LINE 1: SELECT 1234 revoke;
-                    ^
+ revoke 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS role;
  role 
 ------
@@ -4408,9 +4824,11 @@ SELECT 1234 AS role;
 (1 row)
 
 SELECT 1234 role;
-ERROR:  syntax error at or near "role"
-LINE 1: SELECT 1234 role;
-                    ^
+ role 
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS rollback;
  rollback 
 ----------
@@ -4418,9 +4836,11 @@ SELECT 1234 AS rollback;
 (1 row)
 
 SELECT 1234 rollback;
-ERROR:  syntax error at or near "rollback"
-LINE 1: SELECT 1234 rollback;
-                    ^
+ rollback 
+----------
+     1234
+(1 row)
+
 SELECT 1234 AS rollup;
  rollup 
 --------
@@ -4428,9 +4848,11 @@ SELECT 1234 AS rollup;
 (1 row)
 
 SELECT 1234 rollup;
-ERROR:  syntax error at or near "rollup"
-LINE 1: SELECT 1234 rollup;
-                    ^
+ rollup 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS routine;
  routine 
 ---------
@@ -4438,9 +4860,11 @@ SELECT 1234 AS routine;
 (1 row)
 
 SELECT 1234 routine;
-ERROR:  syntax error at or near "routine"
-LINE 1: SELECT 1234 routine;
-                    ^
+ routine 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS routines;
  routines 
 ----------
@@ -4448,9 +4872,11 @@ SELECT 1234 AS routines;
 (1 row)
 
 SELECT 1234 routines;
-ERROR:  syntax error at or near "routines"
-LINE 1: SELECT 1234 routines;
-                    ^
+ routines 
+----------
+     1234
+(1 row)
+
 SELECT 1234 AS rows;
  rows 
 ------
@@ -4458,9 +4884,11 @@ SELECT 1234 AS rows;
 (1 row)
 
 SELECT 1234 rows;
-ERROR:  syntax error at or near "rows"
-LINE 1: SELECT 1234 rows;
-                    ^
+ rows 
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS rule;
  rule 
 ------
@@ -4468,9 +4896,11 @@ SELECT 1234 AS rule;
 (1 row)
 
 SELECT 1234 rule;
-ERROR:  syntax error at or near "rule"
-LINE 1: SELECT 1234 rule;
-                    ^
+ rule 
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS savepoint;
  savepoint 
 -----------
@@ -4478,9 +4908,11 @@ SELECT 1234 AS savepoint;
 (1 row)
 
 SELECT 1234 savepoint;
-ERROR:  syntax error at or near "savepoint"
-LINE 1: SELECT 1234 savepoint;
-                    ^
+ savepoint 
+-----------
+      1234
+(1 row)
+
 SELECT 1234 AS schema;
  schema 
 --------
@@ -4488,9 +4920,11 @@ SELECT 1234 AS schema;
 (1 row)
 
 SELECT 1234 schema;
-ERROR:  syntax error at or near "schema"
-LINE 1: SELECT 1234 schema;
-                    ^
+ schema 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS schemas;
  schemas 
 ---------
@@ -4498,9 +4932,11 @@ SELECT 1234 AS schemas;
 (1 row)
 
 SELECT 1234 schemas;
-ERROR:  syntax error at or near "schemas"
-LINE 1: SELECT 1234 schemas;
-                    ^
+ schemas 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS scroll;
  scroll 
 --------
@@ -4508,9 +4944,11 @@ SELECT 1234 AS scroll;
 (1 row)
 
 SELECT 1234 scroll;
-ERROR:  syntax error at or near "scroll"
-LINE 1: SELECT 1234 scroll;
-                    ^
+ scroll 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS search;
  search 
 --------
@@ -4518,9 +4956,11 @@ SELECT 1234 AS search;
 (1 row)
 
 SELECT 1234 search;
-ERROR:  syntax error at or near "search"
-LINE 1: SELECT 1234 search;
-                    ^
+ search 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS second;
  second 
 --------
@@ -4538,9 +4978,11 @@ SELECT 1234 AS security;
 (1 row)
 
 SELECT 1234 security;
-ERROR:  syntax error at or near "security"
-LINE 1: SELECT 1234 security;
-                    ^
+ security 
+----------
+     1234
+(1 row)
+
 SELECT 1234 AS sequence;
  sequence 
 ----------
@@ -4548,9 +4990,11 @@ SELECT 1234 AS sequence;
 (1 row)
 
 SELECT 1234 sequence;
-ERROR:  syntax error at or near "sequence"
-LINE 1: SELECT 1234 sequence;
-                    ^
+ sequence 
+----------
+     1234
+(1 row)
+
 SELECT 1234 AS sequences;
  sequences 
 -----------
@@ -4558,9 +5002,11 @@ SELECT 1234 AS sequences;
 (1 row)
 
 SELECT 1234 sequences;
-ERROR:  syntax error at or near "sequences"
-LINE 1: SELECT 1234 sequences;
-                    ^
+ sequences 
+-----------
+      1234
+(1 row)
+
 SELECT 1234 AS serializable;
  serializable 
 --------------
@@ -4568,9 +5014,11 @@ SELECT 1234 AS serializable;
 (1 row)
 
 SELECT 1234 serializable;
-ERROR:  syntax error at or near "serializable"
-LINE 1: SELECT 1234 serializable;
-                    ^
+ serializable 
+--------------
+         1234
+(1 row)
+
 SELECT 1234 AS server;
  server 
 --------
@@ -4578,9 +5026,11 @@ SELECT 1234 AS server;
 (1 row)
 
 SELECT 1234 server;
-ERROR:  syntax error at or near "server"
-LINE 1: SELECT 1234 server;
-                    ^
+ server 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS session;
  session 
 ---------
@@ -4588,9 +5038,11 @@ SELECT 1234 AS session;
 (1 row)
 
 SELECT 1234 session;
-ERROR:  syntax error at or near "session"
-LINE 1: SELECT 1234 session;
-                    ^
+ session 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS set;
  set  
 ------
@@ -4598,9 +5050,11 @@ SELECT 1234 AS set;
 (1 row)
 
 SELECT 1234 set;
-ERROR:  syntax error at or near "set"
-LINE 1: SELECT 1234 set;
-                    ^
+ set  
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS sets;
  sets 
 ------
@@ -4608,9 +5062,11 @@ SELECT 1234 AS sets;
 (1 row)
 
 SELECT 1234 sets;
-ERROR:  syntax error at or near "sets"
-LINE 1: SELECT 1234 sets;
-                    ^
+ sets 
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS share;
  share 
 -------
@@ -4618,9 +5074,11 @@ SELECT 1234 AS share;
 (1 row)
 
 SELECT 1234 share;
-ERROR:  syntax error at or near "share"
-LINE 1: SELECT 1234 share;
-                    ^
+ share 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS show;
  show 
 ------
@@ -4628,9 +5086,11 @@ SELECT 1234 AS show;
 (1 row)
 
 SELECT 1234 show;
-ERROR:  syntax error at or near "show"
-LINE 1: SELECT 1234 show;
-                    ^
+ show 
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS simple;
  simple 
 --------
@@ -4638,9 +5098,11 @@ SELECT 1234 AS simple;
 (1 row)
 
 SELECT 1234 simple;
-ERROR:  syntax error at or near "simple"
-LINE 1: SELECT 1234 simple;
-                    ^
+ simple 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS skip;
  skip 
 ------
@@ -4648,9 +5110,11 @@ SELECT 1234 AS skip;
 (1 row)
 
 SELECT 1234 skip;
-ERROR:  syntax error at or near "skip"
-LINE 1: SELECT 1234 skip;
-                    ^
+ skip 
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS snapshot;
  snapshot 
 ----------
@@ -4658,9 +5122,11 @@ SELECT 1234 AS snapshot;
 (1 row)
 
 SELECT 1234 snapshot;
-ERROR:  syntax error at or near "snapshot"
-LINE 1: SELECT 1234 snapshot;
-                    ^
+ snapshot 
+----------
+     1234
+(1 row)
+
 SELECT 1234 AS sql;
  sql  
 ------
@@ -4668,9 +5134,11 @@ SELECT 1234 AS sql;
 (1 row)
 
 SELECT 1234 sql;
-ERROR:  syntax error at or near "sql"
-LINE 1: SELECT 1234 sql;
-                    ^
+ sql  
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS stable;
  stable 
 --------
@@ -4678,9 +5146,11 @@ SELECT 1234 AS stable;
 (1 row)
 
 SELECT 1234 stable;
-ERROR:  syntax error at or near "stable"
-LINE 1: SELECT 1234 stable;
-                    ^
+ stable 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS standalone;
  standalone 
 ------------
@@ -4688,9 +5158,11 @@ SELECT 1234 AS standalone;
 (1 row)
 
 SELECT 1234 standalone;
-ERROR:  syntax error at or near "standalone"
-LINE 1: SELECT 1234 standalone;
-                    ^
+ standalone 
+------------
+       1234
+(1 row)
+
 SELECT 1234 AS start;
  start 
 -------
@@ -4698,9 +5170,11 @@ SELECT 1234 AS start;
 (1 row)
 
 SELECT 1234 start;
-ERROR:  syntax error at or near "start"
-LINE 1: SELECT 1234 start;
-                    ^
+ start 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS statement;
  statement 
 -----------
@@ -4708,9 +5182,11 @@ SELECT 1234 AS statement;
 (1 row)
 
 SELECT 1234 statement;
-ERROR:  syntax error at or near "statement"
-LINE 1: SELECT 1234 statement;
-                    ^
+ statement 
+-----------
+      1234
+(1 row)
+
 SELECT 1234 AS statistics;
  statistics 
 ------------
@@ -4718,9 +5194,11 @@ SELECT 1234 AS statistics;
 (1 row)
 
 SELECT 1234 statistics;
-ERROR:  syntax error at or near "statistics"
-LINE 1: SELECT 1234 statistics;
-                    ^
+ statistics 
+------------
+       1234
+(1 row)
+
 SELECT 1234 AS stdin;
  stdin 
 -------
@@ -4728,9 +5206,11 @@ SELECT 1234 AS stdin;
 (1 row)
 
 SELECT 1234 stdin;
-ERROR:  syntax error at or near "stdin"
-LINE 1: SELECT 1234 stdin;
-                    ^
+ stdin 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS stdout;
  stdout 
 --------
@@ -4738,9 +5218,11 @@ SELECT 1234 AS stdout;
 (1 row)
 
 SELECT 1234 stdout;
-ERROR:  syntax error at or near "stdout"
-LINE 1: SELECT 1234 stdout;
-                    ^
+ stdout 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS storage;
  storage 
 ---------
@@ -4748,9 +5230,11 @@ SELECT 1234 AS storage;
 (1 row)
 
 SELECT 1234 storage;
-ERROR:  syntax error at or near "storage"
-LINE 1: SELECT 1234 storage;
-                    ^
+ storage 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS stored;
  stored 
 --------
@@ -4758,9 +5242,11 @@ SELECT 1234 AS stored;
 (1 row)
 
 SELECT 1234 stored;
-ERROR:  syntax error at or near "stored"
-LINE 1: SELECT 1234 stored;
-                    ^
+ stored 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS strict;
  strict 
 --------
@@ -4768,9 +5254,11 @@ SELECT 1234 AS strict;
 (1 row)
 
 SELECT 1234 strict;
-ERROR:  syntax error at or near "strict"
-LINE 1: SELECT 1234 strict;
-                    ^
+ strict 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS strip;
  strip 
 -------
@@ -4778,19 +5266,23 @@ SELECT 1234 AS strip;
 (1 row)
 
 SELECT 1234 strip;
-ERROR:  syntax error at or near "strip"
-LINE 1: SELECT 1234 strip;
-                    ^
+ strip 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS subscription;
  subscription 
 --------------
          1234
 (1 row)
 
-SELECT 1234 subscription;
-ERROR:  syntax error at or near "subscription"
-LINE 1: SELECT 1234 subscription;
-                    ^
+SELECT 1234 subscription;
+ subscription 
+--------------
+         1234
+(1 row)
+
 SELECT 1234 AS support;
  support 
 ---------
@@ -4798,9 +5290,11 @@ SELECT 1234 AS support;
 (1 row)
 
 SELECT 1234 support;
-ERROR:  syntax error at or near "support"
-LINE 1: SELECT 1234 support;
-                    ^
+ support 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS sysid;
  sysid 
 -------
@@ -4808,9 +5302,11 @@ SELECT 1234 AS sysid;
 (1 row)
 
 SELECT 1234 sysid;
-ERROR:  syntax error at or near "sysid"
-LINE 1: SELECT 1234 sysid;
-                    ^
+ sysid 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS system;
  system 
 --------
@@ -4818,9 +5314,11 @@ SELECT 1234 AS system;
 (1 row)
 
 SELECT 1234 system;
-ERROR:  syntax error at or near "system"
-LINE 1: SELECT 1234 system;
-                    ^
+ system 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS tables;
  tables 
 --------
@@ -4828,9 +5326,11 @@ SELECT 1234 AS tables;
 (1 row)
 
 SELECT 1234 tables;
-ERROR:  syntax error at or near "tables"
-LINE 1: SELECT 1234 tables;
-                    ^
+ tables 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS tablespace;
  tablespace 
 ------------
@@ -4838,9 +5338,11 @@ SELECT 1234 AS tablespace;
 (1 row)
 
 SELECT 1234 tablespace;
-ERROR:  syntax error at or near "tablespace"
-LINE 1: SELECT 1234 tablespace;
-                    ^
+ tablespace 
+------------
+       1234
+(1 row)
+
 SELECT 1234 AS temp;
  temp 
 ------
@@ -4848,9 +5350,11 @@ SELECT 1234 AS temp;
 (1 row)
 
 SELECT 1234 temp;
-ERROR:  syntax error at or near "temp"
-LINE 1: SELECT 1234 temp;
-                    ^
+ temp 
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS template;
  template 
 ----------
@@ -4858,9 +5362,11 @@ SELECT 1234 AS template;
 (1 row)
 
 SELECT 1234 template;
-ERROR:  syntax error at or near "template"
-LINE 1: SELECT 1234 template;
-                    ^
+ template 
+----------
+     1234
+(1 row)
+
 SELECT 1234 AS temporary;
  temporary 
 -----------
@@ -4868,9 +5374,11 @@ SELECT 1234 AS temporary;
 (1 row)
 
 SELECT 1234 temporary;
-ERROR:  syntax error at or near "temporary"
-LINE 1: SELECT 1234 temporary;
-                    ^
+ temporary 
+-----------
+      1234
+(1 row)
+
 SELECT 1234 AS text;
  text 
 ------
@@ -4878,9 +5386,11 @@ SELECT 1234 AS text;
 (1 row)
 
 SELECT 1234 text;
-ERROR:  syntax error at or near "text"
-LINE 1: SELECT 1234 text;
-                    ^
+ text 
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS ties;
  ties 
 ------
@@ -4888,9 +5398,11 @@ SELECT 1234 AS ties;
 (1 row)
 
 SELECT 1234 ties;
-ERROR:  syntax error at or near "ties"
-LINE 1: SELECT 1234 ties;
-                    ^
+ ties 
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS transaction;
  transaction 
 -------------
@@ -4898,9 +5410,11 @@ SELECT 1234 AS transaction;
 (1 row)
 
 SELECT 1234 transaction;
-ERROR:  syntax error at or near "transaction"
-LINE 1: SELECT 1234 transaction;
-                    ^
+ transaction 
+-------------
+        1234
+(1 row)
+
 SELECT 1234 AS transform;
  transform 
 -----------
@@ -4908,9 +5422,11 @@ SELECT 1234 AS transform;
 (1 row)
 
 SELECT 1234 transform;
-ERROR:  syntax error at or near "transform"
-LINE 1: SELECT 1234 transform;
-                    ^
+ transform 
+-----------
+      1234
+(1 row)
+
 SELECT 1234 AS trigger;
  trigger 
 ---------
@@ -4918,9 +5434,11 @@ SELECT 1234 AS trigger;
 (1 row)
 
 SELECT 1234 trigger;
-ERROR:  syntax error at or near "trigger"
-LINE 1: SELECT 1234 trigger;
-                    ^
+ trigger 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS truncate;
  truncate 
 ----------
@@ -4928,9 +5446,11 @@ SELECT 1234 AS truncate;
 (1 row)
 
 SELECT 1234 truncate;
-ERROR:  syntax error at or near "truncate"
-LINE 1: SELECT 1234 truncate;
-                    ^
+ truncate 
+----------
+     1234
+(1 row)
+
 SELECT 1234 AS trusted;
  trusted 
 ---------
@@ -4938,9 +5458,11 @@ SELECT 1234 AS trusted;
 (1 row)
 
 SELECT 1234 trusted;
-ERROR:  syntax error at or near "trusted"
-LINE 1: SELECT 1234 trusted;
-                    ^
+ trusted 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS type;
  type 
 ------
@@ -4948,9 +5470,11 @@ SELECT 1234 AS type;
 (1 row)
 
 SELECT 1234 type;
-ERROR:  syntax error at or near "type"
-LINE 1: SELECT 1234 type;
-                    ^
+ type 
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS types;
  types 
 -------
@@ -4958,9 +5482,11 @@ SELECT 1234 AS types;
 (1 row)
 
 SELECT 1234 types;
-ERROR:  syntax error at or near "types"
-LINE 1: SELECT 1234 types;
-                    ^
+ types 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS uescape;
  uescape 
 ---------
@@ -4968,9 +5494,11 @@ SELECT 1234 AS uescape;
 (1 row)
 
 SELECT 1234 uescape;
-ERROR:  syntax error at or near "uescape"
-LINE 1: SELECT 1234 uescape;
-                    ^
+ uescape 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS unbounded;
  unbounded 
 -----------
@@ -4978,9 +5506,11 @@ SELECT 1234 AS unbounded;
 (1 row)
 
 SELECT 1234 unbounded;
-ERROR:  syntax error at or near "unbounded"
-LINE 1: SELECT 1234 unbounded;
-                    ^
+ unbounded 
+-----------
+      1234
+(1 row)
+
 SELECT 1234 AS uncommitted;
  uncommitted 
 -------------
@@ -4988,9 +5518,11 @@ SELECT 1234 AS uncommitted;
 (1 row)
 
 SELECT 1234 uncommitted;
-ERROR:  syntax error at or near "uncommitted"
-LINE 1: SELECT 1234 uncommitted;
-                    ^
+ uncommitted 
+-------------
+        1234
+(1 row)
+
 SELECT 1234 AS unencrypted;
  unencrypted 
 -------------
@@ -4998,9 +5530,11 @@ SELECT 1234 AS unencrypted;
 (1 row)
 
 SELECT 1234 unencrypted;
-ERROR:  syntax error at or near "unencrypted"
-LINE 1: SELECT 1234 unencrypted;
-                    ^
+ unencrypted 
+-------------
+        1234
+(1 row)
+
 SELECT 1234 AS unknown;
  unknown 
 ---------
@@ -5008,9 +5542,11 @@ SELECT 1234 AS unknown;
 (1 row)
 
 SELECT 1234 unknown;
-ERROR:  syntax error at or near "unknown"
-LINE 1: SELECT 1234 unknown;
-                    ^
+ unknown 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS unlisten;
  unlisten 
 ----------
@@ -5018,9 +5554,11 @@ SELECT 1234 AS unlisten;
 (1 row)
 
 SELECT 1234 unlisten;
-ERROR:  syntax error at or near "unlisten"
-LINE 1: SELECT 1234 unlisten;
-                    ^
+ unlisten 
+----------
+     1234
+(1 row)
+
 SELECT 1234 AS unlogged;
  unlogged 
 ----------
@@ -5028,9 +5566,11 @@ SELECT 1234 AS unlogged;
 (1 row)
 
 SELECT 1234 unlogged;
-ERROR:  syntax error at or near "unlogged"
-LINE 1: SELECT 1234 unlogged;
-                    ^
+ unlogged 
+----------
+     1234
+(1 row)
+
 SELECT 1234 AS until;
  until 
 -------
@@ -5038,9 +5578,11 @@ SELECT 1234 AS until;
 (1 row)
 
 SELECT 1234 until;
-ERROR:  syntax error at or near "until"
-LINE 1: SELECT 1234 until;
-                    ^
+ until 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS update;
  update 
 --------
@@ -5048,9 +5590,11 @@ SELECT 1234 AS update;
 (1 row)
 
 SELECT 1234 update;
-ERROR:  syntax error at or near "update"
-LINE 1: SELECT 1234 update;
-                    ^
+ update 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS vacuum;
  vacuum 
 --------
@@ -5058,9 +5602,11 @@ SELECT 1234 AS vacuum;
 (1 row)
 
 SELECT 1234 vacuum;
-ERROR:  syntax error at or near "vacuum"
-LINE 1: SELECT 1234 vacuum;
-                    ^
+ vacuum 
+--------
+   1234
+(1 row)
+
 SELECT 1234 AS valid;
  valid 
 -------
@@ -5068,9 +5614,11 @@ SELECT 1234 AS valid;
 (1 row)
 
 SELECT 1234 valid;
-ERROR:  syntax error at or near "valid"
-LINE 1: SELECT 1234 valid;
-                    ^
+ valid 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS validate;
  validate 
 ----------
@@ -5078,9 +5626,11 @@ SELECT 1234 AS validate;
 (1 row)
 
 SELECT 1234 validate;
-ERROR:  syntax error at or near "validate"
-LINE 1: SELECT 1234 validate;
-                    ^
+ validate 
+----------
+     1234
+(1 row)
+
 SELECT 1234 AS validator;
  validator 
 -----------
@@ -5088,9 +5638,11 @@ SELECT 1234 AS validator;
 (1 row)
 
 SELECT 1234 validator;
-ERROR:  syntax error at or near "validator"
-LINE 1: SELECT 1234 validator;
-                    ^
+ validator 
+-----------
+      1234
+(1 row)
+
 SELECT 1234 AS value;
  value 
 -------
@@ -5098,9 +5650,11 @@ SELECT 1234 AS value;
 (1 row)
 
 SELECT 1234 value;
-ERROR:  syntax error at or near "value"
-LINE 1: SELECT 1234 value;
-                    ^
+ value 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS varying;
  varying 
 ---------
@@ -5118,9 +5672,11 @@ SELECT 1234 AS version;
 (1 row)
 
 SELECT 1234 version;
-ERROR:  syntax error at or near "version"
-LINE 1: SELECT 1234 version;
-                    ^
+ version 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS view;
  view 
 ------
@@ -5128,9 +5684,11 @@ SELECT 1234 AS view;
 (1 row)
 
 SELECT 1234 view;
-ERROR:  syntax error at or near "view"
-LINE 1: SELECT 1234 view;
-                    ^
+ view 
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS views;
  views 
 -------
@@ -5138,9 +5696,11 @@ SELECT 1234 AS views;
 (1 row)
 
 SELECT 1234 views;
-ERROR:  syntax error at or near "views"
-LINE 1: SELECT 1234 views;
-                    ^
+ views 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS volatile;
  volatile 
 ----------
@@ -5148,9 +5708,11 @@ SELECT 1234 AS volatile;
 (1 row)
 
 SELECT 1234 volatile;
-ERROR:  syntax error at or near "volatile"
-LINE 1: SELECT 1234 volatile;
-                    ^
+ volatile 
+----------
+     1234
+(1 row)
+
 SELECT 1234 AS whitespace;
  whitespace 
 ------------
@@ -5158,9 +5720,11 @@ SELECT 1234 AS whitespace;
 (1 row)
 
 SELECT 1234 whitespace;
-ERROR:  syntax error at or near "whitespace"
-LINE 1: SELECT 1234 whitespace;
-                    ^
+ whitespace 
+------------
+       1234
+(1 row)
+
 SELECT 1234 AS within;
  within 
 --------
@@ -5188,9 +5752,11 @@ SELECT 1234 AS work;
 (1 row)
 
 SELECT 1234 work;
-ERROR:  syntax error at or near "work"
-LINE 1: SELECT 1234 work;
-                    ^
+ work 
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS wrapper;
  wrapper 
 ---------
@@ -5198,9 +5764,11 @@ SELECT 1234 AS wrapper;
 (1 row)
 
 SELECT 1234 wrapper;
-ERROR:  syntax error at or near "wrapper"
-LINE 1: SELECT 1234 wrapper;
-                    ^
+ wrapper 
+---------
+    1234
+(1 row)
+
 SELECT 1234 AS write;
  write 
 -------
@@ -5208,9 +5776,11 @@ SELECT 1234 AS write;
 (1 row)
 
 SELECT 1234 write;
-ERROR:  syntax error at or near "write"
-LINE 1: SELECT 1234 write;
-                    ^
+ write 
+-------
+  1234
+(1 row)
+
 SELECT 1234 AS xml;
  xml  
 ------
@@ -5218,9 +5788,11 @@ SELECT 1234 AS xml;
 (1 row)
 
 SELECT 1234 xml;
-ERROR:  syntax error at or near "xml"
-LINE 1: SELECT 1234 xml;
-                    ^
+ xml  
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS year;
  year 
 ------
@@ -5238,9 +5810,11 @@ SELECT 1234 AS yes;
 (1 row)
 
 SELECT 1234 yes;
-ERROR:  syntax error at or near "yes"
-LINE 1: SELECT 1234 yes;
-                    ^
+ yes  
+------
+ 1234
+(1 row)
+
 SELECT 1234 AS zone;
  zone 
 ------
@@ -5248,6 +5822,8 @@ SELECT 1234 AS zone;
 (1 row)
 
 SELECT 1234 zone;
-ERROR:  syntax error at or near "zone"
-LINE 1: SELECT 1234 zone;
-                    ^
+ zone 
+------
+ 1234
+(1 row)
+
diff --git a/src/test/regress/expected/create_operator.out b/src/test/regress/expected/create_operator.out
index 54e8b79159..ed77a6616e 100644
--- a/src/test/regress/expected/create_operator.out
+++ b/src/test/regress/expected/create_operator.out
@@ -22,10 +22,14 @@ CREATE OPERATOR #@# (
    leftarg = int8,		-- right unary
    procedure = numeric_fac
 );
+ERROR:  rightarg must be specified
+HINT:  postfix operator support has been discontinued
 CREATE OPERATOR #%# (
    leftarg = int8,		-- right unary
    procedure = numeric_fac
 );
+ERROR:  rightarg must be specified
+HINT:  postfix operator support has been discontinued
 -- Test operator created above
 SELECT point '(1,2)' <% widget '(0,0,3)' AS t,
        point '(1,2)' <% widget '(0,0,1)' AS f;
@@ -52,12 +56,12 @@ CREATE OPERATOR !=- (
    leftarg = int8,		-- right unary
    procedure = numeric_fac
 );
+ERROR:  rightarg must be specified
+HINT:  postfix operator support has been discontinued
 SELECT 2 !=-;
- ?column? 
-----------
-        2
-(1 row)
-
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 2 !=-;
+                    ^
 -- make sure lexer returns != as <> even in edge cases
 SELECT 2 !=/**/ 1, 2 !=/**/ 2;
  ?column? | ?column? 
@@ -172,11 +176,13 @@ CREATE OPERATOR #@%# (
    invalid_att = int8
 );
 WARNING:  operator attribute "invalid_att" not recognized
--- Should fail. At least leftarg or rightarg should be mandatorily specified
+ERROR:  rightarg must be specified
+HINT:  postfix operator support has been discontinued
+-- Should fail. At least rightarg should be mandatorily specified
 CREATE OPERATOR #@%# (
    procedure = numeric_fac
 );
-ERROR:  at least one of leftarg or rightarg must be specified
+ERROR:  at least rightarg must be specified
 -- Should fail. Procedure should be mandatorily specified
 CREATE OPERATOR #@%# (
    leftarg = int8
diff --git a/src/test/regress/expected/numeric.out b/src/test/regress/expected/numeric.out
index 81a0c5d40f..8b2e29779d 100644
--- a/src/test/regress/expected/numeric.out
+++ b/src/test/regress/expected/numeric.out
@@ -2318,7 +2318,7 @@ ERROR:  value overflows numeric format
 --
 -- Tests for factorial
 --
-SELECT 4!;
+SELECT !!4;
  ?column? 
 ----------
        24
@@ -2336,19 +2336,38 @@ SELECT factorial(15);
  1307674368000
 (1 row)
 
-SELECT 100000!;
+SELECT !!100000;
 ERROR:  value overflows numeric format
-SELECT 0!;
+SELECT !!0;
  ?column? 
 ----------
         1
 (1 row)
 
-SELECT -4!;
+SELECT !!(-4);
 ERROR:  factorial of a negative number is undefined
 SELECT factorial(-4);
 ERROR:  factorial of a negative number is undefined
 --
+-- Postfix operator support has been removed.
+--
+SELECT -5!;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT -5!;
+                  ^
+SELECT -0!;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT -0!;
+                  ^
+SELECT 0!;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 0!;
+                 ^
+SELECT 100!;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 100!;
+                   ^
+--
 -- Tests for pg_lsn()
 --
 SELECT pg_lsn(23783416::numeric);
diff --git a/src/test/regress/sql/create_operator.sql b/src/test/regress/sql/create_operator.sql
index 8b6fd0bb43..eb2335e0ef 100644
--- a/src/test/regress/sql/create_operator.sql
+++ b/src/test/regress/sql/create_operator.sql
@@ -133,7 +133,7 @@ CREATE OPERATOR #@%# (
    invalid_att = int8
 );
 
--- Should fail. At least leftarg or rightarg should be mandatorily specified
+-- Should fail. At least rightarg should be mandatorily specified
 CREATE OPERATOR #@%# (
    procedure = numeric_fac
 );
diff --git a/src/test/regress/sql/numeric.sql b/src/test/regress/sql/numeric.sql
index 5dc80f686f..f8ce69422e 100644
--- a/src/test/regress/sql/numeric.sql
+++ b/src/test/regress/sql/numeric.sql
@@ -1115,14 +1115,22 @@ SELECT lcm(9999 * (10::numeric)^131068 + (10::numeric^131068 - 1), 2); -- overfl
 --
 -- Tests for factorial
 --
-SELECT 4!;
+SELECT !!4;
 SELECT !!3;
 SELECT factorial(15);
-SELECT 100000!;
-SELECT 0!;
-SELECT -4!;
+SELECT !!100000;
+SELECT !!0;
+SELECT !!(-4);
 SELECT factorial(-4);
 
+--
+-- Postfix operator support has been removed.
+--
+SELECT -5!;
+SELECT -0!;
+SELECT 0!;
+SELECT 100!;
+
 --
 -- Tests for pg_lsn()
 --
-- 
2.21.1 (Apple Git-122.3)

#32Mark Dilger
mark.dilger@enterprisedb.com
In reply to: Mark Dilger (#31)
1 attachment(s)
Re: factorial function/phase out postfix operators?

On Jun 30, 2020, at 2:47 PM, Mark Dilger <mark.dilger@enterprisedb.com> wrote:

On May 19, 2020, at 4:47 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

I wrote:

However, we do have to have a benefit to show those people whose
queries we break. Hence my insistence on having a working AS fix
(or some other benefit) before not after.

I experimented with this a bit more, and came up with the attached.
It's not a working patch, just a set of grammar changes that Bison
is happy with. (Getting to a working patch would require fixing the
various build infrastructure that knows about the keyword classification,
which seems straightforward but tedious.)

I built a patch on top of yours that does much of that tedious work.

As Robert theorized, it works to move a fairly-small number of unreserved
keywords into a new slightly-reserved category. However, as the patch
stands, only the remaining fully-unreserved keywords can be used as bare
column labels. I'd hoped to be able to also use col_name keywords in that
way (which'd make the set of legal bare column labels mostly the same as
ColId). The col_name keywords that cause problems are, it appears,
only PRECISION, CHARACTER, and CHAR_P. So in principle we could move
those three into yet another keyword category and then let the remaining
col_name keywords be included in BareColLabel. I kind of think that
that's more complication than it's worth, though.

By my count, 288 more keywords can be used as column aliases without the AS keyword after the patch. That exactly matches what Robert said upthread.

Tom and Álvaro discussed upthread:

Would it make sense (and possible) to have a keyword category that is
not disjoint wrt. the others? Maybe that ends up being easier than
a solution that ends up with six or seven categories.

Version 2, attached, follows this design, increasing the number of keywords that can be used as column aliases without the AS keyword up to 411, with only 39 keywords still requiring an explicit preceding AS.

Attachments:

v2-0001-Allow-most-keywords-to-be-used-as-implicit-column.patchapplication/octet-stream; name=v2-0001-Allow-most-keywords-to-be-used-as-implicit-column.patch; x-unix-mode=0644Download
From a77c305918223854a267c0c0df48df814784d97c Mon Sep 17 00:00:00 2001
From: Mark Dilger <mark.dilger@enterprisedb.com>
Date: Fri, 10 Jul 2020 08:30:27 -0700
Subject: [PATCH v2] Allow most keywords to be used as implicit column labels.

Previously, to use a keyword as a column label in an expression, the
keyword had to be preceded by the token AS.  That is no longer
required for most keywords.  This is accomplished with some changes
to gram.y and by removing support for postfix operators.

These keywords must still be preceded by AS:

    array, as, char, character, create, day, except, fetch, filter,
    for, from, grant, group, having, hour, intersect, into, isnull,
    limit, minute, month, notnull, offset, on, order, over,
    overlaps, precision, returning, second, to, union, varying,
    where, window, with, within, without, year

The postfix operator removal constitutes a backward compatibility
break.
---
 .../postgres_fdw/expected/postgres_fdw.out    |   8 +-
 contrib/postgres_fdw/sql/postgres_fdw.sql     |   2 +-
 doc/src/sgml/generate-keywords-table.pl       |   2 +-
 src/backend/commands/operatorcmds.c           |  18 +-
 src/backend/parser/check_keywords.pl          |  46 +-
 src/backend/parser/gram.y                     | 474 ++++++++-
 src/backend/parser/scan.l                     |   2 +-
 src/backend/utils/adt/misc.c                  |   4 +
 src/common/keywords.c                         |   2 +-
 src/include/common/keywords.h                 |   7 +-
 src/include/parser/kwlist.h                   | 900 +++++++++---------
 src/interfaces/ecpg/preproc/keywords.c        |   2 +-
 src/test/regress/expected/create_operator.out |  20 +-
 src/test/regress/expected/numeric.out         |  27 +-
 src/test/regress/sql/create_operator.sql      |   2 +-
 src/test/regress/sql/numeric.sql              |  16 +-
 16 files changed, 1030 insertions(+), 502 deletions(-)

diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index 82fc1290ef..4306ae31c9 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -653,12 +653,12 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 = -c1;          -- Op
    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = (- "C 1")))
 (3 rows)
 
-EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE 1 = c1!;           -- OpExpr(r)
-                                                QUERY PLAN                                                
-----------------------------------------------------------------------------------------------------------
+EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE 1 = !!c1;          -- OpExpr(r)
+                                                QUERY PLAN                                                 
+-----------------------------------------------------------------------------------------------------------
  Foreign Scan on public.ft1 t1
    Output: c1, c2, c3, c4, c5, c6, c7, c8
-   Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE ((1::numeric = ("C 1" !)))
+   Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE ((1::numeric = (!! "C 1")))
 (3 rows)
 
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE (c1 IS NOT NULL) IS DISTINCT FROM (c1 IS NOT NULL); -- DistinctExpr
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index 83971665e3..a8e58a8f24 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -307,7 +307,7 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 IS NULL;        -- Nu
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 IS NOT NULL;    -- NullTest
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE round(abs(c1), 0) = 1; -- FuncExpr
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 = -c1;          -- OpExpr(l)
-EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE 1 = c1!;           -- OpExpr(r)
+EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE 1 = !!c1;          -- OpExpr(r)
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE (c1 IS NOT NULL) IS DISTINCT FROM (c1 IS NOT NULL); -- DistinctExpr
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 = ANY(ARRAY[c2, 1, c1 + 0]); -- ScalarArrayOpExpr
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 = (ARRAY[c1,c2,3])[1]; -- SubscriptingRef
diff --git a/doc/src/sgml/generate-keywords-table.pl b/doc/src/sgml/generate-keywords-table.pl
index 824b324ef7..6ae6f80c3f 100644
--- a/doc/src/sgml/generate-keywords-table.pl
+++ b/doc/src/sgml/generate-keywords-table.pl
@@ -39,7 +39,7 @@ 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;
 	}
diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c
index 0a53e9b93e..cb7ffda4bd 100644
--- a/src/backend/commands/operatorcmds.c
+++ b/src/backend/commands/operatorcmds.c
@@ -168,10 +168,26 @@ DefineOperator(List *names, List *parameters)
 	if (typeName2)
 		typeId2 = typenameTypeId(NULL, typeName2);
 
+	/*
+	 * If neither argument is specified, do not mention postfix operator
+	 * discontinuation, as the user is unlikely to have meant to create a
+	 * postfix operator.  It is more likely they simply neglected to mention
+	 * the args.
+	 */
 	if (!OidIsValid(typeId1) && !OidIsValid(typeId2))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
-				 errmsg("at least one of leftarg or rightarg must be specified")));
+				 errmsg("at least rightarg must be specified")));
+
+	/*
+	 * But if only the right arg is missing, they probably do intend to create
+	 * a postfix operator, so give them a hint about why that no longer works.
+	 */
+	if (!OidIsValid(typeId2))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+				 errmsg("rightarg must be specified"),
+				 errhint("postfix operator support has been discontinued")));
 
 	if (typeName1)
 	{
diff --git a/src/backend/parser/check_keywords.pl b/src/backend/parser/check_keywords.pl
index 702c97bba2..550f103c0b 100644
--- a/src/backend/parser/check_keywords.pl
+++ b/src/backend/parser/check_keywords.pl
@@ -26,6 +26,7 @@ $\ = "\n";    # set output record separator
 
 my %keyword_categories;
 $keyword_categories{'unreserved_keyword'}     = 'UNRESERVED_KEYWORD';
+$keyword_categories{'non_label_keyword'}      = 'NON_LABEL_KEYWORD';
 $keyword_categories{'col_name_keyword'}       = 'COL_NAME_KEYWORD';
 $keyword_categories{'type_func_name_keyword'} = 'TYPE_FUNC_NAME_KEYWORD';
 $keyword_categories{'reserved_keyword'}       = 'RESERVED_KEYWORD';
@@ -36,6 +37,7 @@ my $kcat;
 my $comment;
 my @arr;
 my %keywords;
+my ($implicit, %implicit);
 
 line: while (my $S = <$gram>)
 {
@@ -51,7 +53,7 @@ line: while (my $S = <$gram>)
 	$s = '[/][*]', $S =~ s#$s# /* #g;
 	$s = '[*][/]', $S =~ s#$s# */ #g;
 
-	if (!($kcat))
+	if (!($kcat) && !($implicit))
 	{
 
 		# Is this the beginning of a keyword list?
@@ -63,6 +65,10 @@ line: while (my $S = <$gram>)
 				next line;
 			}
 		}
+		if ($S =~ m/^implicit_column_label:/)
+		{
+			$implicit = 1;
+		}
 		next line;
 	}
 
@@ -98,6 +104,7 @@ line: while (my $S = <$gram>)
 
 			# end of keyword list
 			$kcat = '';
+			undef $implicit;
 			next;
 		}
 
@@ -107,7 +114,14 @@ line: while (my $S = <$gram>)
 		}
 
 		# Put this keyword into the right list
-		push @{ $keywords{$kcat} }, $arr[$fieldIndexer];
+		if ($implicit)
+		{
+			$implicit{$arr[$fieldIndexer]} = 1;
+		}
+		else
+		{
+			push @{ $keywords{$kcat} }, $arr[$fieldIndexer];
+		}
 	}
 }
 close $gram;
@@ -156,15 +170,17 @@ open(my $kwlist, '<', $kwlist_filename)
 my $prevkwstring = '';
 my $bare_kwname;
 my %kwhash;
+my %status;
 kwlist_line: while (<$kwlist>)
 {
 	my ($line) = $_;
 
-	if ($line =~ /^PG_KEYWORD\(\"(.*)\", (.*), (.*)\)/)
+	if ($line =~ /^PG_KEYWORD\(\"(.*)\", (.*), (.*), (.*)\)/)
 	{
 		my ($kwstring) = $1;
 		my ($kwname)   = $2;
 		my ($kwcat_id) = $3;
+		$status{$kwname} = $4;
 
 		# Check that the list is in alphabetical order (critical!)
 		if ($kwstring le $prevkwstring)
@@ -234,4 +250,28 @@ while (my ($kwcat, $kwcat_id) = each(%keyword_categories))
 	}
 }
 
+# Check that all keywords in gram.y's implicit_column_label rule are listed as
+# such in kwlist.h
+for my $kw (sort keys %implicit)
+{
+	if (! defined $status{$kw})
+	{
+		error "'$kw'  in kwlist.h";
+	}
+	elsif ($status{$kw} ne 'IMPLICIT_COLUMN_LABEL')
+	{
+		error "'$kw' from gram.y's implicit_column_label rule " .
+			  "listed as $status{$kw} in kwlist.h";
+	}
+}
+
+# Check that all keywords labeled as implicit are indeed part of gram.y's
+# implicit_column_label rule
+for my $kw (sort grep { $status{$_} eq 'IMPLICIT_COLUMN_LABEL' } keys %status)
+{
+	error "'$kw' listed as implicit in kwlist.h is not part of " .
+		  "gram.y's implicit_column_label rule"
+		unless($implicit{$kw});
+}
+
 exit $errors;
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 1ea1fba43a..e947a6367d 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -540,14 +540,15 @@ 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> unreserved_keyword non_label_keyword type_func_name_keyword
+%type <keyword> col_name_keyword implicit_column_label reserved_keyword
 
 %type <node>	TableConstraint TableLikeClause
 %type <ival>	TableLikeOptionList TableLikeOption
@@ -741,7 +742,6 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 %nonassoc	'<' '>' '=' LESS_EQUALS GREATER_EQUALS NOT_EQUALS
 %nonassoc	BETWEEN IN_P LIKE ILIKE SIMILAR NOT_LA
 %nonassoc	ESCAPE			/* ESCAPE must be just above LIKE/ILIKE/SIMILAR */
-%left		POSTFIXOP		/* dummy for postfix Op rules */
 /*
  * To support target_el without AS, we must give IDENT an explicit priority
  * between POSTFIXOP and Op.  We can safely assign the same priority to
@@ -12989,8 +12989,6 @@ a_expr:		c_expr									{ $$ = $1; }
 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3, @2); }
 			| qual_Op a_expr					%prec Op
 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $1, NULL, $2, @1); }
-			| a_expr qual_Op					%prec POSTFIXOP
-				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, NULL, @2); }
 
 			| a_expr AND a_expr
 				{ $$ = makeAndExpr($1, $3, @2); }
@@ -13404,8 +13402,6 @@ b_expr:		c_expr
 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3, @2); }
 			| qual_Op b_expr					%prec Op
 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $1, NULL, $2, @1); }
-			| b_expr qual_Op					%prec POSTFIXOP
-				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, NULL, @2); }
 			| b_expr IS DISTINCT FROM b_expr		%prec IS
 				{
 					$$ = (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $5, @2);
@@ -14667,7 +14663,7 @@ target_el:	a_expr AS ColLabel
 			 * as an infix expression, which we accomplish by assigning
 			 * IDENT a precedence higher than POSTFIXOP.
 			 */
-			| a_expr IDENT
+			| a_expr BareColLabel
 				{
 					$$ = makeNode(ResTarget);
 					$$->name = $2;
@@ -14977,6 +14973,7 @@ role_list:	RoleSpec
  */
 ColId:		IDENT									{ $$ = $1; }
 			| unreserved_keyword					{ $$ = pstrdup($1); }
+			| non_label_keyword						{ $$ = pstrdup($1); }
 			| col_name_keyword						{ $$ = pstrdup($1); }
 		;
 
@@ -14984,6 +14981,7 @@ ColId:		IDENT									{ $$ = $1; }
  */
 type_function_name:	IDENT							{ $$ = $1; }
 			| unreserved_keyword					{ $$ = pstrdup($1); }
+			| non_label_keyword						{ $$ = pstrdup($1); }
 			| type_func_name_keyword				{ $$ = pstrdup($1); }
 		;
 
@@ -14991,21 +14989,451 @@ type_function_name:	IDENT							{ $$ = $1; }
  */
 NonReservedWord:	IDENT							{ $$ = $1; }
 			| unreserved_keyword					{ $$ = pstrdup($1); }
+			| non_label_keyword						{ $$ = pstrdup($1); }
 			| col_name_keyword						{ $$ = pstrdup($1); }
 			| type_func_name_keyword				{ $$ = pstrdup($1); }
 		;
 
+/* Bare column label --- names that can be column labels without writing "AS".
+ */
+BareColLabel:	IDENT								{ $$ = $1; }
+			| implicit_column_label					{ $$ = pstrdup($1); }
+		;
+
 /* Column label --- allowed labels in "AS" clauses.
  * This presently includes *all* Postgres keywords.
  */
 ColLabel:	IDENT									{ $$ = $1; }
 			| unreserved_keyword					{ $$ = pstrdup($1); }
+			| non_label_keyword						{ $$ = pstrdup($1); }
 			| col_name_keyword						{ $$ = pstrdup($1); }
 			| type_func_name_keyword				{ $$ = pstrdup($1); }
 			| reserved_keyword						{ $$ = pstrdup($1); }
 		;
 
 
+/*
+ * All keywords can be used explicitly as a column label in expressions
+ * like 'SELECT 1234 AS keyword', but only some keywords can be used
+ * implicitly as column labels in expressions like 'SELECT 1234 keyword'.
+ * Those that can be used implicitly should be listed here.
+ *
+ * Keep this in alphabetical order.
+ */
+implicit_column_label:
+			  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
+		;
+
 /*
  * Keyword category lists.  Generally, every keyword present in
  * the Postgres grammar should appear in exactly one of these lists.
@@ -15075,7 +15503,6 @@ unreserved_keyword:
 			| CYCLE
 			| DATA_P
 			| DATABASE
-			| DAY_P
 			| DEALLOCATE
 			| DECLARE
 			| DEFAULTS
@@ -15109,7 +15536,6 @@ unreserved_keyword:
 			| EXTENSION
 			| EXTERNAL
 			| FAMILY
-			| FILTER
 			| FIRST_P
 			| FOLLOWING
 			| FORCE
@@ -15123,7 +15549,6 @@ unreserved_keyword:
 			| HANDLER
 			| HEADER_P
 			| HOLD
-			| HOUR_P
 			| IDENTITY_P
 			| IF_P
 			| IMMEDIATE
@@ -15163,10 +15588,8 @@ unreserved_keyword:
 			| MATERIALIZED
 			| MAXVALUE
 			| METHOD
-			| MINUTE_P
 			| MINVALUE
 			| MODE
-			| MONTH_P
 			| MOVE
 			| NAME_P
 			| NAMES
@@ -15192,7 +15615,6 @@ unreserved_keyword:
 			| OPTIONS
 			| ORDINALITY
 			| OTHERS
-			| OVER
 			| OVERRIDING
 			| OWNED
 			| OWNER
@@ -15248,7 +15670,6 @@ unreserved_keyword:
 			| SCHEMAS
 			| SCROLL
 			| SEARCH
-			| SECOND_P
 			| SECURITY
 			| SEQUENCE
 			| SEQUENCES
@@ -15306,23 +15727,36 @@ unreserved_keyword:
 			| VALIDATE
 			| VALIDATOR
 			| VALUE_P
-			| VARYING
 			| VERSION_P
 			| VIEW
 			| VIEWS
 			| VOLATILE
 			| WHITESPACE_P
-			| WITHIN
-			| WITHOUT
 			| WORK
 			| WRAPPER
 			| WRITE
 			| XML_P
-			| YEAR_P
 			| YES_P
 			| ZONE
 		;
 
+/* "Non label" keywords --- cannot be a bare column label in a SELECT list
+ * (you have to write AS in front).  Otherwise usable for anything.
+ */
+non_label_keyword:
+			DAY_P
+			| FILTER
+			| HOUR_P
+			| MINUTE_P
+			| MONTH_P
+			| OVER
+			| SECOND_P
+			| VARYING
+			| WITHIN
+			| WITHOUT
+			| YEAR_P
+		;
+
 /* Column identifier --- keywords that can be column, table, etc names.
  *
  * Many of these keywords will in fact be recognized as type or function
diff --git a/src/backend/parser/scan.l b/src/backend/parser/scan.l
index b1ea0cb538..b26492159b 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, status) 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 37c23c9155..8148071127 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -447,6 +447,10 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 				values[1] = "U";
 				values[2] = _("unreserved");
 				break;
+			case NON_LABEL_KEYWORD:
+				values[1] = "N";
+				values[2] = _("unreserved (cannot be used as an implicit alias)");
+				break;
 			case COL_NAME_KEYWORD:
 				values[1] = "C";
 				values[2] = _("unreserved (cannot be function or type name)");
diff --git a/src/common/keywords.c b/src/common/keywords.c
index 54ed977096..e64bdf00eb 100644
--- a/src/common/keywords.c
+++ b/src/common/keywords.c
@@ -24,7 +24,7 @@
 
 /* Keyword categories for SQL keywords */
 
-#define PG_KEYWORD(kwname, value, category) category,
+#define PG_KEYWORD(kwname, value, category, status) category,
 
 const uint8 ScanKeywordCategories[SCANKEYWORDS_NUM_KEYWORDS] = {
 #include "parser/kwlist.h"
diff --git a/src/include/common/keywords.h b/src/include/common/keywords.h
index 257c050903..835126c599 100644
--- a/src/include/common/keywords.h
+++ b/src/include/common/keywords.h
@@ -18,9 +18,10 @@
 
 /* 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
+#define NON_LABEL_KEYWORD		1
+#define COL_NAME_KEYWORD		2
+#define TYPE_FUNC_NAME_KEYWORD	3
+#define RESERVED_KEYWORD		4
 
 #ifndef FRONTEND
 extern PGDLLIMPORT const ScanKeywordList ScanKeywords;
diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h
index 08f22ce211..b40aa34daf 100644
--- a/src/include/parser/kwlist.h
+++ b/src/include/parser/kwlist.h
@@ -25,453 +25,453 @@
  */
 
 /* name, value, category */
-PG_KEYWORD("abort", ABORT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("absolute", ABSOLUTE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("access", ACCESS, UNRESERVED_KEYWORD)
-PG_KEYWORD("action", ACTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("add", ADD_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("admin", ADMIN, UNRESERVED_KEYWORD)
-PG_KEYWORD("after", AFTER, UNRESERVED_KEYWORD)
-PG_KEYWORD("aggregate", AGGREGATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("all", ALL, RESERVED_KEYWORD)
-PG_KEYWORD("also", ALSO, UNRESERVED_KEYWORD)
-PG_KEYWORD("alter", ALTER, UNRESERVED_KEYWORD)
-PG_KEYWORD("always", ALWAYS, UNRESERVED_KEYWORD)
-PG_KEYWORD("analyse", ANALYSE, RESERVED_KEYWORD)		/* British spelling */
-PG_KEYWORD("analyze", ANALYZE, RESERVED_KEYWORD)
-PG_KEYWORD("and", AND, RESERVED_KEYWORD)
-PG_KEYWORD("any", ANY, RESERVED_KEYWORD)
-PG_KEYWORD("array", ARRAY, RESERVED_KEYWORD)
-PG_KEYWORD("as", AS, RESERVED_KEYWORD)
-PG_KEYWORD("asc", ASC, RESERVED_KEYWORD)
-PG_KEYWORD("assertion", ASSERTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("assignment", ASSIGNMENT, UNRESERVED_KEYWORD)
-PG_KEYWORD("asymmetric", ASYMMETRIC, RESERVED_KEYWORD)
-PG_KEYWORD("at", AT, UNRESERVED_KEYWORD)
-PG_KEYWORD("attach", ATTACH, UNRESERVED_KEYWORD)
-PG_KEYWORD("attribute", ATTRIBUTE, UNRESERVED_KEYWORD)
-PG_KEYWORD("authorization", AUTHORIZATION, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("backward", BACKWARD, UNRESERVED_KEYWORD)
-PG_KEYWORD("before", BEFORE, UNRESERVED_KEYWORD)
-PG_KEYWORD("begin", BEGIN_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("between", BETWEEN, COL_NAME_KEYWORD)
-PG_KEYWORD("bigint", BIGINT, COL_NAME_KEYWORD)
-PG_KEYWORD("binary", BINARY, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("bit", BIT, COL_NAME_KEYWORD)
-PG_KEYWORD("boolean", BOOLEAN_P, COL_NAME_KEYWORD)
-PG_KEYWORD("both", BOTH, RESERVED_KEYWORD)
-PG_KEYWORD("by", BY, UNRESERVED_KEYWORD)
-PG_KEYWORD("cache", CACHE, UNRESERVED_KEYWORD)
-PG_KEYWORD("call", CALL, UNRESERVED_KEYWORD)
-PG_KEYWORD("called", CALLED, UNRESERVED_KEYWORD)
-PG_KEYWORD("cascade", CASCADE, UNRESERVED_KEYWORD)
-PG_KEYWORD("cascaded", CASCADED, UNRESERVED_KEYWORD)
-PG_KEYWORD("case", CASE, RESERVED_KEYWORD)
-PG_KEYWORD("cast", CAST, RESERVED_KEYWORD)
-PG_KEYWORD("catalog", CATALOG_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("chain", CHAIN, UNRESERVED_KEYWORD)
-PG_KEYWORD("char", CHAR_P, COL_NAME_KEYWORD)
-PG_KEYWORD("character", CHARACTER, COL_NAME_KEYWORD)
-PG_KEYWORD("characteristics", CHARACTERISTICS, UNRESERVED_KEYWORD)
-PG_KEYWORD("check", CHECK, RESERVED_KEYWORD)
-PG_KEYWORD("checkpoint", CHECKPOINT, UNRESERVED_KEYWORD)
-PG_KEYWORD("class", CLASS, UNRESERVED_KEYWORD)
-PG_KEYWORD("close", CLOSE, UNRESERVED_KEYWORD)
-PG_KEYWORD("cluster", CLUSTER, UNRESERVED_KEYWORD)
-PG_KEYWORD("coalesce", COALESCE, COL_NAME_KEYWORD)
-PG_KEYWORD("collate", COLLATE, RESERVED_KEYWORD)
-PG_KEYWORD("collation", COLLATION, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("column", COLUMN, RESERVED_KEYWORD)
-PG_KEYWORD("columns", COLUMNS, UNRESERVED_KEYWORD)
-PG_KEYWORD("comment", COMMENT, UNRESERVED_KEYWORD)
-PG_KEYWORD("comments", COMMENTS, UNRESERVED_KEYWORD)
-PG_KEYWORD("commit", COMMIT, UNRESERVED_KEYWORD)
-PG_KEYWORD("committed", COMMITTED, UNRESERVED_KEYWORD)
-PG_KEYWORD("concurrently", CONCURRENTLY, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("configuration", CONFIGURATION, UNRESERVED_KEYWORD)
-PG_KEYWORD("conflict", CONFLICT, UNRESERVED_KEYWORD)
-PG_KEYWORD("connection", CONNECTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("constraint", CONSTRAINT, RESERVED_KEYWORD)
-PG_KEYWORD("constraints", CONSTRAINTS, UNRESERVED_KEYWORD)
-PG_KEYWORD("content", CONTENT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("continue", CONTINUE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("conversion", CONVERSION_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("copy", COPY, UNRESERVED_KEYWORD)
-PG_KEYWORD("cost", COST, UNRESERVED_KEYWORD)
-PG_KEYWORD("create", CREATE, RESERVED_KEYWORD)
-PG_KEYWORD("cross", CROSS, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("csv", CSV, UNRESERVED_KEYWORD)
-PG_KEYWORD("cube", CUBE, UNRESERVED_KEYWORD)
-PG_KEYWORD("current", CURRENT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("current_catalog", CURRENT_CATALOG, RESERVED_KEYWORD)
-PG_KEYWORD("current_date", CURRENT_DATE, RESERVED_KEYWORD)
-PG_KEYWORD("current_role", CURRENT_ROLE, RESERVED_KEYWORD)
-PG_KEYWORD("current_schema", CURRENT_SCHEMA, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("current_time", CURRENT_TIME, RESERVED_KEYWORD)
-PG_KEYWORD("current_timestamp", CURRENT_TIMESTAMP, RESERVED_KEYWORD)
-PG_KEYWORD("current_user", CURRENT_USER, RESERVED_KEYWORD)
-PG_KEYWORD("cursor", CURSOR, UNRESERVED_KEYWORD)
-PG_KEYWORD("cycle", CYCLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("data", DATA_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("database", DATABASE, UNRESERVED_KEYWORD)
-PG_KEYWORD("day", DAY_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("deallocate", DEALLOCATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("dec", DEC, COL_NAME_KEYWORD)
-PG_KEYWORD("decimal", DECIMAL_P, COL_NAME_KEYWORD)
-PG_KEYWORD("declare", DECLARE, UNRESERVED_KEYWORD)
-PG_KEYWORD("default", DEFAULT, RESERVED_KEYWORD)
-PG_KEYWORD("defaults", DEFAULTS, UNRESERVED_KEYWORD)
-PG_KEYWORD("deferrable", DEFERRABLE, RESERVED_KEYWORD)
-PG_KEYWORD("deferred", DEFERRED, UNRESERVED_KEYWORD)
-PG_KEYWORD("definer", DEFINER, UNRESERVED_KEYWORD)
-PG_KEYWORD("delete", DELETE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("delimiter", DELIMITER, UNRESERVED_KEYWORD)
-PG_KEYWORD("delimiters", DELIMITERS, UNRESERVED_KEYWORD)
-PG_KEYWORD("depends", DEPENDS, UNRESERVED_KEYWORD)
-PG_KEYWORD("desc", DESC, RESERVED_KEYWORD)
-PG_KEYWORD("detach", DETACH, UNRESERVED_KEYWORD)
-PG_KEYWORD("dictionary", DICTIONARY, UNRESERVED_KEYWORD)
-PG_KEYWORD("disable", DISABLE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("discard", DISCARD, UNRESERVED_KEYWORD)
-PG_KEYWORD("distinct", DISTINCT, RESERVED_KEYWORD)
-PG_KEYWORD("do", DO, RESERVED_KEYWORD)
-PG_KEYWORD("document", DOCUMENT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("domain", DOMAIN_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("double", DOUBLE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("drop", DROP, UNRESERVED_KEYWORD)
-PG_KEYWORD("each", EACH, UNRESERVED_KEYWORD)
-PG_KEYWORD("else", ELSE, RESERVED_KEYWORD)
-PG_KEYWORD("enable", ENABLE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("encoding", ENCODING, UNRESERVED_KEYWORD)
-PG_KEYWORD("encrypted", ENCRYPTED, UNRESERVED_KEYWORD)
-PG_KEYWORD("end", END_P, RESERVED_KEYWORD)
-PG_KEYWORD("enum", ENUM_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("escape", ESCAPE, UNRESERVED_KEYWORD)
-PG_KEYWORD("event", EVENT, UNRESERVED_KEYWORD)
-PG_KEYWORD("except", EXCEPT, RESERVED_KEYWORD)
-PG_KEYWORD("exclude", EXCLUDE, UNRESERVED_KEYWORD)
-PG_KEYWORD("excluding", EXCLUDING, UNRESERVED_KEYWORD)
-PG_KEYWORD("exclusive", EXCLUSIVE, UNRESERVED_KEYWORD)
-PG_KEYWORD("execute", EXECUTE, UNRESERVED_KEYWORD)
-PG_KEYWORD("exists", EXISTS, COL_NAME_KEYWORD)
-PG_KEYWORD("explain", EXPLAIN, UNRESERVED_KEYWORD)
-PG_KEYWORD("expression", EXPRESSION, UNRESERVED_KEYWORD)
-PG_KEYWORD("extension", EXTENSION, UNRESERVED_KEYWORD)
-PG_KEYWORD("external", EXTERNAL, UNRESERVED_KEYWORD)
-PG_KEYWORD("extract", EXTRACT, COL_NAME_KEYWORD)
-PG_KEYWORD("false", FALSE_P, RESERVED_KEYWORD)
-PG_KEYWORD("family", FAMILY, UNRESERVED_KEYWORD)
-PG_KEYWORD("fetch", FETCH, RESERVED_KEYWORD)
-PG_KEYWORD("filter", FILTER, UNRESERVED_KEYWORD)
-PG_KEYWORD("first", FIRST_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("float", FLOAT_P, COL_NAME_KEYWORD)
-PG_KEYWORD("following", FOLLOWING, UNRESERVED_KEYWORD)
-PG_KEYWORD("for", FOR, RESERVED_KEYWORD)
-PG_KEYWORD("force", FORCE, UNRESERVED_KEYWORD)
-PG_KEYWORD("foreign", FOREIGN, RESERVED_KEYWORD)
-PG_KEYWORD("forward", FORWARD, UNRESERVED_KEYWORD)
-PG_KEYWORD("freeze", FREEZE, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("from", FROM, RESERVED_KEYWORD)
-PG_KEYWORD("full", FULL, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("function", FUNCTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("functions", FUNCTIONS, UNRESERVED_KEYWORD)
-PG_KEYWORD("generated", GENERATED, UNRESERVED_KEYWORD)
-PG_KEYWORD("global", GLOBAL, UNRESERVED_KEYWORD)
-PG_KEYWORD("grant", GRANT, RESERVED_KEYWORD)
-PG_KEYWORD("granted", GRANTED, UNRESERVED_KEYWORD)
-PG_KEYWORD("greatest", GREATEST, COL_NAME_KEYWORD)
-PG_KEYWORD("group", GROUP_P, RESERVED_KEYWORD)
-PG_KEYWORD("grouping", GROUPING, COL_NAME_KEYWORD)
-PG_KEYWORD("groups", GROUPS, UNRESERVED_KEYWORD)
-PG_KEYWORD("handler", HANDLER, UNRESERVED_KEYWORD)
-PG_KEYWORD("having", HAVING, RESERVED_KEYWORD)
-PG_KEYWORD("header", HEADER_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("hold", HOLD, UNRESERVED_KEYWORD)
-PG_KEYWORD("hour", HOUR_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("identity", IDENTITY_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("if", IF_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("ilike", ILIKE, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("immediate", IMMEDIATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("immutable", IMMUTABLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("implicit", IMPLICIT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("import", IMPORT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("in", IN_P, RESERVED_KEYWORD)
-PG_KEYWORD("include", INCLUDE, UNRESERVED_KEYWORD)
-PG_KEYWORD("including", INCLUDING, UNRESERVED_KEYWORD)
-PG_KEYWORD("increment", INCREMENT, UNRESERVED_KEYWORD)
-PG_KEYWORD("index", INDEX, UNRESERVED_KEYWORD)
-PG_KEYWORD("indexes", INDEXES, UNRESERVED_KEYWORD)
-PG_KEYWORD("inherit", INHERIT, UNRESERVED_KEYWORD)
-PG_KEYWORD("inherits", INHERITS, UNRESERVED_KEYWORD)
-PG_KEYWORD("initially", INITIALLY, RESERVED_KEYWORD)
-PG_KEYWORD("inline", INLINE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("inner", INNER_P, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("inout", INOUT, COL_NAME_KEYWORD)
-PG_KEYWORD("input", INPUT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("insensitive", INSENSITIVE, UNRESERVED_KEYWORD)
-PG_KEYWORD("insert", INSERT, UNRESERVED_KEYWORD)
-PG_KEYWORD("instead", INSTEAD, UNRESERVED_KEYWORD)
-PG_KEYWORD("int", INT_P, COL_NAME_KEYWORD)
-PG_KEYWORD("integer", INTEGER, COL_NAME_KEYWORD)
-PG_KEYWORD("intersect", INTERSECT, RESERVED_KEYWORD)
-PG_KEYWORD("interval", INTERVAL, COL_NAME_KEYWORD)
-PG_KEYWORD("into", INTO, RESERVED_KEYWORD)
-PG_KEYWORD("invoker", INVOKER, UNRESERVED_KEYWORD)
-PG_KEYWORD("is", IS, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("isnull", ISNULL, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("isolation", ISOLATION, UNRESERVED_KEYWORD)
-PG_KEYWORD("join", JOIN, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("key", KEY, UNRESERVED_KEYWORD)
-PG_KEYWORD("label", LABEL, UNRESERVED_KEYWORD)
-PG_KEYWORD("language", LANGUAGE, UNRESERVED_KEYWORD)
-PG_KEYWORD("large", LARGE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("last", LAST_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("lateral", LATERAL_P, RESERVED_KEYWORD)
-PG_KEYWORD("leading", LEADING, RESERVED_KEYWORD)
-PG_KEYWORD("leakproof", LEAKPROOF, UNRESERVED_KEYWORD)
-PG_KEYWORD("least", LEAST, COL_NAME_KEYWORD)
-PG_KEYWORD("left", LEFT, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("level", LEVEL, UNRESERVED_KEYWORD)
-PG_KEYWORD("like", LIKE, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("limit", LIMIT, RESERVED_KEYWORD)
-PG_KEYWORD("listen", LISTEN, UNRESERVED_KEYWORD)
-PG_KEYWORD("load", LOAD, UNRESERVED_KEYWORD)
-PG_KEYWORD("local", LOCAL, UNRESERVED_KEYWORD)
-PG_KEYWORD("localtime", LOCALTIME, RESERVED_KEYWORD)
-PG_KEYWORD("localtimestamp", LOCALTIMESTAMP, RESERVED_KEYWORD)
-PG_KEYWORD("location", LOCATION, UNRESERVED_KEYWORD)
-PG_KEYWORD("lock", LOCK_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("locked", LOCKED, UNRESERVED_KEYWORD)
-PG_KEYWORD("logged", LOGGED, UNRESERVED_KEYWORD)
-PG_KEYWORD("mapping", MAPPING, UNRESERVED_KEYWORD)
-PG_KEYWORD("match", MATCH, UNRESERVED_KEYWORD)
-PG_KEYWORD("materialized", MATERIALIZED, UNRESERVED_KEYWORD)
-PG_KEYWORD("maxvalue", MAXVALUE, UNRESERVED_KEYWORD)
-PG_KEYWORD("method", METHOD, UNRESERVED_KEYWORD)
-PG_KEYWORD("minute", MINUTE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("minvalue", MINVALUE, UNRESERVED_KEYWORD)
-PG_KEYWORD("mode", MODE, UNRESERVED_KEYWORD)
-PG_KEYWORD("month", MONTH_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("move", MOVE, UNRESERVED_KEYWORD)
-PG_KEYWORD("name", NAME_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("names", NAMES, UNRESERVED_KEYWORD)
-PG_KEYWORD("national", NATIONAL, COL_NAME_KEYWORD)
-PG_KEYWORD("natural", NATURAL, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("nchar", NCHAR, COL_NAME_KEYWORD)
-PG_KEYWORD("new", NEW, UNRESERVED_KEYWORD)
-PG_KEYWORD("next", NEXT, UNRESERVED_KEYWORD)
-PG_KEYWORD("nfc", NFC, UNRESERVED_KEYWORD)
-PG_KEYWORD("nfd", NFD, UNRESERVED_KEYWORD)
-PG_KEYWORD("nfkc", NFKC, UNRESERVED_KEYWORD)
-PG_KEYWORD("nfkd", NFKD, UNRESERVED_KEYWORD)
-PG_KEYWORD("no", NO, UNRESERVED_KEYWORD)
-PG_KEYWORD("none", NONE, COL_NAME_KEYWORD)
-PG_KEYWORD("normalize", NORMALIZE, COL_NAME_KEYWORD)
-PG_KEYWORD("normalized", NORMALIZED, UNRESERVED_KEYWORD)
-PG_KEYWORD("not", NOT, RESERVED_KEYWORD)
-PG_KEYWORD("nothing", NOTHING, UNRESERVED_KEYWORD)
-PG_KEYWORD("notify", NOTIFY, UNRESERVED_KEYWORD)
-PG_KEYWORD("notnull", NOTNULL, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("nowait", NOWAIT, UNRESERVED_KEYWORD)
-PG_KEYWORD("null", NULL_P, RESERVED_KEYWORD)
-PG_KEYWORD("nullif", NULLIF, COL_NAME_KEYWORD)
-PG_KEYWORD("nulls", NULLS_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("numeric", NUMERIC, COL_NAME_KEYWORD)
-PG_KEYWORD("object", OBJECT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("of", OF, UNRESERVED_KEYWORD)
-PG_KEYWORD("off", OFF, UNRESERVED_KEYWORD)
-PG_KEYWORD("offset", OFFSET, RESERVED_KEYWORD)
-PG_KEYWORD("oids", OIDS, UNRESERVED_KEYWORD)
-PG_KEYWORD("old", OLD, UNRESERVED_KEYWORD)
-PG_KEYWORD("on", ON, RESERVED_KEYWORD)
-PG_KEYWORD("only", ONLY, RESERVED_KEYWORD)
-PG_KEYWORD("operator", OPERATOR, UNRESERVED_KEYWORD)
-PG_KEYWORD("option", OPTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("options", OPTIONS, UNRESERVED_KEYWORD)
-PG_KEYWORD("or", OR, RESERVED_KEYWORD)
-PG_KEYWORD("order", ORDER, RESERVED_KEYWORD)
-PG_KEYWORD("ordinality", ORDINALITY, UNRESERVED_KEYWORD)
-PG_KEYWORD("others", OTHERS, UNRESERVED_KEYWORD)
-PG_KEYWORD("out", OUT_P, COL_NAME_KEYWORD)
-PG_KEYWORD("outer", OUTER_P, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("over", OVER, UNRESERVED_KEYWORD)
-PG_KEYWORD("overlaps", OVERLAPS, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("overlay", OVERLAY, COL_NAME_KEYWORD)
-PG_KEYWORD("overriding", OVERRIDING, UNRESERVED_KEYWORD)
-PG_KEYWORD("owned", OWNED, UNRESERVED_KEYWORD)
-PG_KEYWORD("owner", OWNER, UNRESERVED_KEYWORD)
-PG_KEYWORD("parallel", PARALLEL, UNRESERVED_KEYWORD)
-PG_KEYWORD("parser", PARSER, UNRESERVED_KEYWORD)
-PG_KEYWORD("partial", PARTIAL, UNRESERVED_KEYWORD)
-PG_KEYWORD("partition", PARTITION, UNRESERVED_KEYWORD)
-PG_KEYWORD("passing", PASSING, UNRESERVED_KEYWORD)
-PG_KEYWORD("password", PASSWORD, UNRESERVED_KEYWORD)
-PG_KEYWORD("placing", PLACING, RESERVED_KEYWORD)
-PG_KEYWORD("plans", PLANS, UNRESERVED_KEYWORD)
-PG_KEYWORD("policy", POLICY, UNRESERVED_KEYWORD)
-PG_KEYWORD("position", POSITION, COL_NAME_KEYWORD)
-PG_KEYWORD("preceding", PRECEDING, UNRESERVED_KEYWORD)
-PG_KEYWORD("precision", PRECISION, COL_NAME_KEYWORD)
-PG_KEYWORD("prepare", PREPARE, UNRESERVED_KEYWORD)
-PG_KEYWORD("prepared", PREPARED, UNRESERVED_KEYWORD)
-PG_KEYWORD("preserve", PRESERVE, UNRESERVED_KEYWORD)
-PG_KEYWORD("primary", PRIMARY, RESERVED_KEYWORD)
-PG_KEYWORD("prior", PRIOR, UNRESERVED_KEYWORD)
-PG_KEYWORD("privileges", PRIVILEGES, UNRESERVED_KEYWORD)
-PG_KEYWORD("procedural", PROCEDURAL, UNRESERVED_KEYWORD)
-PG_KEYWORD("procedure", PROCEDURE, UNRESERVED_KEYWORD)
-PG_KEYWORD("procedures", PROCEDURES, UNRESERVED_KEYWORD)
-PG_KEYWORD("program", PROGRAM, UNRESERVED_KEYWORD)
-PG_KEYWORD("publication", PUBLICATION, UNRESERVED_KEYWORD)
-PG_KEYWORD("quote", QUOTE, UNRESERVED_KEYWORD)
-PG_KEYWORD("range", RANGE, UNRESERVED_KEYWORD)
-PG_KEYWORD("read", READ, UNRESERVED_KEYWORD)
-PG_KEYWORD("real", REAL, COL_NAME_KEYWORD)
-PG_KEYWORD("reassign", REASSIGN, UNRESERVED_KEYWORD)
-PG_KEYWORD("recheck", RECHECK, UNRESERVED_KEYWORD)
-PG_KEYWORD("recursive", RECURSIVE, UNRESERVED_KEYWORD)
-PG_KEYWORD("ref", REF, UNRESERVED_KEYWORD)
-PG_KEYWORD("references", REFERENCES, RESERVED_KEYWORD)
-PG_KEYWORD("referencing", REFERENCING, UNRESERVED_KEYWORD)
-PG_KEYWORD("refresh", REFRESH, UNRESERVED_KEYWORD)
-PG_KEYWORD("reindex", REINDEX, UNRESERVED_KEYWORD)
-PG_KEYWORD("relative", RELATIVE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("release", RELEASE, UNRESERVED_KEYWORD)
-PG_KEYWORD("rename", RENAME, UNRESERVED_KEYWORD)
-PG_KEYWORD("repeatable", REPEATABLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("replace", REPLACE, UNRESERVED_KEYWORD)
-PG_KEYWORD("replica", REPLICA, UNRESERVED_KEYWORD)
-PG_KEYWORD("reset", RESET, UNRESERVED_KEYWORD)
-PG_KEYWORD("restart", RESTART, UNRESERVED_KEYWORD)
-PG_KEYWORD("restrict", RESTRICT, UNRESERVED_KEYWORD)
-PG_KEYWORD("returning", RETURNING, RESERVED_KEYWORD)
-PG_KEYWORD("returns", RETURNS, UNRESERVED_KEYWORD)
-PG_KEYWORD("revoke", REVOKE, UNRESERVED_KEYWORD)
-PG_KEYWORD("right", RIGHT, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("role", ROLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("rollback", ROLLBACK, UNRESERVED_KEYWORD)
-PG_KEYWORD("rollup", ROLLUP, UNRESERVED_KEYWORD)
-PG_KEYWORD("routine", ROUTINE, UNRESERVED_KEYWORD)
-PG_KEYWORD("routines", ROUTINES, UNRESERVED_KEYWORD)
-PG_KEYWORD("row", ROW, COL_NAME_KEYWORD)
-PG_KEYWORD("rows", ROWS, UNRESERVED_KEYWORD)
-PG_KEYWORD("rule", RULE, UNRESERVED_KEYWORD)
-PG_KEYWORD("savepoint", SAVEPOINT, UNRESERVED_KEYWORD)
-PG_KEYWORD("schema", SCHEMA, UNRESERVED_KEYWORD)
-PG_KEYWORD("schemas", SCHEMAS, UNRESERVED_KEYWORD)
-PG_KEYWORD("scroll", SCROLL, UNRESERVED_KEYWORD)
-PG_KEYWORD("search", SEARCH, UNRESERVED_KEYWORD)
-PG_KEYWORD("second", SECOND_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("security", SECURITY, UNRESERVED_KEYWORD)
-PG_KEYWORD("select", SELECT, RESERVED_KEYWORD)
-PG_KEYWORD("sequence", SEQUENCE, UNRESERVED_KEYWORD)
-PG_KEYWORD("sequences", SEQUENCES, UNRESERVED_KEYWORD)
-PG_KEYWORD("serializable", SERIALIZABLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("server", SERVER, UNRESERVED_KEYWORD)
-PG_KEYWORD("session", SESSION, UNRESERVED_KEYWORD)
-PG_KEYWORD("session_user", SESSION_USER, RESERVED_KEYWORD)
-PG_KEYWORD("set", SET, UNRESERVED_KEYWORD)
-PG_KEYWORD("setof", SETOF, COL_NAME_KEYWORD)
-PG_KEYWORD("sets", SETS, UNRESERVED_KEYWORD)
-PG_KEYWORD("share", SHARE, UNRESERVED_KEYWORD)
-PG_KEYWORD("show", SHOW, UNRESERVED_KEYWORD)
-PG_KEYWORD("similar", SIMILAR, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("simple", SIMPLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("skip", SKIP, UNRESERVED_KEYWORD)
-PG_KEYWORD("smallint", SMALLINT, COL_NAME_KEYWORD)
-PG_KEYWORD("snapshot", SNAPSHOT, UNRESERVED_KEYWORD)
-PG_KEYWORD("some", SOME, RESERVED_KEYWORD)
-PG_KEYWORD("sql", SQL_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("stable", STABLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("standalone", STANDALONE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("start", START, UNRESERVED_KEYWORD)
-PG_KEYWORD("statement", STATEMENT, UNRESERVED_KEYWORD)
-PG_KEYWORD("statistics", STATISTICS, UNRESERVED_KEYWORD)
-PG_KEYWORD("stdin", STDIN, UNRESERVED_KEYWORD)
-PG_KEYWORD("stdout", STDOUT, UNRESERVED_KEYWORD)
-PG_KEYWORD("storage", STORAGE, UNRESERVED_KEYWORD)
-PG_KEYWORD("stored", STORED, UNRESERVED_KEYWORD)
-PG_KEYWORD("strict", STRICT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("strip", STRIP_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("subscription", SUBSCRIPTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("substring", SUBSTRING, COL_NAME_KEYWORD)
-PG_KEYWORD("support", SUPPORT, UNRESERVED_KEYWORD)
-PG_KEYWORD("symmetric", SYMMETRIC, RESERVED_KEYWORD)
-PG_KEYWORD("sysid", SYSID, UNRESERVED_KEYWORD)
-PG_KEYWORD("system", SYSTEM_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("table", TABLE, RESERVED_KEYWORD)
-PG_KEYWORD("tables", TABLES, UNRESERVED_KEYWORD)
-PG_KEYWORD("tablesample", TABLESAMPLE, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("tablespace", TABLESPACE, UNRESERVED_KEYWORD)
-PG_KEYWORD("temp", TEMP, UNRESERVED_KEYWORD)
-PG_KEYWORD("template", TEMPLATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("temporary", TEMPORARY, UNRESERVED_KEYWORD)
-PG_KEYWORD("text", TEXT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("then", THEN, RESERVED_KEYWORD)
-PG_KEYWORD("ties", TIES, UNRESERVED_KEYWORD)
-PG_KEYWORD("time", TIME, COL_NAME_KEYWORD)
-PG_KEYWORD("timestamp", TIMESTAMP, COL_NAME_KEYWORD)
-PG_KEYWORD("to", TO, RESERVED_KEYWORD)
-PG_KEYWORD("trailing", TRAILING, RESERVED_KEYWORD)
-PG_KEYWORD("transaction", TRANSACTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("transform", TRANSFORM, UNRESERVED_KEYWORD)
-PG_KEYWORD("treat", TREAT, COL_NAME_KEYWORD)
-PG_KEYWORD("trigger", TRIGGER, UNRESERVED_KEYWORD)
-PG_KEYWORD("trim", TRIM, COL_NAME_KEYWORD)
-PG_KEYWORD("true", TRUE_P, RESERVED_KEYWORD)
-PG_KEYWORD("truncate", TRUNCATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("trusted", TRUSTED, UNRESERVED_KEYWORD)
-PG_KEYWORD("type", TYPE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("types", TYPES_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("uescape", UESCAPE, UNRESERVED_KEYWORD)
-PG_KEYWORD("unbounded", UNBOUNDED, UNRESERVED_KEYWORD)
-PG_KEYWORD("uncommitted", UNCOMMITTED, UNRESERVED_KEYWORD)
-PG_KEYWORD("unencrypted", UNENCRYPTED, UNRESERVED_KEYWORD)
-PG_KEYWORD("union", UNION, RESERVED_KEYWORD)
-PG_KEYWORD("unique", UNIQUE, RESERVED_KEYWORD)
-PG_KEYWORD("unknown", UNKNOWN, UNRESERVED_KEYWORD)
-PG_KEYWORD("unlisten", UNLISTEN, UNRESERVED_KEYWORD)
-PG_KEYWORD("unlogged", UNLOGGED, UNRESERVED_KEYWORD)
-PG_KEYWORD("until", UNTIL, UNRESERVED_KEYWORD)
-PG_KEYWORD("update", UPDATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("user", USER, RESERVED_KEYWORD)
-PG_KEYWORD("using", USING, RESERVED_KEYWORD)
-PG_KEYWORD("vacuum", VACUUM, UNRESERVED_KEYWORD)
-PG_KEYWORD("valid", VALID, UNRESERVED_KEYWORD)
-PG_KEYWORD("validate", VALIDATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("validator", VALIDATOR, UNRESERVED_KEYWORD)
-PG_KEYWORD("value", VALUE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("values", VALUES, COL_NAME_KEYWORD)
-PG_KEYWORD("varchar", VARCHAR, COL_NAME_KEYWORD)
-PG_KEYWORD("variadic", VARIADIC, RESERVED_KEYWORD)
-PG_KEYWORD("varying", VARYING, UNRESERVED_KEYWORD)
-PG_KEYWORD("verbose", VERBOSE, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("version", VERSION_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("view", VIEW, UNRESERVED_KEYWORD)
-PG_KEYWORD("views", VIEWS, UNRESERVED_KEYWORD)
-PG_KEYWORD("volatile", VOLATILE, UNRESERVED_KEYWORD)
-PG_KEYWORD("when", WHEN, RESERVED_KEYWORD)
-PG_KEYWORD("where", WHERE, RESERVED_KEYWORD)
-PG_KEYWORD("whitespace", WHITESPACE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("window", WINDOW, RESERVED_KEYWORD)
-PG_KEYWORD("with", WITH, RESERVED_KEYWORD)
-PG_KEYWORD("within", WITHIN, UNRESERVED_KEYWORD)
-PG_KEYWORD("without", WITHOUT, UNRESERVED_KEYWORD)
-PG_KEYWORD("work", WORK, UNRESERVED_KEYWORD)
-PG_KEYWORD("wrapper", WRAPPER, UNRESERVED_KEYWORD)
-PG_KEYWORD("write", WRITE, UNRESERVED_KEYWORD)
-PG_KEYWORD("xml", XML_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("xmlattributes", XMLATTRIBUTES, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlconcat", XMLCONCAT, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlelement", XMLELEMENT, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlexists", XMLEXISTS, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlforest", XMLFOREST, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlnamespaces", XMLNAMESPACES, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlparse", XMLPARSE, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlpi", XMLPI, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlroot", XMLROOT, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlserialize", XMLSERIALIZE, COL_NAME_KEYWORD)
-PG_KEYWORD("xmltable", XMLTABLE, COL_NAME_KEYWORD)
-PG_KEYWORD("year", YEAR_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("yes", YES_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("zone", ZONE, UNRESERVED_KEYWORD)
+PG_KEYWORD("abort", ABORT_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("absolute", ABSOLUTE_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("access", ACCESS, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("action", ACTION, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("add", ADD_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("admin", ADMIN, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("after", AFTER, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("aggregate", AGGREGATE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("all", ALL, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("also", ALSO, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("alter", ALTER, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("always", ALWAYS, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("analyse", ANALYSE, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)		/* British spelling */
+PG_KEYWORD("analyze", ANALYZE, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("and", AND, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("any", ANY, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("array", ARRAY, RESERVED_KEYWORD, EXPLICIT_COLUMN_LABEL)
+PG_KEYWORD("as", AS, RESERVED_KEYWORD, EXPLICIT_COLUMN_LABEL)
+PG_KEYWORD("asc", ASC, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("assertion", ASSERTION, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("assignment", ASSIGNMENT, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("asymmetric", ASYMMETRIC, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("at", AT, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("attach", ATTACH, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("attribute", ATTRIBUTE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("authorization", AUTHORIZATION, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("backward", BACKWARD, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("before", BEFORE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("begin", BEGIN_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("between", BETWEEN, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("bigint", BIGINT, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("binary", BINARY, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("bit", BIT, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("boolean", BOOLEAN_P, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("both", BOTH, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("by", BY, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("cache", CACHE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("call", CALL, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("called", CALLED, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("cascade", CASCADE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("cascaded", CASCADED, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("case", CASE, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("cast", CAST, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("catalog", CATALOG_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("chain", CHAIN, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("char", CHAR_P, COL_NAME_KEYWORD, EXPLICIT_COLUMN_LABEL)
+PG_KEYWORD("character", CHARACTER, COL_NAME_KEYWORD, EXPLICIT_COLUMN_LABEL)
+PG_KEYWORD("characteristics", CHARACTERISTICS, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("check", CHECK, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("checkpoint", CHECKPOINT, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("class", CLASS, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("close", CLOSE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("cluster", CLUSTER, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("coalesce", COALESCE, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("collate", COLLATE, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("collation", COLLATION, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("column", COLUMN, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("columns", COLUMNS, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("comment", COMMENT, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("comments", COMMENTS, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("commit", COMMIT, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("committed", COMMITTED, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("concurrently", CONCURRENTLY, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("configuration", CONFIGURATION, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("conflict", CONFLICT, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("connection", CONNECTION, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("constraint", CONSTRAINT, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("constraints", CONSTRAINTS, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("content", CONTENT_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("continue", CONTINUE_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("conversion", CONVERSION_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("copy", COPY, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("cost", COST, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("create", CREATE, RESERVED_KEYWORD, EXPLICIT_COLUMN_LABEL)
+PG_KEYWORD("cross", CROSS, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("csv", CSV, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("cube", CUBE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("current", CURRENT_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("current_catalog", CURRENT_CATALOG, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("current_date", CURRENT_DATE, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("current_role", CURRENT_ROLE, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("current_schema", CURRENT_SCHEMA, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("current_time", CURRENT_TIME, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("current_timestamp", CURRENT_TIMESTAMP, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("current_user", CURRENT_USER, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("cursor", CURSOR, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("cycle", CYCLE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("data", DATA_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("database", DATABASE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("day", DAY_P, NON_LABEL_KEYWORD, EXPLICIT_COLUMN_LABEL)
+PG_KEYWORD("deallocate", DEALLOCATE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("dec", DEC, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("decimal", DECIMAL_P, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("declare", DECLARE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("default", DEFAULT, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("defaults", DEFAULTS, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("deferrable", DEFERRABLE, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("deferred", DEFERRED, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("definer", DEFINER, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("delete", DELETE_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("delimiter", DELIMITER, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("delimiters", DELIMITERS, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("depends", DEPENDS, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("desc", DESC, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("detach", DETACH, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("dictionary", DICTIONARY, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("disable", DISABLE_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("discard", DISCARD, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("distinct", DISTINCT, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("do", DO, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("document", DOCUMENT_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("domain", DOMAIN_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("double", DOUBLE_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("drop", DROP, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("each", EACH, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("else", ELSE, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("enable", ENABLE_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("encoding", ENCODING, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("encrypted", ENCRYPTED, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("end", END_P, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("enum", ENUM_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("escape", ESCAPE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("event", EVENT, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("except", EXCEPT, RESERVED_KEYWORD, EXPLICIT_COLUMN_LABEL)
+PG_KEYWORD("exclude", EXCLUDE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("excluding", EXCLUDING, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("exclusive", EXCLUSIVE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("execute", EXECUTE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("exists", EXISTS, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("explain", EXPLAIN, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("expression", EXPRESSION, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("extension", EXTENSION, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("external", EXTERNAL, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("extract", EXTRACT, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("false", FALSE_P, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("family", FAMILY, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("fetch", FETCH, RESERVED_KEYWORD, EXPLICIT_COLUMN_LABEL)
+PG_KEYWORD("filter", FILTER, NON_LABEL_KEYWORD, EXPLICIT_COLUMN_LABEL)
+PG_KEYWORD("first", FIRST_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("float", FLOAT_P, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("following", FOLLOWING, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("for", FOR, RESERVED_KEYWORD, EXPLICIT_COLUMN_LABEL)
+PG_KEYWORD("force", FORCE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("foreign", FOREIGN, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("forward", FORWARD, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("freeze", FREEZE, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("from", FROM, RESERVED_KEYWORD, EXPLICIT_COLUMN_LABEL)
+PG_KEYWORD("full", FULL, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("function", FUNCTION, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("functions", FUNCTIONS, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("generated", GENERATED, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("global", GLOBAL, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("grant", GRANT, RESERVED_KEYWORD, EXPLICIT_COLUMN_LABEL)
+PG_KEYWORD("granted", GRANTED, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("greatest", GREATEST, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("group", GROUP_P, RESERVED_KEYWORD, EXPLICIT_COLUMN_LABEL)
+PG_KEYWORD("grouping", GROUPING, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("groups", GROUPS, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("handler", HANDLER, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("having", HAVING, RESERVED_KEYWORD, EXPLICIT_COLUMN_LABEL)
+PG_KEYWORD("header", HEADER_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("hold", HOLD, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("hour", HOUR_P, NON_LABEL_KEYWORD, EXPLICIT_COLUMN_LABEL)
+PG_KEYWORD("identity", IDENTITY_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("if", IF_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("ilike", ILIKE, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("immediate", IMMEDIATE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("immutable", IMMUTABLE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("implicit", IMPLICIT_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("import", IMPORT_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("in", IN_P, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("include", INCLUDE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("including", INCLUDING, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("increment", INCREMENT, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("index", INDEX, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("indexes", INDEXES, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("inherit", INHERIT, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("inherits", INHERITS, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("initially", INITIALLY, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("inline", INLINE_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("inner", INNER_P, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("inout", INOUT, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("input", INPUT_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("insensitive", INSENSITIVE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("insert", INSERT, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("instead", INSTEAD, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("int", INT_P, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("integer", INTEGER, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("intersect", INTERSECT, RESERVED_KEYWORD, EXPLICIT_COLUMN_LABEL)
+PG_KEYWORD("interval", INTERVAL, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("into", INTO, RESERVED_KEYWORD, EXPLICIT_COLUMN_LABEL)
+PG_KEYWORD("invoker", INVOKER, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("is", IS, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("isnull", ISNULL, TYPE_FUNC_NAME_KEYWORD, EXPLICIT_COLUMN_LABEL)
+PG_KEYWORD("isolation", ISOLATION, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("join", JOIN, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("key", KEY, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("label", LABEL, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("language", LANGUAGE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("large", LARGE_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("last", LAST_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("lateral", LATERAL_P, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("leading", LEADING, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("leakproof", LEAKPROOF, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("least", LEAST, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("left", LEFT, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("level", LEVEL, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("like", LIKE, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("limit", LIMIT, RESERVED_KEYWORD, EXPLICIT_COLUMN_LABEL)
+PG_KEYWORD("listen", LISTEN, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("load", LOAD, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("local", LOCAL, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("localtime", LOCALTIME, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("localtimestamp", LOCALTIMESTAMP, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("location", LOCATION, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("lock", LOCK_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("locked", LOCKED, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("logged", LOGGED, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("mapping", MAPPING, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("match", MATCH, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("materialized", MATERIALIZED, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("maxvalue", MAXVALUE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("method", METHOD, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("minute", MINUTE_P, NON_LABEL_KEYWORD, EXPLICIT_COLUMN_LABEL)
+PG_KEYWORD("minvalue", MINVALUE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("mode", MODE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("month", MONTH_P, NON_LABEL_KEYWORD, EXPLICIT_COLUMN_LABEL)
+PG_KEYWORD("move", MOVE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("name", NAME_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("names", NAMES, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("national", NATIONAL, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("natural", NATURAL, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("nchar", NCHAR, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("new", NEW, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("next", NEXT, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("nfc", NFC, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("nfd", NFD, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("nfkc", NFKC, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("nfkd", NFKD, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("no", NO, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("none", NONE, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("normalize", NORMALIZE, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("normalized", NORMALIZED, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("not", NOT, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("nothing", NOTHING, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("notify", NOTIFY, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("notnull", NOTNULL, TYPE_FUNC_NAME_KEYWORD, EXPLICIT_COLUMN_LABEL)
+PG_KEYWORD("nowait", NOWAIT, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("null", NULL_P, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("nullif", NULLIF, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("nulls", NULLS_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("numeric", NUMERIC, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("object", OBJECT_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("of", OF, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("off", OFF, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("offset", OFFSET, RESERVED_KEYWORD, EXPLICIT_COLUMN_LABEL)
+PG_KEYWORD("oids", OIDS, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("old", OLD, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("on", ON, RESERVED_KEYWORD, EXPLICIT_COLUMN_LABEL)
+PG_KEYWORD("only", ONLY, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("operator", OPERATOR, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("option", OPTION, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("options", OPTIONS, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("or", OR, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("order", ORDER, RESERVED_KEYWORD, EXPLICIT_COLUMN_LABEL)
+PG_KEYWORD("ordinality", ORDINALITY, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("others", OTHERS, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("out", OUT_P, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("outer", OUTER_P, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("over", OVER, NON_LABEL_KEYWORD, EXPLICIT_COLUMN_LABEL)
+PG_KEYWORD("overlaps", OVERLAPS, TYPE_FUNC_NAME_KEYWORD, EXPLICIT_COLUMN_LABEL)
+PG_KEYWORD("overlay", OVERLAY, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("overriding", OVERRIDING, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("owned", OWNED, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("owner", OWNER, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("parallel", PARALLEL, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("parser", PARSER, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("partial", PARTIAL, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("partition", PARTITION, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("passing", PASSING, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("password", PASSWORD, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("placing", PLACING, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("plans", PLANS, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("policy", POLICY, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("position", POSITION, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("preceding", PRECEDING, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("precision", PRECISION, COL_NAME_KEYWORD, EXPLICIT_COLUMN_LABEL)
+PG_KEYWORD("prepare", PREPARE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("prepared", PREPARED, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("preserve", PRESERVE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("primary", PRIMARY, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("prior", PRIOR, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("privileges", PRIVILEGES, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("procedural", PROCEDURAL, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("procedure", PROCEDURE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("procedures", PROCEDURES, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("program", PROGRAM, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("publication", PUBLICATION, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("quote", QUOTE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("range", RANGE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("read", READ, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("real", REAL, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("reassign", REASSIGN, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("recheck", RECHECK, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("recursive", RECURSIVE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("ref", REF, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("references", REFERENCES, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("referencing", REFERENCING, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("refresh", REFRESH, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("reindex", REINDEX, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("relative", RELATIVE_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("release", RELEASE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("rename", RENAME, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("repeatable", REPEATABLE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("replace", REPLACE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("replica", REPLICA, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("reset", RESET, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("restart", RESTART, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("restrict", RESTRICT, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("returning", RETURNING, RESERVED_KEYWORD, EXPLICIT_COLUMN_LABEL)
+PG_KEYWORD("returns", RETURNS, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("revoke", REVOKE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("right", RIGHT, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("role", ROLE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("rollback", ROLLBACK, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("rollup", ROLLUP, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("routine", ROUTINE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("routines", ROUTINES, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("row", ROW, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("rows", ROWS, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("rule", RULE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("savepoint", SAVEPOINT, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("schema", SCHEMA, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("schemas", SCHEMAS, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("scroll", SCROLL, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("search", SEARCH, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("second", SECOND_P, NON_LABEL_KEYWORD, EXPLICIT_COLUMN_LABEL)
+PG_KEYWORD("security", SECURITY, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("select", SELECT, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("sequence", SEQUENCE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("sequences", SEQUENCES, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("serializable", SERIALIZABLE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("server", SERVER, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("session", SESSION, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("session_user", SESSION_USER, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("set", SET, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("setof", SETOF, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("sets", SETS, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("share", SHARE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("show", SHOW, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("similar", SIMILAR, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("simple", SIMPLE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("skip", SKIP, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("smallint", SMALLINT, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("snapshot", SNAPSHOT, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("some", SOME, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("sql", SQL_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("stable", STABLE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("standalone", STANDALONE_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("start", START, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("statement", STATEMENT, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("statistics", STATISTICS, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("stdin", STDIN, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("stdout", STDOUT, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("storage", STORAGE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("stored", STORED, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("strict", STRICT_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("strip", STRIP_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("subscription", SUBSCRIPTION, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("substring", SUBSTRING, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("support", SUPPORT, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("symmetric", SYMMETRIC, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("sysid", SYSID, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("system", SYSTEM_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("table", TABLE, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("tables", TABLES, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("tablesample", TABLESAMPLE, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("tablespace", TABLESPACE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("temp", TEMP, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("template", TEMPLATE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("temporary", TEMPORARY, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("text", TEXT_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("then", THEN, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("ties", TIES, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("time", TIME, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("timestamp", TIMESTAMP, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("to", TO, RESERVED_KEYWORD, EXPLICIT_COLUMN_LABEL)
+PG_KEYWORD("trailing", TRAILING, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("transaction", TRANSACTION, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("transform", TRANSFORM, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("treat", TREAT, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("trigger", TRIGGER, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("trim", TRIM, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("true", TRUE_P, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("truncate", TRUNCATE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("trusted", TRUSTED, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("type", TYPE_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("types", TYPES_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("uescape", UESCAPE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("unbounded", UNBOUNDED, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("uncommitted", UNCOMMITTED, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("unencrypted", UNENCRYPTED, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("union", UNION, RESERVED_KEYWORD, EXPLICIT_COLUMN_LABEL)
+PG_KEYWORD("unique", UNIQUE, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("unknown", UNKNOWN, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("unlisten", UNLISTEN, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("unlogged", UNLOGGED, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("until", UNTIL, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("update", UPDATE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("user", USER, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("using", USING, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("vacuum", VACUUM, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("valid", VALID, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("validate", VALIDATE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("validator", VALIDATOR, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("value", VALUE_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("values", VALUES, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("varchar", VARCHAR, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("variadic", VARIADIC, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("varying", VARYING, NON_LABEL_KEYWORD, EXPLICIT_COLUMN_LABEL)
+PG_KEYWORD("verbose", VERBOSE, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("version", VERSION_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("view", VIEW, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("views", VIEWS, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("volatile", VOLATILE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("when", WHEN, RESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("where", WHERE, RESERVED_KEYWORD, EXPLICIT_COLUMN_LABEL)
+PG_KEYWORD("whitespace", WHITESPACE_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("window", WINDOW, RESERVED_KEYWORD, EXPLICIT_COLUMN_LABEL)
+PG_KEYWORD("with", WITH, RESERVED_KEYWORD, EXPLICIT_COLUMN_LABEL)
+PG_KEYWORD("within", WITHIN, NON_LABEL_KEYWORD, EXPLICIT_COLUMN_LABEL)
+PG_KEYWORD("without", WITHOUT, NON_LABEL_KEYWORD, EXPLICIT_COLUMN_LABEL)
+PG_KEYWORD("work", WORK, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("wrapper", WRAPPER, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("write", WRITE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("xml", XML_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("xmlattributes", XMLATTRIBUTES, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("xmlconcat", XMLCONCAT, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("xmlelement", XMLELEMENT, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("xmlexists", XMLEXISTS, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("xmlforest", XMLFOREST, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("xmlnamespaces", XMLNAMESPACES, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("xmlparse", XMLPARSE, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("xmlpi", XMLPI, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("xmlroot", XMLROOT, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("xmlserialize", XMLSERIALIZE, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("xmltable", XMLTABLE, COL_NAME_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("year", YEAR_P, NON_LABEL_KEYWORD, EXPLICIT_COLUMN_LABEL)
+PG_KEYWORD("yes", YES_P, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
+PG_KEYWORD("zone", ZONE, UNRESERVED_KEYWORD, IMPLICIT_COLUMN_LABEL)
diff --git a/src/interfaces/ecpg/preproc/keywords.c b/src/interfaces/ecpg/preproc/keywords.c
index f82764aeb9..34a2f8ba2b 100644
--- a/src/interfaces/ecpg/preproc/keywords.c
+++ b/src/interfaces/ecpg/preproc/keywords.c
@@ -29,7 +29,7 @@
 #include "preproc_extern.h"
 #include "preproc.h"
 
-#define PG_KEYWORD(kwname, value, category) value,
+#define PG_KEYWORD(kwname, value, category, status) value,
 
 const uint16 SQLScanKeywordTokens[] = {
 #include "parser/kwlist.h"
diff --git a/src/test/regress/expected/create_operator.out b/src/test/regress/expected/create_operator.out
index 54e8b79159..ed77a6616e 100644
--- a/src/test/regress/expected/create_operator.out
+++ b/src/test/regress/expected/create_operator.out
@@ -22,10 +22,14 @@ CREATE OPERATOR #@# (
    leftarg = int8,		-- right unary
    procedure = numeric_fac
 );
+ERROR:  rightarg must be specified
+HINT:  postfix operator support has been discontinued
 CREATE OPERATOR #%# (
    leftarg = int8,		-- right unary
    procedure = numeric_fac
 );
+ERROR:  rightarg must be specified
+HINT:  postfix operator support has been discontinued
 -- Test operator created above
 SELECT point '(1,2)' <% widget '(0,0,3)' AS t,
        point '(1,2)' <% widget '(0,0,1)' AS f;
@@ -52,12 +56,12 @@ CREATE OPERATOR !=- (
    leftarg = int8,		-- right unary
    procedure = numeric_fac
 );
+ERROR:  rightarg must be specified
+HINT:  postfix operator support has been discontinued
 SELECT 2 !=-;
- ?column? 
-----------
-        2
-(1 row)
-
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 2 !=-;
+                    ^
 -- make sure lexer returns != as <> even in edge cases
 SELECT 2 !=/**/ 1, 2 !=/**/ 2;
  ?column? | ?column? 
@@ -172,11 +176,13 @@ CREATE OPERATOR #@%# (
    invalid_att = int8
 );
 WARNING:  operator attribute "invalid_att" not recognized
--- Should fail. At least leftarg or rightarg should be mandatorily specified
+ERROR:  rightarg must be specified
+HINT:  postfix operator support has been discontinued
+-- Should fail. At least rightarg should be mandatorily specified
 CREATE OPERATOR #@%# (
    procedure = numeric_fac
 );
-ERROR:  at least one of leftarg or rightarg must be specified
+ERROR:  at least rightarg must be specified
 -- Should fail. Procedure should be mandatorily specified
 CREATE OPERATOR #@%# (
    leftarg = int8
diff --git a/src/test/regress/expected/numeric.out b/src/test/regress/expected/numeric.out
index 81a0c5d40f..8b2e29779d 100644
--- a/src/test/regress/expected/numeric.out
+++ b/src/test/regress/expected/numeric.out
@@ -2318,7 +2318,7 @@ ERROR:  value overflows numeric format
 --
 -- Tests for factorial
 --
-SELECT 4!;
+SELECT !!4;
  ?column? 
 ----------
        24
@@ -2336,19 +2336,38 @@ SELECT factorial(15);
  1307674368000
 (1 row)
 
-SELECT 100000!;
+SELECT !!100000;
 ERROR:  value overflows numeric format
-SELECT 0!;
+SELECT !!0;
  ?column? 
 ----------
         1
 (1 row)
 
-SELECT -4!;
+SELECT !!(-4);
 ERROR:  factorial of a negative number is undefined
 SELECT factorial(-4);
 ERROR:  factorial of a negative number is undefined
 --
+-- Postfix operator support has been removed.
+--
+SELECT -5!;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT -5!;
+                  ^
+SELECT -0!;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT -0!;
+                  ^
+SELECT 0!;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 0!;
+                 ^
+SELECT 100!;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 100!;
+                   ^
+--
 -- Tests for pg_lsn()
 --
 SELECT pg_lsn(23783416::numeric);
diff --git a/src/test/regress/sql/create_operator.sql b/src/test/regress/sql/create_operator.sql
index 8b6fd0bb43..eb2335e0ef 100644
--- a/src/test/regress/sql/create_operator.sql
+++ b/src/test/regress/sql/create_operator.sql
@@ -133,7 +133,7 @@ CREATE OPERATOR #@%# (
    invalid_att = int8
 );
 
--- Should fail. At least leftarg or rightarg should be mandatorily specified
+-- Should fail. At least rightarg should be mandatorily specified
 CREATE OPERATOR #@%# (
    procedure = numeric_fac
 );
diff --git a/src/test/regress/sql/numeric.sql b/src/test/regress/sql/numeric.sql
index 5dc80f686f..f8ce69422e 100644
--- a/src/test/regress/sql/numeric.sql
+++ b/src/test/regress/sql/numeric.sql
@@ -1115,14 +1115,22 @@ SELECT lcm(9999 * (10::numeric)^131068 + (10::numeric^131068 - 1), 2); -- overfl
 --
 -- Tests for factorial
 --
-SELECT 4!;
+SELECT !!4;
 SELECT !!3;
 SELECT factorial(15);
-SELECT 100000!;
-SELECT 0!;
-SELECT -4!;
+SELECT !!100000;
+SELECT !!0;
+SELECT !!(-4);
 SELECT factorial(-4);
 
+--
+-- Postfix operator support has been removed.
+--
+SELECT -5!;
+SELECT -0!;
+SELECT 0!;
+SELECT 100!;
+
 --
 -- Tests for pg_lsn()
 --
-- 
2.21.1 (Apple Git-122.3)

#33John Naylor
john.naylor@2ndquadrant.com
In reply to: Mark Dilger (#32)
Re: factorial function/phase out postfix operators?

On Sat, Jul 11, 2020 at 1:14 AM Mark Dilger
<mark.dilger@enterprisedb.com> wrote:

Tom and Álvaro discussed upthread:

Would it make sense (and possible) to have a keyword category that is
not disjoint wrt. the others? Maybe that ends up being easier than
a solution that ends up with six or seven categories.

Version 2, attached, follows this design, increasing the number of keywords that can be used as column aliases without the AS keyword up to 411, with only 39 keywords still requiring an explicit preceding AS.

Hi Mark,

This isn't a full review, but I have a few questions/comments:

By making col-label-ness an orthogonal attribute, do we still need the
category of non_label_keyword? It seems not.

pg_get_keywords() should probably have a column to display ability to
act as a bare col label. Perhaps a boolean? If so, what do you think
of using true/false for the new field in kwlist.h as well?

In the bikeshedding department, it seems "implicit" was chosen because
it was distinct from "bare". I think "bare" as a descriptor should be
kept throughout for readability's sake. Maybe BareColLabel could be
"IDENT or bare_label_keyword" for example. Same for the $status var.

Likewise, it seems the actual removal of postfix operators should be a
separate patch.

--
John Naylor https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

#34Mark Dilger
mark.dilger@enterprisedb.com
In reply to: John Naylor (#33)
3 attachment(s)
Re: factorial function/phase out postfix operators?

On Jul 18, 2020, at 1:00 AM, John Naylor <john.naylor@2ndquadrant.com> wrote:

On Sat, Jul 11, 2020 at 1:14 AM Mark Dilger
<mark.dilger@enterprisedb.com> wrote:

Tom and Álvaro discussed upthread:

Would it make sense (and possible) to have a keyword category that is
not disjoint wrt. the others? Maybe that ends up being easier than
a solution that ends up with six or seven categories.

Version 2, attached, follows this design, increasing the number of keywords that can be used as column aliases without the AS keyword up to 411, with only 39 keywords still requiring an explicit preceding AS.

Hi Mark,

This isn't a full review, but I have a few questions/comments:

Thanks for looking!

By making col-label-ness an orthogonal attribute, do we still need the
category of non_label_keyword? It seems not.

You are right. The non_label_keyword category has been removed from v3.

pg_get_keywords() should probably have a column to display ability to
act as a bare col label. Perhaps a boolean? If so, what do you think
of using true/false for the new field in kwlist.h as well?

I have broken this into its own patch. I like using a BARE_LABEL / EXPLICIT_LABEL in kwlist.h because it is self-documenting. I don't care about the *exact* strings that we choose for that, but using TRUE/FALSE in kwlist.h makes it harder for a person adding a new keyword to know what to place there. If they guess "FALSE", and also don't know about adding the new keyword to the bare_label_keyword rule in gram.y, then those two mistakes will agree with each other and the person adding the keyword won't likely know they did it wrong. It is simple enough for gen_keywordlist.pl to convert between what we use in kwlist.h and a boolean value for kwlist_d.h, so I did it that way.

In the bikeshedding department, it seems "implicit" was chosen because
it was distinct from "bare". I think "bare" as a descriptor should be
kept throughout for readability's sake. Maybe BareColLabel could be
"IDENT or bare_label_keyword" for example. Same for the $status var.

The category "bare_label_keyword" is used in v3. As for the $status var, I don't want to name that $bare, as I didn't go with your idea about using a boolean. $status = "BARE_LABEL" vs "EXPLICIT_LABEL" makes sense to me, more than $bare = "BARE_LABEL" vs "EXPLICIT_LABEL" does. "status" is still a bit vague, so more bikeshedding is welcome.

Likewise, it seems the actual removal of postfix operators should be a
separate patch.

I broke out the removal of postfix operators into its own patch in the v3 series.

This patch does not attempt to remove pre-existing postfix operators from existing databases, so users upgrading to the new major version who have custom postfix operators will find that pg_upgrade chokes trying to recreate the postfix operator. That's not great, but perhaps there is nothing automated that we could do for them that would be any better.

Attachments:

v3-0001-Removing-postfix-operator-support.patchapplication/octet-stream; name=v3-0001-Removing-postfix-operator-support.patch; x-unix-mode=0644Download
From bc4291a8307fa299d96e99a0a98348c451a3eab6 Mon Sep 17 00:00:00 2001
From: Mark Dilger <mark.dilger@enterprisedb.com>
Date: Tue, 21 Jul 2020 14:18:48 -0700
Subject: [PATCH v3 1/3] Removing postfix operator support.

Removing postfix operator support from the grammar; disallowing
the creation of postfix operators through the CREATE OPERATOR
command; and removing the factorial postfix operator.

This accomplishes nothing useful in itself, but sets up
for grammar changes to allow keywords to be used as bare column
aliases without the use of an explicit "AS".
---
 .../postgres_fdw/expected/postgres_fdw.out    |  8 +++---
 contrib/postgres_fdw/sql/postgres_fdw.sql     |  2 +-
 src/backend/commands/operatorcmds.c           | 18 ++++++++++++-
 src/backend/parser/gram.y                     | 12 +--------
 src/include/catalog/pg_operator.dat           |  3 ---
 src/include/catalog/pg_proc.dat               |  2 +-
 src/test/regress/expected/create_operator.out | 20 +++++++++-----
 src/test/regress/expected/numeric.out         | 27 ++++++++++++++++---
 src/test/regress/sql/create_operator.sql      |  2 +-
 src/test/regress/sql/numeric.sql              | 16 ++++++++---
 10 files changed, 73 insertions(+), 37 deletions(-)

diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index 90db550b92..9728c252ba 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -653,12 +653,12 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 = -c1;          -- Op
    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = (- "C 1")))
 (3 rows)
 
-EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE 1 = c1!;           -- OpExpr(r)
-                                                QUERY PLAN                                                
-----------------------------------------------------------------------------------------------------------
+EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE 1 = !!c1;          -- OpExpr(r)
+                                                QUERY PLAN                                                 
+-----------------------------------------------------------------------------------------------------------
  Foreign Scan on public.ft1 t1
    Output: c1, c2, c3, c4, c5, c6, c7, c8
-   Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE ((1::numeric = ("C 1" !)))
+   Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE ((1::numeric = (!! "C 1")))
 (3 rows)
 
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE (c1 IS NOT NULL) IS DISTINCT FROM (c1 IS NOT NULL); -- DistinctExpr
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index 83971665e3..a8e58a8f24 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -307,7 +307,7 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 IS NULL;        -- Nu
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 IS NOT NULL;    -- NullTest
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE round(abs(c1), 0) = 1; -- FuncExpr
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 = -c1;          -- OpExpr(l)
-EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE 1 = c1!;           -- OpExpr(r)
+EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE 1 = !!c1;          -- OpExpr(r)
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE (c1 IS NOT NULL) IS DISTINCT FROM (c1 IS NOT NULL); -- DistinctExpr
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 = ANY(ARRAY[c2, 1, c1 + 0]); -- ScalarArrayOpExpr
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 = (ARRAY[c1,c2,3])[1]; -- SubscriptingRef
diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c
index 0a53e9b93e..cb7ffda4bd 100644
--- a/src/backend/commands/operatorcmds.c
+++ b/src/backend/commands/operatorcmds.c
@@ -168,10 +168,26 @@ DefineOperator(List *names, List *parameters)
 	if (typeName2)
 		typeId2 = typenameTypeId(NULL, typeName2);
 
+	/*
+	 * If neither argument is specified, do not mention postfix operator
+	 * discontinuation, as the user is unlikely to have meant to create a
+	 * postfix operator.  It is more likely they simply neglected to mention
+	 * the args.
+	 */
 	if (!OidIsValid(typeId1) && !OidIsValid(typeId2))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
-				 errmsg("at least one of leftarg or rightarg must be specified")));
+				 errmsg("at least rightarg must be specified")));
+
+	/*
+	 * But if only the right arg is missing, they probably do intend to create
+	 * a postfix operator, so give them a hint about why that no longer works.
+	 */
+	if (!OidIsValid(typeId2))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+				 errmsg("rightarg must be specified"),
+				 errhint("postfix operator support has been discontinued")));
 
 	if (typeName1)
 	{
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index dbb47d4982..18c2c3c2f0 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -741,7 +741,6 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 %nonassoc	'<' '>' '=' LESS_EQUALS GREATER_EQUALS NOT_EQUALS
 %nonassoc	BETWEEN IN_P LIKE ILIKE SIMILAR NOT_LA
 %nonassoc	ESCAPE			/* ESCAPE must be just above LIKE/ILIKE/SIMILAR */
-%left		POSTFIXOP		/* dummy for postfix Op rules */
 /*
  * To support target_el without AS, we must give IDENT an explicit priority
  * between POSTFIXOP and Op.  We can safely assign the same priority to
@@ -12989,9 +12988,6 @@ a_expr:		c_expr									{ $$ = $1; }
 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3, @2); }
 			| qual_Op a_expr					%prec Op
 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $1, NULL, $2, @1); }
-			| a_expr qual_Op					%prec POSTFIXOP
-				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, NULL, @2); }
-
 			| a_expr AND a_expr
 				{ $$ = makeAndExpr($1, $3, @2); }
 			| a_expr OR a_expr
@@ -13404,8 +13400,6 @@ b_expr:		c_expr
 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3, @2); }
 			| qual_Op b_expr					%prec Op
 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $1, NULL, $2, @1); }
-			| b_expr qual_Op					%prec POSTFIXOP
-				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, NULL, @2); }
 			| b_expr IS DISTINCT FROM b_expr		%prec IS
 				{
 					$$ = (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $5, @2);
@@ -14661,11 +14655,7 @@ target_el:	a_expr AS ColLabel
 				}
 			/*
 			 * 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.
+			 * any known keyword.
 			 */
 			| a_expr IDENT
 				{
diff --git a/src/include/catalog/pg_operator.dat b/src/include/catalog/pg_operator.dat
index 5b0e063655..9b83bddf2e 100644
--- a/src/include/catalog/pg_operator.dat
+++ b/src/include/catalog/pg_operator.dat
@@ -218,9 +218,6 @@
   oprname => '>=', oprleft => 'xid8', oprright => 'xid8', oprresult => 'bool',
   oprcom => '<=(xid8,xid8)', oprnegate => '<(xid8,xid8)', oprcode => 'xid8ge',
   oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' },
-{ oid => '388', descr => 'factorial',
-  oprname => '!', oprkind => 'r', oprleft => 'int8', oprright => '0',
-  oprresult => 'numeric', oprcode => 'numeric_fac' },
 { oid => '389', descr => 'deprecated, use ! instead',
   oprname => '!!', oprkind => 'l', oprleft => '0', oprright => 'int8',
   oprresult => 'numeric', oprcode => 'numeric_fac' },
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 4b5af32440..88d59fb96d 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -327,7 +327,7 @@
 { oid => '110', descr => 'I/O',
   proname => 'unknownout', prorettype => 'cstring', proargtypes => 'unknown',
   prosrc => 'unknownout' },
-{ oid => '111',
+{ oid => '111', descr => 'factorial',
   proname => 'numeric_fac', prorettype => 'numeric', proargtypes => 'int8',
   prosrc => 'numeric_fac' },
 
diff --git a/src/test/regress/expected/create_operator.out b/src/test/regress/expected/create_operator.out
index 54e8b79159..ed77a6616e 100644
--- a/src/test/regress/expected/create_operator.out
+++ b/src/test/regress/expected/create_operator.out
@@ -22,10 +22,14 @@ CREATE OPERATOR #@# (
    leftarg = int8,		-- right unary
    procedure = numeric_fac
 );
+ERROR:  rightarg must be specified
+HINT:  postfix operator support has been discontinued
 CREATE OPERATOR #%# (
    leftarg = int8,		-- right unary
    procedure = numeric_fac
 );
+ERROR:  rightarg must be specified
+HINT:  postfix operator support has been discontinued
 -- Test operator created above
 SELECT point '(1,2)' <% widget '(0,0,3)' AS t,
        point '(1,2)' <% widget '(0,0,1)' AS f;
@@ -52,12 +56,12 @@ CREATE OPERATOR !=- (
    leftarg = int8,		-- right unary
    procedure = numeric_fac
 );
+ERROR:  rightarg must be specified
+HINT:  postfix operator support has been discontinued
 SELECT 2 !=-;
- ?column? 
-----------
-        2
-(1 row)
-
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 2 !=-;
+                    ^
 -- make sure lexer returns != as <> even in edge cases
 SELECT 2 !=/**/ 1, 2 !=/**/ 2;
  ?column? | ?column? 
@@ -172,11 +176,13 @@ CREATE OPERATOR #@%# (
    invalid_att = int8
 );
 WARNING:  operator attribute "invalid_att" not recognized
--- Should fail. At least leftarg or rightarg should be mandatorily specified
+ERROR:  rightarg must be specified
+HINT:  postfix operator support has been discontinued
+-- Should fail. At least rightarg should be mandatorily specified
 CREATE OPERATOR #@%# (
    procedure = numeric_fac
 );
-ERROR:  at least one of leftarg or rightarg must be specified
+ERROR:  at least rightarg must be specified
 -- Should fail. Procedure should be mandatorily specified
 CREATE OPERATOR #@%# (
    leftarg = int8
diff --git a/src/test/regress/expected/numeric.out b/src/test/regress/expected/numeric.out
index 81a0c5d40f..8b2e29779d 100644
--- a/src/test/regress/expected/numeric.out
+++ b/src/test/regress/expected/numeric.out
@@ -2318,7 +2318,7 @@ ERROR:  value overflows numeric format
 --
 -- Tests for factorial
 --
-SELECT 4!;
+SELECT !!4;
  ?column? 
 ----------
        24
@@ -2336,19 +2336,38 @@ SELECT factorial(15);
  1307674368000
 (1 row)
 
-SELECT 100000!;
+SELECT !!100000;
 ERROR:  value overflows numeric format
-SELECT 0!;
+SELECT !!0;
  ?column? 
 ----------
         1
 (1 row)
 
-SELECT -4!;
+SELECT !!(-4);
 ERROR:  factorial of a negative number is undefined
 SELECT factorial(-4);
 ERROR:  factorial of a negative number is undefined
 --
+-- Postfix operator support has been removed.
+--
+SELECT -5!;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT -5!;
+                  ^
+SELECT -0!;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT -0!;
+                  ^
+SELECT 0!;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 0!;
+                 ^
+SELECT 100!;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 100!;
+                   ^
+--
 -- Tests for pg_lsn()
 --
 SELECT pg_lsn(23783416::numeric);
diff --git a/src/test/regress/sql/create_operator.sql b/src/test/regress/sql/create_operator.sql
index 8b6fd0bb43..eb2335e0ef 100644
--- a/src/test/regress/sql/create_operator.sql
+++ b/src/test/regress/sql/create_operator.sql
@@ -133,7 +133,7 @@ CREATE OPERATOR #@%# (
    invalid_att = int8
 );
 
--- Should fail. At least leftarg or rightarg should be mandatorily specified
+-- Should fail. At least rightarg should be mandatorily specified
 CREATE OPERATOR #@%# (
    procedure = numeric_fac
 );
diff --git a/src/test/regress/sql/numeric.sql b/src/test/regress/sql/numeric.sql
index 5dc80f686f..f8ce69422e 100644
--- a/src/test/regress/sql/numeric.sql
+++ b/src/test/regress/sql/numeric.sql
@@ -1115,14 +1115,22 @@ SELECT lcm(9999 * (10::numeric)^131068 + (10::numeric^131068 - 1), 2); -- overfl
 --
 -- Tests for factorial
 --
-SELECT 4!;
+SELECT !!4;
 SELECT !!3;
 SELECT factorial(15);
-SELECT 100000!;
-SELECT 0!;
-SELECT -4!;
+SELECT !!100000;
+SELECT !!0;
+SELECT !!(-4);
 SELECT factorial(-4);
 
+--
+-- Postfix operator support has been removed.
+--
+SELECT -5!;
+SELECT -0!;
+SELECT 0!;
+SELECT 100!;
+
 --
 -- Tests for pg_lsn()
 --
-- 
2.21.1 (Apple Git-122.3)

v3-0002-Allow-most-keywords-to-be-used-as-implicit-column.patchapplication/octet-stream; name=v3-0002-Allow-most-keywords-to-be-used-as-implicit-column.patch; x-unix-mode=0644Download
From db66c658e597ef5977d1e2f4c6f3e00af1651925 Mon Sep 17 00:00:00 2001
From: Mark Dilger <mark.dilger@enterprisedb.com>
Date: Tue, 21 Jul 2020 15:15:49 -0700
Subject: [PATCH v3 2/3] Allow most keywords to be used as implicit column
 labels.

Previously, to use a keyword as a column label in an expression, the
keyword had to be preceded by the token AS.  That is no longer
required for most keywords.  This is accomplished with some changes
to gram.y and by removing support for postfix operators.

These keywords must still be preceded by AS:

    array, as, char, character, create, day, except, fetch, filter,
    for, from, grant, group, having, hour, intersect, into, isnull,
    limit, minute, month, notnull, offset, on, order, over,
    overlaps, precision, returning, second, to, union, varying,
    where, window, with, within, without, year
---
 doc/src/sgml/generate-keywords-table.pl |   2 +-
 src/backend/parser/check_keywords.pl    |  89 ++-
 src/backend/parser/gram.y               | 437 +++++++++++-
 src/backend/parser/scan.l               |   2 +-
 src/common/keywords.c                   |   2 +-
 src/include/parser/kwlist.h             | 902 ++++++++++++------------
 src/interfaces/ecpg/preproc/keywords.c  |   2 +-
 7 files changed, 954 insertions(+), 482 deletions(-)

diff --git a/doc/src/sgml/generate-keywords-table.pl b/doc/src/sgml/generate-keywords-table.pl
index 824b324ef7..6ae6f80c3f 100644
--- a/doc/src/sgml/generate-keywords-table.pl
+++ b/doc/src/sgml/generate-keywords-table.pl
@@ -39,7 +39,7 @@ 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;
 	}
diff --git a/src/backend/parser/check_keywords.pl b/src/backend/parser/check_keywords.pl
index 702c97bba2..98f50c4129 100644
--- a/src/backend/parser/check_keywords.pl
+++ b/src/backend/parser/check_keywords.pl
@@ -21,6 +21,27 @@ sub error
 	return;
 }
 
+sub check_alphabetical_order
+{
+	my ($listname, $list) = @_;
+	my $prevkword = '';
+	my $bare_kword;
+
+	foreach my $kword (@$list)
+	{
+
+		# 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 $listname list is misplaced";
+		}
+		$prevkword = $bare_kword;
+	}
+}
+
 $, = ' ';     # set output field separator
 $\ = "\n";    # set output record separator
 
@@ -33,9 +54,11 @@ $keyword_categories{'reserved_keyword'}       = 'RESERVED_KEYWORD';
 open(my $gram, '<', $gram_filename) || die("Could not open : $gram_filename");
 
 my $kcat;
+my $bare;
 my $comment;
 my @arr;
 my %keywords;
+my @bare;
 
 line: while (my $S = <$gram>)
 {
@@ -51,7 +74,7 @@ line: while (my $S = <$gram>)
 	$s = '[/][*]', $S =~ s#$s# /* #g;
 	$s = '[*][/]', $S =~ s#$s# */ #g;
 
-	if (!($kcat))
+	if (!($kcat) && !($bare))
 	{
 
 		# Is this the beginning of a keyword list?
@@ -63,6 +86,10 @@ line: while (my $S = <$gram>)
 				next line;
 			}
 		}
+
+		# Is this the beginning of the bare_label_keyword list?
+		$bare = 1 if ($S =~ m/^bare_label_keyword:/);
+
 		next line;
 	}
 
@@ -97,7 +124,8 @@ line: while (my $S = <$gram>)
 		{
 
 			# end of keyword list
-			$kcat = '';
+			undef $kcat;
+			undef $bare;
 			next;
 		}
 
@@ -107,31 +135,21 @@ line: while (my $S = <$gram>)
 		}
 
 		# Put this keyword into the right list
-		push @{ $keywords{$kcat} }, $arr[$fieldIndexer];
+		if ($bare)
+		{
+			push @bare, $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);
 
 # Transform the keyword lists into hashes.
 # kwhashes is a hash of hashes, keyed by keyword category id,
@@ -147,6 +165,7 @@ while (my ($kcat, $kcat_id) = each(%keyword_categories))
 
 	$kwhashes{$kcat_id} = $hash;
 }
+my %bare = map { $_ => 1 } @bare;
 
 # Now read in kwlist.h
 
@@ -160,11 +179,35 @@ 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 ($isbare)   = $4;
+
+		# Check that the isbare value matches gram.y
+		if ($isbare eq 'BARE')
+		{
+			unless ($bare{$kwname})
+			{
+				error
+				  "'$kwstring' in kwlist.h is marked as bare, but is missing from gram.y's bare_label_keyword rule";
+			}
+		}
+		elsif ($isbare eq 'EXPLICIT')
+		{
+			if ($bare{$kwname})
+			{
+				error
+				  "'$kwname' in kwlist.h is marked as explicit, but is listed in gram.y's bare_label_keyword rule";
+			}
+		}
+		else
+		{
+			error
+			  "'$isbare' not recognized in kwlist.h.  Expected either 'BARE' or 'EXPLICIT'";
+		}
 
 		# Check that the list is in alphabetical order (critical!)
 		if ($kwstring le $prevkwstring)
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 18c2c3c2f0..c1947c6aac 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -540,14 +540,15 @@ 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> col_name_keyword bare_label_keyword reserved_keyword
 
 %type <node>	TableConstraint TableLikeClause
 %type <ival>	TableLikeOptionList TableLikeOption
@@ -14657,7 +14658,7 @@ target_el:	a_expr AS ColLabel
 			 * We support omitting AS only for column labels that aren't
 			 * any known keyword.
 			 */
-			| a_expr IDENT
+			| a_expr BareColLabel
 				{
 					$$ = makeNode(ResTarget);
 					$$->name = $2;
@@ -14985,6 +14986,12 @@ NonReservedWord:	IDENT							{ $$ = $1; }
 			| type_func_name_keyword				{ $$ = pstrdup($1); }
 		;
 
+/* Bare column label --- names that can be column labels without writing "AS".
+ */
+BareColLabel:	IDENT								{ $$ = $1; }
+			| bare_label_keyword					{ $$ = pstrdup($1); }
+		;
+
 /* Column label --- allowed labels in "AS" clauses.
  * This presently includes *all* Postgres keywords.
  */
@@ -14996,6 +15003,428 @@ ColLabel:	IDENT									{ $$ = $1; }
 		;
 
 
+/*
+ * All keywords can be used explicitly as a column label in expressions
+ * like 'SELECT 1234 AS keyword', but only some keywords can be used
+ * implicitly as column labels in expressions like 'SELECT 1234 keyword'.
+ * Those that can be used implicitly should be listed here.
+ *
+ * Keep this in alphabetical order.
+ */
+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
+		;
+
 /*
  * Keyword category lists.  Generally, every keyword present in
  * the Postgres grammar should appear in exactly one of these lists.
@@ -15006,7 +15435,7 @@ ColLabel:	IDENT									{ $$ = $1; }
  *
  * Make sure that each keyword's category in kwlist.h matches where
  * it is listed here.  (Someday we may be able to generate these lists and
- * kwlist.h's table from one source of truth.)
+ * kwlist.h's table from a common master list.)
  */
 
 /* "Unreserved" keywords --- available for use as any kind of name.
diff --git a/src/backend/parser/scan.l b/src/backend/parser/scan.l
index b1ea0cb538..b26492159b 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, status) value,
 
 const uint16 ScanKeywordTokens[] = {
 #include "parser/kwlist.h"
diff --git a/src/common/keywords.c b/src/common/keywords.c
index 54ed977096..e64bdf00eb 100644
--- a/src/common/keywords.c
+++ b/src/common/keywords.c
@@ -24,7 +24,7 @@
 
 /* Keyword categories for SQL keywords */
 
-#define PG_KEYWORD(kwname, value, category) category,
+#define PG_KEYWORD(kwname, value, category, status) category,
 
 const uint8 ScanKeywordCategories[SCANKEYWORDS_NUM_KEYWORDS] = {
 #include "parser/kwlist.h"
diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h
index 08f22ce211..917e2cffa9 100644
--- a/src/include/parser/kwlist.h
+++ b/src/include/parser/kwlist.h
@@ -24,454 +24,454 @@
  * Note: gen_keywordlist.pl requires the entries to appear in ASCII order.
  */
 
-/* name, value, category */
-PG_KEYWORD("abort", ABORT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("absolute", ABSOLUTE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("access", ACCESS, UNRESERVED_KEYWORD)
-PG_KEYWORD("action", ACTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("add", ADD_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("admin", ADMIN, UNRESERVED_KEYWORD)
-PG_KEYWORD("after", AFTER, UNRESERVED_KEYWORD)
-PG_KEYWORD("aggregate", AGGREGATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("all", ALL, RESERVED_KEYWORD)
-PG_KEYWORD("also", ALSO, UNRESERVED_KEYWORD)
-PG_KEYWORD("alter", ALTER, UNRESERVED_KEYWORD)
-PG_KEYWORD("always", ALWAYS, UNRESERVED_KEYWORD)
-PG_KEYWORD("analyse", ANALYSE, RESERVED_KEYWORD)		/* British spelling */
-PG_KEYWORD("analyze", ANALYZE, RESERVED_KEYWORD)
-PG_KEYWORD("and", AND, RESERVED_KEYWORD)
-PG_KEYWORD("any", ANY, RESERVED_KEYWORD)
-PG_KEYWORD("array", ARRAY, RESERVED_KEYWORD)
-PG_KEYWORD("as", AS, RESERVED_KEYWORD)
-PG_KEYWORD("asc", ASC, RESERVED_KEYWORD)
-PG_KEYWORD("assertion", ASSERTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("assignment", ASSIGNMENT, UNRESERVED_KEYWORD)
-PG_KEYWORD("asymmetric", ASYMMETRIC, RESERVED_KEYWORD)
-PG_KEYWORD("at", AT, UNRESERVED_KEYWORD)
-PG_KEYWORD("attach", ATTACH, UNRESERVED_KEYWORD)
-PG_KEYWORD("attribute", ATTRIBUTE, UNRESERVED_KEYWORD)
-PG_KEYWORD("authorization", AUTHORIZATION, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("backward", BACKWARD, UNRESERVED_KEYWORD)
-PG_KEYWORD("before", BEFORE, UNRESERVED_KEYWORD)
-PG_KEYWORD("begin", BEGIN_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("between", BETWEEN, COL_NAME_KEYWORD)
-PG_KEYWORD("bigint", BIGINT, COL_NAME_KEYWORD)
-PG_KEYWORD("binary", BINARY, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("bit", BIT, COL_NAME_KEYWORD)
-PG_KEYWORD("boolean", BOOLEAN_P, COL_NAME_KEYWORD)
-PG_KEYWORD("both", BOTH, RESERVED_KEYWORD)
-PG_KEYWORD("by", BY, UNRESERVED_KEYWORD)
-PG_KEYWORD("cache", CACHE, UNRESERVED_KEYWORD)
-PG_KEYWORD("call", CALL, UNRESERVED_KEYWORD)
-PG_KEYWORD("called", CALLED, UNRESERVED_KEYWORD)
-PG_KEYWORD("cascade", CASCADE, UNRESERVED_KEYWORD)
-PG_KEYWORD("cascaded", CASCADED, UNRESERVED_KEYWORD)
-PG_KEYWORD("case", CASE, RESERVED_KEYWORD)
-PG_KEYWORD("cast", CAST, RESERVED_KEYWORD)
-PG_KEYWORD("catalog", CATALOG_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("chain", CHAIN, UNRESERVED_KEYWORD)
-PG_KEYWORD("char", CHAR_P, COL_NAME_KEYWORD)
-PG_KEYWORD("character", CHARACTER, COL_NAME_KEYWORD)
-PG_KEYWORD("characteristics", CHARACTERISTICS, UNRESERVED_KEYWORD)
-PG_KEYWORD("check", CHECK, RESERVED_KEYWORD)
-PG_KEYWORD("checkpoint", CHECKPOINT, UNRESERVED_KEYWORD)
-PG_KEYWORD("class", CLASS, UNRESERVED_KEYWORD)
-PG_KEYWORD("close", CLOSE, UNRESERVED_KEYWORD)
-PG_KEYWORD("cluster", CLUSTER, UNRESERVED_KEYWORD)
-PG_KEYWORD("coalesce", COALESCE, COL_NAME_KEYWORD)
-PG_KEYWORD("collate", COLLATE, RESERVED_KEYWORD)
-PG_KEYWORD("collation", COLLATION, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("column", COLUMN, RESERVED_KEYWORD)
-PG_KEYWORD("columns", COLUMNS, UNRESERVED_KEYWORD)
-PG_KEYWORD("comment", COMMENT, UNRESERVED_KEYWORD)
-PG_KEYWORD("comments", COMMENTS, UNRESERVED_KEYWORD)
-PG_KEYWORD("commit", COMMIT, UNRESERVED_KEYWORD)
-PG_KEYWORD("committed", COMMITTED, UNRESERVED_KEYWORD)
-PG_KEYWORD("concurrently", CONCURRENTLY, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("configuration", CONFIGURATION, UNRESERVED_KEYWORD)
-PG_KEYWORD("conflict", CONFLICT, UNRESERVED_KEYWORD)
-PG_KEYWORD("connection", CONNECTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("constraint", CONSTRAINT, RESERVED_KEYWORD)
-PG_KEYWORD("constraints", CONSTRAINTS, UNRESERVED_KEYWORD)
-PG_KEYWORD("content", CONTENT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("continue", CONTINUE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("conversion", CONVERSION_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("copy", COPY, UNRESERVED_KEYWORD)
-PG_KEYWORD("cost", COST, UNRESERVED_KEYWORD)
-PG_KEYWORD("create", CREATE, RESERVED_KEYWORD)
-PG_KEYWORD("cross", CROSS, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("csv", CSV, UNRESERVED_KEYWORD)
-PG_KEYWORD("cube", CUBE, UNRESERVED_KEYWORD)
-PG_KEYWORD("current", CURRENT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("current_catalog", CURRENT_CATALOG, RESERVED_KEYWORD)
-PG_KEYWORD("current_date", CURRENT_DATE, RESERVED_KEYWORD)
-PG_KEYWORD("current_role", CURRENT_ROLE, RESERVED_KEYWORD)
-PG_KEYWORD("current_schema", CURRENT_SCHEMA, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("current_time", CURRENT_TIME, RESERVED_KEYWORD)
-PG_KEYWORD("current_timestamp", CURRENT_TIMESTAMP, RESERVED_KEYWORD)
-PG_KEYWORD("current_user", CURRENT_USER, RESERVED_KEYWORD)
-PG_KEYWORD("cursor", CURSOR, UNRESERVED_KEYWORD)
-PG_KEYWORD("cycle", CYCLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("data", DATA_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("database", DATABASE, UNRESERVED_KEYWORD)
-PG_KEYWORD("day", DAY_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("deallocate", DEALLOCATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("dec", DEC, COL_NAME_KEYWORD)
-PG_KEYWORD("decimal", DECIMAL_P, COL_NAME_KEYWORD)
-PG_KEYWORD("declare", DECLARE, UNRESERVED_KEYWORD)
-PG_KEYWORD("default", DEFAULT, RESERVED_KEYWORD)
-PG_KEYWORD("defaults", DEFAULTS, UNRESERVED_KEYWORD)
-PG_KEYWORD("deferrable", DEFERRABLE, RESERVED_KEYWORD)
-PG_KEYWORD("deferred", DEFERRED, UNRESERVED_KEYWORD)
-PG_KEYWORD("definer", DEFINER, UNRESERVED_KEYWORD)
-PG_KEYWORD("delete", DELETE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("delimiter", DELIMITER, UNRESERVED_KEYWORD)
-PG_KEYWORD("delimiters", DELIMITERS, UNRESERVED_KEYWORD)
-PG_KEYWORD("depends", DEPENDS, UNRESERVED_KEYWORD)
-PG_KEYWORD("desc", DESC, RESERVED_KEYWORD)
-PG_KEYWORD("detach", DETACH, UNRESERVED_KEYWORD)
-PG_KEYWORD("dictionary", DICTIONARY, UNRESERVED_KEYWORD)
-PG_KEYWORD("disable", DISABLE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("discard", DISCARD, UNRESERVED_KEYWORD)
-PG_KEYWORD("distinct", DISTINCT, RESERVED_KEYWORD)
-PG_KEYWORD("do", DO, RESERVED_KEYWORD)
-PG_KEYWORD("document", DOCUMENT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("domain", DOMAIN_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("double", DOUBLE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("drop", DROP, UNRESERVED_KEYWORD)
-PG_KEYWORD("each", EACH, UNRESERVED_KEYWORD)
-PG_KEYWORD("else", ELSE, RESERVED_KEYWORD)
-PG_KEYWORD("enable", ENABLE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("encoding", ENCODING, UNRESERVED_KEYWORD)
-PG_KEYWORD("encrypted", ENCRYPTED, UNRESERVED_KEYWORD)
-PG_KEYWORD("end", END_P, RESERVED_KEYWORD)
-PG_KEYWORD("enum", ENUM_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("escape", ESCAPE, UNRESERVED_KEYWORD)
-PG_KEYWORD("event", EVENT, UNRESERVED_KEYWORD)
-PG_KEYWORD("except", EXCEPT, RESERVED_KEYWORD)
-PG_KEYWORD("exclude", EXCLUDE, UNRESERVED_KEYWORD)
-PG_KEYWORD("excluding", EXCLUDING, UNRESERVED_KEYWORD)
-PG_KEYWORD("exclusive", EXCLUSIVE, UNRESERVED_KEYWORD)
-PG_KEYWORD("execute", EXECUTE, UNRESERVED_KEYWORD)
-PG_KEYWORD("exists", EXISTS, COL_NAME_KEYWORD)
-PG_KEYWORD("explain", EXPLAIN, UNRESERVED_KEYWORD)
-PG_KEYWORD("expression", EXPRESSION, UNRESERVED_KEYWORD)
-PG_KEYWORD("extension", EXTENSION, UNRESERVED_KEYWORD)
-PG_KEYWORD("external", EXTERNAL, UNRESERVED_KEYWORD)
-PG_KEYWORD("extract", EXTRACT, COL_NAME_KEYWORD)
-PG_KEYWORD("false", FALSE_P, RESERVED_KEYWORD)
-PG_KEYWORD("family", FAMILY, UNRESERVED_KEYWORD)
-PG_KEYWORD("fetch", FETCH, RESERVED_KEYWORD)
-PG_KEYWORD("filter", FILTER, UNRESERVED_KEYWORD)
-PG_KEYWORD("first", FIRST_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("float", FLOAT_P, COL_NAME_KEYWORD)
-PG_KEYWORD("following", FOLLOWING, UNRESERVED_KEYWORD)
-PG_KEYWORD("for", FOR, RESERVED_KEYWORD)
-PG_KEYWORD("force", FORCE, UNRESERVED_KEYWORD)
-PG_KEYWORD("foreign", FOREIGN, RESERVED_KEYWORD)
-PG_KEYWORD("forward", FORWARD, UNRESERVED_KEYWORD)
-PG_KEYWORD("freeze", FREEZE, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("from", FROM, RESERVED_KEYWORD)
-PG_KEYWORD("full", FULL, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("function", FUNCTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("functions", FUNCTIONS, UNRESERVED_KEYWORD)
-PG_KEYWORD("generated", GENERATED, UNRESERVED_KEYWORD)
-PG_KEYWORD("global", GLOBAL, UNRESERVED_KEYWORD)
-PG_KEYWORD("grant", GRANT, RESERVED_KEYWORD)
-PG_KEYWORD("granted", GRANTED, UNRESERVED_KEYWORD)
-PG_KEYWORD("greatest", GREATEST, COL_NAME_KEYWORD)
-PG_KEYWORD("group", GROUP_P, RESERVED_KEYWORD)
-PG_KEYWORD("grouping", GROUPING, COL_NAME_KEYWORD)
-PG_KEYWORD("groups", GROUPS, UNRESERVED_KEYWORD)
-PG_KEYWORD("handler", HANDLER, UNRESERVED_KEYWORD)
-PG_KEYWORD("having", HAVING, RESERVED_KEYWORD)
-PG_KEYWORD("header", HEADER_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("hold", HOLD, UNRESERVED_KEYWORD)
-PG_KEYWORD("hour", HOUR_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("identity", IDENTITY_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("if", IF_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("ilike", ILIKE, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("immediate", IMMEDIATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("immutable", IMMUTABLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("implicit", IMPLICIT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("import", IMPORT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("in", IN_P, RESERVED_KEYWORD)
-PG_KEYWORD("include", INCLUDE, UNRESERVED_KEYWORD)
-PG_KEYWORD("including", INCLUDING, UNRESERVED_KEYWORD)
-PG_KEYWORD("increment", INCREMENT, UNRESERVED_KEYWORD)
-PG_KEYWORD("index", INDEX, UNRESERVED_KEYWORD)
-PG_KEYWORD("indexes", INDEXES, UNRESERVED_KEYWORD)
-PG_KEYWORD("inherit", INHERIT, UNRESERVED_KEYWORD)
-PG_KEYWORD("inherits", INHERITS, UNRESERVED_KEYWORD)
-PG_KEYWORD("initially", INITIALLY, RESERVED_KEYWORD)
-PG_KEYWORD("inline", INLINE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("inner", INNER_P, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("inout", INOUT, COL_NAME_KEYWORD)
-PG_KEYWORD("input", INPUT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("insensitive", INSENSITIVE, UNRESERVED_KEYWORD)
-PG_KEYWORD("insert", INSERT, UNRESERVED_KEYWORD)
-PG_KEYWORD("instead", INSTEAD, UNRESERVED_KEYWORD)
-PG_KEYWORD("int", INT_P, COL_NAME_KEYWORD)
-PG_KEYWORD("integer", INTEGER, COL_NAME_KEYWORD)
-PG_KEYWORD("intersect", INTERSECT, RESERVED_KEYWORD)
-PG_KEYWORD("interval", INTERVAL, COL_NAME_KEYWORD)
-PG_KEYWORD("into", INTO, RESERVED_KEYWORD)
-PG_KEYWORD("invoker", INVOKER, UNRESERVED_KEYWORD)
-PG_KEYWORD("is", IS, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("isnull", ISNULL, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("isolation", ISOLATION, UNRESERVED_KEYWORD)
-PG_KEYWORD("join", JOIN, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("key", KEY, UNRESERVED_KEYWORD)
-PG_KEYWORD("label", LABEL, UNRESERVED_KEYWORD)
-PG_KEYWORD("language", LANGUAGE, UNRESERVED_KEYWORD)
-PG_KEYWORD("large", LARGE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("last", LAST_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("lateral", LATERAL_P, RESERVED_KEYWORD)
-PG_KEYWORD("leading", LEADING, RESERVED_KEYWORD)
-PG_KEYWORD("leakproof", LEAKPROOF, UNRESERVED_KEYWORD)
-PG_KEYWORD("least", LEAST, COL_NAME_KEYWORD)
-PG_KEYWORD("left", LEFT, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("level", LEVEL, UNRESERVED_KEYWORD)
-PG_KEYWORD("like", LIKE, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("limit", LIMIT, RESERVED_KEYWORD)
-PG_KEYWORD("listen", LISTEN, UNRESERVED_KEYWORD)
-PG_KEYWORD("load", LOAD, UNRESERVED_KEYWORD)
-PG_KEYWORD("local", LOCAL, UNRESERVED_KEYWORD)
-PG_KEYWORD("localtime", LOCALTIME, RESERVED_KEYWORD)
-PG_KEYWORD("localtimestamp", LOCALTIMESTAMP, RESERVED_KEYWORD)
-PG_KEYWORD("location", LOCATION, UNRESERVED_KEYWORD)
-PG_KEYWORD("lock", LOCK_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("locked", LOCKED, UNRESERVED_KEYWORD)
-PG_KEYWORD("logged", LOGGED, UNRESERVED_KEYWORD)
-PG_KEYWORD("mapping", MAPPING, UNRESERVED_KEYWORD)
-PG_KEYWORD("match", MATCH, UNRESERVED_KEYWORD)
-PG_KEYWORD("materialized", MATERIALIZED, UNRESERVED_KEYWORD)
-PG_KEYWORD("maxvalue", MAXVALUE, UNRESERVED_KEYWORD)
-PG_KEYWORD("method", METHOD, UNRESERVED_KEYWORD)
-PG_KEYWORD("minute", MINUTE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("minvalue", MINVALUE, UNRESERVED_KEYWORD)
-PG_KEYWORD("mode", MODE, UNRESERVED_KEYWORD)
-PG_KEYWORD("month", MONTH_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("move", MOVE, UNRESERVED_KEYWORD)
-PG_KEYWORD("name", NAME_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("names", NAMES, UNRESERVED_KEYWORD)
-PG_KEYWORD("national", NATIONAL, COL_NAME_KEYWORD)
-PG_KEYWORD("natural", NATURAL, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("nchar", NCHAR, COL_NAME_KEYWORD)
-PG_KEYWORD("new", NEW, UNRESERVED_KEYWORD)
-PG_KEYWORD("next", NEXT, UNRESERVED_KEYWORD)
-PG_KEYWORD("nfc", NFC, UNRESERVED_KEYWORD)
-PG_KEYWORD("nfd", NFD, UNRESERVED_KEYWORD)
-PG_KEYWORD("nfkc", NFKC, UNRESERVED_KEYWORD)
-PG_KEYWORD("nfkd", NFKD, UNRESERVED_KEYWORD)
-PG_KEYWORD("no", NO, UNRESERVED_KEYWORD)
-PG_KEYWORD("none", NONE, COL_NAME_KEYWORD)
-PG_KEYWORD("normalize", NORMALIZE, COL_NAME_KEYWORD)
-PG_KEYWORD("normalized", NORMALIZED, UNRESERVED_KEYWORD)
-PG_KEYWORD("not", NOT, RESERVED_KEYWORD)
-PG_KEYWORD("nothing", NOTHING, UNRESERVED_KEYWORD)
-PG_KEYWORD("notify", NOTIFY, UNRESERVED_KEYWORD)
-PG_KEYWORD("notnull", NOTNULL, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("nowait", NOWAIT, UNRESERVED_KEYWORD)
-PG_KEYWORD("null", NULL_P, RESERVED_KEYWORD)
-PG_KEYWORD("nullif", NULLIF, COL_NAME_KEYWORD)
-PG_KEYWORD("nulls", NULLS_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("numeric", NUMERIC, COL_NAME_KEYWORD)
-PG_KEYWORD("object", OBJECT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("of", OF, UNRESERVED_KEYWORD)
-PG_KEYWORD("off", OFF, UNRESERVED_KEYWORD)
-PG_KEYWORD("offset", OFFSET, RESERVED_KEYWORD)
-PG_KEYWORD("oids", OIDS, UNRESERVED_KEYWORD)
-PG_KEYWORD("old", OLD, UNRESERVED_KEYWORD)
-PG_KEYWORD("on", ON, RESERVED_KEYWORD)
-PG_KEYWORD("only", ONLY, RESERVED_KEYWORD)
-PG_KEYWORD("operator", OPERATOR, UNRESERVED_KEYWORD)
-PG_KEYWORD("option", OPTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("options", OPTIONS, UNRESERVED_KEYWORD)
-PG_KEYWORD("or", OR, RESERVED_KEYWORD)
-PG_KEYWORD("order", ORDER, RESERVED_KEYWORD)
-PG_KEYWORD("ordinality", ORDINALITY, UNRESERVED_KEYWORD)
-PG_KEYWORD("others", OTHERS, UNRESERVED_KEYWORD)
-PG_KEYWORD("out", OUT_P, COL_NAME_KEYWORD)
-PG_KEYWORD("outer", OUTER_P, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("over", OVER, UNRESERVED_KEYWORD)
-PG_KEYWORD("overlaps", OVERLAPS, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("overlay", OVERLAY, COL_NAME_KEYWORD)
-PG_KEYWORD("overriding", OVERRIDING, UNRESERVED_KEYWORD)
-PG_KEYWORD("owned", OWNED, UNRESERVED_KEYWORD)
-PG_KEYWORD("owner", OWNER, UNRESERVED_KEYWORD)
-PG_KEYWORD("parallel", PARALLEL, UNRESERVED_KEYWORD)
-PG_KEYWORD("parser", PARSER, UNRESERVED_KEYWORD)
-PG_KEYWORD("partial", PARTIAL, UNRESERVED_KEYWORD)
-PG_KEYWORD("partition", PARTITION, UNRESERVED_KEYWORD)
-PG_KEYWORD("passing", PASSING, UNRESERVED_KEYWORD)
-PG_KEYWORD("password", PASSWORD, UNRESERVED_KEYWORD)
-PG_KEYWORD("placing", PLACING, RESERVED_KEYWORD)
-PG_KEYWORD("plans", PLANS, UNRESERVED_KEYWORD)
-PG_KEYWORD("policy", POLICY, UNRESERVED_KEYWORD)
-PG_KEYWORD("position", POSITION, COL_NAME_KEYWORD)
-PG_KEYWORD("preceding", PRECEDING, UNRESERVED_KEYWORD)
-PG_KEYWORD("precision", PRECISION, COL_NAME_KEYWORD)
-PG_KEYWORD("prepare", PREPARE, UNRESERVED_KEYWORD)
-PG_KEYWORD("prepared", PREPARED, UNRESERVED_KEYWORD)
-PG_KEYWORD("preserve", PRESERVE, UNRESERVED_KEYWORD)
-PG_KEYWORD("primary", PRIMARY, RESERVED_KEYWORD)
-PG_KEYWORD("prior", PRIOR, UNRESERVED_KEYWORD)
-PG_KEYWORD("privileges", PRIVILEGES, UNRESERVED_KEYWORD)
-PG_KEYWORD("procedural", PROCEDURAL, UNRESERVED_KEYWORD)
-PG_KEYWORD("procedure", PROCEDURE, UNRESERVED_KEYWORD)
-PG_KEYWORD("procedures", PROCEDURES, UNRESERVED_KEYWORD)
-PG_KEYWORD("program", PROGRAM, UNRESERVED_KEYWORD)
-PG_KEYWORD("publication", PUBLICATION, UNRESERVED_KEYWORD)
-PG_KEYWORD("quote", QUOTE, UNRESERVED_KEYWORD)
-PG_KEYWORD("range", RANGE, UNRESERVED_KEYWORD)
-PG_KEYWORD("read", READ, UNRESERVED_KEYWORD)
-PG_KEYWORD("real", REAL, COL_NAME_KEYWORD)
-PG_KEYWORD("reassign", REASSIGN, UNRESERVED_KEYWORD)
-PG_KEYWORD("recheck", RECHECK, UNRESERVED_KEYWORD)
-PG_KEYWORD("recursive", RECURSIVE, UNRESERVED_KEYWORD)
-PG_KEYWORD("ref", REF, UNRESERVED_KEYWORD)
-PG_KEYWORD("references", REFERENCES, RESERVED_KEYWORD)
-PG_KEYWORD("referencing", REFERENCING, UNRESERVED_KEYWORD)
-PG_KEYWORD("refresh", REFRESH, UNRESERVED_KEYWORD)
-PG_KEYWORD("reindex", REINDEX, UNRESERVED_KEYWORD)
-PG_KEYWORD("relative", RELATIVE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("release", RELEASE, UNRESERVED_KEYWORD)
-PG_KEYWORD("rename", RENAME, UNRESERVED_KEYWORD)
-PG_KEYWORD("repeatable", REPEATABLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("replace", REPLACE, UNRESERVED_KEYWORD)
-PG_KEYWORD("replica", REPLICA, UNRESERVED_KEYWORD)
-PG_KEYWORD("reset", RESET, UNRESERVED_KEYWORD)
-PG_KEYWORD("restart", RESTART, UNRESERVED_KEYWORD)
-PG_KEYWORD("restrict", RESTRICT, UNRESERVED_KEYWORD)
-PG_KEYWORD("returning", RETURNING, RESERVED_KEYWORD)
-PG_KEYWORD("returns", RETURNS, UNRESERVED_KEYWORD)
-PG_KEYWORD("revoke", REVOKE, UNRESERVED_KEYWORD)
-PG_KEYWORD("right", RIGHT, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("role", ROLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("rollback", ROLLBACK, UNRESERVED_KEYWORD)
-PG_KEYWORD("rollup", ROLLUP, UNRESERVED_KEYWORD)
-PG_KEYWORD("routine", ROUTINE, UNRESERVED_KEYWORD)
-PG_KEYWORD("routines", ROUTINES, UNRESERVED_KEYWORD)
-PG_KEYWORD("row", ROW, COL_NAME_KEYWORD)
-PG_KEYWORD("rows", ROWS, UNRESERVED_KEYWORD)
-PG_KEYWORD("rule", RULE, UNRESERVED_KEYWORD)
-PG_KEYWORD("savepoint", SAVEPOINT, UNRESERVED_KEYWORD)
-PG_KEYWORD("schema", SCHEMA, UNRESERVED_KEYWORD)
-PG_KEYWORD("schemas", SCHEMAS, UNRESERVED_KEYWORD)
-PG_KEYWORD("scroll", SCROLL, UNRESERVED_KEYWORD)
-PG_KEYWORD("search", SEARCH, UNRESERVED_KEYWORD)
-PG_KEYWORD("second", SECOND_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("security", SECURITY, UNRESERVED_KEYWORD)
-PG_KEYWORD("select", SELECT, RESERVED_KEYWORD)
-PG_KEYWORD("sequence", SEQUENCE, UNRESERVED_KEYWORD)
-PG_KEYWORD("sequences", SEQUENCES, UNRESERVED_KEYWORD)
-PG_KEYWORD("serializable", SERIALIZABLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("server", SERVER, UNRESERVED_KEYWORD)
-PG_KEYWORD("session", SESSION, UNRESERVED_KEYWORD)
-PG_KEYWORD("session_user", SESSION_USER, RESERVED_KEYWORD)
-PG_KEYWORD("set", SET, UNRESERVED_KEYWORD)
-PG_KEYWORD("setof", SETOF, COL_NAME_KEYWORD)
-PG_KEYWORD("sets", SETS, UNRESERVED_KEYWORD)
-PG_KEYWORD("share", SHARE, UNRESERVED_KEYWORD)
-PG_KEYWORD("show", SHOW, UNRESERVED_KEYWORD)
-PG_KEYWORD("similar", SIMILAR, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("simple", SIMPLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("skip", SKIP, UNRESERVED_KEYWORD)
-PG_KEYWORD("smallint", SMALLINT, COL_NAME_KEYWORD)
-PG_KEYWORD("snapshot", SNAPSHOT, UNRESERVED_KEYWORD)
-PG_KEYWORD("some", SOME, RESERVED_KEYWORD)
-PG_KEYWORD("sql", SQL_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("stable", STABLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("standalone", STANDALONE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("start", START, UNRESERVED_KEYWORD)
-PG_KEYWORD("statement", STATEMENT, UNRESERVED_KEYWORD)
-PG_KEYWORD("statistics", STATISTICS, UNRESERVED_KEYWORD)
-PG_KEYWORD("stdin", STDIN, UNRESERVED_KEYWORD)
-PG_KEYWORD("stdout", STDOUT, UNRESERVED_KEYWORD)
-PG_KEYWORD("storage", STORAGE, UNRESERVED_KEYWORD)
-PG_KEYWORD("stored", STORED, UNRESERVED_KEYWORD)
-PG_KEYWORD("strict", STRICT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("strip", STRIP_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("subscription", SUBSCRIPTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("substring", SUBSTRING, COL_NAME_KEYWORD)
-PG_KEYWORD("support", SUPPORT, UNRESERVED_KEYWORD)
-PG_KEYWORD("symmetric", SYMMETRIC, RESERVED_KEYWORD)
-PG_KEYWORD("sysid", SYSID, UNRESERVED_KEYWORD)
-PG_KEYWORD("system", SYSTEM_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("table", TABLE, RESERVED_KEYWORD)
-PG_KEYWORD("tables", TABLES, UNRESERVED_KEYWORD)
-PG_KEYWORD("tablesample", TABLESAMPLE, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("tablespace", TABLESPACE, UNRESERVED_KEYWORD)
-PG_KEYWORD("temp", TEMP, UNRESERVED_KEYWORD)
-PG_KEYWORD("template", TEMPLATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("temporary", TEMPORARY, UNRESERVED_KEYWORD)
-PG_KEYWORD("text", TEXT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("then", THEN, RESERVED_KEYWORD)
-PG_KEYWORD("ties", TIES, UNRESERVED_KEYWORD)
-PG_KEYWORD("time", TIME, COL_NAME_KEYWORD)
-PG_KEYWORD("timestamp", TIMESTAMP, COL_NAME_KEYWORD)
-PG_KEYWORD("to", TO, RESERVED_KEYWORD)
-PG_KEYWORD("trailing", TRAILING, RESERVED_KEYWORD)
-PG_KEYWORD("transaction", TRANSACTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("transform", TRANSFORM, UNRESERVED_KEYWORD)
-PG_KEYWORD("treat", TREAT, COL_NAME_KEYWORD)
-PG_KEYWORD("trigger", TRIGGER, UNRESERVED_KEYWORD)
-PG_KEYWORD("trim", TRIM, COL_NAME_KEYWORD)
-PG_KEYWORD("true", TRUE_P, RESERVED_KEYWORD)
-PG_KEYWORD("truncate", TRUNCATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("trusted", TRUSTED, UNRESERVED_KEYWORD)
-PG_KEYWORD("type", TYPE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("types", TYPES_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("uescape", UESCAPE, UNRESERVED_KEYWORD)
-PG_KEYWORD("unbounded", UNBOUNDED, UNRESERVED_KEYWORD)
-PG_KEYWORD("uncommitted", UNCOMMITTED, UNRESERVED_KEYWORD)
-PG_KEYWORD("unencrypted", UNENCRYPTED, UNRESERVED_KEYWORD)
-PG_KEYWORD("union", UNION, RESERVED_KEYWORD)
-PG_KEYWORD("unique", UNIQUE, RESERVED_KEYWORD)
-PG_KEYWORD("unknown", UNKNOWN, UNRESERVED_KEYWORD)
-PG_KEYWORD("unlisten", UNLISTEN, UNRESERVED_KEYWORD)
-PG_KEYWORD("unlogged", UNLOGGED, UNRESERVED_KEYWORD)
-PG_KEYWORD("until", UNTIL, UNRESERVED_KEYWORD)
-PG_KEYWORD("update", UPDATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("user", USER, RESERVED_KEYWORD)
-PG_KEYWORD("using", USING, RESERVED_KEYWORD)
-PG_KEYWORD("vacuum", VACUUM, UNRESERVED_KEYWORD)
-PG_KEYWORD("valid", VALID, UNRESERVED_KEYWORD)
-PG_KEYWORD("validate", VALIDATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("validator", VALIDATOR, UNRESERVED_KEYWORD)
-PG_KEYWORD("value", VALUE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("values", VALUES, COL_NAME_KEYWORD)
-PG_KEYWORD("varchar", VARCHAR, COL_NAME_KEYWORD)
-PG_KEYWORD("variadic", VARIADIC, RESERVED_KEYWORD)
-PG_KEYWORD("varying", VARYING, UNRESERVED_KEYWORD)
-PG_KEYWORD("verbose", VERBOSE, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("version", VERSION_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("view", VIEW, UNRESERVED_KEYWORD)
-PG_KEYWORD("views", VIEWS, UNRESERVED_KEYWORD)
-PG_KEYWORD("volatile", VOLATILE, UNRESERVED_KEYWORD)
-PG_KEYWORD("when", WHEN, RESERVED_KEYWORD)
-PG_KEYWORD("where", WHERE, RESERVED_KEYWORD)
-PG_KEYWORD("whitespace", WHITESPACE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("window", WINDOW, RESERVED_KEYWORD)
-PG_KEYWORD("with", WITH, RESERVED_KEYWORD)
-PG_KEYWORD("within", WITHIN, UNRESERVED_KEYWORD)
-PG_KEYWORD("without", WITHOUT, UNRESERVED_KEYWORD)
-PG_KEYWORD("work", WORK, UNRESERVED_KEYWORD)
-PG_KEYWORD("wrapper", WRAPPER, UNRESERVED_KEYWORD)
-PG_KEYWORD("write", WRITE, UNRESERVED_KEYWORD)
-PG_KEYWORD("xml", XML_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("xmlattributes", XMLATTRIBUTES, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlconcat", XMLCONCAT, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlelement", XMLELEMENT, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlexists", XMLEXISTS, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlforest", XMLFOREST, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlnamespaces", XMLNAMESPACES, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlparse", XMLPARSE, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlpi", XMLPI, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlroot", XMLROOT, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlserialize", XMLSERIALIZE, COL_NAME_KEYWORD)
-PG_KEYWORD("xmltable", XMLTABLE, COL_NAME_KEYWORD)
-PG_KEYWORD("year", YEAR_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("yes", YES_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("zone", ZONE, UNRESERVED_KEYWORD)
+/* name, value, category, is bare */
+PG_KEYWORD("abort", ABORT_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("absolute", ABSOLUTE_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("access", ACCESS, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("action", ACTION, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("add", ADD_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("admin", ADMIN, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("after", AFTER, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("aggregate", AGGREGATE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("all", ALL, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("also", ALSO, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("alter", ALTER, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("always", ALWAYS, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("analyse", ANALYSE, RESERVED_KEYWORD, BARE)		/* British spelling */
+PG_KEYWORD("analyze", ANALYZE, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("and", AND, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("any", ANY, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("array", ARRAY, RESERVED_KEYWORD, EXPLICIT)
+PG_KEYWORD("as", AS, RESERVED_KEYWORD, EXPLICIT)
+PG_KEYWORD("asc", ASC, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("assertion", ASSERTION, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("assignment", ASSIGNMENT, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("asymmetric", ASYMMETRIC, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("at", AT, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("attach", ATTACH, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("attribute", ATTRIBUTE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("authorization", AUTHORIZATION, TYPE_FUNC_NAME_KEYWORD, BARE)
+PG_KEYWORD("backward", BACKWARD, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("before", BEFORE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("begin", BEGIN_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("between", BETWEEN, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("bigint", BIGINT, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("binary", BINARY, TYPE_FUNC_NAME_KEYWORD, BARE)
+PG_KEYWORD("bit", BIT, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("boolean", BOOLEAN_P, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("both", BOTH, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("by", BY, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("cache", CACHE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("call", CALL, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("called", CALLED, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("cascade", CASCADE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("cascaded", CASCADED, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("case", CASE, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("cast", CAST, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("catalog", CATALOG_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("chain", CHAIN, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("char", CHAR_P, COL_NAME_KEYWORD, EXPLICIT)
+PG_KEYWORD("character", CHARACTER, COL_NAME_KEYWORD, EXPLICIT)
+PG_KEYWORD("characteristics", CHARACTERISTICS, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("check", CHECK, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("checkpoint", CHECKPOINT, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("class", CLASS, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("close", CLOSE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("cluster", CLUSTER, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("coalesce", COALESCE, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("collate", COLLATE, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("collation", COLLATION, TYPE_FUNC_NAME_KEYWORD, BARE)
+PG_KEYWORD("column", COLUMN, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("columns", COLUMNS, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("comment", COMMENT, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("comments", COMMENTS, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("commit", COMMIT, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("committed", COMMITTED, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("concurrently", CONCURRENTLY, TYPE_FUNC_NAME_KEYWORD, BARE)
+PG_KEYWORD("configuration", CONFIGURATION, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("conflict", CONFLICT, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("connection", CONNECTION, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("constraint", CONSTRAINT, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("constraints", CONSTRAINTS, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("content", CONTENT_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("continue", CONTINUE_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("conversion", CONVERSION_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("copy", COPY, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("cost", COST, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("create", CREATE, RESERVED_KEYWORD, EXPLICIT)
+PG_KEYWORD("cross", CROSS, TYPE_FUNC_NAME_KEYWORD, BARE)
+PG_KEYWORD("csv", CSV, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("cube", CUBE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("current", CURRENT_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("current_catalog", CURRENT_CATALOG, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("current_date", CURRENT_DATE, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("current_role", CURRENT_ROLE, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("current_schema", CURRENT_SCHEMA, TYPE_FUNC_NAME_KEYWORD, BARE)
+PG_KEYWORD("current_time", CURRENT_TIME, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("current_timestamp", CURRENT_TIMESTAMP, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("current_user", CURRENT_USER, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("cursor", CURSOR, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("cycle", CYCLE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("data", DATA_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("database", DATABASE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("day", DAY_P, UNRESERVED_KEYWORD, EXPLICIT)
+PG_KEYWORD("deallocate", DEALLOCATE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("dec", DEC, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("decimal", DECIMAL_P, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("declare", DECLARE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("default", DEFAULT, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("defaults", DEFAULTS, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("deferrable", DEFERRABLE, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("deferred", DEFERRED, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("definer", DEFINER, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("delete", DELETE_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("delimiter", DELIMITER, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("delimiters", DELIMITERS, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("depends", DEPENDS, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("desc", DESC, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("detach", DETACH, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("dictionary", DICTIONARY, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("disable", DISABLE_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("discard", DISCARD, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("distinct", DISTINCT, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("do", DO, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("document", DOCUMENT_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("domain", DOMAIN_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("double", DOUBLE_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("drop", DROP, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("each", EACH, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("else", ELSE, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("enable", ENABLE_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("encoding", ENCODING, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("encrypted", ENCRYPTED, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("end", END_P, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("enum", ENUM_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("escape", ESCAPE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("event", EVENT, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("except", EXCEPT, RESERVED_KEYWORD, EXPLICIT)
+PG_KEYWORD("exclude", EXCLUDE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("excluding", EXCLUDING, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("exclusive", EXCLUSIVE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("execute", EXECUTE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("exists", EXISTS, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("explain", EXPLAIN, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("expression", EXPRESSION, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("extension", EXTENSION, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("external", EXTERNAL, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("extract", EXTRACT, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("false", FALSE_P, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("family", FAMILY, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("fetch", FETCH, RESERVED_KEYWORD, EXPLICIT)
+PG_KEYWORD("filter", FILTER, UNRESERVED_KEYWORD, EXPLICIT)
+PG_KEYWORD("first", FIRST_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("float", FLOAT_P, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("following", FOLLOWING, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("for", FOR, RESERVED_KEYWORD, EXPLICIT)
+PG_KEYWORD("force", FORCE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("foreign", FOREIGN, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("forward", FORWARD, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("freeze", FREEZE, TYPE_FUNC_NAME_KEYWORD, BARE)
+PG_KEYWORD("from", FROM, RESERVED_KEYWORD, EXPLICIT)
+PG_KEYWORD("full", FULL, TYPE_FUNC_NAME_KEYWORD, BARE)
+PG_KEYWORD("function", FUNCTION, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("functions", FUNCTIONS, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("generated", GENERATED, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("global", GLOBAL, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("grant", GRANT, RESERVED_KEYWORD, EXPLICIT)
+PG_KEYWORD("granted", GRANTED, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("greatest", GREATEST, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("group", GROUP_P, RESERVED_KEYWORD, EXPLICIT)
+PG_KEYWORD("grouping", GROUPING, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("groups", GROUPS, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("handler", HANDLER, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("having", HAVING, RESERVED_KEYWORD, EXPLICIT)
+PG_KEYWORD("header", HEADER_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("hold", HOLD, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("hour", HOUR_P, UNRESERVED_KEYWORD, EXPLICIT)
+PG_KEYWORD("identity", IDENTITY_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("if", IF_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("ilike", ILIKE, TYPE_FUNC_NAME_KEYWORD, BARE)
+PG_KEYWORD("immediate", IMMEDIATE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("immutable", IMMUTABLE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("implicit", IMPLICIT_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("import", IMPORT_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("in", IN_P, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("include", INCLUDE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("including", INCLUDING, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("increment", INCREMENT, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("index", INDEX, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("indexes", INDEXES, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("inherit", INHERIT, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("inherits", INHERITS, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("initially", INITIALLY, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("inline", INLINE_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("inner", INNER_P, TYPE_FUNC_NAME_KEYWORD, BARE)
+PG_KEYWORD("inout", INOUT, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("input", INPUT_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("insensitive", INSENSITIVE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("insert", INSERT, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("instead", INSTEAD, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("int", INT_P, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("integer", INTEGER, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("intersect", INTERSECT, RESERVED_KEYWORD, EXPLICIT)
+PG_KEYWORD("interval", INTERVAL, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("into", INTO, RESERVED_KEYWORD, EXPLICIT)
+PG_KEYWORD("invoker", INVOKER, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("is", IS, TYPE_FUNC_NAME_KEYWORD, BARE)
+PG_KEYWORD("isnull", ISNULL, TYPE_FUNC_NAME_KEYWORD, EXPLICIT)
+PG_KEYWORD("isolation", ISOLATION, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("join", JOIN, TYPE_FUNC_NAME_KEYWORD, BARE)
+PG_KEYWORD("key", KEY, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("label", LABEL, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("language", LANGUAGE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("large", LARGE_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("last", LAST_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("lateral", LATERAL_P, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("leading", LEADING, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("leakproof", LEAKPROOF, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("least", LEAST, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("left", LEFT, TYPE_FUNC_NAME_KEYWORD, BARE)
+PG_KEYWORD("level", LEVEL, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("like", LIKE, TYPE_FUNC_NAME_KEYWORD, BARE)
+PG_KEYWORD("limit", LIMIT, RESERVED_KEYWORD, EXPLICIT)
+PG_KEYWORD("listen", LISTEN, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("load", LOAD, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("local", LOCAL, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("localtime", LOCALTIME, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("localtimestamp", LOCALTIMESTAMP, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("location", LOCATION, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("lock", LOCK_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("locked", LOCKED, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("logged", LOGGED, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("mapping", MAPPING, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("match", MATCH, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("materialized", MATERIALIZED, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("maxvalue", MAXVALUE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("method", METHOD, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("minute", MINUTE_P, UNRESERVED_KEYWORD, EXPLICIT)
+PG_KEYWORD("minvalue", MINVALUE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("mode", MODE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("month", MONTH_P, UNRESERVED_KEYWORD, EXPLICIT)
+PG_KEYWORD("move", MOVE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("name", NAME_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("names", NAMES, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("national", NATIONAL, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("natural", NATURAL, TYPE_FUNC_NAME_KEYWORD, BARE)
+PG_KEYWORD("nchar", NCHAR, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("new", NEW, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("next", NEXT, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("nfc", NFC, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("nfd", NFD, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("nfkc", NFKC, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("nfkd", NFKD, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("no", NO, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("none", NONE, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("normalize", NORMALIZE, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("normalized", NORMALIZED, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("not", NOT, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("nothing", NOTHING, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("notify", NOTIFY, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("notnull", NOTNULL, TYPE_FUNC_NAME_KEYWORD, EXPLICIT)
+PG_KEYWORD("nowait", NOWAIT, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("null", NULL_P, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("nullif", NULLIF, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("nulls", NULLS_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("numeric", NUMERIC, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("object", OBJECT_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("of", OF, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("off", OFF, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("offset", OFFSET, RESERVED_KEYWORD, EXPLICIT)
+PG_KEYWORD("oids", OIDS, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("old", OLD, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("on", ON, RESERVED_KEYWORD, EXPLICIT)
+PG_KEYWORD("only", ONLY, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("operator", OPERATOR, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("option", OPTION, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("options", OPTIONS, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("or", OR, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("order", ORDER, RESERVED_KEYWORD, EXPLICIT)
+PG_KEYWORD("ordinality", ORDINALITY, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("others", OTHERS, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("out", OUT_P, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("outer", OUTER_P, TYPE_FUNC_NAME_KEYWORD, BARE)
+PG_KEYWORD("over", OVER, UNRESERVED_KEYWORD, EXPLICIT)
+PG_KEYWORD("overlaps", OVERLAPS, TYPE_FUNC_NAME_KEYWORD, EXPLICIT)
+PG_KEYWORD("overlay", OVERLAY, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("overriding", OVERRIDING, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("owned", OWNED, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("owner", OWNER, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("parallel", PARALLEL, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("parser", PARSER, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("partial", PARTIAL, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("partition", PARTITION, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("passing", PASSING, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("password", PASSWORD, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("placing", PLACING, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("plans", PLANS, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("policy", POLICY, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("position", POSITION, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("preceding", PRECEDING, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("precision", PRECISION, COL_NAME_KEYWORD, EXPLICIT)
+PG_KEYWORD("prepare", PREPARE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("prepared", PREPARED, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("preserve", PRESERVE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("primary", PRIMARY, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("prior", PRIOR, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("privileges", PRIVILEGES, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("procedural", PROCEDURAL, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("procedure", PROCEDURE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("procedures", PROCEDURES, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("program", PROGRAM, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("publication", PUBLICATION, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("quote", QUOTE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("range", RANGE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("read", READ, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("real", REAL, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("reassign", REASSIGN, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("recheck", RECHECK, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("recursive", RECURSIVE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("ref", REF, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("references", REFERENCES, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("referencing", REFERENCING, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("refresh", REFRESH, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("reindex", REINDEX, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("relative", RELATIVE_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("release", RELEASE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("rename", RENAME, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("repeatable", REPEATABLE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("replace", REPLACE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("replica", REPLICA, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("reset", RESET, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("restart", RESTART, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("restrict", RESTRICT, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("returning", RETURNING, RESERVED_KEYWORD, EXPLICIT)
+PG_KEYWORD("returns", RETURNS, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("revoke", REVOKE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("right", RIGHT, TYPE_FUNC_NAME_KEYWORD, BARE)
+PG_KEYWORD("role", ROLE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("rollback", ROLLBACK, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("rollup", ROLLUP, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("routine", ROUTINE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("routines", ROUTINES, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("row", ROW, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("rows", ROWS, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("rule", RULE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("savepoint", SAVEPOINT, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("schema", SCHEMA, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("schemas", SCHEMAS, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("scroll", SCROLL, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("search", SEARCH, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("second", SECOND_P, UNRESERVED_KEYWORD, EXPLICIT)
+PG_KEYWORD("security", SECURITY, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("select", SELECT, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("sequence", SEQUENCE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("sequences", SEQUENCES, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("serializable", SERIALIZABLE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("server", SERVER, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("session", SESSION, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("session_user", SESSION_USER, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("set", SET, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("setof", SETOF, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("sets", SETS, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("share", SHARE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("show", SHOW, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("similar", SIMILAR, TYPE_FUNC_NAME_KEYWORD, BARE)
+PG_KEYWORD("simple", SIMPLE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("skip", SKIP, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("smallint", SMALLINT, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("snapshot", SNAPSHOT, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("some", SOME, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("sql", SQL_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("stable", STABLE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("standalone", STANDALONE_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("start", START, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("statement", STATEMENT, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("statistics", STATISTICS, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("stdin", STDIN, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("stdout", STDOUT, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("storage", STORAGE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("stored", STORED, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("strict", STRICT_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("strip", STRIP_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("subscription", SUBSCRIPTION, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("substring", SUBSTRING, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("support", SUPPORT, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("symmetric", SYMMETRIC, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("sysid", SYSID, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("system", SYSTEM_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("table", TABLE, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("tables", TABLES, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("tablesample", TABLESAMPLE, TYPE_FUNC_NAME_KEYWORD, BARE)
+PG_KEYWORD("tablespace", TABLESPACE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("temp", TEMP, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("template", TEMPLATE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("temporary", TEMPORARY, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("text", TEXT_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("then", THEN, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("ties", TIES, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("time", TIME, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("timestamp", TIMESTAMP, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("to", TO, RESERVED_KEYWORD, EXPLICIT)
+PG_KEYWORD("trailing", TRAILING, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("transaction", TRANSACTION, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("transform", TRANSFORM, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("treat", TREAT, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("trigger", TRIGGER, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("trim", TRIM, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("true", TRUE_P, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("truncate", TRUNCATE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("trusted", TRUSTED, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("type", TYPE_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("types", TYPES_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("uescape", UESCAPE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("unbounded", UNBOUNDED, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("uncommitted", UNCOMMITTED, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("unencrypted", UNENCRYPTED, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("union", UNION, RESERVED_KEYWORD, EXPLICIT)
+PG_KEYWORD("unique", UNIQUE, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("unknown", UNKNOWN, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("unlisten", UNLISTEN, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("unlogged", UNLOGGED, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("until", UNTIL, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("update", UPDATE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("user", USER, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("using", USING, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("vacuum", VACUUM, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("valid", VALID, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("validate", VALIDATE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("validator", VALIDATOR, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("value", VALUE_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("values", VALUES, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("varchar", VARCHAR, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("variadic", VARIADIC, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("varying", VARYING, UNRESERVED_KEYWORD, EXPLICIT)
+PG_KEYWORD("verbose", VERBOSE, TYPE_FUNC_NAME_KEYWORD, BARE)
+PG_KEYWORD("version", VERSION_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("view", VIEW, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("views", VIEWS, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("volatile", VOLATILE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("when", WHEN, RESERVED_KEYWORD, BARE)
+PG_KEYWORD("where", WHERE, RESERVED_KEYWORD, EXPLICIT)
+PG_KEYWORD("whitespace", WHITESPACE_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("window", WINDOW, RESERVED_KEYWORD, EXPLICIT)
+PG_KEYWORD("with", WITH, RESERVED_KEYWORD, EXPLICIT)
+PG_KEYWORD("within", WITHIN, UNRESERVED_KEYWORD, EXPLICIT)
+PG_KEYWORD("without", WITHOUT, UNRESERVED_KEYWORD, EXPLICIT)
+PG_KEYWORD("work", WORK, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("wrapper", WRAPPER, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("write", WRITE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("xml", XML_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("xmlattributes", XMLATTRIBUTES, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("xmlconcat", XMLCONCAT, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("xmlelement", XMLELEMENT, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("xmlexists", XMLEXISTS, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("xmlforest", XMLFOREST, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("xmlnamespaces", XMLNAMESPACES, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("xmlparse", XMLPARSE, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("xmlpi", XMLPI, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("xmlroot", XMLROOT, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("xmlserialize", XMLSERIALIZE, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("xmltable", XMLTABLE, COL_NAME_KEYWORD, BARE)
+PG_KEYWORD("year", YEAR_P, UNRESERVED_KEYWORD, EXPLICIT)
+PG_KEYWORD("yes", YES_P, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("zone", ZONE, UNRESERVED_KEYWORD, BARE)
diff --git a/src/interfaces/ecpg/preproc/keywords.c b/src/interfaces/ecpg/preproc/keywords.c
index f82764aeb9..34a2f8ba2b 100644
--- a/src/interfaces/ecpg/preproc/keywords.c
+++ b/src/interfaces/ecpg/preproc/keywords.c
@@ -29,7 +29,7 @@
 #include "preproc_extern.h"
 #include "preproc.h"
 
-#define PG_KEYWORD(kwname, value, category) value,
+#define PG_KEYWORD(kwname, value, category, status) value,
 
 const uint16 SQLScanKeywordTokens[] = {
 #include "parser/kwlist.h"
-- 
2.21.1 (Apple Git-122.3)

v3-0003-Extending-function-pg_get_keywords.patchapplication/octet-stream; name=v3-0003-Extending-function-pg_get_keywords.patch; x-unix-mode=0644Download
From 5e40a17d184a999b929945505ed6969baafc950c Mon Sep 17 00:00:00 2001
From: Mark Dilger <mark.dilger@enterprisedb.com>
Date: Tue, 21 Jul 2020 15:47:22 -0700
Subject: [PATCH v3 3/3] Extending function pg_get_keywords

Adding to the return value of pg_get_keywords a fourth column
showing whether the keyword can be used as a bare column label.
---
 doc/src/sgml/func.sgml               |   5 +-
 src/backend/parser/check_keywords.pl |  10 +-
 src/backend/utils/adt/misc.c         |   9 +-
 src/include/catalog/pg_proc.dat      |   6 +-
 src/include/common/kwlookup.h        |   8 +
 src/include/parser/kwlist.h          | 900 +++++++++++++--------------
 src/tools/gen_keywordlist.pl         |  30 +-
 7 files changed, 507 insertions(+), 461 deletions(-)

diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 959f6a1c2f..34b25ce21a 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -22158,7 +22158,8 @@ 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>catdesc</parameter> <type>text</type>,
+        <parameter>bare</parameter> <type>boolean</type> )
        </para>
        <para>
         Returns a set of records describing the SQL keywords recognized by the
@@ -22170,6 +22171,8 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
         function name, or <literal>R</literal> for a fully reserved keyword.
         The <parameter>catdesc</parameter> column contains a
         possibly-localized string describing the category.
+        The <parameter>bare</parameter> column is true if the keyword can be used
+        as a bare column label, false otherwise.
        </para></entry>
       </row>
 
diff --git a/src/backend/parser/check_keywords.pl b/src/backend/parser/check_keywords.pl
index 98f50c4129..eea449259f 100644
--- a/src/backend/parser/check_keywords.pl
+++ b/src/backend/parser/check_keywords.pl
@@ -184,10 +184,10 @@ kwlist_line: while (<$kwlist>)
 		my ($kwstring) = $1;
 		my ($kwname)   = $2;
 		my ($kwcat_id) = $3;
-		my ($isbare)   = $4;
+		my ($status)   = $4;
 
-		# Check that the isbare value matches gram.y
-		if ($isbare eq 'BARE')
+		# Check that the keyword label status value matches treatment in gram.y
+		if ($status eq 'BARE_LABEL')
 		{
 			unless ($bare{$kwname})
 			{
@@ -195,7 +195,7 @@ kwlist_line: while (<$kwlist>)
 				  "'$kwstring' in kwlist.h is marked as bare, but is missing from gram.y's bare_label_keyword rule";
 			}
 		}
-		elsif ($isbare eq 'EXPLICIT')
+		elsif ($status eq 'EXPLICIT_LABEL')
 		{
 			if ($bare{$kwname})
 			{
@@ -206,7 +206,7 @@ kwlist_line: while (<$kwlist>)
 		else
 		{
 			error
-			  "'$isbare' not recognized in kwlist.h.  Expected either 'BARE' or 'EXPLICIT'";
+			  "'$status' not recognized in kwlist.h.  Expected either 'BARE_LABEL' or 'EXPLICIT_LABEL'";
 		}
 
 		# Check that the list is in alphabetical order (critical!)
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 37c23c9155..04d0b0decb 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -423,6 +423,8 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 						   CHAROID, -1, 0);
 		TupleDescInitEntry(tupdesc, (AttrNumber) 3, "catdesc",
 						   TEXTOID, -1, 0);
+		TupleDescInitEntry(tupdesc, (AttrNumber) 4, "bare",
+						   BOOLOID, -1, 0);
 
 		funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
 
@@ -433,7 +435,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 	if (funcctx->call_cntr < ScanKeywords.num_keywords)
 	{
-		char	   *values[3];
+		char	   *values[4];
 		HeapTuple	tuple;
 
 		/* cast-away-const is ugly but alternatives aren't much better */
@@ -465,6 +467,11 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 				break;
 		}
 
+		if (GetScanKeywordIsBare(funcctx->call_cntr, &ScanKeywords))
+			values[3] = unconstify(char *, (const char *)"true");
+		else
+			values[3] = unconstify(char *, (const char *)"false");
+
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
 		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 88d59fb96d..3076ce3b15 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -3678,10 +3678,10 @@
   prosrc => 'pg_get_function_arg_default' },
 
 { oid => '1686', descr => 'list of SQL keywords',
-  proname => 'pg_get_keywords', procost => '10', prorows => '400',
+  proname => 'pg_get_keywords', procost => '10', prorows => '450',
   proretset => 't', provolatile => 's', prorettype => 'record',
-  proargtypes => '', proallargtypes => '{text,char,text}',
-  proargmodes => '{o,o,o}', proargnames => '{word,catcode,catdesc}',
+  proargtypes => '', proallargtypes => '{text,char,text,bool}',
+  proargmodes => '{o,o,o,o}', proargnames => '{word,catcode,catdesc,bare}',
   prosrc => 'pg_get_keywords' },
 
 { oid => '2289', descr => 'convert generic options array to name/value table',
diff --git a/src/include/common/kwlookup.h b/src/include/common/kwlookup.h
index 9c0c7f88d8..3283695dec 100644
--- a/src/include/common/kwlookup.h
+++ b/src/include/common/kwlookup.h
@@ -26,6 +26,7 @@ typedef struct ScanKeywordList
 {
 	const char *kw_string;		/* all keywords in order, separated by \0 */
 	const uint16 *kw_offsets;	/* offsets to the start of each keyword */
+	const bool *kw_is_bare;		/* whether each keyword can be used as a bare label */
 	ScanKeywordHashFunc hash;	/* perfect hash function for keywords */
 	int			num_keywords;	/* number of keywords */
 	int			max_kw_len;		/* length of longest keyword */
@@ -41,4 +42,11 @@ GetScanKeyword(int n, const ScanKeywordList *keywords)
 	return keywords->kw_string + keywords->kw_offsets[n];
 }
 
+/* Code that wants to retrieve the bareness of the N'th keyword should use this. */
+static inline bool
+GetScanKeywordIsBare(int n, const ScanKeywordList *keywords)
+{
+	return keywords->kw_is_bare[n];
+}
+
 #endif							/* KWLOOKUP_H */
diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h
index 917e2cffa9..cdfdb65e69 100644
--- a/src/include/parser/kwlist.h
+++ b/src/include/parser/kwlist.h
@@ -25,453 +25,453 @@
  */
 
 /* name, value, category, is bare */
-PG_KEYWORD("abort", ABORT_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("absolute", ABSOLUTE_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("access", ACCESS, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("action", ACTION, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("add", ADD_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("admin", ADMIN, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("after", AFTER, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("aggregate", AGGREGATE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("all", ALL, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("also", ALSO, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("alter", ALTER, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("always", ALWAYS, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("analyse", ANALYSE, RESERVED_KEYWORD, BARE)		/* British spelling */
-PG_KEYWORD("analyze", ANALYZE, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("and", AND, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("any", ANY, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("array", ARRAY, RESERVED_KEYWORD, EXPLICIT)
-PG_KEYWORD("as", AS, RESERVED_KEYWORD, EXPLICIT)
-PG_KEYWORD("asc", ASC, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("assertion", ASSERTION, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("assignment", ASSIGNMENT, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("asymmetric", ASYMMETRIC, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("at", AT, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("attach", ATTACH, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("attribute", ATTRIBUTE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("authorization", AUTHORIZATION, TYPE_FUNC_NAME_KEYWORD, BARE)
-PG_KEYWORD("backward", BACKWARD, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("before", BEFORE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("begin", BEGIN_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("between", BETWEEN, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("bigint", BIGINT, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("binary", BINARY, TYPE_FUNC_NAME_KEYWORD, BARE)
-PG_KEYWORD("bit", BIT, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("boolean", BOOLEAN_P, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("both", BOTH, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("by", BY, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("cache", CACHE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("call", CALL, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("called", CALLED, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("cascade", CASCADE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("cascaded", CASCADED, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("case", CASE, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("cast", CAST, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("catalog", CATALOG_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("chain", CHAIN, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("char", CHAR_P, COL_NAME_KEYWORD, EXPLICIT)
-PG_KEYWORD("character", CHARACTER, COL_NAME_KEYWORD, EXPLICIT)
-PG_KEYWORD("characteristics", CHARACTERISTICS, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("check", CHECK, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("checkpoint", CHECKPOINT, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("class", CLASS, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("close", CLOSE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("cluster", CLUSTER, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("coalesce", COALESCE, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("collate", COLLATE, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("collation", COLLATION, TYPE_FUNC_NAME_KEYWORD, BARE)
-PG_KEYWORD("column", COLUMN, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("columns", COLUMNS, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("comment", COMMENT, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("comments", COMMENTS, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("commit", COMMIT, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("committed", COMMITTED, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("concurrently", CONCURRENTLY, TYPE_FUNC_NAME_KEYWORD, BARE)
-PG_KEYWORD("configuration", CONFIGURATION, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("conflict", CONFLICT, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("connection", CONNECTION, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("constraint", CONSTRAINT, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("constraints", CONSTRAINTS, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("content", CONTENT_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("continue", CONTINUE_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("conversion", CONVERSION_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("copy", COPY, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("cost", COST, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("create", CREATE, RESERVED_KEYWORD, EXPLICIT)
-PG_KEYWORD("cross", CROSS, TYPE_FUNC_NAME_KEYWORD, BARE)
-PG_KEYWORD("csv", CSV, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("cube", CUBE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("current", CURRENT_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("current_catalog", CURRENT_CATALOG, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("current_date", CURRENT_DATE, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("current_role", CURRENT_ROLE, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("current_schema", CURRENT_SCHEMA, TYPE_FUNC_NAME_KEYWORD, BARE)
-PG_KEYWORD("current_time", CURRENT_TIME, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("current_timestamp", CURRENT_TIMESTAMP, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("current_user", CURRENT_USER, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("cursor", CURSOR, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("cycle", CYCLE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("data", DATA_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("database", DATABASE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("day", DAY_P, UNRESERVED_KEYWORD, EXPLICIT)
-PG_KEYWORD("deallocate", DEALLOCATE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("dec", DEC, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("decimal", DECIMAL_P, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("declare", DECLARE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("default", DEFAULT, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("defaults", DEFAULTS, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("deferrable", DEFERRABLE, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("deferred", DEFERRED, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("definer", DEFINER, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("delete", DELETE_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("delimiter", DELIMITER, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("delimiters", DELIMITERS, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("depends", DEPENDS, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("desc", DESC, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("detach", DETACH, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("dictionary", DICTIONARY, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("disable", DISABLE_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("discard", DISCARD, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("distinct", DISTINCT, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("do", DO, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("document", DOCUMENT_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("domain", DOMAIN_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("double", DOUBLE_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("drop", DROP, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("each", EACH, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("else", ELSE, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("enable", ENABLE_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("encoding", ENCODING, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("encrypted", ENCRYPTED, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("end", END_P, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("enum", ENUM_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("escape", ESCAPE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("event", EVENT, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("except", EXCEPT, RESERVED_KEYWORD, EXPLICIT)
-PG_KEYWORD("exclude", EXCLUDE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("excluding", EXCLUDING, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("exclusive", EXCLUSIVE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("execute", EXECUTE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("exists", EXISTS, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("explain", EXPLAIN, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("expression", EXPRESSION, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("extension", EXTENSION, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("external", EXTERNAL, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("extract", EXTRACT, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("false", FALSE_P, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("family", FAMILY, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("fetch", FETCH, RESERVED_KEYWORD, EXPLICIT)
-PG_KEYWORD("filter", FILTER, UNRESERVED_KEYWORD, EXPLICIT)
-PG_KEYWORD("first", FIRST_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("float", FLOAT_P, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("following", FOLLOWING, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("for", FOR, RESERVED_KEYWORD, EXPLICIT)
-PG_KEYWORD("force", FORCE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("foreign", FOREIGN, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("forward", FORWARD, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("freeze", FREEZE, TYPE_FUNC_NAME_KEYWORD, BARE)
-PG_KEYWORD("from", FROM, RESERVED_KEYWORD, EXPLICIT)
-PG_KEYWORD("full", FULL, TYPE_FUNC_NAME_KEYWORD, BARE)
-PG_KEYWORD("function", FUNCTION, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("functions", FUNCTIONS, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("generated", GENERATED, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("global", GLOBAL, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("grant", GRANT, RESERVED_KEYWORD, EXPLICIT)
-PG_KEYWORD("granted", GRANTED, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("greatest", GREATEST, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("group", GROUP_P, RESERVED_KEYWORD, EXPLICIT)
-PG_KEYWORD("grouping", GROUPING, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("groups", GROUPS, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("handler", HANDLER, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("having", HAVING, RESERVED_KEYWORD, EXPLICIT)
-PG_KEYWORD("header", HEADER_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("hold", HOLD, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("hour", HOUR_P, UNRESERVED_KEYWORD, EXPLICIT)
-PG_KEYWORD("identity", IDENTITY_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("if", IF_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("ilike", ILIKE, TYPE_FUNC_NAME_KEYWORD, BARE)
-PG_KEYWORD("immediate", IMMEDIATE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("immutable", IMMUTABLE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("implicit", IMPLICIT_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("import", IMPORT_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("in", IN_P, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("include", INCLUDE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("including", INCLUDING, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("increment", INCREMENT, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("index", INDEX, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("indexes", INDEXES, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("inherit", INHERIT, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("inherits", INHERITS, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("initially", INITIALLY, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("inline", INLINE_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("inner", INNER_P, TYPE_FUNC_NAME_KEYWORD, BARE)
-PG_KEYWORD("inout", INOUT, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("input", INPUT_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("insensitive", INSENSITIVE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("insert", INSERT, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("instead", INSTEAD, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("int", INT_P, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("integer", INTEGER, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("intersect", INTERSECT, RESERVED_KEYWORD, EXPLICIT)
-PG_KEYWORD("interval", INTERVAL, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("into", INTO, RESERVED_KEYWORD, EXPLICIT)
-PG_KEYWORD("invoker", INVOKER, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("is", IS, TYPE_FUNC_NAME_KEYWORD, BARE)
-PG_KEYWORD("isnull", ISNULL, TYPE_FUNC_NAME_KEYWORD, EXPLICIT)
-PG_KEYWORD("isolation", ISOLATION, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("join", JOIN, TYPE_FUNC_NAME_KEYWORD, BARE)
-PG_KEYWORD("key", KEY, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("label", LABEL, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("language", LANGUAGE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("large", LARGE_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("last", LAST_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("lateral", LATERAL_P, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("leading", LEADING, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("leakproof", LEAKPROOF, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("least", LEAST, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("left", LEFT, TYPE_FUNC_NAME_KEYWORD, BARE)
-PG_KEYWORD("level", LEVEL, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("like", LIKE, TYPE_FUNC_NAME_KEYWORD, BARE)
-PG_KEYWORD("limit", LIMIT, RESERVED_KEYWORD, EXPLICIT)
-PG_KEYWORD("listen", LISTEN, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("load", LOAD, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("local", LOCAL, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("localtime", LOCALTIME, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("localtimestamp", LOCALTIMESTAMP, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("location", LOCATION, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("lock", LOCK_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("locked", LOCKED, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("logged", LOGGED, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("mapping", MAPPING, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("match", MATCH, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("materialized", MATERIALIZED, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("maxvalue", MAXVALUE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("method", METHOD, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("minute", MINUTE_P, UNRESERVED_KEYWORD, EXPLICIT)
-PG_KEYWORD("minvalue", MINVALUE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("mode", MODE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("month", MONTH_P, UNRESERVED_KEYWORD, EXPLICIT)
-PG_KEYWORD("move", MOVE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("name", NAME_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("names", NAMES, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("national", NATIONAL, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("natural", NATURAL, TYPE_FUNC_NAME_KEYWORD, BARE)
-PG_KEYWORD("nchar", NCHAR, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("new", NEW, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("next", NEXT, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("nfc", NFC, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("nfd", NFD, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("nfkc", NFKC, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("nfkd", NFKD, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("no", NO, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("none", NONE, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("normalize", NORMALIZE, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("normalized", NORMALIZED, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("not", NOT, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("nothing", NOTHING, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("notify", NOTIFY, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("notnull", NOTNULL, TYPE_FUNC_NAME_KEYWORD, EXPLICIT)
-PG_KEYWORD("nowait", NOWAIT, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("null", NULL_P, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("nullif", NULLIF, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("nulls", NULLS_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("numeric", NUMERIC, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("object", OBJECT_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("of", OF, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("off", OFF, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("offset", OFFSET, RESERVED_KEYWORD, EXPLICIT)
-PG_KEYWORD("oids", OIDS, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("old", OLD, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("on", ON, RESERVED_KEYWORD, EXPLICIT)
-PG_KEYWORD("only", ONLY, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("operator", OPERATOR, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("option", OPTION, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("options", OPTIONS, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("or", OR, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("order", ORDER, RESERVED_KEYWORD, EXPLICIT)
-PG_KEYWORD("ordinality", ORDINALITY, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("others", OTHERS, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("out", OUT_P, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("outer", OUTER_P, TYPE_FUNC_NAME_KEYWORD, BARE)
-PG_KEYWORD("over", OVER, UNRESERVED_KEYWORD, EXPLICIT)
-PG_KEYWORD("overlaps", OVERLAPS, TYPE_FUNC_NAME_KEYWORD, EXPLICIT)
-PG_KEYWORD("overlay", OVERLAY, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("overriding", OVERRIDING, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("owned", OWNED, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("owner", OWNER, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("parallel", PARALLEL, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("parser", PARSER, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("partial", PARTIAL, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("partition", PARTITION, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("passing", PASSING, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("password", PASSWORD, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("placing", PLACING, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("plans", PLANS, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("policy", POLICY, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("position", POSITION, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("preceding", PRECEDING, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("precision", PRECISION, COL_NAME_KEYWORD, EXPLICIT)
-PG_KEYWORD("prepare", PREPARE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("prepared", PREPARED, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("preserve", PRESERVE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("primary", PRIMARY, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("prior", PRIOR, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("privileges", PRIVILEGES, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("procedural", PROCEDURAL, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("procedure", PROCEDURE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("procedures", PROCEDURES, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("program", PROGRAM, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("publication", PUBLICATION, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("quote", QUOTE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("range", RANGE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("read", READ, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("real", REAL, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("reassign", REASSIGN, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("recheck", RECHECK, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("recursive", RECURSIVE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("ref", REF, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("references", REFERENCES, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("referencing", REFERENCING, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("refresh", REFRESH, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("reindex", REINDEX, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("relative", RELATIVE_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("release", RELEASE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("rename", RENAME, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("repeatable", REPEATABLE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("replace", REPLACE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("replica", REPLICA, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("reset", RESET, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("restart", RESTART, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("restrict", RESTRICT, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("returning", RETURNING, RESERVED_KEYWORD, EXPLICIT)
-PG_KEYWORD("returns", RETURNS, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("revoke", REVOKE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("right", RIGHT, TYPE_FUNC_NAME_KEYWORD, BARE)
-PG_KEYWORD("role", ROLE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("rollback", ROLLBACK, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("rollup", ROLLUP, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("routine", ROUTINE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("routines", ROUTINES, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("row", ROW, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("rows", ROWS, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("rule", RULE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("savepoint", SAVEPOINT, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("schema", SCHEMA, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("schemas", SCHEMAS, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("scroll", SCROLL, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("search", SEARCH, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("second", SECOND_P, UNRESERVED_KEYWORD, EXPLICIT)
-PG_KEYWORD("security", SECURITY, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("select", SELECT, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("sequence", SEQUENCE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("sequences", SEQUENCES, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("serializable", SERIALIZABLE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("server", SERVER, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("session", SESSION, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("session_user", SESSION_USER, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("set", SET, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("setof", SETOF, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("sets", SETS, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("share", SHARE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("show", SHOW, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("similar", SIMILAR, TYPE_FUNC_NAME_KEYWORD, BARE)
-PG_KEYWORD("simple", SIMPLE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("skip", SKIP, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("smallint", SMALLINT, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("snapshot", SNAPSHOT, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("some", SOME, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("sql", SQL_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("stable", STABLE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("standalone", STANDALONE_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("start", START, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("statement", STATEMENT, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("statistics", STATISTICS, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("stdin", STDIN, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("stdout", STDOUT, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("storage", STORAGE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("stored", STORED, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("strict", STRICT_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("strip", STRIP_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("subscription", SUBSCRIPTION, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("substring", SUBSTRING, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("support", SUPPORT, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("symmetric", SYMMETRIC, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("sysid", SYSID, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("system", SYSTEM_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("table", TABLE, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("tables", TABLES, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("tablesample", TABLESAMPLE, TYPE_FUNC_NAME_KEYWORD, BARE)
-PG_KEYWORD("tablespace", TABLESPACE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("temp", TEMP, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("template", TEMPLATE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("temporary", TEMPORARY, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("text", TEXT_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("then", THEN, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("ties", TIES, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("time", TIME, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("timestamp", TIMESTAMP, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("to", TO, RESERVED_KEYWORD, EXPLICIT)
-PG_KEYWORD("trailing", TRAILING, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("transaction", TRANSACTION, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("transform", TRANSFORM, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("treat", TREAT, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("trigger", TRIGGER, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("trim", TRIM, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("true", TRUE_P, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("truncate", TRUNCATE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("trusted", TRUSTED, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("type", TYPE_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("types", TYPES_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("uescape", UESCAPE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("unbounded", UNBOUNDED, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("uncommitted", UNCOMMITTED, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("unencrypted", UNENCRYPTED, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("union", UNION, RESERVED_KEYWORD, EXPLICIT)
-PG_KEYWORD("unique", UNIQUE, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("unknown", UNKNOWN, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("unlisten", UNLISTEN, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("unlogged", UNLOGGED, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("until", UNTIL, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("update", UPDATE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("user", USER, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("using", USING, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("vacuum", VACUUM, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("valid", VALID, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("validate", VALIDATE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("validator", VALIDATOR, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("value", VALUE_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("values", VALUES, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("varchar", VARCHAR, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("variadic", VARIADIC, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("varying", VARYING, UNRESERVED_KEYWORD, EXPLICIT)
-PG_KEYWORD("verbose", VERBOSE, TYPE_FUNC_NAME_KEYWORD, BARE)
-PG_KEYWORD("version", VERSION_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("view", VIEW, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("views", VIEWS, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("volatile", VOLATILE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("when", WHEN, RESERVED_KEYWORD, BARE)
-PG_KEYWORD("where", WHERE, RESERVED_KEYWORD, EXPLICIT)
-PG_KEYWORD("whitespace", WHITESPACE_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("window", WINDOW, RESERVED_KEYWORD, EXPLICIT)
-PG_KEYWORD("with", WITH, RESERVED_KEYWORD, EXPLICIT)
-PG_KEYWORD("within", WITHIN, UNRESERVED_KEYWORD, EXPLICIT)
-PG_KEYWORD("without", WITHOUT, UNRESERVED_KEYWORD, EXPLICIT)
-PG_KEYWORD("work", WORK, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("wrapper", WRAPPER, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("write", WRITE, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("xml", XML_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("xmlattributes", XMLATTRIBUTES, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("xmlconcat", XMLCONCAT, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("xmlelement", XMLELEMENT, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("xmlexists", XMLEXISTS, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("xmlforest", XMLFOREST, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("xmlnamespaces", XMLNAMESPACES, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("xmlparse", XMLPARSE, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("xmlpi", XMLPI, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("xmlroot", XMLROOT, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("xmlserialize", XMLSERIALIZE, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("xmltable", XMLTABLE, COL_NAME_KEYWORD, BARE)
-PG_KEYWORD("year", YEAR_P, UNRESERVED_KEYWORD, EXPLICIT)
-PG_KEYWORD("yes", YES_P, UNRESERVED_KEYWORD, BARE)
-PG_KEYWORD("zone", ZONE, UNRESERVED_KEYWORD, BARE)
+PG_KEYWORD("abort", ABORT_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("absolute", ABSOLUTE_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("access", ACCESS, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("action", ACTION, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("add", ADD_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("admin", ADMIN, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("after", AFTER, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("aggregate", AGGREGATE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("all", ALL, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("also", ALSO, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("alter", ALTER, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("always", ALWAYS, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("analyse", ANALYSE, RESERVED_KEYWORD, BARE_LABEL)		/* British spelling */
+PG_KEYWORD("analyze", ANALYZE, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("and", AND, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("any", ANY, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("array", ARRAY, RESERVED_KEYWORD, EXPLICIT_LABEL)
+PG_KEYWORD("as", AS, RESERVED_KEYWORD, EXPLICIT_LABEL)
+PG_KEYWORD("asc", ASC, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("assertion", ASSERTION, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("assignment", ASSIGNMENT, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("asymmetric", ASYMMETRIC, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("at", AT, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("attach", ATTACH, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("attribute", ATTRIBUTE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("authorization", AUTHORIZATION, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("backward", BACKWARD, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("before", BEFORE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("begin", BEGIN_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("between", BETWEEN, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("bigint", BIGINT, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("binary", BINARY, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("bit", BIT, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("boolean", BOOLEAN_P, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("both", BOTH, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("by", BY, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("cache", CACHE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("call", CALL, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("called", CALLED, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("cascade", CASCADE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("cascaded", CASCADED, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("case", CASE, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("cast", CAST, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("catalog", CATALOG_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("chain", CHAIN, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("char", CHAR_P, COL_NAME_KEYWORD, EXPLICIT_LABEL)
+PG_KEYWORD("character", CHARACTER, COL_NAME_KEYWORD, EXPLICIT_LABEL)
+PG_KEYWORD("characteristics", CHARACTERISTICS, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("check", CHECK, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("checkpoint", CHECKPOINT, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("class", CLASS, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("close", CLOSE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("cluster", CLUSTER, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("coalesce", COALESCE, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("collate", COLLATE, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("collation", COLLATION, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("column", COLUMN, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("columns", COLUMNS, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("comment", COMMENT, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("comments", COMMENTS, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("commit", COMMIT, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("committed", COMMITTED, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("concurrently", CONCURRENTLY, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("configuration", CONFIGURATION, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("conflict", CONFLICT, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("connection", CONNECTION, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("constraint", CONSTRAINT, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("constraints", CONSTRAINTS, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("content", CONTENT_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("continue", CONTINUE_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("conversion", CONVERSION_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("copy", COPY, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("cost", COST, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("create", CREATE, RESERVED_KEYWORD, EXPLICIT_LABEL)
+PG_KEYWORD("cross", CROSS, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("csv", CSV, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("cube", CUBE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("current", CURRENT_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("current_catalog", CURRENT_CATALOG, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("current_date", CURRENT_DATE, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("current_role", CURRENT_ROLE, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("current_schema", CURRENT_SCHEMA, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("current_time", CURRENT_TIME, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("current_timestamp", CURRENT_TIMESTAMP, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("current_user", CURRENT_USER, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("cursor", CURSOR, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("cycle", CYCLE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("data", DATA_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("database", DATABASE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("day", DAY_P, UNRESERVED_KEYWORD, EXPLICIT_LABEL)
+PG_KEYWORD("deallocate", DEALLOCATE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("dec", DEC, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("decimal", DECIMAL_P, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("declare", DECLARE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("default", DEFAULT, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("defaults", DEFAULTS, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("deferrable", DEFERRABLE, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("deferred", DEFERRED, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("definer", DEFINER, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("delete", DELETE_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("delimiter", DELIMITER, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("delimiters", DELIMITERS, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("depends", DEPENDS, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("desc", DESC, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("detach", DETACH, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("dictionary", DICTIONARY, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("disable", DISABLE_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("discard", DISCARD, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("distinct", DISTINCT, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("do", DO, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("document", DOCUMENT_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("domain", DOMAIN_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("double", DOUBLE_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("drop", DROP, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("each", EACH, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("else", ELSE, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("enable", ENABLE_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("encoding", ENCODING, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("encrypted", ENCRYPTED, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("end", END_P, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("enum", ENUM_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("escape", ESCAPE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("event", EVENT, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("except", EXCEPT, RESERVED_KEYWORD, EXPLICIT_LABEL)
+PG_KEYWORD("exclude", EXCLUDE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("excluding", EXCLUDING, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("exclusive", EXCLUSIVE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("execute", EXECUTE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("exists", EXISTS, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("explain", EXPLAIN, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("expression", EXPRESSION, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("extension", EXTENSION, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("external", EXTERNAL, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("extract", EXTRACT, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("false", FALSE_P, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("family", FAMILY, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("fetch", FETCH, RESERVED_KEYWORD, EXPLICIT_LABEL)
+PG_KEYWORD("filter", FILTER, UNRESERVED_KEYWORD, EXPLICIT_LABEL)
+PG_KEYWORD("first", FIRST_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("float", FLOAT_P, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("following", FOLLOWING, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("for", FOR, RESERVED_KEYWORD, EXPLICIT_LABEL)
+PG_KEYWORD("force", FORCE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("foreign", FOREIGN, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("forward", FORWARD, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("freeze", FREEZE, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("from", FROM, RESERVED_KEYWORD, EXPLICIT_LABEL)
+PG_KEYWORD("full", FULL, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("function", FUNCTION, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("functions", FUNCTIONS, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("generated", GENERATED, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("global", GLOBAL, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("grant", GRANT, RESERVED_KEYWORD, EXPLICIT_LABEL)
+PG_KEYWORD("granted", GRANTED, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("greatest", GREATEST, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("group", GROUP_P, RESERVED_KEYWORD, EXPLICIT_LABEL)
+PG_KEYWORD("grouping", GROUPING, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("groups", GROUPS, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("handler", HANDLER, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("having", HAVING, RESERVED_KEYWORD, EXPLICIT_LABEL)
+PG_KEYWORD("header", HEADER_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("hold", HOLD, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("hour", HOUR_P, UNRESERVED_KEYWORD, EXPLICIT_LABEL)
+PG_KEYWORD("identity", IDENTITY_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("if", IF_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("ilike", ILIKE, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("immediate", IMMEDIATE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("immutable", IMMUTABLE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("implicit", IMPLICIT_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("import", IMPORT_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("in", IN_P, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("include", INCLUDE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("including", INCLUDING, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("increment", INCREMENT, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("index", INDEX, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("indexes", INDEXES, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("inherit", INHERIT, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("inherits", INHERITS, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("initially", INITIALLY, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("inline", INLINE_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("inner", INNER_P, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("inout", INOUT, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("input", INPUT_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("insensitive", INSENSITIVE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("insert", INSERT, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("instead", INSTEAD, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("int", INT_P, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("integer", INTEGER, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("intersect", INTERSECT, RESERVED_KEYWORD, EXPLICIT_LABEL)
+PG_KEYWORD("interval", INTERVAL, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("into", INTO, RESERVED_KEYWORD, EXPLICIT_LABEL)
+PG_KEYWORD("invoker", INVOKER, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("is", IS, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("isnull", ISNULL, TYPE_FUNC_NAME_KEYWORD, EXPLICIT_LABEL)
+PG_KEYWORD("isolation", ISOLATION, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("join", JOIN, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("key", KEY, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("label", LABEL, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("language", LANGUAGE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("large", LARGE_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("last", LAST_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("lateral", LATERAL_P, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("leading", LEADING, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("leakproof", LEAKPROOF, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("least", LEAST, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("left", LEFT, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("level", LEVEL, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("like", LIKE, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("limit", LIMIT, RESERVED_KEYWORD, EXPLICIT_LABEL)
+PG_KEYWORD("listen", LISTEN, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("load", LOAD, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("local", LOCAL, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("localtime", LOCALTIME, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("localtimestamp", LOCALTIMESTAMP, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("location", LOCATION, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("lock", LOCK_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("locked", LOCKED, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("logged", LOGGED, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("mapping", MAPPING, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("match", MATCH, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("materialized", MATERIALIZED, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("maxvalue", MAXVALUE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("method", METHOD, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("minute", MINUTE_P, UNRESERVED_KEYWORD, EXPLICIT_LABEL)
+PG_KEYWORD("minvalue", MINVALUE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("mode", MODE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("month", MONTH_P, UNRESERVED_KEYWORD, EXPLICIT_LABEL)
+PG_KEYWORD("move", MOVE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("name", NAME_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("names", NAMES, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("national", NATIONAL, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("natural", NATURAL, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("nchar", NCHAR, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("new", NEW, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("next", NEXT, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("nfc", NFC, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("nfd", NFD, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("nfkc", NFKC, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("nfkd", NFKD, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("no", NO, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("none", NONE, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("normalize", NORMALIZE, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("normalized", NORMALIZED, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("not", NOT, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("nothing", NOTHING, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("notify", NOTIFY, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("notnull", NOTNULL, TYPE_FUNC_NAME_KEYWORD, EXPLICIT_LABEL)
+PG_KEYWORD("nowait", NOWAIT, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("null", NULL_P, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("nullif", NULLIF, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("nulls", NULLS_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("numeric", NUMERIC, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("object", OBJECT_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("of", OF, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("off", OFF, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("offset", OFFSET, RESERVED_KEYWORD, EXPLICIT_LABEL)
+PG_KEYWORD("oids", OIDS, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("old", OLD, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("on", ON, RESERVED_KEYWORD, EXPLICIT_LABEL)
+PG_KEYWORD("only", ONLY, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("operator", OPERATOR, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("option", OPTION, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("options", OPTIONS, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("or", OR, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("order", ORDER, RESERVED_KEYWORD, EXPLICIT_LABEL)
+PG_KEYWORD("ordinality", ORDINALITY, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("others", OTHERS, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("out", OUT_P, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("outer", OUTER_P, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("over", OVER, UNRESERVED_KEYWORD, EXPLICIT_LABEL)
+PG_KEYWORD("overlaps", OVERLAPS, TYPE_FUNC_NAME_KEYWORD, EXPLICIT_LABEL)
+PG_KEYWORD("overlay", OVERLAY, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("overriding", OVERRIDING, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("owned", OWNED, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("owner", OWNER, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("parallel", PARALLEL, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("parser", PARSER, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("partial", PARTIAL, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("partition", PARTITION, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("passing", PASSING, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("password", PASSWORD, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("placing", PLACING, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("plans", PLANS, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("policy", POLICY, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("position", POSITION, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("preceding", PRECEDING, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("precision", PRECISION, COL_NAME_KEYWORD, EXPLICIT_LABEL)
+PG_KEYWORD("prepare", PREPARE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("prepared", PREPARED, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("preserve", PRESERVE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("primary", PRIMARY, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("prior", PRIOR, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("privileges", PRIVILEGES, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("procedural", PROCEDURAL, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("procedure", PROCEDURE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("procedures", PROCEDURES, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("program", PROGRAM, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("publication", PUBLICATION, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("quote", QUOTE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("range", RANGE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("read", READ, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("real", REAL, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("reassign", REASSIGN, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("recheck", RECHECK, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("recursive", RECURSIVE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("ref", REF, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("references", REFERENCES, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("referencing", REFERENCING, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("refresh", REFRESH, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("reindex", REINDEX, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("relative", RELATIVE_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("release", RELEASE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("rename", RENAME, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("repeatable", REPEATABLE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("replace", REPLACE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("replica", REPLICA, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("reset", RESET, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("restart", RESTART, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("restrict", RESTRICT, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("returning", RETURNING, RESERVED_KEYWORD, EXPLICIT_LABEL)
+PG_KEYWORD("returns", RETURNS, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("revoke", REVOKE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("right", RIGHT, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("role", ROLE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("rollback", ROLLBACK, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("rollup", ROLLUP, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("routine", ROUTINE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("routines", ROUTINES, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("row", ROW, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("rows", ROWS, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("rule", RULE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("savepoint", SAVEPOINT, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("schema", SCHEMA, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("schemas", SCHEMAS, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("scroll", SCROLL, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("search", SEARCH, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("second", SECOND_P, UNRESERVED_KEYWORD, EXPLICIT_LABEL)
+PG_KEYWORD("security", SECURITY, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("select", SELECT, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("sequence", SEQUENCE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("sequences", SEQUENCES, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("serializable", SERIALIZABLE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("server", SERVER, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("session", SESSION, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("session_user", SESSION_USER, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("set", SET, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("setof", SETOF, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("sets", SETS, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("share", SHARE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("show", SHOW, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("similar", SIMILAR, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("simple", SIMPLE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("skip", SKIP, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("smallint", SMALLINT, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("snapshot", SNAPSHOT, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("some", SOME, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("sql", SQL_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("stable", STABLE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("standalone", STANDALONE_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("start", START, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("statement", STATEMENT, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("statistics", STATISTICS, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("stdin", STDIN, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("stdout", STDOUT, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("storage", STORAGE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("stored", STORED, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("strict", STRICT_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("strip", STRIP_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("subscription", SUBSCRIPTION, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("substring", SUBSTRING, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("support", SUPPORT, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("symmetric", SYMMETRIC, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("sysid", SYSID, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("system", SYSTEM_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("table", TABLE, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("tables", TABLES, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("tablesample", TABLESAMPLE, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("tablespace", TABLESPACE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("temp", TEMP, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("template", TEMPLATE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("temporary", TEMPORARY, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("text", TEXT_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("then", THEN, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("ties", TIES, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("time", TIME, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("timestamp", TIMESTAMP, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("to", TO, RESERVED_KEYWORD, EXPLICIT_LABEL)
+PG_KEYWORD("trailing", TRAILING, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("transaction", TRANSACTION, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("transform", TRANSFORM, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("treat", TREAT, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("trigger", TRIGGER, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("trim", TRIM, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("true", TRUE_P, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("truncate", TRUNCATE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("trusted", TRUSTED, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("type", TYPE_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("types", TYPES_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("uescape", UESCAPE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("unbounded", UNBOUNDED, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("uncommitted", UNCOMMITTED, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("unencrypted", UNENCRYPTED, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("union", UNION, RESERVED_KEYWORD, EXPLICIT_LABEL)
+PG_KEYWORD("unique", UNIQUE, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("unknown", UNKNOWN, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("unlisten", UNLISTEN, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("unlogged", UNLOGGED, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("until", UNTIL, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("update", UPDATE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("user", USER, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("using", USING, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("vacuum", VACUUM, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("valid", VALID, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("validate", VALIDATE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("validator", VALIDATOR, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("value", VALUE_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("values", VALUES, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("varchar", VARCHAR, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("variadic", VARIADIC, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("varying", VARYING, UNRESERVED_KEYWORD, EXPLICIT_LABEL)
+PG_KEYWORD("verbose", VERBOSE, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("version", VERSION_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("view", VIEW, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("views", VIEWS, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("volatile", VOLATILE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("when", WHEN, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("where", WHERE, RESERVED_KEYWORD, EXPLICIT_LABEL)
+PG_KEYWORD("whitespace", WHITESPACE_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("window", WINDOW, RESERVED_KEYWORD, EXPLICIT_LABEL)
+PG_KEYWORD("with", WITH, RESERVED_KEYWORD, EXPLICIT_LABEL)
+PG_KEYWORD("within", WITHIN, UNRESERVED_KEYWORD, EXPLICIT_LABEL)
+PG_KEYWORD("without", WITHOUT, UNRESERVED_KEYWORD, EXPLICIT_LABEL)
+PG_KEYWORD("work", WORK, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("wrapper", WRAPPER, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("write", WRITE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("xml", XML_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("xmlattributes", XMLATTRIBUTES, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("xmlconcat", XMLCONCAT, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("xmlelement", XMLELEMENT, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("xmlexists", XMLEXISTS, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("xmlforest", XMLFOREST, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("xmlnamespaces", XMLNAMESPACES, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("xmlparse", XMLPARSE, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("xmlpi", XMLPI, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("xmlroot", XMLROOT, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("xmlserialize", XMLSERIALIZE, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("xmltable", XMLTABLE, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("year", YEAR_P, UNRESERVED_KEYWORD, EXPLICIT_LABEL)
+PG_KEYWORD("yes", YES_P, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("zone", ZONE, UNRESERVED_KEYWORD, BARE_LABEL)
diff --git a/src/tools/gen_keywordlist.pl b/src/tools/gen_keywordlist.pl
index e9250b8fb2..c321af8fd1 100644
--- a/src/tools/gen_keywordlist.pl
+++ b/src/tools/gen_keywordlist.pl
@@ -93,11 +93,27 @@ EOM
 
 # Parse input file for keyword names.
 my @keywords;
+my @bare;
+my %transform = ( BARE_LABEL => 'true', EXPLICIT_LABEL => 'false');
 while (<$kif>)
 {
 	if (/^PG_KEYWORD\("(\w+)"/)
 	{
-		push @keywords, $1;
+		my $kword = $1;
+		push @keywords, $kword;
+
+		if (/^PG_KEYWORD\("\w+", .*, (BARE_LABEL|EXPLICIT_LABEL)\)/)
+		{
+			push @bare, $transform{$1};
+		}
+		else
+		{
+			# parser/kwlist.h lists each keyword as either bare or
+			# explicit, but ecpg neither needs nor has any such
+			# distintion.  It really doesn't matter what we use here
+			# as long as it is a valid boolean, so we use 'true'.
+			push @bare, 'true';
+		}
 	}
 }
 
@@ -153,6 +169,17 @@ foreach my $name (@keywords)
 
 print $kwdef "};\n\n";
 
+# Emit an array of boolean is bare values
+
+printf $kwdef "static const bool %s_kw_is_bare[] = {\n", $varname;
+
+foreach my $bool (@bare)
+{
+	print $kwdef "\t$bool,\n";
+}
+
+print $kwdef "};\n\n";
+
 # Emit a macro defining the number of keywords.
 # (In some places it's useful to have access to that as a constant.)
 
@@ -173,6 +200,7 @@ printf $kwdef "static " if !$extern;
 printf $kwdef "const ScanKeywordList %s = {\n", $varname;
 printf $kwdef qq|\t%s_kw_string,\n|,            $varname;
 printf $kwdef qq|\t%s_kw_offsets,\n|,           $varname;
+printf $kwdef qq|\t%s_kw_is_bare,\n|,           $varname;
 printf $kwdef qq|\t%s,\n|,                      $funcname;
 printf $kwdef qq|\t%s_NUM_KEYWORDS,\n|,         uc $varname;
 printf $kwdef qq|\t%d\n|,                       $max_len;
-- 
2.21.1 (Apple Git-122.3)

#35John Naylor
john.naylor@2ndquadrant.com
In reply to: Mark Dilger (#34)
Re: factorial function/phase out postfix operators?

On Wed, Jul 22, 2020 at 8:47 AM Mark Dilger
<mark.dilger@enterprisedb.com> wrote:

On Jul 18, 2020, at 1:00 AM, John Naylor <john.naylor@2ndquadrant.com> wrote:

pg_get_keywords() should probably have a column to display ability to
act as a bare col label. Perhaps a boolean? If so, what do you think
of using true/false for the new field in kwlist.h as well?

Hi Mark, sorry for the delay.

I have broken this into its own patch. I like using a BARE_LABEL / EXPLICIT_LABEL in kwlist.h because it is self-documenting. I don't care about the *exact* strings that we choose for that, but using TRUE/FALSE in kwlist.h makes it harder for a person adding a new keyword to know what to place there. If they guess "FALSE", and also don't know about adding the new keyword to the bare_label_keyword rule in gram.y, then those two mistakes will agree with each other and the person adding the keyword won't likely know they did it wrong. It is simple enough for gen_keywordlist.pl to convert between what we use in kwlist.h and a boolean value for kwlist_d.h, so I did it that way.

Sounds fine to me.

In the bikeshedding department, it seems "implicit" was chosen because
it was distinct from "bare". I think "bare" as a descriptor should be
kept throughout for readability's sake. Maybe BareColLabel could be
"IDENT or bare_label_keyword" for example. Same for the $status var.

The category "bare_label_keyword" is used in v3. As for the $status var, I don't want to name that $bare, as I didn't go with your idea about using a boolean. $status = "BARE_LABEL" vs "EXPLICIT_LABEL" makes sense to me, more than $bare = "BARE_LABEL" vs "EXPLICIT_LABEL" does. "status" is still a bit vague, so more bikeshedding is welcome.

Yeah, it's very generic, but it's hard to find a short word for
"can-be-used-as-a-bare-column-label-ness".

This patch does not attempt to remove pre-existing postfix operators from existing databases, so users upgrading to the new major version who have custom postfix operators will find that pg_upgrade chokes trying to recreate the postfix operator. That's not great, but perhaps there is nothing automated that we could do for them that would be any better.

I'm thinking it would be good to have something like

select oid from pg_operator where oprright = 0 and oid >= FirstNormalObjectId;

in the pre-upgrade check.

Other comments:

0001:

+ errhint("postfix operator support has been discontinued")));

This language seems more appropriate for release notes -- I would word
the hint in the present, as in "postfix operators are not supported".
Ditto the words "discontinuation", "has been removed", and "no longer
works" elsewhere in the patch.

+SELECT -5!;
+SELECT -0!;
+SELECT 0!;
+SELECT 100!;

I think one negative and one non-negative case is enough to confirm
the syntax error.

- gram.y still contains "POSTFIXOP" and "postfix-operator".

- parse_expr.c looks like it has some now-unreachable code.

0002:

+ * All keywords can be used explicitly as a column label in expressions
+ * like 'SELECT 1234 AS keyword', but only some keywords can be used
+ * implicitly as column labels in expressions like 'SELECT 1234 keyword'.
+ * Those that can be used implicitly should be listed here.

In my mind, "AS" is the thing that's implied when not present, so we
should reword this to use the "bare" designation when talking about
the labels. I think there are contexts elsewhere where the implicit
column label is "col1, col2, col3...". I can't remember offhand where
that is though.

- * kwlist.h's table from one source of truth.)
+ * kwlist.h's table from a common master list.)

Off topic.

0003:

First off, I get a crash when trying

select * from pg_get_keywords();

and haven't investigated further. I don't think the returned types
match, though.

Continuing on, I think 2 and 3 can be squashed together. If anything,
it should make revisiting cosmetic decisions easier.

+ TupleDescInitEntry(tupdesc, (AttrNumber) 4, "bare",
+    BOOLOID, -1, 0);

Perhaps something a bit meatier for the user-visible field name. I
don't have a great suggestion.

-  proname => 'pg_get_keywords', procost => '10', prorows => '400',
+  proname => 'pg_get_keywords', procost => '10', prorows => '450',

Off topic for this patch. Not sure it matters much, either.

"EXPLICIT_LABEL" -- continuing my line of thought above, all labels
are explicit, that's why they're called labels. Brainstorm:

EXPLICIT_AS_LABEL
EXPLICIT_AS
NON_BARE_LABEL
*shrug*

+ # parser/kwlist.h lists each keyword as either bare or
+ # explicit, but ecpg neither needs nor has any such

PL/pgSQL also uses this script, so maybe just phrase it to exclude the
core keyword list.

--
John Naylor https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

#36John Naylor
john.naylor@2ndquadrant.com
In reply to: Tom Lane (#4)
Re: factorial function/phase out postfix operators?

On Tue, May 19, 2020 at 5:03 AM Tom Lane <tgl@sss.pgh.pa.us> wrote:

Peter Eisentraut <peter.eisentraut@2ndquadrant.com> writes:

What are the thoughts about then marking the postfix operator deprecated
and eventually removing it?

If we do this it'd require a plan. We'd have to also warn about the
feature deprecation in (at least) the CREATE OPERATOR man page, and
we'd have to decide how many release cycles the deprecation notices
need to stand for.

If that's the intention, though, it'd be good to get those deprecation
notices published in v13 not v14.

I imagine the release candidates are not too far away by now, and if
we are confident enough in the direction the patches in this thread
are going, we should probably consider a deprecation notice soon.

--
John Naylor https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

#37Mark Dilger
mark.dilger@enterprisedb.com
In reply to: John Naylor (#36)
Re: factorial function/phase out postfix operators?

On Aug 24, 2020, at 12:28 AM, John Naylor <john.naylor@2ndquadrant.com> wrote:

On Tue, May 19, 2020 at 5:03 AM Tom Lane <tgl@sss.pgh.pa.us> wrote:

Peter Eisentraut <peter.eisentraut@2ndquadrant.com> writes:

What are the thoughts about then marking the postfix operator deprecated
and eventually removing it?

If we do this it'd require a plan. We'd have to also warn about the
feature deprecation in (at least) the CREATE OPERATOR man page, and
we'd have to decide how many release cycles the deprecation notices
need to stand for.

If that's the intention, though, it'd be good to get those deprecation
notices published in v13 not v14.

I imagine the release candidates are not too far away by now, and if
we are confident enough in the direction the patches in this thread
are going, we should probably consider a deprecation notice soon.

If so, we might want to also update the deprecation warning for the prefix !! operator in pg_operator.dat:

{ oid => '389', descr => 'deprecated, use ! instead',
oprname => '!!', oprkind => 'l', oprleft => '0', oprright => 'int8',
oprresult => 'numeric', oprcode => 'numeric_fac' },

That will be the only remaining factorial operator if we remove postfix operators.


Mark Dilger
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#38Mark Dilger
mark.dilger@enterprisedb.com
In reply to: John Naylor (#35)
2 attachment(s)
Re: factorial function/phase out postfix operators?

On Jul 29, 2020, at 5:03 AM, John Naylor <john.naylor@2ndquadrant.com> wrote:

On Wed, Jul 22, 2020 at 8:47 AM Mark Dilger
<mark.dilger@enterprisedb.com> wrote:

On Jul 18, 2020, at 1:00 AM, John Naylor <john.naylor@2ndquadrant.com> wrote:

pg_get_keywords() should probably have a column to display ability to
act as a bare col label. Perhaps a boolean? If so, what do you think
of using true/false for the new field in kwlist.h as well?

Hi Mark, sorry for the delay.

Likewise, John. Thanks for the review! I am attaching version 4 of the patch to address your comments.

I have broken this into its own patch. I like using a BARE_LABEL / EXPLICIT_LABEL in kwlist.h because it is self-documenting. I don't care about the *exact* strings that we choose for that, but using TRUE/FALSE in kwlist.h makes it harder for a person adding a new keyword to know what to place there. If they guess "FALSE", and also don't know about adding the new keyword to the bare_label_keyword rule in gram.y, then those two mistakes will agree with each other and the person adding the keyword won't likely know they did it wrong. It is simple enough for gen_keywordlist.pl to convert between what we use in kwlist.h and a boolean value for kwlist_d.h, so I did it that way.

Sounds fine to me.

In the bikeshedding department, it seems "implicit" was chosen because
it was distinct from "bare". I think "bare" as a descriptor should be
kept throughout for readability's sake. Maybe BareColLabel could be
"IDENT or bare_label_keyword" for example. Same for the $status var.

The category "bare_label_keyword" is used in v3. As for the $status var, I don't want to name that $bare, as I didn't go with your idea about using a boolean. $status = "BARE_LABEL" vs "EXPLICIT_LABEL" makes sense to me, more than $bare = "BARE_LABEL" vs "EXPLICIT_LABEL" does. "status" is still a bit vague, so more bikeshedding is welcome.

Yeah, it's very generic, but it's hard to find a short word for
"can-be-used-as-a-bare-column-label-ness".

The construction colname AS colalias brings to mind the words "pseudonym" and "alias". The distinction we're trying to draw here is between implicit pseudoyms and explicit ones, but "alias" is shorter and simpler, so I like that better than "pseudonym". Both are labels, so adding "label" to the name doesn't really get us anything. The constructions "implicit alias" vs. "explicit alias" seem to me to be an improvement, along with their other forms like "ImplicitAlias", or "implicit_alias", etc., so I've used those in version 4.

The word "status" here really means something like "plicity" (implict vs. explicit), but "plicity" isn't a word, so I used "aliastype" instead.

I've replaced uses of "bare" with "implicit" or "implicit_alias" or similar.

This patch does not attempt to remove pre-existing postfix operators from existing databases, so users upgrading to the new major version who have custom postfix operators will find that pg_upgrade chokes trying to recreate the postfix operator. That's not great, but perhaps there is nothing automated that we could do for them that would be any better.

I'm thinking it would be good to have something like

select oid from pg_operator where oprright = 0 and oid >= FirstNormalObjectId;

in the pre-upgrade check.

Done. Testing an upgrade of a 9.1 test install, relying on the regression database having left over user defined postfix operators, gives this result:

pg_upgrade --old-bindir=/Users/mark.dilger/pg91/bin --old-datadir=/Users/mark.dilger/pg91/test_data --new-bindir=/Users/mark.dilger/pgtest/test_install/bin --new-datadir=/Users/mark.dilger/pgtest/test_data
Performing Consistency Checks
-----------------------------
Checking cluster versions ok
Checking database user is the install user ok
Checking database connection settings ok
Checking for prepared transactions ok
Checking for reg* data types in user tables ok
Checking for contrib/isn with bigint-passing mismatch ok
Checking for user defined postfix operators fatal

Your installation contains user defined postfix operators, which is not
supported anymore. Consider dropping the postfix operators and replacing
them with prefix operators or function calls.
A list of user defined postfix operators is in the file:
postfix_ops.txt

Failure, exiting

With the contents of postfix_ops.txt:

In database: regression
(oid=27113) public.#@# (pg_catalog.int8)
(oid=27114) public.#%# (pg_catalog.int8)

which should be enough for a user to identify which operator is meant. I just invented that format. Let me know if there is a preferred way to lay out that information.

Other comments:

0001:

+ errhint("postfix operator support has been discontinued")));

This language seems more appropriate for release notes -- I would word
the hint in the present, as in "postfix operators are not supported".
Ditto the words "discontinuation", "has been removed", and "no longer
works" elsewhere in the patch.

Changed the hint to say "Postfix operators are not supported."

Changed the regression test comment and code comments to not use the objectionable language you mention.

+SELECT -5!;
+SELECT -0!;
+SELECT 0!;
+SELECT 100!;

I think one negative and one non-negative case is enough to confirm
the syntax error.

Ok, done.

- gram.y still contains "POSTFIXOP" and "postfix-operator".

- parse_expr.c looks like it has some now-unreachable code.

Good point. I've removed or renamed that stuff. Some of it went away, but some stuff was shared between general postfix operators and ANY/ALL, so that just got renamed accordingly.

0002:

+ * All keywords can be used explicitly as a column label in expressions
+ * like 'SELECT 1234 AS keyword', but only some keywords can be used
+ * implicitly as column labels in expressions like 'SELECT 1234 keyword'.
+ * Those that can be used implicitly should be listed here.

In my mind, "AS" is the thing that's implied when not present, so we
should reword this to use the "bare" designation when talking about
the labels. I think there are contexts elsewhere where the implicit
column label is "col1, col2, col3...". I can't remember offhand where
that is though.

Per my rambling above, I think what's really implied or explicit when "AS" is missing or present is that we're making an alias, so "implicit alias" and "explicit alias" sound correct to me.

- * kwlist.h's table from one source of truth.)
+ * kwlist.h's table from a common master list.)

Off topic.

Removed. This appears to have been an unintentional revert of an unrelated commit.

0003:

First off, I get a crash when trying

select * from pg_get_keywords();

and haven't investigated further. I don't think the returned types
match, though.

Fixed.

Continuing on, I think 2 and 3 can be squashed together. If anything,
it should make revisiting cosmetic decisions easier.

Squashed together.

+ TupleDescInitEntry(tupdesc, (AttrNumber) 4, "bare",
+    BOOLOID, -1, 0);

Perhaps something a bit meatier for the user-visible field name. I
don't have a great suggestion.

I've changed it from "bool bare" to "text aliastype". (I still wish "plicity" were a word.) Rather than true/false, it returns "implicit"/"explicit".

-  proname => 'pg_get_keywords', procost => '10', prorows => '400',
+  proname => 'pg_get_keywords', procost => '10', prorows => '450',

Off topic for this patch. Not sure it matters much, either.

Well, I did touch that function a bit, adding a new column, and the number of rows returned is exactly 450, so if I'm not going to update it, who will? The count may increase over time if other keywords are added, but I doubt anybody who adds a single keyword would bother updating prorows here.

I agree that it doesn't matter much. If you don't buy into the paragraph above, I'll remove it for the next patch version.

"EXPLICIT_LABEL" -- continuing my line of thought above, all labels
are explicit, that's why they're called labels.

Right. Labels are explicit.

Brainstorm:

EXPLICIT_AS_LABEL
EXPLICIT_AS
NON_BARE_LABEL
*shrug*

Changed to EXPLICIT_ALIAS.

+ # parser/kwlist.h lists each keyword as either bare or
+ # explicit, but ecpg neither needs nor has any such

PL/pgSQL also uses this script, so maybe just phrase it to exclude the
core keyword list.

Done.

Attachments:

v4-0001-Removing-postfix-operator-support.patchapplication/octet-stream; name=v4-0001-Removing-postfix-operator-support.patch; x-unix-mode=0644Download
From 476be006f53d32c1b7e6a19fcb15ec8fa77fc8d3 Mon Sep 17 00:00:00 2001
From: Mark Dilger <mark.dilger@enterprisedb.com>
Date: Tue, 25 Aug 2020 19:54:07 -0700
Subject: [PATCH v4 1/2] Removing postfix operator support.

Removing postfix operator support from the grammar; disallowing
the creation of postfix operators through the CREATE OPERATOR
command; and removing the factorial postfix operator.

This accomplishes nothing useful in itself, but sets up
for grammar changes to allow keywords to be used as bare column
aliases without the use of an explicit "AS".
---
 contrib/postgres_fdw/deparse.c                |   5 +-
 .../postgres_fdw/expected/postgres_fdw.out    |   8 +-
 contrib/postgres_fdw/sql/postgres_fdw.sql     |   2 +-
 doc/src/sgml/catalogs.sgml                    |   2 +-
 doc/src/sgml/ref/alter_extension.sgml         |   2 +-
 doc/src/sgml/ref/comment.sgml                 |   2 +-
 doc/src/sgml/syntax.sgml                      |  24 +---
 doc/src/sgml/typeconv.sgml                    |   8 +-
 src/backend/catalog/pg_operator.c             |   4 +-
 src/backend/commands/operatorcmds.c           |  17 ++-
 src/backend/parser/gram.y                     |  26 +---
 src/backend/parser/parse_expr.c               |  48 ++-----
 src/backend/parser/parse_oper.c               | 121 +++---------------
 src/backend/utils/adt/ruleutils.c             |  31 ++---
 src/bin/pg_dump/pg_dump.c                     |   6 +-
 src/bin/pg_dump/pg_dump_sort.c                |   2 +-
 src/bin/pg_upgrade/check.c                    | 106 +++++++++++++++
 src/bin/psql/describe.c                       |   2 +-
 src/include/catalog/pg_operator.dat           |   5 +-
 src/include/catalog/pg_operator.h             |   4 +-
 src/test/regress/expected/create_operator.out |  24 ++--
 src/test/regress/expected/numeric.out         |  19 ++-
 src/test/regress/expected/opr_sanity.out      |  17 +--
 src/test/regress/sql/create_operator.sql      |   3 +-
 src/test/regress/sql/numeric.sql              |  14 +-
 src/test/regress/sql/opr_sanity.sql           |  14 +-
 src/tutorial/syscat.source                    |  14 --
 27 files changed, 237 insertions(+), 293 deletions(-)

diff --git a/contrib/postgres_fdw/deparse.c b/contrib/postgres_fdw/deparse.c
index ad37a74221..32a9b38f10 100644
--- a/contrib/postgres_fdw/deparse.c
+++ b/contrib/postgres_fdw/deparse.c
@@ -2716,15 +2716,14 @@ deparseOpExpr(OpExpr *node, deparse_expr_cxt *context)
 	oprkind = form->oprkind;
 
 	/* Sanity check. */
-	Assert((oprkind == 'r' && list_length(node->args) == 1) ||
-		   (oprkind == 'l' && list_length(node->args) == 1) ||
+	Assert((oprkind == 'l' && list_length(node->args) == 1) ||
 		   (oprkind == 'b' && list_length(node->args) == 2));
 
 	/* Always parenthesize the expression. */
 	appendStringInfoChar(buf, '(');
 
 	/* Deparse left operand. */
-	if (oprkind == 'r' || oprkind == 'b')
+	if (oprkind == 'b')
 	{
 		arg = list_head(node->args);
 		deparseExpr(lfirst(arg), context);
diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index 90db550b92..9728c252ba 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -653,12 +653,12 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 = -c1;          -- Op
    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = (- "C 1")))
 (3 rows)
 
-EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE 1 = c1!;           -- OpExpr(r)
-                                                QUERY PLAN                                                
-----------------------------------------------------------------------------------------------------------
+EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE 1 = !!c1;          -- OpExpr(r)
+                                                QUERY PLAN                                                 
+-----------------------------------------------------------------------------------------------------------
  Foreign Scan on public.ft1 t1
    Output: c1, c2, c3, c4, c5, c6, c7, c8
-   Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE ((1::numeric = ("C 1" !)))
+   Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE ((1::numeric = (!! "C 1")))
 (3 rows)
 
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE (c1 IS NOT NULL) IS DISTINCT FROM (c1 IS NOT NULL); -- DistinctExpr
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index 83971665e3..a8e58a8f24 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -307,7 +307,7 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 IS NULL;        -- Nu
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 IS NOT NULL;    -- NullTest
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE round(abs(c1), 0) = 1; -- FuncExpr
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 = -c1;          -- OpExpr(l)
-EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE 1 = c1!;           -- OpExpr(r)
+EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE 1 = !!c1;          -- OpExpr(r)
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE (c1 IS NOT NULL) IS DISTINCT FROM (c1 IS NOT NULL); -- DistinctExpr
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 = ANY(ARRAY[c2, 1, c1 + 0]); -- ScalarArrayOpExpr
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 = (ARRAY[c1,c2,3])[1]; -- SubscriptingRef
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 9fe260ecff..6ed67eedb1 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -5150,7 +5150,7 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
       </para>
       <para>
        <literal>b</literal> = infix (<quote>both</quote>), <literal>l</literal> = prefix
-       (<quote>left</quote>), <literal>r</literal> = postfix (<quote>right</quote>)
+       (<quote>left</quote>)
       </para></entry>
      </row>
 
diff --git a/doc/src/sgml/ref/alter_extension.sgml b/doc/src/sgml/ref/alter_extension.sgml
index a2d405d6cd..c819c7bb4e 100644
--- a/doc/src/sgml/ref/alter_extension.sgml
+++ b/doc/src/sgml/ref/alter_extension.sgml
@@ -251,7 +251,7 @@ ALTER EXTENSION <replaceable class="parameter">name</replaceable> DROP <replacea
       <para>
        The data type(s) of the operator's arguments (optionally
        schema-qualified).  Write <literal>NONE</literal> for the missing argument
-       of a prefix or postfix operator.
+       of a prefix operator.
       </para>
      </listitem>
     </varlistentry>
diff --git a/doc/src/sgml/ref/comment.sgml b/doc/src/sgml/ref/comment.sgml
index fd7492a255..6e8ced3eaf 100644
--- a/doc/src/sgml/ref/comment.sgml
+++ b/doc/src/sgml/ref/comment.sgml
@@ -224,7 +224,7 @@ COMMENT ON
      <para>
       The data type(s) of the operator's arguments (optionally
       schema-qualified).  Write <literal>NONE</literal> for the missing argument
-      of a prefix or postfix operator.
+      of a prefix operator.
      </para>
     </listitem>
    </varlistentry>
diff --git a/doc/src/sgml/syntax.sgml b/doc/src/sgml/syntax.sgml
index 2f993ca2e0..5ad25d96d6 100644
--- a/doc/src/sgml/syntax.sgml
+++ b/doc/src/sgml/syntax.sgml
@@ -979,27 +979,6 @@ CAST ( '<replaceable>string</replaceable>' AS <replaceable>type</replaceable> )
     into the parser.
    </para>
 
-   <para>
-    You will
-    sometimes need to add parentheses when using combinations of
-    binary and unary operators.  For instance:
-<programlisting>
-SELECT 5 ! - 6;
-</programlisting>
-   will be parsed as:
-<programlisting>
-SELECT 5 ! (- 6);
-</programlisting>
-    because the parser has no idea &mdash; until it is too late
-    &mdash; that <token>!</token> is defined as a postfix operator,
-    not an infix one.  To get the desired behavior in this case, you
-    must write:
-<programlisting>
-SELECT (5 !) - 6;
-</programlisting>
-    This is the price one pays for extensibility.
-   </para>
-
    <table id="sql-precedence-table">
     <title>Operator Precedence (highest to lowest)</title>
 
@@ -1463,11 +1442,10 @@ $1.somecolumn
    </indexterm>
 
    <para>
-    There are three possible syntaxes for an operator invocation:
+    There are two possible syntaxes for an operator invocation:
     <simplelist>
      <member><replaceable>expression</replaceable> <replaceable>operator</replaceable> <replaceable>expression</replaceable> (binary infix operator)</member>
      <member><replaceable>operator</replaceable> <replaceable>expression</replaceable> (unary prefix operator)</member>
-     <member><replaceable>expression</replaceable> <replaceable>operator</replaceable> (unary postfix operator)</member>
     </simplelist>
     where the <replaceable>operator</replaceable> token follows the syntax
     rules of <xref linkend="sql-syntax-operators"/>, or is one of the
diff --git a/doc/src/sgml/typeconv.sgml b/doc/src/sgml/typeconv.sgml
index 8900d0eb38..55780d35ec 100644
--- a/doc/src/sgml/typeconv.sgml
+++ b/doc/src/sgml/typeconv.sgml
@@ -97,7 +97,7 @@ Operators
 <listitem>
 <para>
 <productname>PostgreSQL</productname> allows expressions with
-prefix and postfix unary (one-argument) operators,
+prefix unary (one-argument) operators,
 as well as binary (two-argument) operators.  Like functions, operators can
 be overloaded, so the same problem of selecting the right operator
 exists.
@@ -357,13 +357,13 @@ Some examples follow.
 <title>Factorial Operator Type Resolution</title>
 
 <para>
-There is only one factorial operator (postfix <literal>!</literal>)
+There is only one factorial operator (prefix <literal>!!</literal>)
 defined in the standard catalog, and it takes an argument of type
 <type>bigint</type>.
 The scanner assigns an initial type of <type>integer</type> to the argument
 in this query expression:
 <screen>
-SELECT 40 ! AS "40 factorial";
+SELECT !! 40 AS "40 factorial";
 
                    40 factorial
 --------------------------------------------------
@@ -375,7 +375,7 @@ So the parser does a type conversion on the operand and the query
 is equivalent to:
 
 <screen>
-SELECT CAST(40 AS bigint) ! AS "40 factorial";
+SELECT !! CAST(40 AS bigint) AS "40 factorial";
 </screen>
 </para>
 </example>
diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c
index 65a36be5ee..f817627d86 100644
--- a/src/backend/catalog/pg_operator.c
+++ b/src/backend/catalog/pg_operator.c
@@ -245,7 +245,7 @@ OperatorShellMake(const char *operatorName,
 	values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
 	values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
 	values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId());
-	values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');
+	values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? 'b' : 'l');
 	values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(false);
 	values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(false);
 	values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);
@@ -494,7 +494,7 @@ OperatorCreate(const char *operatorName,
 	values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
 	values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
 	values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId());
-	values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');
+	values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? 'b' : 'l');
 	values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(canMerge);
 	values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(canHash);
 	values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);
diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c
index bf23937849..354a184f0f 100644
--- a/src/backend/commands/operatorcmds.c
+++ b/src/backend/commands/operatorcmds.c
@@ -168,10 +168,25 @@ DefineOperator(List *names, List *parameters)
 	if (typeName2)
 		typeId2 = typenameTypeId(NULL, typeName2);
 
+	/*
+	 * If neither argument is specified, do not mention postfix operators, as
+	 * the user is unlikely to have meant to create one.  It is more likely
+	 * they simply neglected to mention the args.
+	 */
 	if (!OidIsValid(typeId1) && !OidIsValid(typeId2))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
-				 errmsg("at least one of leftarg or rightarg must be specified")));
+				 errmsg("operator arguments must be specified")));
+
+	/*
+	 * But if only the right arg is missing, they probably do intend to create
+	 * a postfix operator, so give them a hint about why that does not work.
+	 */
+	if (!OidIsValid(typeId2))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+				 errmsg("operator right argument must be specified"),
+				 errhint("Postfix operators are not supported.")));
 
 	if (typeName1)
 	{
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index dbb47d4982..0171da5f4b 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -741,19 +741,14 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 %nonassoc	'<' '>' '=' LESS_EQUALS GREATER_EQUALS NOT_EQUALS
 %nonassoc	BETWEEN IN_P LIKE ILIKE SIMILAR NOT_LA
 %nonassoc	ESCAPE			/* ESCAPE must be just above LIKE/ILIKE/SIMILAR */
-%left		POSTFIXOP		/* dummy for postfix Op rules */
 /*
  * To support target_el without AS, we must give IDENT an explicit priority
- * between POSTFIXOP and Op.  We can safely assign the same priority to
- * various unreserved keywords as needed to resolve ambiguities (this can't
- * have any bad effects since obviously the keywords will still behave the
- * same as if they weren't keywords).  We need to do this:
+ * greater than Op.  We can safely assign the same priority to various
+ * unreserved keywords as needed to resolve ambiguities (this can't have any
+ * bad effects since obviously the keywords will still behave the same as if
+ * they weren't keywords).  We need to do this:
  * for PARTITION, RANGE, ROWS, GROUPS to support opt_existing_window_name;
- * for RANGE, ROWS, GROUPS so that they can follow a_expr without creating
- * postfix-operator problems;
  * for GENERATED so that it can follow b_expr;
- * and for NULL so that it can follow b_expr in ColQualList without creating
- * postfix-operator problems.
  *
  * To support CUBE and ROLLUP in GROUP BY without reserving them, we give them
  * an explicit priority lower than '(', so that a rule with CUBE '(' will shift
@@ -770,7 +765,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
  * blame any funny behavior of UNBOUNDED on the SQL standard, though.
  */
 %nonassoc	UNBOUNDED		/* ideally should have same precedence as IDENT */
-%nonassoc	IDENT GENERATED NULL_P PARTITION RANGE ROWS GROUPS PRECEDING FOLLOWING CUBE ROLLUP
+%nonassoc	IDENT GENERATED PARTITION RANGE ROWS GROUPS PRECEDING FOLLOWING CUBE ROLLUP
 %left		Op OPERATOR		/* multi-character ops and user-defined operators */
 %left		'+' '-'
 %left		'*' '/' '%'
@@ -12989,9 +12984,6 @@ a_expr:		c_expr									{ $$ = $1; }
 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3, @2); }
 			| qual_Op a_expr					%prec Op
 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $1, NULL, $2, @1); }
-			| a_expr qual_Op					%prec POSTFIXOP
-				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, NULL, @2); }
-
 			| a_expr AND a_expr
 				{ $$ = makeAndExpr($1, $3, @2); }
 			| a_expr OR a_expr
@@ -13404,8 +13396,6 @@ b_expr:		c_expr
 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3, @2); }
 			| qual_Op b_expr					%prec Op
 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $1, NULL, $2, @1); }
-			| b_expr qual_Op					%prec POSTFIXOP
-				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, NULL, @2); }
 			| b_expr IS DISTINCT FROM b_expr		%prec IS
 				{
 					$$ = (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $5, @2);
@@ -14661,11 +14651,7 @@ target_el:	a_expr AS ColLabel
 				}
 			/*
 			 * 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.
+			 * any known keyword.
 			 */
 			| a_expr IDENT
 				{
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index f69976cc8c..9e266cf3b0 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -57,7 +57,7 @@ bool		Transform_null_equals = false;
 #define PREC_GROUP_NOT_LIKE		9	/* NOT LIKE/ILIKE/SIMILAR */
 #define PREC_GROUP_NOT_BETWEEN	10	/* NOT BETWEEN */
 #define PREC_GROUP_NOT_IN		11	/* NOT IN */
-#define PREC_GROUP_POSTFIX_OP	12	/* generic postfix operators */
+#define PREC_GROUP_ANY_ALL		12	/* ANY/ALL */
 #define PREC_GROUP_INFIX_OP		13	/* generic infix operators */
 #define PREC_GROUP_PREFIX_OP	14	/* generic prefix operators */
 
@@ -71,7 +71,7 @@ bool		Transform_null_equals = false;
  * 4. LIKE ILIKE SIMILAR
  * 5. BETWEEN
  * 6. IN
- * 7. generic postfix Op
+ * 7. ANY ALL
  * 8. generic Op, including <= => <>
  * 9. generic prefix Op
  * 10. IS tests (NullTest, BooleanTest, etc)
@@ -1031,7 +1031,7 @@ transformAExprOpAny(ParseState *pstate, A_Expr *a)
 	Node	   *rexpr = a->rexpr;
 
 	if (operator_precedence_warning)
-		emit_precedence_warnings(pstate, PREC_GROUP_POSTFIX_OP,
+		emit_precedence_warnings(pstate, PREC_GROUP_ANY_ALL,
 								 strVal(llast(a->name)),
 								 lexpr, NULL,
 								 a->location);
@@ -1054,7 +1054,7 @@ transformAExprOpAll(ParseState *pstate, A_Expr *a)
 	Node	   *rexpr = a->rexpr;
 
 	if (operator_precedence_warning)
-		emit_precedence_warnings(pstate, PREC_GROUP_POSTFIX_OP,
+		emit_precedence_warnings(pstate, PREC_GROUP_ANY_ALL,
 								 strVal(llast(a->name)),
 								 lexpr, NULL,
 								 a->location);
@@ -2014,15 +2014,9 @@ transformSubLink(ParseState *pstate, SubLink *sublink)
 
 		if (operator_precedence_warning)
 		{
-			if (sublink->operName == NIL)
-				emit_precedence_warnings(pstate, PREC_GROUP_IN, "IN",
-										 sublink->testexpr, NULL,
-										 sublink->location);
-			else
-				emit_precedence_warnings(pstate, PREC_GROUP_POSTFIX_OP,
-										 strVal(llast(sublink->operName)),
-										 sublink->testexpr, NULL,
-										 sublink->location);
+			emit_precedence_warnings(pstate, PREC_GROUP_IN, "IN",
+									 sublink->testexpr, NULL,
+									 sublink->location);
 		}
 
 		/*
@@ -3244,28 +3238,11 @@ operator_precedence_group(Node *node, const char **nodename)
 				group = PREC_GROUP_PREFIX_OP;
 			}
 		}
-		else if (aexpr->kind == AEXPR_OP &&
-				 aexpr->lexpr != NULL &&
-				 aexpr->rexpr == NULL)
-		{
-			/* postfix operator */
-			if (list_length(aexpr->name) == 1)
-			{
-				*nodename = strVal(linitial(aexpr->name));
-				group = PREC_GROUP_POSTFIX_OP;
-			}
-			else
-			{
-				/* schema-qualified operator syntax */
-				*nodename = "OPERATOR()";
-				group = PREC_GROUP_POSTFIX_OP;
-			}
-		}
 		else if (aexpr->kind == AEXPR_OP_ANY ||
 				 aexpr->kind == AEXPR_OP_ALL)
 		{
 			*nodename = strVal(llast(aexpr->name));
-			group = PREC_GROUP_POSTFIX_OP;
+			group = PREC_GROUP_ANY_ALL;
 		}
 		else if (aexpr->kind == AEXPR_DISTINCT ||
 				 aexpr->kind == AEXPR_NOT_DISTINCT)
@@ -3356,7 +3333,7 @@ operator_precedence_group(Node *node, const char **nodename)
 			else
 			{
 				*nodename = strVal(llast(s->operName));
-				group = PREC_GROUP_POSTFIX_OP;
+				group = PREC_GROUP_ANY_ALL;
 			}
 		}
 	}
@@ -3432,9 +3409,8 @@ emit_precedence_warnings(ParseState *pstate,
 	 * Complain if left child, which should be same or higher precedence
 	 * according to current rules, used to be lower precedence.
 	 *
-	 * Exception to precedence rules: if left child is IN or NOT IN or a
-	 * postfix operator, the grouping is syntactically forced regardless of
-	 * precedence.
+	 * Exception to precedence rules: if left child is IN or NOT IN the
+	 * grouping is syntactically forced regardless of precedence.
 	 */
 	cgroup = operator_precedence_group(lchild, &copname);
 	if (cgroup > 0)
@@ -3442,7 +3418,7 @@ emit_precedence_warnings(ParseState *pstate,
 		if (oldprecedence_l[cgroup] < oldprecedence_r[opgroup] &&
 			cgroup != PREC_GROUP_IN &&
 			cgroup != PREC_GROUP_NOT_IN &&
-			cgroup != PREC_GROUP_POSTFIX_OP &&
+			cgroup != PREC_GROUP_ANY_ALL &&
 			cgroup != PREC_GROUP_POSTFIX_IS)
 			ereport(WARNING,
 					(errmsg("operator precedence change: %s is now lower precedence than %s",
diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c
index 2749974f63..877ffa03a6 100644
--- a/src/backend/parser/parse_oper.c
+++ b/src/backend/parser/parse_oper.c
@@ -52,7 +52,7 @@ typedef struct OprCacheKey
 {
 	char		oprname[NAMEDATALEN];
 	Oid			left_arg;		/* Left input OID, or 0 if prefix op */
-	Oid			right_arg;		/* Right input OID, or 0 if postfix op */
+	Oid			right_arg;		/* Right input OID */
 	Oid			search_path[MAX_CACHED_PATH_LEN];
 } OprCacheKey;
 
@@ -88,8 +88,7 @@ static void InvalidateOprCacheCallBack(Datum arg, int cacheid, uint32 hashvalue)
  *		Given a possibly-qualified operator name and exact input datatypes,
  *		look up the operator.
  *
- * Pass oprleft = InvalidOid for a prefix op, oprright = InvalidOid for
- * a postfix op.
+ * Pass oprleft = InvalidOid for a prefix op.
  *
  * If the operator name is not schema-qualified, it is sought in the current
  * namespace search path.
@@ -115,10 +114,13 @@ LookupOperName(ParseState *pstate, List *opername, Oid oprleft, Oid oprright,
 
 		if (!OidIsValid(oprleft))
 			oprkind = 'l';
-		else if (!OidIsValid(oprright))
-			oprkind = 'r';
-		else
+		else if (OidIsValid(oprright))
 			oprkind = 'b';
+		else
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					 errmsg("postfix operators are not supported"),
+					 parser_errposition(pstate, location)));
 
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_FUNCTION),
@@ -507,85 +509,6 @@ compatible_oper_opid(List *op, Oid arg1, Oid arg2, bool noError)
 }
 
 
-/* right_oper() -- search for a unary right operator (postfix operator)
- * Given operator name and type of arg, return oper struct.
- *
- * IMPORTANT: the returned operator (if any) is only promised to be
- * coercion-compatible with the input datatype.  Do not use this if
- * you need an exact- or binary-compatible match.
- *
- * If no matching operator found, return NULL if noError is true,
- * raise an error if it is false.  pstate and location are used only to report
- * the error position; pass NULL/-1 if not available.
- *
- * NOTE: on success, the returned object is a syscache entry.  The caller
- * must ReleaseSysCache() the entry when done with it.
- */
-Operator
-right_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
-{
-	Oid			operOid;
-	OprCacheKey key;
-	bool		key_ok;
-	FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND;
-	HeapTuple	tup = NULL;
-
-	/*
-	 * Try to find the mapping in the lookaside cache.
-	 */
-	key_ok = make_oper_cache_key(pstate, &key, op, arg, InvalidOid, location);
-
-	if (key_ok)
-	{
-		operOid = find_oper_cache_entry(&key);
-		if (OidIsValid(operOid))
-		{
-			tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
-			if (HeapTupleIsValid(tup))
-				return (Operator) tup;
-		}
-	}
-
-	/*
-	 * First try for an "exact" match.
-	 */
-	operOid = OpernameGetOprid(op, arg, InvalidOid);
-	if (!OidIsValid(operOid))
-	{
-		/*
-		 * Otherwise, search for the most suitable candidate.
-		 */
-		FuncCandidateList clist;
-
-		/* Get postfix operators of given name */
-		clist = OpernameGetCandidates(op, 'r', false);
-
-		/* No operators found? Then fail... */
-		if (clist != NULL)
-		{
-			/*
-			 * We must run oper_select_candidate even if only one candidate,
-			 * otherwise we may falsely return a non-type-compatible operator.
-			 */
-			fdresult = oper_select_candidate(1, &arg, clist, &operOid);
-		}
-	}
-
-	if (OidIsValid(operOid))
-		tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
-
-	if (HeapTupleIsValid(tup))
-	{
-		if (key_ok)
-			make_oper_cache_entry(&key, operOid);
-	}
-	else if (!noError)
-		op_error(pstate, op, 'r', arg, InvalidOid, fdresult, location);
-
-	return (Operator) tup;
-}
-
-
 /* left_oper() -- search for a unary left operator (prefix operator)
  * Given operator name and type of arg, return oper struct.
  *
@@ -696,8 +619,7 @@ op_signature_string(List *op, char oprkind, Oid arg1, Oid arg2)
 
 	appendStringInfoString(&argbuf, NameListToString(op));
 
-	if (oprkind != 'r')
-		appendStringInfo(&argbuf, " %s", format_type_be(arg2));
+	appendStringInfo(&argbuf, " %s", format_type_be(arg2));
 
 	return argbuf.data;			/* return palloc'd string buffer */
 }
@@ -758,15 +680,14 @@ make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree,
 	Oid			rettype;
 	OpExpr	   *result;
 
-	/* Select the operator */
+	/* Check it's not a postfix operator */
 	if (rtree == NULL)
-	{
-		/* right operator */
-		ltypeId = exprType(ltree);
-		rtypeId = InvalidOid;
-		tup = right_oper(pstate, opname, ltypeId, false, location);
-	}
-	else if (ltree == NULL)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+				 errmsg("postfix operators are not supported")));
+
+	/* Select the operator */
+	if (ltree == NULL)
 	{
 		/* left operator */
 		rtypeId = exprType(rtree);
@@ -795,15 +716,7 @@ make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree,
 				 parser_errposition(pstate, location)));
 
 	/* Do typecasting and build the expression tree */
-	if (rtree == NULL)
-	{
-		/* right operator */
-		args = list_make1(ltree);
-		actual_arg_types[0] = ltypeId;
-		declared_arg_types[0] = opform->oprleft;
-		nargs = 1;
-	}
-	else if (ltree == NULL)
+	if (ltree == NULL)
 	{
 		/* left operator */
 		args = list_make1(rtree);
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 60dd80c23c..16abfcb406 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -9207,25 +9207,16 @@ get_oper_expr(OpExpr *expr, deparse_context *context)
 		if (!HeapTupleIsValid(tp))
 			elog(ERROR, "cache lookup failed for operator %u", opno);
 		optup = (Form_pg_operator) GETSTRUCT(tp);
-		switch (optup->oprkind)
-		{
-			case 'l':
-				appendStringInfo(buf, "%s ",
-								 generate_operator_name(opno,
-														InvalidOid,
-														exprType(arg)));
-				get_rule_expr_paren(arg, context, true, (Node *) expr);
-				break;
-			case 'r':
-				get_rule_expr_paren(arg, context, true, (Node *) expr);
-				appendStringInfo(buf, " %s",
-								 generate_operator_name(opno,
-														exprType(arg),
-														InvalidOid));
-				break;
-			default:
-				elog(ERROR, "bogus oprkind: %d", optup->oprkind);
+		if (optup->oprkind == 'l')
+		{
+			appendStringInfo(buf, "%s ",
+							 generate_operator_name(opno,
+													InvalidOid,
+													exprType(arg)));
+			get_rule_expr_paren(arg, context, true, (Node *) expr);
 		}
+		else
+			elog(ERROR, "bogus oprkind: %d", optup->oprkind);
 		ReleaseSysCache(tp);
 	}
 	if (!PRETTY_PAREN(context))
@@ -11087,10 +11078,6 @@ generate_operator_name(Oid operid, Oid arg1, Oid arg2)
 			p_result = left_oper(NULL, list_make1(makeString(oprname)), arg2,
 								 true, -1);
 			break;
-		case 'r':
-			p_result = right_oper(NULL, list_make1(makeString(oprname)), arg1,
-								  true, -1);
-			break;
 		default:
 			elog(ERROR, "unrecognized oprkind: %d", operform->oprkind);
 			p_result = NULL;	/* keep compiler quiet */
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 2cb3f9b083..a93ab8eed3 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -12643,11 +12643,9 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
 					  oprinfo->dobj.name);
 
 	/*
-	 * right unary means there's a left arg and left unary means there's a
-	 * right arg
+	 * left unary means there's only a right arg
 	 */
-	if (strcmp(oprkind, "r") == 0 ||
-		strcmp(oprkind, "b") == 0)
+	if (strcmp(oprkind, "b") == 0)
 	{
 		appendPQExpBuffer(details, ",\n    LEFTARG = %s", oprleft);
 		appendPQExpBufferStr(oprid, oprleft);
diff --git a/src/bin/pg_dump/pg_dump_sort.c b/src/bin/pg_dump/pg_dump_sort.c
index 654e2ec514..c7f06604c6 100644
--- a/src/bin/pg_dump/pg_dump_sort.c
+++ b/src/bin/pg_dump/pg_dump_sort.c
@@ -203,7 +203,7 @@ DOTypeNameCompare(const void *p1, const void *p2)
 		OprInfo    *oobj1 = *(OprInfo *const *) p1;
 		OprInfo    *oobj2 = *(OprInfo *const *) p2;
 
-		/* oprkind is 'l', 'r', or 'b'; this sorts prefix, postfix, infix */
+		/* oprkind is 'l' or 'b'; this sorts prefix and infix */
 		cmpval = (oobj2->oprkind - oobj1->oprkind);
 		if (cmpval != 0)
 			return cmpval;
diff --git a/src/bin/pg_upgrade/check.c b/src/bin/pg_upgrade/check.c
index 00aef855dc..b86098dc42 100644
--- a/src/bin/pg_upgrade/check.c
+++ b/src/bin/pg_upgrade/check.c
@@ -22,6 +22,7 @@ static void check_is_install_user(ClusterInfo *cluster);
 static void check_proper_datallowconn(ClusterInfo *cluster);
 static void check_for_prepared_transactions(ClusterInfo *cluster);
 static void check_for_isn_and_int8_passing_mismatch(ClusterInfo *cluster);
+static void check_for_user_defined_postfix_ops(ClusterInfo *cluster);
 static void check_for_tables_with_oids(ClusterInfo *cluster);
 static void check_for_reg_data_type_usage(ClusterInfo *cluster);
 static void check_for_jsonb_9_4_usage(ClusterInfo *cluster);
@@ -100,6 +101,13 @@ check_and_dump_old_cluster(bool live_check)
 	check_for_reg_data_type_usage(&old_cluster);
 	check_for_isn_and_int8_passing_mismatch(&old_cluster);
 
+	/*
+	 * Pre-PG 14 allowed user defined postfix operators, which are not
+	 * supported anymore.  Verify there are none, iff applicable.
+	 */
+	if (GET_MAJOR_VERSION(old_cluster.major_version) <= 1300)
+		check_for_user_defined_postfix_ops(&old_cluster);
+
 	/*
 	 * Pre-PG 12 allowed tables to be declared WITH OIDS, which is not
 	 * supported anymore. Verify there are none, iff applicable.
@@ -896,6 +904,104 @@ check_for_isn_and_int8_passing_mismatch(ClusterInfo *cluster)
 		check_ok();
 }
 
+/*
+ * Verify that no user defined postfix operators exist.
+ */
+static void
+check_for_user_defined_postfix_ops(ClusterInfo *cluster)
+{
+	int			dbnum;
+	FILE	   *script = NULL;
+	bool		found = false;
+	char		output_path[MAXPGPATH];
+
+	prep_status("Checking for user defined postfix operators");
+
+	snprintf(output_path, sizeof(output_path),
+			 "postfix_ops.txt");
+
+	/* Find any user defined postfix operators */
+	for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
+	{
+		PGresult   *res;
+		bool		db_used = false;
+		int			ntups;
+		int			rowno;
+		int			i_oproid,
+					i_oprnsp,
+					i_oprname,
+					i_typnsp,
+					i_typname;
+		DbInfo	   *active_db = &cluster->dbarr.dbs[dbnum];
+		PGconn	   *conn = connectToServer(cluster, active_db->db_name);
+
+		/*
+		 * The query below hardcodes FirstNormalObjectId as 16384 rather than
+		 * interpolating that C #define into the string because, if that
+		 * #define is ever changed, the cutoff we want to use is the definition
+		 * from pre-verion 14 servers, not from some future version of the
+		 * code.
+		 */
+		res = executeQueryOrDie(conn,
+								"SELECT o.oid AS oproid, "
+								"       n.nspname AS oprnsp, "
+								"       o.oprname, "
+								"       tn.nspname AS typnsp, "
+								"       t.typname "
+								"FROM pg_catalog.pg_operator o, "
+								"     pg_catalog.pg_namespace n, "
+								"     pg_catalog.pg_type t, "
+								"     pg_catalog.pg_namespace tn "
+								"WHERE o.oprnamespace = n.oid AND "
+								"      o.oprleft = t.oid AND "
+								"      t.typnamespace = tn.oid AND "
+								"      o.oprright = 0 AND "
+								"      o.oid >= 16384");
+		ntups = PQntuples(res);
+		i_oproid = PQfnumber(res, "oproid");
+		i_oprnsp = PQfnumber(res, "oprnsp");
+		i_oprname = PQfnumber(res, "oprname");
+		i_typnsp = PQfnumber(res, "typnsp");
+		i_typname = PQfnumber(res, "typname");
+		for (rowno = 0; rowno < ntups; rowno++)
+		{
+			found = true;
+			if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
+				pg_fatal("could not open file \"%s\": %s\n",
+						 output_path, strerror(errno));
+			if (!db_used)
+			{
+				fprintf(script, "In database: %s\n", active_db->db_name);
+				db_used = true;
+			}
+			fprintf(script, "  (oid=%s) %s.%s (%s.%s)\n",
+					PQgetvalue(res, rowno, i_oproid),
+					PQgetvalue(res, rowno, i_oprnsp),
+					PQgetvalue(res, rowno, i_oprname),
+					PQgetvalue(res, rowno, i_typnsp),
+					PQgetvalue(res, rowno, i_typname));
+		}
+
+		PQclear(res);
+
+		PQfinish(conn);
+	}
+
+	if (script)
+		fclose(script);
+
+	if (found)
+	{
+		pg_log(PG_REPORT, "fatal\n");
+		pg_fatal("Your installation contains user defined postfix operators, which is not\n"
+				 "supported anymore.  Consider dropping the postfix operators and replacing\n"
+				 "them with prefix operators or function calls.\n"
+				 "A list of user defined postfix operators is in the file:\n"
+				 "    %s\n\n", output_path);
+	}
+	else
+		check_ok();
+}
 
 /*
  * Verify that no tables are declared WITH OIDS.
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index d81f1575bf..1aaf5ccb38 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -805,7 +805,7 @@ describeOperators(const char *pattern, bool verbose, bool showSystem)
 					  "SELECT n.nspname as \"%s\",\n"
 					  "  o.oprname AS \"%s\",\n"
 					  "  CASE WHEN o.oprkind='l' THEN NULL ELSE pg_catalog.format_type(o.oprleft, NULL) END AS \"%s\",\n"
-					  "  CASE WHEN o.oprkind='r' THEN NULL ELSE pg_catalog.format_type(o.oprright, NULL) END AS \"%s\",\n"
+					  "  pg_catalog.format_type(o.oprright, NULL) AS \"%s\",\n"
 					  "  pg_catalog.format_type(o.oprresult, NULL) AS \"%s\",\n",
 					  gettext_noop("Schema"),
 					  gettext_noop("Name"),
diff --git a/src/include/catalog/pg_operator.dat b/src/include/catalog/pg_operator.dat
index 5b0e063655..9733f18de7 100644
--- a/src/include/catalog/pg_operator.dat
+++ b/src/include/catalog/pg_operator.dat
@@ -218,10 +218,7 @@
   oprname => '>=', oprleft => 'xid8', oprright => 'xid8', oprresult => 'bool',
   oprcom => '<=(xid8,xid8)', oprnegate => '<(xid8,xid8)', oprcode => 'xid8ge',
   oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' },
-{ oid => '388', descr => 'factorial',
-  oprname => '!', oprkind => 'r', oprleft => 'int8', oprright => '0',
-  oprresult => 'numeric', oprcode => 'numeric_fac' },
-{ oid => '389', descr => 'deprecated, use ! instead',
+{ oid => '389', descr => 'factorial',
   oprname => '!!', oprkind => 'l', oprleft => '0', oprright => 'int8',
   oprresult => 'numeric', oprcode => 'numeric_fac' },
 { oid => '385', descr => 'equal',
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index 1daa263852..1491b87582 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -41,7 +41,7 @@ CATALOG(pg_operator,2617,OperatorRelationId)
 	/* operator owner */
 	Oid			oprowner BKI_DEFAULT(PGUID);
 
-	/* 'l', 'r', or 'b' */
+	/* 'l' or 'b' */
 	char		oprkind BKI_DEFAULT(b);
 
 	/* can be used in merge join? */
@@ -53,7 +53,7 @@ CATALOG(pg_operator,2617,OperatorRelationId)
 	/* left arg type, or 0 if 'l' oprkind */
 	Oid			oprleft BKI_LOOKUP(pg_type);
 
-	/* right arg type, or 0 if 'r' oprkind */
+	/* right arg type */
 	Oid			oprright BKI_LOOKUP(pg_type);
 
 	/* result datatype */
diff --git a/src/test/regress/expected/create_operator.out b/src/test/regress/expected/create_operator.out
index 54e8b79159..83172cc073 100644
--- a/src/test/regress/expected/create_operator.out
+++ b/src/test/regress/expected/create_operator.out
@@ -22,10 +22,14 @@ CREATE OPERATOR #@# (
    leftarg = int8,		-- right unary
    procedure = numeric_fac
 );
+ERROR:  operator right argument must be specified
+HINT:  Postfix operators are not supported.
 CREATE OPERATOR #%# (
    leftarg = int8,		-- right unary
    procedure = numeric_fac
 );
+ERROR:  operator right argument must be specified
+HINT:  Postfix operators are not supported.
 -- Test operator created above
 SELECT point '(1,2)' <% widget '(0,0,3)' AS t,
        point '(1,2)' <% widget '(0,0,1)' AS f;
@@ -36,7 +40,9 @@ SELECT point '(1,2)' <% widget '(0,0,3)' AS t,
 
 -- Test comments
 COMMENT ON OPERATOR ###### (int4, NONE) IS 'bad right unary';
-ERROR:  operator does not exist: integer ######
+ERROR:  postfix operators are not supported
+COMMENT ON OPERATOR ###### (NONE, int4) IS 'bad left unary';
+ERROR:  operator does not exist: ###### integer
 -- => is disallowed now
 CREATE OPERATOR => (
    leftarg = int8,		-- right unary
@@ -52,12 +58,12 @@ CREATE OPERATOR !=- (
    leftarg = int8,		-- right unary
    procedure = numeric_fac
 );
+ERROR:  operator right argument must be specified
+HINT:  Postfix operators are not supported.
 SELECT 2 !=-;
- ?column? 
-----------
-        2
-(1 row)
-
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 2 !=-;
+                    ^
 -- make sure lexer returns != as <> even in edge cases
 SELECT 2 !=/**/ 1, 2 !=/**/ 2;
  ?column? | ?column? 
@@ -172,11 +178,13 @@ CREATE OPERATOR #@%# (
    invalid_att = int8
 );
 WARNING:  operator attribute "invalid_att" not recognized
--- Should fail. At least leftarg or rightarg should be mandatorily specified
+ERROR:  operator right argument must be specified
+HINT:  Postfix operators are not supported.
+-- Should fail. At least rightarg should be mandatorily specified
 CREATE OPERATOR #@%# (
    procedure = numeric_fac
 );
-ERROR:  at least one of leftarg or rightarg must be specified
+ERROR:  operator arguments must be specified
 -- Should fail. Procedure should be mandatorily specified
 CREATE OPERATOR #@%# (
    leftarg = int8
diff --git a/src/test/regress/expected/numeric.out b/src/test/regress/expected/numeric.out
index 8546ce901f..186cf1d507 100644
--- a/src/test/regress/expected/numeric.out
+++ b/src/test/regress/expected/numeric.out
@@ -2960,7 +2960,7 @@ ERROR:  value overflows numeric format
 --
 -- Tests for factorial
 --
-SELECT 4!;
+SELECT !!4;
  ?column? 
 ----------
        24
@@ -2978,19 +2978,30 @@ SELECT factorial(15);
  1307674368000
 (1 row)
 
-SELECT 100000!;
+SELECT !!100000;
 ERROR:  value overflows numeric format
-SELECT 0!;
+SELECT !!0;
  ?column? 
 ----------
         1
 (1 row)
 
-SELECT -4!;
+SELECT !!(-4);
 ERROR:  factorial of a negative number is undefined
 SELECT factorial(-4);
 ERROR:  factorial of a negative number is undefined
 --
+-- Postfix operators are not supported.  Check that.
+--
+SELECT -5!;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT -5!;
+                  ^
+SELECT 5!;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 5!;
+                 ^
+--
 -- Tests for pg_lsn()
 --
 SELECT pg_lsn(23783416::numeric);
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index 1b3c146e4c..7825a765cd 100644
--- a/src/test/regress/expected/opr_sanity.out
+++ b/src/test/regress/expected/opr_sanity.out
@@ -1066,7 +1066,7 @@ WHERE condefault AND
 -- Look for illegal values in pg_operator fields.
 SELECT p1.oid, p1.oprname
 FROM pg_operator as p1
-WHERE (p1.oprkind != 'b' AND p1.oprkind != 'l' AND p1.oprkind != 'r') OR
+WHERE (p1.oprkind != 'b' AND p1.oprkind != 'l') OR
     p1.oprresult = 0 OR p1.oprcode = 0;
  oid | oprname 
 -----+---------
@@ -1077,8 +1077,7 @@ SELECT p1.oid, p1.oprname
 FROM pg_operator as p1
 WHERE (p1.oprleft = 0 and p1.oprkind != 'l') OR
     (p1.oprleft != 0 and p1.oprkind = 'l') OR
-    (p1.oprright = 0 and p1.oprkind != 'r') OR
-    (p1.oprright != 0 and p1.oprkind = 'r');
+    p1.oprright = 0;
  oid | oprname 
 -----+---------
 (0 rows)
@@ -1285,18 +1284,6 @@ WHERE p1.oprcode = p2.oid AND
 -----+---------+-----+---------
 (0 rows)
 
-SELECT p1.oid, p1.oprname, p2.oid, p2.proname
-FROM pg_operator AS p1, pg_proc AS p2
-WHERE p1.oprcode = p2.oid AND
-    p1.oprkind = 'r' AND
-    (p2.pronargs != 1
-     OR NOT binary_coercible(p2.prorettype, p1.oprresult)
-     OR NOT binary_coercible(p1.oprleft, p2.proargtypes[0])
-     OR p1.oprright != 0);
- oid | oprname | oid | proname 
------+---------+-----+---------
-(0 rows)
-
 -- If the operator is mergejoinable or hashjoinable, its underlying function
 -- should not be volatile.
 SELECT p1.oid, p1.oprname, p2.oid, p2.proname
diff --git a/src/test/regress/sql/create_operator.sql b/src/test/regress/sql/create_operator.sql
index 8b6fd0bb43..94961d9899 100644
--- a/src/test/regress/sql/create_operator.sql
+++ b/src/test/regress/sql/create_operator.sql
@@ -38,6 +38,7 @@ SELECT point '(1,2)' <% widget '(0,0,3)' AS t,
 
 -- Test comments
 COMMENT ON OPERATOR ###### (int4, NONE) IS 'bad right unary';
+COMMENT ON OPERATOR ###### (NONE, int4) IS 'bad left unary';
 
 -- => is disallowed now
 CREATE OPERATOR => (
@@ -133,7 +134,7 @@ CREATE OPERATOR #@%# (
    invalid_att = int8
 );
 
--- Should fail. At least leftarg or rightarg should be mandatorily specified
+-- Should fail. At least rightarg should be mandatorily specified
 CREATE OPERATOR #@%# (
    procedure = numeric_fac
 );
diff --git a/src/test/regress/sql/numeric.sql b/src/test/regress/sql/numeric.sql
index 416c16722a..45602b00e1 100644
--- a/src/test/regress/sql/numeric.sql
+++ b/src/test/regress/sql/numeric.sql
@@ -1298,14 +1298,20 @@ SELECT lcm(9999 * (10::numeric)^131068 + (10::numeric^131068 - 1), 2); -- overfl
 --
 -- Tests for factorial
 --
-SELECT 4!;
+SELECT !!4;
 SELECT !!3;
 SELECT factorial(15);
-SELECT 100000!;
-SELECT 0!;
-SELECT -4!;
+SELECT !!100000;
+SELECT !!0;
+SELECT !!(-4);
 SELECT factorial(-4);
 
+--
+-- Postfix operators are not supported.  Check that.
+--
+SELECT -5!;
+SELECT 5!;
+
 --
 -- Tests for pg_lsn()
 --
diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql
index 7a9180b081..307aab1deb 100644
--- a/src/test/regress/sql/opr_sanity.sql
+++ b/src/test/regress/sql/opr_sanity.sql
@@ -571,7 +571,7 @@ WHERE condefault AND
 
 SELECT p1.oid, p1.oprname
 FROM pg_operator as p1
-WHERE (p1.oprkind != 'b' AND p1.oprkind != 'l' AND p1.oprkind != 'r') OR
+WHERE (p1.oprkind != 'b' AND p1.oprkind != 'l') OR
     p1.oprresult = 0 OR p1.oprcode = 0;
 
 -- Look for missing or unwanted operand types
@@ -580,8 +580,7 @@ SELECT p1.oid, p1.oprname
 FROM pg_operator as p1
 WHERE (p1.oprleft = 0 and p1.oprkind != 'l') OR
     (p1.oprleft != 0 and p1.oprkind = 'l') OR
-    (p1.oprright = 0 and p1.oprkind != 'r') OR
-    (p1.oprright != 0 and p1.oprkind = 'r');
+    p1.oprright = 0;
 
 -- Look for conflicting operator definitions (same names and input datatypes).
 
@@ -715,15 +714,6 @@ WHERE p1.oprcode = p2.oid AND
      OR NOT binary_coercible(p1.oprright, p2.proargtypes[0])
      OR p1.oprleft != 0);
 
-SELECT p1.oid, p1.oprname, p2.oid, p2.proname
-FROM pg_operator AS p1, pg_proc AS p2
-WHERE p1.oprcode = p2.oid AND
-    p1.oprkind = 'r' AND
-    (p2.pronargs != 1
-     OR NOT binary_coercible(p2.prorettype, p1.oprresult)
-     OR NOT binary_coercible(p1.oprleft, p2.proargtypes[0])
-     OR p1.oprright != 0);
-
 -- If the operator is mergejoinable or hashjoinable, its underlying function
 -- should not be volatile.
 
diff --git a/src/tutorial/syscat.source b/src/tutorial/syscat.source
index 3a1767f97b..a84ea0d5c9 100644
--- a/src/tutorial/syscat.source
+++ b/src/tutorial/syscat.source
@@ -110,20 +110,6 @@ SELECT n.nspname, o.oprname AS left_unary,
   ORDER BY nspname, operand;
 
 
---
--- lists all right unary operators
---
-SELECT n.nspname, o.oprname AS right_unary,
-       format_type(left_type.oid, null) AS operand,
-       format_type(result.oid, null) AS return_type
-  FROM pg_namespace n, pg_operator o,
-       pg_type left_type, pg_type result
-  WHERE o.oprnamespace = n.oid
-    and o.oprkind = 'r'          -- right unary
-    and o.oprleft = left_type.oid
-    and o.oprresult = result.oid
-  ORDER BY nspname, operand;
-
 --
 -- lists all binary operators
 --
-- 
2.21.1 (Apple Git-122.3)

v4-0002-Allow-most-keywords-to-be-used-as-implicit-column.patchapplication/octet-stream; name=v4-0002-Allow-most-keywords-to-be-used-as-implicit-column.patch; x-unix-mode=0644Download
From e8773e8727283682a3f5a3a24a7e41451987cac9 Mon Sep 17 00:00:00 2001
From: Mark Dilger <mark.dilger@enterprisedb.com>
Date: Tue, 25 Aug 2020 19:54:59 -0700
Subject: [PATCH v4 2/2] Allow most keywords to be used as implicit column
 labels.

Previously, to use a keyword as a column label in an expression, the
keyword had to be preceded by the token AS.  That is no longer
required for most keywords.  This is accomplished with some changes
to gram.y and by removing support for postfix operators.

These keywords must still be preceded by AS:

    array, as, char, character, create, day, except, fetch, filter,
    for, from, grant, group, having, hour, intersect, into, isnull,
    limit, minute, month, notnull, offset, on, order, over,
    overlaps, precision, returning, second, to, union, varying,
    where, window, with, within, without, year

Adding to the return value of pg_get_keywords a fourth column
showing whether the keyword can be used as an implicit column label.
---
 doc/src/sgml/func.sgml                  |   6 +-
 doc/src/sgml/generate-keywords-table.pl |   2 +-
 src/backend/parser/check_keywords.pl    |  97 ++-
 src/backend/parser/gram.y               | 439 +++++++++++-
 src/backend/parser/scan.l               |   2 +-
 src/backend/utils/adt/misc.c            |  11 +-
 src/common/keywords.c                   |   2 +-
 src/include/catalog/pg_proc.dat         |   6 +-
 src/include/common/kwlookup.h           |   8 +
 src/include/parser/kwlist.h             | 902 ++++++++++++------------
 src/interfaces/ecpg/preproc/keywords.c  |   2 +-
 src/tools/gen_keywordlist.pl            |  30 +-
 12 files changed, 1011 insertions(+), 496 deletions(-)

diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index bbbffd9d5b..4ac668bcac 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -22169,7 +22169,8 @@ 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>catdesc</parameter> <type>text</type>,
+        <parameter>aliastype</parameter> <type>text</type> )
        </para>
        <para>
         Returns a set of records describing the SQL keywords recognized by the
@@ -22181,6 +22182,9 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
         function name, or <literal>R</literal> for a fully reserved keyword.
         The <parameter>catdesc</parameter> column contains a
         possibly-localized string describing the category.
+        The <parameter>aliastype</parameter> column is
+        <literal>implicit</literal> if the keyword can be used as an implicit
+        column label, <literal>explicit</literal> otherwise.
        </para></entry>
       </row>
 
diff --git a/doc/src/sgml/generate-keywords-table.pl b/doc/src/sgml/generate-keywords-table.pl
index 824b324ef7..6ae6f80c3f 100644
--- a/doc/src/sgml/generate-keywords-table.pl
+++ b/doc/src/sgml/generate-keywords-table.pl
@@ -39,7 +39,7 @@ 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;
 	}
diff --git a/src/backend/parser/check_keywords.pl b/src/backend/parser/check_keywords.pl
index 702c97bba2..ddba00c96f 100644
--- a/src/backend/parser/check_keywords.pl
+++ b/src/backend/parser/check_keywords.pl
@@ -21,6 +21,27 @@ sub error
 	return;
 }
 
+sub check_alphabetical_order
+{
+	my ($listname, $list) = @_;
+	my $prevkword = '';
+	my $implicit_alias_kword;
+
+	foreach my $kword (@$list)
+	{
+
+		# Some keyword have a _P suffix. Remove it for the comparison.
+		$implicit_alias_kword = $kword;
+		$implicit_alias_kword =~ s/_P$//;
+		if ($implicit_alias_kword le $prevkword)
+		{
+			error
+			  "'$implicit_alias_kword' after '$prevkword' in $listname list is misplaced";
+		}
+		$prevkword = $implicit_alias_kword;
+	}
+}
+
 $, = ' ';     # set output field separator
 $\ = "\n";    # set output record separator
 
@@ -33,9 +54,11 @@ $keyword_categories{'reserved_keyword'}       = 'RESERVED_KEYWORD';
 open(my $gram, '<', $gram_filename) || die("Could not open : $gram_filename");
 
 my $kcat;
+my $implicit_alias;
 my $comment;
 my @arr;
 my %keywords;
+my @implicit_alias;
 
 line: while (my $S = <$gram>)
 {
@@ -51,7 +74,7 @@ line: while (my $S = <$gram>)
 	$s = '[/][*]', $S =~ s#$s# /* #g;
 	$s = '[*][/]', $S =~ s#$s# */ #g;
 
-	if (!($kcat))
+	if (!($kcat) && !($implicit_alias))
 	{
 
 		# Is this the beginning of a keyword list?
@@ -63,6 +86,10 @@ line: while (my $S = <$gram>)
 				next line;
 			}
 		}
+
+		# Is this the beginning of the implicit_alias_keyword list?
+		$implicit_alias = 1 if ($S =~ m/^implicit_alias_keyword:/);
+
 		next line;
 	}
 
@@ -97,7 +124,8 @@ line: while (my $S = <$gram>)
 		{
 
 			# end of keyword list
-			$kcat = '';
+			undef $kcat;
+			undef $implicit_alias;
 			next;
 		}
 
@@ -107,31 +135,21 @@ line: while (my $S = <$gram>)
 		}
 
 		# Put this keyword into the right list
-		push @{ $keywords{$kcat} }, $arr[$fieldIndexer];
+		if ($implicit_alias)
+		{
+			push @implicit_alias, $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('implicit_alias_keyword', \@implicit_alias);
 
 # Transform the keyword lists into hashes.
 # kwhashes is a hash of hashes, keyed by keyword category id,
@@ -147,6 +165,7 @@ while (my ($kcat, $kcat_id) = each(%keyword_categories))
 
 	$kwhashes{$kcat_id} = $hash;
 }
+my %implicit_alias = map { $_ => 1 } @implicit_alias;
 
 # Now read in kwlist.h
 
@@ -154,17 +173,41 @@ open(my $kwlist, '<', $kwlist_filename)
   || die("Could not open : $kwlist_filename");
 
 my $prevkwstring = '';
-my $bare_kwname;
+my $implicit_alias_kwname;
 my %kwhash;
 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 ($aliastype) = $4;
+
+		# Check that the keyword label aliastype value matches treatment in gram.y
+		if ($aliastype eq 'IMPLICIT_ALIAS')
+		{
+			unless ($implicit_alias{$kwname})
+			{
+				error
+				  "'$kwstring' in kwlist.h is marked as implicit_alias, but is missing from gram.y's implicit_alias_keyword rule";
+			}
+		}
+		elsif ($aliastype eq 'EXPLICIT_ALIAS')
+		{
+			if ($implicit_alias{$kwname})
+			{
+				error
+				  "'$kwname' in kwlist.h is marked as explicit, but is listed in gram.y's implicit_alias_keyword rule";
+			}
+		}
+		else
+		{
+			error
+			  "'$aliastype' not recognized in kwlist.h.  Expected either 'IMPLICIT_ALIAS' or 'EXPLICIT_ALIAS'";
+		}
 
 		# Check that the list is in alphabetical order (critical!)
 		if ($kwstring le $prevkwstring)
@@ -189,9 +232,9 @@ kwlist_line: while (<$kwlist>)
 		}
 
 		# Check that the keyword string matches keyword name
-		$bare_kwname = $kwname;
-		$bare_kwname =~ s/_P$//;
-		if ($bare_kwname ne uc($kwstring))
+		$implicit_alias_kwname = $kwname;
+		$implicit_alias_kwname =~ s/_P$//;
+		if ($implicit_alias_kwname ne uc($kwstring))
 		{
 			error
 			  "keyword name '$kwname' doesn't match keyword string '$kwstring'";
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 0171da5f4b..67754881e9 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -540,14 +540,15 @@ 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 ImplicitAlias
 %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> col_name_keyword implicit_alias_keyword reserved_keyword
 
 %type <node>	TableConstraint TableLikeClause
 %type <ival>	TableLikeOptionList TableLikeOption
@@ -14649,11 +14650,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 ImplicitAlias
 				{
 					$$ = makeNode(ResTarget);
 					$$->name = $2;
@@ -14981,6 +14978,12 @@ NonReservedWord:	IDENT							{ $$ = $1; }
 			| type_func_name_keyword				{ $$ = pstrdup($1); }
 		;
 
+/* Bare column label --- names that can be column labels without writing "AS".
+ */
+ImplicitAlias:	IDENT								{ $$ = $1; }
+			| implicit_alias_keyword					{ $$ = pstrdup($1); }
+		;
+
 /* Column label --- allowed labels in "AS" clauses.
  * This presently includes *all* Postgres keywords.
  */
@@ -14992,6 +14995,428 @@ ColLabel:	IDENT									{ $$ = $1; }
 		;
 
 
+/*
+ * All keywords can be used explicitly as a column label in expressions
+ * like 'SELECT 1234 AS keyword', but only some keywords can be used
+ * implicitly as column labels in expressions like 'SELECT 1234 keyword'.
+ * Those that can be used implicitly should be listed here.
+ *
+ * Keep this in alphabetical order.
+ */
+implicit_alias_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
+		;
+
 /*
  * Keyword category lists.  Generally, every keyword present in
  * the Postgres grammar should appear in exactly one of these lists.
diff --git a/src/backend/parser/scan.l b/src/backend/parser/scan.l
index b1ea0cb538..58a8afa782 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, aliastype) 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 37c23c9155..1b04b0e079 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -416,13 +416,15 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 		funcctx = SRF_FIRSTCALL_INIT();
 		oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
 
-		tupdesc = CreateTemplateTupleDesc(3);
+		tupdesc = CreateTemplateTupleDesc(4);
 		TupleDescInitEntry(tupdesc, (AttrNumber) 1, "word",
 						   TEXTOID, -1, 0);
 		TupleDescInitEntry(tupdesc, (AttrNumber) 2, "catcode",
 						   CHAROID, -1, 0);
 		TupleDescInitEntry(tupdesc, (AttrNumber) 3, "catdesc",
 						   TEXTOID, -1, 0);
+		TupleDescInitEntry(tupdesc, (AttrNumber) 4, "aliastype",
+						   TEXTOID, -1, 0);
 
 		funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
 
@@ -433,7 +435,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 	if (funcctx->call_cntr < ScanKeywords.num_keywords)
 	{
-		char	   *values[3];
+		char	   *values[4];
 		HeapTuple	tuple;
 
 		/* cast-away-const is ugly but alternatives aren't much better */
@@ -465,6 +467,11 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 				break;
 		}
 
+		if (GetScanKeywordIsImplicit(funcctx->call_cntr, &ScanKeywords))
+			values[3] = unconstify(char *, (const char *)"implicit");
+		else
+			values[3] = unconstify(char *, (const char *)"explicit");
+
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
 		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
diff --git a/src/common/keywords.c b/src/common/keywords.c
index 54ed977096..f42cd69094 100644
--- a/src/common/keywords.c
+++ b/src/common/keywords.c
@@ -24,7 +24,7 @@
 
 /* Keyword categories for SQL keywords */
 
-#define PG_KEYWORD(kwname, value, category) category,
+#define PG_KEYWORD(kwname, value, category, aliastype) category,
 
 const uint8 ScanKeywordCategories[SCANKEYWORDS_NUM_KEYWORDS] = {
 #include "parser/kwlist.h"
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 27989971db..d6fba056aa 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -3678,10 +3678,10 @@
   prosrc => 'pg_get_function_arg_default' },
 
 { oid => '1686', descr => 'list of SQL keywords',
-  proname => 'pg_get_keywords', procost => '10', prorows => '400',
+  proname => 'pg_get_keywords', procost => '10', prorows => '450',
   proretset => 't', provolatile => 's', prorettype => 'record',
-  proargtypes => '', proallargtypes => '{text,char,text}',
-  proargmodes => '{o,o,o}', proargnames => '{word,catcode,catdesc}',
+  proargtypes => '', proallargtypes => '{text,char,text,text}',
+  proargmodes => '{o,o,o,o}', proargnames => '{word,catcode,catdesc,aliastype}',
   prosrc => 'pg_get_keywords' },
 
 { oid => '2289', descr => 'convert generic options array to name/value table',
diff --git a/src/include/common/kwlookup.h b/src/include/common/kwlookup.h
index 9c0c7f88d8..d56b3d895e 100644
--- a/src/include/common/kwlookup.h
+++ b/src/include/common/kwlookup.h
@@ -26,6 +26,7 @@ typedef struct ScanKeywordList
 {
 	const char *kw_string;		/* all keywords in order, separated by \0 */
 	const uint16 *kw_offsets;	/* offsets to the start of each keyword */
+	const bool *kw_is_implicit;	/* whether each keyword can be used as an implicit label */
 	ScanKeywordHashFunc hash;	/* perfect hash function for keywords */
 	int			num_keywords;	/* number of keywords */
 	int			max_kw_len;		/* length of longest keyword */
@@ -41,4 +42,11 @@ GetScanKeyword(int n, const ScanKeywordList *keywords)
 	return keywords->kw_string + keywords->kw_offsets[n];
 }
 
+/* Code that wants to retrieve the aliastype of the N'th keyword should use this. */
+static inline bool
+GetScanKeywordIsImplicit(int n, const ScanKeywordList *keywords)
+{
+	return keywords->kw_is_implicit[n];
+}
+
 #endif							/* KWLOOKUP_H */
diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h
index 08f22ce211..d011b3a5e5 100644
--- a/src/include/parser/kwlist.h
+++ b/src/include/parser/kwlist.h
@@ -24,454 +24,454 @@
  * Note: gen_keywordlist.pl requires the entries to appear in ASCII order.
  */
 
-/* name, value, category */
-PG_KEYWORD("abort", ABORT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("absolute", ABSOLUTE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("access", ACCESS, UNRESERVED_KEYWORD)
-PG_KEYWORD("action", ACTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("add", ADD_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("admin", ADMIN, UNRESERVED_KEYWORD)
-PG_KEYWORD("after", AFTER, UNRESERVED_KEYWORD)
-PG_KEYWORD("aggregate", AGGREGATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("all", ALL, RESERVED_KEYWORD)
-PG_KEYWORD("also", ALSO, UNRESERVED_KEYWORD)
-PG_KEYWORD("alter", ALTER, UNRESERVED_KEYWORD)
-PG_KEYWORD("always", ALWAYS, UNRESERVED_KEYWORD)
-PG_KEYWORD("analyse", ANALYSE, RESERVED_KEYWORD)		/* British spelling */
-PG_KEYWORD("analyze", ANALYZE, RESERVED_KEYWORD)
-PG_KEYWORD("and", AND, RESERVED_KEYWORD)
-PG_KEYWORD("any", ANY, RESERVED_KEYWORD)
-PG_KEYWORD("array", ARRAY, RESERVED_KEYWORD)
-PG_KEYWORD("as", AS, RESERVED_KEYWORD)
-PG_KEYWORD("asc", ASC, RESERVED_KEYWORD)
-PG_KEYWORD("assertion", ASSERTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("assignment", ASSIGNMENT, UNRESERVED_KEYWORD)
-PG_KEYWORD("asymmetric", ASYMMETRIC, RESERVED_KEYWORD)
-PG_KEYWORD("at", AT, UNRESERVED_KEYWORD)
-PG_KEYWORD("attach", ATTACH, UNRESERVED_KEYWORD)
-PG_KEYWORD("attribute", ATTRIBUTE, UNRESERVED_KEYWORD)
-PG_KEYWORD("authorization", AUTHORIZATION, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("backward", BACKWARD, UNRESERVED_KEYWORD)
-PG_KEYWORD("before", BEFORE, UNRESERVED_KEYWORD)
-PG_KEYWORD("begin", BEGIN_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("between", BETWEEN, COL_NAME_KEYWORD)
-PG_KEYWORD("bigint", BIGINT, COL_NAME_KEYWORD)
-PG_KEYWORD("binary", BINARY, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("bit", BIT, COL_NAME_KEYWORD)
-PG_KEYWORD("boolean", BOOLEAN_P, COL_NAME_KEYWORD)
-PG_KEYWORD("both", BOTH, RESERVED_KEYWORD)
-PG_KEYWORD("by", BY, UNRESERVED_KEYWORD)
-PG_KEYWORD("cache", CACHE, UNRESERVED_KEYWORD)
-PG_KEYWORD("call", CALL, UNRESERVED_KEYWORD)
-PG_KEYWORD("called", CALLED, UNRESERVED_KEYWORD)
-PG_KEYWORD("cascade", CASCADE, UNRESERVED_KEYWORD)
-PG_KEYWORD("cascaded", CASCADED, UNRESERVED_KEYWORD)
-PG_KEYWORD("case", CASE, RESERVED_KEYWORD)
-PG_KEYWORD("cast", CAST, RESERVED_KEYWORD)
-PG_KEYWORD("catalog", CATALOG_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("chain", CHAIN, UNRESERVED_KEYWORD)
-PG_KEYWORD("char", CHAR_P, COL_NAME_KEYWORD)
-PG_KEYWORD("character", CHARACTER, COL_NAME_KEYWORD)
-PG_KEYWORD("characteristics", CHARACTERISTICS, UNRESERVED_KEYWORD)
-PG_KEYWORD("check", CHECK, RESERVED_KEYWORD)
-PG_KEYWORD("checkpoint", CHECKPOINT, UNRESERVED_KEYWORD)
-PG_KEYWORD("class", CLASS, UNRESERVED_KEYWORD)
-PG_KEYWORD("close", CLOSE, UNRESERVED_KEYWORD)
-PG_KEYWORD("cluster", CLUSTER, UNRESERVED_KEYWORD)
-PG_KEYWORD("coalesce", COALESCE, COL_NAME_KEYWORD)
-PG_KEYWORD("collate", COLLATE, RESERVED_KEYWORD)
-PG_KEYWORD("collation", COLLATION, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("column", COLUMN, RESERVED_KEYWORD)
-PG_KEYWORD("columns", COLUMNS, UNRESERVED_KEYWORD)
-PG_KEYWORD("comment", COMMENT, UNRESERVED_KEYWORD)
-PG_KEYWORD("comments", COMMENTS, UNRESERVED_KEYWORD)
-PG_KEYWORD("commit", COMMIT, UNRESERVED_KEYWORD)
-PG_KEYWORD("committed", COMMITTED, UNRESERVED_KEYWORD)
-PG_KEYWORD("concurrently", CONCURRENTLY, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("configuration", CONFIGURATION, UNRESERVED_KEYWORD)
-PG_KEYWORD("conflict", CONFLICT, UNRESERVED_KEYWORD)
-PG_KEYWORD("connection", CONNECTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("constraint", CONSTRAINT, RESERVED_KEYWORD)
-PG_KEYWORD("constraints", CONSTRAINTS, UNRESERVED_KEYWORD)
-PG_KEYWORD("content", CONTENT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("continue", CONTINUE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("conversion", CONVERSION_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("copy", COPY, UNRESERVED_KEYWORD)
-PG_KEYWORD("cost", COST, UNRESERVED_KEYWORD)
-PG_KEYWORD("create", CREATE, RESERVED_KEYWORD)
-PG_KEYWORD("cross", CROSS, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("csv", CSV, UNRESERVED_KEYWORD)
-PG_KEYWORD("cube", CUBE, UNRESERVED_KEYWORD)
-PG_KEYWORD("current", CURRENT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("current_catalog", CURRENT_CATALOG, RESERVED_KEYWORD)
-PG_KEYWORD("current_date", CURRENT_DATE, RESERVED_KEYWORD)
-PG_KEYWORD("current_role", CURRENT_ROLE, RESERVED_KEYWORD)
-PG_KEYWORD("current_schema", CURRENT_SCHEMA, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("current_time", CURRENT_TIME, RESERVED_KEYWORD)
-PG_KEYWORD("current_timestamp", CURRENT_TIMESTAMP, RESERVED_KEYWORD)
-PG_KEYWORD("current_user", CURRENT_USER, RESERVED_KEYWORD)
-PG_KEYWORD("cursor", CURSOR, UNRESERVED_KEYWORD)
-PG_KEYWORD("cycle", CYCLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("data", DATA_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("database", DATABASE, UNRESERVED_KEYWORD)
-PG_KEYWORD("day", DAY_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("deallocate", DEALLOCATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("dec", DEC, COL_NAME_KEYWORD)
-PG_KEYWORD("decimal", DECIMAL_P, COL_NAME_KEYWORD)
-PG_KEYWORD("declare", DECLARE, UNRESERVED_KEYWORD)
-PG_KEYWORD("default", DEFAULT, RESERVED_KEYWORD)
-PG_KEYWORD("defaults", DEFAULTS, UNRESERVED_KEYWORD)
-PG_KEYWORD("deferrable", DEFERRABLE, RESERVED_KEYWORD)
-PG_KEYWORD("deferred", DEFERRED, UNRESERVED_KEYWORD)
-PG_KEYWORD("definer", DEFINER, UNRESERVED_KEYWORD)
-PG_KEYWORD("delete", DELETE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("delimiter", DELIMITER, UNRESERVED_KEYWORD)
-PG_KEYWORD("delimiters", DELIMITERS, UNRESERVED_KEYWORD)
-PG_KEYWORD("depends", DEPENDS, UNRESERVED_KEYWORD)
-PG_KEYWORD("desc", DESC, RESERVED_KEYWORD)
-PG_KEYWORD("detach", DETACH, UNRESERVED_KEYWORD)
-PG_KEYWORD("dictionary", DICTIONARY, UNRESERVED_KEYWORD)
-PG_KEYWORD("disable", DISABLE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("discard", DISCARD, UNRESERVED_KEYWORD)
-PG_KEYWORD("distinct", DISTINCT, RESERVED_KEYWORD)
-PG_KEYWORD("do", DO, RESERVED_KEYWORD)
-PG_KEYWORD("document", DOCUMENT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("domain", DOMAIN_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("double", DOUBLE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("drop", DROP, UNRESERVED_KEYWORD)
-PG_KEYWORD("each", EACH, UNRESERVED_KEYWORD)
-PG_KEYWORD("else", ELSE, RESERVED_KEYWORD)
-PG_KEYWORD("enable", ENABLE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("encoding", ENCODING, UNRESERVED_KEYWORD)
-PG_KEYWORD("encrypted", ENCRYPTED, UNRESERVED_KEYWORD)
-PG_KEYWORD("end", END_P, RESERVED_KEYWORD)
-PG_KEYWORD("enum", ENUM_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("escape", ESCAPE, UNRESERVED_KEYWORD)
-PG_KEYWORD("event", EVENT, UNRESERVED_KEYWORD)
-PG_KEYWORD("except", EXCEPT, RESERVED_KEYWORD)
-PG_KEYWORD("exclude", EXCLUDE, UNRESERVED_KEYWORD)
-PG_KEYWORD("excluding", EXCLUDING, UNRESERVED_KEYWORD)
-PG_KEYWORD("exclusive", EXCLUSIVE, UNRESERVED_KEYWORD)
-PG_KEYWORD("execute", EXECUTE, UNRESERVED_KEYWORD)
-PG_KEYWORD("exists", EXISTS, COL_NAME_KEYWORD)
-PG_KEYWORD("explain", EXPLAIN, UNRESERVED_KEYWORD)
-PG_KEYWORD("expression", EXPRESSION, UNRESERVED_KEYWORD)
-PG_KEYWORD("extension", EXTENSION, UNRESERVED_KEYWORD)
-PG_KEYWORD("external", EXTERNAL, UNRESERVED_KEYWORD)
-PG_KEYWORD("extract", EXTRACT, COL_NAME_KEYWORD)
-PG_KEYWORD("false", FALSE_P, RESERVED_KEYWORD)
-PG_KEYWORD("family", FAMILY, UNRESERVED_KEYWORD)
-PG_KEYWORD("fetch", FETCH, RESERVED_KEYWORD)
-PG_KEYWORD("filter", FILTER, UNRESERVED_KEYWORD)
-PG_KEYWORD("first", FIRST_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("float", FLOAT_P, COL_NAME_KEYWORD)
-PG_KEYWORD("following", FOLLOWING, UNRESERVED_KEYWORD)
-PG_KEYWORD("for", FOR, RESERVED_KEYWORD)
-PG_KEYWORD("force", FORCE, UNRESERVED_KEYWORD)
-PG_KEYWORD("foreign", FOREIGN, RESERVED_KEYWORD)
-PG_KEYWORD("forward", FORWARD, UNRESERVED_KEYWORD)
-PG_KEYWORD("freeze", FREEZE, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("from", FROM, RESERVED_KEYWORD)
-PG_KEYWORD("full", FULL, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("function", FUNCTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("functions", FUNCTIONS, UNRESERVED_KEYWORD)
-PG_KEYWORD("generated", GENERATED, UNRESERVED_KEYWORD)
-PG_KEYWORD("global", GLOBAL, UNRESERVED_KEYWORD)
-PG_KEYWORD("grant", GRANT, RESERVED_KEYWORD)
-PG_KEYWORD("granted", GRANTED, UNRESERVED_KEYWORD)
-PG_KEYWORD("greatest", GREATEST, COL_NAME_KEYWORD)
-PG_KEYWORD("group", GROUP_P, RESERVED_KEYWORD)
-PG_KEYWORD("grouping", GROUPING, COL_NAME_KEYWORD)
-PG_KEYWORD("groups", GROUPS, UNRESERVED_KEYWORD)
-PG_KEYWORD("handler", HANDLER, UNRESERVED_KEYWORD)
-PG_KEYWORD("having", HAVING, RESERVED_KEYWORD)
-PG_KEYWORD("header", HEADER_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("hold", HOLD, UNRESERVED_KEYWORD)
-PG_KEYWORD("hour", HOUR_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("identity", IDENTITY_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("if", IF_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("ilike", ILIKE, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("immediate", IMMEDIATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("immutable", IMMUTABLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("implicit", IMPLICIT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("import", IMPORT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("in", IN_P, RESERVED_KEYWORD)
-PG_KEYWORD("include", INCLUDE, UNRESERVED_KEYWORD)
-PG_KEYWORD("including", INCLUDING, UNRESERVED_KEYWORD)
-PG_KEYWORD("increment", INCREMENT, UNRESERVED_KEYWORD)
-PG_KEYWORD("index", INDEX, UNRESERVED_KEYWORD)
-PG_KEYWORD("indexes", INDEXES, UNRESERVED_KEYWORD)
-PG_KEYWORD("inherit", INHERIT, UNRESERVED_KEYWORD)
-PG_KEYWORD("inherits", INHERITS, UNRESERVED_KEYWORD)
-PG_KEYWORD("initially", INITIALLY, RESERVED_KEYWORD)
-PG_KEYWORD("inline", INLINE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("inner", INNER_P, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("inout", INOUT, COL_NAME_KEYWORD)
-PG_KEYWORD("input", INPUT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("insensitive", INSENSITIVE, UNRESERVED_KEYWORD)
-PG_KEYWORD("insert", INSERT, UNRESERVED_KEYWORD)
-PG_KEYWORD("instead", INSTEAD, UNRESERVED_KEYWORD)
-PG_KEYWORD("int", INT_P, COL_NAME_KEYWORD)
-PG_KEYWORD("integer", INTEGER, COL_NAME_KEYWORD)
-PG_KEYWORD("intersect", INTERSECT, RESERVED_KEYWORD)
-PG_KEYWORD("interval", INTERVAL, COL_NAME_KEYWORD)
-PG_KEYWORD("into", INTO, RESERVED_KEYWORD)
-PG_KEYWORD("invoker", INVOKER, UNRESERVED_KEYWORD)
-PG_KEYWORD("is", IS, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("isnull", ISNULL, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("isolation", ISOLATION, UNRESERVED_KEYWORD)
-PG_KEYWORD("join", JOIN, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("key", KEY, UNRESERVED_KEYWORD)
-PG_KEYWORD("label", LABEL, UNRESERVED_KEYWORD)
-PG_KEYWORD("language", LANGUAGE, UNRESERVED_KEYWORD)
-PG_KEYWORD("large", LARGE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("last", LAST_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("lateral", LATERAL_P, RESERVED_KEYWORD)
-PG_KEYWORD("leading", LEADING, RESERVED_KEYWORD)
-PG_KEYWORD("leakproof", LEAKPROOF, UNRESERVED_KEYWORD)
-PG_KEYWORD("least", LEAST, COL_NAME_KEYWORD)
-PG_KEYWORD("left", LEFT, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("level", LEVEL, UNRESERVED_KEYWORD)
-PG_KEYWORD("like", LIKE, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("limit", LIMIT, RESERVED_KEYWORD)
-PG_KEYWORD("listen", LISTEN, UNRESERVED_KEYWORD)
-PG_KEYWORD("load", LOAD, UNRESERVED_KEYWORD)
-PG_KEYWORD("local", LOCAL, UNRESERVED_KEYWORD)
-PG_KEYWORD("localtime", LOCALTIME, RESERVED_KEYWORD)
-PG_KEYWORD("localtimestamp", LOCALTIMESTAMP, RESERVED_KEYWORD)
-PG_KEYWORD("location", LOCATION, UNRESERVED_KEYWORD)
-PG_KEYWORD("lock", LOCK_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("locked", LOCKED, UNRESERVED_KEYWORD)
-PG_KEYWORD("logged", LOGGED, UNRESERVED_KEYWORD)
-PG_KEYWORD("mapping", MAPPING, UNRESERVED_KEYWORD)
-PG_KEYWORD("match", MATCH, UNRESERVED_KEYWORD)
-PG_KEYWORD("materialized", MATERIALIZED, UNRESERVED_KEYWORD)
-PG_KEYWORD("maxvalue", MAXVALUE, UNRESERVED_KEYWORD)
-PG_KEYWORD("method", METHOD, UNRESERVED_KEYWORD)
-PG_KEYWORD("minute", MINUTE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("minvalue", MINVALUE, UNRESERVED_KEYWORD)
-PG_KEYWORD("mode", MODE, UNRESERVED_KEYWORD)
-PG_KEYWORD("month", MONTH_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("move", MOVE, UNRESERVED_KEYWORD)
-PG_KEYWORD("name", NAME_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("names", NAMES, UNRESERVED_KEYWORD)
-PG_KEYWORD("national", NATIONAL, COL_NAME_KEYWORD)
-PG_KEYWORD("natural", NATURAL, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("nchar", NCHAR, COL_NAME_KEYWORD)
-PG_KEYWORD("new", NEW, UNRESERVED_KEYWORD)
-PG_KEYWORD("next", NEXT, UNRESERVED_KEYWORD)
-PG_KEYWORD("nfc", NFC, UNRESERVED_KEYWORD)
-PG_KEYWORD("nfd", NFD, UNRESERVED_KEYWORD)
-PG_KEYWORD("nfkc", NFKC, UNRESERVED_KEYWORD)
-PG_KEYWORD("nfkd", NFKD, UNRESERVED_KEYWORD)
-PG_KEYWORD("no", NO, UNRESERVED_KEYWORD)
-PG_KEYWORD("none", NONE, COL_NAME_KEYWORD)
-PG_KEYWORD("normalize", NORMALIZE, COL_NAME_KEYWORD)
-PG_KEYWORD("normalized", NORMALIZED, UNRESERVED_KEYWORD)
-PG_KEYWORD("not", NOT, RESERVED_KEYWORD)
-PG_KEYWORD("nothing", NOTHING, UNRESERVED_KEYWORD)
-PG_KEYWORD("notify", NOTIFY, UNRESERVED_KEYWORD)
-PG_KEYWORD("notnull", NOTNULL, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("nowait", NOWAIT, UNRESERVED_KEYWORD)
-PG_KEYWORD("null", NULL_P, RESERVED_KEYWORD)
-PG_KEYWORD("nullif", NULLIF, COL_NAME_KEYWORD)
-PG_KEYWORD("nulls", NULLS_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("numeric", NUMERIC, COL_NAME_KEYWORD)
-PG_KEYWORD("object", OBJECT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("of", OF, UNRESERVED_KEYWORD)
-PG_KEYWORD("off", OFF, UNRESERVED_KEYWORD)
-PG_KEYWORD("offset", OFFSET, RESERVED_KEYWORD)
-PG_KEYWORD("oids", OIDS, UNRESERVED_KEYWORD)
-PG_KEYWORD("old", OLD, UNRESERVED_KEYWORD)
-PG_KEYWORD("on", ON, RESERVED_KEYWORD)
-PG_KEYWORD("only", ONLY, RESERVED_KEYWORD)
-PG_KEYWORD("operator", OPERATOR, UNRESERVED_KEYWORD)
-PG_KEYWORD("option", OPTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("options", OPTIONS, UNRESERVED_KEYWORD)
-PG_KEYWORD("or", OR, RESERVED_KEYWORD)
-PG_KEYWORD("order", ORDER, RESERVED_KEYWORD)
-PG_KEYWORD("ordinality", ORDINALITY, UNRESERVED_KEYWORD)
-PG_KEYWORD("others", OTHERS, UNRESERVED_KEYWORD)
-PG_KEYWORD("out", OUT_P, COL_NAME_KEYWORD)
-PG_KEYWORD("outer", OUTER_P, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("over", OVER, UNRESERVED_KEYWORD)
-PG_KEYWORD("overlaps", OVERLAPS, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("overlay", OVERLAY, COL_NAME_KEYWORD)
-PG_KEYWORD("overriding", OVERRIDING, UNRESERVED_KEYWORD)
-PG_KEYWORD("owned", OWNED, UNRESERVED_KEYWORD)
-PG_KEYWORD("owner", OWNER, UNRESERVED_KEYWORD)
-PG_KEYWORD("parallel", PARALLEL, UNRESERVED_KEYWORD)
-PG_KEYWORD("parser", PARSER, UNRESERVED_KEYWORD)
-PG_KEYWORD("partial", PARTIAL, UNRESERVED_KEYWORD)
-PG_KEYWORD("partition", PARTITION, UNRESERVED_KEYWORD)
-PG_KEYWORD("passing", PASSING, UNRESERVED_KEYWORD)
-PG_KEYWORD("password", PASSWORD, UNRESERVED_KEYWORD)
-PG_KEYWORD("placing", PLACING, RESERVED_KEYWORD)
-PG_KEYWORD("plans", PLANS, UNRESERVED_KEYWORD)
-PG_KEYWORD("policy", POLICY, UNRESERVED_KEYWORD)
-PG_KEYWORD("position", POSITION, COL_NAME_KEYWORD)
-PG_KEYWORD("preceding", PRECEDING, UNRESERVED_KEYWORD)
-PG_KEYWORD("precision", PRECISION, COL_NAME_KEYWORD)
-PG_KEYWORD("prepare", PREPARE, UNRESERVED_KEYWORD)
-PG_KEYWORD("prepared", PREPARED, UNRESERVED_KEYWORD)
-PG_KEYWORD("preserve", PRESERVE, UNRESERVED_KEYWORD)
-PG_KEYWORD("primary", PRIMARY, RESERVED_KEYWORD)
-PG_KEYWORD("prior", PRIOR, UNRESERVED_KEYWORD)
-PG_KEYWORD("privileges", PRIVILEGES, UNRESERVED_KEYWORD)
-PG_KEYWORD("procedural", PROCEDURAL, UNRESERVED_KEYWORD)
-PG_KEYWORD("procedure", PROCEDURE, UNRESERVED_KEYWORD)
-PG_KEYWORD("procedures", PROCEDURES, UNRESERVED_KEYWORD)
-PG_KEYWORD("program", PROGRAM, UNRESERVED_KEYWORD)
-PG_KEYWORD("publication", PUBLICATION, UNRESERVED_KEYWORD)
-PG_KEYWORD("quote", QUOTE, UNRESERVED_KEYWORD)
-PG_KEYWORD("range", RANGE, UNRESERVED_KEYWORD)
-PG_KEYWORD("read", READ, UNRESERVED_KEYWORD)
-PG_KEYWORD("real", REAL, COL_NAME_KEYWORD)
-PG_KEYWORD("reassign", REASSIGN, UNRESERVED_KEYWORD)
-PG_KEYWORD("recheck", RECHECK, UNRESERVED_KEYWORD)
-PG_KEYWORD("recursive", RECURSIVE, UNRESERVED_KEYWORD)
-PG_KEYWORD("ref", REF, UNRESERVED_KEYWORD)
-PG_KEYWORD("references", REFERENCES, RESERVED_KEYWORD)
-PG_KEYWORD("referencing", REFERENCING, UNRESERVED_KEYWORD)
-PG_KEYWORD("refresh", REFRESH, UNRESERVED_KEYWORD)
-PG_KEYWORD("reindex", REINDEX, UNRESERVED_KEYWORD)
-PG_KEYWORD("relative", RELATIVE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("release", RELEASE, UNRESERVED_KEYWORD)
-PG_KEYWORD("rename", RENAME, UNRESERVED_KEYWORD)
-PG_KEYWORD("repeatable", REPEATABLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("replace", REPLACE, UNRESERVED_KEYWORD)
-PG_KEYWORD("replica", REPLICA, UNRESERVED_KEYWORD)
-PG_KEYWORD("reset", RESET, UNRESERVED_KEYWORD)
-PG_KEYWORD("restart", RESTART, UNRESERVED_KEYWORD)
-PG_KEYWORD("restrict", RESTRICT, UNRESERVED_KEYWORD)
-PG_KEYWORD("returning", RETURNING, RESERVED_KEYWORD)
-PG_KEYWORD("returns", RETURNS, UNRESERVED_KEYWORD)
-PG_KEYWORD("revoke", REVOKE, UNRESERVED_KEYWORD)
-PG_KEYWORD("right", RIGHT, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("role", ROLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("rollback", ROLLBACK, UNRESERVED_KEYWORD)
-PG_KEYWORD("rollup", ROLLUP, UNRESERVED_KEYWORD)
-PG_KEYWORD("routine", ROUTINE, UNRESERVED_KEYWORD)
-PG_KEYWORD("routines", ROUTINES, UNRESERVED_KEYWORD)
-PG_KEYWORD("row", ROW, COL_NAME_KEYWORD)
-PG_KEYWORD("rows", ROWS, UNRESERVED_KEYWORD)
-PG_KEYWORD("rule", RULE, UNRESERVED_KEYWORD)
-PG_KEYWORD("savepoint", SAVEPOINT, UNRESERVED_KEYWORD)
-PG_KEYWORD("schema", SCHEMA, UNRESERVED_KEYWORD)
-PG_KEYWORD("schemas", SCHEMAS, UNRESERVED_KEYWORD)
-PG_KEYWORD("scroll", SCROLL, UNRESERVED_KEYWORD)
-PG_KEYWORD("search", SEARCH, UNRESERVED_KEYWORD)
-PG_KEYWORD("second", SECOND_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("security", SECURITY, UNRESERVED_KEYWORD)
-PG_KEYWORD("select", SELECT, RESERVED_KEYWORD)
-PG_KEYWORD("sequence", SEQUENCE, UNRESERVED_KEYWORD)
-PG_KEYWORD("sequences", SEQUENCES, UNRESERVED_KEYWORD)
-PG_KEYWORD("serializable", SERIALIZABLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("server", SERVER, UNRESERVED_KEYWORD)
-PG_KEYWORD("session", SESSION, UNRESERVED_KEYWORD)
-PG_KEYWORD("session_user", SESSION_USER, RESERVED_KEYWORD)
-PG_KEYWORD("set", SET, UNRESERVED_KEYWORD)
-PG_KEYWORD("setof", SETOF, COL_NAME_KEYWORD)
-PG_KEYWORD("sets", SETS, UNRESERVED_KEYWORD)
-PG_KEYWORD("share", SHARE, UNRESERVED_KEYWORD)
-PG_KEYWORD("show", SHOW, UNRESERVED_KEYWORD)
-PG_KEYWORD("similar", SIMILAR, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("simple", SIMPLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("skip", SKIP, UNRESERVED_KEYWORD)
-PG_KEYWORD("smallint", SMALLINT, COL_NAME_KEYWORD)
-PG_KEYWORD("snapshot", SNAPSHOT, UNRESERVED_KEYWORD)
-PG_KEYWORD("some", SOME, RESERVED_KEYWORD)
-PG_KEYWORD("sql", SQL_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("stable", STABLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("standalone", STANDALONE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("start", START, UNRESERVED_KEYWORD)
-PG_KEYWORD("statement", STATEMENT, UNRESERVED_KEYWORD)
-PG_KEYWORD("statistics", STATISTICS, UNRESERVED_KEYWORD)
-PG_KEYWORD("stdin", STDIN, UNRESERVED_KEYWORD)
-PG_KEYWORD("stdout", STDOUT, UNRESERVED_KEYWORD)
-PG_KEYWORD("storage", STORAGE, UNRESERVED_KEYWORD)
-PG_KEYWORD("stored", STORED, UNRESERVED_KEYWORD)
-PG_KEYWORD("strict", STRICT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("strip", STRIP_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("subscription", SUBSCRIPTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("substring", SUBSTRING, COL_NAME_KEYWORD)
-PG_KEYWORD("support", SUPPORT, UNRESERVED_KEYWORD)
-PG_KEYWORD("symmetric", SYMMETRIC, RESERVED_KEYWORD)
-PG_KEYWORD("sysid", SYSID, UNRESERVED_KEYWORD)
-PG_KEYWORD("system", SYSTEM_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("table", TABLE, RESERVED_KEYWORD)
-PG_KEYWORD("tables", TABLES, UNRESERVED_KEYWORD)
-PG_KEYWORD("tablesample", TABLESAMPLE, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("tablespace", TABLESPACE, UNRESERVED_KEYWORD)
-PG_KEYWORD("temp", TEMP, UNRESERVED_KEYWORD)
-PG_KEYWORD("template", TEMPLATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("temporary", TEMPORARY, UNRESERVED_KEYWORD)
-PG_KEYWORD("text", TEXT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("then", THEN, RESERVED_KEYWORD)
-PG_KEYWORD("ties", TIES, UNRESERVED_KEYWORD)
-PG_KEYWORD("time", TIME, COL_NAME_KEYWORD)
-PG_KEYWORD("timestamp", TIMESTAMP, COL_NAME_KEYWORD)
-PG_KEYWORD("to", TO, RESERVED_KEYWORD)
-PG_KEYWORD("trailing", TRAILING, RESERVED_KEYWORD)
-PG_KEYWORD("transaction", TRANSACTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("transform", TRANSFORM, UNRESERVED_KEYWORD)
-PG_KEYWORD("treat", TREAT, COL_NAME_KEYWORD)
-PG_KEYWORD("trigger", TRIGGER, UNRESERVED_KEYWORD)
-PG_KEYWORD("trim", TRIM, COL_NAME_KEYWORD)
-PG_KEYWORD("true", TRUE_P, RESERVED_KEYWORD)
-PG_KEYWORD("truncate", TRUNCATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("trusted", TRUSTED, UNRESERVED_KEYWORD)
-PG_KEYWORD("type", TYPE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("types", TYPES_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("uescape", UESCAPE, UNRESERVED_KEYWORD)
-PG_KEYWORD("unbounded", UNBOUNDED, UNRESERVED_KEYWORD)
-PG_KEYWORD("uncommitted", UNCOMMITTED, UNRESERVED_KEYWORD)
-PG_KEYWORD("unencrypted", UNENCRYPTED, UNRESERVED_KEYWORD)
-PG_KEYWORD("union", UNION, RESERVED_KEYWORD)
-PG_KEYWORD("unique", UNIQUE, RESERVED_KEYWORD)
-PG_KEYWORD("unknown", UNKNOWN, UNRESERVED_KEYWORD)
-PG_KEYWORD("unlisten", UNLISTEN, UNRESERVED_KEYWORD)
-PG_KEYWORD("unlogged", UNLOGGED, UNRESERVED_KEYWORD)
-PG_KEYWORD("until", UNTIL, UNRESERVED_KEYWORD)
-PG_KEYWORD("update", UPDATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("user", USER, RESERVED_KEYWORD)
-PG_KEYWORD("using", USING, RESERVED_KEYWORD)
-PG_KEYWORD("vacuum", VACUUM, UNRESERVED_KEYWORD)
-PG_KEYWORD("valid", VALID, UNRESERVED_KEYWORD)
-PG_KEYWORD("validate", VALIDATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("validator", VALIDATOR, UNRESERVED_KEYWORD)
-PG_KEYWORD("value", VALUE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("values", VALUES, COL_NAME_KEYWORD)
-PG_KEYWORD("varchar", VARCHAR, COL_NAME_KEYWORD)
-PG_KEYWORD("variadic", VARIADIC, RESERVED_KEYWORD)
-PG_KEYWORD("varying", VARYING, UNRESERVED_KEYWORD)
-PG_KEYWORD("verbose", VERBOSE, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("version", VERSION_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("view", VIEW, UNRESERVED_KEYWORD)
-PG_KEYWORD("views", VIEWS, UNRESERVED_KEYWORD)
-PG_KEYWORD("volatile", VOLATILE, UNRESERVED_KEYWORD)
-PG_KEYWORD("when", WHEN, RESERVED_KEYWORD)
-PG_KEYWORD("where", WHERE, RESERVED_KEYWORD)
-PG_KEYWORD("whitespace", WHITESPACE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("window", WINDOW, RESERVED_KEYWORD)
-PG_KEYWORD("with", WITH, RESERVED_KEYWORD)
-PG_KEYWORD("within", WITHIN, UNRESERVED_KEYWORD)
-PG_KEYWORD("without", WITHOUT, UNRESERVED_KEYWORD)
-PG_KEYWORD("work", WORK, UNRESERVED_KEYWORD)
-PG_KEYWORD("wrapper", WRAPPER, UNRESERVED_KEYWORD)
-PG_KEYWORD("write", WRITE, UNRESERVED_KEYWORD)
-PG_KEYWORD("xml", XML_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("xmlattributes", XMLATTRIBUTES, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlconcat", XMLCONCAT, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlelement", XMLELEMENT, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlexists", XMLEXISTS, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlforest", XMLFOREST, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlnamespaces", XMLNAMESPACES, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlparse", XMLPARSE, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlpi", XMLPI, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlroot", XMLROOT, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlserialize", XMLSERIALIZE, COL_NAME_KEYWORD)
-PG_KEYWORD("xmltable", XMLTABLE, COL_NAME_KEYWORD)
-PG_KEYWORD("year", YEAR_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("yes", YES_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("zone", ZONE, UNRESERVED_KEYWORD)
+/* name, value, category, aliastype */
+PG_KEYWORD("abort", ABORT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("absolute", ABSOLUTE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("access", ACCESS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("action", ACTION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("add", ADD_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("admin", ADMIN, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("after", AFTER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("aggregate", AGGREGATE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("all", ALL, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("also", ALSO, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("alter", ALTER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("always", ALWAYS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("analyse", ANALYSE, RESERVED_KEYWORD, IMPLICIT_ALIAS)		/* British spelling */
+PG_KEYWORD("analyze", ANALYZE, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("and", AND, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("any", ANY, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("array", ARRAY, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("as", AS, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("asc", ASC, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("assertion", ASSERTION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("assignment", ASSIGNMENT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("asymmetric", ASYMMETRIC, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("at", AT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("attach", ATTACH, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("attribute", ATTRIBUTE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("authorization", AUTHORIZATION, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("backward", BACKWARD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("before", BEFORE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("begin", BEGIN_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("between", BETWEEN, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("bigint", BIGINT, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("binary", BINARY, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("bit", BIT, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("boolean", BOOLEAN_P, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("both", BOTH, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("by", BY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("cache", CACHE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("call", CALL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("called", CALLED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("cascade", CASCADE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("cascaded", CASCADED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("case", CASE, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("cast", CAST, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("catalog", CATALOG_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("chain", CHAIN, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("char", CHAR_P, COL_NAME_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("character", CHARACTER, COL_NAME_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("characteristics", CHARACTERISTICS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("check", CHECK, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("checkpoint", CHECKPOINT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("class", CLASS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("close", CLOSE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("cluster", CLUSTER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("coalesce", COALESCE, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("collate", COLLATE, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("collation", COLLATION, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("column", COLUMN, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("columns", COLUMNS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("comment", COMMENT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("comments", COMMENTS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("commit", COMMIT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("committed", COMMITTED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("concurrently", CONCURRENTLY, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("configuration", CONFIGURATION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("conflict", CONFLICT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("connection", CONNECTION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("constraint", CONSTRAINT, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("constraints", CONSTRAINTS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("content", CONTENT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("continue", CONTINUE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("conversion", CONVERSION_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("copy", COPY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("cost", COST, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("create", CREATE, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("cross", CROSS, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("csv", CSV, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("cube", CUBE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("current", CURRENT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("current_catalog", CURRENT_CATALOG, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("current_date", CURRENT_DATE, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("current_role", CURRENT_ROLE, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("current_schema", CURRENT_SCHEMA, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("current_time", CURRENT_TIME, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("current_timestamp", CURRENT_TIMESTAMP, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("current_user", CURRENT_USER, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("cursor", CURSOR, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("cycle", CYCLE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("data", DATA_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("database", DATABASE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("day", DAY_P, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("deallocate", DEALLOCATE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("dec", DEC, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("decimal", DECIMAL_P, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("declare", DECLARE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("default", DEFAULT, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("defaults", DEFAULTS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("deferrable", DEFERRABLE, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("deferred", DEFERRED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("definer", DEFINER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("delete", DELETE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("delimiter", DELIMITER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("delimiters", DELIMITERS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("depends", DEPENDS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("desc", DESC, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("detach", DETACH, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("dictionary", DICTIONARY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("disable", DISABLE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("discard", DISCARD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("distinct", DISTINCT, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("do", DO, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("document", DOCUMENT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("domain", DOMAIN_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("double", DOUBLE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("drop", DROP, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("each", EACH, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("else", ELSE, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("enable", ENABLE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("encoding", ENCODING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("encrypted", ENCRYPTED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("end", END_P, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("enum", ENUM_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("escape", ESCAPE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("event", EVENT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("except", EXCEPT, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("exclude", EXCLUDE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("excluding", EXCLUDING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("exclusive", EXCLUSIVE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("execute", EXECUTE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("exists", EXISTS, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("explain", EXPLAIN, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("expression", EXPRESSION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("extension", EXTENSION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("external", EXTERNAL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("extract", EXTRACT, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("false", FALSE_P, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("family", FAMILY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("fetch", FETCH, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("filter", FILTER, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("first", FIRST_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("float", FLOAT_P, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("following", FOLLOWING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("for", FOR, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("force", FORCE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("foreign", FOREIGN, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("forward", FORWARD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("freeze", FREEZE, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("from", FROM, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("full", FULL, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("function", FUNCTION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("functions", FUNCTIONS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("generated", GENERATED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("global", GLOBAL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("grant", GRANT, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("granted", GRANTED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("greatest", GREATEST, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("group", GROUP_P, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("grouping", GROUPING, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("groups", GROUPS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("handler", HANDLER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("having", HAVING, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("header", HEADER_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("hold", HOLD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("hour", HOUR_P, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("identity", IDENTITY_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("if", IF_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("ilike", ILIKE, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("immediate", IMMEDIATE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("immutable", IMMUTABLE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("implicit", IMPLICIT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("import", IMPORT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("in", IN_P, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("include", INCLUDE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("including", INCLUDING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("increment", INCREMENT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("index", INDEX, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("indexes", INDEXES, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("inherit", INHERIT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("inherits", INHERITS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("initially", INITIALLY, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("inline", INLINE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("inner", INNER_P, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("inout", INOUT, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("input", INPUT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("insensitive", INSENSITIVE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("insert", INSERT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("instead", INSTEAD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("int", INT_P, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("integer", INTEGER, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("intersect", INTERSECT, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("interval", INTERVAL, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("into", INTO, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("invoker", INVOKER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("is", IS, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("isnull", ISNULL, TYPE_FUNC_NAME_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("isolation", ISOLATION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("join", JOIN, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("key", KEY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("label", LABEL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("language", LANGUAGE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("large", LARGE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("last", LAST_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("lateral", LATERAL_P, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("leading", LEADING, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("leakproof", LEAKPROOF, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("least", LEAST, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("left", LEFT, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("level", LEVEL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("like", LIKE, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("limit", LIMIT, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("listen", LISTEN, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("load", LOAD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("local", LOCAL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("localtime", LOCALTIME, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("localtimestamp", LOCALTIMESTAMP, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("location", LOCATION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("lock", LOCK_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("locked", LOCKED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("logged", LOGGED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("mapping", MAPPING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("match", MATCH, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("materialized", MATERIALIZED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("maxvalue", MAXVALUE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("method", METHOD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("minute", MINUTE_P, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("minvalue", MINVALUE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("mode", MODE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("month", MONTH_P, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("move", MOVE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("name", NAME_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("names", NAMES, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("national", NATIONAL, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("natural", NATURAL, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("nchar", NCHAR, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("new", NEW, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("next", NEXT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("nfc", NFC, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("nfd", NFD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("nfkc", NFKC, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("nfkd", NFKD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("no", NO, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("none", NONE, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("normalize", NORMALIZE, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("normalized", NORMALIZED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("not", NOT, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("nothing", NOTHING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("notify", NOTIFY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("notnull", NOTNULL, TYPE_FUNC_NAME_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("nowait", NOWAIT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("null", NULL_P, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("nullif", NULLIF, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("nulls", NULLS_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("numeric", NUMERIC, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("object", OBJECT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("of", OF, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("off", OFF, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("offset", OFFSET, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("oids", OIDS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("old", OLD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("on", ON, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("only", ONLY, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("operator", OPERATOR, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("option", OPTION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("options", OPTIONS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("or", OR, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("order", ORDER, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("ordinality", ORDINALITY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("others", OTHERS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("out", OUT_P, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("outer", OUTER_P, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("over", OVER, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("overlaps", OVERLAPS, TYPE_FUNC_NAME_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("overlay", OVERLAY, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("overriding", OVERRIDING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("owned", OWNED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("owner", OWNER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("parallel", PARALLEL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("parser", PARSER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("partial", PARTIAL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("partition", PARTITION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("passing", PASSING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("password", PASSWORD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("placing", PLACING, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("plans", PLANS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("policy", POLICY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("position", POSITION, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("preceding", PRECEDING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("precision", PRECISION, COL_NAME_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("prepare", PREPARE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("prepared", PREPARED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("preserve", PRESERVE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("primary", PRIMARY, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("prior", PRIOR, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("privileges", PRIVILEGES, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("procedural", PROCEDURAL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("procedure", PROCEDURE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("procedures", PROCEDURES, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("program", PROGRAM, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("publication", PUBLICATION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("quote", QUOTE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("range", RANGE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("read", READ, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("real", REAL, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("reassign", REASSIGN, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("recheck", RECHECK, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("recursive", RECURSIVE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("ref", REF, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("references", REFERENCES, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("referencing", REFERENCING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("refresh", REFRESH, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("reindex", REINDEX, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("relative", RELATIVE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("release", RELEASE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("rename", RENAME, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("repeatable", REPEATABLE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("replace", REPLACE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("replica", REPLICA, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("reset", RESET, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("restart", RESTART, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("restrict", RESTRICT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("returning", RETURNING, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("returns", RETURNS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("revoke", REVOKE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("right", RIGHT, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("role", ROLE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("rollback", ROLLBACK, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("rollup", ROLLUP, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("routine", ROUTINE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("routines", ROUTINES, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("row", ROW, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("rows", ROWS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("rule", RULE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("savepoint", SAVEPOINT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("schema", SCHEMA, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("schemas", SCHEMAS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("scroll", SCROLL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("search", SEARCH, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("second", SECOND_P, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("security", SECURITY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("select", SELECT, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("sequence", SEQUENCE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("sequences", SEQUENCES, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("serializable", SERIALIZABLE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("server", SERVER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("session", SESSION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("session_user", SESSION_USER, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("set", SET, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("setof", SETOF, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("sets", SETS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("share", SHARE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("show", SHOW, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("similar", SIMILAR, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("simple", SIMPLE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("skip", SKIP, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("smallint", SMALLINT, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("snapshot", SNAPSHOT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("some", SOME, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("sql", SQL_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("stable", STABLE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("standalone", STANDALONE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("start", START, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("statement", STATEMENT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("statistics", STATISTICS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("stdin", STDIN, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("stdout", STDOUT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("storage", STORAGE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("stored", STORED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("strict", STRICT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("strip", STRIP_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("subscription", SUBSCRIPTION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("substring", SUBSTRING, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("support", SUPPORT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("symmetric", SYMMETRIC, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("sysid", SYSID, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("system", SYSTEM_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("table", TABLE, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("tables", TABLES, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("tablesample", TABLESAMPLE, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("tablespace", TABLESPACE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("temp", TEMP, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("template", TEMPLATE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("temporary", TEMPORARY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("text", TEXT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("then", THEN, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("ties", TIES, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("time", TIME, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("timestamp", TIMESTAMP, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("to", TO, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("trailing", TRAILING, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("transaction", TRANSACTION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("transform", TRANSFORM, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("treat", TREAT, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("trigger", TRIGGER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("trim", TRIM, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("true", TRUE_P, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("truncate", TRUNCATE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("trusted", TRUSTED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("type", TYPE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("types", TYPES_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("uescape", UESCAPE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("unbounded", UNBOUNDED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("uncommitted", UNCOMMITTED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("unencrypted", UNENCRYPTED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("union", UNION, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("unique", UNIQUE, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("unknown", UNKNOWN, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("unlisten", UNLISTEN, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("unlogged", UNLOGGED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("until", UNTIL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("update", UPDATE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("user", USER, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("using", USING, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("vacuum", VACUUM, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("valid", VALID, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("validate", VALIDATE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("validator", VALIDATOR, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("value", VALUE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("values", VALUES, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("varchar", VARCHAR, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("variadic", VARIADIC, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("varying", VARYING, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("verbose", VERBOSE, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("version", VERSION_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("view", VIEW, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("views", VIEWS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("volatile", VOLATILE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("when", WHEN, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("where", WHERE, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("whitespace", WHITESPACE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("window", WINDOW, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("with", WITH, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("within", WITHIN, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("without", WITHOUT, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("work", WORK, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("wrapper", WRAPPER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("write", WRITE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xml", XML_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlattributes", XMLATTRIBUTES, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlconcat", XMLCONCAT, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlelement", XMLELEMENT, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlexists", XMLEXISTS, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlforest", XMLFOREST, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlnamespaces", XMLNAMESPACES, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlparse", XMLPARSE, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlpi", XMLPI, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlroot", XMLROOT, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlserialize", XMLSERIALIZE, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmltable", XMLTABLE, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("year", YEAR_P, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("yes", YES_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("zone", ZONE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
diff --git a/src/interfaces/ecpg/preproc/keywords.c b/src/interfaces/ecpg/preproc/keywords.c
index f82764aeb9..624b8bfe60 100644
--- a/src/interfaces/ecpg/preproc/keywords.c
+++ b/src/interfaces/ecpg/preproc/keywords.c
@@ -29,7 +29,7 @@
 #include "preproc_extern.h"
 #include "preproc.h"
 
-#define PG_KEYWORD(kwname, value, category) value,
+#define PG_KEYWORD(kwname, value, category, aliastype) value,
 
 const uint16 SQLScanKeywordTokens[] = {
 #include "parser/kwlist.h"
diff --git a/src/tools/gen_keywordlist.pl b/src/tools/gen_keywordlist.pl
index e9250b8fb2..ad433d416e 100644
--- a/src/tools/gen_keywordlist.pl
+++ b/src/tools/gen_keywordlist.pl
@@ -93,11 +93,27 @@ EOM
 
 # Parse input file for keyword names.
 my @keywords;
+my @implicit_alias;
+my %transform = ( IMPLICIT_ALIAS => 'true', EXPLICIT_ALIAS => 'false');
 while (<$kif>)
 {
 	if (/^PG_KEYWORD\("(\w+)"/)
 	{
-		push @keywords, $1;
+		my $kword = $1;
+		push @keywords, $kword;
+
+		if (/^PG_KEYWORD\("\w+", .*, (IMPLICIT_ALIAS|EXPLICIT_ALIAS)\)/)
+		{
+			push @implicit_alias, $transform{$1};
+		}
+		else
+		{
+			# parser/kwlist.h lists each keyword as either an implicit or an
+			# explicit alias, but other kwlist files do not, and for them, it
+			# won't matter what we use here as long as it is a valid boolean,
+			# so we arbitrarily use 'true'.
+			push @implicit_alias, 'true';
+		}
 	}
 }
 
@@ -153,6 +169,17 @@ foreach my $name (@keywords)
 
 print $kwdef "};\n\n";
 
+# Emit an array of boolean as implicit alias values
+
+printf $kwdef "static const bool %s_kw_is_implicit[] = {\n", $varname;
+
+foreach my $bool (@implicit_alias)
+{
+	print $kwdef "\t$bool,\n";
+}
+
+print $kwdef "};\n\n";
+
 # Emit a macro defining the number of keywords.
 # (In some places it's useful to have access to that as a constant.)
 
@@ -173,6 +200,7 @@ printf $kwdef "static " if !$extern;
 printf $kwdef "const ScanKeywordList %s = {\n", $varname;
 printf $kwdef qq|\t%s_kw_string,\n|,            $varname;
 printf $kwdef qq|\t%s_kw_offsets,\n|,           $varname;
+printf $kwdef qq|\t%s_kw_is_implicit,\n|,       $varname;
 printf $kwdef qq|\t%s,\n|,                      $funcname;
 printf $kwdef qq|\t%s_NUM_KEYWORDS,\n|,         uc $varname;
 printf $kwdef qq|\t%d\n|,                       $max_len;
-- 
2.21.1 (Apple Git-122.3)

#39John Naylor
john.naylor@2ndquadrant.com
In reply to: Mark Dilger (#38)
1 attachment(s)
Re: factorial function/phase out postfix operators?

On Wed, Aug 26, 2020 at 6:12 AM Mark Dilger
<mark.dilger@enterprisedb.com> wrote:

The construction colname AS colalias brings to mind the words "pseudonym" and "alias". The distinction we're trying to draw here is between implicit pseudoyms and explicit ones, but "alias" is shorter and simpler, so I like that better than "pseudonym". Both are labels, so adding "label" to the name doesn't really get us anything. The constructions "implicit alias" vs. "explicit alias" seem to me to be an improvement, along with their other forms like "ImplicitAlias", or "implicit_alias", etc., so I've used those in version 4.

The word "status" here really means something like "plicity" (implict vs. explicit), but "plicity" isn't a word, so I used "aliastype" instead.

Seems fine.

A list of user defined postfix operators is in the file:
postfix_ops.txt

Failure, exiting

With the contents of postfix_ops.txt:

In database: regression
(oid=27113) public.#@# (pg_catalog.int8)
(oid=27114) public.#%# (pg_catalog.int8)

which should be enough for a user to identify which operator is meant. I just invented that format. Let me know if there is a preferred way to lay out that information.

Not sure if there's a precedent here, and seems fine to me.

+ /*
+ * If neither argument is specified, do not mention postfix operators, as
+ * the user is unlikely to have meant to create one.  It is more likely
+ * they simply neglected to mention the args.
+ */
  if (!OidIsValid(typeId1) && !OidIsValid(typeId2))
  ereport(ERROR,
  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
- errmsg("at least one of leftarg or rightarg must be specified")));
+ errmsg("operator arguments must be specified")));
+
+ /*
+ * But if only the right arg is missing, they probably do intend to create
+ * a postfix operator, so give them a hint about why that does not work.
+ */
+ if (!OidIsValid(typeId2))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+ errmsg("operator right argument must be specified"),
+ errhint("Postfix operators are not supported.")));

This is just a nitpick -- I think the comments in this section would
flow better if order of checks were reversed, although the code might
not. I don't feel too strongly about it.

- * between POSTFIXOP and Op.  We can safely assign the same priority to
- * various unreserved keywords as needed to resolve ambiguities (this can't
- * have any bad effects since obviously the keywords will still behave the
- * same as if they weren't keywords).  We need to do this:
+ * greater than Op.  We can safely assign the same priority to various
+ * unreserved keywords as needed to resolve ambiguities (this can't have any
+ * bad effects since obviously the keywords will still behave the same as if
+ * they weren't keywords).  We need to do this:

I believe it's actually "lower than Op", and since POSTFIXOP is gone
it doesn't seem to matter how low it is. In fact, I found that the
lines with INDENT and UNBOUNDED now work as the lowest precedence
declarations. Maybe that's worth something?

Following on Peter E.'s example upthread, GENERATED can be removed
from precedence, and I also found the same is true for PRESERVE and
STRIP_P.

I've attached a patch which applies on top of 0001 to demonstrate
this. There might possibly still be syntax errors for things not
covered in the regression test, but there are no s/r conflicts at
least.

-{ oid => '389', descr => 'deprecated, use ! instead',
+{ oid => '389', descr => 'factorial',

Hmm, no objection, but it could be argued that we should just go ahead
and remove "!!" also, keeping only "factorial()". If we're going to
break a small amount of code using the normal math expression, it
seems silly to use a non-standard one that we deprecated before 2011
(cf. 908ab802864). On the other hand, removing it doesn't buy us
anything.

Some leftovers...

...in catalog/namespace.c:

OpernameGetOprid()
* Pass oprleft = InvalidOid for a prefix op, oprright = InvalidOid for
* a postfix op.

OpernameGetCandidates()
* The returned items always have two args[] entries --- one or the other
* will be InvalidOid for a prefix or postfix oprkind. nargs is 2, too.

...in nodes/print.c:

/* we print prefix and postfix ops the same... */

0002:

+ * All keywords can be used explicitly as a column label in expressions
+ * like 'SELECT 1234 AS keyword', but only some keywords can be used
+ * implicitly as column labels in expressions like 'SELECT 1234 keyword'.
+ * Those that can be used implicitly should be listed here.

In my mind, "AS" is the thing that's implied when not present, so we
should reword this to use the "bare" designation when talking about
the labels. I think there are contexts elsewhere where the implicit
column label is "col1, col2, col3...". I can't remember offhand where
that is though.

Per my rambling above, I think what's really implied or explicit when "AS" is missing or present is that we're making an alias, so "implicit alias" and "explicit alias" sound correct to me.

Sounds fine.

-  proname => 'pg_get_keywords', procost => '10', prorows => '400',
+  proname => 'pg_get_keywords', procost => '10', prorows => '450',

Off topic for this patch. Not sure it matters much, either.

Well, I did touch that function a bit, adding a new column, and the number of rows returned is exactly 450, so if I'm not going to update it, who will? The count may increase over time if other keywords are added, but I doubt anybody who adds a single keyword would bother updating prorows here.

I agree that it doesn't matter much. If you don't buy into the paragraph above, I'll remove it for the next patch version.

No strong feelings -- if it were me, I'd put in a separate
"by-the-way" patch at the end, and the committer can squash at their
discretion. But not really worth a separate thread.

# select aliastype, count(*) from pg_get_keywords() group by 1;
aliastype | count
-----------+-------
explicit | 39
implicit | 411
(2 rows)

Nice!

The binary has increased by ~16kB, mostly because of the new keyword
list in the grammar, but that's pretty small, all things considered.

--
John Naylor https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

Attachments:

remove-more-precedence.patchapplication/octet-stream; name=remove-more-precedence.patchDownload
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 0171da5f4b..e90aa731ad 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -731,24 +731,15 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 
 
 /* Precedence: lowest to highest */
-%nonassoc	SET				/* see relation_expr_opt_alias */
-%left		UNION EXCEPT
-%left		INTERSECT
-%left		OR
-%left		AND
-%right		NOT
-%nonassoc	IS ISNULL NOTNULL	/* IS sets precedence for IS NULL, etc */
-%nonassoc	'<' '>' '=' LESS_EQUALS GREATER_EQUALS NOT_EQUALS
-%nonassoc	BETWEEN IN_P LIKE ILIKE SIMILAR NOT_LA
-%nonassoc	ESCAPE			/* ESCAPE must be just above LIKE/ILIKE/SIMILAR */
+
 /*
  * To support target_el without AS, we must give IDENT an explicit priority
- * greater than Op.  We can safely assign the same priority to various
+ * lower than Op.  We can safely assign the same priority to various
  * unreserved keywords as needed to resolve ambiguities (this can't have any
  * bad effects since obviously the keywords will still behave the same as if
  * they weren't keywords).  We need to do this:
  * for PARTITION, RANGE, ROWS, GROUPS to support opt_existing_window_name;
- * for GENERATED so that it can follow b_expr;
+ * for UNBOUNDED, PRECEDING, FOLLOWING to support frame_bound;
  *
  * To support CUBE and ROLLUP in GROUP BY without reserving them, we give them
  * an explicit priority lower than '(', so that a rule with CUBE '(' will shift
@@ -765,7 +756,18 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
  * blame any funny behavior of UNBOUNDED on the SQL standard, though.
  */
 %nonassoc	UNBOUNDED		/* ideally should have same precedence as IDENT */
-%nonassoc	IDENT GENERATED PARTITION RANGE ROWS GROUPS PRECEDING FOLLOWING CUBE ROLLUP
+%nonassoc	IDENT PARTITION RANGE ROWS GROUPS PRECEDING FOLLOWING CUBE ROLLUP
+
+%nonassoc	SET				/* see relation_expr_opt_alias */
+%left		UNION EXCEPT
+%left		INTERSECT
+%left		OR
+%left		AND
+%right		NOT
+%nonassoc	IS ISNULL NOTNULL	/* IS sets precedence for IS NULL, etc */
+%nonassoc	'<' '>' '=' LESS_EQUALS GREATER_EQUALS NOT_EQUALS
+%nonassoc	BETWEEN IN_P LIKE ILIKE SIMILAR NOT_LA
+%nonassoc	ESCAPE			/* ESCAPE must be just above LIKE/ILIKE/SIMILAR */
 %left		Op OPERATOR		/* multi-character ops and user-defined operators */
 %left		'+' '-'
 %left		'*' '/' '%'
@@ -786,8 +788,6 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
  * left-associativity among the JOIN rules themselves.
  */
 %left		JOIN CROSS LEFT FULL RIGHT INNER_P NATURAL
-/* kluge to keep xml_whitespace_option from causing shift/reduce conflicts */
-%right		PRESERVE STRIP_P
 
 %%
 
#40Mark Dilger
mark.dilger@enterprisedb.com
In reply to: John Naylor (#39)
3 attachment(s)
Re: factorial function/phase out postfix operators?

On Aug 26, 2020, at 6:33 AM, John Naylor <john.naylor@2ndquadrant.com> wrote:

+ /*
+ * If neither argument is specified, do not mention postfix operators, as
+ * the user is unlikely to have meant to create one.  It is more likely
+ * they simply neglected to mention the args.
+ */
if (!OidIsValid(typeId1) && !OidIsValid(typeId2))
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
- errmsg("at least one of leftarg or rightarg must be specified")));
+ errmsg("operator arguments must be specified")));
+
+ /*
+ * But if only the right arg is missing, they probably do intend to create
+ * a postfix operator, so give them a hint about why that does not work.
+ */
+ if (!OidIsValid(typeId2))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+ errmsg("operator right argument must be specified"),
+ errhint("Postfix operators are not supported.")));

This is just a nitpick -- I think the comments in this section would
flow better if order of checks were reversed, although the code might
not. I don't feel too strongly about it.

I don't want to reorder the code, but combining the two code comments together allows the comment to flow more as you indicate. Done for v5.

- * between POSTFIXOP and Op.  We can safely assign the same priority to
- * various unreserved keywords as needed to resolve ambiguities (this can't
- * have any bad effects since obviously the keywords will still behave the
- * same as if they weren't keywords).  We need to do this:
+ * greater than Op.  We can safely assign the same priority to various
+ * unreserved keywords as needed to resolve ambiguities (this can't have any
+ * bad effects since obviously the keywords will still behave the same as if
+ * they weren't keywords).  We need to do this:

I believe it's actually "lower than Op",

Right. I have fixed the comment. Thanks for noticing.

and since POSTFIXOP is gone
it doesn't seem to matter how low it is. In fact, I found that the
lines with INDENT and UNBOUNDED now work as the lowest precedence
declarations. Maybe that's worth something?

Following on Peter E.'s example upthread, GENERATED can be removed
from precedence, and I also found the same is true for PRESERVE and
STRIP_P.

I've attached a patch which applies on top of 0001 to demonstrate
this. There might possibly still be syntax errors for things not
covered in the regression test, but there are no s/r conflicts at
least.

I don't have any problem with the changes you made in your patch, but building on your changes I also found that the following cleanup causes no apparent problems:

-%nonassoc      UNBOUNDED               /* ideally should have same precedence as IDENT */
-%nonassoc      IDENT PARTITION RANGE ROWS GROUPS PRECEDING FOLLOWING CUBE ROLLUP
+%nonassoc      UNBOUNDED IDENT
+%nonassoc      PARTITION RANGE ROWS GROUPS PRECEDING FOLLOWING CUBE ROLLUP

Which does what the old comment apparently wanted.

-{ oid => '389', descr => 'deprecated, use ! instead',
+{ oid => '389', descr => 'factorial',

Hmm, no objection, but it could be argued that we should just go ahead
and remove "!!" also, keeping only "factorial()". If we're going to
break a small amount of code using the normal math expression, it
seems silly to use a non-standard one that we deprecated before 2011
(cf. 908ab802864). On the other hand, removing it doesn't buy us
anything.

Yeah, I don't have strong feelings about this. We should decide soon, though, because we should have the deprecation warnings resolved in time for v13, even if this patch hasn't been applied yet.

Some leftovers...

...in catalog/namespace.c:

OpernameGetOprid()
* Pass oprleft = InvalidOid for a prefix op, oprright = InvalidOid for
* a postfix op.

OpernameGetCandidates()
* The returned items always have two args[] entries --- one or the other
* will be InvalidOid for a prefix or postfix oprkind. nargs is 2, too.

...in nodes/print.c:

/* we print prefix and postfix ops the same... */

Cleaned up.

0002:

+ * All keywords can be used explicitly as a column label in expressions
+ * like 'SELECT 1234 AS keyword', but only some keywords can be used
+ * implicitly as column labels in expressions like 'SELECT 1234 keyword'.
+ * Those that can be used implicitly should be listed here.

In my mind, "AS" is the thing that's implied when not present, so we
should reword this to use the "bare" designation when talking about
the labels. I think there are contexts elsewhere where the implicit
column label is "col1, col2, col3...". I can't remember offhand where
that is though.

Per my rambling above, I think what's really implied or explicit when "AS" is missing or present is that we're making an alias, so "implicit alias" and "explicit alias" sound correct to me.

Sounds fine.

-  proname => 'pg_get_keywords', procost => '10', prorows => '400',
+  proname => 'pg_get_keywords', procost => '10', prorows => '450',

Off topic for this patch. Not sure it matters much, either.

Well, I did touch that function a bit, adding a new column, and the number of rows returned is exactly 450, so if I'm not going to update it, who will? The count may increase over time if other keywords are added, but I doubt anybody who adds a single keyword would bother updating prorows here.

I agree that it doesn't matter much. If you don't buy into the paragraph above, I'll remove it for the next patch version.

No strong feelings -- if it were me, I'd put in a separate
"by-the-way" patch at the end, and the committer can squash at their
discretion. But not really worth a separate thread.

Ok, I've split this out into

# select aliastype, count(*) from pg_get_keywords() group by 1;
aliastype | count
-----------+-------
explicit | 39
implicit | 411
(2 rows)

Nice!

I think the number of people porting from other RDBMSs to PostgreSQL who are helped by this patch scales with the number of keywords moved to the "implicit" category, and we've done pretty well here.

I wonder if we can get more comments for or against this patch, at least in principle, in the very near future, to help determine whether the deprecation notices should go into v13?

The binary has increased by ~16kB, mostly because of the new keyword
list in the grammar, but that's pretty small, all things considered.

Right, thanks for checking the size increase.

Attachments:

v5-0001-Removing-postfix-operator-support.patchapplication/octet-stream; name=v5-0001-Removing-postfix-operator-support.patch; x-unix-mode=0644Download
From 8636303d7aee147787c86a8f348bba7207d43b70 Mon Sep 17 00:00:00 2001
From: Mark Dilger <mark.dilger@enterprisedb.com>
Date: Wed, 26 Aug 2020 07:47:07 -0700
Subject: [PATCH v5 1/3] Removing postfix operator support.

Removing postfix operator support from the grammar; disallowing
the creation of postfix operators through the CREATE OPERATOR
command; and removing the factorial postfix operator.

This accomplishes nothing useful in itself, but sets up
for grammar changes to allow keywords to be used as bare column
aliases without the use of an explicit "AS".
---
 contrib/postgres_fdw/deparse.c                |   5 +-
 .../postgres_fdw/expected/postgres_fdw.out    |   8 +-
 contrib/postgres_fdw/sql/postgres_fdw.sql     |   2 +-
 doc/src/sgml/catalogs.sgml                    |   2 +-
 doc/src/sgml/ref/alter_extension.sgml         |   2 +-
 doc/src/sgml/ref/comment.sgml                 |   2 +-
 doc/src/sgml/syntax.sgml                      |  24 +---
 doc/src/sgml/typeconv.sgml                    |   8 +-
 src/backend/catalog/namespace.c               |   7 +-
 src/backend/catalog/pg_operator.c             |   4 +-
 src/backend/commands/operatorcmds.c           |  14 +-
 src/backend/nodes/print.c                     |   1 -
 src/backend/parser/gram.y                     |  54 +++-----
 src/backend/parser/parse_expr.c               |  48 ++-----
 src/backend/parser/parse_oper.c               | 121 +++---------------
 src/backend/utils/adt/ruleutils.c             |  31 ++---
 src/bin/pg_dump/pg_dump.c                     |   6 +-
 src/bin/pg_dump/pg_dump_sort.c                |   2 +-
 src/bin/pg_upgrade/check.c                    | 106 +++++++++++++++
 src/bin/psql/describe.c                       |   2 +-
 src/include/catalog/pg_operator.dat           |   5 +-
 src/include/catalog/pg_operator.h             |   4 +-
 src/test/regress/expected/create_operator.out |  24 ++--
 src/test/regress/expected/numeric.out         |  19 ++-
 src/test/regress/expected/opr_sanity.out      |  17 +--
 src/test/regress/sql/create_operator.sql      |   3 +-
 src/test/regress/sql/numeric.sql              |  14 +-
 src/test/regress/sql/opr_sanity.sql           |  14 +-
 src/tutorial/syscat.source                    |  14 --
 29 files changed, 251 insertions(+), 312 deletions(-)

diff --git a/contrib/postgres_fdw/deparse.c b/contrib/postgres_fdw/deparse.c
index ad37a74221..32a9b38f10 100644
--- a/contrib/postgres_fdw/deparse.c
+++ b/contrib/postgres_fdw/deparse.c
@@ -2716,15 +2716,14 @@ deparseOpExpr(OpExpr *node, deparse_expr_cxt *context)
 	oprkind = form->oprkind;
 
 	/* Sanity check. */
-	Assert((oprkind == 'r' && list_length(node->args) == 1) ||
-		   (oprkind == 'l' && list_length(node->args) == 1) ||
+	Assert((oprkind == 'l' && list_length(node->args) == 1) ||
 		   (oprkind == 'b' && list_length(node->args) == 2));
 
 	/* Always parenthesize the expression. */
 	appendStringInfoChar(buf, '(');
 
 	/* Deparse left operand. */
-	if (oprkind == 'r' || oprkind == 'b')
+	if (oprkind == 'b')
 	{
 		arg = list_head(node->args);
 		deparseExpr(lfirst(arg), context);
diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index 90db550b92..9728c252ba 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -653,12 +653,12 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 = -c1;          -- Op
    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = (- "C 1")))
 (3 rows)
 
-EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE 1 = c1!;           -- OpExpr(r)
-                                                QUERY PLAN                                                
-----------------------------------------------------------------------------------------------------------
+EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE 1 = !!c1;          -- OpExpr(r)
+                                                QUERY PLAN                                                 
+-----------------------------------------------------------------------------------------------------------
  Foreign Scan on public.ft1 t1
    Output: c1, c2, c3, c4, c5, c6, c7, c8
-   Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE ((1::numeric = ("C 1" !)))
+   Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE ((1::numeric = (!! "C 1")))
 (3 rows)
 
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE (c1 IS NOT NULL) IS DISTINCT FROM (c1 IS NOT NULL); -- DistinctExpr
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index 83971665e3..a8e58a8f24 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -307,7 +307,7 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 IS NULL;        -- Nu
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 IS NOT NULL;    -- NullTest
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE round(abs(c1), 0) = 1; -- FuncExpr
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 = -c1;          -- OpExpr(l)
-EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE 1 = c1!;           -- OpExpr(r)
+EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE 1 = !!c1;          -- OpExpr(r)
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE (c1 IS NOT NULL) IS DISTINCT FROM (c1 IS NOT NULL); -- DistinctExpr
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 = ANY(ARRAY[c2, 1, c1 + 0]); -- ScalarArrayOpExpr
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 = (ARRAY[c1,c2,3])[1]; -- SubscriptingRef
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 9fe260ecff..6ed67eedb1 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -5150,7 +5150,7 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
       </para>
       <para>
        <literal>b</literal> = infix (<quote>both</quote>), <literal>l</literal> = prefix
-       (<quote>left</quote>), <literal>r</literal> = postfix (<quote>right</quote>)
+       (<quote>left</quote>)
       </para></entry>
      </row>
 
diff --git a/doc/src/sgml/ref/alter_extension.sgml b/doc/src/sgml/ref/alter_extension.sgml
index a2d405d6cd..c819c7bb4e 100644
--- a/doc/src/sgml/ref/alter_extension.sgml
+++ b/doc/src/sgml/ref/alter_extension.sgml
@@ -251,7 +251,7 @@ ALTER EXTENSION <replaceable class="parameter">name</replaceable> DROP <replacea
       <para>
        The data type(s) of the operator's arguments (optionally
        schema-qualified).  Write <literal>NONE</literal> for the missing argument
-       of a prefix or postfix operator.
+       of a prefix operator.
       </para>
      </listitem>
     </varlistentry>
diff --git a/doc/src/sgml/ref/comment.sgml b/doc/src/sgml/ref/comment.sgml
index fd7492a255..6e8ced3eaf 100644
--- a/doc/src/sgml/ref/comment.sgml
+++ b/doc/src/sgml/ref/comment.sgml
@@ -224,7 +224,7 @@ COMMENT ON
      <para>
       The data type(s) of the operator's arguments (optionally
       schema-qualified).  Write <literal>NONE</literal> for the missing argument
-      of a prefix or postfix operator.
+      of a prefix operator.
      </para>
     </listitem>
    </varlistentry>
diff --git a/doc/src/sgml/syntax.sgml b/doc/src/sgml/syntax.sgml
index 2f993ca2e0..5ad25d96d6 100644
--- a/doc/src/sgml/syntax.sgml
+++ b/doc/src/sgml/syntax.sgml
@@ -979,27 +979,6 @@ CAST ( '<replaceable>string</replaceable>' AS <replaceable>type</replaceable> )
     into the parser.
    </para>
 
-   <para>
-    You will
-    sometimes need to add parentheses when using combinations of
-    binary and unary operators.  For instance:
-<programlisting>
-SELECT 5 ! - 6;
-</programlisting>
-   will be parsed as:
-<programlisting>
-SELECT 5 ! (- 6);
-</programlisting>
-    because the parser has no idea &mdash; until it is too late
-    &mdash; that <token>!</token> is defined as a postfix operator,
-    not an infix one.  To get the desired behavior in this case, you
-    must write:
-<programlisting>
-SELECT (5 !) - 6;
-</programlisting>
-    This is the price one pays for extensibility.
-   </para>
-
    <table id="sql-precedence-table">
     <title>Operator Precedence (highest to lowest)</title>
 
@@ -1463,11 +1442,10 @@ $1.somecolumn
    </indexterm>
 
    <para>
-    There are three possible syntaxes for an operator invocation:
+    There are two possible syntaxes for an operator invocation:
     <simplelist>
      <member><replaceable>expression</replaceable> <replaceable>operator</replaceable> <replaceable>expression</replaceable> (binary infix operator)</member>
      <member><replaceable>operator</replaceable> <replaceable>expression</replaceable> (unary prefix operator)</member>
-     <member><replaceable>expression</replaceable> <replaceable>operator</replaceable> (unary postfix operator)</member>
     </simplelist>
     where the <replaceable>operator</replaceable> token follows the syntax
     rules of <xref linkend="sql-syntax-operators"/>, or is one of the
diff --git a/doc/src/sgml/typeconv.sgml b/doc/src/sgml/typeconv.sgml
index 8900d0eb38..55780d35ec 100644
--- a/doc/src/sgml/typeconv.sgml
+++ b/doc/src/sgml/typeconv.sgml
@@ -97,7 +97,7 @@ Operators
 <listitem>
 <para>
 <productname>PostgreSQL</productname> allows expressions with
-prefix and postfix unary (one-argument) operators,
+prefix unary (one-argument) operators,
 as well as binary (two-argument) operators.  Like functions, operators can
 be overloaded, so the same problem of selecting the right operator
 exists.
@@ -357,13 +357,13 @@ Some examples follow.
 <title>Factorial Operator Type Resolution</title>
 
 <para>
-There is only one factorial operator (postfix <literal>!</literal>)
+There is only one factorial operator (prefix <literal>!!</literal>)
 defined in the standard catalog, and it takes an argument of type
 <type>bigint</type>.
 The scanner assigns an initial type of <type>integer</type> to the argument
 in this query expression:
 <screen>
-SELECT 40 ! AS "40 factorial";
+SELECT !! 40 AS "40 factorial";
 
                    40 factorial
 --------------------------------------------------
@@ -375,7 +375,7 @@ So the parser does a type conversion on the operand and the query
 is equivalent to:
 
 <screen>
-SELECT CAST(40 AS bigint) ! AS "40 factorial";
+SELECT !! CAST(40 AS bigint) AS "40 factorial";
 </screen>
 </para>
 </example>
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index 0152e3869a..0c78ab8af7 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -1473,8 +1473,7 @@ FunctionIsVisible(Oid funcid)
  *		Given a possibly-qualified operator name and exact input datatypes,
  *		look up the operator.  Returns InvalidOid if not found.
  *
- * Pass oprleft = InvalidOid for a prefix op, oprright = InvalidOid for
- * a postfix op.
+ * Pass oprleft = InvalidOid for a prefix op.
  *
  * If the operator name is not schema-qualified, it is sought in the current
  * namespace search path.  If the name is schema-qualified and the given
@@ -1580,8 +1579,8 @@ OpernameGetOprid(List *names, Oid oprleft, Oid oprright)
  * namespace case, we arrange for entries in earlier namespaces to mask
  * identical entries in later namespaces.
  *
- * The returned items always have two args[] entries --- one or the other
- * will be InvalidOid for a prefix or postfix oprkind.  nargs is 2, too.
+ * The returned items always have two args[] entries --- one will be
+ * InvalidOid for a prefix oprkind.  nargs is 2, too.
  */
 FuncCandidateList
 OpernameGetCandidates(List *names, char oprkind, bool missing_schema_ok)
diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c
index 65a36be5ee..f817627d86 100644
--- a/src/backend/catalog/pg_operator.c
+++ b/src/backend/catalog/pg_operator.c
@@ -245,7 +245,7 @@ OperatorShellMake(const char *operatorName,
 	values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
 	values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
 	values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId());
-	values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');
+	values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? 'b' : 'l');
 	values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(false);
 	values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(false);
 	values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);
@@ -494,7 +494,7 @@ OperatorCreate(const char *operatorName,
 	values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
 	values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
 	values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId());
-	values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');
+	values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? 'b' : 'l');
 	values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(canMerge);
 	values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(canHash);
 	values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);
diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c
index bf23937849..b468c7701b 100644
--- a/src/backend/commands/operatorcmds.c
+++ b/src/backend/commands/operatorcmds.c
@@ -168,10 +168,22 @@ DefineOperator(List *names, List *parameters)
 	if (typeName2)
 		typeId2 = typenameTypeId(NULL, typeName2);
 
+	/*
+	 * If only the right argument is missing, the user is likely trying to
+	 * create a postfix operator, so give them a hint about why that does not
+	 * work.  But if both arguments are missing, do not mention postfix
+	 * operators, as the user most likely simply neglected to mention the
+	 * arguments.
+	 */
 	if (!OidIsValid(typeId1) && !OidIsValid(typeId2))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
-				 errmsg("at least one of leftarg or rightarg must be specified")));
+				 errmsg("operator arguments must be specified")));
+	if (!OidIsValid(typeId2))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+				 errmsg("operator right argument must be specified"),
+				 errhint("Postfix operators are not supported.")));
 
 	if (typeName1)
 	{
diff --git a/src/backend/nodes/print.c b/src/backend/nodes/print.c
index 42476724d8..970a2d4384 100644
--- a/src/backend/nodes/print.c
+++ b/src/backend/nodes/print.c
@@ -394,7 +394,6 @@ print_expr(const Node *expr, const List *rtable)
 		}
 		else
 		{
-			/* we print prefix and postfix ops the same... */
 			printf("%s ", ((opname != NULL) ? opname : "(invalid operator)"));
 			print_expr(get_leftop((const Expr *) e), rtable);
 		}
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index dbb47d4982..2480fba771 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -731,29 +731,15 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 
 
 /* Precedence: lowest to highest */
-%nonassoc	SET				/* see relation_expr_opt_alias */
-%left		UNION EXCEPT
-%left		INTERSECT
-%left		OR
-%left		AND
-%right		NOT
-%nonassoc	IS ISNULL NOTNULL	/* IS sets precedence for IS NULL, etc */
-%nonassoc	'<' '>' '=' LESS_EQUALS GREATER_EQUALS NOT_EQUALS
-%nonassoc	BETWEEN IN_P LIKE ILIKE SIMILAR NOT_LA
-%nonassoc	ESCAPE			/* ESCAPE must be just above LIKE/ILIKE/SIMILAR */
-%left		POSTFIXOP		/* dummy for postfix Op rules */
+
 /*
  * To support target_el without AS, we must give IDENT an explicit priority
- * between POSTFIXOP and Op.  We can safely assign the same priority to
- * various unreserved keywords as needed to resolve ambiguities (this can't
- * have any bad effects since obviously the keywords will still behave the
- * same as if they weren't keywords).  We need to do this:
+ * lower than Op.  We can safely assign the same priority to various
+ * unreserved keywords as needed to resolve ambiguities (this can't have any
+ * bad effects since obviously the keywords will still behave the same as if
+ * they weren't keywords).  We need to do this:
  * for PARTITION, RANGE, ROWS, GROUPS to support opt_existing_window_name;
- * for RANGE, ROWS, GROUPS so that they can follow a_expr without creating
- * postfix-operator problems;
- * for GENERATED so that it can follow b_expr;
- * and for NULL so that it can follow b_expr in ColQualList without creating
- * postfix-operator problems.
+ * for UNBOUNDED, PRECEDING, FOLLOWING to support frame_bound;
  *
  * To support CUBE and ROLLUP in GROUP BY without reserving them, we give them
  * an explicit priority lower than '(', so that a rule with CUBE '(' will shift
@@ -769,8 +755,19 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
  * keywords anywhere else in the grammar, but it's definitely risky.  We can
  * blame any funny behavior of UNBOUNDED on the SQL standard, though.
  */
-%nonassoc	UNBOUNDED		/* ideally should have same precedence as IDENT */
-%nonassoc	IDENT GENERATED NULL_P PARTITION RANGE ROWS GROUPS PRECEDING FOLLOWING CUBE ROLLUP
+%nonassoc	UNBOUNDED IDENT
+%nonassoc	PARTITION RANGE ROWS GROUPS PRECEDING FOLLOWING CUBE ROLLUP
+
+%nonassoc	SET				/* see relation_expr_opt_alias */
+%left		UNION EXCEPT
+%left		INTERSECT
+%left		OR
+%left		AND
+%right		NOT
+%nonassoc	IS ISNULL NOTNULL	/* IS sets precedence for IS NULL, etc */
+%nonassoc	'<' '>' '=' LESS_EQUALS GREATER_EQUALS NOT_EQUALS
+%nonassoc	BETWEEN IN_P LIKE ILIKE SIMILAR NOT_LA
+%nonassoc	ESCAPE			/* ESCAPE must be just above LIKE/ILIKE/SIMILAR */
 %left		Op OPERATOR		/* multi-character ops and user-defined operators */
 %left		'+' '-'
 %left		'*' '/' '%'
@@ -791,8 +788,6 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
  * left-associativity among the JOIN rules themselves.
  */
 %left		JOIN CROSS LEFT FULL RIGHT INNER_P NATURAL
-/* kluge to keep xml_whitespace_option from causing shift/reduce conflicts */
-%right		PRESERVE STRIP_P
 
 %%
 
@@ -12989,9 +12984,6 @@ a_expr:		c_expr									{ $$ = $1; }
 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3, @2); }
 			| qual_Op a_expr					%prec Op
 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $1, NULL, $2, @1); }
-			| a_expr qual_Op					%prec POSTFIXOP
-				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, NULL, @2); }
-
 			| a_expr AND a_expr
 				{ $$ = makeAndExpr($1, $3, @2); }
 			| a_expr OR a_expr
@@ -13404,8 +13396,6 @@ b_expr:		c_expr
 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3, @2); }
 			| qual_Op b_expr					%prec Op
 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $1, NULL, $2, @1); }
-			| b_expr qual_Op					%prec POSTFIXOP
-				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, NULL, @2); }
 			| b_expr IS DISTINCT FROM b_expr		%prec IS
 				{
 					$$ = (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $5, @2);
@@ -14661,11 +14651,7 @@ target_el:	a_expr AS ColLabel
 				}
 			/*
 			 * 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.
+			 * any known keyword.
 			 */
 			| a_expr IDENT
 				{
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index f69976cc8c..9e266cf3b0 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -57,7 +57,7 @@ bool		Transform_null_equals = false;
 #define PREC_GROUP_NOT_LIKE		9	/* NOT LIKE/ILIKE/SIMILAR */
 #define PREC_GROUP_NOT_BETWEEN	10	/* NOT BETWEEN */
 #define PREC_GROUP_NOT_IN		11	/* NOT IN */
-#define PREC_GROUP_POSTFIX_OP	12	/* generic postfix operators */
+#define PREC_GROUP_ANY_ALL		12	/* ANY/ALL */
 #define PREC_GROUP_INFIX_OP		13	/* generic infix operators */
 #define PREC_GROUP_PREFIX_OP	14	/* generic prefix operators */
 
@@ -71,7 +71,7 @@ bool		Transform_null_equals = false;
  * 4. LIKE ILIKE SIMILAR
  * 5. BETWEEN
  * 6. IN
- * 7. generic postfix Op
+ * 7. ANY ALL
  * 8. generic Op, including <= => <>
  * 9. generic prefix Op
  * 10. IS tests (NullTest, BooleanTest, etc)
@@ -1031,7 +1031,7 @@ transformAExprOpAny(ParseState *pstate, A_Expr *a)
 	Node	   *rexpr = a->rexpr;
 
 	if (operator_precedence_warning)
-		emit_precedence_warnings(pstate, PREC_GROUP_POSTFIX_OP,
+		emit_precedence_warnings(pstate, PREC_GROUP_ANY_ALL,
 								 strVal(llast(a->name)),
 								 lexpr, NULL,
 								 a->location);
@@ -1054,7 +1054,7 @@ transformAExprOpAll(ParseState *pstate, A_Expr *a)
 	Node	   *rexpr = a->rexpr;
 
 	if (operator_precedence_warning)
-		emit_precedence_warnings(pstate, PREC_GROUP_POSTFIX_OP,
+		emit_precedence_warnings(pstate, PREC_GROUP_ANY_ALL,
 								 strVal(llast(a->name)),
 								 lexpr, NULL,
 								 a->location);
@@ -2014,15 +2014,9 @@ transformSubLink(ParseState *pstate, SubLink *sublink)
 
 		if (operator_precedence_warning)
 		{
-			if (sublink->operName == NIL)
-				emit_precedence_warnings(pstate, PREC_GROUP_IN, "IN",
-										 sublink->testexpr, NULL,
-										 sublink->location);
-			else
-				emit_precedence_warnings(pstate, PREC_GROUP_POSTFIX_OP,
-										 strVal(llast(sublink->operName)),
-										 sublink->testexpr, NULL,
-										 sublink->location);
+			emit_precedence_warnings(pstate, PREC_GROUP_IN, "IN",
+									 sublink->testexpr, NULL,
+									 sublink->location);
 		}
 
 		/*
@@ -3244,28 +3238,11 @@ operator_precedence_group(Node *node, const char **nodename)
 				group = PREC_GROUP_PREFIX_OP;
 			}
 		}
-		else if (aexpr->kind == AEXPR_OP &&
-				 aexpr->lexpr != NULL &&
-				 aexpr->rexpr == NULL)
-		{
-			/* postfix operator */
-			if (list_length(aexpr->name) == 1)
-			{
-				*nodename = strVal(linitial(aexpr->name));
-				group = PREC_GROUP_POSTFIX_OP;
-			}
-			else
-			{
-				/* schema-qualified operator syntax */
-				*nodename = "OPERATOR()";
-				group = PREC_GROUP_POSTFIX_OP;
-			}
-		}
 		else if (aexpr->kind == AEXPR_OP_ANY ||
 				 aexpr->kind == AEXPR_OP_ALL)
 		{
 			*nodename = strVal(llast(aexpr->name));
-			group = PREC_GROUP_POSTFIX_OP;
+			group = PREC_GROUP_ANY_ALL;
 		}
 		else if (aexpr->kind == AEXPR_DISTINCT ||
 				 aexpr->kind == AEXPR_NOT_DISTINCT)
@@ -3356,7 +3333,7 @@ operator_precedence_group(Node *node, const char **nodename)
 			else
 			{
 				*nodename = strVal(llast(s->operName));
-				group = PREC_GROUP_POSTFIX_OP;
+				group = PREC_GROUP_ANY_ALL;
 			}
 		}
 	}
@@ -3432,9 +3409,8 @@ emit_precedence_warnings(ParseState *pstate,
 	 * Complain if left child, which should be same or higher precedence
 	 * according to current rules, used to be lower precedence.
 	 *
-	 * Exception to precedence rules: if left child is IN or NOT IN or a
-	 * postfix operator, the grouping is syntactically forced regardless of
-	 * precedence.
+	 * Exception to precedence rules: if left child is IN or NOT IN the
+	 * grouping is syntactically forced regardless of precedence.
 	 */
 	cgroup = operator_precedence_group(lchild, &copname);
 	if (cgroup > 0)
@@ -3442,7 +3418,7 @@ emit_precedence_warnings(ParseState *pstate,
 		if (oldprecedence_l[cgroup] < oldprecedence_r[opgroup] &&
 			cgroup != PREC_GROUP_IN &&
 			cgroup != PREC_GROUP_NOT_IN &&
-			cgroup != PREC_GROUP_POSTFIX_OP &&
+			cgroup != PREC_GROUP_ANY_ALL &&
 			cgroup != PREC_GROUP_POSTFIX_IS)
 			ereport(WARNING,
 					(errmsg("operator precedence change: %s is now lower precedence than %s",
diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c
index 2749974f63..877ffa03a6 100644
--- a/src/backend/parser/parse_oper.c
+++ b/src/backend/parser/parse_oper.c
@@ -52,7 +52,7 @@ typedef struct OprCacheKey
 {
 	char		oprname[NAMEDATALEN];
 	Oid			left_arg;		/* Left input OID, or 0 if prefix op */
-	Oid			right_arg;		/* Right input OID, or 0 if postfix op */
+	Oid			right_arg;		/* Right input OID */
 	Oid			search_path[MAX_CACHED_PATH_LEN];
 } OprCacheKey;
 
@@ -88,8 +88,7 @@ static void InvalidateOprCacheCallBack(Datum arg, int cacheid, uint32 hashvalue)
  *		Given a possibly-qualified operator name and exact input datatypes,
  *		look up the operator.
  *
- * Pass oprleft = InvalidOid for a prefix op, oprright = InvalidOid for
- * a postfix op.
+ * Pass oprleft = InvalidOid for a prefix op.
  *
  * If the operator name is not schema-qualified, it is sought in the current
  * namespace search path.
@@ -115,10 +114,13 @@ LookupOperName(ParseState *pstate, List *opername, Oid oprleft, Oid oprright,
 
 		if (!OidIsValid(oprleft))
 			oprkind = 'l';
-		else if (!OidIsValid(oprright))
-			oprkind = 'r';
-		else
+		else if (OidIsValid(oprright))
 			oprkind = 'b';
+		else
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					 errmsg("postfix operators are not supported"),
+					 parser_errposition(pstate, location)));
 
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_FUNCTION),
@@ -507,85 +509,6 @@ compatible_oper_opid(List *op, Oid arg1, Oid arg2, bool noError)
 }
 
 
-/* right_oper() -- search for a unary right operator (postfix operator)
- * Given operator name and type of arg, return oper struct.
- *
- * IMPORTANT: the returned operator (if any) is only promised to be
- * coercion-compatible with the input datatype.  Do not use this if
- * you need an exact- or binary-compatible match.
- *
- * If no matching operator found, return NULL if noError is true,
- * raise an error if it is false.  pstate and location are used only to report
- * the error position; pass NULL/-1 if not available.
- *
- * NOTE: on success, the returned object is a syscache entry.  The caller
- * must ReleaseSysCache() the entry when done with it.
- */
-Operator
-right_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
-{
-	Oid			operOid;
-	OprCacheKey key;
-	bool		key_ok;
-	FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND;
-	HeapTuple	tup = NULL;
-
-	/*
-	 * Try to find the mapping in the lookaside cache.
-	 */
-	key_ok = make_oper_cache_key(pstate, &key, op, arg, InvalidOid, location);
-
-	if (key_ok)
-	{
-		operOid = find_oper_cache_entry(&key);
-		if (OidIsValid(operOid))
-		{
-			tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
-			if (HeapTupleIsValid(tup))
-				return (Operator) tup;
-		}
-	}
-
-	/*
-	 * First try for an "exact" match.
-	 */
-	operOid = OpernameGetOprid(op, arg, InvalidOid);
-	if (!OidIsValid(operOid))
-	{
-		/*
-		 * Otherwise, search for the most suitable candidate.
-		 */
-		FuncCandidateList clist;
-
-		/* Get postfix operators of given name */
-		clist = OpernameGetCandidates(op, 'r', false);
-
-		/* No operators found? Then fail... */
-		if (clist != NULL)
-		{
-			/*
-			 * We must run oper_select_candidate even if only one candidate,
-			 * otherwise we may falsely return a non-type-compatible operator.
-			 */
-			fdresult = oper_select_candidate(1, &arg, clist, &operOid);
-		}
-	}
-
-	if (OidIsValid(operOid))
-		tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
-
-	if (HeapTupleIsValid(tup))
-	{
-		if (key_ok)
-			make_oper_cache_entry(&key, operOid);
-	}
-	else if (!noError)
-		op_error(pstate, op, 'r', arg, InvalidOid, fdresult, location);
-
-	return (Operator) tup;
-}
-
-
 /* left_oper() -- search for a unary left operator (prefix operator)
  * Given operator name and type of arg, return oper struct.
  *
@@ -696,8 +619,7 @@ op_signature_string(List *op, char oprkind, Oid arg1, Oid arg2)
 
 	appendStringInfoString(&argbuf, NameListToString(op));
 
-	if (oprkind != 'r')
-		appendStringInfo(&argbuf, " %s", format_type_be(arg2));
+	appendStringInfo(&argbuf, " %s", format_type_be(arg2));
 
 	return argbuf.data;			/* return palloc'd string buffer */
 }
@@ -758,15 +680,14 @@ make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree,
 	Oid			rettype;
 	OpExpr	   *result;
 
-	/* Select the operator */
+	/* Check it's not a postfix operator */
 	if (rtree == NULL)
-	{
-		/* right operator */
-		ltypeId = exprType(ltree);
-		rtypeId = InvalidOid;
-		tup = right_oper(pstate, opname, ltypeId, false, location);
-	}
-	else if (ltree == NULL)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+				 errmsg("postfix operators are not supported")));
+
+	/* Select the operator */
+	if (ltree == NULL)
 	{
 		/* left operator */
 		rtypeId = exprType(rtree);
@@ -795,15 +716,7 @@ make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree,
 				 parser_errposition(pstate, location)));
 
 	/* Do typecasting and build the expression tree */
-	if (rtree == NULL)
-	{
-		/* right operator */
-		args = list_make1(ltree);
-		actual_arg_types[0] = ltypeId;
-		declared_arg_types[0] = opform->oprleft;
-		nargs = 1;
-	}
-	else if (ltree == NULL)
+	if (ltree == NULL)
 	{
 		/* left operator */
 		args = list_make1(rtree);
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 60dd80c23c..16abfcb406 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -9207,25 +9207,16 @@ get_oper_expr(OpExpr *expr, deparse_context *context)
 		if (!HeapTupleIsValid(tp))
 			elog(ERROR, "cache lookup failed for operator %u", opno);
 		optup = (Form_pg_operator) GETSTRUCT(tp);
-		switch (optup->oprkind)
-		{
-			case 'l':
-				appendStringInfo(buf, "%s ",
-								 generate_operator_name(opno,
-														InvalidOid,
-														exprType(arg)));
-				get_rule_expr_paren(arg, context, true, (Node *) expr);
-				break;
-			case 'r':
-				get_rule_expr_paren(arg, context, true, (Node *) expr);
-				appendStringInfo(buf, " %s",
-								 generate_operator_name(opno,
-														exprType(arg),
-														InvalidOid));
-				break;
-			default:
-				elog(ERROR, "bogus oprkind: %d", optup->oprkind);
+		if (optup->oprkind == 'l')
+		{
+			appendStringInfo(buf, "%s ",
+							 generate_operator_name(opno,
+													InvalidOid,
+													exprType(arg)));
+			get_rule_expr_paren(arg, context, true, (Node *) expr);
 		}
+		else
+			elog(ERROR, "bogus oprkind: %d", optup->oprkind);
 		ReleaseSysCache(tp);
 	}
 	if (!PRETTY_PAREN(context))
@@ -11087,10 +11078,6 @@ generate_operator_name(Oid operid, Oid arg1, Oid arg2)
 			p_result = left_oper(NULL, list_make1(makeString(oprname)), arg2,
 								 true, -1);
 			break;
-		case 'r':
-			p_result = right_oper(NULL, list_make1(makeString(oprname)), arg1,
-								  true, -1);
-			break;
 		default:
 			elog(ERROR, "unrecognized oprkind: %d", operform->oprkind);
 			p_result = NULL;	/* keep compiler quiet */
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 2cb3f9b083..a93ab8eed3 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -12643,11 +12643,9 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
 					  oprinfo->dobj.name);
 
 	/*
-	 * right unary means there's a left arg and left unary means there's a
-	 * right arg
+	 * left unary means there's only a right arg
 	 */
-	if (strcmp(oprkind, "r") == 0 ||
-		strcmp(oprkind, "b") == 0)
+	if (strcmp(oprkind, "b") == 0)
 	{
 		appendPQExpBuffer(details, ",\n    LEFTARG = %s", oprleft);
 		appendPQExpBufferStr(oprid, oprleft);
diff --git a/src/bin/pg_dump/pg_dump_sort.c b/src/bin/pg_dump/pg_dump_sort.c
index 654e2ec514..c7f06604c6 100644
--- a/src/bin/pg_dump/pg_dump_sort.c
+++ b/src/bin/pg_dump/pg_dump_sort.c
@@ -203,7 +203,7 @@ DOTypeNameCompare(const void *p1, const void *p2)
 		OprInfo    *oobj1 = *(OprInfo *const *) p1;
 		OprInfo    *oobj2 = *(OprInfo *const *) p2;
 
-		/* oprkind is 'l', 'r', or 'b'; this sorts prefix, postfix, infix */
+		/* oprkind is 'l' or 'b'; this sorts prefix and infix */
 		cmpval = (oobj2->oprkind - oobj1->oprkind);
 		if (cmpval != 0)
 			return cmpval;
diff --git a/src/bin/pg_upgrade/check.c b/src/bin/pg_upgrade/check.c
index 00aef855dc..b86098dc42 100644
--- a/src/bin/pg_upgrade/check.c
+++ b/src/bin/pg_upgrade/check.c
@@ -22,6 +22,7 @@ static void check_is_install_user(ClusterInfo *cluster);
 static void check_proper_datallowconn(ClusterInfo *cluster);
 static void check_for_prepared_transactions(ClusterInfo *cluster);
 static void check_for_isn_and_int8_passing_mismatch(ClusterInfo *cluster);
+static void check_for_user_defined_postfix_ops(ClusterInfo *cluster);
 static void check_for_tables_with_oids(ClusterInfo *cluster);
 static void check_for_reg_data_type_usage(ClusterInfo *cluster);
 static void check_for_jsonb_9_4_usage(ClusterInfo *cluster);
@@ -100,6 +101,13 @@ check_and_dump_old_cluster(bool live_check)
 	check_for_reg_data_type_usage(&old_cluster);
 	check_for_isn_and_int8_passing_mismatch(&old_cluster);
 
+	/*
+	 * Pre-PG 14 allowed user defined postfix operators, which are not
+	 * supported anymore.  Verify there are none, iff applicable.
+	 */
+	if (GET_MAJOR_VERSION(old_cluster.major_version) <= 1300)
+		check_for_user_defined_postfix_ops(&old_cluster);
+
 	/*
 	 * Pre-PG 12 allowed tables to be declared WITH OIDS, which is not
 	 * supported anymore. Verify there are none, iff applicable.
@@ -896,6 +904,104 @@ check_for_isn_and_int8_passing_mismatch(ClusterInfo *cluster)
 		check_ok();
 }
 
+/*
+ * Verify that no user defined postfix operators exist.
+ */
+static void
+check_for_user_defined_postfix_ops(ClusterInfo *cluster)
+{
+	int			dbnum;
+	FILE	   *script = NULL;
+	bool		found = false;
+	char		output_path[MAXPGPATH];
+
+	prep_status("Checking for user defined postfix operators");
+
+	snprintf(output_path, sizeof(output_path),
+			 "postfix_ops.txt");
+
+	/* Find any user defined postfix operators */
+	for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
+	{
+		PGresult   *res;
+		bool		db_used = false;
+		int			ntups;
+		int			rowno;
+		int			i_oproid,
+					i_oprnsp,
+					i_oprname,
+					i_typnsp,
+					i_typname;
+		DbInfo	   *active_db = &cluster->dbarr.dbs[dbnum];
+		PGconn	   *conn = connectToServer(cluster, active_db->db_name);
+
+		/*
+		 * The query below hardcodes FirstNormalObjectId as 16384 rather than
+		 * interpolating that C #define into the string because, if that
+		 * #define is ever changed, the cutoff we want to use is the definition
+		 * from pre-verion 14 servers, not from some future version of the
+		 * code.
+		 */
+		res = executeQueryOrDie(conn,
+								"SELECT o.oid AS oproid, "
+								"       n.nspname AS oprnsp, "
+								"       o.oprname, "
+								"       tn.nspname AS typnsp, "
+								"       t.typname "
+								"FROM pg_catalog.pg_operator o, "
+								"     pg_catalog.pg_namespace n, "
+								"     pg_catalog.pg_type t, "
+								"     pg_catalog.pg_namespace tn "
+								"WHERE o.oprnamespace = n.oid AND "
+								"      o.oprleft = t.oid AND "
+								"      t.typnamespace = tn.oid AND "
+								"      o.oprright = 0 AND "
+								"      o.oid >= 16384");
+		ntups = PQntuples(res);
+		i_oproid = PQfnumber(res, "oproid");
+		i_oprnsp = PQfnumber(res, "oprnsp");
+		i_oprname = PQfnumber(res, "oprname");
+		i_typnsp = PQfnumber(res, "typnsp");
+		i_typname = PQfnumber(res, "typname");
+		for (rowno = 0; rowno < ntups; rowno++)
+		{
+			found = true;
+			if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
+				pg_fatal("could not open file \"%s\": %s\n",
+						 output_path, strerror(errno));
+			if (!db_used)
+			{
+				fprintf(script, "In database: %s\n", active_db->db_name);
+				db_used = true;
+			}
+			fprintf(script, "  (oid=%s) %s.%s (%s.%s)\n",
+					PQgetvalue(res, rowno, i_oproid),
+					PQgetvalue(res, rowno, i_oprnsp),
+					PQgetvalue(res, rowno, i_oprname),
+					PQgetvalue(res, rowno, i_typnsp),
+					PQgetvalue(res, rowno, i_typname));
+		}
+
+		PQclear(res);
+
+		PQfinish(conn);
+	}
+
+	if (script)
+		fclose(script);
+
+	if (found)
+	{
+		pg_log(PG_REPORT, "fatal\n");
+		pg_fatal("Your installation contains user defined postfix operators, which is not\n"
+				 "supported anymore.  Consider dropping the postfix operators and replacing\n"
+				 "them with prefix operators or function calls.\n"
+				 "A list of user defined postfix operators is in the file:\n"
+				 "    %s\n\n", output_path);
+	}
+	else
+		check_ok();
+}
 
 /*
  * Verify that no tables are declared WITH OIDS.
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index d81f1575bf..1aaf5ccb38 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -805,7 +805,7 @@ describeOperators(const char *pattern, bool verbose, bool showSystem)
 					  "SELECT n.nspname as \"%s\",\n"
 					  "  o.oprname AS \"%s\",\n"
 					  "  CASE WHEN o.oprkind='l' THEN NULL ELSE pg_catalog.format_type(o.oprleft, NULL) END AS \"%s\",\n"
-					  "  CASE WHEN o.oprkind='r' THEN NULL ELSE pg_catalog.format_type(o.oprright, NULL) END AS \"%s\",\n"
+					  "  pg_catalog.format_type(o.oprright, NULL) AS \"%s\",\n"
 					  "  pg_catalog.format_type(o.oprresult, NULL) AS \"%s\",\n",
 					  gettext_noop("Schema"),
 					  gettext_noop("Name"),
diff --git a/src/include/catalog/pg_operator.dat b/src/include/catalog/pg_operator.dat
index 5b0e063655..9733f18de7 100644
--- a/src/include/catalog/pg_operator.dat
+++ b/src/include/catalog/pg_operator.dat
@@ -218,10 +218,7 @@
   oprname => '>=', oprleft => 'xid8', oprright => 'xid8', oprresult => 'bool',
   oprcom => '<=(xid8,xid8)', oprnegate => '<(xid8,xid8)', oprcode => 'xid8ge',
   oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' },
-{ oid => '388', descr => 'factorial',
-  oprname => '!', oprkind => 'r', oprleft => 'int8', oprright => '0',
-  oprresult => 'numeric', oprcode => 'numeric_fac' },
-{ oid => '389', descr => 'deprecated, use ! instead',
+{ oid => '389', descr => 'factorial',
   oprname => '!!', oprkind => 'l', oprleft => '0', oprright => 'int8',
   oprresult => 'numeric', oprcode => 'numeric_fac' },
 { oid => '385', descr => 'equal',
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index 1daa263852..1491b87582 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -41,7 +41,7 @@ CATALOG(pg_operator,2617,OperatorRelationId)
 	/* operator owner */
 	Oid			oprowner BKI_DEFAULT(PGUID);
 
-	/* 'l', 'r', or 'b' */
+	/* 'l' or 'b' */
 	char		oprkind BKI_DEFAULT(b);
 
 	/* can be used in merge join? */
@@ -53,7 +53,7 @@ CATALOG(pg_operator,2617,OperatorRelationId)
 	/* left arg type, or 0 if 'l' oprkind */
 	Oid			oprleft BKI_LOOKUP(pg_type);
 
-	/* right arg type, or 0 if 'r' oprkind */
+	/* right arg type */
 	Oid			oprright BKI_LOOKUP(pg_type);
 
 	/* result datatype */
diff --git a/src/test/regress/expected/create_operator.out b/src/test/regress/expected/create_operator.out
index 54e8b79159..83172cc073 100644
--- a/src/test/regress/expected/create_operator.out
+++ b/src/test/regress/expected/create_operator.out
@@ -22,10 +22,14 @@ CREATE OPERATOR #@# (
    leftarg = int8,		-- right unary
    procedure = numeric_fac
 );
+ERROR:  operator right argument must be specified
+HINT:  Postfix operators are not supported.
 CREATE OPERATOR #%# (
    leftarg = int8,		-- right unary
    procedure = numeric_fac
 );
+ERROR:  operator right argument must be specified
+HINT:  Postfix operators are not supported.
 -- Test operator created above
 SELECT point '(1,2)' <% widget '(0,0,3)' AS t,
        point '(1,2)' <% widget '(0,0,1)' AS f;
@@ -36,7 +40,9 @@ SELECT point '(1,2)' <% widget '(0,0,3)' AS t,
 
 -- Test comments
 COMMENT ON OPERATOR ###### (int4, NONE) IS 'bad right unary';
-ERROR:  operator does not exist: integer ######
+ERROR:  postfix operators are not supported
+COMMENT ON OPERATOR ###### (NONE, int4) IS 'bad left unary';
+ERROR:  operator does not exist: ###### integer
 -- => is disallowed now
 CREATE OPERATOR => (
    leftarg = int8,		-- right unary
@@ -52,12 +58,12 @@ CREATE OPERATOR !=- (
    leftarg = int8,		-- right unary
    procedure = numeric_fac
 );
+ERROR:  operator right argument must be specified
+HINT:  Postfix operators are not supported.
 SELECT 2 !=-;
- ?column? 
-----------
-        2
-(1 row)
-
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 2 !=-;
+                    ^
 -- make sure lexer returns != as <> even in edge cases
 SELECT 2 !=/**/ 1, 2 !=/**/ 2;
  ?column? | ?column? 
@@ -172,11 +178,13 @@ CREATE OPERATOR #@%# (
    invalid_att = int8
 );
 WARNING:  operator attribute "invalid_att" not recognized
--- Should fail. At least leftarg or rightarg should be mandatorily specified
+ERROR:  operator right argument must be specified
+HINT:  Postfix operators are not supported.
+-- Should fail. At least rightarg should be mandatorily specified
 CREATE OPERATOR #@%# (
    procedure = numeric_fac
 );
-ERROR:  at least one of leftarg or rightarg must be specified
+ERROR:  operator arguments must be specified
 -- Should fail. Procedure should be mandatorily specified
 CREATE OPERATOR #@%# (
    leftarg = int8
diff --git a/src/test/regress/expected/numeric.out b/src/test/regress/expected/numeric.out
index 8546ce901f..186cf1d507 100644
--- a/src/test/regress/expected/numeric.out
+++ b/src/test/regress/expected/numeric.out
@@ -2960,7 +2960,7 @@ ERROR:  value overflows numeric format
 --
 -- Tests for factorial
 --
-SELECT 4!;
+SELECT !!4;
  ?column? 
 ----------
        24
@@ -2978,19 +2978,30 @@ SELECT factorial(15);
  1307674368000
 (1 row)
 
-SELECT 100000!;
+SELECT !!100000;
 ERROR:  value overflows numeric format
-SELECT 0!;
+SELECT !!0;
  ?column? 
 ----------
         1
 (1 row)
 
-SELECT -4!;
+SELECT !!(-4);
 ERROR:  factorial of a negative number is undefined
 SELECT factorial(-4);
 ERROR:  factorial of a negative number is undefined
 --
+-- Postfix operators are not supported.  Check that.
+--
+SELECT -5!;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT -5!;
+                  ^
+SELECT 5!;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 5!;
+                 ^
+--
 -- Tests for pg_lsn()
 --
 SELECT pg_lsn(23783416::numeric);
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index 1b3c146e4c..7825a765cd 100644
--- a/src/test/regress/expected/opr_sanity.out
+++ b/src/test/regress/expected/opr_sanity.out
@@ -1066,7 +1066,7 @@ WHERE condefault AND
 -- Look for illegal values in pg_operator fields.
 SELECT p1.oid, p1.oprname
 FROM pg_operator as p1
-WHERE (p1.oprkind != 'b' AND p1.oprkind != 'l' AND p1.oprkind != 'r') OR
+WHERE (p1.oprkind != 'b' AND p1.oprkind != 'l') OR
     p1.oprresult = 0 OR p1.oprcode = 0;
  oid | oprname 
 -----+---------
@@ -1077,8 +1077,7 @@ SELECT p1.oid, p1.oprname
 FROM pg_operator as p1
 WHERE (p1.oprleft = 0 and p1.oprkind != 'l') OR
     (p1.oprleft != 0 and p1.oprkind = 'l') OR
-    (p1.oprright = 0 and p1.oprkind != 'r') OR
-    (p1.oprright != 0 and p1.oprkind = 'r');
+    p1.oprright = 0;
  oid | oprname 
 -----+---------
 (0 rows)
@@ -1285,18 +1284,6 @@ WHERE p1.oprcode = p2.oid AND
 -----+---------+-----+---------
 (0 rows)
 
-SELECT p1.oid, p1.oprname, p2.oid, p2.proname
-FROM pg_operator AS p1, pg_proc AS p2
-WHERE p1.oprcode = p2.oid AND
-    p1.oprkind = 'r' AND
-    (p2.pronargs != 1
-     OR NOT binary_coercible(p2.prorettype, p1.oprresult)
-     OR NOT binary_coercible(p1.oprleft, p2.proargtypes[0])
-     OR p1.oprright != 0);
- oid | oprname | oid | proname 
------+---------+-----+---------
-(0 rows)
-
 -- If the operator is mergejoinable or hashjoinable, its underlying function
 -- should not be volatile.
 SELECT p1.oid, p1.oprname, p2.oid, p2.proname
diff --git a/src/test/regress/sql/create_operator.sql b/src/test/regress/sql/create_operator.sql
index 8b6fd0bb43..94961d9899 100644
--- a/src/test/regress/sql/create_operator.sql
+++ b/src/test/regress/sql/create_operator.sql
@@ -38,6 +38,7 @@ SELECT point '(1,2)' <% widget '(0,0,3)' AS t,
 
 -- Test comments
 COMMENT ON OPERATOR ###### (int4, NONE) IS 'bad right unary';
+COMMENT ON OPERATOR ###### (NONE, int4) IS 'bad left unary';
 
 -- => is disallowed now
 CREATE OPERATOR => (
@@ -133,7 +134,7 @@ CREATE OPERATOR #@%# (
    invalid_att = int8
 );
 
--- Should fail. At least leftarg or rightarg should be mandatorily specified
+-- Should fail. At least rightarg should be mandatorily specified
 CREATE OPERATOR #@%# (
    procedure = numeric_fac
 );
diff --git a/src/test/regress/sql/numeric.sql b/src/test/regress/sql/numeric.sql
index 416c16722a..45602b00e1 100644
--- a/src/test/regress/sql/numeric.sql
+++ b/src/test/regress/sql/numeric.sql
@@ -1298,14 +1298,20 @@ SELECT lcm(9999 * (10::numeric)^131068 + (10::numeric^131068 - 1), 2); -- overfl
 --
 -- Tests for factorial
 --
-SELECT 4!;
+SELECT !!4;
 SELECT !!3;
 SELECT factorial(15);
-SELECT 100000!;
-SELECT 0!;
-SELECT -4!;
+SELECT !!100000;
+SELECT !!0;
+SELECT !!(-4);
 SELECT factorial(-4);
 
+--
+-- Postfix operators are not supported.  Check that.
+--
+SELECT -5!;
+SELECT 5!;
+
 --
 -- Tests for pg_lsn()
 --
diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql
index 7a9180b081..307aab1deb 100644
--- a/src/test/regress/sql/opr_sanity.sql
+++ b/src/test/regress/sql/opr_sanity.sql
@@ -571,7 +571,7 @@ WHERE condefault AND
 
 SELECT p1.oid, p1.oprname
 FROM pg_operator as p1
-WHERE (p1.oprkind != 'b' AND p1.oprkind != 'l' AND p1.oprkind != 'r') OR
+WHERE (p1.oprkind != 'b' AND p1.oprkind != 'l') OR
     p1.oprresult = 0 OR p1.oprcode = 0;
 
 -- Look for missing or unwanted operand types
@@ -580,8 +580,7 @@ SELECT p1.oid, p1.oprname
 FROM pg_operator as p1
 WHERE (p1.oprleft = 0 and p1.oprkind != 'l') OR
     (p1.oprleft != 0 and p1.oprkind = 'l') OR
-    (p1.oprright = 0 and p1.oprkind != 'r') OR
-    (p1.oprright != 0 and p1.oprkind = 'r');
+    p1.oprright = 0;
 
 -- Look for conflicting operator definitions (same names and input datatypes).
 
@@ -715,15 +714,6 @@ WHERE p1.oprcode = p2.oid AND
      OR NOT binary_coercible(p1.oprright, p2.proargtypes[0])
      OR p1.oprleft != 0);
 
-SELECT p1.oid, p1.oprname, p2.oid, p2.proname
-FROM pg_operator AS p1, pg_proc AS p2
-WHERE p1.oprcode = p2.oid AND
-    p1.oprkind = 'r' AND
-    (p2.pronargs != 1
-     OR NOT binary_coercible(p2.prorettype, p1.oprresult)
-     OR NOT binary_coercible(p1.oprleft, p2.proargtypes[0])
-     OR p1.oprright != 0);
-
 -- If the operator is mergejoinable or hashjoinable, its underlying function
 -- should not be volatile.
 
diff --git a/src/tutorial/syscat.source b/src/tutorial/syscat.source
index 3a1767f97b..a84ea0d5c9 100644
--- a/src/tutorial/syscat.source
+++ b/src/tutorial/syscat.source
@@ -110,20 +110,6 @@ SELECT n.nspname, o.oprname AS left_unary,
   ORDER BY nspname, operand;
 
 
---
--- lists all right unary operators
---
-SELECT n.nspname, o.oprname AS right_unary,
-       format_type(left_type.oid, null) AS operand,
-       format_type(result.oid, null) AS return_type
-  FROM pg_namespace n, pg_operator o,
-       pg_type left_type, pg_type result
-  WHERE o.oprnamespace = n.oid
-    and o.oprkind = 'r'          -- right unary
-    and o.oprleft = left_type.oid
-    and o.oprresult = result.oid
-  ORDER BY nspname, operand;
-
 --
 -- lists all binary operators
 --
-- 
2.21.1 (Apple Git-122.3)

v5-0002-Allow-most-keywords-to-be-used-as-implicit-column.patchapplication/octet-stream; name=v5-0002-Allow-most-keywords-to-be-used-as-implicit-column.patch; x-unix-mode=0644Download
From ff1743197661373b9d68657448d004dbf4266d7d Mon Sep 17 00:00:00 2001
From: Mark Dilger <mark.dilger@enterprisedb.com>
Date: Wed, 26 Aug 2020 07:48:21 -0700
Subject: [PATCH v5 2/3] Allow most keywords to be used as implicit column
 labels.

Previously, to use a keyword as a column label in an expression, the
keyword had to be preceded by the token AS.  That is no longer
required for most keywords.  This is accomplished with some changes
to gram.y and by removing support for postfix operators.

These keywords must still be preceded by AS:

    array, as, char, character, create, day, except, fetch, filter,
    for, from, grant, group, having, hour, intersect, into, isnull,
    limit, minute, month, notnull, offset, on, order, over,
    overlaps, precision, returning, second, to, union, varying,
    where, window, with, within, without, year

Adding to the return value of pg_get_keywords a fourth column
showing whether the keyword can be used as an implicit column label.
---
 doc/src/sgml/func.sgml                  |   6 +-
 doc/src/sgml/generate-keywords-table.pl |   2 +-
 src/backend/catalog/namespace.c         |   7 +-
 src/backend/commands/operatorcmds.c     |  13 +-
 src/backend/nodes/print.c               |   1 +
 src/backend/parser/check_keywords.pl    |  97 ++-
 src/backend/parser/gram.y               | 471 ++++++++++++-
 src/backend/parser/scan.l               |   2 +-
 src/backend/utils/adt/misc.c            |  11 +-
 src/common/keywords.c                   |   2 +-
 src/include/catalog/pg_proc.dat         |   4 +-
 src/include/common/kwlookup.h           |   8 +
 src/include/parser/kwlist.h             | 902 ++++++++++++------------
 src/interfaces/ecpg/preproc/keywords.c  |   2 +-
 src/tools/gen_keywordlist.pl            |  30 +-
 15 files changed, 1039 insertions(+), 519 deletions(-)

diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index bbbffd9d5b..4ac668bcac 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -22169,7 +22169,8 @@ 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>catdesc</parameter> <type>text</type>,
+        <parameter>aliastype</parameter> <type>text</type> )
        </para>
        <para>
         Returns a set of records describing the SQL keywords recognized by the
@@ -22181,6 +22182,9 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
         function name, or <literal>R</literal> for a fully reserved keyword.
         The <parameter>catdesc</parameter> column contains a
         possibly-localized string describing the category.
+        The <parameter>aliastype</parameter> column is
+        <literal>implicit</literal> if the keyword can be used as an implicit
+        column label, <literal>explicit</literal> otherwise.
        </para></entry>
       </row>
 
diff --git a/doc/src/sgml/generate-keywords-table.pl b/doc/src/sgml/generate-keywords-table.pl
index 824b324ef7..6ae6f80c3f 100644
--- a/doc/src/sgml/generate-keywords-table.pl
+++ b/doc/src/sgml/generate-keywords-table.pl
@@ -39,7 +39,7 @@ 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;
 	}
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index 0c78ab8af7..0152e3869a 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -1473,7 +1473,8 @@ FunctionIsVisible(Oid funcid)
  *		Given a possibly-qualified operator name and exact input datatypes,
  *		look up the operator.  Returns InvalidOid if not found.
  *
- * Pass oprleft = InvalidOid for a prefix op.
+ * Pass oprleft = InvalidOid for a prefix op, oprright = InvalidOid for
+ * a postfix op.
  *
  * If the operator name is not schema-qualified, it is sought in the current
  * namespace search path.  If the name is schema-qualified and the given
@@ -1579,8 +1580,8 @@ OpernameGetOprid(List *names, Oid oprleft, Oid oprright)
  * namespace case, we arrange for entries in earlier namespaces to mask
  * identical entries in later namespaces.
  *
- * The returned items always have two args[] entries --- one will be
- * InvalidOid for a prefix oprkind.  nargs is 2, too.
+ * The returned items always have two args[] entries --- one or the other
+ * will be InvalidOid for a prefix or postfix oprkind.  nargs is 2, too.
  */
 FuncCandidateList
 OpernameGetCandidates(List *names, char oprkind, bool missing_schema_ok)
diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c
index b468c7701b..354a184f0f 100644
--- a/src/backend/commands/operatorcmds.c
+++ b/src/backend/commands/operatorcmds.c
@@ -169,16 +169,19 @@ DefineOperator(List *names, List *parameters)
 		typeId2 = typenameTypeId(NULL, typeName2);
 
 	/*
-	 * If only the right argument is missing, the user is likely trying to
-	 * create a postfix operator, so give them a hint about why that does not
-	 * work.  But if both arguments are missing, do not mention postfix
-	 * operators, as the user most likely simply neglected to mention the
-	 * arguments.
+	 * If neither argument is specified, do not mention postfix operators, as
+	 * the user is unlikely to have meant to create one.  It is more likely
+	 * they simply neglected to mention the args.
 	 */
 	if (!OidIsValid(typeId1) && !OidIsValid(typeId2))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
 				 errmsg("operator arguments must be specified")));
+
+	/*
+	 * But if only the right arg is missing, they probably do intend to create
+	 * a postfix operator, so give them a hint about why that does not work.
+	 */
 	if (!OidIsValid(typeId2))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
diff --git a/src/backend/nodes/print.c b/src/backend/nodes/print.c
index 970a2d4384..42476724d8 100644
--- a/src/backend/nodes/print.c
+++ b/src/backend/nodes/print.c
@@ -394,6 +394,7 @@ print_expr(const Node *expr, const List *rtable)
 		}
 		else
 		{
+			/* we print prefix and postfix ops the same... */
 			printf("%s ", ((opname != NULL) ? opname : "(invalid operator)"));
 			print_expr(get_leftop((const Expr *) e), rtable);
 		}
diff --git a/src/backend/parser/check_keywords.pl b/src/backend/parser/check_keywords.pl
index 702c97bba2..ddba00c96f 100644
--- a/src/backend/parser/check_keywords.pl
+++ b/src/backend/parser/check_keywords.pl
@@ -21,6 +21,27 @@ sub error
 	return;
 }
 
+sub check_alphabetical_order
+{
+	my ($listname, $list) = @_;
+	my $prevkword = '';
+	my $implicit_alias_kword;
+
+	foreach my $kword (@$list)
+	{
+
+		# Some keyword have a _P suffix. Remove it for the comparison.
+		$implicit_alias_kword = $kword;
+		$implicit_alias_kword =~ s/_P$//;
+		if ($implicit_alias_kword le $prevkword)
+		{
+			error
+			  "'$implicit_alias_kword' after '$prevkword' in $listname list is misplaced";
+		}
+		$prevkword = $implicit_alias_kword;
+	}
+}
+
 $, = ' ';     # set output field separator
 $\ = "\n";    # set output record separator
 
@@ -33,9 +54,11 @@ $keyword_categories{'reserved_keyword'}       = 'RESERVED_KEYWORD';
 open(my $gram, '<', $gram_filename) || die("Could not open : $gram_filename");
 
 my $kcat;
+my $implicit_alias;
 my $comment;
 my @arr;
 my %keywords;
+my @implicit_alias;
 
 line: while (my $S = <$gram>)
 {
@@ -51,7 +74,7 @@ line: while (my $S = <$gram>)
 	$s = '[/][*]', $S =~ s#$s# /* #g;
 	$s = '[*][/]', $S =~ s#$s# */ #g;
 
-	if (!($kcat))
+	if (!($kcat) && !($implicit_alias))
 	{
 
 		# Is this the beginning of a keyword list?
@@ -63,6 +86,10 @@ line: while (my $S = <$gram>)
 				next line;
 			}
 		}
+
+		# Is this the beginning of the implicit_alias_keyword list?
+		$implicit_alias = 1 if ($S =~ m/^implicit_alias_keyword:/);
+
 		next line;
 	}
 
@@ -97,7 +124,8 @@ line: while (my $S = <$gram>)
 		{
 
 			# end of keyword list
-			$kcat = '';
+			undef $kcat;
+			undef $implicit_alias;
 			next;
 		}
 
@@ -107,31 +135,21 @@ line: while (my $S = <$gram>)
 		}
 
 		# Put this keyword into the right list
-		push @{ $keywords{$kcat} }, $arr[$fieldIndexer];
+		if ($implicit_alias)
+		{
+			push @implicit_alias, $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('implicit_alias_keyword', \@implicit_alias);
 
 # Transform the keyword lists into hashes.
 # kwhashes is a hash of hashes, keyed by keyword category id,
@@ -147,6 +165,7 @@ while (my ($kcat, $kcat_id) = each(%keyword_categories))
 
 	$kwhashes{$kcat_id} = $hash;
 }
+my %implicit_alias = map { $_ => 1 } @implicit_alias;
 
 # Now read in kwlist.h
 
@@ -154,17 +173,41 @@ open(my $kwlist, '<', $kwlist_filename)
   || die("Could not open : $kwlist_filename");
 
 my $prevkwstring = '';
-my $bare_kwname;
+my $implicit_alias_kwname;
 my %kwhash;
 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 ($aliastype) = $4;
+
+		# Check that the keyword label aliastype value matches treatment in gram.y
+		if ($aliastype eq 'IMPLICIT_ALIAS')
+		{
+			unless ($implicit_alias{$kwname})
+			{
+				error
+				  "'$kwstring' in kwlist.h is marked as implicit_alias, but is missing from gram.y's implicit_alias_keyword rule";
+			}
+		}
+		elsif ($aliastype eq 'EXPLICIT_ALIAS')
+		{
+			if ($implicit_alias{$kwname})
+			{
+				error
+				  "'$kwname' in kwlist.h is marked as explicit, but is listed in gram.y's implicit_alias_keyword rule";
+			}
+		}
+		else
+		{
+			error
+			  "'$aliastype' not recognized in kwlist.h.  Expected either 'IMPLICIT_ALIAS' or 'EXPLICIT_ALIAS'";
+		}
 
 		# Check that the list is in alphabetical order (critical!)
 		if ($kwstring le $prevkwstring)
@@ -189,9 +232,9 @@ kwlist_line: while (<$kwlist>)
 		}
 
 		# Check that the keyword string matches keyword name
-		$bare_kwname = $kwname;
-		$bare_kwname =~ s/_P$//;
-		if ($bare_kwname ne uc($kwstring))
+		$implicit_alias_kwname = $kwname;
+		$implicit_alias_kwname =~ s/_P$//;
+		if ($implicit_alias_kwname ne uc($kwstring))
 		{
 			error
 			  "keyword name '$kwname' doesn't match keyword string '$kwstring'";
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 2480fba771..67754881e9 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -540,14 +540,15 @@ 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 ImplicitAlias
 %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> col_name_keyword implicit_alias_keyword reserved_keyword
 
 %type <node>	TableConstraint TableLikeClause
 %type <ival>	TableLikeOptionList TableLikeOption
@@ -731,15 +732,24 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 
 
 /* Precedence: lowest to highest */
-
+%nonassoc	SET				/* see relation_expr_opt_alias */
+%left		UNION EXCEPT
+%left		INTERSECT
+%left		OR
+%left		AND
+%right		NOT
+%nonassoc	IS ISNULL NOTNULL	/* IS sets precedence for IS NULL, etc */
+%nonassoc	'<' '>' '=' LESS_EQUALS GREATER_EQUALS NOT_EQUALS
+%nonassoc	BETWEEN IN_P LIKE ILIKE SIMILAR NOT_LA
+%nonassoc	ESCAPE			/* ESCAPE must be just above LIKE/ILIKE/SIMILAR */
 /*
  * To support target_el without AS, we must give IDENT an explicit priority
- * lower than Op.  We can safely assign the same priority to various
+ * greater than Op.  We can safely assign the same priority to various
  * unreserved keywords as needed to resolve ambiguities (this can't have any
  * bad effects since obviously the keywords will still behave the same as if
  * they weren't keywords).  We need to do this:
  * for PARTITION, RANGE, ROWS, GROUPS to support opt_existing_window_name;
- * for UNBOUNDED, PRECEDING, FOLLOWING to support frame_bound;
+ * for GENERATED so that it can follow b_expr;
  *
  * To support CUBE and ROLLUP in GROUP BY without reserving them, we give them
  * an explicit priority lower than '(', so that a rule with CUBE '(' will shift
@@ -755,19 +765,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
  * keywords anywhere else in the grammar, but it's definitely risky.  We can
  * blame any funny behavior of UNBOUNDED on the SQL standard, though.
  */
-%nonassoc	UNBOUNDED IDENT
-%nonassoc	PARTITION RANGE ROWS GROUPS PRECEDING FOLLOWING CUBE ROLLUP
-
-%nonassoc	SET				/* see relation_expr_opt_alias */
-%left		UNION EXCEPT
-%left		INTERSECT
-%left		OR
-%left		AND
-%right		NOT
-%nonassoc	IS ISNULL NOTNULL	/* IS sets precedence for IS NULL, etc */
-%nonassoc	'<' '>' '=' LESS_EQUALS GREATER_EQUALS NOT_EQUALS
-%nonassoc	BETWEEN IN_P LIKE ILIKE SIMILAR NOT_LA
-%nonassoc	ESCAPE			/* ESCAPE must be just above LIKE/ILIKE/SIMILAR */
+%nonassoc	UNBOUNDED		/* ideally should have same precedence as IDENT */
+%nonassoc	IDENT GENERATED PARTITION RANGE ROWS GROUPS PRECEDING FOLLOWING CUBE ROLLUP
 %left		Op OPERATOR		/* multi-character ops and user-defined operators */
 %left		'+' '-'
 %left		'*' '/' '%'
@@ -788,6 +787,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
  * left-associativity among the JOIN rules themselves.
  */
 %left		JOIN CROSS LEFT FULL RIGHT INNER_P NATURAL
+/* kluge to keep xml_whitespace_option from causing shift/reduce conflicts */
+%right		PRESERVE STRIP_P
 
 %%
 
@@ -14649,11 +14650,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 ImplicitAlias
 				{
 					$$ = makeNode(ResTarget);
 					$$->name = $2;
@@ -14981,6 +14978,12 @@ NonReservedWord:	IDENT							{ $$ = $1; }
 			| type_func_name_keyword				{ $$ = pstrdup($1); }
 		;
 
+/* Bare column label --- names that can be column labels without writing "AS".
+ */
+ImplicitAlias:	IDENT								{ $$ = $1; }
+			| implicit_alias_keyword					{ $$ = pstrdup($1); }
+		;
+
 /* Column label --- allowed labels in "AS" clauses.
  * This presently includes *all* Postgres keywords.
  */
@@ -14992,6 +14995,428 @@ ColLabel:	IDENT									{ $$ = $1; }
 		;
 
 
+/*
+ * All keywords can be used explicitly as a column label in expressions
+ * like 'SELECT 1234 AS keyword', but only some keywords can be used
+ * implicitly as column labels in expressions like 'SELECT 1234 keyword'.
+ * Those that can be used implicitly should be listed here.
+ *
+ * Keep this in alphabetical order.
+ */
+implicit_alias_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
+		;
+
 /*
  * Keyword category lists.  Generally, every keyword present in
  * the Postgres grammar should appear in exactly one of these lists.
diff --git a/src/backend/parser/scan.l b/src/backend/parser/scan.l
index b1ea0cb538..58a8afa782 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, aliastype) 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 37c23c9155..1b04b0e079 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -416,13 +416,15 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 		funcctx = SRF_FIRSTCALL_INIT();
 		oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
 
-		tupdesc = CreateTemplateTupleDesc(3);
+		tupdesc = CreateTemplateTupleDesc(4);
 		TupleDescInitEntry(tupdesc, (AttrNumber) 1, "word",
 						   TEXTOID, -1, 0);
 		TupleDescInitEntry(tupdesc, (AttrNumber) 2, "catcode",
 						   CHAROID, -1, 0);
 		TupleDescInitEntry(tupdesc, (AttrNumber) 3, "catdesc",
 						   TEXTOID, -1, 0);
+		TupleDescInitEntry(tupdesc, (AttrNumber) 4, "aliastype",
+						   TEXTOID, -1, 0);
 
 		funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
 
@@ -433,7 +435,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 	if (funcctx->call_cntr < ScanKeywords.num_keywords)
 	{
-		char	   *values[3];
+		char	   *values[4];
 		HeapTuple	tuple;
 
 		/* cast-away-const is ugly but alternatives aren't much better */
@@ -465,6 +467,11 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 				break;
 		}
 
+		if (GetScanKeywordIsImplicit(funcctx->call_cntr, &ScanKeywords))
+			values[3] = unconstify(char *, (const char *)"implicit");
+		else
+			values[3] = unconstify(char *, (const char *)"explicit");
+
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
 		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
diff --git a/src/common/keywords.c b/src/common/keywords.c
index 54ed977096..f42cd69094 100644
--- a/src/common/keywords.c
+++ b/src/common/keywords.c
@@ -24,7 +24,7 @@
 
 /* Keyword categories for SQL keywords */
 
-#define PG_KEYWORD(kwname, value, category) category,
+#define PG_KEYWORD(kwname, value, category, aliastype) category,
 
 const uint8 ScanKeywordCategories[SCANKEYWORDS_NUM_KEYWORDS] = {
 #include "parser/kwlist.h"
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 27989971db..5135bcd28e 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -3680,8 +3680,8 @@
 { oid => '1686', descr => 'list of SQL keywords',
   proname => 'pg_get_keywords', procost => '10', prorows => '400',
   proretset => 't', provolatile => 's', prorettype => 'record',
-  proargtypes => '', proallargtypes => '{text,char,text}',
-  proargmodes => '{o,o,o}', proargnames => '{word,catcode,catdesc}',
+  proargtypes => '', proallargtypes => '{text,char,text,text}',
+  proargmodes => '{o,o,o,o}', proargnames => '{word,catcode,catdesc,aliastype}',
   prosrc => 'pg_get_keywords' },
 
 { oid => '2289', descr => 'convert generic options array to name/value table',
diff --git a/src/include/common/kwlookup.h b/src/include/common/kwlookup.h
index 9c0c7f88d8..d56b3d895e 100644
--- a/src/include/common/kwlookup.h
+++ b/src/include/common/kwlookup.h
@@ -26,6 +26,7 @@ typedef struct ScanKeywordList
 {
 	const char *kw_string;		/* all keywords in order, separated by \0 */
 	const uint16 *kw_offsets;	/* offsets to the start of each keyword */
+	const bool *kw_is_implicit;	/* whether each keyword can be used as an implicit label */
 	ScanKeywordHashFunc hash;	/* perfect hash function for keywords */
 	int			num_keywords;	/* number of keywords */
 	int			max_kw_len;		/* length of longest keyword */
@@ -41,4 +42,11 @@ GetScanKeyword(int n, const ScanKeywordList *keywords)
 	return keywords->kw_string + keywords->kw_offsets[n];
 }
 
+/* Code that wants to retrieve the aliastype of the N'th keyword should use this. */
+static inline bool
+GetScanKeywordIsImplicit(int n, const ScanKeywordList *keywords)
+{
+	return keywords->kw_is_implicit[n];
+}
+
 #endif							/* KWLOOKUP_H */
diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h
index 08f22ce211..d011b3a5e5 100644
--- a/src/include/parser/kwlist.h
+++ b/src/include/parser/kwlist.h
@@ -24,454 +24,454 @@
  * Note: gen_keywordlist.pl requires the entries to appear in ASCII order.
  */
 
-/* name, value, category */
-PG_KEYWORD("abort", ABORT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("absolute", ABSOLUTE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("access", ACCESS, UNRESERVED_KEYWORD)
-PG_KEYWORD("action", ACTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("add", ADD_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("admin", ADMIN, UNRESERVED_KEYWORD)
-PG_KEYWORD("after", AFTER, UNRESERVED_KEYWORD)
-PG_KEYWORD("aggregate", AGGREGATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("all", ALL, RESERVED_KEYWORD)
-PG_KEYWORD("also", ALSO, UNRESERVED_KEYWORD)
-PG_KEYWORD("alter", ALTER, UNRESERVED_KEYWORD)
-PG_KEYWORD("always", ALWAYS, UNRESERVED_KEYWORD)
-PG_KEYWORD("analyse", ANALYSE, RESERVED_KEYWORD)		/* British spelling */
-PG_KEYWORD("analyze", ANALYZE, RESERVED_KEYWORD)
-PG_KEYWORD("and", AND, RESERVED_KEYWORD)
-PG_KEYWORD("any", ANY, RESERVED_KEYWORD)
-PG_KEYWORD("array", ARRAY, RESERVED_KEYWORD)
-PG_KEYWORD("as", AS, RESERVED_KEYWORD)
-PG_KEYWORD("asc", ASC, RESERVED_KEYWORD)
-PG_KEYWORD("assertion", ASSERTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("assignment", ASSIGNMENT, UNRESERVED_KEYWORD)
-PG_KEYWORD("asymmetric", ASYMMETRIC, RESERVED_KEYWORD)
-PG_KEYWORD("at", AT, UNRESERVED_KEYWORD)
-PG_KEYWORD("attach", ATTACH, UNRESERVED_KEYWORD)
-PG_KEYWORD("attribute", ATTRIBUTE, UNRESERVED_KEYWORD)
-PG_KEYWORD("authorization", AUTHORIZATION, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("backward", BACKWARD, UNRESERVED_KEYWORD)
-PG_KEYWORD("before", BEFORE, UNRESERVED_KEYWORD)
-PG_KEYWORD("begin", BEGIN_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("between", BETWEEN, COL_NAME_KEYWORD)
-PG_KEYWORD("bigint", BIGINT, COL_NAME_KEYWORD)
-PG_KEYWORD("binary", BINARY, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("bit", BIT, COL_NAME_KEYWORD)
-PG_KEYWORD("boolean", BOOLEAN_P, COL_NAME_KEYWORD)
-PG_KEYWORD("both", BOTH, RESERVED_KEYWORD)
-PG_KEYWORD("by", BY, UNRESERVED_KEYWORD)
-PG_KEYWORD("cache", CACHE, UNRESERVED_KEYWORD)
-PG_KEYWORD("call", CALL, UNRESERVED_KEYWORD)
-PG_KEYWORD("called", CALLED, UNRESERVED_KEYWORD)
-PG_KEYWORD("cascade", CASCADE, UNRESERVED_KEYWORD)
-PG_KEYWORD("cascaded", CASCADED, UNRESERVED_KEYWORD)
-PG_KEYWORD("case", CASE, RESERVED_KEYWORD)
-PG_KEYWORD("cast", CAST, RESERVED_KEYWORD)
-PG_KEYWORD("catalog", CATALOG_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("chain", CHAIN, UNRESERVED_KEYWORD)
-PG_KEYWORD("char", CHAR_P, COL_NAME_KEYWORD)
-PG_KEYWORD("character", CHARACTER, COL_NAME_KEYWORD)
-PG_KEYWORD("characteristics", CHARACTERISTICS, UNRESERVED_KEYWORD)
-PG_KEYWORD("check", CHECK, RESERVED_KEYWORD)
-PG_KEYWORD("checkpoint", CHECKPOINT, UNRESERVED_KEYWORD)
-PG_KEYWORD("class", CLASS, UNRESERVED_KEYWORD)
-PG_KEYWORD("close", CLOSE, UNRESERVED_KEYWORD)
-PG_KEYWORD("cluster", CLUSTER, UNRESERVED_KEYWORD)
-PG_KEYWORD("coalesce", COALESCE, COL_NAME_KEYWORD)
-PG_KEYWORD("collate", COLLATE, RESERVED_KEYWORD)
-PG_KEYWORD("collation", COLLATION, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("column", COLUMN, RESERVED_KEYWORD)
-PG_KEYWORD("columns", COLUMNS, UNRESERVED_KEYWORD)
-PG_KEYWORD("comment", COMMENT, UNRESERVED_KEYWORD)
-PG_KEYWORD("comments", COMMENTS, UNRESERVED_KEYWORD)
-PG_KEYWORD("commit", COMMIT, UNRESERVED_KEYWORD)
-PG_KEYWORD("committed", COMMITTED, UNRESERVED_KEYWORD)
-PG_KEYWORD("concurrently", CONCURRENTLY, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("configuration", CONFIGURATION, UNRESERVED_KEYWORD)
-PG_KEYWORD("conflict", CONFLICT, UNRESERVED_KEYWORD)
-PG_KEYWORD("connection", CONNECTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("constraint", CONSTRAINT, RESERVED_KEYWORD)
-PG_KEYWORD("constraints", CONSTRAINTS, UNRESERVED_KEYWORD)
-PG_KEYWORD("content", CONTENT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("continue", CONTINUE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("conversion", CONVERSION_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("copy", COPY, UNRESERVED_KEYWORD)
-PG_KEYWORD("cost", COST, UNRESERVED_KEYWORD)
-PG_KEYWORD("create", CREATE, RESERVED_KEYWORD)
-PG_KEYWORD("cross", CROSS, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("csv", CSV, UNRESERVED_KEYWORD)
-PG_KEYWORD("cube", CUBE, UNRESERVED_KEYWORD)
-PG_KEYWORD("current", CURRENT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("current_catalog", CURRENT_CATALOG, RESERVED_KEYWORD)
-PG_KEYWORD("current_date", CURRENT_DATE, RESERVED_KEYWORD)
-PG_KEYWORD("current_role", CURRENT_ROLE, RESERVED_KEYWORD)
-PG_KEYWORD("current_schema", CURRENT_SCHEMA, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("current_time", CURRENT_TIME, RESERVED_KEYWORD)
-PG_KEYWORD("current_timestamp", CURRENT_TIMESTAMP, RESERVED_KEYWORD)
-PG_KEYWORD("current_user", CURRENT_USER, RESERVED_KEYWORD)
-PG_KEYWORD("cursor", CURSOR, UNRESERVED_KEYWORD)
-PG_KEYWORD("cycle", CYCLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("data", DATA_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("database", DATABASE, UNRESERVED_KEYWORD)
-PG_KEYWORD("day", DAY_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("deallocate", DEALLOCATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("dec", DEC, COL_NAME_KEYWORD)
-PG_KEYWORD("decimal", DECIMAL_P, COL_NAME_KEYWORD)
-PG_KEYWORD("declare", DECLARE, UNRESERVED_KEYWORD)
-PG_KEYWORD("default", DEFAULT, RESERVED_KEYWORD)
-PG_KEYWORD("defaults", DEFAULTS, UNRESERVED_KEYWORD)
-PG_KEYWORD("deferrable", DEFERRABLE, RESERVED_KEYWORD)
-PG_KEYWORD("deferred", DEFERRED, UNRESERVED_KEYWORD)
-PG_KEYWORD("definer", DEFINER, UNRESERVED_KEYWORD)
-PG_KEYWORD("delete", DELETE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("delimiter", DELIMITER, UNRESERVED_KEYWORD)
-PG_KEYWORD("delimiters", DELIMITERS, UNRESERVED_KEYWORD)
-PG_KEYWORD("depends", DEPENDS, UNRESERVED_KEYWORD)
-PG_KEYWORD("desc", DESC, RESERVED_KEYWORD)
-PG_KEYWORD("detach", DETACH, UNRESERVED_KEYWORD)
-PG_KEYWORD("dictionary", DICTIONARY, UNRESERVED_KEYWORD)
-PG_KEYWORD("disable", DISABLE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("discard", DISCARD, UNRESERVED_KEYWORD)
-PG_KEYWORD("distinct", DISTINCT, RESERVED_KEYWORD)
-PG_KEYWORD("do", DO, RESERVED_KEYWORD)
-PG_KEYWORD("document", DOCUMENT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("domain", DOMAIN_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("double", DOUBLE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("drop", DROP, UNRESERVED_KEYWORD)
-PG_KEYWORD("each", EACH, UNRESERVED_KEYWORD)
-PG_KEYWORD("else", ELSE, RESERVED_KEYWORD)
-PG_KEYWORD("enable", ENABLE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("encoding", ENCODING, UNRESERVED_KEYWORD)
-PG_KEYWORD("encrypted", ENCRYPTED, UNRESERVED_KEYWORD)
-PG_KEYWORD("end", END_P, RESERVED_KEYWORD)
-PG_KEYWORD("enum", ENUM_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("escape", ESCAPE, UNRESERVED_KEYWORD)
-PG_KEYWORD("event", EVENT, UNRESERVED_KEYWORD)
-PG_KEYWORD("except", EXCEPT, RESERVED_KEYWORD)
-PG_KEYWORD("exclude", EXCLUDE, UNRESERVED_KEYWORD)
-PG_KEYWORD("excluding", EXCLUDING, UNRESERVED_KEYWORD)
-PG_KEYWORD("exclusive", EXCLUSIVE, UNRESERVED_KEYWORD)
-PG_KEYWORD("execute", EXECUTE, UNRESERVED_KEYWORD)
-PG_KEYWORD("exists", EXISTS, COL_NAME_KEYWORD)
-PG_KEYWORD("explain", EXPLAIN, UNRESERVED_KEYWORD)
-PG_KEYWORD("expression", EXPRESSION, UNRESERVED_KEYWORD)
-PG_KEYWORD("extension", EXTENSION, UNRESERVED_KEYWORD)
-PG_KEYWORD("external", EXTERNAL, UNRESERVED_KEYWORD)
-PG_KEYWORD("extract", EXTRACT, COL_NAME_KEYWORD)
-PG_KEYWORD("false", FALSE_P, RESERVED_KEYWORD)
-PG_KEYWORD("family", FAMILY, UNRESERVED_KEYWORD)
-PG_KEYWORD("fetch", FETCH, RESERVED_KEYWORD)
-PG_KEYWORD("filter", FILTER, UNRESERVED_KEYWORD)
-PG_KEYWORD("first", FIRST_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("float", FLOAT_P, COL_NAME_KEYWORD)
-PG_KEYWORD("following", FOLLOWING, UNRESERVED_KEYWORD)
-PG_KEYWORD("for", FOR, RESERVED_KEYWORD)
-PG_KEYWORD("force", FORCE, UNRESERVED_KEYWORD)
-PG_KEYWORD("foreign", FOREIGN, RESERVED_KEYWORD)
-PG_KEYWORD("forward", FORWARD, UNRESERVED_KEYWORD)
-PG_KEYWORD("freeze", FREEZE, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("from", FROM, RESERVED_KEYWORD)
-PG_KEYWORD("full", FULL, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("function", FUNCTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("functions", FUNCTIONS, UNRESERVED_KEYWORD)
-PG_KEYWORD("generated", GENERATED, UNRESERVED_KEYWORD)
-PG_KEYWORD("global", GLOBAL, UNRESERVED_KEYWORD)
-PG_KEYWORD("grant", GRANT, RESERVED_KEYWORD)
-PG_KEYWORD("granted", GRANTED, UNRESERVED_KEYWORD)
-PG_KEYWORD("greatest", GREATEST, COL_NAME_KEYWORD)
-PG_KEYWORD("group", GROUP_P, RESERVED_KEYWORD)
-PG_KEYWORD("grouping", GROUPING, COL_NAME_KEYWORD)
-PG_KEYWORD("groups", GROUPS, UNRESERVED_KEYWORD)
-PG_KEYWORD("handler", HANDLER, UNRESERVED_KEYWORD)
-PG_KEYWORD("having", HAVING, RESERVED_KEYWORD)
-PG_KEYWORD("header", HEADER_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("hold", HOLD, UNRESERVED_KEYWORD)
-PG_KEYWORD("hour", HOUR_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("identity", IDENTITY_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("if", IF_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("ilike", ILIKE, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("immediate", IMMEDIATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("immutable", IMMUTABLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("implicit", IMPLICIT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("import", IMPORT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("in", IN_P, RESERVED_KEYWORD)
-PG_KEYWORD("include", INCLUDE, UNRESERVED_KEYWORD)
-PG_KEYWORD("including", INCLUDING, UNRESERVED_KEYWORD)
-PG_KEYWORD("increment", INCREMENT, UNRESERVED_KEYWORD)
-PG_KEYWORD("index", INDEX, UNRESERVED_KEYWORD)
-PG_KEYWORD("indexes", INDEXES, UNRESERVED_KEYWORD)
-PG_KEYWORD("inherit", INHERIT, UNRESERVED_KEYWORD)
-PG_KEYWORD("inherits", INHERITS, UNRESERVED_KEYWORD)
-PG_KEYWORD("initially", INITIALLY, RESERVED_KEYWORD)
-PG_KEYWORD("inline", INLINE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("inner", INNER_P, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("inout", INOUT, COL_NAME_KEYWORD)
-PG_KEYWORD("input", INPUT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("insensitive", INSENSITIVE, UNRESERVED_KEYWORD)
-PG_KEYWORD("insert", INSERT, UNRESERVED_KEYWORD)
-PG_KEYWORD("instead", INSTEAD, UNRESERVED_KEYWORD)
-PG_KEYWORD("int", INT_P, COL_NAME_KEYWORD)
-PG_KEYWORD("integer", INTEGER, COL_NAME_KEYWORD)
-PG_KEYWORD("intersect", INTERSECT, RESERVED_KEYWORD)
-PG_KEYWORD("interval", INTERVAL, COL_NAME_KEYWORD)
-PG_KEYWORD("into", INTO, RESERVED_KEYWORD)
-PG_KEYWORD("invoker", INVOKER, UNRESERVED_KEYWORD)
-PG_KEYWORD("is", IS, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("isnull", ISNULL, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("isolation", ISOLATION, UNRESERVED_KEYWORD)
-PG_KEYWORD("join", JOIN, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("key", KEY, UNRESERVED_KEYWORD)
-PG_KEYWORD("label", LABEL, UNRESERVED_KEYWORD)
-PG_KEYWORD("language", LANGUAGE, UNRESERVED_KEYWORD)
-PG_KEYWORD("large", LARGE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("last", LAST_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("lateral", LATERAL_P, RESERVED_KEYWORD)
-PG_KEYWORD("leading", LEADING, RESERVED_KEYWORD)
-PG_KEYWORD("leakproof", LEAKPROOF, UNRESERVED_KEYWORD)
-PG_KEYWORD("least", LEAST, COL_NAME_KEYWORD)
-PG_KEYWORD("left", LEFT, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("level", LEVEL, UNRESERVED_KEYWORD)
-PG_KEYWORD("like", LIKE, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("limit", LIMIT, RESERVED_KEYWORD)
-PG_KEYWORD("listen", LISTEN, UNRESERVED_KEYWORD)
-PG_KEYWORD("load", LOAD, UNRESERVED_KEYWORD)
-PG_KEYWORD("local", LOCAL, UNRESERVED_KEYWORD)
-PG_KEYWORD("localtime", LOCALTIME, RESERVED_KEYWORD)
-PG_KEYWORD("localtimestamp", LOCALTIMESTAMP, RESERVED_KEYWORD)
-PG_KEYWORD("location", LOCATION, UNRESERVED_KEYWORD)
-PG_KEYWORD("lock", LOCK_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("locked", LOCKED, UNRESERVED_KEYWORD)
-PG_KEYWORD("logged", LOGGED, UNRESERVED_KEYWORD)
-PG_KEYWORD("mapping", MAPPING, UNRESERVED_KEYWORD)
-PG_KEYWORD("match", MATCH, UNRESERVED_KEYWORD)
-PG_KEYWORD("materialized", MATERIALIZED, UNRESERVED_KEYWORD)
-PG_KEYWORD("maxvalue", MAXVALUE, UNRESERVED_KEYWORD)
-PG_KEYWORD("method", METHOD, UNRESERVED_KEYWORD)
-PG_KEYWORD("minute", MINUTE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("minvalue", MINVALUE, UNRESERVED_KEYWORD)
-PG_KEYWORD("mode", MODE, UNRESERVED_KEYWORD)
-PG_KEYWORD("month", MONTH_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("move", MOVE, UNRESERVED_KEYWORD)
-PG_KEYWORD("name", NAME_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("names", NAMES, UNRESERVED_KEYWORD)
-PG_KEYWORD("national", NATIONAL, COL_NAME_KEYWORD)
-PG_KEYWORD("natural", NATURAL, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("nchar", NCHAR, COL_NAME_KEYWORD)
-PG_KEYWORD("new", NEW, UNRESERVED_KEYWORD)
-PG_KEYWORD("next", NEXT, UNRESERVED_KEYWORD)
-PG_KEYWORD("nfc", NFC, UNRESERVED_KEYWORD)
-PG_KEYWORD("nfd", NFD, UNRESERVED_KEYWORD)
-PG_KEYWORD("nfkc", NFKC, UNRESERVED_KEYWORD)
-PG_KEYWORD("nfkd", NFKD, UNRESERVED_KEYWORD)
-PG_KEYWORD("no", NO, UNRESERVED_KEYWORD)
-PG_KEYWORD("none", NONE, COL_NAME_KEYWORD)
-PG_KEYWORD("normalize", NORMALIZE, COL_NAME_KEYWORD)
-PG_KEYWORD("normalized", NORMALIZED, UNRESERVED_KEYWORD)
-PG_KEYWORD("not", NOT, RESERVED_KEYWORD)
-PG_KEYWORD("nothing", NOTHING, UNRESERVED_KEYWORD)
-PG_KEYWORD("notify", NOTIFY, UNRESERVED_KEYWORD)
-PG_KEYWORD("notnull", NOTNULL, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("nowait", NOWAIT, UNRESERVED_KEYWORD)
-PG_KEYWORD("null", NULL_P, RESERVED_KEYWORD)
-PG_KEYWORD("nullif", NULLIF, COL_NAME_KEYWORD)
-PG_KEYWORD("nulls", NULLS_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("numeric", NUMERIC, COL_NAME_KEYWORD)
-PG_KEYWORD("object", OBJECT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("of", OF, UNRESERVED_KEYWORD)
-PG_KEYWORD("off", OFF, UNRESERVED_KEYWORD)
-PG_KEYWORD("offset", OFFSET, RESERVED_KEYWORD)
-PG_KEYWORD("oids", OIDS, UNRESERVED_KEYWORD)
-PG_KEYWORD("old", OLD, UNRESERVED_KEYWORD)
-PG_KEYWORD("on", ON, RESERVED_KEYWORD)
-PG_KEYWORD("only", ONLY, RESERVED_KEYWORD)
-PG_KEYWORD("operator", OPERATOR, UNRESERVED_KEYWORD)
-PG_KEYWORD("option", OPTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("options", OPTIONS, UNRESERVED_KEYWORD)
-PG_KEYWORD("or", OR, RESERVED_KEYWORD)
-PG_KEYWORD("order", ORDER, RESERVED_KEYWORD)
-PG_KEYWORD("ordinality", ORDINALITY, UNRESERVED_KEYWORD)
-PG_KEYWORD("others", OTHERS, UNRESERVED_KEYWORD)
-PG_KEYWORD("out", OUT_P, COL_NAME_KEYWORD)
-PG_KEYWORD("outer", OUTER_P, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("over", OVER, UNRESERVED_KEYWORD)
-PG_KEYWORD("overlaps", OVERLAPS, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("overlay", OVERLAY, COL_NAME_KEYWORD)
-PG_KEYWORD("overriding", OVERRIDING, UNRESERVED_KEYWORD)
-PG_KEYWORD("owned", OWNED, UNRESERVED_KEYWORD)
-PG_KEYWORD("owner", OWNER, UNRESERVED_KEYWORD)
-PG_KEYWORD("parallel", PARALLEL, UNRESERVED_KEYWORD)
-PG_KEYWORD("parser", PARSER, UNRESERVED_KEYWORD)
-PG_KEYWORD("partial", PARTIAL, UNRESERVED_KEYWORD)
-PG_KEYWORD("partition", PARTITION, UNRESERVED_KEYWORD)
-PG_KEYWORD("passing", PASSING, UNRESERVED_KEYWORD)
-PG_KEYWORD("password", PASSWORD, UNRESERVED_KEYWORD)
-PG_KEYWORD("placing", PLACING, RESERVED_KEYWORD)
-PG_KEYWORD("plans", PLANS, UNRESERVED_KEYWORD)
-PG_KEYWORD("policy", POLICY, UNRESERVED_KEYWORD)
-PG_KEYWORD("position", POSITION, COL_NAME_KEYWORD)
-PG_KEYWORD("preceding", PRECEDING, UNRESERVED_KEYWORD)
-PG_KEYWORD("precision", PRECISION, COL_NAME_KEYWORD)
-PG_KEYWORD("prepare", PREPARE, UNRESERVED_KEYWORD)
-PG_KEYWORD("prepared", PREPARED, UNRESERVED_KEYWORD)
-PG_KEYWORD("preserve", PRESERVE, UNRESERVED_KEYWORD)
-PG_KEYWORD("primary", PRIMARY, RESERVED_KEYWORD)
-PG_KEYWORD("prior", PRIOR, UNRESERVED_KEYWORD)
-PG_KEYWORD("privileges", PRIVILEGES, UNRESERVED_KEYWORD)
-PG_KEYWORD("procedural", PROCEDURAL, UNRESERVED_KEYWORD)
-PG_KEYWORD("procedure", PROCEDURE, UNRESERVED_KEYWORD)
-PG_KEYWORD("procedures", PROCEDURES, UNRESERVED_KEYWORD)
-PG_KEYWORD("program", PROGRAM, UNRESERVED_KEYWORD)
-PG_KEYWORD("publication", PUBLICATION, UNRESERVED_KEYWORD)
-PG_KEYWORD("quote", QUOTE, UNRESERVED_KEYWORD)
-PG_KEYWORD("range", RANGE, UNRESERVED_KEYWORD)
-PG_KEYWORD("read", READ, UNRESERVED_KEYWORD)
-PG_KEYWORD("real", REAL, COL_NAME_KEYWORD)
-PG_KEYWORD("reassign", REASSIGN, UNRESERVED_KEYWORD)
-PG_KEYWORD("recheck", RECHECK, UNRESERVED_KEYWORD)
-PG_KEYWORD("recursive", RECURSIVE, UNRESERVED_KEYWORD)
-PG_KEYWORD("ref", REF, UNRESERVED_KEYWORD)
-PG_KEYWORD("references", REFERENCES, RESERVED_KEYWORD)
-PG_KEYWORD("referencing", REFERENCING, UNRESERVED_KEYWORD)
-PG_KEYWORD("refresh", REFRESH, UNRESERVED_KEYWORD)
-PG_KEYWORD("reindex", REINDEX, UNRESERVED_KEYWORD)
-PG_KEYWORD("relative", RELATIVE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("release", RELEASE, UNRESERVED_KEYWORD)
-PG_KEYWORD("rename", RENAME, UNRESERVED_KEYWORD)
-PG_KEYWORD("repeatable", REPEATABLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("replace", REPLACE, UNRESERVED_KEYWORD)
-PG_KEYWORD("replica", REPLICA, UNRESERVED_KEYWORD)
-PG_KEYWORD("reset", RESET, UNRESERVED_KEYWORD)
-PG_KEYWORD("restart", RESTART, UNRESERVED_KEYWORD)
-PG_KEYWORD("restrict", RESTRICT, UNRESERVED_KEYWORD)
-PG_KEYWORD("returning", RETURNING, RESERVED_KEYWORD)
-PG_KEYWORD("returns", RETURNS, UNRESERVED_KEYWORD)
-PG_KEYWORD("revoke", REVOKE, UNRESERVED_KEYWORD)
-PG_KEYWORD("right", RIGHT, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("role", ROLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("rollback", ROLLBACK, UNRESERVED_KEYWORD)
-PG_KEYWORD("rollup", ROLLUP, UNRESERVED_KEYWORD)
-PG_KEYWORD("routine", ROUTINE, UNRESERVED_KEYWORD)
-PG_KEYWORD("routines", ROUTINES, UNRESERVED_KEYWORD)
-PG_KEYWORD("row", ROW, COL_NAME_KEYWORD)
-PG_KEYWORD("rows", ROWS, UNRESERVED_KEYWORD)
-PG_KEYWORD("rule", RULE, UNRESERVED_KEYWORD)
-PG_KEYWORD("savepoint", SAVEPOINT, UNRESERVED_KEYWORD)
-PG_KEYWORD("schema", SCHEMA, UNRESERVED_KEYWORD)
-PG_KEYWORD("schemas", SCHEMAS, UNRESERVED_KEYWORD)
-PG_KEYWORD("scroll", SCROLL, UNRESERVED_KEYWORD)
-PG_KEYWORD("search", SEARCH, UNRESERVED_KEYWORD)
-PG_KEYWORD("second", SECOND_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("security", SECURITY, UNRESERVED_KEYWORD)
-PG_KEYWORD("select", SELECT, RESERVED_KEYWORD)
-PG_KEYWORD("sequence", SEQUENCE, UNRESERVED_KEYWORD)
-PG_KEYWORD("sequences", SEQUENCES, UNRESERVED_KEYWORD)
-PG_KEYWORD("serializable", SERIALIZABLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("server", SERVER, UNRESERVED_KEYWORD)
-PG_KEYWORD("session", SESSION, UNRESERVED_KEYWORD)
-PG_KEYWORD("session_user", SESSION_USER, RESERVED_KEYWORD)
-PG_KEYWORD("set", SET, UNRESERVED_KEYWORD)
-PG_KEYWORD("setof", SETOF, COL_NAME_KEYWORD)
-PG_KEYWORD("sets", SETS, UNRESERVED_KEYWORD)
-PG_KEYWORD("share", SHARE, UNRESERVED_KEYWORD)
-PG_KEYWORD("show", SHOW, UNRESERVED_KEYWORD)
-PG_KEYWORD("similar", SIMILAR, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("simple", SIMPLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("skip", SKIP, UNRESERVED_KEYWORD)
-PG_KEYWORD("smallint", SMALLINT, COL_NAME_KEYWORD)
-PG_KEYWORD("snapshot", SNAPSHOT, UNRESERVED_KEYWORD)
-PG_KEYWORD("some", SOME, RESERVED_KEYWORD)
-PG_KEYWORD("sql", SQL_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("stable", STABLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("standalone", STANDALONE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("start", START, UNRESERVED_KEYWORD)
-PG_KEYWORD("statement", STATEMENT, UNRESERVED_KEYWORD)
-PG_KEYWORD("statistics", STATISTICS, UNRESERVED_KEYWORD)
-PG_KEYWORD("stdin", STDIN, UNRESERVED_KEYWORD)
-PG_KEYWORD("stdout", STDOUT, UNRESERVED_KEYWORD)
-PG_KEYWORD("storage", STORAGE, UNRESERVED_KEYWORD)
-PG_KEYWORD("stored", STORED, UNRESERVED_KEYWORD)
-PG_KEYWORD("strict", STRICT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("strip", STRIP_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("subscription", SUBSCRIPTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("substring", SUBSTRING, COL_NAME_KEYWORD)
-PG_KEYWORD("support", SUPPORT, UNRESERVED_KEYWORD)
-PG_KEYWORD("symmetric", SYMMETRIC, RESERVED_KEYWORD)
-PG_KEYWORD("sysid", SYSID, UNRESERVED_KEYWORD)
-PG_KEYWORD("system", SYSTEM_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("table", TABLE, RESERVED_KEYWORD)
-PG_KEYWORD("tables", TABLES, UNRESERVED_KEYWORD)
-PG_KEYWORD("tablesample", TABLESAMPLE, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("tablespace", TABLESPACE, UNRESERVED_KEYWORD)
-PG_KEYWORD("temp", TEMP, UNRESERVED_KEYWORD)
-PG_KEYWORD("template", TEMPLATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("temporary", TEMPORARY, UNRESERVED_KEYWORD)
-PG_KEYWORD("text", TEXT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("then", THEN, RESERVED_KEYWORD)
-PG_KEYWORD("ties", TIES, UNRESERVED_KEYWORD)
-PG_KEYWORD("time", TIME, COL_NAME_KEYWORD)
-PG_KEYWORD("timestamp", TIMESTAMP, COL_NAME_KEYWORD)
-PG_KEYWORD("to", TO, RESERVED_KEYWORD)
-PG_KEYWORD("trailing", TRAILING, RESERVED_KEYWORD)
-PG_KEYWORD("transaction", TRANSACTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("transform", TRANSFORM, UNRESERVED_KEYWORD)
-PG_KEYWORD("treat", TREAT, COL_NAME_KEYWORD)
-PG_KEYWORD("trigger", TRIGGER, UNRESERVED_KEYWORD)
-PG_KEYWORD("trim", TRIM, COL_NAME_KEYWORD)
-PG_KEYWORD("true", TRUE_P, RESERVED_KEYWORD)
-PG_KEYWORD("truncate", TRUNCATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("trusted", TRUSTED, UNRESERVED_KEYWORD)
-PG_KEYWORD("type", TYPE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("types", TYPES_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("uescape", UESCAPE, UNRESERVED_KEYWORD)
-PG_KEYWORD("unbounded", UNBOUNDED, UNRESERVED_KEYWORD)
-PG_KEYWORD("uncommitted", UNCOMMITTED, UNRESERVED_KEYWORD)
-PG_KEYWORD("unencrypted", UNENCRYPTED, UNRESERVED_KEYWORD)
-PG_KEYWORD("union", UNION, RESERVED_KEYWORD)
-PG_KEYWORD("unique", UNIQUE, RESERVED_KEYWORD)
-PG_KEYWORD("unknown", UNKNOWN, UNRESERVED_KEYWORD)
-PG_KEYWORD("unlisten", UNLISTEN, UNRESERVED_KEYWORD)
-PG_KEYWORD("unlogged", UNLOGGED, UNRESERVED_KEYWORD)
-PG_KEYWORD("until", UNTIL, UNRESERVED_KEYWORD)
-PG_KEYWORD("update", UPDATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("user", USER, RESERVED_KEYWORD)
-PG_KEYWORD("using", USING, RESERVED_KEYWORD)
-PG_KEYWORD("vacuum", VACUUM, UNRESERVED_KEYWORD)
-PG_KEYWORD("valid", VALID, UNRESERVED_KEYWORD)
-PG_KEYWORD("validate", VALIDATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("validator", VALIDATOR, UNRESERVED_KEYWORD)
-PG_KEYWORD("value", VALUE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("values", VALUES, COL_NAME_KEYWORD)
-PG_KEYWORD("varchar", VARCHAR, COL_NAME_KEYWORD)
-PG_KEYWORD("variadic", VARIADIC, RESERVED_KEYWORD)
-PG_KEYWORD("varying", VARYING, UNRESERVED_KEYWORD)
-PG_KEYWORD("verbose", VERBOSE, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("version", VERSION_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("view", VIEW, UNRESERVED_KEYWORD)
-PG_KEYWORD("views", VIEWS, UNRESERVED_KEYWORD)
-PG_KEYWORD("volatile", VOLATILE, UNRESERVED_KEYWORD)
-PG_KEYWORD("when", WHEN, RESERVED_KEYWORD)
-PG_KEYWORD("where", WHERE, RESERVED_KEYWORD)
-PG_KEYWORD("whitespace", WHITESPACE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("window", WINDOW, RESERVED_KEYWORD)
-PG_KEYWORD("with", WITH, RESERVED_KEYWORD)
-PG_KEYWORD("within", WITHIN, UNRESERVED_KEYWORD)
-PG_KEYWORD("without", WITHOUT, UNRESERVED_KEYWORD)
-PG_KEYWORD("work", WORK, UNRESERVED_KEYWORD)
-PG_KEYWORD("wrapper", WRAPPER, UNRESERVED_KEYWORD)
-PG_KEYWORD("write", WRITE, UNRESERVED_KEYWORD)
-PG_KEYWORD("xml", XML_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("xmlattributes", XMLATTRIBUTES, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlconcat", XMLCONCAT, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlelement", XMLELEMENT, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlexists", XMLEXISTS, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlforest", XMLFOREST, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlnamespaces", XMLNAMESPACES, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlparse", XMLPARSE, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlpi", XMLPI, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlroot", XMLROOT, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlserialize", XMLSERIALIZE, COL_NAME_KEYWORD)
-PG_KEYWORD("xmltable", XMLTABLE, COL_NAME_KEYWORD)
-PG_KEYWORD("year", YEAR_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("yes", YES_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("zone", ZONE, UNRESERVED_KEYWORD)
+/* name, value, category, aliastype */
+PG_KEYWORD("abort", ABORT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("absolute", ABSOLUTE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("access", ACCESS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("action", ACTION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("add", ADD_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("admin", ADMIN, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("after", AFTER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("aggregate", AGGREGATE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("all", ALL, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("also", ALSO, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("alter", ALTER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("always", ALWAYS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("analyse", ANALYSE, RESERVED_KEYWORD, IMPLICIT_ALIAS)		/* British spelling */
+PG_KEYWORD("analyze", ANALYZE, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("and", AND, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("any", ANY, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("array", ARRAY, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("as", AS, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("asc", ASC, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("assertion", ASSERTION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("assignment", ASSIGNMENT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("asymmetric", ASYMMETRIC, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("at", AT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("attach", ATTACH, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("attribute", ATTRIBUTE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("authorization", AUTHORIZATION, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("backward", BACKWARD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("before", BEFORE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("begin", BEGIN_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("between", BETWEEN, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("bigint", BIGINT, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("binary", BINARY, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("bit", BIT, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("boolean", BOOLEAN_P, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("both", BOTH, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("by", BY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("cache", CACHE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("call", CALL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("called", CALLED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("cascade", CASCADE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("cascaded", CASCADED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("case", CASE, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("cast", CAST, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("catalog", CATALOG_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("chain", CHAIN, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("char", CHAR_P, COL_NAME_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("character", CHARACTER, COL_NAME_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("characteristics", CHARACTERISTICS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("check", CHECK, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("checkpoint", CHECKPOINT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("class", CLASS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("close", CLOSE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("cluster", CLUSTER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("coalesce", COALESCE, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("collate", COLLATE, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("collation", COLLATION, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("column", COLUMN, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("columns", COLUMNS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("comment", COMMENT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("comments", COMMENTS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("commit", COMMIT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("committed", COMMITTED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("concurrently", CONCURRENTLY, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("configuration", CONFIGURATION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("conflict", CONFLICT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("connection", CONNECTION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("constraint", CONSTRAINT, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("constraints", CONSTRAINTS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("content", CONTENT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("continue", CONTINUE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("conversion", CONVERSION_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("copy", COPY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("cost", COST, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("create", CREATE, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("cross", CROSS, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("csv", CSV, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("cube", CUBE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("current", CURRENT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("current_catalog", CURRENT_CATALOG, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("current_date", CURRENT_DATE, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("current_role", CURRENT_ROLE, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("current_schema", CURRENT_SCHEMA, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("current_time", CURRENT_TIME, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("current_timestamp", CURRENT_TIMESTAMP, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("current_user", CURRENT_USER, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("cursor", CURSOR, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("cycle", CYCLE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("data", DATA_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("database", DATABASE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("day", DAY_P, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("deallocate", DEALLOCATE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("dec", DEC, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("decimal", DECIMAL_P, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("declare", DECLARE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("default", DEFAULT, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("defaults", DEFAULTS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("deferrable", DEFERRABLE, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("deferred", DEFERRED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("definer", DEFINER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("delete", DELETE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("delimiter", DELIMITER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("delimiters", DELIMITERS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("depends", DEPENDS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("desc", DESC, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("detach", DETACH, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("dictionary", DICTIONARY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("disable", DISABLE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("discard", DISCARD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("distinct", DISTINCT, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("do", DO, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("document", DOCUMENT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("domain", DOMAIN_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("double", DOUBLE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("drop", DROP, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("each", EACH, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("else", ELSE, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("enable", ENABLE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("encoding", ENCODING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("encrypted", ENCRYPTED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("end", END_P, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("enum", ENUM_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("escape", ESCAPE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("event", EVENT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("except", EXCEPT, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("exclude", EXCLUDE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("excluding", EXCLUDING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("exclusive", EXCLUSIVE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("execute", EXECUTE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("exists", EXISTS, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("explain", EXPLAIN, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("expression", EXPRESSION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("extension", EXTENSION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("external", EXTERNAL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("extract", EXTRACT, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("false", FALSE_P, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("family", FAMILY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("fetch", FETCH, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("filter", FILTER, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("first", FIRST_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("float", FLOAT_P, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("following", FOLLOWING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("for", FOR, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("force", FORCE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("foreign", FOREIGN, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("forward", FORWARD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("freeze", FREEZE, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("from", FROM, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("full", FULL, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("function", FUNCTION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("functions", FUNCTIONS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("generated", GENERATED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("global", GLOBAL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("grant", GRANT, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("granted", GRANTED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("greatest", GREATEST, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("group", GROUP_P, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("grouping", GROUPING, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("groups", GROUPS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("handler", HANDLER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("having", HAVING, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("header", HEADER_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("hold", HOLD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("hour", HOUR_P, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("identity", IDENTITY_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("if", IF_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("ilike", ILIKE, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("immediate", IMMEDIATE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("immutable", IMMUTABLE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("implicit", IMPLICIT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("import", IMPORT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("in", IN_P, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("include", INCLUDE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("including", INCLUDING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("increment", INCREMENT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("index", INDEX, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("indexes", INDEXES, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("inherit", INHERIT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("inherits", INHERITS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("initially", INITIALLY, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("inline", INLINE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("inner", INNER_P, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("inout", INOUT, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("input", INPUT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("insensitive", INSENSITIVE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("insert", INSERT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("instead", INSTEAD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("int", INT_P, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("integer", INTEGER, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("intersect", INTERSECT, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("interval", INTERVAL, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("into", INTO, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("invoker", INVOKER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("is", IS, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("isnull", ISNULL, TYPE_FUNC_NAME_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("isolation", ISOLATION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("join", JOIN, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("key", KEY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("label", LABEL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("language", LANGUAGE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("large", LARGE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("last", LAST_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("lateral", LATERAL_P, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("leading", LEADING, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("leakproof", LEAKPROOF, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("least", LEAST, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("left", LEFT, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("level", LEVEL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("like", LIKE, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("limit", LIMIT, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("listen", LISTEN, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("load", LOAD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("local", LOCAL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("localtime", LOCALTIME, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("localtimestamp", LOCALTIMESTAMP, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("location", LOCATION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("lock", LOCK_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("locked", LOCKED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("logged", LOGGED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("mapping", MAPPING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("match", MATCH, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("materialized", MATERIALIZED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("maxvalue", MAXVALUE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("method", METHOD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("minute", MINUTE_P, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("minvalue", MINVALUE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("mode", MODE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("month", MONTH_P, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("move", MOVE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("name", NAME_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("names", NAMES, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("national", NATIONAL, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("natural", NATURAL, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("nchar", NCHAR, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("new", NEW, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("next", NEXT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("nfc", NFC, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("nfd", NFD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("nfkc", NFKC, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("nfkd", NFKD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("no", NO, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("none", NONE, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("normalize", NORMALIZE, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("normalized", NORMALIZED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("not", NOT, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("nothing", NOTHING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("notify", NOTIFY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("notnull", NOTNULL, TYPE_FUNC_NAME_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("nowait", NOWAIT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("null", NULL_P, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("nullif", NULLIF, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("nulls", NULLS_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("numeric", NUMERIC, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("object", OBJECT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("of", OF, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("off", OFF, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("offset", OFFSET, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("oids", OIDS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("old", OLD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("on", ON, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("only", ONLY, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("operator", OPERATOR, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("option", OPTION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("options", OPTIONS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("or", OR, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("order", ORDER, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("ordinality", ORDINALITY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("others", OTHERS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("out", OUT_P, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("outer", OUTER_P, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("over", OVER, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("overlaps", OVERLAPS, TYPE_FUNC_NAME_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("overlay", OVERLAY, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("overriding", OVERRIDING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("owned", OWNED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("owner", OWNER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("parallel", PARALLEL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("parser", PARSER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("partial", PARTIAL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("partition", PARTITION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("passing", PASSING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("password", PASSWORD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("placing", PLACING, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("plans", PLANS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("policy", POLICY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("position", POSITION, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("preceding", PRECEDING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("precision", PRECISION, COL_NAME_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("prepare", PREPARE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("prepared", PREPARED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("preserve", PRESERVE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("primary", PRIMARY, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("prior", PRIOR, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("privileges", PRIVILEGES, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("procedural", PROCEDURAL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("procedure", PROCEDURE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("procedures", PROCEDURES, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("program", PROGRAM, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("publication", PUBLICATION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("quote", QUOTE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("range", RANGE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("read", READ, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("real", REAL, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("reassign", REASSIGN, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("recheck", RECHECK, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("recursive", RECURSIVE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("ref", REF, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("references", REFERENCES, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("referencing", REFERENCING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("refresh", REFRESH, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("reindex", REINDEX, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("relative", RELATIVE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("release", RELEASE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("rename", RENAME, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("repeatable", REPEATABLE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("replace", REPLACE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("replica", REPLICA, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("reset", RESET, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("restart", RESTART, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("restrict", RESTRICT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("returning", RETURNING, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("returns", RETURNS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("revoke", REVOKE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("right", RIGHT, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("role", ROLE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("rollback", ROLLBACK, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("rollup", ROLLUP, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("routine", ROUTINE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("routines", ROUTINES, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("row", ROW, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("rows", ROWS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("rule", RULE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("savepoint", SAVEPOINT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("schema", SCHEMA, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("schemas", SCHEMAS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("scroll", SCROLL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("search", SEARCH, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("second", SECOND_P, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("security", SECURITY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("select", SELECT, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("sequence", SEQUENCE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("sequences", SEQUENCES, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("serializable", SERIALIZABLE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("server", SERVER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("session", SESSION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("session_user", SESSION_USER, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("set", SET, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("setof", SETOF, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("sets", SETS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("share", SHARE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("show", SHOW, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("similar", SIMILAR, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("simple", SIMPLE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("skip", SKIP, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("smallint", SMALLINT, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("snapshot", SNAPSHOT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("some", SOME, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("sql", SQL_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("stable", STABLE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("standalone", STANDALONE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("start", START, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("statement", STATEMENT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("statistics", STATISTICS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("stdin", STDIN, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("stdout", STDOUT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("storage", STORAGE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("stored", STORED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("strict", STRICT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("strip", STRIP_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("subscription", SUBSCRIPTION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("substring", SUBSTRING, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("support", SUPPORT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("symmetric", SYMMETRIC, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("sysid", SYSID, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("system", SYSTEM_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("table", TABLE, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("tables", TABLES, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("tablesample", TABLESAMPLE, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("tablespace", TABLESPACE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("temp", TEMP, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("template", TEMPLATE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("temporary", TEMPORARY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("text", TEXT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("then", THEN, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("ties", TIES, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("time", TIME, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("timestamp", TIMESTAMP, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("to", TO, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("trailing", TRAILING, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("transaction", TRANSACTION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("transform", TRANSFORM, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("treat", TREAT, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("trigger", TRIGGER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("trim", TRIM, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("true", TRUE_P, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("truncate", TRUNCATE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("trusted", TRUSTED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("type", TYPE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("types", TYPES_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("uescape", UESCAPE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("unbounded", UNBOUNDED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("uncommitted", UNCOMMITTED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("unencrypted", UNENCRYPTED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("union", UNION, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("unique", UNIQUE, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("unknown", UNKNOWN, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("unlisten", UNLISTEN, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("unlogged", UNLOGGED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("until", UNTIL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("update", UPDATE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("user", USER, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("using", USING, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("vacuum", VACUUM, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("valid", VALID, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("validate", VALIDATE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("validator", VALIDATOR, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("value", VALUE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("values", VALUES, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("varchar", VARCHAR, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("variadic", VARIADIC, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("varying", VARYING, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("verbose", VERBOSE, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("version", VERSION_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("view", VIEW, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("views", VIEWS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("volatile", VOLATILE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("when", WHEN, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("where", WHERE, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("whitespace", WHITESPACE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("window", WINDOW, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("with", WITH, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("within", WITHIN, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("without", WITHOUT, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("work", WORK, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("wrapper", WRAPPER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("write", WRITE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xml", XML_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlattributes", XMLATTRIBUTES, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlconcat", XMLCONCAT, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlelement", XMLELEMENT, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlexists", XMLEXISTS, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlforest", XMLFOREST, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlnamespaces", XMLNAMESPACES, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlparse", XMLPARSE, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlpi", XMLPI, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlroot", XMLROOT, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlserialize", XMLSERIALIZE, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmltable", XMLTABLE, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("year", YEAR_P, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("yes", YES_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("zone", ZONE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
diff --git a/src/interfaces/ecpg/preproc/keywords.c b/src/interfaces/ecpg/preproc/keywords.c
index f82764aeb9..624b8bfe60 100644
--- a/src/interfaces/ecpg/preproc/keywords.c
+++ b/src/interfaces/ecpg/preproc/keywords.c
@@ -29,7 +29,7 @@
 #include "preproc_extern.h"
 #include "preproc.h"
 
-#define PG_KEYWORD(kwname, value, category) value,
+#define PG_KEYWORD(kwname, value, category, aliastype) value,
 
 const uint16 SQLScanKeywordTokens[] = {
 #include "parser/kwlist.h"
diff --git a/src/tools/gen_keywordlist.pl b/src/tools/gen_keywordlist.pl
index e9250b8fb2..ad433d416e 100644
--- a/src/tools/gen_keywordlist.pl
+++ b/src/tools/gen_keywordlist.pl
@@ -93,11 +93,27 @@ EOM
 
 # Parse input file for keyword names.
 my @keywords;
+my @implicit_alias;
+my %transform = ( IMPLICIT_ALIAS => 'true', EXPLICIT_ALIAS => 'false');
 while (<$kif>)
 {
 	if (/^PG_KEYWORD\("(\w+)"/)
 	{
-		push @keywords, $1;
+		my $kword = $1;
+		push @keywords, $kword;
+
+		if (/^PG_KEYWORD\("\w+", .*, (IMPLICIT_ALIAS|EXPLICIT_ALIAS)\)/)
+		{
+			push @implicit_alias, $transform{$1};
+		}
+		else
+		{
+			# parser/kwlist.h lists each keyword as either an implicit or an
+			# explicit alias, but other kwlist files do not, and for them, it
+			# won't matter what we use here as long as it is a valid boolean,
+			# so we arbitrarily use 'true'.
+			push @implicit_alias, 'true';
+		}
 	}
 }
 
@@ -153,6 +169,17 @@ foreach my $name (@keywords)
 
 print $kwdef "};\n\n";
 
+# Emit an array of boolean as implicit alias values
+
+printf $kwdef "static const bool %s_kw_is_implicit[] = {\n", $varname;
+
+foreach my $bool (@implicit_alias)
+{
+	print $kwdef "\t$bool,\n";
+}
+
+print $kwdef "};\n\n";
+
 # Emit a macro defining the number of keywords.
 # (In some places it's useful to have access to that as a constant.)
 
@@ -173,6 +200,7 @@ printf $kwdef "static " if !$extern;
 printf $kwdef "const ScanKeywordList %s = {\n", $varname;
 printf $kwdef qq|\t%s_kw_string,\n|,            $varname;
 printf $kwdef qq|\t%s_kw_offsets,\n|,           $varname;
+printf $kwdef qq|\t%s_kw_is_implicit,\n|,       $varname;
 printf $kwdef qq|\t%s,\n|,                      $funcname;
 printf $kwdef qq|\t%s_NUM_KEYWORDS,\n|,         uc $varname;
 printf $kwdef qq|\t%d\n|,                       $max_len;
-- 
2.21.1 (Apple Git-122.3)

v5-0003-Updating-prorows-for-pg_get_keywords.patchapplication/octet-stream; name=v5-0003-Updating-prorows-for-pg_get_keywords.patch; x-unix-mode=0644Download
From 76421e701c14473c7bb6886f5a429413a0a484f3 Mon Sep 17 00:00:00 2001
From: Mark Dilger <mark.dilger@enterprisedb.com>
Date: Wed, 26 Aug 2020 07:49:28 -0700
Subject: [PATCH v5 3/3] Updating prorows for pg_get_keywords()

---
 src/include/catalog/pg_proc.dat | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 5135bcd28e..d6fba056aa 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -3678,7 +3678,7 @@
   prosrc => 'pg_get_function_arg_default' },
 
 { oid => '1686', descr => 'list of SQL keywords',
-  proname => 'pg_get_keywords', procost => '10', prorows => '400',
+  proname => 'pg_get_keywords', procost => '10', prorows => '450',
   proretset => 't', provolatile => 's', prorettype => 'record',
   proargtypes => '', proallargtypes => '{text,char,text,text}',
   proargmodes => '{o,o,o,o}', proargnames => '{word,catcode,catdesc,aliastype}',
-- 
2.21.1 (Apple Git-122.3)

#41Robert Haas
robertmhaas@gmail.com
In reply to: Mark Dilger (#40)
Re: factorial function/phase out postfix operators?

On Wed, Aug 26, 2020 at 11:57 AM Mark Dilger
<mark.dilger@enterprisedb.com> wrote:

I wonder if we can get more comments for or against this patch, at least in principle, in the very near future, to help determine whether the deprecation notices should go into v13?

Speaking of that, has somebody written a specific patch for that?
Like, exactly what are we proposing that this deprecation warning is
going to say?

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#42John Naylor
john.naylor@2ndquadrant.com
In reply to: Mark Dilger (#40)
Re: factorial function/phase out postfix operators?

On Wed, Aug 26, 2020 at 6:57 PM Mark Dilger
<mark.dilger@enterprisedb.com> wrote:

On Aug 26, 2020, at 6:33 AM, John Naylor <john.naylor@2ndquadrant.com> wrote:

and since POSTFIXOP is gone
it doesn't seem to matter how low it is. In fact, I found that the
lines with INDENT and UNBOUNDED now work as the lowest precedence
declarations. Maybe that's worth something?

Following on Peter E.'s example upthread, GENERATED can be removed
from precedence, and I also found the same is true for PRESERVE and
STRIP_P.

I've attached a patch which applies on top of 0001 to demonstrate
this. There might possibly still be syntax errors for things not
covered in the regression test, but there are no s/r conflicts at
least.

I don't have any problem with the changes you made in your patch, but building on your changes I also found that the following cleanup causes no apparent problems:

-%nonassoc      UNBOUNDED               /* ideally should have same precedence as IDENT */
-%nonassoc      IDENT PARTITION RANGE ROWS GROUPS PRECEDING FOLLOWING CUBE ROLLUP
+%nonassoc      UNBOUNDED IDENT
+%nonassoc      PARTITION RANGE ROWS GROUPS PRECEDING FOLLOWING CUBE ROLLUP

Which does what the old comment apparently wanted.

This changes the context of the comment at the top of the block:

* To support target_el without AS, we must give IDENT an explicit priority
* lower than Op. We can safely assign the same priority to various
* unreserved keywords as needed to resolve ambiguities (this can't have any

This also works:

-%nonassoc      UNBOUNDED               /* ideally should have same
precedence as IDENT */
-%nonassoc      IDENT PARTITION RANGE ROWS GROUPS PRECEDING FOLLOWING
CUBE ROLLUP
+%nonassoc UNBOUNDED IDENT PARTITION RANGE ROWS GROUPS CUBE ROLLUP
+%nonassoc PRECEDING FOLLOWING

Not sure if either is better. Some additional input would be good here.

While looking for a place to put a v13 deprecation notice, I found
some more places in the docs which need updating:

ref/create_operator.sgml

"At least one of LEFTARG and RIGHTARG must be defined. For binary
operators, both must be defined. For right unary operators, only
LEFTARG should be defined, while for left unary operators only
RIGHTARG should be defined."

ref/create_opclass.sgml

"In an OPERATOR clause, the operand data type(s) of the operator, or
NONE to signify a left-unary or right-unary operator."

--
John Naylor https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

#43John Naylor
john.naylor@2ndquadrant.com
In reply to: Robert Haas (#41)
1 attachment(s)
Re: factorial function/phase out postfix operators?

On Wed, Aug 26, 2020 at 8:55 PM Robert Haas <robertmhaas@gmail.com> wrote:

On Wed, Aug 26, 2020 at 11:57 AM Mark Dilger
<mark.dilger@enterprisedb.com> wrote:

I wonder if we can get more comments for or against this patch, at least in principle, in the very near future, to help determine whether the deprecation notices should go into v13?

Speaking of that, has somebody written a specific patch for that?
Like, exactly what are we proposing that this deprecation warning is
going to say?

Well, for starters it'll say the obvious, but since we have a concrete
timeframe, maybe a <note> tag to make it more visible, like in the
attached, compressed to avoid confusing the cfbot.

--
John Naylor https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

Attachments:

postfix-depr.patch.gzapplication/x-gzip; name=postfix-depr.patch.gzDownload
#44Robert Haas
robertmhaas@gmail.com
In reply to: John Naylor (#43)
Re: factorial function/phase out postfix operators?

On Thu, Aug 27, 2020 at 7:12 AM John Naylor <john.naylor@2ndquadrant.com> wrote:

Well, for starters it'll say the obvious, but since we have a concrete
timeframe, maybe a <note> tag to make it more visible, like in the
attached, compressed to avoid confusing the cfbot.

Yeah, that looks like a good spot. I think we should also add
something to the documentation of the factorial operator, mentioning
that it will be going away. Perhaps we can advise people to write !!3
instead of 3! for forward-compatibility, or maybe we should instead
suggest numeric_fac(3).

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#45Tom Lane
tgl@sss.pgh.pa.us
In reply to: Robert Haas (#44)
Re: factorial function/phase out postfix operators?

Robert Haas <robertmhaas@gmail.com> writes:

Yeah, that looks like a good spot. I think we should also add
something to the documentation of the factorial operator, mentioning
that it will be going away. Perhaps we can advise people to write !!3
instead of 3! for forward-compatibility, or maybe we should instead
suggest numeric_fac(3).

Well, the !! operator itself has been "deprecated" for a long time:

regression=# \do+ !!
List of operators
Schema | Name | Left arg type | Right arg type | Result type | Function | Description
------------+------+---------------+----------------+-------------+-------------+---------------------------
pg_catalog | !! | | bigint | numeric | numeric_fac | deprecated, use ! instead
pg_catalog | !! | | tsquery | tsquery | tsquery_not | NOT tsquery
(2 rows)

I'm a bit inclined to kill them both off and standardize on factorial()
(not numeric_fac).

regards, tom lane

#46Mark Dilger
mark.dilger@enterprisedb.com
In reply to: Tom Lane (#45)
Re: factorial function/phase out postfix operators?

On Aug 27, 2020, at 7:04 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Robert Haas <robertmhaas@gmail.com> writes:

Yeah, that looks like a good spot. I think we should also add
something to the documentation of the factorial operator, mentioning
that it will be going away. Perhaps we can advise people to write !!3
instead of 3! for forward-compatibility, or maybe we should instead
suggest numeric_fac(3).

Well, the !! operator itself has been "deprecated" for a long time:

regression=# \do+ !!
List of operators
Schema | Name | Left arg type | Right arg type | Result type | Function | Description
------------+------+---------------+----------------+-------------+-------------+---------------------------
pg_catalog | !! | | bigint | numeric | numeric_fac | deprecated, use ! instead
pg_catalog | !! | | tsquery | tsquery | tsquery_not | NOT tsquery
(2 rows)

I'm a bit inclined to kill them both off and standardize on factorial()
(not numeric_fac).

regards, tom lane

Just for historical context, it seems that when you committed 908ab80286401bb20a519fa7dc7a837631f20369 in 2011, you were choosing one operator per underlying proc to be the canonical operator name, and deprecating all other operators based on the same proc. You chose postfix ! as the canonical operator for numeric_fac and deprecated prefix !!, but I think I can infer from that commit that if postfix ! did not exist, prefix !! would have been the canonical operator and would not have been deprecated.

The main reason I did not remove prefix !! in this patch series is that the patch is about removing postfix operator support, and so it seemed off topic. But if there is general agreement to remove prefix !!, I'll put that in the next patch.


Mark Dilger
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#47Robert Haas
robertmhaas@gmail.com
In reply to: Tom Lane (#45)
Re: factorial function/phase out postfix operators?

On Thu, Aug 27, 2020 at 10:04 AM Tom Lane <tgl@sss.pgh.pa.us> wrote:

Well, the !! operator itself has been "deprecated" for a long time:

regression=# \do+ !!
List of operators
Schema | Name | Left arg type | Right arg type | Result type | Function | Description
------------+------+---------------+----------------+-------------+-------------+---------------------------
pg_catalog | !! | | bigint | numeric | numeric_fac | deprecated, use ! instead
pg_catalog | !! | | tsquery | tsquery | tsquery_not | NOT tsquery
(2 rows)

I'm a bit inclined to kill them both off and standardize on factorial()
(not numeric_fac).

Works for me. !! hasn't been marked as deprecated in the
documentation, only the operator comment, which probably not many
people look at. But I don't see a problem updating the documentation
now to say:

- !! is going away, use factorial()
- ! is going away, use factorial()
- postfix operators are going away

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#48John Naylor
john.naylor@2ndquadrant.com
In reply to: Tom Lane (#45)
Re: factorial function/phase out postfix operators?

On Thu, Aug 27, 2020 at 5:04 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:

I'm a bit inclined to kill them both off and standardize on factorial()
(not numeric_fac).

+1

--
John Naylor https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

#49John Naylor
john.naylor@2ndquadrant.com
In reply to: Mark Dilger (#40)
Re: factorial function/phase out postfix operators?

On Wed, Aug 26, 2020 at 6:57 PM Mark Dilger
<mark.dilger@enterprisedb.com> wrote:

I don't have any problem with the changes you made in your patch, but building on your changes I also found that the following cleanup causes no apparent problems:

-%nonassoc      UNBOUNDED               /* ideally should have same precedence as IDENT */
-%nonassoc      IDENT PARTITION RANGE ROWS GROUPS PRECEDING FOLLOWING CUBE ROLLUP
+%nonassoc      UNBOUNDED IDENT
+%nonassoc      PARTITION RANGE ROWS GROUPS PRECEDING FOLLOWING CUBE ROLLUP

Thinking about this some more, I don't think we don't need to do any
precedence refactoring in order to apply the functional change of
these patches. We could leave that for follow-on patches once we
figure out the best way forward, which could take some time.

--
John Naylor https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

#50Robert Haas
robertmhaas@gmail.com
In reply to: John Naylor (#48)
1 attachment(s)
Re: factorial function/phase out postfix operators?

On Fri, Aug 28, 2020 at 4:44 AM John Naylor <john.naylor@2ndquadrant.com> wrote:

On Thu, Aug 27, 2020 at 5:04 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:

I'm a bit inclined to kill them both off and standardize on factorial()
(not numeric_fac).

+1

Here's a modified version of John's patch that also describes ! and !!
as deprecated. It looked too wordy to me to recommend what should be
used instead, so I have not done that.

Comments?

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

Attachments:

postfix-and-factorial-deprecate.patchapplication/octet-stream; name=postfix-and-factorial-deprecate.patchDownload
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index bbbffd9d5b..6b183c5ad9 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -1054,7 +1054,8 @@ repeat('Pg', 4) <returnvalue>PgPgPgPg</returnvalue>
         <returnvalue>numeric</returnvalue>
        </para>
        <para>
-        Factorial
+        Factorial (deprecated, will be removed in
+        <productname>PostgreSQL</productname> 14)
        </para>
        <para>
         <literal>5 !</literal>
@@ -1068,7 +1069,8 @@ repeat('Pg', 4) <returnvalue>PgPgPgPg</returnvalue>
         <returnvalue>numeric</returnvalue>
        </para>
        <para>
-        Factorial (as a prefix operator)
+        Factorial (as a prefix operator; deprecated, will be removed in
+        <productname>PostgreSQL</productname> 14)
        </para>
        <para>
         <literal>!! 5</literal>
diff --git a/doc/src/sgml/ref/create_operator.sgml b/doc/src/sgml/ref/create_operator.sgml
index d5c385c087..2d265f34ef 100644
--- a/doc/src/sgml/ref/create_operator.sgml
+++ b/doc/src/sgml/ref/create_operator.sgml
@@ -92,6 +92,13 @@ CREATE OPERATOR <replaceable>name</replaceable> (
    unary operators only <literal>RIGHTARG</literal> should be defined.
   </para>
 
+  <note>
+   <para>
+    Right unary, also called postfix, operators are deprecated and will be
+    removed in <productname>PostgreSQL</productname> version 14.
+   </para>
+  </note>
+
   <para>
    The <replaceable class="parameter">function_name</replaceable>
    function must have been previously defined using <command>CREATE
#51Robert Haas
robertmhaas@gmail.com
In reply to: Robert Haas (#50)
Re: factorial function/phase out postfix operators?

On Fri, Aug 28, 2020 at 11:00 AM Robert Haas <robertmhaas@gmail.com> wrote:

On Fri, Aug 28, 2020 at 4:44 AM John Naylor <john.naylor@2ndquadrant.com> wrote:

On Thu, Aug 27, 2020 at 5:04 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:

I'm a bit inclined to kill them both off and standardize on factorial()
(not numeric_fac).

+1

Here's a modified version of John's patch that also describes ! and !!
as deprecated. It looked too wordy to me to recommend what should be
used instead, so I have not done that.

Comments?

Never mind, I see there's a new thread for this. Sorry for the noise.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#52Mark Dilger
mark.dilger@enterprisedb.com
In reply to: John Naylor (#42)
3 attachment(s)
Re: factorial function/phase out postfix operators?

On Aug 27, 2020, at 2:24 AM, John Naylor <john.naylor@2ndquadrant.com> wrote:

On Wed, Aug 26, 2020 at 6:57 PM Mark Dilger
<mark.dilger@enterprisedb.com> wrote:

On Aug 26, 2020, at 6:33 AM, John Naylor <john.naylor@2ndquadrant.com> wrote:

and since POSTFIXOP is gone
it doesn't seem to matter how low it is. In fact, I found that the
lines with INDENT and UNBOUNDED now work as the lowest precedence
declarations. Maybe that's worth something?

Following on Peter E.'s example upthread, GENERATED can be removed
from precedence, and I also found the same is true for PRESERVE and
STRIP_P.

I've attached a patch which applies on top of 0001 to demonstrate
this. There might possibly still be syntax errors for things not
covered in the regression test, but there are no s/r conflicts at
least.

I don't have any problem with the changes you made in your patch, but building on your changes I also found that the following cleanup causes no apparent problems:

-%nonassoc      UNBOUNDED               /* ideally should have same precedence as IDENT */
-%nonassoc      IDENT PARTITION RANGE ROWS GROUPS PRECEDING FOLLOWING CUBE ROLLUP
+%nonassoc      UNBOUNDED IDENT
+%nonassoc      PARTITION RANGE ROWS GROUPS PRECEDING FOLLOWING CUBE ROLLUP

Which does what the old comment apparently wanted.

This changes the context of the comment at the top of the block:

* To support target_el without AS, we must give IDENT an explicit priority
* lower than Op. We can safely assign the same priority to various
* unreserved keywords as needed to resolve ambiguities (this can't have any

This also works:

-%nonassoc      UNBOUNDED               /* ideally should have same
precedence as IDENT */
-%nonassoc      IDENT PARTITION RANGE ROWS GROUPS PRECEDING FOLLOWING
CUBE ROLLUP
+%nonassoc UNBOUNDED IDENT PARTITION RANGE ROWS GROUPS CUBE ROLLUP
+%nonassoc PRECEDING FOLLOWING

Not sure if either is better. Some additional input would be good here.

You wrote in a later email:

Thinking about this some more, I don't think we don't need to do any
precedence refactoring in order to apply the functional change of
these patches. We could leave that for follow-on patches once we
figure out the best way forward, which could take some time.

So I tried to leave the precedence stuff alone as much as possible in this next patch set. I agree such refactoring can be done separately, and at a later time.

While looking for a place to put a v13 deprecation notice, I found
some more places in the docs which need updating:

ref/create_operator.sgml

"At least one of LEFTARG and RIGHTARG must be defined. For binary
operators, both must be defined. For right unary operators, only
LEFTARG should be defined, while for left unary operators only
RIGHTARG should be defined."

ref/create_opclass.sgml

"In an OPERATOR clause, the operand data type(s) of the operator, or
NONE to signify a left-unary or right-unary operator."

Some changes were made on another thread [1] for the deprecation notices, committed recently by Tom, and I think this patch set is compatible with what was done there. This patch set is intended for commit against master, targeted for PostgreSQL 14, so the deprecation notices are removed along with the things that were deprecated. The references to right-unary operators that you call out, above, have been removed.

Attachments:

v6-0001-Removing-postfix-operator-support.patchapplication/octet-stream; name=v6-0001-Removing-postfix-operator-support.patch; x-unix-mode=0644Download
From bb623e8aa23a430cc5021118a6026e70341c9acf Mon Sep 17 00:00:00 2001
From: Mark Dilger <mark.dilger@enterprisedb.com>
Date: Mon, 31 Aug 2020 13:03:41 -0700
Subject: [PATCH v6 1/3] Removing postfix operator support.

Removing postfix operator support from the grammar; disallowing
the creation of postfix operators through the CREATE OPERATOR
command; and removing the factorial prefix and postfix operators.

In the commit message for 6ca547cf75ef6e922476c51a3fb5e253eef5f1b6,
Tom Lane wrote:

    There is only one built-in postfix operator, ! for factorial.
    Label it deprecated in the docs and in pg_description, and
    adjust some examples that formerly relied on it.  (The sister
    prefix operator !! is also deprecated.  We don't really have to
    remove that one, but since we're suggesting that people use
    factorial() instead, it seems better to remove both operators.)

In the spirit of that message, this patch also removes the !!
factorial prefix operator, even though it is not strongly connected
with the rest of what this commit does.

This accomplishes nothing useful in itself, but sets up for grammar
changes to allow keywords to be used as bare column aliases without
the use of an explicit "AS".
---
 contrib/postgres_fdw/deparse.c                |   5 +-
 .../postgres_fdw/expected/postgres_fdw.out    |   8 --
 contrib/postgres_fdw/sql/postgres_fdw.sql     |   1 -
 doc/src/sgml/catalogs.sgml                    |   2 +-
 doc/src/sgml/ref/alter_extension.sgml         |   2 +-
 doc/src/sgml/ref/alter_opfamily.sgml          |   2 +-
 doc/src/sgml/ref/comment.sgml                 |   2 +-
 doc/src/sgml/ref/create_opclass.sgml          |   2 +-
 doc/src/sgml/ref/create_operator.sgml         |  20 +--
 doc/src/sgml/ref/drop_operator.sgml           |   7 -
 doc/src/sgml/syntax.sgml                      |   3 +-
 doc/src/sgml/typeconv.sgml                    |   2 +-
 doc/src/sgml/xoper.sgml                       |  12 +-
 src/backend/catalog/namespace.c               |   7 +-
 src/backend/catalog/pg_operator.c             |   4 +-
 src/backend/commands/operatorcmds.c           |  14 +-
 src/backend/nodes/print.c                     |   1 -
 src/backend/parser/gram.y                     |  30 ++---
 src/backend/parser/parse_expr.c               |  48 ++-----
 src/backend/parser/parse_oper.c               | 121 +++---------------
 src/backend/utils/adt/ruleutils.c             |  31 ++---
 src/bin/pg_dump/pg_dump.c                     |   6 +-
 src/bin/pg_dump/pg_dump_sort.c                |   2 +-
 src/bin/pg_upgrade/check.c                    | 106 +++++++++++++++
 src/bin/psql/describe.c                       |   2 +-
 src/include/catalog/pg_operator.dat           |   6 -
 src/include/catalog/pg_operator.h             |   4 +-
 src/include/catalog/pg_proc.dat               |   4 -
 src/test/regress/expected/create_operator.out |  33 +++--
 src/test/regress/expected/numeric.out         |  39 +++---
 src/test/regress/expected/opr_sanity.out      |  17 +--
 src/test/regress/sql/create_operator.sql      |  15 ++-
 src/test/regress/sql/numeric.sql              |  15 ++-
 src/test/regress/sql/opr_sanity.sql           |  14 +-
 src/tutorial/complex.source                   |   2 +-
 src/tutorial/syscat.source                    |  14 --
 36 files changed, 264 insertions(+), 339 deletions(-)

diff --git a/contrib/postgres_fdw/deparse.c b/contrib/postgres_fdw/deparse.c
index ad37a74221..32a9b38f10 100644
--- a/contrib/postgres_fdw/deparse.c
+++ b/contrib/postgres_fdw/deparse.c
@@ -2716,15 +2716,14 @@ deparseOpExpr(OpExpr *node, deparse_expr_cxt *context)
 	oprkind = form->oprkind;
 
 	/* Sanity check. */
-	Assert((oprkind == 'r' && list_length(node->args) == 1) ||
-		   (oprkind == 'l' && list_length(node->args) == 1) ||
+	Assert((oprkind == 'l' && list_length(node->args) == 1) ||
 		   (oprkind == 'b' && list_length(node->args) == 2));
 
 	/* Always parenthesize the expression. */
 	appendStringInfoChar(buf, '(');
 
 	/* Deparse left operand. */
-	if (oprkind == 'r' || oprkind == 'b')
+	if (oprkind == 'b')
 	{
 		arg = list_head(node->args);
 		deparseExpr(lfirst(arg), context);
diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index 90db550b92..cae90b45e2 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -653,14 +653,6 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 = -c1;          -- Op
    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = (- "C 1")))
 (3 rows)
 
-EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE 1 = c1!;           -- OpExpr(r)
-                                                QUERY PLAN                                                
-----------------------------------------------------------------------------------------------------------
- Foreign Scan on public.ft1 t1
-   Output: c1, c2, c3, c4, c5, c6, c7, c8
-   Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE ((1::numeric = ("C 1" !)))
-(3 rows)
-
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE (c1 IS NOT NULL) IS DISTINCT FROM (c1 IS NOT NULL); -- DistinctExpr
                                                                  QUERY PLAN                                                                 
 --------------------------------------------------------------------------------------------------------------------------------------------
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index 83971665e3..bbad5b6ec2 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -307,7 +307,6 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 IS NULL;        -- Nu
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 IS NOT NULL;    -- NullTest
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE round(abs(c1), 0) = 1; -- FuncExpr
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 = -c1;          -- OpExpr(l)
-EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE 1 = c1!;           -- OpExpr(r)
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE (c1 IS NOT NULL) IS DISTINCT FROM (c1 IS NOT NULL); -- DistinctExpr
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 = ANY(ARRAY[c2, 1, c1 + 0]); -- ScalarArrayOpExpr
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 = (ARRAY[c1,c2,3])[1]; -- SubscriptingRef
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 1d1b8ce8fb..39eee9d1e2 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -5154,7 +5154,7 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
       </para>
       <para>
        <literal>b</literal> = infix (<quote>both</quote>), <literal>l</literal> = prefix
-       (<quote>left</quote>), <literal>r</literal> = postfix (<quote>right</quote>)
+       (<quote>left</quote>)
       </para></entry>
      </row>
 
diff --git a/doc/src/sgml/ref/alter_extension.sgml b/doc/src/sgml/ref/alter_extension.sgml
index a2d405d6cd..c819c7bb4e 100644
--- a/doc/src/sgml/ref/alter_extension.sgml
+++ b/doc/src/sgml/ref/alter_extension.sgml
@@ -251,7 +251,7 @@ ALTER EXTENSION <replaceable class="parameter">name</replaceable> DROP <replacea
       <para>
        The data type(s) of the operator's arguments (optionally
        schema-qualified).  Write <literal>NONE</literal> for the missing argument
-       of a prefix or postfix operator.
+       of a prefix operator.
       </para>
      </listitem>
     </varlistentry>
diff --git a/doc/src/sgml/ref/alter_opfamily.sgml b/doc/src/sgml/ref/alter_opfamily.sgml
index 4ac1cca95a..c86507edac 100644
--- a/doc/src/sgml/ref/alter_opfamily.sgml
+++ b/doc/src/sgml/ref/alter_opfamily.sgml
@@ -141,7 +141,7 @@ ALTER OPERATOR FAMILY <replaceable>name</replaceable> USING <replaceable class="
      <para>
       In an <literal>OPERATOR</literal> clause,
       the operand data type(s) of the operator, or <literal>NONE</literal> to
-      signify a left-unary or right-unary operator.  Unlike the comparable
+      signify a left-unary operator.  Unlike the comparable
       syntax in <command>CREATE OPERATOR CLASS</command>, the operand data types
       must always be specified.
      </para>
diff --git a/doc/src/sgml/ref/comment.sgml b/doc/src/sgml/ref/comment.sgml
index fd7492a255..6e8ced3eaf 100644
--- a/doc/src/sgml/ref/comment.sgml
+++ b/doc/src/sgml/ref/comment.sgml
@@ -224,7 +224,7 @@ COMMENT ON
      <para>
       The data type(s) of the operator's arguments (optionally
       schema-qualified).  Write <literal>NONE</literal> for the missing argument
-      of a prefix or postfix operator.
+      of a prefix operator.
      </para>
     </listitem>
    </varlistentry>
diff --git a/doc/src/sgml/ref/create_opclass.sgml b/doc/src/sgml/ref/create_opclass.sgml
index f42fb6494c..0f94b6ae3e 100644
--- a/doc/src/sgml/ref/create_opclass.sgml
+++ b/doc/src/sgml/ref/create_opclass.sgml
@@ -161,7 +161,7 @@ CREATE OPERATOR CLASS <replaceable class="parameter">name</replaceable> [ DEFAUL
      <para>
       In an <literal>OPERATOR</literal> clause,
       the operand data type(s) of the operator, or <literal>NONE</literal> to
-      signify a left-unary or right-unary operator.  The operand data
+      signify a left-unary operator.  The operand data
       types can be omitted in the normal case where they are the same
       as the operator class's data type.
      </para>
diff --git a/doc/src/sgml/ref/create_operator.sgml b/doc/src/sgml/ref/create_operator.sgml
index 66c34e0072..082494bd75 100644
--- a/doc/src/sgml/ref/create_operator.sgml
+++ b/doc/src/sgml/ref/create_operator.sgml
@@ -86,20 +86,9 @@ CREATE OPERATOR <replaceable>name</replaceable> (
   </para>
 
   <para>
-   At least one of <literal>LEFTARG</literal> and <literal>RIGHTARG</literal> must be defined.  For
-   binary operators, both must be defined. For right unary
-   operators, only <literal>LEFTARG</literal> should be defined, while for left
-   unary operators only <literal>RIGHTARG</literal> should be defined.
-  </para>
-
-  <note>
-   <para>
-    Right unary, also called postfix, operators are deprecated and will be
-    removed in <productname>PostgreSQL</productname> version 14.
-   </para>
-  </note>
-
-  <para>
+   For binary operators, both <literal>LEFTARG</literal> and
+   <literal>RIGHTARG</literal> must be defined.  For left unary operators only
+   <literal>RIGHTARG</literal> should be defined.
    The <replaceable class="parameter">function_name</replaceable>
    function must have been previously defined using <command>CREATE
    FUNCTION</command> and must be defined to accept the correct number
@@ -169,8 +158,7 @@ CREATE OPERATOR <replaceable>name</replaceable> (
       <term><replaceable class="parameter">right_type</replaceable></term>
       <listitem>
        <para>
-        The data type of the operator's right operand, if any.
-        This option would be omitted for a right-unary operator.
+        The data type of the operator's right operand.
        </para>
       </listitem>
      </varlistentry>
diff --git a/doc/src/sgml/ref/drop_operator.sgml b/doc/src/sgml/ref/drop_operator.sgml
index 2dff050ecf..3c8eecb53a 100644
--- a/doc/src/sgml/ref/drop_operator.sgml
+++ b/doc/src/sgml/ref/drop_operator.sgml
@@ -120,13 +120,6 @@ DROP OPERATOR ~ (none, bit);
 </programlisting>
   </para>
 
-  <para>
-   Remove the right unary factorial operator <literal>x!</literal>
-   for type <type>bigint</type>:
-<programlisting>
-DROP OPERATOR ! (bigint, none);
-</programlisting></para>
-
   <para>
    Remove multiple operators in one command:
 <programlisting>
diff --git a/doc/src/sgml/syntax.sgml b/doc/src/sgml/syntax.sgml
index b0ae5d2e12..abde93895a 100644
--- a/doc/src/sgml/syntax.sgml
+++ b/doc/src/sgml/syntax.sgml
@@ -1444,11 +1444,10 @@ $1.somecolumn
    </indexterm>
 
    <para>
-    There are three possible syntaxes for an operator invocation:
+    There are two possible syntaxes for an operator invocation:
     <simplelist>
      <member><replaceable>expression</replaceable> <replaceable>operator</replaceable> <replaceable>expression</replaceable> (binary infix operator)</member>
      <member><replaceable>operator</replaceable> <replaceable>expression</replaceable> (unary prefix operator)</member>
-     <member><replaceable>expression</replaceable> <replaceable>operator</replaceable> (unary postfix operator)</member>
     </simplelist>
     where the <replaceable>operator</replaceable> token follows the syntax
     rules of <xref linkend="sql-syntax-operators"/>, or is one of the
diff --git a/doc/src/sgml/typeconv.sgml b/doc/src/sgml/typeconv.sgml
index 98662fc91f..ef9e311342 100644
--- a/doc/src/sgml/typeconv.sgml
+++ b/doc/src/sgml/typeconv.sgml
@@ -97,7 +97,7 @@ Operators
 <listitem>
 <para>
 <productname>PostgreSQL</productname> allows expressions with
-prefix and postfix unary (one-argument) operators,
+prefix unary (one-argument) operators,
 as well as binary (two-argument) operators.  Like functions, operators can
 be overloaded, so the same problem of selecting the right operator
 exists.
diff --git a/doc/src/sgml/xoper.sgml b/doc/src/sgml/xoper.sgml
index 56b08491c9..585a8c958f 100644
--- a/doc/src/sgml/xoper.sgml
+++ b/doc/src/sgml/xoper.sgml
@@ -20,8 +20,8 @@
   </para>
 
   <para>
-   <productname>PostgreSQL</productname> supports left unary, right
-   unary, and binary operators.  Operators can be
+   <productname>PostgreSQL</productname> supports left unary
+   and binary operators.  Operators can be
    overloaded;<indexterm><primary>overloading</primary><secondary>operators</secondary></indexterm>
    that is, the same operator name can be used for different operators
    that have different numbers and types of operands.  When a query is
@@ -64,9 +64,9 @@ SELECT (a + b) AS c FROM test_complex;
   </para>
 
   <para>
-   We've shown how to create a binary operator here.  To create unary
-   operators, just omit one of <literal>leftarg</literal> (for left unary) or
-   <literal>rightarg</literal> (for right unary).  The <literal>function</literal>
+   We've shown how to create a binary operator here.  To create left unary
+   operators, just omit the <literal>leftarg</literal>.
+   The <literal>function</literal>
    clause and the argument clauses are the only required items in
    <command>CREATE OPERATOR</command>.  The <literal>commutator</literal>
    clause shown in the example is an optional hint to the query
@@ -202,7 +202,7 @@ SELECT (a + b) AS c FROM test_complex;
    <para>
     Unlike commutators, a pair of unary operators could validly be marked
     as each other's negators; that would mean (A x) equals NOT (B x)
-    for all x, or the equivalent for right unary operators.
+    for all x.
    </para>
 
    <para>
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index 0152e3869a..0c78ab8af7 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -1473,8 +1473,7 @@ FunctionIsVisible(Oid funcid)
  *		Given a possibly-qualified operator name and exact input datatypes,
  *		look up the operator.  Returns InvalidOid if not found.
  *
- * Pass oprleft = InvalidOid for a prefix op, oprright = InvalidOid for
- * a postfix op.
+ * Pass oprleft = InvalidOid for a prefix op.
  *
  * If the operator name is not schema-qualified, it is sought in the current
  * namespace search path.  If the name is schema-qualified and the given
@@ -1580,8 +1579,8 @@ OpernameGetOprid(List *names, Oid oprleft, Oid oprright)
  * namespace case, we arrange for entries in earlier namespaces to mask
  * identical entries in later namespaces.
  *
- * The returned items always have two args[] entries --- one or the other
- * will be InvalidOid for a prefix or postfix oprkind.  nargs is 2, too.
+ * The returned items always have two args[] entries --- one will be
+ * InvalidOid for a prefix oprkind.  nargs is 2, too.
  */
 FuncCandidateList
 OpernameGetCandidates(List *names, char oprkind, bool missing_schema_ok)
diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c
index 65a36be5ee..f817627d86 100644
--- a/src/backend/catalog/pg_operator.c
+++ b/src/backend/catalog/pg_operator.c
@@ -245,7 +245,7 @@ OperatorShellMake(const char *operatorName,
 	values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
 	values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
 	values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId());
-	values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');
+	values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? 'b' : 'l');
 	values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(false);
 	values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(false);
 	values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);
@@ -494,7 +494,7 @@ OperatorCreate(const char *operatorName,
 	values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
 	values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
 	values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId());
-	values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');
+	values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? 'b' : 'l');
 	values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(canMerge);
 	values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(canHash);
 	values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);
diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c
index bf23937849..b468c7701b 100644
--- a/src/backend/commands/operatorcmds.c
+++ b/src/backend/commands/operatorcmds.c
@@ -168,10 +168,22 @@ DefineOperator(List *names, List *parameters)
 	if (typeName2)
 		typeId2 = typenameTypeId(NULL, typeName2);
 
+	/*
+	 * If only the right argument is missing, the user is likely trying to
+	 * create a postfix operator, so give them a hint about why that does not
+	 * work.  But if both arguments are missing, do not mention postfix
+	 * operators, as the user most likely simply neglected to mention the
+	 * arguments.
+	 */
 	if (!OidIsValid(typeId1) && !OidIsValid(typeId2))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
-				 errmsg("at least one of leftarg or rightarg must be specified")));
+				 errmsg("operator arguments must be specified")));
+	if (!OidIsValid(typeId2))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+				 errmsg("operator right argument must be specified"),
+				 errhint("Postfix operators are not supported.")));
 
 	if (typeName1)
 	{
diff --git a/src/backend/nodes/print.c b/src/backend/nodes/print.c
index 42476724d8..970a2d4384 100644
--- a/src/backend/nodes/print.c
+++ b/src/backend/nodes/print.c
@@ -394,7 +394,6 @@ print_expr(const Node *expr, const List *rtable)
 		}
 		else
 		{
-			/* we print prefix and postfix ops the same... */
 			printf("%s ", ((opname != NULL) ? opname : "(invalid operator)"));
 			print_expr(get_leftop((const Expr *) e), rtable);
 		}
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index dbb47d4982..d8a607e29a 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -741,19 +741,14 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 %nonassoc	'<' '>' '=' LESS_EQUALS GREATER_EQUALS NOT_EQUALS
 %nonassoc	BETWEEN IN_P LIKE ILIKE SIMILAR NOT_LA
 %nonassoc	ESCAPE			/* ESCAPE must be just above LIKE/ILIKE/SIMILAR */
-%left		POSTFIXOP		/* dummy for postfix Op rules */
 /*
  * To support target_el without AS, we must give IDENT an explicit priority
- * between POSTFIXOP and Op.  We can safely assign the same priority to
- * various unreserved keywords as needed to resolve ambiguities (this can't
- * have any bad effects since obviously the keywords will still behave the
- * same as if they weren't keywords).  We need to do this:
+ * lower than Op.  We can safely assign the same priority to various
+ * unreserved keywords as needed to resolve ambiguities (this can't have any
+ * bad effects since obviously the keywords will still behave the same as if
+ * they weren't keywords).  We need to do this:
  * for PARTITION, RANGE, ROWS, GROUPS to support opt_existing_window_name;
- * for RANGE, ROWS, GROUPS so that they can follow a_expr without creating
- * postfix-operator problems;
  * for GENERATED so that it can follow b_expr;
- * and for NULL so that it can follow b_expr in ColQualList without creating
- * postfix-operator problems.
  *
  * To support CUBE and ROLLUP in GROUP BY without reserving them, we give them
  * an explicit priority lower than '(', so that a rule with CUBE '(' will shift
@@ -7993,7 +7988,12 @@ oper_argtypes:
 			| '(' NONE ',' Typename ')'					/* left unary */
 					{ $$ = list_make2(NULL, $4); }
 			| '(' Typename ',' NONE ')'					/* right unary */
-					{ $$ = list_make2($2, NULL); }
+				{
+					ereport(ERROR,
+							(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+							 errmsg("operator right argument must be specified"),
+							 errhint("Postfix operators are not supported.")));
+				}
 		;
 
 any_operator:
@@ -12989,8 +12989,6 @@ a_expr:		c_expr									{ $$ = $1; }
 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3, @2); }
 			| qual_Op a_expr					%prec Op
 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $1, NULL, $2, @1); }
-			| a_expr qual_Op					%prec POSTFIXOP
-				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, NULL, @2); }
 
 			| a_expr AND a_expr
 				{ $$ = makeAndExpr($1, $3, @2); }
@@ -13404,8 +13402,6 @@ b_expr:		c_expr
 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3, @2); }
 			| qual_Op b_expr					%prec Op
 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $1, NULL, $2, @1); }
-			| b_expr qual_Op					%prec POSTFIXOP
-				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, NULL, @2); }
 			| b_expr IS DISTINCT FROM b_expr		%prec IS
 				{
 					$$ = (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $5, @2);
@@ -14661,11 +14657,7 @@ target_el:	a_expr AS ColLabel
 				}
 			/*
 			 * 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.
+			 * any known keyword.
 			 */
 			| a_expr IDENT
 				{
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index f69976cc8c..9e266cf3b0 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -57,7 +57,7 @@ bool		Transform_null_equals = false;
 #define PREC_GROUP_NOT_LIKE		9	/* NOT LIKE/ILIKE/SIMILAR */
 #define PREC_GROUP_NOT_BETWEEN	10	/* NOT BETWEEN */
 #define PREC_GROUP_NOT_IN		11	/* NOT IN */
-#define PREC_GROUP_POSTFIX_OP	12	/* generic postfix operators */
+#define PREC_GROUP_ANY_ALL		12	/* ANY/ALL */
 #define PREC_GROUP_INFIX_OP		13	/* generic infix operators */
 #define PREC_GROUP_PREFIX_OP	14	/* generic prefix operators */
 
@@ -71,7 +71,7 @@ bool		Transform_null_equals = false;
  * 4. LIKE ILIKE SIMILAR
  * 5. BETWEEN
  * 6. IN
- * 7. generic postfix Op
+ * 7. ANY ALL
  * 8. generic Op, including <= => <>
  * 9. generic prefix Op
  * 10. IS tests (NullTest, BooleanTest, etc)
@@ -1031,7 +1031,7 @@ transformAExprOpAny(ParseState *pstate, A_Expr *a)
 	Node	   *rexpr = a->rexpr;
 
 	if (operator_precedence_warning)
-		emit_precedence_warnings(pstate, PREC_GROUP_POSTFIX_OP,
+		emit_precedence_warnings(pstate, PREC_GROUP_ANY_ALL,
 								 strVal(llast(a->name)),
 								 lexpr, NULL,
 								 a->location);
@@ -1054,7 +1054,7 @@ transformAExprOpAll(ParseState *pstate, A_Expr *a)
 	Node	   *rexpr = a->rexpr;
 
 	if (operator_precedence_warning)
-		emit_precedence_warnings(pstate, PREC_GROUP_POSTFIX_OP,
+		emit_precedence_warnings(pstate, PREC_GROUP_ANY_ALL,
 								 strVal(llast(a->name)),
 								 lexpr, NULL,
 								 a->location);
@@ -2014,15 +2014,9 @@ transformSubLink(ParseState *pstate, SubLink *sublink)
 
 		if (operator_precedence_warning)
 		{
-			if (sublink->operName == NIL)
-				emit_precedence_warnings(pstate, PREC_GROUP_IN, "IN",
-										 sublink->testexpr, NULL,
-										 sublink->location);
-			else
-				emit_precedence_warnings(pstate, PREC_GROUP_POSTFIX_OP,
-										 strVal(llast(sublink->operName)),
-										 sublink->testexpr, NULL,
-										 sublink->location);
+			emit_precedence_warnings(pstate, PREC_GROUP_IN, "IN",
+									 sublink->testexpr, NULL,
+									 sublink->location);
 		}
 
 		/*
@@ -3244,28 +3238,11 @@ operator_precedence_group(Node *node, const char **nodename)
 				group = PREC_GROUP_PREFIX_OP;
 			}
 		}
-		else if (aexpr->kind == AEXPR_OP &&
-				 aexpr->lexpr != NULL &&
-				 aexpr->rexpr == NULL)
-		{
-			/* postfix operator */
-			if (list_length(aexpr->name) == 1)
-			{
-				*nodename = strVal(linitial(aexpr->name));
-				group = PREC_GROUP_POSTFIX_OP;
-			}
-			else
-			{
-				/* schema-qualified operator syntax */
-				*nodename = "OPERATOR()";
-				group = PREC_GROUP_POSTFIX_OP;
-			}
-		}
 		else if (aexpr->kind == AEXPR_OP_ANY ||
 				 aexpr->kind == AEXPR_OP_ALL)
 		{
 			*nodename = strVal(llast(aexpr->name));
-			group = PREC_GROUP_POSTFIX_OP;
+			group = PREC_GROUP_ANY_ALL;
 		}
 		else if (aexpr->kind == AEXPR_DISTINCT ||
 				 aexpr->kind == AEXPR_NOT_DISTINCT)
@@ -3356,7 +3333,7 @@ operator_precedence_group(Node *node, const char **nodename)
 			else
 			{
 				*nodename = strVal(llast(s->operName));
-				group = PREC_GROUP_POSTFIX_OP;
+				group = PREC_GROUP_ANY_ALL;
 			}
 		}
 	}
@@ -3432,9 +3409,8 @@ emit_precedence_warnings(ParseState *pstate,
 	 * Complain if left child, which should be same or higher precedence
 	 * according to current rules, used to be lower precedence.
 	 *
-	 * Exception to precedence rules: if left child is IN or NOT IN or a
-	 * postfix operator, the grouping is syntactically forced regardless of
-	 * precedence.
+	 * Exception to precedence rules: if left child is IN or NOT IN the
+	 * grouping is syntactically forced regardless of precedence.
 	 */
 	cgroup = operator_precedence_group(lchild, &copname);
 	if (cgroup > 0)
@@ -3442,7 +3418,7 @@ emit_precedence_warnings(ParseState *pstate,
 		if (oldprecedence_l[cgroup] < oldprecedence_r[opgroup] &&
 			cgroup != PREC_GROUP_IN &&
 			cgroup != PREC_GROUP_NOT_IN &&
-			cgroup != PREC_GROUP_POSTFIX_OP &&
+			cgroup != PREC_GROUP_ANY_ALL &&
 			cgroup != PREC_GROUP_POSTFIX_IS)
 			ereport(WARNING,
 					(errmsg("operator precedence change: %s is now lower precedence than %s",
diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c
index 2749974f63..877ffa03a6 100644
--- a/src/backend/parser/parse_oper.c
+++ b/src/backend/parser/parse_oper.c
@@ -52,7 +52,7 @@ typedef struct OprCacheKey
 {
 	char		oprname[NAMEDATALEN];
 	Oid			left_arg;		/* Left input OID, or 0 if prefix op */
-	Oid			right_arg;		/* Right input OID, or 0 if postfix op */
+	Oid			right_arg;		/* Right input OID */
 	Oid			search_path[MAX_CACHED_PATH_LEN];
 } OprCacheKey;
 
@@ -88,8 +88,7 @@ static void InvalidateOprCacheCallBack(Datum arg, int cacheid, uint32 hashvalue)
  *		Given a possibly-qualified operator name and exact input datatypes,
  *		look up the operator.
  *
- * Pass oprleft = InvalidOid for a prefix op, oprright = InvalidOid for
- * a postfix op.
+ * Pass oprleft = InvalidOid for a prefix op.
  *
  * If the operator name is not schema-qualified, it is sought in the current
  * namespace search path.
@@ -115,10 +114,13 @@ LookupOperName(ParseState *pstate, List *opername, Oid oprleft, Oid oprright,
 
 		if (!OidIsValid(oprleft))
 			oprkind = 'l';
-		else if (!OidIsValid(oprright))
-			oprkind = 'r';
-		else
+		else if (OidIsValid(oprright))
 			oprkind = 'b';
+		else
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					 errmsg("postfix operators are not supported"),
+					 parser_errposition(pstate, location)));
 
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_FUNCTION),
@@ -507,85 +509,6 @@ compatible_oper_opid(List *op, Oid arg1, Oid arg2, bool noError)
 }
 
 
-/* right_oper() -- search for a unary right operator (postfix operator)
- * Given operator name and type of arg, return oper struct.
- *
- * IMPORTANT: the returned operator (if any) is only promised to be
- * coercion-compatible with the input datatype.  Do not use this if
- * you need an exact- or binary-compatible match.
- *
- * If no matching operator found, return NULL if noError is true,
- * raise an error if it is false.  pstate and location are used only to report
- * the error position; pass NULL/-1 if not available.
- *
- * NOTE: on success, the returned object is a syscache entry.  The caller
- * must ReleaseSysCache() the entry when done with it.
- */
-Operator
-right_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
-{
-	Oid			operOid;
-	OprCacheKey key;
-	bool		key_ok;
-	FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND;
-	HeapTuple	tup = NULL;
-
-	/*
-	 * Try to find the mapping in the lookaside cache.
-	 */
-	key_ok = make_oper_cache_key(pstate, &key, op, arg, InvalidOid, location);
-
-	if (key_ok)
-	{
-		operOid = find_oper_cache_entry(&key);
-		if (OidIsValid(operOid))
-		{
-			tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
-			if (HeapTupleIsValid(tup))
-				return (Operator) tup;
-		}
-	}
-
-	/*
-	 * First try for an "exact" match.
-	 */
-	operOid = OpernameGetOprid(op, arg, InvalidOid);
-	if (!OidIsValid(operOid))
-	{
-		/*
-		 * Otherwise, search for the most suitable candidate.
-		 */
-		FuncCandidateList clist;
-
-		/* Get postfix operators of given name */
-		clist = OpernameGetCandidates(op, 'r', false);
-
-		/* No operators found? Then fail... */
-		if (clist != NULL)
-		{
-			/*
-			 * We must run oper_select_candidate even if only one candidate,
-			 * otherwise we may falsely return a non-type-compatible operator.
-			 */
-			fdresult = oper_select_candidate(1, &arg, clist, &operOid);
-		}
-	}
-
-	if (OidIsValid(operOid))
-		tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
-
-	if (HeapTupleIsValid(tup))
-	{
-		if (key_ok)
-			make_oper_cache_entry(&key, operOid);
-	}
-	else if (!noError)
-		op_error(pstate, op, 'r', arg, InvalidOid, fdresult, location);
-
-	return (Operator) tup;
-}
-
-
 /* left_oper() -- search for a unary left operator (prefix operator)
  * Given operator name and type of arg, return oper struct.
  *
@@ -696,8 +619,7 @@ op_signature_string(List *op, char oprkind, Oid arg1, Oid arg2)
 
 	appendStringInfoString(&argbuf, NameListToString(op));
 
-	if (oprkind != 'r')
-		appendStringInfo(&argbuf, " %s", format_type_be(arg2));
+	appendStringInfo(&argbuf, " %s", format_type_be(arg2));
 
 	return argbuf.data;			/* return palloc'd string buffer */
 }
@@ -758,15 +680,14 @@ make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree,
 	Oid			rettype;
 	OpExpr	   *result;
 
-	/* Select the operator */
+	/* Check it's not a postfix operator */
 	if (rtree == NULL)
-	{
-		/* right operator */
-		ltypeId = exprType(ltree);
-		rtypeId = InvalidOid;
-		tup = right_oper(pstate, opname, ltypeId, false, location);
-	}
-	else if (ltree == NULL)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+				 errmsg("postfix operators are not supported")));
+
+	/* Select the operator */
+	if (ltree == NULL)
 	{
 		/* left operator */
 		rtypeId = exprType(rtree);
@@ -795,15 +716,7 @@ make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree,
 				 parser_errposition(pstate, location)));
 
 	/* Do typecasting and build the expression tree */
-	if (rtree == NULL)
-	{
-		/* right operator */
-		args = list_make1(ltree);
-		actual_arg_types[0] = ltypeId;
-		declared_arg_types[0] = opform->oprleft;
-		nargs = 1;
-	}
-	else if (ltree == NULL)
+	if (ltree == NULL)
 	{
 		/* left operator */
 		args = list_make1(rtree);
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 60dd80c23c..16abfcb406 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -9207,25 +9207,16 @@ get_oper_expr(OpExpr *expr, deparse_context *context)
 		if (!HeapTupleIsValid(tp))
 			elog(ERROR, "cache lookup failed for operator %u", opno);
 		optup = (Form_pg_operator) GETSTRUCT(tp);
-		switch (optup->oprkind)
-		{
-			case 'l':
-				appendStringInfo(buf, "%s ",
-								 generate_operator_name(opno,
-														InvalidOid,
-														exprType(arg)));
-				get_rule_expr_paren(arg, context, true, (Node *) expr);
-				break;
-			case 'r':
-				get_rule_expr_paren(arg, context, true, (Node *) expr);
-				appendStringInfo(buf, " %s",
-								 generate_operator_name(opno,
-														exprType(arg),
-														InvalidOid));
-				break;
-			default:
-				elog(ERROR, "bogus oprkind: %d", optup->oprkind);
+		if (optup->oprkind == 'l')
+		{
+			appendStringInfo(buf, "%s ",
+							 generate_operator_name(opno,
+													InvalidOid,
+													exprType(arg)));
+			get_rule_expr_paren(arg, context, true, (Node *) expr);
 		}
+		else
+			elog(ERROR, "bogus oprkind: %d", optup->oprkind);
 		ReleaseSysCache(tp);
 	}
 	if (!PRETTY_PAREN(context))
@@ -11087,10 +11078,6 @@ generate_operator_name(Oid operid, Oid arg1, Oid arg2)
 			p_result = left_oper(NULL, list_make1(makeString(oprname)), arg2,
 								 true, -1);
 			break;
-		case 'r':
-			p_result = right_oper(NULL, list_make1(makeString(oprname)), arg1,
-								  true, -1);
-			break;
 		default:
 			elog(ERROR, "unrecognized oprkind: %d", operform->oprkind);
 			p_result = NULL;	/* keep compiler quiet */
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 2cb3f9b083..a93ab8eed3 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -12643,11 +12643,9 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
 					  oprinfo->dobj.name);
 
 	/*
-	 * right unary means there's a left arg and left unary means there's a
-	 * right arg
+	 * left unary means there's only a right arg
 	 */
-	if (strcmp(oprkind, "r") == 0 ||
-		strcmp(oprkind, "b") == 0)
+	if (strcmp(oprkind, "b") == 0)
 	{
 		appendPQExpBuffer(details, ",\n    LEFTARG = %s", oprleft);
 		appendPQExpBufferStr(oprid, oprleft);
diff --git a/src/bin/pg_dump/pg_dump_sort.c b/src/bin/pg_dump/pg_dump_sort.c
index 654e2ec514..c7f06604c6 100644
--- a/src/bin/pg_dump/pg_dump_sort.c
+++ b/src/bin/pg_dump/pg_dump_sort.c
@@ -203,7 +203,7 @@ DOTypeNameCompare(const void *p1, const void *p2)
 		OprInfo    *oobj1 = *(OprInfo *const *) p1;
 		OprInfo    *oobj2 = *(OprInfo *const *) p2;
 
-		/* oprkind is 'l', 'r', or 'b'; this sorts prefix, postfix, infix */
+		/* oprkind is 'l' or 'b'; this sorts prefix and infix */
 		cmpval = (oobj2->oprkind - oobj1->oprkind);
 		if (cmpval != 0)
 			return cmpval;
diff --git a/src/bin/pg_upgrade/check.c b/src/bin/pg_upgrade/check.c
index 00aef855dc..b86098dc42 100644
--- a/src/bin/pg_upgrade/check.c
+++ b/src/bin/pg_upgrade/check.c
@@ -22,6 +22,7 @@ static void check_is_install_user(ClusterInfo *cluster);
 static void check_proper_datallowconn(ClusterInfo *cluster);
 static void check_for_prepared_transactions(ClusterInfo *cluster);
 static void check_for_isn_and_int8_passing_mismatch(ClusterInfo *cluster);
+static void check_for_user_defined_postfix_ops(ClusterInfo *cluster);
 static void check_for_tables_with_oids(ClusterInfo *cluster);
 static void check_for_reg_data_type_usage(ClusterInfo *cluster);
 static void check_for_jsonb_9_4_usage(ClusterInfo *cluster);
@@ -100,6 +101,13 @@ check_and_dump_old_cluster(bool live_check)
 	check_for_reg_data_type_usage(&old_cluster);
 	check_for_isn_and_int8_passing_mismatch(&old_cluster);
 
+	/*
+	 * Pre-PG 14 allowed user defined postfix operators, which are not
+	 * supported anymore.  Verify there are none, iff applicable.
+	 */
+	if (GET_MAJOR_VERSION(old_cluster.major_version) <= 1300)
+		check_for_user_defined_postfix_ops(&old_cluster);
+
 	/*
 	 * Pre-PG 12 allowed tables to be declared WITH OIDS, which is not
 	 * supported anymore. Verify there are none, iff applicable.
@@ -896,6 +904,104 @@ check_for_isn_and_int8_passing_mismatch(ClusterInfo *cluster)
 		check_ok();
 }
 
+/*
+ * Verify that no user defined postfix operators exist.
+ */
+static void
+check_for_user_defined_postfix_ops(ClusterInfo *cluster)
+{
+	int			dbnum;
+	FILE	   *script = NULL;
+	bool		found = false;
+	char		output_path[MAXPGPATH];
+
+	prep_status("Checking for user defined postfix operators");
+
+	snprintf(output_path, sizeof(output_path),
+			 "postfix_ops.txt");
+
+	/* Find any user defined postfix operators */
+	for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
+	{
+		PGresult   *res;
+		bool		db_used = false;
+		int			ntups;
+		int			rowno;
+		int			i_oproid,
+					i_oprnsp,
+					i_oprname,
+					i_typnsp,
+					i_typname;
+		DbInfo	   *active_db = &cluster->dbarr.dbs[dbnum];
+		PGconn	   *conn = connectToServer(cluster, active_db->db_name);
+
+		/*
+		 * The query below hardcodes FirstNormalObjectId as 16384 rather than
+		 * interpolating that C #define into the string because, if that
+		 * #define is ever changed, the cutoff we want to use is the definition
+		 * from pre-verion 14 servers, not from some future version of the
+		 * code.
+		 */
+		res = executeQueryOrDie(conn,
+								"SELECT o.oid AS oproid, "
+								"       n.nspname AS oprnsp, "
+								"       o.oprname, "
+								"       tn.nspname AS typnsp, "
+								"       t.typname "
+								"FROM pg_catalog.pg_operator o, "
+								"     pg_catalog.pg_namespace n, "
+								"     pg_catalog.pg_type t, "
+								"     pg_catalog.pg_namespace tn "
+								"WHERE o.oprnamespace = n.oid AND "
+								"      o.oprleft = t.oid AND "
+								"      t.typnamespace = tn.oid AND "
+								"      o.oprright = 0 AND "
+								"      o.oid >= 16384");
+		ntups = PQntuples(res);
+		i_oproid = PQfnumber(res, "oproid");
+		i_oprnsp = PQfnumber(res, "oprnsp");
+		i_oprname = PQfnumber(res, "oprname");
+		i_typnsp = PQfnumber(res, "typnsp");
+		i_typname = PQfnumber(res, "typname");
+		for (rowno = 0; rowno < ntups; rowno++)
+		{
+			found = true;
+			if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
+				pg_fatal("could not open file \"%s\": %s\n",
+						 output_path, strerror(errno));
+			if (!db_used)
+			{
+				fprintf(script, "In database: %s\n", active_db->db_name);
+				db_used = true;
+			}
+			fprintf(script, "  (oid=%s) %s.%s (%s.%s)\n",
+					PQgetvalue(res, rowno, i_oproid),
+					PQgetvalue(res, rowno, i_oprnsp),
+					PQgetvalue(res, rowno, i_oprname),
+					PQgetvalue(res, rowno, i_typnsp),
+					PQgetvalue(res, rowno, i_typname));
+		}
+
+		PQclear(res);
+
+		PQfinish(conn);
+	}
+
+	if (script)
+		fclose(script);
+
+	if (found)
+	{
+		pg_log(PG_REPORT, "fatal\n");
+		pg_fatal("Your installation contains user defined postfix operators, which is not\n"
+				 "supported anymore.  Consider dropping the postfix operators and replacing\n"
+				 "them with prefix operators or function calls.\n"
+				 "A list of user defined postfix operators is in the file:\n"
+				 "    %s\n\n", output_path);
+	}
+	else
+		check_ok();
+}
 
 /*
  * Verify that no tables are declared WITH OIDS.
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index d81f1575bf..1aaf5ccb38 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -805,7 +805,7 @@ describeOperators(const char *pattern, bool verbose, bool showSystem)
 					  "SELECT n.nspname as \"%s\",\n"
 					  "  o.oprname AS \"%s\",\n"
 					  "  CASE WHEN o.oprkind='l' THEN NULL ELSE pg_catalog.format_type(o.oprleft, NULL) END AS \"%s\",\n"
-					  "  CASE WHEN o.oprkind='r' THEN NULL ELSE pg_catalog.format_type(o.oprright, NULL) END AS \"%s\",\n"
+					  "  pg_catalog.format_type(o.oprright, NULL) AS \"%s\",\n"
 					  "  pg_catalog.format_type(o.oprresult, NULL) AS \"%s\",\n",
 					  gettext_noop("Schema"),
 					  gettext_noop("Name"),
diff --git a/src/include/catalog/pg_operator.dat b/src/include/catalog/pg_operator.dat
index 4f8b9865ef..7cc812adda 100644
--- a/src/include/catalog/pg_operator.dat
+++ b/src/include/catalog/pg_operator.dat
@@ -218,12 +218,6 @@
   oprname => '>=', oprleft => 'xid8', oprright => 'xid8', oprresult => 'bool',
   oprcom => '<=(xid8,xid8)', oprnegate => '<(xid8,xid8)', oprcode => 'xid8ge',
   oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' },
-{ oid => '388', descr => 'deprecated, use factorial() instead',
-  oprname => '!', oprkind => 'r', oprleft => 'int8', oprright => '0',
-  oprresult => 'numeric', oprcode => 'numeric_fac' },
-{ oid => '389', descr => 'deprecated, use factorial() instead',
-  oprname => '!!', oprkind => 'l', oprleft => '0', oprright => 'int8',
-  oprresult => 'numeric', oprcode => 'numeric_fac' },
 { oid => '385', descr => 'equal',
   oprname => '=', oprcanhash => 't', oprleft => 'cid', oprright => 'cid',
   oprresult => 'bool', oprcom => '=(cid,cid)', oprcode => 'cideq',
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index 1daa263852..1491b87582 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -41,7 +41,7 @@ CATALOG(pg_operator,2617,OperatorRelationId)
 	/* operator owner */
 	Oid			oprowner BKI_DEFAULT(PGUID);
 
-	/* 'l', 'r', or 'b' */
+	/* 'l' or 'b' */
 	char		oprkind BKI_DEFAULT(b);
 
 	/* can be used in merge join? */
@@ -53,7 +53,7 @@ CATALOG(pg_operator,2617,OperatorRelationId)
 	/* left arg type, or 0 if 'l' oprkind */
 	Oid			oprleft BKI_LOOKUP(pg_type);
 
-	/* right arg type, or 0 if 'r' oprkind */
+	/* right arg type */
 	Oid			oprright BKI_LOOKUP(pg_type);
 
 	/* result datatype */
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 1dd325e0e6..f5af410434 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -327,10 +327,6 @@
 { oid => '110', descr => 'I/O',
   proname => 'unknownout', prorettype => 'cstring', proargtypes => 'unknown',
   prosrc => 'unknownout' },
-{ oid => '111',
-  descr => 'implementation of deprecated ! and !! factorial operators',
-  proname => 'numeric_fac', prorettype => 'numeric', proargtypes => 'int8',
-  prosrc => 'numeric_fac' },
 
 { oid => '115',
   proname => 'box_above_eq', prorettype => 'bool', proargtypes => 'box box',
diff --git a/src/test/regress/expected/create_operator.out b/src/test/regress/expected/create_operator.out
index 54e8b79159..9d97564a4c 100644
--- a/src/test/regress/expected/create_operator.out
+++ b/src/test/regress/expected/create_operator.out
@@ -15,16 +15,16 @@ CREATE OPERATOR <% (
    negator = >=%
 );
 CREATE OPERATOR @#@ (
-   rightarg = int8,		-- left unary
-   procedure = numeric_fac
+   rightarg = float8,	-- left unary
+   procedure = dsqrt
 );
 CREATE OPERATOR #@# (
-   leftarg = int8,		-- right unary
-   procedure = numeric_fac
+   rightarg = float8,	-- left unary
+   procedure = dsqrt
 );
 CREATE OPERATOR #%# (
-   leftarg = int8,		-- right unary
-   procedure = numeric_fac
+   rightarg = float8,	-- left unary
+   procedure = dsqrt
 );
 -- Test operator created above
 SELECT point '(1,2)' <% widget '(0,0,3)' AS t,
@@ -36,7 +36,10 @@ SELECT point '(1,2)' <% widget '(0,0,3)' AS t,
 
 -- Test comments
 COMMENT ON OPERATOR ###### (int4, NONE) IS 'bad right unary';
-ERROR:  operator does not exist: integer ######
+ERROR:  operator right argument must be specified
+HINT:  Postfix operators are not supported.
+COMMENT ON OPERATOR ###### (NONE, int4) IS 'bad left unary';
+ERROR:  operator does not exist: ###### integer
 -- => is disallowed now
 CREATE OPERATOR => (
    leftarg = int8,		-- right unary
@@ -52,12 +55,12 @@ CREATE OPERATOR !=- (
    leftarg = int8,		-- right unary
    procedure = numeric_fac
 );
+ERROR:  operator right argument must be specified
+HINT:  Postfix operators are not supported.
 SELECT 2 !=-;
- ?column? 
-----------
-        2
-(1 row)
-
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 2 !=-;
+                    ^
 -- make sure lexer returns != as <> even in edge cases
 SELECT 2 !=/**/ 1, 2 !=/**/ 2;
  ?column? | ?column? 
@@ -172,11 +175,13 @@ CREATE OPERATOR #@%# (
    invalid_att = int8
 );
 WARNING:  operator attribute "invalid_att" not recognized
--- Should fail. At least leftarg or rightarg should be mandatorily specified
+ERROR:  operator right argument must be specified
+HINT:  Postfix operators are not supported.
+-- Should fail. At least rightarg should be mandatorily specified
 CREATE OPERATOR #@%# (
    procedure = numeric_fac
 );
-ERROR:  at least one of leftarg or rightarg must be specified
+ERROR:  operator arguments must be specified
 -- Should fail. Procedure should be mandatorily specified
 CREATE OPERATOR #@%# (
    leftarg = int8
diff --git a/src/test/regress/expected/numeric.out b/src/test/regress/expected/numeric.out
index 8546ce901f..8442fbef7d 100644
--- a/src/test/regress/expected/numeric.out
+++ b/src/test/regress/expected/numeric.out
@@ -2960,16 +2960,16 @@ ERROR:  value overflows numeric format
 --
 -- Tests for factorial
 --
-SELECT 4!;
- ?column? 
-----------
-       24
+SELECT factorial(4);
+ factorial 
+-----------
+        24
 (1 row)
 
-SELECT !!3;
- ?column? 
-----------
-        6
+SELECT factorial(3);
+ factorial 
+-----------
+         6
 (1 row)
 
 SELECT factorial(15);
@@ -2978,19 +2978,28 @@ SELECT factorial(15);
  1307674368000
 (1 row)
 
-SELECT 100000!;
+SELECT factorial(100000);
 ERROR:  value overflows numeric format
-SELECT 0!;
- ?column? 
-----------
-        1
+SELECT factorial(0);
+ factorial 
+-----------
+         1
 (1 row)
 
-SELECT -4!;
-ERROR:  factorial of a negative number is undefined
 SELECT factorial(-4);
 ERROR:  factorial of a negative number is undefined
 --
+-- Postfix operators are not supported.  Check that.
+--
+SELECT -5!;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT -5!;
+                  ^
+SELECT 5!;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 5!;
+                 ^
+--
 -- Tests for pg_lsn()
 --
 SELECT pg_lsn(23783416::numeric);
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index 1b3c146e4c..7825a765cd 100644
--- a/src/test/regress/expected/opr_sanity.out
+++ b/src/test/regress/expected/opr_sanity.out
@@ -1066,7 +1066,7 @@ WHERE condefault AND
 -- Look for illegal values in pg_operator fields.
 SELECT p1.oid, p1.oprname
 FROM pg_operator as p1
-WHERE (p1.oprkind != 'b' AND p1.oprkind != 'l' AND p1.oprkind != 'r') OR
+WHERE (p1.oprkind != 'b' AND p1.oprkind != 'l') OR
     p1.oprresult = 0 OR p1.oprcode = 0;
  oid | oprname 
 -----+---------
@@ -1077,8 +1077,7 @@ SELECT p1.oid, p1.oprname
 FROM pg_operator as p1
 WHERE (p1.oprleft = 0 and p1.oprkind != 'l') OR
     (p1.oprleft != 0 and p1.oprkind = 'l') OR
-    (p1.oprright = 0 and p1.oprkind != 'r') OR
-    (p1.oprright != 0 and p1.oprkind = 'r');
+    p1.oprright = 0;
  oid | oprname 
 -----+---------
 (0 rows)
@@ -1285,18 +1284,6 @@ WHERE p1.oprcode = p2.oid AND
 -----+---------+-----+---------
 (0 rows)
 
-SELECT p1.oid, p1.oprname, p2.oid, p2.proname
-FROM pg_operator AS p1, pg_proc AS p2
-WHERE p1.oprcode = p2.oid AND
-    p1.oprkind = 'r' AND
-    (p2.pronargs != 1
-     OR NOT binary_coercible(p2.prorettype, p1.oprresult)
-     OR NOT binary_coercible(p1.oprleft, p2.proargtypes[0])
-     OR p1.oprright != 0);
- oid | oprname | oid | proname 
------+---------+-----+---------
-(0 rows)
-
 -- If the operator is mergejoinable or hashjoinable, its underlying function
 -- should not be volatile.
 SELECT p1.oid, p1.oprname, p2.oid, p2.proname
diff --git a/src/test/regress/sql/create_operator.sql b/src/test/regress/sql/create_operator.sql
index 8b6fd0bb43..d6c3dc98c1 100644
--- a/src/test/regress/sql/create_operator.sql
+++ b/src/test/regress/sql/create_operator.sql
@@ -18,18 +18,18 @@ CREATE OPERATOR <% (
 );
 
 CREATE OPERATOR @#@ (
-   rightarg = int8,		-- left unary
-   procedure = numeric_fac
+   rightarg = float8,	-- left unary
+   procedure = dsqrt
 );
 
 CREATE OPERATOR #@# (
-   leftarg = int8,		-- right unary
-   procedure = numeric_fac
+   rightarg = float8,	-- left unary
+   procedure = dsqrt
 );
 
 CREATE OPERATOR #%# (
-   leftarg = int8,		-- right unary
-   procedure = numeric_fac
+   rightarg = float8,	-- left unary
+   procedure = dsqrt
 );
 
 -- Test operator created above
@@ -38,6 +38,7 @@ SELECT point '(1,2)' <% widget '(0,0,3)' AS t,
 
 -- Test comments
 COMMENT ON OPERATOR ###### (int4, NONE) IS 'bad right unary';
+COMMENT ON OPERATOR ###### (NONE, int4) IS 'bad left unary';
 
 -- => is disallowed now
 CREATE OPERATOR => (
@@ -133,7 +134,7 @@ CREATE OPERATOR #@%# (
    invalid_att = int8
 );
 
--- Should fail. At least leftarg or rightarg should be mandatorily specified
+-- Should fail. At least rightarg should be mandatorily specified
 CREATE OPERATOR #@%# (
    procedure = numeric_fac
 );
diff --git a/src/test/regress/sql/numeric.sql b/src/test/regress/sql/numeric.sql
index 416c16722a..096cafeb69 100644
--- a/src/test/regress/sql/numeric.sql
+++ b/src/test/regress/sql/numeric.sql
@@ -1298,14 +1298,19 @@ SELECT lcm(9999 * (10::numeric)^131068 + (10::numeric^131068 - 1), 2); -- overfl
 --
 -- Tests for factorial
 --
-SELECT 4!;
-SELECT !!3;
+SELECT factorial(4);
+SELECT factorial(3);
 SELECT factorial(15);
-SELECT 100000!;
-SELECT 0!;
-SELECT -4!;
+SELECT factorial(100000);
+SELECT factorial(0);
 SELECT factorial(-4);
 
+--
+-- Postfix operators are not supported.  Check that.
+--
+SELECT -5!;
+SELECT 5!;
+
 --
 -- Tests for pg_lsn()
 --
diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql
index 7a9180b081..307aab1deb 100644
--- a/src/test/regress/sql/opr_sanity.sql
+++ b/src/test/regress/sql/opr_sanity.sql
@@ -571,7 +571,7 @@ WHERE condefault AND
 
 SELECT p1.oid, p1.oprname
 FROM pg_operator as p1
-WHERE (p1.oprkind != 'b' AND p1.oprkind != 'l' AND p1.oprkind != 'r') OR
+WHERE (p1.oprkind != 'b' AND p1.oprkind != 'l') OR
     p1.oprresult = 0 OR p1.oprcode = 0;
 
 -- Look for missing or unwanted operand types
@@ -580,8 +580,7 @@ SELECT p1.oid, p1.oprname
 FROM pg_operator as p1
 WHERE (p1.oprleft = 0 and p1.oprkind != 'l') OR
     (p1.oprleft != 0 and p1.oprkind = 'l') OR
-    (p1.oprright = 0 and p1.oprkind != 'r') OR
-    (p1.oprright != 0 and p1.oprkind = 'r');
+    p1.oprright = 0;
 
 -- Look for conflicting operator definitions (same names and input datatypes).
 
@@ -715,15 +714,6 @@ WHERE p1.oprcode = p2.oid AND
      OR NOT binary_coercible(p1.oprright, p2.proargtypes[0])
      OR p1.oprleft != 0);
 
-SELECT p1.oid, p1.oprname, p2.oid, p2.proname
-FROM pg_operator AS p1, pg_proc AS p2
-WHERE p1.oprcode = p2.oid AND
-    p1.oprkind = 'r' AND
-    (p2.pronargs != 1
-     OR NOT binary_coercible(p2.prorettype, p1.oprresult)
-     OR NOT binary_coercible(p1.oprleft, p2.proargtypes[0])
-     OR p1.oprright != 0);
-
 -- If the operator is mergejoinable or hashjoinable, its underlying function
 -- should not be volatile.
 
diff --git a/src/tutorial/complex.source b/src/tutorial/complex.source
index 0355926701..65db7d5144 100644
--- a/src/tutorial/complex.source
+++ b/src/tutorial/complex.source
@@ -111,7 +111,7 @@ CREATE FUNCTION complex_add(complex, complex)
    LANGUAGE C IMMUTABLE STRICT;
 
 -- we can now define the operator. We show a binary operator here but you
--- can also define unary operators by omitting either of leftarg or rightarg.
+-- can also define a left unary operator by omitting the leftarg.
 CREATE OPERATOR + (
    leftarg = complex,
    rightarg = complex,
diff --git a/src/tutorial/syscat.source b/src/tutorial/syscat.source
index 3a1767f97b..a84ea0d5c9 100644
--- a/src/tutorial/syscat.source
+++ b/src/tutorial/syscat.source
@@ -110,20 +110,6 @@ SELECT n.nspname, o.oprname AS left_unary,
   ORDER BY nspname, operand;
 
 
---
--- lists all right unary operators
---
-SELECT n.nspname, o.oprname AS right_unary,
-       format_type(left_type.oid, null) AS operand,
-       format_type(result.oid, null) AS return_type
-  FROM pg_namespace n, pg_operator o,
-       pg_type left_type, pg_type result
-  WHERE o.oprnamespace = n.oid
-    and o.oprkind = 'r'          -- right unary
-    and o.oprleft = left_type.oid
-    and o.oprresult = result.oid
-  ORDER BY nspname, operand;
-
 --
 -- lists all binary operators
 --
-- 
2.21.1 (Apple Git-122.3)

v6-0002-Allow-most-keywords-to-be-used-as-implicit-column.patchapplication/octet-stream; name=v6-0002-Allow-most-keywords-to-be-used-as-implicit-column.patch; x-unix-mode=0644Download
From eb99bbbd401273916c94825120c594126aa17b66 Mon Sep 17 00:00:00 2001
From: Mark Dilger <mark.dilger@enterprisedb.com>
Date: Mon, 31 Aug 2020 13:13:07 -0700
Subject: [PATCH v6 2/3] Allow most keywords to be used as implicit column
 labels.

Previously, to use a keyword as a column label in an expression, the
keyword had to be preceded by the token AS.  That is no longer
required for most keywords.  This is accomplished with some changes
to gram.y and by removing support for postfix operators.

These keywords must still be preceded by AS:

    array, as, char, character, create, day, except, fetch, filter,
    for, from, grant, group, having, hour, intersect, into, isnull,
    limit, minute, month, notnull, offset, on, order, over,
    overlaps, precision, returning, second, to, union, varying,
    where, window, with, within, without, year

Adding to the return value of pg_get_keywords a fourth column
showing whether the keyword can be used as an implicit column label.
---
 doc/src/sgml/func.sgml                  |   6 +-
 doc/src/sgml/generate-keywords-table.pl |   2 +-
 src/backend/parser/check_keywords.pl    |  97 ++-
 src/backend/parser/gram.y               | 439 +++++++++++-
 src/backend/parser/scan.l               |   2 +-
 src/backend/utils/adt/misc.c            |  11 +-
 src/common/keywords.c                   |   2 +-
 src/include/catalog/pg_proc.dat         |   4 +-
 src/include/common/kwlookup.h           |   8 +
 src/include/parser/kwlist.h             | 902 ++++++++++++------------
 src/interfaces/ecpg/preproc/keywords.c  |   2 +-
 src/tools/gen_keywordlist.pl            |  30 +-
 12 files changed, 1010 insertions(+), 495 deletions(-)

diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index b9f591296a..fd20720734 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -22171,7 +22171,8 @@ 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>catdesc</parameter> <type>text</type>,
+        <parameter>aliastype</parameter> <type>text</type> )
        </para>
        <para>
         Returns a set of records describing the SQL keywords recognized by the
@@ -22183,6 +22184,9 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
         function name, or <literal>R</literal> for a fully reserved keyword.
         The <parameter>catdesc</parameter> column contains a
         possibly-localized string describing the category.
+        The <parameter>aliastype</parameter> column is
+        <literal>implicit</literal> if the keyword can be used as an implicit
+        column label, <literal>explicit</literal> otherwise.
        </para></entry>
       </row>
 
diff --git a/doc/src/sgml/generate-keywords-table.pl b/doc/src/sgml/generate-keywords-table.pl
index 824b324ef7..6ae6f80c3f 100644
--- a/doc/src/sgml/generate-keywords-table.pl
+++ b/doc/src/sgml/generate-keywords-table.pl
@@ -39,7 +39,7 @@ 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;
 	}
diff --git a/src/backend/parser/check_keywords.pl b/src/backend/parser/check_keywords.pl
index 702c97bba2..ddba00c96f 100644
--- a/src/backend/parser/check_keywords.pl
+++ b/src/backend/parser/check_keywords.pl
@@ -21,6 +21,27 @@ sub error
 	return;
 }
 
+sub check_alphabetical_order
+{
+	my ($listname, $list) = @_;
+	my $prevkword = '';
+	my $implicit_alias_kword;
+
+	foreach my $kword (@$list)
+	{
+
+		# Some keyword have a _P suffix. Remove it for the comparison.
+		$implicit_alias_kword = $kword;
+		$implicit_alias_kword =~ s/_P$//;
+		if ($implicit_alias_kword le $prevkword)
+		{
+			error
+			  "'$implicit_alias_kword' after '$prevkword' in $listname list is misplaced";
+		}
+		$prevkword = $implicit_alias_kword;
+	}
+}
+
 $, = ' ';     # set output field separator
 $\ = "\n";    # set output record separator
 
@@ -33,9 +54,11 @@ $keyword_categories{'reserved_keyword'}       = 'RESERVED_KEYWORD';
 open(my $gram, '<', $gram_filename) || die("Could not open : $gram_filename");
 
 my $kcat;
+my $implicit_alias;
 my $comment;
 my @arr;
 my %keywords;
+my @implicit_alias;
 
 line: while (my $S = <$gram>)
 {
@@ -51,7 +74,7 @@ line: while (my $S = <$gram>)
 	$s = '[/][*]', $S =~ s#$s# /* #g;
 	$s = '[*][/]', $S =~ s#$s# */ #g;
 
-	if (!($kcat))
+	if (!($kcat) && !($implicit_alias))
 	{
 
 		# Is this the beginning of a keyword list?
@@ -63,6 +86,10 @@ line: while (my $S = <$gram>)
 				next line;
 			}
 		}
+
+		# Is this the beginning of the implicit_alias_keyword list?
+		$implicit_alias = 1 if ($S =~ m/^implicit_alias_keyword:/);
+
 		next line;
 	}
 
@@ -97,7 +124,8 @@ line: while (my $S = <$gram>)
 		{
 
 			# end of keyword list
-			$kcat = '';
+			undef $kcat;
+			undef $implicit_alias;
 			next;
 		}
 
@@ -107,31 +135,21 @@ line: while (my $S = <$gram>)
 		}
 
 		# Put this keyword into the right list
-		push @{ $keywords{$kcat} }, $arr[$fieldIndexer];
+		if ($implicit_alias)
+		{
+			push @implicit_alias, $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('implicit_alias_keyword', \@implicit_alias);
 
 # Transform the keyword lists into hashes.
 # kwhashes is a hash of hashes, keyed by keyword category id,
@@ -147,6 +165,7 @@ while (my ($kcat, $kcat_id) = each(%keyword_categories))
 
 	$kwhashes{$kcat_id} = $hash;
 }
+my %implicit_alias = map { $_ => 1 } @implicit_alias;
 
 # Now read in kwlist.h
 
@@ -154,17 +173,41 @@ open(my $kwlist, '<', $kwlist_filename)
   || die("Could not open : $kwlist_filename");
 
 my $prevkwstring = '';
-my $bare_kwname;
+my $implicit_alias_kwname;
 my %kwhash;
 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 ($aliastype) = $4;
+
+		# Check that the keyword label aliastype value matches treatment in gram.y
+		if ($aliastype eq 'IMPLICIT_ALIAS')
+		{
+			unless ($implicit_alias{$kwname})
+			{
+				error
+				  "'$kwstring' in kwlist.h is marked as implicit_alias, but is missing from gram.y's implicit_alias_keyword rule";
+			}
+		}
+		elsif ($aliastype eq 'EXPLICIT_ALIAS')
+		{
+			if ($implicit_alias{$kwname})
+			{
+				error
+				  "'$kwname' in kwlist.h is marked as explicit, but is listed in gram.y's implicit_alias_keyword rule";
+			}
+		}
+		else
+		{
+			error
+			  "'$aliastype' not recognized in kwlist.h.  Expected either 'IMPLICIT_ALIAS' or 'EXPLICIT_ALIAS'";
+		}
 
 		# Check that the list is in alphabetical order (critical!)
 		if ($kwstring le $prevkwstring)
@@ -189,9 +232,9 @@ kwlist_line: while (<$kwlist>)
 		}
 
 		# Check that the keyword string matches keyword name
-		$bare_kwname = $kwname;
-		$bare_kwname =~ s/_P$//;
-		if ($bare_kwname ne uc($kwstring))
+		$implicit_alias_kwname = $kwname;
+		$implicit_alias_kwname =~ s/_P$//;
+		if ($implicit_alias_kwname ne uc($kwstring))
 		{
 			error
 			  "keyword name '$kwname' doesn't match keyword string '$kwstring'";
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index d8a607e29a..e9ee5dd873 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -540,14 +540,15 @@ 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 ImplicitAlias
 %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> col_name_keyword implicit_alias_keyword reserved_keyword
 
 %type <node>	TableConstraint TableLikeClause
 %type <ival>	TableLikeOptionList TableLikeOption
@@ -14655,11 +14656,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 ImplicitAlias
 				{
 					$$ = makeNode(ResTarget);
 					$$->name = $2;
@@ -14987,6 +14984,12 @@ NonReservedWord:	IDENT							{ $$ = $1; }
 			| type_func_name_keyword				{ $$ = pstrdup($1); }
 		;
 
+/* Bare column label --- names that can be column labels without writing "AS".
+ */
+ImplicitAlias:	IDENT								{ $$ = $1; }
+			| implicit_alias_keyword					{ $$ = pstrdup($1); }
+		;
+
 /* Column label --- allowed labels in "AS" clauses.
  * This presently includes *all* Postgres keywords.
  */
@@ -14998,6 +15001,428 @@ ColLabel:	IDENT									{ $$ = $1; }
 		;
 
 
+/*
+ * All keywords can be used explicitly as a column label in expressions
+ * like 'SELECT 1234 AS keyword', but only some keywords can be used
+ * implicitly as column labels in expressions like 'SELECT 1234 keyword'.
+ * Those that can be used implicitly should be listed here.
+ *
+ * Keep this in alphabetical order.
+ */
+implicit_alias_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
+		;
+
 /*
  * Keyword category lists.  Generally, every keyword present in
  * the Postgres grammar should appear in exactly one of these lists.
diff --git a/src/backend/parser/scan.l b/src/backend/parser/scan.l
index b1ea0cb538..58a8afa782 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, aliastype) 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 37c23c9155..1b04b0e079 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -416,13 +416,15 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 		funcctx = SRF_FIRSTCALL_INIT();
 		oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
 
-		tupdesc = CreateTemplateTupleDesc(3);
+		tupdesc = CreateTemplateTupleDesc(4);
 		TupleDescInitEntry(tupdesc, (AttrNumber) 1, "word",
 						   TEXTOID, -1, 0);
 		TupleDescInitEntry(tupdesc, (AttrNumber) 2, "catcode",
 						   CHAROID, -1, 0);
 		TupleDescInitEntry(tupdesc, (AttrNumber) 3, "catdesc",
 						   TEXTOID, -1, 0);
+		TupleDescInitEntry(tupdesc, (AttrNumber) 4, "aliastype",
+						   TEXTOID, -1, 0);
 
 		funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
 
@@ -433,7 +435,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 	if (funcctx->call_cntr < ScanKeywords.num_keywords)
 	{
-		char	   *values[3];
+		char	   *values[4];
 		HeapTuple	tuple;
 
 		/* cast-away-const is ugly but alternatives aren't much better */
@@ -465,6 +467,11 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 				break;
 		}
 
+		if (GetScanKeywordIsImplicit(funcctx->call_cntr, &ScanKeywords))
+			values[3] = unconstify(char *, (const char *)"implicit");
+		else
+			values[3] = unconstify(char *, (const char *)"explicit");
+
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
 		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
diff --git a/src/common/keywords.c b/src/common/keywords.c
index 54ed977096..f42cd69094 100644
--- a/src/common/keywords.c
+++ b/src/common/keywords.c
@@ -24,7 +24,7 @@
 
 /* Keyword categories for SQL keywords */
 
-#define PG_KEYWORD(kwname, value, category) category,
+#define PG_KEYWORD(kwname, value, category, aliastype) category,
 
 const uint8 ScanKeywordCategories[SCANKEYWORDS_NUM_KEYWORDS] = {
 #include "parser/kwlist.h"
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index f5af410434..b4c4fe8a5c 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -3677,8 +3677,8 @@
 { oid => '1686', descr => 'list of SQL keywords',
   proname => 'pg_get_keywords', procost => '10', prorows => '400',
   proretset => 't', provolatile => 's', prorettype => 'record',
-  proargtypes => '', proallargtypes => '{text,char,text}',
-  proargmodes => '{o,o,o}', proargnames => '{word,catcode,catdesc}',
+  proargtypes => '', proallargtypes => '{text,char,text,text}',
+  proargmodes => '{o,o,o,o}', proargnames => '{word,catcode,catdesc,aliastype}',
   prosrc => 'pg_get_keywords' },
 
 { oid => '2289', descr => 'convert generic options array to name/value table',
diff --git a/src/include/common/kwlookup.h b/src/include/common/kwlookup.h
index 9c0c7f88d8..d56b3d895e 100644
--- a/src/include/common/kwlookup.h
+++ b/src/include/common/kwlookup.h
@@ -26,6 +26,7 @@ typedef struct ScanKeywordList
 {
 	const char *kw_string;		/* all keywords in order, separated by \0 */
 	const uint16 *kw_offsets;	/* offsets to the start of each keyword */
+	const bool *kw_is_implicit;	/* whether each keyword can be used as an implicit label */
 	ScanKeywordHashFunc hash;	/* perfect hash function for keywords */
 	int			num_keywords;	/* number of keywords */
 	int			max_kw_len;		/* length of longest keyword */
@@ -41,4 +42,11 @@ GetScanKeyword(int n, const ScanKeywordList *keywords)
 	return keywords->kw_string + keywords->kw_offsets[n];
 }
 
+/* Code that wants to retrieve the aliastype of the N'th keyword should use this. */
+static inline bool
+GetScanKeywordIsImplicit(int n, const ScanKeywordList *keywords)
+{
+	return keywords->kw_is_implicit[n];
+}
+
 #endif							/* KWLOOKUP_H */
diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h
index 08f22ce211..d011b3a5e5 100644
--- a/src/include/parser/kwlist.h
+++ b/src/include/parser/kwlist.h
@@ -24,454 +24,454 @@
  * Note: gen_keywordlist.pl requires the entries to appear in ASCII order.
  */
 
-/* name, value, category */
-PG_KEYWORD("abort", ABORT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("absolute", ABSOLUTE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("access", ACCESS, UNRESERVED_KEYWORD)
-PG_KEYWORD("action", ACTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("add", ADD_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("admin", ADMIN, UNRESERVED_KEYWORD)
-PG_KEYWORD("after", AFTER, UNRESERVED_KEYWORD)
-PG_KEYWORD("aggregate", AGGREGATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("all", ALL, RESERVED_KEYWORD)
-PG_KEYWORD("also", ALSO, UNRESERVED_KEYWORD)
-PG_KEYWORD("alter", ALTER, UNRESERVED_KEYWORD)
-PG_KEYWORD("always", ALWAYS, UNRESERVED_KEYWORD)
-PG_KEYWORD("analyse", ANALYSE, RESERVED_KEYWORD)		/* British spelling */
-PG_KEYWORD("analyze", ANALYZE, RESERVED_KEYWORD)
-PG_KEYWORD("and", AND, RESERVED_KEYWORD)
-PG_KEYWORD("any", ANY, RESERVED_KEYWORD)
-PG_KEYWORD("array", ARRAY, RESERVED_KEYWORD)
-PG_KEYWORD("as", AS, RESERVED_KEYWORD)
-PG_KEYWORD("asc", ASC, RESERVED_KEYWORD)
-PG_KEYWORD("assertion", ASSERTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("assignment", ASSIGNMENT, UNRESERVED_KEYWORD)
-PG_KEYWORD("asymmetric", ASYMMETRIC, RESERVED_KEYWORD)
-PG_KEYWORD("at", AT, UNRESERVED_KEYWORD)
-PG_KEYWORD("attach", ATTACH, UNRESERVED_KEYWORD)
-PG_KEYWORD("attribute", ATTRIBUTE, UNRESERVED_KEYWORD)
-PG_KEYWORD("authorization", AUTHORIZATION, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("backward", BACKWARD, UNRESERVED_KEYWORD)
-PG_KEYWORD("before", BEFORE, UNRESERVED_KEYWORD)
-PG_KEYWORD("begin", BEGIN_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("between", BETWEEN, COL_NAME_KEYWORD)
-PG_KEYWORD("bigint", BIGINT, COL_NAME_KEYWORD)
-PG_KEYWORD("binary", BINARY, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("bit", BIT, COL_NAME_KEYWORD)
-PG_KEYWORD("boolean", BOOLEAN_P, COL_NAME_KEYWORD)
-PG_KEYWORD("both", BOTH, RESERVED_KEYWORD)
-PG_KEYWORD("by", BY, UNRESERVED_KEYWORD)
-PG_KEYWORD("cache", CACHE, UNRESERVED_KEYWORD)
-PG_KEYWORD("call", CALL, UNRESERVED_KEYWORD)
-PG_KEYWORD("called", CALLED, UNRESERVED_KEYWORD)
-PG_KEYWORD("cascade", CASCADE, UNRESERVED_KEYWORD)
-PG_KEYWORD("cascaded", CASCADED, UNRESERVED_KEYWORD)
-PG_KEYWORD("case", CASE, RESERVED_KEYWORD)
-PG_KEYWORD("cast", CAST, RESERVED_KEYWORD)
-PG_KEYWORD("catalog", CATALOG_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("chain", CHAIN, UNRESERVED_KEYWORD)
-PG_KEYWORD("char", CHAR_P, COL_NAME_KEYWORD)
-PG_KEYWORD("character", CHARACTER, COL_NAME_KEYWORD)
-PG_KEYWORD("characteristics", CHARACTERISTICS, UNRESERVED_KEYWORD)
-PG_KEYWORD("check", CHECK, RESERVED_KEYWORD)
-PG_KEYWORD("checkpoint", CHECKPOINT, UNRESERVED_KEYWORD)
-PG_KEYWORD("class", CLASS, UNRESERVED_KEYWORD)
-PG_KEYWORD("close", CLOSE, UNRESERVED_KEYWORD)
-PG_KEYWORD("cluster", CLUSTER, UNRESERVED_KEYWORD)
-PG_KEYWORD("coalesce", COALESCE, COL_NAME_KEYWORD)
-PG_KEYWORD("collate", COLLATE, RESERVED_KEYWORD)
-PG_KEYWORD("collation", COLLATION, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("column", COLUMN, RESERVED_KEYWORD)
-PG_KEYWORD("columns", COLUMNS, UNRESERVED_KEYWORD)
-PG_KEYWORD("comment", COMMENT, UNRESERVED_KEYWORD)
-PG_KEYWORD("comments", COMMENTS, UNRESERVED_KEYWORD)
-PG_KEYWORD("commit", COMMIT, UNRESERVED_KEYWORD)
-PG_KEYWORD("committed", COMMITTED, UNRESERVED_KEYWORD)
-PG_KEYWORD("concurrently", CONCURRENTLY, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("configuration", CONFIGURATION, UNRESERVED_KEYWORD)
-PG_KEYWORD("conflict", CONFLICT, UNRESERVED_KEYWORD)
-PG_KEYWORD("connection", CONNECTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("constraint", CONSTRAINT, RESERVED_KEYWORD)
-PG_KEYWORD("constraints", CONSTRAINTS, UNRESERVED_KEYWORD)
-PG_KEYWORD("content", CONTENT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("continue", CONTINUE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("conversion", CONVERSION_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("copy", COPY, UNRESERVED_KEYWORD)
-PG_KEYWORD("cost", COST, UNRESERVED_KEYWORD)
-PG_KEYWORD("create", CREATE, RESERVED_KEYWORD)
-PG_KEYWORD("cross", CROSS, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("csv", CSV, UNRESERVED_KEYWORD)
-PG_KEYWORD("cube", CUBE, UNRESERVED_KEYWORD)
-PG_KEYWORD("current", CURRENT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("current_catalog", CURRENT_CATALOG, RESERVED_KEYWORD)
-PG_KEYWORD("current_date", CURRENT_DATE, RESERVED_KEYWORD)
-PG_KEYWORD("current_role", CURRENT_ROLE, RESERVED_KEYWORD)
-PG_KEYWORD("current_schema", CURRENT_SCHEMA, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("current_time", CURRENT_TIME, RESERVED_KEYWORD)
-PG_KEYWORD("current_timestamp", CURRENT_TIMESTAMP, RESERVED_KEYWORD)
-PG_KEYWORD("current_user", CURRENT_USER, RESERVED_KEYWORD)
-PG_KEYWORD("cursor", CURSOR, UNRESERVED_KEYWORD)
-PG_KEYWORD("cycle", CYCLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("data", DATA_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("database", DATABASE, UNRESERVED_KEYWORD)
-PG_KEYWORD("day", DAY_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("deallocate", DEALLOCATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("dec", DEC, COL_NAME_KEYWORD)
-PG_KEYWORD("decimal", DECIMAL_P, COL_NAME_KEYWORD)
-PG_KEYWORD("declare", DECLARE, UNRESERVED_KEYWORD)
-PG_KEYWORD("default", DEFAULT, RESERVED_KEYWORD)
-PG_KEYWORD("defaults", DEFAULTS, UNRESERVED_KEYWORD)
-PG_KEYWORD("deferrable", DEFERRABLE, RESERVED_KEYWORD)
-PG_KEYWORD("deferred", DEFERRED, UNRESERVED_KEYWORD)
-PG_KEYWORD("definer", DEFINER, UNRESERVED_KEYWORD)
-PG_KEYWORD("delete", DELETE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("delimiter", DELIMITER, UNRESERVED_KEYWORD)
-PG_KEYWORD("delimiters", DELIMITERS, UNRESERVED_KEYWORD)
-PG_KEYWORD("depends", DEPENDS, UNRESERVED_KEYWORD)
-PG_KEYWORD("desc", DESC, RESERVED_KEYWORD)
-PG_KEYWORD("detach", DETACH, UNRESERVED_KEYWORD)
-PG_KEYWORD("dictionary", DICTIONARY, UNRESERVED_KEYWORD)
-PG_KEYWORD("disable", DISABLE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("discard", DISCARD, UNRESERVED_KEYWORD)
-PG_KEYWORD("distinct", DISTINCT, RESERVED_KEYWORD)
-PG_KEYWORD("do", DO, RESERVED_KEYWORD)
-PG_KEYWORD("document", DOCUMENT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("domain", DOMAIN_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("double", DOUBLE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("drop", DROP, UNRESERVED_KEYWORD)
-PG_KEYWORD("each", EACH, UNRESERVED_KEYWORD)
-PG_KEYWORD("else", ELSE, RESERVED_KEYWORD)
-PG_KEYWORD("enable", ENABLE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("encoding", ENCODING, UNRESERVED_KEYWORD)
-PG_KEYWORD("encrypted", ENCRYPTED, UNRESERVED_KEYWORD)
-PG_KEYWORD("end", END_P, RESERVED_KEYWORD)
-PG_KEYWORD("enum", ENUM_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("escape", ESCAPE, UNRESERVED_KEYWORD)
-PG_KEYWORD("event", EVENT, UNRESERVED_KEYWORD)
-PG_KEYWORD("except", EXCEPT, RESERVED_KEYWORD)
-PG_KEYWORD("exclude", EXCLUDE, UNRESERVED_KEYWORD)
-PG_KEYWORD("excluding", EXCLUDING, UNRESERVED_KEYWORD)
-PG_KEYWORD("exclusive", EXCLUSIVE, UNRESERVED_KEYWORD)
-PG_KEYWORD("execute", EXECUTE, UNRESERVED_KEYWORD)
-PG_KEYWORD("exists", EXISTS, COL_NAME_KEYWORD)
-PG_KEYWORD("explain", EXPLAIN, UNRESERVED_KEYWORD)
-PG_KEYWORD("expression", EXPRESSION, UNRESERVED_KEYWORD)
-PG_KEYWORD("extension", EXTENSION, UNRESERVED_KEYWORD)
-PG_KEYWORD("external", EXTERNAL, UNRESERVED_KEYWORD)
-PG_KEYWORD("extract", EXTRACT, COL_NAME_KEYWORD)
-PG_KEYWORD("false", FALSE_P, RESERVED_KEYWORD)
-PG_KEYWORD("family", FAMILY, UNRESERVED_KEYWORD)
-PG_KEYWORD("fetch", FETCH, RESERVED_KEYWORD)
-PG_KEYWORD("filter", FILTER, UNRESERVED_KEYWORD)
-PG_KEYWORD("first", FIRST_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("float", FLOAT_P, COL_NAME_KEYWORD)
-PG_KEYWORD("following", FOLLOWING, UNRESERVED_KEYWORD)
-PG_KEYWORD("for", FOR, RESERVED_KEYWORD)
-PG_KEYWORD("force", FORCE, UNRESERVED_KEYWORD)
-PG_KEYWORD("foreign", FOREIGN, RESERVED_KEYWORD)
-PG_KEYWORD("forward", FORWARD, UNRESERVED_KEYWORD)
-PG_KEYWORD("freeze", FREEZE, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("from", FROM, RESERVED_KEYWORD)
-PG_KEYWORD("full", FULL, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("function", FUNCTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("functions", FUNCTIONS, UNRESERVED_KEYWORD)
-PG_KEYWORD("generated", GENERATED, UNRESERVED_KEYWORD)
-PG_KEYWORD("global", GLOBAL, UNRESERVED_KEYWORD)
-PG_KEYWORD("grant", GRANT, RESERVED_KEYWORD)
-PG_KEYWORD("granted", GRANTED, UNRESERVED_KEYWORD)
-PG_KEYWORD("greatest", GREATEST, COL_NAME_KEYWORD)
-PG_KEYWORD("group", GROUP_P, RESERVED_KEYWORD)
-PG_KEYWORD("grouping", GROUPING, COL_NAME_KEYWORD)
-PG_KEYWORD("groups", GROUPS, UNRESERVED_KEYWORD)
-PG_KEYWORD("handler", HANDLER, UNRESERVED_KEYWORD)
-PG_KEYWORD("having", HAVING, RESERVED_KEYWORD)
-PG_KEYWORD("header", HEADER_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("hold", HOLD, UNRESERVED_KEYWORD)
-PG_KEYWORD("hour", HOUR_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("identity", IDENTITY_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("if", IF_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("ilike", ILIKE, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("immediate", IMMEDIATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("immutable", IMMUTABLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("implicit", IMPLICIT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("import", IMPORT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("in", IN_P, RESERVED_KEYWORD)
-PG_KEYWORD("include", INCLUDE, UNRESERVED_KEYWORD)
-PG_KEYWORD("including", INCLUDING, UNRESERVED_KEYWORD)
-PG_KEYWORD("increment", INCREMENT, UNRESERVED_KEYWORD)
-PG_KEYWORD("index", INDEX, UNRESERVED_KEYWORD)
-PG_KEYWORD("indexes", INDEXES, UNRESERVED_KEYWORD)
-PG_KEYWORD("inherit", INHERIT, UNRESERVED_KEYWORD)
-PG_KEYWORD("inherits", INHERITS, UNRESERVED_KEYWORD)
-PG_KEYWORD("initially", INITIALLY, RESERVED_KEYWORD)
-PG_KEYWORD("inline", INLINE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("inner", INNER_P, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("inout", INOUT, COL_NAME_KEYWORD)
-PG_KEYWORD("input", INPUT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("insensitive", INSENSITIVE, UNRESERVED_KEYWORD)
-PG_KEYWORD("insert", INSERT, UNRESERVED_KEYWORD)
-PG_KEYWORD("instead", INSTEAD, UNRESERVED_KEYWORD)
-PG_KEYWORD("int", INT_P, COL_NAME_KEYWORD)
-PG_KEYWORD("integer", INTEGER, COL_NAME_KEYWORD)
-PG_KEYWORD("intersect", INTERSECT, RESERVED_KEYWORD)
-PG_KEYWORD("interval", INTERVAL, COL_NAME_KEYWORD)
-PG_KEYWORD("into", INTO, RESERVED_KEYWORD)
-PG_KEYWORD("invoker", INVOKER, UNRESERVED_KEYWORD)
-PG_KEYWORD("is", IS, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("isnull", ISNULL, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("isolation", ISOLATION, UNRESERVED_KEYWORD)
-PG_KEYWORD("join", JOIN, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("key", KEY, UNRESERVED_KEYWORD)
-PG_KEYWORD("label", LABEL, UNRESERVED_KEYWORD)
-PG_KEYWORD("language", LANGUAGE, UNRESERVED_KEYWORD)
-PG_KEYWORD("large", LARGE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("last", LAST_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("lateral", LATERAL_P, RESERVED_KEYWORD)
-PG_KEYWORD("leading", LEADING, RESERVED_KEYWORD)
-PG_KEYWORD("leakproof", LEAKPROOF, UNRESERVED_KEYWORD)
-PG_KEYWORD("least", LEAST, COL_NAME_KEYWORD)
-PG_KEYWORD("left", LEFT, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("level", LEVEL, UNRESERVED_KEYWORD)
-PG_KEYWORD("like", LIKE, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("limit", LIMIT, RESERVED_KEYWORD)
-PG_KEYWORD("listen", LISTEN, UNRESERVED_KEYWORD)
-PG_KEYWORD("load", LOAD, UNRESERVED_KEYWORD)
-PG_KEYWORD("local", LOCAL, UNRESERVED_KEYWORD)
-PG_KEYWORD("localtime", LOCALTIME, RESERVED_KEYWORD)
-PG_KEYWORD("localtimestamp", LOCALTIMESTAMP, RESERVED_KEYWORD)
-PG_KEYWORD("location", LOCATION, UNRESERVED_KEYWORD)
-PG_KEYWORD("lock", LOCK_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("locked", LOCKED, UNRESERVED_KEYWORD)
-PG_KEYWORD("logged", LOGGED, UNRESERVED_KEYWORD)
-PG_KEYWORD("mapping", MAPPING, UNRESERVED_KEYWORD)
-PG_KEYWORD("match", MATCH, UNRESERVED_KEYWORD)
-PG_KEYWORD("materialized", MATERIALIZED, UNRESERVED_KEYWORD)
-PG_KEYWORD("maxvalue", MAXVALUE, UNRESERVED_KEYWORD)
-PG_KEYWORD("method", METHOD, UNRESERVED_KEYWORD)
-PG_KEYWORD("minute", MINUTE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("minvalue", MINVALUE, UNRESERVED_KEYWORD)
-PG_KEYWORD("mode", MODE, UNRESERVED_KEYWORD)
-PG_KEYWORD("month", MONTH_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("move", MOVE, UNRESERVED_KEYWORD)
-PG_KEYWORD("name", NAME_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("names", NAMES, UNRESERVED_KEYWORD)
-PG_KEYWORD("national", NATIONAL, COL_NAME_KEYWORD)
-PG_KEYWORD("natural", NATURAL, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("nchar", NCHAR, COL_NAME_KEYWORD)
-PG_KEYWORD("new", NEW, UNRESERVED_KEYWORD)
-PG_KEYWORD("next", NEXT, UNRESERVED_KEYWORD)
-PG_KEYWORD("nfc", NFC, UNRESERVED_KEYWORD)
-PG_KEYWORD("nfd", NFD, UNRESERVED_KEYWORD)
-PG_KEYWORD("nfkc", NFKC, UNRESERVED_KEYWORD)
-PG_KEYWORD("nfkd", NFKD, UNRESERVED_KEYWORD)
-PG_KEYWORD("no", NO, UNRESERVED_KEYWORD)
-PG_KEYWORD("none", NONE, COL_NAME_KEYWORD)
-PG_KEYWORD("normalize", NORMALIZE, COL_NAME_KEYWORD)
-PG_KEYWORD("normalized", NORMALIZED, UNRESERVED_KEYWORD)
-PG_KEYWORD("not", NOT, RESERVED_KEYWORD)
-PG_KEYWORD("nothing", NOTHING, UNRESERVED_KEYWORD)
-PG_KEYWORD("notify", NOTIFY, UNRESERVED_KEYWORD)
-PG_KEYWORD("notnull", NOTNULL, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("nowait", NOWAIT, UNRESERVED_KEYWORD)
-PG_KEYWORD("null", NULL_P, RESERVED_KEYWORD)
-PG_KEYWORD("nullif", NULLIF, COL_NAME_KEYWORD)
-PG_KEYWORD("nulls", NULLS_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("numeric", NUMERIC, COL_NAME_KEYWORD)
-PG_KEYWORD("object", OBJECT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("of", OF, UNRESERVED_KEYWORD)
-PG_KEYWORD("off", OFF, UNRESERVED_KEYWORD)
-PG_KEYWORD("offset", OFFSET, RESERVED_KEYWORD)
-PG_KEYWORD("oids", OIDS, UNRESERVED_KEYWORD)
-PG_KEYWORD("old", OLD, UNRESERVED_KEYWORD)
-PG_KEYWORD("on", ON, RESERVED_KEYWORD)
-PG_KEYWORD("only", ONLY, RESERVED_KEYWORD)
-PG_KEYWORD("operator", OPERATOR, UNRESERVED_KEYWORD)
-PG_KEYWORD("option", OPTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("options", OPTIONS, UNRESERVED_KEYWORD)
-PG_KEYWORD("or", OR, RESERVED_KEYWORD)
-PG_KEYWORD("order", ORDER, RESERVED_KEYWORD)
-PG_KEYWORD("ordinality", ORDINALITY, UNRESERVED_KEYWORD)
-PG_KEYWORD("others", OTHERS, UNRESERVED_KEYWORD)
-PG_KEYWORD("out", OUT_P, COL_NAME_KEYWORD)
-PG_KEYWORD("outer", OUTER_P, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("over", OVER, UNRESERVED_KEYWORD)
-PG_KEYWORD("overlaps", OVERLAPS, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("overlay", OVERLAY, COL_NAME_KEYWORD)
-PG_KEYWORD("overriding", OVERRIDING, UNRESERVED_KEYWORD)
-PG_KEYWORD("owned", OWNED, UNRESERVED_KEYWORD)
-PG_KEYWORD("owner", OWNER, UNRESERVED_KEYWORD)
-PG_KEYWORD("parallel", PARALLEL, UNRESERVED_KEYWORD)
-PG_KEYWORD("parser", PARSER, UNRESERVED_KEYWORD)
-PG_KEYWORD("partial", PARTIAL, UNRESERVED_KEYWORD)
-PG_KEYWORD("partition", PARTITION, UNRESERVED_KEYWORD)
-PG_KEYWORD("passing", PASSING, UNRESERVED_KEYWORD)
-PG_KEYWORD("password", PASSWORD, UNRESERVED_KEYWORD)
-PG_KEYWORD("placing", PLACING, RESERVED_KEYWORD)
-PG_KEYWORD("plans", PLANS, UNRESERVED_KEYWORD)
-PG_KEYWORD("policy", POLICY, UNRESERVED_KEYWORD)
-PG_KEYWORD("position", POSITION, COL_NAME_KEYWORD)
-PG_KEYWORD("preceding", PRECEDING, UNRESERVED_KEYWORD)
-PG_KEYWORD("precision", PRECISION, COL_NAME_KEYWORD)
-PG_KEYWORD("prepare", PREPARE, UNRESERVED_KEYWORD)
-PG_KEYWORD("prepared", PREPARED, UNRESERVED_KEYWORD)
-PG_KEYWORD("preserve", PRESERVE, UNRESERVED_KEYWORD)
-PG_KEYWORD("primary", PRIMARY, RESERVED_KEYWORD)
-PG_KEYWORD("prior", PRIOR, UNRESERVED_KEYWORD)
-PG_KEYWORD("privileges", PRIVILEGES, UNRESERVED_KEYWORD)
-PG_KEYWORD("procedural", PROCEDURAL, UNRESERVED_KEYWORD)
-PG_KEYWORD("procedure", PROCEDURE, UNRESERVED_KEYWORD)
-PG_KEYWORD("procedures", PROCEDURES, UNRESERVED_KEYWORD)
-PG_KEYWORD("program", PROGRAM, UNRESERVED_KEYWORD)
-PG_KEYWORD("publication", PUBLICATION, UNRESERVED_KEYWORD)
-PG_KEYWORD("quote", QUOTE, UNRESERVED_KEYWORD)
-PG_KEYWORD("range", RANGE, UNRESERVED_KEYWORD)
-PG_KEYWORD("read", READ, UNRESERVED_KEYWORD)
-PG_KEYWORD("real", REAL, COL_NAME_KEYWORD)
-PG_KEYWORD("reassign", REASSIGN, UNRESERVED_KEYWORD)
-PG_KEYWORD("recheck", RECHECK, UNRESERVED_KEYWORD)
-PG_KEYWORD("recursive", RECURSIVE, UNRESERVED_KEYWORD)
-PG_KEYWORD("ref", REF, UNRESERVED_KEYWORD)
-PG_KEYWORD("references", REFERENCES, RESERVED_KEYWORD)
-PG_KEYWORD("referencing", REFERENCING, UNRESERVED_KEYWORD)
-PG_KEYWORD("refresh", REFRESH, UNRESERVED_KEYWORD)
-PG_KEYWORD("reindex", REINDEX, UNRESERVED_KEYWORD)
-PG_KEYWORD("relative", RELATIVE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("release", RELEASE, UNRESERVED_KEYWORD)
-PG_KEYWORD("rename", RENAME, UNRESERVED_KEYWORD)
-PG_KEYWORD("repeatable", REPEATABLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("replace", REPLACE, UNRESERVED_KEYWORD)
-PG_KEYWORD("replica", REPLICA, UNRESERVED_KEYWORD)
-PG_KEYWORD("reset", RESET, UNRESERVED_KEYWORD)
-PG_KEYWORD("restart", RESTART, UNRESERVED_KEYWORD)
-PG_KEYWORD("restrict", RESTRICT, UNRESERVED_KEYWORD)
-PG_KEYWORD("returning", RETURNING, RESERVED_KEYWORD)
-PG_KEYWORD("returns", RETURNS, UNRESERVED_KEYWORD)
-PG_KEYWORD("revoke", REVOKE, UNRESERVED_KEYWORD)
-PG_KEYWORD("right", RIGHT, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("role", ROLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("rollback", ROLLBACK, UNRESERVED_KEYWORD)
-PG_KEYWORD("rollup", ROLLUP, UNRESERVED_KEYWORD)
-PG_KEYWORD("routine", ROUTINE, UNRESERVED_KEYWORD)
-PG_KEYWORD("routines", ROUTINES, UNRESERVED_KEYWORD)
-PG_KEYWORD("row", ROW, COL_NAME_KEYWORD)
-PG_KEYWORD("rows", ROWS, UNRESERVED_KEYWORD)
-PG_KEYWORD("rule", RULE, UNRESERVED_KEYWORD)
-PG_KEYWORD("savepoint", SAVEPOINT, UNRESERVED_KEYWORD)
-PG_KEYWORD("schema", SCHEMA, UNRESERVED_KEYWORD)
-PG_KEYWORD("schemas", SCHEMAS, UNRESERVED_KEYWORD)
-PG_KEYWORD("scroll", SCROLL, UNRESERVED_KEYWORD)
-PG_KEYWORD("search", SEARCH, UNRESERVED_KEYWORD)
-PG_KEYWORD("second", SECOND_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("security", SECURITY, UNRESERVED_KEYWORD)
-PG_KEYWORD("select", SELECT, RESERVED_KEYWORD)
-PG_KEYWORD("sequence", SEQUENCE, UNRESERVED_KEYWORD)
-PG_KEYWORD("sequences", SEQUENCES, UNRESERVED_KEYWORD)
-PG_KEYWORD("serializable", SERIALIZABLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("server", SERVER, UNRESERVED_KEYWORD)
-PG_KEYWORD("session", SESSION, UNRESERVED_KEYWORD)
-PG_KEYWORD("session_user", SESSION_USER, RESERVED_KEYWORD)
-PG_KEYWORD("set", SET, UNRESERVED_KEYWORD)
-PG_KEYWORD("setof", SETOF, COL_NAME_KEYWORD)
-PG_KEYWORD("sets", SETS, UNRESERVED_KEYWORD)
-PG_KEYWORD("share", SHARE, UNRESERVED_KEYWORD)
-PG_KEYWORD("show", SHOW, UNRESERVED_KEYWORD)
-PG_KEYWORD("similar", SIMILAR, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("simple", SIMPLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("skip", SKIP, UNRESERVED_KEYWORD)
-PG_KEYWORD("smallint", SMALLINT, COL_NAME_KEYWORD)
-PG_KEYWORD("snapshot", SNAPSHOT, UNRESERVED_KEYWORD)
-PG_KEYWORD("some", SOME, RESERVED_KEYWORD)
-PG_KEYWORD("sql", SQL_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("stable", STABLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("standalone", STANDALONE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("start", START, UNRESERVED_KEYWORD)
-PG_KEYWORD("statement", STATEMENT, UNRESERVED_KEYWORD)
-PG_KEYWORD("statistics", STATISTICS, UNRESERVED_KEYWORD)
-PG_KEYWORD("stdin", STDIN, UNRESERVED_KEYWORD)
-PG_KEYWORD("stdout", STDOUT, UNRESERVED_KEYWORD)
-PG_KEYWORD("storage", STORAGE, UNRESERVED_KEYWORD)
-PG_KEYWORD("stored", STORED, UNRESERVED_KEYWORD)
-PG_KEYWORD("strict", STRICT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("strip", STRIP_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("subscription", SUBSCRIPTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("substring", SUBSTRING, COL_NAME_KEYWORD)
-PG_KEYWORD("support", SUPPORT, UNRESERVED_KEYWORD)
-PG_KEYWORD("symmetric", SYMMETRIC, RESERVED_KEYWORD)
-PG_KEYWORD("sysid", SYSID, UNRESERVED_KEYWORD)
-PG_KEYWORD("system", SYSTEM_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("table", TABLE, RESERVED_KEYWORD)
-PG_KEYWORD("tables", TABLES, UNRESERVED_KEYWORD)
-PG_KEYWORD("tablesample", TABLESAMPLE, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("tablespace", TABLESPACE, UNRESERVED_KEYWORD)
-PG_KEYWORD("temp", TEMP, UNRESERVED_KEYWORD)
-PG_KEYWORD("template", TEMPLATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("temporary", TEMPORARY, UNRESERVED_KEYWORD)
-PG_KEYWORD("text", TEXT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("then", THEN, RESERVED_KEYWORD)
-PG_KEYWORD("ties", TIES, UNRESERVED_KEYWORD)
-PG_KEYWORD("time", TIME, COL_NAME_KEYWORD)
-PG_KEYWORD("timestamp", TIMESTAMP, COL_NAME_KEYWORD)
-PG_KEYWORD("to", TO, RESERVED_KEYWORD)
-PG_KEYWORD("trailing", TRAILING, RESERVED_KEYWORD)
-PG_KEYWORD("transaction", TRANSACTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("transform", TRANSFORM, UNRESERVED_KEYWORD)
-PG_KEYWORD("treat", TREAT, COL_NAME_KEYWORD)
-PG_KEYWORD("trigger", TRIGGER, UNRESERVED_KEYWORD)
-PG_KEYWORD("trim", TRIM, COL_NAME_KEYWORD)
-PG_KEYWORD("true", TRUE_P, RESERVED_KEYWORD)
-PG_KEYWORD("truncate", TRUNCATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("trusted", TRUSTED, UNRESERVED_KEYWORD)
-PG_KEYWORD("type", TYPE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("types", TYPES_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("uescape", UESCAPE, UNRESERVED_KEYWORD)
-PG_KEYWORD("unbounded", UNBOUNDED, UNRESERVED_KEYWORD)
-PG_KEYWORD("uncommitted", UNCOMMITTED, UNRESERVED_KEYWORD)
-PG_KEYWORD("unencrypted", UNENCRYPTED, UNRESERVED_KEYWORD)
-PG_KEYWORD("union", UNION, RESERVED_KEYWORD)
-PG_KEYWORD("unique", UNIQUE, RESERVED_KEYWORD)
-PG_KEYWORD("unknown", UNKNOWN, UNRESERVED_KEYWORD)
-PG_KEYWORD("unlisten", UNLISTEN, UNRESERVED_KEYWORD)
-PG_KEYWORD("unlogged", UNLOGGED, UNRESERVED_KEYWORD)
-PG_KEYWORD("until", UNTIL, UNRESERVED_KEYWORD)
-PG_KEYWORD("update", UPDATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("user", USER, RESERVED_KEYWORD)
-PG_KEYWORD("using", USING, RESERVED_KEYWORD)
-PG_KEYWORD("vacuum", VACUUM, UNRESERVED_KEYWORD)
-PG_KEYWORD("valid", VALID, UNRESERVED_KEYWORD)
-PG_KEYWORD("validate", VALIDATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("validator", VALIDATOR, UNRESERVED_KEYWORD)
-PG_KEYWORD("value", VALUE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("values", VALUES, COL_NAME_KEYWORD)
-PG_KEYWORD("varchar", VARCHAR, COL_NAME_KEYWORD)
-PG_KEYWORD("variadic", VARIADIC, RESERVED_KEYWORD)
-PG_KEYWORD("varying", VARYING, UNRESERVED_KEYWORD)
-PG_KEYWORD("verbose", VERBOSE, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("version", VERSION_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("view", VIEW, UNRESERVED_KEYWORD)
-PG_KEYWORD("views", VIEWS, UNRESERVED_KEYWORD)
-PG_KEYWORD("volatile", VOLATILE, UNRESERVED_KEYWORD)
-PG_KEYWORD("when", WHEN, RESERVED_KEYWORD)
-PG_KEYWORD("where", WHERE, RESERVED_KEYWORD)
-PG_KEYWORD("whitespace", WHITESPACE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("window", WINDOW, RESERVED_KEYWORD)
-PG_KEYWORD("with", WITH, RESERVED_KEYWORD)
-PG_KEYWORD("within", WITHIN, UNRESERVED_KEYWORD)
-PG_KEYWORD("without", WITHOUT, UNRESERVED_KEYWORD)
-PG_KEYWORD("work", WORK, UNRESERVED_KEYWORD)
-PG_KEYWORD("wrapper", WRAPPER, UNRESERVED_KEYWORD)
-PG_KEYWORD("write", WRITE, UNRESERVED_KEYWORD)
-PG_KEYWORD("xml", XML_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("xmlattributes", XMLATTRIBUTES, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlconcat", XMLCONCAT, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlelement", XMLELEMENT, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlexists", XMLEXISTS, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlforest", XMLFOREST, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlnamespaces", XMLNAMESPACES, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlparse", XMLPARSE, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlpi", XMLPI, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlroot", XMLROOT, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlserialize", XMLSERIALIZE, COL_NAME_KEYWORD)
-PG_KEYWORD("xmltable", XMLTABLE, COL_NAME_KEYWORD)
-PG_KEYWORD("year", YEAR_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("yes", YES_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("zone", ZONE, UNRESERVED_KEYWORD)
+/* name, value, category, aliastype */
+PG_KEYWORD("abort", ABORT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("absolute", ABSOLUTE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("access", ACCESS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("action", ACTION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("add", ADD_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("admin", ADMIN, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("after", AFTER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("aggregate", AGGREGATE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("all", ALL, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("also", ALSO, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("alter", ALTER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("always", ALWAYS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("analyse", ANALYSE, RESERVED_KEYWORD, IMPLICIT_ALIAS)		/* British spelling */
+PG_KEYWORD("analyze", ANALYZE, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("and", AND, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("any", ANY, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("array", ARRAY, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("as", AS, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("asc", ASC, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("assertion", ASSERTION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("assignment", ASSIGNMENT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("asymmetric", ASYMMETRIC, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("at", AT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("attach", ATTACH, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("attribute", ATTRIBUTE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("authorization", AUTHORIZATION, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("backward", BACKWARD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("before", BEFORE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("begin", BEGIN_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("between", BETWEEN, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("bigint", BIGINT, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("binary", BINARY, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("bit", BIT, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("boolean", BOOLEAN_P, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("both", BOTH, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("by", BY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("cache", CACHE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("call", CALL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("called", CALLED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("cascade", CASCADE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("cascaded", CASCADED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("case", CASE, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("cast", CAST, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("catalog", CATALOG_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("chain", CHAIN, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("char", CHAR_P, COL_NAME_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("character", CHARACTER, COL_NAME_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("characteristics", CHARACTERISTICS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("check", CHECK, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("checkpoint", CHECKPOINT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("class", CLASS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("close", CLOSE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("cluster", CLUSTER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("coalesce", COALESCE, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("collate", COLLATE, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("collation", COLLATION, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("column", COLUMN, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("columns", COLUMNS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("comment", COMMENT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("comments", COMMENTS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("commit", COMMIT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("committed", COMMITTED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("concurrently", CONCURRENTLY, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("configuration", CONFIGURATION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("conflict", CONFLICT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("connection", CONNECTION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("constraint", CONSTRAINT, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("constraints", CONSTRAINTS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("content", CONTENT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("continue", CONTINUE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("conversion", CONVERSION_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("copy", COPY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("cost", COST, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("create", CREATE, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("cross", CROSS, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("csv", CSV, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("cube", CUBE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("current", CURRENT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("current_catalog", CURRENT_CATALOG, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("current_date", CURRENT_DATE, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("current_role", CURRENT_ROLE, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("current_schema", CURRENT_SCHEMA, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("current_time", CURRENT_TIME, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("current_timestamp", CURRENT_TIMESTAMP, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("current_user", CURRENT_USER, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("cursor", CURSOR, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("cycle", CYCLE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("data", DATA_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("database", DATABASE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("day", DAY_P, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("deallocate", DEALLOCATE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("dec", DEC, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("decimal", DECIMAL_P, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("declare", DECLARE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("default", DEFAULT, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("defaults", DEFAULTS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("deferrable", DEFERRABLE, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("deferred", DEFERRED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("definer", DEFINER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("delete", DELETE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("delimiter", DELIMITER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("delimiters", DELIMITERS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("depends", DEPENDS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("desc", DESC, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("detach", DETACH, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("dictionary", DICTIONARY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("disable", DISABLE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("discard", DISCARD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("distinct", DISTINCT, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("do", DO, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("document", DOCUMENT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("domain", DOMAIN_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("double", DOUBLE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("drop", DROP, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("each", EACH, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("else", ELSE, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("enable", ENABLE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("encoding", ENCODING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("encrypted", ENCRYPTED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("end", END_P, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("enum", ENUM_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("escape", ESCAPE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("event", EVENT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("except", EXCEPT, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("exclude", EXCLUDE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("excluding", EXCLUDING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("exclusive", EXCLUSIVE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("execute", EXECUTE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("exists", EXISTS, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("explain", EXPLAIN, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("expression", EXPRESSION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("extension", EXTENSION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("external", EXTERNAL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("extract", EXTRACT, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("false", FALSE_P, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("family", FAMILY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("fetch", FETCH, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("filter", FILTER, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("first", FIRST_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("float", FLOAT_P, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("following", FOLLOWING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("for", FOR, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("force", FORCE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("foreign", FOREIGN, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("forward", FORWARD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("freeze", FREEZE, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("from", FROM, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("full", FULL, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("function", FUNCTION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("functions", FUNCTIONS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("generated", GENERATED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("global", GLOBAL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("grant", GRANT, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("granted", GRANTED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("greatest", GREATEST, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("group", GROUP_P, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("grouping", GROUPING, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("groups", GROUPS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("handler", HANDLER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("having", HAVING, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("header", HEADER_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("hold", HOLD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("hour", HOUR_P, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("identity", IDENTITY_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("if", IF_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("ilike", ILIKE, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("immediate", IMMEDIATE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("immutable", IMMUTABLE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("implicit", IMPLICIT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("import", IMPORT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("in", IN_P, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("include", INCLUDE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("including", INCLUDING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("increment", INCREMENT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("index", INDEX, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("indexes", INDEXES, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("inherit", INHERIT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("inherits", INHERITS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("initially", INITIALLY, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("inline", INLINE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("inner", INNER_P, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("inout", INOUT, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("input", INPUT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("insensitive", INSENSITIVE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("insert", INSERT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("instead", INSTEAD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("int", INT_P, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("integer", INTEGER, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("intersect", INTERSECT, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("interval", INTERVAL, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("into", INTO, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("invoker", INVOKER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("is", IS, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("isnull", ISNULL, TYPE_FUNC_NAME_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("isolation", ISOLATION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("join", JOIN, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("key", KEY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("label", LABEL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("language", LANGUAGE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("large", LARGE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("last", LAST_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("lateral", LATERAL_P, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("leading", LEADING, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("leakproof", LEAKPROOF, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("least", LEAST, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("left", LEFT, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("level", LEVEL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("like", LIKE, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("limit", LIMIT, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("listen", LISTEN, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("load", LOAD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("local", LOCAL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("localtime", LOCALTIME, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("localtimestamp", LOCALTIMESTAMP, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("location", LOCATION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("lock", LOCK_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("locked", LOCKED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("logged", LOGGED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("mapping", MAPPING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("match", MATCH, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("materialized", MATERIALIZED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("maxvalue", MAXVALUE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("method", METHOD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("minute", MINUTE_P, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("minvalue", MINVALUE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("mode", MODE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("month", MONTH_P, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("move", MOVE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("name", NAME_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("names", NAMES, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("national", NATIONAL, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("natural", NATURAL, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("nchar", NCHAR, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("new", NEW, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("next", NEXT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("nfc", NFC, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("nfd", NFD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("nfkc", NFKC, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("nfkd", NFKD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("no", NO, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("none", NONE, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("normalize", NORMALIZE, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("normalized", NORMALIZED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("not", NOT, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("nothing", NOTHING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("notify", NOTIFY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("notnull", NOTNULL, TYPE_FUNC_NAME_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("nowait", NOWAIT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("null", NULL_P, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("nullif", NULLIF, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("nulls", NULLS_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("numeric", NUMERIC, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("object", OBJECT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("of", OF, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("off", OFF, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("offset", OFFSET, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("oids", OIDS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("old", OLD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("on", ON, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("only", ONLY, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("operator", OPERATOR, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("option", OPTION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("options", OPTIONS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("or", OR, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("order", ORDER, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("ordinality", ORDINALITY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("others", OTHERS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("out", OUT_P, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("outer", OUTER_P, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("over", OVER, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("overlaps", OVERLAPS, TYPE_FUNC_NAME_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("overlay", OVERLAY, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("overriding", OVERRIDING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("owned", OWNED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("owner", OWNER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("parallel", PARALLEL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("parser", PARSER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("partial", PARTIAL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("partition", PARTITION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("passing", PASSING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("password", PASSWORD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("placing", PLACING, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("plans", PLANS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("policy", POLICY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("position", POSITION, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("preceding", PRECEDING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("precision", PRECISION, COL_NAME_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("prepare", PREPARE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("prepared", PREPARED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("preserve", PRESERVE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("primary", PRIMARY, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("prior", PRIOR, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("privileges", PRIVILEGES, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("procedural", PROCEDURAL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("procedure", PROCEDURE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("procedures", PROCEDURES, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("program", PROGRAM, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("publication", PUBLICATION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("quote", QUOTE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("range", RANGE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("read", READ, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("real", REAL, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("reassign", REASSIGN, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("recheck", RECHECK, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("recursive", RECURSIVE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("ref", REF, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("references", REFERENCES, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("referencing", REFERENCING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("refresh", REFRESH, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("reindex", REINDEX, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("relative", RELATIVE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("release", RELEASE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("rename", RENAME, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("repeatable", REPEATABLE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("replace", REPLACE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("replica", REPLICA, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("reset", RESET, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("restart", RESTART, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("restrict", RESTRICT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("returning", RETURNING, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("returns", RETURNS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("revoke", REVOKE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("right", RIGHT, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("role", ROLE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("rollback", ROLLBACK, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("rollup", ROLLUP, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("routine", ROUTINE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("routines", ROUTINES, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("row", ROW, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("rows", ROWS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("rule", RULE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("savepoint", SAVEPOINT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("schema", SCHEMA, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("schemas", SCHEMAS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("scroll", SCROLL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("search", SEARCH, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("second", SECOND_P, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("security", SECURITY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("select", SELECT, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("sequence", SEQUENCE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("sequences", SEQUENCES, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("serializable", SERIALIZABLE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("server", SERVER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("session", SESSION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("session_user", SESSION_USER, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("set", SET, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("setof", SETOF, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("sets", SETS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("share", SHARE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("show", SHOW, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("similar", SIMILAR, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("simple", SIMPLE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("skip", SKIP, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("smallint", SMALLINT, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("snapshot", SNAPSHOT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("some", SOME, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("sql", SQL_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("stable", STABLE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("standalone", STANDALONE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("start", START, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("statement", STATEMENT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("statistics", STATISTICS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("stdin", STDIN, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("stdout", STDOUT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("storage", STORAGE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("stored", STORED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("strict", STRICT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("strip", STRIP_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("subscription", SUBSCRIPTION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("substring", SUBSTRING, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("support", SUPPORT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("symmetric", SYMMETRIC, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("sysid", SYSID, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("system", SYSTEM_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("table", TABLE, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("tables", TABLES, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("tablesample", TABLESAMPLE, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("tablespace", TABLESPACE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("temp", TEMP, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("template", TEMPLATE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("temporary", TEMPORARY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("text", TEXT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("then", THEN, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("ties", TIES, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("time", TIME, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("timestamp", TIMESTAMP, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("to", TO, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("trailing", TRAILING, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("transaction", TRANSACTION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("transform", TRANSFORM, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("treat", TREAT, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("trigger", TRIGGER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("trim", TRIM, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("true", TRUE_P, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("truncate", TRUNCATE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("trusted", TRUSTED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("type", TYPE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("types", TYPES_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("uescape", UESCAPE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("unbounded", UNBOUNDED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("uncommitted", UNCOMMITTED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("unencrypted", UNENCRYPTED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("union", UNION, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("unique", UNIQUE, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("unknown", UNKNOWN, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("unlisten", UNLISTEN, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("unlogged", UNLOGGED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("until", UNTIL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("update", UPDATE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("user", USER, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("using", USING, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("vacuum", VACUUM, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("valid", VALID, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("validate", VALIDATE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("validator", VALIDATOR, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("value", VALUE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("values", VALUES, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("varchar", VARCHAR, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("variadic", VARIADIC, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("varying", VARYING, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("verbose", VERBOSE, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("version", VERSION_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("view", VIEW, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("views", VIEWS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("volatile", VOLATILE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("when", WHEN, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("where", WHERE, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("whitespace", WHITESPACE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("window", WINDOW, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("with", WITH, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("within", WITHIN, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("without", WITHOUT, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("work", WORK, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("wrapper", WRAPPER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("write", WRITE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xml", XML_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlattributes", XMLATTRIBUTES, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlconcat", XMLCONCAT, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlelement", XMLELEMENT, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlexists", XMLEXISTS, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlforest", XMLFOREST, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlnamespaces", XMLNAMESPACES, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlparse", XMLPARSE, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlpi", XMLPI, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlroot", XMLROOT, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlserialize", XMLSERIALIZE, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmltable", XMLTABLE, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("year", YEAR_P, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("yes", YES_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("zone", ZONE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
diff --git a/src/interfaces/ecpg/preproc/keywords.c b/src/interfaces/ecpg/preproc/keywords.c
index f82764aeb9..624b8bfe60 100644
--- a/src/interfaces/ecpg/preproc/keywords.c
+++ b/src/interfaces/ecpg/preproc/keywords.c
@@ -29,7 +29,7 @@
 #include "preproc_extern.h"
 #include "preproc.h"
 
-#define PG_KEYWORD(kwname, value, category) value,
+#define PG_KEYWORD(kwname, value, category, aliastype) value,
 
 const uint16 SQLScanKeywordTokens[] = {
 #include "parser/kwlist.h"
diff --git a/src/tools/gen_keywordlist.pl b/src/tools/gen_keywordlist.pl
index e9250b8fb2..ad433d416e 100644
--- a/src/tools/gen_keywordlist.pl
+++ b/src/tools/gen_keywordlist.pl
@@ -93,11 +93,27 @@ EOM
 
 # Parse input file for keyword names.
 my @keywords;
+my @implicit_alias;
+my %transform = ( IMPLICIT_ALIAS => 'true', EXPLICIT_ALIAS => 'false');
 while (<$kif>)
 {
 	if (/^PG_KEYWORD\("(\w+)"/)
 	{
-		push @keywords, $1;
+		my $kword = $1;
+		push @keywords, $kword;
+
+		if (/^PG_KEYWORD\("\w+", .*, (IMPLICIT_ALIAS|EXPLICIT_ALIAS)\)/)
+		{
+			push @implicit_alias, $transform{$1};
+		}
+		else
+		{
+			# parser/kwlist.h lists each keyword as either an implicit or an
+			# explicit alias, but other kwlist files do not, and for them, it
+			# won't matter what we use here as long as it is a valid boolean,
+			# so we arbitrarily use 'true'.
+			push @implicit_alias, 'true';
+		}
 	}
 }
 
@@ -153,6 +169,17 @@ foreach my $name (@keywords)
 
 print $kwdef "};\n\n";
 
+# Emit an array of boolean as implicit alias values
+
+printf $kwdef "static const bool %s_kw_is_implicit[] = {\n", $varname;
+
+foreach my $bool (@implicit_alias)
+{
+	print $kwdef "\t$bool,\n";
+}
+
+print $kwdef "};\n\n";
+
 # Emit a macro defining the number of keywords.
 # (In some places it's useful to have access to that as a constant.)
 
@@ -173,6 +200,7 @@ printf $kwdef "static " if !$extern;
 printf $kwdef "const ScanKeywordList %s = {\n", $varname;
 printf $kwdef qq|\t%s_kw_string,\n|,            $varname;
 printf $kwdef qq|\t%s_kw_offsets,\n|,           $varname;
+printf $kwdef qq|\t%s_kw_is_implicit,\n|,       $varname;
 printf $kwdef qq|\t%s,\n|,                      $funcname;
 printf $kwdef qq|\t%s_NUM_KEYWORDS,\n|,         uc $varname;
 printf $kwdef qq|\t%d\n|,                       $max_len;
-- 
2.21.1 (Apple Git-122.3)

v6-0003-Updating-prorows-for-pg_get_keywords.patchapplication/octet-stream; name=v6-0003-Updating-prorows-for-pg_get_keywords.patch; x-unix-mode=0644Download
From 3ad53c74182930a58ba0840918e21854595f9842 Mon Sep 17 00:00:00 2001
From: Mark Dilger <mark.dilger@enterprisedb.com>
Date: Mon, 31 Aug 2020 14:53:01 -0700
Subject: [PATCH v6 3/3] Updating prorows for pg_get_keywords()

The number of keywords returned by pg_get_keywords() is known
precisely.  It happens to be 450 as of this commit.  It might slowly
change with future commits, but it is not 400 as pg_proc.dat was
claiming, and there does not seem to be any advantage to leaving it
at 400.

Nothing in this patch series depends on this one patch being committed.
If the committer who picks up this patch series wants to just throw
this third patch file away, that works fine.
---
 src/include/catalog/pg_proc.dat | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index b4c4fe8a5c..8fdbd75ad1 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -3675,7 +3675,7 @@
   prosrc => 'pg_get_function_arg_default' },
 
 { oid => '1686', descr => 'list of SQL keywords',
-  proname => 'pg_get_keywords', procost => '10', prorows => '400',
+  proname => 'pg_get_keywords', procost => '10', prorows => '450',
   proretset => 't', provolatile => 's', prorettype => 'record',
   proargtypes => '', proallargtypes => '{text,char,text,text}',
   proargmodes => '{o,o,o,o}', proargnames => '{word,catcode,catdesc,aliastype}',
-- 
2.21.1 (Apple Git-122.3)

#53John Naylor
john.naylor@2ndquadrant.com
In reply to: Mark Dilger (#52)
Re: factorial function/phase out postfix operators?

On Tue, Sep 1, 2020 at 10:00 PM Mark Dilger
<mark.dilger@enterprisedb.com> wrote:

Some changes were made on another thread [1] for the deprecation notices, committed recently by Tom, and I think this patch set is compatible with what was done there. This patch set is intended for commit against master, targeted for PostgreSQL 14, so the deprecation notices are removed along with the things that were deprecated. The references to right-unary operators that you call out, above, have been removed.

Hi Mark,

Looks good. Just a couple things I found in 0001:

The factorial operators should now be removed from func.sgml.

For pg_dump, should we issue a pg_log_warning() (or stronger)
somewhere if user-defined postfix operators are found? I'm looking at
the example of "WITH OIDS" in pg_dump.c.

Nitpick: these can be removed, since we already test factorial() in this file:

-SELECT 4!;
-SELECT !!3;
+SELECT factorial(4);
+SELECT factorial(3);

--
John Naylor https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

#54Mark Dilger
mark.dilger@enterprisedb.com
In reply to: John Naylor (#53)
3 attachment(s)
Re: factorial function/phase out postfix operators?

On Sep 2, 2020, at 1:33 AM, John Naylor <john.naylor@2ndquadrant.com> wrote:

On Tue, Sep 1, 2020 at 10:00 PM Mark Dilger
<mark.dilger@enterprisedb.com> wrote:

Some changes were made on another thread [1] for the deprecation notices, committed recently by Tom, and I think this patch set is compatible with what was done there. This patch set is intended for commit against master, targeted for PostgreSQL 14, so the deprecation notices are removed along with the things that were deprecated. The references to right-unary operators that you call out, above, have been removed.

Hi Mark,

Looks good. Just a couple things I found in 0001:

The factorial operators should now be removed from func.sgml.

Right you are. Removed in v7.

For pg_dump, should we issue a pg_log_warning() (or stronger)
somewhere if user-defined postfix operators are found? I'm looking at
the example of "WITH OIDS" in pg_dump.c.

Since newer pg_dump binaries can be used to dump data from older servers, and since users might then load that dump back into an older server, I think doing anything stronger than a pg_log_warning() would be incorrect. I did not find precedents under comparable circumstances for taking stronger actions than pg_log_warning. I assume we can't, for example, omit the operator from the dump, nor can we abort the process.

A pg_log_warning has been added in v7.

Dumping right-unary (postfix) operators should work (with a warning) in v7. I think pg_dump in v6 was broken in this regard.

Nitpick: these can be removed, since we already test factorial() in this file:

-SELECT 4!;
-SELECT !!3;
+SELECT factorial(4);
+SELECT factorial(3);

I was on the fence between removing those (as you suggest) vs. converting them to function calls (as v6 did). They are removed in v7.

Attachments:

v7-0001-Removing-postfix-operator-support.patchapplication/octet-stream; name=v7-0001-Removing-postfix-operator-support.patch; x-unix-mode=0644Download
From 8c730c6b51a0d39762b5518b17c0a77e41a1e403 Mon Sep 17 00:00:00 2001
From: Mark Dilger <mark.dilger@enterprisedb.com>
Date: Wed, 2 Sep 2020 07:43:27 -0700
Subject: [PATCH v7 1/3] Removing postfix operator support.

Removing postfix operator support from the grammar; disallowing
the creation of postfix operators through the CREATE OPERATOR
command; and removing the factorial prefix and postfix operators.

In the commit message for 6ca547cf75ef6e922476c51a3fb5e253eef5f1b6,
Tom Lane wrote:

    There is only one built-in postfix operator, ! for factorial.
    Label it deprecated in the docs and in pg_description, and
    adjust some examples that formerly relied on it.  (The sister
    prefix operator !! is also deprecated.  We don't really have to
    remove that one, but since we're suggesting that people use
    factorial() instead, it seems better to remove both operators.)

In the spirit of that message, this patch also removes the !!
factorial prefix operator, even though it is not strongly connected
with the rest of what this commit does.

This accomplishes nothing useful in itself, but sets up for grammar
changes to allow keywords to be used as bare column aliases without
the use of an explicit "AS".
---
 contrib/postgres_fdw/deparse.c                |   5 +-
 .../postgres_fdw/expected/postgres_fdw.out    |   8 --
 contrib/postgres_fdw/sql/postgres_fdw.sql     |   1 -
 doc/src/sgml/catalogs.sgml                    |   2 +-
 doc/src/sgml/func.sgml                        |  30 -----
 doc/src/sgml/ref/alter_extension.sgml         |   2 +-
 doc/src/sgml/ref/alter_opfamily.sgml          |   2 +-
 doc/src/sgml/ref/comment.sgml                 |   2 +-
 doc/src/sgml/ref/create_opclass.sgml          |   2 +-
 doc/src/sgml/ref/create_operator.sgml         |  20 +--
 doc/src/sgml/ref/drop_operator.sgml           |   7 -
 doc/src/sgml/syntax.sgml                      |   3 +-
 doc/src/sgml/typeconv.sgml                    |   2 +-
 doc/src/sgml/xoper.sgml                       |  12 +-
 src/backend/catalog/namespace.c               |   7 +-
 src/backend/catalog/pg_operator.c             |   4 +-
 src/backend/commands/operatorcmds.c           |  14 +-
 src/backend/nodes/print.c                     |   1 -
 src/backend/parser/gram.y                     |  30 ++---
 src/backend/parser/parse_expr.c               |  48 ++-----
 src/backend/parser/parse_oper.c               | 121 +++---------------
 src/backend/utils/adt/ruleutils.c             |  31 ++---
 src/bin/pg_dump/pg_dump.c                     |   5 +
 src/bin/pg_dump/pg_dump_sort.c                |   2 +-
 src/bin/pg_upgrade/check.c                    | 106 +++++++++++++++
 src/bin/psql/describe.c                       |   2 +-
 src/include/catalog/pg_operator.dat           |   6 -
 src/include/catalog/pg_operator.h             |   4 +-
 src/include/catalog/pg_proc.dat               |   4 -
 src/test/regress/expected/create_operator.out |  33 +++--
 src/test/regress/expected/numeric.out         |  35 +++--
 src/test/regress/expected/opr_sanity.out      |  17 +--
 src/test/regress/sql/create_operator.sql      |  15 ++-
 src/test/regress/sql/numeric.sql              |  13 +-
 src/test/regress/sql/opr_sanity.sql           |  14 +-
 src/tutorial/complex.source                   |   2 +-
 src/tutorial/syscat.source                    |  14 --
 37 files changed, 257 insertions(+), 369 deletions(-)

diff --git a/contrib/postgres_fdw/deparse.c b/contrib/postgres_fdw/deparse.c
index ad37a74221..32a9b38f10 100644
--- a/contrib/postgres_fdw/deparse.c
+++ b/contrib/postgres_fdw/deparse.c
@@ -2716,15 +2716,14 @@ deparseOpExpr(OpExpr *node, deparse_expr_cxt *context)
 	oprkind = form->oprkind;
 
 	/* Sanity check. */
-	Assert((oprkind == 'r' && list_length(node->args) == 1) ||
-		   (oprkind == 'l' && list_length(node->args) == 1) ||
+	Assert((oprkind == 'l' && list_length(node->args) == 1) ||
 		   (oprkind == 'b' && list_length(node->args) == 2));
 
 	/* Always parenthesize the expression. */
 	appendStringInfoChar(buf, '(');
 
 	/* Deparse left operand. */
-	if (oprkind == 'r' || oprkind == 'b')
+	if (oprkind == 'b')
 	{
 		arg = list_head(node->args);
 		deparseExpr(lfirst(arg), context);
diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index 90db550b92..cae90b45e2 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -653,14 +653,6 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 = -c1;          -- Op
    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = (- "C 1")))
 (3 rows)
 
-EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE 1 = c1!;           -- OpExpr(r)
-                                                QUERY PLAN                                                
-----------------------------------------------------------------------------------------------------------
- Foreign Scan on public.ft1 t1
-   Output: c1, c2, c3, c4, c5, c6, c7, c8
-   Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE ((1::numeric = ("C 1" !)))
-(3 rows)
-
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE (c1 IS NOT NULL) IS DISTINCT FROM (c1 IS NOT NULL); -- DistinctExpr
                                                                  QUERY PLAN                                                                 
 --------------------------------------------------------------------------------------------------------------------------------------------
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index 83971665e3..bbad5b6ec2 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -307,7 +307,6 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 IS NULL;        -- Nu
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 IS NOT NULL;    -- NullTest
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE round(abs(c1), 0) = 1; -- FuncExpr
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 = -c1;          -- OpExpr(l)
-EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE 1 = c1!;           -- OpExpr(r)
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE (c1 IS NOT NULL) IS DISTINCT FROM (c1 IS NOT NULL); -- DistinctExpr
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 = ANY(ARRAY[c2, 1, c1 + 0]); -- ScalarArrayOpExpr
 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 = (ARRAY[c1,c2,3])[1]; -- SubscriptingRef
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 1d1b8ce8fb..39eee9d1e2 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -5154,7 +5154,7 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
       </para>
       <para>
        <literal>b</literal> = infix (<quote>both</quote>), <literal>l</literal> = prefix
-       (<quote>left</quote>), <literal>r</literal> = postfix (<quote>right</quote>)
+       (<quote>left</quote>)
       </para></entry>
      </row>
 
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 2efd80baa4..8888bc73c9 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -1048,36 +1048,6 @@ repeat('Pg', 4) <returnvalue>PgPgPgPg</returnvalue>
        </para></entry>
       </row>
 
-      <row>
-       <entry role="func_table_entry"><para role="func_signature">
-        <type>bigint</type> <literal>!</literal>
-        <returnvalue>numeric</returnvalue>
-       </para>
-       <para>
-        Factorial
-        (deprecated, use <link linkend="function-factorial"><function>factorial()</function></link> instead)
-       </para>
-       <para>
-        <literal>5 !</literal>
-        <returnvalue>120</returnvalue>
-       </para></entry>
-      </row>
-
-      <row>
-       <entry role="func_table_entry"><para role="func_signature">
-        <literal>!!</literal> <type>bigint</type>
-        <returnvalue>numeric</returnvalue>
-       </para>
-       <para>
-        Factorial as a prefix operator
-        (deprecated, use <link linkend="function-factorial"><function>factorial()</function></link> instead)
-       </para>
-       <para>
-        <literal>!! 5</literal>
-        <returnvalue>120</returnvalue>
-       </para></entry>
-      </row>
-
       <row>
        <entry role="func_table_entry"><para role="func_signature">
         <literal>@</literal> <replaceable>numeric_type</replaceable>
diff --git a/doc/src/sgml/ref/alter_extension.sgml b/doc/src/sgml/ref/alter_extension.sgml
index a2d405d6cd..c819c7bb4e 100644
--- a/doc/src/sgml/ref/alter_extension.sgml
+++ b/doc/src/sgml/ref/alter_extension.sgml
@@ -251,7 +251,7 @@ ALTER EXTENSION <replaceable class="parameter">name</replaceable> DROP <replacea
       <para>
        The data type(s) of the operator's arguments (optionally
        schema-qualified).  Write <literal>NONE</literal> for the missing argument
-       of a prefix or postfix operator.
+       of a prefix operator.
       </para>
      </listitem>
     </varlistentry>
diff --git a/doc/src/sgml/ref/alter_opfamily.sgml b/doc/src/sgml/ref/alter_opfamily.sgml
index 4ac1cca95a..c86507edac 100644
--- a/doc/src/sgml/ref/alter_opfamily.sgml
+++ b/doc/src/sgml/ref/alter_opfamily.sgml
@@ -141,7 +141,7 @@ ALTER OPERATOR FAMILY <replaceable>name</replaceable> USING <replaceable class="
      <para>
       In an <literal>OPERATOR</literal> clause,
       the operand data type(s) of the operator, or <literal>NONE</literal> to
-      signify a left-unary or right-unary operator.  Unlike the comparable
+      signify a left-unary operator.  Unlike the comparable
       syntax in <command>CREATE OPERATOR CLASS</command>, the operand data types
       must always be specified.
      </para>
diff --git a/doc/src/sgml/ref/comment.sgml b/doc/src/sgml/ref/comment.sgml
index fd7492a255..6e8ced3eaf 100644
--- a/doc/src/sgml/ref/comment.sgml
+++ b/doc/src/sgml/ref/comment.sgml
@@ -224,7 +224,7 @@ COMMENT ON
      <para>
       The data type(s) of the operator's arguments (optionally
       schema-qualified).  Write <literal>NONE</literal> for the missing argument
-      of a prefix or postfix operator.
+      of a prefix operator.
      </para>
     </listitem>
    </varlistentry>
diff --git a/doc/src/sgml/ref/create_opclass.sgml b/doc/src/sgml/ref/create_opclass.sgml
index f42fb6494c..0f94b6ae3e 100644
--- a/doc/src/sgml/ref/create_opclass.sgml
+++ b/doc/src/sgml/ref/create_opclass.sgml
@@ -161,7 +161,7 @@ CREATE OPERATOR CLASS <replaceable class="parameter">name</replaceable> [ DEFAUL
      <para>
       In an <literal>OPERATOR</literal> clause,
       the operand data type(s) of the operator, or <literal>NONE</literal> to
-      signify a left-unary or right-unary operator.  The operand data
+      signify a left-unary operator.  The operand data
       types can be omitted in the normal case where they are the same
       as the operator class's data type.
      </para>
diff --git a/doc/src/sgml/ref/create_operator.sgml b/doc/src/sgml/ref/create_operator.sgml
index 66c34e0072..082494bd75 100644
--- a/doc/src/sgml/ref/create_operator.sgml
+++ b/doc/src/sgml/ref/create_operator.sgml
@@ -86,20 +86,9 @@ CREATE OPERATOR <replaceable>name</replaceable> (
   </para>
 
   <para>
-   At least one of <literal>LEFTARG</literal> and <literal>RIGHTARG</literal> must be defined.  For
-   binary operators, both must be defined. For right unary
-   operators, only <literal>LEFTARG</literal> should be defined, while for left
-   unary operators only <literal>RIGHTARG</literal> should be defined.
-  </para>
-
-  <note>
-   <para>
-    Right unary, also called postfix, operators are deprecated and will be
-    removed in <productname>PostgreSQL</productname> version 14.
-   </para>
-  </note>
-
-  <para>
+   For binary operators, both <literal>LEFTARG</literal> and
+   <literal>RIGHTARG</literal> must be defined.  For left unary operators only
+   <literal>RIGHTARG</literal> should be defined.
    The <replaceable class="parameter">function_name</replaceable>
    function must have been previously defined using <command>CREATE
    FUNCTION</command> and must be defined to accept the correct number
@@ -169,8 +158,7 @@ CREATE OPERATOR <replaceable>name</replaceable> (
       <term><replaceable class="parameter">right_type</replaceable></term>
       <listitem>
        <para>
-        The data type of the operator's right operand, if any.
-        This option would be omitted for a right-unary operator.
+        The data type of the operator's right operand.
        </para>
       </listitem>
      </varlistentry>
diff --git a/doc/src/sgml/ref/drop_operator.sgml b/doc/src/sgml/ref/drop_operator.sgml
index 2dff050ecf..3c8eecb53a 100644
--- a/doc/src/sgml/ref/drop_operator.sgml
+++ b/doc/src/sgml/ref/drop_operator.sgml
@@ -120,13 +120,6 @@ DROP OPERATOR ~ (none, bit);
 </programlisting>
   </para>
 
-  <para>
-   Remove the right unary factorial operator <literal>x!</literal>
-   for type <type>bigint</type>:
-<programlisting>
-DROP OPERATOR ! (bigint, none);
-</programlisting></para>
-
   <para>
    Remove multiple operators in one command:
 <programlisting>
diff --git a/doc/src/sgml/syntax.sgml b/doc/src/sgml/syntax.sgml
index b0ae5d2e12..abde93895a 100644
--- a/doc/src/sgml/syntax.sgml
+++ b/doc/src/sgml/syntax.sgml
@@ -1444,11 +1444,10 @@ $1.somecolumn
    </indexterm>
 
    <para>
-    There are three possible syntaxes for an operator invocation:
+    There are two possible syntaxes for an operator invocation:
     <simplelist>
      <member><replaceable>expression</replaceable> <replaceable>operator</replaceable> <replaceable>expression</replaceable> (binary infix operator)</member>
      <member><replaceable>operator</replaceable> <replaceable>expression</replaceable> (unary prefix operator)</member>
-     <member><replaceable>expression</replaceable> <replaceable>operator</replaceable> (unary postfix operator)</member>
     </simplelist>
     where the <replaceable>operator</replaceable> token follows the syntax
     rules of <xref linkend="sql-syntax-operators"/>, or is one of the
diff --git a/doc/src/sgml/typeconv.sgml b/doc/src/sgml/typeconv.sgml
index 98662fc91f..ef9e311342 100644
--- a/doc/src/sgml/typeconv.sgml
+++ b/doc/src/sgml/typeconv.sgml
@@ -97,7 +97,7 @@ Operators
 <listitem>
 <para>
 <productname>PostgreSQL</productname> allows expressions with
-prefix and postfix unary (one-argument) operators,
+prefix unary (one-argument) operators,
 as well as binary (two-argument) operators.  Like functions, operators can
 be overloaded, so the same problem of selecting the right operator
 exists.
diff --git a/doc/src/sgml/xoper.sgml b/doc/src/sgml/xoper.sgml
index 56b08491c9..585a8c958f 100644
--- a/doc/src/sgml/xoper.sgml
+++ b/doc/src/sgml/xoper.sgml
@@ -20,8 +20,8 @@
   </para>
 
   <para>
-   <productname>PostgreSQL</productname> supports left unary, right
-   unary, and binary operators.  Operators can be
+   <productname>PostgreSQL</productname> supports left unary
+   and binary operators.  Operators can be
    overloaded;<indexterm><primary>overloading</primary><secondary>operators</secondary></indexterm>
    that is, the same operator name can be used for different operators
    that have different numbers and types of operands.  When a query is
@@ -64,9 +64,9 @@ SELECT (a + b) AS c FROM test_complex;
   </para>
 
   <para>
-   We've shown how to create a binary operator here.  To create unary
-   operators, just omit one of <literal>leftarg</literal> (for left unary) or
-   <literal>rightarg</literal> (for right unary).  The <literal>function</literal>
+   We've shown how to create a binary operator here.  To create left unary
+   operators, just omit the <literal>leftarg</literal>.
+   The <literal>function</literal>
    clause and the argument clauses are the only required items in
    <command>CREATE OPERATOR</command>.  The <literal>commutator</literal>
    clause shown in the example is an optional hint to the query
@@ -202,7 +202,7 @@ SELECT (a + b) AS c FROM test_complex;
    <para>
     Unlike commutators, a pair of unary operators could validly be marked
     as each other's negators; that would mean (A x) equals NOT (B x)
-    for all x, or the equivalent for right unary operators.
+    for all x.
    </para>
 
    <para>
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index 0152e3869a..0c78ab8af7 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -1473,8 +1473,7 @@ FunctionIsVisible(Oid funcid)
  *		Given a possibly-qualified operator name and exact input datatypes,
  *		look up the operator.  Returns InvalidOid if not found.
  *
- * Pass oprleft = InvalidOid for a prefix op, oprright = InvalidOid for
- * a postfix op.
+ * Pass oprleft = InvalidOid for a prefix op.
  *
  * If the operator name is not schema-qualified, it is sought in the current
  * namespace search path.  If the name is schema-qualified and the given
@@ -1580,8 +1579,8 @@ OpernameGetOprid(List *names, Oid oprleft, Oid oprright)
  * namespace case, we arrange for entries in earlier namespaces to mask
  * identical entries in later namespaces.
  *
- * The returned items always have two args[] entries --- one or the other
- * will be InvalidOid for a prefix or postfix oprkind.  nargs is 2, too.
+ * The returned items always have two args[] entries --- one will be
+ * InvalidOid for a prefix oprkind.  nargs is 2, too.
  */
 FuncCandidateList
 OpernameGetCandidates(List *names, char oprkind, bool missing_schema_ok)
diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c
index 65a36be5ee..f817627d86 100644
--- a/src/backend/catalog/pg_operator.c
+++ b/src/backend/catalog/pg_operator.c
@@ -245,7 +245,7 @@ OperatorShellMake(const char *operatorName,
 	values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
 	values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
 	values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId());
-	values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');
+	values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? 'b' : 'l');
 	values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(false);
 	values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(false);
 	values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);
@@ -494,7 +494,7 @@ OperatorCreate(const char *operatorName,
 	values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
 	values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
 	values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId());
-	values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');
+	values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? 'b' : 'l');
 	values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(canMerge);
 	values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(canHash);
 	values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);
diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c
index bf23937849..b468c7701b 100644
--- a/src/backend/commands/operatorcmds.c
+++ b/src/backend/commands/operatorcmds.c
@@ -168,10 +168,22 @@ DefineOperator(List *names, List *parameters)
 	if (typeName2)
 		typeId2 = typenameTypeId(NULL, typeName2);
 
+	/*
+	 * If only the right argument is missing, the user is likely trying to
+	 * create a postfix operator, so give them a hint about why that does not
+	 * work.  But if both arguments are missing, do not mention postfix
+	 * operators, as the user most likely simply neglected to mention the
+	 * arguments.
+	 */
 	if (!OidIsValid(typeId1) && !OidIsValid(typeId2))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
-				 errmsg("at least one of leftarg or rightarg must be specified")));
+				 errmsg("operator arguments must be specified")));
+	if (!OidIsValid(typeId2))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+				 errmsg("operator right argument must be specified"),
+				 errhint("Postfix operators are not supported.")));
 
 	if (typeName1)
 	{
diff --git a/src/backend/nodes/print.c b/src/backend/nodes/print.c
index 42476724d8..970a2d4384 100644
--- a/src/backend/nodes/print.c
+++ b/src/backend/nodes/print.c
@@ -394,7 +394,6 @@ print_expr(const Node *expr, const List *rtable)
 		}
 		else
 		{
-			/* we print prefix and postfix ops the same... */
 			printf("%s ", ((opname != NULL) ? opname : "(invalid operator)"));
 			print_expr(get_leftop((const Expr *) e), rtable);
 		}
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index dbb47d4982..d8a607e29a 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -741,19 +741,14 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 %nonassoc	'<' '>' '=' LESS_EQUALS GREATER_EQUALS NOT_EQUALS
 %nonassoc	BETWEEN IN_P LIKE ILIKE SIMILAR NOT_LA
 %nonassoc	ESCAPE			/* ESCAPE must be just above LIKE/ILIKE/SIMILAR */
-%left		POSTFIXOP		/* dummy for postfix Op rules */
 /*
  * To support target_el without AS, we must give IDENT an explicit priority
- * between POSTFIXOP and Op.  We can safely assign the same priority to
- * various unreserved keywords as needed to resolve ambiguities (this can't
- * have any bad effects since obviously the keywords will still behave the
- * same as if they weren't keywords).  We need to do this:
+ * lower than Op.  We can safely assign the same priority to various
+ * unreserved keywords as needed to resolve ambiguities (this can't have any
+ * bad effects since obviously the keywords will still behave the same as if
+ * they weren't keywords).  We need to do this:
  * for PARTITION, RANGE, ROWS, GROUPS to support opt_existing_window_name;
- * for RANGE, ROWS, GROUPS so that they can follow a_expr without creating
- * postfix-operator problems;
  * for GENERATED so that it can follow b_expr;
- * and for NULL so that it can follow b_expr in ColQualList without creating
- * postfix-operator problems.
  *
  * To support CUBE and ROLLUP in GROUP BY without reserving them, we give them
  * an explicit priority lower than '(', so that a rule with CUBE '(' will shift
@@ -7993,7 +7988,12 @@ oper_argtypes:
 			| '(' NONE ',' Typename ')'					/* left unary */
 					{ $$ = list_make2(NULL, $4); }
 			| '(' Typename ',' NONE ')'					/* right unary */
-					{ $$ = list_make2($2, NULL); }
+				{
+					ereport(ERROR,
+							(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+							 errmsg("operator right argument must be specified"),
+							 errhint("Postfix operators are not supported.")));
+				}
 		;
 
 any_operator:
@@ -12989,8 +12989,6 @@ a_expr:		c_expr									{ $$ = $1; }
 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3, @2); }
 			| qual_Op a_expr					%prec Op
 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $1, NULL, $2, @1); }
-			| a_expr qual_Op					%prec POSTFIXOP
-				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, NULL, @2); }
 
 			| a_expr AND a_expr
 				{ $$ = makeAndExpr($1, $3, @2); }
@@ -13404,8 +13402,6 @@ b_expr:		c_expr
 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3, @2); }
 			| qual_Op b_expr					%prec Op
 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $1, NULL, $2, @1); }
-			| b_expr qual_Op					%prec POSTFIXOP
-				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, NULL, @2); }
 			| b_expr IS DISTINCT FROM b_expr		%prec IS
 				{
 					$$ = (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $5, @2);
@@ -14661,11 +14657,7 @@ target_el:	a_expr AS ColLabel
 				}
 			/*
 			 * 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.
+			 * any known keyword.
 			 */
 			| a_expr IDENT
 				{
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index f69976cc8c..9e266cf3b0 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -57,7 +57,7 @@ bool		Transform_null_equals = false;
 #define PREC_GROUP_NOT_LIKE		9	/* NOT LIKE/ILIKE/SIMILAR */
 #define PREC_GROUP_NOT_BETWEEN	10	/* NOT BETWEEN */
 #define PREC_GROUP_NOT_IN		11	/* NOT IN */
-#define PREC_GROUP_POSTFIX_OP	12	/* generic postfix operators */
+#define PREC_GROUP_ANY_ALL		12	/* ANY/ALL */
 #define PREC_GROUP_INFIX_OP		13	/* generic infix operators */
 #define PREC_GROUP_PREFIX_OP	14	/* generic prefix operators */
 
@@ -71,7 +71,7 @@ bool		Transform_null_equals = false;
  * 4. LIKE ILIKE SIMILAR
  * 5. BETWEEN
  * 6. IN
- * 7. generic postfix Op
+ * 7. ANY ALL
  * 8. generic Op, including <= => <>
  * 9. generic prefix Op
  * 10. IS tests (NullTest, BooleanTest, etc)
@@ -1031,7 +1031,7 @@ transformAExprOpAny(ParseState *pstate, A_Expr *a)
 	Node	   *rexpr = a->rexpr;
 
 	if (operator_precedence_warning)
-		emit_precedence_warnings(pstate, PREC_GROUP_POSTFIX_OP,
+		emit_precedence_warnings(pstate, PREC_GROUP_ANY_ALL,
 								 strVal(llast(a->name)),
 								 lexpr, NULL,
 								 a->location);
@@ -1054,7 +1054,7 @@ transformAExprOpAll(ParseState *pstate, A_Expr *a)
 	Node	   *rexpr = a->rexpr;
 
 	if (operator_precedence_warning)
-		emit_precedence_warnings(pstate, PREC_GROUP_POSTFIX_OP,
+		emit_precedence_warnings(pstate, PREC_GROUP_ANY_ALL,
 								 strVal(llast(a->name)),
 								 lexpr, NULL,
 								 a->location);
@@ -2014,15 +2014,9 @@ transformSubLink(ParseState *pstate, SubLink *sublink)
 
 		if (operator_precedence_warning)
 		{
-			if (sublink->operName == NIL)
-				emit_precedence_warnings(pstate, PREC_GROUP_IN, "IN",
-										 sublink->testexpr, NULL,
-										 sublink->location);
-			else
-				emit_precedence_warnings(pstate, PREC_GROUP_POSTFIX_OP,
-										 strVal(llast(sublink->operName)),
-										 sublink->testexpr, NULL,
-										 sublink->location);
+			emit_precedence_warnings(pstate, PREC_GROUP_IN, "IN",
+									 sublink->testexpr, NULL,
+									 sublink->location);
 		}
 
 		/*
@@ -3244,28 +3238,11 @@ operator_precedence_group(Node *node, const char **nodename)
 				group = PREC_GROUP_PREFIX_OP;
 			}
 		}
-		else if (aexpr->kind == AEXPR_OP &&
-				 aexpr->lexpr != NULL &&
-				 aexpr->rexpr == NULL)
-		{
-			/* postfix operator */
-			if (list_length(aexpr->name) == 1)
-			{
-				*nodename = strVal(linitial(aexpr->name));
-				group = PREC_GROUP_POSTFIX_OP;
-			}
-			else
-			{
-				/* schema-qualified operator syntax */
-				*nodename = "OPERATOR()";
-				group = PREC_GROUP_POSTFIX_OP;
-			}
-		}
 		else if (aexpr->kind == AEXPR_OP_ANY ||
 				 aexpr->kind == AEXPR_OP_ALL)
 		{
 			*nodename = strVal(llast(aexpr->name));
-			group = PREC_GROUP_POSTFIX_OP;
+			group = PREC_GROUP_ANY_ALL;
 		}
 		else if (aexpr->kind == AEXPR_DISTINCT ||
 				 aexpr->kind == AEXPR_NOT_DISTINCT)
@@ -3356,7 +3333,7 @@ operator_precedence_group(Node *node, const char **nodename)
 			else
 			{
 				*nodename = strVal(llast(s->operName));
-				group = PREC_GROUP_POSTFIX_OP;
+				group = PREC_GROUP_ANY_ALL;
 			}
 		}
 	}
@@ -3432,9 +3409,8 @@ emit_precedence_warnings(ParseState *pstate,
 	 * Complain if left child, which should be same or higher precedence
 	 * according to current rules, used to be lower precedence.
 	 *
-	 * Exception to precedence rules: if left child is IN or NOT IN or a
-	 * postfix operator, the grouping is syntactically forced regardless of
-	 * precedence.
+	 * Exception to precedence rules: if left child is IN or NOT IN the
+	 * grouping is syntactically forced regardless of precedence.
 	 */
 	cgroup = operator_precedence_group(lchild, &copname);
 	if (cgroup > 0)
@@ -3442,7 +3418,7 @@ emit_precedence_warnings(ParseState *pstate,
 		if (oldprecedence_l[cgroup] < oldprecedence_r[opgroup] &&
 			cgroup != PREC_GROUP_IN &&
 			cgroup != PREC_GROUP_NOT_IN &&
-			cgroup != PREC_GROUP_POSTFIX_OP &&
+			cgroup != PREC_GROUP_ANY_ALL &&
 			cgroup != PREC_GROUP_POSTFIX_IS)
 			ereport(WARNING,
 					(errmsg("operator precedence change: %s is now lower precedence than %s",
diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c
index 2749974f63..877ffa03a6 100644
--- a/src/backend/parser/parse_oper.c
+++ b/src/backend/parser/parse_oper.c
@@ -52,7 +52,7 @@ typedef struct OprCacheKey
 {
 	char		oprname[NAMEDATALEN];
 	Oid			left_arg;		/* Left input OID, or 0 if prefix op */
-	Oid			right_arg;		/* Right input OID, or 0 if postfix op */
+	Oid			right_arg;		/* Right input OID */
 	Oid			search_path[MAX_CACHED_PATH_LEN];
 } OprCacheKey;
 
@@ -88,8 +88,7 @@ static void InvalidateOprCacheCallBack(Datum arg, int cacheid, uint32 hashvalue)
  *		Given a possibly-qualified operator name and exact input datatypes,
  *		look up the operator.
  *
- * Pass oprleft = InvalidOid for a prefix op, oprright = InvalidOid for
- * a postfix op.
+ * Pass oprleft = InvalidOid for a prefix op.
  *
  * If the operator name is not schema-qualified, it is sought in the current
  * namespace search path.
@@ -115,10 +114,13 @@ LookupOperName(ParseState *pstate, List *opername, Oid oprleft, Oid oprright,
 
 		if (!OidIsValid(oprleft))
 			oprkind = 'l';
-		else if (!OidIsValid(oprright))
-			oprkind = 'r';
-		else
+		else if (OidIsValid(oprright))
 			oprkind = 'b';
+		else
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					 errmsg("postfix operators are not supported"),
+					 parser_errposition(pstate, location)));
 
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_FUNCTION),
@@ -507,85 +509,6 @@ compatible_oper_opid(List *op, Oid arg1, Oid arg2, bool noError)
 }
 
 
-/* right_oper() -- search for a unary right operator (postfix operator)
- * Given operator name and type of arg, return oper struct.
- *
- * IMPORTANT: the returned operator (if any) is only promised to be
- * coercion-compatible with the input datatype.  Do not use this if
- * you need an exact- or binary-compatible match.
- *
- * If no matching operator found, return NULL if noError is true,
- * raise an error if it is false.  pstate and location are used only to report
- * the error position; pass NULL/-1 if not available.
- *
- * NOTE: on success, the returned object is a syscache entry.  The caller
- * must ReleaseSysCache() the entry when done with it.
- */
-Operator
-right_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
-{
-	Oid			operOid;
-	OprCacheKey key;
-	bool		key_ok;
-	FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND;
-	HeapTuple	tup = NULL;
-
-	/*
-	 * Try to find the mapping in the lookaside cache.
-	 */
-	key_ok = make_oper_cache_key(pstate, &key, op, arg, InvalidOid, location);
-
-	if (key_ok)
-	{
-		operOid = find_oper_cache_entry(&key);
-		if (OidIsValid(operOid))
-		{
-			tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
-			if (HeapTupleIsValid(tup))
-				return (Operator) tup;
-		}
-	}
-
-	/*
-	 * First try for an "exact" match.
-	 */
-	operOid = OpernameGetOprid(op, arg, InvalidOid);
-	if (!OidIsValid(operOid))
-	{
-		/*
-		 * Otherwise, search for the most suitable candidate.
-		 */
-		FuncCandidateList clist;
-
-		/* Get postfix operators of given name */
-		clist = OpernameGetCandidates(op, 'r', false);
-
-		/* No operators found? Then fail... */
-		if (clist != NULL)
-		{
-			/*
-			 * We must run oper_select_candidate even if only one candidate,
-			 * otherwise we may falsely return a non-type-compatible operator.
-			 */
-			fdresult = oper_select_candidate(1, &arg, clist, &operOid);
-		}
-	}
-
-	if (OidIsValid(operOid))
-		tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
-
-	if (HeapTupleIsValid(tup))
-	{
-		if (key_ok)
-			make_oper_cache_entry(&key, operOid);
-	}
-	else if (!noError)
-		op_error(pstate, op, 'r', arg, InvalidOid, fdresult, location);
-
-	return (Operator) tup;
-}
-
-
 /* left_oper() -- search for a unary left operator (prefix operator)
  * Given operator name and type of arg, return oper struct.
  *
@@ -696,8 +619,7 @@ op_signature_string(List *op, char oprkind, Oid arg1, Oid arg2)
 
 	appendStringInfoString(&argbuf, NameListToString(op));
 
-	if (oprkind != 'r')
-		appendStringInfo(&argbuf, " %s", format_type_be(arg2));
+	appendStringInfo(&argbuf, " %s", format_type_be(arg2));
 
 	return argbuf.data;			/* return palloc'd string buffer */
 }
@@ -758,15 +680,14 @@ make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree,
 	Oid			rettype;
 	OpExpr	   *result;
 
-	/* Select the operator */
+	/* Check it's not a postfix operator */
 	if (rtree == NULL)
-	{
-		/* right operator */
-		ltypeId = exprType(ltree);
-		rtypeId = InvalidOid;
-		tup = right_oper(pstate, opname, ltypeId, false, location);
-	}
-	else if (ltree == NULL)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+				 errmsg("postfix operators are not supported")));
+
+	/* Select the operator */
+	if (ltree == NULL)
 	{
 		/* left operator */
 		rtypeId = exprType(rtree);
@@ -795,15 +716,7 @@ make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree,
 				 parser_errposition(pstate, location)));
 
 	/* Do typecasting and build the expression tree */
-	if (rtree == NULL)
-	{
-		/* right operator */
-		args = list_make1(ltree);
-		actual_arg_types[0] = ltypeId;
-		declared_arg_types[0] = opform->oprleft;
-		nargs = 1;
-	}
-	else if (ltree == NULL)
+	if (ltree == NULL)
 	{
 		/* left operator */
 		args = list_make1(rtree);
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 60dd80c23c..16abfcb406 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -9207,25 +9207,16 @@ get_oper_expr(OpExpr *expr, deparse_context *context)
 		if (!HeapTupleIsValid(tp))
 			elog(ERROR, "cache lookup failed for operator %u", opno);
 		optup = (Form_pg_operator) GETSTRUCT(tp);
-		switch (optup->oprkind)
-		{
-			case 'l':
-				appendStringInfo(buf, "%s ",
-								 generate_operator_name(opno,
-														InvalidOid,
-														exprType(arg)));
-				get_rule_expr_paren(arg, context, true, (Node *) expr);
-				break;
-			case 'r':
-				get_rule_expr_paren(arg, context, true, (Node *) expr);
-				appendStringInfo(buf, " %s",
-								 generate_operator_name(opno,
-														exprType(arg),
-														InvalidOid));
-				break;
-			default:
-				elog(ERROR, "bogus oprkind: %d", optup->oprkind);
+		if (optup->oprkind == 'l')
+		{
+			appendStringInfo(buf, "%s ",
+							 generate_operator_name(opno,
+													InvalidOid,
+													exprType(arg)));
+			get_rule_expr_paren(arg, context, true, (Node *) expr);
 		}
+		else
+			elog(ERROR, "bogus oprkind: %d", optup->oprkind);
 		ReleaseSysCache(tp);
 	}
 	if (!PRETTY_PAREN(context))
@@ -11087,10 +11078,6 @@ generate_operator_name(Oid operid, Oid arg1, Oid arg2)
 			p_result = left_oper(NULL, list_make1(makeString(oprname)), arg2,
 								 true, -1);
 			break;
-		case 'r':
-			p_result = right_oper(NULL, list_make1(makeString(oprname)), arg1,
-								  true, -1);
-			break;
 		default:
 			elog(ERROR, "unrecognized oprkind: %d", operform->oprkind);
 			p_result = NULL;	/* keep compiler quiet */
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 2cb3f9b083..105327b3d8 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -12632,6 +12632,11 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
 	oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
 	oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
 
+	/* In PG14 upwards right unary operator support does not exist anymore. */
+	if (strcmp(oprkind, "r") == 0)
+		pg_log_warning("right unary operators are not supported anymore (operator \"%s\")",
+					   oprcode);
+
 	oprregproc = convertRegProcReference(fout, oprcode);
 	if (oprregproc)
 	{
diff --git a/src/bin/pg_dump/pg_dump_sort.c b/src/bin/pg_dump/pg_dump_sort.c
index 654e2ec514..c7f06604c6 100644
--- a/src/bin/pg_dump/pg_dump_sort.c
+++ b/src/bin/pg_dump/pg_dump_sort.c
@@ -203,7 +203,7 @@ DOTypeNameCompare(const void *p1, const void *p2)
 		OprInfo    *oobj1 = *(OprInfo *const *) p1;
 		OprInfo    *oobj2 = *(OprInfo *const *) p2;
 
-		/* oprkind is 'l', 'r', or 'b'; this sorts prefix, postfix, infix */
+		/* oprkind is 'l' or 'b'; this sorts prefix and infix */
 		cmpval = (oobj2->oprkind - oobj1->oprkind);
 		if (cmpval != 0)
 			return cmpval;
diff --git a/src/bin/pg_upgrade/check.c b/src/bin/pg_upgrade/check.c
index 00aef855dc..b86098dc42 100644
--- a/src/bin/pg_upgrade/check.c
+++ b/src/bin/pg_upgrade/check.c
@@ -22,6 +22,7 @@ static void check_is_install_user(ClusterInfo *cluster);
 static void check_proper_datallowconn(ClusterInfo *cluster);
 static void check_for_prepared_transactions(ClusterInfo *cluster);
 static void check_for_isn_and_int8_passing_mismatch(ClusterInfo *cluster);
+static void check_for_user_defined_postfix_ops(ClusterInfo *cluster);
 static void check_for_tables_with_oids(ClusterInfo *cluster);
 static void check_for_reg_data_type_usage(ClusterInfo *cluster);
 static void check_for_jsonb_9_4_usage(ClusterInfo *cluster);
@@ -100,6 +101,13 @@ check_and_dump_old_cluster(bool live_check)
 	check_for_reg_data_type_usage(&old_cluster);
 	check_for_isn_and_int8_passing_mismatch(&old_cluster);
 
+	/*
+	 * Pre-PG 14 allowed user defined postfix operators, which are not
+	 * supported anymore.  Verify there are none, iff applicable.
+	 */
+	if (GET_MAJOR_VERSION(old_cluster.major_version) <= 1300)
+		check_for_user_defined_postfix_ops(&old_cluster);
+
 	/*
 	 * Pre-PG 12 allowed tables to be declared WITH OIDS, which is not
 	 * supported anymore. Verify there are none, iff applicable.
@@ -896,6 +904,104 @@ check_for_isn_and_int8_passing_mismatch(ClusterInfo *cluster)
 		check_ok();
 }
 
+/*
+ * Verify that no user defined postfix operators exist.
+ */
+static void
+check_for_user_defined_postfix_ops(ClusterInfo *cluster)
+{
+	int			dbnum;
+	FILE	   *script = NULL;
+	bool		found = false;
+	char		output_path[MAXPGPATH];
+
+	prep_status("Checking for user defined postfix operators");
+
+	snprintf(output_path, sizeof(output_path),
+			 "postfix_ops.txt");
+
+	/* Find any user defined postfix operators */
+	for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
+	{
+		PGresult   *res;
+		bool		db_used = false;
+		int			ntups;
+		int			rowno;
+		int			i_oproid,
+					i_oprnsp,
+					i_oprname,
+					i_typnsp,
+					i_typname;
+		DbInfo	   *active_db = &cluster->dbarr.dbs[dbnum];
+		PGconn	   *conn = connectToServer(cluster, active_db->db_name);
+
+		/*
+		 * The query below hardcodes FirstNormalObjectId as 16384 rather than
+		 * interpolating that C #define into the string because, if that
+		 * #define is ever changed, the cutoff we want to use is the definition
+		 * from pre-verion 14 servers, not from some future version of the
+		 * code.
+		 */
+		res = executeQueryOrDie(conn,
+								"SELECT o.oid AS oproid, "
+								"       n.nspname AS oprnsp, "
+								"       o.oprname, "
+								"       tn.nspname AS typnsp, "
+								"       t.typname "
+								"FROM pg_catalog.pg_operator o, "
+								"     pg_catalog.pg_namespace n, "
+								"     pg_catalog.pg_type t, "
+								"     pg_catalog.pg_namespace tn "
+								"WHERE o.oprnamespace = n.oid AND "
+								"      o.oprleft = t.oid AND "
+								"      t.typnamespace = tn.oid AND "
+								"      o.oprright = 0 AND "
+								"      o.oid >= 16384");
+		ntups = PQntuples(res);
+		i_oproid = PQfnumber(res, "oproid");
+		i_oprnsp = PQfnumber(res, "oprnsp");
+		i_oprname = PQfnumber(res, "oprname");
+		i_typnsp = PQfnumber(res, "typnsp");
+		i_typname = PQfnumber(res, "typname");
+		for (rowno = 0; rowno < ntups; rowno++)
+		{
+			found = true;
+			if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
+				pg_fatal("could not open file \"%s\": %s\n",
+						 output_path, strerror(errno));
+			if (!db_used)
+			{
+				fprintf(script, "In database: %s\n", active_db->db_name);
+				db_used = true;
+			}
+			fprintf(script, "  (oid=%s) %s.%s (%s.%s)\n",
+					PQgetvalue(res, rowno, i_oproid),
+					PQgetvalue(res, rowno, i_oprnsp),
+					PQgetvalue(res, rowno, i_oprname),
+					PQgetvalue(res, rowno, i_typnsp),
+					PQgetvalue(res, rowno, i_typname));
+		}
+
+		PQclear(res);
+
+		PQfinish(conn);
+	}
+
+	if (script)
+		fclose(script);
+
+	if (found)
+	{
+		pg_log(PG_REPORT, "fatal\n");
+		pg_fatal("Your installation contains user defined postfix operators, which is not\n"
+				 "supported anymore.  Consider dropping the postfix operators and replacing\n"
+				 "them with prefix operators or function calls.\n"
+				 "A list of user defined postfix operators is in the file:\n"
+				 "    %s\n\n", output_path);
+	}
+	else
+		check_ok();
+}
 
 /*
  * Verify that no tables are declared WITH OIDS.
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index 0266fc5fa8..7deb1b09d2 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -805,7 +805,7 @@ describeOperators(const char *pattern, bool verbose, bool showSystem)
 					  "SELECT n.nspname as \"%s\",\n"
 					  "  o.oprname AS \"%s\",\n"
 					  "  CASE WHEN o.oprkind='l' THEN NULL ELSE pg_catalog.format_type(o.oprleft, NULL) END AS \"%s\",\n"
-					  "  CASE WHEN o.oprkind='r' THEN NULL ELSE pg_catalog.format_type(o.oprright, NULL) END AS \"%s\",\n"
+					  "  pg_catalog.format_type(o.oprright, NULL) AS \"%s\",\n"
 					  "  pg_catalog.format_type(o.oprresult, NULL) AS \"%s\",\n",
 					  gettext_noop("Schema"),
 					  gettext_noop("Name"),
diff --git a/src/include/catalog/pg_operator.dat b/src/include/catalog/pg_operator.dat
index 4f8b9865ef..7cc812adda 100644
--- a/src/include/catalog/pg_operator.dat
+++ b/src/include/catalog/pg_operator.dat
@@ -218,12 +218,6 @@
   oprname => '>=', oprleft => 'xid8', oprright => 'xid8', oprresult => 'bool',
   oprcom => '<=(xid8,xid8)', oprnegate => '<(xid8,xid8)', oprcode => 'xid8ge',
   oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' },
-{ oid => '388', descr => 'deprecated, use factorial() instead',
-  oprname => '!', oprkind => 'r', oprleft => 'int8', oprright => '0',
-  oprresult => 'numeric', oprcode => 'numeric_fac' },
-{ oid => '389', descr => 'deprecated, use factorial() instead',
-  oprname => '!!', oprkind => 'l', oprleft => '0', oprright => 'int8',
-  oprresult => 'numeric', oprcode => 'numeric_fac' },
 { oid => '385', descr => 'equal',
   oprname => '=', oprcanhash => 't', oprleft => 'cid', oprright => 'cid',
   oprresult => 'bool', oprcom => '=(cid,cid)', oprcode => 'cideq',
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index 1daa263852..1491b87582 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -41,7 +41,7 @@ CATALOG(pg_operator,2617,OperatorRelationId)
 	/* operator owner */
 	Oid			oprowner BKI_DEFAULT(PGUID);
 
-	/* 'l', 'r', or 'b' */
+	/* 'l' or 'b' */
 	char		oprkind BKI_DEFAULT(b);
 
 	/* can be used in merge join? */
@@ -53,7 +53,7 @@ CATALOG(pg_operator,2617,OperatorRelationId)
 	/* left arg type, or 0 if 'l' oprkind */
 	Oid			oprleft BKI_LOOKUP(pg_type);
 
-	/* right arg type, or 0 if 'r' oprkind */
+	/* right arg type */
 	Oid			oprright BKI_LOOKUP(pg_type);
 
 	/* result datatype */
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 1dd325e0e6..f5af410434 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -327,10 +327,6 @@
 { oid => '110', descr => 'I/O',
   proname => 'unknownout', prorettype => 'cstring', proargtypes => 'unknown',
   prosrc => 'unknownout' },
-{ oid => '111',
-  descr => 'implementation of deprecated ! and !! factorial operators',
-  proname => 'numeric_fac', prorettype => 'numeric', proargtypes => 'int8',
-  prosrc => 'numeric_fac' },
 
 { oid => '115',
   proname => 'box_above_eq', prorettype => 'bool', proargtypes => 'box box',
diff --git a/src/test/regress/expected/create_operator.out b/src/test/regress/expected/create_operator.out
index 54e8b79159..9d97564a4c 100644
--- a/src/test/regress/expected/create_operator.out
+++ b/src/test/regress/expected/create_operator.out
@@ -15,16 +15,16 @@ CREATE OPERATOR <% (
    negator = >=%
 );
 CREATE OPERATOR @#@ (
-   rightarg = int8,		-- left unary
-   procedure = numeric_fac
+   rightarg = float8,	-- left unary
+   procedure = dsqrt
 );
 CREATE OPERATOR #@# (
-   leftarg = int8,		-- right unary
-   procedure = numeric_fac
+   rightarg = float8,	-- left unary
+   procedure = dsqrt
 );
 CREATE OPERATOR #%# (
-   leftarg = int8,		-- right unary
-   procedure = numeric_fac
+   rightarg = float8,	-- left unary
+   procedure = dsqrt
 );
 -- Test operator created above
 SELECT point '(1,2)' <% widget '(0,0,3)' AS t,
@@ -36,7 +36,10 @@ SELECT point '(1,2)' <% widget '(0,0,3)' AS t,
 
 -- Test comments
 COMMENT ON OPERATOR ###### (int4, NONE) IS 'bad right unary';
-ERROR:  operator does not exist: integer ######
+ERROR:  operator right argument must be specified
+HINT:  Postfix operators are not supported.
+COMMENT ON OPERATOR ###### (NONE, int4) IS 'bad left unary';
+ERROR:  operator does not exist: ###### integer
 -- => is disallowed now
 CREATE OPERATOR => (
    leftarg = int8,		-- right unary
@@ -52,12 +55,12 @@ CREATE OPERATOR !=- (
    leftarg = int8,		-- right unary
    procedure = numeric_fac
 );
+ERROR:  operator right argument must be specified
+HINT:  Postfix operators are not supported.
 SELECT 2 !=-;
- ?column? 
-----------
-        2
-(1 row)
-
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 2 !=-;
+                    ^
 -- make sure lexer returns != as <> even in edge cases
 SELECT 2 !=/**/ 1, 2 !=/**/ 2;
  ?column? | ?column? 
@@ -172,11 +175,13 @@ CREATE OPERATOR #@%# (
    invalid_att = int8
 );
 WARNING:  operator attribute "invalid_att" not recognized
--- Should fail. At least leftarg or rightarg should be mandatorily specified
+ERROR:  operator right argument must be specified
+HINT:  Postfix operators are not supported.
+-- Should fail. At least rightarg should be mandatorily specified
 CREATE OPERATOR #@%# (
    procedure = numeric_fac
 );
-ERROR:  at least one of leftarg or rightarg must be specified
+ERROR:  operator arguments must be specified
 -- Should fail. Procedure should be mandatorily specified
 CREATE OPERATOR #@%# (
    leftarg = int8
diff --git a/src/test/regress/expected/numeric.out b/src/test/regress/expected/numeric.out
index 8546ce901f..14617c1117 100644
--- a/src/test/regress/expected/numeric.out
+++ b/src/test/regress/expected/numeric.out
@@ -2960,37 +2960,34 @@ ERROR:  value overflows numeric format
 --
 -- Tests for factorial
 --
-SELECT 4!;
- ?column? 
-----------
-       24
-(1 row)
-
-SELECT !!3;
- ?column? 
-----------
-        6
-(1 row)
-
 SELECT factorial(15);
    factorial   
 ---------------
  1307674368000
 (1 row)
 
-SELECT 100000!;
+SELECT factorial(100000);
 ERROR:  value overflows numeric format
-SELECT 0!;
- ?column? 
-----------
-        1
+SELECT factorial(0);
+ factorial 
+-----------
+         1
 (1 row)
 
-SELECT -4!;
-ERROR:  factorial of a negative number is undefined
 SELECT factorial(-4);
 ERROR:  factorial of a negative number is undefined
 --
+-- Postfix operators are not supported.  Check that.
+--
+SELECT -5!;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT -5!;
+                  ^
+SELECT 5!;
+ERROR:  syntax error at or near ";"
+LINE 1: SELECT 5!;
+                 ^
+--
 -- Tests for pg_lsn()
 --
 SELECT pg_lsn(23783416::numeric);
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index 1b3c146e4c..7825a765cd 100644
--- a/src/test/regress/expected/opr_sanity.out
+++ b/src/test/regress/expected/opr_sanity.out
@@ -1066,7 +1066,7 @@ WHERE condefault AND
 -- Look for illegal values in pg_operator fields.
 SELECT p1.oid, p1.oprname
 FROM pg_operator as p1
-WHERE (p1.oprkind != 'b' AND p1.oprkind != 'l' AND p1.oprkind != 'r') OR
+WHERE (p1.oprkind != 'b' AND p1.oprkind != 'l') OR
     p1.oprresult = 0 OR p1.oprcode = 0;
  oid | oprname 
 -----+---------
@@ -1077,8 +1077,7 @@ SELECT p1.oid, p1.oprname
 FROM pg_operator as p1
 WHERE (p1.oprleft = 0 and p1.oprkind != 'l') OR
     (p1.oprleft != 0 and p1.oprkind = 'l') OR
-    (p1.oprright = 0 and p1.oprkind != 'r') OR
-    (p1.oprright != 0 and p1.oprkind = 'r');
+    p1.oprright = 0;
  oid | oprname 
 -----+---------
 (0 rows)
@@ -1285,18 +1284,6 @@ WHERE p1.oprcode = p2.oid AND
 -----+---------+-----+---------
 (0 rows)
 
-SELECT p1.oid, p1.oprname, p2.oid, p2.proname
-FROM pg_operator AS p1, pg_proc AS p2
-WHERE p1.oprcode = p2.oid AND
-    p1.oprkind = 'r' AND
-    (p2.pronargs != 1
-     OR NOT binary_coercible(p2.prorettype, p1.oprresult)
-     OR NOT binary_coercible(p1.oprleft, p2.proargtypes[0])
-     OR p1.oprright != 0);
- oid | oprname | oid | proname 
------+---------+-----+---------
-(0 rows)
-
 -- If the operator is mergejoinable or hashjoinable, its underlying function
 -- should not be volatile.
 SELECT p1.oid, p1.oprname, p2.oid, p2.proname
diff --git a/src/test/regress/sql/create_operator.sql b/src/test/regress/sql/create_operator.sql
index 8b6fd0bb43..d6c3dc98c1 100644
--- a/src/test/regress/sql/create_operator.sql
+++ b/src/test/regress/sql/create_operator.sql
@@ -18,18 +18,18 @@ CREATE OPERATOR <% (
 );
 
 CREATE OPERATOR @#@ (
-   rightarg = int8,		-- left unary
-   procedure = numeric_fac
+   rightarg = float8,	-- left unary
+   procedure = dsqrt
 );
 
 CREATE OPERATOR #@# (
-   leftarg = int8,		-- right unary
-   procedure = numeric_fac
+   rightarg = float8,	-- left unary
+   procedure = dsqrt
 );
 
 CREATE OPERATOR #%# (
-   leftarg = int8,		-- right unary
-   procedure = numeric_fac
+   rightarg = float8,	-- left unary
+   procedure = dsqrt
 );
 
 -- Test operator created above
@@ -38,6 +38,7 @@ SELECT point '(1,2)' <% widget '(0,0,3)' AS t,
 
 -- Test comments
 COMMENT ON OPERATOR ###### (int4, NONE) IS 'bad right unary';
+COMMENT ON OPERATOR ###### (NONE, int4) IS 'bad left unary';
 
 -- => is disallowed now
 CREATE OPERATOR => (
@@ -133,7 +134,7 @@ CREATE OPERATOR #@%# (
    invalid_att = int8
 );
 
--- Should fail. At least leftarg or rightarg should be mandatorily specified
+-- Should fail. At least rightarg should be mandatorily specified
 CREATE OPERATOR #@%# (
    procedure = numeric_fac
 );
diff --git a/src/test/regress/sql/numeric.sql b/src/test/regress/sql/numeric.sql
index 416c16722a..702b522664 100644
--- a/src/test/regress/sql/numeric.sql
+++ b/src/test/regress/sql/numeric.sql
@@ -1298,14 +1298,17 @@ SELECT lcm(9999 * (10::numeric)^131068 + (10::numeric^131068 - 1), 2); -- overfl
 --
 -- Tests for factorial
 --
-SELECT 4!;
-SELECT !!3;
 SELECT factorial(15);
-SELECT 100000!;
-SELECT 0!;
-SELECT -4!;
+SELECT factorial(100000);
+SELECT factorial(0);
 SELECT factorial(-4);
 
+--
+-- Postfix operators are not supported.  Check that.
+--
+SELECT -5!;
+SELECT 5!;
+
 --
 -- Tests for pg_lsn()
 --
diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql
index 7a9180b081..307aab1deb 100644
--- a/src/test/regress/sql/opr_sanity.sql
+++ b/src/test/regress/sql/opr_sanity.sql
@@ -571,7 +571,7 @@ WHERE condefault AND
 
 SELECT p1.oid, p1.oprname
 FROM pg_operator as p1
-WHERE (p1.oprkind != 'b' AND p1.oprkind != 'l' AND p1.oprkind != 'r') OR
+WHERE (p1.oprkind != 'b' AND p1.oprkind != 'l') OR
     p1.oprresult = 0 OR p1.oprcode = 0;
 
 -- Look for missing or unwanted operand types
@@ -580,8 +580,7 @@ SELECT p1.oid, p1.oprname
 FROM pg_operator as p1
 WHERE (p1.oprleft = 0 and p1.oprkind != 'l') OR
     (p1.oprleft != 0 and p1.oprkind = 'l') OR
-    (p1.oprright = 0 and p1.oprkind != 'r') OR
-    (p1.oprright != 0 and p1.oprkind = 'r');
+    p1.oprright = 0;
 
 -- Look for conflicting operator definitions (same names and input datatypes).
 
@@ -715,15 +714,6 @@ WHERE p1.oprcode = p2.oid AND
      OR NOT binary_coercible(p1.oprright, p2.proargtypes[0])
      OR p1.oprleft != 0);
 
-SELECT p1.oid, p1.oprname, p2.oid, p2.proname
-FROM pg_operator AS p1, pg_proc AS p2
-WHERE p1.oprcode = p2.oid AND
-    p1.oprkind = 'r' AND
-    (p2.pronargs != 1
-     OR NOT binary_coercible(p2.prorettype, p1.oprresult)
-     OR NOT binary_coercible(p1.oprleft, p2.proargtypes[0])
-     OR p1.oprright != 0);
-
 -- If the operator is mergejoinable or hashjoinable, its underlying function
 -- should not be volatile.
 
diff --git a/src/tutorial/complex.source b/src/tutorial/complex.source
index 0355926701..65db7d5144 100644
--- a/src/tutorial/complex.source
+++ b/src/tutorial/complex.source
@@ -111,7 +111,7 @@ CREATE FUNCTION complex_add(complex, complex)
    LANGUAGE C IMMUTABLE STRICT;
 
 -- we can now define the operator. We show a binary operator here but you
--- can also define unary operators by omitting either of leftarg or rightarg.
+-- can also define a left unary operator by omitting the leftarg.
 CREATE OPERATOR + (
    leftarg = complex,
    rightarg = complex,
diff --git a/src/tutorial/syscat.source b/src/tutorial/syscat.source
index 3a1767f97b..a84ea0d5c9 100644
--- a/src/tutorial/syscat.source
+++ b/src/tutorial/syscat.source
@@ -110,20 +110,6 @@ SELECT n.nspname, o.oprname AS left_unary,
   ORDER BY nspname, operand;
 
 
---
--- lists all right unary operators
---
-SELECT n.nspname, o.oprname AS right_unary,
-       format_type(left_type.oid, null) AS operand,
-       format_type(result.oid, null) AS return_type
-  FROM pg_namespace n, pg_operator o,
-       pg_type left_type, pg_type result
-  WHERE o.oprnamespace = n.oid
-    and o.oprkind = 'r'          -- right unary
-    and o.oprleft = left_type.oid
-    and o.oprresult = result.oid
-  ORDER BY nspname, operand;
-
 --
 -- lists all binary operators
 --
-- 
2.21.1 (Apple Git-122.3)

v7-0002-Allow-most-keywords-to-be-used-as-implicit-column.patchapplication/octet-stream; name=v7-0002-Allow-most-keywords-to-be-used-as-implicit-column.patch; x-unix-mode=0644Download
From 2f4a6539ac7f84b41ceeecdb2fdb4792cfdd5b18 Mon Sep 17 00:00:00 2001
From: Mark Dilger <mark.dilger@enterprisedb.com>
Date: Wed, 2 Sep 2020 11:01:26 -0700
Subject: [PATCH v7 2/3] Allow most keywords to be used as implicit column
 labels.

Previously, to use a keyword as a column label in an expression, the
keyword had to be preceded by the token AS.  That is no longer
required for most keywords.  This is accomplished with some changes
to gram.y and by removing support for postfix operators.

These keywords must still be preceded by AS:

    array, as, char, character, create, day, except, fetch, filter,
    for, from, grant, group, having, hour, intersect, into, isnull,
    limit, minute, month, notnull, offset, on, order, over,
    overlaps, precision, returning, second, to, union, varying,
    where, window, with, within, without, year

Adding to the return value of pg_get_keywords a fourth column
showing whether the keyword can be used as an implicit column label.
---
 doc/src/sgml/func.sgml                  |   6 +-
 doc/src/sgml/generate-keywords-table.pl |   2 +-
 src/backend/parser/check_keywords.pl    |  97 ++-
 src/backend/parser/gram.y               | 439 +++++++++++-
 src/backend/parser/scan.l               |   2 +-
 src/backend/utils/adt/misc.c            |  11 +-
 src/common/keywords.c                   |   2 +-
 src/include/catalog/pg_proc.dat         |   4 +-
 src/include/common/kwlookup.h           |   8 +
 src/include/parser/kwlist.h             | 902 ++++++++++++------------
 src/interfaces/ecpg/preproc/keywords.c  |   2 +-
 src/tools/gen_keywordlist.pl            |  30 +-
 12 files changed, 1010 insertions(+), 495 deletions(-)

diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 8888bc73c9..65c3131733 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -22141,7 +22141,8 @@ 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>catdesc</parameter> <type>text</type>,
+        <parameter>aliastype</parameter> <type>text</type> )
        </para>
        <para>
         Returns a set of records describing the SQL keywords recognized by the
@@ -22153,6 +22154,9 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
         function name, or <literal>R</literal> for a fully reserved keyword.
         The <parameter>catdesc</parameter> column contains a
         possibly-localized string describing the category.
+        The <parameter>aliastype</parameter> column is
+        <literal>implicit</literal> if the keyword can be used as an implicit
+        column label, <literal>explicit</literal> otherwise.
        </para></entry>
       </row>
 
diff --git a/doc/src/sgml/generate-keywords-table.pl b/doc/src/sgml/generate-keywords-table.pl
index 824b324ef7..6ae6f80c3f 100644
--- a/doc/src/sgml/generate-keywords-table.pl
+++ b/doc/src/sgml/generate-keywords-table.pl
@@ -39,7 +39,7 @@ 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;
 	}
diff --git a/src/backend/parser/check_keywords.pl b/src/backend/parser/check_keywords.pl
index 702c97bba2..ddba00c96f 100644
--- a/src/backend/parser/check_keywords.pl
+++ b/src/backend/parser/check_keywords.pl
@@ -21,6 +21,27 @@ sub error
 	return;
 }
 
+sub check_alphabetical_order
+{
+	my ($listname, $list) = @_;
+	my $prevkword = '';
+	my $implicit_alias_kword;
+
+	foreach my $kword (@$list)
+	{
+
+		# Some keyword have a _P suffix. Remove it for the comparison.
+		$implicit_alias_kword = $kword;
+		$implicit_alias_kword =~ s/_P$//;
+		if ($implicit_alias_kword le $prevkword)
+		{
+			error
+			  "'$implicit_alias_kword' after '$prevkword' in $listname list is misplaced";
+		}
+		$prevkword = $implicit_alias_kword;
+	}
+}
+
 $, = ' ';     # set output field separator
 $\ = "\n";    # set output record separator
 
@@ -33,9 +54,11 @@ $keyword_categories{'reserved_keyword'}       = 'RESERVED_KEYWORD';
 open(my $gram, '<', $gram_filename) || die("Could not open : $gram_filename");
 
 my $kcat;
+my $implicit_alias;
 my $comment;
 my @arr;
 my %keywords;
+my @implicit_alias;
 
 line: while (my $S = <$gram>)
 {
@@ -51,7 +74,7 @@ line: while (my $S = <$gram>)
 	$s = '[/][*]', $S =~ s#$s# /* #g;
 	$s = '[*][/]', $S =~ s#$s# */ #g;
 
-	if (!($kcat))
+	if (!($kcat) && !($implicit_alias))
 	{
 
 		# Is this the beginning of a keyword list?
@@ -63,6 +86,10 @@ line: while (my $S = <$gram>)
 				next line;
 			}
 		}
+
+		# Is this the beginning of the implicit_alias_keyword list?
+		$implicit_alias = 1 if ($S =~ m/^implicit_alias_keyword:/);
+
 		next line;
 	}
 
@@ -97,7 +124,8 @@ line: while (my $S = <$gram>)
 		{
 
 			# end of keyword list
-			$kcat = '';
+			undef $kcat;
+			undef $implicit_alias;
 			next;
 		}
 
@@ -107,31 +135,21 @@ line: while (my $S = <$gram>)
 		}
 
 		# Put this keyword into the right list
-		push @{ $keywords{$kcat} }, $arr[$fieldIndexer];
+		if ($implicit_alias)
+		{
+			push @implicit_alias, $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('implicit_alias_keyword', \@implicit_alias);
 
 # Transform the keyword lists into hashes.
 # kwhashes is a hash of hashes, keyed by keyword category id,
@@ -147,6 +165,7 @@ while (my ($kcat, $kcat_id) = each(%keyword_categories))
 
 	$kwhashes{$kcat_id} = $hash;
 }
+my %implicit_alias = map { $_ => 1 } @implicit_alias;
 
 # Now read in kwlist.h
 
@@ -154,17 +173,41 @@ open(my $kwlist, '<', $kwlist_filename)
   || die("Could not open : $kwlist_filename");
 
 my $prevkwstring = '';
-my $bare_kwname;
+my $implicit_alias_kwname;
 my %kwhash;
 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 ($aliastype) = $4;
+
+		# Check that the keyword label aliastype value matches treatment in gram.y
+		if ($aliastype eq 'IMPLICIT_ALIAS')
+		{
+			unless ($implicit_alias{$kwname})
+			{
+				error
+				  "'$kwstring' in kwlist.h is marked as implicit_alias, but is missing from gram.y's implicit_alias_keyword rule";
+			}
+		}
+		elsif ($aliastype eq 'EXPLICIT_ALIAS')
+		{
+			if ($implicit_alias{$kwname})
+			{
+				error
+				  "'$kwname' in kwlist.h is marked as explicit, but is listed in gram.y's implicit_alias_keyword rule";
+			}
+		}
+		else
+		{
+			error
+			  "'$aliastype' not recognized in kwlist.h.  Expected either 'IMPLICIT_ALIAS' or 'EXPLICIT_ALIAS'";
+		}
 
 		# Check that the list is in alphabetical order (critical!)
 		if ($kwstring le $prevkwstring)
@@ -189,9 +232,9 @@ kwlist_line: while (<$kwlist>)
 		}
 
 		# Check that the keyword string matches keyword name
-		$bare_kwname = $kwname;
-		$bare_kwname =~ s/_P$//;
-		if ($bare_kwname ne uc($kwstring))
+		$implicit_alias_kwname = $kwname;
+		$implicit_alias_kwname =~ s/_P$//;
+		if ($implicit_alias_kwname ne uc($kwstring))
 		{
 			error
 			  "keyword name '$kwname' doesn't match keyword string '$kwstring'";
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index d8a607e29a..e9ee5dd873 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -540,14 +540,15 @@ 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 ImplicitAlias
 %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> col_name_keyword implicit_alias_keyword reserved_keyword
 
 %type <node>	TableConstraint TableLikeClause
 %type <ival>	TableLikeOptionList TableLikeOption
@@ -14655,11 +14656,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 ImplicitAlias
 				{
 					$$ = makeNode(ResTarget);
 					$$->name = $2;
@@ -14987,6 +14984,12 @@ NonReservedWord:	IDENT							{ $$ = $1; }
 			| type_func_name_keyword				{ $$ = pstrdup($1); }
 		;
 
+/* Bare column label --- names that can be column labels without writing "AS".
+ */
+ImplicitAlias:	IDENT								{ $$ = $1; }
+			| implicit_alias_keyword					{ $$ = pstrdup($1); }
+		;
+
 /* Column label --- allowed labels in "AS" clauses.
  * This presently includes *all* Postgres keywords.
  */
@@ -14998,6 +15001,428 @@ ColLabel:	IDENT									{ $$ = $1; }
 		;
 
 
+/*
+ * All keywords can be used explicitly as a column label in expressions
+ * like 'SELECT 1234 AS keyword', but only some keywords can be used
+ * implicitly as column labels in expressions like 'SELECT 1234 keyword'.
+ * Those that can be used implicitly should be listed here.
+ *
+ * Keep this in alphabetical order.
+ */
+implicit_alias_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
+		;
+
 /*
  * Keyword category lists.  Generally, every keyword present in
  * the Postgres grammar should appear in exactly one of these lists.
diff --git a/src/backend/parser/scan.l b/src/backend/parser/scan.l
index b1ea0cb538..58a8afa782 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, aliastype) 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 37c23c9155..1b04b0e079 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -416,13 +416,15 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 		funcctx = SRF_FIRSTCALL_INIT();
 		oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
 
-		tupdesc = CreateTemplateTupleDesc(3);
+		tupdesc = CreateTemplateTupleDesc(4);
 		TupleDescInitEntry(tupdesc, (AttrNumber) 1, "word",
 						   TEXTOID, -1, 0);
 		TupleDescInitEntry(tupdesc, (AttrNumber) 2, "catcode",
 						   CHAROID, -1, 0);
 		TupleDescInitEntry(tupdesc, (AttrNumber) 3, "catdesc",
 						   TEXTOID, -1, 0);
+		TupleDescInitEntry(tupdesc, (AttrNumber) 4, "aliastype",
+						   TEXTOID, -1, 0);
 
 		funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
 
@@ -433,7 +435,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 	if (funcctx->call_cntr < ScanKeywords.num_keywords)
 	{
-		char	   *values[3];
+		char	   *values[4];
 		HeapTuple	tuple;
 
 		/* cast-away-const is ugly but alternatives aren't much better */
@@ -465,6 +467,11 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 				break;
 		}
 
+		if (GetScanKeywordIsImplicit(funcctx->call_cntr, &ScanKeywords))
+			values[3] = unconstify(char *, (const char *)"implicit");
+		else
+			values[3] = unconstify(char *, (const char *)"explicit");
+
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
 		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
diff --git a/src/common/keywords.c b/src/common/keywords.c
index 54ed977096..f42cd69094 100644
--- a/src/common/keywords.c
+++ b/src/common/keywords.c
@@ -24,7 +24,7 @@
 
 /* Keyword categories for SQL keywords */
 
-#define PG_KEYWORD(kwname, value, category) category,
+#define PG_KEYWORD(kwname, value, category, aliastype) category,
 
 const uint8 ScanKeywordCategories[SCANKEYWORDS_NUM_KEYWORDS] = {
 #include "parser/kwlist.h"
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index f5af410434..b4c4fe8a5c 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -3677,8 +3677,8 @@
 { oid => '1686', descr => 'list of SQL keywords',
   proname => 'pg_get_keywords', procost => '10', prorows => '400',
   proretset => 't', provolatile => 's', prorettype => 'record',
-  proargtypes => '', proallargtypes => '{text,char,text}',
-  proargmodes => '{o,o,o}', proargnames => '{word,catcode,catdesc}',
+  proargtypes => '', proallargtypes => '{text,char,text,text}',
+  proargmodes => '{o,o,o,o}', proargnames => '{word,catcode,catdesc,aliastype}',
   prosrc => 'pg_get_keywords' },
 
 { oid => '2289', descr => 'convert generic options array to name/value table',
diff --git a/src/include/common/kwlookup.h b/src/include/common/kwlookup.h
index 9c0c7f88d8..d56b3d895e 100644
--- a/src/include/common/kwlookup.h
+++ b/src/include/common/kwlookup.h
@@ -26,6 +26,7 @@ typedef struct ScanKeywordList
 {
 	const char *kw_string;		/* all keywords in order, separated by \0 */
 	const uint16 *kw_offsets;	/* offsets to the start of each keyword */
+	const bool *kw_is_implicit;	/* whether each keyword can be used as an implicit label */
 	ScanKeywordHashFunc hash;	/* perfect hash function for keywords */
 	int			num_keywords;	/* number of keywords */
 	int			max_kw_len;		/* length of longest keyword */
@@ -41,4 +42,11 @@ GetScanKeyword(int n, const ScanKeywordList *keywords)
 	return keywords->kw_string + keywords->kw_offsets[n];
 }
 
+/* Code that wants to retrieve the aliastype of the N'th keyword should use this. */
+static inline bool
+GetScanKeywordIsImplicit(int n, const ScanKeywordList *keywords)
+{
+	return keywords->kw_is_implicit[n];
+}
+
 #endif							/* KWLOOKUP_H */
diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h
index 08f22ce211..d011b3a5e5 100644
--- a/src/include/parser/kwlist.h
+++ b/src/include/parser/kwlist.h
@@ -24,454 +24,454 @@
  * Note: gen_keywordlist.pl requires the entries to appear in ASCII order.
  */
 
-/* name, value, category */
-PG_KEYWORD("abort", ABORT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("absolute", ABSOLUTE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("access", ACCESS, UNRESERVED_KEYWORD)
-PG_KEYWORD("action", ACTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("add", ADD_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("admin", ADMIN, UNRESERVED_KEYWORD)
-PG_KEYWORD("after", AFTER, UNRESERVED_KEYWORD)
-PG_KEYWORD("aggregate", AGGREGATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("all", ALL, RESERVED_KEYWORD)
-PG_KEYWORD("also", ALSO, UNRESERVED_KEYWORD)
-PG_KEYWORD("alter", ALTER, UNRESERVED_KEYWORD)
-PG_KEYWORD("always", ALWAYS, UNRESERVED_KEYWORD)
-PG_KEYWORD("analyse", ANALYSE, RESERVED_KEYWORD)		/* British spelling */
-PG_KEYWORD("analyze", ANALYZE, RESERVED_KEYWORD)
-PG_KEYWORD("and", AND, RESERVED_KEYWORD)
-PG_KEYWORD("any", ANY, RESERVED_KEYWORD)
-PG_KEYWORD("array", ARRAY, RESERVED_KEYWORD)
-PG_KEYWORD("as", AS, RESERVED_KEYWORD)
-PG_KEYWORD("asc", ASC, RESERVED_KEYWORD)
-PG_KEYWORD("assertion", ASSERTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("assignment", ASSIGNMENT, UNRESERVED_KEYWORD)
-PG_KEYWORD("asymmetric", ASYMMETRIC, RESERVED_KEYWORD)
-PG_KEYWORD("at", AT, UNRESERVED_KEYWORD)
-PG_KEYWORD("attach", ATTACH, UNRESERVED_KEYWORD)
-PG_KEYWORD("attribute", ATTRIBUTE, UNRESERVED_KEYWORD)
-PG_KEYWORD("authorization", AUTHORIZATION, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("backward", BACKWARD, UNRESERVED_KEYWORD)
-PG_KEYWORD("before", BEFORE, UNRESERVED_KEYWORD)
-PG_KEYWORD("begin", BEGIN_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("between", BETWEEN, COL_NAME_KEYWORD)
-PG_KEYWORD("bigint", BIGINT, COL_NAME_KEYWORD)
-PG_KEYWORD("binary", BINARY, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("bit", BIT, COL_NAME_KEYWORD)
-PG_KEYWORD("boolean", BOOLEAN_P, COL_NAME_KEYWORD)
-PG_KEYWORD("both", BOTH, RESERVED_KEYWORD)
-PG_KEYWORD("by", BY, UNRESERVED_KEYWORD)
-PG_KEYWORD("cache", CACHE, UNRESERVED_KEYWORD)
-PG_KEYWORD("call", CALL, UNRESERVED_KEYWORD)
-PG_KEYWORD("called", CALLED, UNRESERVED_KEYWORD)
-PG_KEYWORD("cascade", CASCADE, UNRESERVED_KEYWORD)
-PG_KEYWORD("cascaded", CASCADED, UNRESERVED_KEYWORD)
-PG_KEYWORD("case", CASE, RESERVED_KEYWORD)
-PG_KEYWORD("cast", CAST, RESERVED_KEYWORD)
-PG_KEYWORD("catalog", CATALOG_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("chain", CHAIN, UNRESERVED_KEYWORD)
-PG_KEYWORD("char", CHAR_P, COL_NAME_KEYWORD)
-PG_KEYWORD("character", CHARACTER, COL_NAME_KEYWORD)
-PG_KEYWORD("characteristics", CHARACTERISTICS, UNRESERVED_KEYWORD)
-PG_KEYWORD("check", CHECK, RESERVED_KEYWORD)
-PG_KEYWORD("checkpoint", CHECKPOINT, UNRESERVED_KEYWORD)
-PG_KEYWORD("class", CLASS, UNRESERVED_KEYWORD)
-PG_KEYWORD("close", CLOSE, UNRESERVED_KEYWORD)
-PG_KEYWORD("cluster", CLUSTER, UNRESERVED_KEYWORD)
-PG_KEYWORD("coalesce", COALESCE, COL_NAME_KEYWORD)
-PG_KEYWORD("collate", COLLATE, RESERVED_KEYWORD)
-PG_KEYWORD("collation", COLLATION, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("column", COLUMN, RESERVED_KEYWORD)
-PG_KEYWORD("columns", COLUMNS, UNRESERVED_KEYWORD)
-PG_KEYWORD("comment", COMMENT, UNRESERVED_KEYWORD)
-PG_KEYWORD("comments", COMMENTS, UNRESERVED_KEYWORD)
-PG_KEYWORD("commit", COMMIT, UNRESERVED_KEYWORD)
-PG_KEYWORD("committed", COMMITTED, UNRESERVED_KEYWORD)
-PG_KEYWORD("concurrently", CONCURRENTLY, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("configuration", CONFIGURATION, UNRESERVED_KEYWORD)
-PG_KEYWORD("conflict", CONFLICT, UNRESERVED_KEYWORD)
-PG_KEYWORD("connection", CONNECTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("constraint", CONSTRAINT, RESERVED_KEYWORD)
-PG_KEYWORD("constraints", CONSTRAINTS, UNRESERVED_KEYWORD)
-PG_KEYWORD("content", CONTENT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("continue", CONTINUE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("conversion", CONVERSION_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("copy", COPY, UNRESERVED_KEYWORD)
-PG_KEYWORD("cost", COST, UNRESERVED_KEYWORD)
-PG_KEYWORD("create", CREATE, RESERVED_KEYWORD)
-PG_KEYWORD("cross", CROSS, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("csv", CSV, UNRESERVED_KEYWORD)
-PG_KEYWORD("cube", CUBE, UNRESERVED_KEYWORD)
-PG_KEYWORD("current", CURRENT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("current_catalog", CURRENT_CATALOG, RESERVED_KEYWORD)
-PG_KEYWORD("current_date", CURRENT_DATE, RESERVED_KEYWORD)
-PG_KEYWORD("current_role", CURRENT_ROLE, RESERVED_KEYWORD)
-PG_KEYWORD("current_schema", CURRENT_SCHEMA, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("current_time", CURRENT_TIME, RESERVED_KEYWORD)
-PG_KEYWORD("current_timestamp", CURRENT_TIMESTAMP, RESERVED_KEYWORD)
-PG_KEYWORD("current_user", CURRENT_USER, RESERVED_KEYWORD)
-PG_KEYWORD("cursor", CURSOR, UNRESERVED_KEYWORD)
-PG_KEYWORD("cycle", CYCLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("data", DATA_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("database", DATABASE, UNRESERVED_KEYWORD)
-PG_KEYWORD("day", DAY_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("deallocate", DEALLOCATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("dec", DEC, COL_NAME_KEYWORD)
-PG_KEYWORD("decimal", DECIMAL_P, COL_NAME_KEYWORD)
-PG_KEYWORD("declare", DECLARE, UNRESERVED_KEYWORD)
-PG_KEYWORD("default", DEFAULT, RESERVED_KEYWORD)
-PG_KEYWORD("defaults", DEFAULTS, UNRESERVED_KEYWORD)
-PG_KEYWORD("deferrable", DEFERRABLE, RESERVED_KEYWORD)
-PG_KEYWORD("deferred", DEFERRED, UNRESERVED_KEYWORD)
-PG_KEYWORD("definer", DEFINER, UNRESERVED_KEYWORD)
-PG_KEYWORD("delete", DELETE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("delimiter", DELIMITER, UNRESERVED_KEYWORD)
-PG_KEYWORD("delimiters", DELIMITERS, UNRESERVED_KEYWORD)
-PG_KEYWORD("depends", DEPENDS, UNRESERVED_KEYWORD)
-PG_KEYWORD("desc", DESC, RESERVED_KEYWORD)
-PG_KEYWORD("detach", DETACH, UNRESERVED_KEYWORD)
-PG_KEYWORD("dictionary", DICTIONARY, UNRESERVED_KEYWORD)
-PG_KEYWORD("disable", DISABLE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("discard", DISCARD, UNRESERVED_KEYWORD)
-PG_KEYWORD("distinct", DISTINCT, RESERVED_KEYWORD)
-PG_KEYWORD("do", DO, RESERVED_KEYWORD)
-PG_KEYWORD("document", DOCUMENT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("domain", DOMAIN_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("double", DOUBLE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("drop", DROP, UNRESERVED_KEYWORD)
-PG_KEYWORD("each", EACH, UNRESERVED_KEYWORD)
-PG_KEYWORD("else", ELSE, RESERVED_KEYWORD)
-PG_KEYWORD("enable", ENABLE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("encoding", ENCODING, UNRESERVED_KEYWORD)
-PG_KEYWORD("encrypted", ENCRYPTED, UNRESERVED_KEYWORD)
-PG_KEYWORD("end", END_P, RESERVED_KEYWORD)
-PG_KEYWORD("enum", ENUM_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("escape", ESCAPE, UNRESERVED_KEYWORD)
-PG_KEYWORD("event", EVENT, UNRESERVED_KEYWORD)
-PG_KEYWORD("except", EXCEPT, RESERVED_KEYWORD)
-PG_KEYWORD("exclude", EXCLUDE, UNRESERVED_KEYWORD)
-PG_KEYWORD("excluding", EXCLUDING, UNRESERVED_KEYWORD)
-PG_KEYWORD("exclusive", EXCLUSIVE, UNRESERVED_KEYWORD)
-PG_KEYWORD("execute", EXECUTE, UNRESERVED_KEYWORD)
-PG_KEYWORD("exists", EXISTS, COL_NAME_KEYWORD)
-PG_KEYWORD("explain", EXPLAIN, UNRESERVED_KEYWORD)
-PG_KEYWORD("expression", EXPRESSION, UNRESERVED_KEYWORD)
-PG_KEYWORD("extension", EXTENSION, UNRESERVED_KEYWORD)
-PG_KEYWORD("external", EXTERNAL, UNRESERVED_KEYWORD)
-PG_KEYWORD("extract", EXTRACT, COL_NAME_KEYWORD)
-PG_KEYWORD("false", FALSE_P, RESERVED_KEYWORD)
-PG_KEYWORD("family", FAMILY, UNRESERVED_KEYWORD)
-PG_KEYWORD("fetch", FETCH, RESERVED_KEYWORD)
-PG_KEYWORD("filter", FILTER, UNRESERVED_KEYWORD)
-PG_KEYWORD("first", FIRST_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("float", FLOAT_P, COL_NAME_KEYWORD)
-PG_KEYWORD("following", FOLLOWING, UNRESERVED_KEYWORD)
-PG_KEYWORD("for", FOR, RESERVED_KEYWORD)
-PG_KEYWORD("force", FORCE, UNRESERVED_KEYWORD)
-PG_KEYWORD("foreign", FOREIGN, RESERVED_KEYWORD)
-PG_KEYWORD("forward", FORWARD, UNRESERVED_KEYWORD)
-PG_KEYWORD("freeze", FREEZE, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("from", FROM, RESERVED_KEYWORD)
-PG_KEYWORD("full", FULL, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("function", FUNCTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("functions", FUNCTIONS, UNRESERVED_KEYWORD)
-PG_KEYWORD("generated", GENERATED, UNRESERVED_KEYWORD)
-PG_KEYWORD("global", GLOBAL, UNRESERVED_KEYWORD)
-PG_KEYWORD("grant", GRANT, RESERVED_KEYWORD)
-PG_KEYWORD("granted", GRANTED, UNRESERVED_KEYWORD)
-PG_KEYWORD("greatest", GREATEST, COL_NAME_KEYWORD)
-PG_KEYWORD("group", GROUP_P, RESERVED_KEYWORD)
-PG_KEYWORD("grouping", GROUPING, COL_NAME_KEYWORD)
-PG_KEYWORD("groups", GROUPS, UNRESERVED_KEYWORD)
-PG_KEYWORD("handler", HANDLER, UNRESERVED_KEYWORD)
-PG_KEYWORD("having", HAVING, RESERVED_KEYWORD)
-PG_KEYWORD("header", HEADER_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("hold", HOLD, UNRESERVED_KEYWORD)
-PG_KEYWORD("hour", HOUR_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("identity", IDENTITY_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("if", IF_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("ilike", ILIKE, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("immediate", IMMEDIATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("immutable", IMMUTABLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("implicit", IMPLICIT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("import", IMPORT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("in", IN_P, RESERVED_KEYWORD)
-PG_KEYWORD("include", INCLUDE, UNRESERVED_KEYWORD)
-PG_KEYWORD("including", INCLUDING, UNRESERVED_KEYWORD)
-PG_KEYWORD("increment", INCREMENT, UNRESERVED_KEYWORD)
-PG_KEYWORD("index", INDEX, UNRESERVED_KEYWORD)
-PG_KEYWORD("indexes", INDEXES, UNRESERVED_KEYWORD)
-PG_KEYWORD("inherit", INHERIT, UNRESERVED_KEYWORD)
-PG_KEYWORD("inherits", INHERITS, UNRESERVED_KEYWORD)
-PG_KEYWORD("initially", INITIALLY, RESERVED_KEYWORD)
-PG_KEYWORD("inline", INLINE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("inner", INNER_P, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("inout", INOUT, COL_NAME_KEYWORD)
-PG_KEYWORD("input", INPUT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("insensitive", INSENSITIVE, UNRESERVED_KEYWORD)
-PG_KEYWORD("insert", INSERT, UNRESERVED_KEYWORD)
-PG_KEYWORD("instead", INSTEAD, UNRESERVED_KEYWORD)
-PG_KEYWORD("int", INT_P, COL_NAME_KEYWORD)
-PG_KEYWORD("integer", INTEGER, COL_NAME_KEYWORD)
-PG_KEYWORD("intersect", INTERSECT, RESERVED_KEYWORD)
-PG_KEYWORD("interval", INTERVAL, COL_NAME_KEYWORD)
-PG_KEYWORD("into", INTO, RESERVED_KEYWORD)
-PG_KEYWORD("invoker", INVOKER, UNRESERVED_KEYWORD)
-PG_KEYWORD("is", IS, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("isnull", ISNULL, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("isolation", ISOLATION, UNRESERVED_KEYWORD)
-PG_KEYWORD("join", JOIN, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("key", KEY, UNRESERVED_KEYWORD)
-PG_KEYWORD("label", LABEL, UNRESERVED_KEYWORD)
-PG_KEYWORD("language", LANGUAGE, UNRESERVED_KEYWORD)
-PG_KEYWORD("large", LARGE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("last", LAST_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("lateral", LATERAL_P, RESERVED_KEYWORD)
-PG_KEYWORD("leading", LEADING, RESERVED_KEYWORD)
-PG_KEYWORD("leakproof", LEAKPROOF, UNRESERVED_KEYWORD)
-PG_KEYWORD("least", LEAST, COL_NAME_KEYWORD)
-PG_KEYWORD("left", LEFT, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("level", LEVEL, UNRESERVED_KEYWORD)
-PG_KEYWORD("like", LIKE, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("limit", LIMIT, RESERVED_KEYWORD)
-PG_KEYWORD("listen", LISTEN, UNRESERVED_KEYWORD)
-PG_KEYWORD("load", LOAD, UNRESERVED_KEYWORD)
-PG_KEYWORD("local", LOCAL, UNRESERVED_KEYWORD)
-PG_KEYWORD("localtime", LOCALTIME, RESERVED_KEYWORD)
-PG_KEYWORD("localtimestamp", LOCALTIMESTAMP, RESERVED_KEYWORD)
-PG_KEYWORD("location", LOCATION, UNRESERVED_KEYWORD)
-PG_KEYWORD("lock", LOCK_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("locked", LOCKED, UNRESERVED_KEYWORD)
-PG_KEYWORD("logged", LOGGED, UNRESERVED_KEYWORD)
-PG_KEYWORD("mapping", MAPPING, UNRESERVED_KEYWORD)
-PG_KEYWORD("match", MATCH, UNRESERVED_KEYWORD)
-PG_KEYWORD("materialized", MATERIALIZED, UNRESERVED_KEYWORD)
-PG_KEYWORD("maxvalue", MAXVALUE, UNRESERVED_KEYWORD)
-PG_KEYWORD("method", METHOD, UNRESERVED_KEYWORD)
-PG_KEYWORD("minute", MINUTE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("minvalue", MINVALUE, UNRESERVED_KEYWORD)
-PG_KEYWORD("mode", MODE, UNRESERVED_KEYWORD)
-PG_KEYWORD("month", MONTH_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("move", MOVE, UNRESERVED_KEYWORD)
-PG_KEYWORD("name", NAME_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("names", NAMES, UNRESERVED_KEYWORD)
-PG_KEYWORD("national", NATIONAL, COL_NAME_KEYWORD)
-PG_KEYWORD("natural", NATURAL, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("nchar", NCHAR, COL_NAME_KEYWORD)
-PG_KEYWORD("new", NEW, UNRESERVED_KEYWORD)
-PG_KEYWORD("next", NEXT, UNRESERVED_KEYWORD)
-PG_KEYWORD("nfc", NFC, UNRESERVED_KEYWORD)
-PG_KEYWORD("nfd", NFD, UNRESERVED_KEYWORD)
-PG_KEYWORD("nfkc", NFKC, UNRESERVED_KEYWORD)
-PG_KEYWORD("nfkd", NFKD, UNRESERVED_KEYWORD)
-PG_KEYWORD("no", NO, UNRESERVED_KEYWORD)
-PG_KEYWORD("none", NONE, COL_NAME_KEYWORD)
-PG_KEYWORD("normalize", NORMALIZE, COL_NAME_KEYWORD)
-PG_KEYWORD("normalized", NORMALIZED, UNRESERVED_KEYWORD)
-PG_KEYWORD("not", NOT, RESERVED_KEYWORD)
-PG_KEYWORD("nothing", NOTHING, UNRESERVED_KEYWORD)
-PG_KEYWORD("notify", NOTIFY, UNRESERVED_KEYWORD)
-PG_KEYWORD("notnull", NOTNULL, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("nowait", NOWAIT, UNRESERVED_KEYWORD)
-PG_KEYWORD("null", NULL_P, RESERVED_KEYWORD)
-PG_KEYWORD("nullif", NULLIF, COL_NAME_KEYWORD)
-PG_KEYWORD("nulls", NULLS_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("numeric", NUMERIC, COL_NAME_KEYWORD)
-PG_KEYWORD("object", OBJECT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("of", OF, UNRESERVED_KEYWORD)
-PG_KEYWORD("off", OFF, UNRESERVED_KEYWORD)
-PG_KEYWORD("offset", OFFSET, RESERVED_KEYWORD)
-PG_KEYWORD("oids", OIDS, UNRESERVED_KEYWORD)
-PG_KEYWORD("old", OLD, UNRESERVED_KEYWORD)
-PG_KEYWORD("on", ON, RESERVED_KEYWORD)
-PG_KEYWORD("only", ONLY, RESERVED_KEYWORD)
-PG_KEYWORD("operator", OPERATOR, UNRESERVED_KEYWORD)
-PG_KEYWORD("option", OPTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("options", OPTIONS, UNRESERVED_KEYWORD)
-PG_KEYWORD("or", OR, RESERVED_KEYWORD)
-PG_KEYWORD("order", ORDER, RESERVED_KEYWORD)
-PG_KEYWORD("ordinality", ORDINALITY, UNRESERVED_KEYWORD)
-PG_KEYWORD("others", OTHERS, UNRESERVED_KEYWORD)
-PG_KEYWORD("out", OUT_P, COL_NAME_KEYWORD)
-PG_KEYWORD("outer", OUTER_P, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("over", OVER, UNRESERVED_KEYWORD)
-PG_KEYWORD("overlaps", OVERLAPS, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("overlay", OVERLAY, COL_NAME_KEYWORD)
-PG_KEYWORD("overriding", OVERRIDING, UNRESERVED_KEYWORD)
-PG_KEYWORD("owned", OWNED, UNRESERVED_KEYWORD)
-PG_KEYWORD("owner", OWNER, UNRESERVED_KEYWORD)
-PG_KEYWORD("parallel", PARALLEL, UNRESERVED_KEYWORD)
-PG_KEYWORD("parser", PARSER, UNRESERVED_KEYWORD)
-PG_KEYWORD("partial", PARTIAL, UNRESERVED_KEYWORD)
-PG_KEYWORD("partition", PARTITION, UNRESERVED_KEYWORD)
-PG_KEYWORD("passing", PASSING, UNRESERVED_KEYWORD)
-PG_KEYWORD("password", PASSWORD, UNRESERVED_KEYWORD)
-PG_KEYWORD("placing", PLACING, RESERVED_KEYWORD)
-PG_KEYWORD("plans", PLANS, UNRESERVED_KEYWORD)
-PG_KEYWORD("policy", POLICY, UNRESERVED_KEYWORD)
-PG_KEYWORD("position", POSITION, COL_NAME_KEYWORD)
-PG_KEYWORD("preceding", PRECEDING, UNRESERVED_KEYWORD)
-PG_KEYWORD("precision", PRECISION, COL_NAME_KEYWORD)
-PG_KEYWORD("prepare", PREPARE, UNRESERVED_KEYWORD)
-PG_KEYWORD("prepared", PREPARED, UNRESERVED_KEYWORD)
-PG_KEYWORD("preserve", PRESERVE, UNRESERVED_KEYWORD)
-PG_KEYWORD("primary", PRIMARY, RESERVED_KEYWORD)
-PG_KEYWORD("prior", PRIOR, UNRESERVED_KEYWORD)
-PG_KEYWORD("privileges", PRIVILEGES, UNRESERVED_KEYWORD)
-PG_KEYWORD("procedural", PROCEDURAL, UNRESERVED_KEYWORD)
-PG_KEYWORD("procedure", PROCEDURE, UNRESERVED_KEYWORD)
-PG_KEYWORD("procedures", PROCEDURES, UNRESERVED_KEYWORD)
-PG_KEYWORD("program", PROGRAM, UNRESERVED_KEYWORD)
-PG_KEYWORD("publication", PUBLICATION, UNRESERVED_KEYWORD)
-PG_KEYWORD("quote", QUOTE, UNRESERVED_KEYWORD)
-PG_KEYWORD("range", RANGE, UNRESERVED_KEYWORD)
-PG_KEYWORD("read", READ, UNRESERVED_KEYWORD)
-PG_KEYWORD("real", REAL, COL_NAME_KEYWORD)
-PG_KEYWORD("reassign", REASSIGN, UNRESERVED_KEYWORD)
-PG_KEYWORD("recheck", RECHECK, UNRESERVED_KEYWORD)
-PG_KEYWORD("recursive", RECURSIVE, UNRESERVED_KEYWORD)
-PG_KEYWORD("ref", REF, UNRESERVED_KEYWORD)
-PG_KEYWORD("references", REFERENCES, RESERVED_KEYWORD)
-PG_KEYWORD("referencing", REFERENCING, UNRESERVED_KEYWORD)
-PG_KEYWORD("refresh", REFRESH, UNRESERVED_KEYWORD)
-PG_KEYWORD("reindex", REINDEX, UNRESERVED_KEYWORD)
-PG_KEYWORD("relative", RELATIVE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("release", RELEASE, UNRESERVED_KEYWORD)
-PG_KEYWORD("rename", RENAME, UNRESERVED_KEYWORD)
-PG_KEYWORD("repeatable", REPEATABLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("replace", REPLACE, UNRESERVED_KEYWORD)
-PG_KEYWORD("replica", REPLICA, UNRESERVED_KEYWORD)
-PG_KEYWORD("reset", RESET, UNRESERVED_KEYWORD)
-PG_KEYWORD("restart", RESTART, UNRESERVED_KEYWORD)
-PG_KEYWORD("restrict", RESTRICT, UNRESERVED_KEYWORD)
-PG_KEYWORD("returning", RETURNING, RESERVED_KEYWORD)
-PG_KEYWORD("returns", RETURNS, UNRESERVED_KEYWORD)
-PG_KEYWORD("revoke", REVOKE, UNRESERVED_KEYWORD)
-PG_KEYWORD("right", RIGHT, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("role", ROLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("rollback", ROLLBACK, UNRESERVED_KEYWORD)
-PG_KEYWORD("rollup", ROLLUP, UNRESERVED_KEYWORD)
-PG_KEYWORD("routine", ROUTINE, UNRESERVED_KEYWORD)
-PG_KEYWORD("routines", ROUTINES, UNRESERVED_KEYWORD)
-PG_KEYWORD("row", ROW, COL_NAME_KEYWORD)
-PG_KEYWORD("rows", ROWS, UNRESERVED_KEYWORD)
-PG_KEYWORD("rule", RULE, UNRESERVED_KEYWORD)
-PG_KEYWORD("savepoint", SAVEPOINT, UNRESERVED_KEYWORD)
-PG_KEYWORD("schema", SCHEMA, UNRESERVED_KEYWORD)
-PG_KEYWORD("schemas", SCHEMAS, UNRESERVED_KEYWORD)
-PG_KEYWORD("scroll", SCROLL, UNRESERVED_KEYWORD)
-PG_KEYWORD("search", SEARCH, UNRESERVED_KEYWORD)
-PG_KEYWORD("second", SECOND_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("security", SECURITY, UNRESERVED_KEYWORD)
-PG_KEYWORD("select", SELECT, RESERVED_KEYWORD)
-PG_KEYWORD("sequence", SEQUENCE, UNRESERVED_KEYWORD)
-PG_KEYWORD("sequences", SEQUENCES, UNRESERVED_KEYWORD)
-PG_KEYWORD("serializable", SERIALIZABLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("server", SERVER, UNRESERVED_KEYWORD)
-PG_KEYWORD("session", SESSION, UNRESERVED_KEYWORD)
-PG_KEYWORD("session_user", SESSION_USER, RESERVED_KEYWORD)
-PG_KEYWORD("set", SET, UNRESERVED_KEYWORD)
-PG_KEYWORD("setof", SETOF, COL_NAME_KEYWORD)
-PG_KEYWORD("sets", SETS, UNRESERVED_KEYWORD)
-PG_KEYWORD("share", SHARE, UNRESERVED_KEYWORD)
-PG_KEYWORD("show", SHOW, UNRESERVED_KEYWORD)
-PG_KEYWORD("similar", SIMILAR, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("simple", SIMPLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("skip", SKIP, UNRESERVED_KEYWORD)
-PG_KEYWORD("smallint", SMALLINT, COL_NAME_KEYWORD)
-PG_KEYWORD("snapshot", SNAPSHOT, UNRESERVED_KEYWORD)
-PG_KEYWORD("some", SOME, RESERVED_KEYWORD)
-PG_KEYWORD("sql", SQL_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("stable", STABLE, UNRESERVED_KEYWORD)
-PG_KEYWORD("standalone", STANDALONE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("start", START, UNRESERVED_KEYWORD)
-PG_KEYWORD("statement", STATEMENT, UNRESERVED_KEYWORD)
-PG_KEYWORD("statistics", STATISTICS, UNRESERVED_KEYWORD)
-PG_KEYWORD("stdin", STDIN, UNRESERVED_KEYWORD)
-PG_KEYWORD("stdout", STDOUT, UNRESERVED_KEYWORD)
-PG_KEYWORD("storage", STORAGE, UNRESERVED_KEYWORD)
-PG_KEYWORD("stored", STORED, UNRESERVED_KEYWORD)
-PG_KEYWORD("strict", STRICT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("strip", STRIP_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("subscription", SUBSCRIPTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("substring", SUBSTRING, COL_NAME_KEYWORD)
-PG_KEYWORD("support", SUPPORT, UNRESERVED_KEYWORD)
-PG_KEYWORD("symmetric", SYMMETRIC, RESERVED_KEYWORD)
-PG_KEYWORD("sysid", SYSID, UNRESERVED_KEYWORD)
-PG_KEYWORD("system", SYSTEM_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("table", TABLE, RESERVED_KEYWORD)
-PG_KEYWORD("tables", TABLES, UNRESERVED_KEYWORD)
-PG_KEYWORD("tablesample", TABLESAMPLE, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("tablespace", TABLESPACE, UNRESERVED_KEYWORD)
-PG_KEYWORD("temp", TEMP, UNRESERVED_KEYWORD)
-PG_KEYWORD("template", TEMPLATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("temporary", TEMPORARY, UNRESERVED_KEYWORD)
-PG_KEYWORD("text", TEXT_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("then", THEN, RESERVED_KEYWORD)
-PG_KEYWORD("ties", TIES, UNRESERVED_KEYWORD)
-PG_KEYWORD("time", TIME, COL_NAME_KEYWORD)
-PG_KEYWORD("timestamp", TIMESTAMP, COL_NAME_KEYWORD)
-PG_KEYWORD("to", TO, RESERVED_KEYWORD)
-PG_KEYWORD("trailing", TRAILING, RESERVED_KEYWORD)
-PG_KEYWORD("transaction", TRANSACTION, UNRESERVED_KEYWORD)
-PG_KEYWORD("transform", TRANSFORM, UNRESERVED_KEYWORD)
-PG_KEYWORD("treat", TREAT, COL_NAME_KEYWORD)
-PG_KEYWORD("trigger", TRIGGER, UNRESERVED_KEYWORD)
-PG_KEYWORD("trim", TRIM, COL_NAME_KEYWORD)
-PG_KEYWORD("true", TRUE_P, RESERVED_KEYWORD)
-PG_KEYWORD("truncate", TRUNCATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("trusted", TRUSTED, UNRESERVED_KEYWORD)
-PG_KEYWORD("type", TYPE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("types", TYPES_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("uescape", UESCAPE, UNRESERVED_KEYWORD)
-PG_KEYWORD("unbounded", UNBOUNDED, UNRESERVED_KEYWORD)
-PG_KEYWORD("uncommitted", UNCOMMITTED, UNRESERVED_KEYWORD)
-PG_KEYWORD("unencrypted", UNENCRYPTED, UNRESERVED_KEYWORD)
-PG_KEYWORD("union", UNION, RESERVED_KEYWORD)
-PG_KEYWORD("unique", UNIQUE, RESERVED_KEYWORD)
-PG_KEYWORD("unknown", UNKNOWN, UNRESERVED_KEYWORD)
-PG_KEYWORD("unlisten", UNLISTEN, UNRESERVED_KEYWORD)
-PG_KEYWORD("unlogged", UNLOGGED, UNRESERVED_KEYWORD)
-PG_KEYWORD("until", UNTIL, UNRESERVED_KEYWORD)
-PG_KEYWORD("update", UPDATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("user", USER, RESERVED_KEYWORD)
-PG_KEYWORD("using", USING, RESERVED_KEYWORD)
-PG_KEYWORD("vacuum", VACUUM, UNRESERVED_KEYWORD)
-PG_KEYWORD("valid", VALID, UNRESERVED_KEYWORD)
-PG_KEYWORD("validate", VALIDATE, UNRESERVED_KEYWORD)
-PG_KEYWORD("validator", VALIDATOR, UNRESERVED_KEYWORD)
-PG_KEYWORD("value", VALUE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("values", VALUES, COL_NAME_KEYWORD)
-PG_KEYWORD("varchar", VARCHAR, COL_NAME_KEYWORD)
-PG_KEYWORD("variadic", VARIADIC, RESERVED_KEYWORD)
-PG_KEYWORD("varying", VARYING, UNRESERVED_KEYWORD)
-PG_KEYWORD("verbose", VERBOSE, TYPE_FUNC_NAME_KEYWORD)
-PG_KEYWORD("version", VERSION_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("view", VIEW, UNRESERVED_KEYWORD)
-PG_KEYWORD("views", VIEWS, UNRESERVED_KEYWORD)
-PG_KEYWORD("volatile", VOLATILE, UNRESERVED_KEYWORD)
-PG_KEYWORD("when", WHEN, RESERVED_KEYWORD)
-PG_KEYWORD("where", WHERE, RESERVED_KEYWORD)
-PG_KEYWORD("whitespace", WHITESPACE_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("window", WINDOW, RESERVED_KEYWORD)
-PG_KEYWORD("with", WITH, RESERVED_KEYWORD)
-PG_KEYWORD("within", WITHIN, UNRESERVED_KEYWORD)
-PG_KEYWORD("without", WITHOUT, UNRESERVED_KEYWORD)
-PG_KEYWORD("work", WORK, UNRESERVED_KEYWORD)
-PG_KEYWORD("wrapper", WRAPPER, UNRESERVED_KEYWORD)
-PG_KEYWORD("write", WRITE, UNRESERVED_KEYWORD)
-PG_KEYWORD("xml", XML_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("xmlattributes", XMLATTRIBUTES, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlconcat", XMLCONCAT, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlelement", XMLELEMENT, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlexists", XMLEXISTS, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlforest", XMLFOREST, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlnamespaces", XMLNAMESPACES, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlparse", XMLPARSE, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlpi", XMLPI, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlroot", XMLROOT, COL_NAME_KEYWORD)
-PG_KEYWORD("xmlserialize", XMLSERIALIZE, COL_NAME_KEYWORD)
-PG_KEYWORD("xmltable", XMLTABLE, COL_NAME_KEYWORD)
-PG_KEYWORD("year", YEAR_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("yes", YES_P, UNRESERVED_KEYWORD)
-PG_KEYWORD("zone", ZONE, UNRESERVED_KEYWORD)
+/* name, value, category, aliastype */
+PG_KEYWORD("abort", ABORT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("absolute", ABSOLUTE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("access", ACCESS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("action", ACTION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("add", ADD_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("admin", ADMIN, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("after", AFTER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("aggregate", AGGREGATE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("all", ALL, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("also", ALSO, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("alter", ALTER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("always", ALWAYS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("analyse", ANALYSE, RESERVED_KEYWORD, IMPLICIT_ALIAS)		/* British spelling */
+PG_KEYWORD("analyze", ANALYZE, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("and", AND, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("any", ANY, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("array", ARRAY, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("as", AS, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("asc", ASC, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("assertion", ASSERTION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("assignment", ASSIGNMENT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("asymmetric", ASYMMETRIC, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("at", AT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("attach", ATTACH, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("attribute", ATTRIBUTE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("authorization", AUTHORIZATION, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("backward", BACKWARD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("before", BEFORE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("begin", BEGIN_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("between", BETWEEN, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("bigint", BIGINT, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("binary", BINARY, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("bit", BIT, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("boolean", BOOLEAN_P, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("both", BOTH, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("by", BY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("cache", CACHE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("call", CALL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("called", CALLED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("cascade", CASCADE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("cascaded", CASCADED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("case", CASE, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("cast", CAST, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("catalog", CATALOG_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("chain", CHAIN, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("char", CHAR_P, COL_NAME_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("character", CHARACTER, COL_NAME_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("characteristics", CHARACTERISTICS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("check", CHECK, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("checkpoint", CHECKPOINT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("class", CLASS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("close", CLOSE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("cluster", CLUSTER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("coalesce", COALESCE, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("collate", COLLATE, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("collation", COLLATION, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("column", COLUMN, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("columns", COLUMNS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("comment", COMMENT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("comments", COMMENTS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("commit", COMMIT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("committed", COMMITTED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("concurrently", CONCURRENTLY, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("configuration", CONFIGURATION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("conflict", CONFLICT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("connection", CONNECTION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("constraint", CONSTRAINT, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("constraints", CONSTRAINTS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("content", CONTENT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("continue", CONTINUE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("conversion", CONVERSION_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("copy", COPY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("cost", COST, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("create", CREATE, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("cross", CROSS, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("csv", CSV, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("cube", CUBE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("current", CURRENT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("current_catalog", CURRENT_CATALOG, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("current_date", CURRENT_DATE, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("current_role", CURRENT_ROLE, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("current_schema", CURRENT_SCHEMA, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("current_time", CURRENT_TIME, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("current_timestamp", CURRENT_TIMESTAMP, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("current_user", CURRENT_USER, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("cursor", CURSOR, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("cycle", CYCLE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("data", DATA_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("database", DATABASE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("day", DAY_P, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("deallocate", DEALLOCATE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("dec", DEC, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("decimal", DECIMAL_P, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("declare", DECLARE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("default", DEFAULT, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("defaults", DEFAULTS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("deferrable", DEFERRABLE, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("deferred", DEFERRED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("definer", DEFINER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("delete", DELETE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("delimiter", DELIMITER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("delimiters", DELIMITERS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("depends", DEPENDS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("desc", DESC, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("detach", DETACH, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("dictionary", DICTIONARY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("disable", DISABLE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("discard", DISCARD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("distinct", DISTINCT, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("do", DO, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("document", DOCUMENT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("domain", DOMAIN_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("double", DOUBLE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("drop", DROP, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("each", EACH, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("else", ELSE, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("enable", ENABLE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("encoding", ENCODING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("encrypted", ENCRYPTED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("end", END_P, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("enum", ENUM_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("escape", ESCAPE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("event", EVENT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("except", EXCEPT, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("exclude", EXCLUDE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("excluding", EXCLUDING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("exclusive", EXCLUSIVE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("execute", EXECUTE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("exists", EXISTS, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("explain", EXPLAIN, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("expression", EXPRESSION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("extension", EXTENSION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("external", EXTERNAL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("extract", EXTRACT, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("false", FALSE_P, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("family", FAMILY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("fetch", FETCH, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("filter", FILTER, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("first", FIRST_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("float", FLOAT_P, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("following", FOLLOWING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("for", FOR, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("force", FORCE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("foreign", FOREIGN, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("forward", FORWARD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("freeze", FREEZE, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("from", FROM, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("full", FULL, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("function", FUNCTION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("functions", FUNCTIONS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("generated", GENERATED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("global", GLOBAL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("grant", GRANT, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("granted", GRANTED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("greatest", GREATEST, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("group", GROUP_P, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("grouping", GROUPING, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("groups", GROUPS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("handler", HANDLER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("having", HAVING, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("header", HEADER_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("hold", HOLD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("hour", HOUR_P, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("identity", IDENTITY_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("if", IF_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("ilike", ILIKE, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("immediate", IMMEDIATE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("immutable", IMMUTABLE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("implicit", IMPLICIT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("import", IMPORT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("in", IN_P, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("include", INCLUDE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("including", INCLUDING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("increment", INCREMENT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("index", INDEX, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("indexes", INDEXES, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("inherit", INHERIT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("inherits", INHERITS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("initially", INITIALLY, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("inline", INLINE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("inner", INNER_P, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("inout", INOUT, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("input", INPUT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("insensitive", INSENSITIVE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("insert", INSERT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("instead", INSTEAD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("int", INT_P, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("integer", INTEGER, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("intersect", INTERSECT, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("interval", INTERVAL, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("into", INTO, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("invoker", INVOKER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("is", IS, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("isnull", ISNULL, TYPE_FUNC_NAME_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("isolation", ISOLATION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("join", JOIN, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("key", KEY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("label", LABEL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("language", LANGUAGE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("large", LARGE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("last", LAST_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("lateral", LATERAL_P, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("leading", LEADING, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("leakproof", LEAKPROOF, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("least", LEAST, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("left", LEFT, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("level", LEVEL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("like", LIKE, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("limit", LIMIT, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("listen", LISTEN, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("load", LOAD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("local", LOCAL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("localtime", LOCALTIME, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("localtimestamp", LOCALTIMESTAMP, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("location", LOCATION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("lock", LOCK_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("locked", LOCKED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("logged", LOGGED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("mapping", MAPPING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("match", MATCH, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("materialized", MATERIALIZED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("maxvalue", MAXVALUE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("method", METHOD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("minute", MINUTE_P, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("minvalue", MINVALUE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("mode", MODE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("month", MONTH_P, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("move", MOVE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("name", NAME_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("names", NAMES, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("national", NATIONAL, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("natural", NATURAL, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("nchar", NCHAR, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("new", NEW, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("next", NEXT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("nfc", NFC, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("nfd", NFD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("nfkc", NFKC, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("nfkd", NFKD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("no", NO, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("none", NONE, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("normalize", NORMALIZE, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("normalized", NORMALIZED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("not", NOT, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("nothing", NOTHING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("notify", NOTIFY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("notnull", NOTNULL, TYPE_FUNC_NAME_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("nowait", NOWAIT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("null", NULL_P, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("nullif", NULLIF, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("nulls", NULLS_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("numeric", NUMERIC, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("object", OBJECT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("of", OF, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("off", OFF, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("offset", OFFSET, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("oids", OIDS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("old", OLD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("on", ON, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("only", ONLY, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("operator", OPERATOR, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("option", OPTION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("options", OPTIONS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("or", OR, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("order", ORDER, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("ordinality", ORDINALITY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("others", OTHERS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("out", OUT_P, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("outer", OUTER_P, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("over", OVER, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("overlaps", OVERLAPS, TYPE_FUNC_NAME_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("overlay", OVERLAY, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("overriding", OVERRIDING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("owned", OWNED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("owner", OWNER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("parallel", PARALLEL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("parser", PARSER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("partial", PARTIAL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("partition", PARTITION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("passing", PASSING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("password", PASSWORD, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("placing", PLACING, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("plans", PLANS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("policy", POLICY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("position", POSITION, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("preceding", PRECEDING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("precision", PRECISION, COL_NAME_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("prepare", PREPARE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("prepared", PREPARED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("preserve", PRESERVE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("primary", PRIMARY, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("prior", PRIOR, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("privileges", PRIVILEGES, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("procedural", PROCEDURAL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("procedure", PROCEDURE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("procedures", PROCEDURES, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("program", PROGRAM, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("publication", PUBLICATION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("quote", QUOTE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("range", RANGE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("read", READ, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("real", REAL, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("reassign", REASSIGN, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("recheck", RECHECK, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("recursive", RECURSIVE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("ref", REF, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("references", REFERENCES, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("referencing", REFERENCING, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("refresh", REFRESH, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("reindex", REINDEX, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("relative", RELATIVE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("release", RELEASE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("rename", RENAME, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("repeatable", REPEATABLE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("replace", REPLACE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("replica", REPLICA, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("reset", RESET, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("restart", RESTART, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("restrict", RESTRICT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("returning", RETURNING, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("returns", RETURNS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("revoke", REVOKE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("right", RIGHT, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("role", ROLE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("rollback", ROLLBACK, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("rollup", ROLLUP, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("routine", ROUTINE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("routines", ROUTINES, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("row", ROW, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("rows", ROWS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("rule", RULE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("savepoint", SAVEPOINT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("schema", SCHEMA, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("schemas", SCHEMAS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("scroll", SCROLL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("search", SEARCH, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("second", SECOND_P, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("security", SECURITY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("select", SELECT, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("sequence", SEQUENCE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("sequences", SEQUENCES, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("serializable", SERIALIZABLE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("server", SERVER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("session", SESSION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("session_user", SESSION_USER, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("set", SET, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("setof", SETOF, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("sets", SETS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("share", SHARE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("show", SHOW, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("similar", SIMILAR, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("simple", SIMPLE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("skip", SKIP, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("smallint", SMALLINT, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("snapshot", SNAPSHOT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("some", SOME, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("sql", SQL_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("stable", STABLE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("standalone", STANDALONE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("start", START, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("statement", STATEMENT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("statistics", STATISTICS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("stdin", STDIN, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("stdout", STDOUT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("storage", STORAGE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("stored", STORED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("strict", STRICT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("strip", STRIP_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("subscription", SUBSCRIPTION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("substring", SUBSTRING, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("support", SUPPORT, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("symmetric", SYMMETRIC, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("sysid", SYSID, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("system", SYSTEM_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("table", TABLE, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("tables", TABLES, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("tablesample", TABLESAMPLE, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("tablespace", TABLESPACE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("temp", TEMP, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("template", TEMPLATE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("temporary", TEMPORARY, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("text", TEXT_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("then", THEN, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("ties", TIES, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("time", TIME, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("timestamp", TIMESTAMP, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("to", TO, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("trailing", TRAILING, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("transaction", TRANSACTION, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("transform", TRANSFORM, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("treat", TREAT, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("trigger", TRIGGER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("trim", TRIM, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("true", TRUE_P, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("truncate", TRUNCATE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("trusted", TRUSTED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("type", TYPE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("types", TYPES_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("uescape", UESCAPE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("unbounded", UNBOUNDED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("uncommitted", UNCOMMITTED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("unencrypted", UNENCRYPTED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("union", UNION, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("unique", UNIQUE, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("unknown", UNKNOWN, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("unlisten", UNLISTEN, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("unlogged", UNLOGGED, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("until", UNTIL, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("update", UPDATE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("user", USER, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("using", USING, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("vacuum", VACUUM, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("valid", VALID, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("validate", VALIDATE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("validator", VALIDATOR, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("value", VALUE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("values", VALUES, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("varchar", VARCHAR, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("variadic", VARIADIC, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("varying", VARYING, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("verbose", VERBOSE, TYPE_FUNC_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("version", VERSION_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("view", VIEW, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("views", VIEWS, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("volatile", VOLATILE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("when", WHEN, RESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("where", WHERE, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("whitespace", WHITESPACE_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("window", WINDOW, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("with", WITH, RESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("within", WITHIN, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("without", WITHOUT, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("work", WORK, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("wrapper", WRAPPER, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("write", WRITE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xml", XML_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlattributes", XMLATTRIBUTES, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlconcat", XMLCONCAT, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlelement", XMLELEMENT, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlexists", XMLEXISTS, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlforest", XMLFOREST, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlnamespaces", XMLNAMESPACES, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlparse", XMLPARSE, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlpi", XMLPI, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlroot", XMLROOT, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmlserialize", XMLSERIALIZE, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("xmltable", XMLTABLE, COL_NAME_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("year", YEAR_P, UNRESERVED_KEYWORD, EXPLICIT_ALIAS)
+PG_KEYWORD("yes", YES_P, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
+PG_KEYWORD("zone", ZONE, UNRESERVED_KEYWORD, IMPLICIT_ALIAS)
diff --git a/src/interfaces/ecpg/preproc/keywords.c b/src/interfaces/ecpg/preproc/keywords.c
index f82764aeb9..624b8bfe60 100644
--- a/src/interfaces/ecpg/preproc/keywords.c
+++ b/src/interfaces/ecpg/preproc/keywords.c
@@ -29,7 +29,7 @@
 #include "preproc_extern.h"
 #include "preproc.h"
 
-#define PG_KEYWORD(kwname, value, category) value,
+#define PG_KEYWORD(kwname, value, category, aliastype) value,
 
 const uint16 SQLScanKeywordTokens[] = {
 #include "parser/kwlist.h"
diff --git a/src/tools/gen_keywordlist.pl b/src/tools/gen_keywordlist.pl
index e9250b8fb2..ad433d416e 100644
--- a/src/tools/gen_keywordlist.pl
+++ b/src/tools/gen_keywordlist.pl
@@ -93,11 +93,27 @@ EOM
 
 # Parse input file for keyword names.
 my @keywords;
+my @implicit_alias;
+my %transform = ( IMPLICIT_ALIAS => 'true', EXPLICIT_ALIAS => 'false');
 while (<$kif>)
 {
 	if (/^PG_KEYWORD\("(\w+)"/)
 	{
-		push @keywords, $1;
+		my $kword = $1;
+		push @keywords, $kword;
+
+		if (/^PG_KEYWORD\("\w+", .*, (IMPLICIT_ALIAS|EXPLICIT_ALIAS)\)/)
+		{
+			push @implicit_alias, $transform{$1};
+		}
+		else
+		{
+			# parser/kwlist.h lists each keyword as either an implicit or an
+			# explicit alias, but other kwlist files do not, and for them, it
+			# won't matter what we use here as long as it is a valid boolean,
+			# so we arbitrarily use 'true'.
+			push @implicit_alias, 'true';
+		}
 	}
 }
 
@@ -153,6 +169,17 @@ foreach my $name (@keywords)
 
 print $kwdef "};\n\n";
 
+# Emit an array of boolean as implicit alias values
+
+printf $kwdef "static const bool %s_kw_is_implicit[] = {\n", $varname;
+
+foreach my $bool (@implicit_alias)
+{
+	print $kwdef "\t$bool,\n";
+}
+
+print $kwdef "};\n\n";
+
 # Emit a macro defining the number of keywords.
 # (In some places it's useful to have access to that as a constant.)
 
@@ -173,6 +200,7 @@ printf $kwdef "static " if !$extern;
 printf $kwdef "const ScanKeywordList %s = {\n", $varname;
 printf $kwdef qq|\t%s_kw_string,\n|,            $varname;
 printf $kwdef qq|\t%s_kw_offsets,\n|,           $varname;
+printf $kwdef qq|\t%s_kw_is_implicit,\n|,       $varname;
 printf $kwdef qq|\t%s,\n|,                      $funcname;
 printf $kwdef qq|\t%s_NUM_KEYWORDS,\n|,         uc $varname;
 printf $kwdef qq|\t%d\n|,                       $max_len;
-- 
2.21.1 (Apple Git-122.3)

v7-0003-Updating-prorows-for-pg_get_keywords.patchapplication/octet-stream; name=v7-0003-Updating-prorows-for-pg_get_keywords.patch; x-unix-mode=0644Download
From df2979deaf91c18ce6778c7a4b083eefa93e85ca Mon Sep 17 00:00:00 2001
From: Mark Dilger <mark.dilger@enterprisedb.com>
Date: Wed, 2 Sep 2020 12:40:20 -0700
Subject: [PATCH v7 3/3] Updating prorows for pg_get_keywords()

The number of keywords returned by pg_get_keywords() is known
precisely.  It happens to be 450 as of this commit.  It might slowly
change with future commits, but it is not 400 as pg_proc.dat was
claiming, and there does not seem to be any advantage to leaving it
at 400.

Nothing in this patch series depends on this one patch being committed.
If the committer who picks up this patch series wants to just throw
this third patch file away, that works fine.
---
 src/include/catalog/pg_proc.dat | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index b4c4fe8a5c..8fdbd75ad1 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -3675,7 +3675,7 @@
   prosrc => 'pg_get_function_arg_default' },
 
 { oid => '1686', descr => 'list of SQL keywords',
-  proname => 'pg_get_keywords', procost => '10', prorows => '400',
+  proname => 'pg_get_keywords', procost => '10', prorows => '450',
   proretset => 't', provolatile => 's', prorettype => 'record',
   proargtypes => '', proallargtypes => '{text,char,text,text}',
   proargmodes => '{o,o,o,o}', proargnames => '{word,catcode,catdesc,aliastype}',
-- 
2.21.1 (Apple Git-122.3)

#55John Naylor
john.naylor@2ndquadrant.com
In reply to: Mark Dilger (#54)
Re: factorial function/phase out postfix operators?

On Thu, Sep 3, 2020 at 11:50 AM Mark Dilger
<mark.dilger@enterprisedb.com> wrote:

[v7]

Ok, I've marked it ready for committer.

--
John Naylor https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

#56Robert Haas
robertmhaas@gmail.com
In reply to: Mark Dilger (#54)
Re: factorial function/phase out postfix operators?

On Thu, Sep 3, 2020 at 11:50 AM Mark Dilger
<mark.dilger@enterprisedb.com> wrote:

Since newer pg_dump binaries can be used to dump data from older servers, and since users might then load that dump back into an older server, I think doing anything stronger than a pg_log_warning() would be incorrect. I did not find precedents under comparable circumstances for taking stronger actions than pg_log_warning. I assume we can't, for example, omit the operator from the dump, nor can we abort the process.

I'm not sure that this is the right solution. Generally, the
recommendation is that you should use the pg_dump that corresponds to
the server version where you want to do the reload, so if you're
hoping to dump 9.6 and restore on 11, you should be using the pg_dump
from 11, not 14. So my thought would be that if there are user-defined
postfix operators, pg_dump ought to error out. However, that could be
inconvenient for people who are using pg_dump in ways that are maybe
not what we would recommend but which may happen to work but for this
issue, so I'm not sure. On the third hand, though, we think that there
are very few user-defined postfix operators out there, so if we just
give an error, we probably won't be inconveniencing many people.

I'm not sure who is going to commit this work, and that person may
have a different preference than me. However, if it's me, I'd like to
see the removal of the existing postfix operators broken off into its
own patch, separate from the removal of the underlying facility to
have postfix operators.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#57Tom Lane
tgl@sss.pgh.pa.us
In reply to: Robert Haas (#56)
Re: factorial function/phase out postfix operators?

Robert Haas <robertmhaas@gmail.com> writes:

On Thu, Sep 3, 2020 at 11:50 AM Mark Dilger
<mark.dilger@enterprisedb.com> wrote:

Since newer pg_dump binaries can be used to dump data from older servers, and since users might then load that dump back into an older server, I think doing anything stronger than a pg_log_warning() would be incorrect. I did not find precedents under comparable circumstances for taking stronger actions than pg_log_warning. I assume we can't, for example, omit the operator from the dump, nor can we abort the process.

I'm not sure that this is the right solution. Generally, the
recommendation is that you should use the pg_dump that corresponds to
the server version where you want to do the reload, so if you're
hoping to dump 9.6 and restore on 11, you should be using the pg_dump
from 11, not 14. So my thought would be that if there are user-defined
postfix operators, pg_dump ought to error out. However, that could be
inconvenient for people who are using pg_dump in ways that are maybe
not what we would recommend but which may happen to work but for this
issue, so I'm not sure. On the third hand, though, we think that there
are very few user-defined postfix operators out there, so if we just
give an error, we probably won't be inconveniencing many people.

My inclination is to simply not change pg_dump. There is no need to break
the use-case of loading the output back into the server version it came
from, if we don't have to. If the output is getting loaded into a server
that lacks postfix operators, that server can throw the error. There's no
real gain in having pg_dump prejudge the issue.

regards, tom lane

#58Mark Dilger
mark.dilger@enterprisedb.com
In reply to: Tom Lane (#57)
Re: factorial function/phase out postfix operators?

On Sep 11, 2020, at 8:36 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Robert Haas <robertmhaas@gmail.com> writes:

On Thu, Sep 3, 2020 at 11:50 AM Mark Dilger
<mark.dilger@enterprisedb.com> wrote:

Since newer pg_dump binaries can be used to dump data from older servers, and since users might then load that dump back into an older server, I think doing anything stronger than a pg_log_warning() would be incorrect. I did not find precedents under comparable circumstances for taking stronger actions than pg_log_warning. I assume we can't, for example, omit the operator from the dump, nor can we abort the process.

I'm not sure that this is the right solution. Generally, the
recommendation is that you should use the pg_dump that corresponds to
the server version where you want to do the reload, so if you're
hoping to dump 9.6 and restore on 11, you should be using the pg_dump
from 11, not 14. So my thought would be that if there are user-defined
postfix operators, pg_dump ought to error out. However, that could be
inconvenient for people who are using pg_dump in ways that are maybe
not what we would recommend but which may happen to work but for this
issue, so I'm not sure. On the third hand, though, we think that there
are very few user-defined postfix operators out there, so if we just
give an error, we probably won't be inconveniencing many people.

My inclination is to simply not change pg_dump. There is no need to break
the use-case of loading the output back into the server version it came
from, if we don't have to. If the output is getting loaded into a server
that lacks postfix operators, that server can throw the error. There's no
real gain in having pg_dump prejudge the issue.

I think some kind of indication that the dump won't be loadable is useful if they're planning to move the dump file across an expensive link, or if they intend to blow away the old data directory to make room for the new. Whether that indication should be in the form of a warning or an error is less clear to me. Whatever we do here, I think it sets a precedent for how such situations are handled in the future, so maybe focusing overmuch on the postfix operator issue is less helpful than on the broader concept. What, for example, would we do if we someday dropped GiST support? Print a warning when dumping a database with GiST indexes? Omit the indexes? Abort the dump?

The docs at https://www.postgresql.org/docs/12/app-pgdump.html say:

Because pg_dump is used to transfer data to newer versions of PostgreSQL, the output of pg_dump can be expected to load into PostgreSQL server versions newer than pg_dump's version.

<snip>

Also, it is not guaranteed that pg_dump's output can be loaded into a server of an older major version — not even if the dump was taken from a server of that version.

I think somewhere around here the docs need to call out what happens when the older major version supported a feature that has been dropped from the newer major version.


Mark Dilger
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#59Tom Lane
tgl@sss.pgh.pa.us
In reply to: Mark Dilger (#58)
Re: factorial function/phase out postfix operators?

Mark Dilger <mark.dilger@enterprisedb.com> writes:

On Sep 11, 2020, at 8:36 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

My inclination is to simply not change pg_dump. There is no need to break
the use-case of loading the output back into the server version it came
from, if we don't have to. If the output is getting loaded into a server
that lacks postfix operators, that server can throw the error. There's no
real gain in having pg_dump prejudge the issue.

I think some kind of indication that the dump won't be loadable is
useful if they're planning to move the dump file across an expensive
link, or if they intend to blow away the old data directory to make room
for the new. Whether that indication should be in the form of a warning
or an error is less clear to me.

I think definitely not an error, because that breaks a plausible (even if
not recommended) use-case.

Whatever we do here, I think it sets a precedent for how such situations
are handled in the future, so maybe focusing overmuch on the postfix
operator issue is less helpful than on the broader concept. What, for
example, would we do if we someday dropped GiST support?

I'm not sure that there is or should be a one-size-fits-all policy.
We do actually have multiple precedents already:

* DefineIndex substitutes "gist" for "rtree" to allow transparent updating
of dumps from DBs that used the old rtree AM.

* Up till very recently (84eca14bc), ResolveOpClass had similar hacks to
substitute for old opclass names.

* bb03010b9 and e58a59975 got rid of other server-side hacks for
converting old dump files.

So generally the preference is to make the server deal with conversion
issues; and this must be so, since what you have to work with may be a
dump taken with an old pg_dump. In this case, though, it doesn't seem
like there's any plausible way for the server to translate old DDL.

As for the pg_dump side, aside from the WITH OIDS precedent you mentioned,
there was till recently (d9fa17aa7) code to deal with unconvertible
pre-7.1 aggregates. That code issued a pg_log_warning and then ignored
(didn't dump) the aggregate. I think it didn't have much choice about
the latter step because, if memory serves, there simply wasn't any way to
represent those old aggregates in the new CREATE AGGREGATE syntax; so we
couldn't leave it to the server to decide whether to throw error or not.
(It's also possible, given how far back that was, that we simply weren't
being very considerate of upgrade issues. It's old enough that I would
not take it as great precedent. But it is a precedent.)

The behavior of WITH OIDS is to issue a pg_log_warning and then ignore
the property. I do not much care for this, although I see the point that
we don't want to stick WITH OIDS into the CREATE TABLE because then the
CREATE would fail, leaving the dump completely unusable on newer servers.
My choice would have been to write CREATE TABLE without that option and
then add ALTER TABLE ... WITH OIDS. In this way the dump script does
what it should when restoring into an old server, while if you load into
a new server you hear about it --- and you can ignore the error if you
want.

I think the right thing for postfix operators is probably to issue
pg_log_warning and then dump the object anyway.

regards, tom lane

#60Mark Dilger
mark.dilger@enterprisedb.com
In reply to: Tom Lane (#59)
Re: factorial function/phase out postfix operators?

On Sep 11, 2020, at 11:25 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Mark Dilger <mark.dilger@enterprisedb.com> writes:

On Sep 11, 2020, at 8:36 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

My inclination is to simply not change pg_dump. There is no need to break
the use-case of loading the output back into the server version it came
from, if we don't have to. If the output is getting loaded into a server
that lacks postfix operators, that server can throw the error. There's no
real gain in having pg_dump prejudge the issue.

I think some kind of indication that the dump won't be loadable is
useful if they're planning to move the dump file across an expensive
link, or if they intend to blow away the old data directory to make room
for the new. Whether that indication should be in the form of a warning
or an error is less clear to me.

I think definitely not an error, because that breaks a plausible (even if
not recommended) use-case.

Whatever we do here, I think it sets a precedent for how such situations
are handled in the future, so maybe focusing overmuch on the postfix
operator issue is less helpful than on the broader concept. What, for
example, would we do if we someday dropped GiST support?

I'm not sure that there is or should be a one-size-fits-all policy.
We do actually have multiple precedents already:

* DefineIndex substitutes "gist" for "rtree" to allow transparent updating
of dumps from DBs that used the old rtree AM.

* Up till very recently (84eca14bc), ResolveOpClass had similar hacks to
substitute for old opclass names.

* bb03010b9 and e58a59975 got rid of other server-side hacks for
converting old dump files.

So generally the preference is to make the server deal with conversion
issues; and this must be so, since what you have to work with may be a
dump taken with an old pg_dump. In this case, though, it doesn't seem
like there's any plausible way for the server to translate old DDL.

As for the pg_dump side, aside from the WITH OIDS precedent you mentioned,
there was till recently (d9fa17aa7) code to deal with unconvertible
pre-7.1 aggregates. That code issued a pg_log_warning and then ignored
(didn't dump) the aggregate. I think it didn't have much choice about
the latter step because, if memory serves, there simply wasn't any way to
represent those old aggregates in the new CREATE AGGREGATE syntax; so we
couldn't leave it to the server to decide whether to throw error or not.
(It's also possible, given how far back that was, that we simply weren't
being very considerate of upgrade issues. It's old enough that I would
not take it as great precedent. But it is a precedent.)

The behavior of WITH OIDS is to issue a pg_log_warning and then ignore
the property. I do not much care for this, although I see the point that
we don't want to stick WITH OIDS into the CREATE TABLE because then the
CREATE would fail, leaving the dump completely unusable on newer servers.
My choice would have been to write CREATE TABLE without that option and
then add ALTER TABLE ... WITH OIDS. In this way the dump script does
what it should when restoring into an old server, while if you load into
a new server you hear about it --- and you can ignore the error if you
want.

I think the right thing for postfix operators is probably to issue
pg_log_warning and then dump the object anyway.

That happens to be the patch behavior as it stands now.

Another option would be to have pg_dump take a strictness mode option. I don't think the option should have anything to do with postfix operators specifically, but be more general like --dump-incompatible-objects vs. --omit-incompatible-objects vs. --error-on-incompatible-objects vs. --do-your-best-to-fixup-incompatible-objects, with one of those being the default (and with all of them having better names). If --error-on-incompatible-objects were the default, that would behave as Robert recommended upthread.

I can totally see an objection to the added complexity of such options, so I'm really just putting this out on the list for comment.


Mark Dilger
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#61Robert Haas
robertmhaas@gmail.com
In reply to: Mark Dilger (#60)
Re: factorial function/phase out postfix operators?

On Fri, Sep 11, 2020 at 3:23 PM Mark Dilger
<mark.dilger@enterprisedb.com> wrote:

Another option would be to have pg_dump take a strictness mode option. I don't think the option should have anything to do with postfix operators specifically, but be more general like --dump-incompatible-objects vs. --omit-incompatible-objects vs. --error-on-incompatible-objects vs. --do-your-best-to-fixup-incompatible-objects, with one of those being the default (and with all of them having better names). If --error-on-incompatible-objects were the default, that would behave as Robert recommended upthread.

I can totally see an objection to the added complexity of such options, so I'm really just putting this out on the list for comment.

I'm not opposed to Tom's proposal. I just wanted to raise the issue
for discussion.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#62Mark Dilger
mark.dilger@enterprisedb.com
In reply to: Robert Haas (#61)
Re: factorial function/phase out postfix operators?

On Sep 11, 2020, at 12:54 PM, Robert Haas <robertmhaas@gmail.com> wrote:

On Fri, Sep 11, 2020 at 3:23 PM Mark Dilger
<mark.dilger@enterprisedb.com> wrote:

Another option would be to have pg_dump take a strictness mode option. I don't think the option should have anything to do with postfix operators specifically, but be more general like --dump-incompatible-objects vs. --omit-incompatible-objects vs. --error-on-incompatible-objects vs. --do-your-best-to-fixup-incompatible-objects, with one of those being the default (and with all of them having better names). If --error-on-incompatible-objects were the default, that would behave as Robert recommended upthread.

I can totally see an objection to the added complexity of such options, so I'm really just putting this out on the list for comment.

I'm not opposed to Tom's proposal. I just wanted to raise the issue
for discussion.

Ah, ok. I don't feel any need for changes, either. I'll leave the patch as it stands now.


Mark Dilger
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#63Tom Lane
tgl@sss.pgh.pa.us
In reply to: Mark Dilger (#62)
Re: factorial function/phase out postfix operators?

Mark Dilger <mark.dilger@enterprisedb.com> writes:

On Sep 11, 2020, at 12:54 PM, Robert Haas <robertmhaas@gmail.com> wrote:

On Fri, Sep 11, 2020 at 3:23 PM Mark Dilger
<mark.dilger@enterprisedb.com> wrote:

Another option would be to have pg_dump take a strictness mode option. I don't think the option should have anything to do with postfix operators specifically, but be more general like --dump-incompatible-objects vs. --omit-incompatible-objects vs. --error-on-incompatible-objects vs. --do-your-best-to-fixup-incompatible-objects, with one of those being the default (and with all of them having better names). If --error-on-incompatible-objects were the default, that would behave as Robert recommended upthread.
I can totally see an objection to the added complexity of such options, so I'm really just putting this out on the list for comment.

I'm not opposed to Tom's proposal. I just wanted to raise the issue
for discussion.

Ah, ok. I don't feel any need for changes, either. I'll leave the
patch as it stands now.

We're in violent agreement it seems.

At some point it might be worth doing something like what Mark suggests
above, but this patch shouldn't be tasked with it. In any case, since
pg_dump does not know what the target server version really is, it's
going to be hard for it to authoritatively distinguish what will work
or not.

regards, tom lane

#64Tom Lane
tgl@sss.pgh.pa.us
In reply to: Robert Haas (#56)
Re: factorial function/phase out postfix operators?

Robert Haas <robertmhaas@gmail.com> writes:

I'm not sure who is going to commit this work, and that person may
have a different preference than me. However, if it's me, I'd like to
see the removal of the existing postfix operators broken off into its
own patch, separate from the removal of the underlying facility to
have postfix operators.

I've pushed a subset of the v7-0001 patch to meet Robert's preference.
Continuing to look at the rest of it.

regards, tom lane

#65Tom Lane
tgl@sss.pgh.pa.us
In reply to: Tom Lane (#63)
Re: factorial function/phase out postfix operators?

So I've finished up applying 0001 and started to look at 0002
... and I find the terminology you've chosen to be just really
opaque and confusing. "aliastype" being "implicit" or "explicit"
is not going to make any sense to anyone until they read the
manual, and it probably still won't make sense after that.

In the first place, the terminology we use for these things
is usually "column label", not "alias"; see e.g.
https://www.postgresql.org/docs/devel/queries-select-lists.html#QUERIES-COLUMN-LABELS
Likewise, gram.y itself refers to the construct as a ColLabel.
Aliases are things that appear in the FROM clause.

In the second place, "implicit" vs "explicit" just doesn't make
any sense to me. You could maybe say that the AS is implicit
when you omit it, but the column label is surely not implicit;
it's right there where you wrote it.

I confess to not having paid very close attention to this thread
lately, but the last I'd noticed the terminology proposed for
internal use was "bare column label", which I think is much better.
As for what to expose in pg_get_keywords, I think something like
"label_requires_as bool" would be immediately understandable.
If you really want it to be an enum sort of thing, maybe the output
column title could be "collabel" with values "bare" or "requires_AS".

So I'm thinking about making these changes in gram.y:

ImplicitAlias -> BareColLabel
implicit_alias_keyword -> bare_label_keyword

and corresponding terminology changes elsewhere.

Thoughts?

regards, tom lane

#66Mark Dilger
mark.dilger@enterprisedb.com
In reply to: Tom Lane (#65)
Re: factorial function/phase out postfix operators?

On Sep 18, 2020, at 8:29 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

So I've finished up applying 0001 and started to look at 0002
... and I find the terminology you've chosen to be just really
opaque and confusing. "aliastype" being "implicit" or "explicit"
is not going to make any sense to anyone until they read the
manual, and it probably still won't make sense after that.

In the first place, the terminology we use for these things
is usually "column label", not "alias"; see e.g.
https://www.postgresql.org/docs/devel/queries-select-lists.html#QUERIES-COLUMN-LABELS
Likewise, gram.y itself refers to the construct as a ColLabel.
Aliases are things that appear in the FROM clause.

In the second place, "implicit" vs "explicit" just doesn't make
any sense to me. You could maybe say that the AS is implicit
when you omit it, but the column label is surely not implicit;
it's right there where you wrote it.

I confess to not having paid very close attention to this thread
lately, but the last I'd noticed the terminology proposed for
internal use was "bare column label", which I think is much better.
As for what to expose in pg_get_keywords, I think something like
"label_requires_as bool" would be immediately understandable.
If you really want it to be an enum sort of thing, maybe the output
column title could be "collabel" with values "bare" or "requires_AS".

So I'm thinking about making these changes in gram.y:

ImplicitAlias -> BareColLabel
implicit_alias_keyword -> bare_label_keyword

and corresponding terminology changes elsewhere.

That sounds ok to me.


Mark Dilger
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#67Robert Haas
robertmhaas@gmail.com
In reply to: Tom Lane (#65)
Re: factorial function/phase out postfix operators?

On Fri, Sep 18, 2020 at 11:29 AM Tom Lane <tgl@sss.pgh.pa.us> wrote:

I confess to not having paid very close attention to this thread
lately, but the last I'd noticed the terminology proposed for
internal use was "bare column label", which I think is much better.

I agree.

As for what to expose in pg_get_keywords, I think something like
"label_requires_as bool" would be immediately understandable.
If you really want it to be an enum sort of thing, maybe the output
column title could be "collabel" with values "bare" or "requires_AS".

It's sort of possible to be confused by "label requires as" since "as"
is being used as a known but isn't really one generally speaking, but
we can't very well quote it so I don't know how to make it more clear.

So I'm thinking about making these changes in gram.y:

ImplicitAlias -> BareColLabel
implicit_alias_keyword -> bare_label_keyword

and corresponding terminology changes elsewhere.

+1.

Thanks for picking this up; I am pretty excited about this.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#68Tom Lane
tgl@sss.pgh.pa.us
In reply to: Robert Haas (#67)
Re: factorial function/phase out postfix operators?

Robert Haas <robertmhaas@gmail.com> writes:

On Fri, Sep 18, 2020 at 11:29 AM Tom Lane <tgl@sss.pgh.pa.us> wrote:

As for what to expose in pg_get_keywords, I think something like
"label_requires_as bool" would be immediately understandable.
If you really want it to be an enum sort of thing, maybe the output
column title could be "collabel" with values "bare" or "requires_AS".

It's sort of possible to be confused by "label requires as" since "as"
is being used as a known but isn't really one generally speaking, but
we can't very well quote it so I don't know how to make it more clear.

After re-reading the description of pg_get_keywords, I was reminded that
what it outputs now is intended to provide both a machine-friendly
description of the keyword category ("catcode") and a human-friendly
description ("catdesc"). So we really should do likewise for the
label property. What I now propose is to add two output columns:

barelabel bool (t or f, obviously)
baredesc text ("can be bare label" or "requires AS", possibly localized)

Feel free to bikeshed on those details.

regards, tom lane

#69Robert Haas
robertmhaas@gmail.com
In reply to: Tom Lane (#68)
Re: factorial function/phase out postfix operators?

On Fri, Sep 18, 2020 at 2:11 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:

After re-reading the description of pg_get_keywords, I was reminded that
what it outputs now is intended to provide both a machine-friendly
description of the keyword category ("catcode") and a human-friendly
description ("catdesc"). So we really should do likewise for the
label property. What I now propose is to add two output columns:

barelabel bool (t or f, obviously)
baredesc text ("can be bare label" or "requires AS", possibly localized)

That might be over-engineered in a vacuum, but it seems like it may be
cleaner to stick with the existing precedent than to diverge from it.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#70Tom Lane
tgl@sss.pgh.pa.us
In reply to: Robert Haas (#69)
Re: factorial function/phase out postfix operators?

Robert Haas <robertmhaas@gmail.com> writes:

On Fri, Sep 18, 2020 at 2:11 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:

What I now propose is to add two output columns:

barelabel bool (t or f, obviously)
baredesc text ("can be bare label" or "requires AS", possibly localized)

That might be over-engineered in a vacuum, but it seems like it may be
cleaner to stick with the existing precedent than to diverge from it.

Yeah, my recollection of the pg_get_keywords design is that we couldn't
agree on whether to emit a machine-friendly description or a
human-friendly one, so we compromised by doing both :-(. But the same
factors exist with this addition --- you can make an argument for
preferring either boolean or text output.

regards, tom lane

#71Tom Lane
tgl@sss.pgh.pa.us
In reply to: Tom Lane (#70)
Re: factorial function/phase out postfix operators?

Pushed with the discussed terminological changes and some other
fooling about, including fixing the documentation.

regards, tom lane

#72Robert Haas
robertmhaas@gmail.com
In reply to: Tom Lane (#71)
Re: factorial function/phase out postfix operators?

On Fri, Sep 18, 2020 at 4:48 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:

Pushed with the discussed terminological changes and some other
fooling about, including fixing the documentation.

Awesome. Thanks!

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#73Tom Lane
tgl@sss.pgh.pa.us
In reply to: John Naylor (#39)
Re: factorial function/phase out postfix operators?

John Naylor <john.naylor@2ndquadrant.com> writes:

I believe it's actually "lower than Op", and since POSTFIXOP is gone
it doesn't seem to matter how low it is. In fact, I found that the
lines with INDENT and UNBOUNDED now work as the lowest precedence
declarations. Maybe that's worth something?

Following on Peter E.'s example upthread, GENERATED can be removed
from precedence, and I also found the same is true for PRESERVE and
STRIP_P.

Now that the main patch is pushed, I went back to revisit this precedence
issue. I'm afraid to move the precedence of IDENT as much as you suggest
here. The comment for opt_existing_window_name says that it's expecting
the precedence of IDENT to be just below that of Op. If there's daylight
in between, that could result in funny behavior for use of some of the
unreserved words with other precedence levels in this context.

However, I concur that we ought to be able to remove the explicit
precedences for GENERATED, NULL_P, PRESERVE, and STRIP_P, so I did that.

An interesting point is that it's actually possible to remove the
precedence declaration for IDENT itself (at least, that does not
create any bison errors; I did not do any behavioral testing).
I believe what we had that for originally was to control the precedence
behavior of the "target_el: a_expr IDENT" rule, and now that that
rule doesn't end with IDENT, its behavior isn't governed by that.
But I think we're best off to keep the precedence assignment, as
a place to hang the precedences of PARTITION etc.

regards, tom lane