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 / ResultSetForSetProviderOperation.java @ 45712

History | View | Annotate | Download (16 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.util.ArrayList;
28
import java.util.HashMap;
29
import java.util.List;
30
import java.util.Map;
31
import java.util.function.Predicate;
32
import org.apache.commons.lang3.ArrayUtils;
33
import org.apache.commons.lang3.StringUtils;
34
import org.gvsig.expressionevaluator.Code;
35
import org.gvsig.expressionevaluator.Expression;
36
import org.gvsig.expressionevaluator.ExpressionBuilder;
37
import org.gvsig.expressionevaluator.ExpressionUtils;
38
import org.gvsig.fmap.dal.SQLBuilder.SelectBuilder;
39
import org.gvsig.fmap.dal.exception.DataException;
40
import org.gvsig.fmap.dal.expressionevaluator.FeatureAttributeEmulatorExpression;
41
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
42
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
43
import org.gvsig.fmap.dal.feature.FeatureQuery;
44
import org.gvsig.fmap.dal.feature.FeatureQueryOrder;
45
import org.gvsig.fmap.dal.feature.FeatureQueryOrder.FeatureQueryOrderMember;
46
import org.gvsig.fmap.dal.feature.FeatureType;
47
import org.gvsig.fmap.dal.store.jdbc2.JDBCHelper;
48
import org.gvsig.fmap.dal.store.jdbc2.OperationsFactory.TableReference;
49
import org.gvsig.fmap.dal.store.jdbc2.ResulSetControler.ResultSetEntry;
50
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase;
51
import static org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase.PROP_FEATURE_TYPE;
52
import static org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase.PROP_TABLE;
53
import org.gvsig.fmap.geom.DataTypes;
54
import org.gvsig.tools.evaluator.Evaluator;
55

    
56
public class ResultSetForSetProviderOperation extends AbstractConnectionOperation {
57

    
58
    private final TableReference table;
59
    private final String baseFilter;
60
    private final String baseOrder;
61
    private final FeatureType storeType;
62
    private final FeatureType setType;
63
    private final FeatureQuery query;
64
    private final long limit;
65
    private final long offset;
66
    private final int fetchSize;
67

    
68
    public ResultSetForSetProviderOperation(
69
            JDBCHelper helper,
70
            TableReference table,
71
            String baseFilter,
72
            String baseOrder,
73
            FeatureQuery query,
74
            FeatureType storeType,
75
            FeatureType setType,
76
            long limit,
77
            long offset,
78
            int fetchSize
79
    ) {
80
        super(helper);
81
        this.table = table;
82
        this.baseFilter = baseFilter;
83
        this.baseOrder = baseOrder;
84
        this.storeType = storeType;
85
        this.setType = setType;
86
        this.query = query;
87
        this.limit = limit;
88
        this.offset = offset;
89
        this.fetchSize = fetchSize;
90
    }
91

    
92
    @Override
93
    protected Object perform_operation() throws Exception {
94
        ResultSetEntry rs = createResultSet();
95
        return rs;
96
    }
97

    
98
    @Override
99
    public Object perform(Connection conn) throws DataException {
100
        throw new UnsupportedOperationException("Not supported yet.");
101
    }
102

    
103
    public String getSQL() {
104
        List<FeatureAttributeDescriptor> columns = new ArrayList<>();
105
        JDBCSQLBuilderBase sqlbuilder = createSQLBuilder();
106
        String sql = this.getSQL(sqlbuilder, columns, null);
107
        return sql;
108
    }
109

    
110
    public String getSQL(
111
            JDBCSQLBuilderBase sqlbuilder,
112
            List<FeatureAttributeDescriptor> columns,
113
            List<String> extraColumnNames
114
    ) {
115
        double tolerance = -1; //query.getScale();
116
        ExpressionBuilder expbuilder = sqlbuilder.expression();
117
        SelectBuilder select = sqlbuilder.select();
118

    
119
        Map<String, EditableFeatureAttributeDescriptor> allExtraColumns = new HashMap<>();
120
        for (EditableFeatureAttributeDescriptor column : this.setType.getExtraColumns().getColumns()) {
121
            allExtraColumns.put(column.getName(), column);
122
        }
123
        for (EditableFeatureAttributeDescriptor column : this.query.getExtraColumn().getColumns()) {
124
            allExtraColumns.put(column.getName(), column);
125
        }
126

    
127
        List<String> primaryKeys = new ArrayList<>();
128
        for (FeatureAttributeDescriptor attr : storeType.getPrimaryKey()) {
129
            primaryKeys.add(attr.getName());
130
        }
131
        List<String> forcedColumns = new ArrayList<>(primaryKeys);
132

    
133
        String[] constantsAttributeNames = null;
134
        if (query != null && query.hasConstantsAttributeNames()) {
135
            constantsAttributeNames = query.getConstantsAttributeNames();
136
        }
137
        for (FeatureAttributeDescriptor attr : setType) {
138
            if (attr.isComputed()) {
139
                continue;
140
            }
141
            if (ArrayUtils.contains(constantsAttributeNames, attr.getName())) {
142
                continue;
143
            }
144
            if (attr.isPrimaryKey()) {
145
                forcedColumns.remove(attr.getName());
146
            }
147
            if (query != null && query.hasGroupByColumns()) {
148
                String aggregate = query.getAggregate(this.table.getTable(), attr.getName());
149
                if (this.query.isAGroupByColumn(attr.getName())) {
150
                    select.column().name(attr.getName());
151
                } else if (aggregate == null) {
152
                    select.column().value(expbuilder.constant(null)).as(attr.getName());
153
                } else {
154
                    select.column()
155
                            .value(ExpressionUtils.compile(aggregate).toValue(expbuilder))
156
                            .as(attr.getName());
157
                }
158
            } else {
159
                if (attr.getType() == DataTypes.GEOMETRY) {
160
                    select.column().name(attr.getName()).as_geometry();
161
                    //                if( tolerance<=0 || !sqlbuilder.getConfig().has_functionality(Config.ST_Simplify)) {
162
                    //                    select.column().name(attr.getName()).as_geometry();
163
                    //                } else {
164
                    //                    select.column().value(
165
                    //                        sqlbuilder.ST_Simplify( 
166
                    //                            sqlbuilder.column(attr.getName()),
167
                    //                            sqlbuilder.constant(tolerance)
168
                    //                        )
169
                    //                    ).as_geometry();
170
                    //                }
171
                } else {
172
                    select.column().name(attr.getName());
173
                }
174
            }
175
            columns.add(attr);
176
        }
177

    
178
        if (query != null && query.hasGroupByColumns()) {
179
            for (Map.Entry<String, String> entry : query.getAggregateFunctions().entrySet()) {
180
                EditableFeatureAttributeDescriptor attr = allExtraColumns.get(entry.getKey());
181
                if (attr != null) {
182
                    Expression exp = ((FeatureAttributeEmulatorExpression) attr.getFeatureAttributeEmulator()).getExpression();
183
                    ExpressionBuilder.Function aggregateExp = expbuilder.function(entry.getValue(), exp.getCode().toValue());
184
                    if (!select.has_column(attr.getName())) {
185
                        select.column().value(aggregateExp).as(attr.getName());
186
                    }
187
                    if (!extraColumnNames.contains(attr.getName())) {
188
                        extraColumnNames.add(attr.getName());
189
                    }
190
                }
191
            }
192
            for (String attrName : query.getGroupByColumns()) {
193
                if (allExtraColumns.get(attrName) != null) { //from setType and query
194
                    EditableFeatureAttributeDescriptor attr = allExtraColumns.get(attrName);
195
                    select.group_by(expbuilder.column(attrName));
196
                    Expression exp = ((FeatureAttributeEmulatorExpression) attr.getFeatureAttributeEmulator()).getExpression();
197
                    if (!select.has_column(attrName)) {
198
                        select.column().value(exp.getCode().toValue()).as(attrName);
199
                    }
200
                    if (!extraColumnNames.contains(attr.getName())) {
201
                        extraColumnNames.add(attrName);
202
                    }
203
                } else if (setType.get(attrName) != null && setType.getAttributeDescriptor(attrName).isComputed()) {
204
                    FeatureAttributeDescriptor attr = setType.getAttributeDescriptor(attrName);
205
                    select.group_by(expbuilder.column(attrName));
206
                    Expression exp = ((FeatureAttributeEmulatorExpression) attr.getFeatureAttributeEmulator()).getExpression();
207
                    if (!select.has_column(attrName)) {
208
                        select.column().value(exp.getCode().toValue()).as(attrName);
209
                    }
210
                    if (!extraColumnNames.contains(attr.getName())) {
211
                        extraColumnNames.add(attrName);
212
                    }
213
                } else if (setType.get(attrName) == null) {
214
                    try {
215
                        Code code = ExpressionUtils.compile(attrName);
216
                        select.group_by(code.toValue());
217
                    } catch (Exception ex) {
218
                        throw new RuntimeException("Not able to create column by expression in groupby query", ex);
219
                    }
220
                } else {
221
                    ExpressionBuilder.Function atrcolumn = expbuilder.getattr(this.table.getTable(), attrName);
222
                    select.group_by(atrcolumn);
223
                }
224
            }
225
        } else {
226
            for (String attrName : forcedColumns) {
227
                select.column().name(attrName);
228
                columns.add(setType.getAttributeDescriptor(attrName));
229
            }
230
        }
231

    
232
        select.from().table()
233
                .database(this.table.getDatabase())
234
                .schema(this.table.getSchema())
235
                .name(this.table.getTable());
236
        select.from().subquery(this.table.getSubquery());
237

    
238
        Evaluator filter = query == null ? null : query.getFilter();
239
        if (filter != null) {
240
            String sqlfilter = filter.getSQL();
241
            if (!StringUtils.isEmpty(sqlfilter)) {
242
                if (this.helper.supportFilter(this.storeType, filter)) {
243
                    select.where().set(expbuilder.toValue(sqlfilter));
244
                }
245
            }
246
        }
247
        if (!StringUtils.isEmpty(baseFilter)) {
248
            select.where().and(expbuilder.toValue(baseFilter));
249
        }
250

    
251
        FeatureQueryOrder order = query == null ? null : query.getOrder();
252
        if (order != null) {
253
            for (FeatureQueryOrderMember member : order.members()) {
254
                String attrName = member.getAttributeName();
255
                if (member.hasEvaluator()) {
256
                    String sqlorder = member.getEvaluator().getSQL();
257
                    select.order_by()
258
                            .value(expbuilder.toValue(sqlorder))
259
                            .ascending(member.getAscending());
260
                } else {
261
                    if (allExtraColumns.get(attrName) != null) {
262
                        Expression exp = ((FeatureAttributeEmulatorExpression) allExtraColumns.get(attrName).getFeatureAttributeEmulator()).getExpression();
263
                        if (!select.has_column(attrName)) {
264
                            select.column().value(exp.getCode().toValue()).as(attrName);
265
                        }
266
                        if (!extraColumnNames.contains(attrName)) {
267
                            extraColumnNames.add(attrName);
268
                        }
269
                    } else if (setType.get(attrName) != null && setType.getAttributeDescriptor(attrName).isComputed()) {
270
                        Expression exp = ((FeatureAttributeEmulatorExpression) setType.getAttributeDescriptor(attrName).getFeatureAttributeEmulator()).getExpression();
271
                        if (!select.has_column(attrName)) {
272
                            select.column().value(exp.getCode().toValue()).as(attrName);
273
                        }
274
                        if (!extraColumnNames.contains(attrName)) {
275
                            extraColumnNames.add(attrName);
276
                        }
277
                    }
278
                    select.order_by()
279
                            .column(member.getAttributeName())
280
                            .ascending(member.getAscending());
281
                }
282
            }
283
        }
284

    
285
        if (!StringUtils.isEmpty(baseOrder)) {
286
            select.order_by().custom(baseOrder);
287
        }
288
        if (!select.has_order_by()) {
289
            // Si no tenemos order by comprobamos si lo necesitamos y lo a?adimos.
290
            if (offset > 0 || (offset == 0 && limit > 0)) {
291
                // No tengo claro que (offset==0 && limit>0) sea lo mas correcto,
292
                // Pero cuando se va a paginar y se pide la primera pagina offset es
293
                // 0 y limit>0, y si no ordenamos ya esa primera pagina los resultados
294
                // que se obtienen no son correctos, ya que la primera pagina se saca
295
                // sin ordenar y el resto ordenadas.
296
                // Probablemente deberiamos tener alguna otra forma de detectar que
297
                // estamos paginanado ya que asi no distinguimo si solo queremos 
298
                // obtener los primeros elementos sin importarnos su orden.
299
                if (select.has_group_by()) {
300
                    ExpressionBuilder.Value group = select.getGroups().get(0);
301
//                  if(!(group instanceof ExpressionBuilder.Function)) {
302
//                      expbuilder.getattr(this.table.getTable(), group.XXX);
303
//                  }
304
                    select.order_by().value(group).ascending();
305

    
306
                } else if (primaryKeys.isEmpty()) {
307
                    // Muy probablemente si no tiene pk sea una vista, asi que 
308
                    // pasaremos de ordenar y esperemos que la vista este ya ordenada.
309
                    select.disable_check_order_and_offset();
310
                } else {
311
                    for (String attrName : primaryKeys) {
312
                        // Se precisa indicar un orden para usar OFFSET.
313
                        //                    select.order_by().column(sqlbuilder.as_identifier(attrName)).ascending();
314
                        select.order_by().column(attrName).ascending();
315
                    }
316

    
317
                }
318
            }
319
        }
320
        if (limit > 0) {
321
            select.limit(limit);
322
        } else {
323
            select.limit(query == null ? null : query.getLimit());
324
        }
325
        if (offset > 0) {
326
            select.offset(offset);
327
        }
328
        sqlbuilder.setProperties(
329
                null,
330
                PROP_FEATURE_TYPE, this.storeType,
331
                PROP_TABLE, table
332
        );
333
        this.helper.processSpecialFunctions(sqlbuilder, storeType, extraColumnNames);
334
        String sql = sqlbuilder.toString();
335
        return sql;
336
    }
337

    
338
    public ResultSetEntry createResultSet() throws DataException {
339
        List<FeatureAttributeDescriptor> columns = new ArrayList<>();
340
        List<String> extraColumnNames = new ArrayList<>();
341

    
342
        JDBCSQLBuilderBase sqlbuilder = createSQLBuilder();
343
        String sql = this.getSQL(sqlbuilder, columns, extraColumnNames);
344

    
345
        ResultSetEntry resultSetEntry = this.helper.getResulSetControler().create(
346
                sql, fetchSize,
347
                columns.toArray(new FeatureAttributeDescriptor[columns.size()]),
348
                extraColumnNames.toArray(new String[extraColumnNames.size()])
349
        );
350
        return resultSetEntry;
351
    }
352

    
353
}