DeveelDB  20151217
complete SQL database system, primarly developed for .NET/Mono frameworks
SqlGrammarBase.cs
Go to the documentation of this file.
1 //
2 // Copyright 2010-2015 Deveel
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
17 using System;
18 
19 using Irony.Parsing;
20 
21 namespace Deveel.Data.Sql.Parser {
22  abstract class SqlGrammarBase : Grammar {
23  // cached most used non-terminal
24  private NonTerminal sqlExpression;
25  private NonTerminal objectname;
26  private NonTerminal datatype;
27 
28  protected SqlGrammarBase()
29  : base(false) {
30  SetupGrammar();
31  }
32 
33  public abstract string Dialect { get; }
34 
35  protected StringLiteral StringLiteral { get; private set; }
36 
37  protected NumberLiteral NumberLiteral { get; private set; }
38 
39  protected NumberLiteral PositiveLiteral { get; private set; }
40 
41  protected IdentifierTerminal Identifier { get; private set; }
42 
43  protected KeyTerm Comma { get; private set; }
44 
45  protected KeyTerm Dot { get; private set; }
46 
47  protected KeyTerm Colon { get; private set; }
48 
49  protected KeyTerm As { get; private set; }
50 
51  protected abstract NonTerminal MakeRoot();
52 
53  private void Comments() {
54  var comment = new CommentTerminal("multiline_comment", "/*", "*/");
55  var lineComment = new CommentTerminal("singleline_comment", "--", "\n", "\r\n");
56  NonGrammarTerminals.Add(comment);
57  NonGrammarTerminals.Add(lineComment);
58  }
59 
60  private void Literals() {
61  StringLiteral = new StringLiteral("string", "'", StringOptions.AllowsAllEscapes, typeof(StringLiteralNode));
62  NumberLiteral = new NumberLiteral("number", NumberOptions.DisableQuickParse | NumberOptions.AllowSign, typeof(NumberLiteralNode));
63  PositiveLiteral = new NumberLiteral("positive", NumberOptions.IntOnly, typeof(IntegerLiteralNode));
64  }
65 
66  private void MakeSimpleId() {
67  Identifier = new IdentifierTerminal("simple_id");
68  var idStringLiteral = new StringLiteral("simple_id_quoted");
69  idStringLiteral.AddStartEnd("\"", StringOptions.NoEscapes);
70  idStringLiteral.AstConfig.NodeType = typeof(IdentifierNode);
71  idStringLiteral.SetOutputTerminal(this, Identifier);
72  }
73 
74  private void Operators() {
75  RegisterOperators(10, "*", "/", "%");
76  RegisterOperators(9, "+", "-");
77  RegisterOperators(8, "=", ">", "<", ">=", "<=", "<>", "!=");
78  RegisterOperators(8, Key("LIKE"), Key("IN"), Key("IS"), Key("IS") + Key("NOT"));
79  RegisterOperators(7, "^", "&", "|");
80  RegisterOperators(6, Key("NOT"));
81  RegisterOperators(5, Key("AND"));
82  RegisterOperators(4, Key("OR"));
83  }
84 
85  private void SetupGrammar() {
86  Comma = ToTerm(",");
87  Dot = ToTerm(".");
88  Colon = ToTerm(":");
89  As = ToTerm("AS");
90 
91  MakeSimpleId();
92 
93  Comments();
94  Keywords();
95  ReservedWords();
96  Literals();
97 
98  Operators();
99 
100  MarkPunctuation(",", "(", ")", "AS");
101 
102  Root = MakeRoot();
103  }
104 
105  protected KeyTerm Key(string term) {
106  KeyTerm keyTerm;
107  if (!KeyTerms.TryGetValue(term, out keyTerm))
108  KeyTerms[term] = keyTerm = ToTerm(term);
109 
110  return keyTerm;
111  }
112 
113  protected virtual void Keywords() {
114 
115  }
116 
117  protected virtual void ReservedWords() {
118 
119  }
120 
121  protected NonTerminal ObjectName() {
122  if (objectname != null)
123  return objectname;
124 
125  objectname = new NonTerminal("object_name", typeof(ObjectNameNode));
126  objectname.Rule = MakePlusRule(objectname, Dot, Identifier);
127  return objectname;
128  }
129 
130  protected NonTerminal DataType() {
131  if (datatype != null)
132  return datatype;
133 
134  datatype = new NonTerminal("datatype", typeof (DataTypeNode));
135  var numberPrecision = new NonTerminal("number_precision");
136  var characterType = new NonTerminal("character_type");
137  var localeOpt = new NonTerminal("locale_opt");
138  var encodingOp = new NonTerminal("encoding_opt");
139  var booleanType = new NonTerminal("boolean_type");
140  var integerType = new NonTerminal("integer_type");
141  var decimalType = new NonTerminal("decimal_type");
142  var floatType = new NonTerminal("float_type");
143  var dateType = new NonTerminal("date_type");
144  var intervalType = new NonTerminal("interval_type");
145  var intervalFormatOpt = new NonTerminal("interval_format_opt");
146  var datatypeSize = new NonTerminal("datatype_size");
147  var longVarchar = new NonTerminal("long_varchar");
148  var binaryType = new NonTerminal("binary_type");
149  var longVarbinary = new NonTerminal("long_varbinary");
150  var userType = new NonTerminal("user_type");
151  var rowType = new NonTerminal("row_type");
152  var userTypeMetaOpt = new NonTerminal("user_type_meta_opt");
153  var userTypeMetaList = new NonTerminal("user_type_meta_list");
154  var userTypeMeta = new NonTerminal("user_type_meta", typeof(DataTypeMetaNode));
155 
156  datatype.Rule = characterType |
157  booleanType |
158  dateType |
159  integerType |
160  decimalType |
161  floatType |
162  binaryType |
163  rowType |
164  userType;
165 
166  characterType.Rule = Key("CHAR") + datatypeSize + localeOpt + encodingOp |
167  Key("VARCHAR") + datatypeSize + localeOpt + encodingOp |
168  longVarchar + datatypeSize + localeOpt + encodingOp;
169  localeOpt.Rule = Empty | Key("LOCALE") + StringLiteral;
170  encodingOp.Rule = Empty | Key("ENCODING") + StringLiteral;
171  dateType.Rule = Key("DATE") | Key("TIME") | Key("TIMESTAMP");
172  booleanType.Rule = Key("BOOLEAN") | Key("BIT");
173  integerType.Rule = Key("INT") |
174  Key("INTEGER") |
175  Key("BIGINT") |
176  Key("SMALLINT") |
177  Key("TINYINT");
178  decimalType.Rule = Key("DECIMAL") + numberPrecision |
179  Key("NUMERIC") + numberPrecision |
180  Key("NUMBER") + numberPrecision;
181  floatType.Rule = Key("FLOAT") |
182  Key("REAL") |
183  Key("DOUBLE");
184  binaryType.Rule = Key("BINARY") + datatypeSize |
185  Key("VARBINARY") + datatypeSize |
186  Key("BLOB") |
187  longVarbinary + datatypeSize;
188  longVarchar.Rule = Key("LONG") + Key("VARCHAR");
189  longVarbinary.Rule = Key("LONG") + Key("VARBINARY");
190  rowType.Rule = ObjectName() + "%" + Key("ROWTYPE");
191  userType.Rule = ObjectName() + userTypeMetaOpt;
192  userTypeMetaOpt.Rule = Empty | "(" + userTypeMetaList + ")";
193  userTypeMetaList.Rule = MakeStarRule(userTypeMetaList, Comma, userTypeMeta);
194  userTypeMeta.Rule = Identifier + "=" + StringLiteral;
195  intervalType.Rule = Key("INTERVAL") + intervalFormatOpt;
196  intervalFormatOpt.Rule = Key("YEAR") + Key("TO") + Key("MONTH") |
197  Key("DAY") + Key("TO") + Key("SECOND");
198 
199  datatypeSize.Rule = Empty | "(" + PositiveLiteral + ")";
200 
201  numberPrecision.Rule = Empty |
202  "(" + PositiveLiteral + ")" |
203  "(" + PositiveLiteral + "," + PositiveLiteral + ")";
204 
205  return datatype;
206  }
207 
208  protected NonTerminal SqlExpressionList() {
209  var list = new NonTerminal("sql_expression_list");
210  list.Rule = MakePlusRule(list, Comma, SqlExpression());
211  return list;
212  }
213 
214  protected NonTerminal SqlQueryExpression() {
215  var selectIntoOpt = new NonTerminal("select_into_opt");
216  var selectSet = new NonTerminal("select_set");
217  var selectRestrictOpt = new NonTerminal("select_restrict_opt");
218  var selectItem = new NonTerminal("select_item", typeof(SelectItemNode));
219  var selectAsOpt = new NonTerminal("select_as_opt");
220  var selectSource = new NonTerminal("select_source");
221  var selectItemList = new NonTerminal("select_item_list");
222  var fromClauseOpt = new NonTerminal("from_clause_opt");
223  var fromClause = new NonTerminal("from_clause", typeof(FromClauseNode));
224  var fromSource = new NonTerminal("from_source");
225  var fromTableSource = new NonTerminal("from_table_source", typeof(FromTableSourceNode));
226  var fromQuerySource = new NonTerminal("from_query_source", typeof(FromQuerySourceNode));
227  var joinOpt = new NonTerminal("join_opt");
228  var joinType = new NonTerminal("join_type");
229  var join = new NonTerminal("join", typeof (JoinNode));
230  var onOpt = new NonTerminal("on_opt");
231  var whereClauseOpt = new NonTerminal("where_clause_opt");
232  var groupByOpt = new NonTerminal("group_by_opt");
233  var groupBy = new NonTerminal("group_by", typeof(GroupByNode));
234  var havingClauseOpt = new NonTerminal("having_clause_opt");
235  var queryCompositeOpt = new NonTerminal("query_composite_opt");
236  var queryComposite = new NonTerminal("query_composite", typeof(QueryCompositeNode));
237  var expression = new NonTerminal("sql_query_expression", typeof(SqlQueryExpressionNode));
238  var allOpt = new NonTerminal("all_opt");
239  var asOpt = new NonTerminal("as_opt");
240 
241  expression.Rule = Key("SELECT") + selectRestrictOpt +
242  selectIntoOpt +
243  selectSet +
244  fromClauseOpt +
245  whereClauseOpt +
246  groupByOpt +
247  queryCompositeOpt;
248 
249  selectRestrictOpt.Rule = Empty | Key("ALL") | Key("DISTINCT");
250  selectIntoOpt.Rule = Empty | Key("INTO") + ObjectName();
251  selectSet.Rule = selectItemList | "*";
252  selectItemList.Rule = MakePlusRule(selectItemList, Comma, selectItem);
253  selectItem.Rule = selectSource + selectAsOpt;
254  selectAsOpt.Rule = Empty |
255  As + Identifier |
256  Identifier;
257  selectSource.Rule = SqlExpression() | ObjectName();
258  fromClauseOpt.Rule = Empty | fromClause;
259  fromClause.Rule = Key("FROM") + fromSource + joinOpt;
260  fromSource.Rule = fromTableSource |
261  fromQuerySource;
262  fromTableSource.Rule = ObjectName() + selectAsOpt;
263  fromQuerySource.Rule = "(" + expression + ")" + selectAsOpt;
264 
265  joinOpt.Rule = Empty | join;
266  join.Rule = joinType + fromSource + onOpt;
267  onOpt.Rule = Empty | Key("ON") + SqlExpression() + joinOpt;
268  joinType.Rule = Key("INNER") + Key("JOIN")|
269  Key("OUTER") + Key("JOIN") |
270  Key("LEFT") + Key("JOIN") |
271  Key("LEFT") + Key("OUTER") + Key("JOIN") |
272  Key("RIGHT") + Key("JOIN") |
273  Key("RIGHT") + Key("OUTER") + Key("JOIN") |
274  Comma;
275  whereClauseOpt.Rule = Empty | Key("WHERE") + SqlExpression();
276  groupByOpt.Rule = Empty | groupBy;
277  groupBy.Rule = Key("GROUP") + Key("BY") + SqlExpressionList() + havingClauseOpt;
278  havingClauseOpt.Rule = Empty | Key("HAVING") + SqlExpression();
279  queryCompositeOpt.Rule = Empty | queryComposite;
280  queryComposite.Rule = Key("UNION") + allOpt + expression |
281  Key("INTERSECT") + allOpt + expression |
282  Key("EXCEPT") + allOpt + expression;
283  allOpt.Rule = Empty | Key("ALL");
284  asOpt.Rule = Empty | As;
285 
286  MarkTransient(selectSource);
287 
288  return expression;
289  }
290 
291  protected NonTerminal SqlExpression() {
292  if (sqlExpression != null)
293  return sqlExpression;
294 
295  sqlExpression = new NonTerminal("sql_expression");
296 
297  var sqlUnaryExpression = new NonTerminal("sql_unary_expression", typeof(SqlUnaryExpressionNode));
298  var sqlBinaryExpression = new NonTerminal("sql_binary_expression", typeof(SqlBinaryExpressionNode));
299  var sqlBetweenExpression = new NonTerminal("sql_between_expression", typeof(SqlBetweenExpressionNode));
300  var sqlCaseExpression = new NonTerminal("sql_case_expression", typeof(SqlCaseExpressionNode));
301  var sqlReferenceExpression = new NonTerminal("sql_reference_expression", typeof(SqlReferenceExpressionNode));
302  var term = new NonTerminal("term");
303  var sqlSimpleExpression = new NonTerminal("sql_simple_expression");
304  var unaryOp = new NonTerminal("unary_op");
305  var binaryOp = new NonTerminal("binary_op");
306  var binaryOpSimple = new NonTerminal("binary_op_simple");
307  var logicalOp = new NonTerminal("logical_op");
308  var subqueryOp = new NonTerminal("subquery_op");
309  var caseTestExpressionOpt = new NonTerminal("case_test_expression_opt");
310  var caseWhenThenList = new NonTerminal("case_when_then_list");
311  var caseWhenThen = new NonTerminal("case_when_then", typeof(CaseSwitchNode));
312  var caseElseOpt = new NonTerminal("case_else_opt");
313  var sqlVarefExpression = new NonTerminal("sql_varef_expression", typeof(SqlVariableRefExpressionNode));
314  var sqlConstantExpression = new NonTerminal("sql_constant_expression", typeof(SqlConstantExpressionNode));
315  var functionCallExpression = new NonTerminal("function_call_expression", typeof(SqlFunctionCallExpressionNode));
316  var functionCallArgsOpt = new NonTerminal("function_call_args_opt");
317  var functionCallArgsList = new NonTerminal("function_call_args_list");
318  var notOpt = new NonTerminal("not_opt");
319  var grouped = new NonTerminal("grouped");
320  var anyOp = new NonTerminal("any_op");
321  var allOp = new NonTerminal("all_op");
322 
323  sqlExpression.Rule = sqlSimpleExpression |
324  sqlBetweenExpression |
325  sqlCaseExpression |
326  SqlQueryExpression();
327  sqlConstantExpression.Rule = StringLiteral | NumberLiteral | Key("TRUE") | Key("FALSE") | Key("NULL");
328  sqlSimpleExpression.Rule = term | sqlBinaryExpression | sqlUnaryExpression;
329  term.Rule = sqlReferenceExpression |
330  sqlVarefExpression |
331  sqlConstantExpression |
332  functionCallExpression |
333  grouped;
334  sqlReferenceExpression.Rule = ObjectName();
335  grouped.Rule = ImplyPrecedenceHere(30) + "(" + sqlExpression + ")";
336  sqlUnaryExpression.Rule = unaryOp + term;
337  unaryOp.Rule = Key("NOT") | "+" | "-" | "~";
338  sqlBinaryExpression.Rule = sqlSimpleExpression + binaryOp + sqlSimpleExpression;
339  binaryOpSimple.Rule = ToTerm("+") | "-" | "*" | "/" | "%" | ">" | "<" | "=" | "<>";
340  binaryOp.Rule = binaryOpSimple | allOp | anyOp | logicalOp | subqueryOp;
341  logicalOp.Rule = Key("AND") | Key("OR") | Key("IS") | Key("IS") + Key("NOT") + "&" | "|";
342  subqueryOp.Rule = Key("IN") | Key("NOT") + Key("IN");
343  anyOp.Rule = Key("ANY") + binaryOpSimple;
344  allOp.Rule = Key("ALL") + binaryOpSimple;
345  sqlBetweenExpression.Rule = sqlSimpleExpression + notOpt + Key("BETWEEN") + sqlSimpleExpression + Key("AND") +
346  sqlSimpleExpression;
347  sqlCaseExpression.Rule = Key("CASE") + caseTestExpressionOpt + caseWhenThenList + caseElseOpt + Key("END");
348  caseTestExpressionOpt.Rule = Empty | sqlExpression;
349  caseElseOpt.Rule = Empty | Key("ELSE") + sqlExpression;
350  caseWhenThenList.Rule = MakePlusRule(caseWhenThenList, caseWhenThen);
351  caseWhenThen.Rule = Key("WHEN") + sqlExpression + Key("THEN") + sqlExpression;
352 
353  functionCallExpression.Rule = ObjectName() + functionCallArgsOpt;
354  functionCallArgsOpt.Rule = Empty | "(" + functionCallArgsList + ")";
355  functionCallArgsList.Rule = MakeStarRule(functionCallArgsList, Comma, sqlExpression);
356 
357  sqlVarefExpression.Rule = Colon + Identifier;
358 
359  notOpt.Rule = Empty | Key("NOT");
360 
361  MarkTransient(sqlExpression, term, sqlSimpleExpression, grouped, functionCallArgsOpt);
362 
363  binaryOp.SetFlag(TermFlags.InheritPrecedence);
364  binaryOpSimple.SetFlag(TermFlags.InheritPrecedence);
365  logicalOp.SetFlag(TermFlags.InheritPrecedence);
366  subqueryOp.SetFlag(TermFlags.InheritPrecedence);
367  unaryOp.SetFlag(TermFlags.InheritPrecedence);
368 
369  return sqlExpression;
370  }
371  }
372 }
The node that represents a switch in a CASE expression
This is a simple identifier within a SQL grammar.
Represents a composed name for an object within the system.
An expression that encapsulates a unary operator for a given operand.
An SQL BETWEEN expression node that evaluates to true if the Expression given is between MinValue (in...
Describes the name of an object within a database.
Definition: ObjectName.cs:44
The node in an SQL query that defines the sources from which to retrieve the data queried...
A node in the grammar tree that defines a sub-query in a FROM clause.
Handles a numeric literal value, belonging to a wider group than integer numbers, spanning from real ...
Represents the node that is a database table as source of a query.
The root node of an expression used to select a set of items from a set of sources defined...
An expression node that references an object within the database context (such as a table...
A node containing a constant literal string passed within an SQL command.
References a variable within a SQL execution context.
A single item selected within a query node tree.
A node describing the JOIN between two sources within a query.
Definition: JoinNode.cs:29
A node that describes the GROUP BY clause in a SQL query.
Definition: GroupByNode.cs:25
An node that represents a constant value set within a context of an SQL command.
Describes the information of a data type as found in a SQL string.
Definition: DataTypeNode.cs:28
Composes two queries to obtain a set that is the result of a given composition function.
Represents an expression that evaluates between two other expressions.
A node in a SQL command tree that is used to request a function.
Encapsulates a number that is any falling in the group of integers.
An SQL node describing an in-line CASE conditional expression.