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

History | View | Annotate | Download (30.9 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.sql.Time;
33
import java.util.ArrayList;
34
import java.util.Arrays;
35
import java.util.Date;
36
import java.util.List;
37

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

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

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

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

    
94
        protected GeometryManager geomManager = null;
95

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

    
99
        private String identifierQuoteString;
100

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

    
109
        }
110

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

    
122
        }
123

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

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

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

    
136
        }
137

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

    
159
                                        user.opendDone();
160

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

    
172
        }
173

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

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

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

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

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

    
215
        }
216

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

    
223
        public boolean isOpen() {
224
                return isOpen;
225
        }
226

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

    
268
                                        result = action.action(conn);
269

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

    
278
                                        return result;
279

    
280
                                } catch (Exception e) {
281

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

    
291
                                } finally {
292
                                        try {
293
                                                if (conn != null) {
294
                                                        conn.close();
295
                                                }
296
                                        } catch (Exception e1) {
297
                                                logger.error("Exception on close connection", e1);
298
                                        }
299
                                        // this.end();
300
                                }
301
                        }
302
                });
303

    
304
        }
305

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

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

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

    
378
                default:
379
                    column = createAttributeFromJDBCNativeType(fType, rsMetadata, colIndex);
380
                        break;
381
                }
382

    
383
                return column;
384

    
385
        }
386
        
387
        
388
        protected EditableFeatureAttributeDescriptor createAttributeFromJDBCNativeType(
389
        EditableFeatureType fType, ResultSetMetaData rsMetadata, int colIndex)
390
        throws SQLException {
391
        EditableFeatureAttributeDescriptor column;
392
        column = fType.add(rsMetadata.getColumnName(colIndex),
393
                DataTypes.OBJECT);
394
        column.setAdditionalInfo("SQLType", new Integer(rsMetadata
395
                .getColumnType(colIndex)));
396
        column.setAdditionalInfo("SQLTypeName", rsMetadata
397
                .getColumnTypeName(colIndex));
398
        return column;
399
    }
400
        
401

    
402
        protected EditableFeatureAttributeDescriptor getAttributeFromJDBC(
403
                        EditableFeatureType fType, Connection conn,
404
                        ResultSetMetaData rsMetadata, int colIndex) throws JDBCException {
405
                EditableFeatureAttributeDescriptor column;
406
                try {
407

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

    
431
                } catch (java.sql.SQLException e) {
432
                        throw new JDBCSQLException(e);
433
                }
434

    
435
                return column;
436

    
437
        }
438

    
439
        /**
440
         * Fill <code>featureType</code> geometry attributes with SRS and ShapeType
441
         * information
442
         *
443
         * <b>Override this if provider has native eometry support</b>
444
         *
445
         * @param conn
446
         * @param rsMetadata
447
         * @param featureType
448
         * @throws ReadException
449
         */
450
        protected void loadSRS_and_shapeType(Connection conn,
451
                        ResultSetMetaData rsMetadata, EditableFeatureType featureType,
452
                        String baseSchema, String baseTable) throws JDBCException {
453

    
454
                // Nothing to do
455

    
456
        }
457

    
458
        public void loadFeatureType(EditableFeatureType featureType,
459
                        JDBCStoreParameters storeParams) throws DataException {
460
                if (storeParams.getSQL() != null
461
                                && storeParams.getSQL().trim().length() > 0) {
462
                        loadFeatureType(featureType, storeParams, storeParams.getSQL(),
463
                                        null, null);
464
                } else {
465
                        String sql = "Select * from " + storeParams.tableID()
466
                                        + " where false";
467
                        loadFeatureType(featureType, storeParams, sql, storeParams
468
                                        .getSchema(), storeParams.getTable());
469
                }
470
        }
471

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

    
510
        protected String[] getPksFrom(Connection conn, JDBCStoreParameters params)
511
                throws JDBCException {
512
                try{
513
                        DatabaseMetaData metadata = conn.getMetaData();
514
                        ResultSet rsPrimaryKeys = null;
515
                        ResultSet rs = null;
516
                        String catalog = params.getCatalog();
517
                        String schema = params.getSchema();
518

    
519
                        try{
520
                                rs = metadata.getTables(catalog,
521
                                                schema, params.getTable(), null);
522

    
523
                                if (!rs.next()) {
524
                                        // No tables found with default values, ignoring catalog
525
                                        rs.close();
526
                                        catalog = null;
527
                                        schema = null;
528
                                        rs = metadata
529
                                                        .getTables(catalog, schema, params.getTable(), null);
530

    
531
                                        if (!rs.next()) {
532
                                                // table not found
533
                                                return null;
534
                                        } else if (rs.next()){
535
                                                // More that one, cant identify
536
                                                return null;
537
                                        }
538

    
539
                                } else if (rs.next()) {
540
                                        // More that one, cant identify
541
                                        return null;
542
                                }
543
                                rsPrimaryKeys = metadata.getPrimaryKeys(catalog, schema, params
544
                                                .getTable());
545
                                List pks = new ArrayList();
546
                                while (rsPrimaryKeys.next()){
547
                                        pks.add(rsPrimaryKeys.getString("COLUMN_NAME"));
548
                                }
549
                                return (String[]) pks.toArray(new String[pks.size()]);
550

    
551

    
552
                        } finally {
553
                                try{if (rs != null) {
554
                                        rs.close();
555
                                }} catch (SQLException ex) {logger.warn("Exception closing tables rs", ex);};
556
                                try{if (rsPrimaryKeys != null) {
557
                                        rsPrimaryKeys.close();
558
                                }} catch (SQLException ex) {logger.warn("Exception closing pk rs", ex);};
559
                        }
560

    
561

    
562
                } catch (SQLException e) {
563
                        logger.warn("Unable to get pk from DatabaseMetada", e);
564
                        return getPksFromInformationSchema(conn, params);
565
                }
566

    
567
        }
568

    
569
        protected String[] getPksFromInformationSchema(Connection conn,
570
                        JDBCStoreParameters params)
571
                        throws JDBCException {
572
                Statement st;
573
                StringBuffer sql = new StringBuffer();
574
                ResultSet rs;
575
                ArrayList list = new ArrayList();
576

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

    
606
                sql.append("select column_name as primary_key ");
607
                sql.append("from information_schema.table_constraints t_cons ");
608
                sql.append("inner join information_schema.key_column_usage c on ");
609
                sql.append("c.constraint_catalog = t_cons.constraint_catalog and ");
610
                sql.append("c.table_schema = t_cons.table_schema and ");
611
                sql.append("c.table_name = t_cons.table_name and ");
612
                sql.append("c.constraint_name = t_cons.constraint_name ");
613
                sql.append("WHERE t_cons.table_name like '");
614

    
615
                sql.append(params.getTable());
616
                sql.append("' ");
617
                String schema = null;
618

    
619

    
620
                if (params.getSchema() == null || params.getSchema() == "") {
621
                        schema = getDefaultSchema(conn);
622
                } else {
623
                        schema = params.getSchema();
624
                }
625
                if (schema != null) {
626
                        sql.append(" and t_cons.table_schema like '");
627
                        sql.append(schema);
628
                        sql.append("' ");
629
                }
630

    
631
                if (params.getCatalog() != null && params.getCatalog() != "") {
632
                        sql
633
                                        .append(" and t_cons.constraint_catalog like '");
634
                        sql.append(params.getCatalog());
635
                        sql.append("' ");
636
                }
637

    
638
                sql.append("' and constraint_type = 'PRIMARY KEY'");
639

    
640
                // System.out.println(sql.toString());
641
                try {
642
                        st = conn.createStatement();
643
                        try {
644
                                rs = st.executeQuery(sql.toString());
645
                        } catch (java.sql.SQLException e) {
646
                                throw new JDBCExecuteSQLException(sql.toString(), e);
647
                        }
648
                        while (rs.next()) {
649
                                list.add(rs.getString(1));
650
                        }
651
                        rs.close();
652
                        st.close();
653

    
654
                } catch (java.sql.SQLException e) {
655
                        throw new JDBCSQLException(e);
656
                }
657
                if (list.size() == 0) {
658
                        return null;
659
                }
660

    
661
                return (String[]) list.toArray(new String[0]);
662

    
663
        }
664

    
665
        protected void loadFeatureType(Connection conn,
666
                        EditableFeatureType featureType, String sql, String[] pks,
667
                        String defGeomName, String schema, String table)
668
                        throws DataException {
669

    
670
                Statement stAux = null;
671
                ResultSet rs = null;
672
                try {
673

    
674
                        stAux = conn.createStatement();
675
                        stAux.setFetchSize(1);
676

    
677
                        try {
678
                                rs = stAux.executeQuery(sql);
679
                        } catch (SQLException e) {
680
                                throw new JDBCExecuteSQLException(sql, e);
681
                        }
682
                        ResultSetMetaData rsMetadata = rs.getMetaData();
683

    
684
                        List pksList = null;
685
                        if (pks != null) {
686
                                pksList = Arrays.asList(pks);
687

    
688
                        }
689

    
690
                        int i;
691
                        int geometriesColumns = 0;
692
                        String lastGeometry = null;
693

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

    
714
                        }
715

    
716
                        if (geometriesColumns > 0) {
717
                                loadSRS_and_shapeType(conn, rsMetadata, featureType, schema,
718
                                                table);
719
                        }
720

    
721
                        if (defGeomName == null && geometriesColumns == 1) {
722
                                featureType.setDefaultGeometryAttributeName(lastGeometry);
723
                                defGeomName = lastGeometry;
724
                        }
725

    
726
                } catch (java.sql.SQLException e) {
727
                        throw new JDBCSQLException(e); // FIXME exception
728
                } finally {
729
                        try {
730
                                rs.close();
731
                        } catch (Exception e) {
732
                        }
733
                        try {
734
                                stAux.close();
735
                        } catch (Exception e) {
736
                        }
737

    
738
                }
739

    
740
        }
741

    
742
        /**
743
         * Override if provider has geometry support
744
         *
745
         * @param storeParams
746
         * @param geometryAttrName
747
         * @param limit
748
         * @return
749
         * @throws DataException
750
         */
751
        public Envelope getFullEnvelopeOfField(JDBCStoreParameters storeParams,
752
                        String geometryAttrName, Envelope limit) throws DataException {
753

    
754
                // TODO
755
                return null;
756

    
757
        }
758

    
759
        public Geometry getGeometry(byte[] buffer) throws BaseException {
760
                if (buffer == null) {
761
                        return null;
762
                }
763
                return geomManager.createFrom(buffer);
764
        }
765

    
766
        public String escapeFieldName(String field) {
767
                if (field.matches("[a-z][a-z0-9_]*")) {
768
                        return field;
769
                }
770
                String quote = getIdentifierQuoteString();
771
                return quote + field + quote;
772
        }
773

    
774
        public class DalValueToJDBCException extends WriteException {
775

    
776
                /**
777
                 * 
778
                 */
779
                private static final long serialVersionUID = -3608973505723097889L;
780
                private final static String MESSAGE_FORMAT = "Can't convert value of attribute '%(attributeName)' to JDBC type (attribute type '%(attributeType)', value class '%(valueClass)').";
781
                private final static String MESSAGE_KEY = "_Cant_convert_value_of_attribute_XattributeNameX_to_JDBC_type_attribute_type_XattributeTypeX_value_class_XvalueClassX";
782

    
783
                public DalValueToJDBCException(FeatureAttributeDescriptor attributeDescriptor, Object object, Throwable cause) {
784
                        super(MESSAGE_FORMAT, cause, MESSAGE_KEY, serialVersionUID);
785
                        if( attributeDescriptor != null ) {
786
                                setValue("attributeName",attributeDescriptor.getName());
787
                                setValue("attributetype",attributeDescriptor.getDataTypeName());
788
                        } else {
789
                                setValue("attributeName","unknown");
790
                                setValue("attributetype","unknown");
791
                        }
792
                        if( object!=null ) {
793
                                setValue("valueClass", object.getClass().getName());
794
                        } else {
795
                                setValue("valueClass", "null");
796
                        }
797
                }
798

    
799
        }
800

    
801
        public Object dalValueToJDBC(
802
                        FeatureAttributeDescriptor attributeDescriptor, Object object)
803
                        throws WriteException {
804
                try {
805
                        if (object == null) {
806
                                return null;
807
                        }
808
        
809
                        if (attributeDescriptor.getType() == DataTypes.TIME) {
810
                            return new Time(((Date)object).getTime());
811
                        }
812
                        if (attributeDescriptor.getType() != DataTypes.GEOMETRY) {
813
                                return object;
814
                        }
815
                        byte[] wkb = null;
816
                        Geometry geom = (Geometry) object;
817
                        IProjection srs = attributeDescriptor.getSRS();
818
                        if (srs != null) {
819
                                wkb =  geom.convertToWKBForcingType(getProviderSRID(srs), attributeDescriptor.getGeomType().getType());
820
                        } else {
821
                                wkb =  geom.convertToWKB();
822
                        }
823
                        return wkb;
824
                } catch (Exception e) {
825
                        throw new DalValueToJDBCException(attributeDescriptor, object,e);
826
                }
827
        }
828

    
829
        public String getSqlColumnTypeDescription(FeatureAttributeDescriptor attr) {
830
                switch (attr.getType()) {
831
                case DataTypes.STRING:
832
                        if (attr.getSize() < 1 || attr.getSize() > 255) {
833
                                return "text";
834
                        } else {
835
                                return "varchar(" + attr.getSize() + ")";
836
                        }
837
                case DataTypes.BOOLEAN:
838
                        return "bool";
839

    
840
                case DataTypes.BYTE:
841
                        return "smallint";
842

    
843
                case DataTypes.DATE:
844
                        return "date";
845

    
846
                case DataTypes.TIMESTAMP:
847
                        return "timestamp";
848

    
849
                case DataTypes.TIME:
850
                        return "time";
851

    
852
                case DataTypes.BYTEARRAY:
853
                case DataTypes.GEOMETRY:
854
                        return "blob";
855

    
856
                case DataTypes.DOUBLE:
857
//                        if (attr.getPrecision() > 0) {
858
//                            return "double precision(" + attr.getPrecision() + ')';
859
//                        } else {
860
                    //It works with PostgreSQL and MySQL. Check with others
861
                            return "double precision";
862
//                        }
863
                case DataTypes.FLOAT:
864
                        return "real";
865

    
866
                case DataTypes.INT:
867
                        if (attr.isAutomatic() && allowAutomaticValues()) {
868
                                return "serial";
869
                        } else {
870
                                return "integer";
871
                        }
872
                case DataTypes.LONG:
873
                        if (attr.isAutomatic()) {
874
                                return "bigserial";
875
                        } else {
876
                                return "bigint";
877
                        }
878

    
879
                default:
880
                        String typeName = (String) attr.getAdditionalInfo("SQLTypeName");
881
                        if (typeName != null) {
882
                                return typeName;
883
                        }
884

    
885
                        throw new UnsupportedDataTypeException(attr.getDataTypeName(), attr
886
                                        .getType());
887
                }
888
        }
889

    
890
        public int getProviderSRID(String srs) {
891
                return -1;
892
        }
893

    
894
        public int getProviderSRID(IProjection srs) {
895
                return -1;
896
        }
897

    
898
        public String getSqlFieldName(FeatureAttributeDescriptor attribute) {
899
                return escapeFieldName(attribute.getName());
900
        }
901

    
902
        public String getSqlFieldDescription(FeatureAttributeDescriptor attr)
903
                        throws DataException {
904

    
905
                /**
906
                 * column_name data_type [ DEFAULT default_expr ] [ column_constraint [
907
                 * ... ] ]
908
                 *
909
                 * where column_constraint is:
910
                 *
911
                 * [ CONSTRAINT constraint_name ] { NOT NULL | NULL | UNIQUE | PRIMARY
912
                 * KEY | CHECK (expression) | REFERENCES reftable [ ( refcolumn ) ] [
913
                 * MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON DELETE action ] [ ON
914
                 * UPDATE action ] } [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY
915
                 * DEFERRED | INITIALLY IMMEDIATE ]
916
                 */
917

    
918
                StringBuilder strb = new StringBuilder();
919
                // name
920
                strb.append(escapeFieldName(attr.getName()));
921
                strb.append(" ");
922

    
923
                // Type
924
                strb.append(this.getSqlColumnTypeDescription(attr));
925
                strb.append(" ");
926

    
927
                boolean allowNull = attr.allowNull()
928
                                && !(attr.isPrimaryKey() || attr.isAutomatic());
929
                // Default
930
                if (attr.getDefaultValue() == null) {
931
                        if (allowNull) {
932
                                strb.append("DEFAULT NULL ");
933
                        }
934
                } else {
935
                        String value = getDefaltFieldValueString(attr);
936
                        strb.append("DEFAULT '");
937
                        strb.append(value);
938
                        strb.append("' ");
939
                }
940

    
941
                // Null
942
                if (allowNull) {
943
                        strb.append("NULL ");
944
                } else {
945
                        strb.append("NOT NULL ");
946
                }
947

    
948
                // Primery key
949
                if (attr.isPrimaryKey()) {
950
                        strb.append("PRIMARY KEY ");
951
                }
952
                return strb.toString();
953
        }
954

    
955
        /**
956
         * @deprecated use getDefaultFieldValueString this has a type writer error.
957
         */
958
        protected String getDefaltFieldValueString(FeatureAttributeDescriptor attr)
959
                        throws WriteException {
960
                return getDefaultFieldValueString(attr);
961
        }
962

    
963
        protected String getDefaultFieldValueString(FeatureAttributeDescriptor attr)
964
                        throws WriteException {
965
                return dalValueToJDBC(attr, attr.getDefaultValue()).toString();
966
        }
967

    
968
        public String compoundLimitAndOffset(long limit, long offset) {
969
                StringBuilder sql = new StringBuilder();
970
                // limit
971
                if (limit > 0) {
972
                        sql.append(" limit ");
973
                        sql.append(limit);
974
                        sql.append(' ');
975
                }
976

    
977
                // offset
978
                if (offset > 0) {
979
                        sql.append(" offset ");
980
                        sql.append(offset);
981
                        sql.append(' ');
982
                }
983
                return sql.toString();
984
        }
985

    
986
        public boolean supportOffset() {
987
                return true;
988
        }
989

    
990
        public List getAdditionalSqlToCreate(NewDataStoreParameters ndsp,
991
                        FeatureType fType) {
992
                // TODO Auto-generated method stub
993
                return null;
994
        }
995

    
996

    
997
        public String stringJoin(List listToJoin,String sep){
998
                StringBuilder strb = new StringBuilder();
999
                stringJoin(listToJoin,sep,strb);
1000
                return strb.toString();
1001
        }
1002

    
1003
        public void stringJoin(List listToJoin, String sep, StringBuilder strb) {
1004
                if (listToJoin.size() < 1) {
1005
                        return;
1006
                }
1007
                if (listToJoin.size() > 1) {
1008
                        for (int i = 0; i < listToJoin.size() - 1; i++) {
1009
                                strb.append(listToJoin.get(i));
1010
                                strb.append(sep);
1011
                        }
1012
                }
1013
                strb.append(listToJoin.get(listToJoin.size() - 1));
1014
        }
1015

    
1016
        /**
1017
         * Inform that provider has supports for geometry store and operations
1018
         * natively
1019
         *
1020
         * @return
1021
         */
1022
        protected boolean supportsGeometry() {
1023
                return false;
1024
        }
1025

    
1026
        public boolean allowAutomaticValues() {
1027
                if (allowAutomaticValues == null) {
1028
                        ConnectionAction action = new ConnectionAction(){
1029

    
1030
                                public Object action(Connection conn) throws DataException {
1031

    
1032
                                        ResultSet rs;
1033
                                        try {
1034
                                                DatabaseMetaData meta = conn.getMetaData();
1035
                                                rs = meta.getTypeInfo();
1036
                                                try{
1037
                                                        while (rs.next()) {
1038
                                                                if (rs.getInt("DATA_TYPE") == java.sql.Types.INTEGER) {
1039
                                                                        if (rs.getBoolean("AUTO_INCREMENT")) {
1040
                                                                                return Boolean.TRUE;
1041
                                                                        } else {
1042
                                                                                return Boolean.FALSE;
1043
                                                                        }
1044
                                                                }
1045
                                                        }
1046
                                                }finally{
1047
                                                        try{ rs.close();} catch (SQLException ex) {logger.error("Exception closing resulset", ex);};
1048
                                                }
1049
                                        } catch (SQLException e) {
1050
                                                throw new JDBCSQLException(e);
1051
                                        }
1052
                                        return Boolean.FALSE;
1053
                                }
1054

    
1055
                        };
1056

    
1057

    
1058

    
1059
                        try {
1060
                                allowAutomaticValues = (Boolean) doConnectionAction(action);
1061
                        } catch (Exception e) {
1062
                                logger.error("Exception checking for automatic integers", e);
1063
                                allowAutomaticValues = Boolean.FALSE;
1064
                        }
1065
                }
1066
                return allowAutomaticValues.booleanValue();
1067
        }
1068

    
1069
        public boolean supportsUnion() {
1070
                if (supportsUnions == null) {
1071
                        ConnectionAction action = new ConnectionAction() {
1072

    
1073
                                public Object action(Connection conn) throws DataException {
1074

    
1075
                                        try {
1076
                                                DatabaseMetaData meta = conn.getMetaData();
1077
                                                return new Boolean(meta.supportsUnion());
1078
                                        } catch (SQLException e) {
1079
                                                throw new JDBCSQLException(e);
1080
                                        }
1081
                                }
1082

    
1083
                        };
1084

    
1085
                        try {
1086
                                supportsUnions = (Boolean) doConnectionAction(action);
1087
                        } catch (Exception e) {
1088
                                logger.error("Exception checking for unions support", e);
1089
                                supportsUnions = Boolean.FALSE;
1090
                        }
1091
                }
1092
                return supportsUnions.booleanValue();
1093
        }
1094

    
1095
        protected String getIdentifierQuoteString() {
1096
                if (identifierQuoteString == null) {
1097
                ConnectionAction action = new ConnectionAction() {
1098

    
1099
                        public Object action(Connection conn) throws DataException {
1100

    
1101
                                try {
1102
                                        DatabaseMetaData meta = conn.getMetaData();
1103
                                        return meta.getIdentifierQuoteString();
1104
                                } catch (SQLException e) {
1105
                                        throw new JDBCSQLException(e);
1106
                                }
1107
                        }
1108

    
1109
                };
1110

    
1111
                try {
1112
                        identifierQuoteString = (String) doConnectionAction(action);
1113
                } catch (Exception e) {
1114
                        logger.error("Exception checking for unions support", e);
1115
                        identifierQuoteString = " ";
1116
                        }
1117
                }
1118
                return identifierQuoteString;
1119
        }
1120

    
1121
        protected boolean isReservedWord(String field) {
1122
                // TODO
1123
                return false;
1124
        }
1125

    
1126
}