Can I execute SQL statements directly in a JDO environment? - sql

I am using Datanucleus JDO on top of HSqlDb.
I would like to execute the following SQL statement to tell HsqlDb to set the write delay to 0:
"SET WRITE_DELAY 0"
Is there a way I can do this from a JDO PersistenceManager or a PersistenceManagerFactory?
On a sidenote: I have tried to modify write_delay by using the following connection URL:
jdbc:hsqldb:file:data/hsqldb/dbbench;write_delay=false
It didn't work. I debugged the HsqlDb sources and I could still see the write delay being set to 10 seconds.

I think I have found a solution that will work for me:
public PersistenceManager getPersistenceManager() {
PersistenceManager persistenceManager =
_persistenceManagerFactory.getPersistenceManager();
JDOConnection dataStoreConnection =
persistenceManager.getDataStoreConnection();
Object nativeConnection = dataStoreConnection.getNativeConnection();
if(! (nativeConnection instanceof Connection) ){
return persistenceManager;
}
Connection connection = (Connection) nativeConnection;
try {
Statement statement = connection.createStatement();
statement.executeUpdate("SET WRITE_DELAY 0");
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
return persistenceManager;
}

You can write a startup script, dbbench.script in this example, and put the SQL in there.
See: http://best-practice-software-engineering.ifs.tuwien.ac.at/technology/tech-hsqldb.html

I think this page
http://www.datanucleus.org/products/accessplatform/jdo/datastore_connection.html
tells all needed. No ?

Related

janusGraph using remote connection to update and delete : report DefaultGraphTraversal.none()

using janusGraph git code example : example-remotegraph
It works well when i going to create elements and do some query things.
But it report exception when update and delete...
java.util.concurrent.CompletionException: org.apache.tinkerpop.gremlin.driver.exception.ResponseException: Could not locate method: DefaultGraphTraversal.none()
at java.util.concurrent.CompletableFuture.reportJoin(CompletableFuture.java:375)
at java.util.concurrent.CompletableFuture.join(CompletableFuture.java:1934)
at org.apache.tinkerpop.gremlin.driver.ResultSet.one(ResultSet.java:107)
at org.apache.tinkerpop.gremlin.driver.ResultSet$1.hasNext(ResultSet.java:159)
at org.apache.tinkerpop.gremlin.driver.ResultSet$1.next(ResultSet.java:166)
at org.apache.tinkerpop.gremlin.driver.ResultSet$1.next(ResultSet.java:153)
at org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteTraversal$TraverserIterator.next(DriverRemoteTraversal.java:142)
at org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteTraversal$TraverserIterator.next(DriverRemoteTraversal.java:127)
at org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteTraversal.nextTraverser(DriverRemoteTraversal.java:108)
at org.apache.tinkerpop.gremlin.process.remote.traversal.step.map.RemoteStep.processNextStart(RemoteStep.java:80)
at org.apache.tinkerpop.gremlin.process.traversal.step.util.AbstractStep.next(AbstractStep.java:128)
at org.apache.tinkerpop.gremlin.process.traversal.step.util.AbstractStep.next(AbstractStep.java:38)
at org.apache.tinkerpop.gremlin.process.traversal.Traversal.iterate(Traversal.java:203)
at org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal.iterate(GraphTraversal.java:2694)
at org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal$Admin.iterate(GraphTraversal.java:178)
at org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.DefaultGraphTraversal.iterate(DefaultGraphTraversal.java:48)
at org.janusgraph.example.GraphApp.deleteElements(GraphApp.java:301)
at org.janusgraph.example.GraphApp.runApp(GraphApp.java:350)
at org.janusgraph.example.RemoteGraphApp.main(RemoteGraphApp.java:227)
here is the code :
public void deleteElements() {
try {
if (g == null) {
return;
}
LOGGER.info("deleting elements");
// note that this will succeed whether or not pluto exists
g.V().has("name", "pluto").drop().iterate();
if (supportsTransactions) {
g.tx().commit();
}
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
if (supportsTransactions) {
g.tx().rollback();
}
}
}
emmm.....i thought i have fixed this problem.....
the only reason perhaps the library version used doesn't match the gremlin-server's version;
I tried to turn the gremlin driver library to 3.2.9 version, and it works well.
You need to use the same Tinkerpop version JanusGraph is using, as this is an incompatible change that was introduced in Tinkerpop

How do I refresh a materialized view with activejdbc?

I've tried using Base.exec / new DB("default").exec("refresh materialized view concurrently ... and neither work. No errors, but the statement isn't run.
Finally figured this out. Not sure why, but Base.exec won't work, only Statement.executeUpdate.
// Open your connection
String sql = "refresh materialized view concurrently MY_VIEW";
try {
Connection conn = new DB("default").connection();
Statement stmt = conn.createStatement();
stmt.executeUpdate(sql);
conn.commit();
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}

Execute DDL from hibernate

I know that SchemaExport should be my friend. But I am using liquibase and want to execute the DDL - pure sql statements - generated from liquibase to recreate the database before every test method.
Do you see problems with the following code? I wonder that this seems to be so complicated ...
public static int executeScript(String sqlFileOnClasspath) {
Session sess = getSessionFactory().openSession();
Transaction ta = sess.beginTransaction();
int sqlCmd = 0;
try {
BufferedReader bReader = new BufferedReader(new InputStreamReader(
Util.class.getResourceAsStream(sqlFileOnClasspath), "UTF-8"));
String line;
while ((line = bReader.readLine()) != null) {
if (line.startsWith("--") || line.trim().isEmpty())
continue;
final String tmp = line;
sess.doWork(new Work() {
#Override
public void execute(Connection connection) throws SQLException {
connection.createStatement().execute(tmp);
}
});
sqlCmd++;
}
} catch (Exception ex) {
log.error("Couldn't execute " + sqlFileOnClasspath, ex);
} finally {
ta.commit();
sess.close();
}
return sqlCmd;
}
BTW: For liquibase you will need to do:
// remove all hibernate managed tables
SchemaExport schemaTool = new SchemaExport(getConfiguration());
schemaTool.drop(false, true);
// DROP TABLE DATABASECHANGELOGLOCK;
// DROP TABLE DATABASECHANGELOG;
executeScript("/drop-none-hib.sql");
// now execute the DDL statements from liquibase
int sqlCmd = executeScript("/schema.sql");
log.info("Executed " + sqlCmd + " sql commands");
Security
Directly executing unprepared statements may lead to SQL injection. However, you seem to read DDL statements from a static file, so this shouldn't be a problem, just wanted to note that.
Exception Handling
Missing entirely, e.g. properly closing the input streams, the connections etc. Also, it misses having detailed information on which of the statements failed if any of the SQLExceptions are being thrown. sqlCmd variable also counts failed statements, so I doubt the usefulness of this counter.
Parsing SQL/DDL
You're testing for -- style comments, but not for /* */ comments. That'll bite you some day. Also, the parser assumes a SQL statement per line. Longer statements may be multiline and end with semicolons which need to be trimmed. Not sure about how liquibase generates the statements though, so this may not be a real problem.
Transaction Handling
DDL statements cannot be rolled back anyway, so not sure about the transactions being helpful. Please correct me if i'm wrong.
Otherwise, as it's for testing, i looks fine to me too.
Why don't you simply use the hbm2ddl.auto configuration?
Or use transactional tests that roll the database back to its original state after each and every test?

How to tell the Session to throw the error query[NHibernate]?

I made a test class against the repository methods shown below:
public void AddFile<TFileType>(TFileType FileToAdd) where TFileType : File
{
try
{
_session.Save(FileToAdd);
_session.Flush();
}
catch (Exception e)
{
if (e.InnerException.Message.Contains("Violation of UNIQUE KEY"))
throw new ArgumentException("Unique Name must be unique");
else
throw e;
}
}
public void RemoveFile(File FileToRemove)
{
_session.Delete(FileToRemove);
_session.Flush();
}
And the test class:
try
{
Data.File crashFile = new Data.File();
crashFile.UniqueName = "NonUniqueFileNameTest";
crashFile.Extension = ".abc";
repo.AddFile(crashFile);
Assert.Fail();
}
catch (Exception e)
{
Assert.IsInstanceOfType(e, typeof(ArgumentException));
}
// Clean up the file
Data.File removeFile = repo.GetFiles().Where(f => f.UniqueName == "NonUniqueFileNameTest").FirstOrDefault();
repo.RemoveFile(removeFile);
The test fails. When I step in to trace the problem, I found out that when I do the _session.flush() right after _session.delete(), it throws the exception, and if I look at the sql it does, it is actually submitting a "INSERT INTO" statement, which is exactly the sql that cause UNIQUE CONSTRAINT error. I tried to encapsulate both in transaction but still same problem happens. Anyone know the reason?
Edit
The other stay the same, only added Evict as suggested
public void AddFile<TFileType>(TFileType FileToAdd) where TFileType : File
{
try
{
_session.Save(FileToAdd);
_session.Flush();
}
catch (Exception e)
{
_session.Evict(FileToAdd);
if (e.InnerException.Message.Contains("Violation of UNIQUE KEY"))
throw new ArgumentException("Unique Name must be unique");
else
throw e;
}
}
No difference to the result.
Call _session.Evict(FileToAdd) in the catch block. Although the save fails, FileToAdd is still a transient object in the session and NH will attempt to persist (insert) it the next time the session is flushed.
NHibernate Manual "Best practices" Chapter 22:
This is more of a necessary practice than a "best" practice. When
an exception occurs, roll back the ITransaction and close the ISession.
If you don't, NHibernate can't guarantee that in-memory state
accurately represents persistent state. As a special case of this,
do not use ISession.Load() to determine if an instance with the given
identifier exists on the database; use Get() or a query instead.

How can i force Nhibernate transaction to fail?

How can i force Nhibernate transaction to fail(from the calling code) so i can make sure that the failing behavior is working properly?
I can't modify the source code i just need to make it fail!
example :
public void DoSomething(/*Some parameters*/){
using (var tx = _session.BeginTransaction())
{
try
{
//Do something
tx.Commit();
}
catch (Exception)
{
if (tx != null) tx.Rollback();
throw;
}
} }
Throw an exception.
Throw an exception:
using(var sess = sf.OpenSession())
using(var tx = sess.BeginTransaction())
throw new Exception();
Close the connection:
using(var sess = sf.OpenSession())
using(var tx = sess.BeginTransaction())
sess.Connection.Close();
Rollback the transaction:
using(var sess = sf.OpenSession())
using(var tx = sess.BeginTransaction())
tx.Rollback();
If you have to have the exception occur within the tx.Commit(), then maybe insert/update a record with invalid data (e.g. a string that's too long for the db column).
One idea would be while you're debugging stop at the line immediately before the query execution will be begin and turn off the database then let the code run. However I assume there is a better and more programmatic way to test this.
Set some global variable (I know people had global variables but this is a good use) that the transaction internal code reads and if it sees the variable set throw an exception.
You can write a unit test to verify the expected behaviour of your code.
One way to do it is:
[Test]
public void VerifyExceptionIsThrown()
{
Assert.Throws<NHibernate.HibernateException>(
() =>
{
using (var tx = _session.BeginTransaction())
{
_session.Update(new Entity());
tx.Commit();
}
});
}
An attempt to update a transient entity will throw an exeption.
Alternatively if you use the NHibernateValidator you can explicitly fail a validation you have set, say you entity's Name property should no more than 10 characters long.
If you populate your entity's Name property with a string longer than 10 characters and you try to Save it, the tx.Commit() will throw you an exception.