RelationExpressionpublic class RelationExpression extends CompoundExpression Purpose:Used for all relation operators except for between. |
Constructors Summary |
---|
public RelationExpression()RelationExpression constructor comment.
super();
|
Methods Summary |
---|
protected boolean | allChildrenAreFields()Test that both of our children are field nodes
return (getFirstChild().getFields().size() == 1) && (getSecondChild().getFields().size() == 1);
| protected void | convertNodeToUseOuterJoin()INTERNAL:
Modify this individual expression node to use outer joins wherever there are
equality operations between two field nodes.
if ((getOperator().getSelector() == ExpressionOperator.Equal) && allChildrenAreFields()) {
setOperator(getOperator(ExpressionOperator.EqualOuterJoin));
}
| public java.lang.String | descriptionOfNodeType()INTERNAL:
Used for debug printing.
return "Relation";
| protected boolean | doValuesConform(java.lang.Object leftValue, java.lang.Object rightValue, oracle.toplink.essentials.internal.sessions.AbstractSession session)Conform in-memory the two values.
// Check for object comparison.
if (isObjectComparison()) {
return doesObjectConform(leftValue, rightValue, session);
} else {
return getOperator().doesRelationConform(leftValue, rightValue);
}
| protected boolean | doesAnyOfLeftValuesConform(java.util.Vector leftValues, java.lang.Object rightValue, oracle.toplink.essentials.internal.sessions.AbstractSession session)Conform in-memory the collection of left values with the right value for this expression.
This is used for anyOf support when the left side is a collection of values.
// Check each left value with the right value.
for (int index = 0; index < leftValues.size(); index++) {
Object leftValue = leftValues.get(index);
if (doValuesConform(leftValue, rightValue, session)) {
// Return true if any value matches.
return true;
}
}
// Return false only if none of the values match.
return false;
| public boolean | doesConform(java.lang.Object object, oracle.toplink.essentials.internal.sessions.AbstractSession session, oracle.toplink.essentials.internal.sessions.AbstractRecord translationRow, oracle.toplink.essentials.queryframework.InMemoryQueryIndirectionPolicy valueHolderPolicy, boolean isObjectUnregistered)INTERNAL:
Check if the object conforms to the expression in memory.
This is used for in-memory querying.
If the expression in not able to determine if the object conform throw a not supported exception.
// Extract the value from the right side.
//CR 3677 integration of valueHolderPolicy
Object rightValue = getSecondChild().valueFromObject(object, session, translationRow, valueHolderPolicy, isObjectUnregistered);
// Extract the value from the object.
//CR 3677 integration of valueHolderPolicy
Object leftValue = getFirstChild().valueFromObject(object, session, translationRow, valueHolderPolicy, isObjectUnregistered);
// The right value may be a vector of values from an anyof, or an in.
if (rightValue instanceof Vector) {
//right vector means an anyof on right, so must check each value.
for (Enumeration rightEnum = (Enumeration)((Vector)rightValue).elements();
rightEnum.hasMoreElements();) {
Object tempRight = rightEnum.nextElement();
// Left may also be an anyof some must check each left with each right.
if (leftValue instanceof Vector) {
// If anyof the left match return true, otherwise keep checking.
if (doesAnyOfLeftValuesConform((Vector)leftValue, tempRight, session)) {
return true;
}
}
if (doValuesConform(leftValue, tempRight, session)) {
return true;
}
}
// None of the value conform.
return false;
}
// Otherwise the left may also be a vector of values from an anyof.
if (leftValue instanceof Vector) {
return doesAnyOfLeftValuesConform((Vector)leftValue, rightValue, session);
}
// Otherwise it is a simple value to value comparison, or simple object to object comparison.
return doValuesConform(leftValue, rightValue, session);
| public boolean | doesObjectConform(java.lang.Object leftValue, java.lang.Object rightValue, oracle.toplink.essentials.internal.sessions.AbstractSession session)INTERNAL:
Check if the object conforms to the expression in memory.
This is used for in-memory querying across object relationships.
if ((leftValue == null) && (rightValue == null)) {
return performSelector(true);
}
if ((leftValue == null) || (rightValue == null)) {
//both are not null.
return performSelector(false);
}
Class javaClass = leftValue.getClass();
Vector leftPrimaryKey;
Vector rightPrimaryKey;
ClassDescriptor descriptor;
oracle.toplink.essentials.internal.identitymaps.CacheKey rightCacheKey;
oracle.toplink.essentials.internal.identitymaps.CacheKey leftCacheKey;
if (javaClass != rightValue.getClass()) {
return performSelector(false);
}
descriptor = session.getDescriptor(javaClass);
// Currently cannot conform aggregate comparisons in-memory.
if (descriptor.isAggregateDescriptor()) {
throw QueryException.cannotConformExpression();
}
leftPrimaryKey = descriptor.getObjectBuilder().extractPrimaryKeyFromObject(leftValue, session);
rightPrimaryKey = descriptor.getObjectBuilder().extractPrimaryKeyFromObject(rightValue, session);
rightCacheKey = new oracle.toplink.essentials.internal.identitymaps.CacheKey(rightPrimaryKey);
leftCacheKey = new oracle.toplink.essentials.internal.identitymaps.CacheKey(leftPrimaryKey);
return performSelector(rightCacheKey.equals(leftCacheKey));
| public boolean | extractPrimaryKeyValues(boolean requireExactMatch, oracle.toplink.essentials.descriptors.ClassDescriptor descriptor, oracle.toplink.essentials.internal.sessions.AbstractRecord primaryKeyRow, oracle.toplink.essentials.internal.sessions.AbstractRecord translationRow)INTERNAL:
Extract the primary key from the expression into the row.
Ensure that the query is quering the exact primary key.
// If an exact match is required then the operator must be equality.
if (requireExactMatch && (!(getOperator().getSelector() == ExpressionOperator.Equal))) {
return false;
}
// If not an exact match only =, <, <=, >=, >,... are allowed but not IN which has a different type
if ((!requireExactMatch) && (getOperator().getSelector() == ExpressionOperator.In)) {
return false;
}
DatabaseField field = null;
Object value = null;
if (getSecondChild().isConstantExpression()) {
value = ((ConstantExpression)getSecondChild()).getValue();
} else if (getSecondChild().isParameterExpression()) {
value = translationRow.get(((ParameterExpression)getSecondChild()).getField());
} else if (getFirstChild().isConstantExpression()) {
value = ((ConstantExpression)getFirstChild()).getValue();
} else if (getFirstChild().isParameterExpression()) {
value = translationRow.get(((ParameterExpression)getFirstChild()).getField());
}
if (value == null) {
return false;
}
// Ensure that the primary key is being queried on.
if (getFirstChild().isFieldExpression()) {
// Only get field for the source object.
if (getFirstChild().getBuilder() != ((FieldExpression)getFirstChild()).getBaseExpression()) {
return false;
}
field = ((FieldExpression)getFirstChild()).getField();
} else if (getFirstChild().isQueryKeyExpression()) {
DatabaseMapping mapping = descriptor.getMappingForAttributeName(((QueryKeyExpression)getFirstChild()).getName());
if (getFirstChild().getBuilder() != ((QueryKeyExpression) getFirstChild()).getBaseExpression()){
return false;
}
// Only support referencing limited number of relationship types.
if (mapping != null && (!mapping.isPrimaryKeyMapping()) ){
return false;
}
if (mapping != null && (mapping.isObjectReferenceMapping() || mapping.isAggregateObjectMapping())){
mapping.writeFromAttributeIntoRow(value, primaryKeyRow, getSession());
return true;
}
if (mapping != null && !mapping.isDirectToFieldMapping()){
return false;
}
// Only get field for the source object.
field = descriptor.getObjectBuilder().getFieldForQueryKeyName(getFirstChild().getName());
} else if (getSecondChild().isFieldExpression()) {// For parameterized queries it may also be on the right side.
// Only get field for the source object.
if (getFirstChild().getBuilder() != ((FieldExpression)getSecondChild()).getBaseExpression()) {
return false;
}
field = ((FieldExpression)getSecondChild()).getField();
} else if (getSecondChild().isQueryKeyExpression()) {
DatabaseMapping mapping = descriptor.getMappingForAttributeName(((QueryKeyExpression)getSecondChild()).getName());
if (getSecondChild().getBuilder() != ((QueryKeyExpression) getSecondChild()).getBaseExpression() ){
return false;
}
// Only support referencing limited number of relationship types.
if (mapping != null && (!mapping.isPrimaryKeyMapping()) ){
return false;
}
if (mapping != null && (mapping.isObjectReferenceMapping() || mapping.isAggregateObjectMapping())){
mapping.writeFromAttributeIntoRow(value, primaryKeyRow, getSession());
return true;
}
if (mapping != null && !mapping.isDirectToFieldMapping()){
return false;
}
field = descriptor.getObjectBuilder().getFieldForQueryKeyName(getSecondChild().getName());
} else {
return false;
}
if ((field == null) || (!descriptor.getPrimaryKeyFields().contains(field))) {
return false;
}
primaryKeyRow.put(field, value);
return true;
| public boolean | isEqualNull(oracle.toplink.essentials.internal.expressions.ExpressionSQLPrinter printer)Check if the expression is an equal null expression, these must be handle in a special way in SQL.
if (isObjectComparison()) {
return false;
}
if (getOperator().getSelector() != ExpressionOperator.Equal) {
return false;
}
if (getSecondChild().isConstantExpression() && (((ConstantExpression)getSecondChild()).getValue() == null)) {
return true;
}
if (getSecondChild().isParameterExpression() && (printer.getTranslationRow() != null) && (((ParameterExpression)getSecondChild()).getValue(printer.getTranslationRow(), printer.getSession()) == null)) {
return true;
}
return false;
| public boolean | isNotEqualNull(oracle.toplink.essentials.internal.expressions.ExpressionSQLPrinter printer)Check if the expression is an equal null expression, these must be handle in a special way in SQL.
if (isObjectComparison()) {
return false;
}
if (getOperator().getSelector() != ExpressionOperator.NotEqual) {
return false;
}
if (getSecondChild().isConstantExpression() && (((ConstantExpression)getSecondChild()).getValue() == null)) {
return true;
}
if (getSecondChild().isParameterExpression() && (printer.getTranslationRow() != null) && (((ParameterExpression)getSecondChild()).getValue(printer.getTranslationRow(), printer.getSession()) == null)) {
return true;
}
return false;
| protected boolean | isObjectComparison()INTERNAL:
Return if the represents an object comparison.
if ((!getFirstChild().isObjectExpression()) || ((ObjectExpression)getFirstChild()).isAttribute()) {
return false;
}
DatabaseMapping mapping = ((ObjectExpression)getFirstChild()).getMapping();
if ((mapping != null) && (mapping.isDirectCollectionMapping())) {
return false;
}
return getSecondChild().isObjectExpression() || (getSecondChild().isValueExpression() || (getSecondChild().isFunctionExpression() && ((FunctionExpression)getSecondChild()).getOperator().isAnyOrAll()));
| public boolean | isRelationExpression()INTERNAL:
return true;
| public oracle.toplink.essentials.expressions.Expression | normalize(oracle.toplink.essentials.internal.expressions.ExpressionNormalizer normalizer)INTERNAL:
Check for object comparison as this requires for the expression to be replaced by the object comparison.
if (!isObjectComparison()) {
return super.normalize(normalizer);
} else {
//bug # 2956674
//validation is moved into normalize to ensure that expressions are valid before we attempt to work with them
// super.normalize will call validateNode as well.
validateNode();
}
if ((getOperator().getSelector() != ExpressionOperator.Equal) && (getOperator().getSelector() != ExpressionOperator.NotEqual)) {
throw QueryException.invalidOperatorForObjectComparison(this);
}
if(getSecondChild().isFunctionExpression()) {
FunctionExpression funcExp = (FunctionExpression)getSecondChild();
if(funcExp.getOperator().isAnyOrAll()) {
SubSelectExpression subSelectExp = (SubSelectExpression)funcExp.getChildren().elementAt(1);
ReportQuery subQuery = subSelectExp.getSubQuery();
// some db (derby) require that in EXIST(SELECT...) subquery returns a single column
subQuery.getItems().clear();
subQuery.addItem("one", new ConstantExpression(new Integer(1), subQuery.getExpressionBuilder()));
Expression subSelectCriteria = subQuery.getSelectionCriteria();
ExpressionBuilder subBuilder = subQuery.getExpressionBuilder();
ExpressionBuilder builder = getFirstChild().getBuilder();
Expression newExp;
if(funcExp.getOperator().isAny()) {
// Any or Some
if(getOperator().getSelector() == ExpressionOperator.Equal) {
subSelectCriteria = subBuilder.equal(getFirstChild()).and(subSelectCriteria);
} else {
subSelectCriteria = subBuilder.notEqual(getFirstChild()).and(subSelectCriteria);
}
subQuery.setSelectionCriteria(subSelectCriteria);
newExp = builder.exists(subQuery);
} else {
// All
if(getOperator().getSelector() == ExpressionOperator.Equal) {
subSelectCriteria = subBuilder.notEqual(getFirstChild()).and(subSelectCriteria);
} else {
subSelectCriteria = subBuilder.equal(getFirstChild()).and(subSelectCriteria);
}
subQuery.setSelectionCriteria(subSelectCriteria);
newExp = builder.notExists(subQuery);
}
return newExp.normalize(normalizer);
}
}
// This can either be comparison to another object, null or another expression reference.
// Object comparisons can be done on other object builders, 1:1 or 1:m m:m mappings,
// 1:m/m:m must twist the primary key expression,
// 1:1 must not join into the target but become the foreign key expression.
// The value may be a constant or another expression.
Expression foreignKeyJoin = null;
ObjectExpression first = (ObjectExpression)getFirstChild();
// OPTIMIZATION 1: IDENTITY for CR#2456 / bug 2778339
// Most exists subqueries have something like projBuilder.equal(empBuilder.anyOf("projects"))
// to correlate the subquery to the enclosing query.
// TopLink can produce SQL with one less join by not mapping projBuilder and
// anyOf("projects") to separate tables and equating them, but by treating
// them as one and the same thing: as identical.
// This trick can be pulled off by giving both the same TableAliasLookup,
// but needs to be done very conservatively.
// the equal() will be replaced directly with the mappingCriteria() of the anyOf("projects")
// Example. emp.equal(emp.get("manager")) will now produce this SQL:
// SELECT ... FROM EMPLOYEE t0 WHERE (t0.EMP_ID = t0.MANAGER_ID) not:
// SELECT ... FROM EMPLOYEE t0, EMPLOYEE t1 WHERE ((t0.EMP_ID = t1.EMP_ID)
// AND (t0.MANAGER_ID = t1.EMP_ID))
if (first.isExpressionBuilder() &&// If setting two query keys to equal the user probably intends a proper join.
getSecondChild().isQueryKeyExpression() &&//.equal(anyOf() or get())
!((QueryKeyExpression)getSecondChild()).hasDerivedExpressions()) {//The right side is not used for anything else.
first = (ExpressionBuilder)first.normalize(normalizer);
// If FK joins go in the WHERE clause, want to get hold of it and
// not put it in normalizer.additionalExpressions.
Vector foreignKeyJoinPointer = new Vector(1);
QueryKeyExpression second = (QueryKeyExpression)getSecondChild();
// If inside an OR the foreign key join must be on both sides.
if (second.hasBeenNormalized()) {
second.setHasBeenNormalized(false);
}
second = (QueryKeyExpression)second.normalize(normalizer, foreignKeyJoinPointer);
if (!foreignKeyJoinPointer.isEmpty()) {
foreignKeyJoin = (Expression)foreignKeyJoinPointer.firstElement();
// Will make left and right identical in the SQL.
if (first.getTableAliases() == null) {
TableAliasLookup tableAliases = new TableAliasLookup();
first.setTableAliases(tableAliases);
second.setTableAliases(tableAliases);
} else {
second.setTableAliases(first.getTableAliases());
}
}
}
// OPTIMIZATION 2: for 1-1 mappings and get(...).equal(null)
// Imagine you had addr1 = emp.get("address"); then addr1.equal(addr2);
// One could go (addr1.ADDRESS_ID = addr2.ADDRESS_ID) and (emp.ADDR_ID = addr1.ADDRESS_ID) (foreign key join).
// The optimization is to drop addr1 and instead have: (emp.ADDR_ID = addr2.ADDRESS_ID).
// Since emp can have only 1 address (OneToOne) the addr1.equal(addr2) is
// implicit. This way if addr1 is used only for the comparison it can
// be optimized out.
// Also if addr2 were NULL there must be no join, just (emp.ADDR_ID = NULL)
// For bug 3105559 handle AggregateObject case (emp.get("period").equal(period2)
// which always falls into this case.
else if (!first.isExpressionBuilder() && !((QueryKeyExpression)first).isNormalizationRequired()) {
// Normalize firstChild's base only, as firstChild will be optimized out.
if (first.getBaseExpression() != null) {
first.setBaseExpression(first.getBaseExpression().normalize(normalizer));
}
if (getSecondChild().isConstantExpression()) {
Object targetObject = ((ConstantExpression)getSecondChild()).getValue();
foreignKeyJoin = first.getMapping().buildObjectJoinExpression(first, targetObject, getSession());
} else if (getSecondChild().isObjectExpression() || getSecondChild().isParameterExpression()) {
foreignKeyJoin = first.getMapping().buildObjectJoinExpression(first, getSecondChild(), getSession());
} else {
throw QueryException.invalidUseOfToManyQueryKeyInExpression(this);
}
}
// DEFAULT: Left and right are separate entities, and the
// equal() will be replaced with a comparison by primary key.
if (foreignKeyJoin == null) {
first = (ObjectExpression)first.normalize(normalizer);
// A ConstantExpression stores a selection object. Compare the primary
// keys of the first expression and the selection object.
if (getSecondChild().isConstantExpression()) {
Expression keyExpression = first.getDescriptor().getObjectBuilder().buildPrimaryKeyExpressionFromObject(((ConstantExpression)getSecondChild()).getValue(), getSession());
foreignKeyJoin = first.twist(keyExpression, first);
// Each expression will represent a separate table, so compare the primary
// keys of the first and second expressions.
} else if (getSecondChild().isObjectExpression() || getSecondChild().isParameterExpression()) {
foreignKeyJoin = first.twist(first.getDescriptor().getObjectBuilder().getPrimaryKeyExpression(), getSecondChild());
} else {
throw QueryException.invalidUseOfToManyQueryKeyInExpression(this);
}
}
if (getOperator().getSelector() == ExpressionOperator.NotEqual) {
foreignKeyJoin = foreignKeyJoin.not();
}
return foreignKeyJoin.normalize(normalizer);
| public boolean | performSelector(boolean areValuesEqual)INTERNAL:
Check if the object conforms to the expression in memory.
This is used for in-memory querying across object relationships.
if (getOperator().getSelector() == getOperator().Equal) {
return areValuesEqual;
}
if (getOperator().getSelector() == getOperator().NotEqual) {
return !areValuesEqual;
}
throw QueryException.cannotConformExpression();
| public void | printJava(oracle.toplink.essentials.internal.expressions.ExpressionJavaPrinter printer)INTERNAL:
Print java for project class generation
ExpressionOperator realOperator = getPlatformOperator(printer.getPlatform());
Expression tempFirstChild = getFirstChild();
Expression tempSecondChild = getSecondChild();
realOperator.printJavaDuo(tempFirstChild, tempSecondChild, printer);
| public void | printSQL(oracle.toplink.essentials.internal.expressions.ExpressionSQLPrinter printer)INTERNAL:
Print SQL
if (isEqualNull(printer)) {
getFirstChild().isNull().printSQL(printer);
} else if (isNotEqualNull(printer)) {
getFirstChild().notNull().printSQL(printer);
} else {
super.printSQL(printer);
}
| public void | printSQLNoParens(oracle.toplink.essentials.internal.expressions.ExpressionSQLPrinter printer)INTERNAL:
Print SQL without adding parentheses (for DB2 outer joins).
ExpressionOperator realOperator = getPlatformOperator(printer.getPlatform());
realOperator.printDuo(getFirstChild(), getSecondChild(), printer);
| public void | validateNode()Do any required validation for this node. Throw an exception if it's incorrect.
if (getFirstChild().isTableExpression()) {
throw QueryException.cannotCompareTablesInExpression(((TableExpression)getFirstChild()).getTable());
}
if (getSecondChild().isTableExpression()) {
throw QueryException.cannotCompareTablesInExpression(((TableExpression)getSecondChild()).getTable());
}
|
|