Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.dal / org.gvsig.fmap.dal.db / org.gvsig.fmap.dal.db.jdbc / src / main / java / org / gvsig / fmap / dal / store / jdbc2 / spi / operations / AppendOperation.java @ 45533

History | View | Annotate | Download (9 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2020 gvSIG Association.
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 3
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24
package org.gvsig.fmap.dal.store.jdbc2.spi.operations;
25

    
26
import java.sql.Connection;
27
import java.sql.PreparedStatement;
28
import java.sql.SQLException;
29
import java.util.Collections;
30
import java.util.List;
31
import org.gvsig.expressionevaluator.GeometryExpressionBuilder;
32
import org.gvsig.fmap.dal.DataTypes;
33
import org.gvsig.fmap.dal.exception.DataException;
34
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
35
import org.gvsig.fmap.dal.feature.FeatureType;
36
import org.gvsig.fmap.dal.feature.exception.AlreadyEditingException;
37
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
38
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCPreparingSQLException;
39
import org.gvsig.fmap.dal.store.jdbc2.JDBCHelper;
40
import org.gvsig.fmap.dal.store.jdbc2.JDBCUtils;
41
import org.gvsig.fmap.dal.store.jdbc2.OperationsFactory.TableReference;
42
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase;
43
import org.gvsig.tools.dispose.Disposable;
44
import org.gvsig.tools.dispose.DisposeUtils;
45
import org.slf4j.LoggerFactory;
46

    
47

    
48
public class AppendOperation {
49
    protected static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(AppendOperation.class);
50
    
51
    protected Connection connection = null;
52
    protected final JDBCHelper helper;
53
    protected final TableReference table;
54
    protected final FeatureType type;
55
    
56
    protected JDBCSQLBuilderBase sqlbuilder = null;
57
    protected GeometryExpressionBuilder expbuilder;
58

    
59
    protected PreparedStatement preparedStatement;
60
    protected String insertSQL;
61
    protected int batchCount;
62
    private final int batchSize;
63
    private final Disposable[] disposableParameters;
64
    
65
    public AppendOperation(
66
            JDBCHelper helper, 
67
            TableReference table, 
68
            FeatureType type
69
        ) {
70
        this.helper = helper;
71
        this.table = table;
72
        this.type = type;
73
        this.batchSize = this.helper.getConnectionParameters().getBatchSize();
74
        if( this.batchSize>0 ) {
75
            this.disposableParameters = new Disposable[this.batchSize];
76
        } else {
77
            this.disposableParameters = null;
78
        }
79
    }
80
    
81
    public void begin() throws DataException {
82
        if (this.sqlbuilder != null) {
83
            throw new AlreadyEditingException(this.helper.getSourceId());
84
        }
85

    
86
        try {
87
            this.connection = this.helper.getConnectionWritable();
88
            
89
            this.sqlbuilder = this.helper.createSQLBuilder();
90
            this.expbuilder = this.sqlbuilder.expression();
91

    
92
            this.sqlbuilder.insert().table()
93
                    .database(this.table.getDatabase())
94
                    .schema(this.table.getSchema())
95
                    .name(this.table.getTable()
96
            );
97
            for (FeatureAttributeDescriptor attr : type) {
98
                if( attr.isAutomatic() || attr.isComputed() ) {
99
                    continue;
100
                }
101
                if (attr.getType() == DataTypes.GEOMETRY) {
102
                        this.sqlbuilder.insert().column().name(attr.getName()).with_value( 
103
                            expbuilder.parameter(attr.getName()).as_geometry_variable().srs( 
104
                                    expbuilder.parameter().value(attr.getSRS()) 
105
                            ) 
106
                        );
107
                    } else {
108
                        this.sqlbuilder.insert().column().name(attr.getName()).with_value(
109
                        expbuilder.parameter(attr.getName()).as_variable()
110
                    );
111
                }
112
            }
113

    
114
            this.insertSQL = this.sqlbuilder.insert().toString();
115
            if( this.connection != null ) { // Not in test mode ???
116
              this.preparedStatement = this.connection.prepareStatement(insertSQL);
117
              this.connection.setAutoCommit(false);
118
              for (String sql : this.getPreviousSQLs()) {
119
                JDBCUtils.execute(this.connection, sql);
120
              }
121
            }
122
            
123
        } catch (SQLException ex) {
124
            throw new JDBCPreparingSQLException(this.sqlbuilder.toString(),ex);
125
        }
126

    
127
    }
128
    
129
    protected void clean() {
130
        if( this.batchCount > 0 ) {
131
            this.clearBatch();
132
        }
133
        JDBCUtils.closeQuietly(this.preparedStatement);
134
        this.helper.closeConnection(this.connection);
135
        this.connection = null;
136
        this.preparedStatement = null;
137
        this.sqlbuilder = null;
138
        this.insertSQL = null;        
139
    }
140
    
141
    public void end() {
142
        try {
143
            if( this.connection == null ) {
144
              return; // In test mode ???
145
            }
146
            if( this.batchCount > 0 ) {
147
                this.executeBatch();
148
            }
149
            this.connection.commit();
150
            for (String sql : this.getPostSQLs()) {
151
              JDBCUtils.execute(this.connection, sql);
152
            }
153
        } catch (SQLException ex) {
154
            try {
155
                this.connection.rollback();
156
            } catch (SQLException ex1) {
157
            }
158
            throw new RuntimeException("Can't commit transaction", ex);
159
        } finally {
160
            clean();
161
        }
162
    }
163
    
164
    public void abort() {        
165
        try {
166
            if( this.connection == null ) {
167
              return; // In test mode ???
168
            }
169
            if( this.batchCount > 0 ) {
170
                this.clearBatch();
171
            }
172
            this.connection.rollback();
173
            for (String sql : this.getPostSQLs()) {
174
              JDBCUtils.execute(this.connection, sql);
175
            }
176
        } catch (SQLException ex) {
177
        } finally {
178
          clean();
179
        }
180
    }
181

    
182
    public String getSQL() { // For test
183
      return this.insertSQL;
184
    }
185
    
186
    public List<String> getPreviousSQLs() {
187
      return Collections.EMPTY_LIST;
188
    }
189
    
190
    public List<String> getPostSQLs() {
191
      return Collections.EMPTY_LIST;
192
    }    
193
    
194
    public List<Object> getSQLParameters(FeatureProvider feature) {
195
      return this.sqlbuilder.getParameters(feature);
196
    }
197
    
198
    @SuppressWarnings("UseSpecificCatch")
199
    public void append(FeatureProvider feature) throws DataException {
200
        try {
201
            if( this.batchSize>0 ) {
202
                this.addBatch(feature);
203
                if( this.batchCount >= this.batchSize ) {
204
                    this.executeBatch();
205
                }
206
            } else {
207
                Disposable theParametersDisposable = null;
208
                try {
209
                    theParametersDisposable = this.sqlbuilder.setParameters(this.preparedStatement, feature);
210
                    int n = JDBCUtils.executeUpdate(this.preparedStatement,this.insertSQL);
211
                    if( n<1 ) {
212
                        throw new RuntimeException("Can't insert feature (n="+n+").");
213
                    }
214
                } finally {
215
                    DisposeUtils.disposeQuietly(theParametersDisposable);
216
                }
217
            }
218
        } catch(Exception ex) {
219
            throw new RuntimeException("Can't insert feature.", ex);
220
        }
221
    }
222
    
223
    private void addBatch(FeatureProvider feature) throws SQLException {
224
        Disposable theParametersDisposable = this.sqlbuilder.setParameters(this.preparedStatement, feature);
225
        JDBCUtils.addBatch(this.preparedStatement,this.insertSQL);
226
        this.disposableParameters[this.batchCount++] = theParametersDisposable;
227
    }
228
    
229
    private void executeBatch() throws SQLException {
230
        int[] status = JDBCUtils.executeBatch(this.preparedStatement,this.insertSQL);
231
        this.clearBatch();
232
        for (int n : status) {
233
            if( n<1 ) {
234
                throw new RuntimeException("Can't insert feature (n="+n+").");
235
            }
236
        }
237
    }
238

    
239
    private void clearBatch() {
240
        try {
241
            this.preparedStatement.clearParameters();
242
            this.preparedStatement.clearBatch();
243
            for (int i = 0; i < this.batchCount && i < this.disposableParameters.length; i++) {
244
                DisposeUtils.dispose(this.disposableParameters[i]);
245
                this.disposableParameters[i] = null;
246
            }
247
            this.batchCount = 0;
248
        } catch (SQLException ex) {
249
            LOGGER.warn("Can't clear batch statement", ex);
250
        }
251
    }    
252
}