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

History | View | Annotate | Download (30.2 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.util.ArrayList;
27
import java.util.HashMap;
28
import java.util.List;
29
import java.util.Map;
30
import org.apache.commons.lang3.ArrayUtils;
31
import org.apache.commons.lang3.BooleanUtils;
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 static org.gvsig.expressionevaluator.ExpressionBuilder.FUNCTION_LET;
37
import org.gvsig.expressionevaluator.ExpressionUtils;
38
import org.gvsig.fmap.dal.SQLBuilder;
39
import org.gvsig.fmap.dal.SQLBuilder.OrderByBuilder;
40
import org.gvsig.fmap.dal.SQLBuilder.SelectBuilder;
41
import org.gvsig.fmap.dal.exception.DataException;
42
import org.gvsig.fmap.dal.expressionevaluator.FeatureAttributeEmulatorExpression;
43
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
44
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
45
import org.gvsig.fmap.dal.feature.FeatureAttributeEmulator;
46
import org.gvsig.fmap.dal.feature.FeatureExtraColumns;
47
import org.gvsig.fmap.dal.feature.FeatureQuery;
48
import org.gvsig.fmap.dal.feature.FeatureQueryOrder;
49
import org.gvsig.fmap.dal.feature.FeatureQueryOrder.FeatureQueryOrderMember;
50
import org.gvsig.fmap.dal.feature.FeatureType;
51
import org.gvsig.fmap.dal.store.jdbc2.JDBCConnection;
52
import org.gvsig.fmap.dal.store.jdbc2.JDBCHelper;
53
import org.gvsig.fmap.dal.store.jdbc2.JDBCServerExplorer;
54
import static org.gvsig.fmap.dal.store.jdbc2.JDBCServerExplorer.QUERY_DONT_ADD_PRIMARY_KEY_IN_THE_ORDER;
55
import org.gvsig.fmap.dal.store.jdbc2.OperationsFactory.TableReference;
56
import org.gvsig.fmap.dal.store.jdbc2.ResulSetControler.ResultSetEntry;
57
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase;
58
import static org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase.PROP_FEATURE_TYPE;
59
import static org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase.PROP_JDBCHELPER;
60
import static org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase.PROP_QUERY;
61
import static org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase.PROP_SYMBOLTABLE;
62
import static org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase.PROP_TABLE;
63
import org.gvsig.fmap.geom.DataTypes;
64
import org.gvsig.tools.dataTypes.DataTypeUtils;
65
import org.gvsig.tools.dynobject.DynField;
66
import org.gvsig.tools.evaluator.Evaluator;
67
import org.gvsig.tools.lang.CloneableUtils;
68

    
69
public class ResultSetForSetProviderOperation extends AbstractConnectionOperation {
70

    
71
    private final TableReference table;
72
    private final String baseFilter;
73
    private final String baseOrder;
74
    private final FeatureType storeType;
75
    private final FeatureType setType;
76
    private final FeatureQuery query;
77
    private final long limit;
78
    private final long offset;
79
    private final int fetchSize;
80

    
81
    public ResultSetForSetProviderOperation(
82
            JDBCHelper helper,
83
            TableReference table,
84
            String baseFilter,
85
            String baseOrder,
86
            FeatureQuery query,
87
            FeatureType storeType,
88
            FeatureType setType,
89
            long limit,
90
            long offset,
91
            int fetchSize
92
    ) {
93
        super(helper);
94
        this.table = table;
95
        this.baseFilter = baseFilter;
96
        this.baseOrder = baseOrder;
97
        this.storeType = storeType;
98
        this.setType = setType;
99
        this.query = query;
100
        this.limit = limit;
101
        this.offset = offset;
102
        this.fetchSize = fetchSize;
103
    }
104

    
105
    @Override
106
    protected Object perform_operation() throws Exception {
107
        ResultSetEntry rs = createResultSet();
108
        return rs;
109
    }
110

    
111
    @Override
112
    public Object perform(JDBCConnection conn) throws DataException {
113
        throw new UnsupportedOperationException("Not supported yet.");
114
    }
115

    
116
    public String getSQL() {
117
        List<FeatureAttributeDescriptor> columns = new ArrayList<>();
118
        JDBCSQLBuilderBase sqlbuilder = createSQLBuilder();
119
        String sql = this.getSQL(sqlbuilder, columns, null);
120
        return sql;
121
    }
122

    
123
    public String getSQL(
124
            JDBCSQLBuilderBase sqlbuilder,
125
            List<FeatureAttributeDescriptor> columns,
126
            List<String> extraColumnNames
127
    ) {
128
        double tolerance = -1; //query.getScale(); 
129
        ExpressionBuilder expbuilder = sqlbuilder.expression();
130
        SelectBuilder select = sqlbuilder.select();
131
        ArrayList<ExpressionBuilder.Value> valuesToRemoveFeatureType = new ArrayList<>();
132
        
133
        if( shouldUseACustomSelect() ) {
134
            String sql = table.getSubquery();
135
            if( StringUtils.containsAny(sql, "${where_filter}", "${and_filter}") ) {
136
                Evaluator filter = query.getFilter();
137
                if (filter != null) {
138
                    String sqlfilter = filter.getSQL();
139
                    if (!StringUtils.isEmpty(sqlfilter)) {
140
                        if (this.helper.supportFilter(this.storeType, filter)) {
141
                            select.where().set(expbuilder.toValue(sqlfilter));
142
                        }
143
                    }
144
                }
145
                if (!StringUtils.isEmpty(baseFilter)) {
146
                    select.where().and(expbuilder.toValue(baseFilter));
147
                }
148
            }
149
            if( StringUtils.containsAny(sql, "${order_by_orderspec}", "${comma_orderspec}") ) {
150
                FeatureQueryOrder order = query.getOrder();
151
                if (order != null) {
152
                    for (FeatureQueryOrderMember member : order.members()) {
153
                        String attrName = member.getAttributeName();
154
                        ExpressionBuilder.Variable col = expbuilder.column(attrName);
155
                        select.order_by().value(col).ascending(member.getAscending());
156
                    }
157
                }
158
            }
159
            if( select.has_where() || select.has_order_by() ) {
160
                sqlbuilder.setProperties(
161
                        null,
162
                        PROP_FEATURE_TYPE, this.storeType,
163
                        PROP_TABLE, table,
164
                        PROP_SYMBOLTABLE, this.query==null? null:this.query.getSymbolTable(),
165
                        PROP_JDBCHELPER, this.helper,
166
                        PROP_QUERY, this.query
167
                );
168
                for (ExpressionBuilder.Value value : valuesToRemoveFeatureType) {
169
                    value.setProperty(PROP_FEATURE_TYPE, null);
170
                }
171
                if( select.has_where()) {
172
                    String s = select.where().toString();
173
                    sql = StringUtils.replace(sql, "${where_filter}", "WHERE " + s);
174
                    sql = StringUtils.replace(sql, "${and_filter}", "AND (" + s + ")");
175
                }
176
                if( select.has_order_by() ) {
177
                    String s = select.order_by().toString();
178
                    sql = StringUtils.replace(sql, "${order_by_orderspec}", "ORDER BY " + s);
179
                    sql = StringUtils.replace(sql, "${comma_orderspec}", ", "+ s);
180
                }
181
            }
182
            for (FeatureAttributeDescriptor attr : storeType) {
183
                columns.add(attr);
184
            }
185
            return sql;
186
        }
187
        
188

    
189
        Map<String, EditableFeatureAttributeDescriptor> allExtraColumns = new HashMap<>();
190
        for (EditableFeatureAttributeDescriptor column : this.setType.getExtraColumns().getColumns()) {
191
            allExtraColumns.put(column.getName(), column);
192
        }
193
        if(query != null){
194
            for (EditableFeatureAttributeDescriptor column : this.query.getExtraColumn().getColumns()) {
195
                allExtraColumns.put(column.getName(), column);
196
            }
197
        }
198

    
199
        List<String> primaryKeys = new ArrayList<>();
200
        for (FeatureAttributeDescriptor attr : storeType.getPrimaryKey()) {
201
            primaryKeys.add(attr.getName());
202
        }
203
        List<String> forcedColumns = new ArrayList<>(primaryKeys);
204

    
205
        String[] constantsAttributeNames = null;
206
        if (query != null && query.hasConstantsAttributeNames()) {
207
            constantsAttributeNames = query.getConstantsAttributeNames();
208
        }
209
        for (FeatureAttributeDescriptor attr : setType) {
210
            if (attr.isComputed()) {
211
                // Campos calculados se a?aden despues para asegurarnos que
212
                // primeros se a?aden los campos reales y al final los calculados
213
                continue;
214
            }
215
            if (ArrayUtils.contains(constantsAttributeNames, attr.getName())) {
216
                continue;
217
            }
218
            if (attr.isPrimaryKey()) {
219
                forcedColumns.remove(attr.getName());
220
            }
221
            if (query != null && (query.hasGroupByColumns() || query.hasAggregateFunctions()) )  {
222
                String aggregate = query.getAggregate(this.table.getTable(), attr.getName());                
223
                if (aggregate == null) {
224
                    if (this.query.isAGroupByColumn(attr.getName()) ) {
225
                        select.column().name(attr.getName());
226
                    } else if (aggregate == null) {
227
                        select.column().value(expbuilder.constant(null)).as(attr.getName());
228
                    }                    
229
                } else {
230
                    select.column()
231
                            .value(ExpressionUtils.compile(aggregate).toValue(expbuilder))
232
                            .as(attr.getName());
233
                }
234
            } else {
235
                if (attr.getType() == DataTypes.GEOMETRY) {
236
                    select.column().name(attr.getName()).as_geometry();
237
                    //                if( tolerance<=0 || !sqlbuilder.getConfig().has_functionality(Config.ST_Simplify)) {
238
                    //                    select.column().name(attr.getName()).as_geometry();
239
                    //                } else {
240
                    //                    select.column().value(
241
                    //                        sqlbuilder.ST_Simplify( 
242
                    //                            sqlbuilder.column(attr.getName()),
243
                    //                            sqlbuilder.constant(tolerance)
244
                    //                        )
245
                    //                    ).as_geometry();
246
                    //                }
247
                } else {
248
                    select.column().name(attr.getName());
249
                }
250
            }
251
            columns.add(attr);
252
        }
253

    
254
        if (query == null || !query.hasGroupByColumns()) {
255
            for (String attrName : forcedColumns) {
256
                select.column().name(attrName);
257
                FeatureAttributeDescriptor attr = setType.getAttributeDescriptor(attrName);
258
                // Ojo, que cuando estamos pintando una vista NO TENEMOS LA PK y attr vale null!!!!
259
                // No se si deberiamos forzar a que cuando se crea un subfeaturetype se meta siempre
260
                // la pk, o simplemente nunca asumir que la vamos a tener.
261
                if (attr != null) {
262
                    columns.add(attr);
263
                }
264
            }
265
        }
266
        
267
        // Despues de a?adir los campos reales, se a?aden los campos calculados
268
        for (FeatureAttributeDescriptor attr : setType) {
269
            if (attr.isComputed()) {
270
                if (attr.getRelationType() == DynField.RELATION_TYPE_NONE) {
271
                    FeatureAttributeEmulator attrEmulator = attr.getFeatureAttributeEmulator();
272
                    if (attrEmulator instanceof FeatureAttributeEmulatorExpression) {
273
                        FeatureAttributeEmulatorExpression x = (FeatureAttributeEmulatorExpression) attrEmulator;
274
                        Expression exp = x.getExpression();
275

    
276
                        if (query != null && query.hasGroupByColumns()) {
277
                            String aggregate = query.getAggregate(this.table.getTable(), attr.getName());
278
                            if (this.query.isAGroupByColumn(attr.getName())) {
279
                                if (!select.has_column(attr.getName())) {
280
                                    select.column().value(exp.getCode().toValue()).as(attr.getName());
281
                                }
282
                                if (extraColumnNames != null && !extraColumnNames.contains(attr.getName())) {
283
                                    extraColumnNames.add(attr.getName());
284
                                }
285
                            } else if (aggregate == null) {
286
                                select.column().value(expbuilder.constant(null)).as(attr.getName());
287
                                
288
                                if (extraColumnNames != null && !extraColumnNames.contains(attr.getName())) {
289
                                    extraColumnNames.add(attr.getName());
290
                                }
291
                            } else {
292
                                String fn = this.query.getAggregateFunctions().get(attr.getName());
293
                                ExpressionBuilder.Function aggregateExp = expbuilder.function(fn, exp.getCode().toValue());
294
                                if (!select.has_column(attr.getName())) {
295
                                    select.column().value(aggregateExp).as(attr.getName());
296
                                }
297
                                if (extraColumnNames != null && !extraColumnNames.contains(attr.getName())) {
298
                                    extraColumnNames.add(attr.getName());
299
                                }
300
                            }
301
                        } else {
302
                            if (exp != null && !exp.isEmpty() && this.helper.supportExpression(setType, exp.getPhrase())) {
303
                                Code code = exp.getCode();
304
                                select.column()
305
                                        .value(code.toValue(expbuilder))
306
                                        .as(attr.getName());
307
                                if (extraColumnNames != null && !extraColumnNames.contains(attr.getName())) {
308
                                    extraColumnNames.add(attr.getName());
309
                                }
310
                            }
311

    
312
                        }
313
                    }
314
                }
315
            }
316
        }
317
        
318
        if (query != null && (query.hasAggregateFunctions() ||  query.hasGroupByColumns())) { 
319
            // Hay que tener en cuenta que puede haber un MAX(CAMPO) sin que se especifique un GROUP BY
320
            if (query.hasAggregateFunctions() ) {
321
                for (Map.Entry<String, String> entry : query.getAggregateFunctions().entrySet()) {
322
                    Expression exp;
323
                    FeatureAttributeDescriptor attr = allExtraColumns.get(entry.getKey());
324
                    if (attr == null) {
325
                        attr = this.setType.getAttributeDescriptorFromAll(entry.getKey());
326
                    }
327
                    if (attr == null) {
328
                            exp = ExpressionUtils.createExpression(entry.getKey());
329
                            Code code = exp.getCode();
330
                            if (!(code instanceof Code.Callable)) {
331
                                throw new RuntimeException("Not able to use aggregate function with this expression(1): " + entry.getKey());
332
                            }
333
                            Code.Callable callable = (Code.Callable) code;
334
                            if (!callable.name().equalsIgnoreCase(FUNCTION_LET)) {
335
                                throw new RuntimeException("Not able to use aggregate function with this expression(2): " + entry.getKey());
336
                            }
337
                            String name = ((Code.Identifier) callable.parameters().get(0)).name();
338
                            ExpressionBuilder.Value aggregate = callable.parameters().get(1).toValue();
339

    
340
                            ExpressionBuilder.Function aggregateExp = expbuilder.function(entry.getValue(), aggregate);
341

    
342
                            select.remove_column(name);
343
                            select.column().value(aggregateExp).as(name);
344
                    } else if( attr.getFeatureAttributeEmulator()!=null ) {
345
                        exp = ((FeatureAttributeEmulatorExpression) attr.getFeatureAttributeEmulator()).getExpression();
346
                        ExpressionBuilder.Function aggregateExp = expbuilder.function(entry.getValue(), exp.getCode().toValue());
347
                        if (!select.has_column(attr.getName())) {
348
                            select.column().value(aggregateExp).as(attr.getName());
349
                        }
350
                        if (extraColumnNames != null && !extraColumnNames.contains(attr.getName())) {
351
                            extraColumnNames.add(attr.getName());
352
                        }
353
                    }
354
                }
355
            }
356
            if (query.hasGroupByColumns()) { // if tiene agrupacion
357
                for (String attrName : query.getGroupByColumns()) {
358
                    if (allExtraColumns.get(attrName) != null) { //from setType and query
359
                        EditableFeatureAttributeDescriptor attr = allExtraColumns.get(attrName);
360
                        ExpressionBuilder.Variable col = expbuilder.column(attrName);
361
                        select.group_by(col);
362
                        Expression exp = ((FeatureAttributeEmulatorExpression) attr.getFeatureAttributeEmulator()).getExpression();
363
                        if (!select.has_column(attrName)) {
364
                            select.column().value(exp.getCode().toValue()).as(attrName);
365
                        }
366
                        if (extraColumnNames!=null && !extraColumnNames.contains(attr.getName())) {
367
                            extraColumnNames.add(attrName);
368
                        }
369
                    } else if (setType.get(attrName) != null && setType.getAttributeDescriptor(attrName).isComputed()) {
370
                        FeatureAttributeDescriptor attr = setType.getAttributeDescriptor(attrName);
371
                        ExpressionBuilder.Variable col = expbuilder.column(attrName);
372
                        select.group_by(col);
373
                        Expression exp = ((FeatureAttributeEmulatorExpression) attr.getFeatureAttributeEmulator()).getExpression();
374
                        if (!select.has_column(attrName)) {
375
                            select.column().value(exp.getCode().toValue()).as(attrName);
376
                        }
377
                        if (extraColumnNames!=null && !extraColumnNames.contains(attr.getName())) {
378
                            extraColumnNames.add(attrName);
379
                        }
380
                    } else if (setType.get(attrName) == null) {
381
                        try {
382
                            Code code = ExpressionUtils.compile(attrName);
383
                            select.group_by(code.toValue());
384
                        } catch (Exception ex) {
385
                            throw new RuntimeException("Not able to create column by expression in groupby query", ex);
386
                        }
387
                    } else {
388
                        ExpressionBuilder.Function atrcolumn = expbuilder.getattr(this.table.getTable(), attrName);
389
                        select.group_by(atrcolumn);
390
                    }
391
                }
392
            }
393
        } else {
394
            if (this.query != null) {
395
                FeatureExtraColumns extraColumns = this.query.getExtraColumn();
396
                if (extraColumns != null && !extraColumns.isEmpty()) {
397
                    for (EditableFeatureAttributeDescriptor attr : extraColumns.getColumns()) {
398
                        if (!attr.isComputed()) {
399
                            continue;
400
                        }
401
                        FeatureAttributeEmulator attrEmulator = attr.getFeatureAttributeEmulator();
402
                        if (attrEmulator instanceof FeatureAttributeEmulatorExpression) {
403
                            FeatureAttributeEmulatorExpression x = (FeatureAttributeEmulatorExpression) attrEmulator;
404
                            Expression exp = x.getExpression();
405
                            if (exp != null && !exp.isEmpty() && this.helper.supportExpression(setType, exp.getPhrase())) {
406
                                Code code = exp.getCode();
407
                                select.column()
408
                                        .value(code.toValue(expbuilder))
409
                                        .as(attr.getName());
410
                                if (extraColumnNames!=null && !extraColumnNames.contains(attr.getName())) {
411
                                    extraColumnNames.add(attr.getName());
412
                                }
413
                            }
414
                        }
415
                    }
416
                }
417
            }
418
        }
419

    
420
        select.from().table()
421
                .database(this.table.getDatabase())
422
                .schema(this.table.getSchema())
423
                .name(this.table.getTable());
424
        select.from().subquery(this.table.getSubquery());
425

    
426
        Evaluator filter = query == null ? null : query.getFilter();
427
        if (filter != null) {
428
            String sqlfilter = filter.getSQL();
429
            if (!StringUtils.isEmpty(sqlfilter)) {
430
                if (this.helper.supportFilter(this.storeType, filter)) {
431
                    select.where().set(expbuilder.toValue(sqlfilter));
432
                }
433
            }
434
        }
435
        if (!StringUtils.isEmpty(baseFilter)) {
436
            select.where().and(expbuilder.toValue(baseFilter));
437
        }
438

    
439
        FeatureQueryOrder order = query == null ? null : query.getOrder();
440
        if (order != null) {
441
            for (FeatureQueryOrderMember member : order.members()) {
442
                String attrName = member.getAttributeName();
443
                if (member.hasEvaluator()) {
444
                    // Order-by una expression en el query
445
                    String sqlorder = member.getEvaluator().getSQL();
446
                    select.order_by()
447
                            .value(expbuilder.toValue(sqlorder))
448
                            .ascending(member.getAscending());
449
                } else {
450
                    int nullsMode = OrderByBuilder.MODE_NULLS_LAST;
451
                    if (allExtraColumns.get(attrName) != null) {
452
                        // Order-by por una columna extra
453
                        Expression exp = ((FeatureAttributeEmulatorExpression) allExtraColumns.get(attrName).getFeatureAttributeEmulator()).getExpression();
454
                        if (!select.has_column(attrName)) {
455
                            select.column().value(exp.getCode().toValue()).as(attrName);
456
                        }
457
                        if (extraColumnNames!=null && !extraColumnNames.contains(attrName)) {
458
                            extraColumnNames.add(attrName);
459
                        }
460
                    } else if (setType.get(attrName) != null && setType.getAttributeDescriptor(attrName).isComputed()) {
461
                        // Order-by por un campo calculado del set/store
462
                        Expression exp = ((FeatureAttributeEmulatorExpression) setType.getAttributeDescriptor(attrName).getFeatureAttributeEmulator()).getExpression();
463
                        if (!select.has_column(attrName)) {
464
                            select.column().value(exp.getCode().toValue()).as(attrName);
465
                        }
466
                        if (extraColumnNames!=null && !extraColumnNames.contains(attrName)) {
467
                            extraColumnNames.add(attrName);
468
                        }
469
                    } else {
470
                        // Order-by por un campo del store
471
                        FeatureAttributeDescriptor attr = storeType.getAttributeDescriptor(attrName);
472
                        if( attr!=null && (!attr.allowNull() || attr.isPrimaryKey()) ) {
473
                            // Puede ser costoso ordenar los nulos al principio o final, asi que
474
                            // si el campo no admite nulos pasamos de indicarselo.
475
                            nullsMode = OrderByBuilder.MODE_NULLS_NOT_SPECIFIED;
476
                        }
477
                    }
478
                    ExpressionBuilder.Variable col = expbuilder.column(attrName);
479
                                        
480
                    // En el OrderBy no queremos que se sustituya el nombre del campo calculado
481
                    // por su expresion. Se encarga el formater y lo evitamos quitandole el ftype
482
                    // al value.
483
                    valuesToRemoveFeatureType.add(col);
484
                    select.order_by().value(col).ascending(member.getAscending()).nulls(nullsMode);
485
                }
486
            }
487
        }
488

    
489
        if (!StringUtils.isEmpty(baseOrder)) {
490
            select.order_by().custom(baseOrder);
491
        }
492

    
493
        if (select.has_group_by()) { // && isPaginated()) {
494
            // Cuando paginamos debemos ordenar por las columnas del groupby.
495
            // Ordenamos siempre para obtener el mismo resultado cuando paginamos
496
            // y no paginamos.
497
            for (ExpressionBuilder.Value group : select.getGroups()) {
498
                if (select.getOrderBy(group) == null) {
499
                    ExpressionBuilder.Value v = (ExpressionBuilder.Value) CloneableUtils.cloneQuietly(group);
500
                    select.order_by().value(v).ascending().nulls(OrderByBuilder.MODE_NULLS_LAST);
501
                    valuesToRemoveFeatureType.add(v);
502
                }
503
            }
504
        }
505
        
506
        if (primaryKeys.isEmpty()) {
507
            // Muy probablemente si no tiene pk sea una vista, asi que 
508
            // pasaremos de ordenar y esperemos que la vista este ya ordenada.
509
            select.disable_check_order_and_offset();
510
        } else {
511
            // Siempre ordenamos por la clave primaria
512
            Object x = query==null? null:query.getQueryParameter(QUERY_DONT_ADD_PRIMARY_KEY_IN_THE_ORDER);
513
            if( x==null || !DataTypeUtils.toBoolean(x) ) {
514
                for (String attrName : primaryKeys) {
515
                    if (select.getOrderBy(attrName) == null) {
516
                        select.order_by()
517
                                .column(attrName)
518
                                .ascending()
519
                                .nulls(OrderByBuilder.MODE_NULLS_NOT_SPECIFIED)
520
                                ;
521
                        // No tengo claro que pasa si se esta agrupando, y no se ha
522
                        // incluido en el agrupamiento al PK. En ese caso el select
523
                        // que se genera tendria una pinta tal que asi:
524
                        //   SELECT NULL as pk, ... ORDER BY pk ASC
525
                        // Probablemente en ese caso no tendriamos que meter la PK
526
                        // en el order-by ya que creo que no cambiaria el resultado.
527
                    }
528
                }
529
            }
530
        }
531

    
532
        if (limit > 0) {
533
            select.limit(limit);
534
        } else {
535
            select.limit(query == null ? null : query.getLimit());
536
        }
537
        if (offset > 0) {
538
            select.offset(offset);
539
        }
540
        sqlbuilder.setProperties(
541
                null,
542
                PROP_FEATURE_TYPE, this.storeType,
543
                PROP_TABLE, table,
544
                PROP_SYMBOLTABLE, this.query==null? null:this.query.getSymbolTable(),
545
                PROP_JDBCHELPER, this.helper,
546
                PROP_QUERY, this.query
547
        );
548
        for (ExpressionBuilder.Value value : valuesToRemoveFeatureType) {
549
            value.setProperty(PROP_FEATURE_TYPE, null);
550
        }
551
        this.helper.expandCalculedColumns(sqlbuilder);
552
        this.helper.processSpecialFunctions(sqlbuilder, storeType, extraColumnNames);
553
        String sql = sqlbuilder.toString();
554
        return sql;
555
    }
556
    
557
    private boolean isPaginated() {
558
        // No tengo claro que (offset==0 && limit>0) sea lo mas correcto,
559
        // Pero cuando se va a paginar y se pide la primera pagina offset es
560
        // 0 y limit>0, y si no ordenamos ya esa primera pagina los resultados
561
        // que se obtienen no son correctos, ya que la primera pagina se saca
562
        // sin ordenar y el resto ordenadas.
563
        // Probablemente deberiamos tener alguna otra forma de detectar que
564
        // estamos paginanado ya que asi no distinguimo si solo queremos 
565
        // obtener los primeros elementos sin importarnos su orden.
566
        return (offset > 0 || (offset == 0 && limit > 0));
567
    }
568

    
569
    public ResultSetEntry createResultSet() throws DataException {
570
        List<FeatureAttributeDescriptor> columns = new ArrayList<>();
571
        List<String> extraColumnNames = new ArrayList<>();
572

    
573
        JDBCSQLBuilderBase sqlbuilder = createSQLBuilder();
574
        String sql = this.getSQL(sqlbuilder, columns, extraColumnNames);
575

    
576
        ResultSetEntry resultSetEntry = this.helper.getResulSetControler().create(
577
                sql, fetchSize,
578
                columns.toArray(new FeatureAttributeDescriptor[columns.size()]),
579
                extraColumnNames.toArray(new String[extraColumnNames.size()])
580
        );
581
        return resultSetEntry;
582
    }
583

    
584
    private boolean shouldUseACustomSelect() {
585
        if( !table.hasSubquery() ) {
586
            return false;
587
        }
588
        if( this.query == null ) {
589
            return false;
590
        }
591
        if( this.query.isUseSubquery() ) {
592
            return false;
593
        }
594
        if( this.query.hasGroupByColumns() ) {
595
            return false;
596
        }
597
        if( this.query.hasAggregateFunctions() ) {
598
            return false;
599
        }        
600
        if( !this.query.hasFilter() && !this.query.hasOrder() ) {
601
            return true;
602
        }
603
//        si el filtro es incompatible con la BBDD
604
//            return false
605
//        si el orden es incompatible con la BBDD
606
//            return false
607
//        si filtro u orden usan la funcion foreing_value 
608
//            return false;
609
        return true;
610
    }
611
}