github.com/matrixorigin/matrixone@v0.7.0/pkg/vm/engine/tae/catalog/schema.go (about)

     1  // Copyright 2021 Matrix Origin
     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  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package catalog
    16  
    17  import (
    18  	"bytes"
    19  	"encoding/binary"
    20  	"encoding/json"
    21  	"fmt"
    22  	"github.com/matrixorigin/matrixone/pkg/pb/plan"
    23  	"io"
    24  	"math/rand"
    25  	"sort"
    26  	"time"
    27  
    28  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    29  	"github.com/matrixorigin/matrixone/pkg/container/types"
    30  	"github.com/matrixorigin/matrixone/pkg/vm/engine"
    31  
    32  	pkgcatalog "github.com/matrixorigin/matrixone/pkg/catalog"
    33  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/common"
    34  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/containers"
    35  )
    36  
    37  func i82bool(v int8) bool {
    38  	return v == 1
    39  }
    40  
    41  type ColDef struct {
    42  	Name          string
    43  	Idx           int // indicates its position in all coldefs
    44  	Type          types.Type
    45  	Hidden        bool // Hidden Column is generated by compute layer, keep hidden from user
    46  	PhyAddr       bool // PhyAddr Column is generated by tae as rowid
    47  	NullAbility   bool
    48  	AutoIncrement bool
    49  	Primary       bool
    50  	SortIdx       int8 // indicates its position in all sort keys
    51  	SortKey       bool
    52  	Comment       string
    53  	ClusterBy     bool
    54  	Default       []byte
    55  	OnUpdate      []byte
    56  }
    57  
    58  func (def *ColDef) GetName() string     { return def.Name }
    59  func (def *ColDef) GetType() types.Type { return def.Type }
    60  
    61  func (def *ColDef) Nullable() bool        { return def.NullAbility }
    62  func (def *ColDef) IsHidden() bool        { return def.Hidden }
    63  func (def *ColDef) IsPhyAddr() bool       { return def.PhyAddr }
    64  func (def *ColDef) IsPrimary() bool       { return def.Primary }
    65  func (def *ColDef) IsAutoIncrement() bool { return def.AutoIncrement }
    66  func (def *ColDef) IsSortKey() bool       { return def.SortKey }
    67  func (def *ColDef) IsClusterBy() bool     { return def.ClusterBy }
    68  
    69  type SortKey struct {
    70  	Defs      []*ColDef
    71  	search    map[int]int
    72  	isPrimary bool
    73  }
    74  
    75  func NewSortKey() *SortKey {
    76  	return &SortKey{
    77  		Defs:   make([]*ColDef, 0),
    78  		search: make(map[int]int),
    79  	}
    80  }
    81  
    82  func (cpk *SortKey) AddDef(def *ColDef) (ok bool) {
    83  	_, found := cpk.search[def.Idx]
    84  	if found {
    85  		return false
    86  	}
    87  	if def.IsPrimary() {
    88  		cpk.isPrimary = true
    89  	}
    90  	cpk.Defs = append(cpk.Defs, def)
    91  	sort.Slice(cpk.Defs, func(i, j int) bool { return cpk.Defs[i].SortIdx < cpk.Defs[j].SortIdx })
    92  	cpk.search[def.Idx] = int(def.SortIdx)
    93  	return true
    94  }
    95  
    96  func (cpk *SortKey) IsPrimary() bool                { return cpk.isPrimary }
    97  func (cpk *SortKey) Size() int                      { return len(cpk.Defs) }
    98  func (cpk *SortKey) GetDef(pos int) *ColDef         { return cpk.Defs[pos] }
    99  func (cpk *SortKey) HasColumn(idx int) (found bool) { _, found = cpk.search[idx]; return }
   100  func (cpk *SortKey) GetSingleIdx() int              { return cpk.Defs[0].Idx }
   101  
   102  type Schema struct {
   103  	AcInfo           accessInfo
   104  	Name             string
   105  	ColDefs          []*ColDef
   106  	NameIndex        map[string]int
   107  	BlockMaxRows     uint32
   108  	SegmentMaxBlocks uint16
   109  	Comment          string
   110  	Partition        string
   111  	Relkind          string
   112  	Createsql        string
   113  	View             string
   114  	UniqueIndex      string
   115  	SecondaryIndex   string
   116  	Constraint       []byte
   117  
   118  	SortKey    *SortKey
   119  	PhyAddrKey *ColDef
   120  }
   121  
   122  func NewEmptySchema(name string) *Schema {
   123  	return &Schema{
   124  		Name:      name,
   125  		ColDefs:   make([]*ColDef, 0),
   126  		NameIndex: make(map[string]int),
   127  	}
   128  }
   129  
   130  func (s *Schema) Clone() *Schema {
   131  	buf, err := s.Marshal()
   132  	if err != nil {
   133  		panic(err)
   134  	}
   135  	ns := NewEmptySchema(s.Name)
   136  	r := bytes.NewBuffer(buf)
   137  	if _, err = ns.ReadFrom(r); err != nil {
   138  		panic(err)
   139  	}
   140  	return ns
   141  }
   142  
   143  func (s *Schema) HasPK() bool      { return s.SortKey != nil && s.SortKey.IsPrimary() }
   144  func (s *Schema) HasSortKey() bool { return s.SortKey != nil }
   145  
   146  // GetSingleSortKey should be call only if IsSinglePK is checked
   147  func (s *Schema) GetSingleSortKey() *ColDef        { return s.SortKey.Defs[0] }
   148  func (s *Schema) GetSingleSortKeyIdx() int         { return s.SortKey.Defs[0].Idx }
   149  func (s *Schema) GetSingleSortKeyType() types.Type { return s.GetSingleSortKey().Type }
   150  
   151  func (s *Schema) ReadFrom(r io.Reader) (n int64, err error) {
   152  	if err = binary.Read(r, binary.BigEndian, &s.BlockMaxRows); err != nil {
   153  		return
   154  	}
   155  	if err = binary.Read(r, binary.BigEndian, &s.SegmentMaxBlocks); err != nil {
   156  		return
   157  	}
   158  	n = 4 + 4
   159  	var sn int64
   160  	if sn, err = s.AcInfo.ReadFrom(r); err != nil {
   161  		return
   162  	}
   163  	n += sn
   164  	if s.Name, sn, err = common.ReadString(r); err != nil {
   165  		return
   166  	}
   167  	n += sn
   168  	if s.Comment, sn, err = common.ReadString(r); err != nil {
   169  		return
   170  	}
   171  	n += sn
   172  	if s.Partition, sn, err = common.ReadString(r); err != nil {
   173  		return
   174  	}
   175  	n += sn
   176  	if s.Relkind, sn, err = common.ReadString(r); err != nil {
   177  		return
   178  	}
   179  	n += sn
   180  	if s.Createsql, sn, err = common.ReadString(r); err != nil {
   181  		return
   182  	}
   183  	n += sn
   184  
   185  	if s.View, sn, err = common.ReadString(r); err != nil {
   186  		return
   187  	}
   188  	n += sn
   189  	if s.Constraint, sn, err = common.ReadBytes(r); err != nil {
   190  		return
   191  	}
   192  	n += sn
   193  	colCnt := uint16(0)
   194  	if err = binary.Read(r, binary.BigEndian, &colCnt); err != nil {
   195  		return
   196  	}
   197  	n += 2
   198  	colBuf := make([]byte, types.TSize)
   199  	for i := uint16(0); i < colCnt; i++ {
   200  		if _, err = r.Read(colBuf); err != nil {
   201  			return
   202  		}
   203  		n += int64(types.TSize)
   204  		def := new(ColDef)
   205  		def.Type = types.DecodeType(colBuf)
   206  		if def.Name, sn, err = common.ReadString(r); err != nil {
   207  			return
   208  		}
   209  		n += sn
   210  		if def.Comment, sn, err = common.ReadString(r); err != nil {
   211  			return
   212  		}
   213  		n += sn
   214  		if err = binary.Read(r, binary.BigEndian, &def.NullAbility); err != nil {
   215  			return
   216  		}
   217  		n += 1
   218  		if err = binary.Read(r, binary.BigEndian, &def.Hidden); err != nil {
   219  			return
   220  		}
   221  		n += 1
   222  		if err = binary.Read(r, binary.BigEndian, &def.PhyAddr); err != nil {
   223  			return
   224  		}
   225  		n += 1
   226  		if err = binary.Read(r, binary.BigEndian, &def.AutoIncrement); err != nil {
   227  			return
   228  		}
   229  		n += 1
   230  		if err = binary.Read(r, binary.BigEndian, &def.SortIdx); err != nil {
   231  			return
   232  		}
   233  		n += 1
   234  		if err = binary.Read(r, binary.BigEndian, &def.Primary); err != nil {
   235  			return
   236  		}
   237  		n += 1
   238  		if err = binary.Read(r, binary.BigEndian, &def.SortKey); err != nil {
   239  			return
   240  		}
   241  		n += 1
   242  		if err = binary.Read(r, binary.BigEndian, &def.ClusterBy); err != nil {
   243  			return
   244  		}
   245  		n += 1
   246  		length := uint64(0)
   247  		if err = binary.Read(r, binary.BigEndian, &length); err != nil {
   248  			return
   249  		}
   250  		n += 8
   251  		def.Default = make([]byte, length)
   252  		var sn2 int
   253  		if sn2, err = r.Read(def.Default); err != nil {
   254  			return
   255  		}
   256  		n += int64(sn2)
   257  
   258  		length = uint64(0)
   259  		if err = binary.Read(r, binary.BigEndian, &length); err != nil {
   260  			return
   261  		}
   262  		n += 8
   263  		def.OnUpdate = make([]byte, length)
   264  		if sn2, err = r.Read(def.OnUpdate); err != nil {
   265  			return
   266  		}
   267  		n += int64(sn2)
   268  		if err = s.AppendColDef(def); err != nil {
   269  			return
   270  		}
   271  	}
   272  	err = s.Finalize(true)
   273  	return
   274  }
   275  
   276  func (s *Schema) Marshal() (buf []byte, err error) {
   277  	var w bytes.Buffer
   278  	if err = binary.Write(&w, binary.BigEndian, s.BlockMaxRows); err != nil {
   279  		return
   280  	}
   281  	if err = binary.Write(&w, binary.BigEndian, s.SegmentMaxBlocks); err != nil {
   282  		return
   283  	}
   284  	if _, err = s.AcInfo.WriteTo(&w); err != nil {
   285  		return
   286  	}
   287  	if _, err = common.WriteString(s.Name, &w); err != nil {
   288  		return
   289  	}
   290  	if _, err = common.WriteString(s.Comment, &w); err != nil {
   291  		return
   292  	}
   293  	if _, err = common.WriteString(s.Partition, &w); err != nil {
   294  		return
   295  	}
   296  	if _, err = common.WriteString(s.Relkind, &w); err != nil {
   297  		return
   298  	}
   299  	if _, err = common.WriteString(s.Createsql, &w); err != nil {
   300  		return
   301  	}
   302  	if _, err = common.WriteString(s.View, &w); err != nil {
   303  		return
   304  	}
   305  	if _, err = common.WriteBytes(s.Constraint, &w); err != nil {
   306  		return
   307  	}
   308  	if err = binary.Write(&w, binary.BigEndian, uint16(len(s.ColDefs))); err != nil {
   309  		return
   310  	}
   311  	for _, def := range s.ColDefs {
   312  		if _, err = w.Write(types.EncodeType(&def.Type)); err != nil {
   313  			return
   314  		}
   315  		if _, err = common.WriteString(def.Name, &w); err != nil {
   316  			return
   317  		}
   318  		if _, err = common.WriteString(def.Comment, &w); err != nil {
   319  			return
   320  		}
   321  		if err = binary.Write(&w, binary.BigEndian, def.NullAbility); err != nil {
   322  			return
   323  		}
   324  		if err = binary.Write(&w, binary.BigEndian, def.Hidden); err != nil {
   325  			return
   326  		}
   327  		if err = binary.Write(&w, binary.BigEndian, def.PhyAddr); err != nil {
   328  			return
   329  		}
   330  		if err = binary.Write(&w, binary.BigEndian, def.AutoIncrement); err != nil {
   331  			return
   332  		}
   333  		if err = binary.Write(&w, binary.BigEndian, def.SortIdx); err != nil {
   334  			return
   335  		}
   336  		if err = binary.Write(&w, binary.BigEndian, def.Primary); err != nil {
   337  			return
   338  		}
   339  		if err = binary.Write(&w, binary.BigEndian, def.SortKey); err != nil {
   340  			return
   341  		}
   342  		if err = binary.Write(&w, binary.BigEndian, def.ClusterBy); err != nil {
   343  			return
   344  		}
   345  		length := uint64(len(def.Default))
   346  		if err = binary.Write(&w, binary.BigEndian, length); err != nil {
   347  			return
   348  		}
   349  		if _, err = w.Write(def.Default); err != nil {
   350  			return
   351  		}
   352  		length = uint64(len(def.OnUpdate))
   353  		if err = binary.Write(&w, binary.BigEndian, length); err != nil {
   354  			return
   355  		}
   356  		if _, err = w.Write(def.OnUpdate); err != nil {
   357  			return
   358  		}
   359  	}
   360  	buf = w.Bytes()
   361  	return
   362  }
   363  
   364  func (s *Schema) ReadFromBatch(bat *containers.Batch, offset int, targetTid uint64) (next int) {
   365  	nameVec := bat.GetVectorByName(pkgcatalog.SystemColAttr_RelName)
   366  	tidVec := bat.GetVectorByName(pkgcatalog.SystemColAttr_RelID)
   367  	seenRowid := false
   368  	for {
   369  		if offset >= nameVec.Length() {
   370  			break
   371  		}
   372  		name := string(nameVec.Get(offset).([]byte))
   373  		id := tidVec.Get(offset).(uint64)
   374  		// every schema has 1 rowid column as last column, if have one, break
   375  		if name != s.Name || targetTid != id || seenRowid {
   376  			break
   377  		}
   378  		def := new(ColDef)
   379  		def.Name = string(bat.GetVectorByName((pkgcatalog.SystemColAttr_Name)).Get(offset).([]byte))
   380  		data := bat.GetVectorByName((pkgcatalog.SystemColAttr_Type)).Get(offset).([]byte)
   381  		types.Decode(data, &def.Type)
   382  		nullable := bat.GetVectorByName((pkgcatalog.SystemColAttr_NullAbility)).Get(offset).(int8)
   383  		def.NullAbility = i82bool(nullable)
   384  		isHidden := bat.GetVectorByName((pkgcatalog.SystemColAttr_IsHidden)).Get(offset).(int8)
   385  		def.Hidden = i82bool(isHidden)
   386  		isClusterBy := bat.GetVectorByName((pkgcatalog.SystemColAttr_IsClusterBy)).Get(offset).(int8)
   387  		def.ClusterBy = i82bool(isClusterBy)
   388  		isAutoIncrement := bat.GetVectorByName((pkgcatalog.SystemColAttr_IsAutoIncrement)).Get(offset).(int8)
   389  		def.AutoIncrement = i82bool(isAutoIncrement)
   390  		def.Comment = string(bat.GetVectorByName((pkgcatalog.SystemColAttr_Comment)).Get(offset).([]byte))
   391  		def.OnUpdate = bat.GetVectorByName((pkgcatalog.SystemColAttr_Update)).Get(offset).([]byte)
   392  		def.Default = bat.GetVectorByName((pkgcatalog.SystemColAttr_DefaultExpr)).Get(offset).([]byte)
   393  		def.Idx = int(bat.GetVectorByName((pkgcatalog.SystemColAttr_Num)).Get(offset).(int32)) - 1
   394  		s.NameIndex[def.Name] = def.Idx
   395  		s.ColDefs = append(s.ColDefs, def)
   396  		if def.Name == PhyAddrColumnName {
   397  			seenRowid = true
   398  			def.PhyAddr = true
   399  		}
   400  		constraint := string(bat.GetVectorByName(pkgcatalog.SystemColAttr_ConstraintType).Get(offset).([]byte))
   401  		if constraint == "p" {
   402  			def.SortKey = true
   403  			def.Primary = true
   404  		}
   405  		offset++
   406  	}
   407  	s.Finalize(true)
   408  	return offset
   409  }
   410  
   411  func (s *Schema) AppendColDef(def *ColDef) (err error) {
   412  	def.Idx = len(s.ColDefs)
   413  	s.ColDefs = append(s.ColDefs, def)
   414  	_, existed := s.NameIndex[def.Name]
   415  	if existed {
   416  		err = moerr.NewConstraintViolationNoCtx("duplicate column \"%s\"", def.Name)
   417  		return
   418  	}
   419  	s.NameIndex[def.Name] = def.Idx
   420  	return
   421  }
   422  
   423  func (s *Schema) AppendCol(name string, typ types.Type) error {
   424  	def := &ColDef{
   425  		Name:        name,
   426  		Type:        typ,
   427  		SortIdx:     -1,
   428  		NullAbility: true,
   429  	}
   430  	return s.AppendColDef(def)
   431  }
   432  
   433  func (s *Schema) AppendSortKey(name string, typ types.Type, idx int, isPrimary bool) error {
   434  	def := &ColDef{
   435  		Name:    name,
   436  		Type:    typ,
   437  		SortIdx: int8(idx),
   438  		SortKey: true,
   439  	}
   440  	def.Primary = isPrimary
   441  	return s.AppendColDef(def)
   442  }
   443  
   444  func (s *Schema) AppendPKCol(name string, typ types.Type, idx int) error {
   445  	def := &ColDef{
   446  		Name:        name,
   447  		Type:        typ,
   448  		SortIdx:     int8(idx),
   449  		SortKey:     true,
   450  		Primary:     true,
   451  		NullAbility: false,
   452  	}
   453  	return s.AppendColDef(def)
   454  }
   455  
   456  // non-cn doesn't set IsPrimary in attr, so isPrimary is used explicitly here
   457  func (s *Schema) AppendSortColWithAttribute(attr engine.Attribute, sorIdx int, isPrimary bool) error {
   458  	def, err := ColDefFromAttribute(attr)
   459  	if err != nil {
   460  		return err
   461  	}
   462  
   463  	def.SortKey = true
   464  	def.SortIdx = int8(sorIdx)
   465  	def.Primary = isPrimary
   466  
   467  	return s.AppendColDef(def)
   468  }
   469  
   470  // make a basic coldef without sortKey info
   471  func ColDefFromAttribute(attr engine.Attribute) (*ColDef, error) {
   472  	var err error
   473  	def := &ColDef{
   474  		Name:          attr.Name,
   475  		Type:          attr.Type,
   476  		Hidden:        attr.IsHidden,
   477  		SortIdx:       -1,
   478  		Comment:       attr.Comment,
   479  		AutoIncrement: attr.AutoIncrement,
   480  		ClusterBy:     attr.ClusterBy,
   481  		Default:       []byte(""),
   482  		OnUpdate:      []byte(""),
   483  	}
   484  	if attr.Default != nil {
   485  		def.NullAbility = attr.Default.NullAbility
   486  		if def.Default, err = types.Encode(attr.Default); err != nil {
   487  			return nil, err
   488  		}
   489  	}
   490  	if attr.OnUpdate != nil {
   491  		if def.OnUpdate, err = types.Encode(attr.OnUpdate); err != nil {
   492  			return nil, err
   493  		}
   494  	}
   495  	return def, nil
   496  }
   497  
   498  func (s *Schema) AppendColWithAttribute(attr engine.Attribute) error {
   499  	def, err := ColDefFromAttribute(attr)
   500  	if err != nil {
   501  		return err
   502  	}
   503  	return s.AppendColDef(def)
   504  }
   505  
   506  func (s *Schema) String() string {
   507  	buf, _ := json.Marshal(s)
   508  	return string(buf)
   509  }
   510  
   511  func (s *Schema) Attrs() []string {
   512  	if len(s.ColDefs) == 0 {
   513  		return make([]string, 0)
   514  	}
   515  	attrs := make([]string, 0, len(s.ColDefs)-1)
   516  	for _, def := range s.ColDefs {
   517  		if def.IsPhyAddr() {
   518  			continue
   519  		}
   520  		attrs = append(attrs, def.Name)
   521  	}
   522  	return attrs
   523  }
   524  
   525  func (s *Schema) Types() []types.Type {
   526  	if len(s.ColDefs) == 0 {
   527  		return make([]types.Type, 0)
   528  	}
   529  	ts := make([]types.Type, 0, len(s.ColDefs)-1)
   530  	for _, def := range s.ColDefs {
   531  		if def.IsPhyAddr() {
   532  			continue
   533  		}
   534  		ts = append(ts, def.Type)
   535  	}
   536  	return ts
   537  }
   538  
   539  func (s *Schema) Nullables() []bool {
   540  	if len(s.ColDefs) == 0 {
   541  		return make([]bool, 0)
   542  	}
   543  	nulls := make([]bool, 0, len(s.ColDefs)-1)
   544  	for _, def := range s.ColDefs {
   545  		if def.IsPhyAddr() {
   546  			continue
   547  		}
   548  		nulls = append(nulls, def.Nullable())
   549  	}
   550  	return nulls
   551  }
   552  
   553  func (s *Schema) AllNullables() []bool {
   554  	if len(s.ColDefs) == 0 {
   555  		return make([]bool, 0)
   556  	}
   557  	nulls := make([]bool, 0, len(s.ColDefs))
   558  	for _, def := range s.ColDefs {
   559  		nulls = append(nulls, def.Nullable())
   560  	}
   561  	return nulls
   562  }
   563  
   564  func (s *Schema) AllTypes() []types.Type {
   565  	if len(s.ColDefs) == 0 {
   566  		return make([]types.Type, 0)
   567  	}
   568  	ts := make([]types.Type, 0, len(s.ColDefs))
   569  	for _, def := range s.ColDefs {
   570  		ts = append(ts, def.Type)
   571  	}
   572  	return ts
   573  }
   574  
   575  func (s *Schema) AllNames() []string {
   576  	if len(s.ColDefs) == 0 {
   577  		return make([]string, 0)
   578  	}
   579  	names := make([]string, 0, len(s.ColDefs))
   580  	for _, def := range s.ColDefs {
   581  		names = append(names, def.Name)
   582  	}
   583  	return names
   584  }
   585  
   586  // Finalize runs various checks and create shortcuts to phyaddr and sortkey
   587  func (s *Schema) Finalize(withoutPhyAddr bool) (err error) {
   588  	if s == nil {
   589  		err = moerr.NewConstraintViolationNoCtx("no schema")
   590  		return
   591  	}
   592  	if !withoutPhyAddr {
   593  		phyAddrDef := &ColDef{
   594  			Name:        PhyAddrColumnName,
   595  			Comment:     PhyAddrColumnComment,
   596  			Type:        PhyAddrColumnType,
   597  			Hidden:      true,
   598  			NullAbility: false,
   599  			PhyAddr:     true,
   600  		}
   601  		if err = s.AppendColDef(phyAddrDef); err != nil {
   602  			return
   603  		}
   604  	}
   605  
   606  	// sortColIdx is sort key index list. as of now, sort key is pk
   607  	sortColIdx := make([]int, 0)
   608  	// check duplicate column names
   609  	names := make(map[string]bool)
   610  	for idx, def := range s.ColDefs {
   611  		// Check column sequence idx validility
   612  		if idx != def.Idx {
   613  			return moerr.NewInvalidInputNoCtx(fmt.Sprintf("schema: wrong column index %d specified for \"%s\"", def.Idx, def.Name))
   614  		}
   615  		// Check unique name
   616  		if _, ok := names[def.Name]; ok {
   617  			return moerr.NewInvalidInputNoCtx("schema: duplicate column \"%s\"", def.Name)
   618  		}
   619  		names[def.Name] = true
   620  		if def.IsSortKey() {
   621  			sortColIdx = append(sortColIdx, idx)
   622  		}
   623  		if def.IsPhyAddr() {
   624  			if s.PhyAddrKey != nil {
   625  				return moerr.NewInvalidInputNoCtx("schema: duplicated physical address column \"%s\"", def.Name)
   626  			}
   627  			s.PhyAddrKey = def
   628  		}
   629  	}
   630  
   631  	if len(sortColIdx) == 1 {
   632  		def := s.ColDefs[sortColIdx[0]]
   633  		if def.SortIdx != 0 {
   634  			err = moerr.NewConstraintViolationNoCtx("bad sort idx %d, should be 0", def.SortIdx)
   635  			return
   636  		}
   637  		s.SortKey = NewSortKey()
   638  		s.SortKey.AddDef(def)
   639  	} else if len(sortColIdx) > 1 {
   640  		// schema has a primary key or a cluster by key, or nothing for now
   641  		panic("schema: multiple sort keys")
   642  	}
   643  	return
   644  }
   645  
   646  // GetColIdx returns column index for the given column name
   647  // if found, otherwise returns -1.
   648  func (s *Schema) GetColIdx(attr string) int {
   649  	idx, ok := s.NameIndex[attr]
   650  	if !ok {
   651  		return -1
   652  	}
   653  	return idx
   654  }
   655  
   656  func GetAttrIdx(attrs []string, name string) int {
   657  	for i, attr := range attrs {
   658  		if attr == name {
   659  			return i
   660  		}
   661  	}
   662  	panic("logic error")
   663  }
   664  
   665  func MockSchema(colCnt int, pkIdx int) *Schema {
   666  	rand.Seed(time.Now().UnixNano())
   667  	schema := NewEmptySchema(time.Now().String())
   668  	prefix := "mock_"
   669  
   670  	constraintDef := &engine.ConstraintDef{
   671  		Cts: make([]engine.Constraint, 0),
   672  	}
   673  
   674  	for i := 0; i < colCnt; i++ {
   675  		if pkIdx == i {
   676  			colName := fmt.Sprintf("%s%d", prefix, i)
   677  			_ = schema.AppendPKCol(colName, types.Type{Oid: types.T_int32, Size: 4, Width: 4}, 0)
   678  			pkConstraint := &engine.PrimaryKeyDef{
   679  				Pkey: &plan.PrimaryKeyDef{
   680  					PkeyColName: colName,
   681  					Names:       []string{colName},
   682  				},
   683  			}
   684  			constraintDef.Cts = append(constraintDef.Cts, pkConstraint)
   685  		} else {
   686  			_ = schema.AppendCol(fmt.Sprintf("%s%d", prefix, i), types.Type{Oid: types.T_int32, Size: 4, Width: 4})
   687  		}
   688  	}
   689  	schema.Constraint, _ = constraintDef.MarshalBinary()
   690  
   691  	_ = schema.Finalize(false)
   692  	return schema
   693  }
   694  
   695  // MockSchemaAll if char/varchar is needed, colCnt = 14, otherwise colCnt = 12
   696  // pkIdx == -1 means no pk defined
   697  func MockSchemaAll(colCnt int, pkIdx int, from ...int) *Schema {
   698  	schema := NewEmptySchema(time.Now().String())
   699  	prefix := "mock_"
   700  	start := 0
   701  	if len(from) > 0 {
   702  		start = from[0]
   703  	}
   704  
   705  	constraintDef := &engine.ConstraintDef{
   706  		Cts: make([]engine.Constraint, 0),
   707  	}
   708  
   709  	for i := 0; i < colCnt; i++ {
   710  		if i < start {
   711  			continue
   712  		}
   713  		name := fmt.Sprintf("%s%d", prefix, i)
   714  		var typ types.Type
   715  		switch i % 18 {
   716  		case 0:
   717  			typ = types.T_int8.ToType()
   718  			typ.Width = 8
   719  		case 1:
   720  			typ = types.T_int16.ToType()
   721  			typ.Width = 16
   722  		case 2:
   723  			typ = types.T_int32.ToType()
   724  			typ.Width = 32
   725  		case 3:
   726  			typ = types.T_int64.ToType()
   727  			typ.Width = 64
   728  		case 4:
   729  			typ = types.T_uint8.ToType()
   730  			typ.Width = 8
   731  		case 5:
   732  			typ = types.T_uint16.ToType()
   733  			typ.Width = 16
   734  		case 6:
   735  			typ = types.T_uint32.ToType()
   736  			typ.Width = 32
   737  		case 7:
   738  			typ = types.T_uint64.ToType()
   739  			typ.Width = 64
   740  		case 8:
   741  			typ = types.T_float32.ToType()
   742  			typ.Width = 32
   743  		case 9:
   744  			typ = types.T_float64.ToType()
   745  			typ.Width = 64
   746  		case 10:
   747  			typ = types.T_date.ToType()
   748  			typ.Width = 32
   749  		case 11:
   750  			typ = types.T_datetime.ToType()
   751  			typ.Width = 64
   752  		case 12:
   753  			typ = types.T_varchar.ToType()
   754  			typ.Width = 100
   755  		case 13:
   756  			typ = types.T_char.ToType()
   757  			typ.Width = 100
   758  		case 14:
   759  			typ = types.T_timestamp.ToType()
   760  			typ.Width = 64
   761  		case 15:
   762  			typ = types.T_decimal64.ToType()
   763  			typ.Width = 64
   764  		case 16:
   765  			typ = types.T_decimal128.ToType()
   766  			typ.Width = 128
   767  		case 17:
   768  			typ = types.T_bool.ToType()
   769  			typ.Width = 8
   770  		}
   771  
   772  		if pkIdx == i {
   773  			_ = schema.AppendPKCol(name, typ, 0)
   774  			pkConstraint := &engine.PrimaryKeyDef{
   775  				Pkey: &plan.PrimaryKeyDef{
   776  					PkeyColName: name,
   777  					Names:       []string{name},
   778  				},
   779  			}
   780  			constraintDef.Cts = append(constraintDef.Cts, pkConstraint)
   781  		} else {
   782  			_ = schema.AppendCol(name, typ)
   783  			schema.ColDefs[len(schema.ColDefs)-1].NullAbility = true
   784  		}
   785  	}
   786  	schema.BlockMaxRows = 1000
   787  	schema.SegmentMaxBlocks = 10
   788  	schema.Constraint, _ = constraintDef.MarshalBinary()
   789  	_ = schema.Finalize(false)
   790  	return schema
   791  }