github.com/matrixorigin/matrixone@v1.2.0/pkg/frontend/show_account.go (about) 1 // Copyright 2021 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 "fmt" 20 "math" 21 "strings" 22 "time" 23 24 "github.com/matrixorigin/matrixone/pkg/catalog" 25 "github.com/matrixorigin/matrixone/pkg/common/moerr" 26 "github.com/matrixorigin/matrixone/pkg/common/mpool" 27 "github.com/matrixorigin/matrixone/pkg/container/batch" 28 "github.com/matrixorigin/matrixone/pkg/container/vector" 29 "github.com/matrixorigin/matrixone/pkg/defines" 30 "github.com/matrixorigin/matrixone/pkg/fileservice" 31 "github.com/matrixorigin/matrixone/pkg/logutil" 32 "github.com/matrixorigin/matrixone/pkg/pb/api" 33 "github.com/matrixorigin/matrixone/pkg/pb/plan" 34 "github.com/matrixorigin/matrixone/pkg/sql/parsers/tree" 35 "github.com/matrixorigin/matrixone/pkg/sql/plan/function/ctl" 36 v2 "github.com/matrixorigin/matrixone/pkg/util/metric/v2" 37 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/db" 38 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/logtail" 39 "github.com/matrixorigin/matrixone/pkg/vm/process" 40 ) 41 42 const ( 43 getAllAccountInfoFormat = "select " + 44 "account_id as `account_id`, " + 45 "account_name as `account_name`, " + 46 "created_time as `created`, " + 47 "status as `status`, " + 48 "suspended_time as `suspended_time`, " + 49 "comments as `comment` " + 50 "from " + 51 "mo_catalog.mo_account " + 52 "%s" + 53 ";" 54 55 getAccountInfoFormat = "select " + 56 "account_id as `account_id`, " + 57 "account_name as `account_name`, " + 58 "created_time as `created`, " + 59 "status as `status`, " + 60 "suspended_time as `suspended_time`, " + 61 "comments as `comment` " + 62 "from " + 63 "mo_catalog.mo_account " + 64 "where account_id = %d;" 65 66 // column index in the result set generated by 67 // the sql getAllAccountInfoFormat, getAccountInfoFormat 68 idxOfAccountId = 0 69 idxOfAccountName = 1 70 idxOfCreated = 2 71 idxOfStatus = 3 72 idxOfSuspendedTime = 4 73 idxOfComment = 5 74 75 // left the `size` as a placeholder, the value will be embedding later 76 // index table(__index_xxx): do not counting it into the `table_count`, but need its size. 77 // mo_increment_columns: do not counting it into the `table_count`, but need its size. 78 // subscription db: do not counting it into the `db_count`, and its size 79 // sys table(mo_database, mo_tables, mo_column): counting them into the `table_count`, and need their sizes 80 getTableStatsFormatV2 = "select " + 81 "( select " + 82 " mu2.user_name as `admin_name` " + 83 " from mo_catalog.mo_user as mu2 join " + 84 " ( select " + 85 " min(user_id) as `min_user_id` " + 86 " from mo_catalog.mo_user " + 87 " ) as mu1 on mu2.user_id = mu1.min_user_id " + 88 ") as `admin_name`, " + 89 "count(distinct md.datname) as `db_count`, " + 90 "count(distinct mt.relname) as `table_count`, " + 91 "cast(0 as double) as `size` " + 92 "from " + 93 "mo_catalog.mo_tables as mt, mo_catalog.mo_database as md " + 94 "where md.dat_type != 'subscription' " + 95 "and mt.relkind in ('v','r','e','cluster') " + 96 "and mt.account_id in (%d, %d);" 97 98 // column index in the result set generated by 99 // the sql getTableStatsFormatV2 100 idxOfAdminName = 0 101 idxOfDBCount = 1 102 idxOfTableCount = 2 103 idxOfSize = 3 104 105 // column index in the result set of the statement show accounts 106 finalIdxOfAccountName = 0 107 finalIdxOfAdminName = 1 108 finalIdxOfCreated = 2 109 finalIdxOfStatus = 3 110 finalIdxOfSuspendedTime = 4 111 finalIdxOfDBCount = 5 112 finalIdxOfTableCount = 6 113 finalIdxOfSize = 7 114 finalIdxOfComment = 8 115 finalColumnCount = 9 116 ) 117 118 var cnUsageCache = logtail.NewStorageUsageCache( 119 logtail.WithLazyThreshold(5)) 120 121 func getSqlForAllAccountInfo(like *tree.ComparisonExpr) string { 122 var likePattern = "" 123 if like != nil { 124 likePattern = strings.TrimSpace(like.Right.String()) 125 } 126 likeClause := "" 127 if len(likePattern) != 0 { 128 likeClause = fmt.Sprintf("where account_name like '%s'", likePattern) 129 } 130 return fmt.Sprintf(getAllAccountInfoFormat, likeClause) 131 } 132 133 func getSqlForAccountInfo(accountId uint64) string { 134 return fmt.Sprintf(getAccountInfoFormat, accountId) 135 } 136 137 func getSqlForTableStats(accountId int32) string { 138 //return fmt.Sprintf(getTableStatsFormatV2, catalog.SystemPartitionRel, accountId) 139 return fmt.Sprintf(getTableStatsFormatV2, accountId, sysAccountID) 140 } 141 142 func requestStorageUsage(ctx context.Context, ses *Session, accIds [][]int32) (resp any, tried bool, err error) { 143 whichTN := func(string) ([]uint64, error) { return nil, nil } 144 payload := func(tnShardID uint64, parameter string, proc *process.Process) ([]byte, error) { 145 req := db.StorageUsageReq{} 146 for x := range accIds { 147 req.AccIds = append(req.AccIds, accIds[x]...) 148 } 149 150 return req.Marshal() 151 } 152 153 responseUnmarshaler := func(payload []byte) (any, error) { 154 usage := &db.StorageUsageResp{} 155 if err := usage.Unmarshal(payload); err != nil { 156 return nil, err 157 } 158 return usage, nil 159 } 160 161 txnOperator := ses.txnHandler.GetTxn() 162 163 // create a new proc for `handler` 164 proc := process.New(ctx, ses.proc.GetMPool(), 165 ses.proc.TxnClient, txnOperator, 166 ses.proc.FileService, ses.proc.LockService, 167 ses.proc.QueryClient, ses.proc.Hakeeper, 168 ses.proc.UdfService, ses.proc.Aicm, 169 ) 170 171 handler := ctl.GetTNHandlerFunc(api.OpCode_OpStorageUsage, whichTN, payload, responseUnmarshaler) 172 result, err := handler(proc, "DN", "", ctl.MoCtlTNCmdSender) 173 if moerr.IsMoErrCode(err, moerr.ErrNotSupported) { 174 // try the previous RPC method 175 payload_V0 := func(tnShardID uint64, parameter string, proc *process.Process) ([]byte, error) { return nil, nil } 176 responseUnmarshaler_V0 := func(payload []byte) (interface{}, error) { 177 usage := &db.StorageUsageResp_V0{} 178 if err := usage.Unmarshal(payload); err != nil { 179 return nil, err 180 } 181 return usage, nil 182 } 183 184 tried = true 185 CmdMethod_StorageUsage := api.OpCode(14) 186 handler = ctl.GetTNHandlerFunc(CmdMethod_StorageUsage, whichTN, payload_V0, responseUnmarshaler_V0) 187 result, err = handler(proc, "DN", "", ctl.MoCtlTNCmdSender) 188 189 if moerr.IsMoErrCode(err, moerr.ErrNotSupported) { 190 return nil, tried, moerr.NewNotSupportedNoCtx("current tn version not supported `show accounts`") 191 } 192 } 193 194 if err != nil { 195 return nil, tried, err 196 } 197 198 return result.Data.([]any)[0], tried, nil 199 } 200 201 func handleStorageUsageResponse_V0(ctx context.Context, fs fileservice.FileService, 202 usage *db.StorageUsageResp_V0) (map[int32]uint64, error) { 203 result := make(map[int32]uint64, 0) 204 for idx := range usage.CkpEntries { 205 version := usage.CkpEntries[idx].Version 206 location := usage.CkpEntries[idx].Location 207 208 // storage usage was introduced after `CheckpointVersion9` 209 if version < logtail.CheckpointVersion9 { 210 // exist old version checkpoint which hasn't storage usage data in it, 211 // to avoid inaccurate info leading misunderstand, we chose to return empty result 212 logutil.Info("[storage usage]: found older ckp when handle storage usage response") 213 return map[int32]uint64{}, nil 214 } 215 216 ckpData, err := logtail.LoadSpecifiedCkpBatch(ctx, location, version, logtail.StorageUsageInsIDX, fs) 217 if err != nil { 218 return nil, err 219 } 220 221 storageUsageBat := ckpData.GetBatches()[logtail.StorageUsageInsIDX] 222 accIDVec := vector.MustFixedCol[uint64]( 223 storageUsageBat.GetVectorByName(catalog.SystemColAttr_AccID).GetDownstreamVector(), 224 ) 225 sizeVec := vector.MustFixedCol[uint64]( 226 storageUsageBat.GetVectorByName(logtail.CheckpointMetaAttr_ObjectSize).GetDownstreamVector(), 227 ) 228 229 size := uint64(0) 230 length := len(accIDVec) 231 for i := 0; i < length; i++ { 232 result[int32(accIDVec[i])] += sizeVec[i] 233 size += sizeVec[i] 234 } 235 236 ckpData.Close() 237 } 238 239 // [account_id, db_id, table_id, obj_id, table_total_size] 240 for _, info := range usage.BlockEntries { 241 result[int32(info.Info[0])] += info.Info[3] 242 } 243 244 return result, nil 245 } 246 247 func handleStorageUsageResponse( 248 ctx context.Context, 249 usage *db.StorageUsageResp, 250 ) (map[int32]uint64, error) { 251 result := make(map[int32]uint64, 0) 252 253 for x := range usage.AccIds { 254 result[usage.AccIds[x]] += usage.Sizes[x] 255 } 256 257 return result, nil 258 } 259 260 func checkStorageUsageCache(accIds [][]int32) (result map[int32]uint64, succeed bool) { 261 cnUsageCache.Lock() 262 defer cnUsageCache.Unlock() 263 264 if cnUsageCache.IsExpired() { 265 return nil, false 266 } 267 268 result = make(map[int32]uint64) 269 for x := range accIds { 270 for y := range accIds[x] { 271 size, exist := cnUsageCache.GatherAccountSize(uint64(accIds[x][y])) 272 if !exist { 273 // one missed, update all 274 return nil, false 275 } 276 277 result[accIds[x][y]] = size 278 } 279 } 280 281 return result, true 282 } 283 284 func updateStorageUsageCache(accIds []int32, sizes []uint64) { 285 286 if len(accIds) == 0 { 287 return 288 } 289 290 cnUsageCache.Lock() 291 defer cnUsageCache.Unlock() 292 293 // step 1: delete stale accounts 294 cnUsageCache.ClearForUpdate() 295 296 // step 2: update 297 for x := range accIds { 298 usage := logtail.UsageData{AccId: uint64(accIds[x]), Size: sizes[x]} 299 if old, exist := cnUsageCache.Get(usage); exist { 300 usage.Size += old.Size 301 } 302 303 cnUsageCache.SetOrReplace(usage) 304 } 305 } 306 307 // getAccountStorageUsage calculates the storage usage of all accounts 308 // by handling checkpoint 309 func getAccountsStorageUsage(ctx context.Context, ses *Session, accIds [][]int32) (map[int32]uint64, error) { 310 if len(accIds) == 0 { 311 return nil, nil 312 } 313 314 // step 1: check cache 315 if usage, succeed := checkStorageUsageCache(accIds); succeed { 316 return usage, nil 317 } 318 319 // step 2: query to tn 320 response, tried, err := requestStorageUsage(ctx, ses, accIds) 321 if err != nil { 322 return nil, err 323 } 324 325 if tried { 326 usage, ok := response.(*db.StorageUsageResp_V0) 327 if !ok { 328 return nil, moerr.NewInternalErrorNoCtx("storage usage response decode failed, retry later") 329 } 330 331 fs, err := fileservice.Get[fileservice.FileService](getGlobalPu().FileService, defines.SharedFileServiceName) 332 if err != nil { 333 return nil, err 334 } 335 336 // step 3: handling these pulled data 337 return handleStorageUsageResponse_V0(ctx, fs, usage) 338 339 } else { 340 usage, ok := response.(*db.StorageUsageResp) 341 if !ok || usage.Magic != logtail.StorageUsageMagic { 342 return nil, moerr.NewInternalErrorNoCtx("storage usage response decode failed, retry later") 343 } 344 345 updateStorageUsageCache(usage.AccIds, usage.Sizes) 346 347 // step 3: handling these pulled data 348 return handleStorageUsageResponse(ctx, usage) 349 } 350 } 351 352 func embeddingSizeToBatch(ori *batch.Batch, size uint64, mp *mpool.MPool) { 353 vector.SetFixedAt(ori.Vecs[idxOfSize], 0, math.Round(float64(size)/1048576.0*1e6)/1e6) 354 } 355 356 func doShowAccounts(ctx context.Context, ses *Session, sa *tree.ShowAccounts) (err error) { 357 var sql string 358 var accountIds [][]int32 359 var allAccountInfo []*batch.Batch 360 var eachAccountInfo []*batch.Batch 361 var tempBatch *batch.Batch 362 var MoAccountColumns, EachAccountColumns *plan.ResultColDef 363 var outputBatches []*batch.Batch 364 365 start := time.Now() 366 getTableStatsDur := time.Duration(0) 367 defer func() { 368 v2.TaskShowAccountsTotalDurationHistogram.Observe(time.Since(start).Seconds()) 369 v2.TaskShowAccountsGetTableStatsDurationHistogram.Observe(getTableStatsDur.Seconds()) 370 371 }() 372 373 mp := ses.GetMemPool() 374 375 defer func() { 376 for _, b := range allAccountInfo { 377 if b == nil { 378 continue 379 } 380 b.Clean(mp) 381 } 382 for _, b := range outputBatches { 383 if b == nil { 384 continue 385 } 386 b.Clean(mp) 387 } 388 for _, b := range eachAccountInfo { 389 if b == nil { 390 continue 391 } 392 b.Clean(mp) 393 } 394 if tempBatch != nil { 395 tempBatch.Clean(mp) 396 } 397 }() 398 399 bh := ses.GetRawBatchBackgroundExec(ctx) 400 defer bh.Close() 401 402 account := ses.GetTenantInfo() 403 404 err = bh.Exec(ctx, "begin;") 405 defer func() { 406 err = finishTxn(ctx, bh, err) 407 }() 408 409 if err != nil { 410 return err 411 } 412 413 var rsOfMoAccount *MysqlResultSet 414 415 // step 1: 416 // get all accounts info according the type of the requested tenant 417 418 // system account 419 if account.IsSysTenant() { 420 sql = getSqlForAllAccountInfo(sa.Like) 421 if allAccountInfo, accountIds, err = getAccountInfo(ctx, bh, sql, true); err != nil { 422 return err 423 } 424 425 // normal account 426 } else { 427 if sa.Like != nil { 428 return moerr.NewInternalError(ctx, "only sys account can use LIKE clause") 429 } 430 // switch to the sys account to get account info 431 newCtx := defines.AttachAccountId(ctx, uint32(sysAccountID)) 432 sql = getSqlForAccountInfo(uint64(account.GetTenantID())) 433 if allAccountInfo, accountIds, err = getAccountInfo(newCtx, bh, sql, true); err != nil { 434 return err 435 } 436 437 if len(allAccountInfo) != 1 { 438 return moerr.NewInternalError(ctx, "no such account %v", account.GetTenantID()) 439 } 440 } 441 442 backSes := bh.(*backExec) 443 rsOfMoAccount = backSes.backSes.allResultSet[0] 444 MoAccountColumns = backSes.backSes.rs 445 bh.ClearExecResultSet() 446 447 // step 2 448 // calculating the storage usage size of accounts 449 // the returned value is a map: account_id -> size (in bytes) 450 tt := time.Now() 451 usage, err := getAccountsStorageUsage(ctx, ses, accountIds) 452 if err != nil { 453 return err 454 } 455 v2.TaskShowAccountsGetUsageDurationHistogram.Observe(time.Since(tt).Seconds()) 456 457 // step 3 458 outputBatches = make([]*batch.Batch, len(allAccountInfo)) 459 for i, ids := range accountIds { 460 for _, id := range ids { 461 //step 3.1: get the admin_name, db_count, table_count for each account 462 newCtx := defines.AttachAccountId(ctx, uint32(id)) 463 464 tt = time.Now() 465 if tempBatch, err = getTableStats(newCtx, bh, id); err != nil { 466 return err 467 } 468 getTableStatsDur += time.Since(tt) 469 470 // step 3.2: put size value into batch 471 embeddingSizeToBatch(tempBatch, usage[id], mp) 472 473 eachAccountInfo = append(eachAccountInfo, tempBatch) 474 } 475 476 // merge result set from mo_account and table stats from each account 477 outputBatches[i] = batch.NewWithSize(finalColumnCount) 478 if err = mergeOutputResult(ses, outputBatches[i], allAccountInfo[i], eachAccountInfo); err != nil { 479 return err 480 } 481 482 for _, b := range eachAccountInfo { 483 b.Clean(mp) 484 } 485 eachAccountInfo = nil 486 } 487 488 rsOfEachAccount := backSes.backSes.allResultSet[0] 489 EachAccountColumns = backSes.backSes.rs 490 bh.ClearExecResultSet() 491 492 //step4: generate mysql result set 493 outputRS := &MysqlResultSet{} 494 if err = initOutputRs(outputRS, rsOfMoAccount, rsOfEachAccount, ctx); err != nil { 495 return err 496 } 497 498 oq := newFakeOutputQueue(outputRS) 499 for _, b := range outputBatches { 500 if err = fillResultSet(ctx, oq, b, ses); err != nil { 501 return err 502 } 503 } 504 505 ses.SetMysqlResultSet(outputRS) 506 507 ses.rs = mergeRsColumns(MoAccountColumns, EachAccountColumns) 508 if openSaveQueryResult(ctx, ses) { 509 err = saveResult(ctx, ses, outputBatches) 510 } 511 512 return err 513 } 514 515 func mergeRsColumns(rsOfMoAccountColumns *plan.ResultColDef, rsOfEachAccountColumns *plan.ResultColDef) *plan.ResultColDef { 516 def := &plan.ResultColDef{ 517 ResultCols: make([]*plan.ColDef, finalColumnCount), 518 } 519 def.ResultCols[finalIdxOfAccountName] = rsOfMoAccountColumns.ResultCols[idxOfAccountName] 520 def.ResultCols[finalIdxOfAdminName] = rsOfEachAccountColumns.ResultCols[idxOfAdminName] 521 def.ResultCols[finalIdxOfCreated] = rsOfMoAccountColumns.ResultCols[idxOfCreated] 522 def.ResultCols[finalIdxOfStatus] = rsOfMoAccountColumns.ResultCols[idxOfStatus] 523 def.ResultCols[finalIdxOfSuspendedTime] = rsOfMoAccountColumns.ResultCols[idxOfSuspendedTime] 524 def.ResultCols[finalIdxOfDBCount] = rsOfEachAccountColumns.ResultCols[idxOfDBCount] 525 def.ResultCols[finalIdxOfTableCount] = rsOfEachAccountColumns.ResultCols[idxOfTableCount] 526 def.ResultCols[finalIdxOfSize] = rsOfEachAccountColumns.ResultCols[idxOfSize] 527 def.ResultCols[finalIdxOfComment] = rsOfMoAccountColumns.ResultCols[idxOfComment] 528 return def 529 } 530 531 func saveResult(ctx context.Context, ses *Session, outputBatch []*batch.Batch) error { 532 for _, b := range outputBatch { 533 if err := saveQueryResult(ctx, ses, b); err != nil { 534 return err 535 } 536 } 537 if err := saveQueryResultMeta(ctx, ses); err != nil { 538 return err 539 } 540 return nil 541 } 542 543 func initOutputRs(rs *MysqlResultSet, rsOfMoAccount *MysqlResultSet, rsOfEachAccount *MysqlResultSet, ctx context.Context) error { 544 outputColumns := make([]Column, finalColumnCount) 545 var err error 546 outputColumns[finalIdxOfAccountName], err = rsOfMoAccount.GetColumn(ctx, idxOfAccountName) 547 if err != nil { 548 return err 549 } 550 outputColumns[finalIdxOfAdminName], err = rsOfEachAccount.GetColumn(ctx, idxOfAdminName) 551 if err != nil { 552 return err 553 } 554 outputColumns[finalIdxOfCreated], err = rsOfMoAccount.GetColumn(ctx, idxOfCreated) 555 if err != nil { 556 return err 557 } 558 outputColumns[finalIdxOfStatus], err = rsOfMoAccount.GetColumn(ctx, idxOfStatus) 559 if err != nil { 560 return err 561 } 562 outputColumns[finalIdxOfSuspendedTime], err = rsOfMoAccount.GetColumn(ctx, idxOfSuspendedTime) 563 if err != nil { 564 return err 565 } 566 outputColumns[finalIdxOfDBCount], err = rsOfEachAccount.GetColumn(ctx, idxOfDBCount) 567 if err != nil { 568 return err 569 } 570 outputColumns[finalIdxOfTableCount], err = rsOfEachAccount.GetColumn(ctx, idxOfTableCount) 571 if err != nil { 572 return err 573 } 574 outputColumns[finalIdxOfSize], err = rsOfEachAccount.GetColumn(ctx, idxOfSize) 575 if err != nil { 576 return err 577 } 578 outputColumns[finalIdxOfComment], err = rsOfMoAccount.GetColumn(ctx, idxOfComment) 579 if err != nil { 580 return err 581 } 582 for _, o := range outputColumns { 583 rs.AddColumn(o) 584 } 585 return nil 586 } 587 588 // getAccountInfo gets account info from mo_account under sys account 589 func getAccountInfo(ctx context.Context, 590 bh BackgroundExec, 591 sql string, 592 returnAccountIds bool) ([]*batch.Batch, [][]int32, error) { 593 var err error 594 var batchIndex2AccounsIds [][]int32 595 var rsOfMoAccount []*batch.Batch 596 597 bh.ClearExecResultBatches() 598 err = bh.Exec(ctx, sql) 599 if err != nil { 600 return nil, nil, err 601 } 602 603 rsOfMoAccount = bh.GetExecResultBatches() 604 if len(rsOfMoAccount) == 0 { 605 return nil, nil, moerr.NewInternalError(ctx, "no account info") 606 } 607 if returnAccountIds { 608 batchCount := len(rsOfMoAccount) 609 batchIndex2AccounsIds = make([][]int32, batchCount) 610 for i := 0; i < batchCount; i++ { 611 vecLen := rsOfMoAccount[i].Vecs[0].Length() 612 for row := 0; row < vecLen; row++ { 613 batchIndex2AccounsIds[i] = append(batchIndex2AccounsIds[i], vector.GetFixedAt[int32](rsOfMoAccount[i].Vecs[0], row)) 614 } 615 } 616 } 617 return rsOfMoAccount, batchIndex2AccounsIds, err 618 } 619 620 // getTableStats gets the table statistics for the account 621 func getTableStats(ctx context.Context, bh BackgroundExec, accountId int32) (*batch.Batch, error) { 622 var sql string 623 var err error 624 var rs []*batch.Batch 625 sql = getSqlForTableStats(accountId) 626 bh.ClearExecResultBatches() 627 err = bh.Exec(ctx, sql) 628 if err != nil { 629 return nil, err 630 } 631 rs = bh.GetExecResultBatches() 632 if len(rs) != 1 { 633 return nil, moerr.NewInternalError(ctx, "get table stats failed") 634 } 635 return rs[0], err 636 } 637 638 // mergeOutputResult merges the result set from mo_account and the table status 639 // into the final output format 640 func mergeOutputResult(ses *Session, outputBatch *batch.Batch, rsOfMoAccount *batch.Batch, rsOfEachAccount []*batch.Batch) error { 641 var err error 642 mp := ses.GetMemPool() 643 outputBatch.Vecs[finalIdxOfAccountName], err = rsOfMoAccount.Vecs[idxOfAccountName].Dup(mp) 644 if err != nil { 645 return err 646 } 647 outputBatch.Vecs[finalIdxOfAdminName] = vector.NewVec(*rsOfEachAccount[0].Vecs[idxOfAdminName].GetType()) 648 outputBatch.Vecs[finalIdxOfCreated], err = rsOfMoAccount.Vecs[idxOfCreated].Dup(mp) 649 if err != nil { 650 return err 651 } 652 outputBatch.Vecs[finalIdxOfStatus], err = rsOfMoAccount.Vecs[idxOfStatus].Dup(mp) 653 if err != nil { 654 return err 655 } 656 outputBatch.Vecs[finalIdxOfSuspendedTime], err = rsOfMoAccount.Vecs[idxOfSuspendedTime].Dup(mp) 657 if err != nil { 658 return err 659 } 660 outputBatch.Vecs[finalIdxOfDBCount] = vector.NewVec(*rsOfEachAccount[0].Vecs[idxOfDBCount].GetType()) 661 outputBatch.Vecs[finalIdxOfTableCount] = vector.NewVec(*rsOfEachAccount[0].Vecs[idxOfTableCount].GetType()) 662 outputBatch.Vecs[finalIdxOfSize] = vector.NewVec(*rsOfEachAccount[0].Vecs[idxOfSize].GetType()) 663 outputBatch.Vecs[finalIdxOfComment], err = rsOfMoAccount.Vecs[idxOfComment].Dup(mp) 664 if err != nil { 665 return err 666 } 667 668 for _, bat := range rsOfEachAccount { 669 err = outputBatch.Vecs[finalIdxOfAdminName].UnionOne(bat.Vecs[idxOfAdminName], 0, mp) 670 if err != nil { 671 return err 672 } 673 err = outputBatch.Vecs[finalIdxOfDBCount].UnionOne(bat.Vecs[idxOfDBCount], 0, mp) 674 if err != nil { 675 return err 676 } 677 err = outputBatch.Vecs[finalIdxOfTableCount].UnionOne(bat.Vecs[idxOfTableCount], 0, mp) 678 if err != nil { 679 return err 680 } 681 if err != nil { 682 return err 683 } 684 err = outputBatch.Vecs[finalIdxOfSize].UnionOne(bat.Vecs[idxOfSize], 0, mp) 685 if err != nil { 686 return err 687 } 688 } 689 outputBatch.SetRowCount(rsOfMoAccount.RowCount()) 690 return nil 691 }