123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667 |
- """
- /***************************************************************************
- Name : DB Manager
- Description : Database manager plugin for QGIS (Oracle)
- Date : Aug 27, 2014
- copyright : (C) 2014 by Médéric RIBREUX
- email : mederic.ribreux@gmail.com
- The content of this file is based on
- - PG_Manager by Martin Dobias <wonder.sk@gmail.com> (GPLv2 license)
- - DB Manager by Giuseppe Sucameli <brush.tyler@gmail.com> (GPLv2 license)
- ***************************************************************************/
- /***************************************************************************
- * *
- * 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 qgis.core import QgsWkbTypes
- from ..info_model import TableInfo, VectorTableInfo, DatabaseInfo
- from ..html_elems import HtmlContent, HtmlSection, HtmlParagraph, \
- HtmlTable, HtmlTableHeader, HtmlTableCol
- # Syntax Highlight for VIEWS/MVIEWS
- from pygments import highlight
- from pygments.lexers import get_lexer_by_name
- from pygments.formatters import HtmlFormatter
- class ORDatabaseInfo(DatabaseInfo):
- def __init__(self, db):
- self.db = db
- def connectionDetails(self):
- tbl = []
- if self.db.connector.host != "":
- tbl.append((QApplication.translate("DBManagerPlugin", "Host:"),
- self.db.connector.host))
- tbl.append((QApplication.translate("DBManagerPlugin", "Database:"),
- self.db.connector.dbname))
- tbl.append((QApplication.translate("DBManagerPlugin", "User:"),
- self.db.connector.user))
- tbl.append((QApplication.translate("DBManagerPlugin",
- "SQLite list tables cache:"),
- "Enabled" if self.db.connector.hasCache else
- "Unavailable"))
- return HtmlTable(tbl)
- def spatialInfo(self):
- ret = []
- info = self.db.connector.getSpatialInfo()
- if not info:
- return
- tbl = [
- (QApplication.translate("DBManagerPlugin", "Oracle Spatial:"),
- info[0])
- ]
- ret.append(HtmlTable(tbl))
- if not self.db.connector.has_geometry_columns:
- ret.append(
- HtmlParagraph(
- QApplication.translate(
- "DBManagerPlugin",
- "<warning> ALL_SDO_GEOM_METADATA"
- " view doesn't exist!\n"
- "This view is essential for many"
- " GIS applications for enumeration of tables.")))
- return ret
- def privilegesDetails(self):
- """ find if user can create schemas (CREATE ANY TABLE or something)"""
- # TODO
- return None
- class ORTableInfo(TableInfo):
- def __init__(self, table):
- self.table = table
- if not self.table.objectType:
- self.table.getType()
- if not self.table.comment:
- self.table.getComment()
- if not self.table.estimatedRowCount and not self.table.isView:
- self.table.refreshRowEstimation()
- if not self.table.creationDate:
- self.table.getDates()
- def generalInfo(self):
- ret = []
- # if the estimation is less than 100 rows, try to count them - it
- # shouldn't take long time
- if (not self.table.isView and
- not self.table.rowCount and
- self.table.estimatedRowCount < 100):
- # 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)
- relation_type = QApplication.translate(
- "DBManagerPlugin", self.table.objectType) if isinstance(self.table.objectType, str) else QApplication.translate("DBManagerPlugin", "Unknown")
- tbl = [
- (QApplication.translate("DBManagerPlugin", "Object type:"),
- relation_type),
- (QApplication.translate("DBManagerPlugin", "Owner:"),
- self.table.owner)
- ]
- if self.table.comment:
- tbl.append(
- (QApplication.translate(
- "DBManagerPlugin",
- "Comment:"),
- self.table.comment))
- # Estimated rows
- if not self.table.isView:
- tbl.append(
- (QApplication.translate(
- "DBManagerPlugin", "Rows (estimation):"),
- self.table.estimatedRowCount)
- )
- if self.table.rowCount is not None and self.table.rowCount >= 0:
- # Add a real count of rows
- tbl.append(
- (QApplication.translate("DBManagerPlugin", "Rows (counted):"),
- self.table.rowCount)
- )
- else:
- tbl.append(
- (QApplication.translate("DBManagerPlugin", "Rows (counted):"),
- 'Unknown (<a href="action:rows/recount">find out</a>)')
- )
- # Add creation and modification dates
- if self.table.creationDate:
- tbl.append(
- (QApplication.translate("DBManagerPlugin", "Creation Date:"),
- self.table.creationDate))
- if self.table.modificationDate:
- tbl.append(
- (QApplication.translate(
- "DBManagerPlugin", "Last Modification Date:"),
- self.table.modificationDate))
- # privileges
- # has the user access to this schema?
- schema_priv = self.table.database().connector.getSchemaPrivileges(
- self.table.schemaName()) if self.table.schema() else None
- if not schema_priv:
- pass
- elif schema_priv[1] is False: # no usage privileges on the schema
- tbl.append((QApplication.translate(
- "DBManagerPlugin", "Privileges:"),
- QApplication.translate(
- "DBManagerPlugin",
- "<warning> This user doesn't have usage privileges"
- " for this schema!")))
- else:
- table_priv = self.table.database().connector.getTablePrivileges(
- (self.table.schemaName(), self.table.name))
- privileges = []
- if table_priv[0]:
- privileges.append("select")
- if table_priv[1]:
- privileges.append("insert")
- if table_priv[2]:
- privileges.append("update")
- if table_priv[3]:
- privileges.append("delete")
- if len(privileges) > 0:
- priv_string = ", ".join(privileges)
- else:
- priv_string = QApplication.translate(
- "DBManagerPlugin",
- '<warning> This user has no privileges!')
- tbl.append(
- (QApplication.translate(
- "DBManagerPlugin", "Privileges:"),
- priv_string))
- ret.append(HtmlTable(tbl))
- if schema_priv and schema_priv[1]:
- if (table_priv[0] and
- not table_priv[1] and
- not table_priv[2] and
- not table_priv[3]):
- ret.append(
- HtmlParagraph(QApplication.translate(
- "DBManagerPlugin",
- "<warning> This user has read-only privileges.")))
- # primary key defined?
- if (not self.table.isView and
- self.table.objectType != "MATERIALIZED VIEW"):
- pk = [fld for fld in self.table.fields() if fld.primaryKey]
- if len(pk) <= 0:
- ret.append(
- HtmlParagraph(QApplication.translate(
- "DBManagerPlugin",
- "<warning> No primary key defined for this table!")))
- return ret
- def getSpatialInfo(self):
- ret = []
- info = self.db.connector.getSpatialInfo()
- if not info:
- return
- tbl = [
- (QApplication.translate(
- "DBManagerPlugin", "Library:"), info[0]) # ,
- ]
- ret.append(HtmlTable(tbl))
- if not self.db.connector.has_geometry_columns:
- ret.append(HtmlParagraph(
- QApplication.translate(
- "DBManagerPlugin",
- "<warning> ALL_SDO_GEOM_METADATA table doesn't exist!\n"
- "This table is essential for many GIS"
- " applications for enumeration of tables.")))
- return ret
- def fieldsDetails(self):
- tbl = []
- # define the table header
- header = (
- "#",
- QApplication.translate("DBManagerPlugin", "Name"),
- QApplication.translate("DBManagerPlugin", "Type"),
- QApplication.translate("DBManagerPlugin", "Length"),
- QApplication.translate("DBManagerPlugin", "Null"),
- QApplication.translate("DBManagerPlugin", "Default"),
- QApplication.translate("DBManagerPlugin", "Comment"))
- tbl.append(HtmlTableHeader(header))
- # add table contents
- for fld in self.table.fields():
- char_max_len = fld.charMaxLen if fld.charMaxLen else ""
- if fld.modifier:
- char_max_len = "{},{}".format(char_max_len, fld.modifier)
- 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(), char_max_len,
- is_null_txt, fld.default2String(), fld.comment))
- return HtmlTable(tbl, {"class": "header"})
- def constraintsDetails(self):
- if not self.table.constraints():
- return None
- tbl = []
- # define the table header
- header = (QApplication.translate("DBManagerPlugin", "Name"),
- QApplication.translate("DBManagerPlugin", "Type"),
- QApplication.translate("DBManagerPlugin", "Column"),
- QApplication.translate("DBManagerPlugin", "Status"),
- QApplication.translate("DBManagerPlugin", "Validated"),
- QApplication.translate("DBManagerPlugin", "Generated"),
- QApplication.translate("DBManagerPlugin", "Check condition"),
- QApplication.translate("DBManagerPlugin", "Foreign Table"),
- QApplication.translate("DBManagerPlugin", "Foreign column"),
- QApplication.translate("DBManagerPlugin", "On Delete"))
- tbl.append(HtmlTableHeader(header))
- # add table contents
- for con in self.table.constraints():
- tbl.append((con.name, con.type2String(), con.column,
- con.status, con.validated, con.generated,
- con.checkSource, con.foreignTable,
- con.foreignKey, con.foreignOnDelete))
- return HtmlTable(tbl, {"class": "header"})
- def indexesDetails(self):
- if not self.table.indexes():
- return None
- tbl = []
- # define the table header
- header = (QApplication.translate("DBManagerPlugin", "Name"),
- QApplication.translate("DBManagerPlugin", "Column(s)"),
- QApplication.translate("DBManagerPlugin", "Index Type"),
- QApplication.translate("DBManagerPlugin", "Status"),
- QApplication.translate("DBManagerPlugin", "Last analyzed"),
- QApplication.translate("DBManagerPlugin", "Compression"),
- QApplication.translate("DBManagerPlugin", "Uniqueness"),
- QApplication.translate("DBManagerPlugin", "Action"))
- tbl.append(HtmlTableHeader(header))
- # add table contents
- for idx in self.table.indexes():
- # get the fields the index is defined on
- tbl.append((idx.name, idx.column, idx.indexType,
- idx.status, idx.analyzed, idx.compression,
- idx.isUnique,
- ('<a href="action:index/{}/rebuild">Rebuild'
- """</a>""".format(idx.name))))
- return HtmlTable(tbl, {"class": "header"})
- def triggersDetails(self):
- if not self.table.triggers():
- return None
- ret = []
- tbl = []
- # define the table header
- header = (
- QApplication.translate("DBManagerPlugin", "Name"),
- QApplication.translate("DBManagerPlugin", "Event"),
- QApplication.translate("DBManagerPlugin", "Type"),
- QApplication.translate("DBManagerPlugin", "Enabled"))
- tbl.append(HtmlTableHeader(header))
- # add table contents
- for trig in self.table.triggers():
- name = ("""{0} (<a href="action:trigger/"""
- """{0}/{1}">{1}</a>)""".format(trig.name, "delete"))
- if trig.enabled == "ENABLED":
- enabled, action = (
- QApplication.translate("DBManagerPlugin", "Yes"),
- "disable")
- else:
- enabled, action = (
- QApplication.translate("DBManagerPlugin", "No"),
- "enable")
- txt_enabled = ("""{0} (<a href="action:trigger/"""
- """{1}/{2}">{2}</a>)""".format(
- enabled, trig.name, action))
- tbl.append((name, trig.event, trig.type, txt_enabled))
- ret.append(HtmlTable(tbl, {"class": "header"}))
- ret.append(
- HtmlParagraph(
- QApplication.translate(
- "DBManagerPlugin",
- '<a href="action:triggers/enable">'
- 'Enable all triggers</a> / '
- '<a href="action:triggers/disable">'
- 'Disable all triggers</a>')))
- return ret
- def getTableInfo(self):
- ret = []
- general_info = self.generalInfo()
- if not general_info:
- pass
- else:
- ret.append(
- HtmlSection(
- QApplication.translate(
- "DBManagerPlugin", 'General info'),
- general_info))
- # spatial info
- spatial_info = self.spatialInfo()
- if not spatial_info:
- 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 not fields_details:
- pass
- else:
- ret.append(
- HtmlSection(
- QApplication.translate(
- "DBManagerPlugin",
- 'Fields'),
- fields_details))
- # constraints
- constraints_details = self.constraintsDetails()
- if not constraints_details:
- pass
- else:
- ret.append(
- HtmlSection(
- QApplication.translate(
- "DBManagerPlugin",
- 'Constraints'),
- constraints_details))
- # indexes
- indexes_details = self.indexesDetails()
- if not indexes_details:
- pass
- else:
- ret.append(
- HtmlSection(
- QApplication.translate(
- "DBManagerPlugin",
- 'Indexes'),
- indexes_details))
- # triggers
- triggers_details = self.triggersDetails()
- if not triggers_details:
- pass
- else:
- ret.append(
- HtmlSection(
- QApplication.translate(
- "DBManagerPlugin",
- 'Triggers'),
- triggers_details))
- if self.table.objectType == "MATERIALIZED VIEW":
- mview_info = self.getMViewInfo()
- ret.append(
- HtmlSection(
- QApplication.translate(
- "DBManagerPlugin",
- 'Materialized View information'),
- mview_info))
- return ret
- def getMViewInfo(self):
- """If the table is a materialized view, grab more
- information...
- """
- ret = []
- tbl = []
- values = self.table.getMViewInfo()
- tbl.append((QApplication.translate("DBManagerPlugin",
- "Refresh Mode:"),
- values[0]))
- tbl.append((QApplication.translate("DBManagerPlugin",
- "Refresh Method:"),
- values[1]))
- tbl.append((QApplication.translate("DBManagerPlugin",
- "Build Mode:"),
- values[2]))
- tbl.append((QApplication.translate("DBManagerPlugin",
- "Last Refresh Date:"),
- values[5]))
- tbl.append((QApplication.translate("DBManagerPlugin",
- "Last Refresh Type:"),
- values[4]))
- tbl.append((QApplication.translate("DBManagerPlugin",
- "Fast Refreshable:"),
- values[3]))
- tbl.append((QApplication.translate("DBManagerPlugin",
- "Staleness:"),
- values[6]))
- tbl.append((QApplication.translate("DBManagerPlugin",
- "Stale since:"),
- values[7]))
- tbl.append((QApplication.translate("DBManagerPlugin",
- "Compile State:"),
- values[8]))
- tbl.append((QApplication.translate("DBManagerPlugin",
- "Use no index:"),
- values[9]))
- tbl.append(('<a href="action:mview/refresh">{}</a>'.format(
- QApplication.translate("DBManagerPlugin", "Refresh the materialized view")),
- ""))
- ret.append(HtmlTable(tbl))
- return ret
- def getViewInfo(self):
- """If the table is a view or a materialized view, add the
- definition of the view.
- """
- if self.table.objectType not in ["VIEW", "MATERIALIZED VIEW"]:
- return []
- ret = self.getTableInfo()
- # view definition
- view_def = self.table.getDefinition()
- # Syntax highlight
- lexer = get_lexer_by_name("sql")
- formatter = HtmlFormatter(
- linenos=True, cssclass="source", noclasses=True)
- result = highlight(view_def, lexer, formatter)
- if view_def:
- if self.table.objectType == "VIEW":
- title = "View Definition"
- else:
- title = "Materialized View Definition"
- ret.append(
- HtmlSection(
- QApplication.translate("DBManagerPlugin", title),
- result))
- return ret
- def toHtml(self):
- if self.table.objectType in ["VIEW", "MATERIALIZED VIEW"]:
- ret = self.getViewInfo()
- else:
- ret = self.getTableInfo()
- return HtmlContent(ret).toHtml()
- class ORVectorTableInfo(ORTableInfo, VectorTableInfo):
- def __init__(self, table):
- VectorTableInfo.__init__(self, table)
- ORTableInfo.__init__(self, table)
- def spatialInfo(self):
- ret = []
- if not self.table.geomType:
- return ret
- tbl = [
- (QApplication.translate("DBManagerPlugin", "Column:"),
- self.table.geomColumn),
- (QApplication.translate("DBManagerPlugin", "Geometry:"),
- self.table.geomType),
- (QApplication.translate("DBManagerPlugin",
- "QGIS Geometry type:"),
- QgsWkbTypes.displayString(self.table.wkbType))
- ]
- # 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 else -1
- if srid != -1:
- sr_info = (
- self.table.database().connector.getSpatialRefInfo(srid))
- else:
- sr_info = QApplication.translate("DBManagerPlugin",
- "Undefined")
- if sr_info:
- tbl.append(
- (QApplication.translate(
- "DBManagerPlugin", "Spatial ref:"),
- "{} ({})".format(sr_info, srid)))
- # estimated extent
- if not self.table.estimatedExtent:
- # 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:
- estimated_extent_str = ("{:.9f}, {:.9f} - {:.9f}, "
- "{:.9f}".format(
- *self.table.estimatedExtent))
- tbl.append(
- (QApplication.translate(
- "DBManagerPlugin", "Estimated extent:"),
- estimated_extent_str))
- # extent
- extent_str = None
- if self.table.extent and len(self.table.extent) == 4:
- extent_str = ("{:.9f}, {:.9f} - {:.9f}, "
- "{:.9f}".format(*self.table.extent))
- elif (self.table.rowCount is not None and self.table.rowCount > 0) or (self.table.estimatedRowCount is not None and self.table.estimatedRowCount > 0):
- # Can't calculate an extent on empty layer
- extent_str = QApplication.translate(
- "DBManagerPlugin",
- '(unknown) (<a href="action:extent/get">find out</a>)')
- if extent_str:
- tbl.append(
- (QApplication.translate(
- "DBManagerPlugin", "Extent:"),
- extent_str))
- ret.append(HtmlTable(tbl))
- # Handle extent update metadata
- if (self.table.extent and
- self.table.extent != self.table.estimatedExtent and
- self.table.canUpdateMetadata()):
- ret.append(
- HtmlParagraph(
- QApplication.translate(
- "DBManagerPlugin",
- '<warning> Metadata extent is different from'
- ' real extent. You should <a href="action:extent'
- '/update">update it</a>!')))
- # 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
|