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 / jdbc / JDBCHelper.java @ 45154

History | View | Annotate | Download (38.4 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 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.jdbc;
25

    
26
import java.sql.Connection;
27
import java.sql.DatabaseMetaData;
28
import java.sql.PreparedStatement;
29
import java.sql.ResultSet;
30
import java.sql.ResultSetMetaData;
31
import java.sql.SQLException;
32
import java.sql.Statement;
33
import java.util.ArrayList;
34
import java.util.Arrays;
35
import java.util.Date;
36
import java.util.List;
37
import java.util.Objects;
38
import java.util.logging.Level;
39
import org.apache.commons.lang3.StringUtils;
40

    
41
import org.cresques.cts.IProjection;
42
import org.gvsig.fmap.dal.DALLocator;
43
import org.gvsig.fmap.dal.DataTypes;
44
import org.gvsig.fmap.dal.NewDataStoreParameters;
45
import org.gvsig.fmap.dal.exception.CloseException;
46
import org.gvsig.fmap.dal.exception.DataException;
47
import org.gvsig.fmap.dal.exception.InitializeException;
48
import org.gvsig.fmap.dal.exception.OpenException;
49
import org.gvsig.fmap.dal.exception.ReadException;
50
import org.gvsig.fmap.dal.exception.WriteException;
51
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
52
import org.gvsig.fmap.dal.feature.EditableFeatureType;
53
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
54
import org.gvsig.fmap.dal.feature.FeatureType;
55
import org.gvsig.fmap.dal.feature.exception.UnsupportedDataTypeException;
56
import org.gvsig.fmap.dal.resource.ResourceAction;
57
import org.gvsig.fmap.dal.resource.exception.AccessResourceException;
58
import org.gvsig.fmap.dal.resource.exception.ResourceExecuteException;
59
import org.gvsig.fmap.dal.resource.spi.ResourceConsumer;
60
import org.gvsig.fmap.dal.resource.spi.ResourceManagerProviderServices;
61
import org.gvsig.fmap.dal.resource.spi.ResourceProvider;
62
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCException;
63
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCExecuteSQLException;
64
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCSQLException;
65
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCTransactionCommitException;
66
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCTransactionRollbackException;
67
import org.gvsig.fmap.geom.Geometry;
68
import org.gvsig.fmap.geom.GeometryLocator;
69
import org.gvsig.fmap.geom.GeometryManager;
70
import org.gvsig.fmap.geom.aggregate.MultiPrimitive;
71
import org.gvsig.fmap.geom.exception.CreateGeometryException;
72
/*
73
import org.gvsig.fmap.geom.operation.fromwkb.FromWKB;
74
import org.gvsig.fmap.geom.operation.fromwkb.FromWKBGeometryOperationContext;
75
import org.gvsig.fmap.geom.operation.towkb.ToWKB;
76
import org.gvsig.fmap.geom.operation.towkb.ToWKBOperationContext;
77
*/
78
import org.gvsig.fmap.geom.primitive.Envelope;
79
import org.gvsig.fmap.geom.primitive.Primitive;
80
import org.gvsig.fmap.geom.type.GeometryType;
81
import org.gvsig.tools.dispose.impl.AbstractDisposable;
82
import org.gvsig.tools.exception.BaseException;
83
import org.slf4j.Logger;
84
import org.slf4j.LoggerFactory;
85

    
86
/**
87
 * @author jmvivo
88
 *
89
 */
90
public class JDBCHelper extends AbstractDisposable implements ResourceConsumer {
91

    
92
        private static Logger logger = LoggerFactory.getLogger(JDBCHelper.class);
93

    
94
        protected JDBCHelperUser user;
95
        protected boolean isOpen;
96
        protected String name;
97
        protected String defaultSchema;
98
        protected JDBCConnectionParameters params;
99
        private JDBCResource resource;
100

    
101
        protected GeometryManager geomManager = null;
102

    
103
        private Boolean allowAutomaticValues = null;
104
        private Boolean supportsUnions = null;
105

    
106
        private String identifierQuoteString;
107

    
108
        protected JDBCHelper(JDBCHelperUser consumer,
109
                        JDBCConnectionParameters params) throws InitializeException {
110
                this.geomManager = GeometryLocator.getGeometryManager();
111
                this.user = consumer;
112
                this.name = user.getProviderName();
113
                this.params = params;
114
                initializeResource();
115

    
116
        }
117

    
118
        public static ResultSet executeQuery(Statement st, String sql) throws SQLException {
119
            logger.debug("execute SQL: "+sql);
120
            ResultSet rs = st.executeQuery(sql);
121
            return rs;
122
        }
123
        
124
        public static void execute(Statement st, String sql) throws SQLException {
125
            logger.debug("execute SQL: "+sql);
126
            st.execute(sql);
127
        }
128
        
129
        public static ResultSet executeQuery(PreparedStatement st, String sql) throws SQLException {
130
            logger.debug("execute SQL: "+sql);
131
            ResultSet rs = st.executeQuery();
132
            return rs;
133
        }
134

    
135
        public static void execute(PreparedStatement st, String sql) throws SQLException {
136
            logger.debug("execute SQL: "+sql);
137
            st.execute();
138
        }
139
        
140
        public static int executeUpdate(PreparedStatement st) throws SQLException {
141
            return st.executeUpdate();
142
        }
143
        
144
        public void closeConnection(Connection connection) {
145
            this.getResource().closeConnection(connection);
146
        }
147
        
148
        public void execute(String sql) throws JDBCExecuteSQLException {
149
            try {
150
                Connection conn = this.getConnection();
151
                Statement st = conn.createStatement();
152
                JDBCHelper.execute(st, sql);            
153
                this.closeConnection(conn);
154
            } catch (Exception ex) {
155
               throw new JDBCExecuteSQLException(sql, ex);
156
            }
157
        }
158
        
159
        protected void initializeResource() throws InitializeException {
160
                ResourceManagerProviderServices manager = (ResourceManagerProviderServices) DALLocator
161
                                .getResourceManager();
162
                JDBCResource resource = (JDBCResource) manager
163
                                .createAddResource(
164
                                JDBCResource.NAME, new Object[] { params.getUrl(),
165
                                                params.getHost(), params.getPort(), params.getDBName(),
166
                                                params.getUser(), params.getPassword(),
167
                                                params.getJDBCDriverClassName() });
168
                this.setResource(resource);
169

    
170
        }
171

    
172
        protected final void setResource(JDBCResource resource) {
173
                this.resource = resource;
174
                this.resource.addConsumer(this);
175
        }
176

    
177
        public boolean closeResourceRequested(ResourceProvider resource) {
178
                return user.closeResourceRequested(resource);
179
        }
180

    
181
        public void resourceChanged(ResourceProvider resource) {
182
                user.resourceChanged(resource);
183

    
184
        }
185

    
186
        /**
187
         * open the resource
188
         *
189
         * @return true if the resourse was open in this call
190
         * @throws OpenException
191
         */
192
        public boolean open() throws OpenException {
193
                if (isOpen) {
194
                        return false;
195
                }
196
                // try {
197
                // begin();
198
                // } catch (ResourceExecuteException e1) {
199
                // throw new OpenException(name, e1);
200
                // }
201
                try {
202
                        getResource().execute(new ResourceAction() {
203
                                public Object run() throws Exception {
204
                                        getResource().connect();
205
                                        getResource().notifyOpen();
206

    
207
                                        user.opendDone();
208

    
209
                                        isOpen = true;
210
                                        return null;
211
                                }
212
                                public String toString() {
213
                                    return "open";
214
                                }
215
                        });
216
                        return true;
217
                } catch (ResourceExecuteException e) {
218
                        throw new OpenException(name, e);
219
                        // } finally {
220
                        // end();
221
                }
222

    
223
        }
224

    
225
        public JDBCResource getResource() {
226
                return resource;
227
        }
228

    
229
        public void close() throws CloseException {
230
                if (!isOpen) {
231
                        return;
232
                }
233
                // try {
234
                // begin();
235
                // } catch (ResourceExecuteException e) {
236
                // throw new CloseException(name, e);
237
                // }
238
                try {
239
                        getResource().execute(new ResourceAction() {
240
                                public Object run() throws Exception {
241
                                        isOpen = false;
242

    
243
                                        resource.notifyClose();
244
                                        user.closeDone();
245
                                        return null;
246
                                }
247
                        });
248
                } catch (ResourceExecuteException e) {
249
                        throw new CloseException(this.name, e);
250
                        // } finally {
251
                        // end();
252
                }
253
        }
254

    
255
        // public void end() {
256
        // resource.end();
257
        // }
258
        //
259
        // public void begin() throws ResourceExecuteException {
260
        // this.resource.begin();
261
        // }
262

    
263
        public Connection getConnection() throws AccessResourceException {
264
                return resource.getJDBCConnection();
265

    
266
        }
267

    
268
        @Override
269
        protected void doDispose() throws BaseException {
270
                this.close();
271
                resource.removeConsumer(this);
272
        }
273

    
274
        public boolean isOpen() {
275
                return isOpen;
276
        }
277

    
278
        /**
279
         * Executes an atomic action that uses an DB Connection.<br>
280
         *
281
         * This methos prepares a connection and close it at the end of execution of
282
         * action.<br>
283
         *
284
         * if <code>action</code> is an instance of {@link TransactionalAction} the
285
         * action will be execute inside of a DB transaction.
286
         *
287
         *
288
         * @param action
289
         * @throws Exception
290
         */
291
        public Object doConnectionAction(final ConnectionAction action)
292
                        throws Exception {
293
                this.open();
294
//                this.begin();
295
                return getResource().execute(new ResourceAction() {
296
                        public Object run() throws Exception {
297
                                Object result = null;
298
                                Connection conn = null;
299
                                boolean beginTrans = false;
300
                                try {
301
                                        conn = getConnection();
302
                                        if (action instanceof TransactionalAction) {
303
                                                // XXX OJO esta condicion NO ES FIABLE
304
                                                if (!conn.getAutoCommit()) {
305
                                                        if (!((TransactionalAction) action)
306
                                                                        .continueTransactionAllowed()) {
307
                                                                // FIXME exception
308
                                                                throw new Exception();
309
                                                        }
310
                                                }
311
                                                try {
312
                                                        conn.setAutoCommit(false);
313
                                                } catch (SQLException e) {
314
                                                        throw new JDBCSQLException(e);
315
                                                }
316
                                                beginTrans = true;
317
                                        }
318

    
319
                                        result = action.action(conn);
320

    
321
                                        if (beginTrans) {
322
                                                try {
323
                                                        conn.commit();
324
                                                } catch (SQLException e) {
325
                                                        throw new JDBCTransactionCommitException(e);
326
                                                }
327
                                        }
328

    
329
                                        return result;
330

    
331
                                } catch (Exception e) {
332

    
333
                                        if (beginTrans) {
334
                                                try {
335
                                                        conn.rollback();
336
                                                } catch (Exception e1) {
337
                                                        throw new JDBCTransactionRollbackException(e1, e);
338
                                                }
339
                                        }
340
                                        throw e;
341

    
342
                                } finally {
343
                                    closeConnection(conn);
344
                                }
345
                        }
346
                });
347

    
348
        }
349

    
350
        protected String getDefaultSchema(Connection conn) throws JDBCException {
351
                return defaultSchema;
352
        }
353

    
354
        protected EditableFeatureAttributeDescriptor createAttributeFromJDBC(
355
                        EditableFeatureType fType, Connection conn,
356
                        ResultSetMetaData rsMetadata, int colIndex)
357
        throws java.sql.SQLException {
358

    
359
                EditableFeatureAttributeDescriptor column;
360
                switch (rsMetadata.getColumnType(colIndex)) {
361
                case java.sql.Types.INTEGER:
362
                        column = fType.add(rsMetadata.getColumnName(colIndex),
363
                                        DataTypes.INT);
364
                        break;
365
                case java.sql.Types.BIGINT:
366
                        column = fType.add(rsMetadata.getColumnName(colIndex),
367
                                        DataTypes.LONG);
368
                        break;
369
                case java.sql.Types.REAL:
370
                        column = fType.add(rsMetadata.getColumnName(colIndex),
371
                                        DataTypes.DOUBLE);
372
                        break;
373
                case java.sql.Types.DOUBLE:
374
                        column = fType.add(rsMetadata.getColumnName(colIndex),
375
                                        DataTypes.DOUBLE);
376
                        break;
377
                case java.sql.Types.CHAR:
378
                        column = fType.add(rsMetadata.getColumnName(colIndex),
379
                                        DataTypes.STRING);
380
                        break;
381
                case java.sql.Types.VARCHAR:
382
                case java.sql.Types.LONGVARCHAR:
383
                        column = fType.add(rsMetadata.getColumnName(colIndex),
384
                                        DataTypes.STRING);
385
                        break;
386
                case java.sql.Types.FLOAT:
387
                        column = fType.add(rsMetadata.getColumnName(colIndex),
388
                                        DataTypes.DOUBLE);
389
                        break;
390
        case java.sql.Types.NUMERIC:
391
            column = fType.add(rsMetadata.getColumnName(colIndex),
392
                    DataTypes.DOUBLE);
393
            break;
394
                case java.sql.Types.DECIMAL:
395
                        column = fType.add(rsMetadata.getColumnName(colIndex),
396
                                        DataTypes.FLOAT);
397
                        break;
398
                case java.sql.Types.DATE:
399
                        column = fType.add(rsMetadata.getColumnName(colIndex),
400
                                        DataTypes.DATE);
401
                        break;
402
                case java.sql.Types.TIME:
403
                        column = fType.add(rsMetadata.getColumnName(colIndex),
404
                                        DataTypes.TIME);
405
                        break;
406
                case java.sql.Types.TIMESTAMP:
407
                        column = fType.add(rsMetadata.getColumnName(colIndex),
408
                                        DataTypes.TIMESTAMP);
409
                        break;
410
                case java.sql.Types.BOOLEAN:
411
                case java.sql.Types.BIT:
412
                        column = fType.add(rsMetadata.getColumnName(colIndex),
413
                                        DataTypes.BOOLEAN);
414
                        break;
415
                case java.sql.Types.BLOB:
416
                case java.sql.Types.BINARY:
417
                case java.sql.Types.LONGVARBINARY:
418
                        column = fType.add(rsMetadata.getColumnName(colIndex),
419
                                        DataTypes.BYTEARRAY);
420
                        break;
421

    
422
                default:
423
                    column = createAttributeFromJDBCNativeType(fType, rsMetadata, colIndex);
424
                        break;
425
                }
426

    
427
                return column;
428

    
429
        }
430
        
431
        
432
        protected EditableFeatureAttributeDescriptor createAttributeFromJDBCNativeType(
433
        EditableFeatureType fType, ResultSetMetaData rsMetadata, int colIndex)
434
        throws SQLException {
435
        EditableFeatureAttributeDescriptor column;
436
        column = fType.add(rsMetadata.getColumnName(colIndex),
437
                DataTypes.OBJECT);
438
        column.setAdditionalInfo("SQLType", Objects.toString(rsMetadata.getColumnType(colIndex),""));
439
        column.setAdditionalInfo("SQLTypeName", rsMetadata.getColumnTypeName(colIndex));
440
        return column;
441
    }
442
        
443

    
444
        protected EditableFeatureAttributeDescriptor getAttributeFromJDBC(
445
                        EditableFeatureType fType, Connection conn,
446
                        ResultSetMetaData rsMetadata, int colIndex) throws JDBCException {
447
                EditableFeatureAttributeDescriptor column;
448
                try {
449

    
450
                        column = createAttributeFromJDBC(fType, conn, rsMetadata, colIndex);
451
                        // column.setCaseSensitive(rsMetadata.isCaseSensitive(colIndex));
452
                        // column.setSqlType(rsMetadata.getColumnType(colIndex));
453
                        column.setAllowNull(
454
                                        rsMetadata.isNullable(colIndex) == ResultSetMetaData.columnNullable);
455
                        column.setIsAutomatic(rsMetadata.isAutoIncrement(colIndex));
456
                        column.setIsReadOnly(rsMetadata.isReadOnly(colIndex));
457
                        // column.setWritable(rsMetadata.isWritable(colIndex));
458
                        // column.setClassName(rsMetadata.getColumnClassName(colIndex));
459
                        // column.setCatalogName(rsMetadata.getCatalogName(colIndex));
460
                        // column.setDefinitelyWritable(rsMetadata
461
                        // .isDefinitelyWritable(colIndex));
462
                        // column.setLabel(rsMetadata.getColumnLabel(colIndex));
463
                        // column.setSchemaName(rsMetadata.getSchemaName(colIndex));
464
                        // column.setTableName(rsMetadata.getTableName(colIndex));
465
                        // column.setCatalogName(rsMetadata.getCatalogName(colIndex));
466
                        // column.setSqlTypeName();
467
                        // column.setSearchable(rsMetadata.isSearchable(colIndex));
468
                        // column.setSigned(rsMetadata.isSigned(colIndex));
469
                        // column.setCurrency(rsMetadata.isCurrency(colIndex));
470
                        column.setPrecision(rsMetadata.getPrecision(colIndex));
471
                        column.setScale(rsMetadata.getScale(colIndex));
472
                        column.setSize(rsMetadata.getColumnDisplaySize(colIndex));
473

    
474
                } catch (java.sql.SQLException e) {
475
                        throw new JDBCSQLException(e);
476
                }
477

    
478
                return column;
479

    
480
        }
481

    
482
        /**
483
         * Fill <code>featureType</code> geometry attributes with SRS and ShapeType
484
         * information
485
         *
486
         * <b>Override this if provider has native eometry support</b>
487
         *
488
         * @param conn
489
         * @param rsMetadata
490
         * @param featureType
491
         * @throws ReadException
492
         */
493
        protected void loadSRS_and_shapeType(Connection conn,
494
                        ResultSetMetaData rsMetadata, EditableFeatureType featureType,
495
                        String baseSchema, String baseTable) throws JDBCException {
496

    
497
                // Nothing to do
498

    
499
        }
500

    
501
        public void loadFeatureType(EditableFeatureType featureType,
502
                        JDBCStoreParameters storeParams) throws DataException {
503
                if (storeParams.getSQL() != null
504
                                && storeParams.getSQL().trim().length() > 0) {
505
                        loadFeatureType(featureType, storeParams, storeParams.getSQL(),
506
                                        null, null);
507
                } else {
508
                        String sql = "Select * from " + storeParams.tableID()
509
                                        + " where false";
510
                        loadFeatureType(featureType, storeParams, sql, storeParams
511
                                        .getSchema(), storeParams.getTable());
512
                }
513
        }
514

    
515
        public void loadFeatureType(final EditableFeatureType featureType,
516
                        final JDBCStoreParameters storeParams, final String sql,
517
                        final String schema, final String table) throws DataException {
518
                this.open();
519
//                this.begin();
520
                getResource().execute(new ResourceAction() {
521
                        public Object run() throws Exception {
522
                                Connection conn = null;
523
                                try {
524
                                        conn = getConnection();
525
                                        
526
                                        String[] pks = storeParams.getPkFields();
527
                                        if (pks == null || pks.length < 1) {
528
                                                if (storeParams.getTable() != null
529
                                                                && storeParams.getTable().trim().length() > 0) {
530
                                                        pks = getPksFrom(conn, storeParams);
531
                                                        
532
                                                }
533
                                        }
534
                                        
535
                                        loadFeatureType(conn, featureType, sql, pks, storeParams
536
                                                        .getDefaultGeometryField(), schema, table);
537
                                        if (storeParams.getCRS()!=null && ((EditableFeatureAttributeDescriptor)featureType.getDefaultGeometryAttribute()) != null){
538
                                                ((EditableFeatureAttributeDescriptor)featureType.getDefaultGeometryAttribute()).setSRS(storeParams.getCRS());
539
                                        }
540
                                        
541
                                } finally {
542
                                        try {
543
                                                conn.close();
544
                                        } catch (Exception e) {
545
                                        }
546
//                        this.end();
547
                                }
548
                                return null;
549
                        }
550
                });
551
        }
552

    
553
        protected String[] getPksFrom(Connection conn, JDBCStoreParameters params)
554
                throws JDBCException {
555
                try{
556
                        DatabaseMetaData metadata = conn.getMetaData();
557
                        ResultSet rsPrimaryKeys = null;
558
                        ResultSet rs = null;
559
                        String catalog = params.getCatalog();
560
                        String schema = params.getSchema();
561

    
562
                        try{
563
                                rs = metadata.getTables(catalog,
564
                                                schema, params.getTable(), null);
565

    
566
                                if (!rs.next()) {
567
                                        // No tables found with default values, ignoring catalog
568
                                        rs.close();
569
                                        catalog = null;
570
                                        schema = null;
571
                                        rs = metadata
572
                                                        .getTables(catalog, schema, params.getTable(), null);
573

    
574
                                        if (!rs.next()) {
575
                                                // table not found
576
                                                return null;
577
                                        } else if (rs.next()){
578
                                                // More that one, cant identify
579
                                                return null;
580
                                        }
581

    
582
                                } else if (rs.next()) {
583
                                        // More that one, cant identify
584
                                        return null;
585
                                }
586
                                rsPrimaryKeys = metadata.getPrimaryKeys(catalog, schema, params
587
                                                .getTable());
588
                                List pks = new ArrayList();
589
                                while (rsPrimaryKeys.next()){
590
                                        pks.add(rsPrimaryKeys.getString("COLUMN_NAME"));
591
                                }
592
                                return (String[]) pks.toArray(new String[pks.size()]);
593

    
594

    
595
                        } finally {
596
                                try{if (rs != null) {
597
                                        rs.close();
598
                                }} catch (SQLException ex) {logger.warn("Exception closing tables rs", ex);};
599
                                try{if (rsPrimaryKeys != null) {
600
                                        rsPrimaryKeys.close();
601
                                }} catch (SQLException ex) {logger.warn("Exception closing pk rs", ex);};
602
                        }
603

    
604

    
605
                } catch (SQLException e) {
606
                        logger.warn("Unable to get pk from DatabaseMetada", e);
607
                        return getPksFromInformationSchema(conn, params);
608
                }
609

    
610
        }
611

    
612
        protected String[] getPksFromInformationSchema(Connection conn,
613
                        JDBCStoreParameters params)
614
                        throws JDBCException {
615
                Statement st;
616
                StringBuffer sql = new StringBuffer();
617
                ResultSet rs;
618
                ArrayList list = new ArrayList();
619

    
620
                /*
621
                 select column_name as primary_key
622
                        from information_schema.table_constraints t_cons
623
                                inner join information_schema.key_column_usage c on
624
                                        c.constraint_catalog = t_cons.table_catalog and
625
                                    c.table_schema = t_cons.table_schema and
626
                                    c.table_name = t_cons.table_name and
627
                                        c.constraint_name = t_cons.constraint_name
628
                                where t_cons.table_schema = <schema>
629
                                and t_cons.constraint_catalog = <catalog>
630
                                 and t_cons.table_name = <table>
631
                                 and constraint_type = 'PRIMARY KEY'
632
                 */
633
                /*
634
                 * SELECT column_name FROM INFORMATION_SCHEMA.constraint_column_usage
635
                 * left join INFORMATION_SCHEMA.table_constraints on
636
                 * (INFORMATION_SCHEMA.table_constraints.constraint_name =
637
                 * INFORMATION_SCHEMA.constraint_column_usage.constraint_name and
638
                 * INFORMATION_SCHEMA.table_constraints.table_name =
639
                 * INFORMATION_SCHEMA.constraint_column_usage.table_name and
640
                 * INFORMATION_SCHEMA.table_constraints.table_schema =
641
                 * INFORMATION_SCHEMA.constraint_column_usage.table_schema) WHERE
642
                 * INFORMATION_SCHEMA.constraint_column_usage.table_name like
643
                 * 'muni10000_peq' AND
644
                 * INFORMATION_SCHEMA.constraint_column_usage.table_schema like 'public'
645
                 * AND INFORMATION_SCHEMA.constraint_column_usage.table_catalog like
646
                 * 'gis' AND constraint_type='PRIMARY KEY'
647
                 */
648

    
649
                sql.append("select column_name as primary_key ");
650
                sql.append("from information_schema.table_constraints t_cons ");
651
                sql.append("inner join information_schema.key_column_usage c on ");
652
                sql.append("c.constraint_catalog = t_cons.constraint_catalog and ");
653
                sql.append("c.table_schema = t_cons.table_schema and ");
654
                sql.append("c.table_name = t_cons.table_name and ");
655
                sql.append("c.constraint_name = t_cons.constraint_name ");
656
                sql.append("WHERE t_cons.table_name like '");
657

    
658
                sql.append(params.getTable());
659
                sql.append("' ");
660
                String schema = null;
661

    
662

    
663
                if (params.getSchema() == null || params.getSchema() == "") {
664
                        schema = getDefaultSchema(conn);
665
                } else {
666
                        schema = params.getSchema();
667
                }
668
                if (schema != null) {
669
                        sql.append(" and t_cons.table_schema like '");
670
                        sql.append(schema);
671
                        sql.append("' ");
672
                }
673

    
674
                if (params.getCatalog() != null && params.getCatalog() != "") {
675
                        sql
676
                                        .append(" and t_cons.constraint_catalog like '");
677
                        sql.append(params.getCatalog());
678
                        sql.append("' ");
679
                }
680

    
681
                sql.append("' and constraint_type = 'PRIMARY KEY'");
682

    
683
                // System.out.println(sql.toString());
684
                try {
685
                        st = conn.createStatement();
686
                        try {
687
                                rs = JDBCHelper.executeQuery(st, sql.toString());
688
                        } catch (java.sql.SQLException e) {
689
                                throw new JDBCExecuteSQLException(sql.toString(), e);
690
                        }
691
                        while (rs.next()) {
692
                                list.add(rs.getString(1));
693
                        }
694
                        rs.close();
695
                        st.close();
696

    
697
                } catch (java.sql.SQLException e) {
698
                        throw new JDBCSQLException(e);
699
                }
700
                if (list.size() == 0) {
701
                        return null;
702
                }
703

    
704
                return (String[]) list.toArray(new String[0]);
705

    
706
        }
707

    
708
    protected void loadFeatureType(Connection conn,
709
            EditableFeatureType featureType, String sql, String[] pks,
710
            String defGeomName, String schema, String table)
711
            throws DataException {
712

    
713
        Statement stAux = null;
714
        ResultSet rs = null;
715
        try {
716

    
717
            stAux = conn.createStatement();
718
            stAux.setFetchSize(1);
719

    
720
            try {
721
                rs = JDBCHelper.executeQuery(stAux, sql);
722
            } catch (SQLException e) {
723
                throw new JDBCExecuteSQLException(sql, e);
724
            }
725
            ResultSetMetaData rsMetadata = rs.getMetaData();
726

    
727
            List pksList = null;
728
            if (pks != null) {
729
                pksList = Arrays.asList(pks);
730

    
731
            }
732

    
733
            int i;
734
            int geometriesColumns = 0;
735
            String lastGeometry = null;
736

    
737
            EditableFeatureAttributeDescriptor attr;
738
            boolean firstGeometryAttrFound = false;
739
            for (i = 1; i <= rsMetadata.getColumnCount(); i++) {
740
                attr = getAttributeFromJDBC(featureType, conn, rsMetadata, i);
741
                if (pksList != null && pksList.contains(attr.getName())) {
742
                    attr.setIsPrimaryKey(true);
743
                }
744
                if (attr.getType() == DataTypes.GEOMETRY) {
745
                    geometriesColumns++;
746
                    lastGeometry = attr.getName();
747
                    // Set the default geometry attribute if it is the one
748
                    // given as parameter or it is the first one, just in case.
749
                    if (!firstGeometryAttrFound
750
                            || lastGeometry.equals(defGeomName)) {
751
                        firstGeometryAttrFound = true;
752
                        featureType
753
                                .setDefaultGeometryAttributeName(lastGeometry);
754
                    }
755
                }
756

    
757
            }
758

    
759
            if (geometriesColumns > 0) {
760
                loadSRS_and_shapeType(conn, rsMetadata, featureType, schema,
761
                        table);
762
            }
763

    
764
            if (defGeomName == null && geometriesColumns == 1) {
765
                featureType.setDefaultGeometryAttributeName(lastGeometry);
766
                defGeomName = lastGeometry;
767
            }
768

    
769
        } catch (java.sql.SQLException e) {
770
            throw new JDBCSQLException(e); // FIXME exception
771
        } finally {
772
            try {
773
                rs.close();
774
            } catch (Exception e) {
775
            }
776
            try {
777
                stAux.close();
778
            } catch (Exception e) {
779
            }
780

    
781
        }
782

    
783
    }
784

    
785
        /**
786
         * Override if provider has geometry support
787
         *
788
         * @param storeParams
789
         * @param geometryAttrName
790
         * @param limit
791
         * @return
792
         * @throws DataException
793
         */
794
        public Envelope getFullEnvelopeOfField(JDBCStoreParameters storeParams,
795
                        String geometryAttrName, Envelope limit) throws DataException {
796

    
797
                // TODO
798
                return null;
799

    
800
        }
801

    
802
        public Geometry getGeometry(byte[] buffer) throws BaseException {
803
                if (buffer == null) {
804
                        return null;
805
                }
806
                return geomManager.createFrom(buffer);
807
        }
808

    
809
        public String escapeFieldName(String field) {
810
                if (field.matches("[a-z][a-z0-9_]*")) {
811
                        return field;
812
                }
813
                String quote = getIdentifierQuoteString();
814
                return quote + field + quote;
815
        }
816

    
817
        public class DalValueToJDBCException extends WriteException {
818

    
819
                /**
820
                 * 
821
                 */
822
                private static final long serialVersionUID = -3608973505723097889L;
823
                private final static String MESSAGE_FORMAT = "Can't convert value of attribute '%(attributeName)' to JDBC type. %(problem) (attribute type '%(attributeType)', value class '%(valueClass)').";
824
                private final static String MESSAGE_KEY = "_Cant_convert_value_of_attribute_XattributeNameX_to_JDBC_type_XproblemX_attribute_type_XattributeTypeX_value_class_XvalueClassX";
825

    
826
                public DalValueToJDBCException(FeatureAttributeDescriptor attributeDescriptor, Object object, Throwable cause) {
827
                    this(attributeDescriptor, object, (String)null, cause);
828
                }
829
                
830
                public DalValueToJDBCException(FeatureAttributeDescriptor attributeDescriptor, Object object, String problem, Throwable cause) {
831
                        super(MESSAGE_FORMAT, cause, MESSAGE_KEY, serialVersionUID);
832
                        if( attributeDescriptor != null ) {
833
                                setValue("attributeName",attributeDescriptor.getName());
834
                                setValue("attributeType",attributeDescriptor.getDataTypeName());
835
                        } else {
836
                                setValue("attributeName","unknown");
837
                                setValue("attributeType","unknown");
838
                        }
839
                        if( object!=null ) {
840
                                setValue("valueClass", object.getClass().getName());
841
                        } else {
842
                                setValue("valueClass", "null");
843
                        }
844
                        if( problem!=null ) {
845
                            setValue("problem","");
846
                        } else {
847
                            setValue("problem",problem);
848
                        }
849
                }
850

    
851
        }
852

    
853
    protected Geometry coerce(GeometryType type, Geometry geometry) {
854
        try {
855
            GeometryType geomType = geometry.getGeometryType();
856
            if (geomType.isTypeOf(type)) {
857
                return geometry;
858
            }
859

    
860
            if (type.isTypeOf(Geometry.TYPES.MULTISURFACE)) {
861
                if (geomType.isTypeOf(Geometry.TYPES.SURFACE)) {
862
                    MultiPrimitive geom2 = (MultiPrimitive) geomManager.create(type.getType(), geomType.getSubType());
863
                    geom2.addPrimitive((Primitive) geometry);
864
                    return geom2;
865
                }
866
            } else if (type.isTypeOf(Geometry.TYPES.MULTICURVE)) {
867
                if (geomType.isTypeOf(Geometry.TYPES.CURVE)) {
868
                    MultiPrimitive geom2 = (MultiPrimitive) geomManager.create(type.getType(), geomType.getSubType());
869
                    geom2.addPrimitive((Primitive) geometry);
870
                    return geom2;
871
                }
872
            } else if (type.isTypeOf(Geometry.TYPES.MULTIPOINT)) {
873
                if (geomType.isTypeOf(Geometry.TYPES.POINT)) {
874
                    MultiPrimitive geom2 = (MultiPrimitive) geomManager.create(type.getType(), geomType.getSubType());
875
                    geom2.addPrimitive((Primitive) geometry);
876
                    return geom2;
877
                }
878
            }
879
        } catch (CreateGeometryException ex) {
880
            // Do nothing, return the same geometry.
881
            logger.trace("Can't coerce geometry '"+geometry+"' to '"+type+"'.",ex);
882
        }
883
        return geometry;
884
    }
885
        
886
    public Object dalValueToJDBC(
887
            FeatureAttributeDescriptor attributeDescriptor, Object value)
888
            throws WriteException {
889

    
890
        try {
891
            if (value == null) {
892
                return null;
893
            }
894
            Date jdate = null;
895
            switch (attributeDescriptor.getType()) {
896
                case DataTypes.DATE:
897
                    jdate = (Date)value;
898
                    java.sql.Date sqldate = new java.sql.Date(jdate.getTime());
899
                    return sqldate;
900
                    
901
                case DataTypes.TIME:
902
                    jdate = (Date)value;
903
                    java.sql.Time sqltime = new java.sql.Time(jdate.getTime());
904
                    return sqltime;
905

    
906
                case DataTypes.GEOMETRY:
907
                    IProjection srs = null;
908
                    byte[] wkb = null;
909
                    Geometry geom = null;
910
                    try {
911
                        geom = (Geometry)value;
912
                        Geometry geom1 = coerce(attributeDescriptor.getGeomType(), geom);
913
                        srs = attributeDescriptor.getSRS();
914
                        if (srs != null) {
915
                            wkb = geom1.convertToWKBForcingType(getProviderSRID(srs), attributeDescriptor.getGeomType().getType());
916
                        } else {
917
                            wkb = geom1.convertToWKB();
918
                        }
919
                    } catch (Exception e) {
920
                        String problem = "";
921
                        if (geom != null) {
922
                            Geometry.ValidationStatus vs = geom.getValidationStatus();
923
                            problem = vs.getMessage();
924
                        }
925
                        throw new DalValueToJDBCException(attributeDescriptor, value, problem, e);
926
                    }
927
                    return wkb;
928
                
929
                default:
930
                    return value;
931
            }
932
            
933
        } catch(DalValueToJDBCException ex) {
934
            throw ex;
935
        } catch (Exception e) {
936
            throw new DalValueToJDBCException(attributeDescriptor, value, e);
937
        }
938

    
939
    }
940

    
941
        public String getSqlColumnTypeDescription(FeatureAttributeDescriptor attr) {
942
                switch (attr.getType()) {
943
                case DataTypes.STRING:
944
                        if (attr.getSize() < 1 || attr.getSize() > 255) {
945
                                return "text";
946
                        } else {
947
                                return "varchar(" + attr.getSize() + ")";
948
                        }
949
                case DataTypes.BOOLEAN:
950
                        return "bool";
951

    
952
                case DataTypes.BYTE:
953
                        return "smallint";
954

    
955
                case DataTypes.DATE:
956
                        return "date";
957

    
958
                case DataTypes.TIMESTAMP:
959
                        return "timestamp";
960

    
961
                case DataTypes.TIME:
962
                        return "time";
963

    
964
                case DataTypes.BYTEARRAY:
965
                case DataTypes.GEOMETRY:
966
                        return "blob";
967

    
968
                case DataTypes.DOUBLE:
969
//                        if (attr.getPrecision() > 0) {
970
//                            return "double precision(" + attr.getPrecision() + ')';
971
//                        } else {
972
                    //It works with PostgreSQL and MySQL. Check with others
973
                            return "double precision";
974
//                        }
975
                case DataTypes.FLOAT:
976
                        return "real";
977

    
978
                case DataTypes.INT:
979
                        if (attr.isAutomatic() && allowAutomaticValues()) {
980
                                return "serial";
981
                        } else {
982
                                return "integer";
983
                        }
984
                case DataTypes.LONG:
985
                        if (attr.isAutomatic()) {
986
                                return "bigserial";
987
                        } else {
988
                                return "bigint";
989
                        }
990

    
991
                default:
992
                        String typeName = (String) attr.getAdditionalInfo("SQLTypeName");
993
                        if (typeName != null) {
994
                                return typeName;
995
                        }
996

    
997
                        throw new UnsupportedDataTypeException(attr.getDataTypeName(), attr
998
                                        .getType());
999
                }
1000
        }
1001

    
1002
        public int getProviderSRID(String srs) {
1003
                return -1;
1004
        }
1005

    
1006
        public int getProviderSRID(IProjection srs) {
1007
                return -1;
1008
        }
1009

    
1010
        public String getSqlFieldName(FeatureAttributeDescriptor attribute) {
1011
                return escapeFieldName(attribute.getName());
1012
        }
1013

    
1014
        public String getSqlFieldDescription(FeatureAttributeDescriptor attr)
1015
                        throws DataException {
1016

    
1017
                /**
1018
                 * column_name data_type [ DEFAULT default_expr ] [ column_constraint [
1019
                 * ... ] ]
1020
                 *
1021
                 * where column_constraint is:
1022
                 *
1023
                 * [ CONSTRAINT constraint_name ] { NOT NULL | NULL | UNIQUE | PRIMARY
1024
                 * KEY | CHECK (expression) | REFERENCES reftable [ ( refcolumn ) ] [
1025
                 * MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON DELETE action ] [ ON
1026
                 * UPDATE action ] } [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY
1027
                 * DEFERRED | INITIALLY IMMEDIATE ]
1028
                 */
1029

    
1030
                StringBuilder strb = new StringBuilder();
1031
                // name
1032
                strb.append(escapeFieldName(attr.getName()));
1033
                strb.append(" ");
1034

    
1035
                // Type
1036
                strb.append(this.getSqlColumnTypeDescription(attr));
1037
                strb.append(" ");
1038

    
1039
                boolean allowNull = attr.allowNull()
1040
                                && !(attr.isPrimaryKey() || attr.isAutomatic());
1041
                // Default
1042
                if (attr.getDefaultValue() == null) {
1043
                        if (allowNull) {
1044
                                strb.append("DEFAULT NULL ");
1045
                        }
1046
                } else {
1047
                        String value = getDefaltFieldValueString(attr);
1048
                        strb.append("DEFAULT '");
1049
                        strb.append(value);
1050
                        strb.append("' ");
1051
                }
1052

    
1053
                // Null
1054
                if (allowNull) {
1055
                        strb.append("NULL ");
1056
                } else {
1057
                        strb.append("NOT NULL ");
1058
                }
1059

    
1060
                // Primery key
1061
                if (attr.isPrimaryKey()) {
1062
                        strb.append("PRIMARY KEY ");
1063
                }
1064
                return strb.toString();
1065
        }
1066

    
1067
        /**
1068
         * @deprecated use getDefaultFieldValueString this has a type writer error.
1069
         */
1070
        protected String getDefaltFieldValueString(FeatureAttributeDescriptor attr)
1071
                        throws WriteException {
1072
                return getDefaultFieldValueString(attr);
1073
        }
1074

    
1075
        protected String getDefaultFieldValueString(FeatureAttributeDescriptor attr)
1076
                        throws WriteException {
1077
                return dalValueToJDBC(attr, attr.getDefaultValue()).toString();
1078
        }
1079

    
1080
        public String compoundLimitAndOffset(long limit, long offset) {
1081
                StringBuilder sql = new StringBuilder();
1082
                // limit
1083
                if (limit > 0) {
1084
                        sql.append(" limit ");
1085
                        sql.append(limit);
1086
                        sql.append(' ');
1087
                }
1088

    
1089
                // offset
1090
                if (offset > 0) {
1091
                        sql.append(" offset ");
1092
                        sql.append(offset);
1093
                        sql.append(' ');
1094
                }
1095
                return sql.toString();
1096
        }
1097

    
1098
        public boolean supportOffset() {
1099
                return true;
1100
        }
1101

    
1102
        public List getAdditionalSqlToCreate(NewDataStoreParameters ndsp,
1103
                        FeatureType fType) {
1104
                // TODO Auto-generated method stub
1105
                return null;
1106
        }
1107

    
1108

    
1109
        public String stringJoin(List listToJoin,String sep){
1110
                StringBuilder strb = new StringBuilder();
1111
                stringJoin(listToJoin,sep,strb);
1112
                return strb.toString();
1113
        }
1114

    
1115
        public void stringJoin(List listToJoin, String sep, StringBuilder strb) {
1116
                if (listToJoin.size() < 1) {
1117
                        return;
1118
                }
1119
                if (listToJoin.size() > 1) {
1120
                        for (int i = 0; i < listToJoin.size() - 1; i++) {
1121
                                strb.append(listToJoin.get(i));
1122
                                strb.append(sep);
1123
                        }
1124
                }
1125
                strb.append(listToJoin.get(listToJoin.size() - 1));
1126
        }
1127

    
1128
        /**
1129
         * Inform that provider has supports for geometry store and operations
1130
         * natively
1131
         *
1132
         * @return
1133
         */
1134
        protected boolean supportsGeometry() {
1135
                return false;
1136
        }
1137

    
1138
        public boolean allowAutomaticValues() {
1139
                if (allowAutomaticValues == null) {
1140
                        ConnectionAction action = new ConnectionAction(){
1141

    
1142
                                public Object action(Connection conn) throws DataException {
1143

    
1144
                                        ResultSet rs;
1145
                                        try {
1146
                                                DatabaseMetaData meta = conn.getMetaData();
1147
                                                rs = meta.getTypeInfo();
1148
                                                try{
1149
                                                        while (rs.next()) {
1150
                                                                if (rs.getInt("DATA_TYPE") == java.sql.Types.INTEGER) {
1151
                                                                        if (rs.getBoolean("AUTO_INCREMENT")) {
1152
                                                                                return Boolean.TRUE;
1153
                                                                        } else {
1154
                                                                                return Boolean.FALSE;
1155
                                                                        }
1156
                                                                }
1157
                                                        }
1158
                                                }finally{
1159
                                                        try{ rs.close();} catch (SQLException ex) {logger.error("Exception closing resulset", ex);};
1160
                                                }
1161
                                        } catch (SQLException e) {
1162
                                                throw new JDBCSQLException(e);
1163
                                        }
1164
                                        return Boolean.FALSE;
1165
                                }
1166

    
1167
                        };
1168

    
1169

    
1170

    
1171
                        try {
1172
                                allowAutomaticValues = (Boolean) doConnectionAction(action);
1173
                        } catch (Exception e) {
1174
                                logger.error("Exception checking for automatic integers", e);
1175
                                allowAutomaticValues = Boolean.FALSE;
1176
                        }
1177
                }
1178
                return allowAutomaticValues.booleanValue();
1179
        }
1180

    
1181
        public boolean supportsUnion() {
1182
                if (supportsUnions == null) {
1183
                        ConnectionAction action = new ConnectionAction() {
1184

    
1185
                                public Object action(Connection conn) throws DataException {
1186

    
1187
                                        try {
1188
                                                DatabaseMetaData meta = conn.getMetaData();
1189
                                                return new Boolean(meta.supportsUnion());
1190
                                        } catch (SQLException e) {
1191
                                                throw new JDBCSQLException(e);
1192
                                        }
1193
                                }
1194

    
1195
                        };
1196

    
1197
                        try {
1198
                                supportsUnions = (Boolean) doConnectionAction(action);
1199
                        } catch (Exception e) {
1200
                                logger.error("Exception checking for unions support", e);
1201
                                supportsUnions = Boolean.FALSE;
1202
                        }
1203
                }
1204
                return supportsUnions.booleanValue();
1205
        }
1206

    
1207
        protected String getIdentifierQuoteString() {
1208
                if (identifierQuoteString == null) {
1209
                ConnectionAction action = new ConnectionAction() {
1210

    
1211
                        public Object action(Connection conn) throws DataException {
1212

    
1213
                                try {
1214
                                        DatabaseMetaData meta = conn.getMetaData();
1215
                                        return meta.getIdentifierQuoteString();
1216
                                } catch (SQLException e) {
1217
                                        throw new JDBCSQLException(e);
1218
                                }
1219
                        }
1220

    
1221
                };
1222

    
1223
                try {
1224
                        identifierQuoteString = (String) doConnectionAction(action);
1225
                } catch (Exception e) {
1226
                        logger.error("Exception checking for unions support", e);
1227
                        identifierQuoteString = " ";
1228
                        }
1229
                }
1230
                return identifierQuoteString;
1231
        }
1232

    
1233
        protected boolean isReservedWord(String field) {
1234
                // TODO
1235
                return false;
1236
        }
1237

    
1238
        protected List createGrantStatements(JDBCNewStoreParameters ndsp) {
1239
            return this.createGrantStatements(ndsp, ndsp.tableID());
1240
        }
1241
        
1242
        protected List createGrantStatements(JDBCNewStoreParameters ndsp, String table) {
1243
            String priviligeParamNames[] = new String[] {   
1244
                "SelectRole",
1245
                "InsertRole",
1246
                "UpdateRole",
1247
                "DeleteRole",
1248
                "TruncateRole",
1249
                "ReferenceRole",
1250
                "TriggerRole",
1251
                "AllRole"
1252
            };
1253
            String priviligeNames[] = new String[] {   
1254
                "SELECT",
1255
                "INSERT",
1256
                "UPDATE",
1257
                "DELETE",
1258
                "TRUNCATE",
1259
                "REFERENCE",
1260
                "TRIGGER",
1261
                "ALL"
1262
            };
1263
            List statements = new ArrayList();;
1264
            
1265
            for( int i=0; i<priviligeParamNames.length; i++ ) {
1266
                String paramName = priviligeParamNames[i];
1267
                String roles = StringUtils.defaultIfBlank(
1268
                        (String) ndsp.getDynValue(paramName), 
1269
                        null
1270
                );
1271
                if( roles!=null ) {
1272
                    statements.addAll(this.createGrantStatements(table, priviligeNames[i], roles));
1273
                }
1274
            }
1275
            return statements;
1276
        }
1277

    
1278
        protected List createGrantStatements(String tableName, String privilege, String theRoles) {
1279
            List statements = new ArrayList();
1280
            String[] roles = StringUtils.split(theRoles,",");
1281
            for( int i=0; i<roles.length; i++) {
1282
                String statement = "GRANT "+ privilege + " ON TABLE " + tableName + " TO \"" + roles[i] + "\"";
1283
                statements.add(statement);
1284
            }
1285
            return statements;
1286
        } 
1287

    
1288
}