in core/src/main/java/com/jetbrains/youtrackdb/internal/core/sql/executor/SelectExecutionPlanner.java [1372:1540]
private boolean handleClassAsTargetWithIndexedFunction(
SelectExecutionPlan plan,
SQLIdentifier queryTarget,
QueryPlanningInfo info,
CommandContext ctx,
boolean profilingEnabled) {
if (queryTarget == null) {
return false;
}
var schema = getSchemaFromContext(ctx);
var clazz = schema.getClassInternal(queryTarget.getStringValue());
if (clazz == null) {
throw new CommandExecutionException(ctx.getDatabaseSession(),
"Class not found: " + queryTarget);
}
if (info.flattenedWhereClause == null || info.flattenedWhereClause.isEmpty()) {
return false;
}
List<InternalExecutionPlan> resultSubPlans = new ArrayList<>();
var indexedFunctionsFound = false;
for (var block : info.flattenedWhereClause) {
var indexedFunctionConditions =
block.getIndexedFunctionConditions(clazz, ctx.getDatabaseSession());
indexedFunctionConditions =
filterIndexedFunctionsWithoutIndex(indexedFunctionConditions, info.target, ctx);
if (indexedFunctionConditions == null || indexedFunctionConditions.isEmpty()) {
var bestIndex = findBestIndexFor(ctx,
clazz.getIndexesInternal(),
block, clazz);
if (bestIndex != null) {
var step = new FetchFromIndexStep(bestIndex, true, ctx, profilingEnabled);
var subPlan = new SelectExecutionPlan(ctx);
subPlan.chain(step);
IntArrayList filterCollectionIds;
filterCollectionIds = IntArrayList.of(clazz.getPolymorphicCollectionIds());
subPlan.chain(new GetValueFromIndexEntryStep(ctx, filterCollectionIds, profilingEnabled));
if (bestIndex.requiresDistinctStep()) {
subPlan.chain(new DistinctExecutionStep(ctx, profilingEnabled));
}
if (!block.getSubBlocks().isEmpty()) {
if ((info.perRecordLetClause != null && refersToLet(block.getSubBlocks()))) {
handleLet(subPlan, info, ctx, profilingEnabled);
}
subPlan.chain(
new FilterStep(
createWhereFrom(block),
ctx,
this.info.timeout != null ? this.info.timeout.getVal().longValue() : -1,
profilingEnabled));
}
resultSubPlans.add(subPlan);
} else {
FetchFromClassExecutionStep step;
step =
new FetchFromClassExecutionStep(
clazz.getName(), null, ctx, true, profilingEnabled);
var subPlan = new SelectExecutionPlan(ctx);
subPlan.chain(step);
if (!block.getSubBlocks().isEmpty()) {
if ((info.perRecordLetClause != null && refersToLet(block.getSubBlocks()))) {
handleLet(subPlan, info, ctx, profilingEnabled);
}
subPlan.chain(
new FilterStep(
createWhereFrom(block),
ctx,
this.info.timeout != null ? this.info.timeout.getVal().longValue() : -1,
profilingEnabled));
}
resultSubPlans.add(subPlan);
}
} else {
SQLBinaryCondition blockCandidateFunction = null;
for (var cond : indexedFunctionConditions) {
if (!cond.allowsIndexedFunctionExecutionOnTarget(info.target, ctx)) {
if (!cond.canExecuteIndexedFunctionWithoutIndex(info.target, ctx)) {
throw new CommandExecutionException(ctx.getDatabaseSession(),
"Cannot execute " + block + " on " + queryTarget);
}
}
if (blockCandidateFunction == null) {
blockCandidateFunction = cond;
} else {
var thisAllowsNoIndex =
cond.canExecuteIndexedFunctionWithoutIndex(info.target, ctx);
var prevAllowsNoIndex =
blockCandidateFunction.canExecuteIndexedFunctionWithoutIndex(info.target, ctx);
if (!thisAllowsNoIndex && !prevAllowsNoIndex) {
// none of the functions allow execution without index, so cannot choose one
throw new CommandExecutionException(ctx.getDatabaseSession(),
"Cannot choose indexed function between "
+ cond
+ " and "
+ blockCandidateFunction
+ ". Both require indexed execution");
} else if (thisAllowsNoIndex && prevAllowsNoIndex) {
// both can be calculated without index, choose the best one for index execution
var thisEstimate = cond.estimateIndexed(info.target, ctx);
var lastEstimate = blockCandidateFunction.estimateIndexed(info.target, ctx);
if (thisEstimate > -1 && thisEstimate < lastEstimate) {
blockCandidateFunction = cond;
}
} else if (prevAllowsNoIndex) {
// choose current condition, because the other one can be calculated without index
blockCandidateFunction = cond;
}
}
}
var step =
new FetchFromIndexedFunctionStep(
blockCandidateFunction, info.target, ctx, profilingEnabled);
if (!blockCandidateFunction.executeIndexedFunctionAfterIndexSearch(info.target, ctx)) {
block = block.copy();
block.getSubBlocks().remove(blockCandidateFunction);
}
if (info.flattenedWhereClause.size() == 1) {
plan.chain(step);
if (!block.getSubBlocks().isEmpty()) {
if ((info.perRecordLetClause != null && refersToLet(block.getSubBlocks()))) {
handleLet(plan, info, ctx, profilingEnabled);
}
plan.chain(
new FilterStep(
createWhereFrom(block),
ctx,
this.info.timeout != null ? this.info.timeout.getVal().longValue() : -1,
profilingEnabled));
}
} else {
var subPlan = new SelectExecutionPlan(ctx);
subPlan.chain(step);
if (!block.getSubBlocks().isEmpty()) {
subPlan.chain(
new FilterStep(
createWhereFrom(block),
ctx,
this.info.timeout != null ? this.info.timeout.getVal().longValue() : -1,
profilingEnabled));
}
resultSubPlans.add(subPlan);
}
indexedFunctionsFound = true;
}
}
if (indexedFunctionsFound) {
if (resultSubPlans.size()
> 1) { // if resultSubPlans.size() == 1 the step was already chained (see above)
plan.chain(new ParallelExecStep(resultSubPlans, ctx, profilingEnabled));
plan.chain(new DistinctExecutionStep(ctx, profilingEnabled));
}
// WHERE condition already applied
info.whereClause = null;
info.flattenedWhereClause = null;
return true;
} else {
return false;
}
}