Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support Expression on Default #180

Merged
merged 1 commit into from
Mar 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ strum_macros = { version = "0.26.2" }
thiserror = { version = "1.0.58" }
tokio = { version = "1.36.0", features = ["full"] }
tracing = { version = "0.1.40" }
typetag = { version = "0.2" }

[dev-dependencies]
cargo-tarpaulin = { version = "0.27.1" }
Expand Down
18 changes: 11 additions & 7 deletions src/binder/create_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ use crate::planner::operator::create_table::CreateTableOperator;
use crate::planner::operator::Operator;
use crate::planner::LogicalPlan;
use crate::storage::Transaction;
use crate::types::value::DataValue;
use crate::types::LogicalType;

impl<'a, T: Transaction> Binder<'a, T> {
Expand Down Expand Up @@ -116,15 +115,20 @@ impl<'a, T: Transaction> Binder<'a, T> {
}
}
ColumnOption::Default(expr) => {
if let ScalarExpression::Constant(value) = self.bind_expr(expr)? {
let cast_value =
DataValue::clone(&value).cast(&column_desc.column_datatype)?;
column_desc.default = Some(Arc::new(cast_value));
} else {
let mut expr = self.bind_expr(expr)?;

if !expr.referenced_columns(true).is_empty() {
return Err(DatabaseError::UnsupportedStmt(
"'DEFAULT' only with constant now".to_string(),
"column is not allowed to exist in `default`".to_string(),
));
}
if expr.return_type() != column_desc.column_datatype {
expr = ScalarExpression::TypeCast {
expr: Box::new(expr),
ty: column_desc.column_datatype,
}
}
column_desc.default = Some(expr);
}
_ => todo!(),
}
Expand Down
9 changes: 4 additions & 5 deletions src/binder/insert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,10 @@ impl<'a, T: Transaction> Binder<'a, T> {
row.push(value);
}
ScalarExpression::Empty => {
row.push(schema_ref[i].default_value().ok_or_else(|| {
DatabaseError::InvalidColumn(
"column does not exist default".to_string(),
)
})?);
let default_value = schema_ref[i]
.default_value()?
.ok_or(DatabaseError::DefaultNotExist)?;
row.push(default_value);
}
_ => return Err(DatabaseError::UnsupportedStmt(expr.to_string())),
}
Expand Down
9 changes: 4 additions & 5 deletions src/binder/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,10 @@ impl<'a, T: Transaction> Binder<'a, T> {
row.push(value.clone());
}
ScalarExpression::Empty => {
row.push(column.default_value().ok_or_else(|| {
DatabaseError::InvalidColumn(
"column does not exist default".to_string(),
)
})?);
let default_value = column
.default_value()?
.ok_or(DatabaseError::DefaultNotExist)?;
row.push(default_value);
}
_ => return Err(DatabaseError::UnsupportedStmt(value.to_string())),
}
Expand Down
15 changes: 11 additions & 4 deletions src/catalog/column.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use crate::catalog::TableName;
use crate::errors::DatabaseError;
use crate::expression::ScalarExpression;
use serde::{Deserialize, Serialize};
use std::hash::Hash;
use std::sync::Arc;

use crate::types::tuple::EMPTY_TUPLE;
use crate::types::value::ValueRef;
use crate::types::{ColumnId, LogicalType};

Expand Down Expand Up @@ -82,8 +85,12 @@ impl ColumnCatalog {
&self.desc.column_datatype
}

pub(crate) fn default_value(&self) -> Option<ValueRef> {
self.desc.default.clone()
pub(crate) fn default_value(&self) -> Result<Option<ValueRef>, DatabaseError> {
self.desc
.default
.as_ref()
.map(|expr| expr.eval(&EMPTY_TUPLE, &[]))
.transpose()
}

#[allow(dead_code)]
Expand All @@ -98,15 +105,15 @@ pub struct ColumnDesc {
pub(crate) column_datatype: LogicalType,
pub(crate) is_primary: bool,
pub(crate) is_unique: bool,
pub(crate) default: Option<ValueRef>,
pub(crate) default: Option<ScalarExpression>,
}

impl ColumnDesc {
pub(crate) const fn new(
column_datatype: LogicalType,
is_primary: bool,
is_unique: bool,
default: Option<ValueRef>,
default: Option<ScalarExpression>,
) -> ColumnDesc {
ColumnDesc {
column_datatype,
Expand Down
12 changes: 7 additions & 5 deletions src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,8 @@ mod test {
use crate::types::tuple::{create_table, Tuple};
use crate::types::value::{DataValue, ValueRef};
use crate::types::LogicalType;
use serde::Deserialize;
use serde::Serialize;
use std::sync::Arc;
use tempfile::TempDir;

Expand Down Expand Up @@ -298,10 +300,10 @@ mod test {
Ok(())
}

function!(TestFunction::test(LogicalType::Integer, LogicalType::Integer) -> LogicalType::Integer => |v1: ValueRef, v2: ValueRef| {
function!(TestFunction::test(LogicalType::Integer, LogicalType::Integer) -> LogicalType::Integer => (|v1: ValueRef, v2: ValueRef| {
let value = DataValue::binary_op(&v1, &v2, &BinaryOperator::Plus)?;
DataValue::unary_op(&value, &UnaryOperator::Minus)
});
}));

#[tokio::test]
async fn test_udf() -> Result<(), DatabaseError> {
Expand All @@ -311,12 +313,12 @@ mod test {
.build()
.await?;
let _ = fnck_sql
.run("CREATE TABLE test (id int primary key, c1 int, c2 int);")
.run("CREATE TABLE test (id int primary key, c1 int, c2 int default test(1, 2));")
.await?;
let _ = fnck_sql
.run("INSERT INTO test VALUES (1, 2, 2), (0, 1, 1), (2, 1, 1), (3, 3, 3);")
.run("INSERT INTO test VALUES (1, 2, 2), (0, 1, 1), (2, 1, 1), (3, 3, default);")
.await?;
let (schema, tuples) = fnck_sql.run("select test(c1, 1) from test").await?;
let (schema, tuples) = fnck_sql.run("select test(c1, 1), c2 from test").await?;
println!("{}", create_table(&schema, &tuples));

Ok(())
Expand Down
2 changes: 2 additions & 0 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ pub enum DatabaseError {
#[source]
csv::Error,
),
#[error("default does not exist")]
DefaultNotExist,
#[error("column: {0} already exists")]
DuplicateColumn(String),
#[error("index: {0} already exists")]
Expand Down
2 changes: 1 addition & 1 deletion src/execution/volcano/ddl/add_column.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ impl AddColumn {
for tuple in build_read(self.input, transaction) {
let mut tuple: Tuple = tuple?;

if let Some(value) = column.default_value() {
if let Some(value) = column.default_value()? {
if let Some(unique_values) = &mut unique_values {
unique_values.push((tuple.id.clone().unwrap(), value.clone()));
}
Expand Down
12 changes: 8 additions & 4 deletions src/execution/volcano/dml/insert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,14 @@ impl Insert {
let mut values = Vec::with_capacity(table_catalog.columns_len());

for col in table_catalog.columns() {
let value = tuple_map
.remove(&col.id())
.or_else(|| col.default_value())
.unwrap_or_else(|| Arc::new(DataValue::none(col.datatype())));
let value = {
let mut value = tuple_map.remove(&col.id());

if value.is_none() {
value = col.default_value()?;
}
value.unwrap_or_else(|| Arc::new(DataValue::none(col.datatype())))
};
if value.is_null() && !col.nullable {
return Err(DatabaseError::NotNull);
}
Expand Down
10 changes: 7 additions & 3 deletions src/execution/volcano/dql/describe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ impl Describe {

for column in table.columns() {
let datatype = column.datatype();
let default = column
.desc
.default
.as_ref()
.map(|expr| format!("{}", expr))
.unwrap_or_else(|| "null".to_string());
let values = vec![
Arc::new(DataValue::Utf8(Some(column.name().to_string()))),
Arc::new(DataValue::Utf8(Some(datatype.to_string()))),
Expand All @@ -63,9 +69,7 @@ impl Describe {
))),
Arc::new(DataValue::Utf8(Some(column.nullable.to_string()))),
key_fn(column),
column
.default_value()
.unwrap_or_else(|| Arc::new(DataValue::none(datatype))),
Arc::new(DataValue::Utf8(Some(default))),
];
yield Tuple { id: None, values };
}
Expand Down
6 changes: 4 additions & 2 deletions src/expression/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::expression::ScalarExpression;
use crate::types::tuple::Tuple;
use crate::types::value::DataValue;
use crate::types::LogicalType;
use serde::{Deserialize, Serialize};
use std::fmt::Debug;
use std::hash::{Hash, Hasher};
use std::sync::Arc;
Expand All @@ -14,7 +15,7 @@ use std::sync::Arc;
/// - `Some(false)` monotonically decreasing
pub type FuncMonotonicity = Vec<Option<bool>>;

#[derive(Debug, Clone)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ScalarFunction {
pub(crate) args: Vec<ScalarExpression>,
pub(crate) inner: Arc<dyn ScalarFunctionImpl>,
Expand All @@ -34,12 +35,13 @@ impl Hash for ScalarFunction {
}
}

#[derive(Debug, Eq, PartialEq, Hash, Clone)]
#[derive(Debug, Eq, PartialEq, Hash, Clone, Serialize, Deserialize)]
pub struct FunctionSummary {
pub(crate) name: String,
pub(crate) arg_types: Vec<LogicalType>,
}

#[typetag::serde(tag = "type")]
pub trait ScalarFunctionImpl: Debug + Send + Sync {
fn eval(
&self,
Expand Down
4 changes: 2 additions & 2 deletions src/expression/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub mod range_detacher;
pub mod simplify;
pub mod value_compute;

#[derive(Debug, PartialEq, Eq, Clone, Hash)]
#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
pub enum AliasType {
Name(String),
Expr(Box<ScalarExpression>),
Expand All @@ -30,7 +30,7 @@ pub enum AliasType {
/// SELECT a+1, b FROM t1.
/// a+1 -> ScalarExpression::Unary(a + 1)
/// b -> ScalarExpression::ColumnRef()
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
pub enum ScalarExpression {
Constant(ValueRef),
ColumnRef(ColumnRef),
Expand Down
9 changes: 6 additions & 3 deletions src/marcos/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ macro_rules! implement_from_tuple {
#[macro_export]
macro_rules! function {
($struct_name:ident::$function_name:ident($($arg_ty:expr),*) -> $return_ty:expr => $closure:expr) => {
#[derive(Debug)]
#[derive(Debug, Serialize, Deserialize)]
pub(crate) struct $struct_name {
summary: FunctionSummary
}
Expand All @@ -91,6 +91,7 @@ macro_rules! function {
}
}

#[typetag::serde]
impl ScalarFunctionImpl for $struct_name {
fn eval(&self, args: &[ScalarExpression], tuple: &Tuple, schema: &[ColumnRef]) -> Result<DataValue, DatabaseError> {
let mut _index = 0;
Expand Down Expand Up @@ -132,6 +133,8 @@ mod test {
use crate::types::tuple::{SchemaRef, Tuple};
use crate::types::value::{DataValue, ValueRef};
use crate::types::LogicalType;
use serde::Deserialize;
use serde::Serialize;
use std::sync::Arc;

fn build_tuple() -> (Tuple, SchemaRef) {
Expand Down Expand Up @@ -187,9 +190,9 @@ mod test {
assert_eq!(my_struct.c2, "LOL");
}

function!(MyFunction::sum(LogicalType::Integer, LogicalType::Integer) -> LogicalType::Integer => |v1: ValueRef, v2: ValueRef| {
function!(MyFunction::sum(LogicalType::Integer, LogicalType::Integer) -> LogicalType::Integer => (|v1: ValueRef, v2: ValueRef| {
DataValue::binary_op(&v1, &v2, &BinaryOperator::Plus)
});
}));

#[test]
fn test_function() -> Result<(), DatabaseError> {
Expand Down
2 changes: 1 addition & 1 deletion src/storage/kip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ impl Transaction for KipTransaction {
if_not_exists: bool,
) -> Result<ColumnId, DatabaseError> {
if let Some(mut table) = self.table(table_name.clone()).cloned() {
if !column.nullable && column.default_value().is_none() {
if !column.nullable && column.default_value()?.is_none() {
return Err(DatabaseError::NeedNullAbleOrDefault);
}

Expand Down
10 changes: 10 additions & 0 deletions src/types/tuple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,18 @@ use crate::types::LogicalType;
use comfy_table::{Cell, Table};
use integer_encoding::FixedInt;
use itertools::Itertools;
use lazy_static::lazy_static;
use std::sync::Arc;

lazy_static! {
pub static ref EMPTY_TUPLE: Tuple = {
Tuple {
id: None,
values: vec![],
}
};
}

const BITS_MAX_INDEX: usize = 8;

pub type TupleId = ValueRef;
Expand Down
5 changes: 4 additions & 1 deletion tests/slt/create.slt
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,7 @@ statement ok
create table if not exists t(id int primary key, v1 int, v2 int, v3 int)

statement ok
create table if not exists t(id int primary key, v1 int, v2 int, v3 int)
create table if not exists t(id int primary key, v1 int, v2 int, v3 int)

statement error
create table test_default_expr(id int primary key, v1 int, v2 int, v3 int default (v1 + 1))
Loading