Search in sources :

Example 1 with PrimaryExpression

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

the class QueryToSQLMapper method getInvokedSqlExpressionForInvokeExpression.

protected SQLExpression getInvokedSqlExpressionForInvokeExpression(InvokeExpression expr) {
    Expression invokedExpr = expr.getLeft();
    SQLExpression invokedSqlExpr = null;
    if (invokedExpr == null) {
    // Static method
    } else if (invokedExpr instanceof PrimaryExpression) {
        processPrimaryExpression((PrimaryExpression) invokedExpr);
        invokedSqlExpr = stack.pop();
    } else if (invokedExpr instanceof Literal) {
        processLiteral((Literal) invokedExpr);
        invokedSqlExpr = stack.pop();
    } else if (invokedExpr instanceof ParameterExpression) {
        // TODO May be needed to set the second parameter to "false" here and then if the method
        // being invoked needs the parameters as a normal SQLLiteral then allow it to convert it itself
        processParameterExpression((ParameterExpression) invokedExpr, true);
        invokedSqlExpr = stack.pop();
    } else if (invokedExpr instanceof InvokeExpression) {
        processInvokeExpression((InvokeExpression) invokedExpr);
        invokedSqlExpr = stack.pop();
    } else if (invokedExpr instanceof VariableExpression) {
        processVariableExpression((VariableExpression) invokedExpr);
        invokedSqlExpr = stack.pop();
    } else if (invokedExpr instanceof ArrayExpression) {
        ArrayExpression arrExpr = (ArrayExpression) invokedExpr;
        SQLExpression[] arrSqlExprs = new SQLExpression[arrExpr.getArraySize()];
        for (int i = 0; i < arrExpr.getArraySize(); i++) {
            Expression arrElemExpr = arrExpr.getElement(i);
            arrElemExpr.evaluate(this);
            arrSqlExprs[i] = stack.pop();
        }
        JavaTypeMapping m = exprFactory.getMappingForType(Object[].class, false);
        invokedSqlExpr = new org.datanucleus.store.rdbms.sql.expression.ArrayExpression(stmt, m, arrSqlExprs);
    } else if (invokedExpr instanceof DyadicExpression) {
        DyadicExpression dyExpr = (DyadicExpression) invokedExpr;
        dyExpr.evaluate(this);
        invokedSqlExpr = stack.pop();
    } else {
        throw new NucleusException("Dont currently support invoke expression " + invokedExpr);
    }
    return invokedSqlExpr;
}
Also used : InvokeExpression(org.datanucleus.store.query.expression.InvokeExpression) SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) PrimaryExpression(org.datanucleus.store.query.expression.PrimaryExpression) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) VariableExpression(org.datanucleus.store.query.expression.VariableExpression) DyadicExpression(org.datanucleus.store.query.expression.DyadicExpression) PrimaryExpression(org.datanucleus.store.query.expression.PrimaryExpression) BooleanSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.BooleanSubqueryExpression) TypeConverterExpression(org.datanucleus.store.rdbms.sql.expression.TypeConverterExpression) StringExpression(org.datanucleus.store.rdbms.sql.expression.StringExpression) NumericSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.NumericSubqueryExpression) StringSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.StringSubqueryExpression) MapExpression(org.datanucleus.store.rdbms.sql.expression.MapExpression) ArrayExpression(org.datanucleus.store.query.expression.ArrayExpression) CaseExpression(org.datanucleus.store.query.expression.CaseExpression) CreatorExpression(org.datanucleus.store.query.expression.CreatorExpression) NewObjectExpression(org.datanucleus.store.rdbms.sql.expression.NewObjectExpression) OrderExpression(org.datanucleus.store.query.expression.OrderExpression) TemporalSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.TemporalSubqueryExpression) ClassExpression(org.datanucleus.store.query.expression.ClassExpression) BooleanExpression(org.datanucleus.store.rdbms.sql.expression.BooleanExpression) Expression(org.datanucleus.store.query.expression.Expression) SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) ParameterExpression(org.datanucleus.store.query.expression.ParameterExpression) UnboundExpression(org.datanucleus.store.rdbms.sql.expression.UnboundExpression) TemporalExpression(org.datanucleus.store.rdbms.sql.expression.TemporalExpression) SubqueryExpression(org.datanucleus.store.query.expression.SubqueryExpression) ResultAliasExpression(org.datanucleus.store.rdbms.sql.expression.ResultAliasExpression) VariableExpression(org.datanucleus.store.query.expression.VariableExpression) TypeExpression(org.datanucleus.store.query.expression.TypeExpression) NumericExpression(org.datanucleus.store.rdbms.sql.expression.NumericExpression) CollectionExpression(org.datanucleus.store.rdbms.sql.expression.CollectionExpression) DyadicExpression(org.datanucleus.store.query.expression.DyadicExpression) ColumnExpression(org.datanucleus.store.rdbms.sql.expression.ColumnExpression) JoinExpression(org.datanucleus.store.query.expression.JoinExpression) InvokeExpression(org.datanucleus.store.query.expression.InvokeExpression) TemporalLiteral(org.datanucleus.store.rdbms.sql.expression.TemporalLiteral) Literal(org.datanucleus.store.query.expression.Literal) SQLLiteral(org.datanucleus.store.rdbms.sql.expression.SQLLiteral) ParameterLiteral(org.datanucleus.store.rdbms.sql.expression.ParameterLiteral) CollectionLiteral(org.datanucleus.store.rdbms.sql.expression.CollectionLiteral) BooleanLiteral(org.datanucleus.store.rdbms.sql.expression.BooleanLiteral) IntegerLiteral(org.datanucleus.store.rdbms.sql.expression.IntegerLiteral) NullLiteral(org.datanucleus.store.rdbms.sql.expression.NullLiteral) ParameterExpression(org.datanucleus.store.query.expression.ParameterExpression) ArrayExpression(org.datanucleus.store.query.expression.ArrayExpression) NucleusException(org.datanucleus.exceptions.NucleusException)

Example 2 with PrimaryExpression

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

the class QueryToSQLMapper method compileOrdering.

/**
 * Method to compile the ordering clause of the query into the SQLStatement.
 * @param stmt SELECT statement
 */
protected void compileOrdering(SelectStatement stmt) {
    if (compilation.getExprOrdering() != null) {
        compileComponent = CompilationComponent.ORDERING;
        Expression[] orderingExpr = compilation.getExprOrdering();
        SQLExpression[] orderSqlExprs = new SQLExpression[orderingExpr.length];
        boolean[] directions = new boolean[orderingExpr.length];
        NullOrderingType[] nullOrders = new NullOrderingType[orderingExpr.length];
        for (int i = 0; i < orderingExpr.length; i++) {
            OrderExpression orderExpr = (OrderExpression) orderingExpr[i];
            Expression expr = orderExpr.getLeft();
            if (expr instanceof PrimaryExpression) {
                PrimaryExpression orderPrimExpr = (PrimaryExpression) expr;
                if (orderPrimExpr.getTuples().size() == 1 && resultAliases != null) {
                    if (resultAliases.contains(orderPrimExpr.getId().toLowerCase())) {
                        // Order by a result alias
                        orderSqlExprs[i] = new ResultAliasExpression(stmt, orderPrimExpr.getId());
                    }
                }
            }
            if (orderSqlExprs[i] == null) {
                orderSqlExprs[i] = (SQLExpression) orderExpr.getLeft().evaluate(this);
            }
            String orderDir = orderExpr.getSortOrder();
            directions[i] = ((orderDir == null || orderDir.equals("ascending")) ? false : true);
            nullOrders[i] = orderExpr.getNullOrder();
        }
        stmt.setOrdering(orderSqlExprs, directions, nullOrders);
        compileComponent = null;
    }
}
Also used : NullOrderingType(org.datanucleus.store.query.NullOrderingType) SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) PrimaryExpression(org.datanucleus.store.query.expression.PrimaryExpression) PrimaryExpression(org.datanucleus.store.query.expression.PrimaryExpression) BooleanSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.BooleanSubqueryExpression) TypeConverterExpression(org.datanucleus.store.rdbms.sql.expression.TypeConverterExpression) StringExpression(org.datanucleus.store.rdbms.sql.expression.StringExpression) NumericSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.NumericSubqueryExpression) StringSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.StringSubqueryExpression) MapExpression(org.datanucleus.store.rdbms.sql.expression.MapExpression) ArrayExpression(org.datanucleus.store.query.expression.ArrayExpression) CaseExpression(org.datanucleus.store.query.expression.CaseExpression) CreatorExpression(org.datanucleus.store.query.expression.CreatorExpression) NewObjectExpression(org.datanucleus.store.rdbms.sql.expression.NewObjectExpression) OrderExpression(org.datanucleus.store.query.expression.OrderExpression) TemporalSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.TemporalSubqueryExpression) ClassExpression(org.datanucleus.store.query.expression.ClassExpression) BooleanExpression(org.datanucleus.store.rdbms.sql.expression.BooleanExpression) Expression(org.datanucleus.store.query.expression.Expression) SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) ParameterExpression(org.datanucleus.store.query.expression.ParameterExpression) UnboundExpression(org.datanucleus.store.rdbms.sql.expression.UnboundExpression) TemporalExpression(org.datanucleus.store.rdbms.sql.expression.TemporalExpression) SubqueryExpression(org.datanucleus.store.query.expression.SubqueryExpression) ResultAliasExpression(org.datanucleus.store.rdbms.sql.expression.ResultAliasExpression) VariableExpression(org.datanucleus.store.query.expression.VariableExpression) TypeExpression(org.datanucleus.store.query.expression.TypeExpression) NumericExpression(org.datanucleus.store.rdbms.sql.expression.NumericExpression) CollectionExpression(org.datanucleus.store.rdbms.sql.expression.CollectionExpression) DyadicExpression(org.datanucleus.store.query.expression.DyadicExpression) ColumnExpression(org.datanucleus.store.rdbms.sql.expression.ColumnExpression) JoinExpression(org.datanucleus.store.query.expression.JoinExpression) InvokeExpression(org.datanucleus.store.query.expression.InvokeExpression) OrderExpression(org.datanucleus.store.query.expression.OrderExpression) ResultAliasExpression(org.datanucleus.store.rdbms.sql.expression.ResultAliasExpression)

Example 3 with PrimaryExpression

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

the class QueryToSQLMapper method compileUpdate.

/**
 * Method to compile the result clause of the query into the SQLStatement.
 * @param stmt UPDATE statement
 */
protected void compileUpdate(UpdateStatement stmt) {
    if (compilation.getExprUpdate() != null) {
        // Update statement, so generate update expression(s)
        compileComponent = CompilationComponent.UPDATE;
        Expression[] updateExprs = compilation.getExprUpdate();
        SQLExpression[] updateSqlExprs = new SQLExpression[updateExprs.length];
        // TODO If the field being set is in a different table omit it
        boolean performingUpdate = false;
        for (int i = 0; i < updateExprs.length; i++) {
            // "field = value"
            DyadicExpression updateExpr = (DyadicExpression) updateExprs[i];
            // Left-side has to be PrimaryExpression
            SQLExpression leftSqlExpr = null;
            if (updateExpr.getLeft() instanceof PrimaryExpression) {
                processPrimaryExpression((PrimaryExpression) updateExpr.getLeft());
                leftSqlExpr = stack.pop();
                if (leftSqlExpr.getSQLTable() != stmt.getPrimaryTable()) {
                    // Set left to null to signify that it is not applicable to the table of this UPDATE statement
                    leftSqlExpr = null;
                }
            } else {
                throw new NucleusException("Dont currently support update clause containing left expression of type " + updateExpr.getLeft());
            }
            if (leftSqlExpr != null) {
                if (!stmt.getDatastoreAdapter().supportsOption(DatastoreAdapter.UPDATE_STATEMENT_ALLOW_TABLE_ALIAS_IN_SET_CLAUSE)) {
                    // This datastore doesn't allow table alias in UPDATE SET clause, so just use column name
                    for (int j = 0; j < leftSqlExpr.getNumberOfSubExpressions(); j++) {
                        ColumnExpression colExpr = leftSqlExpr.getSubExpression(j);
                        colExpr.setOmitTableFromString(true);
                    }
                }
                performingUpdate = true;
                SQLExpression rightSqlExpr = null;
                if (updateExpr.getRight() instanceof Literal) {
                    processLiteral((Literal) updateExpr.getRight());
                    rightSqlExpr = stack.pop();
                } else if (updateExpr.getRight() instanceof ParameterExpression) {
                    ParameterExpression paramExpr = (ParameterExpression) updateExpr.getRight();
                    paramMappingForName.put(paramExpr.getId(), leftSqlExpr.getJavaTypeMapping());
                    processParameterExpression(paramExpr);
                    rightSqlExpr = stack.pop();
                } else if (updateExpr.getRight() instanceof PrimaryExpression) {
                    processPrimaryExpression((PrimaryExpression) updateExpr.getRight());
                    rightSqlExpr = stack.pop();
                } else if (updateExpr.getRight() instanceof DyadicExpression) {
                    updateExpr.getRight().evaluate(this);
                    rightSqlExpr = stack.pop();
                } else if (updateExpr.getRight() instanceof CaseExpression) {
                    CaseExpression caseExpr = (CaseExpression) updateExpr.getRight();
                    processCaseExpression(caseExpr, leftSqlExpr);
                    rightSqlExpr = stack.pop();
                } else if (updateExpr.getRight() instanceof VariableExpression) {
                    // Subquery?
                    processVariableExpression((VariableExpression) updateExpr.getRight());
                    rightSqlExpr = stack.pop();
                    if (rightSqlExpr instanceof UnboundExpression) {
                        // TODO Support whatever this is
                        throw new NucleusException("Found UnboundExpression in UPDATE clause!");
                    }
                } else {
                    throw new NucleusException("Dont currently support update clause containing right expression of type " + updateExpr.getRight());
                }
                if (rightSqlExpr != null) {
                    updateSqlExprs[i] = leftSqlExpr.eq(rightSqlExpr);
                }
            }
        }
        if (candidateCmd.isVersioned() && options.contains(OPTION_BULK_UPDATE_VERSION)) {
            SQLExpression updateSqlExpr = null;
            ClassTable table = (ClassTable) stmt.getPrimaryTable().getTable();
            JavaTypeMapping verMapping = table.getSurrogateMapping(SurrogateColumnType.VERSION, true);
            ClassTable verTable = table.getTableManagingMapping(verMapping);
            if (verTable == stmt.getPrimaryTable().getTable()) {
                VersionMetaData vermd = candidateCmd.getVersionMetaDataForClass();
                if (vermd.getStrategy() == VersionStrategy.VERSION_NUMBER) {
                    // Increment the version
                    SQLTable verSqlTbl = stmt.getTable(verTable, stmt.getPrimaryTable().getGroupName());
                    SQLExpression verExpr = new NumericExpression(stmt, verSqlTbl, verMapping);
                    SQLExpression incrExpr = verExpr.add(new IntegerLiteral(stmt, exprFactory.getMappingForType(Integer.class, false), Integer.valueOf(1), null));
                    updateSqlExpr = verExpr.eq(incrExpr);
                    SQLExpression[] oldArray = updateSqlExprs;
                    updateSqlExprs = new SQLExpression[oldArray.length + 1];
                    System.arraycopy(oldArray, 0, updateSqlExprs, 0, oldArray.length);
                    updateSqlExprs[oldArray.length] = updateSqlExpr;
                    performingUpdate = true;
                } else if (vermd.getStrategy() == VersionStrategy.DATE_TIME) {
                    // Set version to the time of update
                    SQLTable verSqlTbl = stmt.getTable(verTable, stmt.getPrimaryTable().getGroupName());
                    SQLExpression verExpr = new NumericExpression(stmt, verSqlTbl, verMapping);
                    Object newVersion = ec.getLockManager().getNextVersion(vermd, null);
                    JavaTypeMapping valMapping = exprFactory.getMappingForType(newVersion.getClass(), false);
                    SQLExpression valExpr = new TemporalLiteral(stmt, valMapping, newVersion, null);
                    updateSqlExpr = verExpr.eq(valExpr);
                    SQLExpression[] oldArray = updateSqlExprs;
                    updateSqlExprs = new SQLExpression[oldArray.length + 1];
                    System.arraycopy(oldArray, 0, updateSqlExprs, 0, oldArray.length);
                    updateSqlExprs[oldArray.length] = updateSqlExpr;
                    performingUpdate = true;
                }
            }
        }
        if (performingUpdate) {
            // Only set the updates component of the SQLStatement if anything to update in this table
            stmt.setUpdates(updateSqlExprs);
        }
    }
    compileComponent = null;
}
Also used : SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) PrimaryExpression(org.datanucleus.store.query.expression.PrimaryExpression) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) VersionMetaData(org.datanucleus.metadata.VersionMetaData) NumericExpression(org.datanucleus.store.rdbms.sql.expression.NumericExpression) TemporalLiteral(org.datanucleus.store.rdbms.sql.expression.TemporalLiteral) VariableExpression(org.datanucleus.store.query.expression.VariableExpression) UnboundExpression(org.datanucleus.store.rdbms.sql.expression.UnboundExpression) DyadicExpression(org.datanucleus.store.query.expression.DyadicExpression) CaseExpression(org.datanucleus.store.query.expression.CaseExpression) PrimaryExpression(org.datanucleus.store.query.expression.PrimaryExpression) BooleanSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.BooleanSubqueryExpression) TypeConverterExpression(org.datanucleus.store.rdbms.sql.expression.TypeConverterExpression) StringExpression(org.datanucleus.store.rdbms.sql.expression.StringExpression) NumericSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.NumericSubqueryExpression) StringSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.StringSubqueryExpression) MapExpression(org.datanucleus.store.rdbms.sql.expression.MapExpression) ArrayExpression(org.datanucleus.store.query.expression.ArrayExpression) CaseExpression(org.datanucleus.store.query.expression.CaseExpression) CreatorExpression(org.datanucleus.store.query.expression.CreatorExpression) NewObjectExpression(org.datanucleus.store.rdbms.sql.expression.NewObjectExpression) OrderExpression(org.datanucleus.store.query.expression.OrderExpression) TemporalSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.TemporalSubqueryExpression) ClassExpression(org.datanucleus.store.query.expression.ClassExpression) BooleanExpression(org.datanucleus.store.rdbms.sql.expression.BooleanExpression) Expression(org.datanucleus.store.query.expression.Expression) SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) ParameterExpression(org.datanucleus.store.query.expression.ParameterExpression) UnboundExpression(org.datanucleus.store.rdbms.sql.expression.UnboundExpression) TemporalExpression(org.datanucleus.store.rdbms.sql.expression.TemporalExpression) SubqueryExpression(org.datanucleus.store.query.expression.SubqueryExpression) ResultAliasExpression(org.datanucleus.store.rdbms.sql.expression.ResultAliasExpression) VariableExpression(org.datanucleus.store.query.expression.VariableExpression) TypeExpression(org.datanucleus.store.query.expression.TypeExpression) NumericExpression(org.datanucleus.store.rdbms.sql.expression.NumericExpression) CollectionExpression(org.datanucleus.store.rdbms.sql.expression.CollectionExpression) DyadicExpression(org.datanucleus.store.query.expression.DyadicExpression) ColumnExpression(org.datanucleus.store.rdbms.sql.expression.ColumnExpression) JoinExpression(org.datanucleus.store.query.expression.JoinExpression) InvokeExpression(org.datanucleus.store.query.expression.InvokeExpression) ColumnExpression(org.datanucleus.store.rdbms.sql.expression.ColumnExpression) ClassTable(org.datanucleus.store.rdbms.table.ClassTable) TemporalLiteral(org.datanucleus.store.rdbms.sql.expression.TemporalLiteral) Literal(org.datanucleus.store.query.expression.Literal) SQLLiteral(org.datanucleus.store.rdbms.sql.expression.SQLLiteral) ParameterLiteral(org.datanucleus.store.rdbms.sql.expression.ParameterLiteral) CollectionLiteral(org.datanucleus.store.rdbms.sql.expression.CollectionLiteral) BooleanLiteral(org.datanucleus.store.rdbms.sql.expression.BooleanLiteral) IntegerLiteral(org.datanucleus.store.rdbms.sql.expression.IntegerLiteral) NullLiteral(org.datanucleus.store.rdbms.sql.expression.NullLiteral) ParameterExpression(org.datanucleus.store.query.expression.ParameterExpression) SQLTable(org.datanucleus.store.rdbms.sql.SQLTable) NucleusException(org.datanucleus.exceptions.NucleusException) IntegerLiteral(org.datanucleus.store.rdbms.sql.expression.IntegerLiteral)

Example 4 with PrimaryExpression

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

the class QueryToSQLMapper method processPrimaryExpression.

/* (non-Javadoc)
     * @see org.datanucleus.query.evaluator.AbstractExpressionEvaluator#processPrimaryExpression(org.datanucleus.query.expression.PrimaryExpression)
     */
protected Object processPrimaryExpression(PrimaryExpression expr) {
    SQLExpression sqlExpr = null;
    if (expr.getLeft() != null) {
        if (expr.getLeft() instanceof DyadicExpression && expr.getLeft().getOperator() == Expression.OP_CAST) {
            String exprCastName = null;
            if (expr.getLeft().getLeft() instanceof PrimaryExpression) {
                exprCastName = "CAST_" + ((PrimaryExpression) expr.getLeft().getLeft()).getId();
            } else if (expr.getLeft().getLeft() instanceof VariableExpression) {
                exprCastName = "CAST_" + ((VariableExpression) expr.getLeft().getLeft()).getId();
            } else if (expr.getLeft().getLeft() instanceof InvokeExpression) {
                exprCastName = "CAST_" + expr.getLeft().getLeft();
            } else {
                throw new NucleusException("Don't currently support cast of " + expr.getLeft().getLeft());
            }
            expr.getLeft().getLeft().evaluate(this);
            sqlExpr = stack.pop();
            JavaTypeMapping mapping = sqlExpr.getJavaTypeMapping();
            if (mapping instanceof EmbeddedMapping) {
                // Cast of an embedded field, so use same table
                // Extract what we are casting it to
                Literal castLitExpr = (Literal) expr.getLeft().getRight();
                Class castType = resolveClass((String) castLitExpr.getLiteral());
                AbstractClassMetaData castCmd = ec.getMetaDataManager().getMetaDataForClass(castType, clr);
                JavaTypeMapping discMapping = ((EmbeddedMapping) mapping).getDiscriminatorMapping();
                if (discMapping != null) {
                    // Should have a discriminator always when casting this
                    SQLExpression discExpr = exprFactory.newExpression(stmt, sqlExpr.getSQLTable(), discMapping);
                    Object discVal = castCmd.getDiscriminatorValue();
                    SQLExpression discValExpr = exprFactory.newLiteral(stmt, discMapping, discVal);
                    BooleanExpression discRestrictExpr = discExpr.eq(discValExpr);
                    Iterator<String> subclassIter = storeMgr.getSubClassesForClass(castType.getName(), true, clr).iterator();
                    while (subclassIter.hasNext()) {
                        String subclassName = subclassIter.next();
                        AbstractClassMetaData subtypeCmd = storeMgr.getMetaDataManager().getMetaDataForClass(subclassName, clr);
                        discVal = subtypeCmd.getDiscriminatorValue();
                        discValExpr = exprFactory.newLiteral(stmt, discMapping, discVal);
                        BooleanExpression subtypeExpr = discExpr.eq(discValExpr);
                        discRestrictExpr = discRestrictExpr.ior(subtypeExpr);
                    }
                    stmt.whereAnd(discRestrictExpr, true);
                }
                SQLTableMapping tblMapping = new SQLTableMapping(sqlExpr.getSQLTable(), castCmd, sqlExpr.getJavaTypeMapping());
                setSQLTableMappingForAlias(exprCastName, tblMapping);
                SQLTableMapping sqlMapping = getSQLTableMappingForPrimaryExpression(stmt, exprCastName, expr, Boolean.FALSE);
                if (sqlMapping == null) {
                    throw new NucleusException("PrimaryExpression " + expr + " is not yet supported");
                }
                sqlExpr = exprFactory.newExpression(stmt, sqlMapping.table, sqlMapping.mapping);
                stack.push(sqlExpr);
                return sqlExpr;
            }
            // Evaluate the cast
            expr.getLeft().evaluate(this);
            sqlExpr = stack.pop();
            // Extract what we are casting it to
            Literal castLitExpr = (Literal) expr.getLeft().getRight();
            AbstractClassMetaData castCmd = ec.getMetaDataManager().getMetaDataForClass(resolveClass((String) castLitExpr.getLiteral()), clr);
            SQLTableMapping tblMapping = new SQLTableMapping(sqlExpr.getSQLTable(), castCmd, sqlExpr.getJavaTypeMapping());
            setSQLTableMappingForAlias(exprCastName, tblMapping);
            SQLTableMapping sqlMapping = getSQLTableMappingForPrimaryExpression(stmt, exprCastName, expr, Boolean.FALSE);
            if (sqlMapping == null) {
                throw new NucleusException("PrimaryExpression " + expr + " is not yet supported");
            }
            sqlExpr = exprFactory.newExpression(stmt, sqlMapping.table, sqlMapping.mapping);
            stack.push(sqlExpr);
            return sqlExpr;
        } else if (expr.getLeft() instanceof ParameterExpression) {
            // "{paramExpr}.field[.field[.field]]"
            // Need parameter values to process this
            setNotPrecompilable();
            ParameterExpression paramExpr = (ParameterExpression) expr.getLeft();
            Symbol paramSym = compilation.getSymbolTable().getSymbol(paramExpr.getId());
            if (paramSym.getValueType() != null && paramSym.getValueType().isArray()) {
                // Special case : array "methods" (particularly "length")
                String first = expr.getTuples().get(0);
                processParameterExpression(paramExpr, true);
                SQLExpression paramSqlExpr = stack.pop();
                sqlExpr = exprFactory.invokeMethod(stmt, "ARRAY", first, paramSqlExpr, null);
                stack.push(sqlExpr);
                return sqlExpr;
            }
            // Create Literal for the parameter (since we need to perform operations on it)
            processParameterExpression(paramExpr, true);
            SQLExpression paramSqlExpr = stack.pop();
            SQLLiteral lit = (SQLLiteral) paramSqlExpr;
            Object paramValue = lit.getValue();
            List<String> tuples = expr.getTuples();
            Iterator<String> tuplesIter = tuples.iterator();
            Object objValue = paramValue;
            while (tuplesIter.hasNext()) {
                String fieldName = tuplesIter.next();
                if (objValue == null) {
                    NucleusLogger.QUERY.warn(">> Compilation of " + expr + " : need to direct through field \"" + fieldName + "\" on null value, hence not compilable!");
                    // Null value, and we have further path to navigate TODO Handle this "NPE"
                    break;
                }
                objValue = getValueForObjectField(objValue, fieldName);
                // Using literal value of parameter, so cannot precompile it
                setNotPrecompilable();
            }
            if (objValue == null) {
                sqlExpr = exprFactory.newLiteral(stmt, null, null);
                stack.push(sqlExpr);
                return sqlExpr;
            }
            JavaTypeMapping m = exprFactory.getMappingForType(objValue.getClass(), false);
            sqlExpr = exprFactory.newLiteral(stmt, m, objValue);
            stack.push(sqlExpr);
            return sqlExpr;
        } else if (expr.getLeft() instanceof VariableExpression) {
            // "{varExpr}.field[.field[.field]]"
            VariableExpression varExpr = (VariableExpression) expr.getLeft();
            processVariableExpression(varExpr);
            SQLExpression varSqlExpr = stack.pop();
            if (varSqlExpr instanceof UnboundExpression) {
                // Bind as CROSS JOIN for now
                processUnboundExpression((UnboundExpression) varSqlExpr);
                varSqlExpr = stack.pop();
            }
            Class varType = clr.classForName(varSqlExpr.getJavaTypeMapping().getType());
            if (varSqlExpr.getSQLStatement() == stmt.getParentStatement()) {
                // Use parent mapper to get the mapping for this field since it has the table
                SQLTableMapping sqlMapping = parentMapper.getSQLTableMappingForPrimaryExpression(stmt, null, expr, Boolean.FALSE);
                if (sqlMapping == null) {
                    throw new NucleusException("PrimaryExpression " + expr.getId() + " is not yet supported");
                }
                // TODO Cater for the table required to join to not being the primary table of the outer query
                // This should check on
                // getDatastoreAdapter().supportsOption(RDBMSAdapter.ACCESS_PARENTQUERY_IN_SUBQUERY))
                sqlExpr = exprFactory.newExpression(varSqlExpr.getSQLStatement(), sqlMapping.table, sqlMapping.mapping);
                stack.push(sqlExpr);
                return sqlExpr;
            }
            SQLTableMapping varTblMapping = getSQLTableMappingForAlias(varExpr.getId());
            if (varTblMapping == null) {
                throw new NucleusUserException("Variable " + varExpr.getId() + " is not yet bound, so cannot get field " + expr.getId());
            }
            if (varTblMapping.cmd == null) {
                throw new NucleusUserException("Variable " + varExpr.getId() + " of type " + varType.getName() + " cannot evaluate " + expr.getId());
            }
            SQLTableMapping sqlMapping = getSQLTableMappingForPrimaryExpression(varSqlExpr.getSQLStatement(), varExpr.getId(), expr, Boolean.FALSE);
            sqlExpr = exprFactory.newExpression(sqlMapping.table.getSQLStatement(), sqlMapping.table, sqlMapping.mapping);
            stack.push(sqlExpr);
            return sqlExpr;
        } else if (expr.getLeft() instanceof InvokeExpression) {
            InvokeExpression invokeExpr = (InvokeExpression) expr.getLeft();
            SQLExpression invokedSqlExpr = getInvokedSqlExpressionForInvokeExpression(invokeExpr);
            processInvokeExpression(invokeExpr, invokedSqlExpr);
            SQLExpression invokeSqlExpr = stack.pop();
            Table tbl = invokeSqlExpr.getSQLTable().getTable();
            if (expr.getTuples().size() > 1) {
                throw new NucleusUserException("Dont currently support evaluating " + expr.getId() + " on " + invokeSqlExpr);
            }
            SQLTable invokeSqlTbl = invokeSqlExpr.getSQLTable();
            if (invokedSqlExpr.getJavaTypeMapping() instanceof OptionalMapping && invokeExpr.getOperation().equals("get") && expr.getTuples().size() == 1) {
                OptionalMapping opMapping = (OptionalMapping) invokedSqlExpr.getJavaTypeMapping();
                if (opMapping.getWrappedMapping() instanceof PersistableMapping) {
                    // Special case of Optional.get().{field}, so we need to join to the related table
                    AbstractMemberMetaData mmd = invokedSqlExpr.getJavaTypeMapping().getMemberMetaData();
                    AbstractClassMetaData otherCmd = ec.getMetaDataManager().getMetaDataForClass(mmd.getCollection().getElementType(), clr);
                    Table otherTbl = storeMgr.getDatastoreClass(otherCmd.getFullClassName(), clr);
                    // Optional type so do LEFT OUTER JOIN since if it is null then we would eliminate all other results
                    invokeSqlTbl = stmt.join(JoinType.LEFT_OUTER_JOIN, invokeSqlExpr.getSQLTable(), opMapping.getWrappedMapping(), otherTbl, null, otherTbl.getIdMapping(), null, null, true);
                    tbl = invokeSqlTbl.getTable();
                }
            }
            if (tbl instanceof DatastoreClass) {
                // Table of a class, so assume to have field in the table of the class
                // TODO Allow joins to superclasses if required
                JavaTypeMapping mapping = ((DatastoreClass) tbl).getMemberMapping(expr.getId());
                if (mapping == null) {
                    throw new NucleusUserException("Dont currently support evaluating " + expr.getId() + " on " + invokeSqlExpr + ". The field " + expr.getId() + " doesnt exist in table " + tbl);
                }
                sqlExpr = exprFactory.newExpression(stmt, invokeSqlTbl, mapping);
                stack.push(sqlExpr);
                return sqlExpr;
            } else if (tbl instanceof JoinTable) {
                if (invokeSqlExpr.getJavaTypeMapping() instanceof EmbeddedMapping) {
                    // Table containing an embedded element/key/value so assume we have a column in the join table
                    EmbeddedMapping embMapping = (EmbeddedMapping) invokeSqlExpr.getJavaTypeMapping();
                    JavaTypeMapping mapping = embMapping.getJavaTypeMapping(expr.getId());
                    if (mapping == null) {
                        throw new NucleusUserException("Dont currently support evaluating " + expr.getId() + " on " + invokeSqlExpr + ". The field " + expr.getId() + " doesnt exist in table " + tbl);
                    }
                    sqlExpr = exprFactory.newExpression(stmt, invokeSqlTbl, mapping);
                    stack.push(sqlExpr);
                    return sqlExpr;
                }
            }
            throw new NucleusUserException("Dont currently support evaluating " + expr.getId() + " on " + invokeSqlExpr + " with invoke having table of " + tbl);
        } else {
            throw new NucleusUserException("Dont currently support PrimaryExpression with 'left' of " + expr.getLeft());
        }
    }
    // Real primary expression ("field.field", "alias.field.field" etc)
    SQLTableMapping sqlMapping = getSQLTableMappingForPrimaryExpression(stmt, null, expr, null);
    if (sqlMapping == null) {
        throw new NucleusException("PrimaryExpression " + expr.getId() + " is not yet supported");
    }
    sqlExpr = exprFactory.newExpression(stmt, sqlMapping.table, sqlMapping.mapping);
    if (sqlMapping.mmd != null && sqlExpr instanceof MapExpression) {
        // This sqlMapping is for something joined in a FROM clause, so set the alias on the returned MapExpression to avoid doing the same joins
        String alias = getAliasForSQLTableMapping(sqlMapping);
        if (alias == null && parentMapper != null) {
            alias = parentMapper.getAliasForSQLTableMapping(sqlMapping);
        }
        ((MapExpression) sqlExpr).setAliasForMapTable(alias);
    }
    stack.push(sqlExpr);
    return sqlExpr;
}
Also used : SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) PrimaryExpression(org.datanucleus.store.query.expression.PrimaryExpression) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) Symbol(org.datanucleus.store.query.compiler.Symbol) SQLLiteral(org.datanucleus.store.rdbms.sql.expression.SQLLiteral) UnboundExpression(org.datanucleus.store.rdbms.sql.expression.UnboundExpression) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) BooleanExpression(org.datanucleus.store.rdbms.sql.expression.BooleanExpression) TemporalLiteral(org.datanucleus.store.rdbms.sql.expression.TemporalLiteral) Literal(org.datanucleus.store.query.expression.Literal) SQLLiteral(org.datanucleus.store.rdbms.sql.expression.SQLLiteral) ParameterLiteral(org.datanucleus.store.rdbms.sql.expression.ParameterLiteral) CollectionLiteral(org.datanucleus.store.rdbms.sql.expression.CollectionLiteral) BooleanLiteral(org.datanucleus.store.rdbms.sql.expression.BooleanLiteral) IntegerLiteral(org.datanucleus.store.rdbms.sql.expression.IntegerLiteral) NullLiteral(org.datanucleus.store.rdbms.sql.expression.NullLiteral) SQLTable(org.datanucleus.store.rdbms.sql.SQLTable) ListIterator(java.util.ListIterator) Iterator(java.util.Iterator) ArrayList(java.util.ArrayList) List(java.util.List) MapExpression(org.datanucleus.store.rdbms.sql.expression.MapExpression) InvokeExpression(org.datanucleus.store.query.expression.InvokeExpression) Table(org.datanucleus.store.rdbms.table.Table) JoinTable(org.datanucleus.store.rdbms.table.JoinTable) ClassTable(org.datanucleus.store.rdbms.table.ClassTable) ElementContainerTable(org.datanucleus.store.rdbms.table.ElementContainerTable) MapTable(org.datanucleus.store.rdbms.table.MapTable) SQLTable(org.datanucleus.store.rdbms.sql.SQLTable) ArrayTable(org.datanucleus.store.rdbms.table.ArrayTable) CollectionTable(org.datanucleus.store.rdbms.table.CollectionTable) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) VariableExpression(org.datanucleus.store.query.expression.VariableExpression) DyadicExpression(org.datanucleus.store.query.expression.DyadicExpression) OptionalMapping(org.datanucleus.store.rdbms.mapping.java.OptionalMapping) PersistableMapping(org.datanucleus.store.rdbms.mapping.java.PersistableMapping) EmbeddedMapping(org.datanucleus.store.rdbms.mapping.java.EmbeddedMapping) ParameterExpression(org.datanucleus.store.query.expression.ParameterExpression) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) FetchPlanForClass(org.datanucleus.FetchPlanForClass) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) NucleusException(org.datanucleus.exceptions.NucleusException) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData) JoinTable(org.datanucleus.store.rdbms.table.JoinTable)

Example 5 with PrimaryExpression

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

the class QueryToSQLMapper method compileFromClassExpression.

/**
 * Method to take a ClassExpression (in a FROM clause) and process the candidate and any
 * linked JoinExpression(s), adding joins to the SQLStatement as required.
 * @param clsExpr The ClassExpression
 */
protected void compileFromClassExpression(ClassExpression clsExpr) {
    Symbol clsExprSym = clsExpr.getSymbol();
    Class baseCls = (clsExprSym != null ? clsExprSym.getValueType() : null);
    SQLTable candSqlTbl = stmt.getPrimaryTable();
    MetaDataManager mmgr = storeMgr.getMetaDataManager();
    AbstractClassMetaData cmd = mmgr.getMetaDataForClass(baseCls, clr);
    if (baseCls != null && !candidateAlias.equals(clsExpr.getAlias())) {
        // Not candidate class so must be cross join (JPA spec 4.4.5)
        DatastoreClass candTbl = storeMgr.getDatastoreClass(baseCls.getName(), clr);
        candSqlTbl = stmt.join(JoinType.CROSS_JOIN, null, null, null, candTbl, clsExpr.getAlias(), null, null, null, null, true, null);
        SQLTableMapping tblMapping = new SQLTableMapping(candSqlTbl, cmd, candTbl.getIdMapping());
        setSQLTableMappingForAlias(clsExpr.getAlias(), tblMapping);
    }
    if (clsExpr.getCandidateExpression() != null && parentMapper != null) {
        // User defined the candidate of the subquery as an implied join to the outer query
        // e.g SELECT c FROM Customer c WHERE EXISTS (SELECT o FROM c.orders o ...)
        // so add the join(s) to the outer query
        processFromClauseSubquery(clsExpr, candSqlTbl, mmgr);
    }
    // Process all linked JoinExpression(s) for this ClassExpression
    Expression rightExpr = clsExpr.getRight();
    SQLTable sqlTbl = candSqlTbl;
    JavaTypeMapping previousMapping = null;
    while (rightExpr != null) {
        if (rightExpr instanceof JoinExpression) {
            JoinExpression joinExpr = (JoinExpression) rightExpr;
            JoinExpression.JoinType exprJoinType = joinExpr.getType();
            JoinType joinType = org.datanucleus.store.rdbms.sql.SQLJoin.getJoinTypeForJoinExpressionType(exprJoinType);
            Expression joinedExpr = joinExpr.getJoinedExpression();
            Expression joinOnExpr = joinExpr.getOnExpression();
            String joinAlias = joinExpr.getAlias();
            PrimaryExpression joinPrimExpr = null;
            Class castCls = null;
            if (joinedExpr instanceof PrimaryExpression) {
                joinPrimExpr = (PrimaryExpression) joinedExpr;
            } else if (joinedExpr instanceof DyadicExpression && joinedExpr.getOperator() == Expression.OP_CAST) {
                // TREAT this join as a particular type. Cast type is processed below where we add the joins
                joinPrimExpr = (PrimaryExpression) joinedExpr.getLeft();
                String castClassName = (String) ((Literal) joinedExpr.getRight()).getLiteral();
                castCls = clr.classForName(castClassName);
            } else {
                throw new NucleusException("We do not currently support JOIN to " + joinedExpr);
            }
            Iterator<String> iter = joinPrimExpr.getTuples().iterator();
            String rootId = iter.next();
            if (joinPrimExpr.getTuples().size() == 1 && !rootId.endsWith("#KEY") && !rootId.endsWith("#VALUE")) {
                // DN Extension : Join to (new) root element? We need an ON expression to be supplied in this case
                if (joinOnExpr == null) {
                    throw new NucleusUserException("Query has join to " + joinPrimExpr.getId() + " yet this is a root component and there is no ON expression");
                }
                // Add the basic join first with no condition since this root will be referenced in the "on" condition
                baseCls = resolveClass(joinPrimExpr.getId());
                DatastoreClass baseTbl = storeMgr.getDatastoreClass(baseCls.getName(), clr);
                sqlTbl = stmt.join(joinType, candSqlTbl, baseTbl, joinAlias, null, null, true);
                cmd = mmgr.getMetaDataForClass(baseCls, clr);
                SQLTableMapping tblMapping = new SQLTableMapping(sqlTbl, cmd, baseTbl.getIdMapping());
                setSQLTableMappingForAlias(joinAlias, tblMapping);
                // Convert the ON expression to a BooleanExpression and add to the join
                processingOnClause = true;
                joinOnExpr.evaluate(this);
                BooleanExpression joinOnSqlExpr = (BooleanExpression) stack.pop();
                processingOnClause = false;
                stmt.addAndConditionToJoinForTable(sqlTbl, joinOnSqlExpr, true);
                // Move on to next join in the chain
                rightExpr = rightExpr.getRight();
                continue;
            }
            String joinTableGroupName = null;
            SQLTable tblMappingSqlTbl = null;
            JavaTypeMapping tblIdMapping = null;
            AbstractMemberMetaData tblMmd = null;
            boolean mapKey = false;
            boolean mapValue = false;
            String rootComponent = rootId;
            if (rootComponent.endsWith("#KEY")) {
                mapKey = true;
                rootComponent = rootComponent.substring(0, rootComponent.length() - 4);
            } else if (rootComponent.endsWith("#VALUE")) {
                mapValue = true;
                rootComponent = rootComponent.substring(0, rootComponent.length() - 6);
            }
            if (rootComponent.equalsIgnoreCase(candidateAlias)) {
                // Join relative to the candidate
                // Name table group of joined-to as per the relation
                // Note : this will only work for one level out from the candidate TODO Extend this
                cmd = candidateCmd;
                joinTableGroupName = joinPrimExpr.getId();
                sqlTbl = candSqlTbl;
            } else {
                // Join relative to some other alias
                SQLTableMapping sqlTblMapping = getSQLTableMappingForAlias(rootComponent);
                if (sqlTblMapping != null) {
                    if (sqlTblMapping.mmd != null && (mapKey || mapValue)) {
                        // First component is Map-related (i.e m#KEY, m#VALUE), so add any necessary join(s)
                        MapMetaData mapmd = sqlTblMapping.mmd.getMap();
                        cmd = mapKey ? mapmd.getKeyClassMetaData(clr) : mapmd.getValueClassMetaData(clr);
                        // Find the table forming the Map. This may be a join table, or the key or value depending on the type
                        // TODO Use OPTION_CASE_INSENSITIVE
                        sqlTbl = stmt.getTable(rootComponent + "_MAP");
                        if (sqlTbl == null) {
                            sqlTbl = stmt.getTable((rootComponent + "_MAP").toUpperCase());
                            if (sqlTbl == null) {
                                sqlTbl = stmt.getTable((rootComponent + "_MAP").toLowerCase());
                            }
                        }
                        String aliasForJoin = (iter.hasNext()) ? null : joinAlias;
                        boolean embedded = mapKey ? (mapmd.isEmbeddedKey() || mapmd.isSerializedKey()) : (mapmd.isEmbeddedValue() || mapmd.isSerializedValue());
                        if (mapmd.getMapType() == MapType.MAP_TYPE_JOIN) {
                            // Join from join table to KEY/VALUE as required
                            if (!embedded) {
                                if (mapKey) {
                                    DatastoreClass keyTable = storeMgr.getDatastoreClass(mapmd.getKeyType(), clr);
                                    sqlTbl = stmt.join(joinType, sqlTbl, ((MapTable) sqlTbl.getTable()).getKeyMapping(), keyTable, aliasForJoin, keyTable.getIdMapping(), null, joinTableGroupName, true);
                                } else {
                                    DatastoreClass valueTable = storeMgr.getDatastoreClass(mapmd.getValueType(), clr);
                                    sqlTbl = stmt.join(joinType, sqlTbl, ((MapTable) sqlTbl.getTable()).getValueMapping(), valueTable, aliasForJoin, valueTable.getIdMapping(), null, joinTableGroupName, true);
                                }
                                tblMappingSqlTbl = sqlTbl;
                                tblIdMapping = tblMappingSqlTbl.getTable().getIdMapping();
                            }
                        } else if (mapmd.getMapType() == MapType.MAP_TYPE_KEY_IN_VALUE) {
                        // TODO Cater for this type
                        } else if (mapmd.getMapType() == MapType.MAP_TYPE_VALUE_IN_KEY) {
                        // TODO Cater for this type
                        }
                    } else {
                        cmd = sqlTblMapping.cmd;
                        sqlTbl = sqlTblMapping.table;
                    }
                    joinTableGroupName = sqlTbl.getGroupName() + joinPrimExpr.getId().substring(rootComponent.length());
                } else {
                    throw new NucleusUserException("Query has " + joinPrimExpr.getId() + " yet the first component " + rootComponent + " is unknown!");
                }
            }
            while (iter.hasNext()) {
                String id = iter.next();
                String[] ids = id.contains(".") ? StringUtils.split(id, ".") : new String[] { id };
                for (int k = 0; k < ids.length; k++) {
                    if (cmd == null) {
                        throw new NucleusUserException("Error in JOIN clause. id=" + id + " but component prior to " + ids[k] + " has no metadata");
                    }
                    boolean lastComponent = (k == ids.length - 1);
                    String thisComponent = ids[k];
                    mapKey = false;
                    mapValue = false;
                    if (thisComponent.endsWith("#KEY")) {
                        thisComponent = thisComponent.substring(0, thisComponent.length() - 4);
                        mapKey = true;
                    } else if (thisComponent.endsWith("#VALUE")) {
                        thisComponent = thisComponent.substring(0, thisComponent.length() - 6);
                        mapValue = true;
                    }
                    AbstractMemberMetaData mmd = cmd.getMetaDataForMember(thisComponent);
                    if (mmd == null) {
                        if (exprJoinType == JoinExpression.JoinType.JOIN_LEFT_OUTER || exprJoinType == JoinExpression.JoinType.JOIN_LEFT_OUTER_FETCH) {
                            // Polymorphic join, where the field exists in a subclass (doable since we have outer join)
                            String[] subclasses = mmgr.getSubclassesForClass(cmd.getFullClassName(), true);
                            for (int l = 0; l < subclasses.length; l++) {
                                AbstractClassMetaData subCmd = mmgr.getMetaDataForClass(subclasses[l], clr);
                                if (subCmd != null) {
                                    mmd = subCmd.getMetaDataForMember(thisComponent);
                                    if (mmd != null) {
                                        cmd = subCmd;
                                        break;
                                    }
                                }
                            }
                        }
                        if (mmd == null) {
                            throw new NucleusUserException("Query has " + joinPrimExpr.getId() + " yet " + thisComponent + " is not found. Fix your input");
                        }
                    }
                    tblMmd = null;
                    String aliasForJoin = null;
                    if (k == (ids.length - 1) && !iter.hasNext()) {
                        aliasForJoin = joinAlias;
                    }
                    RelationType relationType = mmd.getRelationType(clr);
                    DatastoreClass relTable = null;
                    AbstractMemberMetaData relMmd = null;
                    if (relationType != RelationType.NONE) {
                        if (JoinExpression.JoinType.isFetch(exprJoinType)) {
                            // Add field to FetchPlan since marked for FETCH
                            String fgName = "QUERY_FETCH_" + mmd.getFullFieldName();
                            FetchGroupManager fetchGrpMgr = storeMgr.getNucleusContext().getFetchGroupManager();
                            if (fetchGrpMgr.getFetchGroupsWithName(fgName) == null) {
                                FetchGroup grp = new FetchGroup(storeMgr.getNucleusContext(), fgName, clr.classForName(cmd.getFullClassName()));
                                grp.addMember(mmd.getName());
                                fetchGrpMgr.addFetchGroup(grp);
                            }
                            fetchPlan.addGroup(fgName);
                        }
                    }
                    if (relationType == RelationType.ONE_TO_ONE_UNI) {
                        JavaTypeMapping otherMapping = null;
                        Object[] castDiscrimValues = null;
                        if (castCls != null && lastComponent) {
                            cmd = mmgr.getMetaDataForClass(castCls, clr);
                            if (cmd.hasDiscriminatorStrategy()) {
                                // Restrict discriminator on cast type to be the type+subclasses
                                castDiscrimValues = getDiscriminatorValuesForCastClass(cmd);
                            }
                        } else {
                            cmd = mmgr.getMetaDataForClass(mmd.getType(), clr);
                        }
                        if (mmd.isEmbedded()) {
                            // Embedded into the same table as before, so no join needed
                            otherMapping = sqlTbl.getTable().getMemberMapping(mmd);
                        } else {
                            if (sqlTbl.getTable() instanceof CollectionTable) {
                                // Currently in a join table, so work from the element and this being an embedded member
                                CollectionTable collTbl = (CollectionTable) sqlTbl.getTable();
                                JavaTypeMapping elemMapping = collTbl.getElementMapping();
                                if (elemMapping instanceof EmbeddedMapping) {
                                    otherMapping = ((EmbeddedMapping) elemMapping).getJavaTypeMapping(mmd.getName());
                                }
                            } else {
                                otherMapping = sqlTbl.getTable().getMemberMapping(mmd);
                            }
                            relTable = storeMgr.getDatastoreClass(mmd.getTypeName(), clr);
                            if (otherMapping == null && previousMapping != null) {
                                if (previousMapping instanceof EmbeddedMapping) {
                                    // Part of an embedded 1-1 object, so find the relevant member mapping
                                    EmbeddedMapping embMapping = (EmbeddedMapping) previousMapping;
                                    otherMapping = embMapping.getJavaTypeMapping(mmd.getName());
                                }
                            }
                            if (otherMapping == null) {
                                // Polymorphic join? : cannot find this member in the candidate of the main statement, so need to pick which UNION
                                String tblGroupName = sqlTbl.getGroupName();
                                SQLTableGroup grp = stmt.getTableGroup(tblGroupName);
                                SQLTable nextSqlTbl = null;
                                // Try to find subtable in the same group that has a mapping for this member (and join from that)
                                SQLTable[] grpTbls = grp.getTables();
                                for (SQLTable grpTbl : grpTbls) {
                                    if (grpTbl.getTable().getMemberMapping(mmd) != null) {
                                        otherMapping = grpTbl.getTable().getMemberMapping(mmd);
                                        break;
                                    }
                                }
                                SQLTable newSqlTbl = stmt.join(joinType, sqlTbl, otherMapping, relTable, aliasForJoin, relTable.getIdMapping(), null, joinTableGroupName, false);
                                if (newSqlTbl != null) {
                                    nextSqlTbl = newSqlTbl;
                                }
                                if (stmt instanceof SelectStatement) {
                                    List<SelectStatement> unionStmts = ((SelectStatement) stmt).getUnions();
                                    if (unionStmts != null) {
                                        for (SQLStatement unionStmt : unionStmts) {
                                            // Repeat the process for any unioned statements, find a subtable in the same group (and join from that)
                                            otherMapping = null;
                                            grp = unionStmt.getTableGroup(tblGroupName);
                                            SQLTable[] unionGrpTbls = grp.getTables();
                                            for (SQLTable grpTbl : unionGrpTbls) {
                                                if (grpTbl.getTable().getMemberMapping(mmd) != null) {
                                                    otherMapping = grpTbl.getTable().getMemberMapping(mmd);
                                                    break;
                                                }
                                            }
                                            newSqlTbl = unionStmt.join(joinType, sqlTbl, otherMapping, relTable, aliasForJoin, relTable.getIdMapping(), castDiscrimValues, joinTableGroupName, false);
                                            if (newSqlTbl != null) {
                                                nextSqlTbl = newSqlTbl;
                                            }
                                        }
                                    }
                                }
                                sqlTbl = nextSqlTbl;
                            } else {
                                sqlTbl = stmt.join(joinType, sqlTbl, otherMapping, relTable, aliasForJoin, relTable.getIdMapping(), castDiscrimValues, joinTableGroupName, true);
                            }
                        }
                        previousMapping = otherMapping;
                        tblIdMapping = sqlTbl.getTable().getIdMapping();
                        tblMappingSqlTbl = sqlTbl;
                    } else if (relationType == RelationType.ONE_TO_ONE_BI) {
                        JavaTypeMapping otherMapping = null;
                        Object[] castDiscrimValues = null;
                        if (castCls != null && lastComponent) {
                            cmd = mmgr.getMetaDataForClass(castCls, clr);
                            if (cmd.hasDiscriminatorStrategy()) {
                                // Restrict discriminator on cast type to be the type+subclasses
                                castDiscrimValues = getDiscriminatorValuesForCastClass(cmd);
                            }
                        } else {
                            cmd = mmgr.getMetaDataForClass(mmd.getType(), clr);
                        }
                        if (mmd.isEmbedded()) {
                            // Embedded into the same table as before, so no join needed
                            otherMapping = sqlTbl.getTable().getMemberMapping(mmd);
                        } else {
                            relTable = storeMgr.getDatastoreClass(mmd.getTypeName(), clr);
                            if (mmd.getMappedBy() != null) {
                                relMmd = mmd.getRelatedMemberMetaData(clr)[0];
                                JavaTypeMapping relMapping = relTable.getMemberMapping(relMmd);
                                sqlTbl = stmt.join(joinType, sqlTbl, sqlTbl.getTable().getIdMapping(), relTable, aliasForJoin, relMapping, castDiscrimValues, joinTableGroupName, true);
                            } else {
                                if (sqlTbl.getTable() instanceof CollectionTable) {
                                    // Currently in a join table, so work from the element and this being an embedded member
                                    CollectionTable collTbl = (CollectionTable) sqlTbl.getTable();
                                    JavaTypeMapping elemMapping = collTbl.getElementMapping();
                                    if (elemMapping instanceof EmbeddedMapping) {
                                        otherMapping = ((EmbeddedMapping) elemMapping).getJavaTypeMapping(mmd.getName());
                                    }
                                } else {
                                    otherMapping = sqlTbl.getTable().getMemberMapping(mmd);
                                }
                                if (otherMapping == null && previousMapping != null) {
                                    if (previousMapping instanceof EmbeddedMapping) {
                                        // Part of an embedded 1-1 object, so find the relevant member mapping
                                        EmbeddedMapping embMapping = (EmbeddedMapping) previousMapping;
                                        otherMapping = embMapping.getJavaTypeMapping(mmd.getName());
                                    }
                                }
                                sqlTbl = stmt.join(joinType, sqlTbl, otherMapping, relTable, aliasForJoin, relTable.getIdMapping(), castDiscrimValues, joinTableGroupName, true);
                            }
                        }
                        previousMapping = otherMapping;
                        tblIdMapping = sqlTbl.getTable().getIdMapping();
                        tblMappingSqlTbl = sqlTbl;
                    } else if (relationType == RelationType.ONE_TO_MANY_BI) {
                        previousMapping = null;
                        if (mmd.hasCollection()) {
                            // Join across COLLECTION relation
                            cmd = mmd.getCollection().getElementClassMetaData(clr);
                            if (mmd.getCollection().isEmbeddedElement() && mmd.getJoinMetaData() != null) {
                                // Embedded element stored in (collection) join table
                                CollectionTable relEmbTable = (CollectionTable) storeMgr.getTable(mmd);
                                JavaTypeMapping relOwnerMapping = relEmbTable.getOwnerMapping();
                                sqlTbl = stmt.join(joinType, sqlTbl, sqlTbl.getTable().getIdMapping(), relEmbTable, aliasForJoin, relOwnerMapping, null, joinTableGroupName, true);
                                tblMappingSqlTbl = sqlTbl;
                                tblIdMapping = relEmbTable.getElementMapping();
                            } else {
                                relTable = storeMgr.getDatastoreClass(mmd.getCollection().getElementType(), clr);
                                relMmd = mmd.getRelatedMemberMetaData(clr)[0];
                                if (mmd.getJoinMetaData() != null || relMmd.getJoinMetaData() != null) {
                                    // Join to join table, then to related table
                                    ElementContainerTable joinTbl = (ElementContainerTable) storeMgr.getTable(mmd);
                                    SQLTable joinSqlTbl = stmt.join(joinType, sqlTbl, sqlTbl.getTable().getIdMapping(), joinTbl, null, joinTbl.getOwnerMapping(), null, null, true);
                                    sqlTbl = stmt.join(joinType, joinSqlTbl, joinTbl.getElementMapping(), relTable, aliasForJoin, relTable.getIdMapping(), null, joinTableGroupName, true);
                                } else {
                                    // Join to related table FK
                                    sqlTbl = stmt.join(joinType, sqlTbl, sqlTbl.getTable().getIdMapping(), relTable, aliasForJoin, relTable.getMemberMapping(relMmd), null, joinTableGroupName, true);
                                }
                                tblIdMapping = sqlTbl.getTable().getIdMapping();
                                tblMappingSqlTbl = sqlTbl;
                            }
                        } else if (mmd.hasMap()) {
                            // Join across MAP relation
                            MapMetaData mapmd = mmd.getMap();
                            cmd = mapmd.getValueClassMetaData(clr);
                            tblMmd = mmd;
                            boolean embedded = mapKey ? (mapmd.isEmbeddedKey() || mapmd.isSerializedKey()) : (mapmd.isEmbeddedValue() || mapmd.isSerializedValue());
                            if (mapmd.getMapType() == MapType.MAP_TYPE_JOIN) {
                                // Add join to join table, then to related table (value)
                                MapTable joinTbl = (MapTable) storeMgr.getTable(mmd);
                                String aliasForMap = embedded ? aliasForJoin : (aliasForJoin + "_MAP");
                                sqlTbl = stmt.join(joinType, sqlTbl, sqlTbl.getTable().getIdMapping(), joinTbl, aliasForMap, joinTbl.getOwnerMapping(), null, null, true);
                                if (embedded) {
                                    tblMappingSqlTbl = sqlTbl;
                                    tblIdMapping = mapKey ? joinTbl.getKeyMapping() : joinTbl.getValueMapping();
                                } else {
                                    if (mapKey) {
                                        // Join to key table and use that
                                        relTable = storeMgr.getDatastoreClass(mapmd.getKeyType(), clr);
                                        sqlTbl = stmt.join(joinType, sqlTbl, joinTbl.getKeyMapping(), relTable, aliasForJoin, relTable.getIdMapping(), null, joinTableGroupName, true);
                                    // TODO if there is an ON clause it needs to go on the correct join See [rdbms-177]
                                    } else {
                                        // Join to value table and use that
                                        relTable = storeMgr.getDatastoreClass(mapmd.getValueType(), clr);
                                        sqlTbl = stmt.join(joinType, sqlTbl, joinTbl.getValueMapping(), relTable, aliasForJoin, relTable.getIdMapping(), null, joinTableGroupName, true);
                                    // TODO if there is an ON clause it needs to go on the correct join See [rdbms-177]
                                    }
                                    tblMappingSqlTbl = sqlTbl;
                                    tblIdMapping = tblMappingSqlTbl.getTable().getIdMapping();
                                }
                            } else if (mapmd.getMapType() == MapType.MAP_TYPE_KEY_IN_VALUE) {
                                // Join to value table
                                DatastoreClass valTable = storeMgr.getDatastoreClass(mapmd.getValueType(), clr);
                                JavaTypeMapping mapTblOwnerMapping;
                                if (mmd.getMappedBy() != null) {
                                    mapTblOwnerMapping = valTable.getMemberMapping(mapmd.getValueClassMetaData(clr).getMetaDataForMember(mmd.getMappedBy()));
                                } else {
                                    mapTblOwnerMapping = valTable.getExternalMapping(mmd, MappingType.EXTERNAL_FK);
                                }
                                String aliasForMap = (embedded || !mapKey) ? aliasForJoin : (aliasForJoin + "_MAP");
                                sqlTbl = stmt.join(joinType, sqlTbl, sqlTbl.getTable().getIdMapping(), valTable, aliasForMap, mapTblOwnerMapping, null, null, true);
                                if (!embedded) {
                                    if (mapKey) {
                                        // Join to key table
                                        JavaTypeMapping keyMapping = valTable.getMemberMapping(mmd.getKeyMetaData().getMappedBy());
                                        relTable = storeMgr.getDatastoreClass(mapmd.getKeyType(), clr);
                                        sqlTbl = stmt.join(joinType, sqlTbl, keyMapping, relTable, aliasForJoin, relTable.getIdMapping(), null, joinTableGroupName, true);
                                    // TODO if there is an ON clause it needs to go on the correct join See [rdbms-177]
                                    }
                                }
                                tblMappingSqlTbl = sqlTbl;
                                tblIdMapping = tblMappingSqlTbl.getTable().getIdMapping();
                            } else if (mapmd.getMapType() == MapType.MAP_TYPE_VALUE_IN_KEY) {
                                // Join to key table, and then to value table
                                DatastoreClass keyTable = storeMgr.getDatastoreClass(mapmd.getKeyType(), clr);
                                JavaTypeMapping mapTblOwnerMapping;
                                if (mmd.getMappedBy() != null) {
                                    mapTblOwnerMapping = keyTable.getMemberMapping(mapmd.getKeyClassMetaData(clr).getMetaDataForMember(mmd.getMappedBy()));
                                } else {
                                    mapTblOwnerMapping = keyTable.getExternalMapping(mmd, MappingType.EXTERNAL_FK);
                                }
                                String aliasForMap = (embedded || mapKey) ? aliasForJoin : (aliasForJoin + "_MAP");
                                sqlTbl = stmt.join(joinType, sqlTbl, sqlTbl.getTable().getIdMapping(), keyTable, aliasForMap, mapTblOwnerMapping, null, null, true);
                                if (!embedded) {
                                    if (!mapKey) {
                                        // Join to value table
                                        JavaTypeMapping valueMapping = keyTable.getMemberMapping(mmd.getValueMetaData().getMappedBy());
                                        relTable = storeMgr.getDatastoreClass(mapmd.getValueType(), clr);
                                        sqlTbl = stmt.join(joinType, sqlTbl, valueMapping, relTable, aliasForJoin, relTable.getIdMapping(), null, joinTableGroupName, true);
                                    // TODO if there is an ON clause it needs to go on the correct join See [rdbms-177]
                                    }
                                }
                                tblMappingSqlTbl = sqlTbl;
                                tblIdMapping = tblMappingSqlTbl.getTable().getIdMapping();
                            }
                        } else if (mmd.hasArray()) {
                            // Join across ARRAY relation
                            cmd = mmd.getArray().getElementClassMetaData(clr);
                            if (mmd.getArray().isEmbeddedElement() && mmd.getJoinMetaData() != null) {
                                // Embedded element stored in (array) join table
                                ArrayTable relEmbTable = (ArrayTable) storeMgr.getTable(mmd);
                                JavaTypeMapping relOwnerMapping = relEmbTable.getOwnerMapping();
                                sqlTbl = stmt.join(joinType, sqlTbl, sqlTbl.getTable().getIdMapping(), relEmbTable, aliasForJoin, relOwnerMapping, null, joinTableGroupName, true);
                                tblMappingSqlTbl = sqlTbl;
                                tblIdMapping = relEmbTable.getElementMapping();
                            } else {
                                relTable = storeMgr.getDatastoreClass(mmd.getArray().getElementType(), clr);
                                relMmd = mmd.getRelatedMemberMetaData(clr)[0];
                                if (mmd.getJoinMetaData() != null || relMmd.getJoinMetaData() != null) {
                                    // Join to join table, then to related table
                                    ElementContainerTable joinTbl = (ElementContainerTable) storeMgr.getTable(mmd);
                                    SQLTable joinSqlTbl = stmt.join(joinType, sqlTbl, sqlTbl.getTable().getIdMapping(), joinTbl, null, joinTbl.getOwnerMapping(), null, null, true);
                                    sqlTbl = stmt.join(joinType, joinSqlTbl, joinTbl.getElementMapping(), relTable, aliasForJoin, relTable.getIdMapping(), null, joinTableGroupName, true);
                                // TODO if there is an ON clause it needs to go on the correct join See [rdbms-177]
                                } else {
                                    // Join to related table FK
                                    sqlTbl = stmt.join(joinType, sqlTbl, sqlTbl.getTable().getIdMapping(), relTable, aliasForJoin, relTable.getMemberMapping(relMmd), null, joinTableGroupName, true);
                                }
                                tblIdMapping = sqlTbl.getTable().getIdMapping();
                                tblMappingSqlTbl = sqlTbl;
                            }
                        }
                    } else if (relationType == RelationType.ONE_TO_MANY_UNI) {
                        previousMapping = null;
                        if (mmd.hasCollection()) {
                            // Join across COLLECTION relation
                            cmd = mmd.getCollection().getElementClassMetaData(clr);
                            if (mmd.getCollection().isEmbeddedElement() && mmd.getJoinMetaData() != null) {
                                // Embedded element stored in (collection) join table
                                CollectionTable relEmbTable = (CollectionTable) storeMgr.getTable(mmd);
                                JavaTypeMapping relOwnerMapping = relEmbTable.getOwnerMapping();
                                sqlTbl = stmt.join(joinType, sqlTbl, sqlTbl.getTable().getIdMapping(), relEmbTable, aliasForJoin, relOwnerMapping, null, joinTableGroupName, true);
                                tblMappingSqlTbl = sqlTbl;
                                tblIdMapping = relEmbTable.getElementMapping();
                            } else {
                                relTable = storeMgr.getDatastoreClass(mmd.getCollection().getElementType(), clr);
                                if (mmd.getJoinMetaData() != null) {
                                    // Join to join table, then to related table
                                    ElementContainerTable joinTbl = (ElementContainerTable) storeMgr.getTable(mmd);
                                    SQLTable joinSqlTbl = stmt.join(joinType, sqlTbl, sqlTbl.getTable().getIdMapping(), joinTbl, null, joinTbl.getOwnerMapping(), null, null, true);
                                    sqlTbl = stmt.join(joinType, joinSqlTbl, joinTbl.getElementMapping(), relTable, aliasForJoin, relTable.getIdMapping(), null, joinTableGroupName, true);
                                // TODO if there is an ON clause it needs to go on the correct join See [rdbms-177]
                                } else {
                                    // Join to related table FK
                                    JavaTypeMapping relMapping = relTable.getExternalMapping(mmd, MappingType.EXTERNAL_FK);
                                    sqlTbl = stmt.join(joinType, sqlTbl, sqlTbl.getTable().getIdMapping(), relTable, aliasForJoin, relMapping, null, joinTableGroupName, true);
                                }
                                tblMappingSqlTbl = sqlTbl;
                                tblIdMapping = tblMappingSqlTbl.getTable().getIdMapping();
                            }
                        } else if (mmd.hasMap()) {
                            // Join across MAP relation
                            MapMetaData mapmd = mmd.getMap();
                            cmd = mapmd.getValueClassMetaData(clr);
                            tblMmd = mmd;
                            boolean embedded = mapKey ? (mapmd.isEmbeddedKey() || mapmd.isSerializedKey()) : (mapmd.isEmbeddedValue() || mapmd.isSerializedValue());
                            if (mapmd.getMapType() == MapType.MAP_TYPE_JOIN) {
                                // Add join to join table, then to related table (value)
                                MapTable joinTbl = (MapTable) storeMgr.getTable(mmd);
                                String aliasForMap = (embedded || mapKey) ? aliasForJoin : (aliasForJoin + "_MAP");
                                sqlTbl = stmt.join(joinType, sqlTbl, sqlTbl.getTable().getIdMapping(), joinTbl, aliasForMap, joinTbl.getOwnerMapping(), null, null, true);
                                if (embedded) {
                                    tblMappingSqlTbl = sqlTbl;
                                    tblIdMapping = mapKey ? joinTbl.getKeyMapping() : joinTbl.getValueMapping();
                                } else {
                                    if (mapKey) {
                                        // Join to key table and use that
                                        relTable = storeMgr.getDatastoreClass(mapmd.getKeyType(), clr);
                                        sqlTbl = stmt.join(joinType, sqlTbl, joinTbl.getKeyMapping(), relTable, aliasForJoin, relTable.getIdMapping(), null, joinTableGroupName, true);
                                    // TODO if there is an ON clause it needs to go on the correct join See [rdbms-177]
                                    } else {
                                        // Join to value table and use that
                                        relTable = storeMgr.getDatastoreClass(mapmd.getValueType(), clr);
                                        sqlTbl = stmt.join(joinType, sqlTbl, joinTbl.getValueMapping(), relTable, aliasForJoin, relTable.getIdMapping(), null, joinTableGroupName, true);
                                    // TODO if there is an ON clause it needs to go on the correct join See [rdbms-177]
                                    }
                                    tblMappingSqlTbl = sqlTbl;
                                    tblIdMapping = tblMappingSqlTbl.getTable().getIdMapping();
                                }
                            } else if (mapmd.getMapType() == MapType.MAP_TYPE_KEY_IN_VALUE) {
                                // Join to value table
                                DatastoreClass valTable = storeMgr.getDatastoreClass(mapmd.getValueType(), clr);
                                JavaTypeMapping mapTblOwnerMapping;
                                if (mmd.getMappedBy() != null) {
                                    mapTblOwnerMapping = valTable.getMemberMapping(mapmd.getValueClassMetaData(clr).getMetaDataForMember(mmd.getMappedBy()));
                                } else {
                                    mapTblOwnerMapping = valTable.getExternalMapping(mmd, MappingType.EXTERNAL_FK);
                                }
                                String aliasForMap = (embedded || !mapKey) ? aliasForJoin : (aliasForJoin + "_MAP");
                                sqlTbl = stmt.join(joinType, sqlTbl, sqlTbl.getTable().getIdMapping(), valTable, aliasForMap, mapTblOwnerMapping, null, null, true);
                                if (!embedded) {
                                    if (mapKey) {
                                        // Join to key table
                                        JavaTypeMapping keyMapping = valTable.getMemberMapping(mmd.getKeyMetaData().getMappedBy());
                                        relTable = storeMgr.getDatastoreClass(mapmd.getKeyType(), clr);
                                        sqlTbl = stmt.join(joinType, sqlTbl, keyMapping, relTable, aliasForJoin, relTable.getIdMapping(), null, joinTableGroupName, true);
                                    // TODO if there is an ON clause it needs to go on the correct join See [rdbms-177]
                                    }
                                }
                                tblMappingSqlTbl = sqlTbl;
                                tblIdMapping = tblMappingSqlTbl.getTable().getIdMapping();
                            } else if (mapmd.getMapType() == MapType.MAP_TYPE_VALUE_IN_KEY) {
                                // Join to key table, and then to value table
                                DatastoreClass keyTable = storeMgr.getDatastoreClass(mapmd.getKeyType(), clr);
                                JavaTypeMapping mapTblOwnerMapping;
                                if (mmd.getMappedBy() != null) {
                                    mapTblOwnerMapping = keyTable.getMemberMapping(mapmd.getKeyClassMetaData(clr).getMetaDataForMember(mmd.getMappedBy()));
                                } else {
                                    mapTblOwnerMapping = keyTable.getExternalMapping(mmd, MappingType.EXTERNAL_FK);
                                }
                                String aliasForMap = (embedded || mapKey) ? aliasForJoin : (aliasForJoin + "_MAP");
                                sqlTbl = stmt.join(joinType, sqlTbl, sqlTbl.getTable().getIdMapping(), keyTable, aliasForMap, mapTblOwnerMapping, null, null, true);
                                if (!embedded) {
                                    if (!mapKey) {
                                        // Join to value table
                                        JavaTypeMapping valueMapping = keyTable.getMemberMapping(mmd.getValueMetaData().getMappedBy());
                                        relTable = storeMgr.getDatastoreClass(mapmd.getValueType(), clr);
                                        sqlTbl = stmt.join(joinType, sqlTbl, valueMapping, relTable, aliasForJoin, relTable.getIdMapping(), null, joinTableGroupName, true);
                                    // TODO if there is an ON clause it needs to go on the correct join See [rdbms-177]
                                    }
                                }
                                tblMappingSqlTbl = sqlTbl;
                                tblIdMapping = tblMappingSqlTbl.getTable().getIdMapping();
                            }
                        } else if (mmd.hasArray()) {
                            // Join across ARRAY relation
                            cmd = mmd.getArray().getElementClassMetaData(clr);
                            if (mmd.getArray().isEmbeddedElement() && mmd.getJoinMetaData() != null) {
                                // Embedded element stored in (array) join table
                                ArrayTable relEmbTable = (ArrayTable) storeMgr.getTable(mmd);
                                JavaTypeMapping relOwnerMapping = relEmbTable.getOwnerMapping();
                                sqlTbl = stmt.join(joinType, sqlTbl, sqlTbl.getTable().getIdMapping(), relEmbTable, aliasForJoin, relOwnerMapping, null, joinTableGroupName, true);
                                tblMappingSqlTbl = sqlTbl;
                                tblIdMapping = relEmbTable.getElementMapping();
                            } else {
                                relTable = storeMgr.getDatastoreClass(mmd.getArray().getElementType(), clr);
                                if (mmd.getJoinMetaData() != null) {
                                    // Join to join table, then to related table
                                    ElementContainerTable joinTbl = (ElementContainerTable) storeMgr.getTable(mmd);
                                    SQLTable joinSqlTbl = stmt.join(joinType, sqlTbl, sqlTbl.getTable().getIdMapping(), joinTbl, null, joinTbl.getOwnerMapping(), null, null, true);
                                    sqlTbl = stmt.join(joinType, joinSqlTbl, joinTbl.getElementMapping(), relTable, aliasForJoin, relTable.getIdMapping(), null, joinTableGroupName, true);
                                } else {
                                    // Join to related table FK
                                    JavaTypeMapping relMapping = relTable.getExternalMapping(mmd, MappingType.EXTERNAL_FK);
                                    sqlTbl = stmt.join(joinType, sqlTbl, sqlTbl.getTable().getIdMapping(), relTable, aliasForJoin, relMapping, null, joinTableGroupName, true);
                                }
                                tblMappingSqlTbl = sqlTbl;
                                tblIdMapping = tblMappingSqlTbl.getTable().getIdMapping();
                            }
                        }
                    } else if (relationType == RelationType.MANY_TO_MANY_BI) {
                        previousMapping = null;
                        relTable = storeMgr.getDatastoreClass(mmd.getCollection().getElementType(), clr);
                        cmd = mmd.getCollection().getElementClassMetaData(clr);
                        relMmd = mmd.getRelatedMemberMetaData(clr)[0];
                        // Join to join table, then to related table
                        if (mmd.hasCollection()) {
                            CollectionTable joinTbl = (CollectionTable) storeMgr.getTable(mmd);
                            SQLTable joinSqlTbl = stmt.join(joinType, sqlTbl, sqlTbl.getTable().getIdMapping(), joinTbl, null, joinTbl.getOwnerMapping(), null, null, true);
                            sqlTbl = stmt.join(joinType, joinSqlTbl, joinTbl.getElementMapping(), relTable, aliasForJoin, relTable.getIdMapping(), null, joinTableGroupName, true);
                        } else if (mmd.hasMap()) {
                            NucleusLogger.QUERY.warn("We do not support joining across a M-N MAP field : " + mmd.getFullFieldName());
                        } else if (mmd.hasArray()) {
                            NucleusLogger.QUERY.warn("We do not support joining across a M-N ARRAY field : " + mmd.getFullFieldName());
                        }
                        tblMappingSqlTbl = sqlTbl;
                        tblIdMapping = tblMappingSqlTbl.getTable().getIdMapping();
                    } else if (relationType == RelationType.MANY_TO_ONE_BI) {
                        previousMapping = null;
                        relTable = storeMgr.getDatastoreClass(mmd.getTypeName(), clr);
                        Object[] castDiscrimValues = null;
                        if (castCls != null && lastComponent) {
                            cmd = mmgr.getMetaDataForClass(castCls, clr);
                            if (cmd.hasDiscriminatorStrategy()) {
                                // Restrict discriminator on cast type to be the type+subclasses
                                castDiscrimValues = getDiscriminatorValuesForCastClass(cmd);
                            }
                        } else {
                            cmd = mmgr.getMetaDataForClass(mmd.getType(), clr);
                        }
                        relMmd = mmd.getRelatedMemberMetaData(clr)[0];
                        if (mmd.getJoinMetaData() != null || relMmd.getJoinMetaData() != null) {
                            // Join to join table, then to related table
                            if (mmd.hasCollection()) {
                                CollectionTable joinTbl = (CollectionTable) storeMgr.getTable(relMmd);
                                SQLTable joinSqlTbl = stmt.join(joinType, sqlTbl, sqlTbl.getTable().getIdMapping(), joinTbl, null, joinTbl.getElementMapping(), null, null, true);
                                sqlTbl = stmt.join(joinType, joinSqlTbl, joinTbl.getOwnerMapping(), relTable, aliasForJoin, relTable.getIdMapping(), castDiscrimValues, joinTableGroupName, true);
                            } else if (mmd.hasMap()) {
                                NucleusLogger.QUERY.warn("We do not support joining across a N-1 MAP field : " + mmd.getFullFieldName());
                            } else if (mmd.hasArray()) {
                                NucleusLogger.QUERY.warn("We do not support joining across a N-1 ARRAY field : " + mmd.getFullFieldName());
                            }
                        } else {
                            // Join to owner table
                            JavaTypeMapping fkMapping = sqlTbl.getTable().getMemberMapping(mmd);
                            sqlTbl = stmt.join(joinType, sqlTbl, fkMapping, relTable, aliasForJoin, relTable.getIdMapping(), castDiscrimValues, joinTableGroupName, true);
                        }
                        tblMappingSqlTbl = sqlTbl;
                        tblIdMapping = tblMappingSqlTbl.getTable().getIdMapping();
                    } else {
                        // NO RELATION, but cater for join table cases
                        previousMapping = null;
                        if (mmd.hasCollection()) {
                            cmd = null;
                            if (mmd.getJoinMetaData() != null) {
                                // Join to join table
                                CollectionTable joinTbl = (CollectionTable) storeMgr.getTable(mmd);
                                sqlTbl = stmt.join(joinType, sqlTbl, sqlTbl.getTable().getIdMapping(), joinTbl, aliasForJoin, joinTbl.getOwnerMapping(), null, null, true);
                                tblMappingSqlTbl = sqlTbl;
                                tblIdMapping = joinTbl.getElementMapping();
                            } else {
                                throw new NucleusUserException("FROM clause contains join to Collection field at " + mmd.getFullFieldName() + " yet this has no join table");
                            }
                        } else if (mmd.hasMap()) {
                            MapMetaData mapmd = mmd.getMap();
                            cmd = mapmd.getValueClassMetaData(clr);
                            tblMmd = mmd;
                            if (// Should be the only type when relationType is NONE
                            mapmd.getMapType() == MapType.MAP_TYPE_JOIN) {
                                // Add join to join table
                                MapTable joinTbl = (MapTable) storeMgr.getTable(mmd);
                                String aliasForMap = aliasForJoin;
                                sqlTbl = stmt.join(joinType, sqlTbl, sqlTbl.getTable().getIdMapping(), joinTbl, aliasForMap, joinTbl.getOwnerMapping(), null, null, true);
                                tblMappingSqlTbl = sqlTbl;
                                tblIdMapping = joinTbl.getValueMapping();
                            } else {
                                throw new NucleusUserException("FROM clause contains join to Map field at " + mmd.getFullFieldName() + " yet this has no join table");
                            }
                        } else if (mmd.hasArray()) {
                            cmd = null;
                            if (mmd.getJoinMetaData() != null) {
                                // Join to join table
                                ArrayTable joinTbl = (ArrayTable) storeMgr.getTable(mmd);
                                sqlTbl = stmt.join(joinType, sqlTbl, sqlTbl.getTable().getIdMapping(), joinTbl, aliasForJoin, joinTbl.getOwnerMapping(), null, null, true);
                                tblMappingSqlTbl = sqlTbl;
                                tblIdMapping = joinTbl.getElementMapping();
                            } else {
                                throw new NucleusUserException("FROM clause contains join to array field at " + mmd.getFullFieldName() + " yet this has no join table");
                            }
                        }
                    }
                }
            }
            if (joinAlias != null) {
                if (explicitJoinPrimaryByAlias == null) {
                    explicitJoinPrimaryByAlias = new HashMap<>();
                }
                explicitJoinPrimaryByAlias.put(joinAlias, joinPrimExpr.getId());
                SQLTableMapping tblMapping = null;
                if (tblMmd != null) {
                    // Maps store the member so we can more easily navigate to the key/value
                    tblMapping = new SQLTableMapping(tblMappingSqlTbl, cmd, tblMmd, tblIdMapping);
                } else {
                    tblMapping = new SQLTableMapping(tblMappingSqlTbl, cmd, tblIdMapping);
                }
                setSQLTableMappingForAlias(joinAlias, tblMapping);
            }
            if (joinOnExpr != null) {
                // Convert the ON expression to a BooleanExpression
                processingOnClause = true;
                joinOnExpr.evaluate(this);
                BooleanExpression joinOnSqlExpr = (BooleanExpression) stack.pop();
                processingOnClause = false;
                // Add the ON expression to the most recent SQLTable at the end of this chain
                // TODO Allow for SQL JOIN "grouping" [rdbms-177]. This applies to all cases where we join to a join table then to an element/value table and
                // need to apply the ON clause across both
                SQLJoin join = stmt.getJoinForTable(sqlTbl);
                join.addAndCondition(joinOnSqlExpr);
            }
        } else {
            previousMapping = null;
        }
        // Move on to next join in the chain
        rightExpr = rightExpr.getRight();
    }
}
Also used : FetchGroupManager(org.datanucleus.FetchGroupManager) PrimaryExpression(org.datanucleus.store.query.expression.PrimaryExpression) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) Symbol(org.datanucleus.store.query.compiler.Symbol) SQLJoin(org.datanucleus.store.rdbms.sql.SQLJoin) SQLStatement(org.datanucleus.store.rdbms.sql.SQLStatement) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) MapTable(org.datanucleus.store.rdbms.table.MapTable) SelectStatement(org.datanucleus.store.rdbms.sql.SelectStatement) BooleanExpression(org.datanucleus.store.rdbms.sql.expression.BooleanExpression) CollectionTable(org.datanucleus.store.rdbms.table.CollectionTable) SQLTable(org.datanucleus.store.rdbms.sql.SQLTable) TemporalLiteral(org.datanucleus.store.rdbms.sql.expression.TemporalLiteral) Literal(org.datanucleus.store.query.expression.Literal) SQLLiteral(org.datanucleus.store.rdbms.sql.expression.SQLLiteral) ParameterLiteral(org.datanucleus.store.rdbms.sql.expression.ParameterLiteral) CollectionLiteral(org.datanucleus.store.rdbms.sql.expression.CollectionLiteral) BooleanLiteral(org.datanucleus.store.rdbms.sql.expression.BooleanLiteral) IntegerLiteral(org.datanucleus.store.rdbms.sql.expression.IntegerLiteral) NullLiteral(org.datanucleus.store.rdbms.sql.expression.NullLiteral) RelationType(org.datanucleus.metadata.RelationType) JoinExpression(org.datanucleus.store.query.expression.JoinExpression) ElementContainerTable(org.datanucleus.store.rdbms.table.ElementContainerTable) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) MetaDataManager(org.datanucleus.metadata.MetaDataManager) JoinType(org.datanucleus.store.rdbms.sql.SQLJoin.JoinType) MapMetaData(org.datanucleus.metadata.MapMetaData) DyadicExpression(org.datanucleus.store.query.expression.DyadicExpression) PrimaryExpression(org.datanucleus.store.query.expression.PrimaryExpression) BooleanSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.BooleanSubqueryExpression) TypeConverterExpression(org.datanucleus.store.rdbms.sql.expression.TypeConverterExpression) StringExpression(org.datanucleus.store.rdbms.sql.expression.StringExpression) NumericSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.NumericSubqueryExpression) StringSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.StringSubqueryExpression) MapExpression(org.datanucleus.store.rdbms.sql.expression.MapExpression) ArrayExpression(org.datanucleus.store.query.expression.ArrayExpression) CaseExpression(org.datanucleus.store.query.expression.CaseExpression) CreatorExpression(org.datanucleus.store.query.expression.CreatorExpression) NewObjectExpression(org.datanucleus.store.rdbms.sql.expression.NewObjectExpression) OrderExpression(org.datanucleus.store.query.expression.OrderExpression) TemporalSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.TemporalSubqueryExpression) ClassExpression(org.datanucleus.store.query.expression.ClassExpression) BooleanExpression(org.datanucleus.store.rdbms.sql.expression.BooleanExpression) Expression(org.datanucleus.store.query.expression.Expression) SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) ParameterExpression(org.datanucleus.store.query.expression.ParameterExpression) UnboundExpression(org.datanucleus.store.rdbms.sql.expression.UnboundExpression) TemporalExpression(org.datanucleus.store.rdbms.sql.expression.TemporalExpression) SubqueryExpression(org.datanucleus.store.query.expression.SubqueryExpression) ResultAliasExpression(org.datanucleus.store.rdbms.sql.expression.ResultAliasExpression) VariableExpression(org.datanucleus.store.query.expression.VariableExpression) TypeExpression(org.datanucleus.store.query.expression.TypeExpression) NumericExpression(org.datanucleus.store.rdbms.sql.expression.NumericExpression) CollectionExpression(org.datanucleus.store.rdbms.sql.expression.CollectionExpression) DyadicExpression(org.datanucleus.store.query.expression.DyadicExpression) ColumnExpression(org.datanucleus.store.rdbms.sql.expression.ColumnExpression) JoinExpression(org.datanucleus.store.query.expression.JoinExpression) InvokeExpression(org.datanucleus.store.query.expression.InvokeExpression) EmbeddedMapping(org.datanucleus.store.rdbms.mapping.java.EmbeddedMapping) SQLTableGroup(org.datanucleus.store.rdbms.sql.SQLTableGroup) FetchGroup(org.datanucleus.FetchGroup) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) FetchPlanForClass(org.datanucleus.FetchPlanForClass) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) NucleusException(org.datanucleus.exceptions.NucleusException) ArrayTable(org.datanucleus.store.rdbms.table.ArrayTable) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData)

Aggregations

DyadicExpression (org.datanucleus.store.query.expression.DyadicExpression)7 InvokeExpression (org.datanucleus.store.query.expression.InvokeExpression)7 ParameterExpression (org.datanucleus.store.query.expression.ParameterExpression)7 PrimaryExpression (org.datanucleus.store.query.expression.PrimaryExpression)7 VariableExpression (org.datanucleus.store.query.expression.VariableExpression)7 BooleanExpression (org.datanucleus.store.rdbms.sql.expression.BooleanExpression)7 MapExpression (org.datanucleus.store.rdbms.sql.expression.MapExpression)7 SQLExpression (org.datanucleus.store.rdbms.sql.expression.SQLExpression)7 UnboundExpression (org.datanucleus.store.rdbms.sql.expression.UnboundExpression)7 NucleusException (org.datanucleus.exceptions.NucleusException)6 ArrayExpression (org.datanucleus.store.query.expression.ArrayExpression)6 CaseExpression (org.datanucleus.store.query.expression.CaseExpression)6 ClassExpression (org.datanucleus.store.query.expression.ClassExpression)6 CreatorExpression (org.datanucleus.store.query.expression.CreatorExpression)6 Expression (org.datanucleus.store.query.expression.Expression)6 JoinExpression (org.datanucleus.store.query.expression.JoinExpression)6 Literal (org.datanucleus.store.query.expression.Literal)6 OrderExpression (org.datanucleus.store.query.expression.OrderExpression)6 SubqueryExpression (org.datanucleus.store.query.expression.SubqueryExpression)6 TypeExpression (org.datanucleus.store.query.expression.TypeExpression)6