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

History | View | Annotate | Download (13.5 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
                    if( ! StringUtils.isEmpty(sqlorder) ) {
236
                        select.order_by().custom(sqlorder);
237
                    }
238
                } else {
239
                    select.order_by()
240
                            .column(member.getAttributeName())
241
                            .ascending(member.getAscending());
242
                }
243
            }
244
        }
245
        if( !StringUtils.isEmpty(baseOrder) ) {
246
            select.order_by().custom(baseOrder);
247
        }
248
        if( !select.has_order_by() ) {        
249
          // Si no tenemos order by comprobamos si lo necesitamos y lo a?adimos.
250
          if( offset>0 || (offset==0 && limit>0) ) {
251
              // No tengo claro que (offset==0 && limit>0) sea lo mas correcto,
252
              // Pero cuando se va a paginar y se pide la primera pagina offset es
253
              // 0 y limit>0, y si no ordenamos ya esa primera pagina los resultados
254
              // que se obtienen no son correctos, ya que la primera pagina se saca
255
              // sin ordenar y el resto ordenadas.
256
              // Probablemente deberiamos tener alguna otra forma de detectar que
257
              // estamos paginanado ya que asi no distinguimo si solo queremos 
258
              // obtener los primeros elementos sin importarnos su orden.
259
              if (select.has_group_by()) {
260
                  ExpressionBuilder.Value group = select.getGroups().get(0);
261
//                  if(!(group instanceof ExpressionBuilder.Function)) {
262
//                      expbuilder.getattr(this.table.getTable(), group.XXX);
263
//                  }
264
                  select.order_by().column(group).ascending();
265
                  
266
               } else if( primaryKeys.isEmpty() ) {
267
                // Muy probablemente si no tiene pk sea una vista, asi que 
268
                // pasaremos de ordenar y esperemos que la vista este ya ordenada.
269
                select.disable_check_order_and_offset();
270
              }  else {
271
                    for(String attrName : primaryKeys ) {
272
                        // Se precisa indicar un orden para usar OFFSET.
273
    //                    select.order_by().column(sqlbuilder.as_identifier(attrName)).ascending();
274
                        select.order_by().column(attrName).ascending();
275
                    }
276
                  
277
              }
278
          }            
279
        }        
280
        if( limit > 0 ) {
281
            select.limit(limit);
282
        } else {
283
            select.limit(query==null? null:query.getLimit());
284
        }
285
        if( offset>0 ) {
286
            select.offset(offset);
287
        }        
288
        sqlbuilder.setProperties(
289
                null, 
290
                PROP_FEATURE_TYPE, this.storeType,
291
                PROP_TABLE, table
292
        );        
293
        this.helper.processSpecialFunctions(sqlbuilder, storeType, extraColumnNames);
294
        String sql = sqlbuilder.toString();
295
        return sql;
296
    }
297
    
298
    public ResultSetEntry createResultSet() throws DataException {
299
        List<FeatureAttributeDescriptor> columns = new ArrayList<>();
300
        List<String> extraColumnNames = new ArrayList<>();
301

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