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

History | View | Annotate | Download (16.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.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
        if(query != null){
124
            for (EditableFeatureAttributeDescriptor column : this.query.getExtraColumn().getColumns()) {
125
                allExtraColumns.put(column.getName(), column);
126
            }
127
        }
128

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

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

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

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

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

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

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

    
310
                } else if (primaryKeys.isEmpty()) {
311
                    // Muy probablemente si no tiene pk sea una vista, asi que 
312
                    // pasaremos de ordenar y esperemos que la vista este ya ordenada.
313
                    select.disable_check_order_and_offset();
314
                }
315
            }
316
//        }
317
        for (String attrName : primaryKeys) {
318
            if(select.getOrderBy(attrName)==null){
319
                select.order_by().column(attrName).ascending();
320
            }
321
        }
322
        if (limit > 0) {
323
            select.limit(limit);
324
        } else {
325
            select.limit(query == null ? null : query.getLimit());
326
        }
327
        if (offset > 0) {
328
            select.offset(offset);
329
        }
330
        sqlbuilder.setProperties(
331
                null,
332
                PROP_FEATURE_TYPE, this.storeType,
333
                PROP_TABLE, table
334
        );
335
        this.helper.processSpecialFunctions(sqlbuilder, storeType, extraColumnNames);
336
        String sql = sqlbuilder.toString();
337
        return sql;
338
    }
339

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

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

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

    
355
}