No need to specify column dependencies unless it is :create or :replace

main
Ziyang Hu 1 year ago
parent e974be9a46
commit af46e62a86

@ -123,9 +123,8 @@ pub(crate) struct StoredRelationMetadata {
} }
impl StoredRelationMetadata { impl StoredRelationMetadata {
pub(crate) fn satisfied_by_required_col(&self, col: &ColumnDef, is_key: bool) -> Result<()> { pub(crate) fn satisfied_by_required_col(&self, col: &ColumnDef) -> Result<()> {
let targets = if is_key { &self.keys } else { &self.non_keys }; for target in self.keys.iter().chain(self.non_keys.iter()) {
for target in targets {
if target.name == col.name { if target.name == col.name {
return Ok(()); return Ok(());
} }
@ -140,9 +139,8 @@ impl StoredRelationMetadata {
} }
Ok(()) Ok(())
} }
pub(crate) fn compatible_with_col(&self, col: &ColumnDef, is_key: bool) -> Result<()> { pub(crate) fn compatible_with_col(&self, col: &ColumnDef) -> Result<()> {
let targets = if is_key { &self.keys } else { &self.non_keys }; for target in self.keys.iter().chain(self.non_keys.iter()) {
for target in targets {
if target.name == col.name { if target.name == col.name {
#[derive(Debug, Error, Diagnostic)] #[derive(Debug, Error, Diagnostic)]
#[error("requested column {0} has typing {1}, but the requested typing is {2}")] #[error("requested column {0} has typing {1}, but the requested typing is {2}")]

@ -22,7 +22,11 @@ use thiserror::Error;
use crate::data::aggr::{parse_aggr, Aggregation}; use crate::data::aggr::{parse_aggr, Aggregation};
use crate::data::expr::Expr; use crate::data::expr::Expr;
use crate::data::functions::{str2vld, MAX_VALIDITY_TS}; use crate::data::functions::{str2vld, MAX_VALIDITY_TS};
use crate::data::program::{FixedRuleApply, FixedRuleArg, InputAtom, InputInlineRule, InputInlineRulesOrFixed, InputNamedFieldRelationApplyAtom, InputProgram, InputRelationApplyAtom, InputRuleApplyAtom, QueryAssertion, QueryOutOptions, RelationOp, SearchInput, SortDir, Unification}; use crate::data::program::{
FixedRuleApply, FixedRuleArg, InputAtom, InputInlineRule, InputInlineRulesOrFixed,
InputNamedFieldRelationApplyAtom, InputProgram, InputRelationApplyAtom, InputRuleApplyAtom,
QueryAssertion, QueryOutOptions, RelationOp, SearchInput, SortDir, Unification,
};
use crate::data::relation::{ColType, ColumnDef, NullableColType, StoredRelationMetadata}; use crate::data::relation::{ColType, ColumnDef, NullableColType, StoredRelationMetadata};
use crate::data::symb::{Symbol, PROG_ENTRY}; use crate::data::symb::{Symbol, PROG_ENTRY};
use crate::data::value::{DataValue, ValidityTs}; use crate::data::value::{DataValue, ValidityTs};
@ -319,7 +323,14 @@ pub(crate) fn parse_query(
match args.next() { match args.next() {
None => stored_relation = Some(Left((name, span, op))), None => stored_relation = Some(Left((name, span, op))),
Some(schema_p) => { Some(schema_p) => {
let (metadata, key_bindings, dep_bindings) = parse_schema(schema_p)?; let (mut metadata, mut key_bindings, mut dep_bindings) =
parse_schema(schema_p)?;
if !matches!(op, RelationOp::Create | RelationOp::Replace) {
key_bindings.extend(dep_bindings);
dep_bindings = vec![];
metadata.keys.extend(metadata.non_keys);
metadata.non_keys = vec![];
}
stored_relation = Some(Right(( stored_relation = Some(Right((
InputRelationHandle { InputRelationHandle {
name, name,

@ -7,13 +7,14 @@
*/ */
use std::collections::{BTreeMap, BTreeSet}; use std::collections::{BTreeMap, BTreeSet};
use std::fmt::{Debug, Formatter}; use std::fmt::{Debug, Formatter, Write};
use std::iter; use std::iter;
use either::{Left, Right}; use either::{Left, Right};
use itertools::Itertools; use itertools::Itertools;
use log::{debug, error}; use log::{debug, error};
use miette::{bail, Diagnostic, Result}; use miette::{bail, Diagnostic, Result};
use smartstring::SmartString;
use thiserror::Error; use thiserror::Error;
use crate::data::expr::{compute_bounds, eval_bytecode, eval_bytecode_pred, Bytecode, Expr}; use crate::data::expr::{compute_bounds, eval_bytecode, eval_bytecode_pred, Bytecode, Expr};
@ -1027,14 +1028,14 @@ impl FtsSearchRA {
let q = match tuple[bind_idx].clone() { let q = match tuple[bind_idx].clone() {
DataValue::Str(s) => s, DataValue::Str(s) => s,
DataValue::List(l) => { DataValue::List(l) => {
let mut coll = String::new(); let mut coll = SmartString::new();
for d in l { for d in l {
match d { match d {
DataValue::Str(s) => { DataValue::Str(s) => {
if !coll.is_empty() { if !coll.is_empty() {
coll += " OR "; coll.write_str(" OR ").unwrap();
} }
coll += &s coll.write_str(&s).unwrap();
}, },
d => bail!("Expected string for FTS search, got {:?}", d), d => bail!("Expected string for FTS search, got {:?}", d),
} }

@ -153,7 +153,6 @@ impl<'a> SessionTx<'a> {
&mut relation_store, &mut relation_store,
metadata, metadata,
key_bindings, key_bindings,
dep_bindings,
*span, *span,
)?, )?,
RelationOp::EnsureNot => self.ensure_not_in_relation( RelationOp::EnsureNot => self.ensure_not_in_relation(
@ -177,7 +176,6 @@ impl<'a> SessionTx<'a> {
&mut relation_store, &mut relation_store,
metadata, metadata,
key_bindings, key_bindings,
dep_bindings,
*span, *span,
)?, )?,
RelationOp::Create | RelationOp::Replace | RelationOp::Put => self.put_into_relation( RelationOp::Create | RelationOp::Replace | RelationOp::Put => self.put_into_relation(
@ -243,12 +241,21 @@ impl<'a> SessionTx<'a> {
let mut new_tuples: Vec<DataValue> = vec![]; let mut new_tuples: Vec<DataValue> = vec![];
let mut old_tuples: Vec<DataValue> = vec![]; let mut old_tuples: Vec<DataValue> = vec![];
let val_extractors = make_extractors( let val_extractors = if metadata.non_keys.is_empty() {
make_extractors(
&relation_store.metadata.non_keys,
&metadata.keys,
key_bindings,
headers,
)?
} else {
make_extractors(
&relation_store.metadata.non_keys, &relation_store.metadata.non_keys,
&metadata.non_keys, &metadata.non_keys,
dep_bindings, dep_bindings,
headers, headers,
)?; )?
};
key_extractors.extend(val_extractors); key_extractors.extend(val_extractors);
let mut stack = vec![]; let mut stack = vec![];
let hnsw_filters = Self::make_hnsw_filters(relation_store)?; let hnsw_filters = Self::make_hnsw_filters(relation_store)?;
@ -499,7 +506,6 @@ impl<'a> SessionTx<'a> {
relation_store: &mut RelationHandle, relation_store: &mut RelationHandle,
metadata: &StoredRelationMetadata, metadata: &StoredRelationMetadata,
key_bindings: &[Symbol], key_bindings: &[Symbol],
dep_bindings: &[Symbol],
span: SourceSpan, span: SourceSpan,
) -> Result<()> { ) -> Result<()> {
let is_callback_target = callback_targets.contains(&relation_store.name); let is_callback_target = callback_targets.contains(&relation_store.name);
@ -531,8 +537,8 @@ impl<'a> SessionTx<'a> {
let val_extractors = make_update_extractors( let val_extractors = make_update_extractors(
&relation_store.metadata.non_keys, &relation_store.metadata.non_keys,
&metadata.non_keys, &metadata.keys,
dep_bindings, key_bindings,
headers, headers,
); );
@ -817,7 +823,6 @@ impl<'a> SessionTx<'a> {
relation_store: &mut RelationHandle, relation_store: &mut RelationHandle,
metadata: &StoredRelationMetadata, metadata: &StoredRelationMetadata,
key_bindings: &[Symbol], key_bindings: &[Symbol],
dep_bindings: &[Symbol],
span: SourceSpan, span: SourceSpan,
) -> Result<()> { ) -> Result<()> {
if relation_store.access_level < AccessLevel::ReadOnly { if relation_store.access_level < AccessLevel::ReadOnly {
@ -837,8 +842,8 @@ impl<'a> SessionTx<'a> {
let val_extractors = make_extractors( let val_extractors = make_extractors(
&relation_store.metadata.non_keys, &relation_store.metadata.non_keys,
&metadata.non_keys, &metadata.keys,
dep_bindings, key_bindings,
headers, headers,
)?; )?;
key_extractors.extend(val_extractors); key_extractors.extend(val_extractors);

@ -301,19 +301,16 @@ impl RelationHandle {
) -> Result<()> { ) -> Result<()> {
let InputRelationHandle { metadata, .. } = inp; let InputRelationHandle { metadata, .. } = inp;
// check that every given key is found and compatible // check that every given key is found and compatible
for col in &metadata.keys { for col in metadata.keys.iter().chain(self.metadata.non_keys.iter()) {
self.metadata.compatible_with_col(col, true)? self.metadata.compatible_with_col(col)?
}
for col in &metadata.non_keys {
self.metadata.compatible_with_col(col, false)?
} }
// check that every key is provided or has default // check that every key is provided or has default
for col in &self.metadata.keys { for col in &self.metadata.keys {
metadata.satisfied_by_required_col(col, true)?; metadata.satisfied_by_required_col(col)?;
} }
if !is_remove_or_update { if !is_remove_or_update {
for col in &self.metadata.non_keys { for col in &self.metadata.non_keys {
metadata.satisfied_by_required_col(col, false)?; metadata.satisfied_by_required_col(col)?;
} }
} }
Ok(()) Ok(())

@ -536,7 +536,7 @@ fn test_index() {
.unwrap(); .unwrap();
db.run_script( db.run_script(
r"?[fr, to, data] <- [[1,2,3],[4,5,6]] :put friends {fr, to => data}", r"?[fr, to, data] <- [[1,2,3],[4,5,6]] :put friends {fr, to, data}",
Default::default(), Default::default(),
) )
.unwrap(); .unwrap();

Loading…
Cancel
Save