ANTLR failure due to left recursion. How to solve? - recursion

Here is a simple grammar for an SQL select statement
grammar SQL;
#rulecatch {
//We want to stop parsing when SyntaxException is encountered
//So we re-throw the exception
catch (SyntaxException e) {
throw e;
}
}
eval
: sql_query
;
sql_query
: select_statement from_statement
| select_statement from_statement where_statement
;
select_statement
: 'select' attribute_list
;
from_statement
: 'from' table_name
;
where_statement
: 'where' attribute_name operator constant
;
attribute_list
: '*'
| attribute_name
| attribute_name ',' attribute_list?
;
table_name
: string_literal
;
attribute_name
: string_literal
;
operator
: '=' | '!=' | '>' | '>=' | '<' | '<='
;
constant
: INTEGER
| '"' string_literal '"'
;
fragment DIGIT: '0'..'9';
INTEGER: DIGIT+ ;
fragment LETTER: 'a'..'z'|'A'..'Z';
string_literal: LETTER | LETTER string_literal;
WS : (' ' | '\t' | '\n' | '\r' | '\f')+ {$channel=HIDDEN;};
The Tool is nagging about the sql_query definition as well as the attribute_list definition. Honestly I do not see any left recursion in my code to start with.
Could anyone explain what's going on?

No, ANTLR did not say your grammar is left recursive. It complained about the fact that some rules have non-LL(*) decisions due to recursive rule invocations. Rewrite the following rules as follows and you'll be alright:
sql_query
: select_statement from_statement where_statement?
;
attribute_list
: '*'
| attribute_name (',' attribute_list?)?
;

Related

How to remove error code and print only message | PLSQL

I have to print only error message and remove code number
BEGIN
IF :MY_TEXT is null THEN
raise_application_error(-20001,'Text field cannot be empty')
END IF;
Exception
when others then
:MSG := replace(SQLERRM,'^ORA-+:','');
END;
Expected output :
Text filed cannot be empty
You need to use something like this SUBSTR(MSG, INSTR(MSG, ':', 1, 1)+2 )
DECLARE
MY_TEXT VARCHAR2(100);
MSG VARCHAR2(100);
BEGIN
IF MY_TEXT is null THEN
raise_application_error(-20001,'Text field cannot be empty');
END IF;
Exception
when others then
MSG := SQLERRM ;
dbms_output.put_line( SUBSTR(MSG, INSTR(MSG, ':', 1, 1)+2 ) );
END;
/
You could also just change your REPLACE call to a REGEXP_REPLACE as it appears you were trying to use a regular expression to match the error:
:MSG := REGEXP_REPLACE(SQLERRM,'^ORA-[0-9]+: ', NULL);
Match a pattern of 'ORA-' at the start of the line, followed by 1 or digits, then a colon followed by a space and replace with NULL.
Note technically the ', NULL' is not needed in this call but including makes it clear to future maintainers what the intention is here and I would argue would be best practice.

grep entire text based on key words

i have a file consists of oracle select statements as given below.
select count(*) into v_cnt from table;
select
max(num) into v_max
from table2;
select numm from table3;
output is given below -
select count(*) into v_cnt from table;
select
max(num) into v_max
from table2;
i need help on grepping the select statements(from select keyword till semicolon) which has into key word. select statements may goes n number of rows. begining of line is select. ending of line is semicolon. in between these keywords if we have into text. then we need to capture the whole line. i am trying grep/awk statement. but i am not getting exaclty. multiple line select statements are breaking. Any ideas/suggestions from your end. Thanks in advance.
Perl to the rescue!
perl -0x3b -ne 'print if /\binto\b/'
-0x3b sets the record separator to character x3b, i.e. ;
-n reads the input record by record, running the code for each
\b matches a word boundary, so all records containing "into" that's not part of a longer word should be printed
If there are some commands that don't start with select and you want to skip them, change the condition to if /^select\b/m && /\binto\b/ (which can be incorporated into a single regex if /^select\b.*\binto\b/ms). To make the regexes case insensitive, add the /i modifier: /^select\b/mi.
Try this:
tr '\n' '~' < <Input file> | sed 's#;#\n#g' | grep -i 'select.*into.*' | tr '~' '\n'
Demo:
$cat file.txt
select count(*) into v_cnt from table;
select
max(num) into v_max
from table2;
select numm from table3;
$tr '\n' '~' < file.txt | sed 's#;#\n#g' | grep -i 'select.*into.*' | tr '~' '\n'
select count(*) into v_cnt from table
select
max(num) into v_max
from table2
$
With GNU awk for multi-char RS:
$ awk 'BEGIN{RS=ORS=";\n"} /into/' file
select count(*) into v_cnt from table;
select
max(num) into v_max
from table2;
With any awk:
$ awk -v RS=';' -v ORS=';\n' '/into/{sub(/^\n/,""); print}' file
select count(*) into v_cnt from table;
select
max(num) into v_max
from table2;
awk: issel remembers whether select lacked a ;:
{
if (issel = (issel || $0 ~ /select/)) print $0;
issel = !( $0 ~ /;/)
}

How to restrict special characters < and > in input value for a column

I am not that fluent in using regular expressions. I want that user should not provide value for a column with '<' or '>' in it.
Regards,
Sachin
Use group () and or | operators for example to validate user input you sould do:
set serveroutput on;
declare
l_value varchar2(32767) := '<p>test and data</p>';
begin
if regexp_like(l_value,'(<|>)','i') then
dbms_output.put_line('invalid');
else
dbms_output.put_line('valid');
end if;
end;
/
Good luck.
Use [ and ] to define a set of characters to match, e.g. [abc], [a-z], [a-z0-9_]
select string
, case
when regexp_like(string,'[<>]') then 'Invalid'
else 'Valid'
end as test
from
( select '<p>text</p>' as string from dual union all
select 'text' from dual );
STRING TEST
---------------- -------
<p>text</p> Invalid
text Valid
Or in PL/SQL:
declare
teststring varchar2(100) := '<p>test and data</p>';
regex varchar2(100) := '[<>]';
begin
dbms_output.put('"'||teststring||'"');
dbms_output.put(case when regexp_like(teststring,regex) then ' matches ' else ' does not match ' end );
dbms_output.put(regex);
dbms_output.new_line();
end;
/
"<p>test and data</p>" matches [<>]
PL/SQL procedure successfully completed
As a check constraint:
create table mytable
( col varchar2(20)
constraint mytable_ltgt_chk check ( not regexp_like(col,'[<>]') )
);
Test:
insert into mytable (col) values ('kitten > puppy');
rejected with:
ORA-02290: check constraint (MYRIAD_OWNER_82.MYTABLE_LTGT_CHK) violated
If you wanted to exclude square brackets as well, that would be:
constraint mytable_symbol_chk check ( not regexp_like(col,'[][<>]') );
Or without any regex:
constraint mytable_symbol_chk check ( col = translate(col,'[]<>','.') )
https://regex101.com/r/oQJztM/2/tests

How to format pumped file in Oracle SQL Developer in any way?

My problem is that I unloaded a table from Oracle db into a text file with the following code:
PACKAGE BODY:
procedure d_datapump (tab_name in varchar2,
def_dir in varchar2 default 'MY_DIR',
xt_location in varchar2)
is
d_query varchar2(10000);
d_result varchar2(10000);
begin
d_query := ' create table ' || tab_name || '_xt
organization external
(
type oracle_datapump
default directory ' || def_dir || '
location ( ' || chr(39) || xt_location || chr(39) || ' )
)
as
select * from ' || tab_name;
d_result := '';
dbms_output.put_line (d_query);
execute immediate d_query;
dbms_output.put_line (d_result);
end d_datapump;
thereafter the call:
begin
david_ext_table.d_datapump(tab_name => 'D_TEST_TABLE',
xt_location => 'test_pac.txt');
end;
And it worked, but the result in my txt is something like this:
"?xml...many xml parameters .../ROWSET"
"XXXXXYYYYYZZZZZ§§§§§00000< "XXXXXYYYYYZZZZZ§§§§§00000<
"XXXXXYYYYYZZZZZ§§§§§00000< "XXXXXYYYYYZZZZZ§§§§§00000<
But I would like to see something like this (without xml block):
col1 | col2 | col3 | col4 | col5
-------------------------------------
XXXXX | YYYYY | ZZZZZ | §§§§§ | 00000
XXXXX | YYYYY | ZZZZZ | §§§§§ | 00000
XXXXX | YYYYY | ZZZZZ | §§§§§ | 00000
I have spent hours browsing for a solution and the only things I could find the tons of suggestion to use spooling and UTL_FILE instead of this way, because the datapump is only for creating a binary file, but It is obviously not binary but an ordinary text file.
Is there any way to format it?

Antlr Mutual Left Recursion

I would like to parse something like
f()[3]()[3] ... () or []
meaning fucntions that return arrays, which can be referenced and may contain functions themselves.
I tried
functionCall: (ID | arrayReference) '(' expressionList? ')';
arrayReference: (ID | functionCall) '[' arithmeticExpression ']';
but get mutual recursion errors. Is there an easy way to solve this?
Like this:
value
: value '[' arithmeticExpression ']' # arrayReference
| value '(' expressionList? ')' # functionCall
| ID #id
;

Resources