Загрузка нематериализованного массива из Postgres в Java - PullRequest
0 голосов
/ 05 сентября 2018

Настройка: Я подключаюсь к базе данных Postgres с помощью Java и пытаюсь загрузить статистику pg_stats.histogram_bounds, которая является массивом в Postgres. Я могу извлечь поле как sql.Array объект с Array histogramBounds = rs.getArray("histogram_bounds");. Этот объект может быть напечатан с помощью toString(), но я не могу получить доступ к каким-либо данным (например, вызовы histogramBounds.getArray(), getBaseType и т. Д.), Все генерируют PSQLException: No results were returned by the query..

Документация , а также различные учебные пособия и вопросы по SE предполагают, что это должно быть в силе.

Очевидно, sql.Array объекты не хранят данные массива напрямую, а указывают на них на сервере. Из моих экспериментов у меня есть следующий MWE, который показывает разницу между значением массива, хранящимся в таблице в Postgres, и значением, которое является каким-то эфемерным или нематериализованным (как я подозреваю, pg_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_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)

Я использую postgresql-9.3-1102-jdbc41.jar от Maven, и проблема также с последней 42.2.4.jre7.

1 Ответ

0 голосов
/ 07 сентября 2018

В запросе SELECT '{1, 2, 3}' AS my_data столбец my_data равен , а не любому массиву. Это строка, которая выглядит как массив - но одинарные кавычки обозначают значение 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 ...

Вы должны иметь возможность извлечь содержимое столбца histogram_bounds (но вы получите все в виде строк, а не тип данных, соответствующий типу данных столбца).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...