1use std::sync::Arc;
16
17use ahash::{HashMap, HashMapExt, HashSet, HashSetExt};
18use api::v1::alter_table_expr::Kind;
19use api::v1::column_def::options_from_skipping;
20use api::v1::region::{
21 InsertRequest as RegionInsertRequest, InsertRequests as RegionInsertRequests,
22 RegionRequestHeader,
23};
24use api::v1::{
25 AlterTableExpr, ColumnDataType, ColumnSchema, CreateTableExpr, InsertRequests,
26 RowInsertRequest, RowInsertRequests, SemanticType,
27};
28use catalog::CatalogManagerRef;
29use client::{OutputData, OutputMeta};
30use common_catalog::consts::{
31 PARENT_SPAN_ID_COLUMN, SERVICE_NAME_COLUMN, TRACE_ID_COLUMN, TRACE_TABLE_NAME,
32 TRACE_TABLE_NAME_SESSION_KEY, default_engine, trace_operations_table_name,
33 trace_services_table_name,
34};
35use common_grpc_expr::util::ColumnExpr;
36use common_meta::cache::TableFlownodeSetCacheRef;
37use common_meta::node_manager::{AffectedRows, NodeManagerRef};
38use common_meta::peer::Peer;
39use common_query::Output;
40use common_query::prelude::{greptime_timestamp, greptime_value};
41use common_telemetry::tracing_context::TracingContext;
42use common_telemetry::{error, info, warn};
43use datatypes::schema::SkippingIndexOptions;
44use futures_util::future;
45use meter_macros::write_meter;
46use partition::manager::PartitionRuleManagerRef;
47use session::context::QueryContextRef;
48use snafu::ResultExt;
49use snafu::prelude::*;
50use sql::partition::partition_rule_for_hexstring;
51use sql::statements::create::Partitions;
52use sql::statements::insert::Insert;
53use store_api::metric_engine_consts::{
54 LOGICAL_TABLE_METADATA_KEY, METRIC_ENGINE_NAME, PHYSICAL_TABLE_METADATA_KEY,
55};
56use store_api::mito_engine_options::{
57 APPEND_MODE_KEY, COMPACTION_TYPE, COMPACTION_TYPE_TWCS, MERGE_MODE_KEY, TTL_KEY,
58 TWCS_TIME_WINDOW,
59};
60use store_api::storage::{RegionId, TableId};
61use table::TableRef;
62use table::metadata::TableInfo;
63use table::requests::{
64 AUTO_CREATE_TABLE_KEY, InsertRequest as TableInsertRequest, TABLE_DATA_MODEL,
65 TABLE_DATA_MODEL_TRACE_V1, TRACE_TABLE_PARTITIONS_HINT_KEY, VALID_TABLE_OPTION_KEYS,
66 is_semantic_option_key,
67};
68use table::table_reference::TableReference;
69
70use crate::error::{
71 CatalogSnafu, ColumnOptionsSnafu, CreatePartitionRulesSnafu, FindRegionLeaderSnafu,
72 InvalidInsertRequestSnafu, JoinTaskSnafu, RequestInsertsSnafu, Result, TableNotFoundSnafu,
73};
74use crate::expr_helper;
75use crate::region_req_factory::RegionRequestFactory;
76use crate::req_convert::common::preprocess_row_insert_requests;
77use crate::req_convert::insert::{
78 ColumnToRow, RowToRegion, StatementToRegion, TableToRegion, fill_reqs_with_impure_default,
79};
80use crate::statement::StatementExecutor;
81
82pub struct Inserter {
83 catalog_manager: CatalogManagerRef,
84 pub(crate) partition_manager: PartitionRuleManagerRef,
85 pub(crate) node_manager: NodeManagerRef,
86 pub(crate) table_flownode_set_cache: TableFlownodeSetCacheRef,
87 auto_create_table: bool,
91}
92
93pub type InserterRef = Arc<Inserter>;
94
95#[derive(Clone)]
97pub enum AutoCreateTableType {
98 Logical(String),
100 Physical,
102 Log,
104 LastNonNull,
106 Trace,
108}
109
110impl AutoCreateTableType {
111 pub fn as_str(&self) -> &'static str {
112 match self {
113 AutoCreateTableType::Logical(_) => "logical",
114 AutoCreateTableType::Physical => "physical",
115 AutoCreateTableType::Log => "log",
116 AutoCreateTableType::LastNonNull => "last_non_null",
117 AutoCreateTableType::Trace => "trace",
118 }
119 }
120}
121
122#[derive(Clone)]
129pub struct InstantAndNormalInsertRequests {
130 pub normal_requests: RegionInsertRequests,
132 pub instant_requests: RegionInsertRequests,
135}
136
137impl Inserter {
138 pub fn new(
139 catalog_manager: CatalogManagerRef,
140 partition_manager: PartitionRuleManagerRef,
141 node_manager: NodeManagerRef,
142 table_flownode_set_cache: TableFlownodeSetCacheRef,
143 auto_create_table: bool,
144 ) -> Self {
145 Self {
146 catalog_manager,
147 partition_manager,
148 node_manager,
149 table_flownode_set_cache,
150 auto_create_table,
151 }
152 }
153
154 pub async fn handle_column_inserts(
155 &self,
156 requests: InsertRequests,
157 ctx: QueryContextRef,
158 statement_executor: &StatementExecutor,
159 ) -> Result<Output> {
160 let row_inserts = ColumnToRow::convert(requests)?;
161 self.handle_row_inserts(row_inserts, ctx, statement_executor, false, false)
162 .await
163 }
164
165 pub async fn handle_row_inserts(
167 &self,
168 mut requests: RowInsertRequests,
169 ctx: QueryContextRef,
170 statement_executor: &StatementExecutor,
171 accommodate_existing_schema: bool,
172 is_single_value: bool,
173 ) -> Result<Output> {
174 preprocess_row_insert_requests(&mut requests.inserts)?;
175 self.handle_row_inserts_with_create_type(
176 requests,
177 ctx,
178 statement_executor,
179 AutoCreateTableType::Physical,
180 accommodate_existing_schema,
181 is_single_value,
182 )
183 .await
184 }
185
186 pub async fn handle_log_inserts(
188 &self,
189 requests: RowInsertRequests,
190 ctx: QueryContextRef,
191 statement_executor: &StatementExecutor,
192 ) -> Result<Output> {
193 self.handle_row_inserts_with_create_type(
194 requests,
195 ctx,
196 statement_executor,
197 AutoCreateTableType::Log,
198 false,
199 false,
200 )
201 .await
202 }
203
204 pub async fn handle_trace_inserts(
205 &self,
206 requests: RowInsertRequests,
207 ctx: QueryContextRef,
208 statement_executor: &StatementExecutor,
209 ) -> Result<Output> {
210 self.handle_row_inserts_with_create_type(
211 requests,
212 ctx,
213 statement_executor,
214 AutoCreateTableType::Trace,
215 false,
216 false,
217 )
218 .await
219 }
220
221 pub async fn handle_last_non_null_inserts(
223 &self,
224 requests: RowInsertRequests,
225 ctx: QueryContextRef,
226 statement_executor: &StatementExecutor,
227 accommodate_existing_schema: bool,
228 is_single_value: bool,
229 ) -> Result<Output> {
230 self.handle_row_inserts_with_create_type(
231 requests,
232 ctx,
233 statement_executor,
234 AutoCreateTableType::LastNonNull,
235 accommodate_existing_schema,
236 is_single_value,
237 )
238 .await
239 }
240
241 async fn handle_row_inserts_with_create_type(
243 &self,
244 mut requests: RowInsertRequests,
245 ctx: QueryContextRef,
246 statement_executor: &StatementExecutor,
247 create_type: AutoCreateTableType,
248 accommodate_existing_schema: bool,
249 is_single_value: bool,
250 ) -> Result<Output> {
251 requests.inserts.retain(|req| {
253 req.rows
254 .as_ref()
255 .map(|r| !r.rows.is_empty())
256 .unwrap_or_default()
257 });
258 validate_column_count_match(&requests)?;
259
260 let CreateAlterTableResult {
261 instant_table_ids,
262 table_infos,
263 } = self
264 .create_or_alter_tables_on_demand(
265 &mut requests,
266 &ctx,
267 create_type,
268 statement_executor,
269 accommodate_existing_schema,
270 is_single_value,
271 )
272 .await?;
273
274 let name_to_info = table_infos
275 .values()
276 .map(|info| (info.name.clone(), info.clone()))
277 .collect::<HashMap<_, _>>();
278 let inserts = RowToRegion::new(
279 name_to_info,
280 instant_table_ids,
281 self.partition_manager.as_ref(),
282 )
283 .convert(requests)
284 .await?;
285
286 self.do_request(inserts, &table_infos, &ctx).await
287 }
288
289 pub async fn handle_metric_row_inserts(
291 &self,
292 mut requests: RowInsertRequests,
293 ctx: QueryContextRef,
294 statement_executor: &StatementExecutor,
295 physical_table: String,
296 ) -> Result<Output> {
297 requests.inserts.retain(|req| {
299 req.rows
300 .as_ref()
301 .map(|r| !r.rows.is_empty())
302 .unwrap_or_default()
303 });
304 validate_column_count_match(&requests)?;
305
306 self.create_physical_table_on_demand(&ctx, physical_table.clone(), statement_executor)
308 .await?;
309
310 let CreateAlterTableResult {
312 instant_table_ids,
313 table_infos,
314 } = self
315 .create_or_alter_tables_on_demand(
316 &mut requests,
317 &ctx,
318 AutoCreateTableType::Logical(physical_table.clone()),
319 statement_executor,
320 true,
321 true,
322 )
323 .await?;
324 let name_to_info = table_infos
325 .values()
326 .map(|info| (info.name.clone(), info.clone()))
327 .collect::<HashMap<_, _>>();
328 let inserts = RowToRegion::new(name_to_info, instant_table_ids, &self.partition_manager)
329 .convert(requests)
330 .await?;
331
332 self.do_request(inserts, &table_infos, &ctx).await
333 }
334
335 pub async fn handle_table_insert(
336 &self,
337 request: TableInsertRequest,
338 ctx: QueryContextRef,
339 ) -> Result<Output> {
340 let catalog = request.catalog_name.as_str();
341 let schema = request.schema_name.as_str();
342 let table_name = request.table_name.as_str();
343 let table = self.get_table(catalog, schema, table_name).await?;
344 let table = table.with_context(|| TableNotFoundSnafu {
345 table_name: common_catalog::format_full_table_name(catalog, schema, table_name),
346 })?;
347 let table_info = table.table_info();
348
349 let inserts = TableToRegion::new(&table_info, &self.partition_manager)
350 .convert(request)
351 .await?;
352
353 let table_infos = HashMap::from_iter([(table_info.table_id(), table_info.clone())]);
354
355 self.do_request(inserts, &table_infos, &ctx).await
356 }
357
358 pub async fn handle_statement_insert(
359 &self,
360 insert: &Insert,
361 ctx: &QueryContextRef,
362 ) -> Result<Output> {
363 let (inserts, table_info) =
364 StatementToRegion::new(self.catalog_manager.as_ref(), &self.partition_manager, ctx)
365 .convert(insert, ctx)
366 .await?;
367
368 let table_infos = HashMap::from_iter([(table_info.table_id(), table_info.clone())]);
369
370 self.do_request(inserts, &table_infos, ctx).await
371 }
372}
373
374impl Inserter {
375 async fn do_request(
376 &self,
377 requests: InstantAndNormalInsertRequests,
378 table_infos: &HashMap<TableId, Arc<TableInfo>>,
379 ctx: &QueryContextRef,
380 ) -> Result<Output> {
381 let requests = fill_reqs_with_impure_default(table_infos, requests)?;
383
384 let write_cost = write_meter!(
385 ctx.current_catalog(),
386 ctx.current_schema(),
387 requests,
388 ctx.channel() as u8
389 );
390 let request_factory = RegionRequestFactory::new(RegionRequestHeader {
391 tracing_context: TracingContext::from_current_span().to_w3c(),
392 dbname: ctx.get_db_string(),
393 ..Default::default()
394 });
395
396 let InstantAndNormalInsertRequests {
397 normal_requests,
398 instant_requests,
399 } = requests;
400
401 let flow_mirror_task = FlowMirrorTask::new(
403 &self.table_flownode_set_cache,
404 normal_requests
405 .requests
406 .iter()
407 .chain(instant_requests.requests.iter()),
408 )
409 .await?;
410 flow_mirror_task.detach(self.node_manager.clone())?;
411
412 let write_tasks = self
414 .group_requests_by_peer(normal_requests)
415 .await?
416 .into_iter()
417 .map(|(peer, inserts)| {
418 let node_manager = self.node_manager.clone();
419 let request = request_factory.build_insert(inserts);
420 common_runtime::spawn_global(async move {
421 node_manager
422 .datanode(&peer)
423 .await
424 .handle(request)
425 .await
426 .context(RequestInsertsSnafu)
427 })
428 });
429 let results = future::try_join_all(write_tasks)
430 .await
431 .context(JoinTaskSnafu)?;
432 let affected_rows = results
433 .into_iter()
434 .map(|resp| resp.map(|r| r.affected_rows))
435 .sum::<Result<AffectedRows>>()?;
436 crate::metrics::DIST_INGEST_ROW_COUNT
437 .with_label_values(&[ctx.get_db_string().as_str()])
438 .inc_by(affected_rows as u64);
439 Ok(Output::new(
440 OutputData::AffectedRows(affected_rows),
441 OutputMeta::new_with_cost(write_cost as _),
442 ))
443 }
444
445 async fn group_requests_by_peer(
446 &self,
447 requests: RegionInsertRequests,
448 ) -> Result<HashMap<Peer, RegionInsertRequests>> {
449 let mut requests_per_region: HashMap<RegionId, RegionInsertRequests> = HashMap::new();
452 for req in requests.requests {
453 let region_id = RegionId::from_u64(req.region_id);
454 requests_per_region
455 .entry(region_id)
456 .or_default()
457 .requests
458 .push(req);
459 }
460
461 let mut inserts: HashMap<Peer, RegionInsertRequests> = HashMap::new();
462
463 for (region_id, reqs) in requests_per_region {
464 let peer = self
465 .partition_manager
466 .find_region_leader(region_id)
467 .await
468 .context(FindRegionLeaderSnafu)?;
469 inserts
470 .entry(peer)
471 .or_default()
472 .requests
473 .extend(reqs.requests);
474 }
475
476 Ok(inserts)
477 }
478
479 fn auto_create_disabled_reason(&self, ctx: &QueryContextRef) -> Result<Option<&'static str>> {
483 let auto_create_table_hint = ctx
484 .extension(AUTO_CREATE_TABLE_KEY)
485 .map(|v| v.parse::<bool>())
486 .transpose()
487 .map_err(|_| {
488 InvalidInsertRequestSnafu {
489 reason: "`auto_create_table` hint must be a boolean",
490 }
491 .build()
492 })?
493 .unwrap_or(true);
494 Ok(if !self.auto_create_table {
495 Some("auto-create table is disabled by frontend config")
496 } else if !auto_create_table_hint {
497 Some("`auto_create_table` hint is disabled")
498 } else {
499 None
500 })
501 }
502
503 async fn create_or_alter_tables_on_demand(
516 &self,
517 requests: &mut RowInsertRequests,
518 ctx: &QueryContextRef,
519 auto_create_table_type: AutoCreateTableType,
520 statement_executor: &StatementExecutor,
521 accommodate_existing_schema: bool,
522 is_single_value: bool,
523 ) -> Result<CreateAlterTableResult> {
524 let _timer = crate::metrics::CREATE_ALTER_ON_DEMAND
525 .with_label_values(&[auto_create_table_type.as_str()])
526 .start_timer();
527
528 let catalog = ctx.current_catalog();
529 let schema = ctx.current_schema();
530
531 let mut table_infos = HashMap::new();
532 if let Some(disabled_reason) = self.auto_create_disabled_reason(ctx)? {
533 let mut instant_table_ids = HashSet::new();
534 for req in &requests.inserts {
535 let table = self
536 .get_table(catalog, &schema, &req.table_name)
537 .await?
538 .context(InvalidInsertRequestSnafu {
539 reason: format!(
540 "Table `{}` does not exist, and {}",
541 req.table_name, disabled_reason
542 ),
543 })?;
544 let table_info = table.table_info();
545 if table_info.is_ttl_instant_table() {
546 instant_table_ids.insert(table_info.table_id());
547 }
548 table_infos.insert(table_info.table_id(), table.table_info());
549 }
550 let ret = CreateAlterTableResult {
551 instant_table_ids,
552 table_infos,
553 };
554 return Ok(ret);
555 }
556
557 let mut create_tables = vec![];
558 let mut alter_tables = vec![];
559 let mut need_refresh_table_infos = HashSet::new();
560 let mut instant_table_ids = HashSet::new();
561
562 for req in &mut requests.inserts {
563 match self.get_table(catalog, &schema, &req.table_name).await? {
564 Some(table) => {
565 let table_info = table.table_info();
566 if table_info.is_ttl_instant_table() {
567 instant_table_ids.insert(table_info.table_id());
568 }
569 if let Some(alter_expr) = self.get_alter_table_expr_on_demand(
570 req,
571 &table,
572 ctx,
573 accommodate_existing_schema,
574 is_single_value,
575 )? {
576 alter_tables.push(alter_expr);
577 need_refresh_table_infos.insert((
578 catalog.to_string(),
579 schema.clone(),
580 req.table_name.clone(),
581 ));
582 } else {
583 table_infos.insert(table_info.table_id(), table.table_info());
584 }
585 }
586 None => {
587 let create_expr =
588 self.get_create_table_expr_on_demand(req, &auto_create_table_type, ctx)?;
589 create_tables.push(create_expr);
590 }
591 }
592 }
593
594 match auto_create_table_type {
595 AutoCreateTableType::Logical(_) => {
596 if !create_tables.is_empty() {
597 let tables = self
599 .create_logical_tables(create_tables, ctx, statement_executor)
600 .await?;
601
602 for table in tables {
603 let table_info = table.table_info();
604 if table_info.is_ttl_instant_table() {
605 instant_table_ids.insert(table_info.table_id());
606 }
607 table_infos.insert(table_info.table_id(), table.table_info());
608 }
609 }
610 if !alter_tables.is_empty() {
611 statement_executor
613 .alter_logical_tables(alter_tables, ctx.clone())
614 .await?;
615 }
616 }
617 AutoCreateTableType::Physical
618 | AutoCreateTableType::Log
619 | AutoCreateTableType::LastNonNull => {
620 for create_table in create_tables {
623 let table = self
624 .create_physical_table(create_table, None, ctx, statement_executor)
625 .await?;
626 let table_info = table.table_info();
627 if table_info.is_ttl_instant_table() {
628 instant_table_ids.insert(table_info.table_id());
629 }
630 table_infos.insert(table_info.table_id(), table.table_info());
631 }
632 for alter_expr in alter_tables.into_iter() {
633 statement_executor
634 .alter_table_inner(alter_expr, ctx.clone())
635 .await?;
636 }
637 }
638
639 AutoCreateTableType::Trace => {
640 let trace_table_name = ctx
641 .extension(TRACE_TABLE_NAME_SESSION_KEY)
642 .unwrap_or(TRACE_TABLE_NAME);
643
644 let trace_table_partitions = if let Some(trace_table_partitions) =
645 ctx.extension(TRACE_TABLE_PARTITIONS_HINT_KEY)
646 {
647 let p = trace_table_partitions.parse::<u32>().map_err(|_| {
648 InvalidInsertRequestSnafu {
649 reason: format!(
650 "Failed to parse trace_table_partitions: {}",
651 trace_table_partitions
652 ),
653 }
654 .build()
655 })?;
656 Some(p)
657 } else {
658 None
659 };
660
661 for mut create_table in create_tables {
664 if create_table.table_name == trace_services_table_name(trace_table_name)
665 || create_table.table_name == trace_operations_table_name(trace_table_name)
666 {
667 create_table
669 .table_options
670 .insert(APPEND_MODE_KEY.to_string(), "false".to_string());
671 create_table.table_options.remove(TTL_KEY);
673
674 let table = self
675 .create_physical_table(create_table, None, ctx, statement_executor)
676 .await?;
677 let table_info = table.table_info();
678 if table_info.is_ttl_instant_table() {
679 instant_table_ids.insert(table_info.table_id());
680 }
681 table_infos.insert(table_info.table_id(), table.table_info());
682 } else {
683 let partitions = if matches!(trace_table_partitions, Some(0) | Some(1)) {
686 None
688 } else {
689 let p = partition_rule_for_hexstring(
690 TRACE_ID_COLUMN,
691 trace_table_partitions,
692 )
693 .context(CreatePartitionRulesSnafu)?;
694 Some(p)
695 };
696
697 let index_columns =
702 [TRACE_ID_COLUMN, PARENT_SPAN_ID_COLUMN, SERVICE_NAME_COLUMN];
703 for index_column in index_columns {
704 if let Some(col) = create_table
705 .column_defs
706 .iter_mut()
707 .find(|c| c.name == index_column)
708 {
709 col.options =
710 options_from_skipping(&SkippingIndexOptions::default())
711 .context(ColumnOptionsSnafu)?;
712 } else {
713 warn!(
714 "Column {} not found when creating index for trace table: {}.",
715 index_column, create_table.table_name
716 );
717 }
718 }
719
720 create_table.table_options.insert(
722 TABLE_DATA_MODEL.to_string(),
723 TABLE_DATA_MODEL_TRACE_V1.to_string(),
724 );
725
726 let table = self
727 .create_physical_table(
728 create_table,
729 partitions,
730 ctx,
731 statement_executor,
732 )
733 .await?;
734 let table_info = table.table_info();
735 if table_info.is_ttl_instant_table() {
736 instant_table_ids.insert(table_info.table_id());
737 }
738 table_infos.insert(table_info.table_id(), table.table_info());
739 }
740 }
741 for alter_expr in alter_tables.into_iter() {
742 statement_executor
743 .alter_table_inner(alter_expr, ctx.clone())
744 .await?;
745 }
746 }
747 }
748
749 for (catalog, schema, table_name) in need_refresh_table_infos {
751 let table = self
752 .get_table(&catalog, &schema, &table_name)
753 .await?
754 .context(TableNotFoundSnafu {
755 table_name: common_catalog::format_full_table_name(
756 &catalog,
757 &schema,
758 &table_name,
759 ),
760 })?;
761 let table_info = table.table_info();
762 table_infos.insert(table_info.table_id(), table.table_info());
763 }
764
765 Ok(CreateAlterTableResult {
766 instant_table_ids,
767 table_infos,
768 })
769 }
770
771 async fn create_physical_table_on_demand(
772 &self,
773 ctx: &QueryContextRef,
774 physical_table: String,
775 statement_executor: &StatementExecutor,
776 ) -> Result<()> {
777 let catalog_name = ctx.current_catalog();
778 let schema_name = ctx.current_schema();
779
780 if self
782 .get_table(catalog_name, &schema_name, &physical_table)
783 .await?
784 .is_some()
785 {
786 return Ok(());
787 }
788
789 if let Some(disabled_reason) = self.auto_create_disabled_reason(ctx)? {
791 return InvalidInsertRequestSnafu {
792 reason: format!(
793 "Physical table `{physical_table}` does not exist, and {disabled_reason}"
794 ),
795 }
796 .fail();
797 }
798
799 let table_reference = TableReference::full(catalog_name, &schema_name, &physical_table);
800 info!("Physical metric table `{table_reference}` does not exist, try creating table");
801
802 let default_schema = vec![
804 ColumnSchema {
805 column_name: greptime_timestamp().to_string(),
806 datatype: ColumnDataType::TimestampMillisecond as _,
807 semantic_type: SemanticType::Timestamp as _,
808 datatype_extension: None,
809 options: None,
810 },
811 ColumnSchema {
812 column_name: greptime_value().to_string(),
813 datatype: ColumnDataType::Float64 as _,
814 semantic_type: SemanticType::Field as _,
815 datatype_extension: None,
816 options: None,
817 },
818 ];
819 let create_table_expr =
820 &mut build_create_table_expr(&table_reference, &default_schema, default_engine())?;
821
822 create_table_expr.engine = METRIC_ENGINE_NAME.to_string();
823 create_table_expr
824 .table_options
825 .insert(PHYSICAL_TABLE_METADATA_KEY.to_string(), "true".to_string());
826
827 let res = statement_executor
829 .create_table_inner(create_table_expr, None, ctx.clone())
830 .await;
831
832 match res {
833 Ok(_) => {
834 info!("Successfully created table {table_reference}",);
835 Ok(())
836 }
837 Err(err) => {
838 error!(err; "Failed to create table {table_reference}");
839 Err(err)
840 }
841 }
842 }
843
844 async fn get_table(
845 &self,
846 catalog: &str,
847 schema: &str,
848 table: &str,
849 ) -> Result<Option<TableRef>> {
850 self.catalog_manager
851 .table(catalog, schema, table, None)
852 .await
853 .context(CatalogSnafu)
854 }
855
856 fn get_create_table_expr_on_demand(
857 &self,
858 req: &RowInsertRequest,
859 create_type: &AutoCreateTableType,
860 ctx: &QueryContextRef,
861 ) -> Result<CreateTableExpr> {
862 let mut table_options = std::collections::HashMap::with_capacity(4);
863 fill_table_options_for_create(&mut table_options, create_type, ctx);
864
865 let engine_name = if let AutoCreateTableType::Logical(_) = create_type {
866 METRIC_ENGINE_NAME
868 } else {
869 default_engine()
870 };
871
872 let schema = ctx.current_schema();
873 let table_ref = TableReference::full(ctx.current_catalog(), &schema, &req.table_name);
874 let request_schema = req.rows.as_ref().unwrap().schema.as_slice();
876 let mut create_table_expr =
877 build_create_table_expr(&table_ref, request_schema, engine_name)?;
878
879 info!("Table `{table_ref}` does not exist, try creating table");
880 create_table_expr.table_options.extend(table_options);
881 Ok(create_table_expr)
882 }
883
884 fn get_alter_table_expr_on_demand(
892 &self,
893 req: &mut RowInsertRequest,
894 table: &TableRef,
895 ctx: &QueryContextRef,
896 accommodate_existing_schema: bool,
897 is_single_value: bool,
898 ) -> Result<Option<AlterTableExpr>> {
899 let catalog_name = ctx.current_catalog();
900 let schema_name = ctx.current_schema();
901 let table_name = table.table_info().name.clone();
902
903 let request_schema = req.rows.as_ref().unwrap().schema.as_slice();
904 let column_exprs = ColumnExpr::from_column_schemas(request_schema);
905 let add_columns = expr_helper::extract_add_columns_expr(&table.schema(), column_exprs)?;
906 let Some(mut add_columns) = add_columns else {
907 return Ok(None);
908 };
909
910 if accommodate_existing_schema {
912 let table_schema = table.schema();
913 let ts_col_name = table_schema.timestamp_column().map(|c| c.name.clone());
915 let mut field_col_name = None;
917 if is_single_value {
918 let mut multiple_field_cols = false;
919 table.field_columns().for_each(|col| {
920 if field_col_name.is_none() {
921 field_col_name = Some(col.name.clone());
922 } else {
923 multiple_field_cols = true;
924 }
925 });
926 if multiple_field_cols {
927 field_col_name = None;
928 }
929 }
930
931 if let Some(rows) = req.rows.as_mut() {
933 for col in &mut rows.schema {
934 match col.semantic_type {
935 x if x == SemanticType::Timestamp as i32 => {
936 if let Some(ref ts_name) = ts_col_name
937 && col.column_name != *ts_name
938 {
939 col.column_name = ts_name.clone();
940 }
941 }
942 x if x == SemanticType::Field as i32 => {
943 if let Some(ref field_name) = field_col_name
944 && col.column_name != *field_name
945 {
946 col.column_name = field_name.clone();
947 }
948 }
949 _ => {}
950 }
951 }
952 }
953
954 add_columns.add_columns.retain(|col| {
956 let def = col.column_def.as_ref().unwrap();
957 def.semantic_type == SemanticType::Tag as i32
958 || (def.semantic_type == SemanticType::Field as i32 && field_col_name.is_none())
959 });
960
961 if add_columns.add_columns.is_empty() {
962 return Ok(None);
963 }
964 }
965
966 Ok(Some(AlterTableExpr {
967 catalog_name: catalog_name.to_string(),
968 schema_name: schema_name.clone(),
969 table_name: table_name.clone(),
970 kind: Some(Kind::AddColumns(add_columns)),
971 }))
972 }
973
974 async fn create_physical_table(
976 &self,
977 mut create_table_expr: CreateTableExpr,
978 partitions: Option<Partitions>,
979 ctx: &QueryContextRef,
980 statement_executor: &StatementExecutor,
981 ) -> Result<TableRef> {
982 {
983 let table_ref = TableReference::full(
984 &create_table_expr.catalog_name,
985 &create_table_expr.schema_name,
986 &create_table_expr.table_name,
987 );
988
989 info!("Table `{table_ref}` does not exist, try creating table");
990 }
991 let res = statement_executor
992 .create_table_inner(&mut create_table_expr, partitions, ctx.clone())
993 .await;
994
995 let table_ref = TableReference::full(
996 &create_table_expr.catalog_name,
997 &create_table_expr.schema_name,
998 &create_table_expr.table_name,
999 );
1000
1001 match res {
1002 Ok(table) => {
1003 info!(
1004 "Successfully created table {} with options: {:?}",
1005 table_ref, create_table_expr.table_options,
1006 );
1007 Ok(table)
1008 }
1009 Err(err) => {
1010 error!(err; "Failed to create table {}", table_ref);
1011 Err(err)
1012 }
1013 }
1014 }
1015
1016 async fn create_logical_tables(
1017 &self,
1018 create_table_exprs: Vec<CreateTableExpr>,
1019 ctx: &QueryContextRef,
1020 statement_executor: &StatementExecutor,
1021 ) -> Result<Vec<TableRef>> {
1022 let res = statement_executor
1023 .create_logical_tables(&create_table_exprs, ctx.clone())
1024 .await;
1025
1026 match res {
1027 Ok(res) => {
1028 info!("Successfully created logical tables");
1029 Ok(res)
1030 }
1031 Err(err) => {
1032 let failed_tables = create_table_exprs
1033 .into_iter()
1034 .map(|expr| {
1035 format!(
1036 "{}.{}.{}",
1037 expr.catalog_name, expr.schema_name, expr.table_name
1038 )
1039 })
1040 .collect::<Vec<_>>();
1041 error!(
1042 err;
1043 "Failed to create logical tables {:?}",
1044 failed_tables
1045 );
1046 Err(err)
1047 }
1048 }
1049 }
1050
1051 pub fn node_manager(&self) -> &NodeManagerRef {
1052 &self.node_manager
1053 }
1054
1055 pub fn partition_manager(&self) -> &PartitionRuleManagerRef {
1056 &self.partition_manager
1057 }
1058}
1059
1060fn validate_column_count_match(requests: &RowInsertRequests) -> Result<()> {
1061 for request in &requests.inserts {
1062 let rows = request.rows.as_ref().unwrap();
1063 let column_count = rows.schema.len();
1064 rows.rows.iter().try_for_each(|r| {
1065 ensure!(
1066 r.values.len() == column_count,
1067 InvalidInsertRequestSnafu {
1068 reason: format!(
1069 "column count mismatch, columns: {}, values: {}",
1070 column_count,
1071 r.values.len()
1072 )
1073 }
1074 );
1075 Ok(())
1076 })?;
1077 }
1078 Ok(())
1079}
1080
1081pub fn fill_table_options_for_create(
1083 table_options: &mut std::collections::HashMap<String, String>,
1084 create_type: &AutoCreateTableType,
1085 ctx: &QueryContextRef,
1086) {
1087 for key in VALID_TABLE_OPTION_KEYS {
1088 if let Some(value) = ctx.extension(key) {
1089 table_options.insert(key.to_string(), value.to_string());
1090 }
1091 }
1092
1093 for (key, value) in ctx.extensions() {
1095 if is_semantic_option_key(&key) {
1096 table_options.insert(key, value);
1097 }
1098 }
1099
1100 match create_type {
1101 AutoCreateTableType::Logical(physical_table) => {
1102 table_options.insert(
1103 LOGICAL_TABLE_METADATA_KEY.to_string(),
1104 physical_table.clone(),
1105 );
1106 }
1107 AutoCreateTableType::Physical => {
1108 if let Some(append_mode) = ctx.extension(APPEND_MODE_KEY) {
1109 table_options.insert(APPEND_MODE_KEY.to_string(), append_mode.to_string());
1110 }
1111 if let Some(merge_mode) = ctx.extension(MERGE_MODE_KEY) {
1112 table_options.insert(MERGE_MODE_KEY.to_string(), merge_mode.to_string());
1113 }
1114 if let Some(time_window) = ctx.extension(TWCS_TIME_WINDOW) {
1115 table_options.insert(TWCS_TIME_WINDOW.to_string(), time_window.to_string());
1116 table_options.insert(
1118 COMPACTION_TYPE.to_string(),
1119 COMPACTION_TYPE_TWCS.to_string(),
1120 );
1121 }
1122 }
1123 AutoCreateTableType::Log => {
1126 table_options.insert(APPEND_MODE_KEY.to_string(), "true".to_string());
1127 }
1128 AutoCreateTableType::LastNonNull => {
1129 if ctx
1130 .extension(APPEND_MODE_KEY)
1131 .is_some_and(|value| value.eq_ignore_ascii_case("true"))
1132 {
1133 table_options.insert(APPEND_MODE_KEY.to_string(), "true".to_string());
1134 table_options.insert(MERGE_MODE_KEY.to_string(), "last_row".to_string());
1135 } else if let Some(merge_mode) = ctx.extension(MERGE_MODE_KEY) {
1136 table_options.insert(MERGE_MODE_KEY.to_string(), merge_mode.to_string());
1137 } else {
1138 table_options.insert(MERGE_MODE_KEY.to_string(), "last_non_null".to_string());
1139 }
1140 }
1141 AutoCreateTableType::Trace => {
1142 table_options.insert(APPEND_MODE_KEY.to_string(), "true".to_string());
1143 }
1144 }
1145}
1146
1147pub fn build_create_table_expr(
1148 table: &TableReference,
1149 request_schema: &[ColumnSchema],
1150 engine: &str,
1151) -> Result<CreateTableExpr> {
1152 expr_helper::create_table_expr_by_column_schemas(table, request_schema, engine, None)
1153}
1154
1155struct CreateAlterTableResult {
1157 instant_table_ids: HashSet<TableId>,
1159 table_infos: HashMap<TableId, Arc<TableInfo>>,
1161}
1162
1163struct FlowMirrorTask {
1164 requests: HashMap<Peer, RegionInsertRequests>,
1165 num_rows: usize,
1166}
1167
1168impl FlowMirrorTask {
1169 async fn new(
1170 cache: &TableFlownodeSetCacheRef,
1171 requests: impl Iterator<Item = &RegionInsertRequest>,
1172 ) -> Result<Self> {
1173 let mut src_table_reqs: HashMap<TableId, Option<(Vec<Peer>, RegionInsertRequests)>> =
1174 HashMap::new();
1175 let mut num_rows = 0;
1176
1177 for req in requests {
1178 let table_id = RegionId::from_u64(req.region_id).table_id();
1179 match src_table_reqs.get_mut(&table_id) {
1180 Some(Some((_peers, reqs))) => reqs.requests.push(req.clone()),
1181 Some(None) => continue,
1183 _ => {
1184 let peers = cache
1186 .get(table_id)
1187 .await
1188 .context(RequestInsertsSnafu)?
1189 .unwrap_or_default()
1190 .values()
1191 .cloned()
1192 .collect::<HashSet<_>>()
1193 .into_iter()
1194 .collect::<Vec<_>>();
1195
1196 if !peers.is_empty() {
1197 let mut reqs = RegionInsertRequests::default();
1198 reqs.requests.push(req.clone());
1199 num_rows += reqs
1200 .requests
1201 .iter()
1202 .map(|r| r.rows.as_ref().unwrap().rows.len())
1203 .sum::<usize>();
1204 src_table_reqs.insert(table_id, Some((peers, reqs)));
1205 } else {
1206 src_table_reqs.insert(table_id, None);
1208 }
1209 }
1210 }
1211 }
1212
1213 let mut inserts: HashMap<Peer, RegionInsertRequests> = HashMap::new();
1214
1215 for (_table_id, (peers, reqs)) in src_table_reqs
1216 .into_iter()
1217 .filter_map(|(k, v)| v.map(|v| (k, v)))
1218 {
1219 if peers.len() == 1 {
1220 inserts
1222 .entry(peers[0].clone())
1223 .or_default()
1224 .requests
1225 .extend(reqs.requests);
1226 continue;
1227 } else {
1228 for flownode in peers {
1230 inserts
1231 .entry(flownode.clone())
1232 .or_default()
1233 .requests
1234 .extend(reqs.requests.clone());
1235 }
1236 }
1237 }
1238
1239 Ok(Self {
1240 requests: inserts,
1241 num_rows,
1242 })
1243 }
1244
1245 fn detach(self, node_manager: NodeManagerRef) -> Result<()> {
1246 crate::metrics::DIST_MIRROR_PENDING_ROW_COUNT.add(self.num_rows as i64);
1247 for (peer, inserts) in self.requests {
1248 let node_manager = node_manager.clone();
1249 common_runtime::spawn_global(async move {
1250 let result = node_manager
1251 .flownode(&peer)
1252 .await
1253 .handle_inserts(inserts)
1254 .await
1255 .context(RequestInsertsSnafu);
1256
1257 match result {
1258 Ok(resp) => {
1259 let affected_rows = resp.affected_rows;
1260 crate::metrics::DIST_MIRROR_ROW_COUNT.inc_by(affected_rows);
1261 crate::metrics::DIST_MIRROR_PENDING_ROW_COUNT.sub(affected_rows as _);
1262 }
1263 Err(err) => {
1264 error!(err; "Failed to insert data into flownode {}", peer);
1265 }
1266 }
1267 });
1268 }
1269
1270 Ok(())
1271 }
1272}
1273
1274#[cfg(test)]
1275mod tests {
1276 use std::sync::Arc;
1277
1278 use api::v1::helper::{field_column_schema, time_index_column_schema};
1279 use api::v1::{RowInsertRequest, Rows, Value};
1280 use common_catalog::consts::{DEFAULT_CATALOG_NAME, DEFAULT_SCHEMA_NAME};
1281 use common_meta::cache::new_table_flownode_set_cache;
1282 use common_meta::ddl::test_util::datanode_handler::NaiveDatanodeHandler;
1283 use common_meta::test_util::MockDatanodeManager;
1284 use datatypes::data_type::ConcreteDataType;
1285 use datatypes::schema::ColumnSchema;
1286 use moka::future::Cache;
1287 use session::context::QueryContext;
1288 use table::TableRef;
1289 use table::dist_table::DummyDataSource;
1290 use table::metadata::{TableInfoBuilder, TableMetaBuilder, TableType};
1291
1292 use super::*;
1293 use crate::tests::{create_partition_rule_manager, prepare_mocked_backend};
1294
1295 fn make_table_ref_with_schema(ts_name: &str, field_name: &str) -> TableRef {
1296 let schema = datatypes::schema::SchemaBuilder::try_from_columns(vec![
1297 ColumnSchema::new(
1298 ts_name,
1299 ConcreteDataType::timestamp_millisecond_datatype(),
1300 false,
1301 )
1302 .with_time_index(true),
1303 ColumnSchema::new(field_name, ConcreteDataType::float64_datatype(), true),
1304 ])
1305 .unwrap()
1306 .build()
1307 .unwrap();
1308 let meta = TableMetaBuilder::empty()
1309 .schema(Arc::new(schema))
1310 .primary_key_indices(vec![])
1311 .value_indices(vec![1])
1312 .engine("mito")
1313 .next_column_id(0)
1314 .options(Default::default())
1315 .created_on(Default::default())
1316 .build()
1317 .unwrap();
1318 let info = Arc::new(
1319 TableInfoBuilder::default()
1320 .table_id(1)
1321 .table_version(0)
1322 .name("test_table")
1323 .schema_name(DEFAULT_SCHEMA_NAME)
1324 .catalog_name(DEFAULT_CATALOG_NAME)
1325 .desc(None)
1326 .table_type(TableType::Base)
1327 .meta(meta)
1328 .build()
1329 .unwrap(),
1330 );
1331 Arc::new(table::Table::new(
1332 info,
1333 table::metadata::FilterPushDownType::Unsupported,
1334 Arc::new(DummyDataSource),
1335 ))
1336 }
1337
1338 #[tokio::test]
1339 async fn test_accommodate_existing_schema_logic() {
1340 let ts_name = "my_ts";
1341 let field_name = "my_field";
1342 let table = make_table_ref_with_schema(ts_name, field_name);
1343
1344 let mut req = RowInsertRequest {
1346 table_name: "test_table".to_string(),
1347 rows: Some(Rows {
1348 schema: vec![
1349 time_index_column_schema("ts_wrong", ColumnDataType::TimestampMillisecond),
1350 field_column_schema("field_wrong", ColumnDataType::Float64),
1351 ],
1352 rows: vec![api::v1::Row {
1353 values: vec![Value::default(), Value::default()],
1354 }],
1355 }),
1356 };
1357 let ctx = Arc::new(QueryContext::with(
1358 DEFAULT_CATALOG_NAME,
1359 DEFAULT_SCHEMA_NAME,
1360 ));
1361
1362 let kv_backend = prepare_mocked_backend().await;
1363 let inserter = Inserter::new(
1364 catalog::memory::MemoryCatalogManager::new(),
1365 create_partition_rule_manager(kv_backend.clone()).await,
1366 Arc::new(MockDatanodeManager::new(NaiveDatanodeHandler)),
1367 Arc::new(new_table_flownode_set_cache(
1368 String::new(),
1369 Cache::new(100),
1370 kv_backend.clone(),
1371 )),
1372 true,
1373 );
1374 let alter_expr = inserter
1375 .get_alter_table_expr_on_demand(&mut req, &table, &ctx, true, true)
1376 .unwrap();
1377 assert!(alter_expr.is_none());
1378
1379 let req_schema = req.rows.as_ref().unwrap().schema.clone();
1381 assert_eq!(req_schema[0].column_name, ts_name);
1382 assert_eq!(req_schema[1].column_name, field_name);
1383 }
1384
1385 #[test]
1386 fn test_last_non_null_create_options_preserve_default_without_append_mode() {
1387 let ctx = Arc::new(QueryContext::with(
1388 DEFAULT_CATALOG_NAME,
1389 DEFAULT_SCHEMA_NAME,
1390 ));
1391 let mut table_options = Default::default();
1392
1393 fill_table_options_for_create(&mut table_options, &AutoCreateTableType::LastNonNull, &ctx);
1394
1395 assert_eq!(
1396 Some("last_non_null"),
1397 table_options.get(MERGE_MODE_KEY).map(String::as_str)
1398 );
1399 assert!(!table_options.contains_key(APPEND_MODE_KEY));
1400 }
1401
1402 #[test]
1403 fn test_fill_table_options_copies_semantic_extensions() {
1404 use table::requests::{
1405 SEMANTIC_PER_TABLE_INDEX_KEY, SEMANTIC_SIGNAL_TYPE, SEMANTIC_SOURCE,
1406 SIGNAL_TYPE_METRIC, SOURCE_OPENTELEMETRY,
1407 };
1408
1409 let mut ctx = QueryContext::with(DEFAULT_CATALOG_NAME, DEFAULT_SCHEMA_NAME);
1410 ctx.set_extension(SEMANTIC_SIGNAL_TYPE, SIGNAL_TYPE_METRIC);
1411 ctx.set_extension(SEMANTIC_SOURCE, SOURCE_OPENTELEMETRY);
1412 ctx.set_extension(SEMANTIC_PER_TABLE_INDEX_KEY, "{}");
1414 let ctx = Arc::new(ctx);
1415 let mut table_options = Default::default();
1416
1417 fill_table_options_for_create(&mut table_options, &AutoCreateTableType::Physical, &ctx);
1418
1419 assert_eq!(
1420 Some(SIGNAL_TYPE_METRIC),
1421 table_options.get(SEMANTIC_SIGNAL_TYPE).map(String::as_str)
1422 );
1423 assert_eq!(
1424 Some(SOURCE_OPENTELEMETRY),
1425 table_options.get(SEMANTIC_SOURCE).map(String::as_str)
1426 );
1427 assert!(!table_options.contains_key(SEMANTIC_PER_TABLE_INDEX_KEY));
1428 }
1429
1430 #[test]
1431 fn test_last_non_null_create_options_preserve_default_with_append_mode_false() {
1432 let mut ctx = QueryContext::with(DEFAULT_CATALOG_NAME, DEFAULT_SCHEMA_NAME);
1433 ctx.set_extension(APPEND_MODE_KEY, "false");
1434 let ctx = Arc::new(ctx);
1435 let mut table_options = Default::default();
1436
1437 fill_table_options_for_create(&mut table_options, &AutoCreateTableType::LastNonNull, &ctx);
1438
1439 assert!(!table_options.contains_key(APPEND_MODE_KEY));
1440 assert_eq!(
1441 Some("last_non_null"),
1442 table_options.get(MERGE_MODE_KEY).map(String::as_str)
1443 );
1444 }
1445
1446 #[test]
1447 fn test_last_non_null_create_options_use_configured_merge_mode() {
1448 let mut ctx = QueryContext::with(DEFAULT_CATALOG_NAME, DEFAULT_SCHEMA_NAME);
1449 ctx.set_extension(MERGE_MODE_KEY, "last_row");
1450 let ctx = Arc::new(ctx);
1451 let mut table_options = Default::default();
1452
1453 fill_table_options_for_create(&mut table_options, &AutoCreateTableType::LastNonNull, &ctx);
1454
1455 assert_eq!(
1456 Some("last_row"),
1457 table_options.get(MERGE_MODE_KEY).map(String::as_str)
1458 );
1459 assert!(!table_options.contains_key(APPEND_MODE_KEY));
1460 }
1461
1462 #[test]
1463 fn test_last_non_null_create_options_use_last_row_with_append_mode_true() {
1464 let mut ctx = QueryContext::with(DEFAULT_CATALOG_NAME, DEFAULT_SCHEMA_NAME);
1465 ctx.set_extension(APPEND_MODE_KEY, "true");
1466 let ctx = Arc::new(ctx);
1467 let mut table_options = Default::default();
1468
1469 fill_table_options_for_create(&mut table_options, &AutoCreateTableType::LastNonNull, &ctx);
1470
1471 assert_eq!(
1472 Some("true"),
1473 table_options.get(APPEND_MODE_KEY).map(String::as_str)
1474 );
1475 assert_eq!(
1476 Some("last_row"),
1477 table_options.get(MERGE_MODE_KEY).map(String::as_str)
1478 );
1479 }
1480}