[ 
https://issues.apache.org/jira/browse/DERBY-3880?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12646775#action_12646775
 ] 

A B commented on DERBY-3880:
----------------------------

Hi Bryan,

Thanks for your interest in this issue.

> Army says "so the JoinNode's bind-time RCL is: { T1.i, T1.c, T2.i, T2.c2, 
> T2.i2 }" but I don't
> see how that is [...] I'm having trouble seeing why T1.c and T2.c2 are in the 
> join node's RCL.

I think the key observation here is in the sentence immediately preceding the 
one that you quoted, namely:

  The JoinNode's bind-time result column list is simply a concatenation of the 
result column
  lists from its operands.

Due to the specification of "inner join" the parser will create a parse-time 
JoinNode whose left operand is a FromBaseTable representing T1 and whose right 
operand is a FromBaseTable representing T2.  Note how neither operand has a 
ProjectRestrictNode above it, which in turn means we will *not* project out any 
columns (at this point).  Thus the FromBaseTable for T1 has an RCL with *ALL* 
of T1's columns in it, and the FromBaseTable for T2 has an RCL with *ALL* of 
T2's columns in it.  The fact that some columns are never referenced in the 
query has no effect on the RCLs for the FromBaseTables at this point in binding.

To verify, you can put a breakpoint in JoinNode.buildRCL() and, when the 
breakpoint hits, look at the leftOperand and rightOperand.  They will both be 
FromBaseTables and the RCLs will have all columns that exist in the underlying 
base tables.  So the JoinNode's RCL then becomes a concatenation of all columns 
from T1 and all columns from T2, hence { T1.i, T1.c, T2.i, T2.c2, T2.i2 }--even 
though T1.c and T2.c2 are never referenced in the query.

> I anticipated that I was going to see a fix which involved passing the HAVING 
> clause
> expressions to fromList.flattenFromTables() so that it could properly 
> maintain the
> ColumnReference data in the HAVING clause during flattening. 

To be honest, I think you're absolutely right: that seems like a more robust 
approach to the problem.  See below...

> if it's safe to allow the ColumnReference in the aggregate of a HAVING clause
> to "decay" (become in-accurate) during optimization, and then fix it up at 
> the end,
> why do we have to re-map the ColumnReference information for the SELECT's
> RCL?

Good question.  I do not think it is generally safe to assume that a 
temporarily inaccurate ColumnReference is going to be okay.  The vast majority 
of the ColumnReference remapping that occurs during optimization happens in 
order to support the pushing of predicates down the tree and/or to allow the 
insertion of query tree nodes into an existing tree.  In both cases the column 
reference is being remapped from one valid ResultColumn to another valid 
ResultColumn.  In other words, we can't just look at the ColumnReference after 
optimization has finished and say "pick the only one that's valid", because 
there could be an arbitrarily long chain of ResultColumns, VirtualColumnNodes, 
and ColumnReferences, all of which are valid and referenceable by different 
parts of the query tree.  The only way to know which one is the "right" one for 
a given ColumnReference is to remap (or un-remap) in "real time"--ex. when we 
push/pull a predicate, we have to remap its column reference as part of the 
push/pull.

That said, the fact that a post-optimization remapping of the HAVING 
aggregate's ColumnReference corrected the problem was a pleasant surprise to 
me, as I too was more inclined to believe that, by then, it would be too late.  
But I made the change, saw that it made sense and that it fixed the immediate 
problem, and that's what I posted.  Having done so, I think it's worth it to 
echo the final few sentences from that same comment, namely:

  I admit that this change may not be sufficient (or it may be too general), 
but it does
  cause the reported query to run without error, so at the very least it 
demonstrates
  the problem. There could very well be a better way to fix it...

I posted a quick fix to demonstrate the problem and stopped there.  Kathey was 
kind enough to pick it up and take it to completion.  But at a higher level, I 
think you're right: there's probably a better (and safer) way to fix this bug, 
and your suggestion that such a fix would involve passing the HAVING clause 
expressions to fromList.flattenFromTables() seems like a good one to me...

> I've noticed that (I think) the actual code that is generated to execute the 
> query may
> contain multiple computations of the same expressions. That is, when this 
> query
> runs, is it true that we are actually going to *compute* AVG(t2.i) twice?

I have not looked at this in any detail, but I believe the answer is "Yes", at 
least based on the tracing I was doing when I was trying to track down the 
cause of this issue.  But I wasn't specifically investigating that particular 
behavior at the time, so it's possible I missed something...

> NPE on a query with having clause involving a join
> --------------------------------------------------
>
>                 Key: DERBY-3880
>                 URL: https://issues.apache.org/jira/browse/DERBY-3880
>             Project: Derby
>          Issue Type: Bug
>          Components: SQL
>    Affects Versions: 10.4.2.0
>         Environment: Windows 2003 Server 
>            Reporter: Venkateswaran Iyer
>            Assignee: A B
>            Priority: Minor
>             Fix For: 10.3.3.1, 10.4.2.1, 10.5.0.0
>
>         Attachments: AggregateExpressionResultColumn.txt, querytree_fail.txt, 
> querytree_works.txt
>
>
> A simple query involving a join and having clause causes a NPE. Any 
> subsequent executions cause severe errors. It almost looks like the 
> underlying connection was closed out.
> ====
> C:\apps\derby\db-derby-10.4.2.0-bin\db-derby-10.4.2.0-bin\bin>ij
> ij version 10.4
> ij> connect 'jdbc:derby://speed:1527/ClassicModels;user=sa;password=sa
> ';
> ij> create table t1(i int, c varchar(20));
> 0 rows inserted/updated/deleted
> ij> create table t2(i int, c2 varchar(20), i2 int);
> 0 rows inserted/updated/deleted
> ij> insert into t1 values(1, 'abc');
> 1 row inserted/updated/deleted
> ij> insert into t1 values(2, 'abc');
> 1 row inserted/updated/deleted
> ij> insert into t2 values(1, 'xyz', 10);
> 1 row inserted/updated/deleted
> ij> insert into t2 values(1, 'aaa', 20);
> 1 row inserted/updated/deleted
> ij> insert into t2 values(2, 'xxx', 30);
> 1 row inserted/updated/deleted
> ij> select t1.i, avg(t2.i2) from t1 inner join t2 on (t1.i = t2.i) group by 
> t1.i
>  having avg(t2.i2) > 0;
> ERROR XJ001: DERBY SQL error: SQLCODE: -1, SQLSTATE: XJ001, SQLERRMC: 
> java.lang.
> NullPointerException¶¶XJ001.U

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.

Reply via email to