Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.dal / org.gvsig.fmap.dal.db / org.gvsig.fmap.dal.db.jdbc / src / main / java / org / gvsig / fmap / dal / store / jdbc2 / spi / operations / CalculateEnvelopeOfColumnOperation.java @ 45152

History | View | Annotate | Download (11.5 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2020 gvSIG Association.
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 3
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
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24
package org.gvsig.fmap.dal.store.jdbc2.spi.operations;
25

    
26
import java.sql.Connection;
27
import java.sql.ResultSet;
28
import java.sql.SQLException;
29
import java.sql.Statement;
30
import java.util.logging.Level;
31
import java.util.logging.Logger;
32
import org.apache.commons.lang3.StringUtils;
33
import org.cresques.cts.IProjection;
34
import org.gvsig.expressionevaluator.ExpressionBuilder.Variable;
35
import org.gvsig.expressionevaluator.GeometryExpressionBuilder;
36
import org.gvsig.fmap.dal.exception.DataException;
37
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
38
import org.gvsig.fmap.dal.feature.FeatureType;
39
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCSQLException;
40
import org.gvsig.fmap.dal.store.jdbc2.JDBCHelper;
41
import org.gvsig.fmap.dal.store.jdbc2.JDBCUtils;
42
import org.gvsig.fmap.dal.store.jdbc2.OperationsFactory.TableReference;
43
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase;
44
import static org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase.PROP_TABLE;
45
import org.gvsig.fmap.geom.Geometry;
46
import org.gvsig.fmap.geom.GeometryLocator;
47
import org.gvsig.fmap.geom.GeometryUtils;
48
import org.gvsig.fmap.geom.exception.CreateEnvelopeException;
49
import org.gvsig.fmap.geom.primitive.Envelope;
50
import org.gvsig.fmap.geom.type.GeometryType;
51

    
52
public class CalculateEnvelopeOfColumnOperation extends AbstractConnectionOperation {
53

    
54
    protected final TableReference table;
55
    protected final String columnName;
56
    protected final String baseFilter;
57
    protected final Envelope limit;
58
    protected final IProjection crs;
59
    protected final FeatureType featureType;
60

    
61
    public CalculateEnvelopeOfColumnOperation(
62
            JDBCHelper helper,
63
            FeatureType featureType,
64
            TableReference table,
65
            String columnName,
66
            String baseFilter,
67
            Envelope limit,
68
            IProjection crs
69
    ) {
70
        super(helper);
71
        this.featureType = featureType;
72
        this.table = table;
73
        this.columnName = columnName;
74
        this.baseFilter = baseFilter;
75
        this.limit = limit;
76
        this.crs = crs;
77
    }
78

    
79
    @Override
80
    public final Object perform(Connection conn) throws DataException {
81
        Envelope env = calculateEnvelopeOfColumn(conn);
82
        return env;
83
    }
84

    
85
    public String getSQL() {
86
        if (this.helper.hasSpatialFunctions()) {
87
            return getSQLWithAggregate();
88
        } else {
89
            return getSQLWihoutAggregate();
90
        }
91
    }
92

    
93
    public String getSQLWihoutAggregate() {
94
        //Crear un select que devuelve todas las lineas
95
        JDBCSQLBuilderBase sqlbuilder = this.createSQLBuilder();
96
        GeometryExpressionBuilder expbuilder = sqlbuilder.expression();
97

    
98
        sqlbuilder.select().column().name(columnName).as_geometry();
99
        sqlbuilder.select().from().table()
100
                .database(this.table.getDatabase())
101
                .schema(this.table.getSchema())
102
                .name(this.table.getTable());
103

    
104
        sqlbuilder.select().from().subquery(this.table.getSubquery());
105
        if (!StringUtils.isEmpty(baseFilter)) {
106
            sqlbuilder.select().where().set(expbuilder.custom(baseFilter));
107
        }
108
        // todo ?
109
        sqlbuilder.select().where().and(expbuilder.not_is_null(expbuilder.column(columnName)));
110
        String sql = sqlbuilder.select().toString();
111
        return sql;
112
    }
113

    
114
    public String getSQLWithAggregate() {
115
        //
116
        // Parece ser que en versiones anteriores a SQL Server 2012 no esta
117
        // disponible la funcion ST_ExtentAggregate.
118
        // Habria que determinar si es necesario implementar una alternativa
119
        // para estos casos.
120
        //
121
        // https://alastaira.wordpress.com/2011/07/26/determining-the-geographic-extent-of-spatial-features-in-a-sql-server-table/
122
        //
123
        JDBCSQLBuilderBase sqlbuilder = this.createSQLBuilder();
124
        GeometryExpressionBuilder expbuilder = sqlbuilder.expression();
125

    
126
        sqlbuilder.select().column().value(
127
                //            expbuilder.ifnull(
128
                //                expbuilder.column(columnName), 
129
                //                expbuilder.constant(null), 
130
                expbuilder.as_geometry(
131
                        expbuilder.ST_ExtentAggregate(
132
                                expbuilder.column(columnName)
133
                        )
134
                )
135
        //            )
136
        );
137
//        sqlbuilder.select().group_by(expbuilder.column(columnName));
138
        sqlbuilder.select().from().table()
139
                .database(this.table.getDatabase())
140
                .schema(this.table.getSchema())
141
                .name(this.table.getTable());
142
        sqlbuilder.select().from().subquery(this.table.getSubquery());
143

    
144
        if (StringUtils.isEmpty(baseFilter)) {
145
            if (limit != null) {
146
                sqlbuilder.select().where().set(
147
                        expbuilder.ST_Intersects(
148
                                expbuilder.ST_Envelope(
149
                                        expbuilder.column(columnName)
150
                                ),
151
                                expbuilder.ST_Envelope(
152
                                        expbuilder.geometry(limit.getGeometry(), crs)
153
                                )
154
                        )
155
                );
156
            }
157
        } else {
158
            sqlbuilder.select().where().set(expbuilder.custom(baseFilter));
159
            if (limit != null) {
160
                sqlbuilder.select().where().and(
161
                        expbuilder.ST_Intersects(
162
                                expbuilder.ST_Envelope(
163
                                        expbuilder.column(columnName)
164
                                ),
165
                                expbuilder.ST_Envelope(
166
                                        expbuilder.geometry(limit.getGeometry(), crs)
167
                                )
168
                        )
169
                );
170
            }
171
        }
172
        sqlbuilder.select().where().and(
173
                expbuilder.not_is_null(expbuilder.column(columnName))
174
        );
175
        this.helper.processSpecialFunctions(sqlbuilder, featureType, null);
176
        sqlbuilder.setProperties(
177
                Variable.class,
178
                PROP_TABLE, table
179
        );
180
        String sql = sqlbuilder.select().toString();
181
        return sql;
182
    }
183

    
184
    public Envelope calculateEnvelopeOfColumn(Connection conn) throws DataException {
185
        if (this.helper.hasSpatialFunctions()) {
186
            return calculateEnvelopeOfColumnWithAggregate(conn);
187
        } else {
188
            return calculateEnvelopeOfColumnWithoutAggregate(conn);
189
        }
190
    }
191

    
192
    protected Envelope calculateEnvelopeOfColumnWithAggregate(Connection conn) throws DataException {
193
        String sql = this.getSQL();
194

    
195
        Statement st = null;
196
        ResultSet rs = null;
197
        try {
198
            st = conn.createStatement();
199
            try {
200
                LOGGER.debug("execute query SQL:" + sql);
201
                rs = st.executeQuery(sql);
202
                // No llamo al de JDBC utils para que no meta el error
203
                // en el log.
204
                // rs = JDBCUtils.executeQuery(st, sql);
205
            } catch (SQLException ex) {
206
//                Para calcular el envelope se esta lanzando una consulta como:
207
//                   SELECT ST_AsBinary(ST_Extent("geometry")) 
208
//                   FROM "gis_osm_roads_free_1" 
209
//                   WHERE ( ("geometry") IS NOT NULL )
210
//                Que falla cuando no hay registros al recibir un NULL en el 
211
//                ST_AsBinary. 
212
//                A falta de una forma mejor de detectar eso, si peta en este
213
//                punto asumiremos que no hay registros en la consulta y devolveremos
214
//                null como envelope.
215
//                A?ado un warn al LOGGER para tener constancia de lo que est? pasando.
216
                LOGGER.warn("Fail executing sql: "+sql, ex);
217
                return null;
218
            }
219
            if (!rs.next()) {
220
                return null;
221
            }
222
            Geometry geom = this.helper.getGeometryFromColumn(rs, 1);
223
            if (geom == null) {
224
                return null;
225
            }
226
            return geom.getEnvelope();
227

    
228
        } catch (SQLException ex) {
229
            throw new JDBCSQLException(ex);
230
        } finally {
231
            JDBCUtils.closeQuietly(st);
232
            JDBCUtils.closeQuietly(rs);
233
        }
234
    }
235

    
236
    protected Envelope calculateEnvelopeOfColumnWithoutAggregate(Connection conn) throws DataException {
237
//        crear una sql que devuelva un resultarSet
238
//bucle
239
//        iif instacia de string: cast string
240
//        GeometryLocator.getGeometryManager().createFrom("")
241
//        elif instance de bytearray con cast a bytearray:
242
//         GeometryLocator.getGeometryManager().createFrom("")    
243
//                 else:
244
//                 coerceToGeometry
245
//                         
246
//                         
247
//                         Notas: atrapar error, y si se produce error hago un coerceToGeometry       
248
        String sql = this.getSQL();
249

    
250
        Statement st = null;
251
        ResultSet rs = null;
252
        try {
253
            st = conn.createStatement();
254
            try {
255
                LOGGER.debug("execute query SQL:" + sql);
256
                rs = st.executeQuery(sql);
257
                // No llamo al de JDBC utils para que no meta el error
258
                // en el log.
259
                // rs = JDBCUtils.executeQuery(st, sql);
260
            } catch (SQLException ex) {
261
//                Para calcular el envelope se esta lanzando una colsulta como:
262
//                   SELECT ST_AsBinary(ST_Extent("geometry")) 
263
//                   FROM "gis_osm_roads_free_1" 
264
//                   WHERE ( ("geometry") IS NOT NULL )
265
//                Que falla cuando no hay registros al recibir un NULL en el 
266
//                ST_AsBinary. 
267
//                A falta de una forma mejor de detectar eso, si peta en este
268
//                punto asumiremos que no hay registros en la consulta y devolveremos
269
//                null como envelope.
270
                return null;
271
            }
272
            Envelope finalEnvelope = GeometryUtils.createEnvelope(Geometry.SUBTYPES.GEOM2D);
273
            while (rs.next()) {
274
                String geometryString = rs.getString("geometry");
275
                Geometry geometry = GeometryUtils.createFrom(geometryString);
276
                finalEnvelope.add(geometry);
277
            }
278
//            Geometry geom = this.helper.getGeometryFromColumn(rs, 1);
279
//            if (geom == null) {
280
//                return null;
281
//            }
282
//            return geom.getEnvelope();
283
            return finalEnvelope;
284
        } catch (SQLException ex) {
285
            throw new JDBCSQLException(ex);
286
        } finally {
287
            JDBCUtils.closeQuietly(st);
288
            JDBCUtils.closeQuietly(rs);
289
        }
290

    
291
    }
292

    
293
}