【问题标题】:Inserting PostgreSQL arrays with Clojure使用 Clojure 插入 PostgreSQL 数组
【发布时间】:2014-05-22 11:50:08
【问题描述】:

我找不到用 Clojure 插入 Postgres 数组类型的方法。

(sql/insert! db :things {:animals ["cow" "pig"]})

没有达到我的预期。错误信息:

PSQLException Can't infer the SQL type to use for an instance of clojure.lang.PersistentVector. Use setObject() with an explicit Types value to specify the type to use.  org.postgresql.jdbc2.AbstractJdbc2Statement.setObject (AbstractJdbc2Statement.java:1936)

即使是我能找到的最直接的 SQL 访问也不起作用:

(sql/execute! db "INSERT INTO things (animals) VALUES ('{\"cow\", \"pig\"}')")

真的不知道这里发生了什么:

ClassCastException java.lang.Character cannot be cast to java.lang.String  clojure.java.jdbc/prepare-statement (jdbc.clj:419)

肯定有可能吗?如果不是通过辅助函数,那么通过某种方式执行原始 SQL。

【问题讨论】:

    标签: sql postgresql jdbc clojure


    【解决方案1】:

    您可以通过扩展两个协议使 clojure.java.jdbc 在 Clojure 向量和 SQL 数组之间自动转换。这可以通过您自己的代码完成:

    (extend-protocol clojure.java.jdbc/ISQLParameter
      clojure.lang.IPersistentVector
      (set-parameter [v ^java.sql.PreparedStatement stmt ^long i]
        (let [conn (.getConnection stmt)
              meta (.getParameterMetaData stmt)
              type-name (.getParameterTypeName meta i)]
          (if-let [elem-type (when (= (first type-name) \_) (apply str (rest type-name)))]
            (.setObject stmt i (.createArrayOf conn elem-type (to-array v)))
            (.setObject stmt i v)))))
    
    (extend-protocol clojure.java.jdbc/IResultSetReadColumn
      java.sql.Array
      (result-set-read-column [val _ _]
        (into [] (.getArray val))))
    

    REPL 示例:

    user> (def db (clj-postgresql.core/pool :dbname "test"))
    #'user/db
    user> (clojure.java.jdbc/query db ["SELECT ?::text[], ?::int[]" ["foo" "bar"] [1 2 3]])
    ({:int4 [1 2 3], :text ["foo" "bar"]})
    

    我目前正在开发一个自动支持 PostgreSQL 和 PostGIS 类型的库。尽管https://github.com/remodoy/clj-postgresql

    ,它仍在进行中

    【讨论】:

      【解决方案2】:

      要使用 insert! 插入字符串向量,您必须创建一个实现 java.sql.Array 的对象(从字符串向量)。您可以使用java.sql.Connection.createArrayOf 创建这样的对象

      (def con (sql/get-connection db))
      
      (def val-to-insert 
          (.createArrayOf con "varchar" (into-array String ["cow", "pig"]))
      
      (sql/insert! db :things {:animals val-to-insert})
      

      clojure.java.jdbc 在execute! 上的文档说

      (execute! db-spec [sql & params] :multi? false :transaction? true)
      (execute! db-spec [sql & param-groups] :multi? true :transaction? true)
      

      您必须将您的 sql 字符串放入向量中才能使其工作。

      (sql/execute! db ["INSERT INTO things (animals) VALUES ('{\"cow\", \"pig\"}')"])
      

      【讨论】:

        【解决方案3】:

        我一直在使用的类似策略:

        (defn vec->arr [array-vector]
          (.createArrayOf (j/get-connection db) "varchar" (into-array String array-vector)))
        
        (extend-protocol j/ISQLValue
            clojure.lang.IPersistentVector
            (sql-value [v]
            (vec->arr v)))
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-01-15
          • 1970-01-01
          • 2012-04-03
          • 2023-03-31
          • 2013-06-19
          • 1970-01-01
          • 2014-12-29
          • 2018-06-09
          相关资源
          最近更新 更多