General approach for SQL script execution in Java - java

The functionality that discussed within this question is to execute the given SQL script. The content of the script is intended to be defined by the user during application runtime. The script can be whether one INSERT statement or a sequence of complex PL/SQL statements. Since the input available during runtime (eventually as String instance) it should be executed through Java.
Current approach is wrapping user input with a PreparedStatement and to execute it. This solution works for the existing test cases. The main concern is to provide the full functionality of the used database that might be not covered by tests, i.e. solution that is closest to passing the same user SQL script into database vendor's provided console.
I'm wondering are there any not envisaged limitations in current approach with PreparedStatement? Is there any better general approach for SQL script execution via Java?

Well, this is a broad design question but I think that there are several steps that could be done:
SQL script parsing and recognition: You need to be able to detect which type of SQL script you have: PL/SQL, DML, DDL, CDL, TCL, multipart separated by ";" etc.
Statement building: for each type of sql script you need to be able to execute the statement with java.
Parsing the result. You need to be able to collect the returned in SELECTs and optionally parameters returned by functions or number of affected/inserted rows.
Error handling: you need to be able to report what happened to the SQL Script when things didn't worked as expected.
Please consider:
This seems like the programming of a SQL Client. If not please explain what do you want to do. Do not use this as the connection layer in a normal application. It will be extremely inefficient and vulnerable to SQL injections (It is much more complicated than just scaping commas)
You may want to call functions o execute queries with external parameters.
This does not includes the user interfaces features like Syntax highlighting. Parameters interfaces, etc...

The first limitation of PreparedStatement that comes to mind - you won't be able to register an OUT parameter(s) of a stored procedure, you may wish to look into CallableStatement interface.

Related

Filtering executed SQL queries on application server

First of all, I know this is bad practice but regardless I'm still looking for an answer.
In our web application we have a textarea where the user can write SQL to bring in custom data sets and view them in a chart. The way this works is essentially taking the written string and executing it as a query. What I'm looking for is everything I need to implement in our application server back end security wise as to disallow the execution of queries that produce results other than SELECT type queries.
The user won't be able to execute any type of SELECT query he wants since the app server backend expends the returned result set to have 2 columns named X_FIELD and Y_FIELD so we're not so much worried about the user being able to view data as much as him executing SQL that will break the database.
What we thought of doing is parsing the string for keywords such as DROP, ALTER, CREATE etc. Are there specific things that we have to look out for? Is there a tool/library that automates this? We're using java for our back end code.
Filtering queries can be done at the application level but it requires much more database-specific expertise than creating separate security systems for each database.
As an example, I created an open source program that can do this for Oracle. It won't solve your problem but the code can at least help explain why this is a bad idea.
First, it's important to understand that Oracle SQL syntax is much more complicated than most programming languages, such as Java.
Oracle has 2175 keywords and almost none of them are reserved. Forget about parsing SQL - none of the existing 3rd party parsers are accurate enough to do this securely.
Luckily a full parser is not needed for this task. Oracle syntax is structured in such a way that any statement can be classified with only 8 tokens, excluding
whitespace and comments.
But building a tokenizer and a
statement classifier is still difficult. That solution will handle
unusual kinds of selects, such as (select * from dual) or with asdf as (select 1 a from dual) select a from asdf;. But even a SELECT statement can cause
changes to the database; either through PL/SQL hidden in a function or type, or locking rows through a for update.
And don't forget to remove the (sometimes optional) terminator. They work fine
in most IDEs, but they are not allowed in dynamic SQL. Don't just remove the last characters, or the last token, because some SELECT statements allow semicolons in the middle.
That's a lot of work for just one database! If you want to use this method to implement security policies you need almost 100% accuracy. Very few people are fanatical enough about any database to build this. There's no chance you can do this for multiple databases.

Is there any use for views,triggers and stored procedures for a Java GUI project?

I am making a Java gui and web application which will use the same mysql database.
It's a DTh management system where all the information will be stored and retrieved dynamically depending on input.
I believe that views are static by nature and thus would be useless as all my queries will have a different where condition (userid).
Do I need to use triggers? I mean I could code the java to execute multiple statements instead of using a inbuilt trigger (e.g. Insert in customers name and family members name both will have a duplicate copy for head of the family). Is there a performance hit? Am I wrong in some way?
And same thing what is the use of stored procedures? Can't I use methods in java to do everything?
So, I am asking is it possible to shift all the calculation intensive stuff to java and web script instead of the sql. If yes, does this mean I only have to create the backend structure of Database(i.e. all the different tables and FK,PK) and do rest without using any sql stuff on mysql workbench?
Thank you for helping.
There is (as always) one correct answer: It depends.
If you only want to show and query some data, you probably won't need trigger or stored procedures.
Views are a different thing: They are pretty helpful if you want a static viesw to a join-table or something like that. If you don't need this, just don't use it.
Keys are really important. They make your data robust against wrong input.
What you shoud use is PrepearedStatement instead of Statement. If you only use PreparedStatements, you are (nearly ?) safe in the question of SQL-Injection.
We use Views because it just faster than select query and for just showing data (not edit-update) it is faster and preferable.
Trigger are fired at database side so it is faster because it just execute 2 or more queries in single execution.
Same in Stored procedures, because we can execute more than one queries in single database connection. If we execute different queries than it take more time on every execution for database connection (find database server, authenticate, find database,... etc.).

How to capture/encode special character for SQL Server in java app?

I have a java app + SQL server database. DB operation use JDBC with dynamic SQL string. Example:
Select Column from tab where column=StringParm
StringParam is user input. if the stringParm include apostrophe, Java app will throw exception and said Can't execute the SQL.
How to resolve this problem with no java code changing?
I'm guessing you construct the SQL in some manner like
String sql = "Select Column from tab where column='" + StringParm + "'";
Or something like it ? If you do that, you're open to all kinds of exploits and you'll also see behavior like you describe, where the resulting string is no longer valid SQL. You'd have to escape the user supplied parameter first.
The best solution is to use PreparedStatements, so you do
Statement stmt = conn.prepareStatement("Select Column from tab where column=?");
stmt.setString(1,StringParam);
I can't see any quick way of solving your problem without altering any Java code though, bar perhaps escaping/sanitizing the input before it hits your code (e.g. javascript if you're a webapp)
Never put user input directly in a SQL query. You need to use a PreparedStatement with parameters. Without changing the Java code, I don't see any way to make this safe.
You should really use java.sql.PreparedStatement to set parameters. The code changes should be minimal and it is less problematic that trying to escape user input.
You can not fix this without changing the application. SQL Server can handle quotes, however your application (Java code) is not properly escaping the quotes when you build your dynamic SQL commands. I prefer using stored procedures and passing in parameters, this way there are never any quotes issues or injections.
You could fix this by putting a trigger in the database to clean up the entry - i.e. when an insert is attempted, instead do proper escaping on the input, and then continue with the new insert input. However, this is the wrong layer and it should probably not be done down there. A much better solution (IMO) is to use a prepared statement, and do variable replacements, letting JDBC do the escape work for you.

Add description to columns using Java code

I can create a table and its columns in Java by using the statement:
CREATE TABLE table_name(column1 int, column2 double, etc...)
What I would like to do is to add descriptions to each of these columns with an appropriate statement, I found a stored procedure sp_addextendedproperty that looks like it can be used to accomplish this I just have no idea how to use it in java with jdbc.
Are you creating the table dynamically at runtime (e.g. as part of your application) - perhaps that's even user-driven? If that's the case, you already have that "documentation" (column comments) somewhere and I doubt the utility of adding them to SQL Server.
But if you're just trying to automate your build, take a look at LiquiBase. It's a pretty decent DB change management system that uses XML as backbone. It's written in java and integrates well with Hibernate (useful if you ever decide to use ORM instead of straight JDBC).
Update: If you do decide to go forward with calling stored procedure via JDBC, I would strongly recommend using CallableStatement to invoke it. Dynamically building SQL queries in the application should be avoided if possible.
There are a number of ways to call a stored procedure (essentially, preparing the statement and binding the variables, or sending a string of SQL), but the simplest is to just send rhe SQL statement
exec sp_addextendedproperty list, of, arguments, the, sp, needs;
Skipping your try/finally boilerplate, and assuming connection is a java.sql.Connection, that's:
connection
.createStatement()
.execute( "exec sp_addextendedproperty arguments;");
But ChssPly76 has a good point: doing this from Java isn't a good idea (unless you're developing some database manager in Java).

JDBC generation of SQL in PreparedStatement

I had a really huge problem recently which took me a lot of time to debug. I have an update statement which updates 32 columns in table. I did that with PreparedStatement. Accidentaly I deleted one setParameter() call so update could not be finished successfully.
I got exception from JDBC (Apache Derby) telling: "At leas one parameter is not initialized" and was not able to figure out which parameter is not set since driver would not tell you nothing about name or ordinal number of at least first parameter which is not set...
I was googleing unsuccessfully for some utility which will produce plain old SQL out of (nearly-finished) prepared statement. It would help a lot in situations like this one, since I will be able to see what is not set.
Have anyone faced this problem? Got any solution?
Have a look at P6Spy. It can intercept all your JDBC calls and log them before forwarding them onto your database.
Alternatively, think about using Springs JDBCTemplate which can take out alot of your boilerplate JDBC coding and help avoid these kind of mistakes. You don't need the rest of the Spring framework to use this bit.
Since the parameters in a prepared statement are just a List or Map in the PreparedStatement Object you should be able to inspect the values.
Also you could write a very simple Wrapper around you jdbc driver that creates wrapped PreparedStatements and logs all parameters and there settings before actually executing the statement.

Categories

Resources