#![no_std]
extern crate alloc;
use alloc::vec::Vec;
use lexer::Token;
use parser::Parser;
mod alter_role;
mod alter_table;
mod alter_type;
mod byte_to_char;
mod copy;
mod create;
mod create_constraint_trigger;
mod create_function;
mod create_index;
mod create_option;
mod create_role;
mod create_table;
mod create_trigger;
mod create_view;
mod data_type;
mod delete;
mod drop;
mod expression;
mod flush;
mod function_expression;
mod grant;
mod identifier;
mod insert_replace;
mod issue;
mod keywords;
mod kill;
mod lexer;
mod lock;
mod operator;
mod parser;
mod qualified_name;
mod rename;
mod select;
mod show;
mod span;
mod sstring;
mod statement;
mod truncate;
mod update;
mod values;
mod with_query;
pub use alter_role::{AlterRole, AlterRoleAction, AlterRoleValue};
pub use alter_table::{
AddColumn, AddForeignKey, AddIndex, AddTableConstraint, Algorithm, AlterAlgorithm, AlterColumn,
AlterColumnAction, AlterLock, AlterSpecification, AlterTable, AlterTableOwner, AutoIncrement,
Change, DisableRowLevelSecurity, DisableRule, DisableTrigger, DropColumn, DropForeignKey,
DropPrimaryKey, EnableRowLevelSecurity, EnableRule, EnableTrigger, ForceRowLevelSecurity,
ForeignKeyMatch, ForeignKeyOn, ForeignKeyOnAction, ForeignKeyOnType, IndexCol, IndexColExpr,
IndexOption, IndexType, ModifyColumn, NoForceRowLevelSecurity, OwnerTo, RenameColumn,
RenameConstraint, RenameIndex, RenameTo, ReplicaIdentity, ReplicaIdentityOption,
TableConstraintType, TriggerName, ValidateConstraint,
};
pub use alter_type::{AlterType, AlterTypeAction, AttributeAction};
pub use byte_to_char::ByteToChar;
pub use copy::{
CopyColumnList, CopyFrom, CopyHeaderValue, CopyLocation, CopyOption, CopySource, CopyTo,
};
pub use create::{
CreateDatabase, CreateDatabaseOption, CreateDomain, CreateExtension, CreateSchema,
CreateSequence, CreateServer, CreateTypeEnum, DomainConstraint, SequenceOption,
};
pub use create_constraint_trigger::{AfterEvent, CreateConstraintTrigger, Deferrable, Initially};
pub use create_function::{
CreateFunction, CreateProcedure, FunctionBody, FunctionCharacteristic, FunctionLanguage,
FunctionParallel, FunctionParam, FunctionParamDirection,
};
pub use create_index::{
CreateIndex, CreateIndexOption, IncludeClause, UsingIndexMethod, WithOption,
};
pub use create_option::{CreateAlgorithm, CreateOption};
pub use create_role::{CreateRole, RoleMembership, RoleMembershipType, RoleOption};
pub use create_table::{
CreateDefinition, CreateTable, CreateTableAs, CreateTablePartitionOf, OnCommitAction,
PartitionBoundExpr, PartitionBoundSpec, PartitionBy, PartitionMethod, PartitionOfBound,
TableOption,
};
pub use create_trigger::{
CreateTrigger, ExecuteFunction, TriggerEvent, TriggerForEach, TriggerReference,
TriggerReferenceDirection, TriggerTime,
};
pub use create_view::CreateView;
pub use data_type::{
DataType, DataTypeProperty, Interval, IntervalField, RangeSubtype, Timestamp, Type,
};
pub use delete::{Delete, DeleteFlag};
pub use drop::{
CascadeOrRestrict, DropDatabase, DropDomain, DropEvent, DropExtension, DropFunction,
DropFunctionArg, DropFunctionArgMode, DropIndex, DropOperator, DropOperatorClass,
DropOperatorFamily, DropOperatorItem, DropProcedure, DropSequence, DropServer, DropTable,
DropTrigger, DropType, DropView,
};
pub use expression::{
ArgExpression, ArrayExpression, ArraySubscriptExpression, BetweenExpression, BinaryExpression,
BinaryOperator, BoolExpression, CaseExpression, CastExpression, ConvertExpression,
DefaultExpression, ExistsExpression, Expression, ExtractExpression, FieldAccessExpression,
FloatExpression, GroupConcatExpression, IdentifierExpression, IdentifierPart, InExpression,
IntegerExpression, IntervalExpression, InvalidExpression, Is, IsExpression, ListHackExpression,
MatchAgainstExpression, MatchMode, MemberOfExpression, NullExpression, Quantifier,
QuantifierExpression, RowExpression, SubqueryExpression, TimeUnit, TimestampAddExpression,
TimestampDiffExpression, TrimDirection, TrimExpression, TypeCastExpression, UnaryExpression,
UnaryOperator, UserVariableExpression, Variable, VariableExpression, When,
};
pub use flush::{Flush, FlushOption};
pub use function_expression::{
AggregateFunctionCallExpression, CharFunctionExpression, Function, FunctionCallExpression,
WindowClause, WindowFrame, WindowFrameBound, WindowFrameMode, WindowFunctionCallExpression,
WindowSpec,
};
pub use grant::{
AllRoutineKind, Grant, GrantKind, GrantObject, GrantPrivilege, MembershipOption,
MembershipOptionKind, MembershipOptionValue, PrivilegeItem, RoleSpec, RoutineArgType,
RoutineKind, RoutineName,
};
pub use identifier::Identifier;
pub use insert_replace::{
InsertReplace, InsertReplaceFlag, InsertReplaceOnDuplicateKeyUpdate, InsertReplaceSet,
InsertReplaceSetPair, InsertReplaceType, OnConflict, OnConflictAction, OnConflictTarget,
};
pub use issue::{Fragment, Issue, IssueHandle, Issues, Level};
pub use kill::{Kill, KillType};
pub use lock::{Lock, LockMember, LockType, Unlock};
pub use operator::{
AlterOperator, AlterOperatorAction, AlterOperatorClass, AlterOperatorClassAction,
AlterOperatorFamily, AlterOperatorFamilyAction, CreateOperator, CreateOperatorClass,
CreateOperatorFamily, LeftOperatorType, OperatorClassItem, OperatorClassOperatorOption,
OperatorFamilyDropItem, OperatorFamilyItem, OperatorOption, OperatorRef,
};
pub use qualified_name::QualifiedName;
pub use rename::{RenameTable, TableToTable};
pub use select::{
IndexHint, IndexHintFor, IndexHintType, IndexHintUse, JoinSpecification, JoinType,
JsonTableColumn, JsonTableOnErrorEmpty, LockStrength, LockWait, Locking, OrderFlag, Select,
SelectExpr, SelectFlag, TableFunctionName, TableReference,
};
pub use show::{
ShowCharacterSet, ShowCollation, ShowColumns, ShowCreateDatabase, ShowCreateTable,
ShowCreateView, ShowDatabases, ShowEngines, ShowProcessList, ShowStatus, ShowTables,
ShowVariables,
};
pub use span::{OptSpanned, Span, Spanned};
pub use sstring::SString;
pub use statement::{
AlterSchema, AlterSchemaAction, Analyze, Assign, Begin, Block, Call, CaseStatement,
CloseCursor, CommentOn, CommentOnObjectType, Commit, CompoundOperator, CompoundQuantifier,
CompoundQuery, CompoundQueryBranch, CursorHold, CursorScroll, CursorSensitivity, DeclareCursor,
DeclareCursorMariaDb, DeclareHandler, DeclareVariable, Do, DoBody, End, ExceptionHandler,
Explain, ExplainFormat, ExplainOption, FetchCursor, HandlerAction, HandlerCondition, If,
IfCondition, Invalid, Iterate, Leave, Loop, OpenCursor, Perform, PlpgsqlExecute, Prepare,
Raise, RaiseLevel, RaiseOptionName, RefreshMaterializedView, Repeat, Return, Set, SetVariable,
Signal, SignalConditionInformationName, StartTransaction, Statement, Stdin, WhenStatement,
While,
};
pub use truncate::{IdentityOption, TruncateTable, TruncateTableSpec};
pub use update::{Update, UpdateFlag};
pub use values::{Fetch, FetchDirection, Values};
pub use with_query::{MaterializedHint, WithBlock, WithQuery};
#[derive(Clone, Debug)]
pub enum SQLDialect {
MariaDB,
PostgreSQL,
PostGIS,
Sqlite,
}
impl SQLDialect {
pub fn is_postgresql(&self) -> bool {
matches!(self, SQLDialect::PostgreSQL | SQLDialect::PostGIS)
}
pub fn is_postgis(&self) -> bool {
matches!(self, SQLDialect::PostGIS)
}
pub fn is_maria(&self) -> bool {
matches!(self, SQLDialect::MariaDB)
}
pub fn is_sqlite(&self) -> bool {
matches!(self, SQLDialect::Sqlite)
}
}
#[derive(Clone, Debug)]
pub enum SQLArguments {
None,
Percent,
QuestionMark,
Dollar,
}
#[derive(Clone, Debug)]
pub struct ParseOptions {
dialect: SQLDialect,
arguments: SQLArguments,
warn_unquoted_identifiers: bool,
warn_none_capital_keywords: bool,
list_hack: bool,
function_body: bool,
span_offset: usize,
}
impl Default for ParseOptions {
fn default() -> Self {
Self {
dialect: SQLDialect::MariaDB,
arguments: SQLArguments::None,
warn_none_capital_keywords: false,
warn_unquoted_identifiers: false,
list_hack: false,
function_body: false,
span_offset: 0,
}
}
}
impl ParseOptions {
pub fn new() -> Self {
Default::default()
}
pub fn dialect(self, dialect: SQLDialect) -> Self {
Self { dialect, ..self }
}
pub fn get_dialect(&self) -> SQLDialect {
self.dialect.clone()
}
pub fn arguments(self, arguments: SQLArguments) -> Self {
Self { arguments, ..self }
}
pub fn warn_unquoted_identifiers(self, warn_unquoted_identifiers: bool) -> Self {
Self {
warn_unquoted_identifiers,
..self
}
}
pub fn warn_none_capital_keywords(self, warn_none_capital_keywords: bool) -> Self {
Self {
warn_none_capital_keywords,
..self
}
}
pub fn list_hack(self, list_hack: bool) -> Self {
Self { list_hack, ..self }
}
pub fn function_body(self, function_body: bool) -> Self {
Self {
function_body,
..self
}
}
pub fn get_function_body(&self) -> bool {
self.function_body
}
pub fn span_offset(self, span_offset: usize) -> Self {
Self {
span_offset,
..self
}
}
pub fn get_span_offset(&self) -> usize {
self.span_offset
}
}
#[macro_export]
macro_rules! issue_ice {
( $issues: expr, $spanned:expr ) => {{
$issues.err(
alloc::format!("Internal compiler error in {}:{}", file!(), line!()),
$spanned,
);
}};
}
#[macro_export]
macro_rules! issue_todo {
( $issues: expr, $spanned:expr ) => {{
$issues.err(
alloc::format!("Not yet implemented {}:{}", file!(), line!()),
$spanned,
);
}};
}
pub fn parse_statements<'a>(
src: &'a str,
issues: &mut Issues<'a>,
options: &ParseOptions,
) -> Vec<Statement<'a>> {
let mut parser = Parser::new(src, issues, options);
statement::parse_statements(&mut parser)
}
pub fn parse_statement<'a>(
src: &'a str,
issues: &mut Issues<'a>,
options: &ParseOptions,
) -> Option<Statement<'a>> {
let mut parser = Parser::new(src, issues, options);
match statement::parse_statement(&mut parser) {
Ok(Some(v)) => {
if parser.token == Token::Delimiter {
parser.consume();
}
if parser.token != Token::Eof {
parser.expected_error("Unexpected token after statement")
}
Some(v)
}
Ok(None) => {
parser.expected_error("Statement");
None
}
Err(_) => None,
}
}
#[test]
pub fn test_parse_alter_sql() {
let sql = "ALTER TABLE `test` ADD COLUMN `test1` VARCHAR (128) NULL DEFAULT NULL";
let options = ParseOptions::new()
.dialect(SQLDialect::MariaDB)
.arguments(SQLArguments::QuestionMark)
.warn_unquoted_identifiers(false);
let mut issues = Issues::new(sql);
parse_statement(sql, &mut issues, &options);
assert!(issues.is_ok(), "{}", issues);
}
#[test]
pub fn test_parse_delete_sql_with_schema() {
let sql = "DROP TABLE IF EXISTS `test_schema`.`test`";
let options = ParseOptions::new()
.dialect(SQLDialect::MariaDB)
.arguments(SQLArguments::QuestionMark)
.warn_unquoted_identifiers(false);
let mut issues = Issues::new(sql);
parse_statement(sql, &mut issues, &options);
assert!(issues.is_ok(), "{}", issues);
}
#[test]
pub fn parse_create_index_sql_with_schema() {
let sql = "CREATE INDEX `idx_test` ON test_schema.test(`col_test`)";
let options = ParseOptions::new()
.dialect(SQLDialect::MariaDB)
.arguments(SQLArguments::QuestionMark)
.warn_unquoted_identifiers(false);
let mut issues = Issues::new(sql);
parse_statement(sql, &mut issues, &options);
assert!(issues.is_ok(), "{}", issues);
}
#[test]
pub fn parse_create_index_sql_with_opclass() {
let sql = "CREATE INDEX idx_test ON test(path text_pattern_ops)";
let options = ParseOptions::new()
.dialect(SQLDialect::PostgreSQL)
.arguments(SQLArguments::Dollar)
.warn_unquoted_identifiers(false);
let mut issues = Issues::new(sql);
parse_statement(sql, &mut issues, &options);
assert!(issues.is_ok(), "{}", issues);
}
#[test]
pub fn parse_drop_index_sql_with_schema() {
let sql = "DROP INDEX `idx_test` ON test_schema.test";
let options = ParseOptions::new()
.dialect(SQLDialect::MariaDB)
.arguments(SQLArguments::QuestionMark)
.warn_unquoted_identifiers(false);
let mut issues = Issues::new(sql);
let _result = parse_statement(sql, &mut issues, &options);
assert!(issues.is_ok(), "{}", issues);
}
#[test]
pub fn parse_create_view_sql_with_schema() {
let sql =
"CREATE OR REPLACE VIEW `test_schema`.`view_test` AS SELECT * FROM `test_schema`.`test`";
let options = ParseOptions::new()
.dialect(SQLDialect::MariaDB)
.arguments(SQLArguments::QuestionMark)
.warn_unquoted_identifiers(false);
let mut issues = Issues::new(sql);
let _result = parse_statement(sql, &mut issues, &options);
assert!(issues.is_ok(), "{}", issues);
}
#[test]
pub fn parse_drop_view_sql_with_schema() {
let sql = "DROP VIEW `test_schema`.`view_test`";
let options = ParseOptions::new()
.dialect(SQLDialect::MariaDB)
.arguments(SQLArguments::QuestionMark)
.warn_unquoted_identifiers(false);
let mut issues = Issues::new(sql);
let _result = parse_statement(sql, &mut issues, &options);
assert!(issues.is_ok(), "{}", issues);
}
#[test]
pub fn parse_truncate_table_sql_with_schema() {
let sql = "TRUNCATE TABLE `test_schema`.`table_test`";
let options = ParseOptions::new()
.dialect(SQLDialect::MariaDB)
.arguments(SQLArguments::QuestionMark)
.warn_unquoted_identifiers(false);
let mut issues = Issues::new(sql);
let _result = parse_statement(sql, &mut issues, &options);
assert!(issues.is_ok(), "{}", issues);
}
#[test]
pub fn parse_rename_table_sql_with_schema() {
let sql = "RENAME TABLE `test_schema`.`table_test` To `test_schema`.`table_new_test`";
let options = ParseOptions::new()
.dialect(SQLDialect::MariaDB)
.arguments(SQLArguments::QuestionMark)
.warn_unquoted_identifiers(false);
let mut issues = Issues::new(sql);
let _result = parse_statement(sql, &mut issues, &options);
assert!(issues.is_ok(), "{}", issues);
}
#[test]
pub fn parse_with_statement() {
let sql = "
WITH monkeys AS (DELETE FROM thing RETURNING id),
baz AS (SELECT id FROM cats WHERE comp IN (monkeys))
DELETE FROM dogs WHERE cat IN (cats)";
let options = ParseOptions::new()
.dialect(SQLDialect::PostgreSQL)
.arguments(SQLArguments::QuestionMark)
.warn_unquoted_identifiers(false);
let mut issues = Issues::new(sql);
let _result = parse_statement(sql, &mut issues, &options);
assert!(issues.is_ok(), "{}", issues);
}
#[test]
pub fn parse_use_index() {
let sql = "SELECT `a` FROM `b` FORCE INDEX FOR GROUP BY (`b`, `c`)";
let options = ParseOptions::new()
.dialect(SQLDialect::MariaDB)
.arguments(SQLArguments::QuestionMark)
.warn_unquoted_identifiers(false);
let mut issues = Issues::new(sql);
let _result = parse_statement(sql, &mut issues, &options);
assert!(issues.is_ok(), "{}", issues);
}