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

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