Statistics
| Revision:

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

History | View | Annotate | Download (28.5 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 String toString() {
227
                            return "getEnvelope";
228
                        }                    
229
                        public Object run() throws Exception {
230
                                ResultSet rs = null;
231
                                Statement st = null;
232
                                Connection conn = null;
233
                                Envelope fullEnvelope = null;
234
                                
235
                                Envelope emptyEnv =
236
                                                geomManager.createEnvelope(Geometry.SUBTYPES.GEOM2D);
237
                                
238
                                try {
239

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

    
251
                                        byte[] data = rs.getBytes(1);
252
                                        if (data == null) {
253
                                                return emptyEnv;
254
                                        }
255

    
256
                                        Geometry geom = geomManager.createFrom(data);
257

    
258
                                        fullEnvelope = geom.getEnvelope();
259

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

    
286
        @Override
287
        protected boolean supportsGeometry() {
288
                return true;
289
        }
290

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

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

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

    
323

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

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

    
346
                        }
347
                        Comparator cmp = new Comparator(){
348
                                public int compare(Object arg0, Object arg1) {
349
                                        TableId a0 = (TableId) arg0;
350
                                        TableId a1 = (TableId) arg1;
351

    
352
                                        int aux = a0.field.compareTo(a1.field);
353
                                        if (aux != 0) {
354
                                            return aux;
355
                                        }
356

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

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

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

    
414
                        if (set.size() == 0) {
415
                                return;
416
                        }
417

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

    
433

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

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

    
476
                                        } else {
477
                                                geometrySubtype = Geometry.SUBTYPES.GEOM3DM;
478
                                        }
479
                                }
480
                                addToPgSRToSRSID(pgSrid, srsID);
481

    
482

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

    
492
                                        if (baseSchema == null && baseTable == null) {
493

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

    
511
                                                } else {
512

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

    
542
                                }
543
                        }
544

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

    
552
        }
553

    
554

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

    
562

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

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

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

    
619
        public int getProviderSRID(String srs) {
620
                if (srs != null) {
621
                        Integer pgSRID = (Integer) srsID2pgSR.get(srs);
622
                        if (pgSRID != null) {
623
                                return pgSRID.intValue();
624
                        }
625

    
626
                        return searchpgSRID(srs);
627

    
628
                }
629
                return -1;
630
        }
631

    
632

    
633
        public int getProviderSRID(IProjection srs) {
634
                if (srs != null) {
635
                        Integer pgSRID = (Integer) srsID2pgSR.get(srs.getAbrev());
636
                        if (pgSRID != null) {
637
                                return pgSRID.intValue();
638
                        }
639

    
640
                        return searchpgSRID(srs);
641

    
642
                }
643
                return -1;
644
        }
645

    
646
        private int searchpgSRID(final IProjection srs) {
647
                if (srs == null) {
648
                        return -1;
649
                }
650
                return searchpgSRID(srs.getAbrev());
651
        }
652

    
653
        private int searchpgSRID(final String srsID) {
654
                if (srsID == null) {
655
                        return -1;
656
                }
657

    
658
                ConnectionAction action = new ConnectionAction(){
659

    
660
                        public Object action(Connection conn) throws DataException {
661

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

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

    
686
                                        try{
687
                                                rs = st.executeQuery();
688
                                        } catch (SQLException e){
689
                                                throw new JDBCExecutePreparedSQLException(sql, abrev, e);
690
                                        }
691

    
692
                                        if (!rs.next()) {
693
                                                return null;
694
                                        }
695

    
696
                                        return new Integer(rs.getInt(1));
697

    
698
                                } catch (SQLException e){
699
                                        throw new JDBCSQLException(e);
700
                                } finally{
701
                                        try {rs.close(); } catch (Exception e) {};
702
                                        try {st.close(); } catch (Exception e) {};
703
                                }
704

    
705
                        }
706

    
707
                };
708

    
709
                Integer pgSRSID = null;
710
                try {
711
                        pgSRSID = (Integer) doConnectionAction(action);
712
                } catch (Exception e) {
713
                        logger.error("Excetion searching pgSRS", e);
714
                        return -1;
715
                }
716

    
717
                if (pgSRSID != null) {
718
                        addToPgSRToSRSID(pgSRSID.intValue(), srsID);
719
                        return pgSRSID.intValue();
720
                }
721
                return -1;
722

    
723
        }
724

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

    
734
        public List<String> getSqlGeometyFieldAdd(FeatureAttributeDescriptor attr,
735
                        String table, String schema) {
736
                // SELECT AddGeometryColumn({schema}, {table}, {field}, {srid}(int),
737
                // {geomType}(Str), {dimensions}(int))
738

    
739
                // gemoType:
740
                /*
741
                 * POINT, LINESTRING, POLYGON, MULTIPOINT, MULTILINESTRING,
742
                 * MULTIPOLYGON, GEOMETRYCOLLECTION POINTM, LINESTRINGM, POLYGONM,
743
                 * MULTIPOINTM, MULTILINESTRINGM, MULTIPOLYGONM, GEOMETRYCOLLECTIONM
744
                 */
745

    
746
                List<String> sqls = new ArrayList<String>();
747

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

    
777

    
778
                sqls.add(strb.toString());
779

    
780
                /*ALTER TABLE muni10000_peq_test DROP CONSTRAINT enforce_srid_the_geom;*/
781
                /*
782
                strb = new StringBuilder();
783
                strb.append("Alter table ");
784
                if (schema != null && schema.length() > 0) {
785
                        strb.append(schema);
786
                        strb.append(".");
787
                }
788
                strb.append("f_table_name = '");
789
                strb.append(table);
790
                strb.append("' AND f_geometry_column = '");
791
                strb.append(attr.getName());
792
                strb.append("' AND srid = -1");
793

794

795
                sqls.add(strb.toString());
796
                */
797
                return sqls;
798
        }
799

    
800
        public String getSqlFieldName(FeatureAttributeDescriptor attribute) {
801
                if (attribute.getType() == DataTypes.GEOMETRY) {
802
                        return getFunctionName("ST_AsBinary") + "("
803
                            + super.getSqlFieldName(attribute) + ")";
804
                }
805
                return super.getSqlFieldName(attribute);
806
        }
807

    
808
        protected EditableFeatureAttributeDescriptor createAttributeFromJDBC(
809
                        EditableFeatureType type, Connection conn,
810
                        ResultSetMetaData rsMetadata, int colIndex) throws SQLException {
811
                if (rsMetadata.getColumnType(colIndex) == java.sql.Types.OTHER) {
812
                        if (rsMetadata.getColumnTypeName(colIndex).equalsIgnoreCase(
813
                                        "geometry")) {
814
                                EditableFeatureAttributeDescriptor attr = type.add(rsMetadata.getColumnName(colIndex),
815
                                                DataTypes.GEOMETRY);
816
                                // Set default values for geometry type
817
                                attr.setGeometryType(Geometry.TYPES.GEOMETRY);
818
                                attr.setGeometrySubType(Geometry.SUBTYPES.GEOM2D);
819
                                return attr;
820

    
821
                        }
822
                }
823

    
824
                return super.createAttributeFromJDBC(type, conn, rsMetadata, colIndex);
825
        }
826

    
827
        public List getAdditionalSqlToCreate(NewDataStoreParameters ndsp,
828
                        FeatureType fType) {
829
                FeatureAttributeDescriptor attr;
830
                Iterator iter = fType.iterator();
831
                List result = new ArrayList();
832
                PostgreSQLNewStoreParameters pgNdsp = (PostgreSQLNewStoreParameters) ndsp;
833
                while (iter.hasNext()){
834
                        attr = (FeatureAttributeDescriptor) iter.next();
835
                        if (attr.getType() == DataTypes.GEOMETRY){
836
                                result.addAll(getSqlGeometyFieldAdd(attr, pgNdsp.getTable(),
837
                                                pgNdsp
838
                                                .getSchema()));
839
                        }
840
                }
841

    
842
                return result;
843
        }
844

    
845
        public String getSqlFieldDescription(FeatureAttributeDescriptor attr)
846
                        throws DataException {
847
                if (attr.getType() == DataTypes.GEOMETRY){
848
                        return null;
849
                }
850
                return super.getSqlFieldDescription(attr);
851
        }
852

    
853

    
854
        public boolean allowAutomaticValues() {
855
                return Boolean.TRUE;
856
        }
857

    
858
        public boolean supportOffset() {
859
                return true;
860
        }
861

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

    
881
        EditableFeatureAttributeDescriptor column;
882

    
883
        String nativeType = rsMetadata.getColumnTypeName(colIndex);
884

    
885
        if (nativeType.startsWith("int")) {
886
            column = fType.add(rsMetadata.getColumnName(colIndex),
887
                DataTypes.INT);
888
            column.setAdditionalInfo("SQLType", new Integer(rsMetadata
889
                .getColumnType(colIndex)));
890
            column.setAdditionalInfo("SQLTypeName", rsMetadata
891
                .getColumnTypeName(colIndex));
892
            return column;
893
        }
894
        return super.createAttributeFromJDBCNativeType(fType, rsMetadata, colIndex);
895
    }
896

    
897
    public Object dalValueToJDBC(
898
        FeatureAttributeDescriptor attributeDescriptor, Object object)
899
        throws WriteException {
900
           if ("int2".equals(attributeDescriptor.getAdditionalInfo("SQLTypeName"))) {
901
                return new Short(String.valueOf(object));
902
            }
903

    
904
        return super.dalValueToJDBC(attributeDescriptor, object);
905
    }
906
    
907
    // =======================================
908
    
909

    
910
    public String getFunctionName(String newFuncName) {
911
        
912
        if (!versionSet) {
913
            postGISVersion = getPostgisVersion();
914
            versionSet = true;
915
        }
916
        return getFunctionNameForVersion(newFuncName, postGISVersion);
917
    }
918

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

    
948

    
949
    private int[] getPostgisVersion() {
950

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

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

    
1006

    
1007
}