-
Notifications
You must be signed in to change notification settings - Fork 3.1k
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
Add support for CORRESPONDING option in set operations #25260
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1865,9 +1865,31 @@ private SetOperationPlan process(SetOperation node) | |
ImmutableListMultimap.Builder<Symbol, Symbol> symbolMapping = ImmutableListMultimap.builder(); | ||
ImmutableList.Builder<PlanNode> sources = ImmutableList.builder(); | ||
|
||
for (Relation child : node.getRelations()) { | ||
List<Relation> relations = node.getRelations(); | ||
checkArgument(relations.size() == 2, "relations size must be 2"); | ||
Relation rightRelation = relations.getLast(); | ||
for (Relation child : relations) { | ||
ebyhr marked this conversation as resolved.
Show resolved
Hide resolved
|
||
RelationPlan plan = process(child, null); | ||
|
||
if (node.isCorresponding() && child.equals(rightRelation)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The planner should not be doing any mappings based on names. That should have been established during analysis, and any necessary supporting data structure recorded in the Analysis object. E.g., a list of fields to select in the order in which they should be considered + the corresponding relation types. |
||
// Replace right relation's field order to match the output fields of the set operation | ||
Map<String, Symbol> nameToSymbol = new HashMap<>(); | ||
RelationType descriptor = plan.getDescriptor(); | ||
Collection<Field> visibleFields = outputFields.getVisibleFields(); | ||
for (int i = 0; i < visibleFields.size(); i++) { | ||
nameToSymbol.put(descriptor.getFieldByIndex(i).getName().orElseThrow(), plan.getSymbol(i)); | ||
} | ||
|
||
List<Symbol> fieldMappings = visibleFields.stream() | ||
.map(field -> nameToSymbol.get(field.getName().orElseThrow())) | ||
.collect(toImmutableList()); | ||
ProjectNode projectNode = new ProjectNode( | ||
idAllocator.getNextId(), | ||
plan.getRoot(), | ||
Assignments.identity(fieldMappings)); | ||
plan = new RelationPlan(projectNode, plan.getScope(), fieldMappings, plan.getOuterContext()); | ||
} | ||
|
||
NodeAndMappings planAndMappings; | ||
List<Type> types = analysis.getRelationCoercion(child); | ||
if (types == null) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,9 +28,9 @@ public class Except | |
private final Relation left; | ||
private final Relation right; | ||
|
||
public Except(NodeLocation location, Relation left, Relation right, boolean distinct) | ||
public Except(NodeLocation location, Relation left, Relation right, boolean distinct, boolean corresponding) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using a Add support for passing in the list of columns in the grammar and AST, even if, for the first version, the analyzer rejects any queries where the list is provided. |
||
{ | ||
super(Optional.of(location), distinct); | ||
super(Optional.of(location), distinct, corresponding); | ||
requireNonNull(left, "left is null"); | ||
requireNonNull(right, "right is null"); | ||
|
||
|
@@ -73,6 +73,7 @@ public String toString() | |
.add("left", left) | ||
.add("right", right) | ||
.add("distinct", isDistinct()) | ||
.add("corresponding", isCorresponding()) | ||
.toString(); | ||
} | ||
|
||
|
@@ -88,13 +89,14 @@ public boolean equals(Object obj) | |
Except o = (Except) obj; | ||
return Objects.equals(left, o.left) && | ||
Objects.equals(right, o.right) && | ||
isDistinct() == o.isDistinct(); | ||
isDistinct() == o.isDistinct() && | ||
isCorresponding() == o.isCorresponding(); | ||
} | ||
|
||
@Override | ||
public int hashCode() | ||
{ | ||
return Objects.hash(left, right, isDistinct()); | ||
return Objects.hash(left, right, isDistinct(), isCorresponding()); | ||
} | ||
|
||
@Override | ||
|
@@ -104,6 +106,8 @@ public boolean shallowEquals(Node other) | |
return false; | ||
} | ||
|
||
return this.isDistinct() == ((Except) other).isDistinct(); | ||
Except otherExcept = (Except) other; | ||
return this.isDistinct() == otherExcept.isDistinct() && | ||
this.isCorresponding() == otherExcept.isCorresponding(); | ||
} | ||
} |
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.
How does this handle standard SQL identifier canonicalization and matching?