info_model.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. """
  2. /***************************************************************************
  3. Name : DB Manager
  4. Description : Database manager plugin for QGIS
  5. Date : May 23, 2011
  6. copyright : (C) 2011 by Giuseppe Sucameli
  7. email : brush.tyler@gmail.com
  8. ***************************************************************************/
  9. /***************************************************************************
  10. * *
  11. * This program is free software; you can redistribute it and/or modify *
  12. * it under the terms of the GNU General Public License as published by *
  13. * the Free Software Foundation; either version 2 of the License, or *
  14. * (at your option) any later version. *
  15. * *
  16. ***************************************************************************/
  17. """
  18. from qgis.PyQt.QtWidgets import QApplication
  19. from ..info_model import TableInfo, VectorTableInfo, RasterTableInfo, DatabaseInfo
  20. from ..html_elems import HtmlSection, HtmlParagraph, HtmlTable, HtmlTableHeader, HtmlTableCol
  21. class PGDatabaseInfo(DatabaseInfo):
  22. def connectionDetails(self):
  23. tbl = [
  24. (QApplication.translate("DBManagerPlugin", "Host:"), self.db.connector.host),
  25. (QApplication.translate("DBManagerPlugin", "User:"), self.db.connector.user),
  26. (QApplication.translate("DBManagerPlugin", "Database:"), self.db.connector.dbname)
  27. ]
  28. return HtmlTable(tbl)
  29. class PGTableInfo(TableInfo):
  30. def __init__(self, table):
  31. super().__init__(table)
  32. self.table = table
  33. def generalInfo(self):
  34. ret = []
  35. # if the estimation is less than 100 rows, try to count them - it shouldn't take long time
  36. if self.table.rowCount is None and self.table.estimatedRowCount < 100:
  37. # row count information is not displayed yet, so just block
  38. # table signals to avoid double refreshing (infoViewer->refreshRowCount->tableChanged->infoViewer)
  39. self.table.blockSignals(True)
  40. self.table.refreshRowCount()
  41. self.table.blockSignals(False)
  42. tbl = [
  43. (QApplication.translate("DBManagerPlugin", "Relation type:"),
  44. QApplication.translate("DBManagerPlugin", "View") if self.table._relationType == 'v' else
  45. QApplication.translate("DBManagerPlugin", "Materialized view") if self.table._relationType == 'm' else
  46. QApplication.translate("DBManagerPlugin", "Table")),
  47. (QApplication.translate("DBManagerPlugin", "Owner:"), self.table.owner)
  48. ]
  49. if self.table.comment:
  50. tbl.append((QApplication.translate("DBManagerPlugin", "Comment:"), self.table.comment))
  51. tbl.extend([
  52. (QApplication.translate("DBManagerPlugin", "Pages:"), self.table.pages),
  53. (QApplication.translate("DBManagerPlugin", "Rows (estimation):"), self.table.estimatedRowCount)
  54. ])
  55. # privileges
  56. # has the user access to this schema?
  57. schema_priv = self.table.database().connector.getSchemaPrivileges(
  58. self.table.schemaName()) if self.table.schema() else None
  59. if schema_priv is None:
  60. pass
  61. elif not schema_priv[1]: # no usage privileges on the schema
  62. tbl.append((QApplication.translate("DBManagerPlugin", "Privileges:"),
  63. QApplication.translate("DBManagerPlugin",
  64. "<warning> This user doesn't have usage privileges for this schema!")))
  65. else:
  66. table_priv = self.table.database().connector.getTablePrivileges((self.table.schemaName(), self.table.name))
  67. privileges = []
  68. if table_priv[0]:
  69. privileges.append("select")
  70. if self.table.rowCount is not None and self.table.rowCount >= 0:
  71. tbl.append((QApplication.translate("DBManagerPlugin", "Rows (counted):"),
  72. self.table.rowCount if self.table.rowCount is not None else QApplication.translate(
  73. "DBManagerPlugin", 'Unknown (<a href="action:rows/count">find out</a>)')))
  74. if table_priv[1]:
  75. privileges.append("insert")
  76. if table_priv[2]:
  77. privileges.append("update")
  78. if table_priv[3]:
  79. privileges.append("delete")
  80. priv_string = ", ".join(privileges) if len(privileges) > 0 else QApplication.translate("DBManagerPlugin",
  81. '<warning> This user has no privileges!')
  82. tbl.append((QApplication.translate("DBManagerPlugin", "Privileges:"), priv_string))
  83. ret.append(HtmlTable(tbl))
  84. if schema_priv is not None and schema_priv[1]:
  85. if table_priv[0] and not table_priv[1] and not table_priv[2] and not table_priv[3]:
  86. ret.append(HtmlParagraph(
  87. QApplication.translate("DBManagerPlugin", "<warning> This user has read-only privileges.")))
  88. if not self.table.isView:
  89. if self.table.rowCount is not None:
  90. if abs(self.table.estimatedRowCount - self.table.rowCount) > 1 and \
  91. (self.table.estimatedRowCount > 2 * self.table.rowCount
  92. or self.table.rowCount > 2 * self.table.estimatedRowCount):
  93. ret.append(HtmlParagraph(QApplication.translate("DBManagerPlugin",
  94. "<warning> There's a significant difference between estimated and real row count. "
  95. 'Consider running <a href="action:vacuumanalyze/run">VACUUM ANALYZE</a>.')))
  96. # primary key defined?
  97. if not self.table.isView:
  98. if len([fld for fld in self.table.fields() if fld.primaryKey]) <= 0:
  99. ret.append(HtmlParagraph(
  100. QApplication.translate("DBManagerPlugin", "<warning> No primary key defined for this table!")))
  101. return ret
  102. def getSpatialInfo(self):
  103. ret = []
  104. info = self.db.connector.getSpatialInfo()
  105. if info is None:
  106. return
  107. tbl = [
  108. (QApplication.translate("DBManagerPlugin", "Library:"), info[0]),
  109. (QApplication.translate("DBManagerPlugin", "Scripts:"), info[3]),
  110. ("GEOS:", info[1]),
  111. ("Proj:", info[2])
  112. ]
  113. ret.append(HtmlTable(tbl))
  114. if info[1] is not None and info[1] != info[2]:
  115. ret.append(HtmlParagraph(QApplication.translate("DBManagerPlugin",
  116. "<warning> Version of installed scripts doesn't match version of released scripts!\n"
  117. "This is probably a result of incorrect PostGIS upgrade.")))
  118. if not self.db.connector.has_geometry_columns:
  119. ret.append(HtmlParagraph(
  120. QApplication.translate("DBManagerPlugin", "<warning> geometry_columns table doesn't exist!\n"
  121. "This table is essential for many GIS applications for enumeration of tables.")))
  122. elif not self.db.connector.has_geometry_columns_access:
  123. ret.append(HtmlParagraph(QApplication.translate("DBManagerPlugin",
  124. "<warning> This user doesn't have privileges to read contents of geometry_columns table!\n"
  125. "This table is essential for many GIS applications for enumeration of tables.")))
  126. return ret
  127. def fieldsDetails(self):
  128. tbl = []
  129. # define the table header
  130. header = (
  131. "#", QApplication.translate("DBManagerPlugin", "Name"), QApplication.translate("DBManagerPlugin", "Type"),
  132. QApplication.translate("DBManagerPlugin", "Length"), QApplication.translate("DBManagerPlugin", "Null"),
  133. QApplication.translate("DBManagerPlugin", "Default"), QApplication.translate("DBManagerPlugin", "Comment"))
  134. tbl.append(HtmlTableHeader(header))
  135. # add table contents
  136. for fld in self.table.fields():
  137. char_max_len = fld.charMaxLen if fld.charMaxLen is not None and fld.charMaxLen != -1 else ""
  138. is_null_txt = "N" if fld.notNull else "Y"
  139. # make primary key field underlined
  140. attrs = {"class": "underline"} if fld.primaryKey else None
  141. name = HtmlTableCol(fld.name, attrs)
  142. tbl.append((fld.num, name, fld.type2String(), char_max_len, is_null_txt, fld.default2String(), fld.getComment()))
  143. return HtmlTable(tbl, {"class": "header"})
  144. def triggersDetails(self):
  145. if self.table.triggers() is None or len(self.table.triggers()) <= 0:
  146. return None
  147. ret = []
  148. tbl = []
  149. # define the table header
  150. header = (
  151. QApplication.translate("DBManagerPlugin", "Name"), QApplication.translate("DBManagerPlugin", "Function"),
  152. QApplication.translate("DBManagerPlugin", "Type"), QApplication.translate("DBManagerPlugin", "Enabled"))
  153. tbl.append(HtmlTableHeader(header))
  154. # add table contents
  155. for trig in self.table.triggers():
  156. name = '%(name)s (<a href="action:trigger/%(name)s/%(action)s">%(action)s</a>)' % {"name": trig.name,
  157. "action": "delete"}
  158. (enabled, action) = (QApplication.translate("DBManagerPlugin", "Yes"), "disable") if trig.enabled else (
  159. QApplication.translate("DBManagerPlugin", "No"), "enable")
  160. txt_enabled = '%(enabled)s (<a href="action:trigger/%(name)s/%(action)s">%(action)s</a>)' % {
  161. "name": trig.name, "action": action, "enabled": enabled}
  162. tbl.append((name, trig.function, trig.type2String(), txt_enabled))
  163. ret.append(HtmlTable(tbl, {"class": "header"}))
  164. ret.append(HtmlParagraph(QApplication.translate("DBManagerPlugin",
  165. '<a href="action:triggers/enable">Enable all triggers</a> / <a href="action:triggers/disable">Disable all triggers</a>')))
  166. return ret
  167. def rulesDetails(self):
  168. if self.table.rules() is None or len(self.table.rules()) <= 0:
  169. return None
  170. tbl = []
  171. # define the table header
  172. header = (
  173. QApplication.translate("DBManagerPlugin", "Name"), QApplication.translate("DBManagerPlugin", "Definition"))
  174. tbl.append(HtmlTableHeader(header))
  175. # add table contents
  176. for rule in self.table.rules():
  177. name = '%(name)s (<a href="action:rule/%(name)s/%(action)s">%(action)s</a>)' % {"name": rule.name,
  178. "action": "delete"}
  179. tbl.append((name, rule.definition))
  180. return HtmlTable(tbl, {"class": "header"})
  181. def getTableInfo(self):
  182. ret = TableInfo.getTableInfo(self)
  183. # rules
  184. rules_details = self.rulesDetails()
  185. if rules_details is None:
  186. pass
  187. else:
  188. ret.append(HtmlSection(QApplication.translate("DBManagerPlugin", 'Rules'), rules_details))
  189. return ret
  190. class PGVectorTableInfo(PGTableInfo, VectorTableInfo):
  191. def __init__(self, table):
  192. VectorTableInfo.__init__(self, table)
  193. PGTableInfo.__init__(self, table)
  194. def spatialInfo(self):
  195. return VectorTableInfo.spatialInfo(self)
  196. class PGRasterTableInfo(PGTableInfo, RasterTableInfo):
  197. def __init__(self, table):
  198. RasterTableInfo.__init__(self, table)
  199. PGTableInfo.__init__(self, table)
  200. def spatialInfo(self):
  201. return RasterTableInfo.spatialInfo(self)