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

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

    
54
public class ResultSetForSetProviderOperation extends AbstractConnectionOperation {
55
    private final TableReference table;
56
    private final String baseFilter;
57
    private final String baseOrder;
58
    private final FeatureType storeType;
59
    private final FeatureType setType;
60
    private final FeatureQuery query;
61
    private final long limit;
62
    private final long offset;
63
    private final int fetchSize;
64

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

    
89
    @Override
90
    protected Object perform_operation() throws Exception {
91
        ResultSetEntry rs = createResultSet();
92
        return rs;
93
    }
94
    
95
    @Override
96
    public Object perform(Connection conn) throws DataException {
97
        throw new UnsupportedOperationException("Not supported yet."); 
98
    }
99

    
100
    public String getSQL() {
101
        List<FeatureAttributeDescriptor> columns = new ArrayList<>();
102
        JDBCSQLBuilderBase sqlbuilder = createSQLBuilder();
103
        String sql = this.getSQL(sqlbuilder, columns, null);
104
        return sql;
105
    }
106
    
107
    public String getSQL(
108
            JDBCSQLBuilderBase sqlbuilder, 
109
            List<FeatureAttributeDescriptor> columns, 
110
            List<String> extraColumnNames
111
      ) {
112
        double tolerance = -1 ; //query.getScale();
113
        ExpressionBuilder expbuilder = sqlbuilder.expression();
114
        SelectBuilder select = sqlbuilder.select();
115
        
116
        List<String> primaryKeys = new ArrayList<>();
117
        for(FeatureAttributeDescriptor attr : storeType.getPrimaryKey() ) {
118
            primaryKeys.add(attr.getName());
119
        }
120
        List<String> forcedColumns = new ArrayList<>(primaryKeys);
121

    
122
        String[] constantsAttributeNames = null;
123
        if(query !=null && query.hasConstantsAttributeNames() ) {
124
            constantsAttributeNames = query.getConstantsAttributeNames();
125
        }
126
        for(FeatureAttributeDescriptor attr : setType ) {
127
            if( attr.isComputed() ) {
128
                continue;
129
            }
130
            if( ArrayUtils.contains(constantsAttributeNames, attr.getName()) ) {
131
                continue;
132
            }
133
            if( attr.isPrimaryKey() ) {
134
                forcedColumns.remove(attr.getName());
135
            }
136
            if( query !=null && query.hasGroupByColumns()) {
137
              String aggregate = query.getAggregate(this.table.getTable(), attr.getName());
138
              if( this.query.isAGroupByColumn(attr.getName()) ) {
139
                  select.column().name(attr.getName());
140
              } else if( aggregate == null ) {
141
                select.column().value(expbuilder.constant(null)).as(attr.getName());
142
              } else {
143
                select.column()
144
                        .value(ExpressionUtils.compile(aggregate).toValue(expbuilder))
145
                        .as(attr.getName());
146
              }
147
                } else {
148
              if( attr.getType() == DataTypes.GEOMETRY ) {
149
                  select.column().name(attr.getName()).as_geometry();
150
  //                if( tolerance<=0 || !sqlbuilder.getConfig().has_functionality(Config.ST_Simplify)) {
151
  //                    select.column().name(attr.getName()).as_geometry();
152
  //                } else {
153
  //                    select.column().value(
154
  //                        sqlbuilder.ST_Simplify( 
155
  //                            sqlbuilder.column(attr.getName()),
156
  //                            sqlbuilder.constant(tolerance)
157
  //                        )
158
  //                    ).as_geometry();
159
  //                }
160
              } else {
161
                  select.column().name(attr.getName());
162
            }
163
            }
164
            columns.add(attr);
165
        }
166
                                           
167
       if( query !=null && query.hasGroupByColumns() ) {
168
            for (Map.Entry<String, String> entry : query.getAggregateFunctions().entrySet()) {
169
                 EditableFeatureAttributeDescriptor attr = query.getExtraColumn().get(entry.getKey());
170
               if( attr!=null ) {
171
                    Expression exp = ((FeatureAttributeEmulatorExpression) attr.getFeatureAttributeEmulator()).getExpression();
172
                    ExpressionBuilder.Function aggregateExp = expbuilder.function(entry.getValue(),exp.getCode().toValue());
173
                    if (!select.has_column(attr.getName())) {
174
                        select.column().value(aggregateExp).as(attr.getName());
175
                    }
176
                    if (!extraColumnNames.contains(attr.getName())) {
177
                        extraColumnNames.add(attr.getName());
178
                    }
179
               }
180
            }
181
            for(String attrName : query.getGroupByColumns() ) {
182
                if (this.setType.getExtraColumns().get(attrName) != null) {
183
                    EditableFeatureAttributeDescriptor attr = this.setType.getExtraColumns().get(attrName);
184
                    select.group_by(expbuilder.column(attrName));
185
                    Expression exp = ((FeatureAttributeEmulatorExpression) attr.getFeatureAttributeEmulator()).getExpression();
186
                    if (!select.has_column(attrName)) {
187
                        select.column().value(exp.getCode().toValue()).as(attrName);
188
                    }
189
                    if (!extraColumnNames.contains(attr.getName())) {
190
                        extraColumnNames.add(attrName);
191
                    }
192
                } else if (setType.get(attrName) == null) {
193
                    try {
194
                        Code code = ExpressionUtils.compile(attrName);
195
                        select.group_by(code.toValue());
196
                    } catch (Exception ex) {
197
                        throw new RuntimeException("Not able to create column by expression in groupby query", ex);
198
                    }
199
                } else {
200
                     ExpressionBuilder.Function atrcolumn = expbuilder.getattr(this.table.getTable(), attrName);
201
                    select.group_by(atrcolumn);
202
                }
203
            }                               
204
        } else {
205
            for(String attrName : forcedColumns ) {
206
                select.column().name(attrName);
207
                columns.add(setType.getAttributeDescriptor(attrName));
208
            }
209
        }
210
                            
211
        select.from().table()
212
                .database(this.table.getDatabase())
213
                .schema(this.table.getSchema())
214
                .name(this.table.getTable());
215
        select.from().subquery(this.table.getSubquery());
216
        
217
        Evaluator filter = query==null? null:query.getFilter();
218
        if( filter != null ) {
219
            String sqlfilter = filter.getSQL();
220
            if( ! StringUtils.isEmpty(sqlfilter) ) {
221
                if( this.helper.supportFilter(this.storeType, filter) ) {
222
                    select.where().set(expbuilder.toValue(sqlfilter));
223
                }
224
            }
225
        }
226
        if( ! StringUtils.isEmpty(baseFilter) ) {
227
            select.where().and(expbuilder.toValue(baseFilter));
228
        }
229
        
230
        FeatureQueryOrder order = query == null ? null : query.getOrder();
231
        if (order != null) {
232
            for (FeatureQueryOrderMember member : order.members()) {
233
                if (member.hasEvaluator()) {
234
                    String sqlorder = member.getEvaluator().getSQL();
235
                    select.order_by()
236
                            .value(expbuilder.toValue(sqlorder))
237
                            .ascending(member.getAscending());
238
                } else {
239
                    if (query.getExtraColumn().get(member.getAttributeName()) != null) {
240
                        Expression exp = ((FeatureAttributeEmulatorExpression) query.getExtraColumn().get(member.getAttributeName()).getFeatureAttributeEmulator()).getExpression();
241
                        select.column().value(exp.getCode().toValue()).as(member.getAttributeName());
242
                    }
243
                    select.order_by()
244
                            .column(member.getAttributeName())
245
                            .ascending(member.getAscending());
246
                }
247
            }
248
        }
249
    
250
        if( !StringUtils.isEmpty(baseOrder) ) {
251
            select.order_by().custom(baseOrder);
252
        }
253
        if( !select.has_order_by() ) {        
254
          // Si no tenemos order by comprobamos si lo necesitamos y lo a?adimos.
255
          if( offset>0 || (offset==0 && limit>0) ) {
256
              // No tengo claro que (offset==0 && limit>0) sea lo mas correcto,
257
              // Pero cuando se va a paginar y se pide la primera pagina offset es
258
              // 0 y limit>0, y si no ordenamos ya esa primera pagina los resultados
259
              // que se obtienen no son correctos, ya que la primera pagina se saca
260
              // sin ordenar y el resto ordenadas.
261
              // Probablemente deberiamos tener alguna otra forma de detectar que
262
              // estamos paginanado ya que asi no distinguimo si solo queremos 
263
              // obtener los primeros elementos sin importarnos su orden.
264
              if (select.has_group_by()) {
265
                  ExpressionBuilder.Value group = select.getGroups().get(0);
266
//                  if(!(group instanceof ExpressionBuilder.Function)) {
267
//                      expbuilder.getattr(this.table.getTable(), group.XXX);
268
//                  }
269
                  select.order_by().value(group).ascending();
270
                  
271
               } else if( primaryKeys.isEmpty() ) {
272
                // Muy probablemente si no tiene pk sea una vista, asi que 
273
                // pasaremos de ordenar y esperemos que la vista este ya ordenada.
274
                select.disable_check_order_and_offset();
275
              }  else {
276
                    for(String attrName : primaryKeys ) {
277
                        // Se precisa indicar un orden para usar OFFSET.
278
    //                    select.order_by().column(sqlbuilder.as_identifier(attrName)).ascending();
279
                        select.order_by().column(attrName).ascending();
280
                    }
281
                  
282
              }
283
          }            
284
        }        
285
        if( limit > 0 ) {
286
            select.limit(limit);
287
        } else {
288
            select.limit(query==null? null:query.getLimit());
289
        }
290
        if( offset>0 ) {
291
            select.offset(offset);
292
        }        
293
        sqlbuilder.setProperties(
294
                null, 
295
                PROP_FEATURE_TYPE, this.storeType,
296
                PROP_TABLE, table
297
        );        
298
        this.helper.processSpecialFunctions(sqlbuilder, storeType, extraColumnNames);
299
        String sql = sqlbuilder.toString();
300
        return sql;
301
    }
302
    
303
    public ResultSetEntry createResultSet() throws DataException {
304
        List<FeatureAttributeDescriptor> columns = new ArrayList<>();
305
        List<String> extraColumnNames = new ArrayList<>();
306

    
307
        JDBCSQLBuilderBase sqlbuilder = createSQLBuilder();
308
        String sql = this.getSQL(sqlbuilder, columns, extraColumnNames);
309
        
310
        ResultSetEntry resultSetEntry = this.helper.getResulSetControler().create(
311
                sql, fetchSize, 
312
                columns.toArray(new FeatureAttributeDescriptor[columns.size()]),
313
                extraColumnNames.toArray(new String[extraColumnNames.size()])
314
        );
315
        return resultSetEntry;
316
    }
317
 
318
}