1

I have a small and simple gui where the user can paste some oracle insert SQL statements and submit them to be inserted in a DB.

My question is, how can I retrieve the result status and/or the oracle output of the operations and show it on the GUI ? For example "X rows inserted" or an error (eg an exception stack trace) in case of failure ?

My 2 relevant methods are below - 1st method obtains the SQL commands from the GUI and calls 2nd method to run the statement :

private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {                                         
      String SQL = jEditorPane1.getText();
      jEditorPane1.setText("");
      String[] arraySQL = SQL.split(System.lineSeparator());
      for (String s : arraySQL) {
          System.out.println(s);
      }
      executeSQL(arraySQL);
}

 private void executeSQL(String[] commands) {      
        BasicDataSource dataSource = DatabaseUtility.getDataSource();     
        try (Connection connection = dataSource.getConnection()) {          
            for (String sql : commands) {
                try (PreparedStatement ps = connection.prepareStatement(sql)) {
                    ps.execute();
                }
            }
            connection.commit();           
        } catch (SQLException e) {            
            e.printStackTrace();
        } 
}
2
  • 1
    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. Commented Mar 19, 2019 at 14:17
  • 1
    If they are update statements, then 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/… Commented Mar 19, 2019 at 14:22

2 Answers 2

1

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;
Sign up to request clarification or add additional context in comments.

1 Comment

many thanks for the proposal. Unfortunately I won't be able to install any new packages/SPs on DB side, so I'll have to remain on a purely java-side solution
0

Using @KevinO suggestion to use executeUpdate() method (to check against the inserted records), and in combination with making the 2nd method return a string (either "success" or the SQLException message), has worked for me.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.