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