All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jgrasstools.dbs.compat.ASpatialDb Maven / Gradle / Ivy

The newest version!
/*
 * This file is part of JGrasstools (http://www.jgrasstools.org)
 * (C) HydroloGIS - www.hydrologis.com 
 * 
 * JGrasstools is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */
package org.jgrasstools.dbs.compat;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.jgrasstools.dbs.spatialite.QueryResult;
import org.jgrasstools.dbs.spatialite.RasterCoverage;
import org.jgrasstools.dbs.spatialite.SpatialiteGeometryColumns;
import org.jgrasstools.dbs.spatialite.SpatialiteGeometryType;
import org.jgrasstools.dbs.spatialite.SpatialiteTableNames;

import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKBReader;

/**
 * Abstract spatial db class.
 * 
 * @author Andrea Antonello (www.hydrologis.com)
 *
 */
public abstract class ASpatialDb extends ADb implements AutoCloseable {

    public static String PK_UID = "PK_UID";
    public static String defaultGeomFieldName = "the_geom";

    /**
     * Open the connection to a database.
     * 
     * Make sure the connection object is created here.
     * 
     * @param dbPath
     *            the database path. If null, an in-memory db is
     *            created.
     * @return true if the database did already exist.
     * @throws Exception
     */
    public abstract boolean open( String dbPath ) throws Exception;

    /**
     * Create Spatial Metadata initialize SPATIAL_REF_SYS and GEOMETRY_COLUMNS.
     * 
     * 

* If the optional argument mode is not specified then any possible ESPG * SRID definition will be inserted into the spatial_ref_sys table. *

*

* If the mode arg 'WGS84' (alias 'WGS84_ONLY') is specified, then only * WGS84-related EPSG SRIDs will be inserted *

*

* If the mode arg 'NONE' (alias 'EMPTY') is specified, no EPSG SRID will be * inserted at all *

* * @param options * optional tweaks. * @throws Exception */ public abstract void initSpatialMetadata( String options ) throws Exception; /** * Adds a geometry column to a table. * * @param tableName * the table name. * @param geomColName * the geometry column name. * @param geomType * the geometry type (ex. LINESTRING); * @param epsg * the optional epsg code (default is 4326); * @param avoidIndex if true, the index is not created. * @throws Exception */ public void addGeometryXYColumnAndIndex( String tableName, String geomColName, String geomType, String epsg, boolean avoidIndex ) throws Exception { String epsgStr = "4326"; if (epsg != null) { epsgStr = epsg; } String geomTypeStr = "LINESTRING"; if (geomType != null) { geomTypeStr = geomType; } if (geomColName == null) { geomColName = defaultGeomFieldName; } try (IJGTStatement stmt = mConn.createStatement()) { String sql = "SELECT AddGeometryColumn('" + tableName + "','" + geomColName + "', " + epsgStr + ", '" + geomTypeStr + "', 'XY')"; stmt.execute(sql); if (!avoidIndex) { sql = "SELECT CreateSpatialIndex('" + tableName + "', '" + geomColName + "');"; stmt.execute(sql); } } } /** * Adds a geometry column to a table. * * @param tableName * the table name. * @param geomColName * the geometry column name. * @param geomType * the geometry type (ex. LINESTRING); * @param epsg * the optional epsg code (default is 4326); * @throws Exception */ public void addGeometryXYColumnAndIndex( String tableName, String geomColName, String geomType, String epsg ) throws Exception { addGeometryXYColumnAndIndex(tableName, geomColName, geomType, epsg, false); } /** * Insert a geometry into a table. * * @param tableName * the table to use. * @param geometry * the geometry to insert. * @param epsg * the optional epsg. * @throws Exception */ public void insertGeometry( String tableName, Geometry geometry, String epsg ) throws Exception { String epsgStr = "4326"; if (epsg == null) { epsgStr = epsg; } SpatialiteGeometryColumns gc = getGeometryColumnsForTable(tableName); String sql = "INSERT INTO " + tableName + " (" + gc.f_geometry_column + ") VALUES (GeomFromText(?, " + epsgStr + "))"; try (IJGTPreparedStatement pStmt = mConn.prepareStatement(sql)) { pStmt.setString(1, geometry.toText()); pStmt.executeUpdate(); } } /** * Get the list of available raster coverages. * * @param doOrder * if true, the names are ordered. * @return the list of raster coverages. * @throws Exception */ public List getRasterCoverages( boolean doOrder ) throws Exception { List rasterCoverages = new ArrayList(); String orderBy = " ORDER BY name"; if (!doOrder) { orderBy = ""; } String sql = "SELECT " + RasterCoverage.COVERAGE_NAME + ", " + RasterCoverage.TITLE + ", " + RasterCoverage.SRID + ", " + RasterCoverage.COMPRESSION + ", " + RasterCoverage.EXTENT_MINX + ", " + RasterCoverage.EXTENT_MINY + ", " + RasterCoverage.EXTENT_MAXX + ", " + RasterCoverage.EXTENT_MAXY + " FROM " + RasterCoverage.TABLENAME + orderBy; try (IJGTStatement stmt = mConn.createStatement(); IJGTResultSet rs = stmt.executeQuery(sql)) { while( rs.next() ) { RasterCoverage rc = new RasterCoverage(); int i = 1; rc.coverage_name = rs.getString(i++); rc.title = rs.getString(i++); rc.srid = rs.getInt(i++); rc.compression = rs.getString(i++); rc.extent_minx = rs.getDouble(i++); rc.extent_miny = rs.getDouble(i++); rc.extent_maxx = rs.getDouble(i++); rc.extent_maxy = rs.getDouble(i++); rasterCoverages.add(rc); } return rasterCoverages; } } /** * Get the list of available tables, mapped by type. * *

* Supported types are: *

    *
  • {@value SpatialiteTableNames#INTERNALDATA}
  • *
  • {@value SpatialiteTableNames#METADATA}
  • *
  • {@value SpatialiteTableNames#SPATIALINDEX}
  • *
  • {@value SpatialiteTableNames#STYLE}
  • *
  • {@value SpatialiteTableNames#USERDATA}
  • *
  • *
  • *
  • *
* * @param doOrder * @return the map of tables sorted by aggregated type: * @throws Exception */ public HashMap> getTablesMap( boolean doOrder ) throws Exception { List tableNames = getTables(doOrder); HashMap> tablesMap = SpatialiteTableNames.getTablesSorted(tableNames, doOrder); return tablesMap; } /** * Get the geometry column definition for a given table. * * @param tableName * the table to check. * @return the {@link SpatialiteGeometryColumns column info}. * @throws Exception */ public SpatialiteGeometryColumns getGeometryColumnsForTable( String tableName ) throws Exception { String attachedStr = ""; if (tableName.indexOf('.') != -1) { // if the tablename contains a dot, then it comes from an attached // database // get the database name String[] split = tableName.split("\\."); attachedStr = split[0] + "."; tableName = split[1]; // logger.debug(MessageFormat.format("Considering attached database: // {0}", attachedStr)); } String sql = "select " + SpatialiteGeometryColumns.F_TABLE_NAME + ", " // + SpatialiteGeometryColumns.F_GEOMETRY_COLUMN + ", " // + SpatialiteGeometryColumns.GEOMETRY_TYPE + "," // + SpatialiteGeometryColumns.COORD_DIMENSION + ", " // + SpatialiteGeometryColumns.SRID + ", " // + SpatialiteGeometryColumns.SPATIAL_INDEX_ENABLED + " from " // + attachedStr + SpatialiteGeometryColumns.TABLENAME + " where " + SpatialiteGeometryColumns.F_TABLE_NAME + "='" + tableName + "'"; try (IJGTStatement stmt = mConn.createStatement(); IJGTResultSet rs = stmt.executeQuery(sql)) { if (rs.next()) { SpatialiteGeometryColumns gc = new SpatialiteGeometryColumns(); gc.f_table_name = rs.getString(1); gc.f_geometry_column = rs.getString(2); gc.geometry_type = rs.getInt(3); gc.coord_dimension = rs.getInt(4); gc.srid = rs.getInt(5); gc.spatial_index_enabled = rs.getInt(6); return gc; } return null; } } /** * Checks if a table is spatial. * * @param tableName * the table to check. * @return true if a geometry column is present. * @throws Exception */ public boolean isTableSpatial( String tableName ) throws Exception { SpatialiteGeometryColumns geometryColumns = getGeometryColumnsForTable(tableName); return geometryColumns != null; } /** * Get the table records map with geometry in the given envelope. * *

* If the table is not geometric, the geom is set to null. * * @param tableName * the table name. * @param envelope * the envelope to check. * @param limit * if > 0 a limit is set. * @param alsoPK_UID * if true, also the PK_UID column is considered. * @return the list of found records. * @throws SQLException * @throws ParseException */ public QueryResult getTableRecordsMapIn( String tableName, Envelope envelope, boolean alsoPK_UID, int limit, int reprojectSrid ) throws Exception { QueryResult queryResult = new QueryResult(); SpatialiteGeometryColumns gCol = null; try { gCol = getGeometryColumnsForTable(tableName); } catch (Exception e) { // ignore } boolean hasGeom = gCol != null; List tableColumnsInfo = getTableColumns(tableName); List tableColumns = new ArrayList<>(); for( String[] info : tableColumnsInfo ) { tableColumns.add(info[0]); } if (hasGeom) { tableColumns.remove(gCol.f_geometry_column); } if (!alsoPK_UID) tableColumns.remove(PK_UID); String sql = "SELECT "; if (hasGeom) { if (reprojectSrid == -1 || reprojectSrid == gCol.srid) { sql += "ST_AsBinary(" + gCol.f_geometry_column + ") AS " + gCol.f_geometry_column; } else { sql += "ST_AsBinary(ST_Transform(" + gCol.f_geometry_column + "," + reprojectSrid + ")) AS " + gCol.f_geometry_column; } } for( int i = 0; i < tableColumns.size(); i++ ) { if (hasGeom || i != 0) sql += ","; sql += tableColumns.get(i); } sql += " FROM " + tableName; if (envelope != null) { double x1 = envelope.getMinX(); double y1 = envelope.getMinY(); double x2 = envelope.getMaxX(); double y2 = envelope.getMaxY(); sql += " WHERE "; // sql += getSpatialindexBBoxWherePiece(tableName, null, x1, y1, x2, y2); } if (limit > 0) { sql += " LIMIT " + limit; } WKBReader wkbReader = new WKBReader(); try (IJGTStatement stmt = mConn.createStatement(); IJGTResultSet rs = stmt.executeQuery(sql)) { IJGTResultSetMetaData rsmd = rs.getMetaData(); int columnCount = rsmd.getColumnCount(); for( int i = 1; i <= columnCount; i++ ) { String columnName = rsmd.getColumnName(i); queryResult.names.add(columnName); String columnTypeName = rsmd.getColumnTypeName(i); queryResult.types.add(columnTypeName); if (hasGeom && columnName.equals(gCol.f_geometry_column)) { queryResult.geometryIndex = i - 1; } } while( rs.next() ) { int i = 1; Object[] rec = new Object[columnCount]; if (hasGeom) { byte[] geomBytes = rs.getBytes(i); Geometry geometry = wkbReader.read(geomBytes); rec[i - 1] = geometry; i++; } for( int j = i; j <= columnCount; j++ ) { Object object = rs.getObject(j); rec[j - 1] = object; } queryResult.data.add(rec); } return queryResult; } } /** * Execute a query from raw sql. * * @param sql * the sql to run. * @param limit * a limit, ignored if < 1 * @return the resulting records. * @throws Exception */ public QueryResult getTableRecordsMapFromRawSql( String sql, int limit ) throws Exception { QueryResult queryResult = new QueryResult(); WKBReader wkbReader = new WKBReader(); try (IJGTStatement stmt = mConn.createStatement(); IJGTResultSet rs = stmt.executeQuery(sql)) { IJGTResultSetMetaData rsmd = rs.getMetaData(); int columnCount = rsmd.getColumnCount(); int geometryIndex = -1; for( int i = 1; i <= columnCount; i++ ) { int columnType = rsmd.getColumnType(i); String columnName = rsmd.getColumnName(i); queryResult.names.add(columnName); String columnTypeName = rsmd.getColumnTypeName(i); queryResult.types.add(columnTypeName); if (columnTypeName.equals("BLOB") && SpatialiteGeometryType.forValue(columnType) != null) { geometryIndex = i; queryResult.geometryIndex = i - 1; } } int count = 0; while( rs.next() ) { Object[] rec = new Object[columnCount]; for( int j = 1; j <= columnCount; j++ ) { if (j == geometryIndex) { byte[] geomBytes = rs.getBytes(j); try { Geometry geometry = wkbReader.read(geomBytes); rec[j - 1] = geometry; } catch (Exception e) { // ignore this, it could be missing ST_AsBinary() in // the sql } } else { Object object = rs.getObject(j); rec[j - 1] = object; } } queryResult.data.add(rec); if (limit > 0 && ++count > (limit - 1)) { break; } } return queryResult; } } /** * Execute a query from raw sql and put the result in a csv file. * * @param sql * the sql to run. * @param csvFile * the output file. * @param doHeader * if true, the header is written. * @param separator * the separator (if null, ";" is used). * @throws Exception */ public void runRawSqlToCsv( String sql, File csvFile, boolean doHeader, String separator ) throws Exception { try (BufferedWriter bw = new BufferedWriter(new FileWriter(csvFile))) { WKBReader wkbReader = new WKBReader(); try (IJGTStatement stmt = mConn.createStatement(); IJGTResultSet rs = stmt.executeQuery(sql)) { IJGTResultSetMetaData rsmd = rs.getMetaData(); int columnCount = rsmd.getColumnCount(); int geometryIndex = -1; for( int i = 1; i <= columnCount; i++ ) { if (i > 1) { bw.write(separator); } int columnType = rsmd.getColumnType(i); String columnTypeName = rsmd.getColumnTypeName(i); String columnName = rsmd.getColumnName(i); bw.write(columnName); if (columnTypeName.equals("BLOB") && SpatialiteGeometryType.forValue(columnType) != null) { geometryIndex = i; } } bw.write("\n"); while( rs.next() ) { for( int j = 1; j <= columnCount; j++ ) { if (j > 1) { bw.write(separator); } byte[] geomBytes = null; if (j == geometryIndex) { geomBytes = rs.getBytes(j); } if (geomBytes != null) { try { Geometry geometry = wkbReader.read(geomBytes); bw.write(geometry.toText()); } catch (Exception e) { // write it as it comes Object object = rs.getObject(j); if (object != null) { bw.write(object.toString()); } else { bw.write(""); } } } else { Object object = rs.getObject(j); if (object != null) { bw.write(object.toString()); } else { bw.write(""); } } } bw.write("\n"); } } } } /** * Get the geometries of a table inside a given envelope. * * @param tableName * the table name. * @param envelope * the envelope to check. * @return The list of geometries intersecting the envelope. * @throws Exception */ public List getGeometriesIn( String tableName, Envelope envelope ) throws Exception { List geoms = new ArrayList(); SpatialiteGeometryColumns gCol = getGeometryColumnsForTable(tableName); String sql = "SELECT ST_AsBinary(" + gCol.f_geometry_column + ") FROM " + tableName; if (envelope != null) { double x1 = envelope.getMinX(); double y1 = envelope.getMinY(); double x2 = envelope.getMaxX(); double y2 = envelope.getMaxY(); sql += " WHERE " + getSpatialindexBBoxWherePiece(tableName, null, x1, y1, x2, y2); } WKBReader wkbReader = new WKBReader(); try (IJGTStatement stmt = mConn.createStatement(); IJGTResultSet rs = stmt.executeQuery(sql)) { while( rs.next() ) { byte[] geomBytes = rs.getBytes(1); Geometry geometry = wkbReader.read(geomBytes); geoms.add(geometry); } return geoms; } } /** * Get the where cause of a Spatialindex based BBOX query. * * @param tableName * the name of the table. * @param x1 * west bound. * @param y1 * south bound. * @param x2 * east bound. * @param y2 * north bound. * @return the sql piece. * @throws Exception */ public String getSpatialindexBBoxWherePiece( String tableName, String alias, double x1, double y1, double x2, double y2 ) throws Exception { String rowid = ""; if (alias == null) { alias = ""; rowid = tableName + ".ROWID"; } else { rowid = alias + ".ROWID"; alias = alias + "."; } SpatialiteGeometryColumns gCol = getGeometryColumnsForTable(tableName); if (tableName.indexOf('.') != -1) { // if the tablename contains a dot, then it comes from an attached // database tableName = "DB=" + tableName; } String sql = "ST_Intersects(" + alias + gCol.f_geometry_column + ", BuildMbr(" + x1 + ", " + y1 + ", " + x2 + ", " + y2 + ")) = 1 AND " + rowid + " IN ( SELECT ROWID FROM SpatialIndex WHERE "// + "f_table_name = '" + tableName + "' AND " // + "search_frame = BuildMbr(" + x1 + ", " + y1 + ", " + x2 + ", " + y2 + "))"; return sql; } /** * Get the where query piece based on a geometry intersection. * * @param tableName * the table to query. * @param alias * optinal alias. * @param geometry * the geometry to intersect. * @return the query piece. * @throws Exception */ public String getSpatialindexGeometryWherePiece( String tableName, String alias, Geometry geometry ) throws Exception { String rowid = ""; if (alias == null) { alias = ""; rowid = tableName + ".ROWID"; } else { rowid = alias + ".ROWID"; alias = alias + "."; } Envelope envelope = geometry.getEnvelopeInternal(); double x1 = envelope.getMinX(); double x2 = envelope.getMaxX(); double y1 = envelope.getMinY(); double y2 = envelope.getMaxY(); SpatialiteGeometryColumns gCol = getGeometryColumnsForTable(tableName); if (tableName.indexOf('.') != -1) { // if the tablename contains a dot, then it comes from an attached // database tableName = "DB=" + tableName; } String sql = "ST_Intersects(" + alias + gCol.f_geometry_column + ", " + "GeomFromText('" + geometry.toText() + "')" + ") = 1 AND " + rowid + " IN ( SELECT ROWID FROM SpatialIndex WHERE "// + "f_table_name = '" + tableName + "' AND " // + "search_frame = BuildMbr(" + x1 + ", " + y1 + ", " + x2 + ", " + y2 + "))"; return sql; } /** * Get the bounds of a table. * * @param tableName * the table to query. * @return the {@link Envelope} of the table. * @throws Exception */ public abstract Envelope getTableBounds( String tableName ) throws Exception; protected abstract void logWarn( String message ); protected abstract void logInfo( String message ); protected abstract void logDebug( String message ); }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy