* we always push them into the namespace, but mark them as not
* lateral_ok if the jointype is wrong.
*
+ * Notice that we don't require the merged namespace list to be
+ * conflict-free. See the comments for scanNameSpaceForRefname().
+ *
* NB: this coding relies on the fact that list_concat is not
* destructive to its second argument.
*/
lateral_ok = (j->jointype == JOIN_INNER || j->jointype == JOIN_LEFT);
setNamespaceLateralState(l_namespace, true, lateral_ok);
- checkNameSpaceConflicts(pstate, pstate->p_namespace, l_namespace);
-
sv_namespace_length = list_length(pstate->p_namespace);
pstate->p_namespace = list_concat(pstate->p_namespace, l_namespace);
* Search the query's table namespace for an RTE matching the
* given unqualified refname. Return the RTE if a unique match, or NULL
* if no match. Raise error if multiple matches.
+ *
+ * Note: it might seem that we shouldn't have to worry about the possibility
+ * of multiple matches; after all, the SQL standard disallows duplicate table
+ * aliases within a given SELECT level. Historically, however, Postgres has
+ * been laxer than that. For example, we allow
+ * SELECT ... FROM tab1 x CROSS JOIN (tab2 x CROSS JOIN tab3 y) z
+ * on the grounds that the aliased join (z) hides the aliases within it,
+ * therefore there is no conflict between the two RTEs named "x". However,
+ * if tab3 is a LATERAL subquery, then from within the subquery both "x"es
+ * are visible. Rather than rejecting queries that used to work, we allow
+ * this situation, and complain only if there's actually an ambiguous
+ * reference to "x".
*/
static RangeTblEntry *
scanNameSpaceForRefname(ParseState *pstate, const char *refname, int location)
/*
* Search the query's table namespace for a relation RTE matching the
* given relation OID. Return the RTE if a unique match, or NULL
- * if no match. Raise error if multiple matches (which shouldn't
- * happen if the namespace was checked correctly when it was created).
+ * if no match. Raise error if multiple matches.
*
* See the comments for refnameRangeTblEntry to understand why this
* acts the way it does.
(5 rows)
rollback;
+-- bug #8444: we've historically allowed duplicate aliases within aliased JOINs
+select * from
+ int8_tbl x join (int4_tbl x cross join int4_tbl y) j on q1 = f1; -- error
+ERROR: column reference "f1" is ambiguous
+LINE 2: ..._tbl x join (int4_tbl x cross join int4_tbl y) j on q1 = f1;
+ ^
+select * from
+ int8_tbl x join (int4_tbl x cross join int4_tbl y) j on q1 = y.f1; -- error
+ERROR: invalid reference to FROM-clause entry for table "y"
+LINE 2: ...bl x join (int4_tbl x cross join int4_tbl y) j on q1 = y.f1;
+ ^
+HINT: There is an entry for table "y", but it cannot be referenced from this part of the query.
+select * from
+ int8_tbl x join (int4_tbl x cross join int4_tbl y(ff)) j on q1 = f1; -- ok
+ q1 | q2 | f1 | ff
+----+----+----+----
+(0 rows)
+
--
-- Test LATERAL
--
LINE 1: ...m int4_tbl a full join lateral generate_series(0, a.f1) g on...
^
DETAIL: The combining JOIN type must be INNER or LEFT for a LATERAL reference.
+-- check we complain about ambiguous table references
+select * from
+ int8_tbl x cross join (int4_tbl x cross join lateral (select x.f1) ss);
+ERROR: table reference "x" is ambiguous
+LINE 2: ...cross join (int4_tbl x cross join lateral (select x.f1) ss);
+ ^
-- LATERAL can be used to put an aggregate into the FROM clause of its query
select 1 from tenk1 a, lateral (select max(a.unique1) from int4_tbl b) ss;
ERROR: aggregate functions are not allowed in FROM clause of their own query level
rollback;
+-- bug #8444: we've historically allowed duplicate aliases within aliased JOINs
+
+select * from
+ int8_tbl x join (int4_tbl x cross join int4_tbl y) j on q1 = f1; -- error
+select * from
+ int8_tbl x join (int4_tbl x cross join int4_tbl y) j on q1 = y.f1; -- error
+select * from
+ int8_tbl x join (int4_tbl x cross join int4_tbl y(ff)) j on q1 = f1; -- ok
+
--
-- Test LATERAL
--
-- SQL:2008 says the left table is in scope but illegal to access here
select f1,g from int4_tbl a right join lateral generate_series(0, a.f1) g on true;
select f1,g from int4_tbl a full join lateral generate_series(0, a.f1) g on true;
+-- check we complain about ambiguous table references
+select * from
+ int8_tbl x cross join (int4_tbl x cross join lateral (select x.f1) ss);
-- LATERAL can be used to put an aggregate into the FROM clause of its query
select 1 from tenk1 a, lateral (select max(a.unique1) from int4_tbl b) ss;