# -*- coding: utf-8 -*- """ /*************************************************************************** Name : DB Manager Description : Database manager plugin for QuantumGIS 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 PyQt4.QtCore import * from PyQt4.QtGui import * 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 = [ ("Server version: ", info[0]) ] return HtmlTable( tbl ) def connectionDetails(self): tbl = [ ("Host:", self.db.connector.host), ("User:", self.db.connector.user) ] return HtmlTable( tbl ) def spatialInfo(self): ret = [] info = self.db.connector.getSpatialInfo() if info == None: return tbl = [ ("Library:", info[0]), ("Scripts:", info[1]), ("GEOS:", info[3]), ("Proj:", info[4]), ("Use stats:", info[5]) ] ret.append( HtmlTable( tbl ) ) if info[1] != None and info[1] != info[2]: ret.append( HtmlParagraph( u" Version of installed scripts doesn't match version of released scripts!\n" \ "This is probably a result of incorrect PostGIS upgrade." ) ) if not self.db.connector.has_geometry_columns: ret.append( HtmlParagraph( u" geometry_columns table doesn't exist!\n" \ "This table is essential for many GIS applications for enumeration of tables." ) ) elif not self.db.connector.has_geometry_columns_access: ret.append( HtmlParagraph( u" This user doesn't have privileges to read contents of geometry_columns table!\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("create new schemas") if details[1]: lst.append("create temporary tables") return HtmlList( lst ) def toHtml(self): if self.db == None: return HtmlSection( 'Not connected' ).toHtml() ret = [] # connection details conn_details = self.connectionDetails() if conn_details == None: pass else: ret.append( HtmlSection( 'Connection details', conn_details ) ) # database information general_info = self.generalInfo() if general_info == None: pass else: ret.append( HtmlSection( 'General info', general_info ) ) # has spatial enabled? spatial_info = self.spatialInfo() if spatial_info == None: pass else: typename = self.db.connection().typeNameString() spatial_info = HtmlContent( spatial_info ) if not spatial_info.hasContents(): spatial_info = ' %s support not enabled!' % typename ret.append( HtmlSection( typename, spatial_info ) ) # privileges priv_details = self.privilegesDetails() if priv_details == None: pass else: priv_details = HtmlContent( priv_details ) if not priv_details.hasContents(): priv_details = u' This user has no privileges!' else: priv_details = [ "User has privileges:", priv_details ] ret.append( HtmlSection( '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( ("Owner:", self.schema.owner) ) if self.schema.comment: tbl.append( ("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("create new objects") if details[1]: lst.append("access objects") return HtmlList( lst ) def toHtml(self): ret = [] general_info = self.generalInfo() if general_info == None: pass else: ret.append( HtmlSection( 'Schema details', general_info ) ) priv_details = self.privilegesDetails() if priv_details == None: pass else: priv_details = HtmlContent( priv_details ) if not priv_details.hasContents(): priv_details = u' This user has no privileges to access this schema!' else: priv_details = [ "User has privileges:", priv_details ] ret.append( HtmlSection( '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 == 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 = [ ("Relation type:", "View" if self.table.isView else "Table"), ("Rows:", self.table.rowCount if self.table.rowCount != None else 'Unknown (find out)') ] if self.table.comment: tbl.append( ("Comment:", self.table.comment) ) return HtmlTable( tbl ) def spatialInfo(self): # implemented in subclasses return None def fieldsDetails(self): tbl = [] # define the table header header = ( "#", "Name", "Type", "Null", "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() == None or len(self.table.constraints()) <= 0: return None tbl = [] # define the table header header = ( "Name", "Type", "Column(s)" ) tbl.append( HtmlTableHeader( header ) ) # add table contents for con in self.table.constraints(): # get the fields the constraint is defined on cols = map(lambda p: p[1].name if p[1] != None else u"??? (#%d)" % p[0], con.fields().iteritems()) tbl.append( (con.name, con.type2String(), u'\n'.join(cols)) ) return HtmlTable( tbl, {"class":"header"} ) def indexesDetails(self): if self.table.indexes() == None or len(self.table.indexes()) <= 0: return None tbl = [] # define the table header header = ( "Name", "Column(s)" ) tbl.append( HtmlTableHeader( header ) ) # add table contents for idx in self.table.indexes(): # get the fields the index is defined on cols = map(lambda p: p[1].name if p[1] != None else u"??? (#%d)" % p[0], idx.fields().iteritems()) tbl.append( (idx.name, u'\n'.join(cols)) ) return HtmlTable( tbl, {"class":"header"} ) def triggersDetails(self): if self.table.triggers() == None or len(self.table.triggers()) <= 0: return None tbl = [] # define the table header header = ( "Name", "Function" ) tbl.append( HtmlTableHeader( header ) ) # add table contents for trig in self.table.triggers(): name = u'%(name)s (%(action)s)' % { "name":trig.name, "action":"delete" } tbl.append( (name, trig.function) ) 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 == None: pass else: ret.append( HtmlSection( 'General info', general_info ) ) # spatial info spatial_info = self.spatialInfo() if spatial_info == None: pass else: spatial_info = HtmlContent( spatial_info ) if not spatial_info.hasContents(): spatial_info = u' This is not a spatial table.' ret.append( HtmlSection( self.table.database().connection().typeNameString(), spatial_info ) ) # fields fields_details = self.fieldsDetails() if fields_details == None: pass else: ret.append( HtmlSection( 'Fields', fields_details ) ) # constraints constraints_details = self.constraintsDetails() if constraints_details == None: pass else: ret.append( HtmlSection( 'Constraints', constraints_details ) ) # indexes indexes_details = self.indexesDetails() if indexes_details == None: pass else: ret.append( HtmlSection( 'Indexes', indexes_details ) ) # triggers triggers_details = self.triggersDetails() if triggers_details == None: pass else: ret.append( HtmlSection( '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 == None: pass else: ret.append( HtmlSection( '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 == None: return ret tbl = [ ("Column:", self.table.geomColumn), ("Geometry:", self.table.geomType) ] # only if we have info from geometry_columns if self.table.geomDim: tbl.append( ("Dimension:", self.table.geomDim) ) srid = self.table.srid if self.table.srid != None else -1 sr_info = self.table.database().connector.getSpatialRefInfo(srid) if srid != -1 else "Undefined" if sr_info: tbl.append( ("Spatial ref:", u"%s (%d)" % (sr_info, srid)) ) # estimated extent if not self.table.isView: if self.table.estimatedExtent == 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 != None and self.table.estimatedExtent[0] != None: estimated_extent_str = '%.5f, %.5f - %.5f, %.5f' % self.table.estimatedExtent tbl.append( ("Estimated extent:", estimated_extent_str) ) # extent if self.table.extent != None and self.table.extent[0] != None: extent_str = '%.5f, %.5f - %.5f, %.5f' % self.table.extent else: extent_str = '(unknown) (find out)' tbl.append( ("Extent:", extent_str) ) ret.append( HtmlTable( tbl ) ) # is there an entry in geometry_columns? if self.table.geomType.lower() == 'geometry': ret.append( HtmlParagraph( u" There isn't 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( u' No spatial index defined (create it)' ) ) return ret class RasterTableInfo(TableInfo): def __init__(self, table): TableInfo.__init__(self, table) def spatialInfo(self): ret = [] if self.table.geomType == None: return ret tbl = [ ("Column:", self.table.geomColumn), ("Geometry:", self.table.geomType) ] # only if we have info from geometry_columns srid = self.table.srid if self.table.srid != None else -1 sr_info = self.table.database().connector.getSpatialRefInfo(srid) if srid != -1 else "Undefined" if sr_info: tbl.append( ("Spatial ref:", u"%s (%d)" % (sr_info, srid)) ) # extent if self.table.extent != None and self.table.extent[0] != None: extent_str = '%.5f, %.5f - %.5f, %.5f' % self.table.extent else: extent_str = '(unknown) (find out)' tbl.append( ("Extent:", extent_str) ) ret.append( HtmlTable( tbl ) ) return ret