github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/compile/sql_executor_context.go (about)

     1  // Copyright 2023 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 compile
    16  
    17  import (
    18  	"context"
    19  	"strconv"
    20  	"sync"
    21  
    22  	"github.com/matrixorigin/matrixone/pkg/catalog"
    23  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    24  	"github.com/matrixorigin/matrixone/pkg/defines"
    25  	planpb "github.com/matrixorigin/matrixone/pkg/pb/plan"
    26  	pb "github.com/matrixorigin/matrixone/pkg/pb/statsinfo"
    27  	"github.com/matrixorigin/matrixone/pkg/sql/parsers/tree"
    28  	"github.com/matrixorigin/matrixone/pkg/sql/plan"
    29  	"github.com/matrixorigin/matrixone/pkg/sql/plan/function"
    30  	"github.com/matrixorigin/matrixone/pkg/sql/util"
    31  	"github.com/matrixorigin/matrixone/pkg/vm/engine"
    32  	"github.com/matrixorigin/matrixone/pkg/vm/process"
    33  )
    34  
    35  var _ plan.CompilerContext = new(compilerContext)
    36  
    37  type compilerContext struct {
    38  	ctx        context.Context
    39  	defaultDB  string
    40  	engine     engine.Engine
    41  	proc       *process.Process
    42  	statsCache *plan.StatsCache
    43  
    44  	buildAlterView       bool
    45  	dbOfView, nameOfView string
    46  	sql                  string
    47  	mu                   sync.Mutex
    48  }
    49  
    50  func (c *compilerContext) GetViews() []string {
    51  	return nil
    52  }
    53  
    54  func (c *compilerContext) SetViews(views []string) {}
    55  
    56  func (c *compilerContext) GetSnapshot() *plan.Snapshot {
    57  	return nil
    58  }
    59  
    60  func (c *compilerContext) SetSnapshot(snapshot *plan.Snapshot) {
    61  }
    62  
    63  func (c *compilerContext) ReplacePlan(execPlan *planpb.Execute) (*planpb.Plan, tree.Statement, error) {
    64  	//TODO implement me
    65  	panic("implement me")
    66  }
    67  
    68  func (c *compilerContext) CheckSubscriptionValid(subName, accName string, pubName string) error {
    69  	panic("not supported in internal sql executor")
    70  }
    71  
    72  func (c *compilerContext) ResolveSubscriptionTableById(tableId uint64, pubmeta *plan.SubscriptionMeta) (*plan.ObjectRef, *plan.TableDef) {
    73  	panic("not supported in internal sql executor")
    74  }
    75  
    76  func (c *compilerContext) IsPublishing(dbName string) (bool, error) {
    77  	panic("not supported in internal sql executor")
    78  }
    79  
    80  func (c *compilerContext) ResolveSnapshotWithSnapshotName(snapshotName string) (*plan.Snapshot, error) {
    81  	panic("not supported in internal sql executor")
    82  }
    83  
    84  func (c *compilerContext) CheckTimeStampValid(ts int64) (bool, error) {
    85  	panic("not supported in internal sql executor")
    86  }
    87  
    88  func (c *compilerContext) SetQueryingSubscription(meta *plan.SubscriptionMeta) {
    89  	panic("not supported in internal sql executor")
    90  }
    91  
    92  func (c *compilerContext) GetQueryingSubscription() *plan.SubscriptionMeta {
    93  	return nil
    94  }
    95  
    96  func newCompilerContext(
    97  	ctx context.Context,
    98  	defaultDB string,
    99  	eng engine.Engine,
   100  	proc *process.Process) *compilerContext {
   101  	return &compilerContext{
   102  		ctx:       ctx,
   103  		defaultDB: defaultDB,
   104  		engine:    eng,
   105  		proc:      proc,
   106  	}
   107  }
   108  
   109  func (c *compilerContext) ResolveUdf(name string, ast []*plan.Expr) (*function.Udf, error) {
   110  	panic("not supported in internal sql executor")
   111  }
   112  
   113  func (c *compilerContext) ResolveAccountIds(accountNames []string) ([]uint32, error) {
   114  	panic("not supported in internal sql executor")
   115  }
   116  
   117  func (c *compilerContext) Stats(obj *plan.ObjectRef, snapshot plan.Snapshot) (*pb.StatsInfo, error) {
   118  	ctx, t, err := c.getRelation(obj.GetSchemaName(), obj.GetObjName(), snapshot)
   119  	if err != nil {
   120  		return nil, err
   121  	}
   122  	return t.Stats(ctx, true)
   123  }
   124  
   125  func (c *compilerContext) GetStatsCache() *plan.StatsCache {
   126  	if c.statsCache == nil {
   127  		c.statsCache = plan.NewStatsCache()
   128  	}
   129  	return c.statsCache
   130  }
   131  
   132  func (c *compilerContext) GetSubscriptionMeta(dbName string, snapshot plan.Snapshot) (*plan.SubscriptionMeta, error) {
   133  	return nil, nil
   134  }
   135  
   136  func (c *compilerContext) GetProcess() *process.Process {
   137  	return c.proc
   138  }
   139  
   140  func (c *compilerContext) GetQueryResultMeta(uuid string) ([]*plan.ColDef, string, error) {
   141  	panic("not supported in internal sql executor")
   142  }
   143  
   144  func (c *compilerContext) DatabaseExists(name string, snapshot plan.Snapshot) bool {
   145  	ctx := c.GetContext()
   146  	txnOpt := c.proc.TxnOperator
   147  
   148  	if plan.IsSnapshotValid(&snapshot) && snapshot.TS.Less(c.proc.TxnOperator.Txn().SnapshotTS) {
   149  		txnOpt = c.proc.TxnOperator.CloneSnapshotOp(*snapshot.TS)
   150  
   151  		if snapshot.Tenant != nil {
   152  			ctx = context.WithValue(ctx, defines.TenantIDKey{}, snapshot.Tenant.TenantID)
   153  		}
   154  	}
   155  
   156  	_, err := c.engine.Database(
   157  		ctx,
   158  		name,
   159  		txnOpt,
   160  	)
   161  	return err == nil
   162  }
   163  
   164  func (c *compilerContext) GetDatabaseId(dbName string, snapshot plan.Snapshot) (uint64, error) {
   165  	ctx := c.GetContext()
   166  	txnOpt := c.proc.TxnOperator
   167  
   168  	if plan.IsSnapshotValid(&snapshot) && snapshot.TS.Less(c.proc.TxnOperator.Txn().SnapshotTS) {
   169  		txnOpt = c.proc.TxnOperator.CloneSnapshotOp(*snapshot.TS)
   170  
   171  		if snapshot.Tenant != nil {
   172  			ctx = context.WithValue(ctx, defines.TenantIDKey{}, snapshot.Tenant.TenantID)
   173  		}
   174  	}
   175  
   176  	database, err := c.engine.Database(ctx, dbName, txnOpt)
   177  
   178  	if err != nil {
   179  		return 0, err
   180  	}
   181  	databaseId, err := strconv.ParseUint(database.GetDatabaseId(ctx), 10, 64)
   182  	if err != nil {
   183  		return 0, moerr.NewInternalError(ctx, "The databaseid of '%s' is not a valid number", dbName)
   184  	}
   185  	return databaseId, nil
   186  }
   187  
   188  func (c *compilerContext) DefaultDatabase() string {
   189  	return c.defaultDB
   190  }
   191  
   192  func (c *compilerContext) GetPrimaryKeyDef(
   193  	dbName string,
   194  	tableName string,
   195  	snapshot plan.Snapshot) []*plan.ColDef {
   196  	dbName, err := c.ensureDatabaseIsNotEmpty(dbName)
   197  	if err != nil {
   198  		return nil
   199  	}
   200  	ctx, relation, err := c.getRelation(dbName, tableName, snapshot)
   201  	if err != nil {
   202  		return nil
   203  	}
   204  
   205  	priKeys, err := relation.GetPrimaryKeys(ctx)
   206  	if err != nil {
   207  		return nil
   208  	}
   209  	if len(priKeys) == 0 {
   210  		return nil
   211  	}
   212  
   213  	priDefs := make([]*plan.ColDef, 0, len(priKeys))
   214  	for _, key := range priKeys {
   215  		priDefs = append(priDefs, &plan.ColDef{
   216  			Name: key.Name,
   217  			Typ: plan.Type{
   218  				Id:    int32(key.Type.Oid),
   219  				Width: key.Type.Width,
   220  				Scale: key.Type.Scale,
   221  			},
   222  			Primary: key.Primary,
   223  		})
   224  	}
   225  	return priDefs
   226  }
   227  
   228  func (c *compilerContext) GetRootSql() string {
   229  	return c.sql
   230  }
   231  
   232  func (c *compilerContext) SetRootSql(sql string) {
   233  	c.mu.Lock()
   234  	defer c.mu.Unlock()
   235  	c.sql = sql
   236  }
   237  
   238  func (c *compilerContext) GetUserName() string {
   239  	return "root"
   240  }
   241  
   242  func (c *compilerContext) GetAccountId() (uint32, error) {
   243  	return defines.GetAccountId(c.ctx)
   244  }
   245  
   246  func (c *compilerContext) GetContext() context.Context {
   247  	return c.ctx
   248  }
   249  
   250  func (c *compilerContext) ResolveById(tableId uint64, snapshot plan.Snapshot) (objRef *plan.ObjectRef, tableDef *plan.TableDef) {
   251  	ctx := c.GetContext()
   252  	txnOpt := c.proc.TxnOperator
   253  
   254  	if plan.IsSnapshotValid(&snapshot) && snapshot.TS.Less(c.proc.TxnOperator.Txn().SnapshotTS) {
   255  		txnOpt = c.proc.TxnOperator.CloneSnapshotOp(*snapshot.TS)
   256  
   257  		if snapshot.Tenant != nil {
   258  			ctx = context.WithValue(ctx, defines.TenantIDKey{}, snapshot.Tenant.TenantID)
   259  		}
   260  	}
   261  
   262  	dbName, tableName, _ := c.engine.GetNameById(ctx, txnOpt, tableId)
   263  	if dbName == "" || tableName == "" {
   264  		return nil, nil
   265  	}
   266  	return c.Resolve(dbName, tableName, snapshot)
   267  }
   268  
   269  func (c *compilerContext) Resolve(dbName string, tableName string, snapshot plan.Snapshot) (*plan.ObjectRef, *plan.TableDef) {
   270  	dbName, err := c.ensureDatabaseIsNotEmpty(dbName)
   271  	if err != nil {
   272  		return nil, nil
   273  	}
   274  
   275  	ctx, table, err := c.getRelation(dbName, tableName, snapshot)
   276  	if err != nil {
   277  		return nil, nil
   278  	}
   279  	return c.getTableDef(ctx, table, dbName, tableName)
   280  }
   281  
   282  func (c *compilerContext) ResolveVariable(varName string, isSystemVar bool, isGlobalVar bool) (interface{}, error) {
   283  	return nil, nil
   284  }
   285  
   286  func (c *compilerContext) SetBuildingAlterView(yesOrNo bool, dbName, viewName string) {
   287  	c.mu.Lock()
   288  	defer c.mu.Unlock()
   289  	c.buildAlterView = yesOrNo
   290  	c.dbOfView = dbName
   291  	c.nameOfView = viewName
   292  }
   293  
   294  func (c *compilerContext) GetBuildingAlterView() (bool, string, string) {
   295  	c.mu.Lock()
   296  	defer c.mu.Unlock()
   297  	return c.buildAlterView, c.dbOfView, c.nameOfView
   298  }
   299  
   300  func (c *compilerContext) ensureDatabaseIsNotEmpty(dbName string) (string, error) {
   301  	if len(dbName) == 0 {
   302  		dbName = c.DefaultDatabase()
   303  	}
   304  	if len(dbName) == 0 {
   305  		return "", moerr.NewNoDB(c.GetContext())
   306  	}
   307  	return dbName, nil
   308  }
   309  
   310  func (c *compilerContext) getRelation(
   311  	dbName string,
   312  	tableName string,
   313  	snapshot plan.Snapshot) (context.Context, engine.Relation, error) {
   314  	dbName, err := c.ensureDatabaseIsNotEmpty(dbName)
   315  	if err != nil {
   316  		return nil, nil, err
   317  	}
   318  
   319  	ctx := c.GetContext()
   320  	txnOpt := c.proc.TxnOperator
   321  
   322  	if plan.IsSnapshotValid(&snapshot) && snapshot.TS.Less(c.proc.TxnOperator.Txn().SnapshotTS) {
   323  		txnOpt = c.proc.TxnOperator.CloneSnapshotOp(*snapshot.TS)
   324  
   325  		if snapshot.Tenant != nil {
   326  			ctx = context.WithValue(ctx, defines.TenantIDKey{}, snapshot.Tenant.TenantID)
   327  		}
   328  	}
   329  
   330  	db, err := c.engine.Database(ctx, dbName, txnOpt)
   331  	if err != nil {
   332  		return nil, nil, err
   333  	}
   334  
   335  	table, err := db.Relation(ctx, tableName, nil)
   336  	if err != nil {
   337  		return nil, nil, err
   338  	}
   339  	return ctx, table, nil
   340  }
   341  
   342  func (c *compilerContext) getTableDef(
   343  	ctx context.Context,
   344  	table engine.Relation,
   345  	dbName, tableName string) (*plan.ObjectRef, *plan.TableDef) {
   346  	tableId := table.GetTableID(ctx)
   347  	engineDefs, err := table.TableDefs(ctx)
   348  	if err != nil {
   349  		return nil, nil
   350  	}
   351  
   352  	var clusterByDef *plan.ClusterByDef
   353  	var cols []*plan.ColDef
   354  	var schemaVersion uint32
   355  	var defs []*plan.TableDefType
   356  	var properties []*plan.Property
   357  	var TableType, Createsql string
   358  	var partitionInfo *plan.PartitionByDef
   359  	var viewSql *plan.ViewDef
   360  	var foreignKeys []*plan.ForeignKeyDef
   361  	var primarykey *plan.PrimaryKeyDef
   362  	var indexes []*plan.IndexDef
   363  	var refChildTbls []uint64
   364  	var subscriptionName string
   365  
   366  	for _, def := range engineDefs {
   367  		if attr, ok := def.(*engine.AttributeDef); ok {
   368  			col := &plan.ColDef{
   369  				ColId: attr.Attr.ID,
   370  				Name:  attr.Attr.Name,
   371  				Typ: plan.Type{
   372  					Id:          int32(attr.Attr.Type.Oid),
   373  					Width:       attr.Attr.Type.Width,
   374  					Scale:       attr.Attr.Type.Scale,
   375  					AutoIncr:    attr.Attr.AutoIncrement,
   376  					Table:       tableName,
   377  					NotNullable: attr.Attr.Default != nil && !attr.Attr.Default.NullAbility,
   378  					Enumvalues:  attr.Attr.EnumVlaues,
   379  				},
   380  				Primary:   attr.Attr.Primary,
   381  				Default:   attr.Attr.Default,
   382  				OnUpdate:  attr.Attr.OnUpdate,
   383  				Comment:   attr.Attr.Comment,
   384  				ClusterBy: attr.Attr.ClusterBy,
   385  				Hidden:    attr.Attr.IsHidden,
   386  				Seqnum:    uint32(attr.Attr.Seqnum),
   387  			}
   388  			// Is it a composite primary key
   389  			//if attr.Attr.Name == catalog.CPrimaryKeyColName {
   390  			//	continue
   391  			//}
   392  			if attr.Attr.ClusterBy {
   393  				clusterByDef = &plan.ClusterByDef{
   394  					Name: attr.Attr.Name,
   395  				}
   396  				//if util.JudgeIsCompositeClusterByColumn(attr.Attr.Name) {
   397  				//	continue
   398  				//}
   399  			}
   400  			cols = append(cols, col)
   401  		} else if pro, ok := def.(*engine.PropertiesDef); ok {
   402  			for _, p := range pro.Properties {
   403  				switch p.Key {
   404  				case catalog.SystemRelAttr_Kind:
   405  					TableType = p.Value
   406  				case catalog.SystemRelAttr_CreateSQL:
   407  					Createsql = p.Value
   408  				default:
   409  				}
   410  				properties = append(properties, &plan.Property{
   411  					Key:   p.Key,
   412  					Value: p.Value,
   413  				})
   414  			}
   415  		} else if viewDef, ok := def.(*engine.ViewDef); ok {
   416  			viewSql = &plan.ViewDef{
   417  				View: viewDef.View,
   418  			}
   419  		} else if c, ok := def.(*engine.ConstraintDef); ok {
   420  			for _, ct := range c.Cts {
   421  				switch k := ct.(type) {
   422  				case *engine.IndexDef:
   423  					indexes = k.Indexes
   424  				case *engine.ForeignKeyDef:
   425  					foreignKeys = k.Fkeys
   426  				case *engine.RefChildTableDef:
   427  					refChildTbls = k.Tables
   428  				case *engine.PrimaryKeyDef:
   429  					primarykey = k.Pkey
   430  				}
   431  			}
   432  		} else if commnetDef, ok := def.(*engine.CommentDef); ok {
   433  			properties = append(properties, &plan.Property{
   434  				Key:   catalog.SystemRelAttr_Comment,
   435  				Value: commnetDef.Comment,
   436  			})
   437  		} else if partitionDef, ok := def.(*engine.PartitionDef); ok {
   438  			if partitionDef.Partitioned > 0 {
   439  				p := &plan.PartitionByDef{}
   440  				err = p.UnMarshalPartitionInfo(([]byte)(partitionDef.Partition))
   441  				if err != nil {
   442  					return nil, nil
   443  				}
   444  				partitionInfo = p
   445  			}
   446  		} else if v, ok := def.(*engine.VersionDef); ok {
   447  			schemaVersion = v.Version
   448  		}
   449  	}
   450  	if len(properties) > 0 {
   451  		defs = append(defs, &plan.TableDefType{
   452  			Def: &plan.TableDef_DefType_Properties{
   453  				Properties: &plan.PropertiesDef{
   454  					Properties: properties,
   455  				},
   456  			},
   457  		})
   458  	}
   459  
   460  	if primarykey != nil && primarykey.PkeyColName == catalog.CPrimaryKeyColName {
   461  		//cols = append(cols, plan.MakeHiddenColDefByName(catalog.CPrimaryKeyColName))
   462  		primarykey.CompPkeyCol = plan.GetColDefFromTable(cols, catalog.CPrimaryKeyColName)
   463  	}
   464  	if clusterByDef != nil && util.JudgeIsCompositeClusterByColumn(clusterByDef.Name) {
   465  		//cols = append(cols, plan.MakeHiddenColDefByName(clusterByDef.Name))
   466  		clusterByDef.CompCbkeyCol = plan.GetColDefFromTable(cols, clusterByDef.Name)
   467  	}
   468  	rowIdCol := plan.MakeRowIdColDef()
   469  	cols = append(cols, rowIdCol)
   470  
   471  	//convert
   472  	obj := &plan.ObjectRef{
   473  		SchemaName:       dbName,
   474  		ObjName:          tableName,
   475  		SubscriptionName: subscriptionName,
   476  	}
   477  
   478  	tableDef := &plan.TableDef{
   479  		TblId:        tableId,
   480  		Name:         tableName,
   481  		Cols:         cols,
   482  		Defs:         defs,
   483  		TableType:    TableType,
   484  		Createsql:    Createsql,
   485  		Pkey:         primarykey,
   486  		ViewSql:      viewSql,
   487  		Partition:    partitionInfo,
   488  		Fkeys:        foreignKeys,
   489  		RefChildTbls: refChildTbls,
   490  		ClusterBy:    clusterByDef,
   491  		Indexes:      indexes,
   492  		Version:      schemaVersion,
   493  		DbName:       dbName,
   494  	}
   495  	return obj, tableDef
   496  }