Search in sources :

Example 6 with QueryCompilerSyntaxException

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

the class JavaQueryCompiler method compileFrom.

/**
 * Method to compile the "from" clause (if present for the query language).
 * @return The compiled from expression(s)
 */
protected Expression[] compileFrom() {
    if (from == null) {
        return null;
    }
    Node[] node = parser.parseFrom(from);
    Expression[] expr = new Expression[node.length];
    for (int i = 0; i < node.length; i++) {
        String className = (String) node[i].getNodeValue();
        String classAlias = null;
        Class cls = null;
        if (parentCompiler != null) {
            cls = getClassForSubqueryClassExpression(className);
        } else {
            cls = resolveClass(className);
        }
        List<Node> children = node[i].getChildNodes();
        for (Node child : children) {
            if (// Alias - maybe should assume it is the first child
            child.getNodeType() == NodeType.NAME) {
                classAlias = (String) child.getNodeValue();
            }
        }
        if (i == 0 && classAlias == null) {
            throw new QueryCompilerSyntaxException("FROM clause of query has class " + cls.getName() + " but no alias");
        }
        if (classAlias != null) {
            if (i == 0) {
                // First expression so set up candidateClass/alias
                candidateClass = cls;
                if (parentCompiler != null && parentCompiler.candidateAlias.equals(classAlias)) {
                    // The defined alias is the same as the parent query, so rename
                    candidateAliasOrig = classAlias;
                    candidateAlias = "sub_" + candidateAlias;
                    classAlias = candidateAlias;
                    swapCandidateAliasNodeName(node[i].getChildNode(0));
                } else {
                    candidateAlias = classAlias;
                }
            }
            if (symtbl.getSymbol(classAlias) == null) {
                // Add symbol for this candidate under its alias
                symtbl.addSymbol(new PropertySymbol(classAlias, cls));
            }
        }
        for (Node childNode : children) {
            // Add entries in symbol table for any joined aliases
            if (childNode.getNodeType() == NodeType.OPERATOR) {
                Node joinedNode = childNode.getFirstChild();
                // Extract alias node
                Node aliasNode = childNode.getNextChild();
                // Extract ON node (if present)
                Node onExprNode = null;
                if (childNode.hasNextChild()) {
                    onExprNode = childNode.getNextChild();
                }
                String joinedAlias = (String) joinedNode.getNodeValue();
                boolean rootNode = false;
                Symbol joinedSym = caseSensitiveAliases ? symtbl.getSymbol(joinedAlias) : symtbl.getSymbolIgnoreCase(joinedAlias);
                if (joinedSym == null) {
                    // DN Extension : Check for FROM clause including join to a new root
                    if (aliasNode != null) {
                        joinedAlias = (String) aliasNode.getNodeValue();
                        cls = resolveClass((String) joinedNode.getNodeValue());
                        if (symtbl.getSymbol(joinedAlias) == null) {
                            // Add symbol for this candidate under its alias
                            symtbl.addSymbol(new PropertySymbol(joinedAlias, cls));
                            rootNode = true;
                            NucleusLogger.QUERY.debug("Found suspected ROOT node joined to in FROM clause : attempting to process as alias=" + joinedAlias);
                        }
                        joinedSym = caseSensitiveAliases ? symtbl.getSymbol(joinedAlias) : symtbl.getSymbolIgnoreCase(joinedAlias);
                    }
                    if (joinedSym == null) {
                        throw new QueryCompilerSyntaxException("FROM clause has identifier " + joinedNode.getNodeValue() + " but this is unknown");
                    }
                }
                if (!rootNode) {
                    AbstractClassMetaData joinedCmd = metaDataManager.getMetaDataForClass(joinedSym.getValueType(), clr);
                    Class joinedCls = joinedSym.getValueType();
                    AbstractMemberMetaData joinedMmd = null;
                    while (joinedNode.getFirstChild() != null) {
                        joinedNode = joinedNode.getFirstChild();
                        String joinedMember = (String) joinedNode.getNodeValue();
                        if (joinedNode.getNodeType() == NodeType.CAST) {
                            // JOIN to "TREAT(identifier AS subcls)"
                            String castTypeName = (String) joinedNode.getNodeValue();
                            if (castTypeName.indexOf('.') < 0) {
                                // Fully-qualify with the current class name?
                                castTypeName = ClassUtils.createFullClassName(joinedCmd.getPackageName(), castTypeName);
                            }
                            joinedCls = clr.classForName(castTypeName);
                            // Update cast type now that we have resolved it
                            joinedNode.setNodeValue(castTypeName);
                        } else {
                            // Allow for multi-field joins
                            String[] joinedMembers = joinedMember.contains(".") ? StringUtils.split(joinedMember, ".") : new String[] { joinedMember };
                            for (int k = 0; k < joinedMembers.length; k++) {
                                String memberName = joinedMembers[k];
                                if (joinedCmd == null) {
                                    throw new NucleusUserException("Query has JOIN to " + memberName + " but previous element (" + joinedCls.getName() + ") has no metadata");
                                }
                                if (memberName.endsWith("#KEY")) {
                                    memberName = memberName.substring(0, memberName.length() - 4);
                                } else if (memberName.endsWith("#VALUE")) {
                                    memberName = memberName.substring(0, memberName.length() - 6);
                                }
                                AbstractMemberMetaData mmd = joinedCmd.getMetaDataForMember(memberName);
                                if (mmd == null) {
                                    if (childNode.getNodeValue().equals(JOIN_OUTER) || childNode.getNodeValue().equals(JOIN_OUTER_FETCH)) {
                                        // Polymorphic join, where the field exists in a subclass (doable since we have outer join)
                                        String[] subclasses = metaDataManager.getSubclassesForClass(joinedCmd.getFullClassName(), true);
                                        if (subclasses != null) {
                                            for (int l = 0; l < subclasses.length; l++) {
                                                AbstractClassMetaData subCmd = metaDataManager.getMetaDataForClass(subclasses[l], clr);
                                                if (subCmd != null) {
                                                    mmd = subCmd.getMetaDataForMember(memberName);
                                                    if (mmd != null) {
                                                        NucleusLogger.QUERY.debug("Polymorphic join found at " + memberName + " of " + subCmd.getFullClassName());
                                                        joinedCmd = subCmd;
                                                        break;
                                                    }
                                                }
                                            }
                                        }
                                    }
                                    if (mmd == null) {
                                        throw new QueryCompilerSyntaxException("FROM clause has reference to " + joinedCmd.getFullClassName() + "." + joinedMembers[k] + " but it doesn't exist!");
                                    }
                                }
                                RelationType relationType = mmd.getRelationType(clr);
                                joinedMmd = mmd;
                                if (RelationType.isRelationSingleValued(relationType)) {
                                    joinedCls = mmd.getType();
                                    joinedCmd = metaDataManager.getMetaDataForClass(joinedCls, clr);
                                } else if (RelationType.isRelationMultiValued(relationType)) {
                                    if (mmd.hasCollection()) {
                                        // TODO Don't currently allow interface field navigation
                                        joinedCmd = mmd.getCollection().getElementClassMetaData(clr);
                                        if (joinedCmd != null) {
                                            joinedCls = clr.classForName(joinedCmd.getFullClassName());
                                        } else {
                                            joinedCls = clr.classForName(mmd.getCollection().getElementType());
                                        }
                                    } else if (mmd.hasMap()) {
                                        if (joinedMembers[k].endsWith("#KEY")) {
                                            joinedCmd = mmd.getMap().getKeyClassMetaData(clr);
                                        // TODO Set joinedCls
                                        } else {
                                            joinedCmd = mmd.getMap().getValueClassMetaData(clr);
                                            if (joinedCmd != null) {
                                                // JPA assumption that the value is an entity ... but it may not be!
                                                joinedCls = clr.classForName(joinedCmd.getFullClassName());
                                            } else {
                                                joinedCls = clr.classForName(mmd.getMap().getValueType());
                                            }
                                        }
                                    } else if (mmd.hasArray()) {
                                        // TODO Don't currently allow interface field navigation
                                        joinedCmd = mmd.getArray().getElementClassMetaData(clr);
                                        if (joinedCmd != null) {
                                            joinedCls = clr.classForName(joinedCmd.getFullClassName());
                                        } else {
                                            joinedCls = clr.classForName(mmd.getArray().getElementType());
                                        }
                                    }
                                }
                            }
                        }
                    }
                    if (aliasNode != null && aliasNode.getNodeType() == NodeType.NAME) {
                        // Add JOIN alias to symbol table
                        String alias = (String) aliasNode.getNodeValue();
                        symtbl.addSymbol(new PropertySymbol(alias, joinedCls));
                        if (joinedMmd != null && joinedMmd.hasMap()) {
                            Class keyCls = clr.classForName(joinedMmd.getMap().getKeyType());
                            // Add the KEY so that we can have joins to the key from the value alias
                            symtbl.addSymbol(new PropertySymbol(alias + "#KEY", keyCls));
                            Class valueCls = clr.classForName(joinedMmd.getMap().getValueType());
                            // Add the VALUE so that we can have joins to the value from the key alias
                            symtbl.addSymbol(new PropertySymbol(alias + "#VALUE", valueCls));
                        }
                    }
                }
                if (onExprNode != null) {
                    // ON condition
                    ExpressionCompiler comp = new ExpressionCompiler();
                    comp.setSymbolTable(symtbl);
                    comp.setMethodAliases(queryMgr.getQueryMethodAliasesByPrefix());
                    Expression nextExpr = comp.compileExpression(onExprNode);
                    nextExpr.bind(symtbl);
                }
            }
        }
        boolean classIsExpression = false;
        String[] tokens = StringUtils.split(className, ".");
        if (symtbl.getParentSymbolTable() != null) {
            if (symtbl.getParentSymbolTable().hasSymbol(tokens[0])) {
                classIsExpression = true;
            }
        }
        ExpressionCompiler comp = new ExpressionCompiler();
        comp.setSymbolTable(symtbl);
        comp.setMethodAliases(queryMgr.getQueryMethodAliasesByPrefix());
        expr[i] = comp.compileFromExpression(node[i], classIsExpression);
        if (expr[i] != null) {
            expr[i].bind(symtbl);
        }
    }
    return expr;
}
Also used : NucleusUserException(org.datanucleus.exceptions.NucleusUserException) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) ParameterExpression(org.datanucleus.query.expression.ParameterExpression) Expression(org.datanucleus.query.expression.Expression) VariableExpression(org.datanucleus.query.expression.VariableExpression) PrimaryExpression(org.datanucleus.query.expression.PrimaryExpression) QueryCompilerSyntaxException(org.datanucleus.store.query.QueryCompilerSyntaxException) RelationType(org.datanucleus.metadata.RelationType) ExpressionCompiler(org.datanucleus.query.expression.ExpressionCompiler) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData)

Example 7 with QueryCompilerSyntaxException

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

the class JDOQLParser 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() {
    if (lexer.parseString("DISTINCT ") || lexer.parseString("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;
    }
    // Find any cast first, and remove from top of stack since we put after the cast component
    Node castNode = null;
    if (processCast()) {
        castNode = stack.pop();
    }
    if (lexer.peekString("IF(") || lexer.peekString("if(") || lexer.peekString("IF (") || lexer.peekString("if (")) {
        processIfElseExpression();
        return;
    }
    if (processCreator()) {
        // "new MyClass(...)", allow chain of method invocations
        boolean endOfChain = false;
        while (!endOfChain) {
            if (lexer.parseChar('.')) {
                if (processMethod()) {
                    // Add method invocation as a child node of what it is invoked on
                    Node invokeNode = stack.pop();
                    Node invokedNode = stack.peek();
                    invokedNode.appendChildNode(invokeNode);
                }
            } else {
                endOfChain = true;
            }
        }
        if (castNode != null) {
            // TODO Add cast of creator expression
            throw new NucleusException("Dont currently support compile of cast of creator expression");
        }
        return;
    } else if (processLiteral()) {
        // Literal, allow chain of method invocations
        boolean endOfChain = false;
        while (!endOfChain) {
            if (lexer.parseChar('.')) {
                if (processMethod()) {
                    // Add method invocation as a child node of what it is invoked on
                    Node invokeNode = stack.pop();
                    Node invokedNode = stack.peek();
                    invokedNode.appendChildNode(invokeNode);
                }
            } else {
                endOfChain = true;
            }
        }
        if (castNode != null) {
            throw new NucleusException("Dont currently support compile of cast of literal expression");
        // TODO Add cast of literal
        }
        return;
    } else if (processMethod()) {
        // Static method call
        if (castNode != null) {
            throw new NucleusException("Dont currently support compile of cast of static method call");
        // TODO Add cast of static method call
        }
        return;
    } else if (processArray()) {
        // Array, allow chain of method invocations
        boolean endOfChain = false;
        while (!endOfChain) {
            if (lexer.parseChar('.')) {
                if (processMethod()) {
                    // Add method invocation as a child node of what it is invoked on
                    Node invokeNode = stack.pop();
                    Node invokedNode = stack.peek();
                    invokedNode.appendChildNode(invokeNode);
                }
            } else {
                endOfChain = true;
            }
        }
        if (castNode != null) {
            throw new NucleusException("Dont currently support compile of cast of array expression");
        // TODO Add cast of array
        }
        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 (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;
    }
    while (lexer.parseChar('.')) {
        if (processMethod()) {
        // "a.method(...)"
        } else if (processIdentifier()) {
        // "a.field"
        } else {
            throw new QueryCompilerSyntaxException("Identifier expected", lexer.getIndex(), lexer.getInput());
        }
    }
    // -> node (IDENTIFIER) with child (IDENTIFIER), with child (IDENTIFIER), with child (IDENTIFIER)
    if (castNode != null) {
        // Put the CAST as a child of the Node being cast
        stack.peek().appendChildNode(castNode);
    }
    // ((B)a).c being compiled to "Node[IDENTIFIER, a] -> Node[CAST, B] -> Node[IDENTIFIER, c]"
    while (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) NucleusException(org.datanucleus.exceptions.NucleusException)

Example 8 with QueryCompilerSyntaxException

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

the class ExpressionCompiler method compilePrimaryExpression.

private Expression compilePrimaryExpression(Node node) {
    if (node.getNodeType() == NodeType.PRIMARY) {
        Node currentNode = node.getFirstChild();
        Node invokeNode = node.getNextChild();
        if (invokeNode.getNodeType() != NodeType.INVOKE) {
            // TODO Support more combinations
            throw new QueryCompilerSyntaxException("Dont support compilation of " + node);
        }
        Expression currentExpr = compileExpression(currentNode);
        String methodName = (String) invokeNode.getNodeValue();
        List<Expression> parameterExprs = getExpressionsForPropertiesOfNode(invokeNode);
        Expression invokeExpr = new InvokeExpression(currentExpr, methodName, parameterExprs);
        return invokeExpr;
    } else if (node.getNodeType() == NodeType.IDENTIFIER) {
        Node currentNode = node;
        List tupple = new ArrayList();
        Expression currentExpr = null;
        while (currentNode != null) {
            tupple.add(currentNode.getNodeValue());
            if (currentNode.getNodeType() == NodeType.INVOKE) {
                if (currentExpr == null && tupple.size() > 1) {
                    // Check for starting with parameter/variable
                    String first = (String) tupple.get(0);
                    Symbol firstSym = symtbl.getSymbol(first);
                    if (firstSym != null) {
                        if (firstSym.getType() == Symbol.PARAMETER) {
                            currentExpr = new ParameterExpression(first, -1);
                            if (tupple.size() > 2) {
                                currentExpr = new PrimaryExpression(currentExpr, tupple.subList(1, tupple.size() - 1));
                            }
                        } else if (firstSym.getType() == Symbol.VARIABLE) {
                            currentExpr = new VariableExpression(first);
                            if (tupple.size() > 2) {
                                currentExpr = new PrimaryExpression(currentExpr, tupple.subList(1, tupple.size() - 1));
                            }
                        }
                    }
                    if (currentExpr == null) {
                        currentExpr = new PrimaryExpression(tupple.subList(0, tupple.size() - 1));
                    }
                } else if (currentExpr != null && tupple.size() > 1) {
                    currentExpr = new PrimaryExpression(currentExpr, tupple.subList(0, tupple.size() - 1));
                }
                String methodName = (String) tupple.get(tupple.size() - 1);
                if (currentExpr instanceof PrimaryExpression) {
                    // Check if this is a defined method prefix, and if so use the alias
                    String id = ((PrimaryExpression) currentExpr).getId();
                    if (aliasByPrefix != null && aliasByPrefix.containsKey(id)) {
                        String alias = aliasByPrefix.get(id);
                        methodName = alias + "." + methodName;
                        currentExpr = null;
                    }
                }
                List<Expression> parameterExprs = getExpressionsForPropertiesOfNode(currentNode);
                currentExpr = new InvokeExpression(currentExpr, methodName, parameterExprs);
                currentNode = currentNode.getFirstChild();
                tupple = new ArrayList();
            } else if (currentNode.getNodeType() == NodeType.CAST) {
                if (currentExpr == null && tupple.size() > 1) {
                    // Start from PrimaryExpression and invoke on that
                    currentExpr = new PrimaryExpression(tupple.subList(0, tupple.size() - 1));
                    PrimaryExpression primExpr = (PrimaryExpression) currentExpr;
                    if (primExpr.tuples.size() == 1) {
                        Symbol sym = symtbl.getSymbol(primExpr.getId());
                        if (sym != null) {
                            if (sym.getType() == Symbol.PARAMETER) {
                                // Parameter symbol registered for this identifier so use ParameterExpression
                                currentExpr = new ParameterExpression(primExpr.getId(), -1);
                            } else if (sym.getType() == Symbol.VARIABLE) {
                                // Variable symbol registered for this identifier so use VariableExpression
                                currentExpr = new VariableExpression(primExpr.getId());
                            }
                        }
                    }
                }
                String className = (String) tupple.get(tupple.size() - 1);
                currentExpr = new DyadicExpression(currentExpr, Expression.OP_CAST, new Literal(className));
                currentNode = currentNode.getFirstChild();
                tupple = new ArrayList();
            } else {
                // Part of identifier chain
                currentNode = currentNode.getFirstChild();
            }
        }
        if (currentExpr != null && !tupple.isEmpty()) {
            // We have a trailing identifier expression e.g "((B)a).c" where we have a CastExpression and trailing "c"
            currentExpr = new PrimaryExpression(currentExpr, tupple);
        }
        if (currentExpr == null) {
            // Find type of first of tupples
            String first = (String) tupple.get(0);
            Symbol firstSym = symtbl.getSymbol(first);
            if (firstSym != null) {
                // TODO If the user has a field in the candidate the same name as a parameter and they just put the name (rather than "this.{name}") then it interprets as parameter
                if (firstSym.getType() == Symbol.PARAMETER) {
                    ParameterExpression paramExpr = new ParameterExpression(first, -1);
                    if (tupple.size() > 1) {
                        currentExpr = new PrimaryExpression(paramExpr, tupple.subList(1, tupple.size()));
                    } else {
                        currentExpr = paramExpr;
                    }
                } else if (firstSym.getType() == Symbol.VARIABLE) {
                    VariableExpression varExpr = new VariableExpression(first);
                    if (tupple.size() > 1) {
                        currentExpr = new PrimaryExpression(varExpr, tupple.subList(1, tupple.size()));
                    } else {
                        currentExpr = varExpr;
                    }
                } else {
                    currentExpr = new PrimaryExpression(tupple);
                }
            } else {
                currentExpr = new PrimaryExpression(tupple);
            }
        }
        return currentExpr;
    } else if (node.getNodeType() == NodeType.PARAMETER) {
        // "{paramExpr}", "{paramExpr}.invoke(...)", "{paramExpr}.invoke(...).invoke(...)"
        Object val = node.getNodeValue();
        Expression currentExpr = null;
        if (val instanceof Integer) {
            // Positional parameter TODO Store as Integer to avoid confusion
            currentExpr = new ParameterExpression("" + node.getNodeValue(), ((ParameterNode) node).getPosition());
        } else {
            // Named parameter
            currentExpr = new ParameterExpression((String) node.getNodeValue(), ((ParameterNode) node).getPosition());
        }
        Node childNode = node.getFirstChild();
        while (childNode != null) {
            if (childNode.getNodeType() == NodeType.INVOKE) {
                String methodName = (String) childNode.getNodeValue();
                List<Expression> parameterExprs = getExpressionsForPropertiesOfNode(childNode);
                currentExpr = new InvokeExpression(currentExpr, methodName, parameterExprs);
            } else if (childNode.getNodeType() == NodeType.IDENTIFIER) {
                String identifier = childNode.getNodeId();
                List tuples = new ArrayList();
                tuples.add(identifier);
                boolean moreIdentifierNodes = true;
                while (moreIdentifierNodes) {
                    Node currentNode = childNode;
                    childNode = childNode.getFirstChild();
                    if (childNode == null || childNode.getNodeType() != NodeType.IDENTIFIER) {
                        moreIdentifierNodes = false;
                        childNode = currentNode;
                    } else {
                        // Add as a component of the primary
                        tuples.add(childNode.getNodeId());
                    }
                }
                currentExpr = new PrimaryExpression(currentExpr, tuples);
            } else {
                throw new QueryCompilerSyntaxException("Dont support compilation of " + node);
            }
            childNode = childNode.getFirstChild();
        }
        return currentExpr;
    } else if (node.getNodeType() == NodeType.INVOKE) {
        Node currentNode = node;
        List tupple = new ArrayList();
        Expression currentExpr = null;
        while (currentNode != null) {
            tupple.add(currentNode.getNodeValue());
            if (currentNode.getNodeType() == NodeType.INVOKE) {
                String methodName = (String) tupple.get(tupple.size() - 1);
                List<Expression> parameterExprs = getExpressionsForPropertiesOfNode(currentNode);
                currentExpr = new InvokeExpression(currentExpr, methodName, parameterExprs);
                currentNode = currentNode.getFirstChild();
                if (currentNode != null) {
                    // Continue on along the chain
                    tupple = new ArrayList();
                    // Start from this expression
                    tupple.add(currentExpr);
                }
            } else {
                // TODO What node type is this that comes after an INVOKE?
                currentNode = currentNode.getFirstChild();
            }
        }
        return currentExpr;
    } else if (node.getNodeType() == NodeType.CREATOR) {
        Node currentNode = node.getFirstChild();
        List tupple = new ArrayList();
        boolean method = false;
        while (currentNode != null) {
            tupple.add(currentNode.getNodeValue());
            if (currentNode.getNodeType() == NodeType.INVOKE) {
                method = true;
                break;
            }
            currentNode = currentNode.getFirstChild();
        }
        List<Expression> parameterExprs = null;
        if (method) {
            parameterExprs = getExpressionsForPropertiesOfNode(currentNode);
        } else {
            parameterExprs = new ArrayList();
        }
        return new CreatorExpression(tupple, parameterExprs);
    } else if (node.getNodeType() == NodeType.LITERAL) {
        Node currentNode = node;
        List tupple = new ArrayList();
        Expression currentExpr = null;
        while (currentNode != null) {
            tupple.add(currentNode.getNodeValue());
            if (currentNode.getNodeType() == NodeType.INVOKE) {
                if (currentExpr == null && tupple.size() > 1) {
                    // Start from Literal and invoke on that
                    currentExpr = new Literal(node.getNodeValue());
                }
                String methodName = (String) tupple.get(tupple.size() - 1);
                List<Expression> parameterExprs = getExpressionsForPropertiesOfNode(currentNode);
                currentExpr = new InvokeExpression(currentExpr, methodName, parameterExprs);
                currentNode = currentNode.getFirstChild();
                tupple = new ArrayList();
            } else {
                currentNode = currentNode.getFirstChild();
            }
        }
        if (currentExpr == null) {
            currentExpr = new Literal(node.getNodeValue());
        }
        return currentExpr;
    } else if (node.getNodeType() == NodeType.ARRAY) {
        Node currentNode = node;
        List<Node> arrayElements = (List<Node>) node.getNodeValue();
        // Check if this is an array literal
        boolean literal = true;
        Class type = null;
        Iterator<Node> iter = arrayElements.iterator();
        while (iter.hasNext()) {
            Node element = iter.next();
            if (type == null) {
                type = element.getNodeValue().getClass();
            }
            if (element.getNodeType() == NodeType.IDENTIFIER) {
                literal = false;
                break;
            }
        }
        Expression currentExpr = null;
        if (literal) {
            Object array = Array.newInstance(type, arrayElements.size());
            iter = arrayElements.iterator();
            int index = 0;
            while (iter.hasNext()) {
                Node element = iter.next();
                Array.set(array, index++, element.getNodeValue());
            }
            currentExpr = new Literal(array);
        } else {
            Expression[] arrayElementExprs = new Expression[arrayElements.size()];
            for (int i = 0; i < arrayElementExprs.length; i++) {
                arrayElementExprs[i] = compilePrimaryExpression(arrayElements.get(i));
            }
            currentExpr = new ArrayExpression(arrayElementExprs);
        }
        currentNode = currentNode.getFirstChild();
        List tupple = new ArrayList();
        while (currentNode != null) {
            tupple.add(currentNode.getNodeValue());
            if (currentNode.getNodeType() == NodeType.INVOKE) {
                if (tupple.size() > 1) {
                    // Start from Literal and invoke on that
                    currentExpr = new Literal(node.getNodeValue());
                }
                String methodName = (String) tupple.get(tupple.size() - 1);
                List<Expression> parameterExprs = getExpressionsForPropertiesOfNode(currentNode);
                currentExpr = new InvokeExpression(currentExpr, methodName, parameterExprs);
                currentNode = currentNode.getFirstChild();
                tupple = new ArrayList();
            } else {
                currentNode = currentNode.getFirstChild();
            }
        }
        return currentExpr;
    } else if (node.getNodeType() == NodeType.SUBQUERY) {
        List children = node.getChildNodes();
        if (children.size() != 1) {
            throw new QueryCompilerSyntaxException("Invalid number of children for SUBQUERY node : " + node);
        }
        Node varNode = (Node) children.get(0);
        VariableExpression subqueryExpr = new VariableExpression(varNode.getNodeId());
        Expression currentExpr = new SubqueryExpression((String) node.getNodeValue(), subqueryExpr);
        return currentExpr;
    } else if (node.getNodeType() == NodeType.CASE) {
        // Node with children in the order "when", "action"[, "when", "action"], "else"
        List<Node> children = node.getChildNodes();
        if ((children.size() % 2) == 0) {
            throw new QueryCompilerSyntaxException("Invalid number of children for CASE node (should be odd). Have you omitted the ELSE clause? : " + node);
        }
        Node elseNode = children.get(children.size() - 1);
        Expression elseExpr = compileExpression(elseNode);
        CaseExpression caseExpr = new CaseExpression();
        Iterator<Node> childIter = children.iterator();
        while (childIter.hasNext()) {
            Node whenNode = childIter.next();
            if (childIter.hasNext()) {
                Node actionNode = childIter.next();
                Expression whenExpr = compileExpression(whenNode);
                Expression actionExpr = compileExpression(actionNode);
                caseExpr.addCondition(whenExpr, actionExpr);
            }
        }
        caseExpr.setElseExpression(elseExpr);
        return caseExpr;
    } else if (node.getNodeType() == NodeType.TYPE) {
        List<Node> children = node.getChildNodes();
        Expression containedExpr = compileExpression(children.get(0));
        TypeExpression typeExpr = new TypeExpression(containedExpr);
        return typeExpr;
    } else {
        NucleusLogger.QUERY.warn("ExpressionCompiler.compilePrimaryExpression node=" + node + " ignored by ExpressionCompiler since not of a supported type");
    }
    return null;
}
Also used : Symbol(org.datanucleus.query.compiler.Symbol) Node(org.datanucleus.query.compiler.Node) ParameterNode(org.datanucleus.query.compiler.ParameterNode) ArrayList(java.util.ArrayList) ParameterNode(org.datanucleus.query.compiler.ParameterNode) QueryCompilerSyntaxException(org.datanucleus.store.query.QueryCompilerSyntaxException) ArrayList(java.util.ArrayList) List(java.util.List)

Example 9 with QueryCompilerSyntaxException

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

the class QueryToSQLMapper method compile.

/**
 * Method to update the supplied SQLStatement with the components of the specified query.
 * During the compilation process this updates the SQLStatement "compileComponent" to the
 * component of the query being compiled.
 */
public void compile() {
    if (NucleusLogger.QUERY.isDebugEnabled() && parentMapper == null) {
        // Give debug output of compilation
        StringBuilder str = new StringBuilder("JoinType : navigation(default=");
        str.append(defaultJoinType != null ? defaultJoinType : "(using nullability)");
        str.append(", filter=");
        str.append(defaultJoinTypeFilter != null ? defaultJoinTypeFilter : "(using nullability)");
        str.append(")");
        if (extensionsByName != null) {
            Iterator<Map.Entry<String, Object>> extensionsIter = extensionsByName.entrySet().iterator();
            while (extensionsIter.hasNext()) {
                Map.Entry<String, Object> entry = extensionsIter.next();
                String key = entry.getKey();
                if (key.startsWith("datanucleus.query.jdoql.") && key.endsWith(".join")) {
                    // Alias join definition
                    String alias = key.substring("datanucleus.query.jdoql.".length(), key.lastIndexOf(".join"));
                    str.append(", ").append(alias).append("=").append(entry.getValue());
                }
            }
        }
        NucleusLogger.QUERY.debug("Compile of " + compilation.getQueryLanguage() + " into SQL - " + str);
    }
    compileFrom();
    compileFilter();
    if (stmt instanceof UpdateStatement) {
        compileUpdate((UpdateStatement) stmt);
    } else if (stmt instanceof SelectStatement) {
        SelectStatement selectStmt = (SelectStatement) stmt;
        // the datastore doesn't allow select of some field types when used with DISTINCT
        if (compilation.getResultDistinct()) {
            selectStmt.setDistinct(true);
        } else if (!options.contains(OPTION_EXPLICIT_JOINS) && compilation.getExprResult() == null) {
            // Joins are made implicitly and no result so set distinct based on whether joining to other table groups
            if (selectStmt.getNumberOfTableGroups() > 1) {
                // Queries against an extent always consider only distinct candidate instances, regardless of whether distinct is specified (JDO spec)
                if (!options.contains(OPTION_NON_DISTINCT_IMPLICIT_JOINS)) {
                    // If user can guarantee distinct w/ query no reason to take performance hit of distinct clause
                    selectStmt.setDistinct(true);
                }
            }
        }
        compileResult(selectStmt);
        compileGrouping(selectStmt);
        compileHaving(selectStmt);
        compileOrdering(selectStmt);
    }
    // Check for variables that haven't been bound to the query (declared but not used)
    for (String symbol : compilation.getSymbolTable().getSymbolNames()) {
        Symbol sym = compilation.getSymbolTable().getSymbol(symbol);
        if (sym.getType() == Symbol.VARIABLE) {
            if (compilation.getCompilationForSubquery(sym.getQualifiedName()) == null && !hasSQLTableMappingForAlias(sym.getQualifiedName())) {
                // Variable not a subquery, nor had its table allocated
                throw new QueryCompilerSyntaxException("Query has variable \"" + sym.getQualifiedName() + "\" which is not bound to the query");
            }
        }
    }
}
Also used : SelectStatement(org.datanucleus.store.rdbms.sql.SelectStatement) UpdateStatement(org.datanucleus.store.rdbms.sql.UpdateStatement) Symbol(org.datanucleus.query.compiler.Symbol) QueryCompilerSyntaxException(org.datanucleus.store.query.QueryCompilerSyntaxException) Map(java.util.Map) HashMap(java.util.HashMap)

Example 10 with QueryCompilerSyntaxException

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

the class JDOQLParser method parseVariables.

/* (non-Javadoc)
     * @see org.datanucleus.query.compiler.Parser#parseVariables(java.lang.String)
     */
public Node[][] parseVariables(String expression) {
    lexer = new Lexer(expression, paramPrefixes, true);
    List nodes = new ArrayList();
    do {
        if (StringUtils.isWhitespace(lexer.remaining())) {
            break;
        }
        processPrimary();
        if (stack.isEmpty()) {
            throw new QueryCompilerSyntaxException("Parsing variable list and expected variable type", lexer.getIndex(), lexer.getInput());
        }
        if (!processIdentifier()) {
            throw new QueryCompilerSyntaxException("Parsing variable list and expected variable name", lexer.getIndex(), lexer.getInput());
        }
        Node nodeVariable = stack.pop();
        String varName = (String) nodeVariable.getNodeValue();
        if (!JDOQLQueryHelper.isValidJavaIdentifierForJDOQL(varName)) {
            throw new NucleusUserException(Localiser.msg("021105", varName));
        }
        Node nodeType = stack.pop();
        nodes.add(new Node[] { nodeType, nodeVariable });
    } while (lexer.parseString(";"));
    return (Node[][]) nodes.toArray(new Node[nodes.size()][2]);
}
Also used : NucleusUserException(org.datanucleus.exceptions.NucleusUserException) QueryCompilerSyntaxException(org.datanucleus.store.query.QueryCompilerSyntaxException) ArrayList(java.util.ArrayList) ArrayList(java.util.ArrayList) List(java.util.List)

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