diff --git a/pkg/services/searchV2/index.go b/pkg/services/searchV2/index.go index 7657bd9f115..474836f9dca 100644 --- a/pkg/services/searchV2/index.go +++ b/pkg/services/searchV2/index.go @@ -846,30 +846,101 @@ func (l sqlDashboardLoader) loadAllDashboards(ctx context.Context, limit int, or dashboardQuerySpan.SetAttributes("dashboardUID", dashboardUID, attribute.Key("dashboardUID").String(dashboardUID)) dashboardQuerySpan.SetAttributes("lastID", lastID, attribute.Key("lastID").Int64(lastID)) - rows := make([]*dashboardQueryResult, 0) + var slices [][]string err := l.sql.WithDbSession(dashboardQueryCtx, func(sess *db.Session) error { - sess.Table("dashboard"). - Where("org_id = ?", orgID) + sql := "select id, uid, is_folder, folder_id, slug, data, created, updated from dashboard where org_id = ?" + sqlAndArgs := []interface{}{"", orgID} if lastID > 0 { - sess.Where("id > ?", lastID) + sql += " AND id > ?" + sqlAndArgs = append(sqlAndArgs, lastID) } if dashboardUID != "" { - sess.Where("uid = ?", dashboardUID) + sql += " AND uid = ?" + sqlAndArgs = append(sqlAndArgs, dashboardUID) } - sess.Cols("id", "uid", "is_folder", "folder_id", "data", "slug", "created", "updated") + sql += " order by id asc" + sql += " limit ?" + sqlAndArgs = append(sqlAndArgs, limit) - sess.OrderBy("id ASC") - sess.Limit(limit) - - return sess.Find(&rows) + sqlAndArgs[0] = sql + output, err := sess.QuerySliceString(sqlAndArgs...) + slices = output + return err }) - dashboardQuerySpan.End() + dashboardQuerySpan.SetAttributes("dashboardCount", len(slices), attribute.Key("dashboardCount").Int(len(slices))) - if err != nil || len(rows) < limit || dashboardUID != "" { + if err != nil || slices == nil { + dashboardQuerySpan.End() + ch <- &dashboardsRes{ + dashboards: nil, + err: err, + } + break + } + + rows := make([]*dashboardQueryResult, len(slices)) + var parsingErr error + for i := range slices { + if len(slices[i]) < 8 { + parsingErr = fmt.Errorf("expected the dashboard row at index %d to contain 8 elements, has %d. lastID: %d", i, len(slices[i]), lastID) + break + } + + id, err := strconv.ParseInt(slices[i][0], 10, 64) + if err != nil { + parsingErr = err + break + } + uid := slices[i][1] + isFolder := false + if slices[i][2] == "1" { + isFolder = true + } + + folderID, err := strconv.ParseInt(slices[i][3], 10, 64) + if err != nil { + parsingErr = err + break + } + + // xorm/session_query.go::value2String() uses `time.RFC3339Nano` to format the time type + created, err := time.Parse(time.RFC3339Nano, slices[i][6]) + if err != nil { + parsingErr = err + break + } + updated, err := time.Parse(time.RFC3339Nano, slices[i][7]) + if err != nil { + parsingErr = err + break + } + + rows[i] = &dashboardQueryResult{ + Id: id, + Uid: uid, + IsFolder: isFolder, + FolderID: folderID, + Slug: slices[i][4], + Data: []byte(slices[i][5]), + Created: created, + Updated: updated, + } + } + + dashboardQuerySpan.End() + if parsingErr != nil { + ch <- &dashboardsRes{ + dashboards: nil, + err: parsingErr, + } + break + } + + if len(rows) < limit || dashboardUID != "" { ch <- &dashboardsRes{ dashboards: rows, err: err, @@ -939,7 +1010,7 @@ func (l sqlDashboardLoader) LoadDashboards(ctx context.Context, orgID int64, das for { res, ok := <-dashboardsChannel if res != nil && res.err != nil { - l.logger.Error("Error when loading dashboards", "error", err, "orgID", orgID, "dashboardUID", dashboardUID) + l.logger.Error("Error when loading dashboards", "error", res.err, "orgID", orgID, "dashboardUID", dashboardUID) break } @@ -949,14 +1020,14 @@ func (l sqlDashboardLoader) LoadDashboards(ctx context.Context, orgID int64, das rows := res.dashboards - _, readDashboardSpan := l.tracer.Start(ctx, "sqlDashboardLoader readDashboard") + readDashboardCtx, readDashboardSpan := l.tracer.Start(ctx, "sqlDashboardLoader readDashboard") readDashboardSpan.SetAttributes("orgID", orgID, attribute.Key("orgID").Int64(orgID)) readDashboardSpan.SetAttributes("dashboardCount", len(rows), attribute.Key("dashboardCount").Int(len(rows))) reader := kdash.NewStaticDashboardSummaryBuilder(lookup, false) for _, row := range rows { - summary, _, err := reader(ctx, row.Uid, row.Data) + summary, _, err := reader(readDashboardCtx, row.Uid, row.Data) if err != nil { l.logger.Warn("Error indexing dashboard data", "error", err, "dashboardId", row.Id, "dashboardSlug", row.Slug) // But append info anyway for now, since we possibly extracted useful information.