windows-nt/Source/XPSP1/NT/admin/wmi/wbem/winmgmt/wbemcomn/wql.bnf
2020-09-26 16:20:57 +08:00

417 lines
12 KiB
BNF

/////////////////////////////////////////////////////////////////////////////
//
// 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)