diff --git a/README.md b/README.md index 8197e9c2..3c4a0ad4 100755 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ run `cargo run -p tpcc --release` to run tpcc - i9-13900HX - 32.0 GB -- YMTC PC411-1024GB-B +- KIOXIA-EXCERIA PLUS G3 SSD - Tips: TPC-C currently only supports single thread ```shell <90th Percentile RT (MaxRT)> diff --git a/src/bin/server.rs b/src/bin/server.rs index 8a4afc15..f45edd93 100644 --- a/src/bin/server.rs +++ b/src/bin/server.rs @@ -235,7 +235,9 @@ fn encode_tuples<'a>(schema: &Schema, tuples: Vec) -> PgWireResult encoder.encode_field(&value.date()), LogicalType::DateTime => encoder.encode_field(&value.datetime()), LogicalType::Time => encoder.encode_field(&value.time()), - LogicalType::Decimal(_, _) => todo!(), + LogicalType::Decimal(_, _) => { + encoder.encode_field(&value.decimal().map(|decimal| decimal.to_string())) + } _ => unreachable!(), }?; } @@ -260,7 +262,7 @@ fn into_pg_type(data_type: &LogicalType) -> PgWireResult { LogicalType::Date | LogicalType::DateTime => Type::DATE, LogicalType::Char(..) => Type::CHAR, LogicalType::Time => Type::TIME, - LogicalType::Decimal(_, _) => todo!(), + LogicalType::Decimal(_, _) => Type::FLOAT8, _ => { return Err(PgWireError::UserError(Box::new(ErrorInfo::new( "ERROR".to_owned(), diff --git a/src/binder/alter_table.rs b/src/binder/alter_table.rs index 1c0ff2a1..f2f4d013 100644 --- a/src/binder/alter_table.rs +++ b/src/binder/alter_table.rs @@ -64,23 +64,12 @@ impl> Binder<'_, '_, T, A> Childrens::Only(plan), ) } - AlterTableOperation::DropPrimaryKey => todo!(), - AlterTableOperation::RenameColumn { - old_column_name: _, - new_column_name: _, - } => todo!(), - AlterTableOperation::RenameTable { table_name: _ } => todo!(), - AlterTableOperation::ChangeColumn { - old_name: _, - new_name: _, - data_type: _, - options: _, - } => todo!(), - AlterTableOperation::AlterColumn { - column_name: _, - op: _, - } => todo!(), - _ => todo!(), + op => { + return Err(DatabaseError::UnsupportedStmt(format!( + "AlertOperation: {:?}", + op + ))) + } }; Ok(plan) diff --git a/src/binder/copy.rs b/src/binder/copy.rs index 05966bc1..7e2bdf54 100644 --- a/src/binder/copy.rs +++ b/src/binder/copy.rs @@ -88,7 +88,12 @@ impl> Binder<'_, '_, T, A> let ext_source = ExtSource { path: match target { CopyTarget::File { filename } => filename.into(), - t => todo!("unsupported copy target: {:?}", t), + t => { + return Err(DatabaseError::UnsupportedStmt(format!( + "copy target: {:?}", + t + ))) + } }, format: FileFormat::from_options(options), }; diff --git a/src/binder/create_table.rs b/src/binder/create_table.rs index 54c9d840..c1f21840 100644 --- a/src/binder/create_table.rs +++ b/src/binder/create_table.rs @@ -1,8 +1,3 @@ -use itertools::Itertools; -use sqlparser::ast::{ColumnDef, ColumnOption, ObjectName, TableConstraint}; -use std::collections::HashSet; -use std::sync::Arc; - use super::{is_valid_identifier, Binder}; use crate::binder::lower_case_name; use crate::catalog::{ColumnCatalog, ColumnDesc}; @@ -14,6 +9,10 @@ use crate::planner::{Childrens, LogicalPlan}; use crate::storage::Transaction; use crate::types::value::DataValue; use crate::types::LogicalType; +use itertools::Itertools; +use sqlparser::ast::{ColumnDef, ColumnOption, ObjectName, TableConstraint}; +use std::collections::HashSet; +use std::sync::Arc; impl> Binder<'_, '_, T, A> { // TODO: TableConstraint @@ -75,7 +74,12 @@ impl> Binder<'_, '_, T, A> } } } - _ => todo!(), + constraint => { + return Err(DatabaseError::UnsupportedStmt(format!( + "`CreateTable` does not currently support this constraint: {:?}", + constraint + )))? + } } } @@ -140,7 +144,12 @@ impl> Binder<'_, '_, T, A> } column_desc.default = Some(expr); } - _ => todo!(), + option => { + return Err(DatabaseError::UnsupportedStmt(format!( + "`Column` does not currently support this option: {:?}", + option + ))) + } } } diff --git a/src/binder/expr.rs b/src/binder/expr.rs index 5fa653f2..a89aea0a 100644 --- a/src/binder/expr.rs +++ b/src/binder/expr.rs @@ -56,7 +56,7 @@ impl<'a, T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<'a, '_, T .find_map(|(key, value)| (key == name).then(|| value.clone())) .ok_or_else(|| DatabaseError::ParametersNotFound(name.to_string()))? } else { - v.into() + v.try_into()? }; Ok(ScalarExpression::Constant(value)) } @@ -473,7 +473,12 @@ impl<'a, T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<'a, '_, T match arg_expr { FunctionArgExpr::Expr(expr) => args.push(self.bind_expr(expr)?), FunctionArgExpr::Wildcard => args.push(Self::wildcard_expr()), - _ => todo!(), + expr => { + return Err(DatabaseError::UnsupportedStmt(format!( + "function arg: {:#?}", + expr + ))) + } } } let function_name = func.name.to_string().to_lowercase(); diff --git a/src/binder/mod.rs b/src/binder/mod.rs index 5ff832ba..b26c4d11 100644 --- a/src/binder/mod.rs +++ b/src/binder/mod.rs @@ -350,13 +350,22 @@ impl<'a, 'b, T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<'a, ' names, if_exists, .. - } => match object_type { - // todo handle all names - ObjectType::Table => self.bind_drop_table(&names[0], if_exists)?, - // todo handle all names - ObjectType::View => self.bind_drop_view(&names[0], if_exists)?, - _ => todo!(), - }, + } => { + if names.len() > 1 { + return Err(DatabaseError::UnsupportedStmt( + "only Drop a single `Table` or `View` is allowed".to_string(), + )); + } + match object_type { + ObjectType::Table => self.bind_drop_table(&names[0], if_exists)?, + ObjectType::View => self.bind_drop_view(&names[0], if_exists)?, + _ => { + return Err(DatabaseError::UnsupportedStmt( + "only `Table` and `View` are allowed to be Dropped".to_string(), + )) + } + } + } Statement::Insert { table_name, columns, @@ -364,10 +373,14 @@ impl<'a, 'b, T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<'a, ' overwrite, .. } => { + // TODO: support body on Insert if let SetExpr::Values(values) = source.body.as_ref() { self.bind_insert(table_name, columns, &values.rows, *overwrite, false)? } else { - todo!() + return Err(DatabaseError::UnsupportedStmt(format!( + "insert body: {:#?}", + source.body + ))); } } Statement::Update { @@ -442,7 +455,10 @@ impl<'a, 'b, T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<'a, ' left, right, } => self.bind_set_operation(op, set_quantifier, left, right), - _ => todo!(), + expr => Err(DatabaseError::UnsupportedStmt(format!( + "set expression: {:?}", + expr + ))), } } diff --git a/src/binder/select.rs b/src/binder/select.rs index ec7a4e59..322b8194 100644 --- a/src/binder/select.rs +++ b/src/binder/select.rs @@ -55,7 +55,12 @@ impl<'a: 'b, 'b, T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<' left, right, } => self.bind_set_operation(op, set_quantifier, left, right), - _ => unimplemented!(), + expr => { + return Err(DatabaseError::UnsupportedStmt(format!( + "query body: {:?}", + expr + ))) + } }?; let limit = &query.limit; @@ -136,16 +141,7 @@ impl<'a: 'b, 'b, T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<' plan = self.bind_project(plan, select_list)?; } - if let Some(SelectInto { - name, - unlogged, - temporary, - .. - }) = &select.into - { - if *unlogged || *temporary { - todo!() - } + if let Some(SelectInto { name, .. }) = &select.into { plan = LogicalPlan::new( Operator::Insert(InsertOperator { table_name: Arc::new(lower_case_name(name)?), @@ -234,18 +230,10 @@ impl<'a: 'b, 'b, T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<' distinct_exprs, )) } - (SetOperator::Intersect, true) => { - todo!() - } - (SetOperator::Intersect, false) => { - todo!() - } - (SetOperator::Except, true) => { - todo!() - } - (SetOperator::Except, false) => { - todo!() - } + (set_operator, _) => Err(DatabaseError::UnsupportedStmt(format!( + "set operator: {:?}", + set_operator + ))), } } @@ -287,7 +275,9 @@ impl<'a: 'b, 'b, T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<' }) = alias { if tables.len() > 1 { - todo!("Implement virtual tables for multiple table aliases"); + return Err(DatabaseError::UnsupportedStmt( + "Implement virtual tables for multiple table aliases".to_string(), + )); } let table_alias = Arc::new(name.value.to_lowercase()); diff --git a/src/errors.rs b/src/errors.rs index 7bd53d48..6366b685 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -73,6 +73,8 @@ pub enum DatabaseError { InvalidTable(String), #[error("invalid type")] InvalidType, + #[error("invalid value: {0}")] + InvalidValue(String), #[error("io: {0}")] IO( #[source] diff --git a/src/planner/operator/mod.rs b/src/planner/operator/mod.rs index b4462cd3..e30a7744 100644 --- a/src/planner/operator/mod.rs +++ b/src/planner/operator/mod.rs @@ -287,7 +287,7 @@ impl fmt::Display for Operator { Operator::DropView(op) => write!(f, "{}", op), Operator::Truncate(op) => write!(f, "{}", op), Operator::CopyFromFile(op) => write!(f, "{}", op), - Operator::CopyToFile(_) => todo!(), + Operator::CopyToFile(op) => write!(f, "{}", op), Operator::Union(op) => write!(f, "{}", op), } } diff --git a/src/storage/mod.rs b/src/storage/mod.rs index c3c37164..37b0afda 100644 --- a/src/storage/mod.rs +++ b/src/storage/mod.rs @@ -676,6 +676,7 @@ trait IndexImpl<'bytes, T: Transaction + 'bytes> { &self, params: &IndexImplParams, value: &DataValue, + is_upper: bool, ) -> Result, DatabaseError>; } @@ -792,12 +793,13 @@ impl<'bytes, T: Transaction + 'bytes> IndexImpl<'bytes, T> for IndexImplEnum { &self, params: &IndexImplParams, value: &DataValue, + is_upper: bool, ) -> Result, DatabaseError> { match self { - IndexImplEnum::PrimaryKey(inner) => inner.bound_key(params, value), - IndexImplEnum::Unique(inner) => inner.bound_key(params, value), - IndexImplEnum::Normal(inner) => inner.bound_key(params, value), - IndexImplEnum::Composite(inner) => inner.bound_key(params, value), + IndexImplEnum::PrimaryKey(inner) => inner.bound_key(params, value, is_upper), + IndexImplEnum::Unique(inner) => inner.bound_key(params, value, is_upper), + IndexImplEnum::Normal(inner) => inner.bound_key(params, value, is_upper), + IndexImplEnum::Composite(inner) => inner.bound_key(params, value, is_upper), } } } @@ -844,6 +846,7 @@ impl<'bytes, T: Transaction + 'bytes> IndexImpl<'bytes, T> for PrimaryKeyIndexIm &self, params: &IndexImplParams, value: &DataValue, + _: bool, ) -> Result, DatabaseError> { unsafe { &*params.table_codec() }.encode_tuple_key(params.table_name, value) } @@ -876,7 +879,7 @@ impl<'bytes, T: Transaction + 'bytes> IndexImpl<'bytes, T> for UniqueIndexImpl { pk_indices: &PrimaryKeyIndices, params: &IndexImplParams<'a, T>, ) -> Result, DatabaseError> { - let Some(bytes) = params.tx.get(&self.bound_key(params, value)?)? else { + let Some(bytes) = params.tx.get(&self.bound_key(params, value, false)?)? else { return Ok(IndexResult::Tuple(None)); }; let tuple_id = TableCodec::decode_index(&bytes)?; @@ -890,6 +893,7 @@ impl<'bytes, T: Transaction + 'bytes> IndexImpl<'bytes, T> for UniqueIndexImpl { &self, params: &IndexImplParams, value: &DataValue, + _: bool, ) -> Result, DatabaseError> { let index = Index::new(params.index_meta.id, value, IndexType::Unique); @@ -913,8 +917,8 @@ impl<'bytes, T: Transaction + 'bytes> IndexImpl<'bytes, T> for NormalIndexImpl { _: &PrimaryKeyIndices, params: &IndexImplParams<'a, T>, ) -> Result, DatabaseError> { - let min = self.bound_key(params, value)?; - let max = self.bound_key(params, value)?; + let min = self.bound_key(params, value, false)?; + let max = self.bound_key(params, value, true)?; let iter = params .tx @@ -926,10 +930,15 @@ impl<'bytes, T: Transaction + 'bytes> IndexImpl<'bytes, T> for NormalIndexImpl { &self, params: &IndexImplParams, value: &DataValue, + is_upper: bool, ) -> Result, DatabaseError> { let index = Index::new(params.index_meta.id, value, IndexType::Normal); - unsafe { &*params.table_codec() }.encode_index_bound_key(params.table_name, &index) + unsafe { &*params.table_codec() }.encode_index_bound_key( + params.table_name, + &index, + is_upper, + ) } } @@ -949,8 +958,8 @@ impl<'bytes, T: Transaction + 'bytes> IndexImpl<'bytes, T> for CompositeIndexImp _: &PrimaryKeyIndices, params: &IndexImplParams<'a, T>, ) -> Result, DatabaseError> { - let min = self.bound_key(params, value)?; - let max = self.bound_key(params, value)?; + let min = self.bound_key(params, value, false)?; + let max = self.bound_key(params, value, true)?; let iter = params .tx @@ -962,10 +971,15 @@ impl<'bytes, T: Transaction + 'bytes> IndexImpl<'bytes, T> for CompositeIndexImp &self, params: &IndexImplParams, value: &DataValue, + is_upper: bool, ) -> Result, DatabaseError> { let index = Index::new(params.index_meta.id, value, IndexType::Composite); - unsafe { &*params.table_codec() }.encode_index_bound_key(params.table_name, &index) + unsafe { &*params.table_codec() }.encode_index_bound_key( + params.table_name, + &index, + is_upper, + ) } } @@ -1075,21 +1089,27 @@ impl Iter for IndexIter<'_, T> { let table_name = self.params.table_name; let index_meta = &self.params.index_meta; let bound_encode = - |bound: Bound| -> Result<_, DatabaseError> { + |bound: Bound, + is_upper: bool| + -> Result<_, DatabaseError> { match bound { Bound::Included(mut val) => { val = self.params.try_cast(val)?; - Ok(Bound::Included( - self.inner.bound_key(&self.params, &val)?, - )) + Ok(Bound::Included(self.inner.bound_key( + &self.params, + &val, + is_upper, + )?)) } Bound::Excluded(mut val) => { val = self.params.try_cast(val)?; - Ok(Bound::Excluded( - self.inner.bound_key(&self.params, &val)?, - )) + Ok(Bound::Excluded(self.inner.bound_key( + &self.params, + &val, + is_upper, + )?)) } Bound::Unbounded => Ok(Bound::Unbounded), } @@ -1101,10 +1121,10 @@ impl Iter for IndexIter<'_, T> { unsafe { &*self.params.table_codec() } .index_bound(table_name, &index_meta.id)? }; - let mut encode_min = bound_encode(min)?; + let mut encode_min = bound_encode(min, false)?; check_bound(&mut encode_min, bound_min); - let mut encode_max = bound_encode(max)?; + let mut encode_max = bound_encode(max, true)?; check_bound(&mut encode_max, bound_max); let iter = self.params.tx.range(encode_min, encode_max)?; diff --git a/src/storage/rocksdb.rs b/src/storage/rocksdb.rs index 8e16bd17..1b1d4c4a 100644 --- a/src/storage/rocksdb.rs +++ b/src/storage/rocksdb.rs @@ -139,9 +139,7 @@ impl InnerIter for RocksIter<'_, '_> { if let Some(result) = self.iter.by_ref().next() { let (key, value) = result?; let upper_bound_check = match &self.upper { - Bound::Included(ref upper) => { - key.as_ref() <= upper.as_slice() || key.starts_with(upper.as_slice()) - } + Bound::Included(ref upper) => key.as_ref() <= upper.as_slice(), Bound::Excluded(ref upper) => key.as_ref() < upper.as_slice(), Bound::Unbounded => true, }; diff --git a/src/storage/table_codec.rs b/src/storage/table_codec.rs index aa517a40..8ea890f8 100644 --- a/src/storage/table_codec.rs +++ b/src/storage/table_codec.rs @@ -342,6 +342,7 @@ impl TableCodec { &self, name: &str, index: &Index, + is_upper: bool, ) -> Result { let mut key_prefix = self.key_prefix(CodecType::Index, name); key_prefix.push(BOUND_MIN_TAG); @@ -349,6 +350,9 @@ impl TableCodec { key_prefix.push(BOUND_MIN_TAG); index.value.memcomparable_encode(&mut key_prefix)?; + if is_upper { + key_prefix.push(BOUND_MAX_TAG) + } Ok(key_prefix) } @@ -359,7 +363,7 @@ impl TableCodec { index: &Index, tuple_id: Option<&TupleId>, ) -> Result { - let mut key_prefix = self.encode_index_bound_key(name, index)?; + let mut key_prefix = self.encode_index_bound_key(name, index, false)?; if let Some(tuple_id) = tuple_id { if matches!(index.ty, IndexType::Normal | IndexType::Composite) { diff --git a/src/types/value.rs b/src/types/value.rs index 325fc5b7..7fedc236 100644 --- a/src/types/value.rs +++ b/src/types/value.rs @@ -920,7 +920,7 @@ impl DataValue { encode_u!(b, u); } DataValue::Null => (), - DataValue::Decimal(Some(_v)) => todo!(), + DataValue::Decimal(Some(v)) => Self::serialize_decimal(*v, b)?, DataValue::Tuple(Some((values, is_upper))) => { let last = values.len() - 1; @@ -943,6 +943,125 @@ impl DataValue { Ok(()) } + // https://github.com/risingwavelabs/memcomparable/blob/main/src/ser.rs#L468 + pub fn serialize_decimal(decimal: Decimal, bytes: &mut BumpBytes) -> Result<(), DatabaseError> { + if decimal.is_zero() { + bytes.push(0x15); + return Ok(()); + } + let (exponent, significand) = Self::decimal_e_m(decimal); + if decimal.is_sign_positive() { + match exponent { + 11.. => { + bytes.push(0x22); + bytes.push(exponent as u8); + } + 0..=10 => { + bytes.push(0x17 + exponent as u8); + } + _ => { + bytes.push(0x16); + bytes.push(!(-exponent) as u8); + } + } + bytes.extend_from_slice(&significand) + } else { + match exponent { + 11.. => { + bytes.push(0x8); + bytes.push(!exponent as u8); + } + 0..=10 => { + bytes.push(0x13 - exponent as u8); + } + _ => { + bytes.push(0x14); + bytes.push(-exponent as u8); + } + } + for b in significand { + bytes.push(!b); + } + } + Ok(()) + } + + fn decimal_e_m(decimal: Decimal) -> (i8, Vec) { + if decimal.is_zero() { + return (0, vec![]); + } + const POW10: [u128; 30] = [ + 1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000, + 10000000000, + 100000000000, + 1000000000000, + 10000000000000, + 100000000000000, + 1000000000000000, + 10000000000000000, + 100000000000000000, + 1000000000000000000, + 10000000000000000000, + 100000000000000000000, + 1000000000000000000000, + 10000000000000000000000, + 100000000000000000000000, + 1000000000000000000000000, + 10000000000000000000000000, + 100000000000000000000000000, + 1000000000000000000000000000, + 10000000000000000000000000000, + 100000000000000000000000000000, + ]; + let mut mantissa = decimal.mantissa().unsigned_abs(); + let prec = POW10.as_slice().partition_point(|&p| p <= mantissa); + + let e10 = prec as i32 - decimal.scale() as i32; + let e100 = if e10 >= 0 { (e10 + 1) / 2 } else { e10 / 2 }; + // Maybe need to add a zero at the beginning. + // e.g. 111.11 -> 2(exponent which is 100 based) + 0.011111(mantissa). + // So, the `digit_num` of 111.11 will be 6. + let mut digit_num = if e10 == 2 * e100 { prec } else { prec + 1 }; + + let mut byte_array = Vec::with_capacity(16); + // Remove trailing zero. + while mantissa % 10 == 0 && mantissa != 0 { + mantissa /= 10; + digit_num -= 1; + } + + // Cases like: 0.12345, not 0.01111. + if digit_num % 2 == 1 { + mantissa *= 10; + // digit_num += 1; + } + while mantissa >> 64 != 0 { + let byte = (mantissa % 100) as u8 * 2 + 1; + byte_array.push(byte); + mantissa /= 100; + } + // optimize for division + let mut mantissa = mantissa as u64; + while mantissa != 0 { + let byte = (mantissa % 100) as u8 * 2 + 1; + byte_array.push(byte); + mantissa /= 100; + } + byte_array[0] -= 1; + byte_array.reverse(); + + (e100 as i8, byte_array) + } + #[inline] pub fn is_true(&self) -> Result { if self.is_null() { @@ -1672,9 +1791,11 @@ impl From> for DataValue { } } -impl From<&sqlparser::ast::Value> for DataValue { - fn from(v: &sqlparser::ast::Value) -> Self { - match v { +impl TryFrom<&sqlparser::ast::Value> for DataValue { + type Error = DatabaseError; + + fn try_from(value: &sqlparser::ast::Value) -> Result { + Ok(match value { sqlparser::ast::Value::Number(n, _) => { // use i32 to handle most cases if let Ok(v) = n.parse::() { @@ -1686,15 +1807,15 @@ impl From<&sqlparser::ast::Value> for DataValue { } else if let Ok(v) = n.parse::() { v.into() } else { - panic!("unsupported number {:?}", n) + return Err(DatabaseError::InvalidValue(n.to_string())); } } sqlparser::ast::Value::SingleQuotedString(s) | sqlparser::ast::Value::DoubleQuotedString(s) => s.clone().into(), sqlparser::ast::Value::Boolean(b) => (*b).into(), sqlparser::ast::Value::Null => Self::Null, - _ => todo!("unsupported parsed scalar value {:?}", v), - } + v => return Err(DatabaseError::UnsupportedStmt(format!("{:?}", v))), + }) } } @@ -1801,6 +1922,7 @@ mod test { use crate::storage::table_codec::BumpBytes; use crate::types::value::DataValue; use bumpalo::Bump; + use rust_decimal::Decimal; #[test] fn test_mem_comparable_int() -> Result<(), DatabaseError> { @@ -1892,6 +2014,25 @@ mod test { Ok(()) } + #[test] + fn test_mem_comparable_decimal() -> Result<(), DatabaseError> { + let arena = Bump::new(); + let mut key_deciaml_1 = BumpBytes::new_in(&arena); + let mut key_deciaml_2 = BumpBytes::new_in(&arena); + let mut key_deciaml_3 = BumpBytes::new_in(&arena); + + DataValue::Decimal(Some(Decimal::MIN)).memcomparable_encode(&mut key_deciaml_1)?; + DataValue::Decimal(Some(Decimal::new(-1, 0))).memcomparable_encode(&mut key_deciaml_2)?; + DataValue::Decimal(Some(Decimal::MAX)).memcomparable_encode(&mut key_deciaml_3)?; + + println!("{:?} < {:?}", key_deciaml_1, key_deciaml_2); + println!("{:?} < {:?}", key_deciaml_2, key_deciaml_3); + assert!(key_deciaml_1 < key_deciaml_2); + assert!(key_deciaml_2 < key_deciaml_3); + + Ok(()) + } + #[test] fn test_mem_comparable_tuple_lower() -> Result<(), DatabaseError> { let arena = Bump::new(); diff --git a/tests/slt/where_by_index.slt b/tests/slt/where_by_index.slt index 7f05ad48..c7ca1880 100644 --- a/tests/slt/where_by_index.slt +++ b/tests/slt/where_by_index.slt @@ -174,6 +174,11 @@ select * from t1 where c2 > 0 and c2 < 9; 3 4 5 6 7 8 +query IIT +select * from t1 where c2 = 5; +---- +3 4 5 + statement ok update t1 set c2 = 9 where c1 = 1 diff --git a/tpcc/README.md b/tpcc/README.md index 4e3e929d..7dbb3c07 100644 --- a/tpcc/README.md +++ b/tpcc/README.md @@ -3,7 +3,7 @@ run `cargo run -p tpcc --release` to run tpcc - i9-13900HX - 32.0 GB -- YMTC PC411-1024GB-B +- KIOXIA-EXCERIA PLUS G3 SSD - Tips: TPCC currently only supports single thread ```shell |New-Order| sc: 93779 lt: 0 fl: 926