В Java, вызывающей функцию PostgreSQL, почему я получаю сообщение об ошибке, сообщающее, что функция не существует? - PullRequest
2 голосов
/ 01 сентября 2011

У меня есть эта процедура в базе данных:

CREATE OR REPLACE FUNCTION replacePageRelevance(id INT, value REAL) RETURNS VOID AS $$
BEGIN
INSERT INTO pageRelevance VALUES (id,value);
EXCEPTION WHEN unique_violation THEN
    UPDATE pageRelevance SET relevance = value WHERE pageId = id;       
END
$$
LANGUAGE plpgsql;

И этот код, который вызывает эту функцию:

try (CallableStatement cstm = conn.prepareCall(PAGE_RELEVANCE_SQL)) {
        for (Map.Entry<Integer, Double> entry : weightMap.entrySet()) {
            cstm.setInt(1, entry.getKey());
            cstm.setDouble(2, entry.getValue());
            cstm.addBatch();
        }
        cstm.executeBatch();
    } catch (SQLException e) {
        LOGGER.error("Error discovering pages relevance: " + e.getNextException());
    }
}

Это не работает, я получаю сообщение об ошибке, сообщающее, чтоfunction replacepagerelevance(integer, double precision) doesn't exists..Почему?

Сгенерированный вызов такой: SELECT replacePageRelevance('882','8.0').Если я выполню это в pgAdmin, он будет работать, но не из Java.

1 Ответ

4 голосов
/ 01 сентября 2011

Это потому, что ваша функция PL / pgSQL определена как:

replacePageRelevance(id INT, value REAL)

REAL - это плавающая точка одинарной точности, но на стороне Java вы пытаетесь использовать ее как двойную точность, и для такой ситуации неявное приведение не выполняется.

Вы должны скорее использовать CallableStatement.setFloat для одинарной точности REAL тип данных, однако это не совсем понятно, потому что чтение Java API:

Устанавливает назначенный параметр для данного значения Java с плавающей точкой. драйвер преобразует это в значение SQL FLOAT, когда он отправляет его в базы данных.

Поскольку FLOAT является синонимом для DOUBLE PRECISION в Postgres, он работает с тем же эффектом, что и CallableStatement.setDouble, выдавая сообщение об ошибке (это странно).

Конечно, вы можете просто изменить свою функцию на replacePageRelevance(id INT, value DOUBLE PRECISION), и, как я проверял, она хорошо работает с вашим кодом.

Тем не менее, если вы хотите сохранить REAL в своей функции), используйте явное приведение, например:

String PAGE_RELEVANCE_SQL = "{call replacePageRelevance(?, ?::real)}";
...