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

History | View | Annotate | Download (30.7 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.Connection;
30
import java.sql.ResultSet;
31 44376 jjdelcerro
import java.util.ArrayList;
32 45162 omartinez
import java.util.HashSet;
33 44376 jjdelcerro
import java.util.List;
34 45008 omartinez
import org.apache.commons.io.IOUtils;
35 44376 jjdelcerro
import org.apache.commons.lang3.ArrayUtils;
36 43020 jjdelcerro
import org.apache.commons.lang3.StringUtils;
37 44191 jjdelcerro
import org.apache.commons.lang3.mutable.MutableBoolean;
38
import org.gvsig.expressionevaluator.Code;
39 44376 jjdelcerro
import org.gvsig.expressionevaluator.ExpressionBuilder;
40 44191 jjdelcerro
import org.gvsig.expressionevaluator.ExpressionEvaluatorLocator;
41
import org.gvsig.expressionevaluator.ExpressionEvaluatorManager;
42
import org.gvsig.expressionevaluator.Function;
43 44644 jjdelcerro
import org.gvsig.expressionevaluator.GeometryExpressionBuilderHelper.GeometrySupportType;
44 44198 jjdelcerro
import org.gvsig.expressionevaluator.SymbolTable;
45 44750 jjdelcerro
import static org.gvsig.fmap.dal.DataManager.FUNCTION_EXISTS;
46
import static org.gvsig.fmap.dal.DataManager.FUNCTION_FOREING_VALUE;
47 43020 jjdelcerro
import org.gvsig.fmap.dal.DataTypes;
48 44376 jjdelcerro
import org.gvsig.fmap.dal.SQLBuilder;
49 43020 jjdelcerro
import org.gvsig.fmap.dal.exception.DataException;
50
import org.gvsig.fmap.dal.exception.InitializeException;
51
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
52 44191 jjdelcerro
import org.gvsig.fmap.dal.feature.FeatureQueryOrder;
53 43020 jjdelcerro
import org.gvsig.fmap.dal.feature.FeatureType;
54 44376 jjdelcerro
import org.gvsig.fmap.dal.feature.ForeingKey;
55 43020 jjdelcerro
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
56 44376 jjdelcerro
import org.gvsig.fmap.dal.feature.spi.SQLBuilderBase;
57 43020 jjdelcerro
import org.gvsig.fmap.dal.resource.exception.AccessResourceException;
58
import org.gvsig.fmap.dal.resource.spi.ResourceConsumer;
59
import org.gvsig.fmap.dal.resource.spi.ResourceProvider;
60 45165 jjdelcerro
import org.gvsig.fmap.dal.serverexplorer.filesystem.FilesystemStoreParameters;
61 43020 jjdelcerro
import org.gvsig.fmap.dal.spi.DataServerExplorerProviderServices;
62
import org.gvsig.fmap.dal.spi.DataStoreProviderServices;
63
import org.gvsig.fmap.dal.store.db.DBHelper;
64
import org.gvsig.fmap.dal.store.jdbc.JDBCConnectionParameters;
65
import org.gvsig.fmap.dal.store.jdbc.JDBCLibrary;
66
import org.gvsig.fmap.dal.store.jdbc.JDBCNewStoreParameters;
67
import org.gvsig.fmap.dal.store.jdbc.JDBCResource;
68
import org.gvsig.fmap.dal.store.jdbc.JDBCServerExplorerParameters;
69
import org.gvsig.fmap.dal.store.jdbc.JDBCStoreParameters;
70
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCCantFetchValueException;
71
import org.gvsig.fmap.dal.store.jdbc2.JDBCHelper;
72
import org.gvsig.fmap.dal.store.jdbc2.JDBCServerExplorer;
73
import org.gvsig.fmap.dal.store.jdbc2.JDBCStoreProvider;
74
import org.gvsig.fmap.dal.store.jdbc2.JDBCUtils;
75
import org.gvsig.fmap.dal.store.jdbc2.OperationsFactory;
76
import org.gvsig.fmap.dal.store.jdbc2.ResulSetControler;
77
import org.gvsig.fmap.dal.store.jdbc2.ResulSetControler.ResultSetEntry;
78 45481 fdiaz
import org.gvsig.fmap.dal.store.jdbc2.impl.ResulSetControlerBase;
79
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.OperationsFactoryBase;
80 43020 jjdelcerro
import org.gvsig.fmap.geom.Geometry;
81
import org.gvsig.fmap.geom.GeometryLocator;
82
import org.gvsig.fmap.geom.GeometryManager;
83
import org.gvsig.tools.dispose.impl.AbstractDisposable;
84 44191 jjdelcerro
import org.gvsig.tools.evaluator.Evaluator;
85 43020 jjdelcerro
import org.gvsig.tools.exception.BaseException;
86 43377 jjdelcerro
import org.gvsig.tools.exception.NotYetImplemented;
87 44191 jjdelcerro
import org.gvsig.tools.visitor.VisitCanceledException;
88
import org.gvsig.tools.visitor.Visitor;
89 43020 jjdelcerro
import org.slf4j.Logger;
90
import org.slf4j.LoggerFactory;
91
92 44191 jjdelcerro
@SuppressWarnings("UseSpecificCatch")
93 43020 jjdelcerro
public class JDBCHelperBase extends AbstractDisposable implements ResourceConsumer, JDBCHelper {
94
95 44750 jjdelcerro
  private static final boolean ALLOW_AUTOMATIC_VALUES = true;
96
  private static final String QUOTE_FOR_USE_IN_IDENTIFIERS = "\"";
97
  private static final String QUOTE_FOR_USE_IN_STRINGS = "'";
98 43020 jjdelcerro
99 44750 jjdelcerro
  private static final Logger LOGGER = LoggerFactory.getLogger(JDBCHelperBase.class);
100 43020 jjdelcerro
101 44750 jjdelcerro
  private ResulSetControler resulSetControler = null;
102 43020 jjdelcerro
103 44750 jjdelcerro
  // Quien ha creado este helper.
104
  // Se le reenviaran las notificaciones del recurso asociado al helper.
105
  private ResourceConsumer helperClient = null;
106 43020 jjdelcerro
107 44750 jjdelcerro
  private GeometryManager geometryManager = null;
108 43020 jjdelcerro
109 44750 jjdelcerro
  private JDBCConnectionParameters connectionParameters;
110 43020 jjdelcerro
111 44750 jjdelcerro
  private JDBCStoreProvider store;
112 44403 omartinez
113 44750 jjdelcerro
  protected OperationsFactory operationsFactory = null;
114 44403 omartinez
115 44750 jjdelcerro
  protected SRSSolver srssolver;
116 45152 fdiaz
117
  protected FeatureType providerFeatureType = null;
118 44403 omartinez
119 44750 jjdelcerro
  public JDBCHelperBase(JDBCConnectionParameters connectionParameters) {
120 45647 fdiaz
        if (connectionParameters == null) {
121
            throw new IllegalArgumentException("Connection parameters can't be null.");
122
        }
123
        this.connectionParameters = connectionParameters;
124 44403 omartinez
125 45647 fdiaz
        // If a particular treatment is required to convert SRS to the
126
        // BBDD format, overwrite JDBCSRSsBase and use it instead of JDBCSRSsDumb.
127
        this.srssolver = new SRSSolverDumb(this);
128
    }
129 43020 jjdelcerro
130 44750 jjdelcerro
  protected void initialize(
131
          ResourceConsumer helperClient,
132
          JDBCConnectionParameters connectionParameters,
133
          JDBCStoreProvider store
134
  ) {
135
    this.store = store;
136
    this.helperClient = helperClient;
137
    this.connectionParameters = connectionParameters;
138
    initializeResource(connectionParameters);
139
  }
140 44403 omartinez
141 44750 jjdelcerro
  protected String getResourceType() {
142
    return JDBCResource.NAME;
143
  }
144 43020 jjdelcerro
145 44750 jjdelcerro
  @Override
146
  public String getProviderName() {
147
    return JDBCLibrary.NAME;
148
  }
149 44403 omartinez
150 44750 jjdelcerro
  @Override
151
  public GeometrySupportType getGeometrySupportType() {
152
    // El proveedor generico de JDBC guadara las geoemtrias como WKT
153
    return GeometrySupportType.WKT;
154
  }
155 45152 fdiaz
156
    /**
157
     * @return the providerFeatureType
158
     */
159
  @Override
160
    public FeatureType getProviderFeatureType() {
161
        return providerFeatureType;
162
    }
163 43020 jjdelcerro
164 45152 fdiaz
    /**
165
     * @param providerFeatureType the providerFeatureType to set
166
     */
167 44750 jjdelcerro
  @Override
168 45152 fdiaz
    public void setProviderFeatureType(FeatureType providerFeatureType) {
169
        this.providerFeatureType = providerFeatureType;
170
    }
171
172
173
  @Override
174 44750 jjdelcerro
  public boolean hasSpatialFunctions() {
175
    // Por defecto el proveedor generico de JDBC asume que la BBDD no
176
    // tiene soporte para funciones espaciales.
177
    return false;
178
  }
179 43020 jjdelcerro
180 44750 jjdelcerro
  @Override
181
  public boolean allowNestedOperations() {
182
    return false;
183
  }
184 44403 omartinez
185 44750 jjdelcerro
  @Override
186
  public boolean canWriteGeometry(int geometryType, int geometrySubtype) {
187
    // Como va a guardar las geometrias en WKT, puede escribirlas todas.
188
    return true;
189
  }
190 43020 jjdelcerro
191 44750 jjdelcerro
  @Override
192
  public JDBCSQLBuilderBase createSQLBuilder() {
193
    return new JDBCSQLBuilderBase(this);
194
  }
195 43020 jjdelcerro
196 44750 jjdelcerro
  @Override
197
  public String getQuoteForIdentifiers() {
198
    return QUOTE_FOR_USE_IN_IDENTIFIERS;
199
  }
200 43020 jjdelcerro
201 44750 jjdelcerro
  @Override
202
  public boolean allowAutomaticValues() {
203
    return ALLOW_AUTOMATIC_VALUES;
204
  }
205 43020 jjdelcerro
206 44750 jjdelcerro
  @Override
207
  public boolean supportOffsetInSelect() {
208
    // Asumimos que la BBDD soporta OFFSET
209
    return true;
210
  }
211 44403 omartinez
212 44750 jjdelcerro
  @Override
213
  public String getQuoteForStrings() {
214
    return QUOTE_FOR_USE_IN_STRINGS;
215
  }
216 44191 jjdelcerro
217 44752 jjdelcerro
  protected boolean supportCaller(Code.Callable caller) {
218 44750 jjdelcerro
    if (StringUtils.equalsIgnoreCase(caller.name(), "FOREING_VALUE")) {
219
      return true;
220 44376 jjdelcerro
    }
221 44750 jjdelcerro
    Function function = caller.function();
222
    if (function == null) {
223
      return false;
224
    }
225
    if (!function.isSQLCompatible()) {
226
      return false;
227
    }
228
    if (!this.hasSpatialFunctions()) {
229
      if (StringUtils.equalsIgnoreCase(function.group(), Function.GROUP_OGC)) {
230
        return false;
231
      }
232
    }
233
    return true;
234
  }
235 44403 omartinez
236 44750 jjdelcerro
  @Override
237
  public boolean supportFilter(final FeatureType type, Evaluator filter) {
238
    // No podemos filtrar cuando:
239
    // - Hay una subquery especificada en los parametros
240
    // - Si hay un filtro y el getSQL devuelbe null.
241
    // - Si se esta usando alguna funcion no-sql en el getSQL
242
    // - Si se estan usando funciones OGC y no soportamos funciones espaciales
243
    // - Si se esta usando algun campo calculado en la expresion de filtro.
244
    //
245
    // Un proveedor especifico podria sobreescribir el metodo,
246
    // para hilar mas fino al comprobar si soporta el filtro o no.
247
    //
248 44403 omartinez
249 44750 jjdelcerro
    if (this.useSubquery()) {
250
      // Se esta usando una subquery en los parametros de acceso a la
251
      // BBDD, asi que no podemos filtrar.
252
      return false;
253
    }
254
    if (filter == null) {
255
      // No hay que filtrar nada, asi que se p?ede.
256
      return true;
257
    }
258
    String sql = filter.getSQL();
259
    if (StringUtils.isEmpty(sql)) {
260
      // Hay un filtro, pero la SQL es null, con lo que no podemos
261
      // filtrar por el.
262
      return false;
263
    }
264 44191 jjdelcerro
265 44750 jjdelcerro
    // Ahora vamos a comprobar que las funciones que se usan son
266
    // compatibles sql, y que no se usan funciones OGC si el
267
    // proveedor dice que no soporta funciones espaciales.
268
    // Tambien comprobaremos que el filtro no usa ningun campo calculado.
269
    final MutableBoolean isCompatible = new MutableBoolean(true);
270
    ExpressionEvaluatorManager manager = ExpressionEvaluatorLocator.getManager();
271
    Code code = manager.compile(sql);
272
    SymbolTable symbolTable = manager.createSymbolTable();
273
    code.link(symbolTable);
274
    try {
275
      code.accept(new Visitor() {
276
        @Override
277
        public void visit(Object code_obj) throws VisitCanceledException, BaseException {
278
          Code code = (Code) code_obj;
279
          switch (code.code()) {
280 44752 jjdelcerro
            case Code.CALLABLE:
281
              Code.Callable caller = (Code.Callable) code;
282 44750 jjdelcerro
              if (!supportCaller(caller)) {
283
                isCompatible.setValue(false);
284
                throw new VisitCanceledException();
285
              }
286
              break;
287 44403 omartinez
288 44750 jjdelcerro
            case Code.IDENTIFIER:
289
              Code.Identifier identifier = (Code.Identifier) code;
290
              if (type != null) {
291
                FeatureAttributeDescriptor attrdesc = type.getAttributeDescriptor(identifier.name());
292
                if (attrdesc != null) {
293
                  if (attrdesc.isComputed()) {
294
                    isCompatible.setValue(false);
295
                    throw new VisitCanceledException();
296
                  }
297 44191 jjdelcerro
                }
298 44750 jjdelcerro
              }
299
              break;
300
          }
301 44191 jjdelcerro
        }
302 44750 jjdelcerro
      });
303 44403 omartinez
304 44750 jjdelcerro
    } catch (VisitCanceledException ex) {
305
      // Do nothing
306
    } catch (Exception ex) {
307
      LOGGER.warn("Can't calculate if is SQL compatible.", ex);
308 44191 jjdelcerro
    }
309 44403 omartinez
310 44750 jjdelcerro
    return isCompatible.booleanValue();
311
  }
312
313
  @Override
314
  public boolean supportOrder(FeatureType type, FeatureQueryOrder order) {
315
    if (this.useSubquery()) {
316
      return false;
317
    }
318
    if (order == null) {
319
      return true;
320
    }
321
    for (FeatureQueryOrder.FeatureQueryOrderMember member : order.members()) {
322
      if (member.hasEvaluator()) {
323
        if (!this.supportFilter(type, member.getEvaluator())) {
324
          return false;
325 44191 jjdelcerro
        }
326 44750 jjdelcerro
      }
327 44191 jjdelcerro
    }
328 44750 jjdelcerro
    return true;
329
  }
330 44403 omartinez
331 44750 jjdelcerro
  @Override
332
  public OperationsFactory getOperations() {
333 45481 fdiaz
    if (this.operationsFactory == null && !isClosed()) {
334 44750 jjdelcerro
      this.operationsFactory = new OperationsFactoryBase(this);
335 43020 jjdelcerro
    }
336 44750 jjdelcerro
    return operationsFactory;
337
  }
338 44403 omartinez
339 44750 jjdelcerro
  protected void initializeResource(JDBCConnectionParameters params) {
340 43020 jjdelcerro
//        Object[] resourceParams = new Object[]{
341
//            params.getUrl(),
342
//            params.getHost(),
343
//            params.getPort(),
344
//            params.getDBName(),
345
//            params.getUser(),
346
//            params.getPassword(),
347
//            params.getJDBCDriverClassName()
348
//        };
349
//
350
//        try {
351
//            ResourceManagerProviderServices manager
352
//                    = (ResourceManagerProviderServices) DALLocator.getResourceManager();
353
//            JDBCResource resource = (JDBCResource) manager.createAddResource(
354
//                    this.getResourceType(),
355
//                    resourceParams
356
//            );
357
//            this.resource = resource;
358
//            this.resource.addConsumer(this);
359
//        } catch (InitializeException ex) {
360 44750 jjdelcerro
//            logger.trace("Can't initialize resource (" + ArrayUtils.toString(resourceParams) + ").", ex);
361 43020 jjdelcerro
//            throw new RuntimeException("Can't initialize resource (" + ArrayUtils.toString(resourceParams) + ").", ex);
362
//        }
363
364 44750 jjdelcerro
  }
365 43020 jjdelcerro
366 44750 jjdelcerro
  @Override
367
  public String getSourceId() {
368
    return this.store.getSourceId();
369
  }
370 44403 omartinez
371 44750 jjdelcerro
  @Override
372
  public JDBCResource getResource() {
373
    return null;
374 43020 jjdelcerro
//        return this.resource;
375 44750 jjdelcerro
  }
376 43020 jjdelcerro
377 44750 jjdelcerro
  @Override
378
  public Connection getConnection() throws AccessResourceException {
379
    throw new NotYetImplemented();
380
  }
381 43020 jjdelcerro
382 44750 jjdelcerro
  @Override
383
  public Connection getConnectionWritable() throws AccessResourceException {
384
    return this.getConnection();
385
  }
386 43377 jjdelcerro
387 44750 jjdelcerro
  @Override
388
  public String getConnectionURL() {
389
    return null;
390
  }
391 43035 jjdelcerro
392 44750 jjdelcerro
  @Override
393
  public JDBCConnectionParameters getConnectionParameters() {
394
    return connectionParameters;
395
  }
396 43035 jjdelcerro
397 44750 jjdelcerro
  @Override
398
  public void closeConnection(Connection connection) {
399 45097 jjdelcerro
      JDBCUtils.close(connection);
400 44750 jjdelcerro
  }
401 44191 jjdelcerro
402 44750 jjdelcerro
  @Override
403
  public void closeConnectionQuietly(Connection connection) {
404 45097 jjdelcerro
      JDBCUtils.closeQuietly(connection);
405 44750 jjdelcerro
  }
406 44403 omartinez
407 44750 jjdelcerro
  @Override
408
  protected void doDispose() throws BaseException {
409
    JDBCUtils.closeQuietly(this);
410
  }
411 43020 jjdelcerro
412 44750 jjdelcerro
  @Override
413
  public void close() throws Exception {
414
    JDBCUtils.closeQuietly(this.resulSetControler);
415
    this.resulSetControler = null;
416 45481 fdiaz
    this.operationsFactory = null;
417
    this.srssolver = null;
418
    this.connectionParameters = null;
419
    this.helperClient = null;
420
    this.geometryManager = null;
421
    this.providerFeatureType = null;
422
    this.store = null;
423 44750 jjdelcerro
  }
424 45481 fdiaz
425
  public boolean isClosed() {
426
      return this.srssolver == null;
427
  }
428 43020 jjdelcerro
429 44750 jjdelcerro
  @Override
430
  public boolean closeResourceRequested(ResourceProvider resource) {
431
    return this.helperClient.closeResourceRequested(resource);
432
  }
433 43020 jjdelcerro
434 44750 jjdelcerro
  @Override
435
  public void resourceChanged(ResourceProvider resource) {
436
    this.helperClient.resourceChanged(resource);
437
  }
438 43020 jjdelcerro
439 44750 jjdelcerro
  @Override
440
  public GeometryManager getGeometryManager() {
441
    if (this.geometryManager == null) {
442
      this.geometryManager = GeometryLocator.getGeometryManager();
443 43020 jjdelcerro
    }
444 44750 jjdelcerro
    return this.geometryManager;
445
  }
446 43020 jjdelcerro
447 44750 jjdelcerro
  @Override
448
  public ResulSetControler getResulSetControler() {
449
    if (this.resulSetControler == null) {
450
      this.resulSetControler = new ResulSetControlerBase(this);
451 43020 jjdelcerro
    }
452 44750 jjdelcerro
    return this.resulSetControler;
453
  }
454 43020 jjdelcerro
455 44750 jjdelcerro
  @Override
456
  public void fetchFeature(FeatureProvider feature, ResultSetEntry rs) throws DataException {
457
    fetchFeature(feature, rs.get(), rs.getColumns(), rs.getExtraValueNames());
458
  }
459 43020 jjdelcerro
460 44750 jjdelcerro
  @Override
461
  public void fetchFeature(FeatureProvider feature, ResultSet rs, FeatureAttributeDescriptor[] columns, String[] extraValueNames) throws DataException {
462
    Object value;
463
    try {
464
      int rsIndex = 1;
465
      for (FeatureAttributeDescriptor column : columns) {
466
        switch (column.getType()) {
467
          case DataTypes.GEOMETRY:
468
            value = this.getGeometryFromColumn(rs, rsIndex++);
469
            break;
470
          default:
471
            value = rs.getObject(rsIndex++);
472
            if (value instanceof Blob) {
473
              Blob blob = (Blob) value;
474 45152 fdiaz
              value = blob.getBytes(1, (int) blob.length());
475 44750 jjdelcerro
              blob.free();
476 45008 omartinez
            } else if(value instanceof Clob) {
477
              Clob clob = (Clob) value;
478
              value = new String(IOUtils.toCharArray(clob.getCharacterStream()));
479
              clob.free();
480
          }
481 43020 jjdelcerro
        }
482 44750 jjdelcerro
        feature.set(column.getIndex(), value);
483
      }
484
      if (ArrayUtils.isNotEmpty(extraValueNames)) {
485
        feature.setExtraValueNames(extraValueNames);
486
        for (int index = 0; index < extraValueNames.length; index++) {
487
          value = rs.getObject(rsIndex++);
488
          if (value instanceof Blob) {
489
            Blob blob = (Blob) value;
490
            value = blob.getBytes(0, (int) blob.length());
491
            blob.free();
492
          }
493
          feature.setExtraValue(index, value);
494
        }
495
      }
496
    } catch (Exception ex) {
497
      throw new JDBCCantFetchValueException(ex);
498 43020 jjdelcerro
    }
499 44750 jjdelcerro
  }
500 43020 jjdelcerro
501 44750 jjdelcerro
  @Override
502
  public Geometry getGeometryFromColumn(ResultSetEntry rs, int index) throws DataException {
503
    return getGeometryFromColumn(rs.get(), index);
504
  }
505 43020 jjdelcerro
506 44750 jjdelcerro
  @Override
507
  public Geometry getGeometryFromColumn(ResultSet rs, int index) throws DataException {
508
    try {
509
      Object value;
510
      switch (this.getGeometrySupportType()) {
511
        case NATIVE:
512
        case WKB:
513
          value = rs.getBytes(index);
514
          if (value == null) {
515
            return null;
516
          }
517
          return this.getGeometryManager().createFrom((byte[]) value);
518 43020 jjdelcerro
519 44750 jjdelcerro
        case EWKB:
520
          value = rs.getBytes(index);
521
          if (value == null) {
522
            return null;
523
          }
524
          return this.getGeometryManager().createFrom((byte[]) value);
525
        case WKT:
526
        default:
527
          value = rs.getString(index);
528
          if (value == null) {
529
            return null;
530
          }
531
          return this.getGeometryManager().createFrom((String) value);
532 43020 jjdelcerro
533 44750 jjdelcerro
      }
534
    } catch (Exception ex) {
535
      throw new JDBCCantFetchValueException(ex);
536 43020 jjdelcerro
    }
537 44750 jjdelcerro
  }
538 43020 jjdelcerro
539 44750 jjdelcerro
  @Override
540
  public FeatureProvider createFeature(FeatureType featureType) throws DataException {
541
    return this.store.getStoreServices().createDefaultFeatureProvider(featureType);
542
  }
543 44403 omartinez
544 44750 jjdelcerro
  @Override
545
  public boolean useSubquery() {
546
    if (this.store == null) {
547
      return false;
548 44403 omartinez
    }
549 44750 jjdelcerro
    return !StringUtils.isEmpty(this.store.getParameters().getSQL());
550
  }
551 44403 omartinez
552 44750 jjdelcerro
  @Override
553
  public SRSSolver getSRSSolver() {
554
    return this.srssolver;
555
  }
556 44403 omartinez
557 44750 jjdelcerro
  @Override
558
  public JDBCStoreProvider createProvider(
559
          JDBCStoreParameters parameters,
560
          DataStoreProviderServices providerServices
561
  ) throws InitializeException {
562 44403 omartinez
563 44750 jjdelcerro
    JDBCStoreProviderBase theStore = new JDBCStoreProviderBase(
564
            parameters,
565
            providerServices,
566
            DBHelper.newMetadataContainer(JDBCLibrary.NAME),
567
            this
568
    );
569
    this.initialize(theStore, parameters, theStore);
570
    return theStore;
571
  }
572 43020 jjdelcerro
573 44750 jjdelcerro
  @Override
574
  public JDBCServerExplorer createServerExplorer(
575
          JDBCServerExplorerParameters parameters,
576
          DataServerExplorerProviderServices providerServices
577
  ) throws InitializeException {
578 44403 omartinez
579 44750 jjdelcerro
    JDBCServerExplorer explorer = new JDBCServerExplorerBase(
580
            parameters,
581
            providerServices,
582
            this
583
    );
584
    this.initialize(explorer, parameters, null);
585
    return explorer;
586
  }
587 43020 jjdelcerro
588 44750 jjdelcerro
  @Override
589
  public JDBCNewStoreParameters createNewStoreParameters() {
590
    return new JDBCNewStoreParameters();
591
  }
592 43020 jjdelcerro
593 44750 jjdelcerro
  @Override
594
  public JDBCStoreParameters createOpenStoreParameters() {
595
    return new JDBCStoreParameters();
596
  }
597 45165 jjdelcerro
598
  @Override
599
  public JDBCStoreParameters createOpenStoreParameters(JDBCServerExplorerParameters parameters) {
600
    JDBCStoreParameters params = this.createOpenStoreParameters();
601
    params.setHost(parameters.getHost());
602
    params.setPort(parameters.getPort());
603
    params.setDBName(parameters.getDBName());
604
    params.setUser(parameters.getUser());
605
    params.setPassword(parameters.getPassword());
606
    params.setCatalog(parameters.getCatalog());
607
    params.setSchema(parameters.getSchema());
608
    params.setJDBCDriverClassName(parameters.getJDBCDriverClassName());
609
    params.setUrl(parameters.getUrl());
610
    if( parameters instanceof FilesystemStoreParameters ) {
611
        File f = ((FilesystemStoreParameters) parameters).getFile();
612
        ((FilesystemStoreParameters) params).setFile(f);
613
    }
614
    return params;
615
  }
616
617 43020 jjdelcerro
618 44750 jjdelcerro
  @Override
619
  public JDBCServerExplorerParameters createServerExplorerParameters() {
620
    return new JDBCServerExplorerParameters();
621
  }
622 43020 jjdelcerro
623 44750 jjdelcerro
  @Override
624
  public String getSourceId(JDBCStoreParameters parameters) {
625
    return parameters.getHost() + ":"
626
            + parameters.getDBName() + ":"
627
            + parameters.getSchema() + ":"
628
            + parameters.tableID();
629
  }
630 44198 jjdelcerro
631 44750 jjdelcerro
  @Override
632
  public boolean isThreadSafe() {
633
    return true;
634
  }
635
636 45131 fdiaz
  /**
637
   * This method has been overriden in Oracle provider
638
   *
639
   * @param sqlbuilder
640
   * @param type
641
   * @param extra_column_names
642
   */
643 44750 jjdelcerro
  @Override
644
  public void processSpecialFunctions(
645
          SQLBuilder sqlbuilder,
646
          FeatureType type,
647
          List<String> extra_column_names) {
648
    replaceForeingValueFunction(sqlbuilder, type, extra_column_names);
649
    replaceExistsFunction(sqlbuilder, type, extra_column_names);
650
  }
651
652
  private void replaceExistsFunction(
653
          SQLBuilder sqlbuilder,
654
          FeatureType type,
655
          final List<String> extra_column_names) {
656 44748 jjdelcerro
657 44750 jjdelcerro
    //  Si lse encuentra una construccion del tipo:
658
    //    SELECT ... FROM ... WHERE ... EXISTS(list, 'EXISTS_ID') ...
659
    //  se traslada a:
660
    //    SELECT ... EXISTS(list) AS EXISTS_ID FROM ... WHERE ... EXISTS(list) ...
661
    //  Y se a?ade el valor ESISTS_ID a las columnas extra a recuperar de la consulta.
662
    //
663
664
    final SQLBuilder.SelectBuilder select = sqlbuilder.select();
665
    final ExpressionBuilder where = select.where();
666 44785 jjdelcerro
    if (where == null || where.isEmpty() || select.has_group_by() ) {
667 44750 jjdelcerro
      return;
668 44748 jjdelcerro
    }
669 44750 jjdelcerro
    final List<ExpressionBuilder.Value[]> value_replacements = new ArrayList<>();
670
    where.accept(new ExpressionBuilder.Visitor() {
671
      @Override
672
      public void visit(ExpressionBuilder.Visitable value) {
673
        if (!(value instanceof ExpressionBuilder.Function)) {
674
          return;
675 44376 jjdelcerro
        }
676 44750 jjdelcerro
        ExpressionBuilder.Function function = (ExpressionBuilder.Function) value;
677
        if (!StringUtils.equalsIgnoreCase(function.name(), FUNCTION_EXISTS)) {
678
          return;
679 44682 jjdelcerro
        }
680 44750 jjdelcerro
        if (function.parameters().size() != 2) {
681
          return;
682
        }
683
        ExpressionBuilder.Value arg0 = function.parameters().get(0);
684
        ExpressionBuilder.Value arg1 = function.parameters().get(1);
685
        if (arg1 == null) {
686
          return;
687
        }
688
        String columnName = (String) ((ExpressionBuilder.Constant) arg1).value();
689
        SQLBuilder.SelectColumnBuilder column = select.column();
690
        column.value(
691
                sqlbuilder.expression().function(FUNCTION_EXISTS, arg0)
692
        );
693
        column.as(columnName);
694 45131 fdiaz
695 44750 jjdelcerro
        if( extra_column_names!=null ) {
696
          extra_column_names.add(columnName);
697
        }
698
      }
699
    }, null);
700
    if (value_replacements.isEmpty()) {
701
      return;
702
    }
703
    // Realizamos los reemplazos calculados previamente (value_replacements).
704
    for (ExpressionBuilder.Value[] replaceValue : value_replacements) {
705
      ExpressionBuilder.Value target = replaceValue[0];
706
      ExpressionBuilder.Value replacement = replaceValue[1];
707
      sqlbuilder.select().replace(target, replacement);
708
    }
709
  }
710 44376 jjdelcerro
711 45131 fdiaz
  protected void replaceForeingValueFunction(
712 44750 jjdelcerro
          SQLBuilder sqlbuilder,
713
          FeatureType type,
714
          List<String> extra_column_names) {
715
    try {
716
      // See test SQLBuilderTest->testForeingValue()
717
      final ExpressionBuilder where = sqlbuilder.select().where();
718 45155 omartinez
//      if (where == null || where.isEmpty()) {
719
//        return;
720
//      }
721 44750 jjdelcerro
      final SQLBuilder.TableNameBuilder table = sqlbuilder.select().from().table();
722
      final ExpressionBuilder expbuilder = sqlbuilder.expression();
723 44403 omartinez
724 44750 jjdelcerro
      final List<String> foreing_value_args;
725 45162 omartinez
      if (extra_column_names == null || sqlbuilder.select().has_group_by()) {
726 44750 jjdelcerro
        foreing_value_args = new ArrayList<>();
727
      } else {
728
        foreing_value_args = extra_column_names;
729
      }
730
      final List<ExpressionBuilder.Value[]> value_replacements = new ArrayList<>();
731
732
      // Buscamos las llamadas a la funcion "foreing_value" y nos quedamos
733
      // el argumento de esta asi como por que tendriamos que sustituirla
734
      // una vez hechos los left joins que toquen.
735 45155 omartinez
      sqlbuilder.select().accept(new ExpressionBuilder.Visitor() {
736 44750 jjdelcerro
        @Override
737
        public void visit(ExpressionBuilder.Visitable value) {
738
          // Requiere que sea la funcion "FOREING_VALUE con un solo
739
          // argumento que sea una constante de tipo string.
740
          if (!(value instanceof ExpressionBuilder.Function)) {
741 44682 jjdelcerro
            return;
742 44750 jjdelcerro
          }
743
          ExpressionBuilder.Function function = (ExpressionBuilder.Function) value;
744
          if (!StringUtils.equalsIgnoreCase(function.name(), FUNCTION_FOREING_VALUE)) {
745
            return;
746
          }
747
          if (function.parameters().size() != 1) {
748
            return;
749
          }
750
          ExpressionBuilder.Value arg = function.parameters().get(0);
751
          if (!(arg instanceof ExpressionBuilder.Constant)) {
752
            return;
753
          }
754
          Object arg_value = ((ExpressionBuilder.Constant) arg).value();
755
          if (!(arg_value instanceof CharSequence)) {
756
            return;
757
          }
758
          String foreing_value_arg = arg_value.toString();
759
          String[] foreingNameParts = StringUtils.split(foreing_value_arg, "[.]");
760
          if (foreingNameParts.length != 2) {
761
            // De momento solo tratamos joins entre dos tablas.
762
            return;
763
          }
764
          String columnNameLocal = foreingNameParts[0];
765
          String columnNameForeing = foreingNameParts[1];
766
          FeatureAttributeDescriptor attr = type.getAttributeDescriptor(columnNameLocal);
767 45385 omartinez
          if (attr==null) {
768
              throw new RuntimeException("Cannot find in feature type attribute:"+columnNameLocal);
769
          }
770 44750 jjdelcerro
          if (!attr.isForeingKey()) {
771
            // Uhm... si el argumento no referencia a un campo que es
772
            // clave ajena no lo procesamos.
773
            // ? Deberiamos lanzar un error ?
774
            return;
775
          }
776
          // Nos guardaremos por que hay que reemplazar la funcion
777
          // FOREING_VALUE, y su argumento para mas tarde.
778
          ForeingKey foreingKey = attr.getForeingKey();
779
          SQLBuilder.TableNameBuilder foreingTable = sqlbuilder.createTableNameBuilder()
780
                  .database(table.getDatabase())
781
                  .schema(table.getSchema())
782
                  .name(foreingKey.getTableName());
783
          // Reemplzaremos la funcion FOREING_VALUE, por el acceso al campo
784
          // que toca de la tabla a la que referencia la clave ajena.
785
          ExpressionBuilder.Variable function_replacement = sqlbuilder.column(foreingTable, columnNameForeing);
786
          value_replacements.add(
787
                  new ExpressionBuilder.Value[]{
788
                    function,
789
                    function_replacement
790
                  }
791
          );
792 45155 omartinez
          if (!foreing_value_args.contains(foreing_value_arg)) {
793
            foreing_value_args.add(foreing_value_arg);
794
          }
795 44376 jjdelcerro
        }
796 44750 jjdelcerro
      }, null);
797 45155 omartinez
798 44750 jjdelcerro
      // Si no habia ningun llamada a la funcion FOREING_VALUE, no hay que
799
      // hacer nada.
800
      if (foreing_value_args.isEmpty()) {
801
        return;
802
      }
803 44403 omartinez
804 44750 jjdelcerro
      // Calculamos que referencias de columnas hemos de cambiar para
805
      // que no aparezcan ambiguedades al hacer el join (nombres de
806
      // columna de una y otra tabla que coincidan).
807
      // Para las columnas que puedan dar conflicto se prepara un reemplazo
808
      // de estas que tenga el nombre de tabla.
809
      for (ExpressionBuilder.Variable variable : sqlbuilder.variables()) {
810
        if (variable instanceof SQLBuilderBase.ColumnBase) {
811
          continue;
812 44376 jjdelcerro
        }
813
        for (String foreingName : foreing_value_args) {
814 44750 jjdelcerro
          String[] foreingNameParts = foreingName.split("[.]");
815
          if (foreingNameParts.length != 2) {
816
            continue;
817
          }
818
          String columnNameLocal = foreingNameParts[0];
819
          String columnNameForeing = foreingNameParts[1];
820
          if (StringUtils.equalsIgnoreCase(variable.name(), columnNameForeing)
821
                  || StringUtils.equalsIgnoreCase(variable.name(), columnNameLocal)) {
822
            ExpressionBuilder.Variable variable_replacement = sqlbuilder.column(
823
                    table,
824
                    variable.name()
825
            );
826
            value_replacements.add(
827
                    new ExpressionBuilder.Value[]{
828
                      variable,
829
                      variable_replacement
830
                    }
831
            );
832
          }
833
        }
834
      }
835 44376 jjdelcerro
836 44750 jjdelcerro
      // Realizamos los reemplazos calculados previamente (value_replacements).
837
      for (ExpressionBuilder.Value[] replaceValue : value_replacements) {
838
        ExpressionBuilder.Value target = replaceValue[0];
839
        ExpressionBuilder.Value replacement = replaceValue[1];
840
        sqlbuilder.select().replace(target, replacement);
841
      }
842
843 45162 omartinez
        // A?adimos a la SQL los "LEFT JOIN" que toca para poder acceder
844
        // a los valores referenciados por la funcion FOREING_VALUE.
845
        // Ademas a?adimos los valores referenciados por la funcion FOREING_VALUE
846
        // como columnas de la SQL para poder acceder a ellos si fuese necesario.
847
        HashSet usedLeftJoins = new HashSet();
848 44750 jjdelcerro
      for (String foreingName : foreing_value_args) {
849
        String[] foreingNameParts = foreingName.split("[.]");
850
        if (foreingNameParts.length != 2) {
851
          continue;
852 44376 jjdelcerro
        }
853 44750 jjdelcerro
        String columnNameLocal = foreingNameParts[0];
854
        String columnNameForeing = foreingNameParts[1];
855
        FeatureAttributeDescriptor attr = type.getAttributeDescriptor(columnNameLocal);
856
        if (attr.isForeingKey()) {
857
          ForeingKey foreingKey = attr.getForeingKey();
858
          SQLBuilder.TableNameBuilder foreingTable = sqlbuilder.createTableNameBuilder()
859
                  .database(table.getDatabase())
860
                  .schema(table.getSchema())
861
                  .name(foreingKey.getTableName());
862
          SQLBuilder.TableNameBuilder mainTable = sqlbuilder.createTableNameBuilder()
863
                  .database(table.getDatabase())
864
                  .schema(table.getSchema())
865
                  .name(table.getName());
866 45162 omartinez
867
          if (!usedLeftJoins.contains(foreingTable.getName())) {
868
            sqlbuilder.select().from()
869
                    .left_join(
870
                            foreingTable,
871
                            expbuilder.eq(
872
                                    sqlbuilder.column(mainTable, columnNameLocal),
873
                                    sqlbuilder.column(foreingTable, foreingKey.getCodeName())
874
                            )
875
                    );
876
            usedLeftJoins.add(foreingTable.getName());
877
          }
878
          if (!sqlbuilder.select().has_group_by()) {
879
                sqlbuilder.select().column().name(foreingTable, columnNameForeing);
880
          }
881 44750 jjdelcerro
        }
882 44682 jjdelcerro
      }
883 45385 omartinez
884
        for (SQLBuilder.SelectColumnBuilder column : sqlbuilder.select().getColumns()) {
885
            if(column.getTable()==null && column.getName()!=null) {
886
                column.name(table, column.getName());
887
            }
888
        }
889 44750 jjdelcerro
890
    } catch (Throwable th) {
891 45385 omartinez
      LOGGER.warn("Can't replace FOREING_VALUE function.", th);
892 44750 jjdelcerro
      throw th;
893
    } finally {
894
      LOGGER.trace("Exit from replaceForeingValueFunction.");
895 44376 jjdelcerro
    }
896 44750 jjdelcerro
  }
897 43020 jjdelcerro
}