github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/bootstrap.go (about) 1 // Copyright 2013 The ql Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSES/QL-LICENSE file. 4 5 // Copyright 2015 PingCAP, Inc. 6 // 7 // Licensed under the Apache License, Version 2.0 (the "License"); 8 // you may not use this file except in compliance with the License. 9 // You may obtain a copy of the License at 10 // 11 // http://www.apache.org/licenses/LICENSE-2.0 12 // 13 // Unless required by applicable law or agreed to in writing, software 14 // distributed under the License is distributed on an "AS IS" BASIS, 15 // See the License for the specific language governing permissions and 16 // limitations under the License. 17 18 package tidb 19 20 import ( 21 "fmt" 22 "runtime/debug" 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/pingcap/tidb/infoschema" 29 "github.com/insionng/yougam/libraries/pingcap/tidb/mysql" 30 "github.com/insionng/yougam/libraries/pingcap/tidb/sessionctx/variable" 31 ) 32 33 const ( 34 // CreateUserTable is the SQL statement creates User table in system db. 35 CreateUserTable = `CREATE TABLE if not exists mysql.user ( 36 Host CHAR(64), 37 User CHAR(16), 38 Password CHAR(41), 39 Select_priv ENUM('N','Y') NOT NULL DEFAULT 'N', 40 Insert_priv ENUM('N','Y') NOT NULL DEFAULT 'N', 41 Update_priv ENUM('N','Y') NOT NULL DEFAULT 'N', 42 Delete_priv ENUM('N','Y') NOT NULL DEFAULT 'N', 43 Create_priv ENUM('N','Y') NOT NULL DEFAULT 'N', 44 Drop_priv ENUM('N','Y') NOT NULL DEFAULT 'N', 45 Grant_priv ENUM('N','Y') NOT NULL DEFAULT 'N', 46 Alter_priv ENUM('N','Y') NOT NULL DEFAULT 'N', 47 Show_db_priv ENUM('N','Y') NOT NULL DEFAULT 'N', 48 Execute_priv ENUM('N','Y') NOT NULL DEFAULT 'N', 49 Index_priv ENUM('N','Y') NOT NULL DEFAULT 'N', 50 Create_user_priv ENUM('N','Y') NOT NULL DEFAULT 'N', 51 PRIMARY KEY (Host, User));` 52 // CreateDBPrivTable is the SQL statement creates DB scope privilege table in system db. 53 CreateDBPrivTable = `CREATE TABLE if not exists mysql.db ( 54 Host CHAR(60), 55 DB CHAR(64), 56 User CHAR(16), 57 Select_priv ENUM('N','Y') Not Null DEFAULT 'N', 58 Insert_priv ENUM('N','Y') Not Null DEFAULT 'N', 59 Update_priv ENUM('N','Y') Not Null DEFAULT 'N', 60 Delete_priv ENUM('N','Y') Not Null DEFAULT 'N', 61 Create_priv ENUM('N','Y') Not Null DEFAULT 'N', 62 Drop_priv ENUM('N','Y') Not Null DEFAULT 'N', 63 Grant_priv ENUM('N','Y') Not Null DEFAULT 'N', 64 Index_priv ENUM('N','Y') Not Null DEFAULT 'N', 65 Alter_priv ENUM('N','Y') Not Null DEFAULT 'N', 66 Execute_priv ENUM('N','Y') Not Null DEFAULT 'N', 67 PRIMARY KEY (Host, DB, User));` 68 // CreateTablePrivTable is the SQL statement creates table scope privilege table in system db. 69 CreateTablePrivTable = `CREATE TABLE if not exists mysql.tables_priv ( 70 Host CHAR(60), 71 DB CHAR(64), 72 User CHAR(16), 73 Table_name CHAR(64), 74 Grantor CHAR(77), 75 Timestamp Timestamp DEFAULT CURRENT_TIMESTAMP, 76 Table_priv SET('Select','Insert','Update','Delete','Create','Drop','Grant', 'Index','Alter'), 77 Column_priv SET('Select','Insert','Update'), 78 PRIMARY KEY (Host, DB, User, Table_name));` 79 // CreateColumnPrivTable is the SQL statement creates column scope privilege table in system db. 80 CreateColumnPrivTable = `CREATE TABLE if not exists mysql.columns_priv( 81 Host CHAR(60), 82 DB CHAR(64), 83 User CHAR(16), 84 Table_name CHAR(64), 85 Column_name CHAR(64), 86 Timestamp Timestamp DEFAULT CURRENT_TIMESTAMP, 87 Column_priv SET('Select','Insert','Update'), 88 PRIMARY KEY (Host, DB, User, Table_name, Column_name));` 89 // CreateGloablVariablesTable is the SQL statement creates global variable table in system db. 90 // TODO: MySQL puts GLOBAL_VARIABLES table in INFORMATION_SCHEMA db. 91 // INFORMATION_SCHEMA is a virtual db in TiDB. So we put this table in system db. 92 // Maybe we will put it back to INFORMATION_SCHEMA. 93 CreateGloablVariablesTable = `CREATE TABLE if not exists mysql.GLOBAL_VARIABLES( 94 VARIABLE_NAME VARCHAR(64) Not Null PRIMARY KEY, 95 VARIABLE_VALUE VARCHAR(1024) DEFAULT Null);` 96 // CreateTiDBTable is the SQL statement creates a table in system db. 97 // This table is a key-value struct contains some information used by TiDB. 98 // Currently we only put bootstrapped in it which indicates if the system is already bootstrapped. 99 CreateTiDBTable = `CREATE TABLE if not exists mysql.tidb( 100 VARIABLE_NAME VARCHAR(64) Not Null PRIMARY KEY, 101 VARIABLE_VALUE VARCHAR(1024) DEFAULT Null, 102 COMMENT VARCHAR(1024));` 103 ) 104 105 // Bootstrap initiates system DB for a store. 106 func bootstrap(s Session) { 107 b, err := checkBootstrapped(s) 108 if err != nil { 109 log.Fatal(err) 110 } 111 if b { 112 return 113 } 114 doDDLWorks(s) 115 doDMLWorks(s) 116 } 117 118 const ( 119 bootstrappedVar = "bootstrapped" 120 bootstrappedVarTrue = "True" 121 ) 122 123 func checkBootstrapped(s Session) (bool, error) { 124 // Check if system db exists. 125 _, err := s.Execute(fmt.Sprintf("USE %s;", mysql.SystemDB)) 126 if err != nil && infoschema.ErrDatabaseNotExists.NotEqual(err) { 127 log.Fatal(err) 128 } 129 // Check bootstrapped variable value in TiDB table. 130 v, err := checkBootstrappedVar(s) 131 if err != nil { 132 return false, errors.Trace(err) 133 } 134 return v, nil 135 } 136 137 func checkBootstrappedVar(s Session) (bool, error) { 138 sql := fmt.Sprintf(`SELECT VARIABLE_VALUE FROM %s.%s WHERE VARIABLE_NAME="%s"`, 139 mysql.SystemDB, mysql.TiDBTable, bootstrappedVar) 140 rs, err := s.Execute(sql) 141 if err != nil { 142 if infoschema.ErrTableNotExists.Equal(err) { 143 return false, nil 144 } 145 return false, errors.Trace(err) 146 } 147 148 if len(rs) != 1 { 149 return false, errors.New("Wrong number of Recordset") 150 } 151 r := rs[0] 152 row, err := r.Next() 153 if err != nil || row == nil { 154 return false, errors.Trace(err) 155 } 156 157 isBootstrapped := row.Data[0].GetString() == bootstrappedVarTrue 158 if isBootstrapped { 159 // Make sure that doesn't affect the following operations. 160 161 if err = s.FinishTxn(false); err != nil { 162 return false, errors.Trace(err) 163 } 164 } 165 166 return isBootstrapped, nil 167 } 168 169 // Execute DDL statements in bootstrap stage. 170 func doDDLWorks(s Session) { 171 // Create a test database. 172 mustExecute(s, "CREATE DATABASE IF NOT EXISTS test") 173 // Create system db. 174 mustExecute(s, fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s;", mysql.SystemDB)) 175 // Create user table. 176 mustExecute(s, CreateUserTable) 177 // Create privilege tables. 178 mustExecute(s, CreateDBPrivTable) 179 mustExecute(s, CreateTablePrivTable) 180 mustExecute(s, CreateColumnPrivTable) 181 // Create global systemt variable table. 182 mustExecute(s, CreateGloablVariablesTable) 183 // Create TiDB table. 184 mustExecute(s, CreateTiDBTable) 185 } 186 187 // Execute DML statements in bootstrap stage. 188 // All the statements run in a single transaction. 189 func doDMLWorks(s Session) { 190 mustExecute(s, "BEGIN") 191 192 // Insert a default user with empty password. 193 mustExecute(s, `INSERT INTO mysql.user VALUES 194 ("%", "root", "", "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y")`) 195 196 // Init global system variables table. 197 values := make([]string, 0, len(variable.SysVars)) 198 for k, v := range variable.SysVars { 199 value := fmt.Sprintf(`("%s", "%s")`, strings.ToLower(k), v.Value) 200 values = append(values, value) 201 } 202 sql := fmt.Sprintf("INSERT INTO %s.%s VALUES %s;", mysql.SystemDB, mysql.GlobalVariablesTable, 203 strings.Join(values, ", ")) 204 mustExecute(s, sql) 205 206 sql = fmt.Sprintf(`INSERT INTO %s.%s VALUES("%s", "%s", "Bootstrap flag. Do not delete.") 207 ON DUPLICATE KEY UPDATE VARIABLE_VALUE="%s"`, 208 mysql.SystemDB, mysql.TiDBTable, bootstrappedVar, bootstrappedVarTrue, bootstrappedVarTrue) 209 mustExecute(s, sql) 210 _, err := s.Execute("COMMIT") 211 if err != nil { 212 time.Sleep(1 * time.Second) 213 // Check if TiDB is already bootstrapped. 214 b, err1 := checkBootstrapped(s) 215 if err1 != nil { 216 log.Fatal(err1) 217 } 218 if b { 219 return 220 } 221 log.Fatal(err) 222 } 223 } 224 225 func mustExecute(s Session, sql string) { 226 _, err := s.Execute(sql) 227 if err != nil { 228 debug.PrintStack() 229 log.Fatal(err) 230 } 231 }