Search in sources :

Example 16 with QueryCompilerSyntaxException

use of org.datanucleus.store.query.QueryCompilerSyntaxException in project datanucleus-core by datanucleus.

the class JPQLParser method parseVariables.

/* (non-Javadoc)
     * @see org.datanucleus.query.compiler.Parser#parseVariables(java.lang.String)
     */
public Node[][] parseVariables(String expression) {
    lexer = new Lexer(expression, paramPrefixes, false);
    List nodes = new ArrayList();
    do {
        processPrimary();
        if (stack.isEmpty()) {
            throw new QueryCompilerSyntaxException("expected identifier", lexer.getIndex(), lexer.getInput());
        }
        if (!processIdentifier()) {
            throw new QueryCompilerSyntaxException("expected identifier", lexer.getIndex(), lexer.getInput());
        }
        Node nodeVariable = stack.pop();
        Node nodeType = stack.pop();
        nodes.add(new Node[] { nodeType, nodeVariable });
    } while (lexer.parseString(";"));
    return (Node[][]) nodes.toArray(new Node[nodes.size()][2]);
}
Also used : QueryCompilerSyntaxException(org.datanucleus.store.query.QueryCompilerSyntaxException) ArrayList(java.util.ArrayList) List(java.util.List) ArrayList(java.util.ArrayList)

Example 17 with QueryCompilerSyntaxException

use of org.datanucleus.store.query.QueryCompilerSyntaxException in project datanucleus-core by datanucleus.

the class JPQLParser method processCreator.

/**
 * Method to parse "new a.b.c(param1[,param2], ...)" and create a Node of type CREATOR.
 * The Node at the top of the stack after this call will have any arguments defined in its "properties".
 * @return whether method syntax was found.
 */
private boolean processCreator() {
    if (lexer.parseStringIgnoreCase("NEW ")) {
        // "new MyClass(arg1, arg2)"
        int size = stack.size();
        if (!processMethod()) {
            if (!processIdentifier()) {
                throw new QueryCompilerSyntaxException("Identifier expected", lexer.getIndex(), lexer.getInput());
            }
            // run function on literals or identifiers e.g. "primary.runMethod(arg)"
            while (lexer.parseChar('.')) {
                if (processMethod()) {
                // "a.method(...)"
                } else if (processIdentifier()) {
                // "a.field"
                } else {
                    throw new QueryCompilerSyntaxException("Identifier expected", lexer.getIndex(), lexer.getInput());
                }
            }
        }
        while (stack.size() - 1 > size) {
            Node top = stack.pop();
            Node peek = stack.peek();
            peek.insertChildNode(top);
        }
        Node node = stack.pop();
        Node newNode = new Node(NodeType.CREATOR);
        newNode.insertChildNode(node);
        stack.push(newNode);
        return true;
    }
    return false;
}
Also used : QueryCompilerSyntaxException(org.datanucleus.store.query.QueryCompilerSyntaxException)

Example 18 with QueryCompilerSyntaxException

use of org.datanucleus.store.query.QueryCompilerSyntaxException in project datanucleus-core by datanucleus.

the class JPQLParser method processInExpression.

/**
 * Convenience handler to parse an IN expression.
 * Expression is typically of the form "{expression} IN (expr1 [,expr2 [,expr3]] | subquery)".
 * Can generate a node tree like
 * <pre>({expression} == expr1) || ({expression} == expr2) || ({expression} == expr3)</pre>
 * depending on the precise situation.
 * @param not Whether this is an expression "NOT IN"
 */
private void processInExpression(boolean not) {
    // The left hand side expression
    Node inputNode = stack.pop();
    boolean usesType = false;
    if (inputNode.getNodeType() == NodeType.TYPE) {
        usesType = true;
    }
    if (!lexer.parseChar('(')) {
        // "{expr} IN value" : Subquery/Parameter
        processPrimary();
        Node subqueryNode = stack.pop();
        Node inNode;
        if (usesType) {
            // "TYPE(p) IN :collectionClasses". Convert TYPE into "(p instanceof :collectionClasses)"
            inNode = new Node(NodeType.OPERATOR, "instanceof");
            inNode.appendChildNode(inputNode.getFirstChild());
            inNode.appendChildNode(subqueryNode);
            if (not) {
                Node notNode = new Node(NodeType.OPERATOR, "!");
                notNode.appendChildNode(inNode);
                inNode = notNode;
            }
        } else {
            inNode = new Node(NodeType.OPERATOR, not ? "NOT IN" : "IN");
            inNode.appendChildNode(inputNode);
            inNode.appendChildNode(subqueryNode);
        }
        stack.push(inNode);
        return;
    }
    List<Node> valueNodes = new ArrayList();
    do {
        // "IN ((literal|parameter) [, (literal|parameter)])"
        processPrimary();
        if (stack.peek() == null) {
            throw new QueryCompilerSyntaxException("Expected literal|parameter but got " + lexer.remaining(), lexer.getIndex(), lexer.getInput());
        }
        // Generate node for comparison with this value
        Node valueNode = stack.pop();
        valueNodes.add(valueNode);
        lexer.skipWS();
    } while (lexer.parseChar(','));
    if (!lexer.parseChar(')')) {
        throw new QueryCompilerSyntaxException("Expected: ')' but got " + lexer.remaining(), lexer.getIndex(), lexer.getInput());
    } else if (valueNodes.isEmpty()) {
        throw new QueryCompilerSyntaxException("IN expression had zero arguments!");
    }
    if (usesType) {
        // "TYPE(a) in (b1,b2,b3)". Convert TYPE into "a instanceof (b1,b2,b3)"
        Node inNode = new Node(NodeType.OPERATOR, "instanceof");
        inNode.appendChildNode(inputNode.getFirstChild());
        for (Node valueNode : valueNodes) {
            inNode.appendChildNode(valueNode);
        }
        if (not) {
            Node notNode = new Node(NodeType.OPERATOR, "!");
            notNode.appendChildNode(inNode);
            inNode = notNode;
        }
        stack.push(inNode);
        return;
    }
    // Create the returned Node representing this IN expression
    Node inNode = null;
    Node firstValueNode = valueNodes.get(0);
    if (valueNodes.size() == 1 && firstValueNode.getNodeType() != NodeType.LITERAL) {
        // Compile as (input IN val)
        // Note that we exclude LITERAL single args from here since they can be represented using ==, and also RDBMS needs that currently TODO Fix RDBMS query processor
        inNode = new Node(NodeType.OPERATOR, not ? "NOT IN" : "IN");
        inNode.appendChildNode(inputNode);
        inNode.appendChildNode(valueNodes.get(0));
    } else {
        // TODO Would be nice to do as (input IN (val1, val2, ...)) but that implies changes in datastore query processors
        for (Node valueNode : valueNodes) {
            Node compareNode = new Node(NodeType.OPERATOR, not ? "!=" : "==");
            compareNode.appendChildNode(inputNode);
            compareNode.appendChildNode(valueNode);
            if (inNode == null) {
                inNode = compareNode;
            } else {
                Node newInNode = new Node(NodeType.OPERATOR, not ? "&&" : "||");
                newInNode.appendChildNode(inNode);
                newInNode.appendChildNode(compareNode);
                inNode = newInNode;
            }
        }
    }
    stack.push(inNode);
}
Also used : QueryCompilerSyntaxException(org.datanucleus.store.query.QueryCompilerSyntaxException) ArrayList(java.util.ArrayList)

Example 19 with QueryCompilerSyntaxException

use of org.datanucleus.store.query.QueryCompilerSyntaxException in project datanucleus-core by datanucleus.

the class JPQLParser method processPrimary.

/**
 * Parses the primary. First look for a literal (e.g. "text"), then an identifier(e.g. variable).
 * In the next step, call a function, if executing a function, on the literal or the identifier found.
 */
protected void processPrimary() {
    String subqueryKeyword = null;
    Node subqueryNode = null;
    // Process all syntax that cannot chain off subfield references from
    if (lexer.parseStringIgnoreCase("SOME ")) {
        subqueryKeyword = "SOME";
        // subquery variable
        processExpression();
        subqueryNode = stack.pop();
    } else if (lexer.parseStringIgnoreCase("ALL ")) {
        subqueryKeyword = "ALL";
        // subquery variable
        processExpression();
        subqueryNode = stack.pop();
    } else if (lexer.parseStringIgnoreCase("ANY ")) {
        subqueryKeyword = "ANY";
        // subquery variable
        processExpression();
        subqueryNode = stack.pop();
    } else if (lexer.parseStringIgnoreCase("EXISTS ")) {
        subqueryKeyword = "EXISTS";
        // subquery variable
        processExpression();
        subqueryNode = stack.pop();
    }
    if (subqueryKeyword != null && subqueryNode != null) {
        Node subNode = new Node(NodeType.SUBQUERY, subqueryKeyword);
        subNode.appendChildNode(subqueryNode);
        stack.push(subNode);
        return;
    }
    if (!strict) {
        // Series of user-convenience methods that are not part of strict JPQL
        if (lexer.parseStringIgnoreCase("COUNT(*)")) {
            // Convert to a method call of COUNTSTAR
            Node node = new Node(NodeType.INVOKE, "COUNTSTAR");
            stack.push(node);
            return;
        } else if (// Some people put "()" in JPQL
        lexer.parseStringIgnoreCase("CURRENT_DATE()")) {
            // Convert to a method call of CURRENT_DATE
            Node node = new Node(NodeType.INVOKE, "CURRENT_DATE");
            stack.push(node);
            return;
        } else if (// Some people put "()" in JPQL
        lexer.parseStringIgnoreCase("CURRENT_TIMESTAMP()")) {
            // Convert to a method call
            Node node = new Node(NodeType.INVOKE, "CURRENT_TIMESTAMP");
            stack.push(node);
            return;
        } else if (// Some people put "()" in JPQL
        lexer.parseStringIgnoreCase("CURRENT_TIME()")) {
            // Convert to a method call
            Node node = new Node(NodeType.INVOKE, "CURRENT_TIME");
            stack.push(node);
            return;
        }
    }
    if (lexer.parseStringIgnoreCase("CURRENT_DATE")) {
        // Convert to a method call
        Node node = new Node(NodeType.INVOKE, "CURRENT_DATE");
        stack.push(node);
        return;
    } else if (lexer.parseStringIgnoreCase("CURRENT_TIMESTAMP")) {
        // Convert to a method call
        Node node = new Node(NodeType.INVOKE, "CURRENT_TIMESTAMP");
        stack.push(node);
        return;
    } else if (lexer.parseStringIgnoreCase("CURRENT_TIME")) {
        // Convert to a method call
        Node node = new Node(NodeType.INVOKE, "CURRENT_TIME");
        stack.push(node);
        return;
    } else if (lexer.parseStringIgnoreCase("CASE ")) {
        processCaseExpression();
        return;
    } else if (lexer.parseStringIgnoreCase("DISTINCT ")) {
        // Aggregates can have "count(DISTINCT field1)"
        Node distinctNode = new Node(NodeType.OPERATOR, "DISTINCT");
        processExpression();
        Node identifierNode = stack.pop();
        distinctNode.appendChildNode(identifierNode);
        stack.push(distinctNode);
        return;
    } else if (lexer.peekStringIgnoreCase("TREAT(")) {
    // So we don't get interpreted as a method. Processed later
    } else if (// TODO Can we chain fields/methods off a KEY ?
    processKey()) {
        return;
    } else if (// TODO Can we chain fields/methods off a VALUE ?
    processValue()) {
        return;
    } else if (processEntry()) {
        return;
    } else if (processCreator() || processLiteral() || processMethod()) {
        return;
    }
    int sizeBeforeBraceProcessing = stack.size();
    boolean braceProcessing = false;
    if (lexer.parseChar('(')) {
        // "({expr1})"
        processExpression();
        if (!lexer.parseChar(')')) {
            throw new QueryCompilerSyntaxException("expected ')'", lexer.getIndex(), lexer.getInput());
        }
        if (!lexer.parseChar('.')) {
            // TODO If we have a cast, then apply to the current node (with the brackets)
            return;
        }
        // Has follow on expression "({expr1}).{expr2}" so continue
        braceProcessing = true;
    }
    // We will have an identifier (variable, parameter, or field of candidate class)
    if (processTreat()) {
    } else if (processMethod()) {
    } else if (processIdentifier()) {
    } else {
        throw new QueryCompilerSyntaxException("Method/Identifier expected", lexer.getIndex(), lexer.getInput());
    }
    // Save the stack size just before this component for use later in squashing all nodes
    // down to a single Node in the stack with all others chained off from it
    int size = stack.size();
    if (braceProcessing) {
        size = sizeBeforeBraceProcessing + 1;
    }
    // -> node (IDENTIFIER) with child (IDENTIFIER), with child (IDENTIFIER), with child (IDENTIFIER)
    while (lexer.parseChar('.')) {
        if (processMethod()) {
        // "a.method()" Note this is invalid in JPQL, where they have FUNCTIONs, but we allow it
        } else if (processIdentifier()) {
        // "a.field"
        } else {
            throw new QueryCompilerSyntaxException("Identifier expected", lexer.getIndex(), lexer.getInput());
        }
    }
    // +--- Node[IDENTIFIER, c]
    while (// Nodes added
    stack.size() > size) {
        Node top = stack.pop();
        Node peek = stack.peek();
        Node lastDescendant = getLastDescendantNodeForNode(peek);
        if (lastDescendant != null) {
            lastDescendant.appendChildNode(top);
        } else {
            // The peek node has multiple children, so cannot just put the top Node after the last child
            Node primNode = new Node(NodeType.PRIMARY);
            primNode.appendChildNode(peek);
            primNode.appendChildNode(top);
            // Remove "peek" node and replace with primNode
            stack.pop();
            stack.push(primNode);
        }
    }
}
Also used : QueryCompilerSyntaxException(org.datanucleus.store.query.QueryCompilerSyntaxException)

Example 20 with QueryCompilerSyntaxException

use of org.datanucleus.store.query.QueryCompilerSyntaxException in project tests by datanucleus.

the class JPQLCompilerTest method testFromInExpressionErroneousPrimary.

/**
 * Tests for from clause with an "IN(...) alias" expression with an invalid primary.
 */
public void testFromInExpressionErroneousPrimary() {
    JavaQueryCompiler compiler = null;
    try {
        compiler = new JPQLCompiler(nucCtx, nucCtx.getClassLoaderResolver(null), Department.class.getName() + " d," + "IN(d.products) n", null, null, null, null, null, null, null, null, null, null);
        compiler.compile(new HashMap(), null);
        fail("Was expecting QueryCompilerSyntaxException but compilation worked");
    } catch (QueryCompilerSyntaxException qcse) {
    // Expected
    }
}
Also used : JavaQueryCompiler(org.datanucleus.query.compiler.JavaQueryCompiler) HashMap(java.util.HashMap) QueryCompilerSyntaxException(org.datanucleus.store.query.QueryCompilerSyntaxException) JPQLCompiler(org.datanucleus.query.compiler.JPQLCompiler)

Aggregations

QueryCompilerSyntaxException (org.datanucleus.store.query.QueryCompilerSyntaxException)20 ArrayList (java.util.ArrayList)7 List (java.util.List)5 HashMap (java.util.HashMap)3 NucleusUserException (org.datanucleus.exceptions.NucleusUserException)3 SQLExpression (org.datanucleus.store.rdbms.sql.expression.SQLExpression)3 Map (java.util.Map)2 AbstractClassMetaData (org.datanucleus.metadata.AbstractClassMetaData)2 Symbol (org.datanucleus.query.compiler.Symbol)2 Expression (org.datanucleus.query.expression.Expression)2 ParameterExpression (org.datanucleus.query.expression.ParameterExpression)2 PrimaryExpression (org.datanucleus.query.expression.PrimaryExpression)2 VariableExpression (org.datanucleus.query.expression.VariableExpression)2 SelectStatement (org.datanucleus.store.rdbms.sql.SelectStatement)2 BooleanExpression (org.datanucleus.store.rdbms.sql.expression.BooleanExpression)2 BigDecimal (java.math.BigDecimal)1 BigInteger (java.math.BigInteger)1 StringTokenizer (java.util.StringTokenizer)1 FetchPlanForClass (org.datanucleus.FetchPlanForClass)1 NucleusException (org.datanucleus.exceptions.NucleusException)1