Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.plugin / org.gvsig.sqlite / org.gvsig.sqlite.provider / src / main / java / org / gvsig / sqlite / dal / SQLiteHelper.java @ 47456

History | View | Annotate | Download (14.8 KB)

1
/* gvSIG. Geographic Information System of the Valencian Government
2
 *
3
 * Copyright (C) 2007-2016 Infrastructures and Transports Department
4
 * of the Valencian Government (CIT)
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
 */
22
package org.gvsig.sqlite.dal;
23

    
24
import java.io.File;
25
import java.sql.Connection;
26
import java.sql.ResultSet;
27
import java.sql.SQLException;
28
import org.gvsig.expressionevaluator.GeometryExpressionBuilderHelper.GeometrySupportType;
29
import static org.gvsig.fmap.dal.DatabaseWorkspaceManager.FIELD_CONFIGURATION_NAME;
30
import static org.gvsig.fmap.dal.DatabaseWorkspaceManager.FIELD_CONFIGURATION_VALUE;
31
import static org.gvsig.fmap.dal.DatabaseWorkspaceManager.FIELD_RESOURCES_NAME;
32
import static org.gvsig.fmap.dal.DatabaseWorkspaceManager.FIELD_RESOURCES_RESOURCE;
33
import static org.gvsig.fmap.dal.DatabaseWorkspaceManager.TABLE_CONFIGURATION_NAME;
34
import static org.gvsig.fmap.dal.DatabaseWorkspaceManager.TABLE_RESOURCES_NAME;
35
import org.gvsig.fmap.dal.exception.DataException;
36
import org.gvsig.fmap.dal.resource.exception.AccessResourceException;
37
import org.gvsig.fmap.dal.spi.DataTransactionServices;
38
import org.gvsig.fmap.dal.store.jdbc.JDBCConnectionParameters;
39
import org.gvsig.fmap.dal.store.jdbc.JDBCNewStoreParameters;
40
import org.gvsig.fmap.dal.store.jdbc.JDBCServerExplorerParameters;
41
import org.gvsig.fmap.dal.store.jdbc.JDBCStoreParameters;
42
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCDriverClassNotFoundException;
43
import org.gvsig.fmap.dal.store.jdbc2.JDBCConnection;
44
import org.gvsig.fmap.dal.store.jdbc2.JDBCUtils;
45
import org.gvsig.fmap.dal.store.jdbc2.OperationsFactory;
46
import org.gvsig.fmap.dal.store.jdbc2.spi.AbstractConnectionProvider;
47
import org.gvsig.fmap.dal.store.jdbc2.spi.ConnectionProvider;
48
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCConnectionBase;
49
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCHelperBase;
50
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase;
51
import org.gvsig.fmap.dal.store.jdbc2.spi.SRSSolver;
52
import org.gvsig.fmap.dal.store.jdbc2.spi.SRSSolverDumb;
53
import org.gvsig.fmap.geom.Geometry;
54
import org.gvsig.fmap.geom.aggregate.MultiLine;
55
import org.gvsig.fmap.geom.aggregate.MultiPoint;
56
import org.gvsig.fmap.geom.aggregate.MultiPolygon;
57
import org.gvsig.fmap.geom.exception.CreateGeometryException;
58
import org.gvsig.fmap.geom.primitive.Primitive;
59
import org.gvsig.fmap.geom.type.GeometryType;
60
import org.gvsig.sqlite.dal.functions.Functions;
61
import org.gvsig.sqlite.dal.geopackage.GeopackageGeometryParser;
62
import org.gvsig.sqlite.dal.geopackage.GeopackageUtils;
63
import org.gvsig.sqlite.dal.operations.SQLiteOperationsFactory;
64
import org.gvsig.tools.dispose.DisposeUtils;
65
import org.slf4j.Logger;
66
import org.slf4j.LoggerFactory;
67
import org.sqlite.JDBC;
68
import org.sqlite.SQLiteConfig;
69
import org.sqlite.SQLiteConfig.TransactionMode;
70
import org.sqlite.SQLiteConnection;
71

    
72
@SuppressWarnings("UseSpecificCatch")
73
public class SQLiteHelper extends JDBCHelperBase {
74

    
75
    /*
76
        https://www.jpab.org/Hibernate/H2/embedded/Hibernate/SQLite/embedded.html
77
    */
78
    
79
    @SuppressWarnings("FieldNameHidesFieldInSuperclass")
80
    protected static final Logger LOGGER = LoggerFactory.getLogger(SQLiteHelper.class);
81

    
82
    public static class ConnectionProviderImpl extends AbstractConnectionProvider implements ConnectionProvider {
83

    
84
        private static boolean needRegisterDriver = true;
85

    
86
        private SQLiteConnectionParameters connectionParameters;
87

    
88
        public ConnectionProviderImpl(SQLiteConnectionParameters connectionParameters) {
89
            this.connectionParameters = connectionParameters;
90
        }
91

    
92
        @Override
93
        public synchronized Connection getConnection() throws SQLException {
94
            if (!this.isRegistered()) {
95
                this.registerDriver();
96
            }
97

    
98
            File f = SQLiteUtils.getLocalFile(connectionParameters);
99
            boolean newdb = f != null && !f.exists();
100

    
101
            SQLiteConfig config = new SQLiteConfig();
102
            config.setSharedCache(true);
103
            config.enableLoadExtension(true);
104
            config.setTransactionMode(TransactionMode.IMMEDIATE);
105
//            config.setSynchronous(SQLiteConfig.SynchronousMode.OFF);
106
            config.setPragma(SQLiteConfig.Pragma.CASE_SENSITIVE_LIKE, "true");
107

    
108
            SQLiteConnection conn;
109

    
110
            try {
111
                conn = org.sqlite.JDBC.createConnection(connectionParameters.getUrl(), config.toProperties());
112
            } catch (Throwable th) {
113
                throw th;
114
            }
115

    
116
            Functions.register_all(conn);
117

    
118
            if (newdb) {
119
                String[] sqls2 = new String[]{
120
                    "CREATE CACHED TABLE PUBLIC.\"" + TABLE_RESOURCES_NAME + "\"(\"" + FIELD_RESOURCES_NAME + "\" VARCHAR(150) NOT NULL, \"" + FIELD_RESOURCES_RESOURCE + "\" BLOB DEFAULT NULL)",
121
                    "ALTER TABLE PUBLIC.\"" + TABLE_RESOURCES_NAME + "\" ADD CONSTRAINT PUBLIC.CONSTRAINT_E PRIMARY KEY(\"" + FIELD_RESOURCES_NAME + "\")",
122
                    "CREATE CACHED TABLE PUBLIC.\"" + TABLE_CONFIGURATION_NAME + "\"(\"" + FIELD_CONFIGURATION_NAME + "\" VARCHAR(200) NOT NULL, \"" + FIELD_CONFIGURATION_VALUE + "\" CLOB DEFAULT NULL)",
123
                    "ALTER TABLE PUBLIC.\"" + TABLE_CONFIGURATION_NAME + "\" ADD CONSTRAINT PUBLIC.CONSTRAINT_2 PRIMARY KEY(\"" + FIELD_CONFIGURATION_NAME + "\")",};
124
                for (String sql : sqls2) {
125
                    try {
126
                        conn.createStatement().execute(sql);
127
                    } catch (SQLException ex) {
128
                        LOGGER.debug("Can't configure gvsig tables.", ex);
129
                        LOGGER.warn("Can't configure gvsig tables. " + sql);
130
                        // Ignore this error.
131
                    }
132
                }
133
            }
134
            return conn;
135
        }
136

    
137
        private boolean isRegistered() {
138
            return needRegisterDriver;
139
        }
140

    
141
        @Override
142
        public void registerDriver() throws SQLException {
143
            String className = this.connectionParameters.getJDBCDriverClassName();
144
            if (className == null) {
145
                return;
146
            }
147
            try {
148
                Class theClass = Class.forName(className);
149
                if (theClass == null) {
150
                    throw new JDBCDriverClassNotFoundException(SQLiteLibrary.NAME, className);
151
                }
152
            } catch (Exception e) {
153
                throw new SQLException("Can't register JDBC driver '" + className + "'.", e);
154
            }
155
            needRegisterDriver = false;
156
        }
157

    
158
        @Override
159
        public void dispose() {
160
            if (!DisposeUtils.release(this)) {
161
                return;
162
            }
163
            this.connectionParameters = null;
164
        }
165

    
166
        @Override
167
        public boolean isDisposed() {
168
            return this.connectionParameters == null;
169
        }
170

    
171
    }
172

    
173
    private ConnectionProvider connectionProvider = null;
174

    
175
    /**
176
     * Constructor for use only for testing purposes.
177
     *
178
     * @param connectionParameters
179
     * @param connectionProvider
180
     */
181
    public SQLiteHelper(JDBCConnectionParameters connectionParameters, ConnectionProvider connectionProvider) {
182
        super(connectionParameters);
183
        this.srssolver = new SRSSolverDumb(this);
184
        this.connectionProvider = connectionProvider;
185
    }
186

    
187
    public SQLiteHelper(JDBCConnectionParameters connectionParameters) {
188
        super(connectionParameters);
189
        this.srssolver = null; // GeopackageUtils.createSRSSolver(this);
190
    }
191

    
192
    @Override
193
    public synchronized JDBCConnection getConnection() throws AccessResourceException {
194
        try {
195
            SQLiteConnectionParameters connectionParameters = this.getConnectionParameters();
196
            JDBCConnection conn = (JDBCConnection) DataTransactionServices.getConnection(
197
                    transaction,
198
                    this.getConnectionProviderKey(connectionParameters)
199
            );
200
            if (conn != null) {
201
                return conn;
202
            }
203
            if (this.connectionProvider == null) {
204
                if (connectionParameters == null) {
205
                    return null; // Testing mode?
206
                }
207
                this.connectionProvider = new ConnectionProviderImpl(connectionParameters);
208
            }
209
            JDBCConnection connection = new JDBCConnectionBase(
210
                    this.transaction,
211
                    this.connectionProvider.getConnection(),
212
                    this.getConnectionProviderKey(connectionParameters)
213
            );
214
            if (LOGGER.isDebugEnabled()) {
215
                LOGGER.debug("[" + JDBCUtils.getConnId(connection.get()) + "] getConnection " + connectionProvider.getStatus() + " " + connectionProvider.toString());
216
            }
217
            return connection;
218
        } catch (SQLException ex) {
219
            throw new AccessResourceException(SQLiteLibrary.NAME, ex);
220
        }
221
    }
222

    
223
    @Override
224
    public SQLiteConnectionParameters getConnectionParameters() {
225
        return (SQLiteConnectionParameters) super.getConnectionParameters();
226
    }
227

    
228
    @Override
229
    public String getConnectionURL() {
230
        return SQLiteUtils.getConnectionURL(this.getConnectionParameters());
231
    }
232

    
233
    @Override
234
    protected String getResourceType() {
235
        return SQLiteLibrary.NAME;
236
    }
237

    
238
    @Override
239
    public String getProviderName() {
240
        return SQLiteLibrary.NAME;
241
    }
242

    
243
    @Override
244
    public JDBCSQLBuilderBase createSQLBuilder() {
245
        return new SQLiteSQLBuilder(this);
246
    }
247

    
248
    @Override
249
    public OperationsFactory getOperations() {
250
        if (this.operationsFactory == null) {
251
            this.operationsFactory = new SQLiteOperationsFactory(this);
252
        }
253
        return operationsFactory;
254
    }
255

    
256
    @Override
257
    public GeometrySupportType getGeometrySupportType() {
258
        return GeometrySupportType.NATIVE;
259
//        return GeometrySupportType.EWKB;
260
    }
261

    
262
    @Override
263
    public boolean hasSpatialFunctions() {
264
        return true;
265
    }
266

    
267
    @Override
268
    public boolean canWriteGeometry(int geometryType, int geometrySubtype) {
269
        return true;
270
    }
271

    
272
    @Override
273
    public String getQuoteForIdentifiers() {
274
        return "\"";
275
    }
276

    
277
    @Override
278
    public boolean allowAutomaticValues() {
279
        return true;
280
    }
281

    
282
    @Override
283
    public boolean supportOffsetInSelect() {
284
        return true;
285
    }
286

    
287
    @Override
288
    public String getQuoteForStrings() {
289
        return "'";
290
    }
291

    
292
    @Override
293
    public String getSourceId(JDBCStoreParameters parameters) {
294
        return parameters.getDBName() + "."
295
                + parameters.getSchema() + "."
296
                + parameters.getTable();
297
    }
298

    
299
    @Override
300
    public JDBCNewStoreParameters createNewStoreParameters() {
301
        return new SQLiteNewStoreParameters();
302
    }
303

    
304
    @Override
305
    public JDBCStoreParameters createOpenStoreParameters() {
306
        return new SQLiteStoreParameters();
307
    }
308

    
309
    @Override
310
    public JDBCServerExplorerParameters createServerExplorerParameters() {
311
        return new SQLiteExplorerParameters();
312
    }
313

    
314
    public Geometry forceGeometryType(GeometryType geomtype, Geometry geom) throws CreateGeometryException {
315
        if (geom == null) {
316
            return null;
317
        }
318
        switch (geomtype.getType()) {
319
            case Geometry.TYPES.MULTIPOLYGON:
320
                if (geom.getType() == Geometry.TYPES.POLYGON) {
321
                    MultiPolygon x = getGeometryManager().createMultiPolygon(geomtype.getSubType());
322
                    x.addPrimitive((Primitive) geom);
323
                    geom = x;
324
                }
325
                break;
326
            case Geometry.TYPES.MULTILINE:
327
                if (geom.getType() == Geometry.TYPES.LINE) {
328
                    MultiLine x = getGeometryManager().createMultiLine(geomtype.getSubType());
329
                    x.addPrimitive((Primitive) geom);
330
                    geom = x;
331
                }
332
                break;
333
            case Geometry.TYPES.MULTIPOINT:
334
                if (geom.getType() == Geometry.TYPES.POINT) {
335
                    MultiLine x = getGeometryManager().createMultiLine(geomtype.getSubType());
336
                    x.addPrimitive((Primitive) geom);
337
                    geom = x;
338
                }
339
                break;
340
            case Geometry.TYPES.POLYGON:
341
                if (geom.getType() == Geometry.TYPES.MULTIPOLYGON) {
342
                    MultiPolygon x = (MultiPolygon) geom;
343
                    if (x.getPrimitivesNumber() == 1) {
344
                        geom = x.getPrimitiveAt(0);
345
                    }
346
                }
347
                break;
348
            case Geometry.TYPES.LINE:
349
                if (geom.getType() == Geometry.TYPES.MULTILINE) {
350
                    MultiLine x = (MultiLine) geom;
351
                    if (x.getPrimitivesNumber() == 1) {
352
                        geom = x.getPrimitiveAt(0);
353
                    }
354
                }
355
                break;
356
            case Geometry.TYPES.POINT:
357
                if (geom.getType() == Geometry.TYPES.MULTIPOINT) {
358
                    MultiPoint x = (MultiPoint) geom;
359
                    if (x.getPrimitivesNumber() == 1) {
360
                        geom = x.getPrimitiveAt(0);
361
                    }
362
                }
363
        }
364
        return geom;
365
    }
366

    
367
    @Override
368
    public SRSSolver getSRSSolver() {
369
        if (this.srssolver == null) {
370
            try {
371
                this.srssolver = GeopackageUtils.createSRSSolver((SQLiteConnection) this.getConnection().get());
372
            } catch (Exception ex) {
373
                throw new RuntimeException("Can't get SRSSolver", ex);
374
            }
375
        }
376
        return this.srssolver;
377
    }
378

    
379
    @Override
380
    public Geometry getGeometryFromColumn(ResultSet rs, int index) throws DataException {
381
        try {
382
            if( this.getGeometrySupportType() == GeometrySupportType.NATIVE ) {
383
                byte[] bytes = rs.getBytes(index);
384
                if( GeopackageUtils.isGeopackageGeometry(bytes) ) {
385
                    GeopackageGeometryParser parser = GeopackageUtils.createGeometryParser();
386
                    Geometry geom = parser.parseToGeometry(null, bytes);
387
                    return geom;
388
                }
389
            }
390
        } catch (Exception ex) {
391
            LOGGER.debug("Can't process native geometry", ex);
392
        }
393
        return super.getGeometryFromColumn(rs, index);
394
    }
395

    
396
}