1use std::collections::HashMap;
16
17use api::v1::column_data_type_extension::TypeExt;
18use api::v1::helper::time_index_column_schema;
19use api::v1::value::ValueData;
20use api::v1::{
21 ColumnDataType, ColumnDataTypeExtension, ColumnSchema, JsonTypeExtension, Row,
22 RowInsertRequest, RowInsertRequests, Rows, SemanticType, Value,
23};
24use common_grpc::precision::Precision;
25use common_time::Timestamp;
26use common_time::timestamp::TimeUnit;
27use common_time::timestamp::TimeUnit::Nanosecond;
28use snafu::{OptionExt, ResultExt, ensure};
29
30use crate::error::{
31 IncompatibleSchemaSnafu, Result, RowWriterSnafu, TimePrecisionSnafu, TimestampOverflowSnafu,
32};
33
34pub struct TableData {
38 schema: Vec<ColumnSchema>,
39 rows: Vec<Row>,
40 column_indexes: HashMap<String, usize>,
41}
42
43impl TableData {
44 pub fn new(num_columns: usize, num_rows: usize) -> Self {
45 Self {
46 schema: Vec::with_capacity(num_columns),
47 rows: Vec::with_capacity(num_rows),
48 column_indexes: HashMap::with_capacity(num_columns),
49 }
50 }
51
52 #[inline]
53 pub fn num_columns(&self) -> usize {
54 self.schema.len()
55 }
56
57 #[inline]
58 pub fn num_rows(&self) -> usize {
59 self.rows.len()
60 }
61
62 #[inline]
63 pub fn alloc_one_row(&self) -> Vec<Value> {
64 vec![Value { value_data: None }; self.num_columns()]
65 }
66
67 #[inline]
68 pub fn add_row(&mut self, values: Vec<Value>) {
69 self.rows.push(Row { values })
70 }
71
72 #[inline]
73 pub fn reserve_rows(&mut self, additional: usize) {
74 self.rows.reserve(additional);
75 }
76
77 pub(crate) fn ensure_column(&mut self, column_schema: ColumnSchema) -> Result<usize> {
78 if let Some(index) = self.column_indexes.get(&column_schema.column_name).copied() {
79 check_schema_number(
80 column_schema.datatype,
81 column_schema.semantic_type,
82 &self.schema[index],
83 )?;
84 return Ok(index);
85 }
86
87 let index = self.schema.len();
88 let name = column_schema.column_name.clone();
89 self.schema.push(column_schema);
90 self.column_indexes.insert(name, index);
91 Ok(index)
92 }
93
94 #[allow(dead_code)]
95 pub fn columns(&self) -> &Vec<ColumnSchema> {
96 &self.schema
97 }
98
99 pub fn into_schema_and_rows(self) -> (Vec<ColumnSchema>, Vec<Row>) {
100 (self.schema, self.rows)
101 }
102
103 pub fn write_field_unchecked(
110 &mut self,
111 name: impl ToString,
112 datatype: ColumnDataType,
113 value: Option<ValueData>,
114 one_row: &mut Vec<Value>,
115 ) {
116 self.write_column_unchecked(
117 ColumnSchema {
118 column_name: name.to_string(),
119 datatype: datatype as i32,
120 semantic_type: SemanticType::Field as i32,
121 ..Default::default()
122 },
123 value,
124 one_row,
125 );
126 }
127
128 pub fn write_column_unchecked(
129 &mut self,
130 column_schema: ColumnSchema,
131 value: Option<ValueData>,
132 one_row: &mut Vec<Value>,
133 ) {
134 if let Some(index) = self.column_indexes.get(&column_schema.column_name).copied() {
135 one_row[index].value_data = value;
136 } else {
137 let index = self.schema.len();
138 let name = column_schema.column_name.clone();
139 self.schema.push(column_schema);
140 self.column_indexes.insert(name, index);
141 one_row.push(Value { value_data: value });
142 }
143 }
144}
145
146pub struct MultiTableData {
147 table_data_map: HashMap<String, TableData>,
148}
149
150impl Default for MultiTableData {
151 fn default() -> Self {
152 Self::new()
153 }
154}
155
156impl MultiTableData {
157 pub fn new() -> Self {
158 Self {
159 table_data_map: HashMap::new(),
160 }
161 }
162
163 pub fn get_or_default_table_data(
164 &mut self,
165 table_name: impl ToString,
166 num_columns: usize,
167 num_rows: usize,
168 ) -> &mut TableData {
169 self.table_data_map
170 .entry(table_name.to_string())
171 .or_insert_with(|| TableData::new(num_columns, num_rows))
172 }
173
174 pub fn add_table_data(&mut self, table_name: impl ToString, table_data: TableData) {
175 self.table_data_map
176 .insert(table_name.to_string(), table_data);
177 }
178
179 #[allow(dead_code)]
180 pub fn num_tables(&self) -> usize {
181 self.table_data_map.len()
182 }
183
184 pub fn into_row_insert_requests(self) -> (RowInsertRequests, usize) {
186 let mut total_rows = 0;
187 let inserts = self
188 .table_data_map
189 .into_iter()
190 .map(|(table_name, table_data)| {
191 total_rows += table_data.num_rows();
192 let num_columns = table_data.num_columns();
193 let (schema, mut rows) = table_data.into_schema_and_rows();
194 for row in &mut rows {
195 if num_columns > row.values.len() {
196 row.values.resize(num_columns, Value { value_data: None });
197 }
198 }
199
200 RowInsertRequest {
201 table_name,
202 rows: Some(Rows { schema, rows }),
203 }
204 })
205 .collect::<Vec<_>>();
206 let row_insert_requests = RowInsertRequests { inserts };
207
208 (row_insert_requests, total_rows)
209 }
210}
211
212pub fn write_tags(
214 table_data: &mut TableData,
215 tags: impl Iterator<Item = (String, String)>,
216 one_row: &mut Vec<Value>,
217) -> Result<()> {
218 let ktv_iter = tags.map(|(k, v)| (k, ColumnDataType::String, Some(ValueData::StringValue(v))));
219 write_by_semantic_type(table_data, SemanticType::Tag, ktv_iter, one_row)
220}
221
222pub fn write_fields(
224 table_data: &mut TableData,
225 fields: impl Iterator<Item = (String, ColumnDataType, Option<ValueData>)>,
226 one_row: &mut Vec<Value>,
227) -> Result<()> {
228 write_by_semantic_type(table_data, SemanticType::Field, fields, one_row)
229}
230
231pub fn write_tag(
233 table_data: &mut TableData,
234 name: impl ToString,
235 value: impl ToString,
236 one_row: &mut Vec<Value>,
237) -> Result<()> {
238 write_by_semantic_type(
239 table_data,
240 SemanticType::Tag,
241 std::iter::once((
242 name.to_string(),
243 ColumnDataType::String,
244 Some(ValueData::StringValue(value.to_string())),
245 )),
246 one_row,
247 )
248}
249
250pub fn write_f64(
252 table_data: &mut TableData,
253 name: impl ToString,
254 value: f64,
255 one_row: &mut Vec<Value>,
256) -> Result<()> {
257 write_fields(
258 table_data,
259 std::iter::once((
260 name.to_string(),
261 ColumnDataType::Float64,
262 Some(ValueData::F64Value(value)),
263 )),
264 one_row,
265 )
266}
267
268pub(crate) fn build_json_column_schema(name: impl ToString) -> ColumnSchema {
269 ColumnSchema {
270 column_name: name.to_string(),
271 datatype: ColumnDataType::Binary as i32,
272 semantic_type: SemanticType::Field as i32,
273 datatype_extension: Some(ColumnDataTypeExtension {
274 type_ext: Some(TypeExt::JsonType(JsonTypeExtension::JsonBinary.into())),
275 }),
276 ..Default::default()
277 }
278}
279
280pub fn write_json(
281 table_data: &mut TableData,
282 name: impl ToString,
283 value: jsonb::Value,
284 one_row: &mut Vec<Value>,
285) -> Result<()> {
286 write_by_schema(
287 table_data,
288 std::iter::once((
289 build_json_column_schema(name),
290 Some(ValueData::BinaryValue(value.to_vec())),
291 )),
292 one_row,
293 )
294}
295
296pub(crate) fn write_by_schema(
297 table_data: &mut TableData,
298 kv_iter: impl Iterator<Item = (ColumnSchema, Option<ValueData>)>,
299 one_row: &mut Vec<Value>,
300) -> Result<()> {
301 let TableData {
302 schema,
303 column_indexes,
304 ..
305 } = table_data;
306
307 for (column_schema, value) in kv_iter {
308 let index = column_indexes.get(&column_schema.column_name);
309 if let Some(index) = index {
310 check_schema_number(
311 column_schema.datatype,
312 column_schema.semantic_type,
313 &schema[*index],
314 )?;
315 one_row[*index].value_data = value;
316 } else {
317 let index = schema.len();
318 let key = column_schema.column_name.clone();
319 schema.push(column_schema);
320 column_indexes.insert(key, index);
321 one_row.push(Value { value_data: value });
322 }
323 }
324
325 Ok(())
326}
327
328fn write_by_semantic_type(
329 table_data: &mut TableData,
330 semantic_type: SemanticType,
331 ktv_iter: impl Iterator<Item = (String, ColumnDataType, Option<ValueData>)>,
332 one_row: &mut Vec<Value>,
333) -> Result<()> {
334 let TableData {
335 schema,
336 column_indexes,
337 ..
338 } = table_data;
339
340 for (name, datatype, value) in ktv_iter {
341 let index = column_indexes.get(&name);
342 if let Some(index) = index {
343 check_schema(datatype, semantic_type, &schema[*index])?;
344 one_row[*index].value_data = value;
345 } else {
346 let index = schema.len();
347 schema.push(ColumnSchema {
348 column_name: name.clone(),
349 datatype: datatype as i32,
350 semantic_type: semantic_type as i32,
351 ..Default::default()
352 });
353 column_indexes.insert(name, index);
354 one_row.push(Value { value_data: value });
355 }
356 }
357
358 Ok(())
359}
360
361pub fn write_ts_to_millis(
363 table_data: &mut TableData,
364 name: impl ToString,
365 ts: Option<i64>,
366 precision: Precision,
367 one_row: &mut Vec<Value>,
368) -> Result<()> {
369 write_ts_to(
370 table_data,
371 name,
372 ts,
373 precision,
374 TimestampType::Millis,
375 one_row,
376 )
377}
378
379pub fn write_ts_to_nanos(
381 table_data: &mut TableData,
382 name: impl ToString,
383 ts: Option<i64>,
384 precision: Precision,
385 one_row: &mut Vec<Value>,
386) -> Result<()> {
387 write_ts_to(
388 table_data,
389 name,
390 ts,
391 precision,
392 TimestampType::Nanos,
393 one_row,
394 )
395}
396
397enum TimestampType {
398 Millis,
399 Nanos,
400}
401
402fn write_ts_to(
403 table_data: &mut TableData,
404 name: impl ToString,
405 ts: Option<i64>,
406 precision: Precision,
407 ts_type: TimestampType,
408 one_row: &mut Vec<Value>,
409) -> Result<()> {
410 let TableData {
411 schema,
412 column_indexes,
413 ..
414 } = table_data;
415 let name = name.to_string();
416
417 let ts = match ts {
418 Some(timestamp) => match ts_type {
419 TimestampType::Millis => precision.to_millis(timestamp),
420 TimestampType::Nanos => precision.to_nanos(timestamp),
421 }
422 .with_context(|| TimestampOverflowSnafu {
423 error: format!(
424 "timestamp {} overflow with precision {}",
425 timestamp, precision
426 ),
427 })?,
428 None => {
429 let timestamp = Timestamp::current_time(Nanosecond);
430 let unit: TimeUnit = precision.try_into().context(RowWriterSnafu)?;
431 let timestamp = timestamp
432 .convert_to(unit)
433 .with_context(|| TimePrecisionSnafu {
434 name: precision.to_string(),
435 })?
436 .into();
437 match ts_type {
438 TimestampType::Millis => precision.to_millis(timestamp),
439 TimestampType::Nanos => precision.to_nanos(timestamp),
440 }
441 .with_context(|| TimestampOverflowSnafu {
442 error: format!(
443 "timestamp {} overflow with precision {}",
444 timestamp, precision
445 ),
446 })?
447 }
448 };
449
450 let (datatype, ts) = match ts_type {
451 TimestampType::Millis => (
452 ColumnDataType::TimestampMillisecond,
453 ValueData::TimestampMillisecondValue(ts),
454 ),
455 TimestampType::Nanos => (
456 ColumnDataType::TimestampNanosecond,
457 ValueData::TimestampNanosecondValue(ts),
458 ),
459 };
460
461 let index = column_indexes.get(&name);
462 if let Some(index) = index {
463 check_schema(datatype, SemanticType::Timestamp, &schema[*index])?;
464 one_row[*index].value_data = Some(ts);
465 } else {
466 let index = schema.len();
467 schema.push(time_index_column_schema(&name, datatype));
468 column_indexes.insert(name, index);
469 one_row.push(ts.into())
470 }
471
472 Ok(())
473}
474
475fn check_schema(
476 datatype: ColumnDataType,
477 semantic_type: SemanticType,
478 schema: &ColumnSchema,
479) -> Result<()> {
480 check_schema_number(datatype as i32, semantic_type as i32, schema)
481}
482
483fn check_schema_number(datatype: i32, semantic_type: i32, schema: &ColumnSchema) -> Result<()> {
484 ensure!(
485 schema.datatype == datatype,
486 IncompatibleSchemaSnafu {
487 column_name: &schema.column_name,
488 datatype: "datatype",
489 expected: schema.datatype,
490 actual: datatype,
491 }
492 );
493
494 ensure!(
495 schema.semantic_type == semantic_type,
496 IncompatibleSchemaSnafu {
497 column_name: &schema.column_name,
498 datatype: "semantic_type",
499 expected: schema.semantic_type,
500 actual: semantic_type,
501 }
502 );
503
504 Ok(())
505}