All Downloads are FREE. Search and download functionalities are using the official Maven repository.

javacc-7.0.4.grammars.PlSql.jj Maven / Gradle / Ivy

The newest version!
/** A grammar for Oracle's PL/SQL.

HISTORY:
    30-JUL-2006 John Kristian 
        Upgraded to PL/SQL for Oracle 9.2.
        Added code to gather table and procedure names.
        This version doesn't support the entire PL/SQL language,
        merely the subset that's used with my database.

    07-APR-1997 Ramanathan .S 
         grammar for PLSQL inside Oracle*Forms 4.5 (i.e. PlSql 1.x)
*/

options{
    STATIC=false ;
    IGNORE_CASE=true ;
//  DEBUG_LOOKAHEAD= true ;
}

PARSER_BEGIN(PlSql)
package netflix.db.stats;

import java.io.Reader;
import java.io.FileInputStream;
import java.util.HashSet;
import java.util.Set;

class PlSql {

    /** Parse PL/SQL from files.  Each arg is expected to be the name of a file,
        or "-" to indicate System.in.
     */
    public static void main( String args[] ) throws Throwable {
        if (args.length < 1) {
            args = new String[] {"-"};
        }
        for (int a = 0; a < args.length; ++a) {
            final String input = args[a];
            final PlSql parser = new PlSql("-".equals(input) ? System.in : new FileInputStream(input));
            try {
                parser.CompilationUnit();
            } catch(Throwable t) {
            	System.err.println(input + ":1: not parsed");
            	t.printStackTrace();
            }
            System.out.println(parser.tables.size() + " tables in " + input);
        }
    }

    public Set functions = new HashSet();
    public Set procedures = new HashSet();
    public Set tables = new HashSet();

    public void reInit(Reader input) {
        ReInit(input);
        functions.clear();
        procedures.clear();
        tables.clear();
    }

    private String lastObjectReference = null;

    protected boolean seeTYPE() {
        return "TYPE".equalsIgnoreCase(getToken(1).image);
    }

    protected static final Set ANALYTIC_FUNCTION_NAMES = new HashSet();
    static {
        ANALYTIC_FUNCTION_NAMES.add("AVG");
        ANALYTIC_FUNCTION_NAMES.add("CORR");
        ANALYTIC_FUNCTION_NAMES.add("COVAR_POP");
        ANALYTIC_FUNCTION_NAMES.add("COVAR_SAMP");
        ANALYTIC_FUNCTION_NAMES.add("COUNT");
        ANALYTIC_FUNCTION_NAMES.add("CUME_DIST");
        ANALYTIC_FUNCTION_NAMES.add("DENSE_RANK");
        ANALYTIC_FUNCTION_NAMES.add("FIRST");
        ANALYTIC_FUNCTION_NAMES.add("FIRST_VALUE");
        ANALYTIC_FUNCTION_NAMES.add("LAG");
        ANALYTIC_FUNCTION_NAMES.add("LAST");
        ANALYTIC_FUNCTION_NAMES.add("LAST_VALUE");
        ANALYTIC_FUNCTION_NAMES.add("LEAD");
        ANALYTIC_FUNCTION_NAMES.add("MAX");
        ANALYTIC_FUNCTION_NAMES.add("MIN");
        ANALYTIC_FUNCTION_NAMES.add("NTILE");
        ANALYTIC_FUNCTION_NAMES.add("PERCENT_RANK");
        ANALYTIC_FUNCTION_NAMES.add("PERCENTILE_CONT");
        ANALYTIC_FUNCTION_NAMES.add("PERCENTILE_DISC");
        ANALYTIC_FUNCTION_NAMES.add("RANK");
        ANALYTIC_FUNCTION_NAMES.add("RATIO_TO_REPORT");
        ANALYTIC_FUNCTION_NAMES.add("REGR_SLOPE");
        ANALYTIC_FUNCTION_NAMES.add("REGR_INTERCEPT");
        ANALYTIC_FUNCTION_NAMES.add("REGR_COUNT");
        ANALYTIC_FUNCTION_NAMES.add("REGR_R2");
        ANALYTIC_FUNCTION_NAMES.add("REGR_AVGX");
        ANALYTIC_FUNCTION_NAMES.add("REGR_AVGY");
        ANALYTIC_FUNCTION_NAMES.add("REGR_SXX");
        ANALYTIC_FUNCTION_NAMES.add("REGR_SYY");
        ANALYTIC_FUNCTION_NAMES.add("REGR_SXY");
        ANALYTIC_FUNCTION_NAMES.add("ROW_NUMBER");
        ANALYTIC_FUNCTION_NAMES.add("STDDEV");
        ANALYTIC_FUNCTION_NAMES.add("STDDEV_POP");
        ANALYTIC_FUNCTION_NAMES.add("STDDEV_SAMP");
        ANALYTIC_FUNCTION_NAMES.add("SUM");
        ANALYTIC_FUNCTION_NAMES.add("VAR_POP");
        ANALYTIC_FUNCTION_NAMES.add("VAR_SAMP");
        ANALYTIC_FUNCTION_NAMES.add("VARIANCE");
    }

    protected boolean seeAnalyticFunction() {
        return "(".equals(getToken(2).image)
            && ANALYTIC_FUNCTION_NAMES.contains(getToken(1).image.toUpperCase());
    }

}
PARSER_END(PlSql)


SKIP:
{
    " "
|   "\t"
|   "\r"
|   "\n"
}

/* Prefix      Meaning
    -------------------
    K_          Keyword
    O_          Operator
    S_          Substitutes
*/

TOKEN: /* SQL and PLSQL Keywords. prefixed with K_ to avoid name clashes */
{
    
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   
}

TOKEN : /* Numeric Constants */
{
	< S_NUMBER: 
	    |  ( ["e","E"] ([ "-","+"])?  )?
    	>
  | 	< #FLOAT: 
	    |  ( "."  )?
	    | "." 
    	>
  | 	< #INTEGER: (  )+ >
  | 	< #DIGIT: ["0" - "9"] >
}

SPECIAL_TOKEN:
{
   
|  
}


TOKEN:
{
    < S_IDENTIFIER: ()+ ( |  |)* >
  | < #LETTER: ["a"-"z", "A"-"Z"] >
  | < #SPECIAL_CHARS: "$" | "_" | "#">
  | < S_BIND: ":" (  |  ("." )?) >
  | < S_CHAR_LITERAL: "'" (~["'"])* "'" ("'" (~["'"])* "'")*>
  | < S_QUOTED_IDENTIFIER: "\"" (~["\n","\r","\""])* "\"" >
}

/* Represents a PLSQL code block. */
void CompilationUnit():
{}
{
    ProcedureDeclaration()
  | FunctionDeclaration()
  | SequenceOfStatements()
  | AlterSession()
  | "CALL" ProcedureCall()
}

void BindVariable():
{}
{
    
  | ":" ( |  ["." ])
}

void AlterSession():
{}
{
    "ALTER" ID("SESSION") "SET"
    ( "=" ( | LOOKAHEAD({getToken(1).image.matches("(?i)TRUE|FALSE")}) ))*
    ["COMMENT" "=" ]
}

void DeclarationSection():
{}
{
    "DECLARE" Declarations()
}

void Declarations():
{}
{
    ( ( LOOKAHEAD({seeTYPE()}) ID("TYPE")  "IS" TypeDefinition()
      | CursorDeclaration()
      | PragmaDeclaration()
      | IdentifierDeclaration()
      )
      ";"
    )+
    ( LOOKAHEAD({!seeTYPE()}) ProcedureDeclaration()
    | LOOKAHEAD({!seeTYPE()}) FunctionDeclaration()
    )*
}

void IdentifierDeclaration():
{}
{
    

    ( ConstantDeclaration()
      |
      VariableDeclaration()
      |
      ExceptionDeclaration()
    )
}

void CursorDeclaration():
{}
{
   "CURSOR"  ["(" ParameterList() ")" ]
        "IS" SelectStatement()
}

void PragmaDeclaration():
{}
{
    "PRAGMA" "EXCEPTION_INIT" "(" NumOrID() "," NumOrID() ")"
}

void ProcedureDeclaration():
{}
{
    "PROCEDURE"  [ "(" ParameterList() ")" ]
    ( ";"  // Procedure Specification
      |
      "IS" ProcedureBody()
    )
}

void ProcedureBody():
{}
{
    [ Declarations() ]
    BeginEndBlock()
}

void FunctionDeclaration():
{}
{
    "FUNCTION"  [ "(" ParameterList() ")" ]
    "RETURN" TypeDefinition()
    ( ";" // FunctionSpecification
      |
      "IS" FunctionBody()
    )
}

void FunctionBody():
{}
{
    [ Declarations() ]
    BeginEndBlock()
}

void VariableDeclaration():
{}
{
    TypeDefinition() [ "NOT" "NULL" ]
                        [ (":=" | "DEFAULT" ) PlSqlExpression() ]
}

void ConstantDeclaration():
{}
{
    "CONSTANT" TypeDefinition() [ "NOT" "NULL" ]
                        (":=" | "DEFAULT" ) PlSqlExpression()
}

void TypeDefinition():
{}
{
    BasicDataTypeDefinition()
    |
    "TABLE" "OF" TypeDefinition() [LOOKAHEAD(2) "INDEX" "BY" BasicDataTypeDefinition()]
    |
    LOOKAHEAD(2) ( ("%TYPE" | "%ROWTYPE"))
    |
    LOOKAHEAD(TableColumn() "%TYPE")TableColumn()"%TYPE"
    |
      // For Alert declarations etc, in Forms
}



void BasicDataTypeDefinition():
{}
{
    (       "CHAR"
        |   "VARCHAR"
        |   "VARCHAR2"
        |   "INTEGER"
        |   "NUMBER"
        |   "NATURAL"
        |   "REAL"
        |   "FLOAT"
    ) [ "("  [ ","  ] ")" ]

    |   "DATE"
    |   "BINARY_INTEGER"
    |   "BOOLEAN"
}


void ExceptionDeclaration():
{}
{
    "EXCEPTION"
}

/* ---------------- DECLARATIONS SECTION ends here ------------------ */

/* ---------------- Code Section starts here ---------------------- */
                                
void BeginEndBlock():
{}
{
    "BEGIN"
    SequenceOfStatements()
    [ ExceptionBlock()]
    "END" [] ";"
}

void SequenceOfStatements():
{}
{
    (PLSQLStatement())+
}

void ExceptionBlock():
{}
{
    "EXCEPTION"
    (ExceptionHandler())+
}

void ExceptionHandler():
{}
{
    "WHEN" (  ("OR" )*
             // "OTHERS" is treated as an identifier.
             // Making "OTHERS" a keyword causes problems; for example,
             // a reference to a column named "OTHERS" won't be parsed.
           )
    "THEN" SequenceOfStatements()
}

void PLSQLStatement():
{}
{
    ExitStatement()
    |
    GotoStatement()
    |
    IfStatement()
    |
    LabelDeclaration()
    |
    LoopStatement()
    |
    NullStatement()
    |
    RaiseStatement()
    |
    ReturnStatement()
    |
    ForallStatement()
    |
    SQLStatement()
    |
    [DeclarationSection()] BeginEndBlock()
    |
    LOOKAHEAD(DataItem() ":=") AssignmentStatement()
    |
    LOOKAHEAD(ProcedureCall()) ProcedureCall()
}

void LabelDeclaration():
{}
{
    "<<"  ">>"
}

void ForallStatement():
{}
{
    "FORALL"  "IN" PlSqlSimpleExpression() ".." PlSqlSimpleExpression()
    ( InsertStatement() | UpdateStatement() | DeleteStatement())
}

void SQLStatement():
{}
{
    CloseStatement()
    |
    CommitStatement()
    |
    DeleteStatement()
    |
    FetchStatement()
    |
    InsertStatement()
    |
    LockTableStatement()
    |
    OpenStatement()
    |
    RollbackStatement()
    |
    SavepointStatement()
    |
    QueryStatement()
    |
    SetStatement()
    |
    UpdateStatement()
    |
    MergeStatement()
}

void ProcedureCall():
{}
{
    ProcedureReference() [ "(" [ Arguments() ] ")" ] ";"
}

void ProcedureReference():
{
    String name;
}
{
    name = ObjectReference()
    {procedures.add(name.toUpperCase());}
}

void AssignmentStatement():
{}
{
    DataItem() ":=" PlSqlExpression() ";"
}


void ExitStatement():
{}
{
    "EXIT" [ ] ["WHEN" PlSqlExpression()] ";"
}

void GotoStatement():
{}
{
    "GOTO"  ";"
}

void IfStatement():
{}
{
    "IF" PlSqlExpression()
    "THEN"
          SequenceOfStatements()
    ("ELSIF" PlSqlExpression()
     "THEN"
             SequenceOfStatements()
    )*
    ["ELSE"
            SequenceOfStatements()
    ]
    "END" "IF" [] ";"
}

void LoopStatement():
{}
{
    NormalLoop()
    |
    WhileLoop()
    |
    ForLoop()
}

void NormalLoop():
{}
{
    "LOOP"
        SequenceOfStatements()
    "END" "LOOP" [] ";"
}

void WhileLoop():
{}
{
    "WHILE"  PlSqlExpression()
     NormalLoop()
}

void ForLoop():
{}
{
    LOOKAHEAD(NumericForLoopLookahead())
    NumericForLoop()
    |
    CursorForLoop()
}

void NumericForLoopLookahead():
{}
{
    "FOR"  "IN" ["REVERSE"]
          PlSqlSimpleExpression() ".."
}

void NumericForLoop():
{}
{
    "FOR"  "IN" ["REVERSE"]
          PlSqlSimpleExpression() ".." PlSqlSimpleExpression()
    NormalLoop()

}

void CursorForLoop():
{}
{
  "FOR"  "IN" ( CursorReference() [ "(" Arguments() ")"]
                              | "(" SelectStatement() ")"
                            )
  NormalLoop()
}

void CursorReference():
{}
{
    ObjectReference()
}

void NullStatement():
{}
{
    "NULL" ";"
}

void RaiseStatement():
{}
{
    "RAISE" [] ";"
}


void ReturnStatement():
{}
{
    "RETURN" [ PlSqlExpression() ] ";"
}


void CloseStatement():
{}
{
    "CLOSE"  ";"
}

void CommitStatement():
{}
{
    "COMMIT" ["WORK"] ["COMMENT" ] ";"
}

void FetchStatement():
{}
{
    "FETCH" ()
    ( "INTO" ( | BindVariable()) ("," ( | BindVariable()))*
    | LOOKAHEAD(3) ID("BULK") ID("COLLECT") "INTO"
        ( | ":" ) ("," ( | ":" ))*
        [LOOKAHEAD(2) ID("LIMIT") PlSqlSimpleExpression()]
    ) ";"
}

void LockTableStatement():
{}
{
    "LOCK" "TABLE" TableName() ("," TableName())*
    "IN" LockMode() ID("MODE") ["NOWAIT"] ";"
}

void OpenStatement():
{}
{
    "OPEN" CursorReference() ["(" Arguments() ")"] ";"
}

void RollbackStatement():
{}
{
    "ROLLBACK" ["WORK"] ["TO" ["SAVEPOINT"] ]
    ["COMMENT" ] ";"
}

void SetStatement():
{}
{
    "SET"
      ("TRANSACTION" (  "READ" ("ONLY" | "WRITE")
                      | "ISOLATION" ID("LEVEL") ("SERIALIZABLE" | "READ" ID("COMMITTED"))
                      | "USE" "ROLLBACK" ID("SEGMENT") ObjectReference())
       | ("CONSTRAINT" | "CONSTRAINTS") ("ALL" |  ("," )*)
         [LOOKAHEAD({getToken(1).image.matches("(?i)IMMEDIATE|DEFERRED")}) ]
      )
    ";"
}

void LockMode():
{}
{
    ("ROW" ("SHARE" | "EXCLUSIVE"))
  | ("SHARE" ["UPDATE" | ("ROW" "EXCLUSIVE")])
  | ("EXCLUSIVE")
}

void SavepointStatement():
{}
{
    "SAVEPOINT"  ";"
}

void UpdateStatement():
{}
{
    "UPDATE" (TableName() | "(" SubQuery() ")") [OracleObjectName()]
    "SET" ColumnValues()
    ["WHERE" (SQLExpression() | "CURRENT" "OF" )]
    [ReturningClause()]
    ";"
}

void ReturningClause():
{}
{
    "RETURNING" SQLExpression() ("," SQLExpression())* IntoClause()
}

void ColumnValues():
{}
{
    ColumnValue() ("," ColumnValue())*
  | "(" TableColumn() ("," TableColumn())* ")" "=" "(" SelectStatement() ")"
}

void ColumnValue():
{}
{
    TableColumn() "=" PlSqlExpression()
}

void InsertStatement():
{}
{
    "INSERT" "INTO" TableName() [OracleObjectName()]
     [ LOOKAHEAD(2) "(" TableColumn() ("," TableColumn())* ")" ]
    ( "VALUES" "(" PlSqlExpressionList() ")" [ReturningClause()]
      | SubQuery()
    )
    ";"
}

void MergeStatement():
{}
{
    "MERGE" "INTO" TableReference()
    "USING" TableReference() "ON" "(" SQLExpression() ")"
    "WHEN" ID("MATCHED") "THEN"
        "UPDATE" "SET" MergeSetColumn() ("," MergeSetColumn())*
    "WHEN" "NOT" ID("MATCHED") "THEN"
        "INSERT" "(" TableColumn() ("," TableColumn())* ")"
        "VALUES" "(" ("DEFAULT" | SQLExpressionList()) ")"
    ";"
}

void MergeSetColumn():
{}
{
    TableColumn() "=" ("DEFAULT" | SQLExpression())
}

void DeleteStatement():
{}
{
    "DELETE" ["FROM"] TableName() [OracleObjectName()]
    ["WHERE" (SQLExpression() | "CURRENT" "OF"  ) ] ";"
}

void QueryStatement():
{}
{
    SelectStatement()
    ";"
}

// PLSQL Expression and it's childs

void PlSqlExpression():
{}
{
    PlSqlAndExpression() ("OR" PlSqlAndExpression())*
}

void PlSqlAndExpression():
{}
{
    PlSqlUnaryLogicalExpression() ( "AND" PlSqlUnaryLogicalExpression())*
}

void PlSqlUnaryLogicalExpression():
{}
{
  ["NOT"] PlSqlRelationalExpression()
}

void PlSqlRelationalExpression():
{}
{
    PlSqlSimpleExpression()

    ( Relop() PlSqlSimpleExpression()
      |
      LOOKAHEAD(2) PlSqlInClause()
      |
      LOOKAHEAD(2) PlSqlBetweenClause()
      |
      LOOKAHEAD(2) PlSqlLikeClause()
      |
      IsNullClause()
   )?
}

void PlSqlExpressionList():
{}
{
    PlSqlExpression() ("," PlSqlExpression())*
}

void PlSqlInClause():
{}
{
    ["NOT"] "IN" "(" PlSqlExpressionList()")"
}

void PlSqlBetweenClause():
{}
{
    ["NOT"] "BETWEEN" PlSqlSimpleExpression() "AND" PlSqlSimpleExpression()
}

void PlSqlLikeClause():
{}
{
    ["NOT"] "LIKE" PlSqlSimpleExpression() ["ESCAPE" PlSqlSimpleExpression()]
}

void IsNullClause():
{}
{
    "IS" ["NOT"] "NULL"
}


void PlSqlSimpleExpression():
{}
{
    PlSqlMultiplicativeExpression() ( ("+" | "-" | "||")
                                 PlSqlMultiplicativeExpression()
                               )*
}


void PlSqlMultiplicativeExpression():
{}
{
    PlSqlExponentExpression() ( LOOKAHEAD(1) ("*" | "/" | ID("MOD")) PlSqlExponentExpression())*
}

void PlSqlExponentExpression():
{}
{
    PlSqlUnaryExpression() ( "**" PlSqlUnaryExpression())*
}

void PlSqlUnaryExpression():
{}
{
    (("+" | "-") PlSqlPrimaryExpression())
|
    PlSqlPrimaryExpression()
}


void PlSqlPrimaryExpression():
{}
{
    
  | 
  | "NULL"
  | SQLCaseExpression()
  | "(" (LOOKAHEAD(3) SelectStatement() | PlSqlExpression()) ")"
  | BindVariable()
  | LOOKAHEAD(2) SQLCastExpression()
  | LOOKAHEAD(IntervalExpression()) IntervalExpression()
  | LOOKAHEAD(2) ( | "SQL") "%" ID("FOUND|NOTFOUND|ISOPEN|ROWCOUNT")
  | LOOKAHEAD(FunctionReference() "(") FunctionCall()
  | ObjectReference() // Might be a call to a parameter-less function.
}

/* ----------------------- PLSQL Code Block Ends here -------------- */

/* ---------------- General Productions --------------------- */

void TableColumn():
{}
{
    ObjectReference()
}

String OracleObjectName():
{}
{
            {return token.image;}
  |  {String s = token.image; return s.substring(1, s.length() - 1);}
}

String TNSName():
{
    StringBuilder name = new StringBuilder();
}
{
          {name.append(token.image);}
    ("."  {name.append(".").append(token.image);} )*
    {return name.toString();}
}

void Relop():
{}
{
    "="
  | "!" "="
  | "#"
  | LOOKAHEAD(2) ">" "="
  | ">"
  | LOOKAHEAD(2) "<" ">"
  | LOOKAHEAD(2) "<" "="
  | "<"
}

void TableName():
{
    String s;
    StringBuilder name = new StringBuilder();
}
{
    // schema.table@link
    s=OracleObjectName()       {name.append(s);}
    [ "." s=OracleObjectName() {name.append(".").append(s);} ]
    [ "@" s=TNSName()          {name.append("@").append(s);} ]
    {tables.add(name.toString().toUpperCase());}
}

void ParameterList():
{}
{
    Parameter() ( "," Parameter() )*
}

void NumOrID():
{}
{
     | (["+" | "-"] )
}

void Parameter():
{}
{
     [ ["IN"] ["OUT"] TypeDefinition()
                             [(":=" | "DEFAULT" ) PlSqlExpression()] ]
}

void Arguments():
{}
{
    Argument() ("," Argument())*
}

void Argument():
{}
{
    [LOOKAHEAD(2)  "=>"] PlSqlExpression()
}

/* --------------- General Productions ends here --------------- */

/* ----------- SQL productions start here ----------------- */

void SelectStatement():
{}
{
    SelectWithoutOrder()
    [ OrderByClause() ]
    [ ForUpdateClause() ]
    [ "SKIP" ID("LOCKED") ]
}

void SelectWithoutOrder():
{}
{
    SelectSet() ((("UNION" ["ALL"]) | "INTERSECT" | "MINUS") SelectSet())*
}

void SelectSet():
{}
{
    Select() | "(" SubQuery() ")"
}

void Select():
{}
{
    "SELECT" [ "ALL" | "DISTINCT" | "UNIQUE" ] SelectList()
    [IntoClause()]
    FromClause()
    [ WhereClause() ]
    [ ConnectClause() ]
    [ HavingClause() GroupByClause() | GroupByClause() [ HavingClause() ]]
}

/* Checks for whatever follows  SELECT */
void SelectList():
{}
{
    "*" | SelectItem() ("," SelectItem())*
}

void SelectItem():
{}
{
    (
        LOOKAHEAD(2) OracleObjectName()".*" // table.*
      | LOOKAHEAD(4) OracleObjectName()"." OracleObjectName() ".*" // schema.table.*
      | SQLSimpleExpression() // column name or expression
    )
    [ [ "AS" ] SelectItemAlias()]
}

void SelectItemAlias():
{}
{
    OracleObjectName()
    // Some keywords are acceptable as aliases:
  | "RETURNING" | "WHEN"
}

void AnalyticFunction():
{}
{
    FunctionCall() [ "OVER" "(" AnalyticClause() ")" ]
}

void AnalyticClause():
{}
{
    [ QueryPartitionClause() ] [ OrderByClause() [ WindowingClause() ] ]
}

void QueryPartitionClause():
{}
{
    "PARTITION" "BY" SQLExpression() ( "," SQLExpression() )*
}

void WindowingClause():
{}
{
    ("ROWS" | "RANGE")
    ( "CURRENT" "ROW"
    | SQLSimpleExpression() ID("PRECEDING") // perhaps UNBOUNDED PRECEDING
    | "BETWEEN" ( "CURRENT" "ROW"
                | SQLSimpleExpression() ID("PRECEDING|FOLLOWING") // perhaps UNBOUNDED FOLLOWING
                )
          "AND" ( "CURRENT" "ROW"
                | SQLSimpleExpression() ID("PRECEDING|FOLLOWING") // perhaps UNBOUNDED PRECEDING
                )
    )
}

void IntoClause():
{}
{
   "INTO" DataItem() ("," DataItem())*
}

void DataItem():
{}
{
    ( ["." ] | BindVariable())
    [ "(" PlSqlSimpleExpression() ")" ] // collection subscript
}

void FromClause():
{}
{
    "FROM" TableReference() ( "," TableReference())*
}

void TableReference():
{}
{
    "ONLY" "(" QueryTableExpression() ")"
  | QueryTableExpression()
}

void QueryTableExpression():
{}
{
    (TableName() // might also be a query name
     | TableCollectionExpression()
     | LOOKAHEAD(3) "(" SubQuery() ")"
     | "(" TableReference() ")"
     | BindVariable() // not valid SQL, but appears in StatsPack SQL text
    )
    ["PX_GRANULE" "("  ","  ","  ")"]
    ["SAMPLE" [ID("BLOCK")] "("  ")"]
    [OracleObjectName()] // alias
    (Join())*
}

void TableCollectionExpression():
{}
{
    "TABLE" "(" SQLSimpleExpression() ")" [ "(" "+" ")" ]
}

void Join():
{}
{
    JoinType() ID("JOIN") TableReference() ("ON" SQLExpression() | "USING" "(" ColumnName() ("," ColumnName())* ")")
//| ("CROSS" | "NATURAL" JoinType()) ID("JOIN") TableReference()
}

void JoinType():
{}
{
    "INNER"
  | ("LEFT" | "RIGHT" | "FULL") ID("OUTER")
}

void ColumnName():
{}
{
    
}

void WhereClause():
{}
{
    "WHERE" SQLExpression()
}

void ConnectClause():
{}
{
    // The following grammar will take 2 "START WITH" expressions
    // which is not correct. But alright, because only valid statements
    // will be given.
   (["START" "WITH" SQLExpression()] "CONNECT" "BY" SQLExpression()
    ["START" "WITH" SQLExpression()])
}

void GroupByClause():
{}
{
    "GROUP" "BY" SQLExpressionList()
}

void HavingClause():
{}
{
    "HAVING" SQLExpression()
}

void OrderByClause():
{}
{
    "ORDER" ["SIBLINGS"] "BY" OrderByExpression() ("," OrderByExpression())*
}

void OrderByExpression():
{}
{
    SQLSimpleExpression()
    ["ASC" | "DESC"]
    ["NULLS" ID("LAST")]
}

void ForUpdateClause():
{}
{
    "FOR" "UPDATE" [ "OF" TableColumn() ("," TableColumn())* ]
    [ "NOWAIT" | "WAIT" SQLSimpleExpression() ]
}

void SQLExpression():
{}
{
    SQLAndExpression() ("OR" SQLAndExpression())*
}

void SQLAndExpression():
{}
{
    SQLUnaryLogicalExpression() ( "AND" SQLUnaryLogicalExpression())*
}

void SQLUnaryLogicalExpression():
{}
{
    LOOKAHEAD(2) ExistsClause()
  | (["NOT"] SQLRelationalExpression())
}

void ExistsClause():
{}
{
    ["NOT"] "EXISTS" "(" SubQuery() ")"
}

void SQLRelationalExpression():
{}
{
    /* Only after looking past "(", Expression() and "," we will know that
       it is expression list */

    (LOOKAHEAD("(" SQLSimpleExpression() ",")
     "(" SQLExpressionList() ")"
|
    (["PRIOR"] SQLSimpleExpression()))

    /* Lookahead(2) is required because of NOT IN,NOT BETWEEN and NOT LIKE */
   ( SQLRelationalOperatorExpression() |  LOOKAHEAD(2) (SQLInClause())
                                    |  LOOKAHEAD(2) (SQLBetweenClause())
                                    |  LOOKAHEAD(2) (SQLLikeClause())
                                    |  IsNullClause()
   )?
}

void SQLExpressionList():
{}
{
    SQLExpression() ("," SQLExpression())*
}

void SQLRelationalOperatorExpression():
{}
{

    Relop()

    /* Only after seeing an ANY/ALL or "(" followed by a SubQuery() we can
    determine that is is a sub-query
    */
    (   LOOKAHEAD("ANY" | "ALL" | "(" "SELECT")
        (["ALL" | "ANY"] "(" SubQuery() ")")
        |
        ["PRIOR"] SQLSimpleExpression()
    )
}

void SQLInClause():
{}
{
    ["NOT"] "IN" "(" (LOOKAHEAD(3) SubQuery() | SQLExpressionList()) ")"
}

void SQLBetweenClause():
{}
{
    ["NOT"] "BETWEEN" SQLSimpleExpression() "AND" SQLSimpleExpression()
}

void SQLLikeClause():
{}
{
    ["NOT"] "LIKE" SQLSimpleExpression() ["ESCAPE" SQLSimpleExpression()]
}

void SQLSimpleExpression():
{}
{
    SQLMultiplicativeExpression() ( ("+" | "-" | "||") SQLMultiplicativeExpression())*
}


void SQLMultiplicativeExpression():
{}
{
    SQLExponentExpression() ( ("*" | "/") SQLExponentExpression())*
}

void SQLExponentExpression():
{}
{
    SQLUnaryExpression() ( "**" SQLUnaryExpression())*
}

void SQLUnaryExpression():
{}
{
    ["+" | "-"] SQLPrimaryExpression()
}


void SQLPrimaryExpression():
{}
{
    
  | 
  | "NULL"
  | SQLCaseExpression()
  | "(" (LOOKAHEAD(3) SelectStatement() | SQLExpression()) ")"
  | BindVariable()
  | LOOKAHEAD(2) SQLCastExpression()
  | LOOKAHEAD(IntervalExpression()) IntervalExpression()
  | LOOKAHEAD(OuterJoinExpression()) OuterJoinExpression()
  | LOOKAHEAD({seeAnalyticFunction()}) AnalyticFunction()
  | LOOKAHEAD(FunctionReference() "(") FunctionCall()
  | TableColumn() // Might be a call to a parameter-less function.
}

void SQLCaseExpression():
{}
{
    "CASE" (SQLSimpleExpression() ("WHEN" SQLSimpleExpression() "THEN" SQLSimpleExpression())*
            | ("WHEN" SQLExpression() "THEN" SQLSimpleExpression())*
           )
    ["ELSE" SQLSimpleExpression()]
    "END"
}

void SQLCastExpression():
{}
{
    "CAST" "(" SQLExpression() "AS" BasicDataTypeDefinition() ")"
}

void IntervalExpression():
{}
{
    ID("INTERVAL") SQLSimpleExpression()
    ( LOOKAHEAD({"DAY".equalsIgnoreCase(getToken(1).image)})
      ID("DAY") ["("  ")"] "TO" ID("SECOND") ["("  ")"]
    | ID("YEAR") ["("  ")"] "TO" ID("MONTH") ["("  ")"]
    )
}

void FunctionCall():
{}
{
    FunctionReference() (
        LOOKAHEAD({"TRIM".equalsIgnoreCase(lastObjectReference)}) TrimArguments()
      | LOOKAHEAD({"EXTRACT".equalsIgnoreCase(lastObjectReference)}) "(" DatetimeField() "FROM" SQLSimpleExpression() ")"
      | [ "(" [["ALL" | "DISTINCT" | "UNIQUE"] (FunctionArgumentList() | "*")] ")" ]
    )
    // "all/distinct/unique/*" are permitted only with aggregate functions,
    // but this parser allows their use with any function.
}

void FunctionReference():
{
    String name;
}
{
    name = ObjectReference()
    {functions.add(name.toUpperCase());}
}

void FunctionArgumentList():
{}
{
    FunctionArgument() ("," FunctionArgument())*
}

void FunctionArgument():
{}
{
    [LOOKAHEAD(2)  "=>"] SQLExpression()
}

void TrimArguments():
{}
{
    "(" ( LOOKAHEAD({getToken(1).image.matches("(?i)LEADING|TRAILING|BOTH")})
             [SQLSimpleExpression()] "FROM" SQLSimpleExpression()
        | SQLSimpleExpression() ["FROM" SQLSimpleExpression()]
        )
    ")"
}

void DatetimeField():
{}
{
    
}

String ObjectReference():
{
    String s;
    StringBuilder name = new StringBuilder();
}
{
    s=OracleObjectName()       {name.append(s);}
    [ "." s=OracleObjectName() {name.append(".").append(s);}
    [ "." s=OracleObjectName() {name.append(".").append(s);}
    ]]
    [ "@" ("!" | s=TNSName()   {name.append("@").append(s);} )] // remote reference
    // The @! idiom is undocumented, but accepted by Oracle software.
    {return lastObjectReference = name.toString();}
}

void OuterJoinExpression():
{}
{
    TableColumn() "(" "+" ")"
}

void SubQuery():
{}
{
    SelectStatement()
}

/** Expect an  with the given value. */
void ID(String id):
{}
{
    
    {
        if (!token.image.matches("(?i)" + id)) {
            throw new ParseException("Encountered " + token.image
                + " at line " + token.beginLine + ", column " + token.beginColumn + "."
                + "\nWas expecting: " + id);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy