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 @ 46315

History | View | Annotate | Download (9.08 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.PreparedStatement;
27
import java.sql.SQLException;
28
import java.sql.Statement;
29
import java.util.Collections;
30
import java.util.List;
31
import org.gvsig.expressionevaluator.GeometryExpressionBuilder;
32
import org.gvsig.fmap.dal.exception.DataException;
33
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
34
import org.gvsig.fmap.dal.feature.FeatureType;
35
import org.gvsig.fmap.dal.feature.exception.AlreadyEditingException;
36
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
37
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCPreparingSQLException;
38
import org.gvsig.fmap.dal.store.jdbc2.JDBCConnection;
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.fmap.geom.DataTypes;
44
import org.gvsig.tools.dispose.Disposable;
45
import org.gvsig.tools.dispose.DisposeUtils;
46
import org.slf4j.LoggerFactory;
47

    
48

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

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

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

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

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

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

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

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