1use std::sync::Arc;
16use std::time::SystemTime;
17
18use auth::PermissionTableTarget;
19use catalog::information_schema::TABLES;
20use client::OutputData;
21use common_catalog::consts::INFORMATION_SCHEMA_NAME;
22use common_catalog::format_full_table_name;
23use common_recordbatch::util;
24use common_telemetry::tracing;
25use datafusion_expr::LogicalPlan;
26use promql_parser::label::{Matcher, Matchers};
27use query::promql;
28use query::promql::planner::PromPlanner;
29use servers::prometheus;
30use session::context::QueryContextRef;
31use snafu::{OptionExt, ResultExt};
32
33use crate::error::{
34 CatalogSnafu, CollectRecordbatchSnafu, ExecLogicalPlanSnafu,
35 PrometheusLabelValuesQueryPlanSnafu, PrometheusMetricNamesQueryPlanSnafu, ReadTableSnafu,
36 Result, TableNotFoundSnafu, TableSnafu,
37};
38use crate::instance::Instance;
39
40pub(super) fn remove_output_sort(plan: LogicalPlan) -> LogicalPlan {
45 match plan {
46 LogicalPlan::Sort(sort) if sort.fetch.is_none() => Arc::unwrap_or_clone(sort.input),
47 LogicalPlan::Projection(mut projection) => {
48 projection.input = Arc::new(remove_output_sort(Arc::unwrap_or_clone(projection.input)));
49 LogicalPlan::Projection(projection)
50 }
51 plan => plan,
52 }
53}
54
55impl Instance {
56 #[tracing::instrument(skip_all)]
58 pub(crate) async fn handle_query_metric_names(
59 &self,
60 matchers: Vec<Matcher>,
61 schema: &str,
62 ctx: &QueryContextRef,
63 ) -> Result<Vec<String>> {
64 let _timer = crate::metrics::PROMQL_QUERY_METRICS_ELAPSED
65 .with_label_values(&[ctx.get_db_string().as_str()])
66 .start_timer();
67
68 let table = self
69 .catalog_manager
70 .table(
71 ctx.current_catalog(),
72 INFORMATION_SCHEMA_NAME,
73 TABLES,
74 Some(ctx),
75 )
76 .await
77 .context(CatalogSnafu)?
78 .with_context(|| TableNotFoundSnafu {
79 table_name: "greptime.information_schema.tables",
80 })?;
81
82 let dataframe = self
83 .query_engine
84 .read_table(table)
85 .with_context(|_| ReadTableSnafu {
86 table_name: "greptime.information_schema.tables",
87 })?;
88
89 let logical_plan =
90 prometheus::metric_name_matchers_to_plan(dataframe, matchers, schema, ctx)
91 .context(PrometheusMetricNamesQueryPlanSnafu)?;
92
93 let results = self
94 .query_engine
95 .execute(logical_plan, ctx.clone())
96 .await
97 .context(ExecLogicalPlanSnafu)?;
98
99 let batches = match results.data {
100 OutputData::Stream(stream) => util::collect(stream)
101 .await
102 .context(CollectRecordbatchSnafu)?,
103 OutputData::RecordBatches(rbs) => rbs.take(),
104 _ => unreachable!("should not happen"),
105 };
106
107 let mut results = Vec::with_capacity(batches.iter().map(|b| b.num_rows()).sum());
108
109 for batch in batches {
110 batch
112 .iter_column_as_string(0)
113 .flatten()
114 .for_each(|x| results.push(x))
115 }
116
117 Ok(results)
118 }
119
120 #[tracing::instrument(skip_all)]
122 pub(crate) async fn handle_query_label_values(
123 &self,
124 target: PermissionTableTarget,
125 label_name: String,
126 matchers: Vec<Matcher>,
127 start: SystemTime,
128 end: SystemTime,
129 ctx: &QueryContextRef,
130 ) -> Result<Vec<String>> {
131 let full_table_name =
132 format_full_table_name(&target.catalog, &target.schema, &target.table);
133 let table = self
134 .catalog_manager
135 .table(&target.catalog, &target.schema, &target.table, Some(ctx))
136 .await
137 .context(CatalogSnafu)?
138 .with_context(|| TableNotFoundSnafu {
139 table_name: full_table_name.clone(),
140 })?;
141
142 if table.schema().column_schema_by_name(&label_name).is_none() {
145 return table::error::ColumnNotExistsSnafu {
146 column_name: label_name,
147 table_name: full_table_name,
148 }
149 .fail()
150 .context(TableSnafu);
151 }
152
153 let dataframe = self
154 .query_engine
155 .read_table(table.clone())
156 .with_context(|_| ReadTableSnafu {
157 table_name: full_table_name,
158 })?;
159
160 let scan_plan = dataframe.into_unoptimized_plan();
161 let filter_conditions =
162 PromPlanner::matchers_to_expr(Matchers::new(matchers), scan_plan.schema())
163 .context(PrometheusLabelValuesQueryPlanSnafu)?;
164 let logical_plan = promql::label_values::rewrite_label_values_query(
165 table,
166 scan_plan,
167 filter_conditions,
168 label_name,
169 start,
170 end,
171 )
172 .context(PrometheusLabelValuesQueryPlanSnafu)?;
173
174 let results = self
175 .query_engine
176 .execute(logical_plan, ctx.clone())
177 .await
178 .context(ExecLogicalPlanSnafu)?;
179
180 let batches = match results.data {
181 OutputData::Stream(stream) => util::collect(stream)
182 .await
183 .context(CollectRecordbatchSnafu)?,
184 OutputData::RecordBatches(rbs) => rbs.take(),
185 _ => unreachable!("should not happen"),
186 };
187
188 let mut results = Vec::with_capacity(batches.iter().map(|b| b.num_rows()).sum());
189 for batch in batches {
190 batch
192 .iter_column_as_string(0)
193 .flatten()
194 .for_each(|x| results.push(x))
195 }
196
197 Ok(results)
198 }
199}
200
201#[cfg(test)]
202mod tests {
203 use datafusion::arrow::array::Int64Array;
204 use datafusion::prelude::{SessionConfig, SessionContext};
205 use datafusion_expr::{LogicalPlanBuilder, Sort, col, lit};
206
207 use super::*;
208
209 #[tokio::test]
210 async fn remove_output_sort_keeps_schema_and_row_selection() {
211 let input =
212 LogicalPlanBuilder::values(vec![vec![lit(3_i64)], vec![lit(1_i64)], vec![lit(2_i64)]])
213 .unwrap()
214 .build()
215 .unwrap();
216 let sort = Sort {
217 expr: vec![col("column1").sort(true, false)],
218 input: Arc::new(input),
219 fetch: None,
220 };
221 let projected = LogicalPlanBuilder::from(LogicalPlan::Sort(sort.clone()))
222 .project(vec![col("column1").alias("sample")])
223 .unwrap()
224 .project(vec![col("sample")])
225 .unwrap()
226 .build()
227 .unwrap();
228 let limited = LogicalPlanBuilder::from(LogicalPlan::Sort(sort.clone()))
230 .limit(0, Some(2))
231 .unwrap()
232 .sort(vec![col("column1").sort(false, false)])
233 .unwrap()
234 .build()
235 .unwrap();
236 let fetched = LogicalPlan::Sort(Sort {
237 fetch: Some(2),
238 ..sort.clone()
239 });
240
241 let context =
242 SessionContext::new_with_config(SessionConfig::new().with_target_partitions(1));
243 for (name, plan, expected) in [
244 ("root", LogicalPlan::Sort(sort), vec![3, 1, 2]),
245 ("projection", projected, vec![3, 1, 2]),
246 ("sort below limit", limited, vec![1, 2]),
247 ("fetch", fetched, vec![1, 2]),
248 ] {
249 let schema = plan.schema().clone();
250 let plan = remove_output_sort(plan);
251 assert_eq!(plan.schema(), &schema, "{name}");
252 let output = context
253 .execute_logical_plan(plan)
254 .await
255 .unwrap()
256 .collect()
257 .await
258 .unwrap();
259 let values = output
260 .iter()
261 .flat_map(|batch| {
262 batch
263 .column(0)
264 .as_any()
265 .downcast_ref::<Int64Array>()
266 .unwrap()
267 .values()
268 .iter()
269 .copied()
270 })
271 .collect::<Vec<_>>();
272 assert_eq!(values, expected, "{name}");
273 }
274 }
275}