I’m trying to figure out where I’m going wrong with a query in Datanucleus (backed by a Postgres DB). Even simple queries seem to fail when the expression contains a backslash. However, I was under the impression that JDO/Datanucleus should abstract away the need to manually escape parameters to a query, just as PreparedStatement does with pure JDBC.
Here’s a self-contained example:
package somepkg;
import org.datanucleus.api.jdo.JDOPersistenceManager;
import javax.jdo.*;
import javax.jdo.annotations.*;
import java.util.*;
@PersistenceCapable
public final class MyPersistentObject {
@Persistent(valueStrategy = IdGeneratorStrategy.INCREMENT)
@PrimaryKey
private long id;
@Persistent
private String value;
public MyPersistentObject(String value) {
this.value = value;
}
public static void main(String... args) {
JDOPersistenceManager pm = (JDOPersistenceManager)
JDOHelper.getPersistenceManagerFactory(datanucleusProperties())
.getPersistenceManager();
//seems to be a problem with values that contain a backspace
String value = "\\";
//store (works fine)
Transaction tx = pm.currentTransaction();
tx.begin();
MyPersistentObject objectToStore = new MyPersistentObject(value);
pm.makePersistent(objectToStore);
tx.commit();
//fetch (fails)
MyPersistentObject fetchedObject = pm
.newTypesafeQuery(MyPersistentObject.class)
.filter(QMyPersistentObject.candidate().value.eq(value))
.executeUnique();
System.out.println(fetchedObject);
}
private static Map<String, String> datanucleusProperties() {
Map<String, String> datanucleusProperties = new HashMap<String, String>();
datanucleusProperties.put("javax.jdo.option.ConnectionDriverName", "org.postgresql.Driver");
datanucleusProperties.put("javax.jdo.option.ConnectionURL", "jdbc:postgresql:test");
datanucleusProperties.put("javax.jdo.option.ConnectionUserName", "postgres");
datanucleusProperties.put("javax.jdo.option.ConnectionPassword", "");
datanucleusProperties.put("datanucleus.autoCreateSchema", "true");
datanucleusProperties.put("datanucleus.validateTables", "false");
datanucleusProperties.put("datanucleus.validateConstraints", "false");
return datanucleusProperties;
}
}
QMyPersistentObject is generated by running the annotation processor. This fails with the following message:
Exception in thread "main" javax.jdo.JDOException: Exception thrown when executing query
at org.datanucleus.api.jdo.NucleusJDOHelper.getJDOExceptionForNucleusException(NucleusJDOHelper.java:567)
at org.datanucleus.api.jdo.query.JDOTypesafeQuery.executeInternalQuery(JDOTypesafeQuery.java:946)
at org.datanucleus.api.jdo.query.JDOTypesafeQuery.executeUnique(JDOTypesafeQuery.java:770)
at somepkg.MyPersistentObject.main(MyPersistentObject.java:52)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
NestedThrowablesStackTrace:
org.postgresql.util.PSQLException: ERROR: unterminated quoted string at or near "'\'"
Position: 128
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2102)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1835)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:257)
at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:500)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:388)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeQuery(AbstractJdbc2Statement.java:273)
at org.datanucleus.store.rdbms.datasource.dbcp.DelegatingPreparedStatement.executeQuery(DelegatingPreparedStatement.java:96)
at org.datanucleus.store.rdbms.datasource.dbcp.DelegatingPreparedStatement.executeQuery(DelegatingPreparedStatement.java:96)
at org.datanucleus.store.rdbms.SQLController.executeStatementQuery(SQLController.java:465)
at org.datanucleus.store.rdbms.query.JDOQLQuery.performExecute(JDOQLQuery.java:625)
at org.datanucleus.store.query.Query.executeQuery(Query.java:1789)
at org.datanucleus.store.query.Query.executeWithArray(Query.java:1665)
at org.datanucleus.store.query.Query.execute(Query.java:1638)
at org.datanucleus.api.jdo.query.JDOTypesafeQuery.executeInternalQuery(JDOTypesafeQuery.java:936)
at org.datanucleus.api.jdo.query.JDOTypesafeQuery.executeUnique(JDOTypesafeQuery.java:770)
at somepkg.MyPersistentObject.main(MyPersistentObject.java:52)
Does anyone know enough about JDO or Datanucleus to know if I’m required to take extra steps to escape stuff when I query? If not (as I would assume), I suppose this is a bug in either Datanucleus or the Postgres JDBC driver?
Why not just put a parameter in there (rather than hardcoding values, and getting subsequent problems) and then it is passed to the JDBC driver as a ?. i.e the way that JDBC always recommends handling such things