Merge pull request #6749 from slarosa/db_quey_history_1

[FEATURE][needs-docs] DB Manager: adds SQL query history
This commit is contained in:
Matthias Kuhn 2018-05-07 11:01:47 +02:00 committed by GitHub
commit 9d12b0ad7b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 278 additions and 166 deletions

View File

@ -26,11 +26,11 @@ from builtins import next
from builtins import str from builtins import str
from qgis.PyQt.QtCore import Qt, pyqtSignal from qgis.PyQt.QtCore import Qt, pyqtSignal
from qgis.PyQt.QtWidgets import QDialog, QWidget, QAction, QApplication, QInputDialog, QStyledItemDelegate from qgis.PyQt.QtWidgets import QDialog, QWidget, QAction, QApplication, QInputDialog, QStyledItemDelegate, QTableWidgetItem
from qgis.PyQt.QtGui import QKeySequence, QCursor, QClipboard, QIcon, QStandardItemModel, QStandardItem from qgis.PyQt.QtGui import QKeySequence, QCursor, QClipboard, QIcon, QStandardItemModel, QStandardItem
from qgis.PyQt.Qsci import QsciAPIs from qgis.PyQt.Qsci import QsciAPIs
from qgis.core import QgsProject, QgsApplication, QgsTask from qgis.core import QgsProject, QgsApplication, QgsTask, QgsSettings
from qgis.utils import OverrideCursor from qgis.utils import OverrideCursor
from .db_plugins.plugin import BaseError from .db_plugins.plugin import BaseError
@ -53,19 +53,22 @@ import re
class DlgSqlWindow(QWidget, Ui_Dialog): class DlgSqlWindow(QWidget, Ui_Dialog):
nameChanged = pyqtSignal(str) nameChanged = pyqtSignal(str)
QUERY_HISTORY_LIMIT = 20
def __init__(self, iface, db, parent=None): def __init__(self, iface, db, parent=None):
QWidget.__init__(self, parent) QWidget.__init__(self, parent)
self.mainWindow = parent self.mainWindow = parent
self.iface = iface self.iface = iface
self.db = db self.db = db
self.dbType = db.connection().typeNameString()
self.connectionName = db.connection().connectionName()
self.filter = "" self.filter = ""
self.modelAsync = None self.modelAsync = None
self.allowMultiColumnPk = isinstance(db, PGDatabase) # at the moment only PostgreSQL allows a primary key to span multiple columns, SpatiaLite doesn't self.allowMultiColumnPk = isinstance(db, PGDatabase) # at the moment only PostgreSQL allows a primary key to span multiple columns, SpatiaLite doesn't
self.aliasSubQuery = isinstance(db, PGDatabase) # only PostgreSQL requires subqueries to be aliases self.aliasSubQuery = isinstance(db, PGDatabase) # only PostgreSQL requires subqueries to be aliases
self.setupUi(self) self.setupUi(self)
self.setWindowTitle( self.setWindowTitle(
self.tr(u"{0} - {1} [{2}]").format(self.windowTitle(), db.connection().connectionName(), db.connection().typeNameString())) self.tr(u"{0} - {1} [{2}]").format(self.windowTitle(), self.connectionName, self.dbType))
self.defaultLayerName = 'QueryLayer' self.defaultLayerName = 'QueryLayer'
@ -79,6 +82,17 @@ class DlgSqlWindow(QWidget, Ui_Dialog):
self.editSql.setMarginVisible(True) self.editSql.setMarginVisible(True)
self.initCompleter() self.initCompleter()
settings = QgsSettings()
self.history = settings.value('DB_Manager/queryHistory/' + self.dbType, {self.connectionName: []})
if self.connectionName not in self.history:
self.history[self.connectionName] = []
self.queryHistoryWidget.setVisible(False)
self.queryHistoryTableWidget.verticalHeader().hide()
self.queryHistoryTableWidget.doubleClicked.connect(self.insertQueryInEditor)
self.populateQueryHistory()
self.btnQueryHistory.toggled.connect(self.showHideQueryHistory)
self.btnCancel.setText(self.tr("Cancel (ESC)")) self.btnCancel.setText(self.tr("Cancel (ESC)"))
self.btnCancel.setEnabled(False) self.btnCancel.setEnabled(False)
self.btnCancel.clicked.connect(self.executeSqlCanceled) self.btnCancel.clicked.connect(self.executeSqlCanceled)
@ -140,6 +154,45 @@ class DlgSqlWindow(QWidget, Ui_Dialog):
self.presetName.textChanged.connect(self.nameChanged) self.presetName.textChanged.connect(self.nameChanged)
def insertQueryInEditor(self, item):
sql = item.data(Qt.DisplayRole)
self.editSql.insertText(sql)
def showHideQueryHistory(self, visible):
self.queryHistoryWidget.setVisible(visible)
def populateQueryHistory(self):
self.queryHistoryTableWidget.clearContents()
self.queryHistoryTableWidget.setRowCount(0)
dictlist = self.history[self.connectionName]
if not dictlist:
return
for i in range(len(dictlist)):
self.queryHistoryTableWidget.insertRow(0)
queryItem = QTableWidgetItem(dictlist[i]['query'])
rowsItem = QTableWidgetItem(str(dictlist[i]['rows']))
durationItem = QTableWidgetItem(str(dictlist[i]['secs']))
self.queryHistoryTableWidget.setItem(0, 0, queryItem)
self.queryHistoryTableWidget.setItem(0, 1, rowsItem)
self.queryHistoryTableWidget.setItem(0, 2, durationItem)
self.queryHistoryTableWidget.resizeColumnsToContents()
self.queryHistoryTableWidget.resizeRowsToContents()
def writeQueryHistory(self, sql, affectedRows, secs):
if len(self.history[self.connectionName]) >= self.QUERY_HISTORY_LIMIT:
self.history[self.connectionName].pop(0)
settings = QgsSettings()
self.history[self.connectionName].append({'query': sql,
'rows': affectedRows,
'secs': secs})
settings.setValue('DB_Manager/queryHistory/' + self.dbType, self.history)
self.populateQueryHistory()
def updatePresetsCombobox(self): def updatePresetsCombobox(self):
self.presetCombo.clear() self.presetCombo.clear()
@ -236,12 +289,14 @@ class DlgSqlWindow(QWidget, Ui_Dialog):
quotedCols = [] quotedCols = []
self.viewResult.setModel(model) self.viewResult.setModel(model)
self.lblResult.setText(self.tr("{0} rows, {1:.1f} seconds").format(model.affectedRows(), model.secs())) self.lblResult.setText(self.tr("{0} rows, {1:.3f} seconds").format(model.affectedRows(), model.secs()))
cols = self.viewResult.model().columnNames() cols = self.viewResult.model().columnNames()
for col in cols: for col in cols:
quotedCols.append(self.db.connector.quoteId(col)) quotedCols.append(self.db.connector.quoteId(col))
self.setColumnCombos(cols, quotedCols) self.setColumnCombos(cols, quotedCols)
self.writeQueryHistory(self.modelAsync.task.sql, model.affectedRows(), model.secs())
self.update() self.update()
elif not self.modelAsync.canceled: elif not self.modelAsync.canceled:
DlgDbError.showError(self.modelAsync.error, self) DlgDbError.showError(self.modelAsync.error, self)

View File

@ -19,8 +19,225 @@
<property name="windowTitle"> <property name="windowTitle">
<string>SQL Window</string> <string>SQL Window</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout_2"> <layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QToolButton" name="queryBuilderBtn">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Saved query</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="presetCombo">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Name</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="presetName">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string notr="true"/>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="presetStore">
<property name="text">
<string>Save</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="presetDelete">
<property name="text">
<string>Delete</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0"> <item row="1" column="0">
<widget class="QSplitter" name="splitterHistory">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="handleWidth">
<number>2</number>
</property>
<widget class="QgsCodeEditorSQL" name="editSql"/>
<widget class="QWidget" name="queryHistoryWidget" native="true">
<layout class="QGridLayout" name="gridLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QTableWidget" name="queryHistoryTableWidget">
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<column>
<property name="text">
<string>Query</string>
</property>
</column>
<column>
<property name="text">
<string>Rows affected</string>
</property>
</column>
<column>
<property name="text">
<string>Duration (secs)</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
<item row="2" column="0">
<layout class="QHBoxLayout">
<item>
<widget class="QPushButton" name="btnExecute">
<property name="toolTip">
<string>Execute query (Ctrl+R)</string>
</property>
<property name="text">
<string>Execute</string>
</property>
<property name="shortcut">
<string>Ctrl+R</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblResult">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnCreateView">
<property name="text">
<string>Create a view</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnClear">
<property name="text">
<string>&amp;Clear</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="btnQueryHistory">
<property name="text">
<string>Query History</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item row="3" column="0">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTableView" name="viewResult">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>3</verstretch>
</sizepolicy>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="horizontalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
</widget>
</item>
</layout>
</item>
<item row="4" column="0">
<widget class="QGroupBox" name="loadAsLayerGroup"> <widget class="QGroupBox" name="loadAsLayerGroup">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
@ -233,167 +450,7 @@ unique values</string>
</layout> </layout>
</widget> </widget>
</item> </item>
<item row="0" column="0"> <item row="5" column="0">
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QWidget" name="layoutWidget">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QToolButton" name="queryBuilderBtn">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Saved query</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="presetCombo">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Name</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="presetName">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string notr="true"/>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="presetStore">
<property name="text">
<string>Save</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="presetDelete">
<property name="text">
<string>Delete</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QgsCodeEditorSQL" name="editSql"/>
</item>
<item>
<layout class="QHBoxLayout">
<item>
<widget class="QPushButton" name="btnExecute">
<property name="toolTip">
<string>Execute query (Ctrl+R)</string>
</property>
<property name="text">
<string>Execute</string>
</property>
<property name="shortcut">
<string>Ctrl+R</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblResult">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnCreateView">
<property name="text">
<string>Create a view</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="btnClear">
<property name="text">
<string>&amp;Clear</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="layoutWidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTableView" name="viewResult">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>3</verstretch>
</sizepolicy>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="horizontalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
<item row="4" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_4"> <layout class="QHBoxLayout" name="horizontalLayout_4">
<property name="bottomMargin"> <property name="bottomMargin">
<number>0</number> <number>0</number>