Skip to main content

servers/
row_writer.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use 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
34/// The intermediate data structure for building the write request.
35/// It constructs the `schema` and `rows` as all input data row
36/// parsing is completed.
37pub 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    /// Writes a field value without enforcing that later writes use the same datatype
104    /// as the first-seen schema entry.
105    ///
106    /// The OTLP trace v1 path uses this to preserve raw mixed values inside one request
107    /// so the frontend can reconcile them later against both the full batch and the
108    /// existing table schema.
109    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    /// Returns the request and number of rows in it.
185    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
212/// Write data as tags into the table data.
213pub 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
222/// Write data as fields into the table data.
223pub 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
231/// Write data as a tag into the table data.
232pub 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
250/// Write float64 data as a field into the table data.
251pub 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
361/// Write timestamp data as milliseconds into the table data.
362pub 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
379/// Write timestamp data as nanoseconds into the table data.
380pub 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}