private Object eval()

in openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java [988:1539]


    private Object eval(JPQLNode node) {
        Value val1 = null;
        Value val2 = null;
        Value val3 = null;

        boolean not = node.not;

        switch (node.id) {
            case JJTSCALAREXPRESSION:
                return eval(onlyChild(node));

            case JJTTYPE:
                return getType(onlyChild(node));

            case JJTTYPELITERAL:
                return getTypeLiteral(node);

            case JJTCLASSNAME:
                return getPathOrConstant(node);

            case JJTCASE:
                return eval(onlyChild(node));

            case JJTSIMPLECASE:
                return getSimpleCaseExpression(node);

            case JJTGENERALCASE:
                return getGeneralCaseExpression(node);

            case JJTWHEN:
                return getWhenCondition(node);

            case JJTWHENSCALAR:
                return getWhenScalar(node);

            case JJTCOALESCE:
                return getCoalesceExpression(node);

            case JJTNULLIF:
                return getNullIfExpression(node);

            case JJTWHERE: // top-level WHERE clause
                return getExpression(onlyChild(node));

            case JJTBOOLEANLITERAL:
                return factory.newLiteral("true".equalsIgnoreCase
                    (node.text) ? Boolean.TRUE : Boolean.FALSE,
                    Literal.TYPE_BOOLEAN);

            case JJTINTEGERLITERAL:
                // use BigDecimal because it can handle parsing exponents
                BigDecimal intlit = new BigDecimal
                    (node.text.endsWith("l") || node.text.endsWith("L")
                        ? node.text.substring(0, node.text.length() - 1)
                        : node.text).
                    multiply(new BigDecimal(negative(node)));
                return factory.newLiteral(intlit.longValue(),
                    Literal.TYPE_NUMBER);

            case JJTDECIMALLITERAL:
                BigDecimal declit = new BigDecimal
                    (node.text.endsWith("d") || node.text.endsWith("D") ||
                        node.text.endsWith("f") || node.text.endsWith("F")
                        ? node.text.substring(0, node.text.length() - 1)
                        : node.text).
                    multiply(new BigDecimal(negative(node)));
                return factory.newLiteral(declit, Literal.TYPE_NUMBER);

            case JJTSTRINGLITERAL:
            case JJTTRIMCHARACTER:
            case JJTESCAPECHARACTER:
                return factory.newLiteral(trimQuotes(node.text),
                    Literal.TYPE_SQ_STRING);

            case JJTSTRINGLITERAL2:
                return factory.newLiteral(trimDoubleQuotes(node.text),
                    Literal.TYPE_SQ_STRING);

            case JJTPATTERNVALUE:
                return eval(firstChild(node));

            case JJTNAMEDINPUTPARAMETER:
                return getParameter(onlyChild(node).text, false, false);

            case JJTPOSITIONALINPUTPARAMETER:
                return getParameter(node.text, true, false);

            case JJTCOLLECTIONPARAMETER:
                JPQLNode child = onlyChild(node);
                boolean positional = child.id == JJTPOSITIONALINPUTPARAMETER;
                if (!positional)
                    child = onlyChild(child);
                return getParameter(child.text,
                    positional, true);

            case JJTOR: // x OR y
                return factory.or(getExpression(left(node)),
                    getExpression(right(node)));

            case JJTAND: // x AND y
                return and(getExpression(left(node)),
                    getExpression(right(node)));

            case JJTEQUALS: // x = y
                val1 = getValue(left(node));
                val2 = getValue(right(node));
                setImplicitTypes(val1, val2, null);
                return factory.equal(val1, val2);

            case JJTNOTEQUALS: // x <> y
                val1 = getValue(left(node));
                val2 = getValue(right(node));
                setImplicitTypes(val1, val2, null);
                return factory.notEqual(val1, val2);

            case JJTLESSTHAN: // x < y
                val1 = getValue(left(node));
                val2 = getValue(right(node));
                setImplicitTypes(val1, val2, null);
                return factory.lessThan(val1, val2);

            case JJTLESSOREQUAL: // x <= y
                val1 = getValue(left(node));
                val2 = getValue(right(node));
                setImplicitTypes(val1, val2, null);
                return factory.lessThanEqual(val1, val2);

            case JJTGREATERTHAN: // x > y
                val1 = getValue(left(node));
                val2 = getValue(right(node));
                setImplicitTypes(val1, val2, null);
                return factory.greaterThan(val1, val2);

            case JJTGREATEROREQUAL: // x >= y
                val1 = getValue(left(node));
                val2 = getValue(right(node));
                setImplicitTypes(val1, val2, null);
                return factory.greaterThanEqual(val1, val2);

            case JJTADD: // x + y
                val1 = getValue(left(node));
                val2 = getValue(right(node));
                setImplicitTypes(val1, val2, TYPE_NUMBER);
                return factory.add(val1, val2);

            case JJTSUBTRACT: // x - y
                val1 = getValue(left(node));
                val2 = getValue(right(node));
                setImplicitTypes(val1, val2, TYPE_NUMBER);
                return factory.subtract(val1, val2);

            case JJTMULTIPLY: // x * y
                val1 = getValue(left(node));
                val2 = getValue(right(node));
                setImplicitTypes(val1, val2, TYPE_NUMBER);
                return factory.multiply(val1, val2);

            case JJTDIVIDE: // x / y
                val1 = getValue(left(node));
                val2 = getValue(right(node));
                setImplicitTypes(val1, val2, TYPE_NUMBER);
                return factory.divide(val1, val2);

            case JJTBETWEEN: // x.field [NOT] BETWEEN 5 AND 10
                val1 = getValue(child(node, 0, 3));
                val2 = getValue(child(node, 1, 3));
                val3 = getValue(child(node, 2, 3));
                setImplicitTypes(val1, val2, null);
                setImplicitTypes(val1, val3, null);
                return evalNot(not, and(factory.greaterThanEqual(val1, val2),
                    factory.lessThanEqual(val1, val3)));

            case JJTIN: // x.field [NOT] IN ('a', 'b', 'c')
                        // TYPE(x...) [NOT] IN (entityTypeLiteral1,...)
                Expression inExp = null;
                Iterator<JPQLNode> inIterator = node.iterator();
                // the first child is the path
                JPQLNode first = inIterator.next();
                val1 = getValue(first);
                while (inIterator.hasNext()) {
                    JPQLNode next = inIterator.next();
                    if (first.id == JJTTYPE && next.id == JJTTYPELITERAL)
                        val2 = getTypeLiteral(next);
                    else
                        val2 = getValue(next);
                    if (val2 instanceof Parameter) {
                        hasParameterizedInExpression = true;
                    }
                    // special case for <value> IN (<subquery>) or
                    // <value> IN (<single value>)
                    if (useContains(not, val1, val2, node))
                        return evalNot(not, factory.contains(val2, val1));

                    // this is currently a sequence of OR expressions, since we
                    // do not have support for IN expressions
                    setImplicitTypes(val1, val2, null);
                    if (isVerticalTypeInExpr(val1, node) && not) {
                        if (inExp == null)
                            inExp = factory.notEqual(val1, val2);
                        else
                            inExp = factory.and(inExp, factory.notEqual(val1, val2));
                    } else {
                        if (inExp == null)
                            inExp = factory.equal(val1, val2);
                        else
                            inExp = factory.or(inExp, factory.equal(val1, val2));
                    }
                }


                // we additionally need to add in a "NOT NULL" clause, since
                // the IN behavior that is expected by the CTS also expects
                // to filter our NULLs
                if (isVerticalTypeInExpr(val1, node))
                    return inExp;
                else
                    return and(evalNot(not, inExp),
                            factory.notEqual(val1, factory.getNull()));

            case JJTISNULL: // x.field IS [NOT] NULL
                val1 = getValue(onlyChild(node));
                checkEmbeddable(val1);
                if (not)
                    return factory.notEqual
                        (val1, factory.getNull());
                else
                    return factory.equal
                        (val1, factory.getNull());

            case JJTPATH:
                return getPathOrConstant(node);

            case JJTIDENTIFIER:
            case JJTIDENTIFICATIONVARIABLE:
                return getIdentifier(node);

            case JJTQUALIFIEDPATH:
                return getQualifiedPath(node);

            case JJTQUALIFIEDIDENTIFIER:
                // KEY(e), VALUE(e), ENTRY(e)
                return getQualifiedIdentifier(node);

            case JJTGENERALIDENTIFIER:
                // KEY(e), VALUE(e)
                if (node.parent.parent.id == JJTWHERE || node.parent.id == JJTGROUPBY)
                    return getGeneralIdentifier(onlyChild(node), true);
                return getQualifiedIdentifier(onlyChild(node));

            case JJTNOT:
                return factory.not(getExpression(onlyChild(node)));

            case JJTLIKE: // field LIKE '%someval%'
                val1 = getValue(left(node));
                val2 = getValue(right(node));

                setImplicitType(val1, TYPE_STRING);
                setImplicitType(val2, TYPE_STRING);

                // look for an escape character beneath the node
                String escape = null;
                JPQLNode escapeNode = right(node).
                    findChildByID(JJTESCAPECHARACTER, true);
                if (escapeNode != null)
                    escape = trimQuotes(onlyChild(escapeNode).text);

                if (not)
                    return factory.notMatches(val1, val2, "_", "%", escape);
                else
                    return factory.matches(val1, val2, "_", "%", escape);

            case JJTISEMPTY:
                return evalNot(not,
                    factory.isEmpty(getValue(onlyChild(node))));

            case JJTSIZE:
                return factory.size(getValue(onlyChild(node)));

            case JJTINDEX:
                return factory.index(getValue(onlyChild(node)));

            case JJTUPPER:
                val1 = getValue(onlyChild(node));
                setImplicitType(val1, TYPE_STRING);
                return factory.toUpperCase(val1);

            case JJTLOWER:
                return factory.toLowerCase(getStringValue(onlyChild(node)));

            case JJTLENGTH:
                return factory.stringLength(getStringValue(onlyChild(node)));

            case JJTABS:
                return factory.abs(getNumberValue(onlyChild(node)));
                
            case JJTCEILING:
            	return factory.ceiling(getNumberValue(onlyChild(node)));

            case JJTEXP:
                return factory.exp(getNumberValue(onlyChild(node)));

            case JJTFLOOR:
                return factory.floor(getNumberValue(onlyChild(node)));

            case JJTLN:
                return factory.ln(getNumberValue(onlyChild(node)));
            
            case JJTSIGN:
                return factory.sign(getNumberValue(onlyChild(node)));

            case JJTPOWER:
                return factory.power(getNumberValue(firstChild(node)), getNumberValue(secondChild(node)));
            
            case JJTROUND:
                return factory.round(getNumberValue(firstChild(node)), getNumberValue(secondChild(node)));

            case JJTSQRT:
                return factory.sqrt(getNumberValue(onlyChild(node)));

            case JJTMOD:
                val1 = getValue(left(node));
                val2 = getValue(right(node));
                setImplicitTypes(val1, val2, TYPE_NUMBER);
                return factory.mod(val1, val2);

            case JJTTRIM: // TRIM([[where] [char] FROM] field)
                val1 = getValue(lastChild(node));
                setImplicitType(val1, TYPE_STRING);

                Boolean trimWhere = null;

                JPQLNode firstTrimChild = firstChild(node);

                if (node.getChildCount() > 1) {
                    trimWhere =
                        firstTrimChild.id == JJTTRIMLEADING ? Boolean.TRUE
                            :
                            firstTrimChild.id == JJTTRIMTRAILING ? Boolean.FALSE
                                : null;
                }

                Value trimChar;

                // if there are 3 children, then we know the trim
                // char is the second node
                if (node.getChildCount() == 3)
                    trimChar = getValue(secondChild(node));
                    // if there are two children, then we need to check to see
                    // if the first child is a leading/trailing/both node,
                    // or the trim character node
                else if (node.getChildCount() == 2
                    && firstTrimChild.id != JJTTRIMLEADING
                    && firstTrimChild.id != JJTTRIMTRAILING
                    && firstTrimChild.id != JJTTRIMBOTH)
                    trimChar = getValue(firstChild(node));
                    // othwerwise, we default to trimming the space character
                else
                    trimChar = factory.newLiteral(" ", Literal.TYPE_STRING);

                return factory.trim(val1, trimChar, trimWhere);

            case JJTCONCAT:
                if (node.children.length < 2)
                	throw parseException(EX_USER, "less-child-count",
                        new Object[]{2, node,
                            Arrays.asList(node.children) }, null);

                val1 = getValue(firstChild(node));
                val2 = getValue(secondChild(node));
                setImplicitType(val1, TYPE_STRING);
                setImplicitType(val2, TYPE_STRING);
                Value concat = factory.concat(val1, val2);
                for (int i = 2; i < node.children.length; i++) {
                	val2 = getValue(node.children[i]);
                    setImplicitType(val2, TYPE_STRING);
                	concat = factory.concat(concat, val2);
                }
                return concat;

            case JJTSUBSTRING:
                // Literals are forced to be Integers because PostgreSQL rejects Longs in SUBSTRING parameters.
                // This however does not help if an expression like 1+1 is passed as parameter.
                val1 = getValue(firstChild(node));
                JPQLNode child2 = secondChild(node);
                if (child2.id == JJTINTEGERLITERAL) {
                    val2 = getIntegerValue(child2);
                } else {
                    val2 = getValue(child2);
                }
                if (node.getChildCount() == 3) {
                    JPQLNode child3 = thirdChild(node);
                    if (child3.id == JJTINTEGERLITERAL) {
                        val3 = getIntegerValue(child3);
                    } else {
                        val3 = getValue(child3);
                    }
                }
                setImplicitType(val1, TYPE_STRING);
                setImplicitType(val2, Integer.TYPE);
                if (node.children.length == 3)
                    setImplicitType(val3, Integer.TYPE);

                return convertSubstringArguments(factory, val1, val2, val3);

            case JJTLOCATE:
                Value locatePath = getValue(firstChild(node));
                Value locateSearch = getValue(secondChild(node));
                Value locateFromIndex = null;
                // Literals are forced to be Integers because PostgreSQL rejects Longs in POSITION parameters.
                // This however does not help if an expression like 1+1 is passed as parameter.
                if (node.getChildCount() > 2) { // optional start index arg
                    JPQLNode child3 = thirdChild(node);
                    if (child3.id == JJTINTEGERLITERAL) {
                        locateFromIndex = getIntegerValue(child3);
                    } else
                        locateFromIndex = getValue(child3);
                }
                setImplicitType(locatePath, TYPE_STRING);
                setImplicitType(locateSearch, TYPE_STRING);

                if (locateFromIndex != null)
                    setImplicitType(locateFromIndex, Integer.TYPE);

                return factory.indexOf(locateSearch,
                    locateFromIndex == null ? locatePath
                        : factory.newArgumentList(locatePath, locateFromIndex));

            case JJTAGGREGATE:
                // simply pass-through while asserting a single child
                return eval(onlyChild(node));

            case JJTCOUNT:
                JPQLNode c = lastChild(node);
                if (c.id == JJTIDENTIFIER)
                    // count(e)
                    return factory.count(getPath(node, false, true));
                return factory.count(getValue(c));

            case JJTMAX:
                return factory.max(getNumberValue(onlyChild(node)));

            case JJTMIN:
                return factory.min(getNumberValue(onlyChild(node)));

            case JJTSUM:
                return factory.sum(getNumberValue(onlyChild(node)));

            case JJTAVERAGE:
                return factory.avg(getNumberValue(onlyChild(node)));

            case JJTDISTINCTPATH:
                return factory.distinct(getValue(onlyChild(node)));

            case JJTEXISTS:
                return factory.isNotEmpty((Value) eval(onlyChild(node)));

            case JJTANY:
                return factory.any((Value) eval(onlyChild(node)));

            case JJTALL:
                return factory.all((Value) eval(onlyChild(node)));

            case JJTSUBSELECT:
                return getSubquery(node);

            case JJTMEMBEROF:
                val1 = getValue(left(node), VAR_PATH);
                val2 = getValue(right(node), VAR_PATH);
                checkEmbeddable(val2);
                setImplicitContainsTypes(val2, val1, CONTAINS_TYPE_ELEMENT);
                return evalNot(not, factory.contains(val2, val1));

            case JJTCURRENTDATE:
                return factory.getCurrentDate(Date.class);

            case JJTCURRENTTIME:
                return factory.getCurrentTime(Time.class);

            case JJTCURRENTTIMESTAMP:
                return factory.getCurrentTimestamp(Timestamp.class);

            case JJTLOCALDATETIME:
                return factory.getCurrentLocalDateTime(LocalDateTime.class);

            case JJTLOCALDATE:
                return factory.getCurrentLocalDateTime(LocalDate.class);

            case JJTLOCALTIME:
                return factory.getCurrentLocalDateTime(LocalTime.class);

            case JJTYEAR:
                return DateTimeExtractField.YEAR;

            case JJTQUARTER:
                return DateTimeExtractField.QUARTER;

            case JJTMONTH:
                return DateTimeExtractField.MONTH;
            
            case JJTWEEK:
                return DateTimeExtractField.WEEK;
            
            case JJTDAY:
                return DateTimeExtractField.DAY;
            
            case JJTHOUR:
                return DateTimeExtractField.HOUR;
            
            case JJTMINUTE:
                return DateTimeExtractField.MINUTE;

            case JJTSECOND:
                return DateTimeExtractField.SECOND;

            case JJTDATE:
                return DateTimeExtractPart.DATE;
            
            case JJTTIME:
                return DateTimeExtractPart.TIME;

            case JJTEXTRACTDATETIMEFIELD:
                return factory.getDateTimeField((DateTimeExtractField) eval(firstChild(node)), getValue(secondChild(node)));
            
            case JJTEXTRACTDATETIMEPART:
                return factory.getDateTimePart((DateTimeExtractPart) eval(firstChild(node)), getValue(secondChild(node)));

            case JJTSELECTEXTENSION:
                assertQueryExtensions("SELECT");
                return eval(onlyChild(node));

            case JJTGROUPBYEXTENSION:
                assertQueryExtensions("GROUP BY");
                return eval(onlyChild(node));

            case JJTORDERBYEXTENSION:
                assertQueryExtensions("ORDER BY");
                return eval(onlyChild(node));

            case JJTDATELITERAL:
                return factory.newLiteral(node.text, Literal.TYPE_DATE);

            case JJTTIMELITERAL:
                return factory.newLiteral(node.text, Literal.TYPE_TIME);

            case JJTTIMESTAMPLITERAL:
                return factory.newLiteral(node.text, Literal.TYPE_TIMESTAMP);

            default:
                throw parseException(EX_FATAL, "bad-tree",
                    new Object[]{ node }, null);
        }
    }