SPA

antlr4 Cymbol.g4
javac Cymbol*.java
run Cymbol file -gui ../../../spDir/dbdom.sp

antlr4 Plsql.g4
javac Plsql*.java
run Plsql start_rule -gui C:\ccsnapshot_views\localDEV_tls_fundmsg_01.00.05_pchz_2\tls02\tls_fundmsg\src\research\smartTool\spDir\OPS$FAST.ANTLR1.sp
run Plsql start_rule -gui C:\ccsnapshot_views\localDEV_tls_fundmsg_01.00.05_pchz_2\tls02\tls_fundmsg\src\research\Deliver\public\spPkg\[email protected]_1521_itelsdev\TEMF_DEV.XML_WASH_SALES_PKG.sp

dot -Tpng dot.gv -o dot.png

antlr4 Java.g4
run Java compilationUnit -gui tt/Test2.java



/*******************************************************************************

DESCRIPTION:
		Oracle PL/SQL Grammar for ANTLR v4, target language Java
AUTHOR:
		Andrey Kharitonkin ([email protected])
DATE:
		02-Jan-2008
BASED ON:
		PLSQLGrammar.g for ANTLR v2
		Qazi Firdous Ahmed ([email protected]) 
		Krupa Benhur ([email protected])
		Manojaba Banerjee ([email protected])
		Infosys Technologies Ltd., Bangalore, India
		Sept 18, 2002
		This grammar is for PL/SQL.
COMMENT:
		The grammar has been mostly re-written for ANTLR v3,
		using Oracle 10g Release 2 documentation and ANTLR book.
		New SQL and PL/SQL expression rules, SQL statments
		SELECT, INSERT, UPDATE, DELETE are fully supported.
		Generated parser can parse most  of valid PL/SQL and 
		it was tested with over 10 Mb of test source code.
		Let me know if something cannot be parsed by this grammar.
KNOWN ISSUES:
		At the moment only supports CREATE PACKAGE and PACKAGE BODY.
		Symbol table and gate predicates needed to distinguish
			between function call and variable usage.

It was fun learning ANTLR3 and creating this grammar, hope you enjoy it as well!

*******************************************************************************/

grammar Plsql;

options {
	language=Java;
	//backtrack=true;
	//memoize=true;
	//output=AST;
}

@members {
    private boolean is_sql = false;
}

start_rule
	:	((create_package)* | ('CREATE' ( 'OR' keyREPLACE )? procedure_body)) EOF
        
	;

create_package
	:	'CREATE' ( 'OR' keyREPLACE )?
		( package_spec | package_body )
	;
	
package_spec
	:	keyPACKAGE package_name ( 'IS' | 'AS' ) 
		( package_obj_spec )*
		'END' (package_name)? SEMI
	;
	
package_body
	:	keyPACKAGE ( keyBODY ) package_name ( 'IS' | 'AS' )
		( package_obj_body )*
		( 'BEGIN' seq_of_statements )?  
		'END' ( package_name )? SEMI
	;

package_name
	:	( schema_name DOT )? identifier 
	;

package_obj_spec
	:	variable_declaration 
	|	type_declaration
        |	type_declaration2
        |       table_type_dec
	|	subtype_declaration 
	|	record_declaration 
	|	plsql_table_declaration 
	|	varray_declaration
	|	cursor_declaration 
	|	cursor_spec 
	|	procedure_spec 
	|	function_spec 
	|	exception_declaration 
	|	pragma_declaration
	;

variable_declaration
	:	variable_name ('CONSTANT')?
		type_spec ('NOT' 'NULL')? 
		( ( ASSIGN | 'DEFAULT' ) plsql_expression)? SEMI
	;	

type_declaration 
	:	keyTYPE (type_spec) 'IS' ( keyNEW )? ( type_spec ( 'NOT' 'NULL' )? | LPAREN plsql_expressions RPAREN ) SEMI
	;	

type_declaration2 
	:	keyTYPE type_name 'IS' ('REF' | 'ref') 'CURSOR' (return_statement)? SEMI
	;	

subtype_declaration 
	:	keySUBTYPE type_spec 'IS' type_spec ( 'NOT' 'NULL' | keyRANGE literal DOUBLEDOT literal )? SEMI
	;	
	
cursor_declaration
	:	keyCURSOR cursor_name
		( LPAREN parameter_specs RPAREN )?               
		'IS'  ('WITH' identifier 'AS' LPAREN select_command RPAREN)? LPAREN? select_command RPAREN? SEMI
	;
package_obj_body
	:	variable_declaration 
	|	subtype_declaration 
	|	cursor_declaration 
	|	exception_declaration 
	|	record_declaration 
	|	plsql_table_declaration 
	|	varray_declaration
	|	procedure_body 
	|	function_body 
	|	pragma_declaration
	;

seq_of_statements
	:	statement SEMI ( statement SEMI )*
	;
	
statement
	:	assignment_statement
	|	exit_statement
	|	goto_statement
	|	case_statement
	|	if_statement 
	|	loop_statement 
	|	null_statement
	|	raise_statement
	|	return_statement
	|	sql_statement
	|	plsql_block
//	|	begin_block
	|	function_call
        |       merge_statement
	;

merge_statement
    :    keyMERGE ('INTO' | 'into') selected_table 
        keyUSING selected_table ('ON' | 'on') LPAREN plsql_condition RPAREN
        (('WHEN' | 'when') keyMATCHED ('THEN' | 'then')  'UPDATE' 'SET' merge_element )        
        (('WHEN' | 'when') ('NOT' | 'not') keyMATCHED ('THEN' | 'then')  'INSERT' LPAREN column_name ( COMMA column_name )* RPAREN 'VALUES' LPAREN plsql_expressions RPAREN where_condition?)                
    ;

merge_element
    :    column_name EQ plsql_expression
    ;
		
plsql_block
	:	( LLABEL label_name RLABEL )?
		( ( 'DECLARE' )? (declare_spec)+ )? 
		( 'BEGIN' )
		seq_of_statements
		( 'EXCEPTION' ( exception_handler )+ )? 
		( 'END' ( label_name )? )
	;

declare_spec
	:	variable_declaration 
	|	subtype_declaration 
	|	cursor_declaration 
	|	exception_declaration 
	|	record_declaration 
	|	plsql_table_declaration 
	|	varray_declaration
	|	procedure_declaration 
	|	function_declaration
	|	type_declaration 
        |	type_declaration2         
	|	pragma_declaration
	;

pragma_declaration
	:	keyPRAGMA 
		(	keyRESTRICT_REFERENCES LPAREN ( 'DEFAULT' | function_name ) ( COMMA pragma_param )+ RPAREN 
		|	keyEXCEPTION_INIT LPAREN exception_name COMMA literal RPAREN
		|	keyAUTONOMOUS_TRANSACTION
		|	keySERIALLY_REUSABLE
		|	keyBUILTIN LPAREN pragma_params RPAREN
		|	keyFIPSFLAG LPAREN pragma_params RPAREN
		|	keyINTERFACE LPAREN pragma_params RPAREN
		|	keyNEW_NAMES LPAREN pragma_params RPAREN
		|	keyTIMESTAMP LPAREN pragma_params RPAREN
		)
		SEMI
	;

pragma_params
	:	pragma_param ( COMMA pragma_param )*
	;

pragma_param
	:	( PLUS | MINUS )? NUMBER
	|	QUOTED_STRING
	|	identifier
	;

assignment_statement
	:	// (lvalue ASSIGN function_call)
//	|	
		(lvalue ASSIGN (plsql_expression | ('NEW' function_call)))
//	|	function_call
	;
lvalues
	:	lvalue ( COMMA lvalue )*
	;
lvalue
	:	variable_name
	|	record_name DOT field_name
	|	plsql_table_name LPAREN subscript RPAREN ( DOT field_name )*
	|	COLON host_variable ( COLON host_variable )?
	;

field_name
	:	identifier
	;
	
subscript
	:	plsql_expression 
	;
	
host_variable
	:	identifier
	;
	
goto_statement
	:	'GOTO' label_name
	;
	
label_name
	:	identifier
	;	

exit_statement
	:	keyEXIT ( label_name )? ( 'WHEN' plsql_condition )?
	;
	
datatype
	:	('BINARY_INTEGER' | 'binary_integer')
	|	'BINARY_FLOAT'
	|	'BINARY_DOUBLE'
	|	'NATURAL' 
	|	'POSITIVE' 
	|	( 'NUMBER' | 'NUMERIC' | 'DECIMAL' | 'DEC' ) ( LPAREN NUMBER ( COMMA NUMBER )? RPAREN )?
	|	'LONG' ( 'RAW')? ( LPAREN NUMBER RPAREN )?
	|	'RAW' ( LPAREN NUMBER RPAREN )?
	|	'BOOLEAN'
	|	'DATE'
	|	keyINTERVAL keyDAY ( LPAREN NUMBER RPAREN )? 'TO' keySECOND ( LPAREN NUMBER RPAREN )?
	|	keyINTERVAL keyYEAR ( LPAREN NUMBER RPAREN )? 'TO' keyMONTH
	|	( keyTIME | keyTIMESTAMP ) ( LPAREN NUMBER RPAREN )? ( 'WITH' ( keyLOCAL )? keyTIME keyZONE)?
	|	'INTEGER'
	|	'INT'
	|	'SMALLINT'
	|	'FLOAT' ( LPAREN NUMBER RPAREN )?
	|	'REAL'
	|	'DOUBLE' keyPRECISION
	|	'CHAR'      ( keyVARYING )? ( LPAREN NUMBER ( keyBYTE | 'CHAR' )? RPAREN )? ( 'CHARACTER' 'SET' ( identifier | column_spec CHARSET_ATTR ) )?
	|	'VARCHAR'                   ( LPAREN NUMBER ( keyBYTE | 'CHAR' )? RPAREN )? ( 'CHARACTER' 'SET' ( identifier | column_spec CHARSET_ATTR ) )?
	|	'VARCHAR2'                  ( LPAREN NUMBER ( keyBYTE | 'CHAR' )? RPAREN )? ( 'CHARACTER' 'SET' ( identifier | column_spec CHARSET_ATTR ) )?
	|	'CHARACTER' ( keyVARYING )? ( LPAREN NUMBER RPAREN )?
	|	'NCHAR'     ( keyVARYING )? ( LPAREN NUMBER RPAREN )?
	|	'NVARCHAR'  ( LPAREN NUMBER RPAREN )?
	|	'NVARCHAR2' ( LPAREN NUMBER RPAREN )?
	|	'NATIONAL'  ( 'CHARACTER' | 'CHAR' ) ( keyVARYING )? ( LPAREN NUMBER RPAREN )?
	|	'MLSLABEL'
	|	'PLS_INTEGER'
	|	'BLOB'
	|	'CLOB' ( 'CHARACTER' 'SET' ( identifier | column_spec CHARSET_ATTR ) )?
	|	'NCLOB'
	|	'BFILE'
	|	'ROWID' 
	|	'UROWID' ( LPAREN NUMBER RPAREN )?
        |	'REF' 
	;

type_spec
	:	datatype 
//	|	variable_name TYPE_ATTR
	|	column_spec TYPE_ATTR
//	|	package_name DOT variable_name
	|	table_spec ROWTYPE_ATTR
//	|	keyREF ( keyCURSOR | type_name )
	|	type_name ( LPAREN NUMBER RPAREN )?
	;

type_name
	:	identifier ( DOT identifier )*
	;

parameter_specs
	:	parameter_spec ( COMMA parameter_spec )*
	;

parameter_spec
	:	parameter_name ( 'IN' )? ( type_spec )?
	;	

parameter_name
	:	identifier
	;

cursor_spec
	:	keyCURSOR cursor_name 
		( LPAREN parameter_specs RPAREN )?
		keyRETURN return_type ( ('IS' (select_command)?) ) SEMI 
	;

procedure_spec: 
	'PROCEDURE' procedure_name 
	( LPAREN arguments RPAREN )? SEMI
	;

function_spec
	:	'FUNCTION' function_name 
		( LPAREN arguments RPAREN )?
		keyRETURN return_type ('PARALLEL_ENABLE' LPAREN query_partition_clause RPAREN)? ('PIPELINED' | 'pipelined')? SEMI
	;

exception_declaration
	:	exception_name 'EXCEPTION' SEMI
	;

exception_names
	:	exception_name ( 'OR' exception_name )*
	;

exception_name
	:	( exception_package_name DOT )? identifier
	;

exception_package_name
	:	identifier
	;

	
//oracle_err_number
//	:	( PLUS | MINUS )? NUMBER
//	|	QUOTED_STRING
//	;
	
record_declaration
	:	record_type_dec 
//	|	record_var_dec
	;

record_type_dec
	:	keyTYPE type_name 'IS' keyRECORD 
		LPAREN field_specs RPAREN SEMI
	;

//record_var_dec
//	:	record_name type_name ROWTYPE_ATTR SEMI
//	;

field_specs
	:	field_spec ( COMMA field_spec )*
	;
field_spec
	:	column_name type_spec
		('NOT' 'NULL')? 
		( ( ASSIGN | 'DEFAULT' ) plsql_expression)?
	;

plsql_table_declaration
	:	table_type_dec
//	|	table_var_dec
	;

table_type_dec
	:	keyTYPE type_name 'IS' 'TABLE' 
		'OF' type_spec ( 'NOT' 'NULL' )?
		(	'INDEX' 'BY' 
			(	('BINARY_INTEGER' | 'binary_integer')
			|	'PLS_INTEGER'
			|	'VARCHAR2' LPAREN integer RPAREN
                        |       'NATURAL'
			)
		)?
		SEMI
	;

table_var_dec
	:	plsql_table_name type_name SEMI
	;

plsql_table_name
	:	identifier ( DOT identifier )*
	;

varray_declaration
	:	keyTYPE type_name 'IS' 
		( keyVARRAY | keyVARYING keyARRAY ) LPAREN integer RPAREN
		'OF' type_spec ( 'NOT' 'NULL' )?
	;

procedure_declaration
	:	procedure_body
	;

procedure_body
	:	( proc_fun_start )? 'PROCEDURE' procedure_name 
		( LPAREN argument ( COMMA argument )* RPAREN )? 
		( 'IS' | 'AS' )
		//( keyPRAGMA keyAUTONOMOUS_TRANSACTION )?
		( ( declare_spec )* )
		( 'BEGIN' )
		( seq_of_statements )
		( 'EXCEPTION' ( exception_handler )* )?
		'END' ( procedure_name )? SEMI
	;

begin_block
	:	'BEGIN'
		( seq_of_statements )
		( 'EXCEPTION' ( exception_handler )+ )?
		'END'
	;

//Exception handler needs to be defined
exception_handler
	:	'WHEN' exception_names 'THEN'
		seq_of_statements
	;

proc_fun_start
	:	'CREATE' ( 'OR' keyREPLACE )?
	;

function_body
	:	( proc_fun_start )? 'FUNCTION' function_name 
		( LPAREN arguments RPAREN )? 
		keyRETURN return_type  ('PARALLEL_ENABLE' LPAREN query_partition_clause RPAREN)? ('PIPELINED' | 'pipelined')? 
                ( 'IS' | 'AS' )
		//( keyPRAGMA keyAUTONOMOUS_TRANSACTION )?
		( ( declare_spec )* )
		( 'BEGIN' )
		( seq_of_statements )
		( 'EXCEPTION' ( exception_handler )+ )?
		'END' ( function_name )? SEMI
	;

function_name
	:	identifier | QUOTED_STRING //( schema_name DOT )? identifier
	;

procedure_name
	 :	( schema_name DOT )? (identifier | QUOTED_STRING) //( schema_name DOT )? identifier
	;

arguments
	:	argument ( COMMA argument )*
	;

argument
	:	argument_name ( keyOUT | ('IN' | 'in') keyOUT | ('IN' | 'in') )? ('NOCOPY' | 'nocopy')? (argument_type )?
		( ( ASSIGN | 'DEFAULT' ) plsql_expression )?
	;

argument_name
	:	identifier
	;

argument_type
	:	type_spec
	;

value
	:	( PLUS | MINUS )? NUMBER
	|	quoted_string
	|	'TRUE' | 'FALSE'
	|	'NULL'
	;

return_type
	:	type_spec | sql_identifier
	;

function_declaration
	:	function_body
	;

function_call
	:	user_defined_function LPAREN ( call_parameters )? RPAREN
//	|	//{ _input.LA(1) == ID && _input.LA(2) == LPAREN && _input.LA(3) == ASTERISK && _input.LA(4) == RPAREN }? 
//		{ is_sql }?
//		keyCOUNT LPAREN ( ASTERISK | sql_expression ) RPAREN
//	|	{ is_sql }?
//		'DISTINCT' LPAREN call_parameters RPAREN
	;

collection_function_call
	:	plsql_table_name
	;

variable_names
	:	variable_name ( COMMA variable_name )*
	;
variable_name
	:	identifier ( DOT identifier )* 
	;

null_statement
	:	'NULL' 
	;

raise_statement
	:	keyRAISE ( exception_name )?
	;
	
return_statement
	:	keyRETURN ( plsql_expression   | (table_spec ROWTYPE_ATTR)  )?
	;

loop_statement
	:	( LLABEL label_name RLABEL )?
		(	keyWHILE plsql_condition
		| 	(	'FOR'
				(	 numeric_loop_param
				|	 cursor_loop_param 
				)
			)
		)?
		keyLOOP
		seq_of_statements
		'END' keyLOOP 
		( label_name )?
	;

numeric_loop_param
	:	index_name 'IN' ( keyREVERSE )? integer_expr DOUBLEDOT integer_expr
	;

index_name
	:	identifier
	;

//Added typespec to handle packagename.variablename for loop statement
integer_expr
	:	sql_expression
	;

cursor_name
	:	identifier
	;

cursor_loop_param
	:	record_name 'IN'
		(	cursor_name ( LPAREN plsql_expressions RPAREN )?
		|	LPAREN select_statement RPAREN
		)
	;

record_name
	:	identifier
	;

commit_statement
	:	'COMMIT'
	;

if_statement
	:	'IF' plsql_condition 'THEN' seq_of_statements
		(	//{ _input.LA(1) != ELSE }?
			keyELSIF plsql_condition 'THEN' seq_of_statements
		)*
		( 'ELSE' seq_of_statements )?
		'END' 'IF'
	;

sql_statement
	:	sql_command
	;

sql_command
	:	to_modify_data
	|	to_control_data
	;

to_modify_data
	:	select_command
	|	insert_command
	|	update_command
	|	delete_command
	|	set_transaction_command
	;

to_control_data
	:	close_statement
	|	commit_statement
	|	fetch_statement
	|	lock_table_statement
	|	open_statement
        |	open_statement2
	|	rollback_statement
	|	savepoint_statement
        |	pipe_statement
	;

select_command
	:	select_statement// ( 'UNION' select_statement )*
	;

select_statement
	:	// LPAREN select_command RPAREN |
		LPAREN? select_expression RPAREN?  ('UNION' ( 'ALL' )? LPAREN? select_expression RPAREN? )* ( order_by_clause )?
	;

select_expression
	:	
	        'SELECT' /*( hint )?*/ ( 'DISTINCT' | 'UNIQUE' | 'ALL' )? select_list
		// ( keyBULK keyCOLLECT )?
                ( ('BULK' | 'bulk') ('COLLECT' | 'collect') )?
		( 'INTO' lvalues )?
		'FROM' ( table_reference_list | join_clause | LPAREN join_clause RPAREN )
		( where_clause )? ( hierarchical_query_clause )? ( group_by_clause )?
		( 'HAVING' sql_condition )? ( model_clause )?
		(	(	'UNION' ( 'ALL' )?
			|	'INTERSECT'
			|	'MINUS'
			)
			(	select_expression //LPAREN subquery RPAREN
			|	subquery
			)
		)?
		( order_by_clause )?
	;

select_list
	:	ASTERISK
	|	displayed_column ( COMMA displayed_column )*
	;

table_reference_list_from
	:	'FROM' table_reference_list
	;

table_reference_list
	:	selected_table ( COMMA selected_table )*
	;

join_clause
	:	table_name ( inner_cross_join_clause | outer_join_clause )+
	;
inner_cross_join_clause
	:	( keyINNER )? keyJOIN table_name ( 'ON' sql_condition | keyUSING LPAREN column_specs RPAREN )
	|	( keyCROSS | keyNATURAL ( keyINNER ) ) keyJOIN table_name
	;
outer_join_clause
	:	( query_partition_clause )?
		(	outer_join_type keyJOIN
		|	keyNATURAL ( outer_join_type )? keyJOIN
		)
		table_name ( query_partition_clause )?
		( 'ON' sql_condition | keyUSING LPAREN column_specs RPAREN )?
	;
query_partition_clause
	:	(keyPARTITION (sql_identifier)? 'BY' (expression_list | 'ANY'))? ( order_by_clause )? 
	;
outer_join_type
	:	( keyFULL | keyLEFT | keyRIGHT ) ( keyOUTER )?
	;
outer_join_sign
	:	LPAREN PLUS RPAREN
	;
where_clause
	:	'WHERE' sql_condition
	;
hierarchical_query_clause
	:	( 'START' 'WITH' sql_condition )? 'CONNECT' 'BY' ( keyNOCYCLE )? sql_condition
	;
group_by_clause
	:	'GROUP' 'BY' group_by_exprs
	;
group_by_exprs
	:	group_by_expr ( COMMA group_by_expr )*
	;
group_by_expr
	:	rollup_cube_clause
	|	grouping_sets_clause
	|	grouping_expression_list
	;
rollup_cube_clause
	:	( keyROLLUP | keyCUBE ) LPAREN grouping_expression_list RPAREN
	;
grouping_sets_clause
	:	keyGROUPING keySETS LPAREN grouping_expression_list RPAREN
	;
grouping_sets_exprs
	:	grouping_sets_expr ( COMMA grouping_sets_expr )*
	;
grouping_sets_expr
	:	rollup_cube_clause | grouping_expression_list
	;
model_clause
	:	keyMODEL ( cell_reference_options )
		( return_rows_clause )?
		( reference_model )+ main_model
	;
cell_reference_options
	:	( ( keyIGNORE | keyKEEP ) keyNAV )?
		( 'UNIQUE' ( keyDIMENSION | keySINGLE keyREFERENCE ) )?
	;
return_rows_clause
	:	keyRETURN ( keyUPDATED | 'ALL' ) 'ROWS'
	;
reference_model
	:	keyREFERENCE reference_model_name 'ON' LPAREN subquery RPAREN
		model_column_clauses ( cell_reference_options )
	;
reference_model_name
	:	identifier
	;
main_model
	:	( keyMAIN main_model_name )? model_column_clauses
		( cell_reference_options ) model_rules_clause
	;
main_model_name
	:	identifier
	;
model_column_clauses
	:	( query_partition_clause ( column_spec )? )?
		keyDIMENSION 'BY' LPAREN model_columns RPAREN
		keyMEASURES LPAREN model_columns RPAREN
	;
model_columns
	:	model_column ( COMMA model_column )*
	;
model_column
	:	sql_expression ( ( 'AS' )? column_spec )?
	;
model_rules_clause
	:	( keyRULES ( 'UPDATE' | keyUPSERT ( 'ALL' )? )? ( ( keyAUTOMATIC | keySEQUENTIAL ) keyORDER )? )?
		( keyITERATE LPAREN NUMBER RPAREN ( keyUNTIL LPAREN sql_condition RPAREN )? )?
		LPAREN model_rules_exprs RPAREN
	;
model_rules_exprs
	:	model_rules_expr ( COMMA model_rules_expr )*
	;
model_rules_expr
	:	( 'UPDATE' | keyUPSERT ( 'ALL' )? )? cell_assignment ( order_by_clause )? EQ sql_expression
	;
cell_assignment
	:	measure_column LBRACK ( multi_column_for_loop | cell_assignment_exprs ) RBRACK
	;
cell_assignment_exprs
	:	cell_assignment_expr ( COMMA cell_assignment_expr )*
	;
cell_assignment_expr
	:	sql_condition | sql_expression | single_column_for_loop
	;
measure_column
	:	column_name
	;
single_column_for_loop
	:	'FOR' column_name
		(	'IN' LPAREN ( literals | subquery ) RPAREN
		|	( 'LIKE' pattern )? 'FROM' literal 'TO' literal ( keyINCREMENT | keyDECREMENT ) literal
		)
	;
literal
	:	( PLUS | MINUS )? NUMBER
	|	QUOTED_STRING
	;
literals
	:	literal ( COMMA literal )*
	;
bracket_literals
	:	LPAREN literals RPAREN
	;
bracket_literals_list
	:	bracket_literals ( COMMA bracket_literals )*
	;
pattern
	:	QUOTED_STRING
	;
multi_column_for_loop
	:	'FOR' LPAREN column_specs RPAREN 'IN' LPAREN ( bracket_literals_list | subquery ) RPAREN
	;
order_by_clause
	:	('ORDER' | 'order') ( keySIBLINGS )? ('BY' | 'by') order_by_exprs
	;
order_by_exprs
	:	order_by_expr ( COMMA order_by_expr )*
	;
order_by_expr
	:	(	sql_expression
//		|	position
//		|	column_alias
		)
		( 'ASC' | 'DESC' )? ( keyNULLS keyFIRST | keyNULLS keyLAST )?
	;
for_update_clause
	:	'FOR' 'UPDATE' ( 'OF' column_specs )? ( keyWAIT integer | 'NOWAIT' )?
	;

where_condition_whole
	:	'WHERE' sql_condition
	;

where_condition
	:	sql_condition
	;

displayed_column
	:	(	column_spec DOT ASTERISK
//		|	keyCOUNT LPAREN ( ASTERISK | 'DISTINCT' LPAREN sql_expression RPAREN ) RPAREN
//		|	
		|	sql_expression (keyOVER LPAREN query_partition_clause RPAREN )?
		)
		( alias )?
	;

schema_name
	:	sql_identifier
	;

table_name
	:	sql_identifier
	;

nested_expressions
	:	nested_expression ( COMMA nested_expression )*
	;

nested_expression
	:	{  is_sql }? sql_expression
	|	{ !is_sql }? plsql_expression
	;
plsql_condition
		@init { is_sql = false; }
	:	expr_bool
	;

plsql_expressions
	:	plsql_expression ( COMMA plsql_expression )*
	;

plsql_expression
		@init { is_sql = false; }
	:	expr_bool
	;


expr_bool
	:	expr_or ( 'OR' expr_or )*
	;
expr_or
	:	expr_and ( 'AND' expr_and )*
	;
expr_and
	:	( 'NOT' )? expr_not
	;
expr_not
	:	expr_add 
		(	relational_op expr_add
		|	FOUND_ATTR | NOTFOUND_ATTR | ISOPEN_ATTR | ROWCOUNT_ATTR | BULK_ROWCOUNT_ATTR
		|	'IS' ( 'NOT' )? 'NULL'
		|	( 'NOT' )? 'LIKE' expr_add
		|	( 'NOT' )? 'BETWEEN' expr_add 'AND' expr_add
		|	( 'NOT' )? 'IN' LPAREN nested_expressions RPAREN
		)*
	;

boolean_literal
	:	'TRUE' | 'FALSE'
	;

sql_expressions
	:	sql_expression ( COMMA sql_expression )*
	;
sql_expression
		@init { is_sql = true; }
	:	expr_add
	;
expr_add
	:	expr_mul ( ( PLUS | MINUS | DOUBLEVERTBAR ) expr_mul )*
	;
expr_mul
	:	expr_sign ( ( ASTERISK | DIVIDE ) expr_sign )*
	;
expr_sign
	:	( PLUS | MINUS )? expr_pow
	;
expr_pow
	:	expr_expr ( EXPONENT expr_expr )*
	;
expr_expr
	:	 expr_paren	
        |	 function_expression
//	|	 compound_expression
	|	 case_expression
        |	 cast_expression
        |	 cursor_expression
	|	 simple_expression
	|	 select_expression
//	|	 special_expression
//	|	datetime_expression
//	|	interval_expression
//	|	object_access_expression
//	|	scalar_subquery_expression
//	|	model_expression
//	|	type_constructor_expression
//	|	variable_expression
//	:	'NULL' | NUMBER | QUOTED_STRING | IDENTIFIER
	;
simple_expression
	:	boolean_literal
	|	'SQL' ( FOUND_ATTR | NOTFOUND_ATTR | ISOPEN_ATTR | ROWCOUNT_ATTR | BULK_ROWCOUNT_ATTR )
	|	 column_spec
	|	QUOTED_STRING
	|	NUMBER
//	|	sequence_name DOT ( 'CURRVAL' | 'NEXTVAL' )
//	|	'ROWID'
//	|	'ROWNUM'
	|	'NULL'
	;
compound_expression
//	:	expr_paren
//	|	expr_sign
	:	expr_prior
//	|	expr_add
//	|	expr_cat
	;
expr_paren
	:	LPAREN nested_expression RPAREN
	;
expr_prior
	:	'PRIOR' expr_add
	;
case_expression
	:	'CASE' ( simple_case_expression | searched_case_expression ) ( else_case_expression )? 'END'
	;
cast_expression
	:	'CAST' LPAREN ( sql_identifier 'AS' sql_identifier) RPAREN
	;

simple_case_expression
	:	nested_expression ( 'WHEN' nested_expression 'THEN' nested_expression )+
	;
searched_case_expression
	:	( 'WHEN' nested_condition 'THEN' nested_expression )+
	;
else_case_expression
	:	'ELSE' nested_expression
	;
case_statement
	:	( label_name )? 'CASE' ( simple_case_statement | searched_case_statement ) ( else_case_statement )? 'END' 'CASE' ( label_name )?
	;
simple_case_statement
	:	plsql_expression ( 'WHEN' plsql_expression 'THEN' seq_of_statements )+
	;
searched_case_statement
	:	( 'WHEN' plsql_expression 'THEN' seq_of_statements )+
	;
else_case_statement
	:	'ELSE' seq_of_statements
	;
cursor_expression
	:	keyCURSOR LPAREN subquery RPAREN
	;
datetime_expression
	:	sql_expression 'AT'
		(	keyLOCAL
		|	keyTIME keyZONE ( keyDBTIMEZONE | keySESSIONTIMEZONE | sql_expression )
		)
	;
function_expression
	:	function_call ( DOT nested_expression )?
	|	{ is_sql }?
		(	keyCOUNT LPAREN ( ASTERISK | nested_expression ) RPAREN
		|	'DISTINCT' ( LPAREN nested_expression RPAREN | nested_expression )
		)
	;
special_expression
	:	{ is_sql }?
		(	keyCOUNT LPAREN ( ASTERISK | nested_expression ) RPAREN
		|	'DISTINCT' LPAREN nested_expression RPAREN
		)
	;
interval_expression
	:	sql_expression
		(	keyDAY ( LPAREN leading_field_precision RPAREN )? 'TO' keySECOND ( LPAREN fractional_second_precision RPAREN )?
		|	keyYEAR ( LPAREN leading_field_precision RPAREN )? 'TO' keyMONTH
		)
	;
leading_field_precision
	:	integer // TODO validate digit from 0 to 9
	;
fractional_second_precision
	:	integer // TODO validate digit from 0 to 9
	;
object_access_expression
	:
	;
scalar_subquery_expression
	:
	;
model_expression
	:
	;
type_constructor_expression
	:
	;
variable_expression
	:
	;
sequence_name
	:	identifier
	;
integer
	:	NUMBER
	;


alias
	:	( 'AS' )? sql_identifier
	;

column_specs
	:	column_spec ( COMMA column_spec )*
	;

column_spec
	:	sql_identifier ( DOT sql_identifier )* 
//	|	{ is_sql }?
//		(	ASTERISK
//		|	sql_identifier ( DOT sql_identifier )* ( DOT ASTERISK )
//		)
//		( ( schema_name DOT )? table_name DOT )? column_name
	;

column_name
	:	sql_identifier
	;
nested_table
	:	sql_identifier
	;
nested_table_column_name
	:	( schema_name DOT )? table_name DOT nested_table DOT column_name
	;

user_defined_function
	:	sql_identifier ( DOT sql_identifier )* ( DOT ( 'EXISTS' | 'PRIOR' | 'DELETE' ) )? //( ( schema_name DOT )? package_name DOT )? identifier // sql_identifier ( DOT sql_identifier )*
	;

//function
//	:	user_defined_function
//		number_function
//	|	char_function
//	|	group_function
//	|	conversion_function
//	|	other_function
//	;

selected_table
	:	( table_spec | ( 'TABLE' | keyTHE )? (subquery | sql_expression) ) ( alias )?
	;

table_spec
	:	( schema_name DOT )? table_name ( AT_SIGN link_name )?
	;

table_alias
	:	( schema_name DOT )? table_name ( AT_SIGN link_name )? ( alias )?
	;

link_name
	:	sql_identifier
	;
nested_condition
	:	{  is_sql }? condition_or
	|	{ !is_sql }? expr_bool
	;
sql_condition
		@init { is_sql = true; }
	:	condition_or
//	|	column 'IS' 'NOT' 'NULL' // TODO must be any boolean expression with table columns
	;
condition_paren
	:	LPAREN sql_condition RPAREN
	;
condition_or
	:	condition_and ( 'OR' condition_and )*
	;
condition_and
	:	condition_not ( 'AND' condition_not )*
	;
condition_not
	:	'NOT' condition_expr
	|	condition_expr
	;
condition_expr
	:	condition_exists
	|	condition_is
	|	condition_comparison
	|	condition_group_comparison
        |	condition_in
	|	condition_is_a_set
	|	condition_is_any
	|	condition_is_empty
	|	condition_is_of_type
	|	condition_is_present
	|	condition_like
	|	condition_memeber
	|	condition_between
	|	condition_regexp_like
	|	condition_submultiset
	|	condition_equals_path
	|	condition_under_path
	|	condition_paren
	;
condition_exists
	:	'EXISTS' LPAREN select_command RPAREN
	;
condition_is
	:	sql_expression 'IS' ( 'NOT' )? ( keyNAN | keyINFINITE | 'NULL' )
	;
condition_comparison
	:	LPAREN sql_expressions RPAREN ( outer_join_sign )? ( EQ | NOT_EQ ) LPAREN select_command RPAREN ( outer_join_sign )?
	|	( 'PRIOR' )? sql_expression ( outer_join_sign )? ( EQ | NOT_EQ | GTH | GEQ | LTH | LEQ ) ( 'PRIOR' )? ( sql_expression | LPAREN select_command RPAREN ) ( outer_join_sign )?
	;
condition_group_comparison
	:	LPAREN sql_expressions RPAREN ( EQ | NOT_EQ ) ( 'ANY' | keySOME | 'ALL' ) LPAREN ( grouping_expression_list | select_command ) RPAREN
	|	sql_expression ( EQ | NOT_EQ | GTH | GEQ | LTH | LEQ ) ( 'ANY' | keySOME | 'ALL' ) LPAREN ( sql_expressions | select_command ) RPAREN
	;
condition_in
	:	LPAREN sql_expressions RPAREN ( 'NOT' )? 'IN' LPAREN ( grouping_expression_list | select_command ) RPAREN
	|	sql_expression ( 'NOT' )? 'IN' LPAREN ( expression_list | select_command ) RPAREN
	;
condition_is_a_set
	:	nested_table_column_name 'IS' ( 'NOT' )? keyA 'SET'
	;
condition_is_any
	:	( column_name 'IS' )? 'ANY'
	;
condition_is_empty
	:	nested_table_column_name 'IS' ( 'NOT' )? keyEMPTY
	;
condition_is_of_type
	:	sql_expression 'IS' ( 'NOT' )? 'OF' ( keyTYPE )? LPAREN type_name RPAREN
	;
condition_is_of_type_names
	:	condition_is_of_type_name ( COMMA condition_is_of_type_name )*
	;
condition_is_of_type_name
	:	( keyONLY )? type_name
	;
condition_is_present
	:	cell_reference 'IS' keyPRESENT
	;
condition_like
	:	sql_expression ( 'NOT' )? ( 'LIKE' | keyLIKEC | keyLIKE2 | keyLIKE4 ) sql_expression ( keyESCAPE sql_expression )?
	;
condition_memeber
	:	sql_expression ( 'NOT' )? keyMEMBER ( 'OF' )? nested_table_column_name
	;
condition_between
	:	sql_expression ( 'NOT' )? 'BETWEEN' sql_expression 'AND' sql_expression
	;
condition_regexp_like
	:	keyREGEXP_LIKE LPAREN call_parameters RPAREN
	;
condition_submultiset
	:	nested_table_column_name ( 'NOT' )? keySUBMULTISET ( 'OF' )? nested_table_column_name
	;
condition_equals_path
	:	keyEQUALS_PATH LPAREN column_name COMMA path_string ( COMMA correlation_integer )? RPAREN
	;
condition_under_path
	:	keyUNDER_PATH LPAREN column_name ( COMMA levels )? COMMA path_string ( COMMA correlation_integer )? RPAREN
	;
levels
	:	integer
	;
correlation_integer
	:	integer
	;
path_string
	:	QUOTED_STRING
	;
grouping_expression_list
	:	expression_list ( COMMA expression_list )*
	;
expression_list
	:	LPAREN sql_expressions RPAREN
	|	sql_expressions
	;
cell_reference
	:	sql_identifier
	;
call_parameters
	:	call_parameter ( COMMA call_parameter )*
	;
call_parameter
	:	( parameter_name ARROW )? nested_expression
	;

relational_op
	:	EQ | LTH | GTH | NOT_EQ | LEQ | GEQ
	;

exp_set
	:	 sql_expression
	|	subquery
	;

subquery
	:	LPAREN select_command RPAREN
	;

connect_clause
	:	( 'START' 'WITH' sql_condition )?
		'CONNECT' 'BY' 
		(	'PRIOR' sql_expression relational_op sql_expression
		|	sql_expression relational_op sql_expression 'PRIOR'
		)
		(	 ('PRIOR')? sql_condition
		|	sql_expression relational_op ( 'PRIOR' )? sql_expression ( 'AND' sql_condition )?
		)
		( 'START' 'WITH' sql_condition )?
	;

group_clause
	:	'GROUP' 'BY' sql_expression ( COMMA sql_expression )* ( 'HAVING' sql_condition )?
	;

set_clause
	:	( ( 'UNION' 'ALL' ) | 'INTERSECT' | 'MINUS' ) select_command 
	;

order_clause
	:	keyORDER 'BY' sorted_def ( COMMA sorted_def )*
	;

sorted_def
	:	(  sql_expression |  NUMBER ) ( 'ASC' | 'DESC' )?
	;

update_clause
	:	'FOR' 'UPDATE' ( 'OF' column_name ( COMMA column_name )* )? ( 'NOWAIT' )?
	;

insert_command
	:	'INSERT' 'INTO' table_reference_list
		( LPAREN column_specs RPAREN )?
		(
                    (	'VALUES' LPAREN plsql_expressions RPAREN
                    |	select_statement
                    )
                    | LPAREN? select_command RPAREN?
                )    
		( returning_clause )?
	;

update_command
	:	'UPDATE' selected_table
		'SET' 
		(	update_nested_column_specs
		|	update_column_specs
		)
		(	'WHERE'
			(	keyCURRENT_OF cursor_name
			|	sql_condition
			)
		)?
		( returning_clause )?
	;

update_column_specs
	:	update_column_spec ( COMMA update_column_spec )*
	;

update_column_spec
	:	column_spec EQ sql_expression
	;

update_nested_column_specs
	:	update_nested_column_spec ( COMMA update_nested_column_spec )*
	;

update_nested_column_spec
	:	LPAREN column_specs RPAREN EQ subquery
	;

delete_command
	:	'DELETE' ( 'FROM' )? selected_table
		(	'WHERE'
			(	keyCURRENT_OF cursor_name
			|	sql_condition
			)
		)?
		( returning_clause )?
	;

returning_clause
	:	( keyRETURN | keyRETURNING ) select_list ( keyBULK keyCOLLECT )? 'INTO' lvalues
	;

set_transaction_command
	:	'SET' keyTRANSACTION keyREAD (keyONLY | keyWRITE)
	;

close_statement
	:	keyCLOSE cursor_name
	;

pipe_statement
	:	('PIPE' | 'pipe') ('ROW' | 'row') LPAREN (sql_identifier | function_call) RPAREN
	;

fetch_statement
	:	'FETCH' cursor_name ('BULK' 'COLLECT')? 'INTO' 
		(	variable_names
		|	record_name
		)
                ('LIMIT' NUMBER) ?
	;

lock_table_statement
	:	'LOCK' 'TABLE' table_reference_list
		'IN' lock_mode 'MODE' ( 'NOWAIT' )?
	;

lock_mode
	:	'ROW' 'SHARE'
	|	'ROW' 'EXCLUSIVE'
	|	'SHARE' 'UPDATE'
	|	'SHARE'
	|	'SHARE' 'ROW' 'EXCLUSIVE'
	|	'EXCLUSIVE'
	;

open_statement
	:	keyOPEN cursor_name ( LPAREN plsql_expressions RPAREN )?
	;

open_statement2
	:	keyOPEN cursor_name 'FOR' (select_command | ( (sql_identifier | quoted_string) (keyUSING column_spec ( COMMA column_spec )*)?  ) ) 
	;

rollback_statement
	:	keyROLLBACK ( keyWORK )?
		( 'TO' ( 'SAVEPOINT' )? savepoint_name )?
		( 'COMMENT' quoted_string )?
	;

savepoint_statement
	:	'SAVEPOINT' savepoint_name
	;

savepoint_name
	:	identifier
	;

identifier
	:	ID
	|	DOUBLEQUOTED_STRING 
//	|	keyword
   	;

quoted_string
	:	QUOTED_STRING
	;

match_string
	:	QUOTED_STRING
	;
keyA                             : {"A".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyAUTOMATIC                     : {"AUTOMATIC".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyBy                            : {"BY".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyCOUNT                         : {"COUNT".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyCROSS                         : {"CROSS".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyCUBE                          : {"CUBE".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyCURRENT_OF                    : {"CURRENT_OF".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyDAY                           : {"DAY".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyDBTIMEZONE                    : {"DBTIMEZONE".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyDECREMENT                     : {"DECREMENT".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyDIMENSION                     : {"DIMENSION".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyEMPTY                         : {"EMPTY".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyEQUALS_PATH                   : {"EQUALS_PATH".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyESCAPE                        : {"ESCAPE".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyFIRST                         : {"FIRST".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyFULL                          : {"FULL".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyGROUPING                      : {"GROUPING".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyIGNORE                        : {"IGNORE".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyINCREMENT                     : {"INCREMENT".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyINFINITE                      : {"INFINITE".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyINNER                         : {"INNER".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyINTERVAL                      : {"INTERVAL".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyITERATE                       : {"ITERATE".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyJOIN                          : {"JOIN".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyKEEP                          : {"KEEP".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyLAST                          : {"LAST".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyLEFT                          : {"LEFT".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyLIKE2                         : {"LIKE2".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyLIKE4                         : {"LIKE4".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyLIKEC                         : {"LIKEC".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyLOCAL                         : {"LOCAL".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyMAIN                          : {"MAIN".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyMEASURES                      : {"MEASURES".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyMEMBER                        : {"MEMBER".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyMODEL                         : {"MODEL".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyMONTH                         : {"MONTH".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyNAN                           : {"NAN".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyNATURAL                       : {"NATURAL".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyNAV                           : {"NAV".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyNOCYCLE                       : {"NOCYCLE".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyNULLS                         : {"NULLS".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyONLY                          : {"ONLY".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyWRITE                         : {"WRITE".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyORDER                         : {"ORDER".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyOUTER                         : {"OUTER".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyPARTITION                     : {"PARTITION".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyPRECISION                     : {"PRECISION".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyPRESENT                       : {"PRESENT".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyREFERENCE                     : {"REFERENCE".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyREGEXP_LIKE                   : {"REGEXP_LIKE".equals((this._input).LT(1).getText().toUpperCase())}? ID;
//keyRETURN                        : {"RETURN".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyRIGHT                         : {"RIGHT".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyROLLUP                        : {"ROLLUP".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyRULES                         : {"RULES".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keySECOND                        : {"SECOND".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keySECONDS                       : {"SECONDS".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keySEQUENTIAL                    : {"SEQUENTIAL".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keySESSIONTIMEZONE               : {"SESSIONTIMEZONE".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keySETS                          : {"SETS".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keySIBLINGS                      : {"SIBLINGS".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keySINGLE                        : {"SINGLE".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keySOME                          : {"SOME".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keySUBMULTISET                   : {"SUBMULTISET".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyTIME                          : {"TIME".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyTIMESTAMP                     : {"TIMESTAMP".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyTHE                           : {"THE".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyUNDER_PATH                    : {"UNDER_PATH".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyUNTIL                         : {"UNTIL".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyUPDATED                       : {"UPDATED".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyUPDATE                        : {"UPDATE".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyUPSERT                        : {"UPSERT".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyWAIT                          : {"WAIT".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyYEAR                          : {"YEAR".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyZONE                          : {"ZONE".equals((this._input).LT(1).getText().toUpperCase())}? ID;

keyARRAY                         : {"ARRAY".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyAUTONOMOUS_TRANSACTION        : {"AUTONOMOUS_TRANSACTION".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyBODY                          : {"BODY".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyBUILTIN                       : {"BUILTIN".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyBULK                          : {"BULK".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyBYTE                          : {"BYTE".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyCLOSE                         : {"CLOSE".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyCOLLECT                       : {"COLLECT".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyCURSOR                        : 'CURSOR'; //{"CURSOR".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyELSIF                         : {"ELSIF".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyEXCEPTION_INIT                : {"EXCEPTION_INIT".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyEXIT                          : {"EXIT".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyFIPSFLAG                      : {"FIPSFLAG".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyFUNCTION                      : 'FUNCTION'; //{"FUNCTION".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyINTERFACE                     : {"INTERFACE".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyLOOP                          : 'LOOP'; //{"LOOP".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyNEW                           : {"NEW".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyNEW_NAMES                     : {"NEW_NAMES".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyOPEN                          : {"OPEN".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyOUT                           : 'OUT'; //{"OUT".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyPACKAGE                       : 'PACKAGE'; //{"PACKAGE".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyPRAGMA                        : 'PRAGMA'; //{"PRAGMA".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyRAISE                         : {"RAISE".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyOVER                          : {"OVER".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyRANGE                         : {"RANGE".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyREAD                          : {"READ".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyRECORD                        : {"RECORD".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyREF                           : {"REF".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyREPLACE                       : {"REPLACE".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyRESTRICT_REFERENCES           : {"RESTRICT_REFERENCES".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyRETURN                        : 'RETURN'; //{"RETURN".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyRETURNING                     : 'RETURNING'; //{"RETURNING".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyREVERSE                       : {"REVERSE".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyROLLBACK                      : 'ROLLBACK'; //{"ROLLBACK".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keySERIALLY_REUSABLE             : {"SERIALLY_REUSABLE".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keySUBTYPE                       : {"SUBTYPE".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyTRANSACTION                   : {"TRANSACTION".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyTYPE                          : {"TYPE".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyUSING                         : {"USING".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyVARRAY                        : {"VARRAY".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyVARYING                      : {"VARYING".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyWHILE                         : 'WHILE'; //{"WHILE".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyWORK                          : {"WORK".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyWHEN                          : {"WHEN".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyMATCHED                       : {"MATCHED".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyTHEN                          : {"THEN".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyMERGE                          : {"MERGE".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyINTO                          : {"INTO".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyNOT                           : {"NOT".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keySET                           : {"SET".equals((this._input).LT(1).getText().toUpperCase())}? ID;
keyDELETE                        : {"DELETE".equals((this._input).LT(1).getText().toUpperCase())}? ID;




sql_identifier
	:	identifier
	|	'ROWID'
//	|	'ROWNUM'
	;

QUOTED_STRING
	:	( 'n' )? '\'' ( '\'\'' | ~('\'') )* '\''
	;
ID /*options { testLiterals=true; }*/
    :	('A' .. 'Z' | 'a' .. 'z') ( 'A' .. 'Z'  | 'a' .. 'z' | '0' .. '9' | '_' | '$' | '#' )*
    |	DOUBLEQUOTED_STRING
    ;
SEMI
	:	';'
	;
COLON
	:	':'
	;
DOUBLEDOT
	:	POINT POINT
	;
DOT
	:	POINT
	;
fragment
POINT
	:	'.'
	;
COMMA
	:	','
	;
EXPONENT
	:	'**'
	;
ASTERISK
	:	'*'
	;
AT_SIGN
	:	'@'
	;
RPAREN
	:	')'
	;
LPAREN
	:	'('
	;
RBRACK
	:	']'
	;
LBRACK
	:	'['
	;
PLUS
	:	'+'
	;
MINUS
	:	'-'
	;
DIVIDE
	:	'/'
	;
EQ
	:	'='
	;
PERCENTAGE
	:	'%'
	;
LLABEL
	:	'<<'
	;
RLABEL
	:	'>>'
	;
ASSIGN
	:	':='
	;
ARROW
	:	'=>'
	;
VERTBAR
	:	'|'
	;
DOUBLEVERTBAR
	:	'||'
	;
NOT_EQ
	:	'<>' | '!=' | '^='
	;
LTH
	:	'<'
	;
LEQ
	:	'<='
	;
GTH
	:	'>'
	;
GEQ
	:	'>='
	;
NUMBER
	:	//( PLUS | MINUS )?
		(	 N POINT N
		|	POINT N
		|	N
		)
		( 'E' ( PLUS | MINUS )? N )?
    ;
fragment
N
	: '0' .. '9' ( '0' .. '9' )*
	;
QUOTE
	:	'\''
	;
//fragment
DOUBLEQUOTED_STRING
	:	'"' ( ~('"') )* '"'
	;
WS	:	(' '|'\r'|'\t'|'\n') -> channel(HIDDEN)
	;
SL_COMMENT
	:	'--' ~('\n'|'\r')* '\r'? '\n' -> channel(HIDDEN)
	;
ML_COMMENT
	:	'/*' .*? '*/' -> channel(HIDDEN)
	;
TYPE_ATTR
	:	'%' ('T'|'t')('Y'|'y')('P'|'p')('E'|'e')
	;
ROWTYPE_ATTR
	:	'%ROWTYPE' | '%rowtype'
	;
NOTFOUND_ATTR
	:	'%NOTFOUND' | '%notfound'
	;
FOUND_ATTR
	:	'%FOUND'
	;
ISOPEN_ATTR
	:	'%ISOPEN'
	;
ROWCOUNT_ATTR
	:	'%ROWCOUNT'
	;
BULK_ROWCOUNT_ATTR
	:	'%BULK_ROWCOUNT'
	;
CHARSET_ATTR
	:	'%CHARSET'
	;


/***
 * Excerpted from "The Definitive ANTLR 4 Reference",
 * published by The Pragmatic Bookshelf.
 * Copyrights apply to this code. It may not be used to create training material, 
 * courses, books, articles, and the like. Contact us if you are in doubt.
 * We make no guarantees that this code is fit for any purpose. 
 * Visit http://www.pragmaticprogrammer.com/titles/tpantlr2 for more book information.
 ***/
import java.io.File;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;


import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.BailErrorStrategy;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.misc.MultiMap;
import org.antlr.v4.runtime.misc.NotNull;
import org.antlr.v4.runtime.misc.OrderedHashSet;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.bouncycastle.crypto.RuntimeCryptoException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.stringtemplate.v4.ST;

import cfi.BaseTest;

public class CallGraph3 {

	public final static Set<String> ignoreFuncSpSet = new HashSet<String>();
	static String currentPkgName = null;

	static {
		ignoreFuncSpSet.add("TO_DATE");
		ignoreFuncSpSet.add("LENGTH");
		ignoreFuncSpSet.add("NVL");
		ignoreFuncSpSet.add("TO_CHAR");
		ignoreFuncSpSet.add("SUBSTR");
		ignoreFuncSpSet.add("TO_NUMBER");
		ignoreFuncSpSet.add("LTRIM");
		ignoreFuncSpSet.add("RTRIM");
		ignoreFuncSpSet.add("SUM");
		ignoreFuncSpSet.add("MIN");
		ignoreFuncSpSet.add("UPPER");
		ignoreFuncSpSet.add("TRIM");
		ignoreFuncSpSet.add("COUNT");
		ignoreFuncSpSet.add("TRUNC");
		ignoreFuncSpSet.add("ADD_MONTHS");
		ignoreFuncSpSet.add("DBMS_OUTPUT.PUT_LINE");
		ignoreFuncSpSet.add("RPAD");
		ignoreFuncSpSet.add("LPAD");
		ignoreFuncSpSet.add("CHR");
		ignoreFuncSpSet.add("ROUND");
		ignoreFuncSpSet.add("DECODE");
		ignoreFuncSpSet.add("LAST_DAY");
		ignoreFuncSpSet.add("NEXT_DAY");
		ignoreFuncSpSet.add("MAX");
		ignoreFuncSpSet.add("INSTR");
		ignoreFuncSpSet.add("MOD");
		ignoreFuncSpSet.add("FLOOR");
		ignoreFuncSpSet.add("ABS");
		ignoreFuncSpSet.add("SIGN");
		ignoreFuncSpSet.add("MONTHS_BETWEEN");
		ignoreFuncSpSet.add("AVG");
		ignoreFuncSpSet.add("LOWER");
		ignoreFuncSpSet.add("SYSDATE");
		ignoreFuncSpSet.add("REPLACE");
	}

	/**
	 * A graph model of the output. Tracks call from one function to another by
	 * mapping function to list of called functions. E.g., f -> [g, h] Can dump
	 * DOT two ways (StringBuilder and ST). Sample output: digraph G { ... setup
	 * ... f -> g; g -> f; g -> h; h -> h; }
	 */
	static class Graph {
		// I'm using org.antlr.v4.runtime.misc: OrderedHashSet, MultiMap
		Set<Node> nodes = new OrderedHashSet<Node>(); // list of functions
		MultiMap<String, Node> edges = // caller->callee
		new MultiMap<String, Node>();

		BaseTest baseTest = new BaseTest();
		JdbcTemplate jdbcTemplate = baseTest.getJdbcTemplate(baseTest
				.getConn(BaseTest.INT));

		public void edge(String source, Node target) {
			edges.map(source, target);
		}

		public String toString() {
			return "edges: " + edges.toString() + ", functions: " + nodes;
		}

		public String saveDOTInfo() {

			StringBuilder buf = new StringBuilder();
			StringBuilder edgeBuf = new StringBuilder();

			System.out.println("===currentPkgName:" + currentPkgName);
			if (!StringUtils.isEmpty(currentPkgName)) {
				jdbcTemplate.update("delete from CALLDIC where scope = ?",
						currentPkgName);
			}

			for (Node node : nodes) {
				String type = node.getType();
				if (type.equals("procedure")) {
					String procFullName = node.getName().replace("\"", "")
							.replace("'", "");
					String scope = procFullName.split("\\.")[0];
					String obj = procFullName.split("\\.")[1];
					jdbcTemplate
							.update("delete from CALLDIC where scope = ? and obj = ? and type = ?",
									scope, obj, type);
					jdbcTemplate
							.update("insert into CALLDIC(type, scope, obj, line) values(?, ?, ?, ?)",
									type, scope, obj, node.getLineNum());
					jdbcTemplate
							.update("delete from CALLRELATION where scope1 = ? and obj1 = ? and scope1_file_TYPE = ?",
									scope, obj, type);
				} else if (type.equals("package")) {
					// package
					jdbcTemplate
							.update("insert into CALLDIC(type, scope, obj, line) values(?, ?, ?, ?)",
									type, currentPkgName, node.getName(),
									node.getLineNum());
					jdbcTemplate
							.update("delete from CALLRELATION where scope1 = ? and scope1_file_TYPE = ?",
									currentPkgName, type);
				} else if (type.equals("sp/function")) {
					// sp/function
					if(StringUtils.isEmpty(node.getScope())) {
						String nodeName = node.getName();
						nodeName = nodeName.replace("\"", "");
						node.setScope(nodeName.substring(0, nodeName.indexOf(".")));
						node.setName(nodeName.substring(nodeName.indexOf(".") + 1));
					}
					System.out.println("node.getScope():" + node.getScope() + " node.getName():" + node.getName());
					jdbcTemplate
							.update("delete from  CALLDIC where scope = ? and obj = ?",
									node.getScope(), node.getName());
					jdbcTemplate
					.update("insert into CALLDIC(type, scope, obj, line) values(?, ?, ?, ?)",
							type, node.getScope(), node.getName(),
							node.getLineNum());
					jdbcTemplate
							.update("delete from CALLRELATION where scope1 = ? and obj1 = ?",
									node.getScope(), node.getName());
				} else if (type.equals("table")) {
					jdbcTemplate.update("delete from calldic where obj = ?",
							node.getName());
					jdbcTemplate
							.update("insert into CALLDIC(type, scope, obj, line) values(?, ?, ?, ?)",
									type, node.getScope(), node.getName(), node.getLineNum());
				} else {
					throw new RuntimeCryptoException("unknow type:" + type);
				}
			}

			for (String src : edges.keySet()) {
				for (Node oneEdgeNode : edges.get(src)) {
					edgeBuf.append("  ");
					edgeBuf.append('\"' + src + '\"');
					edgeBuf.append(" -> ");
					edgeBuf.append('\"' + oneEdgeNode.getName() + '\"');
					edgeBuf.append(";\n");

					String scope1 = null;
					String obj1 = null;
					String scope2 = "";
					String obj2 = "";
					String remark = "";
					int line2 = 0;

					String type = null;
					if (StringUtils.isEmpty(currentPkgName)) {
						type = "procedure";
					} else {
						type = "package";
//						jdbcTemplate.update(
//								"delete from CALLDIC where scope = ?",
//								currentPkgName);
					}

					if (type.equals("procedure")) {
						String procFullName = src.replace("\"", "").replace(
								"'", "");
						scope1 = procFullName.split("\\.")[0];
						obj1 = procFullName.split("\\.")[1];
					} else {
						scope1 = currentPkgName;
						obj1 = src;
					}

					if (oneEdgeNode.getName().contains(".")) {
						String[] obj2Arr = oneEdgeNode.getName().split("\\.");
						for (int i = 0; i < obj2Arr.length - 1; i++) {
							scope2 += obj2Arr[i];
							if (i != obj2Arr.length - 2) {
								scope2 += ".";
							}
						}

						obj2 = obj2Arr[obj2Arr.length - 1];
					} else {
						scope2 = "";
						obj2 = oneEdgeNode.getName();
					}
					line2 = oneEdgeNode.getLineNum();

					CallRelation callRel = new CallRelation(scope1, obj1,
							scope2, obj2, line2, remark);

					int maxId = jdbcTemplate
							.queryForInt("select max(id) from CALLRELATION");
					String sql = "INSERT INTO CALLRELATION (ID, OBJ1, OBJ2, SCOPE1, SCOPE2, line2, REMARK, scope1_file_TYPE, scope2_file_TYPE, obj2_action) VALUES (?, ? , ? ,?, ?,?, ?, ?, ?, ?)";
					System.out.println("sql:" + sql);
					System.out.println("callRel:" + callRel);
					
					jdbcTemplate.update(sql, maxId + 1, callRel.getObj1(),
							callRel.getObj2(), callRel.getScope1(),
							callRel.getScope2(), callRel.getLine2(),
							callRel.getRemark(), type, oneEdgeNode.getType(),
							oneEdgeNode.getAction());

				}
			}

			buf.append(edgeBuf);
			// buf.append(getSubGraphStr());
			// subgraph
			buf.append("\n}\n");
			return buf.toString();
		}

		/**
		 * Fill StringTemplate: digraph G { rankdir=LR; <edgePairs:{edge|
		 * <edge.a> -> <edge.b>;}; separator="\n"> <childless:{f | <f>;};
		 * separator="\n"> }
		 * 
		 * Just as an example. Much cleaner than buf.append method
		 */
		public ST toST() {
			ST st = new ST(
					"digraph G {\n"
							+ "  ranksep=.25; \n"
							+ "  edge [arrowsize=.5]\n"
							+ "  node [shape=circle, fontname=\"ArialNarrow\",\n"
							+ "        fontsize=12, fixedsize=true, height=.45];\n"
							+ "  <funcs:{f | <f>; }>\n"
							+ "  <edgePairs:{edge| <edge.a> -> <edge.b>;}; separator=\"\\n\">\n"
							+ "}\n");
			st.add("edgePairs", edges.getPairs());
			st.add("funcs", nodes);
			return st;
		}
	}

	static class SpFuncListener extends PlsqlBaseListener {
		Graph graph = new Graph();
		String currentFuncSpName = null;

		@Override
		public void enterPackage_spec(
				@NotNull PlsqlParser.Package_specContext ctx) {
			super.enterPackage_spec(ctx);
			CallGraph3.currentPkgName = ctx.package_name().get(0).getText()
					.replace("\"", "").replace("'", "");
			System.out.println("enterPackage_name1:"
					+ CallGraph3.currentPkgName);
		}

		@Override
		public void enterPackage_body(
				@NotNull PlsqlParser.Package_bodyContext ctx) {
			super.enterPackage_body(ctx);
			CallGraph3.currentPkgName = ctx.package_name().get(0).getText()
					.replace("\"", "").replace("'", "");
			System.out.println("enterPackage_name2:"
					+ CallGraph3.currentPkgName);
		}

		@Override
		public void enterProcedure_body(
				@NotNull PlsqlParser.Procedure_bodyContext ctx) {
			super.enterProcedure_body(ctx);
			currentFuncSpName = ctx.procedure_name().get(0).getText();
			System.out
					.println("============================enterSp currentSpName:"
							+ currentFuncSpName);
			graph.nodes.add(new Node(CallGraph3.currentPkgName, currentFuncSpName, ctx.start.getLine(),
					"sp/function", "call"));
		}

		@Override
		public void enterFunction_body(
				@NotNull PlsqlParser.Function_bodyContext ctx) {
			super.enterFunction_body(ctx);
			currentFuncSpName = ctx.function_name().get(0).getText();
			System.out
					.println("============================enterFuction currentFunctionName:"
							+ currentFuncSpName);
			graph.nodes.add(new Node(CallGraph3.currentPkgName, currentFuncSpName, ctx.start.getLine(),
					"sp/function", "call"));
		}

		@Override
		public void exitInsert_command(
				@NotNull PlsqlParser.Insert_commandContext ctx) {
			super.enterInsert_command(ctx);
			List<PlsqlParser.Selected_tableContext> tableCtxList = ctx
					.table_reference_list().selected_table();
			for (int i = 0; i < tableCtxList.size(); i++) {
				PlsqlParser.Selected_tableContext oneTableCtx = tableCtxList
						.get(i);
				String oneTableName = oneTableCtx.table_spec().getText();
				int line = oneTableCtx.start.getLine();
				System.out.println("insert table tableCtxList:" + oneTableName
						+ " line:" + line);
				graph.edge(currentFuncSpName, new Node("", oneTableName, line,
						"table", "insert"));

				graph.nodes.add(new Node("", oneTableName, 0, "table", "insert"));
			}
		}

		@Override
		public void exitDelete_command(
				@NotNull PlsqlParser.Delete_commandContext ctx) {
			super.exitDelete_command(ctx);
			PlsqlParser.Selected_tableContext tableCtx = ctx.selected_table();
			String oneTableName = tableCtx.table_spec().getText();
			int line = tableCtx.start.getLine();
			System.out.println("delete table tableCtxList:" + oneTableName
					+ " line:" + line);
			graph.edge(currentFuncSpName, new Node("", oneTableName, line, "table",
					"delete"));

			graph.nodes.add(new Node("", oneTableName, 0, "table", "delete"));
		}

		@Override
		public void exitUpdate_command(
				@NotNull PlsqlParser.Update_commandContext ctx) {
			super.exitUpdate_command(ctx);
			PlsqlParser.Selected_tableContext tableCtx = ctx.selected_table();
			String oneTableName = tableCtx.table_spec().getText();
			int line = tableCtx.start.getLine();
			System.out.println("update table tableCtxList:" + oneTableName
					+ " line:" + line);
			graph.edge(currentFuncSpName, new Node("", oneTableName, line, "table",
					"update"));

			graph.nodes.add(new Node("", oneTableName, 0, "table", "update"));
		}

		@Override
		public void exitSelect_expression(
				@NotNull PlsqlParser.Select_expressionContext ctx) {
			super.exitSelect_expression(ctx);
			List<PlsqlParser.Selected_tableContext> tableCtxList = ctx
					.table_reference_list().selected_table();
			for (int i = 0; i < tableCtxList.size(); i++) {
				PlsqlParser.Selected_tableContext oneTableCtx = tableCtxList
						.get(i);
				PlsqlParser.Table_specContext oneTableSpec = oneTableCtx.table_spec(); 
				if(oneTableSpec == null) {
					continue;
				}
				String oneTableName = oneTableSpec.getText();
				int line = oneTableCtx.start.getLine();
				System.out.println("select table tableCtxList:" + oneTableName
						+ " line:" + line);
				
				String invoker = currentFuncSpName;
				if(StringUtils.isEmpty(currentFuncSpName)) {
					invoker = currentPkgName;
				}
				graph.edge(invoker, new Node("", oneTableName, line,
						"table", "select"));

				graph.nodes.add(new Node("", oneTableName, 0, "table", "select"));
			}

		}

		@Override
		public void exitFunction_call(
				@NotNull PlsqlParser.Function_callContext ctx) {
			super.exitFunction_call(ctx);

			String funcSpName = ctx.user_defined_function().getText();
			System.out.println("exitCall funcName:" + funcSpName
					+ " ctx.start.getLine():" + ctx.start.getLine());
			// map current function to the callee
			if (!ignoreFuncSpSet.contains(funcSpName)) {
				// System.out.println("exitCall funcSpName:" + funcSpName +
				// " ctx.start.getLine():" + ctx.start.getLine());
				graph.edge(currentFuncSpName,
						new Node("", funcSpName, ctx.start.getLine(), "sp/funtion",
								"call"));
			}
		}

	}

	public static void main(String[] args) throws Exception {
		long time1 = System.currentTimeMillis();

		// String dirName = "spDir";
		 String dirName =
		 "C:/ccsnapshot_views/localDEV_tls_fundmsg_01.00.05_pchz_2/tls02/tls_fundmsg/src/research/SpaWeb/public/spPkg/jdbc_oracle_thin_@XXXXXXXXXXXXXXX"; //procedure
//		String dirName = "C:/Documents and Settings/xxxxxxxxxxxx/Desktop/draft/spa/testfile";

		File dir = new File(dirName);
		String[] extensions = { "sp" };
		Collection<File> files = FileUtils.listFiles(dir, extensions, true);

		for (Iterator<File> iterator = files.iterator(); iterator.hasNext();) {
			CallGraph3.currentPkgName = null;
			File file = iterator.next();
			System.out.println("deal file:" + file.getName());
			String content = FileUtils.readFileToString(file, "UTF-8");
			content = content.toUpperCase();
			// ANTLRInputStream input = new ANTLRInputStream(is);
			ANTLRInputStream input = new ANTLRInputStream(content);
			PlsqlLexer lexer = new PlsqlLexer(input);
			CommonTokenStream tokens = new CommonTokenStream(lexer);
			PlsqlParser parser = new PlsqlParser(tokens);
			parser.setBuildParseTree(true);

			parser.setErrorHandler(new BailErrorStrategy());

			ParseTree tree = parser.start_rule();
			// show tree in text form
			// System.out.println(tree.toStringTree(parser));

			ParseTreeWalker walker = new ParseTreeWalker();
			SpFuncListener collector = new SpFuncListener();
			walker.walk(collector, tree);
			System.out.println("==================");
			System.out.println("collector.graph.toString():"
					+ collector.graph.toString());
			System.out.println("==================");
			// String dotStr = collector.graph.toDOT();

			String dotStr = collector.graph.saveDOTInfo();
			System.out.println("currentPkgName:" + currentPkgName);
			System.out.println("============dotStr begin============");
			System.out.println(dotStr);
			System.out.println("============dotStr end============");
			FileUtils
					.writeStringToFile(new File("src/dot.gv"), dotStr, "UTF-8");

			// Here's another example that uses StringTemplate to generate
			// output
			// System.out.println(collector.graph.toST().render());

		}
		
		main1(null);

		long time2 = System.currentTimeMillis();
		System.out.println("time:" + (time2 - time1));
	}
	
	public static void main1(String[] args) {
		
		BaseTest baseTest = new BaseTest();
		JdbcTemplate jdbcTemplate = baseTest.getJdbcTemplate(baseTest
				.getConn(BaseTest.INT));
		jdbcTemplate.update("update calldic set id = rownum");
		
		Class elementType = String.class;
		List<String> userList = jdbcTemplate.queryForList(
				"SELECT username FROM ALL_USERS order by username",
				elementType);
		Set<String> userSet = new HashSet<String>();
		for (int i = 0; i < userList.size(); i++) {
			userSet.add(userList.get(i));
		}
		
		List<CallDic> dicList = null;
		dicList = jdbcTemplate.query("select * from  calldic where scope is null", new ItemMapper());
//		System.out.println(dicList);
		
		for (int i = 0; i < dicList.size(); i++) {
			CallDic oneDic = dicList.get(i);
			String oneObj = oneDic.getObj();
			String[] oneObjs = oneObj.split("\\.");
			
			if(userSet.contains(oneObjs[0])) {
				String destScope = oneObjs[0];
				String destObj = "";
				for (int j = 1; j < oneObjs.length; j++) {
					destObj += oneObjs[j];
					if(j != oneObjs.length - 1) {
						destObj += ".";
					}
				}
				jdbcTemplate.update("update calldic set scope = ?, obj = ? where id = ?", destScope, destObj, oneDic.getId());
			}
			
		}
		
		Map<String, String> synonyMap = new HashMap<String, String>();
		List<String> synonymList = jdbcTemplate.queryForList(
				"select SYNONYM_NAME || '####' || table_owner || '.' || table_name from SYS.all_synonyms",
				elementType);
		for (int i = 0; i < synonymList.size(); i++) {
			String[] synonyms = synonymList.get(i).split("####");
			synonyMap.put(synonyms[0], synonyms[1]);
		}
		
		dicList = jdbcTemplate.query("select * from  calldic where scope is null", new ItemMapper());
//		System.out.println(dicList);
		
		for (int i = 0; i < dicList.size(); i++) {
			CallDic oneDic = dicList.get(i);
			String oneObj = oneDic.getObj();
			String synonyValue = synonyMap.get(oneObj);
			if(synonyValue != null) {
				jdbcTemplate.update("update calldic set name2 = ? where id = ?", synonyValue, oneDic.getId());
			}
			
		}
		
		
	}
}

class ItemMapper implements RowMapper {
	@Override
	public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
		CallDic callDic = new CallDic(rs.getString("scope"), rs.getString("obj"));
		callDic.setId(rs.getInt("id"));
		return callDic;
	}
}





import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;



public class CallDic {
	int id;
	String scope;
	String obj;
	
	public CallDic(String scope, String obj) {
		super();
		this.scope = scope;
		this.obj = obj;
	}
	
	public String getScope() {
		return scope;
	}
	public void setScope(String scope) {
		this.scope = scope;
	}
	public String getObj() {
		return obj;
	}
	public void setObj(String obj) {
		this.obj = obj;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}
	
	@Override
	public String toString() {
		return ToStringBuilder.reflectionToString(this, ToStringStyle.SIMPLE_STYLE);
	}

}



import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;




public class CallRelation  {
    
    public String scope1;

    
    public String obj1;

    
    public String scope2;
    
    
    public String obj2;
    
    public int line2;
    public String remark;
    
	public CallRelation(String scope1, String obj1, String scope2, String obj2, int line2,
			String remark) {
		super();
		this.scope1 = scope1;
		this.obj1 = obj1;
		this.scope2 = scope2;
		this.obj2 = obj2;
		this.line2 = line2;
		this.remark = remark;
	}

	public int getLine2() {
		return line2;
	}

	public void setLine2(int line2) {
		this.line2 = line2;
	}

	public String getScope1() {
		return scope1;
	}

	public void setScope1(String scope1) {
		this.scope1 = scope1;
	}

	public String getObj1() {
		return obj1;
	}

	public void setObj1(String obj1) {
		this.obj1 = obj1;
	}

	public String getScope2() {
		return scope2;
	}

	public void setScope2(String scope2) {
		this.scope2 = scope2;
	}

	public String getObj2() {
		return obj2;
	}

	public void setObj2(String obj2) {
		this.obj2 = obj2;
	}

	public String getRemark() {
		return remark;
	}

	public void setRemark(String remark) {
		this.remark = remark;
	}
    
    @Override
    public String toString() {
    	return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
    }
    
}



import java.util.Set;

import org.antlr.v4.runtime.misc.OrderedHashSet;



public class Node {
	private String scope;
	private String name;
	private int lineNum;
	private String type;
	private String action;
	
	public Node(String scope, String name, int lineNum, String type, String action) {
		super();
		this.scope = scope;
		this.name = name;
		this.lineNum = lineNum;
		this.type = type;
		this.action = action;
	}
	
	public Node(String name, int lineNum) {
		super();
		this.name = name;
		this.lineNum = lineNum;
	}
	
	public String getScope() {
		return scope;
	}

	public void setScope(String scope) {
		this.scope = scope;
	}

	public String getAction() {
		return action;
	}

	public void setAction(String action) {
		this.action = action;
	}

	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getLineNum() {
		return lineNum;
	}
	public void setLineNum(int lineNum) {
		this.lineNum = lineNum;
	}
	
	public String getType() {
		return type;
	}
	public void setType(String type) {
		this.type = type;
	}
	@Override
	public String toString() {
		return "scope:" + scope + "	name:" + this.name + " lineNum:" + this.lineNum + " type:" + this.type + " action:" + action;
	}
	
	@Override
	public boolean equals(Object obj) {
		if(!(obj instanceof Node)) {
			return false;
		}
		Node node = (Node)obj;
		return this.name.equals(node.name);
	}
	
	@Override
	public int hashCode() {
		return 1;
	}
	
	public static void main(String[] args) {
		Set<Node> nodes = new OrderedHashSet<Node>();
		nodes.add(new Node("abc", 0));
		System.out.println(nodes.size());
		nodes.add(new Node("abd", 0));
		nodes.add(new Node("abd", 0));
		nodes.add(new Node("abd", 1));
		System.out.println(nodes.size());
	}
}




猜你喜欢

转载自zgq456.iteye.com/blog/2055729
SPA