Package org.voltdb.expressions

Source Code of org.voltdb.expressions.TestExpressionUtil$TestExpressionTreeWalker

/* This file is part of VoltDB.
* Copyright (C) 2008-2010 VoltDB L.L.C.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
package org.voltdb.expressions;

import java.util.*;

import org.voltdb.VoltType;
import org.voltdb.expressions.AbstractExpression;
import org.voltdb.expressions.ComparisonExpression;
import org.voltdb.expressions.ConjunctionExpression;
import org.voltdb.expressions.ConstantValueExpression;
import org.voltdb.expressions.ExpressionUtil;
import org.voltdb.expressions.ParameterValueExpression;
import org.voltdb.expressions.TupleValueExpression;
import org.voltdb.types.*;

import junit.framework.*;

/**
*
*
*/
public class TestExpressionUtil extends TestCase {
    /**
     * Used for traversing trees.
     *
     */
    static abstract class TestExpressionTreeWalker {

        /**
         * Expression node stack
         */
        private final Stack<AbstractExpression> m_stack = new Stack<AbstractExpression>();

        /**
         * How deep we are in the tree
         */
        private int m_depth = -1;

        /**
         * Depth first traveral
         * @param exp
         */
        public final void traverse(AbstractExpression exp) {
            m_stack.push(exp);
            m_depth++;
            if (exp.getLeft() != null) {
                traverse(exp.getLeft());
            }
            if (exp.getRight() != null) {
                traverse(exp.getRight());
            }
            AbstractExpression check_exp = m_stack.pop();
            assert(exp.equals(check_exp));
            callback(exp);
            m_depth--;
        }

        /**
         * Returns the parent of the current node in callback()
         * @return
         */
        protected final AbstractExpression getParent() {
            AbstractExpression ret = null;
            if (!m_stack.isEmpty()) ret = m_stack.peek();
            return ret;
        }

        /**
         * Returns the depth of the current callback() invocation
         * @return
         */
        protected final int getDepth() {
            return m_depth;
        }

        /**
         * This method will be called after the walker has explored a node's children
         * @param exp the Expression object to perform an operation on
         */
        public abstract void callback(AbstractExpression exp);
    }

    //
    //        AND
    //       /   \
    //    EQUAL  NOT
    //    /   \   |
    //   P   T  C
    //
    protected static final AbstractExpression ROOT_EXP = new ConjunctionExpression(ExpressionType.CONJUNCTION_AND);
    protected static final AbstractExpression CHILD_EXPS[] = { new ComparisonExpression(ExpressionType.COMPARE_EQUAL),
                                                               new ComparisonExpression(ExpressionType.OPERATOR_NOT),
                                                               new ParameterValueExpression(),
                                                               new TupleValueExpression(),
                                                               new ConstantValueExpression()
    };
    static {
        ROOT_EXP.setLeft(CHILD_EXPS[0]);
        ROOT_EXP.setRight(CHILD_EXPS[1]);
        CHILD_EXPS[0].setLeft(CHILD_EXPS[2]);
        CHILD_EXPS[0].setRight(CHILD_EXPS[3]);
        CHILD_EXPS[1].setLeft(CHILD_EXPS[4]);
        //ExpressionUtil.generateIds(ROOT_EXP);
    } // STATIC

    // ------------------------------------------------------------------
    // COMPARISON METHODS
    // ------------------------------------------------------------------

    protected static void compareExpressionTrees(AbstractExpression out_exp, AbstractExpression in_exp) {
        //
        // Make sure that compacted tree is exactly the same as the original
        // sub-tree that should have been preserved
        //
        final Vector<AbstractExpression> orig_list = new Vector<AbstractExpression>();
        new TestExpressionTreeWalker() {
            @Override
            public void callback(AbstractExpression exp) {
                orig_list.add(exp);
            }
        }.traverse(out_exp);
        assertFalse(orig_list.isEmpty());

        new TestExpressionTreeWalker() {
            @Override
            public void callback(AbstractExpression exp) {
                assertFalse(orig_list.isEmpty());
                AbstractExpression pop_exp = orig_list.remove(0);
                TestExpressionUtil.compareExpressions(pop_exp, exp);
            }
        }.traverse(in_exp);
    }

    protected static void compareExpressions(AbstractExpression out_exp, AbstractExpression in_exp) {
        //
        // ID
        //
        /*if (out_exp.getId() != null) {
            assertNotNull(in_exp.getId());
            if (!out_exp.getId().equals(in_exp.getId())) {
                System.err.println("OUT: " + out_exp);
                System.err.println("IN:  " + in_exp);
            }
            assertEquals(out_exp.getId(), in_exp.getId());
        } else {
            assertNull(in_exp.getId());
        }*/
        //
        // LEFT & RIGHT
        //
        assertEquals((out_exp.getLeft() == null), (in_exp.getLeft() == null));
        assertEquals((out_exp.getRight() == null), (in_exp.getRight() == null));
        //
        // VALUE TYPE
        //
        if (out_exp.getValueType() != in_exp.getValueType()) {
            System.err.println("OUT: " + out_exp.getValueType());
            System.err.println("IN:  " + in_exp.getValueType());
        }
        assertEquals(out_exp.getValueType(), in_exp.getValueType());
        //
        // Specialized Checks
        //
        switch (out_exp.getExpressionType()) {
            case VALUE_CONSTANT: {
                ConstantValueExpression out_const_exp = (ConstantValueExpression)out_exp;
                ConstantValueExpression in_const_exp = (ConstantValueExpression)in_exp;
                assertEquals(out_const_exp.getValue(), in_const_exp.getValue());
                break;
            }
            case VALUE_PARAMETER:
                ParameterValueExpression out_param_exp = (ParameterValueExpression)out_exp;
                ParameterValueExpression in_param_exp = (ParameterValueExpression)in_exp;
                assertEquals(out_param_exp.getParameterId(), in_param_exp.getParameterId());
                break;
            case VALUE_TUPLE:
                TupleValueExpression out_tuple_exp = (TupleValueExpression)out_exp;
                TupleValueExpression in_tuple_exp = (TupleValueExpression)in_exp;
                assertEquals(out_tuple_exp.getColumnIndex(), in_tuple_exp.getColumnIndex());
                break;
        } // SWITCH
        return;
    }

    // ------------------------------------------------------------------
    // TEST CASES
    // ------------------------------------------------------------------

    /**
     *  Clone Sub-Tree
     */
    public void testClone() {
        AbstractExpression cloned_exp = null;
        try {
            cloned_exp = ExpressionUtil.clone(ROOT_EXP);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        assertNotNull(cloned_exp);

        //
        // First build our lists of information about each node in the orignal tree
        // It is assumed that the tree will be traversed in the same order
        //
        final ArrayList<AbstractExpression> orig_exps = new ArrayList<AbstractExpression>();
        new TestExpressionTreeWalker() {
            @Override
            public void callback(AbstractExpression exp) {
                orig_exps.add(exp);
            }
        }.traverse(ROOT_EXP);
        //
        // Then walk through the cloned tree and make sure the objects are different
        // but the information is the same
        //
        new TestExpressionTreeWalker() {
            @Override
            public void callback(AbstractExpression exp) {
                assertFalse(orig_exps.isEmpty());
                AbstractExpression orig_exp = orig_exps.remove(0);
                //
                // We want to make sure that the cloned Expression doesn't
                // have the its ID set to its hashCode
                //
                assertTrue(orig_exp.hashCode() != exp.hashCode());
                //assertFalse(orig_exp.getId().equals(Integer.toString(exp.hashCode())));
                //
                // Use our general comparison method to check other things
                //
                TestExpressionUtil.compareExpressions(orig_exp, exp);
            }
        }.traverse(cloned_exp);
    }

    /**
     *
     *
     */
    public void testCombine() {
        //
        // We create a bunch of individual ComparisonExpression trees and we then
        // combine them into a single tree created with AND conjunctions
        //
        int num_of_subtrees = 5;
        final List<AbstractExpression> combine_exps = new ArrayList<AbstractExpression>();
        final Map<AbstractExpression, AbstractExpression> combine_exps_left = new HashMap<AbstractExpression, AbstractExpression>();
        final Map<AbstractExpression, AbstractExpression> combine_exps_right = new HashMap<AbstractExpression, AbstractExpression>();
        for (int ctr = 0; ctr < num_of_subtrees; ctr++) {
            AbstractExpression exps[] = { new ComparisonExpression(ExpressionType.COMPARE_EQUAL),
                                          new ParameterValueExpression(),
                                          new TupleValueExpression()
            };
            exps[0].setLeft(exps[1]);
            exps[0].setRight(exps[2]);
            //ExpressionUtil.generateIds(exps[0]);
            combine_exps.add(exps[0]);
            combine_exps_left.put(exps[0], exps[1]);
            combine_exps_right.put(exps[0], exps[2]);
        } // FOR

        AbstractExpression combined_exp = null;
        try {
            combined_exp = ExpressionUtil.combine(combine_exps);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        assertNotNull(combined_exp);
        assertEquals(combined_exp.getExpressionType(), ExpressionType.CONJUNCTION_AND);
        //System.err.println(combined_exp.toString(true));

        //
        // Checking whether this worked is a bit tricky because the ordering of the may
        // be different if the implementation changges. So we just need to check to make
        // sure that all of our sub-trees are contained within the new tree and that their
        // structure has not changed
        //
        new TestExpressionTreeWalker() {
            @Override
            public void callback(AbstractExpression exp) {
                //
                // This node was in our original tree
                //
                if (combine_exps.contains(exp)) {
                    assertTrue(combine_exps_left.containsKey(exp));
                    TestExpressionUtil.compareExpressions(exp.getLeft(), combine_exps_left.get(exp));
                    assertTrue(combine_exps_right.containsKey(exp));
                    TestExpressionUtil.compareExpressions(exp.getRight(), combine_exps_right.get(exp));
                    //
                    // Make sure our parent is a CONJUNCTION_AND expression node
                    //
                    assertNotNull(this.getParent());
                    assertEquals(this.getParent().getExpressionType(), ExpressionType.CONJUNCTION_AND);
                //
                // If this is a CONJUNCTION_AND that we added, make sure that both of its
                // children are not null
                //
                } else if (exp.getExpressionType() == ExpressionType.CONJUNCTION_AND) {
                    assertNotNull(exp.getLeft());
                    assertNotNull(exp.getRight());
                }
            }
        }.traverse(combined_exp);
    }

    // This is basically just a check that the rules in
    // VoltTypeUtil.determineImplicitCasting() push up through the aggregate
    // expression properly.  We'll just do a few of the corner cases and
    // call it good.
    public void testAssignOutputValueTypesRecursivelyForAggregateAvg()
    {
        AbstractExpression root =
            new AggregateExpression(ExpressionType.AGGREGATE_AVG);

        AbstractExpression op = new TupleValueExpression();
        root.setLeft(op);

        // Simple tuple value type gets pushed through
        op.setValueType(VoltType.FLOAT);
        ExpressionUtil.assignOutputValueTypesRecursively(root);
        assertEquals(VoltType.FLOAT, root.getValueType());

        op.setValueType(VoltType.INTEGER);
        ExpressionUtil.assignOutputValueTypesRecursively(root);
        assertEquals(VoltType.INTEGER, root.getValueType());

        op.setValueType(VoltType.DECIMAL);
        ExpressionUtil.assignOutputValueTypesRecursively(root);
        assertEquals(VoltType.DECIMAL, root.getValueType());

        op = new OperatorExpression();
        root.setLeft(op);

        AbstractExpression left = new TupleValueExpression();
        AbstractExpression right = new TupleValueExpression();

        op.setLeft(left);
        op.setRight(right);

        // FLOAT + int type gets promoted to FLOAT
        left.setValueType(VoltType.FLOAT);
        right.setValueType(VoltType.INTEGER);
        ExpressionUtil.assignOutputValueTypesRecursively(root);
        assertEquals(VoltType.FLOAT, root.getValueType());

        // random INT types get promoted to BIGINT
        left.setValueType(VoltType.TINYINT);
        right.setValueType(VoltType.INTEGER);
        ExpressionUtil.assignOutputValueTypesRecursively(root);
        assertEquals(VoltType.BIGINT, root.getValueType());

        // DECIMAL works, at least
        left.setValueType(VoltType.DECIMAL);
        right.setValueType(VoltType.DECIMAL);
        ExpressionUtil.assignOutputValueTypesRecursively(root);
        assertEquals(VoltType.DECIMAL, root.getValueType());
    }

    /** Base case test of NUMERIC literal processing */
    public void testAssignLiteralConstantTypes()
    {
        AbstractExpression lit_dec;
        AbstractExpression dec_lit;
        AbstractExpression lit;
        AbstractExpression dec;
        AbstractExpression bint;

        // convert NUMERIC to DECIMAL right/left
        lit = new ConstantValueExpression();
        lit.m_valueType = VoltType.NUMERIC;
        lit.m_valueSize = VoltType.NUMERIC.getLengthInBytesForFixedTypes();
        dec = new ConstantValueExpression();
        dec.m_valueType = VoltType.DECIMAL;
        dec.m_valueSize = VoltType.DECIMAL.getLengthInBytesForFixedTypes();
        lit_dec = new OperatorExpression(ExpressionType.OPERATOR_PLUS, lit, dec);

        ExpressionUtil.assignLiteralConstantTypesRecursively(lit_dec, VoltType.STRING);
        assertEquals(lit.m_valueType, VoltType.DECIMAL);
        assertEquals(lit.m_valueSize, VoltType.DECIMAL.getLengthInBytesForFixedTypes());
        assertEquals(dec.m_valueType, VoltType.DECIMAL);
        assertEquals(dec.m_valueSize, VoltType.DECIMAL.getLengthInBytesForFixedTypes());

        // convert NUMERIC to DECIMAL (left/right)
        lit = new ConstantValueExpression();
        lit.m_valueType = VoltType.NUMERIC;
        lit.m_valueSize = VoltType.NUMERIC.getLengthInBytesForFixedTypes();
        dec = new ConstantValueExpression();
        dec.m_valueType = VoltType.DECIMAL;
        dec.m_valueSize = VoltType.DECIMAL.getLengthInBytesForFixedTypes();
        dec_lit = new OperatorExpression(ExpressionType.OPERATOR_DIVIDE, dec, lit);

        ExpressionUtil.assignLiteralConstantTypesRecursively(dec_lit, VoltType.STRING);
        assertEquals(lit.m_valueType, VoltType.DECIMAL);
        assertEquals(lit.m_valueSize, VoltType.DECIMAL.getLengthInBytesForFixedTypes());
        assertEquals(dec.m_valueType, VoltType.DECIMAL);
        assertEquals(dec.m_valueSize, VoltType.DECIMAL.getLengthInBytesForFixedTypes());


        // convert numeric to float
        lit = new ConstantValueExpression();
        lit.m_valueType = VoltType.NUMERIC;
        lit.m_valueSize = VoltType.NUMERIC.getLengthInBytesForFixedTypes();
        bint = new ConstantValueExpression();
        bint.m_valueType = VoltType.BIGINT;
        bint.m_valueSize = VoltType.BIGINT.getLengthInBytesForFixedTypes();
        AbstractExpression lit_bint =
            new OperatorExpression(ExpressionType.OPERATOR_MINUS, lit, bint);

        ExpressionUtil.assignLiteralConstantTypesRecursively(lit_bint, VoltType.STRING);
        assertEquals(lit.m_valueType, VoltType.FLOAT);
        assertEquals(lit.m_valueSize, VoltType.FLOAT.getLengthInBytesForFixedTypes());
        assertEquals(bint.m_valueType, VoltType.BIGINT);
        assertEquals(bint.m_valueSize, VoltType.BIGINT.getLengthInBytesForFixedTypes());

        // test a larger tree
        lit = new ConstantValueExpression();
        lit.m_valueType = VoltType.NUMERIC;
        lit.m_valueSize = VoltType.NUMERIC.getLengthInBytesForFixedTypes();
        bint = new ConstantValueExpression();
        bint.m_valueType = VoltType.DECIMAL;
        bint.m_valueSize = VoltType.DECIMAL.getLengthInBytesForFixedTypes();
        lit_bint = new OperatorExpression(ExpressionType.OPERATOR_MINUS, lit, bint);

        AbstractExpression root = new OperatorExpression(ExpressionType.OPERATOR_MULTIPLY,
                lit_bint, new TupleValueExpression());
        ExpressionUtil.assignLiteralConstantTypesRecursively(root);
        assertEquals(lit.m_valueType, VoltType.DECIMAL);
        assertEquals(lit.m_valueSize, VoltType.DECIMAL.getLengthInBytesForFixedTypes());
        assertEquals(bint.m_valueType, VoltType.DECIMAL);
        assertEquals(bint.m_valueSize, VoltType.DECIMAL.getLengthInBytesForFixedTypes());
    }

}
TOP

Related Classes of org.voltdb.expressions.TestExpressionUtil$TestExpressionTreeWalker

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.