mirror of https://github.com/grafana/grafana.git
				
				
				
			Datasource: Fix missing raw SQL query in Query Inspector when query returns zero rows (#67844)
* baldm0mma/issue5799/ add empty frame with all meta data * baldm0mma/issue5799/ add null test * write an integration test around query results with empty rows * baldm0mma/issue5799/ add tests to mssql and postgres * remove use of apparently reserved keyword in mysql8 * baldm0mma/issue5799 * baldm0mma/issue5799/ update tests * baldm0mma/issue5799/ update test structs * baldm0mma/issue5799/ update annotation --------- Co-authored-by: Michael Mandrus <michael.mandrus@grafana.com>
This commit is contained in:
		
							parent
							
								
									8e752439c6
								
							
						
					
					
						commit
						86228ba1a0
					
				|  | @ -1263,6 +1263,50 @@ func TestMSSQL(t *testing.T) { | |||
| 			}) | ||||
| 		}) | ||||
| 	}) | ||||
| 
 | ||||
| 	t.Run("Given an empty table", func(t *testing.T) { | ||||
| 		type emptyObj struct { | ||||
| 			EmptyKey string | ||||
| 			EmptyVal int64 | ||||
| 		} | ||||
| 
 | ||||
| 		exists, err := sess.IsTableExist(emptyObj{}) | ||||
| 		require.NoError(t, err) | ||||
| 		if exists { | ||||
| 			err := sess.DropTable(emptyObj{}) | ||||
| 			require.NoError(t, err) | ||||
| 		} | ||||
| 		err = sess.CreateTable(emptyObj{}) | ||||
| 		require.NoError(t, err) | ||||
| 
 | ||||
| 		t.Run("When no rows are returned, should return an empty frame", func(t *testing.T) { | ||||
| 			query := &backend.QueryDataRequest{ | ||||
| 				Queries: []backend.DataQuery{ | ||||
| 					{ | ||||
| 						JSON: []byte(`{ | ||||
| 							"rawSql": "SELECT empty_key, empty_val FROM empty_obj", | ||||
| 							"format": "table" | ||||
| 						}`), | ||||
| 						RefID: "A", | ||||
| 						TimeRange: backend.TimeRange{ | ||||
| 							From: time.Now(), | ||||
| 							To:   time.Now().Add(1 * time.Minute), | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			} | ||||
| 
 | ||||
| 			resp, err := endpoint.QueryData(context.Background(), query) | ||||
| 			require.NoError(t, err) | ||||
| 			queryResult := resp.Responses["A"] | ||||
| 
 | ||||
| 			frames := queryResult.Frames | ||||
| 			require.Len(t, frames, 1) | ||||
| 			require.Equal(t, 0, frames[0].Rows()) | ||||
| 			require.NotNil(t, frames[0].Fields) | ||||
| 			require.Empty(t, frames[0].Fields) | ||||
| 		}) | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func TestTransformQueryError(t *testing.T) { | ||||
|  |  | |||
|  | @ -1229,6 +1229,50 @@ func TestIntegrationMySQL(t *testing.T) { | |||
| 			}) | ||||
| 		}) | ||||
| 	}) | ||||
| 
 | ||||
| 	t.Run("Given an empty table", func(t *testing.T) { | ||||
| 		type emptyObj struct { | ||||
| 			EmptyKey string | ||||
| 			EmptyVal int64 | ||||
| 		} | ||||
| 
 | ||||
| 		exists, err := sess.IsTableExist(emptyObj{}) | ||||
| 		require.NoError(t, err) | ||||
| 		if exists { | ||||
| 			err := sess.DropTable(emptyObj{}) | ||||
| 			require.NoError(t, err) | ||||
| 		} | ||||
| 		err = sess.CreateTable(emptyObj{}) | ||||
| 		require.NoError(t, err) | ||||
| 
 | ||||
| 		t.Run("When no rows are returned, should return an empty frame", func(t *testing.T) { | ||||
| 			query := &backend.QueryDataRequest{ | ||||
| 				Queries: []backend.DataQuery{ | ||||
| 					{ | ||||
| 						JSON: []byte(`{ | ||||
| 							"rawSql": "SELECT * FROM empty_obj", | ||||
| 							"format": "table" | ||||
| 						}`), | ||||
| 						RefID: "A", | ||||
| 						TimeRange: backend.TimeRange{ | ||||
| 							From: time.Now(), | ||||
| 							To:   time.Now().Add(1 * time.Minute), | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			} | ||||
| 
 | ||||
| 			resp, err := exe.QueryData(context.Background(), query) | ||||
| 			require.NoError(t, err) | ||||
| 			queryResult := resp.Responses["A"] | ||||
| 
 | ||||
| 			frames := queryResult.Frames | ||||
| 			require.Len(t, frames, 1) | ||||
| 			require.Equal(t, 0, frames[0].Rows()) | ||||
| 			require.NotNil(t, frames[0].Fields) | ||||
| 			require.Empty(t, frames[0].Fields) | ||||
| 		}) | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func InitMySQLTestDB(t *testing.T) *xorm.Engine { | ||||
|  |  | |||
|  | @ -1331,6 +1331,50 @@ func TestIntegrationPostgres(t *testing.T) { | |||
| 			}) | ||||
| 		}) | ||||
| 	}) | ||||
| 
 | ||||
| 	t.Run("Given an empty table", func(t *testing.T) { | ||||
| 		type emptyObj struct { | ||||
| 			EmptyKey string | ||||
| 			EmptyVal int64 | ||||
| 		} | ||||
| 
 | ||||
| 		exists, err := sess.IsTableExist(emptyObj{}) | ||||
| 		require.NoError(t, err) | ||||
| 		if exists { | ||||
| 			err := sess.DropTable(emptyObj{}) | ||||
| 			require.NoError(t, err) | ||||
| 		} | ||||
| 		err = sess.CreateTable(emptyObj{}) | ||||
| 		require.NoError(t, err) | ||||
| 
 | ||||
| 		t.Run("When no rows are returned, should return an empty frame", func(t *testing.T) { | ||||
| 			query := &backend.QueryDataRequest{ | ||||
| 				Queries: []backend.DataQuery{ | ||||
| 					{ | ||||
| 						JSON: []byte(`{ | ||||
| 							"rawSql": "SELECT empty_key, empty_val FROM empty_obj", | ||||
| 							"format": "table" | ||||
| 						}`), | ||||
| 						RefID: "A", | ||||
| 						TimeRange: backend.TimeRange{ | ||||
| 							From: time.Now(), | ||||
| 							To:   time.Now().Add(1 * time.Minute), | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			} | ||||
| 
 | ||||
| 			resp, err := exe.QueryData(context.Background(), query) | ||||
| 			require.NoError(t, err) | ||||
| 			queryResult := resp.Responses["A"] | ||||
| 
 | ||||
| 			frames := queryResult.Frames | ||||
| 			require.Len(t, frames, 1) | ||||
| 			require.Equal(t, 0, frames[0].Rows()) | ||||
| 			require.NotNil(t, frames[0].Fields) | ||||
| 			require.Empty(t, frames[0].Fields) | ||||
| 		}) | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func InitPostgresTestDB(t *testing.T) *xorm.Engine { | ||||
|  |  | |||
|  | @ -312,9 +312,13 @@ func (e *DataSourceHandler) executeQuery(query backend.DataQuery, wg *sync.WaitG | |||
| 
 | ||||
| 	frame.Meta.ExecutedQueryString = interpolatedQuery | ||||
| 
 | ||||
| 	// If no rows were returned, no point checking anything else.
 | ||||
| 	// If no rows were returned, clear any previously set `Fields` with a single empty `data.Field` slice.
 | ||||
| 	// Then assign `queryResult.dataResponse.Frames` the current single frame with that single empty Field.
 | ||||
| 	// This assures 1) our visualization doesn't display unwanted empty fields, and also that 2)
 | ||||
| 	// additionally-needed frame data stays intact and is correctly passed to our visulization.
 | ||||
| 	if frame.Rows() == 0 { | ||||
| 		queryResult.dataResponse.Frames = data.Frames{} | ||||
| 		frame.Fields = []*data.Field{} | ||||
| 		queryResult.dataResponse.Frames = data.Frames{frame} | ||||
| 		ch <- queryResult | ||||
| 		return | ||||
| 	} | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue