[SCM] Akonadi packaging branch, master, updated. debian/1.13.0-6-1-g93b22bd
Dmitry Smirnov
onlyjob at moszumanska.debian.org
Mon Jul 20 03:23:29 UTC 2015
Gitweb-URL: http://git.debian.org/?p=pkg-kde/kde-req/akonadi.git;a=commitdiff;h=93b22bd
The following commit has been merged in the master branch:
commit 93b22bdf7172db48d7e670f751fcc353f39346e7
Author: Dmitry Smirnov <onlyjob at member.fsf.org>
Date: Mon Jul 20 12:34:09 2015 +1000
Drop patches introduced in previous upload due to regressions
causing invalid SQL commands.
---
debian/changelog | 8 +
debian/patches/series | 3 -
...001-skip-value-condition-on-invalid-flags.patch | 38 ---
.../upstream_opt-0006-cache-PartTypes.patch | 261 --------------
...7-avoid-recursive-listing-in-SearchHelper.patch | 374 ---------------------
5 files changed, 8 insertions(+), 676 deletions(-)
diff --git a/debian/changelog b/debian/changelog
index 0aad6e9..7213b06 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,11 @@
+akonadi (1.13.0-7) unstable; urgency=medium
+
+ * Team upload.
+ * Removed some patches introduced in previous upload due to regressions
+ causing invalid SQL commands.
+
+ -- Dmitry Smirnov <onlyjob at debian.org> Mon, 20 Jul 2015 12:30:32 +1000
+
akonadi (1.13.0-6) unstable; urgency=medium
* Team upload.
diff --git a/debian/patches/series b/debian/patches/series
index 9101dec..b64faf0 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -8,10 +8,7 @@ upstream-prevent-QTimer-negative-interval.patch
upstream-use-QAtomicInt.patch
upstream_dont_call_insert_from_Q_ASSERT.patch
upstream_dont_leak_old_external_payload_files.patch
-upstream_opt-0001-skip-value-condition-on-invalid-flags.patch
upstream_opt-0002-intern-entity-strings.patch
upstream_opt-0003-QMutexLocker.patch
upstream_opt-0004-one-hash-lookup.patch
upstream_opt-0005-optimize-queries.patch
-upstream_opt-0006-cache-PartTypes.patch
-upstream_opt-0007-avoid-recursive-listing-in-SearchHelper.patch
diff --git a/debian/patches/upstream_opt-0001-skip-value-condition-on-invalid-flags.patch b/debian/patches/upstream_opt-0001-skip-value-condition-on-invalid-flags.patch
deleted file mode 100644
index 786eb96..0000000
--- a/debian/patches/upstream_opt-0001-skip-value-condition-on-invalid-flags.patch
+++ /dev/null
@@ -1,38 +0,0 @@
-From 7cbff48f5782d1f7f844678e6b785aeb419b0c47 Mon Sep 17 00:00:00 2001
-From: Milian Wolff <mail at milianw.de>
-Date: Mon, 1 Dec 2014 11:59:12 +0100
-Subject: [PATCH] Optimize: Skip value condition on invalid flags.
-
-HandlerHelper::itemWithFlagsCount gets called quite often apparently
-and I noticed that it was relatively slow from the Query Debugger
-in Akonadi Console. EXPLAIN'ing the query showed that it was using
-a slow-path for the WHERE FOO AND (BAR OR ASDF) condition. Here,
-ASDF was always id = -1, the id of the $IGNORED flag, which
-I apparently don't have. Getting rid of that condition simplifies
-the query to WHERE FOO AND BAR, which is apparently much better
-optimizable. Before, the query often showed a runtime of ~15ms.
-Now it is down to ~9ms.
-
-REVIEW: 121306
----
- server/src/handlerhelper.cpp | 4 ++++
- 1 file changed, 4 insertions(+)
-
-diff --git a/server/src/handlerhelper.cpp b/server/src/handlerhelper.cpp
-index 634a26c..82347b4 100644
---- a/server/src/handlerhelper.cpp
-+++ b/server/src/handlerhelper.cpp
-@@ -123,6 +123,10 @@ int HandlerHelper::itemWithFlagsCount( const Collection &col, const QStringList
- // it hits an in-memory cache.
- Q_FOREACH ( const QString &flag, flags ) {
- const Flag f = Flag::retrieveByName( flag );
-+ if (!f.isValid()) {
-+ // since we OR this condition, we can skip invalid flags to speed up the query
-+ continue;
-+ }
- cond.addValueCondition( PimItemFlagRelation::rightFullColumnName(), Query::Equals, f.id() );
- }
- qb.addCondition( cond );
---
-2.1.4
-
diff --git a/debian/patches/upstream_opt-0006-cache-PartTypes.patch b/debian/patches/upstream_opt-0006-cache-PartTypes.patch
deleted file mode 100644
index 51d1f7e..0000000
--- a/debian/patches/upstream_opt-0006-cache-PartTypes.patch
+++ /dev/null
@@ -1,261 +0,0 @@
-From 215b188d891d5236fe94131d176d7ddc3ae02d5d Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Dan=20Vr=C3=A1til?= <dvratil at redhat.com>
-Date: Fri, 5 Dec 2014 17:12:28 +0100
-Subject: [PATCH] Avoid ridiculous amount of SQL queries by caching PartTypes
-
-PartTypes are identified by their FQ name, which is in form NAMESPACE:NAME,
-where namespace and name are stored in individual columns. For this reason
-the standard ::retrieveByName() and name cache generated from entities.xslt
-does not work. This patch adds special handling for PartType table, so that
-a special PartType::retrieveByFQName() method as well as PartType name cache
-handling are generated during the XSL Transformation, allowing us to cache
-all the PartTypes.
-
-This reduces the amount of SQL queries by at least two for each single AKAPPEND,
-MERGE, STORE and FETCH command, providing a nice performance boost during
-sync.
----
- server/src/handler/append.cpp | 4 ++--
- server/src/storage/datastore.cpp | 4 +++-
- server/src/storage/entities-header.xsl | 7 ++++++-
- server/src/storage/entities-source.xsl | 31 ++++++++++++++++++++++++++++++-
- server/src/storage/entities.xsl | 7 ++++++-
- server/src/storage/parttypehelper.cpp | 29 +----------------------------
- server/src/storage/parttypehelper.h | 13 -------------
- 7 files changed, 48 insertions(+), 47 deletions(-)
-
-diff --git a/server/src/handler/append.cpp b/server/src/handler/append.cpp
-index c503216..b594e27 100644
---- a/server/src/handler/append.cpp
-+++ b/server/src/handler/append.cpp
-@@ -134,7 +134,7 @@ bool Append::commit()
-
- // wrap data into a part
- Part part;
-- part.setPartType( PartTypeHelper::fromName( "PLD", "RFC822" ) );
-+ part.setPartType( PartType::retrieveByFQName( QLatin1String("PLD"), QLatin1String("RFC822") ) );
- part.setData( m_data );
- part.setPimItemId( item.id() );
- part.setDatasize( dataSize );
-@@ -148,7 +148,7 @@ bool Append::commit()
- //akDebug() << "Append handler: doPreprocessing is" << doPreprocessing;
- if ( doPreprocessing ) {
- Part hiddenAttribute;
-- hiddenAttribute.setPartType( PartTypeHelper::fromName( "ATR", "HIDDEN" ) );
-+ hiddenAttribute.setPartType( PartType::retrieveByFQName( QLatin1String("ATR"), QLatin1String("HIDDEN") ) );
- hiddenAttribute.setData( QByteArray() );
- hiddenAttribute.setPimItemId( item.id() );
- hiddenAttribute.setDatasize( 0 );
-diff --git a/server/src/storage/datastore.cpp b/server/src/storage/datastore.cpp
-index ae78bab..304f0e8 100644
---- a/server/src/storage/datastore.cpp
-+++ b/server/src/storage/datastore.cpp
-@@ -183,6 +183,7 @@ bool DataStore::init()
- Flag::enableCache( true );
- Resource::enableCache( true );
- Collection::enableCache( true );
-+ PartType::enableCache( true );
-
- return true;
- }
-@@ -1025,7 +1026,8 @@ bool DataStore::unhideAllPimItems()
- akDebug() << "DataStore::unhideAllPimItems()";
-
- try {
-- return PartHelper::remove( Part::partTypeIdFullColumnName(), PartTypeHelper::fromName( "ATR", "HIDDEN" ).id() );
-+ return PartHelper::remove( Part::partTypeIdFullColumnName(),
-+ PartType::retrieveByFQName( QLatin1String("ATR"), QLatin1String("HIDDEN") ).id() );
- } catch ( ... ) {} // we can live with this failing
-
- return false;
-diff --git a/server/src/storage/entities-header.xsl b/server/src/storage/entities-header.xsl
-index 4966966..d515fd3 100644
---- a/server/src/storage/entities-header.xsl
-+++ b/server/src/storage/entities-header.xsl
-@@ -133,11 +133,16 @@ class <xsl:value-of select="$className"/> : private Entity
- <xsl:text>static </xsl:text><xsl:value-of select="$className"/> retrieveById( qint64 id );
- </xsl:if>
-
-- <xsl:if test="column[@name = 'name']">
-+ <xsl:if test="column[@name = 'name'] and $className != 'PartType'">
- /** Returns the record with name @p name. */
- <xsl:text>static </xsl:text><xsl:value-of select="$className"/> retrieveByName( const <xsl:value-of select="column[@name = 'name']/@type"/> &name );
- </xsl:if>
-
-+ <xsl:if test="column[@name = 'name'] and $className = 'PartType'">
-+ <!-- Special case for PartTypes, which are identified by "NS:NAME" -->
-+ <xsl:text>static PartType retrieveByFQName( const QString &ns, const QString &name );</xsl:text>
-+ </xsl:if>
-+
- /** Retrieve all records from this table. */
- static <xsl:value-of select="$className"/>::List retrieveAll();
- /** Retrieve all records with value @p value in column @p key. */
-diff --git a/server/src/storage/entities-source.xsl b/server/src/storage/entities-source.xsl
-index e398da5..46ef3a6 100644
---- a/server/src/storage/entities-source.xsl
-+++ b/server/src/storage/entities-source.xsl
-@@ -130,7 +130,15 @@ void <xsl:value-of select="$className"/>::Private::addToCache( const <xsl:value-
- idCache.insert( entry.id(), entry );
- </xsl:if>
- <xsl:if test="column[@name = 'name']">
-+ <xsl:choose>
-+ <xsl:when test="$className = 'PartType'">
-+ <!-- special case for PartType, which is identified as "NS:NAME" -->
-+ nameCache.insert( entry.ns() + QLatin1Char(':') + entry.name(), entry );
-+ </xsl:when>
-+ <xsl:otherwise>
- nameCache.insert( entry.name(), entry );
-+ </xsl:otherwise>
-+ </xsl:choose>
- </xsl:if>
- }
-
-@@ -323,7 +331,7 @@ QVector< <xsl:value-of select="$className"/> > <xsl:value-of select="$clas
- }
-
- </xsl:if>
--<xsl:if test="column[@name = 'name']">
-+<xsl:if test="column[@name = 'name'] and $className != 'PartType'">
- <xsl:value-of select="$className"/><xsl:text> </xsl:text><xsl:value-of select="$className"/>::retrieveByName( const <xsl:value-of select="column[@name = 'name']/@type"/> &name )
- {
- <xsl:call-template name="data-retrieval">
-@@ -333,6 +341,19 @@ QVector< <xsl:value-of select="$className"/> > <xsl:value-of select="$clas
- }
- </xsl:if>
-
-+<xsl:if test="column[@name = 'name'] and $className = 'PartType'">
-+<xsl:text>PartType PartType::retrieveByFQName( const QString & ns, const QString & name )</xsl:text>
-+{
-+ const QString fqname = ns + QLatin1Char(':') + name;
-+ <xsl:call-template name="data-retrieval">
-+ <xsl:with-param name="key">ns</xsl:with-param>
-+ <xsl:with-param name="key2">name</xsl:with-param>
-+ <xsl:with-param name="lookupKey">fqname</xsl:with-param>
-+ <xsl:with-param name="cache">nameCache</xsl:with-param>
-+ </xsl:call-template>
-+}
-+</xsl:if>
-+
- QVector<<xsl:value-of select="$className"/>> <xsl:value-of select="$className"/>::retrieveAll()
- {
- QSqlDatabase db = DataStore::self()->database();
-@@ -588,7 +609,15 @@ void <xsl:value-of select="$className"/>::invalidateCache() const
- Private::idCache.remove( id() );
- </xsl:if>
- <xsl:if test="column[@name = 'name']">
-+ <xsl:choose>
-+ <xsl:when test="$className = 'PartType'">
-+ <!-- Special handling for PartType, which is identified as "NS:NAME" -->
-+ Private::nameCache.remove( ns() + QLatin1Char(':') + name() );
-+ </xsl:when>
-+ <xsl:otherwise>
- Private::nameCache.remove( name() );
-+ </xsl:otherwise>
-+ </xsl:choose>
- </xsl:if>
- }
- }
-diff --git a/server/src/storage/entities.xsl b/server/src/storage/entities.xsl
-index c8fb1fd..2cf96c4 100644
---- a/server/src/storage/entities.xsl
-+++ b/server/src/storage/entities.xsl
-@@ -169,12 +169,14 @@ set<xsl:value-of select="$methodName"/>( <xsl:call-template name="argument"/> )
- <!-- data retrieval for a given key field -->
- <xsl:template name="data-retrieval">
- <xsl:param name="key"/>
-+<xsl:param name="key2"/>
-+<xsl:param name="lookupKey" select="$key"/>
- <xsl:param name="cache"/>
- <xsl:variable name="className"><xsl:value-of select="@name"/></xsl:variable>
- <xsl:if test="$cache != ''">
- if ( Private::cacheEnabled ) {
- QMutexLocker lock(&Private::cacheMutex);
-- QHash<<xsl:value-of select="column[@name = $key]/@type"/>, <xsl:value-of select="$className"/>>::const_iterator it = Private::<xsl:value-of select="$cache"/>.constFind(<xsl:value-of select="$key"/>);
-+ QHash<<xsl:value-of select="column[@name = $key]/@type"/>, <xsl:value-of select="$className"/>>::const_iterator it = Private::<xsl:value-of select="$cache"/>.constFind(<xsl:value-of select="$lookupKey"/>);
- if ( it != Private::<xsl:value-of select="$cache"/>.constEnd() ) {
- return it.value();
- }
-@@ -188,6 +190,9 @@ set<xsl:value-of select="$methodName"/>( <xsl:call-template name="argument"/> )
- static const QStringList columns = removeEntry(columnNames(), <xsl:value-of select="$key"/>Column());
- qb.addColumns( columns );
- qb.addValueCondition( <xsl:value-of select="$key"/>Column(), Query::Equals, <xsl:value-of select="$key"/> );
-+ <xsl:if test="$key2 != ''">
-+ qb.addValueCondition( <xsl:value-of select="$key2"/>Column(), Query::Equals, <xsl:value-of select="$key2"/> );
-+ </xsl:if>
- if ( !qb.exec() ) {
- akDebug() << "Error during selection of record with <xsl:value-of select="$key"/>"
- << <xsl:value-of select="$key"/> << "from table" << tableName()
-diff --git a/server/src/storage/parttypehelper.cpp b/server/src/storage/parttypehelper.cpp
-index b73dcd5..7654108 100644
---- a/server/src/storage/parttypehelper.cpp
-+++ b/server/src/storage/parttypehelper.cpp
-@@ -37,7 +37,7 @@ QPair< QString, QString > PartTypeHelper::parseFqName(const QString& fqName)
- PartType PartTypeHelper::fromFqName(const QString& fqName)
- {
- const QPair<QString, QString> p = parseFqName( fqName );
-- return fromName( p.first, p.second );
-+ return PartType::retrieveByFQName(p.first, p.second);
- }
-
- PartType PartTypeHelper::fromFqName(const QByteArray& fqName)
-@@ -45,33 +45,6 @@ PartType PartTypeHelper::fromFqName(const QByteArray& fqName)
- return fromFqName( QLatin1String(fqName) );
- }
-
--PartType PartTypeHelper::fromName(const QString& ns, const QString& typeName)
--{
-- SelectQueryBuilder<PartType> qb;
-- qb.addValueCondition( PartType::nsColumn(), Query::Equals, ns );
-- qb.addValueCondition( PartType::nameColumn(), Query::Equals, typeName );
-- if ( !qb.exec() )
-- throw PartTypeException( "Unable to query part type table." );
-- const PartType::List result = qb.result();
-- if ( result.size() == 1 )
-- return result.first();
-- if ( result.size() > 1 )
-- throw PartTypeException( "Part type uniqueness constraint violation." );
--
-- // doesn't exist yet, so let's create a new one
-- PartType type;
-- type.setName( typeName );
-- type.setNs( ns );
-- if ( !type.insert() )
-- throw PartTypeException( "Creating a new part type failed." );
-- return type;
--}
--
--PartType PartTypeHelper::fromName(const char* ns, const char* typeName)
--{
-- return fromName( QLatin1String(ns), QLatin1String(typeName) );
--}
--
- Query::Condition PartTypeHelper::conditionFromFqName(const QString& fqName)
- {
- const QPair<QString, QString> p = parseFqName( fqName );
-diff --git a/server/src/storage/parttypehelper.h b/server/src/storage/parttypehelper.h
-index 38cb858..4c4f42f 100644
---- a/server/src/storage/parttypehelper.h
-+++ b/server/src/storage/parttypehelper.h
-@@ -48,19 +48,6 @@ namespace PartTypeHelper
- PartType fromFqName( const QByteArray &fqName );
-
- /**
-- * Retrieve (or create) PartType for the given namespace and type name.
-- * @param ns Namespace
-- * @param typeName Part type name.
-- * @throws PartTypeException
-- */
-- PartType fromName( const QString &ns, const QString &typeName );
--
-- /**
-- * Convenience overload of the above.
-- */
-- PartType fromName( const char *ns, const char *typeName );
--
-- /**
- * Returns a query condition that matches the given part.
- * @param fqName fully-qualified part type name
- * @throws PartTypeException
---
-2.1.4
-
diff --git a/debian/patches/upstream_opt-0007-avoid-recursive-listing-in-SearchHelper.patch b/debian/patches/upstream_opt-0007-avoid-recursive-listing-in-SearchHelper.patch
deleted file mode 100644
index eebf493..0000000
--- a/debian/patches/upstream_opt-0007-avoid-recursive-listing-in-SearchHelper.patch
+++ /dev/null
@@ -1,374 +0,0 @@
-From 059d52845cbbc10e882764f64245c5995af4e741 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Dan=20Vr=C3=A1til?= <dvratil at redhat.com>
-Date: Mon, 8 Dec 2014 13:49:27 +0100
-Subject: [PATCH] Avoid recursive collection listing in SearchHelper
-
-The recursive listing generates one SQL query per collection, and since search
-is invoked rather often (basically whenever you open an email in KMail), we get
-lots of unnecessary queries. This new algorithm does one query to fetch all
-folders with matching mime types, and only falls back to query the parent chain
-when the requested ancestor is not 0 (root), or when the result collection is
-not a direct descendant of the requested ancestor.
----
- server/src/handler/search.cpp | 4 +-
- server/src/handler/searchhelper.cpp | 111 ++++++++++++++----------
- server/src/handler/searchhelper.h | 2 +-
- server/src/search/searchmanager.cpp | 2 +-
- server/tests/unittest/CMakeLists.txt | 2 +
- server/tests/unittest/searchtest.cpp | 158 +++++++++++++++++++++++++++++++++++
- 6 files changed, 230 insertions(+), 49 deletions(-)
- create mode 100644 server/tests/unittest/searchtest.cpp
-
-diff --git a/server/src/handler/search.cpp b/server/src/handler/search.cpp
-index 06d172f..00484ff 100644
---- a/server/src/handler/search.cpp
-+++ b/server/src/handler/search.cpp
-@@ -95,9 +95,7 @@ bool Search::parseStream()
- }
-
- if ( recursive ) {
-- Q_FOREACH ( qint64 collection, collectionIds ) {
-- collections << SearchHelper::listCollectionsRecursive( QVector<qint64>() << collection, mimeTypes );
-- }
-+ collections << SearchHelper::matchSubcollectionsByMimeType( collectionIds, mimeTypes );
- } else {
- collections = collectionIds;
- }
-diff --git a/server/src/handler/searchhelper.cpp b/server/src/handler/searchhelper.cpp
-index aa6694d..1a06c0e 100644
---- a/server/src/handler/searchhelper.cpp
-+++ b/server/src/handler/searchhelper.cpp
-@@ -20,6 +20,7 @@
-
- #include "searchhelper.h"
- #include "storage/countquerybuilder.h"
-+#include <storage/queryhelper.h>
- #include "entities.h"
-
- #include <libs/protocol_p.h>
-@@ -89,55 +90,77 @@ QString SearchHelper::extractMimetype( const QList<QByteArray> &junks, int start
- }
-
-
--QVector<qint64> SearchHelper::listCollectionsRecursive( const QVector<qint64> &ancestors, const QStringList &mimeTypes )
-+static qint64 parentCollectionId(qint64 collectionId)
- {
-- QVector<qint64> recursiveChildren;
-- Q_FOREACH ( qint64 ancestor, ancestors ) {
-- QVector<qint64> searchChildren;
--
-- { // Free the query before entering recursion to prevent too many opened connections
--
-- Query::Condition mimeTypeCondition;
-- mimeTypeCondition.addColumnCondition( CollectionMimeTypeRelation::rightFullColumnName(), Query::Equals, MimeType::idFullColumnName() );
-- // Exclude top-level collections and collections that cannot have items!
-- mimeTypeCondition.addValueCondition( MimeType::nameFullColumnName(), Query::NotEquals, QLatin1String( "inode/directory" ) );
-- if ( !mimeTypes.isEmpty() ) {
-- mimeTypeCondition.addValueCondition( MimeType::nameFullColumnName(), Query::In, mimeTypes );
-- }
-+ QueryBuilder qb(Collection::tableName(), QueryBuilder::Select);
-+ qb.addColumn(Collection::parentIdColumn());
-+ qb.addValueCondition(Collection::idColumn(), Query::Equals, collectionId);
-+ if (!qb.exec()) {
-+ return -1;
-+ }
-+ if (!qb.query().next()) {
-+ return -1;
-+ }
-+ return qb.query().value(0).toLongLong();
-+}
-
-- CountQueryBuilder qb( Collection::tableName(), MimeType::nameFullColumnName(), CountQueryBuilder::All );
-- qb.addColumn( Collection::idFullColumnName() );
-- qb.addJoin( QueryBuilder::LeftJoin, CollectionMimeTypeRelation::tableName(), CollectionMimeTypeRelation::leftFullColumnName(), Collection::idFullColumnName() );
-- qb.addJoin( QueryBuilder::LeftJoin, MimeType::tableName(), mimeTypeCondition );
-- if ( ancestor == 0 ) {
-- qb.addValueCondition( Collection::parentIdFullColumnName(), Query::Is, QVariant() );
-- } else {
-- // Also include current ancestor's result, so that we know whether we should search in the ancestor too
-- Query::Condition idCond( Query::Or );
-- idCond.addValueCondition( Collection::parentIdFullColumnName(), Query::Equals, ancestor );
-- idCond.addValueCondition( Collection::idFullColumnName(), Query::Equals, ancestor );
-- qb.addCondition( idCond );
-- }
-- qb.addValueCondition( Collection::isVirtualFullColumnName(), Query::Equals, false );
-- qb.addGroupColumn( Collection::idFullColumnName() );
-- qb.exec();
--
-- QSqlQuery query = qb.query();
-- while ( query.next() ) {
-- const qint64 id = query.value( 1 ).toLongLong();
-- // Don't add ancestor into search children, we are resolving it right now
-- if ( id != ancestor ) {
-- searchChildren << id;
-+
-+QVector<qint64> SearchHelper::matchSubcollectionsByMimeType(const QVector<qint64> &ancestors, const QStringList &mimeTypes)
-+{
-+ // Get all collections with given mime types
-+ QueryBuilder qb(Collection::tableName(), QueryBuilder::Select);
-+ qb.setDistinct(true);
-+ qb.addColumn(Collection::idFullColumnName());
-+ qb.addColumn(Collection::parentIdFullColumnName());
-+ qb.addJoin(QueryBuilder::LeftJoin, CollectionMimeTypeRelation::tableName(),
-+ CollectionMimeTypeRelation::leftFullColumnName(), Collection::idFullColumnName());
-+ qb.addJoin(QueryBuilder::LeftJoin, MimeType::tableName(),
-+ CollectionMimeTypeRelation::rightFullColumnName(), MimeType::idFullColumnName());
-+ Query::Condition cond(Query::Or);
-+ Q_FOREACH (const QString &mt, mimeTypes) {
-+ cond.addValueCondition(MimeType::nameFullColumnName(), Query::Equals, mt);
-+ }
-+ qb.addCondition(cond);
-+
-+ if (!qb.exec()) {
-+ qWarning() << "Failed to query search collections";
-+ return QVector<qint64>();
-+ }
-+
-+ QMap<qint64 /* parentId */, QVector<qint64> /* collectionIds */> candidateCollections;
-+ while (qb.query().next()) {
-+ candidateCollections[qb.query().value(1).toLongLong()].append(qb.query().value(0).toLongLong());
-+ }
-+
-+ // If the ancestors list contains root, then return what we got, since everything
-+ // is sub collection of root
-+ QVector<qint64> results;
-+ if (ancestors.contains(0)) {
-+ Q_FOREACH (const QVector<qint64> &res, candidateCollections.values()) {
-+ results += res;
- }
-- if ( query.value( 0 ).toInt() > 0 ) { // count( mimeTypeTable.name ) > 0
-- recursiveChildren << id;
-+ return results;
-+ }
-+
-+ // Try to resolve direct descendants
-+ Q_FOREACH (qint64 ancestor, ancestors) {
-+ const QVector<qint64> cols = candidateCollections.take(ancestor);
-+ if (!cols.isEmpty()) {
-+ results += cols;
- }
-- }
- }
-- if ( !searchChildren.isEmpty() ) {
-- recursiveChildren << listCollectionsRecursive( searchChildren, mimeTypes );
-+
-+ for (auto iter = candidateCollections.begin(); iter != candidateCollections.end(); ++iter) {
-+ // Traverse the collection chain up to root
-+ qint64 parentId = iter.key();
-+ while (!ancestors.contains(parentId) && parentId > 0) {
-+ parentId = parentCollectionId(parentId);
-+ }
-+ // Ok, we found a requested ancestor in the parent chain
-+ if (parentId > 0) {
-+ results += iter.value();
-+ }
- }
-- }
-
-- return recursiveChildren;
-+ return results;
- }
-diff --git a/server/src/handler/searchhelper.h b/server/src/handler/searchhelper.h
-index a64bb61..1595501 100644
---- a/server/src/handler/searchhelper.h
-+++ b/server/src/handler/searchhelper.h
-@@ -33,7 +33,7 @@ class SearchHelper
- public:
- static QList<QByteArray> splitLine( const QByteArray &line );
- static QString extractMimetype( const QList<QByteArray> &junks, int start );
-- static QVector<qint64> listCollectionsRecursive( const QVector<qint64> &ancestors, const QStringList &mimeTypes );
-+ static QVector<qint64> matchSubcollectionsByMimeType( const QVector<qint64> &ancestors, const QStringList &mimeTypes );
- };
-
- } // namespace Server
-diff --git a/server/src/search/searchmanager.cpp b/server/src/search/searchmanager.cpp
-index c821aa3..b940fcc 100644
---- a/server/src/search/searchmanager.cpp
-+++ b/server/src/search/searchmanager.cpp
-@@ -296,7 +296,7 @@ void SearchManager::updateSearchImpl( const Collection &collection, QWaitConditi
- }
-
- if ( recursive ) {
-- queryCollections = SearchHelper::listCollectionsRecursive( queryAncestors, queryMimeTypes );
-+ queryCollections = SearchHelper::matchSubcollectionsByMimeType( queryAncestors, queryMimeTypes );
- } else {
- queryCollections = queryAncestors;
- }
-diff --git a/server/tests/unittest/CMakeLists.txt b/server/tests/unittest/CMakeLists.txt
-index b9744d9..acdc180 100644
---- a/server/tests/unittest/CMakeLists.txt
-+++ b/server/tests/unittest/CMakeLists.txt
-@@ -77,3 +77,5 @@ add_server_test(listhandlertest.cpp akonadiprivate)
- add_server_test(modifyhandlertest.cpp akonadiprivate)
- add_server_test(createhandlertest.cpp akonadiprivate)
- add_server_test(collectionreferencetest.cpp akonadiprivate)
-+
-+add_server_test(searchtest.cpp akonadiprivate)
-\ No newline at end of file
-diff --git a/server/tests/unittest/searchtest.cpp b/server/tests/unittest/searchtest.cpp
-new file mode 100644
-index 0000000..f523b09
---- /dev/null
-+++ b/server/tests/unittest/searchtest.cpp
-@@ -0,0 +1,158 @@
-+/*
-+ * Copyright (C) 2014 Daniel Vrátil <dvratil at redhat.com>
-+ *
-+ * This library is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * This library is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with this library; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-+ *
-+ */
-+
-+#include "fakeakonadiserver.h"
-+#include "searchhelper.h"
-+#include "akdebug.h"
-+#include "aktest.h"
-+
-+#include <entities.h>
-+
-+#include <QTest>
-+
-+using namespace Akonadi::Server;
-+
-+Q_DECLARE_METATYPE(QList<qint64>)
-+Q_DECLARE_METATYPE(QList<QString>)
-+
-+
-+class SearchTest : public QObject
-+{
-+ Q_OBJECT
-+
-+public:
-+ SearchTest()
-+ : QObject()
-+ {
-+ try {
-+ FakeAkonadiServer::instance()->setPopulateDb(false);
-+ FakeAkonadiServer::instance()->init();
-+ } catch (const FakeAkonadiServerException &e) {
-+ akError() << "Server exception: " << e.what();
-+ akFatal() << "Fake Akonadi Server failed to start up, aborting test";
-+ }
-+ }
-+
-+ ~SearchTest()
-+ {
-+ FakeAkonadiServer::instance()->quit();
-+ }
-+
-+ Collection createCollection(const Resource &res, const QString &name, const Collection &parent, const QStringList &mimetypes)
-+ {
-+ Collection col;
-+ col.setName(name);
-+ col.setResource(res);
-+ col.setParentId(parent.isValid() ? parent.id() : 0);
-+ col.insert();
-+ Q_FOREACH (const QString &mimeType, mimetypes) {
-+ MimeType mt = MimeType::retrieveByName(mimeType);
-+ if (!mt.isValid()) {
-+ mt = MimeType(mimeType);
-+ mt.insert();
-+ }
-+ col.addMimeType(mt);
-+ }
-+ return col;
-+ }
-+
-+private Q_SLOTS:
-+ void testSearchHelperCollectionListing_data()
-+ {
-+ /*
-+ Fake Resource
-+ |- Col 1 (inode/directory)
-+ | |- Col 2 (inode/direcotry, application/octet-stream)
-+ | | |- Col 3(application/octet-stream)
-+ | |- Col 4 (text/plain)
-+ |- Col 5 (inode/directory, text/plain)
-+ |- Col 6 (inode/directory, application/octet-stream)
-+ |- Col 7 (inode/directory, text/plain)
-+ |- Col 8 (inode/directory, application/octet-stream)
-+ |- Col 9 (unique/mime-type)
-+ */
-+
-+ Resource res(QLatin1String("Test Resource"), false);
-+ res.insert();
-+
-+ Collection col1 = createCollection(res, QLatin1String("Col 1"), Collection(),
-+ QStringList() << QLatin1String("inode/directory"));
-+ Collection col2 = createCollection(res, QLatin1String("Col 2"), col1,
-+ QStringList() << QLatin1String("inode/directory")
-+ << QLatin1String("application/octet-stream"));
-+ Collection col3 = createCollection(res, QLatin1String("Col 3"), col2,
-+ QStringList() << QLatin1String("application/octet-stream"));
-+ Collection col4 = createCollection(res, QLatin1String("Col 4"), col2,
-+ QStringList() << QLatin1String("text/plain"));
-+ Collection col5 = createCollection(res, QLatin1String("Col 5"), Collection(),
-+ QStringList() << QLatin1String("inode/directory")
-+ << QLatin1String("text/plain"));
-+ Collection col6 = createCollection(res, QLatin1String("Col 6"), col5,
-+ QStringList() << QLatin1String("inode/directory")
-+ << QLatin1String("application/octet-stream"));
-+ Collection col7 = createCollection(res, QLatin1String("Col 7"), col5,
-+ QStringList() << QLatin1String("inode/directory")
-+ << QLatin1String("text/plain"));
-+ Collection col8 = createCollection(res, QLatin1String("Col 8"), col7,
-+ QStringList() << QLatin1String("text/directory")
-+ << QLatin1String("application/octet-stream"));
-+ Collection col9 = createCollection(res, QLatin1String("Col 9"), col8,
-+ QStringList() << QLatin1String("unique/mime-type"));
-+
-+ QTest::addColumn<QVector<qint64>>("ancestors");
-+ QTest::addColumn<QStringList>("mimetypes");
-+ QTest::addColumn<QVector<qint64>>("expectedResults");
-+
-+ QTest::newRow("") << QVector<qint64>({ 0 })
-+ << QStringList({ QLatin1String("text/plain") })
-+ << QVector<qint64>({ col4.id(), col5.id(), col7.id() });
-+ QTest::newRow("") << QVector<qint64>({ 0 })
-+ << QStringList({ QLatin1String("application/octet-stream") })
-+ << QVector<qint64>({ col2.id(), col3.id(), col6.id(), col8.id() });
-+ QTest::newRow("") << QVector<qint64>({ col1.id() })
-+ << QStringList({ QLatin1String("text/plain") })
-+ << QVector<qint64>({ col4.id() });
-+ QTest::newRow("") << QVector<qint64>({ col1.id() })
-+ << QStringList({ QLatin1String("unique/mime-type") })
-+ << QVector<qint64>();
-+ QTest::newRow("") << QVector<qint64>({ col2.id(), col7.id() })
-+ << QStringList({ QLatin1String("application/octet-stream") })
-+ << QVector<qint64>({ col3.id(), col8.id() });
-+ }
-+
-+ void testSearchHelperCollectionListing()
-+ {
-+ QFETCH(QVector<qint64>, ancestors);
-+ QFETCH(QStringList, mimetypes);
-+ QFETCH(QVector<qint64>, expectedResults);
-+
-+ QVector<qint64> results = SearchHelper::matchSubcollectionsByMimeType(ancestors, mimetypes);
-+
-+ qSort(expectedResults);
-+ qSort(results);
-+
-+ QCOMPARE(results.size(), expectedResults.size());
-+ QCOMPARE(results, expectedResults);
-+ }
-+
-+};
-+
-+AKTEST_FAKESERVER_MAIN(SearchTest)
-+
-+#include "searchtest.moc"
---
-2.1.4
-
--
Akonadi packaging
More information about the pkg-kde-commits
mailing list