1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package org.modeshape.graph.query.optimize;
25
26 import java.util.Collections;
27 import java.util.HashSet;
28 import java.util.LinkedList;
29 import java.util.Set;
30 import net.jcip.annotations.Immutable;
31 import org.modeshape.graph.query.QueryContext;
32 import org.modeshape.graph.query.model.Column;
33 import org.modeshape.graph.query.model.Constraint;
34 import org.modeshape.graph.query.model.EquiJoinCondition;
35 import org.modeshape.graph.query.model.JoinCondition;
36 import org.modeshape.graph.query.model.PropertyExistence;
37 import org.modeshape.graph.query.model.PropertyValue;
38 import org.modeshape.graph.query.model.ReferenceValue;
39 import org.modeshape.graph.query.model.SelectorName;
40 import org.modeshape.graph.query.model.Visitable;
41 import org.modeshape.graph.query.model.Visitors;
42 import org.modeshape.graph.query.model.Visitors.AbstractVisitor;
43 import org.modeshape.graph.query.plan.PlanNode;
44 import org.modeshape.graph.query.plan.PlanUtil;
45 import org.modeshape.graph.query.plan.PlanNode.Property;
46 import org.modeshape.graph.query.plan.PlanNode.Type;
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114 @Immutable
115 public class RaiseSelectCriteria implements OptimizerRule {
116
117 public static final RaiseSelectCriteria INSTANCE = new RaiseSelectCriteria();
118
119
120
121
122
123
124
125 public PlanNode execute( QueryContext context,
126 PlanNode plan,
127 LinkedList<OptimizerRule> ruleStack ) {
128 Set<PlanNode> copiedSelectNodes = new HashSet<PlanNode>();
129
130 for (PlanNode join : plan.findAllAtOrBelow(Type.JOIN)) {
131
132 JoinCondition joinCondition = join.getProperty(Property.JOIN_CONDITION, JoinCondition.class);
133 if (joinCondition instanceof EquiJoinCondition) {
134 EquiJoinCondition equiJoinCondition = (EquiJoinCondition)joinCondition;
135 SelectorName selector1 = equiJoinCondition.selector1Name();
136 SelectorName selector2 = equiJoinCondition.selector2Name();
137 String property1 = equiJoinCondition.property1Name();
138 String property2 = equiJoinCondition.property2Name();
139
140
141 PlanNode node = join.getParent();
142 while (node != null) {
143 if (!copiedSelectNodes.contains(node)) {
144 PlanNode copy = copySelectNode(context, node, selector1, property1, selector2, property2);
145 if (copy != null) {
146 node.insertAsParent(copy);
147 copiedSelectNodes.add(node);
148 copiedSelectNodes.add(copy);
149 } else {
150 copy = copySelectNode(context, node, selector2, property2, selector1, property1);
151 if (copy != null) {
152 node.insertAsParent(copy);
153 copiedSelectNodes.add(node);
154 copiedSelectNodes.add(copy);
155 }
156 }
157 }
158 node = node.getParent();
159 }
160 }
161 }
162 return plan;
163 }
164
165 protected PlanNode copySelectNode( QueryContext context,
166 PlanNode selectNode,
167 SelectorName selectorName,
168 String propertyName,
169 SelectorName copySelectorName,
170 String copyPropertyName ) {
171 if (selectNode.isNot(Type.SELECT)) return null;
172 if (selectNode.getSelectors().size() != 1 || !selectNode.getSelectors().contains(selectorName)) return null;
173
174 Constraint constraint = selectNode.getProperty(Property.SELECT_CRITERIA, Constraint.class);
175 Set<Column> columns = getColumnsReferencedBy(constraint);
176 if (columns.size() != 1) return null;
177 Column column = columns.iterator().next();
178 if (!column.selectorName().equals(selectorName)) return null;
179 if (!column.propertyName().equals(propertyName)) return null;
180
181
182
183
184
185 PlanNode copy = new PlanNode(Type.SELECT, copySelectorName);
186
187
188 PlanUtil.ColumnMapping mappings = new PlanUtil.ColumnMapping(selectorName);
189 mappings.map(propertyName, new Column(copySelectorName, copyPropertyName, copyPropertyName));
190 Constraint newCriteria = PlanUtil.replaceReferences(context, constraint, mappings, copy);
191 copy.setProperty(Property.SELECT_CRITERIA, newCriteria);
192
193 return copy;
194 }
195
196
197
198
199
200
201 @Override
202 public String toString() {
203 return getClass().getSimpleName();
204 }
205
206
207
208
209
210
211
212
213 public static Set<Column> getColumnsReferencedBy( Visitable visitable ) {
214 if (visitable == null) return Collections.emptySet();
215 final Set<Column> symbols = new HashSet<Column>();
216
217 Visitors.visitAll(visitable, new AbstractVisitor() {
218 protected void addColumnFor( SelectorName selectorName,
219 String property ) {
220 symbols.add(new Column(selectorName, property, property));
221 }
222
223 @Override
224 public void visit( Column column ) {
225 symbols.add(column);
226 }
227
228 @Override
229 public void visit( EquiJoinCondition joinCondition ) {
230 addColumnFor(joinCondition.selector1Name(), joinCondition.property1Name());
231 addColumnFor(joinCondition.selector2Name(), joinCondition.property2Name());
232 }
233
234 @Override
235 public void visit( PropertyExistence prop ) {
236 addColumnFor(prop.selectorName(), prop.propertyName());
237 }
238
239 @Override
240 public void visit( PropertyValue prop ) {
241 addColumnFor(prop.selectorName(), prop.propertyName());
242 }
243
244 @Override
245 public void visit( ReferenceValue ref ) {
246 String propertyName = ref.propertyName();
247 if (propertyName != null) {
248 addColumnFor(ref.selectorName(), propertyName);
249 }
250 }
251 });
252 return symbols;
253 }
254
255 }