Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 40eb166

Browse files
committed
Enhance annotation processing by improving SQL text handling and adding header stripping functionality
1 parent 2547b40 commit 40eb166

3 files changed

Lines changed: 71 additions & 96 deletions

File tree

source/core/annotations/ut_annotation_manager.pkb

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -231,23 +231,25 @@ create or replace package body ut_annotation_manager as
231231

232232
function get_source_from_sql_text(a_object_name varchar2, a_sql_text ora_name_list_t, a_parts binary_integer) return sys_refcursor is
233233
l_sql_clob clob;
234-
l_sql_lines ut_varchar2_rows := ut_varchar2_rows();
234+
l_sql_lines dbms_preprocessor.source_lines_t := dbms_preprocessor.source_lines_t();
235+
l_sql_lines_clob ut_varchar2_list := ut_varchar2_list();
235236
l_result sys_refcursor;
237+
l_replaced boolean := false;
236238
begin
237239
if a_parts > 0 then
238240
for i in 1..a_parts loop
239241
ut_utils.append_to_clob(l_sql_clob, a_sql_text(i));
240242
end loop;
241-
l_sql_clob := ut_utils.replace_multiline_comments(l_sql_clob);
242-
-- replace comment lines that contain "-- create or replace"
243-
l_sql_clob := regexp_replace(l_sql_clob, '^.*[-]{2,}\s*create(\s+or\s+replace).*$', modifier => 'mi');
244-
-- remove the "create [or replace] [[non]editionable] " so that we have only "type|package|procedure|function" for parsing
245-
-- needed for dbms_preprocessor
246-
l_sql_clob := regexp_replace(l_sql_clob, '^(.*?\s*create(\s+or\s+replace)?(\s+(editionable|noneditionable))?\s+?)((package|type|procedure|function).*)', '\5', 1, 1, 'ni');
247-
-- remove "OWNER." from create or replace statement.
248-
-- Owner is not supported along with AUTHID - see issue https://github.com/utPLSQL/utPLSQL/issues/1088
249-
l_sql_clob := regexp_replace(l_sql_clob, '^(package|type|procedure|function)\s+("?[[:alpha:]][[:alnum:]$#_]*"?\.)(.*)', '\1 \3', 1, 1, 'ni');
250-
l_sql_lines := ut_utils.convert_collection( ut_utils.clob_to_table(l_sql_clob) );
243+
244+
l_sql_lines_clob := ut_utils.clob_to_table(l_sql_clob);
245+
for i in 1..l_sql_lines_clob.count loop
246+
l_sql_lines(i) := l_sql_lines_clob(i);
247+
end loop;
248+
249+
-- replace multiline comments that contain "-- create or replace" with single line comment to avoid parsing issues with dbms_preprocessor
250+
l_sql_lines := ut_utils.replace_multiline_comments(l_sql_lines);
251+
-- strip CREATE header (possibly split across lines) while preserving line numbers
252+
l_sql_lines := ut_utils.strip_create_header_lines(l_sql_lines);
251253
end if;
252254
open l_result for
253255
select /*+ no_parallel */ a_object_name as name, column_value||chr(10) as text from table(l_sql_lines);

source/core/ut_utils.pkb

Lines changed: 50 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -812,94 +812,62 @@ create or replace package body ut_utils is
812812
return l_result;
813813
end replace_multiline_comments;
814814

815-
function replace_multiline_comments(a_source clob) return clob is
816-
l_result clob;
817-
l_ml_comment_start binary_integer := 1;
818-
l_comment_start binary_integer := 1;
819-
l_text_start binary_integer := 1;
820-
l_escaped_text_start binary_integer := 1;
821-
l_escaped_text_end_char varchar2(1 char);
822-
l_end binary_integer := 1;
823-
l_ml_comment clob;
824-
l_newlines_count binary_integer;
825-
l_offset binary_integer := 1;
826-
l_length binary_integer := coalesce(dbms_lob.getlength(a_source), 0);
827-
begin
828-
l_ml_comment_start := instr(a_source,'/*');
829-
l_comment_start := instr(a_source,'--');
830-
l_text_start := instr(a_source,'''');
831-
l_escaped_text_start := instr(a_source,q'[q']');
832-
while l_offset > 0 and l_ml_comment_start > 0 loop
833-
834-
if l_ml_comment_start > 0 and (l_ml_comment_start < l_comment_start or l_comment_start = 0)
835-
and (l_ml_comment_start < l_text_start or l_text_start = 0)and (l_ml_comment_start < l_escaped_text_start or l_escaped_text_start = 0)
836-
then
837-
l_end := instr(a_source,'*/',l_ml_comment_start+2);
838-
append_to_clob(l_result, dbms_lob.substr(a_source, l_ml_comment_start-l_offset, l_offset));
839-
if l_end > 0 then
840-
l_ml_comment := substr(a_source, l_ml_comment_start, l_end-l_ml_comment_start);
841-
l_newlines_count := length( l_ml_comment ) - length( translate( l_ml_comment, 'a'||chr(10), 'a') );
842-
if l_newlines_count > 0 then
843-
append_to_clob(l_result, lpad( chr(10), l_newlines_count, chr(10) ) );
844-
end if;
845-
l_end := l_end + 2;
846-
end if;
847-
else
815+
function strip_create_header_lines(a_source dbms_preprocessor.source_lines_t)
816+
return dbms_preprocessor.source_lines_t
817+
is
818+
l_result dbms_preprocessor.source_lines_t := a_source;
819+
l_rebased dbms_preprocessor.source_lines_t;
820+
l_create_line pls_integer;
821+
l_header_line pls_integer;
822+
l_header_pos pls_integer := 0;
823+
begin
824+
if l_result.count = 0 then
825+
return l_result;
826+
end if;
848827

849-
if l_comment_start > 0 and (l_comment_start < l_ml_comment_start or l_ml_comment_start = 0)
850-
and (l_comment_start < l_text_start or l_text_start = 0) and (l_comment_start < l_escaped_text_start or l_escaped_text_start = 0)
851-
then
852-
l_end := instr(a_source,chr(10),l_comment_start+2);
853-
if l_end > 0 then
854-
l_end := l_end + 1;
855-
end if;
856-
elsif l_text_start > 0 and (l_text_start < l_ml_comment_start or l_ml_comment_start = 0)
857-
and (l_text_start < l_comment_start or l_comment_start = 0) and (l_text_start < l_escaped_text_start or l_escaped_text_start = 0)
858-
then
859-
l_end := instr(a_source,q'[']',l_text_start+1);
860-
861-
--skip double quotes while searching for end of quoted text
862-
while l_end > 0 and l_end = instr(a_source,q'['']',l_text_start+1) loop
863-
l_end := instr(a_source,q'[']',l_end+1);
864-
end loop;
865-
if l_end > 0 then
866-
l_end := l_end + 1;
867-
end if;
828+
-- remove comment lines that contain "-- create or replace" and find first CREATE
829+
for i in 1..l_result.count loop
830+
l_result(i) := regexp_replace(l_result(i), '^.*[-]{2,}\s*create(\s+or\s+replace).*$', null, 1, 1, 'i');
831+
if l_create_line is null and regexp_like(l_result(i), '(^|[[:space:]])create([[:space:]]|$)', 'i') then
832+
l_create_line := i;
833+
end if;
834+
end loop;
868835

869-
elsif l_escaped_text_start > 0 and (l_escaped_text_start < l_ml_comment_start or l_ml_comment_start = 0)
870-
and (l_escaped_text_start < l_comment_start or l_comment_start = 0) and (l_escaped_text_start < l_text_start or l_text_start = 0)
871-
then
872-
--translate char "[" from the start of quoted text "q'[someting]'" into "]"
873-
l_escaped_text_end_char := translate(substr(a_source, l_escaped_text_start + 2, 1),gc_open_chars,gc_close_chars);
874-
l_end := instr(a_source,l_escaped_text_end_char||'''',l_escaped_text_start + 3 );
875-
if l_end > 0 then
876-
l_end := l_end + 2;
877-
end if;
836+
-- find first occurrence of object keyword after CREATE (may be on later line)
837+
if l_create_line is not null then
838+
for i in l_create_line..l_result.count loop
839+
l_header_pos := regexp_instr(
840+
l_result(i),
841+
'(^|[[:space:]])(package|type|procedure|function)([[:space:]]|$)',
842+
1, 1, 0, 'i', 2
843+
);
844+
if l_header_pos > 0 then
845+
l_header_line := i;
846+
exit;
878847
end if;
848+
end loop;
879849

880-
if l_end = 0 then
881-
append_to_clob(l_result, substr(a_source, l_offset, l_length-l_offset));
882-
else
883-
append_to_clob(l_result, substr(a_source, l_offset, l_end-l_offset));
884-
end if;
885-
end if;
886-
l_offset := l_end;
887-
if l_offset >= l_ml_comment_start then
888-
l_ml_comment_start := instr(a_source,'/*',l_offset);
889-
end if;
890-
if l_offset >= l_comment_start then
891-
l_comment_start := instr(a_source,'--',l_offset);
892-
end if;
893-
if l_offset >= l_text_start then
894-
l_text_start := instr(a_source,'''',l_offset);
895-
end if;
896-
if l_offset >= l_escaped_text_start then
897-
l_escaped_text_start := instr(a_source,q'[q']',l_offset);
850+
if l_header_line is not null then
851+
-- keep from keyword onward on the header line
852+
l_result(l_header_line) := substr(l_result(l_header_line), l_header_pos);
853+
-- remove "OWNER." from create or replace statement.
854+
-- Owner is not supported along with AUTHID - see issue https://github.com/utPLSQL/utPLSQL/issues/1088
855+
l_result(l_header_line) := regexp_replace(
856+
l_result(l_header_line),
857+
'^(package|type|procedure|function)\s+("?[[:alpha:]][[:alnum:]$#_]*"?\.)(.*)',
858+
'\1 \3', 1, 1, 'ni'
859+
);
860+
861+
-- rebase so header line becomes line 1 (matches preprocessor expectations)
862+
for i in l_header_line .. l_result.count loop
863+
l_rebased(i - l_header_line + 1) := l_result(i);
864+
end loop;
865+
return l_rebased;
898866
end if;
899-
end loop;
900-
append_to_clob(l_result, substr(a_source, l_end));
867+
end if;
868+
901869
return l_result;
902-
end;
870+
end strip_create_header_lines;
903871

904872
function get_child_reporters(a_for_reporters ut_reporters_info := null) return ut_reporters_info is
905873
l_for_reporters ut_reporters_info := a_for_reporters;

source/core/ut_utils.pks

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -406,9 +406,14 @@ create or replace package ut_utils authid definer is
406406
* Replaces multi-line comments in given source-code with empty lines
407407
*/
408408
function replace_multiline_comments(a_source dbms_preprocessor.source_lines_t)
409-
return dbms_preprocessor.source_lines_t;
410-
411-
function replace_multiline_comments(a_source clob) return clob;
409+
return dbms_preprocessor.source_lines_t;
410+
411+
/**
412+
* Strips the CREATE header (possibly split across lines) so source starts at
413+
* package/type/procedure/function keyword, preserving line numbers.
414+
*/
415+
function strip_create_header_lines(a_source dbms_preprocessor.source_lines_t)
416+
return dbms_preprocessor.source_lines_t;
412417

413418
/**
414419
* Returns list of sub-type reporters for given list of super-type reporters

0 commit comments

Comments
 (0)