mirror of
https://github.com/grafana/grafana.git
synced 2025-09-29 02:23:45 +08:00
Annotations: Fix sql annotation parsing for empty responses (#35367)
* fix sql annotation parsing for empty responses * fix backend when no data returned * add back frontend changes Co-authored-by: Ying WANG <ying.wang@grafana.com>
This commit is contained in:
@ -206,38 +206,37 @@ func (e *dataPlugin) executeQuery(query plugins.DataSubQuery, wg *sync.WaitGroup
|
|||||||
timeRange = *queryContext.TimeRange
|
timeRange = *queryContext.TimeRange
|
||||||
}
|
}
|
||||||
|
|
||||||
|
errAppendDebug := func(frameErr string, err error, query string) {
|
||||||
|
var emptyFrame data.Frame
|
||||||
|
emptyFrame.SetMeta(&data.FrameMeta{
|
||||||
|
ExecutedQueryString: query,
|
||||||
|
})
|
||||||
|
queryResult.Error = fmt.Errorf("%s: %w", frameErr, err)
|
||||||
|
queryResult.Dataframes = plugins.NewDecodedDataFrames(data.Frames{&emptyFrame})
|
||||||
|
ch <- queryResult
|
||||||
|
}
|
||||||
|
|
||||||
// global substitutions
|
// global substitutions
|
||||||
interpolatedQuery, err := Interpolate(query, timeRange, rawSQL)
|
interpolatedQuery, err := Interpolate(query, timeRange, rawSQL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
queryResult.Error = err
|
errAppendDebug("interpolation failed", e.transformQueryError(err), interpolatedQuery)
|
||||||
ch <- queryResult
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// data source specific substitutions
|
// data source specific substitutions
|
||||||
interpolatedQuery, err = e.macroEngine.Interpolate(query, timeRange, interpolatedQuery)
|
interpolatedQuery, err = e.macroEngine.Interpolate(query, timeRange, interpolatedQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
queryResult.Error = err
|
errAppendDebug("interpolation failed", e.transformQueryError(err), interpolatedQuery)
|
||||||
ch <- queryResult
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
errAppendDebug := func(frameErr string, err error) {
|
|
||||||
var emptyFrame data.Frame
|
|
||||||
emptyFrame.SetMeta(&data.FrameMeta{
|
|
||||||
ExecutedQueryString: interpolatedQuery,
|
|
||||||
})
|
|
||||||
queryResult.Error = fmt.Errorf("%s: %w", frameErr, err)
|
|
||||||
queryResult.Dataframes = plugins.NewDecodedDataFrames(data.Frames{&emptyFrame})
|
|
||||||
ch <- queryResult
|
|
||||||
}
|
|
||||||
session := e.engine.NewSession()
|
session := e.engine.NewSession()
|
||||||
defer session.Close()
|
defer session.Close()
|
||||||
db := session.DB()
|
db := session.DB()
|
||||||
|
|
||||||
rows, err := db.Query(interpolatedQuery)
|
rows, err := db.Query(interpolatedQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errAppendDebug("db query error", e.transformQueryError(err))
|
errAppendDebug("db query error", e.transformQueryError(err), interpolatedQuery)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
@ -248,7 +247,7 @@ func (e *dataPlugin) executeQuery(query plugins.DataSubQuery, wg *sync.WaitGroup
|
|||||||
|
|
||||||
qm, err := e.newProcessCfg(query, queryContext, rows, interpolatedQuery)
|
qm, err := e.newProcessCfg(query, queryContext, rows, interpolatedQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errAppendDebug("failed to get configurations", err)
|
errAppendDebug("failed to get configurations", err, interpolatedQuery)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -256,7 +255,7 @@ func (e *dataPlugin) executeQuery(query plugins.DataSubQuery, wg *sync.WaitGroup
|
|||||||
stringConverters := e.queryResultTransformer.GetConverterList()
|
stringConverters := e.queryResultTransformer.GetConverterList()
|
||||||
frame, err := sqlutil.FrameFromRows(rows.Rows, rowLimit, sqlutil.ToConverters(stringConverters...)...)
|
frame, err := sqlutil.FrameFromRows(rows.Rows, rowLimit, sqlutil.ToConverters(stringConverters...)...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errAppendDebug("convert frame from rows error", err)
|
errAppendDebug("convert frame from rows error", err, interpolatedQuery)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,12 +265,14 @@ func (e *dataPlugin) executeQuery(query plugins.DataSubQuery, wg *sync.WaitGroup
|
|||||||
|
|
||||||
// If no rows were returned, no point checking anything else.
|
// If no rows were returned, no point checking anything else.
|
||||||
if frame.Rows() == 0 {
|
if frame.Rows() == 0 {
|
||||||
|
queryResult.Dataframes = plugins.NewDecodedDataFrames(data.Frames{frame})
|
||||||
|
ch <- queryResult
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if qm.timeIndex != -1 {
|
if qm.timeIndex != -1 {
|
||||||
if err := convertSQLTimeColumnToEpochMS(frame, qm.timeIndex); err != nil {
|
if err := convertSQLTimeColumnToEpochMS(frame, qm.timeIndex); err != nil {
|
||||||
errAppendDebug("db convert time column failed", err)
|
errAppendDebug("db convert time column failed", err, interpolatedQuery)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -279,7 +280,7 @@ func (e *dataPlugin) executeQuery(query plugins.DataSubQuery, wg *sync.WaitGroup
|
|||||||
if qm.Format == dataQueryFormatSeries {
|
if qm.Format == dataQueryFormatSeries {
|
||||||
// time series has to have time column
|
// time series has to have time column
|
||||||
if qm.timeIndex == -1 {
|
if qm.timeIndex == -1 {
|
||||||
errAppendDebug("db has no time column", errors.New("no time column found"))
|
errAppendDebug("db has no time column", errors.New("no time column found"), interpolatedQuery)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for i := range qm.columnNames {
|
for i := range qm.columnNames {
|
||||||
@ -289,7 +290,7 @@ func (e *dataPlugin) executeQuery(query plugins.DataSubQuery, wg *sync.WaitGroup
|
|||||||
|
|
||||||
var err error
|
var err error
|
||||||
if frame, err = convertSQLValueColumnToFloat(frame, i); err != nil {
|
if frame, err = convertSQLValueColumnToFloat(frame, i); err != nil {
|
||||||
errAppendDebug("convert value to float failed", err)
|
errAppendDebug("convert value to float failed", err, interpolatedQuery)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -299,7 +300,7 @@ func (e *dataPlugin) executeQuery(query plugins.DataSubQuery, wg *sync.WaitGroup
|
|||||||
var err error
|
var err error
|
||||||
frame, err = data.LongToWide(frame, qm.FillMissing)
|
frame, err = data.LongToWide(frame, qm.FillMissing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errAppendDebug("failed to convert long to wide series when converting from dataframe", err)
|
errAppendDebug("failed to convert long to wide series when converting from dataframe", err, interpolatedQuery)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,9 @@ export default class ResponseParser {
|
|||||||
|
|
||||||
async transformAnnotationResponse(options: any, data: BackendDataSourceResponse): Promise<AnnotationEvent[]> {
|
async transformAnnotationResponse(options: any, data: BackendDataSourceResponse): Promise<AnnotationEvent[]> {
|
||||||
const frames = toDataQueryResponse({ data: data }).data as DataFrame[];
|
const frames = toDataQueryResponse({ data: data }).data as DataFrame[];
|
||||||
|
if (!frames || !frames.length) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
const frame = frames[0];
|
const frame = frames[0];
|
||||||
const timeField = frame.fields.find((f) => f.name === 'time');
|
const timeField = frame.fields.find((f) => f.name === 'time');
|
||||||
|
|
||||||
|
@ -37,6 +37,9 @@ export default class ResponseParser {
|
|||||||
|
|
||||||
async transformAnnotationResponse(options: any, data: BackendDataSourceResponse): Promise<AnnotationEvent[]> {
|
async transformAnnotationResponse(options: any, data: BackendDataSourceResponse): Promise<AnnotationEvent[]> {
|
||||||
const frames = toDataQueryResponse({ data: data }).data as DataFrame[];
|
const frames = toDataQueryResponse({ data: data }).data as DataFrame[];
|
||||||
|
if (!frames || !frames.length) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
const frame = frames[0];
|
const frame = frames[0];
|
||||||
const timeField = frame.fields.find((f) => f.name === 'time' || f.name === 'time_sec');
|
const timeField = frame.fields.find((f) => f.name === 'time' || f.name === 'time_sec');
|
||||||
|
|
||||||
|
@ -37,6 +37,9 @@ export default class ResponseParser {
|
|||||||
|
|
||||||
async transformAnnotationResponse(options: any, data: BackendDataSourceResponse): Promise<AnnotationEvent[]> {
|
async transformAnnotationResponse(options: any, data: BackendDataSourceResponse): Promise<AnnotationEvent[]> {
|
||||||
const frames = toDataQueryResponse({ data: data }).data as DataFrame[];
|
const frames = toDataQueryResponse({ data: data }).data as DataFrame[];
|
||||||
|
if (!frames || !frames.length) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
const frame = frames[0];
|
const frame = frames[0];
|
||||||
const timeField = frame.fields.find((f) => f.name === 'time');
|
const timeField = frame.fields.find((f) => f.name === 'time');
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user