-
Notifications
You must be signed in to change notification settings - Fork 868
/
ODeleteExecutionPlanner.java
180 lines (161 loc) · 6.89 KB
/
ODeleteExecutionPlanner.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
package com.orientechnologies.orient.core.sql.executor;
import com.orientechnologies.orient.core.command.OCommandContext;
import com.orientechnologies.orient.core.exception.OCommandExecutionException;
import com.orientechnologies.orient.core.index.OIndex;
import com.orientechnologies.orient.core.sql.parser.*;
import java.util.List;
/**
* Created by luigidellaquila on 08/08/16.
*/
public class ODeleteExecutionPlanner {
private final OFromClause fromClause;
private final OWhereClause whereClause;
private final boolean returnBefore;
private final OLimit limit;
private final boolean unsafe;
public ODeleteExecutionPlanner(ODeleteStatement stm) {
this.fromClause = stm.getFromClause() == null ? null : stm.getFromClause().copy();
this.whereClause = stm.getWhereClause() == null ? null : stm.getWhereClause().copy();
this.returnBefore = stm.isReturnBefore();
this.limit = stm.getLimit() == null ? null : stm.getLimit();
this.unsafe = stm.isUnsafe();
}
public ODeleteExecutionPlan createExecutionPlan(OCommandContext ctx) {
ODeleteExecutionPlan result = new ODeleteExecutionPlan(ctx);
if (handleIndexAsTarget(result, fromClause.getItem().getIndex(), whereClause, ctx)) {
if (limit != null) {
throw new OCommandExecutionException("Cannot apply a LIMIT on a delete from index");
}
if (unsafe) {
throw new OCommandExecutionException("Cannot apply a UNSAFE on a delete from index");
}
if (returnBefore) {
throw new OCommandExecutionException("Cannot apply a RETURN BEFORE on a delete from index");
}
handleReturn(result, ctx, this.returnBefore);
} else {
handleTarget(result, ctx, this.fromClause, this.whereClause);
handleUnsafe(result, ctx, this.unsafe);
handleLimit(result, ctx, this.limit);
handleDelete(result, ctx);
handleReturn(result, ctx, this.returnBefore);
}
return result;
}
private boolean handleIndexAsTarget(ODeleteExecutionPlan result, OIndexIdentifier indexIdentifier, OWhereClause whereClause,
OCommandContext ctx) {
if (indexIdentifier == null) {
return false;
}
String indexName = indexIdentifier.getIndexName();
OIndex<?> index = ctx.getDatabase().getMetadata().getIndexManager().getIndex(indexName);
if (index == null) {
throw new OCommandExecutionException("Index not found: " + indexName);
}
List<OAndBlock> flattenedWhereClause = whereClause == null ? null : whereClause.flatten();
switch (indexIdentifier.getType()) {
case INDEX:
OBooleanExpression keyCondition = null;
OBooleanExpression ridCondition = null;
if (flattenedWhereClause == null || flattenedWhereClause.size() == 0) {
if (!index.supportsOrderedIterations()) {
throw new OCommandExecutionException("Index " + indexName + " does not allow iteration without a condition");
}
} else if (flattenedWhereClause.size() > 2) {
throw new OCommandExecutionException("Index queries with this kind of condition are not supported yet: " + whereClause);
} else {
OAndBlock andBlock = flattenedWhereClause.get(0);
if (andBlock.getSubBlocks().size() == 1) {
whereClause = null;//The WHERE clause won't be used anymore, the index does all the filtering
flattenedWhereClause = null;
keyCondition = getKeyCondition(andBlock);
if (keyCondition == null) {
throw new OCommandExecutionException("Index queries with this kind of condition are not supported yet: " + whereClause);
}
} else if (andBlock.getSubBlocks().size() == 2) {
whereClause = null;//The WHERE clause won't be used anymore, the index does all the filtering
flattenedWhereClause = null;
keyCondition = getKeyCondition(andBlock);
ridCondition = getRidCondition(andBlock);
if (keyCondition == null || ridCondition == null) {
throw new OCommandExecutionException("Index queries with this kind of condition are not supported yet: " + whereClause);
}
} else {
throw new OCommandExecutionException("Index queries with this kind of condition are not supported yet: " + whereClause);
}
}
result.chain(new DeleteFromIndexStep(index, keyCondition, null, ctx));
if (ridCondition != null) {
OWhereClause where = new OWhereClause(-1);
where.setBaseExpression(ridCondition);
result.chain(new FilterStep(where, ctx));
}
return true;
case VALUES:
case VALUESASC:
if (!index.supportsOrderedIterations()) {
throw new OCommandExecutionException("Index " + indexName + " does not allow iteration on values");
}
result.chain(new FetchFromIndexValuesStep(index, true, ctx));
result.chain(new GetValueFromIndexEntryStep(ctx));
break;
case VALUESDESC:
if (!index.supportsOrderedIterations()) {
throw new OCommandExecutionException("Index " + indexName + " does not allow iteration on values");
}
result.chain(new FetchFromIndexValuesStep(index, false, ctx));
result.chain(new GetValueFromIndexEntryStep(ctx));
break;
}
return false;
}
private void handleDelete(ODeleteExecutionPlan result, OCommandContext ctx) {
result.chain(new DeleteStep(ctx));
}
private void handleUnsafe(ODeleteExecutionPlan result, OCommandContext ctx, boolean unsafe) {
if (!unsafe) {
result.chain(new CheckSafeDeleteStep(ctx));
}
}
private void handleReturn(ODeleteExecutionPlan result, OCommandContext ctx, boolean returnBefore) {
if (!returnBefore) {
result.chain(new CountStep(ctx));
}
}
private void handleLimit(OUpdateExecutionPlan plan, OCommandContext ctx, OLimit limit) {
if (limit != null) {
plan.chain(new LimitExecutionStep(limit, ctx));
}
}
private void handleTarget(OUpdateExecutionPlan result, OCommandContext ctx, OFromClause target, OWhereClause whereClause) {
OSelectStatement sourceStatement = new OSelectStatement(-1);
sourceStatement.setTarget(target);
sourceStatement.setWhereClause(whereClause);
OSelectExecutionPlanner planner = new OSelectExecutionPlanner(sourceStatement);
result.chain(new SubQueryStep(planner.createExecutionPlan(ctx), ctx, ctx));
}
private OBooleanExpression getKeyCondition(OAndBlock andBlock) {
for (OBooleanExpression exp : andBlock.getSubBlocks()) {
String str = exp.toString();
if (str.length() < 5) {
continue;
}
if (str.substring(0, 4).equalsIgnoreCase("key ")) {
return exp;
}
}
return null;
}
private OBooleanExpression getRidCondition(OAndBlock andBlock) {
for (OBooleanExpression exp : andBlock.getSubBlocks()) {
String str = exp.toString();
if (str.length() < 5) {
continue;
}
if (str.substring(0, 4).equalsIgnoreCase("rid ")) {
return exp;
}
}
return null;
}
}