Statistics
| Revision:

svn-gvsig-desktop / 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 / InsertIntoTableFunction.java @ 44896

History | View | Annotate | Download (10.3 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.expressionevaluator.impl.function.dataaccess;
25

    
26
import java.util.ArrayList;
27
import java.util.List;
28
import java.util.Objects;
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.CodeBuilder;
35
import org.gvsig.expressionevaluator.Codes;
36
import static org.gvsig.expressionevaluator.ExpressionBuilder.FUNCTION_GETATTR;
37
import static org.gvsig.expressionevaluator.ExpressionBuilder.FUNCTION_TUPLE;
38
import org.gvsig.expressionevaluator.ExpressionRuntimeException;
39
import org.gvsig.expressionevaluator.ExpressionUtils;
40
import org.gvsig.expressionevaluator.Interpreter;
41
import org.gvsig.expressionevaluator.Optimizer;
42
import org.gvsig.expressionevaluator.SymbolTable;
43
import org.gvsig.expressionevaluator.impl.DALFunctions;
44
import org.gvsig.expressionevaluator.spi.AbstractFunction;
45
import org.gvsig.fmap.dal.DALLocator;
46
import org.gvsig.fmap.dal.DataManager;
47
import static org.gvsig.fmap.dal.DataManager.FUNCTION_SELECT;
48
import org.gvsig.fmap.dal.DataStore;
49
import org.gvsig.fmap.dal.expressionevaluator.ExpressionEvaluator;
50
import static org.gvsig.fmap.dal.expressionevaluator.FeatureSymbolTable.SYMBOL_CURRENT_TABLE;
51
import org.gvsig.fmap.dal.expressionevaluator.TableAttributeHandler;
52
import org.gvsig.fmap.dal.feature.EditableFeature;
53
import org.gvsig.fmap.dal.feature.Feature;
54
import org.gvsig.fmap.dal.feature.FeatureQuery;
55
import org.gvsig.fmap.dal.feature.FeatureQueryOrder;
56
import org.gvsig.fmap.dal.feature.FeatureSet;
57
import org.gvsig.fmap.dal.feature.FeatureStore;
58
import org.gvsig.fmap.dal.impl.expressionevaluator.DefaultExpressionEvaluator;
59
import org.gvsig.tools.dispose.DisposeUtils;
60
import org.gvsig.tools.exception.BaseException;
61

    
62
/**
63
 *
64
 * @author jjdelcerro
65
 */
66
public class InsertIntoTableFunction 
67
        extends AbstractFunction 
68
        implements Optimizer.FunctionOptimizer
69
  {
70

    
71
  public InsertIntoTableFunction() {
72
    super(  DALFunctions.GROUP_DATA_ACCESS,
73
            DataManager.FUNCTION_INSERT_INTO_TABLE,
74
            Range.is(7),
75
            "",
76
            DataManager.FUNCTION_INSERT_INTO_TABLE,
77
            null,
78
            "Number",
79
            false
80
    );
81
  }
82

    
83
  @Override
84
  public boolean allowConstantFolding() {
85
    return false;
86
  }
87

    
88

    
89
  @Override
90
  public boolean useArgumentsInsteadObjects() {
91
    return true;
92
  }
93
  
94
  @Override
95
  public Object call(Interpreter interpreter, Object[] args) throws Exception {
96
    throw new UnsupportedOperationException();
97
  }
98

    
99
  private static final int COLUMNS = 1;
100
  private static final int TABLE = 2;
101
  private static final int WHERE = 3;
102
  private static final int ORDER = 4;
103
  private static final int ORDER_MODE = 5;
104
  private static final int LIMIT = 6;
105
  
106
  
107
  private Code.Callable getTupleOrNull(Codes args, int argn) {
108
    Code code = args.get(argn);
109
    if( code.code()==Code.CONSTANT ) {
110
      if( ((Code.Constant)code).value()!=null ) {
111
        throw new ExpressionRuntimeException("Tupple or null expected in argument "+argn+ " of function '" + FUNCTION_SELECT + "'.");
112
      }
113
      return null;
114
    }
115
    if( code.code()!=Code.CALLABLE ) {
116
      throw new ExpressionRuntimeException("Tupple or null expected in argument "+argn+ " of function '" + FUNCTION_SELECT + "'.");
117
    }
118
    Code.Callable caller = (Code.Callable) code;
119
    if( !StringUtils.equalsIgnoreCase(FUNCTION_TUPLE, caller.name()) ) {
120
      throw new ExpressionRuntimeException("Tupple or null expected in argument "+argn+ " of function '" + FUNCTION_SELECT + "'.");
121
    }
122
    return caller;
123
  }
124
  
125
  @Override
126
  @SuppressWarnings("UseSpecificCatch")
127
  public Object call(Interpreter interpreter, Codes args) throws Exception {
128
    FeatureStore targetStore = null;
129
    FeatureStore sourceStore = null;
130
    try {
131
      String targetTableName = Objects.toString(getObject(interpreter, args, 0),null);
132
      if( targetTableName == null ) {
133
        throw new ExpressionRuntimeException("Target table name can't be null.");    
134
      }
135
      DataManager dataManager = DALLocator.getDataManager();  
136
      targetStore = (FeatureStore) dataManager.getStoresRepository().getStore(targetTableName);
137
      if( targetStore==null ) {
138
        throw new ExpressionRuntimeException("Can't locate target table '"+targetTableName+"'.");    
139
      }
140

    
141

    
142
      Code.Identifier storeName =  (Code.Identifier) args.get(TABLE);
143
      Code columns = getTupleOrNull(args, COLUMNS);
144
      Code where = args.get(WHERE);
145
      Number limit = (Number) getObject(interpreter, args, LIMIT);
146
      Code.Callable order = getTupleOrNull(args, ORDER);
147
      Code.Callable order_mode = getTupleOrNull(args, ORDER_MODE);
148

    
149
      FeatureQueryOrder queryOrder = null;
150
      if( order!=null || order_mode!=null ) {
151
        for( int n=0 ; n<order.parameters().size(); n++) {
152
          String member = (String) interpreter.run(order.parameters().get(n));
153
          Boolean mode = (Boolean) interpreter.run(order_mode.parameters().get(n));
154
          if( queryOrder == null ) {
155
            queryOrder = new FeatureQueryOrder();
156
          }
157
          queryOrder.add(member, mode);
158
        }
159
      }
160

    
161
      // FIXME: add columns to query.addAttributeName() 
162
      DataStore store = this.getStore(storeName.name());
163
      if (store == null ) {
164
        throw new ExpressionRuntimeException("Cant locate the store '" + storeName + "' in function '" + FUNCTION_SELECT + "'.");
165
      }
166
      if (!(store instanceof FeatureStore)) {
167
        throw new ExpressionRuntimeException("The store'" + storeName + "' is not valid for function '" + FUNCTION_SELECT + "', a FeatureStore is required.");
168
      }
169
      sourceStore = (FeatureStore) store;
170
      FeatureSet features;
171
      if (where == null && queryOrder == null && limit==null ) {
172
        features = sourceStore.getFeatureSet();
173
      } else {
174
        FeatureQuery query = sourceStore.createFeatureQuery();
175
        if (where != null) {
176
          removeOuterTablesReferences(interpreter, where);
177
          ExpressionEvaluator filter = new DefaultExpressionEvaluator(where.toString());
178
          filter.getSymbolTable().addSymbolTable(interpreter.getSymbolTable());
179
          query.addFilter(filter);
180
        }
181
        if (queryOrder != null) {
182
          query.getOrder().copyFrom(queryOrder);
183
        }
184
        if( limit!=null ) {
185
          query.setLimit(limit.longValue());
186
        }
187
        query.retrievesAllAttributes();
188
        features = sourceStore.getFeatureSet(query);
189
      }
190
      
191
      long count = 0;
192
      targetStore.edit(FeatureStore.MODE_APPEND);
193
      for (Feature feature : features) {
194
        EditableFeature f = targetStore.createNewFeature();
195
        f.copyFrom(feature);
196
        targetStore.insert(f);
197
        count++;
198
      }
199
      targetStore.finishEditing();
200
      
201
      return count;
202
    } catch (ExpressionRuntimeException ex) {
203
      throw ex;
204
    } catch (Exception ex) {
205
      if( targetStore!=null && targetStore.isAppending() ) {
206
        targetStore.cancelEditing();
207
      }
208
      DisposeUtils.disposeQuietly(targetStore);
209
      DisposeUtils.disposeQuietly(sourceStore);
210
      throw new ExpressionRuntimeException("Problems calling '" + FUNCTION_SELECT + "' function", ex);
211
    }
212
  }
213

    
214
  protected DataStore getStore(String storeName) {
215
    DataManager dataManager = DALLocator.getDataManager();
216
    DataStore store = dataManager.getStoresRepository().getStore(storeName);
217
    return store;
218
  }
219

    
220
  private void removeOuterTablesReferences(Interpreter interpreter, Code where) {
221
    try {
222
      SymbolTable symbolTable = interpreter.getSymbolTable();
223
      TableAttributeHandler table = (TableAttributeHandler) symbolTable.value(SYMBOL_CURRENT_TABLE);
224
      List<Pair<Code,Code>>replaces = new ArrayList<>();
225
      CodeBuilder codeBuilder = ExpressionUtils.createCodeBuilder();
226
      where.accept((Object o) -> {
227
        Code code = (Code) o;
228
        if( code!=null && code.code() == Code.CALLABLE ) {
229
          Code.Callable caller = (Code.Callable) code;
230
          if( StringUtils.equalsIgnoreCase(caller.name(),FUNCTION_GETATTR) ) {
231
            Codes args = caller.parameters();
232
            Code arg0 = args.get(0);
233
            Code arg1 = args.get(1);
234
            if( arg0 instanceof Code.Identifier && arg1 instanceof Code.Identifier ) {
235
              Object tt = symbolTable.value(((Code.Identifier)arg0).name());
236
              if( tt instanceof TableAttributeHandler && 
237
                  StringUtils.equalsIgnoreCase(((TableAttributeHandler)tt).getName(), table.getName()) ) {
238
                String columnName = Objects.toString(((Code.Identifier)arg1).name(), null);
239
                if( columnName!=null ) {
240
                  Object value = table.get(columnName);
241
                  replaces.add(
242
                          new ImmutablePair<>(
243
                                  caller,
244
                                  codeBuilder.constant(value)
245
                          )
246
                  );
247
                }
248
              }
249
            }
250
          }
251
        }
252
      });
253
      for (Pair<Code, Code> replace : replaces) {
254
        if( replace!=null ) {
255
          where.replace(replace.getLeft(), replace.getRight());
256
        }
257
      }
258
    } catch (BaseException ex) {
259
      throw new ExpressionRuntimeException("Can't remove references to outer tables.", ex);
260
    }
261
                
262
  }
263

    
264
  @Override
265
  public Code optimize(Optimizer optimizer, Code.Callable caller) {
266
    return caller; // Don't optimize SELECT
267
  }
268
}