1use std::pin::Pin;
16use std::sync::Arc;
17use std::time::Instant;
18
19use api::helper::from_pb_time_ranges;
20use api::v1::ddl_request::{Expr as DdlExpr, Expr};
21use api::v1::greptime_request::Request;
22use api::v1::query_request::Query;
23use api::v1::{
24 DeleteRequests, DropFlowExpr, InsertIntoPlan, InsertRequests, RowDeleteRequests,
25 RowInsertRequests,
26};
27use async_stream::try_stream;
28use async_trait::async_trait;
29use auth::{PermissionChecker, PermissionCheckerRef, PermissionReq};
30use common_error::ext::BoxedError;
31use common_grpc::flight::do_put::DoPutResponse;
32use common_query::Output;
33use common_query::logical_plan::add_insert_to_logical_plan;
34use common_telemetry::tracing::{self};
35use datafusion::datasource::DefaultTableSource;
36use futures::Stream;
37use futures::stream::StreamExt;
38use query::parser::PromQuery;
39use servers::error as server_error;
40use servers::http::prom_store::PHYSICAL_TABLE_PARAM;
41use servers::interceptor::{GrpcQueryInterceptor, GrpcQueryInterceptorRef};
42use servers::query_handler::grpc::GrpcQueryHandler;
43use session::context::QueryContextRef;
44use snafu::{OptionExt, ResultExt, ensure};
45use table::TableRef;
46use table::table::adapter::DfTableProviderAdapter;
47use table::table_name::TableName;
48
49use crate::error::{
50 CatalogSnafu, DataFusionSnafu, Error, ExternalSnafu, IncompleteGrpcRequestSnafu,
51 NotSupportedSnafu, PermissionSnafu, PlanStatementSnafu, Result,
52 SubstraitDecodeLogicalPlanSnafu, TableNotFoundSnafu, TableOperationSnafu,
53};
54use crate::instance::{Instance, attach_timer};
55use crate::metrics::{
56 GRPC_HANDLE_PLAN_ELAPSED, GRPC_HANDLE_PROMQL_ELAPSED, GRPC_HANDLE_SQL_ELAPSED,
57};
58
59#[async_trait]
60impl GrpcQueryHandler for Instance {
61 async fn do_query(
62 &self,
63 request: Request,
64 ctx: QueryContextRef,
65 ) -> server_error::Result<Output> {
66 let result: Result<Output> = async {
67 let interceptor_ref = self.plugins.get::<GrpcQueryInterceptorRef<Error>>();
68 let interceptor = interceptor_ref.as_ref();
69 interceptor.pre_execute(&request, ctx.clone())?;
70
71 self.plugins
72 .get::<PermissionCheckerRef>()
73 .as_ref()
74 .check_permission_with_context(
75 ctx.current_user(),
76 PermissionReq::GrpcRequest(&request),
77 Some(&ctx.current_schema()),
78 )
79 .context(PermissionSnafu)?;
80
81 let output = match request {
82 Request::Inserts(requests) => self.handle_inserts(requests, ctx.clone()).await?,
83 Request::RowInserts(requests) => match ctx.extension(PHYSICAL_TABLE_PARAM) {
84 Some(physical_table) => {
85 self.handle_metric_row_inserts(
86 requests,
87 ctx.clone(),
88 physical_table.to_string(),
89 )
90 .await?
91 }
92 None => {
93 self.handle_row_inserts(requests, ctx.clone(), false, false)
94 .await?
95 }
96 },
97 Request::Deletes(requests) => self.handle_deletes(requests, ctx.clone()).await?,
98 Request::RowDeletes(requests) => self.handle_row_deletes(requests, ctx.clone()).await?,
99 Request::Query(query_request) => {
100 let query = query_request.query.context(IncompleteGrpcRequestSnafu {
101 err_msg: "Missing field 'QueryRequest.query'",
102 })?;
103 match query {
104 Query::Sql(sql) => {
105 let timer = GRPC_HANDLE_SQL_ELAPSED.start_timer();
106 let mut result = self.do_query_inner(&sql, ctx.clone()).await;
107 ensure!(
108 result.len() == 1,
109 NotSupportedSnafu {
110 feat: "execute multiple statements in SQL query string through GRPC interface"
111 }
112 );
113 let output = result.remove(0)?;
114 attach_timer(output, timer)
115 }
116 Query::LogicalPlan(plan) => {
117 let timer = GRPC_HANDLE_PLAN_ELAPSED.start_timer();
119
120 let plan_decoder = self
122 .query_engine()
123 .engine_context(ctx.clone())
124 .new_plan_decoder()
125 .context(PlanStatementSnafu)?;
126
127 let dummy_catalog_list =
128 Arc::new(catalog::table_source::dummy_catalog::DummyCatalogList::new_with_query_ctx(
129 self.catalog_manager().clone(),
130 ctx.clone(),
131 ));
132
133 let logical_plan = plan_decoder
134 .decode(bytes::Bytes::from(plan), dummy_catalog_list, true)
135 .await
136 .context(SubstraitDecodeLogicalPlanSnafu)?;
137 let output =
138 self.do_exec_plan_inner(logical_plan, None, ctx.clone()).await?;
139
140 attach_timer(output, timer)
141 }
142 Query::InsertIntoPlan(insert) => {
143 self.handle_insert_plan(insert, ctx.clone()).await?
144 }
145 Query::PromRangeQuery(promql) => {
146 let timer = GRPC_HANDLE_PROMQL_ELAPSED.start_timer();
147 let prom_query = PromQuery {
148 query: promql.query,
149 start: promql.start,
150 end: promql.end,
151 step: promql.step,
152 lookback: promql.lookback,
153 alias: None,
154 };
155 let mut result =
156 self.do_promql_query_inner(&prom_query, ctx.clone()).await;
157 ensure!(
158 result.len() == 1,
159 NotSupportedSnafu {
160 feat: "execute multiple statements in PromQL query string through GRPC interface"
161 }
162 );
163 let output = result.remove(0)?;
164 attach_timer(output, timer)
165 }
166 }
167 }
168 Request::Ddl(request) => {
169 let mut expr = request.expr.context(IncompleteGrpcRequestSnafu {
170 err_msg: "'expr' is absent in DDL request",
171 })?;
172
173 fill_catalog_and_schema_from_context(&mut expr, &ctx);
174
175 match expr {
176 DdlExpr::CreateTable(mut expr) => {
177 let _ = self
178 .statement_executor
179 .create_table_inner(&mut expr, None, ctx.clone())
180 .await?;
181 Output::new_with_affected_rows(0)
182 }
183 DdlExpr::AlterDatabase(expr) => {
184 let _ = self
185 .statement_executor
186 .alter_database_inner(expr, ctx.clone())
187 .await?;
188 Output::new_with_affected_rows(0)
189 }
190 DdlExpr::AlterTable(expr) => {
191 self.statement_executor
192 .alter_table_inner(expr, ctx.clone())
193 .await?
194 }
195 DdlExpr::CreateDatabase(expr) => {
196 self.statement_executor
197 .create_database(
198 &expr.schema_name,
199 expr.create_if_not_exists,
200 expr.options,
201 ctx.clone(),
202 )
203 .await?
204 }
205 DdlExpr::DropTable(expr) => {
206 let table_name =
207 TableName::new(&expr.catalog_name, &expr.schema_name, &expr.table_name);
208 self.statement_executor
209 .drop_table(table_name, expr.drop_if_exists, ctx.clone())
210 .await?
211 }
212 DdlExpr::TruncateTable(expr) => {
213 let table_name =
214 TableName::new(&expr.catalog_name, &expr.schema_name, &expr.table_name);
215 let time_ranges = from_pb_time_ranges(expr.time_ranges.unwrap_or_default())
216 .map_err(BoxedError::new)
217 .context(ExternalSnafu)?;
218 self.statement_executor
219 .truncate_table(table_name, time_ranges, ctx.clone())
220 .await?
221 }
222 DdlExpr::CreateFlow(expr) => {
223 self.statement_executor
224 .create_flow_inner(expr, ctx.clone())
225 .await?
226 }
227 DdlExpr::DropFlow(DropFlowExpr {
228 catalog_name,
229 flow_name,
230 drop_if_exists,
231 ..
232 }) => {
233 self.statement_executor
234 .drop_flow(catalog_name, flow_name, drop_if_exists, ctx.clone())
235 .await?
236 }
237 DdlExpr::CreateView(expr) => {
238 let _ = self
239 .statement_executor
240 .create_view_by_expr(expr, ctx.clone())
241 .await?;
242
243 Output::new_with_affected_rows(0)
244 }
245 DdlExpr::DropView(_) => {
246 todo!("implemented in the following PR")
247 }
248 DdlExpr::CommentOn(expr) => {
249 self.statement_executor
250 .comment_by_expr(expr, ctx.clone())
251 .await?
252 }
253 }
254 }
255 };
256
257 let output = interceptor.post_execute(output, ctx)?;
258 Ok(output)
259 }
260 .await;
261
262 result
263 .map_err(BoxedError::new)
264 .context(server_error::ExecuteGrpcQuerySnafu)
265 }
266
267 fn handle_put_record_batch_stream(
268 &self,
269 stream: servers::grpc::flight::PutRecordBatchRequestStream,
270 ctx: QueryContextRef,
271 ) -> Pin<Box<dyn Stream<Item = server_error::Result<DoPutResponse>> + Send>> {
272 Box::pin(
273 self.handle_put_record_batch_stream_inner(stream, ctx)
274 .map(|result| {
275 result
276 .map_err(BoxedError::new)
277 .context(server_error::ExecuteGrpcRequestSnafu)
278 }),
279 )
280 }
281}
282
283fn fill_catalog_and_schema_from_context(ddl_expr: &mut DdlExpr, ctx: &QueryContextRef) {
284 let catalog = ctx.current_catalog();
285 let schema = ctx.current_schema();
286
287 macro_rules! check_and_fill {
288 ($expr:ident) => {
289 if $expr.catalog_name.is_empty() {
290 $expr.catalog_name = catalog.to_string();
291 }
292 if $expr.schema_name.is_empty() {
293 $expr.schema_name = schema.to_string();
294 }
295 };
296 }
297
298 match ddl_expr {
299 Expr::CreateDatabase(_) | Expr::AlterDatabase(_) => { }
300 Expr::CreateTable(expr) => {
301 check_and_fill!(expr);
302 }
303 Expr::AlterTable(expr) => {
304 check_and_fill!(expr);
305 }
306 Expr::DropTable(expr) => {
307 check_and_fill!(expr);
308 }
309 Expr::TruncateTable(expr) => {
310 check_and_fill!(expr);
311 }
312 Expr::CreateFlow(expr) => {
313 if expr.catalog_name.is_empty() {
314 expr.catalog_name = catalog.to_string();
315 }
316 }
317 Expr::DropFlow(expr) => {
318 if expr.catalog_name.is_empty() {
319 expr.catalog_name = catalog.to_string();
320 }
321 }
322 Expr::CreateView(expr) => {
323 check_and_fill!(expr);
324 }
325 Expr::DropView(expr) => {
326 check_and_fill!(expr);
327 }
328 Expr::CommentOn(expr) => {
329 check_and_fill!(expr);
330 }
331 }
332}
333
334impl Instance {
335 fn handle_put_record_batch_stream_inner(
336 &self,
337 mut stream: servers::grpc::flight::PutRecordBatchRequestStream,
338 ctx: QueryContextRef,
339 ) -> Pin<Box<dyn Stream<Item = Result<DoPutResponse>> + Send>> {
340 let catalog_manager = self.catalog_manager().clone();
342 let plugins = self.plugins.clone();
343 let inserter = self.inserter.clone();
344 let ctx = ctx.clone();
345 let mut table_ref: Option<TableRef> = None;
346 let mut table_checked = false;
347
348 Box::pin(try_stream! {
349 while let Some(request_result) = stream.next().await {
351 let request = request_result.map_err(|e| {
352 let error_msg = format!("Stream error: {:?}", e);
353 IncompleteGrpcRequestSnafu { err_msg: error_msg }.build()
354 })?;
355
356 if !table_checked {
358 let table_name = &request.table_name;
359
360 plugins
361 .get::<PermissionCheckerRef>()
362 .as_ref()
363 .check_permission(
364 ctx.current_user(),
365 PermissionReq::BulkInsert {
366 catalog: &table_name.catalog_name,
367 schema: &table_name.schema_name,
368 table: &table_name.table_name,
369 },
370 )
371 .context(PermissionSnafu)?;
372
373 table_ref = Some(
375 catalog_manager
376 .table(
377 &table_name.catalog_name,
378 &table_name.schema_name,
379 &table_name.table_name,
380 None,
381 )
382 .await
383 .context(CatalogSnafu)?
384 .with_context(|| TableNotFoundSnafu {
385 table_name: table_name.to_string(),
386 })?,
387 );
388
389 let interceptor_ref = plugins.get::<GrpcQueryInterceptorRef<Error>>();
391 let interceptor = interceptor_ref.as_ref();
392 interceptor.pre_bulk_insert(table_ref.clone().unwrap(), ctx.clone())?;
393
394 table_checked = true;
395 }
396
397 let request_id = request.request_id;
398 let start = Instant::now();
399 let rows = inserter
400 .handle_bulk_insert(
401 table_ref.clone().unwrap(),
402 request.flight_data,
403 request.record_batch,
404 request.schema_bytes,
405 )
406 .await
407 .context(TableOperationSnafu)?;
408 let elapsed_secs = start.elapsed().as_secs_f64();
409 yield DoPutResponse::new(request_id, rows, elapsed_secs);
410 }
411 })
412 }
413
414 async fn handle_insert_plan(
415 &self,
416 insert: InsertIntoPlan,
417 ctx: QueryContextRef,
418 ) -> Result<Output> {
419 let timer = GRPC_HANDLE_PLAN_ELAPSED.start_timer();
420 let table_name = insert.table_name.context(IncompleteGrpcRequestSnafu {
421 err_msg: "'table_name' is absent in InsertIntoPlan",
422 })?;
423
424 let plan_decoder = self
426 .query_engine()
427 .engine_context(ctx.clone())
428 .new_plan_decoder()
429 .context(PlanStatementSnafu)?;
430
431 let dummy_catalog_list = Arc::new(
432 catalog::table_source::dummy_catalog::DummyCatalogList::new_with_query_ctx(
433 self.catalog_manager().clone(),
434 ctx.clone(),
435 ),
436 );
437
438 let logical_plan = plan_decoder
440 .decode(
441 bytes::Bytes::from(insert.logical_plan),
442 dummy_catalog_list,
443 false,
444 )
445 .await
446 .context(SubstraitDecodeLogicalPlanSnafu)?;
447
448 let table = self
449 .catalog_manager()
450 .table(
451 &table_name.catalog_name,
452 &table_name.schema_name,
453 &table_name.table_name,
454 None,
455 )
456 .await
457 .context(CatalogSnafu)?
458 .with_context(|| TableNotFoundSnafu {
459 table_name: [
460 table_name.catalog_name.clone(),
461 table_name.schema_name.clone(),
462 table_name.table_name.clone(),
463 ]
464 .join("."),
465 })?;
466 let table_provider = Arc::new(DfTableProviderAdapter::new(table));
467 let table_source = Arc::new(DefaultTableSource::new(table_provider));
468
469 let insert_into = add_insert_to_logical_plan(table_name, table_source, logical_plan)
470 .context(SubstraitDecodeLogicalPlanSnafu)?;
471
472 let engine_ctx = self.query_engine().engine_context(ctx.clone());
473 let state = engine_ctx.state();
474 let analyzed_plan = state
476 .analyzer()
477 .execute_and_check(insert_into, state.config_options(), |_, _| {})
478 .context(DataFusionSnafu)?;
479
480 let optimized_plan = state.optimize(&analyzed_plan).context(DataFusionSnafu)?;
482
483 let output = self
484 .do_exec_plan_inner(optimized_plan, None, ctx.clone())
485 .await?;
486
487 Ok(attach_timer(output, timer))
488 }
489 #[tracing::instrument(skip_all)]
490 pub async fn handle_inserts(
491 &self,
492 requests: InsertRequests,
493 ctx: QueryContextRef,
494 ) -> Result<Output> {
495 self.inserter
496 .handle_column_inserts(requests, ctx, self.statement_executor.as_ref())
497 .await
498 .context(TableOperationSnafu)
499 }
500
501 #[tracing::instrument(skip_all)]
502 pub async fn handle_row_inserts(
503 &self,
504 requests: RowInsertRequests,
505 ctx: QueryContextRef,
506 accommodate_existing_schema: bool,
507 is_single_value: bool,
508 ) -> Result<Output> {
509 self.inserter
510 .handle_row_inserts(
511 requests,
512 ctx,
513 self.statement_executor.as_ref(),
514 accommodate_existing_schema,
515 is_single_value,
516 )
517 .await
518 .context(TableOperationSnafu)
519 }
520
521 #[tracing::instrument(skip_all)]
522 pub async fn handle_influx_row_inserts(
523 &self,
524 requests: RowInsertRequests,
525 ctx: QueryContextRef,
526 ) -> Result<Output> {
527 self.inserter
528 .handle_last_non_null_inserts(
529 requests,
530 ctx,
531 self.statement_executor.as_ref(),
532 true,
533 false,
535 )
536 .await
537 .context(TableOperationSnafu)
538 }
539
540 #[tracing::instrument(skip_all)]
541 pub async fn handle_metric_row_inserts(
542 &self,
543 requests: RowInsertRequests,
544 ctx: QueryContextRef,
545 physical_table: String,
546 ) -> Result<Output> {
547 self.inserter
548 .handle_metric_row_inserts(requests, ctx, &self.statement_executor, physical_table)
549 .await
550 .context(TableOperationSnafu)
551 }
552
553 #[tracing::instrument(skip_all)]
554 pub async fn handle_deletes(
555 &self,
556 requests: DeleteRequests,
557 ctx: QueryContextRef,
558 ) -> Result<Output> {
559 self.deleter
560 .handle_column_deletes(requests, ctx)
561 .await
562 .context(TableOperationSnafu)
563 }
564
565 #[tracing::instrument(skip_all)]
566 pub async fn handle_row_deletes(
567 &self,
568 requests: RowDeleteRequests,
569 ctx: QueryContextRef,
570 ) -> Result<Output> {
571 self.deleter
572 .handle_row_deletes(requests, ctx)
573 .await
574 .context(TableOperationSnafu)
575 }
576}