/* Context-free grammar for Doctrine Query Language * * Document syntax: * - non-terminals begin with an upper case character * - terminals begin with a lower case character * - parentheses (...) are used for grouping * - square brackets [...] are used for defining an optional part, eg. zero or * one time * - curly brackets {...} are used for repetion, eg. zero or more times * - double quotation marks "..." define a terminal string * - a vertical bar | represents an alternative * * At a first glance we'll support SQL-99 based queries * Initially Select and Sub-select DQL will not support LIMIT and OFFSET (due to limit-subquery algorithm) */ /* * TERMINALS * * identifier (name, email, ...) * string ('foo', 'bar''s house', '%ninja%', ...) * char ('/', '\\', ' ', ...) * integer (-1, 0, 1, 34, ...) * float (-0.23, 0.007, 1.245342E+8, ...) * boolean (false, true) */ /* * QUERY LANGUAGE (START) */ QueryLanguage ::= SelectStatement | UpdateStatement | DeleteStatement /* * STATEMENTS */ SelectStatement ::= SelectClause FromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause] UpdateStatement ::= UpdateClause [WhereClause] DeleteStatement ::= DeleteClause [WhereClause] /* * IDENTIFIERS */ /* Alias Identification usage */ IdentificationVariable ::= identifier /* Alias Identification declaration */ AliasIdentificationVariable :: = identifier /* identifier that must be a class name */ AbstractSchemaName ::= identifier /* identifier that must be a field */ FieldIdentificationVariable ::= identifier /* identifier that must be a collection-valued association field (to-many) */ CollectionValuedAssociationField ::= FieldIdentificationVariable /* identifier that must be a single-valued association field (to-one) */ SingleValuedAssociationField ::= FieldIdentificationVariable /* identifier that must be an embedded class state field (for the future) */ EmbeddedClassStateField ::= FieldIdentificationVariable /* identifier that must be a simple state field (name, email, ...) */ SimpleStateField ::= FieldIdentificationVariable /* * PATH EXPRESSIONS */ JoinAssociationPathExpression ::= JoinCollectionValuedPathExpression | JoinSingleValuedAssociationPathExpression JoinCollectionValuedPathExpression ::= IdentificationVariable "." CollectionValuedAssociationField JoinSingleValuedAssociationPathExpression ::= IdentificationVariable "." SingleValuedAssociationField AssociationPathExpression ::= CollectionValuedPathExpression | SingleValuedAssociationPathExpression SingleValuedPathExpression ::= StateFieldPathExpression | SingleValuedAssociationPathExpression StateFieldPathExpression ::= SimpleStateFieldPathExpression | SimpleStateFieldAssociationPathExpression SingleValuedAssociationPathExpression ::= IdentificationVariable "." {SingleValuedAssociationField "."}* SingleValuedAssociationField CollectionValuedPathExpression ::= IdentificationVariable "." {SingleValuedAssociationField "."}* CollectionValuedAssociationField StateField ::= {EmbeddedClassStateField "."}* SimpleStateField SimpleStateFieldPathExpression ::= IdentificationVariable "." SimpleStateField SimpleStateFieldAssociationPathExpression ::= SingleValuedAssociationPathExpression "." StateField /* * CLAUSES */ SelectClause ::= "SELECT" ["ALL" | "DISTINCT"] SelectExpression {"," SelectExpression}* SimpleSelectClause ::= "SELECT" ["ALL" | "DISTINCT"] SimpleSelectExpression DeleteClause ::= "DELETE" ["FROM"] AbstractSchemaName [["AS"] AliasIdentificationVariable] WhereClause ::= "WHERE" ConditionalExpression FromClause ::= "FROM" IdentificationVariableDeclaration {"," IdentificationVariableDeclaration}* SubselectFromClause ::= "FROM" SubselectIdentificationVariableDeclaration {"," SubselectIdentificationVariableDeclaration}* HavingClause ::= "HAVING" ConditionalExpression GroupByClause ::= "GROUP" "BY" GroupByItem {"," GroupByItem}* OrderByClause ::= "ORDER" "BY" OrderByItem {"," OrderByItem}* LimitClause ::= "LIMIT" integer OffsetClause ::= "OFFSET" integer UpdateClause ::= "UPDATE" AbstractSchemaName [["AS"] AliasIdentificationVariable] "SET" UpdateItem {"," UpdateItem}* Subselect ::= SimpleSelectClause SubselectFromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause] /* * ITEMS */ OrderByItem ::= StateFieldPathExpression ["ASC" | "DESC"] GroupByItem ::= SingleValuedPathExpression UpdateItem ::= [IdentificationVariable"."]{StateField | SingleValuedAssociationField} "=" NewValue NewValue ::= SimpleArithmeticExpression | StringPrimary | DatetimePrimary | BooleanPrimary | EnumPrimary | SimpleEntityExpression | "NULL" /* * FROM/JOIN/INDEX BY */ IdentificationVariableDeclaration ::= RangeVariableDeclaration [IndexBy] {JoinVariableDeclaration}* SubselectIdentificationVariableDeclaration ::= IdentificationVariableDeclaration | AssociationPathExpression ["AS"] AliasIdentificationVariable JoinVariableDeclaration ::= Join [IndexBy] RangeVariableDeclaration ::= AbstractSchemaName ["AS"] AliasIdentificationVariable Join ::= ["LEFT" ["OUTER"] | "INNER"] "JOIN" JoinAssociationPathExpression ["AS"] AliasIdentificationVariable [("ON" | "WITH") ConditionalExpression] IndexBy ::= "INDEX" "BY" SimpleStateFieldPathExpression /* * SELECT EXPRESSION */ SelectExpression ::= IdentificationVariable ["." "*"] | (StateFieldPathExpression | AggregateExpression | "(" Subselect ")" ) [["AS"] FieldIdentificationVariable] SimpleSelectExpression ::= SingleValuedPathExpression | IdentificationVariable | AggregateExpression /* * CONDITIONAL EXPRESSIONS */ ConditionalExpression ::= ConditionalTerm | ConditionalExpression "OR" ConditionalTerm ConditionalTerm ::= ConditionalFactor | ConditionalTerm "AND" ConditionalFactor ConditionalFactor ::= ["NOT"] ConditionalPrimary ConditionalPrimary ::= SimpleConditionalExpression | "(" ConditionalExpression ")" SimpleConditionalExpression ::= ComparisonExpression | BetweenExpression | LikeExpression | InExpression | NullComparisonExpression | ExistsExpression | EmptyCollectionComparisonExpression | CollectionMemberExpression /* EmptyCollectionComparisonExpression and CollectionMemberExpression are for the future */ /* * COLLECTION EXPRESSIONS (FOR THE FUTURE) */ EmptyCollectionComparisonExpression ::= CollectionValuedPathExpression "IS" ["NOT"] "EMPTY" CollectionMemberExpression ::= EntityExpression ["NOT"] "MEMBER" ["OF"] CollectionValuedPathExpression /* * LITERAL VALUES */ Literal ::= string | char | integer | float | boolean | InputParameter /* * INPUT PARAMETER */ InputParameter ::= PositionalParameter | NamedParameter PositionalParameter ::= "?" integer NamedParameter ::= ":" string /* * ARITHMETIC EXPRESSIONS */ ArithmeticExpression ::= SimpleArithmeticExpression | "(" Subselect ")" SimpleArithmeticExpression ::= ArithmeticTerm | SimpleArithmeticExpression ("+"|"-") ArithmeticTerm ArithmeticTerm ::= ArithmeticFactor | ArithmeticTerm ("*" |"/") ArithmeticFactor ArithmeticFactor ::= [("+" | "-")] ArithmeticPrimary ArithmeticPrimary ::= StateFieldPathExpression | Literal | "(" SimpleArithmeticExpression ")" | Function | AggregateExpression /* * STRING/BOOLEAN/DATE/ENTITY/ENUM EXPRESSIONS */ StringExpression ::= StringPrimary | "(" Subselect ")" StringPrimary ::= StateFieldPathExpression | string | InputParameter | FunctionsReturningStrings | AggregateExpression BooleanExpression ::= BooleanPrimary | "(" Subselect ")" BooleanPrimary ::= StateFieldPathExpression | boolean | InputParameter EnumExpression ::= EnumPrimary | "(" Subselect ")" EnumPrimary ::= StateFieldPathExpression | string | InputParameter EntityExpression ::= SingleValuedAssociationPathExpression | SimpleEntityExpression SimpleEntityExpression ::= IdentificationVariable | InputParameter DatetimeExpression ::= DatetimePrimary | "(" Subselect ")" DatetimePrimary ::= StateFieldPathExpression | InputParameter | FunctionsReturningDatetime | AggregateExpression /* * AGGREGATE EXPRESSION */ AggregateExpression ::= ("AVG" | "MAX" | "MIN" | "SUM") "(" ["DISTINCT"] StateFieldPathExpression ")" | "COUNT" "(" ["DISTINCT"] (IdentificationVariable | SingleValuedAssociationPathExpression | StateFieldPathExpression) ")" /* * QUANTIFIED/BETWEEN/COMPARISON/LIKE/NULL/EXISTS EXPRESSIONS */ QuantifiedExpression ::= ("ALL" | "ANY" | "SOME") "(" Subselect ")" BetweenExpression ::= ArithmeticExpression ["NOT"] "BETWEEN" ArithmeticExpression "AND" ArithmeticExpression ComparisonExpression ::= ArithmeticExpression ComparisonOperator ( QuantifiedExpression | ArithmeticExpression ) | StringExpression ComparisonOperator (StringExpression | QuantifiedExpression) | BooleanExpression ("=" | "<>" | "!=") (BooleanExpression | QuantifiedExpression) | EnumExpression ("=" | "<>" | "!=") (EnumExpression | QuantifiedExpression) | DatetimeExpression ComparisonOperator (DatetimeExpression | QuantifiedExpression) | EntityExpression ("=" | "<>") (EntityExpression | QuantifiedExpression) InExpression ::= StateFieldPathExpression ["NOT"] "IN" "(" (Literal {"," Literal}* | Subselect) ")" LikeExpression ::= ["NOT"] "LIKE" string ["ESCAPE" char] NullComparisonExpression ::= (SingleValuedPathExpression | InputParameter) "IS" ["NOT"] "NULL" ExistsExpression ::= ["NOT"] "EXISTS" "(" Subselect ")" ComparisonOperator ::= "=" | "<" | "<=" | "<>" | ">" | ">=" | "!=" /* * FUNCTIONS */ FunctionsReturningStrings ::= PortableFunctionsReturningStrings | OtherFunctionsReturningStrings FunctionsReturningNumerics ::= PortableFunctionsReturningNumerics | OtherFunctionsReturningNumerics FunctionsReturningDateTime ::= PortableFunctionsReturningDateTime | OtherFunctionsReturningDateTime /* * OTHER FUNCTIONS: List of all allowed (but not portable) functions here. */ OtherFunctionsReturningStrings ::= ... OtherFunctionsReturningNumerics ::= ... OtherFunctionsReturningDateTime ::= ... /* * PORTABLE FUNCTIONS: List all portable functions here * @TODO add all supported portable functions here */ PortableFunctionsReturningNumerics ::= "LENGTH" "(" StringPrimary ")" | "LOCATE" "(" StringPrimary "," StringPrimary ["," SimpleArithmeticExpression]")" | "ABS" "(" SimpleArithmeticExpression ")" | "SQRT" "(" SimpleArithmeticExpression ")" | "MOD" "(" SimpleArithmeticExpression "," SimpleArithmeticExpression ")" | "SIZE" "(" CollectionValuedPathExpression ")" PortableFunctionsReturningDateTime ::= "CURRENT_DATE" | "CURRENT_TIME" | "CURRENT_TIMESTAMP" PortableFunctionsReturningStrings ::= "CONCAT" "(" StringPrimary "," StringPrimary ")" | "SUBSTRING" "(" StringPrimary "," SimpleArithmeticExpression "," SimpleArithmeticExpression ")" | "TRIM" "(" [["LEADING" | "TRAILING" | "BOTH"] [char] "FROM"] StringPrimary ")" | "LOWER" "(" StringPrimary ")" | "UPPER" "(" StringPrimary ")"