a575963da9
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
367 lines
6.8 KiB
Plaintext
367 lines
6.8 KiB
Plaintext
%{
|
|
//
|
|
// Parser.jay
|
|
//
|
|
// Author:
|
|
// Juraj Skripsky (juraj@hotfeet.ch)
|
|
//
|
|
// (C) 2004 HotFeet GmbH (http://www.hotfeet.ch)
|
|
// Copyright 2011 Xamarin Inc (http://www.xamarin.com)
|
|
//
|
|
|
|
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) {
|
|
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 NOT_IN LIKE NOT_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
|
|
| NULL { $$ = new Literal (null); }
|
|
;
|
|
|
|
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
|
|
| ColumnName DOT Identifier
|
|
{
|
|
$$ = (string)$1 + "." + (string)$3;
|
|
}
|
|
;
|
|
|
|
RelationName
|
|
: Identifier;
|
|
|
|
Function
|
|
: CalcFunction
|
|
| AggFunction
|
|
| StringFunction
|
|
;
|
|
|
|
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; }
|
|
;
|
|
|
|
StringExpr
|
|
: SingleColumnValue
|
|
| StringLiteral { $$ = new Literal ($1); }
|
|
| Function
|
|
;
|
|
|
|
StringFunction
|
|
: TRIM PAROPEN ArithExpr PARCLOSE
|
|
{
|
|
$$ = new TrimFunction ((IExpression)$3);
|
|
}
|
|
| SUBSTRING PAROPEN ArithExpr COMMA ArithExpr COMMA ArithExpr PARCLOSE
|
|
{
|
|
$$ = new SubstringFunction ((IExpression)$3, (IExpression)$5, (IExpression)$7);
|
|
}
|
|
;
|
|
|
|
CalcFunction
|
|
: IIF PAROPEN Expr COMMA Expr COMMA Expr PARCLOSE
|
|
{
|
|
$$ = new IifFunction ((IExpression)$3, (IExpression)$5, (IExpression)$7);
|
|
}
|
|
| ISNULL PAROPEN Expr COMMA Expr PARCLOSE
|
|
{
|
|
$$ = new IsNullFunction ((IExpression)$3, (IExpression)$5);
|
|
}
|
|
| LEN PAROPEN Expr PARCLOSE
|
|
{
|
|
$$ = new LenFunction ((IExpression)$3);
|
|
}
|
|
| CONVERT PAROPEN Expr COMMA TypeSpecifier PARCLOSE
|
|
{
|
|
$$ = new ConvertFunction ((IExpression)$3, (string)$5);
|
|
}
|
|
;
|
|
|
|
TypeSpecifier
|
|
: StringLiteral
|
|
| Identifier
|
|
;
|
|
|
|
IsPredicate
|
|
: ArithExpr IS NULL
|
|
{
|
|
$$ = new Comparison (Operation.EQ, (IExpression)$1, new Literal (null));
|
|
}
|
|
| ArithExpr IS NOT NULL
|
|
{
|
|
$$ = new Comparison (Operation.NE, (IExpression)$1, new Literal (null));
|
|
}
|
|
;
|
|
|
|
LikePredicate
|
|
: StringExpr LIKE StringExpr
|
|
{
|
|
$$ = new Like ((IExpression)$1, (IExpression)$3);
|
|
}
|
|
| StringExpr NOT_LIKE StringExpr
|
|
{
|
|
$$ = new Negation (new Like ((IExpression)$1, (IExpression)$3));
|
|
}
|
|
;
|
|
|
|
InPredicate
|
|
: ArithExpr IN InPredicateValue
|
|
{
|
|
$$ = new In ((IExpression)$1, (IList)$3);
|
|
}
|
|
| ArithExpr NOT_IN InPredicateValue
|
|
{
|
|
$$ = new Negation (new In ((IExpression)$1, (IList)$3));
|
|
}
|
|
;
|
|
|
|
InPredicateValue
|
|
: PAROPEN InValueList PARCLOSE { $$ = $2; }
|
|
;
|
|
|
|
InValueList
|
|
: LiteralValue
|
|
{
|
|
$$ = new ArrayList();
|
|
((IList)$$).Add ($1);
|
|
}
|
|
| InValueList COMMA LiteralValue
|
|
{
|
|
((IList)($$ = $1)).Add ($3);
|
|
}
|
|
;
|
|
|
|
%%
|
|
}
|