* But it can arise while simplifying functions.) Also, we
* can optimize field selection from a RowExpr construct.
*
- * We must however check that the declared type of the field
- * is still the same as when the FieldSelect was created ---
- * this can change if someone did ALTER COLUMN TYPE on the
- * rowtype.
+ * However, replacing a whole-row Var in this way has a
+ * pitfall: if we've already built the reltargetlist for the
+ * source relation, then the whole-row Var is scheduled to be
+ * produced by the relation scan, but the simple Var probably
+ * isn't, which will lead to a failure in setrefs.c. This is
+ * not a problem when handling simple single-level queries, in
+ * which expression simplification always happens first. It
+ * is a risk for lateral references from subqueries, though.
+ * To avoid such failures, don't optimize uplevel references.
+ *
+ * We must also check that the declared type of the field is
+ * still the same as when the FieldSelect was created --- this
+ * can change if someone did ALTER COLUMN TYPE on the rowtype.
*/
FieldSelect *fselect = (FieldSelect *) node;
FieldSelect *newfselect;
arg = eval_const_expressions_mutator((Node *) fselect->arg,
context);
if (arg && IsA(arg, Var) &&
- ((Var *) arg)->varattno == InvalidAttrNumber)
+ ((Var *) arg)->varattno == InvalidAttrNumber &&
+ ((Var *) arg)->varlevelsup == 0)
{
if (rowtype_field_matches(((Var *) arg)->vartype,
fselect->fieldnum,
3 | FROM 10000000876 | from 10000000876
(3 rows)
+-- check whole-row-Var handling in nested lateral functions (bug #11703)
+create function extractq2(t int8_tbl) returns int8 as $$
+ select t.q2
+$$ language sql immutable;
+explain (verbose, costs off)
+select x from int8_tbl, extractq2(int8_tbl) f(x);
+ QUERY PLAN
+------------------------------------------
+ Nested Loop
+ Output: f.x
+ -> Seq Scan on public.int8_tbl
+ Output: int8_tbl.q1, int8_tbl.q2
+ -> Function Scan on f
+ Output: f.x
+ Function Call: int8_tbl.q2
+(7 rows)
+
+select x from int8_tbl, extractq2(int8_tbl) f(x);
+ x
+-------------------
+ 456
+ 4567890123456789
+ 123
+ 4567890123456789
+ -4567890123456789
+(5 rows)
+
+create function extractq2_2(t int8_tbl) returns table(ret1 int8) as $$
+ select extractq2(t)
+$$ language sql immutable;
+explain (verbose, costs off)
+select x from int8_tbl, extractq2_2(int8_tbl) f(x);
+ QUERY PLAN
+-----------------------------------
+ Nested Loop
+ Output: ((int8_tbl.*).q2)
+ -> Seq Scan on public.int8_tbl
+ Output: int8_tbl.*
+ -> Result
+ Output: (int8_tbl.*).q2
+(6 rows)
+
+select x from int8_tbl, extractq2_2(int8_tbl) f(x);
+ x
+-------------------
+ 456
+ 4567890123456789
+ 123
+ 4567890123456789
+ -4567890123456789
+(5 rows)
+
END)
FROM
(VALUES (1,''), (2,'0000000049404'), (3,'FROM 10000000876')) v(id, str);
+
+-- check whole-row-Var handling in nested lateral functions (bug #11703)
+
+create function extractq2(t int8_tbl) returns int8 as $$
+ select t.q2
+$$ language sql immutable;
+
+explain (verbose, costs off)
+select x from int8_tbl, extractq2(int8_tbl) f(x);
+
+select x from int8_tbl, extractq2(int8_tbl) f(x);
+
+create function extractq2_2(t int8_tbl) returns table(ret1 int8) as $$
+ select extractq2(t)
+$$ language sql immutable;
+
+explain (verbose, costs off)
+select x from int8_tbl, extractq2_2(int8_tbl) f(x);
+
+select x from int8_tbl, extractq2_2(int8_tbl) f(x);