Statistics
| Revision:

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

History | View | Annotate | Download (33.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.sql.Connection;
34
import java.sql.DatabaseMetaData;
35
import java.sql.PreparedStatement;
36
import java.sql.ResultSet;
37
import java.sql.ResultSetMetaData;
38
import java.sql.SQLException;
39
import java.sql.Statement;
40
import java.util.ArrayList;
41
import java.util.Comparator;
42
import java.util.Iterator;
43
import java.util.List;
44
import java.util.Map;
45
import java.util.Properties;
46
import java.util.TreeMap;
47
import java.util.TreeSet;
48

    
49
import org.apache.commons.lang3.StringUtils;
50
import org.cresques.cts.IProjection;
51
import org.postgresql.PGResultSetMetaData;
52
import org.slf4j.Logger;
53
import org.slf4j.LoggerFactory;
54

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

    
86
/**
87
 * @author jmvivo
88
 *
89
 */
90
public class PostgreSQLHelper extends JDBCHelper {
91

    
92
        private static Logger logger = LoggerFactory
93
                        .getLogger(PostgreSQLHelper.class);
94

    
95
        private Map pgSR2SRSID = new TreeMap();
96
        private Map srsID2pgSR = new TreeMap();
97

    
98
        private static Properties beforePostgis13 = null;
99
    private int[] postGISVersion = { 0,0,0 };
100
    private boolean versionSet = false;
101

    
102
        PostgreSQLHelper(JDBCHelperUser consumer,
103
                        PostgreSQLConnectionParameters params)
104
                        throws InitializeException {
105

    
106
                super(consumer, params);
107
        }
108

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

    
123

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

    
151
                return defaultSchema;
152
        }
153

    
154
    public Envelope getFullEnvelopeOfField(
155
            JDBCStoreParameters storeParams,
156
            String geometryAttrName, Envelope limit)
157
            throws DataException {
158

    
159
        StringBuilder strb = new StringBuilder();
160
        strb.append("Select " + getFunctionName("ST_AsBinary") + "("
161
                + getFunctionName("ST_Extent") + "(");
162
        strb.append(escapeFieldName(geometryAttrName));
163
        strb.append(")) from ");
164

    
165
        if (storeParams.getSQL() != null
166
                && storeParams.getSQL().trim().length() > 0) {
167
            strb.append('(');
168
            strb.append(storeParams.getSQL());
169
            strb.append(") as _subquery_alias_ ");
170
        } else {
171
            strb.append(storeParams.tableID());
172
        }
173

    
174
        if (limit != null || (storeParams.getBaseFilter() != null
175
                && storeParams.getBaseFilter().trim().length() > 0)) {
176
            strb.append(" where  ");
177

    
178
            if (limit != null) {
179
                strb.append(" ( " + getFunctionName("ST_Intersects") + "("
180
                        + getFunctionName("ST_GeomFromText") + "('");
181
                String workAreaWkt = null;
182
                try {
183
                    workAreaWkt = limit.getGeometry().convertToWKT();
184
                } catch (Exception e) {
185
                    throw new CreateGeometryException(e);
186
                }
187
                strb.append(workAreaWkt);
188
                strb.append("', ");
189

    
190
                IProjection proj = storeParams.getCRS();
191
                int sridInt = this.getProviderSRID(proj);
192
                if (sridInt == -1) {
193
                    throw new CreateGeometryException(
194
                            new Exception("CRS is null or unknown."));
195
                } else {
196
                    strb.append(Integer.toString(sridInt));
197
                }
198
                strb.append("), " + getFunctionName("ST_Envelope") + "(");
199
                strb.append(escapeFieldName(geometryAttrName));
200
                strb.append(")) ) ");
201

    
202
            }
203
            if (storeParams.getBaseFilter() != null && storeParams.getBaseFilter().trim().length() > 0) {
204
                if (limit != null) {
205
                    strb.append(" and ");
206
                }
207
                strb.append(" ( ");
208
                strb.append(storeParams.getBaseFilter());
209
                strb.append(" ) ");
210
            }
211

    
212
        }
213

    
214
        final String sql = strb.toString();
215

    
216
        this.open();
217

    
218
        return (Envelope) getResource().execute(new ResourceAction() {
219
            public String toString() {
220
                return "getEnvelope";
221
            }
222

    
223
            public Object run() throws Exception {
224
                ResultSet rs = null;
225
                Statement st = null;
226
                Connection conn = null;
227
                Envelope fullEnvelope = null;
228

    
229
                Envelope emptyEnv
230
                        = geomManager.createEnvelope(Geometry.SUBTYPES.GEOM2D);
231

    
232
                try {
233

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

    
245
                    byte[] data = rs.getBytes(1);
246
                    if (data == null) {
247
                        return emptyEnv;
248
                    }
249

    
250
                    Geometry geom = geomManager.createFrom(data);
251

    
252
                    fullEnvelope = geom.getEnvelope();
253

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

    
280
        @Override
281
        protected boolean supportsGeometry() {
282
                return true;
283
        }
284

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

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

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

    
317

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

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

    
340
                        }
341
                        Comparator cmp = new Comparator(){
342
                                public int compare(Object arg0, Object arg1) {
343
                                        TableId a0 = (TableId) arg0;
344
                                        TableId a1 = (TableId) arg1;
345

    
346
                                        int aux = a0.field.compareTo(a1.field);
347
                                        if (aux != 0) {
348
                                            return aux;
349
                                        }
350

    
351
                                        aux = a0.table.compareTo(a1.table);
352
                    if (aux != 0) {
353
                        return aux;
354
                    }
355

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

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

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

    
408
                        if (set.size() == 0) {
409
                                return;
410
                        }
411

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

    
427

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

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

    
470
                                        } else {
471
                                                geometrySubtype = Geometry.SUBTYPES.GEOM3DM;
472
                                        }
473
                                }
474
                                addToPgSRToSRSID(pgSrid, srsID);
475

    
476

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

    
486
                                        if (baseSchema == null && baseTable == null) {
487

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

    
505
                                                } else {
506

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

    
536
                                }
537
                        }
538

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

    
546
        }
547

    
548

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

    
556

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

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

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

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

    
620
                        return searchpgSRID(srs);
621

    
622
                }
623
                return -1;
624
        }
625

    
626

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

    
634
                        return searchpgSRID(srs);
635

    
636
                }
637
                return -1;
638
        }
639

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

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

    
652
                ConnectionAction action = new ConnectionAction(){
653

    
654
                        public Object action(Connection conn) throws DataException {
655

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

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

    
680
                                        try{
681
                                                rs = JDBCHelper.executeQuery(st,sql);
682

    
683
                                        } catch (SQLException e){
684
                                                throw new JDBCExecutePreparedSQLException(sql, abrev, e);
685
                                        }
686

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

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

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

    
700
                        }
701

    
702
                };
703

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

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

    
718
        }
719

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

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

    
734
                    // gemoType:
735
                    /*
736
             * POINT, LINESTRING, POLYGON, MULTIPOINT, MULTILINESTRING,
737
             * MULTIPOLYGON, GEOMETRYCOLLECTION POINTM, LINESTRINGM, POLYGONM,
738
             * MULTIPOINTM, MULTILINESTRINGM, MULTIPOLYGONM, GEOMETRYCOLLECTIONM
739
             */
740
            List<String> sqls = new ArrayList<String>();
741

    
742
            StringBuilder strb = new StringBuilder();
743
            strb.append("SELECT AddGeometryColumn('");
744
            if ( schema != null && schema.length() > 0 ) {
745
                strb.append(schema);
746
                strb.append("', '");
747
            }
748
            strb.append(table);
749
            strb.append("', '");
750
            strb.append(attr.getName().toLowerCase());
751
            strb.append("', ");
752
            strb.append(getProviderSRID(attr.getSRS()));
753
            strb.append(", '");
754

    
755
            strb.append(getPostgisGeomType(
756
                    attr.getGeometryType(),
757
                    attr.getGeometrySubType()
758
            )
759
            );
760
            strb.append("', ");
761
            strb.append(getPostgisGeomDimensions(attr.getGeometrySubType()));
762
            strb.append(")");
763

    
764
            sqls.add(strb.toString());
765

    
766
            return sqls;
767
        }
768

    
769
        public String getSqlFieldName(FeatureAttributeDescriptor attribute) {
770
                if (attribute.getType() == DataTypes.GEOMETRY) {
771
                        return getFunctionName("ST_AsBinary") + "("
772
                            + super.getSqlFieldName(attribute) + ")";
773
                }
774
                return super.getSqlFieldName(attribute);
775
        }
776

    
777
        protected EditableFeatureAttributeDescriptor createAttributeFromJDBC(
778
                        EditableFeatureType type, Connection conn,
779
                        ResultSetMetaData rsMetadata, int colIndex) throws SQLException {
780
                if (rsMetadata.getColumnType(colIndex) == java.sql.Types.OTHER) {
781
                        if (rsMetadata.getColumnTypeName(colIndex).equalsIgnoreCase(
782
                                        "geometry")) {
783
                                EditableFeatureAttributeDescriptor attr = type.add(rsMetadata.getColumnName(colIndex),
784
                                                DataTypes.GEOMETRY);
785
                                // Set default values for geometry type
786
                                attr.setGeometryType(Geometry.TYPES.GEOMETRY);
787
                                attr.setGeometrySubType(Geometry.SUBTYPES.GEOM2D);
788
                                return attr;
789

    
790
                        }
791
                }
792

    
793
                return super.createAttributeFromJDBC(type, conn, rsMetadata, colIndex);
794
        }
795

    
796
        public List getAdditionalSqlToCreate(NewDataStoreParameters ndsp,
797
                        FeatureType fType) {
798
                FeatureAttributeDescriptor attr;
799
                Iterator iter = fType.iterator();
800
                List result = new ArrayList();
801
                PostgreSQLNewStoreParameters pgNdsp = (PostgreSQLNewStoreParameters) ndsp;
802
                while (iter.hasNext()){
803
                        attr = (FeatureAttributeDescriptor) iter.next();
804
                        if (attr.getType() == DataTypes.GEOMETRY){
805
                                result.addAll(getSqlGeometyFieldAdd(attr, pgNdsp.getTable(),
806
                                                pgNdsp
807
                                                .getSchema()));
808
                        }
809
                        if( attr.isIndexed() ) {
810
                            result.add(getCreateIndexStatement((JDBCNewStoreParameters) ndsp, attr));
811
                        }
812
                        if( attr.isAutomatic() ) {
813
                            // A?adimos los GRANT para la secuencia asociada a la tabla.
814
                            String table = "\""+pgNdsp.getSchema() +"\".\""+pgNdsp.getTable()+"_"+attr.getName()+"_seq\" ";
815
                            result.addAll(this.createGrantStatements(pgNdsp, table));
816
                        }
817
                }
818

    
819

    
820
                return result;
821
        }
822

    
823
        protected String getCreateIndexStatement(JDBCNewStoreParameters params,FeatureAttributeDescriptor attr ) {
824
            String indexName = "idx_"+params.getTable()+"_"+attr.getName();
825

    
826
            String statement = "CREATE ";
827
            if( !attr.allowIndexDuplicateds() ) {
828
                statement += " UNIQUE ";
829
            }
830
            statement += "INDEX \""+indexName+"\" ";
831
            statement += "ON " + params.tableID() + " ";
832
            if( attr.getType()==DataTypes.GEOMETRY ) {
833
                statement += " USING GIST ";
834
                statement += "( \"" + attr.getName()+ "\")";
835
            } else {
836
                statement += "( \"" + attr.getName()+ "\"";
837
                if( attr.isIndexAscending() ) {
838
                    statement += " ASC )";
839
                } else {
840
                    statement += " DESC )";
841
                }
842
            }
843
            return statement;
844
        }
845

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

    
854

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

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

    
863
        public boolean supportsUnion() {
864
                return true;
865
        }
866

    
867
        public String escapeFieldName(String field) {
868
                /*
869
                if (!reservedWord(field) &&
870
                                field.matches("[a-z][a-z0-9_]*")) {
871
                        return field;
872
                }
873
                */
874
                String quote = getIdentifierQuoteString();
875
                return quote + field + quote;
876
        }
877

    
878
    protected EditableFeatureAttributeDescriptor createAttributeFromJDBCNativeType(
879
        EditableFeatureType fType, ResultSetMetaData rsMetadata, int colIndex)
880
        throws SQLException {
881

    
882
        EditableFeatureAttributeDescriptor column;
883

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

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

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

    
905
        return super.dalValueToJDBC(attributeDescriptor, object);
906
    }
907

    
908
    // =======================================
909

    
910

    
911
    public String getFunctionName(String newFuncName) {
912

    
913
        if (!versionSet) {
914
            postGISVersion = getPostgisVersion();
915
            versionSet = true;
916
        }
917
        return getFunctionNameForVersion(newFuncName, postGISVersion);
918
    }
919

    
920
    private String getFunctionNameForVersion(String newFuncName, int[] pv) {
921

    
922
        if (newFuncName == null || pv == null) {
923
            return newFuncName;
924
        }
925

    
926
        if (pv.length < 2) {
927
            // cannot compare
928
            return newFuncName;
929
        }
930

    
931
        if (pv[0] > 1) {
932
            return newFuncName;
933
        }
934

    
935
        if (pv[0] == 1 && pv[1] >= 3) {
936
            return newFuncName;
937
        }
938

    
939
        Properties pp = this.getBeforePostgis13Properties();
940
        String k = newFuncName.toLowerCase();
941
        String v = pp.getProperty(k);
942
        if (v == null) {
943
            return newFuncName;
944
        } else {
945
            return v;
946
        }
947
    }
948

    
949

    
950
    private int[] getPostgisVersion() {
951

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

    
975
        String[] vv = v.split("\\.");
976
        int[] resp = new int[3];
977
        try {
978
            for (int i=0; i<3; i++) {
979
                resp[i] = Integer.parseInt(vv[i]);
980
            }
981
        } catch (Exception exc) {
982
            logger.error("Unable to parse version: " + v, exc);
983
            return null;
984
        }
985
        return resp;
986
    }
987

    
988

    
989

    
990
    protected Properties getBeforePostgis13Properties() {
991
        if (beforePostgis13 == null) {
992

    
993
            beforePostgis13 = new Properties();
994
            // Left side MUST be in lower case
995
            // Right side will be used if Postgis version < 1.3
996
            beforePostgis13.setProperty("st_intersects", "Intersects");
997
            beforePostgis13.setProperty("st_extent", "Extent");
998
            beforePostgis13.setProperty("st_envelope", "Envelope");
999
            beforePostgis13.setProperty("st_asbinary", "AsBinary");
1000
            beforePostgis13.setProperty("st_geomfromtext", "GeomFromText");
1001
            beforePostgis13.setProperty("st_geomfromwkb", "GeomFromWKB");
1002
        }
1003
        return beforePostgis13;
1004
    }
1005

    
1006
    /* (non-Javadoc)
1007
     * @see org.gvsig.fmap.dal.store.jdbc.JDBCHelper#getAttributeFromJDBC(org.gvsig.fmap.dal.feature.EditableFeatureType, java.sql.Connection, java.sql.ResultSetMetaData, int)
1008
     */
1009
    @Override
1010
    protected EditableFeatureAttributeDescriptor getAttributeFromJDBC(EditableFeatureType fType, Connection conn,
1011
        ResultSetMetaData rsMetadata, int colIndex) throws JDBCException {
1012
        EditableFeatureAttributeDescriptor attr = super.getAttributeFromJDBC(fType, conn, rsMetadata, colIndex);
1013
        // El siguiente c?digo sirve para recuperar loas valores por defecto de la
1014
        // base de datos y asign?rselos al atributo, pero de momento lo comentarizamos
1015
        // porque se produce alg?n comportamiento extra?o que debemos valorar.
1016
//        if(rsMetadata instanceof PGResultSetMetaData){
1017
//            try {
1018
//                PGResultSetMetaData pgResultSetMetaData = (PGResultSetMetaData) rsMetadata;
1019
//                String tableName = pgResultSetMetaData.getBaseTableName(colIndex);
1020
//                String columnName = pgResultSetMetaData.getBaseColumnName(colIndex);
1021
//                String defaultValue = "";
1022
//                defaultValue = getColumnDefaultValue(conn, tableName, columnName);
1023
//
1024
//                if (!StringUtils.isEmpty(defaultValue)) {
1025
//
1026
//                    Object coerce = null;
1027
//                    try {
1028
//                        coerce = attr.coerce(defaultValue);
1029
//                    } catch (Throwable e) {
1030
//                        // Do nothing
1031
//                    }
1032
//                    attr.setDefaultValue(coerce);
1033
//                }
1034
//
1035
//            } catch (SQLException e1) {
1036
//                throw new JDBCSQLException(e1);
1037
//            }
1038
//        }
1039
        return attr;
1040
    }
1041

    
1042
    private String getColumnDefaultValue(Connection conn, String tableName, String columnName) {
1043
        String value = "";
1044
        try {
1045
            DatabaseMetaData md = conn.getMetaData();
1046
            String catalog = conn.getCatalog();
1047
            String schema = getDefaultSchema(conn);
1048
            ResultSet rs = md.getColumns(catalog, schema, tableName, columnName);
1049

    
1050
            if (rs.next()) {
1051
                value = rs.getString("COLUMN_DEF");
1052
            }
1053
            logger.info("Default value of column '" + columnName + "' is " + value);
1054
            if (!StringUtils.isEmpty(value)) {
1055
                value = value.split(":")[0];
1056
                if (value.startsWith("'") && value.endsWith("'")) {
1057
                    value = (String) value.subSequence(value.indexOf("'") + 1, value.lastIndexOf("'"));
1058
                } else {
1059
                    try {
1060
                        Double.parseDouble(value);
1061
                    } catch (Exception e) {
1062
                        return "";
1063
                    }
1064
                }
1065
            }
1066
        } catch (Throwable e) {
1067
            logger.info("Can't get default value from column '" + columnName + "'", e);
1068
        }
1069
        return value;
1070

    
1071
    }
1072
}