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

A B commented on DERBY-3301:
----------------------------

Hi Thomas,

I really hate to keep bringing up more issues, but as I was about to sign off 
on patch 6, the
following caught my eye:

                   /*
                    * This WHERE EXISTS | ANY | IN subquery has another
                    * subquery in its own WHERE *clause* if the CNV is not
                    * empty.
                    */
                   return cnv.getList().isEmpty();

Note how the code comments don't match the code--there's a missing "!" operator 
in the
actual code.  This is how I wrote it in my previous comment, but that was 
wrong.  The
method is supposed to return "true" if the SubqueryNode has a WHERE clause with
another subquery in it--which will be true if cnv.getList() is NOT empty.  So I 
missed
the negation (sorry).

With this fix in place all of Craigs queries still run correctly--but the 
queries with
"1 = 1" in them start failing again.  In tracing it turns out that, for those 
cases,
the CollectNodesVisitor does not find the SubqueryNodes in 
"sn.originalWhereClause".
I think it comes down to something you mentioned earlier, namely:

> I still need to have another look at [the "1 = 1"] variant, as it doesn't seem
> to end up with a similar querytree to the others

Upon further inspection, I think you are right about this.

For reference, this is the query in question.  Note the tags on the right for
the sake of discussion, where "SN" implies "SelectNode":

select unbound_e.empid, unbound_p.projid                             -- SN_OUTER
from departments this,
     employees unbound_e,
     projects unbound_p
where exists (
    select 1 from employees this_employees_e                         -- 
SN_INNER_1
    where 1 = 1 and exists (
        select 1 from project_employees this_employees_e_projects_p  -- 
SN_INNER_2
        where this_employees_e_projects_p.empid = this_employees_e.empid
        and this_employees_e.department = this.id
        and unbound_p.projid = this_employees_e_projects_p.projid
        and unbound_e.empid = this_employees_e.empid)
    );

By the time we reach SubqueryNode.isWhereExistsAnyInWithWhereSubquery() for the
SubqueryNode wrapping SN_INNER_1, the clause:

  where 1 = 1 and exists ( ... )

ends up as an AndNode whose left operand is "1 = 1" but whose right operand is 
the
constant literal TRUE--which is not what we expect.  We expect the AndNode's 
right
operand to be the SubqueryNode corresponding to SN_INNER_2.  That is, if "sn" 
is the
SelectNode for SN_INNER_1 then sn.originalWhereClause should include the 
SubqueryNode
that wraps SN_INNER_2.  That is true when we first set sn.originalWhereClause 
in the
init() method of SelectNode--but by the time we get to preprocessing for the 
SubqueryNode
wrapping SN_INNER_1, the SubqueryNode for SN_INNER_2 is no longer in 
SN_INNER_1's
originalWhereClause.

>From what I can tell, this is because sn.originalWhereClause for SN_INNER_1 
>points to
the same object as sn.whereClause.  So when sn.whereClause is itself 
transformed due to
flattening of the subquery SN_INNER_2 (which is legal), 
sn.originalWhereClause() sees
the same transformation.  Thus the SubqueryNode wrapping SN_INNER_2 disappears 
from
sn.whereClause, which is good--but it also disappears from 
sn.originalWhereClause(),
which is bad.  The fact that it disappears means that CollectNodesVisitor for 
SN_INNER_1
will not find it, and thus SN_INNER_1 will be flattened, which is not legal.

With the negation operator gone (as in patch 6), the fact that we can't find 
the SubqueryNode
for SN_INNER_2 causes the method to incorrectly return "true" (because CNV's 
list is empty),
which is then negated by the caller and thus flattening of SN_INNER_1 is 
accidentally (but
correctly) avoided.  I think it's clear that the negation operator should be 
there, though.

I'm not sure what the best way to address that would be--but before you go 
there,
can you double-check these findings to see if you agree?  Maybe I'm just missing
something obvious...

Apologies for the negation slip-up to begin with.

> Incorrect result from query with nested EXIST
> ---------------------------------------------
>
>                 Key: DERBY-3301
>                 URL: https://issues.apache.org/jira/browse/DERBY-3301
>             Project: Derby
>          Issue Type: Bug
>          Components: SQL
>    Affects Versions: 10.1.3.1, 10.2.1.6, 10.3.2.1
>            Reporter: Craig Russell
>            Assignee: Thomas Nielsen
>         Attachments: d3301-queryplan.log, derby-3301-1.diff, 
> derby-3301-1.stat, derby-3301-2.diff, derby-3301-3.diff, derby-3301-3b.diff, 
> derby-3301-4.diff, derby-3301-4b.diff, derby-3301-4b.stat, 
> derby-3301-4c.diff, derby-3301-5.diff, derby-3301-6.diff, 
> derby-3301-extra.sql, derby-3301-test-1.diff, derby-3301-test-1.stat, 
> derby-3301-test-2.diff, derby-3301-test-3.diff, derby-3301-test-3.stat, 
> derby-3301-test-master.diff, derby-3301-test-master.stat, derby-3301.sql
>
>
> Derby returns unexpected results from a query with embedded EXIST clauses. 
> The query SQL is generated by the JPOX jdo implementation and is supposed to 
> return all of the PERSONS and PROJECTS where there is an entry in the join 
> table. This query works as expected when using MySQL.
> Here's the query:
> SELECT UNBOUND_E.PERSONID, UNBOUND_P.PROJID 
> FROM applicationidentity0.DEPARTMENTS THIS, 
>      applicationidentity0.PERSONS UNBOUND_E, 
>      applicationidentity0.PROJECTS UNBOUND_P 
> WHERE EXISTS ( 
>     SELECT 1 FROM applicationidentity0.PERSONS THIS_EMPLOYEES_E 
>     WHERE EXISTS ( 
>         SELECT 1 FROM applicationidentity0.PROJECT_MEMBER 
> THIS_EMPLOYEES_E_PROJECTS_P 
>         WHERE THIS_EMPLOYEES_E_PROJECTS_P."MEMBER" = 
> THIS_EMPLOYEES_E.PERSONID 
>         AND THIS_EMPLOYEES_E_PROJECTS_P."MEMBER" = THIS_EMPLOYEES_E.PERSONID 
>         AND THIS_EMPLOYEES_E.DEPARTMENT = THIS.ID 
>         AND THIS_EMPLOYEES_E.DEPARTMENT = THIS.ID 
>         AND UNBOUND_P.PROJID = THIS_EMPLOYEES_E_PROJECTS_P.PROJID 
>         AND UNBOUND_E.PERSONID = THIS_EMPLOYEES_E.PERSONID) 
>     );
> PERSONID   |PROJID     
> -----------------------
> 3          |1          
> 5          |3          
> 4          |3          
> 2          |1          
> 1          |1          
> 5 rows selected
> I'm expecting 7 rows to be returned here, one row for each row in the join 
> table. 
> Here's the schema:
> CREATE TABLE departments (
>     ID INTEGER NOT NULL,
>     NAME VARCHAR(32) NOT NULL,
>     EMP_OF_THE_MONTH INTEGER,
>     COMPANYID INTEGER,
>     DISCRIMINATOR VARCHAR(255),
>     CONSTRAINT DEPTS_COMP_FK FOREIGN KEY (COMPANYID) REFERENCES companies,
>     CONSTRAINT DEPTS_PK PRIMARY KEY (ID)
> );
> CREATE TABLE persons (
>     PERSONID INTEGER NOT NULL,
>     FIRSTNAME VARCHAR(32) NOT NULL,
>     LASTNAME VARCHAR(32) NOT NULL,
>     MIDDLENAME VARCHAR(32),
>     BIRTHDATE TIMESTAMP NOT NULL,
>     ADDRID INTEGER,
>     STREET VARCHAR(64),
>     CITY VARCHAR(64),
>     STATE CHAR(2),
>     ZIPCODE CHAR(5),
>     COUNTRY VARCHAR(64),
>     HIREDATE TIMESTAMP,
>     WEEKLYHOURS REAL,
>     DEPARTMENT INTEGER,
>     FUNDINGDEPT INTEGER,
>     MANAGER INTEGER,
>     MENTOR INTEGER,
>     HRADVISOR INTEGER,
>     SALARY REAL,
>     WAGE REAL,
>     DISCRIMINATOR varchar(255) NOT NULL,
>     CONSTRAINT PERS_DEPT_FK FOREIGN KEY (DEPARTMENT) REFERENCES departments,
>     CONSTRAINT PERS_FUNDDEPT_FK FOREIGN KEY (FUNDINGDEPT) REFERENCES 
> departments,
>     CONSTRAINT PERS_MANAGER_FK FOREIGN KEY (MANAGER) REFERENCES persons,
>     CONSTRAINT PERS_MENTOR_FK FOREIGN KEY (MENTOR) REFERENCES persons,
>     CONSTRAINT PERS_HRADVISOR_FK FOREIGN KEY (HRADVISOR) REFERENCES persons,
>     CONSTRAINT EMPS_PK PRIMARY KEY (PERSONID)
> );
> CREATE TABLE projects (
>     PROJID INTEGER NOT NULL,
>     NAME VARCHAR(32) NOT NULL,
>     BUDGET DECIMAL(11,2) NOT NULL,
>     DISCRIMINATOR VARCHAR(255),
>     CONSTRAINT PROJS_PK PRIMARY KEY (PROJID)
> );
> CREATE TABLE project_member (
>     PROJID INTEGER REFERENCES projects NOT NULL,
>     MEMBER INTEGER REFERENCES persons NOT NULL
> );
> ij> connect 
> 'jdbc:derby:/Users/clr/apache/jdo/trunk/tck2/target/database/derby/jdotckdb';
> ij> set schema applicationidentity0;
> 0 rows inserted/updated/deleted
> ij> select * from persons;
> PERSONID   |FIRSTNAME                       |LASTNAME                        
> |MIDDLENAME                      |BIRTHDATE                 |ADDRID     
> |STREET                                                          |CITY        
>                                                     |STA&|ZIPC&|COUNTRY       
>                                                   |HIREDATE                  
> |WEEKLYHOURS  |DEPARTMENT |FUNDINGDEPT|MANAGER    |MENTOR     |HRADVISOR  
> |SALARY       |WAGE         |DISCRIMINATOR                                    
>                                                                               
>  
> -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
> 1          |emp1First                       |emp1Last                        
> |emp1Middle                      |1970-06-09 21:00:00.0     |NULL       |NULL 
>                                                            |NULL              
>                                               |NULL|NULL |NULL                
>                                             |1998-12-31 21:00:00.0     |40.0  
>        |NULL       |NULL       |NULL       |NULL       |NULL       |20000.0   
>    |NULL         |org.apache.jdo.tck.pc.company.FullTimeEmployee              
>                                                                     
> 2          |emp2First                       |emp2Last                        
> |emp2Middle                      |1975-12-21 21:00:00.0     |NULL       |NULL 
>                                                            |NULL              
>                                               |NULL|NULL |NULL                
>                                             |2003-06-30 21:00:00.0     |40.0  
>        |NULL       |NULL       |NULL       |NULL       |NULL       |10000.0   
>    |NULL         |org.apache.jdo.tck.pc.company.FullTimeEmployee              
>                                                                     
> 3          |emp3First                       |emp3Last                        
> |emp3Middle                      |1972-09-04 21:00:00.0     |NULL       |NULL 
>                                                            |NULL              
>                                               |NULL|NULL |NULL                
>                                             |2002-08-14 21:00:00.0     |19.0  
>        |NULL       |NULL       |NULL       |NULL       |NULL       |NULL      
>    |15.0         |org.apache.jdo.tck.pc.company.PartTimeEmployee              
>                                                                     
> 4          |emp4First                       |emp4Last                        
> |emp4Middle                      |1973-09-05 21:00:00.0     |NULL       |NULL 
>                                                            |NULL              
>                                               |NULL|NULL |NULL                
>                                             |2001-04-14 21:00:00.0     |0.0   
>        |NULL       |NULL       |NULL       |NULL       |NULL       |NULL      
>    |13.0         |org.apache.jdo.tck.pc.company.PartTimeEmployee              
>                                                                     
> 5          |emp5First                       |emp5Last                        
> |emp5Middle                      |1962-07-04 21:00:00.0     |NULL       |NULL 
>                                                            |NULL              
>                                               |NULL|NULL |NULL                
>                                             |1998-08-14 21:00:00.0     |0.0   
>        |NULL       |NULL       |NULL       |NULL       |NULL       |45000.0   
>    |NULL         |org.apache.jdo.tck.pc.company.FullTimeEmployee              
>                                                                     
> 5 rows selected
> ij> select * from projects;
> PROJID     |NAME                            |BUDGET       |DISCRIMINATOR      
>                                                                               
>                                
> -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
> 1          |orange                          |2500000.99   
> |org.apache.jdo.tck.pc.company.Project                                        
>                                                    
> 2          |blue                            |50000.00     
> |org.apache.jdo.tck.pc.company.Project                                        
>                                                    
> 3          |green                           |2000.99      
> |org.apache.jdo.tck.pc.company.Project                                        
>                                                    
> 3 rows selected
> ij> select * from project_member;
> PROJID     |MEMBER     
> -----------------------
> 2          |3          
> 1          |3          
> 2          |2          
> 3          |5          
> 3          |4          
> 1          |2          
> 1          |1          
> 7 rows selected

-- 
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