github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/interpreter/main.go (about) 1 // Copyright 2015 PingCAP, Inc. 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 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package main 15 16 import ( 17 "database/sql" 18 "flag" 19 "fmt" 20 "io" 21 "os" 22 "runtime" 23 "strings" 24 "time" 25 26 "github.com/insionng/yougam/libraries/juju/errors" 27 "github.com/insionng/yougam/libraries/ngaut/log" 28 "github.com/insionng/yougam/libraries/peterh/liner" 29 "github.com/insionng/yougam/libraries/pingcap/tidb" 30 "github.com/insionng/yougam/libraries/pingcap/tidb/terror" 31 "github.com/insionng/yougam/libraries/pingcap/tidb/util/printer" 32 ) 33 34 var ( 35 logLevel = flag.String("L", "error", "log level") 36 store = flag.String("store", "goleveldb", "the name for the registered storage, e.g. hbase, memory, goleveldb, boltdb") 37 dbPath = flag.String("dbpath", "test", "db path") 38 dbName = flag.String("dbname", "test", "default db name") 39 lease = flag.Int("lease", 1, "schema lease seconds, very dangerous to change only if you know what you do") 40 41 line *liner.State 42 historyPath = "/tmp/tidb_interpreter" 43 ) 44 45 func openHistory() { 46 if f, err := os.Open(historyPath); err == nil { 47 line.ReadHistory(f) 48 f.Close() 49 } 50 } 51 52 func saveHistory() { 53 if f, err := os.Create(historyPath); err == nil { 54 line.WriteHistory(f) 55 f.Close() 56 } 57 } 58 59 func executeLine(tx *sql.Tx, txnLine string) error { 60 start := time.Now() 61 if tidb.IsQuery(txnLine) { 62 rows, err := tx.Query(txnLine) 63 elapsed := time.Since(start).Seconds() 64 if err != nil { 65 return errors.Trace(err) 66 } 67 defer rows.Close() 68 cols, err := rows.Columns() 69 if err != nil { 70 return errors.Trace(err) 71 } 72 73 values := make([][]byte, len(cols)) 74 scanArgs := make([]interface{}, len(values)) 75 for i := range values { 76 scanArgs[i] = &values[i] 77 } 78 79 var datas [][]string 80 for rows.Next() { 81 err := rows.Scan(scanArgs...) 82 if err != nil { 83 return errors.Trace(err) 84 } 85 86 data := make([]string, len(cols)) 87 for i, value := range values { 88 if value == nil { 89 data[i] = "NULL" 90 } else { 91 data[i] = string(value) 92 } 93 } 94 95 datas = append(datas, data) 96 } 97 98 // For `cols` and `datas[i]` always has the same length, 99 // no need to check return validity. 100 result, _ := printer.GetPrintResult(cols, datas) 101 fmt.Printf("%s", result) 102 103 switch len(datas) { 104 case 0: 105 fmt.Printf("Empty set") 106 case 1: 107 fmt.Printf("1 row in set") 108 default: 109 fmt.Printf("%v rows in set", len(datas)) 110 } 111 fmt.Printf(" (%.2f sec)\n", elapsed) 112 if err := rows.Err(); err != nil { 113 return errors.Trace(err) 114 } 115 } else { 116 // TODO: last insert id 117 res, err := tx.Exec(txnLine) 118 elapsed := time.Since(start).Seconds() 119 if err != nil { 120 return errors.Trace(err) 121 } 122 cnt, err := res.RowsAffected() 123 if err != nil { 124 return errors.Trace(err) 125 } 126 switch cnt { 127 case 0, 1: 128 fmt.Printf("Query OK, %d row affected", cnt) 129 default: 130 fmt.Printf("Query OK, %d rows affected", cnt) 131 } 132 fmt.Printf(" (%.2f sec)\n", elapsed) 133 } 134 return nil 135 } 136 137 func mayExit(err error, l string) bool { 138 if terror.ErrorEqual(err, liner.ErrPromptAborted) || terror.ErrorEqual(err, io.EOF) { 139 fmt.Println("\nBye") 140 saveHistory() 141 return true 142 } 143 if err != nil { 144 log.Fatal(errors.ErrorStack(err)) 145 } 146 return false 147 } 148 149 func readStatement(prompt string) (string, error) { 150 var ret string 151 for { 152 l, err := line.Prompt(prompt) 153 if err != nil { 154 return "", err 155 } 156 if strings.HasSuffix(l, ";") == false { 157 ret += l + "\n" 158 prompt = " -> " 159 continue 160 } 161 return ret + l, nil 162 } 163 } 164 165 func main() { 166 printer.PrintTiDBInfo() 167 168 flag.Parse() 169 log.SetLevelByString(*logLevel) 170 // support for signal notify 171 runtime.GOMAXPROCS(runtime.NumCPU()) 172 173 line = liner.NewLiner() 174 defer line.Close() 175 176 line.SetCtrlCAborts(true) 177 openHistory() 178 179 tidb.SetSchemaLease(time.Duration(*lease) * time.Second) 180 181 // use test as default DB. 182 mdb, err := sql.Open(tidb.DriverName, *store+"://"+*dbPath+"/"+*dbName) 183 if err != nil { 184 log.Fatal(errors.ErrorStack(err)) 185 } 186 187 for { 188 l, err := readStatement("tidb> ") 189 if mayExit(err, l) { 190 return 191 } 192 line.AppendHistory(l) 193 194 // if we're in transaction 195 if strings.HasPrefix(l, "BEGIN") || strings.HasPrefix(l, "begin") { 196 tx, err := mdb.Begin() 197 if err != nil { 198 log.Error(errors.ErrorStack(err)) 199 continue 200 } 201 for { 202 txnLine, err := readStatement(">> ") 203 if mayExit(err, txnLine) { 204 return 205 } 206 line.AppendHistory(txnLine) 207 208 if !strings.HasSuffix(txnLine, ";") { 209 txnLine += ";" 210 } 211 212 if strings.HasPrefix(txnLine, "COMMIT") || strings.HasPrefix(txnLine, "commit") { 213 err = tx.Commit() 214 if err != nil { 215 log.Error(errors.ErrorStack(err)) 216 tx.Rollback() 217 } 218 break 219 } 220 // normal sql statement 221 err = executeLine(tx, txnLine) 222 if err != nil { 223 log.Error(errors.ErrorStack(err)) 224 tx.Rollback() 225 break 226 } 227 } 228 } else { 229 tx, err := mdb.Begin() 230 if err != nil { 231 log.Error(errors.ErrorStack(err)) 232 continue 233 } 234 err = executeLine(tx, l) 235 if err != nil { 236 log.Error(errors.ErrorStack(err)) 237 tx.Rollback() 238 continue 239 } 240 err = tx.Commit() 241 if err != nil { 242 log.Error(errors.ErrorStack(err)) 243 } 244 } 245 } 246 }