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

History | View | Annotate | Download (10.2 KB)

1
package org.gvsig.fmap.dal.store.jdbc2.spi.operations;
2

    
3
import java.sql.Connection;
4
import java.sql.ResultSet;
5
import java.sql.SQLException;
6
import java.sql.Statement;
7
import org.apache.commons.lang3.StringUtils;
8
import org.cresques.cts.IProjection;
9
import org.gvsig.expressionevaluator.ExpressionBuilder.Variable;
10
import org.gvsig.expressionevaluator.GeometryExpressionBuilder;
11
import org.gvsig.fmap.dal.exception.DataException;
12
import org.gvsig.fmap.dal.feature.FeatureType;
13
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCSQLException;
14
import org.gvsig.fmap.dal.store.jdbc2.JDBCHelper;
15
import org.gvsig.fmap.dal.store.jdbc2.JDBCUtils;
16
import org.gvsig.fmap.dal.store.jdbc2.OperationsFactory.TableReference;
17
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase;
18
import static org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase.PROP_TABLE;
19
import org.gvsig.fmap.geom.Geometry;
20
import org.gvsig.fmap.geom.GeometryUtils;
21
import org.gvsig.fmap.geom.primitive.Envelope;
22

    
23
public class CalculateEnvelopeOfColumnOperation extends AbstractConnectionOperation {
24

    
25
    private final TableReference table;
26
    private final String columnName;
27
    private final String baseFilter;
28
    private final Envelope limit;
29
    private final IProjection crs;
30
    private final FeatureType featureType;
31

    
32
    public CalculateEnvelopeOfColumnOperation(
33
            JDBCHelper helper,
34
            FeatureType featureType,
35
            TableReference table,
36
            String columnName,
37
            String baseFilter,
38
            Envelope limit,
39
            IProjection crs
40
    ) {
41
        super(helper);
42
        this.featureType = featureType;
43
        this.table = table;
44
        this.columnName = columnName;
45
        this.baseFilter = baseFilter;
46
        this.limit = limit;
47
        this.crs = crs;
48
    }
49

    
50
    @Override
51
    public final Object perform(Connection conn) throws DataException {
52
        Envelope env = calculateEnvelopeOfColumn(conn);
53
        return env;
54
    }
55

    
56
    public String getSQL() {
57
        if (this.helper.hasSpatialFunctions()) {
58
            return getSQLWithAggregate();
59
        } else {
60
            return getSQLWihoutAggregate();
61
        }
62
    }
63

    
64
    public String getSQLWihoutAggregate() {
65
        //Crear un select que devuelve todas las lineas
66
        JDBCSQLBuilderBase sqlbuilder = this.createSQLBuilder();
67
        GeometryExpressionBuilder expbuilder = sqlbuilder.expression();
68

    
69
        sqlbuilder.select().column().name(columnName).as_geometry();
70
        sqlbuilder.select().from().table()
71
                .database(this.table.getDatabase())
72
                .schema(this.table.getSchema())
73
                .name(this.table.getTable());
74

    
75
        sqlbuilder.select().from().subquery(this.table.getSubquery());
76
        if (!StringUtils.isEmpty(baseFilter)) {
77
            sqlbuilder.select().where().set(expbuilder.custom(baseFilter));
78
        }
79
        // todo ?
80
        sqlbuilder.select().where().and(expbuilder.not_is_null(expbuilder.column(columnName)));
81
        String sql = sqlbuilder.select().toString();
82
        return sql;
83
    }
84

    
85
    public String getSQLWithAggregate() {
86
        //
87
        // Parece ser que en versiones anteriores a SQL Server 2012 no esta
88
        // disponible la funcion ST_ExtentAggregate.
89
        // Habria que determinar si es necesario implementar una alternativa
90
        // para estos casos.
91
        //
92
        // https://alastaira.wordpress.com/2011/07/26/determining-the-geographic-extent-of-spatial-features-in-a-sql-server-table/
93
        //
94
        JDBCSQLBuilderBase sqlbuilder = this.createSQLBuilder();
95
        GeometryExpressionBuilder expbuilder = sqlbuilder.expression();
96

    
97
        sqlbuilder.select().column().value(
98
                //            expbuilder.ifnull(
99
                //                expbuilder.column(columnName), 
100
                //                expbuilder.constant(null), 
101
                expbuilder.as_geometry(
102
                        expbuilder.ST_ExtentAggregate(
103
                                expbuilder.column(columnName)
104
                        )
105
                )
106
        //            )
107
        );
108
//        sqlbuilder.select().group_by(expbuilder.column(columnName));
109
        sqlbuilder.select().from().table()
110
                .database(this.table.getDatabase())
111
                .schema(this.table.getSchema())
112
                .name(this.table.getTable());
113
        sqlbuilder.select().from().subquery(this.table.getSubquery());
114

    
115
        if (StringUtils.isEmpty(baseFilter)) {
116
            if (limit != null) {
117
                sqlbuilder.select().where().set(
118
                        expbuilder.ST_Intersects(
119
                                expbuilder.ST_Envelope(
120
                                        expbuilder.column(columnName)
121
                                ),
122
                                expbuilder.ST_Envelope(
123
                                        expbuilder.geometry(limit.getGeometry(), crs)
124
                                )
125
                        )
126
                );
127
            }
128
        } else {
129
            sqlbuilder.select().where().set(expbuilder.custom(baseFilter));
130
            if (limit != null) {
131
                sqlbuilder.select().where().and(
132
                        expbuilder.ST_Intersects(
133
                                expbuilder.ST_Envelope(
134
                                        expbuilder.column(columnName)
135
                                ),
136
                                expbuilder.ST_Envelope(
137
                                        expbuilder.geometry(limit.getGeometry(), crs)
138
                                )
139
                        )
140
                );
141
            }
142
        }
143
        sqlbuilder.select().where().and(
144
                expbuilder.not_is_null(expbuilder.column(columnName))
145
        );
146
        this.helper.processSpecialFunctions(sqlbuilder, featureType, null);
147
        sqlbuilder.setProperties(
148
                Variable.class,
149
                PROP_TABLE, table
150
        );
151
        String sql = sqlbuilder.select().toString();
152
        return sql;
153
    }
154

    
155
    public Envelope calculateEnvelopeOfColumn(Connection conn) throws DataException {
156
        if (this.helper.hasSpatialFunctions()) {
157
            return calculateEnvelopeOfColumnWithAggregate(conn);
158
        } else {
159
            return calculateEnvelopeOfColumnWithoutAggregate(conn);
160
        }
161
    }
162

    
163
    private Envelope calculateEnvelopeOfColumnWithAggregate(Connection conn) throws DataException {
164
        String sql = this.getSQL();
165

    
166
        Statement st = null;
167
        ResultSet rs = null;
168
        try {
169
            st = conn.createStatement();
170
            try {
171
                LOGGER.debug("execute query SQL:" + sql);
172
                rs = st.executeQuery(sql);
173
                // No llamo al de JDBC utils para que no meta el error
174
                // en el log.
175
                // rs = JDBCUtils.executeQuery(st, sql);
176
            } catch (SQLException ex) {
177
//                Para calcular el envelope se esta lanzando una colsulta como:
178
//                   SELECT ST_AsBinary(ST_Extent("geometry")) 
179
//                   FROM "gis_osm_roads_free_1" 
180
//                   WHERE ( ("geometry") IS NOT NULL )
181
//                Que falla cuando no hay registros al recibir un NULL en el 
182
//                ST_AsBinary. 
183
//                A falta de una forma mejor de detectar eso, si peta en este
184
//                punto asumiremos que no hay registros en la consulta y devolveremos
185
//                null como envelope.
186
                return null;
187
            }
188
            if (!rs.next()) {
189
                return null;
190
            }
191
            Geometry geom = this.helper.getGeometryFromColumn(rs, 1);
192
            if (geom == null) {
193
                return null;
194
            }
195
            return geom.getEnvelope();
196

    
197
        } catch (SQLException ex) {
198
            throw new JDBCSQLException(ex);
199
        } finally {
200
            JDBCUtils.closeQuietly(st);
201
            JDBCUtils.closeQuietly(rs);
202
        }
203
    }
204

    
205
    private Envelope calculateEnvelopeOfColumnWithoutAggregate(Connection conn) throws DataException {
206
//        crear una sql que devuelva un resultarSet
207
//bucle
208
//        iif instacia de string: cast string
209
//        GeometryLocator.getGeometryManager().createFrom("")
210
//        elif instance de bytearray con cast a bytearray:
211
//         GeometryLocator.getGeometryManager().createFrom("")    
212
//                 else:
213
//                 coerceToGeometry
214
//                         
215
//                         
216
//                         Notas: atrapar error, y si se produce error hago un coerceToGeometry       
217
        String sql = this.getSQL();
218

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

    
260
    }
261

    
262
}