diff --git a/benches/feophant_benchmark.rs b/benches/feophant_benchmark.rs
index e97a58f..f44ffdf 100644
--- a/benches/feophant_benchmark.rs
+++ b/benches/feophant_benchmark.rs
@@ -2,15 +2,12 @@ use criterion::BenchmarkId;
use criterion::Criterion;
use criterion::{criterion_group, criterion_main};
use feophantlib::constants::Nullable;
+use feophantlib::engine::get_row;
+use feophantlib::engine::get_table;
use feophantlib::engine::io::row_formats::RowData;
use feophantlib::engine::io::FileManager;
use feophantlib::engine::io::LockCacheManager;
use feophantlib::engine::io::RowManager;
-use feophantlib::engine::objects::types::BaseSqlTypes;
-use feophantlib::engine::objects::types::BaseSqlTypesMapper;
-use feophantlib::engine::objects::Attribute;
-use feophantlib::engine::objects::SqlTuple;
-use feophantlib::engine::objects::Table;
use feophantlib::engine::transactions::TransactionId;
use futures::pin_mut;
use std::sync::Arc;
@@ -18,41 +15,6 @@ use tempfile::TempDir;
use tokio::runtime::Builder;
use tokio_stream::StreamExt;
-fn get_table() -> Arc
{
- Arc::new(Table::new(
- uuid::Uuid::new_v4(),
- "test_table".to_string(),
- vec![
- Attribute::new(
- "header".to_string(),
- BaseSqlTypesMapper::Text,
- Nullable::NotNull,
- None,
- ),
- Attribute::new(
- "id".to_string(),
- BaseSqlTypesMapper::Uuid,
- Nullable::Null,
- None,
- ),
- Attribute::new(
- "header3".to_string(),
- BaseSqlTypesMapper::Text,
- Nullable::NotNull,
- None,
- ),
- ],
- ))
-}
-
-fn get_row(input: String) -> SqlTuple {
- SqlTuple(vec![
- Some(BaseSqlTypes::Text(input)),
- 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())),
- ])
-}
-
// Here we have an async function to benchmark
async fn row_manager_mass_insert(row_count: usize) -> Result<(), Box> {
let tmp = TempDir::new()?;
diff --git a/src/constants.rs b/src/constants.rs
index ef87a13..edd04ee 100644
--- a/src/constants.rs
+++ b/src/constants.rs
@@ -11,5 +11,5 @@ pub use pg_error_codes::PgErrorCodes;
mod pg_error_levels;
pub use pg_error_levels::PgErrorLevels;
-mod table_definitions;
-pub use table_definitions::TableDefinitions;
+pub mod system_tables;
+pub use system_tables::SystemTables;
diff --git a/src/constants/system_tables.rs b/src/constants/system_tables.rs
new file mode 100644
index 0000000..f69abe9
--- /dev/null
+++ b/src/constants/system_tables.rs
@@ -0,0 +1,35 @@
+//! This defines all the system internal tables so we can bootstrap the system.
+
+use super::super::engine::objects::Table;
+use std::sync::Arc;
+
+pub mod pg_attribute;
+pub mod pg_class;
+pub mod pg_constraint;
+pub mod pg_index;
+
+#[derive(Copy, Clone)]
+pub enum SystemTables {
+ PgAttribute, //Columns
+ PgClass, //Tables
+ PgConstraint,
+ PgIndex,
+}
+
+impl SystemTables {
+ //TODO Should this be removed?
+ pub const VALUES: [SystemTables; 4] = [
+ SystemTables::PgAttribute,
+ SystemTables::PgClass,
+ SystemTables::PgConstraint,
+ SystemTables::PgIndex,
+ ];
+ pub fn value(self) -> Arc {
+ match self {
+ SystemTables::PgClass => pg_class::get_table(),
+ SystemTables::PgAttribute => pg_attribute::get_table(),
+ SystemTables::PgConstraint => pg_constraint::get_table(),
+ SystemTables::PgIndex => pg_index::get_table(),
+ }
+ }
+}
diff --git a/src/constants/system_tables/pg_attribute.rs b/src/constants/system_tables/pg_attribute.rs
new file mode 100644
index 0000000..b3510db
--- /dev/null
+++ b/src/constants/system_tables/pg_attribute.rs
@@ -0,0 +1,76 @@
+use crate::constants::Nullable;
+use crate::engine::objects::{
+ types::{BaseSqlTypesMapper, SqlTypeDefinition},
+ Attribute, Constraint, Index, PrimaryKeyConstraint, Table,
+};
+use hex_literal::hex;
+use std::sync::Arc;
+use uuid::Uuid;
+
+pub const id: Uuid = Uuid::from_bytes(hex!("EE89957F3E9F482C836DDA6C349AC632"));
+pub const name: &str = "pg_attribute";
+
+pub const column_class_id: &str = "class_id";
+pub const column_name: &str = "name";
+pub const column_sql_type: &str = "type_name";
+pub const column_column_num: &str = "column_num";
+pub const column_nullable: &str = "nullable";
+
+pub fn get_columns() -> Vec {
+ vec![
+ Attribute::new(
+ column_class_id.to_string(),
+ BaseSqlTypesMapper::Uuid,
+ Nullable::NotNull,
+ None,
+ ),
+ Attribute::new(
+ column_name.to_string(),
+ BaseSqlTypesMapper::Text,
+ Nullable::NotNull,
+ None,
+ ),
+ Attribute::new(
+ column_sql_type.to_string(),
+ BaseSqlTypesMapper::Text, //TODO join to pg_type instead, for now its a string
+ Nullable::NotNull,
+ None,
+ ),
+ Attribute::new(
+ column_column_num.to_string(),
+ BaseSqlTypesMapper::Integer,
+ Nullable::NotNull,
+ None,
+ ),
+ Attribute::new(
+ column_nullable.to_string(),
+ BaseSqlTypesMapper::Bool,
+ Nullable::NotNull,
+ None,
+ ),
+ ]
+}
+
+pub fn get_index(attrs: &Vec) -> Arc {
+ Arc::new(Index {
+ id: Uuid::from_bytes(hex!("516B20412CF145A2AD9E39A8BDEB30A8")),
+ name: name.to_string() + "_name_index",
+ columns: Arc::new(SqlTypeDefinition::new(&[attrs[1].clone()])),
+ unique: true,
+ })
+}
+
+pub fn get_table() -> Arc {
+ let columns = get_columns();
+ let index = get_index(&columns);
+ Arc::new(Table::new(
+ id,
+ name.to_string(),
+ get_columns(),
+ vec![Constraint::PrimaryKey(PrimaryKeyConstraint {
+ name: index.name.clone() + "_primary_key",
+ index: index.clone(),
+ })],
+ vec![index],
+ ))
+}
diff --git a/src/constants/system_tables/pg_class.rs b/src/constants/system_tables/pg_class.rs
new file mode 100644
index 0000000..a6ad2f6
--- /dev/null
+++ b/src/constants/system_tables/pg_class.rs
@@ -0,0 +1,55 @@
+use crate::constants::Nullable;
+use crate::engine::objects::{
+ types::{BaseSqlTypesMapper, SqlTypeDefinition},
+ Attribute, Constraint, Index, PrimaryKeyConstraint, Table,
+};
+use hex_literal::hex;
+use std::sync::Arc;
+use uuid::Uuid;
+
+pub const id: Uuid = Uuid::from_bytes(hex!("EE919E33D9054F4889537EBB6CC911EB"));
+pub const name: &str = "pg_class";
+
+pub const column_id: &str = "id";
+pub const column_name: &str = "name";
+
+pub fn get_columns() -> Vec {
+ vec![
+ Attribute::new(
+ column_id.to_string(),
+ BaseSqlTypesMapper::Uuid,
+ Nullable::NotNull,
+ None,
+ ),
+ Attribute::new(
+ column_name.to_string(),
+ BaseSqlTypesMapper::Text,
+ Nullable::NotNull,
+ None,
+ ),
+ ]
+}
+
+pub fn get_index(attrs: &Vec) -> Arc {
+ Arc::new(Index {
+ id: Uuid::from_bytes(hex!("516B20412CF145A2AD9E39A8BDEB30A8")),
+ name: name.to_string() + "_name_index",
+ columns: Arc::new(SqlTypeDefinition::new(&[attrs[1].clone()])),
+ unique: true,
+ })
+}
+
+pub fn get_table() -> Arc {
+ let columns = get_columns();
+ let index = get_index(&columns);
+ Arc::new(Table::new(
+ id,
+ name.to_string(),
+ columns,
+ vec![Constraint::PrimaryKey(PrimaryKeyConstraint {
+ name: name.to_string() + "_primary_key",
+ index: index.clone(),
+ })],
+ vec![index],
+ ))
+}
diff --git a/src/constants/system_tables/pg_constraint.rs b/src/constants/system_tables/pg_constraint.rs
new file mode 100644
index 0000000..131f31f
--- /dev/null
+++ b/src/constants/system_tables/pg_constraint.rs
@@ -0,0 +1,76 @@
+use crate::constants::Nullable;
+use crate::engine::objects::{
+ types::{BaseSqlTypesMapper, SqlTypeDefinition},
+ Attribute, Constraint, Index, PrimaryKeyConstraint, Table,
+};
+use hex_literal::hex;
+use std::sync::Arc;
+use uuid::Uuid;
+
+pub const id: Uuid = Uuid::from_bytes(hex!("DB6AB6BB401B4071BE52763C0C550600"));
+pub const name: &str = "pg_constraint";
+
+pub const column_id: &str = "id";
+pub const column_class_id: &str = "class_id";
+pub const column_index_id: &str = "index_id";
+pub const column_name: &str = "name";
+pub const column_type: &str = "type";
+
+pub fn get_columns() -> Vec {
+ vec![
+ Attribute::new(
+ column_id.to_string(),
+ BaseSqlTypesMapper::Uuid,
+ Nullable::NotNull,
+ None,
+ ),
+ Attribute::new(
+ column_class_id.to_string(),
+ BaseSqlTypesMapper::Uuid,
+ Nullable::NotNull,
+ None,
+ ),
+ Attribute::new(
+ column_index_id.to_string(),
+ BaseSqlTypesMapper::Uuid,
+ Nullable::NotNull,
+ None,
+ ),
+ Attribute::new(
+ column_name.to_string(),
+ BaseSqlTypesMapper::Text,
+ Nullable::NotNull,
+ None,
+ ),
+ Attribute::new(
+ column_type.to_string(),
+ BaseSqlTypesMapper::Text,
+ Nullable::NotNull,
+ None,
+ ),
+ ]
+}
+
+pub fn get_index(attrs: &Vec) -> Arc {
+ Arc::new(Index {
+ id: Uuid::from_bytes(hex!("27182DE783AB42D8B5DD43BFC0154F0F")),
+ name: name.to_string() + "_name_index",
+ columns: Arc::new(SqlTypeDefinition::new(&[attrs[3].clone()])),
+ unique: true,
+ })
+}
+
+pub fn get_table() -> Arc {
+ let columns = get_columns();
+ let index = get_index(&columns);
+ Arc::new(Table::new(
+ id,
+ name.to_string(),
+ columns,
+ vec![Constraint::PrimaryKey(PrimaryKeyConstraint {
+ name: name.to_string() + "_primary_key",
+ index: index.clone(),
+ })],
+ vec![index],
+ ))
+}
diff --git a/src/constants/system_tables/pg_index.rs b/src/constants/system_tables/pg_index.rs
new file mode 100644
index 0000000..a7f4691
--- /dev/null
+++ b/src/constants/system_tables/pg_index.rs
@@ -0,0 +1,76 @@
+use crate::constants::Nullable;
+use crate::engine::objects::{
+ types::{BaseSqlTypesMapper, SqlTypeDefinition},
+ Attribute, Constraint, Index, PrimaryKeyConstraint, Table,
+};
+use hex_literal::hex;
+use std::sync::Arc;
+use uuid::Uuid;
+
+pub const id: Uuid = Uuid::from_bytes(hex!("3AB3B076A0EA46E186130F088D06FA02"));
+pub const name: &str = "pg_index";
+
+pub const column_id: &str = "id";
+pub const column_class_id: &str = "class_id";
+pub const column_name: &str = "name";
+pub const column_attributes: &str = "attributes";
+pub const column_unique: &str = "unique";
+
+pub fn get_columns() -> Vec {
+ vec![
+ Attribute::new(
+ column_id.to_string(),
+ BaseSqlTypesMapper::Uuid,
+ Nullable::NotNull,
+ None,
+ ),
+ Attribute::new(
+ column_class_id.to_string(),
+ BaseSqlTypesMapper::Uuid,
+ Nullable::NotNull,
+ None,
+ ),
+ Attribute::new(
+ column_name.to_string(),
+ BaseSqlTypesMapper::Text,
+ Nullable::NotNull,
+ None,
+ ),
+ Attribute::new(
+ column_attributes.to_string(),
+ BaseSqlTypesMapper::Array(Arc::new(BaseSqlTypesMapper::Integer)),
+ Nullable::NotNull,
+ None,
+ ),
+ Attribute::new(
+ column_unique.to_string(),
+ BaseSqlTypesMapper::Bool,
+ Nullable::NotNull,
+ None,
+ ),
+ ]
+}
+
+pub fn get_index(attrs: &Vec) -> Arc {
+ Arc::new(Index {
+ id: Uuid::from_bytes(hex!("5F59466782874C568F1C0C09E99C9249")),
+ name: name.to_string() + "_name_index",
+ columns: Arc::new(SqlTypeDefinition::new(&[attrs[2].clone()])),
+ unique: true,
+ })
+}
+
+pub fn get_table() -> Arc {
+ let columns = get_columns();
+ let index = get_index(&columns);
+ Arc::new(Table::new(
+ id,
+ name.to_string(),
+ columns,
+ vec![Constraint::PrimaryKey(PrimaryKeyConstraint {
+ name: name.to_string() + "_primary_key",
+ index: index.clone(),
+ })],
+ vec![index],
+ ))
+}
diff --git a/src/constants/table_definitions.rs b/src/constants/table_definitions.rs
deleted file mode 100644
index 2735be0..0000000
--- a/src/constants/table_definitions.rs
+++ /dev/null
@@ -1,78 +0,0 @@
-//! This defines all the system internal tables so we can bootstrap the system
-
-use super::super::engine::objects::{Attribute, Table};
-use crate::constants::Nullable;
-use crate::engine::objects::types::BaseSqlTypesMapper;
-use hex_literal::hex;
-use std::sync::Arc;
-use uuid::Uuid;
-
-#[derive(Copy, Clone)]
-pub enum TableDefinitions {
- PgAttribute, //Columns
- PgClass, //Tables
-}
-
-impl TableDefinitions {
- //TODO Should this be removed?
- pub const VALUES: [TableDefinitions; 2] =
- [TableDefinitions::PgAttribute, TableDefinitions::PgClass];
- pub fn value(self) -> Arc {
- match self {
- TableDefinitions::PgClass => Arc::new(Table::new(
- Uuid::from_bytes(hex!("EE919E33D9054F4889537EBB6CC911EB")),
- "pg_class".to_string(),
- vec![
- Attribute::new(
- "id".to_string(),
- BaseSqlTypesMapper::Uuid,
- Nullable::NotNull,
- None,
- ),
- Attribute::new(
- "name".to_string(),
- BaseSqlTypesMapper::Text,
- Nullable::NotNull,
- None,
- ),
- ],
- )),
- TableDefinitions::PgAttribute => Arc::new(Table::new(
- Uuid::from_bytes(hex!("EE89957F3E9F482C836DDA6C349AC632")),
- "pg_attribute".to_string(),
- vec![
- Attribute::new(
- "attrelid".to_string(),
- BaseSqlTypesMapper::Uuid,
- Nullable::NotNull,
- None,
- ),
- Attribute::new(
- "attname".to_string(),
- BaseSqlTypesMapper::Text,
- Nullable::NotNull,
- None,
- ),
- Attribute::new(
- "atttypid".to_string(),
- BaseSqlTypesMapper::Text, //TODO join to pg_type instead, for now its a string
- Nullable::NotNull,
- None,
- ),
- Attribute::new(
- "attnum".to_string(),
- BaseSqlTypesMapper::Integer,
- Nullable::NotNull,
- None,
- ),
- Attribute::new(
- "attnotnull".to_string(),
- BaseSqlTypesMapper::Bool,
- Nullable::NotNull,
- None,
- ),
- ],
- )),
- }
- }
-}
diff --git a/src/engine.rs b/src/engine.rs
index b886c2b..07c6d77 100644
--- a/src/engine.rs
+++ b/src/engine.rs
@@ -24,6 +24,12 @@ pub mod sql_parser;
pub use sql_parser::SqlParser;
pub use sql_parser::SqlParserError;
+//This module is solely to reduce code duplication in tests.
+//I was conditionally compliling it but that breaks benchmarks and integration tests
+pub mod test_objects;
+pub use test_objects::get_row;
+pub use test_objects::get_table;
+
pub mod transactions;
use transactions::{TransactionId, TransactionManager};
diff --git a/src/engine/analyzer/definition_lookup.rs b/src/engine/analyzer/definition_lookup.rs
index 50dc9ad..459ecce 100644
--- a/src/engine/analyzer/definition_lookup.rs
+++ b/src/engine/analyzer/definition_lookup.rs
@@ -1,7 +1,6 @@
//! This command will look up ONLY hardcoded table definitions first,
//! should be able to fallback to reading new ones off disk
-
-use super::super::super::constants::TableDefinitions;
+//TODO we should use the existing sql query functionality instead of this handcoded stuff
use super::super::io::row_formats::{RowData, RowDataError};
use super::super::io::{VisibleRowManager, VisibleRowManagerError};
use super::super::objects::{
@@ -9,8 +8,10 @@ use super::super::objects::{
Attribute, Table, TableError,
};
use super::super::transactions::TransactionId;
-use crate::constants::Nullable;
-use crate::engine::objects::types::BaseSqlTypesError;
+use crate::constants::system_tables::{pg_attribute, pg_class, pg_constraint, pg_index};
+use crate::constants::{Nullable, SystemTables};
+use crate::engine::objects::types::{BaseSqlTypesError, SqlTypeDefinition};
+use crate::engine::objects::{Constraint, Index, PrimaryKeyConstraint};
use std::convert::TryFrom;
use std::num::TryFromIntError;
use std::str::FromStr;
@@ -36,37 +37,32 @@ impl DefinitionLookup {
name: String,
) -> Result, DefinitionLookupError> {
//System Tables always load
- let system_tables = TableDefinitions::VALUES;
+ let system_tables = SystemTables::VALUES;
for i in &system_tables {
if i.value().name == name {
return Ok(i.value());
}
}
- //TODO not happy with how many strings there are
- let tbl_row = self.get_table_row(tran_id, name).await?;
- let table_id = match tbl_row.get_column_not_null("id")? {
+ let pg_class_entry = self.get_table_row(tran_id, name.clone()).await?;
+ let table_id = match pg_class_entry.get_column_not_null(pg_class::column_id)? {
BaseSqlTypes::Uuid(u) => u,
_ => return Err(DefinitionLookupError::ColumnWrongType()),
};
- let table_name = match tbl_row.get_column_not_null("name")? {
- BaseSqlTypes::Text(t) => t,
- _ => return Err(DefinitionLookupError::ColumnWrongType()),
- };
let tbl_columns = self.get_table_columns(tran_id, table_id).await?;
let mut tbl_attrs = vec![];
for c in tbl_columns {
- let c_name = match c.get_column_not_null("attname")? {
+ let c_name = match c.get_column_not_null(pg_attribute::column_name)? {
BaseSqlTypes::Text(t) => t,
_ => return Err(DefinitionLookupError::ColumnWrongType()),
};
- let c_type = match c.get_column_not_null("atttypid")? {
+ let c_type = match c.get_column_not_null(pg_attribute::column_sql_type)? {
BaseSqlTypes::Text(t) => t,
_ => return Err(DefinitionLookupError::ColumnWrongType()),
};
- let c_null = match c.get_column_not_null("attnotnull")? {
+ let c_null = match c.get_column_not_null(pg_attribute::column_nullable)? {
BaseSqlTypes::Bool(b) => Nullable::from(b),
_ => return Err(DefinitionLookupError::ColumnWrongType()),
};
@@ -79,7 +75,20 @@ impl DefinitionLookup {
));
}
- Ok(Arc::new(Table::new(table_id, table_name, tbl_attrs)))
+ let indexes = self
+ .get_table_indexes(tran_id, table_id, &tbl_attrs)
+ .await?;
+ let constraints = self
+ .get_table_constraints(tran_id, table_id, &indexes)
+ .await?;
+
+ Ok(Arc::new(Table::new(
+ table_id,
+ name,
+ tbl_attrs,
+ constraints,
+ indexes,
+ )))
}
async fn get_table_row(
@@ -87,13 +96,14 @@ impl DefinitionLookup {
tran_id: TransactionId,
name: String,
) -> Result {
- //Now we have to search
- let pg_class = TableDefinitions::PgClass.value();
- let row_stream = self.vis_row_man.clone().get_stream(tran_id, pg_class);
+ let row_stream = self
+ .vis_row_man
+ .clone()
+ .get_stream(tran_id, SystemTables::PgClass.value().clone());
pin!(row_stream);
while let Some(row_res) = row_stream.next().await {
let row = row_res?;
- if row.get_column_not_null("name")? == BaseSqlTypes::Text(name.clone()) {
+ if row.get_column_not_null(pg_class::column_name)? == BaseSqlTypes::Text(name.clone()) {
return Ok(row);
}
}
@@ -104,10 +114,10 @@ impl DefinitionLookup {
async fn get_table_columns(
&self,
tran_id: TransactionId,
- attrelid: Uuid,
+ class_id: Uuid,
) -> Result, DefinitionLookupError> {
let mut columns = vec![];
- let pg_attr = TableDefinitions::PgAttribute.value();
+ let pg_attr = SystemTables::PgAttribute.value();
let row_stream = self
.vis_row_man
.clone()
@@ -115,7 +125,9 @@ impl DefinitionLookup {
pin!(row_stream);
while let Some(row_res) = row_stream.next().await {
let row = row_res?;
- if row.get_column_not_null("attrelid")? == BaseSqlTypes::Uuid(attrelid) {
+ if row.get_column_not_null(pg_attribute::column_class_id)?
+ == BaseSqlTypes::Uuid(class_id)
+ {
columns.push(row);
}
}
@@ -125,7 +137,7 @@ impl DefinitionLookup {
}
//Figure out what column we're dealing with
- let col_offset = pg_attr.get_column_index("attnum".to_string())?;
+ let col_offset = pg_attr.get_column_index(pg_attribute::column_column_num)?;
//Extract column number into tuples so we can sort
let mut column_tuples = vec![];
@@ -158,6 +170,126 @@ impl DefinitionLookup {
Ok(columns)
}
+
+ async fn get_table_indexes(
+ &self,
+ tran_id: TransactionId,
+ class_id: Uuid,
+ attributes: &Vec,
+ ) -> Result>, DefinitionLookupError> {
+ let mut rows = vec![];
+ let row_stream = self
+ .vis_row_man
+ .clone()
+ .get_stream(tran_id, SystemTables::PgIndex.value().clone());
+ pin!(row_stream);
+ while let Some(row_res) = row_stream.next().await {
+ let row = row_res?;
+ if row.get_column_not_null(pg_index::column_class_id)? == BaseSqlTypes::Uuid(class_id) {
+ rows.push(row);
+ }
+ }
+
+ if rows.is_empty() {
+ return Ok(vec![]);
+ }
+
+ let mut indexes = vec![];
+ for r in rows.iter() {
+ let id = match r.get_column_not_null(pg_index::column_id)? {
+ BaseSqlTypes::Uuid(u) => u,
+ _ => return Err(DefinitionLookupError::ColumnWrongType()),
+ };
+ let name = match r.get_column_not_null(pg_index::column_name)? {
+ BaseSqlTypes::Text(t) => t,
+ _ => return Err(DefinitionLookupError::ColumnWrongType()),
+ };
+ let columns = match r.get_column_not_null(pg_index::column_attributes)? {
+ BaseSqlTypes::Array(a) => {
+ let mut cols = vec![];
+ for col in a {
+ match col {
+ BaseSqlTypes::Integer(i) => {
+ let i_usize = usize::try_from(i)?;
+ cols.push(
+ attributes
+ .get(i_usize)
+ .ok_or_else(|| {
+ DefinitionLookupError::WrongColumnIndex(i_usize)
+ })?
+ .clone(),
+ );
+ }
+ _ => {
+ return Err(DefinitionLookupError::ColumnWrongType());
+ }
+ }
+ }
+ cols
+ }
+ _ => return Err(DefinitionLookupError::ColumnWrongType()),
+ };
+ let unique = match r.get_column_not_null(pg_index::column_unique)? {
+ BaseSqlTypes::Bool(b) => b,
+ _ => return Err(DefinitionLookupError::ColumnWrongType()),
+ };
+
+ indexes.push(Arc::new(Index {
+ id,
+ name,
+ columns: Arc::new(SqlTypeDefinition::new(&columns)),
+ unique,
+ }));
+ }
+
+ Ok(indexes)
+ }
+
+ async fn get_table_constraints(
+ &self,
+ tran_id: TransactionId,
+ class_id: Uuid,
+ indexes: &Vec>,
+ ) -> Result, DefinitionLookupError> {
+ let mut rows = vec![];
+ let row_stream = self
+ .vis_row_man
+ .clone()
+ .get_stream(tran_id, SystemTables::PgConstraint.value().clone());
+ pin!(row_stream);
+ while let Some(row_res) = row_stream.next().await {
+ let row = row_res?;
+ if row.get_column_not_null(pg_constraint::column_class_id)?
+ == BaseSqlTypes::Uuid(class_id)
+ {
+ rows.push(row);
+ }
+ }
+
+ let mut constraints = vec![];
+ for r in rows.iter() {
+ let name = match r.get_column_not_null(pg_constraint::column_name)? {
+ BaseSqlTypes::Text(t) => t,
+ _ => return Err(DefinitionLookupError::ColumnWrongType()),
+ };
+ let index_id = match r.get_column_not_null(pg_constraint::column_index_id)? {
+ BaseSqlTypes::Uuid(u) => u,
+ _ => return Err(DefinitionLookupError::ColumnWrongType()),
+ };
+
+ for i in indexes {
+ if i.id == index_id {
+ constraints.push(Constraint::PrimaryKey(PrimaryKeyConstraint {
+ name,
+ index: i.clone(),
+ }));
+ break;
+ }
+ }
+ return Err(DefinitionLookupError::IndexDoesNotExist(index_id));
+ }
+ Ok(constraints)
+ }
}
#[derive(Debug, Error)]
@@ -176,6 +308,8 @@ pub enum DefinitionLookupError {
ColumnWrongType(),
#[error("Gap in columns found at {0}")]
ColumnGap(usize),
+ #[error("Index {0} does not exist")]
+ IndexDoesNotExist(Uuid),
#[error(transparent)]
RowDataError(#[from] RowDataError),
#[error(transparent)]
diff --git a/src/engine/executor.rs b/src/engine/executor.rs
index 1bdb6e3..e13c297 100644
--- a/src/engine/executor.rs
+++ b/src/engine/executor.rs
@@ -1,7 +1,7 @@
+use crate::constants::SystemTables;
use crate::engine::objects::types::BaseSqlTypes;
use crate::engine::objects::SqlTuple;
-use super::super::constants::TableDefinitions;
use super::io::{ConstraintManager, ConstraintManagerError};
use super::objects::types::SqlTypeDefinition;
use super::objects::{ParseTree, Plan, PlannedStatement, SqlTupleError, Table};
@@ -141,7 +141,7 @@ impl Executor {
};
let table_id = Uuid::new_v4();
- let pg_class = TableDefinitions::PgClass.value();
+ let pg_class = SystemTables::PgClass.value();
let table_row = SqlTuple(vec![
Some(BaseSqlTypes::Uuid(table_id)),
Some(BaseSqlTypes::Text(create_table.table_name.clone())),
@@ -149,7 +149,7 @@ impl Executor {
cm.insert_row(tran_id, pg_class, table_row).await?;
- let pg_attribute = TableDefinitions::PgAttribute.value();
+ let pg_attribute = SystemTables::PgAttribute.value();
for i in 0..create_table.provided_columns.len() {
let cm = self.cons_man.clone();
let i_u32 = u32::try_from(i).map_err(ExecutorError::ConversionError)?;
diff --git a/src/engine/io/index_formats/btree_branch.rs b/src/engine/io/index_formats/btree_branch.rs
index 9dc6010..1b1562b 100644
--- a/src/engine/io/index_formats/btree_branch.rs
+++ b/src/engine/io/index_formats/btree_branch.rs
@@ -99,11 +99,13 @@ pub enum BTreeBranchError {
#[cfg(test)]
mod tests {
+ use std::sync::Arc;
+
use super::*;
use crate::{
- constants::{Nullable, TableDefinitions},
+ constants::Nullable,
engine::objects::{
- types::{BaseSqlTypes, BaseSqlTypesMapper},
+ types::{BaseSqlTypes, BaseSqlTypesMapper, SqlTypeDefinition},
Attribute, Index, Table,
},
};
@@ -126,14 +128,10 @@ mod tests {
),
];
- let tbl = Table::new(tbl_uuid, "Test Table".to_string(), attrs);
-
Index {
id: Uuid::new_v4(),
- pg_class_id: Uuid::new_v4(),
name: "TestIndex".to_string(),
- table: TableDefinitions::VALUES[0].value(),
- columns: tbl.attributes,
+ columns: Arc::new(SqlTypeDefinition::new(&attrs)),
unique: true,
}
}
diff --git a/src/engine/io/index_formats/btree_leaf.rs b/src/engine/io/index_formats/btree_leaf.rs
index 1fde6fa..71546ce 100644
--- a/src/engine/io/index_formats/btree_leaf.rs
+++ b/src/engine/io/index_formats/btree_leaf.rs
@@ -138,13 +138,15 @@ pub enum BTreeLeafError {
#[cfg(test)]
mod tests {
+ use std::sync::Arc;
+
use super::*;
use crate::{
- constants::{Nullable, TableDefinitions},
+ constants::Nullable,
engine::{
io::page_formats::UInt12,
objects::{
- types::{BaseSqlTypes, BaseSqlTypesMapper},
+ types::{BaseSqlTypes, BaseSqlTypesMapper, SqlTypeDefinition},
Attribute, Index, Table,
},
},
@@ -168,14 +170,10 @@ mod tests {
),
];
- let tbl = Table::new(tbl_uuid, "Test Table".to_string(), attrs);
-
Index {
id: Uuid::new_v4(),
- pg_class_id: Uuid::new_v4(),
name: "TestIndex".to_string(),
- table: TableDefinitions::VALUES[0].value(),
- columns: tbl.attributes,
+ columns: Arc::new(SqlTypeDefinition::new(&attrs)),
unique: true,
}
}
diff --git a/src/engine/io/index_formats/btree_node.rs b/src/engine/io/index_formats/btree_node.rs
index 0b67a5f..8a19862 100644
--- a/src/engine/io/index_formats/btree_node.rs
+++ b/src/engine/io/index_formats/btree_node.rs
@@ -166,7 +166,7 @@ impl BTreeNode {
if nulls[c] {
bucket.push(None);
} else {
- let key = BaseSqlTypes::deserialize(&index_def.columns[c].sql_type, buffer)?;
+ let key = BaseSqlTypes::deserialize(&index_def.columns[c].1, buffer)?;
bucket.push(Some(key));
}
}
diff --git a/src/engine/io/page_formats/page_data.rs b/src/engine/io/page_formats/page_data.rs
index c30c0c7..0be91f6 100644
--- a/src/engine/io/page_formats/page_data.rs
+++ b/src/engine/io/page_formats/page_data.rs
@@ -164,6 +164,7 @@ pub enum PageDataError {
#[cfg(test)]
mod tests {
use crate::constants::{Nullable, PAGE_SIZE};
+ use crate::engine::get_table;
use crate::engine::objects::SqlTuple;
use super::super::super::super::objects::{
@@ -180,33 +181,6 @@ mod tests {
ItemPointer::new(PageOffset(0), UInt12::new(row_num as u16).unwrap())
}
- fn get_table() -> Arc {
- Arc::new(Table::new(
- uuid::Uuid::new_v4(),
- "test_table".to_string(),
- vec![
- Attribute::new(
- "header".to_string(),
- BaseSqlTypesMapper::Text,
- Nullable::NotNull,
- None,
- ),
- Attribute::new(
- "id".to_string(),
- BaseSqlTypesMapper::Uuid,
- Nullable::Null,
- None,
- ),
- Attribute::new(
- "header3".to_string(),
- BaseSqlTypesMapper::Text,
- Nullable::NotNull,
- None,
- ),
- ],
- ))
- }
-
#[tokio::test]
async fn test_page_data_roundtrip() -> Result<(), Box> {
let table = get_table();
diff --git a/src/engine/io/row_formats/row_data.rs b/src/engine/io/row_formats/row_data.rs
index 2d52105..45b78ae 100644
--- a/src/engine/io/row_formats/row_data.rs
+++ b/src/engine/io/row_formats/row_data.rs
@@ -238,6 +238,8 @@ mod tests {
Nullable::NotNull,
None,
)],
+ vec![],
+ vec![],
));
let test = RowData::new(
@@ -277,6 +279,8 @@ mod tests {
None,
),
],
+ vec![],
+ vec![],
));
let test = RowData::new(
@@ -311,6 +315,8 @@ mod tests {
Nullable::NotNull,
None,
)],
+ vec![],
+ vec![],
));
let test = RowData::new(
@@ -350,6 +356,8 @@ mod tests {
None,
),
],
+ vec![],
+ vec![],
));
let test = RowData::new(
@@ -392,6 +400,8 @@ mod tests {
None,
),
],
+ vec![],
+ vec![],
));
let test = RowData::new(
@@ -438,6 +448,8 @@ mod tests {
None,
),
],
+ vec![],
+ vec![],
));
let test = RowData::new(table.sql_type.clone(),
diff --git a/src/engine/io/row_manager.rs b/src/engine/io/row_manager.rs
index cfd03a2..c391ad1 100644
--- a/src/engine/io/row_manager.rs
+++ b/src/engine/io/row_manager.rs
@@ -304,52 +304,14 @@ pub enum RowManagerError {
#[cfg(test)]
mod tests {
- use super::super::super::objects::Attribute;
- use super::super::super::objects::Table;
use super::*;
- use crate::constants::Nullable;
+ use crate::engine::get_row;
+ use crate::engine::get_table;
use crate::engine::io::FileManager;
- use crate::engine::objects::types::BaseSqlTypes;
- use crate::engine::objects::types::BaseSqlTypesMapper;
use futures::pin_mut;
use tempfile::TempDir;
use tokio_stream::StreamExt;
- fn get_table() -> Arc {
- Arc::new(Table::new(
- uuid::Uuid::new_v4(),
- "test_table".to_string(),
- vec![
- Attribute::new(
- "header".to_string(),
- BaseSqlTypesMapper::Text,
- Nullable::NotNull,
- None,
- ),
- Attribute::new(
- "id".to_string(),
- BaseSqlTypesMapper::Uuid,
- Nullable::Null,
- None,
- ),
- Attribute::new(
- "header3".to_string(),
- BaseSqlTypesMapper::Text,
- Nullable::NotNull,
- None,
- ),
- ],
- ))
- }
-
- fn get_row(input: String) -> SqlTuple {
- SqlTuple(vec![
- Some(BaseSqlTypes::Text(input)),
- 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())),
- ])
- }
-
#[tokio::test]
async fn test_row_manager_mass_insert() -> Result<(), Box> {
let tmp = TempDir::new()?;
diff --git a/src/engine/objects.rs b/src/engine/objects.rs
index 34c841d..4a1a998 100644
--- a/src/engine/objects.rs
+++ b/src/engine/objects.rs
@@ -1,6 +1,10 @@
mod attribute;
pub use attribute::Attribute;
+mod constraint;
+pub use constraint::Constraint;
+pub use constraint::PrimaryKeyConstraint;
+
mod index;
pub use index::Index;
diff --git a/src/engine/objects/constraint.rs b/src/engine/objects/constraint.rs
new file mode 100644
index 0000000..b0af21e
--- /dev/null
+++ b/src/engine/objects/constraint.rs
@@ -0,0 +1,13 @@
+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/index.rs b/src/engine/objects/index.rs
index 6b3f4a2..82c6f68 100644
--- a/src/engine/objects/index.rs
+++ b/src/engine/objects/index.rs
@@ -1,14 +1,12 @@
use uuid::Uuid;
-use super::{Attribute, Table};
+use super::types::SqlTypeDefinition;
use std::sync::Arc;
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, PartialEq)]
pub struct Index {
pub id: Uuid,
- pub pg_class_id: Uuid,
pub name: String,
- pub table: Arc,
- pub columns: Vec,
+ pub columns: Arc,
pub unique: bool,
}
diff --git a/src/engine/objects/table.rs b/src/engine/objects/table.rs
index 313e341..a83860f 100644
--- a/src/engine/objects/table.rs
+++ b/src/engine/objects/table.rs
@@ -2,7 +2,7 @@
use std::sync::Arc;
-use super::{types::SqlTypeDefinition, Attribute};
+use super::{types::SqlTypeDefinition, Attribute, Constraint, Index};
use thiserror::Error;
use uuid::Uuid;
@@ -11,35 +11,39 @@ pub struct Table {
pub id: Uuid,
pub name: String,
pub attributes: Vec,
+ pub constraints: Vec,
+ pub indexes: Vec>,
pub sql_type: Arc,
}
impl Table {
- pub fn new(id: Uuid, name: String, attributes: Vec) -> Table {
- let sql_type = SqlTypeDefinition(
- attributes
- .iter()
- .map(|a| (a.name.clone(), a.sql_type.clone()))
- .collect(),
- );
-
+ pub fn new(
+ id: Uuid,
+ name: String,
+ attributes: Vec,
+ constraints: Vec,
+ indexes: Vec>,
+ ) -> Table {
+ let sql_type = Arc::new(SqlTypeDefinition::new(&attributes));
Table {
id,
name,
attributes,
- sql_type: Arc::new(sql_type),
+ constraints,
+ indexes,
+ sql_type,
}
}
//TODO might not be need any more with the type
- pub fn get_column_index(&self, name: String) -> Result {
+ pub fn get_column_index(&self, name: &str) -> Result {
for i in 0..self.attributes.len() {
if self.attributes[i].name == name {
return Ok(i);
}
}
- Err(TableError::ColumnDoesNotExist(name))
+ Err(TableError::ColumnDoesNotExist(name.to_string()))
}
}
diff --git a/src/engine/objects/types/sql_type_definition.rs b/src/engine/objects/types/sql_type_definition.rs
index f92526a..be15e00 100644
--- a/src/engine/objects/types/sql_type_definition.rs
+++ b/src/engine/objects/types/sql_type_definition.rs
@@ -1,3 +1,5 @@
+use crate::engine::objects::Attribute;
+
use super::base_sql_types::BaseSqlTypesMapper;
use std::{
fmt::{self, Display, Formatter},
@@ -9,6 +11,17 @@ use std::{
// TODO I'm not super happy with the use of Vec but I need the order preseved and easy acess to the offset.
pub struct SqlTypeDefinition(pub Vec<(String, BaseSqlTypesMapper)>);
+impl SqlTypeDefinition {
+ pub fn new(attributes: &[Attribute]) -> SqlTypeDefinition {
+ SqlTypeDefinition(
+ attributes
+ .iter()
+ .map(|a| (a.name.clone(), a.sql_type.clone()))
+ .collect(),
+ )
+ }
+}
+
impl Deref for SqlTypeDefinition {
type Target = Vec<(String, BaseSqlTypesMapper)>;
diff --git a/src/engine/test_objects.rs b/src/engine/test_objects.rs
new file mode 100644
index 0000000..9b8b128
--- /dev/null
+++ b/src/engine/test_objects.rs
@@ -0,0 +1,48 @@
+//! Set of functions used for unit testing instead of copying them everywhere
+
+use super::objects::{SqlTuple, Table};
+use crate::{
+ constants::Nullable,
+ engine::objects::{
+ types::{BaseSqlTypes, BaseSqlTypesMapper},
+ Attribute,
+ },
+};
+use std::sync::Arc;
+
+pub fn get_row(input: String) -> SqlTuple {
+ SqlTuple(vec![
+ Some(BaseSqlTypes::Text(input)),
+ 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())),
+ ])
+}
+
+pub fn get_table() -> Arc {
+ Arc::new(Table::new(
+ uuid::Uuid::new_v4(),
+ "test_table".to_string(),
+ vec![
+ Attribute::new(
+ "header".to_string(),
+ BaseSqlTypesMapper::Text,
+ Nullable::NotNull,
+ None,
+ ),
+ Attribute::new(
+ "id".to_string(),
+ BaseSqlTypesMapper::Uuid,
+ Nullable::Null,
+ None,
+ ),
+ Attribute::new(
+ "header3".to_string(),
+ BaseSqlTypesMapper::Text,
+ Nullable::NotNull,
+ None,
+ ),
+ ],
+ vec![],
+ vec![],
+ ))
+}
diff --git a/tests/common/mod.rs b/tests/common/mod.rs
index 7d24fdb..a9a11dd 100644
--- a/tests/common/mod.rs
+++ b/tests/common/mod.rs
@@ -1,3 +1,8 @@
+use std::sync::Arc;
+
+use feophantlib::constants::Nullable;
+use feophantlib::engine::objects::types::{BaseSqlTypes, BaseSqlTypesMapper};
+use feophantlib::engine::objects::{Attribute, SqlTuple, Table};
use feophantlib::feophant::FeOphant;
use log::LevelFilter;
use simplelog::{ColorChoice, CombinedLogger, Config, TermLogger, TerminalMode};
diff --git a/tests/visibility_tests.rs b/tests/visibility_tests.rs
index deac94e..2a63d06 100644
--- a/tests/visibility_tests.rs
+++ b/tests/visibility_tests.rs
@@ -1,13 +1,7 @@
-use feophantlib::{
- constants::Nullable,
- engine::{
- io::{row_formats::RowData, FileManager, LockCacheManager, RowManager, VisibleRowManager},
- objects::{
- types::{BaseSqlTypes, BaseSqlTypesMapper},
- Attribute, SqlTuple, Table,
- },
- transactions::TransactionManager,
- },
+use feophantlib::engine::{
+ get_row, get_table,
+ io::{row_formats::RowData, FileManager, LockCacheManager, RowManager, VisibleRowManager},
+ transactions::TransactionManager,
};
use futures::stream::StreamExt;
use log::{debug, info};
@@ -16,40 +10,6 @@ use std::sync::Arc;
use tempfile::TempDir;
mod common;
-fn get_row(input: String) -> SqlTuple {
- SqlTuple(vec![
- Some(BaseSqlTypes::Text(input)),
- 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())),
- ])
-}
-fn get_table() -> Arc {
- Arc::new(Table::new(
- uuid::Uuid::new_v4(),
- "test_table".to_string(),
- vec![
- Attribute::new(
- "header".to_string(),
- BaseSqlTypesMapper::Text,
- Nullable::NotNull,
- None,
- ),
- Attribute::new(
- "id".to_string(),
- BaseSqlTypesMapper::Uuid,
- Nullable::Null,
- None,
- ),
- Attribute::new(
- "header3".to_string(),
- BaseSqlTypesMapper::Text,
- Nullable::NotNull,
- None,
- ),
- ],
- ))
-}
-
#[tokio::test]
async fn test_row_manager_visibility() -> Result<(), Box> {
let tmp = TempDir::new()?;