Statistics
| Revision:

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

History | View | Annotate | Download (28.6 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.ResourceAction;
59
import org.gvsig.fmap.dal.resource.exception.AccessResourceException;
60
import org.gvsig.fmap.dal.resource.exception.ResourceExecuteException;
61
import org.gvsig.fmap.dal.resource.spi.ResourceConsumer;
62
import org.gvsig.fmap.dal.resource.spi.ResourceManagerProviderServices;
63
import org.gvsig.fmap.dal.resource.spi.ResourceProvider;
64
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCException;
65
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCExecuteSQLException;
66
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCSQLException;
67
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCTransactionCommitException;
68
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCTransactionRollbackException;
69
import org.gvsig.fmap.geom.Geometry;
70
import org.gvsig.fmap.geom.GeometryLocator;
71
import org.gvsig.fmap.geom.operation.fromwkb.FromWKB;
72
import org.gvsig.fmap.geom.operation.fromwkb.FromWKBGeometryOperationContext;
73
import org.gvsig.fmap.geom.operation.towkb.ToWKB;
74
import org.gvsig.fmap.geom.operation.towkb.ToWKBOperationContext;
75
import org.gvsig.fmap.geom.primitive.Envelope;
76
import org.gvsig.tools.exception.BaseException;
77
import org.slf4j.Logger;
78
import org.slf4j.LoggerFactory;
79

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

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

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

    
95
        protected FromWKB fromWKB = null;
96
        protected FromWKBGeometryOperationContext fromWKBContext = null;
97
        protected ToWKBOperationContext toWKBContext = new ToWKBOperationContext();
98

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

    
102
        private String identifierQuoteString;
103

    
104
        protected JDBCHelper(JDBCHelperUser consumer,
105
                        JDBCConnectionParameters params) throws InitializeException {
106

    
107
                this.user = consumer;
108
                this.name = user.getName();
109
                this.params = params;
110
                initializeResource();
111

    
112
        }
113

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

    
125
        }
126

    
127
        protected final void setResource(JDBCResource resource) {
128
                this.resource = resource;
129
                this.resource.addConsumer(this);
130
        }
131

    
132
        public boolean closeResourceRequested(ResourceProvider resource) {
133
                return user.closeResourceRequested(resource);
134
        }
135

    
136
        public void resourceChanged(ResourceProvider resource) {
137
                user.resourceChanged(resource);
138

    
139
        }
140

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

    
162
                                        user.opendDone();
163

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

    
175
        }
176

    
177
        public JDBCResource getResource() {
178
                return resource;
179
        }
180

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

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

    
207
        // public void end() {
208
        // resource.end();
209
        // }
210
        //
211
        // public void begin() throws ResourceExecuteException {
212
        // this.resource.begin();
213
        // }
214

    
215
        public Connection getConnection() throws AccessResourceException {
216
                return resource.getJDBCConnection();
217

    
218
        }
219

    
220
        public void dispose() {
221
                resource.removeConsumer(this);
222
        }
223

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

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

    
269
                                        result = action.action(conn);
270

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

    
279
                                        return result;
280

    
281
                                } catch (Exception e) {
282

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

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

    
303
        }
304

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

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

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

    
372
                default:
373
                        column = fType.add(rsMetadata.getColumnName(colIndex),
374
                                        DataTypes.OBJECT);
375
                        column.setAdditionalInfo("SQLType", new Integer(rsMetadata
376
                                        .getColumnType(colIndex)));
377
                        column.setAdditionalInfo("SQLTypeName", rsMetadata
378
                                        .getColumnTypeName(colIndex));
379

    
380
                        break;
381
                }
382

    
383
                return column;
384

    
385
        }
386

    
387
        protected EditableFeatureAttributeDescriptor getAttributeFromJDBC(
388
                        EditableFeatureType fType, Connection conn,
389
                        ResultSetMetaData rsMetadata, int colIndex) throws JDBCException {
390
                EditableFeatureAttributeDescriptor column;
391
                try {
392

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

    
416
                } catch (java.sql.SQLException e) {
417
                        throw new JDBCSQLException(e);
418
                }
419

    
420
                return column;
421

    
422
        }
423

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

    
439
                // Nothing to do
440

    
441
        }
442

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

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

    
492
        protected String[] getPksFrom(Connection conn, JDBCStoreParameters params)
493
                throws JDBCException {
494
                try{
495
                        DatabaseMetaData metadata = conn.getMetaData();
496
                        ResultSet rsPrimaryKeys = null;
497
                        ResultSet rs = null;
498
                        String catalog = params.getCatalog();
499
                        String schema = params.getSchema();
500

    
501
                        try{
502
                                rs = metadata.getTables(catalog,
503
                                                schema, params.getTable(), null);
504

    
505
                                if (!rs.next()) {
506
                                        // No tables found with default values, ignoring catalog
507
                                        rs.close();
508
                                        catalog = null;
509
                                        schema = null;
510
                                        rs = metadata
511
                                                        .getTables(catalog, schema, params.getTable(), null);
512

    
513
                                        if (!rs.next()) {
514
                                                // table not found
515
                                                return null;
516
                                        } else if (rs.next()){
517
                                                // More that one, cant identify
518
                                                return null;
519
                                        }
520

    
521
                                } else if (rs.next()) {
522
                                        // More that one, cant identify
523
                                        return null;
524
                                }
525
                                rsPrimaryKeys = metadata.getPrimaryKeys(catalog, schema, params
526
                                                .getTable());
527
                                List pks = new ArrayList();
528
                                while (rsPrimaryKeys.next()){
529
                                        pks.add(rsPrimaryKeys.getString("COLUMN_NAME"));
530
                                }
531
                                return (String[]) pks.toArray(new String[pks.size()]);
532

    
533

    
534
                        } finally {
535
                                try{if (rs != null) {
536
                                        rs.close();
537
                                }} catch (SQLException ex) {logger.warn("Exception closing tables rs", ex);};
538
                                try{if (rsPrimaryKeys != null) {
539
                                        rsPrimaryKeys.close();
540
                                }} catch (SQLException ex) {logger.warn("Exception closing pk rs", ex);};
541
                        }
542

    
543

    
544
                } catch (SQLException e) {
545
                        logger.warn("Unable to get pk from DatabaseMetada", e);
546
                        return getPksFromInformationSchema(conn, params);
547
                }
548

    
549
        }
550

    
551
        protected String[] getPksFromInformationSchema(Connection conn,
552
                        JDBCStoreParameters params)
553
                        throws JDBCException {
554
                Statement st;
555
                StringBuffer sql = new StringBuffer();
556
                ResultSet rs;
557
                ArrayList list = new ArrayList();
558

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

    
588
                sql.append("select column_name as primary_key ");
589
                sql.append("from information_schema.table_constraints t_cons ");
590
                sql.append("inner join information_schema.key_column_usage c on ");
591
                sql.append("c.constraint_catalog = t_cons.constraint_catalog and ");
592
                sql.append("c.table_schema = t_cons.table_schema and ");
593
                sql.append("c.table_name = t_cons.table_name and ");
594
                sql.append("c.constraint_name = t_cons.constraint_name ");
595
                sql.append("WHERE t_cons.table_name like '");
596

    
597
                sql.append(params.getTable());
598
                sql.append("' ");
599
                String schema = null;
600

    
601

    
602
                if (params.getSchema() == null || params.getSchema() == "") {
603
                        schema = getDefaultSchema(conn);
604
                } else {
605
                        schema = params.getSchema();
606
                }
607
                if (schema != null) {
608
                        sql.append(" and t_cons.table_schema like '");
609
                        sql.append(schema);
610
                        sql.append("' ");
611
                }
612

    
613
                if (params.getCatalog() != null && params.getCatalog() != "") {
614
                        sql
615
                                        .append(" and t_cons.constraint_catalog like '");
616
                        sql.append(params.getCatalog());
617
                        sql.append("' ");
618
                }
619

    
620
                sql.append("' and constraint_type = 'PRIMARY KEY'");
621

    
622
                // System.out.println(sql.toString());
623
                try {
624
                        st = conn.createStatement();
625
                        try {
626
                                rs = st.executeQuery(sql.toString());
627
                        } catch (java.sql.SQLException e) {
628
                                throw new JDBCExecuteSQLException(sql.toString(), e);
629
                        }
630
                        while (rs.next()) {
631
                                list.add(rs.getString(1));
632
                        }
633
                        rs.close();
634
                        st.close();
635

    
636
                } catch (java.sql.SQLException e) {
637
                        throw new JDBCSQLException(e);
638
                }
639
                if (list.size() == 0) {
640
                        return null;
641
                }
642

    
643
                return (String[]) list.toArray(new String[0]);
644

    
645
        }
646

    
647
        protected void loadFeatureType(Connection conn,
648
                        EditableFeatureType featureType, String sql, String[] pks,
649
                        String defGeomName, String schema, String table)
650
                        throws DataException {
651

    
652
                Statement stAux = null;
653
                ResultSet rs = null;
654
                try {
655

    
656
                        stAux = conn.createStatement();
657
                        stAux.setFetchSize(1);
658

    
659
                        try {
660
                                rs = stAux.executeQuery(sql);
661
                        } catch (SQLException e) {
662
                                throw new JDBCExecuteSQLException(sql, e);
663
                        }
664
                        ResultSetMetaData rsMetadata = rs.getMetaData();
665

    
666
                        List pksList = null;
667
                        if (pks != null) {
668
                                pksList = Arrays.asList(pks);
669

    
670
                        }
671

    
672
                        int i;
673
                        int geometriesColumns = 0;
674
                        String lastGeometry = null;
675

    
676
                        EditableFeatureAttributeDescriptor attr;
677
                        for (i = 1; i <= rsMetadata.getColumnCount(); i++) {
678
                                attr = getAttributeFromJDBC(featureType, conn, rsMetadata, i);
679
                                if (pksList != null && pksList.contains(attr.getName())) {
680
                                        attr.setIsPrimaryKey(true);
681
                                }
682
                                if (attr.getDataType() == DataTypes.GEOMETRY) {
683
                                        geometriesColumns++;
684
                                        lastGeometry = attr.getName();
685
                                        if (lastGeometry.equals(defGeomName)) {
686
                                                featureType
687
                                                                .setDefaultGeometryAttributeName(defGeomName);
688
                                        }
689

    
690
                                }
691

    
692
                        }
693

    
694
                        if (geometriesColumns > 0) {
695
                                loadSRS_and_shapeType(conn, rsMetadata, featureType, schema,
696
                                                table);
697
                        }
698

    
699
                        if (defGeomName == null && geometriesColumns == 1) {
700
                                featureType.setDefaultGeometryAttributeName(lastGeometry);
701
                                defGeomName = lastGeometry;
702
                        }
703

    
704
                } catch (java.sql.SQLException e) {
705
                        throw new JDBCSQLException(e); // FIXME exception
706
                } finally {
707
                        try {
708
                                rs.close();
709
                        } catch (Exception e) {
710
                        }
711
                        try {
712
                                stAux.close();
713
                        } catch (Exception e) {
714
                        }
715

    
716
                }
717

    
718
        }
719

    
720
        /**
721
         * Override if provider has geometry support
722
         *
723
         * @param storeParams
724
         * @param geometryAttrName
725
         * @param limit
726
         * @return
727
         * @throws DataException
728
         */
729
        public Envelope getFullEnvelopeOfField(JDBCStoreParameters storeParams,
730
                        String geometryAttrName, Envelope limit) throws DataException {
731

    
732
                // TODO
733
                return null;
734

    
735
        }
736

    
737
        protected void initializeFromWKBOperation() throws BaseException {
738
                if (fromWKB == null) {
739
                        fromWKB = (FromWKB) GeometryLocator.getGeometryManager()
740
                                        .getGeometryOperation(FromWKB.CODE,
741
                                                        Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2D);
742
                        fromWKBContext = new FromWKBGeometryOperationContext();
743

    
744
                }
745
        }
746

    
747
        public Geometry getGeometry(byte[] buffer) throws BaseException {
748
                if (buffer == null) {
749
                        return null;
750
                }
751
                initializeFromWKBOperation();
752
                Geometry geom;
753
                try {
754
                        fromWKBContext.setData(buffer);
755

    
756
                        geom = (Geometry) fromWKB.invoke(null, fromWKBContext);
757
                } finally {
758
                        fromWKBContext.setData(null);
759
                }
760
                return geom;
761
        }
762

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

    
771
        public Object dalValueToJDBC(
772
                        FeatureAttributeDescriptor attributeDescriptor, Object object)
773
                        throws WriteException {
774
                if (object == null) {
775
                        return null;
776
                }
777

    
778
                if (attributeDescriptor.getDataType() != DataTypes.GEOMETRY) {
779
                        return object;
780
                }
781
                try {
782
                        Geometry geom = (Geometry) object;
783

    
784
                        toWKBContext.setSrID(-1);
785
                        IProjection srs = attributeDescriptor.getSRS();
786
                        if (srs != null) {
787
                                toWKBContext.setSrID(getProviderSRID(srs));
788
                        }
789

    
790
                        // TODO optimize this
791
                        // byte[] wkb = (byte[])
792
                        // geom.invokeOperation(ToWKBNative.CODE,toWKBContext);
793
                        byte[] wkb = (byte[]) geom.invokeOperation(ToWKB.CODE,
794
                                        toWKBContext);
795
                        if (wkb == null) {
796
                                // FIXME excpetion
797
                                throw new IllegalArgumentException();
798
                        }
799

    
800
                        return wkb;
801
                } catch (Exception e) {
802
                        throw new WriteException(this.name, e);
803
                }
804
        }
805

    
806
        public String getSqlColumnTypeDescription(FeatureAttributeDescriptor attr) {
807
                switch (attr.getDataType()) {
808
                case DataTypes.STRING:
809
                        if (attr.getSize() < 1 || attr.getSize() > 255) {
810
                                return "text";
811
                        } else {
812
                                return "varchar(" + attr.getSize() + ")";
813
                        }
814
                case DataTypes.BOOLEAN:
815
                        return "bool";
816

    
817
                case DataTypes.BYTE:
818
                        return "smallint";
819

    
820
                case DataTypes.DATE:
821
                        return "date";
822

    
823
                case DataTypes.TIMESTAMP:
824
                        return "timestamp";
825

    
826
                case DataTypes.TIME:
827
                        return "time";
828

    
829
                case DataTypes.BYTEARRAY:
830
                case DataTypes.GEOMETRY:
831
                        return "blob";
832

    
833
                case DataTypes.DOUBLE:
834
                        // if (attr.getPrecision() > 0) {
835
                        // return "double precision(" + attr.getPrecision() + ')';
836
                        // } else {
837
                        return "double";
838
                        // }
839
                case DataTypes.FLOAT:
840
                        return "real";
841

    
842
                case DataTypes.INT:
843
                        if (attr.isAutomatic() && allowAutomaticValues()) {
844
                                return "serial";
845
                        } else {
846
                                return "integer";
847
                        }
848
                case DataTypes.LONG:
849
                        if (attr.isAutomatic()) {
850
                                return "bigserial";
851
                        } else {
852
                                return "bigint";
853
                        }
854

    
855
                default:
856
                        String typeName = (String) attr.getAdditionalInfo("SQLTypeName");
857
                        if (typeName != null) {
858
                                return typeName;
859
                        }
860

    
861
                        throw new UnsupportedDataTypeException(attr.getDataTypeName(), attr
862
                                        .getDataType());
863
                }
864
        }
865

    
866
        public int getProviderSRID(String srs) {
867
                return -1;
868
        }
869

    
870
        public int getProviderSRID(IProjection srs) {
871
                return -1;
872
        }
873

    
874
        public String getSqlFieldName(FeatureAttributeDescriptor attribute) {
875
                return escapeFieldName(attribute.getName());
876
        }
877

    
878
        public String getSqlFieldDescription(FeatureAttributeDescriptor attr)
879
                        throws DataException {
880

    
881
                /**
882
                 * column_name data_type [ DEFAULT default_expr ] [ column_constraint [
883
                 * ... ] ]
884
                 *
885
                 * where column_constraint is:
886
                 *
887
                 * [ CONSTRAINT constraint_name ] { NOT NULL | NULL | UNIQUE | PRIMARY
888
                 * KEY | CHECK (expression) | REFERENCES reftable [ ( refcolumn ) ] [
889
                 * MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON DELETE action ] [ ON
890
                 * UPDATE action ] } [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY
891
                 * DEFERRED | INITIALLY IMMEDIATE ]
892
                 */
893

    
894
                StringBuilder strb = new StringBuilder();
895
                // name
896
                strb.append(escapeFieldName(attr.getName()));
897
                strb.append(" ");
898

    
899
                // Type
900
                strb.append(this.getSqlColumnTypeDescription(attr));
901
                strb.append(" ");
902

    
903
                boolean allowNull = attr.allowNull()
904
                                && !(attr.isPrimaryKey() || attr.isAutomatic());
905
                // Default
906
                if (attr.getDefaultValue() == null) {
907
                        if (allowNull) {
908
                                strb.append("DEFAULT NULL ");
909
                        }
910
                } else {
911
                        String value = getDefaltFieldValueString(attr);
912
                        strb.append("DEFAULT '");
913
                        strb.append(value);
914
                        strb.append("' ");
915
                }
916

    
917
                // Null
918
                if (allowNull) {
919
                        strb.append("NULL ");
920
                } else {
921
                        strb.append("NOT NULL ");
922
                }
923

    
924
                // Primery key
925
                if (attr.isPrimaryKey()) {
926
                        strb.append("PRIMARY KEY ");
927
                }
928
                return strb.toString();
929
        }
930

    
931
        protected String getDefaltFieldValueString(FeatureAttributeDescriptor attr)
932
                        throws WriteException {
933
                return dalValueToJDBC(attr, attr.getDefaultValue()).toString();
934
        }
935

    
936
        public String compoundLimitAndOffset(long limit, long offset) {
937
                StringBuilder sql = new StringBuilder();
938
                // limit
939
                if (limit > 0) {
940
                        sql.append(" limit ");
941
                        sql.append(limit);
942
                        sql.append(' ');
943
                }
944

    
945
                // offset
946
                if (offset > 0) {
947
                        sql.append(" offset ");
948
                        sql.append(offset);
949
                        sql.append(' ');
950
                }
951
                return sql.toString();
952
        }
953

    
954
        public boolean supportOffset() {
955
                return true;
956
        }
957

    
958
        public List getAdditionalSqlToCreate(NewDataStoreParameters ndsp,
959
                        FeatureType fType) {
960
                // TODO Auto-generated method stub
961
                return null;
962
        }
963

    
964

    
965
        public String stringJoin(List listToJoin,String sep){
966
                StringBuilder strb = new StringBuilder();
967
                stringJoin(listToJoin,sep,strb);
968
                return strb.toString();
969
        }
970

    
971
        public void stringJoin(List listToJoin, String sep, StringBuilder strb) {
972
                if (listToJoin.size() < 1) {
973
                        return;
974
                }
975
                if (listToJoin.size() > 1) {
976
                        for (int i = 0; i < listToJoin.size() - 1; i++) {
977
                                strb.append(listToJoin.get(i));
978
                                strb.append(sep);
979
                        }
980
                }
981
                strb.append(listToJoin.get(listToJoin.size() - 1));
982
        }
983
        /**
984
         * Inform that provider has supports for geometry store and operations
985
         * natively
986
         *
987
         * @return
988
         */
989
        boolean hasGeometrySupport() {
990
                return false;
991
        }
992

    
993
        public boolean allowAutomaticValues() {
994
                if (allowAutomaticValues == null) {
995
                        ConnectionAction action = new ConnectionAction(){
996

    
997
                                public Object action(Connection conn) throws DataException {
998

    
999
                                        ResultSet rs;
1000
                                        try {
1001
                                                DatabaseMetaData meta = conn.getMetaData();
1002
                                                rs = meta.getTypeInfo();
1003
                                                try{
1004
                                                        while (rs.next()) {
1005
                                                                if (rs.getInt("DATA_TYPE") == java.sql.Types.INTEGER) {
1006
                                                                        if (rs.getBoolean("AUTO_INCREMENT")) {
1007
                                                                                return Boolean.TRUE;
1008
                                                                        } else {
1009
                                                                                return Boolean.FALSE;
1010
                                                                        }
1011
                                                                }
1012
                                                        }
1013
                                                }finally{
1014
                                                        try{ rs.close();} catch (SQLException ex) {logger.error("Exception closing resulset", ex);};
1015
                                                }
1016
                                        } catch (SQLException e) {
1017
                                                throw new JDBCSQLException(e);
1018
                                        }
1019
                                        return Boolean.FALSE;
1020
                                }
1021

    
1022
                        };
1023

    
1024

    
1025

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

    
1036
        public boolean supportsUnion() {
1037
                if (supportsUnions == null) {
1038
                        ConnectionAction action = new ConnectionAction() {
1039

    
1040
                                public Object action(Connection conn) throws DataException {
1041

    
1042
                                        try {
1043
                                                DatabaseMetaData meta = conn.getMetaData();
1044
                                                return new Boolean(meta.supportsUnion());
1045
                                        } catch (SQLException e) {
1046
                                                throw new JDBCSQLException(e);
1047
                                        }
1048
                                }
1049

    
1050
                        };
1051

    
1052
                        try {
1053
                                supportsUnions = (Boolean) doConnectionAction(action);
1054
                        } catch (Exception e) {
1055
                                logger.error("Exception checking for unions support", e);
1056
                                supportsUnions = Boolean.FALSE;
1057
                        }
1058
                }
1059
                return supportsUnions.booleanValue();
1060
        }
1061

    
1062
        protected String getIdentifierQuoteString() {
1063
                if (identifierQuoteString == null) {
1064
                ConnectionAction action = new ConnectionAction() {
1065

    
1066
                        public Object action(Connection conn) throws DataException {
1067

    
1068
                                try {
1069
                                        DatabaseMetaData meta = conn.getMetaData();
1070
                                        return meta.getIdentifierQuoteString();
1071
                                } catch (SQLException e) {
1072
                                        throw new JDBCSQLException(e);
1073
                                }
1074
                        }
1075

    
1076
                };
1077

    
1078
                try {
1079
                        identifierQuoteString = (String) doConnectionAction(action);
1080
                } catch (Exception e) {
1081
                        logger.error("Exception checking for unions support", e);
1082
                        identifierQuoteString = " ";
1083
                        }
1084
                }
1085
                return identifierQuoteString;
1086
        }
1087

    
1088
        protected boolean isReservedWord(String field) {
1089
                // TODO
1090
                return false;
1091
        }
1092

    
1093
}