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

History | View | Annotate | Download (13.4 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
                    select.group_by(expbuilder.column(attrName));
201
                }
202
            }            
203
        } else {
204
            for(String attrName : forcedColumns ) {
205
                select.column().name(attrName);
206
                columns.add(setType.getAttributeDescriptor(attrName));
207
            }
208
        }
209
                                  
210
        select.from().table()
211
                .database(this.table.getDatabase())
212
                .schema(this.table.getSchema())
213
                .name(this.table.getTable());
214
        select.from().subquery(this.table.getSubquery());
215
        
216
        Evaluator filter = query==null? null:query.getFilter();
217
        if( filter != null ) {
218
            String sqlfilter = filter.getSQL();
219
            if( ! StringUtils.isEmpty(sqlfilter) ) {
220
                if( this.helper.supportFilter(this.storeType, filter) ) {
221
                    select.where().set(expbuilder.toValue(sqlfilter));
222
                }
223
            }
224
        }
225
        if( ! StringUtils.isEmpty(baseFilter) ) {
226
            select.where().and(expbuilder.toValue(baseFilter));
227
        }
228
        
229
        FeatureQueryOrder order = query==null? null:query.getOrder();
230
        if( order != null ) {
231
            for( FeatureQueryOrderMember member : order.members() ) {
232
                if( member.hasEvaluator() ) {
233
                    String sqlorder = member.getEvaluator().getSQL();
234
                    if( ! StringUtils.isEmpty(sqlorder) ) {
235
                        select.order_by().custom(sqlorder);
236
                    }
237
                } else {
238
                    select.order_by()
239
                            .column(member.getAttributeName())
240
                            .ascending(member.getAscending());
241
                }
242
            }
243
        }
244
        if( !StringUtils.isEmpty(baseOrder) ) {
245
            select.order_by().custom(baseOrder);
246
        }
247
        if( !select.has_order_by() ) {        
248
          // Si no tenemos order by comprobamos si lo necesitamos y lo a?adimos.
249
          if( offset>0 || (offset==0 && limit>0) ) {
250
              // No tengo claro que (offset==0 && limit>0) sea lo mas correcto,
251
              // Pero cuando se va a paginar y se pide la primera pagina offset es
252
              // 0 y limit>0, y si no ordenamos ya esa primera pagina los resultados
253
              // que se obtienen no son correctos, ya que la primera pagina se saca
254
              // sin ordenar y el resto ordenadas.
255
              // Probablemente deberiamos tener alguna otra forma de detectar que
256
              // estamos paginanado ya que asi no distinguimo si solo queremos 
257
              // obtener los primeros elementos sin importarnos su orden.
258
              if (select.has_group_by()) {
259
                  ExpressionBuilder.Value group = select.getGroups().get(0);
260
//                  if(!(group instanceof ExpressionBuilder.Function)) {
261
//                      expbuilder.getattr(this.table.getTable(), group.XXX);
262
//                  }
263
                  select.order_by().column(group).ascending();
264
                  
265
               } else if( primaryKeys.isEmpty() ) {
266
                // Muy probablemente si no tiene pk sea una vista, asi que 
267
                // pasaremos de ordenar y esperemos que la vista este ya ordenada.
268
                select.disable_check_order_and_offset();
269
              }  else {
270
                    for(String attrName : primaryKeys ) {
271
                        // Se precisa indicar un orden para usar OFFSET.
272
    //                    select.order_by().column(sqlbuilder.as_identifier(attrName)).ascending();
273
                        select.order_by().column(attrName).ascending();
274
                    }
275
                  
276
              }
277
          }            
278
        }        
279
        if( limit > 0 ) {
280
            select.limit(limit);
281
        } else {
282
            select.limit(query==null? null:query.getLimit());
283
        }
284
        if( offset>0 ) {
285
            select.offset(offset);
286
        }        
287
        sqlbuilder.setProperties(
288
                null, 
289
                PROP_FEATURE_TYPE, this.storeType,
290
                PROP_TABLE, table
291
        );        
292
        this.helper.processSpecialFunctions(sqlbuilder, storeType, extraColumnNames);
293
        String sql = sqlbuilder.toString();
294
        return sql;
295
    }
296
    
297
    public ResultSetEntry createResultSet() throws DataException {
298
        List<FeatureAttributeDescriptor> columns = new ArrayList<>();
299
        List<String> extraColumnNames = new ArrayList<>();
300

    
301
        JDBCSQLBuilderBase sqlbuilder = createSQLBuilder();
302
        String sql = this.getSQL(sqlbuilder, columns, extraColumnNames);
303
        
304
        ResultSetEntry resultSetEntry = this.helper.getResulSetControler().create(
305
                sql, fetchSize, 
306
                columns.toArray(new FeatureAttributeDescriptor[columns.size()]),
307
                extraColumnNames.toArray(new String[extraColumnNames.size()])
308
        );
309
        return resultSetEntry;
310
    }
311
 
312
}