github.com/matrixorigin/matrixone@v0.7.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  	"strings"
    22  
    23  	"github.com/matrixorigin/matrixone/pkg/sql/util"
    24  
    25  	"github.com/matrixorigin/matrixone/pkg/catalog"
    26  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    27  	"github.com/matrixorigin/matrixone/pkg/container/types"
    28  	"github.com/matrixorigin/matrixone/pkg/pb/plan"
    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  )
    33  
    34  const MO_CATALOG_DB_NAME = "mo_catalog"
    35  const MO_DEFUALT_HOSTNAME = "localhost"
    36  const INFORMATION_SCHEMA = "information_schema"
    37  
    38  func buildShowCreateDatabase(stmt *tree.ShowCreateDatabase,
    39  	ctx CompilerContext) (*Plan, error) {
    40  	if !ctx.DatabaseExists(stmt.Name) {
    41  		return nil, moerr.NewBadDB(ctx.GetContext(), stmt.Name)
    42  	}
    43  
    44  	// get data from schema
    45  	//sql := fmt.Sprintf("SELECT md.datname as `Database` FROM %s.mo_database md WHERE md.datname = '%s'", MO_CATALOG_DB_NAME, stmt.Name)
    46  	// sql := fmt.Sprintf("SELECT md.datname as `Database`,dat_createsql as `Create Database` FROM %s.mo_database md WHERE md.datname = '%s'", MO_CATALOG_DB_NAME, stmt.Name)
    47  	// return returnByRewriteSQL(ctx, sql, plan.DataDefinition_SHOW_CREATEDATABASE)
    48  
    49  	sqlStr := "select \"%s\" as `Database`, \"%s\" as `Create Database`"
    50  	createSql := fmt.Sprintf("CREATE DATABASE `%s`", stmt.Name)
    51  	sqlStr = fmt.Sprintf(sqlStr, stmt.Name, createSql)
    52  	// logutil.Info(sqlStr)
    53  
    54  	return returnByRewriteSQL(ctx, sqlStr, plan.DataDefinition_SHOW_CREATEDATABASE)
    55  }
    56  
    57  func buildShowCreateTable(stmt *tree.ShowCreateTable, ctx CompilerContext) (*Plan, error) {
    58  	tblName := stmt.Name.Parts[0]
    59  	dbName := ctx.DefaultDatabase()
    60  	if stmt.Name.NumParts == 2 {
    61  		dbName = stmt.Name.Parts[1]
    62  	}
    63  
    64  	_, tableDef := ctx.Resolve(dbName, tblName)
    65  	if tableDef == nil {
    66  		return nil, moerr.NewNoSuchTable(ctx.GetContext(), dbName, tblName)
    67  	}
    68  	if tableDef.TableType == catalog.SystemViewRel {
    69  		newStmt := tree.NewShowCreateView(tree.SetUnresolvedObjectName(1, [3]string{tblName, "", ""}))
    70  		return buildShowCreateView(newStmt, ctx)
    71  	}
    72  
    73  	// sql := `
    74  	// 	SELECT *
    75  	// 		FROM %s.mo_tables mt JOIN %s.mo_columns mc
    76  	// 			ON mt.relname = mc.att_relname and mt.reldatabase=mc.att_database
    77  	// 	WHERE mt.reldatabase = '%s' AND mt.relname = '%s'
    78  	// `
    79  	// sql = fmt.Sprintf(sql, MO_CATALOG_DB_NAME, MO_CATALOG_DB_NAME, dbName, tblName)
    80  	// logutil.Info(sql)
    81  
    82  	var createStr string
    83  	if tableDef.TableType == catalog.SystemOrdinaryRel {
    84  		createStr = fmt.Sprintf("CREATE TABLE `%s` (", tblName)
    85  	} else if tableDef.TableType == catalog.SystemExternalRel {
    86  		createStr = fmt.Sprintf("CREATE EXTERNAL TABLE `%s` (", tblName)
    87  	}
    88  	rowCount := 0
    89  	var pkDefs []string
    90  	isClusterTable := util.TableIsClusterTable(tableDef.TableType)
    91  
    92  	colIdToName := make(map[uint64]string)
    93  	for _, col := range tableDef.Cols {
    94  		colName := col.Name
    95  		colIdToName[col.ColId] = col.Name
    96  		if colName == catalog.Row_ID {
    97  			continue
    98  		}
    99  		//the non-sys account skips the column account_id of the cluster table
   100  		if util.IsClusterTableAttribute(colName) &&
   101  			isClusterTable &&
   102  			ctx.GetAccountId() != catalog.System_Account {
   103  			continue
   104  		}
   105  		nullOrNot := "NOT NULL"
   106  		// col.Default must be not nil
   107  		if len(col.Default.OriginString) > 0 {
   108  			nullOrNot = "DEFAULT " + col.Default.OriginString
   109  		} else if col.Default.NullAbility {
   110  			nullOrNot = "DEFAULT NULL"
   111  		}
   112  
   113  		if col.Typ.AutoIncr {
   114  			nullOrNot = "NOT NULL AUTO_INCREMENT"
   115  		}
   116  
   117  		var hasAttrComment string
   118  		if col.Comment != "" {
   119  			hasAttrComment = " COMMENT '" + col.Comment + "'"
   120  		}
   121  
   122  		if rowCount == 0 {
   123  			createStr += "\n"
   124  		} else {
   125  			createStr += ",\n"
   126  		}
   127  		typ := types.Type{Oid: types.T(col.Typ.Id)}
   128  		typeStr := typ.String()
   129  		if types.IsDecimal(typ.Oid) { //after decimal fix,remove this
   130  			typeStr = fmt.Sprintf("DECIMAL(%d,%d)", col.Typ.Width, col.Typ.Scale)
   131  		}
   132  		if typ.Oid == types.T_varchar || typ.Oid == types.T_char {
   133  			typeStr += fmt.Sprintf("(%d)", col.Typ.Width)
   134  		}
   135  		if types.IsFloat(typ.Oid) && col.Typ.Precision != -1 {
   136  			typeStr += fmt.Sprintf("(%d,%d)", col.Typ.Width, col.Typ.Precision)
   137  		}
   138  
   139  		updateOpt := ""
   140  		if col.OnUpdate != nil && col.OnUpdate.Expr != nil {
   141  			updateOpt = " ON UPDATE " + col.OnUpdate.OriginString
   142  		}
   143  		createStr += fmt.Sprintf("`%s` %s %s%s%s", colName, typeStr, nullOrNot, updateOpt, hasAttrComment)
   144  		rowCount++
   145  		if col.Primary {
   146  			pkDefs = append(pkDefs, colName)
   147  		}
   148  	}
   149  	if tableDef.CompositePkey != nil {
   150  		pkDefs = append(pkDefs, util.SplitCompositePrimaryKeyColumnName(tableDef.CompositePkey.Name)...)
   151  	}
   152  	if len(pkDefs) != 0 {
   153  		pkStr := "PRIMARY KEY ("
   154  		for i, def := range pkDefs {
   155  			if i == len(pkDefs)-1 {
   156  				pkStr += fmt.Sprintf("`%s`", def)
   157  			} else {
   158  				pkStr += fmt.Sprintf("`%s`,", def)
   159  			}
   160  		}
   161  		pkStr += ")"
   162  		if rowCount != 0 {
   163  			createStr += ",\n"
   164  		}
   165  		createStr += pkStr
   166  	}
   167  
   168  	if tableDef.Indexes != nil {
   169  		for _, indexdef := range tableDef.Indexes {
   170  			var indexStr string
   171  			if indexdef.Unique {
   172  				indexStr = "UNIQUE KEY "
   173  			} else {
   174  				indexStr = "KEY "
   175  			}
   176  			indexStr += fmt.Sprintf("`%s` (", indexdef.IndexName)
   177  			for num, part := range indexdef.Parts {
   178  				if num == len(indexdef.Parts)-1 {
   179  					indexStr += fmt.Sprintf("`%s`", part)
   180  				} else {
   181  					indexStr += fmt.Sprintf("`%s`,", part)
   182  				}
   183  			}
   184  			indexStr += ")"
   185  			if indexdef.Comment != "" {
   186  				indexStr += fmt.Sprintf(" COMMENT `%s`", indexdef.Comment)
   187  			}
   188  			if rowCount != 0 {
   189  				createStr += ",\n"
   190  			}
   191  			createStr += indexStr
   192  		}
   193  	}
   194  
   195  	for _, fk := range tableDef.Fkeys {
   196  		colNames := make([]string, len(fk.Cols))
   197  		for i, colId := range fk.Cols {
   198  			colNames[i] = colIdToName[colId]
   199  		}
   200  		_, fkTableDef := ctx.ResolveById(fk.ForeignTbl)
   201  		fkColIdToName := make(map[uint64]string)
   202  		for _, col := range fkTableDef.Cols {
   203  			fkColIdToName[col.ColId] = col.Name
   204  		}
   205  		fkColNames := make([]string, len(fk.ForeignCols))
   206  		for i, colId := range fk.ForeignCols {
   207  			fkColNames[i] = fkColIdToName[colId]
   208  		}
   209  
   210  		if rowCount != 0 {
   211  			createStr += ",\n"
   212  		}
   213  		createStr += fmt.Sprintf("CONSTRAINT `%s` FOREIGN KEY (`%s`) REFERENCES `%s` (`%s`) ON DELETE %s ON UPDATE %s",
   214  			fk.Name, strings.Join(colNames, "`,`"), fkTableDef.Name, strings.Join(fkColNames, "`,`"), fk.OnDelete.String(), fk.OnUpdate.String())
   215  	}
   216  
   217  	if rowCount != 0 {
   218  		createStr += "\n"
   219  	}
   220  	createStr += ")"
   221  
   222  	if tableDef.ClusterBy != nil {
   223  		clusterby := " CLUSTER BY ("
   224  		if util.JudgeIsCompositeClusterByColumn(tableDef.ClusterBy.Name) {
   225  			//multi column clusterby
   226  			cbNames := util.SplitCompositeClusterByColumnName(tableDef.ClusterBy.Name)
   227  			for i, cbName := range cbNames {
   228  				if i != 0 {
   229  					clusterby += fmt.Sprintf(", `%s`", cbName)
   230  				} else {
   231  					clusterby += fmt.Sprintf("`%s`", cbName)
   232  				}
   233  			}
   234  		} else {
   235  			//single column cluster by
   236  			clusterby += fmt.Sprintf("`%s`", tableDef.ClusterBy.Name)
   237  		}
   238  		clusterby += ")"
   239  		createStr += clusterby
   240  	}
   241  
   242  	var comment string
   243  	var partition string
   244  	for _, def := range tableDef.Defs {
   245  		if proDef, ok := def.Def.(*plan.TableDef_DefType_Properties); ok {
   246  			for _, kv := range proDef.Properties.Properties {
   247  				if kv.Key == catalog.SystemRelAttr_Comment {
   248  					comment = " COMMENT='" + kv.Value + "'"
   249  				}
   250  			}
   251  		}
   252  	}
   253  
   254  	if tableDef.Partition != nil {
   255  		partition = ` ` + tableDef.Partition.PartitionMsg
   256  	}
   257  
   258  	createStr += comment
   259  	createStr += partition
   260  
   261  	if tableDef.TableType == catalog.SystemExternalRel {
   262  		param := tree.ExternParam{}
   263  		err := json.Unmarshal([]byte(tableDef.Createsql), &param)
   264  		if err != nil {
   265  			return nil, err
   266  		}
   267  		createStr += fmt.Sprintf(" INFILE{'FILEPATH'='%s','COMPRESSION'='%s','FORMAT'='%s','JSONDATA'='%s'}", param.Filepath, param.CompressType, param.Format, param.JsonData)
   268  
   269  		escapedby := ""
   270  		if param.Tail.Fields.EscapedBy != byte(0) {
   271  			escapedby = fmt.Sprintf(" ESCAPED BY '%c'", param.Tail.Fields.EscapedBy)
   272  		}
   273  
   274  		line := ""
   275  		if param.Tail.Lines.StartingBy != "" {
   276  			line = fmt.Sprintf(" LINE STARTING BY '%s'", param.Tail.Lines.StartingBy)
   277  		}
   278  		lineEnd := ""
   279  		if param.Tail.Lines.TerminatedBy == "\n" || param.Tail.Lines.TerminatedBy == "\r\n" {
   280  			lineEnd = " TERMINATED BY '\\\\n'"
   281  		} else {
   282  			lineEnd = fmt.Sprintf(" TERMINATED BY '%s'", param.Tail.Lines.TerminatedBy)
   283  		}
   284  		if len(line) > 0 {
   285  			line += lineEnd
   286  		} else {
   287  			line = " LINES" + lineEnd
   288  		}
   289  
   290  		createStr += fmt.Sprintf(" FIELDS TERMINATED BY '%s' ENCLOSED BY '%c'%s", param.Tail.Fields.Terminated, rune(param.Tail.Fields.EnclosedBy), escapedby)
   291  		createStr += line
   292  		if param.Tail.IgnoredLines > 0 {
   293  			createStr += fmt.Sprintf(" IGNORE %d LINES", param.Tail.IgnoredLines)
   294  		}
   295  	}
   296  
   297  	sql := "select \"%s\" as `Table`, \"%s\" as `Create Table`"
   298  	var buf bytes.Buffer
   299  	for _, ch := range createStr {
   300  		if ch == '"' {
   301  			buf.WriteRune('"')
   302  		}
   303  		buf.WriteRune(ch)
   304  	}
   305  	sql = fmt.Sprintf(sql, tblName, buf.String())
   306  
   307  	return returnByRewriteSQL(ctx, sql, plan.DataDefinition_SHOW_CREATETABLE)
   308  }
   309  
   310  // buildShowCreateView
   311  func buildShowCreateView(stmt *tree.ShowCreateView, ctx CompilerContext) (*Plan, error) {
   312  	tblName := stmt.Name.Parts[0]
   313  	dbName := ctx.DefaultDatabase()
   314  	if stmt.Name.NumParts == 2 {
   315  		dbName = stmt.Name.Parts[1]
   316  	}
   317  
   318  	_, tableDef := ctx.Resolve(dbName, tblName)
   319  	if tableDef == nil || tableDef.TableType != catalog.SystemViewRel {
   320  		return nil, moerr.NewInvalidInput(ctx.GetContext(), "show view '%s' is not a valid view", tblName)
   321  	}
   322  	sqlStr := "select \"%s\" as `View`, \"%s\" as `Create View`"
   323  	var viewStr string
   324  	if tableDef.TableType == catalog.SystemViewRel {
   325  		viewStr = tableDef.ViewSql.View
   326  	}
   327  
   328  	var viewData ViewData
   329  	err := json.Unmarshal([]byte(viewStr), &viewData)
   330  	if err != nil {
   331  		return nil, err
   332  	}
   333  
   334  	// FixMe  We need a better escape function
   335  	stmtStr := strings.ReplaceAll(viewData.Stmt, "\"", "\\\"")
   336  	sqlStr = fmt.Sprintf(sqlStr, tblName, fmt.Sprint(stmtStr))
   337  
   338  	// logutil.Info(sqlStr)
   339  
   340  	return returnByRewriteSQL(ctx, sqlStr, plan.DataDefinition_SHOW_CREATETABLE)
   341  }
   342  
   343  func buildShowDatabases(stmt *tree.ShowDatabases, ctx CompilerContext) (*Plan, error) {
   344  	if stmt.Like != nil && stmt.Where != nil {
   345  		return nil, moerr.NewSyntaxError(ctx.GetContext(), "like clause and where clause cannot exist at the same time")
   346  	}
   347  
   348  	accountId := ctx.GetAccountId()
   349  	ddlType := plan.DataDefinition_SHOW_DATABASES
   350  
   351  	var sql string
   352  	// Any account should shows database MO_CATALOG_DB_NAME
   353  	if accountId == catalog.System_Account {
   354  		accountClause := fmt.Sprintf("account_id = %v or (account_id = 0 and datname = '%s')", accountId, MO_CATALOG_DB_NAME)
   355  		sql = fmt.Sprintf("SELECT datname `Database` FROM %s.mo_database where (%s)", MO_CATALOG_DB_NAME, accountClause)
   356  	} else {
   357  		sql = fmt.Sprintf("SELECT datname `Database` FROM %s.mo_database", MO_CATALOG_DB_NAME)
   358  	}
   359  
   360  	if stmt.Where != nil {
   361  		return returnByWhereAndBaseSQL(ctx, sql, stmt.Where, ddlType)
   362  	}
   363  
   364  	if stmt.Like != nil {
   365  		// append filter [AND datname like stmt.Like] to WHERE clause
   366  		likeExpr := stmt.Like
   367  		likeExpr.Left = tree.SetUnresolvedName("datname")
   368  		return returnByLikeAndSQL(ctx, sql, likeExpr, ddlType)
   369  	}
   370  
   371  	return returnByRewriteSQL(ctx, sql, ddlType)
   372  }
   373  
   374  func buildShowTables(stmt *tree.ShowTables, ctx CompilerContext) (*Plan, error) {
   375  	if stmt.Like != nil && stmt.Where != nil {
   376  		return nil, moerr.NewSyntaxError(ctx.GetContext(), "like clause and where clause cannot exist at the same time")
   377  	}
   378  
   379  	if stmt.Open {
   380  		return nil, moerr.NewNYI(ctx.GetContext(), "statement: '%v'", tree.String(stmt, dialect.MYSQL))
   381  	}
   382  
   383  	accountId := ctx.GetAccountId()
   384  	dbName := stmt.DBName
   385  	if stmt.DBName == "" {
   386  		dbName = ctx.DefaultDatabase()
   387  	} else if !ctx.DatabaseExists(dbName) {
   388  		return nil, moerr.NewBadDB(ctx.GetContext(), dbName)
   389  	}
   390  
   391  	if dbName == "" {
   392  		return nil, moerr.NewNoDB(ctx.GetContext())
   393  	}
   394  	ddlType := plan.DataDefinition_SHOW_TABLES
   395  	var tableType string
   396  	if stmt.Full {
   397  		tableType = fmt.Sprintf(", case relkind when 'v' then 'VIEW' when '%s' then 'CLUSTER TABLE' else 'BASE TABLE' end as Table_type", catalog.SystemClusterRel)
   398  	}
   399  
   400  	var sql string
   401  	if accountId == catalog.System_Account {
   402  		mustShowTable := "relname = 'mo_database' or relname = 'mo_tables' or relname = 'mo_columns'"
   403  		clusterTable := fmt.Sprintf(" or relkind = '%s'", catalog.SystemClusterRel)
   404  		accountClause := fmt.Sprintf("account_id = %v or (account_id = 0 and (%s))", accountId, mustShowTable+clusterTable)
   405  		sql = fmt.Sprintf("SELECT relname as `Tables_in_%s` %s FROM %s.mo_tables WHERE reldatabase = '%s' and relname != '%s' and relname not like '%s' and (%s)",
   406  			dbName, tableType, MO_CATALOG_DB_NAME, dbName, "%!%mo_increment_columns", "__mo_index_unique__%", accountClause)
   407  	} else {
   408  		sql = fmt.Sprintf("SELECT relname as `Tables_in_%s` %s FROM %s.mo_tables WHERE reldatabase = '%s' and relname != '%s' and relname not like '%s'",
   409  			dbName, tableType, MO_CATALOG_DB_NAME, dbName, "%!%mo_increment_columns", "__mo_index_unique__%")
   410  	}
   411  
   412  	if stmt.Where != nil {
   413  		return returnByWhereAndBaseSQL(ctx, sql, stmt.Where, ddlType)
   414  	}
   415  
   416  	if stmt.Like != nil {
   417  		// append filter [AND relname like stmt.Like] to WHERE clause
   418  		likeExpr := stmt.Like
   419  		likeExpr.Left = tree.SetUnresolvedName("relname")
   420  		return returnByLikeAndSQL(ctx, sql, likeExpr, ddlType)
   421  	}
   422  
   423  	return returnByRewriteSQL(ctx, sql, ddlType)
   424  }
   425  
   426  func buildShowTableNumber(stmt *tree.ShowTableNumber, ctx CompilerContext) (*Plan, error) {
   427  	accountId := ctx.GetAccountId()
   428  	dbName := stmt.DbName
   429  	if stmt.DbName == "" {
   430  		dbName = ctx.DefaultDatabase()
   431  	} else if !ctx.DatabaseExists(dbName) {
   432  		return nil, moerr.NewBadDB(ctx.GetContext(), dbName)
   433  	}
   434  
   435  	if dbName == "" {
   436  		return nil, moerr.NewNoDB(ctx.GetContext())
   437  	}
   438  
   439  	ddlType := plan.DataDefinition_SHOW_TABLES
   440  	var sql string
   441  
   442  	if accountId == catalog.System_Account {
   443  		mustShowTable := "relname = 'mo_database' or relname = 'mo_tables' or relname = 'mo_columns'"
   444  		clusterTable := fmt.Sprintf(" or relkind = '%s'", catalog.SystemClusterRel)
   445  		accountClause := fmt.Sprintf("account_id = %v or (account_id = 0 and (%s))", accountId, mustShowTable+clusterTable)
   446  		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)",
   447  			dbName, MO_CATALOG_DB_NAME, dbName, "%!%mo_increment_columns", "__mo_index_unique__%", accountClause)
   448  	} else {
   449  		sql = "SELECT count(relname) `Number of tables in %s` FROM %s.mo_tables WHERE reldatabase = '%s' and relname != '%s' and relname not like '%s'"
   450  		sql = fmt.Sprintf(sql, dbName, MO_CATALOG_DB_NAME, dbName, "%!%mo_increment_columns", "__mo_index_unique__%")
   451  	}
   452  
   453  	return returnByRewriteSQL(ctx, sql, ddlType)
   454  }
   455  
   456  func buildShowColumnNumber(stmt *tree.ShowColumnNumber, ctx CompilerContext) (*Plan, error) {
   457  	accountId := ctx.GetAccountId()
   458  	dbName := stmt.Table.GetDBName()
   459  	if dbName == "" {
   460  		dbName = ctx.DefaultDatabase()
   461  	} else if !ctx.DatabaseExists(dbName) {
   462  		return nil, moerr.NewBadDB(ctx.GetContext(), dbName)
   463  	}
   464  
   465  	tblName := string(stmt.Table.ToTableName().ObjectName)
   466  	_, tableDef := ctx.Resolve(dbName, tblName)
   467  	if tableDef == nil {
   468  		return nil, moerr.NewNoSuchTable(ctx.GetContext(), dbName, tblName)
   469  	}
   470  
   471  	ddlType := plan.DataDefinition_SHOW_COLUMNS
   472  	var sql string
   473  
   474  	if accountId == catalog.System_Account {
   475  		mustShowTable := "att_relname = 'mo_database' or att_relname = 'mo_tables' or att_relname = 'mo_columns'"
   476  		clusterTable := ""
   477  		if util.TableIsClusterTable(tableDef.GetTableType()) {
   478  			clusterTable = fmt.Sprintf(" or att_relname = '%s'", tblName)
   479  		}
   480  		accountClause := fmt.Sprintf("account_id = %v or (account_id = 0 and (%s))", accountId, mustShowTable+clusterTable)
   481  		sql = "SELECT count(attname) `Number of columns in %s` FROM %s.mo_columns WHERE att_database = '%s' AND att_relname = '%s' AND (%s)"
   482  		sql = fmt.Sprintf(sql, tblName, MO_CATALOG_DB_NAME, dbName, tblName, accountClause)
   483  	} else {
   484  		sql = "SELECT count(attname) `Number of columns in %s` FROM %s.mo_columns WHERE att_database = '%s' AND att_relname = '%s'"
   485  		sql = fmt.Sprintf(sql, tblName, MO_CATALOG_DB_NAME, dbName, tblName)
   486  	}
   487  
   488  	return returnByRewriteSQL(ctx, sql, ddlType)
   489  }
   490  
   491  func buildShowTableValues(stmt *tree.ShowTableValues, ctx CompilerContext) (*Plan, error) {
   492  	dbName := stmt.Table.GetDBName()
   493  	if dbName == "" {
   494  		dbName = ctx.DefaultDatabase()
   495  	} else if !ctx.DatabaseExists(dbName) {
   496  		return nil, moerr.NewBadDB(ctx.GetContext(), dbName)
   497  	}
   498  
   499  	tblName := string(stmt.Table.ToTableName().ObjectName)
   500  	_, tableDef := ctx.Resolve(dbName, tblName)
   501  	if tableDef == nil {
   502  		return nil, moerr.NewNoSuchTable(ctx.GetContext(), dbName, tblName)
   503  	}
   504  
   505  	ddlType := plan.DataDefinition_SHOW_TARGET
   506  
   507  	sql := "SELECT"
   508  	tableCols := tableDef.Cols
   509  	isAllNull := true
   510  	for i := range tableCols {
   511  		colName := tableCols[i].Name
   512  		if types.T(tableCols[i].GetTyp().Id) == types.T_json {
   513  			sql += " null as `max(%s)`, null as `min(%s)`,"
   514  			sql = fmt.Sprintf(sql, colName, colName)
   515  		} else {
   516  			sql += " max(%s), min(%s),"
   517  			sql = fmt.Sprintf(sql, colName, colName)
   518  			isAllNull = false
   519  		}
   520  	}
   521  	sql = sql[:len(sql)-1]
   522  	sql += " FROM %s"
   523  
   524  	if isAllNull {
   525  		sql += " LIMIT 1"
   526  	}
   527  	sql = fmt.Sprintf(sql, tblName)
   528  
   529  	return returnByRewriteSQL(ctx, sql, ddlType)
   530  }
   531  
   532  func buildShowColumns(stmt *tree.ShowColumns, ctx CompilerContext) (*Plan, error) {
   533  	if stmt.Like != nil && stmt.Where != nil {
   534  		return nil, moerr.NewSyntaxError(ctx.GetContext(), "like clause and where clause cannot exist at the same time")
   535  	}
   536  
   537  	accountId := ctx.GetAccountId()
   538  	dbName := stmt.Table.GetDBName()
   539  	if dbName == "" {
   540  		dbName = ctx.DefaultDatabase()
   541  	} else if !ctx.DatabaseExists(dbName) {
   542  		return nil, moerr.NewBadDB(ctx.GetContext(), dbName)
   543  	}
   544  
   545  	tblName := string(stmt.Table.ToTableName().ObjectName)
   546  	_, tableDef := ctx.Resolve(dbName, tblName)
   547  	if tableDef == nil {
   548  		return nil, moerr.NewNoSuchTable(ctx.GetContext(), dbName, tblName)
   549  	}
   550  
   551  	var keyStr string
   552  	if dbName == catalog.MO_CATALOG && tblName == catalog.MO_DATABASE {
   553  		keyStr = "case when attname = '" + catalog.SystemDBAttr_ID + "' then 'PRI' else '' END as `Key`"
   554  	} else if dbName == catalog.MO_CATALOG && tblName == catalog.MO_TABLES {
   555  		keyStr = "case when attname = '" + catalog.SystemRelAttr_ID + "' then 'PRI' else '' END as `Key`"
   556  	} else if dbName == catalog.MO_CATALOG && tblName == catalog.MO_COLUMNS {
   557  		keyStr = "case when attname = '" + catalog.SystemColAttr_UniqName + "' then 'PRI' else '' END as `Key`"
   558  	} else {
   559  		if tableDef.Pkey != nil {
   560  			keyStr += "case"
   561  			for _, name := range tableDef.Pkey.Names {
   562  				keyStr += " when attname = "
   563  				keyStr += "'" + name + "'"
   564  				keyStr += " then 'PRI'"
   565  			}
   566  			keyStr += " else '' END as `Key`"
   567  		} else {
   568  			keyStr = "'' as `Key`"
   569  		}
   570  	}
   571  
   572  	ddlType := plan.DataDefinition_SHOW_COLUMNS
   573  
   574  	var sql string
   575  	if accountId == catalog.System_Account {
   576  		mustShowTable := "att_relname = 'mo_database' or att_relname = 'mo_tables' or att_relname = 'mo_columns'"
   577  		clusterTable := ""
   578  		if util.TableIsClusterTable(tableDef.GetTableType()) {
   579  			clusterTable = fmt.Sprintf(" or att_relname = '%s'", tblName)
   580  		}
   581  		accountClause := fmt.Sprintf("account_id = %v or (account_id = 0 and (%s))", accountId, mustShowTable+clusterTable)
   582  		sql = "SELECT attname `Field`, atttyp `Type`, iff(attnotnull = 0, 'YES', 'NO') `Null`, %s, att_default `Default`, null `Extra`,  att_comment `Comment` FROM %s.mo_columns WHERE att_database = '%s' AND att_relname = '%s' AND (%s)"
   583  		if stmt.Full {
   584  			sql = "SELECT attname `Field`, atttyp `Type`, null `Collation`, iff(attnotnull = 0, 'YES', 'NO') `Null`, %s, att_default `Default`,  null `Extra`,'select,insert,update,references' `Privileges`, att_comment `Comment` FROM %s.mo_columns WHERE att_database = '%s' AND att_relname = '%s' AND (%s)"
   585  		}
   586  		sql = fmt.Sprintf(sql, keyStr, MO_CATALOG_DB_NAME, dbName, tblName, accountClause)
   587  	} else {
   588  		sql = "SELECT attname `Field`, atttyp `Type`, iff(attnotnull = 0, 'YES', 'NO') `Null`, %s, att_default `Default`, null `Extra`,  att_comment `Comment` FROM %s.mo_columns WHERE att_database = '%s' AND att_relname = '%s'"
   589  		if stmt.Full {
   590  			sql = "SELECT attname `Field`, atttyp `Type`, null `Collation`, iff(attnotnull = 0, 'YES', 'NO') `Null`, %s, att_default `Default`,  null `Extra`,'select,insert,update,references' `Privileges`, att_comment `Comment` FROM %s.mo_columns WHERE att_database = '%s' AND att_relname = '%s'"
   591  		}
   592  		sql = fmt.Sprintf(sql, keyStr, MO_CATALOG_DB_NAME, dbName, tblName)
   593  	}
   594  
   595  	if stmt.Where != nil {
   596  		return returnByWhereAndBaseSQL(ctx, sql, stmt.Where, ddlType)
   597  	}
   598  
   599  	if stmt.Like != nil {
   600  		// append filter [AND ma.attname like stmt.Like] to WHERE clause
   601  		likeExpr := stmt.Like
   602  		likeExpr.Left = tree.SetUnresolvedName("attname")
   603  		return returnByLikeAndSQL(ctx, sql, likeExpr, ddlType)
   604  	}
   605  
   606  	return returnByRewriteSQL(ctx, sql, ddlType)
   607  }
   608  
   609  func buildShowTableStatus(stmt *tree.ShowTableStatus, ctx CompilerContext) (*Plan, error) {
   610  	if stmt.Like != nil && stmt.Where != nil {
   611  		return nil, moerr.NewSyntaxError(ctx.GetContext(), "like clause and where clause cannot exist at the same time")
   612  	}
   613  
   614  	dbName := stmt.DbName
   615  	if stmt.DbName == "" {
   616  		dbName = ctx.DefaultDatabase()
   617  		stmt.DbName = dbName
   618  		if dbName == "" {
   619  			return nil, moerr.NewNoDB(ctx.GetContext())
   620  		}
   621  	} else if !ctx.DatabaseExists(dbName) {
   622  		return nil, moerr.NewBadDB(ctx.GetContext(), dbName)
   623  	}
   624  
   625  	ddlType := plan.DataDefinition_SHOW_TABLE_STATUS
   626  	accountId := ctx.GetAccountId()
   627  	mustShowTable := "relname = 'mo_database' or relname = 'mo_tables' or relname = 'mo_columns'"
   628  	accountClause := fmt.Sprintf("account_id = %v or (account_id = 0 and (%s))", accountId, mustShowTable)
   629  	sql := "select relname as `Name`, 'Tae' as `Engine`, 'Dynamic' as `Row_format`, 0 as `Rows`, 0 as `Avg_row_length`, 0 as `Data_length`, 0 as `Max_data_length`, 0 as `Index_length`, 'NULL' as `Data_free`, 0 as `Auto_increment`, created_time as `Create_time`, 'NULL' as `Update_time`, 'NULL' as `Check_time`, 'utf-8' as `Collation`, 'NULL' as `Checksum`, '' as `Create_options`, rel_comment as `Comment` from %s.mo_tables where reldatabase = '%s' and relname != '%s' and relname not like '%s' and (%s)"
   630  
   631  	sql = fmt.Sprintf(sql, MO_CATALOG_DB_NAME, dbName, "%!%mo_increment_columns", "__mo_index_unique__%", accountClause)
   632  
   633  	if stmt.Where != nil {
   634  		return returnByWhereAndBaseSQL(ctx, sql, stmt.Where, ddlType)
   635  	}
   636  
   637  	if stmt.Like != nil {
   638  		// append filter [AND ma.relname like stmt.Like] to WHERE clause
   639  		likeExpr := stmt.Like
   640  		likeExpr.Left = tree.SetUnresolvedName("relname")
   641  		return returnByLikeAndSQL(ctx, sql, likeExpr, ddlType)
   642  	}
   643  
   644  	return returnByRewriteSQL(ctx, sql, ddlType)
   645  }
   646  
   647  // TODO: Implement show target
   648  func buildShowTarget(stmt *tree.ShowTarget, ctx CompilerContext) (*Plan, error) {
   649  	ddlType := plan.DataDefinition_SHOW_TARGET
   650  	sql := ""
   651  	switch stmt.Type {
   652  	case tree.ShowCharset:
   653  		sql = "select '' as `Charset`, '' as `Description`, '' as `Default collation`, '' as `Maxlen` where 0"
   654  	case tree.ShowTriggers:
   655  		return buildShowTriggers(stmt, ctx)
   656  	default:
   657  		sql = "select 1 where 0"
   658  	}
   659  	return returnByRewriteSQL(ctx, sql, ddlType)
   660  }
   661  
   662  func buildShowLocks(stmt *tree.ShowLocks, ctx CompilerContext) (*Plan, error) {
   663  	ddlType := plan.DataDefinition_SHOW_TARGET
   664  	sql := "select 1 where 0"
   665  	return returnByRewriteSQL(ctx, sql, ddlType)
   666  }
   667  
   668  func buildShowNodeList(stmt *tree.ShowNodeList, ctx CompilerContext) (*Plan, error) {
   669  	ddlType := plan.DataDefinition_SHOW_TARGET
   670  	sql := "select 1 where 0"
   671  	return returnByRewriteSQL(ctx, sql, ddlType)
   672  }
   673  
   674  func buildShowFunctionStatus(stmt *tree.ShowFunctionStatus, ctx CompilerContext) (*Plan, error) {
   675  	if stmt.Like != nil && stmt.Where != nil {
   676  		return nil, moerr.NewSyntaxError(ctx.GetContext(), "like clause and where clause cannot exist at the same time")
   677  	}
   678  	ddlType := plan.DataDefinition_SHOW_TARGET
   679  	if stmt.Like != nil && stmt.Where != nil {
   680  		return nil, moerr.NewSyntaxError(ctx.GetContext(), "like clause and where clause cannot exist at the same time")
   681  	}
   682  
   683  	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)
   684  
   685  	if stmt.Where != nil {
   686  		return returnByWhereAndBaseSQL(ctx, sql, stmt.Where, ddlType)
   687  	}
   688  
   689  	if stmt.Like != nil {
   690  		// append filter [AND ma.attname like stmt.Like] to WHERE clause
   691  		likeExpr := stmt.Like
   692  		likeExpr.Left = tree.SetUnresolvedName("name")
   693  		return returnByLikeAndSQL(ctx, sql, likeExpr, ddlType)
   694  	}
   695  
   696  	return returnByRewriteSQL(ctx, sql, ddlType)
   697  }
   698  
   699  func buildShowTriggers(stmt *tree.ShowTarget, ctx CompilerContext) (*Plan, error) {
   700  	if stmt.Like != nil && stmt.Where != nil {
   701  		return nil, moerr.NewSyntaxError(ctx.GetContext(), "like clause and where clause cannot exist at the same time")
   702  	}
   703  
   704  	dbName := stmt.DbName
   705  	if stmt.DbName == "" {
   706  		dbName = ctx.DefaultDatabase()
   707  		stmt.DbName = dbName
   708  		if dbName == "" {
   709  			return nil, moerr.NewNoDB(ctx.GetContext())
   710  		}
   711  	} else if !ctx.DatabaseExists(dbName) {
   712  		return nil, moerr.NewBadDB(ctx.GetContext(), dbName)
   713  	}
   714  
   715  	ddlType := plan.DataDefinition_SHOW_TARGET
   716  	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)
   717  
   718  	if stmt.Where != nil {
   719  		return returnByWhereAndBaseSQL(ctx, sql, stmt.Where, ddlType)
   720  	}
   721  
   722  	if stmt.Like != nil {
   723  		// append filter [AND ma.attname like stmt.Like] to WHERE clause
   724  		likeExpr := stmt.Like
   725  		likeExpr.Left = tree.SetUnresolvedName("event_object_table")
   726  		return returnByLikeAndSQL(ctx, sql, likeExpr, ddlType)
   727  	}
   728  
   729  	return returnByRewriteSQL(ctx, sql, ddlType)
   730  }
   731  
   732  func buildShowIndex(stmt *tree.ShowIndex, ctx CompilerContext) (*Plan, error) {
   733  	dbName := string(stmt.TableName.Schema())
   734  	if dbName == "" {
   735  		dbName = ctx.DefaultDatabase()
   736  		if dbName == "" {
   737  			return nil, moerr.NewNoDB(ctx.GetContext())
   738  		}
   739  	} else if !ctx.DatabaseExists(dbName) {
   740  		return nil, moerr.NewBadDB(ctx.GetContext(), dbName)
   741  	}
   742  
   743  	tblName := string(stmt.TableName.Name())
   744  	_, tableDef := ctx.Resolve(dbName, tblName)
   745  	if tableDef == nil {
   746  		return nil, moerr.NewNoSuchTable(ctx.GetContext(), dbName, tblName)
   747  	}
   748  
   749  	accountId := ctx.GetAccountId()
   750  	ddlType := plan.DataDefinition_SHOW_INDEX
   751  	mustShowTable := "att_relname = 'mo_database' or att_relname = 'mo_tables' or att_relname = 'mo_columns'"
   752  	accountClause := fmt.Sprintf("account_id = %v or (account_id = 0 and (%s))", accountId, mustShowTable)
   753  	sql := "select att_relname as `Table`,  iff(att_constraint_type = 'p', 1, 0) as `Non_unique`,  iff(att_constraint_type = 'p', 'PRIMARY', attname) as `Key_name`,  1 as `Seq_in_index`, attname as `Column_name`, 'A' as `Collation`, 0 as `Cardinality`, 'NULL' as `Sub_part`, 'NULL' as `Packed`, iff(attnotnull = 0, 'YES', 'NO') as `Null`, '' as 'Index_type', att_comment as `Comment`,  iff(att_is_hidden = 0, 'YES', 'NO') as `Visible`, 'NULL' as `Expression` FROM %s.mo_columns WHERE att_database = '%s' AND att_relname = '%s' AND (%s)"
   754  
   755  	sql = fmt.Sprintf(sql, MO_CATALOG_DB_NAME, dbName, tblName, accountClause)
   756  
   757  	if stmt.Where != nil {
   758  		return returnByWhereAndBaseSQL(ctx, sql, stmt.Where, ddlType)
   759  	}
   760  
   761  	return returnByRewriteSQL(ctx, sql, ddlType)
   762  }
   763  
   764  // TODO: Improve SQL. Currently, Lack of the mata of grants
   765  func buildShowGrants(stmt *tree.ShowGrants, ctx CompilerContext) (*Plan, error) {
   766  
   767  	ddlType := plan.DataDefinition_SHOW_TARGET
   768  	if stmt.ShowGrantType == tree.GrantForRole {
   769  		role_name := stmt.Roles[0].UserName
   770  		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';"
   771  		sql = fmt.Sprintf(sql, role_name, role_name, MO_CATALOG_DB_NAME, role_name)
   772  		return returnByRewriteSQL(ctx, sql, ddlType)
   773  	} else {
   774  		if stmt.Hostname == "" {
   775  			stmt.Hostname = MO_DEFUALT_HOSTNAME
   776  		}
   777  		if stmt.Username == "" {
   778  			stmt.Username = ctx.GetUserName()
   779  		}
   780  		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';"
   781  		sql = fmt.Sprintf(sql, stmt.Username, stmt.Hostname, stmt.Username, stmt.Username, stmt.Hostname)
   782  		return returnByRewriteSQL(ctx, sql, ddlType)
   783  	}
   784  }
   785  
   786  func buildShowVariables(stmt *tree.ShowVariables, ctx CompilerContext) (*Plan, error) {
   787  	showVariables := &plan.ShowVariables{
   788  		Global: stmt.Global,
   789  	}
   790  
   791  	// we deal with 'show vriables' statement in frontend now.
   792  	// so just return an empty plan in building plan for prepare statment is ok.
   793  
   794  	// if stmt.Like != nil && stmt.Where != nil {
   795  	// 	return nil, moerr.NewSyntaxError(ctx.GetContext(), "like clause and where clause cannot exist at the same time")
   796  	// }
   797  
   798  	// builder := NewQueryBuilder(plan.Query_SELECT, ctx)
   799  	// binder := NewWhereBinder(builder, &BindContext{})
   800  
   801  	// if stmt.Like != nil {
   802  	//  // here will error because stmt.Like.Left is nil, you need add left expr like : stmt.Like.Left = tree.SetUnresolvedName("column_name")
   803  	//  // but we have no column name, because Variables is save in a hashmap in frontend, not a table.
   804  	// 	expr, err := binder.bindComparisonExpr(stmt.Like, 0, false)
   805  	// 	if err != nil {
   806  	// 		return nil, err
   807  	// 	}
   808  	// 	showVariables.Where = append(showVariables.Where, expr)
   809  	// }
   810  	// if stmt.Where != nil {
   811  	// 	exprs, err := splitAndBindCondition(stmt.Where.Expr, &BindContext{})
   812  	// 	if err != nil {
   813  	// 		return nil, err
   814  	// 	}
   815  	// 	showVariables.Where = append(showVariables.Where, exprs...)
   816  	// }
   817  
   818  	return &Plan{
   819  		Plan: &plan.Plan_Ddl{
   820  			Ddl: &plan.DataDefinition{
   821  				DdlType: plan.DataDefinition_SHOW_VARIABLES,
   822  				Definition: &plan.DataDefinition_ShowVariables{
   823  					ShowVariables: showVariables,
   824  				},
   825  			},
   826  		},
   827  	}, nil
   828  }
   829  
   830  func buildShowStatus(stmt *tree.ShowStatus, ctx CompilerContext) (*Plan, error) {
   831  	ddlType := plan.DataDefinition_SHOW_STATUS
   832  	sql := "select '' as `Variable_name`, '' as `Value` where 0"
   833  	return returnByRewriteSQL(ctx, sql, ddlType)
   834  }
   835  
   836  func buildShowCollation(stmt *tree.ShowCollation, ctx CompilerContext) (*Plan, error) {
   837  	ddlType := plan.DataDefinition_SHOW_COLLATION
   838  	sql := "select 'utf8mb4_bin' as `Collation`, 'utf8mb4' as `Charset`, 46 as `Id`, 'Yes' as `Compiled`, 1 as `Sortlen`"
   839  	return returnByRewriteSQL(ctx, sql, ddlType)
   840  }
   841  
   842  func buildShowProcessList(stmt *tree.ShowProcessList, ctx CompilerContext) (*Plan, error) {
   843  	ddlType := plan.DataDefinition_SHOW_PROCESSLIST
   844  	sql := "select '' as `Id`, '' as `User`, '' as `Host`, '' as `db` , '' as `Command`, '' as `Time` , '' as `State`, '' as `Info` where 0"
   845  	return returnByRewriteSQL(ctx, sql, ddlType)
   846  }
   847  
   848  func returnByRewriteSQL(ctx CompilerContext, sql string,
   849  	ddlType plan.DataDefinition_DdlType) (*Plan, error) {
   850  	stmt, err := getRewriteSQLStmt(ctx, sql)
   851  	if err != nil {
   852  		return nil, err
   853  	}
   854  	return getReturnDdlBySelectStmt(ctx, stmt, ddlType)
   855  }
   856  
   857  func returnByWhereAndBaseSQL(ctx CompilerContext, baseSQL string,
   858  	where *tree.Where, ddlType plan.DataDefinition_DdlType) (*Plan, error) {
   859  	sql := fmt.Sprintf("SELECT * FROM (%s) tbl", baseSQL)
   860  	// logutil.Info(sql)
   861  	newStmt, err := getRewriteSQLStmt(ctx, sql)
   862  	if err != nil {
   863  		return nil, err
   864  	}
   865  	// set show statement's where clause to new statement
   866  	newStmt.(*tree.Select).Select.(*tree.SelectClause).Where = where
   867  	return getReturnDdlBySelectStmt(ctx, newStmt, ddlType)
   868  }
   869  
   870  func returnByLikeAndSQL(ctx CompilerContext, sql string, like *tree.ComparisonExpr,
   871  	ddlType plan.DataDefinition_DdlType) (*Plan, error) {
   872  	newStmt, err := getRewriteSQLStmt(ctx, sql)
   873  	if err != nil {
   874  		return nil, err
   875  	}
   876  	var whereExpr *tree.Where
   877  
   878  	if newStmt.(*tree.Select).Select.(*tree.SelectClause).Where == nil {
   879  		whereExpr = &tree.Where{
   880  			Type: "where",
   881  			Expr: like,
   882  		}
   883  	} else {
   884  		whereExpr = &tree.Where{
   885  			Type: "where",
   886  			Expr: &tree.AndExpr{
   887  				Left:  newStmt.(*tree.Select).Select.(*tree.SelectClause).Where.Expr,
   888  				Right: like,
   889  			},
   890  		}
   891  	}
   892  	// set show statement's like clause to new statement
   893  	newStmt.(*tree.Select).Select.(*tree.SelectClause).Where = whereExpr
   894  	// logutil.Info(tree.String(newStmt, dialect.MYSQL))
   895  	return getReturnDdlBySelectStmt(ctx, newStmt, ddlType)
   896  }
   897  
   898  func getRewriteSQLStmt(ctx CompilerContext, sql string) (tree.Statement, error) {
   899  	newStmts, err := parsers.Parse(ctx.GetContext(), dialect.MYSQL, sql)
   900  	if err != nil {
   901  		return nil, err
   902  	}
   903  	if len(newStmts) != 1 {
   904  		return nil, moerr.NewInvalidInput(ctx.GetContext(), "rewrite can only contain one statement, %d provided", len(newStmts))
   905  	}
   906  	return newStmts[0], nil
   907  }
   908  
   909  func getReturnDdlBySelectStmt(ctx CompilerContext, stmt tree.Statement,
   910  	ddlType plan.DataDefinition_DdlType) (*Plan, error) {
   911  	queryPlan, err := BuildPlan(ctx, stmt)
   912  	if err != nil {
   913  		return nil, err
   914  	}
   915  	return queryPlan, nil
   916  	// return &Plan{
   917  	// 	Plan: &plan.Plan_Ddl{
   918  	// 		Ddl: &plan.DataDefinition{
   919  	// 			DdlType: ddlType,
   920  	// 			Query:   queryPlan.GetQuery(),
   921  	// 		},
   922  	// 	},
   923  	// }, nil
   924  }