// getWhereClause returns a whereClause based on desired upper and lower // bounds for primary key. func (qs *QuerySplitter) getWhereClause(whereClause *sqlparser.Where, bindVars map[string]interface{}, start, end sqltypes.Value) *sqlparser.Where { var startClause *sqlparser.ComparisonExpr var endClause *sqlparser.ComparisonExpr var clauses sqlparser.BoolExpr // No upper or lower bound, just return the where clause of original query if start.IsNull() && end.IsNull() { return whereClause } pk := &sqlparser.ColName{ Name: sqlparser.SQLName(qs.splitColumn), } if !start.IsNull() { startClause = &sqlparser.ComparisonExpr{ Operator: sqlparser.GreaterEqualStr, Left: pk, Right: sqlparser.ValArg([]byte(":" + startBindVarName)), } bindVars[startBindVarName] = start.ToNative() } // splitColumn < end if !end.IsNull() { endClause = &sqlparser.ComparisonExpr{ Operator: sqlparser.LessThanStr, Left: pk, Right: sqlparser.ValArg([]byte(":" + endBindVarName)), } bindVars[endBindVarName] = end.ToNative() } if startClause == nil { clauses = endClause } else { if endClause == nil { clauses = startClause } else { // splitColumn >= start AND splitColumn < end clauses = &sqlparser.AndExpr{ Left: startClause, Right: endClause, } } } if whereClause != nil { clauses = &sqlparser.AndExpr{ Left: &sqlparser.ParenBoolExpr{Expr: whereClause.Expr}, Right: &sqlparser.ParenBoolExpr{Expr: clauses}, } } return &sqlparser.Where{ Type: sqlparser.WhereStr, Expr: clauses, } }
func buildIndexPlan(ins *sqlparser.Insert, tablename string, index *Index, plan *Plan) error { pos := -1 for i, column := range ins.Columns { if index.Column == sqlparser.GetColName(column.(*sqlparser.NonStarExpr).Expr) { pos = i break } } if pos == -1 && index.Owner == tablename && index.IsAutoInc { pos = len(ins.Columns) ins.Columns = append(ins.Columns, &sqlparser.NonStarExpr{Expr: &sqlparser.ColName{Name: []byte(index.Column)}}) ins.Rows.(sqlparser.Values)[0] = append(ins.Rows.(sqlparser.Values)[0].(sqlparser.ValTuple), &sqlparser.NullVal{}) } if pos == -1 { return fmt.Errorf("must supply value for indexed column: %s", index.Column) } row := ins.Rows.(sqlparser.Values)[0].(sqlparser.ValTuple) val, err := sqlparser.AsInterface(row[pos]) if err != nil { return fmt.Errorf("could not convert val: %s, pos: %d", row[pos], pos) } plan.Values = append(plan.Values.([]interface{}), val) if index.Owner == tablename && index.IsAutoInc { row[pos] = sqlparser.ValArg([]byte(fmt.Sprintf(":_%s", index.Column))) } return nil }
func convertBindVariableNamesToValExpr(bindVariableNames []string) []sqlparser.ValExpr { valExprs := make([]sqlparser.ValExpr, 0, len(bindVariableNames)) for _, bindVariableName := range bindVariableNames { valExprs = append(valExprs, sqlparser.ValArg([]byte(":"+bindVariableName))) } return valExprs }
// buildIndexPlan adds the insert value to the Values field for the specified ColumnVindex. // This value will be used at the time of insert to validate the vindex value. func buildIndexPlan(colVindex *vindexes.ColumnVindex, rowNum int, row sqlparser.ValTuple, pos int) (interface{}, error) { val, err := valConvert(row[pos]) if err != nil { return val, fmt.Errorf("could not convert val: %s, pos: %d: %v", sqlparser.String(row[pos]), pos, err) } row[pos] = sqlparser.ValArg([]byte(":_" + colVindex.Column.Original() + strconv.Itoa(rowNum))) return val, nil }
// buildIndexPlan adds the insert value to the Values field for the specified ColVindex. // This value will be used at the time of insert to validate the vindex value. func buildIndexPlan(ins *sqlparser.Insert, colVindex *vindexes.ColVindex, route *engine.Route) error { row, pos := findOrInsertPos(ins, colVindex.Col) val, err := valConvert(row[pos]) if err != nil { return fmt.Errorf("could not convert val: %s, pos: %d: %v", sqlparser.String(row[pos]), pos, err) } route.Values = append(route.Values.([]interface{}), val) row[pos] = sqlparser.ValArg([]byte(":_" + colVindex.Col)) return nil }
func buildAutoIncrementPlan(ins *sqlparser.Insert, autoinc *vindexes.AutoIncrement, route *engine.Route, rowValue []interface{}, rowNum int) (interface{}, []interface{}, error) { var autoIncVal interface{} // If it's also a colvindex, we have to add a redirect from route.Values. // Otherwise, we have to redirect from row[pos]. if autoinc.ColumnVindexNum >= 0 { autoIncVal = rowValue[autoinc.ColumnVindexNum] rowValue[autoinc.ColumnVindexNum] = ":" + engine.SeqVarName + strconv.Itoa(rowNum) return autoIncVal, rowValue, nil } row, pos := findOrInsertPos(ins, autoinc.Column, rowNum) val, err := valConvert(row[pos]) if err != nil { return autoIncVal, rowValue, fmt.Errorf("could not convert val: %s, pos: %d: %v", sqlparser.String(row[pos]), pos, err) } autoIncVal = val row[pos] = sqlparser.ValArg([]byte(":" + engine.SeqVarName + strconv.Itoa(rowNum))) return autoIncVal, rowValue, nil }
func buildIndexPlan(ins *sqlparser.Insert, tablename string, colVindex *ColVindex, plan *Plan) error { pos := -1 for i, column := range ins.Columns { if colVindex.Col == sqlparser.GetColName(column.(*sqlparser.NonStarExpr).Expr) { pos = i break } } if pos == -1 { pos = len(ins.Columns) ins.Columns = append(ins.Columns, &sqlparser.NonStarExpr{Expr: &sqlparser.ColName{Name: sqlparser.SQLName(colVindex.Col)}}) ins.Rows.(sqlparser.Values)[0] = append(ins.Rows.(sqlparser.Values)[0].(sqlparser.ValTuple), &sqlparser.NullVal{}) } row := ins.Rows.(sqlparser.Values)[0].(sqlparser.ValTuple) val, err := asInterface(row[pos]) if err != nil { return fmt.Errorf("could not convert val: %s, pos: %d: %v", sqlparser.String(row[pos]), pos, err) } plan.Values = append(plan.Values.([]interface{}), val) row[pos] = sqlparser.ValArg([]byte(fmt.Sprintf(":_%s", colVindex.Col))) return nil }
func buildAutoincPlan(ins *sqlparser.Insert, autoinc *vindexes.Autoinc, route *engine.Route) error { route.Generate = &engine.Generate{ Opcode: engine.SelectUnsharded, Keyspace: autoinc.Sequence.Keyspace, Query: fmt.Sprintf("select next value from `%s`", autoinc.Sequence.Name), } // If it's also a colvindex, we have to add a redirect from route.Values. // Otherwise, we have to redirect from row[pos]. if autoinc.ColVindexNum >= 0 { route.Generate.Value = route.Values.([]interface{})[autoinc.ColVindexNum] route.Values.([]interface{})[autoinc.ColVindexNum] = ":" + engine.SeqVarName return nil } row, pos := findOrInsertPos(ins, autoinc.Col) val, err := valConvert(row[pos]) if err != nil { return fmt.Errorf("could not convert val: %s, pos: %d: %v", sqlparser.String(row[pos]), pos, err) } route.Generate.Value = val row[pos] = sqlparser.ValArg([]byte(":" + engine.SeqVarName)) return nil }
package planbuilder import ( "errors" "fmt" log "github.com/golang/glog" "github.com/youtube/vitess/go/vt/schema" "github.com/youtube/vitess/go/vt/sqlparser" "github.com/youtube/vitess/go/vt/tableacl" ) var ( // ErrTooComplex indicates given sql query is too complex. ErrTooComplex = errors.New("Complex") execLimit = &sqlparser.Limit{Rowcount: sqlparser.ValArg(":#maxLimit")} ) // PlanType indicates a query plan type. type PlanType int const ( // PLAN_PASS_SELECT is pass through select statements. This is the // default plan for select statements. PLAN_PASS_SELECT PlanType = iota // PLAN_PASS_DML is pass through update & delete statements. This is // the default plan for update and delete statements. PLAN_PASS_DML // PLAN_PK_EQUAL is deprecated. Use PLAN_PK_IN instead. PLAN_PK_EQUAL // PLAN_PK_IN is select statement with a single IN clause on primary key
// license that can be found in the LICENSE file. package planbuilder import ( "errors" "fmt" log "github.com/golang/glog" "github.com/youtube/vitess/go/vt/schema" "github.com/youtube/vitess/go/vt/sqlparser" ) var ( TooComplex = errors.New("Complex") execLimit = &sqlparser.Limit{Rowcount: sqlparser.ValArg(":_vtMaxResultSize")} ) // ExecPlan is built for selects and DMLs. // PK Values values within ExecPlan can be: // sqltypes.Value: sourced form the query, or // string: bind variable name starting with ':', or // nil if no value was specified type ExecPlan struct { PlanId PlanType Reason ReasonType TableName string // FieldQuery is used to fetch field info FieldQuery *sqlparser.ParsedQuery
// getWhereClause returns a whereClause based on desired upper and lower // bounds for primary key. func (qs *QuerySplitter) getWhereClause(whereClause *sqlparser.Where, bindVars map[string]interface{}, start, end sqltypes.Value) *sqlparser.Where { var startClause *sqlparser.ComparisonExpr var endClause *sqlparser.ComparisonExpr var clauses sqlparser.BoolExpr // No upper or lower bound, just return the where clause of original query if start.IsNull() && end.IsNull() { return whereClause } pk := &sqlparser.ColName{ Name: sqlparser.SQLName(qs.splitColumn), } if !start.IsNull() { startClause = &sqlparser.ComparisonExpr{ Operator: sqlparser.AST_GE, Left: pk, Right: sqlparser.ValArg([]byte(":" + startBindVarName)), } if start.IsNumeric() { v, _ := start.ParseInt64() bindVars[startBindVarName] = v } else if start.IsString() { bindVars[startBindVarName] = start.Raw() } else if start.IsFractional() { v, _ := start.ParseFloat64() bindVars[startBindVarName] = v } } // splitColumn < end if !end.IsNull() { endClause = &sqlparser.ComparisonExpr{ Operator: sqlparser.AST_LT, Left: pk, Right: sqlparser.ValArg([]byte(":" + endBindVarName)), } if end.IsNumeric() { v, _ := end.ParseInt64() bindVars[endBindVarName] = v } else if end.IsString() { bindVars[endBindVarName] = end.Raw() } else if end.IsFractional() { v, _ := end.ParseFloat64() bindVars[endBindVarName] = v } } if startClause == nil { clauses = endClause } else { if endClause == nil { clauses = startClause } else { // splitColumn >= start AND splitColumn < end clauses = &sqlparser.AndExpr{ Left: startClause, Right: endClause, } } } if whereClause != nil { clauses = &sqlparser.AndExpr{ Left: &sqlparser.ParenBoolExpr{Expr: whereClause.Expr}, Right: &sqlparser.ParenBoolExpr{Expr: clauses}, } } return &sqlparser.Where{ Type: sqlparser.AST_WHERE, Expr: clauses, } }