insertion

main
Ziyang Hu 1 year ago
parent 55c27e4396
commit 4208989f31

@ -135,9 +135,10 @@ limit_option = {":limit" ~ expr}
offset_option = {":offset" ~ expr}
sort_option = {(":sort" | ":order") ~ (sort_arg ~ ",")* ~ sort_arg }
relation_option = {relation_op ~ (compound_ident | underscore_ident) ~ table_schema?}
relation_op = _{relation_create | relation_replace | relation_put | relation_update | relation_rm | relation_ensure_not | relation_ensure }
relation_op = _{relation_create | relation_replace | relation_insert | relation_put | relation_update | relation_rm | relation_ensure_not | relation_ensure }
relation_create = {":create"}
relation_replace = {":replace"}
relation_insert = {":insert"}
relation_put = {":put"}
relation_update = {":update"}
relation_rm = {":rm"}

@ -76,15 +76,15 @@ impl Display for QueryOutOptions {
writeln!(f, "{symb};")?;
}
if let Some((
InputRelationHandle {
name,
metadata: StoredRelationMetadata { keys, non_keys },
key_bindings,
dep_bindings,
..
},
op,
)) = &self.store_relation
InputRelationHandle {
name,
metadata: StoredRelationMetadata { keys, non_keys },
key_bindings,
dep_bindings,
..
},
op,
)) = &self.store_relation
{
match op {
RelationOp::Create => {
@ -93,6 +93,9 @@ impl Display for QueryOutOptions {
RelationOp::Replace => {
write!(f, ":replace ")?;
}
RelationOp::Insert => {
write!(f, ":insert ")?;
}
RelationOp::Put => {
write!(f, ":put ")?;
}
@ -178,6 +181,7 @@ pub(crate) enum RelationOp {
Create,
Replace,
Put,
Insert,
Update,
Rm,
Ensure,
@ -486,13 +490,13 @@ impl Display for InputProgram {
}
InputInlineRulesOrFixed::Fixed {
fixed:
FixedRuleApply {
fixed_handle: handle,
rule_args,
options,
head,
..
},
FixedRuleApply {
fixed_handle: handle,
rule_args,
options,
head,
..
},
} => {
write!(f, "{name}")?;
f.debug_list().entries(head).finish()?;
@ -627,7 +631,7 @@ impl InputProgram {
inner: rule.body,
span: rule.span,
}
.disjunctive_normal_form(tx)?;
.disjunctive_normal_form(tx)?;
let mut new_head = Vec::with_capacity(rule.head.len());
let mut seen: BTreeMap<&Symbol, Vec<Symbol>> = BTreeMap::default();
for symb in rule.head.iter() {
@ -989,7 +993,7 @@ pub(crate) struct FtsSearch {
}
impl HnswSearch {
pub(crate) fn all_bindings(&self) -> impl Iterator<Item = &Symbol> {
pub(crate) fn all_bindings(&self) -> impl Iterator<Item=&Symbol> {
self.bindings
.iter()
.chain(self.bind_field.iter())
@ -1000,7 +1004,7 @@ impl HnswSearch {
}
impl FtsSearch {
pub(crate) fn all_bindings(&self) -> impl Iterator<Item = &Symbol> {
pub(crate) fn all_bindings(&self) -> impl Iterator<Item=&Symbol> {
self.bindings.iter().chain(self.bind_score.iter())
}
}
@ -1652,12 +1656,12 @@ impl Display for InputAtom {
}
InputAtom::Unification {
inner:
Unification {
binding,
expr,
one_many_unif,
..
},
Unification {
binding,
expr,
one_many_unif,
..
},
} => {
write!(f, "{binding}")?;
if *one_many_unif {

@ -317,6 +317,7 @@ pub(crate) fn parse_query(
Rule::relation_create => RelationOp::Create,
Rule::relation_replace => RelationOp::Replace,
Rule::relation_put => RelationOp::Put,
Rule::relation_insert => RelationOp::Insert,
Rule::relation_update => RelationOp::Update,
Rule::relation_rm => RelationOp::Rm,
Rule::relation_ensure => RelationOp::Ensure,

@ -44,7 +44,7 @@ impl<'a> SessionTx<'a> {
pub(crate) fn execute_relation<'s, S: Storage<'s>>(
&mut self,
db: &Db<S>,
res_iter: impl Iterator<Item = Tuple>,
res_iter: impl Iterator<Item=Tuple>,
op: RelationOp,
meta: &InputRelationHandle,
headers: &[Symbol],
@ -88,7 +88,7 @@ impl<'a> SessionTx<'a> {
&db.fixed_rules.read().unwrap(),
cur_vld,
)?
.get_single_program()?;
.get_single_program()?;
let (_, cleanups) = db
.run_query(
@ -178,7 +178,7 @@ impl<'a> SessionTx<'a> {
key_bindings,
*span,
)?,
RelationOp::Create | RelationOp::Replace | RelationOp::Put => self.put_into_relation(
RelationOp::Create | RelationOp::Replace | RelationOp::Put | RelationOp::Insert => self.put_into_relation(
db,
res_iter,
headers,
@ -191,6 +191,7 @@ impl<'a> SessionTx<'a> {
metadata,
key_bindings,
dep_bindings,
op == RelationOp::Insert,
*span,
)?,
};
@ -201,7 +202,7 @@ impl<'a> SessionTx<'a> {
fn put_into_relation<'s, S: Storage<'s>>(
&mut self,
db: &Db<S>,
res_iter: impl Iterator<Item = Tuple>,
res_iter: impl Iterator<Item=Tuple>,
headers: &[Symbol],
cur_vld: ValidityTs,
callback_targets: &BTreeSet<SmartString<LazyCompact>>,
@ -212,6 +213,7 @@ impl<'a> SessionTx<'a> {
metadata: &StoredRelationMetadata,
key_bindings: &[Symbol],
dep_bindings: &[Symbol],
is_insert: bool,
span: SourceSpan,
) -> Result<()> {
let is_callback_target = callback_targets.contains(&relation_store.name);
@ -233,7 +235,7 @@ impl<'a> SessionTx<'a> {
let need_to_collect = !relation_store.is_temp
&& (is_callback_target
|| (propagate_triggers && !relation_store.put_triggers.is_empty()));
|| (propagate_triggers && !relation_store.put_triggers.is_empty()));
let has_indices = !relation_store.indices.is_empty();
let has_hnsw_indices = !relation_store.hnsw_indices.is_empty();
let has_fts_indices = !relation_store.fts_indices.is_empty();
@ -268,6 +270,16 @@ impl<'a> SessionTx<'a> {
.map(|ex| ex.extract_data(&tuple, cur_vld))
.try_collect()?;
if is_insert {
if relation_store.exists(self, &extracted[..relation_store.metadata.keys.len()])? {
bail!(TransactAssertionFailure {
relation: relation_store.name.to_string(),
key: extracted,
notice: "key exists in database".to_string()
});
}
}
let key = relation_store.encode_key_for_store(&extracted, span)?;
let val = relation_store.encode_val_for_store(&extracted, span)?;
@ -496,7 +508,7 @@ impl<'a> SessionTx<'a> {
fn update_in_relation<'s, S: Storage<'s>>(
&mut self,
db: &Db<S>,
res_iter: impl Iterator<Item = Tuple>,
res_iter: impl Iterator<Item=Tuple>,
headers: &[Symbol],
cur_vld: ValidityTs,
callback_targets: &BTreeSet<SmartString<LazyCompact>>,
@ -527,7 +539,7 @@ impl<'a> SessionTx<'a> {
let need_to_collect = !relation_store.is_temp
&& (is_callback_target
|| (propagate_triggers && !relation_store.put_triggers.is_empty()));
|| (propagate_triggers && !relation_store.put_triggers.is_empty()));
let has_indices = !relation_store.indices.is_empty();
let has_hnsw_indices = !relation_store.hnsw_indices.is_empty();
let has_fts_indices = !relation_store.fts_indices.is_empty();
@ -674,7 +686,7 @@ impl<'a> SessionTx<'a> {
&db.fixed_rules.read().unwrap(),
cur_vld,
)?
.get_single_program()?;
.get_single_program()?;
make_const_rule(
&mut program,
@ -770,7 +782,7 @@ impl<'a> SessionTx<'a> {
fn ensure_not_in_relation(
&mut self,
res_iter: impl Iterator<Item = Tuple>,
res_iter: impl Iterator<Item=Tuple>,
headers: &[Symbol],
cur_vld: ValidityTs,
relation_store: &mut RelationHandle,
@ -817,7 +829,7 @@ impl<'a> SessionTx<'a> {
fn ensure_in_relation(
&mut self,
res_iter: impl Iterator<Item = Tuple>,
res_iter: impl Iterator<Item=Tuple>,
headers: &[Symbol],
cur_vld: ValidityTs,
relation_store: &mut RelationHandle,
@ -887,7 +899,7 @@ impl<'a> SessionTx<'a> {
fn remove_from_relation<'s, S: Storage<'s>>(
&mut self,
db: &Db<S>,
res_iter: impl Iterator<Item = Tuple>,
res_iter: impl Iterator<Item=Tuple>,
headers: &[Symbol],
cur_vld: ValidityTs,
callback_targets: &BTreeSet<SmartString<LazyCompact>>,
@ -917,7 +929,7 @@ impl<'a> SessionTx<'a> {
let need_to_collect = !relation_store.is_temp
&& (is_callback_target
|| (propagate_triggers && !relation_store.rm_triggers.is_empty()));
|| (propagate_triggers && !relation_store.rm_triggers.is_empty()));
let has_indices = !relation_store.indices.is_empty();
let has_hnsw_indices = !relation_store.hnsw_indices.is_empty();
let has_fts_indices = !relation_store.fts_indices.is_empty();
@ -992,7 +1004,7 @@ impl<'a> SessionTx<'a> {
&db.fixed_rules.read().unwrap(),
cur_vld,
)?
.get_single_program()?;
.get_single_program()?;
make_const_rule(&mut program, "_new", k_bindings.clone(), new_tuples.clone());

@ -1177,6 +1177,16 @@ fn ensure_not() {
", Default::default()).unwrap();
}
#[test]
fn insertion() {
let db = DbInstance::new("mem", "", "").unwrap();
db.run_script(r":create a {x => y}", Default::default()).unwrap();
assert!(db.run_script(r"?[x, y] <- [[1, 2]] :insert a {x => y}", Default::default())
.is_ok());
assert!(db.run_script(r"?[x, y] <- [[1, 3]] :insert a {x => y}", Default::default())
.is_err());
}
#[test]
fn parser_corner_case() {
let db = DbInstance::new("mem", "", "").unwrap();

Loading…
Cancel
Save