1919package org .apache .cayenne .dba .postgres ;
2020
2121import org .apache .cayenne .access .DataNode ;
22+ import org .apache .cayenne .access .OperationObserver ;
23+ import org .apache .cayenne .access .jdbc .ColumnDescriptor ;
2224import org .apache .cayenne .access .jdbc .SelectAction ;
25+ import org .apache .cayenne .access .translator .ParameterBinding ;
26+ import org .apache .cayenne .access .translator .select .TranslatedSelect ;
2327import org .apache .cayenne .query .Select ;
2428
29+ import java .sql .Connection ;
30+ import java .sql .SQLException ;
31+ import java .sql .Types ;
32+
2533/**
2634 * @since 3.0
2735 */
@@ -35,4 +43,52 @@ <T> PostgresSelectAction(Select<T> query, DataNode dataNode) {
3543 protected int getInMemoryOffset (int queryOffset ) {
3644 return 0 ;
3745 }
46+
47+ @ Override
48+ protected void performAction (Connection connection , OperationObserver observer , TranslatedSelect translated ) throws Exception {
49+
50+ if (!connection .getAutoCommit () || !readsLargeObjects (translated )) {
51+ super .performAction (connection , observer , translated );
52+ return ;
53+ }
54+
55+ // manual tx management for reading LOBs
56+ connection .setAutoCommit (false );
57+ try {
58+ super .performAction (connection , observer , translated );
59+ connection .commit ();
60+ } catch (Exception e ) {
61+ try {
62+ connection .rollback ();
63+ } catch (SQLException ignored ) {
64+ // connection is being returned/closed anyway
65+ }
66+ throw e ;
67+ } finally {
68+ try {
69+ connection .setAutoCommit (true );
70+ } catch (SQLException ignored ) {
71+ // connection is being returned/closed anyway
72+ }
73+ }
74+ }
75+
76+ private static boolean readsLargeObjects (TranslatedSelect translated ) {
77+ for (ColumnDescriptor column : translated .resultColumns ()) {
78+ if (isLargeObject (column .getJdbcType ())) {
79+ return true ;
80+ }
81+ }
82+ // a large object bound as a parameter (e.g. in a qualifier) also needs a transaction
83+ for (ParameterBinding binding : translated .bindings ()) {
84+ if (isLargeObject (binding .getJdbcType ())) {
85+ return true ;
86+ }
87+ }
88+ return false ;
89+ }
90+
91+ private static boolean isLargeObject (int jdbcType ) {
92+ return jdbcType == Types .BLOB || jdbcType == Types .CLOB || jdbcType == Types .NCLOB ;
93+ }
3894}
0 commit comments