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 }