github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/plan/build_show.go (about)

     1  // Copyright 2021 - 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 plan
    16  
    17  import (
    18  	"bytes"
    19  	"encoding/json"
    20  	"fmt"
    21  	"go/constant"
    22  	"strings"
    23  
    24  	"github.com/matrixorigin/matrixone/pkg/catalog"
    25  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    26  	"github.com/matrixorigin/matrixone/pkg/container/types"
    27  	"github.com/matrixorigin/matrixone/pkg/pb/plan"
    28  	"github.com/matrixorigin/matrixone/pkg/pb/timestamp"
    29  	"github.com/matrixorigin/matrixone/pkg/sql/parsers"
    30  	"github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect"
    31  	"github.com/matrixorigin/matrixone/pkg/sql/parsers/tree"
    32  	"github.com/matrixorigin/matrixone/pkg/sql/util"
    33  )
    34  
    35  const MO_CATALOG_DB_NAME = "mo_catalog"
    36  const MO_DEFUALT_HOSTNAME = "localhost"
    37  const INFORMATION_SCHEMA = "information_schema"
    38  
    39  func buildShowCreateDatabase(stmt *tree.ShowCreateDatabase,
    40  	ctx CompilerContext) (*Plan, error) {
    41  	var err error
    42  	var name string
    43  	// snapshot to fix
    44  	name, err = databaseIsValid(getSuitableDBName("", stmt.Name), ctx, Snapshot{TS: &timestamp.Timestamp{}})
    45  	if err != nil {
    46  		return nil, err
    47  	}
    48  
    49  	if sub, err := ctx.GetSubscriptionMeta(name, Snapshot{TS: &timestamp.Timestamp{}}); err != nil {
    50  		return nil, err
    51  	} else if sub != nil {
    52  		accountId, err := ctx.GetAccountId()
    53  		if err != nil {
    54  			return nil, err
    55  		}
    56  		// get data from schema
    57  		//sql := fmt.Sprintf("SELECT md.datname as `Database` FROM %s.mo_database md WHERE md.datname = '%s'", MO_CATALOG_DB_NAME, stmt.Name)
    58  		sql := fmt.Sprintf("SELECT md.datname as `Database`,dat_createsql as `Create Database` FROM %s.mo_database md WHERE md.datname = '%s' and account_id=%d", MO_CATALOG_DB_NAME, stmt.Name, accountId)
    59  		return returnByRewriteSQL(ctx, sql, plan.DataDefinition_SHOW_CREATEDATABASE)
    60  	}
    61  
    62  	sqlStr := "select \"%s\" as `Database`, \"%s\" as `Create Database`"
    63  	createSql := fmt.Sprintf("CREATE DATABASE `%s`", name)
    64  	sqlStr = fmt.Sprintf(sqlStr, name, createSql)
    65  
    66  	return returnByRewriteSQL(ctx, sqlStr, plan.DataDefinition_SHOW_CREATEDATABASE)
    67  }
    68  
    69  func formatStr(str string) string {
    70  	tmp := strings.Replace(str, "`", "``", -1)
    71  	strLen := len(tmp)
    72  	if strLen < 2 {
    73  		return tmp
    74  	}
    75  	if tmp[0] == '\'' && tmp[strLen-1] == '\'' {
    76  		return "'" + strings.Replace(tmp[1:strLen-1], "'", "''", -1) + "'"
    77  	}
    78  	return strings.Replace(tmp, "'", "''", -1)
    79  }
    80  
    81  func buildShowCreateTable(stmt *tree.ShowCreateTable, ctx CompilerContext) (*Plan, error) {
    82  	var err error
    83  	tblName := stmt.Name.GetTableName()
    84  	dbName := stmt.Name.GetDBName()
    85  
    86  	snapshot := &Snapshot{TS: &timestamp.Timestamp{}}
    87  	if len(stmt.SnapshotName) > 0 {
    88  		if snapshot, err = ctx.ResolveSnapshotWithSnapshotName(stmt.SnapshotName); err != nil {
    89  			return nil, err
    90  		}
    91  	}
    92  
    93  	dbName, err = databaseIsValid(getSuitableDBName(dbName, ""), ctx, *snapshot)
    94  	if err != nil {
    95  		return nil, err
    96  	}
    97  
    98  	// check if the database is a subscription
    99  	sub, err := ctx.GetSubscriptionMeta(dbName, *snapshot)
   100  	if err != nil {
   101  		return nil, err
   102  	}
   103  
   104  	if sub != nil {
   105  		ctx.SetQueryingSubscription(sub)
   106  		defer func() {
   107  			ctx.SetQueryingSubscription(nil)
   108  		}()
   109  	}
   110  
   111  	_, tableDef := ctx.Resolve(dbName, tblName, *snapshot)
   112  	if tableDef == nil {
   113  		return nil, moerr.NewNoSuchTable(ctx.GetContext(), dbName, tblName)
   114  	}
   115  	if tableDef.TableType == catalog.SystemViewRel {
   116  		var newStmt *tree.ShowCreateView
   117  		if stmt.Name.NumParts == 1 {
   118  			newStmt = tree.NewShowCreateView(tree.SetUnresolvedObjectName(1, [3]string{tblName, "", ""}))
   119  		} else if stmt.Name.NumParts == 2 {
   120  			newStmt = tree.NewShowCreateView(tree.SetUnresolvedObjectName(2, [3]string{tblName, dbName, ""}))
   121  		}
   122  		if len(stmt.SnapshotName) > 0 {
   123  			newStmt.SnapshotName = stmt.SnapshotName
   124  		}
   125  
   126  		return buildShowCreateView(newStmt, ctx)
   127  	}
   128  
   129  	// sql := `
   130  	// 	SELECT *
   131  	// 		FROM %s.mo_tables mt JOIN %s.mo_columns mc
   132  	// 			ON mt.relname = mc.att_relname and mt.reldatabase=mc.att_database
   133  	// 	WHERE mt.reldatabase = '%s' AND mt.relname = '%s'
   134  	// `
   135  	// sql = fmt.Sprintf(sql, MO_CATALOG_DB_NAME, MO_CATALOG_DB_NAME, dbName, tblName)
   136  	// logutil.Info(sql)
   137  
   138  	var createStr string
   139  	if tableDef.TableType == catalog.SystemOrdinaryRel {
   140  		createStr = fmt.Sprintf("CREATE TABLE `%s` (", formatStr(tblName))
   141  	} else if tableDef.TableType == catalog.SystemExternalRel {
   142  		createStr = fmt.Sprintf("CREATE EXTERNAL TABLE `%s` (", formatStr(tblName))
   143  	} else if tableDef.TableType == catalog.SystemClusterRel {
   144  		createStr = fmt.Sprintf("CREATE CLUSTER TABLE `%s` (", formatStr(tblName))
   145  	} else if tblName == catalog.MO_DATABASE || tblName == catalog.MO_TABLES || tblName == catalog.MO_COLUMNS {
   146  		createStr = fmt.Sprintf("CREATE TABLE `%s` (", formatStr(tblName))
   147  	}
   148  
   149  	rowCount := 0
   150  	var pkDefs []string
   151  	isClusterTable := util.TableIsClusterTable(tableDef.TableType)
   152  
   153  	colIdToName := make(map[uint64]string)
   154  	for _, col := range tableDef.Cols {
   155  		if col.Hidden {
   156  			continue
   157  		}
   158  		colName := col.Name
   159  		colIdToName[col.ColId] = col.Name
   160  		if colName == catalog.Row_ID {
   161  			continue
   162  		}
   163  		//the non-sys account skips the column account_id of the cluster table
   164  		accountId, err := ctx.GetAccountId()
   165  		if err != nil {
   166  			return nil, err
   167  		}
   168  		if util.IsClusterTableAttribute(colName) &&
   169  			isClusterTable &&
   170  			accountId != catalog.System_Account {
   171  			continue
   172  		}
   173  		nullOrNot := "NOT NULL"
   174  		// col.Default must be not nil
   175  		if len(col.Default.OriginString) > 0 {
   176  			if !col.Primary {
   177  				nullOrNot = "DEFAULT " + formatStr(col.Default.OriginString)
   178  			}
   179  		} else if col.Default.NullAbility {
   180  			nullOrNot = "DEFAULT NULL"
   181  		}
   182  
   183  		if col.Typ.AutoIncr {
   184  			nullOrNot = "NOT NULL AUTO_INCREMENT"
   185  		}
   186  
   187  		var hasAttrComment string
   188  		if col.Comment != "" {
   189  			hasAttrComment = " COMMENT '" + col.Comment + "'"
   190  		}
   191  
   192  		if rowCount == 0 {
   193  			createStr += "\n"
   194  		} else {
   195  			createStr += ",\n"
   196  		}
   197  		typ := types.T(col.Typ.Id).ToType()
   198  		typeStr := typ.String()
   199  		if typ.Oid.IsDecimal() { //after decimal fix,remove this
   200  			typeStr = fmt.Sprintf("DECIMAL(%d,%d)", col.Typ.Width, col.Typ.Scale)
   201  		}
   202  		if typ.Oid == types.T_varchar || typ.Oid == types.T_char ||
   203  			typ.Oid == types.T_binary || typ.Oid == types.T_varbinary ||
   204  			typ.Oid.IsArrayRelate() || typ.Oid == types.T_bit {
   205  			typeStr += fmt.Sprintf("(%d)", col.Typ.Width)
   206  		}
   207  		if typ.Oid.IsFloat() && col.Typ.Scale != -1 {
   208  			typeStr += fmt.Sprintf("(%d,%d)", col.Typ.Width, col.Typ.Scale)
   209  		}
   210  
   211  		if typ.Oid.IsEnum() {
   212  			enums := strings.Split(col.Typ.GetEnumvalues(), ",")
   213  			typeStr += "("
   214  			for i, enum := range enums {
   215  				typeStr += fmt.Sprintf("'%s'", enum)
   216  				if i < len(enums)-1 {
   217  					typeStr += ","
   218  				}
   219  			}
   220  			typeStr += ")"
   221  		}
   222  
   223  		updateOpt := ""
   224  		if col.OnUpdate != nil && col.OnUpdate.Expr != nil {
   225  			updateOpt = " ON UPDATE " + col.OnUpdate.OriginString
   226  		}
   227  		createStr += fmt.Sprintf("`%s` %s %s%s%s", formatStr(colName), typeStr, nullOrNot, updateOpt, hasAttrComment)
   228  		rowCount++
   229  		if col.Primary {
   230  			pkDefs = append(pkDefs, colName)
   231  		}
   232  	}
   233  
   234  	// If it is a composite primary key, get the component columns of the composite primary key
   235  	if tableDef.Pkey != nil && len(tableDef.Pkey.Names) > 1 {
   236  		pkDefs = append(pkDefs, tableDef.Pkey.Names...)
   237  	}
   238  
   239  	if len(pkDefs) != 0 {
   240  		pkStr := "PRIMARY KEY ("
   241  		for i, def := range pkDefs {
   242  			if i == len(pkDefs)-1 {
   243  				pkStr += fmt.Sprintf("`%s`", formatStr(def))
   244  			} else {
   245  				pkStr += fmt.Sprintf("`%s`,", formatStr(def))
   246  			}
   247  		}
   248  		pkStr += ")"
   249  		if rowCount != 0 {
   250  			createStr += ",\n"
   251  		}
   252  		createStr += pkStr
   253  	}
   254  
   255  	if tableDef.Indexes != nil {
   256  
   257  		// We only print distinct index names. This is used to avoid printing the same index multiple times for IVFFLAT or
   258  		// other multi-table indexes.
   259  		indexNames := make(map[string]bool)
   260  
   261  		for _, indexdef := range tableDef.Indexes {
   262  			if _, ok := indexNames[indexdef.IndexName]; ok {
   263  				continue
   264  			} else {
   265  				indexNames[indexdef.IndexName] = true
   266  			}
   267  
   268  			var indexStr string
   269  			if indexdef.Unique {
   270  				indexStr = "UNIQUE KEY "
   271  			} else {
   272  				indexStr = "KEY "
   273  			}
   274  			indexStr += fmt.Sprintf("`%s` ", formatStr(indexdef.IndexName))
   275  			if !catalog.IsNullIndexAlgo(indexdef.IndexAlgo) {
   276  				indexStr += fmt.Sprintf("USING %s ", indexdef.IndexAlgo)
   277  			}
   278  			indexStr += "("
   279  			i := 0
   280  			for _, part := range indexdef.Parts {
   281  				if catalog.IsAlias(part) {
   282  					continue
   283  				}
   284  				if i > 0 {
   285  					indexStr += ","
   286  				}
   287  
   288  				indexStr += fmt.Sprintf("`%s`", formatStr(part))
   289  				i++
   290  			}
   291  
   292  			indexStr += ")"
   293  			if indexdef.IndexAlgoParams != "" {
   294  				var paramList string
   295  				paramList, err = catalog.IndexParamsToStringList(indexdef.IndexAlgoParams)
   296  				if err != nil {
   297  					return nil, err
   298  				}
   299  				indexStr += paramList
   300  			}
   301  			if indexdef.Comment != "" {
   302  				indexdef.Comment = strings.Replace(indexdef.Comment, "'", "\\'", -1)
   303  				indexStr += fmt.Sprintf(" COMMENT '%s'", formatStr(indexdef.Comment))
   304  			}
   305  			if rowCount != 0 {
   306  				createStr += ",\n"
   307  			}
   308  			createStr += indexStr
   309  		}
   310  	}
   311  
   312  	for _, fk := range tableDef.Fkeys {
   313  		colNames := make([]string, len(fk.Cols))
   314  		for i, colId := range fk.Cols {
   315  			colNames[i] = colIdToName[colId]
   316  		}
   317  
   318  		var fkTableDef *TableDef
   319  
   320  		//fk self reference
   321  		if fk.ForeignTbl == 0 {
   322  			fkTableDef = tableDef
   323  		} else {
   324  			if ctx.GetQueryingSubscription() != nil {
   325  				_, fkTableDef = ctx.ResolveSubscriptionTableById(fk.ForeignTbl, ctx.GetQueryingSubscription())
   326  			} else {
   327  				_, fkTableDef = ctx.ResolveById(fk.ForeignTbl, *snapshot)
   328  			}
   329  		}
   330  
   331  		fkColIdToName := make(map[uint64]string)
   332  		for _, col := range fkTableDef.Cols {
   333  			fkColIdToName[col.ColId] = col.Name
   334  		}
   335  		fkColNames := make([]string, len(fk.ForeignCols))
   336  		for i, colId := range fk.ForeignCols {
   337  			fkColNames[i] = fkColIdToName[colId]
   338  		}
   339  
   340  		if rowCount != 0 {
   341  			createStr += ",\n"
   342  		}
   343  		createStr += fmt.Sprintf("CONSTRAINT `%s` FOREIGN KEY (`%s`) REFERENCES `%s` (`%s`) ON DELETE %s ON UPDATE %s",
   344  			formatStr(fk.Name), strings.Join(colNames, "`,`"), formatStr(fkTableDef.Name), strings.Join(fkColNames, "`,`"), fk.OnDelete.String(), fk.OnUpdate.String())
   345  	}
   346  
   347  	if rowCount != 0 {
   348  		createStr += "\n"
   349  	}
   350  	createStr += ")"
   351  
   352  	var comment string
   353  	var partition string
   354  	for _, def := range tableDef.Defs {
   355  		if proDef, ok := def.Def.(*plan.TableDef_DefType_Properties); ok {
   356  			for _, kv := range proDef.Properties.Properties {
   357  				if kv.Key == catalog.SystemRelAttr_Comment {
   358  					comment = " COMMENT='" + kv.Value + "'"
   359  				}
   360  			}
   361  		}
   362  	}
   363  
   364  	if tableDef.Partition != nil {
   365  		partition = ` ` + tableDef.Partition.PartitionMsg
   366  	}
   367  
   368  	createStr += comment
   369  	createStr += partition
   370  
   371  	/**
   372  	Fix issue: https://github.com/matrixorigin/MO-Cloud/issues/1028#issuecomment-1667642384
   373  	Based on the grammar of the 'create table' in the file pkg/sql/parsers/dialect/mysql/mysql_sql.y
   374  		https://github.com/matrixorigin/matrixone/blob/68db7260e411e5a4541eaccf78ca9bb57e810f24/pkg/sql/parsers/dialect/mysql/mysql_sql.y#L6076C7-L6076C7
   375  		https://github.com/matrixorigin/matrixone/blob/68db7260e411e5a4541eaccf78ca9bb57e810f24/pkg/sql/parsers/dialect/mysql/mysql_sql.y#L6097
   376  	The 'cluster by' is after the 'partition by' and the 'table options', so we need to add the 'cluster by' string after the 'partition by' and the 'table options'.
   377  	*/
   378  	if tableDef.ClusterBy != nil {
   379  		clusterby := " CLUSTER BY ("
   380  		if util.JudgeIsCompositeClusterByColumn(tableDef.ClusterBy.Name) {
   381  			//multi column clusterby
   382  			cbNames := util.SplitCompositeClusterByColumnName(tableDef.ClusterBy.Name)
   383  			for i, cbName := range cbNames {
   384  				if i != 0 {
   385  					clusterby += fmt.Sprintf(", `%s`", formatStr(cbName))
   386  				} else {
   387  					clusterby += fmt.Sprintf("`%s`", formatStr(cbName))
   388  				}
   389  			}
   390  		} else {
   391  			//single column cluster by
   392  			clusterby += fmt.Sprintf("`%s`", formatStr(tableDef.ClusterBy.Name))
   393  		}
   394  		clusterby += ")"
   395  		createStr += clusterby
   396  	}
   397  
   398  	if tableDef.TableType == catalog.SystemExternalRel {
   399  		param := tree.ExternParam{}
   400  		err := json.Unmarshal([]byte(tableDef.Createsql), &param)
   401  		if err != nil {
   402  			return nil, err
   403  		}
   404  		createStr += fmt.Sprintf(" INFILE{'FILEPATH'='%s','COMPRESSION'='%s','FORMAT'='%s','JSONDATA'='%s'}", param.Filepath, param.CompressType, param.Format, param.JsonData)
   405  
   406  		fields := ""
   407  		if param.Tail.Fields.Terminated != nil {
   408  			if param.Tail.Fields.Terminated.Value == "" {
   409  				fields += " TERMINATED BY \"\""
   410  			} else {
   411  				fields += fmt.Sprintf(" TERMINATED BY '%s'", param.Tail.Fields.Terminated.Value)
   412  			}
   413  		}
   414  		if param.Tail.Fields.EnclosedBy != nil {
   415  			if param.Tail.Fields.EnclosedBy.Value == byte(0) {
   416  				fields += " ENCLOSED BY ''"
   417  			} else if param.Tail.Fields.EnclosedBy.Value == byte('\\') {
   418  				fields += " ENCLOSED BY '\\\\'"
   419  			} else {
   420  				fields += fmt.Sprintf(" ENCLOSED BY '%c'", param.Tail.Fields.EnclosedBy.Value)
   421  			}
   422  		}
   423  		if param.Tail.Fields.EscapedBy != nil {
   424  			if param.Tail.Fields.EscapedBy.Value == byte(0) {
   425  				fields += " ESCAPED BY ''"
   426  			} else if param.Tail.Fields.EscapedBy.Value == byte('\\') {
   427  				fields += " ESCAPED BY '\\\\'"
   428  			} else {
   429  				fields += fmt.Sprintf(" ESCAPED BY '%c'", param.Tail.Fields.EscapedBy.Value)
   430  			}
   431  		}
   432  
   433  		line := ""
   434  		if param.Tail.Lines.StartingBy != "" {
   435  			line += fmt.Sprintf(" STARTING BY '%s'", param.Tail.Lines.StartingBy)
   436  		}
   437  		if param.Tail.Lines.TerminatedBy != nil {
   438  			if param.Tail.Lines.TerminatedBy.Value == "\n" || param.Tail.Lines.TerminatedBy.Value == "\r\n" {
   439  				line += " TERMINATED BY '\\\\n'"
   440  			} else {
   441  				line += fmt.Sprintf(" TERMINATED BY '%s'", param.Tail.Lines.TerminatedBy)
   442  			}
   443  		}
   444  
   445  		if len(fields) > 0 {
   446  			fields = " FIELDS" + fields
   447  			createStr += fields
   448  		}
   449  		if len(line) > 0 {
   450  			line = " LINES" + line
   451  			createStr += line
   452  		}
   453  
   454  		if param.Tail.IgnoredLines > 0 {
   455  			createStr += fmt.Sprintf(" IGNORE %d LINES", param.Tail.IgnoredLines)
   456  		}
   457  	}
   458  
   459  	sql := "select \"%s\" as `Table`, \"%s\" as `Create Table`"
   460  	var buf bytes.Buffer
   461  	for _, ch := range createStr {
   462  		if ch == '"' {
   463  			buf.WriteRune('"')
   464  		}
   465  		buf.WriteRune(ch)
   466  	}
   467  	sql = fmt.Sprintf(sql, tblName, buf.String())
   468  
   469  	return returnByRewriteSQL(ctx, sql, plan.DataDefinition_SHOW_CREATETABLE)
   470  }
   471  
   472  // buildShowCreateView
   473  func buildShowCreateView(stmt *tree.ShowCreateView, ctx CompilerContext) (*Plan, error) {
   474  	var err error
   475  	tblName := stmt.Name.GetTableName()
   476  	dbName := stmt.Name.GetDBName()
   477  
   478  	snapshot := &Snapshot{TS: &timestamp.Timestamp{}}
   479  	if len(stmt.SnapshotName) > 0 {
   480  		if snapshot, err = ctx.ResolveSnapshotWithSnapshotName(stmt.SnapshotName); err != nil {
   481  			return nil, err
   482  		}
   483  	}
   484  
   485  	dbName, err = databaseIsValid(getSuitableDBName(dbName, ""), ctx, *snapshot)
   486  	if err != nil {
   487  		return nil, err
   488  	}
   489  
   490  	_, tableDef := ctx.Resolve(dbName, tblName, *snapshot)
   491  	if tableDef == nil || tableDef.TableType != catalog.SystemViewRel {
   492  		return nil, moerr.NewInvalidInput(ctx.GetContext(), "show view '%s' is not a valid view", tblName)
   493  	}
   494  	sqlStr := "select \"%s\" as `View`, \"%s\" as `Create View`, 'utf8mb4' as `character_set_client`, 'utf8mb4_general_ci' as `collation_connection`"
   495  	var viewStr string
   496  	if tableDef.TableType == catalog.SystemViewRel {
   497  		viewStr = tableDef.ViewSql.View
   498  	}
   499  
   500  	var viewData ViewData
   501  	err = json.Unmarshal([]byte(viewStr), &viewData)
   502  	if err != nil {
   503  		return nil, err
   504  	}
   505  
   506  	// FixMe  We need a better escape function
   507  	stmtStr := strings.ReplaceAll(viewData.Stmt, "\"", "\\\"")
   508  	sqlStr = fmt.Sprintf(sqlStr, tblName, fmt.Sprint(stmtStr))
   509  
   510  	// logutil.Info(sqlStr)
   511  
   512  	return returnByRewriteSQL(ctx, sqlStr, plan.DataDefinition_SHOW_CREATETABLE)
   513  }
   514  
   515  func buildShowDatabases(stmt *tree.ShowDatabases, ctx CompilerContext) (*Plan, error) {
   516  	if stmt.Like != nil && stmt.Where != nil {
   517  		return nil, moerr.NewSyntaxError(ctx.GetContext(), "like clause and where clause cannot exist at the same time")
   518  	}
   519  
   520  	accountId, err := ctx.GetAccountId()
   521  	if err != nil {
   522  		return nil, err
   523  	}
   524  	ddlType := plan.DataDefinition_SHOW_DATABASES
   525  
   526  	var sql string
   527  	snapshotSpec := ""
   528  	if len(stmt.SnapshotName) > 0 {
   529  		snapshot, err := ctx.ResolveSnapshotWithSnapshotName(stmt.SnapshotName)
   530  		if err != nil {
   531  			return nil, err
   532  		}
   533  		accountId = snapshot.Tenant.TenantID
   534  		snapshotSpec = fmt.Sprintf("{snapshot = '%s'}", stmt.SnapshotName)
   535  	}
   536  	// Any account should show database MO_CATALOG_DB_NAME
   537  	accountClause := fmt.Sprintf("account_id = %v or (account_id = 0 and datname = '%s')", accountId, MO_CATALOG_DB_NAME)
   538  	sql = fmt.Sprintf("SELECT datname `Database` FROM %s.mo_database %s where (%s) ORDER BY %s", MO_CATALOG_DB_NAME, snapshotSpec, accountClause, catalog.SystemDBAttr_Name)
   539  
   540  	if stmt.Where != nil {
   541  		return returnByWhereAndBaseSQL(ctx, sql, stmt.Where, ddlType)
   542  	}
   543  
   544  	if stmt.Like != nil {
   545  		// append filter [AND datname like stmt.Like] to WHERE clause
   546  		likeExpr := stmt.Like
   547  		likeExpr.Left = tree.SetUnresolvedName("datname")
   548  		return returnByLikeAndSQL(ctx, sql, likeExpr, ddlType)
   549  	}
   550  
   551  	return returnByRewriteSQL(ctx, sql, ddlType)
   552  }
   553  
   554  func buildShowSequences(stmt *tree.ShowSequences, ctx CompilerContext) (*Plan, error) {
   555  	// snapshot to fix
   556  	dbName, err := databaseIsValid(stmt.DBName, ctx, Snapshot{TS: &timestamp.Timestamp{}})
   557  	if err != nil {
   558  		return nil, err
   559  	}
   560  
   561  	ddlType := plan.DataDefinition_SHOW_SEQUENCES
   562  
   563  	sql := fmt.Sprintf("select %s.mo_tables.relname as `Names`, mo_show_visible_bin(%s.mo_columns.atttyp, 2) as 'Data Type' from %s.mo_tables left join %s.mo_columns on %s.mo_tables.rel_id = %s.mo_columns.att_relname_id where %s.mo_tables.relkind = '%s' and %s.mo_tables.reldatabase = '%s' and %s.mo_columns.attname = '%s'", MO_CATALOG_DB_NAME,
   564  		MO_CATALOG_DB_NAME, MO_CATALOG_DB_NAME, MO_CATALOG_DB_NAME, MO_CATALOG_DB_NAME, MO_CATALOG_DB_NAME, MO_CATALOG_DB_NAME, catalog.SystemSequenceRel, MO_CATALOG_DB_NAME, dbName, MO_CATALOG_DB_NAME, Sequence_cols_name[0])
   565  
   566  	if stmt.Where != nil {
   567  		return returnByWhereAndBaseSQL(ctx, sql, stmt.Where, ddlType)
   568  	}
   569  
   570  	return returnByRewriteSQL(ctx, sql, ddlType)
   571  }
   572  
   573  func buildShowTables(stmt *tree.ShowTables, ctx CompilerContext) (*Plan, error) {
   574  	if stmt.Like != nil && stmt.Where != nil {
   575  		return nil, moerr.NewSyntaxError(ctx.GetContext(), "like clause and where clause cannot exist at the same time")
   576  	}
   577  
   578  	if stmt.Open {
   579  		return nil, moerr.NewNYI(ctx.GetContext(), "statement: '%v'", tree.String(stmt, dialect.MYSQL))
   580  	}
   581  
   582  	accountId, err := ctx.GetAccountId()
   583  	if err != nil {
   584  		return nil, err
   585  	}
   586  
   587  	snapshot := &Snapshot{TS: &timestamp.Timestamp{}}
   588  	snapshotSpec := ""
   589  	if len(stmt.SnapshotName) > 0 {
   590  		if snapshot, err = ctx.ResolveSnapshotWithSnapshotName(stmt.SnapshotName); err != nil {
   591  			return nil, err
   592  		}
   593  		accountId = snapshot.Tenant.TenantID
   594  		snapshotSpec = fmt.Sprintf("{snapshot = '%s'}", stmt.SnapshotName)
   595  	}
   596  
   597  	dbName, err := databaseIsValid(stmt.DBName, ctx, *snapshot)
   598  	if err != nil {
   599  		return nil, err
   600  	}
   601  
   602  	ddlType := plan.DataDefinition_SHOW_TABLES
   603  	var tableType string
   604  	if stmt.Full {
   605  		tableType = fmt.Sprintf(", case relkind when 'v' then 'VIEW' when '%s' then 'CLUSTER TABLE' else 'BASE TABLE' end as Table_type", catalog.SystemClusterRel)
   606  	}
   607  
   608  	sub, err := ctx.GetSubscriptionMeta(dbName, *snapshot)
   609  	if err != nil {
   610  		return nil, err
   611  	}
   612  	subName := dbName
   613  	if sub != nil {
   614  		accountId = uint32(sub.AccountId)
   615  		dbName = sub.DbName
   616  		ctx.SetQueryingSubscription(sub)
   617  		defer func() {
   618  			ctx.SetQueryingSubscription(nil)
   619  		}()
   620  	}
   621  
   622  	var sql string
   623  	mustShowTable := "relname = 'mo_database' or relname = 'mo_tables' or relname = 'mo_columns'"
   624  	clusterTable := fmt.Sprintf(" or relkind = '%s'", catalog.SystemClusterRel)
   625  	accountClause := fmt.Sprintf("account_id = %v or (account_id = 0 and (%s))", accountId, mustShowTable+clusterTable)
   626  	sql = fmt.Sprintf("SELECT relname as `Tables_in_%s` %s FROM %s.mo_tables %s WHERE reldatabase = '%s' and relname != '%s' and relname not like '%s' and relkind != '%s' and (%s)",
   627  		subName, tableType, MO_CATALOG_DB_NAME, snapshotSpec, dbName, catalog.MOAutoIncrTable, catalog.IndexTableNamePrefix+"%", catalog.SystemPartitionRel, accountClause)
   628  
   629  	// Do not show views in sub-db
   630  	if sub != nil {
   631  		sql += fmt.Sprintf(" and relkind != '%s'", catalog.SystemViewRel)
   632  	}
   633  
   634  	// Do not show sequences.
   635  	sql += fmt.Sprintf(" and relkind != '%s'", catalog.SystemSequenceRel)
   636  
   637  	// Order by relname
   638  	sql += fmt.Sprintf(" ORDER BY %s", catalog.SystemRelAttr_Name)
   639  
   640  	if stmt.Where != nil {
   641  		return returnByWhereAndBaseSQL(ctx, sql, stmt.Where, ddlType)
   642  	}
   643  
   644  	if stmt.Like != nil {
   645  		// append filter [AND relname like stmt.Like] to WHERE clause
   646  		likeExpr := stmt.Like
   647  		likeExpr.Left = tree.SetUnresolvedName("relname")
   648  		return returnByLikeAndSQL(ctx, sql, likeExpr, ddlType)
   649  	}
   650  
   651  	return returnByRewriteSQL(ctx, sql, ddlType)
   652  }
   653  
   654  func buildShowTableNumber(stmt *tree.ShowTableNumber, ctx CompilerContext) (*Plan, error) {
   655  	accountId, err := ctx.GetAccountId()
   656  	if err != nil {
   657  		return nil, err
   658  	}
   659  	// snapshot to fix
   660  	dbName, err := databaseIsValid(stmt.DbName, ctx, Snapshot{TS: &timestamp.Timestamp{}})
   661  	if err != nil {
   662  		return nil, err
   663  	}
   664  
   665  	sub, err := ctx.GetSubscriptionMeta(dbName, Snapshot{TS: &timestamp.Timestamp{}})
   666  	if err != nil {
   667  		return nil, err
   668  	}
   669  
   670  	ddlType := plan.DataDefinition_SHOW_TABLES
   671  	subName := dbName
   672  	var sql string
   673  	if sub != nil {
   674  		accountId = uint32(sub.AccountId)
   675  		dbName = sub.DbName
   676  		ctx.SetQueryingSubscription(sub)
   677  		defer func() {
   678  			ctx.SetQueryingSubscription(nil)
   679  		}()
   680  
   681  		if accountId == catalog.System_Account {
   682  			mustShowTable := "relname = 'mo_database' or relname = 'mo_tables' or relname = 'mo_columns'"
   683  			clusterTable := fmt.Sprintf(" or relkind = '%s'", catalog.SystemClusterRel)
   684  			accountClause := fmt.Sprintf("account_id = %v or (account_id = 0 and (%s))", accountId, mustShowTable+clusterTable)
   685  			sql = fmt.Sprintf("SELECT count(relname) `Number of tables in %s`  FROM %s.mo_tables WHERE reldatabase = '%s' and relname != '%s' and relname not like '%s' and (%s) and relkind != '%s'",
   686  				subName, MO_CATALOG_DB_NAME, dbName, catalog.MOAutoIncrTable, catalog.IndexTableNamePrefix+"%", accountClause, catalog.SystemViewRel)
   687  		} else {
   688  			sql = "SELECT count(relname) `Number of tables in %s` FROM %s.mo_tables WHERE reldatabase = '%s' and relname != '%s' and relname not like '%s'and relkind != '%s'"
   689  			sql = fmt.Sprintf(sql, subName, MO_CATALOG_DB_NAME, dbName, catalog.MOAutoIncrTable, catalog.IndexTableNamePrefix+"%", catalog.SystemViewRel)
   690  		}
   691  	} else {
   692  		if accountId == catalog.System_Account {
   693  			mustShowTable := "relname = 'mo_database' or relname = 'mo_tables' or relname = 'mo_columns'"
   694  			clusterTable := fmt.Sprintf(" or relkind = '%s'", catalog.SystemClusterRel)
   695  			accountClause := fmt.Sprintf("account_id = %v or (account_id = 0 and (%s))", accountId, mustShowTable+clusterTable)
   696  			sql = fmt.Sprintf("SELECT count(relname) `Number of tables in %s`  FROM %s.mo_tables WHERE reldatabase = '%s' and relname != '%s' and relname not like '%s' and (%s)",
   697  				subName, MO_CATALOG_DB_NAME, dbName, catalog.MOAutoIncrTable, catalog.IndexTableNamePrefix+"%", accountClause)
   698  		} else {
   699  			sql = "SELECT count(relname) `Number of tables in %s` FROM %s.mo_tables WHERE reldatabase = '%s' and relname != '%s' and relname not like '%s'"
   700  			sql = fmt.Sprintf(sql, subName, MO_CATALOG_DB_NAME, dbName, catalog.MOAutoIncrTable, catalog.IndexTableNamePrefix+"%")
   701  		}
   702  
   703  	}
   704  
   705  	return returnByRewriteSQL(ctx, sql, ddlType)
   706  }
   707  
   708  func buildShowColumnNumber(stmt *tree.ShowColumnNumber, ctx CompilerContext) (*Plan, error) {
   709  	accountId, err := ctx.GetAccountId()
   710  	if err != nil {
   711  		return nil, err
   712  	}
   713  	// snapshot to fix
   714  	dbName, err := databaseIsValid(getSuitableDBName(stmt.Table.GetDBName(), stmt.DbName), ctx, Snapshot{TS: &timestamp.Timestamp{}})
   715  	if err != nil {
   716  		return nil, err
   717  	}
   718  
   719  	tblName := string(stmt.Table.ToTableName().ObjectName)
   720  	obj, tableDef := ctx.Resolve(dbName, tblName, Snapshot{TS: &timestamp.Timestamp{}})
   721  	if tableDef == nil {
   722  		return nil, moerr.NewNoSuchTable(ctx.GetContext(), dbName, tblName)
   723  	}
   724  
   725  	ddlType := plan.DataDefinition_SHOW_COLUMNS
   726  	var sql string
   727  
   728  	var sub *SubscriptionMeta
   729  	if obj.PubInfo != nil {
   730  		accountId = uint32(obj.PubInfo.GetTenantId())
   731  		dbName = obj.SchemaName
   732  		sub = &SubscriptionMeta{
   733  			AccountId: obj.PubInfo.GetTenantId(),
   734  		}
   735  		ctx.SetQueryingSubscription(sub)
   736  		defer func() {
   737  			ctx.SetQueryingSubscription(nil)
   738  		}()
   739  	}
   740  
   741  	if accountId == catalog.System_Account {
   742  		mustShowTable := "att_relname = 'mo_database' or att_relname = 'mo_tables' or att_relname = 'mo_columns'"
   743  		clusterTable := ""
   744  		if util.TableIsClusterTable(tableDef.GetTableType()) {
   745  			clusterTable = fmt.Sprintf(" or att_relname = '%s'", tblName)
   746  		}
   747  		accountClause := fmt.Sprintf("account_id = %v or (account_id = 0 and (%s))", accountId, mustShowTable+clusterTable)
   748  		sql = "SELECT count(attname) `Number of columns in %s` FROM %s.mo_columns WHERE att_database = '%s' AND att_relname = '%s' AND (%s) AND att_is_hidden = 0"
   749  		sql = fmt.Sprintf(sql, tblName, MO_CATALOG_DB_NAME, dbName, tblName, accountClause)
   750  	} else {
   751  		sql = "SELECT count(attname) `Number of columns in %s` FROM %s.mo_columns WHERE att_database = '%s' AND att_relname = '%s'AND att_is_hidden = 0"
   752  		sql = fmt.Sprintf(sql, tblName, MO_CATALOG_DB_NAME, dbName, tblName)
   753  	}
   754  
   755  	return returnByRewriteSQL(ctx, sql, ddlType)
   756  }
   757  
   758  func buildShowTableValues(stmt *tree.ShowTableValues, ctx CompilerContext) (*Plan, error) {
   759  	dbName, err := databaseIsValid(getSuitableDBName(stmt.Table.GetDBName(), stmt.DbName), ctx, Snapshot{TS: &timestamp.Timestamp{}})
   760  	if err != nil {
   761  		return nil, err
   762  	}
   763  
   764  	tblName := string(stmt.Table.ToTableName().ObjectName)
   765  	obj, tableDef := ctx.Resolve(dbName, tblName, Snapshot{TS: &timestamp.Timestamp{}})
   766  	if tableDef == nil {
   767  		return nil, moerr.NewNoSuchTable(ctx.GetContext(), dbName, tblName)
   768  	}
   769  
   770  	if obj.PubInfo != nil {
   771  		sub := &SubscriptionMeta{
   772  			AccountId: obj.PubInfo.GetTenantId(),
   773  		}
   774  		ctx.SetQueryingSubscription(sub)
   775  		defer func() {
   776  			ctx.SetQueryingSubscription(nil)
   777  		}()
   778  	}
   779  
   780  	ddlType := plan.DataDefinition_SHOW_TARGET
   781  
   782  	sql := "SELECT"
   783  	isAllNull := true
   784  	for _, col := range tableDef.Cols {
   785  		if col.Hidden {
   786  			continue
   787  		}
   788  		colName := col.Name
   789  		if types.T(col.GetTyp().Id) == types.T_json {
   790  			sql += " null as `max(%s)`, null as `min(%s)`,"
   791  			sql = fmt.Sprintf(sql, colName, colName)
   792  		} else {
   793  			sql += " max(%s), min(%s),"
   794  			sql = fmt.Sprintf(sql, colName, colName)
   795  			isAllNull = false
   796  		}
   797  	}
   798  	sql = sql[:len(sql)-1]
   799  	sql += " FROM %s"
   800  
   801  	if isAllNull {
   802  		sql += " LIMIT 1"
   803  	}
   804  	sql = fmt.Sprintf(sql, tblName)
   805  
   806  	return returnByRewriteSQL(ctx, sql, ddlType)
   807  }
   808  
   809  func buildShowColumns(stmt *tree.ShowColumns, ctx CompilerContext) (*Plan, error) {
   810  	if stmt.Like != nil && stmt.Where != nil {
   811  		return nil, moerr.NewSyntaxError(ctx.GetContext(), "like clause and where clause cannot exist at the same time")
   812  	}
   813  
   814  	accountId, err := ctx.GetAccountId()
   815  	if err != nil {
   816  		return nil, err
   817  	}
   818  	dbName, err := databaseIsValid(getSuitableDBName(stmt.Table.GetDBName(), stmt.DBName), ctx, Snapshot{TS: &timestamp.Timestamp{}})
   819  	if err != nil {
   820  		return nil, err
   821  	}
   822  
   823  	tblName := string(stmt.Table.ToTableName().ObjectName)
   824  	obj, tableDef := ctx.Resolve(dbName, tblName, Snapshot{TS: &timestamp.Timestamp{}})
   825  	if tableDef == nil {
   826  		return nil, moerr.NewNoSuchTable(ctx.GetContext(), dbName, tblName)
   827  	}
   828  	var sub *SubscriptionMeta
   829  	if obj.PubInfo != nil {
   830  		dbName = obj.SchemaName
   831  		accountId = uint32(obj.PubInfo.GetTenantId())
   832  		sub = &SubscriptionMeta{
   833  			AccountId: obj.PubInfo.GetTenantId(),
   834  		}
   835  		ctx.SetQueryingSubscription(sub)
   836  		defer func() {
   837  			ctx.SetQueryingSubscription(nil)
   838  		}()
   839  	}
   840  	var keyStr string
   841  	if dbName == catalog.MO_CATALOG && tblName == catalog.MO_DATABASE {
   842  		keyStr = "case when attname = '" + catalog.SystemDBAttr_ID + "' then 'PRI' else '' END as `Key`"
   843  	} else if dbName == catalog.MO_CATALOG && tblName == catalog.MO_TABLES {
   844  		keyStr = "case when attname = '" + catalog.SystemRelAttr_ID + "' then 'PRI' else '' END as `Key`"
   845  	} else if dbName == catalog.MO_CATALOG && tblName == catalog.MO_COLUMNS {
   846  		keyStr = "case when attname = '" + catalog.SystemColAttr_UniqName + "' then 'PRI' else '' END as `Key`"
   847  	} else {
   848  		if tableDef.Pkey != nil || len(tableDef.Fkeys) != 0 || len(tableDef.Indexes) != 0 {
   849  			keyStr += "case"
   850  			if tableDef.Pkey != nil {
   851  				for _, name := range tableDef.Pkey.Names {
   852  					keyStr += " when attname = "
   853  					keyStr += "'" + name + "'"
   854  					keyStr += " then 'PRI'"
   855  				}
   856  			}
   857  			if len(tableDef.Fkeys) != 0 {
   858  				colIdToName := make(map[uint64]string)
   859  				for _, col := range tableDef.Cols {
   860  					if col.Hidden {
   861  						continue
   862  					}
   863  					colIdToName[col.ColId] = col.Name
   864  				}
   865  				for _, fk := range tableDef.Fkeys {
   866  					for _, colId := range fk.Cols {
   867  						keyStr += " when attname = "
   868  						keyStr += "'" + colIdToName[colId] + "'"
   869  						keyStr += " then 'MUL'"
   870  					}
   871  				}
   872  			}
   873  			if tableDef.Indexes != nil {
   874  				for _, indexdef := range tableDef.Indexes {
   875  					name := indexdef.Parts[0]
   876  					if indexdef.Unique {
   877  						if isPrimaryKey(tableDef, indexdef.Parts) {
   878  							for _, name := range indexdef.Parts {
   879  								keyStr += " when attname = "
   880  								keyStr += "'" + name + "'"
   881  								keyStr += " then 'PRI'"
   882  							}
   883  						} else if isMultiplePriKey(indexdef) {
   884  							keyStr += " when attname = "
   885  							keyStr += "'" + name + "'"
   886  							keyStr += " then 'MUL'"
   887  						} else {
   888  							keyStr += " when attname = "
   889  							keyStr += "'" + name + "'"
   890  							keyStr += " then 'UNI'"
   891  						}
   892  					} else {
   893  						keyStr += " when attname = "
   894  						keyStr += "'" + name + "'"
   895  						keyStr += " then 'MUL'"
   896  					}
   897  				}
   898  			}
   899  			keyStr += " else '' END as `Key`"
   900  		} else {
   901  			keyStr = "'' as `Key`"
   902  		}
   903  	}
   904  
   905  	ddlType := plan.DataDefinition_SHOW_COLUMNS
   906  
   907  	var sql string
   908  	if accountId == catalog.System_Account {
   909  		mustShowTable := "att_relname = 'mo_database' or att_relname = 'mo_tables' or att_relname = 'mo_columns'"
   910  		clusterTable := ""
   911  		if util.TableIsClusterTable(tableDef.GetTableType()) {
   912  			clusterTable = fmt.Sprintf(" or att_relname = '%s'", tblName)
   913  		}
   914  		accountClause := fmt.Sprintf("account_id = %v or (account_id = 0 and (%s))", accountId, mustShowTable+clusterTable)
   915  		sql = "SELECT attname `Field`, CASE WHEN LENGTH(attr_enum) > 0 THEN mo_show_visible_bin_enum(atttyp, attr_enum) ELSE mo_show_visible_bin(atttyp, 3) END AS `Type`, iff(attnotnull = 0, 'YES', 'NO') `Null`, %s, mo_show_visible_bin(att_default, 1) `Default`, '' `Extra`,  att_comment `Comment` FROM %s.mo_columns WHERE att_database = '%s' AND att_relname = '%s' AND (%s) AND att_is_hidden = 0 ORDER BY attnum"
   916  		if stmt.Full {
   917  			sql = "SELECT attname `Field`, CASE WHEN LENGTH(attr_enum) > 0 THEN mo_show_visible_bin_enum(atttyp, attr_enum) ELSE mo_show_visible_bin(atttyp, 3) END AS `Type`, null `Collation`, iff(attnotnull = 0, 'YES', 'NO') `Null`, %s, mo_show_visible_bin(att_default, 1) `Default`,  '' `Extra`,'select,insert,update,references' `Privileges`, att_comment `Comment` FROM %s.mo_columns WHERE att_database = '%s' AND att_relname = '%s' AND (%s) AND att_is_hidden = 0 ORDER BY attnum"
   918  		}
   919  		sql = fmt.Sprintf(sql, keyStr, MO_CATALOG_DB_NAME, dbName, tblName, accountClause)
   920  	} else {
   921  		sql = "SELECT attname `Field`, CASE WHEN LENGTH(attr_enum) > 0 THEN mo_show_visible_bin_enum(atttyp, attr_enum) ELSE mo_show_visible_bin(atttyp, 3) END AS `Type`, iff(attnotnull = 0, 'YES', 'NO') `Null`, %s, mo_show_visible_bin(att_default, 1) `Default`, '' `Extra`,  att_comment `Comment` FROM %s.mo_columns WHERE att_database = '%s' AND att_relname = '%s' AND att_is_hidden = 0 ORDER BY attnum"
   922  		if stmt.Full {
   923  			sql = "SELECT attname `Field`, CASE WHEN LENGTH(attr_enum) > 0 THEN mo_show_visible_bin_enum(atttyp, attr_enum) ELSE mo_show_visible_bin(atttyp, 3) END AS `Type`, null `Collation`, iff(attnotnull = 0, 'YES', 'NO') `Null`, %s, mo_show_visible_bin(att_default, 1) `Default`,  '' `Extra`,'select,insert,update,references' `Privileges`, att_comment `Comment` FROM %s.mo_columns WHERE att_database = '%s' AND att_relname = '%s' AND att_is_hidden = 0 ORDER BY attnum"
   924  		}
   925  		sql = fmt.Sprintf(sql, keyStr, MO_CATALOG_DB_NAME, dbName, tblName)
   926  	}
   927  
   928  	if stmt.Where != nil {
   929  		return returnByWhereAndBaseSQL(ctx, sql, stmt.Where, ddlType)
   930  	}
   931  
   932  	if stmt.Like != nil {
   933  		// append filter [AND ma.attname like stmt.Like] to WHERE clause
   934  		likeExpr := stmt.Like
   935  		likeExpr.Left = tree.SetUnresolvedName("attname")
   936  		return returnByLikeAndSQL(ctx, sql, likeExpr, ddlType)
   937  	}
   938  
   939  	return returnByRewriteSQL(ctx, sql, ddlType)
   940  }
   941  
   942  func buildShowTableStatus(stmt *tree.ShowTableStatus, ctx CompilerContext) (*Plan, error) {
   943  	if stmt.Like != nil && stmt.Where != nil {
   944  		return nil, moerr.NewSyntaxError(ctx.GetContext(), "like clause and where clause cannot exist at the same time")
   945  	}
   946  
   947  	dbName, err := databaseIsValid(stmt.DbName, ctx, Snapshot{TS: &timestamp.Timestamp{}})
   948  	if err != nil {
   949  		return nil, err
   950  	}
   951  
   952  	stmt.DbName = dbName
   953  
   954  	ddlType := plan.DataDefinition_SHOW_TABLE_STATUS
   955  	accountId, err := ctx.GetAccountId()
   956  	if err != nil {
   957  		return nil, err
   958  	}
   959  
   960  	sub, err := ctx.GetSubscriptionMeta(dbName, Snapshot{TS: &timestamp.Timestamp{}})
   961  	if err != nil {
   962  		return nil, err
   963  	}
   964  	if sub != nil {
   965  		accountId = uint32(sub.AccountId)
   966  		dbName = sub.DbName
   967  		ctx.SetQueryingSubscription(sub)
   968  		defer func() {
   969  			ctx.SetQueryingSubscription(nil)
   970  		}()
   971  	}
   972  
   973  	mustShowTable := "relname = 'mo_database' or relname = 'mo_tables' or relname = 'mo_columns'"
   974  	accountClause := fmt.Sprintf("account_id = %v or (account_id = 0 and (%s))", accountId, mustShowTable)
   975  	sql := `select
   976  				relname as 'Name',
   977  				'Tae' as 'Engine',
   978  				'Dynamic' as 'Row_format',
   979  				0 as 'Rows',
   980  				0 as 'Avg_row_length',
   981  				0 as 'Data_length',
   982  				0 as 'Max_data_length',
   983  				0 as 'Index_length',
   984  				'NULL' as 'Data_free',
   985  				0 as 'Auto_increment',
   986  				created_time as 'Create_time',
   987  				'NULL' as 'Update_time',
   988  				'NULL' as 'Check_time',
   989  				'utf-8' as 'Collation',
   990  				'NULL' as 'Checksum',
   991  				'' as 'Create_options',
   992  				rel_comment as 'Comment',
   993  				owner as 'Role_id',
   994  				'-' as 'Role_name'
   995  			from
   996  				%s.mo_tables
   997  			where
   998  				reldatabase = '%s'
   999  				and relkind != '%s'
  1000  				and relname != '%s'
  1001  				and relname not like '%s'
  1002  				and (%s)`
  1003  	sql = fmt.Sprintf(sql, MO_CATALOG_DB_NAME, dbName, catalog.SystemPartitionRel, catalog.MOAutoIncrTable, catalog.IndexTableNamePrefix+"%", accountClause)
  1004  
  1005  	if stmt.Where != nil {
  1006  		return returnByWhereAndBaseSQL(ctx, sql, stmt.Where, ddlType)
  1007  	}
  1008  
  1009  	if stmt.Like != nil {
  1010  		// append filter [AND ma.relname like stmt.Like] to WHERE clause
  1011  		likeExpr := stmt.Like
  1012  		likeExpr.Left = tree.SetUnresolvedName("relname")
  1013  		return returnByLikeAndSQL(ctx, sql, likeExpr, ddlType)
  1014  	}
  1015  
  1016  	return returnByRewriteSQL(ctx, sql, ddlType)
  1017  }
  1018  
  1019  // TODO: Implement show target
  1020  func buildShowTarget(stmt *tree.ShowTarget, ctx CompilerContext) (*Plan, error) {
  1021  	ddlType := plan.DataDefinition_SHOW_TARGET
  1022  	sql := ""
  1023  	switch stmt.Type {
  1024  	case tree.ShowCharset:
  1025  		sql = "select '' as `Charset`, '' as `Description`, '' as `Default collation`, '' as `Maxlen` where 0"
  1026  	case tree.ShowTriggers:
  1027  		return buildShowTriggers(stmt, ctx)
  1028  	default:
  1029  		sql = "select 1 where 0"
  1030  	}
  1031  	return returnByRewriteSQL(ctx, sql, ddlType)
  1032  }
  1033  
  1034  func buildShowLocks(stmt *tree.ShowLocks, ctx CompilerContext) (*Plan, error) {
  1035  	ddlType := plan.DataDefinition_SHOW_TARGET
  1036  	sql := "select 1 where 0"
  1037  	return returnByRewriteSQL(ctx, sql, ddlType)
  1038  }
  1039  
  1040  func buildShowNodeList(stmt *tree.ShowNodeList, ctx CompilerContext) (*Plan, error) {
  1041  	ddlType := plan.DataDefinition_SHOW_TARGET
  1042  	sql := "select 1 where 0"
  1043  	return returnByRewriteSQL(ctx, sql, ddlType)
  1044  }
  1045  
  1046  func buildShowFunctionOrProcedureStatus(stmt *tree.ShowFunctionOrProcedureStatus, ctx CompilerContext) (*Plan, error) {
  1047  	var sql string
  1048  
  1049  	ddlType := plan.DataDefinition_SHOW_TARGET
  1050  	if stmt.Like != nil && stmt.Where != nil {
  1051  		return nil, moerr.NewSyntaxError(ctx.GetContext(), "like clause and where clause cannot exist at the same time")
  1052  	}
  1053  
  1054  	if stmt.IsFunction {
  1055  		sql = fmt.Sprintf("SELECT db as `Db`, name as `Name`, type as `Type`, definer as `Definer`, modified_time as `Modified`, created_time as `Created`, security_type as `Security_type`, comment as `Comment`, character_set_client, collation_connection, database_collation as `Database Collation` FROM %s.mo_user_defined_function", MO_CATALOG_DB_NAME)
  1056  	} else {
  1057  		sql = fmt.Sprintf("SELECT db as `Db`, name as `Name`, type as `Type`, definer as `Definer`, modified_time as `Modified`, created_time as `Created`, security_type as `Security_type`, comment as `Comment`, character_set_client, collation_connection, database_collation as `Database Collation` FROM %s.mo_stored_procedure", MO_CATALOG_DB_NAME)
  1058  	}
  1059  
  1060  	if stmt.Where != nil {
  1061  		return returnByWhereAndBaseSQL(ctx, sql, stmt.Where, ddlType)
  1062  	}
  1063  
  1064  	if stmt.Like != nil {
  1065  		// append filter [AND ma.attname like stmt.Like] to WHERE clause
  1066  		likeExpr := stmt.Like
  1067  		likeExpr.Left = tree.SetUnresolvedName("name")
  1068  		return returnByLikeAndSQL(ctx, sql, likeExpr, ddlType)
  1069  	}
  1070  
  1071  	return returnByRewriteSQL(ctx, sql, ddlType)
  1072  }
  1073  
  1074  func buildShowTriggers(stmt *tree.ShowTarget, ctx CompilerContext) (*Plan, error) {
  1075  	if stmt.Like != nil && stmt.Where != nil {
  1076  		return nil, moerr.NewSyntaxError(ctx.GetContext(), "like clause and where clause cannot exist at the same time")
  1077  	}
  1078  
  1079  	dbName, err := databaseIsValid(stmt.DbName, ctx, Snapshot{TS: &timestamp.Timestamp{}})
  1080  	if err != nil {
  1081  		return nil, err
  1082  	}
  1083  	stmt.DbName = dbName
  1084  
  1085  	ddlType := plan.DataDefinition_SHOW_TARGET
  1086  	sql := fmt.Sprintf("SELECT trigger_name as `Trigger`, event_manipulation as `Event`, event_object_table as `Table`, action_statement as `Statement`, action_timing as `Timing`, created as `Created`, sql_mode, definer as `Definer`, character_set_client, collation_connection, database_collation as `Database Collation` FROM %s.TRIGGERS ", INFORMATION_SCHEMA)
  1087  
  1088  	if stmt.Where != nil {
  1089  		return returnByWhereAndBaseSQL(ctx, sql, stmt.Where, ddlType)
  1090  	}
  1091  
  1092  	if stmt.Like != nil {
  1093  		// append filter [AND ma.attname like stmt.Like] to WHERE clause
  1094  		likeExpr := stmt.Like
  1095  		likeExpr.Left = tree.SetUnresolvedName("event_object_table")
  1096  		return returnByLikeAndSQL(ctx, sql, likeExpr, ddlType)
  1097  	}
  1098  
  1099  	return returnByRewriteSQL(ctx, sql, ddlType)
  1100  }
  1101  
  1102  func buildShowIndex(stmt *tree.ShowIndex, ctx CompilerContext) (*Plan, error) {
  1103  	dbName, err := databaseIsValid(getSuitableDBName(stmt.TableName.GetDBName(), stmt.DbName), ctx, Snapshot{TS: &timestamp.Timestamp{}})
  1104  	if err != nil {
  1105  		return nil, err
  1106  	}
  1107  	tblName := stmt.TableName.GetTableName()
  1108  	obj, tableDef := ctx.Resolve(dbName, tblName, Snapshot{TS: &timestamp.Timestamp{}})
  1109  	if tableDef == nil {
  1110  		return nil, moerr.NewNoSuchTable(ctx.GetContext(), dbName, tblName)
  1111  	}
  1112  
  1113  	ddlType := plan.DataDefinition_SHOW_INDEX
  1114  
  1115  	if obj.PubInfo != nil {
  1116  		sub := &SubscriptionMeta{
  1117  			AccountId: obj.PubInfo.GetTenantId(),
  1118  		}
  1119  		dbName = obj.SchemaName
  1120  		ctx.SetQueryingSubscription(sub)
  1121  		defer func() {
  1122  			ctx.SetQueryingSubscription(nil)
  1123  		}()
  1124  	}
  1125  
  1126  	sql := "select " +
  1127  		"`tcl`.`att_relname` as `Table`, " +
  1128  		"if(`idx`.`type` = 'MULTIPLE', 1, 0) as `Non_unique`, " +
  1129  		"`idx`.`name` as `Key_name`, " +
  1130  		"`idx`.`ordinal_position` as `Seq_in_index`, " +
  1131  		"`idx`.`column_name` as `Column_name`, " +
  1132  		"'A' as `Collation`, 0 as `Cardinality`, " +
  1133  		"'NULL' as `Sub_part`, " +
  1134  		"'NULL' as `Packed`, " +
  1135  		"if(`tcl`.`attnotnull` = 0, 'YES', '') as `Null`, " +
  1136  		"`idx`.`algo` as 'Index_type', " +
  1137  		"'' as `Comment`, " +
  1138  		"`idx`.`comment` as `Index_comment`, " +
  1139  		"`idx`.`algo_params` as `Index_params`, " +
  1140  		"if(`idx`.`is_visible` = 1, 'YES', 'NO') as `Visible`, " +
  1141  		"'NULL' as `Expression` " +
  1142  		"from `%s`.`mo_indexes` `idx` left join `%s`.`mo_columns` `tcl` " +
  1143  		"on (`idx`.`table_id` = `tcl`.`att_relname_id` and `idx`.`column_name` = `tcl`.`attname`) " +
  1144  		"where `tcl`.`att_database` = '%s' AND " +
  1145  		"`tcl`.`att_relname` = '%s' AND " +
  1146  		"`idx`.`column_name` NOT LIKE '%s' " +
  1147  		// Below `GROUP BY` is used instead of DISTINCT(`idx`.`name`) to handle IVF-FLAT or multi table indexes scenarios.
  1148  		// NOTE: We need to add all the table column names to the GROUP BY clause
  1149  		//
  1150  		// Without `GROUP BY`, we will printing the same index multiple times for IVFFLAT index.
  1151  		// (there are multiple entries in mo_indexes for the same index, with differing algo_table_type and index_table_name).
  1152  		// mysql> show index from tbl;
  1153  		//+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+-----------------------------------------+---------+------------+
  1154  		//| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Index_params                            | Visible | Expression |
  1155  		//+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+-----------------------------------------+---------+------------+
  1156  		//| tbl   |          1 | idx1     |            1 | embedding   | A         |           0 | NULL     | NULL   | YES  | ivfflat    |         |               | {"lists":"2","op_type":"vector_l2_ops"} | YES     | NULL       |
  1157  		//| tbl   |          1 | idx1     |            1 | embedding   | A         |           0 | NULL     | NULL   | YES  | ivfflat    |         |               | {"lists":"2","op_type":"vector_l2_ops"} | YES     | NULL       |
  1158  		//| tbl   |          1 | idx1     |            1 | embedding   | A         |           0 | NULL     | NULL   | YES  | ivfflat    |         |               | {"lists":"2","op_type":"vector_l2_ops"} | YES     | NULL       |
  1159  		//| tbl   |          0 | PRIMARY  |            1 | id          | A         |           0 | NULL     | NULL   |      |            |         |               |                                         | YES     | NULL       |
  1160  		//+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+-----------------------------------------+---------+------------+
  1161  		//
  1162  		// With `GROUP BY`, we print
  1163  		// mysql> show index from tbl;
  1164  		//+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+-----------------------------------------+---------+------------+
  1165  		//| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Index_params                            | Visible | Expression |
  1166  		//+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+-----------------------------------------+---------+------------+
  1167  		//| tbl   |          0 | PRIMARY  |            1 | id          | A         |           0 | NULL     | NULL   |      |            |         |               |                                         | YES     | NULL       |
  1168  		//| tbl   |          1 | idx1     |            1 | embedding   | A         |           0 | NULL     | NULL   | YES  | ivfflat    |         |               | {"lists":"2","op_type":"vector_l2_ops"} | YES     | NULL       |
  1169  		//+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+-----------------------------------------+---------+------------+
  1170  		"GROUP BY `tcl`.`att_relname`, `idx`.`type`, `idx`.`name`, `idx`.`ordinal_position`, " +
  1171  		"`idx`.`column_name`, `tcl`.`attnotnull`, `idx`.`algo`, `idx`.`comment`, " +
  1172  		"`idx`.`algo_params`, `idx`.`is_visible`" +
  1173  		";"
  1174  	showIndexSql := fmt.Sprintf(sql, MO_CATALOG_DB_NAME, MO_CATALOG_DB_NAME, dbName, tblName, catalog.AliasPrefix+"%")
  1175  
  1176  	if stmt.Where != nil {
  1177  		return returnByWhereAndBaseSQL(ctx, showIndexSql, stmt.Where, ddlType)
  1178  	}
  1179  	return returnByRewriteSQL(ctx, showIndexSql, ddlType)
  1180  }
  1181  
  1182  // TODO: Improve SQL. Currently, Lack of the mata of grants
  1183  func buildShowGrants(stmt *tree.ShowGrants, ctx CompilerContext) (*Plan, error) {
  1184  
  1185  	ddlType := plan.DataDefinition_SHOW_TARGET
  1186  	if stmt.ShowGrantType == tree.GrantForRole {
  1187  		role_name := stmt.Roles[0].UserName
  1188  		sql := "select concat(\"GRANT \", p.privilege_name, ' ON ', p.obj_type, ' ', case p.obj_type when 'account' then '' else p.privilege_level end,   \" `%s`\")  as `Grants for %s` from  %s.mo_role_privs as p where p.role_name = '%s';"
  1189  		sql = fmt.Sprintf(sql, role_name, role_name, MO_CATALOG_DB_NAME, role_name)
  1190  		return returnByRewriteSQL(ctx, sql, ddlType)
  1191  	} else {
  1192  		if stmt.Hostname == "" {
  1193  			stmt.Hostname = MO_DEFUALT_HOSTNAME
  1194  		}
  1195  		if stmt.Username == "" {
  1196  			stmt.Username = ctx.GetUserName()
  1197  		}
  1198  		sql := "select concat(\"GRANT \", p.privilege_name, ' ON ', p.obj_type, ' ', case p.obj_type when 'account' then '' else p.privilege_level end,   \" `%s`\", \"@\", \"`%s`\")  as `Grants for %s@localhost` from mo_catalog.mo_user as u, mo_catalog.mo_role_privs as p, mo_catalog.mo_user_grant as g where g.role_id = p.role_id and g.user_id = u.user_id and u.user_name = '%s' and u.user_host = '%s';"
  1199  		sql = fmt.Sprintf(sql, stmt.Username, stmt.Hostname, stmt.Username, stmt.Username, stmt.Hostname)
  1200  		return returnByRewriteSQL(ctx, sql, ddlType)
  1201  	}
  1202  }
  1203  
  1204  func buildShowRoles(stmt *tree.ShowRolesStmt, ctx CompilerContext) (*Plan, error) {
  1205  	ddlType := plan.DataDefinition_SHOW_TARGET
  1206  	sql := fmt.Sprintf("SELECT role_name as `ROLE_NAME`, creator as `CREATOR`, created_time as `CREATED_TIME`, comments as `COMMENTS` FROM %s.mo_role;", MO_CATALOG_DB_NAME)
  1207  
  1208  	if stmt.Like != nil {
  1209  		// append filter [AND mo_role.role_name like stmt.Like] to WHERE clause
  1210  		likeExpr := stmt.Like
  1211  		likeExpr.Left = tree.SetUnresolvedName("role_name")
  1212  		return returnByLikeAndSQL(ctx, sql, likeExpr, ddlType)
  1213  	}
  1214  
  1215  	return returnByRewriteSQL(ctx, sql, ddlType)
  1216  }
  1217  
  1218  func buildShowStages(stmt *tree.ShowStages, ctx CompilerContext) (*Plan, error) {
  1219  	ddlType := plan.DataDefinition_SHOW_TARGET
  1220  	sql := fmt.Sprintf("SELECT stage_name as `STAGE_NAME`, url as `URL`, case stage_status when 'enabled' then 'ENABLED' else 'DISABLED' end as `STATUS`,  comment as `COMMENT` FROM %s.mo_stages;", MO_CATALOG_DB_NAME)
  1221  
  1222  	if stmt.Like != nil {
  1223  		// append filter [AND mo_stages.stage_name like stmt.Like] to WHERE clause
  1224  		likeExpr := stmt.Like
  1225  		likeExpr.Left = tree.SetUnresolvedName("stage_name")
  1226  		return returnByLikeAndSQL(ctx, sql, likeExpr, ddlType)
  1227  	}
  1228  
  1229  	return returnByRewriteSQL(ctx, sql, ddlType)
  1230  }
  1231  
  1232  func buildShowSnapShots(stmt *tree.ShowSnapShots, ctx CompilerContext) (*Plan, error) {
  1233  	ddlType := plan.DataDefinition_SHOW_TARGET
  1234  	sql := fmt.Sprintf("SELECT sname as `SNAPSHOT_NAME`, CAST_NANO_TO_TIMESTAMP(ts) as `TIMESTAMP`,  level as `SNAPSHOT_LEVEL`, account_name as `ACCOUNT_NAME`, database_name as `DATABASE_NAME`, table_name as `TABLE_NAME` FROM %s.mo_snapshots ORDER BY ts DESC", MO_CATALOG_DB_NAME)
  1235  
  1236  	if stmt.Where != nil {
  1237  		return returnByWhereAndBaseSQL(ctx, sql, stmt.Where, ddlType)
  1238  	}
  1239  
  1240  	return returnByRewriteSQL(ctx, sql, ddlType)
  1241  }
  1242  
  1243  func buildShowAccountUpgrade(stmt *tree.ShowAccountUpgrade, ctx CompilerContext) (*Plan, error) {
  1244  	ddlType := plan.DataDefinition_SHOW_UPGRADE
  1245  	sql := fmt.Sprintf("select account_name as `account_name`, create_version as `current_version` from %s.mo_account order by account_id;", MO_CATALOG_DB_NAME)
  1246  	return returnByRewriteSQL(ctx, sql, ddlType)
  1247  }
  1248  
  1249  func buildShowVariables(stmt *tree.ShowVariables, ctx CompilerContext) (*Plan, error) {
  1250  	showVariables := &plan.ShowVariables{
  1251  		Global: stmt.Global,
  1252  	}
  1253  
  1254  	// we deal with 'show vriables' statement in frontend now.
  1255  	// so just return an empty plan in building plan for prepare statment is ok.
  1256  
  1257  	// if stmt.Like != nil && stmt.Where != nil {
  1258  	// 	return nil, moerr.NewSyntaxError(ctx.GetContext(), "like clause and where clause cannot exist at the same time")
  1259  	// }
  1260  
  1261  	// builder := NewQueryBuilder(plan.Query_SELECT, ctx)
  1262  	// binder := NewWhereBinder(builder, &BindContext{})
  1263  
  1264  	// if stmt.Like != nil {
  1265  	//  // here will error because stmt.Like.Left is nil, you need add left expr like : stmt.Like.Left = tree.SetUnresolvedName("column_name")
  1266  	//  // but we have no column name, because Variables is save in a hashmap in frontend, not a table.
  1267  	// 	expr, err := binder.bindComparisonExpr(stmt.Like, 0, false)
  1268  	// 	if err != nil {
  1269  	// 		return nil, err
  1270  	// 	}
  1271  	// 	showVariables.Where = append(showVariables.Where, expr)
  1272  	// }
  1273  	// if stmt.Where != nil {
  1274  	// 	exprs, err := splitAndBindCondition(stmt.Where.Expr, &BindContext{})
  1275  	// 	if err != nil {
  1276  	// 		return nil, err
  1277  	// 	}
  1278  	// 	showVariables.Where = append(showVariables.Where, exprs...)
  1279  	// }
  1280  
  1281  	return &Plan{
  1282  		Plan: &plan.Plan_Ddl{
  1283  			Ddl: &plan.DataDefinition{
  1284  				DdlType: plan.DataDefinition_SHOW_VARIABLES,
  1285  				Definition: &plan.DataDefinition_ShowVariables{
  1286  					ShowVariables: showVariables,
  1287  				},
  1288  			},
  1289  		},
  1290  	}, nil
  1291  }
  1292  
  1293  func buildShowStatus(stmt *tree.ShowStatus, ctx CompilerContext) (*Plan, error) {
  1294  	ddlType := plan.DataDefinition_SHOW_STATUS
  1295  	sql := "select '' as `Variable_name`, '' as `Value` where 0"
  1296  	return returnByRewriteSQL(ctx, sql, ddlType)
  1297  }
  1298  
  1299  func buildShowProcessList(ctx CompilerContext) (*Plan, error) {
  1300  	ddlType := plan.DataDefinition_SHOW_PROCESSLIST
  1301  	// "show processlist" is implemented by table function processlist().
  1302  	sql := "select * from processlist() a"
  1303  	return returnByRewriteSQL(ctx, sql, ddlType)
  1304  }
  1305  
  1306  func buildShowPublication(stmt *tree.ShowPublications, ctx CompilerContext) (*Plan, error) {
  1307  	ddlType := plan.DataDefinition_SHOW_TARGET
  1308  	sql := "select" +
  1309  		" pub_name as `publication`," +
  1310  		" database_name as `database`," +
  1311  		" created_time as `create_time`," +
  1312  		" update_time as `update_time`," +
  1313  		" case account_list " +
  1314  		" 	when 'all' then cast('*' as text)" +
  1315  		" 	else account_list" +
  1316  		" end as `sub_account`," +
  1317  		" comment as `comments`" +
  1318  		" from mo_catalog.mo_pubs"
  1319  	like := stmt.Like
  1320  	if like != nil {
  1321  		right, ok := like.Right.(*tree.NumVal)
  1322  		if !ok || right.Value.Kind() != constant.String {
  1323  			return nil, moerr.NewInternalError(ctx.GetContext(), "like clause must be a string")
  1324  		}
  1325  		sql += fmt.Sprintf(" where pub_name like '%s' order by pub_name;", constant.StringVal(right.Value))
  1326  	} else {
  1327  		sql += " order by update_time desc, created_time desc;"
  1328  	}
  1329  	return returnByRewriteSQL(ctx, sql, ddlType)
  1330  }
  1331  
  1332  func buildShowCreatePublications(stmt *tree.ShowCreatePublications, ctx CompilerContext) (*Plan, error) {
  1333  	ddlType := plan.DataDefinition_SHOW_TARGET
  1334  	sql := fmt.Sprintf("select pub_name as Publication, 'CREATE PUBLICATION ' || pub_name || ' DATABASE ' || database_name || ' ACCOUNT ' || account_list as 'Create Publication' from mo_catalog.mo_pubs where pub_name='%s';", stmt.Name)
  1335  	return returnByRewriteSQL(ctx, sql, ddlType)
  1336  }
  1337  
  1338  func returnByRewriteSQL(ctx CompilerContext, sql string,
  1339  	ddlType plan.DataDefinition_DdlType) (*Plan, error) {
  1340  	newStmt, err := getRewriteSQLStmt(ctx, sql)
  1341  	defer newStmt.Free()
  1342  	if err != nil {
  1343  		return nil, err
  1344  	}
  1345  	return getReturnDdlBySelectStmt(ctx, newStmt, ddlType)
  1346  }
  1347  
  1348  func returnByWhereAndBaseSQL(ctx CompilerContext, baseSQL string,
  1349  	where *tree.Where, ddlType plan.DataDefinition_DdlType) (*Plan, error) {
  1350  	sql := fmt.Sprintf("SELECT * FROM (%s) tbl", baseSQL)
  1351  	// logutil.Info(sql)
  1352  	newStmt, err := getRewriteSQLStmt(ctx, sql)
  1353  	defer newStmt.Free()
  1354  	if err != nil {
  1355  		return nil, err
  1356  	}
  1357  	// set show statement's where clause to new statement
  1358  	newStmt.(*tree.Select).Select.(*tree.SelectClause).Where = where
  1359  	return getReturnDdlBySelectStmt(ctx, newStmt, ddlType)
  1360  }
  1361  
  1362  func returnByLikeAndSQL(ctx CompilerContext, sql string, like *tree.ComparisonExpr,
  1363  	ddlType plan.DataDefinition_DdlType) (*Plan, error) {
  1364  	newStmt, err := getRewriteSQLStmt(ctx, sql)
  1365  	defer newStmt.Free()
  1366  	if err != nil {
  1367  		return nil, err
  1368  	}
  1369  	var whereExpr *tree.Where
  1370  
  1371  	if newStmt.(*tree.Select).Select.(*tree.SelectClause).Where == nil {
  1372  		whereExpr = &tree.Where{
  1373  			Type: "where",
  1374  			Expr: like,
  1375  		}
  1376  	} else {
  1377  		whereExpr = &tree.Where{
  1378  			Type: "where",
  1379  			Expr: &tree.AndExpr{
  1380  				Left:  newStmt.(*tree.Select).Select.(*tree.SelectClause).Where.Expr,
  1381  				Right: like,
  1382  			},
  1383  		}
  1384  	}
  1385  	// set show statement's like clause to new statement
  1386  	newStmt.(*tree.Select).Select.(*tree.SelectClause).Where = whereExpr
  1387  	// logutil.Info(tree.String(newStmt, dialect.MYSQL))
  1388  	return getReturnDdlBySelectStmt(ctx, newStmt, ddlType)
  1389  }
  1390  
  1391  func getRewriteSQLStmt(ctx CompilerContext, sql string) (tree.Statement, error) {
  1392  	newStmts, err := parsers.Parse(ctx.GetContext(), dialect.MYSQL, sql, 1, 0)
  1393  	if err != nil {
  1394  		return nil, err
  1395  	}
  1396  	if len(newStmts) != 1 {
  1397  		return nil, moerr.NewInvalidInput(ctx.GetContext(), "rewrite can only contain one statement, %d provided", len(newStmts))
  1398  	}
  1399  	return newStmts[0], nil
  1400  }
  1401  
  1402  func getReturnDdlBySelectStmt(ctx CompilerContext, stmt tree.Statement,
  1403  	ddlType plan.DataDefinition_DdlType) (*Plan, error) {
  1404  	queryPlan, err := BuildPlan(ctx, stmt, false)
  1405  	if err != nil {
  1406  		return nil, err
  1407  	}
  1408  	return queryPlan, nil
  1409  	// return &Plan{
  1410  	// 	Plan: &plan.Plan_Ddl{
  1411  	// 		Ddl: &plan.DataDefinition{
  1412  	// 			DdlType: ddlType,
  1413  	// 			Query:   queryPlan.GetQuery(),
  1414  	// 		},
  1415  	// 	},
  1416  	// }, nil
  1417  }