/** * INTERNAL: * This factory method is used to build a subselect that will do a count. * It will count the number of items in baseExpression.anyOf(attribute). */ public static SubSelectExpression createSubSelectExpressionForCount(Expression outerQueryBaseExpression, Expression outerQueryCriteria, String attribute, Class returnType){ SubSelectExpression expression = new SubSelectExpression(); expression.setBaseExpression(outerQueryBaseExpression); expression.attribute = attribute; expression.criteriaBase = outerQueryCriteria; if (returnType != null){ expression.returnType = returnType; } return expression; } }
/** * INTERNAL: * Used to print a debug form of the expression tree. */ @Override public void writeDescriptionOn(BufferedWriter writer) throws IOException { writer.write(String.valueOf(getSubQuery())); }
/** * INTERNAL: * Normalize all subselect expressions found in the course of normalizing the * enclosing query. * This method allows one to completely normalize the parent statement first * (which should treat its sub selects as black boxes), and then normalize the * subselects (which require full knowledge of the enclosing statement). * This should make things clearer too, * Assumes encounteredSubSelectExpressions() true. * For CR#4223. */ public void normalizeSubSelects(Map clonedExpressions) { for (SubSelectExpression next : this.subSelectExpressions) { next.normalizeSubSelect(this, clonedExpressions); } }
@Override public Expression twistedForBaseAndContext(Expression newBase, Expression context, Expression oldBase) { SubSelectExpression subSelect = (SubSelectExpression) shallowClone(); subSelect.setBaseExpression(subSelect.getBaseExpression().twistedForBaseAndContext(newBase, context, oldBase)); ReportQuery reportQuery = (ReportQuery) getSubQuery().clone(); List<ReportItem> newItems = new ArrayList<ReportItem>(getSubQuery().getItems().size()); for (ReportItem item : getSubQuery().getItems()) { newItems.add(new ReportItem(item.getName(), item.getAttributeExpression().twistedForBaseAndContext(newBase, context, getBaseExpression()))); if (getSubQuery().hasGroupByExpressions()) { List<Expression> groupByExpressions = new ArrayList<Expression>(getSubQuery().getGroupByExpressions().size()); for (Expression groupByExpression : getSubQuery().getGroupByExpressions()) { groupByExpressions.add(groupByExpression.twistedForBaseAndContext(newBase, context, getBaseExpression())); if (getSubQuery().hasOrderByExpressions()) { List<Expression> orderByExpressions = new ArrayList<Expression>(getSubQuery().getOrderByExpressions().size()); for (Expression orderByExpression : getSubQuery().getOrderByExpressions()) { orderByExpressions.add(orderByExpression.twistedForBaseAndContext(newBase, context, getBaseExpression())); if (getSubQuery().hasUnionExpressions()) { List<Expression> unionByExpressions = new ArrayList<Expression>(getSubQuery().getUnionExpressions().size()); for (Expression unionExpression : getSubQuery().getUnionExpressions()) { unionByExpressions.add(unionExpression.twistedForBaseAndContext(newBase, context, getBaseExpression())); if (getSubQuery().getSelectionCriteria() != null) { reportQuery.setSelectionCriteria(getSubQuery().getSelectionCriteria().twistedForBaseAndContext(newBase, context, getBaseExpression()));
/** * The query must be cloned, and the sub-expression must be cloned using the same outer expression identity. */ @Override protected void postCopyIn(Map alreadyDone) { initializeCountSubQuery(); super.postCopyIn(alreadyDone); ReportQuery clonedQuery = (ReportQuery)getSubQuery().clone(); if (!clonedQuery.isCallQuery()) { if (clonedQuery.getSelectionCriteria() != null) { clonedQuery.setSelectionCriteria(getSubQuery().getSelectionCriteria().copiedVersionFrom(alreadyDone)); // ensure the builder for the subquery is the same as the builder for the subquery's expression // for certain Subqueries (for instance batch queries for direct collections), when we get to this // point the builder for the clonedQuery will already be aliased. Replacing the builder with // the builder for the query's new expression solves this issue. if (clonedQuery.getExpressionBuilder() != null) { clonedQuery.setExpressionBuilder((ExpressionBuilder)clonedQuery.getExpressionBuilder().copiedVersionFrom(alreadyDone)); } } else if (clonedQuery.getExpressionBuilder() != null) { // Must clone the expression builder. clonedQuery.setExpressionBuilder((ExpressionBuilder)clonedQuery.getExpressionBuilder().copiedVersionFrom(alreadyDone)); } // Must also clone report items, group by, having, order by. clonedQuery.copyReportItems(alreadyDone); } setSubQuery(clonedQuery); }
/** * Print the sub query to the printer. */ public void printSQL(ExpressionSQLPrinter printer) { ReportQuery query = getSubQuery(); printer.printString("("); if (query.isCallQuery()) { printCustomSQL(printer); } else { SQLSelectStatement statement = (SQLSelectStatement)((ExpressionQueryMechanism)query.getQueryMechanism()).getSQLStatement(); boolean isFirstElementPrinted = printer.isFirstElementPrinted(); printer.setIsFirstElementPrinted(false); boolean requiresDistinct = printer.requiresDistinct(); statement.printSQL(printer); printer.setIsFirstElementPrinted(isFirstElementPrinted); printer.setRequiresDistinct(requiresDistinct); } printer.printString(")"); }
if (!getSubQuery().isCallQuery() && (getSubQuery().getReferenceClass() == null)) { ReportQuery subQuery = getSubQuery(); Expression criteria = subQuery.getSelectionCriteria(); validateNode(); getSubQuery().prepareSubSelect(normalizer.getSession(), null, clonedExpressions); if (!getSubQuery().isCallQuery()) { SQLSelectStatement statement = (SQLSelectStatement)((StatementQueryMechanism)getSubQuery().getQueryMechanism()).getSQLStatement(); statement.normalize(normalizer.getSession(), getSubQuery().getDescriptor(), clonedExpressions);
/** * INTERNAL: * Normalize the expression into a printable structure. * Any joins must be added to form a new root. */ @Override public Expression normalize(ExpressionNormalizer normalizer) { if (this.subSelect != null) { // Each item that is a function must have an alias defined for it. for (ReportItem item : this.subSelect.getSubQuery().getItems()) { if (!item.getAttributeExpression().isQueryKeyExpression()) { item.setAttributeExpression(item.getAttributeExpression().as(item.getName())); } } // Need to force the sub-slect to normalize instead of deferring. this.subSelect.normalizeSubSelect(normalizer, normalizer.getClonedExpressions()); } return super.normalize(normalizer); }
/** * The query must be cloned, and the sub-expression must be cloned using the same outer expression identity. */ protected void postCopyIn(Map alreadyDone) { super.postCopyIn(alreadyDone); ReportQuery clonedQuery = (ReportQuery)getSubQuery().clone(); if (!clonedQuery.isCallQuery()) { if (clonedQuery.getSelectionCriteria() != null) { clonedQuery.setSelectionCriteria(getSubQuery().getSelectionCriteria().copiedVersionFrom(alreadyDone)); // ensure the builder for the subquery is the same as the builder for the subquery's expression // for certain Subqueries (for instance batch queries for direct collections), when we get to this // point the builder for the clonedQuery will already be aliased. Replacing the builder with // the builder for the query's new expression solves this issue. if (clonedQuery.getExpressionBuilder() != null) { clonedQuery.setExpressionBuilder(clonedQuery.getSelectionCriteria().getBuilder()); } } else if (clonedQuery.getExpressionBuilder() != null) { // Must clone the expression builder. clonedQuery.setExpressionBuilder((ExpressionBuilder)clonedQuery.getExpressionBuilder().copiedVersionFrom(alreadyDone)); } // Must also clone report items. clonedQuery.copyReportItems(alreadyDone); } setSubQuery(clonedQuery); }
/** * PUBLIC: * Return a sub query expression. * A sub query using a report query to define a subselect within another queries expression or select's where clause. * The sub query (the report query) will use its own expression builder be can reference expressions from the base expression builder. * <p>Example: * <pre><blockquote> * ExpressionBuilder builder = new ExpressionBuilder(); * ReportQuery subQuery = new ReportQuery(Employee.class, new ExpressionBuilder()); * subQuery.addMaximum("salary"); * builder.get("salary").equal(builder.subQuery(subQuery)); * </blockquote></pre> */ public Expression subQuery(ReportQuery subQuery) { return new SubSelectExpression(subQuery, this); }
/** * INTERNAL: * The subquery must be normalized with the knowledge of the outer statement for outer references and correct aliasing. * For CR#4223 it will now be normalized after the outer statement is, rather than * somewhere in the middle of the outer statement's normalize. */ public Expression normalize(ExpressionNormalizer normalizer) { //has no effect but validateNode is here for consistency validateNode(); // Defer normalization of this expression until later. normalizer.addSubSelectExpression(this); normalizer.getStatement().setRequiresAliases(true); return this; }
/** * PUBLIC: A logical expression for the size of collection <code>attributeName</code>. * <p>Example: * <blockquote><pre> * EclipseLink: employee.size("phoneNumbers") * Java: employee.getPhoneNumbers().size() * SQL: SELECT ... FROM EMP t0 WHERE ... * (SELECT COUNT(*) FROM PHONE t1 WHERE (t0.EMP_ID = t1.EMP_ID)) * </pre></blockquote> * This is a case where a fast operation in java does not translate to an * equally fast operation in SQL, requiring a correlated subselect. */ public Expression size(String attributeName) { return SubSelectExpression.createSubSelectExpressionForCount(this, this, attributeName, null); }
/** * INTERNAL: * Also copy over the sub-select if present. */ @Override protected void postCopyIn(Map alreadyDone) { super.postCopyIn(alreadyDone); if (this.subSelect != null) { this.subSelect = (SubSelectExpression)this.subSelect.copiedVersionFrom(alreadyDone); this.table = new SubSelectDatabaseTable(subSelect); } }
@Override public Expression twistedForBaseAndContext(Expression newBase, Expression context, Expression oldBase) { SubSelectExpression subSelect = (SubSelectExpression) shallowClone(); subSelect.setBaseExpression(subSelect.getBaseExpression().twistedForBaseAndContext(newBase, context, oldBase)); ReportQuery reportQuery = (ReportQuery) getSubQuery().clone(); List<ReportItem> newItems = new ArrayList<ReportItem>(getSubQuery().getItems().size()); for (ReportItem item : getSubQuery().getItems()) { newItems.add(new ReportItem(item.getName(), item.getAttributeExpression().twistedForBaseAndContext(newBase, context, getBaseExpression()))); if (getSubQuery().hasGroupByExpressions()) { List<Expression> groupByExpressions = new ArrayList<Expression>(getSubQuery().getGroupByExpressions().size()); for (Expression groupByExpression : getSubQuery().getGroupByExpressions()) { groupByExpressions.add(groupByExpression.twistedForBaseAndContext(newBase, context, getBaseExpression())); if (getSubQuery().hasOrderByExpressions()) { List<Expression> orderByExpressions = new ArrayList<Expression>(getSubQuery().getOrderByExpressions().size()); for (Expression orderByExpression : getSubQuery().getOrderByExpressions()) { orderByExpressions.add(orderByExpression.twistedForBaseAndContext(newBase, context, getBaseExpression())); if (getSubQuery().hasUnionExpressions()) { List<Expression> unionByExpressions = new ArrayList<Expression>(getSubQuery().getUnionExpressions().size()); for (Expression unionExpression : getSubQuery().getUnionExpressions()) { unionByExpressions.add(unionExpression.twistedForBaseAndContext(newBase, context, getBaseExpression())); if (getSubQuery().getSelectionCriteria() != null) { reportQuery.setSelectionCriteria(getSubQuery().getSelectionCriteria().twistedForBaseAndContext(newBase, context, getBaseExpression()));
/** * The query must be cloned, and the sub-expression must be cloned using the same outer expression identity. */ @Override protected void postCopyIn(Map alreadyDone) { initializeCountSubQuery(); super.postCopyIn(alreadyDone); ReportQuery clonedQuery = (ReportQuery)getSubQuery().clone(); if (!clonedQuery.isCallQuery()) { if (clonedQuery.getSelectionCriteria() != null) { clonedQuery.setSelectionCriteria(getSubQuery().getSelectionCriteria().copiedVersionFrom(alreadyDone)); // ensure the builder for the subquery is the same as the builder for the subquery's expression // for certain Subqueries (for instance batch queries for direct collections), when we get to this // point the builder for the clonedQuery will already be aliased. Replacing the builder with // the builder for the query's new expression solves this issue. if (clonedQuery.getExpressionBuilder() != null) { clonedQuery.setExpressionBuilder((ExpressionBuilder)clonedQuery.getExpressionBuilder().copiedVersionFrom(alreadyDone)); } } else if (clonedQuery.getExpressionBuilder() != null) { // Must clone the expression builder. clonedQuery.setExpressionBuilder((ExpressionBuilder)clonedQuery.getExpressionBuilder().copiedVersionFrom(alreadyDone)); } // Must also clone report items, group by, having, order by. clonedQuery.copyReportItems(alreadyDone); } setSubQuery(clonedQuery); }
/** * Print the sub query to the printer. */ @Override public void printSQL(ExpressionSQLPrinter printer) { ReportQuery query = getSubQuery(); printer.printString("("); if (query.isCallQuery()) { printCustomSQL(printer); } else { SQLSelectStatement statement = (SQLSelectStatement)((ExpressionQueryMechanism)query.getQueryMechanism()).getSQLStatement(); boolean isFirstElementPrinted = printer.isFirstElementPrinted(); printer.setIsFirstElementPrinted(false); boolean requiresDistinct = printer.requiresDistinct(); statement.printSQL(printer); printer.setIsFirstElementPrinted(isFirstElementPrinted); printer.setRequiresDistinct(requiresDistinct); } printer.printString(")"); }
if (!getSubQuery().isCallQuery() && (getSubQuery().getReferenceClass() == null)) { ReportQuery subQuery = getSubQuery(); Expression criteria = subQuery.getSelectionCriteria(); validateNode(); getSubQuery().prepareSubSelect(normalizer.getSession(), null, clonedExpressions); if (!getSubQuery().isCallQuery()) { SQLSelectStatement statement = (SQLSelectStatement)((StatementQueryMechanism)getSubQuery().getQueryMechanism()).getSQLStatement(); statement.normalize(normalizer.getSession(), getSubQuery().getDescriptor(), clonedExpressions);
/** * INTERNAL: * Normalize the expression into a printable structure. * Any joins must be added to form a new root. */ @Override public Expression normalize(ExpressionNormalizer normalizer) { if (this.subSelect != null) { // Each item that is a function must have an alias defined for it. for (ReportItem item : this.subSelect.getSubQuery().getItems()) { if (!item.getAttributeExpression().isQueryKeyExpression()) { item.setAttributeExpression(item.getAttributeExpression().as(item.getName())); } } // Need to force the sub-slect to normalize instead of deferring. this.subSelect.normalizeSubSelect(normalizer, normalizer.getClonedExpressions()); } return super.normalize(normalizer); }
/** * PUBLIC: * Return a sub query expression. * A sub query using a report query to define a subselect within another queries expression or select's where clause. * The sub query (the report query) will use its own expression builder be can reference expressions from the base expression builder. * <p>Example: * <blockquote><pre> * ExpressionBuilder builder = new ExpressionBuilder(); * ReportQuery subQuery = new ReportQuery(Employee.class, new ExpressionBuilder()); * subQuery.addMaximum("salary"); * builder.get("salary").equal(builder.subQuery(subQuery)); * </pre></blockquote> */ public Expression subQuery(ReportQuery subQuery) { return new SubSelectExpression(subQuery, this); }
/** * INTERNAL: * The subquery must be normalized with the knowledge of the outer statement for outer references and correct aliasing. * For CR#4223 it will now be normalized after the outer statement is, rather than * somewhere in the middle of the outer statement's normalize. */ @Override public Expression normalize(ExpressionNormalizer normalizer) { if (this.hasBeenNormalized) { return this; } //has no effect but validateNode is here for consistency validateNode(); // Defer normalization of this expression until later. normalizer.addSubSelectExpression(this); normalizer.getStatement().setRequiresAliases(true); return this; }