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

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_EXISTS_TABLE;
48
import static org.gvsig.fmap.dal.DataManager.FUNCTION_SELECT;
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;
53
import org.gvsig.fmap.dal.feature.EditableFeature;
54
import org.gvsig.fmap.dal.feature.Feature;
55
import org.gvsig.fmap.dal.feature.FeatureQuery;
56
import org.gvsig.fmap.dal.feature.FeatureQueryOrder;
57
import org.gvsig.fmap.dal.feature.FeatureSet;
58
import org.gvsig.fmap.dal.feature.FeatureStore;
59
import org.gvsig.fmap.dal.impl.expressionevaluator.DefaultExpressionEvaluator;
60
import org.gvsig.tools.dispose.DisposeUtils;
61
import org.gvsig.tools.exception.BaseException;
62

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

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

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

    
89

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

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

    
142

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

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

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

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

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

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