rawsql-ts 0.26.0 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/index.min.js +2 -2
- package/dist/esm/index.min.js.map +4 -4
- package/dist/esm/transformers/ConditionOptimization.d.ts +11 -1
- package/dist/esm/transformers/ConditionOptimization.js +122 -66
- package/dist/esm/transformers/ConditionOptimization.js.map +1 -1
- package/dist/esm/transformers/ParameterConditionPlacementOptimizer.d.ts +26 -7
- package/dist/esm/transformers/ParameterConditionPlacementOptimizer.js +408 -141
- package/dist/esm/transformers/ParameterConditionPlacementOptimizer.js.map +1 -1
- package/dist/esm/transformers/SSSQLFilterBuilder.d.ts +6 -0
- package/dist/esm/transformers/SSSQLFilterBuilder.js +84 -8
- package/dist/esm/transformers/SSSQLFilterBuilder.js.map +1 -1
- package/dist/esm/transformers/SqlComponentFormatter.d.ts +11 -0
- package/dist/esm/transformers/SqlComponentFormatter.js +16 -0
- package/dist/esm/transformers/SqlComponentFormatter.js.map +1 -0
- package/dist/esm/transformers/StaticPredicatePlacementOptimizer.d.ts +103 -0
- package/dist/esm/transformers/StaticPredicatePlacementOptimizer.js +1435 -0
- package/dist/esm/transformers/StaticPredicatePlacementOptimizer.js.map +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +2 -2
- package/dist/index.min.js.map +4 -4
- package/dist/src/index.d.ts +2 -0
- package/dist/src/transformers/ConditionOptimization.d.ts +11 -1
- package/dist/src/transformers/ParameterConditionPlacementOptimizer.d.ts +26 -7
- package/dist/src/transformers/SSSQLFilterBuilder.d.ts +6 -0
- package/dist/src/transformers/SqlComponentFormatter.d.ts +11 -0
- package/dist/src/transformers/StaticPredicatePlacementOptimizer.d.ts +103 -0
- package/dist/transformers/ConditionOptimization.js +146 -65
- package/dist/transformers/ConditionOptimization.js.map +1 -1
- package/dist/transformers/ParameterConditionPlacementOptimizer.js +407 -140
- package/dist/transformers/ParameterConditionPlacementOptimizer.js.map +1 -1
- package/dist/transformers/SSSQLFilterBuilder.js +92 -16
- package/dist/transformers/SSSQLFilterBuilder.js.map +1 -1
- package/dist/transformers/SqlComponentFormatter.js +21 -0
- package/dist/transformers/SqlComponentFormatter.js.map +1 -0
- package/dist/transformers/StaticPredicatePlacementOptimizer.js +1445 -0
- package/dist/transformers/StaticPredicatePlacementOptimizer.js.map +1 -0
- package/dist/tsconfig.browser.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -6,13 +6,11 @@ const SelectQuery_1 = require("../models/SelectQuery");
|
|
|
6
6
|
const ValueComponent_1 = require("../models/ValueComponent");
|
|
7
7
|
const SelectQueryParser_1 = require("../parsers/SelectQueryParser");
|
|
8
8
|
const ValueParser_1 = require("../parsers/ValueParser");
|
|
9
|
-
const
|
|
9
|
+
const SqlComponentFormatter_1 = require("./SqlComponentFormatter");
|
|
10
|
+
const SelectOutputCollector_1 = require("./SelectOutputCollector");
|
|
10
11
|
const SUPPORTED_OPERATORS = new Set(["=", "<>", "!=", "<", "<=", ">", ">=", "like", "ilike", "in"]);
|
|
11
12
|
const VOLATILE_OR_UNSUPPORTED_FUNCTION_REASON = "Condition contains a function call; volatile and expression predicates are not moved in the safe-only implementation.";
|
|
12
13
|
const normalizeIdentifier = (value) => value.trim().toLowerCase();
|
|
13
|
-
const formatSqlComponent = (component) => {
|
|
14
|
-
return new SqlFormatter_1.SqlFormatter().format(component).formattedSql;
|
|
15
|
-
};
|
|
16
14
|
const unwrapParens = (expression) => {
|
|
17
15
|
let candidate = expression;
|
|
18
16
|
while (candidate instanceof ValueComponent_1.ParenExpression) {
|
|
@@ -51,8 +49,8 @@ const rebuildWhereWithoutTerms = (query, termsToRemove) => {
|
|
|
51
49
|
}
|
|
52
50
|
query.whereClause = new Clause_1.WhereClause(rebuilt);
|
|
53
51
|
};
|
|
54
|
-
const cloneValueComponent = (expression) => {
|
|
55
|
-
return ValueParser_1.ValueParser.parse(formatSqlComponent(expression));
|
|
52
|
+
const cloneValueComponent = (expression, options) => {
|
|
53
|
+
return ValueParser_1.ValueParser.parse((0, SqlComponentFormatter_1.formatSqlComponent)(expression, options));
|
|
56
54
|
};
|
|
57
55
|
const cloneColumnReference = (reference) => {
|
|
58
56
|
var _a, _b;
|
|
@@ -75,11 +73,12 @@ const appendUnique = (items, value) => {
|
|
|
75
73
|
class ParameterConditionPlacementOptimizer {
|
|
76
74
|
plan(input, options = {}) {
|
|
77
75
|
var _a, _b, _c;
|
|
78
|
-
const parsed = this.parseInput(input);
|
|
76
|
+
const parsed = this.parseInput(input, options);
|
|
79
77
|
const warnings = [...parsed.warnings];
|
|
80
78
|
const errors = [...parsed.errors];
|
|
81
79
|
if (!parsed.query) {
|
|
82
80
|
return this.buildResult({
|
|
81
|
+
query: null,
|
|
83
82
|
sql: parsed.sql,
|
|
84
83
|
applied: [],
|
|
85
84
|
skipped: [],
|
|
@@ -95,6 +94,7 @@ class ParameterConditionPlacementOptimizer {
|
|
|
95
94
|
message: "Parameter condition placement currently supports only SimpleSelectQuery roots."
|
|
96
95
|
});
|
|
97
96
|
return this.buildResult({
|
|
97
|
+
query: parsed.query,
|
|
98
98
|
sql: parsed.sql,
|
|
99
99
|
applied: [],
|
|
100
100
|
skipped: [],
|
|
@@ -109,40 +109,75 @@ class ParameterConditionPlacementOptimizer {
|
|
|
109
109
|
const skipped = [];
|
|
110
110
|
const movedTerms = [];
|
|
111
111
|
for (const term of query.whereClause ? collectTopLevelAndTerms(query.whereClause.condition) : []) {
|
|
112
|
-
const candidate = this.analyzeCandidate(term);
|
|
112
|
+
const candidate = this.analyzeCandidate(term, options);
|
|
113
113
|
if (!candidate) {
|
|
114
114
|
continue;
|
|
115
115
|
}
|
|
116
116
|
if ("code" in candidate) {
|
|
117
|
-
skipped.push(this.makeSkipped(term, candidate));
|
|
117
|
+
skipped.push(this.makeSkipped(term, candidate, options));
|
|
118
118
|
continue;
|
|
119
119
|
}
|
|
120
120
|
const target = this.resolveTarget(query, candidate);
|
|
121
121
|
if ("code" in target) {
|
|
122
|
-
skipped.push(this.makeSkipped(term, target));
|
|
122
|
+
skipped.push(this.makeSkipped(term, target, options));
|
|
123
123
|
continue;
|
|
124
124
|
}
|
|
125
|
-
|
|
126
|
-
if ("
|
|
127
|
-
|
|
128
|
-
|
|
125
|
+
let appliedReason = "";
|
|
126
|
+
if (target.kind === "simple") {
|
|
127
|
+
const targetColumns = this.resolveTargetColumns(query, target.query, candidate.references);
|
|
128
|
+
if ("code" in targetColumns) {
|
|
129
|
+
skipped.push(this.makeSkipped(term, targetColumns, options));
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
const placement = this.resolveTargetPlacement(target.query, targetColumns);
|
|
133
|
+
if ("code" in placement) {
|
|
134
|
+
skipped.push(this.makeSkipped(term, placement, options));
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
const movedCondition = this.rebaseCondition(candidate.expression, targetColumns, options);
|
|
138
|
+
target.query.appendWhere(movedCondition);
|
|
139
|
+
appliedReason = placement.reason;
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
const placements = [];
|
|
143
|
+
let skip = null;
|
|
144
|
+
for (const branch of target.branches) {
|
|
145
|
+
const placement = this.resolveTargetPlacement(branch.query, branch.targetColumns);
|
|
146
|
+
if ("code" in placement) {
|
|
147
|
+
skip = placement;
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
placements.push(placement);
|
|
151
|
+
}
|
|
152
|
+
if (skip) {
|
|
153
|
+
skipped.push(this.makeSkipped(term, skip, options));
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
for (const branch of target.branches) {
|
|
157
|
+
const movedCondition = this.rebaseCondition(candidate.expression, branch.targetColumns, options);
|
|
158
|
+
branch.query.appendWhere(movedCondition);
|
|
159
|
+
}
|
|
160
|
+
appliedReason = placements.some(item => /group by/i.test(item.reason))
|
|
161
|
+
? "Condition is distributed to every UNION branch by output column position; grouped branches only receive GROUP BY-key predicates."
|
|
162
|
+
: "Condition is distributed to every UNION branch by output column position before unsafe query boundaries.";
|
|
129
163
|
}
|
|
130
|
-
const movedCondition = this.rebaseCondition(candidate.expression, candidate.column, targetColumn.column);
|
|
131
|
-
target.query.appendWhere(movedCondition);
|
|
132
164
|
movedTerms.push(term);
|
|
133
165
|
applied.push({
|
|
134
166
|
kind: "move_condition",
|
|
135
167
|
conditionSql: candidate.conditionSql,
|
|
136
168
|
fromScopeId: "scope:root",
|
|
137
169
|
toScopeId: target.scopeId,
|
|
138
|
-
reason:
|
|
170
|
+
reason: appliedReason,
|
|
139
171
|
parameterNames: candidate.parameterNames,
|
|
140
|
-
columnReferences:
|
|
172
|
+
columnReferences: candidate.references.map(columnReferenceText)
|
|
141
173
|
});
|
|
142
174
|
}
|
|
143
175
|
rebuildWhereWithoutTerms(query, new Set(movedTerms));
|
|
144
|
-
const sql = applied.length > 0
|
|
176
|
+
const sql = applied.length > 0 || (0, SqlComponentFormatter_1.hasSqlComponentFormatOverride)(options)
|
|
177
|
+
? (0, SqlComponentFormatter_1.formatSqlComponent)(query, options)
|
|
178
|
+
: parsed.sql;
|
|
145
179
|
return this.buildResult({
|
|
180
|
+
query,
|
|
146
181
|
sql,
|
|
147
182
|
applied,
|
|
148
183
|
skipped,
|
|
@@ -156,13 +191,22 @@ class ParameterConditionPlacementOptimizer {
|
|
|
156
191
|
var _a;
|
|
157
192
|
return this.plan(input, { ...options, dryRun: (_a = options.dryRun) !== null && _a !== void 0 ? _a : false });
|
|
158
193
|
}
|
|
159
|
-
parseInput(input) {
|
|
194
|
+
parseInput(input, options) {
|
|
160
195
|
const warnings = [];
|
|
161
196
|
const errors = [];
|
|
162
197
|
try {
|
|
163
198
|
const sourceSql = typeof input === "string"
|
|
164
199
|
? input
|
|
165
|
-
: formatSqlComponent(input);
|
|
200
|
+
: (0, SqlComponentFormatter_1.formatSqlComponent)(input, options);
|
|
201
|
+
if (typeof input !== "string" && options.cloneInput === false) {
|
|
202
|
+
return {
|
|
203
|
+
query: input,
|
|
204
|
+
sql: sourceSql,
|
|
205
|
+
formatterGeneratedSource: false,
|
|
206
|
+
warnings,
|
|
207
|
+
errors
|
|
208
|
+
};
|
|
209
|
+
}
|
|
166
210
|
if (typeof input !== "string") {
|
|
167
211
|
warnings.push({
|
|
168
212
|
code: "AST_INPUT_FORMATTED",
|
|
@@ -193,7 +237,7 @@ class ParameterConditionPlacementOptimizer {
|
|
|
193
237
|
};
|
|
194
238
|
}
|
|
195
239
|
}
|
|
196
|
-
analyzeCandidate(expression) {
|
|
240
|
+
analyzeCandidate(expression, options) {
|
|
197
241
|
const parameterNames = this.collectParameterNames(expression);
|
|
198
242
|
if (parameterNames.length === 0) {
|
|
199
243
|
return null;
|
|
@@ -202,40 +246,22 @@ class ParameterConditionPlacementOptimizer {
|
|
|
202
246
|
if (unsupported) {
|
|
203
247
|
return unsupported;
|
|
204
248
|
}
|
|
205
|
-
const candidate = unwrapParens(expression);
|
|
206
|
-
if (!(candidate instanceof ValueComponent_1.BinaryExpression)) {
|
|
207
|
-
return {
|
|
208
|
-
code: "UNSUPPORTED_PARAMETER_CONDITION",
|
|
209
|
-
reason: "Only simple binary parameter predicates are moved in the safe-only implementation."
|
|
210
|
-
};
|
|
211
|
-
}
|
|
212
|
-
const operator = candidate.operator.value.trim().toLowerCase();
|
|
213
|
-
if (!SUPPORTED_OPERATORS.has(operator)) {
|
|
214
|
-
return {
|
|
215
|
-
code: "UNSUPPORTED_OPERATOR",
|
|
216
|
-
reason: `Operator '${candidate.operator.value}' is not supported for safe-only parameter condition placement.`
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
249
|
const columnReferences = this.collectColumnReferences(expression);
|
|
220
|
-
if (columnReferences.length
|
|
250
|
+
if (columnReferences.length === 0) {
|
|
221
251
|
return {
|
|
222
252
|
code: "AMBIGUOUS_COLUMN_REFERENCE",
|
|
223
|
-
reason:
|
|
224
|
-
? "Parameter condition has no column reference to anchor the move."
|
|
225
|
-
: "Parameter condition references multiple columns; moving it may change semantics."
|
|
253
|
+
reason: "Parameter condition has no column reference to anchor the move."
|
|
226
254
|
};
|
|
227
255
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
reason: "Only simple column IN (:parameter) predicates are moved in the safe-only implementation."
|
|
232
|
-
};
|
|
256
|
+
const unsupportedShape = this.findUnsupportedParameterPredicateShape(expression);
|
|
257
|
+
if (unsupportedShape) {
|
|
258
|
+
return unsupportedShape;
|
|
233
259
|
}
|
|
234
260
|
return {
|
|
235
261
|
expression,
|
|
236
|
-
conditionSql: formatSqlComponent(expression),
|
|
262
|
+
conditionSql: (0, SqlComponentFormatter_1.formatSqlComponent)(expression, options),
|
|
237
263
|
parameterNames,
|
|
238
|
-
|
|
264
|
+
references: columnReferences
|
|
239
265
|
};
|
|
240
266
|
}
|
|
241
267
|
findUnsupportedExpression(expression) {
|
|
@@ -246,13 +272,6 @@ class ParameterConditionPlacementOptimizer {
|
|
|
246
272
|
}
|
|
247
273
|
const candidate = unwrapParens(value);
|
|
248
274
|
if (candidate instanceof ValueComponent_1.BinaryExpression) {
|
|
249
|
-
if (candidate.operator.value.trim().toLowerCase() === "or") {
|
|
250
|
-
found = {
|
|
251
|
-
code: "OR_PREDICATE_UNSUPPORTED",
|
|
252
|
-
reason: "Condition contains OR predicates, which are not moved in the first safe-only implementation."
|
|
253
|
-
};
|
|
254
|
-
return;
|
|
255
|
-
}
|
|
256
275
|
visit(candidate.left);
|
|
257
276
|
visit(candidate.right);
|
|
258
277
|
return;
|
|
@@ -278,13 +297,6 @@ class ParameterConditionPlacementOptimizer {
|
|
|
278
297
|
};
|
|
279
298
|
return;
|
|
280
299
|
}
|
|
281
|
-
if (candidate instanceof ValueComponent_1.BetweenExpression) {
|
|
282
|
-
found = {
|
|
283
|
-
code: "BETWEEN_PREDICATE_UNSUPPORTED",
|
|
284
|
-
reason: "BETWEEN predicates are not moved in the first safe-only implementation."
|
|
285
|
-
};
|
|
286
|
-
return;
|
|
287
|
-
}
|
|
288
300
|
if (candidate instanceof ValueComponent_1.UnaryExpression) {
|
|
289
301
|
visit(candidate.expression);
|
|
290
302
|
return;
|
|
@@ -316,6 +328,39 @@ class ParameterConditionPlacementOptimizer {
|
|
|
316
328
|
visit(expression);
|
|
317
329
|
return found;
|
|
318
330
|
}
|
|
331
|
+
findUnsupportedParameterPredicateShape(expression) {
|
|
332
|
+
const visit = (value) => {
|
|
333
|
+
var _a;
|
|
334
|
+
const candidate = unwrapParens(value);
|
|
335
|
+
if (candidate instanceof ValueComponent_1.BetweenExpression) {
|
|
336
|
+
return null;
|
|
337
|
+
}
|
|
338
|
+
if (candidate instanceof ValueComponent_1.BinaryExpression) {
|
|
339
|
+
const operator = candidate.operator.value.trim().toLowerCase();
|
|
340
|
+
if (operator === "and" || operator === "or") {
|
|
341
|
+
return (_a = visit(candidate.left)) !== null && _a !== void 0 ? _a : visit(candidate.right);
|
|
342
|
+
}
|
|
343
|
+
if (!SUPPORTED_OPERATORS.has(operator)) {
|
|
344
|
+
return {
|
|
345
|
+
code: "UNSUPPORTED_OPERATOR",
|
|
346
|
+
reason: `Operator '${candidate.operator.value}' is not supported for safe-only parameter condition placement.`
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
if (operator === "in" && !this.isSupportedInPredicate(candidate)) {
|
|
350
|
+
return {
|
|
351
|
+
code: "UNSUPPORTED_IN_PREDICATE",
|
|
352
|
+
reason: "Only simple column IN (:parameter) predicates are moved in the safe-only implementation."
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
return null;
|
|
356
|
+
}
|
|
357
|
+
return {
|
|
358
|
+
code: "UNSUPPORTED_PARAMETER_CONDITION",
|
|
359
|
+
reason: "Only simple binary, BETWEEN, and whole OR/AND parameter predicates are moved in the safe-only implementation."
|
|
360
|
+
};
|
|
361
|
+
};
|
|
362
|
+
return visit(expression);
|
|
363
|
+
}
|
|
319
364
|
isSupportedInPredicate(expression) {
|
|
320
365
|
const left = unwrapParens(expression.left);
|
|
321
366
|
const right = unwrapParens(expression.right);
|
|
@@ -332,7 +377,7 @@ class ParameterConditionPlacementOptimizer {
|
|
|
332
377
|
&& right.values.every(value => unwrapParens(value) instanceof ValueComponent_1.ParameterExpression);
|
|
333
378
|
}
|
|
334
379
|
resolveTarget(root, candidate) {
|
|
335
|
-
const boundary = this.
|
|
380
|
+
const boundary = this.findRootQueryBoundary(root);
|
|
336
381
|
if (boundary) {
|
|
337
382
|
return boundary;
|
|
338
383
|
}
|
|
@@ -342,35 +387,38 @@ class ParameterConditionPlacementOptimizer {
|
|
|
342
387
|
reason: "Condition has no FROM source that can receive the predicate safely."
|
|
343
388
|
};
|
|
344
389
|
}
|
|
345
|
-
const
|
|
346
|
-
|
|
347
|
-
|
|
390
|
+
const bindings = [];
|
|
391
|
+
for (const reference of candidate.references) {
|
|
392
|
+
const binding = this.resolveSourceBinding(root, root, reference);
|
|
393
|
+
if ("code" in binding) {
|
|
394
|
+
return binding;
|
|
395
|
+
}
|
|
396
|
+
if (!bindings.some(item => item.source === binding.source)) {
|
|
397
|
+
bindings.push(binding);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
if (bindings.length !== 1) {
|
|
401
|
+
return {
|
|
402
|
+
code: "MULTIPLE_SOURCE_REFERENCES",
|
|
403
|
+
reason: "Parameter condition references multiple source query blocks; moving it may change semantics."
|
|
404
|
+
};
|
|
348
405
|
}
|
|
349
|
-
const
|
|
406
|
+
const binding = bindings[0];
|
|
407
|
+
const nullableSide = this.findNullableSideBoundary(root.fromClause, binding);
|
|
350
408
|
if (nullableSide) {
|
|
351
409
|
return nullableSide;
|
|
352
410
|
}
|
|
353
|
-
const upstream = this.resolveUpstreamQuery(root,
|
|
411
|
+
const upstream = this.resolveUpstreamQuery(root, binding, candidate.references);
|
|
354
412
|
if ("code" in upstream) {
|
|
355
413
|
return upstream;
|
|
356
414
|
}
|
|
357
|
-
const targetBoundary = this.findTargetQueryBoundary(upstream.query);
|
|
358
|
-
if (targetBoundary) {
|
|
359
|
-
return targetBoundary;
|
|
360
|
-
}
|
|
361
415
|
return upstream;
|
|
362
416
|
}
|
|
363
|
-
|
|
364
|
-
if (query
|
|
417
|
+
findRootQueryBoundary(query) {
|
|
418
|
+
if (this.hasDistinctOnBoundary(query)) {
|
|
365
419
|
return {
|
|
366
420
|
code: "DISTINCT_BOUNDARY",
|
|
367
|
-
reason: "Condition crosses DISTINCT boundary; moving it may change semantics."
|
|
368
|
-
};
|
|
369
|
-
}
|
|
370
|
-
if (query.groupByClause || query.havingClause) {
|
|
371
|
-
return {
|
|
372
|
-
code: "GROUP_BY_BOUNDARY",
|
|
373
|
-
reason: "Condition crosses GROUP BY boundary; moving it may change semantics."
|
|
421
|
+
reason: "Condition crosses DISTINCT ON boundary; moving it may change semantics."
|
|
374
422
|
};
|
|
375
423
|
}
|
|
376
424
|
if (this.hasWindowUsage(query)) {
|
|
@@ -381,10 +429,19 @@ class ParameterConditionPlacementOptimizer {
|
|
|
381
429
|
}
|
|
382
430
|
return null;
|
|
383
431
|
}
|
|
384
|
-
|
|
385
|
-
const
|
|
386
|
-
if (
|
|
387
|
-
return
|
|
432
|
+
resolveTargetPlacement(query, targetColumns) {
|
|
433
|
+
const hasOrdinaryDistinct = this.hasOrdinaryDistinct(query);
|
|
434
|
+
if (this.hasDistinctOnBoundary(query)) {
|
|
435
|
+
return {
|
|
436
|
+
code: "DISTINCT_BOUNDARY",
|
|
437
|
+
reason: "Condition crosses DISTINCT ON boundary; moving it may change semantics."
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
if (this.hasWindowUsage(query)) {
|
|
441
|
+
return {
|
|
442
|
+
code: "WINDOW_BOUNDARY",
|
|
443
|
+
reason: "Condition crosses WINDOW boundary; moving it may change semantics."
|
|
444
|
+
};
|
|
388
445
|
}
|
|
389
446
|
if (query.limitClause || query.offsetClause || query.fetchClause) {
|
|
390
447
|
return {
|
|
@@ -398,10 +455,35 @@ class ParameterConditionPlacementOptimizer {
|
|
|
398
455
|
reason: "Target query contains an OUTER JOIN boundary that is not moved across in the safe-only implementation."
|
|
399
456
|
};
|
|
400
457
|
}
|
|
401
|
-
|
|
458
|
+
if (query.groupByClause) {
|
|
459
|
+
const allReferencesAreGroupKeys = targetColumns.every(item => this.isGroupKeyColumn(query, item.targetColumn));
|
|
460
|
+
if (!allReferencesAreGroupKeys) {
|
|
461
|
+
return {
|
|
462
|
+
code: "GROUP_BY_BOUNDARY",
|
|
463
|
+
reason: "Condition references a target column that is not proven to be a GROUP BY key."
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
return {
|
|
467
|
+
reason: "Condition references only GROUP BY keys; it is moved into pre-aggregation WHERE."
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
if (query.havingClause) {
|
|
471
|
+
return {
|
|
472
|
+
code: "GROUP_BY_BOUNDARY",
|
|
473
|
+
reason: "Condition crosses HAVING aggregation boundary; moving it may change semantics."
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
if (hasOrdinaryDistinct) {
|
|
477
|
+
return {
|
|
478
|
+
reason: "Condition references a direct ordinary DISTINCT output column; it is moved into the DISTINCT input WHERE."
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
return {
|
|
482
|
+
reason: "All referenced columns resolve to a single direct upstream output before unsafe query boundaries."
|
|
483
|
+
};
|
|
402
484
|
}
|
|
403
|
-
resolveSourceBinding(
|
|
404
|
-
const fromClause =
|
|
485
|
+
resolveSourceBinding(contextRoot, query, column) {
|
|
486
|
+
const fromClause = query.fromClause;
|
|
405
487
|
if (!fromClause) {
|
|
406
488
|
return {
|
|
407
489
|
code: "NO_FROM_CLAUSE",
|
|
@@ -419,10 +501,7 @@ class ParameterConditionPlacementOptimizer {
|
|
|
419
501
|
reason: `Column source alias '${column.getNamespace()}' is not uniquely resolvable.`
|
|
420
502
|
};
|
|
421
503
|
}
|
|
422
|
-
|
|
423
|
-
return matches[0];
|
|
424
|
-
}
|
|
425
|
-
const matchCount = this.getOutputColumnMatchCount(root, matches[0], columnName);
|
|
504
|
+
const matchCount = this.getOutputColumnMatchCount(contextRoot, matches[0], columnName);
|
|
426
505
|
if (matchCount === 0) {
|
|
427
506
|
return {
|
|
428
507
|
code: "COLUMN_NOT_AVAILABLE_UPSTREAM",
|
|
@@ -438,13 +517,8 @@ class ParameterConditionPlacementOptimizer {
|
|
|
438
517
|
return matches[0];
|
|
439
518
|
}
|
|
440
519
|
const matches = [];
|
|
441
|
-
let unionSource = null;
|
|
442
520
|
for (const binding of bindings) {
|
|
443
|
-
|
|
444
|
-
unionSource !== null && unionSource !== void 0 ? unionSource : (unionSource = binding);
|
|
445
|
-
continue;
|
|
446
|
-
}
|
|
447
|
-
const matchCount = this.getOutputColumnMatchCount(root, binding, columnName);
|
|
521
|
+
const matchCount = this.getOutputColumnMatchCount(contextRoot, binding, columnName);
|
|
448
522
|
if (matchCount > 1) {
|
|
449
523
|
return {
|
|
450
524
|
code: "AMBIGUOUS_COLUMN_REFERENCE",
|
|
@@ -455,12 +529,6 @@ class ParameterConditionPlacementOptimizer {
|
|
|
455
529
|
matches.push(binding);
|
|
456
530
|
}
|
|
457
531
|
}
|
|
458
|
-
if (matches.length === 0 && unionSource) {
|
|
459
|
-
return {
|
|
460
|
-
code: "UNION_BOUNDARY",
|
|
461
|
-
reason: "Condition would need distribution into a UNION branch, which is unsupported."
|
|
462
|
-
};
|
|
463
|
-
}
|
|
464
532
|
if (matches.length !== 1) {
|
|
465
533
|
return {
|
|
466
534
|
code: "AMBIGUOUS_COLUMN_REFERENCE",
|
|
@@ -471,17 +539,20 @@ class ParameterConditionPlacementOptimizer {
|
|
|
471
539
|
}
|
|
472
540
|
return matches[0];
|
|
473
541
|
}
|
|
474
|
-
resolveUpstreamQuery(root, binding,
|
|
542
|
+
resolveUpstreamQuery(root, binding, references) {
|
|
475
543
|
const source = binding.source.datasource;
|
|
476
544
|
if (source instanceof Clause_1.SubQuerySource) {
|
|
477
545
|
if (source.query instanceof SelectQuery_1.SimpleSelectQuery) {
|
|
478
546
|
return {
|
|
547
|
+
kind: "simple",
|
|
479
548
|
query: source.query,
|
|
480
549
|
scopeId: `subquery:${binding.alias}`,
|
|
481
|
-
outputColumnName,
|
|
482
550
|
sourceBinding: binding
|
|
483
551
|
};
|
|
484
552
|
}
|
|
553
|
+
if (source.query instanceof SelectQuery_1.BinarySelectQuery) {
|
|
554
|
+
return this.resolveUnionTarget(root, source.query, `subquery:${binding.alias}`, references);
|
|
555
|
+
}
|
|
485
556
|
return {
|
|
486
557
|
code: "UNION_BOUNDARY",
|
|
487
558
|
reason: "Condition would need distribution into a UNION or non-simple subquery, which is unsupported."
|
|
@@ -509,10 +580,7 @@ class ParameterConditionPlacementOptimizer {
|
|
|
509
580
|
};
|
|
510
581
|
}
|
|
511
582
|
if (commonTable.query instanceof SelectQuery_1.BinarySelectQuery) {
|
|
512
|
-
return {
|
|
513
|
-
code: "UNION_BOUNDARY",
|
|
514
|
-
reason: "Condition would need distribution into a UNION branch, which is unsupported."
|
|
515
|
-
};
|
|
583
|
+
return this.resolveUnionTarget(root, commonTable.query, `cte:${commonTable.getSourceAliasName()}`, references);
|
|
516
584
|
}
|
|
517
585
|
if (!(commonTable.query instanceof SelectQuery_1.SimpleSelectQuery)) {
|
|
518
586
|
return {
|
|
@@ -521,35 +589,140 @@ class ParameterConditionPlacementOptimizer {
|
|
|
521
589
|
};
|
|
522
590
|
}
|
|
523
591
|
return {
|
|
592
|
+
kind: "simple",
|
|
524
593
|
query: commonTable.query,
|
|
525
594
|
scopeId: `cte:${commonTable.getSourceAliasName()}`,
|
|
526
|
-
outputColumnName,
|
|
527
595
|
sourceBinding: binding,
|
|
528
596
|
cteName: commonTable.getSourceAliasName()
|
|
529
597
|
};
|
|
530
598
|
}
|
|
531
|
-
|
|
532
|
-
const
|
|
533
|
-
if (
|
|
599
|
+
resolveUnionTarget(root, query, scopeId, references) {
|
|
600
|
+
const branches = this.collectUnionBranches(query);
|
|
601
|
+
if ("code" in branches) {
|
|
602
|
+
return branches;
|
|
603
|
+
}
|
|
604
|
+
const outputIndexes = new Map();
|
|
605
|
+
for (const reference of references) {
|
|
606
|
+
const outputIndex = this.resolveUnionOutputIndex(root, branches[0], reference.column.name);
|
|
607
|
+
if ("code" in outputIndex) {
|
|
608
|
+
return outputIndex;
|
|
609
|
+
}
|
|
610
|
+
outputIndexes.set(reference, outputIndex.index);
|
|
611
|
+
}
|
|
612
|
+
const branchTargets = [];
|
|
613
|
+
for (const branch of branches) {
|
|
614
|
+
const targetColumns = [];
|
|
615
|
+
for (const [reference, outputIndex] of outputIndexes.entries()) {
|
|
616
|
+
const targetColumn = this.resolveTargetColumnByOutputIndex(root, branch, outputIndex, reference);
|
|
617
|
+
if ("code" in targetColumn) {
|
|
618
|
+
return targetColumn;
|
|
619
|
+
}
|
|
620
|
+
targetColumns.push(targetColumn);
|
|
621
|
+
}
|
|
622
|
+
branchTargets.push(this.resolveDeepestBranchTarget(root, branch, targetColumns));
|
|
623
|
+
}
|
|
624
|
+
return {
|
|
625
|
+
kind: "union",
|
|
626
|
+
scopeId,
|
|
627
|
+
branches: branchTargets
|
|
628
|
+
};
|
|
629
|
+
}
|
|
630
|
+
resolveTargetColumns(root, query, references) {
|
|
631
|
+
const resolved = [];
|
|
632
|
+
for (const reference of references) {
|
|
633
|
+
const matches = this.collectSelectOutputs(root, query).filter(item => normalizeIdentifier(item.name) === normalizeIdentifier(reference.column.name));
|
|
634
|
+
if (matches.length !== 1) {
|
|
635
|
+
return {
|
|
636
|
+
code: "AMBIGUOUS_TARGET_COLUMN",
|
|
637
|
+
reason: matches.length === 0
|
|
638
|
+
? `Target query does not expose '${reference.column.name}' as a direct output column.`
|
|
639
|
+
: `Target query exposes multiple '${reference.column.name}' columns.`
|
|
640
|
+
};
|
|
641
|
+
}
|
|
642
|
+
const value = matches[0].value;
|
|
643
|
+
if (!(value instanceof ValueComponent_1.ColumnReference)) {
|
|
644
|
+
return {
|
|
645
|
+
code: "EXPRESSION_OUTPUT_UNSUPPORTED",
|
|
646
|
+
reason: `Target output '${reference.column.name}' is an expression, not a direct column reference.`
|
|
647
|
+
};
|
|
648
|
+
}
|
|
649
|
+
const sourceResolution = this.verifyColumnResolvableInQuery(query, value);
|
|
650
|
+
if (sourceResolution) {
|
|
651
|
+
return sourceResolution;
|
|
652
|
+
}
|
|
653
|
+
resolved.push({
|
|
654
|
+
sourceColumn: reference,
|
|
655
|
+
targetColumn: value
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
return resolved;
|
|
659
|
+
}
|
|
660
|
+
resolveTargetColumnByOutputIndex(root, query, outputIndex, sourceColumn) {
|
|
661
|
+
const output = this.collectSelectOutputs(root, query)[outputIndex];
|
|
662
|
+
if (!output) {
|
|
534
663
|
return {
|
|
535
|
-
code: "
|
|
536
|
-
reason:
|
|
537
|
-
? `Target query does not expose '${outputColumnName}' as a direct output column.`
|
|
538
|
-
: `Target query exposes multiple '${outputColumnName}' columns.`
|
|
664
|
+
code: "UNION_COLUMN_MISMATCH",
|
|
665
|
+
reason: `UNION branch does not expose column '${sourceColumn.column.name}' at output position ${outputIndex + 1}.`
|
|
539
666
|
};
|
|
540
667
|
}
|
|
541
|
-
|
|
542
|
-
if (!(value instanceof ValueComponent_1.ColumnReference)) {
|
|
668
|
+
if (!(output.value instanceof ValueComponent_1.ColumnReference)) {
|
|
543
669
|
return {
|
|
544
670
|
code: "EXPRESSION_OUTPUT_UNSUPPORTED",
|
|
545
|
-
reason: `
|
|
671
|
+
reason: `UNION branch output at position ${outputIndex + 1} for '${sourceColumn.column.name}' is an expression, not a direct column reference.`
|
|
546
672
|
};
|
|
547
673
|
}
|
|
548
|
-
const sourceResolution = this.verifyColumnResolvableInQuery(query, value);
|
|
674
|
+
const sourceResolution = this.verifyColumnResolvableInQuery(query, output.value);
|
|
549
675
|
if (sourceResolution) {
|
|
550
676
|
return sourceResolution;
|
|
551
677
|
}
|
|
552
|
-
return {
|
|
678
|
+
return {
|
|
679
|
+
sourceColumn,
|
|
680
|
+
targetColumn: output.value
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
resolveDeepestBranchTarget(contextRoot, query, targetColumns, visited = new Set()) {
|
|
684
|
+
if (visited.has(query) || targetColumns.length === 0) {
|
|
685
|
+
return { query, targetColumns: [...targetColumns] };
|
|
686
|
+
}
|
|
687
|
+
const nextVisited = new Set(visited);
|
|
688
|
+
nextVisited.add(query);
|
|
689
|
+
const bindings = [];
|
|
690
|
+
for (const item of targetColumns) {
|
|
691
|
+
const binding = this.resolveSourceBinding(contextRoot, query, item.targetColumn);
|
|
692
|
+
if ("code" in binding) {
|
|
693
|
+
return { query, targetColumns: [...targetColumns] };
|
|
694
|
+
}
|
|
695
|
+
if (!bindings.some(existing => existing.source === binding.source)) {
|
|
696
|
+
bindings.push(binding);
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
if (bindings.length !== 1) {
|
|
700
|
+
return { query, targetColumns: [...targetColumns] };
|
|
701
|
+
}
|
|
702
|
+
const binding = bindings[0];
|
|
703
|
+
const nullableSide = query.fromClause
|
|
704
|
+
? this.findNullableSideBoundary(query.fromClause, binding)
|
|
705
|
+
: null;
|
|
706
|
+
if (nullableSide) {
|
|
707
|
+
return { query, targetColumns: [...targetColumns] };
|
|
708
|
+
}
|
|
709
|
+
const upstream = this.resolveUpstreamQuery(contextRoot, binding, targetColumns.map(item => item.targetColumn));
|
|
710
|
+
if ("code" in upstream || upstream.kind === "union") {
|
|
711
|
+
return { query, targetColumns: [...targetColumns] };
|
|
712
|
+
}
|
|
713
|
+
const upstreamColumns = this.resolveTargetColumns(contextRoot, upstream.query, targetColumns.map(item => item.targetColumn));
|
|
714
|
+
if ("code" in upstreamColumns) {
|
|
715
|
+
return { query, targetColumns: [...targetColumns] };
|
|
716
|
+
}
|
|
717
|
+
const placement = this.resolveTargetPlacement(upstream.query, upstreamColumns);
|
|
718
|
+
if ("code" in placement) {
|
|
719
|
+
return { query, targetColumns: [...targetColumns] };
|
|
720
|
+
}
|
|
721
|
+
const rebasedColumns = upstreamColumns.map((item, index) => ({
|
|
722
|
+
sourceColumn: targetColumns[index].sourceColumn,
|
|
723
|
+
targetColumn: item.targetColumn
|
|
724
|
+
}));
|
|
725
|
+
return this.resolveDeepestBranchTarget(contextRoot, upstream.query, rebasedColumns, nextVisited);
|
|
553
726
|
}
|
|
554
727
|
verifyColumnResolvableInQuery(query, column) {
|
|
555
728
|
if (!query.fromClause) {
|
|
@@ -577,13 +750,47 @@ class ParameterConditionPlacementOptimizer {
|
|
|
577
750
|
reason: `Unqualified target column '${column.column.name}' is ambiguous in a multi-source destination query.`
|
|
578
751
|
};
|
|
579
752
|
}
|
|
580
|
-
|
|
581
|
-
const
|
|
753
|
+
isGroupKeyColumn(query, column) {
|
|
754
|
+
const groupBy = query.groupByClause;
|
|
755
|
+
if (!groupBy || groupBy.mode || groupBy.grouping.length === 0) {
|
|
756
|
+
return false;
|
|
757
|
+
}
|
|
758
|
+
return groupBy.grouping.some(grouping => {
|
|
759
|
+
const candidate = unwrapParens(grouping);
|
|
760
|
+
return candidate instanceof ValueComponent_1.ColumnReference
|
|
761
|
+
&& this.sameResolvableColumnInQuery(query, candidate, column);
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
sameResolvableColumnInQuery(query, left, right) {
|
|
765
|
+
if (sameColumnReference(left, right)) {
|
|
766
|
+
return true;
|
|
767
|
+
}
|
|
768
|
+
if (normalizeIdentifier(left.column.name) !== normalizeIdentifier(right.column.name)) {
|
|
769
|
+
return false;
|
|
770
|
+
}
|
|
771
|
+
const leftSource = this.resolveColumnSourceAlias(query, left);
|
|
772
|
+
const rightSource = this.resolveColumnSourceAlias(query, right);
|
|
773
|
+
return leftSource !== null && leftSource === rightSource;
|
|
774
|
+
}
|
|
775
|
+
resolveColumnSourceAlias(query, column) {
|
|
776
|
+
if (!query.fromClause) {
|
|
777
|
+
return null;
|
|
778
|
+
}
|
|
779
|
+
const bindings = this.getSourceBindings(query.fromClause);
|
|
780
|
+
const namespace = normalizeIdentifier(column.getNamespace());
|
|
781
|
+
if (namespace) {
|
|
782
|
+
const matches = bindings.filter(binding => normalizeIdentifier(binding.alias) === namespace);
|
|
783
|
+
return matches.length === 1 ? normalizeIdentifier(matches[0].alias) : null;
|
|
784
|
+
}
|
|
785
|
+
return bindings.length === 1 ? normalizeIdentifier(bindings[0].alias) : null;
|
|
786
|
+
}
|
|
787
|
+
rebaseCondition(expression, targetColumns, options) {
|
|
788
|
+
const cloned = cloneValueComponent(expression, options);
|
|
582
789
|
for (const reference of this.collectColumnReferences(cloned)) {
|
|
583
|
-
|
|
584
|
-
|
|
790
|
+
const target = targetColumns.find(item => sameColumnReference(reference, item.sourceColumn));
|
|
791
|
+
if (target) {
|
|
792
|
+
reference.qualifiedName = cloneColumnReference(target.targetColumn).qualifiedName;
|
|
585
793
|
}
|
|
586
|
-
reference.qualifiedName = cloneColumnReference(targetColumn).qualifiedName;
|
|
587
794
|
}
|
|
588
795
|
return cloned;
|
|
589
796
|
}
|
|
@@ -641,12 +848,80 @@ class ParameterConditionPlacementOptimizer {
|
|
|
641
848
|
return joinType.includes("left") || joinType.includes("right") || joinType.includes("full") || joinType.includes("outer");
|
|
642
849
|
});
|
|
643
850
|
}
|
|
851
|
+
hasDistinctOnBoundary(query) {
|
|
852
|
+
return query.selectClause.distinct instanceof Clause_1.DistinctOn;
|
|
853
|
+
}
|
|
854
|
+
hasOrdinaryDistinct(query) {
|
|
855
|
+
return query.selectClause.distinct !== null && !this.hasDistinctOnBoundary(query);
|
|
856
|
+
}
|
|
644
857
|
getOutputColumnMatchCount(root, binding, columnName) {
|
|
645
858
|
const target = this.resolveSourceQueryForColumns(root, binding.source);
|
|
646
|
-
if (!target
|
|
859
|
+
if (!target) {
|
|
647
860
|
return 0;
|
|
648
861
|
}
|
|
649
|
-
|
|
862
|
+
if (target instanceof SelectQuery_1.BinarySelectQuery) {
|
|
863
|
+
const branches = this.collectUnionBranches(target);
|
|
864
|
+
if ("code" in branches) {
|
|
865
|
+
return 0;
|
|
866
|
+
}
|
|
867
|
+
return this.collectSelectOutputs(root, branches[0]).filter(item => normalizeIdentifier(item.name) === normalizeIdentifier(columnName)).length;
|
|
868
|
+
}
|
|
869
|
+
if (!(target instanceof SelectQuery_1.SimpleSelectQuery)) {
|
|
870
|
+
return 0;
|
|
871
|
+
}
|
|
872
|
+
return this.collectSelectOutputs(root, target).filter(item => normalizeIdentifier(item.name) === normalizeIdentifier(columnName)).length;
|
|
873
|
+
}
|
|
874
|
+
collectUnionBranches(query) {
|
|
875
|
+
const branches = [];
|
|
876
|
+
const visit = (select) => {
|
|
877
|
+
var _a;
|
|
878
|
+
if (select instanceof SelectQuery_1.SimpleSelectQuery) {
|
|
879
|
+
branches.push(select);
|
|
880
|
+
return null;
|
|
881
|
+
}
|
|
882
|
+
if (!(select instanceof SelectQuery_1.BinarySelectQuery)) {
|
|
883
|
+
return {
|
|
884
|
+
code: "UNION_BOUNDARY",
|
|
885
|
+
reason: "Condition would need distribution into a non-simple UNION branch, which is unsupported."
|
|
886
|
+
};
|
|
887
|
+
}
|
|
888
|
+
const operator = select.operator.value.trim().toLowerCase();
|
|
889
|
+
if (operator !== "union" && operator !== "union all") {
|
|
890
|
+
return {
|
|
891
|
+
code: "UNION_BOUNDARY",
|
|
892
|
+
reason: `Condition would need distribution through '${select.operator.value}', which is unsupported.`
|
|
893
|
+
};
|
|
894
|
+
}
|
|
895
|
+
return (_a = visit(select.left)) !== null && _a !== void 0 ? _a : visit(select.right);
|
|
896
|
+
};
|
|
897
|
+
const skip = visit(query);
|
|
898
|
+
return skip !== null && skip !== void 0 ? skip : branches;
|
|
899
|
+
}
|
|
900
|
+
resolveUnionOutputIndex(root, firstBranch, outputColumnName) {
|
|
901
|
+
const matches = [];
|
|
902
|
+
this.collectSelectOutputs(root, firstBranch).forEach((item, index) => {
|
|
903
|
+
if (normalizeIdentifier(item.name) === normalizeIdentifier(outputColumnName)) {
|
|
904
|
+
matches.push(index);
|
|
905
|
+
}
|
|
906
|
+
});
|
|
907
|
+
if (matches.length !== 1) {
|
|
908
|
+
return {
|
|
909
|
+
code: "AMBIGUOUS_TARGET_COLUMN",
|
|
910
|
+
reason: matches.length === 0
|
|
911
|
+
? `UNION output does not expose '${outputColumnName}' from its first branch.`
|
|
912
|
+
: `UNION first branch exposes multiple '${outputColumnName}' columns.`
|
|
913
|
+
};
|
|
914
|
+
}
|
|
915
|
+
return { index: matches[0] };
|
|
916
|
+
}
|
|
917
|
+
collectSelectOutputs(root, query) {
|
|
918
|
+
var _a, _b, _c, _d;
|
|
919
|
+
const commonTables = [
|
|
920
|
+
...((_b = (_a = query.withClause) === null || _a === void 0 ? void 0 : _a.tables) !== null && _b !== void 0 ? _b : []),
|
|
921
|
+
...((_d = (_c = root.withClause) === null || _c === void 0 ? void 0 : _c.tables) !== null && _d !== void 0 ? _d : [])
|
|
922
|
+
];
|
|
923
|
+
const collector = new SelectOutputCollector_1.SelectOutputCollector(null, commonTables.length > 0 ? commonTables : null);
|
|
924
|
+
return collector.collect(query);
|
|
650
925
|
}
|
|
651
926
|
resolveSourceQueryForColumns(root, source) {
|
|
652
927
|
var _a;
|
|
@@ -661,15 +936,6 @@ class ParameterConditionPlacementOptimizer {
|
|
|
661
936
|
}
|
|
662
937
|
return null;
|
|
663
938
|
}
|
|
664
|
-
getSelectItemOutputName(item) {
|
|
665
|
-
if (item.identifier) {
|
|
666
|
-
return item.identifier.name;
|
|
667
|
-
}
|
|
668
|
-
if (item.value instanceof ValueComponent_1.ColumnReference) {
|
|
669
|
-
return item.value.column.name;
|
|
670
|
-
}
|
|
671
|
-
return null;
|
|
672
|
-
}
|
|
673
939
|
findCte(root, name) {
|
|
674
940
|
var _a, _b;
|
|
675
941
|
const normalized = normalizeIdentifier(name);
|
|
@@ -915,9 +1181,9 @@ class ParameterConditionPlacementOptimizer {
|
|
|
915
1181
|
visit(expression);
|
|
916
1182
|
return names;
|
|
917
1183
|
}
|
|
918
|
-
makeSkipped(expression, draft) {
|
|
1184
|
+
makeSkipped(expression, draft, options) {
|
|
919
1185
|
return {
|
|
920
|
-
conditionSql: formatSqlComponent(expression),
|
|
1186
|
+
conditionSql: (0, SqlComponentFormatter_1.formatSqlComponent)(expression, options),
|
|
921
1187
|
scopeId: "scope:root",
|
|
922
1188
|
...draft
|
|
923
1189
|
};
|
|
@@ -926,6 +1192,7 @@ class ParameterConditionPlacementOptimizer {
|
|
|
926
1192
|
return {
|
|
927
1193
|
ok: params.errors.length === 0,
|
|
928
1194
|
sql: params.sql,
|
|
1195
|
+
query: params.query,
|
|
929
1196
|
applied: params.applied,
|
|
930
1197
|
skipped: params.skipped,
|
|
931
1198
|
warnings: params.warnings,
|