// Ensure that the input query is a Select statement that contains no Join, // GroupBy, OrderBy, Limit or Distinct operations. Also ensure that the // source table is present in the schema and has at least one primary key. func (qs *QuerySplitter) validateQuery() error { statement, err := sqlparser.Parse(qs.query.Sql) if err != nil { return err } var ok bool qs.sel, ok = statement.(*sqlparser.Select) if !ok { return fmt.Errorf("not a select statement") } if qs.sel.Distinct != "" || qs.sel.GroupBy != nil || qs.sel.Having != nil || len(qs.sel.From) != 1 || qs.sel.OrderBy != nil || qs.sel.Limit != nil || qs.sel.Lock != "" { return fmt.Errorf("unsupported query") } node, ok := qs.sel.From[0].(*sqlparser.AliasedTableExpr) if !ok { return fmt.Errorf("unsupported query") } qs.tableName = sqlparser.GetTableName(node.Expr) if qs.tableName == "" { return fmt.Errorf("not a simple table expression") } tableInfo, ok := qs.schemaInfo.tables[qs.tableName] if !ok { return fmt.Errorf("can't find table in schema") } if len(tableInfo.PKColumns) == 0 { return fmt.Errorf("no primary keys") } qs.pkCol = tableInfo.GetPKColumn(0).Name return nil }
func GetStreamExecPlan(sql string, getTable TableGetter) (plan *ExecPlan, err error) { statement, err := sqlparser.Parse(sql) if err != nil { return nil, err } plan = &ExecPlan{ PlanId: PLAN_SELECT_STREAM, FullQuery: GenerateFullQuery(statement), } switch stmt := statement.(type) { case *sqlparser.Select: if stmt.Lock != "" { return nil, errors.New("select with lock disallowed with streaming") } tableName, _ := analyzeFrom(stmt.From) if tableName != "" { plan.setTableInfo(tableName, getTable) } case *sqlparser.Union: // pass default: return nil, fmt.Errorf("'%v' not allowed for streaming", sqlparser.String(stmt)) } return plan, nil }
func BuildPlan(query string, schema *Schema) *Plan { statement, err := sqlparser.Parse(query) if err != nil { return &Plan{ ID: NoPlan, Reason: err.Error(), Original: query, } } noplan := &Plan{ ID: NoPlan, Reason: "too complex", Original: query, } var plan *Plan switch statement := statement.(type) { case *sqlparser.Select: plan = buildSelectPlan(statement, schema) case *sqlparser.Insert: plan = buildInsertPlan(statement, schema) case *sqlparser.Update: plan = buildUpdatePlan(statement, schema) case *sqlparser.Delete: plan = buildDeletePlan(statement, schema) case *sqlparser.Union, *sqlparser.Set, *sqlparser.DDL, *sqlparser.Other: return noplan default: panic("unexpected") } plan.Original = query return plan }
func GetExecPlan(sql string, getTable TableGetter) (plan *ExecPlan, err error) { statement, err := sqlparser.Parse(sql) if err != nil { return nil, err } plan, err = analyzeSQL(statement, getTable) if err != nil { return nil, err } if plan.PlanId == PLAN_PASS_DML { log.Warningf("PASS_DML: %s", sql) } return plan, nil }
func DDLParse(sql string) (plan *DDLPlan) { statement, err := sqlparser.Parse(sql) if err != nil { return &DDLPlan{Action: ""} } stmt, ok := statement.(*sqlparser.DDL) if !ok { return &DDLPlan{Action: ""} } return &DDLPlan{ Action: stmt.Action, TableName: string(stmt.Table), NewName: string(stmt.NewName), } }
func analyze(line []byte) { for _, ignore := range ignores { if bytes.HasPrefix(line, ignore) { return } } dml := string(bytes.TrimRight(line, "\n")) ast, err := sqlparser.Parse(dml) if err != nil { log.Errorf("Error parsing %s", dml) return } bindIndex = 0 buf := sqlparser.NewTrackedBuffer(FormatWithBind) buf.Myprintf("%v", ast) addQuery(buf.ParsedQuery().Query) }
func (rci *RowcacheInvalidator) handleUnrecognizedEvent(sql string) { statement, err := sqlparser.Parse(sql) if err != nil { log.Errorf("Error: %v: %s", err, sql) internalErrors.Add("Invalidation", 1) return } var table *sqlparser.TableName switch stmt := statement.(type) { case *sqlparser.Insert: // Inserts don't affect rowcache. return case *sqlparser.Update: table = stmt.Table case *sqlparser.Delete: table = stmt.Table default: log.Errorf("Unrecognized: %s", sql) internalErrors.Add("Invalidation", 1) return } // Ignore cross-db statements. if table.Qualifier != nil && string(table.Qualifier) != rci.qe.dbconfigs.App.DbName { return } // Ignore if it's an uncached table. tableName := string(table.Name) tableInfo := rci.qe.schemaInfo.GetTable(tableName) if tableInfo == nil { log.Errorf("Table %s not found: %s", tableName, sql) internalErrors.Add("Invalidation", 1) return } if tableInfo.CacheType == schema.CACHE_NONE { return } // Treat the statement as a DDL. // It will conservatively invalidate all rows of the table. log.Warningf("Treating '%s' as DDL for table %s", sql, tableName) rci.qe.schemaInfo.CreateOrUpdateTable(tableName) }
func TestGetWhereClause(t *testing.T) { splitter := &QuerySplitter{} sql := "select * from test_table where count > :count" statement, _ := sqlparser.Parse(sql) splitter.sel, _ = statement.(*sqlparser.Select) splitter.pkCol = "id" // no boundary case, start = end = nil, should not change the where clause nilValue := sqltypes.Value{} clause := splitter.getWhereClause(nilValue, nilValue) want := " where count > :count" got := sqlparser.String(clause) if !reflect.DeepEqual(got, want) { t.Errorf("incorrect where clause for nil ranges, got:%v, want:%v", got, want) } // Set lower bound, should add the lower bound condition to where clause start, _ := sqltypes.BuildValue(20) clause = splitter.getWhereClause(start, nilValue) want = " where count > :count and id >= 20" got = sqlparser.String(clause) if !reflect.DeepEqual(got, want) { t.Errorf("incorrect where clause, got:%v, want:%v", got, want) } // Set upper bound, should add the upper bound condition to where clause end, _ := sqltypes.BuildValue(40) clause = splitter.getWhereClause(nilValue, end) want = " where count > :count and id < 40" got = sqlparser.String(clause) if !reflect.DeepEqual(got, want) { t.Errorf("incorrect where clause, got:%v, want:%v", got, want) } // Set both bounds, should add two conditions to where clause clause = splitter.getWhereClause(start, end) want = " where count > :count and id >= 20 and id < 40" got = sqlparser.String(clause) if !reflect.DeepEqual(got, want) { t.Errorf("incorrect where clause, got:%v, want:%v", got, want) } // Original query with no where clause sql = "select * from test_table" statement, _ = sqlparser.Parse(sql) splitter.sel, _ = statement.(*sqlparser.Select) // no boundary case, start = end = nil should return no where clause clause = splitter.getWhereClause(nilValue, nilValue) want = "" got = sqlparser.String(clause) if !reflect.DeepEqual(got, want) { t.Errorf("incorrect where clause for nil ranges, got:%v, want:%v", got, want) } // Set both bounds, should add two conditions to where clause clause = splitter.getWhereClause(start, end) want = " where id >= 20 and id < 40" got = sqlparser.String(clause) if !reflect.DeepEqual(got, want) { t.Errorf("incorrect where clause, got:%v, want:%v", got, want) } }