Skip to content

Commit

Permalink
feat: support detailed error information
Browse files Browse the repository at this point in the history
  • Loading branch information
EmirVildanov committed Jan 9, 2024
1 parent 199f594 commit 04728e8
Show file tree
Hide file tree
Showing 5 changed files with 801 additions and 12 deletions.
249 changes: 249 additions & 0 deletions grammars/src/grammars/sql.pest
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
Command = _{ SOI ~ (ExplainQuery | Query | DDL | ACL) ~ EOF }

ACL = _{ DropRole | DropUser | CreateRole | CreateUser | AlterUser | GrantPrivilege | RevokePrivilege }
/// Represents both RoleName and UserName.
RoleName = @{ Name }
CreateUser = {
^"create" ~ ^"user" ~ RoleName ~ (^"with")? ~ ^"password" ~ PasswordString ~
AuthMethod? ~ Option?
}
PasswordString = _{ "'" ~ Password ~ "'" }
Password = @{ String }
AlterUser = {
^"alter" ~ ^"user" ~ RoleName ~ (^"with")? ~ AlterOption ~ Option?
}
AlterOption = _{ AlterLogin | AlterNoLogin | AlterPassword }
AlterLogin = { ^"login" }
AlterNoLogin = { ^"nologin" }
AlterPassword = { ^"password" ~ PasswordString ~ AuthMethod? }
AuthMethod = { ^"using" ~ (ChapSha1 | Md5 | Ldap) }
ChapSha1 = { ^"chap-sha1" }
Md5 = { ^"md5" }
Ldap = { ^"ldap" }
DropUser = { ^"drop" ~ ^"user" ~ RoleName ~ Option? }
CreateRole = { ^"create" ~ ^"role" ~ RoleName ~ Option? }
DropRole = { ^"drop" ~ ^"role" ~ RoleName ~ Option? }
GrantPrivilege = { ^"grant" ~ PrivBlock ~ ^"to" ~ RoleName ~ Option? }
RevokePrivilege = { ^"revoke" ~ PrivBlock ~ ^"from" ~ RoleName ~ Option? }
PrivBlock = _{ PrivBlockPrivilege | PrivBlockRolePass }
PrivBlockPrivilege = {Privilege ~ (PrivBlockUser | PrivBlockSpecificUser | PrivBlockRole
| PrivBlockSpecificRole | PrivBlockTable | PrivBlockSpecificTable)}
PrivBlockUser = { ^"user" }
PrivBlockSpecificUser = { ^"on" ~ ^"user" ~ RoleName }
PrivBlockRole = { ^"role" }
PrivBlockSpecificRole = { ^"on" ~ ^"role" ~ RoleName }
PrivBlockTable = { ^"table" }
PrivBlockSpecificTable = { ^"on" ~ ^"table" ~ Table }
PrivBlockRolePass = { RoleName }
Privilege = _{ PrivilegeRead | PrivilegeWrite | PrivilegeExecute |
PrivilegeCreate | PrivilegeAlter | PrivilegeDrop |
PrivilegeSession | PrivilegeUsage }
PrivilegeAlter = { ^"alter" }
PrivilegeCreate = { ^"create" }
PrivilegeDrop = { ^"drop" }
PrivilegeExecute = { ^"execute" }
PrivilegeRead = { ^"read" }
PrivilegeSession = { ^"session" }
PrivilegeUsage = { ^"usage" }
PrivilegeWrite = { ^"write" }

DDL = _{ CreateTable | DropTable }
CreateTable = {
^"create" ~ ^"table" ~ NewTable ~
ColumnsSection ~
Engine? ~ Distribution ~ Option?
}
NewTable = @{ Table }
ColumnsSection = { "(" ~ Columns ~ "," ~ PrimaryKey ~ ")" }
Columns = { ColumnDef ~ ("," ~ ColumnDef)* }
ColumnDef = { ColumnDefName ~ ColumnDefType ~ ColumnDefIsNull? }
ColumnDefName = @{ ColumnName }
ColumnDefType = { TypeBool | TypeDecimal | TypeDouble
| TypeInt | TypeNumber | TypeScalar | TypeString
| TypeText | TypeUnsigned | TypeVarchar }
ColumnDefIsNull = { NotFlag? ~ ^"null" }
PrimaryKey = {
^"primary" ~ ^"key" ~
"(" ~ PrimaryKeyColumn ~ ("," ~ PrimaryKeyColumn)* ~ ")"
}
PrimaryKeyColumn = @{ ColumnName }
Engine = { ^"using" ~ (Memtx | Vinyl) }
Memtx = { ^"memtx" }
Vinyl = { ^"vinyl" }
Distribution = { ^"distributed" ~ (Global | Sharding) }
Global = { ^"globally" }
Sharding = { ^"by" ~ "(" ~ ShardingColumn ~ ("," ~ ShardingColumn)* ~ ")"}
ShardingColumn = @{ ColumnName }

DropTable = { ^"drop" ~ ^"table" ~ DeletedTable ~ Option? }
DeletedTable = @{ Table }

ExplainQuery = _{ Explain }
Explain = { ^"explain" ~ Query }

Query = { (Except | UnionAll | Select | Values | Insert | Update | Delete) ~ Option? }
Select = {
^"select" ~ Projection ~ ^"from" ~ Scan ~
Join? ~ WhereClause? ~
GroupByBlock? ~
HavingBlock?
}
Projection = { Distinct? ~ (Asterisk | Column) ~ ("," ~ (Asterisk | Column))* }
Column = { (Value | Expr) ~ (^"as" ~ AliasName)? }
// May be inside of Value
Reference = { Name ~ ("." ~ Name)? }
ColumnName = @{ Name }
ScanName = @{ Name }
AliasName = @{ Name }
Name = @{ NameString | ("\"" ~ NameString ~ "\"") }
Asterisk = { "*" }
WhereClause = _{ ^"where" ~ Selection }
Selection = { Expr }
Scan = { (SubQuery | ScanTable) ~ (^"as" ~ ScanName)? }
ScanTable = { Table }
Table = @{ Name }
Join = { JoinKind? ~ ^"join" ~ Scan ~ ^"on" ~ Condition }
JoinKind = _{ ( InnerJoinKind | LeftJoinKind ) }
InnerJoinKind = { ^"inner" }
LeftJoinKind = { ^"left" ~ (^"outer")? }
Condition = { Expr }
GroupByBlock = { ^"group" ~ ^"by" ~ GroupBy }
HavingBlock = { ^"having" ~ Having }
GroupBy = { GroupingElement ~ ("," ~ GroupingElement)* }
Having = { Expr }
UnionAll = { Select ~ ^"union" ~ ^"all" ~ Select }
Except = { Select ~ ((^"except" ~ ^"distinct") | ^"except") ~ Select }
SubQuery = { "(" ~ (Except | UnionAll | Select | Values) ~ ")" }
Insert = { ^"insert" ~ ^"into" ~ Table ~ ("(" ~ TargetColumns ~ ")")? ~
(Values | Select) ~ OnConflict? }
TargetColumns = { ColumnName ~ ("," ~ ColumnName)* }
OnConflict = _{ ^"on conflict" ~ ^"do" ~ (DoNothing | DoReplace | DoFail) }
DoReplace = { ^"replace" }
DoNothing = { ^"nothing" }
DoFail = { ^"fail" }
Update = { ^"update" ~ ScanTable ~ ^"set" ~ UpdateList ~ (UpdateFrom | WhereClause)? }
UpdateList = { UpdateItem ~ ("," ~ UpdateItem)* }
UpdateItem = { ColumnName ~ "=" ~ ExprNotSubQuery }
/// Condition is used intentionally here for implementation
/// of Update transform.
UpdateFrom = _{ ^"from" ~ Scan ~ (^"where" ~ Condition)? }
Values = { ^"values" ~ ValuesRow ~ ("," ~ ValuesRow)* }
ValuesRow = { Row }
Option = _{ ^"option" ~ "(" ~ OptionParam ~ ("," ~ OptionParam)* ~ ")" }
OptionParam = _{ Timeout | SqlVdbeMaxSteps | VTableMaxRows }
Timeout = { ^"timeout" ~ "=" ~ Duration }
Duration = @{ Unsigned ~ ("." ~ Unsigned)? }
SqlVdbeMaxSteps = { ^"sql_vdbe_max_steps" ~ "=" ~ (Unsigned | Parameter) }
VTableMaxRows = { ^"vtable_max_rows" ~ "=" ~ (Unsigned | Parameter) }
Delete = { ^"delete" ~ ^"from" ~ ScanTable ~ (^"where" ~ DeleteFilter)? }
DeleteFilter = { Expr }

Expr = _{ BoolOp | Primary | Parentheses }
BoolOp = _{ Or | And | Unary | Between | Cmp }
ExprNotSubQuery = _{ !SubQuery ~ Expr }
Parentheses = _{ "(" ~ Expr ~ ")" }
Primary = _{ SubQuery | ArithmeticExpr | Concat | Cast | Row | Function | Value }
Concat = { ConcatLeft ~ ^"||" ~ ConcatRight }
ConcatLeft = _{ Cast | Function | Reference | SingleQuotedString }
ConcatRight = _{ Concat | ConcatLeft }
ArithmeticExpr = _{ Addition | Multiplication | ArithParentheses }
ArithParentheses = { "(" ~ ArithmeticExpr ~ ")" }
ArithELeft = _{ Cast | Row | Function | ArithParentheses | Value }
Multiplication = { ArithELeft ~ (Multiply | Divide) ~ MultiplicationRight }
MultiplicationRight = _{ Multiplication | ArithELeft }
Addition = { AdditionLeft ~ (Add | Subtract) ~ AdditionRight }
AdditionLeft = _{ MultiplicationRight }
AdditionRight = _{ Addition | MultiplicationRight }
Multiply = { "*" }
Divide = { "/" }
Add = { "+" }
Subtract = { "-" }
Unary = _{ Not | IsNull | Exists }
Not = { NotFlag ~ (NotInnerWithParenthesis | NotInnerWithoutParentheses) }
NotInnerWithoutParentheses = _{ Unary | Cast | Between | Cmp | Function | Row | Parameter | True | False | Null | Reference }
NotInnerWithParenthesis = _{ "(" ~ (Or | And | NotInnerWithoutParentheses) ~ ")" }
Exists = { NotFlag? ~ ^"exists" ~ SubQuery }
IsNull = { Primary ~ ^"is" ~ NotFlag? ~ ^"null" }
Cmp = { Primary ~ CmpOp ~ Primary }
CmpOp = _{ Eq | In | NotEq | GtEq | Gt | LtEq | Lt }
Eq = { "=" }
In = { NotFlag? ~ ^"in" }
Gt = { ">" }
GtEq = { ">=" }
Lt = { "<" }
LtEq = { "<=" }
NotEq = { "<>" | "!=" }
Between = { BetweenLeft ~ NotFlag? ~ ^"between" ~ BetweenCenter ~ ^"and" ~ BetweenRight }
BetweenLeft = _{ Primary }
BetweenCenter = _{ Primary }
BetweenRight = _{ Primary }
And = { AndLeft ~ ^"and" ~ AndRight }
/// Expr without And and Or.
AndLeft = _{ Unary | Between | Cmp | Primary | Parentheses }
AndRight = _{ And | AndLeft }
Or = { OrLeft ~ ^"or" ~ OrRight }
OrLeft = _{ AndRight }
OrRight = _{ Or | OrLeft }

Function = { FunctionName ~ "(" ~ (CountAsterisk | (Distinct? ~ FunctionArgs)) ~ ")" }
FunctionName = @{ Name }
FunctionArgs = _{ (FunctionExpr ~ ("," ~ FunctionExpr)*)? }
FunctionExpr = _{ Parentheses | Primary }
CountAsterisk = { "*" }

Distinct = { ^"distinct" }
NotFlag = { ^"not" }

Cast = { ^"cast" ~ "(" ~ CastExpr ~ ^"as" ~ Type ~ ")" }
CastExpr = _{ Parentheses | Primary }
Type = _{ TypeAny | TypeBool | TypeDecimal | TypeDouble
| TypeInt | TypeNumber | TypeScalar | TypeString
| TypeText | TypeUnsigned | TypeVarchar }
TypeAny = { ^"any" }
TypeBool = { (^"boolean" | ^"bool") }
TypeDecimal = { ^"decimal" }
TypeDouble = { ^"double" }
TypeInt = { (^"integer" | ^"int") }
TypeNumber = { ^"number" }
TypeScalar = { ^"scalar" }
TypeString = { ^"string" }
TypeText = { ^"text" }
TypeUnsigned = { ^"unsigned" }
TypeVarchar = { ^"varchar" ~ "(" ~ Length ~ ")" }
Length = @{ Unsigned }

GroupingElement = _{ Expr }

NameLetters = _{ ('А' .. 'Я' | 'а' .. 'я' | 'A' .. 'Z' | 'a'..'z' | "-" | "_") }
NameString = @{ !(WHITESPACE* ~ Keyword ~ WHITESPACE) ~ ((NameLetters ~ (NameLetters | ASCII_DIGIT)+) | NameLetters+) }
String = @{ !(WHITESPACE* ~ Keyword ~ WHITESPACE) ~ (Character | ("'" ~ "'") | "\"")* }
Keyword = { ^"except" | ^"union" | ^"where" | ^"distinct" }
Character = _{ LETTER | NUMBER | Other | OTHER_ALPHABETIC| Punctuation | SYMBOL }
Punctuation = _{
CONNECTOR_PUNCTUATION
| DASH_PUNCTUATION
| OPEN_PUNCTUATION
| CLOSE_PUNCTUATION
| INITIAL_PUNCTUATION
| "." | "?" | "!" | ":" | ";" | ","
}
Other = _{ "\\" | "/" | "@" | "%" | "&" | "*" | "#" | "§" | "»" | WHITESPACE }

Value = _{ Parameter | True | False | Null | Double | Decimal | Unsigned | Integer | Reference | SingleQuotedString }
True = @{ ^"true" }
False = @{ ^"false" }
Null = @{ ^"null" }
Decimal = @{ Integer ~ ("." ~ ASCII_DIGIT*) }
Double = @{ Integer ~ ("." ~ ASCII_DIGIT*)? ~ (^"e" ~ Integer) }
Integer = @{ ("+" | "-")? ~ ASCII_DIGIT+ }
Unsigned = @{ ASCII_DIGIT+ }
SingleQuotedString = ${ "'" ~ String ~ "'" }
Row = {
("(" ~ RowElem ~ ("," ~ RowElem)* ~ ")")
| (^"row" ~ "(" ~ RowElem ~ ("," ~ RowElem)* ~ ")")
}
RowElem = _{ Concat | Cast | Row | Function | Value }
Parameter = @{ "?" }

EOF = { EOI | ";" }
WHITESPACE = _{ " " | "\t" | "\n" | "\r\n" }
Loading

0 comments on commit 04728e8

Please sign in to comment.