github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/interlock/show.go (about)

     1  // Copyright 2020 WHTCORPS INC, 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 interlock
    15  
    16  import (
    17  	"bytes"
    18  	"context"
    19  	gjson "encoding/json"
    20  	"fmt"
    21  	"sort"
    22  	"strconv"
    23  	"strings"
    24  	"time"
    25  
    26  	"github.com/cznic/mathutil"
    27  	"github.com/whtcorpsinc/BerolinaSQL"
    28  	"github.com/whtcorpsinc/BerolinaSQL/allegrosql"
    29  	"github.com/whtcorpsinc/BerolinaSQL/ast"
    30  	"github.com/whtcorpsinc/BerolinaSQL/auth"
    31  	"github.com/whtcorpsinc/BerolinaSQL/charset"
    32  	"github.com/whtcorpsinc/BerolinaSQL/perceptron"
    33  	"github.com/whtcorpsinc/BerolinaSQL/terror"
    34  	"github.com/whtcorpsinc/errors"
    35  	"github.com/whtcorpsinc/milevadb-tools/milevadb-binlog/node"
    36  	"github.com/whtcorpsinc/milevadb-tools/pkg/etcd"
    37  	"github.com/whtcorpsinc/milevadb-tools/pkg/utils"
    38  	"github.com/whtcorpsinc/milevadb/bindinfo"
    39  	"github.com/whtcorpsinc/milevadb/causet"
    40  	"github.com/whtcorpsinc/milevadb/causet/blocks"
    41  	causetembedded "github.com/whtcorpsinc/milevadb/causet/embedded"
    42  	"github.com/whtcorpsinc/milevadb/causetstore/einsteindb"
    43  	"github.com/whtcorpsinc/milevadb/config"
    44  	"github.com/whtcorpsinc/milevadb/dbs"
    45  	"github.com/whtcorpsinc/milevadb/ekv"
    46  	"github.com/whtcorpsinc/milevadb/memex"
    47  	"github.com/whtcorpsinc/milevadb/petri"
    48  	"github.com/whtcorpsinc/milevadb/plugin"
    49  	"github.com/whtcorpsinc/milevadb/privilege"
    50  	"github.com/whtcorpsinc/milevadb/privilege/privileges"
    51  	"github.com/whtcorpsinc/milevadb/schemareplicant"
    52  	"github.com/whtcorpsinc/milevadb/soliton"
    53  	"github.com/whtcorpsinc/milevadb/soliton/chunk"
    54  	"github.com/whtcorpsinc/milevadb/soliton/defCauslate"
    55  	"github.com/whtcorpsinc/milevadb/soliton/format"
    56  	"github.com/whtcorpsinc/milevadb/soliton/hint"
    57  	"github.com/whtcorpsinc/milevadb/soliton/replog"
    58  	"github.com/whtcorpsinc/milevadb/soliton/set"
    59  	"github.com/whtcorpsinc/milevadb/soliton/sqlexec"
    60  	"github.com/whtcorpsinc/milevadb/soliton/stringutil"
    61  	"github.com/whtcorpsinc/milevadb/spacetime/autoid"
    62  	"github.com/whtcorpsinc/milevadb/stochastikctx"
    63  	"github.com/whtcorpsinc/milevadb/stochastikctx/stmtctx"
    64  	"github.com/whtcorpsinc/milevadb/stochastikctx/variable"
    65  	"github.com/whtcorpsinc/milevadb/types"
    66  	"github.com/whtcorpsinc/milevadb/types/json"
    67  )
    68  
    69  var etcdDialTimeout = 5 * time.Second
    70  
    71  // ShowInterDirc represents a show interlock.
    72  type ShowInterDirc struct {
    73  	baseInterlockingDirectorate
    74  
    75  	Tp             ast.ShowStmtType // Databases/Blocks/DeferredCausets/....
    76  	DBName         perceptron.CIStr
    77  	Block          *ast.BlockName          // Used for showing defCausumns.
    78  	DeferredCauset *ast.DeferredCausetName // Used for `desc causet defCausumn`.
    79  	IndexName      perceptron.CIStr        // Used for show causet regions.
    80  	Flag           int                     // Some flag parsed from allegrosql, such as FULL.
    81  	Roles          []*auth.RoleIdentity    // Used for show grants.
    82  	User           *auth.UserIdentity      // Used by show grants, show create user.
    83  
    84  	is schemareplicant.SchemaReplicant
    85  
    86  	result *chunk.Chunk
    87  	cursor int
    88  
    89  	Full        bool
    90  	IfNotExists bool // Used for `show create database if not exists`
    91  	GlobalScope bool // GlobalScope is used by show variables
    92  	Extended    bool // Used for `show extended defCausumns from ...`
    93  }
    94  
    95  // Next implements the InterlockingDirectorate Next interface.
    96  func (e *ShowInterDirc) Next(ctx context.Context, req *chunk.Chunk) error {
    97  	req.GrowAndReset(e.maxChunkSize)
    98  	if e.result == nil {
    99  		e.result = newFirstChunk(e)
   100  		err := e.fetchAll(ctx)
   101  		if err != nil {
   102  			return errors.Trace(err)
   103  		}
   104  		iter := chunk.NewIterator4Chunk(e.result)
   105  		for defCausIdx := 0; defCausIdx < e.Schema().Len(); defCausIdx++ {
   106  			retType := e.Schema().DeferredCausets[defCausIdx].RetType
   107  			if !types.IsTypeVarchar(retType.Tp) {
   108  				continue
   109  			}
   110  			for event := iter.Begin(); event != iter.End(); event = iter.Next() {
   111  				if valLen := len(event.GetString(defCausIdx)); retType.Flen < valLen {
   112  					retType.Flen = valLen
   113  				}
   114  			}
   115  		}
   116  	}
   117  	if e.cursor >= e.result.NumEvents() {
   118  		return nil
   119  	}
   120  	numCurBatch := mathutil.Min(req.Capacity(), e.result.NumEvents()-e.cursor)
   121  	req.Append(e.result, e.cursor, e.cursor+numCurBatch)
   122  	e.cursor += numCurBatch
   123  	return nil
   124  }
   125  
   126  func (e *ShowInterDirc) fetchAll(ctx context.Context) error {
   127  	switch e.Tp {
   128  	case ast.ShowCharset:
   129  		return e.fetchShowCharset()
   130  	case ast.ShowDefCauslation:
   131  		return e.fetchShowDefCauslation()
   132  	case ast.ShowDeferredCausets:
   133  		return e.fetchShowDeferredCausets(ctx)
   134  	case ast.ShowConfig:
   135  		return e.fetchShowClusterConfigs(ctx)
   136  	case ast.ShowCreateBlock:
   137  		return e.fetchShowCreateBlock()
   138  	case ast.ShowCreateSequence:
   139  		return e.fetchShowCreateSequence()
   140  	case ast.ShowCreateUser:
   141  		return e.fetchShowCreateUser()
   142  	case ast.ShowCreateView:
   143  		return e.fetchShowCreateView()
   144  	case ast.ShowCreateDatabase:
   145  		return e.fetchShowCreateDatabase()
   146  	case ast.ShowDatabases:
   147  		return e.fetchShowDatabases()
   148  	case ast.ShowDrainerStatus:
   149  		return e.fetchShowPumpOrDrainerStatus(node.DrainerNode)
   150  	case ast.ShowEngines:
   151  		return e.fetchShowEngines()
   152  	case ast.ShowGrants:
   153  		return e.fetchShowGrants()
   154  	case ast.ShowIndex:
   155  		return e.fetchShowIndex()
   156  	case ast.ShowProcedureStatus:
   157  		return e.fetchShowProcedureStatus()
   158  	case ast.ShowPumpStatus:
   159  		return e.fetchShowPumpOrDrainerStatus(node.PumpNode)
   160  	case ast.ShowStatus:
   161  		return e.fetchShowStatus()
   162  	case ast.ShowBlocks:
   163  		return e.fetchShowBlocks()
   164  	case ast.ShowOpenBlocks:
   165  		return e.fetchShowOpenBlocks()
   166  	case ast.ShowBlockStatus:
   167  		return e.fetchShowBlockStatus()
   168  	case ast.ShowTriggers:
   169  		return e.fetchShowTriggers()
   170  	case ast.ShowVariables:
   171  		return e.fetchShowVariables()
   172  	case ast.ShowWarnings:
   173  		return e.fetchShowWarnings(false)
   174  	case ast.ShowErrors:
   175  		return e.fetchShowWarnings(true)
   176  	case ast.ShowProcessList:
   177  		return e.fetchShowProcessList()
   178  	case ast.ShowEvents:
   179  		// empty result
   180  	case ast.ShowStatsMeta:
   181  		return e.fetchShowStatsMeta()
   182  	case ast.ShowStatsHistograms:
   183  		return e.fetchShowStatsHistogram()
   184  	case ast.ShowStatsBuckets:
   185  		return e.fetchShowStatsBuckets()
   186  	case ast.ShowStatsHealthy:
   187  		e.fetchShowStatsHealthy()
   188  		return nil
   189  	case ast.ShowPlugins:
   190  		return e.fetchShowPlugins()
   191  	case ast.ShowProfiles:
   192  		// empty result
   193  	case ast.ShowMasterStatus:
   194  		return e.fetchShowMasterStatus()
   195  	case ast.ShowPrivileges:
   196  		return e.fetchShowPrivileges()
   197  	case ast.ShowBindings:
   198  		return e.fetchShowBind()
   199  	case ast.ShowAnalyzeStatus:
   200  		e.fetchShowAnalyzeStatus()
   201  		return nil
   202  	case ast.ShowRegions:
   203  		return e.fetchShowBlockRegions()
   204  	case ast.ShowBuiltins:
   205  		return e.fetchShowBuiltins()
   206  	case ast.ShowBackups:
   207  		return e.fetchShowBRIE(ast.BRIEHoTTBackup)
   208  	case ast.ShowRestores:
   209  		return e.fetchShowBRIE(ast.BRIEHoTTRestore)
   210  	}
   211  	return nil
   212  }
   213  
   214  // visibleChecker checks if a stmt is visible for a certain user.
   215  type visibleChecker struct {
   216  	defaultDB string
   217  	ctx       stochastikctx.Context
   218  	is        schemareplicant.SchemaReplicant
   219  	manager   privilege.Manager
   220  	ok        bool
   221  }
   222  
   223  func (v *visibleChecker) Enter(in ast.Node) (out ast.Node, skipChildren bool) {
   224  	switch x := in.(type) {
   225  	case *ast.BlockName:
   226  		schemaReplicant := x.Schema.L
   227  		if schemaReplicant == "" {
   228  			schemaReplicant = v.defaultDB
   229  		}
   230  		if !v.is.BlockExists(perceptron.NewCIStr(schemaReplicant), x.Name) {
   231  			return in, true
   232  		}
   233  		activeRoles := v.ctx.GetStochastikVars().ActiveRoles
   234  		if v.manager != nil && !v.manager.RequestVerification(activeRoles, schemaReplicant, x.Name.L, "", allegrosql.SelectPriv) {
   235  			v.ok = false
   236  		}
   237  		return in, true
   238  	}
   239  	return in, false
   240  }
   241  
   242  func (v *visibleChecker) Leave(in ast.Node) (out ast.Node, ok bool) {
   243  	return in, true
   244  }
   245  
   246  func (e *ShowInterDirc) fetchShowBind() error {
   247  	var bindRecords []*bindinfo.BindRecord
   248  	if !e.GlobalScope {
   249  		handle := e.ctx.Value(bindinfo.StochastikBindInfoKeyType).(*bindinfo.StochastikHandle)
   250  		bindRecords = handle.GetAllBindRecord()
   251  	} else {
   252  		bindRecords = petri.GetPetri(e.ctx).BindHandle().GetAllBindRecord()
   253  	}
   254  	BerolinaSQL := BerolinaSQL.New()
   255  	for _, bindData := range bindRecords {
   256  		for _, hint := range bindData.Bindings {
   257  			stmt, err := BerolinaSQL.ParseOneStmt(hint.BindALLEGROSQL, hint.Charset, hint.DefCauslation)
   258  			if err != nil {
   259  				return err
   260  			}
   261  			checker := visibleChecker{
   262  				defaultDB: bindData.EDB,
   263  				ctx:       e.ctx,
   264  				is:        e.is,
   265  				manager:   privilege.GetPrivilegeManager(e.ctx),
   266  				ok:        true,
   267  			}
   268  			stmt.Accept(&checker)
   269  			if !checker.ok {
   270  				continue
   271  			}
   272  			e.appendEvent([]interface{}{
   273  				bindData.OriginalALLEGROSQL,
   274  				hint.BindALLEGROSQL,
   275  				bindData.EDB,
   276  				hint.Status,
   277  				hint.CreateTime,
   278  				hint.UFIDelateTime,
   279  				hint.Charset,
   280  				hint.DefCauslation,
   281  				hint.Source,
   282  			})
   283  		}
   284  	}
   285  	return nil
   286  }
   287  
   288  func (e *ShowInterDirc) fetchShowEngines() error {
   289  	allegrosql := `SELECT * FROM information_schema.engines`
   290  	rows, _, err := e.ctx.(sqlexec.RestrictedALLEGROSQLInterlockingDirectorate).InterDircRestrictedALLEGROSQL(allegrosql)
   291  
   292  	if err != nil {
   293  		return errors.Trace(err)
   294  	}
   295  	for _, event := range rows {
   296  		e.result.AppendEvent(event)
   297  	}
   298  	return nil
   299  }
   300  
   301  // moveSchemaReplicantToFront moves information_schema to the first, and the others are sorted in the origin ascending order.
   302  func moveSchemaReplicantToFront(dbs []string) {
   303  	if len(dbs) > 0 && strings.EqualFold(dbs[0], "INFORMATION_SCHEMA") {
   304  		return
   305  	}
   306  
   307  	i := sort.SearchStrings(dbs, "INFORMATION_SCHEMA")
   308  	if i < len(dbs) && strings.EqualFold(dbs[i], "INFORMATION_SCHEMA") {
   309  		copy(dbs[1:i+1], dbs[0:i])
   310  		dbs[0] = "INFORMATION_SCHEMA"
   311  	}
   312  }
   313  
   314  func (e *ShowInterDirc) fetchShowDatabases() error {
   315  	dbs := e.is.AllSchemaNames()
   316  	checker := privilege.GetPrivilegeManager(e.ctx)
   317  	sort.Strings(dbs)
   318  	// let information_schema be the first database
   319  	moveSchemaReplicantToFront(dbs)
   320  	for _, d := range dbs {
   321  		if checker != nil && !checker.DBIsVisible(e.ctx.GetStochastikVars().ActiveRoles, d) {
   322  			continue
   323  		}
   324  		e.appendEvent([]interface{}{
   325  			d,
   326  		})
   327  	}
   328  	return nil
   329  }
   330  
   331  func (e *ShowInterDirc) fetchShowProcessList() error {
   332  	sm := e.ctx.GetStochastikManager()
   333  	if sm == nil {
   334  		return nil
   335  	}
   336  
   337  	loginUser, activeRoles := e.ctx.GetStochastikVars().User, e.ctx.GetStochastikVars().ActiveRoles
   338  	var hasProcessPriv bool
   339  	if pm := privilege.GetPrivilegeManager(e.ctx); pm != nil {
   340  		if pm.RequestVerification(activeRoles, "", "", "", allegrosql.ProcessPriv) {
   341  			hasProcessPriv = true
   342  		}
   343  	}
   344  
   345  	pl := sm.ShowProcessList()
   346  	for _, pi := range pl {
   347  		// If you have the PROCESS privilege, you can see all threads.
   348  		// Otherwise, you can see only your own threads.
   349  		if !hasProcessPriv && pi.User != loginUser.Username {
   350  			continue
   351  		}
   352  		event := pi.ToEventForShow(e.Full)
   353  		e.appendEvent(event)
   354  	}
   355  	return nil
   356  }
   357  
   358  func (e *ShowInterDirc) fetchShowOpenBlocks() error {
   359  	// MilevaDB has no concept like allegrosql's "causet cache" and "open causet"
   360  	// For simplicity, we just return an empty result with the same structure as MyALLEGROSQL's SHOW OPEN TABLES
   361  	return nil
   362  }
   363  
   364  func (e *ShowInterDirc) fetchShowBlocks() error {
   365  	checker := privilege.GetPrivilegeManager(e.ctx)
   366  	if checker != nil && e.ctx.GetStochastikVars().User != nil {
   367  		if !checker.DBIsVisible(e.ctx.GetStochastikVars().ActiveRoles, e.DBName.O) {
   368  			return e.dbAccessDenied()
   369  		}
   370  	}
   371  	if !e.is.SchemaExists(e.DBName) {
   372  		return ErrBadDB.GenWithStackByArgs(e.DBName)
   373  	}
   374  	// sort for blocks
   375  	blockNames := make([]string, 0, len(e.is.SchemaBlocks(e.DBName)))
   376  	activeRoles := e.ctx.GetStochastikVars().ActiveRoles
   377  	var blockTypes = make(map[string]string)
   378  	for _, v := range e.is.SchemaBlocks(e.DBName) {
   379  		// Test with allegrosql.AllPrivMask means any privilege would be OK.
   380  		// TODO: Should consider defCausumn privileges, which also make a causet visible.
   381  		if checker != nil && !checker.RequestVerification(activeRoles, e.DBName.O, v.Meta().Name.O, "", allegrosql.AllPrivMask) {
   382  			continue
   383  		}
   384  		blockNames = append(blockNames, v.Meta().Name.O)
   385  		if v.Meta().IsView() {
   386  			blockTypes[v.Meta().Name.O] = "VIEW"
   387  		} else if v.Meta().IsSequence() {
   388  			blockTypes[v.Meta().Name.O] = "SEQUENCE"
   389  		} else if soliton.IsSystemView(e.DBName.L) {
   390  			blockTypes[v.Meta().Name.O] = "SYSTEM VIEW"
   391  		} else {
   392  			blockTypes[v.Meta().Name.O] = "BASE TABLE"
   393  		}
   394  	}
   395  	sort.Strings(blockNames)
   396  	for _, v := range blockNames {
   397  		if e.Full {
   398  			e.appendEvent([]interface{}{v, blockTypes[v]})
   399  		} else {
   400  			e.appendEvent([]interface{}{v})
   401  		}
   402  	}
   403  	return nil
   404  }
   405  
   406  func (e *ShowInterDirc) fetchShowBlockStatus() error {
   407  	checker := privilege.GetPrivilegeManager(e.ctx)
   408  	if checker != nil && e.ctx.GetStochastikVars().User != nil {
   409  		if !checker.DBIsVisible(e.ctx.GetStochastikVars().ActiveRoles, e.DBName.O) {
   410  			return e.dbAccessDenied()
   411  		}
   412  	}
   413  	if !e.is.SchemaExists(e.DBName) {
   414  		return ErrBadDB.GenWithStackByArgs(e.DBName)
   415  	}
   416  
   417  	allegrosql := fmt.Sprintf(`SELECT
   418                 block_name, engine, version, row_format, block_rows,
   419                 avg_row_length, data_length, max_data_length, index_length,
   420                 data_free, auto_increment, create_time, uFIDelate_time, check_time,
   421                 block_defCauslation, IFNULL(checksum,''), create_options, block_comment
   422                 FROM information_schema.blocks
   423  	       WHERE block_schema='%s' ORDER BY block_name`, e.DBName)
   424  
   425  	rows, _, err := e.ctx.(sqlexec.RestrictedALLEGROSQLInterlockingDirectorate).InterDircRestrictedALLEGROSQLWithSnapshot(allegrosql)
   426  
   427  	if err != nil {
   428  		return errors.Trace(err)
   429  	}
   430  
   431  	activeRoles := e.ctx.GetStochastikVars().ActiveRoles
   432  	for _, event := range rows {
   433  		if checker != nil && !checker.RequestVerification(activeRoles, e.DBName.O, event.GetString(0), "", allegrosql.AllPrivMask) {
   434  			continue
   435  		}
   436  		e.result.AppendEvent(event)
   437  
   438  	}
   439  	return nil
   440  }
   441  
   442  func (e *ShowInterDirc) fetchShowDeferredCausets(ctx context.Context) error {
   443  	tb, err := e.getBlock()
   444  
   445  	if err != nil {
   446  		return errors.Trace(err)
   447  	}
   448  	checker := privilege.GetPrivilegeManager(e.ctx)
   449  	activeRoles := e.ctx.GetStochastikVars().ActiveRoles
   450  	if checker != nil && e.ctx.GetStochastikVars().User != nil && !checker.RequestVerification(activeRoles, e.DBName.O, tb.Meta().Name.O, "", allegrosql.AllPrivMask) {
   451  		return e.blockAccessDenied("SELECT", tb.Meta().Name.O)
   452  	}
   453  
   454  	var defcaus []*causet.DeferredCauset
   455  	// The optional EXTENDED keyword causes the output to include information about hidden defCausumns that MyALLEGROSQL uses internally and are not accessible by users.
   456  	// See https://dev.allegrosql.com/doc/refman/8.0/en/show-defCausumns.html
   457  	if e.Extended {
   458  		defcaus = tb.DefCauss()
   459  	} else {
   460  		defcaus = tb.VisibleDefCauss()
   461  	}
   462  	if tb.Meta().IsView() {
   463  		// Because view's underblock's defCausumn could change or recreate, so view's defCausumn type may change overtime.
   464  		// To avoid this situation we need to generate a logical plan and extract current defCausumn types from Schema.
   465  		planBuilder := causetembedded.NewCausetBuilder(e.ctx, e.is, &hint.BlockHintProcessor{})
   466  		viewLogicalCauset, err := planBuilder.BuildDataSourceFromView(ctx, e.DBName, tb.Meta())
   467  		if err != nil {
   468  			return err
   469  		}
   470  		viewSchema := viewLogicalCauset.Schema()
   471  		viewOutputNames := viewLogicalCauset.OutputNames()
   472  		for _, defCaus := range defcaus {
   473  			idx := memex.FindFieldNameIdxByDefCausName(viewOutputNames, defCaus.Name.L)
   474  			if idx >= 0 {
   475  				defCaus.FieldType = *viewSchema.DeferredCausets[idx].GetType()
   476  			}
   477  		}
   478  	}
   479  	for _, defCaus := range defcaus {
   480  		if e.DeferredCauset != nil && e.DeferredCauset.Name.L != defCaus.Name.L {
   481  			continue
   482  		}
   483  
   484  		desc := causet.NewDefCausDesc(defCaus)
   485  		var defCausumnDefault interface{}
   486  		if desc.DefaultValue != nil {
   487  			// SHOW COLUMNS result expects string value
   488  			defaultValStr := fmt.Sprintf("%v", desc.DefaultValue)
   489  			// If defCausumn is timestamp, and default value is not current_timestamp, should convert the default value to the current stochastik time zone.
   490  			if defCaus.Tp == allegrosql.TypeTimestamp && defaultValStr != types.ZeroDatetimeStr && !strings.HasPrefix(strings.ToUpper(defaultValStr), strings.ToUpper(ast.CurrentTimestamp)) {
   491  				timeValue, err := causet.GetDefCausDefaultValue(e.ctx, defCaus.ToInfo())
   492  				if err != nil {
   493  					return errors.Trace(err)
   494  				}
   495  				defaultValStr = timeValue.GetMysqlTime().String()
   496  			}
   497  			if defCaus.Tp == allegrosql.TypeBit {
   498  				defaultValBinaryLiteral := types.BinaryLiteral(defaultValStr)
   499  				defCausumnDefault = defaultValBinaryLiteral.ToBitLiteralString(true)
   500  			} else {
   501  				defCausumnDefault = defaultValStr
   502  			}
   503  		}
   504  
   505  		// The FULL keyword causes the output to include the defCausumn defCauslation and comments,
   506  		// as well as the privileges you have for each defCausumn.
   507  		if e.Full {
   508  			e.appendEvent([]interface{}{
   509  				desc.Field,
   510  				desc.Type,
   511  				desc.DefCauslation,
   512  				desc.Null,
   513  				desc.Key,
   514  				defCausumnDefault,
   515  				desc.Extra,
   516  				desc.Privileges,
   517  				desc.Comment,
   518  			})
   519  		} else {
   520  			e.appendEvent([]interface{}{
   521  				desc.Field,
   522  				desc.Type,
   523  				desc.Null,
   524  				desc.Key,
   525  				defCausumnDefault,
   526  				desc.Extra,
   527  			})
   528  		}
   529  	}
   530  	return nil
   531  }
   532  
   533  func (e *ShowInterDirc) fetchShowIndex() error {
   534  	tb, err := e.getBlock()
   535  	if err != nil {
   536  		return errors.Trace(err)
   537  	}
   538  
   539  	checker := privilege.GetPrivilegeManager(e.ctx)
   540  	activeRoles := e.ctx.GetStochastikVars().ActiveRoles
   541  	if checker != nil && e.ctx.GetStochastikVars().User != nil && !checker.RequestVerification(activeRoles, e.DBName.O, tb.Meta().Name.O, "", allegrosql.AllPrivMask) {
   542  		return e.blockAccessDenied("SELECT", tb.Meta().Name.O)
   543  	}
   544  
   545  	if tb.Meta().PKIsHandle {
   546  		var pkDefCaus *causet.DeferredCauset
   547  		for _, defCaus := range tb.DefCauss() {
   548  			if allegrosql.HasPriKeyFlag(defCaus.Flag) {
   549  				pkDefCaus = defCaus
   550  				break
   551  			}
   552  		}
   553  		e.appendEvent([]interface{}{
   554  			tb.Meta().Name.O, // Block
   555  			0,                // Non_unique
   556  			"PRIMARY",        // Key_name
   557  			1,                // Seq_in_index
   558  			pkDefCaus.Name.O, // DeferredCauset_name
   559  			"A",              // DefCauslation
   560  			0,                // Cardinality
   561  			nil,              // Sub_part
   562  			nil,              // Packed
   563  			"",               // Null
   564  			"BTREE",          // Index_type
   565  			"",               // Comment
   566  			"",               // Index_comment
   567  			"YES",            // Index_visible
   568  			"NULL",           // Expression
   569  		})
   570  	}
   571  	for _, idx := range tb.Indices() {
   572  		idxInfo := idx.Meta()
   573  		if idxInfo.State != perceptron.StatePublic {
   574  			continue
   575  		}
   576  		for i, defCaus := range idxInfo.DeferredCausets {
   577  			nonUniq := 1
   578  			if idx.Meta().Unique {
   579  				nonUniq = 0
   580  			}
   581  
   582  			var subPart interface{}
   583  			if defCaus.Length != types.UnspecifiedLength {
   584  				subPart = defCaus.Length
   585  			}
   586  
   587  			nullVal := "YES"
   588  			if idx.Meta().Name.O == allegrosql.PrimaryKeyName {
   589  				nullVal = ""
   590  			}
   591  
   592  			visible := "YES"
   593  			if idx.Meta().Invisible {
   594  				visible = "NO"
   595  			}
   596  
   597  			defCausName := defCaus.Name.O
   598  			memex := "NULL"
   599  			tblDefCaus := tb.Meta().DeferredCausets[defCaus.Offset]
   600  			if tblDefCaus.Hidden {
   601  				defCausName = "NULL"
   602  				memex = fmt.Sprintf("(%s)", tblDefCaus.GeneratedExprString)
   603  			}
   604  
   605  			e.appendEvent([]interface{}{
   606  				tb.Meta().Name.O,       // Block
   607  				nonUniq,                // Non_unique
   608  				idx.Meta().Name.O,      // Key_name
   609  				i + 1,                  // Seq_in_index
   610  				defCausName,            // DeferredCauset_name
   611  				"A",                    // DefCauslation
   612  				0,                      // Cardinality
   613  				subPart,                // Sub_part
   614  				nil,                    // Packed
   615  				nullVal,                // Null
   616  				idx.Meta().Tp.String(), // Index_type
   617  				"",                     // Comment
   618  				idx.Meta().Comment,     // Index_comment
   619  				visible,                // Index_visible
   620  				memex,                  // Expression
   621  			})
   622  		}
   623  	}
   624  	return nil
   625  }
   626  
   627  // fetchShowCharset gets all charset information and fill them into e.rows.
   628  // See http://dev.allegrosql.com/doc/refman/5.7/en/show-character-set.html
   629  func (e *ShowInterDirc) fetchShowCharset() error {
   630  	descs := charset.GetSupportedCharsets()
   631  	for _, desc := range descs {
   632  		e.appendEvent([]interface{}{
   633  			desc.Name,
   634  			desc.Desc,
   635  			desc.DefaultDefCauslation,
   636  			desc.Maxlen,
   637  		})
   638  	}
   639  	return nil
   640  }
   641  
   642  func (e *ShowInterDirc) fetchShowMasterStatus() error {
   643  	tso := e.ctx.GetStochastikVars().TxnCtx.StartTS
   644  	e.appendEvent([]interface{}{"milevadb-binlog", tso, "", "", ""})
   645  	return nil
   646  }
   647  
   648  func (e *ShowInterDirc) fetchShowVariables() (err error) {
   649  	var (
   650  		value          string
   651  		ok             bool
   652  		stochastikVars = e.ctx.GetStochastikVars()
   653  		unreachedVars  = make([]string, 0, len(variable.SysVars))
   654  	)
   655  	for _, v := range variable.SysVars {
   656  		if !e.GlobalScope {
   657  			// For a stochastik scope variable,
   658  			// 1. try to fetch value from StochastikVars.Systems;
   659  			// 2. if this variable is stochastik-only, fetch value from SysVars
   660  			//		otherwise, fetch the value from causet `allegrosql.Global_Variables`.
   661  			value, ok, err = variable.GetStochastikOnlySysVars(stochastikVars, v.Name)
   662  		} else {
   663  			// If the scope of a system variable is ScopeNone,
   664  			// it's a read-only variable, so we return the default value of it.
   665  			// Otherwise, we have to fetch the values from causet `allegrosql.Global_Variables` for global variable names.
   666  			value, ok, err = variable.GetScopeNoneSystemVar(v.Name)
   667  		}
   668  		if err != nil {
   669  			return errors.Trace(err)
   670  		}
   671  		if !ok {
   672  			unreachedVars = append(unreachedVars, v.Name)
   673  			continue
   674  		}
   675  		e.appendEvent([]interface{}{v.Name, value})
   676  	}
   677  	if len(unreachedVars) != 0 {
   678  		systemVars, err := stochastikVars.GlobalVarsAccessor.GetAllSysVars()
   679  		if err != nil {
   680  			return errors.Trace(err)
   681  		}
   682  		for _, varName := range unreachedVars {
   683  			varValue, ok := systemVars[varName]
   684  			if !ok {
   685  				varValue = variable.SysVars[varName].Value
   686  			}
   687  			e.appendEvent([]interface{}{varName, varValue})
   688  		}
   689  	}
   690  	return nil
   691  }
   692  
   693  func (e *ShowInterDirc) fetchShowStatus() error {
   694  	stochastikVars := e.ctx.GetStochastikVars()
   695  	statusVars, err := variable.GetStatusVars(stochastikVars)
   696  	if err != nil {
   697  		return errors.Trace(err)
   698  	}
   699  	for status, v := range statusVars {
   700  		if e.GlobalScope && v.Scope == variable.ScopeStochastik {
   701  			continue
   702  		}
   703  		switch v.Value.(type) {
   704  		case []interface{}, nil:
   705  			v.Value = fmt.Sprintf("%v", v.Value)
   706  		}
   707  		value, err := types.ToString(v.Value)
   708  		if err != nil {
   709  			return errors.Trace(err)
   710  		}
   711  		e.appendEvent([]interface{}{status, value})
   712  	}
   713  	return nil
   714  }
   715  
   716  func getDefaultDefCauslate(charsetName string) string {
   717  	for _, c := range charset.GetSupportedCharsets() {
   718  		if strings.EqualFold(c.Name, charsetName) {
   719  			return c.DefaultDefCauslation
   720  		}
   721  	}
   722  	return ""
   723  }
   724  
   725  // ConstructResultOfShowCreateBlock constructs the result for show create causet.
   726  func ConstructResultOfShowCreateBlock(ctx stochastikctx.Context, blockInfo *perceptron.BlockInfo, allocators autoid.SlabPredictors, buf *bytes.Buffer) (err error) {
   727  	if blockInfo.IsView() {
   728  		fetchShowCreateBlock4View(ctx, blockInfo, buf)
   729  		return nil
   730  	}
   731  	if blockInfo.IsSequence() {
   732  		ConstructResultOfShowCreateSequence(ctx, blockInfo, buf)
   733  		return nil
   734  	}
   735  
   736  	tblCharset := blockInfo.Charset
   737  	if len(tblCharset) == 0 {
   738  		tblCharset = allegrosql.DefaultCharset
   739  	}
   740  	tblDefCauslate := blockInfo.DefCauslate
   741  	// Set default defCauslate if defCauslate is not specified.
   742  	if len(tblDefCauslate) == 0 {
   743  		tblDefCauslate = getDefaultDefCauslate(tblCharset)
   744  	}
   745  
   746  	sqlMode := ctx.GetStochastikVars().ALLEGROSQLMode
   747  	fmt.Fprintf(buf, "CREATE TABLE %s (\n", stringutil.Escape(blockInfo.Name.O, sqlMode))
   748  	var pkDefCaus *perceptron.DeferredCausetInfo
   749  	var hasAutoIncID bool
   750  	needAddComma := false
   751  	for i, defCaus := range blockInfo.DefCauss() {
   752  		if defCaus.Hidden {
   753  			continue
   754  		}
   755  		if needAddComma {
   756  			buf.WriteString(",\n")
   757  		}
   758  		fmt.Fprintf(buf, "  %s %s", stringutil.Escape(defCaus.Name.O, sqlMode), defCaus.GetTypeDesc())
   759  		if defCaus.Charset != "binary" {
   760  			if defCaus.Charset != tblCharset {
   761  				fmt.Fprintf(buf, " CHARACTER SET %s", defCaus.Charset)
   762  			}
   763  			if defCaus.DefCauslate != tblDefCauslate {
   764  				fmt.Fprintf(buf, " COLLATE %s", defCaus.DefCauslate)
   765  			} else {
   766  				defdefCaus, err := charset.GetDefaultDefCauslation(defCaus.Charset)
   767  				if err == nil && defdefCaus != defCaus.DefCauslate {
   768  					fmt.Fprintf(buf, " COLLATE %s", defCaus.DefCauslate)
   769  				}
   770  			}
   771  		}
   772  		if defCaus.IsGenerated() {
   773  			// It's a generated defCausumn.
   774  			fmt.Fprintf(buf, " GENERATED ALWAYS AS (%s)", defCaus.GeneratedExprString)
   775  			if defCaus.GeneratedStored {
   776  				buf.WriteString(" STORED")
   777  			} else {
   778  				buf.WriteString(" VIRTUAL")
   779  			}
   780  		}
   781  		if allegrosql.HasAutoIncrementFlag(defCaus.Flag) {
   782  			hasAutoIncID = true
   783  			buf.WriteString(" NOT NULL AUTO_INCREMENT")
   784  		} else {
   785  			if allegrosql.HasNotNullFlag(defCaus.Flag) {
   786  				buf.WriteString(" NOT NULL")
   787  			}
   788  			// default values are not shown for generated defCausumns in MyALLEGROSQL
   789  			if !allegrosql.HasNoDefaultValueFlag(defCaus.Flag) && !defCaus.IsGenerated() {
   790  				defaultValue := defCaus.GetDefaultValue()
   791  				switch defaultValue {
   792  				case nil:
   793  					if !allegrosql.HasNotNullFlag(defCaus.Flag) {
   794  						if defCaus.Tp == allegrosql.TypeTimestamp {
   795  							buf.WriteString(" NULL")
   796  						}
   797  						buf.WriteString(" DEFAULT NULL")
   798  					}
   799  				case "CURRENT_TIMESTAMP":
   800  					buf.WriteString(" DEFAULT CURRENT_TIMESTAMP")
   801  					if defCaus.Decimal > 0 {
   802  						buf.WriteString(fmt.Sprintf("(%d)", defCaus.Decimal))
   803  					}
   804  				default:
   805  					defaultValStr := fmt.Sprintf("%v", defaultValue)
   806  					// If defCausumn is timestamp, and default value is not current_timestamp, should convert the default value to the current stochastik time zone.
   807  					if defCaus.Tp == allegrosql.TypeTimestamp && defaultValStr != types.ZeroDatetimeStr {
   808  						timeValue, err := causet.GetDefCausDefaultValue(ctx, defCaus)
   809  						if err != nil {
   810  							return errors.Trace(err)
   811  						}
   812  						defaultValStr = timeValue.GetMysqlTime().String()
   813  					}
   814  
   815  					if defCaus.Tp == allegrosql.TypeBit {
   816  						defaultValBinaryLiteral := types.BinaryLiteral(defaultValStr)
   817  						fmt.Fprintf(buf, " DEFAULT %s", defaultValBinaryLiteral.ToBitLiteralString(true))
   818  					} else if types.IsTypeNumeric(defCaus.Tp) || defCaus.DefaultIsExpr {
   819  						fmt.Fprintf(buf, " DEFAULT %s", format.OutputFormat(defaultValStr))
   820  					} else {
   821  						fmt.Fprintf(buf, " DEFAULT '%s'", format.OutputFormat(defaultValStr))
   822  					}
   823  				}
   824  			}
   825  			if allegrosql.HasOnUFIDelateNowFlag(defCaus.Flag) {
   826  				buf.WriteString(" ON UFIDelATE CURRENT_TIMESTAMP")
   827  				buf.WriteString(causet.OptionalFsp(&defCaus.FieldType))
   828  			}
   829  		}
   830  		if dbs.IsAutoRandomDeferredCausetID(blockInfo, defCaus.ID) {
   831  			buf.WriteString(fmt.Sprintf(" /*T![auto_rand] AUTO_RANDOM(%d) */", blockInfo.AutoRandomBits))
   832  		}
   833  		if len(defCaus.Comment) > 0 {
   834  			buf.WriteString(fmt.Sprintf(" COMMENT '%s'", format.OutputFormat(defCaus.Comment)))
   835  		}
   836  		if i != len(blockInfo.DefCauss())-1 {
   837  			needAddComma = true
   838  		}
   839  		if blockInfo.PKIsHandle && allegrosql.HasPriKeyFlag(defCaus.Flag) {
   840  			pkDefCaus = defCaus
   841  		}
   842  	}
   843  
   844  	if pkDefCaus != nil {
   845  		// If PKIsHanle, pk info is not in tb.Indices(). We should handle it here.
   846  		buf.WriteString(",\n")
   847  		fmt.Fprintf(buf, "  PRIMARY KEY (%s)", stringutil.Escape(pkDefCaus.Name.O, sqlMode))
   848  	}
   849  
   850  	publicIndices := make([]*perceptron.IndexInfo, 0, len(blockInfo.Indices))
   851  	for _, idx := range blockInfo.Indices {
   852  		if idx.State == perceptron.StatePublic {
   853  			publicIndices = append(publicIndices, idx)
   854  		}
   855  	}
   856  	if len(publicIndices) > 0 {
   857  		buf.WriteString(",\n")
   858  	}
   859  
   860  	for i, idxInfo := range publicIndices {
   861  		if idxInfo.Primary {
   862  			buf.WriteString("  PRIMARY KEY ")
   863  		} else if idxInfo.Unique {
   864  			fmt.Fprintf(buf, "  UNIQUE KEY %s ", stringutil.Escape(idxInfo.Name.O, sqlMode))
   865  		} else {
   866  			fmt.Fprintf(buf, "  KEY %s ", stringutil.Escape(idxInfo.Name.O, sqlMode))
   867  		}
   868  
   869  		defcaus := make([]string, 0, len(idxInfo.DeferredCausets))
   870  		var defCausInfo string
   871  		for _, c := range idxInfo.DeferredCausets {
   872  			if blockInfo.DeferredCausets[c.Offset].Hidden {
   873  				defCausInfo = fmt.Sprintf("(%s)", blockInfo.DeferredCausets[c.Offset].GeneratedExprString)
   874  			} else {
   875  				defCausInfo = stringutil.Escape(c.Name.O, sqlMode)
   876  				if c.Length != types.UnspecifiedLength {
   877  					defCausInfo = fmt.Sprintf("%s(%s)", defCausInfo, strconv.Itoa(c.Length))
   878  				}
   879  			}
   880  			defcaus = append(defcaus, defCausInfo)
   881  		}
   882  		fmt.Fprintf(buf, "(%s)", strings.Join(defcaus, ","))
   883  		if idxInfo.Invisible {
   884  			fmt.Fprintf(buf, ` /*!80000 INVISIBLE */`)
   885  		}
   886  		if i != len(publicIndices)-1 {
   887  			buf.WriteString(",\n")
   888  		}
   889  	}
   890  
   891  	// Foreign Keys are supported by data dictionary even though
   892  	// they are not enforced by DBS. This is still helpful to applications.
   893  	for _, fk := range blockInfo.ForeignKeys {
   894  		buf.WriteString(fmt.Sprintf(",\n  CONSTRAINT %s FOREIGN KEY ", stringutil.Escape(fk.Name.O, sqlMode)))
   895  		defCausNames := make([]string, 0, len(fk.DefCauss))
   896  		for _, defCaus := range fk.DefCauss {
   897  			defCausNames = append(defCausNames, stringutil.Escape(defCaus.O, sqlMode))
   898  		}
   899  		buf.WriteString(fmt.Sprintf("(%s)", strings.Join(defCausNames, ",")))
   900  		buf.WriteString(fmt.Sprintf(" REFERENCES %s ", stringutil.Escape(fk.RefBlock.O, sqlMode)))
   901  		refDefCausNames := make([]string, 0, len(fk.DefCauss))
   902  		for _, refDefCaus := range fk.RefDefCauss {
   903  			refDefCausNames = append(refDefCausNames, stringutil.Escape(refDefCaus.O, sqlMode))
   904  		}
   905  		buf.WriteString(fmt.Sprintf("(%s)", strings.Join(refDefCausNames, ",")))
   906  		if ast.ReferOptionType(fk.OnDelete) != 0 {
   907  			buf.WriteString(fmt.Sprintf(" ON DELETE %s", ast.ReferOptionType(fk.OnDelete).String()))
   908  		}
   909  		if ast.ReferOptionType(fk.OnUFIDelate) != 0 {
   910  			buf.WriteString(fmt.Sprintf(" ON UFIDelATE %s", ast.ReferOptionType(fk.OnUFIDelate).String()))
   911  		}
   912  	}
   913  
   914  	buf.WriteString("\n")
   915  
   916  	buf.WriteString(") ENGINE=InnoDB")
   917  	// We need to explicitly set the default charset and defCauslation
   918  	// to make it work on MyALLEGROSQL server which has default defCauslate utf8_general_ci.
   919  	if len(tblDefCauslate) == 0 || tblDefCauslate == "binary" {
   920  		// If we can not find default defCauslate for the given charset,
   921  		// or the defCauslate is 'binary'(MyALLEGROSQL-5.7 compatibility, see #15633 for details),
   922  		// do not show the defCauslate part.
   923  		fmt.Fprintf(buf, " DEFAULT CHARSET=%s", tblCharset)
   924  	} else {
   925  		fmt.Fprintf(buf, " DEFAULT CHARSET=%s COLLATE=%s", tblCharset, tblDefCauslate)
   926  	}
   927  
   928  	// Displayed if the compression typed is set.
   929  	if len(blockInfo.Compression) != 0 {
   930  		fmt.Fprintf(buf, " COMPRESSION='%s'", blockInfo.Compression)
   931  	}
   932  
   933  	incrementSlabPredictor := allocators.Get(autoid.EventIDAllocType)
   934  	if hasAutoIncID && incrementSlabPredictor != nil {
   935  		autoIncID, err := incrementSlabPredictor.NextGlobalAutoID(blockInfo.ID)
   936  		if err != nil {
   937  			return errors.Trace(err)
   938  		}
   939  
   940  		// It's compatible with MyALLEGROSQL.
   941  		if autoIncID > 1 {
   942  			fmt.Fprintf(buf, " AUTO_INCREMENT=%d", autoIncID)
   943  		}
   944  	}
   945  
   946  	if blockInfo.AutoIdCache != 0 {
   947  		fmt.Fprintf(buf, " /*T![auto_id_cache] AUTO_ID_CACHE=%d */", blockInfo.AutoIdCache)
   948  	}
   949  
   950  	randomSlabPredictor := allocators.Get(autoid.AutoRandomType)
   951  	if randomSlabPredictor != nil {
   952  		autoRandID, err := randomSlabPredictor.NextGlobalAutoID(blockInfo.ID)
   953  		if err != nil {
   954  			return errors.Trace(err)
   955  		}
   956  
   957  		if autoRandID > 1 {
   958  			fmt.Fprintf(buf, " /*T![auto_rand_base] AUTO_RANDOM_BASE=%d */", autoRandID)
   959  		}
   960  	}
   961  
   962  	if blockInfo.ShardEventIDBits > 0 {
   963  		fmt.Fprintf(buf, "/*!90000 SHARD_ROW_ID_BITS=%d ", blockInfo.ShardEventIDBits)
   964  		if blockInfo.PreSplitRegions > 0 {
   965  			fmt.Fprintf(buf, "PRE_SPLIT_REGIONS=%d ", blockInfo.PreSplitRegions)
   966  		}
   967  		buf.WriteString("*/")
   968  	}
   969  
   970  	if len(blockInfo.Comment) > 0 {
   971  		fmt.Fprintf(buf, " COMMENT='%s'", format.OutputFormat(blockInfo.Comment))
   972  	}
   973  	// add partition info here.
   974  	appendPartitionInfo(blockInfo.Partition, buf)
   975  	return nil
   976  }
   977  
   978  // ConstructResultOfShowCreateSequence constructs the result for show create sequence.
   979  func ConstructResultOfShowCreateSequence(ctx stochastikctx.Context, blockInfo *perceptron.BlockInfo, buf *bytes.Buffer) {
   980  	sqlMode := ctx.GetStochastikVars().ALLEGROSQLMode
   981  	fmt.Fprintf(buf, "CREATE SEQUENCE %s ", stringutil.Escape(blockInfo.Name.O, sqlMode))
   982  	sequenceInfo := blockInfo.Sequence
   983  	fmt.Fprintf(buf, "start with %d ", sequenceInfo.Start)
   984  	fmt.Fprintf(buf, "minvalue %d ", sequenceInfo.MinValue)
   985  	fmt.Fprintf(buf, "maxvalue %d ", sequenceInfo.MaxValue)
   986  	fmt.Fprintf(buf, "increment by %d ", sequenceInfo.Increment)
   987  	if sequenceInfo.Cache {
   988  		fmt.Fprintf(buf, "cache %d ", sequenceInfo.CacheValue)
   989  	} else {
   990  		buf.WriteString("nocache ")
   991  	}
   992  	if sequenceInfo.Cycle {
   993  		buf.WriteString("cycle ")
   994  	} else {
   995  		buf.WriteString("nocycle ")
   996  	}
   997  	buf.WriteString("ENGINE=InnoDB")
   998  	if len(sequenceInfo.Comment) > 0 {
   999  		fmt.Fprintf(buf, " COMMENT='%s'", format.OutputFormat(sequenceInfo.Comment))
  1000  	}
  1001  }
  1002  
  1003  func (e *ShowInterDirc) fetchShowCreateSequence() error {
  1004  	tbl, err := e.getBlock()
  1005  	if err != nil {
  1006  		return errors.Trace(err)
  1007  	}
  1008  	blockInfo := tbl.Meta()
  1009  	if !blockInfo.IsSequence() {
  1010  		return ErrWrongObject.GenWithStackByArgs(e.DBName.O, blockInfo.Name.O, "SEQUENCE")
  1011  	}
  1012  	var buf bytes.Buffer
  1013  	ConstructResultOfShowCreateSequence(e.ctx, blockInfo, &buf)
  1014  	e.appendEvent([]interface{}{blockInfo.Name.O, buf.String()})
  1015  	return nil
  1016  }
  1017  
  1018  // TestShowClusterConfigKey is the key used to causetstore TestShowClusterConfigFunc.
  1019  var TestShowClusterConfigKey stringutil.StringerStr = "TestShowClusterConfigKey"
  1020  
  1021  // TestShowClusterConfigFunc is used to test 'show config ...'.
  1022  type TestShowClusterConfigFunc func() ([][]types.Causet, error)
  1023  
  1024  func (e *ShowInterDirc) fetchShowClusterConfigs(ctx context.Context) error {
  1025  	emptySet := set.NewStringSet()
  1026  	var confItems [][]types.Causet
  1027  	var err error
  1028  	if f := e.ctx.Value(TestShowClusterConfigKey); f != nil {
  1029  		confItems, err = f.(TestShowClusterConfigFunc)()
  1030  	} else {
  1031  		confItems, err = fetchClusterConfig(e.ctx, emptySet, emptySet)
  1032  	}
  1033  	if err != nil {
  1034  		return err
  1035  	}
  1036  	for _, items := range confItems {
  1037  		event := make([]interface{}, 0, 4)
  1038  		for _, item := range items {
  1039  			event = append(event, item.GetString())
  1040  		}
  1041  		e.appendEvent(event)
  1042  	}
  1043  	return nil
  1044  }
  1045  
  1046  func (e *ShowInterDirc) fetchShowCreateBlock() error {
  1047  	tb, err := e.getBlock()
  1048  	if err != nil {
  1049  		return errors.Trace(err)
  1050  	}
  1051  
  1052  	blockInfo := tb.Meta()
  1053  	var buf bytes.Buffer
  1054  	// TODO: let the result more like MyALLEGROSQL.
  1055  	if err = ConstructResultOfShowCreateBlock(e.ctx, blockInfo, tb.SlabPredictors(e.ctx), &buf); err != nil {
  1056  		return err
  1057  	}
  1058  	if blockInfo.IsView() {
  1059  		e.appendEvent([]interface{}{blockInfo.Name.O, buf.String(), blockInfo.Charset, blockInfo.DefCauslate})
  1060  		return nil
  1061  	}
  1062  
  1063  	e.appendEvent([]interface{}{blockInfo.Name.O, buf.String()})
  1064  	return nil
  1065  }
  1066  
  1067  func (e *ShowInterDirc) fetchShowCreateView() error {
  1068  	EDB, ok := e.is.SchemaByName(e.DBName)
  1069  	if !ok {
  1070  		return schemareplicant.ErrDatabaseNotExists.GenWithStackByArgs(e.DBName.O)
  1071  	}
  1072  
  1073  	tb, err := e.getBlock()
  1074  	if err != nil {
  1075  		return errors.Trace(err)
  1076  	}
  1077  
  1078  	if !tb.Meta().IsView() {
  1079  		return ErrWrongObject.GenWithStackByArgs(EDB.Name.O, tb.Meta().Name.O, "VIEW")
  1080  	}
  1081  
  1082  	var buf bytes.Buffer
  1083  	fetchShowCreateBlock4View(e.ctx, tb.Meta(), &buf)
  1084  	e.appendEvent([]interface{}{tb.Meta().Name.O, buf.String(), tb.Meta().Charset, tb.Meta().DefCauslate})
  1085  	return nil
  1086  }
  1087  
  1088  func fetchShowCreateBlock4View(ctx stochastikctx.Context, tb *perceptron.BlockInfo, buf *bytes.Buffer) {
  1089  	sqlMode := ctx.GetStochastikVars().ALLEGROSQLMode
  1090  
  1091  	fmt.Fprintf(buf, "CREATE ALGORITHM=%s ", tb.View.Algorithm.String())
  1092  	fmt.Fprintf(buf, "DEFINER=%s@%s ", stringutil.Escape(tb.View.Definer.Username, sqlMode), stringutil.Escape(tb.View.Definer.Hostname, sqlMode))
  1093  	fmt.Fprintf(buf, "ALLEGROALLEGROSQL SECURITY %s ", tb.View.Security.String())
  1094  	fmt.Fprintf(buf, "VIEW %s (", stringutil.Escape(tb.Name.O, sqlMode))
  1095  	for i, defCaus := range tb.DeferredCausets {
  1096  		fmt.Fprintf(buf, "%s", stringutil.Escape(defCaus.Name.O, sqlMode))
  1097  		if i < len(tb.DeferredCausets)-1 {
  1098  			fmt.Fprintf(buf, ", ")
  1099  		}
  1100  	}
  1101  	fmt.Fprintf(buf, ") AS %s", tb.View.SelectStmt)
  1102  }
  1103  
  1104  func appendPartitionInfo(partitionInfo *perceptron.PartitionInfo, buf *bytes.Buffer) {
  1105  	if partitionInfo == nil {
  1106  		return
  1107  	}
  1108  	if partitionInfo.Type == perceptron.PartitionTypeHash {
  1109  		fmt.Fprintf(buf, "\nPARTITION BY HASH( %s )", partitionInfo.Expr)
  1110  		fmt.Fprintf(buf, "\nPARTITIONS %d", partitionInfo.Num)
  1111  		return
  1112  	}
  1113  	// this if memex takes care of range defCausumns case
  1114  	if partitionInfo.DeferredCausets != nil && partitionInfo.Type == perceptron.PartitionTypeRange {
  1115  		buf.WriteString("\nPARTITION BY RANGE COLUMNS(")
  1116  		for i, defCaus := range partitionInfo.DeferredCausets {
  1117  			buf.WriteString(defCaus.L)
  1118  			if i < len(partitionInfo.DeferredCausets)-1 {
  1119  				buf.WriteString(",")
  1120  			}
  1121  		}
  1122  		buf.WriteString(") (\n")
  1123  	} else {
  1124  		fmt.Fprintf(buf, "\nPARTITION BY %s ( %s ) (\n", partitionInfo.Type.String(), partitionInfo.Expr)
  1125  	}
  1126  	for i, def := range partitionInfo.Definitions {
  1127  		lessThans := strings.Join(def.LessThan, ",")
  1128  		fmt.Fprintf(buf, "  PARTITION `%s` VALUES LESS THAN (%s)", def.Name, lessThans)
  1129  		if i < len(partitionInfo.Definitions)-1 {
  1130  			buf.WriteString(",\n")
  1131  		} else {
  1132  			buf.WriteString("\n")
  1133  		}
  1134  	}
  1135  	buf.WriteString(")")
  1136  }
  1137  
  1138  // ConstructResultOfShowCreateDatabase constructs the result for show create database.
  1139  func ConstructResultOfShowCreateDatabase(ctx stochastikctx.Context, dbInfo *perceptron.DBInfo, ifNotExists bool, buf *bytes.Buffer) (err error) {
  1140  	sqlMode := ctx.GetStochastikVars().ALLEGROSQLMode
  1141  	var ifNotExistsStr string
  1142  	if ifNotExists {
  1143  		ifNotExistsStr = "/*!32312 IF NOT EXISTS*/ "
  1144  	}
  1145  	fmt.Fprintf(buf, "CREATE DATABASE %s%s", ifNotExistsStr, stringutil.Escape(dbInfo.Name.O, sqlMode))
  1146  	if dbInfo.Charset != "" {
  1147  		fmt.Fprintf(buf, " /*!40100 DEFAULT CHARACTER SET %s ", dbInfo.Charset)
  1148  		defaultDefCauslate, err := charset.GetDefaultDefCauslation(dbInfo.Charset)
  1149  		if err != nil {
  1150  			return errors.Trace(err)
  1151  		}
  1152  		if dbInfo.DefCauslate != "" && dbInfo.DefCauslate != defaultDefCauslate {
  1153  			fmt.Fprintf(buf, "COLLATE %s ", dbInfo.DefCauslate)
  1154  		}
  1155  		fmt.Fprint(buf, "*/")
  1156  		return nil
  1157  	}
  1158  	if dbInfo.DefCauslate != "" {
  1159  		defCauslInfo, err := defCauslate.GetDefCauslationByName(dbInfo.DefCauslate)
  1160  		if err != nil {
  1161  			return errors.Trace(err)
  1162  		}
  1163  		fmt.Fprintf(buf, " /*!40100 DEFAULT CHARACTER SET %s ", defCauslInfo.CharsetName)
  1164  		if !defCauslInfo.IsDefault {
  1165  			fmt.Fprintf(buf, "COLLATE %s ", dbInfo.DefCauslate)
  1166  		}
  1167  		fmt.Fprint(buf, "*/")
  1168  		return nil
  1169  	}
  1170  	// MyALLEGROSQL 5.7 always show the charset info but MilevaDB may ignore it, which makes a slight difference. We keep this
  1171  	// behavior unchanged because it is trivial enough.
  1172  	return nil
  1173  }
  1174  
  1175  // fetchShowCreateDatabase composes show create database result.
  1176  func (e *ShowInterDirc) fetchShowCreateDatabase() error {
  1177  	checker := privilege.GetPrivilegeManager(e.ctx)
  1178  	if checker != nil && e.ctx.GetStochastikVars().User != nil {
  1179  		if !checker.DBIsVisible(e.ctx.GetStochastikVars().ActiveRoles, e.DBName.String()) {
  1180  			return e.dbAccessDenied()
  1181  		}
  1182  	}
  1183  	dbInfo, ok := e.is.SchemaByName(e.DBName)
  1184  	if !ok {
  1185  		return schemareplicant.ErrDatabaseNotExists.GenWithStackByArgs(e.DBName.O)
  1186  	}
  1187  
  1188  	var buf bytes.Buffer
  1189  	err := ConstructResultOfShowCreateDatabase(e.ctx, dbInfo, e.IfNotExists, &buf)
  1190  	if err != nil {
  1191  		return err
  1192  	}
  1193  	e.appendEvent([]interface{}{dbInfo.Name.O, buf.String()})
  1194  	return nil
  1195  }
  1196  
  1197  func (e *ShowInterDirc) fetchShowDefCauslation() error {
  1198  	defCauslations := defCauslate.GetSupportedDefCauslations()
  1199  	for _, v := range defCauslations {
  1200  		isDefault := ""
  1201  		if v.IsDefault {
  1202  			isDefault = "Yes"
  1203  		}
  1204  		e.appendEvent([]interface{}{
  1205  			v.Name,
  1206  			v.CharsetName,
  1207  			v.ID,
  1208  			isDefault,
  1209  			"Yes",
  1210  			1,
  1211  		})
  1212  	}
  1213  	return nil
  1214  }
  1215  
  1216  // fetchShowCreateUser composes show create create user result.
  1217  func (e *ShowInterDirc) fetchShowCreateUser() error {
  1218  	checker := privilege.GetPrivilegeManager(e.ctx)
  1219  	if checker == nil {
  1220  		return errors.New("miss privilege checker")
  1221  	}
  1222  
  1223  	userName, hostName := e.User.Username, e.User.Hostname
  1224  	sessVars := e.ctx.GetStochastikVars()
  1225  	if e.User.CurrentUser {
  1226  		userName = sessVars.User.AuthUsername
  1227  		hostName = sessVars.User.AuthHostname
  1228  	} else {
  1229  		// Show create user requires the SELECT privilege on allegrosql.user.
  1230  		// Ref https://dev.allegrosql.com/doc/refman/5.7/en/show-create-user.html
  1231  		activeRoles := sessVars.ActiveRoles
  1232  		if !checker.RequestVerification(activeRoles, allegrosql.SystemDB, allegrosql.UserBlock, "", allegrosql.SelectPriv) {
  1233  			return e.blockAccessDenied("SELECT", allegrosql.UserBlock)
  1234  		}
  1235  	}
  1236  
  1237  	allegrosql := fmt.Sprintf(`SELECT * FROM %s.%s WHERE User='%s' AND Host='%s';`,
  1238  		allegrosql.SystemDB, allegrosql.UserBlock, userName, hostName)
  1239  	rows, _, err := e.ctx.(sqlexec.RestrictedALLEGROSQLInterlockingDirectorate).InterDircRestrictedALLEGROSQL(allegrosql)
  1240  	if err != nil {
  1241  		return errors.Trace(err)
  1242  	}
  1243  	if len(rows) == 0 {
  1244  		return ErrCannotUser.GenWithStackByArgs("SHOW CREATE USER",
  1245  			fmt.Sprintf("'%s'@'%s'", e.User.Username, e.User.Hostname))
  1246  	}
  1247  	allegrosql = fmt.Sprintf(`SELECT PRIV FROM %s.%s WHERE User='%s' AND Host='%s'`,
  1248  		allegrosql.SystemDB, allegrosql.GlobalPrivBlock, userName, hostName)
  1249  	rows, _, err = e.ctx.(sqlexec.RestrictedALLEGROSQLInterlockingDirectorate).InterDircRestrictedALLEGROSQL(allegrosql)
  1250  	if err != nil {
  1251  		return errors.Trace(err)
  1252  	}
  1253  	require := "NONE"
  1254  	if len(rows) == 1 {
  1255  		privData := rows[0].GetString(0)
  1256  		var privValue privileges.GlobalPrivValue
  1257  		err = gjson.Unmarshal(replog.Slice(privData), &privValue)
  1258  		if err != nil {
  1259  			return errors.Trace(err)
  1260  		}
  1261  		require = privValue.RequireStr()
  1262  	}
  1263  	showStr := fmt.Sprintf("CREATE USER '%s'@'%s' IDENTIFIED WITH 'mysql_native_password' AS '%s' REQUIRE %s PASSWORD EXPIRE DEFAULT ACCOUNT UNLOCK",
  1264  		e.User.Username, e.User.Hostname, checker.GetEncodedPassword(e.User.Username, e.User.Hostname), require)
  1265  	e.appendEvent([]interface{}{showStr})
  1266  	return nil
  1267  }
  1268  
  1269  func (e *ShowInterDirc) fetchShowGrants() error {
  1270  	// Get checker
  1271  	checker := privilege.GetPrivilegeManager(e.ctx)
  1272  	if checker == nil {
  1273  		return errors.New("miss privilege checker")
  1274  	}
  1275  	sessVars := e.ctx.GetStochastikVars()
  1276  	if !e.User.CurrentUser {
  1277  		userName := sessVars.User.AuthUsername
  1278  		hostName := sessVars.User.AuthHostname
  1279  		// Show grant user requires the SELECT privilege on allegrosql schemaReplicant.
  1280  		// Ref https://dev.allegrosql.com/doc/refman/8.0/en/show-grants.html
  1281  		if userName != e.User.Username || hostName != e.User.Hostname {
  1282  			activeRoles := sessVars.ActiveRoles
  1283  			if !checker.RequestVerification(activeRoles, allegrosql.SystemDB, "", "", allegrosql.SelectPriv) {
  1284  				return ErrDBaccessDenied.GenWithStackByArgs(userName, hostName, allegrosql.SystemDB)
  1285  			}
  1286  		}
  1287  	}
  1288  	for _, r := range e.Roles {
  1289  		if r.Hostname == "" {
  1290  			r.Hostname = "%"
  1291  		}
  1292  		if !checker.FindEdge(e.ctx, r, e.User) {
  1293  			return ErrRoleNotGranted.GenWithStackByArgs(r.String(), e.User.String())
  1294  		}
  1295  	}
  1296  	gs, err := checker.ShowGrants(e.ctx, e.User, e.Roles)
  1297  	if err != nil {
  1298  		return errors.Trace(err)
  1299  	}
  1300  	for _, g := range gs {
  1301  		e.appendEvent([]interface{}{g})
  1302  	}
  1303  	return nil
  1304  }
  1305  
  1306  func (e *ShowInterDirc) fetchShowPrivileges() error {
  1307  	e.appendEvent([]interface{}{"Alter", "Blocks", "To alter the causet"})
  1308  	e.appendEvent([]interface{}{"Alter", "Blocks", "To alter the causet"})
  1309  	e.appendEvent([]interface{}{"Alter routine", "Functions,Procedures", "To alter or drop stored functions/procedures"})
  1310  	e.appendEvent([]interface{}{"Create", "Databases,Blocks,Indexes", "To create new databases and blocks"})
  1311  	e.appendEvent([]interface{}{"Create routine", "Databases", "To use CREATE FUNCTION/PROCEDURE"})
  1312  	e.appendEvent([]interface{}{"Create temporary blocks", "Databases", "To use CREATE TEMPORARY TABLE"})
  1313  	e.appendEvent([]interface{}{"Create view", "Blocks", "To create new views"})
  1314  	e.appendEvent([]interface{}{"Create user", "Server Admin", "To create new users"})
  1315  	e.appendEvent([]interface{}{"Delete", "Blocks", "To delete existing rows"})
  1316  	e.appendEvent([]interface{}{"Drop", "Databases,Blocks", "To drop databases, blocks, and views"})
  1317  	e.appendEvent([]interface{}{"Event", "Server Admin", "To create, alter, drop and execute events"})
  1318  	e.appendEvent([]interface{}{"InterDircute", "Functions,Procedures", "To execute stored routines"})
  1319  	e.appendEvent([]interface{}{"File", "File access on server", "To read and write files on the server"})
  1320  	e.appendEvent([]interface{}{"Grant option", "Databases,Blocks,Functions,Procedures", "To give to other users those privileges you possess"})
  1321  	e.appendEvent([]interface{}{"Index", "Blocks", "To create or drop indexes"})
  1322  	e.appendEvent([]interface{}{"Insert", "Blocks", "To insert data into blocks"})
  1323  	e.appendEvent([]interface{}{"Lock blocks", "Databases", "To use LOCK TABLES (together with SELECT privilege)"})
  1324  	e.appendEvent([]interface{}{"Process", "Server Admin", "To view the plain text of currently executing queries"})
  1325  	e.appendEvent([]interface{}{"Proxy", "Server Admin", "To make proxy user possible"})
  1326  	e.appendEvent([]interface{}{"References", "Databases,Blocks", "To have references on blocks"})
  1327  	e.appendEvent([]interface{}{"Reload", "Server Admin", "To reload or refresh blocks, logs and privileges"})
  1328  	e.appendEvent([]interface{}{"Replication client", "Server Admin", "To ask where the slave or master servers are"})
  1329  	e.appendEvent([]interface{}{"Replication slave", "Server Admin", "To read binary log events from the master"})
  1330  	e.appendEvent([]interface{}{"Select", "Blocks", "To retrieve rows from causet"})
  1331  	e.appendEvent([]interface{}{"Show databases", "Server Admin", "To see all databases with SHOW DATABASES"})
  1332  	e.appendEvent([]interface{}{"Show view", "Blocks", "To see views with SHOW CREATE VIEW"})
  1333  	e.appendEvent([]interface{}{"Shutdown", "Server Admin", "To shut down the server"})
  1334  	e.appendEvent([]interface{}{"Super", "Server Admin", "To use KILL thread, SET GLOBAL, CHANGE MASTER, etc."})
  1335  	e.appendEvent([]interface{}{"Trigger", "Blocks", "To use triggers"})
  1336  	e.appendEvent([]interface{}{"Create blockspace", "Server Admin", "To create/alter/drop blockspaces"})
  1337  	e.appendEvent([]interface{}{"UFIDelate", "Blocks", "To uFIDelate existing rows"})
  1338  	e.appendEvent([]interface{}{"Usage", "Server Admin", "No privileges - allow connect only"})
  1339  	return nil
  1340  }
  1341  
  1342  func (e *ShowInterDirc) fetchShowTriggers() error {
  1343  	return nil
  1344  }
  1345  
  1346  func (e *ShowInterDirc) fetchShowProcedureStatus() error {
  1347  	return nil
  1348  }
  1349  
  1350  func (e *ShowInterDirc) fetchShowPlugins() error {
  1351  	tiPlugins := plugin.GetAll()
  1352  	for _, ps := range tiPlugins {
  1353  		for _, p := range ps {
  1354  			e.appendEvent([]interface{}{p.Name, p.StateValue(), p.HoTT.String(), p.Path, p.License, strconv.Itoa(int(p.Version))})
  1355  		}
  1356  	}
  1357  	return nil
  1358  }
  1359  
  1360  func (e *ShowInterDirc) fetchShowWarnings(errOnly bool) error {
  1361  	warns := e.ctx.GetStochastikVars().StmtCtx.GetWarnings()
  1362  	for _, w := range warns {
  1363  		if errOnly && w.Level != stmtctx.WarnLevelError {
  1364  			continue
  1365  		}
  1366  		warn := errors.Cause(w.Err)
  1367  		switch x := warn.(type) {
  1368  		case *terror.Error:
  1369  			sqlErr := terror.ToALLEGROSQLError(x)
  1370  			e.appendEvent([]interface{}{w.Level, int64(sqlErr.Code), sqlErr.Message})
  1371  		default:
  1372  			e.appendEvent([]interface{}{w.Level, int64(allegrosql.ErrUnknown), warn.Error()})
  1373  		}
  1374  	}
  1375  	return nil
  1376  }
  1377  
  1378  // fetchShowPumpOrDrainerStatus gets status of all pumps or drainers and fill them into e.rows.
  1379  func (e *ShowInterDirc) fetchShowPumpOrDrainerStatus(HoTT string) error {
  1380  	registry, err := createRegistry(config.GetGlobalConfig().Path)
  1381  	if err != nil {
  1382  		return errors.Trace(err)
  1383  	}
  1384  
  1385  	nodes, _, err := registry.Nodes(context.Background(), node.NodePrefix[HoTT])
  1386  	if err != nil {
  1387  		return errors.Trace(err)
  1388  	}
  1389  	err = registry.Close()
  1390  	if err != nil {
  1391  		return errors.Trace(err)
  1392  	}
  1393  
  1394  	for _, n := range nodes {
  1395  		if n.State == node.Offline {
  1396  			continue
  1397  		}
  1398  		e.appendEvent([]interface{}{n.NodeID, n.Addr, n.State, n.MaxCommitTS, utils.TSOToRoughTime(n.UFIDelateTS).Format(types.TimeFormat)})
  1399  	}
  1400  
  1401  	return nil
  1402  }
  1403  
  1404  // createRegistry returns an ectd registry
  1405  func createRegistry(urls string) (*node.EtcdRegistry, error) {
  1406  	ectdEndpoints, err := utils.ParseHostPortAddr(urls)
  1407  	if err != nil {
  1408  		return nil, errors.Trace(err)
  1409  	}
  1410  	cli, err := etcd.NewClientFromCfg(ectdEndpoints, etcdDialTimeout, node.DefaultRootPath, nil)
  1411  	if err != nil {
  1412  		return nil, errors.Trace(err)
  1413  	}
  1414  
  1415  	return node.NewEtcdRegistry(cli, etcdDialTimeout), nil
  1416  }
  1417  
  1418  func (e *ShowInterDirc) getBlock() (causet.Block, error) {
  1419  	if e.Block == nil {
  1420  		return nil, errors.New("causet not found")
  1421  	}
  1422  	tb, ok := e.is.BlockByID(e.Block.BlockInfo.ID)
  1423  	if !ok {
  1424  		return nil, errors.Errorf("causet %s not found", e.Block.Name)
  1425  	}
  1426  	return tb, nil
  1427  }
  1428  
  1429  func (e *ShowInterDirc) dbAccessDenied() error {
  1430  	user := e.ctx.GetStochastikVars().User
  1431  	u := user.Username
  1432  	h := user.Hostname
  1433  	if len(user.AuthUsername) > 0 && len(user.AuthHostname) > 0 {
  1434  		u = user.AuthUsername
  1435  		h = user.AuthHostname
  1436  	}
  1437  	return ErrDBaccessDenied.GenWithStackByArgs(u, h, e.DBName)
  1438  }
  1439  
  1440  func (e *ShowInterDirc) blockAccessDenied(access string, causet string) error {
  1441  	user := e.ctx.GetStochastikVars().User
  1442  	u := user.Username
  1443  	h := user.Hostname
  1444  	if len(user.AuthUsername) > 0 && len(user.AuthHostname) > 0 {
  1445  		u = user.AuthUsername
  1446  		h = user.AuthHostname
  1447  	}
  1448  	return ErrBlockaccessDenied.GenWithStackByArgs(access, u, h, causet)
  1449  }
  1450  
  1451  func (e *ShowInterDirc) appendEvent(event []interface{}) {
  1452  	for i, defCaus := range event {
  1453  		if defCaus == nil {
  1454  			e.result.AppendNull(i)
  1455  			continue
  1456  		}
  1457  		switch x := defCaus.(type) {
  1458  		case nil:
  1459  			e.result.AppendNull(i)
  1460  		case int:
  1461  			e.result.AppendInt64(i, int64(x))
  1462  		case int64:
  1463  			e.result.AppendInt64(i, x)
  1464  		case uint64:
  1465  			e.result.AppendUint64(i, x)
  1466  		case float64:
  1467  			e.result.AppendFloat64(i, x)
  1468  		case float32:
  1469  			e.result.AppendFloat32(i, x)
  1470  		case string:
  1471  			e.result.AppendString(i, x)
  1472  		case []byte:
  1473  			e.result.AppendBytes(i, x)
  1474  		case types.BinaryLiteral:
  1475  			e.result.AppendBytes(i, x)
  1476  		case *types.MyDecimal:
  1477  			e.result.AppendMyDecimal(i, x)
  1478  		case types.Time:
  1479  			e.result.AppendTime(i, x)
  1480  		case json.BinaryJSON:
  1481  			e.result.AppendJSON(i, x)
  1482  		case types.Duration:
  1483  			e.result.AppendDuration(i, x)
  1484  		case types.Enum:
  1485  			e.result.AppendEnum(i, x)
  1486  		case types.Set:
  1487  			e.result.AppendSet(i, x)
  1488  		default:
  1489  			e.result.AppendNull(i)
  1490  		}
  1491  	}
  1492  }
  1493  
  1494  func (e *ShowInterDirc) fetchShowBlockRegions() error {
  1495  	causetstore := e.ctx.GetStore()
  1496  	einsteindbStore, ok := causetstore.(einsteindb.CausetStorage)
  1497  	if !ok {
  1498  		return nil
  1499  	}
  1500  	splitStore, ok := causetstore.(ekv.SplitblockStore)
  1501  	if !ok {
  1502  		return nil
  1503  	}
  1504  
  1505  	tb, err := e.getBlock()
  1506  	if err != nil {
  1507  		return errors.Trace(err)
  1508  	}
  1509  
  1510  	physicalIDs := []int64{}
  1511  	if pi := tb.Meta().GetPartitionInfo(); pi != nil {
  1512  		for _, name := range e.Block.PartitionNames {
  1513  			pid, err := blocks.FindPartitionByName(tb.Meta(), name.L)
  1514  			if err != nil {
  1515  				return err
  1516  			}
  1517  			physicalIDs = append(physicalIDs, pid)
  1518  		}
  1519  		if len(physicalIDs) == 0 {
  1520  			for _, p := range pi.Definitions {
  1521  				physicalIDs = append(physicalIDs, p.ID)
  1522  			}
  1523  		}
  1524  	} else {
  1525  		if len(e.Block.PartitionNames) != 0 {
  1526  			return causetembedded.ErrPartitionClauseOnNonpartitioned
  1527  		}
  1528  		physicalIDs = append(physicalIDs, tb.Meta().ID)
  1529  	}
  1530  
  1531  	// Get causet regions from from fidel, not from regionCache, because the region cache maybe outdated.
  1532  	var regions []regionMeta
  1533  	if len(e.IndexName.L) != 0 {
  1534  		indexInfo := tb.Meta().FindIndexByName(e.IndexName.L)
  1535  		if indexInfo == nil {
  1536  			return causetembedded.ErrKeyDoesNotExist.GenWithStackByArgs(e.IndexName, tb.Meta().Name)
  1537  		}
  1538  		regions, err = getBlockIndexRegions(indexInfo, physicalIDs, einsteindbStore, splitStore)
  1539  	} else {
  1540  		regions, err = getBlockRegions(tb, physicalIDs, einsteindbStore, splitStore)
  1541  	}
  1542  
  1543  	if err != nil {
  1544  		return err
  1545  	}
  1546  	e.fillRegionsToChunk(regions)
  1547  	return nil
  1548  }
  1549  
  1550  func getBlockRegions(tb causet.Block, physicalIDs []int64, einsteindbStore einsteindb.CausetStorage, splitStore ekv.SplitblockStore) ([]regionMeta, error) {
  1551  	regions := make([]regionMeta, 0, len(physicalIDs))
  1552  	uniqueRegionMap := make(map[uint64]struct{})
  1553  	for _, id := range physicalIDs {
  1554  		rs, err := getPhysicalBlockRegions(id, tb.Meta(), einsteindbStore, splitStore, uniqueRegionMap)
  1555  		if err != nil {
  1556  			return nil, err
  1557  		}
  1558  		regions = append(regions, rs...)
  1559  	}
  1560  	return regions, nil
  1561  }
  1562  
  1563  func getBlockIndexRegions(indexInfo *perceptron.IndexInfo, physicalIDs []int64, einsteindbStore einsteindb.CausetStorage, splitStore ekv.SplitblockStore) ([]regionMeta, error) {
  1564  	regions := make([]regionMeta, 0, len(physicalIDs))
  1565  	uniqueRegionMap := make(map[uint64]struct{})
  1566  	for _, id := range physicalIDs {
  1567  		rs, err := getPhysicalIndexRegions(id, indexInfo, einsteindbStore, splitStore, uniqueRegionMap)
  1568  		if err != nil {
  1569  			return nil, err
  1570  		}
  1571  		regions = append(regions, rs...)
  1572  	}
  1573  	return regions, nil
  1574  }
  1575  
  1576  func (e *ShowInterDirc) fillRegionsToChunk(regions []regionMeta) {
  1577  	for i := range regions {
  1578  		e.result.AppendUint64(0, regions[i].region.Id)
  1579  		e.result.AppendString(1, regions[i].start)
  1580  		e.result.AppendString(2, regions[i].end)
  1581  		e.result.AppendUint64(3, regions[i].leaderID)
  1582  		e.result.AppendUint64(4, regions[i].storeID)
  1583  
  1584  		peers := ""
  1585  		for i, peer := range regions[i].region.Peers {
  1586  			if i > 0 {
  1587  				peers += ", "
  1588  			}
  1589  			peers += strconv.FormatUint(peer.Id, 10)
  1590  		}
  1591  		e.result.AppendString(5, peers)
  1592  		if regions[i].scattering {
  1593  			e.result.AppendInt64(6, 1)
  1594  		} else {
  1595  			e.result.AppendInt64(6, 0)
  1596  		}
  1597  
  1598  		e.result.AppendInt64(7, regions[i].writtenBytes)
  1599  		e.result.AppendInt64(8, regions[i].readBytes)
  1600  		e.result.AppendInt64(9, regions[i].approximateSize)
  1601  		e.result.AppendInt64(10, regions[i].approximateKeys)
  1602  	}
  1603  }
  1604  
  1605  func (e *ShowInterDirc) fetchShowBuiltins() error {
  1606  	for _, f := range memex.GetBuiltinList() {
  1607  		e.appendEvent([]interface{}{f})
  1608  	}
  1609  	return nil
  1610  }