<< Back to previous view

[JDBC-87] Laziness on metadata-result results in closed resultset under Microsoft SQL Created: 06/Jan/14  Updated: 30/Jan/14  Resolved: 30/Jan/14

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

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


 Description   

Getting a collection of tables, and then using these to get the columns inside the tables work swimmingly under Oracle, but throws an exception under Microsoft SQL (driver 4.0.2206.100)

CompilerException com.microsoft.sqlserver.jdbc.SQLServerException: The result set is closed., compiling:(form-init602030969958815921.clj:2:3)

 (def tables
    (jdbc/with-db-metadata [m db]
                           (->>
                             (jdbc/metadata-result  (.getTables m nil nil nil (into-array String ["TABLE"])))
                             (map :table_name)
                             doall)))

  (def columns
    (jdbc/with-db-metadata [m db]
                      (->>
                        tables
                        (mapcat #(jdbc/metadata-result (.getColumns m nil nil % nil)))
                        doall)))

The problem lies in the mapcat part. Using only map works fine, but there's no way to concat before the doall, since that results in the same exception.

Changing metadata-result from

(if (instance? java.sql.ResultSet rs-or-value)
    (result-set-seq rs-or-value :identifiers identifiers :as-arrays? as-arrays?)
    rs-or-value)

to

(if (instance? java.sql.ResultSet rs-or-value)
    (doall (result-set-seq rs-or-value :identifiers identifiers :as-arrays? as-arrays?))
   rs-or-value)

fixes things, but I'm not entirely sure of the consequences that would entail in case laziness would be intended.



 Comments   
Comment by Niels van Klaveren [ 06/Jan/14 7:23 AM ]

Giving metadata-result a result-set-fn parameter defaulting to either identity or doall would work, I guess.

(defn metadata-result
  "If the argument is a java.sql.ResultSet, turn it into a result-set-seq,
   else return it as-is. This makes working with metadata easier.
   Also accepts :identifiers and :as-arrays? to control how the ResultSet
   is transformed and returned. See query for more details."
  [rs-or-value & {:keys [identifiers as-arrays? result-set-fn]
                  :or {identifiers str/lower-case result-set-fn doall}}]
  (if (instance? java.sql.ResultSet rs-or-value)
    (result-set-fn (result-set-seq rs-or-value :identifiers identifiers :as-arrays? as-arrays?))
    rs-or-value))
Comment by Sean Corfield [ 06/Jan/14 11:15 AM ]

Yes, I think that is probably the right solution. I'll review it in the context of query etc and make sure it would create a consistent API. It might be worthwhile having :row-fn as well but I need to compare the functions and think carefully about the impact of those changes.

Thanx for spotting the problem!

Comment by Sean Corfield [ 30/Jan/14 1:34 AM ]

Add :row-fn and :result-set-fn to metadata-result

Generated at Sat Nov 29 02:40:08 CST 2014 using JIRA 4.4#649-r158309.