File indexing completed on 2025-02-02 04:56:53
0001 /*************************************************************************** 0002 * SPDX-FileCopyrightText: 2022 S. MANKOWSKI stephane@mankowski.fr 0003 * SPDX-FileCopyrightText: 2022 G. DE BURE support@mankowski.fr 0004 * SPDX-License-Identifier: GPL-3.0-or-later 0005 ***************************************************************************/ 0006 /** @file 0007 * This file is a plugin for debug. 0008 * 0009 * @author Stephane MANKOWSKI / Guillaume DE BURE 0010 */ 0011 #include "skgdebugpluginwidget.h" 0012 0013 #include <qdom.h> 0014 #include <qjsengine.h> 0015 #include <qscriptengine.h> 0016 0017 #include "skgdocument.h" 0018 #include "skgmainpanel.h" 0019 #include "skgservices.h" 0020 #include "skgtraces.h" 0021 #include "skgtransactionmng.h" 0022 0023 SKGDebugPluginWidget::SKGDebugPluginWidget(QWidget* iParent, SKGDocument* iDocument) 0024 : SKGTabPage(iParent, iDocument) 0025 { 0026 SKGTRACEINFUNC(10) 0027 if (iDocument == nullptr) { 0028 return; 0029 } 0030 0031 ui.setupUi(this); 0032 0033 // Set icons 0034 ui.kSQLPushButton->setIcon(SKGServices::fromTheme(QStringLiteral("system-run"))); 0035 ui.kSQLTransactionPushButton->setIcon(SKGServices::fromTheme(QStringLiteral("system-run"))); 0036 ui.kRefreshViewsAndIndexes->setIcon(SKGServices::fromTheme(QStringLiteral("view-refresh"))); 0037 0038 // Fill combo box 0039 ui.kExplainCmb->addItem(SKGServices::fromTheme(QStringLiteral("system-run")), i18nc("Execute an SQL query", "Execute")); 0040 ui.kExplainCmb->addItem(SKGServices::fromTheme(QStringLiteral("system-run")), i18nc("Execute an SQL queries (one per line)", "Execute multi queries")); 0041 ui.kExplainCmb->addItem(SKGServices::fromTheme(QStringLiteral("help-hint")), i18nc("Explain an SQL query", "Explain")); 0042 ui.kExplainCmb->addItem(SKGServices::fromTheme(QStringLiteral("games-hint")), i18nc("Explain the SQL query plan", "Explain query plan")); 0043 ui.kExplainCmb->addItem(SKGServices::fromTheme(QStringLiteral("media-playback-start")), i18nc("Execute script", "Execute script [%1]", "javascript")); 0044 ui.kInput->setVisible(false); 0045 0046 // Set level trace 0047 ui.kTraceLevel->setValue(SKGTraces::SKGLevelTrace); 0048 0049 // Set profiling mode 0050 ui.kEnableProfilingChk->setCheckState(SKGTraces::SKGPerfo ? Qt::Checked : Qt::Unchecked); 0051 0052 // Init debug page 0053 QStringList tables; 0054 ui.kSQLInput->addItem(QStringLiteral("SELECT * FROM sqlite_master;")); 0055 iDocument->getDistinctValues(QStringLiteral("sqlite_master"), QStringLiteral("name"), QStringLiteral("type in ('table', 'view')"), tables); 0056 int nb = tables.count(); 0057 for (int i = 0; i < nb; ++i) { 0058 ui.kSQLInput->addItem("SELECT * FROM " % tables.at(i) % ';'); 0059 } 0060 ui.kSQLInput->addItem(QStringLiteral("ANALYZE;")); 0061 ui.kSQLInput->addItem(QStringLiteral("PRAGMA integrity_check;")); 0062 for (int i = 0; i < nb; ++i) { 0063 ui.kSQLInput->addItem("PRAGMA table_info(" % tables.at(i) % ");"); 0064 ui.kSQLInput->addItem("PRAGMA index_list(" % tables.at(i) % ");"); 0065 } 0066 0067 iDocument->getDistinctValues(QStringLiteral("sqlite_master"), QStringLiteral("name"), QStringLiteral("type='index'"), tables); 0068 nb = tables.count(); 0069 for (int i = 0; i < nb; ++i) { 0070 ui.kSQLInput->addItem("PRAGMA index_info(" % tables.at(i) % ");"); 0071 } 0072 connect(ui.kTraceLevel, &QSlider::valueChanged, this, &SKGDebugPluginWidget::onTraceLevelModified); 0073 connect(ui.kEnableProfilingChk, &QCheckBox::stateChanged, this, &SKGDebugPluginWidget::onProfilingModeChanged); 0074 connect(ui.kExplainCmb, static_cast<void (SKGComboBox::*)(int)>(&SKGComboBox::currentIndexChanged), this, &SKGDebugPluginWidget::onModeChanged); 0075 connect(ui.kSQLPushButton, &QPushButton::clicked, this, &SKGDebugPluginWidget::onExecuteSqlOrder); 0076 connect(ui.kSQLTransactionPushButton, &QPushButton::clicked, this, &SKGDebugPluginWidget::onExecuteSqlOrderInTransaction); 0077 connect(ui.kRefreshViewsAndIndexes, &QPushButton::clicked, this, &SKGDebugPluginWidget::onRefreshViewsAndIndexes); 0078 } 0079 0080 SKGDebugPluginWidget::~SKGDebugPluginWidget() 0081 { 0082 SKGTRACEINFUNC(10) 0083 } 0084 0085 QString SKGDebugPluginWidget::getState() 0086 { 0087 SKGTRACEINFUNC(10) 0088 QDomDocument doc(QStringLiteral("SKGML")); 0089 QDomElement root = doc.createElement(QStringLiteral("parameters")); 0090 doc.appendChild(root); 0091 0092 root.setAttribute(QStringLiteral("explain"), ui.kExplainCmb->currentIndex()); 0093 root.setAttribute(QStringLiteral("enableProfiling"), ui.kEnableProfilingChk->checkState() == Qt::Checked ? QStringLiteral("Y") : QStringLiteral("N")); 0094 root.setAttribute(QStringLiteral("levelTraces"), ui.kTraceLevel->value()); 0095 root.setAttribute(QStringLiteral("sqlOrder"), ui.kSQLInput->currentText()); 0096 0097 return doc.toString(); 0098 } 0099 0100 void SKGDebugPluginWidget::setState(const QString& iState) 0101 { 0102 SKGTRACEINFUNC(10) 0103 QDomDocument doc(QStringLiteral("SKGML")); 0104 doc.setContent(iState); 0105 QDomElement root = doc.documentElement(); 0106 0107 QString explain = root.attribute(QStringLiteral("explain")); 0108 QString enableProfiling = root.attribute(QStringLiteral("enableProfiling")); 0109 QString levelTraces = root.attribute(QStringLiteral("levelTraces")); 0110 QString sqlOrder = root.attribute(QStringLiteral("sqlOrder")); 0111 QString sqlResult = root.attribute(QStringLiteral("sqlResult")); 0112 0113 if (!explain.isEmpty()) { 0114 ui.kExplainCmb->setCurrentIndex(SKGServices::stringToInt(explain == QStringLiteral("Y") ? QStringLiteral("1") : explain)); 0115 } 0116 if (!enableProfiling.isEmpty()) { 0117 ui.kEnableProfilingChk->setCheckState(enableProfiling == QStringLiteral("Y") ? Qt::Checked : Qt::Unchecked); 0118 } 0119 if (!levelTraces.isEmpty()) { 0120 ui.kTraceLevel->setValue(SKGServices::stringToInt(levelTraces)); 0121 } 0122 ui.kSQLInput->setText(sqlOrder); 0123 ui.kSQLResult->setPlainText(sqlResult); 0124 } 0125 0126 void SKGDebugPluginWidget::onExecuteSqlOrderInTransaction() 0127 { 0128 onExecuteSqlOrder(true); 0129 } 0130 0131 SKGError SKGDebugPluginWidget::executeSqlOrders(const QStringList& iSQL, QString& oOutput) 0132 { 0133 SKGError err; 0134 int nb = iSQL.count(); 0135 for (int i = 0; i < nb; ++i) { 0136 auto sql = iSQL[i].trimmed(); 0137 if (!sql.isEmpty()) { 0138 oOutput += sql + '\n'; 0139 0140 QString oResult; 0141 double time = SKGServices::getMicroTime(); 0142 err = getDocument()->dumpSelectSqliteOrder(sql, oResult); 0143 time = SKGServices::getMicroTime() - time; 0144 0145 oOutput += oResult; 0146 oOutput += i18nc("Display the execution time needed by an SQL query", "\nExecution time: %1 ms", SKGServices::doubleToString(time)); 0147 oOutput += "\n\n"; 0148 } 0149 } 0150 0151 IFKO(err) { 0152 oOutput += err.getFullMessageWithHistorical(); 0153 } 0154 return err; 0155 } 0156 0157 void SKGDebugPluginWidget::onExecuteSqlOrder(bool iInTransaction) 0158 { 0159 SKGTRACEINFUNC(10) 0160 SKGError err; 0161 int exp = ui.kExplainCmb->currentIndex(); 0162 if (exp == 4) { 0163 // Script execution 0164 ui.kSQLResult->clear(); 0165 QJSEngine myEngine; 0166 // skgresult.setText(skgdocument.getUniqueIdentifier()) 0167 // skgerror=skgdocument.sendMessage(QStringLiteral("Hello")) 0168 // skgerror=skgdocument.sendMessage(QStringLiteral("Hello")) 0169 // skgmainpanel.closeAllOtherPages(skgmainpanel.currentPage()) 0170 auto t = myEngine.globalObject(); 0171 t.setProperty(QStringLiteral("skgresult"), myEngine.newQObject(ui.kSQLResult)); 0172 t.setProperty(QStringLiteral("skgdocument"), myEngine.newQObject(getDocument())); 0173 // t.setProperty(QStringLiteral("skgerror"), myEngine.newQObject(&err)); 0174 t.setProperty(QStringLiteral("skgmainpanel"), myEngine.newQObject(SKGMainPanel::getMainPanel())); 0175 0176 // Finally execute the scripting code. 0177 myEngine.evaluate(ui.kInput->toPlainText()); 0178 } else if (exp == 1) { 0179 // SQL multi lines 0180 auto sqls = ui.kInput->toPlainText().split('\n'); 0181 QString oResultGlobal; 0182 if (iInTransaction) { 0183 SKGBEGINTRANSACTION(*getDocument(), i18nc("Display an SQL command from the debug plugin", "SQL command from debug plugin"), err) 0184 IFOKDO(err, err = SKGDebugPluginWidget::executeSqlOrders(sqls, oResultGlobal)) 0185 } else { 0186 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); 0187 err = SKGDebugPluginWidget::executeSqlOrders(sqls, oResultGlobal); 0188 QApplication::restoreOverrideCursor(); 0189 } 0190 0191 IFKO(err) { 0192 oResultGlobal += err.getFullMessageWithHistorical(); 0193 } 0194 ui.kSQLResult->setPlainText(oResultGlobal); 0195 } else { 0196 // SQL execution 0197 QString text = ui.kSQLInput->currentText(); 0198 if (exp == 2) { 0199 text = "EXPLAIN " % text; 0200 } else if (exp == 3) { 0201 text = "EXPLAIN QUERY PLAN " % text; 0202 } 0203 QString oResult; 0204 double time = SKGServices::getMicroTime(); 0205 if (iInTransaction) { 0206 SKGBEGINTRANSACTION(*getDocument(), i18nc("Display an SQL command from the debug plugin", "SQL command from debug plugin"), err) 0207 IFOKDO(err, getDocument()->dumpSelectSqliteOrder(text, oResult)) 0208 } else { 0209 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); 0210 err = getDocument()->dumpSelectSqliteOrder(text, oResult); 0211 QApplication::restoreOverrideCursor(); 0212 } 0213 time = SKGServices::getMicroTime() - time; 0214 0215 oResult += i18nc("Display the execution time needed by an SQL query", "\nExecution time: %1 ms", SKGServices::doubleToString(time)); 0216 0217 IFOK(err) { 0218 ui.kSQLResult->setPlainText(oResult); 0219 } else { 0220 ui.kSQLResult->setPlainText(err.getFullMessageWithHistorical()); 0221 } 0222 } 0223 } 0224 0225 void SKGDebugPluginWidget::onTraceLevelModified() 0226 { 0227 SKGTRACEINFUNC(10) 0228 SKGTraces::SKGLevelTrace = ui.kTraceLevel->value(); 0229 } 0230 0231 void SKGDebugPluginWidget::onModeChanged() 0232 { 0233 SKGTRACEINFUNC(10) 0234 int exp = ui.kExplainCmb->currentIndex(); 0235 ui.kInput->setVisible(exp == 4 || exp == 1); 0236 ui.kSQLInput->setVisible(!ui.kInput->isVisible()); 0237 } 0238 0239 void SKGDebugPluginWidget::onProfilingModeChanged() 0240 { 0241 SKGTRACEINFUNC(10) 0242 SKGTraces::SKGPerfo = (ui.kEnableProfilingChk->checkState() == Qt::Checked); 0243 } 0244 0245 void SKGDebugPluginWidget::onRefreshViewsAndIndexes() 0246 { 0247 SKGTRACEINFUNC(10) 0248 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); 0249 SKGError err; 0250 err = getDocument()->refreshViewsIndexesAndTriggers(); 0251 IFKO(err) { 0252 ui.kSQLResult->setPlainText(err.getFullMessageWithHistorical()); 0253 } 0254 QApplication::restoreOverrideCursor(); 0255 } 0256 0257