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

History | View | Annotate | Download (28.8 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.ResultSet;
29
import java.sql.ResultSetMetaData;
30
import java.sql.SQLException;
31
import java.sql.Statement;
32
import java.util.ArrayList;
33
import java.util.Arrays;
34
import java.util.List;
35

    
36
import org.cresques.cts.IProjection;
37
import org.slf4j.Logger;
38
import org.slf4j.LoggerFactory;
39

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

    
78
/**
79
 * @author jmvivo
80
 *
81
 */
82
public class JDBCHelper extends AbstractDisposable implements ResourceConsumer {
83

    
84
        private static Logger logger = LoggerFactory.getLogger(JDBCHelper.class);
85

    
86
        protected JDBCHelperUser user;
87
        protected boolean isOpen;
88
        protected String name;
89
        protected String defaultSchema;
90
        protected JDBCConnectionParameters params;
91
        private JDBCResource resource;
92

    
93
        protected GeometryManager geomManager = null;
94

    
95
        private Boolean allowAutomaticValues = null;
96
        private Boolean supportsUnions = null;
97

    
98
        private String identifierQuoteString;
99

    
100
        protected JDBCHelper(JDBCHelperUser consumer,
101
                        JDBCConnectionParameters params) throws InitializeException {
102
                this.geomManager = GeometryLocator.getGeometryManager();
103
                this.user = consumer;
104
                this.name = user.getProviderName();
105
                this.params = params;
106
                initializeResource();
107

    
108
        }
109

    
110
        protected void initializeResource() throws InitializeException {
111
                ResourceManagerProviderServices manager = (ResourceManagerProviderServices) DALLocator
112
                                .getResourceManager();
113
                JDBCResource resource = (JDBCResource) manager
114
                                .createAddResource(
115
                                JDBCResource.NAME, new Object[] { params.getUrl(),
116
                                                params.getHost(), params.getPort(), params.getDBName(),
117
                                                params.getUser(), params.getPassword(),
118
                                                params.getJDBCDriverClassName() });
119
                this.setResource(resource);
120

    
121
        }
122

    
123
        protected final void setResource(JDBCResource resource) {
124
                this.resource = resource;
125
                this.resource.addConsumer(this);
126
        }
127

    
128
        public boolean closeResourceRequested(ResourceProvider resource) {
129
                return user.closeResourceRequested(resource);
130
        }
131

    
132
        public void resourceChanged(ResourceProvider resource) {
133
                user.resourceChanged(resource);
134

    
135
        }
136

    
137
        /**
138
         * open the resource
139
         *
140
         * @return true if the resourse was open in this call
141
         * @throws OpenException
142
         */
143
        public boolean open() throws OpenException {
144
                if (isOpen) {
145
                        return false;
146
                }
147
                // try {
148
                // begin();
149
                // } catch (ResourceExecuteException e1) {
150
                // throw new OpenException(name, e1);
151
                // }
152
                try {
153
                        getResource().execute(new ResourceAction() {
154
                                public Object run() throws Exception {
155
                                        getResource().connect();
156
                                        getResource().notifyOpen();
157

    
158
                                        user.opendDone();
159

    
160
                                        isOpen = true;
161
                                        return null;
162
                                }
163
                        });
164
                        return true;
165
                } catch (ResourceExecuteException e) {
166
                        throw new OpenException(name, e);
167
                        // } finally {
168
                        // end();
169
                }
170

    
171
        }
172

    
173
        public JDBCResource getResource() {
174
                return resource;
175
        }
176

    
177
        public void close() throws CloseException {
178
                if (!isOpen) {
179
                        return;
180
                }
181
                // try {
182
                // begin();
183
                // } catch (ResourceExecuteException e) {
184
                // throw new CloseException(name, e);
185
                // }
186
                try {
187
                        getResource().execute(new ResourceAction() {
188
                                public Object run() throws Exception {
189
                                        isOpen = false;
190

    
191
                                        resource.notifyClose();
192
                                        user.closeDone();
193
                                        return null;
194
                                }
195
                        });
196
                } catch (ResourceExecuteException e) {
197
                        throw new CloseException(this.name, e);
198
                        // } finally {
199
                        // end();
200
                }
201
        }
202

    
203
        // public void end() {
204
        // resource.end();
205
        // }
206
        //
207
        // public void begin() throws ResourceExecuteException {
208
        // this.resource.begin();
209
        // }
210

    
211
        public Connection getConnection() throws AccessResourceException {
212
                return resource.getJDBCConnection();
213

    
214
        }
215

    
216
        @Override
217
        protected void doDispose() throws BaseException {
218
                resource.removeConsumer(this);
219
        }
220

    
221
        public boolean isOpen() {
222
                return isOpen;
223
        }
224

    
225
        /**
226
         * Executes an atomic action that uses an DB Connection.<br>
227
         *
228
         * This methos prepares a connection and close it at the end of execution of
229
         * action.<br>
230
         *
231
         * if <code>action</code> is an instance of {@link TransactionalAction} the
232
         * action will be execute inside of a DB transaction.
233
         *
234
         *
235
         * @param action
236
         * @throws Exception
237
         */
238
        public Object doConnectionAction(final ConnectionAction action)
239
                        throws Exception {
240
                this.open();
241
//                this.begin();
242
                return getResource().execute(new ResourceAction() {
243
                        public Object run() throws Exception {
244
                                Object result = null;
245
                                Connection conn = null;
246
                                boolean beginTrans = false;
247
                                try {
248
                                        conn = getConnection();
249
                                        if (action instanceof TransactionalAction) {
250
                                                // XXX OJO esta condicion NO ES FIABLE
251
                                                if (!conn.getAutoCommit()) {
252
                                                        if (!((TransactionalAction) action)
253
                                                                        .continueTransactionAllowed()) {
254
                                                                // FIXME exception
255
                                                                throw new Exception();
256
                                                        }
257
                                                }
258
                                                try {
259
                                                        conn.setAutoCommit(false);
260
                                                } catch (SQLException e) {
261
                                                        throw new JDBCSQLException(e);
262
                                                }
263
                                                beginTrans = true;
264
                                        }
265

    
266
                                        result = action.action(conn);
267

    
268
                                        if (beginTrans) {
269
                                                try {
270
                                                        conn.commit();
271
                                                } catch (SQLException e) {
272
                                                        throw new JDBCTransactionCommitException(e);
273
                                                }
274
                                        }
275

    
276
                                        return result;
277

    
278
                                } catch (Exception e) {
279

    
280
                                        if (beginTrans) {
281
                                                try {
282
                                                        conn.rollback();
283
                                                } catch (Exception e1) {
284
                                                        throw new JDBCTransactionRollbackException(e1, e);
285
                                                }
286
                                        }
287
                                        throw e;
288

    
289
                                } finally {
290
                                        try {
291
                                                conn.close();
292
                                        } catch (Exception e1) {
293
                                                logger.error("Exception on close connection", e1);
294
                                        }
295
                                        // this.end();
296
                                }
297
                        }
298
                });
299

    
300
        }
301

    
302
        protected String getDefaultSchema(Connection conn) throws JDBCException {
303
                return defaultSchema;
304
        }
305

    
306
        protected EditableFeatureAttributeDescriptor createAttributeFromJDBC(
307
                        EditableFeatureType fType, Connection conn,
308
                        ResultSetMetaData rsMetadata, int colIndex)
309
        throws java.sql.SQLException {
310

    
311
                EditableFeatureAttributeDescriptor column;
312
                switch (rsMetadata.getColumnType(colIndex)) {
313
                case java.sql.Types.INTEGER:
314
                        column = fType.add(rsMetadata.getColumnName(colIndex),
315
                                        DataTypes.INT);
316
                        break;
317
                case java.sql.Types.BIGINT:
318
                        column = fType.add(rsMetadata.getColumnName(colIndex),
319
                                        DataTypes.LONG);
320
                        break;
321
                case java.sql.Types.REAL:
322
                        column = fType.add(rsMetadata.getColumnName(colIndex),
323
                                        DataTypes.DOUBLE);
324
                        break;
325
                case java.sql.Types.DOUBLE:
326
                        column = fType.add(rsMetadata.getColumnName(colIndex),
327
                                        DataTypes.DOUBLE);
328
                        break;
329
                case java.sql.Types.CHAR:
330
                        column = fType.add(rsMetadata.getColumnName(colIndex),
331
                                        DataTypes.STRING);
332
                        break;
333
                case java.sql.Types.VARCHAR:
334
                case java.sql.Types.LONGVARCHAR:
335
                        column = fType.add(rsMetadata.getColumnName(colIndex),
336
                                        DataTypes.STRING);
337
                        break;
338
                case java.sql.Types.FLOAT:
339
                        column = fType.add(rsMetadata.getColumnName(colIndex),
340
                                        DataTypes.FLOAT);
341
                        break;
342
        case java.sql.Types.NUMERIC:
343
            column = fType.add(rsMetadata.getColumnName(colIndex),
344
                    DataTypes.FLOAT);
345
            break;
346
                case java.sql.Types.DECIMAL:
347
                        column = fType.add(rsMetadata.getColumnName(colIndex),
348
                                        DataTypes.FLOAT);
349
                        break;
350
                case java.sql.Types.DATE:
351
                        column = fType.add(rsMetadata.getColumnName(colIndex),
352
                                        DataTypes.DATE);
353
                        break;
354
                case java.sql.Types.TIME:
355
                        column = fType.add(rsMetadata.getColumnName(colIndex),
356
                                        DataTypes.TIME);
357
                        break;
358
                case java.sql.Types.TIMESTAMP:
359
                        column = fType.add(rsMetadata.getColumnName(colIndex),
360
                                        DataTypes.TIMESTAMP);
361
                        break;
362
                case java.sql.Types.BOOLEAN:
363
                        column = fType.add(rsMetadata.getColumnName(colIndex),
364
                                        DataTypes.BOOLEAN);
365
                        break;
366
                case java.sql.Types.BLOB:
367
                case java.sql.Types.BINARY:
368
                case java.sql.Types.LONGVARBINARY:
369
                        column = fType.add(rsMetadata.getColumnName(colIndex),
370
                                        DataTypes.BYTEARRAY);
371
                        break;
372

    
373
                default:
374
                        column = fType.add(rsMetadata.getColumnName(colIndex),
375
                                        DataTypes.OBJECT);
376
                        column.setAdditionalInfo("SQLType", new Integer(rsMetadata
377
                                        .getColumnType(colIndex)));
378
                        column.setAdditionalInfo("SQLTypeName", rsMetadata
379
                                        .getColumnTypeName(colIndex));
380

    
381
                        break;
382
                }
383

    
384
                return column;
385

    
386
        }
387

    
388
        protected EditableFeatureAttributeDescriptor getAttributeFromJDBC(
389
                        EditableFeatureType fType, Connection conn,
390
                        ResultSetMetaData rsMetadata, int colIndex) throws JDBCException {
391
                EditableFeatureAttributeDescriptor column;
392
                try {
393

    
394
                        column = createAttributeFromJDBC(fType, conn, rsMetadata, colIndex);
395
                        // column.setCaseSensitive(rsMetadata.isCaseSensitive(colIndex));
396
                        // column.setSqlType(rsMetadata.getColumnType(colIndex));
397
                        column.setAllowNull(
398
                                        rsMetadata.isNullable(colIndex) == ResultSetMetaData.columnNullable);
399
                        column.setIsAutomatic(rsMetadata.isAutoIncrement(colIndex));
400
                        column.setIsReadOnly(rsMetadata.isReadOnly(colIndex));
401
                        // column.setWritable(rsMetadata.isWritable(colIndex));
402
                        // column.setClassName(rsMetadata.getColumnClassName(colIndex));
403
                        // column.setCatalogName(rsMetadata.getCatalogName(colIndex));
404
                        // column.setDefinitelyWritable(rsMetadata
405
                        // .isDefinitelyWritable(colIndex));
406
                        // column.setLabel(rsMetadata.getColumnLabel(colIndex));
407
                        // column.setSchemaName(rsMetadata.getSchemaName(colIndex));
408
                        // column.setTableName(rsMetadata.getTableName(colIndex));
409
                        // column.setCatalogName(rsMetadata.getCatalogName(colIndex));
410
                        // column.setSqlTypeName();
411
                        // column.setSearchable(rsMetadata.isSearchable(colIndex));
412
                        // column.setSigned(rsMetadata.isSigned(colIndex));
413
                        // column.setCurrency(rsMetadata.isCurrency(colIndex));
414
                        column.setPrecision(rsMetadata.getPrecision(colIndex));
415
                        column.setSize(rsMetadata.getColumnDisplaySize(colIndex));
416

    
417
                } catch (java.sql.SQLException e) {
418
                        throw new JDBCSQLException(e);
419
                }
420

    
421
                return column;
422

    
423
        }
424

    
425
        /**
426
         * Fill <code>featureType</code> geometry attributes with SRS and ShapeType
427
         * information
428
         *
429
         * <b>Override this if provider has native eometry support</b>
430
         *
431
         * @param conn
432
         * @param rsMetadata
433
         * @param featureType
434
         * @throws ReadException
435
         */
436
        protected void loadSRS_and_shapeType(Connection conn,
437
                        ResultSetMetaData rsMetadata, EditableFeatureType featureType,
438
                        String baseSchema, String baseTable) throws JDBCException {
439

    
440
                // Nothing to do
441

    
442
        }
443

    
444
        public void loadFeatureType(EditableFeatureType featureType,
445
                        JDBCStoreParameters storeParams) throws DataException {
446
                if (storeParams.getSQL() != null
447
                                && storeParams.getSQL().trim().length() > 0) {
448
                        loadFeatureType(featureType, storeParams, storeParams.getSQL(),
449
                                        null, null);
450
                } else {
451
                        String sql = "Select * from " + storeParams.tableID()
452
                                        + " where false";
453
                        loadFeatureType(featureType, storeParams, sql, storeParams
454
                                        .getSchema(), storeParams.getTable());
455
                }
456
        }
457

    
458
        public void loadFeatureType(final EditableFeatureType featureType,
459
                        final JDBCStoreParameters storeParams, final String sql,
460
                        final String schema, final String table) throws DataException {
461
                this.open();
462
//                this.begin();
463
                getResource().execute(new ResourceAction() {
464
                        public Object run() throws Exception {
465
                                Connection conn = null;
466
                                try {
467
                                        conn = getConnection();
468
                                        
469
                                        String[] pks = storeParams.getPkFields();
470
                                        if (pks == null || pks.length < 1) {
471
                                                if (storeParams.getTable() != null
472
                                                                && storeParams.getTable().trim().length() > 0) {
473
                                                        pks = getPksFrom(conn, storeParams);
474
                                                        
475
                                                }
476
                                        }
477
                                        
478
                                        loadFeatureType(conn, featureType, sql, pks, storeParams
479
                                                        .getDefaultGeometryField(), schema, table);
480
                                        if (storeParams.getCRS()!=null){
481
                                                ((EditableFeatureAttributeDescriptor)featureType.getDefaultGeometryAttribute()).setSRS(storeParams.getCRS());
482
                                        }
483
                                        
484
                                } finally {
485
                                        try {
486
                                                conn.close();
487
                                        } catch (Exception e) {
488
                                        }
489
//                        this.end();
490
                                }
491
                                return null;
492
                        }
493
                });
494
        }
495

    
496
        protected String[] getPksFrom(Connection conn, JDBCStoreParameters params)
497
                throws JDBCException {
498
                try{
499
                        DatabaseMetaData metadata = conn.getMetaData();
500
                        ResultSet rsPrimaryKeys = null;
501
                        ResultSet rs = null;
502
                        String catalog = params.getCatalog();
503
                        String schema = params.getSchema();
504

    
505
                        try{
506
                                rs = metadata.getTables(catalog,
507
                                                schema, params.getTable(), null);
508

    
509
                                if (!rs.next()) {
510
                                        // No tables found with default values, ignoring catalog
511
                                        rs.close();
512
                                        catalog = null;
513
                                        schema = null;
514
                                        rs = metadata
515
                                                        .getTables(catalog, schema, params.getTable(), null);
516

    
517
                                        if (!rs.next()) {
518
                                                // table not found
519
                                                return null;
520
                                        } else if (rs.next()){
521
                                                // More that one, cant identify
522
                                                return null;
523
                                        }
524

    
525
                                } else if (rs.next()) {
526
                                        // More that one, cant identify
527
                                        return null;
528
                                }
529
                                rsPrimaryKeys = metadata.getPrimaryKeys(catalog, schema, params
530
                                                .getTable());
531
                                List pks = new ArrayList();
532
                                while (rsPrimaryKeys.next()){
533
                                        pks.add(rsPrimaryKeys.getString("COLUMN_NAME"));
534
                                }
535
                                return (String[]) pks.toArray(new String[pks.size()]);
536

    
537

    
538
                        } finally {
539
                                try{if (rs != null) {
540
                                        rs.close();
541
                                }} catch (SQLException ex) {logger.warn("Exception closing tables rs", ex);};
542
                                try{if (rsPrimaryKeys != null) {
543
                                        rsPrimaryKeys.close();
544
                                }} catch (SQLException ex) {logger.warn("Exception closing pk rs", ex);};
545
                        }
546

    
547

    
548
                } catch (SQLException e) {
549
                        logger.warn("Unable to get pk from DatabaseMetada", e);
550
                        return getPksFromInformationSchema(conn, params);
551
                }
552

    
553
        }
554

    
555
        protected String[] getPksFromInformationSchema(Connection conn,
556
                        JDBCStoreParameters params)
557
                        throws JDBCException {
558
                Statement st;
559
                StringBuffer sql = new StringBuffer();
560
                ResultSet rs;
561
                ArrayList list = new ArrayList();
562

    
563
                /*
564
                 select column_name as primary_key
565
                        from information_schema.table_constraints t_cons
566
                                inner join information_schema.key_column_usage c on
567
                                        c.constraint_catalog = t_cons.table_catalog and
568
                                    c.table_schema = t_cons.table_schema and
569
                                    c.table_name = t_cons.table_name and
570
                                        c.constraint_name = t_cons.constraint_name
571
                                where t_cons.table_schema = <schema>
572
                                and t_cons.constraint_catalog = <catalog>
573
                                 and t_cons.table_name = <table>
574
                                 and constraint_type = 'PRIMARY KEY'
575
                 */
576
                /*
577
                 * SELECT column_name FROM INFORMATION_SCHEMA.constraint_column_usage
578
                 * left join INFORMATION_SCHEMA.table_constraints on
579
                 * (INFORMATION_SCHEMA.table_constraints.constraint_name =
580
                 * INFORMATION_SCHEMA.constraint_column_usage.constraint_name and
581
                 * INFORMATION_SCHEMA.table_constraints.table_name =
582
                 * INFORMATION_SCHEMA.constraint_column_usage.table_name and
583
                 * INFORMATION_SCHEMA.table_constraints.table_schema =
584
                 * INFORMATION_SCHEMA.constraint_column_usage.table_schema) WHERE
585
                 * INFORMATION_SCHEMA.constraint_column_usage.table_name like
586
                 * 'muni10000_peq' AND
587
                 * INFORMATION_SCHEMA.constraint_column_usage.table_schema like 'public'
588
                 * AND INFORMATION_SCHEMA.constraint_column_usage.table_catalog like
589
                 * 'gis' AND constraint_type='PRIMARY KEY'
590
                 */
591

    
592
                sql.append("select column_name as primary_key ");
593
                sql.append("from information_schema.table_constraints t_cons ");
594
                sql.append("inner join information_schema.key_column_usage c on ");
595
                sql.append("c.constraint_catalog = t_cons.constraint_catalog and ");
596
                sql.append("c.table_schema = t_cons.table_schema and ");
597
                sql.append("c.table_name = t_cons.table_name and ");
598
                sql.append("c.constraint_name = t_cons.constraint_name ");
599
                sql.append("WHERE t_cons.table_name like '");
600

    
601
                sql.append(params.getTable());
602
                sql.append("' ");
603
                String schema = null;
604

    
605

    
606
                if (params.getSchema() == null || params.getSchema() == "") {
607
                        schema = getDefaultSchema(conn);
608
                } else {
609
                        schema = params.getSchema();
610
                }
611
                if (schema != null) {
612
                        sql.append(" and t_cons.table_schema like '");
613
                        sql.append(schema);
614
                        sql.append("' ");
615
                }
616

    
617
                if (params.getCatalog() != null && params.getCatalog() != "") {
618
                        sql
619
                                        .append(" and t_cons.constraint_catalog like '");
620
                        sql.append(params.getCatalog());
621
                        sql.append("' ");
622
                }
623

    
624
                sql.append("' and constraint_type = 'PRIMARY KEY'");
625

    
626
                // System.out.println(sql.toString());
627
                try {
628
                        st = conn.createStatement();
629
                        try {
630
                                rs = st.executeQuery(sql.toString());
631
                        } catch (java.sql.SQLException e) {
632
                                throw new JDBCExecuteSQLException(sql.toString(), e);
633
                        }
634
                        while (rs.next()) {
635
                                list.add(rs.getString(1));
636
                        }
637
                        rs.close();
638
                        st.close();
639

    
640
                } catch (java.sql.SQLException e) {
641
                        throw new JDBCSQLException(e);
642
                }
643
                if (list.size() == 0) {
644
                        return null;
645
                }
646

    
647
                return (String[]) list.toArray(new String[0]);
648

    
649
        }
650

    
651
        protected void loadFeatureType(Connection conn,
652
                        EditableFeatureType featureType, String sql, String[] pks,
653
                        String defGeomName, String schema, String table)
654
                        throws DataException {
655

    
656
                Statement stAux = null;
657
                ResultSet rs = null;
658
                try {
659

    
660
                        stAux = conn.createStatement();
661
                        stAux.setFetchSize(1);
662

    
663
                        try {
664
                                rs = stAux.executeQuery(sql);
665
                        } catch (SQLException e) {
666
                                throw new JDBCExecuteSQLException(sql, e);
667
                        }
668
                        ResultSetMetaData rsMetadata = rs.getMetaData();
669

    
670
                        List pksList = null;
671
                        if (pks != null) {
672
                                pksList = Arrays.asList(pks);
673

    
674
                        }
675

    
676
                        int i;
677
                        int geometriesColumns = 0;
678
                        String lastGeometry = null;
679

    
680
                        EditableFeatureAttributeDescriptor attr;
681
            boolean firstGeometryAttrFound = false;
682
                        for (i = 1; i <= rsMetadata.getColumnCount(); i++) {
683
                                attr = getAttributeFromJDBC(featureType, conn, rsMetadata, i);
684
                                if (pksList != null && pksList.contains(attr.getName())) {
685
                                        attr.setIsPrimaryKey(true);
686
                                }
687
                                if (attr.getType() == DataTypes.GEOMETRY) {
688
                    geometriesColumns++;
689
                    lastGeometry = attr.getName();
690
                    // Set the default geometry attribute if it is the one
691
                    // given as parameter or it is the first one, just in case.
692
                    if (!firstGeometryAttrFound
693
                        || lastGeometry.equals(defGeomName)) {
694
                        firstGeometryAttrFound = true;
695
                        featureType
696
                            .setDefaultGeometryAttributeName(lastGeometry);
697
                    }
698
                                }
699

    
700
                        }
701

    
702
                        if (geometriesColumns > 0) {
703
                                loadSRS_and_shapeType(conn, rsMetadata, featureType, schema,
704
                                                table);
705
                        }
706

    
707
                        if (defGeomName == null && geometriesColumns == 1) {
708
                                featureType.setDefaultGeometryAttributeName(lastGeometry);
709
                                defGeomName = lastGeometry;
710
                        }
711

    
712
                } catch (java.sql.SQLException e) {
713
                        throw new JDBCSQLException(e); // FIXME exception
714
                } finally {
715
                        try {
716
                                rs.close();
717
                        } catch (Exception e) {
718
                        }
719
                        try {
720
                                stAux.close();
721
                        } catch (Exception e) {
722
                        }
723

    
724
                }
725

    
726
        }
727

    
728
        /**
729
         * Override if provider has geometry support
730
         *
731
         * @param storeParams
732
         * @param geometryAttrName
733
         * @param limit
734
         * @return
735
         * @throws DataException
736
         */
737
        public Envelope getFullEnvelopeOfField(JDBCStoreParameters storeParams,
738
                        String geometryAttrName, Envelope limit) throws DataException {
739

    
740
                // TODO
741
                return null;
742

    
743
        }
744

    
745
        public Geometry getGeometry(byte[] buffer) throws BaseException {
746
                if (buffer == null) {
747
                        return null;
748
                }
749
                return geomManager.createFrom(buffer);
750
        }
751

    
752
        public String escapeFieldName(String field) {
753
                if (field.matches("[a-z][a-z0-9_]*")) {
754
                        return field;
755
                }
756
                String quote = getIdentifierQuoteString();
757
                return quote + field + quote;
758
        }
759

    
760
        public Object dalValueToJDBC(
761
                        FeatureAttributeDescriptor attributeDescriptor, Object object)
762
                        throws WriteException {
763
                if (object == null) {
764
                        return null;
765
                }
766

    
767
                if (attributeDescriptor.getType() != DataTypes.GEOMETRY) {
768
                        return object;
769
                }
770
                try {
771
                        byte[] wkb = null;
772
                        Geometry geom = (Geometry) object;
773
                        IProjection srs = attributeDescriptor.getSRS();
774
                        if (srs != null) {
775
                                wkb =  geom.convertToWKBForcingType(getProviderSRID(srs), attributeDescriptor.getGeomType().getType());
776
                        } else {
777
                                wkb =  geom.convertToWKB();
778
                        }
779
                        return wkb;
780
                } catch (Exception e) {
781
                        throw new WriteException(this.name, e);
782
                }
783
        }
784

    
785
        public String getSqlColumnTypeDescription(FeatureAttributeDescriptor attr) {
786
                switch (attr.getType()) {
787
                case DataTypes.STRING:
788
                        if (attr.getSize() < 1 || attr.getSize() > 255) {
789
                                return "text";
790
                        } else {
791
                                return "varchar(" + attr.getSize() + ")";
792
                        }
793
                case DataTypes.BOOLEAN:
794
                        return "bool";
795

    
796
                case DataTypes.BYTE:
797
                        return "smallint";
798

    
799
                case DataTypes.DATE:
800
                        return "date";
801

    
802
                case DataTypes.TIMESTAMP:
803
                        return "timestamp";
804

    
805
                case DataTypes.TIME:
806
                        return "time";
807

    
808
                case DataTypes.BYTEARRAY:
809
                case DataTypes.GEOMETRY:
810
                        return "blob";
811

    
812
                case DataTypes.DOUBLE:
813
//                        if (attr.getPrecision() > 0) {
814
//                            return "double precision(" + attr.getPrecision() + ')';
815
//                        } else {
816
                    //It works with PostgreSQL and MySQL. Check with others
817
                            return "double precision";
818
//                        }
819
                case DataTypes.FLOAT:
820
                        return "real";
821

    
822
                case DataTypes.INT:
823
                        if (attr.isAutomatic() && allowAutomaticValues()) {
824
                                return "serial";
825
                        } else {
826
                                return "integer";
827
                        }
828
                case DataTypes.LONG:
829
                        if (attr.isAutomatic()) {
830
                                return "bigserial";
831
                        } else {
832
                                return "bigint";
833
                        }
834

    
835
                default:
836
                        String typeName = (String) attr.getAdditionalInfo("SQLTypeName");
837
                        if (typeName != null) {
838
                                return typeName;
839
                        }
840

    
841
                        throw new UnsupportedDataTypeException(attr.getDataTypeName(), attr
842
                                        .getType());
843
                }
844
        }
845

    
846
        public int getProviderSRID(String srs) {
847
                return -1;
848
        }
849

    
850
        public int getProviderSRID(IProjection srs) {
851
                return -1;
852
        }
853

    
854
        public String getSqlFieldName(FeatureAttributeDescriptor attribute) {
855
                return escapeFieldName(attribute.getName());
856
        }
857

    
858
        public String getSqlFieldDescription(FeatureAttributeDescriptor attr)
859
                        throws DataException {
860

    
861
                /**
862
                 * column_name data_type [ DEFAULT default_expr ] [ column_constraint [
863
                 * ... ] ]
864
                 *
865
                 * where column_constraint is:
866
                 *
867
                 * [ CONSTRAINT constraint_name ] { NOT NULL | NULL | UNIQUE | PRIMARY
868
                 * KEY | CHECK (expression) | REFERENCES reftable [ ( refcolumn ) ] [
869
                 * MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON DELETE action ] [ ON
870
                 * UPDATE action ] } [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY
871
                 * DEFERRED | INITIALLY IMMEDIATE ]
872
                 */
873

    
874
                StringBuilder strb = new StringBuilder();
875
                // name
876
                strb.append(escapeFieldName(attr.getName()));
877
                strb.append(" ");
878

    
879
                // Type
880
                strb.append(this.getSqlColumnTypeDescription(attr));
881
                strb.append(" ");
882

    
883
                boolean allowNull = attr.allowNull()
884
                                && !(attr.isPrimaryKey() || attr.isAutomatic());
885
                // Default
886
                if (attr.getDefaultValue() == null) {
887
                        if (allowNull) {
888
                                strb.append("DEFAULT NULL ");
889
                        }
890
                } else {
891
                        String value = getDefaltFieldValueString(attr);
892
                        strb.append("DEFAULT '");
893
                        strb.append(value);
894
                        strb.append("' ");
895
                }
896

    
897
                // Null
898
                if (allowNull) {
899
                        strb.append("NULL ");
900
                } else {
901
                        strb.append("NOT NULL ");
902
                }
903

    
904
                // Primery key
905
                if (attr.isPrimaryKey()) {
906
                        strb.append("PRIMARY KEY ");
907
                }
908
                return strb.toString();
909
        }
910

    
911
        protected String getDefaltFieldValueString(FeatureAttributeDescriptor attr)
912
                        throws WriteException {
913
                return dalValueToJDBC(attr, attr.getDefaultValue()).toString();
914
        }
915

    
916
        public String compoundLimitAndOffset(long limit, long offset) {
917
                StringBuilder sql = new StringBuilder();
918
                // limit
919
                if (limit > 0) {
920
                        sql.append(" limit ");
921
                        sql.append(limit);
922
                        sql.append(' ');
923
                }
924

    
925
                // offset
926
                if (offset > 0) {
927
                        sql.append(" offset ");
928
                        sql.append(offset);
929
                        sql.append(' ');
930
                }
931
                return sql.toString();
932
        }
933

    
934
        public boolean supportOffset() {
935
                return true;
936
        }
937

    
938
        public List getAdditionalSqlToCreate(NewDataStoreParameters ndsp,
939
                        FeatureType fType) {
940
                // TODO Auto-generated method stub
941
                return null;
942
        }
943

    
944

    
945
        public String stringJoin(List listToJoin,String sep){
946
                StringBuilder strb = new StringBuilder();
947
                stringJoin(listToJoin,sep,strb);
948
                return strb.toString();
949
        }
950

    
951
        public void stringJoin(List listToJoin, String sep, StringBuilder strb) {
952
                if (listToJoin.size() < 1) {
953
                        return;
954
                }
955
                if (listToJoin.size() > 1) {
956
                        for (int i = 0; i < listToJoin.size() - 1; i++) {
957
                                strb.append(listToJoin.get(i));
958
                                strb.append(sep);
959
                        }
960
                }
961
                strb.append(listToJoin.get(listToJoin.size() - 1));
962
        }
963

    
964
        /**
965
         * Inform that provider has supports for geometry store and operations
966
         * natively
967
         *
968
         * @return
969
         */
970
        protected boolean supportsGeometry() {
971
                return false;
972
        }
973

    
974
        public boolean allowAutomaticValues() {
975
                if (allowAutomaticValues == null) {
976
                        ConnectionAction action = new ConnectionAction(){
977

    
978
                                public Object action(Connection conn) throws DataException {
979

    
980
                                        ResultSet rs;
981
                                        try {
982
                                                DatabaseMetaData meta = conn.getMetaData();
983
                                                rs = meta.getTypeInfo();
984
                                                try{
985
                                                        while (rs.next()) {
986
                                                                if (rs.getInt("DATA_TYPE") == java.sql.Types.INTEGER) {
987
                                                                        if (rs.getBoolean("AUTO_INCREMENT")) {
988
                                                                                return Boolean.TRUE;
989
                                                                        } else {
990
                                                                                return Boolean.FALSE;
991
                                                                        }
992
                                                                }
993
                                                        }
994
                                                }finally{
995
                                                        try{ rs.close();} catch (SQLException ex) {logger.error("Exception closing resulset", ex);};
996
                                                }
997
                                        } catch (SQLException e) {
998
                                                throw new JDBCSQLException(e);
999
                                        }
1000
                                        return Boolean.FALSE;
1001
                                }
1002

    
1003
                        };
1004

    
1005

    
1006

    
1007
                        try {
1008
                                allowAutomaticValues = (Boolean) doConnectionAction(action);
1009
                        } catch (Exception e) {
1010
                                logger.error("Exception checking for automatic integers", e);
1011
                                allowAutomaticValues = Boolean.FALSE;
1012
                        }
1013
                }
1014
                return allowAutomaticValues.booleanValue();
1015
        }
1016

    
1017
        public boolean supportsUnion() {
1018
                if (supportsUnions == null) {
1019
                        ConnectionAction action = new ConnectionAction() {
1020

    
1021
                                public Object action(Connection conn) throws DataException {
1022

    
1023
                                        try {
1024
                                                DatabaseMetaData meta = conn.getMetaData();
1025
                                                return new Boolean(meta.supportsUnion());
1026
                                        } catch (SQLException e) {
1027
                                                throw new JDBCSQLException(e);
1028
                                        }
1029
                                }
1030

    
1031
                        };
1032

    
1033
                        try {
1034
                                supportsUnions = (Boolean) doConnectionAction(action);
1035
                        } catch (Exception e) {
1036
                                logger.error("Exception checking for unions support", e);
1037
                                supportsUnions = Boolean.FALSE;
1038
                        }
1039
                }
1040
                return supportsUnions.booleanValue();
1041
        }
1042

    
1043
        protected String getIdentifierQuoteString() {
1044
                if (identifierQuoteString == null) {
1045
                ConnectionAction action = new ConnectionAction() {
1046

    
1047
                        public Object action(Connection conn) throws DataException {
1048

    
1049
                                try {
1050
                                        DatabaseMetaData meta = conn.getMetaData();
1051
                                        return meta.getIdentifierQuoteString();
1052
                                } catch (SQLException e) {
1053
                                        throw new JDBCSQLException(e);
1054
                                }
1055
                        }
1056

    
1057
                };
1058

    
1059
                try {
1060
                        identifierQuoteString = (String) doConnectionAction(action);
1061
                } catch (Exception e) {
1062
                        logger.error("Exception checking for unions support", e);
1063
                        identifierQuoteString = " ";
1064
                        }
1065
                }
1066
                return identifierQuoteString;
1067
        }
1068

    
1069
        protected boolean isReservedWord(String field) {
1070
                // TODO
1071
                return false;
1072
        }
1073

    
1074
}