Statistics
| Revision:

root / trunk / org.gvsig.postgresql / org.gvsig.postgresql.provider / src / main / java / org / gvsig / fmap / dal / store / postgresql / PostgreSQLHelper.java @ 53

History | View | Annotate | Download (28.2 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.postgresql;
32

    
33
import java.io.File;
34
import java.io.InputStream;
35
import java.net.URL;
36
import java.sql.Connection;
37
import java.sql.PreparedStatement;
38
import java.sql.ResultSet;
39
import java.sql.ResultSetMetaData;
40
import java.sql.SQLException;
41
import java.sql.Statement;
42
import java.util.ArrayList;
43
import java.util.Comparator;
44
import java.util.Iterator;
45
import java.util.List;
46
import java.util.Map;
47
import java.util.Properties;
48
import java.util.TreeMap;
49
import java.util.TreeSet;
50

    
51
import org.cresques.cts.IProjection;
52
import org.postgresql.PGResultSetMetaData;
53
import org.slf4j.Logger;
54
import org.slf4j.LoggerFactory;
55

    
56
import org.gvsig.fmap.crs.CRSFactory;
57
import org.gvsig.fmap.dal.DALLocator;
58
import org.gvsig.fmap.dal.DataTypes;
59
import org.gvsig.fmap.dal.NewDataStoreParameters;
60
import org.gvsig.fmap.dal.exception.DataException;
61
import org.gvsig.fmap.dal.exception.InitializeException;
62
import org.gvsig.fmap.dal.exception.ReadException;
63
import org.gvsig.fmap.dal.exception.WriteException;
64
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
65
import org.gvsig.fmap.dal.feature.EditableFeatureType;
66
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
67
import org.gvsig.fmap.dal.feature.FeatureType;
68
import org.gvsig.fmap.dal.feature.exception.CreateGeometryException;
69
import org.gvsig.fmap.dal.feature.exception.UnsupportedDataTypeException;
70
import org.gvsig.fmap.dal.feature.exception.UnsupportedGeometryException;
71
import org.gvsig.fmap.dal.resource.ResourceAction;
72
import org.gvsig.fmap.dal.resource.spi.ResourceManagerProviderServices;
73
import org.gvsig.fmap.dal.store.jdbc.ConnectionAction;
74
import org.gvsig.fmap.dal.store.jdbc.JDBCHelper;
75
import org.gvsig.fmap.dal.store.jdbc.JDBCHelperUser;
76
import org.gvsig.fmap.dal.store.jdbc.JDBCStoreParameters;
77
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCException;
78
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCExecutePreparedSQLException;
79
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCExecuteSQLException;
80
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCPreparingSQLException;
81
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCSQLException;
82
import org.gvsig.fmap.geom.Geometry;
83
import org.gvsig.fmap.geom.GeometryLocator;
84
import org.gvsig.fmap.geom.GeometryManager;
85
import org.gvsig.fmap.geom.operation.GeometryOperationException;
86
import org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException;
87
import org.gvsig.fmap.geom.operation.fromwkb.FromWKB;
88
import org.gvsig.fmap.geom.operation.fromwkb.FromWKBGeometryOperationContext;
89
import org.gvsig.fmap.geom.primitive.Envelope;
90
import org.gvsig.tools.ToolsLocator;
91
import org.gvsig.tools.exception.BaseException;
92

    
93
/**
94
 * @author jmvivo
95
 *
96
 */
97
public class PostgreSQLHelper extends JDBCHelper {
98

    
99
        private static Logger logger = LoggerFactory
100
                        .getLogger(PostgreSQLHelper.class);
101

    
102
        private Map pgSR2SRSID = new TreeMap();
103
        private Map srsID2pgSR = new TreeMap();
104
        
105
        private static Properties beforePostgis13 = null;
106
    private int[] postGISVersion = { 0,0,0 };
107
    private boolean versionSet = false;
108

    
109
        PostgreSQLHelper(JDBCHelperUser consumer,
110
                        PostgreSQLConnectionParameters params)
111
                        throws InitializeException {
112

    
113
                super(consumer, params);
114
        }
115

    
116
        protected void initializeResource() throws InitializeException {
117
                ResourceManagerProviderServices manager = (ResourceManagerProviderServices) DALLocator
118
                .getResourceManager();
119
                PostgreSQLResource resource = (PostgreSQLResource) manager
120
                .createAddResource(
121
                                PostgreSQLResource.NAME, new Object[] {
122
                                                params.getUrl(), params.getHost(),
123
                                                params.getPort(), params.getDBName(), params.getUser(),
124
                                                params.getPassword(),
125
                                                params.getJDBCDriverClassName(),
126
                                                ((PostgreSQLConnectionParameters) params).getUseSSL() });
127
                this.setResource(resource);
128
        }
129

    
130

    
131
        protected String getDefaultSchema(Connection conn)
132
                        throws JDBCException {
133
                if (defaultSchema == null) {
134
                        String sql = "Select current_schema()";
135
                        ResultSet rs = null;
136
                        Statement st = null;
137
                        String schema = null;
138
                        try {
139
                                st = conn.createStatement();
140
                                try {
141
                                        rs = st.executeQuery(sql);
142
                                } catch (java.sql.SQLException e) {
143
                                        throw new JDBCExecuteSQLException(sql, e);
144
                                }
145
                                rs.next();
146
                                schema = rs.getString(1);
147
                        } catch (java.sql.SQLException e) {
148
                                throw new JDBCSQLException(e);
149
                        } finally {
150
                                try {rs.close();} catch (Exception e) {logger.error("Exception clossing resulset", e);};
151
                                try {st.close();} catch (Exception e) {logger.error("Exception clossing statement", e);};
152
                                rs = null;
153
                                st = null;
154
                        }
155
                        defaultSchema = schema;
156
                }
157

    
158
                return defaultSchema;
159
        }
160

    
161
        public Envelope getFullEnvelopeOfField(
162
                        JDBCStoreParameters storeParams,
163
                        String geometryAttrName, Envelope limit)
164
                        throws DataException {
165

    
166
                StringBuilder strb = new StringBuilder();
167
                strb.append("Select " + getFunctionName("ST_AsBinary") + "(" +
168
                getFunctionName("ST_Extent") + "(");
169
                strb.append(escapeFieldName(geometryAttrName));
170
                strb.append(")) from ");
171

    
172
                if (storeParams.getSQL() != null
173
                                && storeParams.getSQL().trim().length() > 0) {
174
                        strb.append('(');
175
                        strb.append(storeParams.getSQL());
176
                        strb.append(") as _subquery_alias_ ");
177
                } else {
178
                        strb.append(storeParams.tableID());
179
                }
180

    
181
                if (limit != null || (storeParams.getBaseFilter() != null 
182
                                && storeParams.getBaseFilter().trim().length() > 0)){
183
                        strb.append(" where  ");
184

    
185
                        if (limit != null) { 
186
                                strb.append(" ( " + getFunctionName("ST_Intersects") + "("
187
                                        + getFunctionName("ST_GeomFromText") + "('");
188
                                String workAreaWkt = null;
189
                                try {
190
                                        workAreaWkt = limit.getGeometry().convertToWKT();
191
                                } catch (Exception e) {
192
                                        throw new CreateGeometryException(e);
193
                                }
194
                                strb.append(workAreaWkt);
195
                                strb.append("', ");
196

    
197
                                IProjection proj = storeParams.getCRS();
198
                                int sridInt = this.getProviderSRID(proj); 
199
                                if (sridInt == -1) {
200
                                        throw new CreateGeometryException(
201
                                                new Exception("CRS is null or unknown."));
202
                                } else {
203
                                        strb.append(Integer.toString(sridInt));
204
                                }
205
                                strb.append("), " + getFunctionName("ST_Envelope") + "(");
206
                                strb.append(escapeFieldName(geometryAttrName));
207
                                strb.append(")) ) ");
208

    
209
                        }
210
                        if (storeParams.getBaseFilter() != null && storeParams.getBaseFilter().trim().length() > 0) {
211
                                if (limit != null) { 
212
                                        strb.append(" and ");
213
                                }
214
                                strb.append(" ( ");
215
                                strb.append(storeParams.getBaseFilter());
216
                                strb.append(" ) ");
217
                        }
218

    
219
                }
220

    
221
                final String sql = strb.toString();
222

    
223
                this.open();
224

    
225
                return (Envelope) getResource().execute(new ResourceAction() {
226
                        public Object run() throws Exception {
227
                                ResultSet rs = null;
228
                                Statement st = null;
229
                                Connection conn = null;
230
                                Envelope fullEnvelope = null;
231
                                
232
                                Envelope emptyEnv =
233
                                                geomManager.createEnvelope(Geometry.SUBTYPES.GEOM2D);
234
                                
235
                                try {
236

    
237
                                        conn = getConnection();
238
                                        st = conn.createStatement();
239
                                        try {
240
                                                rs = st.executeQuery(sql);
241
                                        } catch (java.sql.SQLException e) {
242
                                                throw new JDBCExecuteSQLException(sql, e);
243
                                        }
244
                                        if (!rs.next()) {
245
                                                return emptyEnv;
246
                                        }
247

    
248
                                        byte[] data = rs.getBytes(1);
249
                                        if (data == null) {
250
                                                return emptyEnv;
251
                                        }
252

    
253
                                        Geometry geom = geomManager.createFrom(data);
254

    
255
                                        fullEnvelope = geom.getEnvelope();
256

    
257
                                        return fullEnvelope;
258
                                } catch (java.sql.SQLException e) {
259
                                        throw new JDBCSQLException(e);
260
                                } catch (BaseException e) {
261
                                        throw new ReadException(user.getProviderName(), e);
262
                                } finally {
263
                                        try {
264
                                                rs.close();
265
                                        } catch (Exception e) {
266
                                        }
267
                                        try {
268
                                                st.close();
269
                                        } catch (Exception e) {
270
                                        }
271
                                        try {
272
                                                conn.close();
273
                                        } catch (Exception e) {
274
                                        }
275
                                        rs = null;
276
                                        st = null;
277
                                        conn = null;
278
                                }
279
                        }
280
                });
281
        }
282

    
283
        @Override
284
        protected boolean supportsGeometry() {
285
                return true;
286
        }
287

    
288
        /**
289
         * Fill <code>featureType</code> geometry attributes with SRS and ShapeType
290
         * information stored in the table GEOMETRY_COLUMNS
291
         *
292
         * @param conn
293
         * @param rsMetadata
294
         * @param featureType
295
         * @throws ReadException
296
         */
297
        protected void loadSRS_and_shapeType(Connection conn,
298
                        ResultSetMetaData rsMetadata, EditableFeatureType featureType,
299
                        String baseSchema, String baseTable)
300
                        throws JDBCException {
301

    
302
                Statement st = null;
303
                ResultSet rs = null;
304
                try {
305
                        // Sacamos la lista de los attributos geometricos
306
                        EditableFeatureAttributeDescriptor attr;
307
                        List geoAttrs = new ArrayList();
308

    
309
                        Iterator iter = featureType.iterator();
310
                        while (iter.hasNext()) {
311
                                attr = (EditableFeatureAttributeDescriptor) iter.next();
312
                                if (attr.getType() == DataTypes.GEOMETRY) {
313
                                        geoAttrs.add(attr);
314
                                }
315
                        }
316
                        if (geoAttrs.size() < 1) {
317
                                return;
318
                        }
319

    
320

    
321
                        // preparamos un set con las lista de tablas de origen
322
                        // de los campos
323
                        class TableId {
324
                                public String schema=null;
325
                                public String table=null;
326
                                public String field = null;
327

    
328
                                public void appendToSQL(StringBuilder strb) {
329
                                        if (schema == null || schema.length() == 0) {
330
                                                strb
331
                                                                .append("( F_TABLE_SCHEMA = current_schema() AND F_TABLE_NAME = '");
332
                                        } else {
333
                                                strb.append("( F_TABLE_SCHEMA = '");
334
                                                strb.append(schema);
335
                                                strb.append("' AND F_TABLE_NAME = '");
336
                                        }
337
                                        strb.append(table);
338
                                        strb.append("' AND F_GEOMETRY_COLUMN = '");
339
                                        strb.append(field);
340
                                        strb.append("' )");
341
                                }
342

    
343
                        }
344
                        Comparator cmp = new Comparator(){
345
                                public int compare(Object arg0, Object arg1) {
346
                                        TableId a0 = (TableId) arg0;
347
                                        TableId a1 = (TableId) arg1;
348

    
349
                                        int aux = a0.field.compareTo(a1.field);
350
                                        if (aux != 0) {
351
                                            return aux;
352
                                        }
353

    
354
                                        aux = a0.table.compareTo(a1.table);
355
                    if (aux != 0) {
356
                        return aux;
357
                    }
358
                                        
359
                    if (a0.schema == null) {
360
                        if (a1.schema == null) {
361
                            aux = 0;
362
                        } else {
363
                            aux = -1;
364
                        }
365
                    } else {
366
                        if (a1.schema == null) {
367
                            aux = -1;
368
                        } else {
369
                            aux = a0.schema.compareTo(a1.schema);
370
                        }
371
                    }
372
                                        return aux;
373
                                }
374
                        };
375
                        TreeSet set = new TreeSet(cmp);
376
                        TableId tableId;
377
                        iter = geoAttrs.iterator();
378
                        int rsIndex;
379
                        while (iter.hasNext()) {
380
                                attr = (EditableFeatureAttributeDescriptor) iter.next();
381
                                tableId = new TableId();
382
                                rsIndex = attr.getIndex() + 1;
383

    
384
                                if (baseSchema == null && baseTable == null) {
385
                                        if (rsMetadata instanceof PGResultSetMetaData) {
386
                                                tableId.schema = ((PGResultSetMetaData) rsMetadata)
387
                                                                .getBaseSchemaName(rsIndex);
388
                                                tableId.table = ((PGResultSetMetaData) rsMetadata)
389
                                                                .getBaseTableName(rsIndex);
390
                                                tableId.field = ((PGResultSetMetaData) rsMetadata)
391
                                                                .getBaseColumnName(rsIndex);
392

    
393
                                        } else {
394
                                                tableId.schema = rsMetadata.getSchemaName(rsIndex);
395
                                                tableId.table = rsMetadata.getTableName(rsIndex);
396
                                                tableId.field = rsMetadata.getColumnName(rsIndex);
397
                                        }
398
                                } else {
399
                                        tableId.schema = baseSchema;
400
                                        tableId.table = baseTable;
401
                                        tableId.field = rsMetadata.getColumnName(rsIndex);
402
                                }
403
                                if (tableId.table == null || tableId.table.length() == 0) {
404
                                        // Si no tiene tabla origen (viene de algun calculo por ej.)
405
                                        // lo saltamos ya que no estara en la tabla GEOMETRY_COLUMNS
406
                                        continue;
407
                                }
408
                                set.add(tableId);
409
                        }
410

    
411
                        if (set.size() == 0) {
412
                                return;
413
                        }
414

    
415
                        // Preparamos una sql para que nos saque el resultado
416
                        StringBuilder strb = new StringBuilder();
417
                        strb.append("Select geometry_columns.*,auth_name || ':' || auth_srid as SRSID ");
418
                        strb.append("from geometry_columns left join spatial_ref_sys on ");
419
                        strb.append("geometry_columns.srid = spatial_ref_sys.srid WHERE ");
420
                        iter = set.iterator();
421
                        for (int i=0;i<set.size()-1;i++) {
422
                                tableId = (TableId) iter.next();
423
                                tableId.appendToSQL(strb);
424
                                strb.append(" OR ");
425
                        }
426
                        tableId = (TableId) iter.next();
427
                        tableId.appendToSQL(strb);
428
                        String sql = strb.toString();
429

    
430

    
431
                        st = conn.createStatement();
432
                        try {
433
                                rs = st.executeQuery(sql);
434
                        } catch (SQLException e) {
435
                                throw new JDBCExecuteSQLException(sql, e);
436
                        }
437
                        String srsID;
438
                        int pgSrid;
439
                        int geometryType;
440
                        int geometrySubtype;
441
                        String geomTypeStr;
442
                        int dimensions;
443
                        IProjection srs;
444

    
445
                        while (rs.next()){
446
                                srsID = rs.getString("SRSID");
447
                                pgSrid = rs.getInt("SRID");
448
                                geomTypeStr = rs.getString("TYPE").toUpperCase();
449
                                geometryType = Geometry.TYPES.GEOMETRY;
450
                                if (geomTypeStr.startsWith("POINT")) {
451
                                        geometryType = Geometry.TYPES.POINT;
452
                                } else if (geomTypeStr.startsWith("LINESTRING")) {
453
                                        geometryType = Geometry.TYPES.CURVE;
454
                                } else if (geomTypeStr.startsWith("POLYGON")) {
455
                                        geometryType = Geometry.TYPES.SURFACE;
456
                                } else if (geomTypeStr.startsWith("MULTIPOINT")) {
457
                                        geometryType = Geometry.TYPES.MULTIPOINT;
458
                                } else if (geomTypeStr.startsWith("MULTILINESTRING")) {
459
                                        geometryType = Geometry.TYPES.MULTICURVE;
460
                                } else if (geomTypeStr.startsWith("MULTIPOLYGON")) {
461
                                        geometryType = Geometry.TYPES.MULTISURFACE;
462
                                }
463
                                dimensions = rs.getInt("coord_dimension");
464
                                geometrySubtype = Geometry.SUBTYPES.GEOM2D;
465
                                if (dimensions > 2) {
466
                                        if (dimensions == 3) {
467
                                                if (geomTypeStr.endsWith("M")) {
468
                                                        geometrySubtype = Geometry.SUBTYPES.GEOM2DM;
469
                                                } else {
470
                                                        geometrySubtype = Geometry.SUBTYPES.GEOM3D;
471
                                                }
472

    
473
                                        } else {
474
                                                geometrySubtype = Geometry.SUBTYPES.GEOM3DM;
475
                                        }
476
                                }
477
                                addToPgSRToSRSID(pgSrid, srsID);
478

    
479

    
480
                                iter = geoAttrs.iterator();
481
                                while (iter.hasNext()) {
482
                                        attr = (EditableFeatureAttributeDescriptor) iter.next();
483
                                        rsIndex = attr.getIndex() + 1;
484
                                        if (!rsMetadata.getColumnName(rsIndex).equals(
485
                                                        rs.getString("f_geometry_column"))) {
486
                                                continue;
487
                                        }
488

    
489
                                        if (baseSchema == null && baseTable == null) {
490

    
491
                                                if (rsMetadata instanceof PGResultSetMetaData) {
492
                                                        if (!((PGResultSetMetaData) rsMetadata)
493
                                                                        .getBaseTableName(rsIndex).equals(
494
                                                                                        rs.getString("f_table_name"))) {
495
                                                                continue;
496
                                                        }
497
                                                        String curSchema = rs.getString("f_table_schema");
498
                                                        String metaSchema = ((PGResultSetMetaData) rsMetadata)
499
                                                                        .getBaseSchemaName(rsIndex);
500
                                                        if (!metaSchema.equals(curSchema)) {
501
                                                                if (metaSchema.length() == 0
502
                                                                                && metaSchema == getDefaultSchema(conn)) {
503
                                                                } else {
504
                                                                        continue;
505
                                                                }
506
                                                        }
507

    
508
                                                } else {
509

    
510
                                                        if (!rsMetadata.getTableName(rsIndex).equals(
511
                                                                        rs.getString("f_table_name"))) {
512
                                                                continue;
513
                                                        }
514
                                                        String curSchema = rs.getString("f_table_schema");
515
                                                        String metaSchema = rsMetadata
516
                                                                        .getSchemaName(rsIndex);
517
                                                        if (!metaSchema.equals(curSchema)) {
518
                                                                if (metaSchema.length() == 0
519
                                                                                && metaSchema == getDefaultSchema(conn)) {
520
                                                                } else {
521
                                                                        continue;
522
                                                                }
523
                                                        }
524
                                                }
525
                                        }
526
                                        attr.setGeometryType(geometryType);
527
                                        attr.setGeometrySubType(geometrySubtype);
528
                                        if (srsID != null && srsID.length() > 0) {
529
                                                attr.setSRS(CRSFactory.getCRS(srsID));
530
                                        }
531
                                        iter.remove();
532
                                }
533
                                iter = geoAttrs.iterator();
534
                                while (iter.hasNext()) {
535
                                        attr = (EditableFeatureAttributeDescriptor) iter.next();
536
                                        attr.setSRS(null);
537
                                        attr.setGeometryType(Geometry.TYPES.GEOMETRY);
538

    
539
                                }
540
                        }
541

    
542
                } catch (java.sql.SQLException e) {
543
                        throw new JDBCSQLException(e);
544
                } finally {
545
                        try {rs.close();} catch (Exception e) {        };
546
                        try {st.close();} catch (Exception e) {        };
547
                }
548

    
549
        }
550

    
551

    
552
        public String getSqlColumnTypeDescription(FeatureAttributeDescriptor attr) {
553
                if (attr.getType() == DataTypes.GEOMETRY) {
554
                        return "geometry";
555
                }
556
                return super.getSqlColumnTypeDescription(attr);
557
        }
558

    
559

    
560
        public int getPostgisGeomDimensions(int geometrySubType) {
561
                switch (geometrySubType) {
562
                case Geometry.SUBTYPES.GEOM2D:
563
                        return 2;
564
                case Geometry.SUBTYPES.GEOM2DM:
565
                case Geometry.SUBTYPES.GEOM3D:
566
                        return 3;
567

    
568
                case Geometry.SUBTYPES.GEOM3DM:
569
                        return 4;
570
                default:
571
                        throw new UnsupportedDataTypeException(
572
                                        ToolsLocator.getDataTypesManager().getTypeName(DataTypes.GEOMETRY),
573
                                        DataTypes.GEOMETRY);
574
                }
575
        }
576

    
577
        public String getPostgisGeomType(int geometryType, int geometrySubType) {
578
                String pgGeomType;
579
                switch (geometryType) {
580
                case Geometry.TYPES.GEOMETRY:
581
                        pgGeomType = "GEOMETRY";
582
                        break;
583
                case Geometry.TYPES.POINT:
584
                        pgGeomType = "POINT";
585
                        break;
586
                case Geometry.TYPES.CURVE:
587
                        pgGeomType = "LINESTRING";
588
                        break;
589
                case Geometry.TYPES.SURFACE:
590
                        pgGeomType = "POLYGON";
591
                        break;
592
                case Geometry.TYPES.MULTIPOINT:
593
                        pgGeomType = "MULTIPOINT";
594
                        break;
595
                case Geometry.TYPES.MULTICURVE:
596
                        pgGeomType = "MULTILINESTRING";
597
                        break;
598
                case Geometry.TYPES.MULTISURFACE:
599
                        pgGeomType = "MULTIPOLYGON";
600
                        break;
601
                default:
602
                        throw new UnsupportedGeometryException(geometryType,
603
                                        geometrySubType);
604
                }
605
                if (geometrySubType == Geometry.SUBTYPES.GEOM2DM
606
                                || geometrySubType == Geometry.SUBTYPES.GEOM3DM) {
607
                        pgGeomType = pgGeomType + "M";
608
                } else if (geometrySubType == Geometry.SUBTYPES.GEOM3D) {
609
                        throw new UnsupportedGeometryException(geometryType,
610
                                        geometrySubType);
611
                }
612
                return pgGeomType;
613
        }
614

    
615
        public int getProviderSRID(String srs) {
616
                if (srs != null) {
617
                        Integer pgSRID = (Integer) srsID2pgSR.get(srs);
618
                        if (pgSRID != null) {
619
                                return pgSRID.intValue();
620
                        }
621

    
622
                        return searchpgSRID(srs);
623

    
624
                }
625
                return -1;
626
        }
627

    
628

    
629
        public int getProviderSRID(IProjection srs) {
630
                if (srs != null) {
631
                        Integer pgSRID = (Integer) srsID2pgSR.get(srs.getAbrev());
632
                        if (pgSRID != null) {
633
                                return pgSRID.intValue();
634
                        }
635

    
636
                        return searchpgSRID(srs);
637

    
638
                }
639
                return -1;
640
        }
641

    
642
        private int searchpgSRID(final IProjection srs) {
643
                if (srs == null) {
644
                        return -1;
645
                }
646
                return searchpgSRID(srs.getAbrev());
647
        }
648

    
649
        private int searchpgSRID(final String srsID) {
650
                if (srsID == null) {
651
                        return -1;
652
                }
653

    
654
                ConnectionAction action = new ConnectionAction(){
655

    
656
                        public Object action(Connection conn) throws DataException {
657

    
658
                                String[] abrev = srsID.split(":");
659
                                StringBuilder sqlb = new StringBuilder();
660
                                sqlb.append("select srid from spatial_ref_sys where ");
661
                                if (abrev.length > 1) {
662
                                        sqlb.append("auth_name = ? and ");
663
                                }
664
                                sqlb.append("auth_srid = ?");
665

    
666
                                String sql = sqlb.toString();
667
                                PreparedStatement st;
668
                                try {
669
                                        st = conn.prepareStatement(sql);
670
                                } catch (SQLException e){
671
                                        throw new JDBCPreparingSQLException(sql,e);
672
                                }
673
                                ResultSet rs = null;
674
                                try{
675
                                        int i=0;
676
                                        if (abrev.length > 1){
677
                                                st.setString(i+1, abrev[i]);
678
                                                i++;
679
                                        }
680
                                        st.setInt(i + 1, Integer.parseInt(abrev[i]));
681

    
682
                                        try{
683
                                                rs = st.executeQuery();
684
                                        } catch (SQLException e){
685
                                                throw new JDBCExecutePreparedSQLException(sql, abrev, e);
686
                                        }
687

    
688
                                        if (!rs.next()) {
689
                                                return null;
690
                                        }
691

    
692
                                        return new Integer(rs.getInt(1));
693

    
694
                                } catch (SQLException e){
695
                                        throw new JDBCSQLException(e);
696
                                } finally{
697
                                        try {rs.close(); } catch (Exception e) {};
698
                                        try {st.close(); } catch (Exception e) {};
699
                                }
700

    
701
                        }
702

    
703
                };
704

    
705
                Integer pgSRSID = null;
706
                try {
707
                        pgSRSID = (Integer) doConnectionAction(action);
708
                } catch (Exception e) {
709
                        logger.error("Excetion searching pgSRS", e);
710
                        return -1;
711
                }
712

    
713
                if (pgSRSID != null) {
714
                        addToPgSRToSRSID(pgSRSID.intValue(), srsID);
715
                        return pgSRSID.intValue();
716
                }
717
                return -1;
718

    
719
        }
720

    
721
        private void addToPgSRToSRSID(int pgSRID, String srsId) {
722
                if (pgSRID < 0 || srsId == null || srsId.length() == 0) {
723
                        return;
724
                }
725
                Integer pgSRIDInteger = new Integer(pgSRID);
726
                pgSR2SRSID.put(pgSRIDInteger, srsId);
727
                srsID2pgSR.put(srsId, pgSRIDInteger);
728
        }
729

    
730
        public List<String> getSqlGeometyFieldAdd(FeatureAttributeDescriptor attr,
731
                        String table, String schema) {
732
                // SELECT AddGeometryColumn({schema}, {table}, {field}, {srid}(int),
733
                // {geomType}(Str), {dimensions}(int))
734

    
735
                // gemoType:
736
                /*
737
                 * POINT, LINESTRING, POLYGON, MULTIPOINT, MULTILINESTRING,
738
                 * MULTIPOLYGON, GEOMETRYCOLLECTION POINTM, LINESTRINGM, POLYGONM,
739
                 * MULTIPOINTM, MULTILINESTRINGM, MULTIPOLYGONM, GEOMETRYCOLLECTIONM
740
                 */
741

    
742
                List<String> sqls = new ArrayList<String>();
743

    
744
                StringBuilder strb = new StringBuilder();
745
                strb.append("SELECT AddGeometryColumn('");
746
                if (schema != null && schema.length() > 0) {
747
                        strb.append(schema);
748
                        strb.append("', '");
749
                }
750
                strb.append(table);
751
                strb.append("', '");
752
                strb.append(attr.getName().toLowerCase());
753
                strb.append("', ");
754
                // strb.append("-1");
755
                strb.append(getProviderSRID(attr.getSRS()));
756
                strb.append(", '");
757
                
758
                // ===========================================================================
759
            // TODO Improve this. Keep in mind that MULTIPOLYGON will not accept POLYGON
760
        strb.append("GEOMETRY");
761
                /*
762
                strb.append(getPostgisGeomType(attr.getGeometryType(), attr
763
                                .getGeometrySubType()));
764
                                */
765
        // ===========================================================================
766
                strb.append("', ");
767
                strb.append(getPostgisGeomDimensions(attr.getGeometrySubType()));
768
                strb.append(")");
769

    
770

    
771
                sqls.add(strb.toString());
772

    
773
                /*ALTER TABLE muni10000_peq_test DROP CONSTRAINT enforce_srid_the_geom;*/
774
                /*
775
                strb = new StringBuilder();
776
                strb.append("Alter table ");
777
                if (schema != null && schema.length() > 0) {
778
                        strb.append(schema);
779
                        strb.append(".");
780
                }
781
                strb.append("f_table_name = '");
782
                strb.append(table);
783
                strb.append("' AND f_geometry_column = '");
784
                strb.append(attr.getName());
785
                strb.append("' AND srid = -1");
786

787

788
                sqls.add(strb.toString());
789
                */
790
                return sqls;
791
        }
792

    
793
        public String getSqlFieldName(FeatureAttributeDescriptor attribute) {
794
                if (attribute.getType() == DataTypes.GEOMETRY) {
795
                        return getFunctionName("ST_AsBinary") + "("
796
                            + super.getSqlFieldName(attribute) + ")";
797
                }
798
                return super.getSqlFieldName(attribute);
799
        }
800

    
801
        protected EditableFeatureAttributeDescriptor createAttributeFromJDBC(
802
                        EditableFeatureType type, Connection conn,
803
                        ResultSetMetaData rsMetadata, int colIndex) throws SQLException {
804
                if (rsMetadata.getColumnType(colIndex) == java.sql.Types.OTHER) {
805
                        if (rsMetadata.getColumnTypeName(colIndex).equalsIgnoreCase(
806
                                        "geometry")) {
807
                                EditableFeatureAttributeDescriptor attr = type.add(rsMetadata.getColumnName(colIndex),
808
                                                DataTypes.GEOMETRY);
809
                                // Set default values for geometry type
810
                                attr.setGeometryType(Geometry.TYPES.GEOMETRY);
811
                                attr.setGeometrySubType(Geometry.SUBTYPES.GEOM2D);
812
                                return attr;
813

    
814
                        }
815
                }
816

    
817
                return super.createAttributeFromJDBC(type, conn, rsMetadata, colIndex);
818
        }
819

    
820
        public List getAdditionalSqlToCreate(NewDataStoreParameters ndsp,
821
                        FeatureType fType) {
822
                FeatureAttributeDescriptor attr;
823
                Iterator iter = fType.iterator();
824
                List result = new ArrayList();
825
                PostgreSQLNewStoreParameters pgNdsp = (PostgreSQLNewStoreParameters) ndsp;
826
                while (iter.hasNext()){
827
                        attr = (FeatureAttributeDescriptor) iter.next();
828
                        if (attr.getType() == DataTypes.GEOMETRY){
829
                                result.addAll(getSqlGeometyFieldAdd(attr, pgNdsp.getTable(),
830
                                                pgNdsp
831
                                                .getSchema()));
832
                        }
833
                }
834

    
835
                return result;
836
        }
837

    
838
        public String getSqlFieldDescription(FeatureAttributeDescriptor attr)
839
                        throws DataException {
840
                if (attr.getType() == DataTypes.GEOMETRY){
841
                        return null;
842
                }
843
                return super.getSqlFieldDescription(attr);
844
        }
845

    
846

    
847
        public boolean allowAutomaticValues() {
848
                return Boolean.TRUE;
849
        }
850

    
851
        public boolean supportOffset() {
852
                return true;
853
        }
854

    
855
        public boolean supportsUnion() {
856
                return true;
857
        }
858
        
859
        public String escapeFieldName(String field) {
860
                /*
861
                if (!reservedWord(field) && 
862
                                field.matches("[a-z][a-z0-9_]*")) {
863
                        return field;
864
                }
865
                */
866
                String quote = getIdentifierQuoteString();
867
                return quote + field + quote;
868
        }
869
        
870
    protected EditableFeatureAttributeDescriptor createAttributeFromJDBCNativeType(
871
        EditableFeatureType fType, ResultSetMetaData rsMetadata, int colIndex)
872
        throws SQLException {
873

    
874
        EditableFeatureAttributeDescriptor column;
875

    
876
        String nativeType = rsMetadata.getColumnTypeName(colIndex);
877

    
878
        if (nativeType.startsWith("int")) {
879
            column = fType.add(rsMetadata.getColumnName(colIndex),
880
                DataTypes.INT);
881
            column.setAdditionalInfo("SQLType", new Integer(rsMetadata
882
                .getColumnType(colIndex)));
883
            column.setAdditionalInfo("SQLTypeName", rsMetadata
884
                .getColumnTypeName(colIndex));
885
            return column;
886
        }
887
        return super.createAttributeFromJDBCNativeType(fType, rsMetadata, colIndex);
888
    }
889

    
890
    public Object dalValueToJDBC(
891
        FeatureAttributeDescriptor attributeDescriptor, Object object)
892
        throws WriteException {
893
           if ("int2".equals(attributeDescriptor.getAdditionalInfo("SQLTypeName"))) {
894
                return new Short(String.valueOf(object));
895
            }
896

    
897
        return super.dalValueToJDBC(attributeDescriptor, object);
898
    }
899
    
900
    // =======================================
901
    
902

    
903
    public String getFunctionName(String newFuncName) {
904
        
905
        if (!versionSet) {
906
            postGISVersion = getPostgisVersion();
907
            versionSet = true;
908
        }
909
        return getFunctionNameForVersion(newFuncName, postGISVersion);
910
    }
911

    
912
    private String getFunctionNameForVersion(String newFuncName, int[] pv) {
913
        
914
        if (newFuncName == null || pv == null) {
915
            return newFuncName;
916
        }
917
        
918
        if (pv.length < 2) {
919
            // cannot compare
920
            return newFuncName;
921
        }
922
        
923
        if (pv[0] > 1) {
924
            return newFuncName;
925
        }
926
        
927
        if (pv[0] == 1 && pv[1] >= 3) {
928
            return newFuncName;
929
        }
930
        
931
        Properties pp = this.getBeforePostgis13Properties();
932
        String k = newFuncName.toLowerCase();
933
        String v = pp.getProperty(k);
934
        if (v == null) {
935
            return newFuncName;
936
        } else {
937
            return v;
938
        }
939
    }
940

    
941

    
942
    private int[] getPostgisVersion() {
943

    
944
        String sql = "SELECT PostGIS_Lib_Version()";
945
        ResultSet rs = null;
946
        Statement st = null;
947
        String v = null;
948
        Connection conn = null;
949
        try {
950
            conn = this.getConnection();
951
            st = conn.createStatement();
952
            rs = st.executeQuery(sql);
953
            rs.next();
954
            v = rs.getString(1);
955
            if (v == null) {
956
                throw new Exception("Returned version is NULL");
957
            }
958
        } catch (Exception exc) {
959
            logger.error("Unable to get Postgis version: " + exc.getMessage(), exc);
960
            return null;
961
        } finally {
962
            try { rs.close(); } catch (Exception e) {};
963
            try { st.close(); } catch (Exception e) {};
964
            try { conn.close(); } catch (Exception e) {};
965
        }
966

    
967
        String[] vv = v.split("\\.");
968
        int[] resp = new int[3];
969
        try {
970
            for (int i=0; i<3; i++) {
971
                resp[i] = Integer.parseInt(vv[i]);
972
            }
973
        } catch (Exception exc) {
974
            logger.error("Unable to parse version: " + v, exc);
975
            return null;
976
        }
977
        return resp;
978
    }
979
    
980
    
981
    
982
    protected Properties getBeforePostgis13Properties() {
983
        if (beforePostgis13 == null) {
984
            
985
            beforePostgis13 = new Properties();
986
            // Left side MUST be in lower case
987
            // Right side will be used if Postgis version < 1.3
988
            beforePostgis13.setProperty("st_intersects", "Intersects");
989
            beforePostgis13.setProperty("st_extent", "Extent");
990
            beforePostgis13.setProperty("st_envelope", "Envelope");
991
            beforePostgis13.setProperty("st_asbinary", "AsBinary");
992
            beforePostgis13.setProperty("st_geomfromtext", "GeomFromText");
993
            beforePostgis13.setProperty("st_geomfromwkb", "GeomFromWKB");
994
        }
995
        return beforePostgis13;
996
    }
997
    
998

    
999

    
1000
}