github.com/matrixorigin/matrixone@v1.2.0/pkg/vm/engine/disttae/txn_database.go (about)

     1  // Copyright 2022 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 disttae
    16  
    17  import (
    18  	"context"
    19  	"runtime/debug"
    20  	"strconv"
    21  	"strings"
    22  
    23  	"go.uber.org/zap"
    24  
    25  	"github.com/matrixorigin/matrixone/pkg/logutil"
    26  	txn2 "github.com/matrixorigin/matrixone/pkg/pb/txn"
    27  
    28  	"github.com/matrixorigin/matrixone/pkg/catalog"
    29  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    30  	"github.com/matrixorigin/matrixone/pkg/container/types"
    31  	"github.com/matrixorigin/matrixone/pkg/defines"
    32  	"github.com/matrixorigin/matrixone/pkg/vm/engine"
    33  	"github.com/matrixorigin/matrixone/pkg/vm/engine/disttae/cache"
    34  	"github.com/matrixorigin/matrixone/pkg/vm/process"
    35  )
    36  
    37  var _ engine.Database = new(txnDatabase)
    38  
    39  func (db *txnDatabase) getTxn() *Transaction {
    40  	return db.op.GetWorkspace().(*Transaction)
    41  }
    42  
    43  func (db *txnDatabase) getEng() *Engine {
    44  	return db.op.GetWorkspace().(*Transaction).engine
    45  }
    46  
    47  func (db *txnDatabase) Relations(ctx context.Context) ([]string, error) {
    48  	var rels []string
    49  	//first get all delete tables
    50  	deleteTables := make(map[string]any)
    51  	db.getTxn().deletedTableMap.Range(func(k, _ any) bool {
    52  		key := k.(tableKey)
    53  		if key.databaseId == db.databaseId {
    54  			deleteTables[key.name] = nil
    55  		}
    56  		return true
    57  	})
    58  	db.getTxn().createMap.Range(func(k, _ any) bool {
    59  		key := k.(tableKey)
    60  		if key.databaseId == db.databaseId {
    61  			//if the table is deleted, do not save it.
    62  			if _, exist := deleteTables[key.name]; !exist {
    63  				rels = append(rels, key.name)
    64  			}
    65  		}
    66  		return true
    67  	})
    68  	accountId, err := defines.GetAccountId(ctx)
    69  	if err != nil {
    70  		return nil, err
    71  	}
    72  	var catache *cache.CatalogCache
    73  	if !db.op.IsSnapOp() {
    74  		catache = db.getTxn().engine.getLatestCatalogCache()
    75  	} else {
    76  		catache, err = db.getTxn().engine.getOrCreateSnapCatalogCache(
    77  			ctx,
    78  			types.TimestampToTS(db.op.SnapshotTS()))
    79  		if err != nil {
    80  			return nil, err
    81  		}
    82  	}
    83  	tbls, _ := catache.Tables(
    84  		accountId, db.databaseId, db.op.SnapshotTS())
    85  	for _, tbl := range tbls {
    86  		//if the table is deleted, do not save it.
    87  		if _, exist := deleteTables[tbl]; !exist {
    88  			rels = append(rels, tbl)
    89  		}
    90  	}
    91  	return rels, nil
    92  }
    93  
    94  func (db *txnDatabase) getTableNameById(ctx context.Context, id uint64) (string, error) {
    95  	tblName := ""
    96  	//first check the tableID is deleted or not
    97  	deleted := false
    98  	db.getTxn().deletedTableMap.Range(func(k, v any) bool {
    99  		key := k.(tableKey)
   100  		val := v.(uint64)
   101  		if key.databaseId == db.databaseId && val == id {
   102  			deleted = true
   103  			return false
   104  		}
   105  		return true
   106  	})
   107  	if deleted {
   108  		return "", nil
   109  	}
   110  	db.getTxn().createMap.Range(func(k, v any) bool {
   111  		key := k.(tableKey)
   112  		val := v.(*txnTable)
   113  		if key.databaseId == db.databaseId && val.tableId == id {
   114  			tblName = key.name
   115  			return false
   116  		}
   117  		return true
   118  	})
   119  
   120  	if tblName == "" {
   121  		accountId, err := defines.GetAccountId(ctx)
   122  		if err != nil {
   123  			return "", err
   124  		}
   125  		var catache *cache.CatalogCache
   126  		if !db.op.IsSnapOp() {
   127  			catache = db.getTxn().engine.getLatestCatalogCache()
   128  		} else {
   129  			catache, err = db.getTxn().engine.getOrCreateSnapCatalogCache(
   130  				ctx,
   131  				types.TimestampToTS(db.op.SnapshotTS()))
   132  			if err != nil {
   133  				return "", err
   134  			}
   135  		}
   136  		tbls, tblIds := catache.Tables(
   137  			accountId, db.databaseId, db.op.SnapshotTS())
   138  		for idx, tblId := range tblIds {
   139  			if tblId == id {
   140  				tblName = tbls[idx]
   141  				break
   142  			}
   143  		}
   144  	}
   145  	return tblName, nil
   146  }
   147  
   148  func (db *txnDatabase) getRelationById(ctx context.Context, id uint64) (string, engine.Relation, error) {
   149  	tblName, err := db.getTableNameById(ctx, id)
   150  	if err != nil {
   151  		return "", nil, err
   152  	}
   153  	if tblName == "" {
   154  		return "", nil, nil
   155  	}
   156  	rel, _ := db.Relation(ctx, tblName, nil)
   157  	return tblName, rel, nil
   158  }
   159  
   160  func (db *txnDatabase) RelationByAccountID(
   161  	accountID uint32,
   162  	name string,
   163  	proc any) (engine.Relation, error) {
   164  	logDebugf(db.op.Txn(), "txnDatabase.RelationByAccountID table %s", name)
   165  	txn := db.getTxn()
   166  	if txn.op.Status() == txn2.TxnStatus_Aborted {
   167  		return nil, moerr.NewTxnClosedNoCtx(txn.op.Txn().ID)
   168  	}
   169  
   170  	key := genTableKey(accountID, name, db.databaseId)
   171  	// check the table is deleted or not
   172  	if _, exist := db.getTxn().deletedTableMap.Load(key); exist {
   173  		if strings.Contains(name, "_copy_") {
   174  			stackInfo := debug.Stack()
   175  			logutil.Error(moerr.NewParseError(context.Background(), "table %q does not exists", name).Error(), zap.String("Stack Trace", string(stackInfo)))
   176  		}
   177  		return nil, moerr.NewParseError(context.Background(), "table %q does not exist", name)
   178  	}
   179  
   180  	p := db.getTxn().proc
   181  	if proc != nil {
   182  		p = proc.(*process.Process)
   183  	}
   184  
   185  	rel := db.getTxn().getCachedTable(context.Background(), key)
   186  	if rel != nil {
   187  		rel.proc.Store(p)
   188  		return rel, nil
   189  	}
   190  
   191  	// get relation from the txn created tables cache: created by this txn
   192  	if v, ok := db.getTxn().createMap.Load(key); ok {
   193  		v.(*txnTable).proc.Store(p)
   194  		return v.(*txnTable), nil
   195  	}
   196  
   197  	// special tables
   198  	if db.databaseName == catalog.MO_CATALOG {
   199  		switch name {
   200  		case catalog.MO_DATABASE:
   201  			id := uint64(catalog.MO_DATABASE_ID)
   202  			defs := catalog.MoDatabaseTableDefs
   203  			return db.openSysTable(p, id, name, defs), nil
   204  		case catalog.MO_TABLES:
   205  			id := uint64(catalog.MO_TABLES_ID)
   206  			defs := catalog.MoTablesTableDefs
   207  			return db.openSysTable(p, id, name, defs), nil
   208  		case catalog.MO_COLUMNS:
   209  			id := uint64(catalog.MO_COLUMNS_ID)
   210  			defs := catalog.MoColumnsTableDefs
   211  			return db.openSysTable(p, id, name, defs), nil
   212  		}
   213  	}
   214  	item := &cache.TableItem{
   215  		Name:       name,
   216  		DatabaseId: db.databaseId,
   217  		AccountId:  accountID,
   218  		Ts:         db.op.SnapshotTS(),
   219  	}
   220  	var catache *cache.CatalogCache
   221  	var err error
   222  	if !db.op.IsSnapOp() {
   223  		catache = db.getTxn().engine.getLatestCatalogCache()
   224  	} else {
   225  		catache, err = db.getTxn().engine.getOrCreateSnapCatalogCache(
   226  			context.Background(),
   227  			types.TimestampToTS(db.op.SnapshotTS()))
   228  		if err != nil {
   229  			return nil, err
   230  		}
   231  	}
   232  	if ok := catache.GetTable(item); !ok {
   233  		logutil.Debugf("txnDatabase.Relation table %q(acc %d db %d) does not exist",
   234  			name,
   235  			accountID,
   236  			db.databaseId)
   237  		return nil, moerr.NewParseError(context.Background(), "table %q does not exist", name)
   238  	}
   239  
   240  	tbl := &txnTable{
   241  		db:            db,
   242  		accountId:     item.AccountId,
   243  		tableId:       item.Id,
   244  		version:       item.Version,
   245  		tableName:     item.Name,
   246  		defs:          item.Defs,
   247  		tableDef:      item.TableDef,
   248  		primaryIdx:    item.PrimaryIdx,
   249  		primarySeqnum: item.PrimarySeqnum,
   250  		clusterByIdx:  item.ClusterByIdx,
   251  		relKind:       item.Kind,
   252  		viewdef:       item.ViewDef,
   253  		comment:       item.Comment,
   254  		partitioned:   item.Partitioned,
   255  		partition:     item.Partition,
   256  		createSql:     item.CreateSql,
   257  		constraint:    item.Constraint,
   258  		rowid:         item.Rowid,
   259  		rowids:        item.Rowids,
   260  		lastTS:        txn.op.SnapshotTS(),
   261  	}
   262  	tbl.proc.Store(p)
   263  
   264  	db.getTxn().tableCache.tableMap.Store(key, tbl)
   265  	return tbl, nil
   266  }
   267  
   268  func (db *txnDatabase) Relation(ctx context.Context, name string, proc any) (engine.Relation, error) {
   269  	if db.databaseName == "test" && name == "bugt" && db.op.IsSnapOp() {
   270  		logutil.Infof("xxxx open relation, txn:%s", db.op.Txn().DebugString())
   271  	}
   272  	logDebugf(db.op.Txn(), "txnDatabase.Relation table %s", name)
   273  	txn := db.getTxn()
   274  	if txn.op.Status() == txn2.TxnStatus_Aborted {
   275  		return nil, moerr.NewTxnClosedNoCtx(txn.op.Txn().ID)
   276  	}
   277  	accountId, err := defines.GetAccountId(ctx)
   278  	if err != nil {
   279  		return nil, err
   280  	}
   281  	key := genTableKey(accountId, name, db.databaseId)
   282  	// check the table is deleted or not
   283  	if _, exist := db.getTxn().deletedTableMap.Load(key); exist {
   284  		return nil, moerr.NewParseError(ctx, "table %q does not exist", name)
   285  	}
   286  
   287  	p := db.getTxn().proc
   288  	if proc != nil {
   289  		p = proc.(*process.Process)
   290  	}
   291  
   292  	rel := db.getTxn().getCachedTable(ctx, key)
   293  	if rel != nil {
   294  		rel.proc.Store(p)
   295  		return rel, nil
   296  	}
   297  
   298  	// get relation from the txn created tables cache: created by this txn
   299  	if v, ok := db.getTxn().createMap.Load(key); ok {
   300  		v.(*txnTable).proc.Store(p)
   301  		return v.(*txnTable), nil
   302  	}
   303  
   304  	// special tables
   305  	if db.databaseName == catalog.MO_CATALOG {
   306  		switch name {
   307  		case catalog.MO_DATABASE:
   308  			id := uint64(catalog.MO_DATABASE_ID)
   309  			defs := catalog.MoDatabaseTableDefs
   310  			return db.openSysTable(p, id, name, defs), nil
   311  		case catalog.MO_TABLES:
   312  			id := uint64(catalog.MO_TABLES_ID)
   313  			defs := catalog.MoTablesTableDefs
   314  			return db.openSysTable(p, id, name, defs), nil
   315  		case catalog.MO_COLUMNS:
   316  			id := uint64(catalog.MO_COLUMNS_ID)
   317  			defs := catalog.MoColumnsTableDefs
   318  			return db.openSysTable(p, id, name, defs), nil
   319  		}
   320  	}
   321  	item := &cache.TableItem{
   322  		Name:       name,
   323  		DatabaseId: db.databaseId,
   324  		AccountId:  accountId,
   325  		Ts:         db.op.SnapshotTS(),
   326  	}
   327  	var catache *cache.CatalogCache
   328  	if !db.op.IsSnapOp() {
   329  		catache = db.getTxn().engine.getLatestCatalogCache()
   330  	} else {
   331  		catache, err = db.getTxn().engine.getOrCreateSnapCatalogCache(
   332  			ctx,
   333  			types.TimestampToTS(db.op.SnapshotTS()))
   334  		if err != nil {
   335  			return nil, err
   336  		}
   337  	}
   338  	if ok := catache.GetTable(item); !ok {
   339  		logutil.Debugf("txnDatabase.Relation table %q(acc %d db %d) does not exist",
   340  			name,
   341  			accountId,
   342  			db.databaseId)
   343  		if strings.Contains(name, "_copy_") {
   344  			stackInfo := debug.Stack()
   345  			logutil.Error(moerr.NewParseError(context.Background(), "table %q does not exists", name).Error(), zap.String("Stack Trace", string(stackInfo)))
   346  		}
   347  		return nil, moerr.NewParseError(ctx, "table %q does not exist", name)
   348  	}
   349  
   350  	tbl := &txnTable{
   351  		db:            db,
   352  		accountId:     item.AccountId,
   353  		tableId:       item.Id,
   354  		version:       item.Version,
   355  		tableName:     item.Name,
   356  		defs:          item.Defs,
   357  		tableDef:      item.TableDef,
   358  		primaryIdx:    item.PrimaryIdx,
   359  		primarySeqnum: item.PrimarySeqnum,
   360  		clusterByIdx:  item.ClusterByIdx,
   361  		relKind:       item.Kind,
   362  		viewdef:       item.ViewDef,
   363  		comment:       item.Comment,
   364  		partitioned:   item.Partitioned,
   365  		partition:     item.Partition,
   366  		createSql:     item.CreateSql,
   367  		constraint:    item.Constraint,
   368  		rowid:         item.Rowid,
   369  		rowids:        item.Rowids,
   370  		lastTS:        txn.op.SnapshotTS(),
   371  	}
   372  	tbl.proc.Store(p)
   373  
   374  	db.getTxn().tableCache.tableMap.Store(key, tbl)
   375  	return tbl, nil
   376  }
   377  
   378  func (db *txnDatabase) Delete(ctx context.Context, name string) error {
   379  	var id uint64
   380  	var rowid types.Rowid
   381  	var rowids []types.Rowid
   382  	if db.op.IsSnapOp() {
   383  		return moerr.NewInternalErrorNoCtx("delete table in snapshot transaction")
   384  	}
   385  	accountId, err := defines.GetAccountId(ctx)
   386  	if err != nil {
   387  		return err
   388  	}
   389  	k := genTableKey(accountId, name, db.databaseId)
   390  	if v, ok := db.getTxn().createMap.Load(k); ok {
   391  		db.getTxn().createMap.Delete(k)
   392  		table := v.(*txnTable)
   393  		id = table.tableId
   394  		rowid = table.rowid
   395  		rowids = table.rowids
   396  		/*
   397  			Even if the created table in the createMap, there is an
   398  			INSERT entry in the CN workspace. We need add a DELETE
   399  			entry in the CN workspace to tell the TN to delete the
   400  			table.
   401  			CORNER CASE
   402  			begin;
   403  			create table t1;
   404  			drop table t1;
   405  			commit;
   406  			If we do not add DELETE entry in workspace, there is
   407  			a table t1 there after commit.
   408  		*/
   409  	} else if v, ok := db.getTxn().tableCache.tableMap.Load(k); ok {
   410  		table := v.(*txnTable)
   411  		id = table.tableId
   412  		db.getTxn().tableCache.tableMap.Delete(k)
   413  		rowid = table.rowid
   414  		rowids = table.rowids
   415  	} else {
   416  		item := &cache.TableItem{
   417  			Name:       name,
   418  			DatabaseId: db.databaseId,
   419  			AccountId:  accountId,
   420  			Ts:         db.op.SnapshotTS(),
   421  		}
   422  		if ok := db.getTxn().engine.getLatestCatalogCache().GetTable(item); !ok {
   423  			return moerr.GetOkExpectedEOB()
   424  		}
   425  		id = item.Id
   426  		rowid = item.Rowid
   427  		rowids = item.Rowids
   428  	}
   429  	bat, err := genDropTableTuple(rowid, id, db.databaseId,
   430  		name, db.databaseName, db.getTxn().proc.Mp())
   431  	if err != nil {
   432  		return err
   433  	}
   434  
   435  	for _, store := range db.getTxn().tnStores {
   436  		if err := db.getTxn().WriteBatch(
   437  			DELETE, 0, catalog.MO_CATALOG_ID, catalog.MO_TABLES_ID,
   438  			catalog.MO_CATALOG, catalog.MO_TABLES, bat, store, -1, false, false); err != nil {
   439  			bat.Clean(db.getTxn().proc.Mp())
   440  			return err
   441  		}
   442  	}
   443  
   444  	//Add writeBatch(delete,mo_columns) to filter table in mo_columns.
   445  	//Every row in writeBatch(delete,mo_columns) needs rowid
   446  	for _, rid := range rowids {
   447  		bat, err = genDropColumnTuple(rid, db.getTxn().proc.Mp())
   448  		if err != nil {
   449  			return err
   450  		}
   451  		for _, store := range db.getTxn().tnStores {
   452  			if err = db.getTxn().WriteBatch(
   453  				DELETE, 0, catalog.MO_CATALOG_ID, catalog.MO_COLUMNS_ID,
   454  				catalog.MO_CATALOG, catalog.MO_COLUMNS, bat, store, -1, false, false); err != nil {
   455  				bat.Clean(db.getTxn().proc.Mp())
   456  				return err
   457  			}
   458  		}
   459  	}
   460  
   461  	db.getTxn().deletedTableMap.Store(k, id)
   462  	return nil
   463  }
   464  
   465  func (db *txnDatabase) Truncate(ctx context.Context, name string) (uint64, error) {
   466  	var oldId uint64
   467  	var rowid types.Rowid
   468  	var v any
   469  	var ok bool
   470  	if db.op.IsSnapOp() {
   471  		return 0, moerr.NewInternalErrorNoCtx("truncate table in snapshot transaction")
   472  	}
   473  	newId, err := db.getTxn().allocateID(ctx)
   474  	if err != nil {
   475  		return 0, err
   476  	}
   477  	accountId, err := defines.GetAccountId(ctx)
   478  	if err != nil {
   479  		return 0, err
   480  	}
   481  	k := genTableKey(accountId, name, db.databaseId)
   482  	v, ok = db.getTxn().createMap.Load(k)
   483  	if !ok {
   484  		v, ok = db.getTxn().tableCache.tableMap.Load(k)
   485  	}
   486  
   487  	if ok {
   488  		txnTable := v.(*txnTable)
   489  		oldId = txnTable.tableId
   490  		txnTable.reset(newId)
   491  		rowid = txnTable.rowid
   492  	} else {
   493  		item := &cache.TableItem{
   494  			Name:       name,
   495  			DatabaseId: db.databaseId,
   496  			AccountId:  accountId,
   497  			Ts:         db.op.SnapshotTS(),
   498  		}
   499  		if ok := db.getTxn().engine.getLatestCatalogCache().GetTable(item); !ok {
   500  			return 0, moerr.GetOkExpectedEOB()
   501  		}
   502  		oldId = item.Id
   503  		rowid = item.Rowid
   504  	}
   505  	bat, err := genTruncateTableTuple(rowid, newId, db.databaseId,
   506  		genMetaTableName(oldId)+name, db.databaseName, db.getTxn().proc.Mp())
   507  	if err != nil {
   508  		return 0, err
   509  	}
   510  	for _, store := range db.getTxn().tnStores {
   511  		if err := db.getTxn().WriteBatch(DELETE, 0, catalog.MO_CATALOG_ID, catalog.MO_TABLES_ID,
   512  			catalog.MO_CATALOG, catalog.MO_TABLES, bat, store, -1, false, true); err != nil {
   513  			bat.Clean(db.getTxn().proc.Mp())
   514  			return 0, err
   515  		}
   516  	}
   517  	return newId, nil
   518  }
   519  
   520  func (db *txnDatabase) GetDatabaseId(ctx context.Context) string {
   521  	return strconv.FormatUint(db.databaseId, 10)
   522  }
   523  
   524  func (db *txnDatabase) GetCreateSql(ctx context.Context) string {
   525  	return db.databaseCreateSql
   526  }
   527  
   528  func (db *txnDatabase) IsSubscription(ctx context.Context) bool {
   529  	return db.databaseType == catalog.SystemDBTypeSubscription
   530  }
   531  
   532  func (db *txnDatabase) Create(ctx context.Context, name string, defs []engine.TableDef) error {
   533  	if db.op.IsSnapOp() {
   534  		return moerr.NewInternalErrorNoCtx("create table in snapshot transaction")
   535  	}
   536  	accountId, userId, roleId, err := getAccessInfo(ctx)
   537  	if err != nil {
   538  		return err
   539  	}
   540  	tableId, err := db.getTxn().allocateID(ctx)
   541  	if err != nil {
   542  		return err
   543  	}
   544  	tbl := new(txnTable)
   545  	tbl.accountId = accountId
   546  	tbl.rowid = types.DecodeFixed[types.Rowid](types.EncodeSlice([]uint64{tableId}))
   547  	tbl.comment = getTableComment(defs)
   548  	{
   549  		for _, def := range defs { // copy from tae
   550  			switch defVal := def.(type) {
   551  			case *engine.PropertiesDef:
   552  				for _, property := range defVal.Properties {
   553  					switch strings.ToLower(property.Key) {
   554  					case catalog.SystemRelAttr_Comment: // Watch priority over commentDef
   555  						tbl.comment = property.Value
   556  					case catalog.SystemRelAttr_Kind:
   557  						tbl.relKind = property.Value
   558  					case catalog.SystemRelAttr_CreateSQL:
   559  						tbl.createSql = property.Value // I don't trust this information.
   560  					default:
   561  					}
   562  				}
   563  			case *engine.ViewDef:
   564  				tbl.viewdef = defVal.View
   565  			case *engine.PartitionDef:
   566  				tbl.partitioned = defVal.Partitioned
   567  				tbl.partition = defVal.Partition
   568  			case *engine.ConstraintDef:
   569  				tbl.constraint, err = defVal.MarshalBinary()
   570  				if err != nil {
   571  					return err
   572  				}
   573  			}
   574  		}
   575  	}
   576  	cols, err := genColumns(accountId, name, db.databaseName, tableId, db.databaseId, defs)
   577  	if err != nil {
   578  		return err
   579  	}
   580  	{
   581  		sql := getSql(ctx)
   582  		bat, err := genCreateTableTuple(
   583  			tbl, sql, accountId, userId, roleId, name,
   584  			tableId, db.databaseId, db.databaseName,
   585  			tbl.rowid, true, db.getTxn().proc.Mp())
   586  		if err != nil {
   587  			return err
   588  		}
   589  		for _, store := range db.getTxn().tnStores {
   590  			if err := db.getTxn().WriteBatch(INSERT, 0, catalog.MO_CATALOG_ID, catalog.MO_TABLES_ID,
   591  				catalog.MO_CATALOG, catalog.MO_TABLES, bat, store, -1, true, false); err != nil {
   592  				bat.Clean(db.getTxn().proc.Mp())
   593  				return err
   594  			}
   595  		}
   596  	}
   597  	tbl.primaryIdx = -1
   598  	tbl.primarySeqnum = -1
   599  	tbl.clusterByIdx = -1
   600  	tbl.rowids = make([]types.Rowid, len(cols))
   601  	for i, col := range cols {
   602  		tbl.rowids[i] = db.getTxn().genRowId()
   603  		bat, err := genCreateColumnTuple(col, tbl.rowids[i], true,
   604  			db.getTxn().proc.Mp())
   605  		if err != nil {
   606  			return err
   607  		}
   608  		for _, store := range db.getTxn().tnStores {
   609  			if err := db.getTxn().WriteBatch(
   610  				INSERT, 0, catalog.MO_CATALOG_ID, catalog.MO_COLUMNS_ID,
   611  				catalog.MO_CATALOG, catalog.MO_COLUMNS, bat, store, -1, true, false); err != nil {
   612  				bat.Clean(db.getTxn().proc.Mp())
   613  				return err
   614  			}
   615  		}
   616  		if col.constraintType == catalog.SystemColPKConstraint {
   617  			tbl.primaryIdx = i
   618  			tbl.primarySeqnum = i
   619  		}
   620  		if col.isClusterBy == 1 {
   621  			tbl.clusterByIdx = i
   622  		}
   623  	}
   624  	tbl.db = db
   625  	tbl.defs = defs
   626  	tbl.tableName = name
   627  	tbl.tableId = tableId
   628  	tbl.GetTableDef(ctx)
   629  	key := genTableKey(accountId, name, db.databaseId)
   630  	db.getTxn().addCreateTable(key, tbl)
   631  	//CORNER CASE
   632  	//begin;
   633  	//create table t1(a int);
   634  	//drop table t1; //t1 is in deleteTableMap now.
   635  	//select * from t1; //t1 does not exist.
   636  	//create table t1(a int); //t1 does not exist. t1 can be created again.
   637  	//	t1 needs be deleted from deleteTableMap
   638  	db.getTxn().deletedTableMap.Delete(key)
   639  	return nil
   640  }
   641  
   642  func (db *txnDatabase) openSysTable(p *process.Process, id uint64, name string,
   643  	defs []engine.TableDef) engine.Relation {
   644  	tbl := &txnTable{
   645  		//AccountID for mo_tables, mo_database, mo_columns is always 0.
   646  		accountId:     0,
   647  		db:            db,
   648  		tableId:       id,
   649  		tableName:     name,
   650  		defs:          defs,
   651  		primaryIdx:    0,
   652  		primarySeqnum: db.getEng().getLatestCatalogCache().GetTableById(db.databaseId, id).PrimarySeqnum,
   653  		clusterByIdx:  -1,
   654  	}
   655  	switch name {
   656  	case catalog.MO_DATABASE:
   657  		tbl.constraint = catalog.MoDatabaseConstraint
   658  	case catalog.MO_TABLES:
   659  		tbl.constraint = catalog.MoTableConstraint
   660  	case catalog.MO_COLUMNS:
   661  		tbl.constraint = catalog.MoColumnConstraint
   662  	}
   663  	tbl.GetTableDef(context.TODO())
   664  	tbl.proc.Store(p)
   665  	return tbl
   666  }