2012-04-16 13:19:40 +02:00
# -*- coding: utf-8 -*-
"""
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Name : DB Manager
2013-06-09 18:28:52 +02:00
Description : Database manager plugin for QGIS
2012-04-16 13:19:40 +02:00
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 . *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
"""
2016-09-21 18:24:26 +02:00
from builtins import str
from builtins import range
2012-04-16 13:19:40 +02:00
2017-03-03 20:39:17 +01:00
from qgis . PyQt . QtCore import Qt , QObject , pyqtSignal
2016-04-22 10:38:48 +02:00
from qgis . PyQt . QtWidgets import QApplication , QAction , QMenu , QInputDialog , QMessageBox
from qgis . PyQt . QtGui import QKeySequence , QIcon
2012-04-16 13:19:40 +02:00
2014-09-17 17:27:01 +02:00
from qgis . gui import QgsMessageBar
2018-06-30 11:59:13 +07:00
from qgis . core import Qgis , QgsApplication , QgsSettings
2012-04-16 13:19:40 +02:00
from . . db_plugins import createDbPlugin
2015-03-21 10:41:58 +10:00
2012-04-16 13:19:40 +02:00
class BaseError ( Exception ) :
2015-08-22 14:29:41 +02:00
2015-03-21 10:41:58 +10:00
""" Base class for exceptions in the plugin. """
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
def __init__ ( self , e ) :
if isinstance ( e , Exception ) :
msg = e . args [ 0 ] if len ( e . args ) > 0 else ' '
else :
msg = e
2013-05-27 01:29:53 +02:00
2016-09-21 18:24:26 +02:00
if not isinstance ( msg , str ) :
msg = str ( msg , ' utf-8 ' , ' replace ' ) # convert from utf8 and replace errors (if any)
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
self . msg = msg
Exception . __init__ ( self , msg )
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
def __unicode__ ( self ) :
return self . msg
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
class InvalidDataException ( BaseError ) :
pass
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
class ConnectionError ( BaseError ) :
pass
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
class DbError ( BaseError ) :
2015-08-22 14:29:41 +02:00
2015-03-21 10:41:58 +10:00
def __init__ ( self , e , query = None ) :
BaseError . __init__ ( self , e )
2016-09-21 18:24:26 +02:00
self . query = str ( query ) if query is not None else None
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
def __unicode__ ( self ) :
if self . query is None :
return BaseError . __unicode__ ( self )
2012-04-16 13:19:40 +02:00
2017-03-04 16:23:36 +01:00
msg = QApplication . translate ( " DBManagerPlugin " , " Error: \n {0} " ) . format ( BaseError . __unicode__ ( self ) )
2015-03-21 10:41:58 +10:00
if self . query :
2017-03-04 16:23:36 +01:00
msg + = QApplication . translate ( " DBManagerPlugin " , " \n \n Query: \n {0} " ) . format ( self . query )
2015-03-21 10:41:58 +10:00
return msg
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
class DBPlugin ( QObject ) :
2016-03-15 23:41:19 +01:00
deleted = pyqtSignal ( )
changed = pyqtSignal ( )
aboutToChange = pyqtSignal ( )
2015-08-22 14:29:41 +02:00
2015-03-21 10:41:58 +10:00
def __init__ ( self , conn_name , parent = None ) :
QObject . __init__ ( self , parent )
self . connName = conn_name
self . db = None
def __del__ ( self ) :
pass # print "DBPlugin.__del__", self.connName
2018-06-30 11:59:13 +07:00
def connectionIcon ( self ) :
return QgsApplication . getThemeIcon ( " /mIconDbSchema.svg " )
2015-03-21 10:41:58 +10:00
def connectionName ( self ) :
return self . connName
def database ( self ) :
return self . db
def info ( self ) :
from . info_model import DatabaseInfo
return DatabaseInfo ( None )
2015-09-03 01:22:54 +02:00
def connect ( self , parent = None ) :
2017-10-17 00:01:48 +02:00
raise NotImplementedError ( ' Needs to be implemented by subclasses ' )
2015-09-03 01:22:54 +02:00
2015-03-21 10:41:58 +10:00
def connectToUri ( self , uri ) :
self . db = self . databasesFactory ( self , uri )
if self . db :
return True
return False
def reconnect ( self ) :
if self . db is not None :
uri = self . db . uri ( )
self . db . deleteLater ( )
self . db = None
return self . connectToUri ( uri )
return self . connect ( self . parent ( ) )
2015-09-03 01:22:54 +02:00
def remove ( self ) :
2017-03-03 20:39:17 +01:00
settings = QgsSettings ( )
2015-09-03 01:22:54 +02:00
settings . beginGroup ( u " / %s / %s " % ( self . connectionSettingsKey ( ) , self . connectionName ( ) ) )
settings . remove ( " " )
2016-03-15 23:41:19 +01:00
self . deleted . emit ( )
2015-09-03 01:22:54 +02:00
return True
@classmethod
def addConnection ( self , conn_name , uri ) :
2017-10-17 00:01:48 +02:00
raise NotImplementedError ( ' Needs to be implemented by subclasses ' )
2015-09-03 01:22:54 +02:00
2015-03-21 10:41:58 +10:00
@classmethod
def icon ( self ) :
return None
@classmethod
def typeName ( self ) :
# return the db typename (e.g. 'postgis')
pass
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
@classmethod
def typeNameString ( self ) :
# return the db typename string (e.g. 'PostGIS')
pass
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
@classmethod
def providerName ( self ) :
# return the provider's name (e.g. 'postgres')
pass
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
@classmethod
def connectionSettingsKey ( self ) :
# return the key used to store the connections in settings
pass
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
@classmethod
def connections ( self ) :
# get the list of connections
conn_list = [ ]
2017-03-03 20:39:17 +01:00
settings = QgsSettings ( )
2015-03-21 10:41:58 +10:00
settings . beginGroup ( self . connectionSettingsKey ( ) )
for name in settings . childGroups ( ) :
conn_list . append ( createDbPlugin ( self . typeName ( ) , name ) )
settings . endGroup ( )
return conn_list
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
def databasesFactory ( self , connection , uri ) :
return None
2012-04-16 13:19:40 +02:00
2015-09-03 01:22:54 +02:00
@classmethod
def addConnectionActionSlot ( self , item , action , parent ) :
2017-10-17 00:01:48 +02:00
raise NotImplementedError ( ' Needs to be implemented by subclasses ' )
2015-09-03 01:22:54 +02:00
def removeActionSlot ( self , item , action , parent ) :
QApplication . restoreOverrideCursor ( )
try :
2018-02-13 08:04:32 +10:00
res = QMessageBox . question ( parent , QApplication . translate ( " DBManagerPlugin " , " DB Manager " ) ,
2015-09-03 01:22:54 +02:00
QApplication . translate ( " DBManagerPlugin " ,
2017-03-04 16:23:36 +01:00
" Really remove connection to {0} ? " ) . format ( item . connectionName ( ) ) ,
2015-09-03 01:22:54 +02:00
QMessageBox . Yes | QMessageBox . No )
if res != QMessageBox . Yes :
return
finally :
QApplication . setOverrideCursor ( Qt . WaitCursor )
item . remove ( )
fix python pep8 warnings and fix some revealed errors
pep8 --ignore=E111,E128,E201,E202,E203,E211,E221,E222,E225,E226,E227,E231,E241,E261,E265,E272,E302,E303,E501,E701 \
--exclude="ui_*.py,debian/*,python/ext-libs/*" \
.
2015-02-01 14:15:42 +01:00
2015-03-21 10:41:58 +10:00
class DbItemObject ( QObject ) :
2016-03-15 23:41:19 +01:00
changed = pyqtSignal ( )
aboutToChange = pyqtSignal ( )
deleted = pyqtSignal ( )
2015-08-22 14:29:41 +02:00
2015-03-21 10:41:58 +10:00
def __init__ ( self , parent = None ) :
QObject . __init__ ( self , parent )
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
def database ( self ) :
return None
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
def refresh ( self ) :
2016-03-15 23:41:19 +01:00
self . changed . emit ( ) # refresh the item data reading them from the db
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
def info ( self ) :
pass
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
def runAction ( self ) :
pass
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
def registerActions ( self , mainWindow ) :
pass
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
class Database ( DbItemObject ) :
2015-08-22 14:29:41 +02:00
2015-03-21 10:41:58 +10:00
def __init__ ( self , dbplugin , uri ) :
DbItemObject . __init__ ( self , dbplugin )
self . connector = self . connectorsFactory ( uri )
def connectorsFactory ( self , uri ) :
return None
def __del__ ( self ) :
self . connector = None
pass # print "Database.__del__", self
def connection ( self ) :
return self . parent ( )
def dbplugin ( self ) :
return self . parent ( )
def database ( self ) :
return self
def uri ( self ) :
return self . connector . uri ( )
def publicUri ( self ) :
return self . connector . publicUri ( )
2015-09-03 01:22:54 +02:00
def delete ( self ) :
2016-03-21 04:51:10 +01:00
self . aboutToChange . emit ( )
2015-09-03 01:22:54 +02:00
ret = self . connection ( ) . remove ( )
if ret is not False :
2016-03-15 23:41:19 +01:00
self . deleted . emit ( )
2015-09-03 01:22:54 +02:00
return ret
2015-03-21 10:41:58 +10:00
def info ( self ) :
from . info_model import DatabaseInfo
return DatabaseInfo ( self )
def sqlResultModel ( self , sql , parent ) :
from . data_model import SqlResultModel
return SqlResultModel ( self , sql , parent )
2018-01-22 10:26:31 +00:00
def sqlResultModelAsync ( self , sql , parent ) :
from . data_model import SqlResultModelAsync
return SqlResultModelAsync ( self , sql , parent )
2015-08-22 14:29:41 +02:00
def columnUniqueValuesModel ( self , col , table , limit = 10 ) :
2015-03-30 15:31:19 +02:00
l = " "
if limit is not None :
l = " LIMIT %d " % limit
2015-08-22 14:29:41 +02:00
return self . sqlResultModel ( " SELECT DISTINCT %s FROM %s %s " % ( col , table , l ) , self )
2015-03-30 15:31:19 +02:00
2015-03-27 14:32:41 +01:00
def uniqueIdFunction ( self ) :
""" Return a SQL function used to generate a unique id for rows of a query """
# may be overloaded by derived classes
return " row_number() over () "
2015-11-12 00:36:31 +01:00
def toSqlLayer ( self , sql , geomCol , uniqueCol , layerName = " QueryLayer " , layerType = None , avoidSelectById = False , filter = " " ) :
2015-03-21 10:41:58 +10:00
from qgis . core import QgsMapLayer , QgsVectorLayer , QgsRasterLayer
2015-03-27 14:32:41 +01:00
if uniqueCol is None :
if hasattr ( self , ' uniqueIdFunction ' ) :
uniqueFct = self . uniqueIdFunction ( )
if uniqueFct is not None :
q = 1
while " _subq_ %d _ " % q in sql :
q + = 1
2018-07-05 17:44:14 +02:00
sql = u " SELECT %s AS _uid_,* FROM ( %s \n ) AS _subq_ %d _ " % ( uniqueFct , sql , q )
2015-03-27 14:32:41 +01:00
uniqueCol = " _uid_ "
2015-03-21 10:41:58 +10:00
uri = self . uri ( )
2015-11-12 00:36:31 +01:00
uri . setDataSource ( " " , u " ( %s \n ) " % sql , geomCol , filter , uniqueCol )
2015-03-21 10:41:58 +10:00
if avoidSelectById :
uri . disableSelectAtId ( True )
provider = self . dbplugin ( ) . providerName ( )
if layerType == QgsMapLayer . RasterLayer :
2015-11-17 00:10:09 +01:00
return QgsRasterLayer ( uri . uri ( False ) , layerName , provider )
return QgsVectorLayer ( uri . uri ( False ) , layerName , provider )
2015-03-21 10:41:58 +10:00
def registerAllActions ( self , mainWindow ) :
self . registerDatabaseActions ( mainWindow )
self . registerSubPluginActions ( mainWindow )
def registerSubPluginActions ( self , mainWindow ) :
# load plugins!
try :
2017-03-03 20:44:03 +01:00
exec ( u " from . %s .plugins import load " % self . dbplugin ( ) . typeName ( ) , globals ( ) )
2015-03-21 10:41:58 +10:00
except ImportError :
pass
else :
2016-03-21 04:51:10 +01:00
load ( self , mainWindow ) # NOQA
2015-03-21 10:41:58 +10:00
def registerDatabaseActions ( self , mainWindow ) :
action = QAction ( QApplication . translate ( " DBManagerPlugin " , " &Re-connect " ) , self )
mainWindow . registerAction ( action , QApplication . translate ( " DBManagerPlugin " , " &Database " ) ,
self . reconnectActionSlot )
if self . schemas ( ) is not None :
2018-02-13 08:04:32 +10:00
action = QAction ( QApplication . translate ( " DBManagerPlugin " , " &Create Schema… " ) , self )
2015-03-21 10:41:58 +10:00
mainWindow . registerAction ( action , QApplication . translate ( " DBManagerPlugin " , " &Schema " ) ,
self . createSchemaActionSlot )
2018-02-13 08:04:32 +10:00
action = QAction ( QApplication . translate ( " DBManagerPlugin " , " &Delete (Empty) Schema " ) , self )
2015-03-21 10:41:58 +10:00
mainWindow . registerAction ( action , QApplication . translate ( " DBManagerPlugin " , " &Schema " ) ,
self . deleteSchemaActionSlot )
2018-02-13 08:04:32 +10:00
action = QAction ( QApplication . translate ( " DBManagerPlugin " , " Delete Selected Item " ) , self )
2015-03-21 10:41:58 +10:00
mainWindow . registerAction ( action , None , self . deleteActionSlot )
action . setShortcuts ( QKeySequence . Delete )
2018-07-02 10:04:21 +07:00
action = QAction ( QgsApplication . getThemeIcon ( " /mActionCreateTable.svg " ) ,
2018-02-13 08:04:32 +10:00
QApplication . translate ( " DBManagerPlugin " , " &Create Table… " ) , self )
2015-03-21 10:41:58 +10:00
mainWindow . registerAction ( action , QApplication . translate ( " DBManagerPlugin " , " &Table " ) ,
self . createTableActionSlot )
2018-07-02 10:04:21 +07:00
action = QAction ( QgsApplication . getThemeIcon ( " /mActionEditTable.svg " ) ,
2018-02-13 08:04:32 +10:00
QApplication . translate ( " DBManagerPlugin " , " &Edit Table… " ) , self )
2015-03-21 10:41:58 +10:00
mainWindow . registerAction ( action , QApplication . translate ( " DBManagerPlugin " , " &Table " ) , self . editTableActionSlot )
2018-07-02 10:04:21 +07:00
action = QAction ( QgsApplication . getThemeIcon ( " /mActionDeleteTable.svg " ) ,
2018-02-13 15:24:55 +10:00
QApplication . translate ( " DBManagerPlugin " , " &Delete Table/View… " ) , self )
2015-03-21 10:41:58 +10:00
mainWindow . registerAction ( action , QApplication . translate ( " DBManagerPlugin " , " &Table " ) ,
self . deleteTableActionSlot )
2018-02-13 08:04:32 +10:00
action = QAction ( QApplication . translate ( " DBManagerPlugin " , " &Empty Table… " ) , self )
2015-03-21 10:41:58 +10:00
mainWindow . registerAction ( action , QApplication . translate ( " DBManagerPlugin " , " &Table " ) ,
self . emptyTableActionSlot )
if self . schemas ( ) is not None :
2018-02-13 08:04:32 +10:00
action = QAction ( QApplication . translate ( " DBManagerPlugin " , " &Move to Schema " ) , self )
2015-03-21 10:41:58 +10:00
action . setMenu ( QMenu ( mainWindow ) )
2016-03-21 04:51:10 +01:00
def invoke_callback ( ) :
return mainWindow . invokeCallback ( self . prepareMenuMoveTableToSchemaActionSlot )
2016-03-15 23:41:19 +01:00
action . menu ( ) . aboutToShow . connect ( invoke_callback )
2015-03-21 10:41:58 +10:00
mainWindow . registerAction ( action , QApplication . translate ( " DBManagerPlugin " , " &Table " ) )
def reconnectActionSlot ( self , item , action , parent ) :
db = item . database ( )
db . connection ( ) . reconnect ( )
db . refresh ( )
def deleteActionSlot ( self , item , action , parent ) :
if isinstance ( item , Schema ) :
self . deleteSchemaActionSlot ( item , action , parent )
elif isinstance ( item , Table ) :
self . deleteTableActionSlot ( item , action , parent )
else :
QApplication . restoreOverrideCursor ( )
parent . infoBar . pushMessage ( QApplication . translate ( " DBManagerPlugin " , " Cannot delete the selected item. " ) ,
2018-02-05 22:11:34 -04:00
Qgis . Info , parent . iface . messageTimeout ( ) )
2015-03-21 10:41:58 +10:00
QApplication . setOverrideCursor ( Qt . WaitCursor )
def createSchemaActionSlot ( self , item , action , parent ) :
QApplication . restoreOverrideCursor ( )
try :
if not isinstance ( item , ( DBPlugin , Schema , Table ) ) or item . database ( ) is None :
parent . infoBar . pushMessage (
QApplication . translate ( " DBManagerPlugin " , " No database selected or you are not connected to it. " ) ,
2018-02-05 22:11:34 -04:00
Qgis . Info , parent . iface . messageTimeout ( ) )
2015-03-21 10:41:58 +10:00
return
( schema , ok ) = QInputDialog . getText ( parent , QApplication . translate ( " DBManagerPlugin " , " New schema " ) ,
QApplication . translate ( " DBManagerPlugin " , " Enter new schema name " ) )
if not ok :
return
finally :
QApplication . setOverrideCursor ( Qt . WaitCursor )
self . createSchema ( schema )
def deleteSchemaActionSlot ( self , item , action , parent ) :
QApplication . restoreOverrideCursor ( )
try :
if not isinstance ( item , Schema ) :
parent . infoBar . pushMessage (
QApplication . translate ( " DBManagerPlugin " , " Select an empty schema for deletion. " ) ,
2018-02-05 22:11:34 -04:00
Qgis . Info , parent . iface . messageTimeout ( ) )
2015-03-21 10:41:58 +10:00
return
2018-02-13 08:04:32 +10:00
res = QMessageBox . question ( parent , QApplication . translate ( " DBManagerPlugin " , " DB Manager " ) ,
2015-03-21 10:41:58 +10:00
QApplication . translate ( " DBManagerPlugin " ,
2017-03-04 16:23:36 +01:00
" Really delete schema {0} ? " ) . format ( item . name ) ,
2015-03-21 10:41:58 +10:00
QMessageBox . Yes | QMessageBox . No )
if res != QMessageBox . Yes :
return
finally :
QApplication . setOverrideCursor ( Qt . WaitCursor )
item . delete ( )
def schemasFactory ( self , row , db ) :
return None
def schemas ( self ) :
schemas = self . connector . getSchemas ( )
if schemas is not None :
2016-03-21 04:51:10 +01:00
schemas = [ self . schemasFactory ( x , self ) for x in schemas ]
2015-03-21 10:41:58 +10:00
return schemas
def createSchema ( self , name ) :
self . connector . createSchema ( name )
self . refresh ( )
def createTableActionSlot ( self , item , action , parent ) :
QApplication . restoreOverrideCursor ( )
if not hasattr ( item , ' database ' ) or item . database ( ) is None :
parent . infoBar . pushMessage (
QApplication . translate ( " DBManagerPlugin " , " No database selected or you are not connected to it. " ) ,
2018-02-05 22:11:34 -04:00
Qgis . Info , parent . iface . messageTimeout ( ) )
2015-03-21 10:41:58 +10:00
return
from . . dlg_create_table import DlgCreateTable
DlgCreateTable ( item , parent ) . exec_ ( )
QApplication . setOverrideCursor ( Qt . WaitCursor )
def editTableActionSlot ( self , item , action , parent ) :
QApplication . restoreOverrideCursor ( )
try :
if not isinstance ( item , Table ) or item . isView :
2016-12-21 21:06:56 +01:00
parent . infoBar . pushMessage ( QApplication . translate ( " DBManagerPlugin " , " Select a table to edit. " ) ,
2018-02-05 22:11:34 -04:00
Qgis . Info , parent . iface . messageTimeout ( ) )
2015-03-21 10:41:58 +10:00
return
from . . dlg_table_properties import DlgTableProperties
DlgTableProperties ( item , parent ) . exec_ ( )
finally :
QApplication . setOverrideCursor ( Qt . WaitCursor )
def deleteTableActionSlot ( self , item , action , parent ) :
QApplication . restoreOverrideCursor ( )
try :
if not isinstance ( item , Table ) :
parent . infoBar . pushMessage (
QApplication . translate ( " DBManagerPlugin " , " Select a table/view for deletion. " ) ,
2018-02-05 22:11:34 -04:00
Qgis . Info , parent . iface . messageTimeout ( ) )
2015-03-21 10:41:58 +10:00
return
2018-02-13 08:04:32 +10:00
res = QMessageBox . question ( parent , QApplication . translate ( " DBManagerPlugin " , " DB Manager " ) ,
2015-03-21 10:41:58 +10:00
QApplication . translate ( " DBManagerPlugin " ,
2017-03-04 16:23:36 +01:00
" Really delete table/view {0} ? " ) . format ( item . name ) ,
2015-03-21 10:41:58 +10:00
QMessageBox . Yes | QMessageBox . No )
if res != QMessageBox . Yes :
return
finally :
QApplication . setOverrideCursor ( Qt . WaitCursor )
item . delete ( )
def emptyTableActionSlot ( self , item , action , parent ) :
QApplication . restoreOverrideCursor ( )
try :
if not isinstance ( item , Table ) or item . isView :
parent . infoBar . pushMessage ( QApplication . translate ( " DBManagerPlugin " , " Select a table to empty it. " ) ,
2018-02-05 22:11:34 -04:00
Qgis . Info , parent . iface . messageTimeout ( ) )
2015-03-21 10:41:58 +10:00
return
2018-02-13 08:04:32 +10:00
res = QMessageBox . question ( parent , QApplication . translate ( " DBManagerPlugin " , " DB Manager " ) ,
2015-03-21 10:41:58 +10:00
QApplication . translate ( " DBManagerPlugin " ,
2017-03-04 16:23:36 +01:00
" Really delete all items from table {0} ? " ) . format ( item . name ) ,
2015-03-21 10:41:58 +10:00
QMessageBox . Yes | QMessageBox . No )
if res != QMessageBox . Yes :
return
finally :
QApplication . setOverrideCursor ( Qt . WaitCursor )
item . empty ( )
def prepareMenuMoveTableToSchemaActionSlot ( self , item , menu , mainWindow ) :
""" populate menu with schemas """
2016-03-21 04:51:10 +01:00
def slot ( x ) :
return lambda : mainWindow . invokeCallback ( self . moveTableToSchemaActionSlot , x )
2015-03-21 10:41:58 +10:00
menu . clear ( )
for schema in self . schemas ( ) :
menu . addAction ( schema . name , slot ( schema ) )
def moveTableToSchemaActionSlot ( self , item , action , parent , new_schema ) :
QApplication . restoreOverrideCursor ( )
try :
if not isinstance ( item , Table ) :
parent . infoBar . pushMessage ( QApplication . translate ( " DBManagerPlugin " , " Select a table/view. " ) ,
2018-02-05 22:11:34 -04:00
Qgis . Info , parent . iface . messageTimeout ( ) )
2015-03-21 10:41:58 +10:00
return
finally :
QApplication . setOverrideCursor ( Qt . WaitCursor )
item . moveToSchema ( new_schema )
def tablesFactory ( self , row , db , schema = None ) :
typ , row = row [ 0 ] , row [ 1 : ]
if typ == Table . VectorType :
return self . vectorTablesFactory ( row , db , schema )
elif typ == Table . RasterType :
return self . rasterTablesFactory ( row , db , schema )
return self . dataTablesFactory ( row , db , schema )
def dataTablesFactory ( self , row , db , schema = None ) :
return None
def vectorTablesFactory ( self , row , db , schema = None ) :
return None
def rasterTablesFactory ( self , row , db , schema = None ) :
return None
2015-03-30 15:31:19 +02:00
def tables ( self , schema = None , sys_tables = False ) :
tables = self . connector . getTables ( schema . name if schema else None , sys_tables )
2015-03-21 10:41:58 +10:00
if tables is not None :
2016-03-21 04:51:10 +01:00
tables = [ self . tablesFactory ( x , self , schema ) for x in tables ]
2015-03-21 10:41:58 +10:00
return tables
def createTable ( self , table , fields , schema = None ) :
2016-03-21 04:51:10 +01:00
field_defs = [ x . definition ( ) for x in fields ]
pkeys = [ x for x in fields if x . primaryKey ]
2015-03-21 10:41:58 +10:00
pk_name = pkeys [ 0 ] . name if len ( pkeys ) > 0 else None
ret = self . connector . createTable ( ( schema , table ) , field_defs , pk_name )
if ret is not False :
self . refresh ( )
return ret
def createVectorTable ( self , table , fields , geom , schema = None ) :
ret = self . createTable ( table , fields , schema )
if not ret :
return False
try :
createGeomCol = geom is not None
if createGeomCol :
geomCol , geomType , geomSrid , geomDim = geom [ : 4 ]
createSpatialIndex = geom [ 4 ] if len ( geom ) > 4 else False
self . connector . addGeometryColumn ( ( schema , table ) , geomCol , geomType , geomSrid , geomDim )
if createSpatialIndex :
# commit data definition changes, otherwise index can't be built
self . connector . _commit ( )
self . connector . createSpatialIndex ( ( schema , table ) , geomCol )
finally :
self . refresh ( )
return True
2012-04-16 13:19:40 +02:00
2015-08-22 14:29:41 +02:00
def explicitSpatialIndex ( self ) :
2015-03-30 15:31:19 +02:00
return False
2015-08-22 14:29:41 +02:00
def spatialIndexClause ( self , src_table , src_column , dest_table , dest_table_column ) :
2015-03-30 15:31:19 +02:00
return None
2016-10-18 10:49:26 +02:00
def hasLowercaseFieldNamesOption ( self ) :
return False
fix python pep8 warnings and fix some revealed errors
pep8 --ignore=E111,E128,E201,E202,E203,E211,E221,E222,E225,E226,E227,E231,E241,E261,E265,E272,E302,E303,E501,E701 \
--exclude="ui_*.py,debian/*,python/ext-libs/*" \
.
2015-02-01 14:15:42 +01:00
2015-03-21 10:41:58 +10:00
class Schema ( DbItemObject ) :
2015-08-22 14:29:41 +02:00
2015-03-21 10:41:58 +10:00
def __init__ ( self , db ) :
DbItemObject . __init__ ( self , db )
self . oid = self . name = self . owner = self . perms = None
self . comment = None
self . tableCount = 0
fix python pep8 warnings and fix some revealed errors
pep8 --ignore=E111,E128,E201,E202,E203,E211,E221,E222,E225,E226,E227,E231,E241,E261,E265,E272,E302,E303,E501,E701 \
--exclude="ui_*.py,debian/*,python/ext-libs/*" \
.
2015-02-01 14:15:42 +01:00
2015-03-21 10:41:58 +10:00
def __del__ ( self ) :
pass # print "Schema.__del__", self
fix python pep8 warnings and fix some revealed errors
pep8 --ignore=E111,E128,E201,E202,E203,E211,E221,E222,E225,E226,E227,E231,E241,E261,E265,E272,E302,E303,E501,E701 \
--exclude="ui_*.py,debian/*,python/ext-libs/*" \
.
2015-02-01 14:15:42 +01:00
2015-03-21 10:41:58 +10:00
def database ( self ) :
return self . parent ( )
fix python pep8 warnings and fix some revealed errors
pep8 --ignore=E111,E128,E201,E202,E203,E211,E221,E222,E225,E226,E227,E231,E241,E261,E265,E272,E302,E303,E501,E701 \
--exclude="ui_*.py,debian/*,python/ext-libs/*" \
.
2015-02-01 14:15:42 +01:00
2015-03-21 10:41:58 +10:00
def schema ( self ) :
return self
fix python pep8 warnings and fix some revealed errors
pep8 --ignore=E111,E128,E201,E202,E203,E211,E221,E222,E225,E226,E227,E231,E241,E261,E265,E272,E302,E303,E501,E701 \
--exclude="ui_*.py,debian/*,python/ext-libs/*" \
.
2015-02-01 14:15:42 +01:00
2015-03-21 10:41:58 +10:00
def tables ( self ) :
return self . database ( ) . tables ( self )
fix python pep8 warnings and fix some revealed errors
pep8 --ignore=E111,E128,E201,E202,E203,E211,E221,E222,E225,E226,E227,E231,E241,E261,E265,E272,E302,E303,E501,E701 \
--exclude="ui_*.py,debian/*,python/ext-libs/*" \
.
2015-02-01 14:15:42 +01:00
2015-03-21 10:41:58 +10:00
def delete ( self ) :
2016-03-21 04:51:10 +01:00
self . aboutToChange . emit ( )
2015-03-21 10:41:58 +10:00
ret = self . database ( ) . connector . deleteSchema ( self . name )
if ret is not False :
2016-03-15 23:41:19 +01:00
self . deleted . emit ( )
2015-03-21 10:41:58 +10:00
return ret
fix python pep8 warnings and fix some revealed errors
pep8 --ignore=E111,E128,E201,E202,E203,E211,E221,E222,E225,E226,E227,E231,E241,E261,E265,E272,E302,E303,E501,E701 \
--exclude="ui_*.py,debian/*,python/ext-libs/*" \
.
2015-02-01 14:15:42 +01:00
2015-03-21 10:41:58 +10:00
def rename ( self , new_name ) :
2016-03-21 04:51:10 +01:00
self . aboutToChange . emit ( )
2015-03-21 10:41:58 +10:00
ret = self . database ( ) . connector . renameSchema ( self . name , new_name )
if ret is not False :
self . name = new_name
self . refresh ( )
return ret
fix python pep8 warnings and fix some revealed errors
pep8 --ignore=E111,E128,E201,E202,E203,E211,E221,E222,E225,E226,E227,E231,E241,E261,E265,E272,E302,E303,E501,E701 \
--exclude="ui_*.py,debian/*,python/ext-libs/*" \
.
2015-02-01 14:15:42 +01:00
2015-03-21 10:41:58 +10:00
def info ( self ) :
from . info_model import SchemaInfo
fix python pep8 warnings and fix some revealed errors
pep8 --ignore=E111,E128,E201,E202,E203,E211,E221,E222,E225,E226,E227,E231,E241,E261,E265,E272,E302,E303,E501,E701 \
--exclude="ui_*.py,debian/*,python/ext-libs/*" \
.
2015-02-01 14:15:42 +01:00
2015-03-21 10:41:58 +10:00
return SchemaInfo ( self )
fix python pep8 warnings and fix some revealed errors
pep8 --ignore=E111,E128,E201,E202,E203,E211,E221,E222,E225,E226,E227,E231,E241,E261,E265,E272,E302,E303,E501,E701 \
--exclude="ui_*.py,debian/*,python/ext-libs/*" \
.
2015-02-01 14:15:42 +01:00
2015-03-21 10:41:58 +10:00
class Table ( DbItemObject ) :
2016-09-21 18:24:26 +02:00
TableType , VectorType , RasterType = list ( range ( 3 ) )
2015-03-21 10:41:58 +10:00
def __init__ ( self , db , schema = None , parent = None ) :
DbItemObject . __init__ ( self , db )
self . _schema = schema
if hasattr ( self , ' type ' ) :
return
self . type = Table . TableType
self . name = self . isView = self . owner = self . pages = None
self . comment = None
self . rowCount = None
self . _fields = self . _indexes = self . _constraints = self . _triggers = self . _rules = None
def __del__ ( self ) :
pass # print "Table.__del__", self
2015-08-22 14:29:41 +02:00
def canBeAddedToCanvas ( self ) :
2015-03-30 15:31:19 +02:00
return True
2015-03-21 10:41:58 +10:00
def database ( self ) :
return self . parent ( )
def schema ( self ) :
return self . _schema
def schemaName ( self ) :
return self . schema ( ) . name if self . schema ( ) else None
def quotedName ( self ) :
return self . database ( ) . connector . quoteId ( ( self . schemaName ( ) , self . name ) )
def delete ( self ) :
2016-03-21 04:51:10 +01:00
self . aboutToChange . emit ( )
2015-03-21 10:41:58 +10:00
if self . isView :
ret = self . database ( ) . connector . deleteView ( ( self . schemaName ( ) , self . name ) )
else :
ret = self . database ( ) . connector . deleteTable ( ( self . schemaName ( ) , self . name ) )
if ret is not False :
2016-03-15 23:41:19 +01:00
self . deleted . emit ( )
2015-03-21 10:41:58 +10:00
return ret
def rename ( self , new_name ) :
2016-03-21 04:51:10 +01:00
self . aboutToChange . emit ( )
2015-03-21 10:41:58 +10:00
ret = self . database ( ) . connector . renameTable ( ( self . schemaName ( ) , self . name ) , new_name )
if ret is not False :
self . name = new_name
self . refresh ( )
return ret
def empty ( self ) :
2016-03-21 04:51:10 +01:00
self . aboutToChange . emit ( )
2015-03-21 10:41:58 +10:00
ret = self . database ( ) . connector . emptyTable ( ( self . schemaName ( ) , self . name ) )
if ret is not False :
self . refreshRowCount ( )
return ret
def moveToSchema ( self , schema ) :
2016-03-21 04:51:10 +01:00
self . aboutToChange . emit ( )
2015-03-21 10:41:58 +10:00
if self . schema ( ) == schema :
return True
ret = self . database ( ) . connector . moveTableToSchema ( ( self . schemaName ( ) , self . name ) , schema . name )
if ret is not False :
self . schema ( ) . refresh ( )
schema . refresh ( )
return ret
def info ( self ) :
from . info_model import TableInfo
return TableInfo ( self )
def uri ( self ) :
uri = self . database ( ) . uri ( )
schema = self . schemaName ( ) if self . schemaName ( ) else ' '
geomCol = self . geomColumn if self . type in [ Table . VectorType , Table . RasterType ] else " "
2016-07-21 22:01:38 +10:00
uniqueCol = self . getValidQgisUniqueFields ( True ) if self . isView else None
2015-03-21 10:41:58 +10:00
uri . setDataSource ( schema , self . name , geomCol if geomCol else None , None , uniqueCol . name if uniqueCol else " " )
return uri
def mimeUri ( self ) :
layerType = " raster " if self . type == Table . RasterType else " vector "
2015-11-17 00:10:09 +01:00
return u " %s : %s : %s : %s " % ( layerType , self . database ( ) . dbplugin ( ) . providerName ( ) , self . name , self . uri ( ) . uri ( False ) )
2015-03-21 10:41:58 +10:00
def toMapLayer ( self ) :
from qgis . core import QgsVectorLayer , QgsRasterLayer
provider = self . database ( ) . dbplugin ( ) . providerName ( )
2015-11-17 00:10:09 +01:00
uri = self . uri ( ) . uri ( False )
2015-03-21 10:41:58 +10:00
if self . type == Table . RasterType :
return QgsRasterLayer ( uri , self . name , provider )
return QgsVectorLayer ( uri , self . name , provider )
2016-07-21 22:01:38 +10:00
def getValidQgisUniqueFields ( self , onlyOne = False ) :
""" list of fields valid to load the table as layer in Qgis canvas.
Qgis automatically search for a valid unique field , so it ' s
2015-03-21 10:41:58 +10:00
needed only for queries and views """
ret = [ ]
# add the pk
2016-03-21 04:51:10 +01:00
pkcols = [ x for x in self . fields ( ) if x . primaryKey ]
2015-08-22 14:29:41 +02:00
if len ( pkcols ) == 1 :
ret . append ( pkcols [ 0 ] )
2015-03-21 10:41:58 +10:00
# then add both oid, serial and int fields with an unique index
indexes = self . indexes ( )
if indexes is not None :
for idx in indexes :
if idx . isUnique and len ( idx . columns ) == 1 :
fld = idx . fields ( ) [ idx . columns [ 0 ] ]
if fld . dataType in [ " oid " , " serial " , " int4 " , " int8 " ] and fld not in ret :
ret . append ( fld )
# and finally append the other suitable fields
for fld in self . fields ( ) :
if fld . dataType in [ " oid " , " serial " , " int4 " , " int8 " ] and fld not in ret :
ret . append ( fld )
if onlyOne :
return ret [ 0 ] if len ( ret ) > 0 else None
return ret
def tableDataModel ( self , parent ) :
pass
fix python pep8 warnings and fix some revealed errors
pep8 --ignore=E111,E128,E201,E202,E203,E211,E221,E222,E225,E226,E227,E231,E241,E261,E265,E272,E302,E303,E501,E701 \
--exclude="ui_*.py,debian/*,python/ext-libs/*" \
.
2015-02-01 14:15:42 +01:00
2017-10-17 00:28:58 +02:00
def tableFieldsFactory ( self , row , table ) :
raise NotImplementedError ( ' Needs to be implemented by subclasses ' )
2015-03-21 10:41:58 +10:00
def fields ( self ) :
if self . _fields is None :
fields = self . database ( ) . connector . getTableFields ( ( self . schemaName ( ) , self . name ) )
if fields is not None :
2016-03-21 04:51:10 +01:00
self . _fields = [ self . tableFieldsFactory ( x , self ) for x in fields ]
2015-03-21 10:41:58 +10:00
return self . _fields
def refreshFields ( self ) :
self . _fields = None # refresh table fields
self . refresh ( )
def addField ( self , fld ) :
2016-03-21 04:51:10 +01:00
self . aboutToChange . emit ( )
2015-03-21 10:41:58 +10:00
ret = self . database ( ) . connector . addTableColumn ( ( self . schemaName ( ) , self . name ) , fld . definition ( ) )
if ret is not False :
self . refreshFields ( )
return ret
def deleteField ( self , fld ) :
2016-03-21 04:51:10 +01:00
self . aboutToChange . emit ( )
2015-03-21 10:41:58 +10:00
ret = self . database ( ) . connector . deleteTableColumn ( ( self . schemaName ( ) , self . name ) , fld . name )
if ret is not False :
self . refreshFields ( )
self . refreshConstraints ( )
self . refreshIndexes ( )
return ret
def addGeometryColumn ( self , geomCol , geomType , srid , dim , createSpatialIndex = False ) :
2016-03-21 04:51:10 +01:00
self . aboutToChange . emit ( )
2015-03-21 10:41:58 +10:00
ret = self . database ( ) . connector . addGeometryColumn ( ( self . schemaName ( ) , self . name ) , geomCol , geomType , srid , dim )
if not ret :
return False
try :
if createSpatialIndex :
# commit data definition changes, otherwise index can't be built
self . database ( ) . connector . _commit ( )
self . database ( ) . connector . createSpatialIndex ( ( self . schemaName ( ) , self . name ) , geomCol )
finally :
self . schema ( ) . refresh ( ) if self . schema ( ) else self . database ( ) . refresh ( ) # another table was added
return True
def tableConstraintsFactory ( self ) :
return None
def constraints ( self ) :
if self . _constraints is None :
constraints = self . database ( ) . connector . getTableConstraints ( ( self . schemaName ( ) , self . name ) )
if constraints is not None :
2016-03-21 04:51:10 +01:00
self . _constraints = [ self . tableConstraintsFactory ( x , self ) for x in constraints ]
2015-03-21 10:41:58 +10:00
return self . _constraints
def refreshConstraints ( self ) :
self . _constraints = None # refresh table constraints
self . refresh ( )
def addConstraint ( self , constr ) :
2016-03-21 04:51:10 +01:00
self . aboutToChange . emit ( )
2015-03-21 10:41:58 +10:00
if constr . type == TableConstraint . TypePrimaryKey :
ret = self . database ( ) . connector . addTablePrimaryKey ( ( self . schemaName ( ) , self . name ) ,
constr . fields ( ) [ constr . columns [ 0 ] ] . name )
elif constr . type == TableConstraint . TypeUnique :
ret = self . database ( ) . connector . addTableUniqueConstraint ( ( self . schemaName ( ) , self . name ) ,
constr . fields ( ) [ constr . columns [ 0 ] ] . name )
else :
return False
if ret is not False :
self . refreshConstraints ( )
return ret
def deleteConstraint ( self , constr ) :
2016-03-21 04:51:10 +01:00
self . aboutToChange . emit ( )
2015-03-21 10:41:58 +10:00
ret = self . database ( ) . connector . deleteTableConstraint ( ( self . schemaName ( ) , self . name ) , constr . name )
if ret is not False :
self . refreshConstraints ( )
return ret
def tableIndexesFactory ( self ) :
return None
def indexes ( self ) :
if self . _indexes is None :
indexes = self . database ( ) . connector . getTableIndexes ( ( self . schemaName ( ) , self . name ) )
if indexes is not None :
2016-03-21 04:51:10 +01:00
self . _indexes = [ self . tableIndexesFactory ( x , self ) for x in indexes ]
2015-03-21 10:41:58 +10:00
return self . _indexes
def refreshIndexes ( self ) :
self . _indexes = None # refresh table indexes
self . refresh ( )
def addIndex ( self , idx ) :
2016-03-21 04:51:10 +01:00
self . aboutToChange . emit ( )
2015-03-21 10:41:58 +10:00
ret = self . database ( ) . connector . createTableIndex ( ( self . schemaName ( ) , self . name ) , idx . name ,
idx . fields ( ) [ idx . columns [ 0 ] ] . name )
if ret is not False :
self . refreshIndexes ( )
return ret
def deleteIndex ( self , idx ) :
2016-03-21 04:51:10 +01:00
self . aboutToChange . emit ( )
2015-03-21 10:41:58 +10:00
ret = self . database ( ) . connector . deleteTableIndex ( ( self . schemaName ( ) , self . name ) , idx . name )
if ret is not False :
self . refreshIndexes ( )
return ret
def tableTriggersFactory ( self , row , table ) :
return None
def triggers ( self ) :
if self . _triggers is None :
triggers = self . database ( ) . connector . getTableTriggers ( ( self . schemaName ( ) , self . name ) )
if triggers is not None :
2016-03-21 04:51:10 +01:00
self . _triggers = [ self . tableTriggersFactory ( x , self ) for x in triggers ]
2015-03-21 10:41:58 +10:00
return self . _triggers
def refreshTriggers ( self ) :
self . _triggers = None # refresh table triggers
self . refresh ( )
def tableRulesFactory ( self , row , table ) :
return None
def rules ( self ) :
if self . _rules is None :
rules = self . database ( ) . connector . getTableRules ( ( self . schemaName ( ) , self . name ) )
if rules is not None :
2016-03-21 04:51:10 +01:00
self . _rules = [ self . tableRulesFactory ( x , self ) for x in rules ]
2015-03-21 10:41:58 +10:00
return self . _rules
def refreshRules ( self ) :
self . _rules = None # refresh table rules
self . refresh ( )
def refreshRowCount ( self ) :
2016-03-21 04:51:10 +01:00
self . aboutToChange . emit ( )
2015-03-21 10:41:58 +10:00
prevRowCount = self . rowCount
try :
self . rowCount = self . database ( ) . connector . getTableRowCount ( ( self . schemaName ( ) , self . name ) )
self . rowCount = int ( self . rowCount ) if self . rowCount is not None else None
except DbError :
self . rowCount = None
if self . rowCount != prevRowCount :
self . refresh ( )
def runAction ( self , action ) :
2016-09-21 18:24:26 +02:00
action = str ( action )
2015-03-21 10:41:58 +10:00
if action . startswith ( " rows/ " ) :
if action == " rows/count " :
self . refreshRowCount ( )
fix python pep8 warnings and fix some revealed errors
pep8 --ignore=E111,E128,E201,E202,E203,E211,E221,E222,E225,E226,E227,E231,E241,E261,E265,E272,E302,E303,E501,E701 \
--exclude="ui_*.py,debian/*,python/ext-libs/*" \
.
2015-02-01 14:15:42 +01:00
return True
2015-03-21 10:41:58 +10:00
elif action . startswith ( " triggers/ " ) :
parts = action . split ( ' / ' )
trigger_action = parts [ 1 ]
2017-03-04 16:23:36 +01:00
msg = QApplication . translate ( " DBManagerPlugin " , " Do you want to {0} all triggers? " ) . format ( trigger_action )
2015-03-21 10:41:58 +10:00
QApplication . restoreOverrideCursor ( )
try :
if QMessageBox . question ( None , QApplication . translate ( " DBManagerPlugin " , " Table triggers " ) , msg ,
QMessageBox . Yes | QMessageBox . No ) == QMessageBox . No :
return False
finally :
QApplication . setOverrideCursor ( Qt . WaitCursor )
fix python pep8 warnings and fix some revealed errors
pep8 --ignore=E111,E128,E201,E202,E203,E211,E221,E222,E225,E226,E227,E231,E241,E261,E265,E272,E302,E303,E501,E701 \
--exclude="ui_*.py,debian/*,python/ext-libs/*" \
.
2015-02-01 14:15:42 +01:00
2015-03-21 10:41:58 +10:00
if trigger_action == " enable " or trigger_action == " disable " :
enable = trigger_action == " enable "
2016-03-21 04:51:10 +01:00
self . aboutToChange . emit ( )
2015-03-21 10:41:58 +10:00
self . database ( ) . connector . enableAllTableTriggers ( enable , ( self . schemaName ( ) , self . name ) )
self . refreshTriggers ( )
return True
fix python pep8 warnings and fix some revealed errors
pep8 --ignore=E111,E128,E201,E202,E203,E211,E221,E222,E225,E226,E227,E231,E241,E261,E265,E272,E302,E303,E501,E701 \
--exclude="ui_*.py,debian/*,python/ext-libs/*" \
.
2015-02-01 14:15:42 +01:00
2015-03-21 10:41:58 +10:00
elif action . startswith ( " trigger/ " ) :
parts = action . split ( ' / ' )
trigger_name = parts [ 1 ]
trigger_action = parts [ 2 ]
2017-03-04 16:23:36 +01:00
msg = QApplication . translate ( " DBManagerPlugin " , " Do you want to {0} trigger {1} ? " ) . format (
2015-04-07 14:27:39 +02:00
trigger_action , trigger_name )
2015-03-21 10:41:58 +10:00
QApplication . restoreOverrideCursor ( )
try :
if QMessageBox . question ( None , QApplication . translate ( " DBManagerPlugin " , " Table trigger " ) , msg ,
QMessageBox . Yes | QMessageBox . No ) == QMessageBox . No :
return False
finally :
QApplication . setOverrideCursor ( Qt . WaitCursor )
fix python pep8 warnings and fix some revealed errors
pep8 --ignore=E111,E128,E201,E202,E203,E211,E221,E222,E225,E226,E227,E231,E241,E261,E265,E272,E302,E303,E501,E701 \
--exclude="ui_*.py,debian/*,python/ext-libs/*" \
.
2015-02-01 14:15:42 +01:00
2015-03-21 10:41:58 +10:00
if trigger_action == " delete " :
2016-03-21 04:51:10 +01:00
self . aboutToChange . emit ( )
2015-03-21 10:41:58 +10:00
self . database ( ) . connector . deleteTableTrigger ( trigger_name , ( self . schemaName ( ) , self . name ) )
self . refreshTriggers ( )
return True
fix python pep8 warnings and fix some revealed errors
pep8 --ignore=E111,E128,E201,E202,E203,E211,E221,E222,E225,E226,E227,E231,E241,E261,E265,E272,E302,E303,E501,E701 \
--exclude="ui_*.py,debian/*,python/ext-libs/*" \
.
2015-02-01 14:15:42 +01:00
2015-03-21 10:41:58 +10:00
elif trigger_action == " enable " or trigger_action == " disable " :
enable = trigger_action == " enable "
2016-03-21 04:51:10 +01:00
self . aboutToChange . emit ( )
2015-03-21 10:41:58 +10:00
self . database ( ) . connector . enableTableTrigger ( trigger_name , enable , ( self . schemaName ( ) , self . name ) )
self . refreshTriggers ( )
return True
fix python pep8 warnings and fix some revealed errors
pep8 --ignore=E111,E128,E201,E202,E203,E211,E221,E222,E225,E226,E227,E231,E241,E261,E265,E272,E302,E303,E501,E701 \
--exclude="ui_*.py,debian/*,python/ext-libs/*" \
.
2015-02-01 14:15:42 +01:00
2015-03-21 10:41:58 +10:00
return False
fix python pep8 warnings and fix some revealed errors
pep8 --ignore=E111,E128,E201,E202,E203,E211,E221,E222,E225,E226,E227,E231,E241,E261,E265,E272,E302,E303,E501,E701 \
--exclude="ui_*.py,debian/*,python/ext-libs/*" \
.
2015-02-01 14:15:42 +01:00
2015-03-21 10:41:58 +10:00
class VectorTable ( Table ) :
2015-08-22 14:29:41 +02:00
2015-03-21 10:41:58 +10:00
def __init__ ( self , db , schema = None , parent = None ) :
if not hasattr ( self , ' type ' ) : # check if the superclass constructor was called yet!
Table . __init__ ( self , db , schema , parent )
self . type = Table . VectorType
self . geomColumn = self . geomType = self . geomDim = self . srid = None
self . estimatedExtent = self . extent = None
def info ( self ) :
from . info_model import VectorTableInfo
return VectorTableInfo ( self )
def hasSpatialIndex ( self , geom_column = None ) :
geom_column = geom_column if geom_column is not None else self . geomColumn
fld = None
for fld in self . fields ( ) :
if fld . name == geom_column :
break
if fld is None :
return False
for idx in self . indexes ( ) :
if fld . num in idx . columns :
return True
return False
def createSpatialIndex ( self , geom_column = None ) :
2016-03-21 04:51:10 +01:00
self . aboutToChange . emit ( )
2015-03-21 10:41:58 +10:00
geom_column = geom_column if geom_column is not None else self . geomColumn
ret = self . database ( ) . connector . createSpatialIndex ( ( self . schemaName ( ) , self . name ) , geom_column )
if ret is not False :
self . refreshIndexes ( )
return ret
def deleteSpatialIndex ( self , geom_column = None ) :
2016-03-21 04:51:10 +01:00
self . aboutToChange . emit ( )
2015-03-21 10:41:58 +10:00
geom_column = geom_column if geom_column is not None else self . geomColumn
ret = self . database ( ) . connector . deleteSpatialIndex ( ( self . schemaName ( ) , self . name ) , geom_column )
if ret is not False :
self . refreshIndexes ( )
return ret
def refreshTableExtent ( self ) :
prevExtent = self . extent
try :
self . extent = self . database ( ) . connector . getTableExtent ( ( self . schemaName ( ) , self . name ) , self . geomColumn )
except DbError :
self . extent = None
if self . extent != prevExtent :
self . refresh ( )
def refreshTableEstimatedExtent ( self ) :
prevEstimatedExtent = self . estimatedExtent
try :
self . estimatedExtent = self . database ( ) . connector . getTableEstimatedExtent ( ( self . schemaName ( ) , self . name ) ,
self . geomColumn )
except DbError :
self . estimatedExtent = None
if self . estimatedExtent != prevEstimatedExtent :
self . refresh ( )
def runAction ( self , action ) :
2016-09-21 18:24:26 +02:00
action = str ( action )
2015-03-21 10:41:58 +10:00
if action . startswith ( " spatialindex/ " ) :
parts = action . split ( ' / ' )
spatialIndex_action = parts [ 1 ]
2017-03-04 16:23:36 +01:00
msg = QApplication . translate ( " DBManagerPlugin " , " Do you want to {0} spatial index for field {1} ? " ) . format (
2015-08-22 14:29:41 +02:00
spatialIndex_action , self . geomColumn )
2015-03-21 10:41:58 +10:00
QApplication . restoreOverrideCursor ( )
try :
if QMessageBox . question ( None , QApplication . translate ( " DBManagerPlugin " , " Spatial Index " ) , msg ,
QMessageBox . Yes | QMessageBox . No ) == QMessageBox . No :
return False
finally :
QApplication . setOverrideCursor ( Qt . WaitCursor )
fix python pep8 warnings and fix some revealed errors
pep8 --ignore=E111,E128,E201,E202,E203,E211,E221,E222,E225,E226,E227,E231,E241,E261,E265,E272,E302,E303,E501,E701 \
--exclude="ui_*.py,debian/*,python/ext-libs/*" \
.
2015-02-01 14:15:42 +01:00
2015-03-21 10:41:58 +10:00
if spatialIndex_action == " create " :
self . createSpatialIndex ( )
return True
elif spatialIndex_action == " delete " :
self . deleteSpatialIndex ( )
return True
fix python pep8 warnings and fix some revealed errors
pep8 --ignore=E111,E128,E201,E202,E203,E211,E221,E222,E225,E226,E227,E231,E241,E261,E265,E272,E302,E303,E501,E701 \
--exclude="ui_*.py,debian/*,python/ext-libs/*" \
.
2015-02-01 14:15:42 +01:00
2015-03-21 10:41:58 +10:00
if action . startswith ( " extent/ " ) :
if action == " extent/get " :
self . refreshTableExtent ( )
return True
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
if action == " extent/estimated/get " :
self . refreshTableEstimatedExtent ( )
return True
fix python pep8 warnings and fix some revealed errors
pep8 --ignore=E111,E128,E201,E202,E203,E211,E221,E222,E225,E226,E227,E231,E241,E261,E265,E272,E302,E303,E501,E701 \
--exclude="ui_*.py,debian/*,python/ext-libs/*" \
.
2015-02-01 14:15:42 +01:00
2015-03-21 10:41:58 +10:00
return Table . runAction ( self , action )
2012-04-16 13:19:40 +02:00
class RasterTable ( Table ) :
2015-08-22 14:29:41 +02:00
2015-03-21 10:41:58 +10:00
def __init__ ( self , db , schema = None , parent = None ) :
if not hasattr ( self , ' type ' ) : # check if the superclass constructor was called yet!
Table . __init__ ( self , db , schema , parent )
self . type = Table . RasterType
self . geomColumn = self . geomType = self . pixelSizeX = self . pixelSizeY = self . pixelType = self . isExternal = self . srid = None
self . extent = None
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
def info ( self ) :
from . info_model import RasterTableInfo
return RasterTableInfo ( self )
2012-04-16 13:19:40 +02:00
class TableSubItemObject ( QObject ) :
2015-08-22 14:29:41 +02:00
2015-03-21 10:41:58 +10:00
def __init__ ( self , table ) :
QObject . __init__ ( self , table )
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
def table ( self ) :
return self . parent ( )
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
def database ( self ) :
return self . table ( ) . database ( ) if self . table ( ) else None
2012-04-16 13:19:40 +02:00
class TableField ( TableSubItemObject ) :
2015-08-22 14:29:41 +02:00
2015-03-21 10:41:58 +10:00
def __init__ ( self , table ) :
TableSubItemObject . __init__ ( self , table )
self . num = self . name = self . dataType = self . modifier = self . notNull = self . default = self . hasDefault = self . primaryKey = None
self . comment = None
def type2String ( self ) :
if self . modifier is None or self . modifier == - 1 :
return u " %s " % self . dataType
return u " %s ( %s ) " % ( self . dataType , self . modifier )
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
def default2String ( self ) :
if not self . hasDefault :
return ' '
return self . default if self . default is not None else " NULL "
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
def definition ( self ) :
from . connector import DBConnector
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
quoteIdFunc = self . database ( ) . connector . quoteId if self . database ( ) else DBConnector . quoteId
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
name = quoteIdFunc ( self . name )
not_null = " NOT NULL " if self . notNull else " "
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
txt = u " %s %s %s " % ( name , self . type2String ( ) , not_null )
if self . hasDefault :
txt + = u " DEFAULT %s " % self . default2String ( )
return txt
2012-04-16 13:19:40 +02:00
2019-01-10 16:46:55 +01:00
def getComment ( self ) :
2019-01-11 10:36:14 +01:00
""" Returns the comment for a field """
2019-01-10 16:46:55 +01:00
tab = self . table ( )
2019-01-11 11:10:02 +01:00
# SQL Query checking if a comment exists for the field
sql_cpt = " Select count(*) from pg_description pd, pg_class pc, pg_attribute pa where relname = ' %s ' and attname = ' %s ' and pa.attrelid = pc.oid and pd.objoid = pc.oid and pd.objsubid = pa.attnum " % ( tab . name , self . name )
# SQL Query that return the comment of the field
sql = " Select pd.description from pg_description pd, pg_class pc, pg_attribute pa where relname = ' %s ' and attname = ' %s ' and pa.attrelid = pc.oid and pd.objoid = pc.oid and pd.objsubid = pa.attnum " % ( tab . name , self . name )
c = tab . database ( ) . connector . _execute ( None , sql_cpt ) # Execute Check query
res = tab . database ( ) . connector . _fetchone ( c ) [ 0 ] # Store result
if res == 1 :
2019-01-10 16:46:55 +01:00
# When a comment exists
2019-01-11 11:10:02 +01:00
c = tab . database ( ) . connector . _execute ( None , sql ) # Execute query
res = tab . database ( ) . connector . _fetchone ( c ) [ 0 ] # Store result
tab . database ( ) . connector . _close_cursor ( c ) # Close cursor
return res # Return comment
2019-01-10 16:46:55 +01:00
else :
2019-01-11 10:36:00 +01:00
return ' '
2019-01-10 16:46:55 +01:00
2015-03-21 10:41:58 +10:00
def delete ( self ) :
return self . table ( ) . deleteField ( self )
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
def rename ( self , new_name ) :
return self . update ( new_name )
2012-04-16 13:19:40 +02:00
2019-01-10 16:46:55 +01:00
def update ( self , new_name , new_type_str = None , new_not_null = None , new_default_str = None , new_comment = None ) :
2016-06-11 16:57:08 +02:00
self . table ( ) . aboutToChange . emit ( )
2015-08-22 14:29:41 +02:00
if self . name == new_name :
new_name = None
if self . type2String ( ) == new_type_str :
new_type_str = None
if self . notNull == new_not_null :
new_not_null = None
if self . default2String ( ) == new_default_str :
new_default_str = None
2019-01-10 16:46:55 +01:00
if self . comment == new_comment :
# Update also a new_comment
new_comment = None
2015-03-21 10:41:58 +10:00
ret = self . table ( ) . database ( ) . connector . updateTableColumn ( ( self . table ( ) . schemaName ( ) , self . table ( ) . name ) ,
2019-01-11 14:30:10 +01:00
self . name , new_name , new_type_str ,
new_not_null , new_default_str , new_comment )
2015-03-21 10:41:58 +10:00
if ret is not False :
self . table ( ) . refreshFields ( )
return ret
2012-04-16 13:19:40 +02:00
class TableConstraint ( TableSubItemObject ) :
2015-08-22 14:29:41 +02:00
2015-03-21 10:41:58 +10:00
""" class that represents a constraint of a table (relation) """
2012-12-10 00:12:07 +01:00
2016-09-21 18:24:26 +02:00
TypeCheck , TypeForeignKey , TypePrimaryKey , TypeUnique , TypeExclusion , TypeUnknown = list ( range ( 6 ) )
2015-03-21 10:41:58 +10:00
types = { " c " : TypeCheck , " f " : TypeForeignKey , " p " : TypePrimaryKey , " u " : TypeUnique , " x " : TypeExclusion }
2012-12-10 00:12:07 +01:00
2015-03-21 10:41:58 +10:00
onAction = { " a " : " NO ACTION " , " r " : " RESTRICT " , " c " : " CASCADE " , " n " : " SET NULL " , " d " : " SET DEFAULT " }
matchTypes = { " u " : " UNSPECIFIED " , " f " : " FULL " , " p " : " PARTIAL " , " s " : " SIMPLE " }
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
def __init__ ( self , table ) :
TableSubItemObject . __init__ ( self , table )
self . name = self . type = self . columns = None
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
def type2String ( self ) :
2015-08-22 14:29:41 +02:00
if self . type == TableConstraint . TypeCheck :
return QApplication . translate ( " DBManagerPlugin " , " Check " )
if self . type == TableConstraint . TypePrimaryKey :
return QApplication . translate ( " DBManagerPlugin " , " Primary key " )
if self . type == TableConstraint . TypeForeignKey :
return QApplication . translate ( " DBManagerPlugin " , " Foreign key " )
if self . type == TableConstraint . TypeUnique :
return QApplication . translate ( " DBManagerPlugin " , " Unique " )
if self . type == TableConstraint . TypeExclusion :
return QApplication . translate ( " DBManagerPlugin " , " Exclusion " )
2015-03-21 10:41:58 +10:00
return QApplication . translate ( " DBManagerPlugin " , ' Unknown ' )
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
def fields ( self ) :
def fieldFromNum ( num , fields ) :
""" return field specified by its number or None if doesn ' t exist """
for fld in fields :
if fld . num == num :
return fld
return None
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
fields = self . table ( ) . fields ( )
cols = { }
for num in self . columns :
cols [ num ] = fieldFromNum ( num , fields )
return cols
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
def delete ( self ) :
return self . table ( ) . deleteConstraint ( self )
2012-04-16 13:19:40 +02:00
class TableIndex ( TableSubItemObject ) :
2015-08-22 14:29:41 +02:00
2015-03-21 10:41:58 +10:00
def __init__ ( self , table ) :
TableSubItemObject . __init__ ( self , table )
self . name = self . columns = self . isUnique = None
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
def fields ( self ) :
def fieldFromNum ( num , fields ) :
""" return field specified by its number or None if doesn ' t exist """
for fld in fields :
2015-08-22 14:29:41 +02:00
if fld . num == num :
return fld
2015-03-21 10:41:58 +10:00
return None
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
fields = self . table ( ) . fields ( )
cols = { }
for num in self . columns :
cols [ num ] = fieldFromNum ( num , fields )
return cols
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
def delete ( self ) :
return self . table ( ) . deleteIndex ( self )
2012-04-16 13:19:40 +02:00
class TableTrigger ( TableSubItemObject ) :
2015-08-22 14:29:41 +02:00
2015-03-21 10:41:58 +10:00
""" class that represents a trigger """
# Bits within tgtype (pg_trigger.h)
TypeRow = ( 1 << 0 ) # row or statement
TypeBefore = ( 1 << 1 ) # before or after
# events: one or more
TypeInsert = ( 1 << 2 )
TypeDelete = ( 1 << 3 )
TypeUpdate = ( 1 << 4 )
TypeTruncate = ( 1 << 5 )
def __init__ ( self , table ) :
TableSubItemObject . __init__ ( self , table )
self . name = self . function = None
def type2String ( self ) :
trig_type = u ' '
trig_type + = " Before " if self . type & TableTrigger . TypeBefore else " After "
2015-08-22 14:29:41 +02:00
if self . type & TableTrigger . TypeInsert :
trig_type + = " INSERT "
if self . type & TableTrigger . TypeUpdate :
trig_type + = " UPDATE "
if self . type & TableTrigger . TypeDelete :
trig_type + = " DELETE "
if self . type & TableTrigger . TypeTruncate :
trig_type + = " TRUNCATE "
2015-03-21 10:41:58 +10:00
trig_type + = " \n "
trig_type + = " for each "
trig_type + = " row " if self . type & TableTrigger . TypeRow else " statement "
return trig_type
2012-04-16 13:19:40 +02:00
class TableRule ( TableSubItemObject ) :
2015-08-22 14:29:41 +02:00
2015-03-21 10:41:58 +10:00
def __init__ ( self , table ) :
TableSubItemObject . __init__ ( self , table )
self . name = self . definition = None