clippy happy

main
Ziyang Hu 2 years ago
parent b4e33af5c2
commit 341b94bbcd

@ -26,4 +26,4 @@ fn main() {
println!("cargo:rerun-if-changed=src/bridge.rs");
println!("cargo:rerun-if-changed=bridge/cozorocks.cc");
println!("cargo:rerun-if-changed=bridge/cozorocks.h");
}
}

@ -104,7 +104,9 @@ mod ffi {
fn new_transaction_options() -> UniquePtr<TransactionOptions>;
fn set_deadlock_detect(o: Pin<&mut TransactionOptions>, v: bool);
type OptimisticTransactionOptions;
fn new_optimistic_transaction_options(cmp: &RustComparator) -> UniquePtr<OptimisticTransactionOptions>;
fn new_optimistic_transaction_options(
cmp: &RustComparator,
) -> UniquePtr<OptimisticTransactionOptions>;
type TransactionDBOptions;
fn new_tdb_options() -> UniquePtr<TransactionDBOptions>;
type OptimisticTransactionDBOptions;
@ -116,7 +118,11 @@ mod ffi {
fn set_allow_write_stall(o: Pin<&mut FlushOptions>, v: bool);
type RustComparator;
fn new_rust_comparator(name: &str, cmp: fn(&[u8], &[u8]) -> i8, diff_bytes_can_equal: bool) -> UniquePtr<RustComparator>;
fn new_rust_comparator(
name: &str,
cmp: fn(&[u8], &[u8]) -> i8,
diff_bytes_can_equal: bool,
) -> UniquePtr<RustComparator>;
pub type IteratorBridge;
fn seek_to_first(self: &IteratorBridge);
@ -136,26 +142,76 @@ mod ffi {
fn set_savepoint(self: &TransactionBridge);
fn rollback_to_savepoint(self: &TransactionBridge, status: &mut BridgeStatus);
fn pop_savepoint(self: &TransactionBridge, status: &mut BridgeStatus);
fn get_txn(self: &TransactionBridge, cf: &ColumnFamilyHandle, key: &[u8],
status: &mut BridgeStatus) -> SharedPtr<PinnableSlice>;
fn get_for_update_txn(self: &TransactionBridge, cf: &ColumnFamilyHandle, key: &[u8],
status: &mut BridgeStatus) -> SharedPtr<PinnableSlice>;
fn get_raw(self: &TransactionBridge, cf: &ColumnFamilyHandle, key: &[u8],
status: &mut BridgeStatus) -> SharedPtr<PinnableSlice>;
fn put_txn(self: &TransactionBridge, cf: &ColumnFamilyHandle, key: &[u8], val: &[u8],
status: &mut BridgeStatus);
fn put_raw(self: &TransactionBridge, cf: &ColumnFamilyHandle, key: &[u8], val: &[u8],
status: &mut BridgeStatus);
fn del_txn(self: &TransactionBridge, cf: &ColumnFamilyHandle, key: &[u8],
status: &mut BridgeStatus);
fn del_raw(self: &TransactionBridge, cf: &ColumnFamilyHandle, key: &[u8],
status: &mut BridgeStatus);
fn del_range_raw(self: &TransactionBridge, cf: &ColumnFamilyHandle,
start_key: &[u8], end_key: &[u8], status: &mut BridgeStatus);
fn flush_raw(self: &TransactionBridge, cf: &ColumnFamilyHandle, options: &FlushOptions, status: &mut BridgeStatus);
fn compact_all_raw(self: &TransactionBridge, cf: &ColumnFamilyHandle, status: &mut BridgeStatus);
fn iterator_txn(self: &TransactionBridge, cf: &ColumnFamilyHandle) -> UniquePtr<IteratorBridge>;
fn iterator_raw(self: &TransactionBridge, cf: &ColumnFamilyHandle) -> UniquePtr<IteratorBridge>;
fn get_txn(
self: &TransactionBridge,
cf: &ColumnFamilyHandle,
key: &[u8],
status: &mut BridgeStatus,
) -> SharedPtr<PinnableSlice>;
fn get_for_update_txn(
self: &TransactionBridge,
cf: &ColumnFamilyHandle,
key: &[u8],
status: &mut BridgeStatus,
) -> SharedPtr<PinnableSlice>;
fn get_raw(
self: &TransactionBridge,
cf: &ColumnFamilyHandle,
key: &[u8],
status: &mut BridgeStatus,
) -> SharedPtr<PinnableSlice>;
fn put_txn(
self: &TransactionBridge,
cf: &ColumnFamilyHandle,
key: &[u8],
val: &[u8],
status: &mut BridgeStatus,
);
fn put_raw(
self: &TransactionBridge,
cf: &ColumnFamilyHandle,
key: &[u8],
val: &[u8],
status: &mut BridgeStatus,
);
fn del_txn(
self: &TransactionBridge,
cf: &ColumnFamilyHandle,
key: &[u8],
status: &mut BridgeStatus,
);
fn del_raw(
self: &TransactionBridge,
cf: &ColumnFamilyHandle,
key: &[u8],
status: &mut BridgeStatus,
);
fn del_range_raw(
self: &TransactionBridge,
cf: &ColumnFamilyHandle,
start_key: &[u8],
end_key: &[u8],
status: &mut BridgeStatus,
);
fn flush_raw(
self: &TransactionBridge,
cf: &ColumnFamilyHandle,
options: &FlushOptions,
status: &mut BridgeStatus,
);
fn compact_all_raw(
self: &TransactionBridge,
cf: &ColumnFamilyHandle,
status: &mut BridgeStatus,
);
fn iterator_txn(
self: &TransactionBridge,
cf: &ColumnFamilyHandle,
) -> UniquePtr<IteratorBridge>;
fn iterator_raw(
self: &TransactionBridge,
cf: &ColumnFamilyHandle,
) -> UniquePtr<IteratorBridge>;
// fn multiget_txn(self: &TransactionBridge, cf: &ColumnFamilyHandle,
// keys: &[&[u8]], statuses: &mut [BridgeStatus]) -> UniquePtr<CxxVector<PinnableSlice>>;
// fn multiget_raw(self: &TransactionBridge, cf: &ColumnFamilyHandle,
@ -164,109 +220,138 @@ mod ffi {
pub type ColumnFamilyHandle;
type TDBBridge;
fn begin_t_transaction(self: &TDBBridge,
w_ops: UniquePtr<WriteOptions>,
raw_w_ops: UniquePtr<WriteOptions>,
r_ops: UniquePtr<ReadOptions>,
raw_r_ops: UniquePtr<ReadOptions>,
txn_options: UniquePtr<TransactionOptions>) -> UniquePtr<TransactionBridge>;
fn begin_o_transaction(self: &TDBBridge,
w_ops: UniquePtr<WriteOptions>,
raw_w_ops: UniquePtr<WriteOptions>,
r_ops: UniquePtr<ReadOptions>,
raw_r_ops: UniquePtr<ReadOptions>,
txn_options: UniquePtr<OptimisticTransactionOptions>) -> UniquePtr<TransactionBridge>;
fn begin_t_transaction(
self: &TDBBridge,
w_ops: UniquePtr<WriteOptions>,
raw_w_ops: UniquePtr<WriteOptions>,
r_ops: UniquePtr<ReadOptions>,
raw_r_ops: UniquePtr<ReadOptions>,
txn_options: UniquePtr<TransactionOptions>,
) -> UniquePtr<TransactionBridge>;
fn begin_o_transaction(
self: &TDBBridge,
w_ops: UniquePtr<WriteOptions>,
raw_w_ops: UniquePtr<WriteOptions>,
r_ops: UniquePtr<ReadOptions>,
raw_r_ops: UniquePtr<ReadOptions>,
txn_options: UniquePtr<OptimisticTransactionOptions>,
) -> UniquePtr<TransactionBridge>;
fn get_cf_handle_raw(self: &TDBBridge, name: &CxxString) -> SharedPtr<ColumnFamilyHandle>;
fn get_default_cf_handle_raw(self: &TDBBridge) -> SharedPtr<ColumnFamilyHandle>;
fn create_column_family_raw(self: &TDBBridge, options: &Options, name: &CxxString, status: &mut BridgeStatus) -> SharedPtr<ColumnFamilyHandle>;
fn create_column_family_raw(
self: &TDBBridge,
options: &Options,
name: &CxxString,
status: &mut BridgeStatus,
) -> SharedPtr<ColumnFamilyHandle>;
fn drop_column_family_raw(self: &TDBBridge, name: &CxxString, status: &mut BridgeStatus);
fn get_column_family_names_raw(self: &TDBBridge) -> UniquePtr<CxxVector<CxxString>>;
fn open_tdb_raw(options: &Options,
txn_options: &TransactionDBOptions,
path: &CxxString,
status: &mut BridgeStatus) -> UniquePtr<TDBBridge>;
fn open_odb_raw(options: &Options,
txn_options: &OptimisticTransactionDBOptions,
path: &CxxString,
status: &mut BridgeStatus) -> UniquePtr<TDBBridge>;
fn open_tdb_raw(
options: &Options,
txn_options: &TransactionDBOptions,
path: &CxxString,
status: &mut BridgeStatus,
) -> UniquePtr<TDBBridge>;
fn open_odb_raw(
options: &Options,
txn_options: &OptimisticTransactionDBOptions,
path: &CxxString,
status: &mut BridgeStatus,
) -> UniquePtr<TDBBridge>;
}
}
pub use ffi::*;
use std::fmt::Formatter;
impl std::fmt::Display for StatusBridgeCode {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", match *self {
StatusBridgeCode::OK => "Ok",
StatusBridgeCode::LOCK_ERROR => "LockError",
StatusBridgeCode::EXISTING_ERROR => "ExistingError",
StatusBridgeCode::NOT_FOUND_ERROR => "NotFoundError",
_ => "Unknown"
})
write!(
f,
"{}",
match *self {
StatusBridgeCode::OK => "Ok",
StatusBridgeCode::LOCK_ERROR => "LockError",
StatusBridgeCode::EXISTING_ERROR => "ExistingError",
StatusBridgeCode::NOT_FOUND_ERROR => "NotFoundError",
_ => "Unknown",
}
)
}
}
impl std::fmt::Display for StatusCode {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", match *self {
StatusCode::kOk => "Ok",
StatusCode::kNotFound => "NotFound",
StatusCode::kCorruption => "Corruption",
StatusCode::kNotSupported => "NotSupported",
StatusCode::kInvalidArgument => "InvalidArgument",
StatusCode::kIOError => "IoError",
StatusCode::kMergeInProgress => "MergeInProgress",
StatusCode::kIncomplete => "Incomplete",
StatusCode::kShutdownInProgress => "ShutdownInProgress",
StatusCode::kTimedOut => "TimedOut",
StatusCode::kAborted => "Aborted",
StatusCode::kBusy => "Busy",
StatusCode::kExpired => "Expired",
StatusCode::kTryAgain => "TryAgain",
StatusCode::kCompactionTooLarge => "CompactionTooLarge",
StatusCode::kColumnFamilyDropped => "ColumnFamilyDropped",
StatusCode::kMaxCode => "MaxCode",
_ => "Unknown"
})
write!(
f,
"{}",
match *self {
StatusCode::kOk => "Ok",
StatusCode::kNotFound => "NotFound",
StatusCode::kCorruption => "Corruption",
StatusCode::kNotSupported => "NotSupported",
StatusCode::kInvalidArgument => "InvalidArgument",
StatusCode::kIOError => "IoError",
StatusCode::kMergeInProgress => "MergeInProgress",
StatusCode::kIncomplete => "Incomplete",
StatusCode::kShutdownInProgress => "ShutdownInProgress",
StatusCode::kTimedOut => "TimedOut",
StatusCode::kAborted => "Aborted",
StatusCode::kBusy => "Busy",
StatusCode::kExpired => "Expired",
StatusCode::kTryAgain => "TryAgain",
StatusCode::kCompactionTooLarge => "CompactionTooLarge",
StatusCode::kColumnFamilyDropped => "ColumnFamilyDropped",
StatusCode::kMaxCode => "MaxCode",
_ => "Unknown",
}
)
}
}
impl std::fmt::Display for StatusSubCode {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", match *self {
StatusSubCode::kNone => "None",
StatusSubCode::kMutexTimeout => "MutexTimeout",
StatusSubCode::kLockTimeout => "LockTimeout",
StatusSubCode::kLockLimit => "LockLimit",
StatusSubCode::kNoSpace => "NoSpace",
StatusSubCode::kDeadlock => "DeadLock",
StatusSubCode::kStaleFile => "StaleFile",
StatusSubCode::kMemoryLimit => "MemoryLimit",
StatusSubCode::kSpaceLimit => "SpaceLimit",
StatusSubCode::kPathNotFound => "PathNotFound",
StatusSubCode::KMergeOperandsInsufficientCapacity => "MergeOperandsInsufficientCapacity",
StatusSubCode::kManualCompactionPaused => "ManualCompactionPaused",
StatusSubCode::kOverwritten => "Overwritten",
StatusSubCode::kTxnNotPrepared => "TxnNotPrepared",
StatusSubCode::kIOFenced => "IoFenced",
StatusSubCode::kMaxSubCode => "MaxSubCode",
_ => "Unknown"
})
write!(
f,
"{}",
match *self {
StatusSubCode::kNone => "None",
StatusSubCode::kMutexTimeout => "MutexTimeout",
StatusSubCode::kLockTimeout => "LockTimeout",
StatusSubCode::kLockLimit => "LockLimit",
StatusSubCode::kNoSpace => "NoSpace",
StatusSubCode::kDeadlock => "DeadLock",
StatusSubCode::kStaleFile => "StaleFile",
StatusSubCode::kMemoryLimit => "MemoryLimit",
StatusSubCode::kSpaceLimit => "SpaceLimit",
StatusSubCode::kPathNotFound => "PathNotFound",
StatusSubCode::KMergeOperandsInsufficientCapacity =>
"MergeOperandsInsufficientCapacity",
StatusSubCode::kManualCompactionPaused => "ManualCompactionPaused",
StatusSubCode::kOverwritten => "Overwritten",
StatusSubCode::kTxnNotPrepared => "TxnNotPrepared",
StatusSubCode::kIOFenced => "IoFenced",
StatusSubCode::kMaxSubCode => "MaxSubCode",
_ => "Unknown",
}
)
}
}
impl std::fmt::Display for StatusSeverity {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", match *self {
StatusSeverity::kNoError => "NoError",
StatusSeverity::kSoftError => "SoftError",
StatusSeverity::kHardError => "HardError",
StatusSeverity::kFatalError => "FatalError",
StatusSeverity::kUnrecoverableError => "UnrecoverableError",
StatusSeverity::kMaxSeverity => "MaxSeverity",
_ => "Unknown"
})
write!(
f,
"{}",
match *self {
StatusSeverity::kNoError => "NoError",
StatusSeverity::kSoftError => "SoftError",
StatusSeverity::kHardError => "HardError",
StatusSeverity::kFatalError => "FatalError",
StatusSeverity::kUnrecoverableError => "UnrecoverableError",
StatusSeverity::kMaxSeverity => "MaxSeverity",
_ => "Unknown",
}
)
}
}

@ -2,25 +2,28 @@ mod bridge;
use bridge::*;
use std::fmt::{Display, Formatter};
use std::fmt::Debug;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use cxx::{let_cxx_string};
pub use cxx::{UniquePtr, SharedPtr};
pub use bridge::BridgeStatus;
pub use bridge::ColumnFamilyHandle;
pub use bridge::PinnableSlice;
pub use bridge::Slice;
pub use bridge::StatusBridgeCode;
pub use bridge::StatusCode;
pub use bridge::StatusSubCode;
pub use bridge::StatusSeverity;
pub use bridge::Slice;
pub use bridge::PinnableSlice;
pub use bridge::ColumnFamilyHandle;
pub use bridge::StatusSubCode;
use cxx::let_cxx_string;
pub use cxx::{SharedPtr, UniquePtr};
use std::fmt::Debug;
use std::fmt::{Display, Formatter};
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
impl std::fmt::Display for BridgeStatus {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "BridgeStatus({}, {}, {}, {})", self.code, self.subcode, self.severity, self.bridge_code)
write!(
f,
"BridgeStatus({}, {}, {}, {})",
self.code, self.subcode, self.severity, self.bridge_code
)
}
}
@ -31,7 +34,11 @@ pub struct BridgeError {
impl Display for BridgeError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "BridgeError({}, {}, {}, {})", self.status.code, self.status.subcode, self.status.severity, self.status.bridge_code)
write!(
f,
"BridgeError({}, {}, {}, {})",
self.status.code, self.status.subcode, self.status.severity, self.status.bridge_code
)
}
}
@ -55,7 +62,7 @@ impl BridgeStatus {
let err: Option<BridgeError> = self.into();
match err {
Some(e) => Err(e),
None => Ok(data)
None => Ok(data),
}
}
}
@ -63,9 +70,10 @@ impl BridgeStatus {
impl From<BridgeStatus> for Option<BridgeError> {
#[inline]
fn from(s: BridgeStatus) -> Self {
if s.severity == StatusSeverity::kNoError &&
s.bridge_code == StatusBridgeCode::OK &&
s.code == StatusCode::kOk {
if s.severity == StatusSeverity::kNoError
&& s.bridge_code == StatusBridgeCode::OK
&& s.code == StatusCode::kOk
{
None
} else {
Some(BridgeError { status: s })
@ -85,12 +93,8 @@ impl AsRef<[u8]> for SlicePtr {
#[inline]
fn as_ref(&self) -> &[u8] {
match self {
SlicePtr::Plain(s) => {
convert_slice_back(s)
}
SlicePtr::Pinnable(s) => {
convert_pinnable_slice_back(s)
}
SlicePtr::Plain(s) => convert_slice_back(s),
SlicePtr::Pinnable(s) => convert_pinnable_slice_back(s),
}
}
}
@ -183,7 +187,6 @@ impl OptionsPtr {
}
}
pub struct ReadOptionsPtr(UniquePtr<ReadOptions>);
impl Deref for ReadOptionsPtr {
@ -202,7 +205,6 @@ impl DerefMut for ReadOptionsPtr {
}
}
impl ReadOptionsPtr {
#[inline]
pub fn default() -> Self {
@ -457,8 +459,10 @@ impl<'a> IteratorPtr<'a> {
/// `next()` must not be called on the iterator when the returned value is still used
pub unsafe fn pair(&self) -> Option<(SlicePtr, SlicePtr)> {
if self.is_valid() {
Some((SlicePtr::Plain(IteratorBridge::key_raw(self)),
SlicePtr::Plain(IteratorBridge::value_raw(self))))
Some((
SlicePtr::Plain(IteratorBridge::key_raw(self)),
SlicePtr::Plain(IteratorBridge::value_raw(self)),
))
} else {
None
}
@ -479,7 +483,6 @@ impl Deref for TransactionPtr {
}
}
impl TransactionPtr {
#[inline]
pub fn null() -> Self {
@ -518,7 +521,12 @@ impl TransactionPtr {
status.check_err(())
}
#[inline]
pub fn get(&self, transact: bool, cf: &ColumnFamilyHandle, key: impl AsRef<[u8]>) -> Result<Option<SlicePtr>> {
pub fn get(
&self,
transact: bool,
cf: &ColumnFamilyHandle,
key: impl AsRef<[u8]>,
) -> Result<Option<SlicePtr>> {
let mut status = BridgeStatus::default();
let res = if transact {
let ret = self.get_txn(cf, key.as_ref(), &mut status);
@ -529,18 +537,27 @@ impl TransactionPtr {
};
match res {
Ok(r) => Ok(Some(r)),
Err(e) if e.status.code == StatusCode::kNotFound => Ok(None),
res => res.map(|_| None)
Err(e) if e.status.code == StatusCode::kNotFound => Ok(None),
res => res.map(|_| None),
}
}
#[inline]
pub fn get_for_update(&self, cf: &ColumnFamilyHandle, key: impl AsRef<[u8]>) -> Result<SlicePtr> {
pub fn get_for_update(
&self,
cf: &ColumnFamilyHandle,
key: impl AsRef<[u8]>,
) -> Result<SlicePtr> {
let mut status = BridgeStatus::default();
let ret = self.get_for_update_txn(cf, key.as_ref(), &mut status);
status.check_err(SlicePtr::Pinnable(ret))
}
#[inline]
pub fn del(&self, transact: bool, cf: &ColumnFamilyHandle, key: impl AsRef<[u8]>) -> Result<()> {
pub fn del(
&self,
transact: bool,
cf: &ColumnFamilyHandle,
key: impl AsRef<[u8]>,
) -> Result<()> {
let mut status = BridgeStatus::default();
if transact {
let ret = self.del_txn(cf, key.as_ref(), &mut status);
@ -551,7 +568,12 @@ impl TransactionPtr {
}
}
#[inline]
pub fn del_range(&self, cf: &ColumnFamilyHandle, start_key: impl AsRef<[u8]>, end_key: impl AsRef<[u8]>) -> Result<()> {
pub fn del_range(
&self,
cf: &ColumnFamilyHandle,
start_key: impl AsRef<[u8]>,
end_key: impl AsRef<[u8]>,
) -> Result<()> {
let mut status = BridgeStatus::default();
let ret = self.del_range_raw(cf, start_key.as_ref(), end_key.as_ref(), &mut status);
status.check_err(ret)
@ -569,7 +591,13 @@ impl TransactionPtr {
status.check_err(())
}
#[inline]
pub fn put(&self, transact: bool, cf: &ColumnFamilyHandle, key: impl AsRef<[u8]>, val: impl AsRef<[u8]>) -> Result<()> {
pub fn put(
&self,
transact: bool,
cf: &ColumnFamilyHandle,
key: impl AsRef<[u8]>,
val: impl AsRef<[u8]>,
) -> Result<()> {
let mut status = BridgeStatus::default();
if transact {
let ret = self.put_txn(cf, key.as_ref(), val.as_ref(), &mut status);
@ -584,12 +612,12 @@ impl TransactionPtr {
if transact {
IteratorPtr {
inner: self.iterator_txn(cf),
txn: PhantomData
txn: PhantomData,
}
} else {
IteratorPtr {
inner: self.iterator_raw(cf),
txn: PhantomData
txn: PhantomData,
}
}
}
@ -621,43 +649,44 @@ pub enum TDBOptions {
}
impl DBPtr {
pub fn open(options: &OptionsPtr, t_options: &TDBOptions, path: impl AsRef<str>) -> Result<Self> {
pub fn open(
options: &OptionsPtr,
t_options: &TDBOptions,
path: impl AsRef<str>,
) -> Result<Self> {
let_cxx_string!(cname = path.as_ref());
let mut status = BridgeStatus::default();
let ret = match t_options {
TDBOptions::Pessimistic(o) => open_tdb_raw(options, o, &cname, &mut status),
TDBOptions::Optimistic(o) => open_odb_raw(options, o, &cname, &mut status)
TDBOptions::Optimistic(o) => open_odb_raw(options, o, &cname, &mut status),
};
status.check_err(Self(ret))
}
#[inline]
pub fn make_transaction(&self,
options: TransactOptions,
read_ops: ReadOptionsPtr,
raw_read_ops: ReadOptionsPtr,
write_ops: WriteOptionsPtr,
raw_write_ops: WriteOptionsPtr,
pub fn make_transaction(
&self,
options: TransactOptions,
read_ops: ReadOptionsPtr,
raw_read_ops: ReadOptionsPtr,
write_ops: WriteOptionsPtr,
raw_write_ops: WriteOptionsPtr,
) -> TransactionPtr {
TransactionPtr(match options {
TransactOptions::Optimistic(o) => {
self.begin_o_transaction(
write_ops.0,
raw_write_ops.0,
read_ops.0,
raw_read_ops.0,
o.0,
)
}
TransactOptions::Pessimistic(o) => {
self.begin_t_transaction(
write_ops.0,
raw_write_ops.0,
read_ops.0,
raw_read_ops.0,
o.0,
)
}
TransactOptions::Optimistic(o) => self.begin_o_transaction(
write_ops.0,
raw_write_ops.0,
read_ops.0,
raw_read_ops.0,
o.0,
),
TransactOptions::Pessimistic(o) => self.begin_t_transaction(
write_ops.0,
raw_write_ops.0,
read_ops.0,
raw_read_ops.0,
o.0,
),
})
}
#[inline]
@ -675,7 +704,11 @@ impl DBPtr {
self.get_default_cf_handle_raw()
}
#[inline]
pub fn create_cf(&self, options: &OptionsPtr, name: impl AsRef<str>) -> Result<SharedPtr<ColumnFamilyHandle>> {
pub fn create_cf(
&self,
options: &OptionsPtr,
name: impl AsRef<str>,
) -> Result<SharedPtr<ColumnFamilyHandle>> {
let_cxx_string!(name = name.as_ref());
let mut status = BridgeStatus::default();
let ret = self.create_column_family_raw(options, &name, &mut status);
@ -690,7 +723,10 @@ impl DBPtr {
}
#[inline]
pub fn cf_names(&self) -> Vec<String> {
self.get_column_family_names_raw().iter().map(|v| v.to_string_lossy().to_string()).collect()
self.get_column_family_names_raw()
.iter()
.map(|v| v.to_string_lossy().to_string())
.collect()
}
pub fn drop_non_default_cfs(&self) {
for name in self.cf_names() {
@ -699,4 +735,4 @@ impl DBPtr {
}
}
}
}
}

@ -1,10 +1,10 @@
pub mod cnf_transform;
pub mod ddl;
pub mod engine;
pub mod env;
pub mod eval;
pub mod query;
pub mod iterator;
pub mod mutation;
pub mod table;
pub mod plan;
pub mod ddl;
pub mod env;
pub mod cnf_transform;
pub mod iterator;
pub mod query;
pub mod table;

@ -1,7 +1,7 @@
use std::collections::{BTreeSet};
use crate::db::table::TableId;
use crate::relation::value;
use crate::relation::value::Value;
use std::collections::BTreeSet;
pub fn extract_tables(val: &Value) -> BTreeSet<TableId> {
let mut coll = BTreeSet::new();
@ -11,12 +11,12 @@ pub fn extract_tables(val: &Value) -> BTreeSet<TableId> {
fn do_extract_tables(val: &Value, coll: &mut BTreeSet<TableId>) {
match val {
Value::Null |
Value::Bool(_) |
Value::Int(_) |
Value::Float(_) |
Value::Uuid(_) |
Value::Text(_) => {}
Value::Null
| Value::Bool(_)
| Value::Int(_)
| Value::Float(_)
| Value::Uuid(_)
| Value::Text(_) => {}
Value::List(l) => {
for v in l {
do_extract_tables(v, coll);
@ -59,7 +59,7 @@ fn do_cnf_transform(val: Value) -> (bool, Value) {
value::OP_OR => cnf_transform_or(args),
value::OP_AND => cnf_transform_and(args),
value::OP_NEGATE => cnf_transform_negate(args.into_iter().next().unwrap()),
_ => (false, Value::Apply(op, args))
_ => (false, Value::Apply(op, args)),
}
} else {
(false, val)
@ -87,18 +87,21 @@ fn cnf_transform_or(args: Vec<Value>) -> (bool, Value) {
collected.push(Value::Apply(op, args))
}
}
_ => collected.push(Value::Apply(op, args))
_ => collected.push(Value::Apply(op, args)),
}
} else {
collected.push(v);
}
}
if let Some(to_and) = to_and {
let args = to_and.into_iter().map(|v| {
let mut to_or = collected.clone();
to_or.push(v);
Value::Apply(value::OP_OR.into(), to_or)
}).collect();
let args = to_and
.into_iter()
.map(|v| {
let mut to_or = collected.clone();
to_or.push(v);
Value::Apply(value::OP_OR.into(), to_or)
})
.collect();
(true, Value::Apply(value::OP_AND.into(), args))
} else if collected.is_empty() {
(true, true.into())
@ -151,35 +154,66 @@ fn cnf_transform_negate(arg: Value) -> (bool, Value) {
new_args.push(v);
}
match op.as_ref() {
value::OP_OR => (true, Value::Apply(value::OP_AND.into(), new_args.into_iter().map(|v| {
let (_, v) = do_cnf_transform(v);
Value::Apply(value::OP_NEGATE.into(), vec![v])
}).collect())),
value::OP_AND => (true, Value::Apply(value::OP_OR.into(), new_args.into_iter().map(|v| {
let (_, v) = do_cnf_transform(v);
Value::Apply(value::OP_NEGATE.into(), vec![v])
}).collect())),
value::OP_NEGATE => {
(true, new_args.into_iter().next().unwrap())
}
_ => (changed, Value::Apply(value::OP_NEGATE.into(), vec![Value::Apply(op, new_args)]))
value::OP_OR => (
true,
Value::Apply(
value::OP_AND.into(),
new_args
.into_iter()
.map(|v| {
let (_, v) = do_cnf_transform(v);
Value::Apply(value::OP_NEGATE.into(), vec![v])
})
.collect(),
),
),
value::OP_AND => (
true,
Value::Apply(
value::OP_OR.into(),
new_args
.into_iter()
.map(|v| {
let (_, v) = do_cnf_transform(v);
Value::Apply(value::OP_NEGATE.into(), vec![v])
})
.collect(),
),
),
value::OP_NEGATE => (true, new_args.into_iter().next().unwrap()),
_ => (
changed,
Value::Apply(value::OP_NEGATE.into(), vec![Value::Apply(op, new_args)]),
),
}
} else {
(false, Value::Apply(value::OP_NEGATE.into(), vec![arg]))
}
}
#[cfg(test)]
mod tests {
use crate::db::cnf_transform::cnf_transform;
use crate::relation::value::Value;
use crate::error::Result;
use crate::relation::value::Value;
#[test]
fn test_cnf() -> Result<()> {
for s in ["a", "!a", "!!a", "!!!a", "!(b || c)", "a && (b && c)", "a && b || c", "a || b && c && d",
"a && (b || d && e)", "a && !b || c && !!d || !!!e && f", "(a || !b || !c) && (!d || e || f)", "(a || b) && c", "a || b"] {
for s in [
"a",
"!a",
"!!a",
"!!!a",
"!(b || c)",
"a && (b && c)",
"a && b || c",
"a || b && c && d",
"a && (b || d && e)",
"a && !b || c && !!d || !!!e && f",
"(a || !b || !c) && (!d || e || f)",
"(a || b) && c",
"a || b",
] {
let v = Value::parse_str(s)?;
println!("{}", v);
let v2 = cnf_transform(v);
@ -188,4 +222,4 @@ mod tests {
Ok(())
}
}
}

@ -1,76 +1,109 @@
use std::collections::HashSet;
use pest::iterators::{Pair, Pairs};
use crate::db::engine::Session;
use crate::db::table::TableId;
use crate::relation::tuple::{OwnTuple, SliceTuple, Tuple};
use crate::relation::typing::Typing;
use crate::parser::Rule;
use crate::error::{CozoError, Result};
use crate::parser::text_identifier::build_name_in_def;
use crate::parser::Rule;
use crate::relation::data::DataKind;
use crate::relation::tuple::{OwnTuple, SliceTuple, Tuple};
use crate::relation::typing::Typing;
use crate::relation::value::Value;
use pest::iterators::{Pair, Pairs};
use std::collections::HashSet;
const STORAGE_ID_START: i64 = 10000;
impl<'s> Session<'s> {
pub fn encode_definable_key(&self, name: &str, in_root: bool) -> OwnTuple {
let depth_code = if in_root { 0 } else { self.get_stack_depth() as i64 };
let depth_code = if in_root {
0
} else {
self.get_stack_depth() as i64
};
let mut tuple = Tuple::with_null_prefix();
tuple.push_str(name);
tuple.push_int(depth_code);
tuple
}
fn parse_cols(&self, pair: Pair<Rule>) -> Result<(Typing, Typing)> {
let col_res = pair.into_inner().map(|p| {
let mut ps = p.into_inner();
let mut name_ps = ps.next().unwrap().into_inner();
let is_key;
let mut name_p = name_ps.next().unwrap();
match name_p.as_rule() {
Rule::key_marker => {
is_key = true;
name_p = name_ps.next().unwrap();
let col_res = pair
.into_inner()
.map(|p| {
let mut ps = p.into_inner();
let mut name_ps = ps.next().unwrap().into_inner();
let is_key;
let mut name_p = name_ps.next().unwrap();
match name_p.as_rule() {
Rule::key_marker => {
is_key = true;
name_p = name_ps.next().unwrap();
}
_ => is_key = false,
}
_ => { is_key = false }
}
let name = build_name_in_def(name_p, true)?;
let type_p = Typing::from_pair(ps.next().unwrap(), Some(self))?;
Ok((is_key, name, type_p))
}).collect::<Result<Vec<_>>>()?;
let name = build_name_in_def(name_p, true)?;
let type_p = Typing::from_pair(ps.next().unwrap(), Some(self))?;
Ok((is_key, name, type_p))
})
.collect::<Result<Vec<_>>>()?;
let all_names = col_res.iter().map(|(_, n, _)| n).collect::<HashSet<_>>();
if all_names.len() != col_res.len() {
return Err(CozoError::DuplicateNames(col_res.iter().map(|(_, n, _)| n.to_string()).collect::<Vec<_>>()));
return Err(CozoError::DuplicateNames(
col_res
.iter()
.map(|(_, n, _)| n.to_string())
.collect::<Vec<_>>(),
));
}
let (keys, cols): (Vec<_>, Vec<_>) = col_res.iter().partition(|(is_key, _, _)| *is_key);
let keys_typing = Typing::NamedTuple(keys.iter().map(|(_, n, t)| (n.to_string(), t.clone())).collect());
let vals_typing = Typing::NamedTuple(cols.iter().map(|(_, n, t)| (n.to_string(), t.clone())).collect());
let keys_typing = Typing::NamedTuple(
keys.iter()
.map(|(_, n, t)| (n.to_string(), t.clone()))
.collect(),
);
let vals_typing = Typing::NamedTuple(
cols.iter()
.map(|(_, n, t)| (n.to_string(), t.clone()))
.collect(),
);
Ok((keys_typing, vals_typing))
}
fn parse_definition(&self, pair: Pair<Rule>, in_root: bool) -> Result<(bool, (String, OwnTuple, Vec<OwnTuple>))> {
#[allow(clippy::type_complexity)]
fn parse_definition(
&self,
pair: Pair<Rule>,
in_root: bool,
) -> Result<(bool, (String, OwnTuple, Vec<OwnTuple>))> {
Ok(match pair.as_rule() {
Rule::node_def => (true, self.parse_node_def(pair.into_inner(), in_root)?),
Rule::edge_def => (true, self.parse_edge_def(pair.into_inner(), in_root)?),
Rule::associate_def => (true, self.parse_assoc_def(pair.into_inner(), in_root)?),
Rule::index_def => todo!(),
Rule::type_def => (false, self.parse_type_def(pair.into_inner(), in_root)?),
_ => unreachable!()
_ => unreachable!(),
})
}
fn parse_assoc_def(&self, mut pairs: Pairs<Rule>, in_root: bool) -> Result<(String, OwnTuple, Vec<OwnTuple>)> {
fn parse_assoc_def(
&self,
mut pairs: Pairs<Rule>,
in_root: bool,
) -> Result<(String, OwnTuple, Vec<OwnTuple>)> {
let name = build_name_in_def(pairs.next().unwrap(), true)?;
let src_name = build_name_in_def(pairs.next().unwrap(), true)?;
let src_tbl = match self.resolve(&src_name)? {
Some(res) => res,
None => return Err(CozoError::UndefinedType(src_name))
None => return Err(CozoError::UndefinedType(src_name)),
};
let (_kind, src_global, src_id) = Self::extract_table_id(src_tbl)?;
if in_root && !src_global {
return Err(CozoError::LogicError("Cannot have global edge with local nodes".to_string()));
return Err(CozoError::LogicError(
"Cannot have global edge with local nodes".to_string(),
));
}
let (keys_typing, vals_typing) = self.parse_cols(pairs.next().unwrap())?;
if keys_typing.to_string() != "{}" {
return Err(CozoError::LogicError("Cannot have keys in assoc".to_string()));
return Err(CozoError::LogicError(
"Cannot have keys in assoc".to_string(),
));
}
let mut tuple = Tuple::with_data_prefix(DataKind::Assoc);
@ -81,20 +114,32 @@ impl<'s> Session<'s> {
let mut for_src = Tuple::with_prefix(0);
for_src.push_null();
for_src.push_str(&src_name);
for_src.push_int(if in_root { 0 } else { self.get_stack_depth() as i64 });
for_src.push_int(if in_root {
0
} else {
self.get_stack_depth() as i64
});
for_src.push_int(DataKind::Assoc as i64);
for_src.push_str(&name);
let mut for_src_i = Tuple::with_prefix(0);
for_src_i.push_null();
for_src_i.push_int(if in_root { 0 } else { self.get_stack_depth() as i64 });
for_src_i.push_int(if in_root {
0
} else {
self.get_stack_depth() as i64
});
for_src_i.push_str(&src_name);
for_src_i.push_int(DataKind::Assoc as i64);
for_src_i.push_str(&name);
Ok((name, tuple, vec![for_src, for_src_i]))
}
fn parse_type_def(&self, mut pairs: Pairs<Rule>, _in_root: bool) -> Result<(String, OwnTuple, Vec<OwnTuple>)> {
fn parse_type_def(
&self,
mut pairs: Pairs<Rule>,
_in_root: bool,
) -> Result<(String, OwnTuple, Vec<OwnTuple>)> {
let name = build_name_in_def(pairs.next().unwrap(), true)?;
let typ = Typing::from_pair(pairs.next().unwrap(), Some(self))?;
let mut data = Tuple::with_data_prefix(DataKind::Type);
@ -102,15 +147,21 @@ impl<'s> Session<'s> {
Ok((name, data, vec![]))
}
fn parse_edge_def(&self, mut pairs: Pairs<Rule>, in_root: bool) -> Result<(String, OwnTuple, Vec<OwnTuple>)> {
fn parse_edge_def(
&self,
mut pairs: Pairs<Rule>,
in_root: bool,
) -> Result<(String, OwnTuple, Vec<OwnTuple>)> {
let src_name = build_name_in_def(pairs.next().unwrap(), true)?;
let src_tbl = match self.resolve(&src_name)? {
Some(res) => res,
None => return Err(CozoError::UndefinedType(src_name))
None => return Err(CozoError::UndefinedType(src_name)),
};
let (kind, src_global, src_id) = Self::extract_table_id(src_tbl)?;
if in_root && !src_global {
return Err(CozoError::LogicError("Cannot have global edge with local nodes".to_string()));
return Err(CozoError::LogicError(
"Cannot have global edge with local nodes".to_string(),
));
}
if kind != DataKind::Node {
return Err(CozoError::UnexpectedDataKind(kind));
@ -119,18 +170,20 @@ impl<'s> Session<'s> {
let dst_name = build_name_in_def(pairs.next().unwrap(), true)?;
let dst_tbl = match self.resolve(&dst_name)? {
Some(res) => res,
None => return Err(CozoError::UndefinedType(dst_name))
None => return Err(CozoError::UndefinedType(dst_name)),
};
let (kind, dst_global, dst_id) = Self::extract_table_id(dst_tbl)?;
if in_root && !dst_global {
return Err(CozoError::LogicError("Cannot have global edge with local nodes".to_string()));
return Err(CozoError::LogicError(
"Cannot have global edge with local nodes".to_string(),
));
}
if kind != DataKind::Node {
return Err(CozoError::UnexpectedDataKind(kind));
}
let (keys_typing, vals_typing) = match pairs.next() {
Some(p) => self.parse_cols(p)?,
None => (Typing::NamedTuple(vec![]), Typing::NamedTuple(vec![]))
None => (Typing::NamedTuple(vec![]), Typing::NamedTuple(vec![])),
};
let mut tuple = Tuple::with_data_prefix(DataKind::Edge);
@ -148,7 +201,11 @@ impl<'s> Session<'s> {
let mut for_src = Tuple::with_prefix(0);
for_src.push_null();
for_src.push_str(&src_name);
for_src.push_int(if in_root { 0 } else { self.get_stack_depth() as i64 });
for_src.push_int(if in_root {
0
} else {
self.get_stack_depth() as i64
});
for_src.push_int(DataKind::Edge as i64);
for_src.push_str(&name);
@ -156,7 +213,11 @@ impl<'s> Session<'s> {
let mut for_src_i = Tuple::with_prefix(0);
for_src_i.push_null();
for_src_i.push_int(if in_root { 0 } else { self.get_stack_depth() as i64 });
for_src_i.push_int(if in_root {
0
} else {
self.get_stack_depth() as i64
});
for_src_i.push_str(&src_name);
for_src_i.push_int(DataKind::Edge as i64);
for_src_i.push_str(&name);
@ -167,7 +228,11 @@ impl<'s> Session<'s> {
let mut for_dst = Tuple::with_prefix(0);
for_dst.push_null();
for_dst.push_str(&dst_name);
for_dst.push_int(if in_root { 0 } else { self.get_stack_depth() as i64 });
for_dst.push_int(if in_root {
0
} else {
self.get_stack_depth() as i64
});
for_dst.push_int(DataKind::Edge as i64);
for_dst.push_str(&name);
@ -175,7 +240,11 @@ impl<'s> Session<'s> {
let mut for_dst_i = Tuple::with_prefix(0);
for_dst_i.push_null();
for_dst_i.push_int(if in_root { 0 } else { self.get_stack_depth() as i64 });
for_dst_i.push_int(if in_root {
0
} else {
self.get_stack_depth() as i64
});
for_dst_i.push_str(&dst_name);
for_dst_i.push_int(DataKind::Edge as i64);
for_dst_i.push_str(&name);
@ -189,14 +258,20 @@ impl<'s> Session<'s> {
fn extract_table_id<T: AsRef<[u8]>>(src_tbl: Tuple<T>) -> Result<(DataKind, bool, i64)> {
let kind = src_tbl.data_kind()?;
match kind {
DataKind::Data | DataKind::Val | DataKind::Type => return Err(CozoError::UnexpectedDataKind(kind)),
DataKind::Data | DataKind::Val | DataKind::Type => {
return Err(CozoError::UnexpectedDataKind(kind))
}
_ => {}
};
let is_global = src_tbl.get_bool(0).expect("Data corrupt");
let table_id = src_tbl.get_int(1).expect("Data corrupt");
Ok((kind, is_global, table_id))
}
fn parse_node_def(&self, mut pairs: Pairs<Rule>, _in_root: bool) -> Result<(String, OwnTuple, Vec<OwnTuple>)> {
fn parse_node_def(
&self,
mut pairs: Pairs<Rule>,
_in_root: bool,
) -> Result<(String, OwnTuple, Vec<OwnTuple>)> {
let name = build_name_in_def(pairs.next().unwrap(), true)?;
let col_pair = pairs.next().unwrap();
let (keys_typing, vals_typing) = self.parse_cols(col_pair)?;
@ -211,16 +286,14 @@ impl<'s> Session<'s> {
let in_root = match pair.as_rule() {
Rule::global_def => true,
Rule::local_def => false,
r => panic!("Encountered definition with rule {:?}", r)
r => panic!("Encountered definition with rule {:?}", r),
};
let (need_id, (name, mut tuple, assoc_defs)) = self.parse_definition(
pair.into_inner().next().unwrap(), in_root,
)?;
let (need_id, (name, mut tuple, assoc_defs)) =
self.parse_definition(pair.into_inner().next().unwrap(), in_root)?;
if need_id {
let id = self.get_next_storage_id(in_root)?;
tuple = tuple.insert_values_at(0, &[in_root.into(),
id.into()]);
tuple = tuple.insert_values_at(0, &[in_root.into(), id.into()]);
let mut id_key = Tuple::with_null_prefix();
id_key.push_bool(true);
id_key.push_int(id);
@ -232,7 +305,6 @@ impl<'s> Session<'s> {
self.define_data(&name, tuple, in_root)
}
fn get_next_storage_id(&self, in_root: bool) -> Result<i64> {
let mut key_entry = Tuple::with_null_prefix();
key_entry.push_null();
@ -247,7 +319,9 @@ impl<'s> Session<'s> {
} else {
panic!("Unexpected value in storage id");
}
} else { STORAGE_ID_START };
} else {
STORAGE_ID_START
};
let mut new_data = Tuple::with_null_prefix();
new_data.push_int(u + 1);
if in_root {
@ -290,7 +364,9 @@ impl<'s> Session<'s> {
if !cur.starts_with(&prefix) {
break;
}
let name = cur.get_text(4).ok_or_else(|| CozoError::LogicError("Bad data".to_string()))?;
let name = cur
.get_text(4)
.ok_or_else(|| CozoError::LogicError("Bad data".to_string()))?;
if let Some(data) = self.resolve(&name)? {
if data.data_kind()? == DataKind::Assoc {
assocs.push((name.to_string(), data));
@ -306,7 +382,9 @@ impl<'s> Session<'s> {
if !cur.starts_with(&prefix) {
break;
}
let name = cur.get_text(4).ok_or_else(|| CozoError::LogicError("Bad data".to_string()))?;
let name = cur
.get_text(4)
.ok_or_else(|| CozoError::LogicError("Bad data".to_string()))?;
if let Some(data) = self.resolve(&name)? {
if data.data_kind()? == DataKind::Assoc {
assocs.push((name.to_string(), data));
@ -340,4 +418,4 @@ impl<'s> Session<'s> {
Ok(())
}
}
}

@ -1,16 +1,15 @@
// single engine per db storage
// will be shared among threads
use crate::error::CozoError::{Poisoned, SessionErr};
use crate::error::{CozoError, Result};
use crate::relation::tuple::{Tuple, PREFIX_LEN};
use cozorocks::*;
use rand::Rng;
use std::sync::{Arc, Mutex, RwLock};
use std::time::{SystemTime, UNIX_EPOCH};
use uuid::Uuid;
use uuid::v1::{Context, Timestamp};
use rand::Rng;
use crate::error::{CozoError, Result};
use crate::error::CozoError::{Poisoned, SessionErr};
use crate::relation::tuple::{PREFIX_LEN, Tuple};
use uuid::Uuid;
pub struct EngineOptions {
cmp: RustComparatorPtr,
@ -37,10 +36,7 @@ impl Engine {
} else {
TDBOptions::Pessimistic(PTxnDBOptionsPtr::default())
};
let cmp = RustComparatorPtr::new(
"cozo_cmp_v1",
crate::relation::key_order::compare,
false);
let cmp = RustComparatorPtr::new("cozo_cmp_v1", crate::relation::key_order::compare, false);
let mut options = OptionsPtr::default();
options
.set_comparator(&cmp)
@ -71,13 +67,17 @@ impl Engine {
pub fn session(&self) -> Result<Session> {
// find a handle if there is one available
// otherwise create a new one
let mut guard = self.session_handles.lock().map_err(|_| CozoError::Poisoned)?;
let old_handle = guard.iter().find(|v| {
match v.read() {
let mut guard = self
.session_handles
.lock()
.map_err(|_| CozoError::Poisoned)?;
let old_handle = guard
.iter()
.find(|v| match v.read() {
Ok(content) => content.status == SessionStatus::Completed,
Err(_) => false
}
}).cloned();
Err(_) => false,
})
.cloned();
let handle = match old_handle {
None => {
let now = SystemTime::now();
@ -88,7 +88,17 @@ impl Engine {
since_epoch.subsec_nanos(),
);
let mut rng = rand::thread_rng();
let id = Uuid::new_v1(ts, &[rng.gen(), rng.gen(), rng.gen(), rng.gen(), rng.gen(), rng.gen()])?;
let id = Uuid::new_v1(
ts,
&[
rng.gen(),
rng.gen(),
rng.gen(),
rng.gen(),
rng.gen(),
rng.gen(),
],
)?;
let cf_ident = id.to_string();
self.db.create_cf(&self.options_store.options, &cf_ident)?;
@ -99,7 +109,7 @@ impl Engine {
guard.push(ret.clone());
ret
}
Some(h) => h
Some(h) => h,
};
let mut sess = Session {
@ -133,12 +143,14 @@ impl<'a> Session<'a> {
fn start_with_total_seek(&mut self, total_seek: bool) -> Result<()> {
self.perm_cf = self.engine.db.default_cf();
assert!(!self.perm_cf.is_null());
self.temp_cf = self.engine.db.get_cf(&self.handle.read().map_err(|_| Poisoned)?.cf_ident).ok_or(SessionErr)?;
self.temp_cf = self
.engine
.db
.get_cf(&self.handle.read().map_err(|_| Poisoned)?.cf_ident)
.ok_or(SessionErr)?;
assert!(!self.temp_cf.is_null());
let t_options = match self.engine.options_store.t_options {
TDBOptions::Pessimistic(_) => {
TransactOptions::Pessimistic(PTxnOptionsPtr::default())
}
TDBOptions::Pessimistic(_) => TransactOptions::Pessimistic(PTxnOptionsPtr::default()),
TDBOptions::Optimistic(_) => {
TransactOptions::Optimistic(OTxnOptionsPtr::new(&self.engine.options_store.cmp))
}
@ -167,7 +179,10 @@ impl<'a> Session<'a> {
let w_opts = WriteOptionsPtr::default();
let mut wx_opts = WriteOptionsPtr::default();
wx_opts.set_disable_wal(true);
self.txn = self.engine.db.make_transaction(t_options, r_opts, rx_opts, w_opts, wx_opts);
self.txn = self
.engine
.db
.make_transaction(t_options, r_opts, rx_opts, w_opts, wx_opts);
if self.txn.is_null() {
panic!("Starting session failed as opening transaction failed");
}
@ -183,7 +198,8 @@ impl<'a> Session<'a> {
Ok(())
}
pub fn finish_work(&mut self) -> Result<()> {
self.txn.del_range(&self.temp_cf, Tuple::with_null_prefix(), Tuple::max_tuple())?;
self.txn
.del_range(&self.temp_cf, Tuple::with_null_prefix(), Tuple::max_tuple())?;
self.txn.compact_all(&self.temp_cf)?;
// let mut options = FlushOptionsPtr::default();
// options.set_allow_write_stall(true).set_flush_wait(true);
@ -220,9 +236,9 @@ pub enum SessionStatus {
#[cfg(test)]
mod tests {
use std::{fs, thread};
use crate::relation::tuple::Tuple;
use super::*;
use crate::relation::tuple::Tuple;
use std::{fs, thread};
#[test]
fn push_get() {
@ -328,18 +344,23 @@ mod tests {
}))
}
for t in thread_handles {
t.join().unwrap();
}
println!("All OK");
{
let handles = engine2.session_handles.lock().unwrap();
println!("got handles {:#?}", handles.iter().map(|h| h.read().unwrap().cf_ident.to_string()).collect::<Vec<_>>());
println!(
"got handles {:#?}",
handles
.iter()
.map(|h| h.read().unwrap().cf_ident.to_string())
.collect::<Vec<_>>()
);
}
}
let _ = fs::remove_dir_all(p1);
let _ = fs::remove_dir_all(p2);
let _ = fs::remove_dir_all(p3);
}
}
}

@ -1,8 +1,8 @@
use crate::db::engine::Session;
use crate::relation::value::Value;
use crate::error::{CozoError, Result};
use crate::relation::data::{DataKind, EMPTY_DATA};
use crate::relation::tuple::{OwnTuple, SliceTuple, Tuple};
use crate::relation::value::Value;
/// # layouts for sector 0
///
@ -13,7 +13,6 @@ use crate::relation::tuple::{OwnTuple, SliceTuple, Tuple};
/// `[Null, Int, Text, Int, Text]` inverted index for related tables
/// `[True, Int]` table info, value is key
impl<'s> Session<'s> {
pub fn define_variable(&mut self, name: &str, val: &Value, in_root: bool) -> Result<()> {
let mut data = Tuple::with_data_prefix(DataKind::Val);
@ -36,16 +35,37 @@ impl<'s> Session<'s> {
}
pub fn key_exists(&self, key: &OwnTuple, in_root: bool) -> Result<bool> {
let res = self.txn.get(in_root, if in_root { &self.perm_cf } else { &self.temp_cf }, key)?;
let res = self.txn.get(
in_root,
if in_root {
&self.perm_cf
} else {
&self.temp_cf
},
key,
)?;
Ok(res.is_some())
}
pub fn del_key(&self, key: &OwnTuple, in_root: bool) -> Result<()> {
self.txn.del(in_root, if in_root { &self.perm_cf } else { &self.temp_cf }, key)?;
self.txn.del(
in_root,
if in_root {
&self.perm_cf
} else {
&self.temp_cf
},
key,
)?;
Ok(())
}
pub fn define_raw_key(&self, key: &OwnTuple, value: Option<&OwnTuple>, in_root: bool) -> Result<()> {
pub fn define_raw_key(
&self,
key: &OwnTuple,
value: Option<&OwnTuple>,
in_root: bool,
) -> Result<()> {
if in_root {
match value {
None => {
@ -71,14 +91,14 @@ impl<'s> Session<'s> {
pub fn resolve_value(&self, name: &str) -> Result<Option<Value>> {
match self.resolve(name)? {
None => Ok(None),
Some(t) => {
match t.data_kind()? {
DataKind::Val => Ok(Some(t.get(0)
Some(t) => match t.data_kind()? {
DataKind::Val => Ok(Some(
t.get(0)
.ok_or_else(|| CozoError::LogicError("Corrupt".to_string()))?
.to_static())),
k => Err(CozoError::UnexpectedDataKind(k))
}
}
.to_static(),
)),
k => Err(CozoError::UnexpectedDataKind(k)),
},
}
}
pub fn get_stack_depth(&self) -> i32 {
@ -108,15 +128,16 @@ impl<'s> Session<'s> {
ikey.push_value(&name);
ikey.push_int(self.stack_depth as i64);
let data = self.txn.get(false, &self.temp_cf, &ikey)?
let data = self
.txn
.get(false, &self.temp_cf, &ikey)?
.ok_or_else(|| CozoError::LogicError("Bad format for ikey".to_string()))?;
let data = Tuple::new(data);
match data.data_kind()? {
DataKind::Node |
DataKind::Edge |
DataKind::Assoc |
DataKind::Index => {
let id = data.get_int(1).ok_or_else(|| CozoError::LogicError("Bad table index".to_string()))?;
DataKind::Node | DataKind::Edge | DataKind::Assoc | DataKind::Index => {
let id = data.get_int(1).ok_or_else(|| {
CozoError::LogicError("Bad table index".to_string())
})?;
let mut rkey = Tuple::with_null_prefix();
rkey.push_bool(true);
rkey.push_int(id);
@ -184,7 +205,10 @@ impl<'s> Session<'s> {
}
}
let root_key = self.encode_definable_key(name, true);
let res = self.txn.get(true, &self.perm_cf, root_key).map(|v| v.map(Tuple::new))?;
let res = self
.txn
.get(true, &self.perm_cf, root_key)
.map(|v| v.map(Tuple::new))?;
Ok(res)
}
}
}

File diff suppressed because it is too large Load Diff

@ -1,16 +1,15 @@
use std::cmp::Ordering;
use std::{iter, mem};
use std::fmt::{Debug, Formatter};
use cozorocks::IteratorPtr;
use crate::db::eval::{compare_tuple_by_keys, tuple_eval};
use crate::db::table::{ColId, TableId};
use crate::error::CozoError::LogicError;
use crate::error::{Result};
use crate::error::Result;
use crate::relation::data::{DataKind, EMPTY_DATA};
use crate::relation::table::MegaTuple;
use crate::relation::tuple::{CowSlice, CowTuple, OwnTuple, Tuple};
use crate::relation::value::Value;
use cozorocks::IteratorPtr;
use std::cmp::Ordering;
use std::fmt::{Debug, Formatter};
use std::{iter, mem};
pub enum IteratorSlot<'a> {
Dummy,
@ -21,7 +20,7 @@ impl<'a> Debug for IteratorSlot<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
IteratorSlot::Dummy => write!(f, "DummyIterator"),
IteratorSlot::Reified(_) => write!(f, "BaseIterator")
IteratorSlot::Reified(_) => write!(f, "BaseIterator"),
}
}
}
@ -36,7 +35,7 @@ impl<'a> IteratorSlot<'a> {
pub fn try_get(&self) -> Result<&IteratorPtr<'a>> {
match self {
IteratorSlot::Dummy => Err(LogicError("Cannot iter over dummy".to_string())),
IteratorSlot::Reified(r) => Ok(r)
IteratorSlot::Reified(r) => Ok(r),
}
}
}
@ -100,7 +99,7 @@ pub enum ExecPlan<'a> {
out_prefix: u32,
},
BagsUnionIt {
bags: Vec<ExecPlan<'a>>
bags: Vec<ExecPlan<'a>>,
},
}
@ -126,120 +125,109 @@ impl<'a> ExecPlan<'a> {
let prefix_tuple = OwnTuple::with_prefix(*tid);
it.seek(prefix_tuple);
Ok(Box::new(NodeIterator {
it,
started: false,
}))
Ok(Box::new(NodeIterator { it, started: false }))
}
ExecPlan::EdgeIt { it, tid } => {
let it = it.try_get()?;
let prefix_tuple = OwnTuple::with_prefix(*tid);
it.seek(prefix_tuple);
Ok(Box::new(EdgeIterator {
it,
started: false,
}))
Ok(Box::new(EdgeIterator { it, started: false }))
}
ExecPlan::EdgeKeyOnlyBwdIt { it, tid } => {
let it = it.try_get()?;
let prefix_tuple = OwnTuple::with_prefix(*tid);
it.seek(prefix_tuple);
Ok(Box::new(EdgeKeyOnlyBwdIterator {
it,
started: false,
}))
Ok(Box::new(EdgeKeyOnlyBwdIterator { it, started: false }))
}
ExecPlan::KeySortedWithAssocIt { main, associates } => {
let buffer = iter::repeat_with(|| None).take(associates.len()).collect();
let associates = associates.into_iter().map(|(tid, it)| {
it.try_get().map(|it| {
let prefix_tuple = OwnTuple::with_prefix(*tid);
it.seek(prefix_tuple);
NodeIterator {
it,
started: false,
}
let associates = associates
.iter()
.map(|(tid, it)| {
it.try_get().map(|it| {
let prefix_tuple = OwnTuple::with_prefix(*tid);
it.seek(prefix_tuple);
NodeIterator { it, started: false }
})
})
}).collect::<Result<Vec<_>>>()?;
.collect::<Result<Vec<_>>>()?;
Ok(Box::new(KeySortedWithAssocIterator {
main: main.iter()?,
associates,
buffer,
}))
}
ExecPlan::CartesianProdIt { left, right } => {
Ok(Box::new(CartesianProdIterator {
left: left.iter()?,
left_cache: MegaTuple::empty_tuple(),
right_source: right.as_ref(),
right: right.as_ref().iter()?,
}))
}
ExecPlan::FilterIt { it, filter } => {
Ok(Box::new(FilterIterator {
it: it.iter()?,
filter,
}))
}
ExecPlan::EvalIt { it, keys, vals, out_prefix: prefix } => {
Ok(Box::new(EvalIterator {
it: it.iter()?,
keys,
vals,
prefix: *prefix,
}))
}
ExecPlan::MergeJoinIt { left, right, left_keys, right_keys } => {
Ok(Box::new(MergeJoinIterator {
left: left.iter()?,
right: right.iter()?,
left_keys,
right_keys,
}))
}
ExecPlan::CartesianProdIt { left, right } => Ok(Box::new(CartesianProdIterator {
left: left.iter()?,
left_cache: MegaTuple::empty_tuple(),
right_source: right.as_ref(),
right: right.as_ref().iter()?,
})),
ExecPlan::FilterIt { it, filter } => Ok(Box::new(FilterIterator {
it: it.iter()?,
filter,
})),
ExecPlan::EvalIt {
it,
keys,
vals,
out_prefix: prefix,
} => Ok(Box::new(EvalIterator {
it: it.iter()?,
keys,
vals,
prefix: *prefix,
})),
ExecPlan::MergeJoinIt {
left,
right,
left_keys,
right_keys,
} => Ok(Box::new(MergeJoinIterator {
left: left.iter()?,
right: right.iter()?,
left_keys,
right_keys,
})),
ExecPlan::OuterMergeJoinIt {
left, right,
left_keys, right_keys, left_outer, right_outer,
left_len, right_len
} => {
Ok(Box::new(OuterMergeJoinIterator {
left: left.iter()?,
right: right.iter()?,
left_outer: *left_outer,
right_outer: *right_outer,
left_keys,
right_keys,
left_len: *left_len,
right_len: *right_len,
left_cache: None,
right_cache: None,
pull_left: true,
pull_right: true,
}))
}
ExecPlan::KeyedUnionIt { left, right } => {
Ok(Box::new(KeyedUnionIterator {
left: left.iter()?,
right: right.iter()?,
}))
}
ExecPlan::KeyedDifferenceIt { left, right } => {
Ok(Box::new(KeyedDifferenceIterator {
left: left.iter()?,
right: right.iter()?,
right_cache: None,
started: false,
}))
}
left,
right,
left_keys,
right_keys,
left_outer,
right_outer,
left_len,
right_len,
} => Ok(Box::new(OuterMergeJoinIterator {
left: left.iter()?,
right: right.iter()?,
left_outer: *left_outer,
right_outer: *right_outer,
left_keys,
right_keys,
left_len: *left_len,
right_len: *right_len,
left_cache: None,
right_cache: None,
pull_left: true,
pull_right: true,
})),
ExecPlan::KeyedUnionIt { left, right } => Ok(Box::new(KeyedUnionIterator {
left: left.iter()?,
right: right.iter()?,
})),
ExecPlan::KeyedDifferenceIt { left, right } => Ok(Box::new(KeyedDifferenceIterator {
left: left.iter()?,
right: right.iter()?,
right_cache: None,
started: false,
})),
ExecPlan::BagsUnionIt { bags } => {
let bags = bags.iter().map(|i| i.iter()).collect::<Result<Vec<_>>>()?;
Ok(Box::new(BagsUnionIterator {
bags,
current: 0,
}))
Ok(Box::new(BagsUnionIterator { bags, current: 0 }))
}
}
}
@ -257,13 +245,13 @@ impl<'a> Iterator for KeyedUnionIterator<'a> {
let mut left_cache = match self.left.next() {
None => return None,
Some(Err(e)) => return Some(Err(e)),
Some(Ok(t)) => t
Some(Ok(t)) => t,
};
let mut right_cache = match self.right.next() {
None => return None,
Some(Err(e)) => return Some(Err(e)),
Some(Ok(t)) => t
Some(Ok(t)) => t,
};
loop {
@ -312,7 +300,7 @@ impl<'a> Iterator for KeyedDifferenceIterator<'a> {
self.right_cache = match self.right.next() {
None => None,
Some(Err(e)) => return Some(Err(e)),
Some(Ok(t)) => Some(t)
Some(Ok(t)) => Some(t),
};
self.started = true;
@ -321,17 +309,16 @@ impl<'a> Iterator for KeyedDifferenceIterator<'a> {
let mut left_cache = match self.left.next() {
None => return None,
Some(Err(e)) => return Some(Err(e)),
Some(Ok(t)) => t
Some(Ok(t)) => t,
};
loop {
let right = match &self.right_cache {
None => {
// right is exhausted, so all left ones can be returned
return Some(Ok(left_cache));
}
Some(r) => r
Some(r) => r,
};
let cmp_res = left_cache.all_keys_cmp(right);
match cmp_res {
@ -340,12 +327,12 @@ impl<'a> Iterator for KeyedDifferenceIterator<'a> {
left_cache = match self.left.next() {
None => return None,
Some(Err(e)) => return Some(Err(e)),
Some(Ok(t)) => t
Some(Ok(t)) => t,
};
self.right_cache = match self.right.next() {
None => None,
Some(Err(e)) => return Some(Err(e)),
Some(Ok(t)) => Some(t)
Some(Ok(t)) => Some(t),
};
}
Ordering::Less => {
@ -386,7 +373,7 @@ impl<'a> Iterator for BagsUnionIterator<'a> {
self.next()
}
}
v => v
v => v,
}
}
}
@ -494,36 +481,30 @@ impl<'a> Iterator for KeySortedWithAssocIterator<'a> {
fn next(&mut self) -> Option<Self::Item> {
match self.main.next() {
None => None, // main exhausted, we are finished
Some(Err(e)) => return Some(Err(e)),
Some(Err(e)) => Some(Err(e)),
Some(Ok(MegaTuple { mut keys, mut vals })) => {
// extract key from main
let k = match keys.pop() {
None => return Some(Err(LogicError("Empty keys".to_string()))),
Some(k) => k
Some(k) => k,
};
let l = self.associates.len();
// initialize vector for associate values
let mut assoc_vals: Vec<Option<CowTuple>> = iter::repeat_with(|| None).take(l).collect();
let l = assoc_vals.len();
// let l = assoc_vals.len();
#[allow(clippy::needless_range_loop)]
for i in 0..l {
// for each associate
let cached = self.buffer.get(i).unwrap();
// if no cache, try to get cache filled first
if matches!(cached, None) {
let assoc_data = self.associates.get_mut(i).unwrap().next()
.map(|mt| {
mt.map(|mut mt| {
(mt.keys.pop().unwrap(), mt.vals.pop().unwrap())
})
});
let assoc_data = self.associates.get_mut(i).unwrap().next().map(|mt| {
mt.map(|mut mt| (mt.keys.pop().unwrap(), mt.vals.pop().unwrap()))
});
match assoc_data {
None => {
self.buffer[i] = None
}
Some(Ok(data)) => {
self.buffer[i] = Some(data)
}
Some(Err(e)) => return Some(Err(e))
None => self.buffer[i] = None,
Some(Ok(data)) => self.buffer[i] = Some(data),
Some(Err(e)) => return Some(Err(e)),
}
}
@ -537,38 +518,31 @@ impl<'a> Iterator for KeySortedWithAssocIterator<'a> {
Ordering::Equal => {
// target key equals cache key, we put it into collected values
let (_, v) = mem::replace(&mut self.buffer[i], None).unwrap();
assoc_vals[i] = Some(v.into());
assoc_vals[i] = Some(v);
break;
}
Ordering::Greater => {
// target key greater than cache key, meaning that the source has holes (maybe due to filtering)
// get a new one into buffer
let assoc_data = self.associates.get_mut(i).unwrap().next()
.map(|mt| {
let assoc_data =
self.associates.get_mut(i).unwrap().next().map(|mt| {
mt.map(|mut mt| {
(mt.keys.pop().unwrap(), mt.vals.pop().unwrap())
})
});
match assoc_data {
None => {
self.buffer[i] = None
}
Some(Ok(data)) => {
self.buffer[i] = Some(data)
}
Some(Err(e)) => return Some(Err(e))
None => self.buffer[i] = None,
Some(Ok(data)) => self.buffer[i] = Some(data),
Some(Err(e)) => return Some(Err(e)),
}
}
}
}
}
vals.extend(assoc_vals.into_iter().map(|v|
match v {
None => {
CowTuple::new(CowSlice::Own(EMPTY_DATA.into()))
}
Some(v) => v
}));
vals.extend(assoc_vals.into_iter().map(|v| match v {
None => CowTuple::new(CowSlice::Own(EMPTY_DATA.into())),
Some(v) => v,
}));
Some(Ok(MegaTuple {
keys: vec![k],
vals,
@ -601,7 +575,7 @@ impl<'a> Iterator for OuterMergeJoinIterator<'a> {
self.left_cache = match self.left.next() {
None => None,
Some(Err(e)) => return Some(Err(e)),
Some(Ok(t)) => Some(t)
Some(Ok(t)) => Some(t),
};
self.pull_left = false;
}
@ -610,15 +584,23 @@ impl<'a> Iterator for OuterMergeJoinIterator<'a> {
self.right_cache = match self.right.next() {
None => None,
Some(Err(e)) => return Some(Err(e)),
Some(Ok(t)) => Some(t)
Some(Ok(t)) => Some(t),
};
self.pull_right = false;
}
let make_empty_tuple = |is_left: bool| -> MegaTuple {
let lengths = if is_left { self.left_len } else { self.right_len };
let keys = iter::repeat_with(|| OwnTuple::empty_tuple().into()).take(lengths.0).collect();
let vals = iter::repeat_with(|| OwnTuple::empty_tuple().into()).take(lengths.1).collect();
let lengths = if is_left {
self.left_len
} else {
self.right_len
};
let keys = iter::repeat_with(|| OwnTuple::empty_tuple().into())
.take(lengths.0)
.collect();
let vals = iter::repeat_with(|| OwnTuple::empty_tuple().into())
.take(lengths.1)
.collect();
MegaTuple { keys, vals }
};
@ -640,7 +622,7 @@ impl<'a> Iterator for OuterMergeJoinIterator<'a> {
}
};
}
Some(t) => t
Some(t) => t,
};
let right_cache = match &self.right_cache {
None => {
@ -659,12 +641,14 @@ impl<'a> Iterator for OuterMergeJoinIterator<'a> {
}
};
}
Some(t) => t
Some(t) => t,
};
let cmp_res = match compare_tuple_by_keys((&left_cache, self.left_keys),
(&right_cache, self.right_keys)) {
let cmp_res = match compare_tuple_by_keys(
(left_cache, self.left_keys),
(right_cache, self.right_keys),
) {
Ok(r) => r,
Err(e) => return Some(Err(e))
Err(e) => return Some(Err(e)),
};
match cmp_res {
Ordering::Equal => {
@ -731,20 +715,22 @@ impl<'a> Iterator for MergeJoinIterator<'a> {
let mut left_cache = match self.left.next() {
None => return None,
Some(Err(e)) => return Some(Err(e)),
Some(Ok(t)) => t
Some(Ok(t)) => t,
};
let mut right_cache = match self.right.next() {
None => return None,
Some(Err(e)) => return Some(Err(e)),
Some(Ok(t)) => t
Some(Ok(t)) => t,
};
loop {
let cmp_res = match compare_tuple_by_keys((&left_cache, self.left_keys),
(&right_cache, self.right_keys)) {
let cmp_res = match compare_tuple_by_keys(
(&left_cache, self.left_keys),
(&right_cache, self.right_keys),
) {
Ok(r) => r,
Err(e) => return Some(Err(e))
Err(e) => return Some(Err(e)),
};
match cmp_res {
Ordering::Equal => {
@ -791,29 +777,29 @@ impl<'a> Iterator for CartesianProdIterator<'a> {
self.left_cache = match self.left.next() {
None => return None,
Some(Ok(v)) => v,
Some(Err(e)) => return Some(Err(e))
Some(Err(e)) => return Some(Err(e)),
}
}
let r_tpl = match self.right.next() {
None => {
self.right = match self.right_source.iter() {
Ok(it) => it,
Err(e) => return Some(Err(e))
Err(e) => return Some(Err(e)),
};
self.left_cache = match self.left.next() {
None => return None,
Some(Ok(v)) => v,
Some(Err(e)) => return Some(Err(e))
Some(Err(e)) => return Some(Err(e)),
};
match self.right.next() {
// early return in case right is empty
None => return None,
Some(Ok(r_tpl)) => r_tpl,
Some(Err(e)) => return Some(Err(e))
Some(Err(e)) => return Some(Err(e)),
}
}
Some(Ok(r_tpl)) => r_tpl,
Some(Err(e)) => return Some(Err(e))
Some(Err(e)) => return Some(Err(e)),
};
let mut ret = self.left_cache.clone();
ret.keys.extend(r_tpl.keys);
@ -833,17 +819,17 @@ impl<'a> Iterator for FilterIterator<'a> {
fn next(&mut self) -> Option<Self::Item> {
for t in self.it.by_ref() {
match t {
Ok(t) => {
match tuple_eval(self.filter, &t) {
Ok(Value::Bool(true)) => {
return Some(Ok(t));
}
Ok(Value::Bool(false)) | Ok(Value::Null) => {}
Ok(_v) => return Some(Err(LogicError("Unexpected type in filter".to_string()))),
Err(e) => return Some(Err(e))
Ok(t) => match tuple_eval(self.filter, &t) {
Ok(Value::Bool(true)) => {
return Some(Ok(t));
}
}
Err(e) => return Some(Err(e))
Ok(Value::Bool(false)) | Ok(Value::Null) => {}
Ok(_v) => {
return Some(Err(LogicError("Unexpected type in filter".to_string())));
}
Err(e) => return Some(Err(e)),
},
Err(e) => return Some(Err(e)),
}
}
None
@ -871,7 +857,7 @@ impl<'a> Iterator for OutputIterator<'a> {
match self.it.next() {
None => None,
Some(Err(e)) => Some(Err(e)),
Some(Ok(t)) => Some(tuple_eval(self.transform, &t).map(|v| v.to_static()))
Some(Ok(t)) => Some(tuple_eval(self.transform, &t).map(|v| v.to_static())),
}
}
}
@ -896,16 +882,19 @@ impl<'a> Iterator for EvalIterator<'a> {
for k in self.keys {
match tuple_eval(k, &t) {
Ok(v) => key_tuple.push_value(&v),
Err(e) => return Some(Err(e))
Err(e) => return Some(Err(e)),
}
}
for k in self.vals {
match tuple_eval(k, &t) {
Ok(v) => val_tuple.push_value(&v),
Err(e) => return Some(Err(e))
Err(e) => return Some(Err(e)),
}
}
Some(Ok(MegaTuple { keys: vec![key_tuple.into()], vals: vec![val_tuple.into()] }))
Some(Ok(MegaTuple {
keys: vec![key_tuple.into()],
vals: vec![val_tuple.into()],
}))
}
}
}
@ -913,16 +902,16 @@ impl<'a> Iterator for EvalIterator<'a> {
#[cfg(test)]
mod tests {
use std::collections::BTreeMap;
use std::fs;
use std::time::Instant;
use crate::db::engine::Engine;
use crate::parser::{Parser, Rule};
use pest::Parser as PestParser;
use crate::db::iterator::{ExecPlan, OutputIterator};
use crate::db::query::FromEl;
use crate::relation::value::Value;
use crate::error::Result;
use crate::parser::{Parser, Rule};
use crate::relation::value::Value;
use pest::Parser as PestParser;
use std::collections::BTreeMap;
use std::fs;
use std::time::Instant;
#[test]
fn pair_value() -> Result<()> {
@ -961,25 +950,46 @@ mod tests {
let start2 = Instant::now();
let s = "from e:Employee";
let p = Parser::parse(Rule::from_pattern, s).unwrap().next().unwrap();
let p = Parser::parse(Rule::from_pattern, s)
.unwrap()
.next()
.unwrap();
let from_pat = match sess.parse_from_pattern(p).unwrap().pop().unwrap() {
FromEl::Simple(s) => s,
FromEl::Chain(_) => panic!()
FromEl::Chain(_) => panic!(),
};
let s = "where e.id >= 100, e.id <= 105 || e.id == 110";
let p = Parser::parse(Rule::where_pattern, s).unwrap().next().unwrap();
let p = Parser::parse(Rule::where_pattern, s)
.unwrap()
.next()
.unwrap();
let where_pat = sess.parse_where_pattern(p).unwrap();
let s = r#"select {id: e.id,
full_name: e.first_name ++ ' ' ++ e.last_name, bibio_name: e.last_name ++ ', '
++ e.first_name ++ ': ' ++ (e.phone_number ~ 'N.A.')}"#;
let p = Parser::parse(Rule::select_pattern, s).unwrap().next().unwrap();
let p = Parser::parse(Rule::select_pattern, s)
.unwrap()
.next()
.unwrap();
let sel_pat = sess.parse_select_pattern(p).unwrap();
let amap = sess.base_relation_to_accessor_map(&from_pat.table, &from_pat.binding, &from_pat.info);
let (_, vals) = sess.partial_eval(sel_pat.vals, &Default::default(), &amap).unwrap();
let (_, where_vals) = sess.partial_eval(where_pat, &Default::default(), &amap).unwrap();
println!("{:#?}", sess.cnf_with_table_refs(where_vals.clone(), &Default::default(), &amap));
let (vcoll, mut rel_tbls) = Value::extract_relevant_tables([vals, where_vals].into_iter()).unwrap();
let amap = sess.base_relation_to_accessor_map(
&from_pat.table,
&from_pat.binding,
&from_pat.info,
);
let (_, vals) = sess
.partial_eval(sel_pat.vals, &Default::default(), &amap)
.unwrap();
let (_, where_vals) = sess
.partial_eval(where_pat, &Default::default(), &amap)
.unwrap();
println!(
"{:#?}",
sess.cnf_with_table_refs(where_vals.clone(), &Default::default(), &amap)
);
let (vcoll, mut rel_tbls) =
Value::extract_relevant_tables([vals, where_vals].into_iter()).unwrap();
let mut vcoll = vcoll.into_iter();
let vals = vcoll.next().unwrap();
let where_vals = vcoll.next().unwrap();
@ -991,7 +1001,10 @@ mod tests {
let tbl = rel_tbls.pop().unwrap();
let it = sess.iter_node(tbl);
let it = ExecPlan::FilterIt { filter: where_vals, it: it.into() };
let it = ExecPlan::FilterIt {
filter: where_vals,
it: it.into(),
};
let it = OutputIterator::new(&it, &vals)?;
for val in it {
println!("{}", val.unwrap());
@ -1001,9 +1014,11 @@ mod tests {
println!("Time elapsed {:?} {:?}", duration, duration2);
let it = ExecPlan::KeySortedWithAssocIt {
main: Box::new(sess.iter_node(tbl)),
associates: vec![(tbl.id as u32, sess.raw_iterator(true).into()),
(tbl.id as u32, sess.raw_iterator(true).into()),
(tbl.id as u32, sess.raw_iterator(true).into())],
associates: vec![
(tbl.id as u32, sess.raw_iterator(true).into()),
(tbl.id as u32, sess.raw_iterator(true).into()),
(tbl.id as u32, sess.raw_iterator(true).into()),
],
};
{
for el in it.iter()? {
@ -1033,12 +1048,23 @@ mod tests {
// if n % 4096 == 0 {
// println!("{}: {:?}", n, el)
// }
let _x = el.keys.into_iter().map(|v| v.iter().map(|_v| ()).collect::<Vec<_>>()).collect::<Vec<_>>();
let _y = el.vals.into_iter().map(|v| v.iter().map(|_v| ()).collect::<Vec<_>>()).collect::<Vec<_>>();
let _x = el
.keys
.into_iter()
.map(|v| v.iter().map(|_v| ()).collect::<Vec<_>>())
.collect::<Vec<_>>();
let _y = el
.vals
.into_iter()
.map(|v| v.iter().map(|_v| ()).collect::<Vec<_>>())
.collect::<Vec<_>>();
n += 1;
}
let duration = start.elapsed();
println!("{} items per second", 1e9 * (n as f64) / (duration.as_nanos() as f64));
println!(
"{} items per second",
1e9 * (n as f64) / (duration.as_nanos() as f64)
);
// let a = sess.iter_table(tbl);
// let ac = (&a).into_iter().count();
// println!("{}", ac);
@ -1047,4 +1073,4 @@ mod tests {
let _ = fs::remove_dir_all(db_path);
Ok(())
}
}
}

@ -1,17 +1,17 @@
use std::borrow::Cow;
use std::cell::RefCell;
use std::collections::{BTreeMap, HashSet};
use std::rc::Rc;
use pest::iterators::Pair;
use crate::db::engine::Session;
use crate::db::table::TableInfo;
use crate::error::CozoError::LogicError;
use crate::error::{CozoError, Result};
use crate::parser::Rule;
use crate::parser::text_identifier::build_name_in_def;
use crate::parser::Rule;
use crate::relation::data::DataKind;
use crate::relation::tuple::Tuple;
use crate::relation::value::Value;
use pest::iterators::Pair;
use std::borrow::Cow;
use std::cell::RefCell;
use std::collections::{BTreeMap, HashSet};
use std::rc::Rc;
/// # key layouts
///
@ -36,23 +36,34 @@ enum MutationKind {
}
impl<'a> Session<'a> {
pub fn run_mutation(&mut self, pair: Pair<Rule>, params: &BTreeMap<String, Value>) -> Result<()> {
pub fn run_mutation(
&mut self,
pair: Pair<Rule>,
params: &BTreeMap<String, Value>,
) -> Result<()> {
let mut pairs = pair.into_inner();
let kind = match pairs.next().unwrap().as_rule() {
Rule::upsert => MutationKind::Upsert,
Rule::insert => MutationKind::Insert,
_ => unreachable!()
_ => unreachable!(),
};
let (evaluated, expr) = self.partial_eval(
Value::from_pair(pairs.next().unwrap())?,
params,
&Default::default())?;
&Default::default(),
)?;
if !evaluated {
return Err(LogicError("Mutation encountered unevaluated expression".to_string()));
return Err(LogicError(
"Mutation encountered unevaluated expression".to_string(),
));
}
let expr = match expr {
Value::List(v) => v,
_ => return Err(LogicError("Mutation requires iterator of values".to_string()))
_ => {
return Err(LogicError(
"Mutation requires iterator of values".to_string(),
))
}
};
let mut default_kind = None;
// let mut filters: Option<()> = None;
@ -60,7 +71,7 @@ impl<'a> Session<'a> {
match p.as_rule() {
Rule::name_in_def => default_kind = Some(build_name_in_def(p, true)?),
Rule::mutation_filter => todo!(), // filters = Some(()), // TODO
_ => unreachable!()
_ => unreachable!(),
}
}
// println!("{:?}", kind);
@ -74,7 +85,7 @@ impl<'a> Session<'a> {
for item in expr {
let val_map = match item {
Value::Dict(d) => d,
_ => return Err(LogicError("Must be structs".to_string()))
_ => return Err(LogicError("Must be structs".to_string())),
};
mutation_manager.process_insert(kind == MutationKind::Insert, val_map)?;
}
@ -91,27 +102,38 @@ struct MutationManager<'a, 'b> {
impl<'a, 'b> MutationManager<'a, 'b> {
fn new(sess: &'a Session<'b>, default_tbl: Option<String>) -> Self {
Self { sess, cache: RefCell::new(BTreeMap::new()), default_tbl }
Self {
sess,
cache: RefCell::new(BTreeMap::new()),
default_tbl,
}
}
fn get_table_info(&self, tbl_name: Cow<str>) -> Result<Rc<TableInfo>> {
if !self.cache.borrow().contains_key(tbl_name.as_ref()) {
let coercer = self.sess.get_table_info(&tbl_name)?;
self.cache.borrow_mut().insert(tbl_name.as_ref().to_string(), Rc::new(coercer));
self.cache
.borrow_mut()
.insert(tbl_name.as_ref().to_string(), Rc::new(coercer));
}
let cache = self.cache.borrow();
let info = cache.get(tbl_name.as_ref())
let info = cache
.get(tbl_name.as_ref())
.ok_or_else(|| CozoError::LogicError("Cannot resolve table".to_string()))?;
Ok(info.clone())
}
fn process_insert(&mut self, error_on_existing: bool, mut val_map: BTreeMap<Cow<str>, Value>) -> Result<()> {
fn process_insert(
&mut self,
error_on_existing: bool,
mut val_map: BTreeMap<Cow<str>, Value>,
) -> Result<()> {
let tbl_name = match val_map.get("_type") {
Some(Value::Text(t)) => t.clone(),
Some(_) => return Err(LogicError("Table kind must be text".to_string())),
None => match &self.default_tbl {
Some(v) => v.clone().into(),
None => return Err(LogicError("Cannot determine table kind".to_string()))
}
None => return Err(LogicError("Cannot determine table kind".to_string())),
},
};
let table_info = self.get_table_info(tbl_name)?;
@ -132,10 +154,18 @@ impl<'a, 'b> MutationManager<'a, 'b> {
let processed = v.coerce(raw)?;
val_tuple.push_value(&processed);
}
if error_on_existing && self.sess.key_exists(&key_tuple, table_info.table_id.in_root)? {
if error_on_existing
&& self
.sess
.key_exists(&key_tuple, table_info.table_id.in_root)?
{
return Err(CozoError::KeyConflict(key_tuple));
}
self.sess.define_raw_key(&key_tuple, Some(&val_tuple), table_info.table_id.in_root)?;
self.sess.define_raw_key(
&key_tuple,
Some(&val_tuple),
table_info.table_id.in_root,
)?;
}
DataKind::Edge => {
key_tuple = Tuple::with_prefix(table_info.table_id.id as u32);
@ -149,7 +179,7 @@ impl<'a, 'b> MutationManager<'a, 'b> {
let src = val_map.remove("_src").unwrap_or(Value::Null);
let src_key_list = match src {
Value::List(v) => v,
v => vec![v]
v => vec![v],
};
if src_key_list.len() != table_info.src_key_typing.len() {
@ -158,7 +188,11 @@ impl<'a, 'b> MutationManager<'a, 'b> {
let mut src_keys = Vec::with_capacity(src_key_list.len());
for (t, v) in table_info.src_key_typing.iter().zip(src_key_list.into_iter()) {
for (t, v) in table_info
.src_key_typing
.iter()
.zip(src_key_list.into_iter())
{
let v = t.coerce(v)?;
key_tuple.push_value(&v);
src_keys.push(v);
@ -169,14 +203,18 @@ impl<'a, 'b> MutationManager<'a, 'b> {
let dst = val_map.remove("_dst").unwrap_or(Value::Null);
let dst_key_list = match dst {
Value::List(v) => v,
v => vec![v]
v => vec![v],
};
if dst_key_list.len() != table_info.dst_key_typing.len() {
return Err(CozoError::LogicError("Error in _dst key".to_string()));
}
for (t, v) in table_info.dst_key_typing.iter().zip(dst_key_list.into_iter()) {
for (t, v) in table_info
.dst_key_typing
.iter()
.zip(dst_key_list.into_iter())
{
let v = t.coerce(v)?;
key_tuple.push_value(&v);
ikey_tuple.push_value(&v);
@ -198,13 +236,25 @@ impl<'a, 'b> MutationManager<'a, 'b> {
let processed = v.coerce(raw)?;
val_tuple.push_value(&processed);
}
if error_on_existing && self.sess.key_exists(&key_tuple, table_info.table_id.in_root)? {
if error_on_existing
&& self
.sess
.key_exists(&key_tuple, table_info.table_id.in_root)?
{
return Err(CozoError::KeyConflict(key_tuple));
}
self.sess.define_raw_key(&key_tuple, Some(&val_tuple), table_info.table_id.in_root)?;
self.sess.define_raw_key(&ikey_tuple, Some(&key_tuple), table_info.table_id.in_root)?;
self.sess.define_raw_key(
&key_tuple,
Some(&val_tuple),
table_info.table_id.in_root,
)?;
self.sess.define_raw_key(
&ikey_tuple,
Some(&key_tuple),
table_info.table_id.in_root,
)?;
}
_ => unreachable!()
_ => unreachable!(),
}
let existing_keys: HashSet<_> = val_map.iter().map(|(k, _)| k.to_string()).collect();
@ -218,7 +268,8 @@ impl<'a, 'b> MutationManager<'a, 'b> {
val_tuple.push_value(&processed);
}
key_tuple.overwrite_prefix(assoc.table_id.id as u32);
self.sess.define_raw_key(&key_tuple, Some(&val_tuple), assoc.table_id.in_root)?;
self.sess
.define_raw_key(&key_tuple, Some(&val_tuple), assoc.table_id.in_root)?;
}
}
Ok(())
@ -227,14 +278,14 @@ impl<'a, 'b> MutationManager<'a, 'b> {
#[cfg(test)]
mod tests {
use std::collections::BTreeMap;
use std::fs;
use std::time::Instant;
use pest::Parser as PestParser;
use crate::db::engine::Engine;
use crate::parser::{Parser, Rule};
use crate::relation::tuple::Tuple;
use crate::relation::value::Value;
use pest::Parser as PestParser;
use std::collections::BTreeMap;
use std::fs;
use std::time::Instant;
#[test]
fn test_mutation() {
@ -349,4 +400,4 @@ mod tests {
drop(engine);
let _ = fs::remove_dir_all(db_path);
}
}
}

@ -1,14 +1,13 @@
use std::collections::BTreeMap;
use pest::iterators::Pair;
use cozorocks::{IteratorPtr};
use crate::db::engine::Session;
use crate::db::iterator::{IteratorSlot, ExecPlan, OutputIt};
use crate::db::iterator::{ExecPlan, IteratorSlot, OutputIt};
use crate::db::query::{FromEl, Selection};
use crate::db::table::{ColId, TableId, TableInfo};
use crate::relation::value::{StaticValue, Value};
use crate::error::Result;
use crate::parser::Rule;
use crate::error::{Result};
use crate::relation::value::{StaticValue, Value};
use cozorocks::IteratorPtr;
use pest::iterators::Pair;
use std::collections::BTreeMap;
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum OuterJoinType {
@ -17,14 +16,13 @@ pub enum OuterJoinType {
FullOuterJoin,
}
pub type AccessorMap = BTreeMap<String, BTreeMap<String, (TableId, ColId)>>;
impl<'a> Session<'a> {
pub fn realize_intermediate_plan(&self, plan: ExecPlan) -> ExecPlan {
pub fn realize_intermediate_plan(&self, _plan: ExecPlan) -> ExecPlan {
todo!()
}
pub fn realize_output_plan(&self, plan: ExecPlan) -> OutputIt {
pub fn realize_output_plan(&self, _plan: ExecPlan) -> OutputIt {
todo!()
}
pub fn query_to_plan(&self, pair: Pair<Rule>) -> Result<()> {
@ -37,7 +35,7 @@ impl<'a> Session<'a> {
nxt = pairs.next().unwrap();
r
}
_ => true.into()
_ => true.into(),
};
let select_data = self.parse_select_pattern(nxt)?;
let plan = self.convert_from_data_to_plan(from_data)?;
@ -47,9 +45,12 @@ impl<'a> Session<'a> {
Ok(())
}
fn convert_from_data_to_plan(&self, mut from_data: Vec<FromEl>) -> Result<ExecPlan> {
let res = match from_data.pop().unwrap() {
let _res = match from_data.pop().unwrap() {
FromEl::Simple(el) => {
println!("{:#?}", self.base_relation_to_accessor_map(&el.table, &el.binding, &el.info));
println!(
"{:#?}",
self.base_relation_to_accessor_map(&el.table, &el.binding, &el.info)
);
todo!()
// QueryPlan::BaseRelation {
// table: el.table,
@ -57,11 +58,17 @@ impl<'a> Session<'a> {
// info: el.info,
// }
}
FromEl::Chain(_) => todo!()
FromEl::Chain(_) => todo!(),
};
Ok(res)
// Ok(res)
// todo!()
}
pub(crate) fn base_relation_to_accessor_map(&self, _table: &str, binding: &str, info: &TableInfo) -> AccessorMap {
pub(crate) fn base_relation_to_accessor_map(
&self,
_table: &str,
binding: &str,
info: &TableInfo,
) -> AccessorMap {
let mut ret = BTreeMap::new();
for (i, (k, _)) in info.key_typing.iter().enumerate() {
ret.insert(k.into(), (info.table_id, (true, i).into()));
@ -79,11 +86,15 @@ impl<'a> Session<'a> {
}
BTreeMap::from([(binding.to_string(), ret)])
}
fn convert_where_data_to_plan(&self, plan: ExecPlan, where_data: StaticValue) -> Result<ExecPlan> {
fn convert_where_data_to_plan(
&self,
plan: ExecPlan,
where_data: StaticValue,
) -> Result<ExecPlan> {
let where_data = self.partial_eval(where_data, &Default::default(), &Default::default());
let plan = match where_data?.1 {
let _plan = match where_data?.1 {
Value::Bool(true) => plan,
v => {
_v => {
todo!()
// QueryPlan::Filter { rel: Box::new(plan), filter: v }
}
@ -91,7 +102,11 @@ impl<'a> Session<'a> {
// Ok(plan)
todo!()
}
fn convert_select_data_to_plan(&self, plan: ExecPlan, select_data: Selection) -> Result<ExecPlan> {
fn convert_select_data_to_plan(
&self,
_plan: ExecPlan,
_select_data: Selection,
) -> Result<ExecPlan> {
// Ok(MegaTupleIt::Projection { arg: Box::new(plan), projection: select_data })
todo!()
}
@ -106,6 +121,9 @@ impl<'a> Session<'a> {
pub fn iter_node(&self, tid: TableId) -> ExecPlan {
let it = self.raw_iterator(tid.in_root);
ExecPlan::NodeIt { it: IteratorSlot::Reified(it), tid: tid.id as u32 }
ExecPlan::NodeIt {
it: IteratorSlot::Reified(it),
tid: tid.id as u32,
}
}
}

@ -1,13 +1,13 @@
use std::collections::BTreeMap;
use pest::iterators::Pair;
use crate::db::engine::Session;
use crate::db::table::TableInfo;
use crate::parser::Rule;
use crate::error::{CozoError, Result};
use crate::parser::text_identifier::{build_name_in_def, parse_string};
use crate::parser::Rule;
use crate::relation::data::DataKind;
use crate::relation::value;
use crate::relation::value::{StaticValue, Value};
use pest::iterators::Pair;
use std::collections::BTreeMap;
#[derive(Debug, Eq, PartialEq, Clone)]
pub enum FromEl {
@ -41,13 +41,14 @@ pub struct EdgeOrNodeEl {
impl<'a> Session<'a> {
pub fn parse_from_pattern(&self, pair: Pair<Rule>) -> Result<Vec<FromEl>> {
let res: Result<Vec<_>> = pair.into_inner().map(|p| {
match p.as_rule() {
let res: Result<Vec<_>> = pair
.into_inner()
.map(|p| match p.as_rule() {
Rule::simple_from_pattern => self.parse_simple_from_pattern(p),
Rule::node_edge_pattern => self.parse_node_edge_pattern(p),
_ => unreachable!()
}
}).collect();
_ => unreachable!(),
})
.collect();
res
}
@ -55,17 +56,24 @@ impl<'a> Session<'a> {
let mut pairs = pair.into_inner();
let name = pairs.next().unwrap().as_str();
if name.starts_with('_') {
return Err(CozoError::LogicError("Pattern binding cannot start with underscore".to_string()));
return Err(CozoError::LogicError(
"Pattern binding cannot start with underscore".to_string(),
));
}
let table_name = build_name_in_def(pairs.next().unwrap(), true)?;
let table_info = self.get_table_info(&table_name)?;
let ret = FromEl::Simple(Box::new(SimpleFromEl { binding: name.to_string(), table: table_name, info: table_info }));
let ret = FromEl::Simple(Box::new(SimpleFromEl {
binding: name.to_string(),
table: table_name,
info: table_info,
}));
Ok(ret)
}
fn parse_node_edge_pattern(&self, pair: Pair<Rule>) -> Result<FromEl> {
let res: Result<Vec<_>> = pair.into_inner().map(|p| {
match p.as_rule() {
let res: Result<Vec<_>> = pair
.into_inner()
.map(|p| match p.as_rule() {
Rule::node_pattern => self.parse_node_pattern(p),
Rule::edge_pattern => {
let right_join;
@ -78,21 +86,17 @@ impl<'a> Session<'a> {
right_join = false;
}
let mut edge = match nxt.as_rule() {
Rule::fwd_edge_pattern => {
self.parse_edge_pattern(nxt, true)?
}
Rule::bwd_edge_pattern => {
self.parse_edge_pattern(nxt, false)?
}
_ => unreachable!()
Rule::fwd_edge_pattern => self.parse_edge_pattern(nxt, true)?,
Rule::bwd_edge_pattern => self.parse_edge_pattern(nxt, false)?,
_ => unreachable!(),
};
edge.left_outer_marker = pairs.next().is_some();
edge.right_outer_marker = right_join;
Ok(edge)
}
_ => unreachable!()
}
}).collect();
_ => unreachable!(),
})
.collect();
let res = res?;
let connects = res.windows(2).all(|v| {
let left = &v[0];
@ -110,7 +114,7 @@ impl<'a> Session<'a> {
(EdgeOrNodeKind::Node, EdgeOrNodeKind::BwdEdge) => {
left.info.table_id == right.info.dst_table_id
}
_ => unreachable!()
_ => unreachable!(),
}
});
if !connects {
@ -146,7 +150,11 @@ impl<'a> Session<'a> {
table,
binding,
info,
kind: if is_fwd { EdgeOrNodeKind::FwdEdge } else { EdgeOrNodeKind::BwdEdge },
kind: if is_fwd {
EdgeOrNodeKind::FwdEdge
} else {
EdgeOrNodeKind::BwdEdge
},
left_outer_marker: false,
right_outer_marker: false,
})
@ -171,7 +179,10 @@ impl<'a> Session<'a> {
}
pub fn parse_where_pattern(&self, pair: Pair<Rule>) -> Result<Value> {
let conditions = pair.into_inner().map(Value::from_pair).collect::<Result<Vec<_>>>()?;
let conditions = pair
.into_inner()
.map(Value::from_pair)
.collect::<Result<Vec<_>>>()?;
Ok(Value::Apply(value::OP_AND.into(), conditions).to_static())
}
@ -185,7 +196,7 @@ impl<'a> Session<'a> {
nxt = pp.next().unwrap();
Some(name.to_string())
}
_ => None
_ => None,
};
let mut keys = BTreeMap::new();
@ -210,8 +221,14 @@ impl<'a> Session<'a> {
Rule::spreading => {
let el = p.into_inner().next().unwrap();
let to_concat = Value::from_pair(el)?;
if !matches!(to_concat, Value::Dict(_) | Value::Variable(_) |
Value::IdxAccess(_, _) | Value:: FieldAccess(_, _) | Value::Apply(_, _)) {
if !matches!(
to_concat,
Value::Dict(_)
| Value::Variable(_)
| Value::IdxAccess(_, _)
| Value::FieldAccess(_, _)
| Value::Apply(_, _)
) {
return Err(CozoError::LogicError("Cannot spread".to_string()));
}
if !collected_vals.is_empty() {
@ -222,11 +239,11 @@ impl<'a> Session<'a> {
}
Rule::scoped_accessor => {
let name = parse_string(p.into_inner().next().unwrap())?;
let val = Value::FieldAccess(name.clone().into(),
Value::Variable("_".into()).into());
let val =
Value::FieldAccess(name.clone().into(), Value::Variable("_".into()).into());
collected_vals.insert(name.into(), val);
}
_ => unreachable!()
_ => unreachable!(),
}
}
@ -247,23 +264,40 @@ impl<'a> Session<'a> {
match p.as_rule() {
Rule::order_pattern => {
for p in p.into_inner() {
ordering.push((p.as_rule() == Rule::order_asc, parse_string(p.into_inner().next().unwrap())?))
ordering.push((
p.as_rule() == Rule::order_asc,
parse_string(p.into_inner().next().unwrap())?,
))
}
}
Rule::offset_pattern => {
for p in p.into_inner() {
match p.as_rule() {
Rule::limit_clause => {
limit = Some(p.into_inner().next().unwrap().as_str().replace('_', "").parse::<i64>()?);
limit = Some(
p.into_inner()
.next()
.unwrap()
.as_str()
.replace('_', "")
.parse::<i64>()?,
);
}
Rule::offset_clause => {
offset = Some(p.into_inner().next().unwrap().as_str().replace('_', "").parse::<i64>()?);
offset = Some(
p.into_inner()
.next()
.unwrap()
.as_str()
.replace('_', "")
.parse::<i64>()?,
);
}
_ => unreachable!()
_ => unreachable!(),
}
}
}
_ => unreachable!()
_ => unreachable!(),
}
}
@ -292,9 +326,9 @@ pub struct Selection {
mod tests {
use std::fs;
// use super::*;
use crate::db::engine::Engine;
use crate::parser::{Parser, Rule};
use pest::Parser as PestParser;
use crate::db::engine::Engine;
#[test]
fn parse_patterns() {
@ -335,27 +369,39 @@ mod tests {
sess.commit().unwrap();
let s = "from a:Friend, (b:Person)-[:Friend]->(c:Z), x:Person";
let parsed = Parser::parse(Rule::from_pattern, s).unwrap().next().unwrap();
let parsed = Parser::parse(Rule::from_pattern, s)
.unwrap()
.next()
.unwrap();
assert_eq!(parsed.as_rule(), Rule::from_pattern);
assert!(sess.parse_from_pattern(parsed).is_err());
let s = "from a:Friend, (b:Person)-[:Friend]->?(c:Person), x:Person";
let parsed = Parser::parse(Rule::from_pattern, s).unwrap().next().unwrap();
let parsed = Parser::parse(Rule::from_pattern, s)
.unwrap()
.next()
.unwrap();
assert_eq!(parsed.as_rule(), Rule::from_pattern);
let from_pattern = sess.parse_from_pattern(parsed).unwrap();
println!("{:#?}", from_pattern);
let s = "where b.id > c.id || x.name.is_null(), a.id == 5, x.name == 'Joe', x.name.len() == 3";
let parsed = Parser::parse(Rule::where_pattern, s).unwrap().next().unwrap();
let parsed = Parser::parse(Rule::where_pattern, s)
.unwrap()
.next()
.unwrap();
let where_result = sess.parse_where_pattern(parsed).unwrap();
println!("{:#?}", where_result);
let s = "select {*id: a.id, b: a.b, c: a.c} ordered [e, +c, -b] limit 1 offset 2";
let parsed = Parser::parse(Rule::select_pattern, s).unwrap().next().unwrap();
let parsed = Parser::parse(Rule::select_pattern, s)
.unwrap()
.next()
.unwrap();
let select_result = sess.parse_select_pattern(parsed).unwrap();
println!("{:#?}", select_result);
}
drop(engine);
let _ = fs::remove_dir_all(db_path);
}
}
}

@ -1,10 +1,10 @@
use std::collections::HashSet;
use std::fmt::{Debug, Formatter};
use crate::db::engine::Session;
use crate::error::{CozoError, Result};
use crate::error::CozoError::LogicError;
use crate::error::{CozoError, Result};
use crate::relation::data::DataKind;
use crate::relation::typing::Typing;
use std::collections::HashSet;
use std::fmt::{Debug, Formatter};
#[derive(Eq, PartialEq, Clone, Copy, Ord, PartialOrd, Hash)]
pub struct TableId {
@ -29,7 +29,10 @@ impl TableId {
impl From<(bool, usize)> for TableId {
fn from((in_root, id): (bool, usize)) -> Self {
Self { in_root, id: id as i64 }
Self {
in_root,
id: id as i64,
}
}
}
@ -59,13 +62,19 @@ impl From<(bool, i64)> for ColId {
impl From<(bool, usize)> for ColId {
fn from((is_key, id): (bool, usize)) -> Self {
Self { is_key, id: id as i64 }
Self {
is_key,
id: id as i64,
}
}
}
impl Default for TableId {
fn default() -> Self {
TableId { in_root: false, id: -1 }
TableId {
in_root: false,
id: -1,
}
}
}
@ -85,19 +94,35 @@ pub struct TableInfo {
impl<'a> Session<'a> {
pub fn get_table_info(&self, tbl_name: &str) -> Result<TableInfo> {
let table_info = match self.resolve(&tbl_name)? {
let table_info = match self.resolve(tbl_name)? {
None => return Err(CozoError::UndefinedType(tbl_name.to_string())),
Some(tpl) => {
let mut main_coercer = match tpl.data_kind()? {
DataKind::Node => {
let key_extractor = Typing::try_from(tpl.get_text(2)
.ok_or_else(|| CozoError::BadDataFormat(tpl.data.as_ref().to_vec()))?.as_ref())?
.extract_named_tuple().ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?;
let val_extractor = Typing::try_from(tpl.get_text(3)
.ok_or_else(|| CozoError::BadDataFormat(tpl.data.as_ref().to_vec()))?.as_ref())?
.extract_named_tuple().ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?;
let in_root = tpl.get_bool(0).ok_or_else(|| CozoError::LogicError("Cannot extract in root".to_string()))?;
let table_id = tpl.get_int(1).ok_or_else(|| CozoError::LogicError("Cannot extract in root".to_string()))?;
let key_extractor = Typing::try_from(
tpl.get_text(2)
.ok_or_else(|| {
CozoError::BadDataFormat(tpl.data.as_ref().to_vec())
})?
.as_ref(),
)?
.extract_named_tuple()
.ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?;
let val_extractor = Typing::try_from(
tpl.get_text(3)
.ok_or_else(|| {
CozoError::BadDataFormat(tpl.data.as_ref().to_vec())
})?
.as_ref(),
)?
.extract_named_tuple()
.ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?;
let in_root = tpl.get_bool(0).ok_or_else(|| {
CozoError::LogicError("Cannot extract in root".to_string())
})?;
let table_id = tpl.get_int(1).ok_or_else(|| {
CozoError::LogicError("Cannot extract in root".to_string())
})?;
let table_id = TableId::new(in_root, table_id);
TableInfo {
@ -114,38 +139,72 @@ impl<'a> Session<'a> {
}
}
DataKind::Edge => {
let other_key_extractor = Typing::try_from(tpl.get_text(6)
.ok_or_else(|| CozoError::LogicError("Key extraction failed".to_string()))?.as_ref())?
.extract_named_tuple().ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?;
let val_extractor = Typing::try_from(tpl.get_text(7)
.ok_or_else(|| CozoError::LogicError("Val extraction failed".to_string()))?.as_ref())?
.extract_named_tuple().ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?;
let src_in_root = tpl.get_bool(2)
.ok_or_else(|| CozoError::LogicError("Src in root extraction failed".to_string()))?;
let src_id = tpl.get_int(3)
.ok_or_else(|| CozoError::LogicError("Src id extraction failed".to_string()))?;
let other_key_extractor = Typing::try_from(
tpl.get_text(6)
.ok_or_else(|| {
CozoError::LogicError("Key extraction failed".to_string())
})?
.as_ref(),
)?
.extract_named_tuple()
.ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?;
let val_extractor = Typing::try_from(
tpl.get_text(7)
.ok_or_else(|| {
CozoError::LogicError("Val extraction failed".to_string())
})?
.as_ref(),
)?
.extract_named_tuple()
.ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?;
let src_in_root = tpl.get_bool(2).ok_or_else(|| {
CozoError::LogicError("Src in root extraction failed".to_string())
})?;
let src_id = tpl.get_int(3).ok_or_else(|| {
CozoError::LogicError("Src id extraction failed".to_string())
})?;
let src_table_id = TableId::new(src_in_root, src_id);
let dst_in_root = tpl.get_bool(4)
.ok_or_else(|| CozoError::LogicError("Dst in root extraction failed".to_string()))?;
let dst_id = tpl.get_int(5)
.ok_or_else(|| CozoError::LogicError("Dst id extraction failed".to_string()))?;
let dst_in_root = tpl.get_bool(4).ok_or_else(|| {
CozoError::LogicError("Dst in root extraction failed".to_string())
})?;
let dst_id = tpl.get_int(5).ok_or_else(|| {
CozoError::LogicError("Dst id extraction failed".to_string())
})?;
let dst_table_id = TableId::new(dst_in_root, dst_id);
let src = self.table_data(src_id, src_in_root)?
.ok_or_else(|| CozoError::LogicError("Getting src failed".to_string()))?;
let src_key = Typing::try_from(src.get_text(2)
.ok_or_else(|| CozoError::BadDataFormat(tpl.data.as_ref().to_vec()))?.as_ref())?
.extract_named_tuple().ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?;
let src = self.table_data(src_id, src_in_root)?.ok_or_else(|| {
CozoError::LogicError("Getting src failed".to_string())
})?;
let src_key = Typing::try_from(
src.get_text(2)
.ok_or_else(|| {
CozoError::BadDataFormat(tpl.data.as_ref().to_vec())
})?
.as_ref(),
)?
.extract_named_tuple()
.ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?;
let src_key_typing = src_key.into_iter().map(|(_, v)| v).collect();
let dst = self.table_data(dst_id, dst_in_root)?
.ok_or_else(|| CozoError::LogicError("Getting dst failed".to_string()))?;
let dst_key = Typing::try_from(dst.get_text(2)
.ok_or_else(|| CozoError::BadDataFormat(tpl.data.as_ref().to_vec()))?.as_ref())?
.extract_named_tuple().ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?;
let dst = self.table_data(dst_id, dst_in_root)?.ok_or_else(|| {
CozoError::LogicError("Getting dst failed".to_string())
})?;
let dst_key = Typing::try_from(
dst.get_text(2)
.ok_or_else(|| {
CozoError::BadDataFormat(tpl.data.as_ref().to_vec())
})?
.as_ref(),
)?
.extract_named_tuple()
.ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?;
let dst_key_typing = dst_key.into_iter().map(|(_, v)| v).collect();
let in_root = tpl.get_bool(0).ok_or_else(|| CozoError::LogicError("Cannot extract in root".to_string()))?;
let table_id = tpl.get_int(1).ok_or_else(|| CozoError::LogicError("Cannot extract in root".to_string()))?;
let in_root = tpl.get_bool(0).ok_or_else(|| {
CozoError::LogicError("Cannot extract in root".to_string())
})?;
let table_id = tpl.get_int(1).ok_or_else(|| {
CozoError::LogicError("Cannot extract in root".to_string())
})?;
let table_id = TableId::new(in_root, table_id);
TableInfo {
@ -161,16 +220,22 @@ impl<'a> Session<'a> {
associates: vec![],
}
}
_ => return Err(LogicError("Cannot insert into non-tables".to_string()))
_ => return Err(LogicError("Cannot insert into non-tables".to_string())),
};
let related = self.resolve_related_tables(&tbl_name)?;
let related = self.resolve_related_tables(tbl_name)?;
for (_n, d) in related {
let t = d.get_text(4)
.ok_or_else(|| CozoError::LogicError("Unable to extract typing from assoc".to_string()))?;
let t = d.get_text(4).ok_or_else(|| {
CozoError::LogicError("Unable to extract typing from assoc".to_string())
})?;
let t = Typing::try_from(t.as_ref())?
.extract_named_tuple().ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?;
let in_root = d.get_bool(0).ok_or_else(|| CozoError::LogicError("Cannot extract in root".to_string()))?;
let table_id = d.get_int(1).ok_or_else(|| CozoError::LogicError("Cannot extract in root".to_string()))?;
.extract_named_tuple()
.ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?;
let in_root = d.get_bool(0).ok_or_else(|| {
CozoError::LogicError("Cannot extract in root".to_string())
})?;
let table_id = d.get_int(1).ok_or_else(|| {
CozoError::LogicError("Cannot extract in root".to_string())
})?;
let table_id = TableId::new(in_root, table_id);
let coercer = TableInfo {
@ -193,4 +258,4 @@ impl<'a> Session<'a> {
};
Ok(table_info)
}
}
}

@ -1,11 +1,11 @@
use std::result;
use std::time::SystemTimeError;
use thiserror::Error;
use cozorocks::BridgeError;
use crate::parser::Rule;
use crate::relation::data::DataKind;
use crate::relation::tuple::OwnTuple;
use crate::relation::value::{StaticValue};
use crate::relation::value::StaticValue;
use cozorocks::BridgeError;
use std::result;
use std::time::SystemTimeError;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum CozoError {
@ -15,15 +15,14 @@ pub enum CozoError {
#[error("Invalid escape sequence")]
InvalidEscapeSequence,
// #[error("Type mismatch")]
// TypeError,
// #[error("Type mismatch")]
// TypeError,
#[error("Reserved identifier")]
ReservedIdent,
// #[error("The requested name exists")]
// NameConflict,
//
// NameConflict,
//
#[error("Undefined type '{0}'")]
UndefinedType(String),
@ -50,31 +49,30 @@ pub enum CozoError {
#[error("Undefined parameter {0}")]
UndefinedParam(String),
//
// #[error("Undefined table")]
// UndefinedTable,
//
// #[error("Undefined parameter")]
// UndefinedParam,
//
// #[error("Value required")]
// ValueRequired,
//
// #[error("Incompatible value")]
// IncompatibleValue,
//
// #[error("Wrong type")]
// WrongType,
//
// #[error("Cannot have global edge between local nodes")]
// IncompatibleEdge,
//
// #[error("Unexpected index columns found")]
// UnexpectedIndexColumns,
//
// #[error("Database already closed")]
// DatabaseClosed,
//
// #[error("Undefined table")]
// UndefinedTable,
//
// #[error("Undefined parameter")]
// UndefinedParam,
//
// #[error("Value required")]
// ValueRequired,
//
// #[error("Incompatible value")]
// IncompatibleValue,
//
// #[error("Wrong type")]
// WrongType,
//
// #[error("Cannot have global edge between local nodes")]
// IncompatibleEdge,
//
// #[error("Unexpected index columns found")]
// UnexpectedIndexColumns,
//
// #[error("Database already closed")]
// DatabaseClosed,
#[error("InvalidArgument")]
InvalidArgument,
@ -94,8 +92,8 @@ pub enum CozoError {
TypeMismatch,
// #[error(transparent)]
// Storage(#[from] cozo_rocks::BridgeStatus),
//
// Storage(#[from] cozo_rocks::BridgeStatus),
//
#[error(transparent)]
Io(#[from] std::io::Error),
@ -115,4 +113,4 @@ pub enum CozoError {
Bridge(#[from] BridgeError),
}
pub type Result<T> = result::Result<T, CozoError>;
pub type Result<T> = result::Result<T, CozoError>;

@ -11,10 +11,10 @@ extern crate core;
// pub mod storage;
// pub mod mutation;
// pub mod plan;
pub mod relation;
pub mod db;
pub mod error;
pub mod parser;
pub mod relation;
#[cfg(test)]
mod tests {
@ -24,4 +24,4 @@ mod tests {
let _o = OptionsPtr::default();
println!("Hello");
}
}
}

@ -1,13 +1,11 @@
pub mod text_identifier;
pub mod number;
pub mod text_identifier;
use pest_derive::Parser;
#[derive(Parser)]
#[grammar = "grammar.pest"]
pub struct Parser;
#[cfg(test)]
mod tests {
use super::*;
@ -20,7 +18,10 @@ mod tests {
assert_eq!(Parser::parse(Rule::ident, "x_y").unwrap().as_str(), "x_y");
assert_eq!(Parser::parse(Rule::ident, "x_").unwrap().as_str(), "x_");
assert_eq!(Parser::parse(Rule::ident, "你好").unwrap().as_str(), "你好");
assert_eq!(Parser::parse(Rule::ident, "你好123").unwrap().as_str(), "你好123");
assert_eq!(
Parser::parse(Rule::ident, "你好123").unwrap().as_str(),
"你好123"
);
assert_ne!(Parser::parse(Rule::ident, "x$y").unwrap().as_str(), "x$y");
assert_eq!(Parser::parse(Rule::ident, "_x").unwrap().as_str(), "_x");
@ -38,33 +39,95 @@ mod tests {
#[test]
fn strings() {
assert_eq!(Parser::parse(Rule::string, r#""""#).unwrap().as_str(), r#""""#);
assert_eq!(Parser::parse(Rule::string, r#"" b a c""#).unwrap().as_str(), r#"" b a c""#);
assert_eq!(Parser::parse(Rule::string, r#""你好👋""#).unwrap().as_str(), r#""你好👋""#);
assert_eq!(Parser::parse(Rule::string, r#""\n""#).unwrap().as_str(), r#""\n""#);
assert_eq!(Parser::parse(Rule::string, r#""\u5678""#).unwrap().as_str(), r#""\u5678""#);
assert_eq!(
Parser::parse(Rule::string, r#""""#).unwrap().as_str(),
r#""""#
);
assert_eq!(
Parser::parse(Rule::string, r#"" b a c""#).unwrap().as_str(),
r#"" b a c""#
);
assert_eq!(
Parser::parse(Rule::string, r#""你好👋""#).unwrap().as_str(),
r#""你好👋""#
);
assert_eq!(
Parser::parse(Rule::string, r#""\n""#).unwrap().as_str(),
r#""\n""#
);
assert_eq!(
Parser::parse(Rule::string, r#""\u5678""#).unwrap().as_str(),
r#""\u5678""#
);
assert!(Parser::parse(Rule::string, r#""\ux""#).is_err());
assert_eq!(Parser::parse(Rule::string, r###"r#"a"#"###).unwrap().as_str(), r##"r#"a"#"##);
assert_eq!(
Parser::parse(Rule::string, r###"r#"a"#"###)
.unwrap()
.as_str(),
r##"r#"a"#"##
);
}
#[test]
fn numbers() {
assert_eq!(Parser::parse(Rule::number, "123").unwrap().as_str(), "123");
assert_eq!(Parser::parse(Rule::number, "0").unwrap().as_str(), "0");
assert_eq!(Parser::parse(Rule::number, "0123").unwrap().as_str(), "0123");
assert_eq!(Parser::parse(Rule::number, "000_1").unwrap().as_str(), "000_1");
assert_eq!(
Parser::parse(Rule::number, "0123").unwrap().as_str(),
"0123"
);
assert_eq!(
Parser::parse(Rule::number, "000_1").unwrap().as_str(),
"000_1"
);
assert!(Parser::parse(Rule::number, "_000_1").is_err());
assert_eq!(Parser::parse(Rule::number, "0xAf03").unwrap().as_str(), "0xAf03");
assert_eq!(Parser::parse(Rule::number, "0o0_7067").unwrap().as_str(), "0o0_7067");
assert_ne!(Parser::parse(Rule::number, "0o0_7068").unwrap().as_str(), "0o0_7068");
assert_eq!(Parser::parse(Rule::number, "0b0000_0000_1111").unwrap().as_str(), "0b0000_0000_1111");
assert_ne!(Parser::parse(Rule::number, "0b0000_0000_1112").unwrap().as_str(), "0b0000_0000_1112");
assert_eq!(
Parser::parse(Rule::number, "0xAf03").unwrap().as_str(),
"0xAf03"
);
assert_eq!(
Parser::parse(Rule::number, "0o0_7067").unwrap().as_str(),
"0o0_7067"
);
assert_ne!(
Parser::parse(Rule::number, "0o0_7068").unwrap().as_str(),
"0o0_7068"
);
assert_eq!(
Parser::parse(Rule::number, "0b0000_0000_1111")
.unwrap()
.as_str(),
"0b0000_0000_1111"
);
assert_ne!(
Parser::parse(Rule::number, "0b0000_0000_1112")
.unwrap()
.as_str(),
"0b0000_0000_1112"
);
assert_eq!(Parser::parse(Rule::number, "123.45").unwrap().as_str(), "123.45");
assert_eq!(Parser::parse(Rule::number, "1_23.4_5_").unwrap().as_str(), "1_23.4_5_");
assert_ne!(Parser::parse(Rule::number, "123.").unwrap().as_str(), "123.");
assert_eq!(Parser::parse(Rule::number, "123.333e456").unwrap().as_str(), "123.333e456");
assert_eq!(Parser::parse(Rule::number, "1_23.33_3e45_6").unwrap().as_str(), "1_23.33_3e45_6");
assert_eq!(
Parser::parse(Rule::number, "123.45").unwrap().as_str(),
"123.45"
);
assert_eq!(
Parser::parse(Rule::number, "1_23.4_5_").unwrap().as_str(),
"1_23.4_5_"
);
assert_ne!(
Parser::parse(Rule::number, "123.").unwrap().as_str(),
"123."
);
assert_eq!(
Parser::parse(Rule::number, "123.333e456").unwrap().as_str(),
"123.333e456"
);
assert_eq!(
Parser::parse(Rule::number, "1_23.33_3e45_6")
.unwrap()
.as_str(),
"1_23.33_3e45_6"
);
}
#[test]

@ -1,11 +1,17 @@
use pest::iterators::Pair;
use crate::parser::Rule;
use crate::error::{CozoError, Result};
use crate::parser::number::parse_int;
use crate::parser::Rule;
use pest::iterators::Pair;
#[inline]
fn parse_raw_string(pair: Pair<Rule>) -> Result<String> {
Ok(pair.into_inner().into_iter().next().unwrap().as_str().to_string())
Ok(pair
.into_inner()
.into_iter()
.next()
.unwrap()
.as_str()
.to_string())
}
#[inline]
@ -29,13 +35,12 @@ fn parse_quoted_string(pair: Pair<Rule>) -> Result<String> {
ret.push(ch);
}
s if s.starts_with('\\') => return Err(CozoError::InvalidEscapeSequence),
s => ret.push_str(s)
s => ret.push_str(s),
}
}
Ok(ret)
}
#[inline]
fn parse_s_quoted_string(pair: Pair<Rule>) -> Result<String> {
let pairs = pair.into_inner().next().unwrap().into_inner();
@ -57,7 +62,7 @@ fn parse_s_quoted_string(pair: Pair<Rule>) -> Result<String> {
ret.push(ch);
}
s if s.starts_with('\\') => return Err(CozoError::InvalidEscapeSequence),
s => ret.push_str(s)
s => ret.push_str(s),
}
}
Ok(ret)
@ -70,7 +75,7 @@ pub fn parse_string(pair: Pair<Rule>) -> Result<String> {
Rule::s_quoted_string => Ok(parse_s_quoted_string(pair)?),
Rule::raw_string => Ok(parse_raw_string(pair)?),
Rule::ident => Ok(pair.as_str().to_string()),
_ => unreachable!()
_ => unreachable!(),
}
}
@ -83,7 +88,7 @@ pub fn build_name_in_def(pair: Pair<Rule>, forbid_underscore: bool) -> Result<St
let name = match inner.as_rule() {
Rule::ident => parse_ident(inner),
Rule::raw_string | Rule::s_quoted_string | Rule::quoted_string => parse_string(inner)?,
_ => unreachable!()
_ => unreachable!(),
};
if forbid_underscore && name.starts_with('_') {
Err(CozoError::ReservedIdent)

@ -1,6 +1,6 @@
pub mod tuple;
pub mod value;
pub mod data;
pub mod key_order;
pub mod typing;
pub mod table;
pub mod data;
pub mod tuple;
pub mod typing;
pub mod value;

@ -1,7 +1,7 @@
use std::borrow::Borrow;
use crate::relation::tuple::Tuple;
use crate::error::{CozoError, Result};
use crate::relation::tuple::Tuple;
use crate::relation::typing::Typing;
use std::borrow::Borrow;
#[repr(u32)]
#[derive(Ord, PartialOrd, Eq, PartialEq, Debug, Clone)]
@ -32,11 +32,13 @@ impl<T: AsRef<[u8]>> Tuple<T> {
5 => Val,
6 => Type,
u32::MAX => Empty,
v => return Err(CozoError::UndefinedDataKind(v))
v => return Err(CozoError::UndefinedDataKind(v)),
})
}
pub fn interpret_as_type(&self) -> Result<Typing> {
let text = self.get_text(0).ok_or_else(|| CozoError::BadDataFormat(self.as_ref().to_vec()))?;
let text = self
.get_text(0)
.ok_or_else(|| CozoError::BadDataFormat(self.as_ref().to_vec()))?;
Typing::try_from(text.borrow())
}
}
}

@ -1,5 +1,5 @@
use std::cmp::Ordering;
use crate::relation::tuple::Tuple;
use std::cmp::Ordering;
impl<T: AsRef<[u8]>, T2: AsRef<[u8]>> PartialOrd<Tuple<T2>> for Tuple<T> {
fn partial_cmp(&self, other: &Tuple<T2>) -> Option<Ordering> {
@ -24,16 +24,16 @@ pub fn compare(a: &[u8], b: &[u8]) -> i8 {
match ta.cmp(&tb) {
Ordering::Less => -1,
Ordering::Greater => 1,
Ordering::Equal => 0
Ordering::Equal => 0,
}
}
#[cfg(test)]
mod tests {
use std::collections::BTreeMap;
use crate::relation::key_order::compare;
use crate::relation::tuple::Tuple;
use crate::relation::value::Value;
use std::collections::BTreeMap;
#[test]
fn ordering() {
@ -56,8 +56,15 @@ mod tests {
t2.push_int(123);
assert_eq!(compare(t.as_ref(), t2.as_ref()), -1);
assert_eq!(compare(t.as_ref(), t.as_ref()), 0);
let vals: Value = vec![().into(), BTreeMap::new().into(), 1e23.into(), false.into(), "xxyx".into()].into();
let vals: Value = vec![
().into(),
BTreeMap::new().into(),
1e23.into(),
false.into(),
"xxyx".into(),
]
.into();
t.push_value(&vals);
assert_eq!(compare(t.as_ref(), t.as_ref()), 0);
}
}
}

@ -1,6 +1,6 @@
use std::cmp::Ordering;
use crate::relation::tuple::{CowTuple};
use crate::relation::tuple::CowTuple;
use crate::relation::typing::Typing;
use std::cmp::Ordering;
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Clone)]
pub struct StorageId {
@ -49,7 +49,10 @@ pub struct MegaTuple {
impl MegaTuple {
pub fn empty_tuple() -> Self {
MegaTuple { keys: vec![], vals: vec![] }
MegaTuple {
keys: vec![],
vals: vec![],
}
}
pub fn is_empty(&self) -> bool {
self.keys.is_empty()
@ -72,10 +75,10 @@ impl MegaTuple {
pub fn all_keys_cmp(&self, other: &Self) -> Ordering {
for (l, r) in self.keys.iter().zip(&other.keys) {
match l.key_part_cmp(r) {
Ordering::Equal => {},
v => return v
Ordering::Equal => {}
v => return v,
}
}
Ordering::Equal
}
}
}

@ -1,24 +1,28 @@
use std::borrow::{Cow};
use crate::db::table::{ColId, TableId};
use crate::relation::data::DataKind;
use crate::relation::value::{Tag, Value};
use cozorocks::SlicePtr;
use std::borrow::Cow;
use std::cell::RefCell;
use std::cmp::Ordering;
use std::collections::BTreeMap;
use std::fmt::{Debug, Formatter};
use std::hash::{Hash, Hasher};
use uuid::Uuid;
use cozorocks::SlicePtr;
use crate::db::table::{ColId, TableId};
use crate::relation::data::DataKind;
use crate::relation::value::{Tag, Value};
#[derive(Clone)]
pub struct Tuple<T>
where T: AsRef<[u8]>
where
T: AsRef<[u8]>,
{
pub data: T,
idx_cache: RefCell<Vec<usize>>,
}
impl<T> AsRef<[u8]> for Tuple<T> where T: AsRef<[u8]> {
impl<T> AsRef<[u8]> for Tuple<T>
where
T: AsRef<[u8]>,
{
fn as_ref(&self) -> &[u8] {
self.data.as_ref()
}
@ -55,7 +59,7 @@ impl AsRef<[u8]> for CowSlice {
fn as_ref(&self) -> &[u8] {
match self {
CowSlice::Ptr(s) => s.as_ref(),
CowSlice::Own(o) => o.as_ref()
CowSlice::Own(o) => o.as_ref(),
}
}
}
@ -76,7 +80,7 @@ impl CowTuple {
pub fn to_owned(self) -> OwnTuple {
match self.data {
CowSlice::Ptr(p) => OwnTuple::new(p.as_ref().to_vec()),
CowSlice::Own(o) => OwnTuple::new(o)
CowSlice::Own(o) => OwnTuple::new(o),
}
}
}
@ -120,7 +124,7 @@ impl<T: AsRef<[u8]>> Tuple<T> {
fn all_cached(&self) -> bool {
match self.idx_cache.borrow().last() {
None => self.data.as_ref().len() == PREFIX_LEN,
Some(l) => *l == self.data.as_ref().len()
Some(l) => *l == self.data.as_ref().len(),
}
}
#[inline]
@ -157,11 +161,9 @@ impl<T: AsRef<[u8]>> Tuple<T> {
let slen = slen as usize;
start + slen + offset
}
Tag::List |
Tag::Apply |
Tag::Dict |
Tag::IdxAccess |
Tag::FieldAccess => start + u32::from_be_bytes(data[start..start + 4].try_into().unwrap()) as usize,
Tag::List | Tag::Apply | Tag::Dict | Tag::IdxAccess | Tag::FieldAccess => {
start + u32::from_be_bytes(data[start..start + 4].try_into().unwrap()) as usize
}
Tag::TupleRef => {
let temp = start + 1 + self.parse_varint(start + 1).1 + 1;
temp + self.parse_varint(temp).1
@ -202,7 +204,7 @@ impl<T: AsRef<[u8]>> Tuple<T> {
}
Some(val)
}
None => None
None => None,
}
}
@ -210,7 +212,7 @@ impl<T: AsRef<[u8]>> Tuple<T> {
pub fn get_null(&self, idx: usize) -> Option<()> {
match self.get(idx)? {
Value::Null => Some(()),
_ => None
_ => None,
}
}
@ -218,7 +220,7 @@ impl<T: AsRef<[u8]>> Tuple<T> {
pub fn get_int(&self, idx: usize) -> Option<i64> {
match self.get(idx)? {
Value::Int(i) => Some(i),
_ => None
_ => None,
}
}
@ -226,7 +228,7 @@ impl<T: AsRef<[u8]>> Tuple<T> {
pub fn get_text(&self, idx: usize) -> Option<Cow<str>> {
match self.get(idx)? {
Value::Text(d) => Some(d),
_ => None
_ => None,
}
}
@ -234,16 +236,15 @@ impl<T: AsRef<[u8]>> Tuple<T> {
pub fn get_bool(&self, idx: usize) -> Option<bool> {
match self.get(idx)? {
Value::Bool(b) => Some(b),
_ => None
_ => None,
}
}
#[inline]
pub fn get_float(&self, idx: usize) -> Option<f64> {
match self.get(idx)? {
Value::Float(f) => Some(f.into_inner()),
_ => None
_ => None,
}
}
@ -251,7 +252,7 @@ impl<T: AsRef<[u8]>> Tuple<T> {
pub fn get_uuid(&self, idx: usize) -> Option<Uuid> {
match self.get(idx)? {
Value::Uuid(u) => Some(u),
_ => None
_ => None,
}
}
@ -259,7 +260,7 @@ impl<T: AsRef<[u8]>> Tuple<T> {
pub fn get_list(&self, idx: usize) -> Option<Vec<Value>> {
match self.get(idx)? {
Value::List(u) => Some(u),
_ => None
_ => None,
}
}
@ -267,7 +268,7 @@ impl<T: AsRef<[u8]>> Tuple<T> {
pub fn get_dict(&self, idx: usize) -> Option<BTreeMap<Cow<str>, Value>> {
match self.get(idx)? {
Value::Dict(u) => Some(u),
_ => None
_ => None,
}
}
@ -275,7 +276,7 @@ impl<T: AsRef<[u8]>> Tuple<T> {
pub fn get_variable(&self, idx: usize) -> Option<Cow<str>> {
match self.get(idx)? {
Value::Variable(u) => Some(u),
_ => None
_ => None,
}
}
@ -283,7 +284,7 @@ impl<T: AsRef<[u8]>> Tuple<T> {
pub fn get_apply(&self, idx: usize) -> Option<(Cow<str>, Vec<Value>)> {
match self.get(idx)? {
Value::Apply(n, l) => Some((n, l)),
_ => None
_ => None,
}
}
@ -293,7 +294,7 @@ impl<T: AsRef<[u8]>> Tuple<T> {
let start = pos + 1;
let tag = match Tag::try_from(data[pos]) {
Ok(t) => t,
Err(e) => panic!("Cannot parse tag {} for {:?}", e, data)
Err(e) => panic!("Cannot parse tag {} for {:?}", e, data),
};
let (nxt, val): (usize, Value) = match tag {
Tag::Null => (start, ().into()),
@ -304,8 +305,14 @@ impl<T: AsRef<[u8]>> Tuple<T> {
let val = Self::varint_to_zigzag(u);
(start + offset, val.into())
}
Tag::Float => (start + 8, f64::from_be_bytes(data[start..start + 8].try_into().unwrap()).into()),
Tag::Uuid => (start + 16, Uuid::from_slice(&data[start..start + 16]).unwrap().into()),
Tag::Float => (
start + 8,
f64::from_be_bytes(data[start..start + 8].try_into().unwrap()).into(),
),
Tag::Uuid => (
start + 16,
Uuid::from_slice(&data[start..start + 16]).unwrap().into(),
),
Tag::Text => {
let (slen, offset) = self.parse_varint(start);
let slen = slen as usize;
@ -325,7 +332,8 @@ impl<T: AsRef<[u8]>> Tuple<T> {
(start + slen + offset, Value::Variable(s.into()))
}
Tag::List => {
let end_pos = start + u32::from_be_bytes(data[start..start + 4].try_into().unwrap()) as usize;
let end_pos =
start + u32::from_be_bytes(data[start..start + 4].try_into().unwrap()) as usize;
let mut start_pos = start + 4;
let mut collected = vec![];
while start_pos < end_pos {
@ -336,14 +344,15 @@ impl<T: AsRef<[u8]>> Tuple<T> {
(end_pos, collected.into())
}
Tag::Apply => {
let end_pos = start + u32::from_be_bytes(data[start..start + 4].try_into().unwrap()) as usize;
let end_pos =
start + u32::from_be_bytes(data[start..start + 4].try_into().unwrap()) as usize;
let mut start_pos = start + 4;
let mut collected = vec![];
let (val, new_pos) = self.parse_value_at(start_pos);
start_pos = new_pos;
let op = match val {
Value::Variable(s) => s,
_ => panic!("Corrupt data when parsing Apply")
_ => panic!("Corrupt data when parsing Apply"),
};
while start_pos < end_pos {
let (val, new_pos) = self.parse_value_at(start_pos);
@ -353,7 +362,8 @@ impl<T: AsRef<[u8]>> Tuple<T> {
(end_pos, Value::Apply(op, collected))
}
Tag::Dict => {
let end_pos = start + u32::from_be_bytes(data[start..start + 4].try_into().unwrap()) as usize;
let end_pos =
start + u32::from_be_bytes(data[start..start + 4].try_into().unwrap()) as usize;
let mut start_pos = start + 4;
let mut collected: BTreeMap<Cow<str>, Value> = BTreeMap::new();
while start_pos < end_pos {
@ -371,7 +381,8 @@ impl<T: AsRef<[u8]>> Tuple<T> {
}
Tag::MaxTag => (start, Value::EndSentinel),
Tag::IdxAccess => {
let end_pos = start + u32::from_be_bytes(data[start..start + 4].try_into().unwrap()) as usize;
let end_pos =
start + u32::from_be_bytes(data[start..start + 4].try_into().unwrap()) as usize;
let mut start_pos = start + 4;
let (idx, offset) = self.parse_varint(start_pos);
start_pos += offset;
@ -379,7 +390,8 @@ impl<T: AsRef<[u8]>> Tuple<T> {
(end_pos, Value::IdxAccess(idx as usize, val.into()))
}
Tag::FieldAccess => {
let end_pos = start + u32::from_be_bytes(data[start..start + 4].try_into().unwrap()) as usize;
let end_pos =
start + u32::from_be_bytes(data[start..start + 4].try_into().unwrap()) as usize;
let mut start_pos = start + 4;
let (slen, offset) = self.parse_varint(start);
@ -398,9 +410,19 @@ impl<T: AsRef<[u8]>> Tuple<T> {
let (tidu, parse_len) = self.parse_varint(start + 1);
let is_key = self.parse_value_at(parse_len + start + 1).0 == Value::Bool(true);
let (cidu, parse_len2) = self.parse_varint(start + 1 + parse_len + 1);
(start + 1 + parse_len + 1 + parse_len2,
Value::TupleRef(TableId { in_root, id: Self::varint_to_zigzag(tidu) },
ColId { is_key, id: Self::varint_to_zigzag(cidu) }))
(
start + 1 + parse_len + 1 + parse_len2,
Value::TupleRef(
TableId {
in_root,
id: Self::varint_to_zigzag(tidu),
},
ColId {
is_key,
id: Self::varint_to_zigzag(cidu),
},
),
)
}
};
(val, nxt)
@ -431,8 +453,12 @@ impl<T: AsRef<[u8]>> Debug for Tuple<T> {
write!(f, "Tuple<{}>{{", self.get_prefix())?;
}
}
let strings = self.iter().enumerate().map(|(i, v)| format!("{}: {}", i, v))
.collect::<Vec<_>>().join(", ");
let strings = self
.iter()
.enumerate()
.map(|(i, v)| format!("{}: {}", i, v))
.collect::<Vec<_>>()
.join(", ");
write!(f, "{}}}", strings)
}
}
@ -641,7 +667,6 @@ impl OwnTuple {
}
}
#[inline]
fn push_varint(&mut self, u: u64) {
let mut u = u;
@ -687,7 +712,7 @@ impl OwnTuple {
impl<'a> Extend<Value<'a>> for OwnTuple {
#[inline]
fn extend<T: IntoIterator<Item=Value<'a>>>(&mut self, iter: T) {
fn extend<T: IntoIterator<Item = Value<'a>>>(&mut self, iter: T) {
for v in iter {
self.push_value(&v)
}
@ -709,11 +734,10 @@ impl<T: AsRef<[u8]>> Hash for Tuple<T> {
impl<T: AsRef<[u8]>> Eq for Tuple<T> {}
#[cfg(test)]
mod tests {
use std::collections::BTreeMap;
use super::*;
use std::collections::BTreeMap;
#[test]
fn serde() {
@ -724,11 +748,7 @@ mod tests {
t.push_null();
t.push_str("abcdef");
t.push_null();
t.push_value(&vec![
true.into(),
1e236.into(),
"xxyyzz".into(),
].into());
t.push_value(&vec![true.into(), 1e236.into(), "xxyyzz".into()].into());
t.push_int(-123345);
t.push_value(&BTreeMap::from([]).into());
t.push_int(12121212);
@ -758,11 +778,14 @@ mod tests {
assert_eq!(Value::Null, t.get(5).unwrap());
t3.get_pos(6);
assert_eq!(t.idx_cache.borrow().last(), t3.idx_cache.borrow().last());
assert_eq!(Value::from(Value::from(vec![
true.into(),
1e236.into(),
"xxyyzz".into(),
])), t.get(6).unwrap());
assert_eq!(
Value::from(Value::from(vec![
true.into(),
1e236.into(),
"xxyyzz".into(),
])),
t.get(6).unwrap()
);
t3.get_pos(7);
assert_eq!(t.idx_cache.borrow().last(), t3.idx_cache.borrow().last());
assert_eq!(Value::from(-123345i64), t.get(7).unwrap());
@ -774,7 +797,10 @@ mod tests {
assert_eq!(Value::from(12121212i64), t.get(9).unwrap());
t3.get_pos(10);
assert_eq!(t.idx_cache.borrow().last(), t3.idx_cache.borrow().last());
assert_eq!(Value::from(BTreeMap::from([("yzyz".into(), "fifo".into())])), t.get(10).unwrap());
assert_eq!(
Value::from(BTreeMap::from([("yzyz".into(), "fifo".into())])),
t.get(10).unwrap()
);
t3.get_pos(11);
assert_eq!(t.idx_cache.borrow().last(), t3.idx_cache.borrow().last());
assert_eq!(Value::from(1e245), t.get(11).unwrap());
@ -797,14 +823,20 @@ mod tests {
assert_eq!(Value::from(BTreeMap::new()), t.get(8).unwrap());
assert_eq!(Value::Null, t.get(3).unwrap());
assert_eq!(Value::from("abcdef"), t.get(4).unwrap());
assert_eq!(Value::from(Value::from(vec![
true.into(),
1e236.into(),
"xxyyzz".into(),
])), t.get(6).unwrap());
assert_eq!(
Value::from(Value::from(vec![
true.into(),
1e236.into(),
"xxyyzz".into(),
])),
t.get(6).unwrap()
);
assert_eq!(None, t.get(13));
assert_eq!(Value::from(-123345i64), t.get(7).unwrap());
assert_eq!(Value::from(BTreeMap::from([("yzyz".into(), "fifo".into())])), t.get(10).unwrap());
assert_eq!(
Value::from(BTreeMap::from([("yzyz".into(), "fifo".into())])),
t.get(10).unwrap()
);
assert_eq!(None, t.get(13131));
println!("{:?}", t.iter().collect::<Vec<Value>>());
@ -834,4 +866,4 @@ mod tests {
v.push_int(-64);
println!("{:?} {:?}", v, v.data);
}
}
}

@ -1,14 +1,13 @@
use std::fmt::{Display, Formatter};
use pest::iterators::Pair;
use crate::error::{Result, CozoError};
use crate::relation::value::Value;
use pest::Parser as PestParser;
use crate::db::engine::Session;
use crate::error::{CozoError, Result};
use crate::parser::text_identifier::build_name_in_def;
use crate::parser::Parser;
use crate::parser::Rule;
use crate::parser::text_identifier::build_name_in_def;
use crate::relation::data::DataKind;
use crate::relation::value::Value;
use pest::iterators::Pair;
use pest::Parser as PestParser;
use std::fmt::{Display, Formatter};
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Clone)]
pub enum Typing {
@ -42,15 +41,21 @@ impl Display for Typing {
write!(f, "({})", joined)
}
Typing::NamedTuple(n) => {
let collected = n.iter().map(|(k, v)|
format!(r##""{}":{}"##, k, v)).collect::<Vec<_>>();
let collected = n
.iter()
.map(|(k, v)| format!(r##""{}":{}"##, k, v))
.collect::<Vec<_>>();
let joined = collected.join(",");
write!(f, "{{")?;
write!(f, "{}", joined)?;
write!(f, "}}")
}
Typing::Function(args, ret) => {
let args_display = args.iter().map(|t| t.to_string()).collect::<Vec<_>>().join(",");
let args_display = args
.iter()
.map(|t| t.to_string())
.collect::<Vec<_>>()
.join(",");
write!(f, "<{}>->{}", args_display, ret)
}
}
@ -69,7 +74,7 @@ impl Typing {
}
impl Typing {
pub fn from_pair<'a, 't>(pair: Pair<Rule>, env: Option<&Session<'a>>) -> Result<Self> {
pub fn from_pair<'a>(pair: Pair<Rule>, env: Option<&Session<'a>>) -> Result<Self> {
Ok(match pair.as_rule() {
Rule::simple_type => match pair.as_str() {
"Any" => Typing::Any,
@ -78,52 +83,67 @@ impl Typing {
"Float" => Typing::Float,
"Text" => Typing::Text,
"Uuid" => Typing::Uuid,
t => {
match env {
None => return Err(CozoError::UndefinedType(t.to_string())),
Some(env) => {
let resolved = env.resolve(t)?;
let resolved = resolved.ok_or_else(|| CozoError::UndefinedType(t.to_string()))?;
match resolved.data_kind()? {
DataKind::Type => resolved.interpret_as_type()?,
_ => return Err(CozoError::UndefinedType(t.to_string()))
}
t => match env {
None => return Err(CozoError::UndefinedType(t.to_string())),
Some(env) => {
let resolved = env.resolve(t)?;
let resolved =
resolved.ok_or_else(|| CozoError::UndefinedType(t.to_string()))?;
match resolved.data_kind()? {
DataKind::Type => resolved.interpret_as_type()?,
_ => return Err(CozoError::UndefinedType(t.to_string())),
}
}
}
},
},
Rule::nullable_type => Typing::Nullable(Box::new(Typing::from_pair(pair.into_inner().next().unwrap(), env)?)),
Rule::homogeneous_list_type => Typing::Homogeneous(Box::new(Typing::from_pair(pair.into_inner().next().unwrap(), env)?)),
Rule::nullable_type => Typing::Nullable(Box::new(Typing::from_pair(
pair.into_inner().next().unwrap(),
env,
)?)),
Rule::homogeneous_list_type => Typing::Homogeneous(Box::new(Typing::from_pair(
pair.into_inner().next().unwrap(),
env,
)?)),
Rule::unnamed_tuple_type => {
let types = pair.into_inner().map(|p| Typing::from_pair(p, env)).collect::<Result<Vec<Typing>>>()?;
let types = pair
.into_inner()
.map(|p| Typing::from_pair(p, env))
.collect::<Result<Vec<Typing>>>()?;
Typing::UnnamedTuple(types)
}
Rule::named_tuple_type => {
let types = pair.into_inner().map(|p| -> Result<(String, Typing)> {
let mut ps = p.into_inner();
let name_pair = ps.next().unwrap();
let name = build_name_in_def(name_pair, true)?;
let typ_pair = ps.next().unwrap();
let typ = Typing::from_pair(typ_pair, env)?;
Ok((name, typ))
}).collect::<Result<Vec<(String, Typing)>>>()?;
let types = pair
.into_inner()
.map(|p| -> Result<(String, Typing)> {
let mut ps = p.into_inner();
let name_pair = ps.next().unwrap();
let name = build_name_in_def(name_pair, true)?;
let typ_pair = ps.next().unwrap();
let typ = Typing::from_pair(typ_pair, env)?;
Ok((name, typ))
})
.collect::<Result<Vec<(String, Typing)>>>()?;
Typing::NamedTuple(types)
}
Rule::function_type => {
let mut pairs = pair.into_inner();
let args = pairs.next().unwrap().into_inner()
.map(|p| Typing::from_pair(p, env)).collect::<Result<Vec<_>>>()?;
let args = pairs
.next()
.unwrap()
.into_inner()
.map(|p| Typing::from_pair(p, env))
.collect::<Result<Vec<_>>>()?;
let ret = Typing::from_pair(pairs.next().unwrap(), env)?;
Typing::Function(args, ret.into())
}
_ => unreachable!()
_ => unreachable!(),
})
}
pub fn extract_named_tuple(self) -> Option<Vec<(String, Typing)>> {
match self {
Typing::NamedTuple(t) => Some(t),
_ => None
_ => None,
}
}
@ -149,14 +169,14 @@ impl Typing {
Typing::Float => self.coerce_float(v),
Typing::Text => self.coerce_text(v),
Typing::Uuid => self.coerce_uuid(v),
Typing::Homogeneous(t) => {
match v {
Value::List(vs) => {
Ok(Value::List(vs.into_iter().map(|v| t.coerce(v)).collect::<Result<Vec<_>>>()?))
}
_ => Err(CozoError::TypeMismatch)
}
}
Typing::Homogeneous(t) => match v {
Value::List(vs) => Ok(Value::List(
vs.into_iter()
.map(|v| t.coerce(v))
.collect::<Result<Vec<_>>>()?,
)),
_ => Err(CozoError::TypeMismatch),
},
Typing::UnnamedTuple(_ut) => {
todo!()
}
@ -165,37 +185,39 @@ impl Typing {
}
Typing::Any => unreachable!(),
Typing::Nullable(_) => unreachable!(),
Typing::Function(_, _) => Err(CozoError::LogicError("Cannot coerce function types".to_string()))
Typing::Function(_, _) => Err(CozoError::LogicError(
"Cannot coerce function types".to_string(),
)),
}
}
fn coerce_bool<'a>(&self, v: Value<'a>) -> Result<Value<'a>> {
match v {
v @ Value::Bool(_) => Ok(v),
_ => Err(CozoError::TypeMismatch)
_ => Err(CozoError::TypeMismatch),
}
}
fn coerce_int<'a>(&self, v: Value<'a>) -> Result<Value<'a>> {
match v {
v @ Value::Int(_) => Ok(v),
_ => Err(CozoError::TypeMismatch)
_ => Err(CozoError::TypeMismatch),
}
}
fn coerce_float<'a>(&self, v: Value<'a>) -> Result<Value<'a>> {
match v {
v @ Value::Float(_) => Ok(v),
_ => Err(CozoError::TypeMismatch)
_ => Err(CozoError::TypeMismatch),
}
}
fn coerce_text<'a>(&self, v: Value<'a>) -> Result<Value<'a>> {
match v {
v @ Value::Text(_) => Ok(v),
_ => Err(CozoError::TypeMismatch)
_ => Err(CozoError::TypeMismatch),
}
}
fn coerce_uuid<'a>(&self, v: Value<'a>) -> Result<Value<'a>> {
match v {
v @ Value::Uuid(_) => Ok(v),
_ => Err(CozoError::TypeMismatch)
_ => Err(CozoError::TypeMismatch),
}
}
}
@ -217,7 +239,10 @@ mod tests {
#[test]
fn to_string() {
assert_eq!(
format!("{}", Typing::Nullable(Box::new(Typing::Homogeneous(Box::new(Typing::Text))))),
format!(
"{}",
Typing::Nullable(Box::new(Typing::Homogeneous(Box::new(Typing::Text))))
),
"?[Text]"
);
}
@ -246,4 +271,4 @@ mod tests {
println!("{:#?}", res);
assert!(res.is_ok());
}
}
}

@ -1,19 +1,18 @@
use std::borrow::Cow;
use std::collections::BTreeMap;
use std::fmt::{Debug, Display, Formatter, Write};
use lazy_static::lazy_static;
use pest::prec_climber::{Assoc, PrecClimber, Operator};
use ordered_float::OrderedFloat;
use pest::Parser as PestParser;
use pest::iterators::Pair;
use uuid::Uuid;
use crate::db::table::{ColId, TableId};
use crate::parser::{Parser, Rule};
use crate::error::{CozoError, Result};
use crate::error::CozoError::LogicError;
use crate::error::{CozoError, Result};
use crate::parser::number::parse_int;
use crate::parser::text_identifier::parse_string;
use crate::parser::{Parser, Rule};
use lazy_static::lazy_static;
use ordered_float::OrderedFloat;
use pest::iterators::Pair;
use pest::prec_climber::{Assoc, Operator, PrecClimber};
use pest::Parser as PestParser;
use std::borrow::Cow;
use std::collections::BTreeMap;
use std::fmt::{Debug, Display, Formatter, Write};
use uuid::Uuid;
#[repr(u8)]
#[derive(Ord, PartialOrd, Eq, PartialEq)]
@ -60,7 +59,7 @@ impl TryFrom<u8> for Tag {
253 => Variable,
254 => Apply,
255 => MaxTag,
v => return Err(v)
v => return Err(v),
})
}
}
@ -91,7 +90,6 @@ impl TryFrom<u8> for Tag {
// C64Arr = 73,
// C128Arr = 74,
#[derive(Clone, PartialEq, Ord, PartialOrd, Eq)]
pub enum Value<'a> {
// evaluated
@ -107,7 +105,7 @@ pub enum Value<'a> {
// not evaluated
Variable(Cow<'a, str>),
TupleRef(TableId, ColId),
Apply(Cow<'a, str>, Vec<Value<'a>>), // TODO optimization: special case for small number of args (esp. 0, 1, 2)
Apply(Cow<'a, str>, Vec<Value<'a>>), // TODO optimization: special case for small number of args (esp. 0, 1, 2)
FieldAccess(Cow<'a, str>, Box<Value<'a>>),
IdxAccess(usize, Box<Value<'a>>),
// cannot exist
@ -116,7 +114,7 @@ pub enum Value<'a> {
pub type StaticValue = Value<'static>;
impl <'a> Debug for Value<'a> {
impl<'a> Debug for Value<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "Value {{ {} }}", self)
}
@ -133,41 +131,47 @@ impl<'a> Value<'a> {
Value::Uuid(u) => Value::from(u),
Value::Text(t) => Value::from(t.into_owned()),
Value::Variable(s) => Value::Variable(Cow::Owned(s.into_owned())),
Value::List(l) => l.into_iter().map(|v| v.to_static()).collect::<Vec<StaticValue>>().into(),
Value::Apply(op, args) => {
Value::Apply(Cow::Owned(op.into_owned()),
args.into_iter().map(|v| v.to_static()).collect::<Vec<StaticValue>>())
}
Value::Dict(d) => d.into_iter()
Value::List(l) => l
.into_iter()
.map(|v| v.to_static())
.collect::<Vec<StaticValue>>()
.into(),
Value::Apply(op, args) => Value::Apply(
Cow::Owned(op.into_owned()),
args.into_iter()
.map(|v| v.to_static())
.collect::<Vec<StaticValue>>(),
),
Value::Dict(d) => d
.into_iter()
.map(|(k, v)| (Cow::Owned(k.into_owned()), v.to_static()))
.collect::<BTreeMap<Cow<'static, str>, StaticValue>>().into(),
.collect::<BTreeMap<Cow<'static, str>, StaticValue>>()
.into(),
Value::EndSentinel => panic!("Cannot process sentinel value"),
Value::FieldAccess(field, value) => {
Value::FieldAccess(Cow::from(field.into_owned()), value.to_static().into())
}
Value::IdxAccess(idx, value) => {
Value::IdxAccess(idx, value.to_static().into())
}
Value::TupleRef(tid, cid) => Value::TupleRef(tid, cid)
Value::IdxAccess(idx, value) => Value::IdxAccess(idx, value.to_static().into()),
Value::TupleRef(tid, cid) => Value::TupleRef(tid, cid),
}
}
#[inline]
pub fn is_evaluated(&self) -> bool {
match self {
Value::Null |
Value::Bool(_) |
Value::Int(_) |
Value::Float(_) |
Value::Uuid(_) |
Value::Text(_) |
Value::EndSentinel => true,
Value::Null
| Value::Bool(_)
| Value::Int(_)
| Value::Float(_)
| Value::Uuid(_)
| Value::Text(_)
| Value::EndSentinel => true,
Value::List(l) => l.iter().all(|v| v.is_evaluated()),
Value::Dict(d) => d.values().all(|v| v.is_evaluated()),
Value::Variable(_) => false,
Value::Apply(_, _) => false,
Value::FieldAccess(_, _) => false,
Value::IdxAccess(_, _) => false,
Value::TupleRef(_, _) => false
Value::TupleRef(_, _) => false,
}
}
#[inline]
@ -182,7 +186,9 @@ impl<'a> Value<'a> {
Value::from_pair(pair)
}
pub fn extract_relevant_tables<T: Iterator<Item=Self>>(data: T) -> Result<(Vec<Self>, Vec<TableId>)> {
pub fn extract_relevant_tables<T: Iterator<Item = Self>>(
data: T,
) -> Result<(Vec<Self>, Vec<TableId>)> {
let mut coll = vec![];
let mut res = Vec::with_capacity(data.size_hint().1.unwrap_or(0));
for v in data {
@ -193,24 +199,23 @@ impl<'a> Value<'a> {
fn do_extract_relevant_tables(self, coll: &mut Vec<TableId>) -> Result<Self> {
Ok(match self {
v @ (Value::Null |
Value::Bool(_) |
Value::Int(_) |
Value::Float(_) |
Value::Uuid(_) |
Value::Text(_) |
Value::Variable(_)) => v,
Value::List(l) => {
Value::List(l.into_iter()
v @ (Value::Null
| Value::Bool(_)
| Value::Int(_)
| Value::Float(_)
| Value::Uuid(_)
| Value::Text(_)
| Value::Variable(_)) => v,
Value::List(l) => Value::List(
l.into_iter()
.map(|v| v.do_extract_relevant_tables(coll))
.collect::<Result<Vec<_>>>()?)
}
Value::Dict(d) => {
Value::Dict(d.into_iter()
.map(|(k, v)|
v.do_extract_relevant_tables(coll).map(|v| (k, v)))
.collect::<Result<BTreeMap<_, _>>>()?)
}
.collect::<Result<Vec<_>>>()?,
),
Value::Dict(d) => Value::Dict(
d.into_iter()
.map(|(k, v)| v.do_extract_relevant_tables(coll).map(|v| (k, v)))
.collect::<Result<BTreeMap<_, _>>>()?,
),
Value::TupleRef(tid, cid) => {
let pos = coll.iter().position(|id| id == &tid).unwrap_or_else(|| {
let olen = coll.len();
@ -219,11 +224,12 @@ impl<'a> Value<'a> {
});
Value::TupleRef((false, pos).into(), cid)
}
Value::Apply(op, args) => {
Value::Apply(op, args.into_iter()
Value::Apply(op, args) => Value::Apply(
op,
args.into_iter()
.map(|v| v.do_extract_relevant_tables(coll))
.collect::<Result<Vec<_>>>()?)
}
.collect::<Result<Vec<_>>>()?,
),
Value::FieldAccess(field, arg) => {
Value::FieldAccess(field, arg.do_extract_relevant_tables(coll)?.into())
}
@ -272,7 +278,6 @@ impl From<f64> for StaticValue {
}
}
impl From<OrderedFloat<f64>> for StaticValue {
#[inline]
fn from(f: OrderedFloat<f64>) -> Self {
@ -315,28 +320,55 @@ impl<'a> From<BTreeMap<Cow<'a, str>, Value<'a>>> for Value<'a> {
}
}
impl<'a> Display for Value<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Value::Null => { write!(f, "null")?; }
Value::Bool(b) => { write!(f, "{}", if *b { "true" } else { "false" })?; }
Value::Int(i) => { write!(f, "{}", i)?; }
Value::Float(n) => { write!(f, "{}", n.into_inner())?; }
Value::Uuid(u) => { write!(f, "{}", u)?; }
Value::Null => {
write!(f, "null")?;
}
Value::Bool(b) => {
write!(f, "{}", if *b { "true" } else { "false" })?;
}
Value::Int(i) => {
write!(f, "{}", i)?;
}
Value::Float(n) => {
write!(f, "{}", n.into_inner())?;
}
Value::Uuid(u) => {
write!(f, "{}", u)?;
}
Value::Text(t) => {
f.write_char('"')?;
for char in t.chars() {
match char {
'"' => { f.write_str("\\\"")?; }
'\\' => { f.write_str("\\\\")?; }
'/' => { f.write_str("\\/")?; }
'\x08' => { f.write_str("\\b")?; }
'\x0c' => { f.write_str("\\f")?; }
'\n' => { f.write_str("\\n")?; }
'\r' => { f.write_str("\\r")?; }
'\t' => { f.write_str("\\t")?; }
c => { f.write_char(c)?; }
'"' => {
f.write_str("\\\"")?;
}
'\\' => {
f.write_str("\\\\")?;
}
'/' => {
f.write_str("\\/")?;
}
'\x08' => {
f.write_str("\\b")?;
}
'\x0c' => {
f.write_str("\\f")?;
}
'\n' => {
f.write_str("\\n")?;
}
'\r' => {
f.write_str("\\r")?;
}
'\t' => {
f.write_str("\\t")?;
}
c => {
f.write_char(c)?;
}
}
}
f.write_char('"')?;
@ -367,15 +399,18 @@ impl<'a> Display for Value<'a> {
}
f.write_char('}')?;
}
Value::Variable(s) => {
write!(f, "`{}`", s)?
}
Value::EndSentinel => {
write!(f, "Sentinel")?
}
Value::Variable(s) => write!(f, "`{}`", s)?,
Value::EndSentinel => write!(f, "Sentinel")?,
Value::Apply(op, args) => {
write!(f, "({} {})", op,
args.iter().map(|v| v.to_string()).collect::<Vec<_>>().join(" "))?;
write!(
f,
"({} {})",
op,
args.iter()
.map(|v| v.to_string())
.collect::<Vec<_>>()
.join(" ")
)?;
}
Value::FieldAccess(field, value) => {
write!(f, "(.{} {})", field, value)?;
@ -384,7 +419,14 @@ impl<'a> Display for Value<'a> {
write!(f, "(.{} {})", idx, value)?;
}
Value::TupleRef(tid, cid) => {
write!(f, "#{}{}.{}{}", if tid.in_root { 'G' } else { 'L' }, tid.id, if cid.is_key { 'K' } else { 'D' }, cid.id)?;
write!(
f,
"#{}{}.{}{}",
if tid.in_root { 'G' } else { 'L' },
tid.id,
if cid.is_key { 'K' } else { 'D' },
cid.id
)?;
}
}
Ok(())
@ -398,13 +440,18 @@ lazy_static! {
PrecClimber::new(vec![
Operator::new(Rule::op_or, Left),
Operator::new(Rule::op_and, Left),
Operator::new(Rule::op_gt, Left) | Operator::new(Rule::op_lt, Left) | Operator::new(Rule::op_ge,Left) | Operator::new(Rule::op_le, Left),
Operator::new(Rule::op_gt, Left)
| Operator::new(Rule::op_lt, Left)
| Operator::new(Rule::op_ge, Left)
| Operator::new(Rule::op_le, Left),
Operator::new(Rule::op_mod, Left),
Operator::new(Rule::op_eq, Left) | Operator::new(Rule::op_ne, Left),
Operator::new(Rule::op_add, Left) | Operator::new(Rule::op_sub, Left) | Operator::new(Rule::op_str_cat, Left),
Operator::new(Rule::op_add, Left)
| Operator::new(Rule::op_sub, Left)
| Operator::new(Rule::op_str_cat, Left),
Operator::new(Rule::op_mul, Left) | Operator::new(Rule::op_div, Left),
Operator::new(Rule::op_pow, Assoc::Right),
Operator::new(Rule::op_coalesce, Assoc::Left)
Operator::new(Rule::op_coalesce, Assoc::Left),
])
};
}
@ -432,8 +479,11 @@ pub const METHOD_NOT_NULL: &str = "not_null";
pub const METHOD_CONCAT: &str = "concat";
pub const METHOD_MERGE: &str = "merge";
fn build_expr_infix<'a>(lhs: Result<Value<'a>>, op: Pair<Rule>, rhs: Result<Value<'a>>) -> Result<Value<'a>> {
fn build_expr_infix<'a>(
lhs: Result<Value<'a>>,
op: Pair<Rule>,
rhs: Result<Value<'a>>,
) -> Result<Value<'a>> {
let lhs = lhs?;
let rhs = rhs?;
let op = match op.as_rule() {
@ -453,12 +503,11 @@ fn build_expr_infix<'a>(lhs: Result<Value<'a>>, op: Pair<Rule>, rhs: Result<Valu
Rule::op_le => OP_LE,
Rule::op_pow => OP_POW,
Rule::op_coalesce => OP_COALESCE,
_ => unreachable!()
_ => unreachable!(),
};
Ok(Value::Apply(op.into(), vec![lhs, rhs]))
}
fn build_expr_primary(pair: Pair<Rule>) -> Result<Value> {
match pair.as_rule() {
Rule::expr => build_expr_primary(pair.into_inner().next().unwrap()),
@ -483,7 +532,7 @@ fn build_expr_primary(pair: Pair<Rule>) -> Result<Value> {
args.extend(pairs.map(Value::from_pair).collect::<Result<Vec<_>>>()?);
head = Value::Apply(method_name.into(), args);
}
_ => todo!()
_ => todo!(),
}
}
Ok(head)
@ -498,7 +547,7 @@ fn build_expr_primary(pair: Pair<Rule>) -> Result<Value> {
Rule::term => return build_expr_primary(p),
Rule::negate => OP_NEGATE,
Rule::minus => OP_MINUS,
_ => unreachable!()
_ => unreachable!(),
};
let term = build_expr_primary(inner.next().unwrap())?;
Ok(Value::Apply(op.into(), vec![term]))
@ -508,11 +557,14 @@ fn build_expr_primary(pair: Pair<Rule>) -> Result<Value> {
Rule::hex_pos_int => Ok(Value::Int(parse_int(pair.as_str(), 16))),
Rule::octo_pos_int => Ok(Value::Int(parse_int(pair.as_str(), 8))),
Rule::bin_pos_int => Ok(Value::Int(parse_int(pair.as_str(), 2))),
Rule::dot_float | Rule::sci_float => Ok(Value::Float(pair.as_str().replace('_', "").parse::<f64>()?.into())),
Rule::dot_float | Rule::sci_float => Ok(Value::Float(
pair.as_str().replace('_', "").parse::<f64>()?.into(),
)),
Rule::null => Ok(Value::Null),
Rule::boolean => Ok(Value::Bool(pair.as_str() == "true")),
Rule::quoted_string | Rule::s_quoted_string | Rule::raw_string => Ok(
Value::Text(Cow::Owned(parse_string(pair)?))),
Rule::quoted_string | Rule::s_quoted_string | Rule::raw_string => {
Ok(Value::Text(Cow::Owned(parse_string(pair)?)))
}
Rule::list => {
let mut spread_collected = vec![];
let mut collected = vec![];
@ -522,8 +574,14 @@ fn build_expr_primary(pair: Pair<Rule>) -> Result<Value> {
Rule::spreading => {
let el = p.into_inner().next().unwrap();
let to_concat = Value::from_pair(el)?;
if !matches!(to_concat, Value::List(_) | Value::Variable(_) |
Value::IdxAccess(_, _) | Value:: FieldAccess(_, _) | Value::Apply(_, _)) {
if !matches!(
to_concat,
Value::List(_)
| Value::Variable(_)
| Value::IdxAccess(_, _)
| Value::FieldAccess(_, _)
| Value::Apply(_, _)
) {
return Err(CozoError::LogicError("Cannot spread".to_string()));
}
if !collected.is_empty() {
@ -532,7 +590,7 @@ fn build_expr_primary(pair: Pair<Rule>) -> Result<Value> {
}
spread_collected.push(to_concat);
}
_ => unreachable!()
_ => unreachable!(),
}
}
if spread_collected.is_empty() {
@ -556,15 +614,23 @@ fn build_expr_primary(pair: Pair<Rule>) -> Result<Value> {
}
Rule::scoped_accessor => {
let name = parse_string(p.into_inner().next().unwrap())?;
let val = Value::FieldAccess(name.clone().into(),
Value::Variable("_".into()).into());
let val = Value::FieldAccess(
name.clone().into(),
Value::Variable("_".into()).into(),
);
collected.insert(name.into(), val);
}
Rule::spreading => {
let el = p.into_inner().next().unwrap();
let to_concat = build_expr_primary(el)?;
if !matches!(to_concat, Value::Dict(_) | Value::Variable(_) |
Value::IdxAccess(_, _) | Value:: FieldAccess(_, _) | Value::Apply(_, _)) {
if !matches!(
to_concat,
Value::Dict(_)
| Value::Variable(_)
| Value::IdxAccess(_, _)
| Value::FieldAccess(_, _)
| Value::Apply(_, _)
) {
return Err(CozoError::LogicError("Cannot spread".to_string()));
}
if !collected.is_empty() {
@ -573,7 +639,7 @@ fn build_expr_primary(pair: Pair<Rule>) -> Result<Value> {
}
spread_collected.push(to_concat);
}
_ => unreachable!()
_ => unreachable!(),
}
}
@ -586,12 +652,8 @@ fn build_expr_primary(pair: Pair<Rule>) -> Result<Value> {
}
Ok(Value::Apply(METHOD_MERGE.into(), spread_collected))
}
Rule::param => {
Ok(Value::Variable(pair.as_str().into()))
}
Rule::ident => {
Ok(Value::Variable(pair.as_str().into()))
}
Rule::param => Ok(Value::Variable(pair.as_str().into())),
Rule::ident => Ok(Value::Variable(pair.as_str().into())),
_ => {
println!("Unhandled rule {:?}", pair.as_rule());
unimplemented!()
@ -599,7 +661,6 @@ fn build_expr_primary(pair: Pair<Rule>) -> Result<Value> {
}
}
#[cfg(test)]
mod tests {
use super::*;
@ -607,7 +668,10 @@ mod tests {
use pest::Parser as PestParser;
fn parse_expr_from_str<S: AsRef<str>>(s: S) -> Result<StaticValue> {
let pair = Parser::parse(Rule::expr, s.as_ref()).unwrap().next().unwrap();
let pair = Parser::parse(Rule::expr, s.as_ref())
.unwrap()
.next()
.unwrap();
Value::from_pair(pair).map(|v| v.to_static())
}
@ -628,22 +692,55 @@ mod tests {
assert_eq!(parse_expr_from_str("1").unwrap(), Value::Int(1));
assert_eq!(parse_expr_from_str("12_3").unwrap(), Value::Int(123));
assert_eq!(parse_expr_from_str("0xaf").unwrap(), Value::Int(0xaf));
assert_eq!(parse_expr_from_str("0xafcE_f").unwrap(), Value::Int(0xafcef));
assert_eq!(parse_expr_from_str("0o1234_567").unwrap(), Value::Int(0o1234567));
assert_eq!(parse_expr_from_str("0o0001234_567").unwrap(), Value::Int(0o1234567));
assert_eq!(parse_expr_from_str("0b101010").unwrap(), Value::Int(0b101010));
assert_eq!(parse_expr_from_str("0.0").unwrap(), Value::Float((0.).into()));
assert_eq!(parse_expr_from_str("10.022_3").unwrap(), Value::Float(10.0223.into()));
assert_eq!(parse_expr_from_str("10.022_3e-100").unwrap(), Value::Float(10.0223e-100.into()));
assert_eq!(
parse_expr_from_str("0xafcE_f").unwrap(),
Value::Int(0xafcef)
);
assert_eq!(
parse_expr_from_str("0o1234_567").unwrap(),
Value::Int(0o1234567)
);
assert_eq!(
parse_expr_from_str("0o0001234_567").unwrap(),
Value::Int(0o1234567)
);
assert_eq!(
parse_expr_from_str("0b101010").unwrap(),
Value::Int(0b101010)
);
assert_eq!(
parse_expr_from_str("0.0").unwrap(),
Value::Float((0.).into())
);
assert_eq!(
parse_expr_from_str("10.022_3").unwrap(),
Value::Float(10.0223.into())
);
assert_eq!(
parse_expr_from_str("10.022_3e-100").unwrap(),
Value::Float(10.0223e-100.into())
);
assert_eq!(parse_expr_from_str("null").unwrap(), Value::Null);
assert_eq!(parse_expr_from_str("true").unwrap(), Value::Bool(true));
assert_eq!(parse_expr_from_str("false").unwrap(), Value::Bool(false));
assert_eq!(parse_expr_from_str(r#""x \n \ty \"""#).unwrap(), Value::Text(Cow::Borrowed("x \n \ty \"")));
assert_eq!(parse_expr_from_str(r#""x'""#).unwrap(), Value::Text("x'".into()));
assert_eq!(parse_expr_from_str(r#"'"x"'"#).unwrap(), Value::Text(r##""x""##.into()));
assert_eq!(parse_expr_from_str(r#####"r###"x"yz"###"#####).unwrap(), (Value::Text(r##"x"yz"##.into())));
assert_eq!(
parse_expr_from_str(r#""x \n \ty \"""#).unwrap(),
Value::Text(Cow::Borrowed("x \n \ty \""))
);
assert_eq!(
parse_expr_from_str(r#""x'""#).unwrap(),
Value::Text("x'".into())
);
assert_eq!(
parse_expr_from_str(r#"'"x"'"#).unwrap(),
Value::Text(r##""x""##.into())
);
assert_eq!(
parse_expr_from_str(r#####"r###"x"yz"###"#####).unwrap(),
(Value::Text(r##"x"yz"##.into()))
);
}
#[test]
@ -655,4 +752,4 @@ mod tests {
println!("{}", parse_expr_from_str("[...a,...b,1,2,...e,3]")?);
Ok(())
}
}
}

Loading…
Cancel
Save