/*++

Copyright (C) 1997-2001 Microsoft Corporation

Module Name:

    WQLNODE.H

Abstract:

	WQL Parse Node Definitions 

History:

	raymcc      29-Sep-97       Created

--*/

#ifndef _WQLNODE_H_
#define _WQLNODE_H_


#define  WQL_FLAG_ALIAS          0x1
#define  WQL_FLAG_TABLE          0x2
#define  WQL_FLAG_ASTERISK       0x4
#define  WQL_FLAG_DISTINCT       0x8
#define  WQL_FLAG_ALL            0x10
#define  WQL_FLAG_COUNT          0x20
#define  WQL_FLAG_CONST          0x40
#define  WQL_FLAG_COLUMN         0x80
#define  WQL_FLAG_COMPLEX_NAME   0x100
#define  WQL_FLAG_FUNCTIONIZED   0x200
#define  WQL_FLAG_ARRAY_REF      0x400
#define  WQL_FLAG_UPPER          0x800
#define  WQL_FLAG_LOWER          0x1000
#define  WQL_FLAG_FIRSTROW       0x2000
#define  WQL_FLAG_CONST_RANGE    0x4000
#define  WQL_FLAG_SORT_ASC       0x8000
#define  WQL_FLAG_SORT_DESC      0x10000
#define  WQL_FLAG_AGGREGATE      0x20000
#define  WQL_FLAG_NULL           0x40000

#define WQL_FLAG_INNER_JOIN         1
#define WQL_FLAG_LEFT_OUTER_JOIN    2
#define WQL_FLAG_RIGHT_OUTER_JOIN   3
#define WQL_FLAG_FULL_OUTER_JOIN    4



//***************************************************************************
//
//  SWQLNode
//
//  Base node type for all parser output.
//  
//***************************************************************************

struct SWQLNode
{
    DWORD        m_dwNodeType;
    SWQLNode    *m_pLeft;
    SWQLNode    *m_pRight;

    SWQLNode() { m_pLeft = 0; m_pRight = 0; m_dwNodeType = 0; }
    virtual ~SWQLNode() { delete m_pLeft; delete m_pRight; }
    virtual void DebugDump() = 0;
};


//***************************************************************************
//
//  SWQLTypedConst
//
//  Typed constant container (similar to OA VARIANT).
//  
//***************************************************************************

union UWQLTypedConst
{
    LPWSTR m_pString;       // VT_LPWSTR for WQL_TOK_QSTRING and WQL_TOK_PROMPT
    LONG   m_lValue;        // VT_LONG
    double m_dblValue;      // VT_DOUBLE
    BOOL   m_bValue;        // VT_BOOL, use TRUE/FALSE (not VARIANT_TRUE, VARIANT_FALSE)
};

struct SWQLTypedConst
{
    DWORD m_dwType;             // A VT_ type
    UWQLTypedConst m_Value;     // One of the union fields
    bool m_bPrompt;             // Only true if token was WQL_TOK_PROMPT

    SWQLTypedConst();
    SWQLTypedConst(SWQLTypedConst &Src) { m_dwType = VT_NULL; *this = Src; }
    SWQLTypedConst & operator = (SWQLTypedConst &Src);
   ~SWQLTypedConst() { Empty(); }
    void Empty();
    void DebugDump();
};

struct SWQLConstList
{
    CFlexArray m_aValues;       // ptrs to SWQLTypedConst

    SWQLConstList() {}
    SWQLConstList(SWQLConstList &Src) { *this = Src; }
    SWQLConstList & operator = (SWQLConstList & Src);
   ~SWQLConstList() { Empty(); }
    void Add(SWQLTypedConst *pTC) { m_aValues.Add(pTC); }
    void Empty();
};



struct SWQLQualifiedNameField
{
    LPWSTR  m_pName;         // Name
    BOOL    m_bArrayRef;     // TRUE if this is an array reference
    DWORD   m_dwArrayIndex;  // If <m_bArrayRef == TRUE> this is the array index

    SWQLQualifiedNameField() { m_pName = 0; m_bArrayRef = 0; m_dwArrayIndex = 0; }
    SWQLQualifiedNameField(SWQLQualifiedNameField &Src) { m_pName = 0; *this = Src; } 
    SWQLQualifiedNameField & operator = (SWQLQualifiedNameField &Src);    
   ~SWQLQualifiedNameField() { Empty(); }
    void Empty() { delete [] m_pName; }
};

struct SWQLQualifiedName
{
    CFlexArray m_aFields;       // [0] =  left most, last entry is column

    SWQLQualifiedName() {}
    SWQLQualifiedName(SWQLQualifiedName &Src) { *this = Src; }
    SWQLQualifiedName & operator = (SWQLQualifiedName &Src);    
   ~SWQLQualifiedName() { Empty(); }

    int GetNumNames() { return m_aFields.Size(); }
    
    const LPWSTR GetName(int nIndex) 
    { 
        return (LPWSTR) ((SWQLQualifiedNameField*) m_aFields[nIndex])->m_pName; 
    }

    int Add(SWQLQualifiedNameField *pQN) { return m_aFields.Add(pQN); }
    void Empty();
};



#define WQL_TOK_BASE            100

//***************************************************************************
//
//   SWQLNode_Select
//
//   This is the root of the parse tree or the root of a subselect.
//
//                SWQLNode_Select
//               /               \
//      SWQLNode_TableRefs     SWQLNode_WhereClause
//     /                \      /                   \
//    x                  x    x                     x
//
//***************************************************************************

#define TYPE_SWQLNode_Select        (WQL_TOK_BASE + 1)



struct SWQLNode_Select : SWQLNode
{
    // Left  Node is of type SWQLNode_TableRefs
    // Right Node is of type SWQLNode_WhereClause

    int m_nStPos;
    int m_nEndPos;

    SWQLNode_Select() : m_nStPos(-1), m_nEndPos(-1) { m_dwNodeType = TYPE_SWQLNode_Select; }
    void DebugDump();
};


//***************************************************************************
//
//   SWQLNode_TableRefs
//
//  This contains everything prior to the WHERE clause: the target
//  column list and the FROM clause.
//
//  Also contains the SELECT type, i.e., ALL vs. DISTINCT vs. COUNT.
//
//                SWQLNode_TableRefs
//               /               \
//      SWQLNode_ColumnList     SWQLNode_FromClause
//
//  In all cases, SWQLNode_ColumnList is present.  Note that if the
//  user did a "select *...", then the SWQLNode_ColumnList will only
//  have a single column in it clearly marked as an asterisk.  If
//  a "select count(...) " was done, then m_nSelectType is set to
//  WQL_FLAG_COUNT and the SWQLNode_ColumnList will have a single
//  column in it, whether an * or a qualified name.
//
//***************************************************************************

#define TYPE_SWQLNode_TableRefs      (WQL_TOK_BASE + 2)

struct SWQLNode_TableRefs : SWQLNode
{
    // Left  Node is SWQLNode_ColumnList
    // Right Node is SWQLNode_FromClause

    int m_nSelectType;       // WQL_FLAG_ALL means ALL was used.
                             // WQL_FLAG_DISTINCT means DISTINCT was used.
                             // WQL_FLAG_COUNT means COUNT was used.  

    SWQLNode_TableRefs() 
        { m_nSelectType = WQL_FLAG_ALL; 
          m_dwNodeType = TYPE_SWQLNode_TableRefs;
        }

   ~SWQLNode_TableRefs() {}
    void DebugDump();
};


//***************************************************************************
//
//   SWQLNode_ColumnList
//
//  This contains the selected list of columns.
//
//                SWQLNode_ColumnList
//               /                 \
//              NULL               NULL
//
//***************************************************************************

#define TYPE_SWQLNode_ColumnList   (WQL_TOK_BASE + 3)

struct SWQLNode_ColumnList : SWQLNode
{
    // Left  Node is NULL
    // Right Node is NULL

    CFlexArray m_aColumnRefs ;   // Pointers to SWQLColRef entries.

    SWQLNode_ColumnList() { m_dwNodeType = TYPE_SWQLNode_ColumnList; }
   ~SWQLNode_ColumnList() { Empty(); }
    void Empty();
    void DebugDump();
};


struct SWQLColRef
{
    LPWSTR m_pColName;      // The column name or "*" or NULL
    LPWSTR m_pTableRef;     // The table/alias name or NULL if there is none
    DWORD  m_dwArrayIndex;
    DWORD  m_dwFlags;       // WQL_FLAG_TABLE bit set if m_pTableRef 
                            //   is a table name
                            // WQL_FLAG_ALIAS bit set if m_pTableRef 
                            //   is a table alias
                            // WQL_FLAG_ASTERISK bit set if m_pColName is 
                            //   * (this is faster than to check than a 
                            //   string compare on <m_pColName> for "*".
                            // WQL_FLAG_NULL if the column name was "NULL"
                            // WQL_FLAG_FUNCTIONIZED is set if the column
                            //    is wrapped in a function call.
                            //    The function bits WQL_FLAG_UPPER or
                            //    WQL_FLAG_LOWER will be set.
                            // WQL_FLAG_ARRAY_REF is set if the column
                            //    is an array column, in which case
                            //    m_dwArrayIndex is set to the array offset.
                            // WQL_FLAG_COMPLEX_NAME is set if the name
                            //  is qualified in a deeply nested way,
                            //  which requires examination of the <QName>
                            //  object.  In this case <m_pColName> is
                            //  set to the last name, but m_pTableRef
                            //  is left blank.
                            // WQL_FLAG_SORT_ASC to sort ascending (Order by only)
                            // WQL_FLAG_SORT_DESC to sort descending (Order by only)

    SWQLQualifiedName *m_pQName;    // The full qualified name

    SWQLColRef() { m_pColName = NULL; m_pTableRef = 0; 
        m_dwFlags = 0; m_dwArrayIndex = 0; m_pQName = 0;
        }

   ~SWQLColRef() { delete [] m_pColName; delete [] m_pTableRef; delete m_pQName; }
    void DebugDump();
};



//***************************************************************************
//
//   SWQLNode_FromClause
//
//   The subtree containing the tables selected from and any joins.
//
//                SWQLNode_FromClause
//               /                   \
//             SWQLNode_TableRef      NULL
//          or SWQLNode_Join
//          or SWQLNode_Sql89Join
//
//***************************************************************************

#define TYPE_SWQLNode_FromClause  (WQL_TOK_BASE + 4)

struct SWQLNode_FromClause : SWQLNode
{
    // Left is SWQLNode_TableRef or SWQLNode_Join
    // Right is NULL

    SWQLNode_FromClause() { m_dwNodeType = TYPE_SWQLNode_FromClause; }
   ~SWQLNode_FromClause() {}
    void DebugDump();
};



//***************************************************************************
//
//  SWQLNode_Sql89Join
//  
//  A subtree which expresses a SQL-89 join.
//
//                SWQLNode_Sql89Join
//               /             \
//             NULL             NULL
//
//***************************************************************************

#define TYPE_SWQLNode_Sql89Join     (WQL_TOK_BASE + 5)

struct SWQLNode_Sql89Join : SWQLNode
{
    CFlexArray m_aValues;           // Array of pointers to SWQLNode_TableRef
                                    // objects

    SWQLNode_Sql89Join() { m_dwNodeType = TYPE_SWQLNode_Sql89Join; }
    ~SWQLNode_Sql89Join() {Empty();};
    void DebugDump();
    void Empty();
};



//***************************************************************************
//
//  SWQLNode_Join
//  
//  A subtree which expresses a join.
//
//                SWQLNode_Join
//               /              \
//       SWQLNode_JoinPair       SWQLNode_OnClause or NULL.
//
//***************************************************************************

#define TYPE_SWQLNode_Join  (WQL_TOK_BASE + 6)

struct SWQLNode_Join : SWQLNode
{
    // Left ptr is SWQLNode_JoinPair
    // Right ptr is ON clause.  If NULL, there is no ON clause
    // and the JOIN was a SQL-89 style join with the join condition
    // present in the WHERE clause.  

    DWORD m_dwJoinType;     
            // One of WQL_FLAG_INNER_JOIN, WQL_FLAG_LEFT_OUTER_JOIN, 
            // WQL_FLAG_RIGHT_OUTER_JOIN or WQL_FLAG_FULL_OUTER_JOIN
    DWORD m_dwFlags;
        // Contains WQL_FLAG_FIRSTROW if used

    SWQLNode_Join() { m_dwNodeType = TYPE_SWQLNode_Join; m_dwJoinType = m_dwFlags = 0; }
   ~SWQLNode_Join() {}
    void DebugDump();
};


//***************************************************************************
//
//  SWQLNode_JoinPair
//  
//                SWQLNode_JoinPair
//               /                 \
//        <SWQLNode_Join or SWQLNode_TableRef>
//
//***************************************************************************
#define TYPE_SWQLNode_JoinPair   (WQL_TOK_BASE + 7)

struct SWQLNode_JoinPair : SWQLNode
{
    // Left ptr is SWQLNode_Join or SWQLNode_TableRef
    // Right ptr is SWQLNodeNode_Join or SWQL_NodeTableRef

    SWQLNode_JoinPair() { m_dwNodeType = TYPE_SWQLNode_JoinPair; }
   ~SWQLNode_JoinPair() {}

    void DebugDump();
};



//***************************************************************************
//
//  SWQLNode_TableRef
//  
//  A node representing a table name and its alias, if any.
//
//                SWQLNode_TableRef
//               /                 \
//             NULL               NULL
//
//***************************************************************************

#define TYPE_SWQLNode_TableRef  (WQL_TOK_BASE + 8)

struct SWQLNode_TableRef : SWQLNode
{
    LPWSTR m_pTableName;        // The table
    LPWSTR m_pAlias;            // Table alias. NULL if not used.

    SWQLNode_TableRef() { m_pTableName = 0; m_pAlias = 0; m_dwNodeType = TYPE_SWQLNode_TableRef; }
    ~SWQLNode_TableRef() { delete [] m_pTableName; delete [] m_pAlias; }
    void DebugDump();    
};

//***************************************************************************
//
//  SWQLNode_OnClause
//  
//                SWQLNode_OnClause
//               /                 \
//        <SWQLNode_RelExpr>        NULL
//
//***************************************************************************
#define TYPE_SWQLNode_OnClause   (WQL_TOK_BASE + 9)

struct SWQLNode_OnClause : SWQLNode
{
    // Left ptr is <SWQLNode_RelExpr> which contains the ON clause.
    // Right ptr is always NULL.

    SWQLNode_OnClause() { m_dwNodeType = TYPE_SWQLNode_OnClause; }
   ~SWQLNode_OnClause() {}
    void DebugDump();
};



//***************************************************************************
//
//  SWQLNode_WhereClause
//  
//                SWQLNode_WhereClause
//               /                 \
//        SWQLNode_RelExpr         SWQLNode_WhereOptions or NULL
//        or 
//        NULL if no conditions
//
//***************************************************************************

#define TYPE_SWQLNode_WhereClause  (WQL_TOK_BASE + 10)

struct SWQLNode_WhereClause : SWQLNode
{
    // Left ptr is SWQLNode_RelExpr.
    // Right ptr is SQLNode_QueryOptions or NULL if none

    SWQLNode_WhereClause() { m_dwNodeType = TYPE_SWQLNode_WhereClause; }
   ~SWQLNode_WhereClause() {}

    void DebugDump();
};

//***************************************************************************
//  
//  struct SWQLTypedExpr
//
//  This represents a typed subexpression in a where clause:
//
//      mycol < 2
//      33 <= tbl1.col2
//      tbl3.col4 = tbl4.col5
//      ...etc.
//       
//***************************************************************************

struct SWQLTypedExpr
{
    LPWSTR         m_pTableRef;         // For qualified column names, 
                                        //   NULL if not used
    LPWSTR         m_pColRef;           // Column name

    DWORD          m_dwRelOperator;     // The operator used: WQL_TOK_LE, 
                                        //  WQL_TOK_GE, WQL_TOK_LIKE etc.   
                                        //  WQL_TOK_IN_CONST_LIST
                                        //  WQL_TOK_NOT_IN_CONST_LIST
                                        //  WQL_TOK_IN_SUBSELECT
                                        //  WQL_TOK_NOT_IN_SUBSELECT

    SWQLTypedConst *m_pConstValue;     // A const value 
    SWQLTypedConst *m_pConstValue2;    // The other const value used with BETWEEN

    LPWSTR         m_pJoinTableRef;     // The joined table name or its alias, 
                                        //   NULL if not used
    LPWSTR         m_pJoinColRef;       // The joined column name

    LPWSTR         m_pIntrinsicFuncOnColRef;        
    LPWSTR         m_pIntrinsicFuncOnJoinColRef;
    LPWSTR         m_pIntrinsicFuncOnConstValue;
    
    SWQLNode      *m_pLeftFunction;         // More detail for DATEPART, etc.
    SWQLNode      *m_pRightFunction;        // More detail for DATEPART, etc.

    DWORD          m_dwLeftArrayIndex;
    DWORD          m_dwRightArrayIndex;

    SWQLQualifiedName *m_pQNRight;
    SWQLQualifiedName *m_pQNLeft;

    DWORD          m_dwLeftFlags;
    DWORD          m_dwRightFlags;           
        // Each of the above to Flags shows the expression layout on each side 
        // of the operator.
        //  WQL_FLAG_CONST        = A typed constant was used
        //  WQL_FLAG_COLUMN       = Column field was used
        //  WQL_FLAG_TABLE        = Table/Alias was used
        //  WQL_FLAG_COMPLEX      = Complex qualified name and/or array was used
        //  WQL_FLAG_FUNCTIONIZED = Function was applied over the const or col.


    // For IN and NOT IN clauses.
    // ==========================

    SWQLNode       *m_pSubSelect;

    SWQLConstList  *m_pConstList;   // For IN clause with constant-list
            
    /*
    (1) If a const is tested against a column, then <m_pConstValue> will 
        be used to represent it, and the table+col referenced will be in 
        <m_pTableRef> and <m_pColRef>.

    (2) If a join occurs, then <m_pConstValue> will be NULL.

    (3) Intrinsic functions (primarily UPPER() and LOWER()) can be applied 
        to the column references  or the constant.  The function names will 
        be placed in the <m_pIntrinsic...> pointers when applied.

    (4) If <m_dwRelOperator> is WQL_TOK_IN_CONST_LIST or WQL_TOK_NOT_IN_CONST_LIST
        then <m_aConstSet> is an array of pointers to SWQLTypedConst structs representing
        the set of constants that the referenced column must intersect with.

    (5) If <m_dwRelOperator> is WQL_TOK_IN_SUBSELECT or WQL_TOK_NOT_IN_SUBSELECT
        then m_pSubSelect is a pointer to an embedded subselect tree in the form
        of a SWQLNode_Select struct, beginning the root of an entirely new select
        statement.
    */
        
    SWQLTypedExpr();
   ~SWQLTypedExpr() { Empty(); }
    void DebugDump();
    void Empty();
};



//***************************************************************************
//
//  SWQLNode_RelExpr
//  
//                SWQLNode_RelExpr
//               /                \
//        SWQLNode_RelExpr        SWQLNode_RelExpr
//        or NULL                 or NULL
//
//***************************************************************************

#define TYPE_SWQLNode_RelExpr   (WQL_TOK_BASE + 11)

struct SWQLNode_RelExpr : SWQLNode
{
    DWORD m_dwExprType;  // WQL_TOK_OR
                         // WQL_TOK_AND
                         // WQL_TOK_NOT
                         // WQL_TOK_TYPED_EXPR

    SWQLTypedExpr *m_pTypedExpr; 

    /*
    (1) If the <m_dwExprType> is WQL_TOK_AND or WQL_TOK_OR, then each of 
        the two subnodes are themselves SWQLNode_RelExpr nodes and 
        <m_pTypedExpr> points to NULL.

    (2) If <m_dwExprType> is WQL_TOK_NOT, then <m_pLeft> points to a 
        SWQLNode_RelExpr containing the subclause to which to apply the NOT 
        operation and <m_pRight> points to NULL.

    (3) If <m_dwExprType> is WQL_TOK_TYPED_EXPR, then <m_pLeft> and 
        <m_pRight> both point to NULL, and <m_pTypedExpr> contains a typed 
        relational subexpression.

    (4) Parentheses have been removed and are implied by the nesting.
    */

    SWQLNode_RelExpr() { m_dwNodeType = TYPE_SWQLNode_RelExpr; m_pTypedExpr = 0; m_dwExprType = 0; }
   ~SWQLNode_RelExpr() { delete m_pTypedExpr; }
    void DebugDump();
};



//***************************************************************************
//
//  SWQLNode_WhereOptions
//  
//                SWQLNode_WhereOptions
//               /                 \
//           SWQLNode_GroupBy      SWQLNode_OrderBy
//
//***************************************************************************

#define TYPE_SWQLNode_WhereOptions (WQL_TOK_BASE + 12)

struct SWQLNode_WhereOptions : SWQLNode
{
    // left ptr is SWQLNode_GroupBy, or NULL if not used
    // right ptr is SWQLNode_OrderBy, or NULL if not used    

    SWQLNode_WhereOptions() { m_dwNodeType = TYPE_SWQLNode_WhereOptions; }
    void DebugDump();
};

//***************************************************************************
//
//  SWQLNode_GroupBy
//  
//                SWQLNode_GroupBy
//               /                \
//        SWQLNode_ColumnList    SWQLNode_Having
//                               or NULL
//
//***************************************************************************

#define TYPE_SWQLNode_GroupBy (WQL_TOK_BASE + 13)

struct SWQLNode_GroupBy : SWQLNode
{
    // left ptr is SWQLNode_ColumnList of columns to group by
    // right ptr is Having clause, if any

    SWQLNode_GroupBy() { m_dwNodeType = TYPE_SWQLNode_GroupBy; }
    void DebugDump();
};

//***************************************************************************
//
//  SWQLNode_Having
//  
//                SWQLNode_Having
//               /               \
//           SWQLNode_RelExpr    NULL
//
//***************************************************************************

#define TYPE_SWQLNode_Having (WQL_TOK_BASE + 14)

struct SWQLNode_Having : SWQLNode
{
    // left ptr is SQLNode_RelExpr pointing to HAVING expressions
    // right ptr is NULL

    SWQLNode_Having() { m_dwNodeType = TYPE_SWQLNode_Having; }
    void DebugDump();
};



//***************************************************************************
//
//  SWQLNode_OrderBy
//  
//                SWQLNode_OrderBy
//               /                \
//      SWQLNode_ColumnList       NULL
//
//***************************************************************************

#define TYPE_SWQLNode_OrderBy (WQL_TOK_BASE + 15)

struct SWQLNode_OrderBy : SWQLNode
{
    // left ptr is SWQLNode_ColumnList 
    // right ptr is NULL
    SWQLNode_OrderBy() { m_dwNodeType = TYPE_SWQLNode_OrderBy; }
    void DebugDump();
};

//***************************************************************************
//
//  SWQLNode_Datepart 
//
//  Contains a datepart call.
//
//***************************************************************************
#define TYPE_SWQLNode_Datepart  (WQL_TOK_BASE + 16)

struct SWQLNode_Datepart : SWQLNode
{
    int m_nDatepart;        // One of WQL_TOK_YEAR, WQL_TOK_MONTH, 
                            // WQL_TOK_DAY, WQL_TOK_HOUR, WQL_TOK_MINUTE
                            // WQL_TOK_SECOND

    SWQLColRef *m_pColRef;  // The column to which DATEPART applies
    
    SWQLNode_Datepart() { m_dwNodeType = TYPE_SWQLNode_Datepart; m_nDatepart = 0; }
   ~SWQLNode_Datepart() { delete m_pColRef; }

    void DebugDump();    
};


#endif
