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 plan_decoder = self
145 .query_engine()
146 .engine_context(ctx.clone())
147 .new_plan_decoder()
148 .context(PlanStatementSnafu)?;
149
150 let dummy_catalog_list =
151 Arc::new(catalog::table_source::dummy_catalog::DummyCatalogList::new_with_query_ctx(
152 self.catalog_manager().clone(),
153 ctx.clone(),
154 ));
155
156 let logical_plan = plan_decoder
157 .decode(bytes::Bytes::from(plan), dummy_catalog_list, true)
158 .await
159 .context(SubstraitDecodeLogicalPlanSnafu)?;
160 let output =
161 self.do_exec_plan_inner(logical_plan, None, ctx.clone()).await?;
162
163 attach_timer(output, timer)
164 }
165 Query::InsertIntoPlan(insert) => {
166 self.handle_insert_plan(insert, ctx.clone()).await?
167 }
168 Query::PromRangeQuery(promql) => {
169 let timer = GRPC_HANDLE_PROMQL_ELAPSED.start_timer();
170 let prom_query = PromQuery {
171 query: promql.query,
172 start: promql.start,
173 end: promql.end,
174 step: promql.step,
175 lookback: promql.lookback,
176 alias: None,
177 };
178 let mut result =
179 self.do_promql_query_inner(&prom_query, ctx.clone()).await;
180 ensure!(
181 result.len() == 1,
182 NotSupportedSnafu {
183 feat: "execute multiple statements in PromQL query string through GRPC interface"
184 }
185 );
186 let output = result.remove(0)?;
187 attach_timer(output, timer)
188 }
189 }
190 }
191 Request::Ddl(request) => {
192 let mut expr = request.expr.context(IncompleteGrpcRequestSnafu {
193 err_msg: "'expr' is absent in DDL request",
194 })?;
195
196 fill_catalog_and_schema_from_context(&mut expr, &ctx);
197
198 match expr {
199 DdlExpr::CreateTable(mut expr) => {
200 operator::expr_helper::validate_create_expr(&expr)?;
203 let _ = self
204 .statement_executor
205 .create_table_inner(
206 &mut expr,
207 None,
208 ctx.clone(),
209 TriggerReason::Manual,
210 )
211 .await?;
212 Output::new_with_affected_rows(0)
213 }
214 DdlExpr::AlterDatabase(expr) => {
215 let _ = self
216 .statement_executor
217 .alter_database_inner(expr, ctx.clone())
218 .await?;
219 Output::new_with_affected_rows(0)
220 }
221 DdlExpr::AlterTable(expr) => {
222 self.statement_executor
223 .alter_table_inner(expr, ctx.clone(), TriggerReason::Manual)
224 .await?
225 }
226 DdlExpr::CreateDatabase(expr) => {
227 self.statement_executor
228 .create_database(
229 &expr.schema_name,
230 expr.create_if_not_exists,
231 expr.options,
232 ctx.clone(),
233 )
234 .await?
235 }
236 DdlExpr::DropTable(expr) => {
237 let table_name =
238 TableName::new(&expr.catalog_name, &expr.schema_name, &expr.table_name);
239 self.statement_executor
240 .drop_table(table_name, expr.drop_if_exists, ctx.clone())
241 .await?
242 }
243 DdlExpr::TruncateTable(expr) => {
244 let table_name =
245 TableName::new(&expr.catalog_name, &expr.schema_name, &expr.table_name);
246 let time_ranges = from_pb_time_ranges(expr.time_ranges.unwrap_or_default())
247 .map_err(BoxedError::new)
248 .context(ExternalSnafu)?;
249 self.statement_executor
250 .truncate_table(table_name, time_ranges, ctx.clone())
251 .await?
252 }
253 DdlExpr::CreateFlow(expr) => {
254 self.statement_executor
255 .create_flow_inner(expr, ctx.clone())
256 .await?
257 }
258 DdlExpr::DropFlow(DropFlowExpr {
259 catalog_name,
260 flow_name,
261 drop_if_exists,
262 ..
263 }) => {
264 self.statement_executor
265 .drop_flow(catalog_name, flow_name, drop_if_exists, ctx.clone())
266 .await?
267 }
268 DdlExpr::CreateView(expr) => {
269 let _ = self
270 .statement_executor
271 .create_view_by_expr(expr, ctx.clone())
272 .await?;
273
274 Output::new_with_affected_rows(0)
275 }
276 DdlExpr::DropView(expr) => {
277 self.statement_executor
278 .drop_view(
279 expr.catalog_name,
280 expr.schema_name,
281 expr.view_name,
282 expr.drop_if_exists,
283 ctx.clone(),
284 )
285 .await?
286 }
287 DdlExpr::CommentOn(expr) => {
288 self.statement_executor
289 .comment_by_expr(expr, ctx.clone())
290 .await?
291 }
292 }
293 }
294 };
295
296 let output = interceptor.post_execute(output, ctx)?;
297 Ok(output)
298 }
299 .await;
300
301 result
302 .map_err(BoxedError::new)
303 .context(server_error::ExecuteGrpcQuerySnafu)
304 }
305
306 fn handle_put_record_batch_stream(
307 &self,
308 stream: servers::grpc::flight::PutRecordBatchRequestStream,
309 ctx: QueryContextRef,
310 ) -> Pin<Box<dyn Stream<Item = server_error::Result<DoPutResponse>> + Send>> {
311 Box::pin(
312 self.handle_put_record_batch_stream_inner(stream, ctx)
313 .map(|result| {
314 result
315 .map_err(BoxedError::new)
316 .context(server_error::ExecuteGrpcRequestSnafu)
317 }),
318 )
319 }
320}
321
322fn fill_catalog_and_schema_from_context(ddl_expr: &mut DdlExpr, ctx: &QueryContextRef) {
323 let catalog = ctx.current_catalog();
324 let schema = ctx.current_schema();
325
326 macro_rules! check_and_fill {
327 ($expr:ident) => {
328 if $expr.catalog_name.is_empty() {
329 $expr.catalog_name = catalog.to_string();
330 }
331 if $expr.schema_name.is_empty() {
332 $expr.schema_name = schema.to_string();
333 }
334 };
335 }
336
337 match ddl_expr {
338 Expr::CreateDatabase(_) | Expr::AlterDatabase(_) => { }
339 Expr::CreateTable(expr) => {
340 check_and_fill!(expr);
341 }
342 Expr::AlterTable(expr) => {
343 check_and_fill!(expr);
344 }
345 Expr::DropTable(expr) => {
346 check_and_fill!(expr);
347 }
348 Expr::TruncateTable(expr) => {
349 check_and_fill!(expr);
350 }
351 Expr::CreateFlow(expr) => {
352 if expr.catalog_name.is_empty() {
353 expr.catalog_name = catalog.to_string();
354 }
355 }
356 Expr::DropFlow(expr) => {
357 if expr.catalog_name.is_empty() {
358 expr.catalog_name = catalog.to_string();
359 }
360 }
361 Expr::CreateView(expr) => {
362 check_and_fill!(expr);
363 }
364 Expr::DropView(expr) => {
365 check_and_fill!(expr);
366 }
367 Expr::CommentOn(expr) => {
368 check_and_fill!(expr);
369 }
370 }
371}
372
373impl Instance {
374 pub(crate) fn check_table_permission(
375 &self,
376 ctx: &QueryContextRef,
377 req: PermissionReq<'_>,
378 targets: PermissionTableTargets,
379 ) -> auth::error::Result<PermissionResp> {
380 self.plugins
381 .get::<PermissionCheckerRef>()
382 .as_ref()
383 .check_permission_with_table_targets(ctx.current_user(), req, targets)
384 }
385
386 pub(crate) fn check_row_insert_permission(
388 &self,
389 requests: &RowInsertRequests,
390 ctx: &QueryContextRef,
391 req: PermissionReq<'_>,
392 ) -> auth::error::Result<PermissionResp> {
393 let catalog = ctx.current_catalog();
394 let schema = ctx.current_schema();
395 let targets = PermissionTableTargets::from_row_insert_requests(catalog, &schema, requests);
396
397 self.check_table_permission(ctx, req, targets)
398 }
399
400 fn handle_put_record_batch_stream_inner(
401 &self,
402 mut stream: servers::grpc::flight::PutRecordBatchRequestStream,
403 ctx: QueryContextRef,
404 ) -> Pin<Box<dyn Stream<Item = Result<DoPutResponse>> + Send>> {
405 let catalog_manager = self.catalog_manager().clone();
407 let plugins = self.plugins.clone();
408 let inserter = self.inserter.clone();
409 let statement_executor = self.statement_executor.clone();
410 let ctx = ctx.clone();
411 let mut table_ref: Option<TableRef> = None;
412 let mut table_checked = false;
413
414 Box::pin(try_stream! {
415 while let Some(request_result) = stream.next().await {
417 let request = request_result.map_err(|e| {
418 let error_msg = format!("Stream error: {:?}", e);
419 IncompleteGrpcRequestSnafu { err_msg: error_msg }.build()
420 })?;
421
422 if !table_checked {
424 let table_name = &request.table_name;
425
426 plugins
427 .get::<PermissionCheckerRef>()
428 .as_ref()
429 .check_permission(
430 ctx.current_user(),
431 PermissionReq::BulkInsert {
432 catalog: &table_name.catalog_name,
433 schema: &table_name.schema_name,
434 table: &table_name.table_name,
435 },
436 )
437 .context(PermissionSnafu)?;
438
439 let table = catalog_manager
441 .table(
442 &table_name.catalog_name,
443 &table_name.schema_name,
444 &table_name.table_name,
445 None,
446 )
447 .await
448 .context(CatalogSnafu)?
449 .with_context(|| TableNotFoundSnafu {
450 table_name: table_name.to_string(),
451 })?;
452
453 let interceptor_ref = plugins.get::<GrpcQueryInterceptorRef<Error>>();
455 let interceptor = interceptor_ref.as_ref();
456 interceptor.pre_bulk_insert(table.clone(), ctx.clone())?;
457
458 table_ref = Some(
461 inserter
462 .ensure_bulk_insert_schema(
463 table,
464 request.record_batch.schema().as_ref(),
465 &ctx,
466 statement_executor.as_ref(),
467 )
468 .await
469 .context(TableOperationSnafu)?,
470 );
471
472 table_checked = true;
473 }
474
475 let request_id = request.request_id;
476 let start = Instant::now();
477 let rows = inserter
478 .handle_bulk_insert(
479 table_ref.clone().unwrap(),
480 request.flight_data,
481 request.record_batch,
482 request.schema_bytes,
483 ctx.skip_wal(),
484 ctx.channel(),
485 )
486 .await
487 .context(TableOperationSnafu)?;
488 let elapsed_secs = start.elapsed().as_secs_f64();
489 yield DoPutResponse::new(request_id, rows, elapsed_secs);
490 }
491 })
492 }
493
494 async fn handle_insert_plan(
495 &self,
496 insert: InsertIntoPlan,
497 ctx: QueryContextRef,
498 ) -> Result<Output> {
499 let timer = GRPC_HANDLE_PLAN_ELAPSED.start_timer();
500 let table_name = insert.table_name.context(IncompleteGrpcRequestSnafu {
501 err_msg: "'table_name' is absent in InsertIntoPlan",
502 })?;
503
504 let plan_decoder = self
506 .query_engine()
507 .engine_context(ctx.clone())
508 .new_plan_decoder()
509 .context(PlanStatementSnafu)?;
510
511 let dummy_catalog_list = Arc::new(
512 catalog::table_source::dummy_catalog::DummyCatalogList::new_with_query_ctx(
513 self.catalog_manager().clone(),
514 ctx.clone(),
515 ),
516 );
517
518 let logical_plan = plan_decoder
520 .decode(
521 bytes::Bytes::from(insert.logical_plan),
522 dummy_catalog_list,
523 false,
524 )
525 .await
526 .context(SubstraitDecodeLogicalPlanSnafu)?;
527
528 let table = self
529 .catalog_manager()
530 .table(
531 &table_name.catalog_name,
532 &table_name.schema_name,
533 &table_name.table_name,
534 None,
535 )
536 .await
537 .context(CatalogSnafu)?
538 .with_context(|| TableNotFoundSnafu {
539 table_name: [
540 table_name.catalog_name.clone(),
541 table_name.schema_name.clone(),
542 table_name.table_name.clone(),
543 ]
544 .join("."),
545 })?;
546 let table_provider = Arc::new(DfTableProviderAdapter::new(table));
547 let table_source = Arc::new(DefaultTableSource::new(table_provider));
548
549 let insert_into = add_insert_to_logical_plan(table_name, table_source, logical_plan)
550 .context(SubstraitDecodeLogicalPlanSnafu)?;
551
552 let engine_ctx = self.query_engine().engine_context(ctx.clone());
553 let state = engine_ctx.state();
554 let analyzed_plan = state
556 .analyzer()
557 .execute_and_check(insert_into, state.config_options(), |_, _| {})
558 .context(DataFusionSnafu)?;
559
560 let optimized_plan = state.optimize(&analyzed_plan).context(DataFusionSnafu)?;
562
563 let output = self
564 .do_exec_plan_inner(optimized_plan, None, ctx.clone())
565 .await?;
566
567 Ok(attach_timer(output, timer))
568 }
569 #[tracing::instrument(skip_all)]
570 pub async fn handle_inserts(
571 &self,
572 requests: InsertRequests,
573 ctx: QueryContextRef,
574 ) -> Result<Output> {
575 self.inserter
576 .handle_column_inserts(requests, ctx, self.statement_executor.as_ref())
577 .await
578 .context(TableOperationSnafu)
579 }
580
581 #[tracing::instrument(skip_all)]
582 pub async fn handle_row_inserts(
583 &self,
584 requests: RowInsertRequests,
585 ctx: QueryContextRef,
586 accommodate_existing_schema: bool,
587 is_single_value: bool,
588 ) -> Result<Output> {
589 self.inserter
590 .handle_row_inserts(
591 requests,
592 ctx,
593 self.statement_executor.as_ref(),
594 accommodate_existing_schema,
595 is_single_value,
596 )
597 .await
598 .context(TableOperationSnafu)
599 }
600
601 #[tracing::instrument(skip_all)]
602 pub async fn handle_influx_row_inserts(
603 &self,
604 requests: RowInsertRequests,
605 ctx: QueryContextRef,
606 ) -> Result<Output> {
607 self.inserter
608 .handle_last_non_null_inserts(
609 requests,
610 ctx,
611 self.statement_executor.as_ref(),
612 true,
613 false,
615 )
616 .await
617 .context(TableOperationSnafu)
618 }
619
620 #[tracing::instrument(skip_all)]
621 pub async fn handle_metric_row_inserts(
622 &self,
623 requests: RowInsertRequests,
624 ctx: QueryContextRef,
625 physical_table: String,
626 ) -> Result<Output> {
627 self.inserter
628 .handle_metric_row_inserts(requests, ctx, &self.statement_executor, physical_table)
629 .await
630 .context(TableOperationSnafu)
631 }
632
633 #[tracing::instrument(skip_all)]
634 pub async fn handle_deletes(
635 &self,
636 requests: DeleteRequests,
637 ctx: QueryContextRef,
638 ) -> Result<Output> {
639 self.deleter
640 .handle_column_deletes(requests, ctx)
641 .await
642 .context(TableOperationSnafu)
643 }
644
645 #[tracing::instrument(skip_all)]
646 pub async fn handle_row_deletes(
647 &self,
648 requests: RowDeleteRequests,
649 ctx: QueryContextRef,
650 ) -> Result<Output> {
651 self.deleter
652 .handle_row_deletes(requests, ctx)
653 .await
654 .context(TableOperationSnafu)
655 }
656}