【问题标题】:How to call a postgres function with an array of composite type如何使用复合类型数组调用 postgres 函数
【发布时间】:2017-11-25 15:21:04
【问题描述】:

我正在寻找有关如何调用具有复合类型数组参数的 postgres 函数的建议。有人问过类似的问题,但我找到了满意的答案。

我有以下复合类型:

CREATE TYPE collect.event_record AS (
    event_type      integer
  , event_timestamp timestamp without time zone
  , event_data      text
  , event_import_id integer
  );

我有以下功能:

CREATE OR REPLACE FUNCTION collect.insert_events(
    fail_on_duplicates boolean,
    source_public_id text,
    event_records collect.event_record[])
  RETURNS integer AS
  ...

在 postgres 方面,一切似乎都运行良好。现在我只需要从 java/kotlin 调用它。

我们使用这个版本的 postgres 驱动:

compile group: "org.postgresql", name: "postgresql", version: "9.4.1212"

PreparedStatement 上有一种方法似乎是我正在寻找的:

void setArray (int parameterIndex, Array x) throws SQLException;

数组类型是java.sql.Array,据我所知可以使用 Connection 对象创建:

Array createArrayOf(String typeName, Object[] elements) throws SQLException;

但是,在这里我不确定要输入什么。typeName 应该是什么?我想我应该创建一个与复合类型匹配的类,并根据需要对字段进行序列化,或者它是java.sql.Struct 的数组。

我一直在搜索示例,但它们似乎主要处理原始类型,这对我的情况没有帮助。

另一种方法是重构 insert_events 以接受多个原始类型数组,类似于我的对象的列视图。

另一种选择是发送一个 JSON 数组,我在 postgres 函数中将其转换为 collect.event_record[] 数组。

但是,我想找到一种方法来保留我目前拥有的 postgres 函数签名。

非常感谢任何想法。

【问题讨论】:

  • From this doc typeName 确实应该是您要创建数组的类型的字符串表示形式。所以在你的情况下它应该是“collect.event_record”。

标签: java postgresql jdbc kotlin


【解决方案1】:

据我所知,Postgres jdbc 驱动程序不支持 Struct,但是对于复合类型数组还有另一种解决方法。文档says 可以使用以下构造创建复合类型的实例:(value_of_event_type,value_of_event_timestamp,value_of_event_data,value_event_import_id)event_record数据结构可以这样定义:

data class EventRecord(
    val eventType: Int,
    val eventTimestamp: Instant,
    val eventData: String,
    val eventImportId: Int) {

    fun toSqlRow(): String {
        return ("(" + eventType + ","
                    + eventTimestamp + ","
                    + eventData + ","
                    + eventImportId +
                ")")
    }
}

下一步是创建PreparedStatement

val preparedStatement = con.prepareStatement("SELECT * FROM public.insert_events(?, ?, ?)")
// ... define other parameters
preparedStatement.setArray(3, con.createArrayOf("public.event_record", records.map { e -> e.toSqlRow() }.toTypedArray()))

创建的PreparedStatement可以用来查询数据库。

PS:当前实现不适用于包含,"' 的文本值。如果文本值包含,,则将其括在引号中,并将" 替换为\"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-09
    • 2014-12-14
    • 1970-01-01
    • 1970-01-01
    • 2010-10-08
    • 1970-01-01
    • 2017-01-24
    • 2014-08-20
    相关资源
    最近更新 更多