github.com/bingoohuang/gg@v0.0.0-20240325092523-45da7dee9335/pkg/sqlparse/tidbparser/dependency/model/model.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 model 15 16 import ( 17 "strings" 18 "time" 19 20 "github.com/bingoohuang/gg/pkg/sqlparse/tidbparser/dependency/mysql" 21 "github.com/bingoohuang/gg/pkg/sqlparse/tidbparser/dependency/types" 22 ) 23 24 // SchemaState is the state for schema elements. 25 type SchemaState byte 26 27 const ( 28 // StateNone means this schema element is absent and can't be used. 29 StateNone SchemaState = iota 30 // StateDeleteOnly means we can only delete items for this schema element. 31 StateDeleteOnly 32 // StateWriteOnly means we can use any write operation on this schema element, 33 // but outer can't read the changed data. 34 StateWriteOnly 35 // StateWriteReorganization means we are re-organizating whole data after write only state. 36 StateWriteReorganization 37 // StateDeleteReorganization means we are re-organizating whole data after delete only state. 38 StateDeleteReorganization 39 // StatePublic means this schema element is ok for all write and read operations. 40 StatePublic 41 ) 42 43 // String implements fmt.Stringer interface. 44 func (s SchemaState) String() string { 45 switch s { 46 case StateDeleteOnly: 47 return "delete only" 48 case StateWriteOnly: 49 return "write only" 50 case StateWriteReorganization: 51 return "write reorganization" 52 case StateDeleteReorganization: 53 return "delete reorganization" 54 case StatePublic: 55 return "public" 56 default: 57 return "none" 58 } 59 } 60 61 // ColumnInfo provides meta data describing of a table column. 62 type ColumnInfo struct { 63 ID int64 `json:"id"` 64 Name CIStr `json:"name"` 65 Offset int `json:"offset"` 66 OriginDefaultValue interface{} `json:"origin_default"` 67 DefaultValue interface{} `json:"default"` 68 GeneratedExprString string `json:"generated_expr_string"` 69 GeneratedStored bool `json:"generated_stored"` 70 Dependences map[string]struct{} `json:"dependences"` 71 types.FieldType `json:"type"` 72 State SchemaState `json:"state"` 73 Comment string `json:"comment"` 74 } 75 76 // Clone clones ColumnInfo. 77 func (c *ColumnInfo) Clone() *ColumnInfo { 78 nc := *c 79 return &nc 80 } 81 82 // IsGenerated returns true if the column is generated column. 83 func (c *ColumnInfo) IsGenerated() bool { 84 return len(c.GeneratedExprString) != 0 85 } 86 87 // ExtraHandleID is the column ID of column which we need to append to schema to occupy the handle's position 88 // for use of execution phase. 89 const ExtraHandleID = -1 90 91 // ExtraHandleName is the name of ExtraHandle Column. 92 var ExtraHandleName = NewCIStr("_rowid") 93 94 // TableInfo provides meta data describing a DB table. 95 type TableInfo struct { 96 ID int64 `json:"id"` 97 Name CIStr `json:"name"` 98 Charset string `json:"charset"` 99 Collate string `json:"collate"` 100 // Columns are listed in the order in which they appear in the schema. 101 Columns []*ColumnInfo `json:"cols"` 102 Indices []*IndexInfo `json:"index_info"` 103 ForeignKeys []*FKInfo `json:"fk_info"` 104 State SchemaState `json:"state"` 105 PKIsHandle bool `json:"pk_is_handle"` 106 Comment string `json:"comment"` 107 AutoIncID int64 `json:"auto_inc_id"` 108 MaxColumnID int64 `json:"max_col_id"` 109 MaxIndexID int64 `json:"max_idx_id"` 110 // UpdateTS is used to record the timestamp of updating the table's schema information. 111 // These changing schema operations don't include 'truncate table' and 'rename table'. 112 UpdateTS uint64 `json:"update_timestamp"` 113 // OldSchemaID : 114 // Because auto increment ID has schemaID as prefix, 115 // We need to save original schemaID to keep autoID unchanged 116 // while renaming a table from one database to another. 117 // TODO: Remove it. 118 // Now it only uses for compatibility with the old version that already uses this field. 119 OldSchemaID int64 `json:"old_schema_id,omitempty"` 120 121 // ShardRowIDBits specify if the implicit row ID is sharded. 122 ShardRowIDBits uint64 123 } 124 125 // GetUpdateTime gets the table's updating time. 126 func (t *TableInfo) GetUpdateTime() time.Time { 127 return tsConvert2Time(t.UpdateTS) 128 } 129 130 // GetDBID returns the schema ID that is used to create an allocator. 131 // TODO: Remove it after removing OldSchemaID. 132 func (t *TableInfo) GetDBID(dbID int64) int64 { 133 if t.OldSchemaID != 0 { 134 return t.OldSchemaID 135 } 136 return dbID 137 } 138 139 // Clone clones TableInfo. 140 func (t *TableInfo) Clone() *TableInfo { 141 nt := *t 142 nt.Columns = make([]*ColumnInfo, len(t.Columns)) 143 nt.Indices = make([]*IndexInfo, len(t.Indices)) 144 nt.ForeignKeys = make([]*FKInfo, len(t.ForeignKeys)) 145 146 for i := range t.Columns { 147 nt.Columns[i] = t.Columns[i].Clone() 148 } 149 150 for i := range t.Indices { 151 nt.Indices[i] = t.Indices[i].Clone() 152 } 153 154 for i := range t.ForeignKeys { 155 nt.ForeignKeys[i] = t.ForeignKeys[i].Clone() 156 } 157 158 return &nt 159 } 160 161 // GetPkName will return the pk name if pk exists. 162 func (t *TableInfo) GetPkName() CIStr { 163 if t.PKIsHandle { 164 for _, colInfo := range t.Columns { 165 if mysql.HasPriKeyFlag(colInfo.Flag) { 166 return colInfo.Name 167 } 168 } 169 } 170 return CIStr{} 171 } 172 173 // GetPkColInfo gets the ColumnInfo of pk if exists. 174 // Make sure PkIsHandle checked before call this method. 175 func (t *TableInfo) GetPkColInfo() *ColumnInfo { 176 for _, colInfo := range t.Columns { 177 if mysql.HasPriKeyFlag(colInfo.Flag) { 178 return colInfo 179 } 180 } 181 return nil 182 } 183 184 // Cols returns the columns of the table in public state. 185 func (t *TableInfo) Cols() []*ColumnInfo { 186 publicColumns := make([]*ColumnInfo, len(t.Columns)) 187 maxOffset := -1 188 for _, col := range t.Columns { 189 if col.State != StatePublic { 190 continue 191 } 192 publicColumns[col.Offset] = col 193 if maxOffset < col.Offset { 194 maxOffset = col.Offset 195 } 196 } 197 return publicColumns[0 : maxOffset+1] 198 } 199 200 // NewExtraHandleColInfo mocks a column info for extra handle column. 201 func NewExtraHandleColInfo() *ColumnInfo { 202 colInfo := &ColumnInfo{ 203 ID: ExtraHandleID, 204 Name: ExtraHandleName, 205 } 206 colInfo.Flag = mysql.PriKeyFlag 207 return colInfo 208 } 209 210 // ColumnIsInIndex checks whether c is included in any indices of t. 211 func (t *TableInfo) ColumnIsInIndex(c *ColumnInfo) bool { 212 for _, index := range t.Indices { 213 for _, column := range index.Columns { 214 if column.Name.L == c.Name.L { 215 return true 216 } 217 } 218 } 219 return false 220 } 221 222 // IndexColumn provides index column info. 223 type IndexColumn struct { 224 Name CIStr `json:"name"` // Index name 225 Offset int `json:"offset"` // Index offset 226 // Length of prefix when using column prefix 227 // for indexing; 228 // UnspecifedLength if not using prefix indexing 229 Length int `json:"length"` 230 } 231 232 // Clone clones IndexColumn. 233 func (i *IndexColumn) Clone() *IndexColumn { 234 ni := *i 235 return &ni 236 } 237 238 // IndexType is the type of index 239 type IndexType int 240 241 // String implements Stringer interface. 242 func (t IndexType) String() string { 243 switch t { 244 case IndexTypeBtree: 245 return "BTREE" 246 case IndexTypeHash: 247 return "HASH" 248 default: 249 return "" 250 } 251 } 252 253 // IndexTypes 254 const ( 255 IndexTypeInvalid IndexType = iota 256 IndexTypeBtree 257 IndexTypeHash 258 ) 259 260 // IndexInfo provides meta data describing a DB index. 261 // It corresponds to the statement `CREATE INDEX Name ON Table (Column);` 262 // See https://dev.mysql.com/doc/refman/5.7/en/create-index.html 263 type IndexInfo struct { 264 ID int64 `json:"id"` 265 Name CIStr `json:"idx_name"` // Index name. 266 Table CIStr `json:"tbl_name"` // Table name. 267 Columns []*IndexColumn `json:"idx_cols"` // Index columns. 268 Unique bool `json:"is_unique"` // Whether the index is unique. 269 Primary bool `json:"is_primary"` // Whether the index is primary key. 270 State SchemaState `json:"state"` 271 Comment string `json:"comment"` // Comment 272 Tp IndexType `json:"index_type"` // Index type: Btree or Hash 273 } 274 275 // Clone clones IndexInfo. 276 func (index *IndexInfo) Clone() *IndexInfo { 277 ni := *index 278 ni.Columns = make([]*IndexColumn, len(index.Columns)) 279 for i := range index.Columns { 280 ni.Columns[i] = index.Columns[i].Clone() 281 } 282 return &ni 283 } 284 285 // HasPrefixIndex returns whether any columns of this index uses prefix length. 286 func (index *IndexInfo) HasPrefixIndex() bool { 287 for _, ic := range index.Columns { 288 if ic.Length != types.UnspecifiedLength { 289 return true 290 } 291 } 292 return false 293 } 294 295 // FKInfo provides meta data describing a foreign key constraint. 296 type FKInfo struct { 297 ID int64 `json:"id"` 298 Name CIStr `json:"fk_name"` 299 RefTable CIStr `json:"ref_table"` 300 RefCols []CIStr `json:"ref_cols"` 301 Cols []CIStr `json:"cols"` 302 OnDelete int `json:"on_delete"` 303 OnUpdate int `json:"on_update"` 304 State SchemaState `json:"state"` 305 } 306 307 // Clone clones FKInfo. 308 func (fk *FKInfo) Clone() *FKInfo { 309 nfk := *fk 310 311 nfk.RefCols = make([]CIStr, len(fk.RefCols)) 312 nfk.Cols = make([]CIStr, len(fk.Cols)) 313 copy(nfk.RefCols, fk.RefCols) 314 copy(nfk.Cols, fk.Cols) 315 316 return &nfk 317 } 318 319 // DBInfo provides meta data describing a DB. 320 type DBInfo struct { 321 ID int64 `json:"id"` // Database ID 322 Name CIStr `json:"db_name"` // DB name. 323 Charset string `json:"charset"` 324 Collate string `json:"collate"` 325 Tables []*TableInfo `json:"-"` // Tables in the DB. 326 State SchemaState `json:"state"` 327 } 328 329 // Clone clones DBInfo. 330 func (db *DBInfo) Clone() *DBInfo { 331 newInfo := *db 332 newInfo.Tables = make([]*TableInfo, len(db.Tables)) 333 for i := range db.Tables { 334 newInfo.Tables[i] = db.Tables[i].Clone() 335 } 336 return &newInfo 337 } 338 339 // CIStr is case insensitive string. 340 type CIStr struct { 341 O string `json:"O"` // Original string. 342 L string `json:"L"` // Lower case string. 343 } 344 345 // String implements fmt.Stringer interface. 346 func (cis CIStr) String() string { 347 return cis.O 348 } 349 350 // NewCIStr creates a new CIStr. 351 func NewCIStr(s string) (cs CIStr) { 352 cs.O = s 353 cs.L = strings.ToLower(s) 354 return 355 }