-
Notifications
You must be signed in to change notification settings - Fork 3.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Enhance unnest support in decoupled mode #17550
Open
kgyrtkirk
wants to merge
113
commits into
apache:master
Choose a base branch
from
kgyrtkirk:unnest-relfieldtrimmer-unnestfieldtype
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 90 commits
Commits
Show all changes
113 commits
Select commit
Hold shift + click to select a range
7021b3f
working?
kgyrtkirk 54b057e
x
kgyrtkirk 00837c5
clenaup
kgyrtkirk 314d3f7
some updates
kgyrtkirk 2ceefdc
try-unnestfiled-instead-rowtype
kgyrtkirk 4e0a37a
more wood
kgyrtkirk e7061ad
more wood
kgyrtkirk b45b3ba
run trimmer
kgyrtkirk d38215f
ok-but alon trim should have affected native query - right?
kgyrtkirk 322ec81
make some assert function and fail with that
kgyrtkirk e8f06bf
make helper method
kgyrtkirk 04ab28f
one way
kgyrtkirk c49fc27
rename: d1/dbl1
kgyrtkirk 0d03cc5
Revert "rename: d1/dbl1"
kgyrtkirk d4b4c94
Reapply "rename: d1/dbl1"
kgyrtkirk 7777e48
dbl1/etc
kgyrtkirk 0d07cf1
dbl1/etc
kgyrtkirk bd72b95
fix some
kgyrtkirk 88e57f9
fix some more
kgyrtkirk 62664e3
fix windowtests
kgyrtkirk 0874843
fix some more
kgyrtkirk ced72b3
fix nondefault
kgyrtkirk fc31c8a
update iq files
kgyrtkirk a1b9f52
Merge remote-tracking branch 'apache/master' into rename-d1-dbl1
kgyrtkirk 247ee17
fixups after merge
kgyrtkirk 1379c9a
Merge branch 'rename-d1-dbl1' into unnest-relfieldtrimmer-unnestfield…
kgyrtkirk 8dfd57f
update test
kgyrtkirk 0d09c18
undo trials; re-introduce expr if needed (will be trimmed in most cases)
kgyrtkirk 96f572e
updates/etc
kgyrtkirk 7d9693b
aa
kgyrtkirk fbfed8a
update
kgyrtkirk f4d7ec2
cleanup/enhance rule order to simplify
kgyrtkirk fd564fd
cleanup/enhance rule order to simplify
kgyrtkirk 9448ed3
enable trim for unnest
kgyrtkirk 9afdfb2
updates
kgyrtkirk dcdd7d4
fix final test
kgyrtkirk 23e4dab
trim-trim
kgyrtkirk a075cb9
removal of some projects
kgyrtkirk 12373a8
fix one
kgyrtkirk 6ee980e
update unnest.iq
kgyrtkirk 1e5c37b
inline const back
kgyrtkirk acc9eb6
Merge branch 'rename-d1-dbl1' into unnest-relfieldtrimmer-unnestfield…
kgyrtkirk 44523a8
update
kgyrtkirk 351615a
Merge branch 'rename-d1-dbl1' into unnest-relfieldtrimmer-unnestfield…
kgyrtkirk f89cc82
update 2 more tests
kgyrtkirk f9823b0
Merge branch 'rename-d1-dbl1' into unnest-relfieldtrimmer-unnestfield…
kgyrtkirk 3aff161
fix fail
kgyrtkirk 797f35d
celanup
kgyrtkirk 8800763
correct indent
kgyrtkirk 7e46880
cleanup
kgyrtkirk d2e97da
add back dummyproject
kgyrtkirk afad58c
Merge branch 'rename-d1-dbl1' into unnest-relfieldtrimmer-unnestfield…
kgyrtkirk 0378e65
trimmed
kgyrtkirk 400c05e
last trim possibly nbot needed
kgyrtkirk 79c489c
;stuf
kgyrtkirk 4cc0077
Merge remote-tracking branch 'apache/master' into rename-d1-dbl1
kgyrtkirk 93bae23
Merge branch 'rename-d1-dbl1' into unnest-relfieldtrimmer-unnestfield…
kgyrtkirk d4ebca9
enable trimmer to create blinding project
kgyrtkirk 0c6b40c
update
kgyrtkirk bdfcef8
add note; conditional
kgyrtkirk 5ca3f14
more sophisiticated filter
kgyrtkirk 1ad8289
Merge remote-tracking branch 'apache/master' into rename-d1-dbl1
kgyrtkirk e67b609
Merge branch 'rename-d1-dbl1' into unnest-relfieldtrimmer-unnestfield…
kgyrtkirk 34426e1
remove ds2
kgyrtkirk d536217
renames
kgyrtkirk 8cb1178
its ok
kgyrtkirk e7aface
reduce
kgyrtkirk 2c71133
x
kgyrtkirk 285d178
dont care about filter; it only references unnest col
kgyrtkirk 6d577f8
some stuf
kgyrtkirk 3f3335f
updates
kgyrtkirk 12c82dd
more w
kgyrtkirk 7bb3d7a
convert early
kgyrtkirk f584ab0
convert early
kgyrtkirk 627f4a8
up
kgyrtkirk b7dcbf6
cleanup
kgyrtkirk e72d54b
cleanup
kgyrtkirk 1fd2add
cleanup
kgyrtkirk 844b1f2
remove tmp tests
kgyrtkirk c024d1e
indent
kgyrtkirk 928637d
add
kgyrtkirk e195135
try to fix unnest outputColumn
kgyrtkirk adfdbde
Revert "try to fix unnest outputColumn"
kgyrtkirk 034aeed
some progress
kgyrtkirk 48032ce
fixup
kgyrtkirk fa96b15
fix?
kgyrtkirk a830e97
uipdate
kgyrtkirk 8f286b3
a
kgyrtkirk 4e84219
removals
kgyrtkirk 5c5ca27
cleanup
kgyrtkirk 86bec3b
update
kgyrtkirk b8726c3
fix for sqlcompat
kgyrtkirk ef12701
up
kgyrtkirk 1960994
trial of accepting empty project
kgyrtkirk c51607e
fix
kgyrtkirk a161b6c
retain for old
kgyrtkirk dde6e06
remove boolean
kgyrtkirk c8d2392
add missing override
kgyrtkirk e989112
Merge remote-tracking branch 'apache/master' into unnest-relfieldtrim…
kgyrtkirk 3477592
up
kgyrtkirk cc7e0b4
Merge remote-tracking branch 'apache/master' into unnest-relfieldtrim…
kgyrtkirk 7e5658e
add apidoc
kgyrtkirk d1e8ae1
up
kgyrtkirk c518b48
fix compile; add doc
kgyrtkirk db8d422
rename test
kgyrtkirk 8d46ff5
update apidoc
kgyrtkirk 9fe9b76
Merge remote-tracking branch 'apache/master' into unnest-relfieldtrim…
kgyrtkirk a700f52
Add test for join with input ref condition
kgyrtkirk 8f189e4
Update test configuration and annotation for unnest predicate not sup…
kgyrtkirk 805f775
Merge remote-tracking branch 'apache/master' into unnest-relfieldtrim…
kgyrtkirk 96be3a2
fx
kgyrtkirk 163dcb4
u
kgyrtkirk d1106cc
fix
kgyrtkirk File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
313 changes: 313 additions & 0 deletions
313
sql/src/main/java/org/apache/druid/sql/calcite/planner/DruidRelFieldTrimmer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,313 @@ | ||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one | ||
* or more contributor license agreements. See the NOTICE file | ||
* distributed with this work for additional information | ||
* regarding copyright ownership. The ASF licenses this file | ||
* to you 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.apache.druid.sql.calcite.planner; | ||
|
||
import com.google.common.collect.ImmutableList; | ||
import org.apache.calcite.plan.RelOptUtil; | ||
import org.apache.calcite.rel.RelHomogeneousShuttle; | ||
import org.apache.calcite.rel.RelNode; | ||
import org.apache.calcite.rel.core.CorrelationId; | ||
import org.apache.calcite.rel.core.TableScan; | ||
import org.apache.calcite.rel.logical.LogicalCorrelate; | ||
import org.apache.calcite.rel.type.RelDataType; | ||
import org.apache.calcite.rel.type.RelDataTypeField; | ||
import org.apache.calcite.rex.RexBuilder; | ||
import org.apache.calcite.rex.RexCorrelVariable; | ||
import org.apache.calcite.rex.RexFieldAccess; | ||
import org.apache.calcite.rex.RexNode; | ||
import org.apache.calcite.rex.RexPermuteInputsShuttle; | ||
import org.apache.calcite.rex.RexShuttle; | ||
import org.apache.calcite.rex.RexVisitor; | ||
import org.apache.calcite.sql.validate.SqlValidator; | ||
import org.apache.calcite.sql2rel.RelFieldTrimmer; | ||
import org.apache.calcite.tools.RelBuilder; | ||
import org.apache.calcite.util.ImmutableBitSet; | ||
import org.apache.calcite.util.mapping.IntPair; | ||
import org.apache.calcite.util.mapping.Mapping; | ||
import org.apache.calcite.util.mapping.MappingType; | ||
import org.apache.calcite.util.mapping.Mappings; | ||
import org.apache.druid.sql.calcite.rule.logical.LogicalUnnest; | ||
import org.checkerframework.checker.nullness.qual.Nullable; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.Set; | ||
|
||
public class DruidRelFieldTrimmer extends RelFieldTrimmer | ||
{ | ||
private final boolean trimTableScan; | ||
private final RelBuilder relBuilder; | ||
|
||
public DruidRelFieldTrimmer(@Nullable SqlValidator validator, RelBuilder relBuilder, boolean trimTableScan) | ||
{ | ||
super(validator, relBuilder); | ||
this.relBuilder = relBuilder; | ||
this.trimTableScan = trimTableScan; | ||
} | ||
|
||
@Override | ||
protected TrimResult dummyProject(int fieldCount, RelNode input) | ||
{ | ||
return makeIdentityMapping(input); | ||
} | ||
|
||
protected TrimResult dummyProject(int fieldCount, RelNode input, | ||
Check notice Code scanning / CodeQL Missing Override annotation
This method overrides [RelFieldTrimmer.dummyProject](1); it is advisable to add an Override annotation.
|
||
@Nullable RelNode originalRelNode) | ||
{ | ||
if (fieldCount != 0 && trimTableScan) { | ||
return super.dummyProject(fieldCount, input, originalRelNode); | ||
} | ||
// workaround to support fieldCount == 0 projections | ||
final Mapping mapping = Mappings.create(MappingType.INVERSE_SURJECTION, fieldCount, 0); | ||
if (input.getRowType().getFieldCount() == 0) { | ||
// there is no need to do anything | ||
return result(input, mapping); | ||
} | ||
relBuilder.push(input); | ||
relBuilder.project(Collections.emptyList(), Collections.emptyList()); | ||
RelNode newProject = relBuilder.build(); | ||
if (originalRelNode != null) { | ||
newProject = RelOptUtil.propagateRelHints(originalRelNode, newProject); | ||
} | ||
return result(newProject, mapping); | ||
} | ||
|
||
private TrimResult makeIdentityMapping(RelNode input) | ||
{ | ||
Mapping mapping = Mappings.createIdentity(input.getRowType().getFieldCount()); | ||
return result(input, mapping); | ||
} | ||
|
||
public TrimResult trimFields( | ||
Check notice Code scanning / CodeQL Deprecated method or constructor invocation Note test
Invoking
CalciteTestBase.makeColumnExpression Error loading related location Loading
|
||
final TableScan tableAccessRel, | ||
ImmutableBitSet fieldsUsed, | ||
Set<RelDataTypeField> extraFields) | ||
{ | ||
if (trimTableScan) { | ||
return super.trimFields(tableAccessRel, fieldsUsed, extraFields); | ||
} else { | ||
Mapping mapping = Mappings.createIdentity(tableAccessRel.getRowType().getFieldCount()); | ||
return result(tableAccessRel, mapping, tableAccessRel); | ||
} | ||
} | ||
|
||
public TrimResult trimFields(LogicalCorrelate correlate, | ||
ImmutableBitSet fieldsUsed, | ||
Set<RelDataTypeField> extraFields) | ||
{ | ||
if (!extraFields.isEmpty()) { | ||
// bail out with generic trim | ||
return trimFields((RelNode) correlate, fieldsUsed, extraFields); | ||
} | ||
|
||
fieldsUsed = fieldsUsed.union(correlate.getRequiredColumns()); | ||
|
||
List<RelNode> newInputs = new ArrayList<>(); | ||
List<Mapping> inputMappings = new ArrayList<>(); | ||
int changeCount = 0; | ||
int offset = 0; | ||
for (RelNode input : correlate.getInputs()) { | ||
final RelDataType inputRowType = input.getRowType(); | ||
final int inputFieldCount = inputRowType.getFieldCount(); | ||
|
||
ImmutableBitSet currentInputFieldsUsed = fieldsUsed | ||
.intersect(ImmutableBitSet.range(offset, offset + inputFieldCount)) | ||
.shift(-offset); | ||
|
||
TrimResult trimResult; | ||
try { | ||
trimResult = dispatchTrimFields(input, currentInputFieldsUsed, extraFields); | ||
} | ||
catch (RuntimeException e) { | ||
throw e; | ||
} | ||
|
||
newInputs.add(trimResult.left); | ||
if (trimResult.left != input) { | ||
changeCount++; | ||
} | ||
|
||
final Mapping inputMapping = trimResult.right; | ||
inputMappings.add(inputMapping); | ||
|
||
offset += inputFieldCount; | ||
} | ||
|
||
if (changeCount == 0) { | ||
return result(correlate, Mappings.createIdentity(correlate.getRowType().getFieldCount())); | ||
} | ||
|
||
Mapping mapping = makeMapping(inputMappings); | ||
RexBuilder rexBuilder = correlate.getCluster().getRexBuilder(); | ||
|
||
final LogicalCorrelate newCorrelate = correlate.copy( | ||
correlate.getTraitSet(), | ||
newInputs.get(0), | ||
newInputs.get(1).accept( | ||
new RexRewritingRelShuttle( | ||
new RexCorrelVariableMapShuttle(correlate.getCorrelationId(), newInputs.get(0).getRowType(), mapping, rexBuilder) | ||
) | ||
), | ||
correlate.getCorrelationId(), | ||
correlate.getRequiredColumns().permute(mapping), | ||
correlate.getJoinType() | ||
); | ||
|
||
return result(newCorrelate, mapping); | ||
} | ||
|
||
public TrimResult trimFields(LogicalUnnest correlate, | ||
ImmutableBitSet fieldsUsed, | ||
Set<RelDataTypeField> extraFields) | ||
{ | ||
if (!extraFields.isEmpty()) { | ||
// bail out with generic trim | ||
return trimFields((RelNode) correlate, fieldsUsed, extraFields); | ||
} | ||
RelOptUtil.InputFinder inputFinder = new RelOptUtil.InputFinder(extraFields); | ||
|
||
correlate.getUnnestExpr().accept(inputFinder); | ||
|
||
ImmutableBitSet finderFields = inputFinder.build(); | ||
|
||
ImmutableBitSet inputFieldsUsed = ImmutableBitSet.builder() | ||
.addAll(fieldsUsed.clear(correlate.getRowType().getFieldCount() - 1)) | ||
.addAll(finderFields) | ||
.build(); | ||
|
||
RelNode input = correlate.getInput(); | ||
|
||
// Create input with trimmed columns. | ||
TrimResult trimResult = trimChild(correlate, input, inputFieldsUsed, extraFields); | ||
|
||
RelNode newInput = trimResult.left; | ||
final Mapping inputMapping = trimResult.right; | ||
|
||
if (newInput == input) { | ||
return result(correlate, Mappings.createIdentity(correlate.getRowType().getFieldCount())); | ||
} | ||
|
||
Mapping mapping = makeMapping(ImmutableList.of(inputMapping, Mappings.createIdentity(1))); | ||
|
||
final RexVisitor<RexNode> shuttle = new RexPermuteInputsShuttle(inputMapping, newInput); | ||
|
||
RexNode newUnnestExpr = correlate.getUnnestExpr().accept(shuttle); | ||
RexNode newFilterExpr = correlate.getFilter(); | ||
|
||
final LogicalUnnest newCorrelate = correlate.copy( | ||
correlate.getTraitSet(), | ||
newInput, | ||
newUnnestExpr, | ||
newFilterExpr | ||
); | ||
|
||
return result(newCorrelate, mapping); | ||
} | ||
|
||
/** | ||
* Concatenates multiple mapping. | ||
* | ||
* <pre> | ||
* [ 1:0, 2:1] // sourceCount:100 | ||
* [ 1:0, 2:1] // sourceCount:100 | ||
* output: | ||
* [ 1:0, 2:1, 101:2, 102:3 ] ; sourceCount:200 | ||
* </pre> | ||
*/ | ||
private Mapping makeMapping(List<Mapping> inputMappings) | ||
{ | ||
int fieldCount = 0; | ||
int newFieldCount = 0; | ||
for (Mapping mapping : inputMappings) { | ||
fieldCount += mapping.getSourceCount(); | ||
newFieldCount += mapping.getTargetCount(); | ||
} | ||
|
||
Mapping mapping = Mappings.create( | ||
MappingType.INVERSE_SURJECTION, | ||
fieldCount, | ||
newFieldCount | ||
); | ||
int offset = 0; | ||
int newOffset = 0; | ||
for (int i = 0; i < inputMappings.size(); i++) { | ||
Mapping inputMapping = inputMappings.get(i); | ||
for (IntPair pair : inputMapping) { | ||
mapping.set(pair.source + offset, pair.target + newOffset); | ||
} | ||
offset += inputMapping.getSourceCount(); | ||
newOffset += inputMapping.getTargetCount(); | ||
} | ||
return mapping; | ||
} | ||
|
||
static class RexCorrelVariableMapShuttle extends RexShuttle | ||
{ | ||
private final CorrelationId correlationId; | ||
private final Mapping mapping; | ||
private final RelDataType newCorrelRowType; | ||
private final RexBuilder rexBuilder; | ||
|
||
public RexCorrelVariableMapShuttle(final CorrelationId correlationId, RelDataType newCorrelRowType, Mapping mapping, RexBuilder rexBuilder) | ||
{ | ||
this.correlationId = correlationId; | ||
this.newCorrelRowType = newCorrelRowType; | ||
this.mapping = mapping; | ||
this.rexBuilder = rexBuilder; | ||
} | ||
|
||
@Override | ||
public RexNode visitFieldAccess(final RexFieldAccess fieldAccess) | ||
{ | ||
if (fieldAccess.getReferenceExpr() instanceof RexCorrelVariable) { | ||
RexCorrelVariable referenceExpr = (RexCorrelVariable) fieldAccess.getReferenceExpr(); | ||
final RexCorrelVariable encounteredCorrelationId = referenceExpr; | ||
if (encounteredCorrelationId.id.equals(correlationId)) { | ||
int sourceIndex = fieldAccess.getField().getIndex(); | ||
return rexBuilder.makeFieldAccess(map(referenceExpr), mapping.getTarget(sourceIndex)); | ||
} | ||
} | ||
return super.visitFieldAccess(fieldAccess); | ||
} | ||
|
||
private RexNode map(RexCorrelVariable referenceExpr) | ||
{ | ||
return rexBuilder.makeCorrel(newCorrelRowType, referenceExpr.id); | ||
} | ||
} | ||
|
||
static class RexRewritingRelShuttle extends RelHomogeneousShuttle | ||
{ | ||
private final RexShuttle rexVisitor; | ||
|
||
RexRewritingRelShuttle(RexShuttle rexVisitor) | ||
{ | ||
this.rexVisitor = rexVisitor; | ||
} | ||
|
||
@Override | ||
public RelNode visit(RelNode other) | ||
{ | ||
RelNode next = super.visit(other); | ||
return next.accept(rexVisitor); | ||
} | ||
} | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A javadoc for this class would be really useful
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added a few lines; main goal of the class is the same as
RelFieldTrimmer
- so I've added a link to it in the apidoc as all of those also applies here