diff --git a/python/plugins/processing/algs/help/qgis.yaml b/python/plugins/processing/algs/help/qgis.yaml index bc1d4b3a2d1..117343975da 100644 --- a/python/plugins/processing/algs/help/qgis.yaml +++ b/python/plugins/processing/algs/help/qgis.yaml @@ -198,6 +198,9 @@ qgis:hublines: qgis:hypsometriccurves: > This algorithm computes hypsometric curves for an input Digital Elevation Model. Curves are produced as table files in an output folder specified by the user. +qgis:importintospatialite: > + This algorithms imports a vector layer into a Spatialite database, creating a new table. + qgis:importintopostgis: > This algorithms imports a vector layer into a PostGIS database, creating a new table. diff --git a/python/plugins/processing/algs/qgis/ImportIntoPostGIS.py b/python/plugins/processing/algs/qgis/ImportIntoPostGIS.py index ae6240bd8b0..062211cc22f 100644 --- a/python/plugins/processing/algs/qgis/ImportIntoPostGIS.py +++ b/python/plugins/processing/algs/qgis/ImportIntoPostGIS.py @@ -65,7 +65,7 @@ class ImportIntoPostGIS(GeoAlgorithm): self.addParameter(ParameterString(self.SCHEMA, self.tr('Schema (schema name)'), 'public')) self.addParameter(ParameterString(self.TABLENAME, - self.tr('Table to import to (leave blank to use layer name)'))) + self.tr('Table to import to (leave blank to use layer name)'), optional=True)) self.addParameter(ParameterTableField(self.PRIMARY_KEY, self.tr('Primary key field'), self.INPUT, optional=True)) self.addParameter(ParameterString(self.GEOMETRY_COLUMN, @@ -100,8 +100,10 @@ class ImportIntoPostGIS(GeoAlgorithm): layerUri = self.getParameterValue(self.INPUT) layer = dataobjects.getObjectFromUri(layerUri) - table = self.getParameterValue(self.TABLENAME).strip() - if table == '': + table = self.getParameterValue(self.TABLENAME) + if table: + table.strip() + if not table or table == '': table = layer.name() table = "_".join(table.split(".")[:-1]) table = table.replace(' ', '').lower()[0:62] diff --git a/python/plugins/processing/algs/qgis/ImportIntoSpatialite.py b/python/plugins/processing/algs/qgis/ImportIntoSpatialite.py new file mode 100644 index 00000000000..47bfcfd99f2 --- /dev/null +++ b/python/plugins/processing/algs/qgis/ImportIntoSpatialite.py @@ -0,0 +1,137 @@ +# -*- coding: utf-8 -*- + +""" +*************************************************************************** + ImportIntoSpatialite.py + --------------------- + Date : October 2016 + Copyright : (C) 2016 by Mathieu Pellerin + Email : nirvn dot asia at gmail dot com +*************************************************************************** +* * +* This program 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 2 of the License, or * +* (at your option) any later version. * +* * +*************************************************************************** +""" + +__author__ = 'Mathieu Pellerin' +__date__ = 'October 2016' +__copyright__ = '(C) 2012, Mathieu Pellerin' + +# This will get replaced with a git SHA1 when you do a git archive + +__revision__ = '$Format:%H$' + +from qgis.PyQt.QtCore import QSettings +from qgis.core import QgsDataSourceUri, QgsVectorLayerImport + +from processing.core.GeoAlgorithm import GeoAlgorithm +from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException +from processing.core.parameters import ParameterBoolean +from processing.core.parameters import ParameterVector +from processing.core.parameters import ParameterString +from processing.core.parameters import ParameterSelection +from processing.core.parameters import ParameterTableField +from processing.tools import dataobjects, spatialite + + +class ImportIntoSpatialite(GeoAlgorithm): + + DATABASE = 'DATABASE' + TABLENAME = 'TABLENAME' + INPUT = 'INPUT' + OVERWRITE = 'OVERWRITE' + CREATEINDEX = 'CREATEINDEX' + GEOMETRY_COLUMN = 'GEOMETRY_COLUMN' + LOWERCASE_NAMES = 'LOWERCASE_NAMES' + DROP_STRING_LENGTH = 'DROP_STRING_LENGTH' + FORCE_SINGLEPART = 'FORCE_SINGLEPART' + PRIMARY_KEY = 'PRIMARY_KEY' + ENCODING = 'ENCODING' + + def defineCharacteristics(self): + self.name, self.i18n_name = self.trAlgorithm('Import into Spatialite') + self.group, self.i18n_group = self.trAlgorithm('Database') + self.addParameter(ParameterVector(self.INPUT, self.tr('Layer to import'))) + self.addParameter(ParameterVector(self.DATABASE, self.tr('File database'), False, False)) + self.addParameter(ParameterString(self.TABLENAME, self.tr('Table to import to (leave blank to use layer name)'), optional=True)) + self.addParameter(ParameterTableField(self.PRIMARY_KEY, self.tr('Primary key field'), self.INPUT, optional=True)) + self.addParameter(ParameterString(self.GEOMETRY_COLUMN, self.tr('Geometry column'), 'geom')) + self.addParameter(ParameterString(self.ENCODING, self.tr('Encoding'), 'UTF-8', optional=True)) + self.addParameter(ParameterBoolean(self.OVERWRITE, self.tr('Overwrite'), True)) + self.addParameter(ParameterBoolean(self.CREATEINDEX, self.tr('Create spatial index'), True)) + self.addParameter(ParameterBoolean(self.LOWERCASE_NAMES, self.tr('Convert field names to lowercase'), True)) + self.addParameter(ParameterBoolean(self.DROP_STRING_LENGTH, self.tr('Drop length constraints on character fields'), False)) + self.addParameter(ParameterBoolean(self.FORCE_SINGLEPART, self.tr('Create single-part geometries instead of multi-part'), False)) + + def processAlgorithm(self, progress): + database = self.getParameterValue(self.DATABASE) + uri = QgsDataSourceUri(database) + if uri.database() is '': + if '|layerid' in database: + database = database[:database.find('|layerid')] + uri = QgsDataSourceUri('dbname=\'%s\'' % (database)) + db = spatialite.GeoDB(uri) + + overwrite = self.getParameterValue(self.OVERWRITE) + createIndex = self.getParameterValue(self.CREATEINDEX) + convertLowerCase = self.getParameterValue(self.LOWERCASE_NAMES) + dropStringLength = self.getParameterValue(self.DROP_STRING_LENGTH) + forceSinglePart = self.getParameterValue(self.FORCE_SINGLEPART) + primaryKeyField = self.getParameterValue(self.PRIMARY_KEY) or 'id' + encoding = self.getParameterValue(self.ENCODING) + + layerUri = self.getParameterValue(self.INPUT) + layer = dataobjects.getObjectFromUri(layerUri) + + table = self.getParameterValue(self.TABLENAME) + if table: + table.strip() + if not table or table == '': + table = layer.name() + table = table.replace(' ', '').lower() + providerName = 'spatialite' + + geomColumn = self.getParameterValue(self.GEOMETRY_COLUMN) + if not geomColumn: + geomColumn = 'the_geom' + + options = {} + if overwrite: + options['overwrite'] = True + if convertLowerCase: + options['lowercaseFieldNames'] = True + geomColumn = geomColumn.lower() + if dropStringLength: + options['dropStringConstraints'] = True + if forceSinglePart: + options['forceSinglePartGeometryType'] = True + + # Clear geometry column for non-geometry tables + if not layer.hasGeometryType(): + geomColumn = None + + uri = db.uri + uri.setDataSource('', table, geomColumn, '', primaryKeyField) + + if encoding: + layer.setProviderEncoding(encoding) + + (ret, errMsg) = QgsVectorLayerImport.importLayer( + layer, + uri.uri(), + providerName, + self.crs, + False, + False, + options, + ) + if ret != 0: + raise GeoAlgorithmExecutionException( + self.tr('Error importing to Spatialite\n%s' % errMsg)) + + if geomColumn and createIndex: + db.create_spatial_index(table, geomColumn) diff --git a/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py b/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py index 9cb4a1cab64..622e91a98b4 100644 --- a/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py +++ b/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py @@ -133,6 +133,7 @@ from .RandomPointsAlongLines import RandomPointsAlongLines from .PointsToPaths import PointsToPaths from .SpatialiteExecuteSQL import SpatialiteExecuteSQL from .PostGISExecuteSQL import PostGISExecuteSQL +from .ImportIntoSpatialite import ImportIntoSpatialite from .ImportIntoPostGIS import ImportIntoPostGIS from .SetVectorStyle import SetVectorStyle from .SetRasterStyle import SetRasterStyle @@ -214,7 +215,7 @@ class QGISAlgorithmProvider(AlgorithmProvider): RandomPointsLayer(), RandomPointsPolygonsFixed(), RandomPointsPolygonsVariable(), RandomPointsAlongLines(), PointsToPaths(), - SpatialiteExecuteSQL(), + SpatialiteExecuteSQL(), ImportIntoSpatialite(), PostGISExecuteSQL(), ImportIntoPostGIS(), SetVectorStyle(), SetRasterStyle(), SelectByExpression(), HypsometricCurves(), diff --git a/python/plugins/processing/tools/spatialite.py b/python/plugins/processing/tools/spatialite.py index 95a75e970ab..bb99ccfc4d3 100644 --- a/python/plugins/processing/tools/spatialite.py +++ b/python/plugins/processing/tools/spatialite.py @@ -28,7 +28,6 @@ __copyright__ = '(C) 2015, René-Luc Dhont' __revision__ = '$Format:%H$' from qgis.utils import spatialite_connect - import sqlite3 as sqlite @@ -124,3 +123,13 @@ class GeoDB(object): except DbError: self.con.rollback() raise + + def create_spatial_index(self, table, geom_column='the_geom'): + sql = u"SELECT CreateSpatialIndex(%s, %s)" % (self._quote(table), self._quote(geom_column)) + self._exec_sql_and_commit(sql) + + def _quote(self, identifier): + """Quote identifier.""" + + # quote identifier, and double the double-quotes + return u"'%s'" % identifier.replace("'", "''")