From c65cef8fd3486a82e4e2a0d01d69a74819ff672b Mon Sep 17 00:00:00 2001 From: Christopher Hotchkiss Date: Sat, 4 Sep 2021 14:53:36 -0400 Subject: [PATCH] Wired the primary key system in further. Found out my array support had major bugs in it. --- README.md | 3 +- src/engine/executor.rs | 46 ++++++++++++++++++- src/engine/io/row_formats/row_data.rs | 10 ++-- src/engine/objects.rs | 7 +-- src/engine/objects/constraint.rs | 13 ------ src/engine/objects/constraints.rs | 36 +++++++++++++++ .../objects/constraints/parse_constraint.rs | 21 +++++++++ src/engine/objects/types/base_sql_types.rs | 46 ++++++++++++++++++- 8 files changed, 159 insertions(+), 23 deletions(-) delete mode 100644 src/engine/objects/constraint.rs create mode 100644 src/engine/objects/constraints.rs create mode 100644 src/engine/objects/constraints/parse_constraint.rs diff --git a/README.md b/README.md index 6fd4c77..02030a2 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,8 @@ Reasonable application error type creation: https://github.com/dtolnay/anyhow Library Errors: https://github.com/dtolnay/thiserror -Rust's inability to treat enum variants as a type is a HUGE pain. I cheated and separated serialization from deserialization. +Rust's inability to treat enum variants as a type is a HUGE pain. I end up having an enum to hold data and another enum to validate and match the sub type. The [RFC](https://github.com/rust-lang/rfcs/pull/2593) to fix this was postponed indefinately. + ## Legal Stuff (Note I'm not a lawyer!) diff --git a/src/engine/executor.rs b/src/engine/executor.rs index e13c297..6507f22 100644 --- a/src/engine/executor.rs +++ b/src/engine/executor.rs @@ -1,6 +1,6 @@ use crate::constants::SystemTables; use crate::engine::objects::types::BaseSqlTypes; -use crate::engine::objects::SqlTuple; +use crate::engine::objects::{ConstraintMapper, SqlTuple}; use super::io::{ConstraintManager, ConstraintManagerError}; use super::objects::types::SqlTypeDefinition; @@ -149,6 +149,8 @@ impl Executor { cm.insert_row(tran_id, pg_class, table_row).await?; + let mut primary_key_cols = vec![]; + let pg_attribute = SystemTables::PgAttribute.value(); for i in 0..create_table.provided_columns.len() { let cm = self.cons_man.clone(); @@ -168,7 +170,49 @@ impl Executor { cm.clone() .insert_row(tran_id, pg_attribute.clone(), table_row) .await?; + + if create_table.provided_columns[i].primary_key { + primary_key_cols.push(BaseSqlTypes::Integer(i_u32)); + } } + + if !primary_key_cols.is_empty() { + //We assume the the order that columns with primary key were defined are the order desired + let pk_id = Uuid::new_v4(); + let primary_key_index = SqlTuple(vec![ + Some(BaseSqlTypes::Uuid(pk_id)), + Some(BaseSqlTypes::Uuid(table_id)), + Some(BaseSqlTypes::Text(format!( + "{}_primary_key_index", + create_table.table_name + ))), + Some(BaseSqlTypes::Array(primary_key_cols)), + Some(BaseSqlTypes::Bool(true)), + ]); + let pg_index = SystemTables::PgIndex.value(); + self.cons_man + .clone() + .insert_row(tran_id, pg_index, primary_key_index) + .await?; + + //Now we can insert the constraint + let primary_key_constraint = SqlTuple(vec![ + Some(BaseSqlTypes::Uuid(Uuid::new_v4())), + Some(BaseSqlTypes::Uuid(table_id)), + Some(BaseSqlTypes::Uuid(pk_id)), + Some(BaseSqlTypes::Text(format!( + "{}_primary_key", + create_table.table_name + ))), + Some(BaseSqlTypes::Text(ConstraintMapper::PrimaryKey.to_string())), + ]); + let pg_constraint = SystemTables::PgConstraint.value(); + self.cons_man + .clone() + .insert_row(tran_id, pg_constraint, primary_key_constraint) + .await?; + } + Ok(vec![]) } } diff --git a/src/engine/io/row_formats/row_data.rs b/src/engine/io/row_formats/row_data.rs index bc9d751..4d8a7a4 100644 --- a/src/engine/io/row_formats/row_data.rs +++ b/src/engine/io/row_formats/row_data.rs @@ -443,7 +443,7 @@ mod tests { ), Attribute::new( "header3".to_string(), - BaseSqlTypesMapper::Text, + BaseSqlTypesMapper::Array(Arc::new(BaseSqlTypesMapper::Integer)), Nullable::NotNull, None, ), @@ -452,14 +452,18 @@ mod tests { vec![], )); - let test = RowData::new(table.sql_type.clone(), + let test = RowData::new( + table.sql_type.clone(), TransactionId::new(1), None, get_item_pointer(), SqlTuple(vec![ Some(BaseSqlTypes::Text("this is a test".to_string())), None, - Some(BaseSqlTypes::Text("blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah".to_string())), + Some(BaseSqlTypes::Array(vec![ + BaseSqlTypes::Integer(1), + BaseSqlTypes::Integer(2), + ])), ]), ); diff --git a/src/engine/objects.rs b/src/engine/objects.rs index 4a1a998..1824c7e 100644 --- a/src/engine/objects.rs +++ b/src/engine/objects.rs @@ -1,9 +1,10 @@ mod attribute; pub use attribute::Attribute; -mod constraint; -pub use constraint::Constraint; -pub use constraint::PrimaryKeyConstraint; +mod constraints; +pub use constraints::Constraint; +pub use constraints::ConstraintMapper; +pub use constraints::PrimaryKeyConstraint; mod index; pub use index::Index; diff --git a/src/engine/objects/constraint.rs b/src/engine/objects/constraint.rs deleted file mode 100644 index b0af21e..0000000 --- a/src/engine/objects/constraint.rs +++ /dev/null @@ -1,13 +0,0 @@ -use super::Index; -use std::sync::Arc; - -#[derive(Clone, Debug, PartialEq)] -pub enum Constraint { - PrimaryKey(PrimaryKeyConstraint), -} - -#[derive(Clone, Debug, PartialEq)] -pub struct PrimaryKeyConstraint { - pub name: String, - pub index: Arc, -} diff --git a/src/engine/objects/constraints.rs b/src/engine/objects/constraints.rs new file mode 100644 index 0000000..94e106f --- /dev/null +++ b/src/engine/objects/constraints.rs @@ -0,0 +1,36 @@ +use super::Index; +use std::{ + fmt::{self, Display, Formatter}, + sync::Arc, +}; + +mod parse_constraint; + +#[derive(Clone, Debug, PartialEq)] +pub enum Constraint { + PrimaryKey(PrimaryKeyConstraint), +} + +/// ConstraintMapper exists to map to SqlType without imposing the cost of an empty version +/// +/// This will exist until this RFC is brought back: https://github.com/rust-lang/rfcs/pull/2593 +#[derive(Clone, Debug, PartialEq)] +pub enum ConstraintMapper { + PrimaryKey, +} + +impl Display for ConstraintMapper { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + PrimaryKey => { + write!(f, "PrimaryKey") + } + } + } +} + +#[derive(Clone, Debug, PartialEq)] +pub struct PrimaryKeyConstraint { + pub name: String, + pub index: Arc, +} diff --git a/src/engine/objects/constraints/parse_constraint.rs b/src/engine/objects/constraints/parse_constraint.rs new file mode 100644 index 0000000..1bcd9ec --- /dev/null +++ b/src/engine/objects/constraints/parse_constraint.rs @@ -0,0 +1,21 @@ +use nom::{ + bytes::complete::tag_no_case, + error::{make_error, ContextError, ErrorKind, ParseError}, + IResult, +}; + +use super::ConstraintMapper; + +pub fn parse_constraint<'a, E: ParseError<&'a str> + ContextError<&'a str>>( + input: &'a str, +) -> IResult<&'a str, ConstraintMapper, E> { + let (input, matched) = tag_no_case("PrimaryKey")(input)?; + + let constraint_type = match matched { + "PrimaryKey" => ConstraintMapper::PrimaryKey, + _ => { + return Err(nom::Err::Failure(make_error(input, ErrorKind::Fix))); + } + }; + Ok((input, constraint_type)) +} diff --git a/src/engine/objects/types/base_sql_types.rs b/src/engine/objects/types/base_sql_types.rs index ad9d6ef..cde12f3 100644 --- a/src/engine/objects/types/base_sql_types.rs +++ b/src/engine/objects/types/base_sql_types.rs @@ -31,7 +31,7 @@ pub enum BaseSqlTypes { /// BaseSqlTypesMapper exists to map to SqlType without imposing the cost of an empty version /// -/// This will exist until this RFC is fixed: https://github.com/rust-lang/rfcs/pull/2593 +/// This will exist until this RFC is brought back: https://github.com/rust-lang/rfcs/pull/2593 #[derive(Clone, Debug, PartialEq)] pub enum BaseSqlTypesMapper { Array(Arc), @@ -240,7 +240,9 @@ impl SelfEncodedSize for BaseSqlTypes { /// is not needed to find space. fn encoded_size(&self) -> usize { match self { - Self::Array(ref a) => a.iter().fold(0, |acc, x| acc + x.encoded_size()), + Self::Array(ref a) => { + expected_encoded_size(a.len()) + a.iter().fold(0, |acc, x| acc + x.encoded_size()) + } Self::Bool(_) => size_of::(), Self::Integer(_) => size_of::(), Self::Uuid(_) => size_of::(), @@ -372,6 +374,25 @@ mod tests { Ok(()) } + #[test] + fn test_array_roundtrip() -> Result<(), Box> { + let array = BaseSqlTypes::Array(vec![BaseSqlTypes::Integer(1), BaseSqlTypes::Integer(2)]); + + let mut buffer = BytesMut::new(); + array.serialize(&mut buffer); + + let mut buffer = buffer.freeze(); + + let parse = BaseSqlTypes::deserialize( + &BaseSqlTypesMapper::Array(Arc::new(BaseSqlTypesMapper::Integer)), + &mut buffer, + )?; + + assert_eq!(parse, array); + + Ok(()) + } + #[test] //Used to map if we have the types linked up right pub fn test_type_matches() { @@ -397,4 +418,25 @@ mod tests { assert!(!BaseSqlTypes::Text("foo".to_string()).type_matches(&BaseSqlTypesMapper::Uuid)); assert!(BaseSqlTypes::Text("foo".to_string()).type_matches(&BaseSqlTypesMapper::Text)); } + + #[test] + pub fn test_encoded_size() { + assert_eq!( + BaseSqlTypes::Array(vec![BaseSqlTypes::Integer(1), BaseSqlTypes::Integer(2)]) + .encoded_size(), + 9 + ); + assert_eq!( + BaseSqlTypes::Array(vec![ + BaseSqlTypes::Text("Test".to_string()), + BaseSqlTypes::Text("Test".to_string()) + ]) + .encoded_size(), + 11 + ); + assert_eq!(BaseSqlTypes::Bool(true).encoded_size(), 1); + assert_eq!(BaseSqlTypes::Integer(1).encoded_size(), 4); + assert_eq!(BaseSqlTypes::Text("Test".to_string()).encoded_size(), 5); + assert_eq!(BaseSqlTypes::Uuid(Uuid::new_v4()).encoded_size(), 16); + } }