In one of my applications I am providing the users the ability to issue direct SQL queries against a database. They type the SQL text into a text box, then I run it exactly as is using JDBC.
Obviously I trust these users very much. But I would like to limit them programatically to issuing only SELECT statements. They should never DELETE/UPDATE/INSERT. I thought maybe JDBC itself could help me here. I found the executeQuery() method in the java.sql.Statement class. But that method allows me to call DELETE (and maybe UPDATE and INSERT too). It does throw an Exception because no ResultSet is returned, but only after deleting the records.
So, I ask here, is there any way in JDBC to make sure that a SQL statement is only performed if it is a query? Or do I have to parse the statement myself and make sure it complies with my wishes?
I suggest you connect to the DBMS with a user that lacks the DELETE / UPDATE and INSERT permissions.
Related
I am trying to run a insert statement which will help me to create user account for my following api calls.
I looked at JMeter JDBC request which has select/update/ect... i don't see insert query type.
does anyone know how can i run some insert query to create the user for my database?
thanks
L.
You should use Update Statement Query type also for inserts
Update Statement - use this for Inserts and Deletes as well
You may use also Prepared Update Statement type:
Prepared Update Statement - use this for Inserts and Deletes as well
In JDBC terms "insert" equivalent is update therefore you need to choose Update Statement from the "Query Type" dropdown:
You might also find How to Create Test Data in a Database with JMeter useful, it provides more insight and examples.
So basically, I would like to avoid stored procedures, but at the same time I would'nt want multiple round-trips to database to execute sequential statements.
Apparently this blog says Facebook uses mysql's multiple-statement-queries. Unfortunately, its a C API, is there a java equivalent of it?
So in brief, the question "is in java+mysql how can a second jdbc statement use the output of the first statement as input to execute, without a round-trip to database and without a storedproc" ?
If not how do other people approach this problem?
Yes, the JDBC driver for MySQL support the multi-statement queries. It is however disabled by default for security reasons, as multi-statement queries significantly increase the risks associated with eventual SQL injections.
To turn on multi-statement queries support, simply add the allowMultiQueries=true option to your connection string (or pass the equivalent option in map format). You can get more information on that option here: https://dev.mysql.com/doc/connector-j/5.1/en/connector-j-reference-configuration-properties.html.
Once this option enabled, you can simply execute a call similar to: statement.execute("select ... ; select ... ; select ..."). Returned ResultSets can be iterated from the Statement object: each call to statement.getResultSet() return the next one. Use statement.getMoreResults() to determine if there are indeed more ResultSet available.
It sounds like you want to do batch processing.
here is a duplicate question with an good answer:
How to execute multiple SQL statements from java
I'm hitting a problem when trying to update a ResultSet.
I'm querying the database via JDBC, and getting back a resultset which is not CONCUR_UPDATABLE.
I need to replace the '_' into ' ' at the specified columns. How could I do that?
String value = derivedResult.getString(column).replace("_", " ");
derivedResult.updateString(column, value);
derivedResult.updateRow();
This works fine on Updatable, but what if it's ResultSet.CONCUR_READ_ONLY?
EDIT:
This will be a JDBC driver, which calls another JDBC Drivers, my problem is i need to replace the content of the ResultSets, even if it's forward only, or Read only. If I set scroll_insensitive and updatable, there isn't a problem, but there are JDBC drivers that works with forward only resultsets.
Solutions:
Should I try to move the results to an inmemory database and replace the contents there.
Should I implement the resultset which acts like all my other classes: Calls the underlying drivers function with modifications if needed.
I don't want to use the resulst afterward to make updates or inserts. Basically this will be done on select queries.
In my experience updating the result set is only possible for simple queries (select statements on a single table). However, depending on the database, this may change. I would first consult the database documentation.
Even if you create your own resultset which would be updatable, why do you think that the database data would change? It is highly probable (almost certain) that the update mechanism uses code that is not public and only exists in the resultset instance implementation type of the jdbc driver you use.
I hope the above makes sense.
I have to confirm that can we execute multiple select statement in one shot and get multiple resultsets. Please give me some idea for doing this.
I have to execute two select query in one statement:-
String sql="select * form test;
select * from test where empid=1;"
I am expecting to run like this :-
statement.execute(sql);
thanks
I don't believe that standard JDBC supports this. Certainly the ResultSet interface is oriented towards "multiple rows, one row at a time" - but not "multiple sets of results".
That doesn't mean it's not feasible with your specific database, however - it's possible that there's a driver for your database which extends JDBC to allow it. If you specify which database and driver you're using, we could verify that more easily.
In my opinion JDBC does not allow executing multiple statements in one go. The language used in the JDBC specification and API doc indicates that the expectation is that one Statement execution is one statement, not multiple statements (eg it uses 'a SQL statement', which when reading the SQL spec means a single SELECT, INSERT, etc). However it never explicitly states it is not allowed.
Some drivers do support execution of multiple statements in one execution, but this usually has to be explicitly enabled using a connection property. Also some databases support executing a block of stored procedure code without explicitly defining a stored procedure (in that case the block is considered to be the statement).
Create a stored procedure with those set of select statements and use Statement.getMoreResults() to check whether you have more ResultSets and use
Statement.getResultSet() to get the next ResultSet
An example is given Here
I have a list of strings that contain valid SQL expressions.
I need to execute only those that do not modify the database.
What would be the best way to do this? Just doing something like:
if(sqlQuery.contains("DELETE")){
//don't execute this
}
seems like a bad hack
Update:
I'll make this more specific.
I already have a list of SQL queries that are allowed. I want to make sure only these are executed.
What would be the best way to match against these?
The easiest and best (most comprehensive) way to do this is to create a read-only user and only connect to the database with that user. In SQLServer, the easiest way to do this is to create the user and add them to the built-in "db_datareader" role. This will only allow SELECTs.
And you have to worry about more than just DELETEs, INSERTs or UPDATEs. You also have to be careful about calling any stored procedures, so to be safe you'd also want to remove execute rights, ALTER rights, GRANT rights, etc...
EDIT:
Just execute this...
CREATE LOGIN [user] WITH PASSWORD='password', DEFAULT_DATABASE=[your_db], CHECK_POLICY=OFF
GO
CREATE USER [user] FOR LOGIN [user]
EXEC sp_addrolemember N'db_datareader', N'your_db'
GO
DELETE is not the only SQL instruction that might modify your database; INSERT will definitely do so, and UPDATE might (depending on your exact query). So just analysing the Strings might be a hard way of doing this.
As long as performance is not really an issue, you could start a transaction, run your instructions one by one, check the number of affected rows for each of them, and finally rollback your transaction. Afterwards, you only run those statements that affected 0 rows.
Besides, check your database documentation: some RDBMS-es (like Oracle) don't support rollback of DDL statements like ALTER TABLE, DROP TABLE and the like...
I don't think there's a bulletproof way of preventing the alteration of records by simply checking the content of the given SQL. For example, you might have a field, which has the value "update" and some user is trying to query all rows which contain this value, yet the SQL would not be executed, since it contains a "blacklisted" string.
I guess the only safe way would be to execute the SQL's with an user, who has no rights to alter records at all.