1#![no_std]
42extern crate alloc;
43
44use alloc::vec::Vec;
45use lexer::Token;
46use parser::Parser;
47mod alter_role;
48mod alter_table;
49mod alter_type;
50mod copy;
51mod create;
52mod create_constraint_trigger;
53mod create_function;
54mod create_index;
55mod create_option;
56mod create_role;
57mod create_table;
58mod create_trigger;
59mod create_view;
60mod data_type;
61mod delete;
62mod drop;
63mod expression;
64mod flush;
65mod function_expression;
66mod identifier;
67mod insert_replace;
68mod issue;
69mod keywords;
70mod kill;
71mod lexer;
72mod lock;
73mod operator;
74mod parser;
75mod qualified_name;
76mod rename;
77mod select;
78mod show;
79mod span;
80mod sstring;
81mod statement;
82mod truncate;
83mod update;
84mod values;
85mod with_query;
86
87pub use alter_role::{AlterRole, AlterRoleAction, AlterRoleValue};
88pub use alter_table::{
89 AddColumn, AddForeignKey, AddIndex, AddTableConstraint, Algorithm, AlterAlgorithm, AlterColumn,
90 AlterColumnAction, AlterLock, AlterSpecification, AlterTable, AlterTableOwner, AutoIncrement,
91 Change, DisableRowLevelSecurity, DisableRule, DisableTrigger, DropColumn, DropForeignKey,
92 DropPrimaryKey, EnableRowLevelSecurity, EnableRule, EnableTrigger, ForceRowLevelSecurity,
93 ForeignKeyMatch, ForeignKeyOn, ForeignKeyOnAction, ForeignKeyOnType, IndexCol, IndexColExpr,
94 IndexOption, IndexType, ModifyColumn, NoForceRowLevelSecurity, OwnerTo, RenameColumn,
95 RenameConstraint, RenameIndex, RenameTo, ReplicaIdentity, ReplicaIdentityOption,
96 TableConstraintType, TriggerName, ValidateConstraint,
97};
98pub use alter_type::{AlterType, AlterTypeAction, AttributeAction};
99pub use copy::{
100 CopyColumnList, CopyFrom, CopyHeaderValue, CopyLocation, CopyOption, CopySource, CopyTo,
101};
102pub use create::{
103 CreateDatabase, CreateDatabaseOption, CreateDomain, CreateExtension, CreateSchema,
104 CreateSequence, CreateServer, CreateTypeEnum, DomainConstraint, SequenceOption,
105};
106pub use create_constraint_trigger::{AfterEvent, CreateConstraintTrigger, Deferrable, Initially};
107pub use create_function::{
108 CreateFunction, CreateProcedure, FunctionBody, FunctionCharacteristic, FunctionLanguage,
109 FunctionParallel, FunctionParam, FunctionParamDirection,
110};
111pub use create_index::{
112 CreateIndex, CreateIndexOption, IncludeClause, UsingIndexMethod, WithOption,
113};
114pub use create_option::{CreateAlgorithm, CreateOption};
115pub use create_role::{CreateRole, RoleMembership, RoleMembershipType, RoleOption};
116pub use create_table::{
117 CreateDefinition, CreateTable, CreateTableAs, CreateTablePartitionOf, OnCommitAction,
118 PartitionBoundExpr, PartitionBoundSpec, PartitionBy, PartitionMethod, PartitionOfBound,
119 TableOption,
120};
121pub use create_trigger::{
122 CreateTrigger, TriggerEvent, TriggerReference, TriggerReferenceDirection, TriggerTime,
123};
124pub use create_view::CreateView;
125pub use data_type::{
126 DataType, DataTypeProperty, Interval, IntervalField, RangeSubtype, Timestamp, Type,
127};
128pub use delete::{Delete, DeleteFlag};
129pub use drop::{
130 CascadeOrRestrict, DropDatabase, DropDomain, DropEvent, DropExtension, DropFunction,
131 DropFunctionArg, DropFunctionArgMode, DropIndex, DropOperator, DropOperatorClass,
132 DropOperatorFamily, DropOperatorItem, DropProcedure, DropSequence, DropServer, DropTable,
133 DropTrigger, DropView,
134};
135pub use expression::{
136 ArgExpression, ArrayExpression, ArraySubscriptExpression, BetweenExpression, BinaryExpression,
137 BinaryOperator, BoolExpression, CaseExpression, CastExpression, ConvertExpression,
138 DefaultExpression, ExistsExpression, Expression, ExtractExpression, FieldAccessExpression,
139 FloatExpression, GroupConcatExpression, IdentifierExpression, IdentifierPart, InExpression,
140 IntegerExpression, IntervalExpression, InvalidExpression, Is, IsExpression, ListHackExpression,
141 MatchAgainstExpression, MatchMode, MemberOfExpression, NullExpression, Quantifier,
142 QuantifierExpression, RowExpression, SubqueryExpression, TimeUnit, TimestampAddExpression,
143 TimestampDiffExpression, TrimDirection, TrimExpression, TypeCastExpression, UnaryExpression,
144 UnaryOperator, UserVariableExpression, Variable, VariableExpression, When,
145};
146pub use flush::{Flush, FlushOption};
147pub use function_expression::{
148 AggregateFunctionCallExpression, CharFunctionExpression, Function, FunctionCallExpression,
149 WindowClause, WindowFrame, WindowFrameBound, WindowFrameMode, WindowFunctionCallExpression,
150 WindowSpec,
151};
152pub use identifier::Identifier;
153pub use insert_replace::{
154 InsertReplace, InsertReplaceFlag, InsertReplaceOnDuplicateKeyUpdate, InsertReplaceSet,
155 InsertReplaceSetPair, InsertReplaceType, OnConflict, OnConflictAction, OnConflictTarget,
156};
157pub use issue::{Fragment, Issue, IssueHandle, Issues, Level};
158pub use kill::{Kill, KillType};
159pub use lock::{Lock, LockMember, LockType, Unlock};
160pub use operator::{
161 AlterOperator, AlterOperatorAction, AlterOperatorClass, AlterOperatorClassAction,
162 AlterOperatorFamily, AlterOperatorFamilyAction, CreateOperator, CreateOperatorClass,
163 CreateOperatorFamily, LeftOperatorType, OperatorClassItem, OperatorClassOperatorOption,
164 OperatorFamilyDropItem, OperatorFamilyItem, OperatorOption, OperatorRef,
165};
166pub use qualified_name::QualifiedName;
167pub use rename::{RenameTable, TableToTable};
168pub use select::{
169 IndexHint, IndexHintFor, IndexHintType, IndexHintUse, JoinSpecification, JoinType,
170 JsonTableColumn, JsonTableOnErrorEmpty, LockStrength, LockWait, Locking, OrderFlag, Select,
171 SelectExpr, SelectFlag, TableFunctionName, TableReference,
172};
173pub use show::{
174 ShowCharacterSet, ShowCollation, ShowColumns, ShowCreateDatabase, ShowCreateTable,
175 ShowCreateView, ShowDatabases, ShowEngines, ShowProcessList, ShowStatus, ShowTables,
176 ShowVariables,
177};
178pub use span::{OptSpanned, Span, Spanned};
179pub use sstring::SString;
180pub use statement::{
181 AlterSchema, AlterSchemaAction, Begin, Block, Call, CaseStatement, CloseCursor, Commit,
182 CompoundOperator, CompoundQuantifier, CompoundQuery, CompoundQueryBranch, CursorHold,
183 CursorScroll, CursorSensitivity, DeclareCursor, DeclareCursorMariaDb, DeclareHandler,
184 DeclareVariable, Do, DoBody, End, Explain, ExplainFormat, ExplainOption, FetchCursor,
185 HandlerAction, HandlerCondition, If, IfCondition, Invalid, Iterate, Leave, Loop, OpenCursor,
186 Prepare, RefreshMaterializedView, Repeat, Return, Set, Signal, SignalConditionInformationName,
187 StartTransaction, Statement, Stdin, WhenStatement, While,
188};
189pub use truncate::{IdentityOption, TruncateTable, TruncateTableSpec};
190pub use update::{Update, UpdateFlag};
191pub use values::{Fetch, FetchDirection, Values};
192pub use with_query::{MaterializedHint, WithBlock, WithQuery};
193
194#[derive(Clone, Debug)]
196pub enum SQLDialect {
197 MariaDB,
199 PostgreSQL,
200 Sqlite,
201}
202
203impl SQLDialect {
204 pub fn is_postgresql(&self) -> bool {
205 matches!(self, SQLDialect::PostgreSQL)
206 }
207
208 pub fn is_maria(&self) -> bool {
209 matches!(self, SQLDialect::MariaDB)
210 }
211
212 pub fn is_sqlite(&self) -> bool {
213 matches!(self, SQLDialect::Sqlite)
214 }
215}
216
217#[derive(Clone, Debug)]
219pub enum SQLArguments {
220 None,
222 Percent,
224 QuestionMark,
226 Dollar,
228}
229
230#[derive(Clone, Debug)]
232pub struct ParseOptions {
233 dialect: SQLDialect,
234 arguments: SQLArguments,
235 warn_unquoted_identifiers: bool,
236 warn_none_capital_keywords: bool,
237 list_hack: bool,
238}
239
240impl Default for ParseOptions {
241 fn default() -> Self {
242 Self {
243 dialect: SQLDialect::MariaDB,
244 arguments: SQLArguments::None,
245 warn_none_capital_keywords: false,
246 warn_unquoted_identifiers: false,
247 list_hack: false,
248 }
249 }
250}
251
252impl ParseOptions {
253 pub fn new() -> Self {
254 Default::default()
255 }
256
257 pub fn dialect(self, dialect: SQLDialect) -> Self {
259 Self { dialect, ..self }
260 }
261
262 pub fn get_dialect(&self) -> SQLDialect {
263 self.dialect.clone()
264 }
265
266 pub fn arguments(self, arguments: SQLArguments) -> Self {
268 Self { arguments, ..self }
269 }
270
271 pub fn warn_unquoted_identifiers(self, warn_unquoted_identifiers: bool) -> Self {
273 Self {
274 warn_unquoted_identifiers,
275 ..self
276 }
277 }
278
279 pub fn warn_none_capital_keywords(self, warn_none_capital_keywords: bool) -> Self {
281 Self {
282 warn_none_capital_keywords,
283 ..self
284 }
285 }
286
287 pub fn list_hack(self, list_hack: bool) -> Self {
289 Self { list_hack, ..self }
290 }
291}
292
293#[macro_export]
295macro_rules! issue_ice {
296 ( $issues: expr, $spanned:expr ) => {{
297 $issues.err(
298 alloc::format!("Internal compiler error in {}:{}", file!(), line!()),
299 $spanned,
300 );
301 }};
302}
303
304#[macro_export]
306macro_rules! issue_todo {
307 ( $issues: expr, $spanned:expr ) => {{
308 $issues.err(
309 alloc::format!("Not yet implemented {}:{}", file!(), line!()),
310 $spanned,
311 );
312 }};
313}
314
315pub fn parse_statements<'a>(
320 src: &'a str,
321 issues: &mut Issues<'a>,
322 options: &ParseOptions,
323) -> Vec<Statement<'a>> {
324 let mut parser = Parser::new(src, issues, options);
325 statement::parse_statements(&mut parser)
326}
327
328pub fn parse_statement<'a>(
333 src: &'a str,
334 issues: &mut Issues<'a>,
335 options: &ParseOptions,
336) -> Option<Statement<'a>> {
337 let mut parser = Parser::new(src, issues, options);
338 match statement::parse_statement(&mut parser) {
339 Ok(Some(v)) => {
340 if parser.token != Token::Eof {
341 parser.expected_error("Unexpected token after statement")
342 }
343 Some(v)
344 }
345 Ok(None) => {
346 parser.expected_error("Statement");
347 None
348 }
349 Err(_) => None,
350 }
351}
352
353#[test]
354pub fn test_parse_alter_sql() {
355 let sql = "ALTER TABLE `test` ADD COLUMN `test1` VARCHAR (128) NULL DEFAULT NULL";
356 let options = ParseOptions::new()
357 .dialect(SQLDialect::MariaDB)
358 .arguments(SQLArguments::QuestionMark)
359 .warn_unquoted_identifiers(false);
360
361 let mut issues = Issues::new(sql);
362 parse_statement(sql, &mut issues, &options);
363 assert!(issues.is_ok(), "{}", issues);
364}
365
366#[test]
367pub fn test_parse_delete_sql_with_schema() {
368 let sql = "DROP TABLE IF EXISTS `test_schema`.`test`";
369 let options = ParseOptions::new()
370 .dialect(SQLDialect::MariaDB)
371 .arguments(SQLArguments::QuestionMark)
372 .warn_unquoted_identifiers(false);
373
374 let mut issues = Issues::new(sql);
375 parse_statement(sql, &mut issues, &options);
376 assert!(issues.is_ok(), "{}", issues);
377}
378
379#[test]
380pub fn parse_create_index_sql_with_schema() {
381 let sql = "CREATE INDEX `idx_test` ON test_schema.test(`col_test`)";
382 let options = ParseOptions::new()
383 .dialect(SQLDialect::MariaDB)
384 .arguments(SQLArguments::QuestionMark)
385 .warn_unquoted_identifiers(false);
386
387 let mut issues = Issues::new(sql);
388 parse_statement(sql, &mut issues, &options);
389 assert!(issues.is_ok(), "{}", issues);
390}
391
392#[test]
393pub fn parse_create_index_sql_with_opclass() {
394 let sql = "CREATE INDEX idx_test ON test(path text_pattern_ops)";
395 let options = ParseOptions::new()
396 .dialect(SQLDialect::PostgreSQL)
397 .arguments(SQLArguments::Dollar)
398 .warn_unquoted_identifiers(false);
399
400 let mut issues = Issues::new(sql);
401 parse_statement(sql, &mut issues, &options);
402 assert!(issues.is_ok(), "{}", issues);
403}
404
405#[test]
406pub fn parse_drop_index_sql_with_schema() {
407 let sql = "DROP INDEX `idx_test` ON test_schema.test";
408 let options = ParseOptions::new()
409 .dialect(SQLDialect::MariaDB)
410 .arguments(SQLArguments::QuestionMark)
411 .warn_unquoted_identifiers(false);
412
413 let mut issues = Issues::new(sql);
414 let _result = parse_statement(sql, &mut issues, &options);
415 assert!(issues.is_ok(), "{}", issues);
417}
418
419#[test]
420pub fn parse_create_view_sql_with_schema() {
421 let sql =
422 "CREATE OR REPLACE VIEW `test_schema`.`view_test` AS SELECT * FROM `test_schema`.`test`";
423 let options = ParseOptions::new()
424 .dialect(SQLDialect::MariaDB)
425 .arguments(SQLArguments::QuestionMark)
426 .warn_unquoted_identifiers(false);
427
428 let mut issues = Issues::new(sql);
429 let _result = parse_statement(sql, &mut issues, &options);
430 assert!(issues.is_ok(), "{}", issues);
432}
433
434#[test]
435pub fn parse_drop_view_sql_with_schema() {
436 let sql = "DROP VIEW `test_schema`.`view_test`";
437 let options = ParseOptions::new()
438 .dialect(SQLDialect::MariaDB)
439 .arguments(SQLArguments::QuestionMark)
440 .warn_unquoted_identifiers(false);
441
442 let mut issues = Issues::new(sql);
443 let _result = parse_statement(sql, &mut issues, &options);
444 assert!(issues.is_ok(), "{}", issues);
446}
447
448#[test]
449pub fn parse_truncate_table_sql_with_schema() {
450 let sql = "TRUNCATE TABLE `test_schema`.`table_test`";
451 let options = ParseOptions::new()
452 .dialect(SQLDialect::MariaDB)
453 .arguments(SQLArguments::QuestionMark)
454 .warn_unquoted_identifiers(false);
455
456 let mut issues = Issues::new(sql);
457 let _result = parse_statement(sql, &mut issues, &options);
458 assert!(issues.is_ok(), "{}", issues);
460}
461
462#[test]
463pub fn parse_rename_table_sql_with_schema() {
464 let sql = "RENAME TABLE `test_schema`.`table_test` To `test_schema`.`table_new_test`";
465 let options = ParseOptions::new()
466 .dialect(SQLDialect::MariaDB)
467 .arguments(SQLArguments::QuestionMark)
468 .warn_unquoted_identifiers(false);
469
470 let mut issues = Issues::new(sql);
471 let _result = parse_statement(sql, &mut issues, &options);
472 assert!(issues.is_ok(), "{}", issues);
474}
475
476#[test]
477pub fn parse_with_statement() {
478 let sql = "
479 WITH monkeys AS (DELETE FROM thing RETURNING id),
480 baz AS (SELECT id FROM cats WHERE comp IN (monkeys))
481 DELETE FROM dogs WHERE cat IN (cats)";
482 let options = ParseOptions::new()
483 .dialect(SQLDialect::PostgreSQL)
484 .arguments(SQLArguments::QuestionMark)
485 .warn_unquoted_identifiers(false);
486
487 let mut issues = Issues::new(sql);
488 let _result = parse_statement(sql, &mut issues, &options);
489 assert!(issues.is_ok(), "{}", issues);
491}
492
493#[test]
494pub fn parse_use_index() {
495 let sql = "SELECT `a` FROM `b` FORCE INDEX FOR GROUP BY (`b`, `c`)";
496 let options = ParseOptions::new()
497 .dialect(SQLDialect::MariaDB)
498 .arguments(SQLArguments::QuestionMark)
499 .warn_unquoted_identifiers(false);
500
501 let mut issues = Issues::new(sql);
502 let _result = parse_statement(sql, &mut issues, &options);
503 assert!(issues.is_ok(), "{}", issues);
504}