Statistics
| Revision:

svn-gvsig-desktop / branches / v2_0_0_prep / libraries / libFMap_daldb / src / org / gvsig / fmap / dal / store / jdbc / JDBCHelper.java @ 28967

History | View | Annotate | Download (26.9 KB)

1
/* gvSIG. Geographic Information System of the Valencian Government
2
*
3
* Copyright (C) 2007-2008 Infrastructures and Transports Department
4
* of the Valencian Government (CIT)
5
*
6
* This program is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU General Public License
8
* as published by the Free Software Foundation; either version 2
9
* of the License, or (at your option) any later version.
10
*
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
* GNU General Public License for more details.
15
*
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
* MA  02110-1301, USA.
20
*
21
*/
22

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

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

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

    
43
import org.cresques.cts.IProjection;
44
import org.gvsig.fmap.dal.DALLocator;
45
import org.gvsig.fmap.dal.DataTypes;
46
import org.gvsig.fmap.dal.NewDataStoreParameters;
47
import org.gvsig.fmap.dal.exception.CloseException;
48
import org.gvsig.fmap.dal.exception.DataException;
49
import org.gvsig.fmap.dal.exception.InitializeException;
50
import org.gvsig.fmap.dal.exception.OpenException;
51
import org.gvsig.fmap.dal.exception.ReadException;
52
import org.gvsig.fmap.dal.exception.WriteException;
53
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
54
import org.gvsig.fmap.dal.feature.EditableFeatureType;
55
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
56
import org.gvsig.fmap.dal.feature.FeatureType;
57
import org.gvsig.fmap.dal.feature.exception.UnsupportedDataTypeException;
58
import org.gvsig.fmap.dal.resource.exception.AccessResourceException;
59
import org.gvsig.fmap.dal.resource.exception.ResourceBeginException;
60
import org.gvsig.fmap.dal.resource.spi.ResourceConsumer;
61
import org.gvsig.fmap.dal.resource.spi.ResourceManagerProviderServices;
62
import org.gvsig.fmap.dal.resource.spi.ResourceProvider;
63
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCException;
64
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCExecuteSQLException;
65
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCSQLException;
66
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCTransactionCommitException;
67
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCTransactionRollbackException;
68
import org.gvsig.fmap.geom.Geometry;
69
import org.gvsig.fmap.geom.GeometryLocator;
70
import org.gvsig.fmap.geom.operation.fromwkb.FromWKB;
71
import org.gvsig.fmap.geom.operation.fromwkb.FromWKBGeometryOperationContext;
72
import org.gvsig.fmap.geom.operation.towkb.ToWKB;
73
import org.gvsig.fmap.geom.operation.towkb.ToWKBOperationContext;
74
import org.gvsig.fmap.geom.primitive.Envelope;
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 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 FromWKB fromWKB = null;
95
        protected FromWKBGeometryOperationContext fromWKBContext = null;
96
        protected ToWKBOperationContext toWKBContext = new ToWKBOperationContext();
97

    
98
        private Boolean allowAutomaticValues = null;
99
        private Boolean supportsUnions = null;
100

    
101
        protected JDBCHelper(JDBCHelperUser consumer,
102
                        JDBCConnectionParameters params) throws InitializeException {
103

    
104
                this.user = consumer;
105
                this.name = user.getName();
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
                                .createResource(
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 (ResourceBeginException e1) {
151
                        throw new OpenException(name, e1);
152
                }
153
                try {
154
                        resource.connect();
155
                        resource.notifyOpen();
156

    
157
                        this.user.opendDone();
158

    
159
                        isOpen = true;
160

    
161
                        return true;
162
                } catch (DataException e) {
163
                        throw new OpenException(name, e);
164
                } finally {
165
                        end();
166
                }
167

    
168
        }
169

    
170
        public void close() throws CloseException {
171
                if (!isOpen) {
172
                        return;
173
                }
174
                try {
175
                        begin();
176
                } catch (ResourceBeginException e) {
177
                        throw new CloseException(name, e);
178
                }
179
                try {
180

    
181
                        isOpen = false;
182

    
183
                        resource.notifyClose();
184
                        this.user.closeDone();
185
                } catch (DataException e) {
186
                        throw new CloseException(this.name, e);
187
                } finally {
188
                        end();
189
                }
190
        }
191

    
192
        public void end() {
193
                resource.end();
194
        }
195

    
196
        public void begin() throws ResourceBeginException {
197
                this.resource.begin();
198
        }
199

    
200
        public Connection getConnection() throws AccessResourceException {
201
                return resource.getJDBCConnection();
202

    
203
        }
204

    
205
        public void dispose() {
206
                resource.removeConsumer(this);
207
        }
208

    
209
        public boolean isOpen() {
210
                return isOpen;
211
        }
212

    
213
        /**
214
         * Executes an atomic action that uses an DB Connection.<br>
215
         *
216
         * This methos prepares a connection and close it at the end of execution of
217
         * action.<br>
218
         *
219
         * if <code>action</code> is an instance of {@link TransactionalAction} the
220
         * action will be execute inside of a DB transaction.
221
         *
222
         *
223
         * @param action
224
         * @throws Exception
225
         */
226
        public Object doConnectionAction(ConnectionAction action) throws Exception {
227
                Object result = null;
228
                Connection conn = null;
229
                boolean beginTrans = false;
230
                this.open();
231
                this.begin();
232
                try {
233

    
234
                        conn = this.getConnection();
235
                        if (action instanceof TransactionalAction) {
236
                                // XXX OJO esta condicion NO ES FIABLE
237
                                if (!conn.getAutoCommit()) {
238
                                        if (!((TransactionalAction) action)
239
                                                        .continueTransactionAllowed()) {
240
                                                // FIXME exception
241
                                                throw new Exception();
242
                                        }
243
                                }
244
                                try {
245
                                        conn.setAutoCommit(false);
246
                                } catch (SQLException e) {
247
                                        throw new JDBCSQLException(e);
248
                                }
249
                                beginTrans = true;
250
                        }
251

    
252
                        result = action.action(conn);
253

    
254
                        if (beginTrans) {
255
                                try {
256
                                        conn.commit();
257
                                } catch (SQLException e) {
258
                                        throw new JDBCTransactionCommitException(e);
259
                                }
260
                        }
261

    
262
                        return result;
263

    
264
                } catch (Exception e) {
265

    
266
                        if (beginTrans) {
267
                                try {
268
                                        conn.rollback();
269
                                } catch (Exception e1) {
270
                                        throw new JDBCTransactionRollbackException(e1, e);
271
                                }
272
                        }
273
                        throw e;
274

    
275
                } finally {
276
                        try {
277
                                conn.close();
278
                        } catch (Exception e1) {
279
                                logger.error("Exception on close connection", e1);
280
                        }
281
                        this.end();
282
                }
283

    
284
        }
285

    
286
        protected String getDefaultSchema(Connection conn) throws JDBCException {
287
                return defaultSchema;
288
        }
289

    
290
        protected EditableFeatureAttributeDescriptor createAttributeFromJDBC(
291
                        EditableFeatureType fType, Connection conn,
292
                        ResultSetMetaData rsMetadata, int colIndex)
293
                        throws java.sql.SQLException {
294

    
295
                EditableFeatureAttributeDescriptor column;
296
                switch (rsMetadata.getColumnType(colIndex)) {
297
                case java.sql.Types.INTEGER:
298
                        column = fType.add(rsMetadata.getColumnName(colIndex),
299
                                        DataTypes.INT);
300
                        break;
301
                case java.sql.Types.BIGINT:
302
                        column = fType.add(rsMetadata.getColumnName(colIndex),
303
                                        DataTypes.LONG);
304
                        break;
305
                case java.sql.Types.REAL:
306
                        column = fType.add(rsMetadata.getColumnName(colIndex),
307
                                        DataTypes.DOUBLE);
308
                        break;
309
                case java.sql.Types.DOUBLE:
310
                        column = fType.add(rsMetadata.getColumnName(colIndex),
311
                                        DataTypes.DOUBLE);
312
                        break;
313
                case java.sql.Types.CHAR:
314
                        column = fType.add(rsMetadata.getColumnName(colIndex),
315
                                        DataTypes.STRING);
316
                        break;
317
                case java.sql.Types.VARCHAR:
318
                case java.sql.Types.LONGVARCHAR:
319
                        column = fType.add(rsMetadata.getColumnName(colIndex),
320
                                        DataTypes.STRING);
321
                        break;
322
                case java.sql.Types.FLOAT:
323
                        column = fType.add(rsMetadata.getColumnName(colIndex),
324
                                        DataTypes.FLOAT);
325
                        break;
326
                case java.sql.Types.DECIMAL:
327
                        column = fType.add(rsMetadata.getColumnName(colIndex),
328
                                        DataTypes.FLOAT);
329
                        break;
330
                case java.sql.Types.DATE:
331
                        column = fType.add(rsMetadata.getColumnName(colIndex),
332
                                        DataTypes.DATE);
333
                        break;
334
                case java.sql.Types.TIME:
335
                        column = fType.add(rsMetadata.getColumnName(colIndex),
336
                                        DataTypes.TIME);
337
                        break;
338
                case java.sql.Types.TIMESTAMP:
339
                        column = fType.add(rsMetadata.getColumnName(colIndex),
340
                                        DataTypes.TIMESTAMP);
341
                        break;
342
                case java.sql.Types.BOOLEAN:
343
                        column = fType.add(rsMetadata.getColumnName(colIndex),
344
                                        DataTypes.BOOLEAN);
345
                        break;
346
                case java.sql.Types.BLOB:
347
                case java.sql.Types.BINARY:
348
                case java.sql.Types.LONGVARBINARY:
349
                        column = fType.add(rsMetadata.getColumnName(colIndex),
350
                                        DataTypes.BYTEARRAY);
351
                        break;
352

    
353
                default:
354
                        column = fType.add(rsMetadata.getColumnName(colIndex),
355
                                        DataTypes.OBJECT);
356
                        column.setAdditionalInfo("SQLType", new Integer(rsMetadata
357
                                        .getColumnType(colIndex)));
358
                        column.setAdditionalInfo("SQLTypeName", rsMetadata
359
                                        .getColumnTypeName(colIndex));
360

    
361
                        break;
362
                }
363

    
364
                return column;
365

    
366
        }
367

    
368
        protected EditableFeatureAttributeDescriptor getAttributeFromJDBC(
369
                        EditableFeatureType fType, Connection conn,
370
                        ResultSetMetaData rsMetadata, int colIndex) throws JDBCException {
371
                EditableFeatureAttributeDescriptor column;
372
                try {
373

    
374
                        column = createAttributeFromJDBC(fType, conn, rsMetadata, colIndex);
375
                        // column.setCaseSensitive(rsMetadata.isCaseSensitive(colIndex));
376
                        // column.setSqlType(rsMetadata.getColumnType(colIndex));
377
                        column.setAllowNull(
378
                                        rsMetadata.isNullable(colIndex) == ResultSetMetaData.columnNullable);
379
                        column.setIsAutomatic(rsMetadata.isAutoIncrement(colIndex));
380
                        column.setIsReadOnly(rsMetadata.isReadOnly(colIndex));
381
                        // column.setWritable(rsMetadata.isWritable(colIndex));
382
                        // column.setClassName(rsMetadata.getColumnClassName(colIndex));
383
                        // column.setCatalogName(rsMetadata.getCatalogName(colIndex));
384
                        // column.setDefinitelyWritable(rsMetadata
385
                        // .isDefinitelyWritable(colIndex));
386
                        // column.setLabel(rsMetadata.getColumnLabel(colIndex));
387
                        // column.setSchemaName(rsMetadata.getSchemaName(colIndex));
388
                        // column.setTableName(rsMetadata.getTableName(colIndex));
389
                        // column.setCatalogName(rsMetadata.getCatalogName(colIndex));
390
                        // column.setSqlTypeName();
391
                        // column.setSearchable(rsMetadata.isSearchable(colIndex));
392
                        // column.setSigned(rsMetadata.isSigned(colIndex));
393
                        // column.setCurrency(rsMetadata.isCurrency(colIndex));
394
                        column.setPrecision(rsMetadata.getPrecision(colIndex));
395
                        column.setSize(rsMetadata.getColumnDisplaySize(colIndex));
396

    
397
                } catch (java.sql.SQLException e) {
398
                        throw new JDBCSQLException(e);
399
                }
400

    
401
                return column;
402

    
403
        }
404

    
405
        /**
406
         * Fill <code>featureType</code> geometry attributes with SRS and ShapeType
407
         * information
408
         *
409
         * <b>Override this if provider has native eometry support</b>
410
         *
411
         * @param conn
412
         * @param rsMetadata
413
         * @param featureType
414
         * @throws ReadException
415
         */
416
        protected void loadSRS_and_shapeType(Connection conn,
417
                        ResultSetMetaData rsMetadata, EditableFeatureType featureType,
418
                        String baseSchema, String baseTable) throws JDBCException {
419

    
420
                // Nothing to do
421

    
422
        }
423

    
424
        public void loadFeatureType(EditableFeatureType featureType,
425
                        JDBCStoreParameters storeParams) throws DataException {
426
                if (storeParams.getSQL() != null
427
                                && storeParams.getSQL().trim().length() == 0) {
428
                        loadFeatureType(featureType, storeParams, storeParams.getSQL(),
429
                                        null, null);
430
                } else {
431
                        String sql = "Select * from " + storeParams.tableID()
432
                                        + " where false";
433
                        loadFeatureType(featureType, storeParams, sql, storeParams
434
                                        .getSchema(), storeParams.getTable());
435
                }
436
        }
437

    
438
        public void loadFeatureType(EditableFeatureType featureType,
439
                        JDBCStoreParameters storeParams, String sql, String schema,
440
                        String table) throws DataException {
441
                Connection conn = null;
442
                this.open();
443
                this.begin();
444
                try {
445
                        conn = getConnection();
446

    
447
                        String[] pks = storeParams.getPkFields();
448
                        if (pks == null || pks.length < 1) {
449
                                if (storeParams.getTable() != null
450
                                                && storeParams.getTable().trim().length() > 0) {
451
                                        pks = getPksFrom(conn, storeParams);
452

    
453
                                }
454
                        }
455

    
456
                        loadFeatureType(conn, featureType, sql, pks, storeParams
457
                                        .getDefaultGeometry(), schema, table);
458

    
459
                } finally {
460
                        try {
461
                                conn.close();
462
                        } catch (Exception e) {
463
                        }
464
                        ;
465
                        this.end();
466
                }
467
        }
468

    
469
        protected String[] getPksFrom(Connection conn, JDBCStoreParameters params)
470
                throws JDBCException {
471
                try{
472
                        DatabaseMetaData metadata = conn.getMetaData();
473
                        ResultSet rsPrimaryKeys = null;
474
                        ResultSet rs = null;
475
                        String catalog = params.getCatalog();
476
                        String schema = params.getSchema();
477

    
478
                        try{
479
                                rs = metadata.getTables(catalog,
480
                                                schema, params.getTable(), null);
481

    
482
                                if (!rs.next()) {
483
                                        // No tables found with default values, ignoring catalog
484
                                        rs.close();
485
                                        catalog = null;
486
                                        schema = null;
487
                                        rs = metadata
488
                                                        .getTables(catalog, schema, params.getTable(), null);
489

    
490
                                        if (!rs.next()) {
491
                                                // table not found
492
                                                return null;
493
                                        } else if (rs.next()){
494
                                                // More that one, cant identify
495
                                                return null;
496
                                        }
497

    
498
                                } else if (rs.next()) {
499
                                        // More that one, cant identify
500
                                        return null;
501
                                }
502
                                rsPrimaryKeys = metadata.getPrimaryKeys(catalog, schema, params
503
                                                .getTable());
504
                                List pks = new ArrayList();
505
                                while (rsPrimaryKeys.next()){
506
                                        pks.add(rsPrimaryKeys.getString("COLUMN_NAME"));
507
                                }
508
                                return (String[]) pks.toArray(new String[pks.size()]);
509

    
510

    
511
                        } finally {
512
                                try{if (rs != null) {
513
                                        rs.close();
514
                                }} catch (SQLException ex) {logger.warn("Exception closing tables rs", ex);};
515
                                try{if (rsPrimaryKeys != null) {
516
                                        rsPrimaryKeys.close();
517
                                }} catch (SQLException ex) {logger.warn("Exception closing pk rs", ex);};
518
                        }
519

    
520

    
521
                } catch (SQLException e) {
522
                        logger.warn("Unable to get pk from DatabaseMetada", e);
523
                        return getPksFromInformationSchema(conn, params);
524
                }
525

    
526
        }
527

    
528
        protected String[] getPksFromInformationSchema(Connection conn,
529
                        JDBCStoreParameters params)
530
                        throws JDBCException {
531
                Statement st;
532
                StringBuffer sql = new StringBuffer();
533
                ResultSet rs;
534
                ArrayList list = new ArrayList();
535

    
536
                /*
537
                 select column_name as primary_key
538
                        from information_schema.table_constraints t_cons
539
                                inner join information_schema.key_column_usage c on
540
                                        c.constraint_catalog = t_cons.table_catalog and
541
                                    c.table_schema = t_cons.table_schema and
542
                                    c.table_name = t_cons.table_name and
543
                                        c.constraint_name = t_cons.constraint_name
544
                                where t_cons.table_schema = <schema>
545
                                and t_cons.constraint_catalog = <catalog>
546
                                 and t_cons.table_name = <table>
547
                                 and constraint_type = 'PRIMARY KEY'
548
                 */
549
                /*
550
                 * SELECT column_name FROM INFORMATION_SCHEMA.constraint_column_usage
551
                 * left join INFORMATION_SCHEMA.table_constraints on
552
                 * (INFORMATION_SCHEMA.table_constraints.constraint_name =
553
                 * INFORMATION_SCHEMA.constraint_column_usage.constraint_name and
554
                 * INFORMATION_SCHEMA.table_constraints.table_name =
555
                 * INFORMATION_SCHEMA.constraint_column_usage.table_name and
556
                 * INFORMATION_SCHEMA.table_constraints.table_schema =
557
                 * INFORMATION_SCHEMA.constraint_column_usage.table_schema) WHERE
558
                 * INFORMATION_SCHEMA.constraint_column_usage.table_name like
559
                 * 'muni10000_peq' AND
560
                 * INFORMATION_SCHEMA.constraint_column_usage.table_schema like 'public'
561
                 * AND INFORMATION_SCHEMA.constraint_column_usage.table_catalog like
562
                 * 'gis' AND constraint_type='PRIMARY KEY'
563
                 */
564

    
565
                sql.append("select column_name as primary_key ");
566
                sql.append("from information_schema.table_constraints t_cons ");
567
                sql.append("inner join information_schema.key_column_usage c on ");
568
                sql.append("c.constraint_catalog = t_cons.constraint_catalog and ");
569
                sql.append("c.table_schema = t_cons.table_schema and ");
570
                sql.append("c.table_name = t_cons.table_name and ");
571
                sql.append("c.constraint_name = t_cons.constraint_name ");
572
                sql.append("WHERE t_cons.table_name like '");
573

    
574
                sql.append(params.getTable());
575
                sql.append("' ");
576
                String schema = null;
577

    
578

    
579
                if (params.getSchema() == null || params.getSchema() == "") {
580
                        schema = getDefaultSchema(conn);
581
                } else {
582
                        schema = params.getSchema();
583
                }
584
                if (schema != null) {
585
                        sql.append(" and t_cons.table_schema like '");
586
                        sql.append(schema);
587
                        sql.append("' ");
588
                }
589

    
590
                if (params.getCatalog() != null && params.getCatalog() != "") {
591
                        sql
592
                                        .append(" and t_cons.constraint_catalog like '");
593
                        sql.append(params.getCatalog());
594
                        sql.append("' ");
595
                }
596

    
597
                sql.append("' and constraint_type = 'PRIMARY KEY'");
598

    
599
                // System.out.println(sql.toString());
600
                try {
601
                        st = conn.createStatement();
602
                        try {
603
                                rs = st.executeQuery(sql.toString());
604
                        } catch (java.sql.SQLException e) {
605
                                throw new JDBCExecuteSQLException(sql.toString(), e);
606
                        }
607
                        while (rs.next()) {
608
                                list.add(rs.getString(1));
609
                        }
610
                        rs.close();
611
                        st.close();
612

    
613
                } catch (java.sql.SQLException e) {
614
                        throw new JDBCSQLException(e);
615
                }
616
                if (list.size() == 0) {
617
                        return null;
618
                }
619

    
620
                return (String[]) list.toArray(new String[0]);
621

    
622
        }
623

    
624
        protected void loadFeatureType(Connection conn,
625
                        EditableFeatureType featureType, String sql, String[] pks,
626
                        String defGeomName, String schema, String table)
627
                        throws DataException {
628

    
629
                Statement stAux = null;
630
                ResultSet rs = null;
631
                try {
632

    
633
                        stAux = conn.createStatement();
634
                        stAux.setFetchSize(1);
635

    
636
                        try {
637
                                rs = stAux.executeQuery(sql);
638
                        } catch (SQLException e) {
639
                                throw new JDBCExecuteSQLException(sql, e);
640
                        }
641
                        ResultSetMetaData rsMetadata = rs.getMetaData();
642

    
643
                        List pksList = null;
644
                        if (pks != null) {
645
                                pksList = Arrays.asList(pks);
646

    
647
                        }
648

    
649
                        int i;
650
                        int geometriesColumns = 0;
651
                        String lastGeometry = null;
652

    
653
                        EditableFeatureAttributeDescriptor attr;
654
                        for (i = 1; i <= rsMetadata.getColumnCount(); i++) {
655
                                attr = getAttributeFromJDBC(featureType, conn, rsMetadata, i);
656
                                if (pksList != null && pksList.contains(attr.getName())) {
657
                                        attr.setIsPrimaryKey(true);
658
                                }
659
                                if (attr.getDataType() == DataTypes.GEOMETRY) {
660
                                        geometriesColumns++;
661
                                        lastGeometry = attr.getName();
662
                                        if (lastGeometry.equals(defGeomName)) {
663
                                                featureType
664
                                                                .setDefaultGeometryAttributeName(defGeomName);
665
                                        }
666

    
667
                                }
668

    
669
                        }
670

    
671
                        if (geometriesColumns > 0) {
672
                                loadSRS_and_shapeType(conn, rsMetadata, featureType, schema,
673
                                                table);
674
                        }
675

    
676
                        if (defGeomName == null && geometriesColumns == 1) {
677
                                featureType.setDefaultGeometryAttributeName(lastGeometry);
678
                                defGeomName = lastGeometry;
679
                        }
680

    
681
                } catch (java.sql.SQLException e) {
682
                        throw new JDBCSQLException(e); // FIXME exception
683
                } finally {
684
                        try {
685
                                rs.close();
686
                        } catch (Exception e) {
687
                        }
688
                        try {
689
                                stAux.close();
690
                        } catch (Exception e) {
691
                        }
692

    
693
                }
694

    
695
        }
696

    
697
        /**
698
         * Override if provider has geometry support
699
         *
700
         * @param storeParams
701
         * @param geometryAttrName
702
         * @param limit
703
         * @return
704
         * @throws DataException
705
         */
706
        public Envelope getFullEnvelopeOfField(JDBCStoreParameters storeParams,
707
                        String geometryAttrName, Envelope limit) throws DataException {
708

    
709
                // TODO
710
                return null;
711

    
712
        }
713

    
714
        protected void initializeFromWKBOperation() throws BaseException {
715
                if (fromWKB == null) {
716
                        fromWKB = (FromWKB) GeometryLocator.getGeometryManager()
717
                                        .getGeometryOperation(FromWKB.CODE,
718
                                                        Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2D);
719
                        fromWKBContext = new FromWKBGeometryOperationContext();
720

    
721
                }
722
        }
723

    
724
        public Geometry getGeometry(byte[] buffer) throws BaseException {
725
                if (buffer == null) {
726
                        return null;
727
                }
728
                initializeFromWKBOperation();
729
                Geometry geom;
730
                try {
731
                        fromWKBContext.setData(buffer);
732

    
733
                        geom = (Geometry) fromWKB.invoke(null, fromWKBContext);
734
                } finally {
735
                        fromWKBContext.setData(null);
736
                }
737
                return geom;
738
        }
739

    
740
        public String escapeFieldName(String field) {
741
                return field;
742
        }
743

    
744
        public Object dalValueToJDBC(
745
                        FeatureAttributeDescriptor attributeDescriptor, Object object)
746
                        throws WriteException {
747
                if (object == null) {
748
                        return null;
749
                }
750

    
751
                if (attributeDescriptor.getDataType() != DataTypes.GEOMETRY) {
752
                        return object;
753
                }
754
                try {
755
                        Geometry geom = (Geometry) object;
756

    
757
                        toWKBContext.setSrID(-1);
758
                        IProjection srs = attributeDescriptor.getSRS();
759
                        if (srs != null) {
760
                                toWKBContext.setSrID(getProviderSRID(srs));
761
                        }
762

    
763
                        // TODO optimize this
764
                        // byte[] wkb = (byte[])
765
                        // geom.invokeOperation(ToWKBNative.CODE,toWKBContext);
766
                        byte[] wkb = (byte[]) geom.invokeOperation(ToWKB.CODE,
767
                                        toWKBContext);
768
                        if (wkb == null) {
769
                                // FIXME excpetion
770
                                throw new IllegalArgumentException();
771
                        }
772

    
773
                        return wkb;
774
                } catch (Exception e) {
775
                        throw new WriteException(this.name, e);
776
                }
777
        }
778

    
779
        public String getSqlColumnTypeDescription(FeatureAttributeDescriptor attr) {
780
                switch (attr.getDataType()) {
781
                case DataTypes.STRING:
782
                        if (attr.getSize() < 1 || attr.getSize() > 255) {
783
                                return "text";
784
                        } else {
785
                                return "varchar(" + attr.getSize() + ")";
786
                        }
787
                case DataTypes.BOOLEAN:
788
                        return "bool";
789

    
790
                case DataTypes.BYTE:
791
                        return "smallint";
792

    
793
                case DataTypes.DATE:
794
                        return "date";
795

    
796
                case DataTypes.TIMESTAMP:
797
                        return "timestamp";
798

    
799
                case DataTypes.TIME:
800
                        return "time";
801

    
802
                case DataTypes.BYTEARRAY:
803
                case DataTypes.GEOMETRY:
804
                        return "blob";
805

    
806
                case DataTypes.DOUBLE:
807
                        // if (attr.getPrecision() > 0) {
808
                        // return "double precision(" + attr.getPrecision() + ')';
809
                        // } else {
810
                        return "double";
811
                        // }
812
                case DataTypes.FLOAT:
813
                        return "real";
814

    
815
                case DataTypes.INT:
816
                        if (attr.isAutomatic() && allowAutomaticValues()) {
817
                                return "serial";
818
                        } else {
819
                                return "integer";
820
                        }
821
                case DataTypes.LONG:
822
                        if (attr.isAutomatic()) {
823
                                return "bigserial";
824
                        } else {
825
                                return "bigint";
826
                        }
827

    
828
                default:
829
                        String typeName = (String) attr.getAdditionalInfo("SQLTypeName");
830
                        if (typeName != null) {
831
                                return typeName;
832
                        }
833

    
834
                        throw new UnsupportedDataTypeException(attr.getDataTypeName(), attr
835
                                        .getDataType());
836
                }
837
        }
838

    
839
        public int getProviderSRID(String srs) {
840
                return -1;
841
        }
842

    
843
        public int getProviderSRID(IProjection srs) {
844
                return -1;
845
        }
846

    
847
        public String getSqlFieldName(FeatureAttributeDescriptor attribute) {
848
                return escapeFieldName(attribute.getName());
849
        }
850

    
851
        public String getSqlFieldDescription(FeatureAttributeDescriptor attr)
852
                        throws DataException {
853

    
854
                /**
855
                 * column_name data_type [ DEFAULT default_expr ] [ column_constraint [
856
                 * ... ] ]
857
                 *
858
                 * where column_constraint is:
859
                 *
860
                 * [ CONSTRAINT constraint_name ] { NOT NULL | NULL | UNIQUE | PRIMARY
861
                 * KEY | CHECK (expression) | REFERENCES reftable [ ( refcolumn ) ] [
862
                 * MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON DELETE action ] [ ON
863
                 * UPDATE action ] } [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY
864
                 * DEFERRED | INITIALLY IMMEDIATE ]
865
                 */
866

    
867
                StringBuilder strb = new StringBuilder();
868
                // name
869
                strb.append(escapeFieldName(attr.getName()));
870
                strb.append(" ");
871

    
872
                // Type
873
                strb.append(this.getSqlColumnTypeDescription(attr));
874
                strb.append(" ");
875

    
876
                boolean allowNull = attr.allowNull()
877
                                && !(attr.isPrimaryKey() || attr.isAutomatic());
878
                // Default
879
                if (attr.getDefaultValue() == null) {
880
                        if (allowNull) {
881
                                strb.append("DEFAULT NULL ");
882
                        }
883
                } else {
884
                        String value = getDefaltFieldValueString(attr);
885
                        strb.append("DEFAULT '");
886
                        strb.append(value);
887
                        strb.append("' ");
888
                }
889

    
890
                // Null
891
                if (allowNull) {
892
                        strb.append("NULL ");
893
                } else {
894
                        strb.append("NOT NULL ");
895
                }
896

    
897
                // Primery key
898
                if (attr.isPrimaryKey()) {
899
                        strb.append("PRIMARY KEY ");
900
                }
901
                return strb.toString();
902
        }
903

    
904
        protected String getDefaltFieldValueString(FeatureAttributeDescriptor attr)
905
                        throws WriteException {
906
                return dalValueToJDBC(attr, attr.getDefaultValue()).toString();
907
        }
908

    
909
        public String compoundLimitAndOffset(long limit, long offset) {
910
                StringBuilder sql = new StringBuilder();
911
                // limit
912
                if (limit >= 1) {
913
                        sql.append(" limit ");
914
                        sql.append(limit);
915
                        sql.append(' ');
916
                }
917

    
918
                // offset
919
                if (offset >= 1) {
920
                        sql.append(" offset ");
921
                        sql.append(offset);
922
                        sql.append(' ');
923
                }
924
                return sql.toString();
925
        }
926

    
927
        public boolean supportOffset() {
928
                return true;
929
        }
930

    
931
        public List getAdditionalSqlToCreate(NewDataStoreParameters ndsp,
932
                        FeatureType fType) {
933
                // TODO Auto-generated method stub
934
                return null;
935
        }
936

    
937

    
938
        public String stringJoin(List listToJoin,String sep){
939
                StringBuilder strb = new StringBuilder();
940
                stringJoin(listToJoin,sep,strb);
941
                return strb.toString();
942
        }
943

    
944
        public void stringJoin(List listToJoin, String sep, StringBuilder strb) {
945
                if (listToJoin.size() < 1) {
946
                        return;
947
                }
948
                if (listToJoin.size() > 1) {
949
                        for (int i = 0; i < listToJoin.size() - 1; i++) {
950
                                strb.append(listToJoin.get(i));
951
                                strb.append(sep);
952
                        }
953
                }
954
                strb.append(listToJoin.get(listToJoin.size() - 1));
955
        }
956
        /**
957
         * Inform that provider has supports for geometry store and operations
958
         * natively
959
         *
960
         * @return
961
         */
962
        boolean hasGeometrySupport() {
963
                return false;
964
        }
965

    
966
        public boolean allowAutomaticValues() {
967
                if (allowAutomaticValues == null) {
968
                        ConnectionAction action = new ConnectionAction(){
969

    
970
                                public Object action(Connection conn) throws DataException {
971

    
972
                                        ResultSet rs;
973
                                        try {
974
                                                DatabaseMetaData meta = conn.getMetaData();
975
                                                rs = meta.getTypeInfo();
976
                                                try{
977
                                                        while (rs.next()) {
978
                                                                if (rs.getInt("DATA_TYPE") == java.sql.Types.INTEGER) {
979
                                                                        if (rs.getBoolean("AUTO_INCREMENT")) {
980
                                                                                return Boolean.TRUE;
981
                                                                        } else {
982
                                                                                return Boolean.FALSE;
983
                                                                        }
984
                                                                }
985
                                                        }
986
                                                }finally{
987
                                                        try{ rs.close();} catch (SQLException ex) {logger.error("Exception closing resulset", ex);};
988
                                                }
989
                                        } catch (SQLException e) {
990
                                                throw new JDBCSQLException(e);
991
                                        }
992
                                        return Boolean.FALSE;
993
                                }
994

    
995
                        };
996

    
997

    
998

    
999
                        try {
1000
                                allowAutomaticValues = (Boolean) doConnectionAction(action);
1001
                        } catch (Exception e) {
1002
                                logger.error("Exception checking for automatic integers", e);
1003
                                allowAutomaticValues = Boolean.FALSE;
1004
                        }
1005
                }
1006
                return allowAutomaticValues.booleanValue();
1007
        }
1008

    
1009
        public boolean supportsUnion() {
1010
                if (supportsUnions == null) {
1011
                        ConnectionAction action = new ConnectionAction() {
1012

    
1013
                                public Object action(Connection conn) throws DataException {
1014

    
1015
                                        try {
1016
                                                DatabaseMetaData meta = conn.getMetaData();
1017
                                                return new Boolean(meta.supportsUnion());
1018
                                        } catch (SQLException e) {
1019
                                                throw new JDBCSQLException(e);
1020
                                        }
1021
                                }
1022

    
1023
                        };
1024

    
1025
                        try {
1026
                                supportsUnions = (Boolean) doConnectionAction(action);
1027
                        } catch (Exception e) {
1028
                                logger.error("Exception checking for unions support", e);
1029
                                supportsUnions = Boolean.FALSE;
1030
                        }
1031
                }
1032
                return supportsUnions.booleanValue();
1033
        }
1034
}