Does anyone know a way (in java) to check permissions to a specific table for a user? It has to work on the most Databases. SELECT right is simple to check (just trying to execute a simple SELECT statement), but how to check INSERT permission?
You can use the DatabaseMetaData to get this information. It should work in most cases. However, it might be inaccurate in special cases, if the privileges can not be represented in this abstract way:
DatabaseMetaData metaData connection.getMetaData();
metaData.getTablePrivileges();
metaData.getColumnPrivileges();
though not a direct solution but the only option that comes to my mind is to use TRY CATCH blocks, issue an INSERT statement and then checking the error message in java.sql.SQLException object returned in case of exception.
Related
I execute the following queries:
SELECT 1; CREATE TABLE ....; SELECT 2;
after that I try to get all resultSets. I use the following code for this:
while(!stmt.getMoreResults()) {
stmt.getResultSet();
}
Unfortunately I get jus first result set. Please tell me what I'm doing wrong?
Your second CREATE TABLE statement technically does not even return a result set (though JDBC might return a count of the records affected by DML). So, if you want to capture the conceptual return value of each statement, then you should just run them separately.
If your second statement were actually a SELECT, then perhaps we could find some way to combine the queries together.
Read this canonical answer to see how to handle the case where you really do have mulitple selects. But, note that not all databases support this (e.g. Oracle does not support it). And read here to see why multiple queries in a single JDBC call might even be a bad thing.
Are you trying to say that Java is just not capable of doing the thing .Net does without a hitch? Is it as simple as that?
No matter what kind of dummy statements are between selects in the script that is run as batch the bool IDataReader.NextResult() in the C# code reliably returns next result jumping over the next dummy statements for Netezza we are trying to debug for now. It did the same thing for many years for all the platforms that support batch calls in case we had to deal with them.
I'm trying to create a table in mysql through java. I'm using putty for this by the way. Here is a bit of the code I have so far but it doesn't work.
rs=s.executeQuery("CREATE TABLE test(id CHAR(2),name VARCHAR(3),PRIMARY KEY(id)); ");
while(rs.next())
{
System.out.println(rs.getString(1));
}
catch (SQLException ex)
{
System.out.println("SQLException:"+ ex.getMessage());
}
executeQuery() is for quires (usually SELECT) that return a ResultSet.
With DML (and DDL) queries you need to use executeUpdate() method.
For more information and examples use Setting Up Tables tutorial.
See this post here: Data Manipulation Statements
You should be using executeUpdate() if you wish to actually modify the database.
Your query is ok! But you don't get a result set! the CREATE TABLE won't give an rows or columns.
You have been tricked be the documentation:
Returns:
a ResultSet object that contains the data produced by the given query; never null
however
Throws:
SQLException - if a database access error occurs,... the given SQL statement produces anything other than a single ResultSet object, ...
In my opinion a call of "execute" would be the proper way.
I don't think its ever a good idea to generate your database schema via Java. Use the utility tool that comes with your database to create your schema. This way, you or anyone (such as a DBA) can create your tables, views, indexes, constraints, grant permissions, etc without having to know Java. You can even have your database utility generate an SQL script that you can run to re-generate the schema from scratch. Last point: I believe you will be better off calling your primary key test_id and making it type numberic, long, or int. this way, when you refer to it as a foreign key in another table, you will immediately know it refers back to the test table.
I am writing a DAO layer IN Java for my Tomcat server application,
I wish to use Prepared Statement wrapping my queries (1. parsing queries once, 2. defend against SQL injections),
My db design contains a MyISAM table per data source system. And most of the queries through DBO are selects using different table names as arguments.
Some of this tables may be created on the fly.
I already went though many posts that explain that i may not use table name as an argument for Prepared statement.
I have found solutions that suggest to use some type of function (e.g. mysql_real_escape_string) that may process this argument and append the result as a string to the query,
Is there any built in Jave library function that may do it in the best optimized way, or may be you may suggest to do something else in the DAO layer (i do not prefer to add any routines to the DB it self)?
Are you able to apply restrictions to the table names? That may well be easier than quoting. For example, if you could say that all table names had to match a regex of [0-9A-Za-z_]+ then I don't think you'd need any quoting. If you need spaces, you could probably get away with always using `table name` - but again, without worrying about "full" quoting.
Restricting what's available is often a lot simpler than handling all the possibilities :)
If you want to be extra safe than you can prepare a query and call it with supplied table name to check if it really exists:
PreparedStatement ps = conn.prepareStatement("SHOW TABLES WHERE tables = ?");
ps.setString(1, nameToCheck);
if(!ps.executeQuery().next())
throw new RuntimeException("Illegal table name: " + nameToCheck);
(The WHERE condition might need some correction because I don't have mysql under my fingers at the moment).
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.
I have a Java program that is agnostic from the database and I need to know, while inserting, if an SQLException was thrown because of a duplicate key.
If I was using a single database driver I would simply use the ErrorCode, but since I can be using very different engines the ErrorCode are not the same.
Has anyone done this before? Any ideas?
Many TIA!
Edit: I have a configuration file where I store the driver class (ie: org.apache.derby.jdbc.ClientDriver) and some other needed information (ie: username, password, url...). The connection is always passed as a "java.SQL.Connection" so I don't really care what drivers is being used.
This is exactly what SQLException.getSQLState() is for. Acoording to Google, "23000" indicates a unique constraint violation in at least MySQL, PostgreSQL, and Oracle.
With basic JDBC, there really isn't a way to do what you are saying in a cross-database manner. As you mentioned getErrorCode could be used, but required vendor-specific error codes.
The only three ways I see to get around this is:
Use some sort of framework that does all of the translating from error code to meaningful exceptions (Hibernate would probably do this, someone else mentioned that Spring does)
Check for the duplicate manually (with a select) prior to doing your insert. (This wouldn't be 100%, as its technically possible that someone could have done an insert after your query).
After you get any sql exception on the insert, try to query for that id. If you can actually find the match - you can be fairly sure that the error you received was due to a duplicate primary key. (Although its possible that there was multiple problems, and that wasn't actually the one that was thrown).
My recommendation would be to write your code to avoid the problem as much as possible, and then (if absolutely necessary), use #3.
You could "train" the program on startup (or config) by inserting a known duplicate key, and recording the thrown error code.
I think the ideal solution would be to have the data layer throw a specific exception in this case, perhaps a subclass of SQLException for DuplicateKeyException or something similar.
If you want to be able to treat different exceptions differently, then you have to throw different exception types (or sub-types) to begin with.
I think this is an area where the Spring Framework gets things really right: they provide a very rich hierarchy of "database exceptions" all of which extend DataAccessException , with sub-trees of types for "recoverable exceptions", "transient exceptions", "data integrity exceptions", etc etc. This leaves your client code free to catch any (or none) of the exception types which it can handle or care about: exceptions that indicate an error that may not be repeatable if you re-run the transaction, a fatal non-recoverable error, or you can simply catch the root type.
Well, if you can't rely on the exception to tell you why it was thrown, you could test by following the exception with a "select count(*) from table where key = #keyfailedtoinsert;"
Unfortunately, the exception isn't guaranteed to give you the table name and key name. In some cases, the java code that called called the JDBC driver may never have had them, e.g., if the insert happened wihin a stored procedure, or as in a trigger.
So you're back to having to trust each JDBC driver's vendor.
Am I missing something? If you're using JDBC you should get back a duplicate key exception, regardless of the DB being used.
Or did you ask how you would determine a dupkey BEFORE you tried teh insert?
I believe a simple and reliable way is to check if the key exists prior to doing the insert. As you have rightly pointed out, each database has it's own way of reporting the error.
If you are using spring, set your unique KEY name as UK_user_id for example and catch the DataIntegrityViolationException. You can then compare ex.getCause().getConstraintName() with UK_user_id.
Maybe it's not the right way to solve this problem, but I have the same issue and I resolved with the following code:
try{
//here goes your code
//Conection to DB, stmt, ...
}catch (SQLException sqlEx){
//Check if the SQLException message contains the words "duplicate entry" and "for key"
if(sqlEx.getMessage().contains("Duplicate entry")
&& sqlEx.getMessage().contains("for key")){
System.out.println("This Key already exists in the database");
}else {
//if your Exception is not due to the duplicate key, print your SQLException
System.out.println("Error SQL:" + sqlEx.getMessage());
}
}
I hope this solution can be helpful to someone!!
I'm assuming you aren't using JDBC or this would be a very simple error lookup.
Do you have a different set of classes for accessing the different databases? If so, you could catch the exception in the database specific classes and throw your own exception type that is shared among all the database types.