Simplify entity handling, impl describe and use

next
Sayan Nandan 10 months ago
parent 6ea9758714
commit 0fdd615665
No known key found for this signature in database
GPG Key ID: 42EEDF4AE9D96B54

@ -23,6 +23,9 @@ All changes in this project will be noted in this file.
- `ALTER MODEL ...`
- `DROP SPACE ...`
- `DROP MODEL ...`
- `USE <space>`:
- 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:

3
Cargo.lock generated

@ -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",

@ -57,13 +57,13 @@ enum Item {
}
impl SQParam for Item {
fn push(self, buf: &mut Vec<u8>) {
fn append_param(self, buf: &mut Vec<u8>) {
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(())
}
}?

@ -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<u8>, item: &Datacell) {

@ -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<Response> {
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<A: ASTNode<'static> + core::fmt::Debug, T>(
g: Global,
tokens: RawSlice<Token<'static>>,
f: impl FnOnce(&Global, A) -> QueryResult<T>,
) -> QueryResult<T> {
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<A: ASTNode<'static> + core::fmt::Debug, T>(
g: &Global,
@ -88,7 +74,7 @@ fn _call<A: ASTNode<'static> + core::fmt::Debug, T>(
async fn run_blocking_stmt(
global: &Global,
cstate: &ClientLocalState,
cstate: &mut ClientLocalState,
mut state: State<'_, InplaceData>,
stmt: KeywordStmt,
) -> Result<Response, QueryError> {
@ -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<Token<'static>>) -> 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<Token<'static>>,
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<Response> {
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<Response> {
let stmt = stmt.value_u8() - KeywordStmt::Use.value_u8();
static F: [fn(&Global, &mut State<'static, InplaceData>) -> QueryResult<Response>; 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<Response>; 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)
}
}

@ -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<T>
pub fn with_model_space_mut_for_ddl<'a, T, F>(
&self,
entity: EntityIDRef<'a>,
f: F,
) -> QueryResult<T>
where
F: FnOnce(&Space, &mut Model) -> QueryResult<T>,
{
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<T>
pub fn with_model<'a, T, F>(&self, entity: EntityIDRef<'a>, f: F) -> QueryResult<T>
where
F: FnOnce(&Model) -> QueryResult<T>,
{
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<QueryExecMeta>,
{
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(())
}

@ -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| {

@ -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
*/

@ -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,

@ -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
);

@ -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<Model> {
@ -52,13 +48,11 @@ pub fn exec_create(
) -> QueryResult<String> {
let tok = lex_insecure(create_stmt.as_bytes()).unwrap();
let create_model = parse_ast_node_full::<CreateModel>(&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)
}

@ -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<T>(
global: &impl GlobalInstanceLike,
insert: &str,
and_then: impl Fn(Entity) -> T,
and_then: impl Fn(EntityIDRef) -> T,
) -> QueryResult<T> {
let lex_insert = lex_insecure(insert.as_bytes()).unwrap();
let stmt_insert = parse_ast_node_full::<InsertStatement>(&lex_insert[1..]).unwrap();
@ -68,7 +68,7 @@ fn _exec_only_insert<T>(
fn _exec_only_read_key_and_then<T>(
global: &impl GlobalInstanceLike,
entity: Entity,
entity: EntityIDRef,
key_name: &str,
and_then: impl Fn(Row) -> T,
) -> QueryResult<T> {

@ -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<EntityIDRef<'a>> 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)
}
}

@ -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

@ -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

@ -41,7 +41,7 @@ pub use {
astr::AStr,
ll::CachePadded,
numbuf::IntegerRepr,
rawslice::{RawSlice, RawStr},
rawslice::RawStr,
scanner::BufferedScanner,
uarray::UArray,
vinline::VInline,

@ -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<str>,
root: bool,
hs: handshake::CHandshakeStatic,
cs: Option<Box<str>>,
}
impl ClientLocalState {
pub fn new(username: Box<str>, 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<str>) {
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<u8> },
Serialized {
ty: ResponseType,
size: usize,
data: Vec<u8>,
},
}
pub(super) async fn query_loop<S: Socket>(
@ -82,7 +121,7 @@ pub(super) async fn query_loop<S: Socket>(
global: &Global,
) -> IoResult<QueryLoopResult> {
// 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<S: Socket>(
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<S: Socket>(
}
};
// 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<S: Socket>(
}
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?;

@ -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<T>(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<EntityIDRef<'a>> {
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<EntityIDRef<'a>> {
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<EntityIDRef<'a>> {
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<KeywordStmt> {
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<Self> {
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<Qd: QueryData<'a>>(
state: &mut State<'a, Qd>,
) -> QueryResult<Self> {
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<Qd: QueryData<'a>>(
state: &mut State<'a, Qd>,
d: &mut MaybeInit<Entity<'a>>,
) {
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<Qd: QueryData<'a>>(
state: &mut State<'a, Qd>,
d: &mut MaybeInit<Entity<'a>>,
) {
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<Statement<'a>> {
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),

@ -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<Self> {
let mut state = State::new(tok, InplaceData::new());
state.set_space(space_name);
let r = <Self as ASTNode>::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<Vec<Self>> {
@ -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> {
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<Vec<N>> {

@ -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 <ohsayan@outlook.com>
*
* 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 <https://www.gnu.org/licenses/>.
*
*/
/*
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);
});
}
}
}

@ -52,27 +52,22 @@ impl<'a> traits::ASTNode<'a> for SysctlCommand<'a> {
fn __base_impl_parse_from_state<Qd: QueryData<'a>>(
state: &mut State<'a, Qd>,
) -> QueryResult<Self> {
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)
}
}
}

@ -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),

@ -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<FieldSpec<'a>>,
/// properties
@ -101,7 +102,11 @@ pub struct CreateModel<'a> {
impl<'a> CreateModel<'a> {
#[cfg(test)]
pub fn new(model_name: Entity<'a>, fields: Vec<FieldSpec<'a>>, props: DictGeneric) -> Self {
pub fn new(
model_name: EntityIDRef<'a>,
fields: Vec<FieldSpec<'a>>,
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

@ -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<Qd: QueryData<'a>>(state: &mut State<'a, Qd>) -> QueryResult<Self> {
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))

@ -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 <ohsayan@outlook.com>
*
* 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 <https://www.gnu.org/licenses/>.
*
*/
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<Statement<'a>> {
/*
inpsect model <entity>
inspect space <entity>
inspect spaces
min length -> (<model> | <space>) <model> = 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<Qd: QueryData<'a>>(
state: &mut State<'a, Qd>,
) -> QueryResult<Self> {
super::parse_inspect(state).map(Self)
}
}
}

@ -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<Qd: super::ast::QueryData<'a>>(
state: &mut super::ast::State<'a, Qd>,
) -> crate::engine::error::QueryResult<Self> {
/*
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),
})
}
}

@ -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

@ -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<HashMap<Ident<'static>, 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() => {

@ -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<Ident<'a>>,
/// 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<Ident<'a>>,
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<Ident<'a>>,
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();

@ -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<AssignmentExpression<'a>>,
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<AssignmentExpression<'a>>,
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

@ -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;

@ -35,8 +35,8 @@ use {
mod dcl;
mod dml_tests;
mod entity;
mod lexer_tests;
mod misc;
mod schema_tests;
mod structure_syn;

@ -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::<dcl::SysctlCommand>(&query[1..]).unwrap();
assert_eq!(q, SysctlCommand::ReportStatus)
}

@ -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::<InsertStatement>(&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::<InsertStatement>(&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::<InsertStatement>(&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::<InsertStatement>(&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::<InsertStatement>(&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::<InsertStatement>(&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::<InsertStatement>(&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::<InsertStatement>(&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::<SelectStatement>(&tok[1..]).unwrap();
let r = parse_ast_node_full_with_space::<SelectStatement>(&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::<SelectStatement>(&tok[1..]).unwrap();
let r = parse_ast_node_full_with_space::<SelectStatement>(&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::<SelectStatement>(&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::<SelectStatement>(&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::<UpdateStatement>(&tok[1..]).unwrap();
let r = parse_ast_node_full_with_space::<UpdateStatement>(&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::<UpdateStatement>(&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::<DeleteStatement>(&tok[1..]).unwrap(),
parse_ast_node_full_with_space::<DeleteStatement>(&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"),

@ -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);
}

@ -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::<InspectStatementAST>(&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::<InspectStatementAST>(&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::<InspectStatementAST>(&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::<InspectStatementAST>(&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::<CreateModel>(tok).unwrap();
let model = parse_ast_node_full_with_space::<CreateModel>(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::<CreateModel>(tok).unwrap();
let model = parse_ast_node_full_with_space::<CreateModel>(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::<CreateModel>(tok).unwrap();
let model = parse_ast_node_full_with_space::<CreateModel>(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::<CreateModel>(tok).unwrap();
let model = parse_ast_node_full_with_space::<CreateModel>(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::<AlterModel>(&tok[2..]).unwrap();
let remove = parse_ast_node_full_with_space::<AlterModel>(&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::<AlterModel>(&tok[2..]).unwrap();
let remove = parse_ast_node_full_with_space::<AlterModel>(&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::<AlterModel>(&tok[2..]).unwrap();
let remove = parse_ast_node_full_with_space::<AlterModel>(&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::<AlterModel>(&tok[2..]).unwrap(),
parse_ast_node_full_with_space::<AlterModel>(&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::<AlterModel>(&tok[2..]).unwrap();
let r = parse_ast_node_full_with_space::<AlterModel>(&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::<AlterModel>(&tok[2..]).unwrap();
let r = parse_ast_node_full_with_space::<AlterModel>(&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::<AlterModel>(&tok[2..]).unwrap();
let r = parse_ast_node_full_with_space::<AlterModel>(&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::<AlterModel>(&tok[2..]).unwrap();
let r = parse_ast_node_full_with_space::<AlterModel>(&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::<AlterModel>(&tok[2..]).unwrap();
let r = parse_ast_node_full_with_space::<AlterModel>(&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::<AlterModel>(&tok[2..]).unwrap();
let r = parse_ast_node_full_with_space::<AlterModel>(&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::<AlterModel>(&tok[2..]).unwrap();
let r = parse_ast_node_full_with_space::<AlterModel>(&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::<AlterModel>(&tok[2..]).unwrap();
let r = parse_ast_node_full_with_space::<AlterModel>(&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::<DropStatementAST>(&src[1..]).unwrap(),
Statement::DropModel(DropModel::new(
Entity::Single(Ident::from("mymodel")),
false
))
parse_ast_node_full_with_space::<DropStatementAST>(&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::<DropStatementAST>(&src[1..]).unwrap(),
Statement::DropModel(DropModel::new(Entity::Single(Ident::from("mymodel")), true))
parse_ast_node_full_with_space::<DropStatementAST>(&src[1..], "apps").unwrap(),
Statement::DropModel(DropModel::new(("apps", "mymodel").into(), true))
);
}
}

@ -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),

@ -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(

@ -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),

@ -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),

@ -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::Worker, Self::WorkerInitError> {
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<BenchItem> {
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,
),
]

@ -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(()) => {}

Loading…
Cancel
Save