github.com/matrixorigin/matrixone@v0.7.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/config" 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 ) 31 32 const DefaultTenantMoAdmin = "sys:internal:moadmin" 33 34 func applyOverride(sess *Session, opts ie.SessionOverrideOptions) { 35 if opts.Database != nil { 36 sess.SetDatabaseName(*opts.Database) 37 } 38 39 if opts.Username != nil { 40 sess.GetMysqlProtocol().SetUserName(*opts.Username) 41 } 42 43 if opts.IsInternal != nil { 44 sess.isInternal = *opts.IsInternal 45 } 46 } 47 48 type internalMiniExec interface { 49 doComQuery(requestCtx context.Context, sql string) error 50 SetSession(*Session) 51 } 52 53 type internalExecutor struct { 54 sync.Mutex 55 proto *internalProtocol 56 executor internalMiniExec // MySqlCmdExecutor struct impls miniExec 57 pu *config.ParameterUnit 58 baseSessOpts ie.SessionOverrideOptions 59 autoIncrCaches defines.AutoIncrCaches 60 } 61 62 func NewInternalExecutor(pu *config.ParameterUnit, autoIncrCaches defines.AutoIncrCaches) *internalExecutor { 63 return newIe(pu, NewMysqlCmdExecutor(), autoIncrCaches) 64 } 65 66 func newIe(pu *config.ParameterUnit, inner internalMiniExec, autoIncrCaches defines.AutoIncrCaches) *internalExecutor { 67 proto := &internalProtocol{result: &internalExecResult{}} 68 ret := &internalExecutor{ 69 proto: proto, 70 executor: inner, 71 pu: pu, 72 baseSessOpts: ie.NewOptsBuilder().Finish(), 73 autoIncrCaches: autoIncrCaches, 74 } 75 return ret 76 } 77 78 type internalExecResult struct { 79 affectedRows uint64 80 resultSet *MysqlResultSet 81 dropped uint64 82 err error 83 } 84 85 func (res *internalExecResult) Error() error { 86 return res.err 87 } 88 89 func (res *internalExecResult) ColumnCount() uint64 { 90 return res.resultSet.GetColumnCount() 91 } 92 93 func (res *internalExecResult) Column(ctx context.Context, i uint64) (name string, typ uint8, signed bool, err error) { 94 col, err := res.resultSet.GetColumn(ctx, i) 95 if err == nil { 96 name = col.Name() 97 typ = uint8(col.ColumnType()) 98 signed = col.IsSigned() 99 } 100 return 101 } 102 103 func (res *internalExecResult) RowCount() uint64 { 104 return res.resultSet.GetRowCount() 105 } 106 107 func (res *internalExecResult) Row(ctx context.Context, i uint64) ([]interface{}, error) { 108 return res.resultSet.GetRow(ctx, i) 109 } 110 111 func (res *internalExecResult) Value(ctx context.Context, ridx uint64, cidx uint64) (interface{}, error) { 112 return res.resultSet.GetValue(ctx, ridx, cidx) 113 } 114 115 func (res *internalExecResult) ValueByName(ctx context.Context, ridx uint64, col string) (interface{}, error) { 116 return res.resultSet.GetValueByName(ctx, ridx, col) 117 } 118 119 func (res *internalExecResult) StringValueByName(ctx context.Context, ridx uint64, col string) (string, error) { 120 if cidx, err := res.resultSet.columnName2Index(ctx, col); err != nil { 121 return "", err 122 } else { 123 return res.resultSet.GetString(ctx, ridx, cidx) 124 } 125 } 126 127 func (res *internalExecResult) Float64ValueByName(ctx context.Context, ridx uint64, col string) (float64, error) { 128 if cidx, err := res.resultSet.columnName2Index(ctx, col); err != nil { 129 return 0.0, err 130 } else { 131 return res.resultSet.GetFloat64(ctx, ridx, cidx) 132 } 133 } 134 135 func (ie *internalExecutor) Exec(ctx context.Context, sql string, opts ie.SessionOverrideOptions) (err error) { 136 ie.Lock() 137 defer ie.Unlock() 138 sess := ie.newCmdSession(ctx, opts) 139 defer sess.Dispose() 140 ie.executor.SetSession(sess) 141 ie.proto.stashResult = false 142 return ie.executor.doComQuery(ctx, sql) 143 } 144 145 func (ie *internalExecutor) Query(ctx context.Context, sql string, opts ie.SessionOverrideOptions) ie.InternalExecResult { 146 ie.Lock() 147 defer ie.Unlock() 148 sess := ie.newCmdSession(ctx, opts) 149 defer sess.Dispose() 150 ie.executor.SetSession(sess) 151 ie.proto.stashResult = true 152 logutil.Info("internalExecutor new session", trace.ContextField(ctx), zap.String("session uuid", sess.uuid.String())) 153 err := ie.executor.doComQuery(ctx, sql) 154 res := ie.proto.swapOutResult() 155 res.err = err 156 return res 157 } 158 159 func (ie *internalExecutor) newCmdSession(ctx context.Context, opts ie.SessionOverrideOptions) *Session { 160 // Use the Mid configuration for session. We can make Mid a configuration 161 // param, or, compute from GuestMmuLimitation. Lazy. 162 // 163 // XXX MPOOL 164 // Cannot use Mid. Turns out we create a Session for *EVERY QUERY* 165 // If we preallocate anything, we will explode. 166 // 167 // Session does not have a close call. We need a Close() call in the Exec/Query method above. 168 // 169 mp, err := mpool.NewMPool("internal_exec_cmd_session", ie.pu.SV.GuestMmuLimitation, mpool.NoFixed) 170 if err != nil { 171 logutil.Fatalf("internalExecutor cannot create mpool in newCmdSession") 172 panic(err) 173 } 174 sess := NewSession(ie.proto, mp, ie.pu, GSysVariables, true) 175 sess.SetRequestContext(ctx) 176 177 // Set AutoIncrCache for this session. 178 sess.SetAutoIncrCaches(ie.autoIncrCaches) 179 180 t, _ := GetTenantInfo(ctx, DefaultTenantMoAdmin) 181 sess.SetTenantInfo(t) 182 applyOverride(sess, ie.baseSessOpts) 183 applyOverride(sess, opts) 184 return sess 185 } 186 187 func (ie *internalExecutor) ApplySessionOverride(opts ie.SessionOverrideOptions) { 188 ie.baseSessOpts = opts 189 } 190 191 // func showCaller() { 192 // pc, _, _, _ := runtime.Caller(1) 193 // callFunc := runtime.FuncForPC(pc) 194 // logutil.Infof("[Metric] called: %s", callFunc.Name()) 195 // } 196 197 var _ MysqlProtocol = &internalProtocol{} 198 199 type internalProtocol struct { 200 sync.Mutex 201 stashResult bool 202 result *internalExecResult 203 database string 204 username string 205 } 206 207 func (ip *internalProtocol) GetCapability() uint32 { 208 return DefaultCapability 209 } 210 211 func (ip *internalProtocol) IsTlsEstablished() bool { 212 return true 213 } 214 215 func (ip *internalProtocol) SetTlsEstablished() { 216 } 217 218 func (ip *internalProtocol) HandleHandshake(ctx context.Context, payload []byte) (bool, error) { 219 return false, nil 220 } 221 222 func (ip *internalProtocol) GetTcpConnection() goetty.IOSession { 223 return nil 224 } 225 226 func (ip *internalProtocol) GetConciseProfile() string { 227 return "internal protocol" 228 } 229 230 func (ip *internalProtocol) GetSequenceId() uint8 { 231 return 0 232 } 233 234 func (ip *internalProtocol) SetSequenceID(value uint8) { 235 } 236 237 func (ip *internalProtocol) makeProfile(profileTyp profileType) { 238 239 } 240 241 func (ip *internalProtocol) getProfile(profileTyp profileType) string { 242 return "" 243 } 244 245 func (ip *internalProtocol) IsEstablished() bool { 246 return true 247 } 248 249 func (ip *internalProtocol) ParseExecuteData(ctx context.Context, stmt *PrepareStmt, data []byte, pos int) (names []string, vars []any, err error) { 250 return nil, nil, nil 251 } 252 253 func (ip *internalProtocol) SendPrepareResponse(ctx context.Context, stmt *PrepareStmt) error { 254 return nil 255 } 256 257 func (ip *internalProtocol) SetEstablished() {} 258 259 func (ip *internalProtocol) GetRequest(payload []byte) *Request { 260 panic("not impl") 261 } 262 263 // ConnectionID the identity of the client 264 func (ip *internalProtocol) ConnectionID() uint32 { 265 return 74751101 266 } 267 268 // Peer gets the address [Host:Port] of the client 269 func (ip *internalProtocol) Peer() (string, string, string, string) { 270 panic("not impl") 271 } 272 273 func (ip *internalProtocol) GetDatabaseName() string { 274 return ip.database 275 } 276 277 func (ip *internalProtocol) SetDatabaseName(database string) { 278 ip.database = database 279 } 280 281 func (ip *internalProtocol) GetUserName() string { 282 return ip.username 283 } 284 285 func (ip *internalProtocol) SetUserName(username string) { 286 ip.username = username 287 } 288 289 func (ip *internalProtocol) Quit() {} 290 291 func (ip *internalProtocol) sendRows(mrs *MysqlResultSet, cnt uint64) error { 292 if ip.stashResult { 293 res := ip.result.resultSet 294 if res == nil { 295 res = &MysqlResultSet{} 296 ip.result.resultSet = res 297 } 298 299 if res.GetRowCount() > 100 { 300 ip.result.dropped += cnt 301 return nil 302 } 303 304 if res.GetColumnCount() == 0 { 305 for _, col := range mrs.Columns { 306 res.AddColumn(col) 307 } 308 } 309 colCnt := res.GetColumnCount() 310 for i := uint64(0); i < cnt; i++ { 311 row := make([]any, colCnt) 312 copy(row, mrs.Data[i]) 313 res.Data = append(res.Data, row) 314 } 315 } 316 317 ip.result.affectedRows += cnt 318 return nil 319 } 320 321 func (ip *internalProtocol) swapOutResult() *internalExecResult { 322 ret := ip.result 323 if ret.resultSet == nil { 324 ret.resultSet = &MysqlResultSet{} 325 } 326 ip.result = &internalExecResult{} 327 return ret 328 } 329 330 // the server send group row of the result set as an independent packet thread safe 331 func (ip *internalProtocol) SendResultSetTextBatchRow(mrs *MysqlResultSet, cnt uint64) error { 332 ip.Lock() 333 defer ip.Unlock() 334 return ip.sendRows(mrs, cnt) 335 } 336 337 func (ip *internalProtocol) SendResultSetTextBatchRowSpeedup(mrs *MysqlResultSet, cnt uint64) error { 338 ip.Lock() 339 defer ip.Unlock() 340 return ip.sendRows(mrs, cnt) 341 } 342 343 // SendColumnDefinitionPacket the server send the column definition to the client 344 func (ip *internalProtocol) SendColumnDefinitionPacket(ctx context.Context, column Column, cmd int) error { 345 return nil 346 } 347 348 // SendColumnCountPacket makes the column count packet 349 func (ip *internalProtocol) SendColumnCountPacket(count uint64) error { 350 return nil 351 } 352 353 // SendResponse sends a response to the client for the application request 354 func (ip *internalProtocol) SendResponse(ctx context.Context, resp *Response) error { 355 ip.Lock() 356 defer ip.Unlock() 357 ip.ResetStatistics() 358 if resp.category == ResultResponse { 359 if mer := resp.data.(*MysqlExecutionResult); mer != nil && mer.Mrs() != nil { 360 ip.sendRows(mer.Mrs(), mer.mrs.GetRowCount()) 361 } 362 } else { 363 // OkResponse. this is NOT ErrorResponse because error will be returned by doComQuery 364 ip.result.affectedRows = resp.affectedRows 365 } 366 return nil 367 } 368 369 // SendEOFPacketIf ends the sending of columns definations 370 func (ip *internalProtocol) SendEOFPacketIf(warnings uint16, status uint16) error { 371 return nil 372 } 373 374 // sendOKPacket sends OK packet to the client, used in the end of sql like use <database> 375 func (ip *internalProtocol) sendOKPacket(affectedRows uint64, lastInsertId uint64, status uint16, warnings uint16, message string) error { 376 ip.result.affectedRows = affectedRows 377 return nil 378 } 379 380 // sendEOFOrOkPacket sends the OK or EOF packet thread safe, and ends the sending of result set 381 func (ip *internalProtocol) sendEOFOrOkPacket(warnings uint16, status uint16) error { 382 return nil 383 } 384 385 func (ip *internalProtocol) ResetStatistics() { 386 ip.result.affectedRows = 0 387 ip.result.dropped = 0 388 ip.result.err = nil 389 ip.result.resultSet = nil 390 } 391 392 func (ip *internalProtocol) GetStats() string { return "internal unknown stats" } 393 394 func (ip *internalProtocol) sendLocalInfileRequest(filename string) error { 395 return nil 396 }