123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424 |
- """
- /***************************************************************************
- 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 qgis.PyQt.QtCore import QUrl, QTemporaryFile
- from ..connector import DBConnector
- from ..plugin import Table
- from qgis.core import (
- QgsDataSourceUri,
- QgsVirtualLayerDefinition,
- QgsProject,
- QgsMapLayerType,
- QgsVectorLayer,
- QgsCoordinateReferenceSystem,
- QgsWkbTypes
- )
- 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, ex_type, value, traceback):
- self.conn.close()
- return ex_type is None
- 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(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 is 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 list(self.layers.items())
- def getLayer(self, l):
- lid = self.layers.get(l)
- if lid is None:
- return lid
- if lid not in QgsProject.instance().mapLayers().keys():
- self.layers.pop(l)
- return None
- return QgsProject.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):
- # fix_print_with_import
- print(("_get_cursor_", name))
- def _get_cursor_columns(self, c):
- tf = QTemporaryFile()
- tf.open()
- tmp = tf.fileName()
- tf.close()
- df = QgsVirtualLayerDefinition()
- df.setFilePath(tmp)
- df.setQuery(c.sql)
- p = QgsVectorLayer(df.toString(), "vv", "virtual")
- if not p.isValid():
- return []
- f = [f.name() for f in p.fields()]
- if p.geometryType() != QgsWkbTypes.NullGeometry:
- 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 QgsProject.instance().mapLayers().items():
- if l.type() == QgsMapLayerType.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
- if l.isSpatial():
- g = l.dataProvider().wkbType()
- g_flat = QgsWkbTypes.flatType(g)
- geomType = QgsWkbTypes.displayString(g_flat).upper()
- if geomType:
- dim = 'XY'
- if QgsWkbTypes.hasZ(g):
- dim += 'Z'
- if QgsWkbTypes.hasM(g):
- dim += 'M'
- lst.append(
- (Table.VectorType, lname, False, False, l.id(), 'geometry', geomType, dim, l.crs().postgisSrid()))
- else:
- lst.append((Table.TableType, lname, False, False))
- return lst
- def getRasterTables(self, schema=None):
- return []
- def getTableRowCount(self, table):
- t = table[1]
- l = VLayerRegistry.instance().getLayer(t)
- if not l or not l.isValid():
- return None
- return l.featureCount()
- def getTableFields(self, table):
- """ return list of columns in table """
- t = table[1]
- l = VLayerRegistry.instance().getLayer(t)
- if not l or not l.isValid():
- return []
- # 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())]
- if l.isSpatial():
- 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 = QgsProject.instance().mapLayer(t)
- else:
- l = VLayerRegistry.instance().getLayer(t)
- if not l or not l.isValid():
- return None
- 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, comment=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()
|