My open source program PLSQL_LEXER may be able to help you with your task.
Sounds like you're trying to setup a smaller version of SQL Fiddle, which is a difficult task. There are a ton of weird parsing problems trying to split, classify, and run SQL statements. I can't help you with the Java side of things, but if you're willing to do most of the heavy lifting in PL/SQL, then the below code should help.
If you install the package, and then create the stored function below, you can simply pass a string (CLOB) to Oracle, and then get the results back.
The code also shows how to prevent certain kinds of commands from running. But that's only for convenience, if want to warn people not to run certain things. You do not want to try to re-implement Oracle security here. You should assume that anybody who submits commands to this function has all of the same privileges as the user that owns the function.
create or replace function run_commands(p_statements clob) return clob
as
v_split_statements token_table_table;
v_category varchar2(100);
v_statement_type varchar2(100);
v_command_name varchar2(64);
v_command_type number;
v_lex_sqlcode number;
v_lex_sqlerrm varchar2(4000);
v_output clob;
begin
--Tokenize and split the string into multiple statements.
v_split_statements := statement_splitter.split_by_semicolon(
plsql_lexer.lex(p_statements));
--Loop through the statements.
for i in 1 .. v_split_statements.count loop
--Classify each statement.
statement_classifier.classify(
p_tokens => v_split_statements(i),
p_category => v_category,
p_statement_type => v_statement_type,
p_command_name => v_command_name,
p_command_type => v_command_type,
p_lex_sqlcode => v_lex_sqlcode,
p_lex_sqlerrm => v_lex_sqlerrm
);
--For debugging, print the statement and COMMAND_NAME.
v_output := v_output||chr(10)||'Statement '||i||' : '||
replace(replace(
plsql_lexer.concatenate(v_split_statements(i))
,chr(10)), chr(9));
v_output := v_output||chr(10)||'Command Name: '||v_command_name;
--Handle different command types.
--
--Prevent Anonymous Blocks from running.
if v_command_name = 'PL/SQL EXECUTE' then
v_output := v_output||chr(10)||'Error : Anonymous PL/SQL blocks not allowed.';
--Warning message if "Invalid" - probably a typo.
elsif v_command_name = 'Invalid' then
v_output := v_output||chr(10)||'Warning : Could not classify this statement, '||
'please check for a typo: '||
replace(replace(substr(
plsql_lexer.concatenate(v_split_statements(i))
, 1, 30), chr(10)), chr(9));
--Warning message if "Nothing"
elsif v_command_name = 'Nothing' then
v_output := v_output||chr(10)||'No statements found.';
--Run everything else.
else
declare
v_success_message varchar2(4000);
v_compile_warning_message varchar2(4000);
begin
--Remove extra semicolons and run.
execute immediate to_clob(plsql_lexer.concatenate(
statement_terminator.remove_semicolon(
p_tokens => v_split_statements(i))));
--Get the feedback message.
statement_feedback.get_feedback_message(
p_tokens => v_split_statements(i),
p_rowcount => sql%rowcount,
p_success_message => v_success_message,
p_compile_warning_message => v_compile_warning_message
);
--Print success message.
v_output := v_output||chr(10)||'Status : '||v_success_message;
--Print compile warning message, if any.
--This happens when objects successfully compile but are invalid.
if v_compile_warning_message is not null then
v_output := v_output||chr(10)||'Compile warning: '||v_compile_warning_message;
end if;
exception when others then
v_output := v_output||chr(10)||'Error : '||dbms_utility.format_error_stack||
dbms_utility.format_error_backtrace;
end;
end if;
end loop;
return v_output;
end;
/
Below is an example of running the stored procedure and the output. You'll have to convert this PL/SQL block into a Java call, but I don't think that will be too complicated.
declare
--A collection of statements separated by semicolons.
--These may come from a website, text file, etc.
v_statements clob := q'<
create table my_table(a number);
insert into my_table values(1);
begin null; end;
udpate my_table set a = 2;
>';
v_results clob;
begin
v_results := run_commands(v_statements);
dbms_output.put_line(v_results);
end;
/
Statement 1 : create table my_table(a number);
Command Name: CREATE TABLE
Status : Table created.
Statement 2 : insert into my_table values(1);
Command Name: INSERT
Status : 1 row created.
Statement 3 : begin null; end;
Command Name: PL/SQL EXECUTE
Error : Anonymous PL/SQL blocks not allowed.
Statement 4 : udpate my_table set a = 2;
Command Name: Invalid
Warning : Could not classify this statement, please check for a typo: udpate my_table set a = 2;
the user can paste some oracle insert SQL statements... this leaves open the possibility for SQL injection, and maybe worse. I hope you are not doing this in production.ps.executeUpdate()returns the row count (insert, update, delete). It also executes DDL, with a return of 0. See docs.oracle.com/javase/7/docs/api/java/sql/…