Reputation: 43560
I have an SQL statement (for an Oracle database) that takes a long time to run if it is valid. If it's not valid, it returns immediately with an error.
I'd like to check that the syntax is valid without running the statement (via JDBC), for example behind a 'check statement' button. Is there a vendor-independent way of doing that? My first thought of simply defining the query as a PreparedStatement does not seem to cause any kind of compilation or error checking.
Upvotes: 14
Views: 11504
Reputation: 11146
You can use Oracle's Pro*C precompiler to perform a syntax check (download here).
This is a tool meant to precompile C code containing raw Oracle SQL statements, but you can "abuse" it to perform SQL syntax checks.
Create a file test.pc with this code:
EXEC SQL SELECT * FROM DUAL WERE 1=1;
Run this command after installing the precompiler tools:
proc INAME=test SQLCHECK=SYNTAX
You will see this output:
Syntax error at line 1, column 34, file test.pc:
Error at line 1, column 34 in file test.pc
EXEC SQL SELECT * FROM DUAL WERE 1=1;
.................................1
PCC-S-02201, Encountered the symbol "1" when expecting one of the following:
; , for, union, connect, group, having, intersect, minus,
order, start, where, with,
The symbol "having," was substituted for "1" to continue.
It should be straightforward to integrate that into your solution.
Note that it can also perform online semantics checks, verifying that all the used procedures and tables are valid in a specific schema. For that you pass in SQLCHECK=SEMANTICS USERID=youruser
Upvotes: 0
Reputation: 8376
If you're dealing with SELECT queries, perhaps JDBC PreparedStatement#getMetaData will work?
Upvotes: 6
Reputation: 7256
You could use DBMS_SQL.PARSE
to check your statement. Warning: It will just parse DML statements, but it will execute and commit DDL statements such as create table etc. You could create a stored procedure to return a value or boolean and wrap a block like this:
set serveroutput on
-- Example of good SQL
declare
c integer;
s varchar2(50) := 'select * from dual';
begin
c := dbms_sql.open_cursor;
dbms_sql.parse(c,s,1);
dbms_sql.close_cursor(c);
dbms_output.put_line('SQL Ok');
exception
when others then
dbms_sql.close_cursor(c);
dbms_output.put_line('SQL Not Ok');
end;
/
-- Example of bad SQL
declare
c integer;
s varchar2(50) := 'select splat from dual';
begin
c := dbms_sql.open_cursor;
dbms_sql.parse(c,s,1);
dbms_sql.close_cursor(c);
dbms_output.put_line('SQL Ok');
exception
when others then
dbms_sql.close_cursor(c);
dbms_output.put_line('SQL Not Ok');
end;
/
Upvotes: 2
Reputation: 115550
This is more of a hack than a real answer but you could run a query that will always return one row and one column:
SELECT ( EXISTS (SELECT 1 FROM dual)
OR
EXISTS (your Query here)
) AS result
FROM dual
This should return TRUE
if your query is valid and raise error if it is invalid.
Upvotes: 5
Reputation: 16677
possibly issuing an explain plan for the statement would give you useful results.
another thought - but maybe harder is to edit the query to add (and rownum < 1) or something to make it run fast
Upvotes: 12