在Java中从Postgres加载非物质化数组

在Java中从Postgres加载非物质化数组,java,arrays,postgresql,jdbc,Java,Arrays,Postgresql,Jdbc,设置: 我正在用Java连接到Postgres数据库,并尝试加载pg_stats.histogram_boundsstatistic,这是Postgres中的一个数组。我可以使用Array historogrambounds=rs.getArray(“直方图边界”)将字段提取为sql.Array对象。此对象可以使用toString()打印,但我无法访问任何数据(例如调用historogrambounds.getArray(),getBaseType等),所有这些都会生成PSQLException

设置: 我正在用Java连接到Postgres数据库,并尝试加载
pg_stats.histogram_bounds
statistic,这是Postgres中的一个数组。我可以使用
Array historogrambounds=rs.getArray(“直方图边界”)将字段提取为
sql.Array
对象。此对象可以使用
toString()
打印,但我无法访问任何数据(例如调用
historogrambounds.getArray()
getBaseType
等),所有这些都会生成
PSQLException:查询未返回任何结果。

的,以及各种教程和SE问题建议这应该是有效的

显然,
sql.Array
对象并不直接保存数组数据,而是指向服务器上的数组数据。从我的实验中,我得到了以下MWE,它显示了Postgres表中存储的数组值与某种程度上短暂或非物质化的数组值之间的差异(我怀疑
pgu stats
可能是其他内部表的视图)

MWE: 我有两个查询,一个从表中选择数据并工作,另一个直接从查询中选择数据但不工作。我在文档中看不到任何原因,它们不应该同时工作,我希望第二个版本能够工作,以获得Java数组
[1,2,3]
。 令人困惑的是,
toString
在第二种情况下仍然正确显示数据,因此必须在某个时候成功加载数据

import java.sql.Array;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class PostgresStatsExperiments {
    public static void main(String[] args) throws SQLException {
        Connection conn = DriverManager.getConnection("jdbc:postgresql://localhost/tmp", "admin", "admin");
        Statement stmt = conn.createStatement();

        ResultSet rs = stmt.executeQuery("SELECT name, my_data from array_test;"); // This one works
        //ResultSet rs = stmt.executeQuery("SELECT '{1, 2, 3}' AS my_data;"); // This one does not work.

        while (rs.next()) {
            Array myData = rs.getArray("my_data");
            System.out.println(myData);
            System.out.println(myData.getArray()); // PSQLException here in the second case
        }

        stmt.close();
        rs.close();
        conn.close();
    }
}
array\u test
如下所示:

create table array_test ( name varchar, my_data integer ARRAY[3] );
insert into array_test values ('Alice', '{1, 2, 3}');
insert into array_test values ('Bob', '{4, 5, 6}');
在第二种情况下,我得到以下输出:

{1, 2, 3}
Exception in thread "main" org.postgresql.util.PSQLException: No results were returned by the query.
    at org.postgresql.jdbc2.TypeInfoCache.getPGArrayElement(TypeInfoCache.java:425)
    at org.postgresql.jdbc2.AbstractJdbc2Array.buildArray(AbstractJdbc2Array.java:540)
    at org.postgresql.jdbc2.AbstractJdbc2Array.getArrayImpl(AbstractJdbc2Array.java:171)
    at org.postgresql.jdbc2.AbstractJdbc2Array.getArray(AbstractJdbc2Array.java:128)
    at tmp.PostgresStatsExperiments.main(PostgresStatsExperiments.java:21)

我使用的是Maven的
postgresql-9.3-1102-jdbc41.jar
,最新的
42.2.4.jre7
在查询
中选择“{1,2,3}”作为我的_数据
my_数据
不是任何数组。这是一个看起来像数组的字符串,但单引号表示
text
(或
varchar
)值

由于列的数据类型不是数组,因此调用
getArray()
会引发异常

如果需要数组,则需要将文本值强制转换为数组:

SELECT '{1, 2, 3}'::int[] AS my_data;
或者更好:使用显式数组构造函数:

SELECT array[1, 2, 3] AS my_data;

pg_stats.histogram_bounds
定义为
anyarray
——它不是类型化数组,因为它包含每列不同的数据类型(这意味着在每行中,因为该表每列包含一行)

显然,JDBC驱动程序无法正确使用
anyarray

要处理Java代码中的值,我认为最简单的方法是将其转换为字符串,然后再将其转换回文本数组(因为字符串表示是正确的)

因此,如果使用以下查询:

select schemaname, tablename, attname, histogram_bounds::text::text[] as histogram_bounds, ..
from pg_stats
where ...

您应该能够检索
直方图界限
列的内容(但所有内容都是字符串,而不是与列的数据类型匹配的数据类型)。

在查询
中选择“{1,2,3}”作为我的数据
我的数据
不是任何数组。这是一个看起来像数组的字符串,但单引号表示
text
(或
varchar
)值

由于列的数据类型不是数组,因此调用
getArray()
会引发异常

如果需要数组,则需要将文本值强制转换为数组:

SELECT '{1, 2, 3}'::int[] AS my_data;
或者更好:使用显式数组构造函数:

SELECT array[1, 2, 3] AS my_data;

pg_stats.histogram_bounds
定义为
anyarray
——它不是类型化数组,因为它包含每列不同的数据类型(这意味着在每行中,因为该表每列包含一行)

显然,JDBC驱动程序无法正确使用
anyarray

要处理Java代码中的值,我认为最简单的方法是将其转换为字符串,然后再将其转换回文本数组(因为字符串表示是正确的)

因此,如果使用以下查询:

select schemaname, tablename, attname, histogram_bounds::text::text[] as histogram_bounds, ..
from pg_stats
where ...

您应该能够检索
直方图\u界限
列的内容(但您可以将所有内容作为字符串获取,而不是与列的数据类型匹配的数据类型)。

谢谢。“my_数据不是任何数组。它是一个恰巧看起来像数组的字符串”-现在您指出这一点似乎非常明显;哎呀。也许是调用rs.getArray()使我上当了,这是我直觉上无法预料的。你知道为什么吗?我怀疑
anyarray
可能会引起问题,这就是为什么我想首先构建一个更简单的MWE作为一个实验。我很惊讶我没有首先尝试
pg_data
中的一个单类型数组字段,但我想我一定跳过了这一步。如果我将所有内容都转换为字符串,我总是可以从
pg_data
中提取SQL类型,以帮助在Java端进行解码。谢谢。“my_数据不是任何数组。它是一个恰巧看起来像数组的字符串”-现在您指出这一点似乎非常明显;哎呀。也许是调用rs.getArray()使我上当了,这是我直觉上无法预料的。你知道为什么吗?我怀疑
anyarray
可能会引起问题,这就是为什么我想首先构建一个更简单的MWE作为一个实验。我很惊讶我没有首先尝试
pg_data
中的一个单类型数组字段,但我想我一定跳过了这一步。如果我将所有内容都转换为字符串,我总是可以从
pg_data
中提取SQL类型,以帮助在Java端进行解码。