Search in sources :

Example 36 with PrimaryExpression

use of org.datanucleus.query.expression.PrimaryExpression in project tests by datanucleus.

the class JDOQLCompilerTest method testOrderNulls.

/**
 * Test for order clause.
 */
public void testOrderNulls() {
    // Test use of implicit variable in filter
    JavaQueryCompiler compiler = null;
    QueryCompilation compilation = null;
    try {
        compiler = new JDOQLCompiler(nucCtx, nucCtx.getClassLoaderResolver(null), null, Product.class, null, null, null, "name ASC", null, null, null, null, null, null);
        compilation = compiler.compile(null, null);
    } catch (NucleusUserException ne) {
        NucleusLogger.QUERY.error("Exception thrown during compilation", ne);
        fail("compilation of filter with valid field threw exception : " + ne.getMessage());
    }
    Expression[] orderExprs1 = compilation.getExprOrdering();
    assertEquals(1, orderExprs1.length);
    assertTrue(orderExprs1[0] instanceof OrderExpression);
    OrderExpression orderExpr1 = (OrderExpression) orderExprs1[0];
    assertEquals("name", ((PrimaryExpression) orderExpr1.getLeft()).getId());
    assertEquals("ascending", orderExpr1.getSortOrder());
    assertNull(orderExpr1.getNullOrder());
    // Test use of NULLS
    try {
        compiler = new JDOQLCompiler(nucCtx, nucCtx.getClassLoaderResolver(null), null, Product.class, null, null, null, "name ASC NULLS FIRST", null, null, null, null, null, null);
        compilation = compiler.compile(null, null);
    } catch (NucleusUserException ne) {
        NucleusLogger.QUERY.error("Exception thrown during compilation", ne);
        fail("compilation of filter with valid field threw exception : " + ne.getMessage());
    }
    Expression[] orderExprs2 = compilation.getExprOrdering();
    assertEquals(1, orderExprs2.length);
    assertTrue(orderExprs2[0] instanceof OrderExpression);
    OrderExpression orderExpr2 = (OrderExpression) orderExprs2[0];
    assertEquals("name", ((PrimaryExpression) orderExpr2.getLeft()).getId());
    assertEquals("ascending", orderExpr2.getSortOrder());
    assertEquals(NullOrderingType.NULLS_FIRST, orderExpr2.getNullOrder());
}
Also used : JDOQLCompiler(org.datanucleus.query.compiler.JDOQLCompiler) JavaQueryCompiler(org.datanucleus.query.compiler.JavaQueryCompiler) DyadicExpression(org.datanucleus.query.expression.DyadicExpression) ParameterExpression(org.datanucleus.query.expression.ParameterExpression) Expression(org.datanucleus.query.expression.Expression) InvokeExpression(org.datanucleus.query.expression.InvokeExpression) VariableExpression(org.datanucleus.query.expression.VariableExpression) OrderExpression(org.datanucleus.query.expression.OrderExpression) PrimaryExpression(org.datanucleus.query.expression.PrimaryExpression) OrderExpression(org.datanucleus.query.expression.OrderExpression) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) Product(org.datanucleus.samples.store.Product) QueryCompilation(org.datanucleus.query.compiler.QueryCompilation)

Example 37 with PrimaryExpression

use of org.datanucleus.query.expression.PrimaryExpression in project tests by datanucleus.

the class JDOQLCompilerTest method testFilterCollectionContainsVariable.

/**
 * Tests for collection.contains(element).
 */
public void testFilterCollectionContainsVariable() {
    JavaQueryCompiler compiler = null;
    QueryCompilation compilation = null;
    try {
        compiler = new JDOQLCompiler(nucCtx, nucCtx.getClassLoaderResolver(null), null, Inventory.class, null, "products.contains(element) && element.price < 200", null, null, null, null, null, null, Product.class.getName() + " element", null);
        compilation = compiler.compile(new HashMap(), null);
    } catch (NucleusException ne) {
        NucleusLogger.QUERY.error("Exception thrown during compilation", ne);
        fail("compilation of filter with valid field threw exception : " + ne.getMessage());
    }
    Expression expr = compilation.getExprFilter();
    assertTrue("Compiled expression should have been DyadicExpression but wasnt", expr instanceof DyadicExpression);
    DyadicExpression dyExpr = (DyadicExpression) expr;
    // product.contains(element)
    assertTrue("Left expression should have been InvokeExpression but wasnt", dyExpr.getLeft() instanceof InvokeExpression);
    InvokeExpression leftExpr = (InvokeExpression) dyExpr.getLeft();
    assertTrue("InvokeExpression should have been invoked on PrimaryExpression but wasnt", leftExpr.getLeft() instanceof PrimaryExpression);
    assertEquals("Left expression : Name of field upon which we invoke the method was wrong", "products", ((PrimaryExpression) leftExpr.getLeft()).getId());
    assertEquals("Left expression : Name of invoked method was wrong", "contains", leftExpr.getOperation());
    assertEquals("Left expression : Number of parameters to contains() is wrong", 1, leftExpr.getArguments().size());
    Object param1 = leftExpr.getArguments().get(0);
    assertTrue("Left expression : Parameter1 to contains() is of wrong type", param1 instanceof VariableExpression);
    VariableExpression vrExpr = (VariableExpression) param1;
    assertEquals("Left expression : Name of variable to contains() is incorrect", "element", vrExpr.getId());
    // element.price < 200
    assertTrue("Right expression should have been DyadicExpression but wasnt", dyExpr.getRight() instanceof DyadicExpression);
    DyadicExpression rightExpr = (DyadicExpression) dyExpr.getRight();
    assertTrue("Right expression (left) should have been PrimaryExpression but wasnt", rightExpr.getLeft() instanceof PrimaryExpression);
    PrimaryExpression rightExprLeft = (PrimaryExpression) rightExpr.getLeft();
    assertTrue("Right expression (left).left is of incorrect type", rightExprLeft.getLeft() instanceof VariableExpression);
    VariableExpression rightExprLeftLeft = (VariableExpression) rightExprLeft.getLeft();
    assertTrue("Right expression (left).left is of incorrect type", rightExprLeft.getLeft() instanceof VariableExpression);
    assertEquals("Right expression (left) part1 is incorrect", "element", rightExprLeftLeft.getId());
    assertEquals("Right expression (left) has incorrect number of tuples", 1, rightExprLeft.getTuples().size());
    assertEquals("Right expression (left) part2 is incorrect", "price", rightExprLeft.getTuples().get(0));
    assertEquals("Right expression : Operator between left and right is incorrect", Expression.OP_LT, rightExpr.getOperator());
    assertTrue("Right expression (right) should have been Literal but wasnt", rightExpr.getRight() instanceof Literal);
    Literal rightExprRight = (Literal) rightExpr.getRight();
    assertEquals("Right expression (right) literal has incorrect value", 200, ((Long) rightExprRight.getLiteral()).longValue());
    // Check symbols
    SymbolTable symbols = compilation.getSymbolTable();
    assertTrue("Symbol table doesnt have entry for 'element'", symbols.hasSymbol("element"));
    assertTrue("Symbol table doesnt have entry for 'this'", symbols.hasSymbol("this"));
    Symbol sy1 = symbols.getSymbol("element");
    assertEquals("Type of symbol for 'element' is wrong", Product.class, sy1.getValueType());
    Symbol sy2 = symbols.getSymbol("this");
    assertEquals("Type of symbol for 'this' is wrong", Inventory.class, sy2.getValueType());
}
Also used : JDOQLCompiler(org.datanucleus.query.compiler.JDOQLCompiler) InvokeExpression(org.datanucleus.query.expression.InvokeExpression) PrimaryExpression(org.datanucleus.query.expression.PrimaryExpression) HashMap(java.util.HashMap) Symbol(org.datanucleus.query.compiler.Symbol) Product(org.datanucleus.samples.store.Product) SymbolTable(org.datanucleus.query.compiler.SymbolTable) VariableExpression(org.datanucleus.query.expression.VariableExpression) DyadicExpression(org.datanucleus.query.expression.DyadicExpression) JavaQueryCompiler(org.datanucleus.query.compiler.JavaQueryCompiler) DyadicExpression(org.datanucleus.query.expression.DyadicExpression) ParameterExpression(org.datanucleus.query.expression.ParameterExpression) Expression(org.datanucleus.query.expression.Expression) InvokeExpression(org.datanucleus.query.expression.InvokeExpression) VariableExpression(org.datanucleus.query.expression.VariableExpression) OrderExpression(org.datanucleus.query.expression.OrderExpression) PrimaryExpression(org.datanucleus.query.expression.PrimaryExpression) Literal(org.datanucleus.query.expression.Literal) QueryCompilation(org.datanucleus.query.compiler.QueryCompilation) NucleusException(org.datanucleus.exceptions.NucleusException) Inventory(org.datanucleus.samples.store.Inventory)

Example 38 with PrimaryExpression

use of org.datanucleus.query.expression.PrimaryExpression in project tests by datanucleus.

the class JDOQLCompilerTest method testFilterWithNegateExpression.

/**
 * Tests for "!(expression)".
 */
public void testFilterWithNegateExpression() {
    JavaQueryCompiler compiler = null;
    QueryCompilation compilation = null;
    try {
        compiler = new JDOQLCompiler(nucCtx, nucCtx.getClassLoaderResolver(null), null, Product.class, null, "!(price > 32)", null, null, null, null, null, null, null, null);
        compilation = compiler.compile(new HashMap(), null);
    } catch (NucleusException ne) {
        NucleusLogger.QUERY.error("Exception thrown during compilation", ne);
        fail("compilation of filter with valid field threw exception : " + ne.getMessage());
    }
    Expression expr = compilation.getExprFilter();
    assertTrue("Compiled expression should have been DyadicExpression but wasnt", expr instanceof DyadicExpression);
    DyadicExpression dyExpr = (DyadicExpression) expr;
    assertTrue("Compiled left expression should have been DyadicExpression but wasnt", dyExpr.getLeft() instanceof DyadicExpression);
    assertNull("Compiled right expression should have been null but wasnt", dyExpr.getRight());
    assertEquals("Expression operator is wrong", Expression.OP_NOT, dyExpr.getOperator());
    DyadicExpression leftExpr = (DyadicExpression) dyExpr.getLeft();
    assertTrue("Left (left) should be PrimaryExpression but isnt", leftExpr.getLeft() instanceof PrimaryExpression);
    assertTrue("Left (right) should be Literal but isnt", leftExpr.getRight() instanceof Literal);
    assertEquals("Left expression operator is wrong", Expression.OP_GT, leftExpr.getOperator());
    PrimaryExpression primExpr = (PrimaryExpression) leftExpr.getLeft();
    assertEquals("Left (left) expression has incorrect number of tuples", 1, primExpr.getTuples().size());
    assertEquals("Left (left) expression 'id' is incorrect", "price", primExpr.getId());
    Literal lit = (Literal) leftExpr.getRight();
    assertTrue("Left (right) expression literal is of incorrect type", lit.getLiteral() instanceof Long);
    assertEquals("Left (right) expression literal has incorrect value", 32, ((Long) lit.getLiteral()).longValue());
}
Also used : JDOQLCompiler(org.datanucleus.query.compiler.JDOQLCompiler) JavaQueryCompiler(org.datanucleus.query.compiler.JavaQueryCompiler) PrimaryExpression(org.datanucleus.query.expression.PrimaryExpression) HashMap(java.util.HashMap) DyadicExpression(org.datanucleus.query.expression.DyadicExpression) ParameterExpression(org.datanucleus.query.expression.ParameterExpression) Expression(org.datanucleus.query.expression.Expression) InvokeExpression(org.datanucleus.query.expression.InvokeExpression) VariableExpression(org.datanucleus.query.expression.VariableExpression) OrderExpression(org.datanucleus.query.expression.OrderExpression) PrimaryExpression(org.datanucleus.query.expression.PrimaryExpression) Literal(org.datanucleus.query.expression.Literal) Product(org.datanucleus.samples.store.Product) QueryCompilation(org.datanucleus.query.compiler.QueryCompilation) NucleusException(org.datanucleus.exceptions.NucleusException) DyadicExpression(org.datanucleus.query.expression.DyadicExpression)

Example 39 with PrimaryExpression

use of org.datanucleus.query.expression.PrimaryExpression in project datanucleus-rdbms by datanucleus.

the class QueryToSQLMapper method processInvokeExpression.

/**
 * Internal method to handle the processing of an InvokeExpression.
 * @param expr The InvokeExpression
 * @param invokedSqlExpr The SQLExpression that we are invoking the method on.
 * @return The resultant SQLExpression
 */
protected SQLExpression processInvokeExpression(InvokeExpression expr, SQLExpression invokedSqlExpr) {
    if (invokedSqlExpr instanceof NullLiteral) {
        // We cannot invoke anything on a null TODO Handle this "NPE"
        NucleusLogger.QUERY.warn("Compilation of InvokeExpression needs to invoke method \"" + expr.getOperation() + "\" on " + invokedSqlExpr + " but not possible");
    }
    String operation = expr.getOperation();
    if (invokedSqlExpr instanceof MapExpression && operation.equals("contains") && compilation.getQueryLanguage().equalsIgnoreCase(Query.LANGUAGE_JPQL)) {
        // JPQL "MEMBER OF" will be passed through from generic compilation as "contains" since we don't know types at that point
        operation = "containsValue";
    }
    // Process the arguments for invoking
    List args = expr.getArguments();
    List sqlExprArgs = null;
    if (args != null) {
        sqlExprArgs = new ArrayList<SQLExpression>();
        Iterator<Expression> iter = args.iterator();
        while (iter.hasNext()) {
            Expression argExpr = iter.next();
            if (argExpr instanceof PrimaryExpression) {
                processPrimaryExpression((PrimaryExpression) argExpr);
                SQLExpression argSqlExpr = stack.pop();
                if (compileComponent == CompilationComponent.RESULT && operation.equalsIgnoreCase("count") && stmt.getNumberOfTableGroups() > 1) {
                    if (argSqlExpr.getSQLTable() == stmt.getPrimaryTable() && argSqlExpr.getJavaTypeMapping() == stmt.getPrimaryTable().getTable().getIdMapping()) {
                        // Result with "count(this)" and joins to other groups, so enforce distinct
                        argSqlExpr.distinct();
                    }
                }
                sqlExprArgs.add(argSqlExpr);
            } else if (argExpr instanceof ParameterExpression) {
                processParameterExpression((ParameterExpression) argExpr);
                sqlExprArgs.add(stack.pop());
            } else if (argExpr instanceof InvokeExpression) {
                processInvokeExpression((InvokeExpression) argExpr);
                sqlExprArgs.add(stack.pop());
            } else if (argExpr instanceof Literal) {
                processLiteral((Literal) argExpr);
                sqlExprArgs.add(stack.pop());
            } else if (argExpr instanceof DyadicExpression) {
                // Evaluate using this evaluator
                argExpr.evaluate(this);
                sqlExprArgs.add(stack.pop());
            } else if (argExpr instanceof VariableExpression) {
                processVariableExpression((VariableExpression) argExpr);
                sqlExprArgs.add(stack.pop());
            } else if (argExpr instanceof CaseExpression) {
                processCaseExpression((CaseExpression) argExpr);
                sqlExprArgs.add(stack.pop());
            } else {
                throw new NucleusException("Dont currently support invoke expression argument " + argExpr);
            }
        }
        if (operation.equals("INDEX")) {
            // Special case of index expression
            List<Expression> indexArgs = expr.getArguments();
            if (indexArgs == null || indexArgs.size() > 1) {
                throw new NucleusException("Can only use INDEX with single argument");
            }
            PrimaryExpression indexExpr = (PrimaryExpression) indexArgs.get(0);
            String joinAlias = indexExpr.getId();
            String collExprName = joinAlias;
            if (explicitJoinPrimaryByAlias != null) {
                collExprName = explicitJoinPrimaryByAlias.get(joinAlias);
                if (collExprName == null) {
                    throw new NucleusException("Unable to locate primary expression for alias " + joinAlias);
                }
            }
            // Find an expression for the collection field
            List<String> tuples = new ArrayList<>();
            StringTokenizer primTokenizer = new StringTokenizer(collExprName, ".");
            while (primTokenizer.hasMoreTokens()) {
                String token = primTokenizer.nextToken();
                tuples.add(token);
            }
            PrimaryExpression collPrimExpr = new PrimaryExpression(tuples);
            processPrimaryExpression(collPrimExpr);
            SQLExpression collSqlExpr = stack.pop();
            sqlExprArgs.add(collSqlExpr);
        }
    }
    // Invoke the method
    SQLExpression sqlExpr = null;
    if (invokedSqlExpr instanceof org.datanucleus.store.rdbms.sql.expression.SubqueryExpression) {
        if (operation.equalsIgnoreCase("isEmpty")) {
            // Special case of {subquery}.isEmpty(), equates to "NOT EXISTS (subquery)"
            org.datanucleus.store.rdbms.sql.expression.SubqueryExpression subquerySqlExpr = (org.datanucleus.store.rdbms.sql.expression.SubqueryExpression) invokedSqlExpr;
            SQLStatement subStmt = subquerySqlExpr.getSubqueryStatement();
            SQLExpression subqueryNotExistsExpr = new BooleanSubqueryExpression(stmt, "EXISTS", subStmt).not();
            stack.push(subqueryNotExistsExpr);
            return subqueryNotExistsExpr;
        } else if (operation.equalsIgnoreCase("size")) {
            // {subquery}.size() should simply be changed to have a subquery of "SELECT COUNT(*) FROM ..."
            throw new NucleusUserException("Attempt to invoke method `" + operation + "` on Subquery. This is not supported. Change the subquery to return COUNT() instead.");
        }
        throw new NucleusUserException("Attempt to invoke method `" + operation + "` on Subquery. This is not supported");
    }
    if (invokedSqlExpr != null) {
        sqlExpr = invokedSqlExpr.invoke(operation, sqlExprArgs);
    } else {
        sqlExpr = exprFactory.invokeMethod(stmt, null, operation, null, sqlExprArgs);
    }
    stack.push(sqlExpr);
    return sqlExpr;
}
Also used : SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) PrimaryExpression(org.datanucleus.query.expression.PrimaryExpression) ArrayList(java.util.ArrayList) SQLStatement(org.datanucleus.store.rdbms.sql.SQLStatement) CaseExpression(org.datanucleus.query.expression.CaseExpression) BooleanSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.BooleanSubqueryExpression) NumericSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.NumericSubqueryExpression) StringSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.StringSubqueryExpression) SubqueryExpression(org.datanucleus.query.expression.SubqueryExpression) TemporalSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.TemporalSubqueryExpression) TemporalLiteral(org.datanucleus.store.rdbms.sql.expression.TemporalLiteral) SQLLiteral(org.datanucleus.store.rdbms.sql.expression.SQLLiteral) ParameterLiteral(org.datanucleus.store.rdbms.sql.expression.ParameterLiteral) BooleanLiteral(org.datanucleus.store.rdbms.sql.expression.BooleanLiteral) IntegerLiteral(org.datanucleus.store.rdbms.sql.expression.IntegerLiteral) Literal(org.datanucleus.query.expression.Literal) NullLiteral(org.datanucleus.store.rdbms.sql.expression.NullLiteral) ArrayList(java.util.ArrayList) List(java.util.List) MapExpression(org.datanucleus.store.rdbms.sql.expression.MapExpression) InvokeExpression(org.datanucleus.query.expression.InvokeExpression) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) VariableExpression(org.datanucleus.query.expression.VariableExpression) DyadicExpression(org.datanucleus.query.expression.DyadicExpression) StringTokenizer(java.util.StringTokenizer) CaseExpression(org.datanucleus.query.expression.CaseExpression) BooleanSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.BooleanSubqueryExpression) StringExpression(org.datanucleus.store.rdbms.sql.expression.StringExpression) JoinExpression(org.datanucleus.query.expression.JoinExpression) NumericSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.NumericSubqueryExpression) StringSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.StringSubqueryExpression) ClassExpression(org.datanucleus.query.expression.ClassExpression) InvokeExpression(org.datanucleus.query.expression.InvokeExpression) MapExpression(org.datanucleus.store.rdbms.sql.expression.MapExpression) SubqueryExpression(org.datanucleus.query.expression.SubqueryExpression) NewObjectExpression(org.datanucleus.store.rdbms.sql.expression.NewObjectExpression) TemporalSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.TemporalSubqueryExpression) BooleanExpression(org.datanucleus.store.rdbms.sql.expression.BooleanExpression) OrderExpression(org.datanucleus.query.expression.OrderExpression) PrimaryExpression(org.datanucleus.query.expression.PrimaryExpression) SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) UnboundExpression(org.datanucleus.store.rdbms.sql.expression.UnboundExpression) TemporalExpression(org.datanucleus.store.rdbms.sql.expression.TemporalExpression) ArrayExpression(org.datanucleus.query.expression.ArrayExpression) ResultAliasExpression(org.datanucleus.store.rdbms.sql.expression.ResultAliasExpression) CreatorExpression(org.datanucleus.query.expression.CreatorExpression) Expression(org.datanucleus.query.expression.Expression) TypeExpression(org.datanucleus.query.expression.TypeExpression) NumericExpression(org.datanucleus.store.rdbms.sql.expression.NumericExpression) CollectionExpression(org.datanucleus.store.rdbms.sql.expression.CollectionExpression) DyadicExpression(org.datanucleus.query.expression.DyadicExpression) ParameterExpression(org.datanucleus.query.expression.ParameterExpression) ColumnExpression(org.datanucleus.store.rdbms.sql.expression.ColumnExpression) VariableExpression(org.datanucleus.query.expression.VariableExpression) BooleanSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.BooleanSubqueryExpression) ParameterExpression(org.datanucleus.query.expression.ParameterExpression) NucleusException(org.datanucleus.exceptions.NucleusException) NullLiteral(org.datanucleus.store.rdbms.sql.expression.NullLiteral)

Example 40 with PrimaryExpression

use of org.datanucleus.query.expression.PrimaryExpression in project datanucleus-rdbms by datanucleus.

the class QueryToSQLMapper method compileResult.

/**
 * Method to compile the result clause of the query into the SQLStatement.
 * Note that this also compiles queries of the candidate (no specified result), selecting the candidate field(s).
 * @param stmt SELECT statement
 */
protected void compileResult(SelectStatement stmt) {
    compileComponent = CompilationComponent.RESULT;
    boolean unionsPresent = stmt.getNumberOfUnions() > 0;
    // TODO Cater for more expression types where we have UNIONs and select each UNION separately
    if (compilation.getExprResult() != null) {
        // Select any result expressions
        Expression[] resultExprs = compilation.getExprResult();
        for (int i = 0; i < resultExprs.length; i++) {
            String alias = resultExprs[i].getAlias();
            if (alias != null && resultAliases == null) {
                resultAliases = new HashSet<>();
            }
            if (resultExprs[i] instanceof InvokeExpression || resultExprs[i] instanceof ParameterExpression || resultExprs[i] instanceof Literal) {
                // Process expressions that need no special treatment
                if (resultExprs[i] instanceof InvokeExpression) {
                    processInvokeExpression((InvokeExpression) resultExprs[i]);
                } else if (resultExprs[i] instanceof ParameterExpression) {
                    // Second argument : parameters are literals in result
                    processParameterExpression((ParameterExpression) resultExprs[i], true);
                } else {
                    processLiteral((Literal) resultExprs[i]);
                }
                SQLExpression sqlExpr = stack.pop();
                validateExpressionForResult(sqlExpr);
                int[] cols = stmt.select(sqlExpr, alias);
                StatementMappingIndex idx = new StatementMappingIndex(sqlExpr.getJavaTypeMapping());
                idx.setColumnPositions(cols);
                if (alias != null) {
                    resultAliases.add(alias);
                    idx.setColumnAlias(alias);
                }
                resultDefinition.addMappingForResultExpression(i, idx);
            } else if (resultExprs[i] instanceof PrimaryExpression) {
                PrimaryExpression primExpr = (PrimaryExpression) resultExprs[i];
                if (primExpr.getId().equals(candidateAlias)) {
                    // "this", so select fetch plan fields
                    if (unionsPresent) {
                        // Process the first union separately (in case they have TYPE/instanceof) and then handle remaining UNIONs below
                        stmt.setAllowUnions(false);
                    }
                    StatementClassMapping map = new StatementClassMapping(candidateCmd.getFullClassName(), null);
                    SQLStatementHelper.selectFetchPlanOfCandidateInStatement(stmt, map, candidateCmd, fetchPlan, 1);
                    resultDefinition.addMappingForResultExpression(i, map);
                    if (unionsPresent) {
                        // Process remaining UNIONs. Assumed that we have the same result mapping as the first UNION otherwise SQL wouldn't work anyway
                        stmt.setAllowUnions(true);
                        List<SelectStatement> unionStmts = stmt.getUnions();
                        SelectStatement originalStmt = stmt;
                        for (SelectStatement unionStmt : unionStmts) {
                            this.stmt = unionStmt;
                            unionStmt.setQueryGenerator(this);
                            unionStmt.setAllowUnions(false);
                            StatementClassMapping dummyClsMapping = new StatementClassMapping(candidateCmd.getFullClassName(), null);
                            SQLStatementHelper.selectFetchPlanOfCandidateInStatement(unionStmt, dummyClsMapping, candidateCmd, fetchPlan, 1);
                            unionStmt.setQueryGenerator(null);
                            unionStmt.setAllowUnions(true);
                        }
                        this.stmt = originalStmt;
                    }
                } else {
                    processPrimaryExpression(primExpr);
                    SQLExpression sqlExpr = stack.pop();
                    validateExpressionForResult(sqlExpr);
                    if (primExpr.getId().endsWith("#KEY") || primExpr.getId().endsWith("#VALUE")) {
                        // JPQL KEY(map) or VALUE(map), so select FetchPlan fields where persistable
                        if (sqlExpr.getJavaTypeMapping() instanceof PersistableMapping) {
                            // Method returns persistable object, so select the FetchPlan
                            String selectedType = ((PersistableMapping) sqlExpr.getJavaTypeMapping()).getType();
                            AbstractClassMetaData selectedCmd = ec.getMetaDataManager().getMetaDataForClass(selectedType, clr);
                            FetchPlanForClass fpForCmd = fetchPlan.getFetchPlanForClass(selectedCmd);
                            int[] membersToSelect = fpForCmd.getMemberNumbers();
                            ClassTable selectedTable = (ClassTable) sqlExpr.getSQLTable().getTable();
                            StatementClassMapping map = new StatementClassMapping(selectedCmd.getFullClassName(), null);
                            if (selectedCmd.getIdentityType() == IdentityType.DATASTORE) {
                                int[] cols = stmt.select(sqlExpr.getSQLTable(), selectedTable.getSurrogateMapping(SurrogateColumnType.DATASTORE_ID, false), alias);
                                StatementMappingIndex idx = new StatementMappingIndex(selectedTable.getSurrogateMapping(SurrogateColumnType.DATASTORE_ID, false));
                                idx.setColumnPositions(cols);
                                map.addMappingForMember(SurrogateColumnType.DATASTORE_ID.getFieldNumber(), idx);
                            }
                            // Select the FetchPlan members
                            for (int memberToSelect : membersToSelect) {
                                AbstractMemberMetaData selMmd = selectedCmd.getMetaDataForManagedMemberAtAbsolutePosition(memberToSelect);
                                // TODO Arbitrary penultimate argument
                                SQLStatementHelper.selectMemberOfSourceInStatement(stmt, map, fetchPlan, sqlExpr.getSQLTable(), selMmd, clr, 1, null);
                            }
                            resultDefinition.addMappingForResultExpression(i, map);
                            continue;
                        } else if (sqlExpr.getJavaTypeMapping() instanceof EmbeddedMapping) {
                            // Method returns embedded object, so select the FetchPlan
                            EmbeddedMapping embMapping = (EmbeddedMapping) sqlExpr.getJavaTypeMapping();
                            AbstractClassMetaData selectedCmd = ec.getMetaDataManager().getMetaDataForClass(embMapping.getType(), clr);
                            // Select the FetchPlan members
                            StatementClassMapping map = new StatementClassMapping(selectedCmd.getFullClassName(), null);
                            int[] membersToSelect = fetchPlan.getFetchPlanForClass(selectedCmd).getMemberNumbers();
                            for (int memberToSelect : membersToSelect) {
                                AbstractMemberMetaData selMmd = selectedCmd.getMetaDataForManagedMemberAtAbsolutePosition(memberToSelect);
                                JavaTypeMapping selMapping = embMapping.getJavaTypeMapping(selMmd.getName());
                                if (selMapping.includeInFetchStatement()) {
                                    int[] cols = stmt.select(sqlExpr.getSQLTable(), selMapping, alias);
                                    StatementMappingIndex idx = new StatementMappingIndex(selMapping);
                                    idx.setColumnPositions(cols);
                                    map.addMappingForMember(memberToSelect, idx);
                                }
                            }
                            resultDefinition.addMappingForResultExpression(i, map);
                            continue;
                        }
                    }
                    // TODO If the user selects an alias here that is joined, should maybe respect FetchPlan for that (like above for candidate)
                    // TODO Cater for use of UNIONs (e.g "complete-table" inheritance) where mapping is different in other UNION
                    // The difficulty here is that processPrimaryExpression makes use of the sqlTableByPrimary lookup, which is based on the primary statement, so
                    // it still doesn't find the right table/mapping for the UNIONed statements.
                    int[] cols = null;
                    if (sqlExpr instanceof SQLLiteral) {
                        cols = stmt.select(sqlExpr, alias);
                    } else {
                        cols = stmt.select(sqlExpr.getSQLTable(), sqlExpr.getJavaTypeMapping(), alias);
                    }
                    StatementMappingIndex idx = new StatementMappingIndex(sqlExpr.getJavaTypeMapping());
                    idx.setColumnPositions(cols);
                    if (alias != null) {
                        resultAliases.add(alias);
                        idx.setColumnAlias(alias);
                    }
                    resultDefinition.addMappingForResultExpression(i, idx);
                }
            } else if (resultExprs[i] instanceof VariableExpression) {
                // Subquery?
                processVariableExpression((VariableExpression) resultExprs[i]);
                SQLExpression sqlExpr = stack.pop();
                validateExpressionForResult(sqlExpr);
                if (sqlExpr instanceof UnboundExpression) {
                    // Variable wasn't bound in the compilation so far, so handle as cross-join
                    processUnboundExpression((UnboundExpression) sqlExpr);
                    sqlExpr = stack.pop();
                    NucleusLogger.QUERY.debug("QueryToSQL.exprResult variable was still unbound, so binding via cross-join");
                }
                int[] cols = stmt.select(sqlExpr, alias);
                StatementMappingIndex idx = new StatementMappingIndex(sqlExpr.getJavaTypeMapping());
                idx.setColumnPositions(cols);
                if (alias != null) {
                    resultAliases.add(alias);
                    idx.setColumnAlias(alias);
                }
                resultDefinition.addMappingForResultExpression(i, idx);
            } else if (resultExprs[i] instanceof TypeExpression) {
                // TYPE(identification_variable | single_valued_path_expr | input_parameter)
                TypeExpression typeExpr = (TypeExpression) resultExprs[i];
                Expression containedExpr = typeExpr.getContainedExpression();
                if (containedExpr instanceof PrimaryExpression) {
                    processPrimaryExpression((PrimaryExpression) containedExpr);
                    SQLExpression sqlExpr = stack.pop();
                    JavaTypeMapping discrimMapping = sqlExpr.getSQLTable().getTable().getSurrogateMapping(SurrogateColumnType.DISCRIMINATOR, true);
                    if (discrimMapping == null) {
                        // TODO If we have a UNIONED primary expression then it would be possible to just select the DN_TYPE from the particular union
                        throw new NucleusException("Result has call to " + typeExpr + " but contained expression has no discriminator. Not supported");
                    }
                    int[] cols = stmt.select(sqlExpr.getSQLTable(), discrimMapping, null, true);
                    StatementMappingIndex idx = new StatementMappingIndex(discrimMapping);
                    idx.setColumnPositions(cols);
                    resultDefinition.addMappingForResultExpression(i, idx);
                } else {
                    throw new NucleusException("Result has call to " + typeExpr + " but contained expression not supported");
                }
            } else if (resultExprs[i] instanceof CreatorExpression) {
                processCreatorExpression((CreatorExpression) resultExprs[i]);
                NewObjectExpression sqlExpr = (NewObjectExpression) stack.pop();
                StatementNewObjectMapping stmtMap = getStatementMappingForNewObjectExpression(sqlExpr, stmt);
                resultDefinition.addMappingForResultExpression(i, stmtMap);
            } else if (resultExprs[i] instanceof DyadicExpression || resultExprs[i] instanceof CaseExpression) {
                if (unionsPresent) {
                    // Process the first union separately (in case they have TYPE/instanceof) and then handle remaining UNIONs below
                    stmt.setAllowUnions(false);
                }
                resultExprs[i].evaluate(this);
                SQLExpression sqlExpr = stack.pop();
                int[] cols = stmt.select(sqlExpr, alias);
                StatementMappingIndex idx = new StatementMappingIndex(sqlExpr.getJavaTypeMapping());
                idx.setColumnPositions(cols);
                if (alias != null) {
                    resultAliases.add(alias);
                    idx.setColumnAlias(alias);
                }
                resultDefinition.addMappingForResultExpression(i, idx);
                if (unionsPresent) {
                    // Process remaining UNIONs. Assumed that we have the same result mapping as the first UNION otherwise SQL wouldn't work anyway
                    stmt.setAllowUnions(true);
                    List<SelectStatement> unionStmts = stmt.getUnions();
                    SelectStatement originalStmt = stmt;
                    for (SelectStatement unionStmt : unionStmts) {
                        this.stmt = unionStmt;
                        unionStmt.setQueryGenerator(this);
                        unionStmt.setAllowUnions(false);
                        resultExprs[i].evaluate(this);
                        sqlExpr = stack.pop();
                        unionStmt.select(sqlExpr, alias);
                        unionStmt.setQueryGenerator(null);
                        unionStmt.setAllowUnions(true);
                    }
                    this.stmt = originalStmt;
                }
            } else {
                throw new NucleusException("Dont currently support result clause containing expression of type " + resultExprs[i]);
            }
        }
        if (stmt.getNumberOfSelects() == 0) {
            // Nothing selected so likely the user had some "new MyClass()" expression, so select "1"
            stmt.select(exprFactory.newLiteral(stmt, storeMgr.getMappingManager().getMapping(Integer.class), 1), null);
        }
    } else {
        // Select of the candidate (no result)
        if (candidateCmd.getIdentityType() == IdentityType.NONDURABLE) {
            // Nondurable identity cases have no "id" for later fetching so get all fields now
            if (NucleusLogger.QUERY.isDebugEnabled()) {
                NucleusLogger.QUERY.debug(Localiser.msg("052520", candidateCmd.getFullClassName()));
            }
            fetchPlan.setGroup("all");
        }
        if (subclasses) {
        // TODO Check for special case of candidate+subclasses stores in same table with discriminator, so select FetchGroup of subclasses also
        }
        int maxFetchDepth = fetchPlan.getMaxFetchDepth();
        if (maxFetchDepth < 0) {
            NucleusLogger.QUERY.debug("No limit specified on query fetch so limiting to 3 levels from candidate. " + "Specify the '" + PropertyNames.PROPERTY_MAX_FETCH_DEPTH + "' to override this");
            // TODO Arbitrary
            maxFetchDepth = 3;
        }
        // This means that we then cater for a UNION using a different column name than the primary statement
        if (unionsPresent) {
            // Process the first union separately (in case they have TYPE/instanceof) and then handle remaining UNIONs below
            stmt.setAllowUnions(false);
        }
        selectFetchPlanForCandidate(stmt, resultDefinitionForClass, maxFetchDepth);
        if (unionsPresent) {
            // Process remaining UNIONs. Assumed that we have the same result mapping as the first UNION otherwise SQL wouldn't work anyway
            stmt.setAllowUnions(true);
            List<SelectStatement> unionStmts = stmt.getUnions();
            SelectStatement originalStmt = stmt;
            for (SelectStatement unionStmt : unionStmts) {
                this.stmt = unionStmt;
                unionStmt.setQueryGenerator(this);
                unionStmt.setAllowUnions(false);
                // We don't want to overwrite anything in the root StatementClassMapping
                StatementClassMapping dummyResClsMapping = new StatementClassMapping();
                selectFetchPlanForCandidate(unionStmt, dummyResClsMapping, maxFetchDepth);
                unionStmt.setQueryGenerator(null);
                unionStmt.setAllowUnions(true);
            }
            this.stmt = originalStmt;
        }
    }
    compileComponent = null;
}
Also used : SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) PrimaryExpression(org.datanucleus.query.expression.PrimaryExpression) FetchPlanForClass(org.datanucleus.FetchPlanForClass) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) SQLLiteral(org.datanucleus.store.rdbms.sql.expression.SQLLiteral) UnboundExpression(org.datanucleus.store.rdbms.sql.expression.UnboundExpression) CreatorExpression(org.datanucleus.query.expression.CreatorExpression) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) CaseExpression(org.datanucleus.query.expression.CaseExpression) NewObjectExpression(org.datanucleus.store.rdbms.sql.expression.NewObjectExpression) SelectStatement(org.datanucleus.store.rdbms.sql.SelectStatement) TemporalLiteral(org.datanucleus.store.rdbms.sql.expression.TemporalLiteral) SQLLiteral(org.datanucleus.store.rdbms.sql.expression.SQLLiteral) ParameterLiteral(org.datanucleus.store.rdbms.sql.expression.ParameterLiteral) BooleanLiteral(org.datanucleus.store.rdbms.sql.expression.BooleanLiteral) IntegerLiteral(org.datanucleus.store.rdbms.sql.expression.IntegerLiteral) Literal(org.datanucleus.query.expression.Literal) NullLiteral(org.datanucleus.store.rdbms.sql.expression.NullLiteral) ArrayList(java.util.ArrayList) List(java.util.List) InvokeExpression(org.datanucleus.query.expression.InvokeExpression) TypeExpression(org.datanucleus.query.expression.TypeExpression) VariableExpression(org.datanucleus.query.expression.VariableExpression) DyadicExpression(org.datanucleus.query.expression.DyadicExpression) PersistableMapping(org.datanucleus.store.rdbms.mapping.java.PersistableMapping) CaseExpression(org.datanucleus.query.expression.CaseExpression) BooleanSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.BooleanSubqueryExpression) StringExpression(org.datanucleus.store.rdbms.sql.expression.StringExpression) JoinExpression(org.datanucleus.query.expression.JoinExpression) NumericSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.NumericSubqueryExpression) StringSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.StringSubqueryExpression) ClassExpression(org.datanucleus.query.expression.ClassExpression) InvokeExpression(org.datanucleus.query.expression.InvokeExpression) MapExpression(org.datanucleus.store.rdbms.sql.expression.MapExpression) SubqueryExpression(org.datanucleus.query.expression.SubqueryExpression) NewObjectExpression(org.datanucleus.store.rdbms.sql.expression.NewObjectExpression) TemporalSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.TemporalSubqueryExpression) BooleanExpression(org.datanucleus.store.rdbms.sql.expression.BooleanExpression) OrderExpression(org.datanucleus.query.expression.OrderExpression) PrimaryExpression(org.datanucleus.query.expression.PrimaryExpression) SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) UnboundExpression(org.datanucleus.store.rdbms.sql.expression.UnboundExpression) TemporalExpression(org.datanucleus.store.rdbms.sql.expression.TemporalExpression) ArrayExpression(org.datanucleus.query.expression.ArrayExpression) ResultAliasExpression(org.datanucleus.store.rdbms.sql.expression.ResultAliasExpression) CreatorExpression(org.datanucleus.query.expression.CreatorExpression) Expression(org.datanucleus.query.expression.Expression) TypeExpression(org.datanucleus.query.expression.TypeExpression) NumericExpression(org.datanucleus.store.rdbms.sql.expression.NumericExpression) CollectionExpression(org.datanucleus.store.rdbms.sql.expression.CollectionExpression) DyadicExpression(org.datanucleus.query.expression.DyadicExpression) ParameterExpression(org.datanucleus.query.expression.ParameterExpression) ColumnExpression(org.datanucleus.store.rdbms.sql.expression.ColumnExpression) VariableExpression(org.datanucleus.query.expression.VariableExpression) EmbeddedMapping(org.datanucleus.store.rdbms.mapping.java.EmbeddedMapping) ClassTable(org.datanucleus.store.rdbms.table.ClassTable) ParameterExpression(org.datanucleus.query.expression.ParameterExpression) NucleusException(org.datanucleus.exceptions.NucleusException) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData)

Aggregations

PrimaryExpression (org.datanucleus.query.expression.PrimaryExpression)77 ParameterExpression (org.datanucleus.query.expression.ParameterExpression)73 Literal (org.datanucleus.query.expression.Literal)60 NucleusException (org.datanucleus.exceptions.NucleusException)59 InvokeExpression (org.datanucleus.query.expression.InvokeExpression)54 VariableExpression (org.datanucleus.query.expression.VariableExpression)48 DyadicExpression (org.datanucleus.query.expression.DyadicExpression)46 Expression (org.datanucleus.query.expression.Expression)46 QueryCompilation (org.datanucleus.query.compiler.QueryCompilation)25 JavaQueryCompiler (org.datanucleus.query.compiler.JavaQueryCompiler)23 OrderExpression (org.datanucleus.query.expression.OrderExpression)22 HashMap (java.util.HashMap)16 JDOQLCompiler (org.datanucleus.query.compiler.JDOQLCompiler)15 ClassExpression (org.datanucleus.query.expression.ClassExpression)15 JoinExpression (org.datanucleus.query.expression.JoinExpression)15 SubqueryExpression (org.datanucleus.query.expression.SubqueryExpression)15 Product (org.datanucleus.samples.store.Product)15 NucleusUserException (org.datanucleus.exceptions.NucleusUserException)12 JPQLCompiler (org.datanucleus.query.compiler.JPQLCompiler)9 List (java.util.List)8