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

History | View | Annotate | Download (29.8 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 3
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24
/* gvSIG. Geographic Information System of the Valencian Government
25
*
26
* Copyright (C) 2007-2008 Infrastructures and Transports Department
27
* of the Valencian Government (CIT)
28
*
29
* This program is free software; you can redistribute it and/or
30
* modify it under the terms of the GNU General Public License
31
* as published by the Free Software Foundation; either version 2
32
* of the License, or (at your option) any later version.
33
*
34
* This program is distributed in the hope that it will be useful,
35
* but WITHOUT ANY WARRANTY; without even the implied warranty of
36
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
37
* GNU General Public License for more details.
38
*
39
* You should have received a copy of the GNU General Public License
40
* along with this program; if not, write to the Free Software
41
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
42
* MA  02110-1301, USA.
43
*
44
*/
45

    
46
/*
47
* AUTHORS (In addition to CIT):
48
* 2009 IVER T.I   {{Task}}
49
*/
50

    
51
/**
52
 *
53
 */
54
package org.gvsig.fmap.dal.store.jdbc;
55

    
56
import java.sql.Connection;
57
import java.sql.DatabaseMetaData;
58
import java.sql.ResultSet;
59
import java.sql.ResultSetMetaData;
60
import java.sql.SQLException;
61
import java.sql.Statement;
62
import java.util.ArrayList;
63
import java.util.Arrays;
64
import java.util.List;
65

    
66
import org.cresques.cts.IProjection;
67
import org.slf4j.Logger;
68
import org.slf4j.LoggerFactory;
69

    
70
import org.gvsig.fmap.dal.DALLocator;
71
import org.gvsig.fmap.dal.DataTypes;
72
import org.gvsig.fmap.dal.NewDataStoreParameters;
73
import org.gvsig.fmap.dal.exception.CloseException;
74
import org.gvsig.fmap.dal.exception.DataException;
75
import org.gvsig.fmap.dal.exception.InitializeException;
76
import org.gvsig.fmap.dal.exception.OpenException;
77
import org.gvsig.fmap.dal.exception.ReadException;
78
import org.gvsig.fmap.dal.exception.WriteException;
79
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
80
import org.gvsig.fmap.dal.feature.EditableFeatureType;
81
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
82
import org.gvsig.fmap.dal.feature.FeatureType;
83
import org.gvsig.fmap.dal.feature.exception.UnsupportedDataTypeException;
84
import org.gvsig.fmap.dal.resource.ResourceAction;
85
import org.gvsig.fmap.dal.resource.exception.AccessResourceException;
86
import org.gvsig.fmap.dal.resource.exception.ResourceExecuteException;
87
import org.gvsig.fmap.dal.resource.spi.ResourceConsumer;
88
import org.gvsig.fmap.dal.resource.spi.ResourceManagerProviderServices;
89
import org.gvsig.fmap.dal.resource.spi.ResourceProvider;
90
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCException;
91
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCExecuteSQLException;
92
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCSQLException;
93
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCTransactionCommitException;
94
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCTransactionRollbackException;
95
import org.gvsig.fmap.geom.Geometry;
96
import org.gvsig.fmap.geom.GeometryLocator;
97
import org.gvsig.fmap.geom.GeometryManager;
98
/*
99
import org.gvsig.fmap.geom.operation.fromwkb.FromWKB;
100
import org.gvsig.fmap.geom.operation.fromwkb.FromWKBGeometryOperationContext;
101
import org.gvsig.fmap.geom.operation.towkb.ToWKB;
102
import org.gvsig.fmap.geom.operation.towkb.ToWKBOperationContext;
103
*/
104
import org.gvsig.fmap.geom.primitive.Envelope;
105
import org.gvsig.tools.dispose.impl.AbstractDisposable;
106
import org.gvsig.tools.exception.BaseException;
107

    
108
/**
109
 * @author jmvivo
110
 *
111
 */
112
public class JDBCHelper extends AbstractDisposable implements ResourceConsumer {
113

    
114
        private static Logger logger = LoggerFactory.getLogger(JDBCHelper.class);
115

    
116
        protected JDBCHelperUser user;
117
        protected boolean isOpen;
118
        protected String name;
119
        protected String defaultSchema;
120
        protected JDBCConnectionParameters params;
121
        private JDBCResource resource;
122

    
123
        protected GeometryManager geomManager = null;
124

    
125
        private Boolean allowAutomaticValues = null;
126
        private Boolean supportsUnions = null;
127

    
128
        private String identifierQuoteString;
129

    
130
        protected JDBCHelper(JDBCHelperUser consumer,
131
                        JDBCConnectionParameters params) throws InitializeException {
132
                this.geomManager = GeometryLocator.getGeometryManager();
133
                this.user = consumer;
134
                this.name = user.getProviderName();
135
                this.params = params;
136
                initializeResource();
137

    
138
        }
139

    
140
        protected void initializeResource() throws InitializeException {
141
                ResourceManagerProviderServices manager = (ResourceManagerProviderServices) DALLocator
142
                                .getResourceManager();
143
                JDBCResource resource = (JDBCResource) manager
144
                                .createAddResource(
145
                                JDBCResource.NAME, new Object[] { params.getUrl(),
146
                                                params.getHost(), params.getPort(), params.getDBName(),
147
                                                params.getUser(), params.getPassword(),
148
                                                params.getJDBCDriverClassName() });
149
                this.setResource(resource);
150

    
151
        }
152

    
153
        protected final void setResource(JDBCResource resource) {
154
                this.resource = resource;
155
                this.resource.addConsumer(this);
156
        }
157

    
158
        public boolean closeResourceRequested(ResourceProvider resource) {
159
                return user.closeResourceRequested(resource);
160
        }
161

    
162
        public void resourceChanged(ResourceProvider resource) {
163
                user.resourceChanged(resource);
164

    
165
        }
166

    
167
        /**
168
         * open the resource
169
         *
170
         * @return true if the resourse was open in this call
171
         * @throws OpenException
172
         */
173
        public boolean open() throws OpenException {
174
                if (isOpen) {
175
                        return false;
176
                }
177
                // try {
178
                // begin();
179
                // } catch (ResourceExecuteException e1) {
180
                // throw new OpenException(name, e1);
181
                // }
182
                try {
183
                        getResource().execute(new ResourceAction() {
184
                                public Object run() throws Exception {
185
                                        getResource().connect();
186
                                        getResource().notifyOpen();
187

    
188
                                        user.opendDone();
189

    
190
                                        isOpen = true;
191
                                        return null;
192
                                }
193
                        });
194
                        return true;
195
                } catch (ResourceExecuteException e) {
196
                        throw new OpenException(name, e);
197
                        // } finally {
198
                        // end();
199
                }
200

    
201
        }
202

    
203
        public JDBCResource getResource() {
204
                return resource;
205
        }
206

    
207
        public void close() throws CloseException {
208
                if (!isOpen) {
209
                        return;
210
                }
211
                // try {
212
                // begin();
213
                // } catch (ResourceExecuteException e) {
214
                // throw new CloseException(name, e);
215
                // }
216
                try {
217
                        getResource().execute(new ResourceAction() {
218
                                public Object run() throws Exception {
219
                                        isOpen = false;
220

    
221
                                        resource.notifyClose();
222
                                        user.closeDone();
223
                                        return null;
224
                                }
225
                        });
226
                } catch (ResourceExecuteException e) {
227
                        throw new CloseException(this.name, e);
228
                        // } finally {
229
                        // end();
230
                }
231
        }
232

    
233
        // public void end() {
234
        // resource.end();
235
        // }
236
        //
237
        // public void begin() throws ResourceExecuteException {
238
        // this.resource.begin();
239
        // }
240

    
241
        public Connection getConnection() throws AccessResourceException {
242
                return resource.getJDBCConnection();
243

    
244
        }
245

    
246
        @Override
247
        protected void doDispose() throws BaseException {
248
                resource.removeConsumer(this);
249
        }
250

    
251
        public boolean isOpen() {
252
                return isOpen;
253
        }
254

    
255
        /**
256
         * Executes an atomic action that uses an DB Connection.<br>
257
         *
258
         * This methos prepares a connection and close it at the end of execution of
259
         * action.<br>
260
         *
261
         * if <code>action</code> is an instance of {@link TransactionalAction} the
262
         * action will be execute inside of a DB transaction.
263
         *
264
         *
265
         * @param action
266
         * @throws Exception
267
         */
268
        public Object doConnectionAction(final ConnectionAction action)
269
                        throws Exception {
270
                this.open();
271
//                this.begin();
272
                return getResource().execute(new ResourceAction() {
273
                        public Object run() throws Exception {
274
                                Object result = null;
275
                                Connection conn = null;
276
                                boolean beginTrans = false;
277
                                try {
278
                                        conn = getConnection();
279
                                        if (action instanceof TransactionalAction) {
280
                                                // XXX OJO esta condicion NO ES FIABLE
281
                                                if (!conn.getAutoCommit()) {
282
                                                        if (!((TransactionalAction) action)
283
                                                                        .continueTransactionAllowed()) {
284
                                                                // FIXME exception
285
                                                                throw new Exception();
286
                                                        }
287
                                                }
288
                                                try {
289
                                                        conn.setAutoCommit(false);
290
                                                } catch (SQLException e) {
291
                                                        throw new JDBCSQLException(e);
292
                                                }
293
                                                beginTrans = true;
294
                                        }
295

    
296
                                        result = action.action(conn);
297

    
298
                                        if (beginTrans) {
299
                                                try {
300
                                                        conn.commit();
301
                                                } catch (SQLException e) {
302
                                                        throw new JDBCTransactionCommitException(e);
303
                                                }
304
                                        }
305

    
306
                                        return result;
307

    
308
                                } catch (Exception e) {
309

    
310
                                        if (beginTrans) {
311
                                                try {
312
                                                        conn.rollback();
313
                                                } catch (Exception e1) {
314
                                                        throw new JDBCTransactionRollbackException(e1, e);
315
                                                }
316
                                        }
317
                                        throw e;
318

    
319
                                } finally {
320
                                        try {
321
                                                conn.close();
322
                                        } catch (Exception e1) {
323
                                                logger.error("Exception on close connection", e1);
324
                                        }
325
                                        // this.end();
326
                                }
327
                        }
328
                });
329

    
330
        }
331

    
332
        protected String getDefaultSchema(Connection conn) throws JDBCException {
333
                return defaultSchema;
334
        }
335

    
336
        protected EditableFeatureAttributeDescriptor createAttributeFromJDBC(
337
                        EditableFeatureType fType, Connection conn,
338
                        ResultSetMetaData rsMetadata, int colIndex)
339
        throws java.sql.SQLException {
340

    
341
                EditableFeatureAttributeDescriptor column;
342
                switch (rsMetadata.getColumnType(colIndex)) {
343
                case java.sql.Types.INTEGER:
344
                        column = fType.add(rsMetadata.getColumnName(colIndex),
345
                                        DataTypes.INT);
346
                        break;
347
                case java.sql.Types.BIGINT:
348
                        column = fType.add(rsMetadata.getColumnName(colIndex),
349
                                        DataTypes.LONG);
350
                        break;
351
                case java.sql.Types.REAL:
352
                        column = fType.add(rsMetadata.getColumnName(colIndex),
353
                                        DataTypes.DOUBLE);
354
                        break;
355
                case java.sql.Types.DOUBLE:
356
                        column = fType.add(rsMetadata.getColumnName(colIndex),
357
                                        DataTypes.DOUBLE);
358
                        break;
359
                case java.sql.Types.CHAR:
360
                        column = fType.add(rsMetadata.getColumnName(colIndex),
361
                                        DataTypes.STRING);
362
                        break;
363
                case java.sql.Types.VARCHAR:
364
                case java.sql.Types.LONGVARCHAR:
365
                        column = fType.add(rsMetadata.getColumnName(colIndex),
366
                                        DataTypes.STRING);
367
                        break;
368
                case java.sql.Types.FLOAT:
369
                        column = fType.add(rsMetadata.getColumnName(colIndex),
370
                                        DataTypes.FLOAT);
371
                        break;
372
        case java.sql.Types.NUMERIC:
373
            column = fType.add(rsMetadata.getColumnName(colIndex),
374
                    DataTypes.FLOAT);
375
            break;
376
                case java.sql.Types.DECIMAL:
377
                        column = fType.add(rsMetadata.getColumnName(colIndex),
378
                                        DataTypes.FLOAT);
379
                        break;
380
                case java.sql.Types.DATE:
381
                        column = fType.add(rsMetadata.getColumnName(colIndex),
382
                                        DataTypes.DATE);
383
                        break;
384
                case java.sql.Types.TIME:
385
                        column = fType.add(rsMetadata.getColumnName(colIndex),
386
                                        DataTypes.TIME);
387
                        break;
388
                case java.sql.Types.TIMESTAMP:
389
                        column = fType.add(rsMetadata.getColumnName(colIndex),
390
                                        DataTypes.TIMESTAMP);
391
                        break;
392
                case java.sql.Types.BOOLEAN:
393
                        column = fType.add(rsMetadata.getColumnName(colIndex),
394
                                        DataTypes.BOOLEAN);
395
                        break;
396
                case java.sql.Types.BLOB:
397
                case java.sql.Types.BINARY:
398
                case java.sql.Types.LONGVARBINARY:
399
                        column = fType.add(rsMetadata.getColumnName(colIndex),
400
                                        DataTypes.BYTEARRAY);
401
                        break;
402

    
403
                default:
404
                        column = fType.add(rsMetadata.getColumnName(colIndex),
405
                                        DataTypes.OBJECT);
406
                        column.setAdditionalInfo("SQLType", new Integer(rsMetadata
407
                                        .getColumnType(colIndex)));
408
                        column.setAdditionalInfo("SQLTypeName", rsMetadata
409
                                        .getColumnTypeName(colIndex));
410

    
411
                        break;
412
                }
413

    
414
                return column;
415

    
416
        }
417

    
418
        protected EditableFeatureAttributeDescriptor getAttributeFromJDBC(
419
                        EditableFeatureType fType, Connection conn,
420
                        ResultSetMetaData rsMetadata, int colIndex) throws JDBCException {
421
                EditableFeatureAttributeDescriptor column;
422
                try {
423

    
424
                        column = createAttributeFromJDBC(fType, conn, rsMetadata, colIndex);
425
                        // column.setCaseSensitive(rsMetadata.isCaseSensitive(colIndex));
426
                        // column.setSqlType(rsMetadata.getColumnType(colIndex));
427
                        column.setAllowNull(
428
                                        rsMetadata.isNullable(colIndex) == ResultSetMetaData.columnNullable);
429
                        column.setIsAutomatic(rsMetadata.isAutoIncrement(colIndex));
430
                        column.setIsReadOnly(rsMetadata.isReadOnly(colIndex));
431
                        // column.setWritable(rsMetadata.isWritable(colIndex));
432
                        // column.setClassName(rsMetadata.getColumnClassName(colIndex));
433
                        // column.setCatalogName(rsMetadata.getCatalogName(colIndex));
434
                        // column.setDefinitelyWritable(rsMetadata
435
                        // .isDefinitelyWritable(colIndex));
436
                        // column.setLabel(rsMetadata.getColumnLabel(colIndex));
437
                        // column.setSchemaName(rsMetadata.getSchemaName(colIndex));
438
                        // column.setTableName(rsMetadata.getTableName(colIndex));
439
                        // column.setCatalogName(rsMetadata.getCatalogName(colIndex));
440
                        // column.setSqlTypeName();
441
                        // column.setSearchable(rsMetadata.isSearchable(colIndex));
442
                        // column.setSigned(rsMetadata.isSigned(colIndex));
443
                        // column.setCurrency(rsMetadata.isCurrency(colIndex));
444
                        column.setPrecision(rsMetadata.getPrecision(colIndex));
445
                        column.setSize(rsMetadata.getColumnDisplaySize(colIndex));
446

    
447
                } catch (java.sql.SQLException e) {
448
                        throw new JDBCSQLException(e);
449
                }
450

    
451
                return column;
452

    
453
        }
454

    
455
        /**
456
         * Fill <code>featureType</code> geometry attributes with SRS and ShapeType
457
         * information
458
         *
459
         * <b>Override this if provider has native eometry support</b>
460
         *
461
         * @param conn
462
         * @param rsMetadata
463
         * @param featureType
464
         * @throws ReadException
465
         */
466
        protected void loadSRS_and_shapeType(Connection conn,
467
                        ResultSetMetaData rsMetadata, EditableFeatureType featureType,
468
                        String baseSchema, String baseTable) throws JDBCException {
469

    
470
                // Nothing to do
471

    
472
        }
473

    
474
        public void loadFeatureType(EditableFeatureType featureType,
475
                        JDBCStoreParameters storeParams) throws DataException {
476
                if (storeParams.getSQL() != null
477
                                && storeParams.getSQL().trim().length() > 0) {
478
                        loadFeatureType(featureType, storeParams, storeParams.getSQL(),
479
                                        null, null);
480
                } else {
481
                        String sql = "Select * from " + storeParams.tableID()
482
                                        + " where false";
483
                        loadFeatureType(featureType, storeParams, sql, storeParams
484
                                        .getSchema(), storeParams.getTable());
485
                }
486
        }
487

    
488
        public void loadFeatureType(final EditableFeatureType featureType,
489
                        final JDBCStoreParameters storeParams, final String sql,
490
                        final String schema, final String table) throws DataException {
491
                this.open();
492
//                this.begin();
493
                getResource().execute(new ResourceAction() {
494
                        public Object run() throws Exception {
495
                                Connection conn = null;
496
                                try {
497
                                        conn = getConnection();
498
                                        
499
                                        String[] pks = storeParams.getPkFields();
500
                                        if (pks == null || pks.length < 1) {
501
                                                if (storeParams.getTable() != null
502
                                                                && storeParams.getTable().trim().length() > 0) {
503
                                                        pks = getPksFrom(conn, storeParams);
504
                                                        
505
                                                }
506
                                        }
507
                                        
508
                                        loadFeatureType(conn, featureType, sql, pks, storeParams
509
                                                        .getDefaultGeometryField(), schema, table);
510
                                        if (storeParams.getCRS()!=null){
511
                                                ((EditableFeatureAttributeDescriptor)featureType.getDefaultGeometryAttribute()).setSRS(storeParams.getCRS());
512
                                        }
513
                                        
514
                                } finally {
515
                                        try {
516
                                                conn.close();
517
                                        } catch (Exception e) {
518
                                        }
519
//                        this.end();
520
                                }
521
                                return null;
522
                        }
523
                });
524
        }
525

    
526
        protected String[] getPksFrom(Connection conn, JDBCStoreParameters params)
527
                throws JDBCException {
528
                try{
529
                        DatabaseMetaData metadata = conn.getMetaData();
530
                        ResultSet rsPrimaryKeys = null;
531
                        ResultSet rs = null;
532
                        String catalog = params.getCatalog();
533
                        String schema = params.getSchema();
534

    
535
                        try{
536
                                rs = metadata.getTables(catalog,
537
                                                schema, params.getTable(), null);
538

    
539
                                if (!rs.next()) {
540
                                        // No tables found with default values, ignoring catalog
541
                                        rs.close();
542
                                        catalog = null;
543
                                        schema = null;
544
                                        rs = metadata
545
                                                        .getTables(catalog, schema, params.getTable(), null);
546

    
547
                                        if (!rs.next()) {
548
                                                // table not found
549
                                                return null;
550
                                        } else if (rs.next()){
551
                                                // More that one, cant identify
552
                                                return null;
553
                                        }
554

    
555
                                } else if (rs.next()) {
556
                                        // More that one, cant identify
557
                                        return null;
558
                                }
559
                                rsPrimaryKeys = metadata.getPrimaryKeys(catalog, schema, params
560
                                                .getTable());
561
                                List pks = new ArrayList();
562
                                while (rsPrimaryKeys.next()){
563
                                        pks.add(rsPrimaryKeys.getString("COLUMN_NAME"));
564
                                }
565
                                return (String[]) pks.toArray(new String[pks.size()]);
566

    
567

    
568
                        } finally {
569
                                try{if (rs != null) {
570
                                        rs.close();
571
                                }} catch (SQLException ex) {logger.warn("Exception closing tables rs", ex);};
572
                                try{if (rsPrimaryKeys != null) {
573
                                        rsPrimaryKeys.close();
574
                                }} catch (SQLException ex) {logger.warn("Exception closing pk rs", ex);};
575
                        }
576

    
577

    
578
                } catch (SQLException e) {
579
                        logger.warn("Unable to get pk from DatabaseMetada", e);
580
                        return getPksFromInformationSchema(conn, params);
581
                }
582

    
583
        }
584

    
585
        protected String[] getPksFromInformationSchema(Connection conn,
586
                        JDBCStoreParameters params)
587
                        throws JDBCException {
588
                Statement st;
589
                StringBuffer sql = new StringBuffer();
590
                ResultSet rs;
591
                ArrayList list = new ArrayList();
592

    
593
                /*
594
                 select column_name as primary_key
595
                        from information_schema.table_constraints t_cons
596
                                inner join information_schema.key_column_usage c on
597
                                        c.constraint_catalog = t_cons.table_catalog and
598
                                    c.table_schema = t_cons.table_schema and
599
                                    c.table_name = t_cons.table_name and
600
                                        c.constraint_name = t_cons.constraint_name
601
                                where t_cons.table_schema = <schema>
602
                                and t_cons.constraint_catalog = <catalog>
603
                                 and t_cons.table_name = <table>
604
                                 and constraint_type = 'PRIMARY KEY'
605
                 */
606
                /*
607
                 * SELECT column_name FROM INFORMATION_SCHEMA.constraint_column_usage
608
                 * left join INFORMATION_SCHEMA.table_constraints on
609
                 * (INFORMATION_SCHEMA.table_constraints.constraint_name =
610
                 * INFORMATION_SCHEMA.constraint_column_usage.constraint_name and
611
                 * INFORMATION_SCHEMA.table_constraints.table_name =
612
                 * INFORMATION_SCHEMA.constraint_column_usage.table_name and
613
                 * INFORMATION_SCHEMA.table_constraints.table_schema =
614
                 * INFORMATION_SCHEMA.constraint_column_usage.table_schema) WHERE
615
                 * INFORMATION_SCHEMA.constraint_column_usage.table_name like
616
                 * 'muni10000_peq' AND
617
                 * INFORMATION_SCHEMA.constraint_column_usage.table_schema like 'public'
618
                 * AND INFORMATION_SCHEMA.constraint_column_usage.table_catalog like
619
                 * 'gis' AND constraint_type='PRIMARY KEY'
620
                 */
621

    
622
                sql.append("select column_name as primary_key ");
623
                sql.append("from information_schema.table_constraints t_cons ");
624
                sql.append("inner join information_schema.key_column_usage c on ");
625
                sql.append("c.constraint_catalog = t_cons.constraint_catalog and ");
626
                sql.append("c.table_schema = t_cons.table_schema and ");
627
                sql.append("c.table_name = t_cons.table_name and ");
628
                sql.append("c.constraint_name = t_cons.constraint_name ");
629
                sql.append("WHERE t_cons.table_name like '");
630

    
631
                sql.append(params.getTable());
632
                sql.append("' ");
633
                String schema = null;
634

    
635

    
636
                if (params.getSchema() == null || params.getSchema() == "") {
637
                        schema = getDefaultSchema(conn);
638
                } else {
639
                        schema = params.getSchema();
640
                }
641
                if (schema != null) {
642
                        sql.append(" and t_cons.table_schema like '");
643
                        sql.append(schema);
644
                        sql.append("' ");
645
                }
646

    
647
                if (params.getCatalog() != null && params.getCatalog() != "") {
648
                        sql
649
                                        .append(" and t_cons.constraint_catalog like '");
650
                        sql.append(params.getCatalog());
651
                        sql.append("' ");
652
                }
653

    
654
                sql.append("' and constraint_type = 'PRIMARY KEY'");
655

    
656
                // System.out.println(sql.toString());
657
                try {
658
                        st = conn.createStatement();
659
                        try {
660
                                rs = st.executeQuery(sql.toString());
661
                        } catch (java.sql.SQLException e) {
662
                                throw new JDBCExecuteSQLException(sql.toString(), e);
663
                        }
664
                        while (rs.next()) {
665
                                list.add(rs.getString(1));
666
                        }
667
                        rs.close();
668
                        st.close();
669

    
670
                } catch (java.sql.SQLException e) {
671
                        throw new JDBCSQLException(e);
672
                }
673
                if (list.size() == 0) {
674
                        return null;
675
                }
676

    
677
                return (String[]) list.toArray(new String[0]);
678

    
679
        }
680

    
681
        protected void loadFeatureType(Connection conn,
682
                        EditableFeatureType featureType, String sql, String[] pks,
683
                        String defGeomName, String schema, String table)
684
                        throws DataException {
685

    
686
                Statement stAux = null;
687
                ResultSet rs = null;
688
                try {
689

    
690
                        stAux = conn.createStatement();
691
                        stAux.setFetchSize(1);
692

    
693
                        try {
694
                                rs = stAux.executeQuery(sql);
695
                        } catch (SQLException e) {
696
                                throw new JDBCExecuteSQLException(sql, e);
697
                        }
698
                        ResultSetMetaData rsMetadata = rs.getMetaData();
699

    
700
                        List pksList = null;
701
                        if (pks != null) {
702
                                pksList = Arrays.asList(pks);
703

    
704
                        }
705

    
706
                        int i;
707
                        int geometriesColumns = 0;
708
                        String lastGeometry = null;
709

    
710
                        EditableFeatureAttributeDescriptor attr;
711
            boolean firstGeometryAttrFound = false;
712
                        for (i = 1; i <= rsMetadata.getColumnCount(); i++) {
713
                                attr = getAttributeFromJDBC(featureType, conn, rsMetadata, i);
714
                                if (pksList != null && pksList.contains(attr.getName())) {
715
                                        attr.setIsPrimaryKey(true);
716
                                }
717
                                if (attr.getType() == DataTypes.GEOMETRY) {
718
                    geometriesColumns++;
719
                    lastGeometry = attr.getName();
720
                    // Set the default geometry attribute if it is the one
721
                    // given as parameter or it is the first one, just in case.
722
                    if (!firstGeometryAttrFound
723
                        || lastGeometry.equals(defGeomName)) {
724
                        firstGeometryAttrFound = true;
725
                        featureType
726
                            .setDefaultGeometryAttributeName(lastGeometry);
727
                    }
728
                                }
729

    
730
                        }
731

    
732
                        if (geometriesColumns > 0) {
733
                                loadSRS_and_shapeType(conn, rsMetadata, featureType, schema,
734
                                                table);
735
                        }
736

    
737
                        if (defGeomName == null && geometriesColumns == 1) {
738
                                featureType.setDefaultGeometryAttributeName(lastGeometry);
739
                                defGeomName = lastGeometry;
740
                        }
741

    
742
                } catch (java.sql.SQLException e) {
743
                        throw new JDBCSQLException(e); // FIXME exception
744
                } finally {
745
                        try {
746
                                rs.close();
747
                        } catch (Exception e) {
748
                        }
749
                        try {
750
                                stAux.close();
751
                        } catch (Exception e) {
752
                        }
753

    
754
                }
755

    
756
        }
757

    
758
        /**
759
         * Override if provider has geometry support
760
         *
761
         * @param storeParams
762
         * @param geometryAttrName
763
         * @param limit
764
         * @return
765
         * @throws DataException
766
         */
767
        public Envelope getFullEnvelopeOfField(JDBCStoreParameters storeParams,
768
                        String geometryAttrName, Envelope limit) throws DataException {
769

    
770
                // TODO
771
                return null;
772

    
773
        }
774

    
775
        public Geometry getGeometry(byte[] buffer) throws BaseException {
776
                if (buffer == null) {
777
                        return null;
778
                }
779
                return geomManager.createFrom(buffer);
780
        }
781

    
782
        public String escapeFieldName(String field) {
783
                if (field.matches("[a-z][a-z0-9_]*")) {
784
                        return field;
785
                }
786
                String quote = getIdentifierQuoteString();
787
                return quote + field + quote;
788
        }
789

    
790
        public Object dalValueToJDBC(
791
                        FeatureAttributeDescriptor attributeDescriptor, Object object)
792
                        throws WriteException {
793
                if (object == null) {
794
                        return null;
795
                }
796

    
797
                if (attributeDescriptor.getType() != DataTypes.GEOMETRY) {
798
                        return object;
799
                }
800
                try {
801
                        byte[] wkb = null;
802
                        Geometry geom = (Geometry) object;
803
                        IProjection srs = attributeDescriptor.getSRS();
804
                        if (srs != null) {
805
                                wkb =  geom.convertToWKBForcingType(getProviderSRID(srs), attributeDescriptor.getGeomType().getType());
806
                        } else {
807
                                wkb =  geom.convertToWKB();
808
                        }
809
                        return wkb;
810
                } catch (Exception e) {
811
                        throw new WriteException(this.name, e);
812
                }
813
        }
814

    
815
        public String getSqlColumnTypeDescription(FeatureAttributeDescriptor attr) {
816
                switch (attr.getType()) {
817
                case DataTypes.STRING:
818
                        if (attr.getSize() < 1 || attr.getSize() > 255) {
819
                                return "text";
820
                        } else {
821
                                return "varchar(" + attr.getSize() + ")";
822
                        }
823
                case DataTypes.BOOLEAN:
824
                        return "bool";
825

    
826
                case DataTypes.BYTE:
827
                        return "smallint";
828

    
829
                case DataTypes.DATE:
830
                        return "date";
831

    
832
                case DataTypes.TIMESTAMP:
833
                        return "timestamp";
834

    
835
                case DataTypes.TIME:
836
                        return "time";
837

    
838
                case DataTypes.BYTEARRAY:
839
                case DataTypes.GEOMETRY:
840
                        return "blob";
841

    
842
                case DataTypes.DOUBLE:
843
//                        if (attr.getPrecision() > 0) {
844
//                            return "double precision(" + attr.getPrecision() + ')';
845
//                        } else {
846
                    //It works with PostgreSQL and MySQL. Check with others
847
                            return "double precision";
848
//                        }
849
                case DataTypes.FLOAT:
850
                        return "real";
851

    
852
                case DataTypes.INT:
853
                        if (attr.isAutomatic() && allowAutomaticValues()) {
854
                                return "serial";
855
                        } else {
856
                                return "integer";
857
                        }
858
                case DataTypes.LONG:
859
                        if (attr.isAutomatic()) {
860
                                return "bigserial";
861
                        } else {
862
                                return "bigint";
863
                        }
864

    
865
                default:
866
                        String typeName = (String) attr.getAdditionalInfo("SQLTypeName");
867
                        if (typeName != null) {
868
                                return typeName;
869
                        }
870

    
871
                        throw new UnsupportedDataTypeException(attr.getDataTypeName(), attr
872
                                        .getType());
873
                }
874
        }
875

    
876
        public int getProviderSRID(String srs) {
877
                return -1;
878
        }
879

    
880
        public int getProviderSRID(IProjection srs) {
881
                return -1;
882
        }
883

    
884
        public String getSqlFieldName(FeatureAttributeDescriptor attribute) {
885
                return escapeFieldName(attribute.getName());
886
        }
887

    
888
        public String getSqlFieldDescription(FeatureAttributeDescriptor attr)
889
                        throws DataException {
890

    
891
                /**
892
                 * column_name data_type [ DEFAULT default_expr ] [ column_constraint [
893
                 * ... ] ]
894
                 *
895
                 * where column_constraint is:
896
                 *
897
                 * [ CONSTRAINT constraint_name ] { NOT NULL | NULL | UNIQUE | PRIMARY
898
                 * KEY | CHECK (expression) | REFERENCES reftable [ ( refcolumn ) ] [
899
                 * MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON DELETE action ] [ ON
900
                 * UPDATE action ] } [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY
901
                 * DEFERRED | INITIALLY IMMEDIATE ]
902
                 */
903

    
904
                StringBuilder strb = new StringBuilder();
905
                // name
906
                strb.append(escapeFieldName(attr.getName()));
907
                strb.append(" ");
908

    
909
                // Type
910
                strb.append(this.getSqlColumnTypeDescription(attr));
911
                strb.append(" ");
912

    
913
                boolean allowNull = attr.allowNull()
914
                                && !(attr.isPrimaryKey() || attr.isAutomatic());
915
                // Default
916
                if (attr.getDefaultValue() == null) {
917
                        if (allowNull) {
918
                                strb.append("DEFAULT NULL ");
919
                        }
920
                } else {
921
                        String value = getDefaltFieldValueString(attr);
922
                        strb.append("DEFAULT '");
923
                        strb.append(value);
924
                        strb.append("' ");
925
                }
926

    
927
                // Null
928
                if (allowNull) {
929
                        strb.append("NULL ");
930
                } else {
931
                        strb.append("NOT NULL ");
932
                }
933

    
934
                // Primery key
935
                if (attr.isPrimaryKey()) {
936
                        strb.append("PRIMARY KEY ");
937
                }
938
                return strb.toString();
939
        }
940

    
941
        protected String getDefaltFieldValueString(FeatureAttributeDescriptor attr)
942
                        throws WriteException {
943
                return dalValueToJDBC(attr, attr.getDefaultValue()).toString();
944
        }
945

    
946
        public String compoundLimitAndOffset(long limit, long offset) {
947
                StringBuilder sql = new StringBuilder();
948
                // limit
949
                if (limit > 0) {
950
                        sql.append(" limit ");
951
                        sql.append(limit);
952
                        sql.append(' ');
953
                }
954

    
955
                // offset
956
                if (offset > 0) {
957
                        sql.append(" offset ");
958
                        sql.append(offset);
959
                        sql.append(' ');
960
                }
961
                return sql.toString();
962
        }
963

    
964
        public boolean supportOffset() {
965
                return true;
966
        }
967

    
968
        public List getAdditionalSqlToCreate(NewDataStoreParameters ndsp,
969
                        FeatureType fType) {
970
                // TODO Auto-generated method stub
971
                return null;
972
        }
973

    
974

    
975
        public String stringJoin(List listToJoin,String sep){
976
                StringBuilder strb = new StringBuilder();
977
                stringJoin(listToJoin,sep,strb);
978
                return strb.toString();
979
        }
980

    
981
        public void stringJoin(List listToJoin, String sep, StringBuilder strb) {
982
                if (listToJoin.size() < 1) {
983
                        return;
984
                }
985
                if (listToJoin.size() > 1) {
986
                        for (int i = 0; i < listToJoin.size() - 1; i++) {
987
                                strb.append(listToJoin.get(i));
988
                                strb.append(sep);
989
                        }
990
                }
991
                strb.append(listToJoin.get(listToJoin.size() - 1));
992
        }
993

    
994
        /**
995
         * Inform that provider has supports for geometry store and operations
996
         * natively
997
         *
998
         * @return
999
         */
1000
        protected boolean supportsGeometry() {
1001
                return false;
1002
        }
1003

    
1004
        public boolean allowAutomaticValues() {
1005
                if (allowAutomaticValues == null) {
1006
                        ConnectionAction action = new ConnectionAction(){
1007

    
1008
                                public Object action(Connection conn) throws DataException {
1009

    
1010
                                        ResultSet rs;
1011
                                        try {
1012
                                                DatabaseMetaData meta = conn.getMetaData();
1013
                                                rs = meta.getTypeInfo();
1014
                                                try{
1015
                                                        while (rs.next()) {
1016
                                                                if (rs.getInt("DATA_TYPE") == java.sql.Types.INTEGER) {
1017
                                                                        if (rs.getBoolean("AUTO_INCREMENT")) {
1018
                                                                                return Boolean.TRUE;
1019
                                                                        } else {
1020
                                                                                return Boolean.FALSE;
1021
                                                                        }
1022
                                                                }
1023
                                                        }
1024
                                                }finally{
1025
                                                        try{ rs.close();} catch (SQLException ex) {logger.error("Exception closing resulset", ex);};
1026
                                                }
1027
                                        } catch (SQLException e) {
1028
                                                throw new JDBCSQLException(e);
1029
                                        }
1030
                                        return Boolean.FALSE;
1031
                                }
1032

    
1033
                        };
1034

    
1035

    
1036

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

    
1047
        public boolean supportsUnion() {
1048
                if (supportsUnions == null) {
1049
                        ConnectionAction action = new ConnectionAction() {
1050

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

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

    
1061
                        };
1062

    
1063
                        try {
1064
                                supportsUnions = (Boolean) doConnectionAction(action);
1065
                        } catch (Exception e) {
1066
                                logger.error("Exception checking for unions support", e);
1067
                                supportsUnions = Boolean.FALSE;
1068
                        }
1069
                }
1070
                return supportsUnions.booleanValue();
1071
        }
1072

    
1073
        protected String getIdentifierQuoteString() {
1074
                if (identifierQuoteString == null) {
1075
                ConnectionAction action = new ConnectionAction() {
1076

    
1077
                        public Object action(Connection conn) throws DataException {
1078

    
1079
                                try {
1080
                                        DatabaseMetaData meta = conn.getMetaData();
1081
                                        return meta.getIdentifierQuoteString();
1082
                                } catch (SQLException e) {
1083
                                        throw new JDBCSQLException(e);
1084
                                }
1085
                        }
1086

    
1087
                };
1088

    
1089
                try {
1090
                        identifierQuoteString = (String) doConnectionAction(action);
1091
                } catch (Exception e) {
1092
                        logger.error("Exception checking for unions support", e);
1093
                        identifierQuoteString = " ";
1094
                        }
1095
                }
1096
                return identifierQuoteString;
1097
        }
1098

    
1099
        protected boolean isReservedWord(String field) {
1100
                // TODO
1101
                return false;
1102
        }
1103

    
1104
}