I'm having trouble when trying to run the following query against an in memory H2 (version 1.4.181) table:
Object result = hibernateSession
.createSQLQuery("show columns from :myTable")
.setString("myTable", "some_table")
.list();
This query causes the following exception:
Caused by: org.h2.jdbc.JdbcSQLException: Syntax error in SQL statement "SHOW COLUMNS FROM ?[*] "; expected "identifier"; SQL statement: show columns from ? [42001-181]
...
...
...
I had done some debbuging and I found that during parse of query, the character "?" is tested to check if it is a valid identififer and it fails, causing the rise of exception (class org.h2.command.Parser, line 3027):
//currentToken is "?" at this point
if (currentTokenType != IDENTIFIER) {
throw DbException.getSyntaxError(sqlCommand, parseIndex,
"identifier");
}
I think it is a bug. What you think?
No, it is quite normal. Hibernate could not possibly make a PreparedStatement of it.
Standard JDBC has many possibilities to query schemata and such, in a database vendor independant way.
DatabaseMetaData dbMeta = connection.getMetaData();
Then getColumns can be used to receive a ResultSet of miscellaneous information.
You can try creating the required query instead of setting table name as named-parameter which won't work.
String sqlQuery = "show columns from " + tableName;
Class<?> entity = Class.forName(entityName);
session.createSQLQuery(sqlQuery);
Get the metadata information & then can retrieve required details from it.
String[] properties =
sessionFactory.getClassMetadata(entityClass).getPropertyNames();
There are several other methods available to get meta information, can refer ClassMetaData
[I haven't checked Criteria API, will update if found anything relevant, you can try it]
Related
I am currently working on fixing some SQL injection bugs in my project.
Here is my current sql string:
String sql = "select * from :table order by storenum";
Here is how I am setting the parameters:
SQLQuery query = sess.createSQLQuery(sql).setParameter("table", table);
(table is a string that is passed in through a method)
Whenever I run the program I get something like this:
select * from ? order by storenum
You can't dynamically bind table names, only values, so you'll have to resort to string manipulation/concatenation to get the table name dynamically. However, you would probably want to escape it to avoid SQL Injections.
I'm having an strange issue in this query.
Code:
em2=getNewEntityManager();
(...)
Query query2 = em2.createNativeQuery("SELECT DISTINCT ID_ZONA FROM VWG_REL_USUARIOS_ZONAS WHERE DNI like '"+dni+"'") ;
List <Long> permisos = query2.getResultList();
(...)
If "dni" equals to: "%" the query goes normal, but if "dni" is "%123456789" gives this error
javax.persistence.PersistenceException: Exception [EclipseLink-4002]
(Eclipse Persistence Services - 2.5.0.v20130507-3faac2b):
org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLException: sql string is not a dml statement
Error Code: 17129
Call: SELECT DISTINCT ID_ZONA FROM VWG_REL_USUARIOS_ZONAS WHERE DNI like '%XX828747B'
Query: DataReadQuery(sql="SELECT DISTINCT ID_ZONA FROM VWG_REL_USUARIOS_ZONAS WHERE DNI like '%XX828747B'")
And if I copy the exact query above in my SQL developer, it works as magic.
I've tried with the "createQuery" with the entities and all the stuff, same error.
Thanks a lot
Try assigning the value to a parameter, such as:
String dni = "some value";
Query query2 = em2.createNativeQuery("SELECT DISTINCT ID_ZONA FROM VWG_REL_USUARIOS_ZONAS WHERE DNI like :param") ;
query2.setParamter("param", dni);
List <Long> permisos = query2.getResultList();
Update: In EclipseLink, Only indexed parameters are supported, named parameters are not supported.
Finally I got it, it is working now.
I was changing DNI value in debugging mode in eclipse, to fit the test I want to do. So a session validator invalidated my the user as some of the data "by magic" changed in an strange way. To do the test without compiling every time, I have to change DNI value BEFORE session is created.
What I don't know is why is it giving so specific SQL exception when the error originated validating the session. Something like "session is invalid" would have saved me a couple of hours...
Thanks all for your time
I am trying to make a select from a table, which works fine with every other table in my database, but when I try the following I recieve an error:
db.makeQuery("SELECT * FROM References");
Which calls:
public ResultSet makeQuery(String query) throws Exception
{
preparedStatement = connect.prepareStatement(query);
resultSet = preparedStatement.executeQuery(query);
return resultSet;
}
It then throws the following error:
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException:
You have an error in your SQL syntax; check the manual that corresponds to your
MySQL server version for the right syntax to use near 'References' at line 1
I seems very strange to me, since this statement works:
db.makeQuery("select * from Products");
References is a keyword in SQL, so you better avoid it for table names. (See for instance this documentation.)
As suggested by Nishant, you can use reserved words in queries if you escape them with backticks.
Related question:
Using MySQL keywords in a query?
use
db.makeQuery("SELECT * FROM `References`");
if you can, better, avoid having names that are MySQL keywords. As suggested by aioobe
You might be misspelling the name of your table. MySQL gives this error when it can't find that table you're referring to.
Use SHOW TABLES; to see the names of the tables in your database, and double-check the name.
Currently i'm writing a JDBC application to manage a MySQL database. I have the delete, insert and select methods functioning with the correct queries. I'm having trouble with the Update method. When using using the following code I receive a MySQL error:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near "",Street",Town",City",PostCode",Age",email",RunningFee'false'Where PID=" at line 1...
private void updateData()
{
Connection con;
try
{
Class.forName("com.mysql.jdbc.Driver");
con = DriverManager.getConnection(
"jdbc:mysql://localhost/snr","root","");
String sql = "Update participant Set password='"+txtpassword.getText()+"'," +
"lastName='"+txtlastName.getText()+"',firstName='"+
txtfirstName.getText()+"',HouseNumber'"+txtHouseNumber.getText()+"',Street'"+txtStreet.getText()+"',Town'"+txtTown.getText()+"',City'"+txtCity.getText()+"',PostCode'"+txtPostCode.getText()+"',Age'"+txtAge.getText()+"',email'"+txtemail.getText()+"',RunningFee'"+cbRunningFee.isSelected()+"' Where PID='"+txtPID.getText()+"'";
Statement statement = con.createStatement();
statement.execute(sql);
createMessageBox("Updated Successfully");
clearControls();
}
catch(Exception e)
{
createMessageBox(e.getMessage());
}
}
Is there something wrong with my SQL query?
Yes, your query is wrong. You're missing = on a great big bunch of set column/value pairs.
(And please consider using prepared statements and bind variables, SQL injection is just not something you want to be open to.)
Yes there is something wrong with the query. Your way of building query is vulnerable to SQL Injection. Use Parameterized Queries instead of concatenating text like that.
Read this article: Preventing SQL Injection in Java
Not only is your query incorrect, but it may also open you to SQL Interjection Attacks.
You need to parameterize your query by replacing the pasted-in values with question marks, preparing the statement, and executing it. See the tutorial that I linked.
Finally, storing a password as plain text is a very, very bad idea.
String sql = "UPDATE participant SET "+
"password=?, lastName=?, firstName=?, HouseNumber=?, Street=?, Town=?, "+
"City=?,PostCode?,Age=?,email=?,RunningFee=? "+
"WHERE PID=?";
PreparedStatement upd = con.prepareStatement(sql);
upd.setString(1, txtpassword.getText());
upd.setString(2, txtlastName.getText());
// ... and so on
upd.executeUpdate();
con.commit();
You are forgetting some = in your query.
Try
String sql = "Update participant Set password='"+txtpassword.getText()+"'," +
"lastName='"+txtlastName.getText()+"',firstName='"+
txtfirstName.getText()+"',HouseNumber='"+txtHouseNumber.getText()+"',Street='"+
txtStreet.getText()+"',Town='"+txtTown.getText()+"',City='"+txtCity.getText()+
"',PostCode='"+txtPostCode.getText()+"',Age='"+txtAge.getText()+"',email='"+
txtemail.getText()+"',RunningFee='"+cbRunningFee.isSelected()+
"' Where PID='"+txtPID.getText()+"'";
The error 'you have an error in your SQL syntax' is from the sql server and indicates that yes, you do have an error in your query. In these cases I often find it useful to print the constructed query itself, just to check that it is being constructed correctly.
In your case I believe the problem is that you are missing a bunch of "="s, you also probably need to escape your single quotes in the java so they are passed through correctly (replace ' with \').
Following on from one of my previous questions to do with method design I was advised to implemented my SQL queries as a parameterized query as opposed to a simple string.
I've never used parameterized queries before so I decided to start with something simple, take the following Select statement:
String select = "SELECT * FROM ? ";
PreparedStatement ps = connection.prepareStatement(select);
ps.setString(1, "person");
This gives me the following error: "[SQLITE_ERROR] SQL error or missing database (near "?": syntax error)"
I then tried a modified version which has additional criteria;
String select = "SELECT id FROM person WHERE name = ? ";
PreparedStatement ps = connection.prepareStatement(select);
ps.setString(1, "Yui");
This version works fine, in the my first example am I missing the point of parameterized queries or am I constructing them incorrectly?
Thanks!
Simply put, SQL binds can't bind tables, only where clause values. There are some under-the-hood technical reasons for this related to "compiling" prepared SQL statements. In general, parameterized queries was designed to make SQL more secure by preventing SQL injection and it had a side benefit of making queries more "modular" as well but not to the extent of being able to dynamically set a table name (since it's assumed you already know what the table is going to be).
If you want all rows from PERSON table, here is what you should do:
String select = "SELECT * FROM person";
PreparedStatement ps = connection.prepareStatement(select);
Variable binding does not dynamically bind table names as others mentioned above.
If you have the table name coming in to your method as a variable, you may construct the whole query as below:
String select = "SELECT * FROM " + varTableName;
PreparedStatement ps = connection.prepareStatement(select);
Parameterized queries are for querying field names - not the table name!
Prepared statements are still SQL and need to be constructed with the appropriate where clause; i.e. where x = y. One of their advantages is they are parsed by the RDMS when first seen, rather than every time they are sent, which speeds up subsequent executions of the same query with different bind values.