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