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

History | View | Annotate | Download (28.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.PreparedStatement;
27
import java.sql.SQLException;
28
import java.sql.Statement;
29
import java.util.Arrays;
30
import java.util.HashMap;
31
import java.util.Iterator;
32
import java.util.List;
33
import java.util.Map;
34
import java.util.Objects;
35
import org.apache.commons.collections.CollectionUtils;
36
import org.apache.commons.lang3.StringUtils;
37
import org.gvsig.expressionevaluator.ExpressionBuilder;
38
import org.gvsig.expressionevaluator.ExpressionBuilder.Parameter;
39
import org.gvsig.expressionevaluator.ExpressionBuilder.Variable;
40
import org.gvsig.expressionevaluator.ExpressionUtils;
41
import org.gvsig.expressionevaluator.GeometryExpressionBuilder;
42
import org.gvsig.fmap.dal.DataTypes;
43
import org.gvsig.fmap.dal.SQLBuilder;
44
import static org.gvsig.fmap.dal.SQLBuilder.PROP_FEATURE_TYPE;
45
import static org.gvsig.fmap.dal.SQLBuilder.PROP_TABLE;
46
import org.gvsig.fmap.dal.exception.DataException;
47
import org.gvsig.fmap.dal.feature.EditableFeatureType;
48
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
49
import org.gvsig.fmap.dal.feature.FeatureReference;
50
import org.gvsig.fmap.dal.feature.FeatureType;
51
import org.gvsig.fmap.dal.feature.FeatureType.FeatureTypeChanged;
52
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
53
import org.gvsig.fmap.dal.feature.spi.FeatureReferenceProviderServices;
54
import org.gvsig.fmap.dal.feature.spi.FeatureStoreProviderServices;
55
import org.gvsig.fmap.dal.store.jdbc.JDBCStoreParameters;
56
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCExecuteSQLException;
57
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCSQLException;
58
import org.gvsig.fmap.dal.store.jdbc2.JDBCConnection;
59
import org.gvsig.fmap.dal.store.jdbc2.JDBCHelper;
60
import org.gvsig.fmap.dal.store.jdbc2.JDBCUtils;
61
import org.gvsig.fmap.dal.store.jdbc2.OperationsFactory.TableReference;
62
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase;
63
import org.gvsig.tools.dispose.Disposable;
64
import org.gvsig.tools.dispose.DisposeUtils;
65
import org.gvsig.tools.util.Bitmask;
66
import org.gvsig.tools.util.Invocable;
67

    
68
@SuppressWarnings("UseSpecificCatch")
69
public class PerformChangesOperation extends AbstractConnectionWritableOperation {
70

    
71
    protected TableReference table;
72
    protected FeatureType featureType;
73
    protected FeatureType featureTypeSource;
74
    protected FeatureType featureTypeTarget;
75
    protected Iterator<FeatureReferenceProviderServices> deleteds;
76
    protected Iterator<FeatureProvider> updateds;
77
    protected Iterator<FeatureProvider> inserteds;
78

    
79
    protected boolean typeChanged = false;
80
    protected final FeatureStoreProviderServices storeServices;
81
    
82
    public PerformChangesOperation(JDBCHelper helper) {
83
        this(helper, null, null, null, null, null, null, null);
84
    }
85

    
86
    public PerformChangesOperation(JDBCHelper helper,
87
            TableReference table,
88
            FeatureType featureType,
89
            Iterator<FeatureReferenceProviderServices> deleteds,
90
            Iterator<FeatureProvider> inserteds,
91
            Iterator<FeatureProvider> updateds,
92
            Iterator<FeatureTypeChanged> featureTypesChanged,
93
            FeatureStoreProviderServices storeServices) {
94
        super(helper);
95
        this.deleteds = deleteds;
96
        this.inserteds = inserteds;
97
        this.updateds = updateds;
98
        this.table = table;
99
        this.featureType = featureType;
100
        if (featureTypesChanged.hasNext()) {
101
            FeatureTypeChanged item = featureTypesChanged.next();
102
            this.featureTypeSource = item.getSource();
103
            this.featureTypeTarget = item.getTarget();
104
            typeChanged = true;
105
        } else {
106
            this.featureTypeSource = null;
107
            this.featureTypeTarget = null;
108
            typeChanged = false;
109
        }
110
        this.storeServices = storeServices;
111
    }
112

    
113
    public boolean isTypeChanged() {
114
        return typeChanged;
115
    }
116

    
117
    @Override
118
    public Object perform(JDBCConnection conn) throws DataException {
119
        if (typeChanged) {
120
            this.performUpdateTable(conn);
121
        }
122
        if (inserteds.hasNext()) {
123
            performInserts(conn);
124
        }
125
        if (updateds.hasNext()) {
126
            performUpdates(conn);
127
        }
128
        if (deleteds.hasNext()) {
129
            performDeletes(conn);
130
        }
131
        return true;
132
    }
133
    
134
    public String getDeleteSQL() {
135
        JDBCSQLBuilderBase sqlbuilder = createSQLBuilder();
136
        return this.getDeleteSQL(sqlbuilder);
137
    }
138
    
139
    public String getDeleteSQL(JDBCSQLBuilderBase sqlbuilder) {
140
        ExpressionBuilder expbuilder = sqlbuilder.expression();
141

    
142
        sqlbuilder.delete().table()
143
                .database(this.table.getDatabase())
144
                .schema(this.table.getSchema())
145
                .name(this.table.getTable());
146
        for (FeatureAttributeDescriptor attr : this.featureType) {
147
            if (attr.isPrimaryKey()) {
148
                sqlbuilder.delete().where().and(
149
                        expbuilder.eq(
150
                                expbuilder.column(attr.getName()),
151
                                expbuilder.parameter(attr.getName()).as_variable()
152
                        )
153
                );
154
            }
155
        }
156
        if (!sqlbuilder.delete().has_where() ) {
157
            throw new RuntimeException("Operation requires missing pk");
158
        }
159
        sqlbuilder.setProperties(
160
                Variable.class, 
161
                PROP_TABLE, table
162
        );
163
        String sql = sqlbuilder.delete().toString();
164
        return sql;
165
    }
166

    
167
    public void performDeletes(JDBCConnection conn) throws DataException {
168
        JDBCSQLBuilderBase sqlbuilder = createSQLBuilder();
169
        String sql = getDeleteSQL(sqlbuilder);
170
        perform_batchmode(conn, this.deleteds, sqlbuilder, sql, new Invocable() {
171
            @Override
172
            public Object call(Object... args) {
173
                JDBCSQLBuilderBase sqlbuilder = (JDBCSQLBuilderBase) args[0];
174
                PreparedStatement preparedStatement = (PreparedStatement) args[1];
175
                FeatureReference reference = (FeatureReference) args[2];
176
                Disposable theParametersDisposable = sqlbuilder.setParameters(preparedStatement, reference);
177
                return theParametersDisposable;
178
            }
179
        });
180
    }
181
    
182
    public String getInsertSQL() {
183
        JDBCSQLBuilderBase sqlbuilder = createSQLBuilder();
184
        return this.getInsertSQL(sqlbuilder);
185
    }
186
    
187
    public String getInsertSQL(JDBCSQLBuilderBase sqlbuilder) {
188
        GeometryExpressionBuilder expbuilder = sqlbuilder.expression();
189

    
190
        sqlbuilder.insert().table()
191
                .database(this.table.getDatabase())
192
                .schema(this.table.getSchema())
193
                .name(this.table.getTable());
194
        for (FeatureAttributeDescriptor attr : this.featureType) {
195
            // Cuando insertamos registros hay que permitir meter un valor
196
            // en la claves automaticas. Es responsable de quien los inserta,
197
            // en caso de que no meta nulos, que se asegure que no hay valores
198
            // duplicados, ya que que de haberlos fallara el insert.
199
            if( /*attr.isAutomatic() ||*/ attr.isComputed() ) {
200
                continue;
201
            }
202
            if (attr.getType() == DataTypes.GEOMETRY) {
203
                sqlbuilder.insert().column().name(attr.getName()).with_value(
204
                    expbuilder.parameter(attr.getName()).as_variable()
205
                        .srs(
206
                            expbuilder.parameter().value(
207
                                attr.getSRS()).as_constant()
208
                        )
209
                );
210
            } else {
211
                sqlbuilder.insert().column().name(attr.getName()).with_value(
212
                        expbuilder.parameter(attr.getName())
213
                );
214
            }
215
        }
216

    
217
        sqlbuilder.setProperties(
218
                Variable.class, 
219
                PROP_FEATURE_TYPE, featureType,
220
                PROP_TABLE, table
221
        );
222
        sqlbuilder.setProperties(
223
                Parameter.class, 
224
                PROP_FEATURE_TYPE, featureType,
225
                PROP_TABLE, table
226
        );
227
        String sql = sqlbuilder.insert().toString();
228
        return sql;
229
    }
230

    
231
    public void performInserts(JDBCConnection conn) throws DataException {
232
        JDBCSQLBuilderBase sqlbuilder = createSQLBuilder();
233
        String sql = getInsertSQL(sqlbuilder);
234
        perform_batchmode(conn, this.inserteds, sqlbuilder, sql, new Invocable() {
235
            @Override
236
            public Object call(Object... args) {
237
                JDBCSQLBuilderBase sqlbuilder = (JDBCSQLBuilderBase) args[0];
238
                PreparedStatement preparedStatement = (PreparedStatement) args[1];
239
                FeatureProvider feature = (FeatureProvider) args[2];
240
                Disposable theParametersDisposable = sqlbuilder.setParameters(preparedStatement, feature);
241
                return theParametersDisposable;
242
            }
243
        });
244
    }
245
    
246
    public String getUpdateSQL() {
247
        JDBCSQLBuilderBase sqlbuilder = createSQLBuilder();
248
        return this.getUpdateSQL(sqlbuilder);
249
    }
250
    
251
    public String getUpdateSQL(JDBCSQLBuilderBase sqlbuilder) {
252
        if(!this.featureType.hasPrimaryKey()) {
253
            throw new RuntimeException("Operation requires missing pk");
254
        }
255
        GeometryExpressionBuilder expbuilder = sqlbuilder.expression();
256

    
257
        sqlbuilder.update().table()
258
                .database(this.table.getDatabase())
259
                .schema(this.table.getSchema())
260
                .name(this.table.getTable());
261
        for (FeatureAttributeDescriptor attr : this.featureType) {
262
            if (attr.isPrimaryKey()) {
263
                sqlbuilder.update().where().and(
264
                        expbuilder.eq(
265
                                expbuilder.column(attr.getName()),
266
                                expbuilder.parameter(attr.getName()).as_variable()
267
                        )
268
                );
269
                continue;
270
            } 
271
            if ( attr.isAutomatic() || attr.isReadOnly() || attr.isComputed() ) {
272
                continue;
273
            }
274
            if (attr.getType() == DataTypes.GEOMETRY) {
275
                if (attr.getSRS()==null) {
276
                    throw new RuntimeException("Geometries with null srs are not valid. SRS is required in "+this.table.toString()+"in the field:"+attr.getName());
277
                }
278
                sqlbuilder.update().column().name(attr.getName()).with_value(
279
                    expbuilder.parameter(attr.getName()).as_geometry_variable().srs(
280
                        expbuilder.parameter().value(attr.getSRS()).as_constant()
281
                    )
282
                );
283
            } else {
284
                sqlbuilder.update().column().name(attr.getName()).with_value(
285
                    expbuilder.parameter(attr.getName()).as_variable()
286
                );
287
            }
288
        }
289
        if (!sqlbuilder.update().has_where() ) {
290
            throw new RuntimeException("Operation requires missing pk");
291
        }
292
        sqlbuilder.setProperties(
293
                Variable.class, 
294
                PROP_FEATURE_TYPE, this.featureType,
295
                PROP_TABLE, table
296
        );
297
        sqlbuilder.setProperties(
298
                Parameter.class, 
299
                PROP_FEATURE_TYPE, featureType,
300
                PROP_TABLE, table
301
        );
302
        
303
        String sql = sqlbuilder.update().toString();
304
        return sql;
305
    }
306
    
307
    public void performUpdates(JDBCConnection conn) throws DataException {
308
        JDBCSQLBuilderBase sqlbuilder = createSQLBuilder();
309
        String sql = getUpdateSQL(sqlbuilder);
310
        perform_batchmode(conn, this.updateds, sqlbuilder, sql, new Invocable() {
311
            @Override
312
            public Object call(Object... args) {
313
                JDBCSQLBuilderBase sqlbuilder = (JDBCSQLBuilderBase) args[0];
314
                PreparedStatement preparedStatement = (PreparedStatement) args[1];
315
                FeatureProvider feature = (FeatureProvider) args[2];
316
                Disposable theParametersDisposable = sqlbuilder.setParameters(preparedStatement, feature);
317
                return theParametersDisposable;
318
            }
319
        });
320
    }
321
    
322
       
323
    private void perform_batchmode(JDBCConnection conn, Iterator elements, JDBCSQLBuilderBase sqlbuilder, String sql, Invocable fillPreparedStatement) throws DataException {       
324
        PreparedStatement preparedStatement;
325
        Disposable[] disposableParameters;
326
        int batchSize = this.helper.getConnectionParameters().getBatchSize();
327
        if( batchSize==0 ) {
328
            try {
329
                preparedStatement = conn.prepareStatement(sql);
330
                while (elements.hasNext()) {
331
                    Object element = elements.next();
332

    
333
                    Disposable theParametersDisposable = (Disposable) fillPreparedStatement.call(sqlbuilder,preparedStatement, element );
334
                    JDBCUtils.execute(preparedStatement, sql);
335
                    DisposeUtils.disposeQuietly(theParametersDisposable);
336
                }                
337
            } catch (Exception ex) {
338
                throw new JDBCExecuteSQLException(sql + " ("+Objects.toString(elements)+")",ex);
339
            }
340
        } else {
341
            try {
342
                preparedStatement = conn.prepareStatement(sql);
343
                if( batchSize<1 ) {
344
                    batchSize = 200;
345
                }
346
                int batchCount = 0;
347
                disposableParameters = new Disposable[batchSize];
348

    
349
                while (elements.hasNext()) {
350
                    Object element = elements.next();
351

    
352
                    Disposable theParametersDisposable = (Disposable) fillPreparedStatement.call(sqlbuilder,preparedStatement, element );
353
                    JDBCUtils.addBatch(preparedStatement,sql);
354
                    disposableParameters[batchCount++] = theParametersDisposable;
355

    
356
                    if( batchCount >= batchSize || (!elements.hasNext() && batchCount>0) ) {
357
                        int[] status = JDBCUtils.executeBatch(preparedStatement,sql);
358

    
359
                        preparedStatement.clearParameters();
360
                        preparedStatement.clearBatch();
361
                        for (int i = 0; i < batchCount && i < disposableParameters.length; i++) {
362
                            DisposeUtils.dispose(disposableParameters[i]);
363
                            disposableParameters[i] = null;
364
                        }
365
                        batchCount = 0;
366

    
367
                        for (int n : status) {
368
                            if( n<=Statement.EXECUTE_FAILED ) { //-3
369
                                throw new RuntimeException("Can't process element (n="+n+").");
370
                            }
371
                        }                
372
                    }
373
                }
374
            } catch (Exception ex) {
375
                throw new JDBCExecuteSQLException(sql,ex);
376
            }
377
        }
378
    }
379
    
380
    protected FeatureType getCurrentFeatureTypeDB(){
381
        if(this.storeServices == null){
382
            return this.featureTypeSource;
383
        }
384
        try{
385
            JDBCStoreParameters params = (JDBCStoreParameters) this.storeServices.getFeatureStore().getParameters();
386
            EditableFeatureType type = this.storeServices.createFeatureType(this.storeServices.getName());
387
            FetchFeatureTypeOperation fetchFeatureType = 
388
                 this.helper.getOperations().createFetchFeatureType(
389
                    type,
390
                    this.table,
391
                    params.getPkFields()==null?null:Arrays.asList(params.getPkFields()),
392
                    params.getDefaultGeometryField(),
393
                    params.getCRS(),
394
                    params.getGeometryType(),
395
                    params.getGeometrySubtype()
396
                );
397
            fetchFeatureType.perform(this.getConnection());
398
            return type;
399
        } catch(Throwable t){
400
            LOGGER.warn("Can't get current feature type from database of table = "+Objects.toString(this.table), t);
401
            return this.featureTypeSource;
402
        }
403
    }
404

    
405
    public List<String> getUpdateTableSQLs() {
406
        FeatureType currentFeatureTypeDB = getCurrentFeatureTypeDB();
407
        Map<String, Bitmask> changes = getUpdateTableChanges(currentFeatureTypeDB);
408
        List<String> sqls = getUpdateTableSQLs(currentFeatureTypeDB, changes);
409
        return sqls;
410
    }
411
    
412
    public List<String> getUpdateTableSQLs(FeatureType currentFeatureTypeDB, Map<String, Bitmask> changes) {
413
        
414
        JDBCSQLBuilderBase sqlbuilder = createSQLBuilder();
415
        SQLBuilder.AlterTableBuilder alter_table = sqlbuilder.alter_table();
416
        alter_table.setProperty(PROP_FEATURE_TYPE, featureTypeTarget);
417
        alter_table.table()
418
                .database(this.table.getDatabase())
419
                .schema(this.table.getSchema())
420
                .name(this.table.getTable());
421

    
422
//        // Primero comprobamos si hay que eliminar la primary-key o algun indice
423
//        for (FeatureAttributeDescriptor attrOrgiginal : currentFeatureTypeDB) {
424
//            if( attrOrgiginal.isComputed() ) {
425
//                continue;
426
//            }
427
//            FeatureAttributeDescriptor attrTarget = featureTypeTarget.getAttributeDescriptor(
428
//                    attrOrgiginal.getName()
429
//            );
430
//            if (attrTarget == null) {
431
//                continue;
432
//            }
433
//            if( attrOrgiginal.isPrimaryKey() && !attrTarget.isPrimaryKey() ) {
434
//                sqlbuilder.alter_table().drop_primary_key(attrTarget.getName());
435
//            }
436
//        }
437

    
438
        // Comprobamos si hay que eliminar o modificar alguna columna existente
439
        for (FeatureAttributeDescriptor attrOriginal : currentFeatureTypeDB) {
440
            if( attrOriginal.isComputed() ) {
441
                continue;
442
            }
443
            FeatureAttributeDescriptor attrTarget = featureTypeTarget.getAttributeDescriptor(
444
                    attrOriginal.getName()
445
            );
446
            if (attrTarget == null) {
447
                sqlbuilder.alter_table().drop_column(attrOriginal.getName());
448
            } else {
449
                Bitmask changesAttr = changes.get(attrOriginal.getName());
450
                if( !changesAttr.isEmpty() ) {
451
                    if( attrTarget.getType()==DataTypes.GEOMETRY ) {
452
                        sqlbuilder.alter_table().alter_geometry_column(
453
                                changesAttr,
454
                                attrTarget.getName(),
455
                                attrTarget.getGeomType().getType(),
456
                                attrTarget.getGeomType().getSubType(),
457
                                attrTarget.getSRS(),
458
                                attrTarget.isIndexed(),
459
                                attrTarget.allowNull()
460
                        );
461
                    } else {
462
                        Object defaultValue = attrTarget.getDefaultValue();
463
                        if( defaultValue instanceof CharSequence ) {
464
                            if( ExpressionUtils.isDynamicText(defaultValue.toString())) {
465
                                defaultValue = null;
466
                            }
467
                        }
468
                        sqlbuilder.alter_table().alter_column(    
469
                                changesAttr,
470
                                attrTarget.getName(),
471
                                attrTarget.getType(),
472
                                attrTarget.getSize(),
473
                                attrTarget.getPrecision(),
474
                                attrTarget.getScale(),
475
                                attrTarget.isPrimaryKey(),
476
                                attrTarget.isIndexed(),
477
                                attrTarget.allowNull(),
478
                                attrTarget.isAutomatic(),
479
                                defaultValue,
480
                                attrTarget.allowIndexDuplicateds()
481
                        );
482
                    }
483
                }
484
            }
485
        }
486
        
487
        // Por ultimo comprobamos si hay que anadir alguna columna nueva.
488
        for (FeatureAttributeDescriptor attrTarget : featureTypeTarget) {
489
            if( attrTarget.isComputed() ) {
490
                continue;
491
            }
492
            FeatureAttributeDescriptor attrOriginal = currentFeatureTypeDB.getAttributeDescriptor(
493
                    attrTarget.getName()
494
            );
495
            if (attrOriginal == null) {
496
                if( attrTarget.getType()==DataTypes.GEOMETRY ) {
497
                    sqlbuilder.alter_table().add_geometry_column(
498
                            attrTarget.getName(),
499
                            attrTarget.getGeomType().getType(),
500
                            attrTarget.getGeomType().getSubType(),
501
                            attrTarget.getSRS(),
502
                            attrTarget.isIndexed(),
503
                            attrTarget.allowNull()
504
                    );
505
                } else {
506
                    Object defaultValue = attrTarget.getDefaultValue();
507
                    if( defaultValue instanceof CharSequence ) {
508
                        if( ExpressionUtils.isDynamicText(defaultValue.toString())) {
509
                            defaultValue = null;
510
                        }
511
                    }
512
                    sqlbuilder.alter_table().add_column(
513
                            attrTarget.getName(),
514
                            attrTarget.getType(),
515
                            attrTarget.getSize(),
516
                            attrTarget.getPrecision(),
517
                            attrTarget.getScale(),
518
                            attrTarget.isPrimaryKey(),
519
                            attrTarget.isIndexed(),
520
                            attrTarget.allowNull(),
521
                            attrTarget.isAutomatic(),
522
                            defaultValue,
523
                            attrTarget.allowIndexDuplicateds()
524
                    );
525
                }
526
            }
527
        }
528
        
529
        sqlbuilder.setProperties(
530
                Variable.class, 
531
                PROP_TABLE, table
532
        );
533
        List<String> sqls = sqlbuilder.alter_table().toStrings();
534
//        sqls.addAll(buildCreateIndexSQL());
535
        return sqls;
536
    }
537
    
538
    public Map<String, Bitmask> getUpdateTableChanges(FeatureType currentFeatureTypeDB) {
539
        Map<String, Bitmask> changes = new HashMap<>();
540
        // Comprobamos si hay que eliminar o modificar alguna columna existente
541
        for (FeatureAttributeDescriptor attrOriginal : currentFeatureTypeDB) {
542
            if( attrOriginal.isComputed() ) {
543
                continue;
544
            }
545
            FeatureAttributeDescriptor attrTarget = featureTypeTarget.getAttributeDescriptor(
546
                    attrOriginal.getName()
547
            );
548
            if (attrTarget == null) {
549
                Bitmask changesAttr = Bitmask.createBitmask(0);
550
                changesAttr.setBit(SQLBuilder.AlterTableBuilder.ALTER_COLUMN_DROP_COLUMN);
551
                changes.put(attrOriginal.getName(), changesAttr);
552
            } else {
553
                Bitmask changesAttr = this.getAlterTableChanges(attrOriginal, attrTarget);
554
                changes.put(attrOriginal.getName(), changesAttr);
555
            }
556
        }
557
        
558
        // Por ultimo comprobamos si hay que anadir alguna columna nueva.
559
        for (FeatureAttributeDescriptor attrTarget : featureTypeTarget) {
560
            if( attrTarget.isComputed() ) {
561
                continue;
562
            }
563
            FeatureAttributeDescriptor attrOriginal = currentFeatureTypeDB.getAttributeDescriptor(
564
                    attrTarget.getName()
565
            );
566
            if (attrOriginal == null) {
567
                Bitmask changesAttr = Bitmask.createBitmask(0);
568
                changesAttr.setBit(SQLBuilder.AlterTableBuilder.ALTER_COLUMN_ADD_COLUMN);
569
                changes.put(attrTarget.getName(), changesAttr);
570
            }
571
        }
572
        return changes;
573
    }
574
    
575
    protected Bitmask getAlterTableChanges(FeatureAttributeDescriptor src, FeatureAttributeDescriptor target) {
576
        Bitmask changes = Bitmask.createBitmask(0);
577
        
578
        if( src.getType() != target.getType() ) {
579
            changes.setBit(SQLBuilder.AlterTableBuilder.ALTER_COLUMN_SET_DATA_TYPE);
580
        }
581
        if( src.getPrecision() != target.getPrecision() ) {
582
            changes.setBit(SQLBuilder.AlterTableBuilder.ALTER_COLUMN_SET_DATA_TYPE);
583
        }
584
        if( src.getScale() != target.getScale() ) {
585
            changes.setBit(SQLBuilder.AlterTableBuilder.ALTER_COLUMN_SET_DATA_TYPE);
586
        }
587
        if( src.getSize() != target.getSize() ) {
588
            changes.setBit(SQLBuilder.AlterTableBuilder.ALTER_COLUMN_SET_DATA_TYPE);
589
        }
590
        if( src.isPrimaryKey() != target.isPrimaryKey() ) {
591
            if( target.isPrimaryKey() ) {
592
                changes.setBit(SQLBuilder.AlterTableBuilder.ALTER_COLUMN_ADD_PRIMARY_KEY);
593
            } else {
594
                changes.setBit(SQLBuilder.AlterTableBuilder.ALTER_COLUMN_DROP_PRIMARY_KEY);
595
            }
596
        }        
597
        if( src.isIndexed()!= target.isIndexed()) {
598
            if( target.isIndexed()) {
599
                changes.setBit(SQLBuilder.AlterTableBuilder.ALTER_COLUMN_CREATE_INDEX);
600
            } else {
601
                changes.setBit(SQLBuilder.AlterTableBuilder.ALTER_COLUMN_DROP_INDEX);
602
            }
603
        }        
604
        if( src.isAutomatic() != target.isAutomatic() ) {
605
            changes.setBit(SQLBuilder.AlterTableBuilder.ALTER_COLUMN_SET_DATA_TYPE);
606
        }
607
        if( src.allowNull() != target.allowNull() ) {
608
            changes.setBit(SQLBuilder.AlterTableBuilder.ALTER_COLUMN_SET_NULL);
609
        }
610
        if( src.getDefaultValue() != target.getDefaultValue() ) {
611
            changes.setBit(SQLBuilder.AlterTableBuilder.ALTER_COLUMN_SET_DEFAULT);
612
        }
613
        return changes;
614
    }
615

    
616
//    protected List<String> buildCreateIndexSQL() {
617
//        ArrayList<String> sqls = new ArrayList<>();
618
//        
619
//        for (FeatureAttributeDescriptor attrTarget : featureTypeTarget) {
620
//            boolean createIndex;
621
//            boolean dropIndex;
622
//            FeatureAttributeDescriptor attrOriginal = featureTypeSource.getAttributeDescriptor(attrTarget.getName());
623
//            if( attrOriginal != null ) {
624
//                 createIndex = (attrTarget.isIndexed() && !attrOriginal.isIndexed());
625
//                 dropIndex = (!attrTarget.isIndexed() && attrOriginal.isIndexed());
626
//            } else {
627
//                createIndex = attrTarget.isIndexed();
628
//                dropIndex = false;
629
//            }
630
//            if( createIndex ) {
631
//                JDBCSQLBuilderBase sqlbuilder = createSQLBuilder();
632
//                if( attrTarget.getType()==DataTypes.GEOMETRY ) {
633
//                    sqlbuilder.create_index().spatial();
634
//                }
635
//                sqlbuilder.create_index().if_not_exist();
636
//                sqlbuilder.create_index().name(table.getTable(), attrTarget.getName());
637
//                sqlbuilder.create_index().column(attrTarget.getName());
638
//                sqlbuilder.create_index().table()
639
//                    .database(this.table.getDatabase())
640
//                    .schema(this.table.getSchema())
641
//                    .name(this.table.getTable());
642
//                sqlbuilder.setProperties(
643
//                        Variable.class, 
644
//                        PROP_TABLE, table
645
//                );
646
//                sqls.addAll(sqlbuilder.create_index().toStrings());
647
//            } else if( dropIndex ) {
648
//                JDBCSQLBuilderBase sqlbuilder = createSQLBuilder();
649
//                sqlbuilder.drop_index().if_not_exist();
650
//                sqlbuilder.drop_index().name( table.getTable(), attrTarget.getName());
651
//            }
652
//        }
653
//        return sqls;
654
//    }
655
    
656
    public void performUpdateTable(JDBCConnection conn) throws DataException {
657
        
658
        List<String> sqls = this.getUpdateTableSQLs();
659

    
660
        if( !CollectionUtils.isEmpty(sqls) ) {
661
            Statement st = null;
662
            String currentsql = null;
663
            try {
664
                st = conn.createStatement();
665
                for (String sql : sqls) {
666
                    currentsql = sql;
667
                    if( !StringUtils.isBlank(sql) ) {
668
                        JDBCUtils.execute(st, sql);
669
                    }
670
                }
671
            } catch (SQLException e) {
672
                throw new JDBCSQLException(e,currentsql);
673
            } finally {
674
                JDBCUtils.closeQuietly(st);
675
            }
676
        }
677
    }
678
}