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

History | View | Annotate | Download (28.8 KB)

1
/* gvSIG. Geographic Information System of the Valencian Government
2
*
3
* Copyright (C) 2007-2008 Infrastructures and Transports Department
4
* of the Valencian Government (CIT)
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 2
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
*/
22

    
23
/*
24
* AUTHORS (In addition to CIT):
25
* 2009 IVER T.I   {{Task}}
26
*/
27

    
28
/**
29
 *
30
 */
31
package org.gvsig.fmap.dal.store.jdbc;
32

    
33
import java.sql.Connection;
34
import java.sql.DatabaseMetaData;
35
import java.sql.ResultSet;
36
import java.sql.ResultSetMetaData;
37
import java.sql.SQLException;
38
import java.sql.Statement;
39
import java.util.ArrayList;
40
import java.util.Arrays;
41
import java.util.List;
42

    
43
import org.cresques.cts.IProjection;
44
import org.slf4j.Logger;
45
import org.slf4j.LoggerFactory;
46

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

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

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

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

    
100
        protected GeometryManager geomManager = null;
101

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

    
105
        private String identifierQuoteString;
106

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

    
115
        }
116

    
117
        protected void initializeResource() throws InitializeException {
118
                ResourceManagerProviderServices manager = (ResourceManagerProviderServices) DALLocator
119
                                .getResourceManager();
120
                JDBCResource resource = (JDBCResource) manager
121
                                .createAddResource(
122
                                JDBCResource.NAME, new Object[] { params.getUrl(),
123
                                                params.getHost(), params.getPort(), params.getDBName(),
124
                                                params.getUser(), params.getPassword(),
125
                                                params.getJDBCDriverClassName() });
126
                this.setResource(resource);
127

    
128
        }
129

    
130
        protected final void setResource(JDBCResource resource) {
131
                this.resource = resource;
132
                this.resource.addConsumer(this);
133
        }
134

    
135
        public boolean closeResourceRequested(ResourceProvider resource) {
136
                return user.closeResourceRequested(resource);
137
        }
138

    
139
        public void resourceChanged(ResourceProvider resource) {
140
                user.resourceChanged(resource);
141

    
142
        }
143

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

    
165
                                        user.opendDone();
166

    
167
                                        isOpen = true;
168
                                        return null;
169
                                }
170
                        });
171
                        return true;
172
                } catch (ResourceExecuteException e) {
173
                        throw new OpenException(name, e);
174
                        // } finally {
175
                        // end();
176
                }
177

    
178
        }
179

    
180
        public JDBCResource getResource() {
181
                return resource;
182
        }
183

    
184
        public void close() throws CloseException {
185
                if (!isOpen) {
186
                        return;
187
                }
188
                // try {
189
                // begin();
190
                // } catch (ResourceExecuteException e) {
191
                // throw new CloseException(name, e);
192
                // }
193
                try {
194
                        getResource().execute(new ResourceAction() {
195
                                public Object run() throws Exception {
196
                                        isOpen = false;
197

    
198
                                        resource.notifyClose();
199
                                        user.closeDone();
200
                                        return null;
201
                                }
202
                        });
203
                } catch (ResourceExecuteException e) {
204
                        throw new CloseException(this.name, e);
205
                        // } finally {
206
                        // end();
207
                }
208
        }
209

    
210
        // public void end() {
211
        // resource.end();
212
        // }
213
        //
214
        // public void begin() throws ResourceExecuteException {
215
        // this.resource.begin();
216
        // }
217

    
218
        public Connection getConnection() throws AccessResourceException {
219
                return resource.getJDBCConnection();
220

    
221
        }
222

    
223
        @Override
224
        protected void doDispose() throws BaseException {
225
                resource.removeConsumer(this);
226
        }
227

    
228
        public boolean isOpen() {
229
                return isOpen;
230
        }
231

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

    
273
                                        result = action.action(conn);
274

    
275
                                        if (beginTrans) {
276
                                                try {
277
                                                        conn.commit();
278
                                                } catch (SQLException e) {
279
                                                        throw new JDBCTransactionCommitException(e);
280
                                                }
281
                                        }
282

    
283
                                        return result;
284

    
285
                                } catch (Exception e) {
286

    
287
                                        if (beginTrans) {
288
                                                try {
289
                                                        conn.rollback();
290
                                                } catch (Exception e1) {
291
                                                        throw new JDBCTransactionRollbackException(e1, e);
292
                                                }
293
                                        }
294
                                        throw e;
295

    
296
                                } finally {
297
                                        try {
298
                                                conn.close();
299
                                        } catch (Exception e1) {
300
                                                logger.error("Exception on close connection", e1);
301
                                        }
302
                                        // this.end();
303
                                }
304
                        }
305
                });
306

    
307
        }
308

    
309
        protected String getDefaultSchema(Connection conn) throws JDBCException {
310
                return defaultSchema;
311
        }
312

    
313
        protected EditableFeatureAttributeDescriptor createAttributeFromJDBC(
314
                        EditableFeatureType fType, Connection conn,
315
                        ResultSetMetaData rsMetadata, int colIndex)
316
        throws java.sql.SQLException {
317

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

    
380
                default:
381
                        column = fType.add(rsMetadata.getColumnName(colIndex),
382
                                        DataTypes.OBJECT);
383
                        column.setAdditionalInfo("SQLType", new Integer(rsMetadata
384
                                        .getColumnType(colIndex)));
385
                        column.setAdditionalInfo("SQLTypeName", rsMetadata
386
                                        .getColumnTypeName(colIndex));
387

    
388
                        break;
389
                }
390

    
391
                return column;
392

    
393
        }
394

    
395
        protected EditableFeatureAttributeDescriptor getAttributeFromJDBC(
396
                        EditableFeatureType fType, Connection conn,
397
                        ResultSetMetaData rsMetadata, int colIndex) throws JDBCException {
398
                EditableFeatureAttributeDescriptor column;
399
                try {
400

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

    
424
                } catch (java.sql.SQLException e) {
425
                        throw new JDBCSQLException(e);
426
                }
427

    
428
                return column;
429

    
430
        }
431

    
432
        /**
433
         * Fill <code>featureType</code> geometry attributes with SRS and ShapeType
434
         * information
435
         *
436
         * <b>Override this if provider has native eometry support</b>
437
         *
438
         * @param conn
439
         * @param rsMetadata
440
         * @param featureType
441
         * @throws ReadException
442
         */
443
        protected void loadSRS_and_shapeType(Connection conn,
444
                        ResultSetMetaData rsMetadata, EditableFeatureType featureType,
445
                        String baseSchema, String baseTable) throws JDBCException {
446

    
447
                // Nothing to do
448

    
449
        }
450

    
451
        public void loadFeatureType(EditableFeatureType featureType,
452
                        JDBCStoreParameters storeParams) throws DataException {
453
                if (storeParams.getSQL() != null
454
                                && storeParams.getSQL().trim().length() > 0) {
455
                        loadFeatureType(featureType, storeParams, storeParams.getSQL(),
456
                                        null, null);
457
                } else {
458
                        String sql = "Select * from " + storeParams.tableID()
459
                                        + " where false";
460
                        loadFeatureType(featureType, storeParams, sql, storeParams
461
                                        .getSchema(), storeParams.getTable());
462
                }
463
        }
464

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

    
503
        protected String[] getPksFrom(Connection conn, JDBCStoreParameters params)
504
                throws JDBCException {
505
                try{
506
                        DatabaseMetaData metadata = conn.getMetaData();
507
                        ResultSet rsPrimaryKeys = null;
508
                        ResultSet rs = null;
509
                        String catalog = params.getCatalog();
510
                        String schema = params.getSchema();
511

    
512
                        try{
513
                                rs = metadata.getTables(catalog,
514
                                                schema, params.getTable(), null);
515

    
516
                                if (!rs.next()) {
517
                                        // No tables found with default values, ignoring catalog
518
                                        rs.close();
519
                                        catalog = null;
520
                                        schema = null;
521
                                        rs = metadata
522
                                                        .getTables(catalog, schema, params.getTable(), null);
523

    
524
                                        if (!rs.next()) {
525
                                                // table not found
526
                                                return null;
527
                                        } else if (rs.next()){
528
                                                // More that one, cant identify
529
                                                return null;
530
                                        }
531

    
532
                                } else if (rs.next()) {
533
                                        // More that one, cant identify
534
                                        return null;
535
                                }
536
                                rsPrimaryKeys = metadata.getPrimaryKeys(catalog, schema, params
537
                                                .getTable());
538
                                List pks = new ArrayList();
539
                                while (rsPrimaryKeys.next()){
540
                                        pks.add(rsPrimaryKeys.getString("COLUMN_NAME"));
541
                                }
542
                                return (String[]) pks.toArray(new String[pks.size()]);
543

    
544

    
545
                        } finally {
546
                                try{if (rs != null) {
547
                                        rs.close();
548
                                }} catch (SQLException ex) {logger.warn("Exception closing tables rs", ex);};
549
                                try{if (rsPrimaryKeys != null) {
550
                                        rsPrimaryKeys.close();
551
                                }} catch (SQLException ex) {logger.warn("Exception closing pk rs", ex);};
552
                        }
553

    
554

    
555
                } catch (SQLException e) {
556
                        logger.warn("Unable to get pk from DatabaseMetada", e);
557
                        return getPksFromInformationSchema(conn, params);
558
                }
559

    
560
        }
561

    
562
        protected String[] getPksFromInformationSchema(Connection conn,
563
                        JDBCStoreParameters params)
564
                        throws JDBCException {
565
                Statement st;
566
                StringBuffer sql = new StringBuffer();
567
                ResultSet rs;
568
                ArrayList list = new ArrayList();
569

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

    
599
                sql.append("select column_name as primary_key ");
600
                sql.append("from information_schema.table_constraints t_cons ");
601
                sql.append("inner join information_schema.key_column_usage c on ");
602
                sql.append("c.constraint_catalog = t_cons.constraint_catalog and ");
603
                sql.append("c.table_schema = t_cons.table_schema and ");
604
                sql.append("c.table_name = t_cons.table_name and ");
605
                sql.append("c.constraint_name = t_cons.constraint_name ");
606
                sql.append("WHERE t_cons.table_name like '");
607

    
608
                sql.append(params.getTable());
609
                sql.append("' ");
610
                String schema = null;
611

    
612

    
613
                if (params.getSchema() == null || params.getSchema() == "") {
614
                        schema = getDefaultSchema(conn);
615
                } else {
616
                        schema = params.getSchema();
617
                }
618
                if (schema != null) {
619
                        sql.append(" and t_cons.table_schema like '");
620
                        sql.append(schema);
621
                        sql.append("' ");
622
                }
623

    
624
                if (params.getCatalog() != null && params.getCatalog() != "") {
625
                        sql
626
                                        .append(" and t_cons.constraint_catalog like '");
627
                        sql.append(params.getCatalog());
628
                        sql.append("' ");
629
                }
630

    
631
                sql.append("' and constraint_type = 'PRIMARY KEY'");
632

    
633
                // System.out.println(sql.toString());
634
                try {
635
                        st = conn.createStatement();
636
                        try {
637
                                rs = st.executeQuery(sql.toString());
638
                        } catch (java.sql.SQLException e) {
639
                                throw new JDBCExecuteSQLException(sql.toString(), e);
640
                        }
641
                        while (rs.next()) {
642
                                list.add(rs.getString(1));
643
                        }
644
                        rs.close();
645
                        st.close();
646

    
647
                } catch (java.sql.SQLException e) {
648
                        throw new JDBCSQLException(e);
649
                }
650
                if (list.size() == 0) {
651
                        return null;
652
                }
653

    
654
                return (String[]) list.toArray(new String[0]);
655

    
656
        }
657

    
658
        protected void loadFeatureType(Connection conn,
659
                        EditableFeatureType featureType, String sql, String[] pks,
660
                        String defGeomName, String schema, String table)
661
                        throws DataException {
662

    
663
                Statement stAux = null;
664
                ResultSet rs = null;
665
                try {
666

    
667
                        stAux = conn.createStatement();
668
                        stAux.setFetchSize(1);
669

    
670
                        try {
671
                                rs = stAux.executeQuery(sql);
672
                        } catch (SQLException e) {
673
                                throw new JDBCExecuteSQLException(sql, e);
674
                        }
675
                        ResultSetMetaData rsMetadata = rs.getMetaData();
676

    
677
                        List pksList = null;
678
                        if (pks != null) {
679
                                pksList = Arrays.asList(pks);
680

    
681
                        }
682

    
683
                        int i;
684
                        int geometriesColumns = 0;
685
                        String lastGeometry = null;
686

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

    
707
                        }
708

    
709
                        if (geometriesColumns > 0) {
710
                                loadSRS_and_shapeType(conn, rsMetadata, featureType, schema,
711
                                                table);
712
                        }
713

    
714
                        if (defGeomName == null && geometriesColumns == 1) {
715
                                featureType.setDefaultGeometryAttributeName(lastGeometry);
716
                                defGeomName = lastGeometry;
717
                        }
718

    
719
                } catch (java.sql.SQLException e) {
720
                        throw new JDBCSQLException(e); // FIXME exception
721
                } finally {
722
                        try {
723
                                rs.close();
724
                        } catch (Exception e) {
725
                        }
726
                        try {
727
                                stAux.close();
728
                        } catch (Exception e) {
729
                        }
730

    
731
                }
732

    
733
        }
734

    
735
        /**
736
         * Override if provider has geometry support
737
         *
738
         * @param storeParams
739
         * @param geometryAttrName
740
         * @param limit
741
         * @return
742
         * @throws DataException
743
         */
744
        public Envelope getFullEnvelopeOfField(JDBCStoreParameters storeParams,
745
                        String geometryAttrName, Envelope limit) throws DataException {
746

    
747
                // TODO
748
                return null;
749

    
750
        }
751

    
752
        public Geometry getGeometry(byte[] buffer) throws BaseException {
753
                if (buffer == null) {
754
                        return null;
755
                }
756
                return geomManager.createFrom(buffer);
757
        }
758

    
759
        public String escapeFieldName(String field) {
760
                if (field.matches("[a-z][a-z0-9_]*")) {
761
                        return field;
762
                }
763
                String quote = getIdentifierQuoteString();
764
                return quote + field + quote;
765
        }
766

    
767
        public Object dalValueToJDBC(
768
                        FeatureAttributeDescriptor attributeDescriptor, Object object)
769
                        throws WriteException {
770
                if (object == null) {
771
                        return null;
772
                }
773

    
774
                if (attributeDescriptor.getType() != DataTypes.GEOMETRY) {
775
                        return object;
776
                }
777
                try {
778
                        byte[] wkb = null;
779
                        Geometry geom = (Geometry) object;
780
                        IProjection srs = attributeDescriptor.getSRS();
781
                        if (srs != null) {
782
                                wkb =  geom.convertToWKBForcingType(getProviderSRID(srs), attributeDescriptor.getGeomType().getType());
783
                        } else {
784
                                wkb =  geom.convertToWKB();
785
                        }
786
                        return wkb;
787
                } catch (Exception e) {
788
                        throw new WriteException(this.name, e);
789
                }
790
        }
791

    
792
        public String getSqlColumnTypeDescription(FeatureAttributeDescriptor attr) {
793
                switch (attr.getType()) {
794
                case DataTypes.STRING:
795
                        if (attr.getSize() < 1 || attr.getSize() > 255) {
796
                                return "text";
797
                        } else {
798
                                return "varchar(" + attr.getSize() + ")";
799
                        }
800
                case DataTypes.BOOLEAN:
801
                        return "bool";
802

    
803
                case DataTypes.BYTE:
804
                        return "smallint";
805

    
806
                case DataTypes.DATE:
807
                        return "date";
808

    
809
                case DataTypes.TIMESTAMP:
810
                        return "timestamp";
811

    
812
                case DataTypes.TIME:
813
                        return "time";
814

    
815
                case DataTypes.BYTEARRAY:
816
                case DataTypes.GEOMETRY:
817
                        return "blob";
818

    
819
                case DataTypes.DOUBLE:
820
//                        if (attr.getPrecision() > 0) {
821
//                            return "double precision(" + attr.getPrecision() + ')';
822
//                        } else {
823
                    //It works with PostgreSQL and MySQL. Check with others
824
                            return "double precision";
825
//                        }
826
                case DataTypes.FLOAT:
827
                        return "real";
828

    
829
                case DataTypes.INT:
830
                        if (attr.isAutomatic() && allowAutomaticValues()) {
831
                                return "serial";
832
                        } else {
833
                                return "integer";
834
                        }
835
                case DataTypes.LONG:
836
                        if (attr.isAutomatic()) {
837
                                return "bigserial";
838
                        } else {
839
                                return "bigint";
840
                        }
841

    
842
                default:
843
                        String typeName = (String) attr.getAdditionalInfo("SQLTypeName");
844
                        if (typeName != null) {
845
                                return typeName;
846
                        }
847

    
848
                        throw new UnsupportedDataTypeException(attr.getDataTypeName(), attr
849
                                        .getType());
850
                }
851
        }
852

    
853
        public int getProviderSRID(String srs) {
854
                return -1;
855
        }
856

    
857
        public int getProviderSRID(IProjection srs) {
858
                return -1;
859
        }
860

    
861
        public String getSqlFieldName(FeatureAttributeDescriptor attribute) {
862
                return escapeFieldName(attribute.getName());
863
        }
864

    
865
        public String getSqlFieldDescription(FeatureAttributeDescriptor attr)
866
                        throws DataException {
867

    
868
                /**
869
                 * column_name data_type [ DEFAULT default_expr ] [ column_constraint [
870
                 * ... ] ]
871
                 *
872
                 * where column_constraint is:
873
                 *
874
                 * [ CONSTRAINT constraint_name ] { NOT NULL | NULL | UNIQUE | PRIMARY
875
                 * KEY | CHECK (expression) | REFERENCES reftable [ ( refcolumn ) ] [
876
                 * MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON DELETE action ] [ ON
877
                 * UPDATE action ] } [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY
878
                 * DEFERRED | INITIALLY IMMEDIATE ]
879
                 */
880

    
881
                StringBuilder strb = new StringBuilder();
882
                // name
883
                strb.append(escapeFieldName(attr.getName()));
884
                strb.append(" ");
885

    
886
                // Type
887
                strb.append(this.getSqlColumnTypeDescription(attr));
888
                strb.append(" ");
889

    
890
                boolean allowNull = attr.allowNull()
891
                                && !(attr.isPrimaryKey() || attr.isAutomatic());
892
                // Default
893
                if (attr.getDefaultValue() == null) {
894
                        if (allowNull) {
895
                                strb.append("DEFAULT NULL ");
896
                        }
897
                } else {
898
                        String value = getDefaltFieldValueString(attr);
899
                        strb.append("DEFAULT '");
900
                        strb.append(value);
901
                        strb.append("' ");
902
                }
903

    
904
                // Null
905
                if (allowNull) {
906
                        strb.append("NULL ");
907
                } else {
908
                        strb.append("NOT NULL ");
909
                }
910

    
911
                // Primery key
912
                if (attr.isPrimaryKey()) {
913
                        strb.append("PRIMARY KEY ");
914
                }
915
                return strb.toString();
916
        }
917

    
918
        protected String getDefaltFieldValueString(FeatureAttributeDescriptor attr)
919
                        throws WriteException {
920
                return dalValueToJDBC(attr, attr.getDefaultValue()).toString();
921
        }
922

    
923
        public String compoundLimitAndOffset(long limit, long offset) {
924
                StringBuilder sql = new StringBuilder();
925
                // limit
926
                if (limit > 0) {
927
                        sql.append(" limit ");
928
                        sql.append(limit);
929
                        sql.append(' ');
930
                }
931

    
932
                // offset
933
                if (offset > 0) {
934
                        sql.append(" offset ");
935
                        sql.append(offset);
936
                        sql.append(' ');
937
                }
938
                return sql.toString();
939
        }
940

    
941
        public boolean supportOffset() {
942
                return true;
943
        }
944

    
945
        public List getAdditionalSqlToCreate(NewDataStoreParameters ndsp,
946
                        FeatureType fType) {
947
                // TODO Auto-generated method stub
948
                return null;
949
        }
950

    
951

    
952
        public String stringJoin(List listToJoin,String sep){
953
                StringBuilder strb = new StringBuilder();
954
                stringJoin(listToJoin,sep,strb);
955
                return strb.toString();
956
        }
957

    
958
        public void stringJoin(List listToJoin, String sep, StringBuilder strb) {
959
                if (listToJoin.size() < 1) {
960
                        return;
961
                }
962
                if (listToJoin.size() > 1) {
963
                        for (int i = 0; i < listToJoin.size() - 1; i++) {
964
                                strb.append(listToJoin.get(i));
965
                                strb.append(sep);
966
                        }
967
                }
968
                strb.append(listToJoin.get(listToJoin.size() - 1));
969
        }
970

    
971
        /**
972
         * Inform that provider has supports for geometry store and operations
973
         * natively
974
         *
975
         * @return
976
         */
977
        protected boolean supportsGeometry() {
978
                return false;
979
        }
980

    
981
        public boolean allowAutomaticValues() {
982
                if (allowAutomaticValues == null) {
983
                        ConnectionAction action = new ConnectionAction(){
984

    
985
                                public Object action(Connection conn) throws DataException {
986

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

    
1010
                        };
1011

    
1012

    
1013

    
1014
                        try {
1015
                                allowAutomaticValues = (Boolean) doConnectionAction(action);
1016
                        } catch (Exception e) {
1017
                                logger.error("Exception checking for automatic integers", e);
1018
                                allowAutomaticValues = Boolean.FALSE;
1019
                        }
1020
                }
1021
                return allowAutomaticValues.booleanValue();
1022
        }
1023

    
1024
        public boolean supportsUnion() {
1025
                if (supportsUnions == null) {
1026
                        ConnectionAction action = new ConnectionAction() {
1027

    
1028
                                public Object action(Connection conn) throws DataException {
1029

    
1030
                                        try {
1031
                                                DatabaseMetaData meta = conn.getMetaData();
1032
                                                return new Boolean(meta.supportsUnion());
1033
                                        } catch (SQLException e) {
1034
                                                throw new JDBCSQLException(e);
1035
                                        }
1036
                                }
1037

    
1038
                        };
1039

    
1040
                        try {
1041
                                supportsUnions = (Boolean) doConnectionAction(action);
1042
                        } catch (Exception e) {
1043
                                logger.error("Exception checking for unions support", e);
1044
                                supportsUnions = Boolean.FALSE;
1045
                        }
1046
                }
1047
                return supportsUnions.booleanValue();
1048
        }
1049

    
1050
        protected String getIdentifierQuoteString() {
1051
                if (identifierQuoteString == null) {
1052
                ConnectionAction action = new ConnectionAction() {
1053

    
1054
                        public Object action(Connection conn) throws DataException {
1055

    
1056
                                try {
1057
                                        DatabaseMetaData meta = conn.getMetaData();
1058
                                        return meta.getIdentifierQuoteString();
1059
                                } catch (SQLException e) {
1060
                                        throw new JDBCSQLException(e);
1061
                                }
1062
                        }
1063

    
1064
                };
1065

    
1066
                try {
1067
                        identifierQuoteString = (String) doConnectionAction(action);
1068
                } catch (Exception e) {
1069
                        logger.error("Exception checking for unions support", e);
1070
                        identifierQuoteString = " ";
1071
                        }
1072
                }
1073
                return identifierQuoteString;
1074
        }
1075

    
1076
        protected boolean isReservedWord(String field) {
1077
                // TODO
1078
                return false;
1079
        }
1080

    
1081
}