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 / PerformChangesOperation.java @ 44058

History | View | Annotate | Download (17.2 KB)

1 43020 jjdelcerro
package org.gvsig.fmap.dal.store.jdbc2.spi.operations;
2
3
import java.sql.Connection;
4
import java.sql.PreparedStatement;
5
import java.sql.SQLException;
6
import java.sql.Statement;
7 43687 jjdelcerro
import java.util.ArrayList;
8 43020 jjdelcerro
import java.util.Iterator;
9 43687 jjdelcerro
import java.util.List;
10
import org.apache.commons.collections.CollectionUtils;
11 43650 jjdelcerro
import org.apache.commons.lang3.StringUtils;
12 43020 jjdelcerro
import org.gvsig.fmap.dal.DataTypes;
13
import org.gvsig.fmap.dal.exception.DataException;
14
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
15 43479 jjdelcerro
import org.gvsig.fmap.dal.feature.FeatureReference;
16 43020 jjdelcerro
import org.gvsig.fmap.dal.feature.FeatureType;
17
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
18
import org.gvsig.fmap.dal.feature.spi.FeatureReferenceProviderServices;
19
import org.gvsig.fmap.dal.feature.spi.FeatureStoreProvider;
20
import org.gvsig.fmap.dal.store.jdbc2.JDBCHelper;
21
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCExecuteSQLException;
22
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCSQLException;
23
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCUpdateWithoutChangesException;
24
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase;
25
import org.gvsig.fmap.dal.store.jdbc2.JDBCUtils;
26 44058 jjdelcerro
import org.gvsig.fmap.dal.store.jdbc2.OperationsFactory.TableReference;
27 43629 jjdelcerro
import org.gvsig.tools.dispose.Disposable;
28
import org.gvsig.tools.dispose.DisposeUtils;
29 43020 jjdelcerro
30 43377 jjdelcerro
public class PerformChangesOperation extends AbstractConnectionWritableOperation {
31 43020 jjdelcerro
32 44058 jjdelcerro
    protected TableReference table;
33 43355 jjdelcerro
    protected FeatureType featureType;
34
    protected Iterator<FeatureReferenceProviderServices> deleteds;
35
    protected Iterator<FeatureStoreProvider.FeatureTypeChanged> featureTypesChanged;
36
    protected Iterator<FeatureProvider> updateds;
37
    protected Iterator<FeatureProvider> inserteds;
38 43020 jjdelcerro
39 43355 jjdelcerro
    protected boolean typeChanged = false;
40 43020 jjdelcerro
41
    public PerformChangesOperation(JDBCHelper helper) {
42 44058 jjdelcerro
        this(helper, null, null, null, null, null, null);
43 43020 jjdelcerro
    }
44
45
    public PerformChangesOperation(JDBCHelper helper,
46 44058 jjdelcerro
            TableReference table,
47 43020 jjdelcerro
            FeatureType featureType,
48
            Iterator<FeatureReferenceProviderServices> deleteds,
49
            Iterator<FeatureProvider> inserteds,
50
            Iterator<FeatureProvider> updateds,
51
            Iterator<FeatureStoreProvider.FeatureTypeChanged> featureTypesChanged) {
52
        super(helper);
53
        this.deleteds = deleteds;
54
        this.inserteds = inserteds;
55
        this.updateds = updateds;
56 44058 jjdelcerro
        this.table = table;
57 43020 jjdelcerro
        this.featureType = featureType;
58
        this.featureTypesChanged = featureTypesChanged;
59
    }
60
61
    public boolean isTypeChanged() {
62
        return typeChanged;
63
    }
64 43377 jjdelcerro
65 43020 jjdelcerro
    @Override
66 43629 jjdelcerro
    public Object perform(Connection conn) throws DataException {
67 43020 jjdelcerro
        if (featureTypesChanged.hasNext()) {
68
            FeatureStoreProvider.FeatureTypeChanged item = featureTypesChanged.next();
69 44058 jjdelcerro
            this.performUpdateTable(conn, table, item.getSource(), item.getTarget());
70 43020 jjdelcerro
            typeChanged = true;
71
        } else {
72
            typeChanged = false;
73
        }
74
        if (deleteds.hasNext()) {
75 44058 jjdelcerro
            performDeletes(conn, table, featureType, deleteds);
76 43020 jjdelcerro
        }
77
        if (updateds.hasNext()) {
78 44058 jjdelcerro
            performUpdates(conn, table, featureType, updateds);
79 43020 jjdelcerro
        }
80
        if (inserteds.hasNext()) {
81 44058 jjdelcerro
            performInserts(conn, table, featureType, inserteds);
82 43020 jjdelcerro
        }
83
        return true;
84
    }
85
86 43362 jjdelcerro
    protected JDBCSQLBuilderBase buildDeleteSQL(
87 44058 jjdelcerro
            TableReference table,
88 43362 jjdelcerro
            FeatureType type
89
        ) {
90
        JDBCSQLBuilderBase sqlbuilder = createSQLBuilder();
91 44058 jjdelcerro
        sqlbuilder.delete().table()
92
                .database(this.table.getDatabase())
93
                .schema(this.table.getSchema())
94
                .name(this.table.getTable());
95 43020 jjdelcerro
        for (FeatureAttributeDescriptor attr : type) {
96
            if (attr.isPrimaryKey()) {
97
                sqlbuilder.delete().where().and(
98
                        sqlbuilder.eq(
99
                                sqlbuilder.column(attr.getName()),
100
                                sqlbuilder.parameter(attr.getName()).as_variable()
101
                        )
102
                );
103
            }
104
        }
105
        if (!sqlbuilder.delete().has_where() ) {
106
            throw new RuntimeException("Operation requires missing pk");
107
        }
108 43362 jjdelcerro
        return sqlbuilder;
109
    }
110 43020 jjdelcerro
111 43362 jjdelcerro
    public void performDeletes(Connection conn,
112 44058 jjdelcerro
            TableReference table,
113 43362 jjdelcerro
            FeatureType type,
114
            Iterator<FeatureReferenceProviderServices> deleteds) throws DataException {
115
116 44058 jjdelcerro
        JDBCSQLBuilderBase sqlbuilder = buildDeleteSQL(table, type);
117 43362 jjdelcerro
118 43020 jjdelcerro
        PreparedStatement st = null;
119 43629 jjdelcerro
        Disposable paramsDisposer = null;
120 43020 jjdelcerro
        String sql = sqlbuilder.delete().toString();
121
        try {
122
            st = conn.prepareStatement(sql);
123
            while (deleteds.hasNext()) {
124 43479 jjdelcerro
                FeatureReference reference = (FeatureReference) deleteds.next();
125 43629 jjdelcerro
                paramsDisposer = sqlbuilder.setParameters(st, reference);
126 43020 jjdelcerro
                int nAffected = JDBCUtils.executeUpdate(st,sql);
127
                if (nAffected == 0) {
128
                    throw new JDBCUpdateWithoutChangesException(
129
                            sqlbuilder.delete().toString(),
130
                            null
131
                    );
132
                }
133
                if (nAffected > 1) {
134 44058 jjdelcerro
                    LOGGER.warn("Remove statement affectst to {} rows ( {} )",
135 43020 jjdelcerro
                            nAffected, sql
136
                    );
137
                }
138
            }
139
        } catch (SQLException e) {
140
            throw new JDBCSQLException(e);
141
        } finally {
142
            JDBCUtils.closeQuietly(st);
143 43629 jjdelcerro
            DisposeUtils.disposeQuietly(paramsDisposer);
144 43020 jjdelcerro
        }
145
    }
146 43362 jjdelcerro
147
    protected JDBCSQLBuilderBase buildInsertSQL(
148 44058 jjdelcerro
            TableReference table,
149 43362 jjdelcerro
            FeatureType type
150
        ) {
151 43020 jjdelcerro
        JDBCSQLBuilderBase sqlbuilder = createSQLBuilder();
152
153 44058 jjdelcerro
        sqlbuilder.insert().table()
154
                .database(this.table.getDatabase())
155
                .schema(this.table.getSchema())
156
                .name(this.table.getTable());
157 43020 jjdelcerro
        for (FeatureAttributeDescriptor attr : type) {
158 43362 jjdelcerro
            if( attr.isAutomatic() ) {
159
                continue;
160
            }
161 43020 jjdelcerro
            if (attr.getType() == DataTypes.GEOMETRY) {
162
                sqlbuilder.insert().column().name(attr.getName()).with_value(
163 43093 jjdelcerro
                    sqlbuilder.parameter(attr.getName()).as_geometry_variable().srs(
164
                        sqlbuilder.parameter().value(attr.getSRS()).as_constant()
165 43020 jjdelcerro
                    )
166
                );
167
            } else {
168
                sqlbuilder.insert().column().name(attr.getName()).with_value(
169
                        sqlbuilder.parameter(attr.getName())
170
                );
171
            }
172
        }
173 43362 jjdelcerro
        return sqlbuilder;
174
    }
175 43020 jjdelcerro
176 43362 jjdelcerro
    public void performInserts(Connection conn,
177 44058 jjdelcerro
            TableReference table,
178 43362 jjdelcerro
            FeatureType type,
179
            Iterator<FeatureProvider> inserteds) throws DataException {
180 44058 jjdelcerro
        JDBCSQLBuilderBase sqlbuilder = buildInsertSQL(table, type);
181 43362 jjdelcerro
182 43020 jjdelcerro
        PreparedStatement st;
183 43650 jjdelcerro
        Disposable paramsDisposer;
184 43020 jjdelcerro
        String sql = sqlbuilder.insert().toString();
185
        try {
186
            st = conn.prepareStatement(sql);
187
            while (inserteds.hasNext()) {
188
                FeatureProvider feature = inserteds.next();
189 43629 jjdelcerro
                paramsDisposer = sqlbuilder.setParameters(st, feature);
190
                try {
191
                    if (JDBCUtils.executeUpdate(st,sql) == 0) {
192
                        throw new JDBCExecuteSQLException(
193
                                sqlbuilder.insert().toString(),
194
                                null
195
                        );
196
                    }
197
                } finally {
198
                    DisposeUtils.disposeQuietly(paramsDisposer);
199 43020 jjdelcerro
                }
200
            }
201
        } catch (JDBCExecuteSQLException ex) {
202
            throw ex;
203
        } catch (Exception ex) {
204
            throw new JDBCExecuteSQLException(sql,ex);
205
        }
206
    }
207
208 43362 jjdelcerro
    protected JDBCSQLBuilderBase buildUpdateSQL(
209 44058 jjdelcerro
            TableReference table,
210 43362 jjdelcerro
            FeatureType type
211
        ) {
212
        JDBCSQLBuilderBase sqlbuilder = createSQLBuilder();
213 43020 jjdelcerro
214 44058 jjdelcerro
        sqlbuilder.update().table()
215
                .database(this.table.getDatabase())
216
                .schema(this.table.getSchema())
217
                .name(this.table.getTable());
218 43020 jjdelcerro
        for (FeatureAttributeDescriptor attr : type) {
219
            if (attr.isPrimaryKey()) {
220
                sqlbuilder.update().where().and(
221
                        sqlbuilder.eq(
222
                                sqlbuilder.column(attr.getName()),
223
                                sqlbuilder.parameter(attr.getName()).as_variable()
224
                        )
225
                );
226
            } if ( ! attr.isAutomatic() &&  !attr.isReadOnly() ) {
227
                if (attr.getType() == DataTypes.GEOMETRY) {
228
                    sqlbuilder.update().column().name(attr.getName()).with_value(
229 43093 jjdelcerro
                        sqlbuilder.parameter(attr.getName()).as_geometry_variable().srs(
230
                            sqlbuilder.parameter().value(attr.getSRS()).as_constant()
231 43020 jjdelcerro
                        )
232
                    );
233
                } else {
234
                    sqlbuilder.update().column().name(attr.getName()).with_value(
235
                        sqlbuilder.parameter(attr.getName()).as_variable()
236
                    );
237
                }
238
            }
239
        }
240
        if (!sqlbuilder.update().has_where() ) {
241
            throw new RuntimeException("Operation requires missing pk");
242
        }
243 43362 jjdelcerro
        return sqlbuilder;
244
    }
245
246
    public void performUpdates(Connection conn,
247 44058 jjdelcerro
            TableReference table,
248 43362 jjdelcerro
            FeatureType type,
249
            Iterator<FeatureProvider> updateds) throws DataException {
250 43020 jjdelcerro
251 44058 jjdelcerro
        JDBCSQLBuilderBase sqlbuilder = buildUpdateSQL(table, type);
252 43362 jjdelcerro
253 43020 jjdelcerro
        PreparedStatement st = null;
254 43629 jjdelcerro
        Disposable paramsDisposer = null;
255 43020 jjdelcerro
        String sql = sqlbuilder.update().toString();
256
        try {
257
            st = conn.prepareStatement(sql);
258
            while (updateds.hasNext()) {
259
                FeatureProvider featureProvider = (FeatureProvider) updateds.next();
260 43629 jjdelcerro
                paramsDisposer = sqlbuilder.setParameters(st, featureProvider);
261 43020 jjdelcerro
                if (JDBCUtils.executeUpdate(st,sql) == 0) {
262
                    throw new JDBCUpdateWithoutChangesException(sql,null);
263
                }
264
            }
265
        } catch (SQLException e) {
266
            throw new JDBCSQLException(e);
267
        } finally {
268
            JDBCUtils.closeQuietly(st);
269 43629 jjdelcerro
            DisposeUtils.disposeQuietly(paramsDisposer);
270 43020 jjdelcerro
        }
271
    }
272
273 43687 jjdelcerro
    protected List<String> buildUpdateTableSQL(
274 44058 jjdelcerro
            TableReference table,
275 43020 jjdelcerro
            FeatureType original,
276 43362 jjdelcerro
            FeatureType target
277
        ) {
278
        JDBCSQLBuilderBase sqlbuilder = createSQLBuilder();
279 44058 jjdelcerro
        sqlbuilder.alter_table().table()
280
                .database(this.table.getDatabase())
281
                .schema(this.table.getSchema())
282
                .name(this.table.getTable());
283 43020 jjdelcerro
284
        for (FeatureAttributeDescriptor attrOrgiginal : original) {
285
            FeatureAttributeDescriptor attrTarget = target.getAttributeDescriptor(
286
                    attrOrgiginal.getName()
287
            );
288
            if (attrTarget == null) {
289
                sqlbuilder.alter_table().drop_column(attrOrgiginal.getName());
290 43650 jjdelcerro
            } else if( !this.areEquals(attrOrgiginal, attrTarget) ) {
291
                if( attrTarget.getType()==DataTypes.GEOMETRY ) {
292
                    sqlbuilder.alter_table().alter_geometry_column(
293
                            attrTarget.getName(),
294
                            attrTarget.getGeomType().getType(),
295
                            attrTarget.getGeomType().getSubType(),
296
                            attrTarget.getSRS(),
297
                            attrTarget.isIndexed(),
298
                            attrTarget.allowNull()
299
                    );
300
                } else {
301
                    sqlbuilder.alter_table().alter_column(
302
                            attrTarget.getName(),
303
                            attrTarget.getType(),
304
                            attrTarget.getPrecision(),
305
                            attrTarget.getSize(),
306
                            attrTarget.isPrimaryKey(),
307
                            attrTarget.isIndexed(),
308
                            attrTarget.allowNull(),
309
                            attrTarget.isAutomatic(),
310
                            attrTarget.getDefaultValue()
311
                    );
312
                }
313 43020 jjdelcerro
            }
314
        }
315
        for (FeatureAttributeDescriptor attrTarget : target) {
316
            if (original.getAttributeDescriptor(attrTarget.getName()) == null) {
317 43650 jjdelcerro
                if( attrTarget.getType()==DataTypes.GEOMETRY ) {
318
                    sqlbuilder.alter_table().add_geometry_column(
319
                            attrTarget.getName(),
320
                            attrTarget.getGeomType().getType(),
321
                            attrTarget.getGeomType().getSubType(),
322
                            attrTarget.getSRS(),
323
                            attrTarget.isIndexed(),
324
                            attrTarget.allowNull()
325
                    );
326
                } else {
327
                    sqlbuilder.alter_table().add_column(
328
                            attrTarget.getName(),
329
                            attrTarget.getType(),
330
                            attrTarget.getPrecision(),
331
                            attrTarget.getSize(),
332
                            attrTarget.isPrimaryKey(),
333
                            attrTarget.isIndexed(),
334
                            attrTarget.allowNull(),
335
                            attrTarget.isAutomatic(),
336
                            attrTarget.getDefaultValue()
337
                    );
338
                }
339 43020 jjdelcerro
            }
340
        }
341 43687 jjdelcerro
        return sqlbuilder.alter_table().toStrings();
342 43362 jjdelcerro
    }
343 43650 jjdelcerro
344
    protected boolean areEquals(FeatureAttributeDescriptor attr1, FeatureAttributeDescriptor attr2) {
345
        // No interesa si son o no iguales en general, solo si son iguales en lo
346
        // que a los atributos usados para crear la columna de la tabla se refiere.
347
        if( !StringUtils.equals(attr1.getName(), attr2.getName()) ) {
348
            return false;
349
        }
350
        if( attr1.getType() != attr2.getType() ) {
351
            return false;
352
        }
353
        if( attr1.getPrecision() != attr2.getPrecision() ) {
354
            return false;
355
        }
356
        if( attr1.getSize() != attr2.getSize() ) {
357
            return false;
358
        }
359
        if( attr1.isPrimaryKey() != attr2.isPrimaryKey() ) {
360
            return false;
361
        }
362 43687 jjdelcerro
//        if( attr1.isIndexed() != attr2.isIndexed() ) {
363
//            return false;
364
//        }
365 43650 jjdelcerro
        if( attr1.allowNull() != attr2.allowNull() ) {
366
            return false;
367
        }
368
        if( attr1.isAutomatic() != attr2.isAutomatic() ) {
369
            return false;
370
        }
371
        if( attr1.getDefaultValue() != attr2.getDefaultValue() ) {
372
            if( attr1.getDefaultValue()==null || attr2.getDefaultValue()==null) {
373
                return false;
374
            }
375
            if( !attr1.getDefaultValue().equals(attr2.getDefaultValue()) ) {
376
                return false;
377
            }
378
        }
379
        return true;
380
    }
381 43362 jjdelcerro
382 43687 jjdelcerro
    protected List<String> buildCreateIndexSQL(
383 44058 jjdelcerro
            TableReference table,
384 43687 jjdelcerro
            FeatureType original,
385
            FeatureType target
386
        ) {
387
        ArrayList<String> sqls = new ArrayList<>();
388
389
        for (FeatureAttributeDescriptor attrTarget : target) {
390
            boolean createIndex = false;
391
            if( attrTarget.isIndexed() ) {
392
                FeatureAttributeDescriptor attrOriginal = original.getAttributeDescriptor(attrTarget.getName());
393
                if ( attrOriginal == null) {
394
                    createIndex = true;
395
                } else {
396
                    if( attrOriginal.isIndexed() ) {
397
                        createIndex = false;
398
                    } else {
399
                        createIndex = true;
400
                    }
401
                }
402
            }
403
            if( createIndex ) {
404
                JDBCSQLBuilderBase sqlbuilder = createSQLBuilder();
405
                if( attrTarget.getType()==DataTypes.GEOMETRY ) {
406
                    sqlbuilder.create_index().spatial();
407
                }
408
                sqlbuilder.create_index().if_not_exist();
409
                sqlbuilder.create_index().name("idx_" + table + "_" + attrTarget.getName());
410
                sqlbuilder.create_index().column(attrTarget.getName());
411 44058 jjdelcerro
                sqlbuilder.create_index().table()
412
                    .database(this.table.getDatabase())
413
                    .schema(this.table.getSchema())
414
                    .name(this.table.getTable());
415 43687 jjdelcerro
                sqls.addAll(sqlbuilder.create_index().toStrings());
416
            }
417
        }
418
        return sqls;
419
    }
420
421 43362 jjdelcerro
    public void performUpdateTable(Connection conn,
422 44058 jjdelcerro
            TableReference table,
423 43362 jjdelcerro
            FeatureType original,
424
            FeatureType target) throws DataException {
425 43687 jjdelcerro
426
        ArrayList<String> sqls = new ArrayList<>();
427
428 44058 jjdelcerro
        sqls.addAll(buildUpdateTableSQL(table, original, target));
429
        sqls.addAll(buildCreateIndexSQL(table, original, target));
430 43687 jjdelcerro
431
        if( !CollectionUtils.isEmpty(sqls) ) {
432
            Statement st = null;
433
            try {
434
                st = conn.createStatement();
435
                for (String sql : sqls) {
436
                    JDBCUtils.execute(st, sql);
437
                }
438
            } catch (SQLException e) {
439
                throw new JDBCSQLException(e);
440
            } finally {
441
                JDBCUtils.closeQuietly(st);
442 43020 jjdelcerro
            }
443
        }
444
    }
445
}