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

History | View | Annotate | Download (29 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
                                                if (conn != null) {
292
                                                        conn.close();
293
                                                }
294
                                        } catch (Exception e1) {
295
                                                logger.error("Exception on close connection", e1);
296
                                        }
297
                                        // this.end();
298
                                }
299
                        }
300
                });
301

    
302
        }
303

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

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

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

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

    
384
                        break;
385
                }
386

    
387
                return column;
388

    
389
        }
390

    
391
        protected EditableFeatureAttributeDescriptor getAttributeFromJDBC(
392
                        EditableFeatureType fType, Connection conn,
393
                        ResultSetMetaData rsMetadata, int colIndex) throws JDBCException {
394
                EditableFeatureAttributeDescriptor column;
395
                try {
396

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

    
420
                } catch (java.sql.SQLException e) {
421
                        throw new JDBCSQLException(e);
422
                }
423

    
424
                return column;
425

    
426
        }
427

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

    
443
                // Nothing to do
444

    
445
        }
446

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

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

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

    
508
                        try{
509
                                rs = metadata.getTables(catalog,
510
                                                schema, params.getTable(), null);
511

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

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

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

    
540

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

    
550

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

    
556
        }
557

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

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

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

    
604
                sql.append(params.getTable());
605
                sql.append("' ");
606
                String schema = null;
607

    
608

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

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

    
627
                sql.append("' and constraint_type = 'PRIMARY KEY'");
628

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

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

    
650
                return (String[]) list.toArray(new String[0]);
651

    
652
        }
653

    
654
        protected void loadFeatureType(Connection conn,
655
                        EditableFeatureType featureType, String sql, String[] pks,
656
                        String defGeomName, String schema, String table)
657
                        throws DataException {
658

    
659
                Statement stAux = null;
660
                ResultSet rs = null;
661
                try {
662

    
663
                        stAux = conn.createStatement();
664
                        stAux.setFetchSize(1);
665

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

    
673
                        List pksList = null;
674
                        if (pks != null) {
675
                                pksList = Arrays.asList(pks);
676

    
677
                        }
678

    
679
                        int i;
680
                        int geometriesColumns = 0;
681
                        String lastGeometry = null;
682

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

    
703
                        }
704

    
705
                        if (geometriesColumns > 0) {
706
                                loadSRS_and_shapeType(conn, rsMetadata, featureType, schema,
707
                                                table);
708
                        }
709

    
710
                        if (defGeomName == null && geometriesColumns == 1) {
711
                                featureType.setDefaultGeometryAttributeName(lastGeometry);
712
                                defGeomName = lastGeometry;
713
                        }
714

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

    
727
                }
728

    
729
        }
730

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

    
743
                // TODO
744
                return null;
745

    
746
        }
747

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

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

    
763
        public Object dalValueToJDBC(
764
                        FeatureAttributeDescriptor attributeDescriptor, Object object)
765
                        throws WriteException {
766
                if (object == null) {
767
                        return null;
768
                }
769

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

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

    
799
                case DataTypes.BYTE:
800
                        return "smallint";
801

    
802
                case DataTypes.DATE:
803
                        return "date";
804

    
805
                case DataTypes.TIMESTAMP:
806
                        return "timestamp";
807

    
808
                case DataTypes.TIME:
809
                        return "time";
810

    
811
                case DataTypes.BYTEARRAY:
812
                case DataTypes.GEOMETRY:
813
                        return "blob";
814

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

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

    
838
                default:
839
                        String typeName = (String) attr.getAdditionalInfo("SQLTypeName");
840
                        if (typeName != null) {
841
                                return typeName;
842
                        }
843

    
844
                        throw new UnsupportedDataTypeException(attr.getDataTypeName(), attr
845
                                        .getType());
846
                }
847
        }
848

    
849
        public int getProviderSRID(String srs) {
850
                return -1;
851
        }
852

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

    
857
        public String getSqlFieldName(FeatureAttributeDescriptor attribute) {
858
                return escapeFieldName(attribute.getName());
859
        }
860

    
861
        public String getSqlFieldDescription(FeatureAttributeDescriptor attr)
862
                        throws DataException {
863

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

    
877
                StringBuilder strb = new StringBuilder();
878
                // name
879
                strb.append(escapeFieldName(attr.getName()));
880
                strb.append(" ");
881

    
882
                // Type
883
                strb.append(this.getSqlColumnTypeDescription(attr));
884
                strb.append(" ");
885

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

    
900
                // Null
901
                if (allowNull) {
902
                        strb.append("NULL ");
903
                } else {
904
                        strb.append("NOT NULL ");
905
                }
906

    
907
                // Primery key
908
                if (attr.isPrimaryKey()) {
909
                        strb.append("PRIMARY KEY ");
910
                }
911
                return strb.toString();
912
        }
913

    
914
        protected String getDefaltFieldValueString(FeatureAttributeDescriptor attr)
915
                        throws WriteException {
916
                return dalValueToJDBC(attr, attr.getDefaultValue()).toString();
917
        }
918

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

    
928
                // offset
929
                if (offset > 0) {
930
                        sql.append(" offset ");
931
                        sql.append(offset);
932
                        sql.append(' ');
933
                }
934
                return sql.toString();
935
        }
936

    
937
        public boolean supportOffset() {
938
                return true;
939
        }
940

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

    
947

    
948
        public String stringJoin(List listToJoin,String sep){
949
                StringBuilder strb = new StringBuilder();
950
                stringJoin(listToJoin,sep,strb);
951
                return strb.toString();
952
        }
953

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

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

    
977
        public boolean allowAutomaticValues() {
978
                if (allowAutomaticValues == null) {
979
                        ConnectionAction action = new ConnectionAction(){
980

    
981
                                public Object action(Connection conn) throws DataException {
982

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

    
1006
                        };
1007

    
1008

    
1009

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

    
1020
        public boolean supportsUnion() {
1021
                if (supportsUnions == null) {
1022
                        ConnectionAction action = new ConnectionAction() {
1023

    
1024
                                public Object action(Connection conn) throws DataException {
1025

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

    
1034
                        };
1035

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

    
1046
        protected String getIdentifierQuoteString() {
1047
                if (identifierQuoteString == null) {
1048
                ConnectionAction action = new ConnectionAction() {
1049

    
1050
                        public Object action(Connection conn) throws DataException {
1051

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

    
1060
                };
1061

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

    
1072
        protected boolean isReservedWord(String field) {
1073
                // TODO
1074
                return false;
1075
        }
1076

    
1077
}