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

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

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

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

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

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

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

    
277
        JDBCSQLBuilderBase sqlbuilder = createSQLBuilder();
278
        String sql = this.getSQL(sqlbuilder, columns, extraColumnNames);
279
        
280
        ResultSetEntry resultSetEntry = this.helper.getResulSetControler().create(
281
                sql, fetchSize, 
282
                columns.toArray(new FeatureAttributeDescriptor[columns.size()]),
283
                extraColumnNames.toArray(new String[extraColumnNames.size()])
284
        );
285
        return resultSetEntry;
286
    }
287
 
288
}