summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--build/depends.py1
-rw-r--r--src/library/banshee/bansheeplaylistmodel.cpp4
-rw-r--r--src/library/basesqltablemodel.cpp37
-rw-r--r--src/library/basetrackcache.cpp4
-rw-r--r--src/library/browse/browsetablemodel.cpp2
-rw-r--r--src/library/crate/cratestorage.cpp21
-rw-r--r--src/library/itunes/itunesfeature.cpp4
-rw-r--r--src/library/librarytablemodel.cpp2
-rw-r--r--src/library/mixxxlibraryfeature.cpp2
-rw-r--r--src/library/playlistfeature.cpp4
-rw-r--r--src/library/rhythmbox/rhythmboxfeature.cpp2
-rw-r--r--src/library/scanner/libraryscanner.cpp2
-rw-r--r--src/library/setlogfeature.cpp2
-rw-r--r--src/library/trackcollection.cpp398
-rw-r--r--src/library/trackcollection.h30
-rw-r--r--src/library/traktor/traktorfeature.cpp2
-rw-r--r--src/test/sqliteliketest.cpp34
-rw-r--r--src/util/db/dbconnection.cpp418
-rw-r--r--src/util/db/dbconnection.h40
-rw-r--r--src/util/string.h16
20 files changed, 548 insertions, 477 deletions
diff --git a/build/depends.py b/build/depends.py
index 79d328c55a..b416902679 100644
--- a/build/depends.py
+++ b/build/depends.py
@@ -1099,6 +1099,7 @@ class MixxxCore(Feature):
"util/tapfilter.cpp",
"util/movinginterquartilemean.cpp",
"util/console.cpp",
+ "util/db/dbconnection.cpp",
"util/db/dbid.cpp",
"util/db/fwdsqlquery.cpp",
"util/db/sqllikeescaper.cpp",
diff --git a/src/library/banshee/bansheeplaylistmodel.cpp b/src/library/banshee/bansheeplaylistmodel.cpp
index 5bfcfb977b..c871095bd3 100644
--- a/src/library/banshee/bansheeplaylistmodel.cpp
+++ b/src/library/banshee/bansheeplaylistmodel.cpp
@@ -50,7 +50,7 @@ void BansheePlaylistModel::setTableModel(int playlistId) {
if (m_playlistId >= 0) {
// Clear old playlist
m_playlistId = -1;
- QSqlQuery query(m_pTrackCollection->getDatabase());
+ QSqlQuery query(m_pTrackCollection->database());
QString strQuery("DELETE FROM " BANSHEE_TABLE);
if (!query.exec(strQuery)) {
LOG_FAILED_QUERY(query);
@@ -61,7 +61,7 @@ void BansheePlaylistModel::setTableModel(int playlistId) {
// setup new playlist
m_playlistId = playlistId;
- QSqlQuery query(m_pTrackCollection->getDatabase());
+ QSqlQuery query(m_pTrackCollection->database());
QString strQuery("CREATE TEMP TABLE IF NOT EXISTS " BANSHEE_TABLE
" (" CLM_VIEW_ORDER " INTEGER, "
CLM_ARTIST " TEXT, "
diff --git a/src/library/basesqltablemodel.cpp b/src/library/basesqltablemodel.cpp
index 56fe2efa94..b734e1d151 100644
--- a/src/library/basesqltablemodel.cpp
+++ b/src/library/basesqltablemodel.cpp
@@ -29,16 +29,16 @@ static const bool sDebug = false;
static const int kIdColumn = 0;
static const int kMaxSortColumns = 3;
-// Constant for getModelSetting(name)
+// Constant for getModelSetting(name)
static const char* COLUMNS_SORTING = "ColumnsSorting";
BaseSqlTableModel::BaseSqlTableModel(QObject* pParent,
TrackCollection* pTrackCollection,
const char* settingsNamespace)
: QAbstractTableModel(pParent),
- TrackModel(pTrackCollection->getDatabase(), settingsNamespace),
+ TrackModel(pTrackCollection->database(), settingsNamespace),
m_pTrackCollection(pTrackCollection),
- m_database(pTrackCollection->getDatabase()),
+ m_database(pTrackCollection->database()),
m_previewDeckGroup(PlayerManager::groupForPreviewDeck(0)),
m_bInitialized(false),
m_currentSearch("") {
@@ -424,24 +424,24 @@ void BaseSqlTableModel::setSort(int column, Qt::SortOrder order) {
qWarning() << "BaseSqlTableModel::setSort invalid column:" << column;
return;
}
-
+
// There's no item to sort already, load from Settings last sort
if (m_sortColumns.isEmpty()) {
QString val = getModelSetting(COLUMNS_SORTING);
QTextStream in(&val);
-
+
while (!in.atEnd()) {
int ordI = -1;
QString name;
-
+
in >> name >> ordI;
-
+
int col = fieldIndex(name);
if (col < 0) continue;
-
+
Qt::SortOrder ord;
ord = ordI > 0 ? Qt::AscendingOrder : Qt::DescendingOrder;
-
+
m_sortColumns << SortColumn(col, ord);
}
}
@@ -465,13 +465,13 @@ void BaseSqlTableModel::setSort(int column, Qt::SortOrder order) {
m_sortColumns.removeLast();
}
}
-
+
// Write new sortColumns order to user settings
QString val;
QTextStream out(&val);
for (SortColumn& sc : m_sortColumns) {
- QString name;
+ QString name;
if (sc.m_column > 0 && sc.m_column < m_tableColumns.size()) {
name = m_tableColumns[sc.m_column];
} else {
@@ -489,7 +489,7 @@ void BaseSqlTableModel::setSort(int column, Qt::SortOrder order) {
if (sDebug) {
qDebug() << "setSort() sortColumns:" << val;
}
-
+
// we have two selects for sorting, since keeping the select history
// across the two selects is hard, we do this only for the trackSource
@@ -511,9 +511,8 @@ void BaseSqlTableModel::setSort(int column, Qt::SortOrder order) {
QString field = m_tableColumns[column];
QString sort_field = QString("%1.%2").arg(m_tableName, field);
m_tableOrderBy.append(sort_field);
- #ifdef __SQLITE3__
- m_tableOrderBy.append(" COLLATE localeAwareCompare");
- #endif
+ m_tableOrderBy.append(" COLLATE ");
+ m_tableOrderBy.append(DbConnection::kStringCollationFunc);
m_tableOrderBy.append((order == Qt::AscendingOrder) ? " ASC" : " DESC");
}
m_sortColumns.clear();
@@ -530,7 +529,7 @@ void BaseSqlTableModel::setSort(int column, Qt::SortOrder order) {
sort_field = "RANDOM()";
} else {
// we can't sort by other table columns here since primary sort is a track
- // column: skip
+ // column: skip
continue;
}
} else {
@@ -544,10 +543,8 @@ void BaseSqlTableModel::setSort(int column, Qt::SortOrder order) {
m_trackSourceOrderBy.append(first ? "ORDER BY ": ", ");
m_trackSourceOrderBy.append(sort_field);
-
- #ifdef __SQLITE3__
- m_trackSourceOrderBy.append(" COLLATE localeAwareCompare");
- #endif
+ m_trackSourceOrderBy.append(" COLLATE ");
+ m_trackSourceOrderBy.append(DbConnection::kStringCollationFunc);
m_trackSourceOrderBy.append((sc.m_order == Qt::AscendingOrder) ?
" ASC" : " DESC");
//qDebug() << m_trackSourceOrderBy;
diff --git a/src/library/basetrackcache.cpp b/src/library/basetrackcache.cpp
index 882945d7a1..a1f4b96346 100644
--- a/src/library/basetrackcache.cpp
+++ b/src/library/basetrackcache.cpp
@@ -32,8 +32,8 @@ BaseTrackCache::BaseTrackCache(TrackCollection* pTrackCollection,
m_bIndexBuilt(false),
m_bIsCaching(isCaching),
m_trackDAO(pTrackCollection->getTrackDAO()),
- m_database(pTrackCollection->getDatabase()),
- m_pQueryParser(new SearchQueryParser(pTrackCollection->getDatabase())) {
+ m_database(pTrackCollection->database()),
+ m_pQueryParser(new SearchQueryParser(pTrackCollection->database())) {
m_searchColumns << "artist"
<< "album"
<< "album_artist"
diff --git a/src/library/browse/browsetablemodel.cpp b/src/library/browse/browsetablemodel.cpp
index 93f3ae3ff6..a1dc266530 100644
--- a/src/library/browse/browsetablemodel.cpp
+++ b/src/library/browse/browsetablemodel.cpp
@@ -17,7 +17,7 @@
BrowseTableModel::BrowseTableModel(QObject* parent,
TrackCollection* pTrackCollection,
RecordingManager* pRecordingManager)
- : TrackModel(pTrackCollection->getDatabase(),
+ : TrackModel(pTrackCollection->database(),
"mixxx.db.model.browse"),
QStandardItemModel(parent),
m_pTrackCollection(pTrackCollection),
diff --git a/src/library/crate/cratestorage.cpp b/src/library/crate/cratestorage.cpp
index 3176a1b633..83de31e151 100644
--- a/src/library/crate/cratestorage.cpp
+++ b/src/library/crate/cratestorage.cpp
@@ -1,10 +1,11 @@
#include "library/crate/cratestorage.h"
#include "library/crate/crateschema.h"
-
#include "library/dao/trackschema.h"
-#include "util/db/fwdsqlquery.h"
+
+#include "util/db/dbconnection.h"
#include "util/db/sqltransaction.h"
+#include "util/db/fwdsqlquery.h"
#include <QtDebug>
@@ -318,9 +319,11 @@ bool CrateStorage::readCrateByName(const QString& name, Crate* pCrate) const {
CrateSelectIterator CrateStorage::selectCrates() const {
FwdSqlQuery query(m_database, QString(
- "SELECT * FROM %1 ORDER BY %2 COLLATE localeAwareCompare").arg(
+ "SELECT * FROM %1 ORDER BY %2 COLLATE %3").arg(
CRATE_TABLE,
- CRATETABLE_NAME));
+ CRATETABLE_NAME,
+ DbConnection::kStringCollationFunc));
+
if (query.execPrepared()) {
return CrateSelectIterator(query);
} else {
@@ -331,10 +334,11 @@ CrateSelectIterator CrateStorage::selectCrates() const {
CrateSelectIterator CrateStorage::selectAutoDjCrates(bool autoDjSource) const {
FwdSqlQuery query(m_database, QString(
- "SELECT * FROM %1 WHERE %2=:autoDjSource ORDER BY %3 COLLATE localeAwareCompare").arg(
+ "SELECT * FROM %1 WHERE %2=:autoDjSource ORDER BY %3 COLLATE %4").arg(
CRATE_TABLE,
CRATETABLE_AUTODJ_SOURCE,
- CRATETABLE_NAME));
+ CRATETABLE_NAME,
+ DbConnection::kStringCollationFunc));
query.bindValue(":autoDjSource", autoDjSource);
if (query.execPrepared()) {
return CrateSelectIterator(query);
@@ -346,9 +350,10 @@ CrateSelectIterator CrateStorage::selectAutoDjCrates(bool autoDjSource) const {
CrateSummarySelectIterator CrateStorage::selectCrateSummaries() const {
FwdSqlQuery query(m_database, QString(
- "SELECT * FROM %1 ORDER BY %2 COLLATE localeAwareCompare").arg(
+ "SELECT * FROM %1 ORDER BY %2 COLLATE %3").arg(
CRATE_SUMMARY_VIEW,
- CRATETABLE_NAME));
+ CRATETABLE_NAME,
+ DbConnection::kStringCollationFunc));
if (query.execPrepared()) {
return CrateSummarySelectIterator(query);
} else {
diff --git a/src/library/itunes/itunesfeature.cpp b/src/library/itunes/itunesfeature.cpp
index 5a3a4d1a80..fa13586498 100644
--- a/src/library/itunes/itunesfeature.cpp
+++ b/src/library/itunes/itunesfeature.cpp
@@ -68,7 +68,7 @@ ITunesFeature::ITunesFeature(QObject* parent, TrackCollection* pTrackCollection)
m_isActivated = false;
m_title = tr("iTunes");
- m_database = QSqlDatabase::cloneDatabase(pTrackCollection->getDatabase(), "ITUNES_SCANNER");
+ m_database = QSqlDatabase::cloneDatabase(pTrackCollection->database(), "ITUNES_SCANNER");
//Open the database connection in this thread.
if (!m_database.open()) {
@@ -120,7 +120,7 @@ void ITunesFeature::activate() {
void ITunesFeature::activate(bool forceReload) {
//qDebug("ITunesFeature::activate()");
if (!m_isActivated || forceReload) {
- SettingsDAO settings(m_pTrackCollection->getDatabase());
+ SettingsDAO settings(m_pTrackCollection->database());
QString dbSetting(settings.getValue(ITDB_PATH_KEY));
// if a path exists in the database, use it
if (!dbSetting.isEmpty() && QFile::exists(dbSetting)) {
diff --git a/src/library/librarytablemodel.cpp b/src/library/librarytablemodel.cpp
index 21ea1e8676..c6c2f504ea 100644
--- a/src/library/librarytablemodel.cpp
+++ b/src/library/librarytablemodel.cpp
@@ -32,7 +32,7 @@ void LibraryTableModel::setTableModel(int id) {
const QString tableName = "library_view";
- QSqlQuery query(m_pTrackCollection->getDatabase());
+ QSqlQuery query(m_pTrackCollection->database());
QString queryString = "CREATE TEMPORARY VIEW IF NOT EXISTS " + tableName + " AS "
"SELECT " + columns.join(", ") +
" FROM library INNER JOIN track_locations "
diff --git a/src/library/mixxxlibraryfeature.cpp b/src/library/mixxxlibraryfeature.cpp
index 43393d1d9b..bb090dba9c 100644
--- a/src/library/mixxxlibraryfeature.cpp
+++ b/src/library/mixxxlibraryfeature.cpp
@@ -66,7 +66,7 @@ MixxxLibraryFeature::MixxxLibraryFeature(Library* pLibrary,
<< "library." + LIBRARYTABLE_COVERART_LOCATION
<< "library." + LIBRARYTABLE_COVERART_HASH;
- QSqlQuery query(pTrackCollection->getDatabase());
+ QSqlQuery query(pTrackCollection->database());
QString tableName = "library_cache_view";
QString queryString = QString(
"CREATE TEMPORARY VIEW IF NOT EXISTS %1 AS "
diff --git a/src/library/playlistfeature.cpp b/src/library/playlistfeature.cpp
index 2ea3ef6348..0f1d513d08 100644
--- a/src/library/playlistfeature.cpp
+++ b/src/library/playlistfeature.cpp
@@ -140,13 +140,13 @@ void PlaylistFeature::buildPlaylistList() {
"LEFT JOIN library ON PlaylistTracks.track_id = library.id "
"WHERE Playlists.hidden = 0 "
"GROUP BY Playlists.id;");
- QSqlQuery query(m_pTrackCollection->getDatabase());
+ QSqlQuery query(m_pTrackCollection->database());
if (!query.exec(queryString)) {
LOG_FAILED_QUERY(query);
}
// Setup the sidebar playlist model
- QSqlTableModel playlistTableModel(this, m_pTrackCollection->getDatabase());
+ QSqlTableModel playlistTableModel(this, m_pTrackCollection->database());
playlistTableModel.setTable("PlaylistsCountsDurations");
playlistTableModel.setSort(playlistTableModel.fieldIndex("sort_name"),
Qt::AscendingOrder);
diff --git a/src/library/rhythmbox/rhythmboxfeature.cpp b/src/library/rhythmbox/rhythmboxfeature.cpp
index 81dbc2029e..47a4e001e6 100644
--- a/src/library/rhythmbox/rhythmboxfeature.cpp
+++ b/src/library/rhythmbox/rhythmboxfeature.cpp
@@ -57,7 +57,7 @@ RhythmboxFeature::RhythmboxFeature(QObject* parent, TrackCollection* pTrackColle
m_isActivated = false;
m_title = tr("Rhythmbox");
- m_database = QSqlDatabase::cloneDatabase(pTrackCollection->getDatabase(),
+ m_database = QSqlDatabase::cloneDatabase(pTrackCollection->database(),
"RHYTHMBOX_SCANNER");
//Open the database connection in this thread.
diff --git a/src/library/scanner/libraryscanner.cpp b/src/library/scanner/libraryscanner.cpp
index e61fc2479a..843eb31d05 100644
--- a/src/library/scanner/libraryscanner.cpp
+++ b/src/library/scanner/libraryscanner.cpp
@@ -124,7 +124,7 @@ void LibraryScanner::run() {
Trace trace("LibraryScanner");
if (m_pCollection != NULL) { // false only during tests
if (!m_database.isValid()) {
- m_database = QSqlDatabase::cloneDatabase(m_pCollection->getDatabase(), "LIBRARY_SCANNER");
+ m_database = QSqlDatabase::cloneDatabase(m_pCollection->database(), "LIBRARY_SCANNER");
}
if (!m_database.isOpen()) {
diff --git a/src/library/setlogfeature.cpp b/src/library/setlogfeature.cpp
index 18dbbdef4f..530e157c21 100644
--- a/src/library/setlogfeature.cpp
+++ b/src/library/setlogfeature.cpp
@@ -117,7 +117,7 @@ void SetlogFeature::onRightClickChild(const QPoint& globalPos, QModelIndex index
void SetlogFeature::buildPlaylistList() {
m_playlistList.clear();
// Setup the sidebar playlist model
- QSqlTableModel playlistTableModel(this, m_pTrackCollection->getDatabase());
+ QSqlTableModel playlistTableModel(this, m_pTrackCollection->database());
playlistTableModel.setTable("Playlists");
playlistTableModel.setFilter("hidden=2"); // PLHT_SET_LOG
playlistTableModel.setSort(playlistTableModel.fieldIndex("id"),
diff --git a/src/library/trackcollection.cpp b/src/library/trackcollection.cpp
index 70a1bcd46c..6c8559f7b5 100644
--- a/src/library/trackcollection.cpp
+++ b/src/library/trackcollection.cpp
@@ -3,10 +3,6 @@
#include "library/trackcollection.h"
-#ifdef __SQLITE3__
-#include <sqlite3.h>
-#endif
-
#include "library/librarytablemodel.h"
#include "library/schemamanager.h"
#include "library/crate/cratestorage.h"
@@ -20,25 +16,14 @@ const int TrackCollection::kRequiredSchemaVersion = 27;
TrackCollection::TrackCollection(UserSettingsPointer pConfig)
: m_pConfig(pConfig),
- m_db(QSqlDatabase::addDatabase("QSQLITE")), // defaultConnection
- m_playlistDao(m_db),
- m_cueDao(m_db),
- m_directoryDao(m_db),
- m_analysisDao(m_db, pConfig),
- m_libraryHashDao(m_db),
- m_trackDao(m_db, m_cueDao, m_playlistDao,
+ m_dbConnection(m_pConfig->getSettingsPath()),
+ m_playlistDao(database()),
+ m_cueDao(database()),
+ m_directoryDao(database()),
+ m_analysisDao(database(), pConfig),
+ m_libraryHashDao(database()),
+ m_trackDao(database(), m_cueDao, m_playlistDao,
m_analysisDao, m_libraryHashDao, pConfig) {
- qDebug() << "Available QtSQL drivers:" << QSqlDatabase::drivers();
-
- m_db.setHostName("localhost");
- m_db.setDatabaseName(QDir(pConfig->getSettingsPath()).filePath("mixxxdb.sqlite"));
- m_db.setUserName("mixxx");
- m_db.setPassword("mixxx");
- bool ok = m_db.open();
- qDebug() << "DB status:" << m_db.databaseName() << "=" << ok;
- if (m_db.lastError().isValid()) {
- qDebug() << "Error loading database:" << m_db.lastError();
- }
// Check for tables and create them if missing
if (!checkForTables()) {
// TODO(XXX) something a little more elegant
@@ -50,24 +35,10 @@ TrackCollection::~TrackCollection() {
qDebug() << "~TrackCollection()";
m_trackDao.finish();
m_crates.detachDatabase();
-
- if (m_db.isOpen()) {
- // There should never be an outstanding transaction when this code is
- // called. If there is, it means we probably aren't committing a
- // transaction somewhere that should be.
- if (m_db.rollback()) {
- qDebug() << "ERROR: There was a transaction in progress on the main database connection while shutting down."
- << "There is a logic error somewhere.";
- }
- m_db.close();
- } else {
- qDebug() << "ERROR: The main database connection was closed before TrackCollection closed it."
- << "There is a logic error somewhere.";
- }
}
bool TrackCollection::checkForTables() {
- if (!m_db.open()) {
+ if (!m_dbConnection) {
QMessageBox::critical(0, tr("Cannot open database"),
tr("Unable to establish a database connection.\n"
"Mixxx requires QT with SQLite support. Please read "
@@ -77,10 +48,6 @@ bool TrackCollection::checkForTables() {
return false;
}
-#ifdef __SQLITE3__
- installSorting(m_db);
-#endif
-
// The schema XML is baked into the binary via Qt resources.
QString schemaFilename(":/schema.xml");
QString okToExit = tr("Click OK to exit.");
@@ -92,7 +59,7 @@ bool TrackCollection::checkForTables() {
"mixxx-devel@lists.sourceforge.net";
SchemaManager::Result result = SchemaManager::upgradeToSchemaVersion(
- schemaFilename, m_db, kRequiredSchemaVersion);
+ schemaFilename, database(), kRequiredSchemaVersion);
switch (result) {
case SchemaManager::RESULT_BACKWARDS_INCOMPATIBLE:
QMessageBox::warning(
@@ -130,14 +97,10 @@ bool TrackCollection::checkForTables() {
m_cueDao.initialize();
m_directoryDao.initialize();
m_libraryHashDao.initialize();
- m_crates.attachDatabase(m_db);
+ m_crates.attachDatabase(database());
return true;
}
-QSqlDatabase& TrackCollection::getDatabase() {
- return m_db;
-}
-
TrackDAO& TrackCollection::getTrackDAO() {
return m_trackDao;
}
@@ -391,344 +354,3 @@ bool TrackCollection::removeCrateTracks(
return true;
}
-
-#ifdef __SQLITE3__
-
-// from public domain code
-// http://www.archivum.info/qt-interest@trolltech.com/2008-12/00584/Re-%28Qt-interest%29-Qt-Sqlite-UserDefinedFunction.html
-
-namespace {
-
-inline
-int compareLocalAwareCaseInsensitive(
- const QString& first, const QString& second) {
- return QString::localeAwareCompare(first.toLower(), second.toLower());
-}
-
-void makeLatinLow(QChar* c, int count) {
- for (int i = 0; i < count; ++i) {
- if (c[i].decompositionTag() != QChar::NoDecomposition) {
- c[i] = c[i].decomposition()[0];
- }
- if (c[i].isUpper()) {
- c[i] = c[i].toLower();
- }
- }
-}
-
-const QChar LIKE_MATCH_ONE = '_';
-const QChar LIKE_MATCH_ALL = '%';
-const QChar LIKE_DEFAULT_ESCAPE = '\0';
-
-// The collating function callback is invoked with a copy of the pArg
-// application data pointer and with two strings in the encoding specified
-// by the eTextRep argument.
-// The collating function must return an integer that is negative, zero,
-// or positive if the first string is less than, equal to, or greater
-// than the second, respectively.
-int sqliteStringCompare(void* pArg,
- int len1, const void* data1,
- int len2, const void* data2) {
- Q_UNUSED(pArg);
- // Construct a QString without copy
- QString string1 = QString::fromRawData(reinterpret_cast<const QChar*>(data1),
- len1 / sizeof(QChar));
- QString string2 = QString::fromRawData(reinterpret_cast<const QChar*>(data2),
- len2 / sizeof(QChar));
- return compareLocalAwareCaseInsensitive(string1, string2);
-}
-
-// Compare two strings for equality where the first string is
-// a "LIKE" expression. Return true (1) if they are the same and
-// false (0) if they are different.
-// This is the original sqlite3 icuLikeCompare rewritten for QChar
-int likeCompareInner(
- const QChar* pattern, // LIKE pattern
- int patternSize,
- const QChar* string, // The string to compare against
- int stringSize,
- const QChar esc) { // The escape character
-
- int iPattern = 0; // Current index in pattern
- int iString = 0; // Current index in string
-
- bool prevEscape = false; // True if the previous character was uEsc
-
- while (iPattern < patternSize) {
- // Read (and consume) the next character from the input pattern.
- QChar uPattern = pattern[iPattern++];
- // There are now 4 possibilities:
- // 1. uPattern is an unescaped match-all character "%",
- // 2. uPattern is an unescaped match-one character "_",
- // 3. uPattern is an unescaped escape character, or
- // 4. uPattern is to be handled as an ordinary character
-
- if (!prevEscape && uPattern == LIKE_MATCH_ALL) {
- // Case 1.
- QChar c;
-
- // Skip any LIKE_MATCH_ALL or LIKE_MATCH_ONE characters that follow a
- // LIKE_MATCH_ALL. For each LIKE_MATCH_ONE, skip one character in the
- // test string.
-
- if (iPattern >= patternSize) {
- // Tailing %
- return 1;
- }
-
- while ((c = pattern[iPattern]) == LIKE_MATCH_ALL || c == LIKE_MATCH_ONE) {
- if (c == LIKE_MATCH_ONE) {
- if (++iString == stringSize) {
- return 0;
- }
- }
- if (++iPattern == patternSize) {
- // Two or more tailing %
- return 1;
- }
- }
-
- while (iString < stringSize) {
- if (likeCompareInner(&pattern[iPattern], patternSize - iPattern,
- &string[iString], stringSize - iString, esc)) {
- return 1;
- }
- iString++;
- }
- return 0;
- } else if (!prevEscape && uPattern == LIKE_MATCH_ONE) {
- // Case 2.
- if (++iString == stringSize) {
- return 0;
- }
- } else if (!prevEscape && uPattern == esc) {
- // Case 3.
- prevEscape = 1;
- } else {
- // Case 4.
- if (iString == stringSize) {
- return 0;
- }
- QChar uString = string[iString++];
- if (uString != uPattern) {
- return 0;
- }
- prevEscape = false;
- }
- }
- return iString == stringSize;
-}
-
-} // anonymous namespace
-
-void TrackCollection::installSorting(QSqlDatabase &db) {
- QVariant v = db.driver()->handle();
- if (v.isValid() && strcmp(v.typeName(), "sqlite3*") == 0) {
- // v.data() returns a pointer to the handle
- sqlite3* handle = *static_cast<sqlite3**>(v.data());
- if (handle != 0) { // check that it is not NULL
- int result = sqlite3_create_collation(
- handle,
- "localeAwareCompare",
- SQLITE_UTF16,
- NULL,
- sqliteStringCompare);
- if (result != SQLITE_OK)
- qWarning() << "Could not add string collation function: " << result;
-
- result = sqlite3_create_function(
- handle,
- "like",
- 2,
- SQLITE_ANY,
- NULL,
- sqliteLike,
- NULL, NULL);
- if (result != SQLITE_OK)
- qWarning() << "Could not add like 2 function: " << result;
-
- result = sqlite3_create_function(
- handle,
- "like",
- 3,
- SQLITE_UTF8, // No conversion, Data is stored as UTF8
- NULL,
- sqliteLike,
- NULL, NULL);
- if (result != SQLITE_OK)
- qWarning() << "Could not add like 3 function: " << result;
- } else {
- qWarning() << "Could not get sqlite handle";
- }
- } else {
- qWarning() << "handle variant returned typename " << v.typeName();
- }
-}
-
-// This implements the like() SQL function. This is used by the LIKE operator.
-// The SQL statement 'A LIKE B' is implemented as 'like(B, A)', and if there is
-// an escape character, say E, it is implemented as 'like(B, A, E)'
-//static
-void TrackCollection::sqliteLike(sqlite3_context *context,
- int aArgc,
- sqlite3_value **aArgv) {
- VERIFY_OR_DEBUG_ASSERT(aArgc == 2 || aArgc == 3) {
- return;
- }
-
- const char* b = reinterpret_cast<const char*>(
- sqlite3_value_text(aArgv[0]));
- const char* a = reinterpret_cast<const char*>(
- sqlite3_value_text(aArgv[1]));
-
- if (!a || !b) {
- return;
- }
-
- QString stringB = QString::fromUtf8(b); // Like String
- QString stringA = QString::fromUtf8(a);
-
- QChar esc = LIKE_DEFAULT_ESCAPE;
- if (aArgc == 3) {
- const char* e = reinterpret_cast<const char*>(
- sqlite3_value_text(aArgv[2]));
- if (e) {
- QString stringE = QString::fromUtf8(e);
- if (!stringE.isEmpty()) {
- esc = stringE.data()[0];
- }
- }
- }
-
- int ret = likeCompareLatinLow(&stringB, &stringA, esc);
- sqlite3_result_int64(context, ret);
- return;
-}
-
-//static
-int TrackCollection::likeCompareLatinLow(
- QString* pattern,
- QString* string,
- QChar esc) {
- makeLatinLow(pattern->data(), pattern->length());
- makeLatinLow(string->data(), string->length());
- //qDebug() << *pattern << *string;
- return likeCompareInner(pattern->data(), pattern->length(), string->data(), string->length(), esc);
-}
-
-
-/*
-static int
-likeCompare(nsAString::const_iterator aPatternItr,
- nsAString::const_iterator aPatternEnd,
- nsAString::const_iterator aStringItr,
- nsAString::const_iterator aStringEnd,
- PRUnichar aEscape)
-{
- const PRUnichar LIKE_MATCH_ALL('%');
- const PRUnichar LIKE_MATCH_ONE('_');
-
- PRBool lastWasEscape = PR_FALSE;
- while (aPatternItr != aPatternEnd) {
-
-* What we do in here is take a look at each character from the input
-* pattern, and do something with it. There are 4 possibilities:
-* 1) character is an un-escaped match-all character
-* 2) character is an un-escaped match-one character
-* 3) character is an un-escaped escape character
-* 4) character is not any of the above
-
- if (!lastWasEscape && *aPatternItr == LIKE_MATCH_ALL) {
- // CASE 1
-
-* Now we need to skip any LIKE_MATCH_ALL or LIKE_MATCH_ONE characters that follow a
-* LIKE_MATCH_ALL character. For each LIKE_MATCH_ONE character, skip one character
-* in the pattern string.
-
- while (*aPatternItr == LIKE_MATCH_ALL || *aPatternItr == LIKE_MATCH_ONE) {
- if (*aPatternItr == LIKE_MATCH_ONE) {
- // If we've hit the end of the string we are testing, no match
- if (aStringItr == aStringEnd)
- return 0;
- aStringItr++;
- }
- aPatternItr++;
- }
-
- // If we've hit the end of the pattern string, match
- if (aPatternItr == aPatternEnd)
- return 1;
-
- while (aStringItr != aStringEnd) {
- if (likeCompare(aPatternItr, aPatternEnd, aStringItr, aStringEnd, aEscape)) {
- // we've hit a match, so indicate this
- return 1;
- }
- aStringItr++;
- }
-
- // No match
- return 0;
- } else if (!lastWasEscape && *aPatternItr == LIKE_MATCH_ONE) {
- // CASE 2
- if (aStringItr == aStringEnd) {
- // If we've hit the end of the string we are testing, no match
- return 0;
- }
- aStringItr++;
- lastWasEscape = PR_FALSE;
- } else if (!lastWasEscape && *aPatternItr == aEscape) {
- // CASE 3
- lastWasEscape = PR_TRUE;
- } else {
- // CASE 4
- if (ToUpperCase(*aStringItr) != ToUpperCase(*aPatternItr)) {
- // If we've hit a point where the strings don't match, there is no match
- return 0;
- }
- aStringItr++;
- lastWasEscape = PR_FALSE;
- }
-
- aPatternItr++;
- }
-
- return aStringItr == aStringEnd;
-}
-
-
-.
-void
-StorageUnicodeFunctions::likeFunction(sqlite3_context *p,
- int aArgc,
- sqlite3_value **aArgv)
-{
- NS_ASSERTION(2 == aArgc || 3 == aArgc, "Invalid number of arguments!");
-
- if (sqlite3_value_bytes(aArgv[0]) > SQLITE_MAX_LIKE_PATTERN_LENGTH) {
- sqlite3_result_error(p, "LIKE or GLOB pattern too complex", SQLITE_TOOBIG);
- return;
- }
-
- if (!sqlite3_value_text16(aArgv[0]) || !sqlite3_value_text16(aArgv[1]))
- return;
-
- nsDependentString A(static_cast<const PRUnichar *>(sqlite3_value_text16(aArgv[1])));
- nsDependentString B(static_cast<const PRUnichar *>(sqlite3_value_text16(aArgv[0])));
- NS_ASSERTION(!B.IsEmpty(), "LIKE string must not be null!");
-
- PRUnichar E = 0;
- if (3 == aArgc)
- E = static_cast<const PRUnichar *>(sqlite3_value_text16(aArgv[2]))[0];
-
- nsAString::const_iterator itrString, endString;
- A.BeginReading(itrString);
- A.EndReading(endString);