File indexing completed on 2024-05-12 15:27:51
0001 /*************************************************************************** 0002 File : ImportSQLDatabaseWidget.cpp 0003 Project : LabPlot 0004 Description : Datapicker 0005 -------------------------------------------------------------------- 0006 Copyright : (C) 2016 by Ankit Wagadre (wagadre.ankit@gmail.com) 0007 Copyright : (C) 2016-2017 Alexander Semke (alexander.semke@web.de) 0008 0009 ***************************************************************************/ 0010 /*************************************************************************** 0011 * * 0012 * This program is free software; you can redistribute it and/or modify * 0013 * it under the terms of the GNU General Public License as published by * 0014 * the Free Software Foundation; either version 2 of the License, or * 0015 * (at your option) any later version. * 0016 * * 0017 * This program is distributed in the hope that it will be useful, * 0018 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0019 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0020 * GNU General Public License for more details. * 0021 * * 0022 * You should have received a copy of the GNU General Public License * 0023 * along with this program; if not, write to the Free Software * 0024 * Foundation, Inc., 51 Franklin Street, Fifth Floor, * 0025 * Boston, MA 02110-1301 USA * 0026 * * 0027 ***************************************************************************/ 0028 0029 #include "ImportSQLDatabaseWidget.h" 0030 #include "DatabaseManagerDialog.h" 0031 #include "DatabaseManagerWidget.h" 0032 #include "backend/datasources/AbstractDataSource.h" 0033 #include "backend/datasources/filters/AbstractFileFilter.h" 0034 #include "backend/lib/macros.h" 0035 0036 #include <QTimer> 0037 #include <QSqlError> 0038 #include <QSqlQuery> 0039 #include <QSqlRecord> 0040 #include <QStandardItem> 0041 0042 #include <KConfig> 0043 #include <KConfigGroup> 0044 #include <KLocalizedString> 0045 #include <KMessageBox> 0046 #include <KSharedConfig> 0047 #ifdef HAVE_KF5_SYNTAX_HIGHLIGHTING 0048 #include <KF5/KSyntaxHighlighting/SyntaxHighlighter> 0049 #include <KF5/KSyntaxHighlighting/Definition> 0050 #include <KF5/KSyntaxHighlighting/Theme> 0051 #endif 0052 0053 ImportSQLDatabaseWidget::ImportSQLDatabaseWidget(QWidget* parent) : QWidget(parent) { 0054 ui.setupUi(this); 0055 0056 ui.cbImportFrom->addItem(i18n("Table")); 0057 ui.cbImportFrom->addItem(i18n("Custom query")); 0058 0059 ui.bDatabaseManager->setIcon(QIcon::fromTheme("network-server-database")); 0060 ui.bDatabaseManager->setToolTip(i18n("Manage connections")); 0061 ui.twPreview->setEditTriggers(QAbstractItemView::NoEditTriggers); 0062 0063 ui.cbDecimalSeparator->addItem(i18n("Point '.'")); 0064 ui.cbDecimalSeparator->addItem(i18n("Comma ','")); 0065 ui.cbDateTimeFormat->addItems(AbstractColumn::dateTimeFormats()); 0066 0067 const QString textNumberFormatShort = i18n("This option determines how the imported strings have to be converted to numbers."); 0068 const QString textNumberFormat = textNumberFormatShort + "<br><br>" + i18n( 0069 "When point character is used for the decimal separator, the valid number representations are:" 0070 "<ul>" 0071 "<li>1234.56</li>" 0072 "<li>1,234.56</li>" 0073 "<li>etc.</li>" 0074 "</ul>" 0075 "For comma as the decimal separator, the valid number representations are:" 0076 "<ul>" 0077 "<li>1234,56</li>" 0078 "<li>1.234,56</li>" 0079 "<li>etc.</li>" 0080 "</ul>" 0081 ); 0082 0083 ui.lDecimalSeparator->setToolTip(textNumberFormatShort); 0084 ui.lDecimalSeparator->setWhatsThis(textNumberFormat); 0085 ui.cbDecimalSeparator->setToolTip(textNumberFormatShort); 0086 ui.cbDecimalSeparator->setWhatsThis(textNumberFormat); 0087 0088 const QString textDateTimeFormatShort = i18n("This option determines how the imported strings have to be converted to calendar date, i.e. year, month, and day numbers in the Gregorian calendar and to time."); 0089 const QString textDateTimeFormat = textDateTimeFormatShort + "<br><br>" + i18n( 0090 "Expressions that may be used for the date part of format string:" 0091 "<table>" 0092 "<tr><td>d</td><td>the day as number without a leading zero (1 to 31).</td></tr>" 0093 "<tr><td>dd</td><td>the day as number with a leading zero (01 to 31).</td></tr>" 0094 "<tr><td>ddd</td><td>the abbreviated localized day name (e.g. 'Mon' to 'Sun'). Uses the system locale to localize the name.</td></tr>" 0095 "<tr><td>dddd</td><td>the long localized day name (e.g. 'Monday' to 'Sunday'). Uses the system locale to localize the name.</td></tr>" 0096 "<tr><td>M</td><td>the month as number without a leading zero (1 to 12).</td></tr>" 0097 "<tr><td>MM</td><td>the month as number with a leading zero (01 to 12).</td></tr>" 0098 "<tr><td>MMM</td><td>the abbreviated localized month name (e.g. 'Jan' to 'Dec'). Uses the system locale to localize the name.</td></tr>" 0099 "<tr><td>MMMM</td><td>the long localized month name (e.g. 'January' to 'December'). Uses the system locale to localize the name.</td></tr>" 0100 "<tr><td>yy</td><td>the year as two digit number (00 to 99).</td></tr>" 0101 "<tr><td>yyyy</td><td>the year as four digit number. If the year is negative, a minus sign is prepended in addition.</td></tr>" 0102 "</table><br><br>" 0103 "Expressions that may be used for the time part of the format string:" 0104 "<table>" 0105 "<tr><td>h</td><td>the hour without a leading zero (0 to 23 or 1 to 12 if AM/PM display)</td></tr>" 0106 "<tr><td>hh</td><td>the hour with a leading zero (00 to 23 or 01 to 12 if AM/PM display)</td></tr>" 0107 "<tr><td>H</td><td>the hour without a leading zero (0 to 23, even with AM/PM display)</td></tr>" 0108 "<tr><td>HH</td><td>the hour with a leading zero (00 to 23, even with AM/PM display)</td></tr>" 0109 "<tr><td>m</td><td>the minute without a leading zero (0 to 59)</td></tr>" 0110 "<tr><td>mm</td><td>the minute with a leading zero (00 to 59)</td></tr>" 0111 "<tr><td>s</td><td>the second without a leading zero (0 to 59)</td></tr>" 0112 "<tr><td>ss</td><td>the second with a leading zero (00 to 59)</td></tr>" 0113 "<tr><td>z</td><td>the milliseconds without leading zeroes (0 to 999)</td></tr>" 0114 "<tr><td>zzz</td><td>the milliseconds with leading zeroes (000 to 999)</td></tr>" 0115 "<tr><td>AP or A</td><td>interpret as an AM/PM time. AP must be either 'AM' or 'PM'.</td></tr>" 0116 "<tr><td>ap or a</td><td>Interpret as an AM/PM time. ap must be either 'am' or 'pm'.</td></tr>" 0117 "</table><br><br>" 0118 "Examples are:" 0119 "<table>" 0120 "<tr><td>dd.MM.yyyy</td><td>20.07.1969</td></tr>" 0121 "<tr><td>ddd MMMM d yy</td><td>Sun July 20 69</td></tr>" 0122 "<tr><td>'The day is' dddd</td><td>The day is Sunday</td></tr>" 0123 "</table>"); 0124 0125 ui.lDateTimeFormat->setToolTip(textDateTimeFormatShort); 0126 ui.lDateTimeFormat->setWhatsThis(textDateTimeFormat); 0127 ui.cbDateTimeFormat->setToolTip(textDateTimeFormatShort); 0128 ui.cbDateTimeFormat->setWhatsThis(textDateTimeFormat); 0129 0130 #ifdef HAVE_KF5_SYNTAX_HIGHLIGHTING 0131 m_highlighter = new KSyntaxHighlighting::SyntaxHighlighter(ui.teQuery->document()); 0132 m_highlighter->setDefinition(m_repository.definitionForName("SQL")); 0133 m_highlighter->setTheme( (palette().color(QPalette::Base).lightness() < 128) 0134 ? m_repository.defaultTheme(KSyntaxHighlighting::Repository::DarkTheme) 0135 : m_repository.defaultTheme(KSyntaxHighlighting::Repository::LightTheme) ); 0136 #endif 0137 0138 m_configPath = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation).constFirst() + "sql_connections"; 0139 0140 connect( ui.cbConnection, SIGNAL(currentIndexChanged(int)), SLOT(connectionChanged()) ); 0141 connect( ui.cbImportFrom, SIGNAL(currentIndexChanged(int)), SLOT(importFromChanged(int)) ); 0142 connect( ui.bDatabaseManager, SIGNAL(clicked()), this, SLOT(showDatabaseManager()) ); 0143 connect( ui.lwTables, SIGNAL(currentRowChanged(int)), this, SLOT(refreshPreview()) ); 0144 connect( ui.bRefreshPreview, SIGNAL(clicked()), this, SLOT(refreshPreview()) ); 0145 0146 //defer the loading of settings a bit in order to show the dialog prior to blocking the GUI in refreshPreview() 0147 QTimer::singleShot( 100, this, SLOT(loadSettings()) ); 0148 } 0149 0150 void ImportSQLDatabaseWidget::loadSettings() { 0151 m_initializing = true; 0152 0153 //read available connections 0154 readConnections(); 0155 0156 //load last used connection and other settings 0157 KConfigGroup config(KSharedConfig::openConfig(), "ImportSQLDatabaseWidget"); 0158 ui.cbConnection->setCurrentIndex(ui.cbConnection->findText(config.readEntry("Connection", ""))); 0159 ui.cbImportFrom->setCurrentIndex(config.readEntry("ImportFrom", 0)); 0160 importFromChanged(ui.cbImportFrom->currentIndex()); 0161 0162 //TODO: use general setting for decimal separator? 0163 const QChar decimalSeparator = QLocale().decimalPoint(); 0164 int index = (decimalSeparator == '.') ? 0 : 1; 0165 ui.cbDecimalSeparator->setCurrentIndex(config.readEntry("DecimalSeparator", index)); 0166 0167 ui.cbDateTimeFormat->setCurrentText(config.readEntry("DateTimeFormat", "yyyy-dd-MM hh:mm:ss:zzz")); 0168 QList<int> defaultSizes{100, 100}; 0169 ui.splitterMain->setSizes(config.readEntry("SplitterMainSizes", defaultSizes)); 0170 ui.splitterPreview->setSizes(config.readEntry("SplitterPreviewSizes", defaultSizes)); 0171 //TODO 0172 0173 0174 m_initializing = false; 0175 0176 //all settings loaded -> trigger the selection of the last used connection in order to get the data preview 0177 connectionChanged(); 0178 } 0179 0180 ImportSQLDatabaseWidget::~ImportSQLDatabaseWidget() { 0181 // save current settings 0182 KConfigGroup config(KSharedConfig::openConfig(), "ImportSQLDatabaseWidget"); 0183 config.writeEntry("Connection", ui.cbConnection->currentText()); 0184 config.writeEntry("ImportFrom", ui.cbImportFrom->currentIndex()); 0185 config.writeEntry("DecimalSeparator", ui.cbDecimalSeparator->currentIndex()); 0186 config.writeEntry("DateTimeFormat", ui.cbDateTimeFormat->currentText()); 0187 config.writeEntry("SplitterMainSizes", ui.splitterMain->sizes()); 0188 config.writeEntry("SplitterPreviewSizes", ui.splitterPreview->sizes()); 0189 //TODO 0190 } 0191 0192 /*! 0193 * in case the import from a table is selected, returns the currently selected database table. 0194 * returns empty string otherwise. 0195 */ 0196 QString ImportSQLDatabaseWidget::selectedTable() const { 0197 if (ui.cbImportFrom->currentIndex() == 0) { 0198 if (ui.lwTables->currentItem()) 0199 return ui.lwTables->currentItem()->text(); 0200 } 0201 0202 return QString(); 0203 } 0204 0205 /*! 0206 returns \c true if a working connections was selected and a table (or custom query) is provided and ready to be imported. 0207 returns \c false otherwise. 0208 */ 0209 bool ImportSQLDatabaseWidget::isValid() const { 0210 return m_valid; 0211 } 0212 0213 /*! 0214 returns \c true if the selected table or the result of a custom query contains numeric data only. 0215 returns \c false otherwise. 0216 */ 0217 bool ImportSQLDatabaseWidget::isNumericData() const { 0218 return m_numeric; 0219 } 0220 0221 /*! 0222 loads all available saved connections 0223 */ 0224 void ImportSQLDatabaseWidget::readConnections() { 0225 DEBUG("ImportSQLDatabaseWidget: reading available connections"); 0226 KConfig config(m_configPath, KConfig::SimpleConfig); 0227 for (const auto& name : config.groupList()) 0228 ui.cbConnection->addItem(name); 0229 } 0230 0231 void ImportSQLDatabaseWidget::connectionChanged() { 0232 if (m_initializing) 0233 return; 0234 0235 QDEBUG("ImportSQLDatabaseWidget: connecting to " + ui.cbConnection->currentText()); 0236 0237 //clear the previously shown content 0238 ui.teQuery->clear(); 0239 ui.lwTables->clear(); 0240 ui.twPreview->clear(); 0241 ui.twPreview->setColumnCount(0); 0242 ui.twPreview->setRowCount(0); 0243 0244 if (ui.cbConnection->currentIndex() == -1) 0245 return; 0246 0247 //connection name was changed, determine the current connections settings 0248 KConfig config(m_configPath, KConfig::SimpleConfig); 0249 KConfigGroup group = config.group(ui.cbConnection->currentText()); 0250 0251 //close and remove the previous connection, if available 0252 if (m_db.isOpen()) { 0253 m_db.close(); 0254 QSqlDatabase::removeDatabase(m_db.driverName()); 0255 } 0256 0257 //open the selected connection 0258 const QString& driver = group.readEntry("Driver"); 0259 m_db = QSqlDatabase::addDatabase(driver); 0260 0261 const QString& dbName = group.readEntry("DatabaseName"); 0262 if (DatabaseManagerWidget::isFileDB(driver)) { 0263 if (!QFile::exists(dbName)) { 0264 KMessageBox::error(this, i18n("Couldn't find the database file '%1'. Please check the connection settings.", dbName), 0265 i18n("Connection Failed")); 0266 setInvalid(); 0267 return; 0268 } else 0269 m_db.setDatabaseName(dbName); 0270 } else if (DatabaseManagerWidget::isODBC(driver)) { 0271 if (group.readEntry("CustomConnectionEnabled", false)) 0272 m_db.setDatabaseName(group.readEntry("CustomConnectionString")); 0273 else 0274 m_db.setDatabaseName(dbName); 0275 } else { 0276 m_db.setDatabaseName(dbName); 0277 m_db.setHostName( group.readEntry("HostName") ); 0278 m_db.setPort( group.readEntry("Port", 0) ); 0279 m_db.setUserName( group.readEntry("UserName") ); 0280 m_db.setPassword( group.readEntry("Password") ); 0281 } 0282 0283 WAIT_CURSOR; 0284 if (!m_db.open()) { 0285 RESET_CURSOR; 0286 KMessageBox::error(this, i18n("Failed to connect to the database '%1'. Please check the connection settings.", ui.cbConnection->currentText()) + 0287 QLatin1String("\n\n") + m_db.lastError().databaseText(), 0288 i18n("Connection Failed")); 0289 setInvalid(); 0290 return; 0291 } 0292 0293 //show all available database tables 0294 if (m_db.tables().size()) { 0295 ui.lwTables->addItems(m_db.tables()); 0296 ui.lwTables->setCurrentRow(0); 0297 for (int i = 0; i < ui.lwTables->count(); ++i) 0298 ui.lwTables->item(i)->setIcon(QIcon::fromTheme("view-form-table")); 0299 } else 0300 setInvalid(); 0301 0302 //show the last used query 0303 ui.teQuery->setText(group.readEntry("Query")); 0304 0305 RESET_CURSOR; 0306 } 0307 0308 void ImportSQLDatabaseWidget::refreshPreview() { 0309 if (!ui.lwTables->currentItem()) { 0310 setInvalid(); 0311 return; 0312 } 0313 0314 WAIT_CURSOR; 0315 ui.twPreview->clear(); 0316 0317 bool customQuery = (ui.cbImportFrom->currentIndex() != 0); 0318 0319 //save the last used custom query 0320 if (customQuery) { 0321 KConfig config(m_configPath, KConfig::SimpleConfig); 0322 KConfigGroup group = config.group(ui.cbConnection->currentText()); 0323 group.writeEntry("Query", ui.teQuery->toPlainText().simplified()); 0324 } 0325 0326 //execute the current query (select on a table or a custom query) 0327 const QString& query = currentQuery(true); 0328 if (query.isEmpty()) { 0329 RESET_CURSOR; 0330 setInvalid(); 0331 return; 0332 } 0333 0334 QSqlQuery q; 0335 q.prepare(currentQuery(true)); 0336 q.setForwardOnly(true); 0337 q.exec(); 0338 if (!q.isActive() || !q.next()) { // check if query was successful and got to first record 0339 RESET_CURSOR; 0340 if (!q.lastError().databaseText().isEmpty()) 0341 KMessageBox::error(this, q.lastError().databaseText(), i18n("Unable to Execute Query")); 0342 0343 setInvalid(); 0344 return; 0345 } 0346 0347 //resize the table to the number of columns (=number of fields in the result set) 0348 m_cols = q.record().count(); 0349 ui.twPreview->setColumnCount(m_cols); 0350 0351 //determine the names and the data type (column modes) of the table columns. 0352 //check whether we have numerical data only by checking the data types of the first record. 0353 m_columnNames.clear(); 0354 m_columnModes.clear(); 0355 bool numeric = true; 0356 //TODO: use general setting for decimal separator? 0357 QLocale::Language lang; 0358 if (ui.cbDecimalSeparator->currentIndex() == 0) 0359 lang = QLocale::Language::C; 0360 else 0361 lang = QLocale::Language::German; 0362 const QString& dateTimeFormat = ui.cbDateTimeFormat->currentText(); 0363 // ui.twPreview->setRowCount(1); //add the first row for the check boxes 0364 for (int i = 0; i < m_cols; ++i) { 0365 //name 0366 m_columnNames << q.record().fieldName(i); 0367 0368 //value and type 0369 const QString valueString = q.record().value(i).toString(); 0370 AbstractColumn::ColumnMode mode = AbstractFileFilter::columnMode(valueString, dateTimeFormat, lang); 0371 m_columnModes << mode; 0372 if (mode != AbstractColumn::ColumnMode::Numeric) 0373 numeric = false; 0374 0375 //header item 0376 auto* item = new QTableWidgetItem(m_columnNames[i] + QLatin1String(" {") + ENUM_TO_STRING(AbstractColumn, ColumnMode, mode) + QLatin1String("}")); 0377 item->setTextAlignment(Qt::AlignLeft); 0378 item->setIcon(AbstractColumn::iconForMode(mode)); 0379 ui.twPreview->setHorizontalHeaderItem(i, item); 0380 0381 //create checked items 0382 // QTableWidgetItem* itemChecked = new QTableWidgetItem(); 0383 // itemChecked->setCheckState(Qt::Checked); 0384 // ui.twPreview->setItem(0, i, itemChecked); 0385 } 0386 0387 //preview the data 0388 int row = 0; 0389 do { 0390 for (int col = 0; col < m_cols; ++col) { 0391 ui.twPreview->setRowCount(row+1); 0392 ui.twPreview->setItem(row, col, new QTableWidgetItem(q.value(col).toString()) ); 0393 } 0394 row++; 0395 0396 //in case a custom query is executed, check whether the row number limit is reached 0397 if (customQuery && row >= ui.sbPreviewLines->value()) 0398 break; 0399 } while (q.next()); 0400 0401 ui.twPreview->horizontalHeader()->resizeSections(QHeaderView::ResizeToContents); 0402 0403 setValid(); 0404 0405 if (numeric != m_numeric) { 0406 m_numeric = numeric; 0407 emit stateChanged(); 0408 } 0409 0410 RESET_CURSOR; 0411 } 0412 0413 void ImportSQLDatabaseWidget::importFromChanged(int index) { 0414 if (index == 0) { //import from a table 0415 ui.gbQuery->hide(); 0416 ui.lwTables->show(); 0417 } else { //import the result set of a custom query 0418 ui.gbQuery->show(); 0419 ui.lwTables->hide(); 0420 ui.twPreview->clear(); 0421 } 0422 0423 refreshPreview(); 0424 } 0425 0426 void ImportSQLDatabaseWidget::read(AbstractDataSource* dataSource, AbstractFileFilter::ImportMode importMode) { 0427 if (!dataSource) 0428 return; 0429 0430 WAIT_CURSOR; 0431 //execute the current query (select on a table or a custom query) 0432 QSqlQuery q; 0433 // q.setForwardOnly(true); //TODO: crashes most probably because of q.last() and q.first() below 0434 q.prepare(currentQuery()); 0435 if (!q.exec() || !q.isActive()) { 0436 RESET_CURSOR; 0437 if (!q.lastError().databaseText().isEmpty()) 0438 KMessageBox::error(this, q.lastError().databaseText(), i18n("Unable to Execute Query")); 0439 0440 setInvalid(); 0441 return; 0442 } 0443 0444 //determine the number of rows/records to read 0445 q.last(); 0446 const int rows = q.at()+1; 0447 q.first(); 0448 0449 // pointers to the actual data containers 0450 //columnOffset indexes the "start column" in the datasource. Data will be imported starting from this column. 0451 std::vector<void*> dataContainer; 0452 int columnOffset = dataSource->prepareImport(dataContainer, importMode, rows, m_cols, m_columnNames, m_columnModes); 0453 0454 //number and DateTime formatting 0455 const QString& dateTimeFormat = ui.cbDateTimeFormat->currentText(); 0456 0457 //TODO: use general setting for decimal separator? 0458 QLocale::Language lang; 0459 if (ui.cbDecimalSeparator->currentIndex() == 0) 0460 lang = QLocale::Language::C; 0461 else 0462 lang = QLocale::Language::German; 0463 const QLocale numberFormat = QLocale(lang); 0464 0465 //read the data 0466 int row = 0; 0467 do { 0468 for (int col = 0; col < m_cols; ++col) { 0469 const QString valueString = q.record().value(col).toString(); 0470 0471 // set value depending on data type 0472 switch (m_columnModes[col]) { 0473 case AbstractColumn::ColumnMode::Numeric: { 0474 bool isNumber; 0475 const double value = numberFormat.toDouble(valueString, &isNumber); 0476 static_cast<QVector<double>*>(dataContainer[col])->operator[](row) = (isNumber ? value : NAN); 0477 break; 0478 } 0479 case AbstractColumn::ColumnMode::Integer: { 0480 bool isNumber; 0481 const int value = numberFormat.toInt(valueString, &isNumber); 0482 static_cast<QVector<int>*>(dataContainer[col])->operator[](row) = (isNumber ? value : NAN); 0483 break; 0484 } 0485 case AbstractColumn::ColumnMode::BigInt: { 0486 bool isNumber; 0487 const qint64 value = numberFormat.toLongLong(valueString, &isNumber); 0488 static_cast<QVector<qint64>*>(dataContainer[col])->operator[](row) = (isNumber ? value : NAN); 0489 break; 0490 } 0491 case AbstractColumn::ColumnMode::DateTime: { 0492 const QDateTime valueDateTime = QDateTime::fromString(valueString, dateTimeFormat); 0493 static_cast<QVector<QDateTime>*>(dataContainer[col])->operator[](row) = valueDateTime.isValid() ? valueDateTime : QDateTime(); 0494 break; 0495 } 0496 case AbstractColumn::ColumnMode::Text: 0497 static_cast<QVector<QString>*>(dataContainer[col])->operator[](row) = valueString; 0498 break; 0499 case AbstractColumn::ColumnMode::Month: // never happens 0500 case AbstractColumn::ColumnMode::Day: 0501 break; 0502 } 0503 } 0504 0505 row++; 0506 emit completed(100 * row/rows); 0507 } while (q.next()); 0508 DEBUG(" Read " << row << " rows"); 0509 0510 dataSource->finalizeImport(columnOffset, 1, m_cols, dateTimeFormat, importMode); 0511 RESET_CURSOR; 0512 } 0513 0514 QString ImportSQLDatabaseWidget::currentQuery(bool preview) { 0515 QString query; 0516 const bool customQuery = (ui.cbImportFrom->currentIndex() != 0); 0517 if ( !customQuery ) { 0518 const QString& tableName = ui.lwTables->currentItem()->text(); 0519 if (!preview) { 0520 query = QLatin1String("SELECT * FROM ") + tableName; 0521 } else { 0522 //preview the content of the currently selected table 0523 const QString& driver = m_db.driverName(); 0524 const QString& limit = QString::number(ui.sbPreviewLines->value()); 0525 if ( (driver == QLatin1String("QSQLITE3")) || (driver == QLatin1String("QSQLITE")) 0526 || (driver == QLatin1String("QMYSQL3")) || (driver == QLatin1String("QMYSQL")) 0527 || (driver == QLatin1String("QPSQL")) ) 0528 query = QLatin1String("SELECT * FROM ") + tableName + QLatin1String(" LIMIT ") + limit; 0529 else if (driver == QLatin1String("QOCI")) 0530 query = QLatin1String("SELECT * FROM ") + tableName + QLatin1String(" ROWNUM<=") + limit; 0531 else if (driver == QLatin1String("QDB2")) 0532 query = QLatin1String("SELECT * FROM ") + tableName + QLatin1String(" FETCH FIRST ") + limit + QLatin1String(" ROWS ONLY"); 0533 else if (driver == QLatin1String("QIBASE")) 0534 query = QLatin1String("SELECT * FROM ") + tableName + QLatin1String(" ROWS ") + limit; 0535 else 0536 //for ODBC the DBMS is not known and it's not clear what syntax to use -> select all rows 0537 query = QLatin1String("SELECT * FROM ") + tableName; 0538 } 0539 } else { 0540 //preview the result of a custom query 0541 query = ui.teQuery->toPlainText().simplified(); 0542 } 0543 0544 return query; 0545 } 0546 0547 /*! 0548 shows the database manager where the connections are created and edited. 0549 The selected connection is selected in the connection combo box in this widget. 0550 **/ 0551 void ImportSQLDatabaseWidget::showDatabaseManager() { 0552 auto* dlg = new DatabaseManagerDialog(this, ui.cbConnection->currentText()); 0553 0554 if (dlg->exec() == QDialog::Accepted) { 0555 //re-read the available connections to be in sync with the changes in DatabaseManager 0556 m_initializing = true; 0557 ui.cbConnection->clear(); 0558 readConnections(); 0559 0560 //select the connection the user has selected in DatabaseManager 0561 const QString& conn = dlg->connection(); 0562 ui.cbConnection->setCurrentIndex(ui.cbConnection->findText(conn)); 0563 m_initializing = false; 0564 0565 connectionChanged(); 0566 } 0567 0568 delete dlg; 0569 } 0570 0571 void ImportSQLDatabaseWidget::setInvalid() { 0572 if (m_valid) { 0573 ui.twPreview->setColumnCount(0); 0574 ui.twPreview->setRowCount(0); 0575 0576 m_valid = false; 0577 emit stateChanged(); 0578 } 0579 } 0580 0581 void ImportSQLDatabaseWidget::setValid() { 0582 if (!m_valid) { 0583 m_valid = true; 0584 emit stateChanged(); 0585 } 0586 }