Hi Jian,

> ParseFuncOrColumn cleanly handles (f).prev by translating it to prev(f)
as a
> regular function call. However, if a dedicated window navigation function
> exists, this translation creates ambiguity -- it becomes unclear whether
> prev(f) is window navigation or a normal function call.

Agreed, and that is the reason I would rather not have a dedicated
navigation function at all.  With navigation handled purely as syntax,
(f).prev never has to compete with it: attribute notation just falls
through to an ordinary function (prev(f)), the same inside and outside a
DEFINE clause.  That is Tatsuo's and my preferred option (a), so I will
settle on it.

> Cases with additional dots (e.g., public.prev(arg)) should also be treated
> as normal function calls, IMHO.

Yes.  A schema-qualified name is the explicit escape hatch to an ordinary
function; navigation is recognized only for an unqualified, single-element
name.

> As a result, only prev(arg) and prev(arg, offset) are recognized as
special
> window navigation syntax, despite being visually identical to a function
> call.

Right -- that is exactly the surface I want to land on: the dotless
prev(...)/next(...)/first(...)/last(...) forms are navigation, everything
else is an ordinary function.

> Summary:
> Dedicated window navigation functions should be removed entirely.  Window
> navigation should be limited to a single syntactic form (no dots) -- one
> that *looks* like a function call but is parsed as syntax.

That is the direction I will take the tree.  So the three of us have
converged.

> This is not unprecedented; there are many existing cases where something
> appears to be a function call but is actually a syntax form, for example:
>
> SELECT json_object('{}');
>  json_object
> -------------
>  {}
> (1 row)
>
> SELECT public.json_object('{}');
> ERROR:  function public.json_object(unknown) does not exist
> LINE 1: SELECT public.json_object('{}');
>                ^
>
> So I think in the DEFINE context, it makes sense for some form that looks
> like a function call to actually be syntax.

The json_object parallel is exact at the user-visible level, but I want to
flag that the implementation has to differ underneath -- and that is
actually why navigation is not done the json_object way.

json_object can live in the grammar because two constraints do not apply to
it:

  - No context restriction.  JSON_OBJECT means the same thing wherever a
    value expression is allowed, so a single keyword production in the
    shared a_expr grammar is enough.

  - The name is safe to reserve.  Making json_object a keyword costs almost
    nobody an identifier.

Row pattern navigation has both constraints:

  - It must mean navigation *only* inside DEFINE; everywhere else
    prev/next/first/last are ordinary names.  bison is LALR(1) and
    context-free, so a production cannot be conditioned on "are we inside
    DEFINE"; a_expr is shared by SELECT lists, WHERE, etc.  And a row
    pattern definition is "ColId AS a_expr", so navigation can appear
    anywhere a value expression can.  Special-casing it in the grammar
    would mean duplicating the whole a_expr tree into a second DEFINE-only
    expression grammar (or resorting to lexer feedback), which is not worth
    it.

  - The names are common.  prev/next/first/last (especially next, first,
    last) are everyday column and function names; reserving them globally
    would break existing queries.

So the plan is the opposite of a grammar keyword: parse navigation as an
ordinary FuncCall and reinterpret it in parse analysis, gated on
p_expr_kind == EXPR_KIND_RPR_DEFINE and an unqualified, single-element
name.  That keeps one expression grammar, leaves the names free everywhere
else, and confines the special meaning to exactly the DEFINE context -- the
same "looks like a function call, parsed as syntax" behavior you described,
reached by a lighter path that does not grow the keyword list.

Thanks,
Henson

Reply via email to