Skip to content

Commit

Permalink
[Improvement] : For auto incr unique key, remove deduplication detect…
Browse files Browse the repository at this point in the history
…ion if there will be no conflict (#14980)

For auto incr unique key, no deduplication detection is performed if there is definitely no conflict.

Approved by: @ouyuanning, @sukki37
  • Loading branch information
jensenojs committed Mar 15, 2024
1 parent 400c0c2 commit a7b2462
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 39 deletions.
44 changes: 22 additions & 22 deletions pkg/sql/plan/build_constraint_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ func getDmlTableInfo(ctx CompilerContext, tableExprs tree.TableExprs, with *tree
return tblInfo, nil
}

func initInsertStmt(builder *QueryBuilder, bindCtx *BindContext, stmt *tree.Insert, info *dmlSelectInfo) (bool, map[int]int, bool, map[string]bool, error) {
func initInsertStmt(builder *QueryBuilder, bindCtx *BindContext, stmt *tree.Insert, info *dmlSelectInfo) (bool, map[int]int, bool, map[string]bool, []string, error) {
var err error
var insertColumns []string
tableDef := info.tblInfo.tableDefs[0]
Expand Down Expand Up @@ -386,7 +386,7 @@ func initInsertStmt(builder *QueryBuilder, bindCtx *BindContext, stmt *tree.Inse
for _, column := range stmt.Columns {
colName := string(column)
if _, ok := colToIdx[colName]; !ok {
return false, nil, false, nil, moerr.NewBadFieldError(builder.GetContext(), colName, tableDef.Name)
return false, nil, false, nil, nil, moerr.NewBadFieldError(builder.GetContext(), colName, tableDef.Name)
}
insertColumns = append(insertColumns, colName)
}
Expand All @@ -403,14 +403,14 @@ func initInsertStmt(builder *QueryBuilder, bindCtx *BindContext, stmt *tree.Inse
if isAllDefault {
for j, row := range slt.Rows {
if row != nil {
return false, nil, false, nil, moerr.NewWrongValueCountOnRow(builder.GetContext(), j+1)
return false, nil, false, nil, nil, moerr.NewWrongValueCountOnRow(builder.GetContext(), j+1)
}
}
} else {
colCount := len(insertColumns)
for j, row := range slt.Rows {
if len(row) != colCount {
return false, nil, false, nil, moerr.NewWrongValueCountOnRow(builder.GetContext(), j+1)
return false, nil, false, nil, nil, moerr.NewWrongValueCountOnRow(builder.GetContext(), j+1)
}
}
}
Expand All @@ -419,7 +419,7 @@ func initInsertStmt(builder *QueryBuilder, bindCtx *BindContext, stmt *tree.Inse
//but it does not work at the case:
//insert into a(a) values (); insert into a values (0),();
if isAllDefault && syntaxHasColumnNames {
return false, nil, false, nil, moerr.NewInvalidInput(builder.GetContext(), "insert values does not match the number of columns")
return false, nil, false, nil, nil, moerr.NewInvalidInput(builder.GetContext(), "insert values does not match the number of columns")
}
checkInsertPkDup = len(slt.Rows) > 1
if CNPrimaryCheck {
Expand Down Expand Up @@ -476,7 +476,7 @@ func initInsertStmt(builder *QueryBuilder, bindCtx *BindContext, stmt *tree.Inse

err = buildValueScan(isAllDefault, info, builder, bindCtx, tableDef, slt, insertColumns, colToIdx)
if err != nil {
return false, nil, false, nil, err
return false, nil, false, nil, nil, err
}

case *tree.SelectClause:
Expand All @@ -485,7 +485,7 @@ func initInsertStmt(builder *QueryBuilder, bindCtx *BindContext, stmt *tree.Inse
subCtx := NewBindContext(builder, bindCtx)
info.rootId, err = builder.buildSelect(astSlt, subCtx, false)
if err != nil {
return false, nil, false, nil, err
return false, nil, false, nil, nil, err
}

case *tree.ParenSelect:
Expand All @@ -494,23 +494,23 @@ func initInsertStmt(builder *QueryBuilder, bindCtx *BindContext, stmt *tree.Inse
subCtx := NewBindContext(builder, bindCtx)
info.rootId, err = builder.buildSelect(astSlt, subCtx, false)
if err != nil {
return false, nil, false, nil, err
return false, nil, false, nil, nil, err
}

default:
return false, nil, false, nil, moerr.NewInvalidInput(builder.GetContext(), "insert has unknown select statement")
return false, nil, false, nil, nil, moerr.NewInvalidInput(builder.GetContext(), "insert has unknown select statement")
}

err = builder.addBinding(info.rootId, tree.AliasClause{
Alias: derivedTableName,
}, bindCtx)
if err != nil {
return false, nil, false, nil, err
return false, nil, false, nil, nil, err
}

lastNode := builder.qry.Nodes[info.rootId]
if len(insertColumns) != len(lastNode.ProjectList) {
return false, nil, false, nil, moerr.NewInvalidInput(builder.GetContext(), "insert values does not match the number of columns")
return false, nil, false, nil, nil, moerr.NewInvalidInput(builder.GetContext(), "insert values does not match the number of columns")
}

tag := builder.qry.Nodes[info.rootId].BindingTags[0]
Expand All @@ -532,12 +532,12 @@ func initInsertStmt(builder *QueryBuilder, bindCtx *BindContext, stmt *tree.Inse
if tableDef.Cols[colIdx].Typ.Id == int32(types.T_enum) {
projExpr, err = funcCastForEnumType(builder.GetContext(), projExpr, tableDef.Cols[colIdx].Typ)
if err != nil {
return false, nil, false, nil, err
return false, nil, false, nil, nil, err
}
} else {
projExpr, err = forceCastExpr(builder.GetContext(), projExpr, tableDef.Cols[colIdx].Typ)
if err != nil {
return false, nil, false, nil, err
return false, nil, false, nil, nil, err
}
}
insertColToExpr[column] = projExpr
Expand Down Expand Up @@ -582,7 +582,7 @@ func initInsertStmt(builder *QueryBuilder, bindCtx *BindContext, stmt *tree.Inse
} else {
defExpr, err := getDefaultExpr(builder.GetContext(), col)
if err != nil {
return false, nil, false, nil, err
return false, nil, false, nil, nil, err
}

if col.Typ.AutoIncr && col.Name == tableDef.Pkey.PkeyColName {
Expand Down Expand Up @@ -677,17 +677,17 @@ func initInsertStmt(builder *QueryBuilder, bindCtx *BindContext, stmt *tree.Inse
if _, ok := updateExpr.(*tree.DefaultVal); ok {
defExpr, err = getDefaultExpr(builder.GetContext(), col)
if err != nil {
return false, nil, false, nil, err
return false, nil, false, nil, nil, err
}
} else {
defExpr, err = binder.BindExpr(updateExpr, 0, true)
if err != nil {
return false, nil, false, nil, err
return false, nil, false, nil, nil, err
}
}
defExpr, err = forceCastExpr(builder.GetContext(), defExpr, col.Typ)
if err != nil {
return false, nil, false, nil, err
return false, nil, false, nil, nil, err
}
updateExprs[col.Name] = defExpr
}
Expand Down Expand Up @@ -730,14 +730,14 @@ func initInsertStmt(builder *QueryBuilder, bindCtx *BindContext, stmt *tree.Inse
}
eqExpr, err := BindFuncExprImplByPlanExpr(builder.GetContext(), "=", []*Expr{leftExpr, rightExpr})
if err != nil {
return false, nil, false, nil, err
return false, nil, false, nil, nil, err
}
if condIdx == 0 {
condExpr = eqExpr
} else {
condExpr, err = BindFuncExprImplByPlanExpr(builder.GetContext(), "and", []*Expr{condExpr, eqExpr})
if err != nil {
return false, nil, false, nil, err
return false, nil, false, nil, nil, err
}
}
condIdx++
Expand All @@ -748,7 +748,7 @@ func initInsertStmt(builder *QueryBuilder, bindCtx *BindContext, stmt *tree.Inse
} else {
joinConds, err = BindFuncExprImplByPlanExpr(builder.GetContext(), "or", []*Expr{joinConds, condExpr})
if err != nil {
return false, nil, false, nil, err
return false, nil, false, nil, nil, err
}
}
joinIdx++
Expand All @@ -758,7 +758,7 @@ func initInsertStmt(builder *QueryBuilder, bindCtx *BindContext, stmt *tree.Inse
leftCtx := builder.ctxByNode[info.rootId]
err = joinCtx.mergeContexts(builder.GetContext(), leftCtx, rightCtx)
if err != nil {
return false, nil, false, nil, err
return false, nil, false, nil, nil, err
}
newRootId := builder.appendNode(&plan.Node{
NodeType: plan.Node_JOIN,
Expand All @@ -784,7 +784,7 @@ func initInsertStmt(builder *QueryBuilder, bindCtx *BindContext, stmt *tree.Inse
}
}

return checkInsertPkDup, pkPosInValues, isInsertWithoutAutoPkCol, insertWithoutUniqueKeyMap, nil
return checkInsertPkDup, pkPosInValues, isInsertWithoutAutoPkCol, insertWithoutUniqueKeyMap, insertColumns, nil
}

func deleteToSelect(builder *QueryBuilder, bindCtx *BindContext, node *tree.Delete, haveConstraint bool, tblInfo *dmlTableInfo) (int32, error) {
Expand Down
61 changes: 47 additions & 14 deletions pkg/sql/plan/build_dml_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ type deleteNodeInfo struct {
func buildInsertPlans(
ctx CompilerContext, builder *QueryBuilder, bindCtx *BindContext,
objRef *ObjectRef, tableDef *TableDef, lastNodeId int32,
checkInsertPkDup bool, pkFilterExpr []*Expr, newPartitionExpr *Expr, isInsertWithoutAutoPkCol bool, insertWithoutUniqueKeyMap map[string]bool) error {

checkInsertPkDup bool, pkFilterExpr []*Expr, newPartitionExpr *Expr, isInsertWithoutAutoPkCol bool, insertWithoutUniqueKeyMap map[string]bool, insertColumns []string,
) error {
// add plan: -> preinsert -> sink
lastNodeId = appendPreInsertNode(builder, bindCtx, objRef, tableDef, lastNodeId, false)

Expand All @@ -121,7 +121,7 @@ func buildInsertPlans(

// make insert plans
insertBindCtx := NewBindContext(builder, nil)
err := makeInsertPlan(ctx, builder, insertBindCtx, objRef, tableDef, 0, sourceStep, true, false, checkInsertPkDup, true, pkFilterExpr, newPartitionExpr, isInsertWithoutAutoPkCol, !builder.qry.LoadTag, nil, nil, insertWithoutUniqueKeyMap)
err := makeInsertPlan(ctx, builder, insertBindCtx, objRef, tableDef, 0, sourceStep, true, false, checkInsertPkDup, true, pkFilterExpr, newPartitionExpr, isInsertWithoutAutoPkCol, !builder.qry.LoadTag, nil, nil, insertWithoutUniqueKeyMap, insertColumns)
return err
}

Expand Down Expand Up @@ -200,7 +200,7 @@ func buildUpdatePlans(ctx CompilerContext, builder *QueryBuilder, bindCtx *BindC
// build insert plan.
insertBindCtx := NewBindContext(builder, nil)
err = makeInsertPlan(ctx, builder, insertBindCtx, updatePlanCtx.objRef, updatePlanCtx.tableDef, updatePlanCtx.updateColLength,
sourceStep, false, updatePlanCtx.isFkRecursionCall, updatePlanCtx.checkInsertPkDup, updatePlanCtx.updatePkCol, updatePlanCtx.pkFilterExprs, nil, false, true, nil, nil, nil)
sourceStep, false, updatePlanCtx.isFkRecursionCall, updatePlanCtx.checkInsertPkDup, updatePlanCtx.updatePkCol, updatePlanCtx.pkFilterExprs, nil, false, true, nil, nil, nil, nil)
return err
}

Expand Down Expand Up @@ -407,7 +407,7 @@ func buildDeletePlans(ctx CompilerContext, builder *QueryBuilder, bindCtx *BindC
}
}
_checkInsertPKDupForHiddenIndexTable := indexdef.Unique // only check PK uniqueness for UK. SK will not check PK uniqueness.
err = makeInsertPlan(ctx, builder, bindCtx, uniqueObjRef, insertUniqueTableDef, 1, preUKStep, false, false, _checkInsertPKDupForHiddenIndexTable, true, nil, nil, false, _checkInsertPKDupForHiddenIndexTable, nil, nil, nil)
err = makeInsertPlan(ctx, builder, bindCtx, uniqueObjRef, insertUniqueTableDef, 1, preUKStep, false, false, _checkInsertPKDupForHiddenIndexTable, true, nil, nil, false, _checkInsertPKDupForHiddenIndexTable, nil, nil, nil, nil)
if err != nil {
return err
}
Expand Down Expand Up @@ -924,6 +924,7 @@ func makeInsertPlan(
indexSourceColTypes []*plan.Type,
fuzzymessage *OriginTableMessageForFuzzy,
insertWithoutUniqueKeyMap map[string]bool,
insertColumns []string,
) error {
var lastNodeId int32
var err error
Expand Down Expand Up @@ -1005,32 +1006,64 @@ func makeInsertPlan(

var originTableMessageForFuzzy *OriginTableMessageForFuzzy

_checkInsertPkDupForHiddenTable := indexdef.Unique // only check PK uniqueness for UK. SK will not check PK uniqueness.

// The way to guarantee the uniqueness of the unique key is to create a hidden table,
// with the primary key of the hidden table as the unique key.
// package contains some information needed by the fuzzy filter to run background SQL.
if indexdef.GetUnique() {
originTableMessageForFuzzy = &OriginTableMessageForFuzzy{
ParentTableName: tableDef.Name,
}
autoUniqueNameSet := make(map[string]bool)
uniqueNameSet := make(map[string]int)
partialUniqueCols := make([]*plan.ColDef, len(indexdef.Parts))
set := make(map[string]int)

for i, n := range indexdef.Parts {
set[n] = i
uniqueNameSet[n] = i
}
for _, c := range tableDef.Cols { // sort
if i, ok := set[c.Name]; ok {
if i, ok := uniqueNameSet[c.Name]; ok {
partialUniqueCols[i] = c
if c.Typ.AutoIncr {
autoUniqueNameSet[c.Name] = true
}
}
}
originTableMessageForFuzzy.ParentUniqueCols = partialUniqueCols

if insertColumns != nil && len(autoUniqueNameSet) > 0 {
atLeastOneHasNoValue := false

// for those unique key
for n := range autoUniqueNameSet {
if atLeastOneHasNoValue {
break
}

found := false
// check if at least one auto unique has no value
for _, c := range insertColumns {
if c == n {
found = true
}
}
if !found {
atLeastOneHasNoValue = true
}
}

if atLeastOneHasNoValue {
_checkInsertPkDupForHiddenTable = false // if so, no need to check dup
}
}
}

_checkInsertPkDupForHiddenTable := indexdef.Unique // only check PK uniqueness for UK. SK will not check PK uniqueness.
colTypes := make([]*plan.Type, len(tableDef.Cols))
for i := range tableDef.Cols {
colTypes[i] = tableDef.Cols[i].Typ
}
err = makeInsertPlan(ctx, builder, bindCtx, idxRef, idxTableDef, 0, newSourceStep, false, false, checkInsertPkDupForHiddenIndexTable, true, nil, nil, false, _checkInsertPkDupForHiddenTable, colTypes, originTableMessageForFuzzy, nil)
err = makeInsertPlan(ctx, builder, bindCtx, idxRef, idxTableDef, 0, newSourceStep, false, false, checkInsertPkDupForHiddenIndexTable, true, nil, nil, false, _checkInsertPkDupForHiddenTable, colTypes, originTableMessageForFuzzy, nil, insertColumns)
if err != nil {
return err
}
Expand All @@ -1048,13 +1081,13 @@ func makeInsertPlan(
return err
}

//if the all fk are fk self refer, the lastNodeId is -1.
//skip fk self refer here
// if the all fk are fk self refer, the lastNodeId is -1.
// skip fk self refer here
if lastNodeId >= 0 {
lastNode := builder.qry.Nodes[lastNodeId]
beginIdx := len(lastNode.ProjectList) - len(tableDef.Fkeys)

//get filter exprs
// get filter exprs
rowIdTyp := types.T_Rowid.ToType()
filters := make([]*Expr, len(tableDef.Fkeys))
errExpr := makePlan2StringConstExprWithType("Cannot add or update a child row: a foreign key constraint fails")
Expand All @@ -1064,7 +1097,7 @@ func makeInsertPlan(
Expr: &plan.Expr_Col{
Col: &plan.ColRef{
ColPos: int32(beginIdx + i),
//Name: catalog.Row_ID,
// Name: catalog.Row_ID,
},
},
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/sql/plan/build_insert.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func buildInsert(stmt *tree.Insert, ctx CompilerContext, isReplace bool, isPrepa
builder.haveOnDuplicateKey = len(stmt.OnDuplicateUpdate) > 0

bindCtx := NewBindContext(builder, nil)
checkInsertPkDup, pkPosInValues, isInsertWithoutAutoPkCol, insertWithoutUniqueKeyMap, err := initInsertStmt(builder, bindCtx, stmt, rewriteInfo)
checkInsertPkDup, pkPosInValues, isInsertWithoutAutoPkCol, insertWithoutUniqueKeyMap, insertColumns, err := initInsertStmt(builder, bindCtx, stmt, rewriteInfo)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -255,7 +255,7 @@ func buildInsert(stmt *tree.Insert, ctx CompilerContext, isReplace bool, isPrepa

query.StmtType = plan.Query_UPDATE
} else {
err = buildInsertPlans(ctx, builder, bindCtx, objRef, tableDef, rewriteInfo.rootId, checkInsertPkDup, pkFilterExprs, newPartitionExpr, isInsertWithoutAutoPkCol, insertWithoutUniqueKeyMap)
err = buildInsertPlans(ctx, builder, bindCtx, objRef, tableDef, rewriteInfo.rootId, checkInsertPkDup, pkFilterExprs, newPartitionExpr, isInsertWithoutAutoPkCol, insertWithoutUniqueKeyMap, insertColumns)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/sql/plan/build_load.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ func buildLoad(stmt *tree.Load, ctx CompilerContext, isPrepareStmt bool) (*Plan,
// append hidden column to tableDef
newTableDef := DeepCopyTableDef(tableDef, true)
checkInsertPkDup := false
err = buildInsertPlans(ctx, builder, bindCtx, objRef, newTableDef, lastNodeId, checkInsertPkDup, nil, nil, isInsertWithoutAutoPkCol, nil)
err = buildInsertPlans(ctx, builder, bindCtx, objRef, newTableDef, lastNodeId, checkInsertPkDup, nil, nil, isInsertWithoutAutoPkCol, nil, nil)
if err != nil {
return nil, err
}
Expand Down

0 comments on commit a7b2462

Please sign in to comment.