diff --git a/CHANGELOG.md b/CHANGELOG.md index e0f9e9dc..35ea6ac1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,9 @@ All changes in this project will be noted in this file. - `ALTER MODEL ...` - `DROP SPACE ...` - `DROP MODEL ...` + - `USE `: + - works just like SQL + - **does not work with DDL queries**: the reason it works in this way is to prevent accidental deletes - DML: - **All actions removed**: All the prior `SET`, `GET` and other actions have been removed in favor of the new query language - The following queries were added: diff --git a/Cargo.lock b/Cargo.lock index 1dfd1815..58bda0d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1233,10 +1233,11 @@ dependencies = [ [[package]] name = "skytable" version = "0.8.0" -source = "git+https://github.com/skytable/client-rust.git?branch=octave#691e15578c1a09a5d2b6b85c8752e6eee31fbda2" +source = "git+https://github.com/skytable/client-rust.git?branch=octave#62e4f3152d56127e406b9d5eeea60696acd77031" dependencies = [ "async-trait", "bb8", + "itoa", "native-tls", "r2d2", "rand", diff --git a/cli/src/query.rs b/cli/src/query.rs index db272493..f4204131 100644 --- a/cli/src/query.rs +++ b/cli/src/query.rs @@ -57,13 +57,13 @@ enum Item { } impl SQParam for Item { - fn push(self, buf: &mut Vec) { + fn append_param(self, buf: &mut Vec) { match self { - Item::UInt(u) => u.push(buf), - Item::SInt(s) => s.push(buf), - Item::Float(f) => f.push(buf), - Item::String(s) => s.push(buf), - Item::Bin(b) => SQParam::push(&*b, buf), + Item::UInt(u) => u.append_param(buf), + Item::SInt(s) => s.append_param(buf), + Item::Float(f) => f.append_param(buf), + Item::String(s) => s.append_param(buf), + Item::Bin(b) => SQParam::append_param(&*b, buf), } } } @@ -100,7 +100,7 @@ impl Parameterizer { } sym => { self.i += 1; - self.query.push(sym); + Vec::push(&mut self.query, sym); Ok(()) } }? diff --git a/server/src/engine/core/dml/sel.rs b/server/src/engine/core/dml/sel.rs index bb586677..7199f404 100644 --- a/server/src/engine/core/dml/sel.rs +++ b/server/src/engine/core/dml/sel.rs @@ -34,7 +34,7 @@ use crate::engine::{ fractal::GlobalInstanceLike, idx::{STIndex, STIndexSeq}, mem::IntegerRepr, - net::protocol::Response, + net::protocol::{Response, ResponseType}, ql::dml::sel::SelectStatement, sync, }; @@ -49,7 +49,11 @@ pub fn select_resp( encode_cell(&mut data, item); i += 1; })?; - Ok(Response::Row { size: i, data }) + Ok(Response::Serialized { + ty: ResponseType::Row, + size: i, + data, + }) } fn encode_cell(resp: &mut Vec, item: &Datacell) { diff --git a/server/src/engine/core/exec.rs b/server/src/engine/core/exec.rs index 1d10113b..0ad1c5ca 100644 --- a/server/src/engine/core/exec.rs +++ b/server/src/engine/core/exec.rs @@ -27,29 +27,34 @@ use crate::engine::{ core::{dml, model::Model, space::Space}, error::{QueryError, QueryResult}, - fractal::Global, - mem::RawSlice, + fractal::{Global, GlobalInstanceLike}, net::protocol::{ClientLocalState, Response, SQuery}, ql::{ ast::{traits::ASTNode, InplaceData, State}, - lex::{Keyword, KeywordStmt, Token}, + ddl::Use, + lex::KeywordStmt, }, }; +/* + --- + trigger warning: disgusting hacks below owing to token lifetimes +*/ + pub async fn dispatch_to_executor<'a>( global: &Global, - cstate: &ClientLocalState, + cstate: &mut ClientLocalState, query: SQuery<'a>, ) -> QueryResult { let tokens = crate::engine::ql::lex::SecureLexer::new_with_segments(query.query(), query.params()) .lex()?; let mut state = State::new_inplace(&tokens); - let stmt = match state.read() { - Token::Keyword(Keyword::Statement(stmt)) if state.remaining() >= 3 => *stmt, - _ => return Err(QueryError::QLExpectedStatement), - }; - state.cursor_ahead(); + state.set_space_maybe(unsafe { + // UNSAFE(@ohsayan): exclusively used within this scope + core::mem::transmute(cstate.get_cs()) + }); + let stmt = state.try_statement()?; if stmt.is_blocking() { run_blocking_stmt(global, cstate, state, stmt).await } else { @@ -57,25 +62,6 @@ pub async fn dispatch_to_executor<'a>( } } -/* - blocking exec - --- - trigger warning: disgusting hacks below (why can't async play nice with lifetimes :|) -*/ - -#[inline(always)] -fn call + core::fmt::Debug, T>( - g: Global, - tokens: RawSlice>, - f: impl FnOnce(&Global, A) -> QueryResult, -) -> QueryResult { - let mut state = State::new_inplace(unsafe { - // UNSAFE(@ohsayan): nothing to drop. all cool - core::mem::transmute(tokens) - }); - _call(&g, &mut state, f) -} - #[inline(always)] fn _call + core::fmt::Debug, T>( g: &Global, @@ -88,7 +74,7 @@ fn _call + core::fmt::Debug, T>( async fn run_blocking_stmt( global: &Global, - cstate: &ClientLocalState, + cstate: &mut ClientLocalState, mut state: State<'_, InplaceData>, stmt: KeywordStmt, ) -> Result { @@ -96,6 +82,12 @@ async fn run_blocking_stmt( // all the actions here need root permission return Err(QueryError::SysPermissionDenied); } + state.ensure_minimum_for_blocking_stmt()?; + /* + IMPORTANT: DDL queries will NOT pick up the currently set space. instead EVERY DDL query must manually fully specify the entity that + they want to manipulate. this prevents a whole set of exciting errors like dropping a model with the same model name from another space + */ + state.unset_space(); let (a, b) = (&state.current()[0], &state.current()[1]); let sysctl = stmt == KeywordStmt::Sysctl; let create = stmt == KeywordStmt::Create; @@ -110,26 +102,28 @@ async fn run_blocking_stmt( let d_m = (drop & Token![model].eq(a) & last_id) as u8 * 7; let fc = sysctl as u8 | c_s | c_m | a_s | a_m | d_s | d_m; state.cursor_ahead_if(!sysctl); - static BLK_EXEC: [fn(Global, &ClientLocalState, RawSlice>) -> QueryResult<()>; - 8] = [ + static BLK_EXEC: [fn( + Global, + &ClientLocalState, + &mut State<'static, InplaceData>, + ) -> QueryResult<()>; 8] = [ |_, _, _| Err(QueryError::QLUnknownStatement), // unknown blocking_exec_sysctl, // sysctl - |g, _, t| call(g, t, Space::transactional_exec_create), - |g, _, t| call(g, t, Model::transactional_exec_create), - |g, _, t| call(g, t, Space::transactional_exec_alter), - |g, _, t| call(g, t, Model::transactional_exec_alter), - |g, _, t| call(g, t, Space::transactional_exec_drop), - |g, _, t| call(g, t, Model::transactional_exec_drop), + |g, _, t| _call(&g, t, Space::transactional_exec_create), + |g, _, t| _call(&g, t, Model::transactional_exec_create), + |g, _, t| _call(&g, t, Space::transactional_exec_alter), + |g, _, t| _call(&g, t, Model::transactional_exec_alter), + |g, _, t| _call(&g, t, Space::transactional_exec_drop), + |g, _, t| _call(&g, t, Model::transactional_exec_drop), ]; let r = unsafe { // UNSAFE(@ohsayan): the only await is within this block let c_glob = global.clone(); - let ptr = state.current().as_ptr() as usize; - let len = state.current().len(); - let cstate: &'static ClientLocalState = core::mem::transmute(cstate); + let static_cstate: &'static ClientLocalState = core::mem::transmute(cstate); + let static_state: &'static mut State<'static, InplaceData> = + core::mem::transmute(&mut state); tokio::task::spawn_blocking(move || { - let tokens = RawSlice::new(ptr as *const Token, len); - BLK_EXEC[fc as usize](c_glob, cstate, tokens)?; + BLK_EXEC[fc as usize](c_glob, static_cstate, static_state)?; Ok(Response::Empty) }) .await @@ -140,10 +134,9 @@ async fn run_blocking_stmt( fn blocking_exec_sysctl( g: Global, cstate: &ClientLocalState, - tokens: RawSlice>, + state: &mut State<'static, InplaceData>, ) -> QueryResult<()> { - let mut state = State::new_inplace(&tokens); - let r = ASTNode::parse_from_state_hardened(&mut state)?; + let r = ASTNode::parse_from_state_hardened(state)?; super::dcl::exec(g, cstate, r) } @@ -151,28 +144,54 @@ fn blocking_exec_sysctl( nb exec */ +fn cstate_use( + global: &Global, + cstate: &mut ClientLocalState, + state: &mut State<'static, InplaceData>, +) -> QueryResult { + let use_c = Use::parse_from_state_hardened(state)?; + match use_c { + Use::Null => cstate.unset_cs(), + Use::Space(new_space) => { + /* + NB: just like SQL, we don't really care about what this is set to as it's basically a shorthand. + so we do a simple vanity check + */ + if !global.namespace().contains_space(new_space.as_str()) { + return Err(QueryError::QExecObjectNotFound); + } + cstate.set_cs(new_space.boxed_str()); + } + } + Ok(Response::Empty) +} + fn run_nb( global: &Global, - _cstate: &ClientLocalState, + cstate: &mut ClientLocalState, state: State<'_, InplaceData>, stmt: KeywordStmt, ) -> QueryResult { let stmt = stmt.value_u8() - KeywordStmt::Use.value_u8(); - static F: [fn(&Global, &mut State<'static, InplaceData>) -> QueryResult; 8] = [ - |_, _| Err(QueryError::QLUnknownStatement), // use - |_, _| Err(QueryError::QLUnknownStatement), // inspect - |_, _| Err(QueryError::QLUnknownStatement), // describe - |g, s| _call(g, s, dml::insert_resp), - |g, s| _call(g, s, dml::select_resp), - |g, s| _call(g, s, dml::update_resp), - |g, s| _call(g, s, dml::delete_resp), - |_, _| Err(QueryError::QLUnknownStatement), // exists + static F: [fn( + &Global, + &mut ClientLocalState, + &mut State<'static, InplaceData>, + ) -> QueryResult; 8] = [ + cstate_use, // use + |_, _, _| Err(QueryError::QLUnknownStatement), // inspect + |_, _, _| Err(QueryError::QLUnknownStatement), // describe + |g, _, s| _call(g, s, dml::insert_resp), + |g, _, s| _call(g, s, dml::select_resp), + |g, _, s| _call(g, s, dml::update_resp), + |g, _, s| _call(g, s, dml::delete_resp), + |_, _, _| Err(QueryError::QLUnknownStatement), // exists ]; { let mut state = unsafe { // UNSAFE(@ohsayan): this is a lifetime issue with the token handle core::mem::transmute(state) }; - F[stmt as usize](global, &mut state) + F[stmt as usize](global, cstate, &mut state) } } diff --git a/server/src/engine/core/mod.rs b/server/src/engine/core/mod.rs index 69bfd829..8e416efc 100644 --- a/server/src/engine/core/mod.rs +++ b/server/src/engine/core/mod.rs @@ -41,7 +41,7 @@ pub use self::util::{EntityID, EntityIDRef}; // imports use { self::{dml::QueryExecMeta, model::Model}, - super::{fractal::GlobalInstanceLike, ql::ast::Entity}, + super::fractal::GlobalInstanceLike, crate::engine::{ core::space::Space, error::{QueryError, QueryResult}, @@ -87,26 +87,28 @@ impl GlobalNS { let mut space = space.write(); f(&mut space) } - pub fn with_model_space_mut_for_ddl<'a, T, F>(&self, entity: Entity<'a>, f: F) -> QueryResult + pub fn with_model_space_mut_for_ddl<'a, T, F>( + &self, + entity: EntityIDRef<'a>, + f: F, + ) -> QueryResult where F: FnOnce(&Space, &mut Model) -> QueryResult, { - let (space, model_name) = entity.into_full_result()?; let mut mdl_idx = self.idx_mdl.write(); - let Some(model) = mdl_idx.get_mut(&EntityIDRef::new(&space, &model_name)) else { + let Some(model) = mdl_idx.get_mut(&entity) else { return Err(QueryError::QExecObjectNotFound); }; let space_read = self.idx.read(); - let space = space_read.get(space.as_str()).unwrap().read(); + let space = space_read.get(entity.space()).unwrap().read(); f(&space, model) } - pub fn with_model<'a, T, F>(&self, entity: Entity<'a>, f: F) -> QueryResult + pub fn with_model<'a, T, F>(&self, entity: EntityIDRef<'a>, f: F) -> QueryResult where F: FnOnce(&Model) -> QueryResult, { - let (space, model_name) = entity.into_full_result()?; let mdl_idx = self.idx_mdl.read(); - let Some(model) = mdl_idx.get(&EntityIDRef::new(&space, &model_name)) else { + let Some(model) = mdl_idx.get(&entity) else { return Err(QueryError::QExecObjectNotFound); }; f(model) @@ -124,22 +126,24 @@ impl GlobalNS { .write() .insert(space_name.into(), Space::new_auto_all().into()); } + pub fn contains_space(&self, name: &str) -> bool { + self.idx.read().contains_key(name) + } } pub(self) fn with_model_for_data_update<'a, F>( global: &impl GlobalInstanceLike, - entity: Entity<'a>, + entity: EntityIDRef<'a>, f: F, ) -> QueryResult<()> where F: FnOnce(&Model) -> QueryResult, { - let (space, model_name) = entity.into_full_result()?; let mdl_idx = global.namespace().idx_mdl.read(); - let Some(model) = mdl_idx.get(&EntityIDRef::new(&space, &model_name)) else { + let Some(model) = mdl_idx.get(&entity) else { return Err(QueryError::QExecObjectNotFound); }; let r = f(model)?; - model::DeltaState::guard_delta_overflow(global, &space, &model_name, model, r); + model::DeltaState::guard_delta_overflow(global, entity.space(), entity.entity(), model, r); Ok(()) } diff --git a/server/src/engine/core/model/alt.rs b/server/src/engine/core/model/alt.rs index d9b7a51d..3a8dbabc 100644 --- a/server/src/engine/core/model/alt.rs +++ b/server/src/engine/core/model/alt.rs @@ -28,6 +28,7 @@ use { super::{Field, Layer, Model}, crate::{ engine::{ + core::EntityIDRef, data::{ tag::{DataTag, TagClass}, DictEntryGeneric, @@ -36,7 +37,6 @@ use { fractal::GlobalInstanceLike, idx::{IndexST, IndexSTSeqCns, STIndex, STIndexSeq}, ql::{ - ast::Entity, ddl::{ alt::{AlterKind, AlterModel}, syn::{ExpandedField, LayerSpec}, @@ -52,7 +52,7 @@ use { #[derive(Debug, PartialEq)] pub(in crate::engine::core) struct AlterPlan<'a> { - pub(in crate::engine::core) model: Entity<'a>, + pub(in crate::engine::core) model: EntityIDRef<'a>, pub(in crate::engine::core) no_lock: bool, pub(in crate::engine::core) action: AlterAction<'a>, } @@ -250,7 +250,7 @@ impl Model { global: &G, alter: AlterModel, ) -> QueryResult<()> { - let (space_name, model_name) = alter.model.into_full_result()?; + let (space_name, model_name) = (alter.model.space(), alter.model.entity()); global .namespace() .with_model_space_mut_for_ddl(alter.model, |space, model| { diff --git a/server/src/engine/core/model/mod.rs b/server/src/engine/core/model/mod.rs index 13f39cb6..6c67b55b 100644 --- a/server/src/engine/core/model/mod.rs +++ b/server/src/engine/core/model/mod.rs @@ -66,6 +66,7 @@ pub struct Model { data: PrimaryIndex, delta: DeltaState, private: ModelPrivate, + decl: String, } #[cfg(test)] @@ -113,6 +114,49 @@ impl Model { pub fn model_mutator<'a>(&'a mut self) -> ModelMutator<'a> { ModelMutator { model: self } } + fn sync_decl(&mut self) { + self.decl = self.redescribe(); + } + pub fn describe(&self) -> &str { + &self.decl + } + fn redescribe(&self) -> String { + let mut ret = format!("{{ "); + let mut it = self.fields().stseq_ord_kv().peekable(); + while let Some((field_name, field_decl)) = it.next() { + // legend: * -> primary, ! -> not null, ? -> null + if self.is_pk(&field_name) { + ret.push('*'); + } else if field_decl.is_nullable() { + ret.push('?'); + } else { + ret.push('!'); + } + ret.push_str(&field_name); + ret.push(':'); + ret.push(' '); + // TODO(@ohsayan): it's all lists right now, so this is okay but fix it later + if field_decl.layers().len() == 1 { + ret.push_str(field_decl.layers()[0].tag().tag_selector().name_str()); + } else { + ret.push_str(&"[".repeat(field_decl.layers().len() - 1)); + ret.push_str( + field_decl.layers()[field_decl.layers().len() - 1] + .tag() + .tag_selector() + .name_str(), + ); + ret.push_str(&"]".repeat(field_decl.layers().len() - 1)) + } + if it.peek().is_some() { + ret.push(','); + ret.push(' '); + } + } + ret.push(' '); + ret.push('}'); + ret + } } impl Model { @@ -123,7 +167,7 @@ impl Model { fields: Fields, private: ModelPrivate, ) -> Self { - Self { + let mut slf = Self { uuid, p_key, p_tag, @@ -131,7 +175,10 @@ impl Model { data: PrimaryIndex::new_empty(), delta: DeltaState::new_resolved(), private, - } + decl: String::new(), + }; + slf.sync_decl(); + slf } pub fn new_restore( uuid: Uuid, @@ -223,11 +270,11 @@ impl Model { global: &G, stmt: CreateModel, ) -> QueryResult<()> { - let (space_name, model_name) = stmt.model_name.into_full_result()?; + let (space_name, model_name) = (stmt.model_name.space(), stmt.model_name.entity()); let model = Self::process_create(stmt)?; global.namespace().ddl_with_space_mut(&space_name, |space| { // TODO(@ohsayan): be extra cautious with post-transactional tasks (memck) - if space.models().contains(model_name.as_str()) { + if space.models().contains(model_name) { return Err(QueryError::QExecDdlObjectAlreadyExists); } // since we've locked this down, no one else can parallely create another model in the same space (or remove) @@ -264,7 +311,7 @@ impl Model { } } // update global state - let _ = space.models_mut().insert(model_name.as_str().into()); + let _ = space.models_mut().insert(model_name.into()); let _ = global .namespace() .idx_models() @@ -277,9 +324,9 @@ impl Model { global: &G, stmt: DropModel, ) -> QueryResult<()> { - let (space_name, model_name) = stmt.entity.into_full_result()?; + let (space_name, model_name) = (stmt.entity.space(), stmt.entity.entity()); global.namespace().ddl_with_space_mut(&space_name, |space| { - if !space.models().contains(model_name.as_str()) { + if !space.models().contains(model_name) { // the model isn't even present return Err(QueryError::QExecObjectNotFound); } @@ -306,15 +353,15 @@ impl Model { global.namespace_txn_driver().lock().try_commit(txn)?; // request cleanup global.purge_model_driver( - space_name.as_str(), + space_name, space.get_uuid(), - model_name.as_str(), + model_name, model.get_uuid(), ); } // update global state let _ = models_idx.remove(&EntityIDRef::new(&space_name, &model_name)); - let _ = space.models_mut().remove(model_name.as_str()); + let _ = space.models_mut().remove(model_name); Ok(()) }) } @@ -406,6 +453,12 @@ impl<'a> ModelMutator<'a> { } } +impl<'a> Drop for ModelMutator<'a> { + fn drop(&mut self) { + self.model.sync_decl(); + } +} + /* Layer */ diff --git a/server/src/engine/core/tests/ddl_model/alt.rs b/server/src/engine/core/tests/ddl_model/alt.rs index fc8b3c0c..d154cabc 100644 --- a/server/src/engine/core/tests/ddl_model/alt.rs +++ b/server/src/engine/core/tests/ddl_model/alt.rs @@ -89,7 +89,7 @@ mod plan { "create model myspace.mymodel(username: string, password: binary)", "alter model myspace.mymodel add myfield { type: string, nullable: true }", |plan| { - assert_eq!(plan.model.into_full().unwrap().1.as_str(), "mymodel"); + assert_eq!(plan.model.entity(), "mymodel"); assert!(plan.no_lock); assert_eq!( plan.action, @@ -106,7 +106,7 @@ mod plan { "create model myspace.mymodel(username: string, password: binary, useless_field: uint8)", "alter model myspace.mymodel remove useless_field", |plan| { - assert_eq!(plan.model.into_full().unwrap().1.as_str(), "mymodel"); + assert_eq!(plan.model.entity(), "mymodel"); assert!(plan.no_lock); assert_eq!( plan.action, @@ -122,7 +122,7 @@ mod plan { "create model myspace.mymodel(username: string, password: binary)", "alter model myspace.mymodel update password { nullable: true }", |plan| { - assert_eq!(plan.model.into_full().unwrap().1.as_str(), "mymodel"); + assert_eq!(plan.model.entity(), "mymodel"); assert!(plan.no_lock); assert_eq!( plan.action, @@ -140,7 +140,7 @@ mod plan { "create model myspace.mymodel(username: string, null password: binary)", "alter model myspace.mymodel update password { nullable: false }", |plan| { - assert_eq!(plan.model.into_full().unwrap().1.as_str(), "mymodel"); + assert_eq!(plan.model.entity(), "mymodel"); assert!(!plan.no_lock); assert_eq!( plan.action, diff --git a/server/src/engine/core/tests/ddl_model/crt.rs b/server/src/engine/core/tests/ddl_model/crt.rs index 909582c2..d519a365 100644 --- a/server/src/engine/core/tests/ddl_model/crt.rs +++ b/server/src/engine/core/tests/ddl_model/crt.rs @@ -37,7 +37,8 @@ mod validation { #[test] fn simple() { - let model = create("create model mymodel(username: string, password: binary)").unwrap(); + let model = + create("create model myspace.mymodel(username: string, password: binary)").unwrap(); assert_eq!(model.p_key(), "username"); assert_eq!(model.p_tag(), FullTag::STR); assert_eq!( @@ -60,7 +61,8 @@ mod validation { #[test] fn idiotic_order() { let model = - create("create model mymodel(password: binary, primary username: string)").unwrap(); + create("create model myspace.mymodel(password: binary, primary username: string)") + .unwrap(); assert_eq!(model.p_key(), "username"); assert_eq!(model.p_tag(), FullTag::STR); assert_eq!( @@ -84,7 +86,7 @@ mod validation { fn duplicate_primary_key() { assert_eq!( create( - "create model mymodel(primary username: string, primary contract_location: binary)" + "create model myspace.mymodel(primary username: string, primary contract_location: binary)" ) .unwrap_err(), QueryError::QExecDdlModelBadDefinition @@ -94,7 +96,8 @@ mod validation { #[test] fn duplicate_fields() { assert_eq!( - create("create model mymodel(primary username: string, username: binary)").unwrap_err(), + create("create model myspace.mymodel(primary username: string, username: binary)") + .unwrap_err(), QueryError::QExecDdlModelBadDefinition ); } @@ -102,7 +105,7 @@ mod validation { #[test] fn illegal_props() { assert_eq!( - create("create model mymodel(primary username: string, password: binary) with { lol_prop: false }").unwrap_err(), + create("create model myspace.mymodel(primary username: string, password: binary) with { lol_prop: false }").unwrap_err(), QueryError::QExecDdlModelBadDefinition ); } @@ -111,13 +114,13 @@ mod validation { fn illegal_pk() { assert_eq!( create( - "create model mymodel(primary username_bytes: list { type: uint8 }, password: binary)" + "create model myspace.mymodel(primary username_bytes: list { type: uint8 }, password: binary)" ) .unwrap_err(), QueryError::QExecDdlModelBadDefinition ); assert_eq!( - create("create model mymodel(primary username: float32, password: binary)") + create("create model myspace.mymodel(primary username: float32, password: binary)") .unwrap_err(), QueryError::QExecDdlModelBadDefinition ); diff --git a/server/src/engine/core/tests/ddl_model/mod.rs b/server/src/engine/core/tests/ddl_model/mod.rs index 6d4352f6..b58cdc5e 100644 --- a/server/src/engine/core/tests/ddl_model/mod.rs +++ b/server/src/engine/core/tests/ddl_model/mod.rs @@ -32,11 +32,7 @@ use crate::engine::{ core::{model::Model, EntityIDRef}, error::QueryResult, fractal::GlobalInstanceLike, - ql::{ - ast::{parse_ast_node_full, Entity}, - ddl::crt::CreateModel, - tests::lex_insecure, - }, + ql::{ast::parse_ast_node_full, ddl::crt::CreateModel, tests::lex_insecure}, }; fn create(s: &str) -> QueryResult { @@ -52,13 +48,11 @@ pub fn exec_create( ) -> QueryResult { let tok = lex_insecure(create_stmt.as_bytes()).unwrap(); let create_model = parse_ast_node_full::(&tok[2..]).unwrap(); - let name = match create_model.model_name { - Entity::Single(tbl) | Entity::Full(_, tbl) => tbl.to_string(), - }; + let name = create_model.model_name.entity().to_owned(); if create_new_space { global .namespace() - .create_empty_test_space(&create_model.model_name.into_full().unwrap().0) + .create_empty_test_space(create_model.model_name.space()) } Model::transactional_exec_create(global, create_model).map(|_| name) } diff --git a/server/src/engine/core/tests/dml/mod.rs b/server/src/engine/core/tests/dml/mod.rs index 41dd7854..4418a943 100644 --- a/server/src/engine/core/tests/dml/mod.rs +++ b/server/src/engine/core/tests/dml/mod.rs @@ -30,12 +30,12 @@ mod select; mod update; use crate::engine::{ - core::{dml, index::Row, model::Model, space::Space}, + core::{dml, index::Row, model::Model, space::Space, EntityIDRef}, data::{cell::Datacell, lit::Lit}, error::QueryResult, fractal::GlobalInstanceLike, ql::{ - ast::{parse_ast_node_full, Entity}, + ast::parse_ast_node_full, dml::{del::DeleteStatement, ins::InsertStatement}, tests::lex_insecure, }, @@ -56,7 +56,7 @@ fn _exec_only_create_space_model(global: &impl GlobalInstanceLike, model: &str) fn _exec_only_insert( global: &impl GlobalInstanceLike, insert: &str, - and_then: impl Fn(Entity) -> T, + and_then: impl Fn(EntityIDRef) -> T, ) -> QueryResult { let lex_insert = lex_insecure(insert.as_bytes()).unwrap(); let stmt_insert = parse_ast_node_full::(&lex_insert[1..]).unwrap(); @@ -68,7 +68,7 @@ fn _exec_only_insert( fn _exec_only_read_key_and_then( global: &impl GlobalInstanceLike, - entity: Entity, + entity: EntityIDRef, key_name: &str, and_then: impl Fn(Row) -> T, ) -> QueryResult { diff --git a/server/src/engine/core/util.rs b/server/src/engine/core/util.rs index fb5b7021..02afa907 100644 --- a/server/src/engine/core/util.rs +++ b/server/src/engine/core/util.rs @@ -93,6 +93,7 @@ impl fmt::Debug for EntityID { } } +#[derive(Clone, Copy)] pub struct EntityIDRef<'a> { sp: *const u8, sl: usize, @@ -148,3 +149,9 @@ impl<'a> Borrow> for EntityID { unsafe { core::mem::transmute(self) } } } + +impl From<(&'static str, &'static str)> for EntityIDRef<'static> { + fn from((s, e): (&'static str, &'static str)) -> Self { + Self::new(s, e) + } +} diff --git a/server/src/engine/data/tag.rs b/server/src/engine/data/tag.rs index 68b66d50..62e6f73a 100644 --- a/server/src/engine/data/tag.rs +++ b/server/src/engine/data/tag.rs @@ -24,6 +24,15 @@ * */ +macro_rules! strid { + ($(#[$attr:meta])*$vis:vis enum $enum:ident {$($(#[$var_attr:meta])* $variant:ident $(= $dscr:expr)?),* $(,)?}) => { + $(#[$attr])* $vis enum $enum { $($(#[$var_attr])* $variant $(= $dscr)?),*} + impl $enum { + pub const fn name_str(&self) -> &'static str { match self { $(Self::$variant => stringify!($variant),)* } } + } + } +} + #[repr(u8)] #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, PartialOrd, Ord, sky_macros::EnumMethods)] pub enum TagClass { @@ -36,23 +45,25 @@ pub enum TagClass { List = 6, } -#[repr(u8)] -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, PartialOrd, Ord, sky_macros::EnumMethods)] -pub enum TagSelector { - Bool = 0, - UInt8 = 1, - UInt16 = 2, - UInt32 = 3, - UInt64 = 4, - SInt8 = 5, - SInt16 = 6, - SInt32 = 7, - SInt64 = 8, - Float32 = 9, - Float64 = 10, - Bin = 11, - Str = 12, - List = 13, +strid! { + #[repr(u8)] + #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, PartialOrd, Ord, sky_macros::EnumMethods)] + pub enum TagSelector { + Bool = 0, + UInt8 = 1, + UInt16 = 2, + UInt32 = 3, + UInt64 = 4, + SInt8 = 5, + SInt16 = 6, + SInt32 = 7, + SInt64 = 8, + Float32 = 9, + Float64 = 10, + Binary = 11, + String = 12, + List = 13, + } } impl TagSelector { @@ -175,8 +186,8 @@ impl DataTag for FullTag { const UINT: Self = fulltag!(UnsignedInt, UInt64, UnsignedInt); const SINT: Self = fulltag!(SignedInt, SInt64, SignedInt); const FLOAT: Self = fulltag!(Float, Float64); - const BIN: Self = fulltag!(Bin, Bin, Bin); - const STR: Self = fulltag!(Str, Str, Str); + const BIN: Self = fulltag!(Bin, Binary, Bin); + const STR: Self = fulltag!(Str, String, Str); const LIST: Self = fulltag!(List, List); fn tag_class(&self) -> TagClass { self.class diff --git a/server/src/engine/fractal/mgr.rs b/server/src/engine/fractal/mgr.rs index 3440dbf7..ea9332ab 100644 --- a/server/src/engine/fractal/mgr.rs +++ b/server/src/engine/fractal/mgr.rs @@ -28,9 +28,11 @@ use { super::ModelUniqueID, crate::{ engine::{ - core::model::{delta::DataDelta, Model}, + core::{ + model::{delta::DataDelta, Model}, + EntityIDRef, + }, data::uuid::Uuid, - ql::ast::Entity, storage::v1::LocalFS, }, util::os, @@ -290,7 +292,7 @@ impl FractalMgr { return; }; let res = global._namespace().with_model( - Entity::Full(model_id.space().into(), model_id.model().into()), + EntityIDRef::new(model_id.space().into(), model_id.model().into()), |model| { if model.get_uuid() != model_id.uuid() { // once again, throughput maximization will lead to, in extremely rare cases, this @@ -382,7 +384,7 @@ impl FractalMgr { for (model_id, driver) in mdl_drivers.iter() { let mut observed_len = 0; let res = global._namespace().with_model( - Entity::Full(model_id.space().into(), model_id.model().into()), + EntityIDRef::new(model_id.space().into(), model_id.model().into()), |model| { if model.get_uuid() != model_id.uuid() { // once again, throughput maximization will lead to, in extremely rare cases, this diff --git a/server/src/engine/mem/mod.rs b/server/src/engine/mem/mod.rs index a823287c..46ce25c2 100644 --- a/server/src/engine/mem/mod.rs +++ b/server/src/engine/mem/mod.rs @@ -41,7 +41,7 @@ pub use { astr::AStr, ll::CachePadded, numbuf::IntegerRepr, - rawslice::{RawSlice, RawStr}, + rawslice::RawStr, scanner::BufferedScanner, uarray::UArray, vinline::VInline, diff --git a/server/src/engine/net/protocol/mod.rs b/server/src/engine/net/protocol/mod.rs index da804566..cc2c5eec 100644 --- a/server/src/engine/net/protocol/mod.rs +++ b/server/src/engine/net/protocol/mod.rs @@ -51,16 +51,42 @@ use { tokio::io::{AsyncReadExt, AsyncWriteExt, BufWriter}, }; +#[repr(u8)] +#[derive(sky_macros::EnumMethods, Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[allow(unused)] +pub enum ResponseType { + Null = 0x00, + Bool = 0x01, + UInt8 = 0x02, + UInt16 = 0x03, + UInt32 = 0x04, + UInt64 = 0x05, + SInt8 = 0x06, + SInt16 = 0x07, + SInt32 = 0x08, + SInt64 = 0x09, + Float32 = 0x0A, + Float64 = 0x0B, + Binary = 0x0C, + String = 0x0D, + List = 0x0E, + Dict = 0x0F, + Error = 0x10, + Row = 0x11, + Empty = 0x12, +} + #[derive(Debug, PartialEq)] pub struct ClientLocalState { username: Box, root: bool, hs: handshake::CHandshakeStatic, + cs: Option>, } impl ClientLocalState { pub fn new(username: Box, root: bool, hs: handshake::CHandshakeStatic) -> Self { - Self { username, root, hs } + Self { username, root, hs, cs: None } } pub fn is_root(&self) -> bool { self.root @@ -68,12 +94,25 @@ impl ClientLocalState { pub fn username(&self) -> &str { &self.username } + pub fn set_cs(&mut self, new: Box) { + self.cs = Some(new); + } + pub fn unset_cs(&mut self) { + self.cs = None; + } + pub fn get_cs(&self) -> Option<&str> { + self.cs.as_deref() + } } #[derive(Debug, PartialEq)] pub enum Response { Empty, - Row { size: usize, data: Vec }, + Serialized { + ty: ResponseType, + size: usize, + data: Vec, + }, } pub(super) async fn query_loop( @@ -82,7 +121,7 @@ pub(super) async fn query_loop( global: &Global, ) -> IoResult { // handshake - let client_state = match do_handshake(con, buf, global).await? { + let mut client_state = match do_handshake(con, buf, global).await? { PostHandshake::Okay(hs) => hs, PostHandshake::ConnectionClosedFin => return Ok(QueryLoopResult::Fin), PostHandshake::ConnectionClosedRst => return Ok(QueryLoopResult::Rst), @@ -127,7 +166,8 @@ pub(super) async fn query_loop( QueryTimeExchangeResult::Error => { let [a, b] = (QueryError::NetworkSubsystemCorruptedPacket.value_u8() as u16).to_le_bytes(); - con.write_all(&[0x10, a, b]).await?; + con.write_all(&[ResponseType::Error.value_u8(), a, b]) + .await?; con.flush().await?; buf.clear(); exchg_state = QueryTimeExchangeState::default(); @@ -135,12 +175,12 @@ pub(super) async fn query_loop( } }; // now execute query - match engine::core::exec::dispatch_to_executor(global, &client_state, sq).await { + match engine::core::exec::dispatch_to_executor(global, &mut client_state, sq).await { Ok(Response::Empty) => { - con.write_all(&[0x12]).await?; + con.write_all(&[ResponseType::Empty.value_u8()]).await?; } - Ok(Response::Row { size, data }) => { - con.write_u8(0x11).await?; + Ok(Response::Serialized { ty, size, data }) => { + con.write_u8(ty.value_u8()).await?; let mut irep = IntegerRepr::new(); con.write_all(irep.as_bytes(size as u64)).await?; con.write_u8(b'\n').await?; @@ -148,7 +188,8 @@ pub(super) async fn query_loop( } Err(e) => { let [a, b] = (e.value_u8() as u16).to_le_bytes(); - con.write_all(&[0x10, a, b]).await?; + con.write_all(&[ResponseType::Error.value_u8(), a, b]) + .await?; } } con.flush().await?; diff --git a/server/src/engine/ql/ast/mod.rs b/server/src/engine/ql/ast/mod.rs index b4b61306..c2c29c99 100644 --- a/server/src/engine/ql/ast/mod.rs +++ b/server/src/engine/ql/ast/mod.rs @@ -27,26 +27,25 @@ pub mod traits; #[cfg(test)] -pub use traits::{parse_ast_node_full, parse_ast_node_multiple_full}; +pub use traits::{ + parse_ast_node_full, parse_ast_node_full_with_space, parse_ast_node_multiple_full, +}; + use { super::{ ddl, dml, - lex::{Ident, Token}, + lex::{Ident, Keyword, KeywordStmt, Token}, }, crate::{ engine::{ + core::EntityIDRef, data::{cell::Datacell, lit::Lit}, error::{QueryError, QueryResult}, }, - util::{compiler, MaybeInit}, + util::MaybeInit, }, }; -#[inline(always)] -pub fn minidx(src: &[T], index: usize) -> usize { - (src.len() - 1).min(index) -} - #[derive(Debug, PartialEq)] /// Query parse state pub struct State<'a, Qd> { @@ -54,6 +53,7 @@ pub struct State<'a, Qd> { d: Qd, i: usize, f: bool, + cs: Option<&'static str>, } impl<'a> State<'a, InplaceData> { @@ -62,6 +62,79 @@ impl<'a> State<'a, InplaceData> { } } +impl<'a, Qd: QueryData<'a>> State<'a, Qd> { + fn _entity_signature_match_self_full(a: &Token<'a>, b: &Token<'a>, c: &Token<'a>) -> bool { + a.is_ident() & Token![.].eq(b) & c.is_ident() + } + fn _entity_signature_match_cs(&self, a: &Token<'a>) -> bool { + a.is_ident() & self.cs.is_some() + } + unsafe fn _entity_new_from_tokens(&mut self) -> EntityIDRef<'a> { + let space = self.fw_read().uck_read_ident(); + self.cursor_ahead(); + let entity = self.fw_read().uck_read_ident(); + EntityIDRef::new(space.as_str(), entity.as_str()) + } + unsafe fn _entity_new_from_cs(&mut self) -> EntityIDRef<'a> { + let entity = self.fw_read().uck_read_ident(); + EntityIDRef::new(self.cs.unwrap_unchecked(), entity.as_str()) + } + pub fn set_space_maybe(&mut self, maybe: Option<&'static str>) { + self.cs = maybe; + } + pub fn unset_space(&mut self) { + self.set_space_maybe(None) + } + #[cfg(test)] + pub fn set_space(&mut self, s: &'static str) { + self.set_space_maybe(Some(s)); + } + pub fn try_entity_buffered_into_state_uninit(&mut self) -> MaybeInit> { + let mut ret = MaybeInit::uninit(); + let self_has_full = Self::_entity_signature_match_self_full( + &self.t[self.cursor()], + &self.t[self.cursor() + 1], + &self.t[self.cursor() + 2], + ); + let self_has_full_cs = self._entity_signature_match_cs(&self.t[self.cursor()]); + unsafe { + if self_has_full { + ret = MaybeInit::new(self._entity_new_from_tokens()); + } else if self_has_full_cs { + ret = MaybeInit::new(self._entity_new_from_cs()); + } + } + self.poison_if_not(self_has_full | self_has_full_cs); + ret + } + pub fn try_entity_ref(&mut self) -> Option> { + let self_has_full = Self::_entity_signature_match_self_full( + &self.t[self.round_cursor()], + &self.t[self.round_cursor_up(1)], + &self.t[self.round_cursor_up(2)], + ); + let self_has_pre_full = self._entity_signature_match_cs(&self.t[self.round_cursor()]); + if self_has_full { + unsafe { + // UNSAFE(@ohsayan): +branch condition + Some(self._entity_new_from_tokens()) + } + } else { + if self_has_pre_full { + unsafe { + // UNSAFE(@ohsayan): +branch condition + Some(self._entity_new_from_cs()) + } + } else { + None + } + } + } + pub fn try_entity_ref_result(&mut self) -> QueryResult> { + self.try_entity_ref().ok_or(QueryError::QLExpectedEntity) + } +} + impl<'a, Qd: QueryData<'a>> State<'a, Qd> { #[inline(always)] /// Create a new [`State`] instance using the given tokens and data @@ -71,6 +144,7 @@ impl<'a, Qd: QueryData<'a>> State<'a, Qd> { f: true, t, d, + cs: None, } } #[inline(always)] @@ -148,7 +222,7 @@ impl<'a, Qd: QueryData<'a>> State<'a, Qd> { #[inline(always)] /// Check if the current cursor can read a lit (with context from the data source); rounded pub fn can_read_lit_rounded(&self) -> bool { - let mx = minidx(self.t, self.i); + let mx = self.round_cursor(); Qd::can_read_lit_from(&self.d, &self.t[mx]) && mx == self.i } #[inline(always)] @@ -176,7 +250,7 @@ impl<'a, Qd: QueryData<'a>> State<'a, Qd> { #[inline(always)] /// Check if the cursor equals the given token; rounded pub fn cursor_rounded_eq(&self, tok: Token<'a>) -> bool { - let mx = minidx(self.t, self.i); + let mx = self.round_cursor(); self.t[mx] == tok && mx == self.i } #[inline(always)] @@ -196,33 +270,17 @@ impl<'a, Qd: QueryData<'a>> State<'a, Qd> { } #[inline(always)] pub(crate) fn cursor_has_ident_rounded(&self) -> bool { - self.t[minidx(self.t, self.i)].is_ident() && self.not_exhausted() + self.t[self.round_cursor()].is_ident() && self.not_exhausted() } #[inline(always)] /// Check if the current token stream matches the signature of an arity(0) fn; rounded /// /// NOTE: Consider using a direct comparison without rounding pub(crate) fn cursor_signature_match_fn_arity0_rounded(&self) -> bool { - let rem = self.has_remaining(3); - let idx_a = self.i * rem as usize; - let idx_b = (self.i + 1) * rem as usize; - let idx_c = (self.i + 2) * rem as usize; - (self.t[idx_a].is_ident()) - & (self.t[idx_b] == Token![() open]) - & (self.t[idx_c] == Token![() close]) - & rem - } - #[inline(always)] - /// Check if the current token stream matches the signature of a full entity; rounded - /// - /// NOTE: Consider using a direct comparison without rounding; rounding is always slower - pub(crate) fn cursor_signature_match_entity_full_rounded(&self) -> bool { - let rem = self.has_remaining(3); - let rem_u = rem as usize; - let idx_a = self.i * rem_u; - let idx_b = (self.i + 1) * rem_u; - let idx_c = (self.i + 2) * rem_u; - (self.t[idx_a].is_ident()) & (self.t[idx_b] == Token![.]) & (self.t[idx_c].is_ident()) & rem + (self.t[self.round_cursor()].is_ident()) + & (self.t[self.round_cursor_up(1)] == Token![() open]) + & (self.t[self.round_cursor_up(2)] == Token![() close]) + & self.has_remaining(3) } #[inline(always)] /// Reads a lit using the given token and the internal data source and return a data type @@ -240,7 +298,6 @@ impl<'a, Qd: QueryData<'a>> State<'a, Qd> { self.not_exhausted() && self.okay() } #[inline(always)] - #[cfg(test)] /// Returns the position of the cursor pub(crate) fn cursor(&self) -> usize { self.i @@ -250,6 +307,27 @@ impl<'a, Qd: QueryData<'a>> State<'a, Qd> { pub(crate) fn cursor_is_ident(&self) -> bool { self.read().is_ident() } + #[inline(always)] + fn round_cursor_up(&self, up: usize) -> usize { + core::cmp::min(self.t.len() - 1, self.i + up) + } + #[inline(always)] + fn round_cursor(&self) -> usize { + self.round_cursor_up(0) + } + pub fn try_statement(&mut self) -> QueryResult { + match self.fw_read() { + Token::Keyword(Keyword::Statement(stmt)) => Ok(*stmt), + _ => Err(QueryError::QLExpectedStatement), + } + } + pub fn ensure_minimum_for_blocking_stmt(&self) -> QueryResult<()> { + if self.remaining() < 2 { + return Err(QueryError::QLExpectedStatement); + } else { + Ok(()) + } + } } pub trait QueryData<'a> { @@ -297,174 +375,11 @@ impl<'a> QueryData<'a> for InplaceData { } } -/* - AST -*/ - -#[derive(Debug, PartialEq, Clone, Copy)] -/// An [`Entity`] represents the location for a specific structure, such as a model -pub enum Entity<'a> { - /// A single entity is used when switching to a model wrt the currently set space (commonly used - /// when running DML queries) - /// - /// syntax: - /// ```sql - /// model - /// ``` - Single(Ident<'a>), - /// A full entity is a complete definition to a model wrt to the given space (commonly used with - /// DML queries) - /// - /// syntax: - /// ```sql - /// space.model - /// ``` - Full(Ident<'a>, Ident<'a>), -} - -impl<'a> Entity<'a> { - pub fn into_full_result(self) -> QueryResult<(Ident<'a>, Ident<'a>)> { - match self { - Self::Full(a, b) => Ok((a, b)), - _ => Err(QueryError::QLExpectedEntity), - } - } -} - -impl<'a> From<(&'a str, &'a str)> for Entity<'a> { - fn from((s, e): (&'a str, &'a str)) -> Self { - Self::Full(s.into(), e.into()) - } -} - -impl<'a> Entity<'a> { - #[cfg(test)] - pub fn into_full(self) -> Option<(Ident<'a>, Ident<'a>)> { - if let Self::Full(a, b) = self { - Some((a, b)) - } else { - None - } - } - #[inline(always)] - /// Parse a full entity from the given slice - /// - /// ## Safety - /// - /// Caller guarantees that the token stream matches the exact stream of tokens - /// expected for a full entity - pub(super) unsafe fn parse_uck_tokens_full(sl: &'a [Token]) -> Self { - Entity::Full(sl[0].uck_read_ident(), sl[2].uck_read_ident()) - } - #[inline(always)] - /// Parse a single entity from the given slice - /// - /// ## Safety - /// - /// Caller guarantees that the token stream matches the exact stream of tokens - /// expected for a single entity - pub(super) unsafe fn parse_uck_tokens_single(sl: &'a [Token]) -> Self { - Entity::Single(sl[0].uck_read_ident()) - } - #[inline(always)] - #[cfg(test)] - /// Returns true if the given token stream matches the signature of single entity syntax - /// - /// ⚠ WARNING: This will pass for full and single - pub(super) fn signature_matches_single_len_checked(tok: &[Token]) -> bool { - !tok.is_empty() && tok[0].is_ident() - } - #[inline(always)] - #[cfg(test)] - /// Returns true if the given token stream matches the signature of full entity syntax - pub(super) fn signature_matches_full_len_checked(tok: &[Token]) -> bool { - tok.len() > 2 && tok[0].is_ident() && tok[1] == Token![.] && tok[2].is_ident() - } - #[inline(always)] - #[cfg(test)] - /// Attempt to parse an entity using the given token stream. It also accepts a counter - /// argument to forward the cursor - pub fn parse_from_tokens_len_checked(tok: &'a [Token], c: &mut usize) -> QueryResult { - let is_current = Self::signature_matches_single_len_checked(tok); - let is_full = Self::signature_matches_full_len_checked(tok); - let r = match () { - _ if is_full => unsafe { - // UNSAFE(@ohsayan): just verified signature - *c += 3; - Self::parse_uck_tokens_full(tok) - }, - _ if is_current => unsafe { - // UNSAFE(@ohsayan): just verified signature - *c += 1; - Self::parse_uck_tokens_single(tok) - }, - _ => return Err(QueryError::QLExpectedEntity), - }; - Ok(r) - } - #[inline(always)] - pub fn parse_from_state_rounded_result>( - state: &mut State<'a, Qd>, - ) -> QueryResult { - let mut e = MaybeInit::uninit(); - Self::parse_from_state_rounded(state, &mut e); - if compiler::likely(state.okay()) { - unsafe { - // UNSAFE(@ohsayan): just checked if okay - Ok(e.assume_init()) - } - } else { - Err(QueryError::QLExpectedEntity) - } - } - #[inline(always)] - pub fn parse_from_state_rounded>( - state: &mut State<'a, Qd>, - d: &mut MaybeInit>, - ) { - let tok = state.current(); - let is_full = state.cursor_signature_match_entity_full_rounded(); - let is_single = state.cursor_has_ident_rounded(); - unsafe { - // UNSAFE(@ohsayan): verified signatures - if is_full { - state.cursor_ahead_by(3); - *d = MaybeInit::new(Entity::parse_uck_tokens_full(tok)); - } else if is_single { - state.cursor_ahead(); - *d = MaybeInit::new(Entity::parse_uck_tokens_single(tok)); - } - } - state.poison_if_not(is_full | is_single); - } - pub fn parse_from_state_len_unchecked>( - state: &mut State<'a, Qd>, - d: &mut MaybeInit>, - ) { - let tok = state.current(); - let is_full = tok[0].is_ident() && tok[1] == Token![.] && tok[2].is_ident(); - let is_single = tok[0].is_ident(); - unsafe { - // UNSAFE(@ohsayan): verified signatures - if is_full { - state.cursor_ahead_by(3); - *d = MaybeInit::new(Entity::parse_uck_tokens_full(tok)); - } else if is_single { - state.cursor_ahead(); - *d = MaybeInit::new(Entity::parse_uck_tokens_single(tok)); - } - } - state.poison_if_not(is_full | is_single); - } -} - #[derive(Debug, PartialEq)] #[allow(dead_code)] // TODO(@ohsayan): get rid of this /// A [`Statement`] is a fully BlueQL statement that can be executed by the query engine // TODO(@ohsayan): Determine whether we actually need this pub enum Statement<'a> { - /// DDL query to switch between spaces and models - Use(Entity<'a>), /// DDL query to create a model CreateModel(ddl::crt::CreateModel<'a>), /// DDL query to create a space @@ -487,8 +402,6 @@ pub enum Statement<'a> { DropSpace(ddl::drop::DropSpace<'a>), /// DDL query to inspect a space (returns a list of models in the space) InspectSpace(Ident<'a>), - /// DDL query to inspect a model (returns the model definition) - InspectModel(Entity<'a>), /// DDL query to inspect all spaces (returns a list of spaces in the database) InspectSpaces, /// DML insert @@ -505,14 +418,13 @@ pub enum Statement<'a> { #[cfg(test)] #[allow(dead_code)] // TODO(@ohsayan): get rid of this pub fn compile<'a, Qd: QueryData<'a>>(tok: &'a [Token<'a>], d: Qd) -> QueryResult> { - use self::traits::ASTNode; + use {self::traits::ASTNode, crate::util::compiler}; if compiler::unlikely(tok.len() < 2) { return Err(QueryError::QLUnexpectedEndOfStatement); } let mut state = State::new(tok, d); match state.fw_read() { // DDL - Token![use] => Entity::parse_from_state_rounded_result(&mut state).map(Statement::Use), Token![create] => match state.fw_read() { Token![model] => ASTNode::test_parse_from_state(&mut state).map(Statement::CreateModel), Token![space] => ASTNode::test_parse_from_state(&mut state).map(Statement::CreateSpace), @@ -524,9 +436,6 @@ pub fn compile<'a, Qd: QueryData<'a>>(tok: &'a [Token<'a>], d: Qd) -> QueryResul _ => compiler::cold_rerr(QueryError::QLUnknownStatement), }, Token![drop] if state.remaining() >= 2 => ddl::drop::parse_drop(&mut state), - Token::Ident(id) if id.eq_ignore_ascii_case("inspect") => { - ddl::ins::parse_inspect(&mut state) - } // DML Token![insert] => ASTNode::test_parse_from_state(&mut state).map(Statement::Insert), Token![select] => ASTNode::test_parse_from_state(&mut state).map(Statement::Select), diff --git a/server/src/engine/ql/ast/traits.rs b/server/src/engine/ql/ast/traits.rs index 925a4da5..5ccb37e8 100644 --- a/server/src/engine/ql/ast/traits.rs +++ b/server/src/engine/ql/ast/traits.rs @@ -108,6 +108,17 @@ pub trait ASTNode<'a>: Sized { Ok(r) } #[cfg(test)] + fn from_insecure_tokens_full_with_space( + tok: &'a [Token<'a>], + space_name: &'static str, + ) -> QueryResult { + let mut state = State::new(tok, InplaceData::new()); + state.set_space(space_name); + let r = ::test_parse_from_state(&mut state)?; + assert!(state.exhausted()); + Ok(r) + } + #[cfg(test)] /// Parse multiple nodes of this AST node type, utilizing the full token stream. /// Intended for the test suite. fn multiple_from_insecure_tokens_full(tok: &'a [Token<'a>]) -> QueryResult> { @@ -126,6 +137,13 @@ pub fn parse_ast_node_full<'a, N: ASTNode<'a>>(tok: &'a [Token<'a>]) -> QueryRes N::from_insecure_tokens_full(tok) } #[cfg(test)] +pub fn parse_ast_node_full_with_space<'a, N: ASTNode<'a>>( + tok: &'a [Token<'a>], + space_name: &'static str, +) -> QueryResult { + N::from_insecure_tokens_full_with_space(tok, space_name) +} +#[cfg(test)] pub fn parse_ast_node_multiple_full<'a, N: ASTNode<'a>>( tok: &'a [Token<'a>], ) -> QueryResult> { diff --git a/server/src/engine/ql/benches.rs b/server/src/engine/ql/benches.rs deleted file mode 100644 index 5bd97a3e..00000000 --- a/server/src/engine/ql/benches.rs +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Created on Wed Nov 16 2022 - * - * This file is a part of Skytable - * Skytable (formerly known as TerrabaseDB or Skybase) is a free and open-source - * NoSQL database written by Sayan Nandan ("the Author") with the - * vision to provide flexibility in data modelling without compromising - * on performance, queryability or scalability. - * - * Copyright (c) 2022, Sayan Nandan - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * -*/ - -/* - All benches should be aggregate costs of full execution. This means that when for example - you're writing a benchmark for something like parsing a `select` statement, you should calculate - the total time of execution including lexing, parsing and allocating. Hopefully in the future we can - implement a testing framework that enables us to find the total tiered cost of execution for each stage - and hence enable us to iterate on the weakness and fix it. Maybe even visualize it? That'd be amazing - and maybe would be something I'll work on around 0.9. - - -- Sayan (@ohsayan) -*/ - -extern crate test; - -use { - crate::engine::ql::{lex::Ident, tests::lex_insecure}, - test::Bencher, -}; - -mod lexer { - use { - super::*, - crate::engine::{data::lit::Lit, ql::lex::Token}, - }; - #[bench] - fn lex_number(b: &mut Bencher) { - let src = b"1234567890"; - let expected = vec![Token::Lit(1234567890_u64.into())]; - b.iter(|| assert_eq!(lex_insecure(src).unwrap(), expected)); - } - #[bench] - fn lex_bool(b: &mut Bencher) { - let s = b"true"; - let e = vec![Token::Lit(true.into())]; - b.iter(|| assert_eq!(lex_insecure(s).unwrap(), e)); - } - #[bench] - fn lex_string_noescapes(b: &mut Bencher) { - let s = br#"'hello, world!'"#; - let e = vec![Token::Lit("hello, world!".into())]; - b.iter(|| assert_eq!(lex_insecure(s).unwrap(), e)); - } - #[bench] - fn lex_string_with_escapes(b: &mut Bencher) { - let s = br#"'hello, world! this is within a \'quote\''"#; - let e = vec![Token::Lit("hello, world! this is within a 'quote'".into())]; - b.iter(|| assert_eq!(lex_insecure(s).unwrap(), e)); - } - #[bench] - fn lex_raw_literal(b: &mut Bencher) { - let src = b"\r44\ne69b10ffcc250ae5091dec6f299072e23b0b41d6a739"; - let expected = vec![Token::Lit(Lit::new_bin( - b"e69b10ffcc250ae5091dec6f299072e23b0b41d6a739", - ))]; - b.iter(|| assert_eq!(lex_insecure(src).unwrap(), expected)); - } -} - -mod ast { - use { - super::*, - crate::engine::ql::ast::{Entity, InplaceData, State}, - }; - #[bench] - fn parse_entity_single(b: &mut Bencher) { - let e = Entity::Single(Ident::from("user")); - b.iter(|| { - let src = lex_insecure(b"user").unwrap(); - let mut state = State::new(&src, InplaceData::new()); - let re = Entity::parse_from_state_rounded_result(&mut state).unwrap(); - assert_eq!(e, re); - assert!(state.exhausted()); - }) - } - #[bench] - fn parse_entity_double(b: &mut Bencher) { - let e = Entity::Full(Ident::from("tweeter"), Ident::from("user")); - b.iter(|| { - let src = lex_insecure(b"tweeter.user").unwrap(); - let mut state = State::new(&src, InplaceData::new()); - let re = Entity::parse_from_state_rounded_result(&mut state).unwrap(); - assert_eq!(e, re); - assert!(state.exhausted()); - }) - } -} - -mod ddl_queries { - use { - super::*, - crate::engine::ql::{ - ast::{compile, Entity, InplaceData, Statement}, - lex::InsecureLexer, - }, - }; - mod use_stmt { - use super::*; - #[bench] - fn use_space(b: &mut Bencher) { - let src = b"use myspace"; - let expected = Statement::Use(Entity::Single(Ident::from("myspace"))); - b.iter(|| { - let lexed = InsecureLexer::lex(src).unwrap(); - assert_eq!(compile(&lexed, InplaceData::new()).unwrap(), expected); - }); - } - #[bench] - fn use_model(b: &mut Bencher) { - let src = b"use myspace.mymodel"; - let expected = - Statement::Use(Entity::Full(Ident::from("myspace"), Ident::from("mymodel"))); - b.iter(|| { - let lexed = InsecureLexer::lex(src).unwrap(); - assert_eq!(compile(&lexed, InplaceData::new()).unwrap(), expected); - }); - } - } - mod inspect_stmt { - use super::*; - #[bench] - fn inspect_space(b: &mut Bencher) { - let src = b"inspect space myspace"; - let expected = Statement::InspectSpace(Ident::from("myspace")); - b.iter(|| { - let lexed = InsecureLexer::lex(src).unwrap(); - assert_eq!(compile(&lexed, InplaceData::new()).unwrap(), expected); - }); - } - #[bench] - fn inspect_model_single_entity(b: &mut Bencher) { - let src = b"inspect model mymodel"; - let expected = Statement::InspectModel(Entity::Single(Ident::from("mymodel"))); - b.iter(|| { - let lexed = InsecureLexer::lex(src).unwrap(); - assert_eq!(compile(&lexed, InplaceData::new()).unwrap(), expected); - }); - } - #[bench] - fn inspect_model_full_entity(b: &mut Bencher) { - let src = b"inspect model myspace.mymodel"; - let expected = Statement::InspectModel(Entity::Full( - Ident::from("myspace"), - Ident::from("mymodel"), - )); - b.iter(|| { - let lexed = InsecureLexer::lex(src).unwrap(); - assert_eq!(compile(&lexed, InplaceData::new()).unwrap(), expected); - }); - } - #[bench] - fn inspect_spaces(b: &mut Bencher) { - let src = b"inspect spaces"; - let expected = Statement::InspectSpaces; - b.iter(|| { - let lexed = InsecureLexer::lex(src).unwrap(); - assert_eq!(compile(&lexed, InplaceData::new()).unwrap(), expected); - }); - } - } - mod drop_stmt { - use { - super::*, - crate::engine::ql::ddl::drop::{DropModel, DropSpace}, - }; - #[bench] - fn drop_space(b: &mut Bencher) { - let src = b"drop space myspace"; - let expected = Statement::DropSpace(DropSpace::new(Ident::from("myspace"), false)); - b.iter(|| { - let lexed = InsecureLexer::lex(src).unwrap(); - assert_eq!(compile(&lexed, InplaceData::new()).unwrap(), expected); - }); - } - #[bench] - fn drop_space_force(b: &mut Bencher) { - let src = b"drop space myspace force"; - let expected = Statement::DropSpace(DropSpace::new(Ident::from("myspace"), true)); - b.iter(|| { - let lexed = InsecureLexer::lex(src).unwrap(); - assert_eq!(compile(&lexed, InplaceData::new()).unwrap(), expected); - }); - } - #[bench] - fn drop_model_single(b: &mut Bencher) { - let src = b"drop model mymodel"; - let expected = Statement::DropModel(DropModel::new( - Entity::Single(Ident::from("mymodel")), - false, - )); - b.iter(|| { - let lexed = InsecureLexer::lex(src).unwrap(); - assert_eq!(compile(&lexed, InplaceData::new()).unwrap(), expected); - }); - } - #[bench] - fn drop_model_single_force(b: &mut Bencher) { - let src = b"drop model mymodel force"; - let expected = - Statement::DropModel(DropModel::new(Entity::Single(Ident::from("mymodel")), true)); - b.iter(|| { - let lexed = InsecureLexer::lex(src).unwrap(); - assert_eq!(compile(&lexed, InplaceData::new()).unwrap(), expected); - }); - } - #[bench] - fn drop_model_full(b: &mut Bencher) { - let src = b"drop model myspace.mymodel"; - let expected = Statement::DropModel(DropModel::new( - Entity::Full(Ident::from("myspace"), Ident::from("mymodel")), - false, - )); - b.iter(|| { - let lexed = InsecureLexer::lex(src).unwrap(); - assert_eq!(compile(&lexed, InplaceData::new()).unwrap(), expected); - }); - } - #[bench] - fn drop_model_full_force(b: &mut Bencher) { - let src = b"drop model myspace.mymodel force"; - let expected = Statement::DropModel(DropModel::new( - Entity::Full(Ident::from("myspace"), Ident::from("mymodel")), - true, - )); - b.iter(|| { - let lexed = InsecureLexer::lex(src).unwrap(); - assert_eq!(compile(&lexed, InplaceData::new()).unwrap(), expected); - }); - } - } -} diff --git a/server/src/engine/ql/dcl.rs b/server/src/engine/ql/dcl.rs index 5d6b9d31..ec4be180 100644 --- a/server/src/engine/ql/dcl.rs +++ b/server/src/engine/ql/dcl.rs @@ -52,27 +52,22 @@ impl<'a> traits::ASTNode<'a> for SysctlCommand<'a> { fn __base_impl_parse_from_state>( state: &mut State<'a, Qd>, ) -> QueryResult { - if state.remaining() < 1 { + if state.remaining() < 2 { return Err(QueryError::QLUnexpectedEndOfStatement); } - let token = state.fw_read(); - let create = Token![create].eq(token); - let drop = Token![drop].eq(token); - let status = token.ident_eq("status"); - if status { - return Ok(SysctlCommand::ReportStatus); - } - if state.exhausted() { - return Err(QueryError::QLUnexpectedEndOfStatement); - } - let create_or_drop = state.fw_read(); - if !create_or_drop.ident_eq("user") & !(create | drop) { + let (a, b) = (state.fw_read(), state.fw_read()); + let create = Token![create].eq(a) & b.ident_eq("user"); + let drop = Token![drop].eq(a) & b.ident_eq("user"); + let status = a.ident_eq("report") & b.ident_eq("status"); + if !(create | drop | status) { return Err(QueryError::QLUnknownStatement); } if create { UserAdd::parse(state).map(SysctlCommand::CreateUser) - } else { + } else if drop { UserDel::parse(state).map(SysctlCommand::DropUser) + } else { + Ok(SysctlCommand::ReportStatus) } } } diff --git a/server/src/engine/ql/ddl/alt.rs b/server/src/engine/ql/ddl/alt.rs index 702dcdc8..b6069a05 100644 --- a/server/src/engine/ql/ddl/alt.rs +++ b/server/src/engine/ql/ddl/alt.rs @@ -28,10 +28,11 @@ use { super::syn::{self, DictFoldState, ExpandedField}, crate::{ engine::{ + core::EntityIDRef, data::DictGeneric, error::{QueryError, QueryResult}, ql::{ - ast::{Entity, QueryData, State}, + ast::{QueryData, State}, lex::{Ident, Token}, }, }, @@ -90,13 +91,13 @@ impl<'a> AlterSpace<'a> { #[derive(Debug, PartialEq)] pub struct AlterModel<'a> { - pub(in crate::engine) model: Entity<'a>, + pub(in crate::engine) model: EntityIDRef<'a>, pub(in crate::engine) kind: AlterKind<'a>, } impl<'a> AlterModel<'a> { #[inline(always)] - pub fn new(model: Entity<'a>, kind: AlterKind<'a>) -> Self { + pub fn new(model: EntityIDRef<'a>, kind: AlterKind<'a>) -> Self { Self { model, kind } } } @@ -118,7 +119,7 @@ impl<'a> AlterModel<'a> { return compiler::cold_rerr(QueryError::QLInvalidSyntax); // FIXME(@ohsayan): bad because no specificity } - let model_name = Entity::parse_from_state_rounded_result(state)?; + let model_name = state.try_entity_ref_result()?; let kind = match state.fw_read() { Token![add] => AlterKind::alter_add(state), Token![remove] => AlterKind::alter_remove(state), diff --git a/server/src/engine/ql/ddl/crt.rs b/server/src/engine/ql/ddl/crt.rs index edab417c..4827146f 100644 --- a/server/src/engine/ql/ddl/crt.rs +++ b/server/src/engine/ql/ddl/crt.rs @@ -28,14 +28,15 @@ use { super::syn::{self, DictFoldState, FieldSpec}, crate::{ engine::{ + core::EntityIDRef, data::DictGeneric, error::{QueryError, QueryResult}, ql::{ - ast::{Entity, QueryData, State}, + ast::{QueryData, State}, lex::Ident, }, }, - util::{compiler, MaybeInit}, + util::compiler, }, }; @@ -85,7 +86,7 @@ impl<'a> CreateSpace<'a> { /// A model definition pub struct CreateModel<'a> { /// the model name - pub(in crate::engine) model_name: Entity<'a>, + pub(in crate::engine) model_name: EntityIDRef<'a>, /// the fields pub(in crate::engine) fields: Vec>, /// properties @@ -101,7 +102,11 @@ pub struct CreateModel<'a> { impl<'a> CreateModel<'a> { #[cfg(test)] - pub fn new(model_name: Entity<'a>, fields: Vec>, props: DictGeneric) -> Self { + pub fn new( + model_name: EntityIDRef<'a>, + fields: Vec>, + props: DictGeneric, + ) -> Self { Self { model_name, fields, @@ -114,8 +119,7 @@ impl<'a> CreateModel<'a> { return compiler::cold_rerr(QueryError::QLUnexpectedEndOfStatement); } // model name; ignore errors - let mut model_uninit = MaybeInit::uninit(); - Entity::parse_from_state_len_unchecked(state, &mut model_uninit); + let model_uninit = state.try_entity_buffered_into_state_uninit(); state.poison_if_not(state.cursor_eq(Token![() open])); state.cursor_ahead(); // fields diff --git a/server/src/engine/ql/ddl/drop.rs b/server/src/engine/ql/ddl/drop.rs index 15634118..2497e518 100644 --- a/server/src/engine/ql/ddl/drop.rs +++ b/server/src/engine/ql/ddl/drop.rs @@ -25,9 +25,10 @@ */ use crate::engine::{ + core::EntityIDRef, error::{QueryError, QueryResult}, ql::{ - ast::{Entity, QueryData, State, Statement}, + ast::{QueryData, State, Statement}, lex::{Ident, Token}, }, }; @@ -66,17 +67,17 @@ impl<'a> DropSpace<'a> { #[derive(Debug, PartialEq)] pub struct DropModel<'a> { - pub(in crate::engine) entity: Entity<'a>, + pub(in crate::engine) entity: EntityIDRef<'a>, pub(in crate::engine) force: bool, } impl<'a> DropModel<'a> { #[inline(always)] - pub fn new(entity: Entity<'a>, force: bool) -> Self { + pub fn new(entity: EntityIDRef<'a>, force: bool) -> Self { Self { entity, force } } fn parse>(state: &mut State<'a, Qd>) -> QueryResult { - let e = Entity::parse_from_state_rounded_result(state)?; + let e = state.try_entity_ref_result()?; let force = state.cursor_rounded_eq(Token::Ident(Ident::from("force"))); state.cursor_ahead_if(force); Ok(DropModel::new(e, force)) diff --git a/server/src/engine/ql/ddl/ins.rs b/server/src/engine/ql/ddl/ins.rs deleted file mode 100644 index fc69e888..00000000 --- a/server/src/engine/ql/ddl/ins.rs +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Created on Wed Feb 01 2023 - * - * This file is a part of Skytable - * Skytable (formerly known as TerrabaseDB or Skybase) is a free and open-source - * NoSQL database written by Sayan Nandan ("the Author") with the - * vision to provide flexibility in data modelling without compromising - * on performance, queryability or scalability. - * - * Copyright (c) 2023, Sayan Nandan - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * -*/ - -use crate::{ - engine::{ - error::{QueryError, QueryResult}, - ql::{ - ast::{Entity, QueryData, State, Statement}, - lex::Token, - }, - }, - util::compiler, -}; - -pub fn parse_inspect<'a, Qd: QueryData<'a>>( - state: &mut State<'a, Qd>, -) -> QueryResult> { - /* - inpsect model - inspect space - inspect spaces - - min length -> ( | ) = 2 - */ - - if compiler::unlikely(state.remaining() < 1) { - return compiler::cold_rerr(QueryError::QLUnexpectedEndOfStatement); - } - - match state.fw_read() { - Token![model] => { - Entity::parse_from_state_rounded_result(state).map(Statement::InspectModel) - } - Token![space] if state.cursor_has_ident_rounded() => { - Ok(Statement::InspectSpace(unsafe { - // UNSAFE(@ohsayan): Safe because of the match predicate - state.fw_read().uck_read_ident() - })) - } - Token::Ident(id) if id.eq_ignore_ascii_case("spaces") && state.exhausted() => { - Ok(Statement::InspectSpaces) - } - _ => { - state.cursor_back(); - Err(QueryError::QLExpectedStatement) - } - } -} - -#[cfg(test)] -pub use impls::InspectStatementAST; -mod impls { - use crate::engine::{ - error::QueryResult, - ql::ast::{traits::ASTNode, QueryData, State, Statement}, - }; - #[derive(sky_macros::Wrapper, Debug)] - pub struct InspectStatementAST<'a>(Statement<'a>); - impl<'a> ASTNode<'a> for InspectStatementAST<'a> { - const MUST_USE_FULL_TOKEN_RANGE: bool = true; - const VERIFIES_FULL_TOKEN_RANGE_USAGE: bool = false; - fn __base_impl_parse_from_state>( - state: &mut State<'a, Qd>, - ) -> QueryResult { - super::parse_inspect(state).map(Self) - } - } -} diff --git a/server/src/engine/ql/ddl/mod.rs b/server/src/engine/ql/ddl/mod.rs index 639106d0..4f0e0c21 100644 --- a/server/src/engine/ql/ddl/mod.rs +++ b/server/src/engine/ql/ddl/mod.rs @@ -29,4 +29,37 @@ pub(in crate::engine) mod syn; pub(in crate::engine) mod alt; pub(in crate::engine) mod crt; pub(in crate::engine) mod drop; -pub(in crate::engine) mod ins; + +use { + super::{ + ast::traits::ASTNode, + lex::{Ident, Token}, + }, + crate::engine::error::QueryError, +}; + +#[derive(Debug, PartialEq)] +pub enum Use<'a> { + Space(Ident<'a>), + Null, +} + +impl<'a> ASTNode<'a> for Use<'a> { + const MUST_USE_FULL_TOKEN_RANGE: bool = true; + const VERIFIES_FULL_TOKEN_RANGE_USAGE: bool = true; + fn __base_impl_parse_from_state>( + state: &mut super::ast::State<'a, Qd>, + ) -> crate::engine::error::QueryResult { + /* + should have either an ident or null + */ + if state.remaining() != 1 { + return Err(QueryError::QLInvalidSyntax); + } + Ok(match state.fw_read() { + Token![null] => Self::Null, + Token::Ident(id) => Self::Space(id.clone()), + _ => return Err(QueryError::QLInvalidSyntax), + }) + } +} diff --git a/server/src/engine/ql/dml/del.rs b/server/src/engine/ql/dml/del.rs index ed38ca56..7ecb0127 100644 --- a/server/src/engine/ql/dml/del.rs +++ b/server/src/engine/ql/dml/del.rs @@ -30,10 +30,11 @@ use { super::WhereClause, crate::{ engine::{ + core::EntityIDRef, error::{QueryError, QueryResult}, - ql::ast::{Entity, QueryData, State}, + ql::ast::{QueryData, State}, }, - util::{compiler, MaybeInit}, + util::compiler, }, }; @@ -46,12 +47,12 @@ use { #[derive(Debug, PartialEq)] pub struct DeleteStatement<'a> { - pub(super) entity: Entity<'a>, + pub(super) entity: EntityIDRef<'a>, pub(super) wc: WhereClause<'a>, } impl<'a> DeleteStatement<'a> { - pub const fn entity(&self) -> Entity<'a> { + pub const fn entity(&self) -> EntityIDRef<'a> { self.entity } pub fn clauses_mut(&mut self) -> &mut WhereClause<'a> { @@ -62,12 +63,12 @@ impl<'a> DeleteStatement<'a> { impl<'a> DeleteStatement<'a> { #[inline(always)] #[cfg(test)] - pub(super) fn new(entity: Entity<'a>, wc: WhereClause<'a>) -> Self { + pub(super) fn new(entity: EntityIDRef<'a>, wc: WhereClause<'a>) -> Self { Self { entity, wc } } #[inline(always)] #[cfg(test)] - pub fn new_test(entity: Entity<'a>, wc: WhereClauseCollection<'a>) -> Self { + pub fn new_test(entity: EntityIDRef<'a>, wc: WhereClauseCollection<'a>) -> Self { Self::new(entity, WhereClause::new(wc)) } #[inline(always)] @@ -84,8 +85,7 @@ impl<'a> DeleteStatement<'a> { // from + entity state.poison_if_not(state.cursor_eq(Token![from])); state.cursor_ahead(); // ignore errors (if any) - let mut entity = MaybeInit::uninit(); - Entity::parse_from_state_len_unchecked(state, &mut entity); + let entity = state.try_entity_buffered_into_state_uninit(); // where + clauses state.poison_if_not(state.cursor_eq(Token![where])); state.cursor_ahead(); // ignore errors diff --git a/server/src/engine/ql/dml/ins.rs b/server/src/engine/ql/dml/ins.rs index eaf70aba..9bd4069b 100644 --- a/server/src/engine/ql/dml/ins.rs +++ b/server/src/engine/ql/dml/ins.rs @@ -27,14 +27,15 @@ use { crate::{ engine::{ + core::EntityIDRef, data::cell::Datacell, error::{QueryError, QueryResult}, ql::{ - ast::{Entity, QueryData, State}, + ast::{QueryData, State}, lex::{Ident, Token}, }, }, - util::{compiler, MaybeInit}, + util::compiler, }, std::{ collections::HashMap, @@ -321,17 +322,17 @@ impl<'a> From, Datacell>> for InsertData<'a> { #[derive(Debug, PartialEq)] pub struct InsertStatement<'a> { - pub(super) entity: Entity<'a>, + pub(super) entity: EntityIDRef<'a>, pub(super) data: InsertData<'a>, } impl<'a> InsertStatement<'a> { #[inline(always)] #[cfg(test)] - pub fn new(entity: Entity<'a>, data: InsertData<'a>) -> Self { + pub fn new(entity: EntityIDRef<'a>, data: InsertData<'a>) -> Self { Self { entity, data } } - pub fn entity(&self) -> Entity<'a> { + pub fn entity(&self) -> EntityIDRef<'a> { self.entity } pub fn data(self) -> InsertData<'a> { @@ -353,8 +354,7 @@ impl<'a> InsertStatement<'a> { state.cursor_ahead(); // ignore errors // entity - let mut entity = MaybeInit::uninit(); - Entity::parse_from_state_len_unchecked(state, &mut entity); + let entity = state.try_entity_buffered_into_state_uninit(); let mut data = None; match state.fw_read() { Token![() open] if state.not_exhausted() => { diff --git a/server/src/engine/ql/dml/sel.rs b/server/src/engine/ql/dml/sel.rs index a17d58d6..2efd189f 100644 --- a/server/src/engine/ql/dml/sel.rs +++ b/server/src/engine/ql/dml/sel.rs @@ -30,13 +30,14 @@ use { super::WhereClause, crate::{ engine::{ + core::EntityIDRef, error::{QueryError, QueryResult}, ql::{ - ast::{Entity, QueryData, State}, + ast::{QueryData, State}, lex::{Ident, Token}, }, }, - util::{compiler, MaybeInit}, + util::compiler, }, }; @@ -47,7 +48,7 @@ use { #[derive(Debug, PartialEq)] pub struct SelectStatement<'a> { /// the entity - pub(super) entity: Entity<'a>, + pub(super) entity: EntityIDRef<'a>, /// fields in order of querying. will be zero when wildcard is set pub(super) fields: Vec>, /// whether a wildcard was passed @@ -60,7 +61,7 @@ impl<'a> SelectStatement<'a> { #[inline(always)] #[cfg(test)] pub(crate) fn new_test( - entity: Entity<'a>, + entity: EntityIDRef<'a>, fields: Vec>, wildcard: bool, clauses: WhereClauseCollection<'a>, @@ -70,7 +71,7 @@ impl<'a> SelectStatement<'a> { #[inline(always)] #[cfg(test)] fn new( - entity: Entity<'a>, + entity: EntityIDRef<'a>, fields: Vec>, wildcard: bool, clauses: WhereClauseCollection<'a>, @@ -82,7 +83,7 @@ impl<'a> SelectStatement<'a> { clause: WhereClause::new(clauses), } } - pub fn entity(&self) -> Entity<'a> { + pub fn entity(&self) -> EntityIDRef<'a> { self.entity } pub fn clauses_mut(&mut self) -> &mut WhereClause<'a> { @@ -128,8 +129,7 @@ impl<'a> SelectStatement<'a> { } state.poison_if_not(state.cursor_eq(Token![from])); state.cursor_ahead(); // ignore errors - let mut entity = MaybeInit::uninit(); - Entity::parse_from_state_rounded(state, &mut entity); + let entity = state.try_entity_buffered_into_state_uninit(); let mut clauses = <_ as Default>::default(); if state.cursor_rounded_eq(Token![where]) { state.cursor_ahead(); diff --git a/server/src/engine/ql/dml/upd.rs b/server/src/engine/ql/dml/upd.rs index 9252ba06..8eaf8ea3 100644 --- a/server/src/engine/ql/dml/upd.rs +++ b/server/src/engine/ql/dml/upd.rs @@ -28,15 +28,15 @@ use { super::{u, WhereClause}, crate::{ engine::{ - core::query_meta::AssignmentOperator, + core::{query_meta::AssignmentOperator, EntityIDRef}, data::lit::Lit, error::{QueryError, QueryResult}, ql::{ - ast::{Entity, QueryData, State}, + ast::{QueryData, State}, lex::Ident, }, }, - util::{compiler, MaybeInit}, + util::compiler, }, }; @@ -124,13 +124,13 @@ impl<'a> AssignmentExpression<'a> { #[derive(Debug, PartialEq)] pub struct UpdateStatement<'a> { - pub(super) entity: Entity<'a>, + pub(super) entity: EntityIDRef<'a>, pub(super) expressions: Vec>, pub(super) wc: WhereClause<'a>, } impl<'a> UpdateStatement<'a> { - pub fn entity(&self) -> Entity<'a> { + pub fn entity(&self) -> EntityIDRef<'a> { self.entity } pub fn expressions(&self) -> &[AssignmentExpression<'a>] { @@ -148,7 +148,7 @@ impl<'a> UpdateStatement<'a> { #[inline(always)] #[cfg(test)] pub fn new( - entity: Entity<'a>, + entity: EntityIDRef<'a>, expressions: Vec>, wc: WhereClause<'a>, ) -> Self { @@ -170,8 +170,7 @@ impl<'a> UpdateStatement<'a> { return compiler::cold_rerr(QueryError::QLUnexpectedEndOfStatement); } // parse entity - let mut entity = MaybeInit::uninit(); - Entity::parse_from_state_len_unchecked(state, &mut entity); + let entity = state.try_entity_buffered_into_state_uninit(); if !(state.has_remaining(6)) { unsafe { // UNSAFE(@ohsayan): Obvious from above, max 3 fw diff --git a/server/src/engine/ql/mod.rs b/server/src/engine/ql/mod.rs index 02c1368f..a05c924c 100644 --- a/server/src/engine/ql/mod.rs +++ b/server/src/engine/ql/mod.rs @@ -27,9 +27,6 @@ #[macro_use] mod macros; pub(super) mod ast; -#[cfg(feature = "nightly")] -#[cfg(test)] -mod benches; pub(super) mod dcl; pub(super) mod ddl; pub(super) mod dml; diff --git a/server/src/engine/ql/tests.rs b/server/src/engine/ql/tests.rs index c856f19d..25c4b3a1 100644 --- a/server/src/engine/ql/tests.rs +++ b/server/src/engine/ql/tests.rs @@ -35,8 +35,8 @@ use { mod dcl; mod dml_tests; -mod entity; mod lexer_tests; +mod misc; mod schema_tests; mod structure_syn; diff --git a/server/src/engine/ql/tests/dcl.rs b/server/src/engine/ql/tests/dcl.rs index 5e15170a..44596d99 100644 --- a/server/src/engine/ql/tests/dcl.rs +++ b/server/src/engine/ql/tests/dcl.rs @@ -32,7 +32,7 @@ use crate::engine::ql::{ #[test] fn report_status_simple() { - let query = lex_insecure(b"sysctl status").unwrap(); + let query = lex_insecure(b"sysctl report status").unwrap(); let q = ast::parse_ast_node_full::(&query[1..]).unwrap(); assert_eq!(q, SysctlCommand::ReportStatus) } diff --git a/server/src/engine/ql/tests/dml_tests.rs b/server/src/engine/ql/tests/dml_tests.rs index eeb7ec3a..15ad9c44 100644 --- a/server/src/engine/ql/tests/dml_tests.rs +++ b/server/src/engine/ql/tests/dml_tests.rs @@ -295,7 +295,7 @@ mod stmt_insert { use { super::*, crate::engine::ql::{ - ast::{parse_ast_node_full, Entity}, + ast::parse_ast_node_full, dml::{self, ins::InsertStatement}, lex::Ident, }, @@ -311,7 +311,7 @@ mod stmt_insert { .unwrap(); let r = parse_ast_node_full::(&x[1..]).unwrap(); let e = InsertStatement::new( - Entity::Full(Ident::from("twitter"), Ident::from("users")), + ("twitter", "users").into(), into_array_nullable!["sayan"].to_vec().into(), ); assert_eq!(e, r); @@ -333,7 +333,7 @@ mod stmt_insert { .unwrap(); let r = parse_ast_node_full::(&x[1..]).unwrap(); let e = InsertStatement::new( - Entity::Full(Ident::from("twitter"), Ident::from("users")), + ("twitter", "users").into(), into_array_nullable!["sayan", "Sayan", "sayan@example.com", true, 12345, 67890] .to_vec() .into(), @@ -360,7 +360,7 @@ mod stmt_insert { .unwrap(); let r = parse_ast_node_full::(&x[1..]).unwrap(); let e = InsertStatement::new( - Entity::Full(Ident::from("twitter"), Ident::from("users")), + ("twitter", "users").into(), into_array_nullable![ "sayan", "Sayan", @@ -387,7 +387,7 @@ mod stmt_insert { .unwrap(); let r = parse_ast_node_full::(&tok[1..]).unwrap(); let e = InsertStatement::new( - Entity::Full(Ident::from("jotsy"), Ident::from("app")), + ("jotsy", "app").into(), dict_nullable! { Ident::from("username") => "sayan" } @@ -412,7 +412,7 @@ mod stmt_insert { .unwrap(); let r = parse_ast_node_full::(&tok[1..]).unwrap(); let e = InsertStatement::new( - Entity::Full(Ident::from("jotsy"), Ident::from("app")), + ("jotsy", "app").into(), dict_nullable! { Ident::from("username") => "sayan", Ident::from("name") => "Sayan", @@ -445,7 +445,7 @@ mod stmt_insert { .unwrap(); let r = parse_ast_node_full::(&tok[1..]).unwrap(); let e = InsertStatement::new( - Entity::Full(Ident::from("jotsy"), Ident::from("app")), + ("jotsy", "app").into(), dict_nullable! { Ident::from("username") => "sayan", "password" => "pass123", @@ -467,7 +467,7 @@ mod stmt_insert { lex_insecure(br#"insert into jotsy.app(@uuidstr(), "sayan", @timesec())"#).unwrap(); let ret = parse_ast_node_full::(&tok[1..]).unwrap(); let expected = InsertStatement::new( - Entity::Full(Ident::from("jotsy"), Ident::from("app")), + ("jotsy", "app").into(), into_array_nullable![dml::ins::T_UUIDSTR, "sayan", dml::ins::T_TIMESEC] .to_vec() .into(), @@ -481,7 +481,7 @@ mod stmt_insert { ).unwrap(); let ret = parse_ast_node_full::(&tok[1..]).unwrap(); let expected = InsertStatement::new( - Entity::Full(Ident::from("jotsy"), Ident::from("app")), + ("jotsy", "app").into(), dict_nullable! { "uuid" => dml::ins::T_UUIDSTR, Ident::from("username") => "sayan", @@ -499,7 +499,7 @@ mod stmt_select { crate::engine::{ data::lit::Lit, ql::{ - ast::{parse_ast_node_full, Entity}, + ast::{parse_ast_node_full, parse_ast_node_full_with_space}, dml::{sel::SelectStatement, RelationalExpr}, lex::Ident, }, @@ -513,9 +513,9 @@ mod stmt_select { "#, ) .unwrap(); - let r = parse_ast_node_full::(&tok[1..]).unwrap(); + let r = parse_ast_node_full_with_space::(&tok[1..], "apps").unwrap(); let e = SelectStatement::new_test( - Entity::Single(Ident::from("users")), + ("apps", "users").into(), [].to_vec(), true, dict! { @@ -534,9 +534,9 @@ mod stmt_select { "#, ) .unwrap(); - let r = parse_ast_node_full::(&tok[1..]).unwrap(); + let r = parse_ast_node_full_with_space::(&tok[1..], "apps").unwrap(); let e = SelectStatement::new_test( - Entity::Single(Ident::from("users")), + ("apps", "users").into(), [Ident::from("field1")].to_vec(), false, dict! { @@ -557,7 +557,7 @@ mod stmt_select { .unwrap(); let r = parse_ast_node_full::(&tok[1..]).unwrap(); let e = SelectStatement::new_test( - Entity::Full(Ident::from("twitter"), Ident::from("users")), + ("twitter", "users").into(), [Ident::from("field1")].to_vec(), false, dict! { @@ -578,7 +578,7 @@ mod stmt_select { .unwrap(); let r = parse_ast_node_full::(&tok[1..]).unwrap(); let e = SelectStatement::new_test( - Entity::Full(Ident::from("twitter"), Ident::from("users")), + ("twitter", "users").into(), [Ident::from("field1"), Ident::from("field2")].to_vec(), false, dict! { @@ -672,7 +672,7 @@ mod update_statement { core::query_meta::AssignmentOperator, data::lit::Lit, ql::{ - ast::{parse_ast_node_full, Entity}, + ast::{parse_ast_node_full, parse_ast_node_full_with_space}, dml::{ upd::{AssignmentExpression, UpdateStatement}, RelationalExpr, WhereClause, @@ -689,9 +689,9 @@ mod update_statement { "#, ) .unwrap(); - let r = parse_ast_node_full::(&tok[1..]).unwrap(); + let r = parse_ast_node_full_with_space::(&tok[1..], "apps").unwrap(); let e = UpdateStatement::new( - Entity::Single(Ident::from("app")), + ("apps", "app").into(), vec![AssignmentExpression::new( Ident::from("notes"), Lit::new_str("this is my new note"), @@ -723,7 +723,7 @@ mod update_statement { .unwrap(); let r = parse_ast_node_full::(&tok[1..]).unwrap(); let e = UpdateStatement::new( - Entity::Full(Ident::from("jotsy"), Ident::from("app")), + ("jotsy", "app").into(), vec![ AssignmentExpression::new( Ident::from("notes"), @@ -753,7 +753,7 @@ mod delete_stmt { crate::engine::{ data::lit::Lit, ql::{ - ast::{parse_ast_node_full, Entity}, + ast::{parse_ast_node_full, parse_ast_node_full_with_space}, dml::{del::DeleteStatement, RelationalExpr}, lex::Ident, }, @@ -769,7 +769,7 @@ mod delete_stmt { ) .unwrap(); let e = DeleteStatement::new_test( - Entity::Single(Ident::from("users")), + ("apps", "users").into(), dict! { Ident::from("username") => RelationalExpr::new( Ident::from("username"), @@ -779,7 +779,7 @@ mod delete_stmt { }, ); assert_eq!( - parse_ast_node_full::(&tok[1..]).unwrap(), + parse_ast_node_full_with_space::(&tok[1..], "apps").unwrap(), e ); } @@ -792,7 +792,7 @@ mod delete_stmt { ) .unwrap(); let e = DeleteStatement::new_test( - Entity::Full(Ident::from("twitter"), Ident::from("users")), + ("twitter", "users").into(), dict! { Ident::from("username") => RelationalExpr::new( Ident::from("username"), diff --git a/server/src/engine/ql/tests/entity.rs b/server/src/engine/ql/tests/misc.rs similarity index 59% rename from server/src/engine/ql/tests/entity.rs rename to server/src/engine/ql/tests/misc.rs index 7999d36e..f9837884 100644 --- a/server/src/engine/ql/tests/entity.rs +++ b/server/src/engine/ql/tests/misc.rs @@ -25,17 +25,51 @@ */ use super::*; -use crate::engine::ql::{ast::Entity, lex::Ident}; +use crate::engine::ql::{ + ast::{traits::ASTNode, State}, + ddl::Use, +}; + +/* + entity +*/ + #[test] fn entity_current() { let t = lex_insecure(b"hello").unwrap(); - let r = Entity::parse_from_tokens_len_checked(&t, &mut 0).unwrap(); - assert_eq!(r, Entity::Single(Ident::from("hello"))) + let mut state = State::new_inplace(&t); + state.set_space("apps"); + let r = state.try_entity_ref().unwrap(); + assert_eq!(r, ("apps", "hello").into()); } #[test] fn entity_full() { let t = lex_insecure(b"hello.world").unwrap(); - let r = Entity::parse_from_tokens_len_checked(&t, &mut 0).unwrap(); - assert_eq!(r, Entity::Full(Ident::from("hello"), Ident::from("world"))) + let mut state = State::new_inplace(&t); + assert_eq!( + state.try_entity_ref().unwrap(), + (("hello"), ("world")).into() + ) +} + +/* + use +*/ + +#[test] +fn use_new() { + let t = lex_insecure(b"use myspace").unwrap(); + let mut state = State::new_inplace(&t); + assert_eq!( + Use::test_parse_from_state(&mut state).unwrap(), + Use::Space("myspace".into()) + ); +} + +#[test] +fn use_null() { + let t = lex_insecure(b"use null").unwrap(); + let mut state = State::new_inplace(&t); + assert_eq!(Use::test_parse_from_state(&mut state).unwrap(), Use::Null); } diff --git a/server/src/engine/ql/tests/schema_tests.rs b/server/src/engine/ql/tests/schema_tests.rs index bb0e1acf..6ee020b8 100644 --- a/server/src/engine/ql/tests/schema_tests.rs +++ b/server/src/engine/ql/tests/schema_tests.rs @@ -28,44 +28,6 @@ use { super::{super::lex::Ident, lex_insecure, *}, crate::engine::data::lit::Lit, }; -mod inspect { - use { - super::*, - crate::engine::ql::{ - ast::{parse_ast_node_full, Entity, Statement}, - ddl::ins::InspectStatementAST, - }, - }; - #[test] - fn inspect_space() { - let tok = lex_insecure(b"inspect space myspace").unwrap(); - assert_eq!( - parse_ast_node_full::(&tok[1..]).unwrap(), - Statement::InspectSpace(Ident::from("myspace")) - ); - } - #[test] - fn inspect_model() { - let tok = lex_insecure(b"inspect model users").unwrap(); - assert_eq!( - parse_ast_node_full::(&tok[1..]).unwrap(), - Statement::InspectModel(Entity::Single(Ident::from("users"))) - ); - let tok = lex_insecure(b"inspect model tweeter.users").unwrap(); - assert_eq!( - parse_ast_node_full::(&tok[1..]).unwrap(), - Statement::InspectModel(Entity::Full(Ident::from("tweeter"), Ident::from("users"))) - ); - } - #[test] - fn inspect_spaces() { - let tok = lex_insecure(b"inspect spaces").unwrap(); - assert_eq!( - parse_ast_node_full::(&tok[1..]).unwrap(), - Statement::InspectSpaces - ); - } -} mod alter_space { use { @@ -417,7 +379,7 @@ mod fields { mod schemas { use super::*; use crate::engine::ql::{ - ast::{parse_ast_node_full, Entity}, + ast::parse_ast_node_full_with_space, ddl::{ crt::CreateModel, syn::{FieldSpec, LayerSpec}, @@ -437,12 +399,12 @@ mod schemas { let tok = &tok[2..]; // parse model - let model = parse_ast_node_full::(tok).unwrap(); + let model = parse_ast_node_full_with_space::(tok, "apps").unwrap(); assert_eq!( model, CreateModel::new( - Entity::Single(Ident::from("mymodel")), + ("apps", "mymodel").into(), vec![ FieldSpec::new( Ident::from("username"), @@ -476,12 +438,12 @@ mod schemas { let tok = &tok[2..]; // parse model - let model = parse_ast_node_full::(tok).unwrap(); + let model = parse_ast_node_full_with_space::(tok, "apps").unwrap(); assert_eq!( model, CreateModel::new( - Entity::Single(Ident::from("mymodel")), + ("apps", "mymodel").into(), vec![ FieldSpec::new( Ident::from("username"), @@ -526,12 +488,12 @@ mod schemas { let tok = &tok[2..]; // parse model - let model = parse_ast_node_full::(tok).unwrap(); + let model = parse_ast_node_full_with_space::(tok, "apps").unwrap(); assert_eq!( model, CreateModel::new( - Entity::Single(Ident::from("mymodel")), + ("apps", "mymodel").into(), vec![ FieldSpec::new( Ident::from("username"), @@ -595,12 +557,12 @@ mod schemas { let tok = &tok[2..]; // parse model - let model = parse_ast_node_full::(tok).unwrap(); + let model = parse_ast_node_full_with_space::(tok, "apps").unwrap(); assert_eq!( model, CreateModel::new( - Entity::Single(Ident::from("mymodel")), + ("apps", "mymodel").into(), vec![ FieldSpec::new( Ident::from("username"), @@ -768,18 +730,18 @@ mod dict_field_syntax { mod alter_model_remove { use super::*; use crate::engine::ql::{ - ast::{parse_ast_node_full, Entity}, + ast::parse_ast_node_full_with_space, ddl::alt::{AlterKind, AlterModel}, lex::Ident, }; #[test] fn alter_mini() { let tok = lex_insecure(b"alter model mymodel remove myfield").unwrap(); - let remove = parse_ast_node_full::(&tok[2..]).unwrap(); + let remove = parse_ast_node_full_with_space::(&tok[2..], "apps").unwrap(); assert_eq!( remove, AlterModel::new( - Entity::Single(Ident::from("mymodel")), + ("apps", "mymodel").into(), AlterKind::Remove(Box::from([Ident::from("myfield")])) ) ); @@ -787,11 +749,11 @@ mod alter_model_remove { #[test] fn alter_mini_2() { let tok = lex_insecure(b"alter model mymodel remove (myfield)").unwrap(); - let remove = parse_ast_node_full::(&tok[2..]).unwrap(); + let remove = parse_ast_node_full_with_space::(&tok[2..], "apps").unwrap(); assert_eq!( remove, AlterModel::new( - Entity::Single(Ident::from("mymodel")), + ("apps", "mymodel").into(), AlterKind::Remove(Box::from([Ident::from("myfield")])) ) ); @@ -801,11 +763,11 @@ mod alter_model_remove { let tok = lex_insecure(b"alter model mymodel remove (myfield1, myfield2, myfield3, myfield4)") .unwrap(); - let remove = parse_ast_node_full::(&tok[2..]).unwrap(); + let remove = parse_ast_node_full_with_space::(&tok[2..], "apps").unwrap(); assert_eq!( remove, AlterModel::new( - Entity::Single(Ident::from("mymodel")), + ("apps", "mymodel").into(), AlterKind::Remove(Box::from([ Ident::from("myfield1"), Ident::from("myfield2"), @@ -819,7 +781,7 @@ mod alter_model_remove { mod alter_model_add { use super::*; use crate::engine::ql::{ - ast::{parse_ast_node_full, Entity}, + ast::parse_ast_node_full_with_space, ddl::{ alt::{AlterKind, AlterModel}, syn::{ExpandedField, LayerSpec}, @@ -834,9 +796,9 @@ mod alter_model_add { ) .unwrap(); assert_eq!( - parse_ast_node_full::(&tok[2..]).unwrap(), + parse_ast_node_full_with_space::(&tok[2..], "apps").unwrap(), AlterModel::new( - Entity::Single(Ident::from("mymodel")), + ("apps", "mymodel").into(), AlterKind::Add( [ExpandedField::new( Ident::from("myfield"), @@ -856,11 +818,11 @@ mod alter_model_add { ", ) .unwrap(); - let r = parse_ast_node_full::(&tok[2..]).unwrap(); + let r = parse_ast_node_full_with_space::(&tok[2..], "apps").unwrap(); assert_eq!( r, AlterModel::new( - Entity::Single(Ident::from("mymodel")), + ("apps", "mymodel").into(), AlterKind::Add( [ExpandedField::new( Ident::from("myfield"), @@ -882,11 +844,11 @@ mod alter_model_add { ", ) .unwrap(); - let r = parse_ast_node_full::(&tok[2..]).unwrap(); + let r = parse_ast_node_full_with_space::(&tok[2..], "apps").unwrap(); assert_eq!( r, AlterModel::new( - Entity::Single(Ident::from("mymodel")), + ("apps", "mymodel").into(), AlterKind::Add( [ExpandedField::new( Ident::from("myfield"), @@ -922,11 +884,11 @@ mod alter_model_add { ", ) .unwrap(); - let r = parse_ast_node_full::(&tok[2..]).unwrap(); + let r = parse_ast_node_full_with_space::(&tok[2..], "apps").unwrap(); assert_eq!( r, AlterModel::new( - Entity::Single(Ident::from("mymodel")), + ("apps", "mymodel").into(), AlterKind::Add( [ ExpandedField::new( @@ -967,7 +929,7 @@ mod alter_model_add { mod alter_model_update { use super::*; use crate::engine::ql::{ - ast::{parse_ast_node_full, Entity}, + ast::parse_ast_node_full_with_space, ddl::{ alt::{AlterKind, AlterModel}, syn::{ExpandedField, LayerSpec}, @@ -982,11 +944,11 @@ mod alter_model_update { ", ) .unwrap(); - let r = parse_ast_node_full::(&tok[2..]).unwrap(); + let r = parse_ast_node_full_with_space::(&tok[2..], "apps").unwrap(); assert_eq!( r, AlterModel::new( - Entity::Single(Ident::from("mymodel")), + ("apps", "mymodel").into(), AlterKind::Update( [ExpandedField::new( Ident::from("myfield"), @@ -1006,11 +968,11 @@ mod alter_model_update { ", ) .unwrap(); - let r = parse_ast_node_full::(&tok[2..]).unwrap(); + let r = parse_ast_node_full_with_space::(&tok[2..], "apps").unwrap(); assert_eq!( r, AlterModel::new( - Entity::Single(Ident::from("mymodel")), + ("apps", "mymodel").into(), AlterKind::Update( [ExpandedField::new( Ident::from("myfield"), @@ -1035,11 +997,11 @@ mod alter_model_update { ", ) .unwrap(); - let r = parse_ast_node_full::(&tok[2..]).unwrap(); + let r = parse_ast_node_full_with_space::(&tok[2..], "apps").unwrap(); assert_eq!( r, AlterModel::new( - Entity::Single(Ident::from("mymodel")), + ("apps", "mymodel").into(), AlterKind::Update( [ExpandedField::new( Ident::from("myfield"), @@ -1069,11 +1031,11 @@ mod alter_model_update { ", ) .unwrap(); - let r = parse_ast_node_full::(&tok[2..]).unwrap(); + let r = parse_ast_node_full_with_space::(&tok[2..], "apps").unwrap(); assert_eq!( r, AlterModel::new( - Entity::Single(Ident::from("mymodel")), + ("apps", "mymodel").into(), AlterKind::Update( [ ExpandedField::new( @@ -1112,11 +1074,11 @@ mod alter_model_update { ", ) .unwrap(); - let r = parse_ast_node_full::(&tok[2..]).unwrap(); + let r = parse_ast_node_full_with_space::(&tok[2..], "apps").unwrap(); assert_eq!( r, AlterModel::new( - Entity::Single(Ident::from("mymodel")), + ("apps", "mymodel").into(), AlterKind::Update( [ ExpandedField::new( @@ -1147,7 +1109,7 @@ mod ddl_other_query_tests { use { super::*, crate::engine::ql::{ - ast::{parse_ast_node_full, Entity, Statement}, + ast::{parse_ast_node_full, parse_ast_node_full_with_space, Statement}, ddl::drop::{DropModel, DropSpace, DropStatementAST}, lex::Ident, }, @@ -1172,19 +1134,16 @@ mod ddl_other_query_tests { fn drop_model() { let src = lex_insecure(br"drop model mymodel").unwrap(); assert_eq!( - parse_ast_node_full::(&src[1..]).unwrap(), - Statement::DropModel(DropModel::new( - Entity::Single(Ident::from("mymodel")), - false - )) + parse_ast_node_full_with_space::(&src[1..], "apps").unwrap(), + Statement::DropModel(DropModel::new(("apps", "mymodel").into(), false)) ); } #[test] fn drop_model_force() { let src = lex_insecure(br"drop model mymodel force").unwrap(); assert_eq!( - parse_ast_node_full::(&src[1..]).unwrap(), - Statement::DropModel(DropModel::new(Entity::Single(Ident::from("mymodel")), true)) + parse_ast_node_full_with_space::(&src[1..], "apps").unwrap(), + Statement::DropModel(DropModel::new(("apps", "mymodel").into(), true)) ); } } diff --git a/server/src/engine/storage/v1/inf/tests.rs b/server/src/engine/storage/v1/inf/tests.rs index 9e1ce4fc..c8e2f7b0 100644 --- a/server/src/engine/storage/v1/inf/tests.rs +++ b/server/src/engine/storage/v1/inf/tests.rs @@ -99,7 +99,7 @@ fn model() { let model = Model::new_restore( uuid, "username".into(), - TagSelector::Str.into_full(), + TagSelector::String.into_full(), into_dict! { "password" => Field::new([Layer::bin()].into(), false), "profile_pic" => Field::new([Layer::bin()].into(), true), diff --git a/server/src/engine/storage/v1/tests/batch.rs b/server/src/engine/storage/v1/tests/batch.rs index 0cb4d24c..75ab5578 100644 --- a/server/src/engine/storage/v1/tests/batch.rs +++ b/server/src/engine/storage/v1/tests/batch.rs @@ -131,7 +131,7 @@ fn empty_multi_open_reopen() { let mdl = Model::new_restore( uuid, "username".into(), - TagSelector::Str.into_full(), + TagSelector::String.into_full(), into_dict!( "username" => Field::new([Layer::str()].into(), false), "password" => Field::new([Layer::bin()].into(), false) @@ -149,7 +149,7 @@ fn unskewed_delta() { let mdl = Model::new_restore( uuid, "username".into(), - TagSelector::Str.into_full(), + TagSelector::String.into_full(), into_dict!( "username" => Field::new([Layer::str()].into(), false), "password" => Field::new([Layer::bin()].into(), false) @@ -219,7 +219,7 @@ fn skewed_delta() { let mdl = Model::new_restore( uuid, "catname".into(), - TagSelector::Str.into_full(), + TagSelector::String.into_full(), into_dict!( "catname" => Field::new([Layer::str()].into(), false), "is_good" => Field::new([Layer::bool()].into(), false), @@ -302,7 +302,7 @@ fn skewed_shuffled_persist_restore() { let model = Model::new_restore( uuid, "username".into(), - TagSelector::Str.into_full(), + TagSelector::String.into_full(), into_dict!("username" => Field::new([Layer::str()].into(), false), "password" => Field::new([Layer::str()].into(), false)), ); let mongobongo = Row::new( diff --git a/server/src/engine/txn/gns/tests/full_chain.rs b/server/src/engine/txn/gns/tests/full_chain.rs index 191d663f..35be0bfb 100644 --- a/server/src/engine/txn/gns/tests/full_chain.rs +++ b/server/src/engine/txn/gns/tests/full_chain.rs @@ -185,7 +185,7 @@ fn create_model() { &Model::new_restore( uuid_model, "username".into(), - TagSelector::Str.into_full(), + TagSelector::String.into_full(), into_dict! { "username" => Field::new([Layer::str()].into(), false), "password" => Field::new([Layer::bin()].into(), false), diff --git a/server/src/engine/txn/gns/tests/io.rs b/server/src/engine/txn/gns/tests/io.rs index 99ffc200..9a03c5dd 100644 --- a/server/src/engine/txn/gns/tests/io.rs +++ b/server/src/engine/txn/gns/tests/io.rs @@ -107,7 +107,7 @@ mod model_tests { let model = Model::new_restore( Uuid::new(), "username".into(), - TagSelector::Str.into_full(), + TagSelector::String.into_full(), into_dict!( "password" => Field::new([Layer::bin()].into(), false), "profile_pic" => Field::new([Layer::bin()].into(), true), diff --git a/sky-bench/src/bench.rs b/sky-bench/src/bench.rs index 4b9d435f..dc52f662 100644 --- a/sky-bench/src/bench.rs +++ b/sky-bench/src/bench.rs @@ -36,6 +36,9 @@ use { std::{fmt, time::Instant}, }; +pub const BENCHMARK_SPACE_ID: &'static str = "bench"; +pub const BENCHMARK_MODEL_ID: &'static str = "bench"; + /* task impl */ @@ -90,7 +93,7 @@ impl BombardTaskSpec { } } pub fn generate(&self, current: u64) -> (Query, Response) { - let mut q = query!(&self.base_query); + let mut q = query!(self.base_query.as_str()); let resp = match self.kind { BombardTaskKind::Insert(second_column) => { self.push_pk(&mut q, current); @@ -146,7 +149,9 @@ impl rookie::ThreadedBombardTask for BombardTask { type WorkerInitError = Error; type WorkerTaskError = BombardTaskError; fn worker_init(&self) -> Result { - self.config.connect() + let mut db = self.config.connect()?; + db.query_parse::<()>(&skytable::query!(format!("use {BENCHMARK_SPACE_ID}"))) + .map(|_| db) } fn generate_task(spec: &Self::WorkerTaskSpec, current: u64) -> Self::WorkerTask { spec.generate(current) @@ -180,7 +185,9 @@ pub fn run(bench: BenchConfig) -> error::BenchResult<()> { info!("running preliminary checks and creating model `bench.bench` with definition: `{{un: string, pw: uint8}}`"); let mut main_thread_db = bench_config.config.connect()?; main_thread_db.query_parse::<()>(&query!("create space bench"))?; - main_thread_db.query_parse::<()>(&query!("create model bench.bench(un: string, pw: uint8)"))?; + main_thread_db.query_parse::<()>(&query!(format!( + "create model {BENCHMARK_SPACE_ID}.{BENCHMARK_MODEL_ID}(un: string, pw: uint8)" + )))?; let stats = match bench.engine { BenchEngine::Rookie => bench_rookie(bench_config, bench), BenchEngine::Fury => bench_fury(bench), @@ -278,23 +285,20 @@ fn prepare_bench_spec(bench: &BenchConfig) -> Vec { vec![ BenchItem::new( "INSERT", - BombardTaskSpec::insert("insert into bench.bench(?, ?)".into(), bench.key_size, 0), + BombardTaskSpec::insert("insert into bench(?, ?)".into(), bench.key_size, 0), bench.query_count, ), BenchItem::new( "UPDATE", BombardTaskSpec::update( - "update bench.bench set pw += ? where un = ?".into(), + "update bench set pw += ? where un = ?".into(), bench.key_size, ), bench.query_count, ), BenchItem::new( "DELETE", - BombardTaskSpec::delete( - "delete from bench.bench where un = ?".into(), - bench.key_size, - ), + BombardTaskSpec::delete("delete from bench where un = ?".into(), bench.key_size), bench.query_count, ), ] diff --git a/sky-bench/src/runtime/fury.rs b/sky-bench/src/runtime/fury.rs index 53f0b2df..1d06e5de 100644 --- a/sky-bench/src/runtime/fury.rs +++ b/sky-bench/src/runtime/fury.rs @@ -26,7 +26,7 @@ use { super::{RuntimeStats, WorkerLocalStats, WorkerTask}, - crate::bench::BombardTaskSpec, + crate::bench::{BombardTaskSpec, BENCHMARK_SPACE_ID}, skytable::Config, std::{ fmt, @@ -232,9 +232,9 @@ async fn worker_svc( return; } }; - // warm up connection + // set DB in connections match db - .query_parse::<()>(&skytable::query!("sysctl report status")) + .query_parse::<()>(&skytable::query!(format!("use {BENCHMARK_SPACE_ID}"))) .await { Ok(()) => {}