use crate::RemDbError;
use alloc::boxed::Box;
use alloc::string::String;
use alloc::string::ToString;
use alloc::vec::Vec;
use std::collections::HashMap;
#[cfg(feature = "log")]
use crate::log::debug;
pub fn parse_time_string(time_str: &str) -> Result<i64, ()> {
if time_str.starts_with('[') && time_str.ends_with(']') {
return Err(());
}
if time_str.contains(|c| c == 'Y' || c == 'M' || c == 'D' || c == 'H' || c == 'I' || c == 'S') {
return Err(());
}
if let Ok(timestamp) = time_str.parse::<i64>() {
return Ok(timestamp);
}
let time_str = time_str.trim();
let mut parts = time_str.split_whitespace();
let date_part = parts.next().ok_or(())?;
let date_components: Vec<&str> = date_part.split('-').collect();
if date_components.len() != 3 {
return Err(());
}
let year = date_components[0].parse::<i64>().map_err(|_| ())?;
let month = date_components[1].parse::<i64>().map_err(|_| ())?;
let day = date_components[2].parse::<i64>().map_err(|_| ())?;
let mut hour = 0;
let mut minute = 0;
let mut second = 0;
if let Some(time_part) = parts.next() {
let (time_only, _tz_offset_seconds) = split_timezone_from_time(time_part);
let time_components: Vec<&str> = time_only.split(':').collect();
if time_components.len() != 3 {
return Err(());
}
hour = time_components[0].parse::<i64>().map_err(|_| ())?;
minute = time_components[1].parse::<i64>().map_err(|_| ())?;
second = time_components[2].parse::<i64>().map_err(|_| ())?;
}
let mut seconds = 0;
for _y in 1970..year {
seconds += 365 * 24 * 60 * 60;
}
let days_in_month = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
for m in 0..(month - 1) {
seconds += days_in_month[m as usize] * 24 * 60 * 60;
}
seconds += (day - 1) * 24 * 60 * 60;
seconds += hour * 60 * 60;
seconds += minute * 60;
seconds += second;
Ok(seconds * 1000000)
}
fn split_timezone_from_time(time_part: &str) -> (&str, i32) {
if let Some(pos) = time_part.find(|c| c == '+' || c == '-') {
if pos > 0 {
let before = &time_part[..pos];
let after = &time_part[pos..];
if after.len() > 1 && after.chars().nth(1).map_or(false, |c| c.is_ascii_digit()) {
let tz_seconds = parse_timezone_offset(after).unwrap_or(0);
return (before, tz_seconds);
}
}
}
(time_part, 0)
}
fn parse_timezone_offset(tz_str: &str) -> Option<i32> {
let sign = if tz_str.starts_with('+') {
1
} else if tz_str.starts_with('-') {
-1
} else {
return None;
};
let offset_str = &tz_str[1..];
let parts: Vec<&str> = offset_str.split(':').collect();
if parts.len() == 2 {
let hours = parts[0].parse::<i32>().ok()?;
let minutes = parts[1].parse::<i32>().ok()?;
Some(sign * (hours * 3600 + minutes * 60))
} else if offset_str.len() == 2 {
let hours = offset_str.parse::<i32>().ok()?;
Some(sign * hours * 3600)
} else if offset_str.len() == 4 {
let hours = offset_str[0..2].parse::<i32>().ok()?;
let minutes = offset_str[2..4].parse::<i32>().ok()?;
Some(sign * (hours * 3600 + minutes * 60))
} else {
None
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct GroupByClause {
pub expressions: Vec<Expression>,
pub fields: Vec<String>,
}
#[derive(Debug, Clone, PartialEq)]
pub enum JoinType {
Inner,
Left,
Right,
Full,
}
#[derive(Debug, Clone, PartialEq)]
pub struct JoinClause {
pub join_type: JoinType,
pub table_name: String,
pub table_alias: Option<String>,
pub on_condition: Condition,
}
#[derive(Debug, Clone, PartialEq)]
pub struct WindowFunctionClause {
pub name: String,
pub args: Vec<Expression>,
pub window_name: Option<String>,
pub partition_by: Vec<String>,
pub order_by: Option<OrderByClause>,
pub frame_clause: Option<String>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct SqlQuery {
pub query_type: QueryType,
pub table_name: String,
pub table_alias: Option<String>,
pub joins: Vec<JoinClause>,
pub columns: Vec<Expression>,
pub select_all: bool,
pub distinct: bool,
pub where_clause: Option<WhereClause>,
pub having_clause: Option<WhereClause>,
pub group_by: Option<GroupByClause>,
pub order_by: Option<OrderByClause>,
pub limit: Option<usize>,
pub sample_by: Option<String>,
pub fill_clause: Option<FillClause>,
pub window_functions: Vec<WindowFunctionClause>,
pub insert_columns: Vec<String>,
pub values: Vec<Vec<Value>>,
pub table_def: Vec<(String, String, bool, bool, bool, bool, Option<Value>)>,
pub primary_key: Option<Vec<String>>,
pub index_column: Option<Vec<String>>,
pub index_type: Option<String>,
pub index_params: HashMap<String, String>,
pub index_online: bool,
pub update_pairs: Vec<(String, Expression)>,
pub ignore_duplicates: bool,
pub if_not_exists: bool,
pub model_path: String,
pub model_inputs: Vec<(String, String)>,
pub model_output: (String, String),
pub table_config: HashMap<String, String>,
}
impl Default for SqlQuery {
fn default() -> Self {
Self {
query_type: QueryType::Select,
table_name: String::new(),
table_alias: None,
columns: Vec::new(),
select_all: false,
distinct: false,
where_clause: None,
having_clause: None,
order_by: None,
group_by: None,
joins: Vec::new(),
limit: None,
sample_by: None,
fill_clause: None,
window_functions: Vec::new(),
insert_columns: Vec::new(),
values: Vec::new(),
table_def: Vec::new(),
primary_key: None,
index_column: None,
index_type: None,
index_params: HashMap::new(),
index_online: false,
update_pairs: Vec::new(),
ignore_duplicates: false,
if_not_exists: false,
model_path: String::new(),
model_inputs: Vec::new(),
model_output: (String::new(), String::new()),
table_config: HashMap::new(),
}
}
}
#[test]
fn test_parse_composite_primary_key() {
use super::parse_sql_query;
let sql = "CREATE TABLE IF NOT EXISTS test_composite_pk (id1 INTEGER, id2 INTEGER, name TEXT, PRIMARY KEY (id1, id2))";
let result = parse_sql_query(sql);
assert!(result.is_ok());
let query = result.unwrap();
assert!(query.primary_key.is_some());
let pk = query.primary_key.unwrap();
assert_eq!(pk, vec!["id1", "id2"]);
}
#[derive(Debug, Clone, PartialEq)]
pub enum IndexType {
BTree,
HNSW,
IVF,
Default,
}
impl std::fmt::Display for IndexType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
IndexType::BTree => write!(f, "BTree"),
IndexType::HNSW => write!(f, "HNSW"),
IndexType::IVF => write!(f, "IVF"),
IndexType::Default => write!(f, "Default"),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum QueryType {
Select,
Insert,
Update,
Delete,
Describe,
CreateTable,
CreateTimeSeriesTable,
CreateIndex,
CreateDatabase,
CreateModel,
CreateRole,
GrantPermission,
GrantRole,
RevokePermission,
RevokeRole,
DropRole,
CreateUser,
DropUser,
UseDatabase,
CloseDatabase,
DropDatabase,
AlterTable,
DropTable,
BeginTransaction,
Commit,
Rollback,
CreateCheckpoint,
ShowIndexBuildStatus,
Reindex,
ShowTables,
Other,
}
#[derive(Debug, Clone, PartialEq)]
pub struct WhereClause {
pub condition: Condition,
}
#[derive(Debug, Clone, PartialEq)]
pub enum Condition {
Comparison(ComparisonCondition),
Between(BetweenCondition),
And(Box<Condition>, Box<Condition>),
Or(Box<Condition>, Box<Condition>),
Not(Box<Condition>),
}
#[derive(Debug, Clone, PartialEq)]
pub enum FillClause {
Prev,
Linear,
Next,
FixedValue(f64),
}
#[derive(Debug, Clone, PartialEq)]
pub struct BetweenCondition {
pub field: String,
pub min_value: Value,
pub max_value: Value,
}
#[derive(Debug, Clone, PartialEq)]
pub struct ComparisonCondition {
pub field: String,
pub operator: ComparisonOperator,
pub value: Value,
}
#[derive(Debug, Clone, PartialEq)]
pub enum ComparisonOperator {
Equal,
NotEqual,
GreaterThan,
GreaterThanOrEqual,
LessThan,
LessThanOrEqual,
Like,
}
#[derive(Debug, Clone, PartialEq)]
pub struct OrderByClause {
pub field: String,
pub direction: OrderDirection,
}
#[derive(Debug, Clone, PartialEq)]
pub enum OrderDirection {
Ascending,
Descending,
}
#[derive(Debug, Clone, PartialEq)]
pub enum Expression {
Field {
name: String,
alias: Option<String>,
},
FunctionCall {
name: String,
args: Vec<Expression>,
alias: Option<String>,
},
Constant {
value: Value,
alias: Option<String>,
},
BinaryOp {
left: Box<Expression>,
op: BinaryOperator,
right: Box<Expression>,
alias: Option<String>,
},
LogicalOp {
left: Box<Expression>,
op: LogicalOperator,
right: Box<Expression>,
alias: Option<String>,
},
UnaryOp {
op: UnaryOperator,
operand: Box<Expression>,
alias: Option<String>,
},
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum UnaryOperator {
Not,
Minus,
Plus,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum LogicalOperator {
And,
Or,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum BinaryOperator {
Add,
Subtract,
Multiply,
Divide,
Equal,
NotEqual,
GreaterThan,
GreaterThanOrEqual,
LessThan,
LessThanOrEqual,
VectorL2,
VectorIP,
VectorCosine,
}
#[derive(Debug, Clone, PartialEq)]
pub enum Value {
Integer(i64),
Float(f64),
String(String),
Boolean(bool),
Null,
Identifier(String),
Json(String),
}
#[derive(Debug, Clone, PartialEq)]
pub enum QueryParseError {
InvalidSyntax,
UnsupportedKeyword,
InvalidTableName,
InvalidFieldName,
InvalidCondition,
InvalidOperator,
InvalidValue,
MissingClause,
}
impl core::fmt::Display for QueryParseError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
QueryParseError::InvalidSyntax => write!(f, "Invalid SQL syntax"),
QueryParseError::UnsupportedKeyword => write!(f, "Unsupported SQL keyword"),
QueryParseError::InvalidTableName => write!(f, "Invalid table name"),
QueryParseError::InvalidFieldName => write!(f, "Invalid field name"),
QueryParseError::InvalidCondition => write!(f, "Invalid condition"),
QueryParseError::InvalidOperator => write!(f, "Invalid operator"),
QueryParseError::InvalidValue => write!(f, "Invalid value"),
QueryParseError::MissingClause => write!(f, "Missing required clause"),
}
}
}
impl From<RemDbError> for QueryParseError {
fn from(_: RemDbError) -> Self {
QueryParseError::InvalidSyntax
}
}
impl core::error::Error for QueryParseError {}
pub struct SqlParser {
input: String,
position: usize,
line: usize,
column: usize,
}
impl SqlParser {
pub fn new(input: String) -> Self {
SqlParser {
input,
position: 0,
line: 1,
column: 1,
}
}
fn parse_string(&mut self) -> Result<String, QueryParseError> {
if let Some(quote_char) = self.peek_char() {
if quote_char == '"' || quote_char == '\'' {
self.next_char(); let mut string_value = String::new();
while let Some(c) = self.next_char() {
if c == quote_char {
break;
}
string_value.push(c);
}
Ok(string_value)
} else {
Err(QueryParseError::InvalidSyntax)
}
} else {
Err(QueryParseError::InvalidSyntax)
}
}
pub fn parse(&mut self) -> Result<SqlQuery, QueryParseError> {
self.skip_whitespace();
let query_type = self.parse_query_type()?;
let query = match query_type {
QueryType::Select => self.parse_select_query(),
QueryType::Insert => self.parse_insert_query(),
QueryType::Update => self.parse_update_query(),
QueryType::Delete => self.parse_delete_query(),
QueryType::Describe => self.parse_describe_query(),
QueryType::CreateTable => self.parse_create_table_query(),
QueryType::CreateTimeSeriesTable => {
let mut query = self.parse_create_table_query()?;
query.query_type = QueryType::CreateTimeSeriesTable;
Ok(query)
}
QueryType::CreateIndex => self.parse_create_index_query(),
QueryType::CreateDatabase => self.parse_create_database_query(),
QueryType::CreateModel => self.parse_create_model_query(),
QueryType::CreateRole => self.parse_create_role_query(),
QueryType::CreateUser => self.parse_create_user_query(),
QueryType::GrantPermission => self.parse_grant_permission_query(),
QueryType::GrantRole => self.parse_grant_role_query(),
QueryType::RevokePermission => self.parse_revoke_permission_query(),
QueryType::RevokeRole => self.parse_revoke_role_query(),
QueryType::DropRole => self.parse_drop_role_query(),
QueryType::DropUser => self.parse_drop_user_query(),
QueryType::UseDatabase => self.parse_use_database_query(),
QueryType::CloseDatabase => self.parse_close_database_query(),
QueryType::DropDatabase => self.parse_drop_database_query(),
QueryType::AlterTable => self.parse_alter_table_query(),
QueryType::DropTable => self.parse_drop_table_query(),
QueryType::BeginTransaction => Ok(SqlQuery {
query_type,
table_name: String::new(),
table_alias: None,
joins: Vec::new(),
columns: Vec::new(),
select_all: false,
distinct: false,
where_clause: None,
having_clause: None,
group_by: None,
order_by: None,
limit: None,
sample_by: None,
fill_clause: None,
window_functions: Vec::new(),
insert_columns: Vec::new(),
values: Vec::new(),
table_def: Vec::new(),
primary_key: None,
index_column: None,
index_type: None,
index_params: HashMap::new(),
index_online: true,
update_pairs: Vec::new(),
ignore_duplicates: false,
if_not_exists: false,
model_path: String::new(),
model_inputs: Vec::new(),
model_output: (String::new(), String::new()),
table_config: HashMap::new(),
}),
QueryType::Commit => Ok(SqlQuery {
query_type: QueryType::Commit,
table_name: String::new(),
table_alias: None,
joins: Vec::new(),
columns: Vec::new(),
select_all: false,
distinct: false,
where_clause: None,
having_clause: None,
group_by: None,
order_by: None,
limit: None,
sample_by: None,
fill_clause: None,
window_functions: Vec::new(),
insert_columns: Vec::new(),
values: Vec::new(),
table_def: Vec::new(),
primary_key: None,
index_column: None,
index_type: None,
index_params: HashMap::new(),
index_online: true,
update_pairs: Vec::new(),
ignore_duplicates: false,
if_not_exists: false,
model_path: String::new(),
model_inputs: Vec::new(),
model_output: (String::new(), String::new()),
table_config: HashMap::new(),
}),
QueryType::Rollback => Ok(SqlQuery {
query_type: QueryType::Rollback,
table_name: String::new(),
table_alias: None,
joins: Vec::new(),
columns: Vec::new(),
select_all: false,
distinct: false,
where_clause: None,
having_clause: None,
group_by: None,
order_by: None,
limit: None,
sample_by: None,
fill_clause: None,
window_functions: Vec::new(),
insert_columns: Vec::new(),
values: Vec::new(),
table_def: Vec::new(),
primary_key: None,
index_column: None,
index_type: None,
index_params: HashMap::new(),
index_online: true,
update_pairs: Vec::new(),
ignore_duplicates: false,
if_not_exists: false,
model_path: String::new(),
model_inputs: Vec::new(),
model_output: (String::new(), String::new()),
table_config: HashMap::new(),
}),
QueryType::CreateCheckpoint => Ok(SqlQuery {
query_type: QueryType::CreateCheckpoint,
table_name: String::new(),
table_alias: None,
joins: Vec::new(),
columns: Vec::new(),
select_all: false,
distinct: false,
where_clause: None,
having_clause: None,
group_by: None,
order_by: None,
limit: None,
sample_by: None,
fill_clause: None,
window_functions: Vec::new(),
insert_columns: Vec::new(),
values: Vec::new(),
table_def: Vec::new(),
primary_key: None,
index_column: None,
index_type: None,
index_params: HashMap::new(),
index_online: true,
update_pairs: Vec::new(),
ignore_duplicates: false,
if_not_exists: false,
model_path: String::new(),
model_inputs: Vec::new(),
model_output: (String::new(), String::new()),
table_config: HashMap::new(),
}),
QueryType::ShowIndexBuildStatus => {
let mut object_name = String::new();
self.skip_whitespace();
if self.match_keyword("FOR") {
self.skip_whitespace();
object_name = self.parse_identifier()?;
}
Ok(SqlQuery {
query_type: QueryType::ShowIndexBuildStatus,
table_name: object_name,
table_alias: None,
joins: Vec::new(),
columns: Vec::new(),
select_all: false,
distinct: false,
where_clause: None,
having_clause: None,
group_by: None,
order_by: None,
limit: None,
sample_by: None,
fill_clause: None,
window_functions: Vec::new(),
insert_columns: Vec::new(),
values: Vec::new(),
table_def: Vec::new(),
primary_key: None,
index_column: None,
index_type: None,
index_params: HashMap::new(),
index_online: true,
update_pairs: Vec::new(),
ignore_duplicates: false,
if_not_exists: false,
model_path: String::new(),
model_inputs: Vec::new(),
model_output: (String::new(), String::new()),
table_config: HashMap::new(),
})
}
QueryType::Reindex => self.parse_reindex_query(),
QueryType::ShowTables => Ok(SqlQuery {
query_type: QueryType::ShowTables,
table_name: String::new(),
table_alias: None,
joins: Vec::new(),
columns: Vec::new(),
select_all: false,
distinct: false,
where_clause: None,
having_clause: None,
group_by: None,
order_by: None,
limit: None,
sample_by: None,
fill_clause: None,
window_functions: Vec::new(),
insert_columns: Vec::new(),
values: Vec::new(),
table_def: Vec::new(),
primary_key: None,
index_column: None,
index_type: None,
index_params: HashMap::new(),
index_online: true,
update_pairs: Vec::new(),
ignore_duplicates: false,
if_not_exists: false,
model_path: String::new(),
model_inputs: Vec::new(),
model_output: (String::new(), String::new()),
table_config: HashMap::new(),
}),
QueryType::Other => Err(QueryParseError::UnsupportedKeyword),
}?;
self.skip_whitespace();
self.match_char(';');
Ok(query)
}
fn parse_update_query(&mut self) -> Result<SqlQuery, QueryParseError> {
self.skip_whitespace();
let table_name = self.parse_identifier()?;
self.skip_whitespace();
self.expect_keyword("SET")?;
let mut update_pairs = Vec::new();
loop {
self.skip_whitespace();
let field_name = self.parse_identifier()?;
self.skip_whitespace();
self.expect_char('=')?;
self.skip_whitespace();
let value_expr = self.parse_expression()?;
update_pairs.push((field_name, value_expr));
self.skip_whitespace();
if self.match_char(',') {
continue;
} else {
break;
}
}
let where_clause = self.parse_where_clause()?;
Ok(SqlQuery {
query_type: QueryType::Update,
table_name,
table_alias: None,
joins: Vec::new(),
columns: Vec::new(),
select_all: false,
distinct: false,
where_clause,
group_by: None,
order_by: None,
limit: None,
sample_by: None,
fill_clause: None,
insert_columns: Vec::new(),
values: Vec::new(),
table_def: Vec::new(),
primary_key: None,
index_column: None,
index_type: None,
index_params: HashMap::new(),
index_online: true,
update_pairs,
ignore_duplicates: false,
if_not_exists: false,
..Default::default()
})
}
fn parse_describe_query(&mut self) -> Result<SqlQuery, QueryParseError> {
self.skip_whitespace();
self.match_keyword("TABLE");
self.skip_whitespace();
let table_name = self.parse_identifier()?;
Ok(SqlQuery {
query_type: QueryType::Describe,
table_name,
table_alias: None,
joins: Vec::new(),
columns: Vec::new(),
select_all: false,
distinct: false,
where_clause: None,
group_by: None,
order_by: None,
limit: None,
sample_by: None,
fill_clause: None,
insert_columns: Vec::new(),
values: Vec::new(),
table_def: Vec::new(),
primary_key: None,
index_column: None,
index_type: None,
index_params: HashMap::new(),
index_online: true,
update_pairs: Vec::new(),
ignore_duplicates: false,
if_not_exists: false,
..Default::default()
})
}
fn parse_insert_query(&mut self) -> Result<SqlQuery, QueryParseError> {
#[cfg(feature = "log")]
debug!("parse_insert_query called");
let mut ignore_duplicates = false;
self.skip_whitespace();
if self.match_keyword("IGNORE") {
ignore_duplicates = true;
}
self.skip_whitespace();
self.expect_keyword("INTO")?;
self.skip_whitespace();
let table_name = self.parse_identifier()?;
let insert_columns = self.parse_insert_columns()?;
self.skip_whitespace();
self.expect_keyword("VALUES")?;
let values = self.parse_values()?;
Ok(SqlQuery {
query_type: QueryType::Insert,
table_name,
table_alias: None,
joins: Vec::new(),
columns: Vec::new(),
select_all: false,
distinct: false,
where_clause: None,
having_clause: None,
group_by: None,
order_by: None,
limit: None,
sample_by: None,
fill_clause: None,
window_functions: Vec::new(),
insert_columns,
values,
table_def: Vec::new(),
primary_key: None,
index_column: None,
index_type: None,
index_params: HashMap::new(),
index_online: true,
update_pairs: Vec::new(),
ignore_duplicates,
if_not_exists: false,
model_path: String::new(),
model_inputs: Vec::new(),
model_output: (String::new(), String::new()),
table_config: HashMap::new(),
})
}
fn parse_insert_columns(&mut self) -> Result<Vec<String>, QueryParseError> {
self.skip_whitespace();
if self.match_char('(') {
let mut columns = Vec::new();
loop {
self.skip_whitespace();
let column = self.parse_identifier()?;
columns.push(column);
self.skip_whitespace();
if self.match_char(')') {
break;
}
if !self.match_char(',') {
return Err(QueryParseError::InvalidSyntax);
}
}
Ok(columns)
} else {
Ok(Vec::new())
}
}
fn parse_values(&mut self) -> Result<Vec<Vec<Value>>, QueryParseError> {
#[cfg(feature = "log")]
debug!("parse_values called");
let mut all_values = Vec::new();
loop {
self.skip_whitespace();
if !self.match_char('(') {
return Err(QueryParseError::InvalidSyntax);
}
let mut values = Vec::new();
loop {
self.skip_whitespace();
#[cfg(feature = "log")]
debug!("About to call parse_value");
let value = self.parse_value()?;
#[cfg(feature = "log")]
debug!("parse_value returned: {:?}", value);
values.push(value);
self.skip_whitespace();
if self.match_char(')') {
break;
}
if !self.match_char(',') {
return Err(QueryParseError::InvalidSyntax);
}
}
all_values.push(values);
self.skip_whitespace();
if !self.match_char(',') {
break;
}
}
#[cfg(feature = "log")]
debug!("parse_values returning {:?} values", all_values.len());
Ok(all_values)
}
fn parse_delete_query(&mut self) -> Result<SqlQuery, QueryParseError> {
self.skip_whitespace();
self.expect_keyword("FROM")?;
self.skip_whitespace();
let table_name = self.parse_identifier()?;
let where_clause = self.parse_where_clause()?;
Ok(SqlQuery {
query_type: QueryType::Delete,
table_name,
table_alias: None,
joins: Vec::new(),
columns: Vec::new(),
select_all: false,
distinct: false,
where_clause,
having_clause: None,
group_by: None,
order_by: None,
limit: None,
sample_by: None,
fill_clause: None,
window_functions: Vec::new(),
insert_columns: Vec::new(),
values: Vec::new(),
table_def: Vec::new(),
primary_key: None,
index_column: None,
index_type: None,
index_params: HashMap::new(),
index_online: true,
update_pairs: Vec::new(),
ignore_duplicates: false,
if_not_exists: false,
model_path: String::new(),
model_inputs: Vec::new(),
model_output: (String::new(), String::new()),
table_config: HashMap::new(),
})
}
fn parse_create_table_query(&mut self) -> Result<SqlQuery, QueryParseError> {
let mut if_not_exists = false;
self.skip_whitespace();
if self.match_keyword("IF") {
self.skip_whitespace();
self.expect_keyword("NOT")?;
self.skip_whitespace();
self.expect_keyword("EXISTS")?;
if_not_exists = true;
}
self.skip_whitespace();
let table_name = self.parse_identifier()?;
self.skip_whitespace();
self.expect_char('(')?;
let mut table_def = Vec::new();
let mut primary_key = None;
let mut primary_key_fields = Vec::new();
loop {
self.skip_whitespace();
#[cfg(feature = "log")]
{
let remaining: String = self.input[self.position..].chars().take(50).collect();
debug!(
"parse_create_table_query: position={}, remaining='{}'",
self.position, remaining
);
}
let _remaining_debug: String = self.input[self.position..].chars().take(50).collect();
let is_primary = self.match_keyword("PRIMARY");
#[cfg(feature = "log")]
debug!(
"parse_create_table_query: match_keyword('PRIMARY')={}, position_after={}",
is_primary, self.position
);
if is_primary {
self.skip_whitespace();
self.expect_keyword("KEY")?;
self.skip_whitespace();
self.expect_char('(')?;
loop {
self.skip_whitespace();
let field_name = self.parse_identifier()?;
primary_key_fields.push(field_name);
self.skip_whitespace();
if self.match_char(')') {
break;
}
if !self.match_char(',') {
return Err(QueryParseError::InvalidSyntax);
}
}
primary_key = Some(primary_key_fields.clone());
} else if self.match_keyword("FOREIGN") {
self.skip_whitespace();
self.expect_keyword("KEY")?;
self.skip_whitespace();
self.expect_char('(')?;
loop {
self.skip_whitespace();
self.parse_identifier()?;
self.skip_whitespace();
if self.match_char(')') {
break;
}
if !self.match_char(',') {
return Err(QueryParseError::InvalidSyntax);
}
}
self.skip_whitespace();
self.expect_keyword("REFERENCES")?;
self.skip_whitespace();
self.parse_identifier()?; self.skip_whitespace();
if self.match_char('(') {
loop {
self.skip_whitespace();
self.parse_identifier()?;
self.skip_whitespace();
if self.match_char(')') {
break;
}
if !self.match_char(',') {
return Err(QueryParseError::InvalidSyntax);
}
}
}
} else if self.match_keyword("CONSTRAINT") {
self.skip_whitespace();
self.parse_identifier()?;
self.skip_whitespace();
if self.match_keyword("PRIMARY") {
self.skip_whitespace();
self.expect_keyword("KEY")?;
self.skip_whitespace();
self.expect_char('(')?;
loop {
self.skip_whitespace();
let field_name = self.parse_identifier()?;
primary_key_fields.push(field_name);
self.skip_whitespace();
if self.match_char(')') {
break;
}
if !self.match_char(',') {
return Err(QueryParseError::InvalidSyntax);
}
}
primary_key = Some(primary_key_fields.clone());
} else if self.match_keyword("UNIQUE") {
self.skip_whitespace();
self.expect_char('(')?;
loop {
self.skip_whitespace();
self.parse_identifier()?;
self.skip_whitespace();
if self.match_char(')') {
break;
}
if !self.match_char(',') {
return Err(QueryParseError::InvalidSyntax);
}
}
} else if self.match_keyword("FOREIGN") {
self.skip_whitespace();
self.expect_keyword("KEY")?;
self.skip_whitespace();
self.expect_char('(')?;
loop {
self.skip_whitespace();
self.parse_identifier()?;
self.skip_whitespace();
if self.match_char(')') {
break;
}
if !self.match_char(',') {
return Err(QueryParseError::InvalidSyntax);
}
}
self.skip_whitespace();
self.expect_keyword("REFERENCES")?;
self.skip_whitespace();
self.parse_identifier()?;
self.skip_whitespace();
if self.match_char('(') {
loop {
self.skip_whitespace();
self.parse_identifier()?;
self.skip_whitespace();
if self.match_char(')') {
break;
}
if !self.match_char(',') {
return Err(QueryParseError::InvalidSyntax);
}
}
}
} else {
return Err(QueryParseError::InvalidSyntax);
}
} else {
let field_name = self.parse_identifier()?;
self.skip_whitespace();
let data_type = self.parse_data_type()?.to_uppercase();
let mut is_primary_key = false;
let mut is_not_null = false;
let mut is_unique = false;
let mut is_auto_increment = false;
let mut default_value: Option<Value> = None;
loop {
self.skip_whitespace();
if self.match_keyword("PRIMARY") {
self.skip_whitespace();
self.expect_keyword("KEY")?;
is_primary_key = true;
primary_key_fields.push(field_name.clone());
primary_key = Some(primary_key_fields.clone());
} else if self.match_keyword("NOT") {
self.skip_whitespace();
self.expect_keyword("NULL")?;
is_not_null = true;
} else if self.match_keyword("UNIQUE") {
is_unique = true;
} else if self.match_keyword("AUTOINCREMENT")
|| self.match_keyword("AUTO_INCREMENT")
{
is_auto_increment = true;
} else if self.match_keyword("DEFAULT") {
self.skip_whitespace();
let value = self.parse_value()?;
default_value = Some(value);
} else {
break;
}
}
if data_type == "INTEGER" && is_primary_key {
is_auto_increment = true;
}
table_def.push((
field_name,
data_type,
is_primary_key,
is_not_null,
is_unique,
is_auto_increment,
default_value,
));
}
self.skip_whitespace();
if self.match_char(')') {
break;
}
if !self.match_char(',') {
return Err(QueryParseError::InvalidSyntax);
}
}
if primary_key.is_none() {
primary_key = primary_key_fields.into_iter().collect::<Vec<_>>().into();
}
if let Some(pk_fields) = &primary_key {
for (field_name, _, ref mut is_pk, _, _, _, _) in &mut table_def {
if pk_fields.contains(field_name) {
*is_pk = true;
}
}
}
let mut table_config = HashMap::new();
self.skip_whitespace();
if self.match_keyword("WITH") {
self.skip_whitespace();
self.expect_keyword("CONFIGURATION")?;
self.skip_whitespace();
self.expect_char('(')?;
loop {
self.skip_whitespace();
let param_name = self.parse_identifier()?.to_uppercase();
self.skip_whitespace();
self.expect_char('=')?;
self.skip_whitespace();
let param_value = self.parse_value()?;
let value_str = match param_value {
Value::String(s) => s,
Value::Identifier(id) => id,
Value::Integer(i) => i.to_string(),
Value::Float(f) => f.to_string(),
Value::Boolean(b) => b.to_string(),
Value::Json(s) => s,
_ => return Err(QueryParseError::InvalidValue),
};
table_config.insert(param_name, value_str);
self.skip_whitespace();
if self.match_char(')') {
break;
} else if !self.match_char(',') {
return Err(QueryParseError::InvalidSyntax);
}
}
}
Ok(SqlQuery {
query_type: QueryType::CreateTable,
table_name,
table_alias: None,
joins: Vec::new(),
columns: Vec::new(),
select_all: false,
distinct: false,
where_clause: None,
having_clause: None,
group_by: None,
order_by: None,
limit: None,
sample_by: None,
fill_clause: None,
window_functions: Vec::new(),
insert_columns: Vec::new(),
values: Vec::new(),
table_def,
primary_key,
index_column: None,
index_type: None,
index_params: HashMap::new(),
index_online: true,
update_pairs: Vec::new(),
ignore_duplicates: false,
if_not_exists,
model_path: String::new(),
model_inputs: Vec::new(),
model_output: (String::new(), String::new()),
table_config,
})
}
fn parse_create_index_query(&mut self) -> Result<SqlQuery, QueryParseError> {
self.skip_whitespace();
let _index_name = self.parse_identifier()?;
self.skip_whitespace();
self.expect_keyword("ON")?;
self.skip_whitespace();
let table_name = self.parse_identifier()?;
self.skip_whitespace();
self.expect_char('(')?;
let mut index_columns = Vec::new();
loop {
self.skip_whitespace();
let column_name = self.parse_identifier()?;
index_columns.push(column_name);
self.skip_whitespace();
if self.match_keyword("ASC") || self.match_keyword("DESC") {
}
self.skip_whitespace();
if self.match_char(')') {
break;
}
if !self.match_char(',') {
return Err(QueryParseError::InvalidSyntax);
}
}
let mut index_type = None;
self.skip_whitespace();
if self.match_keyword("USING") {
self.skip_whitespace();
index_type = Some(self.parse_identifier()?.to_uppercase());
}
let mut index_params = HashMap::new();
self.skip_whitespace();
if self.match_keyword("WITH") {
self.skip_whitespace();
self.expect_char('(')?;
loop {
self.skip_whitespace();
let param_name = self.parse_identifier()?.to_uppercase();
self.skip_whitespace();
self.expect_char('=')?;
self.skip_whitespace();
let param_value = self.parse_value()?;
let value_str = match param_value {
Value::String(s) => s,
Value::Identifier(id) => id,
Value::Integer(i) => i.to_string(),
Value::Float(f) => f.to_string(),
Value::Boolean(b) => b.to_string(),
Value::Json(s) => s,
_ => return Err(QueryParseError::InvalidValue),
};
index_params.insert(param_name, value_str);
self.skip_whitespace();
if self.match_char(',') {
continue;
} else {
break;
}
}
self.skip_whitespace();
self.expect_char(')')?;
}
let mut index_online = true; self.skip_whitespace();
if self.match_keyword("ONLINE") {
index_online = true;
} else if self.match_keyword("OFFLINE") {
index_online = false;
}
Ok(SqlQuery {
query_type: QueryType::CreateIndex,
table_name,
table_alias: None,
joins: Vec::new(),
columns: Vec::new(),
select_all: false,
distinct: false,
where_clause: None,
having_clause: None,
group_by: None,
order_by: None,
limit: None,
sample_by: None,
fill_clause: None,
window_functions: Vec::new(),
insert_columns: Vec::new(),
values: Vec::new(),
table_def: Vec::new(),
primary_key: None,
index_column: Some(index_columns),
index_type,
index_params,
index_online,
update_pairs: Vec::new(),
ignore_duplicates: false,
if_not_exists: false,
model_path: String::new(),
model_inputs: Vec::new(),
model_output: (String::new(), String::new()),
table_config: HashMap::new(),
})
}
fn parse_reindex_query(&mut self) -> Result<SqlQuery, QueryParseError> {
self.skip_whitespace();
let index_name = self.parse_identifier()?;
let mut index_online = true; self.skip_whitespace();
if self.match_keyword("ONLINE") {
index_online = true;
} else if self.match_keyword("OFFLINE") {
index_online = false;
}
Ok(SqlQuery {
query_type: QueryType::Reindex,
table_name: index_name,
table_alias: None,
joins: Vec::new(),
columns: Vec::new(),
select_all: false,
distinct: false,
where_clause: None,
having_clause: None,
group_by: None,
order_by: None,
limit: None,
sample_by: None,
fill_clause: None,
window_functions: Vec::new(),
insert_columns: Vec::new(),
values: Vec::new(),
table_def: Vec::new(),
primary_key: None,
index_column: None,
index_type: None,
index_params: HashMap::new(),
index_online,
update_pairs: Vec::new(),
ignore_duplicates: false,
if_not_exists: false,
model_path: String::new(),
model_inputs: Vec::new(),
model_output: (String::new(), String::new()),
table_config: HashMap::new(),
})
}
fn parse_alter_table_query(&mut self) -> Result<SqlQuery, QueryParseError> {
self.skip_whitespace();
let table_name = self.parse_identifier()?;
self.skip_whitespace();
let mut table_def = Vec::new();
if self.match_keyword("ADD") {
self.skip_whitespace();
if self.match_keyword("COLUMN") {
self.skip_whitespace();
}
let field_def = self.parse_column_definition()?;
table_def.push(field_def);
} else if self.match_keyword("DROP") {
self.skip_whitespace();
if self.match_keyword("COLUMN") {
self.skip_whitespace();
}
let field_name = self.parse_identifier()?;
table_def.push((
field_name,
"DROP".to_string(),
false,
false,
false,
false,
None,
));
} else if self.match_keyword("MODIFY") {
self.skip_whitespace();
if self.match_keyword("COLUMN") {
self.skip_whitespace();
}
let field_def = self.parse_column_definition()?;
table_def.push(field_def);
} else if self.match_keyword("RENAME") {
self.skip_whitespace();
if self.match_keyword("COLUMN") {
self.skip_whitespace();
}
let old_name = self.parse_identifier()?;
self.skip_whitespace();
self.expect_keyword("TO")?;
self.skip_whitespace();
let new_name = self.parse_identifier()?;
table_def.push((old_name, new_name, false, false, false, false, None));
} else {
return Err(QueryParseError::UnsupportedKeyword);
}
Ok(SqlQuery {
query_type: QueryType::AlterTable,
table_name,
table_alias: None,
joins: Vec::new(),
columns: Vec::new(),
select_all: false,
distinct: false,
where_clause: None,
having_clause: None,
group_by: None,
order_by: None,
limit: None,
sample_by: None,
fill_clause: None,
window_functions: Vec::new(),
insert_columns: Vec::new(),
values: Vec::new(),
table_def,
primary_key: None,
index_column: None,
index_type: None,
index_params: std::collections::HashMap::new(),
index_online: true,
update_pairs: Vec::new(),
ignore_duplicates: false,
if_not_exists: false,
model_path: String::new(),
model_inputs: Vec::new(),
model_output: (String::new(), String::new()),
table_config: HashMap::new(),
})
}
fn parse_column_definition(
&mut self,
) -> Result<(String, String, bool, bool, bool, bool, Option<Value>), QueryParseError> {
let field_name = self.parse_identifier()?;
self.skip_whitespace();
let data_type = self.parse_data_type()?.to_uppercase();
let mut is_primary_key = false;
let mut is_not_null = false;
let mut is_unique = false;
let mut is_auto_increment = false;
let mut default_value: Option<Value> = None;
loop {
self.skip_whitespace();
if self.match_keyword("PRIMARY") {
self.skip_whitespace();
self.expect_keyword("KEY")?;
is_primary_key = true;
} else if self.match_keyword("NOT") {
self.skip_whitespace();
self.expect_keyword("NULL")?;
is_not_null = true;
} else if self.match_keyword("UNIQUE") {
is_unique = true;
} else if self.match_keyword("AUTOINCREMENT") || self.match_keyword("AUTO_INCREMENT") {
is_auto_increment = true;
} else if self.match_keyword("DEFAULT") {
self.skip_whitespace();
let value = self.parse_value()?;
default_value = Some(value);
} else {
break;
}
}
Ok((
field_name,
data_type,
is_primary_key,
is_not_null,
is_unique,
is_auto_increment,
default_value,
))
}
fn parse_drop_table_query(&mut self) -> Result<SqlQuery, QueryParseError> {
let mut if_exists = false;
self.skip_whitespace();
if self.match_keyword("IF") {
self.skip_whitespace();
self.expect_keyword("EXISTS")?;
if_exists = true;
}
self.skip_whitespace();
let table_name = self.parse_identifier()?;
self.skip_whitespace();
let mut is_deferred = false;
if self.match_keyword("DEFERRED") {
is_deferred = true;
} else if self.match_keyword("CASCADE") {
} else if self.match_keyword("RESTRICT") {
}
let mut query = SqlQuery {
query_type: QueryType::DropTable,
table_name,
table_alias: None,
joins: Vec::new(),
columns: Vec::new(),
select_all: false,
distinct: false,
where_clause: None,
having_clause: None,
group_by: None,
order_by: None,
limit: None,
sample_by: None,
fill_clause: None,
window_functions: Vec::new(),
insert_columns: Vec::new(),
values: Vec::new(),
table_def: Vec::new(),
primary_key: None,
index_column: None,
index_type: None,
index_params: HashMap::new(),
index_online: true,
update_pairs: Vec::new(),
ignore_duplicates: false,
if_not_exists: false,
model_path: String::new(),
model_inputs: Vec::new(),
model_output: (String::new(), String::new()),
table_config: HashMap::new(),
};
query.table_def.push((
if_exists.to_string(),
is_deferred.to_string(),
false,
false,
false,
false,
None,
));
Ok(query)
}
fn parse_create_database_query(&mut self) -> Result<SqlQuery, QueryParseError> {
let mut if_not_exists = false;
self.skip_whitespace();
if self.match_keyword("IF") {
self.skip_whitespace();
self.expect_keyword("NOT")?;
self.skip_whitespace();
self.expect_keyword("EXISTS")?;
if_not_exists = true;
}
self.skip_whitespace();
let database_name = self.parse_identifier()?;
let mut schema = None;
self.skip_whitespace();
if self.match_keyword("USING") {
self.skip_whitespace();
self.expect_keyword("SCHEMA")?;
self.skip_whitespace();
schema = Some(self.parse_identifier()?);
}
let mut config_params = HashMap::new();
self.skip_whitespace();
if self.match_keyword("WITH") {
self.skip_whitespace();
self.expect_keyword("CONFIGURATION")?;
self.skip_whitespace();
self.expect_char('(')?;
loop {
self.skip_whitespace();
let param_name = self.parse_identifier()?.to_uppercase();
self.skip_whitespace();
self.expect_char('=')?;
self.skip_whitespace();
let param_value = self.parse_value()?;
let value_str = match param_value {
Value::String(s) => s,
Value::Identifier(id) => id,
Value::Integer(i) => i.to_string(),
Value::Float(f) => f.to_string(),
Value::Boolean(b) => b.to_string(),
Value::Json(s) => s,
_ => return Err(QueryParseError::InvalidValue),
};
config_params.insert(param_name, value_str);
self.skip_whitespace();
if self.match_char(')') {
break;
} else if !self.match_char(',') {
return Err(QueryParseError::InvalidSyntax);
}
}
}
let query = SqlQuery {
query_type: QueryType::CreateDatabase,
table_name: database_name,
table_alias: schema,
joins: Vec::new(),
columns: Vec::new(),
select_all: false,
distinct: false,
where_clause: None,
having_clause: None,
group_by: None,
order_by: None,
limit: None,
sample_by: None,
fill_clause: None,
window_functions: Vec::new(),
insert_columns: Vec::new(),
values: Vec::new(),
table_def: Vec::new(),
primary_key: None,
index_column: None,
index_type: None,
index_params: config_params,
index_online: true,
update_pairs: Vec::new(),
ignore_duplicates: if_not_exists,
if_not_exists: false,
model_path: String::new(),
model_inputs: Vec::new(),
model_output: (String::new(), String::new()),
table_config: HashMap::new(),
};
Ok(query)
}
fn parse_create_model_query(&mut self) -> Result<SqlQuery, QueryParseError> {
let mut if_not_exists = false;
self.skip_whitespace();
if self.match_keyword("IF") {
self.skip_whitespace();
self.expect_keyword("NOT")?;
self.skip_whitespace();
self.expect_keyword("EXISTS")?;
if_not_exists = true;
}
self.skip_whitespace();
let model_name = self.parse_identifier()?;
self.skip_whitespace();
self.expect_keyword("USING")?;
self.skip_whitespace();
let model_path = self.parse_string()?;
self.skip_whitespace();
self.expect_keyword("AS")?;
self.skip_whitespace();
self.expect_char('(')?;
let mut model_inputs = Vec::new();
loop {
self.skip_whitespace();
let param_name = self.parse_identifier()?;
self.skip_whitespace();
let param_type = self.parse_identifier()?.to_uppercase();
model_inputs.push((param_name, param_type));
self.skip_whitespace();
if self.match_char(')') {
break;
} else if !self.match_char(',') {
return Err(QueryParseError::InvalidSyntax);
}
}
self.skip_whitespace();
self.expect_keyword("RETURNS")?;
self.skip_whitespace();
let return_type = self.parse_identifier()?.to_uppercase();
Ok(SqlQuery {
query_type: QueryType::CreateModel,
table_name: model_name,
table_alias: None,
joins: Vec::new(),
columns: Vec::new(),
select_all: false,
distinct: false,
where_clause: None,
having_clause: None,
group_by: None,
order_by: None,
limit: None,
sample_by: None,
fill_clause: None,
window_functions: Vec::new(),
insert_columns: Vec::new(),
values: Vec::new(),
table_def: Vec::new(),
primary_key: None,
index_column: None,
index_type: None,
index_params: HashMap::new(),
index_online: true,
update_pairs: Vec::new(),
ignore_duplicates: false,
if_not_exists,
model_path,
model_inputs,
model_output: ("result".to_string(), return_type),
table_config: HashMap::new(),
})
}
fn parse_use_database_query(&mut self) -> Result<SqlQuery, QueryParseError> {
self.skip_whitespace();
let database_name = self.parse_identifier()?;
let query = SqlQuery {
query_type: QueryType::UseDatabase,
table_name: database_name,
table_alias: None,
joins: Vec::new(),
columns: Vec::new(),
select_all: false,
distinct: false,
where_clause: None,
having_clause: None,
group_by: None,
order_by: None,
limit: None,
sample_by: None,
fill_clause: None,
window_functions: Vec::new(),
insert_columns: Vec::new(),
values: Vec::new(),
table_def: Vec::new(),
primary_key: None,
index_column: None,
index_type: None,
index_params: HashMap::new(),
index_online: true,
update_pairs: Vec::new(),
ignore_duplicates: false,
if_not_exists: false,
model_path: String::new(),
model_inputs: Vec::new(),
model_output: (String::new(), String::new()),
table_config: HashMap::new(),
};
Ok(query)
}
fn parse_close_database_query(&mut self) -> Result<SqlQuery, QueryParseError> {
self.skip_whitespace();
let database_name = self.parse_identifier()?;
let query = SqlQuery {
query_type: QueryType::CloseDatabase,
table_name: database_name,
table_alias: None,
joins: Vec::new(),
columns: Vec::new(),
select_all: false,
distinct: false,
where_clause: None,
having_clause: None,
group_by: None,
order_by: None,
limit: None,
sample_by: None,
fill_clause: None,
window_functions: Vec::new(),
insert_columns: Vec::new(),
values: Vec::new(),
table_def: Vec::new(),
primary_key: None,
index_column: None,
index_type: None,
index_params: HashMap::new(),
index_online: true,
update_pairs: Vec::new(),
ignore_duplicates: false,
if_not_exists: false,
model_path: String::new(),
model_inputs: Vec::new(),
model_output: (String::new(), String::new()),
table_config: HashMap::new(),
};
Ok(query)
}
fn parse_drop_database_query(&mut self) -> Result<SqlQuery, QueryParseError> {
let mut if_exists = false;
self.skip_whitespace();
if self.match_keyword("IF") {
self.skip_whitespace();
self.expect_keyword("EXISTS")?;
if_exists = true;
}
self.skip_whitespace();
let database_name = self.parse_identifier()?;
let query = SqlQuery {
query_type: QueryType::DropDatabase,
table_name: database_name,
table_alias: None,
joins: Vec::new(),
columns: Vec::new(),
select_all: false,
distinct: false,
where_clause: None,
having_clause: None,
group_by: None,
order_by: None,
limit: None,
sample_by: None,
fill_clause: None,
window_functions: Vec::new(),
insert_columns: Vec::new(),
values: Vec::new(),
table_def: Vec::new(),
primary_key: None,
index_column: None,
index_type: None,
index_params: HashMap::new(),
index_online: true,
update_pairs: Vec::new(),
ignore_duplicates: if_exists,
if_not_exists: false,
model_path: String::new(),
model_inputs: Vec::new(),
model_output: (String::new(), String::new()),
table_config: HashMap::new(),
};
Ok(query)
}
fn parse_query_type(&mut self) -> Result<QueryType, QueryParseError> {
if self.match_keyword("SELECT") {
Ok(QueryType::Select)
} else if self.match_keyword("INSERT") {
Ok(QueryType::Insert)
} else if self.match_keyword("UPDATE") {
Ok(QueryType::Update)
} else if self.match_keyword("DELETE") {
Ok(QueryType::Delete)
} else if self.match_keyword("DESCRIBE") {
Ok(QueryType::Describe)
} else if self.match_keyword("CREATE") {
self.skip_whitespace();
if self.match_keyword("CHECKPOINT") {
Ok(QueryType::CreateCheckpoint)
} else if self.match_keyword("TIMESERIES") {
self.skip_whitespace();
if self.match_keyword("TABLE") {
Ok(QueryType::CreateTimeSeriesTable)
} else {
Ok(QueryType::Other)
}
} else if self.match_keyword("TABLE") {
Ok(QueryType::CreateTable)
} else if self.match_keyword("INDEX") {
Ok(QueryType::CreateIndex)
} else if self.match_keyword("DATABASE") {
Ok(QueryType::CreateDatabase)
} else if self.match_keyword("MODEL") {
Ok(QueryType::CreateModel)
} else if self.match_keyword("ROLE") {
Ok(QueryType::CreateRole)
} else if self.match_keyword("USER") {
Ok(QueryType::CreateUser)
} else {
Ok(QueryType::Other)
}
} else if self.match_keyword("ALTER") {
self.skip_whitespace();
if self.match_keyword("TABLE") {
Ok(QueryType::AlterTable)
} else {
Ok(QueryType::Other)
}
} else if self.match_keyword("DROP") {
self.skip_whitespace();
if self.match_keyword("TABLE") {
Ok(QueryType::DropTable)
} else if self.match_keyword("DATABASE") {
Ok(QueryType::DropDatabase)
} else if self.match_keyword("ROLE") {
Ok(QueryType::DropRole)
} else if self.match_keyword("USER") {
Ok(QueryType::DropUser)
} else {
Ok(QueryType::Other)
}
} else if self.match_keyword("GRANT") {
self.skip_whitespace();
if self.match_keyword("ROLE") {
Ok(QueryType::GrantRole)
} else {
Ok(QueryType::GrantPermission)
}
} else if self.match_keyword("REVOKE") {
self.skip_whitespace();
if self.match_keyword("ROLE") {
Ok(QueryType::RevokeRole)
} else {
Ok(QueryType::RevokePermission)
}
} else if self.match_keyword("USE") {
self.skip_whitespace();
if self.match_keyword("DATABASE") {
Ok(QueryType::UseDatabase)
} else {
Ok(QueryType::Other)
}
} else if self.match_keyword("CLOSE") {
self.skip_whitespace();
if self.match_keyword("DATABASE") {
Ok(QueryType::CloseDatabase)
} else {
Ok(QueryType::Other)
}
} else if self.match_keyword("BEGIN") {
self.skip_whitespace();
self.match_keyword("TRANSACTION");
Ok(QueryType::BeginTransaction)
} else if self.match_keyword("COMMIT") {
Ok(QueryType::Commit)
} else if self.match_keyword("ROLLBACK") {
Ok(QueryType::Rollback)
} else if self.match_keyword("SHOW") {
self.skip_whitespace();
if self.match_keyword("INDEX") {
self.skip_whitespace();
if self.match_keyword("BUILD") {
self.skip_whitespace();
if self.match_keyword("STATUS") {
Ok(QueryType::ShowIndexBuildStatus)
} else {
Ok(QueryType::Other)
}
} else {
Ok(QueryType::Other)
}
} else if self.match_keyword("TABLES") {
Ok(QueryType::ShowTables)
} else {
Ok(QueryType::Other)
}
} else if self.match_keyword("REINDEX") {
Ok(QueryType::Reindex)
} else {
Ok(QueryType::Other)
}
}
fn parse_having_clause(&mut self) -> Result<Option<WhereClause>, QueryParseError> {
self.skip_whitespace();
if self.match_keyword("HAVING") {
self.skip_whitespace();
let condition = self.parse_condition()?;
Ok(Some(WhereClause { condition }))
} else {
Ok(None)
}
}
fn parse_select_query(&mut self) -> Result<SqlQuery, QueryParseError> {
let (columns, select_all, distinct) = self.parse_select_clause()?;
let (table_name, table_alias, joins) = self.parse_from_and_join_clauses()?;
let where_clause = self.parse_where_clause()?;
let group_by = self.parse_group_by_clause()?;
let having_clause = self.parse_having_clause()?;
let order_by = self.parse_order_by_clause()?;
let limit = self.parse_limit_clause()?;
let sample_by = self.parse_sample_by_clause()?;
let fill_clause = self.parse_fill_clause()?;
let mut query = SqlQuery {
query_type: QueryType::Select,
table_name,
table_alias,
joins,
columns,
select_all,
distinct,
where_clause,
having_clause: None,
group_by,
order_by,
limit,
sample_by,
fill_clause,
window_functions: Vec::new(),
insert_columns: Vec::new(),
values: Vec::new(),
table_def: Vec::new(),
primary_key: None,
index_column: None,
index_type: None,
index_params: std::collections::HashMap::new(),
index_online: true,
update_pairs: Vec::new(),
ignore_duplicates: false,
if_not_exists: false,
model_path: String::new(),
model_inputs: Vec::new(),
model_output: (String::new(), String::new()),
table_config: HashMap::new(),
};
query.having_clause = having_clause;
Ok(query)
}
fn parse_select_clause(&mut self) -> Result<(Vec<Expression>, bool, bool), QueryParseError> {
self.skip_whitespace();
let distinct = self.match_keyword("DISTINCT");
self.skip_whitespace();
if self.match_char('*') {
Ok((Vec::new(), true, distinct))
} else {
let mut expressions = Vec::new();
loop {
self.skip_whitespace();
let expr = self.parse_expression()?;
expressions.push(expr);
self.skip_whitespace();
if !self.match_char(',') {
break;
}
}
Ok((expressions, false, distinct))
}
}
fn parse_expression(&mut self) -> Result<Expression, QueryParseError> {
self.skip_whitespace();
let mut left_expr = self.parse_primary_expression()?;
loop {
self.skip_whitespace();
let saved_pos = self.position;
let saved_col = self.column;
let op = match self.peek_char() {
Some('+') => {
self.next_char();
BinaryOperator::Add
}
Some('-') => {
self.next_char();
BinaryOperator::Subtract
}
Some('*') => {
self.next_char();
BinaryOperator::Multiply
}
Some('/') => {
self.next_char();
BinaryOperator::Divide
}
Some('<') => {
self.next_char();
match self.peek_char() {
Some('-') => {
self.next_char();
if self.peek_char() == Some('>') {
self.next_char();
BinaryOperator::VectorL2 } else {
self.position = saved_pos;
self.column = saved_col;
break;
}
}
Some('#') => {
self.next_char();
if self.peek_char() == Some('>') {
self.next_char();
BinaryOperator::VectorIP } else {
self.position = saved_pos;
self.column = saved_col;
break;
}
}
Some('=') => {
self.next_char();
if self.peek_char() == Some('>') {
self.next_char();
BinaryOperator::VectorCosine } else {
BinaryOperator::LessThanOrEqual
}
}
_ => BinaryOperator::LessThan,
}
}
Some('>') => {
self.next_char();
if self.peek_char() == Some('=') {
self.next_char();
BinaryOperator::GreaterThanOrEqual
} else {
BinaryOperator::GreaterThan
}
}
Some('=') => {
self.next_char();
BinaryOperator::Equal
}
Some('!') => {
self.next_char();
if self.peek_char() == Some('=') {
self.next_char();
BinaryOperator::NotEqual
} else {
break;
}
}
_ => break,
};
self.skip_whitespace();
let right_expr = self.parse_primary_expression()?;
left_expr = Expression::BinaryOp {
left: Box::new(left_expr),
op,
right: Box::new(right_expr),
alias: None,
};
}
self.skip_whitespace();
if self.match_keyword("IS") {
self.skip_whitespace();
let is_not = self.match_keyword("NOT");
self.skip_whitespace();
if self.match_keyword("NULL") {
let right_expr = Expression::Constant {
value: Value::Null,
alias: None,
};
let op = if is_not {
BinaryOperator::NotEqual
} else {
BinaryOperator::Equal
};
left_expr = Expression::BinaryOp {
left: Box::new(left_expr),
op,
right: Box::new(right_expr),
alias: None,
};
}
}
self.skip_whitespace();
let alias = self.parse_alias()?;
match left_expr {
Expression::Field {
alias: expr_alias,
name,
..
} => Ok(Expression::Field {
name,
alias: alias.or(expr_alias),
}),
Expression::FunctionCall {
alias: expr_alias,
name,
args,
..
} => Ok(Expression::FunctionCall {
name,
args,
alias: alias.or(expr_alias),
}),
Expression::Constant {
alias: expr_alias,
value,
..
} => Ok(Expression::Constant {
value,
alias: alias.or(expr_alias),
}),
Expression::BinaryOp {
left, op, right, ..
} => Ok(Expression::BinaryOp {
left,
op,
right,
alias,
}),
Expression::LogicalOp {
left, op, right, ..
} => Ok(Expression::LogicalOp {
left,
op,
right,
alias,
}),
Expression::UnaryOp { op, operand, .. } => {
Ok(Expression::UnaryOp { op, operand, alias })
}
}
}
fn parse_primary_expression(&mut self) -> Result<Expression, QueryParseError> {
self.skip_whitespace();
let saved_pos = self.position;
let saved_col = self.column;
if self.match_char('*') {
return Ok(Expression::Field {
name: "*".to_string(),
alias: None,
});
}
if self.peek_char() == Some('[') {
if let Ok(value) = self.parse_value() {
return Ok(Expression::Constant { value, alias: None });
} else {
self.position = saved_pos;
self.column = saved_col;
}
}
let current_char = self.peek_char().ok_or(QueryParseError::InvalidSyntax)?;
if current_char.is_ascii_digit()
|| current_char == '-'
|| current_char == '"'
|| current_char == '\''
|| current_char.is_ascii_alphabetic()
{
let saved_pos_bool = self.position;
if self.match_keyword("TRUE") {
return Ok(Expression::Constant {
value: Value::Boolean(true),
alias: None,
});
} else if self.match_keyword("FALSE") {
return Ok(Expression::Constant {
value: Value::Boolean(false),
alias: None,
});
} else if self.match_keyword("NULL") {
return Ok(Expression::Constant {
value: Value::Null,
alias: None,
});
}
self.position = saved_pos_bool;
self.column = saved_col;
if current_char.is_ascii_digit() || current_char == '-' {
let value = self.parse_value()?;
return Ok(Expression::Constant { value, alias: None });
}
else if current_char == '"' || current_char == '\'' {
let value = self.parse_value()?;
return Ok(Expression::Constant { value, alias: None });
}
}
let func_saved_pos = self.position;
let func_saved_col = self.column;
if let Ok(function_name) = self.parse_identifier() {
self.skip_whitespace();
if self.peek_char() == Some('(') {
self.next_char();
let mut args = Vec::new();
loop {
self.skip_whitespace();
if self.peek_char() == Some(')') {
break;
}
let arg_expr = self.parse_expression()?;
args.push(arg_expr);
self.skip_whitespace();
if self.match_char(',') {
continue;
} else {
break;
}
}
self.skip_whitespace();
self.expect_char(')')?;
return Ok(Expression::FunctionCall {
name: function_name,
args,
alias: None,
});
}
}
self.position = func_saved_pos;
self.column = func_saved_col;
let identifier = self.parse_identifier()?;
if identifier.eq_ignore_ascii_case("INTERVAL") {
self.skip_whitespace();
let interval_value = self.parse_value()?;
self.skip_whitespace();
if let Ok(unit) = self.parse_identifier() {
let interval_str = match interval_value {
Value::Integer(i) => alloc::format!("{} {}", i, unit),
Value::String(s) => alloc::format!("{} {}", s, unit),
_ => return Err(QueryParseError::InvalidValue),
};
return Ok(Expression::Constant {
value: Value::String(interval_str),
alias: None,
});
} else {
return Ok(Expression::Constant {
value: interval_value,
alias: None,
});
}
}
else {
return Ok(Expression::Field {
name: identifier,
alias: None,
});
}
}
fn parse_function_call(&mut self) -> Result<Expression, QueryParseError> {
let function_name = self.parse_identifier()?;
self.skip_whitespace();
if !self.match_char('(') {
return Err(QueryParseError::InvalidSyntax);
}
let args = self.parse_function_args()?;
self.skip_whitespace();
if !self.match_char(')') {
return Err(QueryParseError::InvalidSyntax);
}
let alias = self.parse_alias()?;
Ok(Expression::FunctionCall {
name: function_name,
args,
alias,
})
}
fn parse_function_args(&mut self) -> Result<Vec<Expression>, QueryParseError> {
let mut args = Vec::new();
self.skip_whitespace();
if self.peek_char() == Some(')') {
return Ok(args);
}
loop {
let arg = self.parse_expression()?;
args.push(arg);
self.skip_whitespace();
if self.match_char(',') {
continue;
} else {
break;
}
}
Ok(args)
}
fn parse_alias(&mut self) -> Result<Option<String>, QueryParseError> {
self.skip_whitespace();
let _saved_pos = self.position;
let _saved_col = self.column;
if self.match_keyword("AS") {
self.skip_whitespace();
}
let next_token = self.peek_identifier();
if let Some(token) = next_token {
let token_upper = token.to_uppercase();
let keywords = [
"FROM", "WHERE", "ORDER", "LIMIT", "GROUP", "HAVING", "JOIN", "ON", "IN", "AND",
"OR", "NOT",
];
if keywords.contains(&token_upper.as_str()) {
return Ok(None);
}
}
if self
.peek_char()
.is_some_and(|c| c.is_ascii_alphabetic() || c == '_')
{
let alias = self.parse_identifier()?;
Ok(Some(alias))
} else {
Ok(None)
}
}
fn parse_from_and_join_clauses(
&mut self,
) -> Result<(String, Option<String>, Vec<JoinClause>), QueryParseError> {
self.skip_whitespace();
if !self.match_keyword("FROM") {
return Ok((String::new(), None, Vec::new()));
}
self.skip_whitespace();
let table_name = self.parse_identifier()?;
if table_name.is_empty() {
return Err(QueryParseError::InvalidSyntax);
}
self.skip_whitespace();
let table_alias = self.parse_alias()?;
let mut joins = Vec::new();
loop {
self.skip_whitespace();
let join_type = match self.peek_identifier() {
Some(token) => {
let token_upper = token.to_uppercase();
match token_upper.as_str() {
"INNER" => {
self.parse_identifier()?;
self.skip_whitespace();
if !self.match_keyword("JOIN") {
return Err(QueryParseError::InvalidSyntax);
}
JoinType::Inner
}
"LEFT" => {
self.parse_identifier()?;
self.skip_whitespace();
if self.match_keyword("OUTER") {
self.skip_whitespace();
}
if !self.match_keyword("JOIN") {
return Err(QueryParseError::InvalidSyntax);
}
JoinType::Left
}
"RIGHT" => {
self.parse_identifier()?;
self.skip_whitespace();
if self.match_keyword("OUTER") {
self.skip_whitespace();
}
if !self.match_keyword("JOIN") {
return Err(QueryParseError::InvalidSyntax);
}
JoinType::Right
}
"FULL" => {
self.parse_identifier()?;
self.skip_whitespace();
if self.match_keyword("OUTER") {
self.skip_whitespace();
}
if !self.match_keyword("JOIN") {
return Err(QueryParseError::InvalidSyntax);
}
JoinType::Full
}
"JOIN" => {
self.parse_identifier()?;
JoinType::Inner
}
_ => break, }
}
None => break, };
self.skip_whitespace();
let join_table_name = self.parse_identifier()?;
self.skip_whitespace();
let join_table_alias = self.parse_alias()?;
self.skip_whitespace();
self.expect_keyword("ON")?;
self.skip_whitespace();
let on_condition = self.parse_condition()?;
let join_clause = JoinClause {
join_type,
table_name: join_table_name,
table_alias: join_table_alias,
on_condition,
};
joins.push(join_clause);
}
Ok((table_name, table_alias, joins))
}
fn parse_where_clause(&mut self) -> Result<Option<WhereClause>, QueryParseError> {
self.skip_whitespace();
if self.match_keyword("WHERE") {
self.skip_whitespace();
let condition = self.parse_condition()?;
Ok(Some(WhereClause { condition }))
} else {
Ok(None)
}
}
fn parse_group_by_clause(&mut self) -> Result<Option<GroupByClause>, QueryParseError> {
self.skip_whitespace();
if self.match_keyword("GROUP") {
self.skip_whitespace();
self.expect_keyword("BY")?;
let mut expressions = Vec::new();
let mut fields = Vec::new();
loop {
self.skip_whitespace();
let expr = self.parse_expression()?;
expressions.push(expr.clone());
if let Expression::Field { name, .. } = expr {
fields.push(name);
}
self.skip_whitespace();
if !self.match_char(',') {
break;
}
}
Ok(Some(GroupByClause {
expressions,
fields,
}))
} else {
Ok(None)
}
}
}
pub fn expression_to_order_by_string(expr: &Expression) -> String {
match expr {
Expression::Field { name, .. } => name.clone(),
Expression::BinaryOp {
left, op, right, ..
} => {
let left_name = match left.as_ref() {
Expression::Field { name, .. } => name.clone(),
_ => return String::new(),
};
let op_str = match op {
BinaryOperator::VectorL2 => "<->",
BinaryOperator::VectorIP => "<#>",
BinaryOperator::VectorCosine => "<=>",
_ => return String::new(),
};
let right_str = match right.as_ref() {
Expression::Constant { value, .. } => match value {
crate::sql::Value::Json(json_str) => json_str.clone(),
crate::sql::Value::String(s) => s.clone(),
_ => format!("{:?}", value),
},
_ => format!("{:?}", right.as_ref()),
};
format!("{} {} {}", left_name, op_str, right_str)
}
Expression::Constant { value, .. } => format!("{:?}", value),
_ => format!("{:?}", expr),
}
}
impl SqlParser {
fn parse_order_by_clause(&mut self) -> Result<Option<OrderByClause>, QueryParseError> {
self.skip_whitespace();
if self.match_keyword("ORDER") {
self.skip_whitespace();
self.expect_keyword("BY")?;
self.skip_whitespace();
let field = if let Some(c) = self.peek_char() {
if c.is_ascii_digit() {
self.parse_number()?.to_string()
} else {
let expr = self.parse_vector_expression()?;
self::expression_to_order_by_string(&expr)
}
} else {
return Err(QueryParseError::InvalidSyntax);
};
self.skip_whitespace();
let direction = if self.match_keyword("DESC") {
OrderDirection::Descending
} else {
self.match_keyword("ASC");
OrderDirection::Ascending
};
Ok(Some(OrderByClause { field, direction }))
} else {
Ok(None)
}
}
fn parse_limit_clause(&mut self) -> Result<Option<usize>, QueryParseError> {
self.skip_whitespace();
if self.match_keyword("LIMIT") {
self.skip_whitespace();
let limit = self.parse_number()? as usize;
Ok(Some(limit))
} else {
Ok(None)
}
}
fn parse_sample_by_clause(&mut self) -> Result<Option<String>, QueryParseError> {
self.skip_whitespace();
if self.match_keyword("SAMPLE") {
self.skip_whitespace();
if !self.match_keyword("BY") {
return Err(QueryParseError::InvalidSyntax);
}
self.skip_whitespace();
let start = self.position;
while let Some(c) = self.peek_char() {
if c.is_ascii_alphanumeric() {
self.next_char();
} else {
break;
}
}
if self.position == start {
return Err(QueryParseError::InvalidValue);
}
let interval = self.input[start..self.position].to_string();
Ok(Some(interval))
} else {
Ok(None)
}
}
fn parse_fill_clause(&mut self) -> Result<Option<FillClause>, QueryParseError> {
self.skip_whitespace();
if self.match_keyword("FILL") {
self.skip_whitespace();
if self.match_keyword("PREV") {
Ok(Some(FillClause::Prev))
} else if self.match_keyword("LINEAR") {
Ok(Some(FillClause::Linear))
} else if self.match_keyword("NEXT") {
Ok(Some(FillClause::Next))
} else {
let saved_pos = self.position;
let saved_col = self.column;
match self.parse_number() {
Ok(num) => Ok(Some(FillClause::FixedValue(num as f64))),
Err(_) => {
self.position = saved_pos;
self.column = saved_col;
Err(QueryParseError::InvalidValue)
}
}
}
} else {
Ok(None)
}
}
fn parse_condition(&mut self) -> Result<Condition, QueryParseError> {
self.parse_where_condition()
}
fn parse_where_condition(&mut self) -> Result<Condition, QueryParseError> {
self.skip_whitespace();
if self.match_keyword("NOT") {
let inner_condition = self.parse_where_condition()?;
return Ok(Condition::Not(Box::new(inner_condition)));
}
let mut condition = self.parse_single_condition()?;
loop {
self.skip_whitespace();
if self.match_keyword("AND") {
let right_condition = self.parse_where_condition()?;
condition = Condition::And(Box::new(condition), Box::new(right_condition));
} else if self.match_keyword("OR") {
let right_condition = self.parse_where_condition()?;
condition = Condition::Or(Box::new(condition), Box::new(right_condition));
} else {
break;
}
}
Ok(condition)
}
fn parse_single_condition(&mut self) -> Result<Condition, QueryParseError> {
self.skip_whitespace();
if self.match_keyword("NOT") {
let inner_condition = self.parse_single_condition()?;
return Ok(Condition::Not(Box::new(inner_condition)));
}
if self.match_char('(') {
let inner_condition = self.parse_where_condition()?;
self.skip_whitespace();
self.expect_char(')')?;
return Ok(inner_condition);
}
let saved_pos = self.position;
let saved_col = self.column;
if let Ok(condition) = self.parse_between_condition() {
return Ok(condition);
}
self.position = saved_pos;
self.column = saved_col;
let saved_pos_compare = self.position;
let saved_col_compare = self.column;
if let Ok(condition) = self.parse_comparison_condition() {
return Ok(condition);
}
self.position = saved_pos_compare;
self.column = saved_col_compare;
let expr = self.parse_expression()?;
Ok(Condition::Comparison(ComparisonCondition {
field: match expr {
Expression::Field { name, alias: None } => name,
_ => format!("{:?}", expr),
},
operator: ComparisonOperator::Equal,
value: Value::Boolean(true),
}))
}
fn parse_between_condition(&mut self) -> Result<Condition, QueryParseError> {
let left_expr = self.parse_vector_expression()?;
self.skip_whitespace();
if !self.match_keyword("BETWEEN") {
return Err(QueryParseError::InvalidSyntax);
}
self.skip_whitespace();
let min_value = self.parse_value()?;
self.skip_whitespace();
self.expect_keyword("AND")?;
self.skip_whitespace();
let max_value = self.parse_value()?;
let field = match left_expr {
Expression::Field { name, alias: None } => name,
Expression::BinaryOp {
left,
op,
right,
alias: None,
} => {
let left_name = match *left {
Expression::Field { name, alias: None } => name,
_ => format!("{:?}", *left),
};
let right_str = match *right {
Expression::Constant { value, alias: None } => format!("{:?}", value),
_ => format!("{:?}", *right),
};
let op_str = match op {
BinaryOperator::Add => "+",
BinaryOperator::Subtract => "-",
BinaryOperator::Multiply => "*",
BinaryOperator::Equal => "=",
BinaryOperator::NotEqual => "!=",
BinaryOperator::GreaterThan => ">",
BinaryOperator::GreaterThanOrEqual => ">=",
BinaryOperator::LessThan => "<",
BinaryOperator::LessThanOrEqual => "<=",
BinaryOperator::VectorL2 => "<->",
BinaryOperator::VectorIP => "<#>",
BinaryOperator::VectorCosine => "<=>",
_ => "?",
};
format!("{} {} {}", left_name, op_str, right_str)
}
_ => format!("{:?}", left_expr),
};
Ok(Condition::Between(BetweenCondition {
field,
min_value,
max_value,
}))
}
fn parse_comparison_condition(&mut self) -> Result<Condition, QueryParseError> {
let _saved_pos = self.position;
let _saved_col = self.column;
let left_expr = self.parse_vector_expression()?;
self.skip_whitespace();
let operator = if self.match_keyword("LIKE") {
ComparisonOperator::Like
} else {
self.parse_comparison_operator()?
};
self.skip_whitespace();
let right_value = self.parse_value()?;
Ok(Condition::Comparison(ComparisonCondition {
field: match left_expr {
Expression::Field { name, alias: None } => name,
Expression::BinaryOp {
left,
op,
right,
alias: None,
} => {
let field_name = match *left {
Expression::Field { name, alias: None } => name,
_ => return Err(QueryParseError::InvalidSyntax),
};
let op_str = match op {
BinaryOperator::VectorL2 => "<->",
BinaryOperator::VectorIP => "<#>",
BinaryOperator::VectorCosine => "<=>",
_ => return Err(QueryParseError::InvalidSyntax),
};
let vector_str = match *right {
Expression::Constant {
ref value,
alias: None,
} => match value {
Value::String(ref vec_str) => vec_str.clone(),
Value::Json(ref json_str) => json_str.clone(),
_ => return Err(QueryParseError::InvalidSyntax),
},
_ => return Err(QueryParseError::InvalidSyntax),
};
format!("{field_name} {op_str} {vector_str}")
}
_ => format!("{:?}", left_expr),
},
operator,
value: right_value,
}))
}
fn parse_vector_expression(&mut self) -> Result<Expression, QueryParseError> {
let mut expr = self.parse_primary_expression()?;
self.skip_whitespace();
let saved_pos = self.position;
let saved_col = self.column;
let op = match self.peek_char() {
Some('<') => {
self.next_char();
match self.peek_char() {
Some('-') => {
self.next_char();
if self.peek_char() == Some('>') {
self.next_char();
Some(BinaryOperator::VectorL2) } else {
self.position = saved_pos;
self.column = saved_col;
None
}
}
Some('#') => {
self.next_char();
if self.peek_char() == Some('>') {
self.next_char();
Some(BinaryOperator::VectorIP) } else {
self.position = saved_pos;
self.column = saved_col;
None
}
}
Some('=') => {
self.next_char();
if self.peek_char() == Some('>') {
self.next_char();
Some(BinaryOperator::VectorCosine) } else {
self.position = saved_pos;
self.column = saved_col;
None
}
}
_ => {
self.position = saved_pos;
self.column = saved_col;
None
}
}
}
_ => None,
};
if let Some(op) = op {
self.skip_whitespace();
let right_expr = self.parse_primary_expression()?;
expr = Expression::BinaryOp {
left: Box::new(expr),
op,
right: Box::new(right_expr),
alias: None,
};
self.skip_whitespace();
}
Ok(expr)
}
fn parse_comparison_operator(&mut self) -> Result<ComparisonOperator, QueryParseError> {
if self.match_str("=") {
Ok(ComparisonOperator::Equal)
} else if self.match_str("<>") || self.match_str("!=") {
Ok(ComparisonOperator::NotEqual)
} else if self.match_str(">=") {
Ok(ComparisonOperator::GreaterThanOrEqual)
} else if self.match_str(">") {
Ok(ComparisonOperator::GreaterThan)
} else if self.match_str("<=") {
Ok(ComparisonOperator::LessThanOrEqual)
} else if self.match_str("<") {
Ok(ComparisonOperator::LessThan)
} else {
Err(QueryParseError::InvalidOperator)
}
}
fn parse_operator(&mut self) -> Result<ComparisonOperator, QueryParseError> {
if self.match_str("=") {
Ok(ComparisonOperator::Equal)
} else if self.match_str("<>") || self.match_str("!=") {
Ok(ComparisonOperator::NotEqual)
} else if self.match_str(">") {
Ok(ComparisonOperator::GreaterThan)
} else if self.match_str(">=") {
Ok(ComparisonOperator::GreaterThanOrEqual)
} else if self.match_str("<") {
Ok(ComparisonOperator::LessThan)
} else if self.match_str("<=") {
Ok(ComparisonOperator::LessThanOrEqual)
} else {
Err(QueryParseError::InvalidOperator)
}
}
fn parse_value(&mut self) -> Result<Value, QueryParseError> {
let _saved_pos = self.position;
if self.peek_char() == Some('"') || self.peek_char() == Some('\'') {
let quote_char = self.next_char().ok_or(RemDbError::InvalidSqlQuery)?;
let mut string_value = String::new();
while let Some(c) = self.next_char() {
if c == quote_char {
break;
}
string_value.push(c);
}
if string_value.starts_with("__JSON__:") {
let json_str = string_value.trim_start_matches("__JSON__:");
#[cfg(feature = "log")]
debug!("parse_value: Parsed as JSON with prefix");
Ok(Value::Json(json_str.to_string()))
} else {
let unquoted = string_value
.trim_start_matches('"')
.trim_end_matches('"')
.trim_start_matches('\'')
.trim_end_matches('\'');
if unquoted.starts_with('{') || unquoted.starts_with('[') {
#[cfg(feature = "log")]
debug!("parse_value: Parsed as JSON (unquoted starts with {{ or [)");
Ok(Value::Json(unquoted.to_string()))
} else {
if let Ok(timestamp) = parse_time_string(&string_value) {
#[cfg(feature = "log")]
debug!("parse_value: Parsed as timestamp");
Ok(Value::Integer(timestamp))
} else {
#[cfg(feature = "log")]
debug!("parse_value: Parsed as String");
Ok(Value::String(string_value))
}
}
}
} else if self.match_keyword("NULL") {
Ok(Value::Null)
} else if self.match_keyword("TRUE") {
Ok(Value::Boolean(true))
} else if self.match_keyword("FALSE") {
Ok(Value::Boolean(false))
} else if self.match_keyword("NOW") {
self.skip_whitespace();
self.expect_char('(')?;
self.skip_whitespace();
self.expect_char(')')?;
Ok(Value::Integer(0))
} else if self.match_keyword("CURRENT_TIMESTAMP") {
self.skip_whitespace();
if self.peek_char() == Some('(') {
self.next_char();
self.skip_whitespace();
self.expect_char(')')?;
}
Ok(Value::Integer(0))
} else if self.match_keyword("LOCALTIMESTAMP") {
self.skip_whitespace();
if self.peek_char() == Some('(') {
self.next_char();
self.skip_whitespace();
self.expect_char(')')?;
}
Ok(Value::Integer(0))
} else if self.match_keyword("TIMEZONE") {
self.skip_whitespace();
self.expect_char('(')?;
self.skip_whitespace();
while self.peek_char() != Some(')') {
self.next_char();
}
self.next_char();
Ok(Value::Integer(0))
} else if self.match_keyword("TO_CHAR") {
self.skip_whitespace();
self.expect_char('(')?;
self.skip_whitespace();
while self.peek_char() != Some(')') {
self.next_char();
}
self.next_char();
Ok(Value::Integer(0))
} else if self.match_keyword("TO_ISO8601") {
self.skip_whitespace();
self.expect_char('(')?;
self.skip_whitespace();
while self.peek_char() != Some(')') {
self.next_char();
}
self.next_char();
Ok(Value::Integer(0))
} else if self.match_keyword("TO_EPOCH") {
self.skip_whitespace();
self.expect_char('(')?;
self.skip_whitespace();
while self.peek_char() != Some(')') {
self.next_char();
}
self.next_char();
Ok(Value::Integer(0))
} else if self.peek_char() == Some('[') {
let start_pos = self.position;
self.next_char();
let mut bracket_count = 1;
let mut end_pos = start_pos + 1;
let mut in_string = false;
let mut quote_char = '"';
while bracket_count > 0 {
if self.is_eof() {
return Err(QueryParseError::InvalidSyntax);
}
let c = self.next_char().ok_or(RemDbError::InvalidSqlQuery)?;
end_pos += 1;
if c == '"' || c == '\'' {
if !in_string {
in_string = true;
quote_char = c;
} else if c == quote_char {
in_string = false;
}
}
if !in_string {
if c == '[' {
bracket_count += 1;
} else if c == ']' {
bracket_count -= 1;
}
}
}
let json_str = self.input[start_pos..end_pos].to_string();
Ok(Value::Json(json_str))
} else if self.peek_char() == Some('{') {
let start_pos = self.position;
self.next_char();
let mut brace_count = 1;
let mut end_pos = start_pos + 1;
let mut in_string = false;
let mut quote_char = '"';
while brace_count > 0 {
if self.is_eof() {
return Err(QueryParseError::InvalidSyntax);
}
let c = self.next_char().ok_or(RemDbError::InvalidSqlQuery)?;
end_pos += 1;
if c == '"' || c == '\'' {
if !in_string {
in_string = true;
quote_char = c;
} else if c == quote_char {
in_string = false;
}
}
if !in_string {
if c == '{' {
brace_count += 1;
} else if c == '}' {
brace_count -= 1;
}
}
}
let json_str = self.input[start_pos..end_pos].to_string();
Ok(Value::Json(json_str))
} else if self
.peek_char()
.is_some_and(|c| c.is_ascii_digit() || c == '-')
{
let number_str = self.parse_number_str()?;
if number_str.contains('.') {
let float_value = number_str
.parse::<f64>()
.map_err(|_| QueryParseError::InvalidValue)?;
Ok(Value::Float(float_value))
} else {
let int_value = number_str
.parse::<i64>()
.map_err(|_| QueryParseError::InvalidValue)?;
Ok(Value::Integer(int_value))
}
} else if self
.peek_char()
.is_some_and(|c| c.is_ascii_alphabetic() || c == '_')
{
let identifier = self.parse_identifier()?;
Ok(Value::Identifier(identifier))
} else {
return Err(QueryParseError::InvalidValue);
}
}
fn parse_identifier(&mut self) -> Result<String, QueryParseError> {
let start = self.position;
let c = self.peek_char().ok_or(QueryParseError::InvalidSyntax)?;
if !c.is_ascii_alphabetic() && c != '_' {
return Err(QueryParseError::InvalidSyntax);
}
self.next_char();
while let Some(c) = self.peek_char() {
if c.is_ascii_alphanumeric() || c == '_' || c == '.' {
self.next_char();
} else {
break;
}
}
Ok(self.input[start..self.position].to_string())
}
fn parse_number_str(&mut self) -> Result<String, QueryParseError> {
let start = self.position;
if self.match_char('-') {
}
if !self.peek_char().is_some_and(|c| c.is_ascii_digit()) {
return Err(QueryParseError::InvalidValue);
}
while let Some(c) = self.peek_char() {
if c.is_ascii_digit() || c == '.' {
self.next_char();
} else {
break;
}
}
Ok(self.input[start..self.position].to_string())
}
fn parse_number(&mut self) -> Result<usize, QueryParseError> {
let number_str = self.parse_number_str()?;
number_str
.parse::<usize>()
.map_err(|_| QueryParseError::InvalidValue)
}
fn match_keyword(&mut self, keyword: &str) -> bool {
let start = self.position;
let keyword_bytes = keyword.as_bytes();
let end = start + keyword_bytes.len();
if end <= self.input.as_bytes().len() {
let actual_bytes = &self.input.as_bytes()[start..end];
let expected_bytes = keyword_bytes;
if actual_bytes.eq_ignore_ascii_case(expected_bytes) {
let next_char = self.input.as_bytes().get(end).map(|&b| b as char);
if next_char.is_none() || !next_char.unwrap_or(' ').is_ascii_alphanumeric() {
self.position = end;
self.column += keyword.len();
return true;
}
}
}
false
}
fn match_str(&mut self, s: &str) -> bool {
let start = self.position;
let s_bytes = s.as_bytes();
let end = start + s_bytes.len();
if end <= self.input.as_bytes().len() {
if &self.input.as_bytes()[start..end] == s_bytes {
self.position = end;
self.column += s.len();
return true;
}
}
false
}
fn match_char(&mut self, c: char) -> bool {
if self.peek_char() == Some(c) {
self.next_char();
true
} else {
false
}
}
fn expect_keyword(&mut self, keyword: &str) -> Result<(), QueryParseError> {
if self.match_keyword(keyword) {
Ok(())
} else {
Err(QueryParseError::InvalidSyntax)
}
}
fn peek_char(&self) -> Option<char> {
if self.position < self.input.as_bytes().len() {
Some(self.input.as_bytes()[self.position] as char)
} else {
None
}
}
fn next_char(&mut self) -> Option<char> {
if let Some(c) = self.peek_char() {
self.position += 1;
if c == '\n' {
self.line += 1;
self.column = 1;
} else {
self.column += 1;
}
Some(c)
} else {
None
}
}
fn skip_whitespace(&mut self) {
let max_skips = self.input.len();
let mut skips = 0;
while let Some(c) = self.peek_char() {
if skips > max_skips {
break; }
if c.is_whitespace() {
self.next_char();
skips += 1;
} else {
break;
}
}
}
fn is_eof(&self) -> bool {
self.position >= self.input.len()
}
fn parse_data_type(&mut self) -> Result<String, QueryParseError> {
let base_type = self.parse_identifier()?;
let mut result = base_type.clone();
self.skip_whitespace();
if self.match_char('(') {
result.push('(');
let mut depth = 1;
while depth > 0 {
let c = self.next_char().ok_or(QueryParseError::InvalidSyntax)?;
result.push(c);
if c == '(' {
depth += 1;
} else if c == ')' {
depth -= 1;
}
}
}
self.skip_whitespace();
if self.peek_char().is_some() {
let next_token = self.peek_identifier();
if let Some(token) = next_token {
let token_upper = token.to_uppercase();
if [
"PRIMARY",
"NOT",
"UNIQUE",
"AUTOINCREMENT",
"AUTO_INCREMENT",
"DEFAULT",
]
.contains(&token_upper.as_str())
{
return Ok(result);
}
}
let c = self.peek_char().ok_or(RemDbError::InvalidSqlQuery)?;
if c.is_ascii_alphabetic() || c == '_' {
let modifier = self.parse_identifier()?;
result.push(' ');
result.push_str(&modifier);
if modifier.eq_ignore_ascii_case("WITH") {
self.skip_whitespace();
if self.peek_char().is_some() {
let next_token = self.peek_identifier();
if let Some(token) = next_token {
let token_upper = token.to_uppercase();
if ![
"PRIMARY",
"NOT",
"UNIQUE",
"AUTOINCREMENT",
"AUTO_INCREMENT",
"DEFAULT",
]
.contains(&token_upper.as_str())
{
let next_char =
self.peek_char().ok_or(RemDbError::InvalidSqlQuery)?;
if next_char.is_ascii_alphabetic() || next_char == '_' {
let with_modifier = self.parse_identifier()?;
result.push(' ');
result.push_str(&with_modifier);
self.skip_whitespace();
if self.match_char('=') {
result.push('=');
let value = self.parse_identifier()?;
result.push_str(&value);
}
}
}
}
}
}
}
}
Ok(result)
}
fn peek_identifier(&self) -> Option<String> {
let start = self.position;
let mut pos = start;
if let Some(c) = self.input.chars().nth(pos) {
if !c.is_ascii_alphabetic() && c != '_' {
return None;
}
pos += 1;
while let Some(c) = self.input.chars().nth(pos) {
if c.is_ascii_alphanumeric() || c == '_' {
pos += 1;
} else {
break;
}
}
Some(self.input[start..pos].to_string())
} else {
None
}
}
fn expect_char(&mut self, c: char) -> Result<(), QueryParseError> {
if self.match_char(c) {
Ok(())
} else {
Err(QueryParseError::InvalidSyntax)
}
}
fn parse_create_role_query(&mut self) -> Result<SqlQuery, QueryParseError> {
self.skip_whitespace();
let role_name = self.parse_identifier()?;
Ok(SqlQuery {
query_type: QueryType::CreateRole,
table_name: role_name,
table_alias: None,
joins: Vec::new(),
columns: Vec::new(),
select_all: false,
distinct: false,
where_clause: None,
having_clause: None,
group_by: None,
order_by: None,
limit: None,
sample_by: None,
fill_clause: None,
window_functions: Vec::new(),
insert_columns: Vec::new(),
values: Vec::new(),
table_def: Vec::new(),
primary_key: None,
index_column: None,
index_type: None,
index_params: HashMap::new(),
index_online: true,
update_pairs: Vec::new(),
ignore_duplicates: false,
if_not_exists: false,
model_path: String::new(),
model_inputs: Vec::new(),
model_output: (String::new(), String::new()),
table_config: HashMap::new(),
})
}
fn parse_create_user_query(&mut self) -> Result<SqlQuery, QueryParseError> {
self.skip_whitespace();
let user_name = self.parse_identifier()?;
Ok(SqlQuery {
query_type: QueryType::CreateUser,
table_name: user_name,
table_alias: None,
joins: Vec::new(),
columns: Vec::new(),
select_all: false,
distinct: false,
where_clause: None,
having_clause: None,
group_by: None,
order_by: None,
limit: None,
sample_by: None,
fill_clause: None,
window_functions: Vec::new(),
insert_columns: Vec::new(),
values: Vec::new(),
table_def: Vec::new(),
primary_key: None,
index_column: None,
index_type: None,
index_params: HashMap::new(),
index_online: true,
update_pairs: Vec::new(),
ignore_duplicates: false,
if_not_exists: false,
model_path: String::new(),
model_inputs: Vec::new(),
model_output: (String::new(), String::new()),
table_config: HashMap::new(),
})
}
fn parse_grant_permission_query(&mut self) -> Result<SqlQuery, QueryParseError> {
let mut permissions = Vec::new();
loop {
self.skip_whitespace();
let permission = self.parse_identifier()?;
permissions.push(permission);
self.skip_whitespace();
if self.match_char(',') {
continue;
} else {
break;
}
}
self.skip_whitespace();
self.expect_keyword("ON")?;
self.skip_whitespace();
let table_name = self.parse_identifier()?;
self.skip_whitespace();
self.expect_keyword("TO")?;
self.skip_whitespace();
let role_name = self.parse_identifier()?;
Ok(SqlQuery {
query_type: QueryType::GrantPermission,
table_name,
table_alias: Some(role_name),
joins: Vec::new(),
columns: permissions
.into_iter()
.map(|p| Expression::Field {
name: p,
alias: None,
})
.collect(),
select_all: false,
distinct: false,
where_clause: None,
having_clause: None,
group_by: None,
order_by: None,
limit: None,
sample_by: None,
fill_clause: None,
window_functions: Vec::new(),
insert_columns: Vec::new(),
values: Vec::new(),
table_def: Vec::new(),
primary_key: None,
index_column: None,
index_type: None,
index_params: HashMap::new(),
index_online: true,
update_pairs: Vec::new(),
ignore_duplicates: false,
if_not_exists: false,
model_path: String::new(),
model_inputs: Vec::new(),
model_output: (String::new(), String::new()),
table_config: HashMap::new(),
})
}
fn parse_grant_role_query(&mut self) -> Result<SqlQuery, QueryParseError> {
self.skip_whitespace();
let role_name = self.parse_identifier()?;
self.skip_whitespace();
self.expect_keyword("TO")?;
self.skip_whitespace();
let user_name = self.parse_identifier()?;
Ok(SqlQuery {
query_type: QueryType::GrantRole,
table_name: role_name,
table_alias: Some(user_name),
joins: Vec::new(),
columns: Vec::new(),
select_all: false,
distinct: false,
where_clause: None,
having_clause: None,
group_by: None,
order_by: None,
limit: None,
sample_by: None,
fill_clause: None,
window_functions: Vec::new(),
insert_columns: Vec::new(),
values: Vec::new(),
table_def: Vec::new(),
primary_key: None,
index_column: None,
index_type: None,
index_params: HashMap::new(),
index_online: true,
update_pairs: Vec::new(),
ignore_duplicates: false,
if_not_exists: false,
model_path: String::new(),
model_inputs: Vec::new(),
model_output: (String::new(), String::new()),
table_config: HashMap::new(),
})
}
fn parse_revoke_permission_query(&mut self) -> Result<SqlQuery, QueryParseError> {
let mut permissions = Vec::new();
loop {
self.skip_whitespace();
let permission = self.parse_identifier()?;
permissions.push(permission);
self.skip_whitespace();
if self.match_char(',') {
continue;
} else {
break;
}
}
self.skip_whitespace();
self.expect_keyword("ON")?;
self.skip_whitespace();
let table_name = self.parse_identifier()?;
self.skip_whitespace();
self.expect_keyword("FROM")?;
self.skip_whitespace();
let role_name = self.parse_identifier()?;
Ok(SqlQuery {
query_type: QueryType::RevokePermission,
table_name,
table_alias: Some(role_name),
joins: Vec::new(),
columns: permissions
.into_iter()
.map(|p| Expression::Field {
name: p,
alias: None,
})
.collect(),
select_all: false,
distinct: false,
where_clause: None,
having_clause: None,
group_by: None,
order_by: None,
limit: None,
sample_by: None,
fill_clause: None,
window_functions: Vec::new(),
insert_columns: Vec::new(),
values: Vec::new(),
table_def: Vec::new(),
primary_key: None,
index_column: None,
index_type: None,
index_params: HashMap::new(),
index_online: true,
update_pairs: Vec::new(),
ignore_duplicates: false,
if_not_exists: false,
model_path: String::new(),
model_inputs: Vec::new(),
model_output: (String::new(), String::new()),
table_config: HashMap::new(),
})
}
fn parse_revoke_role_query(&mut self) -> Result<SqlQuery, QueryParseError> {
self.skip_whitespace();
let role_name = self.parse_identifier()?;
self.skip_whitespace();
self.expect_keyword("FROM")?;
self.skip_whitespace();
let user_name = self.parse_identifier()?;
Ok(SqlQuery {
query_type: QueryType::RevokeRole,
table_name: role_name,
table_alias: Some(user_name),
joins: Vec::new(),
columns: Vec::new(),
select_all: false,
distinct: false,
where_clause: None,
having_clause: None,
group_by: None,
order_by: None,
limit: None,
sample_by: None,
fill_clause: None,
window_functions: Vec::new(),
insert_columns: Vec::new(),
values: Vec::new(),
table_def: Vec::new(),
primary_key: None,
index_column: None,
index_type: None,
index_params: HashMap::new(),
index_online: true,
update_pairs: Vec::new(),
ignore_duplicates: false,
if_not_exists: false,
model_path: String::new(),
model_inputs: Vec::new(),
model_output: (String::new(), String::new()),
table_config: HashMap::new(),
})
}
fn parse_drop_role_query(&mut self) -> Result<SqlQuery, QueryParseError> {
self.skip_whitespace();
let role_name = self.parse_identifier()?;
Ok(SqlQuery {
query_type: QueryType::DropRole,
table_name: role_name,
table_alias: None,
joins: Vec::new(),
columns: Vec::new(),
select_all: false,
distinct: false,
where_clause: None,
having_clause: None,
group_by: None,
order_by: None,
limit: None,
sample_by: None,
fill_clause: None,
window_functions: Vec::new(),
insert_columns: Vec::new(),
values: Vec::new(),
table_def: Vec::new(),
primary_key: None,
index_column: None,
index_type: None,
index_params: HashMap::new(),
index_online: true,
update_pairs: Vec::new(),
ignore_duplicates: false,
if_not_exists: false,
model_path: String::new(),
model_inputs: Vec::new(),
model_output: (String::new(), String::new()),
table_config: HashMap::new(),
})
}
fn parse_drop_user_query(&mut self) -> Result<SqlQuery, QueryParseError> {
self.skip_whitespace();
let user_name = self.parse_identifier()?;
Ok(SqlQuery {
query_type: QueryType::DropUser,
table_name: user_name,
table_alias: None,
joins: Vec::new(),
columns: Vec::new(),
select_all: false,
distinct: false,
where_clause: None,
having_clause: None,
group_by: None,
order_by: None,
limit: None,
sample_by: None,
fill_clause: None,
window_functions: Vec::new(),
insert_columns: Vec::new(),
values: Vec::new(),
table_def: Vec::new(),
primary_key: None,
index_column: None,
index_type: None,
index_params: HashMap::new(),
index_online: true,
update_pairs: Vec::new(),
ignore_duplicates: false,
if_not_exists: false,
model_path: String::new(),
model_inputs: Vec::new(),
model_output: (String::new(), String::new()),
table_config: HashMap::new(),
})
}
}
pub fn parse_sql_query(sql: &str) -> Result<SqlQuery, QueryParseError> {
let mut parser = SqlParser::new(sql.to_string());
parser.parse()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_create_table_composite_primary_key() {
let sql = "CREATE TABLE IF NOT EXISTS test_composite_pk (id1 INTEGER, id2 INTEGER, name TEXT, PRIMARY KEY (id1, id2))";
let result = parse_sql_query(sql);
assert!(result.is_ok());
let query = result.unwrap();
match query.query_type {
QueryType::CreateTable => {
assert!(query.primary_key.is_some());
let pk = query.primary_key.unwrap();
assert_eq!(pk, vec!["id1", "id2"]);
}
_ => panic!("Expected CreateTable query"),
}
}
}