<< Back to previous view

[JDBC-7] Clojure 1.2 compatibility Created: 06/Jun/11  Updated: 08/Jun/11  Resolved: 08/Jun/11

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Blocker
Reporter: Sean Corfield Assignee: Aaron Bedra
Resolution: Completed Votes: 0
Labels: None


 Description   

Per Aaron Bedra: "I just tried to use this on a 1.2 project that we have been working on for a while now and the dynamic defs are killing it. Can I change it to use the older ^{:dynamic true} syntax and release a new version? Is that the only thing that is keeping this off of 1.2? For now we need to make sure the new contrib libraries are 1.2 compatible, so people can start transitioning now."






[JDBC-51] Reflection warning removal Created: 07/Apr/13  Updated: 19/Apr/13  Resolved: 19/Apr/13

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Task Priority: Critical
Reporter: Sean Corfield Assignee: Sean Corfield
Resolution: Completed Votes: 0
Labels: None


 Description   

Before releasing 0.3.0, make a pass over the code and remove reflection where reasonable.



 Comments   
Comment by Sean Corfield [ 19/Apr/13 9:52 PM ]

Declared get-connection to return Connection in 0.3.0-alpha2.





[JDBC-54] db-transaction does not close connection? Created: 01/May/13  Updated: 07/May/13  Resolved: 07/May/13

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Critical
Reporter: Sean Corfield Assignee: Sean Corfield
Resolution: Completed Votes: 0
Labels: None


 Description   

See https://gist.github.com/aphyr/5493964



 Comments   
Comment by Sean Corfield [ 03/May/13 12:39 PM ]

Having reviewed the code, the result of get-connection is never closed, only the result of calling .getConnection on a PreparedStatement and that matches how java.jdbc has always worked, so I don't believe this is a problem. Aphyr mentioned on Twitter that he believes the problem was just due to his test code and not inherent in java.jdbc but we are still waiting for confirmation. Lowering priority for now.

Comment by Sean Corfield [ 07/May/13 8:30 PM ]

I believe I have verified this locally. Under the old API, a connection was only added explicitly at the "top" of a call chain. Under the new API, a connection can be added on-demand in many places which makes the logic much more complex and there are a couple of places where normal usage could indeed cause a connection leak.

Comment by Sean Corfield [ 07/May/13 9:27 PM ]

I believe this is resolved in the latest snapshot (which will become Alpha 4 at some point), as I've gone thru and changed how get-connection is called and ensured that with-open is used whenever a new connection is actually created.

The code needs a fair bit of clean up now tho'. I'm not happy with the result of adding that logic so I need to spend some time refactoring...





[JDBC-2] create-table should allow table-spec Created: 08/May/11  Updated: 09/Jul/11  Resolved: 09/Jul/11

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Sean Corfield Assignee: Sean Corfield
Resolution: Completed Votes: 0
Labels: None


 Description   

create-table takes a name and a seq of column-specs but does not allow any table-spec to follow that so you cannot, for example, the engine type / charset / etc.



 Comments   
Comment by Sean Corfield [ 09/Jul/11 2:18 PM ]

create-table now allows optional :table-spec "table level attributes" at the end of the specs.





[JDBC-6] Add hook to allow operations on PreparedStatement prior to query execution Created: 26/May/11  Updated: 10/Aug/11  Resolved: 10/Aug/11

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Sean Corfield Assignee: Sean Corfield
Resolution: Completed Votes: 0
Labels: None


 Description   

It would be very useful to be able to pass in a function argument to several c.j.j functions that would be called on the PreparedStatement before executing the query, for example, calling setFetchSize(). I'm not sure what the syntax should look like for this...



 Comments   
Comment by Sean Corfield [ 17/Jul/11 3:36 AM ]

I've started the work to reorganize the code to better expose the statement object for this sort of manipulation.

Comment by Sean Corfield [ 17/Jul/11 5:57 PM ]

Two options under consideration:

  • allow raw PreparedStatement to be passed in by user where appropriate so they have complete control
  • allow map of settings that would be used to create the PreparedStatement and set its options

I like the latter better but Alan Malloy made the point that the former may still be needed for total control anyway.

I'm leaning toward adding a function to ease creation of PreparedStatement objects to at least provide a clean API and then I'll consider how best to integrate that with the other functions.

Comment by Sean Corfield [ 17/Jul/11 10:02 PM ]

Added prepare-statement* to jdbc.internal which takes a connection, a SQL string and a map of options; returns a PreparedStatement. Will expose this in top-level.

with-query-results now allows the first element in the sql-params vector to be either:

  • PreparedStatement object created by the user
  • map of options passed to prepare-statement* in order to create the PreparedStatement

Options supported are in the docstring. May add additional post-creation options (beyond fetch-size and max-rows).

Comment by Sean Corfield [ 10/Aug/11 2:23 AM ]

Users have verified that being able to specify :fetch-size in with-query-results handles the common use cases for performance.





[JDBC-9] Solve duplicate column label issue Created: 10/Jun/11  Updated: 11/Oct/11  Resolved: 11/Oct/11

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Sean Corfield Assignee: Sean Corfield
Resolution: Completed Votes: 0
Labels: None


 Description   

Per Peter Siewart (and others):

– While working with clojure.java.jdbc, I kept running into the "ResultSet must have unique column labels" exception, so I rewrote it to automatically rename duplicate columns. Now, I can run "SELECT * FROM tbl1 JOIN tbl2 ON tbl1.id = tbl2.id" without causing any errors.

This would definitely be a nice enhancement but so far no one with a signed CA has offered a patch

Figuring out the appropriate renaming strategy is key - a sensible default with an optional function to allow users to specify how to do this? Or perhaps only renaming if users specify such a function?



 Comments   
Comment by Sean Corfield [ 11/Oct/11 4:12 PM ]

Applied a variant of Peter's patch and added unit tests.





[JDBC-8] Review (and fix) reflection warnings Created: 08/Jun/11  Updated: 17/Jul/11  Resolved: 17/Jul/11

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Task Priority: Major
Reporter: Sean Corfield Assignee: Sean Corfield
Resolution: Completed Votes: 0
Labels: None


 Description   

There are quite a few reflection warnings in the c.j.j code which should be reviewed and performance critical pieces type hinted.



 Comments   
Comment by Allen Rohner [ 09/Jul/11 3:50 PM ]

Empirically, I can tell you the one in do-prepared*, (.prepareStatement (connection), and the one in transaction* (let [con (connection*) ...) are both performance critical for me.

Comment by Sean Corfield [ 09/Jul/11 4:00 PM ]

Thanx Allen. The impression I get from clojure-dev is new contrib libraries should have zero reflection warnings so I plan to find and fix all such cases in c.j.j.

Comment by Sean Corfield [ 17/Jul/11 5:47 PM ]

All reflection warnings have been removed.





[JDBC-10] Attempts to return generated keys on batch inserts fails on PostgreSQL and MS SQL Server Created: 18/Jun/11  Updated: 27/Jun/11  Resolved: 27/Jun/11

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Sean Corfield Assignee: Sean Corfield
Resolution: Completed Votes: 0
Labels: None


 Description   

From andreasmk2:

"JDBC driver for PostgreSQL and ms-sql does not support returning of generated keys from statements executed in batch. The SQL exception was thrown when 'do-prepared*' was called with 'return-keys' set to true. Currently only the function 'insert-values' calls a new method 'do-single-prepared-get-keys*' when single relation is inserted."



 Comments   
Comment by Sean Corfield [ 27/Jun/11 5:54 PM ]

I just committed a potential fix for this. It's available in the Sonatype snapshots repo.





[JDBC-11] Transaction not rolled back on Throwable exception Created: 03/Jul/11  Updated: 17/Jul/11  Resolved: 17/Jul/11

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Sean Corfield Assignee: Sean Corfield
Resolution: Completed Votes: 1
Labels: None

Attachments: Text File 0001-Don-t-commit-transaction-in-case-of-exceptions.patch     Text File test-mechanism.patch    

 Description   

(transaction
(insert-values .....)
(throw (Throwable. "baaaaad")))

Reported by Sebastián Galkin on github.

Transactions rollback on Exception but not Throwable.



 Comments   
Comment by Sebastián Bernardo Galkin [ 03/Jul/11 11:07 PM ]

I think the correct behavior would be to call rollback on the transaction and not just not calling commit? The user will expect at the end of the transaction block one of commit or rollback to be called.

I was thinking about how to test this. How do you feel about a mock Connection object, where we can check if commit and/or rollback have been called as part of the test?

The same mechanism could be used to test other features.

Comment by Sebastián Bernardo Galkin [ 04/Jul/11 12:23 AM ]

I was thinking in something like the attached for testing the issue (and other functionality).
It needs several improvements, but it's enough to get the idea.
What do you think?

Comment by Sean Corfield [ 04/Jul/11 12:27 AM ]

FYI, here's the IRC discussion about this, for the record:

[5:11pm] <paraseba>
In clojure.java.jdbc there is a transaction function, which is supposed to rollback if the passed body throws an exception, but it only does that in case of an Exception, not any Throwable. What's the rationale behind this?
[5:11pm] <paraseba>
I'd want my transaction rolledback in case of any errors
[5:12pm] <paraseba>
seancorfield: maybe you can explain me this?
[5:53pm] <amalloy>
paraseba: catching Errors is generally a bad practice. i'm not saying it's wrong all the time, but Errors are often unrecoverable anyway
[5:53pm] <amalloy>
eg, "You ran out of heap space! I can't even allocate memory to throw an exception!"
[5:54pm] <paraseba>
but, even in the worst conditions, shouldn't we try to rollback the transaction? is not better that commiting in this unexpected error condition?
[5:55pm] <paraseba>
we can then rethrow the Throwable, after trying to rollback
[5:55pm] <lucian>
paraseba: i don't think the db will commit if it gives you an error
[5:55pm] <lucian>
and as amalloy, errors like OOM are best solved with exit()
[5:55pm] <paraseba>
lucian: it will ... jdbc is catching Exception and rolling back in that case .... but it commits in a finally
[5:56pm] <paraseba>
so, if you have an Error thrown, it will commit
[5:56pm] <paraseba>
I guess that's more surprising than a rollback
[5:57pm] <paraseba>
the logic is .... (try do-your-thing (catch Exception roll-back) (finally commit))
[5:57pm] <lucian>
paraseba: well, then maybe you don't want to commit in finally?
[5:57pm] <paraseba>
I don't, not if I got an Error
[5:58pm] <amalloy>
lucian: i think he's upset that a library he's using is committing on error
[5:59pm] <paraseba>
amalloy: I can solve it easily by wrapping my operations in a catch Throwable -> rollback -> rethrow, but I think it's not the right behavior for the library
[5:59pm] <paraseba>
I would expect a commit only if the block ended without any kind of exceptions or errors. don't you agree ?
[6:01pm] <amalloy>
paraseba: meh. all kinds of weird stuff can happen if an Error occurs; i wouldn't be entirely certain that an attempt to "recover" makes things worse due to some weird program state caused by the Error. i mean, my completely-unresearched opinion is that catching Throwable would be better, but you can't really rely for your program's correctness on anything that happens after an Error
[6:02pm] <paraseba>
but, we are forcing a commit after an Error
[6:04pm] <paraseba>
the usual logic should be .... (do do-your-thing (commit)) if do-your-thing throws anything ... no commit is done. Puting a commit in a finally enforces the commit, even after Errors
[6:06pm] <amalloy>
yeah, i think i agree
[6:08pm] <paraseba>
amalloy: ok, I'll report an issue, thanks

Comment by Sebastián Bernardo Galkin [ 09/Jul/11 2:36 PM ]

It's important to realize that there are 2 problems here.

a.- Transaction not rolled back on Throwable
b.- The original Exception is "swallowed" and a new, different one is thrown

I think both are equally serious.

Comment by Sean Corfield [ 09/Jul/11 3:57 PM ]

I agree Sebastian. I've raised this issue for input from clojure-dev (looking for stylistic guidelines for contrib libraries) because I think both problems need to be fixed.

My current leaning is toward supporting three paths:

  • success: rollback transaction if user code sets rollback true, else commit
  • Exception: rollback transaction and rethrow (without wrapping)
  • Throwable: allow it to escape, take no action
Comment by Sebastián Bernardo Galkin [ 12/Jul/11 11:05 AM ]

I'm attaching a patch that fixes the problem without adding any tests.

Comment by Sean Corfield [ 17/Jul/11 3:28 AM ]

On success, commit unless rollback has been set (in which case rollback).
On Exception, rollback and rethrow as-is.
On Error (Throwable), allow it to escape.
In all cases, set rollback false and restore auto-commit setting.

The only two changes here should be:

  • Exception is no longer wrapped when thrown (may break code that expected the wrapping?)
  • No commit attempted on Error (Throwable)




[JDBC-12] exceptions when trying to insert into apache derby Created: 24/Jul/11  Updated: 25/Jul/11  Resolved: 25/Jul/11

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Kevin Downey Assignee: Sean Corfield
Resolution: Completed Votes: 0
Labels: None

Waiting On: Sean Corfield

 Description   

java.sql.SQLException: Only executeBatch and clearBatch allowed in the middle of a batch.
at org.apache.derby.impl.jdbc.SQLExceptionFactory40.getSQLException(Unknown Source)
at org.apache.derby.impl.jdbc.Util.newEmbedSQLException(Unknown Source)
at org.apache.derby.impl.jdbc.Util.newEmbedSQLException(Unknown Source)
at org.apache.derby.impl.jdbc.Util.generateCsSQLException(Unknown Source)
at org.apache.derby.impl.jdbc.EmbedConnection.newSQLException(Unknown Source)
at org.apache.derby.impl.jdbc.ConnectionChild.newSQLException(Unknown Source)
at org.apache.derby.impl.jdbc.EmbedStatement.checkIfInMiddleOfBatch(Unknown Source)
at org.apache.derby.impl.jdbc.EmbedPreparedStatement.executeStatement(Unknown Source)
at org.apache.derby.impl.jdbc.EmbedPreparedStatement.executeUpdate(Unknown Source)
at clojure.java.jdbc.internal$do_prepared_return_keys_STAR_$fn__84.invoke(internal.clj:272)
at clojure.java.jdbc.internal$transaction_STAR_.invoke(internal.clj:185)
at clojure.java.jdbc.internal$do_prepared_return_keys_STAR_.doInvoke(internal.clj:272)
at clojure.lang.RestFn.applyTo(RestFn.java:140)
at clojure.core$apply.invoke(core.clj:542)
at clojure.java.jdbc$insert_values.doInvoke(jdbc.clj:259)
at clojure.lang.RestFn.invoke(RestFn.java:443)
at hiredman.triples$store_triple$fn_471$fn_472.invoke(triples.clj:39)
at clojure.java.jdbc.internal$transaction_STAR_.invoke(internal.clj:174)
at hiredman.triples$store_triple$fn__471.invoke(triples.clj:39)
at clojure.java.jdbc.internal$with_connection_STAR_.invoke(internal.clj:156)
at hiredman.triples$store_triple.invoke(triples.clj:39)
at hiredman.clojurebot.factoids$fn__2689.invoke(factoids.clj:139)
at clojure.lang.MultiFn.invoke(MultiFn.java:167)
at hiredman.clojurebot.factoids$factoid_command_run.invoke(factoids.clj:173)
at conduit.core$fn_284$a_arr285$a_arr_286.invoke(core.clj:233)
at conduit.core$select_fn.invoke(core.clj:148)
at clojure.lang.AFn.applyToHelper(AFn.java:165)
at clojure.lang.AFn.applyTo(AFn.java:151)
at clojure.core$apply.invoke(core.clj:542)
at clojure.core$partial$fn__3678.doInvoke(core.clj:2009)
at clojure.lang.RestFn.invoke(RestFn.java:409)
at conduit.core$comp_fn$a_comp__193.invoke(core.clj:45)
at conduit.core$comp_fn$a_comp__193.invoke(core.clj:42)
at conduit.core$select_fn.invoke(core.clj:148)
at clojure.lang.AFn.applyToHelper(AFn.java:165)
at clojure.lang.AFn.applyTo(AFn.java:151)
at clojure.core$apply.invoke(core.clj:542)
at clojure.core$partial$fn__3678.doInvoke(core.clj:2009)
at clojure.lang.RestFn.invoke(RestFn.java:409)
at conduit.core$comp_fn$a_comp__193.invoke(core.clj:45)
at conduit.core$comp_fn$a_comp__193.invoke(core.clj:42)
at conduit.core$select_fn.invoke(core.clj:148)
at clojure.lang.AFn.applyToHelper(AFn.java:165)
at clojure.lang.AFn.applyTo(AFn.java:151)
at clojure.core$apply.invoke(core.clj:542)
at clojure.core$partial$fn__3678.doInvoke(core.clj:2009)
at clojure.lang.RestFn.invoke(RestFn.java:409)
at conduit.core$comp_fn$a_comp__193.invoke(core.clj:45)
at conduit.core$comp_fn$a_comp__193.invoke(core.clj:42)
at conduit.core$select_fn.invoke(core.clj:148)
at clojure.lang.AFn.applyToHelper(AFn.java:165)
at clojure.lang.AFn.applyTo(AFn.java:151)
at clojure.core$apply.invoke(core.clj:542)
at clojure.core$partial$fn__3678.doInvoke(core.clj:2009)
at clojure.lang.RestFn.invoke(RestFn.java:409)
at conduit.core$comp_fn$a_comp__193.invoke(core.clj:45)
at conduit.core$comp_fn$a_comp__193.invoke(core.clj:42)
at conduit.core$select_fn.invoke(core.clj:148)
at clojure.lang.AFn.applyToHelper(AFn.java:165)
at clojure.lang.AFn.applyTo(AFn.java:151)
at clojure.core$apply.invoke(core.clj:542)
at clojure.core$partial$fn__3678.doInvoke(core.clj:2009)
at clojure.lang.RestFn.invoke(RestFn.java:409)
at conduit.core$comp_fn$a_comp__193.invoke(core.clj:45)
at conduit.core$comp_fn$a_comp__193.invoke(core.clj:42)
at conduit.core$select_fn.invoke(core.clj:148)
at clojure.lang.AFn.applyToHelper(AFn.java:165)
at clojure.lang.AFn.applyTo(AFn.java:151)
at clojure.core$apply.invoke(core.clj:542)
at clojure.core$partial$fn__3678.doInvoke(core.clj:2009)
at clojure.lang.RestFn.invoke(RestFn.java:409)
at conduit.core$comp_fn$a_comp__193.invoke(core.clj:45)
at conduit.core$comp_fn$a_comp__193.invoke(core.clj:42)
at conduit.core$select_fn.invoke(core.clj:148)
at clojure.lang.AFn.applyToHelper(AFn.java:165)
at clojure.lang.AFn.applyTo(AFn.java:151)
at clojure.core$apply.invoke(core.clj:542)
at clojure.core$partial$fn__3678.doInvoke(core.clj:2009)
at clojure.lang.RestFn.invoke(RestFn.java:409)
at conduit.core$comp_fn$a_comp__193.invoke(core.clj:45)
at conduit.core$comp_fn$a_comp__193.invoke(core.clj:42)
at conduit.core$select_fn.invoke(core.clj:148)
at clojure.lang.AFn.applyToHelper(AFn.java:165)
at clojure.lang.AFn.applyTo(AFn.java:151)
at clojure.core$apply.invoke(core.clj:542)
at clojure.core$partial$fn__3678.doInvoke(core.clj:2009)
at clojure.lang.RestFn.invoke(RestFn.java:409)
at conduit.core$comp_fn$a_comp__193.invoke(core.clj:45)
at conduit.core$comp_fn$a_comp__193.invoke(core.clj:42)
at conduit.core$select_fn.invoke(core.clj:148)
at clojure.lang.AFn.applyToHelper(AFn.java:165)
at clojure.lang.AFn.applyTo(AFn.java:151)
at clojure.core$apply.invoke(core.clj:542)
at clojure.core$partial$fn__3678.doInvoke(core.clj:2009)
at clojure.lang.RestFn.invoke(RestFn.java:409)
at conduit.core$comp_fn$a_comp__193.invoke(core.clj:45)
at conduit.core$select_fn.invoke(core.clj:148)
at clojure.lang.AFn.applyToHelper(AFn.java:165)
at clojure.lang.AFn.applyTo(AFn.java:151)
at clojure.core$apply.invoke(core.clj:542)
at clojure.core$partial$fn__3678.doInvoke(core.clj:2009)
at clojure.lang.RestFn.invoke(RestFn.java:409)
at conduit.core$comp_fn$a_comp__193.invoke(core.clj:45)
at conduit.core$comp_fn$a_comp__193.invoke(core.clj:42)
at conduit.core$select_fn.invoke(core.clj:148)
at clojure.lang.AFn.applyToHelper(AFn.java:165)
at clojure.lang.AFn.applyTo(AFn.java:151)
at clojure.core$apply.invoke(core.clj:542)
at clojure.core$partial$fn__3678.doInvoke(core.clj:2009)
at clojure.lang.RestFn.invoke(RestFn.java:409)
at conduit.core$comp_fn$a_comp__193.invoke(core.clj:45)
at conduit.core$comp_fn$a_comp__193.invoke(core.clj:42)
at conduit.core$select_fn.invoke(core.clj:148)
at clojure.lang.AFn.applyToHelper(AFn.java:165)
at clojure.lang.AFn.applyTo(AFn.java:151)
at clojure.core$apply.invoke(core.clj:542)
at clojure.core$partial$fn__3678.doInvoke(core.clj:2009)
at clojure.lang.RestFn.invoke(RestFn.java:409)
at conduit.core$comp_fn$a_comp__193.invoke(core.clj:45)
at conduit.core$comp_fn$a_comp__193.invoke(core.clj:42)
at conduit.core$select_fn.invoke(core.clj:148)
at clojure.lang.AFn.applyToHelper(AFn.java:165)
at clojure.lang.AFn.applyTo(AFn.java:151)
at clojure.core$apply.invoke(core.clj:542)
at clojure.core$partial$fn__3678.doInvoke(core.clj:2009)
at clojure.lang.RestFn.invoke(RestFn.java:409)
at conduit.core$comp_fn$a_comp__193.invoke(core.clj:45)
at conduit.core$comp_fn$a_comp__193.invoke(core.clj:42)
at conduit.core$select_fn.invoke(core.clj:148)
at clojure.lang.AFn.applyToHelper(AFn.java:165)
at clojure.lang.AFn.applyTo(AFn.java:151)
at clojure.core$apply.invoke(core.clj:542)
at clojure.core$partial$fn__3678.doInvoke(core.clj:2009)
at clojure.lang.RestFn.invoke(RestFn.java:409)
at conduit.core$comp_fn$a_comp__193.invoke(core.clj:45)
at conduit.core$comp_fn$a_comp__193.invoke(core.clj:42)
at conduit.core$select_fn.invoke(core.clj:148)
at clojure.lang.AFn.applyToHelper(AFn.java:165)
at clojure.lang.AFn.applyTo(AFn.java:151)
at clojure.core$apply.invoke(core.clj:542)
at clojure.core$partial$fn__3678.doInvoke(core.clj:2009)
at clojure.lang.RestFn.invoke(RestFn.java:409)
at conduit.core$comp_fn$a_comp__193.invoke(core.clj:45)
at conduit.core$comp_fn$a_comp__193.invoke(core.clj:42)
at conduit.core$comp_fn$a_comp__193.invoke(core.clj:45)
at conduit.core$a_except$a_except__307.invoke(core.clj:350)
at clojure.lang.AFn.applyToHelper(AFn.java:165)
at clojure.lang.AFn.applyTo(AFn.java:151)
at clojure.core$apply.invoke(core.clj:542)
at clojure.core$partial$fn__3678.doInvoke(core.clj:2009)
at clojure.lang.RestFn.invoke(RestFn.java:409)
at conduit.core$comp_fn$a_comp__193.invoke(core.clj:42)
at clojurebot.conduit$a_indirect$this_fn__500.invoke(conduit.clj:9)
at conduit.core$comp_fn$a_comp__193.invoke(core.clj:45)
at conduit.irc$reply_fn$irc_reply_fn__350.invoke(irc.clj:22)
at clojure.lang.AFn.applyToHelper(AFn.java:165)
at clojure.lang.AFn.applyTo(AFn.java:151)
at clojure.core$apply.invoke(core.clj:542)
at clojure.core$partial$fn__3678.doInvoke(core.clj:2009)
at clojure.lang.RestFn.invoke(RestFn.java:409)
at conduit.core$select_fn.invoke(core.clj:148)
at clojure.lang.AFn.applyToHelper(AFn.java:165)
at clojure.lang.AFn.applyTo(AFn.java:151)
at clojure.core$apply.invoke(core.clj:542)
at clojure.core$partial$fn__3678.doInvoke(core.clj:2009)
at clojure.lang.RestFn.invoke(RestFn.java:409)
at conduit.irc$irc_run$handle_msg__421.invoke(irc.clj:166)
at clojure.lang.AFn.applyToHelper(AFn.java:165)
at clojure.lang.AFn.applyTo(AFn.java:151)
at clojure.core$apply.invoke(core.clj:542)
at clojure.core$partial$fn__3678.doInvoke(core.clj:2009)
at clojure.lang.RestFn.invoke(RestFn.java:409)
at conduit.core$comp_fn$a_comp__193.invoke(core.clj:45)
at conduit.core$a_run.invoke(core.clj:28)
at conduit.irc$irc_run$run__424.invoke(irc.clj:175)
at conduit.irc$irc_run.doInvoke(irc.clj:179)
at clojure.lang.RestFn.applyTo(RestFn.java:140)
at clojure.core$apply.invoke(core.clj:542)
at clojurebot.core$main$fn_4654.invoke(core.clj:214)
at clojure.lang.AFn.call(AFn.java:18)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:680)
Caused by: java.sql.SQLException: Only executeBatch and clearBatch allowed in the middle of a batch.
at org.apache.derby.impl.jdbc.SQLExceptionFactory.getSQLException(Unknown Source)
at org.apache.derby.impl.jdbc.SQLExceptionFactory40.wrapArgsForTransportAcrossDRDA(Unknown Source)
... 185 more

replacing .executeUpdate with .executeBatch in do-prepared-return-keys* seems to fix the problem and be what was meant in the first place, the result is bound to 'counts' and .executeUpdate returns a single count while .executeBatch returns multiple



 Comments   
Comment by Sean Corfield [ 24/Jul/11 3:38 PM ]

Unfortunately .executeBatch had to be changed to .executeUpdate in order to solve JDBC-10:

https://github.com/clojure/java.jdbc/commit/9240d66c9124454187416861a0e2021952eb4f40

MS SQL Server and PostgreSQL both fail on .executeUpdate in that call position.

Clearly we need as many of these DBs up and running for automated testing as possible before I can attempt to fix this so that I don't accidentally break something else.

Comment by Sean Corfield [ 24/Jul/11 5:26 PM ]

I now have some unit tests for MySQL, HSQLDB and Derby. insert-records fails with the exception reported here, only for Derby. I'll complete the suite of tests, try to get PostgreSQL and MS SQL Server tests running as well and then I'll be in a good position to fix things...

Comment by Sean Corfield [ 25/Jul/11 4:52 PM ]

The culprit was .addBatch which has now been removed and do-prepared-return-keys now explicitly only has one param-group argument.





[JDBC-15] resultset-seq uses structmap which has been deprecated Created: 13/Aug/11  Updated: 16/Oct/11  Resolved: 16/Oct/11

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Task Priority: Major
Reporter: Sean Corfield Assignee: Sean Corfield
Resolution: Completed Votes: 0
Labels: None


 Description   

structmap has been deprecated. The open question is whether to replace its use with record or regular map (I'd expect the latter would be less surprising?).



 Comments   
Comment by Sean Corfield [ 12/Oct/11 4:29 PM ]

See JDBC-3 for some background on this.

Comment by Sean Corfield [ 16/Oct/11 3:41 PM ]

The way resultset-seq uses create-struct and struct doesn't seem to leverage any inherent functionality of structmaps except perhaps some vague guarantee of ordering of columns in rows. Replacing the create-struct / struct calls with

(into {} (map vector keys (row-values)))

maintains the order up to 16 columns (PersistentArrayMap) so that seems a reasonable compromise.

I'm not sure that preserving order is something that should be documented or supported?

Comment by Sean Corfield [ 16/Oct/11 4:32 PM ]

No longer uses structmap. Attempts to provide column order (up to 16 columns) but don't rely on that... it was never documented as a guarantee!





[JDBC-16] do-prepared doesn't throw on invalid SQL Created: 07/Sep/11  Updated: 11/Oct/11  Resolved: 11/Oct/11

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Allen Rohner Assignee: Sean Corfield
Resolution: Completed Votes: 0
Labels: None


 Description   
(jdbc/do-prepared "syntactically invalid SQL")

returns nil, while

(jdbc/do-commands "syntactically invalid SQL")
throws as expected.



 Comments   
Comment by Allen Rohner [ 07/Sep/11 4:00 PM ]

Actually, do-prepared doesn't seem to do anything at all. (jdbc/do-commands "insert into foo (foo,bar) VALUES (1,2)") works as expected, same command with do-prepared doesn't do anything.

Comment by Sean Corfield [ 11/Oct/11 2:12 PM ]

Ensure .addBatch is called even when there are no param-groups.





[JDBC-23] Prepared statements' parameters don't get applied Created: 21/Nov/11  Updated: 22/Nov/11  Resolved: 22/Nov/11

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Ghadi Shayban Assignee: Sean Corfield
Resolution: Completed Votes: 0
Labels: None
Environment:

Oracle JDBC, probably applies universally


Attachments: Text File param.patch    
Patch: Fixed

 Description   

Basically a goof line in the code.
If you pass a PreparedStatement to with-query-results, it chops off too many items from the param list, whereas if you pass in straight SQL, it's ok.

Deleted the offending line



 Comments   
Comment by Sean Corfield [ 22/Nov/11 1:01 AM ]

Thanx Ghadi.





[JDBC-32] with-connection does not accept standard jdbc URIs. Created: 18/May/12  Updated: 10/Jun/12  Resolved: 10/Jun/12

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Tyler Jennings Assignee: Sean Corfield
Resolution: Completed Votes: 0
Labels: None
Environment:

clojure 1.4.0
clojure.java.jdbc 0.2.1



 Description   

with-connect and other functions accepting a db-spec do not support standard jdbc uris, like this one:

jdbc:mysql://localhost:3306/<database>

In my environment passing that uri to yields an exception:

Exception in thread "main" java.lang.NullPointerException
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:247)
at clojure.lang.RT.loadClassForName(RT.java:2050)
at clojure.java.jdbc$get_connection.invoke(jdbc.clj:175)
at clojure.java.jdbc$get_connection.invoke(jdbc.clj:166)
at clojure.java.jdbc$get_connection.invoke(jdbc.clj:168)
at clojure.java.jdbc$with_connection_STAR_.invoke(jdbc.clj:299)
at bungle_o.migration$create_exceptions.invoke(migration.clj:17)
at bungle_o.migration$_main.invoke(migration.clj:21)
at clojure.lang.Var.invoke(Var.java:411)
at user$eval191.invoke(NO_SOURCE_FILE:1)
at clojure.lang.Compiler.eval(Compiler.java:6511)
at clojure.lang.Compiler.eval(Compiler.java:6501)
at clojure.lang.Compiler.eval(Compiler.java:6477)
at clojure.core$eval.invoke(core.clj:2797)
at clojure.main$eval_opt.invoke(main.clj:297)
at clojure.main$initialize.invoke(main.clj:316)
at clojure.main$null_opt.invoke(main.clj:349)
at clojure.main$main.doInvoke(main.clj:427)
at clojure.lang.RestFn.invoke(RestFn.java:421)
at clojure.lang.Var.invoke(Var.java:419)
at clojure.lang.AFn.applyToHelper(AFn.java:163)
at clojure.lang.Var.applyTo(Var.java:532)
at clojure.main.main(main.java:37)

This URI works fine, however:

mysql://localhost:3306/<database>

Is this intentional or a bug?

Here's the mysql documentation for reference: http://dev.mysql.com/doc/refman/5.0/en/connector-j-reference-configuration-properties.html



 Comments   
Comment by Sean Corfield [ 10/Jun/12 5:48 PM ]

It was a bug. Thanks for spotting that.





[JDBC-28] prepared-statement* behaves different on OpenJDK 1.6 and OS X Java 1.6. Created: 30/Mar/12  Updated: 31/Mar/12  Resolved: 31/Mar/12

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Jeroen van Dijk Assignee: Sean Corfield
Resolution: Declined Votes: 0
Labels: None
Environment:

Ubuntu
OpenJDK:
java version "1.6.0_22"
OpenJDK Runtime Environment (IcedTea6 1.10.6) (6b22-1.10.6-0ubuntu1)
OpenJDK 64-Bit Server VM (build 20.0-b11, mixed mode)

OS X Java
java version "1.6.0_29"
Java(TM) SE Runtime Environment (build 1.6.0_29-b11-402-10M3527)
Java HotSpot(TM) 64-Bit Server VM (build 20.4-b02-402, mixed mode)

Relevant clojure libraries
[org.clojure/clojure "1.3.0"]
[korma "0.3.0-beta9"]
[org.clojure/java.jdbc "0.1.3"]
[postgresql/postgresql "9.1-901.jdbc3"]



 Description   

I'm using the Clojure library Korma to generate SQL for Postgres, which depends on clojure.java.jdbc. Recently I added a custom 'upsert' query. Using it on normal java 1.6 is fine, but on openJDK it breaks due to the use of 'java.sql.Statement/RETURN_GENERATED_KEYS'. This makes the Postgres driver add a seemingly random "RETURNING *" at the end of the query.

On normal Java 1.6 java.sql.Statement/RETURN_GENERATED_KEYS doesn't exist and then a exception is caught and everything works as expected. Sounds like the world up side down, but I'm probably missing the rational behind this.

The line that causes the weird behavior is here: https://github.com/clojure/java.jdbc/blob/master/src/main/clojure/clojure/java/jdbc/internal.clj#L315

The code that showcases the 'bug' is here:
https://gist.github.com/2e8a3d55d80707ce79e0

(Sorry for the monkey patching in the gist, if there is a better way I would love to hear it)

I guess a naive patch would be to remove the java.sql.Statement/RETURN_GENERATED_KEYS line, but there must be a reason for its existence I assume.



 Comments   
Comment by Sean Corfield [ 31/Mar/12 1:30 AM ]

RETURN_GENERATED_KEYS is required for inserts to return the generated keys. Since this works on Sun's Java 6 and with all intended databases, and is per spec, it is not going away.

Right now OpenJDK / PostgreSQL is not a supported combination, sorry.





[JDBC-19] Consolidate jdbc / jdbc.internal namespaces (post 0.1.0) Created: 12/Oct/11  Updated: 23/Apr/12  Resolved: 23/Apr/12

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Sean Corfield Assignee: Sean Corfield
Resolution: Completed Votes: 0
Labels: None


 Description   

Since clojure.java.jdbc.internal is not intended to be called externally, merge it into clojure.java.jdbc and make its members private. Then merge simplify functions where appropriate.



 Comments   
Comment by Sean Corfield [ 23/Apr/12 3:22 AM ]

Fixed in 0.2.0 release.





[JDBC-34] get-connection's URI conventions incompatible with PostgreSQL Created: 12/Jun/12  Updated: 31/Jul/12  Resolved: 18/Jun/12

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Chas Emerick Assignee: Sean Corfield
Resolution: Completed Votes: 0
Labels: None


 Description   

get-connection requires that provided URIs be structured like so:

dbtype://user:password@host:port/database

This is often sufficient, but many PostgreSQL URIs require the use of URI parameters to further configure connections. For example, postgresql.heroku.com provides JDBC URIs like this:

jdbc:postgresql://ec2-22-11-231-117.compute-1.amazonaws.com:5432/d1kuttup5cbafl6?user=pcgoxvmssqabye&password=PFZXtxaLFhIX-nCA0Vi4UbJ6lH&ssl=true

...which, when used outside of Heroku's network, require a further sslfactory=org.postgresql.ssl.NonValidatingFactory parameter.

The PostgreSQL JDBC driver supports a number of different URI parameters, and recommends putting credentials into parameters rather than using the user:password@ convention. Peeking over at the Oracle thin JDBC driver's docs, it appears that it expects credentials using its own idiosyncratic convention, user/password@.

<opinion>
This all leads me to think that get-connection should pass URIs along to DriverManager without modification, and leave URI format conventions up to the drivers involved. For now, my workaround is to do essentially that, using a map like this as input to with-connection et al.:

{:factory #(DriverManager/getConnection (:url %))
 :url "jdbc:postgresql://ec2-22-11-231-117.compute-1.amazonaws.com:5432/d1kuttup5cbafl6?user=pcgoxvmssqabye&password=PFZXtxaLFhIX-nCA0Vi4UbJ6lH&ssl=true"}

That certainly works, but I presume that such a workaround won't occur to many users, despite the docs/source.
</opinion>

I don't think I've used java.jdbc enough (or RDMBS' enough of late) to comfortably provide a patch (or feel particularly confident in the suggestion above). Hopefully the report is helpful in any case.



 Comments   
Comment by Sean Corfield [ 14/Jun/12 1:36 AM ]

How about an option that takes a map like:

{:connection-uri "jdbc:postgresql://ec2-22-11-231-117.compute-1.amazonaws.com:5432/d1kuttup5cbafl6?user=pcgoxvmssqabye&password=PFZXtxaLFhIX-nCA0Vi4UbJ6lH&ssl=true"}

Essentially as a shorthand for the workaround you've come up with?

Comment by Sean Corfield [ 15/Jun/12 10:20 PM ]

Try 0.2.3-SNAPSHOT which has support for :connection-uri and let me know if that is a reasonable solution for you?

Comment by Chas Emerick [ 18/Jun/12 3:35 PM ]

Yup, 0.2.3-SNAPSHOT's :connection-uri works fine. I've since moved on to using a pooled datasource, but this will hopefully be a more obvious path to newcomers than having to learn about :factory and DriverManager.

Comment by Sean Corfield [ 18/Jun/12 3:52 PM ]

Resolved by adding :connection-uri option.

Comment by Carlos [ 28/Jul/12 8:09 PM ]

accessing an heroku database outside heroku, "sslfactory=org.postgresql.ssl.NonValidatingFactory" doesn't work. i get "ERROR: syntax error at or near "user" Position: 13 - (class org.postgresql.util.PSQLException". this happens whether adding it to :subname or :connection-uri Strings

another minor issue - why the documentation of "with-connection" (0.2.3) refers the following format for the connection string URI:
"subprotocol://user:password@host:post/subname
An optional prefix of jdbc: is allowed."
but the URI which can actually be parsed successfully is like the one above: jdbc:postgresql://ec2-22-11-231-117.compute-1.amazonaws.com:5432/d1kuttup5cbafl6?user=pcgoxvmssqabye&password=PFZXtxaLFhIX-nCA0Vi4UbJ6lH&ssl=true
"subprotocol://user:password@host:post/subname" (format like the DATABASE environment variables on heroku) will not be parsed correctly. why the format for the URI that is used on heroku is not supported by the parser?

maybe i'm doing something wrong here

thanks in advance

Comment by Sean Corfield [ 29/Jul/12 4:57 PM ]

Carlos, the :connection-uri passes the string directly to the driver with no parsing. The exception you're seeing is coming from inside the PostgreSQL driver so you'll have to consult the documentation for the driver.

The three "URI" styles accepted by java.jdbc are:

  • :connection-uri - passed directly to the driver with no parsing or other logic in java.jdbc,
  • :uri - a pre-parsed Java URI object,
  • a string literal - any optional "jdbc:" prefix is ignored, then the string is parsed by logic in java.jdbc, based on the pattern shown (subprotocol://user:password@host:port/subname).

If you're using :connection-uri (which is used on its own), you're dealing with the JDBC driver directly.

If you're using :uri or a bare string literal, you're dealing with java.jdbc's parsing (implemented by Phil Hagelberg - of Heroku).

Hope that clarifies?

Comment by Carlos [ 29/Jul/12 8:36 PM ]

Sean, thank you for such comprehensive explanation.

Still, it didn't work with any of the options. I used before a postgres JDBC driver to export to the same database (in an SQL modeller - SQLEditor for the MAC) and it worked (though it would connect some times, but others not). The connection String used was like "jdbc:postgresql://host:port/database?user=xxx&password=yyy&ssl=true&sslfactory=org.postgresql.ssl.NonValidatingFactory". The driver name was "org.postgresql.Driver" (JDBC4). Anyway, time to give up. I will just use a local database.

Thank you!

Comment by Carlos [ 31/Jul/12 7:20 PM ]

Sean, JDBC combinations were working after. i was neglecting an insert operation in a table with a reserved sql keyword "user", so i was getting a "ERROR: syntax error at or near "user" Position: 13", and therefore the connection was already established at the time.

i'm sorry for all the trouble answering the question (_

thank you

Comment by Sean Corfield [ 31/Jul/12 7:46 PM ]

Glad you got to the bottom of it and confirmed that it wasn't a problem in java.jdbc!





[JDBC-36] using exisiting java based connection pool in clojure Created: 24/Jul/12  Updated: 12/Aug/12  Resolved: 12/Aug/12

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Amir Assignee: Sean Corfield
Resolution: Declined Votes: 0
Labels: None


 Description   

We have a connection pool in Java and would like to use the same for our complete project where code is mixture of Clojure/Java.

(def db (ConnectionManager/getConnection)) ; #<ConnectionHandle com.jolbox.bonecp.ConnectionHandle@53371566> connection type we get after excuting this line
sql/with-connection db
(sql/with-query-results res ["select * from DummyTable where rownum <=100"] (vec res)
(map #(println (class (val %)) " " (key %)) (first res))
)
)



 Comments   
Comment by Amir [ 24/Jul/12 3:00 AM ]

If we execute the above (with connection - with-query results) i get the following exception

IllegalArgumentException db-spec com.jolbox.bonecp.ConnectionHandle@53371566 is missing a required parameter clojure.java.jdbc/get-connection (jdbc.clj:192)

Comment by Sean Corfield [ 24/Jul/12 12:34 PM ]

Use the :datasource option to define your db-spec:

(def db {:datasource bonecpDataSourceObject})

I looked at the BoneCP docs and I don't see a ConnectionManager class but if you define the db-spec based on the BoneCPDataSource object, java.jdbc will call getConnection on that object to get a working connection for operations.

Comment by Sean Corfield [ 31/Jul/12 7:49 PM ]

Amir, have you had a chance to try my suggestion?

Comment by Amir [ 01/Aug/12 2:20 AM ]

Hi Sean,

No, we moved to clojure based pooling in a while. We thought its better to have all stuff in clojure rather than having java+clojure. But i can give it a try today.

Thanks for your suggestion. will keep you posted.

Comment by Sean Corfield [ 12/Aug/12 9:35 PM ]

I'll close this out then Amir, thanx.

Comment by Sean Corfield [ 12/Aug/12 9:36 PM ]

I believe there is a way to access the the BoneCP connection pool directly and use it with java.jdbc as-is, however it is no longer an issue for the creator of this ticket.





[JDBC-30] Consider to make do-prepared-return-keys public Created: 10/May/12  Updated: 10/May/12  Resolved: 10/May/12

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Roman Scherer Assignee: Sean Corfield
Resolution: Completed Votes: 0
Labels: None


 Description   

Libraries like Korma, that build upon clojure.java.jdbc depend
on, or have use cases for do-prepared-return-keys. It's a useful
function and we would like to use it. As discussed over here:

https://github.com/ibdknox/Korma/pull/60#issuecomment-5630604



 Comments   
Comment by Sean Corfield [ 10/May/12 2:12 PM ]

Made do-prepared-return-keys public. Will cut a new build.





[JDBC-31] distinct? throws clojure.lang.ArityException, when applied with no arguments Created: 12/May/12  Updated: 10/Jun/12  Resolved: 10/Jun/12

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Jürgen Hötzel Assignee: Sean Corfield
Resolution: Completed Votes: 0
Labels: patch,, performance

Attachments: Text File 0001-add-make-cols-unique-test-case-empty-cols.patch     Text File 0002-distinct-throws-clojure.lang.ArityException-when-app.patch    
Patch: Code and Test

 Description   

HSQLDB returns an empty ResultSet when using (.getGeneratedKeys stmt)
and no keys are generated. So this Exception is thrown for each record
without generated keys.

While this Exception is caught in do-prepared-return-keys, this can lead to a huge overhead caused by the JVM exception handling. I did a performance test.

Before Patch:

clojure.java.test-jdbc> (time (sql/with-connection hsqldb-db (count (apply sql/insert-records :dummy  (map #(hash-map :name (str %) :id %) (range 10000))))))
"Elapsed time: 3429.346743 msecs"
10000

After Patch:

 clojure.java.test-jdbc> (time (sql/with-connection hsqldb-db (count (apply sql/insert-records :dummy  (map #(hash-map :name (str %) :id %) (range 10000))))))
"Elapsed time: 1397.444753 msecs"


 Comments   
Comment by Sean Corfield [ 10/Jun/12 5:24 PM ]

Thanx for the patch!





[JDBC-39] Boolean - BIT(1) - columns are returned as byte[] via some DB connections Created: 10/Sep/12  Updated: 12/Sep/12  Resolved: 12/Sep/12

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Sean Corfield Assignee: Sean Corfield
Resolution: Declined Votes: 0
Labels: None
Environment:

Specifically using the MySQL connector 5.0.x or 5.1.x against a Tungsten Connector proxy



 Description   

The root cause appears to be that rs.getObject( i ) seems to take the field flags into effect over the basic java.sql.Types values.

In this case a BIT(1) column comes back from MySQL as type 16 (BOOLEAN), flags UNSIGNED. From Tungsten it comes back as type 16, flags BINARY BLOB UNSIGNED.

The resultset-seq construction code is pretty cavalier about using just getObject() instead of more specific types so this might be the start of a smarter approach to that.



 Comments   
Comment by Sean Corfield [ 10/Sep/12 5:51 PM ]

Further update: this looks to be a configuration or version issue with the Tungsten Connector setup as we've been able to repro the problem in one environment but it works as expected in a newer environment.

May still go ahead with this change anyway since I believe it's a good change for robustness, but it looks lower priority right now.

Comment by Sean Corfield [ 10/Sep/12 6:51 PM ]

Pushed a fix for this but would like more hands on this in SNAPSHOT form before declaring it resolved.

Comment by Sean Corfield [ 10/Sep/12 7:46 PM ]

Tungsten's Connector defeats this fix. Even tho' the fields have an underlying mysqlType value of 16 (BOOLEAN), (.getColumnType) returns -3 (byte[] presumably) so Boolean is not forced as I had hoped.

Comment by Sean Corfield [ 12/Sep/12 7:51 PM ]

The underlying behavior is a quirk of the Tungsten Connector configuration which we believe we've successfully corrected. Given the result of (.getColumnType) is -3, I'm not sure anything could be done in code to address this, so I'm going to resolve this as invalid.

Comment by Sean Corfield [ 12/Sep/12 7:52 PM ]

Not a code issue.





[JDBC-35] Wrong timezone for java.sql.Date, java.sql.Time and java.sql.Timestamp objects returned by with-query-results Created: 20/Jul/12  Updated: 12/Sep/12  Resolved: 12/Sep/12

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Jestine Paul Assignee: Sean Corfield
Resolution: Declined Votes: 0
Labels: bug

Attachments: File resultset-timezone.diff    

 Description   

Our database stores date and time related information in UTC. But, the results from with-query-results creates objects in the local timezone. This is causing a lot of unexpected behavior when constructing Joda DateTime objects in clj-time. Currently, the with-query-results function is using the single argument getter functions in the ResultSet

getDate(int columnIndex)
getTime(int columnIndex)
getTimestamp(int columnIndex)

We can solve this problem if we can optionally pass the timezone information and call the two argument getter functions.

getDate(int columnIndex, Calendar cal)
getTime(int columnIndex, Calendar cal)
getTimestamp(int columnIndex, Calendar cal)



 Comments   
Comment by Sean Corfield [ 21/Jul/12 1:30 AM ]

Can you provide a self-contained test case? Lots of people are using java.jdbc in production without running into this problem, and at World Singles we've had this in production for a long time in a high traffic environment without seeing any problems with timezones. Dates go in and out of the database unchanged, which is exactly as expected - and we have databases running in three different timezones.

Comment by Jestine Paul [ 21/Jul/12 5:29 AM ]

I have added a new test and it is failing with my Postgresql.

https://github.com/jestinepaul/java.jdbc/commit/195397b1b2a0245d2439ab9963fe2138450a27f3

Comment by Sean Corfield [ 21/Jul/12 1:03 PM ]

Looking at recommended practices out there, such as listed here: http://stackoverflow.com/questions/2532729/daylight-saving-time-and-timezone-best-practices one important thing is: "On Servers, set hardware clocks and OS clocks to UTC. Use NTP services on all servers." The same advice is repeated here: http://www.dbspecialists.com/blog/database-theory/intelligent-date-handling/

Looking further into PostgreSQL (a database I generally don't use), I see this: http://stackoverflow.com/questions/6151084/which-timestamp-type-to-choose-in-a-postgresql-database which seems to contain a lot of PostgreSQL-specific stuff. However, that article makes it clear that you need to set the database timezone to UTC in order to SELECT timestamp columns correctly.

In my opinion, the behavior you're seeing is not a bug (in java.jdbc) but an artifact of your environment being set up incorrectly. I'll leave this ticket open for a little while for more discussion but without a concrete patch that is shown to not affect other use cases, I will close this ticket by the end of August.

Comment by Jestine Paul [ 23/Jul/12 1:26 PM ]

As mentioned earlier, the database server timezone is in UTC and the JDBC library runs on a client machine set to local time. If the database has a date value of 2012-7-23, it changes to 2012-7-22 on the client side (if the client is running at timezone greater than UTC) when coerced using to-date-time in clj-time. This is extremely dangerous and is not specific to any database. I noticed it first on Sybase Enterprise Server and I have now also replicated it in the test case with Postgresql.

I have attached a patch which fixes this problem by passing in an optional parameter. The test case is also modified to use clj-time, as it expresses the problem more clearly. Please let me know if you need any more clarification.

p.s. I have already mailed the CA and should reach Durham in a few days.

Comment by Sean Corfield [ 12/Sep/12 8:01 PM ]

Since the proposed patch requires the user to pass in a list of columns to treat specially - and reorders columns in results and adds some performance overhead for all users, not just those wanting to adjust column values - I believe users who choose to run JDBC clients in timezones different to the database, against the widely-listed best practice recommendations, should bear the burden of adjusting the columns themselves in their own client code. Since they already know which columns to adjust and they know the difference between UTC and local time, they should be able to make the adjustments easily enough as part of post-processing the resultset-seq.





[JDBC-20] Create new clean API that accepts connection etc (post 0.1.0) Created: 12/Oct/11  Updated: 26/Dec/12  Resolved: 26/Dec/12

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Sean Corfield Assignee: Sean Corfield
Resolution: Completed Votes: 0
Labels: None


 Description   

Create streamlined API that relies on no bindings but instead accepts everything as an argument. Refactor existing API methods to operate in terms of this new API as appropriate.



 Comments   
Comment by Sean Corfield [ 12/Oct/11 4:28 PM ]

See JDBC-3 for some more background.

Comment by Sean Corfield [ 26/Dec/12 3:41 PM ]

The new API has been added. There is also an optional DSL to make it slightly easier to generate SQL that can be used with both the original and the new API.

I will open tickets for follow-up issues.





[JDBC-44] Add db-do-commands to match new API Created: 26/Dec/12  Updated: 26/Dec/12  Resolved: 26/Dec/12

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Sean Corfield Assignee: Sean Corfield
Resolution: Completed Votes: 0
Labels: None


 Description   

New version of do-commands but with db explicitly passed in and transaction? argument - this will satisfy JDBC-38.



 Comments   
Comment by Sean Corfield [ 26/Dec/12 4:10 PM ]

db-do-commands added





[JDBC-47] Transactions do not rollback on non-Exception Throwables Created: 26/Feb/13  Updated: 26/Feb/13  Resolved: 26/Feb/13

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Gary Fredericks Assignee: Sean Corfield
Resolution: Completed Votes: 0
Labels: None
Environment:

0.2.3


Attachments: Text File JDBC-47-p1.patch    

 Description   

transaction* currently catches Exceptions for its rollback logic. This means Throwables subclassing java.lang.Error are not caught, and indeed the transaction seems to be immediately committed in this case (at least if the connection has autocommit set to true).

This happened to me in the case of an OutOfMemoryError. Another example is that the following code commits:

(transaction
  (insert-records "table" {:foo 12})
  (assert false))

Presumably this can be fixed by catching Throwable instead of Exception. I'll prepare a patch to that effect.



 Comments   
Comment by Sean Corfield [ 26/Feb/13 4:48 PM ]

Thanx Gary. In the latest source there may be two pieces of transaction logic so please check for anywhere else that Exception is mentioned!

Comment by Gary Fredericks [ 26/Feb/13 5:17 PM ]

This patch changes Exception to Throwable in two places – transaction* and db-transaction*. The tests pass.

Comment by Sean Corfield [ 26/Feb/13 8:08 PM ]

Patch applied.





[JDBC-50] insert-rows (incorrectly) patches incomplete records Created: 21/Mar/13  Updated: 06/Apr/13  Resolved: 06/Apr/13

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Cees van Kemenade Assignee: Sean Corfield
Resolution: Completed Votes: 0
Labels: bug, docs
Environment:

Postgres database on Debian machine


Attachments: File jdbcIssue.clj    

 Description   

When using sql/insert-rows with a dataset that contains incomplete rows the rows will be patched with values from the preceding rows. The behaviour to be expected is not documented.

I would expect insert-rows either only accepts complete rows. When accepting incomplete rows I would expect patching with nil-values instead of values from other rows.

Attached you find an example and the output when running in comments.



 Comments   
Comment by Sean Corfield [ 06/Apr/13 3:10 PM ]

This looks like an old / long-standing bug that no one has run into before.

In the new (soon-to-be 0.3.0) release, (clojure.java.jdbc.sql/insert :table [1 1] [2] []) would throw an exception:

IllegalArgumentException insert called with inconsistent number of columns / values clojure.java.jdbc.sql/insert-multi-row (sql.clj:116)

I will update clojure.java.jdbc/insert-rows to throw a similar exception.

Comment by Sean Corfield [ 06/Apr/13 3:38 PM ]

Fixed in 0.3.0-SNAPSHOT by throwing an exception if the value-groups are not all the same length.

Currently relies on the DB to trap column names not matching value groups (which is known not to work on SQLite but does work on other DBs as far as I know).

insert-rows is deprecated in 0.3.0 - use insert! instead going forward (which does more validation).





[JDBC-49] jdbc insert-records can not handle spaces in columnames Created: 21/Mar/13  Updated: 06/Apr/13  Resolved: 06/Apr/13

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Cees van Kemenade Assignee: Sean Corfield
Resolution: Completed Votes: 0
Labels: bug
Environment:

Postgres on Debian


Attachments: File jdbcIssue2.clj    

 Description   

If a database contains column-names that include spaces an sql/insert-record will fail. However, inserting via sql/do-commands or sql/insert-rows works as expected.

Attached you find a file showing the error.



 Comments   
Comment by Cees van Kemenade [ 22/Mar/13 1:21 AM ]

Further analysis based on a suggestion of Sean leads to:

It seems to be that there is an issue in the naming-strategy in this issue. Either in the way I define it of the way it is implemented
(sql/with-connection db
(sql/with-naming-strategy {:keyword identity :entity (fn [x] (str \" x \"))}
...
))

When I remove the naming-strategy and replace the offending insert by a manual quoting strategy via
(sql/insert-records "test_jdbc_naming3" {((fn [x] (str \" x \")) "b- b") 7})
which corresponds to
(sql/insert-records "test_jdbc_naming3" {"\"b- b\"" 7})
then the code runs fine.

So the issue is located in the handling of the naming-strategy, or in the way I defined the naming-strategy (for postgres).

Comment by Sean Corfield [ 06/Apr/13 4:14 PM ]

Fixed in 0.3.0-SNAPSHOT by wiring as-str variable into compatibility layer as :entities argument.





[JDBC-45] insert! (and insert) need to support insert of full rows with no column names Created: 27/Dec/12  Updated: 06/Apr/13  Resolved: 06/Apr/13

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Sean Corfield Assignee: Sean Corfield
Resolution: Completed Votes: 0
Labels: None


 Description   

In order to fully deprecate insert-values (and to deprecate insert-rows at all), the new insert logic needs to support lack of column names.



 Comments   
Comment by Sean Corfield [ 06/Apr/13 4:38 PM ]

Fixed in 0.3.0-SNAPSHOT and insert-values / insert-rows are fully deprecated.





[JDBC-42] insert! always uses a transaction Created: 26/Dec/12  Updated: 06/Apr/13  Resolved: 06/Apr/13

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Sean Corfield Assignee: Sean Corfield
Resolution: Completed Votes: 0
Labels: None


 Description   

execute! delete! and update! all accept an optional :transaction? argument that allows you to control whether the operation occurs in a transaction or not.



 Comments   
Comment by Sean Corfield [ 06/Apr/13 6:53 PM ]

Fixed in 0.3.0-SNAPSHOT - :transaction? argument is now supported on insert!





[JDBC-43] Rewrite old API (with *db*) in terms of new API Created: 26/Dec/12  Updated: 07/Apr/13  Resolved: 07/Apr/13

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Task Priority: Major
Reporter: Sean Corfield Assignee: Sean Corfield
Resolution: Completed Votes: 0
Labels: None


 Description   

Now that the new API exists, the old API should be rewritten in terms of the new API, passing db and binding it appropriately. Where no new equivalent exists, extend the new API (in particular, the form of insert that just provides rows without column names is not supported in the new API).



 Comments   
Comment by Sean Corfield [ 30/Dec/12 7:51 PM ]

Most of this has been done now. It needs extensive testing!

Comment by Gerrard McNulty [ 18/Feb/13 4:05 PM ]

When are you planning on making a stable release? Are the new APIs going to change at all?

Comment by Sean Corfield [ 19/Feb/13 6:41 PM ]

There are still a number of open tickets that need completing before I can call this a stable release. Folks are welcome to test the SNAPSHOT release on Sonatype and provide feedback.

Comment by Sean Corfield [ 07/Apr/13 2:23 PM ]

0.3.0-alpha1 has been released so this is "done". What's left is polishing and bug fixing.





[JDBC-52] Allow execute! to do batch updates via :multi? optional argument Created: 19/Apr/13  Updated: 19/Apr/13  Resolved: 19/Apr/13

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Sean Corfield Assignee: Sean Corfield
Resolution: Completed Votes: 0
Labels: None


 Description   

See https://groups.google.com/d/msg/clojure-java-jdbc/H3spAaWgkZI/9WJPXJsHiVsJ for background and justification.

execute! would take an optional :multi? argument, default false, and execute-helper would either call db-do-prepared directly (as it does now) or apply it, assuming (rest sql-params) is a sequence of vectors, which would become multiple params-groups.

I think this would also allow insert! to be simplified and implemented in terms of execute! which would be a nice symmetry.



 Comments   
Comment by Sean Corfield [ 19/Apr/13 9:18 PM ]

Implemented. Will be in alpha2.





[JDBC-46] A mechanism for reading specialized types from result sets could be useful Created: 23/Jan/13  Updated: 15/May/13  Resolved: 19/Apr/13

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Gary Fredericks Assignee: Sean Corfield
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File JDBC-46-p1.patch     Text File JDBC-46-p2.patch     Text File JDBC-46-p3.patch    

 Description   

I had this idea when trying to adapt Korma to use with postgres tables with columns of array types. I had some success using Korma's transform functions to convert the java.sql.Array objects into a seq on the way out, but recent changes to Korma seem to indicate that the transform functions are not guaranteed to run before the connection is closed. This interferes with efforts to read the arrays, which I think can be their own result sets.

Presumably korma could be changed to support reading the arrays on the way out, but maybe being able to customize the read behavior within c.j.jdbc would be simpler.

The first idea I've had toward this end is to create a protocol with a single function that objects being read out of the resultset get passed through. It would default to the identity function, but users could e.g. extend it to java.sql.Array. I don't know if there are significant performance implications for an extra function call for each value coming out of the database.

I'll have a patch in this vein attached shortly.



 Comments   
Comment by Gary Fredericks [ 23/Jan/13 10:26 AM ]

Attached patch. Is there any straightforward way to test this? Or a place it should be documented?

Comment by Sean Corfield [ 23/Jan/13 10:48 AM ]

Docs: just needs good docstring since the clojure.github.com site is auto-generated from those (although it is still triggered manually it seems).

Test: mvn test

I have Derby, HSQLDB, MySQL, MS SQL Server (two drivers), MySQL. I don't have Postgres to test against. By default mvn test only tries Derby, HSQLDB and SQLite. TEST_DBS=... mvn test will test more.

Comment by Sean Corfield [ 23/Jan/13 10:49 AM ]

Would be nice to have a test with a custom conversion, mapping any String to some constant perhaps? Perhaps a separate test ns that is required and tested from test_jdbc.clj?

Comment by Gary Fredericks [ 23/Jan/13 2:38 PM ]

Oh, we have to be careful with testing because I believe any extensions to the protocol are going to be effective for all the remaining tests, right?

Comment by Gary Fredericks [ 23/Jan/13 3:53 PM ]

Attached new patch with docstrings and a test. I've only run the tests with MySQL. Let me know if there's anything else I can do.

Comment by Gary Fredericks [ 29/Jan/13 4:37 PM ]

This patch recently came in handy in an different situation, when jdbc was returning Integers instead of Longs, we had a really clean spot to do the conversion.

Comment by Sean Corfield [ 07/Apr/13 3:44 AM ]

There have been a lot of code changes since you submitted the patch and right now the patch doesn't apply. Can you re-submit the patch against the latest master branch so I can try again? Thanx!

Comment by Gary Fredericks [ 11/Apr/13 9:32 PM ]

I'm getting 3 test failures on master currently (with a basic mvn test), and after applying this new patch (p3) I still get 3 failures. So hopefully that means I didn't break anything.

Comment by Sean Corfield [ 19/Apr/13 9:34 PM ]

Applied. Will be in 0.3.0-alpha2

Comment by Gary Fredericks [ 15/May/13 9:52 AM ]

I'm thinking this feature is no longer necessary due to the :row-fn option – since the only motivation in the first place was to have the opportunity to transform a result before the connection closes.

There would still be no easy way to do it from Korma, but that's Korma's fault. So maybe we should remove this before 0.3.0 is released?





[JDBC-5] Adding stropping and qualified identifiers to java.jdbc Created: 24/Apr/11  Updated: 09/Jul/11  Resolved: 09/Jul/11

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Nicolas Buduroi Assignee: Nicolas Buduroi
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File 0001-Added-the-with-stropping-macro-and-the-as-identifier.patch    
Patch: Code
Waiting On: Sean Corfield

 Description   

Following the following discussion:

https://groups.google.com/d/topic/clojure/j7fXdkFMrec/discussion

I've implemented a simple stropping feature that also provide a way to supply qualified identifiers and a function (as-identifier) that can be reused in user code. The implementation can be found there:

https://github.com/budu/java.jdbc/commit/0822d323cd4d267533a88241be68cb184ff9bf28

It's also attached to this issue.

Here's some example of how that feature could be used:

user> (create-table :foo [:bar :integer] [:baz :text])
"CREATE TABLE foo (bar integer, baz text)"
user> (create-table [:schema :foo] [:bar :integer] [:baz :text])
"CREATE TABLE schema.foo (bar integer, baz text)"
user> (with-stropping \" identity (create-table [:schema :foo] [:bar :integer] [:baz :text]))
"CREATE TABLE \"schema\".\"foo\" (\"bar\" integer, \"baz\" text)"
user> (with-stropping [[ ]] identity (create-table [:schema :foo] [:bar :integer] [:baz :text]))
"CREATE TABLE [schema].[foo] ([bar] integer, [baz] text)"



 Comments   
Comment by Sean Corfield [ 24/Apr/11 8:21 PM ]

Duplicate of https://github.com/clojure/java.jdbc/issues/7 - thanx for the patch!

Comment by Sean Corfield [ 09/Jul/11 2:28 PM ]

with-naming-strategy, with-quoted-identifiers, as-quoted-str address this.





[JDBC-3] Inconsistency between tuples and regular maps Created: 08/May/11  Updated: 12/Oct/11  Resolved: 12/Oct/11

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Task Priority: Minor
Reporter: Sean Corfield Assignee: Sean Corfield
Resolution: Duplicate Votes: 0
Labels: None


 Description   

Stuart Sierra: In general, c.c.sql is inconsistent about using tuples of column values versus maps of column=>value pairs. Both are useful, and I'd like to see versions of all the core functions that support both modes.



 Comments   
Comment by Sean Corfield [ 13/Aug/11 6:59 PM ]

Having reviewed this after using the library for quite a while, I don't really see any inconsistencies except, perhaps in the naming of update-values (and update-or-insert-values).

insert-values is the base function, taking a table name, a vector of column names and any number of vectors of column values. Generates one insert statement (containing multiple rows). If only one row is inserted, returns a map of generated keys if the database supports that.

insert-rows takes a table name and any number of vectors of column values (for all columns); uses insert-values.

insert-records takes a table name and any number of maps (containing column/value pairs); uses insert-values to insert one record at a time (and thus may return a sequence of maps of generated keys).

insert-record takes a table name and a single map; uses insert-records and returns a map of generated key if the database supports that.

delete-rows takes a table name and a where clause. Perhaps delete-where might be a better name?

update-values takes a table name, a where clause and a map (of column/value pairs to update). Arguably this should be renamed since it doesn't take the same argument pattern as insert-values, but whilst update-records might sound more appropriate it only takes one "record" and update-record is clearly not right since it can update more than one row!

update-or-insert-values (taking the same arguments as update-values) can however lead to inserting a single record but it can also update multiple records instead.

On both of the latter functions, an analogy could be drawn with the findAndModify command in MongoDB which has an upsert option (to insert the document if no matches are found for the update), but most notably, findAndModify only updates a single record. I don't believe SQL has any portable equivalent but perhaps find-and-modify is a better name for update-values? Or perhaps, in the spirit of my suggestion for delete-where, we might call it update-where - and use an optional keyword argument to indicate that an insert-record should be performed when no rows match?

The only other comment I could make on update-values is that it might be nice to have a variant that took: table where-params column-names value-group - somewhat inline with insert-values (although not allowing any number of vectors of column values).

Comment by Sean Corfield [ 12/Oct/11 4:29 PM ]

The API aspects of this ticket are covered in JDBC-20 (post 0.1.0) and the struct-map issue is covered in JDBC-15 so I'm closing this out as a duplicate for now.

Comment by Sean Corfield [ 12/Oct/11 4:29 PM ]

Essentially duplicated with more focus in JDBC-15 and JDBC-20.





[JDBC-4] Global connection mechanism / connection pooling Created: 08/May/11  Updated: 10/Aug/11  Resolved: 10/Aug/11

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Sean Corfield Assignee: Sean Corfield
Resolution: Completed Votes: 0
Labels: None


 Description   

Nicolas Buduroi: What I would like to see added is a global connection mechanism like in ClojureQL and Lobos. We could even add a connection pool behind the scene.



 Comments   
Comment by Sean Corfield [ 09/Jul/11 12:23 PM ]

For production usage, I've been relying on c3p0 for connection pooling which works very well with c.j.j so I'm not sure that we need something specific within the library itself. What we do need, of course, is documentation on how to use something like c3p0 for connection pooling with c.j.j!

Comment by Sean Corfield [ 17/Jul/11 3:31 AM ]

Given the ease of using 3rd-party connection pooling libraries like c3p0, I think this is low priority (and I may simply close out after documenting how to use c3p0 with c.j.j).

Comment by Sean Corfield [ 10/Aug/11 2:21 AM ]

I've documented it here: https://github.com/clojure/java.jdbc/blob/master/doc/clojure/java/jdbc/ConnectionPooling.md

I don't believe this should be in c.j.j itself so I'm going to close this.

Comment by Sean Corfield [ 10/Aug/11 2:22 AM ]

Documented how to use a 3rd party library for connection pooling which I think is sufficient since it's so easy.





[JDBC-14] delete-rows does not work with null WHERE Created: 06/Aug/11  Updated: 04/Sep/11  Resolved: 04/Sep/11

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Allen Rohner Assignee: Sean Corfield
Resolution: Declined Votes: 0
Labels: None


 Description   

(delete-rows "foo" [])
generates the SQL
delete from foo where null
, which deletes 0 rows. Instead, I expect it to generate
delete from foo
.



 Comments   
Comment by Allen Rohner [ 06/Aug/11 3:46 PM ]

I can't find the button to edit the issue, this happened on ver. 0.0.6

Comment by Sean Corfield [ 10/Aug/11 1:46 AM ]

I actually think that would be rather dangerous. Imagine constructing the where parameters dynamically and accidentally passing in an empty sequence - you'd delete everything in the table.

I believe you can safely and deliberately get the effect you are looking for by doing either of these:

(delete-rows "foo" [true])
(delete-rows "foo" [1])
Comment by Sean Corfield [ 04/Sep/11 1:32 AM ]

Given the lack of response to my comment and the fact that there is a clear and explicit workaround, I'm resolving this, declined.





[JDBC-17] Type-hint public fns returning Connection Created: 10/Oct/11  Updated: 10/Oct/11  Resolved: 10/Oct/11

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Stuart Sierra Assignee: Sean Corfield
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File JDBC-17-a.patch    
Patch: Code

 Description   

clojure.java.jdbc/connection and find-connection both return a java.sql.Connection but are not type-hinted.

There is a type hint on clojure.java.jdbc.internal/connection*, but it does not carry through to the public Var.

Tagging these functions eliminates 9 reflection warnings in a project I have.



 Comments   
Comment by Sean Corfield [ 10/Oct/11 11:21 PM ]

Patch applied. Thanx Stuart!





[JDBC-27] Use repeat instead of replicate Created: 29/Feb/12  Updated: 29/Feb/12  Resolved: 29/Feb/12

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Jonas Enlund Assignee: Sean Corfield
Resolution: Completed Votes: 0
Labels: None

Attachments: File repeat-patch.diff    
Patch: Fixed

 Description   

The replicate function is deprecated and the suggested alternative is to use repeat.



 Comments   
Comment by Sean Corfield [ 29/Feb/12 5:34 PM ]

Thanx Jonas. This made me look thru all my other Clojure code but it was the only instance of replicate that I could find.





[JDBC-21] Accept string URL as connection parameters Created: 17/Oct/11  Updated: 02/Nov/11  Resolved: 02/Nov/11

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Phil Hagelberg Assignee: Phil Hagelberg
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File 0001-Accept-string-or-URI-in-with-connection.patch     Text File jdbc-21-take2.patch    
Patch: Code and Test

 Description   

Should support connection parameters in this style:

(with-connection "postgres://user:password@host.com:port/db-name" [...])



 Comments   
Comment by Phil Hagelberg [ 17/Oct/11 1:18 PM ]

Talked this over with Sean on IRC; I'll put together a patch.

Comment by Phil Hagelberg [ 17/Oct/11 4:21 PM ]

Implements said functionality. Patch depends upon supplied patch for JDBC-22.

Comment by Phil Hagelberg [ 17/Oct/11 4:54 PM ]

Hold off on this patch; apparently the scheme and subprotocol don't always match up. Will provide an updated patch.

Comment by Phil Hagelberg [ 17/Oct/11 6:00 PM ]

This one should take care of the subprotocol issue; it also adds support for running the tests against postgres.

Comment by Sean Corfield [ 02/Nov/11 2:52 PM ]

Patches applied - thank you!





[JDBC-18] Consider ["name = ? and age = ?" nil 42] Created: 11/Oct/11  Updated: 12/Aug/12  Resolved: 12/Aug/12

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Sean Corfield Assignee: Sean Corfield
Resolution: Duplicate Votes: 0
Labels: None


 Description   

The query is "name = nil and age = 42" where the intent is probably "name is null and age = 42".

It's not clear whether this is really the library's responsibility (to rewrite the SQL) or whether this should be handled by another layer above so this ticket is a placeholder for discussion.



 Comments   
Comment by Julian Birch [ 13/Oct/11 1:43 PM ]

I've been thinking about this a bit more, and I'm thinking that a function "match-clause" might deal with this in a fairly composable way. So

(match-clause { :name nil :age 42 })

would return

["Name is null and Age = ?" 42]

It's not exactly ClojureQL, but it's non-invasive and makes query-by-example easy to achieve.

Comment by Sean Corfield [ 13/Oct/11 2:28 PM ]

That's nice idea. I actually do something similar in the CRUD wrapper I built around java.jdbc at World Singles so that might be a nice addition to the library.

Comment by Sean Corfield [ 12/Aug/12 9:39 PM ]

This will be incorporated into the new API I'm adding in JDBC-20 so you can say (where {:name nil :age 42}) and it will return the correct SQL where clause. Accordingly, I'm closing this as a duplicate.

Comment by Sean Corfield [ 12/Aug/12 9:39 PM ]

A subset of what will be implemented as part of JDBC-20





[JDBC-22] Infer :classname from :subprotocol Created: 17/Oct/11  Updated: 04/Jan/12  Resolved: 04/Jan/12

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Phil Hagelberg Assignee: Phil Hagelberg
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File 0001-Infer-classname-from-subprotocol.patch    
Patch: Code and Test
Waiting On: Sean Corfield

 Description   

Having to specify both :classname and :subprotocol seems like needless boilerplate. Only :subprotocol should be required.



 Comments   
Comment by Phil Hagelberg [ 17/Oct/11 1:48 PM ]

This should take care of it. Updated the tests to remove the inferred value.

Comment by Sean Corfield [ 04/Jan/12 11:53 PM ]

Sorry, I should have closed this out ages ago - when the patch was applied.





[JDBC-24] Make where-params optional for update-values function Created: 04/Jan/12  Updated: 04/Jan/12  Resolved: 04/Jan/12

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Trent Ogren Assignee: Sean Corfield
Resolution: Declined Votes: 0
Labels: None

Attachments: Text File optional-where-params-update-values.patch    
Patch: Code and Test

 Description   

This prevents having to pass a wonky always-true clause (e.g. ["1=1"]) as the where-params when updating all the rows in a table.



 Comments   
Comment by Trent Ogren [ 04/Jan/12 11:04 PM ]

I'm aware that I might have to sign the Clojure CA. I just thought I'd see what you think first...

Comment by Sean Corfield [ 04/Jan/12 11:43 PM ]

See JDBC-14 since I'm declining this for the same reason. Performing a global update is an unusual operation and I think the API should prevent you from accidentally updating all rows, just as it should prevent you from deleting all rows. Requiring a where clause does that.





[JDBC-26] Add sqlite3 support Created: 13/Feb/12  Updated: 23/Apr/12  Resolved: 23/Apr/12

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Nelson Morris Assignee: Sean Corfield
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File mssql-error.log     Text File sqlite3-support.patch     Text File sqlite_transaction_test.patch    
Patch: Code and Test

 Description   

sqlite3 has some problems:

1) PreparedStatements.addBatch does not do anything without some parameters, so executeBatch doesn't do anything.
2) Transaction support appears to require closing the ResultSet object from generatedKeys.

I've only tested the included patch with the default test dbs and sqlite3.



 Comments   
Comment by Sean Corfield [ 14/Feb/12 1:01 AM ]

This will break things - see JDBC-16 which required that .addBatch be called when there are no param-groups. I'm not going to reject this out of hand but patches for new database support need testing against MySQL, PostgreSQL and MS SQL Server.

Comment by Nelson Morris [ 14/Feb/12 1:48 PM ]

Test suite runs correctly for TEST_DBS=mysql,postgres,derby,hsqldb,sqlite3 and TEST_DBS=mysql-str,postgres-str. This just leaves MS SQL server, which I do not have the ability to run.

Regarding JDBC-16, when I revert to just using .executeBatch for the no param-groups case I can see the errors produced in the test-suite. Using .executeUpdate for the no params-group case continues to fix these errors (note MS SQL server untested). I do not see any other information in the ticket that would explain why using .executeUpdate instead of .addBatch/.executeBatch for the no params-group case would break JDBC-16. Is there a reason I am missing?

Comment by Nelson Morris [ 17/Feb/12 10:05 PM ]

I ran the test suite against an ec2 instance with MS SQL server 2008 R2. Current test suite on master fails with attached mssql-error.log. Using patch produces the same output.

Please let me know if there is anything that you would like changed.

Comment by Sean Corfield [ 17/Feb/12 10:14 PM ]

Thanx Nelson. I've been a bit busy with work this week but I'll try to look at this at the weekend. I appreciate your thoroughness on testing this!

Comment by Sean Corfield [ 29/Feb/12 11:33 PM ]

Integrated parts of the patch. SQLite 3 is now supported. Thanx!

Comment by Nelson Morris [ 01/Mar/12 12:57 AM ]

I still get the transaction issue (part 2 from original description) when clojure.java.jdbc tries to return the generated keys, in a transaction, using sqlite. https://gist.github.com/1947746

I believe this is because the ResultSet from .getGeneratedKeys never gets .close called, so sqlite keeps the db locked and can't rollback. Would you like me to make a new issue?

Comment by Sean Corfield [ 01/Mar/12 1:03 AM ]

The tests pass locally (Mac OS X) and on the Clojure build server (Linux) but you're right that I didn't include the close call on the record set.

I didn't include your additional test which I'm guessing is the key to highlighting the errant behavior for SQLite?

(I couldn't actually apply your patch because I'd spent some time getting all the tests passing for MS SQL Server with both the Microsoft and jTDS drivers)

Comment by Nelson Morris [ 01/Mar/12 1:19 AM ]

Attached patch that fails with `mvn test`.

Comment by Sean Corfield [ 23/Apr/12 3:35 AM ]

I believe this was fixed in 0.1.3 (at the end of February). As far as I can tell, all of the patch components are applied. Specifically, your transaction test is included in the test suite and passes.





[JDBC-29] Performance improvement (Remove intermediate lazy sequence in resultset-seq) Created: 10/May/12  Updated: 10/May/12  Resolved: 10/May/12

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Jürgen Hötzel Assignee: Sean Corfield
Resolution: Completed Votes: 0
Labels: patch,, performance

Attachments: Text File 0001-Don-t-create-intermediate-lazy-sequences-of-vectors.patch    

 Description   

This improves performance on large result sets by up to 30%.



 Comments   
Comment by Sean Corfield [ 10/May/12 12:09 PM ]

Nice catch!





[JDBC-33] update-or-insert does not work with oracle Created: 21/May/12  Updated: 10/Jun/12  Resolved: 10/Jun/12

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Brian Tatnall Assignee: Sean Corfield
Resolution: Completed Votes: 0
Labels: bug
Environment:

clojure 1.3.0
clojure.java.jdbc 0.2.1
oracle 10.2.0.4.0



 Description   

According to the oracle documentation

For a prepared statement batch, it is not possible to know the number of rows affected in the database by each individual statement in the batch. Therefore, all array elements have a value of -2. According to the JDBC 2.0 specification, a value of -2 indicates that the operation was successful but the number of rows affected is unknown.

As documented update-values returns (-2) which means that the (if (zero?)) check in update-or-insert-values will never return true.

Oracle does provide the number of rows updated via an the method getUpdateCount on instances of Statement.

The following change fixes this problem for oracle users, but I am not sure how it will affect other drivers.

(defn oracle-do-prepared
  "Executes an (optionally parameterized) SQL prepared statement on the                                           
  open database connection. Each param-group is a seq of values for all of                                        
  the parameters.                                                                                                 
  Return a seq of update counts (one count for each param-group)."
  [sql & param-groups]
  (with-open [^PreparedStatement stmt (prepare-statement (connection) sql)]
    (if (empty? param-groups)
      (transaction* (ƒ [] (vector (.executeUpdate stmt))))
      (do
        (doseq [param-group param-groups]
          (set-parameters stmt param-group)
          (.addBatch stmt))
        (transaction* (ƒ [] (let [result (.executeBatch stmt)
                                  count  (.getUpdateCount stmt)]
                              (vector count))))))))


 Comments   
Comment by Sean Corfield [ 22/May/12 12:17 AM ]

Interesting. (.getUpdateCount stmt) is a standard part of the JDBC API so it looks reasonable to see if the result of the (.executeBatch stmt) is a single sequence with a -2 value, the code could call (.getUpdateCount stmt) and return that (single) value as a sequence. It looks like that should be completely portable but it will be hard to test since none of the other DBs return -2 as far as I know and I don't have an Oracle install to test against





[JDBC-38] There is no way to execute a raw statement outside a transaction Created: 12/Aug/12  Updated: 27/Dec/12  Resolved: 26/Dec/12

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Rasmus Svensson Assignee: Sean Corfield
Resolution: Completed Votes: 0
Labels: None
Environment:

Dependencies used:

[org.clojure/clojure "1.4.0"]
[org.clojure/java.jdbc "0.2.3"]
[org.xerial/sqlite-jdbc "3.7.2"]



 Description   

To be able to enforce foreign key constraints in SQLite you need to execute the following statement:

PRAGMA foreign_keys = ON;

However, this statement can't be used from within a transaction. From the SQLite docs:

It is not possible to enable or disable foreign key constraints in the middle of a multi-statement transaction (when SQLite is not in autocommit mode). Attempting to do so does not return an error; it simply has no effect.

In clojure.java.jdbc both do-commands and do-prepared unconditionally run the supplied statements in a transaction. To me it seems like these two functions are the only ones that provide a way to execute an arbitrary SQL statement.

Example using [org.clojure/java.jdbc "0.2.3"] and [org.xerial/sqlite-jdbc "3.7.2"]:

(sql/with-connection {:classname   "org.sqlite.JDBC"
                      :subprotocol "sqlite"
                      :subname     "foo.db"}
  (sql/do-commands "PRAGMA foreign_keys = ON;")
  (sql/with-query-results res ["PRAGMA foreign_keys;"]
    (doall res)))
; => ({:foreign_keys 0})

When using this function instead of do-commands foreign keys work as expected:

(defn do-raw  [& commands]
  (with-open [^java.sql.Statement stmt (let [^java.sql.Connection con (sql/connection)] (.createStatement con))]
    (doseq [^String cmd commands]
      (.addBatch stmt cmd))
    (let [result (.executeBatch stmt)]
      (if (and (= 1 (count result)) (= -2 (first result)))
        (list (.getUpdateCount stmt))
        (seq result)))))

This function is simply do-commands with execute-batch inlined and the wrapping transaction form removed.



 Comments   
Comment by Sean Corfield [ 12/Aug/12 9:33 PM ]

It seems like the more flexible thing to do would be to allow users to specify that a transaction not be used on the existing operations. I'm reworking the API substantially soon so I'll bear that in mind. I might not make it possible with the existing API but I'll make sure that's an option in the new API that I'm adding.

Comment by Sean Corfield [ 26/Dec/12 4:11 PM ]

0.2.4-SNAPSHOT contains db-do-commands which allows bare execution of commands against a specific database connection with or without a transaction wrapping the commands.

Comment by Rasmus Svensson [ 27/Dec/12 7:03 AM ]

Neat!





[JDBC-41] How to preserve order of rows? Created: 24/Dec/12  Updated: 07/Apr/13  Resolved: 07/Apr/13

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Konstantin Assignee: Sean Corfield
Resolution: Completed Votes: 0
Labels: None


 Description   

I'd like to get the ordered record set within with-query-results
(or the way to restore the original order).
Is this possible with clojure/java.jdbc?



 Comments   
Comment by Sean Corfield [ 24/Dec/12 12:49 PM ]

I assume you mean the order of columns within the rows, not the actual order of rows within the result set?

I'm looking at providing an alternative result set format using arrays instead of maps which will preserve column orders.

Since maps are unordered by default in Clojure, I'd be suspicious of code that relies on ordering of keys (so I'm reducing this to 'minor').

Comment by Konstantin [ 24/Dec/12 10:54 PM ]

You are right, I mean the order of columns, not the rows.

I understand, that maps are unordered. There are few reasons when
the order is matters. The one of them is my task - simple
SQL database client.

Probably it would be better to do this possibility optional,
since it is not used very often?

Comment by Sean Corfield [ 25/Dec/12 8:26 PM ]

An optional keyword argument sounds like a reasonable compromise. I'm already looking at keyword arguments on resultset-seq for returning arrays instead of maps and returning an order-preserving map should be as simple as replacing (zipmap keys (row-values)) with (apply array-map (interleave keys (row-values)))

Comment by Sean Corfield [ 07/Apr/13 3:38 AM ]

Fixed in 0.3.0-SNAPSHOT by allowing :as-arrays argument to query and result-set-seq functions, which returns result as vector of column names, followed by vectors for each row.





[JDBC-13] Add unit tests for generated keys Created: 25/Jul/11  Updated: 07/May/13  Resolved: 07/May/13

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Task Priority: Minor
Reporter: Sean Corfield Assignee: Sean Corfield
Resolution: Completed Votes: 0
Labels: None


 Description   

Need to test that generated keys come back as expected for various databases - and that DBs which can't generate keys let you use transactions and select identity kind of SQL stuff.



 Comments   
Comment by Sean Corfield [ 07/May/13 9:28 PM ]

This has sort of been handled along the way with functions used in the test suite to reflect how various databases handle key generation / return. Surprisingly few seem to reliably return keys on an insert





[JDBC-25] The classnames private var should be public Created: 07/Feb/12  Updated: 12/Feb/12  Resolved: 12/Feb/12

Status: Resolved
Project: java.jdbc
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Trivial
Reporter: Nicolas Buduroi Assignee: Sean Corfield
Resolution: Declined Votes: 0
Labels: None


 Description   

I've got a bunch of integration/system tests in Lobos which are run over multiple target database. As I do not want to force all target drivers to be made as dev-dependencies, I check if the driver is available before running those tests. As long as the classname key is in the db-spec it's all fine, but now java.jdbc support db-spec with that key, it would be useful to have access to the classnames var for me, so it would be great to have it made public. This isn't a blocker as up till now I don't really need it, but I'm planning to add some tests for string based db-spec.



 Comments   
Comment by Sean Corfield [ 12/Feb/12 4:21 AM ]

Right now, that's in the internal namespace which is going away so I can't make it part of the API. You can always pull private vars out with @#'clojure.java.jdbc.internal/classnames but bear in mind that internal ns will merge with the parent ns soon!





Generated at Sat May 18 07:53:18 CDT 2013 using JIRA 4.4#649-r158309.