operator/req_convert/insert/
stmt_to_region.rs1use api::helper::{ColumnDataTypeWrapper, to_grpc_value};
16use api::v1::column_def::options_from_column_schema;
17use api::v1::region::InsertRequests as RegionInsertRequests;
18use api::v1::{ColumnSchema as GrpcColumnSchema, Row, Rows};
19use catalog::CatalogManager;
20use common_time::Timezone;
21use datatypes::schema::{ColumnSchema, SchemaRef};
22use datatypes::value::Value;
23use partition::manager::PartitionRuleManager;
24use session::context::{QueryContext, QueryContextRef};
25use snafu::{OptionExt, ResultExt, ensure};
26use sql::ast::ObjectNamePartExt;
27use sql::statements::insert::Insert;
28use sqlparser::ast::{ObjectName, Value as SqlValue};
29use table::TableRef;
30use table::metadata::TableInfoRef;
31
32use crate::error::{
33 CatalogSnafu, ColumnDataTypeSnafu, ColumnDefaultValueSnafu, ColumnNoneDefaultValueSnafu,
34 ColumnNotFoundSnafu, InvalidSqlSnafu, MissingInsertBodySnafu, ParseSqlSnafu, Result,
35 SchemaReadOnlySnafu, TableNotFoundSnafu, TableReadOnlySnafu,
36};
37use crate::insert::InstantAndNormalInsertRequests;
38use crate::req_convert::common::partitioner::Partitioner;
39use crate::req_convert::insert::semantic_type;
40
41const DEFAULT_PLACEHOLDER_VALUE: &str = "default";
42
43pub struct StatementToRegion<'a> {
44 catalog_manager: &'a dyn CatalogManager,
45 partition_manager: &'a PartitionRuleManager,
46 ctx: &'a QueryContext,
47}
48
49impl<'a> StatementToRegion<'a> {
50 pub fn new(
51 catalog_manager: &'a dyn CatalogManager,
52 partition_manager: &'a PartitionRuleManager,
53 ctx: &'a QueryContext,
54 ) -> Self {
55 Self {
56 catalog_manager,
57 partition_manager,
58 ctx,
59 }
60 }
61
62 pub async fn convert(
63 &self,
64 stmt: &Insert,
65 query_ctx: &QueryContextRef,
66 ) -> Result<(InstantAndNormalInsertRequests, TableInfoRef)> {
67 let (rows, table_info) = self.prepare(stmt, query_ctx).await?;
68 let requests = self.partition(rows, table_info.clone(), query_ctx).await?;
69 Ok((requests, table_info))
70 }
71
72 pub async fn partition(
74 &self,
75 rows: Rows,
76 table_info: TableInfoRef,
77 query_ctx: &QueryContextRef,
78 ) -> Result<InstantAndNormalInsertRequests> {
79 let requests = Partitioner::new(self.partition_manager)
80 .partition_insert_requests(&table_info, rows, query_ctx.skip_wal())
81 .await?;
82 let requests = RegionInsertRequests { requests };
83 if table_info.is_ttl_instant_table() {
84 Ok(InstantAndNormalInsertRequests {
85 normal_requests: Default::default(),
86 instant_requests: requests,
87 })
88 } else {
89 Ok(InstantAndNormalInsertRequests {
90 normal_requests: requests,
91 instant_requests: Default::default(),
92 })
93 }
94 }
95
96 pub async fn prepare(
98 &self,
99 stmt: &Insert,
100 query_ctx: &QueryContextRef,
101 ) -> Result<(Rows, TableInfoRef)> {
102 let name = stmt.table_name().context(ParseSqlSnafu)?;
103 let (catalog, schema, table_name) = self.get_full_name(name)?;
104 let table = self.get_table(&catalog, &schema, &table_name).await?;
105 let table_schema = table.schema();
106
107 ensure!(
108 !common_catalog::consts::is_readonly_schema(&schema),
109 SchemaReadOnlySnafu { name: schema }
110 );
111 ensure!(
114 !common_catalog::consts::is_readonly_table(&schema, &table_name),
115 TableReadOnlySnafu { name: table_name }
116 );
117
118 let column_names = column_names(stmt, &table_schema);
119 let column_count = column_names.len();
120
121 let sql_rows = stmt.values_body().context(MissingInsertBodySnafu)?;
122 let row_count = sql_rows.len();
123
124 sql_rows.iter().try_for_each(|r| {
125 ensure!(
126 r.len() == column_count,
127 InvalidSqlSnafu {
128 err_msg: format!(
129 "column count mismatch, columns: {}, values: {}",
130 column_count,
131 r.len()
132 )
133 }
134 );
135 Ok(())
136 })?;
137
138 let mut rows = vec![
139 Row {
140 values: Vec::with_capacity(column_count)
141 };
142 row_count
143 ];
144
145 fn find_insert_columns<'a>(
146 table: &'a TableRef,
147 column_names: &[&String],
148 ) -> Result<Vec<&'a ColumnSchema>> {
149 let schema = table.schema_ref();
150 column_names
151 .iter()
152 .map(|name| {
153 schema
154 .column_schema_by_name(name)
155 .context(ColumnNotFoundSnafu { msg: *name })
156 })
157 .collect::<Result<Vec<_>>>()
158 }
159
160 let insert_columns = find_insert_columns(&table, &column_names)?;
161 let converter = SqlRowConverter::new(&insert_columns, query_ctx);
162 let value_rows = converter.convert(&sql_rows)?;
163 for (i, row) in value_rows.into_iter().enumerate() {
164 for value in row {
165 let grpc_value = to_grpc_value(value);
166 rows[i].values.push(grpc_value);
167 }
168 }
169
170 let table_info = table.table_info();
171 let mut schema = Vec::with_capacity(column_count);
172 for column_schema in insert_columns {
173 let (datatype, datatype_extension) =
174 ColumnDataTypeWrapper::try_from(column_schema.data_type.clone())
175 .context(ColumnDataTypeSnafu)?
176 .to_parts();
177
178 let column_name = &column_schema.name;
179 let semantic_type = semantic_type(&table_info, column_name)?;
180
181 let grpc_column_schema = GrpcColumnSchema {
182 column_name: column_name.clone(),
183 datatype: datatype.into(),
184 semantic_type: semantic_type.into(),
185 datatype_extension,
186 options: options_from_column_schema(column_schema),
187 };
188 schema.push(grpc_column_schema);
189 }
190
191 Ok((Rows { schema, rows }, table_info))
192 }
193
194 async fn get_table(&self, catalog: &str, schema: &str, table: &str) -> Result<TableRef> {
195 self.catalog_manager
196 .table(catalog, schema, table, None)
197 .await
198 .context(CatalogSnafu)?
199 .with_context(|| TableNotFoundSnafu {
200 table_name: common_catalog::format_full_table_name(catalog, schema, table),
201 })
202 }
203
204 fn get_full_name(&self, obj_name: &ObjectName) -> Result<(String, String, String)> {
205 match &obj_name.0[..] {
206 [table] => Ok((
207 self.ctx.current_catalog().to_owned(),
208 self.ctx.current_schema(),
209 table.to_string_unquoted(),
210 )),
211 [schema, table] => Ok((
212 self.ctx.current_catalog().to_owned(),
213 schema.to_string_unquoted(),
214 table.to_string_unquoted(),
215 )),
216 [catalog, schema, table] => Ok((
217 catalog.to_string_unquoted(),
218 schema.to_string_unquoted(),
219 table.to_string_unquoted(),
220 )),
221 _ => InvalidSqlSnafu {
222 err_msg: format!(
223 "expect table name to be <catalog>.<schema>.<table>, <schema>.<table> or <table>, actual: {obj_name}",
224 ),
225 }.fail(),
226 }
227 }
228}
229
230struct SqlRowConverter<'a, 'b> {
231 insert_columns: &'a [&'a ColumnSchema],
232 query_context: &'b QueryContextRef,
233}
234
235impl<'a, 'b> SqlRowConverter<'a, 'b> {
236 fn new(insert_columns: &'a [&'a ColumnSchema], query_context: &'b QueryContextRef) -> Self {
237 Self {
238 insert_columns,
239 query_context,
240 }
241 }
242
243 fn convert(&self, sql_rows: &[Vec<SqlValue>]) -> Result<Vec<Vec<Value>>> {
244 let timezone = Some(&self.query_context.timezone());
245 let auto_string_to_numeric = self.query_context.auto_string_to_numeric();
246
247 let mut value_rows = Vec::with_capacity(sql_rows.len());
248 for sql_row in sql_rows {
249 let mut value_row = Vec::with_capacity(self.insert_columns.len());
250
251 for (insert_column, sql_value) in self.insert_columns.iter().zip(sql_row) {
252 let value =
253 sql_value_to_value(insert_column, sql_value, timezone, auto_string_to_numeric)?;
254 value_row.push(value);
255 }
256 value_rows.push(value_row);
257 }
258 Ok(value_rows)
259 }
260}
261
262fn column_names<'a>(stmt: &'a Insert, table_schema: &'a SchemaRef) -> Vec<&'a String> {
263 if !stmt.columns().is_empty() {
264 stmt.columns()
265 } else {
266 table_schema
267 .column_schemas()
268 .iter()
269 .map(|column| &column.name)
270 .collect()
271 }
272}
273
274fn sql_value_to_value(
278 column_schema: &ColumnSchema,
279 sql_val: &SqlValue,
280 timezone: Option<&Timezone>,
281 auto_string_to_numeric: bool,
282) -> Result<Value> {
283 let column = &column_schema.name;
284 let value = if replace_default(sql_val) {
285 let default_value = column_schema
286 .create_default()
287 .context(ColumnDefaultValueSnafu {
288 column: column.clone(),
289 })?;
290
291 default_value.context(ColumnNoneDefaultValueSnafu {
292 column: column.clone(),
293 })?
294 } else {
295 common_sql::convert::sql_value_to_value(
296 column_schema,
297 sql_val,
298 timezone,
299 None,
300 auto_string_to_numeric,
301 )
302 .context(crate::error::SqlCommonSnafu)?
303 };
304 Ok(value)
305}
306
307fn replace_default(sql_val: &SqlValue) -> bool {
308 matches!(sql_val, SqlValue::Placeholder(s) if s.to_lowercase() == DEFAULT_PLACEHOLDER_VALUE)
309}