Revision 46954

View differences:

trunk/org.gvsig.desktop/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.dal/org.gvsig.fmap.dal.impl/src/main/java/org/gvsig/expressionevaluator/impl/function/dataaccess/SelectAggregateFunction.java
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.expressionevaluator.impl.function.dataaccess;
25

  
26
import org.apache.commons.lang3.Range;
27
import org.apache.commons.lang3.StringUtils;
28
import org.gvsig.expressionevaluator.Code;
29
import org.gvsig.expressionevaluator.Codes;
30
import org.gvsig.expressionevaluator.ExpressionBuilder;
31
import static org.gvsig.expressionevaluator.ExpressionBuilder.FUNCTION_COUNT;
32
import org.gvsig.expressionevaluator.ExpressionEvaluator;
33
import org.gvsig.expressionevaluator.ExpressionRuntimeException;
34
import org.gvsig.expressionevaluator.Interpreter;
35
import org.gvsig.expressionevaluator.impl.DALFunctions;
36
import org.gvsig.fmap.dal.DALLocator;
37
import org.gvsig.fmap.dal.DataManager;
38
import static org.gvsig.fmap.dal.DataManager.FUNCTION_SELECT_COUNT;
39
import org.gvsig.fmap.dal.SQLBuilder;
40
import static org.gvsig.fmap.dal.SQLBuilder.PROP_FEATURE_TYPE;
41
import static org.gvsig.fmap.dal.SQLBuilder.PROP_SQLBUILDER;
42
import static org.gvsig.fmap.dal.SQLBuilder.PROP_TABLE;
43
import org.gvsig.fmap.dal.feature.Feature;
44
import org.gvsig.fmap.dal.feature.FeatureQuery;
45
import org.gvsig.fmap.dal.feature.FeatureSet;
46
import org.gvsig.fmap.dal.feature.FeatureStore;
47
import org.gvsig.fmap.dal.feature.FeatureType;
48
import org.gvsig.fmap.dal.impl.expressionevaluator.DefaultFeatureExpressionEvaluator;
49
import org.gvsig.tools.dispose.DisposeUtils;
50

  
51
/**
52
 *
53
 * @author jjdelcerro
54
 */
55
@SuppressWarnings("UseSpecificCatch")
56
public class SelectAggregateFunction extends AbstractSelectFunction {
57
    
58
    public static String FUNCTION_SELECT_AGGREGATE = "SELECT_AGGREGATE";
59

  
60
    public SelectAggregateFunction() {
61
        super(DALFunctions.GROUP_DATA_ACCESS,
62
                FUNCTION_SELECT_AGGREGATE,
63
                Range.is(4),
64
                "Returns the aggregate function of features of the table by applying the filter indicated.\n"
65
                + "The syntax is:\n\n"
66
                + "SELECT aggregate_function(column1) FROM table WHERE boolean_expression;\n\n"
67
                + "Indicate a filter expression with WHERE is optional.\n"
68
                + "The SELECT statement must always end with a semicolon.",
69
                "SELECT sum({{column1}}) FROM table WHERE filter ;",
70
                new String[]{
71
                    "table - Name of the table",
72
                    "filter - boolean expression with the filter to apply",
73
                    "aggregate_function - aggregate function to use. Valid functions are SUM, COUNT, MAX, MIN, AVG",
74
                    "column1 - name of column to use in aggregate function",
75
                },
76
                "Object",
77
                true
78
        );
79
    }
80

  
81
    @Override
82
    public boolean isHidden() {
83
        return false;
84
    }
85

  
86
    @Override
87
    public boolean allowConstantFolding() {
88
        return false;
89
    }
90

  
91
    @Override
92
    public boolean useArgumentsInsteadObjects() {
93
        return true;
94
    }
95

  
96
    @Override
97
    public Object call(Interpreter interpreter, Object[] args) throws Exception {
98
        throw new UnsupportedOperationException();
99
    }
100

  
101
    private static final int TABLE = 0;
102
    private static final int WHERE = 1;
103
    private static final int AGGREGATE_FUNCTION = 2;
104
    private static final int AGGREGATE_COLUMN = 3;
105

  
106
    @Override
107
    public Object call(Interpreter interpreter, Codes args) throws Exception {
108

  
109
        String storeName = this.getIdentifier(args, TABLE);
110
        Code where = this.getWhereCode(args, WHERE);
111
        String aggregateFunction = this.getIdentifier(args, AGGREGATE_FUNCTION);
112
        String aggregateColumn = this.getIdentifier(args, AGGREGATE_COLUMN);
113

  
114
        FeatureStore featureStore = null;
115
        FeatureSet set = null;
116
        try {
117
            featureStore = this.getFeatureStore(storeName);
118
            if (featureStore == null) {
119
                throw new ExpressionRuntimeException("Cant locate the feature store '" + storeName + "' in function '" + this.name() + "'.");
120
            }
121
            FeatureQuery query = featureStore.createFeatureQuery();
122
            if (where != null) {
123
                Code where2 = removeOuterTablesReferences(interpreter, where);
124
                ExpressionEvaluator filter = new DefaultFeatureExpressionEvaluator(where2.toString());
125
                filter.toSymbolTable().addSymbolTable(interpreter.getSymbolTable());
126
                query.addFilter(filter);
127
            }
128
            query.retrievesAllAttributes();
129
            query.addAggregate(aggregateFunction, aggregateColumn);
130
            Feature f = featureStore.findFirst(query);
131
            if (f == null){
132
                return null;
133
            }
134
            return f.get(aggregateColumn);
135
        } catch (ExpressionRuntimeException ex) {
136
            throw ex;
137
        } catch (Exception ex) {
138
            throw new ExpressionRuntimeException("Problems calling '" + this.name() + "' function", ex);
139
        } finally {
140
            DisposeUtils.disposeQuietly(set);
141
            DisposeUtils.disposeQuietly(featureStore);
142
        }
143
    }
144

  
145
    @Override
146
    public ExpressionBuilder.Value toValue(ExpressionBuilder builder, Codes args) {
147
        try {
148
            SQLBuilder sqlBuilder = (SQLBuilder) builder.getProperty(PROP_SQLBUILDER);
149
            if(sqlBuilder == null){
150
                return super.toValue(builder, args);
151
            }
152
            FeatureType featureType = null;
153
            SQLBuilder.SelectBuilder select = sqlBuilder.createSelectBuilder();
154
            String builderTableName = (String) builder.getProperty(SQLBuilder.PROP_TABLENAME);
155

  
156
            String storeName = this.getIdentifier(args, TABLE);
157
            Code where = this.getWhereCode(args, WHERE);
158

  
159
            String aggregateFunction = this.getIdentifier(args, AGGREGATE_FUNCTION);
160
            String aggregateColumn = this.getIdentifier(args, AGGREGATE_COLUMN);
161

  
162
            if (storeName != null) {
163
                select.from().table().name(storeName);
164
            }
165

  
166
            SQLBuilder.TableNameBuilder table = select.from().table();
167
            String tableName = table.getName();
168
            
169
            select.column(aggregateColumn).value(builder.function(aggregateFunction, builder.column(aggregateColumn)));
170

  
171
            if (where != null) {
172
                ExpressionBuilder.Value value = where.toValue(builder);
173
                select.where().value(value);
174
                sqlBuilder.setProperties(value, null, SQLBuilder.PROP_ADD_TABLE_NAME_TO_COLUMNS, true);
175
            }
176

  
177
            if (featureType == null) {
178
                if (StringUtils.equalsIgnoreCase(builderTableName, tableName)) {
179
                    featureType = (FeatureType) builder.getProperty(SQLBuilder.PROP_FEATURE_TYPE);
180
                } else {
181
                    DataManager dataManager = DALLocator.getDataManager();
182
                    featureType = dataManager.getStoresRepository().getFeatureType(tableName);
183
                }
184
            }
185

  
186
            sqlBuilder.setProperties(
187
                    select,
188
                    null,
189
                    PROP_FEATURE_TYPE, featureType,
190
                    PROP_TABLE, table
191
            );
192

  
193
            return builder.group(select);
194
        } catch (Exception ex) {
195
            return super.toValue(builder, args);
196
        }
197
    }
198
    
199
}
trunk/org.gvsig.desktop/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.dal/org.gvsig.fmap.dal.impl/src/main/java/org/gvsig/expressionevaluator/impl/function/dataaccess/SelectCountFunction.java
99 99
    @Override
100 100
    public Object call(Interpreter interpreter, Codes args) throws Exception {
101 101

  
102
        String storeName = this.getTableName(args, TABLE);
102
        String storeName = this.getIdentifier(args, TABLE);
103 103
        Code where = this.getWhereCode(args, WHERE);
104 104

  
105 105
        FeatureStore featureStore = null;
......
142 142
            SQLBuilder.SelectBuilder select = sqlBuilder.createSelectBuilder();
143 143
            String builderTableName = (String) builder.getProperty(SQLBuilder.PROP_TABLENAME);
144 144

  
145
            String storeName = this.getTableName(args, TABLE);
145
            String storeName = this.getIdentifier(args, TABLE);
146 146
            Code where = this.getWhereCode(args, WHERE);
147 147

  
148 148
            if (storeName != null) {
trunk/org.gvsig.desktop/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.dal/org.gvsig.fmap.dal.impl/src/main/java/org/gvsig/expressionevaluator/impl/function/dataaccess/AbstractSelectFunction.java
42 42
        super(group, name, argc, description, template, descriptionArgs, returnType);
43 43
    }
44 44

  
45
    protected String getTableName(Codes args, int argn) {
45
    protected String getIdentifier(Codes args, int argn) {
46 46
        Code storeName_code = (Code) args.get(argn);
47 47
        if (storeName_code instanceof Code.Identifier) {
48 48
            return ((Code.Identifier) storeName_code).name();
trunk/org.gvsig.desktop/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.dal/org.gvsig.fmap.dal.impl/src/main/java/org/gvsig/expressionevaluator/impl/function/dataaccess/SelectFromSelectionFunction.java
101 101
    public Object call(Interpreter interpreter, Codes args) throws Exception {
102 102

  
103 103
        Code columns = getTupleOrNull(args, COLUMNS);
104
        String storeName = this.getTableName(args, TABLE);
104
        String storeName = this.getIdentifier(args, TABLE);
105 105
        Code where = this.getWhereCode(args, WHERE);
106 106
        Number limit = (Number) getObject(interpreter, args, LIMIT);
107 107
        Object selection_if_not_empty = getObject(interpreter, args, SELECCTION_IF_NOT_EMPTY);
trunk/org.gvsig.desktop/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.dal/org.gvsig.fmap.dal.impl/src/main/java/org/gvsig/expressionevaluator/impl/function/dataaccess/SelectFunction.java
115 115
    @Override
116 116
    public Object call(Interpreter interpreter, Codes args) throws Exception {
117 117

  
118
        String storeName = this.getTableName(args, TABLE);
118
        String storeName = this.getIdentifier(args, TABLE);
119 119
        Code columns = getTupleOrNull(args, COLUMNS);
120 120
        Code where = this.getWhereCode(args, WHERE);
121 121
        Number limit = (Number) getObject(interpreter, args, LIMIT);
......
182 182
            SQLBuilder.SelectBuilder select = sqlBuilder.createSelectBuilder();
183 183
            String builderTableName = (String) builder.getProperty(SQLBuilder.PROP_TABLENAME);
184 184

  
185
            String storeName = this.getTableName(args, TABLE);
185
            String storeName = this.getIdentifier(args, TABLE);
186 186
            Callable columns = getTupleOrNull(args, COLUMNS);
187 187
            Code where = this.getWhereCode(args, WHERE);
188 188
            Callable order = getTupleOrNull(args, ORDER);
trunk/org.gvsig.desktop/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.dal/org.gvsig.fmap.dal.impl/src/main/java/org/gvsig/expressionevaluator/impl/function/dataaccess/SelectCountFromSelectionFunction.java
91 91
    @Override
92 92
    public Object call(Interpreter interpreter, Codes args) throws Exception {
93 93

  
94
        String storeName = this.getTableName(args, TABLE);
94
        String storeName = this.getIdentifier(args, TABLE);
95 95
        Code where = this.getWhereCode(args, WHERE);
96 96
        Object selection_if_not_empty = getObject(interpreter, args, SELECCTION_IF_NOT_EMPTY);
97 97
        
trunk/org.gvsig.desktop/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.dal/org.gvsig.fmap.dal.impl/src/main/java/org/gvsig/expressionevaluator/impl/grammars/DataAccessGrammarFactory.java
43 43
import static org.gvsig.fmap.dal.DataManager.FUNCTION_SELECT;
44 44
import static org.gvsig.fmap.dal.DataManager.FUNCTION_SELECT_COUNT;
45 45
import org.gvsig.expressionevaluator.Code.Callable;
46
import static org.gvsig.expressionevaluator.impl.function.dataaccess.SelectAggregateFunction.FUNCTION_SELECT_AGGREGATE;
46 47
import org.gvsig.fmap.dal.DataManager;
47 48
import static org.gvsig.fmap.dal.DataManager.FUNCTION_CREATE_TABLE;
48 49
import static org.gvsig.fmap.dal.DataManager.FUNCTION_CREATE_TABLE_STRUCTURE;
......
221 222
        }
222 223

  
223 224
    }
225
    private static class SelectAggregateArgsBuilder implements ArgsBuilder {
224 226

  
227
        public SelectAggregateArgsBuilder() {
228
        }
229

  
230
        @Override
231
        public String toString() {
232
            return "select_aggregate_args()";
233
        }
234

  
235
        @Override
236
        public Codes build(StatementContext context) {
237
            context.trace(this.toString() + ".build");
238
            CodeBuilder codeBuilder = context.getCodeBuilder();
239
            BaseCodes args = (BaseCodes) codeBuilder.args();
240

  
241
            Code table = context.getCode("table");
242
            Code where = context.getCode("where");
243
            Code aggregateFunction = context.getCode("AGGREGATE_FUNCTION");
244
            Code aggregateColumn = context.getCode("AGGREGATE_COLUMN");
245

  
246
            args.add(table);
247

  
248
            if (where == null) {
249
                args.add(codeBuilder.constant(null));
250
            } else {
251
                args.add(where);
252
            }
253
            args.add(aggregateFunction);
254
            args.add(aggregateColumn);
255
            return args;
256
        }
257

  
258
    }
259

  
225 260
    public DataAccessGrammarFactory() {
226 261
        super(DALFunctions.GRAMMAR_NAME, true);
227 262
    }
......
239 274
            theGrammar.addStatement(createForeingValueStatement(theGrammar));
240 275
            theGrammar.addStatement(createInsertIntoTableSelectStatement(theGrammar));
241 276
            theGrammar.addStatement(createSelectCountStatement(theGrammar));
277
            theGrammar.addStatement(createSelectAggregateStatement(theGrammar));
242 278
            theGrammar.addStatement(createSelectStatement(theGrammar));
243 279
//            theGrammar.addStatement(createUpdateStatement(theGrammar));
244 280
            theGrammar.addStatement(createSelectCountFromSelectionStatement(theGrammar));
......
503 539
        return stmt;
504 540
    }
505 541

  
542
    private Statement createSelectAggregateStatement(Grammar theGrammar) {
543
        Statement stmt;
544
//
545
//      SELECT COUNT(*) FROM table_name WHERE expression
546
//        
547
        theGrammar.addReservedWord("SELECT");
548
        theGrammar.addReservedWord("FROM");
549
        theGrammar.addReservedWord("WHERE");
550

  
551
        stmt = theGrammar.createStatement("SELECT_COUNT");
552
        stmt.addRule(stmt.require_any_token("SELECT"));
553
        stmt.addRule(stmt.require_any_token("COUNT","SUM", "MIN","MAX", "AVG").capture_as("AGGREGATE_FUNCTION"));
554
        stmt.addRule(stmt.require_any_token("("));
555
        stmt.addRule(stmt.require_identifier().capture_as("AGGREGATE_COLUMN"));
556
        stmt.addRule(stmt.require_any_token(")"));
557
        stmt.addRule(stmt.require_any_token("FROM"));
558
        stmt.addRule(stmt.require_expression().capture_as("TABLE"));
559
        stmt.addRule(stmt.optional_any_token("WHERE")
560
                .addRuleOnTrue(stmt.require_expression().capture_as("WHERE"))
561
        );
562
        stmt.addRule(stmt.optional_any_token(";"));
563
        stmt.code(
564
                FUNCTION_SELECT_AGGREGATE,
565
                new SelectAggregateArgsBuilder()
566
        );
567
        return stmt;
568
    }
569

  
506 570
    private Statement createSelectCountFromSelectionStatement(Grammar theGrammar) {
507 571
        Statement stmt;
508 572
//
trunk/org.gvsig.desktop/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.dal/org.gvsig.fmap.dal.impl/src/main/java/org/gvsig/expressionevaluator/impl/symboltable/DALSymbolTable.java
37 37
import org.gvsig.expressionevaluator.impl.function.dataaccess.InsertIntoTableFunction;
38 38
import org.gvsig.expressionevaluator.impl.function.dataaccess.IsSelectedCurrentRowFunction;
39 39
import org.gvsig.expressionevaluator.impl.function.dataaccess.RowTagFunction;
40
import org.gvsig.expressionevaluator.impl.function.dataaccess.SelectAggregateFunction;
40 41
import org.gvsig.expressionevaluator.impl.function.dataaccess.SelectCountFromSelectionFunction;
41 42
import org.gvsig.expressionevaluator.impl.function.dataaccess.SelectCountFunction;
42 43
import org.gvsig.expressionevaluator.impl.function.dataaccess.SelectFromSelectionFunction;
......
62 63
        this.addFunction(new ExistsTableFunction());
63 64
        this.addFunction(new SelectFunction());
64 65
        this.addFunction(new SelectCountFunction());
66
        this.addFunction(new SelectAggregateFunction());
65 67
        this.addFunction(new CurrentRowFunction());
66 68
        this.addFunction(new CurrentStoreFunction());
67 69
        this.addFunction(new ForeingValueFunction());
trunk/org.gvsig.desktop/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.dal/org.gvsig.fmap.dal.impl/src/test/java/org/gvsig/expressionevaluator/TestGrammarCompiler.java
111 111
        checkEquals("testSelect", "SELECT_COUNT(\"countries\", NULL)", code.toString());
112 112
    }
113 113
    
114
    public void testSelectAggregate() {
115
        StringBuilder source = new StringBuilder();
116
        source.append("SELECT sum(\"TOTAL_MUERTOS\") FROM \"ARENA2_ACCIDENTES\";");
117

  
118
        Compiler compiler = createCompiler();
119

  
120
        Code code = compiler.compileExpression(source.toString());
121
        link(code);
122
        checkEquals("testSelect", "SELECT_AGGREGATE(\"ARENA2_ACCIDENTES\", NULL, 'sum', 'TOTAL_MUERTOS')", code.toString());
123
    }
124
    
114 125
    public void testSelectCountToValue() {
115 126
        StringBuilder source = new StringBuilder();
116 127
        source.append("SELECT COUNT(*) FROM countries;");

Also available in: Unified diff