github.com/matrixorigin/matrixone@v0.7.0/pkg/sql/plan/build_constraint_util.go (about)

     1  // Copyright 2022 Matrix Origin
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package plan
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  
    21  	"github.com/matrixorigin/matrixone/pkg/catalog"
    22  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    23  	"github.com/matrixorigin/matrixone/pkg/container/types"
    24  	"github.com/matrixorigin/matrixone/pkg/pb/plan"
    25  	"github.com/matrixorigin/matrixone/pkg/sql/parsers/tree"
    26  	"github.com/matrixorigin/matrixone/pkg/sql/plan/function"
    27  	"github.com/matrixorigin/matrixone/pkg/sql/util"
    28  )
    29  
    30  const derivedTableName = "_t"
    31  
    32  type dmlSelectInfo struct {
    33  	typ string
    34  
    35  	projectList    []*Expr
    36  	tblInfo        *dmlTableInfo
    37  	idx            int32
    38  	rootId         int32
    39  	derivedTableId int32
    40  
    41  	onIdx    []int32 //remove these row
    42  	onIdxTbl []*ObjectRef
    43  
    44  	onRestrict    []int32 // check these, not all null then throw error
    45  	onRestrictTbl []*ObjectRef
    46  
    47  	onSet          [][]int64
    48  	onSetTableDef  []*TableDef
    49  	onSetRef       []*ObjectRef
    50  	onSetUpdateCol []map[string]int32 // name=updated col.Name  value=col position in TableDef.Cols
    51  
    52  	onCascade          [][]int64
    53  	onCascadeTableDef  []*TableDef
    54  	onCascadeRef       []*ObjectRef
    55  	onCascadeUpdateCol []map[string]int32 // name=updated col.Name  value=col position in TableDef.Cols
    56  
    57  	parentIdx []map[string]int32
    58  }
    59  
    60  type dmlTableInfo struct {
    61  	objRef         []*ObjectRef
    62  	tableDefs      []*TableDef
    63  	isClusterTable []bool
    64  	haveConstraint bool
    65  	updateCol      []map[string]int32     // name=updated col.Name  value=col position in TableDef.Cols
    66  	updateKeys     []map[string]tree.Expr // This slice index correspond to tableDefs
    67  	oldColPosMap   []map[string]int       // origin table values to their position in derived table
    68  	newColPosMap   []map[string]int       // insert/update values to their position in derived table
    69  	nameToIdx      map[string]int         // Mapping of table full path name to tableDefs index,such as: 'tpch.nation -> 0'
    70  	idToName       map[uint64]string      // Mapping of tableId to full path name of table
    71  	alias          map[string]int         // Mapping of table aliases to tableDefs array index,If there is no alias, replace it with the original name of the table
    72  }
    73  
    74  func getAliasToName(ctx CompilerContext, expr tree.TableExpr, alias string, aliasMap map[string][2]string) {
    75  	switch t := expr.(type) {
    76  	case *tree.TableName:
    77  		dbName := string(t.SchemaName)
    78  		if dbName == "" {
    79  			dbName = ctx.DefaultDatabase()
    80  		}
    81  		tblName := string(t.ObjectName)
    82  		if alias != "" {
    83  			aliasMap[alias] = [2]string{dbName, tblName}
    84  		}
    85  	case *tree.AliasedTableExpr:
    86  		alias := string(t.As.Alias)
    87  		getAliasToName(ctx, t.Expr, alias, aliasMap)
    88  	case *tree.JoinTableExpr:
    89  		getAliasToName(ctx, t.Left, alias, aliasMap)
    90  		getAliasToName(ctx, t.Right, alias, aliasMap)
    91  	}
    92  }
    93  
    94  func getUpdateTableInfo(ctx CompilerContext, stmt *tree.Update) (*dmlTableInfo, error) {
    95  	tblInfo, err := getDmlTableInfo(ctx, stmt.Tables, stmt.With, nil)
    96  	if err != nil {
    97  		return nil, err
    98  	}
    99  
   100  	//check update field and set updateKeys
   101  	usedTbl := make(map[string]map[string]tree.Expr)
   102  	allColumns := make(map[string]map[string]struct{})
   103  	for alias, idx := range tblInfo.alias {
   104  		allColumns[alias] = make(map[string]struct{})
   105  		for _, col := range tblInfo.tableDefs[idx].Cols {
   106  			allColumns[alias][col.Name] = struct{}{}
   107  		}
   108  	}
   109  
   110  	appendToTbl := func(table, column string, expr tree.Expr) {
   111  		if _, exists := usedTbl[table]; !exists {
   112  			usedTbl[table] = make(map[string]tree.Expr)
   113  		}
   114  		usedTbl[table][column] = expr
   115  	}
   116  
   117  	for _, updateExpr := range stmt.Exprs {
   118  		if len(updateExpr.Names) > 1 {
   119  			return nil, moerr.NewNYI(ctx.GetContext(), "unsupport expr")
   120  		}
   121  		parts := updateExpr.Names[0]
   122  		expr := updateExpr.Expr
   123  		if parts.NumParts > 1 {
   124  			colName := parts.Parts[0]
   125  			tblName := parts.Parts[1]
   126  			if _, tblExists := tblInfo.alias[tblName]; tblExists {
   127  				if _, colExists := allColumns[tblName][colName]; colExists {
   128  					appendToTbl(tblName, colName, expr)
   129  				} else {
   130  					return nil, moerr.NewInternalError(ctx.GetContext(), "column '%v' not found in table %s", colName, tblName)
   131  				}
   132  			} else {
   133  				return nil, moerr.NewNoSuchTable(ctx.GetContext(), "", tblName)
   134  			}
   135  		} else {
   136  			colName := parts.Parts[0]
   137  			tblName := ""
   138  			found := false
   139  			for alias, colulmns := range allColumns {
   140  				if _, colExists := colulmns[colName]; colExists {
   141  					if tblName != "" {
   142  						return nil, moerr.NewInternalError(ctx.GetContext(), "Column '%v' in field list is ambiguous", colName)
   143  					}
   144  					found = true
   145  					appendToTbl(alias, colName, expr)
   146  				}
   147  			}
   148  			if !found {
   149  				return nil, moerr.NewInternalError(ctx.GetContext(), "column '%v' not found in table %s", colName, tblName)
   150  			}
   151  		}
   152  	}
   153  
   154  	// remove unused table
   155  	newTblInfo := &dmlTableInfo{
   156  		nameToIdx: make(map[string]int),
   157  		idToName:  make(map[uint64]string),
   158  		alias:     make(map[string]int),
   159  	}
   160  	for alias, columns := range usedTbl {
   161  		idx := tblInfo.alias[alias]
   162  		tblDef := tblInfo.tableDefs[idx]
   163  		newTblInfo.objRef = append(newTblInfo.objRef, tblInfo.objRef[idx])
   164  		newTblInfo.tableDefs = append(newTblInfo.tableDefs, tblDef)
   165  		newTblInfo.isClusterTable = append(newTblInfo.isClusterTable, tblInfo.isClusterTable[idx])
   166  		newTblInfo.alias[alias] = len(newTblInfo.tableDefs) - 1
   167  		newTblInfo.updateKeys = append(newTblInfo.updateKeys, columns)
   168  
   169  		if !newTblInfo.haveConstraint {
   170  			if len(tblDef.RefChildTbls) > 0 {
   171  				newTblInfo.haveConstraint = true
   172  			} else if len(tblDef.Fkeys) > 0 {
   173  				newTblInfo.haveConstraint = true
   174  			} else {
   175  				for _, indexdef := range tblDef.Indexes {
   176  					if indexdef.Unique {
   177  						newTblInfo.haveConstraint = true
   178  						break
   179  					}
   180  				}
   181  			}
   182  		}
   183  	}
   184  	for idx, ref := range newTblInfo.objRef {
   185  		key := ref.SchemaName + "." + ref.ObjName
   186  		newTblInfo.idToName[newTblInfo.tableDefs[idx].TblId] = key
   187  		newTblInfo.nameToIdx[key] = idx
   188  	}
   189  
   190  	return newTblInfo, nil
   191  }
   192  
   193  func setTableExprToDmlTableInfo(ctx CompilerContext, tbl tree.TableExpr, tblInfo *dmlTableInfo, aliasMap map[string][2]string, withMap map[string]struct{}) error {
   194  	var tblName, dbName, alias string
   195  
   196  	if aliasTbl, ok := tbl.(*tree.AliasedTableExpr); ok {
   197  		alias = string(aliasTbl.As.Alias)
   198  		tbl = aliasTbl.Expr
   199  	}
   200  
   201  	if jionTbl, ok := tbl.(*tree.JoinTableExpr); ok {
   202  		err := setTableExprToDmlTableInfo(ctx, jionTbl.Left, tblInfo, aliasMap, withMap)
   203  		if err != nil {
   204  			return err
   205  		}
   206  		if jionTbl.Right != nil {
   207  			return setTableExprToDmlTableInfo(ctx, jionTbl.Right, tblInfo, aliasMap, withMap)
   208  		}
   209  		return nil
   210  	}
   211  
   212  	if baseTbl, ok := tbl.(*tree.TableName); ok {
   213  		tblName = string(baseTbl.ObjectName)
   214  		dbName = string(baseTbl.SchemaName)
   215  	}
   216  
   217  	if _, exist := withMap[tblName]; exist {
   218  		return nil
   219  	}
   220  
   221  	if aliasNames, exist := aliasMap[tblName]; exist {
   222  		dbName = aliasNames[0]
   223  		tblName = aliasNames[1]
   224  	}
   225  
   226  	if tblName == "" {
   227  		return nil
   228  	}
   229  
   230  	if dbName == "" {
   231  		dbName = ctx.DefaultDatabase()
   232  	}
   233  
   234  	_, tableDef := ctx.Resolve(dbName, tblName)
   235  	if tableDef == nil {
   236  		return moerr.NewNoSuchTable(ctx.GetContext(), dbName, tblName)
   237  	}
   238  	if tableDef.TableType == catalog.SystemExternalRel {
   239  		return moerr.NewInvalidInput(ctx.GetContext(), "cannot insert/update/delete from external table")
   240  	} else if tableDef.TableType == catalog.SystemViewRel {
   241  		return moerr.NewInvalidInput(ctx.GetContext(), "cannot insert/update/delete from view")
   242  	}
   243  
   244  	isClusterTable := util.TableIsClusterTable(tableDef.GetTableType())
   245  	if isClusterTable && ctx.GetAccountId() != catalog.System_Account {
   246  		return moerr.NewInternalError(ctx.GetContext(), "only the sys account can insert/update/delete the cluster table")
   247  	}
   248  
   249  	if util.TableIsClusterTable(tableDef.GetTableType()) && ctx.GetAccountId() != catalog.System_Account {
   250  		return moerr.NewInternalError(ctx.GetContext(), "only the sys account can insert/update/delete the cluster table %s", tableDef.GetName())
   251  	}
   252  
   253  	if !tblInfo.haveConstraint {
   254  		if len(tableDef.RefChildTbls) > 0 {
   255  			tblInfo.haveConstraint = true
   256  		} else if len(tableDef.Fkeys) > 0 {
   257  			tblInfo.haveConstraint = true
   258  		} else {
   259  			for _, indexdef := range tableDef.Indexes {
   260  				if indexdef.Unique {
   261  					tblInfo.haveConstraint = true
   262  					break
   263  				}
   264  			}
   265  		}
   266  	}
   267  
   268  	nowIdx := len(tblInfo.tableDefs)
   269  	tblInfo.isClusterTable = append(tblInfo.isClusterTable, isClusterTable)
   270  	tblInfo.objRef = append(tblInfo.objRef, &ObjectRef{
   271  		Obj:        int64(tableDef.TblId),
   272  		SchemaName: dbName,
   273  		ObjName:    tblName,
   274  	})
   275  	tblInfo.tableDefs = append(tblInfo.tableDefs, tableDef)
   276  	key := dbName + "." + tblName
   277  	tblInfo.nameToIdx[key] = nowIdx
   278  	tblInfo.idToName[tableDef.TblId] = key
   279  	if alias == "" {
   280  		alias = tblName
   281  	}
   282  	tblInfo.alias[alias] = nowIdx
   283  
   284  	return nil
   285  }
   286  
   287  func getDmlTableInfo(ctx CompilerContext, tableExprs tree.TableExprs, with *tree.With, aliasMap map[string][2]string) (*dmlTableInfo, error) {
   288  	tblInfo := &dmlTableInfo{
   289  		nameToIdx: make(map[string]int),
   290  		idToName:  make(map[uint64]string),
   291  		alias:     make(map[string]int),
   292  	}
   293  
   294  	cteMap := make(map[string]struct{})
   295  	if with != nil {
   296  		for _, cte := range with.CTEs {
   297  			cteMap[string(cte.Name.Alias)] = struct{}{}
   298  		}
   299  	}
   300  
   301  	for _, tbl := range tableExprs {
   302  		err := setTableExprToDmlTableInfo(ctx, tbl, tblInfo, aliasMap, cteMap)
   303  		if err != nil {
   304  			return nil, err
   305  		}
   306  	}
   307  
   308  	return tblInfo, nil
   309  }
   310  
   311  func updateToSelect(builder *QueryBuilder, bindCtx *BindContext, stmt *tree.Update, tableInfo *dmlTableInfo, haveConstraint bool) (int32, error) {
   312  	fromTables := &tree.From{
   313  		Tables: stmt.Tables,
   314  	}
   315  	selectList := make([]tree.SelectExpr, len(tableInfo.tableDefs))
   316  
   317  	// append  table.* to project list
   318  	columnsSize := 0
   319  	for alias, i := range tableInfo.alias {
   320  		e, _ := tree.NewUnresolvedNameWithStar(builder.GetContext(), alias)
   321  		columnsSize += len(tableInfo.tableDefs[i].Cols)
   322  		selectList[i] = tree.SelectExpr{
   323  			Expr: e,
   324  		}
   325  	}
   326  
   327  	// append  [update expr] to project list
   328  	counter := 0
   329  	updateColsOffset := make([]map[string]int, len(tableInfo.updateKeys))
   330  	for idx, tbUpdateMap := range tableInfo.updateKeys {
   331  		updateColsOffset[idx] = make(map[string]int)
   332  		for colName, updateCol := range tbUpdateMap {
   333  			valuePos := columnsSize + counter
   334  			// Add update expression after select list
   335  			selectList = append(selectList, tree.SelectExpr{
   336  				Expr: updateCol,
   337  			})
   338  			updateColsOffset[idx][colName] = valuePos
   339  			counter++
   340  		}
   341  	}
   342  
   343  	// origin table values to their position in dev derived table
   344  	oldColPosMap := make([]map[string]int, len(tableInfo.tableDefs))
   345  	// insert/update values to their position in derived table
   346  	newColPosMap := make([]map[string]int, len(tableInfo.tableDefs))
   347  	projectSeq := 0
   348  	updateCol := make([]map[string]int32, len(tableInfo.updateKeys))
   349  	for idx, tableDef := range tableInfo.tableDefs {
   350  		//append update
   351  		oldColPosMap[idx] = make(map[string]int)
   352  		newColPosMap[idx] = make(map[string]int)
   353  		updateCol[idx] = make(map[string]int32)
   354  		for j, coldef := range tableDef.Cols {
   355  			oldColPosMap[idx][coldef.Name] = projectSeq + j
   356  			if pos, ok := updateColsOffset[idx][coldef.Name]; ok {
   357  				newColPosMap[idx][coldef.Name] = pos
   358  				updateCol[idx][coldef.Name] = int32(j)
   359  			} else {
   360  				newColPosMap[idx][coldef.Name] = projectSeq + j
   361  			}
   362  		}
   363  		projectSeq += len(tableDef.Cols)
   364  	}
   365  	tableInfo.oldColPosMap = oldColPosMap
   366  	tableInfo.newColPosMap = newColPosMap
   367  	tableInfo.updateCol = updateCol
   368  
   369  	selectAst := &tree.Select{
   370  		Select: &tree.SelectClause{
   371  			Distinct: false,
   372  			Exprs:    selectList,
   373  			From:     fromTables,
   374  			Where:    stmt.Where,
   375  		},
   376  		OrderBy: stmt.OrderBy,
   377  		Limit:   stmt.Limit,
   378  		With:    stmt.With,
   379  	}
   380  	//ftCtx := tree.NewFmtCtx(dialect.MYSQL)
   381  	//selectAst.Format(ftCtx)
   382  	//sql := ftCtx.String()
   383  	//fmt.Print(sql)
   384  	return builder.buildSelect(selectAst, bindCtx, false)
   385  }
   386  
   387  func initInsertStmt(builder *QueryBuilder, bindCtx *BindContext, stmt *tree.Insert, info *dmlSelectInfo) error {
   388  	var err error
   389  	var updateColumns []string
   390  	tableDef := info.tblInfo.tableDefs[0]
   391  	syntaxHasColumnNames := false
   392  	isClusterTable := info.tblInfo.isClusterTable[0]
   393  	colToIdx := make(map[string]int)
   394  	oldColPosMap := make(map[string]int)
   395  	for i, col := range tableDef.Cols {
   396  		colToIdx[col.Name] = i
   397  		oldColPosMap[col.Name] = i
   398  	}
   399  	info.tblInfo.oldColPosMap = append(info.tblInfo.oldColPosMap, oldColPosMap)
   400  	info.tblInfo.newColPosMap = append(info.tblInfo.newColPosMap, oldColPosMap)
   401  
   402  	if stmt.Columns == nil {
   403  		if isClusterTable {
   404  			for _, col := range tableDef.Cols {
   405  				if !util.IsClusterTableAttribute(col.Name) {
   406  					updateColumns = append(updateColumns, col.Name)
   407  				}
   408  			}
   409  		} else {
   410  			for _, col := range tableDef.Cols {
   411  				updateColumns = append(updateColumns, col.Name)
   412  			}
   413  		}
   414  	} else {
   415  		syntaxHasColumnNames = true
   416  		for _, column := range stmt.Columns {
   417  			colName := string(column)
   418  			if isClusterTable && util.IsClusterTableAttribute(colName) {
   419  				return moerr.NewInvalidInput(builder.GetContext(), "do not specify the attribute %s for the cluster table", util.GetClusterTableAttributeName())
   420  			}
   421  			if _, exists := colToIdx[string(column)]; !exists {
   422  				return moerr.NewInvalidInput(builder.GetContext(), "insert value into unknown column '%s'", colName)
   423  			}
   424  			updateColumns = append(updateColumns, colName)
   425  		}
   426  	}
   427  
   428  	var astSlt *tree.Select
   429  	switch slt := stmt.Rows.Select.(type) {
   430  	// rewrite 'insert into tbl values (1,1)' to 'insert into tbl select * from (values row(1,1))'
   431  	case *tree.ValuesClause:
   432  		isAllDefault := false
   433  		if slt.Rows[0] == nil {
   434  			isAllDefault = true
   435  		}
   436  		if isAllDefault {
   437  			for j, row := range slt.Rows {
   438  				if row != nil {
   439  					return moerr.NewInternalError(builder.GetContext(), fmt.Sprintf("Column count doesn't match value count at row '%v'", j))
   440  				}
   441  			}
   442  		} else {
   443  			colCount := len(updateColumns)
   444  			for j, row := range slt.Rows {
   445  				if len(row) != colCount {
   446  					return moerr.NewInternalError(builder.GetContext(), fmt.Sprintf("Column count doesn't match value count at row '%v'", j))
   447  				}
   448  			}
   449  		}
   450  
   451  		//example1:insert into a values ();
   452  		//but it does not work at the case:
   453  		//insert into a(a) values (); insert into a values (0),();
   454  		if isAllDefault && syntaxHasColumnNames {
   455  			return moerr.NewInvalidInput(builder.GetContext(), "insert values does not match the number of columns")
   456  		}
   457  
   458  		err = buildValueScan(isAllDefault, info, builder, bindCtx, tableDef, slt, updateColumns, colToIdx)
   459  		if err != nil {
   460  			return err
   461  		}
   462  
   463  	case *tree.SelectClause:
   464  		astSlt = stmt.Rows
   465  
   466  		subCtx := NewBindContext(builder, bindCtx)
   467  		info.rootId, err = builder.buildSelect(astSlt, subCtx, false)
   468  		if err != nil {
   469  			return err
   470  		}
   471  
   472  	case *tree.ParenSelect:
   473  		astSlt = slt.Select
   474  
   475  		subCtx := NewBindContext(builder, bindCtx)
   476  		info.rootId, err = builder.buildSelect(astSlt, subCtx, false)
   477  		if err != nil {
   478  			return err
   479  		}
   480  
   481  	default:
   482  		return moerr.NewInvalidInput(builder.GetContext(), "insert has unknown select statement")
   483  	}
   484  
   485  	err = builder.addBinding(info.rootId, tree.AliasClause{
   486  		Alias: derivedTableName,
   487  	}, bindCtx)
   488  	if err != nil {
   489  		return err
   490  	}
   491  
   492  	lastNode := builder.qry.Nodes[info.rootId]
   493  	if len(updateColumns) != len(lastNode.ProjectList) {
   494  		return moerr.NewInvalidInput(builder.GetContext(), "insert values does not match the number of columns")
   495  	}
   496  
   497  	tag := builder.qry.Nodes[info.rootId].BindingTags[0]
   498  	info.derivedTableId = info.rootId
   499  	oldProject := append([]*Expr{}, lastNode.ProjectList...)
   500  
   501  	insertColToExpr := make(map[string]*Expr)
   502  	for i, column := range updateColumns {
   503  		colIdx := colToIdx[column]
   504  		projExpr := &plan.Expr{
   505  			Typ: oldProject[i].Typ,
   506  			Expr: &plan.Expr_Col{
   507  				Col: &plan.ColRef{
   508  					RelPos: tag,
   509  					ColPos: int32(i),
   510  				},
   511  			},
   512  		}
   513  		projExpr, err = forceCastExpr(builder.GetContext(), projExpr, tableDef.Cols[colIdx].Typ)
   514  		if err != nil {
   515  			return err
   516  		}
   517  		insertColToExpr[column] = projExpr
   518  	}
   519  
   520  	// have tables : t1(a default 0, b int, pk(a,b)) ,  t2(j int,k int)
   521  	// rewrite 'insert into t1 select * from t2' to
   522  	// select 'select _t.j, _t.k from (select * from t2) _t
   523  	// --------
   524  	// rewrite 'insert into t1(b) values (1)' to
   525  	// select 'select 0, _t.column_0 from (select * from values (1)) _t
   526  	projectList := make([]*Expr, 0, len(tableDef.Cols))
   527  	for _, col := range tableDef.Cols {
   528  		if oldExpr, exists := insertColToExpr[col.Name]; exists {
   529  			projectList = append(projectList, oldExpr)
   530  		} else {
   531  			defExpr, err := getDefaultExpr(builder.GetContext(), col)
   532  			if err != nil {
   533  				return err
   534  			}
   535  			projectList = append(projectList, defExpr)
   536  		}
   537  	}
   538  
   539  	// append ProjectNode
   540  	projectCtx := NewBindContext(builder, bindCtx)
   541  	lastTag := builder.genNewTag()
   542  	info.rootId = builder.appendNode(&plan.Node{
   543  		NodeType:    plan.Node_PROJECT,
   544  		ProjectList: projectList,
   545  		Children:    []int32{info.rootId},
   546  		BindingTags: []int32{lastTag},
   547  	}, projectCtx)
   548  
   549  	info.projectList = make([]*Expr, len(projectList))
   550  	info.derivedTableId = info.rootId
   551  	for i, e := range projectList {
   552  		info.projectList[i] = &plan.Expr{
   553  			Typ: e.Typ,
   554  			Expr: &plan.Expr_Col{
   555  				Col: &plan.ColRef{
   556  					RelPos: lastTag,
   557  					ColPos: int32(i),
   558  				},
   559  			},
   560  		}
   561  	}
   562  	info.idx = int32(len(info.projectList))
   563  
   564  	return nil
   565  }
   566  
   567  func deleteToSelect(builder *QueryBuilder, bindCtx *BindContext, node *tree.Delete, haveConstraint bool) (int32, error) {
   568  	var selectList []tree.SelectExpr
   569  	fromTables := &tree.From{}
   570  
   571  	getResolveExpr := func(tblName string) tree.SelectExpr {
   572  		var ret *tree.UnresolvedName
   573  		if haveConstraint {
   574  			ret, _ = tree.NewUnresolvedNameWithStar(builder.GetContext(), tblName)
   575  		} else {
   576  			ret, _ = tree.NewUnresolvedName(builder.GetContext(), tblName, catalog.Row_ID)
   577  		}
   578  		return tree.SelectExpr{
   579  			Expr: ret,
   580  		}
   581  	}
   582  
   583  	for _, tbl := range node.Tables {
   584  		if aliasTbl, ok := tbl.(*tree.AliasedTableExpr); ok {
   585  			alias := string(aliasTbl.As.Alias)
   586  			if alias != "" {
   587  				selectList = append(selectList, getResolveExpr(alias))
   588  			} else {
   589  				astTbl := aliasTbl.Expr.(*tree.TableName)
   590  				selectList = append(selectList, getResolveExpr(string(astTbl.ObjectName)))
   591  			}
   592  		} else if astTbl, ok := tbl.(*tree.TableName); ok {
   593  			selectList = append(selectList, getResolveExpr(string(astTbl.ObjectName)))
   594  		}
   595  	}
   596  
   597  	if node.TableRefs != nil {
   598  		fromTables.Tables = node.TableRefs
   599  	} else {
   600  		fromTables.Tables = node.Tables
   601  	}
   602  
   603  	astSelect := &tree.Select{
   604  		Select: &tree.SelectClause{
   605  			Distinct: false,
   606  			Exprs:    selectList,
   607  			From:     fromTables,
   608  			Where:    node.Where,
   609  		},
   610  		OrderBy: node.OrderBy,
   611  		Limit:   node.Limit,
   612  		With:    node.With,
   613  	}
   614  	// ftCtx := tree.NewFmtCtx(dialectType)
   615  	// astSelect.Format(ftCtx)
   616  	// sql := ftCtx.String()
   617  	// fmt.Print(sql)
   618  
   619  	return builder.buildSelect(astSelect, bindCtx, false)
   620  }
   621  
   622  func initDeleteStmt(builder *QueryBuilder, bindCtx *BindContext, info *dmlSelectInfo, stmt *tree.Delete) error {
   623  	var err error
   624  	subCtx := NewBindContext(builder, bindCtx)
   625  	info.rootId, err = deleteToSelect(builder, subCtx, stmt, true)
   626  	if err != nil {
   627  		return err
   628  	}
   629  
   630  	err = builder.addBinding(info.rootId, tree.AliasClause{
   631  		Alias: derivedTableName,
   632  	}, bindCtx)
   633  	if err != nil {
   634  		return err
   635  	}
   636  
   637  	lastNode := builder.qry.Nodes[info.rootId]
   638  	tag := builder.qry.Nodes[info.rootId].BindingTags[0]
   639  	info.derivedTableId = info.rootId
   640  
   641  	// origin table values to their position
   642  	oldColPosMap := make([]map[string]int, len(info.tblInfo.tableDefs))
   643  	projectSeq := 0
   644  	for idx, tableDef := range info.tblInfo.tableDefs {
   645  		oldColPosMap[idx] = make(map[string]int)
   646  		for j, coldef := range tableDef.Cols {
   647  			pos := projectSeq + j
   648  			oldColPosMap[idx][coldef.Name] = pos
   649  			if coldef.Name == catalog.Row_ID {
   650  				info.projectList = append(info.projectList, &plan.Expr{
   651  					Typ: coldef.Typ,
   652  					Expr: &plan.Expr_Col{
   653  						Col: &plan.ColRef{
   654  							RelPos: tag,
   655  							ColPos: int32(pos),
   656  						},
   657  					},
   658  				})
   659  			}
   660  		}
   661  		projectSeq += len(tableDef.Cols)
   662  	}
   663  	info.tblInfo.oldColPosMap = oldColPosMap
   664  	info.tblInfo.newColPosMap = oldColPosMap //we donot need this field in delete statement
   665  
   666  	for idx, expr := range lastNode.ProjectList {
   667  		if expr.Typ.Id == int32(types.T_Rowid) {
   668  			info.projectList = append(info.projectList, &plan.Expr{
   669  				Typ: expr.Typ,
   670  				Expr: &plan.Expr_Col{
   671  					Col: &plan.ColRef{
   672  						RelPos: tag,
   673  						ColPos: int32(idx),
   674  					},
   675  				},
   676  			})
   677  		}
   678  	}
   679  	info.idx = int32(len(info.projectList))
   680  	return nil
   681  }
   682  
   683  func checkNotNull(ctx context.Context, expr *Expr, tableDef *TableDef, col *ColDef) error {
   684  	isConstantNull := false
   685  	if ef, ok := expr.Expr.(*plan.Expr_C); ok {
   686  		isConstantNull = ef.C.Isnull
   687  	}
   688  	if !isConstantNull {
   689  		return nil
   690  	}
   691  
   692  	if col.NotNull {
   693  		return moerr.NewConstraintViolation(ctx, fmt.Sprintf("Column '%s' cannot be null", col.Name))
   694  	}
   695  
   696  	if (col.Primary && !col.Typ.AutoIncr) ||
   697  		(col.Default != nil && !col.Default.NullAbility) {
   698  		return moerr.NewConstraintViolation(ctx, fmt.Sprintf("Column '%s' cannot be null", col.Name))
   699  	}
   700  
   701  	if tableDef.CompositePkey != nil {
   702  		names := util.SplitCompositePrimaryKeyColumnName(tableDef.CompositePkey.Name)
   703  		for _, name := range names {
   704  			if name == col.Name {
   705  				return moerr.NewConstraintViolation(ctx, fmt.Sprintf("Column '%s' cannot be null", name))
   706  			}
   707  		}
   708  	}
   709  
   710  	return nil
   711  }
   712  
   713  func forceCastExpr(ctx context.Context, expr *Expr, targetType *Type) (*Expr, error) {
   714  	t1, t2 := makeTypeByPlan2Expr(expr), makeTypeByPlan2Type(targetType)
   715  	if t1.Oid == t2.Oid && t1.Width == t2.Width && t1.Precision == t2.Precision && t1.Size == t2.Size && t1.Scale == t2.Scale {
   716  		return expr, nil
   717  	}
   718  
   719  	targetType.NotNullable = expr.Typ.NotNullable
   720  	id, _, _, err := function.GetFunctionByName(ctx, "cast", []types.Type{t1, t2})
   721  	if err != nil {
   722  		return nil, err
   723  	}
   724  	t := &plan.Expr{
   725  		Typ: targetType,
   726  		Expr: &plan.Expr_T{
   727  			T: &plan.TargetType{
   728  				Typ: targetType,
   729  			},
   730  		},
   731  	}
   732  	return &plan.Expr{
   733  		Expr: &plan.Expr_F{
   734  			F: &plan.Function{
   735  				Func: &ObjectRef{Obj: id, ObjName: "cast"},
   736  				Args: []*Expr{expr, t},
   737  			},
   738  		},
   739  		Typ: targetType,
   740  	}, nil
   741  }
   742  
   743  func initUpdateStmt(builder *QueryBuilder, bindCtx *BindContext, info *dmlSelectInfo, stmt *tree.Update) error {
   744  	var err error
   745  	subCtx := NewBindContext(builder, bindCtx)
   746  
   747  	info.rootId, err = updateToSelect(builder, subCtx, stmt, info.tblInfo, true)
   748  	if err != nil {
   749  		return err
   750  	}
   751  
   752  	err = builder.addBinding(info.rootId, tree.AliasClause{
   753  		Alias: derivedTableName,
   754  	}, bindCtx)
   755  	if err != nil {
   756  		return err
   757  	}
   758  
   759  	lastNode := builder.qry.Nodes[info.rootId]
   760  	tag := lastNode.BindingTags[0]
   761  	info.derivedTableId = info.rootId
   762  
   763  	idx := 0
   764  	for i, tableDef := range info.tblInfo.tableDefs {
   765  		updateKeysMap := info.tblInfo.updateKeys[i]
   766  		newColPosMap := info.tblInfo.newColPosMap[i]
   767  		nameToIdx := make(map[string]int32)
   768  		for j, coldef := range tableDef.Cols {
   769  			nameToIdx[coldef.Name] = int32(j)
   770  		}
   771  
   772  		for _, coldef := range tableDef.Cols {
   773  			if _, ok := updateKeysMap[coldef.Name]; ok {
   774  				pos := newColPosMap[coldef.Name]
   775  				posExpr := lastNode.ProjectList[pos]
   776  				if posExpr.Typ == nil { // set col = default
   777  					lastNode.ProjectList[pos], err = getDefaultExpr(builder.GetContext(), coldef)
   778  					if err != nil {
   779  						return err
   780  					}
   781  					posExpr = lastNode.ProjectList[pos]
   782  				}
   783  				err = checkNotNull(builder.GetContext(), posExpr, tableDef, coldef)
   784  				if err != nil {
   785  					return err
   786  				}
   787  				lastNode.ProjectList[pos], err = forceCastExpr(builder.GetContext(), posExpr, coldef.Typ)
   788  				if err != nil {
   789  					return err
   790  				}
   791  				projExpr := &plan.Expr{
   792  					Typ: coldef.Typ,
   793  					Expr: &plan.Expr_Col{
   794  						Col: &plan.ColRef{
   795  							RelPos: tag,
   796  							ColPos: int32(pos),
   797  						},
   798  					},
   799  				}
   800  				info.projectList = append(info.projectList, projExpr)
   801  
   802  			} else {
   803  				if coldef.OnUpdate != nil && coldef.OnUpdate.Expr != nil {
   804  					lastNode.ProjectList[idx] = coldef.OnUpdate.Expr
   805  				}
   806  
   807  				lastNode.ProjectList[idx], err = forceCastExpr(builder.GetContext(), lastNode.ProjectList[idx], coldef.Typ)
   808  				if err != nil {
   809  					return err
   810  				}
   811  
   812  				info.projectList = append(info.projectList, &plan.Expr{
   813  					Typ: coldef.Typ,
   814  					Expr: &plan.Expr_Col{
   815  						Col: &plan.ColRef{
   816  							RelPos: tag,
   817  							ColPos: int32(idx),
   818  						},
   819  					},
   820  				})
   821  			}
   822  			idx++
   823  		}
   824  	}
   825  	info.idx = int32(len(info.projectList))
   826  	return nil
   827  }
   828  
   829  func rewriteDmlSelectInfo(builder *QueryBuilder, bindCtx *BindContext, info *dmlSelectInfo, tableDef *TableDef, baseNodeId int32, rewriteIdx int) error {
   830  	// posMap := make(map[string]int32)
   831  	typMap := make(map[string]*plan.Type)
   832  	id2name := make(map[uint64]string)
   833  
   834  	//use origin query as left, we need add prefix pos
   835  	var oldColPosMap map[string]int
   836  	var newColPosMap map[string]int
   837  	if rewriteIdx > -1 {
   838  		oldColPosMap = info.tblInfo.oldColPosMap[rewriteIdx]
   839  		newColPosMap = info.tblInfo.newColPosMap[rewriteIdx]
   840  		for _, col := range tableDef.Cols {
   841  			typMap[col.Name] = col.Typ
   842  			id2name[col.ColId] = col.Name
   843  		}
   844  
   845  	} else {
   846  		// unsupport deep level, no test
   847  		oldColPosMap = make(map[string]int)
   848  		newColPosMap = make(map[string]int)
   849  		for idx, col := range tableDef.Cols {
   850  			oldColPosMap[col.Name] = idx
   851  			newColPosMap[col.Name] = idx
   852  			typMap[col.Name] = col.Typ
   853  			id2name[col.ColId] = col.Name
   854  		}
   855  	}
   856  
   857  	// rewrite index, to get rows of unique table to delete
   858  	if info.typ != "insert" {
   859  		if tableDef.Indexes != nil {
   860  			for _, indexdef := range tableDef.Indexes {
   861  				if indexdef.Unique {
   862  					idxRef := &plan.ObjectRef{
   863  						SchemaName: builder.compCtx.DefaultDatabase(),
   864  						ObjName:    indexdef.IndexTableName,
   865  					}
   866  
   867  					// append table_scan node
   868  					joinCtx := NewBindContext(builder, bindCtx)
   869  
   870  					rightCtx := NewBindContext(builder, joinCtx)
   871  					astTblName := tree.NewTableName(tree.Identifier(indexdef.IndexTableName), tree.ObjectNamePrefix{})
   872  					rightId, err := builder.buildTable(astTblName, rightCtx)
   873  					if err != nil {
   874  						return err
   875  					}
   876  					rightTag := builder.qry.Nodes[rightId].BindingTags[0]
   877  					baseTag := builder.qry.Nodes[baseNodeId].BindingTags[0]
   878  					rightTableDef := builder.qry.Nodes[rightId].TableDef
   879  					rightRowIdPos := int32(len(rightTableDef.Cols)) - 1
   880  					rightIdxPos := int32(0)
   881  
   882  					// append projection
   883  					info.projectList = append(info.projectList, &plan.Expr{
   884  						Typ: rightTableDef.Cols[rightRowIdPos].Typ,
   885  						Expr: &plan.Expr_Col{
   886  							Col: &plan.ColRef{
   887  								RelPos: rightTag,
   888  								ColPos: rightRowIdPos,
   889  							},
   890  						},
   891  					})
   892  
   893  					rightExpr := &plan.Expr{
   894  						Typ: rightTableDef.Cols[rightIdxPos].Typ,
   895  						Expr: &plan.Expr_Col{
   896  							Col: &plan.ColRef{
   897  								RelPos: rightTag,
   898  								ColPos: rightIdxPos,
   899  							},
   900  						},
   901  					}
   902  
   903  					// append join node
   904  					var joinConds []*Expr
   905  					var leftExpr *Expr
   906  					partsLength := len(indexdef.Parts)
   907  					if partsLength == 1 {
   908  						orginIndexColumnName := indexdef.Parts[0]
   909  						typ := typMap[orginIndexColumnName]
   910  						leftExpr = &Expr{
   911  							Typ: typ,
   912  							Expr: &plan.Expr_Col{
   913  								Col: &plan.ColRef{
   914  									RelPos: baseTag,
   915  									ColPos: int32(oldColPosMap[orginIndexColumnName]),
   916  								},
   917  							},
   918  						}
   919  					} else {
   920  						args := make([]*Expr, partsLength)
   921  						for i, column := range indexdef.Parts {
   922  							typ := typMap[column]
   923  							args[i] = &plan.Expr{
   924  								Typ: typ,
   925  								Expr: &plan.Expr_Col{
   926  									Col: &plan.ColRef{
   927  										RelPos: baseTag,
   928  										ColPos: int32(oldColPosMap[column]),
   929  									},
   930  								},
   931  							}
   932  						}
   933  						leftExpr, err = bindFuncExprImplByPlanExpr(builder.GetContext(), "serial", args)
   934  						if err != nil {
   935  							return err
   936  						}
   937  					}
   938  
   939  					condExpr, err := bindFuncExprImplByPlanExpr(builder.GetContext(), "=", []*Expr{leftExpr, rightExpr})
   940  					if err != nil {
   941  						return err
   942  					}
   943  					joinConds = []*Expr{condExpr}
   944  
   945  					leftCtx := builder.ctxByNode[info.rootId]
   946  					err = joinCtx.mergeContexts(builder.GetContext(), leftCtx, rightCtx)
   947  					if err != nil {
   948  						return err
   949  					}
   950  					newRootId := builder.appendNode(&plan.Node{
   951  						NodeType: plan.Node_JOIN,
   952  						Children: []int32{info.rootId, rightId},
   953  						JoinType: plan.Node_LEFT,
   954  						OnList:   joinConds,
   955  					}, joinCtx)
   956  					bindCtx.binder = NewTableBinder(builder, bindCtx)
   957  					info.rootId = newRootId
   958  					info.onIdxTbl = append(info.onIdxTbl, idxRef)
   959  					info.onIdx = append(info.onIdx, info.idx)
   960  					info.idx = info.idx + 1
   961  				}
   962  			}
   963  		}
   964  	}
   965  
   966  	// check child table
   967  	if info.typ != "insert" {
   968  		for _, tableId := range tableDef.RefChildTbls {
   969  			if _, existInDelTable := info.tblInfo.idToName[tableId]; existInDelTable {
   970  				// delete parent_tbl, child_tbl from parent_tbl join child_tbl xxxxxx
   971  				// we will skip child_tbl here.
   972  				continue
   973  			}
   974  
   975  			_, childTableDef := builder.compCtx.ResolveById(tableId)
   976  			childPosMap := make(map[string]int32)
   977  			childTypMap := make(map[string]*plan.Type)
   978  			childId2name := make(map[uint64]string)
   979  			for idx, col := range childTableDef.Cols {
   980  				childPosMap[col.Name] = int32(idx)
   981  				childTypMap[col.Name] = col.Typ
   982  				childId2name[col.ColId] = col.Name
   983  			}
   984  
   985  			objRef := &plan.ObjectRef{
   986  				Obj:        int64(childTableDef.TblId),
   987  				SchemaName: builder.compCtx.DefaultDatabase(),
   988  				ObjName:    childTableDef.Name,
   989  			}
   990  
   991  			for _, fk := range childTableDef.Fkeys {
   992  				if fk.ForeignTbl == tableDef.TblId {
   993  					// in update statement. only add left join logic when update the column in foreign key
   994  					if info.typ == "update" {
   995  						updateRefColumn := false
   996  						for _, colId := range fk.ForeignCols {
   997  							updateName := id2name[colId]
   998  							if _, ok := info.tblInfo.updateKeys[rewriteIdx][updateName]; ok {
   999  								updateRefColumn = true
  1000  								break
  1001  							}
  1002  						}
  1003  						if !updateRefColumn {
  1004  							continue
  1005  						}
  1006  					}
  1007  
  1008  					// append table scan node
  1009  					joinCtx := NewBindContext(builder, bindCtx)
  1010  					rightCtx := NewBindContext(builder, joinCtx)
  1011  					astTblName := tree.NewTableName(tree.Identifier(childTableDef.Name), tree.ObjectNamePrefix{})
  1012  					rightId, err := builder.buildTable(astTblName, rightCtx)
  1013  					if err != nil {
  1014  						return err
  1015  					}
  1016  					rightTag := builder.qry.Nodes[rightId].BindingTags[0]
  1017  					baseNodeTag := builder.qry.Nodes[baseNodeId].BindingTags[0]
  1018  					// needRecursionCall := false
  1019  
  1020  					// build join conds
  1021  					joinConds := make([]*Expr, len(fk.Cols))
  1022  					for i, colId := range fk.Cols {
  1023  						for _, col := range childTableDef.Cols {
  1024  							if col.ColId == colId {
  1025  								childColumnName := col.Name
  1026  								originColumnName := id2name[fk.ForeignCols[i]]
  1027  
  1028  								leftExpr := &Expr{
  1029  									Typ: typMap[originColumnName],
  1030  									Expr: &plan.Expr_Col{
  1031  										Col: &plan.ColRef{
  1032  											RelPos: baseNodeTag,
  1033  											ColPos: int32(oldColPosMap[originColumnName]),
  1034  										},
  1035  									},
  1036  								}
  1037  								rightExpr := &plan.Expr{
  1038  									Typ: childTypMap[childColumnName],
  1039  									Expr: &plan.Expr_Col{
  1040  										Col: &plan.ColRef{
  1041  											RelPos: rightTag,
  1042  											ColPos: childPosMap[childColumnName],
  1043  										},
  1044  									},
  1045  								}
  1046  								condExpr, err := bindFuncExprImplByPlanExpr(builder.GetContext(), "=", []*Expr{leftExpr, rightExpr})
  1047  								if err != nil {
  1048  									return err
  1049  								}
  1050  								joinConds[i] = condExpr
  1051  								break
  1052  							}
  1053  						}
  1054  					}
  1055  
  1056  					// append project
  1057  					var refAction plan.ForeignKeyDef_RefAction
  1058  					if info.typ == "update" {
  1059  						refAction = fk.OnUpdate
  1060  					} else {
  1061  						refAction = fk.OnDelete
  1062  					}
  1063  
  1064  					switch refAction {
  1065  					case plan.ForeignKeyDef_NO_ACTION, plan.ForeignKeyDef_RESTRICT, plan.ForeignKeyDef_SET_DEFAULT:
  1066  						info.projectList = append(info.projectList, &plan.Expr{
  1067  							Typ: childTypMap[catalog.Row_ID],
  1068  							Expr: &plan.Expr_Col{
  1069  								Col: &plan.ColRef{
  1070  									RelPos: rightTag,
  1071  									ColPos: childPosMap[catalog.Row_ID],
  1072  								},
  1073  							},
  1074  						})
  1075  						info.onRestrict = append(info.onRestrict, info.idx)
  1076  						info.idx = info.idx + 1
  1077  						info.onRestrictTbl = append(info.onRestrictTbl, objRef)
  1078  
  1079  					case plan.ForeignKeyDef_CASCADE:
  1080  						// for update ,we need to reset column's value of child table, just like set null
  1081  						updateCol := make(map[string]int32)
  1082  						if info.typ == "update" {
  1083  							fkIdMap := make(map[uint64]uint64)
  1084  							for j, colId := range fk.Cols {
  1085  								fkIdMap[colId] = fk.ForeignCols[j]
  1086  							}
  1087  
  1088  							var setIdxs []int64
  1089  							for j, col := range childTableDef.Cols {
  1090  								if pIdx, ok := fkIdMap[col.ColId]; ok {
  1091  									originName := id2name[pIdx]
  1092  									info.projectList = append(info.projectList, &plan.Expr{
  1093  										Typ: col.Typ,
  1094  										Expr: &plan.Expr_Col{
  1095  											Col: &plan.ColRef{
  1096  												RelPos: baseNodeTag,
  1097  												ColPos: int32(newColPosMap[originName]),
  1098  											},
  1099  										},
  1100  									})
  1101  									updateCol[col.Name] = int32(j)
  1102  								} else {
  1103  									info.projectList = append(info.projectList, &plan.Expr{
  1104  										Typ: col.Typ,
  1105  										Expr: &plan.Expr_Col{
  1106  											Col: &plan.ColRef{
  1107  												RelPos: rightTag,
  1108  												ColPos: int32(j),
  1109  											},
  1110  										},
  1111  									})
  1112  								}
  1113  								setIdxs = append(setIdxs, int64(info.idx))
  1114  								info.idx = info.idx + 1
  1115  							}
  1116  							info.onCascade = append(info.onCascade, setIdxs)
  1117  							info.onCascadeRef = append(info.onCascadeRef, objRef)
  1118  							info.onCascadeTableDef = append(info.onCascadeTableDef, childTableDef)
  1119  							info.onCascadeUpdateCol = append(info.onCascadeUpdateCol, updateCol)
  1120  						} else {
  1121  							// for delete, we only get row_id and delete the rows
  1122  							info.projectList = append(info.projectList, &plan.Expr{
  1123  								Typ: childTypMap[catalog.Row_ID],
  1124  								Expr: &plan.Expr_Col{
  1125  									Col: &plan.ColRef{
  1126  										RelPos: rightTag,
  1127  										ColPos: childPosMap[catalog.Row_ID],
  1128  									},
  1129  								},
  1130  							})
  1131  							info.onCascade = append(info.onCascade, []int64{int64(info.idx)})
  1132  							info.idx = info.idx + 1
  1133  							info.onCascadeRef = append(info.onCascadeRef, objRef)
  1134  							info.onCascadeUpdateCol = append(info.onCascadeUpdateCol, updateCol)
  1135  						}
  1136  
  1137  						// needRecursionCall = true
  1138  
  1139  					case plan.ForeignKeyDef_SET_NULL:
  1140  						updateCol := make(map[string]int32)
  1141  						fkIdMap := make(map[uint64]struct{})
  1142  						for _, colId := range fk.Cols {
  1143  							fkIdMap[colId] = struct{}{}
  1144  						}
  1145  						var setIdxs []int64
  1146  						for j, col := range childTableDef.Cols {
  1147  							if _, ok := fkIdMap[col.ColId]; ok {
  1148  								info.projectList = append(info.projectList, &plan.Expr{
  1149  									Typ: col.Typ,
  1150  									Expr: &plan.Expr_C{
  1151  										C: &Const{
  1152  											Isnull: true,
  1153  										},
  1154  									},
  1155  								})
  1156  								updateCol[col.Name] = int32(j)
  1157  							} else {
  1158  								info.projectList = append(info.projectList, &plan.Expr{
  1159  									Typ: col.Typ,
  1160  									Expr: &plan.Expr_Col{
  1161  										Col: &plan.ColRef{
  1162  											RelPos: rightTag,
  1163  											ColPos: int32(j),
  1164  										},
  1165  									},
  1166  								})
  1167  							}
  1168  							setIdxs = append(setIdxs, int64(info.idx))
  1169  							info.idx = info.idx + 1
  1170  						}
  1171  						info.onSet = append(info.onSet, setIdxs)
  1172  						info.onSetRef = append(info.onSetRef, objRef)
  1173  						info.onSetTableDef = append(info.onSetTableDef, childTableDef)
  1174  						info.onSetUpdateCol = append(info.onSetUpdateCol, updateCol)
  1175  						// needRecursionCall = true
  1176  					}
  1177  
  1178  					// append join node
  1179  					leftCtx := builder.ctxByNode[info.rootId]
  1180  					err = joinCtx.mergeContexts(builder.GetContext(), leftCtx, rightCtx)
  1181  					if err != nil {
  1182  						return err
  1183  					}
  1184  					newRootId := builder.appendNode(&plan.Node{
  1185  						NodeType: plan.Node_JOIN,
  1186  						Children: []int32{info.rootId, rightId},
  1187  						JoinType: plan.Node_LEFT,
  1188  						OnList:   joinConds,
  1189  					}, joinCtx)
  1190  					bindCtx.binder = NewTableBinder(builder, bindCtx)
  1191  					info.rootId = newRootId
  1192  
  1193  					// if needRecursionCall {
  1194  
  1195  					// err := rewriteDeleteSelectInfo(builder, bindCtx, info, childTableDef, info.rootId)
  1196  					// if err != nil {
  1197  					// 	return err
  1198  					// }
  1199  					// }
  1200  				}
  1201  			}
  1202  		}
  1203  	}
  1204  
  1205  	// check parent table
  1206  	if info.typ != "delete" {
  1207  		parentIdx := make(map[string]int32)
  1208  
  1209  		for _, fk := range tableDef.Fkeys {
  1210  			// in update statement. only add left join logic when update the column in foreign key
  1211  			if info.typ == "update" {
  1212  				updateRefColumn := false
  1213  				for _, colId := range fk.Cols {
  1214  					updateName := id2name[colId]
  1215  					if _, ok := info.tblInfo.updateKeys[rewriteIdx][updateName]; ok {
  1216  						updateRefColumn = true
  1217  						break
  1218  					}
  1219  				}
  1220  				if !updateRefColumn {
  1221  					continue
  1222  				}
  1223  			}
  1224  
  1225  			// insert statement, we will alsways check parent ref
  1226  			for _, colId := range fk.Cols {
  1227  				updateName := id2name[colId]
  1228  				parentIdx[updateName] = info.idx
  1229  			}
  1230  
  1231  			_, parentTableDef := builder.compCtx.ResolveById(fk.ForeignTbl)
  1232  			parentPosMap := make(map[string]int32)
  1233  			parentTypMap := make(map[string]*plan.Type)
  1234  			parentId2name := make(map[uint64]string)
  1235  			for idx, col := range parentTableDef.Cols {
  1236  				parentPosMap[col.Name] = int32(idx)
  1237  				parentTypMap[col.Name] = col.Typ
  1238  				parentId2name[col.ColId] = col.Name
  1239  			}
  1240  
  1241  			// append table scan node
  1242  			joinCtx := NewBindContext(builder, bindCtx)
  1243  
  1244  			rightCtx := NewBindContext(builder, joinCtx)
  1245  			astTblName := tree.NewTableName(tree.Identifier(parentTableDef.Name), tree.ObjectNamePrefix{})
  1246  			rightId, err := builder.buildTable(astTblName, rightCtx)
  1247  			if err != nil {
  1248  				return err
  1249  			}
  1250  			rightTag := builder.qry.Nodes[rightId].BindingTags[0]
  1251  			baseNodeTag := builder.qry.Nodes[baseNodeId].BindingTags[0]
  1252  			// needRecursionCall := false
  1253  
  1254  			// build join conds
  1255  			joinConds := make([]*Expr, len(fk.Cols))
  1256  			for i, colId := range fk.ForeignCols {
  1257  				for _, col := range parentTableDef.Cols {
  1258  					if col.ColId == colId {
  1259  						parentColumnName := col.Name
  1260  						childColumnName := id2name[fk.Cols[i]]
  1261  
  1262  						leftExpr := &Expr{
  1263  							Typ: typMap[childColumnName],
  1264  							Expr: &plan.Expr_Col{
  1265  								Col: &plan.ColRef{
  1266  									RelPos: baseNodeTag,
  1267  									ColPos: int32(newColPosMap[childColumnName]),
  1268  								},
  1269  							},
  1270  						}
  1271  						rightExpr := &plan.Expr{
  1272  							Typ: parentTypMap[parentColumnName],
  1273  							Expr: &plan.Expr_Col{
  1274  								Col: &plan.ColRef{
  1275  									RelPos: rightTag,
  1276  									ColPos: parentPosMap[parentColumnName],
  1277  								},
  1278  							},
  1279  						}
  1280  						condExpr, err := bindFuncExprImplByPlanExpr(builder.GetContext(), "=", []*Expr{leftExpr, rightExpr})
  1281  						if err != nil {
  1282  							return err
  1283  						}
  1284  						joinConds[i] = condExpr
  1285  						break
  1286  					}
  1287  				}
  1288  			}
  1289  
  1290  			// append project
  1291  			info.projectList = append(info.projectList, &plan.Expr{
  1292  				Typ: parentTypMap[catalog.Row_ID],
  1293  				Expr: &plan.Expr_Col{
  1294  					Col: &plan.ColRef{
  1295  						RelPos: rightTag,
  1296  						ColPos: parentPosMap[catalog.Row_ID],
  1297  					},
  1298  				},
  1299  			})
  1300  			info.idx = info.idx + 1
  1301  
  1302  			// append join node
  1303  			leftCtx := builder.ctxByNode[info.rootId]
  1304  			err = joinCtx.mergeContexts(builder.GetContext(), leftCtx, rightCtx)
  1305  			if err != nil {
  1306  				return err
  1307  			}
  1308  			newRootId := builder.appendNode(&plan.Node{
  1309  				NodeType: plan.Node_JOIN,
  1310  				Children: []int32{info.rootId, rightId},
  1311  				JoinType: plan.Node_LEFT,
  1312  				OnList:   joinConds,
  1313  			}, joinCtx)
  1314  			bindCtx.binder = NewTableBinder(builder, bindCtx)
  1315  			info.rootId = newRootId
  1316  		}
  1317  
  1318  		info.parentIdx = append(info.parentIdx, parentIdx)
  1319  	}
  1320  
  1321  	// check for OnDuplicateUpdate
  1322  
  1323  	// todo check for replace
  1324  
  1325  	return nil
  1326  }
  1327  
  1328  func buildValueScan(
  1329  	isAllDefault bool,
  1330  	info *dmlSelectInfo,
  1331  	builder *QueryBuilder,
  1332  	bindCtx *BindContext,
  1333  	tableDef *TableDef,
  1334  	slt *tree.ValuesClause,
  1335  	updateColumns []string,
  1336  	colToIdx map[string]int,
  1337  ) error {
  1338  	var err error
  1339  	lastTag := builder.genNewTag()
  1340  	colCount := len(updateColumns)
  1341  	rowsetData := &plan.RowsetData{
  1342  		Cols: make([]*plan.ColData, colCount),
  1343  	}
  1344  	valueScanTableDef := &plan.TableDef{
  1345  		TblId: 0,
  1346  		Name:  "",
  1347  		Cols:  make([]*plan.ColDef, colCount),
  1348  	}
  1349  	projectList := make([]*Expr, colCount)
  1350  
  1351  	for i, colName := range updateColumns {
  1352  		col := tableDef.Cols[colToIdx[colName]]
  1353  		var defExpr *Expr
  1354  		rows := make([]*Expr, len(slt.Rows))
  1355  		if isAllDefault {
  1356  			defExpr, err := getDefaultExpr(builder.GetContext(), col)
  1357  			if err != nil {
  1358  				return err
  1359  			}
  1360  			defExpr, err = forceCastExpr(builder.GetContext(), defExpr, col.Typ)
  1361  			if err != nil {
  1362  				return err
  1363  			}
  1364  			for j := range slt.Rows {
  1365  				rows[j] = defExpr
  1366  			}
  1367  		} else {
  1368  			binder := NewDefaultBinder(builder.GetContext(), nil, nil, col.Typ, nil)
  1369  			for j, r := range slt.Rows {
  1370  				if _, ok := r[i].(*tree.DefaultVal); ok {
  1371  					defExpr, err = getDefaultExpr(builder.GetContext(), col)
  1372  					if err != nil {
  1373  						return err
  1374  					}
  1375  				} else {
  1376  					defExpr, err = binder.BindExpr(r[i], 0, true)
  1377  					if err != nil {
  1378  						return err
  1379  					}
  1380  				}
  1381  				defExpr, err = forceCastExpr(builder.GetContext(), defExpr, col.Typ)
  1382  				if err != nil {
  1383  					return err
  1384  				}
  1385  				rows[j] = defExpr
  1386  			}
  1387  		}
  1388  		rowsetData.Cols[i] = &plan.ColData{
  1389  			Data: rows,
  1390  		}
  1391  		colName := fmt.Sprintf("column_%d", i) // like MySQL
  1392  		valueScanTableDef.Cols[i] = &plan.ColDef{
  1393  			ColId: 0,
  1394  			Name:  colName,
  1395  			Typ:   col.Typ,
  1396  		}
  1397  		projectList[i] = &plan.Expr{
  1398  			Typ: col.Typ,
  1399  			Expr: &plan.Expr_Col{
  1400  				Col: &plan.ColRef{
  1401  					RelPos: lastTag,
  1402  					ColPos: int32(i),
  1403  				},
  1404  			},
  1405  		}
  1406  	}
  1407  	info.rootId = builder.appendNode(&plan.Node{
  1408  		NodeType:    plan.Node_VALUE_SCAN,
  1409  		RowsetData:  rowsetData,
  1410  		TableDef:    valueScanTableDef,
  1411  		BindingTags: []int32{lastTag},
  1412  	}, bindCtx)
  1413  	err = builder.addBinding(info.rootId, tree.AliasClause{
  1414  		Alias: "_ValueScan",
  1415  	}, bindCtx)
  1416  	if err != nil {
  1417  		return err
  1418  	}
  1419  
  1420  	lastTag = builder.genNewTag()
  1421  	info.rootId = builder.appendNode(&plan.Node{
  1422  		NodeType:    plan.Node_PROJECT,
  1423  		ProjectList: projectList,
  1424  		Children:    []int32{info.rootId},
  1425  		BindingTags: []int32{lastTag},
  1426  	}, bindCtx)
  1427  
  1428  	return nil
  1429  }