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  }