2016-01-01 4 views
2

Я выполняю подготовленную вставку пакета в таблицу Postgres, используя pg-jdbc/JDBI, чтобы получить список сгенерированных значений id, используя явное предложение RETURNING:Pg-jdbc добавляет RETURNING * в подготовленную партию с существующим пунктом RETURNING

PreparedBatch b = getHandle().prepareBatch("INSERT INTO death_star(id,exhaust_port) VALUES (:id, :exhaust_port) RETURNING id;"); 

for (RebelPilot p : rebelPilots) { 
    b.add().bind("id",p.getId()).bind("exhaust_port",p.getProtonTorpedo()); 
} 

ResultSetMapper<Long> mapper = new IdMapper() 
GeneratedKeys<Long> gk = b.executeAndGenerateKeys(mapper); 
return gk.list() 

Когда готовят заявление, пг-JDBC будет бездумно добавить дополнительный RETURNING * после существующего RETURNING пункта приводит к следующему искаженной мерзости:

INSERT INTO death_star(id,exhaust_port) VALUES (?, ?) RETURNING id RETURNING *; 

Если я удалить явную получать отдачу NG, заявление отлично работает; однако он возвращает ВСЕ поля из целевой таблицы, что крайне нежелательно во многих ситуациях, когда вставляются большие объемы данных.

Есть ли способ остановить pg-jdbc от такого поведения?

Тестовые Зависимости:

<dependency> 
    <groupId>org.postgresql</groupId> 
    <artifactId>postgresql</artifactId> 
    <version>9.4.1207.jre7</version> 
    </dependency> 
    <dependency> 
    <groupId>org.jdbi</groupId> 
    <artifactId>jdbi</artifactId> 
    <version>2.71</version> 
    </dependency> 
+0

При использовании обычного JDBC 'Connection.prepareStatement (String)' будет ** не ** добавьте 'returning' пункт. Поэтому я предполагаю, что метод 'prepareBatch()' вызывает вызовы, например. ['Connection.prepareStatement (String, int)'] (http://docs.oracle.com/javase/8/docs/api/java/sql/Connection.html#prepareStatement-java.lang.String-int-) , Можете ли вы научить этот метод делать «обычную» подготовку? Я не знаю, что делает 'executeAndGenerateKeys()' делает. Но с помощью простого JDBC вы просто вызываете 'execute()', а затем получаете сгенерированные ключи с помощью 'getResultSet()' из 'PreparedStatement' –

+0

. Я не понимаю, почему добавление« RETURNING * »в качестве дополнения по умолчанию будет недействительным глобальный вариант, чтобы изменить его, особенно когда предложение 'RETURNING' уже присутствует в заявлении. Возможно, мне нужно записать проблему на pg-jdbc и JDBI. Кажется, что нет способа обойти это поведение с подготовленной партией JDBI. Согласно [this] (https://github.com/2ndQuadrant/pgjdbc/commit/1471bd93fce5401c8bc80f686f8beace9572ec79) pg-jdbc фактически не выполняет пакетную обработку, если целевые таблицы содержат массивы или неограниченные текстовые столбцы, поэтому я не уверен, что есть пункт для начала, – THX1138

+1

Это обсуждалось в списке рассылки JDBC. При использовании 'prepareStatement (String, int)' драйвер должен будет проанализировать инструкцию, чтобы узнать, какие столбцы будут возвращены. Но у вас есть возможность изменить это (в JDBC). Если вы используете 'prepareStatement (String, String []), то драйвер вернет только указанные столбцы (я не знаю, сможет ли ваш слой обфускации сделать это) –

ответ

1

Вы используете executeAndGenerateKeys, которые, вероятно, использовать Connection.prepareStatement(query, Statement.RETURN_GENERATED_KEYS). Сгенерированная реализация ключей PostgreSQL JDBC добавит RETURNING * к запросу в этом случае (он не проверяет, существует ли он в тексте запроса). Вам нужно удалить RETURNING id из вашего собственного запроса, чтобы он работал.

Если вы хотите использовать RETURNING id как своего рода оптимизацию, то вам нужно выяснить, имеет ли JDBI API доступ к Connection.preparedStatement(String query, String[] columnNames) (который, насколько я могу судить, этого не имеет).

К только другому варианту необходимо подать запрос на улучшение для pgjdbc.

+0

Поданные ошибки на JDBI [здесь] (https://github.com/jdbi/jdbi/issues/253) и pgjdbc [здесь] (https://github.com/pgjdbc/pgjdbc/issues/488) – THX1138

0

Использование connection.prepareStatement(sql) вместо connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)