如何使用复合类型数组调用postgres函数

时间:2017-06-22 11:16:18

标签: java postgresql jdbc kotlin

我正在寻找有关如何调用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功能签名。

非常感谢任何想法。

1 个答案:

答案 0 :(得分:0)

据我所知,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:当前实现不适用于包含,"'的文本值。如果文本值包含,,请用引号将其引起来,并将"替换为\"