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

History | View | Annotate | Download (22.1 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 org.apache.commons.lang3.ArrayUtils;
32
import org.apache.commons.lang3.StringUtils;
33
import org.gvsig.expressionevaluator.Code;
34
import org.gvsig.expressionevaluator.Expression;
35
import org.gvsig.expressionevaluator.ExpressionBuilder;
36
import org.gvsig.expressionevaluator.ExpressionUtils;
37
import org.gvsig.expressionevaluator.SymbolTable;
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.FeatureAttributeEmulator;
44
import org.gvsig.fmap.dal.feature.FeatureExtraColumns;
45
import org.gvsig.fmap.dal.feature.FeatureQuery;
46
import org.gvsig.fmap.dal.feature.FeatureQueryOrder;
47
import org.gvsig.fmap.dal.feature.FeatureQueryOrder.FeatureQueryOrderMember;
48
import org.gvsig.fmap.dal.feature.FeatureType;
49
import org.gvsig.fmap.dal.store.jdbc2.JDBCHelper;
50
import org.gvsig.fmap.dal.store.jdbc2.OperationsFactory.TableReference;
51
import org.gvsig.fmap.dal.store.jdbc2.ResulSetControler.ResultSetEntry;
52
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase;
53
import static org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase.PROP_FEATURE_TYPE;
54
import static org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase.PROP_JDBCHELPER;
55
import static org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase.PROP_QUERY;
56
import static org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase.PROP_SYMBOLTABLE;
57
import static org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase.PROP_TABLE;
58
import org.gvsig.fmap.geom.DataTypes;
59
import org.gvsig.tools.dynobject.DynField;
60
import org.gvsig.tools.evaluator.Evaluator;
61
import org.gvsig.tools.util.ContainerUtils;
62

    
63
public class ResultSetForSetProviderOperation extends AbstractConnectionOperation {
64

    
65
    private final TableReference table;
66
    private final String baseFilter;
67
    private final String baseOrder;
68
    private final FeatureType storeType;
69
    private final FeatureType setType;
70
    private final FeatureQuery query;
71
    private final long limit;
72
    private final long offset;
73
    private final int fetchSize;
74

    
75
    public ResultSetForSetProviderOperation(
76
            JDBCHelper helper,
77
            TableReference table,
78
            String baseFilter,
79
            String baseOrder,
80
            FeatureQuery query,
81
            FeatureType storeType,
82
            FeatureType setType,
83
            long limit,
84
            long offset,
85
            int fetchSize
86
    ) {
87
        super(helper);
88
        this.table = table;
89
        this.baseFilter = baseFilter;
90
        this.baseOrder = baseOrder;
91
        this.storeType = storeType;
92
        this.setType = setType;
93
        this.query = query;
94
        this.limit = limit;
95
        this.offset = offset;
96
        this.fetchSize = fetchSize;
97
    }
98

    
99
    @Override
100
    protected Object perform_operation() throws Exception {
101
        ResultSetEntry rs = createResultSet();
102
        return rs;
103
    }
104

    
105
    @Override
106
    public Object perform(Connection conn) throws DataException {
107
        throw new UnsupportedOperationException("Not supported yet.");
108
    }
109

    
110
    public String getSQL() {
111
        List<FeatureAttributeDescriptor> columns = new ArrayList<>();
112
        JDBCSQLBuilderBase sqlbuilder = createSQLBuilder();
113
        String sql = this.getSQL(sqlbuilder, columns, null);
114
        return sql;
115
    }
116

    
117
    public String getSQL(
118
            JDBCSQLBuilderBase sqlbuilder,
119
            List<FeatureAttributeDescriptor> columns,
120
            List<String> extraColumnNames
121
    ) {
122
        double tolerance = -1; //query.getScale(); 
123
        ExpressionBuilder expbuilder = sqlbuilder.expression();
124
        SelectBuilder select = sqlbuilder.select();
125

    
126
        Map<String, EditableFeatureAttributeDescriptor> allExtraColumns = new HashMap<>();
127
        for (EditableFeatureAttributeDescriptor column : this.setType.getExtraColumns().getColumns()) {
128
            allExtraColumns.put(column.getName(), column);
129
        }
130
        if(query != null){
131
            for (EditableFeatureAttributeDescriptor column : this.query.getExtraColumn().getColumns()) {
132
                allExtraColumns.put(column.getName(), column);
133
            }
134
        }
135

    
136
        List<String> primaryKeys = new ArrayList<>();
137
        for (FeatureAttributeDescriptor attr : storeType.getPrimaryKey()) {
138
            primaryKeys.add(attr.getName());
139
        }
140
        List<String> forcedColumns = new ArrayList<>(primaryKeys);
141

    
142
        String[] constantsAttributeNames = null;
143
        if (query != null && query.hasConstantsAttributeNames()) {
144
            constantsAttributeNames = query.getConstantsAttributeNames();
145
        }
146
        ArrayList<ExpressionBuilder.Value> valuesToRemoveFeatureType = new ArrayList<>();
147
        for (FeatureAttributeDescriptor attr : setType) {
148
            if (attr.isComputed()) {
149
//              if(StringUtils.isNotBlank(System.getenv("ENABLE_COMPUTED_SQL_ATTR"))) { 
150
                if (attr.getRelationType() == DynField.RELATION_TYPE_NONE) {
151
                    FeatureAttributeEmulator attrEmulator = attr.getFeatureAttributeEmulator();
152
                    if (attrEmulator instanceof FeatureAttributeEmulatorExpression) {
153
                        FeatureAttributeEmulatorExpression x = (FeatureAttributeEmulatorExpression) attrEmulator;
154
                        Expression exp = x.getExpression();
155

    
156
                        if (query != null && query.hasGroupByColumns()) {
157
                            String aggregate = query.getAggregate(this.table.getTable(), attr.getName());
158
                            if (this.query.isAGroupByColumn(attr.getName())) {
159
                                if (!select.has_column(attr.getName())) {
160
                                    select.column().value(exp.getCode().toValue()).as(attr.getName());
161
                                }
162
                                if (extraColumnNames != null && !extraColumnNames.contains(attr.getName())) {
163
                                    extraColumnNames.add(attr.getName());
164
                                }
165
                            } else if (aggregate == null) {
166
                                select.column().value(expbuilder.constant(null)).as(attr.getName());
167
                            } else {
168
                                String fn = this.query.getAggregateFunctions().get(attr.getName());
169
                                ExpressionBuilder.Function aggregateExp = expbuilder.function(fn, exp.getCode().toValue());
170
                                if (!select.has_column(attr.getName())) {
171
                                    select.column().value(aggregateExp).as(attr.getName());
172
                                }
173
                                if (extraColumnNames != null && !extraColumnNames.contains(attr.getName())) {
174
                                    extraColumnNames.add(attr.getName());
175
                                }
176
                            }
177
                        } else {
178
                            if (exp != null && !exp.isEmpty() && this.helper.supportExpression(setType, exp.getPhrase())) {
179
                                Code code = exp.getCode();
180
                                select.column()
181
                                        .value(code.toValue(expbuilder))
182
                                        .as(attr.getName());
183
                                if (extraColumnNames != null && !extraColumnNames.contains(attr.getName())) {
184
                                    extraColumnNames.add(attr.getName());
185
                                }
186
                            }
187

    
188
                        }
189
                    }
190
                }
191
//              }
192
                continue;
193
            }
194
            if (ArrayUtils.contains(constantsAttributeNames, attr.getName())) {
195
                continue;
196
            }
197
            if (attr.isPrimaryKey()) {
198
                forcedColumns.remove(attr.getName());
199
            }
200
            if (query != null && query.hasGroupByColumns()) {
201
                String aggregate = query.getAggregate(this.table.getTable(), attr.getName());
202
                if (this.query.isAGroupByColumn(attr.getName())) {
203
                    select.column().name(attr.getName());
204
                } else if (aggregate == null) {
205
                    select.column().value(expbuilder.constant(null)).as(attr.getName());
206
                } else {
207
                    select.column()
208
                            .value(ExpressionUtils.compile(aggregate).toValue(expbuilder))
209
                            .as(attr.getName());
210
                }
211
            } else {
212
                if (attr.getType() == DataTypes.GEOMETRY) {
213
                    select.column().name(attr.getName()).as_geometry();
214
                    //                if( tolerance<=0 || !sqlbuilder.getConfig().has_functionality(Config.ST_Simplify)) {
215
                    //                    select.column().name(attr.getName()).as_geometry();
216
                    //                } else {
217
                    //                    select.column().value(
218
                    //                        sqlbuilder.ST_Simplify( 
219
                    //                            sqlbuilder.column(attr.getName()),
220
                    //                            sqlbuilder.constant(tolerance)
221
                    //                        )
222
                    //                    ).as_geometry();
223
                    //                }
224
                } else {
225
                    select.column().name(attr.getName());
226
                }
227
            }
228
            columns.add(attr);
229
        }
230

    
231
        if (query != null && query.hasGroupByColumns()) {
232
            for (Map.Entry<String, String> entry : query.getAggregateFunctions().entrySet()) {
233
                EditableFeatureAttributeDescriptor attr = allExtraColumns.get(entry.getKey());
234
                if (attr != null) {
235
                    Expression exp = ((FeatureAttributeEmulatorExpression) attr.getFeatureAttributeEmulator()).getExpression();
236
                    ExpressionBuilder.Function aggregateExp = expbuilder.function(entry.getValue(), exp.getCode().toValue());
237
                    if (!select.has_column(attr.getName())) {
238
                        select.column().value(aggregateExp).as(attr.getName());
239
                    }
240
                    if (extraColumnNames!=null && !extraColumnNames.contains(attr.getName())) {
241
                        extraColumnNames.add(attr.getName());
242
                    }
243
                }
244
            }
245
            for (String attrName : query.getGroupByColumns()) {
246
                if (allExtraColumns.get(attrName) != null) { //from setType and query
247
                    EditableFeatureAttributeDescriptor attr = allExtraColumns.get(attrName);
248
                    ExpressionBuilder.Variable col = expbuilder.column(attrName);
249
                    select.group_by(col);
250
                    // En el groupBy no queremos que se sustituya el nombre del campo calculado
251
                    // por su expresion. Se encarga el formater y lo evitamos quitandole el ftype
252
                    // al value.
253
                    valuesToRemoveFeatureType.add(col);
254
                    Expression exp = ((FeatureAttributeEmulatorExpression) attr.getFeatureAttributeEmulator()).getExpression();
255
                    if (!select.has_column(attrName)) {
256
                        select.column().value(exp.getCode().toValue()).as(attrName);
257
                    }
258
                    if (extraColumnNames!=null && !extraColumnNames.contains(attr.getName())) {
259
                        extraColumnNames.add(attrName);
260
                    }
261
                } else if (setType.get(attrName) != null && setType.getAttributeDescriptor(attrName).isComputed()) {
262
                    FeatureAttributeDescriptor attr = setType.getAttributeDescriptor(attrName);
263
                    ExpressionBuilder.Variable col = expbuilder.column(attrName);
264
                    select.group_by(col);
265
                    valuesToRemoveFeatureType.add(col);
266
                    Expression exp = ((FeatureAttributeEmulatorExpression) attr.getFeatureAttributeEmulator()).getExpression();
267
                    if (!select.has_column(attrName)) {
268
                        select.column().value(exp.getCode().toValue()).as(attrName);
269
                    }
270
                    if (extraColumnNames!=null && !extraColumnNames.contains(attr.getName())) {
271
                        extraColumnNames.add(attrName);
272
                    }
273
                } else if (setType.get(attrName) == null) {
274
                    try {
275
                        Code code = ExpressionUtils.compile(attrName);
276
                        select.group_by(code.toValue());
277
                    } catch (Exception ex) {
278
                        throw new RuntimeException("Not able to create column by expression in groupby query", ex);
279
                    }
280
                } else {
281
                    ExpressionBuilder.Function atrcolumn = expbuilder.getattr(this.table.getTable(), attrName);
282
                    select.group_by(atrcolumn);
283
                }
284
            }
285
        } else {
286
            for (String attrName : forcedColumns) {
287
                select.column().name(attrName);
288
                columns.add(setType.getAttributeDescriptor(attrName));
289
            }
290
            if (this.query != null) {
291
                FeatureExtraColumns extraColumns = this.query.getExtraColumn();
292
                if (extraColumns != null && !extraColumns.isEmpty()) {
293
                    for (EditableFeatureAttributeDescriptor attr : extraColumns.getColumns()) {
294
                        if (!attr.isComputed()) {
295
                            continue;
296
                        }
297
                        FeatureAttributeEmulator attrEmulator = attr.getFeatureAttributeEmulator();
298
                        if (attrEmulator instanceof FeatureAttributeEmulatorExpression) {
299
                            FeatureAttributeEmulatorExpression x = (FeatureAttributeEmulatorExpression) attrEmulator;
300
                            Expression exp = x.getExpression();
301
                            if (exp != null && !exp.isEmpty() && this.helper.supportExpression(setType, exp.getPhrase())) {
302
                                Code code = exp.getCode();
303
                                select.column()
304
                                        .value(code.toValue(expbuilder))
305
                                        .as(attr.getName());
306
                                if (extraColumnNames!=null && !extraColumnNames.contains(attr.getName())) {
307
                                    extraColumnNames.add(attr.getName());
308
                                }
309
                            }
310
                        }
311
                    }
312
                }
313
            }
314
        }
315

    
316
        select.from().table()
317
                .database(this.table.getDatabase())
318
                .schema(this.table.getSchema())
319
                .name(this.table.getTable());
320
        select.from().subquery(this.table.getSubquery());
321

    
322
        Evaluator filter = query == null ? null : query.getFilter();
323
        if (filter != null) {
324
            String sqlfilter = filter.getSQL();
325
            if (!StringUtils.isEmpty(sqlfilter)) {
326
                if (this.helper.supportFilter(this.storeType, filter)) {
327
                    select.where().set(expbuilder.toValue(sqlfilter));
328
                }
329
            }
330
        }
331
        if (!StringUtils.isEmpty(baseFilter)) {
332
            select.where().and(expbuilder.toValue(baseFilter));
333
        }
334

    
335
        FeatureQueryOrder order = query == null ? null : query.getOrder();
336
        if (order != null) {
337
            for (FeatureQueryOrderMember member : order.members()) {
338
                String attrName = member.getAttributeName();
339
                if (member.hasEvaluator()) {
340
                    String sqlorder = member.getEvaluator().getSQL();
341
                    select.order_by()
342
                            .value(expbuilder.toValue(sqlorder))
343
                            .ascending(member.getAscending());
344
                } else {
345
                    if (allExtraColumns.get(attrName) != null) {
346
                        Expression exp = ((FeatureAttributeEmulatorExpression) allExtraColumns.get(attrName).getFeatureAttributeEmulator()).getExpression();
347
                        if (!select.has_column(attrName)) {
348
                            select.column().value(exp.getCode().toValue()).as(attrName);
349
                        }
350
                        if (extraColumnNames!=null && !extraColumnNames.contains(attrName)) {
351
                            extraColumnNames.add(attrName);
352
                        }
353
                    } else if (setType.get(attrName) != null && setType.getAttributeDescriptor(attrName).isComputed()) {
354
                        Expression exp = ((FeatureAttributeEmulatorExpression) setType.getAttributeDescriptor(attrName).getFeatureAttributeEmulator()).getExpression();
355
                        if (!select.has_column(attrName)) {
356
                            select.column().value(exp.getCode().toValue()).as(attrName);
357
                        }
358
                        if (extraColumnNames!=null && !extraColumnNames.contains(attrName)) {
359
                            extraColumnNames.add(attrName);
360
                        }
361
                    }
362
                    select.order_by()
363
                            .column(member.getAttributeName())
364
                            .ascending(member.getAscending());
365
                }
366
            }
367
        }
368

    
369
        if (!StringUtils.isEmpty(baseOrder)) {
370
            select.order_by().custom(baseOrder);
371
        }
372
        //Si hay especificado un offset (se esta paginando) siempre deberemos ordenar por un campo con valores unicos.
373
        //Anadiremos la clave primaria siempre en este caso para asegurarnos de que el orden de los registros es siempre el mismo.
374
//        if (!select.has_order_by()) {
375
            // Si no tenemos order by comprobamos si lo necesitamos y lo a?adimos.
376
            if (offset > 0 || (offset == 0 && limit > 0)) {
377
                // No tengo claro que (offset==0 && limit>0) sea lo mas correcto,
378
                // Pero cuando se va a paginar y se pide la primera pagina offset es
379
                // 0 y limit>0, y si no ordenamos ya esa primera pagina los resultados
380
                // que se obtienen no son correctos, ya que la primera pagina se saca
381
                // sin ordenar y el resto ordenadas.
382
                // Probablemente deberiamos tener alguna otra forma de detectar que
383
                // estamos paginanado ya que asi no distinguimo si solo queremos 
384
                // obtener los primeros elementos sin importarnos su orden.
385
                if (select.has_group_by()) {
386
                    ExpressionBuilder.Value group = select.getGroups().get(0);
387
//                  if(!(group instanceof ExpressionBuilder.Function)) {
388
//                      expbuilder.getattr(this.table.getTable(), group.XXX);
389
//                  }
390
                    select.order_by().value(group).ascending();
391

    
392
                } else if (primaryKeys.isEmpty()) {
393
                    // Muy probablemente si no tiene pk sea una vista, asi que 
394
                    // pasaremos de ordenar y esperemos que la vista este ya ordenada.
395
                    select.disable_check_order_and_offset();
396
                } else {
397
                    for (String attrName : primaryKeys) {
398
                        // Se precisa indicar un orden para usar OFFSET.
399
                        if(select.getOrderBy(attrName)==null){
400
                            select.order_by().column(attrName).ascending();
401
                        }
402
                    }
403
                }
404
            }
405
//        }
406
        for (String attrName : primaryKeys) {
407
            if(select.getOrderBy(attrName)==null){
408
                select.order_by().column(attrName).ascending();
409
            }
410
        }
411
        if (limit > 0) {
412
            select.limit(limit);
413
        } else {
414
            select.limit(query == null ? null : query.getLimit());
415
        }
416
        if (offset > 0) {
417
            select.offset(offset);
418
        }
419
        sqlbuilder.setProperties(
420
                null,
421
                PROP_FEATURE_TYPE, this.storeType,
422
                PROP_TABLE, table,
423
                PROP_SYMBOLTABLE, this.query==null? null:this.query.getSymbolTable(),
424
                PROP_JDBCHELPER, this.helper,
425
                PROP_QUERY, this.query
426
        );
427
        for (ExpressionBuilder.Value value : valuesToRemoveFeatureType) {
428
            value.setProperty(PROP_FEATURE_TYPE, null);
429
        }
430
        this.helper.processSpecialFunctions(sqlbuilder, storeType, extraColumnNames);
431
        String sql = sqlbuilder.toString();
432
        return sql;
433
    }
434

    
435
    public ResultSetEntry createResultSet() throws DataException {
436
        List<FeatureAttributeDescriptor> columns = new ArrayList<>();
437
        List<String> extraColumnNames = new ArrayList<>();
438

    
439
        JDBCSQLBuilderBase sqlbuilder = createSQLBuilder();
440
        String sql = this.getSQL(sqlbuilder, columns, extraColumnNames);
441

    
442
        ResultSetEntry resultSetEntry = this.helper.getResulSetControler().create(
443
                sql, fetchSize,
444
                columns.toArray(new FeatureAttributeDescriptor[columns.size()]),
445
                extraColumnNames.toArray(new String[extraColumnNames.size()])
446
        );
447
        return resultSetEntry;
448
    }
449

    
450
}