/** Return the expression from the attribute dervied from this expression. */ @Override public Expression get(String attributeName, boolean forceInnerJoin) { ObjectExpression result = derivedExpressionNamed(attributeName); if (forceInnerJoin) { result.doNotUseOuterJoin(); } return result; }
/** Defines a join between this expression and the target expression based on the ON clause. */ @Override public Expression join(Expression target, Expression onClause) { if (target instanceof ObjectExpression) { ((ObjectExpression) target).setJoinSource(this); ((ObjectExpression) target).setOnClause(onClause); } else { throw new IllegalArgumentException(); } return this; }
@Override public Expression getAllowingNull(String attributeName) { ObjectExpression exp = existingDerivedExpressionNamed(attributeName); // The same (aliased) table cannot participate in a normal join and an outer join. // To help enforce this, if the node already exists if (exp != null) { return exp; } ObjectExpression result = derivedExpressionNamed(attributeName); result.doUseOuterJoin(); return result; }
/** * INTERNAL: This method is used when computing the nested queries for batch read mappings. It * recurses computing the nested mapping queries. */ protected void computeNestedQueriesForBatchReadExpressions(Vector batchReadExpressions) { for (int index = 0; index < batchReadExpressions.size(); index++) { ObjectExpression objectExpression = (ObjectExpression) batchReadExpressions.get(index); // Expression may not have been initialized. ExpressionBuilder builder = objectExpression.getBuilder(); builder.setSession(getSession().getRootSession(null)); builder.setQueryClass(getReferenceClass()); // PERF: Cache join attribute names. ObjectExpression baseExpression = objectExpression; while (!baseExpression.getBaseExpression().isExpressionBuilder()) { baseExpression = (ObjectExpression) baseExpression.getBaseExpression(); } this.batchReadAttributes.add(baseExpression.getName()); // Ignore nested if (objectExpression.getBaseExpression().isExpressionBuilder()) { DatabaseMapping mapping = objectExpression.getMapping(); if ((mapping != null) && mapping.isForeignReferenceMapping()) { // A nested query must be built to pass to the descriptor that looks like the real query // execution would. ReadQuery nestedQuery = ((ForeignReferenceMapping) mapping).prepareNestedBatchQuery(this); // Register the nested query to be used by the mapping for all the objects. getBatchReadMappingQueries().put(mapping, nestedQuery); } } } }
/** * INTERNAL: Parses an expression to return the first non-AggregateObjectMapping expression after * the base ExpressionBuilder. This is used by joining and batch fetch to get the list of mappings * that really need to be processed (non-aggregates). * * @param aggregateMappingsEncountered - collection of aggregateObjectMapping expressions * encountered in the returned expression between the first expression and the * ExpressionBuilder * @return first non-AggregateObjectMapping expression after the base ExpressionBuilder from the * fullExpression */ public ObjectExpression getFirstNonAggregateExpressionAfterExpressionBuilder( List aggregateMappingsEncountered) { boolean done = false; ObjectExpression baseExpression = this; ObjectExpression prevExpression = this; while (!baseExpression.getBaseExpression().isExpressionBuilder() && !done) { baseExpression = (ObjectExpression) baseExpression.getBaseExpression(); while (!baseExpression.isExpressionBuilder() && baseExpression.getMapping().isAggregateObjectMapping()) { aggregateMappingsEncountered.add(baseExpression.getMapping()); baseExpression = (ObjectExpression) baseExpression.getBaseExpression(); } if (baseExpression.isExpressionBuilder()) { done = true; // use the one closest to the expression builder that wasn't an aggregate baseExpression = prevExpression; } else { prevExpression = baseExpression; } } return baseExpression; }
/** * INTERNAL: For CR#2456 if this is part of an objExp.equal(objExp), do not need to add additional * expressions to normalizer both times, and the foreign key join replaces the equal expression. */ public Expression normalize(ExpressionNormalizer normalizer, Vector foreignKeyJoinPointer) { if (hasBeenNormalized()) { return this; } super.normalize(normalizer); setHasBeenNormalized(true); if ((getMapping() != null) && getMapping().isDirectToXMLTypeMapping()) { normalizer.getStatement().setRequiresAliases(true); } // Check if any joins need to be added. if (isAttribute()) { return this; } // If the mapping is 'ref' or 'structure', no join needed. if ((getMapping() != null) && (getMapping().isReferenceMapping() || getMapping().isStructureMapping())) { normalizer.getStatement().setRequiresAliases(true); return this; } // Compute if a distinct is required during normalization. if (shouldQueryToManyRelationship() && (!normalizer.getStatement().isDistinctComputed()) && (!normalizer.getStatement().isAggregateSelect())) { normalizer.getStatement().useDistinct(); } // Turn off DISTINCT if nestedTableMapping is used (not supported by Oracle 8.1.5). if ((getMapping() != null) && getMapping().isNestedTableMapping()) { // There are two types of nested tables, one used by clients, one used by mappings, do nothing // in the mapping case. if (!shouldQueryToManyRelationship()) { return this; } normalizer.getStatement().dontUseDistinct(); } Expression mappingExpression = mappingCriteria(); if (mappingExpression != null) { mappingExpression = mappingExpression.normalize(normalizer); } if (mappingExpression != null) { // If the join was an outer join we must not add the join criteria to the where clause, // if the platform prints the join in the from clause. if (shouldUseOuterJoin() && (getSession().getPlatform().isInformixOuterJoin())) { normalizer.getStatement().getOuterJoinExpressions().addElement(this); normalizer.getStatement().getOuterJoinedMappingCriteria().addElement(mappingExpression); normalizer.addAdditionalExpression(mappingExpression.and(additionalExpressionCriteria())); return this; } else if ((shouldUseOuterJoin() || isUsingOuterJoinForMultitableInheritance()) && (!getSession().getPlatform().shouldPrintOuterJoinInWhereClause())) { if (shouldUseOuterJoin()) { normalizer.getStatement().getOuterJoinExpressions().addElement(this); normalizer.getStatement().getOuterJoinedMappingCriteria().addElement(mappingExpression); normalizer .getStatement() .getOuterJoinedAdditionalJoinCriteria() .addElement(additionalExpressionCriteriaMap()); normalizer.getStatement().getDescriptorsForMultitableInheritanceOnly().add(null); return this; } else { if (isUsingOuterJoinForMultitableInheritance()) { normalizer.getStatement().getOuterJoinExpressions().addElement(null); normalizer.getStatement().getOuterJoinedMappingCriteria().addElement(null); normalizer .getStatement() .getOuterJoinedAdditionalJoinCriteria() .addElement(additionalExpressionCriteriaMap()); normalizer .getStatement() .getDescriptorsForMultitableInheritanceOnly() .add(getMapping().getReferenceDescriptor()); // fall through to the main case } } } // This must be added even if outer. Actually it should be converted to use a right outer // join, but that gets complex // so we do not support this current which is a limitation in some cases. if (foreignKeyJoinPointer != null) { // If this expression is right side of an objExp.equal(objExp), one // need not add additionalExpressionCriteria twice. // Also the join will replace the original objExp.equal(objExp). // For CR#2456. foreignKeyJoinPointer.add(mappingExpression); } else { normalizer.addAdditionalExpression(mappingExpression.and(additionalExpressionCriteria())); } } // For bug 2900974 special code for DirectCollectionMappings moved to printSQL. return this; }
/** INTERNAL: Used for cloning. */ protected void postCopyIn(Map alreadyDone) { super.postCopyIn(alreadyDone); if (index != null) { index = (IndexExpression) index.copiedVersionFrom(alreadyDone); } }
/** Defines a join between this expression and the target expression based on the ON clause. */ @Override public Expression leftJoin(Expression target, Expression onClause) { join(target, onClause); ((ObjectExpression) target).doUseOuterJoin(); return this; }