%{ // // Parser.jay // // Author: // Juraj Skripsky (juraj@hotfeet.ch) // // (C) 2004 HotFeet GmbH (http://www.hotfeet.ch) // using System; using System.Collections; using System.Data; namespace Mono.Data.SqlExpressions { internal class Parser { static Parser () { if (Environment.GetEnvironmentVariable ("MONO_DEBUG_SQLEXPRESSIONS") != null) yacc_verbose_flag = 2; } bool cacheAggregationResults = false; DataRow[] aggregationRows = null; static int yacc_verbose_flag; //called by DataTable.Select //called by DataColumn.set_Expression //FIXME: enable cache in this case? public Parser () { ErrorOutput = System.IO.TextWriter.Null; cacheAggregationResults = true; } //called by DataTable.Compute public Parser (DataRow[] aggregationRows) { ErrorOutput = System.IO.TextWriter.Null; this.aggregationRows = aggregationRows; } public IExpression Compile (string sqlExpr) { try { Tokenizer tokenizer = new Tokenizer (sqlExpr); if (yacc_verbose_flag > 1) return (IExpression) yyparse (tokenizer, new yydebug.yyDebugSimple ()); else return (IExpression) yyparse (tokenizer); } catch (yyParser.yyException e) { throw new SyntaxErrorException (String.Format ("Expression '{0}' is invalid.", sqlExpr)); } } %} %token PAROPEN PARCLOSE %token AND OR %token NOT %token TRUE FALSE %token NULL %token PARENT CHILD %token EQ LT GT %token PLUS MINUS %token MUL DIV MOD %token DOT COMMA %token IS IN LIKE %token COUNT SUM AVG MAX MIN STDEV VAR %token IIF SUBSTRING ISNULL LEN TRIM CONVERT %token StringLiteral NumberLiteral DateLiteral %token Identifier %token FunctionName %start Expr %left OR %left AND %left NOT %left EQ LT GT %left PLUS MINUS %left MUL DIV MOD %left UMINUS %% Expr : BoolExpr | ArithExpr ; BoolExpr : PAROPEN BoolExpr PARCLOSE { $$ = (IExpression)$2; } | BoolExpr AND BoolExpr { $$ = new BoolOperation (Operation.AND, (IExpression)$1, (IExpression)$3); } | BoolExpr OR BoolExpr { $$ = new BoolOperation (Operation.OR, (IExpression)$1, (IExpression)$3); } | NOT BoolExpr { $$ = new Negation ((IExpression)$2); } | Predicate ; Predicate : CompPredicate | IsPredicate | LikePredicate | InPredicate ; CompPredicate : ArithExpr CompOp ArithExpr { $$ = new Comparison ((Operation)$2, (IExpression)$1, (IExpression)$3); } ; CompOp : EQ { $$ = Operation.EQ; } | NE { $$ = Operation.NE; } | LT { $$ = Operation.LT; } | GT { $$ = Operation.GT; } | LE { $$ = Operation.LE; } | GE { $$ = Operation.GE; } ; LE : LT EQ; // <= NE : LT GT; // <> GE : GT EQ; // >= ArithExpr : PAROPEN ArithExpr PARCLOSE { $$ = (IExpression)$2; } | ArithExpr MUL ArithExpr { $$ = new ArithmeticOperation (Operation.MUL, (IExpression)$1, (IExpression)$3); } | ArithExpr DIV ArithExpr { $$ = new ArithmeticOperation (Operation.DIV, (IExpression)$1, (IExpression)$3); } | ArithExpr MOD ArithExpr { $$ = new ArithmeticOperation (Operation.MOD, (IExpression)$1, (IExpression)$3); } | ArithExpr PLUS ArithExpr { $$ = new ArithmeticOperation (Operation.ADD, (IExpression)$1, (IExpression)$3); } | ArithExpr MINUS ArithExpr { $$ = new ArithmeticOperation (Operation.SUB, (IExpression)$1, (IExpression)$3); } | MINUS ArithExpr %prec UMINUS { $$ = new Negative ((IExpression)$2); } | Function | Value ; Value : LiteralValue | SingleColumnValue ; LiteralValue : StringLiteral { $$ = new Literal ($1); } | NumberLiteral { $$ = new Literal ($1); } | DateLiteral { $$ = new Literal ($1); } | BoolLiteral ; BoolLiteral : TRUE { $$ = new Literal (true); } | FALSE { $$ = new Literal (false); } ; SingleColumnValue : LocalColumnValue | ParentColumnValue ; MultiColumnValue : LocalColumnValue | ChildColumnValue ; LocalColumnValue : ColumnName { $$ = new ColumnReference ((string)$1); } ; ParentColumnValue : PARENT DOT ColumnName { $$ = new ColumnReference (ReferencedTable.Parent, null, (string)$3); } | PARENT PAROPEN RelationName PARCLOSE DOT ColumnName { $$ = new ColumnReference (ReferencedTable.Parent, (string)$3, (string)$6); } ; ChildColumnValue : CHILD DOT ColumnName { $$ = new ColumnReference (ReferencedTable.Child, null, (string)$3); } | CHILD PAROPEN RelationName PARCLOSE DOT ColumnName { $$ = new ColumnReference (ReferencedTable.Child, (string)$3, (string)$6); } ; ColumnName : Identifier; RelationName : Identifier; Function : CalcFunction | AggFunction ; AggFunction : AggFunctionName PAROPEN MultiColumnValue PARCLOSE { $$ = new Aggregation (cacheAggregationResults, aggregationRows, (AggregationFunction)$1, (ColumnReference)$3); } ; AggFunctionName : COUNT { $$ = AggregationFunction.Count; } | SUM { $$ = AggregationFunction.Sum; } | AVG { $$ = AggregationFunction.Avg; } | MAX { $$ = AggregationFunction.Max; } | MIN { $$ = AggregationFunction.Min; } | STDEV { $$ = AggregationFunction.StDev; } | VAR { $$ = AggregationFunction.Var; } ; CalcFunction : IIF PAROPEN BoolExpr COMMA Expr COMMA Expr PARCLOSE { $$ = new IifFunction ((IExpression)$3, (IExpression)$5, (IExpression)$7); } | SUBSTRING PAROPEN Expr COMMA NumberLiteral COMMA NumberLiteral PARCLOSE { long arg1 = (long) $5; long arg2 = (long) $7; $$ = new SubstringFunction ((IExpression)$3, Convert.ToInt32(arg1), Convert.ToInt32(arg2)); } | ISNULL PAROPEN SingleColumnValue COMMA Expr PARCLOSE { $$ = new IsNullFunction ((IExpression)$3, (IExpression)$5); } | LEN PAROPEN Expr PARCLOSE { $$ = new LenFunction ((IExpression)$3); } | TRIM PAROPEN Expr PARCLOSE { $$ = new TrimFunction ((IExpression)$3); } | CONVERT PAROPEN Expr COMMA TypeSpecifier PARCLOSE { $$ = new ConvertFunction ((IExpression)$3, (string)$5); } ; TypeSpecifier : StringLiteral | Identifier ; IsPredicate : SingleColumnValue IS NULL { $$ = new Comparison (Operation.EQ, (IExpression)$1, new Literal (null)); } | SingleColumnValue IS NOT NULL { $$ = new Comparison (Operation.NE, (IExpression)$1, new Literal (null)); } ; LikePredicate : ArithExpr LIKE StringLiteral { $$ = new Like ((IExpression)$1, (string)$3); } | ArithExpr NOT LIKE StringLiteral { $$ = new Negation (new Like ((IExpression)$1, (string)$3)); } ; InPredicate : SingleColumnValue IN InPredicateValue { $$ = new In ((IExpression)$1, (IList)$3); } | SingleColumnValue NOT IN InPredicateValue { $$ = new Negation (new In ((IExpression)$1, (IList)$4)); } ; InPredicateValue : PAROPEN InValueList PARCLOSE { $$ = $2; } ; InValueList : LiteralValue { $$ = new ArrayList(); ((IList)$$).Add ($1); } | InValueList COMMA LiteralValue { ((IList)($$ = $1)).Add ($3); } ; %% }