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 / JDBCHelperBase.java @ 47779

History | View | Annotate | Download (51.9 KB)

1 45065 jjdelcerro
/**
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 43020 jjdelcerro
package org.gvsig.fmap.dal.store.jdbc2.spi;
25
26 45165 jjdelcerro
import java.io.File;
27 44297 jjdelcerro
import java.sql.Blob;
28 45008 omartinez
import java.sql.Clob;
29 43020 jjdelcerro
import java.sql.ResultSet;
30 44376 jjdelcerro
import java.util.ArrayList;
31 45162 omartinez
import java.util.HashSet;
32 46542 fdiaz
import java.util.Iterator;
33 44376 jjdelcerro
import java.util.List;
34 46010 jjdelcerro
import java.util.function.Predicate;
35 47106 jjdelcerro
import org.apache.commons.codec.binary.Hex;
36 46517 fdiaz
import org.apache.commons.collections.CollectionUtils;
37 46542 fdiaz
import org.apache.commons.collections.iterators.ReverseListIterator;
38 45008 omartinez
import org.apache.commons.io.IOUtils;
39 44376 jjdelcerro
import org.apache.commons.lang3.ArrayUtils;
40 43020 jjdelcerro
import org.apache.commons.lang3.StringUtils;
41 47198 jjdelcerro
import org.apache.commons.lang3.builder.ToStringBuilder;
42 44191 jjdelcerro
import org.apache.commons.lang3.mutable.MutableBoolean;
43 46147 jjdelcerro
import org.apache.commons.lang3.mutable.MutableObject;
44 46517 fdiaz
import org.apache.commons.lang3.tuple.ImmutablePair;
45 46108 omartinez
import org.apache.commons.lang3.tuple.Pair;
46 44191 jjdelcerro
import org.gvsig.expressionevaluator.Code;
47 46010 jjdelcerro
import org.gvsig.expressionevaluator.Expression;
48 44376 jjdelcerro
import org.gvsig.expressionevaluator.ExpressionBuilder;
49 46517 fdiaz
import static org.gvsig.expressionevaluator.ExpressionBuilder.FUNCTION_$CONSTANT;
50
import static org.gvsig.expressionevaluator.ExpressionBuilder.FUNCTION_$IDENTIFIER;
51 44191 jjdelcerro
import org.gvsig.expressionevaluator.ExpressionEvaluatorLocator;
52
import org.gvsig.expressionevaluator.ExpressionEvaluatorManager;
53
import org.gvsig.expressionevaluator.Function;
54 44644 jjdelcerro
import org.gvsig.expressionevaluator.GeometryExpressionBuilderHelper.GeometrySupportType;
55 44198 jjdelcerro
import org.gvsig.expressionevaluator.SymbolTable;
56 46517 fdiaz
import org.gvsig.fmap.dal.DALLocator;
57
import org.gvsig.fmap.dal.DataManager;
58 44750 jjdelcerro
import static org.gvsig.fmap.dal.DataManager.FUNCTION_EXISTS;
59 46783 fdiaz
import static org.gvsig.fmap.dal.DataManager.FUNCTION_FOREIGN_VALUE;
60 44750 jjdelcerro
import static org.gvsig.fmap.dal.DataManager.FUNCTION_FOREING_VALUE;
61 43020 jjdelcerro
import org.gvsig.fmap.dal.DataTypes;
62 44376 jjdelcerro
import org.gvsig.fmap.dal.SQLBuilder;
63 46517 fdiaz
import org.gvsig.fmap.dal.SQLBuilder.Column;
64 46518 fdiaz
import static org.gvsig.fmap.dal.SQLBuilder.PROP_ADD_TABLE_NAME_TO_COLUMNS;
65 47318 fdiaz
import static org.gvsig.fmap.dal.SQLBuilder.PROP_FEATURE_TYPE;
66
import static org.gvsig.fmap.dal.SQLBuilder.PROP_JDBCHELPER;
67
import static org.gvsig.fmap.dal.SQLBuilder.PROP_QUERY;
68 46517 fdiaz
import org.gvsig.fmap.dal.SQLBuilder.SelectBuilder;
69 47611 fdiaz
import org.gvsig.fmap.dal.SupportTransactionsHelper;
70 43020 jjdelcerro
import org.gvsig.fmap.dal.exception.DataException;
71
import org.gvsig.fmap.dal.exception.InitializeException;
72 46010 jjdelcerro
import org.gvsig.fmap.dal.expressionevaluator.FeatureAttributeEmulatorExpression;
73 43020 jjdelcerro
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
74 46010 jjdelcerro
import org.gvsig.fmap.dal.feature.FeatureAttributeEmulator;
75 44191 jjdelcerro
import org.gvsig.fmap.dal.feature.FeatureQueryOrder;
76 43020 jjdelcerro
import org.gvsig.fmap.dal.feature.FeatureType;
77 44376 jjdelcerro
import org.gvsig.fmap.dal.feature.ForeingKey;
78 43020 jjdelcerro
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
79 44376 jjdelcerro
import org.gvsig.fmap.dal.feature.spi.SQLBuilderBase;
80 43020 jjdelcerro
import org.gvsig.fmap.dal.resource.exception.AccessResourceException;
81
import org.gvsig.fmap.dal.resource.spi.ResourceConsumer;
82
import org.gvsig.fmap.dal.resource.spi.ResourceProvider;
83 45165 jjdelcerro
import org.gvsig.fmap.dal.serverexplorer.filesystem.FilesystemStoreParameters;
84 43020 jjdelcerro
import org.gvsig.fmap.dal.spi.DataServerExplorerProviderServices;
85
import org.gvsig.fmap.dal.spi.DataStoreProviderServices;
86 45650 jjdelcerro
import org.gvsig.fmap.dal.spi.DataTransactionServices;
87 43020 jjdelcerro
import org.gvsig.fmap.dal.store.db.DBHelper;
88
import org.gvsig.fmap.dal.store.jdbc.JDBCConnectionParameters;
89
import org.gvsig.fmap.dal.store.jdbc.JDBCNewStoreParameters;
90 46542 fdiaz
import org.gvsig.fmap.dal.store.jdbc.JDBCNewStoreParametersBase;
91
import org.gvsig.fmap.dal.store.jdbc.JDBCResourceBase;
92 43020 jjdelcerro
import org.gvsig.fmap.dal.store.jdbc.JDBCServerExplorerParameters;
93 46542 fdiaz
import org.gvsig.fmap.dal.store.jdbc.JDBCServerExplorerParametersBase;
94 43020 jjdelcerro
import org.gvsig.fmap.dal.store.jdbc.JDBCStoreParameters;
95 46542 fdiaz
import org.gvsig.fmap.dal.store.jdbc.JDBCStoreParametersBase;
96 43020 jjdelcerro
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCCantFetchValueException;
97 46517 fdiaz
import org.gvsig.fmap.dal.store.jdbc2.JDBCConnection;
98 43020 jjdelcerro
import org.gvsig.fmap.dal.store.jdbc2.JDBCHelper;
99 46542 fdiaz
import org.gvsig.fmap.dal.store.jdbc2.JDBCLibrary;
100 43020 jjdelcerro
import org.gvsig.fmap.dal.store.jdbc2.JDBCServerExplorer;
101
import org.gvsig.fmap.dal.store.jdbc2.JDBCStoreProvider;
102
import org.gvsig.fmap.dal.store.jdbc2.JDBCUtils;
103
import org.gvsig.fmap.dal.store.jdbc2.OperationsFactory;
104
import org.gvsig.fmap.dal.store.jdbc2.ResulSetControler;
105
import org.gvsig.fmap.dal.store.jdbc2.ResulSetControler.ResultSetEntry;
106 45481 fdiaz
import org.gvsig.fmap.dal.store.jdbc2.impl.ResulSetControlerBase;
107 46517 fdiaz
import org.gvsig.fmap.dal.store.jdbc2.spi.expressionbuilder.formatters.ComputedAttribute;
108 45481 fdiaz
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.OperationsFactoryBase;
109 43020 jjdelcerro
import org.gvsig.fmap.geom.Geometry;
110
import org.gvsig.fmap.geom.GeometryLocator;
111
import org.gvsig.fmap.geom.GeometryManager;
112
import org.gvsig.tools.dispose.impl.AbstractDisposable;
113 44191 jjdelcerro
import org.gvsig.tools.evaluator.Evaluator;
114 43020 jjdelcerro
import org.gvsig.tools.exception.BaseException;
115 43377 jjdelcerro
import org.gvsig.tools.exception.NotYetImplemented;
116 46517 fdiaz
import org.gvsig.tools.locator.LocatorException;
117
import org.gvsig.tools.util.ContainerUtils;
118 46010 jjdelcerro
import org.gvsig.tools.visitor.FilteredVisitable;
119 44191 jjdelcerro
import org.gvsig.tools.visitor.VisitCanceledException;
120
import org.gvsig.tools.visitor.Visitor;
121 43020 jjdelcerro
import org.slf4j.Logger;
122
import org.slf4j.LoggerFactory;
123
124 44191 jjdelcerro
@SuppressWarnings("UseSpecificCatch")
125 43020 jjdelcerro
public class JDBCHelperBase extends AbstractDisposable implements ResourceConsumer, JDBCHelper {
126
127 44750 jjdelcerro
  private static final boolean ALLOW_AUTOMATIC_VALUES = true;
128
  private static final String QUOTE_FOR_USE_IN_IDENTIFIERS = "\"";
129
  private static final String QUOTE_FOR_USE_IN_STRINGS = "'";
130 43020 jjdelcerro
131 47456 jjdelcerro
  protected static final Logger LOGGER = LoggerFactory.getLogger(JDBCHelperBase.class);
132 43020 jjdelcerro
133 44750 jjdelcerro
  private ResulSetControler resulSetControler = null;
134 43020 jjdelcerro
135 44750 jjdelcerro
  // Quien ha creado este helper.
136
  // Se le reenviaran las notificaciones del recurso asociado al helper.
137
  private ResourceConsumer helperClient = null;
138 43020 jjdelcerro
139 44750 jjdelcerro
  private GeometryManager geometryManager = null;
140 43020 jjdelcerro
141 44750 jjdelcerro
  private JDBCConnectionParameters connectionParameters;
142 43020 jjdelcerro
143 44750 jjdelcerro
  private JDBCStoreProvider store;
144 44403 omartinez
145 44750 jjdelcerro
  protected OperationsFactory operationsFactory = null;
146 44403 omartinez
147 44750 jjdelcerro
  protected SRSSolver srssolver;
148 45152 fdiaz
149
  protected FeatureType providerFeatureType = null;
150 45650 jjdelcerro
151 47611 fdiaz
//  protected DataTransactionServices transaction;
152
153
  protected SupportTransactionsHelper transactionsHelper;
154 44403 omartinez
155 44750 jjdelcerro
  public JDBCHelperBase(JDBCConnectionParameters connectionParameters) {
156 45647 fdiaz
        if (connectionParameters == null) {
157
            throw new IllegalArgumentException("Connection parameters can't be null.");
158
        }
159
        this.connectionParameters = connectionParameters;
160 47611 fdiaz
        this.transactionsHelper = new SupportTransactionsHelper();
161 44403 omartinez
162 45647 fdiaz
        // If a particular treatment is required to convert SRS to the
163
        // BBDD format, overwrite JDBCSRSsBase and use it instead of JDBCSRSsDumb.
164
        this.srssolver = new SRSSolverDumb(this);
165
    }
166 43020 jjdelcerro
167 44750 jjdelcerro
  protected void initialize(
168
          ResourceConsumer helperClient,
169
          JDBCConnectionParameters connectionParameters,
170
          JDBCStoreProvider store
171
  ) {
172
    this.store = store;
173
    this.helperClient = helperClient;
174
    this.connectionParameters = connectionParameters;
175
    initializeResource(connectionParameters);
176
  }
177 44403 omartinez
178 44750 jjdelcerro
  protected String getResourceType() {
179 46542 fdiaz
    return JDBCResourceBase.NAME;
180 44750 jjdelcerro
  }
181 43020 jjdelcerro
182 44750 jjdelcerro
  @Override
183
  public String getProviderName() {
184
    return JDBCLibrary.NAME;
185
  }
186 44403 omartinez
187 44750 jjdelcerro
  @Override
188
  public GeometrySupportType getGeometrySupportType() {
189
    // El proveedor generico de JDBC guadara las geoemtrias como WKT
190
    return GeometrySupportType.WKT;
191
  }
192 45152 fdiaz
193
    /**
194
     * @return the providerFeatureType
195
     */
196
  @Override
197
    public FeatureType getProviderFeatureType() {
198
        return providerFeatureType;
199
    }
200 43020 jjdelcerro
201 45152 fdiaz
    /**
202
     * @param providerFeatureType the providerFeatureType to set
203
     */
204 44750 jjdelcerro
  @Override
205 45152 fdiaz
    public void setProviderFeatureType(FeatureType providerFeatureType) {
206
        this.providerFeatureType = providerFeatureType;
207
    }
208
209
210
  @Override
211 44750 jjdelcerro
  public boolean hasSpatialFunctions() {
212
    // Por defecto el proveedor generico de JDBC asume que la BBDD no
213
    // tiene soporte para funciones espaciales.
214
    return false;
215
  }
216 43020 jjdelcerro
217 44750 jjdelcerro
  @Override
218
  public boolean allowNestedOperations() {
219
    return false;
220
  }
221 44403 omartinez
222 44750 jjdelcerro
  @Override
223
  public boolean canWriteGeometry(int geometryType, int geometrySubtype) {
224
    // Como va a guardar las geometrias en WKT, puede escribirlas todas.
225
    return true;
226
  }
227 43020 jjdelcerro
228 44750 jjdelcerro
  @Override
229
  public JDBCSQLBuilderBase createSQLBuilder() {
230
    return new JDBCSQLBuilderBase(this);
231
  }
232 43020 jjdelcerro
233 44750 jjdelcerro
  @Override
234
  public String getQuoteForIdentifiers() {
235
    return QUOTE_FOR_USE_IN_IDENTIFIERS;
236
  }
237 43020 jjdelcerro
238 44750 jjdelcerro
  @Override
239
  public boolean allowAutomaticValues() {
240
    return ALLOW_AUTOMATIC_VALUES;
241
  }
242 43020 jjdelcerro
243 44750 jjdelcerro
  @Override
244
  public boolean supportOffsetInSelect() {
245
    // Asumimos que la BBDD soporta OFFSET
246
    return true;
247
  }
248 44403 omartinez
249 44750 jjdelcerro
  @Override
250
  public String getQuoteForStrings() {
251
    return QUOTE_FOR_USE_IN_STRINGS;
252
  }
253 44191 jjdelcerro
254 44752 jjdelcerro
  protected boolean supportCaller(Code.Callable caller) {
255 46783 fdiaz
    if (StringUtils.equalsIgnoreCase(caller.name(), FUNCTION_FOREING_VALUE) ||
256
            StringUtils.equalsIgnoreCase(caller.name(), FUNCTION_FOREIGN_VALUE)
257
            ) {
258 44750 jjdelcerro
      return true;
259 44376 jjdelcerro
    }
260 44750 jjdelcerro
    Function function = caller.function();
261
    if (function == null) {
262
      return false;
263
    }
264
    if (!function.isSQLCompatible()) {
265
      return false;
266
    }
267
    if (!this.hasSpatialFunctions()) {
268
      if (StringUtils.equalsIgnoreCase(function.group(), Function.GROUP_OGC)) {
269
        return false;
270
      }
271
    }
272
    return true;
273
  }
274 44403 omartinez
275 44750 jjdelcerro
  @Override
276 46010 jjdelcerro
  @SuppressWarnings("Convert2Lambda")
277 44750 jjdelcerro
  public boolean supportFilter(final FeatureType type, Evaluator filter) {
278 45999 omartinez
    if (filter == null) {
279
      // No hay que filtrar nada, asi que se p?ede.
280
      return true;
281
    }
282
    String sql = filter.getSQL();
283 44750 jjdelcerro
    if (StringUtils.isEmpty(sql)) {
284
      // Hay un filtro, pero la SQL es null, con lo que no podemos
285
      // filtrar por el.
286
      return false;
287
    }
288 46010 jjdelcerro
    return this.supportExpression(type, sql);
289
  }
290
291
    @Override
292
    @SuppressWarnings("Convert2Lambda")
293
    public boolean supportExpression(final FeatureType type, String sql) {
294
        // La expression no es valida si:
295
        // - Hay una subquery especificada en los parametros
296
        // - Si la sql es null.
297
        // - Si se esta usando alguna funcion no-sql en el getSQL
298
        // - Si se esta invocando a metodos de un objeto
299
        // - Si se estan usando funciones OGC y no soportamos funciones espaciales
300
        // - Si se esta usando algun campo calculado en la expresion de filtro.
301
        //
302
        // Un proveedor especifico podria sobreescribir el metodo,
303
        // para hilar mas fino al comprobar si soporta el filtro o no.
304
        //
305 44191 jjdelcerro
306 46010 jjdelcerro
        if (StringUtils.isEmpty(sql)) {
307
            return false;
308
        }
309 44403 omartinez
310 46147 jjdelcerro
//        if (this.useSubquery()) {
311
//            // Se esta usando una subquery en los parametros de acceso a la
312
//            // BBDD, asi que no podemos filtrar.
313
//            return false;
314
//        }
315 46010 jjdelcerro
316
        // Ahora vamos a comprobar que las funciones que se usan son
317
        // compatibles sql, y que no se usan funciones OGC si el
318
        // proveedor dice que no soporta funciones espaciales.
319
        // Tambien comprobaremos que el filtro no usa ningun campo calculado.
320
        final MutableBoolean isCompatible = new MutableBoolean(true);
321
        ExpressionEvaluatorManager manager = ExpressionEvaluatorLocator.getManager();
322
        Code code = manager.compile(sql);
323
        SymbolTable symbolTable = manager.createSymbolTable();
324
        code.link(symbolTable);
325
        try {
326
            code.accept(new Visitor() {
327
                @Override
328
                public void visit(Object code_obj) throws VisitCanceledException, BaseException {
329
                    Code code1 = (Code) code_obj;
330
                    switch (code1.code()) {
331
                        case Code.CALLABLE:
332
                            Code.Callable caller = (Code.Callable) code1;
333
                            if (!supportCaller(caller)) {
334
                                isCompatible.setValue(false);
335 47319 jjdelcerro
                                LOGGER.debug("Expression not SQL compatible, use '"+caller.name()+"' ("+sql+").");
336 46010 jjdelcerro
                                throw new VisitCanceledException();
337
                            }
338
                            break;
339
                        case Code.METHOD:
340
                            isCompatible.setValue(false);
341 47319 jjdelcerro
                            LOGGER.debug("Expression not SQL compatible, use objects methods ("+sql+").");
342 46010 jjdelcerro
                            throw new VisitCanceledException();
343
                        case Code.IDENTIFIER:
344
                            Code.Identifier identifier = (Code.Identifier) code1;
345
                            if (type != null) {
346
                                FeatureAttributeDescriptor attrdesc = type.getAttributeDescriptor(identifier.name());
347
                                if (attrdesc != null) {
348
                                    if (attrdesc.isComputed()) {
349
                                        FeatureAttributeEmulator emulator = attrdesc.getFeatureAttributeEmulator();
350
                                        if (!(emulator instanceof FeatureAttributeEmulatorExpression)) {
351 47319 jjdelcerro
                                            LOGGER.debug("Expression not SQL compatible, use calculated field '"+attrdesc.getName()+"' ("+sql+").");
352 46010 jjdelcerro
                                            isCompatible.setValue(false);
353
                                            throw new VisitCanceledException();
354
                                        }
355
                                        Expression expr = ((FeatureAttributeEmulatorExpression) emulator).getExpression();
356
                                        if (!supportExpression(type, expr.getPhrase())) {
357 47319 jjdelcerro
                                            LOGGER.debug("Expression not SQL compatible, use calculated field '"+attrdesc.getName()+"' ("+expr.getPhrase()+"/"+sql+").");
358 46010 jjdelcerro
                                            isCompatible.setValue(false);
359
                                            throw new VisitCanceledException();
360
                                        }
361
                                    }
362
                                }
363
                            }
364
                            break;
365
                    }
366 45999 omartinez
                }
367 46010 jjdelcerro
            }, new Predicate<FilteredVisitable>() {
368
                @Override
369
                public boolean test(FilteredVisitable code0) {
370
                    if (code0 instanceof Code.Callable) {
371
                        String name = ((Code.Callable) code0).name();
372 46050 omartinez
                        return StringUtils.equalsIgnoreCase(name, FUNCTION_$CONSTANT)
373
                                || StringUtils.equalsIgnoreCase(name, FUNCTION_$IDENTIFIER);
374 46010 jjdelcerro
                    }
375
                    return false;
376
                }
377
            });
378
379
        } catch (VisitCanceledException ex) {
380
            // Do nothing
381
        } catch (Exception ex) {
382
            LOGGER.warn("Can't calculate if is SQL compatible.", ex);
383 44191 jjdelcerro
        }
384 44403 omartinez
385 46010 jjdelcerro
        return isCompatible.booleanValue();
386 44191 jjdelcerro
    }
387 44403 omartinez
388 44750 jjdelcerro
  @Override
389
  public boolean supportOrder(FeatureType type, FeatureQueryOrder order) {
390
    if (this.useSubquery()) {
391
      return false;
392
    }
393
    if (order == null) {
394
      return true;
395
    }
396
    for (FeatureQueryOrder.FeatureQueryOrderMember member : order.members()) {
397
      if (member.hasEvaluator()) {
398
        if (!this.supportFilter(type, member.getEvaluator())) {
399
          return false;
400 44191 jjdelcerro
        }
401 44750 jjdelcerro
      }
402 44191 jjdelcerro
    }
403 44750 jjdelcerro
    return true;
404
  }
405 44403 omartinez
406 44750 jjdelcerro
  @Override
407
  public OperationsFactory getOperations() {
408 45481 fdiaz
    if (this.operationsFactory == null && !isClosed()) {
409 44750 jjdelcerro
      this.operationsFactory = new OperationsFactoryBase(this);
410 43020 jjdelcerro
    }
411 44750 jjdelcerro
    return operationsFactory;
412
  }
413 44403 omartinez
414 44750 jjdelcerro
  protected void initializeResource(JDBCConnectionParameters params) {
415 43020 jjdelcerro
//        Object[] resourceParams = new Object[]{
416
//            params.getUrl(),
417
//            params.getHost(),
418
//            params.getPort(),
419
//            params.getDBName(),
420
//            params.getUser(),
421
//            params.getPassword(),
422
//            params.getJDBCDriverClassName()
423
//        };
424
//
425
//        try {
426
//            ResourceManagerProviderServices manager
427
//                    = (ResourceManagerProviderServices) DALLocator.getResourceManager();
428 46542 fdiaz
//            JDBCResourceBase resource = (JDBCResourceBase) manager.createAddResource(
429 43020 jjdelcerro
//                    this.getResourceType(),
430
//                    resourceParams
431
//            );
432
//            this.resource = resource;
433
//            this.resource.addConsumer(this);
434
//        } catch (InitializeException ex) {
435 44750 jjdelcerro
//            logger.trace("Can't initialize resource (" + ArrayUtils.toString(resourceParams) + ").", ex);
436 43020 jjdelcerro
//            throw new RuntimeException("Can't initialize resource (" + ArrayUtils.toString(resourceParams) + ").", ex);
437
//        }
438
439 44750 jjdelcerro
  }
440 43020 jjdelcerro
441 44750 jjdelcerro
  @Override
442
  public String getSourceId() {
443
    return this.store.getSourceId();
444
  }
445 44403 omartinez
446 44750 jjdelcerro
  @Override
447 46542 fdiaz
  public JDBCResourceBase getResource() {
448 44750 jjdelcerro
    return null;
449 43020 jjdelcerro
//        return this.resource;
450 44750 jjdelcerro
  }
451 43020 jjdelcerro
452 44750 jjdelcerro
  @Override
453 46315 jjdelcerro
  public JDBCConnection getConnection() throws AccessResourceException {
454 44750 jjdelcerro
    throw new NotYetImplemented();
455
  }
456 43020 jjdelcerro
457 44750 jjdelcerro
  @Override
458 46315 jjdelcerro
  public JDBCConnection getConnectionWritable() throws AccessResourceException {
459 44750 jjdelcerro
    return this.getConnection();
460
  }
461 43377 jjdelcerro
462 44750 jjdelcerro
  @Override
463
  public String getConnectionURL() {
464
    return null;
465
  }
466 43035 jjdelcerro
467 44750 jjdelcerro
  @Override
468
  public JDBCConnectionParameters getConnectionParameters() {
469
    return connectionParameters;
470
  }
471 43035 jjdelcerro
472 44750 jjdelcerro
  @Override
473
  protected void doDispose() throws BaseException {
474
    JDBCUtils.closeQuietly(this);
475
  }
476 43020 jjdelcerro
477 44750 jjdelcerro
  @Override
478
  public void close() throws Exception {
479
    JDBCUtils.closeQuietly(this.resulSetControler);
480
    this.resulSetControler = null;
481 45481 fdiaz
    this.operationsFactory = null;
482
    this.srssolver = null;
483
    this.connectionParameters = null;
484
    this.helperClient = null;
485
    this.geometryManager = null;
486
    this.providerFeatureType = null;
487
    this.store = null;
488 47611 fdiaz
//    this.transaction = null;
489
    this.transactionsHelper.setTransaction(null);
490 44750 jjdelcerro
  }
491 45481 fdiaz
492
  public boolean isClosed() {
493
      return this.srssolver == null;
494
  }
495 43020 jjdelcerro
496 44750 jjdelcerro
  @Override
497
  public boolean closeResourceRequested(ResourceProvider resource) {
498
    return this.helperClient.closeResourceRequested(resource);
499
  }
500 43020 jjdelcerro
501 44750 jjdelcerro
  @Override
502
  public void resourceChanged(ResourceProvider resource) {
503
    this.helperClient.resourceChanged(resource);
504
  }
505 43020 jjdelcerro
506 44750 jjdelcerro
  @Override
507
  public GeometryManager getGeometryManager() {
508
    if (this.geometryManager == null) {
509
      this.geometryManager = GeometryLocator.getGeometryManager();
510 43020 jjdelcerro
    }
511 44750 jjdelcerro
    return this.geometryManager;
512
  }
513 43020 jjdelcerro
514 44750 jjdelcerro
  @Override
515
  public ResulSetControler getResulSetControler() {
516
    if (this.resulSetControler == null) {
517
      this.resulSetControler = new ResulSetControlerBase(this);
518 43020 jjdelcerro
    }
519 44750 jjdelcerro
    return this.resulSetControler;
520
  }
521 43020 jjdelcerro
522 44750 jjdelcerro
  @Override
523
  public void fetchFeature(FeatureProvider feature, ResultSetEntry rs) throws DataException {
524
    fetchFeature(feature, rs.get(), rs.getColumns(), rs.getExtraValueNames());
525
  }
526 43020 jjdelcerro
527 44750 jjdelcerro
  @Override
528
  public void fetchFeature(FeatureProvider feature, ResultSet rs, FeatureAttributeDescriptor[] columns, String[] extraValueNames) throws DataException {
529
    Object value;
530
    try {
531
      int rsIndex = 1;
532
      for (FeatureAttributeDescriptor column : columns) {
533
        switch (column.getType()) {
534
          case DataTypes.GEOMETRY:
535
            value = this.getGeometryFromColumn(rs, rsIndex++);
536 47062 fdiaz
            if (value != null){
537
                ((Geometry)value).setProjection(column.getSRS());
538
            }
539 44750 jjdelcerro
            break;
540
          default:
541
            value = rs.getObject(rsIndex++);
542
            if (value instanceof Blob) {
543
              Blob blob = (Blob) value;
544 45152 fdiaz
              value = blob.getBytes(1, (int) blob.length());
545 44750 jjdelcerro
              blob.free();
546 45008 omartinez
            } else if(value instanceof Clob) {
547
              Clob clob = (Clob) value;
548
              value = new String(IOUtils.toCharArray(clob.getCharacterStream()));
549
              clob.free();
550
          }
551 43020 jjdelcerro
        }
552 44750 jjdelcerro
        feature.set(column.getIndex(), value);
553
      }
554
      if (ArrayUtils.isNotEmpty(extraValueNames)) {
555
        feature.setExtraValueNames(extraValueNames);
556
        for (int index = 0; index < extraValueNames.length; index++) {
557
          value = rs.getObject(rsIndex++);
558
          if (value instanceof Blob) {
559
            Blob blob = (Blob) value;
560
            value = blob.getBytes(0, (int) blob.length());
561
            blob.free();
562
          }
563
          feature.setExtraValue(index, value);
564
        }
565
      }
566
    } catch (Exception ex) {
567
      throw new JDBCCantFetchValueException(ex);
568 43020 jjdelcerro
    }
569 44750 jjdelcerro
  }
570 43020 jjdelcerro
571 44750 jjdelcerro
  @Override
572
  public Geometry getGeometryFromColumn(ResultSetEntry rs, int index) throws DataException {
573
    return getGeometryFromColumn(rs.get(), index);
574
  }
575 43020 jjdelcerro
576 44750 jjdelcerro
  @Override
577
  public Geometry getGeometryFromColumn(ResultSet rs, int index) throws DataException {
578
    try {
579
      Object value;
580 46302 jjdelcerro
      Geometry geom;
581 44750 jjdelcerro
      switch (this.getGeometrySupportType()) {
582
        case WKB:
583
          value = rs.getBytes(index);
584
          if (value == null) {
585
            return null;
586
          }
587 46302 jjdelcerro
          geom = this.getGeometryManager().createFrom((byte[]) value);
588
          if( geom == null ) {
589
              LOGGER.debug("Can't get geometry from bytes of column "+index);
590
          }
591
          return geom;
592 43020 jjdelcerro
593 47456 jjdelcerro
        case NATIVE:
594 44750 jjdelcerro
        case EWKB:
595
          value = rs.getBytes(index);
596
          if (value == null) {
597
            return null;
598
          }
599 46302 jjdelcerro
          geom = this.getGeometryManager().createFrom((byte[]) value);
600
          if( geom == null ) {
601
              LOGGER.debug("Can't get geometry from bytes of column "+index);
602
          }
603
          return geom;
604 44750 jjdelcerro
        case WKT:
605
        default:
606
          value = rs.getString(index);
607
          if (value == null) {
608
            return null;
609
          }
610 46302 jjdelcerro
          geom = this.getGeometryManager().createFrom((String) value);
611
          if( geom == null ) {
612
              LOGGER.debug("Can't get geometry from bytes of column "+index);
613
          }
614
          return geom;
615 43020 jjdelcerro
616 44750 jjdelcerro
      }
617
    } catch (Exception ex) {
618
      throw new JDBCCantFetchValueException(ex);
619 43020 jjdelcerro
    }
620 44750 jjdelcerro
  }
621 43020 jjdelcerro
622 44750 jjdelcerro
  @Override
623
  public FeatureProvider createFeature(FeatureType featureType) throws DataException {
624
    return this.store.getStoreServices().createDefaultFeatureProvider(featureType);
625
  }
626 44403 omartinez
627 44750 jjdelcerro
  @Override
628
  public boolean useSubquery() {
629
    if (this.store == null) {
630
      return false;
631 44403 omartinez
    }
632 44750 jjdelcerro
    return !StringUtils.isEmpty(this.store.getParameters().getSQL());
633
  }
634 44403 omartinez
635 44750 jjdelcerro
  @Override
636
  public SRSSolver getSRSSolver() {
637
    return this.srssolver;
638
  }
639 44403 omartinez
640 44750 jjdelcerro
  @Override
641
  public JDBCStoreProvider createProvider(
642
          JDBCStoreParameters parameters,
643
          DataStoreProviderServices providerServices
644
  ) throws InitializeException {
645 44403 omartinez
646 44750 jjdelcerro
    JDBCStoreProviderBase theStore = new JDBCStoreProviderBase(
647
            parameters,
648
            providerServices,
649
            DBHelper.newMetadataContainer(JDBCLibrary.NAME),
650
            this
651
    );
652
    this.initialize(theStore, parameters, theStore);
653
    return theStore;
654
  }
655 43020 jjdelcerro
656 44750 jjdelcerro
  @Override
657
  public JDBCServerExplorer createServerExplorer(
658
          JDBCServerExplorerParameters parameters,
659
          DataServerExplorerProviderServices providerServices
660
  ) throws InitializeException {
661 44403 omartinez
662 44750 jjdelcerro
    JDBCServerExplorer explorer = new JDBCServerExplorerBase(
663
            parameters,
664
            providerServices,
665
            this
666
    );
667
    this.initialize(explorer, parameters, null);
668
    return explorer;
669
  }
670 43020 jjdelcerro
671 44750 jjdelcerro
  @Override
672
  public JDBCNewStoreParameters createNewStoreParameters() {
673 46542 fdiaz
    return new JDBCNewStoreParametersBase();
674 44750 jjdelcerro
  }
675 43020 jjdelcerro
676 44750 jjdelcerro
  @Override
677
  public JDBCStoreParameters createOpenStoreParameters() {
678 46542 fdiaz
    return new JDBCStoreParametersBase();
679 44750 jjdelcerro
  }
680 45165 jjdelcerro
681
  @Override
682
  public JDBCStoreParameters createOpenStoreParameters(JDBCServerExplorerParameters parameters) {
683
    JDBCStoreParameters params = this.createOpenStoreParameters();
684
    params.setHost(parameters.getHost());
685
    params.setPort(parameters.getPort());
686
    params.setDBName(parameters.getDBName());
687
    params.setUser(parameters.getUser());
688
    params.setPassword(parameters.getPassword());
689
    params.setCatalog(parameters.getCatalog());
690
    params.setSchema(parameters.getSchema());
691
    params.setJDBCDriverClassName(parameters.getJDBCDriverClassName());
692
    params.setUrl(parameters.getUrl());
693
    if( parameters instanceof FilesystemStoreParameters ) {
694
        File f = ((FilesystemStoreParameters) parameters).getFile();
695
        ((FilesystemStoreParameters) params).setFile(f);
696
    }
697 46422 jjdelcerro
    params.setBatchSize(parameters.getBatchSize());
698 45165 jjdelcerro
    return params;
699
  }
700
701 43020 jjdelcerro
702 44750 jjdelcerro
  @Override
703
  public JDBCServerExplorerParameters createServerExplorerParameters() {
704 46542 fdiaz
    return new JDBCServerExplorerParametersBase();
705 44750 jjdelcerro
  }
706 43020 jjdelcerro
707 44750 jjdelcerro
  @Override
708 46942 fdiaz
  public String getSourceId(JDBCStoreParameters params) {
709
        StringBuilder builder = new StringBuilder();
710
        builder.append(params.getTable());
711
        builder.append("(");
712
        boolean needComma = false;
713
        if( StringUtils.isNotBlank(params.getHost()) ) {
714
            builder.append("host=");
715
            builder.append(params.getHost());
716
            needComma = true;
717
        }
718
        if( params.getPort()>0 ) {
719
            if (needComma ) {
720
                builder.append(", ");
721
            }
722
            builder.append("port=");
723
            builder.append(params.getPort());
724
            needComma = true;
725
        }
726
        if( StringUtils.isNotBlank(params.getDBName()) ) {
727
            if (needComma ) {
728
                builder.append(", ");
729
            }
730
            builder.append("db=");
731
            builder.append(params.getDBName());
732
            needComma = true;
733
        }
734
        if( StringUtils.isNotBlank(params.getSchema()) ) {
735
            if (needComma ) {
736
                builder.append(", ");
737
            }
738
            builder.append("schema=");
739
            builder.append(params.getSchema());
740
            needComma = true;
741
        }
742
        builder.append(")");
743
        return builder.toString();
744 44750 jjdelcerro
  }
745 44198 jjdelcerro
746 44750 jjdelcerro
  @Override
747
  public boolean isThreadSafe() {
748
    return true;
749
  }
750
751 45131 fdiaz
  /**
752
   * This method has been overriden in Oracle provider
753
   *
754
   * @param sqlbuilder
755
   * @param type
756
   * @param extra_column_names
757
   */
758 44750 jjdelcerro
  @Override
759
  public void processSpecialFunctions(
760
          SQLBuilder sqlbuilder,
761
          FeatureType type,
762
          List<String> extra_column_names) {
763
    replaceForeingValueFunction(sqlbuilder, type, extra_column_names);
764
    replaceExistsFunction(sqlbuilder, type, extra_column_names);
765 46505 fdiaz
    addTableToColumnReferences(sqlbuilder, type);
766 44750 jjdelcerro
  }
767
768 46010 jjdelcerro
  @SuppressWarnings("Convert2Lambda")
769 46518 fdiaz
  protected void replaceExistsFunction(
770 44750 jjdelcerro
          SQLBuilder sqlbuilder,
771
          FeatureType type,
772
          final List<String> extra_column_names) {
773 44748 jjdelcerro
774 44750 jjdelcerro
    //  Si lse encuentra una construccion del tipo:
775
    //    SELECT ... FROM ... WHERE ... EXISTS(list, 'EXISTS_ID') ...
776
    //  se traslada a:
777
    //    SELECT ... EXISTS(list) AS EXISTS_ID FROM ... WHERE ... EXISTS(list) ...
778
    //  Y se a?ade el valor ESISTS_ID a las columnas extra a recuperar de la consulta.
779
    //
780
781
    final SQLBuilder.SelectBuilder select = sqlbuilder.select();
782
    final ExpressionBuilder where = select.where();
783 46559 fdiaz
    if (where == null || where.isEmpty() || select.has_group_by() || select.has_aggregate_functions()) {
784 44750 jjdelcerro
      return;
785 44748 jjdelcerro
    }
786 44750 jjdelcerro
    final List<ExpressionBuilder.Value[]> value_replacements = new ArrayList<>();
787
    where.accept(new ExpressionBuilder.Visitor() {
788
      @Override
789
      public void visit(ExpressionBuilder.Visitable value) {
790
        if (!(value instanceof ExpressionBuilder.Function)) {
791
          return;
792 44376 jjdelcerro
        }
793 44750 jjdelcerro
        ExpressionBuilder.Function function = (ExpressionBuilder.Function) value;
794
        if (!StringUtils.equalsIgnoreCase(function.name(), FUNCTION_EXISTS)) {
795
          return;
796 44682 jjdelcerro
        }
797 44750 jjdelcerro
        if (function.parameters().size() != 2) {
798
          return;
799
        }
800
        ExpressionBuilder.Value arg0 = function.parameters().get(0);
801
        ExpressionBuilder.Value arg1 = function.parameters().get(1);
802
        if (arg1 == null) {
803
          return;
804
        }
805
        String columnName = (String) ((ExpressionBuilder.Constant) arg1).value();
806
        SQLBuilder.SelectColumnBuilder column = select.column();
807
        column.value(
808
                sqlbuilder.expression().function(FUNCTION_EXISTS, arg0)
809
        );
810
        column.as(columnName);
811 45131 fdiaz
812 44750 jjdelcerro
        if( extra_column_names!=null ) {
813
          extra_column_names.add(columnName);
814
        }
815
      }
816
    }, null);
817
    if (value_replacements.isEmpty()) {
818
      return;
819
    }
820
    // Realizamos los reemplazos calculados previamente (value_replacements).
821
    for (ExpressionBuilder.Value[] replaceValue : value_replacements) {
822
      ExpressionBuilder.Value target = replaceValue[0];
823
      ExpressionBuilder.Value replacement = replaceValue[1];
824
      sqlbuilder.select().replace(target, replacement);
825
    }
826
  }
827 44376 jjdelcerro
828 46010 jjdelcerro
  @SuppressWarnings("Convert2Lambda")
829 45131 fdiaz
  protected void replaceForeingValueFunction(
830 44750 jjdelcerro
          SQLBuilder sqlbuilder,
831
          FeatureType type,
832
          List<String> extra_column_names) {
833
    try {
834
      // See test SQLBuilderTest->testForeingValue()
835
      final ExpressionBuilder where = sqlbuilder.select().where();
836 45155 omartinez
//      if (where == null || where.isEmpty()) {
837
//        return;
838
//      }
839 44750 jjdelcerro
      final SQLBuilder.TableNameBuilder table = sqlbuilder.select().from().table();
840
      final ExpressionBuilder expbuilder = sqlbuilder.expression();
841 44403 omartinez
842 44750 jjdelcerro
      final List<String> foreing_value_args;
843 46258 jjdelcerro
      if (extra_column_names == null || sqlbuilder.select().has_group_by() || sqlbuilder.select().has_aggregate_functions() ) {
844 44750 jjdelcerro
        foreing_value_args = new ArrayList<>();
845
      } else {
846
        foreing_value_args = extra_column_names;
847
      }
848
      final List<ExpressionBuilder.Value[]> value_replacements = new ArrayList<>();
849
850 46147 jjdelcerro
      MutableObject<Boolean> hasForeignValueFunctions = new MutableObject<>(false);
851
852 44750 jjdelcerro
      // Buscamos las llamadas a la funcion "foreing_value" y nos quedamos
853
      // el argumento de esta asi como por que tendriamos que sustituirla
854
      // una vez hechos los left joins que toquen.
855 45155 omartinez
      sqlbuilder.select().accept(new ExpressionBuilder.Visitor() {
856 44750 jjdelcerro
        @Override
857
        public void visit(ExpressionBuilder.Visitable value) {
858
          // Requiere que sea la funcion "FOREING_VALUE con un solo
859
          // argumento que sea una constante de tipo string.
860
          if (!(value instanceof ExpressionBuilder.Function)) {
861 44682 jjdelcerro
            return;
862 44750 jjdelcerro
          }
863
          ExpressionBuilder.Function function = (ExpressionBuilder.Function) value;
864 46783 fdiaz
          if (!(StringUtils.equalsIgnoreCase(function.name(), FUNCTION_FOREIGN_VALUE)
865
                  || StringUtils.equalsIgnoreCase(function.name(), FUNCTION_FOREING_VALUE))) {
866 44750 jjdelcerro
            return;
867
          }
868
          if (function.parameters().size() != 1) {
869
            return;
870
          }
871
          ExpressionBuilder.Value arg = function.parameters().get(0);
872
          if (!(arg instanceof ExpressionBuilder.Constant)) {
873
            return;
874
          }
875
          Object arg_value = ((ExpressionBuilder.Constant) arg).value();
876
          if (!(arg_value instanceof CharSequence)) {
877
            return;
878
          }
879 46147 jjdelcerro
          hasForeignValueFunctions.setValue(true);
880 44750 jjdelcerro
          String foreing_value_arg = arg_value.toString();
881
          String[] foreingNameParts = StringUtils.split(foreing_value_arg, "[.]");
882
          if (foreingNameParts.length != 2) {
883
            // De momento solo tratamos joins entre dos tablas.
884
            return;
885
          }
886
          String columnNameLocal = foreingNameParts[0];
887
          String columnNameForeing = foreingNameParts[1];
888
          FeatureAttributeDescriptor attr = type.getAttributeDescriptor(columnNameLocal);
889 45385 omartinez
          if (attr==null) {
890
              throw new RuntimeException("Cannot find in feature type attribute:"+columnNameLocal);
891
          }
892 44750 jjdelcerro
          if (!attr.isForeingKey()) {
893
            // Uhm... si el argumento no referencia a un campo que es
894
            // clave ajena no lo procesamos.
895
            // ? Deberiamos lanzar un error ?
896
            return;
897
          }
898
          // Nos guardaremos por que hay que reemplazar la funcion
899
          // FOREING_VALUE, y su argumento para mas tarde.
900
          ForeingKey foreingKey = attr.getForeingKey();
901
          SQLBuilder.TableNameBuilder foreingTable = sqlbuilder.createTableNameBuilder()
902
                  .database(table.getDatabase())
903
                  .schema(table.getSchema())
904
                  .name(foreingKey.getTableName());
905
          // Reemplzaremos la funcion FOREING_VALUE, por el acceso al campo
906
          // que toca de la tabla a la que referencia la clave ajena.
907
          ExpressionBuilder.Variable function_replacement = sqlbuilder.column(foreingTable, columnNameForeing);
908
          value_replacements.add(
909
                  new ExpressionBuilder.Value[]{
910
                    function,
911
                    function_replacement
912
                  }
913
          );
914 45155 omartinez
          if (!foreing_value_args.contains(foreing_value_arg)) {
915
            foreing_value_args.add(foreing_value_arg);
916
          }
917 44376 jjdelcerro
        }
918 44750 jjdelcerro
      }, null);
919 45155 omartinez
920 44750 jjdelcerro
      // Si no habia ningun llamada a la funcion FOREING_VALUE, no hay que
921
      // hacer nada.
922 46147 jjdelcerro
      if ( !hasForeignValueFunctions.getValue() || foreing_value_args.isEmpty()) {
923 44750 jjdelcerro
        return;
924
      }
925 44403 omartinez
926 44750 jjdelcerro
      // Calculamos que referencias de columnas hemos de cambiar para
927
      // que no aparezcan ambiguedades al hacer el join (nombres de
928
      // columna de una y otra tabla que coincidan).
929
      // Para las columnas que puedan dar conflicto se prepara un reemplazo
930
      // de estas que tenga el nombre de tabla.
931
      for (ExpressionBuilder.Variable variable : sqlbuilder.variables()) {
932 46010 jjdelcerro
        if (variable == null || variable instanceof SQLBuilderBase.ColumnBase) {
933 44750 jjdelcerro
          continue;
934 44376 jjdelcerro
        }
935 46221 omartinez
        if (ContainerUtils.contains(extra_column_names, variable.name(), ContainerUtils.EQUALS_IGNORECASE_COMPARATOR)) {
936
            continue;
937
        }
938 46505 fdiaz
        boolean alreadyReplaced = false;
939 44376 jjdelcerro
        for (String foreingName : foreing_value_args) {
940 44750 jjdelcerro
          String[] foreingNameParts = foreingName.split("[.]");
941
          if (foreingNameParts.length != 2) {
942
            continue;
943
          }
944
          String columnNameLocal = foreingNameParts[0];
945
          String columnNameForeing = foreingNameParts[1];
946 46221 omartinez
          if (StringUtils.equalsIgnoreCase(variable.name(), columnNameForeing)) {
947 46505 fdiaz
              if(alreadyReplaced){
948
                  throw new RuntimeException("Column reference \""+ columnNameForeing+"\" is ambiguous");
949
              }
950
              alreadyReplaced = true;
951 46221 omartinez
952
              FeatureAttributeDescriptor attr = type.getAttributeDescriptor(columnNameLocal);
953
              if (attr == null) {
954
                  throw new RuntimeException("Cannot find in feature type attribute:" + columnNameLocal);
955
              }
956
              if (attr.isForeingKey()) {
957
                  // Nos guardaremos por que hay que reemplazar la funcion
958
                  // FOREING_VALUE, y su argumento para mas tarde.
959
                  ForeingKey foreingKey = attr.getForeingKey();
960
                  SQLBuilder.TableNameBuilder foreingTable = sqlbuilder.createTableNameBuilder()
961
                          .database(table.getDatabase())
962
                          .schema(table.getSchema())
963
                          .name(foreingKey.getTableName());
964
                  ExpressionBuilder.Variable variable_replacement = sqlbuilder.column(
965
                          foreingTable,
966
                          variable.name()
967
                  );
968
                  value_replacements.add(
969
                          new ExpressionBuilder.Value[]{
970
                              variable,
971
                              variable_replacement
972
                          }
973
                  );
974
              }
975
          }
976
          if (StringUtils.equalsIgnoreCase(variable.name(), columnNameLocal)) {
977 44750 jjdelcerro
            ExpressionBuilder.Variable variable_replacement = sqlbuilder.column(
978
                    table,
979
                    variable.name()
980
            );
981
            value_replacements.add(
982
                    new ExpressionBuilder.Value[]{
983
                      variable,
984
                      variable_replacement
985
                    }
986
            );
987
          }
988
        }
989
      }
990 44376 jjdelcerro
991 44750 jjdelcerro
      // Realizamos los reemplazos calculados previamente (value_replacements).
992
      for (ExpressionBuilder.Value[] replaceValue : value_replacements) {
993
        ExpressionBuilder.Value target = replaceValue[0];
994
        ExpressionBuilder.Value replacement = replaceValue[1];
995
        sqlbuilder.select().replace(target, replacement);
996
      }
997
998 45162 omartinez
        // A?adimos a la SQL los "LEFT JOIN" que toca para poder acceder
999
        // a los valores referenciados por la funcion FOREING_VALUE.
1000
        // Ademas a?adimos los valores referenciados por la funcion FOREING_VALUE
1001
        // como columnas de la SQL para poder acceder a ellos si fuese necesario.
1002
        HashSet usedLeftJoins = new HashSet();
1003 44750 jjdelcerro
      for (String foreingName : foreing_value_args) {
1004
        String[] foreingNameParts = foreingName.split("[.]");
1005
        if (foreingNameParts.length != 2) {
1006
          continue;
1007 44376 jjdelcerro
        }
1008 44750 jjdelcerro
        String columnNameLocal = foreingNameParts[0];
1009
        String columnNameForeing = foreingNameParts[1];
1010
        FeatureAttributeDescriptor attr = type.getAttributeDescriptor(columnNameLocal);
1011
        if (attr.isForeingKey()) {
1012
          ForeingKey foreingKey = attr.getForeingKey();
1013
          SQLBuilder.TableNameBuilder foreingTable = sqlbuilder.createTableNameBuilder()
1014
                  .database(table.getDatabase())
1015
                  .schema(table.getSchema())
1016
                  .name(foreingKey.getTableName());
1017
          SQLBuilder.TableNameBuilder mainTable = sqlbuilder.createTableNameBuilder()
1018
                  .database(table.getDatabase())
1019
                  .schema(table.getSchema())
1020
                  .name(table.getName());
1021 45162 omartinez
1022
          if (!usedLeftJoins.contains(foreingTable.getName())) {
1023 47318 fdiaz
            Column v = sqlbuilder.column(mainTable, columnNameLocal);
1024
            v.setProperty(PROP_FEATURE_TYPE, type);
1025
            v.setProperty(PROP_JDBCHELPER, this);
1026
            v.setProperty(PROP_QUERY, sqlbuilder.select().getProperty(PROP_QUERY));
1027
1028 45162 omartinez
            sqlbuilder.select().from()
1029
                    .left_join(
1030
                            foreingTable,
1031
                            expbuilder.eq(
1032 47318 fdiaz
                                    v,
1033 45162 omartinez
                                    sqlbuilder.column(foreingTable, foreingKey.getCodeName())
1034
                            )
1035
                    );
1036
            usedLeftJoins.add(foreingTable.getName());
1037
          }
1038 46505 fdiaz
          //No est? claro si debe a?adirse esta columna o no, OJO quitarlo o ponerlo altera los test de  H2
1039 46517 fdiaz
          //Si se comentarizan ojo con extra_column_names ya que se habr?n a?adido columnas que no estar?n en la select
1040
          if ( !(sqlbuilder.select().has_group_by() || sqlbuilder.select().has_aggregate_functions()) ) {
1041
                sqlbuilder.select().column().name(foreingTable, columnNameForeing);
1042
          }
1043 44750 jjdelcerro
        }
1044 44682 jjdelcerro
      }
1045 45385 omartinez
1046 44750 jjdelcerro
    } catch (Throwable th) {
1047 46783 fdiaz
      LOGGER.warn("Can't replace FOREIGN_VALUE function.", th);
1048 44750 jjdelcerro
      throw th;
1049
    } finally {
1050 46361 jjdelcerro
//      LOGGER.trace("Exit from replaceForeingValueFunction.");
1051 44376 jjdelcerro
    }
1052 44750 jjdelcerro
  }
1053 46505 fdiaz
1054
    protected void addTableToColumnReferences(SQLBuilder sqlbuilder, FeatureType type) {
1055 46517 fdiaz
        SelectBuilder select = sqlbuilder.select();
1056
        List<Pair<SQLBuilder.TableNameBuilder, FeatureType>> tables = new ArrayList<>();
1057
        collectTablesFromSelect(select, tables, type);
1058 45650 jjdelcerro
1059 46517 fdiaz
        addTableToColumnReferencesInSingleSelect(
1060
                sqlbuilder,
1061
                select,
1062
                tables
1063
        );
1064
1065
    }
1066 46505 fdiaz
1067 46517 fdiaz
    private void collectTablesFromSelect(SelectBuilder select, List<Pair<SQLBuilder.TableNameBuilder, FeatureType>> tables, FeatureType type) throws LocatorException {
1068
        DataManager dataManager = DALLocator.getDataManager();
1069 46505 fdiaz
1070 46517 fdiaz
        List<SQLBuilder.JoinBuilder> joins = select.from().getJoins();
1071
        if(!CollectionUtils.isEmpty(joins)){
1072
            for (SQLBuilder.JoinBuilder join : joins) {
1073
                SQLBuilder.TableNameBuilder joinTable = join.getTable();
1074
                FeatureType featureType = dataManager.getStoresRepository().getFeatureType(joinTable.getName());
1075 46518 fdiaz
                if(featureType != null){
1076
                    tables.add(new ImmutablePair<>(joinTable,featureType));
1077
                }
1078 46517 fdiaz
            }
1079
        }
1080
        SQLBuilder.TableNameBuilder table = select.from().table();
1081
        if(type == null){
1082
            type = dataManager.getStoresRepository().getFeatureType(table.getName());
1083 46518 fdiaz
1084 46517 fdiaz
        }
1085 46518 fdiaz
        if(type != null){
1086
            tables.add(new ImmutablePair<>(table,type));
1087
        }
1088 46505 fdiaz
    }
1089
1090 46517 fdiaz
    protected void addTableToColumnReferencesInSingleSelect(SQLBuilder sqlbuilder, SelectBuilder select, List<Pair<SQLBuilder.TableNameBuilder,FeatureType>> outerTables) {
1091 46505 fdiaz
1092 46542 fdiaz
        final SQLBuilder.TableNameBuilder fromTable = select.from().table();
1093 46505 fdiaz
1094
        final List<ExpressionBuilder.Value[]> value_replacements = new ArrayList<>();
1095
        List<ExpressionBuilder.Variable> variables = new ArrayList<>();
1096 46518 fdiaz
//        List<ExpressionBuilder.Value> variablesToExclude = new ArrayList<>();
1097 46505 fdiaz
1098
        select.accept((ExpressionBuilder.Visitable value) -> {
1099 46517 fdiaz
            if(value instanceof Column) {
1100 46505 fdiaz
                Column c = (Column)value;
1101 46518 fdiaz
                if(c.table() == null || !c.table().has_name() || !c.table().has_schema()){
1102 46505 fdiaz
                    variables.add(c);
1103
                }
1104
1105
            } else if(value instanceof ExpressionBuilder.Variable) {
1106
                variables.add((ExpressionBuilder.Variable) value);
1107
            }
1108
1109
        }, new ExpressionBuilder.VisitorFilter() {
1110
            @Override
1111
            public boolean skipChildren() {
1112
                return true;
1113
            }
1114
1115
            @Override
1116
            public boolean accept(ExpressionBuilder.Visitable visitable) {
1117
                if(select == visitable){
1118
                    return true;
1119
                }
1120
                if(visitable instanceof SelectBuilder) {
1121 46517 fdiaz
                    ArrayList<Pair<SQLBuilder.TableNameBuilder, FeatureType>> tables = new ArrayList<>(outerTables);
1122 46542 fdiaz
                    collectTablesFromSelect((SelectBuilder) visitable, tables, null);
1123 46517 fdiaz
1124
                    addTableToColumnReferencesInSingleSelect(sqlbuilder, (SelectBuilder) visitable, tables);
1125 46505 fdiaz
                    return false;
1126
                }
1127
                return true;
1128
            }
1129
        });
1130
1131
        for (ExpressionBuilder.Variable variable : variables) {
1132 46542 fdiaz
            ExpressionBuilder.Variable variable_replacement = null;
1133
1134 46543 fdiaz
            Pair<SQLBuilder.TableNameBuilder, FeatureType> tableNameAndFeatureType = getTableAndFeatureType(outerTables, variable.name());
1135
            if (tableNameAndFeatureType != null) {
1136
                SQLBuilder.TableNameBuilder variableTable = tableNameAndFeatureType.getLeft();
1137 46542 fdiaz
1138 46543 fdiaz
                if (variable instanceof SQLBuilder.Column) {
1139
                    Column column = (SQLBuilder.Column) variable;
1140
                    if (column.table() != null && column.table().has_name()) {
1141
                        if (column.table().has_schema()) {
1142
                            //La columna tiene tabla y esquema => No hacemos nada
1143
                        } else {
1144
                            if(column.table().getName().equals(variableTable.getName())){
1145
                                SQLBuilder.TableNameBuilder t = sqlbuilder.createTableNameBuilder()
1146
                                        .name(column.table().getName())
1147
                                        .schema(variableTable.getSchema());
1148
                                variable_replacement = sqlbuilder.column_from(
1149
                                        t,
1150
                                        variable
1151
                                );
1152
                            } else {
1153
                                if(fromTable.has_schema()){
1154
                                    SQLBuilder.TableNameBuilder t = sqlbuilder.createTableNameBuilder()
1155
                                            .name(column.table().getName())
1156
                                            .schema(fromTable.getSchema()); //Mismo esquema que en el FROM
1157
                                    variable_replacement = sqlbuilder.column_from(
1158
                                            t,
1159
                                            variable
1160
                                    );
1161
                                } else {
1162
                                    // No tiene esquema ni podemos averiguarlo => No hacemos nada
1163
                                }
1164
                            }
1165
                        }
1166
                    } else {
1167
                        column = sqlbuilder.column_from(tableNameAndFeatureType.getLeft(), variable);
1168
                        column.setProperty(SQLBuilder.PROP_FEATURE_TYPE, tableNameAndFeatureType.getRight());
1169
                        variable_replacement = column;
1170 46542 fdiaz
                    }
1171 46543 fdiaz
                } else {
1172 46542 fdiaz
                    Column column = sqlbuilder.column_from(tableNameAndFeatureType.getLeft(), variable);
1173
                    column.setProperty(SQLBuilder.PROP_FEATURE_TYPE, tableNameAndFeatureType.getRight());
1174
                    variable_replacement = column;
1175 46543 fdiaz
                }
1176
1177
            } else {
1178
                if (variable instanceof SQLBuilder.Column) {
1179
                    Column column = (SQLBuilder.Column) variable;
1180
                    if (column.table() == null || !column.table().has_name()) {
1181
                        variable_replacement = sqlbuilder.column_from(
1182
                                fromTable,
1183
                                variable
1184
                        );
1185
                    } else if (!column.table().has_schema()) {
1186
                        if(fromTable.has_schema()){
1187
                            SQLBuilder.TableNameBuilder t = sqlbuilder.createTableNameBuilder()
1188 46542 fdiaz
                                    .name(column.table().getName())
1189
                                    .schema(fromTable.getSchema()); //Mismo esquema que en el FROM
1190
                            variable_replacement = sqlbuilder.column_from(
1191
                                    t,
1192
                                    variable
1193
                            );
1194 46543 fdiaz
                        } else {
1195
                            // No tiene esquema ni podemos averiguarlo => No hacemos nada
1196 46505 fdiaz
                        }
1197
                    }
1198 46543 fdiaz
                } else {
1199 47118 jjdelcerro
                    if( StringUtils.equals(fromTable.getName(), variable.name()) ) {
1200
                        LOGGER.debug("Uff, la variable coincide con el nombre de la tabla...\nNo esta nada claro que haya que ponerle el prefijo,\nde momento no hacemos nada.");
1201
                    } else {
1202
                        variable_replacement = sqlbuilder.column_from(
1203
                                fromTable,
1204
                                variable
1205
                        );
1206
                    }
1207 46505 fdiaz
                }
1208
            }
1209 46542 fdiaz
            if(variable_replacement != null){
1210
                value_replacements.add(
1211
                        new ExpressionBuilder.Value[]{
1212
                            variable,
1213
                            variable_replacement
1214
                        }
1215
                );
1216
            }
1217 46505 fdiaz
1218
        }
1219
1220
        for (ExpressionBuilder.Value[] replaceValue : value_replacements) {
1221
            ExpressionBuilder.Value target = replaceValue[0];
1222
            ExpressionBuilder.Value replacement = replaceValue[1];
1223 46518 fdiaz
            Boolean addTableName = (Boolean) target.getProperty(PROP_ADD_TABLE_NAME_TO_COLUMNS);
1224 46507 jjdelcerro
            if(addTableName == null || !addTableName){
1225 46505 fdiaz
                continue;
1226
            }
1227
            select.replace(target, replacement);
1228
        }
1229
1230
    }
1231
1232 46518 fdiaz
    protected Pair<SQLBuilder.TableNameBuilder, FeatureType> getTableAndFeatureType(List<Pair<SQLBuilder.TableNameBuilder, FeatureType>> outerTables, String columnName) {
1233 46542 fdiaz
//        ListIterator<Pair<SQLBuilder.TableNameBuilder, FeatureType>> it = outerTables.listIterator(outerTables.size());
1234
//
1235
//        while (it.hasPrevious()) {
1236
//            Pair<SQLBuilder.TableNameBuilder, FeatureType> pair = it.previous();
1237
//            FeatureType featureType = pair.getRight();
1238
//            if(featureType.get(columnName) != null){
1239
//                return pair;
1240
//            }
1241
//        }
1242
1243
//        ListIterator<Pair<SQLBuilder.TableNameBuilder, FeatureType>> it = new ReverseListIterator(outerTables);
1244
//        while (it.hasNext()) {
1245
//            Pair<SQLBuilder.TableNameBuilder, FeatureType> pair = it.next();
1246
//            FeatureType featureType = pair.getRight();
1247
//            if(featureType.get(columnName) != null){
1248
//                return pair;
1249
//            }
1250
//        }
1251
1252
        for (Iterator<Pair<SQLBuilder.TableNameBuilder, FeatureType>> iterator = new ReverseListIterator(outerTables); iterator.hasNext();) {
1253
            Pair<SQLBuilder.TableNameBuilder, FeatureType> pair = iterator.next();
1254 46517 fdiaz
            FeatureType featureType = pair.getRight();
1255
            if(featureType.get(columnName) != null){
1256 46518 fdiaz
                return pair;
1257 46505 fdiaz
            }
1258
        }
1259 46542 fdiaz
1260 46505 fdiaz
        return null;
1261
    }
1262
1263 45650 jjdelcerro
    @Override
1264
    public void setTransaction(DataTransactionServices transaction) {
1265 47611 fdiaz
        this.transactionsHelper.setTransaction(transaction);
1266 45650 jjdelcerro
    }
1267 45717 fdiaz
1268
    @Override
1269
    public String toString() {
1270
        try {
1271 47198 jjdelcerro
            ToStringBuilder builder = new ToStringBuilder(this);
1272
            builder.append("hash", String.format("%x", this.hashCode()));
1273
            builder.append("url", this.connectionParameters.getUrl());
1274
            return builder.toString();
1275 45717 fdiaz
        } catch (Exception e) {
1276
            return super.toString();
1277
        }
1278
    }
1279
1280 46302 jjdelcerro
  @Override
1281 45736 fdiaz
    public String getConnectionProviderStatus() {
1282
        return "";
1283
    }
1284 46104 omartinez
1285 46302 jjdelcerro
  @Override
1286 46104 omartinez
        public void expandCalculedColumns(JDBCSQLBuilderBase sqlbuilder) {
1287 46221 omartinez
            ComputedAttribute computedAttributeFormater = new ComputedAttribute(sqlbuilder, sqlbuilder.formatter());
1288
            for (int i = 0; i < 10; i++) {
1289 46505 fdiaz
                List<Pair<ExpressionBuilder.Variable, ExpressionBuilder.Value>> variablesToReplace = new ArrayList<>();
1290
                sqlbuilder.accept((ExpressionBuilder.Visitable value) -> {
1291
                    if (computedAttributeFormater.canApply((ExpressionBuilder.Value) value)) {
1292
                        ExpressionBuilder.Variable variable = (ExpressionBuilder.Variable) value;
1293
                        ExpressionBuilder.Value replace = computedAttributeFormater.expandedValue(variable);
1294
                        variablesToReplace.add(Pair.of(variable, replace));
1295 46221 omartinez
                    }
1296
                }, null);
1297
                if (variablesToReplace.isEmpty()) {
1298
                    break;
1299
                }
1300 46505 fdiaz
                for (Pair<ExpressionBuilder.Variable, ExpressionBuilder.Value> entry : variablesToReplace) {
1301 46221 omartinez
                    ExpressionBuilder.Value variable = entry.getKey();
1302
                    ExpressionBuilder.Value replace = entry.getValue();
1303 46518 fdiaz
                    Boolean addTableName = (Boolean) variable.getProperty(PROP_ADD_TABLE_NAME_TO_COLUMNS);
1304 46507 jjdelcerro
                    if (addTableName != null && addTableName) {
1305 46518 fdiaz
                        sqlbuilder.setProperties(replace, null, PROP_ADD_TABLE_NAME_TO_COLUMNS,true);
1306 46505 fdiaz
                    }
1307 46221 omartinez
                    sqlbuilder.select().replace(variable, replace);
1308
                }
1309
            }
1310
    }
1311 46315 jjdelcerro
1312
    @Override
1313
    public DataTransactionServices getTransaction() {
1314 47611 fdiaz
        return (DataTransactionServices) this.transactionsHelper.getTransaction();
1315 46315 jjdelcerro
    }
1316 46104 omartinez
1317 46361 jjdelcerro
    public ConnectionProvider getConnectionProvider() {
1318
        return new FakeConnectionProvider(connectionParameters);
1319
    }
1320 47106 jjdelcerro
1321
    protected String getConnectionProviderKey(JDBCConnectionParameters connectionParameters) {
1322
        String pass = Hex.encodeHexString((connectionParameters.getPassword()+"").getBytes());
1323
//        String pass = connectionParameters.getPassword();
1324
        return connectionParameters.getUrl() + ";user:"+connectionParameters.getUser()+"@"+pass;
1325
    }
1326
1327 43020 jjdelcerro
}