Skip to content

Commit

Permalink
Feat: add Function: current_date & add Type: LogicalType::Time (#181
Browse files Browse the repository at this point in the history
)

* feat: support 'current_date'

* feat: support `DataType::Time` & perf `Tuple::serialize_to`

* fix: into_pg_type add `LogicalType::Time`

* fix: encode_tuples add `LogicalType::Time`

* doc: add `Time` for DataTypes
  • Loading branch information
KKould authored Mar 25, 2024
1 parent a90f94b commit faf27fe
Show file tree
Hide file tree
Showing 16 changed files with 272 additions and 49 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ let fnck_sql = DataBaseBuilder::path("./data")
- Varchar
- Date
- DateTime
- Time
- Tuple

## Roadmap
Expand Down
2 changes: 2 additions & 0 deletions src/bin/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ fn encode_tuples<'a>(schema: &Schema, tuples: Vec<Tuple>) -> PgWireResult<QueryR
}
LogicalType::Date => encoder.encode_field(&value.date()),
LogicalType::DateTime => encoder.encode_field(&value.datetime()),
LogicalType::Time => encoder.encode_field(&value.time()),
LogicalType::Decimal(_, _) => todo!(),
_ => unreachable!(),
}?;
Expand All @@ -227,6 +228,7 @@ fn into_pg_type(data_type: &LogicalType) -> PgWireResult<Type> {
LogicalType::Varchar(_) => Type::VARCHAR,
LogicalType::Date | LogicalType::DateTime => Type::DATE,
LogicalType::Char(_) => Type::CHAR,
LogicalType::Time => Type::TIME,
LogicalType::Decimal(_, _) => todo!(),
_ => {
return Err(PgWireError::UserError(Box::new(ErrorInfo::new(
Expand Down
5 changes: 4 additions & 1 deletion src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use crate::planner::LogicalPlan;
use crate::storage::kip::KipStorage;
use crate::storage::{Storage, Transaction};
use crate::types::tuple::{SchemaRef, Tuple};
use crate::udf::current_date::CurrentDate;

pub(crate) type Functions = HashMap<FunctionSummary, Arc<dyn ScalarFunctionImpl>>;

Expand Down Expand Up @@ -47,7 +48,9 @@ impl DataBaseBuilder {
self
}

pub async fn build(self) -> Result<Database<KipStorage>, DatabaseError> {
pub async fn build(mut self) -> Result<Database<KipStorage>, DatabaseError> {
self = self.register_function(CurrentDate::new());

let storage = KipStorage::new(self.path).await?;

Ok(Database {
Expand Down
9 changes: 9 additions & 0 deletions src/expression/value_compute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,15 @@ impl DataValue {
&unified_type
)
}
LogicalType::Time => {
numeric_binary_compute!(
DataValue::Time,
self.clone(),
right.clone(),
op,
&unified_type
)
}
LogicalType::Decimal(_, _) => {
let left_value = self.clone().cast(&unified_type)?;
let right_value = right.clone().cast(&unified_type)?;
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ pub mod parser;
pub mod planner;
pub mod storage;
pub mod types;
mod udf;
2 changes: 2 additions & 0 deletions src/marcos/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ macro_rules! function {
}

impl $struct_name {
#[allow(unused_mut)]
pub(crate) fn new() -> Arc<Self> {
let function_name = stringify!($function_name).to_lowercase();

Expand All @@ -93,6 +94,7 @@ macro_rules! function {

#[typetag::serde]
impl ScalarFunctionImpl for $struct_name {
#[allow(unused_variables, clippy::redundant_closure_call)]
fn eval(&self, args: &[ScalarExpression], tuple: &Tuple, schema: &[ColumnRef]) -> Result<DataValue, DatabaseError> {
let mut _index = 0;

Expand Down
5 changes: 4 additions & 1 deletion src/optimizer/core/histogram.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,13 +279,16 @@ impl Histogram {
}),
_ => unreachable!(),
},
LogicalType::Date | LogicalType::DateTime => match value {
LogicalType::Date | LogicalType::DateTime | LogicalType::Time => match value {
DataValue::Date32(value) => DataValue::Int32(*value)
.cast(&LogicalType::Double)?
.double(),
DataValue::Date64(value) => DataValue::Int64(*value)
.cast(&LogicalType::Double)?
.double(),
DataValue::Time(value) => DataValue::UInt32(*value)
.cast(&LogicalType::Double)?
.double(),
_ => unreachable!(),
},

Expand Down
8 changes: 5 additions & 3 deletions src/storage/table_codec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ impl TableCodec {
let tuple_id = tuple.id.clone().ok_or(DatabaseError::PrimaryKeyNotFound)?;
let key = Self::encode_tuple_key(table_name, &tuple_id)?;

Ok((Bytes::from(key), Bytes::from(tuple.serialize_to(types))))
Ok((Bytes::from(key), Bytes::from(tuple.serialize_to(types)?)))
}

pub fn encode_tuple_key(
Expand Down Expand Up @@ -226,8 +226,10 @@ impl TableCodec {
tuple_id: &TupleId,
) -> Result<(Bytes, Bytes), DatabaseError> {
let key = TableCodec::encode_index_key(name, index, Some(tuple_id))?;
let mut bytes = Vec::new();
tuple_id.to_raw(&mut bytes, None)?;

Ok((Bytes::from(key), Bytes::from(tuple_id.to_raw(None))))
Ok((Bytes::from(key), Bytes::from(bytes)))
}

fn _encode_index_key(name: &str, index: &Index) -> Result<Vec<u8>, DatabaseError> {
Expand Down Expand Up @@ -267,7 +269,7 @@ impl TableCodec {

if let Some(tuple_id) = tuple_id {
if matches!(index.ty, IndexType::Normal | IndexType::Composite) {
key_prefix.append(&mut tuple_id.to_raw(None));
tuple_id.to_raw(&mut key_prefix, None)?;
}
}
Ok(key_prefix)
Expand Down
32 changes: 29 additions & 3 deletions src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use std::any::TypeId;
use std::cmp;

use crate::errors::DatabaseError;
use sqlparser::ast::{CharLengthUnits, CharacterLength, ExactNumberInfo};
use sqlparser::ast::{CharLengthUnits, CharacterLength, ExactNumberInfo, TimezoneInfo};
use strum_macros::AsRefStr;

pub type ColumnId = u32;
Expand Down Expand Up @@ -38,6 +38,7 @@ pub enum LogicalType {
Varchar(Option<u32>),
Date,
DateTime,
Time,
// decimal (precision, scale)
Decimal(Option<u8>, Option<u8>),
Tuple,
Expand Down Expand Up @@ -100,6 +101,7 @@ impl LogicalType {
LogicalType::Decimal(_, _) => Some(16),
LogicalType::Date => Some(4),
LogicalType::DateTime => Some(8),
LogicalType::Time => Some(4),
LogicalType::Invalid | LogicalType::Tuple => unreachable!(),
}
}
Expand Down Expand Up @@ -297,8 +299,12 @@ impl LogicalType {
),
LogicalType::DateTime => matches!(
to,
LogicalType::Date | LogicalType::Varchar(_) | LogicalType::Char(_)
LogicalType::Date
| LogicalType::Time
| LogicalType::Varchar(_)
| LogicalType::Char(_)
),
LogicalType::Time => matches!(to, LogicalType::Varchar(_) | LogicalType::Char(_)),
LogicalType::Decimal(_, _) | LogicalType::Tuple => false,
}
}
Expand Down Expand Up @@ -356,7 +362,27 @@ impl TryFrom<sqlparser::ast::DataType> for LogicalType {
sqlparser::ast::DataType::UnsignedBigInt(_) => Ok(LogicalType::UBigint),
sqlparser::ast::DataType::Boolean => Ok(LogicalType::Boolean),
sqlparser::ast::DataType::Date => Ok(LogicalType::Date),
sqlparser::ast::DataType::Datetime(_) => Ok(LogicalType::DateTime),
sqlparser::ast::DataType::Datetime(precision) => {
if precision.is_some() {
return Err(DatabaseError::UnsupportedStmt(
"time's precision".to_string(),
));
}
Ok(LogicalType::DateTime)
}
sqlparser::ast::DataType::Time(precision, info) => {
if precision.is_some() {
return Err(DatabaseError::UnsupportedStmt(
"time's precision".to_string(),
));
}
if !matches!(info, TimezoneInfo::None) {
return Err(DatabaseError::UnsupportedStmt(
"time's time zone".to_string(),
));
}
Ok(LogicalType::Time)
}
sqlparser::ast::DataType::Decimal(info) | sqlparser::ast::DataType::Dec(info) => {
match info {
ExactNumberInfo::None => Ok(Self::Decimal(None, None)),
Expand Down
16 changes: 9 additions & 7 deletions src/types/tuple.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::catalog::ColumnRef;
use crate::errors::DatabaseError;
use crate::types::value::{DataValue, ValueRef};
use crate::types::LogicalType;
use comfy_table::{Cell, Table};
Expand Down Expand Up @@ -108,7 +109,7 @@ impl Tuple {

/// e.g.: bits(u8)..|data_0(len for utf8_1)|utf8_0|data_1|
/// Tips: all len is u32
pub fn serialize_to(&self, types: &[LogicalType]) -> Vec<u8> {
pub fn serialize_to(&self, types: &[LogicalType]) -> Result<Vec<u8>, DatabaseError> {
assert_eq!(self.values.len(), types.len());

fn flip_bit(bits: u8, i: usize) -> u8 {
Expand All @@ -124,16 +125,17 @@ impl Tuple {
bytes[i / BITS_MAX_INDEX] = flip_bit(bytes[i / BITS_MAX_INDEX], i % BITS_MAX_INDEX);
} else {
let logical_type = types[i];
let mut value_bytes = value.to_raw(Some(logical_type));
let value_len = value.to_raw(&mut bytes, Some(logical_type))?;

if logical_type.raw_len().is_none() {
bytes.append(&mut (value_bytes.len() as u32).encode_fixed_vec());
let index = bytes.len() - value_len;

bytes.splice(index..index, (value_len as u32).encode_fixed_vec());
}
bytes.append(&mut value_bytes);
}
}

bytes
Ok(bytes)
}
}

Expand Down Expand Up @@ -300,13 +302,13 @@ mod tests {
&types,
&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13],
&columns,
&tuples[0].serialize_to(&types),
&tuples[0].serialize_to(&types).unwrap(),
);
let tuple_1 = Tuple::deserialize_from(
&types,
&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13],
&columns,
&tuples[1].serialize_to(&types),
&tuples[1].serialize_to(&types).unwrap(),
);

assert_eq!(tuples[0], tuple_0);
Expand Down
Loading

0 comments on commit faf27fe

Please sign in to comment.