2010-09-03 8 views
1

Comment insérer un blob dans une base de données en utilisant clojure.contrib.sql?Clojure comment insérer un blob dans la base de données?

J'ai essayé ce qui suit la lecture d'un fichier, mais je reçois cette exception:

SQLException: Message: type de colonne non valide SQLSTATE: 99999 Code d'erreur: 17004 java.lang.Exception: transaction annulée: Type de colonne non valide (repl-1: 125)

(clojure.contrib.sql/with-connection 
    db 
    (clojure.contrib.sql/transaction 
    (clojure.contrib.sql/insert-values :test_blob [:blob_id :a_blob] [3 (FileInputStream. "c:/somefile.xls")]))) 

Merci.

Répondre

2

j'ai pu résoudre ce problème en convertissant le FileInputStream en ByteArray.

(clojure.contrib.sql/with-connection 
    db 
    (clojure.contrib.sql/transaction 
    (clojure.contrib.sql/insert-values :test_blob [:blob_id :a_blob] [3 (to-byte-array(FileInputStream. "c:/somefile.xls"))]))) 
0

Je crois que c'est de la même façon que vous insérez une autre valeur: utilisez l'une des insert-records, insert-rows ou insert-values. .: par exemple

(insert-values :mytable [:id :blobcolumn] [42 blob]) 

Plus exemples: http://github.com/richhickey/clojure-contrib/blob/master/src/test/clojure/clojure/contrib/test_sql.clj

+0

Cela ne fonctionne pas si je veux enregistrer un fichier en tant que BLOB. – aQ123

+0

Oh. Je n'imagine pas 'FileInputStream' est sérialisable - je me demande si c'est le problème. – harto

2

En théorie, vous pouvez utiliser l'une des méthodes de clojure.contrib.sql/Insérer- * pour insérer un blob, en passant le blob soit comme un tableau d'octets, ou un java.sql.Blob java.io Objet .InputStream. En pratique, il dépend du conducteur.

Pour de nombreuses implémentations JDBC, tout ce qui précède fonctionne comme prévu, mais si vous utilisez sqlitejdbc 0.5.6 à partir de Clojars, vous trouverez votre blob converti en une chaîne via toString(). Toutes les commandes clojure.contrib.sql/insert- * sont émises via clojure.contrib.sql/do-prepared, qui appelle setObject() sur un java.sql.PreparedStatement. L'implémentation sqlitejdbc ne gère pas setObject() pour l'un des types de données blob, mais par défaut les contraint à une chaîne. Voici une solution qui vous permet de stocker des blobs dans SQLite:

(use '[clojure.contrib.io :only (input-stream to-byte-array)]) 
    (require '[clojure.contrib.sql :as sql]) 

    (defn my-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. This is a modified version of clojure.contrib.sql/do-prepared 
    with special handling of byte arrays." 
    [sql & param-groups] 
    (with-open [stmt (.prepareStatement (sql/connection) sql)] 
    (doseq [param-group param-groups] 
     (doseq [[index value] (map vector (iterate inc 1) param-group)] 
     (if (= (class value) (class (to-byte-array ""))) 
      (.setBytes stmt index value) 
      (.setObject stmt index value))) 
     (.addBatch stmt)) 
    (sql/transaction 
     (seq (.executeBatch stmt))))) 

(defn my-load-blob [filename] 
    (let [blob (to-byte-array (input-stream filename))] 
    (sql/with-connection db 
      (my-do-prepared "insert into mytable (blob_column) values (?)" [blob])))) 
Questions connexes