`

SPA

    博客分类:
  • Java
 
阅读更多
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\jdbc_oracle_thin_@10.248.98.74_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 (thikone@gmail.com)
DATE:
		02-Jan-2008
BASED ON:
		PLSQLGrammar.g for ANTLR v2
		Qazi Firdous Ahmed (qazif_ahmed@infosys.com) 
		Krupa Benhur (krupa_bg@infosys.com)
		Manojaba Banerjee (manojaba_banerjee@infosys.com)
		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());
	}
}




分享到:
评论

相关推荐

    SPA-GUI使用手册

    SPA-GUI是一款在Matlab环境下运行的图形用户界面程序,它的目的是允许用户进行信号处理和变量选择,以便进行多变量校准。SPA-GUI是一个学术和非商业用途的自由软件。用户可以自由使用和重新分发该软件,但前提是不能...

    SPA-连续投影算法-教程版.zip

    **SPA(Singular Spectrum Analysis)连续投影算法** SPA(Singular Spectrum Analysis)是一种基于奇异值分解(SVD)的统计数据分析方法,常用于时间序列分析、信号处理和数据降维等场景。它通过分解时间序列矩阵...

    SPANet-master_spa注意力_spa注意力实现_SPANet_注意力机制_去雾_

    标题中的"SPANet-master_spa注意力_spa注意力实现_SPANet_注意力机制_去雾_"表明我们关注的是一个名为SPANet(Spatial Attention Network)的深度学习模型,它专注于利用注意力机制来处理图像去雾和去雨任务。...

    SPA会所网站源码

    SPA(拉丁语"Solus Par Agula",意为“健康之水”)通常指的是提供休闲、美容和健康护理的场所,而这个源码则提供了创建此类业务在线平台所需的基础架构。 在PHPWeb.net上,用户需要注册成为会员才能获取并使用这个...

    SPA_GUI.zip_GUI_SPA_GUI_spa GUI_连续投影_连续投影算法

    SPA(Sequential Projection Algorithm,连续投影算法)是一种在高维数据降维过程中常用的方法,它通过连续投影寻找数据的主要方向,从而降低数据的复杂性,便于后续的分析和可视化。GUI(Graphical User Interface...

    SPA-连续投影算法-教程版

    **SPA(Singular Projection Algorithm)连续投影算法**是一种在高维数据中进行降维的统计方法,常用于数据可视化和预处理。它属于主成分分析(PCA)的一种变体,旨在保留原始数据集的主要信息,同时减少计算复杂度...

    ABB_SPA通讯协议

    ABB_SPA通讯协议是一种专门用于ABB设备之间的串行通信协议,它支持SPA-BUS和RS485等物理层标准。SPA-BUS通信协议主要用于工业自动化的场景中,特别是在电力系统的继电保护和测控设备中应用广泛。该协议的设计使其能...

    紫色SPA按摩网站模板

    【紫色SPA按摩网站模板】是专为SPA按摩服务行业设计的一款独特且专业的单页HTML5页面模板。这款模板以其优雅的紫色调为主色,旨在营造一种舒缓、高雅的氛围,吸引潜在客户并提升品牌形象。在网页设计领域,HTML5是一...

    SPA提取特征_spa_光谱特征提取_连续投影算法;SPA;特征提取_spa提取_

    SPA提取特征,数据为高光谱数据,感兴趣区域数据,最后一列为标签

    超微X11SPA-TF主板用户手册

    ### 超微X11SPA-TF主板用户手册知识点详解 #### 一、前言与免责声明 在开始深入探讨超微X11SPA-TF主板的各项特性之前,我们需要了解制造商的一些基本声明与责任免除条款。 1. **文档准确性声明**:本用户手册中的...

    spa-eng.zip

    本篇将详细探讨由“spa-eng.zip”压缩包提供的西班牙语到英语的词汇对照表,该资源是机器翻译领域的宝贵素材,对于学习者、研究人员以及开发者来说具有极高的价值。 首先,我们要理解“spa-eng.zip”的核心内容。这...

    cisco linksys spa942 Firmware

    【Cisco Linksys SPA942固件】是Cisco Small Business系列IP电话中的一款关键软件组件,主要用于提升SPA942、SPA962以及SPA922型号电话的功能和性能。这款固件版本为6.1.5a,是Cisco官方发布的一个更新,旨在解决...

    SPA.zip_光谱_光谱分析_变量选择_波段选择_连续投影算法

    在光谱分析领域,理解和应用连续投影算法(Sequential Projection Algorithm, SPA)对于处理高维光谱数据至关重要。SPA是一种变量选择方法,常用于减少数据集中的特征数量,从而提高模型的解释性和预测性能,特别是...

    spa200504.zip

    标题"spa200504.zip"暗示了一个与SPA(Single Page Application,单页应用)相关的项目,可能是一个基于前端框架或库构建的应用。SPA是现代Web开发中常用的一种设计模式,它允许用户在不刷新整个页面的情况下,通过...

    ORACLE DB升级性能保障利器SPA最佳实践

    标题和描述中提到的知识点主要集中在Oracle数据库升级过程中如何使用性能保障工具SPA(SQL Performance Analyzer)来确保性能不受影响。SPA是Oracle提供的一个强大的性能监控和分析工具,专门用于评估数据库变更前后...

    SPA matlab程序

    **SPA(Singular Perturbation Analysis)在Matlab中的实现** SPA,全称为奇异摄动分析(Singular Perturbation Analysis),是一种在系统理论中用于处理快速和慢速动态过程的数学方法。在Matlab环境中,SPA程序...

    spa_spa_连续投影算法_变量筛选_特征筛选_featureselection

    **连续投影算法(Sequential Projection Algorithm, SPA)**是一种在机器学习和数据分析中广泛使用的特征选择方法,主要用于降低数据集的维度,去除冗余或不重要的特征,以提高模型的效率和准确性。它主要针对数值型...

    single-spa.zip

    《深入理解single-spa:构建微前端架构的基石》 在现代Web开发中,随着企业级应用复杂性的提升,单一的单页应用(SPA)架构已经无法满足需求。在这种背景下,微前端(Micro Frontend)架构应运而生,而single-spa则...

    个人学习实现源码 注释比较全面 基于single-spa实现的的 前端微服务架构 内部含有 single-spa不足技术点的解决方案 相关的具体实现教程 我

    在本文中,我们将深入探讨基于single-spa的前端微服务架构,这是一个强大的工具,用于构建模块化的大型前端应用。Single-spa 是一个JavaScript库,它允许我们构建可组合的前端应用,每个应用都可以独立开发、部署和...

Global site tag (gtag.js) - Google Analytics