github.com/pingcap/tidb/parser@v0.0.0-20231013125129-93a834a6bf8d/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  	"bytes"
    18  	"cmp"
    19  	"encoding/json"
    20  	"fmt"
    21  	"strconv"
    22  	"strings"
    23  	"time"
    24  	"unsafe"
    25  
    26  	"github.com/pingcap/errors"
    27  	"github.com/pingcap/tidb/parser/auth"
    28  	"github.com/pingcap/tidb/parser/charset"
    29  	"github.com/pingcap/tidb/parser/duration"
    30  	"github.com/pingcap/tidb/parser/mysql"
    31  	"github.com/pingcap/tidb/parser/types"
    32  )
    33  
    34  // SchemaState is the state for schema elements.
    35  type SchemaState byte
    36  
    37  const (
    38  	// StateNone means this schema element is absent and can't be used.
    39  	StateNone SchemaState = iota
    40  	// StateDeleteOnly means we can only delete items for this schema element.
    41  	StateDeleteOnly
    42  	// StateWriteOnly means we can use any write operation on this schema element,
    43  	// but outer can't read the changed data.
    44  	StateWriteOnly
    45  	// StateWriteReorganization means we are re-organizing whole data after write only state.
    46  	StateWriteReorganization
    47  	// StateDeleteReorganization means we are re-organizing whole data after delete only state.
    48  	StateDeleteReorganization
    49  	// StatePublic means this schema element is ok for all write and read operations.
    50  	StatePublic
    51  	// StateReplicaOnly means we're waiting tiflash replica to be finished.
    52  	StateReplicaOnly
    53  	// StateGlobalTxnOnly means we can only use global txn for operator on this schema element
    54  	StateGlobalTxnOnly
    55  	/*
    56  	 *  Please add the new state at the end to keep the values consistent across versions.
    57  	 */
    58  )
    59  
    60  // String implements fmt.Stringer interface.
    61  func (s SchemaState) String() string {
    62  	switch s {
    63  	case StateDeleteOnly:
    64  		return "delete only"
    65  	case StateWriteOnly:
    66  		return "write only"
    67  	case StateWriteReorganization:
    68  		return "write reorganization"
    69  	case StateDeleteReorganization:
    70  		return "delete reorganization"
    71  	case StatePublic:
    72  		return "public"
    73  	case StateReplicaOnly:
    74  		return "replica only"
    75  	case StateGlobalTxnOnly:
    76  		return "global txn only"
    77  	default:
    78  		return "none"
    79  	}
    80  }
    81  
    82  const (
    83  	// ColumnInfoVersion0 means the column info version is 0.
    84  	ColumnInfoVersion0 = uint64(0)
    85  	// ColumnInfoVersion1 means the column info version is 1.
    86  	ColumnInfoVersion1 = uint64(1)
    87  	// ColumnInfoVersion2 means the column info version is 2.
    88  	// This is for v2.1.7 to Compatible with older versions charset problem.
    89  	// Old version such as v2.0.8 treat utf8 as utf8mb4, because there is no UTF8 check in v2.0.8.
    90  	// After version V2.1.2 (PR#8738) , TiDB add UTF8 check, then the user upgrade from v2.0.8 insert some UTF8MB4 characters will got error.
    91  	// This is not compatibility for user. Then we try to fix this in PR #9820, and increase the version number.
    92  	ColumnInfoVersion2 = uint64(2)
    93  
    94  	// CurrLatestColumnInfoVersion means the latest column info in the current TiDB.
    95  	CurrLatestColumnInfoVersion = ColumnInfoVersion2
    96  )
    97  
    98  // ChangeStateInfo is used for recording the information of schema changing.
    99  type ChangeStateInfo struct {
   100  	// DependencyColumnOffset is the changing column offset that the current column depends on when executing modify/change column.
   101  	DependencyColumnOffset int `json:"relative_col_offset"`
   102  }
   103  
   104  // ColumnInfo provides meta data describing of a table column.
   105  type ColumnInfo struct {
   106  	ID                    int64       `json:"id"`
   107  	Name                  CIStr       `json:"name"`
   108  	Offset                int         `json:"offset"`
   109  	OriginDefaultValue    interface{} `json:"origin_default"`
   110  	OriginDefaultValueBit []byte      `json:"origin_default_bit"`
   111  	DefaultValue          interface{} `json:"default"`
   112  	DefaultValueBit       []byte      `json:"default_bit"`
   113  	// DefaultIsExpr is indicates the default value string is expr.
   114  	DefaultIsExpr       bool                `json:"default_is_expr"`
   115  	GeneratedExprString string              `json:"generated_expr_string"`
   116  	GeneratedStored     bool                `json:"generated_stored"`
   117  	Dependences         map[string]struct{} `json:"dependences"`
   118  	FieldType           types.FieldType     `json:"type"`
   119  	State               SchemaState         `json:"state"`
   120  	Comment             string              `json:"comment"`
   121  	// A hidden column is used internally(expression index) and are not accessible by users.
   122  	Hidden           bool `json:"hidden"`
   123  	*ChangeStateInfo `json:"change_state_info"`
   124  	// Version means the version of the column info.
   125  	// Version = 0: For OriginDefaultValue and DefaultValue of timestamp column will stores the default time in system time zone.
   126  	//              That is a bug if multiple TiDB servers in different system time zone.
   127  	// Version = 1: For OriginDefaultValue and DefaultValue of timestamp column will stores the default time in UTC time zone.
   128  	//              This will fix bug in version 0. For compatibility with version 0, we add version field in column info struct.
   129  	Version uint64 `json:"version"`
   130  }
   131  
   132  // IsVirtualGenerated checks the column if it is virtual.
   133  func (c *ColumnInfo) IsVirtualGenerated() bool {
   134  	return c.IsGenerated() && !c.GeneratedStored
   135  }
   136  
   137  // Clone clones ColumnInfo.
   138  func (c *ColumnInfo) Clone() *ColumnInfo {
   139  	if c == nil {
   140  		return nil
   141  	}
   142  	nc := *c
   143  	return &nc
   144  }
   145  
   146  // GetType returns the type of ColumnInfo.
   147  func (c *ColumnInfo) GetType() byte {
   148  	return c.FieldType.GetType()
   149  }
   150  
   151  // GetFlag returns the flag of ColumnInfo.
   152  func (c *ColumnInfo) GetFlag() uint {
   153  	return c.FieldType.GetFlag()
   154  }
   155  
   156  // GetFlen returns the flen of ColumnInfo.
   157  func (c *ColumnInfo) GetFlen() int {
   158  	return c.FieldType.GetFlen()
   159  }
   160  
   161  // GetDecimal returns the decimal of ColumnInfo.
   162  func (c *ColumnInfo) GetDecimal() int {
   163  	return c.FieldType.GetDecimal()
   164  }
   165  
   166  // GetCharset returns the charset of ColumnInfo.
   167  func (c *ColumnInfo) GetCharset() string {
   168  	return c.FieldType.GetCharset()
   169  }
   170  
   171  // GetCollate returns the collation of ColumnInfo.
   172  func (c *ColumnInfo) GetCollate() string {
   173  	return c.FieldType.GetCollate()
   174  }
   175  
   176  // GetElems returns the elems of ColumnInfo.
   177  func (c *ColumnInfo) GetElems() []string {
   178  	return c.FieldType.GetElems()
   179  }
   180  
   181  // SetType set the type of ColumnInfo.
   182  func (c *ColumnInfo) SetType(tp byte) {
   183  	c.FieldType.SetType(tp)
   184  }
   185  
   186  // SetFlag set the flag of ColumnInfo.
   187  func (c *ColumnInfo) SetFlag(flag uint) {
   188  	c.FieldType.SetFlag(flag)
   189  }
   190  
   191  // AddFlag adds the flag of ColumnInfo.
   192  func (c *ColumnInfo) AddFlag(flag uint) {
   193  	c.FieldType.AddFlag(flag)
   194  }
   195  
   196  // AndFlag adds a flag to the column.
   197  func (c *ColumnInfo) AndFlag(flag uint) {
   198  	c.FieldType.AndFlag(flag)
   199  }
   200  
   201  // ToggleFlag flips the flag according to the value.
   202  func (c *ColumnInfo) ToggleFlag(flag uint) {
   203  	c.FieldType.ToggleFlag(flag)
   204  }
   205  
   206  // DelFlag removes the flag from the column's flag.
   207  func (c *ColumnInfo) DelFlag(flag uint) {
   208  	c.FieldType.DelFlag(flag)
   209  }
   210  
   211  // SetFlen sets the flen of ColumnInfo.
   212  func (c *ColumnInfo) SetFlen(flen int) {
   213  	c.FieldType.SetFlen(flen)
   214  }
   215  
   216  // SetDecimal sets the decimal of ColumnInfo.
   217  func (c *ColumnInfo) SetDecimal(decimal int) {
   218  	c.FieldType.SetDecimal(decimal)
   219  }
   220  
   221  // SetCharset sets charset of the ColumnInfo
   222  func (c *ColumnInfo) SetCharset(charset string) {
   223  	c.FieldType.SetCharset(charset)
   224  }
   225  
   226  // SetCollate sets the collation of the column.
   227  func (c *ColumnInfo) SetCollate(collate string) {
   228  	c.FieldType.SetCollate(collate)
   229  }
   230  
   231  // SetElems set the elements of enum column.
   232  func (c *ColumnInfo) SetElems(elems []string) {
   233  	c.FieldType.SetElems(elems)
   234  }
   235  
   236  // IsGenerated returns true if the column is generated column.
   237  func (c *ColumnInfo) IsGenerated() bool {
   238  	return len(c.GeneratedExprString) != 0
   239  }
   240  
   241  // SetOriginDefaultValue sets the origin default value.
   242  // For mysql.TypeBit type, the default value storage format must be a string.
   243  // Other value such as int must convert to string format first.
   244  // The mysql.TypeBit type supports the null default value.
   245  func (c *ColumnInfo) SetOriginDefaultValue(value interface{}) error {
   246  	c.OriginDefaultValue = value
   247  	if c.GetType() == mysql.TypeBit {
   248  		if value == nil {
   249  			return nil
   250  		}
   251  		if v, ok := value.(string); ok {
   252  			c.OriginDefaultValueBit = []byte(v)
   253  			return nil
   254  		}
   255  		return types.ErrInvalidDefault.GenWithStackByArgs(c.Name)
   256  	}
   257  	return nil
   258  }
   259  
   260  // GetOriginDefaultValue gets the origin default value.
   261  func (c *ColumnInfo) GetOriginDefaultValue() interface{} {
   262  	if c.GetType() == mysql.TypeBit && c.OriginDefaultValueBit != nil {
   263  		// If the column type is BIT, both `OriginDefaultValue` and `DefaultValue` of ColumnInfo are corrupted,
   264  		// because the content before json.Marshal is INCONSISTENT with the content after json.Unmarshal.
   265  		return string(c.OriginDefaultValueBit)
   266  	}
   267  	return c.OriginDefaultValue
   268  }
   269  
   270  // SetDefaultValue sets the default value.
   271  func (c *ColumnInfo) SetDefaultValue(value interface{}) error {
   272  	c.DefaultValue = value
   273  	if c.GetType() == mysql.TypeBit {
   274  		// For mysql.TypeBit type, the default value storage format must be a string.
   275  		// Other value such as int must convert to string format first.
   276  		// The mysql.TypeBit type supports the null default value.
   277  		if value == nil {
   278  			return nil
   279  		}
   280  		if v, ok := value.(string); ok {
   281  			c.DefaultValueBit = []byte(v)
   282  			return nil
   283  		}
   284  		return types.ErrInvalidDefault.GenWithStackByArgs(c.Name)
   285  	}
   286  	return nil
   287  }
   288  
   289  // GetDefaultValue gets the default value of the column.
   290  // Default value use to stored in DefaultValue field, but now,
   291  // bit type default value will store in DefaultValueBit for fix bit default value decode/encode bug.
   292  func (c *ColumnInfo) GetDefaultValue() interface{} {
   293  	if c.GetType() == mysql.TypeBit && c.DefaultValueBit != nil {
   294  		return string(c.DefaultValueBit)
   295  	}
   296  	return c.DefaultValue
   297  }
   298  
   299  // GetTypeDesc gets the description for column type.
   300  func (c *ColumnInfo) GetTypeDesc() string {
   301  	desc := c.FieldType.CompactStr()
   302  	if mysql.HasUnsignedFlag(c.GetFlag()) && c.GetType() != mysql.TypeBit && c.GetType() != mysql.TypeYear {
   303  		desc += " unsigned"
   304  	}
   305  	if mysql.HasZerofillFlag(c.GetFlag()) && c.GetType() != mysql.TypeYear {
   306  		desc += " zerofill"
   307  	}
   308  	return desc
   309  }
   310  
   311  // EmptyColumnInfoSize is the memory usage of ColumnInfoSize
   312  const EmptyColumnInfoSize = int64(unsafe.Sizeof(ColumnInfo{}))
   313  
   314  // FindColumnInfo finds ColumnInfo in cols by name.
   315  func FindColumnInfo(cols []*ColumnInfo, name string) *ColumnInfo {
   316  	name = strings.ToLower(name)
   317  	for _, col := range cols {
   318  		if col.Name.L == name {
   319  			return col
   320  		}
   321  	}
   322  	return nil
   323  }
   324  
   325  // FindColumnInfoByID finds ColumnInfo in cols by id.
   326  func FindColumnInfoByID(cols []*ColumnInfo, id int64) *ColumnInfo {
   327  	for _, col := range cols {
   328  		if col.ID == id {
   329  			return col
   330  		}
   331  	}
   332  	return nil
   333  }
   334  
   335  // FindIndexInfoByID finds IndexInfo in indices by id.
   336  func FindIndexInfoByID(indices []*IndexInfo, id int64) *IndexInfo {
   337  	for _, idx := range indices {
   338  		if idx.ID == id {
   339  			return idx
   340  		}
   341  	}
   342  	return nil
   343  }
   344  
   345  // FindFKInfoByName finds FKInfo in fks by lowercase name.
   346  func FindFKInfoByName(fks []*FKInfo, name string) *FKInfo {
   347  	for _, fk := range fks {
   348  		if fk.Name.L == name {
   349  			return fk
   350  		}
   351  	}
   352  	return nil
   353  }
   354  
   355  // FindIndexByColumns find IndexInfo in indices which is cover the specified columns.
   356  func FindIndexByColumns(tbInfo *TableInfo, indices []*IndexInfo, cols ...CIStr) *IndexInfo {
   357  	for _, index := range indices {
   358  		if IsIndexPrefixCovered(tbInfo, index, cols...) {
   359  			return index
   360  		}
   361  	}
   362  	return nil
   363  }
   364  
   365  // IsIndexPrefixCovered checks the index's columns beginning with the cols.
   366  func IsIndexPrefixCovered(tbInfo *TableInfo, index *IndexInfo, cols ...CIStr) bool {
   367  	if len(index.Columns) < len(cols) {
   368  		return false
   369  	}
   370  	for i := range cols {
   371  		if cols[i].L != index.Columns[i].Name.L ||
   372  			index.Columns[i].Offset >= len(tbInfo.Columns) {
   373  			return false
   374  		}
   375  		colInfo := tbInfo.Columns[index.Columns[i].Offset]
   376  		if index.Columns[i].Length != types.UnspecifiedLength && index.Columns[i].Length < colInfo.GetFlen() {
   377  			return false
   378  		}
   379  	}
   380  	return true
   381  }
   382  
   383  // ExtraHandleID is the column ID of column which we need to append to schema to occupy the handle's position
   384  // for use of execution phase.
   385  const ExtraHandleID = -1
   386  
   387  // ExtraPidColID is the column ID of column which store the partitionID decoded in global index values.
   388  const ExtraPidColID = -2
   389  
   390  // ExtraPhysTblID is the column ID of column that should be filled in with the physical table id.
   391  // Primarily used for table partition dynamic prune mode, to return which partition (physical table id) the row came from.
   392  // Using a dedicated id for this, since in the future ExtraPidColID and ExtraPhysTblID may be used for the same request.
   393  // Must be after ExtraPidColID!
   394  const ExtraPhysTblID = -3
   395  
   396  // ExtraRowChecksumID is the column ID of column which holds the row checksum info.
   397  const ExtraRowChecksumID = -4
   398  
   399  const (
   400  	// TableInfoVersion0 means the table info version is 0.
   401  	// Upgrade from v2.1.1 or v2.1.2 to v2.1.3 and later, and then execute a "change/modify column" statement
   402  	// that does not specify a charset value for column. Then the following error may be reported:
   403  	// ERROR 1105 (HY000): unsupported modify charset from utf8mb4 to utf8.
   404  	// To eliminate this error, we will not modify the charset of this column
   405  	// when executing a change/modify column statement that does not specify a charset value for column.
   406  	// This behavior is not compatible with MySQL.
   407  	TableInfoVersion0 = uint16(0)
   408  	// TableInfoVersion1 means the table info version is 1.
   409  	// When we execute a change/modify column statement that does not specify a charset value for column,
   410  	// we set the charset of this column to the charset of table. This behavior is compatible with MySQL.
   411  	TableInfoVersion1 = uint16(1)
   412  	// TableInfoVersion2 means the table info version is 2.
   413  	// This is for v2.1.7 to Compatible with older versions charset problem.
   414  	// Old version such as v2.0.8 treat utf8 as utf8mb4, because there is no UTF8 check in v2.0.8.
   415  	// After version V2.1.2 (PR#8738) , TiDB add UTF8 check, then the user upgrade from v2.0.8 insert some UTF8MB4 characters will got error.
   416  	// This is not compatibility for user. Then we try to fix this in PR #9820, and increase the version number.
   417  	TableInfoVersion2 = uint16(2)
   418  	// TableInfoVersion3 means the table info version is 3.
   419  	// This version aims to deal with upper-cased charset name in TableInfo stored by versions prior to TiDB v2.1.9:
   420  	// TiDB always suppose all charsets / collations as lower-cased and try to convert them if they're not.
   421  	// However, the convert is missed in some scenarios before v2.1.9, so for all those tables prior to TableInfoVersion3, their
   422  	// charsets / collations will be converted to lower-case while loading from the storage.
   423  	TableInfoVersion3 = uint16(3)
   424  	// TableInfoVersion4 is not used.
   425  	TableInfoVersion4 = uint16(4)
   426  	// TableInfoVersion5 indicates that the auto_increment allocator in TiDB has been separated from
   427  	// _tidb_rowid allocator when AUTO_ID_CACHE is 1. This version is introduced to preserve the compatibility of old tables:
   428  	// the tables with version <= TableInfoVersion4 still use a single allocator for auto_increment and _tidb_rowid.
   429  	// Also see https://github.com/pingcap/tidb/issues/982.
   430  	TableInfoVersion5 = uint16(5)
   431  
   432  	// CurrLatestTableInfoVersion means the latest table info in the current TiDB.
   433  	CurrLatestTableInfoVersion = TableInfoVersion5
   434  )
   435  
   436  // ExtraHandleName is the name of ExtraHandle Column.
   437  var ExtraHandleName = NewCIStr("_tidb_rowid")
   438  
   439  // ExtraPartitionIdName is the name of ExtraPartitionId Column.
   440  var ExtraPartitionIdName = NewCIStr("_tidb_pid") //nolint:revive
   441  
   442  // ExtraPhysTblIdName is the name of ExtraPhysTblID Column.
   443  var ExtraPhysTblIdName = NewCIStr("_tidb_tid") //nolint:revive
   444  
   445  // TableInfo provides meta data describing a DB table.
   446  type TableInfo struct {
   447  	ID      int64  `json:"id"`
   448  	Name    CIStr  `json:"name"`
   449  	Charset string `json:"charset"`
   450  	Collate string `json:"collate"`
   451  	// Columns are listed in the order in which they appear in the schema.
   452  	Columns     []*ColumnInfo     `json:"cols"`
   453  	Indices     []*IndexInfo      `json:"index_info"`
   454  	Constraints []*ConstraintInfo `json:"constraint_info"`
   455  	ForeignKeys []*FKInfo         `json:"fk_info"`
   456  	State       SchemaState       `json:"state"`
   457  	// PKIsHandle is true when primary key is a single integer column.
   458  	PKIsHandle bool `json:"pk_is_handle"`
   459  	// IsCommonHandle is true when clustered index feature is
   460  	// enabled and the primary key is not a single integer column.
   461  	IsCommonHandle bool `json:"is_common_handle"`
   462  	// CommonHandleVersion is the version of the clustered index.
   463  	// 0 for the clustered index created == 5.0.0 RC.
   464  	// 1 for the clustered index created > 5.0.0 RC.
   465  	CommonHandleVersion uint16 `json:"common_handle_version"`
   466  
   467  	Comment   string `json:"comment"`
   468  	AutoIncID int64  `json:"auto_inc_id"`
   469  
   470  	// Only used by BR when:
   471  	// 1. SepAutoInc() is true
   472  	// 2. The table is nonclustered and has auto_increment column.
   473  	// In that case, both auto_increment_id and tidb_rowid need to be backup & recover.
   474  	// See also https://github.com/pingcap/tidb/issues/46093
   475  	//
   476  	// It should have been named TiDBRowID, but for historial reasons, we do not use separate meta key for _tidb_rowid and auto_increment_id,
   477  	// and field `AutoIncID` is used to serve both _tidb_rowid and auto_increment_id.
   478  	// If we introduce a TiDBRowID here, it could make furthur misunderstanding:
   479  	//	in most cases, AutoIncID is _tidb_rowid and TiDBRowID is null
   480  	//      but in some cases, AutoIncID is auto_increment_id and TiDBRowID is _tidb_rowid
   481  	// So let's just use another name AutoIncIDExtra to avoid misconception.
   482  	AutoIncIDExtra int64 `json:"auto_inc_id_extra,omitempty"`
   483  
   484  	AutoIdCache     int64 `json:"auto_id_cache"` //nolint:revive
   485  	AutoRandID      int64 `json:"auto_rand_id"`
   486  	MaxColumnID     int64 `json:"max_col_id"`
   487  	MaxIndexID      int64 `json:"max_idx_id"`
   488  	MaxForeignKeyID int64 `json:"max_fk_id"`
   489  	MaxConstraintID int64 `json:"max_cst_id"`
   490  	// UpdateTS is used to record the timestamp of updating the table's schema information.
   491  	// These changing schema operations don't include 'truncate table' and 'rename table'.
   492  	UpdateTS uint64 `json:"update_timestamp"`
   493  	// OldSchemaID :
   494  	// Because auto increment ID has schemaID as prefix,
   495  	// We need to save original schemaID to keep autoID unchanged
   496  	// while renaming a table from one database to another.
   497  	// TODO: Remove it.
   498  	// Now it only uses for compatibility with the old version that already uses this field.
   499  	OldSchemaID int64 `json:"old_schema_id,omitempty"`
   500  
   501  	// ShardRowIDBits specify if the implicit row ID is sharded.
   502  	ShardRowIDBits uint64
   503  	// MaxShardRowIDBits uses to record the max ShardRowIDBits be used so far.
   504  	MaxShardRowIDBits uint64 `json:"max_shard_row_id_bits"`
   505  	// AutoRandomBits is used to set the bit number to shard automatically when PKIsHandle.
   506  	AutoRandomBits uint64 `json:"auto_random_bits"`
   507  	// AutoRandomRangeBits represents the bit number of the int primary key that will be used by TiDB.
   508  	AutoRandomRangeBits uint64 `json:"auto_random_range_bits"`
   509  	// PreSplitRegions specify the pre-split region when create table.
   510  	// The pre-split region num is 2^(PreSplitRegions-1).
   511  	// And the PreSplitRegions should less than or equal to ShardRowIDBits.
   512  	PreSplitRegions uint64 `json:"pre_split_regions"`
   513  
   514  	Partition *PartitionInfo `json:"partition"`
   515  
   516  	Compression string `json:"compression"`
   517  
   518  	View *ViewInfo `json:"view"`
   519  
   520  	Sequence *SequenceInfo `json:"sequence"`
   521  
   522  	// Lock represent the table lock info.
   523  	Lock *TableLockInfo `json:"Lock"`
   524  
   525  	// Version means the version of the table info.
   526  	Version uint16 `json:"version"`
   527  
   528  	// TiFlashReplica means the TiFlash replica info.
   529  	TiFlashReplica *TiFlashReplicaInfo `json:"tiflash_replica"`
   530  
   531  	// IsColumnar means the table is column-oriented.
   532  	// It's true when the engine of the table is TiFlash only.
   533  	IsColumnar bool `json:"is_columnar"`
   534  
   535  	TempTableType        `json:"temp_table_type"`
   536  	TableCacheStatusType `json:"cache_table_status"`
   537  	PlacementPolicyRef   *PolicyRefInfo `json:"policy_ref_info"`
   538  
   539  	// StatsOptions is used when do analyze/auto-analyze for each table
   540  	StatsOptions *StatsOptions `json:"stats_options"`
   541  
   542  	ExchangePartitionInfo *ExchangePartitionInfo `json:"exchange_partition_info"`
   543  
   544  	TTLInfo *TTLInfo `json:"ttl_info"`
   545  }
   546  
   547  // SepAutoInc decides whether _rowid and auto_increment id use separate allocator.
   548  func (t *TableInfo) SepAutoInc() bool {
   549  	return t.Version >= TableInfoVersion5 && t.AutoIdCache == 1
   550  }
   551  
   552  // TableCacheStatusType is the type of the table cache status
   553  type TableCacheStatusType int
   554  
   555  //revive:disable:exported
   556  const (
   557  	TableCacheStatusDisable TableCacheStatusType = iota
   558  	TableCacheStatusEnable
   559  	TableCacheStatusSwitching
   560  )
   561  
   562  //revive:enable:exported
   563  
   564  func (t TableCacheStatusType) String() string {
   565  	switch t {
   566  	case TableCacheStatusDisable:
   567  		return "disable"
   568  	case TableCacheStatusEnable:
   569  		return "enable"
   570  	case TableCacheStatusSwitching:
   571  		return "switching"
   572  	default:
   573  		return ""
   574  	}
   575  }
   576  
   577  // TempTableType is the type of the temp table
   578  type TempTableType byte
   579  
   580  //revive:disable:exported
   581  const (
   582  	TempTableNone TempTableType = iota
   583  	TempTableGlobal
   584  	TempTableLocal
   585  )
   586  
   587  //revive:enable:exported
   588  
   589  func (t TempTableType) String() string {
   590  	switch t {
   591  	case TempTableGlobal:
   592  		return "global"
   593  	case TempTableLocal:
   594  		return "local"
   595  	default:
   596  		return ""
   597  	}
   598  }
   599  
   600  // TableLockInfo provides meta data describing a table lock.
   601  type TableLockInfo struct {
   602  	Tp TableLockType
   603  	// Use array because there may be multiple sessions holding the same read lock.
   604  	Sessions []SessionInfo
   605  	State    TableLockState
   606  	// TS is used to record the timestamp this table lock been locked.
   607  	TS uint64
   608  }
   609  
   610  // SessionInfo contain the session ID and the server ID.
   611  type SessionInfo struct {
   612  	ServerID  string
   613  	SessionID uint64
   614  }
   615  
   616  func (s SessionInfo) String() string {
   617  	return "server: " + s.ServerID + "_session: " + strconv.FormatUint(s.SessionID, 10)
   618  }
   619  
   620  // TableLockTpInfo is composed by schema ID, table ID and table lock type.
   621  type TableLockTpInfo struct {
   622  	SchemaID int64
   623  	TableID  int64
   624  	Tp       TableLockType
   625  }
   626  
   627  // TableLockState is the state for table lock.
   628  type TableLockState byte
   629  
   630  const (
   631  	// TableLockStateNone means this table lock is absent.
   632  	TableLockStateNone TableLockState = iota
   633  	// TableLockStatePreLock means this table lock is pre-lock state. Other session doesn't hold this lock should't do corresponding operation according to the lock type.
   634  	TableLockStatePreLock
   635  	// TableLockStatePublic means this table lock is public state.
   636  	TableLockStatePublic
   637  )
   638  
   639  // String implements fmt.Stringer interface.
   640  func (t TableLockState) String() string {
   641  	switch t {
   642  	case TableLockStatePreLock:
   643  		return "pre-lock"
   644  	case TableLockStatePublic:
   645  		return "public"
   646  	default:
   647  		return "none"
   648  	}
   649  }
   650  
   651  // TableLockType is the type of the table lock.
   652  type TableLockType byte
   653  
   654  const (
   655  	// TableLockNone means this table lock is absent.
   656  	TableLockNone TableLockType = iota
   657  	// TableLockRead means the session with this lock can read the table (but not write it).
   658  	// Multiple sessions can acquire a READ lock for the table at the same time.
   659  	// Other sessions can read the table without explicitly acquiring a READ lock.
   660  	TableLockRead
   661  	// TableLockReadLocal is not supported.
   662  	TableLockReadLocal
   663  	// TableLockReadOnly is used to set a table into read-only status,
   664  	// when the session exits, it will not release its lock automatically.
   665  	TableLockReadOnly
   666  	// TableLockWrite means only the session with this lock has write/read permission.
   667  	// Only the session that holds the lock can access the table. No other session can access it until the lock is released.
   668  	TableLockWrite
   669  	// TableLockWriteLocal means the session with this lock has write/read permission, and the other session still has read permission.
   670  	TableLockWriteLocal
   671  )
   672  
   673  func (t TableLockType) String() string {
   674  	switch t {
   675  	case TableLockNone:
   676  		return "NONE"
   677  	case TableLockRead:
   678  		return "READ"
   679  	case TableLockReadLocal:
   680  		return "READ LOCAL"
   681  	case TableLockReadOnly:
   682  		return "READ ONLY"
   683  	case TableLockWriteLocal:
   684  		return "WRITE LOCAL"
   685  	case TableLockWrite:
   686  		return "WRITE"
   687  	}
   688  	return ""
   689  }
   690  
   691  // TiFlashReplicaInfo means the flash replica info.
   692  type TiFlashReplicaInfo struct {
   693  	Count                 uint64
   694  	LocationLabels        []string
   695  	Available             bool
   696  	AvailablePartitionIDs []int64
   697  }
   698  
   699  // IsPartitionAvailable checks whether the partition table replica was available.
   700  func (tr *TiFlashReplicaInfo) IsPartitionAvailable(pid int64) bool {
   701  	for _, id := range tr.AvailablePartitionIDs {
   702  		if id == pid {
   703  			return true
   704  		}
   705  	}
   706  	return false
   707  }
   708  
   709  // GetPartitionInfo returns the partition information.
   710  func (t *TableInfo) GetPartitionInfo() *PartitionInfo {
   711  	if t.Partition != nil && t.Partition.Enable {
   712  		return t.Partition
   713  	}
   714  	return nil
   715  }
   716  
   717  // GetUpdateTime gets the table's updating time.
   718  func (t *TableInfo) GetUpdateTime() time.Time {
   719  	return TSConvert2Time(t.UpdateTS)
   720  }
   721  
   722  // GetDBID returns the schema ID that is used to create an allocator.
   723  // TODO: Remove it after removing OldSchemaID.
   724  func (t *TableInfo) GetDBID(dbID int64) int64 {
   725  	if t.OldSchemaID != 0 {
   726  		return t.OldSchemaID
   727  	}
   728  	return dbID
   729  }
   730  
   731  // Clone clones TableInfo.
   732  func (t *TableInfo) Clone() *TableInfo {
   733  	nt := *t
   734  	nt.Columns = make([]*ColumnInfo, len(t.Columns))
   735  	nt.Indices = make([]*IndexInfo, len(t.Indices))
   736  	nt.ForeignKeys = make([]*FKInfo, len(t.ForeignKeys))
   737  
   738  	for i := range t.Columns {
   739  		nt.Columns[i] = t.Columns[i].Clone()
   740  	}
   741  
   742  	for i := range t.Indices {
   743  		nt.Indices[i] = t.Indices[i].Clone()
   744  	}
   745  
   746  	for i := range t.ForeignKeys {
   747  		nt.ForeignKeys[i] = t.ForeignKeys[i].Clone()
   748  	}
   749  
   750  	if t.Partition != nil {
   751  		nt.Partition = t.Partition.Clone()
   752  	}
   753  	if t.TTLInfo != nil {
   754  		nt.TTLInfo = t.TTLInfo.Clone()
   755  	}
   756  
   757  	return &nt
   758  }
   759  
   760  // GetPkName will return the pk name if pk exists.
   761  func (t *TableInfo) GetPkName() CIStr {
   762  	for _, colInfo := range t.Columns {
   763  		if mysql.HasPriKeyFlag(colInfo.GetFlag()) {
   764  			return colInfo.Name
   765  		}
   766  	}
   767  	return CIStr{}
   768  }
   769  
   770  // GetPkColInfo gets the ColumnInfo of pk if exists.
   771  // Make sure PkIsHandle checked before call this method.
   772  func (t *TableInfo) GetPkColInfo() *ColumnInfo {
   773  	for _, colInfo := range t.Columns {
   774  		if mysql.HasPriKeyFlag(colInfo.GetFlag()) {
   775  			return colInfo
   776  		}
   777  	}
   778  	return nil
   779  }
   780  
   781  // GetAutoIncrementColInfo gets the ColumnInfo of auto_increment column if exists.
   782  func (t *TableInfo) GetAutoIncrementColInfo() *ColumnInfo {
   783  	for _, colInfo := range t.Columns {
   784  		if mysql.HasAutoIncrementFlag(colInfo.GetFlag()) {
   785  			return colInfo
   786  		}
   787  	}
   788  	return nil
   789  }
   790  
   791  // IsAutoIncColUnsigned checks whether the auto increment column is unsigned.
   792  func (t *TableInfo) IsAutoIncColUnsigned() bool {
   793  	col := t.GetAutoIncrementColInfo()
   794  	if col == nil {
   795  		return false
   796  	}
   797  	return mysql.HasUnsignedFlag(col.GetFlag())
   798  }
   799  
   800  // ContainsAutoRandomBits indicates whether a table contains auto_random column.
   801  func (t *TableInfo) ContainsAutoRandomBits() bool {
   802  	return t.AutoRandomBits != 0
   803  }
   804  
   805  // IsAutoRandomBitColUnsigned indicates whether the auto_random column is unsigned. Make sure the table contains auto_random before calling this method.
   806  func (t *TableInfo) IsAutoRandomBitColUnsigned() bool {
   807  	if !t.PKIsHandle || t.AutoRandomBits == 0 {
   808  		return false
   809  	}
   810  	return mysql.HasUnsignedFlag(t.GetPkColInfo().GetFlag())
   811  }
   812  
   813  // Cols returns the columns of the table in public state.
   814  func (t *TableInfo) Cols() []*ColumnInfo {
   815  	publicColumns := make([]*ColumnInfo, len(t.Columns))
   816  	maxOffset := -1
   817  	for _, col := range t.Columns {
   818  		if col.State != StatePublic {
   819  			continue
   820  		}
   821  		publicColumns[col.Offset] = col
   822  		if maxOffset < col.Offset {
   823  			maxOffset = col.Offset
   824  		}
   825  	}
   826  	return publicColumns[0 : maxOffset+1]
   827  }
   828  
   829  // FindIndexByName finds index by name.
   830  func (t *TableInfo) FindIndexByName(idxName string) *IndexInfo {
   831  	for _, idx := range t.Indices {
   832  		if idx.Name.L == idxName {
   833  			return idx
   834  		}
   835  	}
   836  	return nil
   837  }
   838  
   839  // FindPublicColumnByName finds the public column by name.
   840  func (t *TableInfo) FindPublicColumnByName(colNameL string) *ColumnInfo {
   841  	for _, col := range t.Cols() {
   842  		if col.Name.L == colNameL {
   843  			return col
   844  		}
   845  	}
   846  	return nil
   847  }
   848  
   849  // IsLocked checks whether the table was locked.
   850  func (t *TableInfo) IsLocked() bool {
   851  	return t.Lock != nil && len(t.Lock.Sessions) > 0
   852  }
   853  
   854  // MoveColumnInfo moves a column to another offset. It maintains the offsets of all affects columns and index columns,
   855  func (t *TableInfo) MoveColumnInfo(from, to int) {
   856  	if from == to {
   857  		return
   858  	}
   859  	updatedOffsets := make(map[int]int)
   860  	src := t.Columns[from]
   861  	if from < to {
   862  		for i := from; i < to; i++ {
   863  			t.Columns[i] = t.Columns[i+1]
   864  			t.Columns[i].Offset = i
   865  			updatedOffsets[i+1] = i
   866  		}
   867  	} else if from > to {
   868  		for i := from; i > to; i-- {
   869  			t.Columns[i] = t.Columns[i-1]
   870  			t.Columns[i].Offset = i
   871  			updatedOffsets[i-1] = i
   872  		}
   873  	}
   874  	t.Columns[to] = src
   875  	t.Columns[to].Offset = to
   876  	updatedOffsets[from] = to
   877  	for _, idx := range t.Indices {
   878  		for _, idxCol := range idx.Columns {
   879  			newOffset, ok := updatedOffsets[idxCol.Offset]
   880  			if ok {
   881  				idxCol.Offset = newOffset
   882  			}
   883  		}
   884  	}
   885  }
   886  
   887  // ClearPlacement clears all table and partitions' placement settings
   888  func (t *TableInfo) ClearPlacement() {
   889  	t.PlacementPolicyRef = nil
   890  	if t.Partition != nil {
   891  		for i := range t.Partition.Definitions {
   892  			def := &t.Partition.Definitions[i]
   893  			def.PlacementPolicyRef = nil
   894  		}
   895  	}
   896  }
   897  
   898  // NewExtraHandleColInfo mocks a column info for extra handle column.
   899  func NewExtraHandleColInfo() *ColumnInfo {
   900  	colInfo := &ColumnInfo{
   901  		ID:   ExtraHandleID,
   902  		Name: ExtraHandleName,
   903  	}
   904  
   905  	colInfo.SetFlag(mysql.PriKeyFlag | mysql.NotNullFlag)
   906  	colInfo.SetType(mysql.TypeLonglong)
   907  
   908  	flen, decimal := mysql.GetDefaultFieldLengthAndDecimal(mysql.TypeLonglong)
   909  	colInfo.SetFlen(flen)
   910  	colInfo.SetDecimal(decimal)
   911  
   912  	colInfo.SetCharset(charset.CharsetBin)
   913  	colInfo.SetCollate(charset.CollationBin)
   914  	return colInfo
   915  }
   916  
   917  // NewExtraPartitionIDColInfo mocks a column info for extra partition id column.
   918  func NewExtraPartitionIDColInfo() *ColumnInfo {
   919  	colInfo := &ColumnInfo{
   920  		ID:   ExtraPidColID,
   921  		Name: ExtraPartitionIdName,
   922  	}
   923  	colInfo.SetType(mysql.TypeLonglong)
   924  	flen, decimal := mysql.GetDefaultFieldLengthAndDecimal(mysql.TypeLonglong)
   925  	colInfo.SetFlen(flen)
   926  	colInfo.SetDecimal(decimal)
   927  	colInfo.SetCharset(charset.CharsetBin)
   928  	colInfo.SetCollate(charset.CollationBin)
   929  	return colInfo
   930  }
   931  
   932  // NewExtraPhysTblIDColInfo mocks a column info for extra partition id column.
   933  func NewExtraPhysTblIDColInfo() *ColumnInfo {
   934  	colInfo := &ColumnInfo{
   935  		ID:   ExtraPhysTblID,
   936  		Name: ExtraPhysTblIdName,
   937  	}
   938  	colInfo.SetType(mysql.TypeLonglong)
   939  	flen, decimal := mysql.GetDefaultFieldLengthAndDecimal(mysql.TypeLonglong)
   940  	colInfo.SetFlen(flen)
   941  	colInfo.SetDecimal(decimal)
   942  	colInfo.SetCharset(charset.CharsetBin)
   943  	colInfo.SetCollate(charset.CollationBin)
   944  	return colInfo
   945  }
   946  
   947  // GetPrimaryKey extract the primary key in a table and return `IndexInfo`
   948  // The returned primary key could be explicit or implicit.
   949  // If there is no explicit primary key in table,
   950  // the first UNIQUE INDEX on NOT NULL columns will be the implicit primary key.
   951  // For more information about implicit primary key, see
   952  // https://dev.mysql.com/doc/refman/8.0/en/invisible-indexes.html
   953  func (t *TableInfo) GetPrimaryKey() *IndexInfo {
   954  	var implicitPK *IndexInfo
   955  
   956  	for _, key := range t.Indices {
   957  		if key.Primary {
   958  			// table has explicit primary key
   959  			return key
   960  		}
   961  		// The case index without any columns should never happen, but still do a check here
   962  		if len(key.Columns) == 0 {
   963  			continue
   964  		}
   965  		// find the first unique key with NOT NULL columns
   966  		if implicitPK == nil && key.Unique {
   967  			// ensure all columns in unique key have NOT NULL flag
   968  			allColNotNull := true
   969  			skip := false
   970  			for _, idxCol := range key.Columns {
   971  				col := FindColumnInfo(t.Cols(), idxCol.Name.L)
   972  				// This index has a column in DeleteOnly state,
   973  				// or it is expression index (it defined on a hidden column),
   974  				// it can not be implicit PK, go to next index iterator
   975  				if col == nil || col.Hidden {
   976  					skip = true
   977  					break
   978  				}
   979  				if !mysql.HasNotNullFlag(col.GetFlag()) {
   980  					allColNotNull = false
   981  					break
   982  				}
   983  			}
   984  			if skip {
   985  				continue
   986  			}
   987  			if allColNotNull {
   988  				implicitPK = key
   989  			}
   990  		}
   991  	}
   992  	return implicitPK
   993  }
   994  
   995  // ColumnIsInIndex checks whether c is included in any indices of t.
   996  func (t *TableInfo) ColumnIsInIndex(c *ColumnInfo) bool {
   997  	for _, index := range t.Indices {
   998  		for _, column := range index.Columns {
   999  			if column.Name.L == c.Name.L {
  1000  				return true
  1001  			}
  1002  		}
  1003  	}
  1004  	return false
  1005  }
  1006  
  1007  // HasClusteredIndex checks whether the table has a clustered index.
  1008  func (t *TableInfo) HasClusteredIndex() bool {
  1009  	return t.PKIsHandle || t.IsCommonHandle
  1010  }
  1011  
  1012  // IsView checks if TableInfo is a view.
  1013  func (t *TableInfo) IsView() bool {
  1014  	return t.View != nil
  1015  }
  1016  
  1017  // IsSequence checks if TableInfo is a sequence.
  1018  func (t *TableInfo) IsSequence() bool {
  1019  	return t.Sequence != nil
  1020  }
  1021  
  1022  // IsBaseTable checks to see the table is neither a view or a sequence.
  1023  func (t *TableInfo) IsBaseTable() bool {
  1024  	return t.Sequence == nil && t.View == nil
  1025  }
  1026  
  1027  // ViewAlgorithm is VIEW's SQL ALGORITHM characteristic.
  1028  // See https://dev.mysql.com/doc/refman/5.7/en/view-algorithms.html
  1029  type ViewAlgorithm int
  1030  
  1031  //revive:disable:exported
  1032  const (
  1033  	AlgorithmUndefined ViewAlgorithm = iota
  1034  	AlgorithmMerge
  1035  	AlgorithmTemptable
  1036  )
  1037  
  1038  //revive:enable:exported
  1039  
  1040  func (v *ViewAlgorithm) String() string {
  1041  	switch *v {
  1042  	case AlgorithmMerge:
  1043  		return "MERGE"
  1044  	case AlgorithmTemptable:
  1045  		return "TEMPTABLE"
  1046  	case AlgorithmUndefined:
  1047  		return "UNDEFINED"
  1048  	default:
  1049  		return "UNDEFINED"
  1050  	}
  1051  }
  1052  
  1053  // ViewSecurity is VIEW's SQL SECURITY characteristic.
  1054  // See https://dev.mysql.com/doc/refman/5.7/en/create-view.html
  1055  type ViewSecurity int
  1056  
  1057  //revive:disable:exported
  1058  const (
  1059  	SecurityDefiner ViewSecurity = iota
  1060  	SecurityInvoker
  1061  )
  1062  
  1063  //revive:enable:exported
  1064  
  1065  func (v *ViewSecurity) String() string {
  1066  	switch *v {
  1067  	case SecurityInvoker:
  1068  		return "INVOKER"
  1069  	case SecurityDefiner:
  1070  		return "DEFINER"
  1071  	default:
  1072  		return "DEFINER"
  1073  	}
  1074  }
  1075  
  1076  // ViewCheckOption is VIEW's WITH CHECK OPTION clause part.
  1077  // See https://dev.mysql.com/doc/refman/5.7/en/view-check-option.html
  1078  type ViewCheckOption int
  1079  
  1080  //revive:disable:exported
  1081  const (
  1082  	CheckOptionLocal ViewCheckOption = iota
  1083  	CheckOptionCascaded
  1084  )
  1085  
  1086  //revive:enable:exported
  1087  
  1088  func (v *ViewCheckOption) String() string {
  1089  	switch *v {
  1090  	case CheckOptionLocal:
  1091  		return "LOCAL"
  1092  	case CheckOptionCascaded:
  1093  		return "CASCADED"
  1094  	default:
  1095  		return "CASCADED"
  1096  	}
  1097  }
  1098  
  1099  // ViewInfo provides meta data describing a DB view.
  1100  //
  1101  //revive:disable:exported
  1102  type ViewInfo struct {
  1103  	Algorithm   ViewAlgorithm      `json:"view_algorithm"`
  1104  	Definer     *auth.UserIdentity `json:"view_definer"`
  1105  	Security    ViewSecurity       `json:"view_security"`
  1106  	SelectStmt  string             `json:"view_select"`
  1107  	CheckOption ViewCheckOption    `json:"view_checkoption"`
  1108  	Cols        []CIStr            `json:"view_cols"`
  1109  }
  1110  
  1111  const (
  1112  	DefaultSequenceCacheBool          = true
  1113  	DefaultSequenceCycleBool          = false
  1114  	DefaultSequenceOrderBool          = false
  1115  	DefaultSequenceCacheValue         = int64(1000)
  1116  	DefaultSequenceIncrementValue     = int64(1)
  1117  	DefaultPositiveSequenceStartValue = int64(1)
  1118  	DefaultNegativeSequenceStartValue = int64(-1)
  1119  	DefaultPositiveSequenceMinValue   = int64(1)
  1120  	DefaultPositiveSequenceMaxValue   = int64(9223372036854775806)
  1121  	DefaultNegativeSequenceMaxValue   = int64(-1)
  1122  	DefaultNegativeSequenceMinValue   = int64(-9223372036854775807)
  1123  )
  1124  
  1125  // SequenceInfo provide meta data describing a DB sequence.
  1126  type SequenceInfo struct {
  1127  	Start      int64  `json:"sequence_start"`
  1128  	Cache      bool   `json:"sequence_cache"`
  1129  	Cycle      bool   `json:"sequence_cycle"`
  1130  	MinValue   int64  `json:"sequence_min_value"`
  1131  	MaxValue   int64  `json:"sequence_max_value"`
  1132  	Increment  int64  `json:"sequence_increment"`
  1133  	CacheValue int64  `json:"sequence_cache_value"`
  1134  	Comment    string `json:"sequence_comment"`
  1135  }
  1136  
  1137  //revive:enable:exported
  1138  
  1139  // PartitionType is the type for PartitionInfo
  1140  type PartitionType int
  1141  
  1142  // Partition types.
  1143  const (
  1144  	// Actually non-partitioned, but during DDL keeping the table as
  1145  	// a single partition
  1146  	PartitionTypeNone PartitionType = 0
  1147  
  1148  	PartitionTypeRange      PartitionType = 1
  1149  	PartitionTypeHash       PartitionType = 2
  1150  	PartitionTypeList       PartitionType = 3
  1151  	PartitionTypeKey        PartitionType = 4
  1152  	PartitionTypeSystemTime PartitionType = 5
  1153  )
  1154  
  1155  func (p PartitionType) String() string {
  1156  	switch p {
  1157  	case PartitionTypeRange:
  1158  		return "RANGE"
  1159  	case PartitionTypeHash:
  1160  		return "HASH"
  1161  	case PartitionTypeList:
  1162  		return "LIST"
  1163  	case PartitionTypeKey:
  1164  		return "KEY"
  1165  	case PartitionTypeSystemTime:
  1166  		return "SYSTEM_TIME"
  1167  	case PartitionTypeNone:
  1168  		return "NONE"
  1169  	default:
  1170  		return ""
  1171  	}
  1172  }
  1173  
  1174  // ExchangePartitionInfo provides exchange partition info.
  1175  type ExchangePartitionInfo struct {
  1176  	// It is nt tableID when table which has the info is a partition table, else pt tableID.
  1177  	ExchangePartitionTableID int64 `json:"exchange_partition_id"`
  1178  	ExchangePartitionDefID   int64 `json:"exchange_partition_def_id"`
  1179  	// Deprecated, not used
  1180  	XXXExchangePartitionFlag bool `json:"exchange_partition_flag"`
  1181  }
  1182  
  1183  // PartitionInfo provides table partition info.
  1184  type PartitionInfo struct {
  1185  	Type    PartitionType `json:"type"`
  1186  	Expr    string        `json:"expr"`
  1187  	Columns []CIStr       `json:"columns"`
  1188  
  1189  	// User may already create table with partition but table partition is not
  1190  	// yet supported back then. When Enable is true, write/read need use tid
  1191  	// rather than pid.
  1192  	Enable bool `json:"enable"`
  1193  
  1194  	Definitions []PartitionDefinition `json:"definitions"`
  1195  	// AddingDefinitions is filled when adding partitions that is in the mid state.
  1196  	AddingDefinitions []PartitionDefinition `json:"adding_definitions"`
  1197  	// DroppingDefinitions is filled when dropping/truncating partitions that is in the mid state.
  1198  	DroppingDefinitions []PartitionDefinition `json:"dropping_definitions"`
  1199  	// NewPartitionIDs is filled when truncating partitions that is in the mid state.
  1200  	NewPartitionIDs []int64
  1201  
  1202  	States []PartitionState `json:"states"`
  1203  	Num    uint64           `json:"num"`
  1204  	// Only used during ReorganizePartition so far
  1205  	DDLState SchemaState `json:"ddl_state"`
  1206  	// Set during ALTER TABLE ... if the table id needs to change
  1207  	// like if there is a global index or going between non-partitioned
  1208  	// and partitioned table, to make the data dropping / range delete
  1209  	// optimized.
  1210  	NewTableID int64 `json:"new_table_id"`
  1211  	// Set during ALTER TABLE ... PARTITION BY ...
  1212  	// First as the new partition scheme, then in StateDeleteReorg as the old
  1213  	DDLType    PartitionType `json:"ddl_type"`
  1214  	DDLExpr    string        `json:"ddl_expr"`
  1215  	DDLColumns []CIStr       `json:"ddl_columns"`
  1216  }
  1217  
  1218  // Clone clones itself.
  1219  func (pi *PartitionInfo) Clone() *PartitionInfo {
  1220  	newPi := *pi
  1221  	newPi.Columns = make([]CIStr, len(pi.Columns))
  1222  	copy(newPi.Columns, pi.Columns)
  1223  
  1224  	newPi.Definitions = make([]PartitionDefinition, len(pi.Definitions))
  1225  	for i := range pi.Definitions {
  1226  		newPi.Definitions[i] = pi.Definitions[i].Clone()
  1227  	}
  1228  
  1229  	newPi.AddingDefinitions = make([]PartitionDefinition, len(pi.AddingDefinitions))
  1230  	for i := range pi.AddingDefinitions {
  1231  		newPi.AddingDefinitions[i] = pi.AddingDefinitions[i].Clone()
  1232  	}
  1233  
  1234  	newPi.DroppingDefinitions = make([]PartitionDefinition, len(pi.DroppingDefinitions))
  1235  	for i := range pi.DroppingDefinitions {
  1236  		newPi.DroppingDefinitions[i] = pi.DroppingDefinitions[i].Clone()
  1237  	}
  1238  
  1239  	return &newPi
  1240  }
  1241  
  1242  // GetNameByID gets the partition name by ID.
  1243  func (pi *PartitionInfo) GetNameByID(id int64) string {
  1244  	definitions := pi.Definitions
  1245  	// do not convert this loop to `for _, def := range definitions`.
  1246  	// see https://github.com/pingcap/parser/pull/1072 for the benchmark.
  1247  	for i := range definitions {
  1248  		if id == definitions[i].ID {
  1249  			return definitions[i].Name.O
  1250  		}
  1251  	}
  1252  	return ""
  1253  }
  1254  
  1255  // GetStateByID gets the partition state by ID.
  1256  func (pi *PartitionInfo) GetStateByID(id int64) SchemaState {
  1257  	for _, pstate := range pi.States {
  1258  		if pstate.ID == id {
  1259  			return pstate.State
  1260  		}
  1261  	}
  1262  	return StatePublic
  1263  }
  1264  
  1265  // SetStateByID sets the state of the partition by ID.
  1266  func (pi *PartitionInfo) SetStateByID(id int64, state SchemaState) {
  1267  	newState := PartitionState{ID: id, State: state}
  1268  	for i, pstate := range pi.States {
  1269  		if pstate.ID == id {
  1270  			pi.States[i] = newState
  1271  			return
  1272  		}
  1273  	}
  1274  	if pi.States == nil {
  1275  		pi.States = make([]PartitionState, 0, 1)
  1276  	}
  1277  	pi.States = append(pi.States, newState)
  1278  }
  1279  
  1280  // GCPartitionStates cleans up the partition state.
  1281  func (pi *PartitionInfo) GCPartitionStates() {
  1282  	if len(pi.States) < 1 {
  1283  		return
  1284  	}
  1285  	newStates := make([]PartitionState, 0, len(pi.Definitions))
  1286  	for _, state := range pi.States {
  1287  		found := false
  1288  		for _, def := range pi.Definitions {
  1289  			if def.ID == state.ID {
  1290  				found = true
  1291  				break
  1292  			}
  1293  		}
  1294  		if found {
  1295  			newStates = append(newStates, state)
  1296  		}
  1297  	}
  1298  	pi.States = newStates
  1299  }
  1300  
  1301  // HasTruncatingPartitionID checks whether the pid is truncating.
  1302  func (pi *PartitionInfo) HasTruncatingPartitionID(pid int64) bool {
  1303  	for i := range pi.NewPartitionIDs {
  1304  		if pi.NewPartitionIDs[i] == pid {
  1305  			return true
  1306  		}
  1307  	}
  1308  	return false
  1309  }
  1310  
  1311  // PartitionState is the state of the partition.
  1312  type PartitionState struct {
  1313  	ID    int64       `json:"id"`
  1314  	State SchemaState `json:"state"`
  1315  }
  1316  
  1317  // PartitionDefinition defines a single partition.
  1318  type PartitionDefinition struct {
  1319  	ID                 int64          `json:"id"`
  1320  	Name               CIStr          `json:"name"`
  1321  	LessThan           []string       `json:"less_than"`
  1322  	InValues           [][]string     `json:"in_values"`
  1323  	PlacementPolicyRef *PolicyRefInfo `json:"policy_ref_info"`
  1324  	Comment            string         `json:"comment,omitempty"`
  1325  }
  1326  
  1327  // Clone clones ConstraintInfo.
  1328  func (ci *PartitionDefinition) Clone() PartitionDefinition {
  1329  	nci := *ci
  1330  	nci.LessThan = make([]string, len(ci.LessThan))
  1331  	copy(nci.LessThan, ci.LessThan)
  1332  	return nci
  1333  }
  1334  
  1335  const emptyPartitionDefinitionSize = int64(unsafe.Sizeof(PartitionState{}))
  1336  
  1337  // MemoryUsage return the memory usage of PartitionDefinition
  1338  func (ci *PartitionDefinition) MemoryUsage() (sum int64) {
  1339  	if ci == nil {
  1340  		return
  1341  	}
  1342  
  1343  	sum = emptyPartitionDefinitionSize + ci.Name.MemoryUsage()
  1344  	if ci.PlacementPolicyRef != nil {
  1345  		sum += int64(unsafe.Sizeof(ci.PlacementPolicyRef.ID)) + ci.PlacementPolicyRef.Name.MemoryUsage()
  1346  	}
  1347  
  1348  	for _, str := range ci.LessThan {
  1349  		sum += int64(len(str))
  1350  	}
  1351  	for _, strs := range ci.InValues {
  1352  		for _, str := range strs {
  1353  			sum += int64(len(str))
  1354  		}
  1355  	}
  1356  	return
  1357  }
  1358  
  1359  // FindPartitionDefinitionByName finds PartitionDefinition by name.
  1360  func (pi *PartitionInfo) FindPartitionDefinitionByName(partitionDefinitionName string) int {
  1361  	lowConstrName := strings.ToLower(partitionDefinitionName)
  1362  	definitions := pi.Definitions
  1363  	for i := range definitions {
  1364  		if definitions[i].Name.L == lowConstrName {
  1365  			return i
  1366  		}
  1367  	}
  1368  	return -1
  1369  }
  1370  
  1371  // GetPartitionIDByName gets the partition ID by name.
  1372  func (pi *PartitionInfo) GetPartitionIDByName(partitionDefinitionName string) int64 {
  1373  	lowConstrName := strings.ToLower(partitionDefinitionName)
  1374  	for _, definition := range pi.Definitions {
  1375  		if definition.Name.L == lowConstrName {
  1376  			return definition.ID
  1377  		}
  1378  	}
  1379  	return -1
  1380  }
  1381  
  1382  // IndexColumn provides index column info.
  1383  type IndexColumn struct {
  1384  	Name   CIStr `json:"name"`   // Index name
  1385  	Offset int   `json:"offset"` // Index offset
  1386  	// Length of prefix when using column prefix
  1387  	// for indexing;
  1388  	// UnspecifedLength if not using prefix indexing
  1389  	Length int `json:"length"`
  1390  }
  1391  
  1392  // Clone clones IndexColumn.
  1393  func (i *IndexColumn) Clone() *IndexColumn {
  1394  	ni := *i
  1395  	return &ni
  1396  }
  1397  
  1398  // PrimaryKeyType is the type of primary key.
  1399  // Available values are "clustered", "nonclustered", and ""(default).
  1400  type PrimaryKeyType int8
  1401  
  1402  func (p PrimaryKeyType) String() string {
  1403  	switch p {
  1404  	case PrimaryKeyTypeClustered:
  1405  		return "CLUSTERED"
  1406  	case PrimaryKeyTypeNonClustered:
  1407  		return "NONCLUSTERED"
  1408  	default:
  1409  		return ""
  1410  	}
  1411  }
  1412  
  1413  //revive:disable:exported
  1414  const (
  1415  	PrimaryKeyTypeDefault PrimaryKeyType = iota
  1416  	PrimaryKeyTypeClustered
  1417  	PrimaryKeyTypeNonClustered
  1418  )
  1419  
  1420  //revive:enable:exported
  1421  
  1422  // IndexType is the type of index
  1423  type IndexType int
  1424  
  1425  // String implements Stringer interface.
  1426  func (t IndexType) String() string {
  1427  	switch t {
  1428  	case IndexTypeBtree:
  1429  		return "BTREE"
  1430  	case IndexTypeHash:
  1431  		return "HASH"
  1432  	case IndexTypeRtree:
  1433  		return "RTREE"
  1434  	case IndexTypeHypo:
  1435  		return "HYPO"
  1436  	default:
  1437  		return ""
  1438  	}
  1439  }
  1440  
  1441  // IndexTypes
  1442  const (
  1443  	IndexTypeInvalid IndexType = iota
  1444  	IndexTypeBtree
  1445  	IndexTypeHash
  1446  	IndexTypeRtree
  1447  	IndexTypeHypo
  1448  )
  1449  
  1450  // IndexInfo provides meta data describing a DB index.
  1451  // It corresponds to the statement `CREATE INDEX Name ON Table (Column);`
  1452  // See https://dev.mysql.com/doc/refman/5.7/en/create-index.html
  1453  type IndexInfo struct {
  1454  	ID            int64          `json:"id"`
  1455  	Name          CIStr          `json:"idx_name"` // Index name.
  1456  	Table         CIStr          `json:"tbl_name"` // Table name.
  1457  	Columns       []*IndexColumn `json:"idx_cols"` // Index columns.
  1458  	State         SchemaState    `json:"state"`
  1459  	BackfillState BackfillState  `json:"backfill_state"`
  1460  	Comment       string         `json:"comment"`      // Comment
  1461  	Tp            IndexType      `json:"index_type"`   // Index type: Btree, Hash or Rtree
  1462  	Unique        bool           `json:"is_unique"`    // Whether the index is unique.
  1463  	Primary       bool           `json:"is_primary"`   // Whether the index is primary key.
  1464  	Invisible     bool           `json:"is_invisible"` // Whether the index is invisible.
  1465  	Global        bool           `json:"is_global"`    // Whether the index is global.
  1466  	MVIndex       bool           `json:"mv_index"`     // Whether the index is multivalued index.
  1467  }
  1468  
  1469  // Clone clones IndexInfo.
  1470  func (index *IndexInfo) Clone() *IndexInfo {
  1471  	if index == nil {
  1472  		return nil
  1473  	}
  1474  	ni := *index
  1475  	ni.Columns = make([]*IndexColumn, len(index.Columns))
  1476  	for i := range index.Columns {
  1477  		ni.Columns[i] = index.Columns[i].Clone()
  1478  	}
  1479  	return &ni
  1480  }
  1481  
  1482  // HasPrefixIndex returns whether any columns of this index uses prefix length.
  1483  func (index *IndexInfo) HasPrefixIndex() bool {
  1484  	for _, ic := range index.Columns {
  1485  		if ic.Length != types.UnspecifiedLength {
  1486  			return true
  1487  		}
  1488  	}
  1489  	return false
  1490  }
  1491  
  1492  // HasColumnInIndexColumns checks whether the index contains the column with the specified ID.
  1493  func (index *IndexInfo) HasColumnInIndexColumns(tblInfo *TableInfo, colID int64) bool {
  1494  	for _, ic := range index.Columns {
  1495  		if tblInfo.Columns[ic.Offset].ID == colID {
  1496  			return true
  1497  		}
  1498  	}
  1499  	return false
  1500  }
  1501  
  1502  // FindColumnByName finds the index column with the specified name.
  1503  func (index *IndexInfo) FindColumnByName(nameL string) *IndexColumn {
  1504  	_, ret := FindIndexColumnByName(index.Columns, nameL)
  1505  	return ret
  1506  }
  1507  
  1508  // IsPublic checks if the index state is public
  1509  func (index *IndexInfo) IsPublic() bool {
  1510  	return index.State == StatePublic
  1511  }
  1512  
  1513  // FindIndexColumnByName finds IndexColumn by name. When IndexColumn is not found, returns (-1, nil).
  1514  func FindIndexColumnByName(indexCols []*IndexColumn, nameL string) (int, *IndexColumn) {
  1515  	for i, ic := range indexCols {
  1516  		if ic.Name.L == nameL {
  1517  			return i, ic
  1518  		}
  1519  	}
  1520  	return -1, nil
  1521  }
  1522  
  1523  // ConstraintInfo provides meta data describing check-expression constraint.
  1524  type ConstraintInfo struct {
  1525  	ID             int64       `json:"id"`
  1526  	Name           CIStr       `json:"constraint_name"`
  1527  	Table          CIStr       `json:"tbl_name"`        // Table name.
  1528  	ConstraintCols []CIStr     `json:"constraint_cols"` // Depended column names.
  1529  	Enforced       bool        `json:"enforced"`
  1530  	InColumn       bool        `json:"in_column"` // Indicate whether the constraint is column type check.
  1531  	ExprString     string      `json:"expr_string"`
  1532  	State          SchemaState `json:"state"`
  1533  }
  1534  
  1535  // Clone clones ConstraintInfo.
  1536  func (ci *ConstraintInfo) Clone() *ConstraintInfo {
  1537  	nci := *ci
  1538  
  1539  	nci.ConstraintCols = make([]CIStr, len(ci.ConstraintCols))
  1540  	copy(nci.ConstraintCols, ci.ConstraintCols)
  1541  	return &nci
  1542  }
  1543  
  1544  // FindConstraintInfoByName finds constraintInfo by name.
  1545  func (t *TableInfo) FindConstraintInfoByName(constrName string) *ConstraintInfo {
  1546  	lowConstrName := strings.ToLower(constrName)
  1547  	for _, chk := range t.Constraints {
  1548  		if chk.Name.L == lowConstrName {
  1549  			return chk
  1550  		}
  1551  	}
  1552  	return nil
  1553  }
  1554  
  1555  // FindIndexNameByID finds index name by id.
  1556  func (t *TableInfo) FindIndexNameByID(id int64) string {
  1557  	indexInfo := FindIndexInfoByID(t.Indices, id)
  1558  	if indexInfo != nil {
  1559  		return indexInfo.Name.L
  1560  	}
  1561  	return ""
  1562  }
  1563  
  1564  // FindColumnNameByID finds column name by id.
  1565  func (t *TableInfo) FindColumnNameByID(id int64) string {
  1566  	colInfo := FindColumnInfoByID(t.Columns, id)
  1567  	if colInfo != nil {
  1568  		return colInfo.Name.L
  1569  	}
  1570  	return ""
  1571  }
  1572  
  1573  // FKInfo provides meta data describing a foreign key constraint.
  1574  type FKInfo struct {
  1575  	ID        int64       `json:"id"`
  1576  	Name      CIStr       `json:"fk_name"`
  1577  	RefSchema CIStr       `json:"ref_schema"`
  1578  	RefTable  CIStr       `json:"ref_table"`
  1579  	RefCols   []CIStr     `json:"ref_cols"`
  1580  	Cols      []CIStr     `json:"cols"`
  1581  	OnDelete  int         `json:"on_delete"`
  1582  	OnUpdate  int         `json:"on_update"`
  1583  	State     SchemaState `json:"state"`
  1584  	Version   int         `json:"version"`
  1585  }
  1586  
  1587  const (
  1588  	// FKVersion0 indicate the FKInfo version is 0.
  1589  	// In FKVersion0, TiDB only supported syntax of foreign key, but the foreign key constraint doesn't take effect.
  1590  	FKVersion0 = 0
  1591  	// FKVersion1 indicate the FKInfo version is 1.
  1592  	// In FKVersion1, TiDB supports the foreign key constraint.
  1593  	FKVersion1 = 1
  1594  )
  1595  
  1596  // ReferredFKInfo provides the cited foreign key in the child table.
  1597  type ReferredFKInfo struct {
  1598  	Cols        []CIStr `json:"cols"`
  1599  	ChildSchema CIStr   `json:"child_schema"`
  1600  	ChildTable  CIStr   `json:"child_table"`
  1601  	ChildFKName CIStr   `json:"child_fk_name"`
  1602  }
  1603  
  1604  // ReferOptionType is the type for refer options.
  1605  type ReferOptionType int
  1606  
  1607  // Refer option types.
  1608  const (
  1609  	ReferOptionNoOption ReferOptionType = iota
  1610  	ReferOptionRestrict
  1611  	ReferOptionCascade
  1612  	ReferOptionSetNull
  1613  	ReferOptionNoAction
  1614  	ReferOptionSetDefault
  1615  )
  1616  
  1617  // String implements fmt.Stringer interface.
  1618  func (r ReferOptionType) String() string {
  1619  	switch r {
  1620  	case ReferOptionRestrict:
  1621  		return "RESTRICT"
  1622  	case ReferOptionCascade:
  1623  		return "CASCADE"
  1624  	case ReferOptionSetNull:
  1625  		return "SET NULL"
  1626  	case ReferOptionNoAction:
  1627  		return "NO ACTION"
  1628  	case ReferOptionSetDefault:
  1629  		return "SET DEFAULT"
  1630  	}
  1631  	return ""
  1632  }
  1633  
  1634  func (fk *FKInfo) String(db, tb string) string {
  1635  	buf := bytes.Buffer{}
  1636  	buf.WriteString("`" + db + "`.`")
  1637  	buf.WriteString(tb + "`, CONSTRAINT `")
  1638  	buf.WriteString(fk.Name.O + "` FOREIGN KEY (")
  1639  	for i, col := range fk.Cols {
  1640  		if i > 0 {
  1641  			buf.WriteString(", ")
  1642  		}
  1643  		buf.WriteString("`" + col.O + "`")
  1644  	}
  1645  	buf.WriteString(") REFERENCES `")
  1646  	if fk.RefSchema.L != db {
  1647  		buf.WriteString(fk.RefSchema.L)
  1648  		buf.WriteString("`.`")
  1649  	}
  1650  	buf.WriteString(fk.RefTable.L)
  1651  	buf.WriteString("` (")
  1652  	for i, col := range fk.RefCols {
  1653  		if i > 0 {
  1654  			buf.WriteString(", ")
  1655  		}
  1656  		buf.WriteString("`" + col.O + "`")
  1657  	}
  1658  	buf.WriteString(")")
  1659  	if onDelete := ReferOptionType(fk.OnDelete); onDelete != ReferOptionNoOption {
  1660  		buf.WriteString(" ON DELETE ")
  1661  		buf.WriteString(onDelete.String())
  1662  	}
  1663  	if onUpdate := ReferOptionType(fk.OnUpdate); onUpdate != ReferOptionNoOption {
  1664  		buf.WriteString(" ON UPDATE ")
  1665  		buf.WriteString(onUpdate.String())
  1666  	}
  1667  	return buf.String()
  1668  }
  1669  
  1670  // Clone clones FKInfo.
  1671  func (fk *FKInfo) Clone() *FKInfo {
  1672  	nfk := *fk
  1673  
  1674  	nfk.RefCols = make([]CIStr, len(fk.RefCols))
  1675  	nfk.Cols = make([]CIStr, len(fk.Cols))
  1676  	copy(nfk.RefCols, fk.RefCols)
  1677  	copy(nfk.Cols, fk.Cols)
  1678  
  1679  	return &nfk
  1680  }
  1681  
  1682  // DBInfo provides meta data describing a DB.
  1683  type DBInfo struct {
  1684  	ID                 int64          `json:"id"`      // Database ID
  1685  	Name               CIStr          `json:"db_name"` // DB name.
  1686  	Charset            string         `json:"charset"`
  1687  	Collate            string         `json:"collate"`
  1688  	Tables             []*TableInfo   `json:"-"` // Tables in the DB.
  1689  	State              SchemaState    `json:"state"`
  1690  	PlacementPolicyRef *PolicyRefInfo `json:"policy_ref_info"`
  1691  }
  1692  
  1693  // Clone clones DBInfo.
  1694  func (db *DBInfo) Clone() *DBInfo {
  1695  	newInfo := *db
  1696  	newInfo.Tables = make([]*TableInfo, len(db.Tables))
  1697  	for i := range db.Tables {
  1698  		newInfo.Tables[i] = db.Tables[i].Clone()
  1699  	}
  1700  	return &newInfo
  1701  }
  1702  
  1703  // Copy shallow copies DBInfo.
  1704  func (db *DBInfo) Copy() *DBInfo {
  1705  	newInfo := *db
  1706  	newInfo.Tables = make([]*TableInfo, len(db.Tables))
  1707  	copy(newInfo.Tables, db.Tables)
  1708  	return &newInfo
  1709  }
  1710  
  1711  // LessDBInfo is used for sorting DBInfo by DBInfo.Name.
  1712  func LessDBInfo(a *DBInfo, b *DBInfo) int {
  1713  	return cmp.Compare(a.Name.L, b.Name.L)
  1714  }
  1715  
  1716  // CIStr is case insensitive string.
  1717  type CIStr struct {
  1718  	O string `json:"O"` // Original string.
  1719  	L string `json:"L"` // Lower case string.
  1720  }
  1721  
  1722  // String implements fmt.Stringer interface.
  1723  func (cis CIStr) String() string {
  1724  	return cis.O
  1725  }
  1726  
  1727  // NewCIStr creates a new CIStr.
  1728  func NewCIStr(s string) (cs CIStr) {
  1729  	cs.O = s
  1730  	cs.L = strings.ToLower(s)
  1731  	return
  1732  }
  1733  
  1734  // UnmarshalJSON implements the user defined unmarshal method.
  1735  // CIStr can be unmarshaled from a single string, so PartitionDefinition.Name
  1736  // in this change https://github.com/pingcap/tidb/pull/6460/files would be
  1737  // compatible during TiDB upgrading.
  1738  func (cis *CIStr) UnmarshalJSON(b []byte) error {
  1739  	type T CIStr
  1740  	if err := json.Unmarshal(b, (*T)(cis)); err == nil {
  1741  		return nil
  1742  	}
  1743  
  1744  	// Unmarshal CIStr from a single string.
  1745  	err := json.Unmarshal(b, &cis.O)
  1746  	if err != nil {
  1747  		return errors.Trace(err)
  1748  	}
  1749  	cis.L = strings.ToLower(cis.O)
  1750  	return nil
  1751  }
  1752  
  1753  // MemoryUsage return the memory usage of CIStr
  1754  func (cis *CIStr) MemoryUsage() (sum int64) {
  1755  	if cis == nil {
  1756  		return
  1757  	}
  1758  
  1759  	return int64(unsafe.Sizeof(cis.O))*2 + int64(len(cis.O)+len(cis.L))
  1760  }
  1761  
  1762  // TableItemID is composed by table ID and column/index ID
  1763  type TableItemID struct {
  1764  	TableID int64
  1765  	ID      int64
  1766  	IsIndex bool
  1767  }
  1768  
  1769  // PolicyRefInfo is the struct to refer the placement policy.
  1770  type PolicyRefInfo struct {
  1771  	ID   int64 `json:"id"`
  1772  	Name CIStr `json:"name"`
  1773  }
  1774  
  1775  // PlacementSettings is the settings of the placement
  1776  type PlacementSettings struct {
  1777  	PrimaryRegion       string `json:"primary_region"`
  1778  	Regions             string `json:"regions"`
  1779  	Learners            uint64 `json:"learners"`
  1780  	Followers           uint64 `json:"followers"`
  1781  	Voters              uint64 `json:"voters"`
  1782  	Schedule            string `json:"schedule"`
  1783  	Constraints         string `json:"constraints"`
  1784  	LeaderConstraints   string `json:"leader_constraints"`
  1785  	LearnerConstraints  string `json:"learner_constraints"`
  1786  	FollowerConstraints string `json:"follower_constraints"`
  1787  	VoterConstraints    string `json:"voter_constraints"`
  1788  	SurvivalPreferences string `json:"survival_preferences"`
  1789  }
  1790  
  1791  // PolicyInfo is the struct to store the placement policy.
  1792  type PolicyInfo struct {
  1793  	*PlacementSettings
  1794  	ID    int64       `json:"id"`
  1795  	Name  CIStr       `json:"name"`
  1796  	State SchemaState `json:"state"`
  1797  }
  1798  
  1799  // Clone clones PolicyInfo.
  1800  func (p *PolicyInfo) Clone() *PolicyInfo {
  1801  	cloned := *p
  1802  	cloned.PlacementSettings = p.PlacementSettings.Clone()
  1803  	return &cloned
  1804  }
  1805  
  1806  // DefaultJobInterval sets the default interval between TTL jobs
  1807  const DefaultJobInterval = time.Hour
  1808  
  1809  // TTLInfo records the TTL config
  1810  type TTLInfo struct {
  1811  	ColumnName      CIStr  `json:"column"`
  1812  	IntervalExprStr string `json:"interval_expr"`
  1813  	// `IntervalTimeUnit` is actually ast.TimeUnitType. Use `int` to avoid cycle dependency
  1814  	IntervalTimeUnit int  `json:"interval_time_unit"`
  1815  	Enable           bool `json:"enable"`
  1816  	// JobInterval is the interval between two TTL scan jobs.
  1817  	// It's suggested to get a duration with `(*TTLInfo).GetJobInterval`
  1818  	JobInterval string `json:"job_interval"`
  1819  }
  1820  
  1821  // Clone clones TTLInfo
  1822  func (t *TTLInfo) Clone() *TTLInfo {
  1823  	cloned := *t
  1824  	return &cloned
  1825  }
  1826  
  1827  // GetJobInterval parses the job interval and return
  1828  // if the job interval is an empty string, the "1h" will be returned, to keep compatible with 6.5 (in which
  1829  // TTL_JOB_INTERVAL attribute doesn't exist)
  1830  // Didn't set TTL_JOB_INTERVAL during upgrade and bootstrap because setting default value here is much simpler
  1831  // and could avoid bugs blocking users from upgrading or bootstrapping the cluster.
  1832  func (t *TTLInfo) GetJobInterval() (time.Duration, error) {
  1833  	if len(t.JobInterval) == 0 {
  1834  		return DefaultJobInterval, nil
  1835  	}
  1836  
  1837  	return duration.ParseDuration(t.JobInterval)
  1838  }
  1839  
  1840  func writeSettingItemToBuilder(sb *strings.Builder, item string, separatorFns ...func()) {
  1841  	if sb.Len() != 0 {
  1842  		for _, fn := range separatorFns {
  1843  			fn()
  1844  		}
  1845  		if len(separatorFns) == 0 {
  1846  			sb.WriteString(" ")
  1847  		}
  1848  	}
  1849  	sb.WriteString(item)
  1850  }
  1851  func writeSettingStringToBuilder(sb *strings.Builder, item string, value string, separatorFns ...func()) {
  1852  	writeSettingItemToBuilder(sb, fmt.Sprintf("%s=\"%s\"", item, strings.ReplaceAll(value, "\"", "\\\"")), separatorFns...)
  1853  }
  1854  func writeSettingIntegerToBuilder(sb *strings.Builder, item string, value uint64, separatorFns ...func()) {
  1855  	writeSettingItemToBuilder(sb, fmt.Sprintf("%s=%d", item, value), separatorFns...)
  1856  }
  1857  
  1858  func writeSettingDurationToBuilder(sb *strings.Builder, item string, dur time.Duration, separatorFns ...func()) {
  1859  	writeSettingStringToBuilder(sb, item, dur.String(), separatorFns...)
  1860  }
  1861  
  1862  func (p *PlacementSettings) String() string {
  1863  	sb := new(strings.Builder)
  1864  	if len(p.PrimaryRegion) > 0 {
  1865  		writeSettingStringToBuilder(sb, "PRIMARY_REGION", p.PrimaryRegion)
  1866  	}
  1867  
  1868  	if len(p.Regions) > 0 {
  1869  		writeSettingStringToBuilder(sb, "REGIONS", p.Regions)
  1870  	}
  1871  
  1872  	if len(p.Schedule) > 0 {
  1873  		writeSettingStringToBuilder(sb, "SCHEDULE", p.Schedule)
  1874  	}
  1875  
  1876  	if len(p.Constraints) > 0 {
  1877  		writeSettingStringToBuilder(sb, "CONSTRAINTS", p.Constraints)
  1878  	}
  1879  
  1880  	if len(p.LeaderConstraints) > 0 {
  1881  		writeSettingStringToBuilder(sb, "LEADER_CONSTRAINTS", p.LeaderConstraints)
  1882  	}
  1883  
  1884  	if p.Voters > 0 {
  1885  		writeSettingIntegerToBuilder(sb, "VOTERS", p.Voters)
  1886  	}
  1887  
  1888  	if len(p.VoterConstraints) > 0 {
  1889  		writeSettingStringToBuilder(sb, "VOTER_CONSTRAINTS", p.VoterConstraints)
  1890  	}
  1891  
  1892  	if p.Followers > 0 {
  1893  		writeSettingIntegerToBuilder(sb, "FOLLOWERS", p.Followers)
  1894  	}
  1895  
  1896  	if len(p.FollowerConstraints) > 0 {
  1897  		writeSettingStringToBuilder(sb, "FOLLOWER_CONSTRAINTS", p.FollowerConstraints)
  1898  	}
  1899  
  1900  	if p.Learners > 0 {
  1901  		writeSettingIntegerToBuilder(sb, "LEARNERS", p.Learners)
  1902  	}
  1903  
  1904  	if len(p.LearnerConstraints) > 0 {
  1905  		writeSettingStringToBuilder(sb, "LEARNER_CONSTRAINTS", p.LearnerConstraints)
  1906  	}
  1907  
  1908  	return sb.String()
  1909  }
  1910  
  1911  // Clone clones the placement settings.
  1912  func (p *PlacementSettings) Clone() *PlacementSettings {
  1913  	cloned := *p
  1914  	return &cloned
  1915  }
  1916  
  1917  // RunawayActionType is the type of runaway action.
  1918  type RunawayActionType int32
  1919  
  1920  //revive:disable:exported
  1921  const (
  1922  	RunawayActionNone RunawayActionType = iota
  1923  	RunawayActionDryRun
  1924  	RunawayActionCooldown
  1925  	RunawayActionKill
  1926  )
  1927  
  1928  // RunawayWatchType is the type of runaway watch.
  1929  type RunawayWatchType int32
  1930  
  1931  //revive:disable:exported
  1932  const (
  1933  	WatchNone RunawayWatchType = iota
  1934  	WatchExact
  1935  	WatchSimilar
  1936  	WatchPlan
  1937  )
  1938  
  1939  func (t RunawayWatchType) String() string {
  1940  	switch t {
  1941  	case WatchExact:
  1942  		return "EXACT"
  1943  	case WatchSimilar:
  1944  		return "SIMILAR"
  1945  	case WatchPlan:
  1946  		return "PLAN"
  1947  	default:
  1948  		return "NONE"
  1949  	}
  1950  }
  1951  
  1952  // RunawayOptionType is the runaway's option type.
  1953  type RunawayOptionType int
  1954  
  1955  //revive:disable:exported
  1956  const (
  1957  	RunawayRule RunawayOptionType = iota
  1958  	RunawayAction
  1959  	RunawayWatch
  1960  )
  1961  
  1962  func (t RunawayActionType) String() string {
  1963  	switch t {
  1964  	case RunawayActionDryRun:
  1965  		return "DRYRUN"
  1966  	case RunawayActionCooldown:
  1967  		return "COOLDOWN"
  1968  	case RunawayActionKill:
  1969  		return "KILL"
  1970  	default:
  1971  		return "DRYRUN"
  1972  	}
  1973  }
  1974  
  1975  // ResourceGroupRefInfo is the struct to refer the resource group.
  1976  type ResourceGroupRefInfo struct {
  1977  	ID   int64 `json:"id"`
  1978  	Name CIStr `json:"name"`
  1979  }
  1980  
  1981  // ResourceGroupRunawaySettings is the runaway settings of the resource group
  1982  type ResourceGroupRunawaySettings struct {
  1983  	ExecElapsedTimeMs uint64            `json:"exec_elapsed_time_ms"`
  1984  	Action            RunawayActionType `json:"action"`
  1985  	WatchType         RunawayWatchType  `json:"watch_type"`
  1986  	WatchDurationMs   int64             `json:"watch_duration_ms"`
  1987  }
  1988  
  1989  type ResourceGroupBackgroundSettings struct {
  1990  	JobTypes []string `json:"job_types"`
  1991  }
  1992  
  1993  // ResourceGroupSettings is the settings of the resource group
  1994  type ResourceGroupSettings struct {
  1995  	RURate           uint64                           `json:"ru_per_sec"`
  1996  	Priority         uint64                           `json:"priority"`
  1997  	CPULimiter       string                           `json:"cpu_limit"`
  1998  	IOReadBandwidth  string                           `json:"io_read_bandwidth"`
  1999  	IOWriteBandwidth string                           `json:"io_write_bandwidth"`
  2000  	BurstLimit       int64                            `json:"burst_limit"`
  2001  	Runaway          *ResourceGroupRunawaySettings    `json:"runaway"`
  2002  	Background       *ResourceGroupBackgroundSettings `json:"background"`
  2003  }
  2004  
  2005  // NewResourceGroupSettings creates a new ResourceGroupSettings.
  2006  func NewResourceGroupSettings() *ResourceGroupSettings {
  2007  	return &ResourceGroupSettings{
  2008  		RURate:           0,
  2009  		Priority:         MediumPriorityValue,
  2010  		CPULimiter:       "",
  2011  		IOReadBandwidth:  "",
  2012  		IOWriteBandwidth: "",
  2013  		BurstLimit:       0,
  2014  	}
  2015  }
  2016  
  2017  // PriorityValueToName converts the priority value to corresponding name
  2018  func PriorityValueToName(value uint64) string {
  2019  	switch value {
  2020  	case LowPriorityValue:
  2021  		return "LOW"
  2022  	case MediumPriorityValue:
  2023  		return "MEDIUM"
  2024  	case HighPriorityValue:
  2025  		return "HIGH"
  2026  	default:
  2027  		return "MEDIUM"
  2028  	}
  2029  }
  2030  
  2031  //revive:disable:exported
  2032  const (
  2033  	LowPriorityValue    = 1
  2034  	MediumPriorityValue = 8
  2035  	HighPriorityValue   = 16
  2036  )
  2037  
  2038  func (p *ResourceGroupSettings) String() string {
  2039  	sb := new(strings.Builder)
  2040  	separatorFn := func() {
  2041  		sb.WriteString(", ")
  2042  	}
  2043  	if p.RURate != 0 {
  2044  		writeSettingIntegerToBuilder(sb, "RU_PER_SEC", p.RURate, separatorFn)
  2045  	}
  2046  	writeSettingItemToBuilder(sb, "PRIORITY="+PriorityValueToName(p.Priority), separatorFn)
  2047  	if len(p.CPULimiter) > 0 {
  2048  		writeSettingStringToBuilder(sb, "CPU", p.CPULimiter, separatorFn)
  2049  	}
  2050  	if len(p.IOReadBandwidth) > 0 {
  2051  		writeSettingStringToBuilder(sb, "IO_READ_BANDWIDTH", p.IOReadBandwidth, separatorFn)
  2052  	}
  2053  	if len(p.IOWriteBandwidth) > 0 {
  2054  		writeSettingStringToBuilder(sb, "IO_WRITE_BANDWIDTH", p.IOWriteBandwidth, separatorFn)
  2055  	}
  2056  	// Once burst limit is negative, meaning allow burst with unlimit.
  2057  	if p.BurstLimit < 0 {
  2058  		writeSettingItemToBuilder(sb, "BURSTABLE", separatorFn)
  2059  	}
  2060  	if p.Runaway != nil {
  2061  		writeSettingDurationToBuilder(sb, "QUERY_LIMIT=(EXEC_ELAPSED", time.Duration(p.Runaway.ExecElapsedTimeMs)*time.Millisecond, separatorFn)
  2062  		writeSettingItemToBuilder(sb, "ACTION="+p.Runaway.Action.String())
  2063  		if p.Runaway.WatchType != WatchNone {
  2064  			writeSettingItemToBuilder(sb, "WATCH="+p.Runaway.WatchType.String())
  2065  			if p.Runaway.WatchDurationMs > 0 {
  2066  				writeSettingDurationToBuilder(sb, "DURATION", time.Duration(p.Runaway.WatchDurationMs)*time.Millisecond)
  2067  			} else {
  2068  				writeSettingItemToBuilder(sb, "DURATION=UNLIMITED")
  2069  			}
  2070  		}
  2071  		sb.WriteString(")")
  2072  	}
  2073  	if p.Background != nil {
  2074  		fmt.Fprintf(sb, ", BACKGROUND=(TASK_TYPES='%s')", strings.Join(p.Background.JobTypes, ","))
  2075  	}
  2076  
  2077  	return sb.String()
  2078  }
  2079  
  2080  // Adjust adjusts the resource group settings.
  2081  func (p *ResourceGroupSettings) Adjust() {
  2082  	// Curretly we only support ru_per_sec sytanx, so BurstLimit(capicity) is always same as ru_per_sec.
  2083  	if p.BurstLimit == 0 {
  2084  		p.BurstLimit = int64(p.RURate)
  2085  	}
  2086  }
  2087  
  2088  // Clone clones the resource group settings.
  2089  func (p *ResourceGroupSettings) Clone() *ResourceGroupSettings {
  2090  	cloned := *p
  2091  	return &cloned
  2092  }
  2093  
  2094  // ResourceGroupInfo is the struct to store the resource group.
  2095  type ResourceGroupInfo struct {
  2096  	*ResourceGroupSettings
  2097  	ID    int64       `json:"id"`
  2098  	Name  CIStr       `json:"name"`
  2099  	State SchemaState `json:"state"`
  2100  }
  2101  
  2102  // Clone clones the ResourceGroupInfo.
  2103  func (p *ResourceGroupInfo) Clone() *ResourceGroupInfo {
  2104  	cloned := *p
  2105  	cloned.ResourceGroupSettings = p.ResourceGroupSettings.Clone()
  2106  	return &cloned
  2107  }
  2108  
  2109  // StatsOptions is the struct to store the stats options.
  2110  type StatsOptions struct {
  2111  	*StatsWindowSettings
  2112  	AutoRecalc   bool         `json:"auto_recalc"`
  2113  	ColumnChoice ColumnChoice `json:"column_choice"`
  2114  	ColumnList   []CIStr      `json:"column_list"`
  2115  	SampleNum    uint64       `json:"sample_num"`
  2116  	SampleRate   float64      `json:"sample_rate"`
  2117  	Buckets      uint64       `json:"buckets"`
  2118  	TopN         uint64       `json:"topn"`
  2119  	Concurrency  uint         `json:"concurrency"`
  2120  }
  2121  
  2122  // NewStatsOptions creates a new StatsOptions.
  2123  func NewStatsOptions() *StatsOptions {
  2124  	return &StatsOptions{
  2125  		AutoRecalc:   true,
  2126  		ColumnChoice: DefaultChoice,
  2127  		ColumnList:   []CIStr{},
  2128  		SampleNum:    uint64(0),
  2129  		SampleRate:   0.0,
  2130  		Buckets:      uint64(0),
  2131  		TopN:         uint64(0),
  2132  		Concurrency:  uint(0),
  2133  	}
  2134  }
  2135  
  2136  // ColumnChoice is the type of the column choice.
  2137  type ColumnChoice byte
  2138  
  2139  //revive:disable:exported
  2140  const (
  2141  	DefaultChoice ColumnChoice = iota
  2142  	AllColumns
  2143  	PredicateColumns
  2144  	ColumnList
  2145  )
  2146  
  2147  //revive:enable:exported
  2148  
  2149  func (s ColumnChoice) String() string {
  2150  	switch s {
  2151  	case AllColumns:
  2152  		return "ALL"
  2153  	case PredicateColumns:
  2154  		return "PREDICATE"
  2155  	case ColumnList:
  2156  		return "LIST"
  2157  	default:
  2158  		return "DEFAULT"
  2159  	}
  2160  }
  2161  
  2162  // StatsWindowSettings is the settings of the stats window.
  2163  type StatsWindowSettings struct {
  2164  	WindowStart    time.Time        `json:"window_start"`
  2165  	WindowEnd      time.Time        `json:"window_end"`
  2166  	RepeatType     WindowRepeatType `json:"repeat_type"`
  2167  	RepeatInterval uint             `json:"repeat_interval"`
  2168  }
  2169  
  2170  // WindowRepeatType is the type of the window repeat.
  2171  type WindowRepeatType byte
  2172  
  2173  //revive:disable:exported
  2174  const (
  2175  	Never WindowRepeatType = iota
  2176  	Day
  2177  	Week
  2178  	Month
  2179  )
  2180  
  2181  //revive:enable:exported
  2182  
  2183  func (s WindowRepeatType) String() string {
  2184  	switch s {
  2185  	case Never:
  2186  		return "Never"
  2187  	case Day:
  2188  		return "Day"
  2189  	case Week:
  2190  		return "Week"
  2191  	case Month:
  2192  		return "Month"
  2193  	default:
  2194  		return ""
  2195  	}
  2196  }
  2197  
  2198  // TraceInfo is the information for trace.
  2199  type TraceInfo struct {
  2200  	// ConnectionID is the id of the connection
  2201  	ConnectionID uint64 `json:"connection_id"`
  2202  	// SessionAlias is the alias of session
  2203  	SessionAlias string `json:"session_alias"`
  2204  }