2024-11-29 15:38:02 +01:00

666 lines
21 KiB
Python

"""
/***************************************************************************
Name : DB Manager
Description : Database manager plugin for QGIS
Date : May 23, 2011
copyright : (C) 2011 by Giuseppe Sucameli
email : brush.tyler@gmail.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.QtWidgets import QApplication
from .html_elems import (
HtmlContent,
HtmlSection,
HtmlParagraph,
HtmlList,
HtmlTable,
HtmlTableHeader,
HtmlTableCol,
)
class DatabaseInfo:
def __init__(self, db):
self.db = db
def __del__(self):
self.db = None
def generalInfo(self):
info = self.db.connector.getInfo()
tbl = [(QApplication.translate("DBManagerPlugin", "Server version: "), info[0])]
return HtmlTable(tbl)
def connectionDetails(self):
tbl = [
(
QApplication.translate("DBManagerPlugin", "Host:"),
self.db.connector.host,
),
(
QApplication.translate("DBManagerPlugin", "User:"),
self.db.connector.user,
),
]
return HtmlTable(tbl)
def spatialInfo(self):
ret = []
info = self.db.connector.getSpatialInfo()
if info is None:
return
tbl = [
(QApplication.translate("DBManagerPlugin", "Library:"), info[0]),
("GEOS:", info[1]),
("Proj:", info[2]),
]
ret.append(HtmlTable(tbl))
if not self.db.connector.has_geometry_columns:
ret.append(
HtmlParagraph(
QApplication.translate(
"DBManagerPlugin",
"<warning> geometry_columns table doesn't exist!\n"
"This table is essential for many GIS applications for enumeration of tables.",
)
)
)
return ret
def privilegesDetails(self):
details = self.db.connector.getDatabasePrivileges()
lst = []
if details[0]:
lst.append(QApplication.translate("DBManagerPlugin", "create new schemas"))
if details[1]:
lst.append(
QApplication.translate("DBManagerPlugin", "create temporary tables")
)
return HtmlList(lst)
def toHtml(self):
if self.db is None:
return HtmlSection(
QApplication.translate("DBManagerPlugin", "<warning> Not connected")
).toHtml()
ret = []
# connection details
conn_details = self.connectionDetails()
if conn_details is None:
pass
else:
ret.append(
HtmlSection(
QApplication.translate("DBManagerPlugin", "Connection details"),
conn_details,
)
)
# database information
general_info = self.generalInfo()
if general_info is None:
pass
else:
ret.append(
HtmlSection(
QApplication.translate("DBManagerPlugin", "General info"),
general_info,
)
)
# has spatial enabled?
spatial_info = self.spatialInfo()
if spatial_info is None:
pass
else:
typename = self.db.connection().typeNameString()
spatial_info = HtmlContent(spatial_info)
if not spatial_info.hasContents():
spatial_info = QApplication.translate(
"DBManagerPlugin", "<warning> {0} support not enabled!"
).format(typename)
ret.append(HtmlSection(typename, spatial_info))
# privileges
priv_details = self.privilegesDetails()
if priv_details is None:
pass
else:
priv_details = HtmlContent(priv_details)
if not priv_details.hasContents():
priv_details = QApplication.translate(
"DBManagerPlugin", "<warning> This user has no privileges!"
)
else:
priv_details = [
QApplication.translate("DBManagerPlugin", "User has privileges:"),
priv_details,
]
ret.append(
HtmlSection(
QApplication.translate("DBManagerPlugin", "Privileges"),
priv_details,
)
)
return HtmlContent(ret).toHtml()
class SchemaInfo:
def __init__(self, schema):
self.schema = schema
def __del__(self):
self.schema = None
def generalInfo(self):
tbl = [
# ("Tables:", self.schema.tableCount)
]
if self.schema.owner:
tbl.append(
(QApplication.translate("DBManagerPlugin", "Owner:"), self.schema.owner)
)
if self.schema.comment:
tbl.append(
(
QApplication.translate("DBManagerPlugin", "Comment:"),
self.schema.comment,
)
)
return HtmlTable(tbl)
def privilegesDetails(self):
details = self.schema.database().connector.getSchemaPrivileges(self.schema.name)
lst = []
if details[0]:
lst.append(QApplication.translate("DBManagerPlugin", "create new objects"))
if details[1]:
lst.append(QApplication.translate("DBManagerPlugin", "access objects"))
return HtmlList(lst)
def toHtml(self):
ret = []
general_info = self.generalInfo()
if general_info is None:
pass
else:
ret.append(
HtmlSection(
QApplication.translate("DBManagerPlugin", "Schema details"),
general_info,
)
)
priv_details = self.privilegesDetails()
if priv_details is None:
pass
else:
priv_details = HtmlContent(priv_details)
if not priv_details.hasContents():
priv_details = QApplication.translate(
"DBManagerPlugin",
"<warning> This user has no privileges to access this schema!",
)
else:
priv_details = [
QApplication.translate("DBManagerPlugin", "User has privileges:"),
priv_details,
]
ret.append(
HtmlSection(
QApplication.translate("DBManagerPlugin", "Privileges"),
priv_details,
)
)
return HtmlContent(ret).toHtml()
class TableInfo:
def __init__(self, table):
self.table = table
def __del__(self):
self.table = None
def generalInfo(self):
if self.table.rowCount is None:
# row count information is not displayed yet, so just block
# table signals to avoid double refreshing (infoViewer->refreshRowCount->tableChanged->infoViewer)
self.table.blockSignals(True)
self.table.refreshRowCount()
self.table.blockSignals(False)
tbl = [
(
QApplication.translate("DBManagerPlugin", "Relation type:"),
(
QApplication.translate("DBManagerPlugin", "View")
if self.table.isView
else QApplication.translate("DBManagerPlugin", "Table")
),
),
(
QApplication.translate("DBManagerPlugin", "Rows:"),
(
self.table.rowCount
if self.table.rowCount is not None
else QApplication.translate(
"DBManagerPlugin",
'Unknown (<a href="action:rows/count">find out</a>)',
)
),
),
]
if self.table.comment:
tbl.append(
(
QApplication.translate("DBManagerPlugin", "Comment:"),
self.table.comment,
)
)
return HtmlTable(tbl)
def spatialInfo(self): # implemented in subclasses
return None
def fieldsDetails(self):
tbl = []
# define the table header
header = (
"#",
QApplication.translate("DBManagerPlugin", "Name"),
QApplication.translate("DBManagerPlugin", "Type"),
QApplication.translate("DBManagerPlugin", "Null"),
QApplication.translate("DBManagerPlugin", "Default"),
)
tbl.append(HtmlTableHeader(header))
# add table contents
for fld in self.table.fields():
is_null_txt = "N" if fld.notNull else "Y"
# make primary key field underlined
attrs = {"class": "underline"} if fld.primaryKey else None
name = HtmlTableCol(fld.name, attrs)
tbl.append(
(fld.num, name, fld.type2String(), is_null_txt, fld.default2String())
)
return HtmlTable(tbl, {"class": "header"})
def constraintsDetails(self):
if self.table.constraints() is None or len(self.table.constraints()) <= 0:
return None
tbl = []
# define the table header
header = (
QApplication.translate("DBManagerPlugin", "Name"),
QApplication.translate("DBManagerPlugin", "Type"),
QApplication.translate("DBManagerPlugin", "Column(s)"),
)
tbl.append(HtmlTableHeader(header))
# add table contents
for con in self.table.constraints():
# get the fields the constraint is defined on
cols = [
p[1].name if p[1] is not None else "??? (#%d)" % p[0]
for p in iter(list(con.fields().items()))
]
tbl.append((con.name, con.type2String(), "\n".join(cols)))
return HtmlTable(tbl, {"class": "header"})
def indexesDetails(self):
if self.table.indexes() is None or len(self.table.indexes()) <= 0:
return None
tbl = []
# define the table header
header = (
QApplication.translate("DBManagerPlugin", "Name"),
QApplication.translate("DBManagerPlugin", "Column(s)"),
)
tbl.append(HtmlTableHeader(header))
# add table contents
for idx in self.table.indexes():
# get the fields the index is defined on
cols = [
p[1].name if p[1] is not None else "??? (#%d)" % p[0]
for p in iter(list(idx.fields().items()))
]
tbl.append((idx.name, "\n".join(cols)))
return HtmlTable(tbl, {"class": "header"})
def triggersDetails(self):
if self.table.triggers() is None or len(self.table.triggers()) <= 0:
return None
tbl = []
# define the table header
header = (
QApplication.translate("DBManagerPlugin", "Name"),
QApplication.translate("DBManagerPlugin", "Function"),
)
tbl.append(HtmlTableHeader(header))
# add table contents
for trig in self.table.triggers():
name = (
'{name} (<a href="action:trigger/{name}/{action}">{action}</a>)'.format(
name=trig.name, action="delete"
)
)
tbl.append((name, trig.function.replace("<", "&lt;")))
return HtmlTable(tbl, {"class": "header"})
def getViewDefinition(self):
if not self.table.isView:
return None
return self.table.database().connector.getViewDefinition(
(self.table.schemaName(), self.table.name)
)
def getTableInfo(self):
ret = []
general_info = self.generalInfo()
if general_info is None:
pass
else:
ret.append(
HtmlSection(
QApplication.translate("DBManagerPlugin", "General info"),
general_info,
)
)
# spatial info
spatial_info = self.spatialInfo()
if spatial_info is None:
pass
else:
spatial_info = HtmlContent(spatial_info)
if not spatial_info.hasContents():
spatial_info = QApplication.translate(
"DBManagerPlugin", "<warning> This is not a spatial table."
)
ret.append(
HtmlSection(
self.table.database().connection().typeNameString(), spatial_info
)
)
# fields
fields_details = self.fieldsDetails()
if fields_details is None:
pass
else:
ret.append(
HtmlSection(
QApplication.translate("DBManagerPlugin", "Fields"), fields_details
)
)
# constraints
constraints_details = self.constraintsDetails()
if constraints_details is None:
pass
else:
ret.append(
HtmlSection(
QApplication.translate("DBManagerPlugin", "Constraints"),
constraints_details,
)
)
# indexes
indexes_details = self.indexesDetails()
if indexes_details is None:
pass
else:
ret.append(
HtmlSection(
QApplication.translate("DBManagerPlugin", "Indexes"),
indexes_details,
)
)
# triggers
triggers_details = self.triggersDetails()
if triggers_details is None:
pass
else:
ret.append(
HtmlSection(
QApplication.translate("DBManagerPlugin", "Triggers"),
triggers_details,
)
)
return ret
def getViewInfo(self):
if not self.table.isView:
return []
ret = self.getTableInfo()
# view definition
view_def = self.getViewDefinition()
if view_def is None:
pass
else:
ret.append(
HtmlSection(
QApplication.translate("DBManagerPlugin", "View definition"),
view_def,
)
)
return ret
def toHtml(self):
if self.table.isView:
ret = self.getViewInfo()
else:
ret = self.getTableInfo()
return HtmlContent(ret).toHtml()
class VectorTableInfo(TableInfo):
def __init__(self, table):
TableInfo.__init__(self, table)
def spatialInfo(self):
ret = []
if self.table.geomType is None:
return ret
tbl = [
(
QApplication.translate("DBManagerPlugin", "Column:"),
self.table.geomColumn,
),
(
QApplication.translate("DBManagerPlugin", "Geometry:"),
self.table.geomType,
),
]
# only if we have info from geometry_columns
if self.table.geomDim:
tbl.append(
(
QApplication.translate("DBManagerPlugin", "Dimension:"),
self.table.geomDim,
)
)
srid = self.table.srid if self.table.srid not in (None, 0) else -1
sr_info = (
self.table.database().connector.getSpatialRefInfo(srid)
if srid != -1
else QApplication.translate("DBManagerPlugin", "Undefined")
)
if sr_info:
tbl.append(
(
QApplication.translate("DBManagerPlugin", "Spatial ref:"),
"%s (%d)" % (sr_info, srid),
)
)
# estimated extent
if not self.table.isView:
if self.table.estimatedExtent is None:
# estimated extent information is not displayed yet, so just block
# table signals to avoid double refreshing (infoViewer->refreshEstimatedExtent->tableChanged->infoViewer)
self.table.blockSignals(True)
self.table.refreshTableEstimatedExtent()
self.table.blockSignals(False)
if (
self.table.estimatedExtent is not None
and self.table.estimatedExtent[0] is not None
):
if isinstance(self.table.estimatedExtent, list):
estimated_extent_str = ", ".join(
"%.5f" % e for e in self.table.estimatedExtent
)
else:
estimated_extent_str = (
"%.5f, %.5f - %.5f, %.5f" % self.table.estimatedExtent
)
tbl.append(
(
QApplication.translate("DBManagerPlugin", "Estimated extent:"),
estimated_extent_str,
)
)
# extent
if self.table.extent is not None and self.table.extent[0] is not None:
if isinstance(self.table.extent, list):
extent_str = ", ".join("%.5f" % e for e in self.table.extent)
else:
extent_str = "%.5f, %.5f - %.5f, %.5f" % self.table.extent
else:
extent_str = QApplication.translate(
"DBManagerPlugin",
'(unknown) (<a href="action:extent/get">find out</a>)',
)
tbl.append((QApplication.translate("DBManagerPlugin", "Extent:"), extent_str))
ret.append(HtmlTable(tbl))
# is there an entry in geometry_columns?
if self.table.geomType.lower() == "geometry":
ret.append(
HtmlParagraph(
QApplication.translate(
"DBManagerPlugin",
"<warning> There is no entry in geometry_columns!",
)
)
)
# find out whether the geometry column has spatial index on it
if not self.table.isView:
if not self.table.hasSpatialIndex():
ret.append(
HtmlParagraph(
QApplication.translate(
"DBManagerPlugin",
'<warning> No spatial index defined (<a href="action:spatialindex/create">create it</a>)',
)
)
)
return ret
class RasterTableInfo(TableInfo):
def __init__(self, table):
TableInfo.__init__(self, table)
def spatialInfo(self):
ret = []
if self.table.geomType is None:
return ret
tbl = [
(
QApplication.translate("DBManagerPlugin", "Column:"),
self.table.geomColumn,
),
(
QApplication.translate("DBManagerPlugin", "Geometry:"),
self.table.geomType,
),
]
# only if we have info from geometry_columns
srid = self.table.srid if self.table.srid is not None else -1
sr_info = (
self.table.database().connector.getSpatialRefInfo(srid)
if srid != -1
else QApplication.translate("DBManagerPlugin", "Undefined")
)
if sr_info:
tbl.append(
(
QApplication.translate("DBManagerPlugin", "Spatial ref:"),
"%s (%d)" % (sr_info, srid),
)
)
# extent
if self.table.extent is not None and self.table.extent[0] is not None:
extent_str = "%.5f, %.5f - %.5f, %.5f" % self.table.extent
else:
extent_str = QApplication.translate(
"DBManagerPlugin",
'(unknown) (<a href="action:extent/get">find out</a>)',
)
tbl.append((QApplication.translate("DBManagerPlugin", "Extent:"), extent_str))
ret.append(HtmlTable(tbl))
return ret