From: | Dean Rasheed <dean(dot)a(dot)rasheed(at)gmail(dot)com> |
---|---|
To: | Craig Ringer <craig(at)2ndquadrant(dot)com> |
Cc: | Abbas Butt <abbas(dot)butt(at)enterprisedb(dot)com>, PostgreSQL Hackers <pgsql-hackers(at)postgresql(dot)org> |
Subject: | Re: varattno remapping |
Date: | 2013-12-24 15:17:49 |
Message-ID: | CAEZATCUxsQOxhenY72PY3KVfCtLX8Xj2CSOoS7x+r_-kJr2U-A@mail.gmail.com |
Views: | Raw Message | Whole Thread | Download mbox | Resend email |
Thread: | |
Lists: | pgsql-hackers |
On 24 December 2013 12:12, Craig Ringer <craig(at)2ndquadrant(dot)com> wrote:
> On 12/24/2013 03:21 PM, Abbas Butt wrote:
>
>> Could you please explain a little bit more how would you solve the posed
>> problem using map_variable_attnos?
>
> It actually turns out to be even simpler, and easy to do in one pass,
> when using ReplaceVarsFromTargetList .
>
> You just generate a temporary new list of TargetEntry, with resnos
> matching the attribute numbers of the view. Each contained Var points to
> the remapped varno and varattno.
>
> Then you let ReplaceVarsFromTargetList substitute Vars recursively
> through the expression tree with ones in the replacement tlist you supply.
>
> The more I've thought about it, the shorter this code has got. Currently:
>
>
>
>
> /*
> * Scan the passed view target list, whose members must consist solely
> * of Var nodes with a varno equal to the passed targetvarno, and
> * produce a targetlist of Var nodes with the corresponding varno and
> * varattno of the base relation 'targetvarno'.
> *
> * This tlist is used when remapping Vars that point to a view so they
> * point to the base relation of the view instead. It is entirely
> * newly allocated. The result tlist is not in resno order.
> *
> * Must not be called with a targetlist containing non-Var entries.
> */
> static List *
> gen_view_base_attr_map(List *viewtlist, int targetvarno, int newvarno)
> {
> ListCell *lc;
> TargetEntry *te, *newte;
> Var *tev, *newvar;
> int l_viewtlist = list_length(viewtlist);
> List *newtlist = NIL;
>
> foreach(lc, viewtlist)
> {
> te = (TargetEntry*) lfirst(lc);
> /* Could relax this in future and map only the var entries,
> * ignoring everything else, but currently pointless since we
> * are only interested in simple views. */
> Assert(IsA(te->expr, Var));
> tev = (Var*) te->expr;
> Assert(tev->varno == targetvarno);
> Assert(te->resno - 1 < l_viewtlist);
>
> /* Construct the new Var with the remapped attno and varno */
> newvar = (Var*) palloc(sizeof(Var));
> *newvar = *tev;
> newvar->varno = newvarno;
> newvar->varattno = tev->varattno;
>
> /* and wrap it in a new tle to cons to the list */
> newte = flatCopyTargetEntry(te);
> newte->expr = (Expr*) newvar;
> newtlist = lcons(newte, newtlist);
> }
>
> return newtlist;
> }
>
>
I don't think this bit is quite right.
It's not correct to assume that all the view columns are simple
references to columns of the base relation --- auto-updatable views
may now contain a mix of updatable and non-updatable columns, so some
of the view columns may be arbitrary expressions.
There is already code in rewriteTargetView() that does something very
similar (to the whole parsetree, rather than just the returning list)
with 2 function calls:
/*
* Make a copy of the view's targetlist, adjusting its Vars to reference
* the new target RTE, ie make their varnos be new_rt_index instead of
* base_rt_index. There can be no Vars for other rels in the tlist, so
* this is sufficient to pull up the tlist expressions for use in the
* outer query. The tlist will provide the replacement expressions used
* by ReplaceVarsFromTargetList below.
*/
view_targetlist = copyObject(viewquery->targetList);
ChangeVarNodes((Node *) view_targetlist,
base_rt_index,
new_rt_index,
0);
and then later:
/*
* Now update all Vars in the outer query that reference the view to
* reference the appropriate column of the base relation instead.
*/
parsetree = (Query *)
ReplaceVarsFromTargetList((Node *) parsetree,
parsetree->resultRelation,
0,
view_rte,
view_targetlist,
REPLACEVARS_REPORT_ERROR,
0,
&parsetree->hasSubLinks);
Regards,
Dean
>
>
> and invocation:
>
>
> /*
> * We need to adjust any RETURNING clause entries to point to the new
> * target RTE instead of the old one so that we see the effects of
> * BEFORE triggers. Varattnos must be remapped so that the new Var
> * points to the correct col of the base rel, since the view will
> * usually have a different set of columns / column order.
> *
> * As part of this pass any whole-row references to the view are
> * expanded into ROW(...) expressions to ensure we don't expose
> * columns that are not visible through the view, and to make sure
> * the client gets the result type it expected.
> */
>
> List * remap_tlist = gen_view_base_attr_map(
> viewquery->targetList, rtr->rtindex, new_result_rt_index);
>
> parsetree->returningList = ReplaceVarsFromTargetList(
> (Node*) parsetree->returningList,
> old_result_rt_index, 0 /*sublevels_up*/,
> view_rte,
> remap_tlist,
> REPLACEVARS_REPORT_ERROR, 0 /*nomatch_varno, unused */,
> NULL /* outer_hasSubLinks, unused */
> );
>
>
>
>
>
> --
> Craig Ringer http://www.2ndQuadrant.com/
> PostgreSQL Development, 24x7 Support, Training & Services
>
>
> --
> Sent via pgsql-hackers mailing list (pgsql-hackers(at)postgresql(dot)org)
> To make changes to your subscription:
> http://www.postgresql.org/mailpref/pgsql-hackers
From | Date | Subject | |
---|---|---|---|
Next Message | Andres Freund | 2013-12-24 15:27:17 | Re: trailing comment ghost-timing |
Previous Message | Tom Lane | 2013-12-24 14:59:23 | Re: trailing comment ghost-timing |