use crate::*;
use Instruction::*;
pub struct EvalEnv<'r> {
pub stack: Vec<Value>,
pub bp: usize, pub db: DB,
pub tr: &'r mut dyn Transaction,
pub call_depth: usize,
}
impl<'r> EvalEnv<'r> {
pub fn new(db: DB, tr: &'r mut dyn Transaction) -> Self {
EvalEnv {
stack: Vec::new(),
bp: 0,
db,
tr,
call_depth: 0,
}
}
pub fn alloc_locals(&mut self, dt: &[DataType], param_count: usize) {
for d in dt.iter().skip(param_count) {
let v = Value::default(*d);
self.stack.push(v);
}
}
pub fn go(&mut self, ilist: &[Instruction]) {
let n = ilist.len();
let mut ip = 0;
while ip < n {
let i = &ilist[ip];
ip += 1;
match i {
PushConst(x) => self.stack.push((*x).clone()),
PushValue(e) => {
let v = e.eval(self, &[]);
self.stack.push(v);
}
PushLocal(x) => self.push_local(*x),
PopToLocal(x) => self.pop_to_local(*x),
Jump(x) => ip = *x,
JumpIfFalse(x, e) => {
if !e.eval(self, &[]) {
ip = *x;
}
}
Call(x) => self.call(x),
Return => break,
Throw => {
let s = self.pop_string();
panic!("{}", s);
}
Execute => self.execute(),
DataOp(x) => self.exec_do(x),
Select(cse) => self.select(cse),
Set(cse) => self.set(cse),
ForInit(for_id, cte) => self.for_init(*for_id, cte),
ForNext(break_id, info) => {
if !self.for_next(info) {
ip = *break_id;
}
}
ForSortInit(for_id, cte) => self.for_sort_init(*for_id, cte),
ForSortNext(break_id, info) => {
if !self.for_sort_next(info) {
ip = *break_id;
}
}
PushInt(e) => {
let v = e.eval(self, &[]);
self.stack.push(Value::Int(v));
}
PushFloat(e) => {
let v = e.eval(self, &[]);
self.stack.push(Value::Float(v));
}
PushBool(e) => {
let v = e.eval(self, &[]);
self.stack.push(Value::Bool(v));
}
}
}
}
pub fn call(&mut self, r: &Function) {
self.call_depth += 1;
if self.call_depth > 500 {
panic!("Call depth limit of 500 reached");
}
let save_bp = self.bp;
self.bp = self.stack.len() - r.param_count;
self.alloc_locals(&r.local_typ, r.param_count);
self.go(&r.ilist.borrow());
let pop_count = r.local_typ.len();
if pop_count > 0 {
if r.return_type != NONE {
if r.param_count == 0
{
self.discard(pop_count - 1);
} else {
let result = self.stack[self.bp + r.param_count].clone();
self.discard(pop_count);
self.stack.push(result);
}
} else {
self.discard(pop_count);
}
}
self.bp = save_bp;
self.call_depth -= 1;
}
fn discard(&mut self, mut n: usize) {
while n > 0 {
self.stack.pop();
n -= 1;
}
}
fn pop_to_local(&mut self, local: usize) {
self.stack[self.bp + local] = self.stack.pop().unwrap();
}
fn pop_string(&mut self) -> String {
if let Value::String(s) = self.stack.pop().unwrap() {
s.to_string()
} else {
panic!()
}
}
fn push_local(&mut self, local: usize) {
self.stack.push(self.stack[self.bp + local].clone());
}
fn for_init(&mut self, for_id: usize, cte: &CTableExpression) {
let data_source = self.data_source(cte);
let fs = util::new(ForState { data_source });
self.stack[self.bp + for_id] = Value::For(fs);
}
fn ok(&mut self, wher: &Option<CExpPtr<bool>>, data: &[u8]) -> bool {
if let Some(w) = wher {
w.eval(self, data)
} else {
true
}
}
fn for_next(&mut self, info: &ForNextInfo) -> bool {
loop {
let next = if let Value::For(fs) = &self.stack[self.bp + info.for_id] {
fs.borrow_mut().data_source.next()
} else {
panic!("Jump into FOR loop");
};
if let Some((pp, off)) = next {
let p = pp.borrow();
let data = &p.data[off..];
if self.ok(&info.wher, data) {
for (i, a) in info.assigns.iter().enumerate() {
let val = info.exps[i].eval(self, data);
self.assign_local(a, val);
}
return true;
}
} else {
return false;
}
}
}
fn for_sort_init(&mut self, for_id: usize, cse: &CSelectExpression) {
let rows = self.get_temp(cse);
self.stack[self.bp + for_id] = Value::ForSort(util::new(ForSortState { ix: 0, rows }));
}
fn for_sort_next(&mut self, info: &(usize, usize, Assigns)) -> bool {
let (for_id, orderbylen, assigns) = info;
if let Value::ForSort(fs) = &self.stack[self.bp + for_id] {
let fs = fs.clone();
let mut fs = fs.borrow_mut();
if fs.ix == fs.rows.len() {
false
} else {
fs.ix += 1;
let row = &fs.rows[fs.ix - 1];
for (cn, a) in assigns.iter().enumerate() {
let val = row[orderbylen + cn].clone();
self.assign_local(a, val);
}
true
}
} else {
panic!("Jump into FOR loop");
}
}
fn execute(&mut self) {
let s = self.pop_string();
self.db.run(&s, self.tr);
}
fn exec_do(&mut self, dop: &DO) {
match dop {
DO::Insert(tp, cols, values) => self.insert(tp.clone(), cols, values),
DO::Update(assigns, from, wher) => self.update(assigns, from, wher),
DO::Delete(from, wher) => self.delete(from, wher),
DO::CreateSchema(name) => sys::create_schema(&self.db, name),
DO::CreateTable(ti) => sys::create_table(&self.db, ti),
DO::CreateIndex(x) => sys::create_index(&self.db, x),
DO::CreateFunction(name, source, alter) => {
sys::create_function(&self.db, name, source.clone(), *alter)
}
DO::DropSchema(name) => self.drop_schema(name),
DO::DropTable(name) => self.drop_table(name),
DO::DropFunction(name) => self.drop_function(name),
_ => panic!(),
}
}
fn get_id_list(&mut self, te: &CTableExpression, w: &Option<CExpPtr<bool>>) -> Vec<u64> {
let mut idlist = Vec::new();
for (pp, off) in self.data_source(te) {
let p = pp.borrow();
let data = &p.data[off..];
if self.ok(w, data) {
idlist.push(util::getu64(data, 0));
}
}
idlist
}
fn insert(&mut self, t: TablePtr, cols: &[usize], src: &CTableExpression) {
if let CTableExpression::Values(x) = src {
self.insert_values(t, cols, x);
} else {
panic!();
}
}
fn delete(&mut self, from: &CTableExpression, w: &Option<CExpPtr<bool>>) {
let idlist = self.get_id_list(from, w);
let t = from.table();
let mut oldrow = t.row();
for id in idlist {
if let Some((pp, off)) = t.id_get(&self.db, id) {
let p = pp.borrow();
let data = &p.data[off..];
oldrow.load(&self.db, data);
} else {
panic!()
}
t.remove(&self.db, &oldrow);
}
}
fn update(
&mut self,
assigns: &[(usize, CExpPtr<Value>)],
from: &CTableExpression,
w: &Option<CExpPtr<bool>>,
) {
let idlist = self.get_id_list(from, w);
let t = from.table();
let mut oldrow = t.row();
for id in idlist {
if let Some((pp, off)) = t.id_get(&self.db, id) {
let mut newrow = {
let p = pp.borrow();
let data = &p.data[off..];
oldrow.load(&self.db, data);
let mut newrow = oldrow.clone();
for (col, exp) in assigns {
newrow.values[*col] = exp.eval(self, data);
}
newrow
};
t.remove(&self.db, &oldrow);
t.insert(&self.db, &mut newrow);
}
}
}
fn data_source(&mut self, te: &CTableExpression) -> DataSource {
match te {
CTableExpression::Base(t) => Box::new(t.scan(&self.db)),
CTableExpression::IdGet(t, idexp) => {
let id = idexp.eval(self, &[]);
Box::new(t.scan_id(&self.db, id))
}
CTableExpression::IxGet(t, val, index) => {
let mut keys = Vec::new();
for v in val {
keys.push(v.eval(self, &[]));
}
Box::new(t.scan_keys(&self.db, keys, *index))
}
_ => panic!(),
}
}
fn select(&mut self, cse: &CSelectExpression) {
if let Some(te) = &cse.from {
let obl = cse.orderby.len();
let mut temp = Vec::new(); for (pp, off) in self.data_source(te) {
let p = pp.borrow();
let data = &p.data[off..];
if self.ok(&cse.wher, data) {
let mut values = Vec::new();
if obl > 0 {
for ce in &cse.orderby {
let val = ce.eval(self, data);
values.push(val);
}
}
for ce in &cse.exps {
let val = ce.eval(self, data);
values.push(val);
}
if obl > 0 {
temp.push(values);
} else {
self.tr.selected(&values);
}
}
}
if obl > 0 {
temp.sort_by(|a, b| table::row_compare(a, b, &cse.desc));
for r in &temp {
self.tr.selected(&r[obl..]);
}
}
} else {
let mut values = Vec::new();
for ce in &cse.exps {
let val = ce.eval(self, &[]);
values.push(val);
}
self.tr.selected(&values);
}
}
fn set(&mut self, cse: &CSelectExpression) {
if let Some(te) = &cse.from {
for (pp, off) in self.data_source(te) {
let p = pp.borrow();
let data = &p.data[off..];
if self.ok(&cse.wher, data) {
for (i, ce) in cse.exps.iter().enumerate() {
let val = ce.eval(self, data);
self.assign_local(&cse.assigns[i], val);
}
break; }
}
} else {
for (i, ce) in cse.exps.iter().enumerate() {
let val = ce.eval(self, &[]);
self.assign_local(&cse.assigns[i], val);
}
}
}
fn assign_local(&mut self, a: &(usize, AssignOp), val: Value) {
let var = &mut self.stack[self.bp + a.0];
match a.1 {
AssignOp::Assign => {
*var = val;
}
AssignOp::Append => {
var.append(&val);
}
}
}
fn insert_values(&mut self, table: TablePtr, ci: &[usize], vals: &[Vec<CExpPtr<Value>>]) {
let mut row = Row::new(table.info.clone());
for r in vals {
row.id = 0;
for (i, ce) in r.iter().enumerate() {
let val = ce.eval(self, &[]);
let cn = ci[i];
if cn == usize::MAX {
if let Value::Int(v) = val {
row.id = v;
}
} else {
row.values[cn] = val;
}
}
if row.id == 0 {
row.id = table.alloc_id();
} else {
table.id_allocated(row.id);
}
self.db.lastid.set(row.id);
table.insert(&self.db, &mut row);
}
}
fn get_temp(&mut self, cse: &CSelectExpression) -> Vec<Vec<Value>> {
if let Some(te) = &cse.from {
let mut temp = Vec::new(); for (pp, off) in self.data_source(te) {
let p = pp.borrow();
let data = &p.data[off..];
if self.ok(&cse.wher, data) {
let mut values = Vec::new();
for ce in &cse.orderby {
let val = ce.eval(self, data);
values.push(val);
}
for ce in &cse.exps {
let val = ce.eval(self, data);
values.push(val);
}
temp.push(values); }
}
temp.sort_by(|a, b| table::row_compare(a, b, &cse.desc));
temp
} else {
panic!()
}
}
fn drop_schema(&mut self, name: &str) {
if let Some(sid) = sys::get_schema(&self.db, name) {
let sql = "EXEC sys.DropSchema(".to_string() + &sid.to_string() + ")";
self.db.run(&sql, self.tr);
self.db.schemas.borrow_mut().remove(name);
self.db.function_reset.set(true);
} else {
panic!("Drop Schema not found {}", name);
}
}
fn drop_table(&mut self, name: &ObjRef) {
if let Some(t) = sys::get_table(&self.db, name) {
let sql = "EXEC sys.DropTable(".to_string() + &t.id.to_string() + ")";
self.db.run(&sql, self.tr);
self.db.tables.borrow_mut().remove(name);
self.db.function_reset.set(true);
t.free_pages(&self.db);
} else {
panic!("Drop Table not found {}", name.str());
}
}
fn drop_function(&mut self, name: &ObjRef) {
if let Some(fid) = sys::get_function_id(&self.db, name) {
let sql = "DELETE FROM sys.Function WHERE Id = ".to_string() + &fid.to_string();
self.db.run(&sql, self.tr);
self.db.function_reset.set(true);
} else {
panic!("Drop Function not found {}", name.str());
}
}
}