From e6bf91ea7d1e9184d552571812b77d813f4d8155 Mon Sep 17 00:00:00 2001 From: Aaron Raddon Date: Sat, 18 Jun 2016 14:21:24 -0700 Subject: [PATCH 1/2] Info schema enhancments --- datasource/schemadb.go | 82 ++++++++++++++++++++++++++++++++++++++---- exec/executor.go | 2 +- exec/projection.go | 2 +- lex/dialect_sql.go | 42 +++++++++++++++++++--- plan/projection.go | 4 ++- plan/sql_rewrite.go | 55 ++++++++++++++++++++++++++-- rel/parse_sql.go | 44 +++++++++++++++++++++-- rel/parse_sql_test.go | 10 +++++- rel/sql.go | 4 +-- schema/schema.go | 3 +- 10 files changed, 226 insertions(+), 22 deletions(-) diff --git a/datasource/schemadb.go b/datasource/schemadb.go index 801298f8..5f960192 100644 --- a/datasource/schemadb.go +++ b/datasource/schemadb.go @@ -31,9 +31,10 @@ var ( _ schema.ConnScanner = (*SchemaSource)(nil) // normal tables - defaultSchemaTables = []string{"tables", "databases", "columns", "global_variables", "session_variables"} - DialectWriterCols = []string{"mysql"} - DialectWriters = []schema.DialectWriter{&mysqlWriter{}} + defaultSchemaTables = []string{"tables", "databases", "columns", "global_variables", "session_variables", + "functions", "procedures", "engines", "status", "indexes"} + DialectWriterCols = []string{"mysql"} + DialectWriters = []schema.DialectWriter{&mysqlWriter{}} ) type ( @@ -68,7 +69,7 @@ func (m *SchemaDb) Close() error { return nil } func (m *SchemaDb) Tables() []string { return m.tbls } func (m *SchemaDb) Table(table string) (*schema.Table, error) { - //u.Debugf("Table(%q)", table) + u.Debugf("Table(%q)", table) switch table { case "tables": return m.tableForTables() @@ -76,7 +77,14 @@ func (m *SchemaDb) Table(table string) (*schema.Table, error) { return m.tableForDatabases() case "session_variables", "global_variables": return m.tableForVariables(table) + case "procedures", "functions": + return m.tableForProcedures(table) + case "engines": + return m.tableForEngines() + case "indexes": + default: + u.Debugf("Table(%q)", table) return m.tableForTable(table) } return nil, schema.ErrNotFound @@ -85,14 +93,15 @@ func (m *SchemaDb) Table(table string) (*schema.Table, error) { // Create a SchemaSource specific to schema object (table, database) func (m *SchemaDb) Open(schemaObjectName string) (schema.Conn, error) { - //u.Debugf("SchemaDb.Open(%q)", schemaObjectName) - //u.WarnT(8) + u.Debugf("SchemaDb.Open(%q)", schemaObjectName) tbl, err := m.Table(schemaObjectName) if err == nil && tbl != nil { switch schemaObjectName { case "session_variables", "global_variables": return &SchemaSource{db: m, tbl: tbl, session: true}, nil + case "engines", "procedures", "functions": + return &SchemaSource{db: m, tbl: tbl, rows: nil}, nil default: return &SchemaSource{db: m, tbl: tbl, rows: tbl.AsRows()}, nil } @@ -184,6 +193,67 @@ func (m *SchemaDb) tableForTable(table string) (*schema.Table, error) { return t, nil } +func (m *SchemaDb) tableForProcedures(table string) (*schema.Table, error) { + + //table := "procedures" // procedures, functions + + ss := m.is.SchemaSources["schema"] + tbl, hasTable := m.tableMap[table] + + if hasTable { + u.Infof("found existing table %q", table) + return tbl, nil + } + + u.Debugf("s:%p infoschema:%p creating schema table for %q", m.s, m.is, table) + + // SELECT Db, Name, Type, Definer, Modified, Created, Security_type, Comment, + // character_set_client, `collation_connection`, `Database Collation` from `context`.`procedures`;") + + t := schema.NewTable(table, ss) + t.AddField(schema.NewFieldBase("Db", value.StringType, 64, "string")) + t.AddField(schema.NewFieldBase("Name", value.StringType, 64, "string")) + t.AddField(schema.NewFieldBase("Type", value.StringType, 64, "string")) + t.AddField(schema.NewFieldBase("Definer", value.StringType, 64, "string")) + t.AddField(schema.NewFieldBase("Modified", value.TimeType, 8, "datetime")) + t.AddField(schema.NewFieldBase("Created", value.TimeType, 8, "datetime")) + t.AddField(schema.NewFieldBase("Security_type", value.StringType, 64, "string")) + t.AddField(schema.NewFieldBase("Comment", value.StringType, 64, "string")) + t.AddField(schema.NewFieldBase("character_set_client", value.StringType, 64, "string")) + t.AddField(schema.NewFieldBase("collation_connection", value.StringType, 64, "string")) + t.AddField(schema.NewFieldBase("Database Collation", value.StringType, 64, "string")) + t.SetColumns(schema.ProdedureFullCols) + ss.AddTable(t) + m.tableMap[table] = t + return t, nil +} + +func (m *SchemaDb) tableForEngines() (*schema.Table, error) { + + table := "engines" + + ss := m.is.SchemaSources["schema"] + tbl, hasTable := m.tableMap[table] + //u.Debugf("s:%p infoschema:%p creating schema table for %q", m.s, m.is, table) + if hasTable { + //u.Infof("found existing table %q", table) + return tbl, nil + } + // Engine, Support, Comment, Transactions, XA, Savepoints + + t := schema.NewTable(table, ss) + t.AddField(schema.NewFieldBase("Engine", value.StringType, 64, "string")) + t.AddField(schema.NewFieldBase("Support", value.StringType, 64, "string")) + t.AddField(schema.NewFieldBase("Comment", value.StringType, 255, "string")) + t.AddField(schema.NewFieldBase("Transactions", value.BoolType, 1, "tinyint")) + t.AddField(schema.NewFieldBase("XA", value.StringType, 64, "string")) + t.AddField(schema.NewFieldBase("Savepoints", value.BoolType, 1, "tinyint")) + t.SetColumns(schema.EngineFullCols) + ss.AddTable(t) + m.tableMap[table] = t + return t, nil +} + func (m *SchemaDb) tableForVariables(table string) (*schema.Table, error) { // This table doesn't belong in schema ss := m.is.SchemaSources["schema"] diff --git a/exec/executor.go b/exec/executor.go index 262f81cc..dd66f025 100644 --- a/exec/executor.go +++ b/exec/executor.go @@ -94,7 +94,7 @@ func BuildSqlJobPlanned(planner plan.Planner, executor Executor, ctx *plan.Conte //u.Debugf("finished exec task plan: %#v", execRoot) if err != nil { - u.Errorf("error on plan? %v", err) + //u.Errorf("error on plan? %v", err) return nil, err } if execRoot == nil { diff --git a/exec/projection.go b/exec/projection.go index c1f80e66..74e4ae0c 100644 --- a/exec/projection.go +++ b/exec/projection.go @@ -203,7 +203,7 @@ func (m *Projection) projectionEvaluator(isFinal bool) MessageHandler { } else { v, ok := vm.Eval(rdr, col.Expr) if !ok { - u.Warnf("failed eval key=%v val=%#v expr:%s mt:%#v", col.Key(), v, col.Expr, mt) + u.Warnf("failed eval key=%q val=%#v expr:%q mt:%#v", col.Key(), v, col.Expr, mt) // for k, v := range ctx.Session.Row() { // u.Infof("%p session? %s: %v", ctx.Session, k, v.Value()) // } diff --git a/lex/dialect_sql.go b/lex/dialect_sql.go index d8449a49..474d2e63 100644 --- a/lex/dialect_sql.go +++ b/lex/dialect_sql.go @@ -16,7 +16,7 @@ var SqlSelect = []*Clause{ {Token: TokenGroupBy, Lexer: LexColumns, Optional: true, Name: "sqlSelect.groupby"}, {Token: TokenHaving, Lexer: LexConditionalClause, Optional: true, Name: "sqlSelect.having"}, {Token: TokenOrderBy, Lexer: LexOrderByColumn, Optional: true, Name: "sqlSelect.orderby"}, - {Token: TokenLimit, Lexer: LexNumber, Optional: true}, + {Token: TokenLimit, Lexer: LexLimit, Optional: true}, {Token: TokenOffset, Lexer: LexNumber, Optional: true}, {Token: TokenWith, Lexer: LexJsonOrKeyValue, Optional: true}, {Token: TokenAlias, Lexer: LexIdentifier, Optional: true}, @@ -48,7 +48,8 @@ var fromSource = []*Clause{ {Token: TokenHaving, Lexer: LexConditionalClause, Optional: true}, {Token: TokenGroupBy, Lexer: LexColumns, Optional: true}, {Token: TokenOrderBy, Lexer: LexOrderByColumn, Optional: true}, - {Token: TokenLimit, Lexer: LexNumber, Optional: true}, + {Token: TokenLimit, Lexer: LexLimit, Optional: true}, + {Token: TokenOffset, Lexer: LexNumber, Optional: true}, {Token: TokenAs, Lexer: LexIdentifier, Optional: true}, {Token: TokenOn, Lexer: LexConditionalClause, Optional: true}, } @@ -61,7 +62,8 @@ var moreSources = []*Clause{ {Token: TokenHaving, Lexer: LexConditionalClause, Optional: true, Name: "moreSources.Having"}, {Token: TokenGroupBy, Lexer: LexColumns, Optional: true, Name: "moreSources.GroupBy"}, {Token: TokenOrderBy, Lexer: LexOrderByColumn, Optional: true, Name: "moreSources.OrderBy"}, - {Token: TokenLimit, Lexer: LexNumber, Optional: true, Name: "moreSources.Limit"}, + {Token: TokenLimit, Lexer: LexLimit, Optional: true, Name: "moreSources.Limit"}, + {Token: TokenOffset, Lexer: LexNumber, Optional: true, Name: "moreSources.Offset"}, {Token: TokenAs, Lexer: LexIdentifier, Optional: true, Name: "moreSources.As"}, {Token: TokenOn, Lexer: LexConditionalClause, Optional: true, Name: "moreSources.On"}, } @@ -264,7 +266,9 @@ func LexShowClause(l *Lexer) StateFn { l.ConsumeWord(keyWord) l.Emit(TokenTables) return LexShowClause - case "columns", "global", "session", "variables": + case "columns", "global", "session", "variables", "status", + "engine", "engines", "procedure", "indexes", "index", "keys", + "function", "functions": // TODO: these should not be identities but tokens? l.ConsumeWord(keyWord) l.Emit(TokenIdentity) @@ -291,3 +295,33 @@ func LexShowClause(l *Lexer) StateFn { } return LexIdentifier } + +// LexLimit clause +// LIMIT 1000 OFFSET 100 +// LIMIT 0, 1000 +// LIMIT 1000 +func LexLimit(l *Lexer) StateFn { + + l.SkipWhiteSpaces() + keyWord := strings.ToLower(l.PeekWord()) + //u.Debugf("LexLimit r= '%v'", string(keyWord)) + + switch keyWord { + case "limit": + l.ConsumeWord(keyWord) + l.Emit(TokenLimit) + return LexLimit + case "offset": + return nil + case "", ";": + return nil + case ",": + l.ConsumeWord(keyWord) + l.Emit(TokenComma) + return LexNumber + default: + l.Push("LexLimit", LexLimit) + return LexNumber + } + return nil +} diff --git a/plan/projection.go b/plan/projection.go index 7e20eb0e..5ed92dcd 100644 --- a/plan/projection.go +++ b/plan/projection.go @@ -153,6 +153,8 @@ func projectionForSourcePlan(plan *Source) error { if col.InFinalProjection() { //u.Infof("col add %v for %s", schemaCol.Type.String(), col) plan.Proj.AddColumn(col, schemaCol.Type) + } else { + //u.Infof("not in final? %#v", col) } } else { plan.Proj.AddColumn(col, schemaCol.Type) @@ -173,7 +175,7 @@ func projectionForSourcePlan(plan *Source) error { //u.Warnf("count(*) as=%v", col.As) plan.Proj.AddColumn(col, value.IntType) } else { - //u.Errorf("schema col not found: vals=%#v", col) + //u.Errorf("schema col not found: SourceField=%q vals=%#v", col.SourceField, col) } } diff --git a/plan/sql_rewrite.go b/plan/sql_rewrite.go index 0bb8475a..7814bed2 100644 --- a/plan/sql_rewrite.go +++ b/plan/sql_rewrite.go @@ -40,7 +40,7 @@ func RewriteShowAsSelect(stmt *rel.SqlShow, ctx *Context) (*rel.SqlSelect, error } showType := strings.ToLower(stmt.ShowType) - //u.Debugf("showType=%q create=%q from=%q rewrite: %s", showType, stmt.CreateWhat, stmt.From, raw) + u.Debugf("showType=%q create=%q from=%q rewrite: %s", showType, stmt.CreateWhat, stmt.From, raw) sqlStatement := "" from := "tables" if stmt.Db != "" { @@ -108,7 +108,7 @@ func RewriteShowAsSelect(stmt *rel.SqlShow, ctx *Context) (*rel.SqlSelect, error | user | 0 | PRIMARY | 2 | User | A | 7 | NULL | NULL | | BTREE | | | +-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ */ - sqlStatement = fmt.Sprintf("select Table, Non_unique, Key_name, Seq_in_index, Column_name, Collation, Cardinality, Sub_part, Packed, `Null`, Index_type, Index_comment from `schema`.`%s`;", stmt.Identity) + sqlStatement = fmt.Sprintf("select Table, Non_unique, Key_name, Seq_in_index, Column_name, Collation, Cardinality, Sub_part, Packed, `Null`, Index_type, Index_comment from `schema`.`indexes`;") case "variables": // SHOW [GLOBAL | SESSION] VARIABLES [like_or_where] @@ -128,8 +128,57 @@ func RewriteShowAsSelect(stmt *rel.SqlShow, ctx *Context) (*rel.SqlSelect, error +---------------+----------+ */ + case "status": + // Status is a subset of just some variables + // http://dev.mysql.com/doc/refman/5.7/en/server-status-variables.html + + // SHOW [GLOBAL | SESSION | SLAVE ] STATUS [like_or_where] + scope := stmt.Scope + switch scope { + case "session", "": + scope = "session" + } + sqlStatement = fmt.Sprintf("select Variable_name, Value from `context`.`%s_variables`;", scope) + /* + mysql> show global status; + +--------------------------------+-----------------+ + | Variable_name | Value + +--------------------------------+------------------ + | Aborted_clients | 0 + | Aborted_connects | 0 + | Binlog_snapshot_file | + | Binlog_snapshot_position | 0 + */ + case "engines": + sqlStatement = fmt.Sprintf("select Engine, Support, Comment, Transactions, XA, Savepoints from `context`.`engines`;") + /* + show engines; + mysql> show engines; + +--------------------+---------+----------------------------------------------------------------------------+--------------+------+------------+ + | Engine | Support | Comment | Transactions | XA | Savepoints | + +--------------------+---------+----------------------------------------------------------------------------+--------------+------+------------+ + | InnoDB | DEFAULT | Percona-XtraDB, Supports transactions, row-level locking, and foreign keys | YES | YES | YES | + | CSV | YES | CSV storage engine | NO | NO | NO | + | MyISAM | YES | MyISAM storage engine | NO | NO | NO | + | BLACKHOLE | YES | /dev/null storage engine (anything you write to it disappears) | NO | NO | NO | + | PERFORMANCE_SCHEMA | YES | Performance Schema | NO | NO | NO | + | MEMORY | YES | Hash based, stored in memory, useful for temporary tables | NO | NO | NO | + | ARCHIVE | YES | Archive storage engine | NO | NO | NO | + | MRG_MYISAM | YES | Collection of identical MyISAM tables | NO | NO | NO | + | FEDERATED | NO | Federated MySQL storage engine | NULL | NULL | NULL | + +--------------------+---------+----------------------------------------------------------------------------+--------------+------+------------+ + */ + case "procedure", "function": + /* + show procuedure status; + show function status; + + | Db | Name | Type | Definer | Modified | Created | Security_type | Comment| character_set_client | collation_connection | Database Collation | + */ + sqlStatement = fmt.Sprintf("SELECT Db, Name, Type, Definer, Modified, Created, Security_type, Comment, character_set_client, `collation_connection`, `Database Collation` from `context`.`%ss`;", showType) + default: - u.Warnf("unhandled %s", raw) + u.Warnf("unhandled sql rewrite statement %s", raw) return nil, fmt.Errorf("Unrecognized: %s", raw) } sel, err := rel.ParseSqlSelectResolver(sqlStatement, ctx.Funcs) diff --git a/rel/parse_sql.go b/rel/parse_sql.go index e1b64e8a..f1c1c840 100644 --- a/rel/parse_sql.go +++ b/rel/parse_sql.go @@ -522,6 +522,7 @@ func (m *Sqlbridge) parseShow() (*SqlShow, error) { SHOW [FULL] TABLES [FROM db_name] [like_or_where] SHOW TRIGGERS [FROM db_name] [like_or_where] SHOW [GLOBAL | SESSION] VARIABLES [like_or_where] + SHOW [GLOBAL | SESSION | SLAVE] STATUS [like_or_where] SHOW WARNINGS [LIMIT [offset,] row_count] */ likeLhs := "Table" @@ -534,7 +535,7 @@ func (m *Sqlbridge) parseShow() (*SqlShow, error) { case "full": req.Full = true m.Next() - case "global", "session": + case "global", "session", "slave": req.Scope = strings.ToLower(m.Next().V) //u.Infof("scope:%q next:%v", req.Scope, m.Cur()) case "create": @@ -558,10 +559,29 @@ func (m *Sqlbridge) parseShow() (*SqlShow, error) { case "databases": req.ShowType = "databases" m.Next() + case "indexes": + req.ShowType = "indexes" + m.Next() case "variables": req.ShowType = "variables" likeLhs = "Variable_name" m.Next() + case "status": + req.ShowType = "status" + likeLhs = "Variable_name" + m.Next() + case "engine": + req.ShowType = "status" + likeLhs = "Engine" + m.Next() + case "engines": + req.ShowType = "status" + likeLhs = "Engine" + m.Next() + case "procedure", "function": + req.ShowType = objectType + likeLhs = "Name" + m.Next() case "columns": m.Next() // consume columns likeLhs = "Field" @@ -622,6 +642,13 @@ func (m *Sqlbridge) parseCommand() (*SqlCommand, error) { */ req := &SqlCommand{Columns: make(CommandColumns, 0)} req.kw = m.Next().T // USE, SET + + // USE `baseball`; + if req.kw == lex.TokenUse { + req.Identity = m.Next().V + return req, nil + } + cur := m.Cur() peek := m.Peek() // Look for special cases for mysql weird SET syntax @@ -1514,7 +1541,20 @@ func (m *Sqlbridge) parseLimit(req *SqlSelect) error { return fmt.Errorf("Could not convert limit to integer %v", m.Cur().V) } req.Limit = int(iv) - if m.Cur().T == lex.TokenOffset { + switch m.Cur().T { + case lex.TokenComma: + // LIMIT 0, 1000 + m.Next() // consume the comma + if m.Cur().T != lex.TokenInteger { + return fmt.Errorf("Limit 0, 1000 2nd number must be an integer %v %v", m.Cur().T, m.Cur().V) + } + iv, err = strconv.Atoi(m.Next().V) + if err != nil { + return fmt.Errorf("Could not convert limit to integer %v", m.Cur().V) + } + req.Offset = req.Limit + req.Limit = iv + case lex.TokenOffset: m.Next() // consume "OFFSET" if m.Cur().T != lex.TokenInteger { return fmt.Errorf("Offset must be an integer %v %v", m.Cur().T, m.Cur().V) diff --git a/rel/parse_sql_test.go b/rel/parse_sql_test.go index 9ea991e8..fa9d3291 100644 --- a/rel/parse_sql_test.go +++ b/rel/parse_sql_test.go @@ -42,6 +42,7 @@ func TestSqlShowLexOnly(t *testing.T) { t.Parallel() parseSqlTest(t, "SHOW FULL TABLES FROM `temp_schema` LIKE '%'") parseSqlTest(t, "SHOW CREATE TABLE `temp_schema`.`users`") + parseSqlTest(t, `show session status like "ssl_cipher"`) } func TestSqlLexOnly(t *testing.T) { @@ -216,6 +217,13 @@ func TestSqlParseAstCheck(t *testing.T) { assert.Tf(t, sel.OrderBy[0].Order == "ASC", "%v", sel.OrderBy[0].String()) assert.Tf(t, sel.OrderBy[1].Order == "DESC", "%v", sel.OrderBy[1].String()) + sql = "select name from `github_public` limit 0, 100;" + req, err = ParseSql(sql) + assert.Tf(t, err == nil && req != nil, "Must parse: %s \n\t%v", sql, err) + sel = req.(*SqlSelect) + assert.Tf(t, sel.Limit == 100, "want limit = 100 but have %v", sel.Limit) + assert.Tf(t, sel.Offset == 0, "want offset = 0 but have %v", sel.Offset) + sql = "select `actor.id`, `actor.login` from github_watch where `actor.id` < 1000" req, err = ParseSql(sql) assert.Tf(t, err == nil && req != nil, "Must parse: %s \n\t%v", sql, err) @@ -423,7 +431,7 @@ func TestSqlCommands(t *testing.T) { cmd, ok = req.(*SqlCommand) assert.Tf(t, ok, "is SqlCommand: %T", req) assert.Tf(t, cmd.Keyword() == lex.TokenUse, "has USE kw: %#v", cmd) - assert.Tf(t, len(cmd.Columns) == 1 && cmd.Columns[0].Name == "myschema", "has myschema: %#v", cmd.Columns[0]) + assert.Tf(t, cmd.Identity == "myschema", "has myschema: %#v", cmd.Identity) } func TestSqlAlias(t *testing.T) { diff --git a/rel/sql.go b/rel/sql.go index 194cbf10..685f95b8 100644 --- a/rel/sql.go +++ b/rel/sql.go @@ -204,9 +204,9 @@ type ( SqlInto struct { Table string } - // Sql Command is admin command such as "SET" + // Sql Command is admin command such as "SET", "USE" SqlCommand struct { - kw lex.TokenType // SET + kw lex.TokenType // SET or USE Columns CommandColumns // can have multiple columns in command Identity string // Value expr.Node // diff --git a/schema/schema.go b/schema/schema.go index ebc0ec67..f145a6df 100644 --- a/schema/schema.go +++ b/schema/schema.go @@ -23,7 +23,8 @@ var ( SchemaRefreshInterval = -time.Minute * 5 // Static list of common field names for describe header on Show, Describe - + EngineFullCols = []string{"Engine", "Support", "Comment", "Transactions", "XA", "Savepoints"} + ProdedureFullCols = []string{"Db", "Name", "Type", "Definer", "Modified", "Created", "Security_type", "Comment", "character_set_client ", "collation_connection", "Database Collation"} DescribeFullCols = []string{"Field", "Type", "Collation", "Null", "Key", "Default", "Extra", "Privileges", "Comment"} DescribeFullColMap = map[string]int{"Field": 0, "Type": 1, "Collation": 2, "Null": 3, "Key": 4, "Default": 5, "Extra": 6, "Privileges": 7, "Comment": 8} DescribeCols = []string{"Field", "Type", "Null", "Key", "Default", "Extra"} From 52ea03ccd96343528b15e65d6813f7711982149d Mon Sep 17 00:00:00 2001 From: Aaron Raddon Date: Sat, 18 Jun 2016 15:18:37 -0700 Subject: [PATCH 2/2] update to latest dependencies --- GLOCKFILE | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/GLOCKFILE b/GLOCKFILE index 2a3bb900..2d53469e 100644 --- a/GLOCKFILE +++ b/GLOCKFILE @@ -1,21 +1,21 @@ -github.com/araddon/dateparse 2f41da3eb28d713ca2f45682fae66173fad5e85b -github.com/araddon/gou c4d51044125da629d6f2aa594f25b45c451a7d2a -github.com/bmizerany/assert e17e99893cb6509f428e1728281c2ad60a6b31e3 +github.com/araddon/dateparse a19b713c2e31cec89903deb95b4d053e9e7b4db5 +github.com/araddon/gou 50a94aa4a3fb69e8fbde05df290fcb49fa685e07 +github.com/bmizerany/assert b7ed37b82869576c289d7d97fb2bbd8b64a0cb28 github.com/dataux/dataux 06be63898155e3a23d5794244545e63428943015 github.com/dchest/siphash 6d8617816bb5d8268011ffbfb8720f17ce9af63c -github.com/go-sql-driver/mysql 7ebe0a500653eeb1859664bed5e48dec1e164e73 -github.com/gogo/protobuf 4f262e4b0f3a6cea646e15798109335551e21756 -github.com/golang/protobuf f0a097ddac24fb00e07d2ac17f8671423f3ea47c -github.com/google/btree f06e229e679911bb31a04e07ac891115822e37c3 -github.com/hashicorp/go-immutable-radix 8e8ed81f8f0bf1bdd829593fdd5c29922c1ea990 +github.com/go-sql-driver/mysql 3654d25ec346ee8ce71a68431025458d52a38ac0 +github.com/gogo/protobuf 2752d97bbd91927dd1c43296dbf8700e50e2708c +github.com/golang/protobuf 0c1f6d65b5a189c2250d10e71a5506f06f9fa0a0 +github.com/google/btree 7d79101e329e5a3adf994758c578dab82b90c017 +github.com/hashicorp/go-immutable-radix afc5a0dbb18abdf82c277a7bc01533e81fa1d6b8 github.com/hashicorp/go-memdb 98f52f52d7a476958fa9da671354d270c50661a7 github.com/hashicorp/golang-lru a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4 github.com/kr/pretty add1dbc86daf0f983cd4a48ceb39deb95c729b67 -github.com/kr/text bb797dc4fb8320488f47bf11de07a733d7233e1f +github.com/kr/text 7cafcd837844e784b526369c9bce262804aebc60 github.com/leekchan/timeutil 28917288c48df3d2c1cfe468c273e0b2adda0aa5 github.com/lytics/datemath 988020f3ad34814005ab10b6c7863e31672b5f63 github.com/mb0/glob 1eb79d2de6c448664e7272f8b9fe1938239e3aaa github.com/pborman/uuid c55201b036063326c5b1b89ccfe45a184973d073 github.com/surge/sqlparser 6b860f881ddbb9373d7173bdfa1f052ec3e6b215 github.com/zhenjl/sqlparser 6b860f881ddbb9373d7173bdfa1f052ec3e6b215 -golang.org/x/net fb93926129b8ec0056f2f458b1f519654814edf0 +golang.org/x/net 1961d9def2b2d7a28d7958926d2457d05a178ecd