github.com/matrixorigin/matrixone@v1.2.0/pkg/frontend/internal_executor.go (about)

     1  // Copyright 2022 Matrix Origin
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package frontend
    16  
    17  import (
    18  	"context"
    19  	"sync"
    20  
    21  	"github.com/fagongzi/goetty/v2"
    22  	"go.uber.org/zap"
    23  
    24  	"github.com/matrixorigin/matrixone/pkg/common/mpool"
    25  	"github.com/matrixorigin/matrixone/pkg/common/runtime"
    26  	"github.com/matrixorigin/matrixone/pkg/defines"
    27  	"github.com/matrixorigin/matrixone/pkg/logutil"
    28  	ie "github.com/matrixorigin/matrixone/pkg/util/internalExecutor"
    29  	"github.com/matrixorigin/matrixone/pkg/util/trace"
    30  	"github.com/matrixorigin/matrixone/pkg/vm/process"
    31  )
    32  
    33  const DefaultTenantMoAdmin = "sys:internal:moadmin"
    34  
    35  func applyOverride(sess *Session, opts ie.SessionOverrideOptions) {
    36  	if opts.Database != nil {
    37  		sess.SetDatabaseName(*opts.Database)
    38  	}
    39  
    40  	if opts.Username != nil {
    41  		sess.GetMysqlProtocol().SetUserName(*opts.Username)
    42  	}
    43  
    44  	if opts.IsInternal != nil {
    45  		sess.isInternal = *opts.IsInternal
    46  	}
    47  
    48  	acc := sess.GetTenantInfo()
    49  	if acc != nil {
    50  		if opts.AccountId != nil {
    51  			acc.SetTenantID(*opts.AccountId)
    52  		}
    53  
    54  		if opts.UserId != nil {
    55  			acc.SetUserID(*opts.UserId)
    56  		}
    57  
    58  		if opts.DefaultRoleId != nil {
    59  			acc.SetDefaultRoleID(*opts.DefaultRoleId)
    60  		}
    61  	}
    62  
    63  }
    64  
    65  type internalExecutor struct {
    66  	sync.Mutex
    67  	proto        *internalProtocol
    68  	baseSessOpts ie.SessionOverrideOptions
    69  }
    70  
    71  func NewInternalExecutor() *internalExecutor {
    72  	return newIe()
    73  }
    74  
    75  func newIe() *internalExecutor {
    76  	proto := &internalProtocol{result: &internalExecResult{}}
    77  	ret := &internalExecutor{
    78  		proto:        proto,
    79  		baseSessOpts: ie.NewOptsBuilder().Finish(),
    80  	}
    81  	return ret
    82  }
    83  
    84  type internalExecResult struct {
    85  	affectedRows uint64
    86  	resultSet    *MysqlResultSet
    87  	dropped      uint64
    88  	err          error
    89  }
    90  
    91  func (res *internalExecResult) Error() error {
    92  	return res.err
    93  }
    94  
    95  func (res *internalExecResult) ColumnCount() uint64 {
    96  	return res.resultSet.GetColumnCount()
    97  }
    98  
    99  func (res *internalExecResult) Column(ctx context.Context, i uint64) (name string, typ uint8, signed bool, err error) {
   100  	col, err := res.resultSet.GetColumn(ctx, i)
   101  	if err == nil {
   102  		name = col.Name()
   103  		typ = uint8(col.ColumnType())
   104  		signed = col.IsSigned()
   105  	}
   106  	return
   107  }
   108  
   109  func (res *internalExecResult) RowCount() uint64 {
   110  	return res.resultSet.GetRowCount()
   111  }
   112  
   113  func (res *internalExecResult) Row(ctx context.Context, i uint64) ([]interface{}, error) {
   114  	return res.resultSet.GetRow(ctx, i)
   115  }
   116  
   117  func (res *internalExecResult) Value(ctx context.Context, ridx uint64, cidx uint64) (interface{}, error) {
   118  	return res.resultSet.GetValue(ctx, ridx, cidx)
   119  }
   120  
   121  func (res *internalExecResult) ValueByName(ctx context.Context, ridx uint64, col string) (interface{}, error) {
   122  	return res.resultSet.GetValueByName(ctx, ridx, col)
   123  }
   124  
   125  func (res *internalExecResult) StringValueByName(ctx context.Context, ridx uint64, col string) (string, error) {
   126  	if cidx, err := res.resultSet.columnName2Index(ctx, col); err != nil {
   127  		return "", err
   128  	} else {
   129  		return res.resultSet.GetString(ctx, ridx, cidx)
   130  	}
   131  }
   132  
   133  func (res *internalExecResult) Float64ValueByName(ctx context.Context, ridx uint64, col string) (float64, error) {
   134  	if cidx, err := res.resultSet.columnName2Index(ctx, col); err != nil {
   135  		return 0.0, err
   136  	} else {
   137  		return res.resultSet.GetFloat64(ctx, ridx, cidx)
   138  	}
   139  }
   140  
   141  func (ie *internalExecutor) Exec(ctx context.Context, sql string, opts ie.SessionOverrideOptions) (err error) {
   142  	ie.Lock()
   143  	defer ie.Unlock()
   144  	var cancel context.CancelFunc
   145  	ctx, cancel = context.WithTimeout(ctx, getGlobalPu().SV.SessionTimeout.Duration)
   146  	defer cancel()
   147  	sess := ie.newCmdSession(ctx, opts)
   148  	defer func() {
   149  		sess.Close()
   150  	}()
   151  	ie.proto.stashResult = false
   152  	if sql == "" {
   153  		return
   154  	}
   155  	tempExecCtx := ExecCtx{
   156  		reqCtx: ctx,
   157  		ses:    sess,
   158  	}
   159  	return doComQuery(sess, &tempExecCtx, &UserInput{sql: sql})
   160  }
   161  
   162  func (ie *internalExecutor) Query(ctx context.Context, sql string, opts ie.SessionOverrideOptions) ie.InternalExecResult {
   163  	ie.Lock()
   164  	defer ie.Unlock()
   165  	var cancel context.CancelFunc
   166  	ctx, cancel = context.WithTimeout(ctx, getGlobalPu().SV.SessionTimeout.Duration)
   167  	defer cancel()
   168  	sess := ie.newCmdSession(ctx, opts)
   169  	defer sess.Close()
   170  	ie.proto.stashResult = true
   171  	logutil.Info("internalExecutor new session", trace.ContextField(ctx), zap.String("session uuid", sess.uuid.String()))
   172  	tempExecCtx := ExecCtx{
   173  		reqCtx: ctx,
   174  		ses:    sess,
   175  	}
   176  	err := doComQuery(sess, &tempExecCtx, &UserInput{sql: sql})
   177  	res := ie.proto.swapOutResult()
   178  	res.err = err
   179  	return res
   180  }
   181  
   182  func (ie *internalExecutor) newCmdSession(ctx context.Context, opts ie.SessionOverrideOptions) *Session {
   183  	// Use the Mid configuration for session. We can make Mid a configuration
   184  	// param, or, compute from GuestMmuLimitation.   Lazy.
   185  	//
   186  	// XXX MPOOL
   187  	// Cannot use Mid.   Turns out we create a Session for *EVERY QUERY*
   188  	// If we preallocate anything, we will explode.
   189  	//
   190  	// Session does not have a close call.   We need a Close() call in the Exec/Query method above.
   191  	//
   192  	mp, err := mpool.NewMPool("internal_exec_cmd_session", getGlobalPu().SV.GuestMmuLimitation, mpool.NoFixed)
   193  	if err != nil {
   194  		logutil.Fatalf("internalExecutor cannot create mpool in newCmdSession")
   195  		panic(err)
   196  	}
   197  	sess := NewSession(ctx, ie.proto, mp, GSysVariables, true, nil)
   198  	sess.disableTrace = true
   199  
   200  	var t *TenantInfo
   201  	if accountId, err := defines.GetAccountId(ctx); err == nil {
   202  		t = &TenantInfo{
   203  			TenantID:      accountId,
   204  			UserID:        defines.GetUserId(ctx),
   205  			DefaultRoleID: defines.GetRoleId(ctx),
   206  		}
   207  		if accountId == sysAccountID {
   208  			t.Tenant = sysAccountName // fixme: fix empty tencent value, while do metric collection.
   209  			t.User = "internal"
   210  			// more details in authenticateUserCanExecuteStatementWithObjectTypeNone()
   211  			t.DefaultRole = moAdminRoleName
   212  		}
   213  	} else {
   214  		t, _ = GetTenantInfo(ctx, DefaultTenantMoAdmin)
   215  	}
   216  	sess.SetTenantInfo(t)
   217  	applyOverride(sess, ie.baseSessOpts)
   218  	applyOverride(sess, opts)
   219  
   220  	//make sure init tasks can see the prev task's data
   221  	now, _ := runtime.ProcessLevelRuntime().Clock().Now()
   222  	sess.lastCommitTS = now
   223  	return sess
   224  }
   225  
   226  func (ie *internalExecutor) ApplySessionOverride(opts ie.SessionOverrideOptions) {
   227  	ie.baseSessOpts = opts
   228  }
   229  
   230  // func showCaller() {
   231  // 	pc, _, _, _ := runtime.Caller(1)
   232  // 	callFunc := runtime.FuncForPC(pc)
   233  // 	logutil.Infof("[Metric] called: %s", callFunc.Name())
   234  // }
   235  
   236  var _ MysqlProtocol = &internalProtocol{}
   237  
   238  type internalProtocol struct {
   239  	sync.Mutex
   240  	stashResult bool
   241  	result      *internalExecResult
   242  	database    string
   243  	username    string
   244  }
   245  
   246  func (ip *internalProtocol) UpdateCtx(ctx context.Context) {
   247  
   248  }
   249  
   250  func (ip *internalProtocol) GetCapability() uint32 {
   251  	return DefaultCapability
   252  }
   253  
   254  func (ip *internalProtocol) SetCapability(uint32) {
   255  
   256  }
   257  
   258  func (ip *internalProtocol) IsTlsEstablished() bool {
   259  	return true
   260  }
   261  
   262  func (ip *internalProtocol) SetTlsEstablished() {
   263  }
   264  
   265  func (ip *internalProtocol) HandleHandshake(ctx context.Context, payload []byte) (bool, error) {
   266  	return false, nil
   267  }
   268  
   269  func (ip *internalProtocol) Authenticate(ctx context.Context) error {
   270  	return nil
   271  }
   272  
   273  func (ip *internalProtocol) GetTcpConnection() goetty.IOSession {
   274  	return nil
   275  }
   276  
   277  func (ip *internalProtocol) GetDebugString() string {
   278  	return "internal protocol"
   279  }
   280  
   281  func (ip *internalProtocol) GetSequenceId() uint8 {
   282  	return 0
   283  }
   284  
   285  func (ip *internalProtocol) GetConnectAttrs() map[string]string {
   286  	return nil
   287  }
   288  
   289  func (ip *internalProtocol) SetSequenceID(value uint8) {
   290  }
   291  
   292  func (ip *internalProtocol) IsEstablished() bool {
   293  	return true
   294  }
   295  
   296  func (ip *internalProtocol) ParseSendLongData(ctx context.Context, proc *process.Process, stmt *PrepareStmt, data []byte, pos int) error {
   297  	return nil
   298  }
   299  
   300  func (ip *internalProtocol) ParseExecuteData(ctx context.Context, proc *process.Process, stmt *PrepareStmt, data []byte, pos int) error {
   301  	return nil
   302  }
   303  
   304  func (ip *internalProtocol) SendPrepareResponse(ctx context.Context, stmt *PrepareStmt) error {
   305  	return nil
   306  }
   307  
   308  func (ip *internalProtocol) SetEstablished() {}
   309  
   310  func (ip *internalProtocol) GetRequest(payload []byte) *Request {
   311  	panic("not impl")
   312  }
   313  
   314  // ConnectionID the identity of the client
   315  func (ip *internalProtocol) ConnectionID() uint32 {
   316  	return 74751101
   317  }
   318  
   319  // Peer gets the address [Host:Port] of the client
   320  func (ip *internalProtocol) Peer() string {
   321  	return "0.0.0.0:0"
   322  }
   323  
   324  func (ip *internalProtocol) GetDatabaseName() string {
   325  	return ip.database
   326  }
   327  
   328  func (ip *internalProtocol) SetDatabaseName(database string) {
   329  	ip.database = database
   330  }
   331  
   332  func (ip *internalProtocol) GetUserName() string {
   333  	return ip.username
   334  }
   335  
   336  func (ip *internalProtocol) SetUserName(username string) {
   337  	ip.username = username
   338  }
   339  
   340  func (ip *internalProtocol) Quit() {}
   341  
   342  func (ip *internalProtocol) sendRows(mrs *MysqlResultSet, cnt uint64) error {
   343  	if ip.stashResult {
   344  		res := ip.result.resultSet
   345  		if res == nil {
   346  			res = &MysqlResultSet{}
   347  			ip.result.resultSet = res
   348  		}
   349  
   350  		if res.GetRowCount() > 100 {
   351  			ip.result.dropped += cnt
   352  			return nil
   353  		}
   354  
   355  		if res.GetColumnCount() == 0 {
   356  			for _, col := range mrs.Columns {
   357  				res.AddColumn(col)
   358  			}
   359  		}
   360  		colCnt := res.GetColumnCount()
   361  		for i := uint64(0); i < cnt; i++ {
   362  			row := make([]any, colCnt)
   363  			copy(row, mrs.Data[i])
   364  			res.Data = append(res.Data, row)
   365  		}
   366  	}
   367  
   368  	ip.result.affectedRows += cnt
   369  	return nil
   370  }
   371  
   372  func (ip *internalProtocol) swapOutResult() *internalExecResult {
   373  	ret := ip.result
   374  	if ret.resultSet == nil {
   375  		ret.resultSet = &MysqlResultSet{}
   376  	}
   377  	ip.result = &internalExecResult{}
   378  	return ret
   379  }
   380  
   381  // the server send group row of the result set as an independent packet thread safe
   382  func (ip *internalProtocol) SendResultSetTextBatchRow(mrs *MysqlResultSet, cnt uint64) error {
   383  	ip.Lock()
   384  	defer ip.Unlock()
   385  	return ip.sendRows(mrs, cnt)
   386  }
   387  
   388  func (ip *internalProtocol) SendResultSetTextBatchRowSpeedup(mrs *MysqlResultSet, cnt uint64) error {
   389  	ip.Lock()
   390  	defer ip.Unlock()
   391  	return ip.sendRows(mrs, cnt)
   392  }
   393  
   394  // SendColumnDefinitionPacket the server send the column definition to the client
   395  func (ip *internalProtocol) SendColumnDefinitionPacket(ctx context.Context, column Column, cmd int) error {
   396  	return nil
   397  }
   398  
   399  // SendColumnCountPacket makes the column count packet
   400  func (ip *internalProtocol) SendColumnCountPacket(count uint64) error {
   401  	return nil
   402  }
   403  
   404  // SendResponse sends a response to the client for the application request
   405  func (ip *internalProtocol) SendResponse(ctx context.Context, resp *Response) error {
   406  	ip.Lock()
   407  	defer ip.Unlock()
   408  	ip.ResetStatistics()
   409  	if resp.category == ResultResponse {
   410  		if mer := resp.data.(*MysqlExecutionResult); mer != nil && mer.Mrs() != nil {
   411  			ip.sendRows(mer.Mrs(), mer.mrs.GetRowCount())
   412  		}
   413  	} else {
   414  		// OkResponse. this is NOT ErrorResponse because error will be returned by doComQuery
   415  		ip.result.affectedRows = resp.affectedRows
   416  	}
   417  	return nil
   418  }
   419  
   420  // SendEOFPacketIf ends the sending of columns definations
   421  func (ip *internalProtocol) SendEOFPacketIf(warnings uint16, status uint16) error {
   422  	return nil
   423  }
   424  
   425  // sendOKPacket sends OK packet to the client, used in the end of sql like use <database>
   426  func (ip *internalProtocol) sendOKPacket(affectedRows uint64, lastInsertId uint64, status uint16, warnings uint16, message string) error {
   427  	ip.result.affectedRows = affectedRows
   428  	return nil
   429  }
   430  
   431  // sendEOFOrOkPacket sends the OK or EOF packet thread safe, and ends the sending of result set
   432  func (ip *internalProtocol) sendEOFOrOkPacket(warnings uint16, status uint16) error {
   433  	return nil
   434  }
   435  
   436  func (ip *internalProtocol) ResetStatistics() {
   437  	ip.result.affectedRows = 0
   438  	ip.result.dropped = 0
   439  	ip.result.err = nil
   440  	ip.result.resultSet = nil
   441  }
   442  
   443  func (ip *internalProtocol) GetStats() string { return "internal unknown stats" }
   444  
   445  func (ip *internalProtocol) CalculateOutTrafficBytes(reset bool) (int64, int64) { return 0, 0 }
   446  
   447  func (ip *internalProtocol) sendLocalInfileRequest(filename string) error {
   448  	return nil
   449  }
   450  
   451  func (ip *internalProtocol) incDebugCount(int) {}
   452  
   453  func (ip *internalProtocol) resetDebugCount() []uint64 {
   454  	return nil
   455  }
   456  
   457  func (ip *internalProtocol) DisableAutoFlush() {
   458  }
   459  
   460  func (ip *internalProtocol) EnableAutoFlush() {
   461  }
   462  
   463  func (ip *internalProtocol) Flush() error {
   464  	return nil
   465  }