org.modeshape.jcr.query.optimize.AddJoinConditionColumnsToSources Maven / Gradle / Ivy
/*
* ModeShape (http://www.modeshape.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.modeshape.jcr.query.optimize;
import java.util.LinkedList;
import java.util.List;
import org.modeshape.jcr.query.QueryContext;
import org.modeshape.jcr.query.model.Column;
import org.modeshape.jcr.query.model.EquiJoinCondition;
import org.modeshape.jcr.query.model.JoinCondition;
import org.modeshape.jcr.query.model.SelectorName;
import org.modeshape.jcr.query.plan.PlanNode;
import org.modeshape.jcr.query.plan.PlanNode.Property;
import org.modeshape.jcr.query.plan.PlanNode.Type;
/**
* An {@link OptimizerRule} that adds any missing columns required by the join conditions to the appropriate join source.
*/
public class AddJoinConditionColumnsToSources implements OptimizerRule {
public static final AddJoinConditionColumnsToSources INSTANCE = new AddJoinConditionColumnsToSources();
@Override
public PlanNode execute( QueryContext context,
PlanNode plan,
LinkedList ruleStack ) {
final boolean includeSourceName = context.getHints().qualifyExpandedColumnNames;
// For each of the JOIN nodes ...
for (PlanNode joinNode : plan.findAllAtOrBelow(Type.JOIN)) {
JoinCondition condition = joinNode.getProperty(Property.JOIN_CONDITION, JoinCondition.class);
if (condition instanceof EquiJoinCondition) {
EquiJoinCondition equiJoinCondition = (EquiJoinCondition)condition;
SelectorName selector1 = equiJoinCondition.selector1Name();
Column joinColumn1 = columnFor(equiJoinCondition.selector1Name(),
equiJoinCondition.getProperty1Name(),
includeSourceName);
Column joinColumn2 = columnFor(equiJoinCondition.selector2Name(),
equiJoinCondition.getProperty2Name(),
includeSourceName);
// Figure out which side of the join condition goes with which side of the plan nodes ...
PlanNode left = joinNode.getFirstChild();
PlanNode right = joinNode.getLastChild();
if (left.getSelectors().contains(selector1)) {
addEquiJoinColumn(context, left, joinColumn1);
addEquiJoinColumn(context, right, joinColumn2);
} else {
addEquiJoinColumn(context, left, joinColumn2);
addEquiJoinColumn(context, right, joinColumn1);
}
}
}
return plan;
}
/**
* Make sure that the supplied column is included in the {@link Property#PROJECT_COLUMNS projected columns} on the supplied
* plan node or its children.
*
* @param context the query context; may not be null
* @param node the query plan node
* @param joinColumn the column required by the join
*/
protected void addEquiJoinColumn( QueryContext context,
PlanNode node,
Column joinColumn ) {
if (node.getSelectors().contains(joinColumn.selectorName())) {
// Get the existing projected columns ...
List columns = node.getPropertyAsList(Property.PROJECT_COLUMNS, Column.class);
List types = node.getPropertyAsList(Property.PROJECT_COLUMN_TYPES, String.class);
if (columns != null && addIfMissing(context, joinColumn, columns, types)) {
node.setProperty(Property.PROJECT_COLUMNS, columns);
node.setProperty(Property.PROJECT_COLUMN_TYPES, types);
}
}
// Apply recursively ...
for (PlanNode child : node) {
addEquiJoinColumn(context, child, joinColumn);
}
}
/**
* Check the supplied list of columns for an existing column that matches the supplied {@link Column}, and if none is found
* add the supplied Column to the list and add an appropriate type.
*
* @param context the query context
* @param column the column that will be added if not already in the list; may not be null
* @param columns the list of columns; may not be null
* @param columnTypes the list of column types; may not be null
* @return true if the column was added (i.e., the lists were modified), or false if the lists were not modified
*/
protected boolean addIfMissing( QueryContext context,
Column column,
List columns,
List columnTypes ) {
for (Column c : columns) {
if (!c.selectorName().equals(column.selectorName())) continue;
String cName = c.getPropertyName();
if (cName.equals(column.getPropertyName()) || cName.equals(column.getColumnName())) return false;
cName = c.getColumnName();
if (cName.equals(column.getPropertyName()) || cName.equals(column.getColumnName())) return false;
}
columns.add(column);
columnTypes.add(context.getTypeSystem().getDefaultType());
return true;
}
protected Column columnFor( SelectorName selector,
String property,
boolean includeSourceName ) {
String columnName = includeSourceName ? selector.getString() + "." + property : property;
return new Column(selector, property, columnName);
}
@Override
public String toString() {
return getClass().getSimpleName();
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy