diff --git a/src/AddRecordDialog.cpp b/src/AddRecordDialog.cpp index 2a6bcf9e..f7b12c50 100644 --- a/src/AddRecordDialog.cpp +++ b/src/AddRecordDialog.cpp @@ -213,7 +213,7 @@ void AddRecordDialog::populateFields() tbitem->setText(kName, QString::fromStdString(f.name())); tbitem->setText(kType, QString::fromStdString(f.type())); - tbitem->setData(kType, Qt::UserRole, QString::fromStdString(f.affinity())); + tbitem->setData(kType, Qt::UserRole, f.affinity()); // NOT NULL fields are indicated in bold. if (f.notnull()) { @@ -303,7 +303,7 @@ void AddRecordDialog::updateSqlText() fields << sqlb::escapeIdentifier(item->text(kName)); value.toDouble(&isNumeric); // If it has a numeric format and has no text affinity, do not quote it. - if (isNumeric && item->data(kType, Qt::UserRole).toString() != "TEXT") + if (isNumeric && item->data(kType, Qt::UserRole).toInt() != sqlb::Field::TextAffinity) vals << value.toString(); else vals << QString("'%1'").arg(value.toString().replace("'", "''")); diff --git a/src/sql/sqlitetypes.cpp b/src/sql/sqlitetypes.cpp index 815a1887..03711e3e 100644 --- a/src/sql/sqlitetypes.cpp +++ b/src/sql/sqlitetypes.cpp @@ -323,17 +323,17 @@ bool Field::isBlob() const return false; } -std::string Field::affinity() const +Field::Affinity Field::affinity() const { - if (isInteger()) return "INTEGER"; + if (isInteger()) return IntegerAffinity; - if (isText()) return "TEXT"; + if (isText()) return TextAffinity; - if (isBlob()) return "BLOB"; + if (isBlob()) return BlobAffinity; - if (isReal()) return "REAL"; + if (isReal() || isNumeric()) return FloatAffinity; - return "NUMERIC"; + return BlobAffinity; } Table::Table(const Table& table) diff --git a/src/sql/sqlitetypes.h b/src/sql/sqlitetypes.h index 07584e49..4efab688 100644 --- a/src/sql/sqlitetypes.h +++ b/src/sql/sqlitetypes.h @@ -296,8 +296,16 @@ public: bool isReal() const; bool isNumeric() const; - // Type affinity of the column according to SQLite3 rules - std::string affinity() const; + // Type affinity of the column according to SQLite3 rules. + // The Affinity enum values match the SQLITE_INTEGER, SQLITE_FLOAT, SQLITE_BLOB, and SQLITE_TEXT constants + enum Affinity + { + IntegerAffinity = 1, + FloatAffinity = 2, + TextAffinity = 3, + BlobAffinity = 4, + }; + Affinity affinity() const; const std::string& name() const { return m_name; } const std::string& type() const { return m_type; } diff --git a/src/sqlitetablemodel.cpp b/src/sqlitetablemodel.cpp index c1a3ae84..d5e6004a 100644 --- a/src/sqlitetablemodel.cpp +++ b/src/sqlitetablemodel.cpp @@ -128,40 +128,24 @@ void SqliteTableModel::setQuery(const sqlb::Query& query) m_vDataTypes.emplace_back(SQLITE_INTEGER); // Get the data types of all other columns as well as the column names - bool allOk = false; - if(m_db.getObjectByName(query.table()) && m_db.getObjectByName(query.table())->type() == sqlb::Object::Types::Table) + sqlb::TablePtr t = m_db.getObjectByName(query.table()); + if(t && t->fields.size()) // It is a table and parsing was OK { - sqlb::TablePtr t = m_db.getObjectByName(query.table()); - if(t && t->fields.size()) // parsing was OK + sqlb::StringVector rowids = t->rowidColumns(); + m_query.setRowIdColumns(rowids); + m_headers.push_back(sqlb::joinStringVector(rowids, ",")); + + // Store field names and affinity data types + for(const sqlb::Field& fld : t->fields) { - sqlb::StringVector rowids = t->rowidColumns(); - m_query.setRowIdColumns(rowids); - m_headers.push_back(sqlb::joinStringVector(rowids, ",")); - for(const auto& n : t->fieldNames()) - m_headers.push_back(n); - - // parse columns types - static QStringList dataTypes = QStringList() - << "INTEGER" - << "REAL" - << "TEXT" - << "BLOB"; - for(const sqlb::Field& fld : t->fields) - { - QString name = QString::fromStdString(fld.type()).toUpper(); - int colType = dataTypes.indexOf(name); - colType = (colType == -1) ? SQLITE_TEXT : colType + 1; - m_vDataTypes.push_back(colType); - } - allOk = true; + m_headers.push_back(fld.name()); + m_vDataTypes.push_back(fld.affinity()); } - } + } else { + // If for one reason or another (either it's a view or we couldn't parse the table statement) we couldn't get the field + // information we retrieve it from SQLite using an extra query. + // NOTE: It would be nice to eventually get rid of this piece here. As soon as the grammar parser is good enough... - // If for one reason or another (either it's a view or we couldn't parse the table statement) we couldn't get the field - // information we retrieve it from SQLite using an extra query. - // NOTE: It would be nice to eventually get rid of this piece here. As soon as the grammar parser is good enough... - if(!allOk) - { QString sColumnQuery = QString::fromUtf8("SELECT * FROM %1;").arg(QString::fromStdString(query.table().toString())); if(m_query.rowIdColumns().empty()) m_query.setRowIdColumn("_rowid_"); @@ -266,15 +250,15 @@ QVariant SqliteTableModel::headerData(int section, Qt::Orientation orientation, return plainHeader + sortIndicator; } } - return QString("%1").arg(section + 1); + return QString::number(section + 1); } else - return QString("%1").arg(section + 1); + return QString::number(section + 1); } QVariant SqliteTableModel::getMatchingCondFormat(size_t column, const QString& value, int role) const { - if (m_mCondFormats.find(column) == m_mCondFormats.end()) + if (!m_mCondFormats.count(column)) return QVariant(); bool isNumber; @@ -330,7 +314,7 @@ QVariant SqliteTableModel::data(const QModelIndex &index, int role) const if(data.isNull()) { return m_nullText; - } else if(nosync_isBinary(index)) { + } else if(isBinary(data)) { return m_blobText; } else { if (data.length() > m_symbolLimit) { @@ -346,7 +330,7 @@ QVariant SqliteTableModel::data(const QModelIndex &index, int role) const return decode(data); } else if(role == Qt::FontRole) { QFont font; - if(!row_available || data.isNull() || nosync_isBinary(index)) + if(!row_available || data.isNull() || isBinary(data)) font.setItalic(true); else { // Unlock before querying from DB @@ -361,9 +345,9 @@ QVariant SqliteTableModel::data(const QModelIndex &index, int role) const return QColor(100, 100, 100); if(data.isNull()) return m_nullFgColour; - else if (nosync_isBinary(index)) + else if (isBinary(data)) return m_binFgColour; - else if (m_mCondFormats.find(column) != m_mCondFormats.end()) { + else if (m_mCondFormats.count(column)) { // Unlock before querying from DB lock.unlock(); QVariant condFormatColor = getMatchingCondFormat(column, data, role); @@ -377,9 +361,9 @@ QVariant SqliteTableModel::data(const QModelIndex &index, int role) const return QColor(255, 200, 200); if(data.isNull()) return m_nullBgColour; - else if (nosync_isBinary(index)) + else if (isBinary(data)) return m_binBgColour; - else if (m_mCondFormats.find(column) != m_mCondFormats.end()) { + else if (m_mCondFormats.count(column)) { // Unlock before querying from DB lock.unlock(); QVariant condFormatColor = getMatchingCondFormat(column, data, role); @@ -883,18 +867,18 @@ void SqliteTableModel::clearCache() bool SqliteTableModel::isBinary(const QModelIndex& index) const { QMutexLocker lock(&m_mutexDataCache); - return nosync_isBinary(index); -} -bool SqliteTableModel::nosync_isBinary(const QModelIndex& index) const -{ const size_t row = static_cast(index.row()); if(!m_cache.count(row)) return false; const auto & cached_row = m_cache.at(row); + return isBinary(cached_row.at(static_cast(index.column()))); +} - return !isTextOnly(cached_row.at(static_cast(index.column())), m_encoding, true); +bool SqliteTableModel::isBinary(const QByteArray& data) const +{ + return !isTextOnly(data, m_encoding, true); } QByteArray SqliteTableModel::encode(const QByteArray& str) const diff --git a/src/sqlitetablemodel.h b/src/sqlitetablemodel.h index 8162ad73..b673baf5 100644 --- a/src/sqlitetablemodel.h +++ b/src/sqlitetablemodel.h @@ -194,7 +194,7 @@ private: Row makeDefaultCacheEntry () const; - bool nosync_isBinary(const QModelIndex& index) const; + bool isBinary(const QByteArray& index) const; QString m_sQuery; std::vector m_vDataTypes;