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 @ 47787

History | View | Annotate | Download (10.4 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.ResultSet;
27
import java.sql.SQLException;
28
import java.sql.Statement;
29
import org.apache.commons.lang3.StringUtils;
30
import org.cresques.cts.IProjection;
31
import org.gvsig.expressionevaluator.ExpressionBuilder.Variable;
32
import org.gvsig.expressionevaluator.GeometryExpressionBuilder;
33
import org.gvsig.fmap.dal.SQLBuilder;
34
import org.gvsig.fmap.dal.exception.DataException;
35
import org.gvsig.fmap.dal.feature.FeatureType;
36
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCSQLException;
37
import org.gvsig.fmap.dal.store.jdbc2.JDBCConnection;
38
import org.gvsig.fmap.dal.store.jdbc2.JDBCHelper;
39
import org.gvsig.fmap.dal.store.jdbc2.JDBCUtils;
40
import org.gvsig.fmap.dal.store.jdbc2.OperationsFactory.TableReference;
41
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase;
42
import static org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase.PROP_TABLE;
43
import org.gvsig.fmap.geom.Geometry;
44
import org.gvsig.fmap.geom.GeometryUtils;
45
import org.gvsig.fmap.geom.primitive.Envelope;
46

    
47
public class CalculateEnvelopeOfColumnOperation extends AbstractConnectionOperation {
48

    
49
    protected final TableReference table;
50
    protected final String columnName;
51
    protected final String baseFilter;
52
    protected final Envelope limit;
53
    protected final IProjection crs;
54
    protected final FeatureType featureType;
55

    
56
    public CalculateEnvelopeOfColumnOperation(
57
            JDBCHelper helper,
58
            FeatureType featureType,
59
            TableReference table,
60
            String columnName,
61
            String baseFilter,
62
            Envelope limit,
63
            IProjection crs
64
    ) {
65
        super(helper);
66
        this.featureType = featureType;
67
        this.table = table;
68
        this.columnName = columnName;
69
        this.baseFilter = baseFilter;
70
        this.limit = limit;
71
        this.crs = crs;
72
    }
73

    
74
    @Override
75
    public final Object perform(JDBCConnection conn) throws DataException {
76
        Envelope env = calculateEnvelopeOfColumn(conn);
77
        return env;
78
    }
79

    
80
    public String getSQL() {
81
        if (this.helper.hasSpatialFunctions()) {
82
            return getSQLWithAggregate();
83
        } else {
84
            return getSQLWihoutAggregate();
85
        }
86
    }
87

    
88
    public String getSQLWihoutAggregate() {
89
        //Crear un select que devuelve todas las lineas
90
        JDBCSQLBuilderBase sqlbuilder = this.createSQLBuilder();
91
        GeometryExpressionBuilder expbuilder = sqlbuilder.expression();
92

    
93
        sqlbuilder.select().from().table()
94
                .database(this.table.getDatabase())
95
                .schema(this.table.getSchema())
96
                .name(this.table.getTable());
97

    
98
        sqlbuilder.select().column().name(columnName).as_geometry();
99
        sqlbuilder.select().from().subquery(this.table.getSubquery());
100
        if (!StringUtils.isEmpty(baseFilter)) {
101
            sqlbuilder.select().where().set(expbuilder.custom(baseFilter));
102
        }
103
        // todo ?
104
        sqlbuilder.select().where().and(expbuilder.not_is_null(expbuilder.column(columnName)));
105
        String sql = sqlbuilder.select().toString();
106
        return sql;
107
    }
108

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

    
121
        SQLBuilder.SelectBuilder select = sqlbuilder.select();
122
        select.from().table()
123
                .database(this.table.getDatabase())
124
                .schema(this.table.getSchema())
125
                .name(this.table.getTable());
126

    
127
        select.column().value(
128
                expbuilder.as_geometry(
129
                        expbuilder.ST_ExtentAggregate(
130
                                sqlbuilder.column(select.from().table(),columnName)
131
                        )
132
                )
133
        );
134
        select.from().subquery(this.table.getSubquery());
135

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

    
176
    public Envelope calculateEnvelopeOfColumn(JDBCConnection conn) throws DataException {
177
        if (this.helper.hasSpatialFunctions()) {
178
            return calculateEnvelopeOfColumnWithAggregate(conn);
179
        } else {
180
            return calculateEnvelopeOfColumnWithoutAggregate(conn);
181
        }
182
    }
183

    
184
    protected Envelope calculateEnvelopeOfColumnWithAggregate(JDBCConnection conn) throws DataException {
185
        String sql = this.getSQL();
186

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

    
220
        } catch (SQLException ex) {
221
            throw new JDBCSQLException(ex,sql);
222
        } finally {
223
            JDBCUtils.closeQuietly(st);
224
            JDBCUtils.closeQuietly(rs);
225
        }
226
    }
227

    
228
    protected Envelope calculateEnvelopeOfColumnWithoutAggregate(JDBCConnection conn) throws DataException {
229
        String sql = this.getSQL();
230

    
231
        Statement st = null;
232
        ResultSet rs = null;
233
        try {
234
            st = conn.createStatement(sql);
235
            try {
236
                LOGGER.debug("execute query SQL:" + sql);
237
                rs = st.executeQuery(sql);
238
                // No llamo al de JDBC utils para que no meta el error
239
                // en el log.
240
                // rs = JDBCUtils.executeQuery(st, sql);
241
            } catch (SQLException ex) {
242
//                Para calcular el envelope se esta lanzando una colsulta como:
243
//                   SELECT ST_AsBinary(ST_Extent("geometry")) 
244
//                   FROM "gis_osm_roads_free_1" 
245
//                   WHERE ( ("geometry") IS NOT NULL )
246
//                Que falla cuando no hay registros al recibir un NULL en el 
247
//                ST_AsBinary. 
248
//                A falta de una forma mejor de detectar eso, si peta en este
249
//                punto asumiremos que no hay registros en la consulta y devolveremos
250
//                null como envelope.
251
                return null;
252
            }
253
            Envelope finalEnvelope = GeometryUtils.createEnvelope(Geometry.SUBTYPES.GEOM2D);
254
            while (rs.next()) {
255
                Geometry geometry = helper.getGeometryFromColumn(rs, 1);
256
                finalEnvelope.add(geometry);
257
            }
258
            return finalEnvelope;
259
        } catch (SQLException ex) {
260
            throw new JDBCSQLException(ex,sql);
261
        } finally {
262
            JDBCUtils.closeQuietly(st);
263
            JDBCUtils.closeQuietly(rs);
264
        }
265

    
266
    }
267

    
268
}