Files
steampipe/pkg/query/queryresult/scan_metadata.go
kaidaguerre 07782a2b13 Adds support for verbose timing information. Closes #4237. Closes #4244
- JSON output format has changed to move the rows to under a `rows` property, with timing information under the `metadata` property
- Update timing display to show rows returned and rows fetched, as well as adding verbose mode which lists all scans
- Use enums for output mode and timing mode - timing is now either `on`, `off` or `verbose`
- Bugfix: ensure error is returned from ExecuteSystemClientCall. Closes #4246
2024-04-17 10:12:17 +01:00

105 lines
3.5 KiB
Go

package queryresult
import (
"github.com/turbot/steampipe-plugin-sdk/v5/grpc"
"github.com/turbot/steampipe-plugin-sdk/v5/grpc/proto"
"time"
)
type ScanMetadataRow struct {
// the fields of this struct need to be public since these are populated by pgx using RowsToStruct
Connection string `db:"connection,optional" json:"connection"`
Table string `db:"table" json:"table"`
CacheHit bool `db:"cache_hit" json:"cache_hit"`
RowsFetched int64 `db:"rows_fetched" json:"rows_fetched"`
HydrateCalls int64 `db:"hydrate_calls" json:"hydrate_calls"`
StartTime time.Time `db:"start_time" json:"start_time"`
DurationMs int64 `db:"duration_ms" json:"duration_ms"`
Columns []string `db:"columns" json:"columns"`
Limit *int64 `db:"limit" json:"limit,omitempty"`
Quals []grpc.SerializableQual `db:"quals" json:"quals,omitempty"`
}
func NewScanMetadataRow(connection string, table string, columns []string, quals map[string]*proto.Quals, startTime time.Time, diration time.Duration, limit int64, m *proto.QueryMetadata) ScanMetadataRow {
res := ScanMetadataRow{
Connection: connection,
Table: table,
StartTime: startTime,
DurationMs: diration.Milliseconds(),
Columns: columns,
Quals: grpc.QualMapToSerializableSlice(quals),
}
if limit == -1 {
res.Limit = nil
} else {
res.Limit = &limit
}
if m != nil {
res.CacheHit = m.CacheHit
res.RowsFetched = m.RowsFetched
res.HydrateCalls = m.HydrateCalls
}
return res
}
// AsResultRow returns the ScanMetadata as a map[string]interface which can be returned as a query result
func (m ScanMetadataRow) AsResultRow() map[string]any {
res := map[string]any{
"connection": m.Connection,
"table": m.Table,
"cache_hit": m.CacheHit,
"rows_fetched": m.RowsFetched,
"hydrate_calls": m.HydrateCalls,
"start_time": m.StartTime,
"duration_ms": m.DurationMs,
"columns": m.Columns,
"quals": m.Quals,
}
// explicitly set limit to nil if needed (otherwise postgres returns `1`)
if m.Limit != nil {
res["limit"] = *m.Limit
} else {
res["limit"] = nil // Explicitly set nil
}
return res
}
type QueryRowSummary struct {
UncachedRowsFetched int64 `db:"uncached_rows_fetched" json:"uncached_rows_fetched"`
CachedRowsFetched int64 `db:"cached_rows_fetched" json:"cached_rows_fetched"`
HydrateCalls int64 `db:"hydrate_calls" json:"hydrate_calls"`
ScanCount int64 `db:"scan_count" json:"scan_count"`
ConnectionCount int64 `db:"connection_count" json:"connection_count"`
// map connections to the scans
connections map[string]struct{}
}
func NewQueryRowSummary() *QueryRowSummary {
return &QueryRowSummary{
connections: make(map[string]struct{}),
}
}
func (s *QueryRowSummary) AsResultRow() map[string]any {
res := map[string]any{
"uncached_rows_fetched": s.UncachedRowsFetched,
"cached_rows_fetched": s.CachedRowsFetched,
"hydrate_calls": s.HydrateCalls,
"scan_count": s.ScanCount,
"connection_count": s.ConnectionCount,
}
return res
}
func (s *QueryRowSummary) Update(m ScanMetadataRow) {
if m.CacheHit {
s.CachedRowsFetched += m.RowsFetched
} else {
s.UncachedRowsFetched += m.RowsFetched
}
s.HydrateCalls += m.HydrateCalls
s.ScanCount++
s.connections[m.Connection] = struct{}{}
s.ConnectionCount = int64(len(s.connections))
}