Revision 44750 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

View differences:

SelectFunction.java
23 23
 */
24 24
package org.gvsig.expressionevaluator.impl.function.dataaccess;
25 25

  
26
import java.util.ArrayList;
26 27
import java.util.List;
27 28
import java.util.Objects;
28 29
import org.apache.commons.lang3.Range;
30
import org.apache.commons.lang3.StringUtils;
31
import org.apache.commons.lang3.tuple.ImmutablePair;
32
import org.apache.commons.lang3.tuple.Pair;
33
import org.gvsig.expressionevaluator.Code;
34
import org.gvsig.expressionevaluator.Code.Caller;
35
import org.gvsig.expressionevaluator.CodeBuilder;
29 36
import org.gvsig.expressionevaluator.Codes;
30
import org.gvsig.expressionevaluator.Expression;
37
import static org.gvsig.expressionevaluator.ExpressionBuilder.FUNCTION_GETATTR;
38
import static org.gvsig.expressionevaluator.ExpressionBuilder.FUNCTION_TUPLE;
31 39
import org.gvsig.expressionevaluator.ExpressionRuntimeException;
32 40
import org.gvsig.expressionevaluator.ExpressionUtils;
33 41
import org.gvsig.expressionevaluator.Interpreter;
42
import org.gvsig.expressionevaluator.Optimizer;
43
import org.gvsig.expressionevaluator.SymbolTable;
34 44
import org.gvsig.expressionevaluator.impl.DALFunctions;
35 45
import org.gvsig.expressionevaluator.spi.AbstractFunction;
36 46
import org.gvsig.fmap.dal.DALLocator;
37 47
import org.gvsig.fmap.dal.DataManager;
38 48
import static org.gvsig.fmap.dal.DataManager.FUNCTION_SELECT;
39 49
import org.gvsig.fmap.dal.DataStore;
50
import org.gvsig.fmap.dal.expressionevaluator.ExpressionEvaluator;
51
import static org.gvsig.fmap.dal.expressionevaluator.FeatureSymbolTable.SYMBOL_CURRENT_TABLE;
52
import org.gvsig.fmap.dal.expressionevaluator.TableAttributeHandler;
40 53
import org.gvsig.fmap.dal.feature.Feature;
41 54
import org.gvsig.fmap.dal.feature.FeatureQuery;
42 55
import org.gvsig.fmap.dal.feature.FeatureQueryOrder;
43 56
import org.gvsig.fmap.dal.feature.FeatureStore;
57
import org.gvsig.fmap.dal.impl.expressionevaluator.DefaultExpressionEvaluator;
58
import org.gvsig.tools.exception.BaseException;
44 59

  
45 60
/**
46 61
 *
47 62
 * @author jjdelcerro
48 63
 */
49
public class SelectFunction extends AbstractFunction {
64
public class SelectFunction 
65
        extends AbstractFunction 
66
        implements Optimizer.FunctionOptimizer
67
  {
50 68

  
51 69
  public SelectFunction() {
52 70
    super(DALFunctions.GROUP_DATA_ACCESS,
53 71
            FUNCTION_SELECT,
54
            Range.between(1,5),
72
            Range.is(6),
55 73
            "Returns a list of features of the table by applying the filter, order and limit indicated.\n"+
56 74
                    "The syntax is:\n\n"+
57 75
                    "SELECT * FROM table WHERE boolean_expression ORDER BY order_column LIMIT limit;\n\n"+
......
65 83
              "limit - Maximum number of features to return"
66 84
            },
67 85
            "List",
68
            false
86
            true
69 87
    );
70 88
  }
71 89

  
......
80 98
  }
81 99

  
82 100
  @Override
83
  public boolean allowArgNames() {
84
    return true;
85
  }
86

  
87
  @Override
88 101
  public boolean useArgumentsInsteadObjects() {
89 102
    return true;
90 103
  }
......
94 107
    throw new UnsupportedOperationException();
95 108
  }
96 109

  
110
  private static final int COLUMNS = 0;
111
  private static final int TABLE = 1;
112
  private static final int WHERE = 2;
113
  private static final int ORDER = 3;
114
  private static final int ORDER_MODE = 4;
115
  private static final int LIMIT = 5;
116
  
117
  
118
  private Caller getTupleOrNull(Codes args, int argn) {
119
    Code code = args.get(argn);
120
    if( code.code()==Code.CONSTANT ) {
121
      if( ((Code.Constant)code).value()!=null ) {
122
        throw new ExpressionRuntimeException("Tupple or null expected in argument "+argn+ " of function '" + FUNCTION_SELECT + "'.");
123
      }
124
      return null;
125
    }
126
    if( code.code()!=Code.CALLER ) {
127
      throw new ExpressionRuntimeException("Tupple or null expected in argument "+argn+ " of function '" + FUNCTION_SELECT + "'.");
128
    }
129
    Caller caller = (Caller) code;
130
    if( !StringUtils.equalsIgnoreCase(FUNCTION_TUPLE, caller.name()) ) {
131
      throw new ExpressionRuntimeException("Tupple or null expected in argument "+argn+ " of function '" + FUNCTION_SELECT + "'.");
132
    }
133
    return caller;
134
  }
135
  
97 136
  @Override
98 137
  public Object call(Interpreter interpreter, Codes args) throws Exception {
99 138

  
100
    String storeName =  (String) getObject(interpreter, args, "TABLE");
101
    String where = Objects.toString(args.get("WHERE"),null);
102
    Number limit = (Number) getObject(interpreter, args, "LIMIT");
103
    FeatureQueryOrder order = null;
104
    for( int n=0 ; args.contains("ORDER", n); n++) {
105
      String member = (String) getObject(interpreter, args, "ORDER", n);
106
      Boolean mode = (Boolean) getObject(interpreter, args, "ORDER_MODE", n);
107
      if( order == null ) {
108
        order = new FeatureQueryOrder();
139
    Code.Identifier storeName =  (Code.Identifier) args.get(TABLE);
140
    Code columns = getTupleOrNull(args, COLUMNS);
141
    Code where = args.get(WHERE);
142
    Number limit = (Number) getObject(interpreter, args, LIMIT);
143
    Caller order = getTupleOrNull(args, ORDER);
144
    Caller order_mode = getTupleOrNull(args, ORDER_MODE);
145
    
146
    FeatureQueryOrder queryOrder = null;
147
    if( order!=null || order_mode!=null ) {
148
      for( int n=0 ; n<order.parameters().size(); n++) {
149
        String member = (String) interpreter.run(order.parameters().get(n));
150
        Boolean mode = (Boolean) interpreter.run(order_mode.parameters().get(n));
151
        if( queryOrder == null ) {
152
          queryOrder = new FeatureQueryOrder();
153
        }
154
        queryOrder.add(member, mode);
109 155
      }
110
      order.add(member, mode);
111 156
    }
112
    
157
    // FIXME: add columns to query.addAttributeName() 
113 158
    try {
114
      DataStore store = this.getStore(storeName);
159
      DataStore store = this.getStore(storeName.name());
115 160
      if (store == null ) {
116 161
        throw new ExpressionRuntimeException("Cant locate the store '" + storeName + "' in function '" + FUNCTION_SELECT + "'.");
117 162
      }
......
120 165
      }
121 166
      FeatureStore featureStore = (FeatureStore) store;
122 167
      List<Feature> features;
123
      if (where == null && order == null && limit==null ) {
168
      if (where == null && queryOrder == null && limit==null ) {
124 169
        features = featureStore.getFeatures();
125 170
      } else {
126 171
        FeatureQuery query = featureStore.createFeatureQuery();
127 172
        if (where != null) {
128
          Expression filter = ExpressionUtils.createExpression(where);
173
          removeOuterTablesReferences(interpreter, where);
174
          ExpressionEvaluator filter = new DefaultExpressionEvaluator(where.toString());
129 175
          filter.getSymbolTable().addSymbolTable(interpreter.getSymbolTable());
130 176
          query.addFilter(filter);
131 177
        }
132
        if (order != null) {
133
          query.getOrder().copyFrom(order);
178
        if (queryOrder != null) {
179
          query.getOrder().copyFrom(queryOrder);
134 180
        }
135 181
        if( limit!=null ) {
136 182
          query.setLimit(limit.longValue());
......
152 198
    return store;
153 199
  }
154 200

  
201
  private void removeOuterTablesReferences(Interpreter interpreter, Code where) {
202
    try {
203
      SymbolTable symbolTable = interpreter.getSymbolTable();
204
      TableAttributeHandler table = (TableAttributeHandler) symbolTable.value(SYMBOL_CURRENT_TABLE);
205
      List<Pair<Code,Code>>replaces = new ArrayList<>();
206
      CodeBuilder codeBuilder = ExpressionUtils.createCodeBuilder();
207
      where.accept((Object o) -> {
208
        Code code = (Code) o;
209
        if( code!=null && code.code() == Code.CALLER ) {
210
          Code.Caller caller = (Code.Caller) code;
211
          if( StringUtils.equalsIgnoreCase(caller.name(),FUNCTION_GETATTR) ) {
212
            Codes args = caller.parameters();
213
            Code arg0 = args.get(0);
214
            Code arg1 = args.get(1);
215
            if( arg0 instanceof Code.Identifier && arg1 instanceof Code.Identifier ) {
216
              Object tt = symbolTable.value(((Code.Identifier)arg0).name());
217
              if( tt instanceof TableAttributeHandler && 
218
                  StringUtils.equalsIgnoreCase(((TableAttributeHandler)tt).getName(), table.getName()) ) {
219
                String columnName = Objects.toString(((Code.Identifier)arg1).name(), null);
220
                if( columnName!=null ) {
221
                  Object value = table.get(columnName);
222
                  replaces.add(
223
                          new ImmutablePair<>(
224
                                  caller,
225
                                  codeBuilder.constant(value)
226
                          )
227
                  );
228
                }
229
              }
230
            }
231
          }
232
        }
233
      });
234
      for (Pair<Code, Code> replace : replaces) {
235
        if( replace!=null ) {
236
          where.replace(replace.getLeft(), replace.getRight());
237
        }
238
      }
239
    } catch (BaseException ex) {
240
      throw new ExpressionRuntimeException("Can't remove references to outer tables.", ex);
241
    }
242
                
243
  }
244

  
245
  @Override
246
  public Code optimize(Optimizer optimizer, Caller caller) {
247
    return caller; // Don't optimize SELECT
248
  }
249

  
155 250
}

Also available in: Unified diff