feat: frontend instance (#238)

* feat: frontend instance

* no need to carry column length in `Column` proto

* add more tests

* rebase develop

* create a new variant with already provisioned RecordBatches in Output

* resolve code review comments

* new frontend instance does not connect datanode grpc

* add more tests

* add more tests

* rebase develop

Co-authored-by: luofucong <luofucong@greptime.com>
This commit is contained in:
LFC
2022-09-13 17:10:22 +08:00
committed by GitHub
parent bdd5bdd917
commit ec99eb0cd0
71 changed files with 2324 additions and 362 deletions

View File

@@ -159,12 +159,6 @@ pub enum Error {
source: datatypes::error::Error,
},
#[snafu(display("SQL data type not supported yet: {:?}", t))]
SqlTypeNotSupported {
t: sql::ast::DataType,
backtrace: Backtrace,
},
#[snafu(display("Specified timestamp key or primary key column not found: {}", name))]
KeyColumnNotFound { name: String, backtrace: Backtrace },
@@ -189,8 +183,17 @@ pub enum Error {
source: common_grpc::Error,
},
#[snafu(display("Invalid ColumnDef in protobuf msg: {}", msg))]
InvalidColumnDef { msg: String, backtrace: Backtrace },
#[snafu(display("Column datatype error, source: {}", source))]
ColumnDataType {
#[snafu(backtrace)]
source: api::error::Error,
},
#[snafu(display("Failed to parse SQL, source: {}", source))]
ParseSql {
#[snafu(backtrace)]
source: sql::error::Error,
},
#[snafu(display("Failed to start script manager, source: {}", source))]
StartScriptManager {
@@ -220,12 +223,10 @@ impl ErrorExt for Error {
| Error::IllegalInsertData { .. }
| Error::DecodeInsert { .. }
| Error::InvalidSql { .. }
| Error::SqlTypeNotSupported { .. }
| Error::CreateSchema { .. }
| Error::KeyColumnNotFound { .. }
| Error::MissingField { .. }
| Error::ConstraintNotSupported { .. }
| Error::InvalidColumnDef { .. } => StatusCode::InvalidArguments,
| Error::ConstraintNotSupported { .. } => StatusCode::InvalidArguments,
// TODO(yingwen): Further categorize http error.
Error::StartServer { .. }
| Error::ParseAddr { .. }
@@ -235,7 +236,9 @@ impl ErrorExt for Error {
| Error::InsertSystemCatalog { .. }
| Error::Conversion { .. }
| Error::IntoPhysicalPlan { .. }
| Error::UnsupportedExpr { .. } => StatusCode::Internal,
| Error::UnsupportedExpr { .. }
| Error::ColumnDataType { .. } => StatusCode::Internal,
Error::ParseSql { source } => source.status_code(),
Error::InitBackend { .. } => StatusCode::StorageUnavailable,
Error::OpenLogStore { source } => source.status_code(),
Error::StartScriptManager { source } => source.status_code(),

View File

@@ -1,7 +1,7 @@
use std::{fs, path, sync::Arc};
use api::v1::{
admin_expr, object_expr, select_expr, AdminExpr, AdminResult, InsertExpr, ObjectExpr,
admin_expr, insert_expr, object_expr, select_expr, AdminExpr, AdminResult, ObjectExpr,
ObjectResult, SelectExpr,
};
use async_trait::async_trait;
@@ -81,7 +81,11 @@ impl Instance {
})
}
pub async fn execute_grpc_insert(&self, insert_expr: InsertExpr) -> Result<Output> {
pub async fn execute_grpc_insert(
&self,
table_name: &str,
values: insert_expr::Values,
) -> Result<Output> {
let schema_provider = self
.catalog_manager
.catalog(DEFAULT_CATALOG_NAME)
@@ -89,12 +93,11 @@ impl Instance {
.schema(DEFAULT_SCHEMA_NAME)
.unwrap();
let table_name = &insert_expr.table_name.clone();
let table = schema_provider
.table(table_name)
.context(TableNotFoundSnafu { table_name })?;
let insert = insertion_expr_to_request(insert_expr, table.clone())?;
let insert = insertion_expr_to_request(table_name, values, table.clone())?;
let affected_rows = table
.insert(insert)
@@ -167,8 +170,8 @@ impl Instance {
Ok(())
}
async fn handle_insert(&self, insert_expr: InsertExpr) -> ObjectResult {
match self.execute_grpc_insert(insert_expr).await {
async fn handle_insert(&self, table_name: &str, values: insert_expr::Values) -> ObjectResult {
match self.execute_grpc_insert(table_name, values).await {
Ok(Output::AffectedRows(rows)) => ObjectResultBuilder::new()
.status_code(StatusCode::Success as u32)
.mutate_result(rows as u32, 0)
@@ -289,6 +292,7 @@ async fn create_local_file_log_store(opts: &DatanodeOptions) -> Result<LocalFile
Ok(log_store)
}
// TODO(LFC): Refactor datanode and frontend instances, separate impl for each query handler.
#[async_trait]
impl SqlQueryHandler for Instance {
async fn do_query(&self, query: &str) -> servers::error::Result<Output> {
@@ -315,7 +319,23 @@ impl SqlQueryHandler for Instance {
impl GrpcQueryHandler for Instance {
async fn do_query(&self, query: ObjectExpr) -> servers::error::Result<ObjectResult> {
let object_resp = match query.expr {
Some(object_expr::Expr::Insert(insert_expr)) => self.handle_insert(insert_expr).await,
Some(object_expr::Expr::Insert(insert_expr)) => {
let table_name = &insert_expr.table_name;
let expr = insert_expr
.expr
.context(servers::error::InvalidQuerySnafu {
reason: "missing `expr` in `InsertExpr`",
})?;
match expr {
insert_expr::Expr::Values(values) => {
self.handle_insert(table_name, values).await
}
insert_expr::Expr::Sql(sql) => {
let output = self.execute_sql(&sql).await;
to_object_result(output).await
}
}
}
Some(object_expr::Expr::Select(select_expr)) => self.handle_select(select_expr).await,
other => {
return servers::error::NotSupportedSnafu {

View File

@@ -2,4 +2,4 @@ mod ddl;
pub(crate) mod handler;
pub(crate) mod insert;
pub(crate) mod plan;
pub(crate) mod select;
pub mod select;

View File

@@ -1,8 +1,8 @@
use std::sync::Arc;
use api::v1::{alter_expr::Kind, AdminResult, AlterExpr, ColumnDataType, ColumnDef, CreateExpr};
use api::helper::ColumnDataTypeWrapper;
use api::v1::{alter_expr::Kind, AdminResult, AlterExpr, ColumnDef, CreateExpr};
use common_error::prelude::{ErrorExt, StatusCode};
use datatypes::prelude::*;
use datatypes::schema::{ColumnSchema, SchemaBuilder, SchemaRef};
use futures::TryFutureExt;
use query::Output;
@@ -26,7 +26,7 @@ impl Instance {
.mutate_result(rows as u32, 0)
.build(),
// Unreachable because we are executing "CREATE TABLE"; otherwise it's an internal bug.
Ok(Output::RecordBatch(_)) => unreachable!(),
Ok(Output::Stream(_)) | Ok(Output::RecordBatches(_)) => unreachable!(),
Err(err) => AdminResultBuilder::default()
.status_code(err.status_code() as u32)
.err_msg(err.to_string())
@@ -53,7 +53,7 @@ impl Instance {
.status_code(StatusCode::Success as u32)
.mutate_result(rows as u32, 0)
.build(),
Ok(Output::RecordBatch(_)) => unreachable!(),
Ok(Output::Stream(_)) | Ok(Output::RecordBatches(_)) => unreachable!(),
Err(err) => AdminResultBuilder::default()
.status_code(err.status_code() as u32)
.err_msg(err.to_string())
@@ -140,30 +140,10 @@ fn create_table_schema(expr: &CreateExpr) -> Result<SchemaRef> {
fn create_column_schema(column_def: &ColumnDef) -> Result<ColumnSchema> {
let data_type =
ColumnDataType::from_i32(column_def.data_type).context(error::InvalidColumnDefSnafu {
msg: format!("unknown ColumnDataType {}", column_def.data_type),
})?;
let data_type = match data_type {
ColumnDataType::Boolean => ConcreteDataType::boolean_datatype(),
ColumnDataType::Int8 => ConcreteDataType::int8_datatype(),
ColumnDataType::Int16 => ConcreteDataType::int16_datatype(),
ColumnDataType::Int32 => ConcreteDataType::int32_datatype(),
ColumnDataType::Int64 => ConcreteDataType::int64_datatype(),
ColumnDataType::Uint8 => ConcreteDataType::uint8_datatype(),
ColumnDataType::Uint16 => ConcreteDataType::uint16_datatype(),
ColumnDataType::Uint32 => ConcreteDataType::uint32_datatype(),
ColumnDataType::Uint64 => ConcreteDataType::uint64_datatype(),
ColumnDataType::Float32 => ConcreteDataType::float32_datatype(),
ColumnDataType::Float64 => ConcreteDataType::float64_datatype(),
ColumnDataType::Binary => ConcreteDataType::binary_datatype(),
ColumnDataType::String => ConcreteDataType::string_datatype(),
ColumnDataType::Date => ConcreteDataType::date_datatype(),
ColumnDataType::Datetime => ConcreteDataType::datetime_datatype(),
ColumnDataType::Timestamp => ConcreteDataType::timestamp_millis_datatype(),
};
ColumnDataTypeWrapper::try_new(column_def.data_type).context(error::ColumnDataTypeSnafu)?;
Ok(ColumnSchema {
name: column_def.name.clone(),
data_type,
data_type: data_type.into(),
is_nullable: column_def.is_nullable,
})
}
@@ -173,6 +153,7 @@ mod tests {
use std::collections::HashMap;
use catalog::MIN_USER_TABLE_ID;
use datatypes::prelude::ConcreteDataType;
use super::*;
use crate::tests::test_util;
@@ -228,10 +209,10 @@ mod tests {
};
let result = create_column_schema(&column_def);
assert!(result.is_err());
assert!(result
.unwrap_err()
.to_string()
.contains("Invalid ColumnDef in protobuf msg: unknown ColumnDataType 1024"));
assert_eq!(
result.unwrap_err().to_string(),
"Column datatype error, source: Unknown proto column datatype: 1024"
);
let column_def = ColumnDef {
name: "a".to_string(),

View File

@@ -4,7 +4,7 @@ use std::{
sync::Arc,
};
use api::v1::{codec::InsertBatch, column::Values, Column, InsertExpr};
use api::v1::{codec::InsertBatch, column::Values, insert_expr, Column};
use common_base::BitVec;
use common_time::timestamp::Timestamp;
use datatypes::{data_type::ConcreteDataType, value::Value, vectors::VectorBuilder};
@@ -14,13 +14,13 @@ use table::{requests::InsertRequest, Table};
use crate::error::{ColumnNotFoundSnafu, DecodeInsertSnafu, IllegalInsertDataSnafu, Result};
pub fn insertion_expr_to_request(
insert: InsertExpr,
table_name: &str,
values: insert_expr::Values,
table: Arc<dyn Table>,
) -> Result<InsertRequest> {
let schema = table.schema();
let table_name = &insert.table_name;
let mut columns_builders = HashMap::with_capacity(schema.column_schemas().len());
let insert_batches = insert_batches(insert.values)?;
let insert_batches = insert_batches(values.values)?;
for InsertBatch { columns, row_count } in insert_batches {
for Column {
@@ -182,7 +182,7 @@ fn convert_values(data_type: &ConcreteDataType, values: Values) -> Vec<Value> {
.map(|v| Value::Date(v.into()))
.collect(),
ConcreteDataType::Timestamp(_) => values
.i64_values
.ts_millis_values
.into_iter()
.map(|v| Value::Timestamp(Timestamp::from_millis(v)))
.collect(),
@@ -202,7 +202,7 @@ mod tests {
use api::v1::{
codec::InsertBatch,
column::{self, Values},
Column, InsertExpr,
insert_expr, Column,
};
use common_base::BitVec;
use common_query::prelude::Expr;
@@ -219,13 +219,12 @@ mod tests {
#[test]
fn test_insertion_expr_to_request() {
let insert_expr = InsertExpr {
table_name: "demo".to_string(),
values: mock_insert_batches(),
};
let table: Arc<dyn Table> = Arc::new(DemoTable {});
let insert_req = insertion_expr_to_request(insert_expr, table).unwrap();
let values = insert_expr::Values {
values: mock_insert_batches(),
};
let insert_req = insertion_expr_to_request("demo", values, table).unwrap();
assert_eq!("demo", insert_req.table_name);
@@ -329,6 +328,7 @@ mod tests {
semantic_type: SEMANTIC_TAG,
values: Some(host_vals),
null_mask: vec![0],
..Default::default()
};
let cpu_vals = column::Values {
@@ -340,6 +340,7 @@ mod tests {
semantic_type: SEMANTIC_FEILD,
values: Some(cpu_vals),
null_mask: vec![2],
..Default::default()
};
let mem_vals = column::Values {
@@ -351,6 +352,7 @@ mod tests {
semantic_type: SEMANTIC_FEILD,
values: Some(mem_vals),
null_mask: vec![1],
..Default::default()
};
let ts_vals = column::Values {
@@ -362,6 +364,7 @@ mod tests {
semantic_type: SEMANTIC_TS,
values: Some(ts_vals),
null_mask: vec![0],
..Default::default()
};
let insert_batch = InsertBatch {

View File

@@ -1,5 +1,6 @@
use std::sync::Arc;
use api::helper::ColumnDataTypeWrapper;
use api::v1::{codec::SelectResult, column::Values, Column, ObjectResult};
use arrow::array::{Array, BooleanArray, PrimitiveArray};
use common_base::BitVec;
@@ -8,9 +9,9 @@ use common_error::status_code::StatusCode;
use common_recordbatch::{util, RecordBatch, SendableRecordBatchStream};
use datatypes::arrow_array::{BinaryArray, StringArray};
use query::Output;
use snafu::OptionExt;
use snafu::{OptionExt, ResultExt};
use crate::error::{ConversionSnafu, Result};
use crate::error::{self, ConversionSnafu, Result};
use crate::server::grpc::handler::{build_err_result, ObjectResultBuilder};
pub async fn to_object_result(result: Result<Output>) -> ObjectResult {
@@ -19,7 +20,8 @@ pub async fn to_object_result(result: Result<Output>) -> ObjectResult {
.status_code(StatusCode::Success as u32)
.mutate_result(rows as u32, 0)
.build(),
Ok(Output::RecordBatch(stream)) => record_batchs(stream).await,
Ok(Output::Stream(stream)) => record_batchs(stream).await,
Ok(Output::RecordBatches(recordbatches)) => build_result(recordbatches.to_vec()).await,
Err(err) => ObjectResultBuilder::new()
.status_code(err.status_code() as u32)
.err_msg(err.to_string())
@@ -28,15 +30,18 @@ pub async fn to_object_result(result: Result<Output>) -> ObjectResult {
}
async fn record_batchs(stream: SendableRecordBatchStream) -> ObjectResult {
let builder = ObjectResultBuilder::new();
match util::collect(stream).await {
Ok(record_batches) => match try_convert(record_batches) {
Ok(select_result) => builder
.status_code(StatusCode::Success as u32)
.select_result(select_result)
.build(),
Err(err) => build_err_result(&err),
},
Ok(recordbatches) => build_result(recordbatches).await,
Err(err) => build_err_result(&err),
}
}
async fn build_result(recordbatches: Vec<RecordBatch>) -> ObjectResult {
match try_convert(recordbatches) {
Ok(select_result) => ObjectResultBuilder::new()
.status_code(StatusCode::Success as u32)
.select_result(select_result)
.build(),
Err(err) => build_err_result(&err),
}
}
@@ -69,6 +74,9 @@ fn try_convert(record_batches: Vec<RecordBatch>) -> Result<SelectResult> {
column_name,
values: Some(values(&arrays)?),
null_mask: null_mask(&arrays, row_count),
datatype: ColumnDataTypeWrapper::try_from(schema.data_type.clone())
.context(error::ColumnDataTypeSnafu)?
.datatype() as i32,
..Default::default()
};
columns.push(column);
@@ -80,7 +88,7 @@ fn try_convert(record_batches: Vec<RecordBatch>) -> Result<SelectResult> {
})
}
fn null_mask(arrays: &Vec<Arc<dyn Array>>, row_count: usize) -> Vec<u8> {
pub fn null_mask(arrays: &Vec<Arc<dyn Array>>, row_count: usize) -> Vec<u8> {
let null_count: usize = arrays.iter().map(|a| a.null_count()).sum();
if null_count == 0 {
@@ -123,7 +131,7 @@ macro_rules! convert_arrow_array_to_grpc_vals {
}
fn values(arrays: &[Arc<dyn Array>]) -> Result<Values> {
pub fn values(arrays: &[Arc<dyn Array>]) -> Result<Values> {
if arrays.is_empty() {
return Ok(Values::default());
}
@@ -153,10 +161,11 @@ fn values(arrays: &[Arc<dyn Array>]) -> Result<Values> {
(DataType::Utf8, StringArray, string_values, |x| {x.into()}),
(DataType::LargeUtf8, StringArray, string_values, |x| {x.into()}),
(DataType::Date32, PrimitiveArray<i32>, i32_values, |x| {*x as i32}),
(DataType::Date64, PrimitiveArray<i64>, i64_values, |x| {*x as i64}),
(DataType::Timestamp(arrow::datatypes::TimeUnit::Millisecond, _), PrimitiveArray<i64>, i64_values, |x| {*x} )
(DataType::Date32, PrimitiveArray<i32>, date_values, |x| {*x as i32}),
(DataType::Date64, PrimitiveArray<i64>, datetime_values,|x| {*x as i64}),
(DataType::Timestamp(arrow::datatypes::TimeUnit::Millisecond, _), PrimitiveArray<i64>, ts_millis_values, |x| {*x})
)
}

View File

@@ -1,17 +1,13 @@
//! sql handler
use catalog::CatalogManagerRef;
use datatypes::prelude::ConcreteDataType;
use datatypes::schema::ColumnSchema;
use datatypes::types::DateTimeType;
use query::query_engine::Output;
use snafu::{OptionExt, ResultExt};
use sql::ast::{ColumnDef, ColumnOption, DataType as SqlDataType, ObjectName};
use table::engine::{EngineContext, TableEngineRef};
use table::requests::*;
use table::TableRef;
use crate::error::{self, GetTableSnafu, Result, TableNotFoundSnafu};
use crate::error::{GetTableSnafu, Result, TableNotFoundSnafu};
mod alter;
mod create;
@@ -58,77 +54,6 @@ impl SqlHandler {
}
}
/// Converts maybe fully-qualified table name (`<catalog>.<schema>.<table>` or `<table>` when
/// catalog and schema are default) to tuple.
fn table_idents_to_full_name(
obj_name: &ObjectName,
) -> Result<(Option<String>, Option<String>, String)> {
match &obj_name.0[..] {
[table] => Ok((None, None, table.value.clone())),
[catalog, schema, table] => Ok((
Some(catalog.value.clone()),
Some(schema.value.clone()),
table.value.clone(),
)),
_ => error::InvalidSqlSnafu {
msg: format!(
"expect table name to be <catalog>.<schema>.<table> or <table>, actual: {}",
obj_name
),
}
.fail(),
}
}
fn column_def_to_schema(column_def: &ColumnDef) -> Result<ColumnSchema> {
let is_nullable = column_def
.options
.iter()
.any(|o| matches!(o.option, ColumnOption::Null));
Ok(ColumnSchema {
name: column_def.name.value.clone(),
data_type: sql_data_type_to_concrete_data_type(&column_def.data_type)?,
is_nullable,
})
}
fn sql_data_type_to_concrete_data_type(data_type: &SqlDataType) -> Result<ConcreteDataType> {
match data_type {
SqlDataType::BigInt(_) => Ok(ConcreteDataType::int64_datatype()),
SqlDataType::Int(_) => Ok(ConcreteDataType::int32_datatype()),
SqlDataType::SmallInt(_) => Ok(ConcreteDataType::int16_datatype()),
SqlDataType::Char(_)
| SqlDataType::Varchar(_)
| SqlDataType::Text
| SqlDataType::String => Ok(ConcreteDataType::string_datatype()),
SqlDataType::Float(_) => Ok(ConcreteDataType::float32_datatype()),
SqlDataType::Double => Ok(ConcreteDataType::float64_datatype()),
SqlDataType::Boolean => Ok(ConcreteDataType::boolean_datatype()),
SqlDataType::Date => Ok(ConcreteDataType::date_datatype()),
SqlDataType::Custom(obj_name) => match &obj_name.0[..] {
[type_name] => {
if type_name.value.eq_ignore_ascii_case(DateTimeType::name()) {
Ok(ConcreteDataType::datetime_datatype())
} else {
error::SqlTypeNotSupportedSnafu {
t: data_type.clone(),
}
.fail()
}
}
_ => error::SqlTypeNotSupportedSnafu {
t: data_type.clone(),
}
.fail(),
},
SqlDataType::Timestamp => Ok(ConcreteDataType::timestamp_millis_datatype()),
_ => error::SqlTypeNotSupportedSnafu {
t: data_type.clone(),
}
.fail(),
}
}
#[cfg(test)]
mod tests {
use std::any::Any;

View File

@@ -1,11 +1,12 @@
use query::query_engine::Output;
use snafu::prelude::*;
use sql::statements::alter::{AlterTable, AlterTableOperation};
use sql::statements::{column_def_to_schema, table_idents_to_full_name};
use table::engine::EngineContext;
use table::requests::{AlterKind, AlterTableRequest};
use crate::error::{self, Result};
use crate::sql::{column_def_to_schema, table_idents_to_full_name, SqlHandler};
use crate::sql::SqlHandler;
impl SqlHandler {
pub(crate) async fn alter(&self, req: AlterTableRequest) -> Result<Output> {
@@ -24,7 +25,7 @@ impl SqlHandler {
pub(crate) fn alter_to_request(&self, alter_table: AlterTable) -> Result<AlterTableRequest> {
let (catalog_name, schema_name, table_name) =
table_idents_to_full_name(alter_table.table_name())?;
table_idents_to_full_name(alter_table.table_name()).context(error::ParseSqlSnafu)?;
let alter_kind = match alter_table.alter_operation() {
AlterTableOperation::AddConstraint(table_constraint) => {
@@ -34,7 +35,7 @@ impl SqlHandler {
.fail()
}
AlterTableOperation::AddColumn { column_def } => AlterKind::AddColumn {
new_column: column_def_to_schema(column_def)?,
new_column: column_def_to_schema(column_def).context(error::ParseSqlSnafu)?,
},
};
Ok(AlterTableRequest {

View File

@@ -8,6 +8,7 @@ use query::query_engine::Output;
use snafu::{OptionExt, ResultExt};
use sql::ast::TableConstraint;
use sql::statements::create_table::CreateTable;
use sql::statements::{column_def_to_schema, table_idents_to_full_name};
use store_api::storage::consts::TIME_INDEX_NAME;
use table::engine::EngineContext;
use table::metadata::TableId;
@@ -17,7 +18,7 @@ use crate::error::{
self, ConstraintNotSupportedSnafu, CreateSchemaSnafu, CreateTableSnafu,
InsertSystemCatalogSnafu, KeyColumnNotFoundSnafu, Result,
};
use crate::sql::{column_def_to_schema, table_idents_to_full_name, SqlHandler};
use crate::sql::SqlHandler;
impl SqlHandler {
pub(crate) async fn create(&self, req: CreateTableRequest) -> Result<Output> {
@@ -61,7 +62,8 @@ impl SqlHandler {
let mut ts_index = usize::MAX;
let mut primary_keys = vec![];
let (catalog_name, schema_name, table_name) = table_idents_to_full_name(&stmt.name)?;
let (catalog_name, schema_name, table_name) =
table_idents_to_full_name(&stmt.name).context(error::ParseSqlSnafu)?;
let col_map = stmt
.columns
@@ -129,7 +131,7 @@ impl SqlHandler {
let columns_schemas: Vec<_> = stmt
.columns
.iter()
.map(column_def_to_schema)
.map(|column| column_def_to_schema(column).context(error::ParseSqlSnafu))
.collect::<Result<Vec<_>>>()?;
let schema = Arc::new(
@@ -159,15 +161,12 @@ mod tests {
use std::assert_matches::assert_matches;
use datatypes::prelude::ConcreteDataType;
use sql::ast::Ident;
use sql::ast::{DataType as SqlDataType, ObjectName};
use sql::dialect::GenericDialect;
use sql::parser::ParserContext;
use sql::statements::statement::Statement;
use super::*;
use crate::error::Error;
use crate::sql::sql_data_type_to_concrete_data_type;
use crate::tests::test_util::create_mock_sql_handler;
fn sql_to_statement(sql: &str) -> CreateTable {
@@ -292,46 +291,4 @@ mod tests {
.data_type
);
}
fn check_type(sql_type: SqlDataType, data_type: ConcreteDataType) {
assert_eq!(
data_type,
sql_data_type_to_concrete_data_type(&sql_type).unwrap()
);
}
#[test]
pub fn test_sql_data_type_to_concrete_data_type() {
check_type(
SqlDataType::BigInt(None),
ConcreteDataType::int64_datatype(),
);
check_type(SqlDataType::Int(None), ConcreteDataType::int32_datatype());
check_type(
SqlDataType::SmallInt(None),
ConcreteDataType::int16_datatype(),
);
check_type(SqlDataType::Char(None), ConcreteDataType::string_datatype());
check_type(
SqlDataType::Varchar(None),
ConcreteDataType::string_datatype(),
);
check_type(SqlDataType::Text, ConcreteDataType::string_datatype());
check_type(SqlDataType::String, ConcreteDataType::string_datatype());
check_type(
SqlDataType::Float(None),
ConcreteDataType::float32_datatype(),
);
check_type(SqlDataType::Double, ConcreteDataType::float64_datatype());
check_type(SqlDataType::Boolean, ConcreteDataType::boolean_datatype());
check_type(SqlDataType::Date, ConcreteDataType::date_datatype());
check_type(
SqlDataType::Custom(ObjectName(vec![Ident::new("datetime")])),
ConcreteDataType::datetime_datatype(),
);
check_type(
SqlDataType::Timestamp,
ConcreteDataType::timestamp_millis_datatype(),
);
}
}

View File

@@ -6,8 +6,8 @@ use std::time::Duration;
use api::v1::ColumnDataType;
use api::v1::{
admin_result, alter_expr::Kind, codec::InsertBatch, column, AddColumn, AlterExpr, Column,
ColumnDef, CreateExpr, MutateResult,
admin_result, alter_expr::Kind, codec::InsertBatch, column, insert_expr, AddColumn, AlterExpr,
Column, ColumnDef, CreateExpr, InsertExpr, MutateResult,
};
use client::admin::Admin;
use client::{Client, Database, ObjectResult};
@@ -48,6 +48,7 @@ async fn test_insert_and_select() {
.collect(),
..Default::default()
}),
datatype: 12, // string
..Default::default()
};
let expected_cpu_col = Column {
@@ -57,6 +58,7 @@ async fn test_insert_and_select() {
..Default::default()
}),
null_mask: vec![2],
datatype: 10, // float64
..Default::default()
};
let expected_mem_col = Column {
@@ -66,14 +68,16 @@ async fn test_insert_and_select() {
..Default::default()
}),
null_mask: vec![4],
datatype: 10, // float64
..Default::default()
};
let expected_ts_col = Column {
column_name: "ts".to_string(),
values: Some(column::Values {
i64_values: vec![100, 101, 102, 103],
ts_millis_values: vec![100, 101, 102, 103],
..Default::default()
}),
datatype: 15, // timestamp
..Default::default()
};
@@ -117,7 +121,11 @@ async fn test_insert_and_select() {
row_count: 4,
}
.into()];
let result = db.insert("demo", values).await;
let expr = InsertExpr {
table_name: "demo".to_string(),
expr: Some(insert_expr::Expr::Values(insert_expr::Values { values })),
};
let result = db.insert(expr).await;
assert!(result.is_ok());
// select

View File

@@ -40,7 +40,7 @@ async fn test_execute_query() {
.await
.unwrap();
match output {
Output::RecordBatch(recordbatch) => {
Output::Stream(recordbatch) => {
let numbers = util::collect(recordbatch).await.unwrap();
let columns = numbers[0].df_recordbatch.columns();
assert_eq!(1, columns.len());
@@ -116,7 +116,7 @@ async fn test_alter_table() {
let output = instance.execute_sql("select * from demo").await.unwrap();
match output {
Output::RecordBatch(stream) => {
Output::Stream(stream) => {
let recordbatches = util::collect(stream).await.unwrap();
let recordbatch = recordbatches
.into_iter()