Package org.teiid.query.optimizer.relational.rules

Source Code of org.teiid.query.optimizer.relational.rules.TestRuleChooseDependent

/*
* JBoss, Home of Professional Open Source.
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.  Some portions may be licensed
* to Red Hat, Inc. under one or more contributor license agreements.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*/

package org.teiid.query.optimizer.relational.rules;

import static org.junit.Assert.*;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import org.junit.Test;
import org.teiid.api.exception.query.QueryMetadataException;
import org.teiid.api.exception.query.QueryPlannerException;
import org.teiid.core.TeiidComponentException;
import org.teiid.query.analysis.AnalysisRecord;
import org.teiid.query.optimizer.TestOptimizer;
import org.teiid.query.optimizer.capabilities.FakeCapabilitiesFinder;
import org.teiid.query.optimizer.relational.RuleStack;
import org.teiid.query.optimizer.relational.plantree.NodeConstants;
import org.teiid.query.optimizer.relational.plantree.NodeFactory;
import org.teiid.query.optimizer.relational.plantree.PlanNode;
import org.teiid.query.processor.relational.JoinNode.JoinStrategyType;
import org.teiid.query.rewriter.QueryRewriter;
import org.teiid.query.sql.lang.CompareCriteria;
import org.teiid.query.sql.lang.CompoundCriteria;
import org.teiid.query.sql.lang.Criteria;
import org.teiid.query.sql.lang.From;
import org.teiid.query.sql.lang.IsNullCriteria;
import org.teiid.query.sql.lang.JoinType;
import org.teiid.query.sql.lang.MatchCriteria;
import org.teiid.query.sql.lang.NotCriteria;
import org.teiid.query.sql.lang.Query;
import org.teiid.query.sql.lang.Select;
import org.teiid.query.sql.lang.SetCriteria;
import org.teiid.query.sql.symbol.Constant;
import org.teiid.query.sql.symbol.ElementSymbol;
import org.teiid.query.sql.symbol.GroupSymbol;
import org.teiid.query.unittest.FakeMetadataFacade;
import org.teiid.query.unittest.FakeMetadataFactory;
import org.teiid.query.unittest.FakeMetadataObject;
import org.teiid.query.util.CommandContext;

@SuppressWarnings("unchecked")
public class TestRuleChooseDependent {

    /* Make Left Side Dependent */
    private static final int LEFT_SIDE = 1;
    /* Make Right Side Dependent */
    private static final int RIGHT_SIDE = 2;
    /* Make Neither Side Dependent */
    private static final int NEITHER_SIDE = 3;

    private FakeMetadataFacade metadata = FakeMetadataFactory.example1Cached();
   
    // ################################## TEST HELPERS ################################
   
    public PlanNode createAccessNode(Collection groupSymbols) {
        PlanNode accessNode = NodeFactory.getNewNode(NodeConstants.Types.ACCESS);                       
        PlanNode joinNode = NodeFactory.getNewNode(NodeConstants.Types.JOIN);       
        PlanNode sourceNode = NodeFactory.getNewNode(NodeConstants.Types.SOURCE);       
        joinNode.setProperty(NodeConstants.Info.JOIN_TYPE, JoinType.JOIN_INNER);
        List crits = new ArrayList();
        crits.add(new CompareCriteria(getElementSymbol(1,1), CompareCriteria.EQ, getElementSymbol(2,1)));
        joinNode.setProperty(NodeConstants.Info.JOIN_CRITERIA, crits);               
        joinNode.addFirstChild(accessNode);
        accessNode.addFirstChild(sourceNode);
        Iterator i = groupSymbols.iterator();
        while (i.hasNext()) {
            GroupSymbol gs = (GroupSymbol)i.next();
            accessNode.addGroup(gs);
            sourceNode.addGroup(gs);
        }      
        return accessNode;
    }
   
    public GroupSymbol getVirtualGroup() {
        GroupSymbol gs = new GroupSymbol("vm1.g1"); //$NON-NLS-1$
        gs.setMetadataID(this.metadata.getStore().findObject("vm1.g1", FakeMetadataObject.GROUP));   //$NON-NLS-1$
        return gs;
    }

    public GroupSymbol getPhysicalGroup(int num) {
        String id = "pm1.g" + num; //$NON-NLS-1$
        GroupSymbol gs = new GroupSymbol(id);
        gs.setMetadataID(this.metadata.getStore().findObject(id, FakeMetadataObject.GROUP))
        return gs;
    }
   
    public GroupSymbol getPhysicalGroup(int modelNum, int num) {
        String id = "pm" + modelNum + ".g" + num; //$NON-NLS-1$ //$NON-NLS-2$
        GroupSymbol gs = new GroupSymbol(id);
        gs.setMetadataID(this.metadata.getStore().findObject(id, FakeMetadataObject.GROUP))
        return gs;
    }   

    public GroupSymbol getPhysicalGroupWithAlias(int num, String alias) {
        String id = "pm1.g" + num; //$NON-NLS-1$
        GroupSymbol gs = new GroupSymbol(alias, id);
        gs.setMetadataID(this.metadata.getStore().findObject(id, FakeMetadataObject.GROUP))
        return gs;
    }
   
    public ElementSymbol getElementSymbol(int groupNum, int elementNum) {
        String id = "pm1.g" + groupNum + ".e" + elementNum; //$NON-NLS-1$ //$NON-NLS-2$
         ElementSymbol es = new ElementSymbol(id);
         es.setMetadataID(this.metadata.getStore().findObject(id, FakeMetadataObject.ELEMENT));
         es.setGroupSymbol(getPhysicalGroup(groupNum));
         return es;
    }

    public ElementSymbol getElementSymbol(int modelNum, int groupNum, int elementNum) {
        String id = "pm" + modelNum + ".g" + groupNum + ".e" + elementNum; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
        ElementSymbol es = new ElementSymbol(id);
        es.setMetadataID(this.metadata.getStore().findObject(id, FakeMetadataObject.ELEMENT));
        es.setGroupSymbol(getPhysicalGroup(modelNum, groupNum));
        return es;
    }

    public ElementSymbol getElementSymbolWithGroupAlias(int groupNum, int elementNum, String alias) {
        String id = "pm1.g" + groupNum + ".e" + elementNum; //$NON-NLS-1$ //$NON-NLS-2$
         ElementSymbol es = new ElementSymbol(id);
         es.setMetadataID(this.metadata.getStore().findObject(id, FakeMetadataObject.ELEMENT));
         es.setGroupSymbol(getPhysicalGroupWithAlias(groupNum, alias));
         return es;
    }
   
    public Query createBaseQuery() {
        Query query = new Query();
       
        Select select = new Select();
        select.addSymbol(getElementSymbol(1,1));
        query.setSelect(select);
       
        From from = new From();
        from.addGroup(getPhysicalGroup(1));
        query.setFrom(from);
       
        return query;               
    }
   
    public void helpTestValidJoin(PlanNode joinNode, PlanNode accessNode, boolean expectedValid) {
        RuleChooseDependent rule = new RuleChooseDependent();
        RuleChooseJoinStrategy.chooseJoinStrategy(joinNode, metadata);
        boolean isValid = rule.isValidJoin(joinNode, accessNode, AnalysisRecord.createNonRecordingRecord());
        assertEquals("Valid join check is wrong ", expectedValid, isValid);         //$NON-NLS-1$
    }

    /**
     * Tests choosing from two eligible sibling access nodes, and then tests marking
     * the chosen one dependent.  This method sets up a bogus plan tree using a
     * bogus project parent node, an inner join node using the supplied join criteria, and
     * two access nodes using each of the groups and (optional) atomic criteria.  Then
     * this method tests that, if an access node is chosen, it can be marked dependent,
     * and that the chosen one is the one which was expected to be marked dependent.
     * @param atomicRequestGroup1 GroupSymbol to select * from in atomic request 1
     * @param atomicRequestCrit1 optional, may be null
     * @param atomicRequestGroup2 GroupSymbol to select * from in atomic request 2
     * @param atomicRequestCrit2 optional, may be null
     * @param joinCriteria Collection of Criteria to add to join node
     * @param expectedMadeDependent one of the three outcome possibility class constants
     * @throws TeiidComponentException
     * @throws QueryMetadataException
     * @throws QueryPlannerException
     */
    private void helpTestChooseSiblingAndMarkDependent(GroupSymbol atomicRequestGroup1,
                                                        Criteria atomicRequestCrit1,
                                                        GroupSymbol atomicRequestGroup2,
                                                        Criteria atomicRequestCrit2,
                                                        Collection joinCriteria,
                                                        int expectedMadeDependent) throws QueryPlannerException, QueryMetadataException, TeiidComponentException {

        helpTestChooseSiblingAndMarkDependent(atomicRequestGroup1,
        atomicRequestCrit1,
        null,
        null,
        null,
        atomicRequestGroup2,
        atomicRequestCrit2,
        null,
        null,
        null,
        joinCriteria,
        expectedMadeDependent, null, null);       
    }

    /**
     * Tests choosing from two eligible sibling access nodes, and then tests marking
     * the chosen one dependent.  This method sets up a bogus plan tree using a
     * bogus project parent node, a join node using the supplied join criteria, and
     * two access nodes using each of the groups and (optional) atomic criteria and
     * join criteria.  Then
     * this method tests that, if an access node is chosen, it is marked dependent,
     * and that the chosen one is the one which was expected to be marked dependent.
     * @param atomicRequestGroup1 GroupSymbol to select from in atomic request 1
     * @param atomicRequestCrit1 optional, may be null
     * @param atomicRequestGroup1a optional, may be null
     * @param atomicRequestCrit1a optional, may be null
     * @param atomicJoinCriteria1 optional, may be null
     * @param atomicRequestGroup2 GroupSymbol to select from in atomic request 2
     * @param atomicRequestCrit2 optional, may be null
     * @param atomicRequestGroup2a optional, may be null
     * @param atomicRequestCrit2a optional, may be null
     * @param atomicJoinCriteria2 optional, may be null
     * @param joinCriteria Collection of Criteria to add to outer join node
     * @param expectedMadeDependent one of the three outcome possibility class constants
     * @throws TeiidComponentException
     * @throws QueryMetadataException
     * @throws QueryPlannerException
     */   
    private void helpTestChooseSiblingAndMarkDependent(GroupSymbol atomicRequestGroup1,
                                                        Criteria atomicRequestCrit1,  //optional
                                                        GroupSymbol atomicRequestGroup1a, //optional
                                                        Criteria atomicRequestCrit1a,  //optional
                                                        Collection atomicJoinCriteria1,  //optional
                                                        GroupSymbol atomicRequestGroup2,
                                                        Criteria atomicRequestCrit2,  //optional
                                                        GroupSymbol atomicRequestGroup2a,  //optional
                                                        Criteria atomicRequestCrit2a,  //optional
                                                        Collection atomicJoinCriteria2,  //optional
                                                        Collection joinCriteria,
                                                        int expectedMadeDependent, Number expectedCost1, Number expectedCost2) throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
//EXAMPLE:
//    Project(groups=[])
//      Join(groups=[], props={21=joinCriteria, 23=true, 22=INNER JOIN})
//        Access(groups=[atomicRequestGroup1], props={...})
//          Source(groups=[atomicRequestGroup1])
//        Access(groups=[atomicRequestGroup2, atomicRequestGroup2a], props={...})
//          Join(groups=[atomicRequestGroup2, atomicRequestGroup2a], props={21=[atomicJoinCriteria2], 23=true, 22=INNER JOIN})
//            Select(groups=[atomicRequestGroup2], props={40=atomicRequestCrit2})
//              Source(groups=[atomicRequestGroup2])
//            Source(groups=[atomicRequestGroup2a])

        PlanNode accessNode1 = NodeFactory.getNewNode(NodeConstants.Types.ACCESS);
        accessNode1.addGroup(atomicRequestGroup1);
        if (atomicRequestGroup1a != null){
            accessNode1.addGroup(atomicRequestGroup1a);
        }

        PlanNode accessNode2 = NodeFactory.getNewNode(NodeConstants.Types.ACCESS);
        accessNode2.addGroup(atomicRequestGroup2);
        if (atomicRequestGroup2a != null){
            accessNode2.addGroup(atomicRequestGroup2a);
        }

        PlanNode joinNode = NodeFactory.getNewNode(NodeConstants.Types.JOIN);      
        joinNode.setProperty(NodeConstants.Info.JOIN_TYPE, JoinType.JOIN_INNER);
        joinNode.setProperty(NodeConstants.Info.JOIN_CRITERIA, joinCriteria);
        joinNode.setProperty(NodeConstants.Info.JOIN_STRATEGY, JoinStrategyType.NESTED_LOOP);
        joinNode.addLastChild(accessNode1);      
        joinNode.addLastChild(accessNode2);      

        PlanNode bogusParentNode = NodeFactory.getNewNode(NodeConstants.Types.PROJECT);      
        bogusParentNode.addLastChild(joinNode);      

        //FIRST (LEFT) BRANCH OF TREE
        PlanNode sourceNode1 = NodeFactory.getNewNode(NodeConstants.Types.SOURCE);      
        sourceNode1.addGroup(atomicRequestGroup1);
        if (atomicRequestCrit1 != null){
            PlanNode selectNode1 = NodeFactory.getNewNode(NodeConstants.Types.SELECT);
            selectNode1.setProperty(NodeConstants.Info.SELECT_CRITERIA, atomicRequestCrit1);      
            selectNode1.addGroup(atomicRequestGroup1);
            selectNode1.addFirstChild(sourceNode1);       
            if (atomicRequestGroup1a != null){
                PlanNode atomicJoinNode1 = NodeFactory.getNewNode(NodeConstants.Types.JOIN);
                if (atomicJoinCriteria1.isEmpty()){
                    atomicJoinNode1.setProperty(NodeConstants.Info.JOIN_TYPE, JoinType.JOIN_CROSS);
                } else {
                    atomicJoinNode1.setProperty(NodeConstants.Info.JOIN_TYPE, JoinType.JOIN_INNER);
                    atomicJoinNode1.setProperty(NodeConstants.Info.JOIN_CRITERIA, atomicJoinCriteria1);
                }
                atomicJoinNode1.addGroup(atomicRequestGroup1);
                atomicJoinNode1.addGroup(atomicRequestGroup1a);
                atomicJoinNode1.addLastChild(selectNode1);       

                PlanNode sourceNode1a = NodeFactory.getNewNode(NodeConstants.Types.SOURCE);      
                sourceNode1a.addGroup(atomicRequestGroup1a);
                if (atomicRequestCrit1a != null){
                    PlanNode selectNode1a = NodeFactory.getNewNode(NodeConstants.Types.SELECT);
                    selectNode1a.setProperty(NodeConstants.Info.SELECT_CRITERIA, atomicRequestCrit1a);      
                    selectNode1a.addGroup(atomicRequestGroup1a);
                    selectNode1a.addFirstChild(sourceNode1a);       
                    atomicJoinNode1.addLastChild(selectNode1a);       
                } else {
                  atomicJoinNode1.addLastChild(sourceNode1a);       
                }
                accessNode1.addLastChild(atomicJoinNode1);       
            } else {
                accessNode1.addFirstChild(selectNode1);       
            }
        } else {
            accessNode1.addFirstChild(sourceNode1);       
        }

        //SECOND (RIGHT) BRANCH OF TREE
        PlanNode sourceNode2 = NodeFactory.getNewNode(NodeConstants.Types.SOURCE);      
        sourceNode2.addGroup(atomicRequestGroup2);
        if (atomicRequestCrit2 != null){
            PlanNode selectNode2 = NodeFactory.getNewNode(NodeConstants.Types.SELECT);
            selectNode2.setProperty(NodeConstants.Info.SELECT_CRITERIA, atomicRequestCrit2);      
            selectNode2.addGroup(atomicRequestGroup2);
            selectNode2.addFirstChild(sourceNode2);       
            if (atomicRequestGroup2a != null){
                PlanNode atomicJoinNode2 = NodeFactory.getNewNode(NodeConstants.Types.JOIN);      
                if (atomicJoinCriteria2.isEmpty()){
                    atomicJoinNode2.setProperty(NodeConstants.Info.JOIN_TYPE, JoinType.JOIN_CROSS);
                } else {
                    atomicJoinNode2.setProperty(NodeConstants.Info.JOIN_TYPE, JoinType.JOIN_INNER);
                    atomicJoinNode2.setProperty(NodeConstants.Info.JOIN_CRITERIA, atomicJoinCriteria2);
                }
                atomicJoinNode2.addGroup(atomicRequestGroup2);
                atomicJoinNode2.addGroup(atomicRequestGroup2a);
                atomicJoinNode2.addLastChild(selectNode2);       

                PlanNode sourceNode2a = NodeFactory.getNewNode(NodeConstants.Types.SOURCE);      
                sourceNode2a.addGroup(atomicRequestGroup2a);
                if (atomicRequestCrit2a != null){
                    PlanNode selectNode2a = NodeFactory.getNewNode(NodeConstants.Types.SELECT);
                    selectNode2a.setProperty(NodeConstants.Info.SELECT_CRITERIA, atomicRequestCrit2a);      
                    selectNode2a.addGroup(atomicRequestGroup2a);
                    selectNode2a.addFirstChild(sourceNode2a);       
                    atomicJoinNode2.addLastChild(selectNode2a);       
                } else {
                  atomicJoinNode2.addLastChild(sourceNode2a);       
                }
                accessNode2.addLastChild(atomicJoinNode2);       
            } else {
                accessNode2.addFirstChild(selectNode2);       
            }
        } else {
            accessNode2.addFirstChild(sourceNode2);       
        }

        //Add access pattern(s)
        RulePlaceAccess.addAccessPatternsProperty(accessNode1, metadata);
        RulePlaceAccess.addAccessPatternsProperty(accessNode2, metadata);

        if (DEBUG){
            System.out.println("Before."); //$NON-NLS-1$
            System.out.println(bogusParentNode);
        }

        RuleChooseDependent rule = new RuleChooseDependent();
        RuleChooseJoinStrategy.chooseJoinStrategy(joinNode, metadata);
        FakeCapabilitiesFinder capFinder = new FakeCapabilitiesFinder();
        capFinder.addCapabilities("pm1", TestOptimizer.getTypicalCapabilities()); //$NON-NLS-1$
        capFinder.addCapabilities("pm2", TestOptimizer.getTypicalCapabilities()); //$NON-NLS-1$
        capFinder.addCapabilities("pm3", TestOptimizer.getTypicalCapabilities()); //$NON-NLS-1$
        capFinder.addCapabilities("pm4", TestOptimizer.getTypicalCapabilities()); //$NON-NLS-1$
       
        rule.execute(bogusParentNode, metadata, capFinder, new RuleStack(), null, new CommandContext());

        if (DEBUG){
            System.out.println("Done."); //$NON-NLS-1$
            System.out.println(bogusParentNode);
        }

        Object prop1 = joinNode.getProperty(NodeConstants.Info.DEPENDENT_VALUE_SOURCE);
       
        if (expectedMadeDependent == LEFT_SIDE){
            assertNotNull("Expected one side to be made dependent", prop1); //$NON-NLS-1$
            assertEquals(accessNode1, FrameUtil.findJoinSourceNode(joinNode.getLastChild()));
        } else if (expectedMadeDependent == RIGHT_SIDE){
            assertNotNull("Expected one side to be made dependent", prop1); //$NON-NLS-1$
            assertEquals(accessNode2, FrameUtil.findJoinSourceNode(joinNode.getLastChild()));
        } else if (expectedMadeDependent == NEITHER_SIDE){
            assertNull("Neither side should be dependent", prop1); //$NON-NLS-1$
        } else {
            fail("Invalid test constant " + expectedMadeDependent); //$NON-NLS-1$
        }
       
        Float cost1 = (Float)accessNode1.getProperty(NodeConstants.Info.EST_CARDINALITY);
        Float cost2 = (Float)accessNode2.getProperty(NodeConstants.Info.EST_CARDINALITY);
        assertNotNull(cost2);
        assertNotNull(cost1);
        if (expectedCost1 != null) {
          assertEquals(expectedCost1.longValue(), cost1.longValue());
          assertEquals(expectedCost2.longValue(), cost2.longValue());
        }
    }   
   
    // ################################## ACTUAL TESTS ################################
   
    @Test public void testValidJoin1() {
        PlanNode accessNode = NodeFactory.getNewNode(NodeConstants.Types.ACCESS);                      
        accessNode.addGroup(getPhysicalGroup(1));
                       
        PlanNode joinNode = NodeFactory.getNewNode(NodeConstants.Types.JOIN);      
        joinNode.setProperty(NodeConstants.Info.JOIN_TYPE, JoinType.JOIN_CROSS);
        joinNode.addFirstChild(accessNode);      

        helpTestValidJoin(joinNode, accessNode, false);
    }

    @Test public void testValidJoin2() {
        PlanNode accessNode = NodeFactory.getNewNode(NodeConstants.Types.ACCESS);                      
        accessNode.addGroup(getPhysicalGroup(1));
                       
        PlanNode joinNode = NodeFactory.getNewNode(NodeConstants.Types.JOIN);      
        joinNode.setProperty(NodeConstants.Info.JOIN_TYPE, JoinType.JOIN_FULL_OUTER);
        joinNode.setProperty(NodeConstants.Info.JOIN_CRITERIA, Arrays.asList(QueryRewriter.FALSE_CRITERIA));
        joinNode.addFirstChild(accessNode);      

        helpTestValidJoin(joinNode, accessNode, false);
    }

    @Test public void testValidJoin3() {
        PlanNode accessNode1 = NodeFactory.getNewNode(NodeConstants.Types.ACCESS);                      
        PlanNode accessNode2 = NodeFactory.getNewNode(NodeConstants.Types.ACCESS);                      
        accessNode1.addGroup(getPhysicalGroup(1));               
        accessNode2.addGroup(getPhysicalGroup(2));               
       
        PlanNode joinNode = NodeFactory.getNewNode(NodeConstants.Types.JOIN);      
        joinNode.setProperty(NodeConstants.Info.JOIN_TYPE, JoinType.JOIN_RIGHT_OUTER);
        List crits = new ArrayList();
        crits.add(new CompareCriteria(getElementSymbol(1,1), CompareCriteria.EQ, getElementSymbol(2,1)));
        joinNode.setProperty(NodeConstants.Info.JOIN_CRITERIA, crits);             
        joinNode.addLastChild(accessNode1);      
        joinNode.addLastChild(accessNode2);      

        helpTestValidJoin(joinNode, accessNode1, true);
    }

    @Test public void testValidJoin4() {
        PlanNode accessNode1 = NodeFactory.getNewNode(NodeConstants.Types.ACCESS);                      
        PlanNode accessNode2 = NodeFactory.getNewNode(NodeConstants.Types.ACCESS);                      
                       
        PlanNode joinNode = NodeFactory.getNewNode(NodeConstants.Types.JOIN);      
        joinNode.setProperty(NodeConstants.Info.JOIN_TYPE, JoinType.JOIN_RIGHT_OUTER);
        List crits = new ArrayList();
        crits.add(new CompareCriteria(getElementSymbol(1,1), CompareCriteria.EQ, getElementSymbol(2,1)));
        joinNode.setProperty(NodeConstants.Info.JOIN_CRITERIA, crits);             
        joinNode.addLastChild(accessNode1);      
        joinNode.addLastChild(accessNode2);      

        helpTestValidJoin(joinNode, accessNode2, false);
    }

    @Test public void testValidJoin5() {
        PlanNode accessNode1 = NodeFactory.getNewNode(NodeConstants.Types.ACCESS);                      
        PlanNode accessNode2 = NodeFactory.getNewNode(NodeConstants.Types.ACCESS);                      
                       
        PlanNode joinNode = NodeFactory.getNewNode(NodeConstants.Types.JOIN);      
        joinNode.setProperty(NodeConstants.Info.JOIN_TYPE, JoinType.JOIN_LEFT_OUTER);
        List crits = new ArrayList();
        crits.add(new CompareCriteria(getElementSymbol(1,1), CompareCriteria.EQ, getElementSymbol(2,1)));
        joinNode.setProperty(NodeConstants.Info.JOIN_CRITERIA, crits);             
        joinNode.addLastChild(accessNode1);      
        joinNode.addLastChild(accessNode2);      

        helpTestValidJoin(joinNode, accessNode1, false);
    }

    @Test public void testValidJoin6() {
        PlanNode accessNode1 = NodeFactory.getNewNode(NodeConstants.Types.ACCESS);                      
        PlanNode accessNode2 = NodeFactory.getNewNode(NodeConstants.Types.ACCESS);
        accessNode1.addGroup(getPhysicalGroup(1));               
        accessNode2.addGroup(getPhysicalGroup(2));     
                       
        PlanNode joinNode = NodeFactory.getNewNode(NodeConstants.Types.JOIN);      
        joinNode.setProperty(NodeConstants.Info.JOIN_TYPE, JoinType.JOIN_LEFT_OUTER);
        List crits = new ArrayList();
        crits.add(new CompareCriteria(getElementSymbol(1,1), CompareCriteria.EQ, getElementSymbol(2,1)));
        joinNode.setProperty(NodeConstants.Info.JOIN_CRITERIA, crits);             
        joinNode.addLastChild(accessNode1);      
        joinNode.addLastChild(accessNode2);      

        helpTestValidJoin(joinNode, accessNode2, true);
    }

    /**
     * Tests that heuristics will take a primary key in the atomic criteria into account when
     * making a dependent join.
     */
    @Test public void testChooseKey() throws Exception {
        //override default metadata
        this.metadata = FakeMetadataFactory.example4();
       
        GroupSymbol group1 = getPhysicalGroup(2,3);                   
        GroupSymbol group2 = getPhysicalGroup(3,3);                   

        //Join criteria
        ElementSymbol group1e1 = getElementSymbol(2,3,1);
        ElementSymbol group2e1 = getElementSymbol(3,3,1);
        CompareCriteria crit = new CompareCriteria(group2e1, CompareCriteria.EQ, group1e1);
        ArrayList crits = new ArrayList(1);
        crits.add(crit);

        Criteria atomicCrit1 = null;
        Criteria atomicCrit2 = new CompareCriteria(group2e1, CompareCriteria.EQ, new Constant(new Integer(5)));
        int expected = LEFT_SIDE;
        helpTestChooseSiblingAndMarkDependent(group1, atomicCrit1, group2, atomicCrit2, crits, expected);       
        expected = RIGHT_SIDE;
        helpTestChooseSiblingAndMarkDependent(group2, atomicCrit2, group1, atomicCrit1, crits, expected);       
    }

    /**
     * Neither side should be chosen since the left side lacks cardinality information and the right is not strong
     */
    @Test public void testChooseKey2() throws Exception {
        //override default metadata
        this.metadata = FakeMetadataFactory.example4();
       
        GroupSymbol group1 = getPhysicalGroup(2,3); //no key                
        GroupSymbol group1a = null;                
        GroupSymbol group2 = getPhysicalGroup(3,3); //has key                   
        GroupSymbol group2a = getPhysicalGroup(3,2); //no key                   

        ElementSymbol group1e1 = getElementSymbol(2,3,1);
        ElementSymbol group2e1 = getElementSymbol(3,3,1);
        ElementSymbol group2e2 = getElementSymbol(3,3,2);
        ElementSymbol group2ae1 = getElementSymbol(3,2,1);

        //Outer Join criteria
        CompareCriteria crit = new CompareCriteria(group2e1, CompareCriteria.EQ, group1e1);
        ArrayList crits = new ArrayList(1);
        crits.add(crit);

        //atomic select criteria
        Criteria atomicCrit1 = null;
        Criteria atomicCrit1a = null;
        Criteria atomicCrit2 = new CompareCriteria(group2e2, CompareCriteria.EQ, new Constant(new Integer(5)));
        Criteria atomicCrit2a = null;

        //atomic Join criteria 1
        Collection atomicJoinCrits1 = null;

        //atomic Join criteria 2
        CompareCriteria atomicJoinCrit2 = new CompareCriteria(group2ae1, CompareCriteria.EQ, group2e1);
        ArrayList atomicJoinCrits2 = new ArrayList(1);
        atomicJoinCrits2.add(atomicJoinCrit2);       
       
        int expected = NEITHER_SIDE;

        helpTestChooseSiblingAndMarkDependent(
         group1,
         atomicCrit1,
         group1a,
         atomicCrit1a,
         atomicJoinCrits1,
         group2,
         atomicCrit2,
         group2a,
         atomicCrit2a,
         atomicJoinCrits2,
         crits,
         expected, -1, 7930);       
    }
   
    /**
     * Tests that heuristics will take cardinality of a group into account when
     * making a dependent join.
     */
    @Test public void testCardinality() throws Exception {
        //override default metadata
        this.metadata = FakeMetadataFactory.example4();
       
        GroupSymbol group1 = getPhysicalGroup(1,2);                   
        GroupSymbol group2 = getPhysicalGroup(2,2);                   

        //Join criteria
        ElementSymbol pm1g2e1 = getElementSymbol(1,2,1);
        ElementSymbol pm2g2e1 = getElementSymbol(2,2,1);
        CompareCriteria crit = new CompareCriteria(pm2g2e1, CompareCriteria.EQ, pm1g2e1);
        ArrayList crits = new ArrayList(2);
        crits.add(crit);
        ElementSymbol pm1g2e2 = getElementSymbol(1,2,2);
        ElementSymbol pm2g2e2 = getElementSymbol(2,2,2);
        CompareCriteria crit2 = new CompareCriteria(pm1g2e2, CompareCriteria.EQ, pm2g2e2);
        crits.add(crit2);

        Criteria atomicCrit1 = null;
        Criteria atomicCrit2 = null;
        int expected = RIGHT_SIDE;
        helpTestChooseSiblingAndMarkDependent(group1, atomicCrit1, group2, atomicCrit2, crits, expected);       
        expected = LEFT_SIDE;
        helpTestChooseSiblingAndMarkDependent(group2, atomicCrit2, group1, atomicCrit1, crits, expected);       
    }

    /**
     * Tests that heuristics will take cardinality of a group into account when
     * making a dependent join, and that this information supercedes a key
     * in the atomic criteria.
     */
    @Test public void testCardinalityAndKey() throws Exception {
        //override default metadata
        this.metadata = FakeMetadataFactory.example4();
       
        GroupSymbol group1 = getPhysicalGroup(1,2);                   
        GroupSymbol group2 = getPhysicalGroup(2,2);                   

        //Join criteria
        ElementSymbol pm1g2e1 = getElementSymbol(1,2,1);
        ElementSymbol pm2g2e1 = getElementSymbol(2,2,1);
        CompareCriteria crit = new CompareCriteria(pm2g2e1, CompareCriteria.EQ, pm1g2e1);
        ArrayList crits = new ArrayList(1);
        crits.add(crit);
        ElementSymbol pm1g2e2 = getElementSymbol(1,2,2);
        ElementSymbol pm2g2e2 = getElementSymbol(2,2,2);
        CompareCriteria crit2 = new CompareCriteria(pm1g2e2, CompareCriteria.EQ, pm2g2e2);
        crits.add(crit2);

        Criteria atomicCrit1 = null;
        Criteria atomicCrit2 = null;
        int expected = RIGHT_SIDE;
        helpTestChooseSiblingAndMarkDependent(group1, atomicCrit1, group2, atomicCrit2, crits, expected);       
        expected = LEFT_SIDE;
        helpTestChooseSiblingAndMarkDependent(group2, atomicCrit2, group1, atomicCrit1, crits, expected);       
    }
   
    @Test public void testCardinalityAndKeyNestedLoop() throws Exception {
        //override default metadata
        this.metadata = FakeMetadataFactory.example4();
       
        GroupSymbol group1 = getPhysicalGroup(1,2);                   
        GroupSymbol group2 = getPhysicalGroup(2,2);                   

        //Join criteria
        ElementSymbol pm1g2e1 = getElementSymbol(1,2,1);
        ElementSymbol pm2g2e1 = getElementSymbol(2,2,1);
        CompareCriteria crit = new CompareCriteria(pm2g2e1, CompareCriteria.EQ, pm1g2e1);
        ArrayList crits = new ArrayList(1);
        crits.add(crit);
        ElementSymbol pm1g2e2 = getElementSymbol(1,2,2);
        ElementSymbol pm2g2e2 = getElementSymbol(2,2,2);
        CompareCriteria crit2 = new CompareCriteria(pm1g2e2, CompareCriteria.LT, pm2g2e2);
        crits.add(crit2);

        Criteria atomicCrit1 = null;
        Criteria atomicCrit2 = null;
        int expected = RIGHT_SIDE;
        helpTestChooseSiblingAndMarkDependent(group1, atomicCrit1, group2, atomicCrit2, crits, expected);       
        expected = LEFT_SIDE;
        helpTestChooseSiblingAndMarkDependent(group2, atomicCrit2, group1, atomicCrit1, crits, expected);       
    }
   
    @Test public void testRejectDependentJoin() throws Exception {
        //override default metadata
        this.metadata = FakeMetadataFactory.example4();
       
        GroupSymbol group1 = getPhysicalGroup(3,1);                   
        GroupSymbol group2 = getPhysicalGroup(3,2);                   

        //Join criteria
        ElementSymbol pm3g1e2 = getElementSymbol(3,1,2);
        ElementSymbol pm3g2e2 = getElementSymbol(3,2,2);
        CompareCriteria crit = new CompareCriteria(pm3g1e2, CompareCriteria.EQ, pm3g2e2);
        ArrayList crits = new ArrayList(1);
        crits.add(crit);

        Criteria atomicCrit1 = null;
        Criteria atomicCrit2 = null;
        int expected = NEITHER_SIDE;
        helpTestChooseSiblingAndMarkDependent(group1, atomicCrit1, group2, atomicCrit2, crits, expected);       
        expected = NEITHER_SIDE;
        helpTestChooseSiblingAndMarkDependent(group2, atomicCrit2, group1, atomicCrit1, crits, expected);       
    }
   
    /**
     * Tests that join side with larger cardinality will still have a lower
     * cost computed because it has a criteria including a primary key
     */
    @Test public void testCardinalityWithKeyCrit() throws Exception {
        //override default metadata
        this.metadata = FakeMetadataFactory.example4();
       
        GroupSymbol group1 = getPhysicalGroup(1,2);                   
        ElementSymbol g1e2 = getElementSymbol(1,2,2);

        GroupSymbol group2 = getPhysicalGroup(3,3);                   
        ElementSymbol g2e1 = getElementSymbol(3,3,1);
        ElementSymbol g2e2 = getElementSymbol(3,3,2);

        //Join criteria
        ArrayList crits = new ArrayList(1);
        CompareCriteria crit2 = new CompareCriteria(g1e2, CompareCriteria.EQ, g2e2);
        crits.add(crit2);

        Criteria atomicCrit1 = null;
        Criteria atomicCrit2 = new CompareCriteria(g2e1, CompareCriteria.EQ, new Constant(new Integer(5)));
        int expected = LEFT_SIDE;
        helpTestChooseSiblingAndMarkDependent(group1, atomicCrit1, group2, atomicCrit2, crits, expected);       
        expected = RIGHT_SIDE;
        helpTestChooseSiblingAndMarkDependent(group2, atomicCrit2, group1, atomicCrit1, crits, expected);       
    }   

    /**
     * Tests that join side with larger cardinality will still have a lower
     * cost computed because it has a criteria including a primary key
     */
    @Test public void testCardinalityWithKeyCompoundCritAND() throws Exception {
        //override default metadata
        this.metadata = FakeMetadataFactory.example4();
       
        GroupSymbol group1 = getPhysicalGroup(1,2);                   
        ElementSymbol g1e2 = getElementSymbol(1,2,2);

        GroupSymbol group2 = getPhysicalGroup(3,3);                   
        ElementSymbol g2e1 = getElementSymbol(3,3,1);
        ElementSymbol g2e2 = getElementSymbol(3,3,2);

        //Join criteria
        ArrayList crits = new ArrayList(1);
        crits.add(new CompareCriteria(g1e2, CompareCriteria.EQ, g2e2));

        Criteria atomicCrit1 = null;

        Criteria crit1 = new CompareCriteria(g2e1, CompareCriteria.EQ, new Constant(new Integer(5)));
        Criteria crit2 = new CompareCriteria(g2e1, CompareCriteria.EQ, new Constant(new Integer(7)));
        CompoundCriteria atomicCrit2 = new CompoundCriteria(CompoundCriteria.AND, crit1, crit2);
       
        int expected = LEFT_SIDE;
        helpTestChooseSiblingAndMarkDependent(group1, atomicCrit1, group2, atomicCrit2, crits, expected);       
        expected = RIGHT_SIDE;
        helpTestChooseSiblingAndMarkDependent(group2, atomicCrit2, group1, atomicCrit1, crits, expected);       
    }   

    /**
     * Tests that join side with larger cardinality will still have a lower
     * cost computed because it has a criteria including a primary key.
     * Defect 8445
     */
    @Test public void testCardinalityWithKeyCompoundCritOR() throws Exception {
        //override default metadata
        this.metadata = FakeMetadataFactory.example4();
       
        GroupSymbol group1 = getPhysicalGroup(1,2);                   
        ElementSymbol g1e2 = getElementSymbol(1,2,2);

        GroupSymbol group2 = getPhysicalGroup(3,3);                   
        ElementSymbol g2e1 = getElementSymbol(3,3,1);
        ElementSymbol g2e2 = getElementSymbol(3,3,2);

        //Join criteria
        ArrayList crits = new ArrayList(1);
        crits.add(new CompareCriteria(g1e2, CompareCriteria.EQ, g2e2));

        Criteria atomicCrit1 = null;

        Criteria crit1 = new CompareCriteria(g2e1, CompareCriteria.EQ, new Constant(new Integer(5)));
        Criteria crit2 = new CompareCriteria(g2e1, CompareCriteria.EQ, new Constant(new Integer(7)));
        CompoundCriteria atomicCrit2 = new CompoundCriteria(CompoundCriteria.OR, crit1, crit2);
       
        int expected = LEFT_SIDE;
        helpTestChooseSiblingAndMarkDependent(group1, atomicCrit1, group2, atomicCrit2, crits, expected);       
        expected = RIGHT_SIDE;
        helpTestChooseSiblingAndMarkDependent(group2, atomicCrit2, group1, atomicCrit1, crits, expected);       
   
   
    /**
     * Tests SetCriteria against a key column in the atomic criteria
     */
    @Test public void testCardinalityWithKeySetCrit() throws Exception {
        //override default metadata
        this.metadata = FakeMetadataFactory.example4();
       
        GroupSymbol group1 = getPhysicalGroup(1,2);                   
        ElementSymbol g1e2 = getElementSymbol(1,2,2);

        GroupSymbol group2 = getPhysicalGroup(3,3);                   
        ElementSymbol g2e1 = getElementSymbol(3,3,1);
        ElementSymbol g2e2 = getElementSymbol(3,3,2);

        //Join criteria
        ArrayList crits = new ArrayList(1);
        CompareCriteria crit2 = new CompareCriteria(g1e2, CompareCriteria.EQ, g2e2);
        crits.add(crit2);

        Criteria atomicCrit1 = null;
        Collection values = new LinkedList();
        values.add(new Constant(new Integer(3)));
        values.add(new Constant(new Integer(4)));
        values.add(new Constant(new Integer(5)));
        Criteria atomicCrit2 = new SetCriteria(g2e1, values);
        int expected = LEFT_SIDE;
        helpTestChooseSiblingAndMarkDependent(group1, atomicCrit1, group2, atomicCrit2, crits, expected);       
        expected = RIGHT_SIDE;
        helpTestChooseSiblingAndMarkDependent(group2, atomicCrit2, group1, atomicCrit1, crits, expected);       
    }    

    /**
     * Tests SetCriteria in the atomic criteria
     */
    @Test public void testCardinalityWithKeyMatchCrit() throws Exception {
        //override default metadata
        this.metadata = FakeMetadataFactory.example4();
       
        GroupSymbol group1 = getPhysicalGroup(1,2);                   
        ElementSymbol g1e2 = getElementSymbol(1,2,2);

        GroupSymbol group2 = getPhysicalGroup(3,3);                   
        ElementSymbol g2e1 = getElementSymbol(3,3,1);
        ElementSymbol g2e2 = getElementSymbol(3,3,2);

        //Join criteria
        ArrayList crits = new ArrayList(1);
        CompareCriteria crit2 = new CompareCriteria(g1e2, CompareCriteria.EQ, g2e2);
        crits.add(crit2);

        Criteria atomicCrit1 = null;
        Criteria atomicCrit2 = new MatchCriteria(g2e1, new Constant(new String("ab%"))); //$NON-NLS-1$
        int expected = RIGHT_SIDE;
        helpTestChooseSiblingAndMarkDependent(group1, atomicCrit1, group2, atomicCrit2, crits, expected);       
        expected = LEFT_SIDE;
        helpTestChooseSiblingAndMarkDependent(group2, atomicCrit2, group1, atomicCrit1, crits, expected);       
    }
   
    /**
     * Tests SetCriteria in the atomic criteria
     */
    @Test public void testCardinalityWithKeyIsNullCrit() throws Exception {
        //override default metadata
        this.metadata = FakeMetadataFactory.example4();
       
        GroupSymbol group1 = getPhysicalGroup(1,2);                   
        ElementSymbol g1e2 = getElementSymbol(1,2,2);

        GroupSymbol group2 = getPhysicalGroup(3,3);                   
        ElementSymbol g2e1 = getElementSymbol(3,3,1);
        ElementSymbol g2e2 = getElementSymbol(3,3,2);

        //Join criteria
        ArrayList crits = new ArrayList(1);
        CompareCriteria crit2 = new CompareCriteria(g1e2, CompareCriteria.EQ, g2e2);
        crits.add(crit2);

        Criteria atomicCrit1 = null;
        Criteria atomicCrit2 = new IsNullCriteria(g2e1);
        int expected = LEFT_SIDE;
        helpTestChooseSiblingAndMarkDependent(group1, atomicCrit1, group2, atomicCrit2, crits, expected);       
        expected = RIGHT_SIDE;
        helpTestChooseSiblingAndMarkDependent(group2, atomicCrit2, group1, atomicCrit1, crits, expected);       
    }    

    /**
     * Tests NotCriteria in the atomic criteria
     */
    @Test public void testCardinalityWithKeyNotCrit() throws Exception {
        //override default metadata
        this.metadata = FakeMetadataFactory.example4();
       
        GroupSymbol group1 = getPhysicalGroup(1,2);                   
        ElementSymbol g1e2 = getElementSymbol(1,2,2);

        GroupSymbol group2 = getPhysicalGroup(3,3);                   
        ElementSymbol g2e1 = getElementSymbol(3,3,1);
        ElementSymbol g2e2 = getElementSymbol(3,3,2);

        //Join criteria
        ArrayList crits = new ArrayList(1);
        CompareCriteria crit2 = new CompareCriteria(g1e2, CompareCriteria.EQ, g2e2);
        crits.add(crit2);

        Criteria atomicCrit1 = null;
        Criteria atomicCrit2 = new CompareCriteria(g2e1, CompareCriteria.EQ, new Constant(new Integer(5)));
        atomicCrit2 = new NotCriteria(atomicCrit2);       
        int expected = RIGHT_SIDE;
        helpTestChooseSiblingAndMarkDependent(group1, atomicCrit1, group2, atomicCrit2, crits, expected);       
        expected = LEFT_SIDE;
        helpTestChooseSiblingAndMarkDependent(group2, atomicCrit2, group1, atomicCrit1, crits, expected);      
    }

    /**
     * Tests that join side with larger cardinality will still have a lower
     * cost computed because it has a criteria including a primary key
     */
    @Test public void testCardinalityWithKeyComplexCrit() throws Exception {
        //override default metadata
        this.metadata = FakeMetadataFactory.example4();
       
        GroupSymbol group1 = getPhysicalGroup(1,2);                   
        ElementSymbol g1e2 = getElementSymbol(1,2,2);

        GroupSymbol group2 = getPhysicalGroup(3,3);                   
        ElementSymbol g2e1 = getElementSymbol(3,3,1);
        ElementSymbol g2e2 = getElementSymbol(3,3,2);

        //Join criteria
        ArrayList crits = new ArrayList(1);
        crits.add(new CompareCriteria(g1e2, CompareCriteria.EQ, g2e2));

        Criteria atomicCrit1 = null;

        Criteria crit1 = new CompareCriteria(g2e1, CompareCriteria.EQ, new Constant(new Integer(5)));
        Criteria crit2 = new CompareCriteria(g2e1, CompareCriteria.EQ, new Constant(new Integer(7)));
        CompoundCriteria atomicCrit2 = new CompoundCriteria(CompoundCriteria.AND, crit1, crit2);
        Criteria crit3 = new MatchCriteria(g2e1, new Constant(new String("ab"))); //$NON-NLS-1$
        atomicCrit2 = new CompoundCriteria(CompoundCriteria.OR, atomicCrit2, crit3);
       
        int expected = LEFT_SIDE;
        helpTestChooseSiblingAndMarkDependent(group1, atomicCrit1, group2, atomicCrit2, crits, expected);       
        expected = RIGHT_SIDE;
        helpTestChooseSiblingAndMarkDependent(group2, atomicCrit2, group1, atomicCrit1, crits, expected);       
   

    @Test public void testCardinalityWithKeyComplexCrit2() throws Exception {
        //override default metadata
        this.metadata = FakeMetadataFactory.example4();
       
        GroupSymbol group1 = getPhysicalGroup(1,2);                   
        ElementSymbol g1e2 = getElementSymbol(1,2,2);

        GroupSymbol group2 = getPhysicalGroup(3,3);                   
        ElementSymbol g2e1 = getElementSymbol(3,3,1);
        ElementSymbol g2e2 = getElementSymbol(3,3,2);

        //Join criteria
        ArrayList crits = new ArrayList(1);
        crits.add(new CompareCriteria(g1e2, CompareCriteria.EQ, g2e2));

        Criteria atomicCrit1 = null;

        Criteria crit1 = new CompareCriteria(g2e1, CompareCriteria.GT, new Constant(new Integer(5)));
        Criteria crit2 = new CompareCriteria(g2e1, CompareCriteria.LT, new Constant(new Integer(7)));
        Criteria atomicCrit2 = new CompoundCriteria(CompoundCriteria.AND, crit1, crit2);
        Criteria crit3 = new MatchCriteria(g2e1, new Constant(new String("cd%"))); //$NON-NLS-1$
        atomicCrit2 = new CompoundCriteria(CompoundCriteria.OR, atomicCrit2, crit3);
        atomicCrit2 = new NotCriteria(atomicCrit2);
       
        int expected = RIGHT_SIDE;
        helpTestChooseSiblingAndMarkDependent(group1, atomicCrit1, group2, atomicCrit2, crits, expected);       
        expected = LEFT_SIDE;
        helpTestChooseSiblingAndMarkDependent(group2, atomicCrit2, group1, atomicCrit1, crits, expected);       
    }

    @Test public void testCardinalityWithKeyComplexCrit3() throws Exception {
        //override default metadata
        this.metadata = FakeMetadataFactory.example4();
       
        GroupSymbol group1 = getPhysicalGroup(1,2);                   
        ElementSymbol g1e2 = getElementSymbol(1,2,2);

        GroupSymbol group2 = getPhysicalGroup(3,3);                   
        ElementSymbol g2e1 = getElementSymbol(3,3,1);
        ElementSymbol g2e2 = getElementSymbol(3,3,2);

        //Join criteria
        ArrayList crits = new ArrayList(1);
        crits.add(new CompareCriteria(g1e2, CompareCriteria.EQ, g2e2));

        Criteria atomicCrit1 = null;

        Criteria crit1 = new CompareCriteria(g2e1, CompareCriteria.GE, new Constant(new Integer(5)));
        Criteria crit2 = new CompareCriteria(g2e1, CompareCriteria.NE, new Constant(new Integer(7)));
        Criteria atomicCrit2 = new CompoundCriteria(CompoundCriteria.OR, crit1, crit2);
        atomicCrit2 = new NotCriteria(atomicCrit2);
        Criteria crit3 = new CompareCriteria(g2e1, CompareCriteria.LE, new Constant(new Integer(25)));
        atomicCrit2 = new CompoundCriteria(CompoundCriteria.AND, atomicCrit2, crit3);
       
        int expected = LEFT_SIDE;
        helpTestChooseSiblingAndMarkDependent(group1, atomicCrit1, group2, atomicCrit2, crits, expected);       
        expected = RIGHT_SIDE;
        helpTestChooseSiblingAndMarkDependent(group2, atomicCrit2, group1, atomicCrit1, crits, expected);       
    }

    /**
     * Tests that join side with larger cardinality and non-key criteria
     * will be made dependent
     */
    @Test public void testCardinalityWithNonKeyCrit() throws Exception {
        //override default metadata
        this.metadata = FakeMetadataFactory.example4();
       
        GroupSymbol group1 = getPhysicalGroup(1,2);                   
        ElementSymbol g1e1 = getElementSymbol(1,2,1);
//        ElementSymbol g1e2 = getElementSymbol(1,2,2);

        GroupSymbol group2 = getPhysicalGroup(3,3);                   
        ElementSymbol g2e1 = getElementSymbol(3,3,1);
        ElementSymbol g2e2 = getElementSymbol(3,3,2);

        //Join criteria
        ArrayList crits = new ArrayList(1);
        CompareCriteria crit2 = new CompareCriteria(g1e1, CompareCriteria.EQ, g2e1);
        crits.add(crit2);

        Criteria atomicCrit1 = null;
        Criteria atomicCrit2 = new CompareCriteria(g2e2, CompareCriteria.EQ, new Constant(new Integer(5)));
        int expected = RIGHT_SIDE;
        helpTestChooseSiblingAndMarkDependent(group1, atomicCrit1, group2, atomicCrit2, crits, expected);       
        expected = LEFT_SIDE;
        helpTestChooseSiblingAndMarkDependent(group2, atomicCrit2, group1, atomicCrit1, crits, expected);       
   
   
    /**
     * Tests that join side with larger cardinality will still have a lower
     * cost computed because it has a criteria including a primary key
     */
    @Test public void testCardinalityWithCriteriaAndJoin() throws Exception {
        //override default metadata
        this.metadata = FakeMetadataFactory.example4();
       
        GroupSymbol group1 = getPhysicalGroup(2,2); //no key                
        GroupSymbol group1a = null;                
        GroupSymbol group2 = getPhysicalGroup(3,3); //has key                   
        GroupSymbol group2a = getPhysicalGroup(3,1); //has key                   

        ElementSymbol group1e1 = getElementSymbol(2,2,1);
        ElementSymbol group2e1 = getElementSymbol(3,3,1);
        ElementSymbol group2e2 = getElementSymbol(3,3,2);
        ElementSymbol group2ae1 = getElementSymbol(3,1,1);
        ElementSymbol group2ae2 = getElementSymbol(3,1,2);

        //Outer Join criteria
        CompareCriteria crit = new CompareCriteria(group2e1, CompareCriteria.EQ, group1e1);
        ArrayList crits = new ArrayList(1);
        crits.add(crit);

        //atomic select criteria
        Criteria atomicCrit1 = null;
        Criteria atomicCrit1a = null;
        Criteria atomicCrit2 = new CompareCriteria(group2e1, CompareCriteria.EQ, new Constant(new Integer(5)));
        Criteria atomicCrit2a = new CompareCriteria(group2ae1, CompareCriteria.EQ, new Constant(new Integer(5)));

        //atomic Join criteria 1
        Collection atomicJoinCrits1 = null;

        //atomic Join criteria 2
        CompareCriteria atomicJoinCrit2 = new CompareCriteria(group2ae2, CompareCriteria.EQ, group2e2);
        ArrayList atomicJoinCrits2 = new ArrayList(1);
        atomicJoinCrits2.add(atomicJoinCrit2);       
       
        int expected = LEFT_SIDE;

        helpTestChooseSiblingAndMarkDependent(
         group1,
         atomicCrit1,
         group1a,
         atomicCrit1a,
         atomicJoinCrits1,
         group2,
         atomicCrit2,
         group2a,
         atomicCrit2a,
         atomicJoinCrits2,
         crits,
         expected, 1000, 1);       
    }   

    @Test public void testCardinalityWithAtomicCrossJoin() throws Exception {
        //override default metadata
        this.metadata = FakeMetadataFactory.example4();
       
        GroupSymbol group1 = getPhysicalGroup(2,2); //no key                
        GroupSymbol group1a = null;                
        GroupSymbol group2 = getPhysicalGroup(3,3); //has key                   
        GroupSymbol group2a = getPhysicalGroup(3,1); //has key                   

        ElementSymbol group1e1 = getElementSymbol(2,2,1);
        ElementSymbol group2e1 = getElementSymbol(3,3,1);

        //Outer Join criteria
        CompareCriteria crit = new CompareCriteria(group2e1, CompareCriteria.EQ, group1e1);
        ArrayList crits = new ArrayList(1);
        crits.add(crit);

        //atomic select criteria
        Criteria atomicCrit1 = null;
        Criteria atomicCrit1a = null;
        Criteria atomicCrit2 = new CompareCriteria(group2e1, CompareCriteria.EQ, new Constant(new Integer(5)));
        Criteria atomicCrit2a = null;

        //atomic Join criteria 1
        Collection atomicJoinCrits1 = null;

        //atomic Join criteria 2
        List atomicJoinCrits2 = Collections.EMPTY_LIST; //INDICATES CROSS JOIN
       
        int expected = NEITHER_SIDE;

        helpTestChooseSiblingAndMarkDependent(
         group1,
         atomicCrit1,
         group1a,
         atomicCrit1a,
         atomicJoinCrits1,
         group2,
         atomicCrit2,
         group2a,
         atomicCrit2a,
         atomicJoinCrits2,
         crits,
         expected, 1000, 1E5);       
    }
   
    @Test public void testCardinalityWithAtomicCrossJoin2() throws Exception {
        //override default metadata
        this.metadata = FakeMetadataFactory.example4();
       
        GroupSymbol group1 = getPhysicalGroup(2,2); //no key                
        GroupSymbol group1a = null;                
        GroupSymbol group2 = getPhysicalGroup(3,3); //has key                   
        GroupSymbol group2a = getPhysicalGroup(3,1); //has key                   

        ElementSymbol group1e1 = getElementSymbol(2,2,1);
        ElementSymbol group2e1 = getElementSymbol(3,3,1);

        //Outer Join criteria
        CompareCriteria crit = new CompareCriteria(group2e1, CompareCriteria.EQ, group1e1);
        ArrayList crits = new ArrayList(1);
        crits.add(crit);

        //atomic select criteria
        Criteria atomicCrit1 = null;
        Criteria atomicCrit1a = null;
        Criteria atomicCrit2 = new CompareCriteria(group2e1, CompareCriteria.NE, new Constant(new Integer(5)));
        Criteria atomicCrit2a = null;

        //atomic Join criteria 1
        Collection atomicJoinCrits1 = null;

        //atomic Join criteria 2
        List atomicJoinCrits2 = Collections.EMPTY_LIST; //INDICATES CROSS JOIN
       
        int expected = RIGHT_SIDE;

        helpTestChooseSiblingAndMarkDependent(
         group1,
         atomicCrit1,
         group1a,
         atomicCrit1a,
         atomicJoinCrits1,
         group2,
         atomicCrit2,
         group2a,
         atomicCrit2a,
         atomicJoinCrits2,
         crits,
         expected, 1000, 9999899648l);       
    }    

    // ################################## TEST SUITE ################################

    private static final boolean DEBUG = false;
}
TOP

Related Classes of org.teiid.query.optimizer.relational.rules.TestRuleChooseDependent

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.