-
Notifications
You must be signed in to change notification settings - Fork 5.8k
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
plan: fix a problem caused by union's schema #7680
Changes from 2 commits
296562b
8c99231
99122ef
da03ba7
51061ea
698c799
fd0b11d
89f9fd6
c9c4db6
106fce2
05e9ee4
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 |
---|---|---|
|
@@ -626,29 +626,32 @@ func unionJoinFieldType(a, b *types.FieldType) *types.FieldType { | |
} | ||
|
||
func (b *planBuilder) buildProjection4Union(u *LogicalUnionAll) { | ||
unionSchema := u.children[0].Schema().Clone() | ||
unionCols := make([]*expression.Column, 0, u.children[0].Schema().Len()) | ||
|
||
// Infer union result types by its children's schema. | ||
for i, col := range unionSchema.Columns { | ||
var resultTp *types.FieldType | ||
for j, child := range u.children { | ||
childTp := child.Schema().Columns[i].RetType | ||
if j == 0 { | ||
resultTp = childTp | ||
} else { | ||
resultTp = unionJoinFieldType(resultTp, childTp) | ||
} | ||
} | ||
unionSchema.Columns[i] = col.Clone().(*expression.Column) | ||
unionSchema.Columns[i].RetType = resultTp | ||
unionSchema.Columns[i].DBName = model.NewCIStr("") | ||
for i, col := range u.children[0].Schema().Columns { | ||
resultTp := col.RetType | ||
for j := 1; j < len(u.children); j++ { | ||
childTp := u.children[j].Schema().Columns[i].RetType | ||
resultTp = unionJoinFieldType(resultTp, childTp) | ||
} | ||
unionCols = append(unionCols, &expression.Column{ | ||
ColName: col.ColName, | ||
TblName: col.TblName, | ||
RetType: resultTp, | ||
UniqueID: b.ctx.GetSessionVars().AllocPlanColumnID(), | ||
}) | ||
} | ||
// If the types of some child don't match the types of union, we add a projection with cast function. | ||
u.schema = expression.NewSchema(unionCols...) | ||
// Process each child | ||
// 1. Check whether the `TypeField` is correct. If not, create a projection. | ||
// 2. If we need to create projection, create it. | ||
// 3. If we not need, but the child is not projection. We still need a projection. To make its schema the same with the union. | ||
for childID, child := range u.children { | ||
exprs := make([]expression.Expression, len(child.Schema().Columns)) | ||
needProjection := false | ||
for i, srcCol := range child.Schema().Columns { | ||
dstType := unionSchema.Columns[i].RetType | ||
dstType := unionCols[i].RetType | ||
srcType := srcCol.RetType | ||
if !srcType.Equal(dstType) { | ||
exprs[i] = expression.BuildCastFunction4Union(b.ctx, srcCol, dstType) | ||
|
@@ -660,15 +663,10 @@ func (b *planBuilder) buildProjection4Union(u *LogicalUnionAll) { | |
if _, isProj := child.(*LogicalProjection); needProjection || !isProj { | ||
winoros marked this conversation as resolved.
Show resolved
Hide resolved
|
||
b.optFlag |= flagEliminateProjection | ||
proj := LogicalProjection{Exprs: exprs}.init(b.ctx) | ||
if childID == 0 { | ||
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. Why remove this? 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. We generated new columns above here. So don't need add this check. |
||
for _, col := range unionSchema.Columns { | ||
col.UniqueID = b.ctx.GetSessionVars().AllocPlanColumnID() | ||
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. what if all children of 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. We could do this. |
||
} | ||
} | ||
proj.SetChildren(child) | ||
u.children[childID] = proj | ||
} | ||
u.children[childID].(*LogicalProjection).SetSchema(unionSchema.Clone()) | ||
u.children[childID].(*LogicalProjection).SetSchema(expression.NewSchema(unionCols...)) | ||
} | ||
} | ||
|
||
|
@@ -678,15 +676,15 @@ func (b *planBuilder) buildUnion(union *ast.UnionStmt) (LogicalPlan, error) { | |
return nil, errors.Trace(err) | ||
} | ||
|
||
unionDistinctPlan := b.buildSubUnion(distinctSelectPlans) | ||
unionDistinctPlan := b.buildUnionAll(distinctSelectPlans) | ||
if unionDistinctPlan != nil { | ||
unionDistinctPlan = b.buildDistinct(unionDistinctPlan, unionDistinctPlan.Schema().Len()) | ||
if len(allSelectPlans) > 0 { | ||
allSelectPlans = append(allSelectPlans, unionDistinctPlan) | ||
} | ||
} | ||
|
||
unionAllPlan := b.buildSubUnion(allSelectPlans) | ||
unionAllPlan := b.buildUnionAll(allSelectPlans) | ||
unionPlan := unionDistinctPlan | ||
if unionAllPlan != nil { | ||
unionPlan = unionAllPlan | ||
|
@@ -738,7 +736,7 @@ func (b *planBuilder) divideUnionSelectPlans(selects []*ast.SelectStmt) (distinc | |
return children[:firstUnionAllIdx], children[firstUnionAllIdx:], nil | ||
} | ||
|
||
func (b *planBuilder) buildSubUnion(subPlan []LogicalPlan) LogicalPlan { | ||
func (b *planBuilder) buildUnionAll(subPlan []LogicalPlan) LogicalPlan { | ||
if len(subPlan) == 0 { | ||
return nil | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -132,6 +132,7 @@ func (p *LogicalUnionAll) PruneColumns(parentUsedCols []*expression.Column) { | |
for _, child := range p.Children() { | ||
child.PruneColumns(parentUsedCols) | ||
} | ||
p.schema.Columns = p.children[0].Schema().Columns | ||
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. Is this right? parent columns may have different 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.
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. Here https://github.com/pingcap/tidb/pull/7680/files#diff-638d8be162d442ef3a5c423ff0c735d4R642 the
What does 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. It's done by here |
||
} | ||
|
||
// PruneColumns implements LogicalPlan interface. | ||
|
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.
Since we are using
ColName
ofchildren[0]
's Column here, should we keep other fields exceptUniqueID
same withchildren[0]
's Column as well? such asOrigTblName
,OrigColName