@@ -16,6 +16,7 @@ import (
1616 "github.com/prometheus/prometheus/util/annotations"
1717 "github.com/prometheus/prometheus/util/httputil"
1818 v1 "github.com/prometheus/prometheus/web/api/v1"
19+ "github.com/thanos-io/promql-engine/logicalplan"
1920 "github.com/weaveworks/common/httpgrpc"
2021
2122 "github.com/cortexproject/cortex/pkg/engine"
@@ -26,7 +27,7 @@ import (
2627
2728type QueryAPI struct {
2829 queryable storage.SampleAndChunkQueryable
29- queryEngine promql .QueryEngine
30+ queryEngine engine .QueryEngine
3031 now func () time.Time
3132 statsRenderer v1.StatsRenderer
3233 logger log.Logger
@@ -35,7 +36,7 @@ type QueryAPI struct {
3536}
3637
3738func NewQueryAPI (
38- qe promql .QueryEngine ,
39+ qe engine .QueryEngine ,
3940 q storage.SampleAndChunkQueryable ,
4041 statsRenderer v1.StatsRenderer ,
4142 logger log.Logger ,
@@ -101,10 +102,29 @@ func (q *QueryAPI) RangeQueryHandler(r *http.Request) (result apiFuncResult) {
101102
102103 ctx = engine .AddEngineTypeToContext (ctx , r )
103104 ctx = querier .AddBlockStoreTypeToContext (ctx , r .Header .Get (querier .BlockStoreTypeHeader ))
104- qry , err := q .queryEngine .NewRangeQuery (ctx , q .queryable , opts , r .FormValue ("query" ), convertMsToTime (start ), convertMsToTime (end ), convertMsToDuration (step ))
105- if err != nil {
106- return invalidParamError (httpgrpc .Errorf (http .StatusBadRequest , "%s" , err .Error ()), "query" )
105+
106+ var qry promql.Query
107+ startTime := convertMsToTime (start )
108+ endTime := convertMsToTime (end )
109+ stepDuration := convertMsToDuration (step )
110+
111+ byteLP := []byte (r .PostFormValue ("plan" ))
112+ if len (byteLP ) != 0 {
113+ logicalPlan , err := logicalplan .Unmarshal (byteLP )
114+ if err != nil {
115+ return apiFuncResult {nil , & apiError {errorInternal , fmt .Errorf ("invalid logical plan: %v" , err )}, nil , nil }
116+ }
117+ qry , err = q .queryEngine .MakeRangeQueryFromPlan (ctx , q .queryable , opts , logicalPlan , startTime , endTime , stepDuration , r .FormValue ("query" ))
118+ if err != nil {
119+ return apiFuncResult {nil , & apiError {errorInternal , fmt .Errorf ("failed to create range query from logical plan: %v" , err )}, nil , nil }
120+ }
121+ } else { // if there is logical plan field is empty, fall back
122+ qry , err = q .queryEngine .NewRangeQuery (ctx , q .queryable , opts , r .FormValue ("query" ), startTime , endTime , stepDuration )
123+ if err != nil {
124+ return invalidParamError (httpgrpc .Errorf (http .StatusBadRequest , "%s" , err .Error ()), "query" )
125+ }
107126 }
127+
108128 // From now on, we must only return with a finalizer in the result (to
109129 // be called by the caller) or call qry.Close ourselves (which is
110130 // required in the case of a panic).
@@ -157,9 +177,25 @@ func (q *QueryAPI) InstantQueryHandler(r *http.Request) (result apiFuncResult) {
157177
158178 ctx = engine .AddEngineTypeToContext (ctx , r )
159179 ctx = querier .AddBlockStoreTypeToContext (ctx , r .Header .Get (querier .BlockStoreTypeHeader ))
160- qry , err := q .queryEngine .NewInstantQuery (ctx , q .queryable , opts , r .FormValue ("query" ), convertMsToTime (ts ))
161- if err != nil {
162- return invalidParamError (httpgrpc .Errorf (http .StatusBadRequest , "%s" , err .Error ()), "query" )
180+
181+ var qry promql.Query
182+ tsTime := convertMsToTime (ts )
183+
184+ byteLP := []byte (r .PostFormValue ("plan" ))
185+ if len (byteLP ) != 0 {
186+ logicalPlan , err := logicalplan .Unmarshal (byteLP )
187+ if err != nil {
188+ return apiFuncResult {nil , & apiError {errorInternal , fmt .Errorf ("invalid logical plan: %v" , err )}, nil , nil }
189+ }
190+ qry , err = q .queryEngine .MakeInstantQueryFromPlan (ctx , q .queryable , opts , logicalPlan , tsTime , r .FormValue ("query" ))
191+ if err != nil {
192+ return apiFuncResult {nil , & apiError {errorInternal , fmt .Errorf ("failed to create instant query from logical plan: %v" , err )}, nil , nil }
193+ }
194+ } else { // if there is logical plan field is empty, fall back
195+ qry , err = q .queryEngine .NewInstantQuery (ctx , q .queryable , opts , r .FormValue ("query" ), tsTime )
196+ if err != nil {
197+ return invalidParamError (httpgrpc .Errorf (http .StatusBadRequest , "%s" , err .Error ()), "query" )
198+ }
163199 }
164200
165201 // From now on, we must only return with a finalizer in the result (to
0 commit comments