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

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

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

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

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

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

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

    
255
        JDBCSQLBuilderBase sqlbuilder = createSQLBuilder();
256
        String sql = this.getSQL(sqlbuilder, columns, extraColumnNames);
257
        
258
        ResultSetEntry resultSetEntry = this.helper.getResulSetControler().create(
259
                sql, fetchSize, 
260
                columns.toArray(new FeatureAttributeDescriptor[columns.size()]),
261
                extraColumnNames.toArray(new String[extraColumnNames.size()])
262
        );
263
        return resultSetEntry;
264
    }
265

    
266
}