2016-01-07 15:38:09 +01:00

430 lines
13 KiB
Python

# -*- coding: utf-8 -*-
"""
/***************************************************************************
Name : Virtual layers plugin for DB Manager
Date : December 2015
copyright : (C) 2015 by Hugo Mercier
email : hugo dot mercier at oslandia 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. *
* *
***************************************************************************/
"""
from PyQt4.QtCore import QFile, QUrl, QTemporaryFile
from PyQt4.QtGui import QApplication
from ..connector import DBConnector
from ..plugin import ConnectionError, DbError, Table
from qgis.core import *
import sqlite3
class sqlite3_connection:
def __init__(self, sqlite_file):
self.conn = sqlite3.connect(sqlite_file)
def __enter__(self):
return self.conn
def __exit__(self, type, value, traceback):
self.conn.close()
def getQueryGeometryName(sqlite_file):
# introspect the file
with sqlite3_connection(sqlite_file) as conn:
c = conn.cursor()
for r in c.execute("SELECT url FROM _meta"):
d = QgsVirtualLayerDefinition.fromUrl(QUrl.fromEncoded(r[0]))
if d.hasDefinedGeometry():
return d.geometryField()
return None
def classFactory():
return VLayerConnector
# Tables in DB Manager are identified by their display names
# This global registry maps a display name with a layer id
# It is filled when getVectorTables is called
class VLayerRegistry:
_instance = None
@classmethod
def instance(cls):
if cls._instance == None:
cls._instance = VLayerRegistry()
return cls._instance
def __init__(self):
self.layers = {}
def reset(self):
self.layers = {}
def has(self, k):
return k in self.layers
def get(self, k):
return self.layers.get(k)
def __getitem__(self, k):
return self.get(k)
def set(self, k, l):
self.layers[k] = l
def __setitem__(self, k, l):
self.set(k, l)
def items(self):
return self.layers.items()
def getLayer(self, l):
lid = self.layers.get(l)
if lid is None:
return lid
return QgsMapLayerRegistry.instance().mapLayer(lid)
class VLayerConnector(DBConnector):
def __init__(self, uri):
pass
def _execute(self, cursor, sql):
# This is only used to get list of fields
class DummyCursor:
def __init__(self, sql):
self.sql = sql
def close(self):
pass
return DummyCursor(sql)
def _get_cursor(self, name=None):
print "_get_cursor_", name
def _get_cursor_columns(self, c):
tf = QTemporaryFile()
tf.open()
tmp = tf.fileName()
tf.close()
q = QUrl.toPercentEncoding(c.sql)
p = QgsVectorLayer("%s?query=%s" % (tmp, q), "vv", "virtual")
if not p.isValid():
return []
f = [f.name() for f in p.fields()]
if p.geometryType() != QGis.WKBNoGeometry:
gn = getQueryGeometryName(tmp)
if gn:
f += [gn]
return f
def uri(self):
return QgsDataSourceURI("qgis")
def getInfo(self):
return "info"
def getSpatialInfo(self):
return None
def hasSpatialSupport(self):
return True
def hasRasterSupport(self):
return False
def hasCustomQuerySupport(self):
return True
def hasTableColumnEditingSupport(self):
return False
def fieldTypes(self):
return [
"integer", "bigint", "smallint", # integers
"real", "double", "float", "numeric", # floats
"varchar", "varchar(255)", "character(20)", "text", # strings
"date", "datetime" # date/time
]
def getSchemas(self):
return None
def getTables(self, schema=None, add_sys_tables=False):
""" get list of tables """
return self.getVectorTables()
def getVectorTables(self, schema=None):
""" get list of table with a geometry column
it returns:
name (table name)
is_system_table
type = 'view' (is a view?)
geometry_column:
f_table_name (the table name in geometry_columns may be in a wrong case, use this to load the layer)
f_geometry_column
type
coord_dimension
srid
"""
reg = VLayerRegistry.instance()
VLayerRegistry.instance().reset()
lst = []
for _, l in QgsMapLayerRegistry.instance().mapLayers().items():
if l.type() == QgsMapLayer.VectorLayer:
lname = l.name()
# if there is already a layer with this name, use the layer id
# as name
if reg.has(lname):
lname = l.id()
VLayerRegistry.instance().set(lname, l.id())
geomType = None
dim = None
g = l.dataProvider().geometryType()
if g == QGis.WKBPoint:
geomType = 'POINT'
dim = 'XY'
elif g == QGis.WKBLineString:
geomType = 'LINESTRING'
dim = 'XY'
elif g == QGis.WKBPolygon:
geomType = 'POLYGON'
dim = 'XY'
elif g == QGis.WKBMultiPoint:
geomType = 'MULTIPOINT'
dim = 'XY'
elif g == QGis.WKBMultiLineString:
geomType = 'MULTILINESTRING'
dim = 'XY'
elif g == QGis.WKBMultiPolygon:
geomType = 'MULTIPOLYGON'
dim = 'XY'
elif g == QGis.WKBPoint25D:
geomType = 'POINT'
dim = 'XYZ'
elif g == QGis.WKBLineString25D:
geomType = 'LINESTRING'
dim = 'XYZ'
elif g == QGis.WKBPolygon25D:
geomType = 'POLYGON'
dim = 'XYZ'
elif g == QGis.WKBMultiPoint25D:
geomType = 'MULTIPOINT'
dim = 'XYZ'
elif g == QGis.WKBMultiLineString25D:
geomType = 'MULTILINESTRING'
dim = 'XYZ'
elif g == QGis.WKBMultiPolygon25D:
geomType = 'MULTIPOLYGON'
dim = 'XYZ'
lst.append(
(Table.VectorType, lname, False, False, l.id(), 'geometry', geomType, dim, l.crs().postgisSrid()))
return lst
def getRasterTables(self, schema=None):
return []
def getTableRowCount(self, table):
t = table[1]
l = VLayerRegistry.instance().getLayer(t)
return l.featureCount()
def getTableFields(self, table):
""" return list of columns in table """
t = table[1]
l = VLayerRegistry.instance().getLayer(t)
# id, name, type, nonnull, default, pk
n = l.dataProvider().fields().size()
f = [(i, f.name(), f.typeName(), False, None, False)
for i, f in enumerate(l.dataProvider().fields())]
f += [(n, "geometry", "geometry", False, None, False)]
return f
def getTableIndexes(self, table):
return []
def getTableConstraints(self, table):
return None
def getTableTriggers(self, table):
return []
def deleteTableTrigger(self, trigger, table=None):
return
def getTableExtent(self, table, geom):
is_id, t = table
if is_id:
l = QgsMapLayerRegistry.instance().mapLayer(t)
else:
l = VLayerRegistry.instance().getLayer(t)
e = l.extent()
r = (e.xMinimum(), e.yMinimum(), e.xMaximum(), e.yMaximum())
return r
def getViewDefinition(self, view):
print "**unimplemented** getViewDefinition"
def getSpatialRefInfo(self, srid):
crs = QgsCoordinateReferenceSystem(srid)
return crs.description()
def isVectorTable(self, table):
return True
def isRasterTable(self, table):
return False
def createTable(self, table, field_defs, pkey):
print "**unimplemented** createTable"
return False
def deleteTable(self, table):
print "**unimplemented** deleteTable"
return False
def emptyTable(self, table):
print "**unimplemented** emptyTable"
return False
def renameTable(self, table, new_table):
print "**unimplemented** renameTable"
return False
def moveTable(self, table, new_table, new_schema=None):
print "**unimplemented** moveTable"
return False
def createView(self, view, query):
print "**unimplemented** createView"
return False
def deleteView(self, view):
print "**unimplemented** deleteView"
return False
def renameView(self, view, new_name):
print "**unimplemented** renameView"
return False
def runVacuum(self):
print "**unimplemented** runVacuum"
return False
def addTableColumn(self, table, field_def):
print "**unimplemented** addTableColumn"
return False
def deleteTableColumn(self, table, column):
print "**unimplemented** deleteTableColumn"
def updateTableColumn(self, table, column, new_name, new_data_type=None, new_not_null=None, new_default=None):
print "**unimplemented** updateTableColumn"
def renameTableColumn(self, table, column, new_name):
print "**unimplemented** renameTableColumn"
return False
def setColumnType(self, table, column, data_type):
print "**unimplemented** setColumnType"
return False
def setColumnDefault(self, table, column, default):
print "**unimplemented** setColumnDefault"
return False
def setColumnNull(self, table, column, is_null):
print "**unimplemented** setColumnNull"
return False
def isGeometryColumn(self, table, column):
print "**unimplemented** isGeometryColumn"
return False
def addGeometryColumn(self, table, geom_column='geometry', geom_type='POINT', srid=-1, dim=2):
print "**unimplemented** addGeometryColumn"
return False
def deleteGeometryColumn(self, table, geom_column):
print "**unimplemented** deleteGeometryColumn"
return False
def addTableUniqueConstraint(self, table, column):
print "**unimplemented** addTableUniqueConstraint"
return False
def deleteTableConstraint(self, table, constraint):
print "**unimplemented** deleteTableConstraint"
return False
def addTablePrimaryKey(self, table, column):
print "**unimplemented** addTablePrimaryKey"
return False
def createTableIndex(self, table, name, column, unique=False):
print "**unimplemented** createTableIndex"
return False
def deleteTableIndex(self, table, name):
print "**unimplemented** deleteTableIndex"
return False
def createSpatialIndex(self, table, geom_column='geometry'):
print "**unimplemented** createSpatialIndex"
return False
def deleteSpatialIndex(self, table, geom_column='geometry'):
print "**unimplemented** deleteSpatialIndex"
return False
def hasSpatialIndex(self, table, geom_column='geometry'):
print "**unimplemented** hasSpatialIndex"
return False
def execution_error_types(self):
print "**unimplemented** execution_error_types"
return False
def connection_error_types(self):
print "**unimplemented** connection_error_types"
return False
def getSqlDictionary(self):
from .sql_dictionary import getSqlDictionary
sql_dict = getSqlDictionary()
items = []
for tbl in self.getTables():
items.append(tbl[1]) # table name
for fld in self.getTableFields((None, tbl[1])):
items.append(fld[1]) # field name
sql_dict["identifier"] = items
return sql_dict
def getQueryBuilderDictionary(self):
from .sql_dictionary import getQueryBuilderDictionary
return getQueryBuilderDictionary()