|
|
///////////////////////////////////////////////////////////////////////////// // // WQL Version 1.1 for WBEM M6 / SMS Opal. // // This file describes a validated LL(1) grammar for top-down // or recursive descent parsing of WQL. // // raymcc 11-Sep-97 Created // /////////////////////////////////////////////////////////////////////////////
<parse> ::= WQL_TOK_SELECT <select_stmt>;
///////////////////////////////////////////////////////////////////////////// // // SELECT statement // /////////////////////////////////////////////////////////////////////////////
<select_stmt> ::= <select_type> <col_ref_list> <from_clause> <where_clause> ;
<select_type> ::= WQL_TOK_ALL; <select_type> ::= WQL_TOK_DISTINCT; <select_type> ::= <>;
<subselect_stmt> ::= WQL_TOK_SELECT <select_type> <col_ref_list> // Additionally, must be a single col & not an asterisk <from_clause> <where_clause> ;
///////////////////////////////////////////////////////////////////////////// // // Column reference list // // Supports either simple names, *, or qualified names of the form // "table.col" where table could be a literal table name or an aliased // table name. At this point in the parsing, we can't really tell // which one is being used. // // Either * is required, or at least one column reference. // /////////////////////////////////////////////////////////////////////////////
<col_ref_list> ::= <col_ref> <col_ref_rest>; <col_ref_list> ::= WQL_TOK_ASTERISK; <col_ref_list> ::= WQL_TOK_COUNT <count_clause>;
<col_ref_rest> ::= WQL_TOK_COMMA <col_ref_list>; <col_ref_rest> ::= <>;
<count_clause> ::= WQL_TOK_OPEN_PAREN <count_col> WQL_TOK_CLOSE_PAREN; <count_col> ::= WQL_TOK_ASTERISK; <count_col> ::= <col_ref>;
///////////////////////////////////////////////////////////////////////////// // // Column reference // // Used both in the WHERE clause and the COUNT clause // /////////////////////////////////////////////////////////////////////////////
<col_ref> ::= <qualified_name>;
///////////////////////////////////////////////////////////////////////////// // // qualified names // // (dot-separated names with optional array references. // /////////////////////////////////////////////////////////////////////////////
<qualified_name> ::= WQL_TOK_IDENT <qualified_name2>; <qualified_name2> ::= WQL_TOK_DOT WQL_TOK_IDENT <qualified_name2>;
<qualified_name2> ::= WQL_TOK_OPEN_BRACKET WQL_TOK_INT WQL_TOK_CLOSEBRACKET <qname_becomes_array_ref> <qualified_name2>;
<qname_becomes_array_ref> ::= <>; // Dummy to enforce array semantics
<qualified_name2> ::= <>;
///////////////////////////////////////////////////////////////////////////// // // "FROM" clause // // Both SQL-89 and SQL-92 join syntax supported. // /////////////////////////////////////////////////////////////////////////////
<from_clause> ::= WQL_TOK_FROM <table_list>;
<table_list> ::= <single_table_decl> <optional_join>;
<optional_join> ::= <sql89_join_entry>; <optional_join> ::= <sql92_join_entry>;
<optional_join> ::= <>; // Unary query
///////////////////////////////////////////////////////////////////////////// // // Table reference // // This supports a single table reference in a FROM clause, whether // an isolated name, or alias (with or without AS). // /////////////////////////////////////////////////////////////////////////////
<single_table_decl> ::= <unbound_table_ident> <table_decl_rest>;
<unbound_table_ident> ::= WQL_TOK_IDENT; <table_decl_rest> ::= <redundant_as> <table_alias>; <table_decl_rest> ::= <>; <table_alias> ::= WQL_TOK_IDENT;
<redundant_as> ::= WQL_TOK_AS; <redundant_as> ::= <>;
///////////////////////////////////////////////////////////////////////////// // // SQL-89 Joins // /////////////////////////////////////////////////////////////////////////////
<sql89_join_entry> ::= WQL_TOK_COMMA <sql89_join_list>;
<sql89_join_list> ::= <single_table_decl> <sql89_join_rest>;
<sql89_join_rest> ::= WQL_TOK_COMMA <sql89_join_list>; <sql89_join_rest> ::= <>;
///////////////////////////////////////////////////////////////////////////// // // SQL-92 Joins. // // We support: // 1. [INNER] JOIN // 2. LEFT [OUTER] JOIN // 3. RIGHT [OUTER] JOIN // 4. FULL [OUTER] JOIN // /////////////////////////////////////////////////////////////////////////////
<sql92_join_entry> ::= <simple_join_clause>; <sql92_join_entry> ::= WQL_TOK_INNER <simple_join_clause>; <sql92_join_entry> ::= WQL_TOK_FULL <opt_outer> <simple_join_clause>; <sql92_join_entry> ::= WQL_TOK_LEFT <opt_outer> <simple_join_clause>; <sql92_join_entry> ::= WQL_TOK_RIGHT <opt_outer> <simple_join_clause>;
<opt_outer> ::= WQL_TOK_OUTER; <opt_outer> ::= <>;
<simple_join_clause> ::= WQL_TOK_JOIN <single_table_decl> <on_clause> <sql92_join_continuator> ;
<on_clause> ::= WQL_TOK_ON <rel_expr>;
<sql92_join_continuator> ::= <sql92_join_entry>; <sql92_join_continuator> ::= <>;
///////////////////////////////////////////////////////////////////////////// // // "WHERE" clause // /////////////////////////////////////////////////////////////////////////////
<where_clause> ::= WQL_TOK_WHERE <rel_expr> <where_options>; <where_clause> ::= <>; // 'where' is not required
///////////////////////////////////////////////////////////////////////////// // // WHERE OPTIONS // // We currently force the GROUP BY to precede ORDER BY if they are both // present. If this causes a problem, we can fix it by using an // iterative construct below and doing the checking in the parser itself // as a semantic operation. // /////////////////////////////////////////////////////////////////////////////
<where_options> ::= <group_by_clause> <order_by_clause> ;
<group_by_clause> ::= WQL_TOK_GROUP WQL_TOK_BY <col_list> <having_clause>; <group_by_clause> ::= <>;
<having_clause> ::= WQL_TOK_HAVING <rel_expr>; <having_clause> ::= <>;
<order_by_clause> ::= WQL_TOK_ORDER WQL_TOK_BY <col_list>; <order_by_clause> ::= <>;
///////////////////////////////////////////////////////////////////////////// // // Simple column list with no asterisk // /////////////////////////////////////////////////////////////////////////////
<col_list> ::= <col_ref> <col_list_rest>; <col_list_rest> ::= WQL_TOK_COMMA <col_ref> <col_list_rest>; <col_list_rest> ::= <>;
///////////////////////////////////////////////////////////////////////////// // // Relational expressions // // These set out the precedence of typed expressions relative to the // NOT, AND, OR and parentheses operators. // /////////////////////////////////////////////////////////////////////////////
<rel_expr> ::= <rel_term> <rel_expr2>; <rel_expr2> ::= WQL_TOK_OR <rel_term> <rel_expr2>; <rel_expr2> ::= <>;
<rel_term> ::= <rel_simple_expr> <rel_term2>; <rel_term2> ::= WQL_TOK_AND <rel_simple_expr> <rel_term2>; <rel_term2> ::= <>;
<rel_simple_expr> ::= WQL_TOK_NOT <rel_expr>; <rel_simple_expr> ::= WQL_TOK_OPEN_PAREN <rel_expr> WQL_TOK_CLOSE_PAREN; <rel_simple_expr> ::= <typed_expr>;
///////////////////////////////////////////////////////////////////////////// // // Typed expression // // This is the lower level expression which requires a relational // operator. Many of these combined constitute a relational expression. // /////////////////////////////////////////////////////////////////////////////
<typed_expr> ::= <typed_subexpr> <rel_op> <typed_subexpr_rh>;
<typed_subexpr> ::= <function_call>; <typed_subexpr> ::= <typed_const>; <typed_subexpr> ::= <col_ref>;
<typed_subexpr_rh> ::= <function_call>; <typed_subexpr_rh> ::= <typed_const>; <typed_subexpr_rh> ::= <col_ref>;
<typed_subexpr_rh> ::= <in_clause>; // Operator must be _IN or _NOT_IN
///////////////////////////////////////////////////////////////////////////// // // Function calls // // Each of the recognized functions is part of the grammar. // /////////////////////////////////////////////////////////////////////////////
<function_call> ::= WQL_TOK_UPPER <function_call_parms>; <function_call> ::= WQL_TOK_LOWER <function_call_parms>; <function_call> ::= WQL_TOK_DATEPART <datepart_call>; <function_call> ::= WQL_TOK_QUALIFIER <function_call_parms>; <function_call> ::= WQL_TOK_ISNULL <function_call_parms>;
<function_call_parms> ::= WQL_TOK_OPEN_PAREN <func_args> WQL_TOK_CLOSE_PAREN ;
<func_args> ::= <func_arg> <func_arg_list>; <func_arg_list> ::= WQL_TOK_COMMA <func_arg> <func_arg_list>; <func_arg_list> ::= <>;
<func_arg> ::= <typed_const>; <func_arg> ::= <col_ref>;
///////////////////////////////////////////////////////////////////////////// // // IN clause // // We support three syntax branches: // (a) IN with subselect // (b) IN with const-list // (c) IN with qualified name which is an array reference // /////////////////////////////////////////////////////////////////////////////
<in_clause> ::= WQL_TOK_OPEN_PAREN <in_type> WQL_TOK_CLOSE_PAREN; <in_type> ::= <subselect_stmt>; <in_type> ::= <const_list>; <in_type> ::= <qualified_name>;
///////////////////////////////////////////////////////////////////////////// // // Comma-separated list of constants // /////////////////////////////////////////////////////////////////////////////
<const_list> ::= <typed_const> <const_list2>; <const_list2> ::= WQL_TOK_COMMA <typed_const> <const_list2>; <const_list2> ::= <>;
///////////////////////////////////////////////////////////////////////////// // // Primary relational operator terminals // Some branching with continuators occurs for IS, IN, and NOT. // /////////////////////////////////////////////////////////////////////////////
<rel_op> ::= WQL_TOK_LE; <rel_op> ::= WQL_TOK_LT; <rel_op> ::= WQL_TOK_GE; <rel_op> ::= WQL_TOK_GT; <rel_op> ::= WQL_TOK_EQ; <rel_op> ::= WQL_TOK_NE; <rel_op> ::= WQL_TOK_LIKE; <rel_op> ::= WQL_TOK_BETWEEN; <rel_op> ::= WQL_TOK_IS <is_continuator>; <rel_op> ::= WQL_TOK_ISA; <rel_op> ::= WQL_TOK_IN; <rel_op> ::= WQL_TOK_NOT <not_continuator>;
///////////////////////////////////////////////////////////////////////////// // // Tokens which can follow IS // /////////////////////////////////////////////////////////////////////////////
<is_continuator> ::= WQL_TOK_LIKE; <is_continuator> ::= WQL_TOK_BEFORE; <is_continuator> ::= WQL_TOK_AFTER; <is_continuator> ::= WQL_TOK_BETWEEN; <is_continuator> ::= WQL_TOK_NULL; <is_continuator> ::= WQL_TOK_NOT <not_continuator>; <is_continuator> ::= WQL_TOK_IN; <is_continuator> ::= WQL_TOK_A;
///////////////////////////////////////////////////////////////////////////// // // Tokens which can follow NOT // /////////////////////////////////////////////////////////////////////////////
<not_continuator> ::= WQL_TOK_LIKE; <not_continuator> ::= WQL_TOK_BEFORE; <not_continuator> ::= WQL_TOK_AFTER; <not_continuator> ::= WQL_TOK_BETWEEN; <not_continuator> ::= WQL_TOK_NULL; <not_continuator> ::= WQL_TOK_IN; <not_continuator> ::= WQL_TOK_A;
///////////////////////////////////////////////////////////////////////////// // // Typed constants (literals) // /////////////////////////////////////////////////////////////////////////////
<typed_const> ::= WQL_TOK_QSTRING; <typed_const> ::= WQL_TOK_INT; <typed_const> ::= WQL_TOK_REAL; <typed_const> ::= WQL_TOK_NULL;
///////////////////////////////////////////////////////////////////////////// // // Transact-SQL plagiarism: Datepart // // datepart(ident, col) // /////////////////////////////////////////////////////////////////////////////
<datepart_call> ::= WQL_TOK_OPEN_PAREN WQL_TOK_IDENT // yy, mm,dd, hh, mm, ss, year, month, etc. WQL_TOK_COMMA <col_ref> WQL_TOK_CLOSE_PAREN ;
// RAIX xxxx: Ensure that lexer returns single quoted strings as valid, and recognizes escapes // RAID 3716: Syntax to reference a qualifier; promised to do this // qualifier(prop, "MyQual") = 'xxx' qualifier("MyQual") = 'const' // RAID xxxx : Hex constants // // Intrinsic function applied to columns in "select a, func(b), c from d where..." // Use of qualified asterisks "select t1.*, t2.*, t3.x from ..." // // BETWEEN needs to be supported *correctly* // Unexpected Features: (1) subselects in IN, (2) DatePart (required new approach to functions // because of the keyword problem, (3) functionized col-refs, (4) COUNT(col-name) as opposed // to COUNT(*), (5)
|