use crate::capacity::{DEFAULT_COLUMN_CAPACITY, DEFAULT_INSTRUCTION_CAPACITY};
use crate::table::{DataType, Value};
use std::fmt;
use std::rc::Rc;
pub const AGG_COUNT: i64 = 0;
pub const AGG_SUM: i64 = 1;
pub const AGG_AVG: i64 = 2;
pub const AGG_MIN: i64 = 3;
pub const AGG_MAX: i64 = 4;
pub const AGG_DISTINCT: i64 = 0x100;
pub const AGG_TYPE_MASK: i64 = 0xFF;
#[derive(Debug, Clone)]
pub struct ResultColumn {
pub name: String,
pub data_type: DataType,
}
impl ResultColumn {
pub fn new(name: String, data_type: DataType) -> Self {
Self { name, data_type }
}
}
#[derive(Debug, Clone, Default)]
pub struct ResultSchema {
pub columns: Vec<ResultColumn>,
}
impl ResultSchema {
pub fn new() -> Self {
Self {
columns: Vec::with_capacity(DEFAULT_COLUMN_CAPACITY),
}
}
pub fn add_column(&mut self, name: String, data_type: DataType) {
self.columns.push(ResultColumn::new(name, data_type));
}
pub fn is_empty(&self) -> bool {
self.columns.is_empty()
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[allow(dead_code)]
pub enum OpCode {
Init, Goto, Halt,
OpenRead, OpenWrite, Close,
Rewind, Next, Column, InsertRow, DeleteRow, UpdateRow,
Integer, String, Null, ResultRow, Copy,
Begin, Commit, Rollback, SavePoint, Release,
Lt, Le, Eq, Ne, Gt, Ge,
Like, Glob,
Cast,
IsNull,
Not,
Compare, Jump,
IfZ, IfPos, IfNeg,
Noop,
SortResults, Distinct, Limit, Intersect, Except,
NullRow, RewindInner, MarkMatch, CheckMatch,
InitCoroutine, Yield, EndCoroutine, Once,
AggStep, AggFinal, AggReset, Exists, NotExists,
DecrJumpZero,
SorterOpen, SorterInsert, SorterSort, SorterData, SorterNext,
OpenEphemeral, IdxInsert, Sort, Sequence,
CreateTable, DropTable, AlterTableAdd, Truncate,
StringFunc,
MathFunc,
DateFunc,
Add, Subtract, Multiply, Divide, Remainder,
WindowAggStep, WindowValue, WindowFinalize, }
#[derive(Debug, Clone)]
pub struct Instruction {
pub opcode: OpCode,
pub p1: i64,
pub p2: i64,
pub p3: i64,
pub p4: Option<Rc<str>>,
pub comment: Option<Rc<str>>,
}
impl Instruction {
pub fn new(
opcode: OpCode,
p1: i64,
p2: i64,
p3: i64,
p4: Option<String>,
_p5: i64, comment: Option<String>,
) -> Self {
Self {
opcode,
p1,
p2,
p3,
p4: p4.map(Rc::from),
comment: comment.map(Rc::from),
}
}
}
impl fmt::Display for Instruction {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{:?} p1={} p2={} p3={}{}{}",
self.opcode,
self.p1,
self.p2,
self.p3,
if let Some(p4) = &self.p4 {
format!(" p4=\"{}\"", p4)
} else {
String::new()
},
if let Some(comment) = &self.comment {
format!(" /* {} */", comment)
} else {
String::new()
}
)
}
}
#[derive(Debug, Clone)]
pub struct Program {
pub instructions: Vec<Instruction>,
pub result_schema: ResultSchema,
pub register_count: i64,
}
impl Default for Program {
fn default() -> Self {
Self::new()
}
}
impl Program {
pub fn new() -> Self {
Self {
instructions: Vec::with_capacity(DEFAULT_INSTRUCTION_CAPACITY),
result_schema: ResultSchema::new(),
register_count: 0,
}
}
pub fn set_result_schema(&mut self, schema: ResultSchema) {
self.result_schema = schema;
}
pub fn add_instruction(&mut self, instruction: Instruction) {
self.instructions.push(instruction);
}
pub fn len(&self) -> usize {
self.instructions.len()
}
pub fn is_empty(&self) -> bool {
self.instructions.is_empty()
}
pub fn get(&self, addr: usize) -> Option<&Instruction> {
self.instructions.get(addr)
}
}
impl fmt::Display for Program {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "Program ({} instructions):", self.instructions.len())?;
for (i, instruction) in self.instructions.iter().enumerate() {
writeln!(f, "{:3}: {}", i, instruction)?;
}
Ok(())
}
}
#[derive(Debug, Clone)]
pub enum Register {
Integer(i64),
String(String),
Float(f64),
Boolean(bool),
Null,
}
impl From<Value> for Register {
fn from(value: Value) -> Self {
match value {
Value::Integer(i) => Register::Integer(i),
Value::Float(f) => Register::Float(f),
Value::String(s) => Register::String(s.into_owned()),
Value::Boolean(b) => Register::Boolean(b),
Value::Null => Register::Null,
}
}
}
impl From<Register> for Value {
fn from(register: Register) -> Self {
use std::borrow::Cow;
match register {
Register::Integer(i) => Value::Integer(i),
Register::Float(f) => Value::Float(f),
Register::String(s) => Value::String(Cow::Owned(s)),
Register::Boolean(b) => Value::Boolean(b),
Register::Null => Value::Null,
}
}
}