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