Permalink
Browse files

Fix JDBC-9 by renaming duplicate columns

  • Loading branch information...
1 parent 8855cf8 commit 27b97ef8419d475f7eb3adcaa8dd0c7608edf48f @seancorfield seancorfield committed Oct 11, 2011
@@ -66,7 +66,9 @@ generated keys are returned (as a map)." }
(def ^{:doc "Creates and returns a lazy sequence of structmaps
corresponding to the rows in the java.sql.ResultSet
rs. Based on clojure.core/resultset-seq but it respects
- the current naming strategy."}
+ the current naming strategy. Duplicate column names are
+ made unique by appending _N before applying the naming
+ strategy (where N is a unique integer)."}
resultset-seq
resultset-seq*)
@@ -192,18 +192,41 @@
(.setAutoCommit con auto-commit)))))
(func))))
+(defn- make-name-unique
+ "Given a collection of column names and a new column name,
+ return the new column name made unique, if necessary, by
+ appending _N where N is some unique integer suffix."
+ [cols col-name n]
+ (let [suffixed-name (if (= n 1) col-name (str col-name "_" n))]
+ (if (apply distinct? suffixed-name cols)
+ suffixed-name
+ (recur cols col-name (inc n)))))
+
+(defn- make-cols-unique
+ "Given a collection of column names, rename duplicates so
+ that the result is a collection of unique column names."
+ [cols]
+ (if (apply distinct? cols)
+ cols
+ (loop [[col-name :as new-cols] (seq cols)
+ unique-cols []]
+ (if (seq new-cols)
+ (recur (rest new-cols) (conj unique-cols (make-name-unique unique-cols col-name 1)))
+ unique-cols))))
+
(defn resultset-seq*
"Creates and returns a lazy sequence of structmaps corresponding to
the rows in the java.sql.ResultSet rs. Based on clojure.core/resultset-seq
- but it respects the current naming strategy."
+ but it respects the current naming strategy. Duplicate column names are
+ made unique by appending _N before applying the naming strategy (where
+ N is a unique integer)."
[^ResultSet rs]
(let [rsmeta (.getMetaData rs)
idxs (range 1 (inc (.getColumnCount rsmeta)))
- keys (map (comp keyword *as-key*)
- (map (fn [^Integer i] (.getColumnLabel rsmeta i)) idxs))
- check-keys
- (or (apply distinct? keys)
- (throw (Exception. "ResultSet must have unique column labels")))
+ keys (->> idxs
+ (map (fn [^Integer i] (.getColumnLabel rsmeta i)))
+ make-cols-unique
+ (map (comp keyword *as-key*)))
row-struct (apply create-struct keys)
row-values (fn [] (map (fn [^Integer i] (.getObject rs i)) idxs))
rows (fn thisfn []
@@ -19,7 +19,8 @@
(ns clojure.java.test-utilities
(:use clojure.test)
- (:require [clojure.java.jdbc :as sql]))
+ (:require [clojure.java.jdbc :as sql])
+ (:require [clojure.java.jdbc.internal :as internal]))
;; basic tests for keyword / entity conversion
@@ -82,6 +83,19 @@
(is (re-find (pattern "Message: Test Message.*Message: Base Message") except-str))
(is (re-find (pattern "SQLState: Test State.*SQLState: Base State") except-str)))))
+(deftest test-make-name-unique
+ (let [make-name-unique @#'internal/make-name-unique]
+ (is (= "a" (make-name-unique '() "a" 1)))
+ (is (= "a_2" (make-name-unique '("a") "a" 1)))
+ (is (= "a_3" (make-name-unique '("a" "b" "a_2") "a" 1)))))
+
+(deftest test-make-cols-unique
+ (let [make-cols-unique @#'internal/make-cols-unique]
+ (is (= '("a") (make-cols-unique '("a"))))
+ (is (= '("a" "a_2") (make-cols-unique '("a" "a"))))
+ (is (= '("a" "b" "a_2" "a_3") (make-cols-unique '("a" "b" "a" "a"))))
+ (is (= '("a" "b" "a_2" "b_2" "a_3" "b_3") (make-cols-unique '("a" "b" "a" "b" "a" "b"))))))
+
;; DDL tests
(deftest test-create-table-ddl

0 comments on commit 27b97ef

Please sign in to comment.