DeveelDB  20151217
complete SQL database system, primarly developed for .NET/Mono frameworks
SqlExpression.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 using System.IO;
19 using System.Text;
20 
22 using Deveel.Data.Sql.Parser;
23 using Deveel.Data.Types;
24 
25 namespace Deveel.Data.Sql.Expressions {
34  [Serializable]
35  public abstract class SqlExpression : ISerializable {
36  private int precedence;
37 
42  internal SqlExpression() {
43  }
44 
45  internal SqlExpression(ObjectData data) {
46  }
47 
51  public abstract SqlExpressionType ExpressionType { get; }
52 
58  public virtual bool CanEvaluate {
59  get { return false; }
60  }
61 
62  internal int EvaluatePrecedence {
63  get {
64  if (precedence > 0)
65  return precedence;
66 
67  // Primary
68  if (ExpressionType == SqlExpressionType.Reference ||
69  ExpressionType == SqlExpressionType.FunctionCall ||
70  ExpressionType == SqlExpressionType.Constant)
71  return 150;
72 
73  // Unary
74  if (ExpressionType == SqlExpressionType.UnaryPlus ||
75  ExpressionType == SqlExpressionType.Negate ||
76  ExpressionType == SqlExpressionType.Not)
77  return 140;
78 
79  // Cast
80  if (ExpressionType == SqlExpressionType.Cast)
81  return 139;
82 
83  // Multiplicative
84  if (ExpressionType == SqlExpressionType.Multiply ||
85  ExpressionType == SqlExpressionType.Divide ||
86  ExpressionType == SqlExpressionType.Modulo)
87  return 130;
88 
89  // Additive
90  if (ExpressionType == SqlExpressionType.Add ||
91  ExpressionType == SqlExpressionType.Subtract)
92  return 120;
93 
94  // Relational
95  if (ExpressionType == SqlExpressionType.GreaterThan ||
96  ExpressionType == SqlExpressionType.GreaterOrEqualThan ||
97  ExpressionType == SqlExpressionType.SmallerThan ||
98  ExpressionType == SqlExpressionType.SmallerOrEqualThan ||
99  ExpressionType == SqlExpressionType.Is ||
100  ExpressionType == SqlExpressionType.IsNot ||
101  ExpressionType == SqlExpressionType.Like ||
102  ExpressionType == SqlExpressionType.NotLike)
103  return 110;
104 
105  // Equality
106  if (ExpressionType == SqlExpressionType.Equal ||
107  ExpressionType == SqlExpressionType.NotEqual)
108  return 100;
109 
110  // Logical
111  if (ExpressionType == SqlExpressionType.And)
112  return 90;
113  if (ExpressionType == SqlExpressionType.Or)
114  return 89;
115  if (ExpressionType == SqlExpressionType.XOr)
116  return 88;
117 
118  if (ExpressionType == SqlExpressionType.Conditional)
119  return 80;
120 
121  if (ExpressionType == SqlExpressionType.Assign)
122  return 70;
123 
124  if (ExpressionType == SqlExpressionType.Tuple)
125  return 60;
126 
127  return -1;
128  }
129  set { precedence = value; }
130  }
131 
132  public virtual SqlExpression Prepare(IExpressionPreparer preparer) {
133  var visitor = new PreparerVisitor(preparer);
134  return visitor.Visit(this);
135  }
136 
137  public virtual SqlExpression Accept(SqlExpressionVisitor visitor) {
138  return visitor.Visit(this);
139  }
140 
142  GetData(data);
143  }
144 
145  protected virtual void GetData(SerializeData data) {
146  }
147 
167  public virtual SqlExpression Evaluate(EvaluateContext context) {
168  var visitor = new ExpressionEvaluatorVisitor(context);
169  return visitor.Visit(this);
170  }
171 
172 
195  return Evaluate(null, null);
196  }
197 
198  public SqlExpression Evaluate(IRequest context, IVariableResolver variables) {
199  return Evaluate(context, variables, null);
200  }
201 
202  public SqlExpression Evaluate(IRequest context, IVariableResolver variables, IGroupResolver group) {
203  return Evaluate(new EvaluateContext(context, variables, group));
204  }
205 
206  public override string ToString() {
207  var builder = new ExpressionStringBuilder();
208  return builder.ToSqlString(this);
209  }
210 
219  public static SqlExpression Parse(string s) {
220  return Parse(s, null);
221  }
222 
232  public static SqlExpression Parse(string s, ISystemContext context) {
233  try {
234  // TODO: Get the expression compiler from the context
235  var compiler = SqlParsers.Expression;
236  var result = compiler.Parse(s);
237 
238  if (result.HasErrors)
239  throw new SqlParseException();
240 
241  var expNode = result.RootNode as IExpressionNode;
242  if (expNode == null)
243  throw new SqlExpressionException(ExpressionErrorCodes.CannotParse, "The parse of the text did not result into an expression.");
244 
245  return ExpressionBuilder.Build(expNode);
246  } catch (SqlParseException ex) {
247  throw new SqlExpressionException(ExpressionErrorCodes.CannotParse,
248  "Could not parse input expression: see inner exception for details.", ex);
249  }
250  }
251 
252  #region Factory Methods
253 
254  #region Primary
255 
256  public static SqlConstantExpression Constant(object value) {
257  return Constant(DataObject.Create(value));
258  }
259 
261  return new SqlConstantExpression(value);
262  }
263 
264  public static SqlCastExpression Cast(SqlExpression value, SqlType destType) {
265  return new SqlCastExpression(value, destType);
266  }
267 
268  public static SqlFunctionCallExpression FunctionCall(ObjectName functionName) {
269  return FunctionCall(functionName, new SqlExpression[0]);
270  }
271 
272  public static SqlFunctionCallExpression FunctionCall(ObjectName functionName, SqlExpression[] args) {
273  return new SqlFunctionCallExpression(functionName, args);
274  }
275 
276  public static SqlFunctionCallExpression FunctionCall(string functionName) {
277  return FunctionCall(functionName, new SqlExpression[0]);
278  }
279 
280  public static SqlFunctionCallExpression FunctionCall(string functionName, SqlExpression[] args) {
281  return FunctionCall(ObjectName.Parse(functionName), args);
282  }
283 
284  public static SqlReferenceExpression Reference(ObjectName objectName) {
285  return new SqlReferenceExpression(objectName);
286  }
287 
288  public static SqlVariableReferenceExpression VariableReference(string varName) {
289  return new SqlVariableReferenceExpression(varName);
290  }
291 
292  #endregion
293 
294  public static SqlConditionalExpression Conditional(SqlExpression testExpression, SqlExpression ifTrue) {
295  return Conditional(testExpression, ifTrue, null);
296  }
297 
298  public static SqlConditionalExpression Conditional(SqlExpression testExpression, SqlExpression ifTrue, SqlExpression ifFalse) {
299  return new SqlConditionalExpression(testExpression, ifTrue, ifFalse);
300  }
301 
302  #region Binary Expressions
303 
304  public static SqlBinaryExpression Binary(SqlExpression left, SqlExpressionType expressionType, SqlExpression right) {
305  if (expressionType == SqlExpressionType.Add)
306  return Add(left, right);
307  if (expressionType == SqlExpressionType.Subtract)
308  return Subtract(left, right);
309  if (expressionType == SqlExpressionType.Multiply)
310  return Multiply(left, right);
311  if (expressionType == SqlExpressionType.Divide)
312  return Divide(left, right);
313  if (expressionType == SqlExpressionType.Modulo)
314  return Modulo(left, right);
315 
316  if (expressionType == SqlExpressionType.Equal)
317  return Equal(left, right);
318  if (expressionType == SqlExpressionType.NotEqual)
319  return NotEqual(left, right);
320  if (expressionType == SqlExpressionType.Is)
321  return Is(left, right);
322  if (expressionType == SqlExpressionType.IsNot)
323  return IsNot(left, right);
324  if (expressionType == SqlExpressionType.GreaterThan)
325  return GreaterThan(left, right);
326  if (expressionType == SqlExpressionType.GreaterOrEqualThan)
327  return GreaterOrEqualThan(left, right);
328  if (expressionType == SqlExpressionType.SmallerThan)
329  return SmallerThan(left, right);
330  if (expressionType == SqlExpressionType.SmallerOrEqualThan)
331  return SmallerOrEqualThan(left, right);
332 
333  if (expressionType == SqlExpressionType.Like)
334  return Like(left, right);
335  if (expressionType == SqlExpressionType.NotLike)
336  return NotLike(left, right);
337 
338  if (expressionType == SqlExpressionType.And)
339  return And(left, right);
340  if (expressionType == SqlExpressionType.Or)
341  return Or(left, right);
342  if (expressionType == SqlExpressionType.XOr)
343  return XOr(left, right);
344 
345  if (expressionType.IsAny())
346  return Any(left, expressionType.SubQueryPlainType(), right);
347  if (expressionType.IsAll())
348  return All(left, expressionType.SubQueryPlainType(), right);
349 
350  throw new ArgumentException(String.Format("Expression type {0} is not a Binary", expressionType));
351  }
352 
354  return new SqlBinaryExpression(left, SqlExpressionType.Equal, right);
355  }
356 
358  return new SqlBinaryExpression(left, SqlExpressionType.NotEqual, right);
359  }
360 
361  public static SqlBinaryExpression Is(SqlExpression left, SqlExpression right) {
362  return new SqlBinaryExpression(left, SqlExpressionType.Is, right);
363  }
364 
366  return new SqlBinaryExpression(left, SqlExpressionType.IsNot, right);
367  }
368 
371  }
372 
375  }
376 
378  return new SqlBinaryExpression(left, SqlExpressionType.SmallerThan, right);
379  }
380 
382  return new SqlBinaryExpression(left, SqlExpressionType.GreaterThan, right);
383  }
384 
386  return new SqlBinaryExpression(left, SqlExpressionType.Like, right);
387  }
388 
390  return new SqlBinaryExpression(left, SqlExpressionType.NotLike, right);
391  }
392 
393  public static SqlBinaryExpression And(SqlExpression left, SqlExpression right) {
394  return new SqlBinaryExpression(left, SqlExpressionType.And, right);
395  }
396 
397  public static SqlBinaryExpression Or(SqlExpression left, SqlExpression right) {
398  return new SqlBinaryExpression(left, SqlExpressionType.Or, right);
399  }
400 
401  public static SqlBinaryExpression XOr(SqlExpression left, SqlExpression right) {
402  return new SqlBinaryExpression(left, SqlExpressionType.XOr, right);
403  }
404 
405  public static SqlBinaryExpression Add(SqlExpression left, SqlExpression right) {
406  return new SqlBinaryExpression(left, SqlExpressionType.Add, right);
407  }
408 
410  return new SqlBinaryExpression(left, SqlExpressionType.Subtract, right);
411  }
412 
414  return new SqlBinaryExpression(left, SqlExpressionType.Multiply, right);
415  }
416 
418  return new SqlBinaryExpression(left, SqlExpressionType.Divide, right);
419  }
420 
422  return new SqlBinaryExpression(left, SqlExpressionType.Modulo, right);
423  }
424 
426  if (anyType == SqlExpressionType.Equal ||
427  anyType == SqlExpressionType.AnyEqual)
428  return AnyEqual(left, right);
429  if (anyType == SqlExpressionType.NotEqual ||
430  anyType == SqlExpressionType.AnyNotEqual)
431  return AnyNotEqual(left, right);
432  if (anyType == SqlExpressionType.AnyGreaterThan ||
433  anyType == SqlExpressionType.GreaterThan)
434  return AnyGreaterThan(left, right);
435  if (anyType == SqlExpressionType.SmallerThan ||
436  anyType == SqlExpressionType.AnySmallerThan)
437  return AnySmallerThan(left, right);
438  if (anyType == SqlExpressionType.GreaterOrEqualThan ||
439  anyType == SqlExpressionType.AnyGreaterOrEqualThan)
440  return AnyGreaterOrEqualThan(left, right);
441  if (anyType == SqlExpressionType.GreaterOrEqualThan ||
442  anyType == SqlExpressionType.AnySmallerOrEqualThan)
443  return AnySmallerOrEqualThan(left, right);
444 
445  throw new ArgumentException(String.Format("The type '{0}' cannot be part of an ANY operator.", anyType));
446  }
447 
449  return new SqlBinaryExpression(left, SqlExpressionType.AnyEqual, right);
450  }
451 
453  return new SqlBinaryExpression(left, SqlExpressionType.AnyNotEqual, right);
454  }
455 
457  return new SqlBinaryExpression(left, SqlExpressionType.AnyGreaterThan, right);
458  }
459 
462  }
463 
465  return new SqlBinaryExpression(left, SqlExpressionType.AnySmallerThan, right);
466  }
467 
470  }
471 
473  if (allType == SqlExpressionType.Equal ||
474  allType == SqlExpressionType.AllEqual)
475  return AllEqual(left, right);
476  if (allType == SqlExpressionType.NotEqual ||
477  allType == SqlExpressionType.AllNotEqual)
478  return AllNotEqual(left, right);
479  if (allType == SqlExpressionType.GreaterThan ||
480  allType == SqlExpressionType.AllGreaterThan)
481  return AllGreaterThan(left, right);
482  if (allType == SqlExpressionType.SmallerThan ||
483  allType == SqlExpressionType.AllSmallerThan)
484  return AllSmallerThan(left, right);
485  if (allType == SqlExpressionType.GreaterOrEqualThan ||
486  allType == SqlExpressionType.AllGreaterOrEqualThan)
487  return AllGreaterOrEqualThan(left, right);
488  if (allType == SqlExpressionType.SmallerOrEqualThan ||
489  allType == SqlExpressionType.AllSmallerOrEqualThan)
490  return AllSmallerOrEqualThan(left, right);
491 
492  throw new ArgumentException(String.Format("The type '{0}' cannot be part of an ALL operator.", allType));
493  }
494 
496  return new SqlBinaryExpression(left, SqlExpressionType.AllEqual, right);
497  }
498 
500  return new SqlBinaryExpression(left, SqlExpressionType.AllNotEqual, right);
501  }
502 
504  return new SqlBinaryExpression(left, SqlExpressionType.AllGreaterThan, right);
505  }
506 
509  }
510 
512  return new SqlBinaryExpression(left, SqlExpressionType.AllSmallerThan, right);
513  }
514 
517  }
518 
519  #endregion
520 
521  #region Unary Expressions
522 
523  public static SqlUnaryExpression Unary(SqlExpressionType expressionType, SqlExpression operand) {
524  if (expressionType == SqlExpressionType.UnaryPlus)
525  return UnaryPlus(operand);
526  if (expressionType == SqlExpressionType.Negate)
527  return Negate(operand);
528  if (expressionType == SqlExpressionType.Not)
529  return Not(operand);
530 
531  throw new ArgumentException(String.Format("Expression Type {0} is not an Unary.", expressionType));
532  }
533 
534  public static SqlUnaryExpression Not(SqlExpression operand) {
535  return new SqlUnaryExpression(SqlExpressionType.Not, operand);
536  }
537 
538  public static SqlUnaryExpression Negate(SqlExpression operand) {
539  return new SqlUnaryExpression(SqlExpressionType.Negate, operand);
540  }
541 
542  public static SqlUnaryExpression UnaryPlus(SqlExpression operand) {
543  return new SqlUnaryExpression(SqlExpressionType.UnaryPlus, operand);
544  }
545 
546  #endregion
547 
548  public static SqlAssignExpression Assign(SqlExpression reference, SqlExpression valueExpression) {
549  return new SqlAssignExpression(reference, valueExpression);
550  }
551 
552 
553  public static SqlTupleExpression Tuple(SqlExpression[] expressions) {
554  return new SqlTupleExpression(expressions);
555  }
556 
558  return Tuple(new[] {expr1, exp2});
559  }
560 
561  public static SqlTupleExpression Tuple(SqlExpression expr1, SqlExpression expr2, SqlExpression expr3) {
562  return Tuple(new[] {expr1, expr2, expr3});
563  }
564 
565  #endregion
566 
567  internal static void Serialize(SqlExpression expression, BinaryWriter writer) {
568  var serializer = new BinarySerializer();
569  serializer.Serialize(writer, expression);
570  }
571 
572  internal static SqlExpression Deserialize(BinaryReader reader) {
573  var serializer = new BinarySerializer();
574  return (SqlExpression) serializer.Deserialize(reader, typeof(SqlExpression));
575  }
576  }
577 }
static SqlBinaryExpression Divide(SqlExpression left, SqlExpression right)
void GetData(SerializeData data)
static ObjectName Parse(string s)
Parses the given string into a ObjectName object.
Definition: ObjectName.cs:139
static SqlBinaryExpression AllGreaterThan(SqlExpression left, SqlExpression right)
static SqlExpression Parse(string s)
Parses the given SQL string to an expression that can be evaluated.
An expression that references an object within a context.
static SqlBinaryExpression All(SqlExpression left, SqlExpressionType allType, SqlExpression right)
A long string in the system.
static SqlBinaryExpression And(SqlExpression left, SqlExpression right)
Handles expressions computed against an unary operator.
static SqlBinaryExpression SmallerOrEqualThan(SqlExpression left, SqlExpression right)
static SqlBinaryExpression AllSmallerThan(SqlExpression left, SqlExpression right)
The execution context of a database system, that is defining the configurations and the components us...
static SqlBinaryExpression Multiply(SqlExpression left, SqlExpression right)
static SqlBinaryExpression AllGreaterOrEqualThan(SqlExpression left, SqlExpression right)
virtual void GetData(SerializeData data)
static SqlExpression Build(IExpressionNode node)
static DataObject Create(object value)
Definition: DataObject.cs:646
static SqlTupleExpression Tuple(SqlExpression[] expressions)
An SqlExpression that will cast a value retrieved by the evaluation of another expression into a give...
static SqlVariableReferenceExpression VariableReference(string varName)
static SqlBinaryExpression Equal(SqlExpression left, SqlExpression right)
static SqlBinaryExpression SmallerThan(SqlExpression left, SqlExpression right)
Describes the name of an object within a database.
Definition: ObjectName.cs:44
static SqlBinaryExpression AnySmallerThan(SqlExpression left, SqlExpression right)
static SqlTupleExpression Tuple(SqlExpression expr1, SqlExpression expr2, SqlExpression expr3)
static SqlAssignExpression Assign(SqlExpression reference, SqlExpression valueExpression)
SqlExpression()
Internally constructs the SQL expression, avoiding external implementations to be allowed to inherit ...
static SqlUnaryExpression Not(SqlExpression operand)
static SqlConditionalExpression Conditional(SqlExpression testExpression, SqlExpression ifTrue)
static void Serialize(SqlExpression expression, BinaryWriter writer)
SqlExpressionType
All the possible type of SqlExpression supported
SqlExpression Evaluate(IRequest context, IVariableResolver variables)
virtual SqlExpression Evaluate(EvaluateContext context)
When overridden by a derived class, this method evaluates the expression within the provided context...
static SqlBinaryExpression AllSmallerOrEqualThan(SqlExpression left, SqlExpression right)
static SqlConstantExpression Constant(DataObject value)
static SqlBinaryExpression Modulo(SqlExpression left, SqlExpression right)
static SqlBinaryExpression Add(SqlExpression left, SqlExpression right)
static SqlBinaryExpression Or(SqlExpression left, SqlExpression right)
static SqlBinaryExpression IsNot(SqlExpression left, SqlExpression right)
static SqlExpression Deserialize(BinaryReader reader)
Defines a contract used by grouping functions to find information about the current group being evalu...
SqlExpression Evaluate()
Statically evaluates the expression, outside any context.
static SqlBinaryExpression NotEqual(SqlExpression left, SqlExpression right)
static SqlBinaryExpression AnyEqual(SqlExpression left, SqlExpression right)
static readonly ISqlParser Expression
Definition: SqlParsers.cs:21
Represents a dynamic object that encapsulates a defined SqlType and a compatible constant ISqlObject ...
Definition: DataObject.cs:35
static SqlBinaryExpression XOr(SqlExpression left, SqlExpression right)
An interface used to prepare a SqlExpression object.
static SqlBinaryExpression Subtract(SqlExpression left, SqlExpression right)
static SqlBinaryExpression AnyNotEqual(SqlExpression left, SqlExpression right)
ExpressionErrorCodes
Lists all the codes of errors in the expressions domain
static SqlBinaryExpression Like(SqlExpression left, SqlExpression right)
virtual SqlExpression Prepare(IExpressionPreparer preparer)
Represents an expression which has a constant value
Defines the properties of a specific SQL Type and handles the values compatible.
Definition: SqlType.cs:33
static SqlUnaryExpression UnaryPlus(SqlExpression operand)
SqlParseResult Parse(string input)
Analyzes and parses the input and results an object that describes the parsed nodes in a tree that ca...
static SqlExpression Parse(string s, ISystemContext context)
Parses the given SQL string to an expression that can be evaluated.
An interface to resolve a variable name to a constant object.
static SqlBinaryExpression Any(SqlExpression left, SqlExpressionType anyType, SqlExpression right)
static SqlBinaryExpression AnyGreaterThan(SqlExpression left, SqlExpression right)
An expression that holds a constant value.
SqlExpression Evaluate(IRequest context, IVariableResolver variables, IGroupResolver group)
static SqlFunctionCallExpression FunctionCall(string functionName, SqlExpression[] args)
static SqlBinaryExpression AllEqual(SqlExpression left, SqlExpression right)
static SqlBinaryExpression NotLike(SqlExpression left, SqlExpression right)
static SqlReferenceExpression Reference(ObjectName objectName)
virtual SqlExpression Accept(SqlExpressionVisitor visitor)
static SqlConditionalExpression Conditional(SqlExpression testExpression, SqlExpression ifTrue, SqlExpression ifFalse)
static SqlBinaryExpression AnyGreaterOrEqualThan(SqlExpression left, SqlExpression right)
static SqlFunctionCallExpression FunctionCall(string functionName)
static SqlCastExpression Cast(SqlExpression value, SqlType destType)
static SqlBinaryExpression Binary(SqlExpression left, SqlExpressionType expressionType, SqlExpression right)
Defines the base class for instances that represent SQL expression tree nodes.
static SqlFunctionCallExpression FunctionCall(ObjectName functionName, SqlExpression[] args)
static SqlConstantExpression Constant(object value)
static SqlUnaryExpression Negate(SqlExpression operand)
static SqlFunctionCallExpression FunctionCall(ObjectName functionName)
Encapsulates the elements needed to evaluate an SqlExpression
An error that occurs when compiling a input string into a SQL object.
This interface acts like a marker that indicates if a ISqlNode represents a SQL expression.
static SqlBinaryExpression AnySmallerOrEqualThan(SqlExpression left, SqlExpression right)
static SqlTupleExpression Tuple(SqlExpression expr1, SqlExpression exp2)
static SqlBinaryExpression AllNotEqual(SqlExpression left, SqlExpression right)
static SqlUnaryExpression Unary(SqlExpressionType expressionType, SqlExpression operand)
static SqlBinaryExpression GreaterThan(SqlExpression left, SqlExpression right)
static SqlBinaryExpression GreaterOrEqualThan(SqlExpression left, SqlExpression right)
virtual SqlExpression Visit(SqlExpression expression)
Visits a given SQL expression.
static SqlBinaryExpression Is(SqlExpression left, SqlExpression right)