[meego-commits] 24017: Changes to devel:contentfw/libqtsparql

Marko Saukko no_reply at build.meego.com
Tue Sep 20 08:01:24 UTC 2011


Hi,
I have made the following changes to libqtsparql in project devel:contentfw. Please review and accept ASAP.

Thank You,
Marko Saukko

[This message was auto-generated]

---

Request #24017:

  submit:   home:marko.saukko:branches:devel:contentfw/libqtsparql(r6)(cleanup) -> devel:contentfw/libqtsparql


Message:
    * Tue Sep 20 2011 Marko Saukko <marko.saukko at cybercom.com> - 0.2.1
- Moved tracker dependency to tracker related packages.
- Updated to latest released version.
- BMC#22527 Fix compile with qt 4.8

State:   new          2011-09-20T00:50:35 marko.saukko
Comment: None



changes files:
--------------
--- libqtsparql.changes
+++ libqtsparql.changes
@@ -0,0 +1,5 @@
+* Tue Sep 20 2011 Marko Saukko <marko.saukko at cybercom.com> - 0.2.1
+- Moved tracker dependency to tracker related packages.
+- Updated to latest released version.
+- BMC#22527 Fix compile with qt 4.8
+

old:
----
  libqtsparql-0.0.28.tar.gz

new:
----
  compile-fix-with-qt-4.8.patch
  libqtsparql-0.2.1.tar.gz

spec files:
-----------
--- libqtsparql.spec
+++ libqtsparql.spec
@@ -1,5 +1,5 @@
 Name: libqtsparql
-Version: 0.0.28
+Version: 0.2.1
 Release: 1
 Summary: Library for accessing RDF stores
 Group:   System/Libraries
@@ -7,10 +7,10 @@
 URL:     http://maemo.gitorious.org/maemo-af/qsparql
 Source0: %{name}-%{version}.tar.gz
 Patch0: 0001-Fix-for-tests-xml.patch
+Patch1: compile-fix-with-qt-4.8.patch
 BuildRequires: doxygen
 BuildRequires: pkgconfig(QtCore)
 BuildRequires: tracker-devel
-Requires: tracker >= 0.10.0
 
 %description
 Library for accessing RDF stores.
@@ -28,7 +28,7 @@
 Summary:  QtSparql testsuite 
 Group:    System/X11
 Requires:  %{name} >= %{version}
-Requires: libqtsparql-tracker 
+Requires: libqtsparql-tracker >= %{version}
 Requires: libqtsparql-tracker-direct >= %{version} 
 
 %description tests
@@ -44,6 +44,7 @@
 %package tracker 
 Summary:  Tracker driver package for %{name}
 Group:    Libraries
+Requires: tracker >= 0.10.0
 
 %description tracker
 Tracker driver for QtSparql.
@@ -51,6 +52,7 @@
 %package tracker-direct
 Summary:  Tracker driver package for %{name}
 Group:    Libraries
+Requires: tracker >= 0.10.0
 
 %description tracker-direct
 Tracker direct access driver for QtSparql.
@@ -59,6 +61,7 @@
 %setup -q -n %{name}-%{version}
 
 %patch0 -p1
+%patch1 -p1
 
 %build
 ./configure -prefix /usr
@@ -91,6 +94,8 @@
 %{_libdir}/libQtSparql.so
 %{_libdir}/pkgconfig/*
 %{_libdir}/qt4/imports/QtSparql/libsparqlresultslist.so
+%{_libdir}/qt4/imports/QtSparql/libsparqlconnection.so
+%{_libdir}/qt4/imports/QtSparql/libsparqllistmodel.so
 %{_includedir}/QtSparql/*
 %{_libdir}/libQtSparql.prl
 %{_datadir}/qt4/mkspecs/features/*

other changes:
--------------

++++++ 0001-Fix-for-tests-xml.patch
--- 0001-Fix-for-tests-xml.patch
+++ 0001-Fix-for-tests-xml.patch
@@ -1,16 +1,25 @@
-diff -Naur ../libqtsparql-0.0.28/tests/auto/tests.xml libqtsparql-0.0.28/tests/auto/tests.xml
---- ../libqtsparql-0.0.28/tests/auto/tests.xml	2011-06-01 17:11:14.000000000 +0300
-+++ libqtsparql-0.0.28/tests/auto/tests.xml	2011-06-06 17:07:20.586296659 +0300
+diff -ruN libqtsparql-0.2.1.orig/tests/auto/tests.xml libqtsparql-0.2.1/tests/auto/tests.xml
+--- libqtsparql-0.2.1.orig/tests/auto/tests.xml	2011-09-20 08:48:14.347259690 +0300
++++ libqtsparql-0.2.1/tests/auto/tests.xml	2011-09-20 08:51:58.580030578 +0300
 @@ -30,7 +30,7 @@
+     <set name="qsparql-api" description="Tests for qsparql API">
+       <case name="tst_qsparql_api" description="Executing tst_qsparql_api">
+         <step>
+-            su - user -c "/usr/lib/libqtsparql-tests/tst_qsparql_api"
++            /usr/lib/libqtsparql-tests/tst_qsparql_api
+         </step>
+       </case>
+       <environments>
+@@ -41,7 +41,7 @@
      <set name="qsparql-tracker" description="Tests for tracker plugin of qsparql">
        <case name="tst_qsparql_tracker" description="Executing tst_qsparql_tracker">
-         <step expected_result="0">
+         <step>
 -            su - user -c "/usr/lib/libqtsparql-tests/tst_qsparql_tracker"
 +            /usr/lib/libqtsparql-tests/tst_qsparql_tracker
          </step>
        </case>
        <environments>
-@@ -38,13 +38,13 @@
+@@ -49,13 +49,13 @@
          <hardware>true</hardware>
        </environments>
        <get>
@@ -20,13 +29,13 @@
      </set>
      <set name="qsparql-tracker-direct" description="Tests for tracker direct access plugin of qsparql">
        <case name="tst_qsparql_tracker_direct" description="Executing tst_qsparql_tracker_direct" timeout="900">
-         <step expected_result="0">
+         <step>
 -            su - user -c "/usr/lib/libqtsparql-tests/tst_qsparql_tracker_direct"
 +            /usr/lib/libqtsparql-tests/tst_qsparql_tracker_direct
          </step>
        </case>
        <environments>
-@@ -52,30 +52,30 @@
+@@ -63,13 +63,13 @@
          <hardware>true</hardware>
        </environments>
        <get>
@@ -36,34 +45,13 @@
      </set>
      <set name="qsparql-threading" description="Multithreading tests">
          <case name="test-tracker-queries" description="Tracker queries">
-             <step expected_result="0">
+             <step>
 -                su - user -c "/usr/lib/libqtsparql-tests/tst_qsparql_threading concurrentTrackerQueries"
 +                /usr/lib/libqtsparql-tests/tst_qsparql_threading concurrentTrackerQueries
              </step>
          </case>
-         <case name="test-tracker-direct-queries" description="Tracker direct queries">
-             <step expected_result="0">
--                su - user -c "/usr/lib/libqtsparql-tests/tst_qsparql_threading concurrentTrackerDirectQueries"
-+                /usr/lib/libqtsparql-tests/tst_qsparql_threading concurrentTrackerDirectQueries
-             </step>
-         </case>
-         <case name="test-tracker-direct-inserts" description="Tracker direct inserts" insignificant="true">
-             <!-- this is marked as insigficant since it fails sporadically; this needs debugging! -->
-             <step expected_result="0">
--                su - user -c "/usr/lib/libqtsparql-tests/tst_qsparql_threading concurrentTrackerDirectInserts ||
--                ( i=$? && tracker-sparql -u -f /usr/share/libqtsparql-tests/clean_data_threading.rq && exit $i )"
-+                /usr/lib/libqtsparql-tests/tst_qsparql_threading concurrentTrackerDirectInserts ||
-+                ( i=$? && tracker-sparql -u -f /usr/share/libqtsparql-tests/clean_data_threading.rq && exit $i )
-             </step>
-         </case>
-         <post_steps>
-             <step expected_result="0">
--                su - user -c "tracker-sparql -u -f /usr/share/libqtsparql-tests/clean_data_threading.rq"
-+                su - meego -c "tracker-sparql -u -f /usr/share/libqtsparql-tests/clean_data_threading.rq"
-             </step>
-         </post_steps>
          <environments>
-@@ -83,13 +83,13 @@
+@@ -77,13 +77,13 @@
              <hardware>true</hardware>
          </environments>
          <get>
@@ -73,13 +61,13 @@
      </set>
      <set name="qsparql-tracker-direct-sync" description="Tests for tracker direct access plugin of qsparql, sync mode">
          <case name="tst_qsparql_tracker_direct_sync" description="Executing tst_qsparql_tracker_direct_sync">
-             <step expected_result="0">
+             <step>
 -                su - user -c "/usr/lib/libqtsparql-tests/tst_qsparql_tracker_direct_sync"
 +                /usr/lib/libqtsparql-tests/tst_qsparql_tracker_direct_sync
              </step>
          </case>
          <environments>
-@@ -97,7 +97,7 @@
+@@ -91,21 +91,21 @@
              <hardware>true</hardware>
          </environments>
          <get>
@@ -88,3 +76,19 @@
          </get>
      </set>
      <set name="qsparql-tracker-direct-crashes" description="Regression tests">
+       <case name="tst_qsparql_tracker_direct_crashes" description="Regression test">
+         <step>
+             <!-- Note: the env vars should ensure that the direct connection opening fails -->
+-            su - user -c "XDG_CACHE_HOME=bogus TRACKER_SPARQL_BACKEND=direct /usr/lib/libqtsparql-tests/tst_qsparql_tracker_direct_crashes"
++            XDG_CACHE_HOME=bogus TRACKER_SPARQL_BACKEND=direct /usr/lib/libqtsparql-tests/tst_qsparql_tracker_direct_crashes
+         </step>
+       </case>
+     </set>
+     <set name="qsparql-qmlbindings" description="Tests for qsparql QML bindings">
+       <case name="tst_qsparql_qmlbindings" description="Executing tst_qsparql_qmlbindings">
+         <step>
+-            su - user -c "/usr/lib/libqtsparql-tests/tst_qsparql_qmlbindings"
++            /usr/lib/libqtsparql-tests/tst_qsparql_qmlbindings
+         </step>
+       </case>
+       <environments>

++++++ compile-fix-with-qt-4.8.patch (new)
--- compile-fix-with-qt-4.8.patch
+++ compile-fix-with-qt-4.8.patch
+--- ../libqtsparql-0.0.28/src/sparql/kernel/qsparql.h	2011-05-27 11:37:20.000000000 +0300
++++ libqtsparql-0.0.28/src/sparql/kernel/qsparql.h	2011-09-06 17:28:15.687013002 +0300
+@@ -55,7 +55,7 @@
+ 
+ #if !WE_ARE_QT
+ #    undef QT_MODULE // hack; remove this when we go back to Qt repo
+-#    define QT_MODULE(x) ;
++#    define QT_MODULE(x)
+ #endif
+ 
+ QT_MODULE(Sparql)

++++++ libqtsparql-0.0.28.tar.gz -> libqtsparql-0.2.1.tar.gz
--- .git
+++ .git
-(directory)
--- .git/HEAD
+++ .git/HEAD
-ref: refs/heads/test
--- .git/branches
+++ .git/branches
-(directory)
--- .git/config
+++ .git/config
-[core]
-	repositoryformatversion = 0
-	filemode = true
-	bare = false
-	logallrefupdates = true
-[remote "origin"]
-	fetch = +refs/heads/*:refs/remotes/origin/*
-	url = git at gitorious.org:maemo-af/qsparql.git
-[branch "master"]
-	remote = origin
-	merge = refs/heads/master
--- .git/description
+++ .git/description
-Unnamed repository; edit this file 'description' to name the repository.
--- .git/hooks
+++ .git/hooks
-(directory)
--- .git/hooks/applypatch-msg.sample
+++ .git/hooks/applypatch-msg.sample
-#!/bin/sh
-#
-# An example hook script to check the commit log message taken by
-# applypatch from an e-mail message.
-#
-# The hook should exit with non-zero status after issuing an
-# appropriate message if it wants to stop the commit.  The hook is
-# allowed to edit the commit message file.
-#
-# To enable this hook, rename this file to "applypatch-msg".
-
-. git-sh-setup
-test -x "$GIT_DIR/hooks/commit-msg" &&
-	exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"}
-:
--- .git/hooks/commit-msg.sample
+++ .git/hooks/commit-msg.sample
-#!/bin/sh
-#
-# An example hook script to check the commit log message.
-# Called by "git commit" with one argument, the name of the file
-# that has the commit message.  The hook should exit with non-zero
-# status after issuing an appropriate message if it wants to stop the
-# commit.  The hook is allowed to edit the commit message file.
-#
-# To enable this hook, rename this file to "commit-msg".
-
-# Uncomment the below to add a Signed-off-by line to the message.
-# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
-# hook is more suited to it.
-#
-# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
-# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
-
-# This example catches duplicate Signed-off-by lines.
-
-test "" = "$(grep '^Signed-off-by: ' "$1" |
-	 sort | uniq -c | sed -e '/^[ 	]*1[ 	]/d')" || {
-	echo >&2 Duplicate Signed-off-by lines.
-	exit 1
-}
--- .git/hooks/post-commit.sample
+++ .git/hooks/post-commit.sample
-#!/bin/sh
-#
-# An example hook script that is called after a successful
-# commit is made.
-#
-# To enable this hook, rename this file to "post-commit".
-
-: Nothing
--- .git/hooks/post-receive.sample
+++ .git/hooks/post-receive.sample
-#!/bin/sh
-#
-# An example hook script for the "post-receive" event.
-#
-# The "post-receive" script is run after receive-pack has accepted a pack
-# and the repository has been updated.  It is passed arguments in through
-# stdin in the form
-#  <oldrev> <newrev> <refname>
-# For example:
-#  aa453216d1b3e49e7f6f98441fa56946ddcd6a20 68f7abf4e6f922807889f52bc043ecd31b79f814 refs/heads/master
-#
-# see contrib/hooks/ for a sample, or uncomment the next line and
-# rename the file to "post-receive".
-
-#. /usr/share/doc/git-core/contrib/hooks/post-receive-email
--- .git/hooks/post-update.sample
+++ .git/hooks/post-update.sample
-#!/bin/sh
-#
-# An example hook script to prepare a packed repository for use over
-# dumb transports.
-#
-# To enable this hook, rename this file to "post-update".
-
-exec git update-server-info
--- .git/hooks/pre-applypatch.sample
+++ .git/hooks/pre-applypatch.sample
-#!/bin/sh
-#
-# An example hook script to verify what is about to be committed
-# by applypatch from an e-mail message.
-#
-# The hook should exit with non-zero status after issuing an
-# appropriate message if it wants to stop the commit.
-#
-# To enable this hook, rename this file to "pre-applypatch".
-
-. git-sh-setup
-test -x "$GIT_DIR/hooks/pre-commit" &&
-	exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"}
-:
--- .git/hooks/pre-commit.sample
+++ .git/hooks/pre-commit.sample
-#!/bin/sh
-#
-# An example hook script to verify what is about to be committed.
-# Called by "git commit" with no arguments.  The hook should
-# exit with non-zero status after issuing an appropriate message if
-# it wants to stop the commit.
-#
-# To enable this hook, rename this file to "pre-commit".
-
-if git rev-parse --verify HEAD >/dev/null 2>&1
-then
-	against=HEAD
-else
-	# Initial commit: diff against an empty tree object
-	against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
-fi
-
-# If you want to allow non-ascii filenames set this variable to true.
-allownonascii=$(git config hooks.allownonascii)
-
-# Cross platform projects tend to avoid non-ascii filenames; prevent
-# them from being added to the repository. We exploit the fact that the
-# printable range starts at the space character and ends with tilde.
-if [ "$allownonascii" != "true" ] &&
-	# Note that the use of brackets around a tr range is ok here, (it's
-	# even required, for portability to Solaris 10's /usr/bin/tr), since
-	# the square bracket bytes happen to fall in the designated range.
-	test "$(git diff --cached --name-only --diff-filter=A -z $against |
-	  LC_ALL=C tr -d '[ -~]\0')"
-then
-	echo "Error: Attempt to add a non-ascii file name."
-	echo
-	echo "This can cause problems if you want to work"
-	echo "with people on other platforms."
-	echo
-	echo "To be portable it is advisable to rename the file ..."
-	echo
-	echo "If you know what you are doing you can disable this"
-	echo "check using:"
-	echo
-	echo "  git config hooks.allownonascii true"
-	echo
-	exit 1
-fi
-
-exec git diff-index --check --cached $against --
--- .git/hooks/pre-rebase.sample
+++ .git/hooks/pre-rebase.sample
-#!/bin/sh
-#
-# Copyright (c) 2006, 2008 Junio C Hamano
-#
-# The "pre-rebase" hook is run just before "git rebase" starts doing
-# its job, and can prevent the command from running by exiting with
-# non-zero status.
-#
-# The hook is called with the following parameters:
-#
-# $1 -- the upstream the series was forked from.
-# $2 -- the branch being rebased (or empty when rebasing the current branch).
-#
-# This sample shows how to prevent topic branches that are already
-# merged to 'next' branch from getting rebased, because allowing it
-# would result in rebasing already published history.
-
-publish=next
-basebranch="$1"
-if test "$#" = 2
-then
-	topic="refs/heads/$2"
-else
-	topic=`git symbolic-ref HEAD` ||
-	exit 0 ;# we do not interrupt rebasing detached HEAD
-fi
-
-case "$topic" in
-refs/heads/??/*)
-	;;
-*)
-	exit 0 ;# we do not interrupt others.
-	;;
-esac
-
-# Now we are dealing with a topic branch being rebased
-# on top of master.  Is it OK to rebase it?
-
-# Does the topic really exist?
-git show-ref -q "$topic" || {
-	echo >&2 "No such branch $topic"
-	exit 1
-}
-
-# Is topic fully merged to master?
-not_in_master=`git rev-list --pretty=oneline ^master "$topic"`
-if test -z "$not_in_master"
-then
-	echo >&2 "$topic is fully merged to master; better remove it."
-	exit 1 ;# we could allow it, but there is no point.
-fi
-
-# Is topic ever merged to next?  If so you should not be rebasing it.
-only_next_1=`git rev-list ^master "^$topic" ${publish} | sort`
-only_next_2=`git rev-list ^master           ${publish} | sort`
-if test "$only_next_1" = "$only_next_2"
-then
-	not_in_topic=`git rev-list "^$topic" master`
-	if test -z "$not_in_topic"
-	then
-		echo >&2 "$topic is already up-to-date with master"
-		exit 1 ;# we could allow it, but there is no point.
-	else
-		exit 0
-	fi
-else
-	not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"`
-	/usr/bin/perl -e '
-		my $topic = $ARGV[0];
-		my $msg = "* $topic has commits already merged to public branch:\n";
-		my (%not_in_next) = map {
-			/^([0-9a-f]+) /;
-			($1 => 1);
-		} split(/\n/, $ARGV[1]);
-		for my $elem (map {
-				/^([0-9a-f]+) (.*)$/;
-				[$1 => $2];
-			} split(/\n/, $ARGV[2])) {
-			if (!exists $not_in_next{$elem->[0]}) {
-				if ($msg) {
-					print STDERR $msg;
-					undef $msg;
-				}
-				print STDERR " $elem->[1]\n";
-			}
-		}
-	' "$topic" "$not_in_next" "$not_in_master"
-	exit 1
-fi
-
-exit 0
-
-<<\DOC_END
-################################################################
-
-This sample hook safeguards topic branches that have been
-published from being rewound.
-
-The workflow assumed here is:
-
- * Once a topic branch forks from "master", "master" is never
-   merged into it again (either directly or indirectly).
-
- * Once a topic branch is fully cooked and merged into "master",
-   it is deleted.  If you need to build on top of it to correct
-   earlier mistakes, a new topic branch is created by forking at
-   the tip of the "master".  This is not strictly necessary, but
-   it makes it easier to keep your history simple.
-
- * Whenever you need to test or publish your changes to topic
-   branches, merge them into "next" branch.
-
-The script, being an example, hardcodes the publish branch name
-to be "next", but it is trivial to make it configurable via
-$GIT_DIR/config mechanism.
-
-With this workflow, you would want to know:
-
-(1) ... if a topic branch has ever been merged to "next".  Young
-    topic branches can have stupid mistakes you would rather
-    clean up before publishing, and things that have not been
-    merged into other branches can be easily rebased without
-    affecting other people.  But once it is published, you would
-    not want to rewind it.
-
-(2) ... if a topic branch has been fully merged to "master".
-    Then you can delete it.  More importantly, you should not
-    build on top of it -- other people may already want to
-    change things related to the topic as patches against your
-    "master", so if you need further changes, it is better to
-    fork the topic (perhaps with the same name) afresh from the
-    tip of "master".
-
-Let's look at this example:
-
-		   o---o---o---o---o---o---o---o---o---o "next"
-		  /       /           /           /
-		 /   a---a---b A     /           /
-		/   /               /           /
-	       /   /   c---c---c---c B         /
-	      /   /   /             \         /
-	     /   /   /   b---b C     \       /
-	    /   /   /   /             \     /
-    ---o---o---o---o---o---o---o---o---o---o---o "master"
-
-
-A, B and C are topic branches.
-
- * A has one fix since it was merged up to "next".
-
- * B has finished.  It has been fully merged up to "master" and "next",
-   and is ready to be deleted.
-
- * C has not merged to "next" at all.
-
-We would want to allow C to be rebased, refuse A, and encourage
-B to be deleted.
-
-To compute (1):
-
-	git rev-list ^master ^topic next
-	git rev-list ^master        next
-
-	if these match, topic has not merged in next at all.
-
-To compute (2):
-
-	git rev-list master..topic
-
-	if this is empty, it is fully merged to "master".
-
-DOC_END
--- .git/hooks/prepare-commit-msg.sample
+++ .git/hooks/prepare-commit-msg.sample
-#!/bin/sh
-#
-# An example hook script to prepare the commit log message.
-# Called by "git commit" with the name of the file that has the
-# commit message, followed by the description of the commit
-# message's source.  The hook's purpose is to edit the commit
-# message file.  If the hook fails with a non-zero status,
-# the commit is aborted.
-#
-# To enable this hook, rename this file to "prepare-commit-msg".
-
-# This hook includes three examples.  The first comments out the
-# "Conflicts:" part of a merge commit.
-#
-# The second includes the output of "git diff --name-status -r"
-# into the message, just before the "git status" output.  It is
-# commented because it doesn't cope with --amend or with squashed
-# commits.
-#
-# The third example adds a Signed-off-by line to the message, that can
-# still be edited.  This is rarely a good idea.
-
-case "$2,$3" in
-  merge,)
-    /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;;
-
-# ,|template,)
-#   /usr/bin/perl -i.bak -pe '
-#      print "\n" . `git diff --cached --name-status -r`
-#	 if /^#/ && $first++ == 0' "$1" ;;
-
-  *) ;;
-esac
-
-# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
-# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
--- .git/hooks/update.sample
+++ .git/hooks/update.sample
-#!/bin/sh
-#
-# An example hook script to blocks unannotated tags from entering.
-# Called by "git receive-pack" with arguments: refname sha1-old sha1-new
-#
-# To enable this hook, rename this file to "update".
-#
-# Config
-# ------
-# hooks.allowunannotated
-#   This boolean sets whether unannotated tags will be allowed into the
-#   repository.  By default they won't be.
-# hooks.allowdeletetag
-#   This boolean sets whether deleting tags will be allowed in the
-#   repository.  By default they won't be.
-# hooks.allowmodifytag
-#   This boolean sets whether a tag may be modified after creation. By default
-#   it won't be.
-# hooks.allowdeletebranch
-#   This boolean sets whether deleting branches will be allowed in the
-#   repository.  By default they won't be.
-# hooks.denycreatebranch
-#   This boolean sets whether remotely creating branches will be denied
-#   in the repository.  By default this is allowed.
-#
-
-# --- Command line
-refname="$1"
-oldrev="$2"
-newrev="$3"
-
-# --- Safety check
-if [ -z "$GIT_DIR" ]; then
-	echo "Don't run this script from the command line." >&2
-	echo " (if you want, you could supply GIT_DIR then run" >&2
-	echo "  $0 <ref> <oldrev> <newrev>)" >&2
-	exit 1
-fi
-
-if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
-	echo "Usage: $0 <ref> <oldrev> <newrev>" >&2
-	exit 1
-fi
-
-# --- Config
-allowunannotated=$(git config --bool hooks.allowunannotated)
-allowdeletebranch=$(git config --bool hooks.allowdeletebranch)
-denycreatebranch=$(git config --bool hooks.denycreatebranch)
-allowdeletetag=$(git config --bool hooks.allowdeletetag)
-allowmodifytag=$(git config --bool hooks.allowmodifytag)
-
-# check for no description
-projectdesc=$(sed -e '1q' "$GIT_DIR/description")
-case "$projectdesc" in
-"Unnamed repository"* | "")
-	echo "*** Project description file hasn't been set" >&2
-	exit 1
-	;;
-esac
-
-# --- Check types
-# if $newrev is 0000...0000, it's a commit to delete a ref.
-zero="0000000000000000000000000000000000000000"
-if [ "$newrev" = "$zero" ]; then
-	newrev_type=delete
-else
-	newrev_type=$(git cat-file -t $newrev)
-fi
-
-case "$refname","$newrev_type" in
-	refs/tags/*,commit)
-		# un-annotated tag
-		short_refname=${refname##refs/tags/}
-		if [ "$allowunannotated" != "true" ]; then
-			echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
-			echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
-			exit 1
-		fi
-		;;
-	refs/tags/*,delete)
-		# delete tag
-		if [ "$allowdeletetag" != "true" ]; then
-			echo "*** Deleting a tag is not allowed in this repository" >&2
-			exit 1
-		fi
-		;;
-	refs/tags/*,tag)
-		# annotated tag
-		if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
-		then
-			echo "*** Tag '$refname' already exists." >&2
-			echo "*** Modifying a tag is not allowed in this repository." >&2
-			exit 1
-		fi
-		;;
-	refs/heads/*,commit)
-		# branch
-		if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
-			echo "*** Creating a branch is not allowed in this repository" >&2
-			exit 1
-		fi
-		;;
-	refs/heads/*,delete)
-		# delete branch
-		if [ "$allowdeletebranch" != "true" ]; then
-			echo "*** Deleting a branch is not allowed in this repository" >&2
-			exit 1
-		fi
-		;;
-	refs/remotes/*,commit)
-		# tracking branch
-		;;
-	refs/remotes/*,delete)
-		# delete tracking branch
-		if [ "$allowdeletebranch" != "true" ]; then
-			echo "*** Deleting a tracking branch is not allowed in this repository" >&2
-			exit 1
-		fi
-		;;
-	*)
-		# Anything else (is there anything else?)
-		echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
-		exit 1
-		;;
-esac
-
-# --- Finished
-exit 0
--- .git/info
+++ .git/info
-(directory)
--- .git/info/exclude
+++ .git/info/exclude
-# git ls-files --others --exclude-from=.git/info/exclude
-# Lines that start with '#' are comments.
-# For a project mostly in C, the following would be a good set of
-# exclude patterns (uncomment them if you want to use them):
-# *.[oa]
-# *~
--- .git/logs
+++ .git/logs
-(directory)
--- .git/logs/HEAD
+++ .git/logs/HEAD
-0000000000000000000000000000000000000000 f66d94e6491351867cbd0e8dfcddc3473ea2c8a4 maimishr <ext-maitrey.mishra at nokia.com> 1306937474 +0300	clone: from git at gitorious.org:maemo-af/qsparql.git
-f66d94e6491351867cbd0e8dfcddc3473ea2c8a4 0c046594780e15cb523e98d84dd62c54f98129dc maimishr <ext-maitrey.mishra at nokia.com> 1306937495 +0300	checkout: moving from master to test
--- .git/logs/refs
+++ .git/logs/refs
-(directory)
--- .git/logs/refs/heads
+++ .git/logs/refs/heads
-(directory)
--- .git/logs/refs/heads/master
+++ .git/logs/refs/heads/master
-0000000000000000000000000000000000000000 f66d94e6491351867cbd0e8dfcddc3473ea2c8a4 maimishr <ext-maitrey.mishra at nokia.com> 1306937474 +0300	clone: from git at gitorious.org:maemo-af/qsparql.git
--- .git/logs/refs/heads/test
+++ .git/logs/refs/heads/test
-0000000000000000000000000000000000000000 0c046594780e15cb523e98d84dd62c54f98129dc maimishr <ext-maitrey.mishra at nokia.com> 1306937495 +0300	branch: Created from 0.0.28
--- .git/objects
+++ .git/objects
-(directory)
--- .git/objects/info
+++ .git/objects/info
-(directory)
--- .git/objects/pack
+++ .git/objects/pack
-(directory)
--- .git/packed-refs
+++ .git/packed-refs
-# pack-refs with: peeled 
-a764eb3038e259fded007ec47758fc0f3614bb3f refs/tags/sync_0.0.19
-ac6b1053e82ac546f1208f2588f1f7e73c0d414d refs/tags/sync_0.0.17
-cb80ca4e88ba9613ff71e52bc15066ff95e0e92b refs/tags/dummy0.0.17
-af3844d4fbe0c51c30cee603ea269896e996e68f refs/tags/0.0.9
-444daac7a778a33afd09a9b99d0c370a9d1c198e refs/tags/0.0.8_sync
-2a8f000fa74e6f2dcfd1a71cfc7a95b6a3f4379f refs/tags/0.0.7
-75bba358253d29c90642207ca51a02543a880633 refs/tags/0.0.6
-9bfffa84282f19730c3cc9be4362b8081d2a69ef refs/tags/0.0.5
-e19664823534045f91e5136d170173a219437208 refs/tags/0.0.4
-a2e6e30d0e4ee4be7808594131d1c5a8557a0711 refs/tags/0.0.3
-0c046594780e15cb523e98d84dd62c54f98129dc refs/tags/0.0.28
-8a5ed2a740e2ec825adf124c798bc7194aa45f7e refs/tags/0.0.27
-6c84a9f92b57615306811a2e6767f7e65687353e refs/tags/0.0.26
-0555517d469cbef24cbcb4e17b2fb009c9f333ae refs/tags/0.0.25
-7411f8765cb6ca17674e1acb6954587ff7bd9a68 refs/tags/0.0.24
-0821eb3d937fc7528f55a86d0d6536b522dd0eac refs/tags/0.0.23
-6660255fee074f56d8bc40596d825c21ba73c056 refs/tags/0.0.22
-53e99793971da201c16513081c984eaf5ed8578e refs/tags/0.0.21
-840af0877e1ae3d7f5327de9d0d20c248f2af47a refs/tags/0.0.20
-953538f1726438548b20c0d11e06dbbd51c2a5a4 refs/tags/0.0.2
-4c8ef96048385b2dccf821e08faeda0104039f46 refs/tags/0.0.18
-9a09116eaf7925f22a9128694b9c19eace2ca6ec refs/tags/0.0.16
-f9289ff0494cb0af38f0c8cb310e8bf297e08830 refs/tags/0.0.15
-2a749e0284d8128142b34823717aed58c309cf9c refs/tags/0.0.14
-4040a2be30b6fdc3b8dca4b4b2f031e923c8a4de refs/tags/0.0.13
-aec88772ed6ea3e13bf2f5f4235fa48c264828dc refs/tags/0.0.12
-a898b232c0d14a16b355d5fc9651fd09a21bb175 refs/tags/0.0.11
-6008a342ee4b6bdecf583860a8734c09ce78776f refs/tags/0.0.10
-aecd2e710bb73cd833c6f42f3d0bc1222a234a35 refs/tags/0.0.1
-b611c558b6ad8ca33734821610e504e7d7b2c029 refs/remotes/origin/virtuoso_fixes
-7c9d9e4ece945bc79cecd292533b7623a2845d92 refs/remotes/origin/tracker_direct_forward_only1
-b058a9f1e4ac6264bdfe044dbcaf32cb12d396b4 refs/remotes/origin/tracker_direct_forward_only
-11e57a8f7b824a4d9d879457c6a66563efcaf25e refs/remotes/origin/tracker_direct_benchmarking
-09668961940723643f93207697933f2e88d16cbd refs/remotes/origin/sync_async_experiment
-25fab59acdb30036c13168eff5915adc29818c8d refs/remotes/origin/qml_fix
-05a0696df26c677e887e29e6738a9ab5acb7bad4 refs/remotes/origin/q_func_info
-5436a7da86a4fce8100ff97ed4072ed293ce8c7a refs/remotes/origin/open_direct_connection_synchronously_in_syncExec
-f66d94e6491351867cbd0e8dfcddc3473ea2c8a4 refs/remotes/origin/master
-e07fc47d8fe05941846d6446cec99025090cd575 refs/remotes/origin/license_update
-233572880573792615ea8741a9e69615a7a24f95 refs/remotes/origin/improve_error_reporting_in_tracker_direct_tests
-b0167c5cfcb1e1701ab0e757bda380069f3636e7 refs/remotes/origin/fix_coverage_build
-1ed5f4d2843be86dfcc1959ced9298c184b6e01e refs/remotes/origin/doc_update
-f906a2898ed1b61e06207ec55ee09a8e27333c11 refs/remotes/origin/benchmark_update
-69499d647102d56aa68a004d3c820271658ecd45 refs/remotes/origin/attempt_to_test_low_priority_queries
-8794be40d20718c358b99b34a102fd8c21e59e7d refs/remotes/origin/api_test
-1b81ce49b02fae85fdcfb19c675bbfa10ad79954 refs/remotes/origin/add_torture_tests
-b90900df3d6612e9fee8feec4733cbbe90d1fe4a refs/remotes/origin/add_query_options
--- .git/refs
+++ .git/refs
-(directory)
--- .git/refs/heads
+++ .git/refs/heads
-(directory)
--- .git/refs/heads/master
+++ .git/refs/heads/master
-f66d94e6491351867cbd0e8dfcddc3473ea2c8a4
--- .git/refs/heads/test
+++ .git/refs/heads/test
-0c046594780e15cb523e98d84dd62c54f98129dc
--- .git/refs/remotes
+++ .git/refs/remotes
-(directory)
--- .git/refs/remotes/origin
+++ .git/refs/remotes/origin
-(directory)
--- .git/refs/remotes/origin/HEAD
+++ .git/refs/remotes/origin/HEAD
-ref: refs/remotes/origin/master
--- .git/refs/tags
+++ .git/refs/tags
-(directory)
--- .gitignore
+++ .gitignore
@@ -27,6 +27,7 @@
 dbpedia
 querymodel
 qmlquerymodel
+qmlbindings
 
 # tests
 tests/auto/qsparql/tst_qsparql
@@ -38,6 +39,7 @@
 tests/auto/qsparql_virtuoso_endpoint/tst_qsparql_virtuoso_endpoint
 tests/auto/qsparql_tracker_direct/tst_qsparql_tracker_direct
 tests/auto/qsparql_tracker_direct_sync/tst_qsparql_tracker_direct_sync
+tests/auto/qsparql_tracker_direct_concurrency/tst_qsparql_tracker_direct_concurrency
 tests/auto/qsparql_tracker_direct_crashes/tst_qsparql_tracker_direct_crashes
 tests/auto/qsparql_tracker_signals/tst_qsparql_tracker_signals
 tests/auto/qsparql_endpoint_threading/tst_qsparql_endpoint_threading
@@ -45,6 +47,8 @@
 tests/auto/qsparql_ntriples/tst_qsparql_ntriples
 tests/auto/qsparqlresultrow/tst_qsparqlresultrow
 tests/auto/qsparql_benchmark/tst_qsparql_benchmark
+tests/auto/qsparql_api/tst_qsparql_api
+tests/auto/qsparql_qmlbindings/tst_qsparql_qmlbindings
 
 # debian packaging
 debian/build-stamp
@@ -70,6 +74,8 @@
 debian/libqtsparql-virtuoso
 debian/libqtsparql-tracker-direct
 debian/libqtsparql-tracker-direct-dbg
+debian/stamp-patched
+.pc/*
 
 # configure-time tests
 config.tests/unix/odbc/odbc
--- config.tests/unix/iodbc/iodbc.cpp
+++ config.tests/unix/iodbc/iodbc.cpp
@@ -2,39 +2,37 @@
 **
 ** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
 ** All rights reserved.
-** Contact: Nokia Corporation (qt-info at nokia.com)
+** Contact: Nokia Corporation (ivan.frade at nokia.com)
 **
-** This file is part of the documentation of the Qt Toolkit.
+** This file is part of the QtSparql module (not yet part of the Qt Toolkit).
 **
 ** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
 ** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file.  Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 **
 ** In addition, as a special exception, Nokia gives you certain additional
-** rights.  These rights are described in the Nokia Qt LGPL Exception
+** rights. These rights are described in the Nokia Qt LGPL Exception
 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
 **
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info at nokia.com.
-**
-**
-**
-**
-**
-**
-**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
 **
+** If you have questions regarding the use of this file, please contact
+** Nokia at ivan.frade at nokia.com.
 ** $QT_END_LICENSE$
 **
 ****************************************************************************/
--- config.tests/unix/tracker-sparql/tracker-sparql.cpp
+++ config.tests/unix/tracker-sparql/tracker-sparql.cpp
@@ -2,39 +2,37 @@
 **
 ** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
 ** All rights reserved.
-** Contact: Nokia Corporation (qt-info at nokia.com)
+** Contact: Nokia Corporation (ivan.frade at nokia.com)
 **
-** This file is part of the config.tests of the Qt Toolkit.
+** This file is part of the QtSparql module (not yet part of the Qt Toolkit).
 **
 ** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
 ** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file.  Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 **
 ** In addition, as a special exception, Nokia gives you certain additional
-** rights.  These rights are described in the Nokia Qt LGPL Exception
+** rights. These rights are described in the Nokia Qt LGPL Exception
 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
 **
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info at nokia.com.
-**
-**
-**
-**
-**
-**
-**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
 **
+** If you have questions regarding the use of this file, please contact
+** Nokia at ivan.frade at nokia.com.
 ** $QT_END_LICENSE$
 **
 ****************************************************************************/
--- configure
+++ configure
@@ -3,39 +3,37 @@
 ##
 ## Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
 ## All rights reserved.
-## Contact: Nokia Corporation (qt-info at nokia.com)
+## Contact: Nokia Corporation (ivan.frade at nokia.com)
 ##
-## This file is the build configuration utility of the Qt Toolkit.
+## This file is part of the QtSparql module (not yet part of the Qt Toolkit).
 ##
 ## $QT_BEGIN_LICENSE:LGPL$
-## No Commercial Usage
-## This file contains pre-release code and may not be distributed.
-## You may use this file in accordance with the terms and conditions
-## contained in the Technology Preview License Agreement accompanying
-## this package.
-##
 ## GNU Lesser General Public License Usage
-## Alternatively, this file may be used under the terms of the GNU Lesser
-## General Public License version 2.1 as published by the Free Software
-## Foundation and appearing in the file LICENSE.LGPL included in the
-## packaging of this file.  Please review the following information to
-## ensure the GNU Lesser General Public License version 2.1 requirements
-## will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+## This file may be used under the terms of the GNU Lesser General Public
+## License version 2.1 as published by the Free Software Foundation and
+## appearing in the file LICENSE.LGPL included in the packaging of this
+## file. Please review the following information to ensure the GNU Lesser
+## General Public License version 2.1 requirements will be met:
+## http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 ##
 ## In addition, as a special exception, Nokia gives you certain additional
-## rights.  These rights are described in the Nokia Qt LGPL Exception
+## rights. These rights are described in the Nokia Qt LGPL Exception
 ## version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
 ##
-## If you have questions regarding the use of this file, please contact
-## Nokia at qt-info at nokia.com.
-##
-##
-##
-##
-##
-##
-##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU General
+## Public License version 3.0 as published by the Free Software Foundation
+## and appearing in the file LICENSE.GPL included in the packaging of this
+## file. Please review the following information to ensure the GNU General
+## Public License version 3.0 requirements will be met:
+## http://www.gnu.org/copyleft/gpl.html.
+##
+## Other Usage
+## Alternatively, this file may be used in accordance with the terms and
+## conditions contained in a signed written agreement between you and Nokia.
 ##
+## If you have questions regarding the use of this file, please contact
+## Nokia at ivan.frade at nokia.com.
 ## $QT_END_LICENSE$
 ##
 #############################################################################
--- debian/changelog
+++ debian/changelog
@@ -1,3 +1,60 @@
+libqtsparql (0.2.1) unstable; urgency=low
+
+  * Fixes: NB#278959 - [TASK] Forward Only Tracker Direct Asynchronous Results
+  * Fixes: NB#276498 - [TASK] Add support for asynchronous result priority in tracker_direct driver
+
+ -- James Thomas <james.thomas at codethink.co.uk>  Thu, 8 Sep 2011 14:42:00 +0300
+
+libqtsparql (0.2.0) unstable; urgency=low
+
+  * Fixes: NB#275331 - [TASK] QML Bindings for QSparqlConnection and QSparqlQueryModel
+  * Fixes: NB#276497 - [TASK] Implement addPrefix() for all drivers
+  * Fixes: NB#269045 - QSparqlResult::isBool() returns always false for DBus driver
+  * Fixes: NB#269071 - Tracker direct async ask query result size is always zero
+  * Fixes: NB#269283 - Tracker direct async ask query result is accessible only through boolValue() AP
+  * Fixes: NB#274411 - qtsparql mainpage has one table with a hard-coded style
+  * Fixes: NB#268129 - libqtsparql mainpage has a placeholder \brief
+  * Test improvements in coverage and API test
+
+ -- Sami Rosendahl <ext-sami.1.rosendahl at nokia.com>  Tue, 30 Aug 2011 16:15:00 +0300
+
+libqtsparql (0.1.2) unstable; urgency=low
+
+  * Fixes: NB#280978 - QSparqlResult may run even after connection is deleted, resulting in a crash.
+  * Added a new concurrency stress test for the QTRACKER_DIRECT driver.
+
+ -- James Thomas <james.thomas at codethink.co.uk>  Tue, 6 Sep 2011 12:21:00 +0300
+
+libqtsparql (0.1.1) unstable; urgency=low
+
+  * Fixes: NB#268310 - [TASK] Implement QtSparql asynchronous API in tracker direct driver with synchronous tracker-sparql API
+  * Fixed a regression: QObject::sender() returned null in stead of the result object in finished() signal handler
+
+ -- Sami Rosendahl <ext-sami.1.rosendahl at nokia.com>  Thu, 4 Aug 2011 15:00:00 +0300
+
+libqtsparql (0.1.0) unstable; urgency=low
+
+  * Fixes: NB#268310 - [TASK] Implement QtSparql asynchronous API in tracker direct driver with synchronous tracker-sparql API
+  * Adds cross-driver API consistency tests
+
+ -- Sami Rosendahl <ext-sami.1.rosendahl at nokia.com>  Wed, 3 Aug 2011 16:25:00 +0300
+
+libqtsparql (0.0.30) unstable; urgency=low
+
+  * Fixes: NB#269688 - Endpoint driver related test cases are failing with undefined symbol error
+  * Updated QML Example
+  * Updated QSparqlQueryModel documentation
+
+ -- James Thomas <james.thomas at codethink.co.uk>  Tue, 5 Jul 2011 14:14:00 +0300
+
+libqtsparql (0.0.29) unstable; urgency=low
+
+  * Fixes: NB#264179 - Crash if QSparqlConnection is destroyed before a re-parented async update query finishes
+  * Fixes: NB#266153 - legal fix to a few source file headers
+  * Unifies QSparqlResult behavior and warning messages when a connection is deleted before result
+
+ -- Sami Rosendahl <ext-sami.1.rosendahl at nokia.com>  Fri, 17 Jun 2011 13:20:00 +0300
+
 libqtsparql (0.0.28) unstable; urgency=low
 
   * Fixes: NB#257702
--- debian/libqtsparql-tests.aegis
+++ debian/libqtsparql-tests.aegis
@@ -9,9 +9,12 @@
       <credential name="TrackerWriteAccess" />
       <credential name="GID::metadata-users" />
       <credential name="GRP::metadata-users" />
+      <for path="/usr/lib/libqtsparql-tests/tst_qsparql_api" />
       <for path="/usr/lib/libqtsparql-tests/tst_qsparql_tracker_direct" />
       <for path="/usr/lib/libqtsparql-tests/tst_qsparql_tracker_direct_sync" />
       <for path="/usr/lib/libqtsparql-tests/tst_qsparql_threading" />
       <for path="/usr/lib/libqtsparql-tests/tst_qsparql_benchmark" />
+      <for path="/usr/lib/libqtsparql-tests/tst_qsparql_qmlbindings" />
+      <for path="/usr/lib/libqtsparql-tests/tst_qsparql_tracker_direct_concurrency" />
    </request>
 </aegis>
--- debian/libqtsparql0.install
+++ debian/libqtsparql0.install
@@ -1,3 +1,5 @@
 usr/lib/libQtSparql.so.*
 /usr/lib/qt4/imports/QtSparql/qmldir
+/usr/lib/qt4/imports/QtSparql/libsparqllistmodel.so
+/usr/lib/qt4/imports/QtSparql/libsparqlconnection.so
 /usr/lib/qt4/imports/QtSparql/libsparqlresultslist.so
--- examples/sparql/asynctracker/main.cpp
+++ examples/sparql/asynctracker/main.cpp
@@ -97,9 +97,11 @@
                        "?pn a nco:PhoneNumber ; nco:phoneNumber ?p }");
     QSparqlResult* result = conn.exec(query);
     MyObject obj;
-    QObject::connect(result, SIGNAL(finished()), &obj, SLOT(onFinished()));
-    QObject::connect(result, SIGNAL(dataReady(int)),
+    if (!result->hasError()) {
+        QObject::connect(result, SIGNAL(finished()), &obj, SLOT(onFinished()));
+        QObject::connect(result, SIGNAL(dataReady(int)),
                      &obj, SLOT(onDataReady(int)));
+    }
 
     app.exec();
     qDebug() << "Exiting";
--- examples/sparql/qmlbindings
+++ examples/sparql/qmlbindings
+(directory)
--- examples/sparql/qmlbindings/main.cpp
+++ examples/sparql/qmlbindings/main.cpp
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (ivan.frade at nokia.com)
+**
+** This file is part of QtSparqlTracker library.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial Usage
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at ivan.frade at nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QApplication>
+#include <QtDeclarative>
+#include <QtSparql>
+#include <QtDBus>
+#include <QString>
+
+class ModelLiveChange : public QObject
+{
+    Q_OBJECT
+    QDeclarativeView *view;
+
+public :
+    ModelLiveChange(QDeclarativeView *view);
+    ~ModelLiveChange();
+
+public slots:
+    void changed(QString);
+};
+
+ModelLiveChange::ModelLiveChange(QDeclarativeView *view)
+    : view(view)
+{
+    // Monitor dbus for any notifications from Tracker.
+    // More information about Tracker over Dbus can be found at :
+    // http://live.gnome.org/Tracker/Documentation/SignalsOnChanges
+    // Please note: a more complete implementation, TrackerChangeNotifier,
+    // is available in libqtsparql-tracker-extensions
+    const QString service("org.freedesktop.Tracker1");
+    const QString basePath("/org/freedesktop/Tracker1");
+    const QString resourcesInterface("org.freedesktop.Tracker1.Resources");
+    const QString resourcesPath("/org/freedesktop/Tracker1/Resources");
+    const QString changedSignal("GraphUpdated");
+    const QString changedSignature("sa(iiii)a(iiii)");
+    const QString syncFunction("Sync");
+    // We'll need to use the long form of the class name to watch.
+    const QString className("http://www.semanticdesktop.org/ontologies/2007/03/22/nco#PersonContact");
+    QDBusConnection::sessionBus().connect(service, resourcesPath,
+                                          resourcesInterface, changedSignal,
+                                          QStringList() << className,
+                                          changedSignature,
+                                          this, SLOT(changed(QString)));
+}
+
+ModelLiveChange::~ModelLiveChange()
+{
+    // We don't need to delete anything here, cleanup of the objects
+    // will be dealt with on the QML side
+}
+
+void ModelLiveChange::changed(QString className)
+{
+    Q_UNUSED(className);
+    // We got a change notification from DBus on the class
+    // we are watching, so now call the "reload" function in the QML
+    // file.
+    QMetaObject::invokeMethod(view->rootObject(),
+                              "reload",
+                              Qt::DirectConnection);
+}
+
+int main(int argc, char *argv[])
+{
+    QApplication app(argc, argv);
+    QCoreApplication::addLibraryPath("../../../plugins");
+
+    // Initialise QML
+    QDeclarativeView viewQml;
+    // Load the QML plugins from the build tree, if
+    // they haven't been install
+    viewQml.engine()->addImportPath("../../../imports");
+
+    viewQml.setSource(QUrl::fromLocalFile("main.qml"));
+
+    // The bindings can be cast back to the appropriate QtSparql classes by setting
+    // an "objectName" property on them, and casting them, eg :
+    // QSparqlQueryModel *model =
+    //            qobject_cast<QSparqlQueryModel *>(viewQml.rootObject()->findChild<QObject*>("queryModel"));
+    // QSparqlConnection *connection =
+    //            qobject_cast<QSparqlConnection *>(viewQml.rootObject()->findChild<QObject*>("sparqlConnection"));
+    // However, we do not need to do that for this example
+
+    // Monitor dbus for changes, we will call a function in the QML file when we get them
+    ModelLiveChange changeNotifier(&viewQml);
+    viewQml.show();
+
+    return app.exec();
+}
+
+#include "main.moc"
+
+/*
+How to insert/delete example data into tracker:
+tracker-sparql -qu "insert { _:u a nco:PersonContact; nie:isLogicalPartOf <qml-example>; nco:nameGiven 'foo'; nco:nameFamily 'bar' .}"
+tracker-sparql -qu "delete { ?u a nco:PersonContact } WHERE { ?u a nco:PersonContact; nie:isLogicalPartOf <qml-example> }"
+*/
--- examples/sparql/qmlbindings/main.qml
+++ examples/sparql/qmlbindings/main.qml
+import Qt 4.7
+import QtSparql 1.0
+
+Rectangle {
+    id: mainRectangle
+    width: 800
+    height: 400
+
+    // this will force the ListView model
+    // to requery the data
+    function reload() {
+        queryModel.reload();
+    }
+
+    Rectangle {
+        id: contactsRect
+        width: parent.width
+        height : parent.height - 50
+        anchors.top: controlRect.bottom
+        ListView {
+            id: contactsView
+            width: parent.width
+            height: parent.height
+
+            // We'll use a results list model here
+            // By setting the "objectName" property we can use these models and connections
+            // in C++, see main.cpp for an example
+            model: SparqlListModel {
+                       id: "queryModel"
+                       objectName: "queryModel"
+                       // create a new SparqlConnection for the queryModel
+                       connection: SparqlConnection { id:sparqlConnection; objectName:"sparqlConnection"; driver:"QTRACKER_DIRECT" }
+                       // This is the query for the model
+                       query: "select ?u ?firstName ?secondName"+
+                              "{ ?u a nco:PersonContact;"+
+                              "nie:isLogicalPartOf <qml-example>;"+
+                              "nco:nameGiven ?firstName;"+
+                              "nco:nameFamily ?secondName .} order by ?secondName ?firstName"
+                   }
+
+            delegate: Item {  height: 50; Text { font.pixelSize: 40; text: secondName+","+firstName }  }
+        }
+    }
+// The "NameInput" page,
+    Rectangle {
+        id: nameInput
+        visible: false
+        width: mainRectangle.width
+        height: mainRectangle.height
+        anchors.verticalCenter: parent.verticalCenter
+        Rectangle {
+            width: parent.width
+            height: 300
+
+            // This is the button that deals with inserting
+            // a contact
+            Rectangle {
+                // When the button is clicked, insert the data using the "update" function of
+                // of the sparql connection
+                MouseArea {
+                    anchors.fill: parent
+                    onClicked: {
+                        var queryString = "insert { "+
+                                         "_:u a nco:PersonContact; nie:isLogicalPartOf <qml-example>; "+
+                                         "nco:nameGiven $:firstName;"+
+                                         "nco:nameFamily $:secondName . }";
+                        var boundValues = { "firstName":firstNameInput.text, "secondName":familyNameInput.text }
+                        sparqlConnection.update(queryString, boundValues);
+                        // clean up
+                        firstNameInput.text = ""
+                        familyNameInput.text = ""
+                        nameInput.visible = false
+                        contactsRect.visible = true
+                        contactsView.visible = true
+                        controlRect.visible = true
+                    }
+                }
+                anchors.top: gridView.bottom
+                anchors.topMargin: 20
+                anchors.horizontalCenter: gridView.horizontalCenter
+                color: "red"; width: 75; height: 75
+
+                gradient: Gradient {
+                    GradientStop {
+                        position: 0.0
+                        color: "dimgrey"
+                    }
+                    GradientStop {
+                        position: 1.0
+                        color: "darkgrey"
+                    }
+                }
+                Text { anchors.centerIn: parent; font.pixelSize: 50; text: "+" }
+
+            }
+
+            Grid {
+                id: gridView
+                columns: 1
+                spacing: 2
+                width: parent.width - 50
+                anchors.horizontalCenter : parent.horizontalCenter
+                Rectangle {
+                    width: parent.width; height: 50
+                    Text { smooth: true; font.pixelSize: 50; text: "Firstname"; anchors.verticalCenter: parent.verticalCenter}
+                }
+                Rectangle {
+                    border.width:5; radius:5; border.color:"black"; width: parent.width; height: 75
+                    TextInput {
+                        id: firstNameInput
+                        smooth: true
+                        font.pixelSize: 50
+                        anchors.fill: parent
+                        anchors.leftMargin: 10
+                        anchors.topMargin: 10
+                        anchors.verticalCenter: parent.verticalCenter
+                        MouseArea {
+                            anchors.fill: parent
+                            onClicked: {
+                                if (!firstNameInput.activeFocus) {
+                                    firstNameInput.forceActiveFocus()
+                                } else {
+                                    firstNameInput.focus = false
+                                }
+                            }
+                        }
+                        onAccepted: { firstNameInput.closeSoftwareInputPanel() }
+                    }
+                }
+                Rectangle {
+                    width: parent.width; height: 50
+                    Text { smooth: true; font.pixelSize: 50; text: "Surname"; anchors.verticalCenter: parent.verticalCenter}
+                }
+                Rectangle {
+                    border.width:5; radius:5; border.color:"black"; width: parent.width; height: 75
+                    TextInput {
+                        id: familyNameInput
+                        smooth: true
+                        font.pixelSize: 50
+                        anchors.fill: parent
+                        anchors.leftMargin: 10
+                        anchors.topMargin: 10
+                        anchors.verticalCenter: parent.verticalCenter
+                        MouseArea {
+                            anchors.fill: parent
+                            onClicked: {
+                               if (!familyNameInput.activeFocus) {
+                                    familyNameInput.forceActiveFocus();
+                               } else {
+                                    familyNameInput.focus = false;
+                               }
+                            }
+                        }
+                        onAccepted: { familyNameInput.closeSoftwareInputPanel() }
+                    }
+                }
+            }
+        }
+    }
+// the menu bar
+    Rectangle {
+        id: controlRect
+        width: parent.width
+        height: 50
+
+        color: "blue"
+        gradient: Gradient {
+            GradientStop {
+                position: 0.0
+                color: "dimgrey"
+            }
+            GradientStop {
+                position: 1.0
+                color: "darkgrey"
+            }
+        }
+
+        Rectangle {
+            id: addButton
+            width: 50
+            height: 50
+            anchors.centerIn: parent
+            color: "red"
+            border.width: 1
+            radius: 4
+            smooth: true
+
+            gradient: Gradient {
+                GradientStop {
+                    position: 0.0
+                    color: !mouseArea.pressed ? activePalette.light : activePalette.button
+                }
+                GradientStop {
+                    position: 1.0
+                    color: !mouseArea.pressed ? activePalette.button : activePalette.dark
+                }
+            }
+            SystemPalette { id: activePalette }
+            MouseArea {
+                id: mouseArea
+                anchors.fill: parent
+                onClicked:
+                {
+                    if (contactsRect.visible) {
+                        controlRect.visible = false
+                        contactsRect.visible = false
+                        nameInput.visible = true
+                    } else {
+                        contactsRect.visible = true
+                        nameInput.visible = false
+                    }
+                }
+            }
+            Text {
+                id: text
+                anchors.centerIn:parent
+                font.pointSize: 50
+                smooth: true
+                text: "+"
+                color: activePalette.buttonText
+            }
+        }
+    }
+}
--- examples/sparql/qmlbindings/qmlbindings.pro
+++ examples/sparql/qmlbindings/qmlbindings.pro
+include(../sparql-examples.pri)
+
+SOURCES += main.cpp
+
+#QT += sparql #enable this later
+QT += gui declarative dbus
+
+copy2build.target = $$QT_BUILD_TREE/examples/sparql/qmlbindings/main.qml
+copy2build.commands = $$QMAKE_COPY $$PWD/main.qml $$QT_BUILD_TREE/examples/sparql/qmlbindings
+QMAKE_EXTRA_TARGETS += copy2build
+
+copy2buildhook.depends = copy2build
+copy2buildhook.target = Makefile
+QMAKE_EXTRA_TARGETS += copy2buildhook
+
+# install # FIXME: install & package examples later
+#target.path = $$EXAMPLES_DIR/sparql/qmlbindings
+#sources.files = $$SOURCES *.h $$RESOURCES $$FORMS qmlbindings.pro
+#sources.path = $$EXAMPLES_DIR/sparql/qmlbindings
+#INSTALLS += target sources
--- examples/sparql/qmlquerymodel/main.cpp
+++ examples/sparql/qmlquerymodel/main.cpp
@@ -39,47 +39,129 @@
 **
 ****************************************************************************/
 
-#include <QtGui/QApplication>
+#include <QApplication>
 #include <QtDeclarative>
 #include <QtSparql>
-#include <QDebug>
+#include <QtDBus>
+#include <QString>
 
-int main(int argc, char *argv[])
+class ModelLiveChange : public QObject
 {
-    QApplication app(argc, argv);
+    Q_OBJECT
+    QSparqlQueryModel *model;
+    QSparqlConnection *connection;
+    QString query;
+
+public :
+    ModelLiveChange(QSparqlQueryModel *model);
+    ~ModelLiveChange();
+
+public slots:
+    void changed(QString);
+    void gotClick(QString, QString);
+};
 
-    QString query("select ?urn ?subject "
-                       "{ ?urn a nmo:Email ; "
-                       "nmo:messageSubject ?subject . "
-                       "} "
-                       "order by ?e");
+ModelLiveChange::ModelLiveChange(QSparqlQueryModel *model) : model(model)
+{
+    // The property names in QML will be "u" "firstName" and "secondName"
+    query = "select ?u ?firstName ?secondName "
+            "{ ?u a nco:PersonContact; "
+            "nie:isLogicalPartOf <qml-example>; "
+            "nco:nameGiven ?firstName; "
+            "nco:nameFamily ?secondName .} order by ?secondName ?firstName";
+
+    // In this example we use the QTRACKER_DIRECT driver, QML model support
+    // also works the same for the QSPARQL_ENDPOINT driver.
+    connection = new QSparqlConnection("QTRACKER_DIRECT");
+
+    // Create a new model and set the query
+    // We use setQueryQML here so the properties are extracted from
+    // the query
+    model->setQueryQML(QSparqlQuery(query), *connection);
+
+    // Now we need to monitor dbus for any notifications from Tracker.
+    // More information about Tracker over Dbus can be found at :
+    // http://live.gnome.org/Tracker/Documentation/SignalsOnChanges
+    // Please note: a more complete implementation, TrackerChangeNotifier,
+    // is available in libqtsparql-tracker-extensions
+    const QString service("org.freedesktop.Tracker1");
+    const QString basePath("/org/freedesktop/Tracker1");
+    const QString resourcesInterface("org.freedesktop.Tracker1.Resources");
+    const QString resourcesPath("/org/freedesktop/Tracker1/Resources");
+    const QString changedSignal("GraphUpdated");
+    const QString changedSignature("sa(iiii)a(iiii)");
+    const QString syncFunction("Sync");
+    // We'll need to use the long form of the class name to watch.
+    const QString className("http://www.semanticdesktop.org/ontologies/2007/03/22/nco#PersonContact");
+    QDBusConnection::sessionBus().connect(service, resourcesPath,
+                                          resourcesInterface, changedSignal,
+                                          QStringList() << className,
+                                          changedSignature,
+                                          this, SLOT(changed(QString)));
+}
 
-    QSparqlConnection connection("QTRACKER_DIRECT");
+ModelLiveChange::~ModelLiveChange()
+{
+    delete model;
+    delete connection;
+}
 
-    // Create a query model
+void ModelLiveChange::changed(QString className)
+{
+    Q_UNUSED(className);
+    // We got a change notification from DBus on the class
+    // we are watching, so call setQuery on the model again
+    // this will make the model requery, and any new results
+    // will be displayed
+    model->setQueryQML(QSparqlQuery(query), *connection);
+}
 
-    QSparqlQueryModel model;
-    model.setQuery(QSparqlQuery(query), connection);
+void ModelLiveChange::gotClick(QString firstName, QString familyName)
+{
+    // We use this slot to handel contact inserts from QML, simply insert
+    // them and the change notifier will pick them up and requery
+    const QString insertString("insert { _:u a nco:PersonContact; "
+                                   "nie:isLogicalPartOf <qml-example>; "
+                                   "nco:nameGiven $:firstName; "
+                                   "nco:nameFamily $:familyName .}");
+    QSparqlQuery insertQuery(insertString, QSparqlQuery::InsertStatement);
+    // Use bindValue to insert the user-provided strings into the query to
+    // avoid SPARQL injection issues. See QSparqlQuery::bindValue
+    insertQuery.bindValue("firstName", firstName);
+    insertQuery.bindValue("familyName", familyName);
+    QSparqlResult *r = connection->syncExec(insertQuery);
+    delete r;
+}
 
+int main(int argc, char *argv[])
+{
+    QApplication app(argc, argv);
 
-    // Initilise QML
+    // Initialise QML
     QDeclarativeView viewQml;
     QDeclarativeContext *ctxt = viewQml.rootContext();
 
+    // Create the model
+    QSparqlQueryModel *model = new QSparqlQueryModel();
     // Now set the context property for the ListView model to the liveQuery model
-    // access the values in qml using urn and subject
-    ctxt->setContextProperty("contactModel", &model);
+    ctxt->setContextProperty("contactModel", model);
     viewQml.setSource(QUrl::fromLocalFile("main.qml"));
-    viewQml.show();
 
-    return app.exec();
-}
+    ModelLiveChange changeNotifier(model);
 
-/*
+    // When a contact is added in the app, a "addContact" signal is emitted, connect
+    // this to a slot so we can insert the data into tracker
+    QObject::connect(viewQml.rootObject(), SIGNAL(addContact(QString, QString)),
+                     &changeNotifier, SLOT(gotClick(QString, QString)));
 
-How to insert example data into tracker:
+    viewQml.show();
+    return app.exec();
+}
 
-tracker-sparql -qu "insert {<email0> a nmo:Email ; nmo:messageSubject \"foo\" .}"
-tracker-sparql -qu "delete {<email0> a rdfs:Resource . }"
+#include "main.moc"
 
+/*
+How to insert/delete example data into tracker:
+tracker-sparql -qu "insert { _:u a nco:PersonContact; nie:isLogicalPartOf <qml-example>; nco:nameGiven 'foo'; nco:nameFamily 'bar' .}"
+tracker-sparql -qu "delete { ?u a nco:PersonContact } WHERE { ?u a nco:PersonContact; nie:isLogicalPartOf <qml-example> }"
 */
--- examples/sparql/qmlquerymodel/main.qml
+++ examples/sparql/qmlquerymodel/main.qml
@@ -1,14 +1,199 @@
 import Qt 4.7
+import QtSparql 1.0
 
 Rectangle {
-    width: 360
-    height: 360
+    id: mainRectangle
+    width: 800
+    height: 400
+    // This signal will be emitted, and caught on the c++ side
+    // we someone enters a new contact
+    signal addContact(string firstName, string familyName)
 
-    ListView {
-        id: contactsView
-        anchors.fill: parent
-        model: contactModel
+    Rectangle {
+        id: contactsRect
+        width: parent.width
+        height : parent.height - 50
+        anchors.top: controlRect.bottom
+        ListView {
+            id: contactsView
+            width: parent.width
+            height: parent.height
+            // contactModel will be set from C++
+            model: contactModel
+            delegate: Item {  height: 50; Text { font.pixelSize: 40; text: secondName+","+firstName }  }
+        }
+    }
+// The "NameInput" page,
+    Rectangle {
+        id: nameInput
+        visible: false
+        width: mainRectangle.width
+        height: mainRectangle.height
+        anchors.verticalCenter: parent.verticalCenter
+        Rectangle {
+            width: parent.width
+            height: 300
+
+            // This is the button that deals with inserting
+            // a contact
+            Rectangle {
+                // When the button is clicked, emit the addContact signal with the input
+                // we can catch and process this on the C++ side
+                MouseArea {
+                    anchors.fill: parent
+                    onClicked: {
+                        addContact(firstNameInput.text ,familyNameInput.text)
+                        firstNameInput.text = ""
+                        familyNameInput.text = ""
+                        nameInput.visible = false
+                        contactsRect.visible = true
+                        contactsView.visible = true
+                        controlRect.visible = true
+                    }
+                }
+                anchors.top: gridView.bottom
+                anchors.topMargin: 20
+                anchors.horizontalCenter: gridView.horizontalCenter
+                color: "red"; width: 75; height: 75
+
+                gradient: Gradient {
+                    GradientStop {
+                        position: 0.0
+                        color: "dimgrey"
+                    }
+                    GradientStop {
+                        position: 1.0
+                        color: "darkgrey"
+                    }
+                }
+                Text { anchors.centerIn: parent; font.pixelSize: 50; text: "+" }
+            }
+
+            Grid {
+                id: gridView
+                columns: 1
+                spacing: 2
+                width: parent.width - 50
+                anchors.horizontalCenter : parent.horizontalCenter
+                Rectangle {
+                    width: parent.width; height: 50
+                    Text { smooth: true; font.pixelSize: 50; text: "Firstname"; anchors.verticalCenter: parent.verticalCenter}
+                }
+                Rectangle {
+                    border.width:5; radius:5; border.color:"black"; width: parent.width; height: 75
+                    TextInput {
+                        id: firstNameInput
+                        smooth: true
+                        font.pixelSize: 50
+                        anchors.fill: parent
+                        anchors.leftMargin: 10
+                        anchors.topMargin: 10
+                        anchors.verticalCenter: parent.verticalCenter
+                        MouseArea {
+                            anchors.fill: parent
+                            onClicked: {
+                                if (!firstNameInput.activeFocus) {
+                                    firstNameInput.forceActiveFocus()
+                                } else {
+                                    firstNameInput.focus = false
+                                }
+                            }
+                        }
+                        onAccepted: { firstNameInput.closeSoftwareInputPanel() }
+                    }
+                }
+                Rectangle {
+                    width: parent.width; height: 50
+                    Text { smooth: true; font.pixelSize: 50; text: "Surname"; anchors.verticalCenter: parent.verticalCenter}
+                }
+                Rectangle {
+                    border.width:5; radius:5; border.color:"black"; width: parent.width; height: 75
+                    TextInput {
+                        id: familyNameInput
+                        smooth: true
+                        font.pixelSize: 50
+                        anchors.fill: parent
+                        anchors.leftMargin: 10
+                        anchors.topMargin: 10
+                        anchors.verticalCenter: parent.verticalCenter
+                        MouseArea {
+                            anchors.fill: parent
+                            onClicked: {
+                               if (!familyNameInput.activeFocus) {
+                                    familyNameInput.forceActiveFocus();
+                               } else {
+                                    familyNameInput.focus = false;
+                               }
+                            }
+                        }
+                        onAccepted: { familyNameInput.closeSoftwareInputPanel() }
+                    }
+                }
+            }
+        }
+    }
+// the menu bar
+    Rectangle {
+        id: controlRect
+        width: parent.width
+        height: 50
+
+        color: "blue"
+        gradient: Gradient {
+            GradientStop {
+                position: 0.0
+                color: "dimgrey"
+            }
+            GradientStop {
+                position: 1.0
+                color: "darkgrey"
+            }
+        }
+
+        Rectangle {
+            id: addButton
+            width: 50
+            height: 50
+            anchors.centerIn: parent
+            color: "red"
+            border.width: 1
+            radius: 4
+            smooth: true
 
-        delegate: Text { text: "ID = " + urn + "\nSubject = " + subject + "\n" }
+            gradient: Gradient {
+                GradientStop {
+                    position: 0.0
+                    color: !mouseArea.pressed ? activePalette.light : activePalette.button
+                }
+                GradientStop {
+                    position: 1.0
+                    color: !mouseArea.pressed ? activePalette.button : activePalette.dark
+                }
+            }
+            SystemPalette { id: activePalette }
+            MouseArea {
+                id: mouseArea
+                anchors.fill: parent
+                onClicked:
+                {
+                    if (contactsRect.visible) {
+                        controlRect.visible = false
+                        contactsRect.visible = false
+                        nameInput.visible = true
+                    } else {
+                        contactsRect.visible = true
+                        nameInput.visible = false
+                    }
+                }
+            }
+            Text {
+                id: text
+                anchors.centerIn:parent
+                font.pointSize: 50
+                smooth: true
+                text: "+"
+                color: activePalette.buttonText
+            }
+        }
     }
 }
--- examples/sparql/qmlquerymodel/qmlquerymodel.pro
+++ examples/sparql/qmlquerymodel/qmlquerymodel.pro
@@ -1,15 +1,12 @@
 include(../sparql-examples.pri)
 
-CONFIG += qt
-
 SOURCES += main.cpp
 
 #QT += sparql #enable this later
-QT += gui declarative
+QT += gui declarative dbus
 
 copy2build.target = $$QT_BUILD_TREE/examples/sparql/qmlquerymodel/main.qml
-copy2build.commands = $$QMAKE_COPY $$PWD/albums.qml $$QT_BUILD_TREE/examples/sparql/qmlquerymodel
-copy2build.depends = $$PWD/main.qml
+copy2build.commands = $$QMAKE_COPY $$PWD/main.qml $$QT_BUILD_TREE/examples/sparql/qmlquerymodel
 QMAKE_EXTRA_TARGETS += copy2build
 
 copy2buildhook.depends = copy2build
--- examples/sparql/sparql.pro
+++ examples/sparql/sparql.pro
@@ -3,6 +3,7 @@
 SUBDIRS       = simple \
                 dbpedia \
                 qmlquerymodel \
+                qmlbindings \
                 querymodel \
                 iteration \
                 asynctracker \
--- shared.pri
+++ shared.pri
@@ -1,6 +1,6 @@
 #we need to explicitly set the include path for any Qt Includes now, add them here
 #then we can add the base include path after we've included the headers from the build tree
-INCLUDEPATH += $$[QT_INSTALL_HEADERS]/QtCore $$[QT_INSTALL_HEADERS]/QtXml $$[QT_INSTALL_HEADERS]/QtNetwork $$[QT_INSTALL_HEADERS]/QtDeclarative $$[QT_INSTALL_HEADERS]/QtTest $$[QT_INSTALL_HEADERS]/QtGui \
+INCLUDEPATH += $$[QT_INSTALL_HEADERS]/QtCore $$[QT_INSTALL_HEADERS]/QtXml $$[QT_INSTALL_HEADERS]/QtNetwork $$[QT_INSTALL_HEADERS]/QtDeclarative $$[QT_INSTALL_HEADERS]/QtTest $$[QT_INSTALL_HEADERS]/QtGui $$[QT_INSTALL_HEADERS]/QtDBus \
                $$QT_BUILD_TREE/include $$QT_BUILD_TREE/include/QtSparql/ \
                $$[QT_INSTALL_HEADERS]
 QT = core
@@ -13,10 +13,10 @@
 isEmpty(PREFIX): PREFIX = $$QTSPARQL_INSTALL_PREFIX
 
 # this will be in the .so name
-VERSION = 0.0.28
+VERSION = 0.2.1
 
 # for documentation
-DOC_VERSION = 0.0.28
+DOC_VERSION = 0.2.1
 LIBRARYNAME = QtSparql
 PACKAGENAME = libqtsparql
 
--- src/plugins/declarative/declarative.pro
+++ src/plugins/declarative/declarative.pro
@@ -1,7 +1,7 @@
 include(../../../shared.pri)
 
 TEMPLATE = subdirs
-SUBDIRS += sparqlresultslist
+SUBDIRS += sparqllistmodel sparqlconnection sparqlresultslist
 
 qmldir.files = $$PWD/qmldir
 qmldir.path = $$QTSPARQL_INSTALL_IMPORTS/QtSparql
--- src/plugins/declarative/qmldir
+++ src/plugins/declarative/qmldir
@@ -1 +1,3 @@
+plugin sparqllistmodel
+plugin sparqlconnection
 plugin sparqlresultslist
--- src/plugins/declarative/sparqlconnection
+++ src/plugins/declarative/sparqlconnection
+(directory)
--- src/plugins/declarative/sparqlconnection/plugin.cpp
+++ src/plugins/declarative/sparqlconnection/plugin.cpp
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (ivan.frade at nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at ivan.frade at nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qdebug.h>
+
+#include <QtDeclarative/QDeclarativeExtensionPlugin>
+#include <QtDeclarative/qdeclarative.h>
+
+#include <QtSparql/qsparqlquerymodel.h>
+#include <QtSparql/private/qsparqlsparqlconnection_p.h>
+#include <QtSparql/private/qsparqlsparqlconnectionoptions_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class SparqlConnectionPlugin : public QDeclarativeExtensionPlugin
+{
+public:
+    void registerTypes(const char *uri)
+    {
+        Q_ASSERT(uri == QLatin1String("QSparql"));
+        qmlRegisterType<SparqlConnection>(uri, 1, 0, "SparqlConnection");
+        qmlRegisterType<SparqlConnectionOptions>(uri, 1, 0, "SparqlConnectionOptions");
+    }
+};
+
+Q_EXPORT_PLUGIN2(sparqlconnection, SparqlConnectionPlugin);
+
+QT_END_NAMESPACE
--- src/plugins/declarative/sparqlconnection/sparqlconnection.pro
+++ src/plugins/declarative/sparqlconnection/sparqlconnection.pro
+include(../declarativebase.pri)
+
+TARGET	 = sparqlconnection
+SOURCES		= plugin.cpp
+
+DESTDIR = $$QT_BUILD_TREE/imports/QtSparql
--- src/plugins/declarative/sparqllistmodel
+++ src/plugins/declarative/sparqllistmodel
+(directory)
--- src/plugins/declarative/sparqllistmodel/plugin.cpp
+++ src/plugins/declarative/sparqllistmodel/plugin.cpp
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (ivan.frade at nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at ivan.frade at nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qdebug.h>
+
+#include <QtDeclarative/QDeclarativeExtensionPlugin>
+#include <QtDeclarative/qdeclarative.h>
+
+#include <QtSparql/qsparqlquerymodel.h>
+#include <QtSparql/private/qsparqlsparqllistmodel_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class SparqlListModelPlugin : public QDeclarativeExtensionPlugin
+{
+public:
+    void registerTypes(const char *uri)
+    {
+        Q_ASSERT(uri == QLatin1String("QSparql"));
+        qmlRegisterType<SparqlListModel>(uri, 1, 0, "SparqlListModel");
+    }
+};
+
+Q_EXPORT_PLUGIN2(sparqllistmodel, SparqlListModelPlugin);
+
+QT_END_NAMESPACE
--- src/plugins/declarative/sparqllistmodel/sparqllistmodel.pro
+++ src/plugins/declarative/sparqllistmodel/sparqllistmodel.pro
+include(../declarativebase.pri)
+
+TARGET	 = sparqllistmodel
+SOURCES		= plugin.cpp
+
+DESTDIR = $$QT_BUILD_TREE/imports/QtSparql
--- src/plugins/declarative/sparqlresultslist/plugin.cpp
+++ src/plugins/declarative/sparqlresultslist/plugin.cpp
@@ -54,7 +54,7 @@
     {
         Q_ASSERT(qstrcmp(uri, "QSparql") == 0);
         qmlRegisterType<QSparqlResultsList>(uri, 0, 1, "SparqlResultsList");
-        qmlRegisterType<QSparqlConnectionOptionsWrapper>(uri, 0, 1, "SparqlConnectionOptions");
+        qmlRegisterType<SparqlConnectionOptions>(uri, 0, 1, "SparqlConnectionOptions");
     }
 };
 
--- src/plugins/sparqldrivers/tracker_direct/main.cpp
+++ src/plugins/sparqldrivers/tracker_direct/main.cpp
@@ -39,7 +39,7 @@
 
 #include <QtSparql/private/qsparqldriverplugin_p.h>
 #include <qstringlist.h>
-#include "../../../sparql/drivers/tracker_direct/qsparql_tracker_direct_driver_p.h"
+#include "../../../sparql/drivers/tracker_direct/qsparql_tracker_direct_p.h"
 
 QT_BEGIN_NAMESPACE
 
--- src/plugins/sparqldrivers/tracker_direct/tracker_direct.pro
+++ src/plugins/sparqldrivers/tracker_direct/tracker_direct.pro
@@ -1,13 +1,16 @@
 TARGET   = qsparqltrackerdirect
 CONFIG += no_keywords
 
-HEADERS         = ../../../sparql/drivers/tracker_direct/qsparql_tracker_direct_driver_p.h \
+HEADERS         = ../../../sparql/drivers/tracker_direct/qsparql_tracker_direct_p.h \
+                  ../../../sparql/drivers/tracker_direct/qsparql_tracker_direct_driver_p.h \
                   ../../../sparql/drivers/tracker_direct/qsparql_tracker_direct_result_p.h \
+                  ../../../sparql/drivers/tracker_direct/qsparql_tracker_direct_select_result_p.h \
                   ../../../sparql/drivers/tracker_direct/qsparql_tracker_direct_sync_result_p.h \
                   ../../../sparql/drivers/tracker_direct/qsparql_tracker_direct_update_result_p.h
 SOURCES         = main.cpp \
                   ../../../sparql/drivers/tracker_direct/qsparql_tracker_direct_driver_p.cpp \
                   ../../../sparql/drivers/tracker_direct/qsparql_tracker_direct_result_p.cpp \
+                  ../../../sparql/drivers/tracker_direct/qsparql_tracker_direct_select_result_p.cpp \
                   ../../../sparql/drivers/tracker_direct/qsparql_tracker_direct_sync_result_p.cpp \
                   ../../../sparql/drivers/tracker_direct/qsparql_tracker_direct_update_result_p.cpp
 
--- src/sparql/declarative
+++ src/sparql/declarative
+(directory)
--- src/sparql/declarative/declarative.pri
+++ src/sparql/declarative/declarative.pri
+HEADERS +=      declarative/qsparqlsparqlconnection_p.h declarative/qsparqlsparqlconnectionoptions_p.h declarative/qsparqlsparqllistmodel_p.h
+SOURCES += declarative/qsparqlsparqlconnection.cpp declarative/qsparqlsparqllistmodel.cpp
+QT += declarative
--- src/sparql/declarative/qsparqlsparqlconnection.cpp
+++ src/sparql/declarative/qsparqlsparqlconnection.cpp
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (ivan.frade at nokia.com)
+**
+** This file is part of the QtSparql module (not yet part of the Qt Toolkit).
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at ivan.frade at nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsparqlsparqlconnection_p.h"
+#include "qsparqlsparqlconnectionoptions_p.h"
+#include <QSparqlResult>
+#include <QSparqlResultRow>
+#include <QSparqlError>
+
+SparqlConnection::SparqlConnection()
+  : asyncResult(0)
+  , lastResult(0)  // To avoid "result" property having undefined value in QML
+  , options(0)
+  , connectionStatus(Null)
+{
+}
+
+void SparqlConnection::classBegin()
+{
+    changeStatus(Loading);
+}
+
+void SparqlConnection::componentComplete()
+{
+    // we will create the connection once the component has finished reading, that way
+    // we know if any connection options have been set
+    if (options) {
+        qmlConstructor(driverName, *options);
+    } else {
+        qmlConstructor(driverName);
+    }
+
+    // check connection opening when ok
+    if (isValid()) {
+        changeStatus(Ready);
+    } else {
+        lastErrorMessage = QLatin1String("Failed to open connection");
+        changeStatus(Error);
+    }
+    Q_EMIT onCompleted();
+}
+
+QString SparqlConnection::errorString() const
+{
+    if (connectionStatus != Error)
+        return QString();
+    return lastErrorMessage;
+}
+
+QVariant SparqlConnection::select(QString queryString, bool async)
+{
+    QSparqlQuery query(queryString);
+    return runQuery(query, async);
+}
+
+QVariant SparqlConnection::select(QString queryString, QVariant boundValues, bool async)
+{
+    QSparqlQuery query(queryString);
+    if (bindValues(&query, boundValues))
+        return runQuery(query, async);
+    return -1;
+}
+
+QVariant SparqlConnection::ask(QString queryString, bool async)
+{
+    QSparqlQuery query(queryString, QSparqlQuery::AskStatement);
+    return runQuery(query, async);
+}
+
+QVariant SparqlConnection::ask(QString queryString, QVariant boundValues, bool async)
+{
+    QSparqlQuery query(queryString, QSparqlQuery::AskStatement);
+    if (bindValues(&query, boundValues))
+        return runQuery(query, async);
+    return -1;
+}
+
+QVariant SparqlConnection::update(QString queryString, bool async)
+{
+    // inserts and deletes are both update queries, and run in the same
+    // way, so it doesn't matter if this is an insert or delete statement
+    QSparqlQuery query(queryString, QSparqlQuery::InsertStatement);
+    return runQuery(query, async);
+}
+
+QVariant SparqlConnection::update(QString queryString, QVariant boundValues, bool async)
+{
+    QSparqlQuery query(queryString, QSparqlQuery::InsertStatement);
+    if (bindValues(&query, boundValues))
+        return runQuery(query, async);
+    return -1;
+}
+
+QVariant SparqlConnection::construct(QString queryString, bool async)
+{
+    QSparqlQuery query(queryString, QSparqlQuery::ConstructStatement);
+    return runQuery(query, async);
+}
+
+QVariant SparqlConnection::construct(QString queryString, QVariant boundValues, bool async)
+{
+    QSparqlQuery query(queryString, QSparqlQuery::ConstructStatement);
+    if (bindValues(&query, boundValues))
+        return runQuery(query, async);
+    return -1;
+}
+
+bool SparqlConnection::bindValues(QSparqlQuery *query, QVariant boundValues)
+{
+    if (!boundValues.convert(QVariant::Map)) {
+        lastErrorMessage = QLatin1String("Invalid bound values hashmap");
+        changeStatus(Error);
+        return false;
+    }
+
+    QMap<QString, QVariant> boundPairs = boundValues.toMap();
+
+    QMapIterator<QString, QVariant> i(boundPairs);
+    while (i.hasNext()) {
+        i.next();
+        query->bindValue(i.key(), i.value());
+    }
+    return true;
+}
+
+QVariant SparqlConnection::runQuery(QSparqlQuery query, bool async)
+{
+    if (!isValid()) {
+        return -1;
+    }
+    changeStatus(Ready);
+    // clear the last result
+    lastResult.clear();
+    if (async) {
+        // in case of previous active async result
+        delete asyncResult;
+        asyncResult = exec(query);
+        connect(asyncResult, SIGNAL(finished()), this, SLOT(onResultFinished()));
+    } else {
+        QSparqlResult *result = syncExec(query);
+        return resultToVariant(result);
+    }
+    return 0;
+}
+
+QVariant SparqlConnection::getResult()
+{
+    return lastResult;
+}
+
+void SparqlConnection::onResultFinished()
+{
+    resultToVariant(asyncResult);
+    asyncResult = 0;
+}
+
+QVariant SparqlConnection::resultToVariant(QSparqlResult *result)
+{
+    // check for a result error
+    if (result->hasError()) {
+        lastErrorMessage = result->lastError().message();
+        changeStatus(Error);
+        delete result;
+        return -1;
+    }
+    // check for ask query first, just return a bool
+    // if it is
+    if (result->isBool()) {
+        // next past the result to avoid warning
+        result->next();
+        result->next();
+        lastResult = result->boolValue();
+    } else {
+        QVariantList resultList;
+        QVector<QString> bindingNames;
+        while(result->next()) {
+            // only read the binding names once
+            if (result->pos() == 0) {
+                QSparqlResultRow row = result->current();
+                for (int i=0; i<row.count(); i++) {
+                    bindingNames.append(row.binding(i).name());
+                }
+            }
+            QVariantMap resultHash;
+            for (int i=0; i<bindingNames.size(); i++) {
+                resultHash.insert(bindingNames.at(i), result->value(i));
+            }
+            resultList.append(resultHash);
+        }
+        lastResult = resultList;
+    }
+    result->deleteLater();
+    Q_EMIT resultReady(lastResult);
+    return lastResult;
+}
+
+void SparqlConnection::changeStatus(SparqlConnection::Status status)
+{
+    if (connectionStatus != status) {
+        connectionStatus = status;
+        Q_EMIT statusChanged(connectionStatus);
+    }
+}
+// property set/get methods
+
+SparqlConnection::Status SparqlConnection::status()
+{
+    return connectionStatus;
+}
+
+void SparqlConnection::setOptions(SparqlConnectionOptions* options)
+{
+    if (options)
+    {
+       this->options = options;
+    }
+}
+
+SparqlConnectionOptions* SparqlConnection::getOptions()
+{
+    return options;
+}
+
+void SparqlConnection::setDriver(QString driverName)
+{
+    this->driverName = driverName;
+}
+
+QString SparqlConnection::getDriver()
+{
+    return driverName;
+}
--- src/sparql/declarative/qsparqlsparqlconnection_p.h
+++ src/sparql/declarative/qsparqlsparqlconnection_p.h
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (ivan.frade at nokia.com)
+**
+** This file is part of the QtSparql module (not yet part of the Qt Toolkit).
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at ivan.frade at nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qdebug.h>
+
+#include <QtDeclarative/qdeclarative.h>
+#include <QDeclarativeParserStatus>
+#include <QtSparql/qsparqlquerymodel.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Sparql)
+
+class SparqlQuery;
+class SparqlConnectionOptions;
+
+class Q_SPARQL_EXPORT SparqlConnection : public QSparqlConnection, public QDeclarativeParserStatus
+{
+    Q_OBJECT
+    Q_ENUMS(Status)
+    Q_PROPERTY(Status status READ status NOTIFY statusChanged)
+    Q_PROPERTY(QString driver WRITE setDriver READ getDriver)
+    Q_PROPERTY(QVariant result READ getResult NOTIFY resultReady)
+    Q_PROPERTY(SparqlConnectionOptions * options WRITE setOptions READ getOptions)
+    Q_CLASSINFO("DefaultProperty", "driver")
+    Q_INTERFACES(QDeclarativeParserStatus)
+
+public:
+    SparqlConnection();
+    ~SparqlConnection() {}
+
+    enum Status { Null, Ready, Loading, Error };
+
+    void classBegin();
+    void componentComplete();
+
+    Q_INVOKABLE QVariant select(QString query, bool async = false);
+    Q_INVOKABLE QVariant select(QString query, QVariant boundValues, bool async = false);
+    Q_INVOKABLE QVariant ask(QString query, bool async = false);
+    Q_INVOKABLE QVariant ask(QString query, QVariant boundValues, bool async = false);
+    Q_INVOKABLE QVariant update(QString query, bool async = false);
+    Q_INVOKABLE QVariant update(QString query, QVariant boundValues, bool async = false);
+    Q_INVOKABLE QVariant construct(QString query, bool async = false);
+    Q_INVOKABLE QVariant construct(QString query, QVariant boundValues, bool async = false);
+    Q_INVOKABLE QString errorString() const;
+
+Q_SIGNALS:
+    void statusChanged(SparqlConnection::Status);
+    void resultReady(QVariant);
+    void onCompleted();
+
+private Q_SLOTS:
+    void onResultFinished();
+
+private:
+    QString driverName;
+    QString lastErrorMessage;
+    QSparqlResult *asyncResult; // for async queries
+    QVariant lastResult;
+    SparqlConnectionOptions *options;
+    Status connectionStatus;
+
+    QVariant resultToVariant(QSparqlResult *result);
+    QVariant runQuery(QSparqlQuery query, bool async);
+    QVariant getResult();
+    void changeStatus(SparqlConnection::Status);
+    bool bindValues(QSparqlQuery *query, QVariant boundValues);
+    // property methods
+    void setOptions(SparqlConnectionOptions* options);
+    SparqlConnectionOptions* getOptions();
+    void setDriver(QString driverName);
+    QString getDriver();
+    Status status();
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
--- src/sparql/declarative/qsparqlsparqlconnectionoptions_p.h
+++ src/sparql/declarative/qsparqlsparqlconnectionoptions_p.h
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (ivan.frade at nokia.com)
+**
+** This file is part of the QtSparql module (not yet part of the Qt Toolkit).
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at ivan.frade at nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qstring.h>
+
+#include <QtDeclarative/qdeclarative.h>
+#include <QDeclarativeParserStatus>
+#include <QtSparql/qsparqlquerymodel.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Sparql)
+
+class Q_SPARQL_EXPORT SparqlConnectionOptions : public QObject, public QDeclarativeParserStatus, public QSparqlConnectionOptions
+{
+    Q_OBJECT
+    Q_PROPERTY(QString databaseName READ databaseName WRITE setDatabaseName)
+    Q_PROPERTY(QString userName READ userName WRITE setUserName)
+    Q_PROPERTY(QString password READ password WRITE setPassword)
+    Q_PROPERTY(QString hostName READ hostName WRITE setHostName)
+    Q_PROPERTY(QString path READ path WRITE setPath)
+    Q_PROPERTY(int port READ port WRITE setPort)
+    Q_PROPERTY(QString driverName READ driverName WRITE setDriverName)
+    Q_INTERFACES(QDeclarativeParserStatus)
+public:
+    SparqlConnectionOptions() {}
+    void classBegin() {}
+    void componentComplete() {}
+
+    void setDriverName(const QString& name)
+    {
+        driver = name;
+    }
+
+    QString driverName() const
+    {
+        return driver;
+    }
+private:
+    QString driver;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
--- src/sparql/declarative/qsparqlsparqllistmodel.cpp
+++ src/sparql/declarative/qsparqlsparqllistmodel.cpp
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (ivan.frade at nokia.com)
+**
+** This file is part of the QtSparql module (not yet part of the Qt Toolkit).
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at ivan.frade at nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsparqlsparqllistmodel_p.h"
+#include "qsparqlsparqlconnection_p.h"
+#include <QtSparql>
+
+SparqlListModel::SparqlListModel()
+  : connection(0)
+  , modelStatus(Null)
+{
+    connect(this, SIGNAL(rowsRemoved(const QModelIndex &, int, int)), this, SIGNAL(countChanged()));
+    connect(this, SIGNAL(rowsInserted(const QModelIndex &, int, int)), this, SIGNAL(countChanged()));
+    connect(this, SIGNAL(finished()), this, SLOT(onFinished()));
+    connect(this, SIGNAL(started()), this, SLOT(onStarted()));
+}
+
+void SparqlListModel::classBegin()
+{
+}
+
+void SparqlListModel::componentComplete()
+{
+    changeStatus(Loading);
+    // we will create the connection once the component has finished reading, that way
+    // we know if any connection options have been set
+}
+
+void SparqlListModel::setQuery(QString query)
+{
+    queryString = query;
+    // if the query property changes, after the binding has been
+    // initilised, call reload
+    if (modelStatus != Null)
+        reload();
+}
+
+QString SparqlListModel::getQuery() const
+{
+    return queryString;
+}
+
+QVariant SparqlListModel::get(int rowNumber)
+{
+    QVariantMap map;
+    QSparqlResultRow row = resultRow(rowNumber);
+    for (int i=0; i<row.count(); i++) {
+        map.insert(row.binding(i).name(), row.value(i));
+    }
+    return map;
+}
+
+void SparqlListModel::reload()
+{
+    changeStatus(Loading);
+    setQueryQML(QSparqlQuery(queryString), *connection);
+}
+
+void SparqlListModel::setConnection(SparqlConnection* connection)
+{
+    if (connection)
+    {
+        this->connection = connection;
+        connect(connection, SIGNAL(onCompleted()), this, SLOT(onConnectionComplete()));
+    }
+}
+
+void SparqlListModel::onConnectionComplete()
+{
+    if (connection && connection->isValid()) {
+        setQueryQML(QSparqlQuery(queryString), *connection);
+    } else {
+        lastErrorMessage = QLatin1String("Error opening connection");
+        changeStatus(Error);
+    }
+}
+
+SparqlConnection* SparqlListModel::getConnection()
+{
+    return connection;
+}
+
+SparqlListModel::Status SparqlListModel::status()
+{
+    return modelStatus;
+}
+
+QString SparqlListModel::errorString() const
+{
+    return lastErrorMessage;
+}
+
+void SparqlListModel::onStarted()
+{
+    changeStatus(Loading);
+}
+
+void SparqlListModel::onFinished()
+{
+    if (lastError().type() == QSparqlError::NoError) {
+        changeStatus(Ready);
+    } else {
+        lastErrorMessage = lastError().message();
+        changeStatus(Error);
+    }
+}
+
+void SparqlListModel::changeStatus(SparqlListModel::Status status)
+{
+    if (modelStatus != status) {
+        modelStatus = status;
+        Q_EMIT statusChanged(modelStatus);
+    }
+}
--- src/sparql/declarative/qsparqlsparqllistmodel_p.h
+++ src/sparql/declarative/qsparqlsparqllistmodel_p.h
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (ivan.frade at nokia.com)
+**
+** This file is part of the QtSparql module (not yet part of the Qt Toolkit).
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at ivan.frade at nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qdebug.h>
+
+#include <QtDeclarative/qdeclarative.h>
+#include <QDeclarativeParserStatus>
+#include <QtSparql/qsparqlquerymodel.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Sparql)
+
+class SparqlConnection;
+
+class Q_SPARQL_EXPORT SparqlListModel : public QSparqlQueryModel, public QDeclarativeParserStatus
+{
+    Q_OBJECT
+    Q_DECLARE_PRIVATE(QSparqlQueryModel)
+    Q_ENUMS(Status)
+    Q_PROPERTY(QString query READ getQuery WRITE setQuery)
+    Q_PROPERTY(SparqlConnection* connection READ getConnection WRITE setConnection)
+    Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
+    Q_PROPERTY(Status status READ status NOTIFY statusChanged)
+    Q_CLASSINFO("DefaultProperty", "query")
+    Q_INTERFACES(QDeclarativeParserStatus)
+
+public:
+    SparqlListModel();
+    void classBegin();
+    void componentComplete();
+
+    Q_INVOKABLE QString errorString() const;
+    Q_INVOKABLE QVariant get(int rowNumber);
+    Q_INVOKABLE void reload();
+
+    enum Status { Null, Ready, Loading, Error };
+
+
+Q_SIGNALS:
+    void countChanged();
+    void statusChanged(SparqlListModel::Status);
+
+private Q_SLOTS:
+    void onFinished();
+    void onStarted();
+    void onConnectionComplete();
+
+private:
+    SparqlConnection *connection;
+    QString queryString;
+    QString lastErrorMessage;
+    Status modelStatus;
+
+    void changeStatus(SparqlListModel::Status status);
+    // property methods
+    Status status();
+    void setConnection(SparqlConnection* connection);
+    SparqlConnection* getConnection();
+    void setQuery(QString query);
+    QString getQuery() const;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
--- src/sparql/declarative/sparqlconnectiondoc.cpp
+++ src/sparql/declarative/sparqlconnectiondoc.cpp
+/*!
+    \page qmlSparqlConnection SparqlConnection
+    \brief Provides a QML binding for QSparqlConnection. The connection can be used to issue SPARQL queries
+    directly from javascript, or as a connection for the ListView model \ref qmlSparqlListModel
+
+    \code
+    import QtSparql 1.0
+    \endcode
+
+    \section qmlproperties Properties
+    \li \ref qmlPropertyDriver "driver : string"
+    \li \ref qmlPropertyStatus "status : enumeration"
+    \li \ref qmlPropertyOptions "options : SparqlConnectionOptions"
+    \li \ref qmlPropertyResult "result : variant"
+
+    \section qmlmethods Methods
+    \li \ref qmlMethodSelect "variant select"
+    \li \ref qmlMethodAsk "bool ask"
+    \li \ref qmlMethodUpdate "variant update"
+    \li \ref qmlMethodConstruct "variant construct"
+    \li \ref qmlMethodErrorString "string errorString"
+
+    \section qmlPropertyDoc Property Documentation
+
+    The only required property to set is \a driver.
+
+    \anchor qmlPropertyDriver
+    <table><tr><th>driver : string</th></tr></table>
+    Set the driver to use for the connection, E.g. to use the tracker direct driver :
+    \code
+    SparqlConnection {
+        id: connection
+        driver: "QTRACKER_DIRECT"
+    }
+    \endcode
+    \anchor qmlPropertyStatus
+    <table><tr><th>status : enumeration \a read-only</th></tr></table>
+    Specifies the connection status, which can be one of the following:
+        \li Null - Connection has not been established
+        \li Ready - Connection is ready
+        \li Loading - Connection opening is established and waiting for completion
+        \li Error - There was an error in the connection opening, or an error with a query
+
+    The status can be monitored using the statusChanged() signal. E.g :
+    \code
+    SparqlConnection {
+        id: connectionalternatively
+        driver: "QTRACKER_DIRECT"
+        onStatusChanged: checkStatus(status)
+    }
+
+    function checkStatus(status)
+    {
+        if (status == SparqlConnection.Error)
+            console.log("Error = "+connection.errorString());
+    }
+    \endcode
+
+    \anchor qmlPropertyOptions
+    <table><tr><th>options : SparqlConnectionOptions</th></tr></table>
+
+    If connection options need to be set, the SparqlConnectionOptions binding can be used, E.g :
+
+    \code
+    SparqlConnection {
+        driver: "QSPARQL_ENDPOINT"
+        options: SparqlConnectionOptions {
+                    hostName: "localhost"
+                    port: 1234
+                 }
+    \endcode
+
+    For a full list of options, see QSparqlConnectionOptions.
+
+    \anchor qmlPropertyResult
+    <table><tr><th>result : variant \a read-only </th></tr></table>
+
+    Stores the current result after executing a query with \ref qmlMethodSelect "select()". This is a convenience
+    property to allow for a common function to be used for both synchronous and asynchronous queries. When a new result
+    is ready, a resultReady() signal will be emitted. E.g :
+    \code
+    SparqlConnection {
+        id: connection
+        driver: "QTRACKER_DIRECT"
+        onResultReady: resultFunction(result)
+    }
+
+    function resultFunction(result)
+    {
+        \\ do something with result
+    }
+    \endcode
+
+    See the section \ref usingResults "Using Results" for more information.
+
+    \section qmlMethodDoc Method Documentation
+
+    \anchor qmlMethodSelect
+    <table><tr><th>variant select (string query, bool async = false)</th></tr></table>
+    Runs a QSparqlQuery::SelectStatement, synchronous by default.
+
+    The function will return a list of results, see the section \ref usingResults "Using Results" for
+    result usage.
+
+    If the async parameter is set to true, the query will be executed asynchronously, and the function
+    will return 0. For asynchronous usage, see the section \ref asyncQueries "Asynchronous Queries".
+
+    <table><tr><th>variant select (string query, QVariantMap boundValues, bool async = false)</th></tr></table>
+    Overloaded method to allow for the replacing of placeholders in \a query with their corresponding values contained
+    in the hashmap \a boundValues. See \ref bindingValues "Binding Values".
+
+    \anchor qmlMethodAsk
+    <table><tr><th>bool ask (string query, bool async = false)</th></tr></table>
+    Runs a QSparqlQuery::AskStatement, synchronous by default, returning the bool value of the query.
+
+    <table><tr><th>bool ask (string query, QVariantMap boundValues, bool async = false)</th></tr></table>
+    Overloaded method to allow for the replacing of placeholders in \a query with their corresponding values contained
+    in the hashmap \a boundValues. See \ref bindingValues "Binding Values".
+
+    \anchor qmlMethodUpdate
+    <table><tr><th>variant update (string query, bool async = false)</th></tr></table>
+    Runs a QSparqlQuery::InsertStatement or QSparqlQuery::DeleteStatement. If there was an error with the
+    update query, -1 will be returned, otherwise an empty list will be returned.
+
+    <table><tr><th>variant update (string query, QVariantMap boundValues, bool async = false)</th></tr></table>
+    Overloaded method to allow for the replacing of placeholders in \a query with their corresponding values contained
+    in the hashmap \a boundValues. See \ref bindingValues "Binding Values".
+
+    \anchor qmlMethodConstruct
+    <table><tr><th>variant construct (string query, bool async = false)</th></tr></table>
+    Runs a QSparqlQuery::ConstructStatement returning the results, or -1 if there was an error.
+
+    <table><tr><th>variant construct (string query, QVariantMap boundValues, bool async = false)</th></tr></table>
+    Overloaded method to allow for the replacing of placeholders in \a query with their corresponding values contained
+    in the hashmap \a boundValues. See \ref bindingValues "Binding Values".
+
+    \anchor qmlMethodErrorString
+    <table><tr><th>string errorString ()</th></tr></table>
+    Returns a string description of the last error that occurred if status is SparqlConnection::Error
+
+    \section qmlDetatiled Detailed Description
+    \subsection basicUsage Basic Usage
+    The SparqlConnection binding can be used to issue SPARQL queries, and as a connection for the ListView model SparqlListModel.
+    To create a new connection :
+    \code
+    SparqlConnection {
+        id: connection
+        driver: "QTRACKER_DIRECT"
+    }
+    \endcode
+
+    The connection can then be used in javascript functions using the id "connection".
+
+    \subsection usingResults Using Results
+    Property names for results will be extracted from the query string that is used. For example, results for the query :
+    \code
+    select ?u ?ng ?nf { ?u a nco:PersonContact; nco:nameGiven ?ng; nco:nameFamily ?nf }
+    \endcode
+    Will have property names "u", "ng" and "nf". It is important to note that when using a function in the query, the property
+    name must be defined using the AS keyword. E.g :
+    \code
+    select ?u fn:string( (?nf, ?ng), ' ') AS ?joinedName { ... }
+    \endcode
+    Will return "u" and "joinedNamed" as the property names.
+
+    When using \ref qmlMethodSelect "select()" results will be returned as a list of "result rows" :
+    \code
+    var result = connection.select(query)
+    \endcode
+    It is easy to iterate through the results using its length property :
+    \code
+    for (var i=0; i<result.length; i++) {
+        var resultRow = result[i];
+        var nameGiven = resultRow["ng"]
+        // Alternatively the property name could be used
+        var nameGivenProperty = resultRow.ng;
+    }
+    \endcode
+
+    Alternatively, you can access result properties by looping through the property values, E.g :
+    \code
+    for (var i=0; i<result.length; i++) {
+        var resultRow = result[i];
+        for (var property in resultRow) {
+            console.log("property name = "+property)
+            console.log("property value = "+resultRow[property])
+        }
+    }
+    \endcode
+
+    \subsection asyncQueries Asynchronous Queries
+
+    Queries may also be executed asynchronously, and processed once they have been completed.
+    This is convenient if you intend to issue large queries with the connection, as any call to
+    \ref qmlMethodSelect "select()" or \ref qmlMethodUpdate "update()" will not block. This is done by setting the
+    async paramater to true for both \ref qmlMethodSelect "select()" and \ref qmlMethodUpdate "update()".
+
+    To issue a select query asynchronoulsy :
+    \code
+    connection.select(query, true);
+    \endcode
+
+    The result can be processed after the connections resultReady() signal has been emitted, E.g :
+    \code
+    SparqlConnection {
+        ...
+        onResultReady: resultFunction(result)
+    }
+
+    function resultFunction(result)
+    {
+        // check for an error
+        if (connection.status != SparqlConnection.Error) {
+            //process the results
+        }
+    }
+    \endcode
+
+    It is also possible to connect to the resultReady() signal directly in javascript, E.g :
+
+    \code
+    function asyncSelect() {
+        sparqlConnection.resultReady.connect(someFunction)
+        sparqlConnection.select(query, true)
+    }
+    \endcode
+
+    Please note: Synchronous calls to select() will also emit the resultReady signal, so if you intend to use
+    both asynchronous and synchronous queries you can process both using the onResultReady: property.
+
+    \subsection bindingValues Binding Values
+
+    The bindings support the QSparqlQuery feature of allowing query placeholders (marked with ?: or $:) to be replaced
+    with strings. This approach is preferable for \ref qmlMethodUpdate "update" queries as it provides protection
+    against SPARQL injection.
+
+    When using placeholders, a hash map containing the placeholder to value pairs must be included with any query execution,
+    E.g :
+
+    \code
+    var query = "insert { <newContact> a nco:PersonContact; nco:nameGiven ?:boundValue1; nco:nameFamily ?:boundValue2 . }"
+    var boundValues = { "boundValue1":"Joe", "boundValue2":"Chip" }
+    var result = sparqlConnection.update(query, boundValues);
+    \endcode
+*/
+
--- src/sparql/declarative/sparqllistmodeldoc.cpp
+++ src/sparql/declarative/sparqllistmodeldoc.cpp
+/*!
+    \page qmlSparqlListModel SparqlListModel
+    \brief Provides a QML binding for QSparqlQueryModel.
+
+    \code
+    import QtSparql 1.0
+    \endcode
+
+    \section qmlproperties Properties
+    \li \ref qmlPropertyQuery "query : string"
+    \li \ref qmlPropertyConnection "connection : SparqlConnection"
+    \li \ref qmlPropertyStatus "status : enumeration"
+    \li \ref qmlPropertyCount "count : int"
+
+    \section qmlmethods Methods
+    \li \ref qmlMethodGet "variant get"
+    \li \ref qmlMethodReload "void reload"
+    \li \ref qmlMethodErrorString "string errorString"
+
+    \section qmlPropertyDoc Property Documentation
+
+    Required properties are query and connection.
+
+    \anchor qmlPropertyQuery
+    <table><tr><th>query : string</th></tr></table>
+    Set the QSparqlQuery::SelectStatment to be used to populate the model
+
+    \anchor qmlPropertyConnection
+    <table><tr><th>connection : SparqlConnection</th></tr></table>
+    Set the \ref qmlSparqlConnection to be used for the model.
+
+    \anchor qmlPropertyStatus
+    <table><tr><th>status : enumeration \a read-only</th></tr></table>
+    Specifies the model status, which can be one of the following:
+        \li Null - Model has not been set.
+        \li Ready - Model is ready, and populated with results.
+        \li Loading - Model is executing the query.
+        \li Error - There was an error with the query or connection.
+
+    The status can be monitored using the statusChanged() signal.
+
+    \anchor qmlPropertyCount
+    <table><tr><th>count : int \a read-only</th></tr></table>
+    Returns the number of rows in the model. The countChanged() signal can be used
+    to notify of any insertions or deletions.
+
+    \section qmlMethodDoc Method Documentation
+
+    \anchor qmlMethodGet
+    <table><tr><th>variant get (int i)</th></tr></table>
+    Returns the result from row i. See \ref qmlDetatiled "Detailed Description" for usage.
+
+    \anchor qmlMethodReload
+    <table><tr><th>void reload ()</th></tr></table>
+    Executes the \ref qmlPropertyQuery "query" again. Useful if you wish to periodically
+    check for new results.
+
+    \anchor qmlMethodErrorString
+    <table><tr><th>string errorString ()</th></tr></table>
+    Returns a string description of the last error that occurred if status is SparqlListModel::Error.
+
+    \section qmlDetatiled Detailed Description
+    The SparqlListModel binding allows for SPARQL queries to be used as a ListView model.
+    The binding requires a \ref qmlSparqlConnection and a \ref qmlPropertyQuery "query" to be set, E.g :
+
+    \code
+    ListView {
+        id: contactView
+        model: SparqlListModel {
+                    id:resultList
+                    connection: SparqlConnection { driver:"QTRACKER_DIRECT" }
+                    query: "select ?u ?firstName ?secondName"+
+                           "{ ?u a nco:PersonContact;"+
+                           "nco:nameGiven ?firstName;"+
+                           "nco:nameFamily ?secondName .}"
+                }
+        delegate: Item { Text { text: "firstname = "+firstName+", secondname = "+secondName } }
+    }
+    \endcode
+
+    The delegates property names are extracted from the query, see the section "Using Results" in
+    \ref qmlSparqlConnection for more information on this.
+
+    If you intend to use the \ref qmlSparqlConnection for other queries, it may be more convenient to declare
+    it as a property, E.g :
+
+    \code
+    property SparqlConnection sparqlConnection : SparqlConnection {
+                                                    driver: "QTRACKER_DIRECT"
+                                                 }
+
+    ListView {
+        model: SparqlListModel {
+                connection: sparqlConnection
+                ...
+               }
+    }
+    \endcode
+
+    The \ref qmlPropertyCount "count" property can be used to return the number of rows in the model,
+    and to be notified of insertions/deletions by connecting to the countChanged() signal, E.g :
+
+    \code
+    SparqlListModel {
+        onCountChanged : someFunction()
+        ...
+    }
+    \endcode
+
+    To return result information for a specific row in the model, the \ref qmlMethodGet "get" function can
+    be used, E.g :
+
+    \code
+    SparqlListModel {
+        id:resultList
+        ...
+    }
+
+    function getRow(row)
+    {
+        var result = getRow(row)
+        for (var property in result) {
+            console.log("Property name = "+property)
+            console.log("Property value = "+result[property])
+        }
+    }
+    \endcode
+*/
--- src/sparql/drivers/drivers.pri
+++ src/sparql/drivers/drivers.pri
@@ -13,9 +13,18 @@
 }
 
 contains(sparql-drivers, tracker_direct) {
-    HEADERS +=      drivers/tracker_direct/qsparql_tracker_direct_p.h
-    SOURCES +=      drivers/tracker_direct/qsparql_tracker_direct.cpp
-    CONFIG += link_pkgconfig
+    HEADERS += drivers/tracker_direct/qsparql_tracker_direct_p.h \
+               drivers/tracker_direct/qsparql_tracker_direct_driver_p.h \
+               drivers/tracker_direct/qsparql_tracker_direct_result_p.h \
+               drivers/tracker_direct/qsparql_tracker_direct_select_result_p.h \
+               drivers/tracker_direct/qsparql_tracker_direct_sync_result_p.h \
+               drivers/tracker_direct/qsparql_tracker_direct_update_result_p.h
+    SOURCES += drivers/tracker_direct/qsparql_tracker_direct_driver_p.cpp \
+               drivers/tracker_direct/qsparql_tracker_direct_result_p.cpp \
+               drivers/tracker_direct/qsparql_tracker_direct_select_result_p.cpp \
+               drivers/tracker_direct/qsparql_tracker_direct_sync_result_p.cpp \
+               drivers/tracker_direct/qsparql_tracker_direct_update_result_p.cpp
+    CONFIG += no_keywords link_pkgconfig
     PKGCONFIG += tracker-sparql-0.10
     DEFINES += QT_SPARQL_TRACKER_DIRECT
 }
--- src/sparql/drivers/endpoint/qsparql_endpoint.cpp
+++ src/sparql/drivers/endpoint/qsparql_endpoint.cpp
@@ -136,13 +136,12 @@
 public:
     EndpointResultPrivate(EndpointResult *result, EndpointDriverPrivate *dpp)
     : reply(0), xml(0), parser(0), reader(0),
-        isFinished(false), loop(0), q(result), driverPrivate(dpp)
+        isFinished(false), loop(0), q(result), driverPrivate(dpp), noResults(false)
     {
     }
 
     ~EndpointResultPrivate()
     {
-        delete reply;
         delete xml;
         delete parser;
         delete reader;
@@ -160,6 +159,7 @@
     QXmlSimpleReader *reader;
     QVector<QSparqlResultRow> results;
     bool isFinished;
+    bool noResults;
     QEventLoop *loop;
     EndpointResult *q;
     EndpointDriverPrivate *driverPrivate;
@@ -209,38 +209,44 @@
     Q_UNUSED(namespaceURI);
     Q_UNUSED(localName);
 
-    if (qName == QLatin1String("sparql")) {
-    } else if (qName == QLatin1String("head")) {
-    } else if (qName == QLatin1String("variable")) {
-    } else if (qName == QLatin1String("results")) {
-    } else if (qName == QLatin1String("result")) {
-        d->results.append(resultRow);
-    } else if (qName == QLatin1String("binding")) {
-        resultRow.append(binding);
-    } else if (qName == QLatin1String("boolean")) {
-        d->setBoolValue(currentText.toLower() == QLatin1String("true"));
-    } else if (qName == QLatin1String("bnode")) {
-        currentText.replace(QRegExp(QString::fromLatin1("^nodeID://")), QString::fromLatin1(""));
-        currentText.replace(QRegExp(QString::fromLatin1("^_:")), QString::fromLatin1(""));
-        binding.setBlankNodeLabel(currentText);
-    } else if (qName == QLatin1String("uri")) {
-        QUrl url(currentText);
-        binding.setValue(QVariant(url));
-    } else if (qName == QLatin1String("literal")) {
-        if (lattrs.index(QString::fromLatin1("datatype")) != -1) {
-            if (lattrs.index(QString::fromLatin1("xsi:type")) != -1) {
-                // TODO: How should we treat xsi:types here?
-                binding.setValue(currentText, QUrl(lattrs.value(QString::fromLatin1("datatype"))));
+    if (!d->noResults) {
+        if (qName == QLatin1String("sparql")) {
+        } else if (qName == QLatin1String("head")) {
+        } else if (qName == QLatin1String("variable")) {
+        } else if (qName == QLatin1String("results")) {
+        } else if (qName == QLatin1String("result")) {
+            d->results.append(resultRow);
+        } else if (qName == QLatin1String("binding")) {
+            resultRow.append(binding);
+        } else if (qName == QLatin1String("boolean")) {
+            bool boolValue = currentText.toLower() == QLatin1String("true");
+            d->setBoolValue(boolValue);
+            binding.setValue(QVariant(boolValue));
+            resultRow.append(binding);
+            d->results.append(resultRow);
+        } else if (qName == QLatin1String("bnode")) {
+            currentText.replace(QRegExp(QString::fromLatin1("^nodeID://")), QString::fromLatin1(""));
+            currentText.replace(QRegExp(QString::fromLatin1("^_:")), QString::fromLatin1(""));
+            binding.setBlankNodeLabel(currentText);
+        } else if (qName == QLatin1String("uri")) {
+            QUrl url(currentText);
+            binding.setValue(QVariant(url));
+        } else if (qName == QLatin1String("literal")) {
+            if (lattrs.index(QString::fromLatin1("datatype")) != -1) {
+                if (lattrs.index(QString::fromLatin1("xsi:type")) != -1) {
+                    // TODO: How should we treat xsi:types here?
+                    binding.setValue(currentText, QUrl(lattrs.value(QString::fromLatin1("datatype"))));
+                } else {
+                    binding.setValue(currentText, QUrl(lattrs.value(QString::fromLatin1("datatype"))));
+                }
+            } else if (lattrs.index(QString::fromLatin1("xml:lang")) != -1) {
+                binding.setValue(QVariant(currentText));
+                binding.setLanguageTag(lattrs.value(QString::fromLatin1("xml:lang")));
             } else {
-                binding.setValue(currentText, QUrl(lattrs.value(QString::fromLatin1("datatype"))));
+                binding.setValue(QVariant(currentText));
             }
-        } else if (lattrs.index(QString::fromLatin1("xml:lang")) != -1) {
-            binding.setValue(QVariant(currentText));
-            binding.setLanguageTag(lattrs.value(QString::fromLatin1("xml:lang")));
         } else {
-            binding.setValue(QVariant(currentText));
         }
-    } else {
     }
 
     return true;
@@ -272,11 +278,11 @@
 
 void EndpointResultPrivate::handleError(QNetworkReply::NetworkError code)
 {
-    if (code == QNetworkReply::UnknownContentError)
-        q->setLastError(QSparqlError(QString::fromLatin1(buffer), QSparqlError::StatementError, code));
-    else
+    if (code != QNetworkReply::UnknownContentError) {
         q->setLastError(QSparqlError(reply->errorString(), QSparqlError::ConnectionError, code));
-
+        terminate();
+        qWarning() << "QEndpoint:" << q->lastError() << q->query();
+    }
     terminate();
 }
 
@@ -286,7 +292,7 @@
         return;
 
     isFinished = true;
-    q->emit finished();
+    q->Q_EMIT finished();
     
     if (loop != 0)
         loop->exit();
@@ -313,6 +319,7 @@
         if (!reader->parse(xml, true)) {
             q->setLastError(QSparqlError(xml->data(), QSparqlError::StatementError));
             terminate();
+            qWarning() << "QEndpoint:" << q->lastError() << q->query();
             return;
         }
     }
@@ -321,11 +328,12 @@
         if (!reader->parseContinue()) {
             q->setLastError(QSparqlError(xml->data(), QSparqlError::StatementError));
             terminate();
+            qWarning() << "QEndpoint:" << q->lastError() << q->query();
             return;
         }
     }
 
-    q->emit dataReady(results.count());
+    q->Q_EMIT dataReady(results.count());
 }
 
 void EndpointResultPrivate::parseResults()
@@ -360,7 +368,11 @@
 
 void EndpointResult::cleanup()
 {
-    setPos(QSparql::BeforeFirstRow);
+    // if we still have a network manager,
+    // delete the previous result here
+    if (d->driverPrivate)
+        delete d->reply;
+    d->reply = 0;
 }
 
 QSparqlBinding EndpointResult::binding(int field) const
@@ -405,8 +417,6 @@
 
 bool EndpointResult::exec(const QString& query, QSparqlQuery::StatementType type, const QString& prefixes)
 {
-    cleanup();
-
     QUrl queryUrl(d->driverPrivate->url);
     queryUrl.addQueryItem(QLatin1String("query"), prefixes + query);
     setQuery(query);
@@ -423,7 +433,7 @@
         queryUrl.addQueryItem(QLatin1String("maxrows"), maxrows.toString());
     }
 
-    qDebug() << "Real url to run.... " << queryUrl.toString();
+    // qDebug() << "Real url to run.... " << queryUrl.toString();
 
     d->buffer.clear();
     QNetworkRequest request(queryUrl);
@@ -443,6 +453,11 @@
     if (!isGraph())
         d->xml = new XmlInputSource(d->reply);
 
+    // We don't want to add any results if it's an insert or delete, however, we still need to parse them
+    // because there may be warnings that need to be printed
+    if (statementType() == QSparqlQuery::InsertStatement || statementType() == QSparqlQuery::DeleteStatement)
+        d->noResults = true;
+
     QObject::connect(d->reply, SIGNAL(readyRead()), d, SLOT(readData()));
     QObject::connect(d->reply, SIGNAL(finished()), d, SLOT(parseResults()));
     QObject::connect(d->reply, SIGNAL(error(QNetworkReply::NetworkError)), d, SLOT(handleError(QNetworkReply::NetworkError)));
@@ -497,8 +512,10 @@
 
 EndpointDriver::~EndpointDriver()
 {
-    if (d->managerOwned)
+    if (d->managerOwned) {
         delete d->manager;
+        d->managerOwned = false;
+    }
     delete d;
 }
 
@@ -564,6 +581,7 @@
 
 void EndpointDriver::close()
 {
+    Q_EMIT closing();
     if (isOpen()) {
         setOpen(false);
         setOpenError(false);
@@ -575,7 +593,23 @@
 
 EndpointResult* EndpointDriver::createResult() const
 {
-    return new EndpointResult(d);
+    EndpointResult *result = new EndpointResult(d);
+    QObject::connect(this, SIGNAL(closing()), result, SLOT(driverClosing()));
+    return result;
+}
+
+void EndpointResult::driverClosing()
+{
+    if (!isFinished()) {
+        setLastError(QSparqlError(
+                QString::fromUtf8("QSparqlConnection closed before QSparqlResult"),
+                QSparqlError::ConnectionError));
+    }
+    d->terminate();
+
+    d->driverPrivate = 0;
+
+    qWarning() << "QEndpointResult: QSparqlConnection closed before QSparqlResult with query:" << query();
 }
 
 QT_END_NAMESPACE
--- src/sparql/drivers/endpoint/qsparql_endpoint_p.h
+++ src/sparql/drivers/endpoint/qsparql_endpoint_p.h
@@ -84,6 +84,9 @@
 protected:
     void cleanup();
 
+private Q_SLOTS:
+    void driverClosing();
+
 private:
     EndpointResultPrivate* d;
 };
@@ -101,6 +104,9 @@
     EndpointResult* createResult() const;
     EndpointResult* exec(const QString& query, QSparqlQuery::StatementType type, const QSparqlQueryOptions& options);
 
+Q_SIGNALS:
+    void closing();
+
 private:
     EndpointDriverPrivate* d;
 };
--- src/sparql/drivers/tracker/qsparql_tracker.cpp
+++ src/sparql/drivers/tracker/qsparql_tracker.cpp
@@ -113,17 +113,17 @@
     Q_OBJECT
 public:
     QTrackerResultPrivate(QTrackerResult* res,
-                          QSparqlQuery::StatementType tp);
+                          QTrackerDriverPrivate* dp);
 
     ~QTrackerResultPrivate();
     QDBusPendingCallWatcher* watcher;
     QVector<QStringList> data;
-    QSparqlQuery::StatementType type;
+    QTrackerDriverPrivate* driverPrivate;
     void setCall(QDBusPendingCall& call);
     static TrackerSparqlError errorNameToCode(const QString& name);
     static QSparqlError::ErrorType errorCodeToType(TrackerSparqlError code);
 
-private slots:
+private Q_SLOTS:
     void onDBusCallFinished();
 private:
     QTrackerResult* q; // public part
@@ -140,8 +140,8 @@
 } // end of unnamed namespace
 
 QTrackerResultPrivate::QTrackerResultPrivate(QTrackerResult* res,
-                                             QSparqlQuery::StatementType tp)
-: watcher(0), type(tp), q(res)
+                                             QTrackerDriverPrivate* dp)
+: watcher(0), driverPrivate(dp), q(res)
 {
 }
 
@@ -208,9 +208,6 @@
 void QTrackerResultPrivate::onDBusCallFinished()
 {
     if (watcher->isError()) {
-        qWarning() << "Tracker driver error:" << watcher->error().message();
-        qWarning() << "The query was" << q->query();
-
         QSparqlError error(watcher->error().message());
         if (watcher->error().type() == QDBusError::Other) {
             TrackerSparqlError code = errorNameToCode(watcher->error().name());
@@ -223,27 +220,40 @@
         }
 
         q->setLastError(error);
-        emit q->finished();
+        qWarning() << "QTrackerResult:" << q->lastError() << q->query();
+        Q_EMIT q->finished();
         return;
     }
-    switch (type) {
+
+    switch (q->statementType()) {
+    case QSparqlQuery::AskStatement:
     case QSparqlQuery::SelectStatement:
     {
         QDBusPendingReply<QVector<QStringList> > reply = *watcher;
         data = reply.argumentAt<0>();
-        emit q->dataReady(data.size());
+
+        if (q->statementType() == QSparqlQuery::AskStatement && data.count() == 1 && data[0].count() == 1)
+        {
+            QVariant boolValue = data[0][0];
+            q->setBoolValue(boolValue.toBool());
+        }
+
+        Q_EMIT q->dataReady(data.size());
         break;
     }
     default:
         // TODO: handle update results here
         break;
     }
-    emit q->finished();
+    Q_EMIT q->finished();
 }
 
-QTrackerResult::QTrackerResult(QSparqlQuery::StatementType tp)
+QTrackerResult::QTrackerResult(const QString& query, QSparqlQuery::StatementType tp, QTrackerDriver* driver)
 {
-    d = new QTrackerResultPrivate(this, tp);
+    setQuery(query);
+    setStatementType(tp);
+    d = new QTrackerResultPrivate(this, driver->d);
+    connect(driver, SIGNAL(closing()), this, SLOT(driverClosing()), Qt::DirectConnection);
 }
 
 QTrackerResult::~QTrackerResult()
@@ -251,48 +261,6 @@
     delete d;
 }
 
-QTrackerResult* QTrackerDriver::exec(const QString& query,
-                          QSparqlQuery::StatementType type,
-                          const QSparqlQueryOptions& options)
-{
-    if (options.executionMethod() == QSparqlQueryOptions::SyncExec)
-        return 0;
-
-    QTrackerResult* res = new QTrackerResult(type);
-    res->setQuery(query);
-
-    QString funcToCall;
-    switch (type) {
-    case QSparqlQuery::SelectStatement:
-    {
-        funcToCall = QString::fromLatin1("SparqlQuery");
-        break;
-    }
-    case QSparqlQuery::InsertStatement: // fall-through
-    case QSparqlQuery::DeleteStatement:
-    {
-        if (d->doBatch || options.priority() == QSparqlQueryOptions::LowPriority) {
-            funcToCall = QString::fromLatin1("BatchSparqlUpdate");
-        }
-        else {
-            funcToCall = QString::fromLatin1("SparqlUpdateBlank");
-        }
-        break;
-    }
-    default:
-        qWarning() << "Tracker backend: non-supported statement";
-        res->setLastError(QSparqlError(
-                              QLatin1String("Non-supported statement type"),
-                              QSparqlError::BackendError));
-        return res;
-        break;
-    }
-    QDBusPendingCall call = d->iface->asyncCall(funcToCall,
-                                                QVariant(query));
-    res->d->setCall(call);
-    return res;
-}
-
 QSparqlBinding QTrackerResult::binding(int field) const
 {
     if (!isValid()) {
@@ -354,7 +322,7 @@
         return info;
 
     QStringList resultStrings = d->data[pos()];
-    foreach (const QString& str, resultStrings) {
+    Q_FOREACH (const QString& str, resultStrings) {
         // This only creates a binding with the values but with empty column
         // names.
         // TODO: how to add column names?
@@ -364,6 +332,64 @@
     return info;
 }
 
+bool QTrackerResult::hasFeature(QSparqlResult::Feature feature) const
+{
+    switch (feature) {
+        case QSparqlResult::Sync:
+        case QSparqlResult::ForwardOnly:
+            return false;
+        case QSparqlResult::QuerySize:
+            return true;
+        default:
+            return false;
+    }
+}
+
+void QTrackerResult::exec(const QSparqlQueryOptions& options)
+{
+    QString funcToCall;
+    switch (statementType()) {
+    case QSparqlQuery::AskStatement:
+    case QSparqlQuery::SelectStatement:
+    {
+        funcToCall = QString::fromLatin1("SparqlQuery");
+        break;
+    }
+    case QSparqlQuery::InsertStatement: // fall-through
+    case QSparqlQuery::DeleteStatement:
+    {
+        if (d->driverPrivate->doBatch || options.priority() == QSparqlQueryOptions::LowPriority) {
+            funcToCall = QString::fromLatin1("BatchSparqlUpdate");
+        }
+        else {
+            funcToCall = QString::fromLatin1("SparqlUpdateBlank");
+        }
+        break;
+    }
+    default:
+        setLastError(QSparqlError(
+                QLatin1String("Non-supported statement type"),
+                QSparqlError::BackendError));
+        qWarning() << "QTrackerResult:" << lastError() << query();
+        return;
+    }
+    QDBusPendingCall call = d->driverPrivate->iface->asyncCall(funcToCall,
+                                                QVariant(query()));
+    d->setCall(call);
+}
+
+void QTrackerResult::driverClosing()
+{
+    if (!isFinished()) {
+        setLastError(QSparqlError(
+                QString::fromUtf8("QSparqlConnection closed before QSparqlResult"),
+                QSparqlError::ConnectionError));
+    }
+    delete d->watcher;
+    d->watcher = 0;
+    qWarning() << "QTrackerResult: QSparqlConnection closed before QSparqlResult with query:" << query();
+}
+
 QTrackerDriverPrivate::QTrackerDriverPrivate()
     : iface(0),  doBatch(false)
 {
@@ -442,6 +468,7 @@
 void QTrackerDriver::close()
 {
     if (isOpen()) {
+        Q_EMIT closing();
         delete d->iface;
         d->iface = 0;
         setOpen(false);
@@ -449,6 +476,19 @@
     }
 }
 
+QTrackerResult* QTrackerDriver::exec(const QString& query,
+                          QSparqlQuery::StatementType type,
+                          const QSparqlQueryOptions& options)
+{
+    if (options.executionMethod() == QSparqlQueryOptions::SyncExec)
+        return 0;
+    QString query_with_prefixes(query);
+    query_with_prefixes.prepend(prefixes());
+    QTrackerResult* res = new QTrackerResult(query_with_prefixes, type, this);
+    res->exec(options);
+    return res;
+}
+
 QT_END_NAMESPACE
 
 #include "qsparql_tracker.moc"
--- src/sparql/drivers/tracker/qsparql_tracker_p.h
+++ src/sparql/drivers/tracker/qsparql_tracker_p.h
@@ -67,10 +67,9 @@
 class Q_EXPORT_SPARQLDRIVER_TRACKER QTrackerResult : public QSparqlResult
 {
     Q_OBJECT
-    friend class QTrackerDriver;
     friend class QTrackerResultPrivate; // for emitting signals
 public:
-    explicit QTrackerResult(QSparqlQuery::StatementType type);
+    explicit QTrackerResult(const QString& query, QSparqlQuery::StatementType type, QTrackerDriver* driver);
     ~QTrackerResult();
 
     // Implementation of the QSparqlResult interface
@@ -80,6 +79,13 @@
     virtual QSparqlResultRow current() const;
     virtual QSparqlBinding binding(int i) const;
     virtual QVariant value(int i) const;
+    virtual bool hasFeature(QSparqlResult::Feature feature) const;
+
+public:
+    void exec(const QSparqlQueryOptions& options);
+
+private Q_SLOTS:
+    void driverClosing();
 
 protected:
     int size() const;
@@ -91,6 +97,7 @@
 class Q_EXPORT_SPARQLDRIVER_TRACKER QTrackerDriver : public QSparqlDriver
 {
     Q_OBJECT
+    friend class QTrackerResult;
 public:
     explicit QTrackerDriver(QObject *parent=0);
     ~QTrackerDriver();
@@ -102,6 +109,9 @@
     QTrackerResult* exec(const QString& query,
                          QSparqlQuery::StatementType type,
                          const QSparqlQueryOptions& options);
+Q_SIGNALS:
+    void closing();
+
 private:
     QTrackerDriverPrivate* d;
 };
--- src/sparql/drivers/tracker_direct/qsparql_tracker_direct_driver_p.cpp
+++ src/sparql/drivers/tracker_direct/qsparql_tracker_direct_driver_p.cpp
@@ -37,23 +37,23 @@
 **
 ****************************************************************************/
 
+#include "qsparql_tracker_direct_p.h"
 #include "qsparql_tracker_direct_driver_p.h"
-#include "qsparql_tracker_direct_result_p.h"
+#include "qsparql_tracker_direct_select_result_p.h"
 #include "qsparql_tracker_direct_sync_result_p.h"
 #include "qsparql_tracker_direct_update_result_p.h"
 
 #include <qsparqlconnection.h>
 
 #include <QtCore/qdatetime.h>
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qeventloop.h>
 
 #include <QtCore/qdebug.h>
 #include <QtCore/qmetaobject.h>
+#include <QtCore/qsemaphore.h>
 
 QT_BEGIN_NAMESPACE
 
-// Helper functions used both by QTrackerDirectResult and
+// Helper functions used both by QTrackerDirectSelectResult and
 // QTrackerDirectSyncResult
 
 namespace {
@@ -156,6 +156,8 @@
 gint qSparqlPriorityToGlib(QSparqlQueryOptions::Priority priority)
 {
     switch (priority) {
+    case QSparqlQueryOptions::HighPriority:
+        return G_PRIORITY_HIGH;
     case QSparqlQueryOptions::LowPriority:
         return G_PRIORITY_LOW;
     case QSparqlQueryOptions::NormalPriority:
@@ -164,36 +166,108 @@
     }
 }
 
-////////////////////////////////////////////////////////////////////////////
+struct QTrackerDirectDriverConnectionData
+{
+    QTrackerDirectDriverConnectionData() : error(0), connection(0) { }
+
+    QTrackerDirectDriverConnectionData take()
+    {
+        QTrackerDirectDriverConnectionData result(*this);
+        this->error = 0;
+        this->connection = 0;
+        return result;
+    }
 
-static void
-async_open_callback(GObject         * /*source_object*/,
-                    GAsyncResult    *result,
-                    gpointer         user_data)
+    GError *error;
+    TrackerSparqlConnection *connection;
+};
+
+////////////////////////////////////////////////////////////////////////////
+class QTrackerDirectDriverConnectionOpen : public QObject, public QRunnable
 {
-    QTrackerDirectDriverPrivate *d = static_cast<QTrackerDirectDriverPrivate*>(user_data);
-    d->asyncOpenComplete(result);
-}
+    Q_OBJECT
+public:
+    QTrackerDirectDriverConnectionOpen()
+        : runSemaphore(1), runFinished(0)
+    {
+        setAutoDelete(false);
+    }
+
+    QTrackerDirectDriverConnectionData takeConnection()
+    {
+        return cd.take();
+    }
+
+    void runOrWait()
+    {
+        if (acquireRunSemaphore())
+        {
+            if (!runFinished)
+                run();
+            else
+                runSemaphore.release(1);
+        }
+        else
+            wait();
+    }
+
+    void queue(QThreadPool& threadPool)
+    {
+        if (acquireRunSemaphore())
+            threadPool.start(this);
+    }
+
+Q_SIGNALS:
+    void connectionOpened();
+
+private:
+    QTrackerDirectDriverConnectionData cd;
+    QSemaphore runSemaphore;
+    bool runFinished;
+
+    void run()
+    {
+        if (!runFinished) {
+            cd.connection = tracker_sparql_connection_get(0, &cd.error);
+            Q_EMIT connectionOpened();
+            runFinished = true;
+        }
+        runSemaphore.release(1);
+    }
+
+    void wait()
+    {
+        runSemaphore.acquire(1);
+        runSemaphore.release(1);
+    }
+
+    bool acquireRunSemaphore()
+    {
+        return runSemaphore.tryAcquire(1);
+    }
+};
 
 QTrackerDirectDriverPrivate::QTrackerDirectDriverPrivate(QTrackerDirectDriver *driver)
     : connection(0), dataReadyInterval(1), connectionMutex(QMutex::Recursive), driver(driver),
-      asyncOpenCalled(false)
+      asyncOpenCalled(false), connectionOpener(new QTrackerDirectDriverConnectionOpen)
 {
+    QObject::connect(connectionOpener, SIGNAL(connectionOpened()), this, SLOT(asyncOpenComplete()));
 }
 
 QTrackerDirectDriverPrivate::~QTrackerDirectDriverPrivate()
 {
+    delete connectionOpener;
 }
 
-void QTrackerDirectDriverPrivate::asyncOpenComplete(GAsyncResult *result)
+void QTrackerDirectDriverPrivate::asyncOpenComplete()
 {
-    if (!connection) {
-        GError * error = 0;
-        connection = tracker_sparql_connection_get_finish(result, &error);
-        checkConnectionError(connection, error);
+    if (connection == 0) {
+        QTrackerDirectDriverConnectionData cd = connectionOpener->takeConnection();
+        connection = cd.connection;
+        checkConnectionError(connection, cd.error);
+        asyncOpenCalled = true;
+        Q_EMIT driver->opened();
     }
-    asyncOpenCalled = true;
-    Q_EMIT driver->opened();
 }
 
 void QTrackerDirectDriverPrivate::checkConnectionError(TrackerSparqlConnection *conn, GError* gerr)
@@ -211,21 +285,6 @@
     }
 }
 
-void QTrackerDirectDriverPrivate::addActiveResult(QTrackerDirectResult* result)
-{
-    for (QList<QPointer<QTrackerDirectResult> >::iterator it = activeResults.begin();
-            it != activeResults.end(); ++it) {
-        if (it->isNull()) {
-            // Replace entry for deleted result if one is found. This is done
-            // to avoid the activeResults list from growing indefinitely.
-            *it = result;
-            return;
-        }
-    }
-    // No deleted result found, append new one
-    activeResults.append(result);
-}
-
 void QTrackerDirectDriverPrivate::onConnectionOpen(QObject* object, const char* method, const char* slot)
 {
     if (connection || asyncOpenCalled) {
@@ -238,26 +297,13 @@
 
 void QTrackerDirectDriverPrivate::waitForConnectionOpen()
 {
-    if (!asyncOpenCalled) {
-        if (QCoreApplication::instance()) {
-            QEventLoop loop;
-            QObject::connect(driver, SIGNAL(opened()), &loop, SLOT(quit()));
-            loop.exec();
-        }
-        else {
-            qWarning() << "QTRACKER_DIRECT: QCoreApplication instance not found: cannot wait for asynchronous connection open";
-        }
-    }
+    connectionOpener->runOrWait();
+    asyncOpenComplete();
 }
 
-void QTrackerDirectDriverPrivate::openConnectionSync()
+void QTrackerDirectDriverPrivate::openConnection()
 {
-
-    if (!asyncOpenCalled && !connection) {
-        GError* error = 0;
-        this->connection = tracker_sparql_connection_get(0, &error);
-        checkConnectionError(this->connection, error);
-    }
+    connectionOpener->queue(threadPool);
 }
 
 QTrackerDirectDriver::QTrackerDirectDriver(QObject* parent)
@@ -301,7 +347,6 @@
     if (isOpen())
         close();
 
-    tracker_sparql_connection_get_async(0, async_open_callback, static_cast<gpointer>(d));
     setOpen(true);
     setOpenError(false);
 
@@ -321,25 +366,26 @@
         d->threadPool.setMaxThreadCount(maxThreads);
     }
 
+    //Now start a thread to open the connection
+    d->openConnection();
+
     return true;
 }
 
 void QTrackerDirectDriver::close()
 {
-    Q_FOREACH(QPointer<QTrackerDirectResult> result, d->activeResults) {
-        if (!result.isNull()) {
-            qWarning() << "QSparqlConnection closed before QSparqlResult with query:" <<
-                result->query();
-            disconnect(this, SIGNAL(opened()), result.data(), SLOT(exec()));
-            result->stopAndWait();
-        }
-    }
-    d->activeResults.clear();
+    Q_EMIT closing();
+
+    // We no longer want to emit any signals, since the driver is
+    // closing, so block all signals to prevent any exec methods being
+    // called
+    blockSignals(true);
+
     QMutexLocker connectionLocker(&(d->connectionMutex));
 
-    // Need to wait for the connection to open because there is no good way
-    // to cancel it synchronously
+    // We just check to see if we can get a semaphore here
     d->waitForConnectionOpen();
+
     if (d->connection) {
         g_object_unref(d->connection);
         d->connection = 0;
@@ -354,13 +400,14 @@
 QSparqlResult* QTrackerDirectDriver::exec(const QString &query, QSparqlQuery::StatementType type, const QSparqlQueryOptions& options)
 {
     QSparqlResult* result = 0;
-
+    QString query_with_prefixes(query);
+    query_with_prefixes.prepend(prefixes());
     switch (options.executionMethod()) {
     case QSparqlQueryOptions::AsyncExec:
-        result = asyncExec(query, type, options);
+        result = asyncExec(query_with_prefixes, type, options);
         break;
     case QSparqlQueryOptions::SyncExec:
-        result = syncExec(query, type, options);
+        result = syncExec(query_with_prefixes, type, options);
         break;
     }
 
@@ -369,33 +416,30 @@
 
 QSparqlResult* QTrackerDirectDriver::asyncExec(const QString &query, QSparqlQuery::StatementType type, const QSparqlQueryOptions& options)
 {
+    QTrackerDirectResult *result = 0;
     if (type == QSparqlQuery::AskStatement || type == QSparqlQuery::SelectStatement) {
-        QTrackerDirectResult *result = new QTrackerDirectResult(d, query, type);
-        d->addActiveResult(result);
-        d->onConnectionOpen(result, "exec", SLOT(exec()));
-        return result;
+        if (options.isForwardOnly())
+            result = new QTrackerDirectSyncResult(d, query, type, options);
+        else
+            result = new QTrackerDirectSelectResult(d, query, type, options);
     } else {
-        QTrackerDirectUpdateResult *result = new QTrackerDirectUpdateResult(d, query, type, options);
-        d->onConnectionOpen(result, "exec", SLOT(exec()));
-        return result;
+        result = new QTrackerDirectUpdateResult(d, query, type, options);
     }
+    connect(this, SIGNAL(closing()), result, SLOT(driverClosing()), Qt::DirectConnection);
+    d->onConnectionOpen(result, "exec", SLOT(exec()));
+    return result;
 }
 
 QSparqlResult* QTrackerDirectDriver::syncExec
         (const QString& query, QSparqlQuery::StatementType type, const QSparqlQueryOptions& options)
 {
-    QTrackerDirectSyncResult* result = new QTrackerDirectSyncResult(d, options);
-    result->setQuery(query);
-    result->setStatementType(type);
-    if (type == QSparqlQuery::AskStatement || type == QSparqlQuery::SelectStatement) {
-        d->openConnectionSync();
-        result->exec();
-    } else if (type == QSparqlQuery::InsertStatement || type == QSparqlQuery::DeleteStatement) {
-        d->openConnectionSync();
-        result->update();
-    }
-
+    QTrackerDirectResult* result = new QTrackerDirectSyncResult(d, query, type, options);
+    connect(this, SIGNAL(closing()), result, SLOT(driverClosing()), Qt::DirectConnection);
+    d->waitForConnectionOpen();
+    result->exec();
     return result;
 }
 
 QT_END_NAMESPACE
+
+#include "qsparql_tracker_direct_driver_p.moc"
--- src/sparql/drivers/tracker_direct/qsparql_tracker_direct_driver_p.h
+++ src/sparql/drivers/tracker_direct/qsparql_tracker_direct_driver_p.h
@@ -42,73 +42,30 @@
 
 #include <tracker-sparql.h>
 
-#include <QtSparql/private/qsparqldriver_p.h>
-#include <QtSparql/qsparqlquery.h>
 #include <QtSparql/qsparqlqueryoptions.h>
 #include <QtSparql/qsparqlerror.h>
 
-#include <QtCore/qlist.h>
-#include <QtCore/qpointer.h>
 #include <QtCore/qmutex.h>
-#include <QThreadPool>
-
-class QSparqlResult;
-
-#ifdef QT_PLUGIN
-#define Q_EXPORT_SPARQLDRIVER_TRACKER_DIRECT
-#else
-#define Q_EXPORT_SPARQLDRIVER_TRACKER_DIRECT Q_SPARQL_EXPORT
-#endif
+#include <QtCore/qthreadpool.h>
 
 QT_BEGIN_HEADER
 
 QT_BEGIN_NAMESPACE
 
-class QTrackerDirectDriverPrivate;
 class QTrackerDirectDriver;
-class QTrackerDirectResult;
+class QTrackerDirectSelectResult;
+class QTrackerDirectDriverConnectionOpen;
 
-class Q_EXPORT_SPARQLDRIVER_TRACKER_DIRECT QTrackerDirectDriver : public QSparqlDriver
+class QTrackerDirectDriverPrivate : public QObject
 {
     Q_OBJECT
 public:
-    explicit QTrackerDirectDriver(QObject *parent=0);
-    ~QTrackerDirectDriver();
-
-    // Implementation of the QSparqlDriver interface
-    bool hasFeature(QSparqlConnection::Feature f) const;
-    bool open(const QSparqlConnectionOptions& options);
-    void close();
-    QSparqlResult* exec(const QString& query,
-                         QSparqlQuery::StatementType type,
-                         const QSparqlQueryOptions& options);
-
-Q_SIGNALS:
-    void opened();
-
-private:
-    QSparqlResult* asyncExec(const QString& query,
-                            QSparqlQuery::StatementType type,
-                            const QSparqlQueryOptions& options);
-    QSparqlResult* syncExec(const QString& query,
-                            QSparqlQuery::StatementType type,
-                            const QSparqlQueryOptions& options);
-
-private:
-    friend class QTrackerDirectDriverPrivate;
-    QTrackerDirectDriverPrivate* d;
-};
-
-class QTrackerDirectDriverPrivate {
-public:
     QTrackerDirectDriverPrivate(QTrackerDirectDriver *driver);
     ~QTrackerDirectDriverPrivate();
 
-    void asyncOpenComplete(GAsyncResult* result);
-    void addActiveResult(QTrackerDirectResult* result);
     void onConnectionOpen(QObject* object,  const char* method, const char* slot);
     void waitForConnectionOpen();
-    void openConnectionSync();
+    void openConnection();
 
     TrackerSparqlConnection *connection;
     int dataReadyInterval;
@@ -119,13 +76,17 @@
     QMutex connectionMutex;
     QTrackerDirectDriver *driver;
     QString error;
-    QList<QPointer<QTrackerDirectResult> > activeResults;
+    bool asyncOpenCalled;
 
     QThreadPool threadPool;
 
+private Q_SLOTS:
+    void asyncOpenComplete();
+
 private:
-    bool asyncOpenCalled;
+    friend class QTrackerDirectDriverConnectionOpen;
     void checkConnectionError(TrackerSparqlConnection *conn, GError* gerr);
+    QTrackerDirectDriverConnectionOpen *connectionOpener;
 };
 
 QVariant readVariant(TrackerSparqlCursor* cursor, int col);
--- src/sparql/drivers/tracker_direct/qsparql_tracker_direct_p.h
+++ src/sparql/drivers/tracker_direct/qsparql_tracker_direct_p.h
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (ivan.frade at nokia.com)
+**
+** This file is part of the QtSparql module (not yet part of the Qt Toolkit).
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at ivan.frade at nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSPARQL_TRACKER_DIRECT_H
+#define QSPARQL_TRACKER_DIRECT_H
+
+#include <QtSparql/private/qsparqldriver_p.h>
+
+#ifdef QT_PLUGIN
+#define Q_EXPORT_SPARQLDRIVER_TRACKER_DIRECT
+#else
+#define Q_EXPORT_SPARQLDRIVER_TRACKER_DIRECT Q_SPARQL_EXPORT
+#endif
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QTrackerDirectDriverPrivate;
+
+class Q_EXPORT_SPARQLDRIVER_TRACKER_DIRECT QTrackerDirectDriver : public QSparqlDriver
+{
+    Q_OBJECT
+public:
+    explicit QTrackerDirectDriver(QObject *parent=0);
+    ~QTrackerDirectDriver();
+
+    // Implementation of the QSparqlDriver interface
+    bool hasFeature(QSparqlConnection::Feature f) const;
+    bool open(const QSparqlConnectionOptions& options);
+    void close();
+    QSparqlResult* exec(const QString& query,
+                         QSparqlQuery::StatementType type,
+                         const QSparqlQueryOptions& options);
+
+Q_SIGNALS:
+    void opened();
+    void closing();
+
+private:
+    QSparqlResult* asyncExec(const QString& query,
+                            QSparqlQuery::StatementType type,
+                            const QSparqlQueryOptions& options);
+    QSparqlResult* syncExec(const QString& query,
+                            QSparqlQuery::StatementType type,
+                            const QSparqlQueryOptions& options);
+
+private:
+    friend class QTrackerDirectDriverPrivate;
+    QTrackerDirectDriverPrivate* d;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSPARQL_TRACKER_DIRECT_DRIVER_P_H
--- src/sparql/drivers/tracker_direct/qsparql_tracker_direct_result_p.cpp
+++ src/sparql/drivers/tracker_direct/qsparql_tracker_direct_result_p.cpp
@@ -38,415 +38,87 @@
 ****************************************************************************/
 
 #include "qsparql_tracker_direct_result_p.h"
-#include "qsparql_tracker_direct_driver_p.h"
-
-#include <qsparqlerror.h>
-#include <qsparqlbinding.h>
-#include <qsparqlquery.h>
-#include <qsparqlresultrow.h>
-#define XSD_INTEGER
-#include "../../kernel/qsparqlxsd_p.h"
-
-#include <QtCore/qvariant.h>
-#include <QtCore/qvector.h>
-#include <QtCore/qpointer.h>
-#include <QtCore/qthread.h>
-#include <QtCore/qmutex.h>
-#include <QtCore/qsemaphore.h>
-#include <QtCore/qeventloop.h>
-
+#include <QtSparql/qsparqlerror.h>
 #include <QtCore/qdebug.h>
 
-QT_BEGIN_NAMESPACE
-
-////////////////////////////////////////////////////////////////////////////
-// FIXME: refactor QTrackerDirectResult to use QTrackerDirectSyncResult +
-// sync->async wrapper.
-
-class QTrackerDirectFetcherPrivate : public QRunnable
-{
-public:
-    QTrackerDirectFetcherPrivate(QTrackerDirectResult *res) : result(res), runFinished(0), runSemaphore(1) { setAutoDelete(false); }
-
-    void runOrWait()
-    {
-        if(acquireRunSemaphore())
-            run();
-        else
-            wait();
-    }
-
-    void queue(QThreadPool& threadPool)
-    {
-        if(acquireRunSemaphore())
-            threadPool.start(this);
-    }
-
-    void wait()
-    {
-        //if something has has acquired the semaphore (eg the fetcher thread)
-        //this will block until it is released in run
-        runSemaphore.acquire(1);
-        runSemaphore.release(1);
-    }
-
-private:
-    QTrackerDirectResult *result;
-    QAtomicInt runFinished;
-    QSemaphore runSemaphore;
-
-    void run()
-    {
-        //check to make sure we are not going to do this twice
-        if(!runFinished)
-        {
-            if(result->runQuery()) {
-                if (result->isTable()) {
-                    while (!result->isFinished() && result->fetchNextResult()) {
-                        ;
-                    }
-                } else if (result->isBool()) {
-                    result->fetchBoolResult();
-                } else {
-                    result->terminate();
-                }
-            }
-        }
-        runFinished=1;
-        runSemaphore.release(1);
-    }
-
-    bool acquireRunSemaphore()
-    {
-        return runSemaphore.tryAcquire(1);
-    }
-
-};
-
-class QTrackerDirectResultPrivate : public QObject {
-    Q_OBJECT
-public:
-    QTrackerDirectResultPrivate(QTrackerDirectResult* result, QTrackerDirectDriverPrivate *dpp, QTrackerDirectFetcherPrivate *f);
-
-    ~QTrackerDirectResultPrivate();
-    void terminate();
-    void setBoolValue(bool v);
-    void dataReady(int totalCount);
-
-    TrackerSparqlCursor* cursor;
-    QVector<QString> columnNames;
-    QList<QVector<QVariant> > results;
-    QAtomicInt isFinished;
-
-    QTrackerDirectResult* q;
-    QTrackerDirectDriverPrivate *driverPrivate;
-    QTrackerDirectFetcherPrivate *fetcher;
-    bool fetcherStarted;
-    // This mutex is for ensuring that only one thread at a time is accessing
-    // the member variables of this class (mainly: "results").
-    // Note that only the fetcher thread accesses the 'cursor', and so that
-    // is protected by the connectionMutex in the driver, not this mutex.
-    QMutex resultMutex;
-};
-
-QTrackerDirectResultPrivate::QTrackerDirectResultPrivate(   QTrackerDirectResult* result,
-                                                            QTrackerDirectDriverPrivate *dpp,
-                                                            QTrackerDirectFetcherPrivate *f)
-  : cursor(0),
-  q(result), driverPrivate(dpp), fetcher(f), fetcherStarted(false),
-  resultMutex(QMutex::Recursive)
-{
-}
-
-QTrackerDirectResultPrivate::~QTrackerDirectResultPrivate()
+// Query Runner Implementation
+QTrackerDirectQueryRunner::QTrackerDirectQueryRunner(QTrackerDirectResult *result)
+  : result(result), runFinished(0), runSemaphore(1), started(false)
 {
-    if (cursor)
-        g_object_unref(cursor);
+    setAutoDelete(false);
 }
 
-void QTrackerDirectResultPrivate::terminate()
+void QTrackerDirectQueryRunner::runOrWait()
 {
-    QMutexLocker resultLocker(&resultMutex);
-
-    if (results.count() % driverPrivate->dataReadyInterval != 0) {
-        dataReady(results.count());
-    }
-
-    isFinished = 1;
-    q->Q_EMIT finished();
-    if (cursor) {
-        g_object_unref(cursor);
-        cursor = 0;
+    if(acquireRunSemaphore()) {
+        if (!runFinished)
+            run();
+        else
+            runSemaphore.release(1);
+    } else {
+        wait();
     }
 }
 
-void QTrackerDirectResultPrivate::setBoolValue(bool v)
-{
-    q->setBoolValue(v);
-}
-
-void QTrackerDirectResultPrivate::dataReady(int totalCount)
+void QTrackerDirectQueryRunner::queue(QThreadPool& threadPool)
 {
-    Q_EMIT q->dataReady(totalCount);
-}
-
-////////////////////////////////////////////////////////////////////////////
-
-QTrackerDirectResult::QTrackerDirectResult(QTrackerDirectDriverPrivate* p,
-                                           const QString& query,
-                                           QSparqlQuery::StatementType type)
-{
-    setQuery(query);
-    setStatementType(type);
-    d = new QTrackerDirectResultPrivate(this, p, new QTrackerDirectFetcherPrivate(this));
-}
-
-QTrackerDirectResult::~QTrackerDirectResult()
-{
-    stopAndWait();
-    delete d;
-}
-
-void QTrackerDirectResult::exec()
-{
-    if (!d->driverPrivate->driver->isOpen()) {
-        setLastError(QSparqlError(d->driverPrivate->error,
-                                  QSparqlError::ConnectionError));
-        d->terminate();
-        return;
+    if(acquireRunSemaphore()) {
+        // QSparqlQueryPriority's are the wrong way round for
+        // the thread pool, so just * -1 to get the correct
+        // number
+        int priority = result->options.priority() * -1;
+        threadPool.start(this, priority);
     }
-
-    // Queue calling exec() on the result. This way the finished() and
-    // dataReady() signals won't be emitted before the user connects to
-    // them, and the result won't be in the "finished" state before the
-    // thread that calls this function has entered its event loop.
-    QMetaObject::invokeMethod(this, "startFetcher",  Qt::QueuedConnection);
 }
 
-void QTrackerDirectResult::startFetcher()
+void QTrackerDirectQueryRunner::wait()
 {
-    QMutexLocker resultLocker(&(d->resultMutex));
-    if (d->fetcher && !d->fetcherStarted && !isFinished()) {
-        d->fetcherStarted = true;
-        //first attempt to acquire the semaphore, if we can, then add the
-        //fetcher to the threadPool queue, if we can't then waitForFinished
-        //has it, so we don't need to refetch the results using this thread
-        d->fetcher->queue(d->driverPrivate->threadPool);
-    }
+    //if something has has acquired the semaphore (eg the fetcher thread)
+    //this will block until it is released in run
+    runSemaphore.acquire(1);
+    runSemaphore.release(1);
 }
 
-bool QTrackerDirectResult::runQuery()
+void QTrackerDirectQueryRunner::run()
 {
-    if (isFinished())
-        return false;
-
-    QMutexLocker connectionLocker(&(d->driverPrivate->connectionMutex));
-
-    GError * error = 0;
-    d->cursor = tracker_sparql_connection_query(    d->driverPrivate->connection,
-                                                    query().toUtf8().constData(),
-                                                    0,
-                                                    &error );
-    if (error || !d->cursor) {
-        QMutexLocker resultLocker(&(d->resultMutex));
-        setLastError(QSparqlError(QString::fromUtf8(error ? error->message : "unknown error"),
-                        QSparqlError::StatementError,
-                        error ? error->code : -1));
-        if (error)
-            g_error_free(error);
-        qWarning() << "QTrackerDirectResult:" << lastError() << query();
-        terminate();
-        return false;
+    if (!runFinished) {
+        result->run();
     }
-
-    return true;
+    runFinished=1;
+    runSemaphore.release(1);
 }
 
-bool QTrackerDirectResult::fetchNextResult()
+bool QTrackerDirectQueryRunner::acquireRunSemaphore()
 {
-    QMutexLocker connectionLocker(&(d->driverPrivate->connectionMutex));
-
-    GError * error = 0;
-    gboolean active = tracker_sparql_cursor_next(d->cursor, 0, &error);
-
-    if (error) {
-        setLastError(QSparqlError(QString::fromUtf8(error->message),
-                       errorCodeToType(error->code),
-                       error->code));
-        g_error_free(error);
-        qWarning() << "QTrackerDirectResult:" << lastError() << query();
-        terminate();
-        return false;
-    }
-
-    if (!active) {
-        terminate();
-        return false;
-    }
-
-    QMutexLocker resultLocker(&(d->resultMutex));
-
-    const gint n_columns = tracker_sparql_cursor_get_n_columns(d->cursor);
-
-    if (d->columnNames.empty()) {
-        for (int i = 0; i < n_columns; i++) {
-            d->columnNames.append(QString::fromUtf8(tracker_sparql_cursor_get_variable_name(d->cursor, i)));
-        }
-    }
-
-    QVector<QVariant> resultRow;
-    resultRow.reserve(n_columns);
-    for (int i = 0; i < n_columns; i++) {
-        resultRow.append(readVariant(d->cursor, i));
-    }
-
-    d->results.append(resultRow);
-    if (d->results.count() % d->driverPrivate->dataReadyInterval == 0) {
-        d->dataReady(d->results.count());
-    }
-
-    return true;
+    return runSemaphore.tryAcquire(1);
 }
 
-bool QTrackerDirectResult::fetchBoolResult()
-{
-    QMutexLocker connectionLocker(&(d->driverPrivate->connectionMutex));
-
-    GError * error = 0;
-    tracker_sparql_cursor_next(d->cursor, 0, &error);
-    if (error) {
-        setLastError(QSparqlError(QString::fromUtf8(error->message),
-                       errorCodeToType(error->code),
-                       error->code));
-        g_error_free(error);
-        qWarning() << "QTrackerDirectResult:" << lastError() << query();
-        terminate();
-        return false;
-    }
-
-    QMutexLocker resultLocker(&(d->resultMutex));
-
-    if (tracker_sparql_cursor_get_n_columns(d->cursor) == 1 &&
-        tracker_sparql_cursor_get_value_type(d->cursor, 0) == TRACKER_SPARQL_VALUE_TYPE_BOOLEAN)  {
-        const gboolean value = tracker_sparql_cursor_get_boolean(d->cursor, 0);
-        d->setBoolValue(value != FALSE);
-    }
-
-    terminate();
-    return true;
-}
+////////////////////////////////////////////////////////////////////////////
 
-QSparqlBinding QTrackerDirectResult::binding(int field) const
+QTrackerDirectResult::QTrackerDirectResult(const QSparqlQueryOptions& options)
+  : options(options), queryRunner(0), resultFinished(0)
 {
-    QMutexLocker resultLocker(&(d->resultMutex));
-
-    if (!isValid()) {
-        return QSparqlBinding();
-    }
-
-    if (field >= d->results[pos()].count() || field < 0) {
-        qWarning() << "QTrackerDirectResult::data[" << pos() << "]: column" << field << "out of range";
-        return QSparqlBinding();
-    }
-    // A special case: we store TRACKER_SPARQL_VALUE_TYPE_INTEGER as longlong,
-    // but its data type uri should be xsd:integer. Set it manually here.
-    QSparqlBinding b;
-    const QVariant& value = d->results[pos()][field];
-    if (value.type() == QVariant::LongLong) {
-        b.setValue(value.toString(), *XSD::Integer());
-    }
-    else {
-        b.setValue(value);
-    }
-
-    if (field < d->columnNames.count()) {
-        b.setName(d->columnNames[field]);
-    }
-    return b;
 }
 
-QVariant QTrackerDirectResult::value(int field) const
+QTrackerDirectResult::~QTrackerDirectResult()
 {
-    QMutexLocker resultLocker(&(d->resultMutex));
-
-    if (!isValid()) {
-        return QVariant();
-    }
-
-    if (field >= d->results[pos()].count() || field < 0) {
-        qWarning() << "QTrackerDirectResult::data[" << pos() << "]: column" << field << "out of range";
-        return QVariant();
-    }
-
-    return d->results[pos()].value(field);
 }
 
-void QTrackerDirectResult::waitForFinished()
+void QTrackerDirectResult::driverClosing()
 {
-    if (d->isFinished == 1)
-        return;
-
-    // We first need the connection to be ready before doing anything
-    d->driverPrivate->openConnectionSync();
-
-    if (!d->driverPrivate->driver->isOpen()) {
-        setLastError(QSparqlError(d->driverPrivate->error,
-                                  QSparqlError::ConnectionError));
-        d->terminate();
-        return;
+    qWarning() << "QSparqlConnection closed before QSparqlResult with query:" <<
+                    query();
+    if (!isFinished())
+    {
+        setLastError(QSparqlError(QString::fromUtf8("QSparqlConnection closed before QSparqlResult"),
+                        QSparqlError::ConnectionError,
+                        -1));
     }
-
-    //if we can acquire the semaphore then run fetcher directly
-    //if we can't then fetcher is in the threadpool, so we wait
-    //for it to complete
-    d->fetcher->runOrWait();
+    stopAndWait();
 }
 
 bool QTrackerDirectResult::isFinished() const
 {
-    return d->isFinished == 1;
-}
-
-void QTrackerDirectResult::terminate()
-{
-    d->terminate();
+    return resultFinished == 1;
 }
 
-void QTrackerDirectResult::stopAndWait()
-{
-    if (d->fetcher)
-    {
-        d->isFinished = 1;
-        d->fetcher->wait();
-    }
-    delete d->fetcher; d->fetcher = 0;
-}
-
-int QTrackerDirectResult::size() const
-{
-    QMutexLocker resultLocker(&(d->resultMutex));
-    return d->results.size();
-}
-
-QSparqlResultRow QTrackerDirectResult::current() const
-{
-    QMutexLocker resultLocker(&(d->resultMutex));
-
-    if (!isValid()) {
-        return QSparqlResultRow();
-    }
-
-    if (d->columnNames.size() != d->results[pos()].size())
-        return QSparqlResultRow();
-
-    QSparqlResultRow resultRow;
-    for (int i = 0; i < d->results[pos()].size(); ++i) {
-        QSparqlBinding b(d->columnNames[i], d->results[pos()][i]);
-        resultRow.append(b);
-    }
-    return resultRow;
-}
-
-QT_END_NAMESPACE
-
-#include "qsparql_tracker_direct_result_p.moc"
--- src/sparql/drivers/tracker_direct/qsparql_tracker_direct_result_p.h
+++ src/sparql/drivers/tracker_direct/qsparql_tracker_direct_result_p.h
@@ -41,58 +41,62 @@
 #define QSPARQL_TRACKER_DIRECT_RESULT_P_H
 
 #include <QtSparql/qsparqlresult.h>
-#include <QtSparql/qsparqlquery.h>
-
-#ifdef QT_PLUGIN
-#define Q_EXPORT_SPARQLDRIVER_TRACKER_DIRECT
-#else
-#define Q_EXPORT_SPARQLDRIVER_TRACKER_DIRECT Q_SPARQL_EXPORT
-#endif
+#include <QtSparql/qsparqlqueryoptions.h>
+#include <QtCore/qrunnable.h>
+#include <QtCore/qthreadpool.h>
+#include <QtCore/qsemaphore.h>
 
 QT_BEGIN_HEADER
 
 QT_BEGIN_NAMESPACE
 
 class QTrackerDirectDriverPrivate;
-class QTrackerDirectDriver;
-class QTrackerDirectResultPrivate;
-class QTrackerDirectUpdateResultPrivate;
+class QTrackerDirectQueryRunner;
 
-class Q_EXPORT_SPARQLDRIVER_TRACKER_DIRECT QTrackerDirectResult : public QSparqlResult
+class QTrackerDirectResult : public QSparqlResult
 {
     Q_OBJECT
-    friend class QTrackerDirectDriver;
-    friend class QTrackerDirectResultPrivate; // for emitting signals
-    friend class QTrackerDirectUpdateResultPrivate;
+    friend class QTrackerDirectQueryRunner;
 public:
-    explicit QTrackerDirectResult(QTrackerDirectDriverPrivate* p,
-                                  const QString& query,
-                                  QSparqlQuery::StatementType type);
+    QTrackerDirectResult(const QSparqlQueryOptions& options);
     ~QTrackerDirectResult();
 
-    Q_INVOKABLE void startFetcher();
-    bool runQuery();
-
-    // Implementation of the QSparqlResult interface
-    virtual void waitForFinished();
     virtual bool isFinished() const;
+    QSparqlQueryOptions options;
+private:
+    // Will be called by the query runner to execute the query, results that don't
+    // need a thread to run in (sync) do not need to implement this
+    virtual void run() {}
+    virtual void stopAndWait() = 0;
+
+protected:
+    QTrackerDirectDriverPrivate *driverPrivate;
+    QAtomicInt resultFinished;
+    QTrackerDirectQueryRunner *queryRunner;
+
+public Q_SLOTS:
+    virtual void exec() = 0;
+    void driverClosing();
 
-    virtual QSparqlResultRow current() const;
-    virtual QSparqlBinding binding(int i) const;
-    virtual QVariant value(int i) const;
-    virtual int size() const;
+};
 
-private Q_SLOTS:
-    void exec();
+class QTrackerDirectQueryRunner : public QRunnable
+{
+public:
+    QTrackerDirectResult *result;
+    QAtomicInt runFinished;
+    QSemaphore runSemaphore;
+    bool started;
+
+    QTrackerDirectQueryRunner(QTrackerDirectResult *result);
+    void runOrWait();
+    void queue(QThreadPool& threadPool);
+    void wait();
 
 private:
-    void terminate();
-    void stopAndWait();
-    bool fetchNextResult();
-    bool fetchBoolResult();
+    void run();
+    bool acquireRunSemaphore();
 
-    QTrackerDirectResultPrivate* d;
-    friend class QTrackerDirectFetcherPrivate;
 };
 
 QT_END_NAMESPACE
--- src/sparql/drivers/tracker_direct/qsparql_tracker_direct_select_result_p.cpp
+++ src/sparql/drivers/tracker_direct/qsparql_tracker_direct_select_result_p.cpp
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (ivan.frade at nokia.com)
+**
+** This file is part of the QtSparql module (not yet part of the Qt Toolkit).
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at ivan.frade at nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsparql_tracker_direct_select_result_p.h"
+#include "qsparql_tracker_direct_p.h"
+#include "qsparql_tracker_direct_driver_p.h"
+
+#include <QtSparql/qsparqlerror.h>
+#include <QtSparql/qsparqlbinding.h>
+#include <QtSparql/qsparqlquery.h>
+#include <QtSparql/qsparqlresultrow.h>
+#define XSD_INTEGER
+#include "../../kernel/qsparqlxsd_p.h"
+
+#include <QtCore/qvector.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+////////////////////////////////////////////////////////////////////////////
+
+QTrackerDirectSelectResult::QTrackerDirectSelectResult(QTrackerDirectDriverPrivate* p,
+                                           const QString& query,
+                                           QSparqlQuery::StatementType type,
+                                           const QSparqlQueryOptions& options)
+  : QTrackerDirectResult(options), cursor(0), resultMutex(QMutex::Recursive)
+{
+    setQuery(query);
+    setStatementType(type);
+    driverPrivate = p;
+    queryRunner = new QTrackerDirectQueryRunner(this);
+}
+
+QTrackerDirectSelectResult::~QTrackerDirectSelectResult()
+{
+    stopAndWait();
+    delete queryRunner;
+}
+
+void QTrackerDirectSelectResult::exec()
+{
+    if (!driverPrivate->driver->isOpen()) {
+        setLastError(QSparqlError(driverPrivate->error,
+                                  QSparqlError::ConnectionError));
+        terminate();
+        return;
+    }
+
+    // Queue calling exec() on the result. This way the finished() and
+    // dataReady() signals won't be emitted before the user connects to
+    // them, and the result won't be in the "finished" state before the
+    // thread that calls this function has entered its event loop.
+    QMetaObject::invokeMethod(this, "startFetcher",  Qt::QueuedConnection);
+}
+
+void QTrackerDirectSelectResult::startFetcher()
+{
+    QMutexLocker resultLocker(&resultMutex);
+    if (queryRunner && !queryRunner->started && !isFinished()) {
+        queryRunner->started = true;
+        //first attempt to acquire the semaphore, if we can, then add the
+        //fetcher to the threadPool queue, if we can't then waitForFinished
+        //has it, so we don't need to refetch the results using this thread
+        queryRunner->queue(driverPrivate->threadPool);
+    }
+}
+
+void QTrackerDirectSelectResult::run()
+{
+    if(runQuery()) {
+        if (isTable()) {
+            while (!isFinished() && fetchNextResult()) {
+                ;
+            }
+        } else if (isBool()) {
+            fetchBoolResult();
+        } else {
+            terminate();
+        }
+     }
+}
+
+bool QTrackerDirectSelectResult::runQuery()
+{
+    if (isFinished())
+        return false;
+
+    QMutexLocker connectionLocker(&(driverPrivate->connectionMutex));
+
+    GError * error = 0;
+    cursor = tracker_sparql_connection_query(    driverPrivate->connection,
+                                                    query().toUtf8().constData(),
+                                                    0,
+                                                    &error );
+    if (error || !cursor) {
+        QMutexLocker resultLocker(&resultMutex);
+        setLastError(QSparqlError(QString::fromUtf8(error ? error->message : "unknown error"),
+                        error ? errorCodeToType(error->code) : QSparqlError::StatementError,
+                        error ? error->code : -1));
+        if (error)
+            g_error_free(error);
+        terminate();
+        qWarning() << "QTrackerDirectSelectResult:" << lastError() << query();
+        return false;
+    }
+
+    return true;
+}
+
+bool QTrackerDirectSelectResult::fetchNextResult()
+{
+    QMutexLocker connectionLocker(&(driverPrivate->connectionMutex));
+    GError * error = 0;
+    gboolean active = tracker_sparql_cursor_next(cursor, 0, &error);
+
+    if (error) {
+        setLastError(QSparqlError(QString::fromUtf8(error->message),
+                       errorCodeToType(error->code),
+                       error->code));
+        g_error_free(error);
+        terminate();
+        qWarning() << "QTrackerDirectSelectResult:" << lastError() << query();
+        return false;
+    }
+
+    if (!active) {
+        terminate();
+        return false;
+    }
+
+    QMutexLocker resultLocker(&resultMutex);
+
+    const gint n_columns = tracker_sparql_cursor_get_n_columns(cursor);
+
+    if (columnNames.empty()) {
+        for (int i = 0; i < n_columns; i++) {
+            columnNames.append(QString::fromUtf8(tracker_sparql_cursor_get_variable_name(cursor, i)));
+        }
+    }
+
+    QVector<QVariant> resultRow;
+    resultRow.reserve(n_columns);
+    for (int i = 0; i < n_columns; i++) {
+        resultRow.append(readVariant(cursor, i));
+    }
+
+    results.append(resultRow);
+    if (results.count() % driverPrivate->dataReadyInterval == 0) {
+        emitDataReady(results.count());
+    }
+
+    return true;
+}
+
+bool QTrackerDirectSelectResult::fetchBoolResult()
+{
+    QMutexLocker resultLocker(&(resultMutex));
+
+    if (!fetchNextResult())
+        return false;
+
+    if (results.count() == 1 && results[0].count() == 1) {
+        const QVariant result = results[0][0];
+        if (result.canConvert<bool>()) {
+            setBoolValue(result.toBool());
+        }
+    }
+
+    terminate();
+    return true;
+}
+
+QSparqlBinding QTrackerDirectSelectResult::binding(int field) const
+{
+    QMutexLocker resultLocker(&resultMutex);
+
+    if (!isValid()) {
+        return QSparqlBinding();
+    }
+
+    if (field >= results[pos()].count() || field < 0) {
+        qWarning() << "QTrackerDirectSelectResult::data[" << pos() << "]: column" << field << "out of range";
+        return QSparqlBinding();
+    }
+    // A special case: we store TRACKER_SPARQL_VALUE_TYPE_INTEGER as longlong,
+    // but its data type uri should be xsd:integer. Set it manually here.
+    QSparqlBinding b;
+    const QVariant& value = results[pos()][field];
+    if (value.type() == QVariant::LongLong) {
+        b.setValue(value.toString(), *XSD::Integer());
+    }
+    else {
+        b.setValue(value);
+    }
+
+    if (field < columnNames.count()) {
+        b.setName(columnNames[field]);
+    }
+    return b;
+}
+
+QVariant QTrackerDirectSelectResult::value(int field) const
+{
+    QMutexLocker resultLocker(&resultMutex);
+
+    if (!isValid()) {
+        return QVariant();
+    }
+
+    if (field >= results[pos()].count() || field < 0) {
+        qWarning() << "QTrackerDirectSelectResult::data[" << pos() << "]: column" << field << "out of range";
+        return QVariant();
+    }
+
+    return results[pos()].value(field);
+}
+
+void QTrackerDirectSelectResult::waitForFinished()
+{
+    if (isFinished())
+        return;
+
+    // We first need the connection to be ready before doing anything
+    driverPrivate->waitForConnectionOpen();
+
+    if (!driverPrivate->driver->isOpen()) {
+        setLastError(QSparqlError(driverPrivate->error,
+                                  QSparqlError::ConnectionError));
+        terminate();
+        return;
+    }
+
+    //if we can acquire the semaphore then run fetcher directly
+    //if we can't then fetcher is in the threadpool, so we wait
+    //for it to complete
+    queryRunner->runOrWait();
+}
+
+void QTrackerDirectSelectResult::terminate()
+{
+
+    QMutexLocker resultLocker(&resultMutex);
+
+    if (results.count() % driverPrivate->dataReadyInterval != 0) {
+        emitDataReady(results.count());
+    }
+
+    if (!resultFinished) {
+        resultFinished = 1;
+        Q_EMIT finished();
+    }
+    if (cursor) {
+        g_object_unref(cursor);
+        cursor = 0;
+    }
+}
+
+void QTrackerDirectSelectResult::stopAndWait()
+{
+    if (queryRunner)
+    {
+        resultFinished = 1;
+        queryRunner->wait();
+    }
+
+    if (cursor) {
+        g_object_unref(cursor);
+        cursor = 0;
+    }
+
+    delete queryRunner; queryRunner = 0;
+}
+
+int QTrackerDirectSelectResult::size() const
+{
+    QMutexLocker resultLocker(&resultMutex);
+    return results.size();
+}
+
+QSparqlResultRow QTrackerDirectSelectResult::current() const
+{
+
+    QMutexLocker resultLocker(&resultMutex);
+
+    if (!isValid()) {
+        return QSparqlResultRow();
+    }
+
+    if (columnNames.size() != results[pos()].size())
+        return QSparqlResultRow();
+
+    QSparqlResultRow resultRow;
+    for (int i = 0; i < results[pos()].size(); ++i) {
+        QSparqlBinding b(columnNames[i], results[pos()][i]);
+        resultRow.append(b);
+    }
+    return resultRow;
+}
+
+void QTrackerDirectSelectResult::emitDataReady(int totalCount)
+{
+    Q_EMIT dataReady(totalCount);
+}
+
+bool QTrackerDirectSelectResult::hasFeature(QSparqlResult::Feature feature) const
+{
+    switch (feature) {
+        case QSparqlResult::Sync:
+        case QSparqlResult::ForwardOnly:
+            return false;
+        case QSparqlResult::QuerySize:
+            return true;
+        default:
+            return false;
+    }
+}
+
+QT_END_NAMESPACE
--- src/sparql/drivers/tracker_direct/qsparql_tracker_direct_select_result_p.h
+++ src/sparql/drivers/tracker_direct/qsparql_tracker_direct_select_result_p.h
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (ivan.frade at nokia.com)
+**
+** This file is part of the QtSparql module (not yet part of the Qt Toolkit).
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at ivan.frade at nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSPARQL_TRACKER_DIRECT_SELECT_RESULT_P_H
+#define QSPARQL_TRACKER_DIRECT_SELECT_RESULT_P_H
+
+#include "qsparql_tracker_direct_result_p.h"
+#include <QtCore/qvector.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qmutex.h>
+
+#include <tracker-sparql.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QTrackerDirectDriverPrivate;
+
+class QTrackerDirectSelectResult : public QTrackerDirectResult
+{
+    Q_OBJECT
+public:
+    explicit QTrackerDirectSelectResult(QTrackerDirectDriverPrivate* p,
+                                  const QString& query,
+                                  QSparqlQuery::StatementType type,
+                                  const QSparqlQueryOptions& options);
+    ~QTrackerDirectSelectResult();
+
+    Q_INVOKABLE void startFetcher();
+
+    bool runQuery();
+
+    // Implementation of the QSparqlResult interface
+    virtual void waitForFinished();
+
+    virtual QSparqlResultRow current() const;
+    virtual QSparqlBinding binding(int i) const;
+    virtual QVariant value(int i) const;
+    virtual int size() const;
+    virtual bool hasFeature(QSparqlResult::Feature feature) const;
+
+public Q_SLOTS:
+    virtual void exec();
+
+private:
+    void terminate();
+    bool fetchNextResult();
+    bool fetchBoolResult();
+    void emitDataReady(int totalCount);
+
+    //QTrackerDirectResult implementation
+    virtual void stopAndWait();
+    virtual void run();
+
+    TrackerSparqlCursor* cursor;
+    mutable QMutex resultMutex;
+    QVector<QString> columnNames;
+    QList<QVector<QVariant> > results;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSPARQL_TRACKER_DIRECT_RESULT_P_H
--- src/sparql/drivers/tracker_direct/qsparql_tracker_direct_sync_result_p.cpp
+++ src/sparql/drivers/tracker_direct/qsparql_tracker_direct_sync_result_p.cpp
@@ -37,79 +37,100 @@
 **
 ****************************************************************************/
 
-#include <tracker-sparql.h>
-
 #include "qsparql_tracker_direct_sync_result_p.h"
+#include "qsparql_tracker_direct_p.h"
 #include "qsparql_tracker_direct_driver_p.h"
-#include "qsparql_tracker_direct_result_p.h"
 
-#include <qsparqlerror.h>
-#include <qsparqlbinding.h>
-#include <qsparqlquery.h>
-#include <qsparqlqueryoptions.h>
-#include <qsparqlresultrow.h>
-#include <qsparqlconnection.h>
+#include <QtSparql/qsparqlerror.h>
+#include <QtSparql/qsparqlbinding.h>
+#include <QtSparql/qsparqlquery.h>
+#include <QtSparql/qsparqlqueryoptions.h>
+#include <QtSparql/qsparqlresultrow.h>
 #define XSD_INTEGER
 #include "../../kernel/qsparqlxsd_p.h"
 
 #include <QtCore/qvariant.h>
-#include <QtCore/qpointer.h>
-#include <QtCore/qmutex.h>
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qeventloop.h>
-
 #include <QtCore/qdebug.h>
 
 QT_BEGIN_NAMESPACE
 
-struct QTrackerDirectSyncResultPrivate
+QTrackerDirectSyncResult::QTrackerDirectSyncResult(QTrackerDirectDriverPrivate* p,
+                                                   const QString& query,
+                                                   QSparqlQuery::StatementType type,
+                                                   const QSparqlQueryOptions& options)
+    : QTrackerDirectResult(options), cursor(0), n_columns(-1), isAsync(false)
 {
-    QTrackerDirectSyncResultPrivate(QTrackerDirectDriverPrivate *dpp, const QSparqlQueryOptions& options);
-    ~QTrackerDirectSyncResultPrivate();
-    TrackerSparqlCursor* cursor;
-    int n_columns;
-    QTrackerDirectDriverPrivate *driverPrivate;
-    QSparqlQueryOptions options;
-};
+    setQuery(query);
+    setStatementType(type);
+    driverPrivate = p;
+    if (options.executionMethod() == QSparqlQueryOptions::AsyncExec && options.isForwardOnly()) {
+        isAsync = true;
+        queryRunner = new QTrackerDirectQueryRunner(this);
+    }
+}
 
-QTrackerDirectSyncResultPrivate::QTrackerDirectSyncResultPrivate(QTrackerDirectDriverPrivate *dpp,
-                                                                 const QSparqlQueryOptions& options)
-    : cursor(0), n_columns(-1), driverPrivate(dpp), options(options)
+QTrackerDirectSyncResult::~QTrackerDirectSyncResult()
 {
+    stopAndWait();
 }
 
-QTrackerDirectSyncResultPrivate::~QTrackerDirectSyncResultPrivate()
+void QTrackerDirectSyncResult::run()
 {
-    if (cursor)
-        g_object_unref(cursor);
+    runQuery();
+    terminate();
 }
 
-////////////////////////////////////////////////////////////////////////////
-
-QTrackerDirectSyncResult::QTrackerDirectSyncResult(QTrackerDirectDriverPrivate* p,
-                                                   const QSparqlQueryOptions& options)
+void QTrackerDirectSyncResult::terminate()
 {
-    d = new QTrackerDirectSyncResultPrivate(p, options);
+    resultFinished = 1;
+    // can revert back to sync mode for the result now
+    isAsync = false;
+    Q_EMIT finished();
 }
 
-QTrackerDirectSyncResult::~QTrackerDirectSyncResult()
+void QTrackerDirectSyncResult::startFetcher()
 {
-    delete d;
+    if (queryRunner && !queryRunner->started && !isFinished()) {
+        queryRunner->started = true;
+        //first attempt to acquire the semaphore, if we can, then add the
+        //fetcher to the threadPool queue, if we can't then waitForFinished
+        //has it, so we don't need to refetch the results using this thread
+        queryRunner->queue(driverPrivate->threadPool);
+    }
 }
 
 void QTrackerDirectSyncResult::exec()
 {
-    if (!d->driverPrivate->driver->isOpen()) {
-        setLastError(QSparqlError(d->driverPrivate->error,
+    if (isAsync && !queryRunner->started) {
+        // we queue this method to allow client to connect signals
+        QMetaObject::invokeMethod(this, "startFetcher",  Qt::QueuedConnection);
+    } else {
+        runQuery();
+    }
+}
+
+void QTrackerDirectSyncResult::runQuery()
+{
+    if (statementType() == QSparqlQuery::AskStatement || statementType() == QSparqlQuery::SelectStatement) {
+        selectQuery();
+    } else if (statementType() == QSparqlQuery::InsertStatement || statementType() == QSparqlQuery::DeleteStatement) {
+        updateQuery();
+    }
+}
+
+void QTrackerDirectSyncResult::selectQuery()
+{
+    if (!driverPrivate->driver->isOpen()) {
+        setLastError(QSparqlError(driverPrivate->error,
                                   QSparqlError::ConnectionError));
         return;
     }
 
     GError * error = 0;
-    d->cursor = tracker_sparql_connection_query(d->driverPrivate->connection, query().toUtf8().constData(), 0, &error);
-    if (error || !d->cursor) {
+    cursor = tracker_sparql_connection_query(driverPrivate->connection, query().toUtf8().constData(), 0, &error);
+    if (error || !cursor) {
         setLastError(QSparqlError(QString::fromUtf8(error ? error->message : "unknown error"),
-                        QSparqlError::StatementError,
+                        error ? errorCodeToType(error->code) : QSparqlError::StatementError,
                         error ? error->code : -1));
         if (error)
             g_error_free(error);
@@ -117,18 +138,19 @@
     }
 }
 
-void QTrackerDirectSyncResult::update()
+void QTrackerDirectSyncResult::updateQuery()
 {
-    if (!d->driverPrivate->driver->isOpen()) {
-        setLastError(QSparqlError(d->driverPrivate->error,
+    if (!driverPrivate->driver->isOpen()) {
+        setLastError(QSparqlError(driverPrivate->error,
                                   QSparqlError::ConnectionError));
         return;
     }
 
     GError * error = 0;
-    tracker_sparql_connection_update(d->driverPrivate->connection,
+
+    tracker_sparql_connection_update(driverPrivate->connection,
                                      query().toUtf8().constData(),
-                                     qSparqlPriorityToGlib(d->options.priority()),
+                                     qSparqlPriorityToGlib(options.priority()),
                                      0,
                                      &error);
     if (error) {
@@ -142,11 +164,21 @@
 
 bool QTrackerDirectSyncResult::next()
 {
-    if (!d->cursor)
+    if (!cursor) {
+        // The cursor may have been unreferenced because the connection was deleted
+        // and now the user is calling next(), so set the row here
+        updatePos(QSparql::AfterLastRow);
         return false;
+    }
 
     GError * error = 0;
-    const gboolean active = tracker_sparql_cursor_next(d->cursor, 0, &error);
+    const gboolean active = tracker_sparql_cursor_next(cursor, 0, &error);
+
+    // if this is an ask query, get the result
+    if (isBool() && active && tracker_sparql_cursor_get_value_type(cursor, 0) == TRACKER_SPARQL_VALUE_TYPE_BOOLEAN) {
+        const gboolean value = tracker_sparql_cursor_get_boolean(cursor, 0);
+        setBoolValue(value != FALSE);
+    }
 
     if (error) {
         setLastError(QSparqlError(QString::fromUtf8(error->message),
@@ -154,14 +186,14 @@
                        error->code));
         g_error_free(error);
         qWarning() << "QTrackerDirectSyncResult:" << lastError() << query();
-        g_object_unref(d->cursor);
-        d->cursor = 0;
+        g_object_unref(cursor);
+        cursor = 0;
         return false;
     }
 
     if (!active) {
-        g_object_unref(d->cursor);
-        d->cursor = 0;
+        g_object_unref(cursor);
+        cursor = 0;
         updatePos(QSparql::AfterLastRow);
         return false;
     }
@@ -176,15 +208,15 @@
 QSparqlResultRow QTrackerDirectSyncResult::current() const
 {
     // Note: this function reads and constructs the data again every time it's called.
-    if (!d->cursor || pos() == QSparql::BeforeFirstRow || pos() == QSparql::AfterLastRow)
+    if (!cursor || pos() == QSparql::BeforeFirstRow || pos() == QSparql::AfterLastRow)
         return QSparqlResultRow();
 
     QSparqlResultRow resultRow;
     // get the no. of columns only once; it won't change between rows
-    if (d->n_columns < 0)
-        d->n_columns = tracker_sparql_cursor_get_n_columns(d->cursor);
+    if (n_columns < 0)
+        n_columns = tracker_sparql_cursor_get_n_columns(cursor);
 
-    for (int i = 0; i < d->n_columns; i++) {
+    for (int i = 0; i < n_columns; i++) {
         resultRow.append(binding(i));
     }
     return resultRow;
@@ -193,18 +225,18 @@
 QSparqlBinding QTrackerDirectSyncResult::binding(int i) const
 {
     // Note: this function reads and constructs the data again every time it's called.
-    if (!d->cursor || pos() == QSparql::BeforeFirstRow || pos() == QSparql::AfterLastRow)
+    if (!cursor || pos() == QSparql::BeforeFirstRow || pos() == QSparql::AfterLastRow)
         return QSparqlBinding();
 
     // get the no. of columns only once; it won't change between rows
-    if (d->n_columns < 0)
-        d->n_columns = tracker_sparql_cursor_get_n_columns(d->cursor);
+    if (n_columns < 0)
+        n_columns = tracker_sparql_cursor_get_n_columns(cursor);
 
-    if (i < 0 || i >= d->n_columns)
+    if (i < 0 || i >= n_columns)
         return QSparqlBinding();
 
-    const gchar* name = tracker_sparql_cursor_get_variable_name(d->cursor, i);
-    const QVariant& value = readVariant(d->cursor, i);
+    const gchar* name = tracker_sparql_cursor_get_variable_name(cursor, i);
+    const QVariant& value = readVariant(cursor, i);
 
     // A special case: we store TRACKER_SPARQL_VALUE_TYPE_INTEGER as longlong,
     // but its data type uri should be xsd:integer. Set it manually here.
@@ -222,37 +254,58 @@
 QVariant QTrackerDirectSyncResult::value(int i) const
 {
     // Note: this function re-constructs the data every time it's called.
-    if (!d->cursor || pos() == QSparql::BeforeFirstRow || pos() == QSparql::AfterLastRow)
+    if (!cursor || pos() == QSparql::BeforeFirstRow || pos() == QSparql::AfterLastRow)
         return QVariant();
 
     // get the no. of columns only once; it won't change between rows
-    if (d->n_columns < 0)
-        d->n_columns = tracker_sparql_cursor_get_n_columns(d->cursor);
+    if (n_columns < 0)
+        n_columns = tracker_sparql_cursor_get_n_columns(cursor);
 
-    if (i < 0 || i >= d->n_columns)
+    if (i < 0 || i >= n_columns)
         return QVariant();
 
-    return readVariant(d->cursor, i);
+    return readVariant(cursor, i);
 }
 
 QString QTrackerDirectSyncResult::stringValue(int i) const
 {
-    if (!d->cursor || pos() == QSparql::BeforeFirstRow || pos() == QSparql::AfterLastRow)
+    if (!cursor || pos() == QSparql::BeforeFirstRow || pos() == QSparql::AfterLastRow)
         return QString();
 
     // get the no. of columns only once; it won't change between rows
-    if (d->n_columns < 0)
-        d->n_columns = tracker_sparql_cursor_get_n_columns(d->cursor);
+    if (n_columns < 0)
+        n_columns = tracker_sparql_cursor_get_n_columns(cursor);
 
-    if (i < 0 || i >= d->n_columns)
+    if (i < 0 || i >= n_columns)
         return QString();
 
-    return QString::fromUtf8(tracker_sparql_cursor_get_string(d->cursor, i, 0));
+    return QString::fromUtf8(tracker_sparql_cursor_get_string(cursor, i, 0));
+}
+
+void QTrackerDirectSyncResult::stopAndWait()
+{
+    if (queryRunner) {
+        resultFinished = 1;
+        queryRunner->wait();
+        delete queryRunner; queryRunner = 0;
+    }
+    if (cursor)
+        g_object_unref(cursor);
+    cursor = 0;
 }
 
 bool QTrackerDirectSyncResult::isFinished() const
 {
-    return !d->cursor;
+    // check for a query runner here, if it has been deleted
+    // then return the sync isFinnished, if it's still there
+    // the result still may have reverted to sync mode, so also
+    // check isAsync
+    if (queryRunner && isAsync) {
+        // return false until the async execution as finnished
+        return resultFinished == 1;
+    } else {
+        return !cursor;
+    }
 }
 
 bool QTrackerDirectSyncResult::hasFeature(QSparqlResult::Feature feature) const
@@ -268,4 +321,22 @@
     }
 }
 
+void QTrackerDirectSyncResult::waitForFinished()
+{
+    if (queryRunner && isAsync) {
+        driverPrivate->waitForConnectionOpen();
+        if (!driverPrivate->driver->isOpen()) {
+            setLastError(QSparqlError(driverPrivate->error,
+                                      QSparqlError::ConnectionError));
+            terminate();
+            return;
+        }
+        //if we can acquire the semaphore then run fetcher directly
+        //if we can't then fetcher is in the threadpool, so we wait
+        //for it to complete
+        queryRunner->runOrWait();
+    }
+
+}
+
 QT_END_NAMESPACE
--- src/sparql/drivers/tracker_direct/qsparql_tracker_direct_sync_result_p.h
+++ src/sparql/drivers/tracker_direct/qsparql_tracker_direct_sync_result_p.h
@@ -40,31 +40,26 @@
 #ifndef QSPARQL_TRACKER_DIRECT_SYNC_RESULT_P_H
 #define QSPARQL_TRACKER_DIRECT_SYNC_RESULT_P_H
 
-#include <QtSparql/qsparqlresult.h>
-
-#ifdef QT_PLUGIN
-#define Q_EXPORT_SPARQLDRIVER_TRACKER_DIRECT
-#else
-#define Q_EXPORT_SPARQLDRIVER_TRACKER_DIRECT Q_SPARQL_EXPORT
-#endif
+#include <tracker-sparql.h>
+#include "qsparql_tracker_direct_result_p.h"
 
 QT_BEGIN_HEADER
 
 QT_BEGIN_NAMESPACE
 
 class QTrackerDirectDriverPrivate;
-class QTrackerDirectDriver;
-class QTrackerDirectSyncResultPrivate;
 class QSparqlQueryOptions;
 
 // A sync and forward-only Result class. The instance of this class is retreved
 // with QTrackerDirectDriver::syncExec().
-class Q_EXPORT_SPARQLDRIVER_TRACKER_DIRECT QTrackerDirectSyncResult : public QSparqlResult
+class QTrackerDirectSyncResult : public QTrackerDirectResult
 {
     Q_OBJECT
-    friend class QTrackerDirectDriver;
 public:
-    explicit QTrackerDirectSyncResult(QTrackerDirectDriverPrivate* p, const QSparqlQueryOptions& options);
+    explicit QTrackerDirectSyncResult(QTrackerDirectDriverPrivate* p,
+                                      const QString& query,
+                                      QSparqlQuery::StatementType type,
+                                      const QSparqlQueryOptions& options);
     ~QTrackerDirectSyncResult();
 
     // Implementation of the QSparqlResult interface
@@ -76,15 +71,25 @@
     virtual QString stringValue(int i) const;
 
     virtual bool isFinished() const;
-
     virtual bool hasFeature(QSparqlResult::Feature feature) const;
+    virtual void waitForFinished();
 
-private Q_SLOTS:
-    void exec();
-    void update();
+public Q_SLOTS:
+    virtual void exec();
 
 private:
-    QTrackerDirectSyncResultPrivate* d;
+    TrackerSparqlCursor* cursor;
+    mutable int n_columns;
+    bool isAsync;
+
+    Q_INVOKABLE void startFetcher();
+
+    virtual void stopAndWait();
+    virtual void run();
+    void runQuery();
+    void updateQuery();
+    void selectQuery();
+    void terminate();
 };
 
 QT_END_NAMESPACE
--- src/sparql/drivers/tracker_direct/qsparql_tracker_direct_update_result_p.cpp
+++ src/sparql/drivers/tracker_direct/qsparql_tracker_direct_update_result_p.cpp
@@ -37,156 +37,71 @@
 **
 ****************************************************************************/
 
-#include <tracker-sparql.h>
-
 #include "qsparql_tracker_direct_update_result_p.h"
+#include "qsparql_tracker_direct_p.h"
 #include "qsparql_tracker_direct_driver_p.h"
-#include "qsparql_tracker_direct_result_p.h"
-
-#include <qsparqlerror.h>
-#include <qsparqlbinding.h>
-#include <qsparqlquery.h>
-#include <qsparqlqueryoptions.h>
-#include <qsparqlresultrow.h>
 
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qeventloop.h>
+#include <QtSparql/qsparqlbinding.h>
+#include <QtSparql/qsparqlquery.h>
+#include <QtSparql/qsparqlresultrow.h>
 
+#include <QtCore/qvariant.h>
 #include <QtCore/qdebug.h>
 
 QT_BEGIN_NAMESPACE
 
-////////////////////////////////////////////////////////////////////////////
-
-class QTrackerDirectUpdateResultPrivate : public QObject {
-    Q_OBJECT
-public:
-    QTrackerDirectUpdateResultPrivate(QTrackerDirectUpdateResult* result, QTrackerDirectDriverPrivate *dpp,
-                                      const QSparqlQueryOptions& options);
-
-    ~QTrackerDirectUpdateResultPrivate();
-    void startUpdate(const QString& query);
-    void terminate();
-    void setLastError(const QSparqlError& e);
-
-    enum State {
-        Idle, Executing, Finished
-    };
-    State state;
-    QEventLoop *loop;
-
-    QTrackerDirectUpdateResult* q;
-    QTrackerDirectDriverPrivate *driverPrivate;
-    QSparqlQueryOptions options;
-};
-
-static void
-async_update_callback( GObject *source_object,
-                       GAsyncResult *result,
-                       gpointer user_data)
-{
-    Q_UNUSED(source_object);
-    QTrackerDirectUpdateResultPrivate *data = static_cast<QTrackerDirectUpdateResultPrivate*>(user_data);
-    if (!data->q) {
-        // The user has deleted the Result object before this callback was
-        // called. Just delete the ResultPrivate here and do nothing.
-        delete data;
-        return;
-    }
-
-    GError *error = 0;
-    tracker_sparql_connection_update_finish(data->driverPrivate->connection, result, &error);
-
-    if (error) {
-        QSparqlError e(QString::fromUtf8(error->message));
-        e.setType(errorCodeToType(error->code));
-        e.setNumber(error->code);
-        data->setLastError(e);
-        g_error_free(error);
-    }
-
-    // A workaround for http://bugreports.qt.nokia.com/browse/QTBUG-18434
-
-    // We cannot emit the QSparqlResult::finished() signal directly here; so
-    // delay it and emit it the next time the main loop spins.
-    QMetaObject::invokeMethod(data->q, "terminate", Qt::QueuedConnection);
-}
-
-QTrackerDirectUpdateResultPrivate::QTrackerDirectUpdateResultPrivate(QTrackerDirectUpdateResult* result,
-                                                                     QTrackerDirectDriverPrivate *dpp,
-                                                                     const QSparqlQueryOptions& options)
-  : state(Idle), loop(0),
-  q(result), driverPrivate(dpp), options(options)
-{
-}
-
-QTrackerDirectUpdateResultPrivate::~QTrackerDirectUpdateResultPrivate()
-{
-}
-
-void QTrackerDirectUpdateResultPrivate::startUpdate(const QString& query)
-{
-    tracker_sparql_connection_update_async( driverPrivate->connection,
-                                            query.toUtf8().constData(),
-                                            0,
-                                            0,
-                                            async_update_callback,
-                                            this);
-    state = QTrackerDirectUpdateResultPrivate::Executing;
-}
-
-void QTrackerDirectUpdateResultPrivate::terminate()
-{
-    state = Finished;
-    q->Q_EMIT finished();
-
-    if (loop)
-        loop->exit();
-}
-
-void QTrackerDirectUpdateResultPrivate::setLastError(const QSparqlError& e)
-{
-    q->setLastError(e);
-}
-
-
-////////////////////////////////////////////////////////////////////////////
-
 QTrackerDirectUpdateResult::QTrackerDirectUpdateResult(QTrackerDirectDriverPrivate* p,
                                            const QString& query,
                                            QSparqlQuery::StatementType type,
                                            const QSparqlQueryOptions& options)
+  : QTrackerDirectResult(options)
 {
     setQuery(query);
     setStatementType(type);
-    d = new QTrackerDirectUpdateResultPrivate(this, p, options);
+    driverPrivate = p;
+    queryRunner = new QTrackerDirectQueryRunner(this);
 }
 
 QTrackerDirectUpdateResult::~QTrackerDirectUpdateResult()
 {
-    if (d->state == QTrackerDirectUpdateResultPrivate::Executing) {
-        // We're deleting the Result before the async update has
-        // finished. There is a pending async callback that will be called at
-        // some point, and that will have our ResultPrivate as user_data. Don't
-        // delete the ResultPrivate here, but just mark that we're no longer
-        // alive. The callback will then delete the ResultPrivate.
-        d->q = 0;
-        return;
-    }
-
-    delete d;
+    stopAndWait();
+    delete queryRunner;
 }
 
 void QTrackerDirectUpdateResult::exec()
 {
-    if (!d->driverPrivate->driver->isOpen()) {
-        setLastError(QSparqlError(d->driverPrivate->error,
+    if (!driverPrivate)
+        return;
+
+    if (!driverPrivate->driver->isOpen()) {
+        setLastError(QSparqlError(driverPrivate->error,
                                   QSparqlError::ConnectionError));
-        d->terminate();
+        terminate();
         return;
     }
+    queryRunner->queue(driverPrivate->threadPool);
+}
+
+void QTrackerDirectUpdateResult::run()
+{
+    if (driverPrivate) {
+        GError * error = 0;
+        tracker_sparql_connection_update(driverPrivate->connection,
+                                         query().toUtf8().constData(),
+                                         qSparqlPriorityToGlib(options.priority()),
+                                         0,
+                                         &error);
+
+        if (error) {
+            setLastError(QSparqlError(QString::fromUtf8(error->message),
+                             errorCodeToType(error->code),
+                             error->code));
+            g_error_free(error);
+            qWarning() << "QTrackerDirectUpdateResult:" << lastError() << query();
+        }
+        QMetaObject::invokeMethod(this, "terminate", Qt::QueuedConnection);
+    }
 
-    d->startUpdate(query());
 }
 
 QSparqlBinding QTrackerDirectUpdateResult::binding(int /*field*/) const
@@ -205,29 +120,26 @@
         return;
 
     // We first need the connection to be ready before doing anything
-    d->driverPrivate->openConnectionSync();
+    if (driverPrivate) {
+        driverPrivate->waitForConnectionOpen();
 
-    if (!d->driverPrivate->driver->isOpen()) {
-        setLastError(QSparqlError(d->driverPrivate->error,
-                                  QSparqlError::ConnectionError));
-        d->terminate();
-        return;
+        if (!driverPrivate->driver->isOpen()) {
+            setLastError(QSparqlError(driverPrivate->error,
+                                      QSparqlError::ConnectionError));
+            terminate();
+            return;
+        }
+        queryRunner->runOrWait();
+        terminate();
     }
-
-    QEventLoop loop;
-    d->loop = &loop;
-    loop.exec();
-    d->loop = 0;
-}
-
-bool QTrackerDirectUpdateResult::isFinished() const
-{
-    return (d->state == QTrackerDirectUpdateResultPrivate::Finished);
 }
 
 void QTrackerDirectUpdateResult::terminate()
 {
-    d->terminate();
+    if (!resultFinished) {
+        resultFinished = 1;
+        Q_EMIT finished();
+    }
 }
 
 int QTrackerDirectUpdateResult::size() const
@@ -240,6 +152,15 @@
     return QSparqlResultRow();
 }
 
+void QTrackerDirectUpdateResult::stopAndWait()
+{
+    if (queryRunner) {
+        queryRunner->wait();
+    }
+    driverPrivate = 0;
+    resultFinished = 1;
+    delete queryRunner; queryRunner = 0;
+}
+
 QT_END_NAMESPACE
 
-#include "qsparql_tracker_direct_update_result_p.moc"
--- src/sparql/drivers/tracker_direct/qsparql_tracker_direct_update_result_p.h
+++ src/sparql/drivers/tracker_direct/qsparql_tracker_direct_update_result_p.h
@@ -40,27 +40,19 @@
 #ifndef QSPARQL_TRACKER_DIRECT_UPDATE_RESULT_P_H
 #define QSPARQL_TRACKER_DIRECT_UPDATE_RESULT_P_H
 
-#include <QtSparql/qsparqlresult.h>
-#include <QtSparql/qsparqlquery.h>
-
-#ifdef QT_PLUGIN
-#define Q_EXPORT_SPARQLDRIVER_TRACKER_DIRECT
-#else
-#define Q_EXPORT_SPARQLDRIVER_TRACKER_DIRECT Q_SPARQL_EXPORT
-#endif
+#include "qsparql_tracker_direct_result_p.h"
+#include <QtSparql/qsparqlqueryoptions.h>
 
 QT_BEGIN_HEADER
 
 QT_BEGIN_NAMESPACE
 
-class QSparqlQueryOptions;
 class QTrackerDirectDriverPrivate;
 class QTrackerDirectUpdateResultPrivate;
 
-class Q_EXPORT_SPARQLDRIVER_TRACKER_DIRECT QTrackerDirectUpdateResult : public QSparqlResult
+class QTrackerDirectUpdateResult : public QTrackerDirectResult
 {
     Q_OBJECT
-    friend class QTrackerDirectDriver;
     friend class QTrackerDirectUpdateResultPrivate;
 public:
     explicit QTrackerDirectUpdateResult(QTrackerDirectDriverPrivate* p,
@@ -73,20 +65,21 @@
 
     // Implementation of the QSparqlResult interface
     virtual void waitForFinished();
-    virtual bool isFinished() const;
 
     virtual QSparqlResultRow current() const;
     virtual QSparqlBinding binding(int i) const;
     virtual QVariant value(int i) const;
     virtual int size() const;
 
-private Q_SLOTS:
-    void exec();
+public Q_SLOTS:
+    virtual void exec();
 
 private:
     Q_INVOKABLE void terminate();
 
-    QTrackerDirectUpdateResultPrivate* d;
+    // QTrackerDirectResult implementation
+    virtual void stopAndWait();
+    virtual void run();
 };
 
 QT_END_NAMESPACE
--- src/sparql/kernel/doc.cpp
+++ src/sparql/kernel/doc.cpp
@@ -1,13 +1,16 @@
 /*!
     \mainpage The QtSparql library
 
-    \brief <center>unstable</center>
-
     \section Introduction
 
     <b>Description</b>
 
-    QtSparql is a client-side library for accessing RDF stores.
+    QtSparql is a client-side library for accessing RDF stores. To use, add QtSparql to
+    your project file:
+
+    \code
+    CONFIG+=qtsparql
+    \endcode
 
     The query language for RDF stores is <a
     href="http://www.w3.org/TR/rdf-sparql-query/">SPARQL</a>.
@@ -31,42 +34,70 @@
       href="http://docs.openlinksw.com/virtuoso/">Virtuoso</a>
 
     <b>List of classes QtSparql API provides:</b>
-    <p><table width="100%">
-    <tr valign="top" bgcolor="#ffffff"><td><i>Class</i></td><td><i>Description</i></td></tr>
-
-    <tr valign="top" bgcolor="#f0f0f0"><td><b>QSparqlConnection</b></td>
-    <td>Interface for accessing an RDF store.</td></tr>
-
-    <tr valign="top" bgcolor="#f0f0f0"><td><b>QSparqlConnectionOptions</b></td>
-    <td>Encapsulates options given to QSparqlConnection. Some options are used
-    only by some drivers.</td></tr>
-
-    <tr valign="top" bgcolor="#f0f0f0"><td><b>QSparqlError</b></td><td>SPARQL
-    error information.</td></tr>
-
-    <tr valign="top" bgcolor="#f0f0f0"><td><b>QSparqlBinding</b></td><td>Handles
-    a binding between a SPARQL query variable name and the value of the RDF
-    node.</td></tr>
-
-    <tr valign="top" bgcolor="#f0f0f0"><td><b>QSparqlQuery</b></td><td>Means of
-    executing and manipulating SPARQL statements.</td></tr>
-
-    <tr valign="top" bgcolor="#f0f0f0"><td><b>QSparqlQueryOptions</b></td>
-    <td>Encapsulates query execution options given to QSparqlConnection::exec(const  QSparqlQuery&, const QSparqlQueryOptions&)
-    Some options are used only by some drivers.</td></tr>
-
-    <tr valign="top"
-    bgcolor="#f0f0f0"><td><b>QSparqlQueryModel</b></td><td>Read-only data model
-    for SPARQL result sets.</td></tr>
-
-    <tr valign="top"
-    bgcolor="#f0f0f0"><td><b>QSparqlResultRow</b></td><td>Encapsulates a row in
-    the results of a query.</td></tr>
+    <p>
+    <table>
+    <tr>
+    <th>Class</th>
+    <th>Description</th>
+    </tr>
+    <tr>
+    <td><b>QSparqlConnection</b></td>
+    <td>Interface for accessing an RDF store.</td>
+    </tr>
+    <tr>
+    <td><b>QSparqlConnectionOptions</b></td>
+    <td>Encapsulates options given to QSparqlConnection. Some options are used only by
+    some drivers.</td>
+    </tr>
+    <tr>
+    <td><b>QSparqlError</b></td>
+    <td>SPARQL error information.</td>
+    </tr>
+    <tr>
+    <td><b>QSparqlBinding</b></td>
+    <td>Handles a binding between a SPARQL query variable name and the value of the RDF
+    node.</td>
+    </tr>
+    <tr>
+    <td><b>QSparqlQuery</b></td>
+    <td>Means of executing and manipulating SPARQL statements.</td>
+    </tr>
+    <tr>
+    <td><b>QSparqlQueryOptions</b></td>
+    <td>Encapsulates query execution options given to QSparqlConnection::exec(const  QSparqlQuery&,
+    const QSparqlQueryOptions&) Some options are used only by some drivers.</td>
+    </tr>
+    <tr>
+    <td><b>QSparqlQueryModel</b></td>
+    <td>Read-only data model for SPARQL result sets.</td>
+    </tr>
+    <tr>
+    <td><b>QSparqlResultRow</b></td>
+    <td>Encapsulates a row in the results of a query.</td>
+    </tr>
+    <tr>
+    <td><b>QSparqlResult</b></td>
+    <td>Abstract interface for accessing the results of an executed QSparqlQuery.</td>
+    </tr>
+    </table>
+    </p>
 
-    <tr valign="top" bgcolor="#f0f0f0"><td><b>QSparqlResult</b></td><td>Abstract
-    interface for accessing the results of an executed QSparqlQuery.</td></tr>
+    The QtSparql API also provides two QML Bindings:
 
-    </table></p>
+    <table>
+    <tr>
+    <th>Binding</th>
+    <th>Description</th>
+    </tr>
+    <tr>
+    <td><b>\ref qmlSparqlConnection "SparqlConnection"</b></td>
+    <td>Binding for QSparqlConnection. Allows queries to be run in QML</td>
+    </tr>
+    <tr>
+    <td><b>\ref qmlSparqlListModel "SparqlListModel"</b></td>
+    <td>Binding for QSparqlQueryModel. Allows for ListView models to be easily defined</td>
+    </tr>
+    </table>
 
     \attention The QtSparql library is not yet stable; we make no
     promises about API / ABI compatibility!
@@ -111,12 +142,14 @@
 
     - Alternatively you can call QSparqlConnection::exec() to exectute the query
       asynchronously. You can then connect to the QSparqlResult::finished() and
-      QSparqlResult::dataReady() signals.
+      QSparqlResult::dataReady() signals. Please note, it is always important to check
+      if the result has an error (using QSparqlResult::hasError()) before connecting the
+      signals.
 
     E.g.
     \dontinclude asynctracker/main.cpp
     \skip conn.exec(query)
-    \until onDataReady
+    \until }
 
     - The QSparqlResult can be iterated over by using the following functions:
       QSparqlResult::first(), QSparqlResult::last(), QSparqlResult::next(),
@@ -159,6 +192,29 @@
     It is also easy to implement custom query models by reimplementing QSparqlQueryModel::data(), see
     the querymodel example for an example of this.
 
+    \section querymodelsqml Query models in QML
+
+    When using the QTRACKER_DIRECT and QSPARQL_ENDPOINT drivers, it is possible to use the models in
+    QML applications. The property names will be selected from the query.
+
+    E.g.
+    \dontinclude qmlquerymodel/main.cpp
+    \skip query =
+    \until "nco:nameFamily
+
+    The results will be accessible using the property names "u", "firstName" and "secondName". After
+    creating a model, it can be set as a context property for a QML file.
+
+    E.g.
+    \dontinclude qmlquerymodel/main.cpp
+    \skip QSparqlQueryModel *model = new
+    \until ctxt->
+
+    The query model can then be used in the same way, with one important difference, QSparqlQueryModel::setQueryQML()
+    must be called instead of QSparqlQueryModel::setQuery(). This is so the role names are extracted from the query, so
+    as to make the model usable in QML. The example <i>qmlquerymodel</i> shows how to use the model with the
+    QTRACKER_DIRECT driver so that it updates when new data is available.
+
     \section connectionoptions Connection options supported by drivers
 
     QTRACKER_DIRECT driver supports the following connection options:
@@ -192,8 +248,7 @@
     give the option name as a string, followed by the value.
 
     Other options can be set using QSparqlConnectionOptions::setOption(), however
-    it is preferable to use the convinence functions in QSparqlConnectionOptions,
-    as these provide additional error checking.
+    it is preferable to use the type-safe convinence functions in QSparqlConnectionOptions.
 
     \section connectionfeatures Connection features
 
@@ -292,6 +347,11 @@
     that may have been added after your original query will not be included in any subsequent
     queries you make.
 
+    The driver supports executing asynchronous queries as ForwardOnly synchronous results by setting
+    QSparqlQueryOptions::setForwardOnly to true. This may be prefarable if you are using the asynchronous
+    API to execute large queries quickly, since the results will not be retrieved before QSparqlResult::finished
+    is emitted.
+
     \section backendspecific Accessing backend-specific functionalities
 
     QtSparql doesn't offer backend-specific functionalities.  For that purpose,
--- src/sparql/kernel/qsparqlbinding.cpp
+++ src/sparql/kernel/qsparqlbinding.cpp
@@ -333,7 +333,7 @@
         {
             quoted = true;
             literal.append(QLatin1Char('\"'));
-            foreach (const QChar ch, val.toString()) {
+            Q_FOREACH (const QChar ch, val.toString()) {
                 if (ch == QLatin1Char('\t'))
                     literal.append(QLatin1String("\\t"));
                 else if (ch == QLatin1Char('\n'))
--- src/sparql/kernel/qsparqlconnection.cpp
+++ src/sparql/kernel/qsparqlconnection.cpp
@@ -245,7 +245,7 @@
     int debugLevel = QString::fromLatin1(getenv("QT_DEBUG_PLUGINS")).toInt();
 
     QStringList paths = QCoreApplication::libraryPaths();
-    foreach(const QString& path, paths) {
+    Q_FOREACH(const QString& path, paths) {
         QString realPath = path + QLatin1String("/sparqldrivers");
         QStringList pluginNames = QDir(realPath).entryList(QDir::Files);
         for (int j = 0; j < pluginNames.count(); ++j) {
@@ -346,6 +346,14 @@
                                      QSparqlConnectionOptions());
 }
 
+void QSparqlConnection::qmlConstructor(const QString& type, const QSparqlConnectionOptions& options)
+{
+    delete d;
+    QSparqlDriver* driver = QSparqlConnectionPrivate::findDriver(type);
+    d = new QSparqlConnectionPrivate(driver, type, options);
+    d->driver->open(d->options);
+}
+
 /*!
 
     Constructs a QSparqlConnection of the given \a type with the given \a options.
@@ -374,7 +382,7 @@
 QSparqlConnection::~QSparqlConnection()
 {
     QList<QSparqlResult*> children = findChildren<QSparqlResult *>();
-    foreach (QSparqlResult *result, children) {
+    Q_FOREACH (QSparqlResult *result, children) {
         if (!result->isFinished())
             qWarning() << "QSparqlConnection: Deleting active query:" <<
                 result->query();
@@ -391,24 +399,23 @@
 {
     QSparqlResult* result = 0;
     if (driver->isOpenError()) {
-        qWarning("QSparqlConnection::exec: connection not open");
-
         result = new QSparqlNullResult();
         result->setLastError(driver->lastError());
+        qWarning() << "QSparqlConnection:" << result->lastError() << result->query();
     } else if (!driver->isOpen()) {
-        qWarning("QSparqlConnection::exec: connection not open");
-
         result = new QSparqlNullResult();
         result->setLastError(QSparqlError(QLatin1String("Connection not open"),
                                           QSparqlError::ConnectionError));
+        qWarning() << "QSparqlConnection:" << result->lastError() << result->query();
     } else {
         if (queryText.isEmpty()) {
-            qWarning("QSparqlConnection::exec: empty query");
             result = new QSparqlNullResult();
             result->setLastError(QSparqlError(QLatin1String("Query is empty"),
-                                            QSparqlError::ConnectionError));
+                                            QSparqlError::StatementError));
+            qWarning() << "QSparqlConnection:" << result->lastError() << result->query();
         }
     }
+
     return result;
 }
 
@@ -484,7 +491,7 @@
             result->setLastError(QSparqlError(
                                     QLatin1String("Unsupported statement type"),
                                     QSparqlError::BackendError));
-            qWarning("QSparqlConnection::exec: Unsupported statement type");
+            qWarning() << "QSparqlConnection:" << result->lastError() << result->query();
         } else {
             if (!d->driver->hasFeature(QSparqlConnection::SyncExec) &&
                     options.executionMethod() == QSparqlQueryOptions::SyncExec) {
--- src/sparql/kernel/qsparqlconnection.h
+++ src/sparql/kernel/qsparqlconnection.h
@@ -49,7 +49,7 @@
 #include <QtSparql/qsparql.h>
 #include <QtSparql/qsparqlconnectionoptions.h>
 #include <QtSparql/qsparqlbinding.h>
-
+#include <QDebug>
 QT_BEGIN_HEADER
 
 QT_BEGIN_NAMESPACE
@@ -61,6 +61,7 @@
 class QSparqlResult;
 class QSparqlConnectionPrivate;
 class QSparqlQueryOptions;
+class SparqlConnection;
 
 class Q_SPARQL_EXPORT QSparqlConnection : public QObject
 {
@@ -95,6 +96,10 @@
 
 private:
     friend class QSparqlConnectionPrivate;
+    friend class SparqlConnection;
+
+    void qmlConstructor(const QString& type, const QSparqlConnectionOptions& options = QSparqlConnectionOptions());
+
     QSparqlConnectionPrivate *d; // replace with Q_DECLARE_PRIVATE when Qt publishes it
 };
 // TODO: make "validness" of a connection a QObject property
--- src/sparql/kernel/qsparqlconnectionoptions.cpp
+++ src/sparql/kernel/qsparqlconnectionoptions.cpp
@@ -46,7 +46,8 @@
 class QSparqlConnectionOptionsPrivate: public QSharedData
 {
 public:
-    QMap<QString,QVariant> map;
+    typedef QMap<QString,QVariant> OptionMap;
+    OptionMap map;
 
     // Settings that cannot easily be put in a QVariant
 #ifndef QT_NO_NETWORKPROXY
@@ -67,28 +68,131 @@
 #endif
                 nam == other.nam;
     }
+
+    QVariant option(const QString& name) const;
+    QVariant optionOrDefaultValue(const QString& name) const;
+    static bool validateOptionValue(const QString& name, const QVariant& value, QVariant& convertedValue);
+    void setOption(const QString& name, const QVariant& value);
+
+    class OptionInfo;
+    class OptionRegistry;
+    };
+
+Q_GLOBAL_STATIC_WITH_ARGS(const QString, hostKey,  (QString::fromLatin1("host")));
+Q_GLOBAL_STATIC_WITH_ARGS(const QString, pathKey, (QString::fromLatin1("path")));
+Q_GLOBAL_STATIC_WITH_ARGS(const QString, portKey, (QString::fromLatin1("port")));
+Q_GLOBAL_STATIC_WITH_ARGS(const QString, dataReadyIntervalKey, (QString::fromLatin1("dataReadyInterval")));
+Q_GLOBAL_STATIC_WITH_ARGS(const QString, userKey, (QString::fromLatin1("user")));
+Q_GLOBAL_STATIC_WITH_ARGS(const QString, passwordKey, (QString::fromLatin1("password")));
+Q_GLOBAL_STATIC_WITH_ARGS(const QString, databaseKey, (QString::fromLatin1("database")));
+Q_GLOBAL_STATIC_WITH_ARGS(const QString, maxThreadKey, (QString::fromLatin1("maxThread")));
+Q_GLOBAL_STATIC_WITH_ARGS(const QString, threadExpiryKey, (QString::fromLatin1("threadExpiry")));
+
+class QSparqlConnectionOptionsPrivate::OptionInfo {
+public:
+    typedef bool (*ValidationFunc)(const QVariant& value);
+
+    const QVariant defaultValue;
+
+    OptionInfo(const QVariant& dv, ValidationFunc vf=0)
+        : defaultValue(dv), validationFunc(vf)
+    {
+    }
+
+    bool validateValue(const QVariant& value, QVariant& convertedValue) const {
+        QVariant newValue(value);
+        if (!newValue.convert(defaultValue.type()))
+            return false;
+        if (validationFunc && !(*validationFunc)(newValue))
+            return false;
+        convertedValue = newValue;
+        return true;
+    }
+
+private:
+    ValidationFunc validationFunc;
+};
+
+class QSparqlConnectionOptionsPrivate::OptionRegistry {
+public:
+    OptionRegistry()
+    {
+        registry.insert(*hostKey(),              new OptionInfo(QVariant(QString())) );
+        registry.insert(*pathKey(),              new OptionInfo(QVariant(QString())) );
+        registry.insert(*userKey(),              new OptionInfo(QVariant(QString())) );
+        registry.insert(*passwordKey(),          new OptionInfo(QVariant(QString())) );
+        registry.insert(*databaseKey(),          new OptionInfo(QVariant(QString())) );
+        registry.insert(*portKey(),              new OptionInfo(QVariant(int(-1)))   );
+        registry.insert(*dataReadyIntervalKey(), new OptionInfo(QVariant(int(1)),  &greaterThanZero) );
+        registry.insert(*maxThreadKey(),         new OptionInfo(QVariant(int(-1)), &greaterThanZero) );
+        registry.insert(*threadExpiryKey(),      new OptionInfo(QVariant(int(-1))) );
+    }
+
+    ~OptionRegistry()
+    {
+        qDeleteAll(registry);
+    }
+
+    const OptionInfo* lookup(const QString& optionName) const
+    {
+        return registry.value(optionName);
+    }
+
+private:
+    static bool greaterThanZero(const QVariant& value)
+    {
+        return (value.toInt() > 0);
+    }
+
+private:
+    QMap<QString, const OptionInfo*> registry;
 };
 
-static QString hostKey = QString::fromLatin1("host");
-static QString pathKey = QString::fromLatin1("path");
-static QString portKey = QString::fromLatin1("port");
-static QString dataReadyIntervalKey = QString::fromLatin1("dataReadyInterval");
-static QString userKey = QString::fromLatin1("user");
-static QString passwordKey = QString::fromLatin1("password");
-static QString databaseKey = QString::fromLatin1("database");
-static QString maxThreadKey = QString::fromLatin1("maxThread");
-static QString threadExpiryKey = QString::fromLatin1("threadExpiry");
-
-template<> void QSharedDataPointer<QSparqlConnectionOptionsPrivate>::detach()
-{
-    if (d && d->ref == 1)
-        return;
-    QSparqlConnectionOptionsPrivate *x = (d ? new QSparqlConnectionOptionsPrivate(*d)
-                               : new QSparqlConnectionOptionsPrivate);
-    x->ref.ref();
-    if (d && !d->ref.deref())
-        delete d;
-    d = x;
+Q_GLOBAL_STATIC(QSparqlConnectionOptionsPrivate::OptionRegistry, connectionOptionRegistry);
+
+QVariant QSparqlConnectionOptionsPrivate::option(const QString& name) const
+{
+    return map.value(name);
+}
+
+QVariant QSparqlConnectionOptionsPrivate::optionOrDefaultValue(const QString& name) const
+{
+    OptionMap::const_iterator optionIter = map.constFind(name);
+    if (optionIter != map.constEnd()) {
+        return *optionIter;
+    }
+    else {
+        const OptionInfo* optionInfo = connectionOptionRegistry()->lookup(name);
+        return (optionInfo ? optionInfo->defaultValue : QVariant());
+    }
+}
+
+bool QSparqlConnectionOptionsPrivate::validateOptionValue(const QString& name, const QVariant& value, QVariant& convertedValue)
+{
+    const OptionInfo* optionInfo = connectionOptionRegistry()->lookup(name);
+    if (!optionInfo) {
+        // Use driver-specific option values as-is
+        convertedValue = value;
+        return true;
+    }
+
+    if (!optionInfo->validateValue(value, convertedValue)) {
+        qWarning() << "QSparqlConnectionOptions: invalid value for option" << name << ":" << value;
+        return false;
+    }
+    return true;
+}
+
+void QSparqlConnectionOptionsPrivate::setOption(const QString& name, const QVariant& value)
+{
+    if (value.isValid()) {
+        QVariant convertedValue;
+        if (validateOptionValue(name, value, convertedValue))
+            map.insert(name, convertedValue);
+    }
+    else {
+        map.remove(name);
+    }
 }
 
 /*!
@@ -109,7 +213,7 @@
 */
 
 QSparqlConnectionOptions::QSparqlConnectionOptions()
-    : d(0)
+    : d(new QSparqlConnectionOptionsPrivate)
 {
 }
 
@@ -122,7 +226,7 @@
 /// equal if they describe the same set of key-value pairs.
 bool QSparqlConnectionOptions::operator==(const QSparqlConnectionOptions &other) const
 {
-    return d == other.d || (d && other.d && *d == *other.d);
+    return d == other.d || *d == *other.d;
 }
 
 /// Creates a QSparqlConnectionOptions object based on \a other, copying all
@@ -146,7 +250,7 @@
 */
 void QSparqlConnectionOptions::setOption(const QString& name, const QVariant& value)
 {
-    d->map[name] = value;
+    d->setOption(name, value);
 }
 
 /*!
@@ -156,7 +260,7 @@
 */
 void QSparqlConnectionOptions::setDatabaseName(const QString& name)
 {
-    setOption(databaseKey, name);
+    setOption(*databaseKey(), name);
 }
 
 /*!
@@ -167,7 +271,7 @@
 */
 void QSparqlConnectionOptions::setUserName(const QString& name)
 {
-    setOption(userKey, name);
+    setOption(*userKey(), name);
 }
 
 /*!
@@ -178,7 +282,7 @@
 */
 void QSparqlConnectionOptions::setPassword(const QString& password)
 {
-    setOption(passwordKey, password);
+    setOption(*passwordKey(), password);
 }
 
 /*!
@@ -188,7 +292,7 @@
 */
 void QSparqlConnectionOptions::setHostName(const QString& host)
 {
-    setOption(hostKey, host);
+    setOption(*hostKey(), host);
 }
 
 /*!
@@ -198,7 +302,7 @@
 */
 void QSparqlConnectionOptions::setPath(const QString& path)
 {
-    setOption(pathKey, path);
+    setOption(*pathKey(), path);
 }
 
 /*!
@@ -208,7 +312,7 @@
 */
 void QSparqlConnectionOptions::setPort(int p)
 {
-    setOption(portKey, p);
+    setOption(*portKey(), p);
 }
 
 /*!
@@ -219,10 +323,7 @@
 */
 void QSparqlConnectionOptions::setDataReadyInterval(int interval)
 {
-    if (interval > 0)
-        setOption(dataReadyIntervalKey, interval);
-    else
-        qWarning() << "QSparqlConnectionOptions: invalid dataReady interval:" << interval;
+    setOption(*dataReadyIntervalKey(), interval);
 }
 
 /*!
@@ -233,10 +334,7 @@
 */
 void QSparqlConnectionOptions::setMaxThreadCount(int p)
 {
-    if (p > 0)
-        setOption(maxThreadKey, p);
-    else
-        qWarning() << "QSparqlConnectionOptions: invalid maxThread amount:" << p;
+    setOption(*maxThreadKey(), p);
 }
 
 /*!
@@ -249,7 +347,7 @@
 {
     //do not need to check for > 0, if the value is negative
     //threads will not expire until the threadpool is destroyed
-    setOption(threadExpiryKey, p);
+    setOption(*threadExpiryKey(), p);
 }
 #ifndef QT_NO_NETWORKPROXY
 /*!
@@ -282,7 +380,7 @@
 */
 QString QSparqlConnectionOptions::databaseName() const
 {
-    return d ? option(databaseKey).toString() : QString();
+    return d->optionOrDefaultValue(*databaseKey()).value<QString>();
 }
 
 /*!
@@ -292,7 +390,7 @@
 */
 QString QSparqlConnectionOptions::path() const
 {
-    return d ? option(pathKey).toString() : QString();
+    return d->optionOrDefaultValue(*pathKey()).value<QString>();
 }
 
 /*!
@@ -303,7 +401,7 @@
 */
 QString QSparqlConnectionOptions::userName() const
 {
-    return d ? option(userKey).toString() : QString();
+    return d->optionOrDefaultValue(*userKey()).value<QString>();
 }
 
 /*!
@@ -314,7 +412,7 @@
 */
 QString QSparqlConnectionOptions::password() const
 {
-    return d ? option(passwordKey).toString() : QString();
+    return d->optionOrDefaultValue(*passwordKey()).value<QString>();
 }
 
 /*!
@@ -324,7 +422,7 @@
 */
 QString QSparqlConnectionOptions::hostName() const
 {
-    return d ? option(hostKey).toString() : QString();
+    return d->optionOrDefaultValue(*hostKey()).value<QString>();
 }
 
 /*!
@@ -334,8 +432,7 @@
 */
 int QSparqlConnectionOptions::port() const
 {
-    QVariant v = option(portKey);
-    return v.canConvert(QVariant::Int) ? v.toInt() : -1;
+    return d->optionOrDefaultValue(*portKey()).value<int>();
 }
 
 /*!
@@ -348,8 +445,7 @@
 */
 int QSparqlConnectionOptions::dataReadyInterval() const
 {
-    QVariant v = option(dataReadyIntervalKey);
-    return v.canConvert(QVariant::Int) ? v.toInt() : 1;
+    return d->optionOrDefaultValue(*dataReadyIntervalKey()).value<int>();
 }
 
 /*!
@@ -360,8 +456,7 @@
 */
 int QSparqlConnectionOptions::maxThreadCount() const
 {
-    QVariant v = option(maxThreadKey);
-    return v.canConvert(QVariant::Int) ? v.toInt() : -1;
+    return d->optionOrDefaultValue(*maxThreadKey()).value<int>();
 }
 
 /*!
@@ -371,8 +466,7 @@
 */
 int QSparqlConnectionOptions::threadExpiryTime() const
 {
-    QVariant v = option(threadExpiryKey);
-    return v.canConvert(QVariant::Int) ? v.toInt() : -1;
+    return d->optionOrDefaultValue(*threadExpiryKey()).value<int>();
 }
 
 /*!
@@ -383,7 +477,7 @@
 */
 QNetworkAccessManager* QSparqlConnectionOptions::networkAccessManager() const
 {
-    return d ? d->nam : 0;
+    return d->nam;
 }
 
 #ifndef QT_NO_NETWORKPROXY
@@ -395,7 +489,7 @@
 */
 QNetworkProxy QSparqlConnectionOptions::proxy() const
 {
-    return d ? d->proxy : QNetworkProxy();
+    return d->proxy;
 }
 #endif
 
@@ -407,12 +501,7 @@
 */
 QVariant QSparqlConnectionOptions::option(const QString& name) const
 {
-    if (d == 0)
-        return QVariant();
-    if (d->map.contains(name))
-        return d->map[name];
-    else
-        return QVariant();
+    return d->option(name);
 }
 
 QT_END_NAMESPACE
--- src/sparql/kernel/qsparqldriver.cpp
+++ src/sparql/kernel/qsparqldriver.cpp
@@ -185,6 +185,8 @@
         d->isOpen = false;
 }
 
+// Exclude from covarage virtual function that will be never called
+// LCOV_EXCL_START
 /*!
     This function is called to begin a transaction. If successful,
     return true, otherwise return false. The default implementation
@@ -223,7 +225,7 @@
 {
     return false;
 }
-
+// LCOV_EXCL_STOP
 /*!
     This function is used to set the value of the last error, \a error,
     that occurred on the database.
--- src/sparql/kernel/qsparqlerror.cpp
+++ src/sparql/kernel/qsparqlerror.cpp
@@ -46,7 +46,7 @@
 // LCOV_EXCL_START
 QDebug operator<<(QDebug dbg, const QSparqlError &s)
 {
-    dbg.nospace() << "QSparqlError(" << s.number() << ", " << s.message() << ')';
+    dbg.nospace() << "QSparqlError(" << s.number() << ", " << s.message() << ", " << s.type() << ")";
     return dbg.space();
 }
 // LCOV_EXCL_STOP
--- src/sparql/kernel/qsparqlntriples_p.h
+++ src/sparql/kernel/qsparqlntriples_p.h
@@ -60,7 +60,9 @@
 
 QT_BEGIN_NAMESPACE
 
-class QSparqlNTriples {
+QT_MODULE(Sparql)
+
+class Q_SPARQL_EXPORT QSparqlNTriples {
 public:
     QSparqlNTriples(QByteArray &b) : buffer(b), i(0), lineNumber(1) {}
     
@@ -83,4 +85,4 @@
 
 QT_END_NAMESPACE
 
-#endif // QSPARQLNTRIPLES_P_H
\ No newline at end of file
+#endif // QSPARQLNTRIPLES_P_H
--- src/sparql/kernel/qsparqlquery.cpp
+++ src/sparql/kernel/qsparqlquery.cpp
@@ -66,10 +66,11 @@
     int holderPos;
 };
 
-struct QSparqlQueryPrivate
+class QSparqlQueryPrivate : public QSharedData
 {
-    QSparqlQueryPrivate(const QString& q = QString(),
-                        QSparqlQuery::StatementType t = QSparqlQuery::SelectStatement)
+public:
+    QSparqlQueryPrivate(const QString& q,
+                        QSparqlQuery::StatementType t)
         : query(q), type(t)
     {
         findPlaceholders();
@@ -79,7 +80,6 @@
 
     void findPlaceholders();
 
-    QAtomicInt ref;
     QString query;
     QSparqlQuery::StatementType type;
 
@@ -176,9 +176,8 @@
 */
 
 QSparqlQuery::QSparqlQuery(const QString& query, StatementType type)
+  : d(new QSparqlQueryPrivate(query, type))
 {
-    d = new QSparqlQueryPrivate(query, type);
-    d->ref.ref();
 }
 
 /*!
@@ -187,8 +186,7 @@
 
 QSparqlQuery::~QSparqlQuery()
 {
-    if (!d->ref.deref())
-        delete d;
+     // QSharedDataPointer takes care of deleting the data object
 }
 
 /*!
@@ -197,9 +195,8 @@
 
 
 QSparqlQuery::QSparqlQuery(const QSparqlQuery& other)
+  : d(other.d)
 {
-    d = other.d;
-    d->ref.ref();
 }
 
 /*!
@@ -208,7 +205,7 @@
 
 QSparqlQuery& QSparqlQuery::operator=(const QSparqlQuery& other)
 {
-    qAtomicAssign(d, other.d);
+    d = other.d;
     return *this;
 }
 
--- src/sparql/kernel/qsparqlquery.h
+++ src/sparql/kernel/qsparqlquery.h
@@ -47,6 +47,7 @@
 #include <QtSparql/qsparql.h>
 
 #include <QtCore/qstring.h>
+#include <QtCore/qshareddata.h>
 
 QT_BEGIN_HEADER
 
@@ -88,7 +89,7 @@
     QString preparedQueryText() const;
 
 private:
-    QSparqlQueryPrivate* d;
+    QSharedDataPointer<QSparqlQueryPrivate> d;
 };
 
 QT_END_NAMESPACE
--- src/sparql/kernel/qsparqlqueryoptions.cpp
+++ src/sparql/kernel/qsparqlqueryoptions.cpp
@@ -38,7 +38,7 @@
 ****************************************************************************/
 
 #include "qsparqlqueryoptions.h"
-
+#include <QDebug>
 QT_BEGIN_NAMESPACE
 
 class QSparqlQueryOptionsPrivate: public QSharedData
@@ -51,12 +51,14 @@
 
     QSparqlQueryOptions::ExecutionMethod executionMethod;
     QSparqlQueryOptions::Priority priority;
+    bool forwardOnly;
 };
 
 QSparqlQueryOptionsPrivate::QSparqlQueryOptionsPrivate()
     // Set the options to their default values
     : executionMethod(QSparqlQueryOptions::AsyncExec)
     , priority(QSparqlQueryOptions::NormalPriority)
+    , forwardOnly(false)
 {
 }
 
@@ -128,7 +130,7 @@
     d->executionMethod = em;
 }
 
-/// Returns the exeuction method of the query.
+/// Returns the execution method of the query.
 /// \sa setExecutionMethod
 QSparqlQueryOptions::ExecutionMethod QSparqlQueryOptions::executionMethod() const
 {
@@ -136,6 +138,24 @@
 }
 
 /*!
+    Sets whether or not to execute asynchronous queries in a ForwardOnly manner.
+    Support for this option is currently limited to the QTRACKER_DIRECT driver.
+    \sa \ref trackerdirectspecific "QTRACKER_DIRECT specific usage"
+*/
+void QSparqlQueryOptions::setForwardOnly(bool forward)
+{
+    d->forwardOnly = forward;
+}
+
+/*!
+    Returns whether or not an asynchronous query will be executed in a forward only manner.
+*/
+bool QSparqlQueryOptions::isForwardOnly() const
+{
+    return d->forwardOnly;
+}
+
+/*!
     \enum QSparqlQueryOptions::Priority
     Priority of the query.
 
--- src/sparql/kernel/qsparqlqueryoptions.h
+++ src/sparql/kernel/qsparqlqueryoptions.h
@@ -72,9 +72,12 @@
     };
 
     void setExecutionMethod(ExecutionMethod em);
+    void setForwardOnly(bool value);
+    bool isForwardOnly() const;
     ExecutionMethod executionMethod() const;
 
     enum Priority {
+        HighPriority =  -10,
         NormalPriority =  0,
         LowPriority    = 10
     };
--- src/sparql/kernel/qsparqlresult.cpp
+++ src/sparql/kernel/qsparqlresult.cpp
@@ -128,6 +128,12 @@
     return d->sparql;
 }
 
+/// Returns the statement type of this QSparqlResult object.
+QSparqlQuery::StatementType QSparqlResult::statementType() const
+{
+    return d->statementType;
+}
+
 /// Sets the information about the query whose results this QSparqlResult object
 /// represents.
 void QSparqlResult::setQuery(const QString &query)
@@ -176,13 +182,18 @@
 }
 
 /*!
-    Returns the boolean result of an ASK query
+    Returns the boolean result of an ASK query.
+
+    Note that this should only be used when isFinished() is true.
 
     \sa isBool() setBoolValue()
 */
 
 bool QSparqlResult::boolValue() const
 {
+    if(!isFinished())
+        qWarning() <<
+            "QSparqlResult: isFinished() is false, boolValue() may be incorrect";
     return d->boolValue;
 }
 
@@ -246,12 +257,26 @@
     been received. If this function returns true, the hasError() and lastError()
     methods should return valid information.
 
-    The useage of this function differs depending on the driver, and method of 
-    execution used. For asynchronous queries the results will be availible once the
-    finished() signal has been emitted. For synchronous execution, the value of isFinished()
-    will be false until all the results have been retrieved using next().
-
-    TODO: Add useage example
+    The usage of this function differs depending on the driver, and method of
+    execution used. For asynchronous queries the results will be available once the
+    finished() signal has been emitted, or waitForFinished() has been called. For
+    synchronous execution, where the driver supports QSparqlConnection::SyncExec,
+    the value of isFinished() will be false until all the results have been retrieved
+    using next().
+
+    E.g For a synchronous result
+    @verbatim
+        QSparqlResult *result = connection.syncExec(query);
+        // result->isFinished() will be false
+        while(result->next())
+            do something
+        // result->isFinished() will now be true @endverbatim
+
+    And for asynchronous execution
+    @verbatim
+        QSparqlResult *result = connection.exec(query);
+        result->waitForFinished();
+        result->isFinished(); // will be true @endverbatim
 
     Note that this function only changes state if you call waitForFinished(), or
     if an external event happens, which in general only happens if you return to
--- src/sparql/kernel/qsparqlresult.h
+++ src/sparql/kernel/qsparqlresult.h
@@ -102,6 +102,7 @@
     QSparqlError lastError() const;
 
     QString query() const;
+    QSparqlQuery::StatementType statementType() const;
 
     bool isTable() const;
     bool isGraph() const;
--- src/sparql/models/models.pri
+++ src/sparql/models/models.pri
@@ -1,9 +1,7 @@
 HEADERS +=      models/qsparqlquerymodel.h \
                 models/qsparqlquerymodel_p.h \
-                models/qsparqlconnectionoptionswrapper_p.h \
                 models/qsparqlresultslist_p.h
 
 SOURCES +=      models/qsparqlquerymodel.cpp \
-		models/qsparqlconnectionoptionswrapper.cpp \
 		models/qsparqlresultslist.cpp
 
--- src/sparql/models/qsparqlconnectionoptionswrapper.cpp
+++ src/sparql/models/qsparqlconnectionoptionswrapper.cpp
-/****************************************************************************
-**
-** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (ivan.frade at nokia.com)
-**
-** This file is part of the QtSparql module (not yet part of the Qt Toolkit).
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** GNU Lesser General Public License Usage
-** This file may be used under the terms of the GNU Lesser General Public
-** License version 2.1 as published by the Free Software Foundation and
-** appearing in the file LICENSE.LGPL included in the packaging of this
-** file. Please review the following information to ensure the GNU Lesser
-** General Public License version 2.1 requirements will be met:
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU General
-** Public License version 3.0 as published by the Free Software Foundation
-** and appearing in the file LICENSE.GPL included in the packaging of this
-** file. Please review the following information to ensure the GNU General
-** Public License version 3.0 requirements will be met:
-** http://www.gnu.org/copyleft/gpl.html.
-**
-** Other Usage
-** Alternatively, this file may be used in accordance with the terms and
-** conditions contained in a signed written agreement between you and Nokia.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at ivan.frade at nokia.com.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qsparqlconnectionoptionswrapper_p.h"
-
-QSparqlConnectionOptions QSparqlConnectionOptionsWrapper::options() const
-{
-    return opts;
-}
-
-QString QSparqlConnectionOptionsWrapper::databaseName() const
-{
-    return opts.databaseName();
-}
-
-void QSparqlConnectionOptionsWrapper::setDatabaseName(const QString &databaseName)
-{
-    opts.setDatabaseName(databaseName);
-}
-
-QString QSparqlConnectionOptionsWrapper::userName() const
-{
-    return opts.hostName();
-}
-
-void QSparqlConnectionOptionsWrapper::setUserName(const QString &userName)
-{
-    opts.setUserName(userName);
-}
-
-QString QSparqlConnectionOptionsWrapper::password() const
-{
-    return opts.password();
-}
-
-void QSparqlConnectionOptionsWrapper::setPassword(const QString &password)
-{
-    opts.setPassword(password);
-}
-
-QString QSparqlConnectionOptionsWrapper::hostName() const
-{
-    return opts.hostName();
-}
-
-void QSparqlConnectionOptionsWrapper::setHostName(const QString &hostName)
-{
-    opts.setHostName(hostName);
-}
-
-QString QSparqlConnectionOptionsWrapper::path() const
-{
-    return opts.path();
-}
-
-void QSparqlConnectionOptionsWrapper::setPath(const QString &path)
-{
-    opts.setPath(path);
-}
-
-QString QSparqlConnectionOptionsWrapper::driverName() const
-{
-    return driver;
-}
-
-void QSparqlConnectionOptionsWrapper::setDriverName(const QString &name)
-{
-    driver = name;
-}
-
-int QSparqlConnectionOptionsWrapper::port() const
-{
-    return opts.port();
-}
-
-void QSparqlConnectionOptionsWrapper::setPort(int port)
-{
-    opts.setPort(port);
-}
--- src/sparql/models/qsparqlconnectionoptionswrapper_p.h
+++ src/sparql/models/qsparqlconnectionoptionswrapper_p.h
-/****************************************************************************
-**
-** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (ivan.frade at nokia.com)
-**
-** This file is part of the QtSparql module (not yet part of the Qt Toolkit).
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** GNU Lesser General Public License Usage
-** This file may be used under the terms of the GNU Lesser General Public
-** License version 2.1 as published by the Free Software Foundation and
-** appearing in the file LICENSE.LGPL included in the packaging of this
-** file. Please review the following information to ensure the GNU Lesser
-** General Public License version 2.1 requirements will be met:
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU General
-** Public License version 3.0 as published by the Free Software Foundation
-** and appearing in the file LICENSE.GPL included in the packaging of this
-** file. Please review the following information to ensure the GNU General
-** Public License version 3.0 requirements will be met:
-** http://www.gnu.org/copyleft/gpl.html.
-**
-** Other Usage
-** Alternatively, this file may be used in accordance with the terms and
-** conditions contained in a signed written agreement between you and Nokia.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at ivan.frade at nokia.com.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QSPARQLCONNECTIONOPTIONSWRAPPER_H
-#define QSPARQLCONNECTIONOPTIONSWRAPPER_H
-
-#include <QtCore/qstring.h>
-#include <QtSparql/qsparqlconnectionoptions.h>
-
-QT_BEGIN_HEADER
-
-QT_BEGIN_NAMESPACE
-
-QT_MODULE(Sparql)
-
-class Q_SPARQL_EXPORT QSparqlConnectionOptionsWrapper : public QObject
-{
-    Q_OBJECT
-    Q_PROPERTY(QString databaseName READ databaseName WRITE setDatabaseName)
-    Q_PROPERTY(QString userName READ userName WRITE setUserName)
-    Q_PROPERTY(QString password READ password WRITE setPassword)
-    Q_PROPERTY(QString hostName READ hostName WRITE setHostName)
-    Q_PROPERTY(QString path READ path WRITE setPath)
-    Q_PROPERTY(QString driverName READ driverName WRITE setDriverName)
-    Q_PROPERTY(int port READ port WRITE setPort)
-
-public:
-    QSparqlConnectionOptions options() const;
-
-    void setDatabaseName(const QString& name);
-    void setUserName(const QString& name);
-    void setPassword(const QString& password);
-    void setHostName(const QString& host);
-    void setPath(const QString& path);
-    void setDriverName(const QString& name);
-    void setPort(int p);
-
-    QString databaseName() const;
-    QString userName() const;
-    QString password() const;
-    QString hostName() const;
-    QString path() const;
-    QString driverName() const;
-    int port() const;
-
-private:
-    QSparqlConnectionOptions opts;
-    QString driver;
-};
-
-QT_END_NAMESPACE
-
-QT_END_HEADER
-
-#endif // QSPARQLCONNECTIONOPTIONSWRAPPER_H
--- src/sparql/models/qsparqlquerymodel.cpp
+++ src/sparql/models/qsparqlquerymodel.cpp
@@ -44,7 +44,7 @@
 #include "private/qsparqldriver_p.h"
 #include <qsparqlbinding.h>
 #include <qsparqlresult.h>
-
+#include <QRegExp>
 QT_BEGIN_NAMESPACE
 
 // #define QSPARQL_PREFETCH 255
@@ -64,7 +64,7 @@
     if (result->hasError())
         q->setLastError(result->lastError());
 
-    emit q->finished();
+    Q_EMIT q->finished();
 }
 
 void QSparqlQueryModelPrivate::beginQuery(int totalResults)
@@ -83,13 +83,6 @@
     resultRow = newResultRow;
     atEnd = false;
 
-    QHash<int, QByteArray> roleNames = q->roleNames();
-    for (int i = 0; i < newResultRow.count(); i++) {
-        roleNames.insert((Qt::UserRole + 1) + i, newResultRow.binding(i).name().toLatin1());
-    }
-
-    q->setRoleNames(roleNames);
-
     if (columnsChanged && hasNewData)
         q->reset();
 
@@ -133,6 +126,95 @@
     memset(colOffsets.data(), 0, colOffsets.size() * sizeof(int));
 }
 
+void QSparqlQueryModelPrivate::findRoleNames()
+{
+    QString queryString = query.preparedQueryText().simplified();
+    roleNames.clear();
+    QList<QString> uniqueNames;
+
+    bool processLoop = true;
+    bool process = false;
+    int firstPosition = 0;
+    int deletePosition = 0;
+
+    QChar closeChar;
+    QChar openChar;
+    QList<QPair<QLatin1Char, QLatin1Char> > bracketMatch;
+
+    bracketMatch.append( qMakePair( QLatin1Char('('), QLatin1Char(')') ) );
+    bracketMatch.append( qMakePair( QLatin1Char('{'), QLatin1Char('}') ) );
+    bracketMatch.append( qMakePair( QLatin1Char('"'), QLatin1Char('"') ) );
+    bracketMatch.append( qMakePair( QLatin1Char('\''), QLatin1Char('\'') ) );
+
+    // check query is valid, will ensure we don't get stuck in the loop
+    if ( queryString.count(QLatin1Char('(')) == queryString.count(QLatin1Char(')'))
+        && queryString.count(QLatin1Char('{')) == queryString.count(QLatin1Char('}'))
+        && queryString.count(QLatin1Char('"')) % 2 == 0
+        && queryString.count(QLatin1Char('\'')) % 2 == 0 )
+    {
+        // first remove any, potentially nested, brackets
+        while (processLoop) {
+            if (!process) {
+                for (int i = 0; i < bracketMatch.size(); ++i) {
+                    firstPosition = queryString.indexOf( bracketMatch.at(i).first );
+                    if (firstPosition != -1) {
+                        openChar = bracketMatch.at(i).first;
+                        closeChar = bracketMatch.at(i).second;
+                        deletePosition = firstPosition;
+                        break;
+                    }
+                 }
+            }
+            if (firstPosition != -1) {
+                process = true;
+                int openCount = 0;
+                int closeCount = 0;
+                // go to the first close, count how many opens, repeat until they match
+                // then delete!
+                do {
+                    deletePosition = queryString.indexOf(closeChar, deletePosition+1);
+                    openCount = queryString.left(deletePosition).count(openChar);
+                    if(deletePosition != -1)
+                        closeCount++;
+                    } while (closeCount != openCount);
+                    queryString.remove(firstPosition, (deletePosition-firstPosition)+1);
+                    firstPosition = 0;
+                    closeCount = 0;
+                    process = false;
+            } else {
+                processLoop = false;
+            }
+        }
+
+        QStringList stringList = queryString.split(QLatin1Char(' '));
+        Q_FOREACH(QString word, stringList) {
+            if ((word.at(0) == QLatin1Char('?') || word.at(0) == QLatin1Char('$'))
+            && (!word.contains(QLatin1Char(';')) && !word.contains(QLatin1Char(':')))) {
+                //remove the ? or $
+                word.remove(0,1);
+                // select ?u{?u a ... is valid, need to make sure
+                // this is dealt with
+                if (word.contains(QLatin1Char('{'))) {
+                   word = word.split(QLatin1Char('{')).at(0);
+                }
+                QRegExp cleanUp(QLatin1String("[,]|[{]|[}]|[.]"));
+                word.replace(cleanUp,QLatin1String(""));
+                if (!uniqueNames.contains(word)) {
+                   uniqueNames.append(word);
+                }
+            }
+        }
+
+        int roleCounter = Qt::UserRole + 1;
+        Q_FOREACH(QString word, uniqueNames) {
+            roleNames[roleCounter++] = word.toLatin1();
+        }
+        q->setRoleNames(roleNames);
+    } else {
+        qWarning() << "QSparqlQueryModel: Invalid Query";
+    }
+}
+
 /*!
     \class QSparqlQueryModel
     \brief The QSparqlQueryModel class provides a read-only data model
@@ -157,6 +239,13 @@
 */
 
 /*!
+    \fn void QSparqlQueryModel::started()
+
+    This signal is emitted when the QSparqlResult, used by the model, has
+    started to execute.
+*/
+
+/*!
     Creates an empty QSparqlQueryModel with the given \a parent.
  */
 QSparqlQueryModel::QSparqlQueryModel(QObject *parent)
@@ -282,10 +371,11 @@
     lastError() can be used to retrieve verbose information if there
     was an error setting the query.
 
-    \sa query(), queryChange(), lastError()
+    \sa setQueryQML(), query(), queryChange(), lastError()
 */
 void QSparqlQueryModel::setQuery(const QSparqlQuery &query, QSparqlConnection &connection)
 {
+    d->query = query;
     bool mustClearModel = d->bottom.isValid();
     if (mustClearModel) {
         d->atEnd = true;
@@ -300,7 +390,21 @@
     d->newQuery = true;
     connect(d->result, SIGNAL(finished()), d, SLOT(queryFinished()));
     connect(d->result, SIGNAL(dataReady(int)), d, SLOT(addData(int)));
+    Q_EMIT started();
+
+}
 
+/*!
+    Same as setQuery(), however role names are extracted from the query to be used as
+    property values in QML.
+
+    \sa setQuery()
+*/
+void QSparqlQueryModel::setQueryQML(const QSparqlQuery &query, QSparqlConnection &connection)
+{
+    d->query = query;
+    d->findRoleNames();
+    setQuery(query, connection);
 }
 
 /*!
@@ -349,7 +453,7 @@
     if (d->headers.size() <= section)
         d->headers.resize(qMax(section + 1, 16));
     d->headers[section][role] = value;
-    emit headerDataChanged(orientation, section, section);
+    Q_EMIT headerDataChanged(orientation, section, section);
     return true;
 }
 
--- src/sparql/models/qsparqlquerymodel.h
+++ src/sparql/models/qsparqlquerymodel.h
@@ -47,6 +47,7 @@
 
 #include <QtCore/qabstractitemmodel.h>
 #include <QtSparql/qsparqlconnection.h>
+#include <QtSparql/QSparqlQuery>
 
 QT_BEGIN_HEADER
 
@@ -57,7 +58,6 @@
 class QSparqlQueryModelPrivate;
 class QSparqlError;
 class QSparqlResultRow;
-class QSparqlQuery;
 
 class Q_SPARQL_EXPORT QSparqlQueryModel: public QAbstractTableModel
 {
@@ -83,14 +83,15 @@
     bool removeColumns(int column, int count, const QModelIndex &parent = QModelIndex());
 
     void setQuery(const QSparqlQuery &query, QSparqlConnection &conn);
+    void setQueryQML(const QSparqlQuery &query, QSparqlConnection &conn);
     QSparqlQuery query() const;
-
     virtual void clear(); // FIXME: do we need this?
 
     QSparqlError lastError() const;
 
 Q_SIGNALS:
     void finished();
+    void started();
 
 protected:
     virtual void queryChange();
--- src/sparql/models/qsparqlquerymodel_p.h
+++ src/sparql/models/qsparqlquerymodel_p.h
@@ -58,6 +58,7 @@
 #include "QtCore/qvarlengtharray.h"
 #include "QtCore/qvector.h"
 #include "QtCore/qabstractitemmodel.h"
+#include "qsparqlquerymodel.h"
 
 QT_BEGIN_NAMESPACE
 
@@ -87,7 +88,10 @@
     QVarLengthArray<int, 56> colOffsets; // used to calculate indexInQuery of columns
     bool newQuery;
     void beginQuery(int totalResults);
-public slots:
+    void findRoleNames();
+    QHash<int, QByteArray> roleNames;
+
+public Q_SLOTS:
     void addData(int totalResults);
     void queryFinished();
 };
--- src/sparql/models/qsparqlresultslist.cpp
+++ src/sparql/models/qsparqlresultslist.cpp
@@ -38,6 +38,7 @@
 ****************************************************************************/
 
 #include <QtCore/QDebug>
+#include <QtNetwork/qnetworkaccessmanager.h>
 
 #include <QtSparql/qsparqlerror.h>
 
@@ -62,7 +63,7 @@
     QSparqlConnection *connection;
     QSparqlResult *result;
     QString query;
-    QSparqlConnectionOptionsWrapper *options;
+    SparqlConnectionOptions *options;
     int lastRowCount;
     QSparqlResultsList::Status status;
 };
@@ -75,6 +76,8 @@
 
 QSparqlResultsList::~QSparqlResultsList()
 {
+    delete d->result;
+    delete d->connection;
     delete d;
 }
 
@@ -113,16 +116,17 @@
             delete d->result;
     }
 
+    delete d->result;
     delete d->connection;
 
-    d->connection = new QSparqlConnection(d->options->driverName(), d->options->options());
+    d->connection = new QSparqlConnection(d->options->driverName(), *d->options);
     d->result = d->connection->exec(QSparqlQuery(d->query));
 
     if (d->result->hasError())
         d->status = Error;
     else
         d->status = Loading;
-    emit statusChanged(d->status);
+    Q_EMIT statusChanged(d->status);
 
     connect(d->result, SIGNAL(finished()), this, SIGNAL(finished()));
     connect(d->result, SIGNAL(finished()), this, SLOT(queryFinished()));
@@ -155,7 +159,7 @@
 
     d->lastRowCount = rowCount;
     QAbstractItemModel::endInsertRows();
-    emit countChanged();
+    Q_EMIT countChanged();
 }
 
 void QSparqlResultsList::queryFinished()
@@ -167,20 +171,20 @@
     else
         d->status = Ready;
 
-    emit statusChanged(d->status);
-    emit countChanged();
+    Q_EMIT statusChanged(d->status);
+    Q_EMIT countChanged();
 }
 
-QSparqlConnectionOptionsWrapper* QSparqlResultsList::options() const
+SparqlConnectionOptions* QSparqlResultsList::options() const
 {
     return d->options;
 }
 
-void QSparqlResultsList::setOptions(QSparqlConnectionOptionsWrapper *options)
+void QSparqlResultsList::setOptions(SparqlConnectionOptions *options)
 {
     d->options = options;
     reload();
-    emit optionsChanged();
+    Q_EMIT optionsChanged();
 }
 
 QString QSparqlResultsList::query() const
@@ -193,7 +197,7 @@
     if (d->query != query) {
         d->query = query;
         reload();
-        emit queryChanged();
+        Q_EMIT queryChanged();
     }
 }
 
--- src/sparql/models/qsparqlresultslist_p.h
+++ src/sparql/models/qsparqlresultslist_p.h
@@ -50,7 +50,7 @@
 #include <QtSparql/QSparqlConnectionOptions>
 #include <QtSparql/QSparqlConnection>
 
-#include "qsparqlconnectionoptionswrapper_p.h"
+#include <QtSparql/private/qsparqlsparqlconnectionoptions_p.h>
 
 QT_BEGIN_HEADER
 
@@ -64,7 +64,7 @@
 {
     Q_OBJECT
     Q_ENUMS(Status)
-    Q_PROPERTY(QSparqlConnectionOptionsWrapper * options READ options WRITE setOptions NOTIFY optionsChanged)
+    Q_PROPERTY(SparqlConnectionOptions * options READ options WRITE setOptions NOTIFY optionsChanged)
     Q_PROPERTY(QString query READ query WRITE setQuery NOTIFY queryChanged)
     Q_PROPERTY(int count READ count NOTIFY countChanged)
     Q_PROPERTY(Status status READ status NOTIFY statusChanged)
@@ -77,8 +77,8 @@
     QVariant data(const QModelIndex &index, int role) const;
     int rowCount(const QModelIndex &parent) const;
 
-    QSparqlConnectionOptionsWrapper * options() const;
-    void setOptions(QSparqlConnectionOptionsWrapper *options);
+    SparqlConnectionOptions * options() const;
+    void setOptions(SparqlConnectionOptions *options);
 
     QString query() const;
     void setQuery(const QString &query);
--- src/sparql/sparql.pro
+++ src/sparql/sparql.pro
@@ -8,7 +8,7 @@
 DEFINES += QT_NO_USING_NAMESPACE
 QT += network
 
-CONFIG += hide_symbols
+CONFIG += hide_symbols no_keywords
 
 DEFINES += QT_NO_CAST_FROM_ASCII
 
@@ -44,6 +44,7 @@
 include(kernel/kernel.pri)
 include(drivers/drivers.pri)
 include(models/models.pri)
+include(declarative/declarative.pri)
 
 INSTALLS += \
         target \
@@ -51,6 +52,7 @@
         install_prf
 target.path = $$QTSPARQL_INSTALL_LIBS
 
+QMAKE_PKGCONFIG_PREFIX = $$QTSPARQL_INSTALL_PREFIX
 QMAKE_PKGCONFIG_REQUIRES = QtCore QtNetwork
 QMAKE_PKGCONFIG_DESTDIR = pkgconfig
 QMAKE_PKGCONFIG_CFLAGS = -I$$QTSPARQL_INSTALL_HEADERS
--- tests/auto/messagerecorder.h
+++ tests/auto/messagerecorder.h
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (ivan.frade at nokia.com)
+**
+** This file is part of the test suite of the QtSparql module (not yet part of the Qt Toolkit).
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at ivan.frade at nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MESSAGERECORDER_H
+#define MESSAGERECORDER_H
+
+class MessageRecorder {
+public:
+    MessageRecorder()
+    {
+        selfPtr = this;
+        prevMsgHandler = qInstallMsgHandler(&MessageRecorder::msgHandler);
+    }
+
+    ~MessageRecorder()
+    {
+        qInstallMsgHandler(prevMsgHandler);
+        selfPtr = 0;
+    }
+
+    void addMsgTypeToRecord(QtMsgType type)      { msgsToRecord.insert(type);    }
+    bool hasMsgsOfType(QtMsgType type) const     { return !msgs[type].isEmpty(); }
+    QStringList msgsOfType(QtMsgType type) const { return msgs[type];            }
+    QStringList operator[](QtMsgType type) const { return msgs[type];            }
+
+private:
+    static MessageRecorder* selfPtr;
+
+    void handleMsg(QtMsgType type, const char *msg)
+    {
+        if (msgsToRecord.contains(type))
+            msgs[type] << QString(msg);
+        else
+            (*prevMsgHandler)(type, msg);
+    }
+
+    static void msgHandler(QtMsgType type, const char *msg)
+    {
+        selfPtr->handleMsg(type, msg);
+    }
+
+private:
+    QtMsgHandler prevMsgHandler;
+    QSet<QtMsgType> msgsToRecord;
+    QMap<QtMsgType, QStringList> msgs;
+};
+MessageRecorder* MessageRecorder::selfPtr = 0;
+
+#endif
--- tests/auto/qsparql.pro
+++ tests/auto/qsparql.pro
@@ -11,29 +11,30 @@
     qsparql_threading \
     qsparql_tracker \
     qsparql_tracker_direct \
+    qsparql_tracker_direct_concurrency \
     qsparql_tracker_direct_sync \
     qsparql_tracker_direct_crashes \
     qsparql_virtuoso \
-    qsparql_virtuoso_endpoint
+    qsparql_virtuoso_endpoint \
+    qsparql_api \
+    qsparql_qmlbindings
 
 contains(sparql-plugins, tracker_direct): SUBDIRS += qsparql_benchmark
 
+QSPARQL_TESTS = qsparql qsparqlquery qsparqlbinding qsparql_api qsparql_tracker \
+                qsparql_tracker_direct qsparql_tracker_direct_sync qsparql_ntriples \
+                qsparql_tracker_direct_crashes qsparql_threading \
+                qsparqlresultrow qsparql_qmlbindings
+
 check.CONFIG = recursive
-check.recurse = qsparql qsparqlquery qsparqlbinding qsparql_tracker \
-                qsparql_tracker_direct qsparql_tracker_direct_sync qsparql_ntriples
+check.recurse = $$QSPARQL_TESTS
 
 memcheck.CONFIG = recursive
-memcheck.recurse = qsparql_tracker qsparql_tracker_direct qsparql_direct_sync \
-                   qsparql_direct_crashes
+memcheck.recurse = $$QSPARQL_TESTS
 
 QMAKE_EXTRA_TARGETS += check memcheck
 
-
-testdata.target = qsparql_threading/clean_data_threading.rq
-
-testdata.files = $$testdata.target
-testdata.path = $$PREFIX/share/$$PACKAGENAME-tests/
 testxml.target = tests.xml
 install_testxml.files = $$testxml.target
 install_testxml.path = $$PREFIX/share/$$PACKAGENAME-tests/
-INSTALLS += target install_testxml testdata
+INSTALLS += target install_testxml
--- tests/auto/qsparql/qsparql.pro
+++ tests/auto/qsparql/qsparql.pro
@@ -1,12 +1,15 @@
 include(../sparqltest.pri)
 CONFIG += qt warn_on console depend_includepath
-QT += testlib
+QT += testlib network
 SOURCES  += tst_qsparql.cpp
 
 check.depends = $$TARGET
 check.commands = ./tst_qsparql
 
-QMAKE_EXTRA_TARGETS += check
+memcheck.depends = $$TARGET
+memcheck.commands = $$VALGRIND $$VALGRIND_OPT ./tst_qsparql
+
+QMAKE_EXTRA_TARGETS += check memcheck
 
 # QT = sparql # enable this later
 
--- tests/auto/qsparql/tst_qsparql.cpp
+++ tests/auto/qsparql/tst_qsparql.cpp
@@ -42,9 +42,6 @@
 
 #include "private/qsparqlconnection_p.h"
 #include "private/qsparqldriver_p.h"
-//const QString qtest(qTableName( "qtest", __FILE__ )); // FIXME: what's this
-
-//TESTED_FILES=
 
 class MockDriver;
 
@@ -217,6 +214,13 @@
     void default_QSparqlQueryOptions();
     void copies_of_QSparqlQueryOptions_are_equal_and_independent();
     void assignment_of_QSparqlQueryOptions_creates_equal_and_independent_copy();
+
+    void default_QSparqlConnectionOptions();
+    void set_QSparqlConnectionOptions();
+    void try_set_illegal_value_in_QSparqlConnectionOptions();
+    void try_set_illegal_type_in_QSparqlConnectionOptions();
+    void copies_of_QSparqlConnectionOptions_are_equal_and_independent();
+    void assignment_of_QSparqlConnectionOptions_creates_equal_and_independent_copy();
 };
 
 tst_QSparql::tst_QSparql()
@@ -488,6 +492,318 @@
     QVERIFY( opt2 == opt1 );
 }
 
+// Constants and functions for QSparqlConnectionOptions tests
+namespace {
+    const char* databaseKey = "database";
+    const QString databaseName("qsparql_test_database");
+    const QString defaultDatabaseName;
+
+    const char* userNameKey = "user";
+    const QString userName("qsparql_user");
+    const QString defaultUserName;
+
+    const char* passwordKey = "password";
+    const QString password("secret_password");
+    const QString defaultPassword;
+
+    const char* hostNameKey = "host";
+    const QString hostName("remote.server.qsparql.com");
+    const QString defaultHostName;
+
+    const char* pathKey = "path";
+    const QString path("/the/path/");
+    const QString defaultPath;
+
+    const char* portKey = "port";
+    const int port = 2226;
+    const int defaultPort = -1;
+
+    const char* dataReadyIntervalKey = "dataReadyInterval";
+    const int dataReadyInterval = 42;
+    const int defaultDataReadyInterval = 1;
+
+    const char* maxThreadCountKey = "maxThread";
+    const int maxThreadCount = 10;
+    const int defaultMaxThreadCount = -1;
+
+    const char* threadExpiryTimeKey = "threadExpiry";
+    const int threadExpiryTime = 500;
+    const int defaultThreadExpiryTime = -1;
+
+    #ifndef QT_NO_NETWORKPROXY
+    inline QNetworkProxy createTestNetworkProxy()
+    {
+        QNetworkProxy p;
+        p.setHostName(hostName);
+        return p;
+    }
+    const QNetworkProxy networkProxy = createTestNetworkProxy();
+    const QNetworkProxy defaultNetworkProxy;
+    #endif
+
+    QNetworkAccessManager networkAccessManagerInstance;
+    QNetworkAccessManager* const networkAccessManager = &networkAccessManagerInstance;
+    QNetworkAccessManager* const defaultNetworkAccessManager = 0;
+
+    void setTestConnectionOptions(QSparqlConnectionOptions& connOptions)
+    {
+        connOptions.setDatabaseName(databaseName);
+        connOptions.setUserName(userName);
+        connOptions.setPassword(password);
+        connOptions.setHostName(hostName);
+        connOptions.setPath(path);
+        connOptions.setPort(port);
+        connOptions.setDataReadyInterval(dataReadyInterval);
+        connOptions.setMaxThreadCount(maxThreadCount);
+        connOptions.setThreadExpiryTime(threadExpiryTime);
+        #ifndef QT_NO_NETWORKPROXY
+        connOptions.setProxy(networkProxy);
+        #endif
+        connOptions.setNetworkAccessManager(networkAccessManager);
+    }
+}
+
+void tst_QSparql::default_QSparqlConnectionOptions()
+{
+    QSparqlConnectionOptions connOptions;
+
+    QCOMPARE( connOptions.databaseName(), defaultDatabaseName );
+    QCOMPARE( connOptions.userName(), defaultUserName );
+    QCOMPARE( connOptions.password(), defaultPassword );
+    QCOMPARE( connOptions.hostName(), defaultHostName );
+    QCOMPARE( connOptions.path(), defaultPath );
+    QCOMPARE( connOptions.port(), defaultPort );
+    QCOMPARE( connOptions.dataReadyInterval(), defaultDataReadyInterval );
+    QCOMPARE( connOptions.maxThreadCount(), defaultMaxThreadCount );
+    QCOMPARE( connOptions.threadExpiryTime(), defaultThreadExpiryTime );
+#ifndef QT_NO_NETWORKPROXY
+    QCOMPARE( connOptions.proxy(), defaultNetworkProxy );
+#endif
+    QCOMPARE( connOptions.networkAccessManager(), defaultNetworkAccessManager );
+
+    const QStringList keys = QStringList()
+            << databaseKey << userNameKey << passwordKey << hostNameKey << pathKey
+            << portKey << dataReadyIntervalKey << maxThreadCountKey << threadExpiryTimeKey;
+    Q_FOREACH(QString key, keys) {
+        QCOMPARE( connOptions.option(key), QVariant() );
+    }
+
+    QVERIFY( connOptions == QSparqlConnectionOptions() );
+}
+
+template<class OptionParamType, class OptionDataType>
+void testSetOption(QSparqlConnectionOptions& connOptions,
+                   void (QSparqlConnectionOptions::*setterFunc)(OptionParamType),
+                   OptionDataType (QSparqlConnectionOptions::*getterFunc)() const,
+                   const OptionDataType& value)
+{
+    // Check that the current option value is different from the test value to
+    // ensure the setter is actually tested
+    QVERIFY( (connOptions.*getterFunc)() != value );
+
+    // Set the option value with setter function and check it has been set
+    (connOptions.*setterFunc)(value);
+    QCOMPARE( (connOptions.*getterFunc)(), value );
+}
+
+template<class OptionParamType, class OptionDataType>
+void testSetOption(QSparqlConnectionOptions& connOptions,
+                   void (QSparqlConnectionOptions::*setterFunc)(OptionParamType),
+                   OptionDataType (QSparqlConnectionOptions::*getterFunc)() const,
+                   const char* optionKey,
+                   const OptionDataType& value,
+                   const OptionDataType& defaultValue)
+{
+    // Delegate to other helper function to test basic setter and getter
+    testSetOption(connOptions, setterFunc, getterFunc, value);
+
+    // Reset the setting with setOption to defaut and check it gets reset
+    connOptions.setOption(optionKey, QVariant());
+    QCOMPARE( connOptions.option(optionKey), QVariant() );
+    QCOMPARE( (connOptions.*getterFunc)(), defaultValue );
+
+    // Re-set the option to the test value with setOption and check it has been set
+    connOptions.setOption(optionKey, QVariant(value));
+    QCOMPARE( (connOptions.*getterFunc)(), value );
+    QCOMPARE( connOptions.option(optionKey), QVariant(value) );
+}
+
+void tst_QSparql::set_QSparqlConnectionOptions()
+{
+    QSparqlConnectionOptions connOptions;
+
+    testSetOption(connOptions,
+                  &QSparqlConnectionOptions::setDatabaseName, &QSparqlConnectionOptions::databaseName, databaseKey,
+                  databaseName, defaultDatabaseName);
+
+    testSetOption(connOptions,
+                  &QSparqlConnectionOptions::setUserName, &QSparqlConnectionOptions::userName, userNameKey,
+                  userName, defaultUserName);
+
+    testSetOption(connOptions,
+                  &QSparqlConnectionOptions::setPassword, &QSparqlConnectionOptions::password, passwordKey,
+                  password, defaultPassword);
+
+    testSetOption(connOptions,
+                  &QSparqlConnectionOptions::setHostName, &QSparqlConnectionOptions::hostName, hostNameKey,
+                  hostName, defaultHostName);
+
+    testSetOption(connOptions,
+                  &QSparqlConnectionOptions::setPath, &QSparqlConnectionOptions::path, pathKey,
+                  path, defaultPath);
+
+    testSetOption(connOptions,
+                  &QSparqlConnectionOptions::setPort, &QSparqlConnectionOptions::port, portKey,
+                  port, defaultPort);
+
+    testSetOption(connOptions,
+                  &QSparqlConnectionOptions::setDataReadyInterval, &QSparqlConnectionOptions::dataReadyInterval, dataReadyIntervalKey,
+                  dataReadyInterval, defaultDataReadyInterval);
+
+    testSetOption(connOptions,
+                  &QSparqlConnectionOptions::setMaxThreadCount, &QSparqlConnectionOptions::maxThreadCount, maxThreadCountKey,
+                  maxThreadCount, defaultMaxThreadCount);
+
+    testSetOption(connOptions,
+                  &QSparqlConnectionOptions::setThreadExpiryTime, &QSparqlConnectionOptions::threadExpiryTime, threadExpiryTimeKey,
+                  threadExpiryTime, defaultThreadExpiryTime);
+
+#ifndef QT_NO_NETWORKPROXY
+    testSetOption(connOptions,
+                  &QSparqlConnectionOptions::setProxy, &QSparqlConnectionOptions::proxy,
+                  networkProxy);
+#endif
+
+    testSetOption(connOptions,
+                  &QSparqlConnectionOptions::setNetworkAccessManager, &QSparqlConnectionOptions::networkAccessManager,
+                  networkAccessManager);
+
+    // Test driver-specific option
+    const QString driverSpecificOptionName = "test_driverspecificoption";
+    QCOMPARE( connOptions.option(driverSpecificOptionName), QVariant() );
+    const QVariant driverSpecificOptionValue = QVariant(QString("test_driverspecificvalue"));
+    connOptions.setOption(driverSpecificOptionName, driverSpecificOptionValue);
+    QCOMPARE( connOptions.option(driverSpecificOptionName), driverSpecificOptionValue );
+
+    // Verify that all options are still set
+    QCOMPARE( connOptions.databaseName(), databaseName );
+    QCOMPARE( connOptions.option(databaseKey), QVariant(databaseName) );
+
+    QCOMPARE( connOptions.userName(), userName );
+    QCOMPARE( connOptions.option(userNameKey), QVariant(userName) );
+
+    QCOMPARE( connOptions.password(), password );
+    QCOMPARE( connOptions.option(passwordKey), QVariant(password) );
+
+    QCOMPARE( connOptions.password(), password );
+    QCOMPARE( connOptions.option(passwordKey), QVariant(password) );
+
+    QCOMPARE( connOptions.hostName(), hostName );
+    QCOMPARE( connOptions.option(hostNameKey), QVariant(hostName) );
+
+    QCOMPARE( connOptions.path(), path );
+    QCOMPARE( connOptions.option(pathKey), QVariant(path) );
+
+    QCOMPARE( connOptions.port(), port );
+    QCOMPARE( connOptions.option(portKey), QVariant(port) );
+
+    QCOMPARE( connOptions.dataReadyInterval(), dataReadyInterval );
+    QCOMPARE( connOptions.option(dataReadyIntervalKey), QVariant(dataReadyInterval) );
+
+    QCOMPARE( connOptions.maxThreadCount(), maxThreadCount );
+    QCOMPARE( connOptions.option(maxThreadCountKey), QVariant(maxThreadCount) );
+
+    QCOMPARE( connOptions.threadExpiryTime(), threadExpiryTime );
+    QCOMPARE( connOptions.option(threadExpiryTimeKey), QVariant(threadExpiryTime) );
+
+    QCOMPARE( connOptions.proxy(), networkProxy );
+
+    QCOMPARE( connOptions.networkAccessManager(), networkAccessManager );
+}
+
+void tst_QSparql::try_set_illegal_value_in_QSparqlConnectionOptions()
+{
+    QSparqlConnectionOptions connOptions;
+    
+    connOptions.setDataReadyInterval(-5);
+    QCOMPARE( connOptions.dataReadyInterval(), defaultDataReadyInterval );
+    QCOMPARE( connOptions.option(dataReadyIntervalKey), QVariant() );
+
+    connOptions.setOption(dataReadyIntervalKey, -10);
+    QCOMPARE( connOptions.dataReadyInterval(), defaultDataReadyInterval );
+    QCOMPARE( connOptions.option(dataReadyIntervalKey), QVariant() );
+
+    connOptions.setMaxThreadCount(-4);
+    QCOMPARE( connOptions.maxThreadCount(), defaultMaxThreadCount );
+    QCOMPARE( connOptions.option(maxThreadCountKey), QVariant() );
+
+    connOptions.setOption(maxThreadCountKey, -8);
+    QCOMPARE( connOptions.maxThreadCount(), defaultMaxThreadCount );
+    QCOMPARE( connOptions.option(maxThreadCountKey), QVariant() );
+}
+
+void tst_QSparql::try_set_illegal_type_in_QSparqlConnectionOptions()
+{
+    QSparqlConnectionOptions connOptions;
+    const QVariant illegalIntVariant(QString("illegal"));
+
+    connOptions.setOption(portKey, illegalIntVariant);
+    QCOMPARE(connOptions.option(portKey), QVariant());
+    QCOMPARE(connOptions.port(), defaultPort);
+
+    connOptions.setOption(dataReadyIntervalKey, illegalIntVariant);
+    QCOMPARE(connOptions.option(dataReadyIntervalKey), QVariant());
+    QCOMPARE(connOptions.dataReadyInterval(), defaultDataReadyInterval);
+
+    connOptions.setOption(maxThreadCountKey, illegalIntVariant);
+    QCOMPARE(connOptions.option(maxThreadCountKey), QVariant());
+    QCOMPARE(connOptions.maxThreadCount(), defaultMaxThreadCount);
+
+    connOptions.setOption(threadExpiryTimeKey, illegalIntVariant);
+    QCOMPARE(connOptions.option(threadExpiryTimeKey), QVariant());
+    QCOMPARE(connOptions.threadExpiryTime(), defaultThreadExpiryTime);
+}
+
+void tst_QSparql::copies_of_QSparqlConnectionOptions_are_equal_and_independent()
+{
+    QSparqlConnectionOptions connOptions;
+    setTestConnectionOptions(connOptions);
+    QVERIFY( connOptions == connOptions );
+    QVERIFY( !(connOptions == QSparqlConnectionOptions()) );
+
+    QSparqlConnectionOptions connOptionsCopy(connOptions);
+    QVERIFY( connOptions == connOptionsCopy );
+
+    const QString databaseName = connOptions.databaseName();
+    connOptionsCopy.setDatabaseName( databaseName + "_COPY");
+    QVERIFY( !(connOptions == connOptionsCopy) );
+    QCOMPARE( connOptions.databaseName(), databaseName );
+
+    connOptionsCopy.setDatabaseName(databaseName);
+    QVERIFY( connOptions == connOptionsCopy );
+}
+
+void tst_QSparql::assignment_of_QSparqlConnectionOptions_creates_equal_and_independent_copy()
+{
+    QSparqlConnectionOptions connOptions;
+    setTestConnectionOptions(connOptions);
+    QVERIFY( connOptions == connOptions );
+    QSparqlConnectionOptions connOptions2;
+    QVERIFY( !(connOptions == connOptions2) );
+
+    connOptions2 = connOptions;
+    QVERIFY( connOptions == connOptions2 );
+
+    const QString databaseName = connOptions.databaseName();
+    connOptions2.setDatabaseName( databaseName + "_COPY");
+    QVERIFY( !(connOptions == connOptions2) );
+    QCOMPARE( connOptions.databaseName(), databaseName );
+
+    connOptions2.setDatabaseName(databaseName);
+    QVERIFY( connOptions == connOptions2 );
+}
+
+
 QTEST_MAIN(tst_QSparql)
 #include "tst_qsparql.moc"
 
--- tests/auto/qsparql_api
+++ tests/auto/qsparql_api
+(directory)
--- tests/auto/qsparql_api/qsparql_api.pro
+++ tests/auto/qsparql_api/qsparql_api.pro
+include(../sparqltest.pri)
+CONFIG += qt warn_on console depend_includepath
+QT += testlib
+SOURCES  += tst_qsparql_api.cpp
+
+check.depends = $$TARGET
+check.commands = ./tst_qsparql_api
+
+memcheck.depends = $$TARGET
+memcheck.commands = $$VALGRIND $$VALGRIND_OPT ./tst_qsparql_api
+
+QMAKE_EXTRA_TARGETS += check memcheck
+
+#QT = sparql # enable this later
--- tests/auto/qsparql_api/tst_qsparql_api.cpp
+++ tests/auto/qsparql_api/tst_qsparql_api.cpp
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (ivan.frade at nokia.com)
+**
+** This file is part of the test suite of the QtSparql module (not yet part of the Qt Toolkit).
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at ivan.frade at nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QtSparql/QtSparql>
+
+#include "../messagerecorder.h"
+#include "../testhelpers.h"
+
+// define the amount of data we are going to insert for the tests
+#define NUM_INSERTS 15
+
+class tst_QSparqlAPI : public QObject
+{
+    Q_OBJECT
+
+public:
+    tst_QSparqlAPI();
+    ~tst_QSparqlAPI();
+
+private slots:
+    void initTestCase();
+    void cleanupTestCase();
+    void init();
+    void cleanup();
+
+    void connection_test();
+    void connection_test_data();
+
+    void query_test();
+    void query_test_data();
+
+    void query_destroy_connection_after_finished_test();
+    void query_destroy_connection_after_finished_test_data();
+
+    void query_error_test();
+    void query_error_test_data();
+
+    void query_destroy_connection_test();
+    void query_destroy_connection_test_data();
+
+    void update_query_test();
+    void update_query_test_data();
+
+    void update_query_error_test();
+    void update_query_error_test_data();
+
+    void update_query_destroy_connection_test();
+    void update_query_destroy_connection_test_data();
+
+    void ask_query_test();
+    void ask_query_test_data();
+
+    void isFinished_test();
+    void isFinished_test_data();
+
+    void queryModel_test();
+    void queryModel_test_data();
+
+    void syncExec_waitForFinished_query_test();
+    void syncExec_waitForFinished_query_test_data();
+
+    void syncExec_waitForFinished_update_query_test();
+    void syncExec_waitForFinished_update_query_test_data();
+    
+    void query_with_prefix();
+    void query_with_prefix_data();
+
+    void go_beyond_columns_number();
+    void go_beyond_columns_number_data();
+
+private:
+    void insertTrackerTestData();
+    void insertEndpointTestData();
+    void cleanupTrackerTestData();
+    void cleanupEndpointTestData();
+    void add_query_test_data(const QString& connectionDriver, const QString& dataTagPrefix);
+    void add_query_error_test_data(const QString& connectionDriver, const QString& dataTagPrefix, bool supportsConstruct);
+    void add_query_destroy_connection_test_data(const QString& connectionDriver, const QString& dataTagPrefix);
+    void add_update_query_test_data(const QString& connectionDriver, const QString& dataTagPrefix);
+    void add_update_query_error_test_data(const QString& connectionDriver, const QString& dataTagPrefix, bool supportsConstruct);
+    void add_update_query_destroy_connection_test_data(const QString& connectionDriver, const QString& dataTagPrefix);
+    void add_ask_query_test_data(const QString& connectionDriver, const QString& dataTagPrefix);
+
+private:
+    MessageRecorder *msgRecorder;
+    bool testEndpoint;
+};
+
+namespace {
+
+const QString contactSelectQueryTemplate =
+    "select ?u ?ng %1 {"
+    "    ?u a nco:PersonContact; "
+    "    nie:isLogicalPartOf <qsparql-api-tests> ;"
+    "    nco:nameGiven ?ng .}";
+const QString contactSelectNothingQuery =
+    "select ?u ?ng {"
+    "    ?u a nco:PersonContact; "
+    "    nie:isLogicalPartOf <qsparql-api-tests-not-here> ;"
+    "    nco:nameGiven ?ng .}";
+const int contactSelectColumnCount = 2;
+
+const QString contactInsertHeader =
+    "insert %1 { <qsparql-api-tests> a nie:InformationElement.";
+const QString contactInsertQueryTemplate =
+    "<uri00%1> a nco:PersonContact;"
+    "nie:isLogicalPartOf <qsparql-api-tests> ;"
+    "nco:nameGiven \"name00%1\" .";
+const int contactInsertAmount = 1;
+
+const QString contactDeleteHeader =
+    "delete %1 { <qsparql-api-tests> a nie:InformationElement .";
+const QString contactDeleteQueryTemplate =
+    "<uri00%1> a nco:PersonContact .";
+const int contactDeleteAmount = 1;
+
+
+const QString askQueryTrue =
+    "ask {"
+    "    <uri001> a nco:PersonContact, nie:InformationElement ;"
+    "    nie:isLogicalPartOf <qsparql-api-tests> ;"
+    "    nco:nameGiven \"name001\" .}";
+
+const QString askQueryFalse =
+    "ask {"
+    "    <uri001> a nco:PersonContact, nie:InformationElement ;"
+    "    nie:isLogicalPartOf <qsparql-api-tests> ;"
+    "    nco:nameGiven \"name002\" .}";
+
+const QString constructQuery =
+    "CONSTRUCT { ?s ?p ?o }"
+    "    WHERE { GRAPH <http://example.org/aGraph> { ?s ?p ?o } . }";
+
+const QString invalidQuery =
+    "Invalid query";
+
+class FinishedSignalReceiver : public QObject
+{
+    Q_OBJECT
+    int numFinished;
+    QObject* expectedSender;
+
+public:
+    FinishedSignalReceiver()
+        : numFinished(0), expectedSender(0)
+    { }
+
+    void connectFinished(QObject* sender)
+    {
+        QVERIFY( QObject::connect(sender, SIGNAL(finished()), this, SLOT(onFinished())) );
+        expectedSender = sender;
+    }
+
+    void waitForFinished(int timeoutMs)
+    {
+        bool timeout = false;
+        numFinished = 0;
+        QTime timeoutTimer;
+        timeoutTimer.start();
+        while (numFinished == 0 && !(timeout = (timeoutTimer.elapsed() > timeoutMs))) {
+            QTest::qWait(qMax(20, timeoutMs / 100));
+        }
+        QVERIFY(!timeout);
+    }
+
+    void ensureOneFinishedReceived(int timeoutMs)
+    {
+        QCOMPARE( numFinished, 1 );
+        QTest::qWait(timeoutMs);
+        QCOMPARE( numFinished, 1 );
+    }
+
+public slots:
+    void onFinished()
+    {
+        ++numFinished;
+        QCOMPARE( sender(), expectedSender );
+    }
+};
+
+void checkExecutionMethod(QSparqlResult* r, const int executionMethod, const bool useAsyncObject)
+{
+    QVERIFY(r);
+    if (executionMethod == QSparqlQueryOptions::AsyncExec) {
+        if (useAsyncObject) {
+            // As per documentation requirement, only attempt to connect the
+            // signals after first validating that there is no error
+            if (!r->hasError()) {
+                FinishedSignalReceiver signalReceiver;
+                signalReceiver.connectFinished(r);
+                signalReceiver.waitForFinished(2000);
+                signalReceiver.ensureOneFinishedReceived(100);
+            }
+        } else {
+            r->waitForFinished();
+        }
+    }
+}
+
+void validateResults(QSparqlResult *r, const int expectedResultsSize)
+{
+    if (r->hasFeature(QSparqlResult::QuerySize))
+        QCOMPARE(r->size(), expectedResultsSize);
+
+    QHash<QString, QString> contactNamesValue;
+    QHash<QString, QString> contactNamesBindings;
+    QHash<QString, QString> contactNamesStringValue;
+    QList<QString> contactOrder;
+
+    QVERIFY(r->pos() == QSparql::BeforeFirstRow);
+    QVERIFY(!r->isValid());
+    int resultSize = 0;
+    while (r->next()) {
+        QVERIFY(r->isValid());
+        // keep a list of the uri's to be used to track the insert order
+        contactOrder.append(r->value(0).toString());
+
+        contactNamesValue[r->value(0).toString()] = r->value(1).toString();
+        contactNamesBindings[r->binding(0).value().toString()] = r->binding(1).value().toString();
+        contactNamesStringValue[r->stringValue(0)] = r->stringValue(1);
+        ++resultSize;
+    }
+    QVERIFY(r->pos() == QSparql::AfterLastRow);
+    QVERIFY(!r->isValid());
+    QCOMPARE(resultSize, expectedResultsSize);
+
+    // Checks for if we expect some results
+    if (expectedResultsSize != 0) {
+        for(int i=1; i<=expectedResultsSize; i++)
+        {
+            QCOMPARE(contactNamesValue[QString("uri00%1").arg(i)], QString("name00%1").arg(i));
+            QCOMPARE(contactNamesValue[QString("uri00%1").arg(i)], contactNamesBindings[QString("uri00%1").arg(i)]);
+            QCOMPARE(contactNamesValue[QString("uri00%1").arg(i)], contactNamesStringValue[QString("uri00%1").arg(i)]);
+        }
+
+        if (r->hasFeature(QSparqlResult::ForwardOnly)) {
+            QVERIFY(!r->previous());
+            QVERIFY(!r->next());
+            QVERIFY(r->pos() == QSparql::AfterLastRow);
+            QVERIFY(!r->isValid());
+        } else {
+            // Iterate the result backwards
+            int resultSize = 0;
+            while (r->previous()) {
+                QVERIFY(r->pos() != QSparql::AfterLastRow);
+                QVERIFY(r->isValid());
+                QCOMPARE(contactNamesValue[r->value(0).toString()], r->value(1).toString());
+                QCOMPARE(contactNamesBindings[r->binding(0).value().toString()], r->binding(1).value().toString());
+                QCOMPARE(contactNamesStringValue[r->stringValue(0)], r->stringValue(1));
+                ++resultSize;
+            }
+            QCOMPARE(resultSize, expectedResultsSize);
+            // Now move forward one...
+            QVERIFY(r->pos() == QSparql::BeforeFirstRow);
+            QVERIFY(!r->isValid());
+            QVERIFY(r->next());
+            QVERIFY(r->pos() != QSparql::BeforeFirstRow);
+            QVERIFY(r->isValid());
+            QCOMPARE(contactNamesValue[contactOrder.at(0)], r->value(1).toString());
+            QCOMPARE(contactNamesBindings[contactOrder.at(0)], r->binding(1).value().toString());
+            QCOMPARE(contactNamesStringValue[contactOrder.at(0)], r->stringValue(1));
+        }
+    } else {
+        //Make sure using the result doesn't crash
+        QVERIFY(r->pos() < 0);
+        QVERIFY(!r->isValid());
+        QVERIFY(!r->next());
+        QVERIFY(!r->previous());
+        QVERIFY(r->pos() < 0);
+        QVERIFY(!r->isValid());
+    }
+}
+
+void validateBoolVariant_impl(bool& result, const QVariant& variant, const bool expectedResult)
+{
+    result = false;
+    QVERIFY(variant.canConvert<bool>());
+    QCOMPARE(variant.toBool(), expectedResult);
+    result = true;
+}
+
+bool validateBoolVariant(const QVariant& variant, const bool expectedResult)
+{
+    bool result = false;
+    validateBoolVariant_impl(result, variant, expectedResult);
+    return result;
+}
+
+void validateCurrentBoolResult_impl(bool& result, QSparqlResult* r, const bool expectedResult)
+{
+    result = false;
+
+    QVERIFY(!r->hasError());
+    QVERIFY(r->isValid());
+    QVERIFY(r->isBool());
+    QCOMPARE(r->boolValue(), expectedResult);
+
+    QCOMPARE(r->current().count(), 1);
+    QVERIFY(validateBoolVariant(r->current().value(0), expectedResult));
+
+    QVERIFY(validateBoolVariant(r->value(0), expectedResult));
+
+    QVERIFY(r->binding(0).isValid());
+    QVERIFY(r->binding(0).isLiteral());
+    QVERIFY(validateBoolVariant(r->binding(0).value(), expectedResult));
+
+    result = true;
+}
+
+bool validateCurrentBoolResult(QSparqlResult* r, const bool expectedResult)
+{
+    bool result = false;
+    validateCurrentBoolResult_impl(result, r, expectedResult);
+    return result;
+}
+
+void validateErrorResult(QSparqlResult *r, int expectedErrorType)
+{
+    QVERIFY(r);
+    QVERIFY(r->hasError());
+    QVERIFY(r->lastError().type() == expectedErrorType);
+
+    // Check iteration behaviour
+    QVERIFY(r->pos() < 0);
+    QVERIFY(!r->isValid());
+    QVERIFY(!r->next());
+    QVERIFY(!r->previous());
+    QVERIFY(r->pos() < 0);
+    QVERIFY(!r->isValid());
+}
+
+QSparqlConnectionOptions getConnectionOptions(QString driver)
+{
+    QSparqlConnectionOptions options;
+    if (driver == "QSPARQL_ENDPOINT") {
+        options.setHostName("127.0.0.1");
+        options.setPort(8890);
+        return options;
+    }
+    return options;
+}
+
+QString getTemplateArguments(QString driver, QString query)
+{
+    if (driver == "QSPARQL_ENDPOINT") {
+        if (query == "SELECT" || query == "DELETE") {
+            return "FROM <http://virtuoso_endpoint/testgraph>";
+        } else {
+            return "INTO <http://virtuoso_endpoint/testgraph>";
+        }
+    } else {
+        return "";
+    }
+}
+
+} // end unnamed namespace
+
+tst_QSparqlAPI::tst_QSparqlAPI()
+{
+}
+
+tst_QSparqlAPI::~tst_QSparqlAPI()
+{
+}
+
+void tst_QSparqlAPI::initTestCase()
+{
+    // For running the test without installing the plugins. Should work in
+    // normal and vpath builds.
+    QCoreApplication::addLibraryPath("../../../plugins");
+
+    testEndpoint = false;
+    cleanupTestCase();
+    insertTrackerTestData();
+    insertEndpointTestData();
+}
+
+void tst_QSparqlAPI::insertTrackerTestData()
+{
+    const QString insertQueryTemplate =
+        "<uri00%1> a nco:PersonContact, nie:InformationElement ;"
+        "nie:isLogicalPartOf <qsparql-api-tests> ;"
+        "nco:nameGiven \"name00%1\" .";
+    QString insertQuery = "insert { <qsparql-api-tests> a nie:InformationElement .";
+    for (int item = 1; item <= NUM_INSERTS; item++) {
+        insertQuery.append( insertQueryTemplate.arg(item) );
+    }
+    insertQuery.append(" }");
+
+    QSparqlConnection conn("QTRACKER");
+    const QSparqlQuery q(insertQuery,QSparqlQuery::InsertStatement);
+    QSparqlResult* r = conn.exec(q);
+    QVERIFY(!r->hasError());
+    r->waitForFinished();
+    QVERIFY(!r->hasError());
+    delete r;
+}
+
+void tst_QSparqlAPI::insertEndpointTestData()
+{
+    const QString insertQueryTemplate =
+        "<uri00%1> a nco:PersonContact, nie:InformationElement ;"
+        "nie:isLogicalPartOf <qsparql-api-tests> ;"
+        "nco:nameGiven \"name00%1\" .";
+    QString insertQuery = "insert into <http://virtuoso_endpoint/testgraph> { <qsparql-api-tests> a nie:InformationElement .";
+    for (int item = 1; item <= NUM_INSERTS; item++) {
+        insertQuery.append( insertQueryTemplate.arg(item) );
+    }
+    insertQuery.append(" }");
+    QSparqlConnectionOptions options = getConnectionOptions("QSPARQL_ENDPOINT");
+    QSparqlConnection conn("QSPARQL_ENDPOINT", options);
+    const QSparqlQuery q(insertQuery,QSparqlQuery::InsertStatement);
+    QSparqlResult* r = conn.exec(q);
+    r->waitForFinished();
+    if (!r->hasError()) {
+        testEndpoint = true;
+    }
+    delete r;
+
+}
+
+void tst_QSparqlAPI::cleanupTestCase()
+{
+    cleanupTrackerTestData();
+    if (testEndpoint)
+        cleanupEndpointTestData();
+}
+
+void tst_QSparqlAPI::cleanupTrackerTestData()
+{
+    QSparqlConnection conn("QTRACKER");
+    const QSparqlQuery q("DELETE { ?u a rdfs:Resource . } "
+                         "  WHERE { ?u nie:isLogicalPartOf <qsparql-api-tests> . }"
+                         "DELETE { <qsparql-api-tests> a rdfs:Resource . }",
+                    QSparqlQuery::DeleteStatement);
+    QSparqlResult* r = conn.exec(q);
+    QVERIFY(!r->hasError());
+    r->waitForFinished();
+    QVERIFY(!r->hasError());
+    delete r;
+}
+
+void tst_QSparqlAPI::cleanupEndpointTestData()
+{
+    QSparqlConnectionOptions options = getConnectionOptions("QSPARQL_ENDPOINT");
+    QSparqlConnection conn("QSPARQL_ENDPOINT", options);
+    const QSparqlQuery q("DELETE FROM <http://virtuoso_endpoint/testgraph> { ?u a nco:PersonContact . } "
+                         "WHERE { ?u nie:isLogicalPartOf <qsparql-api-tests> .}",
+                     QSparqlQuery::DeleteStatement);
+
+    QSparqlResult* r = conn.exec(q);
+    QVERIFY(!r->hasError());
+    r->waitForFinished();
+    QVERIFY(!r->hasError());
+    delete r;
+}
+
+void tst_QSparqlAPI::init()
+{
+    msgRecorder = new MessageRecorder;
+    msgRecorder->addMsgTypeToRecord(QtWarningMsg);
+}
+
+void tst_QSparqlAPI::cleanup()
+{
+    delete msgRecorder;
+    msgRecorder = 0;
+}
+
+void tst_QSparqlAPI::connection_test()
+{
+    QFETCH(QString, driverName);
+    QFETCH(bool, isValid);
+    
+    QSparqlConnection conn(driverName);
+    QCOMPARE(driverName, conn.driverName());
+    QCOMPARE(conn.isValid(), isValid);
+}
+
+void tst_QSparqlAPI::connection_test_data()
+{
+    QTest::addColumn<QString>("driverName");
+    QTest::addColumn<bool>("isValid");
+    
+    QTest::newRow("dbus driver") << "QTRACKER" << true;
+    QTest::newRow("direct driver") <<  "QTRACKER_DIRECT" << true;
+    QTest::newRow("dummy driver") << "QTRACKER_DUMMY" << false;
+
+}
+
+void tst_QSparqlAPI::query_test()
+{
+    QFETCH(QString, connectionDriver);
+    QFETCH(QString, queryTemplate);
+    QFETCH(int, expectedResultsSize);
+    QFETCH(int, executionMethod);
+    QFETCH(bool, useAsyncObject);
+    QFETCH(bool, forwardOnly);
+
+    QSparqlConnectionOptions options = getConnectionOptions(connectionDriver);
+    QSparqlConnection conn(connectionDriver, options);
+
+    QSparqlQueryOptions queryOptions;
+    queryOptions.setForwardOnly(forwardOnly);
+    queryOptions.setExecutionMethod(QSparqlQueryOptions::ExecutionMethod(executionMethod));
+
+    const QString queryString = queryTemplate.arg( getTemplateArguments(connectionDriver, "SELECT") );
+    const QSparqlQuery q(queryString);
+
+    QSparqlResult* r = conn.exec(q, queryOptions);
+    checkExecutionMethod(r, executionMethod, useAsyncObject);
+    validateResults(r, expectedResultsSize);
+
+    delete r;
+}
+
+void tst_QSparqlAPI::add_query_test_data(const QString& connectionDriver, const QString& dataTagPrefix)
+{
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async Query")))
+        << connectionDriver
+        << contactSelectQueryTemplate
+        << NUM_INSERTS
+        << int(QSparqlQueryOptions::AsyncExec)
+        << false
+        << false;
+
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async Query Forward Only")))
+        << connectionDriver
+        << contactSelectQueryTemplate
+        << NUM_INSERTS
+        << int(QSparqlQueryOptions::AsyncExec)
+        << false
+        << true;
+
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async No Results Query")))
+        << connectionDriver
+        << contactSelectNothingQuery
+        << 0
+        << int(QSparqlQueryOptions::AsyncExec)
+        << false
+        << false;
+
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async No Results Query Forward Only")))
+        << connectionDriver
+        << contactSelectNothingQuery
+        << 0
+        << int(QSparqlQueryOptions::AsyncExec)
+        << false
+        << true;
+
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Sync Query")))
+        << connectionDriver
+        << contactSelectQueryTemplate
+        << NUM_INSERTS
+        << int(QSparqlQueryOptions::SyncExec)
+        << false
+        << false;
+
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Sync No Results Query")))
+        << connectionDriver
+        << contactSelectNothingQuery
+        << 0
+        << int(QSparqlQueryOptions::SyncExec)
+        << false
+        << false;
+
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async Object Query")))
+        << connectionDriver
+        << contactSelectQueryTemplate
+        << NUM_INSERTS
+        << int(QSparqlQueryOptions::AsyncExec)
+        << true
+        << false;
+
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async Object Query Forward Only")))
+        << connectionDriver
+        << contactSelectQueryTemplate
+        << NUM_INSERTS
+        << int(QSparqlQueryOptions::AsyncExec)
+        << true
+        << true;
+
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async Object No Results Query")))
+        << connectionDriver
+        << contactSelectNothingQuery
+        << 0
+        << int(QSparqlQueryOptions::AsyncExec)
+        << true
+        << false;
+
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async Object No Results Query Forward Only")))
+        << connectionDriver
+        << contactSelectNothingQuery
+        << 0
+        << int(QSparqlQueryOptions::AsyncExec)
+        << true
+        << true;
+}
+
+void tst_QSparqlAPI::query_test_data()
+{
+    QTest::addColumn<QString>("connectionDriver");
+    QTest::addColumn<QString>("queryTemplate");
+    QTest::addColumn<int>("expectedResultsSize");
+    QTest::addColumn<int>("executionMethod");
+    QTest::addColumn<bool>("useAsyncObject");
+    QTest::addColumn<bool>("forwardOnly");
+    add_query_test_data("QTRACKER_DIRECT", "Tracker Direct");
+    add_query_test_data("QTRACKER", "Tracker DBus");
+    if (testEndpoint)
+        add_query_test_data("QSPARQL_ENDPOINT", "Endpoint");
+
+}
+
+void tst_QSparqlAPI::query_destroy_connection_after_finished_test()
+{
+    QFETCH(QString, connectionDriver);
+    QFETCH(QString, queryTemplate);
+    QFETCH(int, expectedResultsSize);
+    QFETCH(int, executionMethod);
+    QFETCH(bool, useAsyncObject);
+
+    QSparqlConnectionOptions options = getConnectionOptions(connectionDriver);
+    QSparqlConnection* conn = new QSparqlConnection(connectionDriver, options);
+
+    QSparqlQueryOptions queryOptions;
+    queryOptions.setExecutionMethod(QSparqlQueryOptions::ExecutionMethod(executionMethod));
+
+    const QString queryString = queryTemplate.arg( getTemplateArguments(connectionDriver, "SELECT") );
+    const QSparqlQuery q(queryString);
+
+    QSparqlResult* r = conn->exec(q, queryOptions);
+
+    // Re-parent the result to release from the ownership of conn
+    r->setParent(this);
+
+    checkExecutionMethod(r, executionMethod, useAsyncObject);
+    if (r->isFinished())
+    {
+        // Result is finished after wait: destroy connection and validate result
+        delete conn; conn = 0;
+    }
+
+    // Check that result is not in error and valid
+    QVERIFY( !r->hasError() );
+    validateResults(r, expectedResultsSize);
+
+    QVERIFY( r->isFinished() );
+    // Destroying connection after validation must not raise an error in the result
+    delete conn; conn = 0;
+    QVERIFY( !r->hasError() );
+
+    delete r;
+}
+
+void tst_QSparqlAPI::query_destroy_connection_after_finished_test_data()
+{
+    // Reuse test data from query_test
+    query_test_data();
+}
+
+void tst_QSparqlAPI::query_error_test()
+{
+    QFETCH(QString, connectionDriver);
+    QFETCH(QString, query);
+    QFETCH(int, executionMethod);
+    QFETCH(int, expectedErrorType);
+    QFETCH(bool, useAsyncObject);
+    QFETCH(bool, forwardOnly);
+
+    QSparqlConnectionOptions options = getConnectionOptions(connectionDriver);
+    QSparqlConnection conn(connectionDriver, options);
+
+    QSparqlQueryOptions queryOptions;
+    queryOptions.setForwardOnly(forwardOnly);
+    queryOptions.setExecutionMethod(QSparqlQueryOptions::ExecutionMethod(executionMethod));
+    const QSparqlQuery q(query);
+
+    QSparqlResult* r = conn.exec(q, queryOptions);
+
+    checkExecutionMethod(r, executionMethod, useAsyncObject);
+    validateErrorResult(r, expectedErrorType);
+    QCOMPARE((*msgRecorder)[QtWarningMsg].count(), 1);
+
+    delete r;
+}
+
+void tst_QSparqlAPI::add_query_error_test_data(const QString& connectionDriver, const QString& dataTagPrefix, bool supportsConstruct)
+{
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async Empty Query")))
+        << connectionDriver
+        << ""
+        << int(QSparqlQueryOptions::AsyncExec)
+        << int(QSparqlError::StatementError)
+        << false
+        << false;
+
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async Empty Query Forward Only")))
+        << connectionDriver
+        << ""
+        << int(QSparqlQueryOptions::AsyncExec)
+        << int(QSparqlError::StatementError)
+        << false
+        << true;
+
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async Object Empty Query")))
+        << connectionDriver
+        << ""
+        << int(QSparqlQueryOptions::AsyncExec)
+        << int(QSparqlError::StatementError)
+        << true
+        << false;
+
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async Object Empty Query Forward Only")))
+        << connectionDriver
+        << ""
+        << int(QSparqlQueryOptions::AsyncExec)
+        << int(QSparqlError::StatementError)
+        << true
+        << true;
+
+
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Sync Empty Query")))
+        << connectionDriver
+        << ""
+        << int(QSparqlQueryOptions::SyncExec)
+        << int(QSparqlError::StatementError)
+        << false
+        << false;
+
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async Invalid Query")))
+        << connectionDriver
+        << invalidQuery
+        << int(QSparqlQueryOptions::AsyncExec)
+        << int(QSparqlError::StatementError)
+        << false
+        << false;
+
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async Invalid Query Forward Only")))
+        << connectionDriver
+        << invalidQuery
+        << int(QSparqlQueryOptions::AsyncExec)
+        << int(QSparqlError::StatementError)
+        << false
+        << true;
+
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async Object Invalid Query")))
+        << connectionDriver
+        << invalidQuery
+        << int(QSparqlQueryOptions::AsyncExec)
+        << int(QSparqlError::StatementError)
+        << true
+        << false;
+
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async Object Invalid Query Forward Only")))
+        << connectionDriver
+        << invalidQuery
+        << int(QSparqlQueryOptions::AsyncExec)
+        << int(QSparqlError::StatementError)
+        << true
+        << true;
+
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Sync Invalid Query")))
+        << connectionDriver
+        << invalidQuery
+        << int(QSparqlQueryOptions::SyncExec)
+        << int(QSparqlError::StatementError)
+        << false
+        << false;
+
+    if (!supportsConstruct) {
+        QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async Unsupported Construct Query")))
+            << connectionDriver
+            << constructQuery
+            << int(QSparqlQueryOptions::AsyncExec)
+            << int(QSparqlError::BackendError)
+            << false
+            << false;
+
+        QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async Unsupported Construct Query Forward Only")))
+            << connectionDriver
+            << constructQuery
+            << int(QSparqlQueryOptions::AsyncExec)
+            << int(QSparqlError::BackendError)
+            << false
+            << false;
+
+        QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async Object Unsupported Construct Query")))
+            << connectionDriver
+            << constructQuery
+            << int(QSparqlQueryOptions::AsyncExec)
+            << int(QSparqlError::BackendError)
+            << true
+            << false;
+
+        QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async Object Unsupported Construct Query Forward Only")))
+            << connectionDriver
+            << constructQuery
+            << int(QSparqlQueryOptions::AsyncExec)
+            << int(QSparqlError::BackendError)
+            << true
+            << true;
+
+        QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Sync Unsupported Construct Query")))
+            << connectionDriver
+            << constructQuery
+            << int(QSparqlQueryOptions::SyncExec)
+            << int(QSparqlError::BackendError)
+            << false
+            << false;
+    }
+}
+
+void tst_QSparqlAPI::query_error_test_data()
+{
+    QTest::addColumn<QString>("connectionDriver");
+    QTest::addColumn<QString>("query");
+    QTest::addColumn<int>("executionMethod");
+    QTest::addColumn<int>("expectedErrorType");
+    QTest::addColumn<bool>("useAsyncObject");
+    QTest::addColumn<bool>("forwardOnly");
+    add_query_error_test_data("QTRACKER_DIRECT", "Tracker Direct", false);
+    add_query_error_test_data("QTRACKER", "Tracker DBus", false);
+    if (testEndpoint)
+        add_query_error_test_data("QSPARQL_ENDPOINT", "Endpoint", true);
+}
+
+void tst_QSparqlAPI::query_destroy_connection_test()
+{
+    QFETCH(QString, connectionDriver);
+    QFETCH(QString, query);
+    QFETCH(int, expectedResultsSize);
+    QFETCH(int, executionMethod);
+    QFETCH(bool, useAsyncObject);
+    QFETCH(bool, forwardOnly);
+
+    QSparqlConnectionOptions options = getConnectionOptions(connectionDriver);
+    QSparqlConnection *conn = new QSparqlConnection(connectionDriver, options);
+
+    QSparqlQueryOptions queryOptions;
+    queryOptions.setForwardOnly(forwardOnly);
+    queryOptions.setExecutionMethod(QSparqlQueryOptions::ExecutionMethod(executionMethod));
+
+    const QString queryString = query.arg( getTemplateArguments(connectionDriver, "SELECT") );
+    const QSparqlQuery q(queryString);
+
+    QSparqlResult* r = conn->exec(q, queryOptions);
+    const bool immediatelyFinished = r->isFinished();
+
+    // Re-parent the result to release it from the connection's ownership
+    r->setParent(this);
+    delete conn; conn = 0;
+
+    if (immediatelyFinished) {
+        // If the query completes immediately, before the connection is
+        // destroyed, it should not be in error and should contain valid data
+        QVERIFY(!r->hasError());
+        checkExecutionMethod(r, executionMethod, useAsyncObject);
+        validateResults(r, expectedResultsSize);
+    }
+    else {
+        // If the result was not finished immediately after exec, it should be in
+        // error after connection close
+        QVERIFY(r->hasError());
+        QVERIFY(r->lastError().type() == QSparqlError::ConnectionError);
+
+        checkExecutionMethod(r, executionMethod, useAsyncObject);
+        QVERIFY(r->hasError());
+        QVERIFY(r->lastError().type() == QSparqlError::ConnectionError);
+
+        validateResults(r, 0);
+    }
+
+    // There must always be a warning about connection closed before result
+    QCOMPARE((*msgRecorder)[QtWarningMsg].count(), 1);
+
+    delete r;
+}
+
+void tst_QSparqlAPI::add_query_destroy_connection_test_data(const QString& connectionDriver, const QString& dataTagPrefix)
+{
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async Query")))
+        << connectionDriver
+        << contactSelectQueryTemplate
+        << NUM_INSERTS
+        << int(QSparqlQueryOptions::AsyncExec)
+        << false
+        << false;
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async Query Forward Only")))
+        << connectionDriver
+        << contactSelectQueryTemplate
+        << NUM_INSERTS
+        << int(QSparqlQueryOptions::AsyncExec)
+        << false
+        << true;
+
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async Object Query")))
+        << connectionDriver
+        << contactSelectQueryTemplate
+        << NUM_INSERTS
+        << int(QSparqlQueryOptions::AsyncExec)
+        << true
+        << false;
+
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async Object Query Forward Only")))
+        << connectionDriver
+        << contactSelectQueryTemplate
+        << NUM_INSERTS
+        << int(QSparqlQueryOptions::AsyncExec)
+        << true
+        << true;
+
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Sync Query")))
+        << connectionDriver
+        << contactSelectQueryTemplate
+        << NUM_INSERTS
+        << int(QSparqlQueryOptions::SyncExec)
+        << false
+        << false;
+}
+
+void tst_QSparqlAPI::query_destroy_connection_test_data()
+{
+    QTest::addColumn<QString>("connectionDriver");
+    QTest::addColumn<QString>("query");
+    QTest::addColumn<int>("expectedResultsSize");
+    QTest::addColumn<int>("executionMethod");
+    QTest::addColumn<bool>("useAsyncObject");
+    QTest::addColumn<bool>("forwardOnly");
+    add_query_destroy_connection_test_data("QTRACKER_DIRECT", "Tracker Direct");
+    add_query_destroy_connection_test_data("QTRACKER", "Tracker DBus");
+    if (testEndpoint)
+        add_query_destroy_connection_test_data("QSPARQL_ENDPOINT", "Endpoint");
+}
+
+void tst_QSparqlAPI::update_query_test()
+{
+    QFETCH(QString, connectionDriver);
+    QFETCH(QString, insertTemplate);
+    QFETCH(QString, deleteTemplate);
+    QFETCH(int, initialSize);
+    QFETCH(int, contactInserts);
+    QFETCH(int, contactDeletes);
+    QFETCH(int, executionMethod);
+    QFETCH(bool, useAsyncObject);
+
+    QSparqlConnectionOptions options = getConnectionOptions(connectionDriver);
+    QSparqlConnection conn(connectionDriver, options);
+
+    const int expectedResultsSize = initialSize + contactInserts;
+
+    QString insertQuery = contactInsertHeader.arg( getTemplateArguments(connectionDriver, "INSERT") ); //
+
+    for (int item = initialSize+1; item <= expectedResultsSize; item++) {
+        insertQuery.append( insertTemplate.arg(item) );
+    }
+    insertQuery.append(" }");
+
+    QSparqlQueryOptions queryOptions;
+    queryOptions.setExecutionMethod(QSparqlQueryOptions::ExecutionMethod(executionMethod));
+    const QSparqlQuery q(insertQuery, QSparqlQuery::InsertStatement);
+
+    QSparqlResult* r = conn.exec(q, queryOptions);
+
+    checkExecutionMethod(r, executionMethod, useAsyncObject);
+
+    // Update query binding values will return empty bindings
+    QCOMPARE(QString(""), r->binding(0).value().toString());
+    QCOMPARE(QString(""), r->binding(1).value().toString());
+    // Check the value() for the same thing
+    QCOMPARE(QString(""), r->value(0).toString());
+    // for updates, current() should return a empty result row
+    QCOMPARE(QSparqlResultRow(), r->current());
+    // and size should be 0
+    if (r->hasFeature(QSparqlResult::QuerySize) )
+        QCOMPARE(r->size(), 0);
+    delete r;
+
+    // Verify the insertion
+    QString validateQuery = contactSelectQueryTemplate.arg(getTemplateArguments(connectionDriver, "SELECT"));
+    r = conn.exec(QSparqlQuery(validateQuery), queryOptions);
+    checkExecutionMethod(r, executionMethod, useAsyncObject);
+    validateResults(r, expectedResultsSize);
+    delete r;
+
+    // Delete the insertion
+    QString deleteQuery = contactDeleteHeader.arg( getTemplateArguments(connectionDriver, "DELETE") ); //"delete { <qsparql-api-tests> a nie:InformationElement .";
+    for (int item = initialSize+1; item <= expectedResultsSize; item++) {
+        deleteQuery.append( deleteTemplate.arg(item) );
+    }
+    deleteQuery.append(" }");
+
+    const QSparqlQuery delQuery(deleteQuery, QSparqlQuery::DeleteStatement);
+    r = conn.exec(delQuery, queryOptions);
+    checkExecutionMethod(r, executionMethod, useAsyncObject);
+    delete r;
+
+    // Now verify deletion
+    r = conn.exec(QSparqlQuery(validateQuery), queryOptions);
+    checkExecutionMethod(r, executionMethod, useAsyncObject);
+    validateResults(r, expectedResultsSize - contactDeletes);
+    delete r;
+}
+
+void tst_QSparqlAPI::add_update_query_test_data(const QString& connectionDriver, const QString& dataTagPrefix)
+{
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async Update Query")))
+        << connectionDriver
+        << contactInsertQueryTemplate
+        << contactDeleteQueryTemplate
+        << NUM_INSERTS
+        << contactInsertAmount
+        << contactDeleteAmount
+        << int(QSparqlQueryOptions::AsyncExec)
+        << false;
+
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async Object Update Query")))
+        << connectionDriver
+        << contactInsertQueryTemplate
+        << contactDeleteQueryTemplate
+        << NUM_INSERTS
+        << contactInsertAmount
+        << contactDeleteAmount
+        << int(QSparqlQueryOptions::AsyncExec)
+        << true;
+
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Sync Update Query")))
+        << connectionDriver
+        << contactInsertQueryTemplate
+        << contactDeleteQueryTemplate
+        << NUM_INSERTS
+        << contactInsertAmount
+        << contactDeleteAmount
+        << int(QSparqlQueryOptions::SyncExec)
+        << false;
+}
+
+void tst_QSparqlAPI::update_query_test_data()
+{
+    QTest::addColumn<QString>("connectionDriver");
+    QTest::addColumn<QString>("insertTemplate");
+    QTest::addColumn<QString>("deleteTemplate");
+    QTest::addColumn<int>("initialSize");
+    QTest::addColumn<int>("contactInserts");
+    QTest::addColumn<int>("contactDeletes");
+    QTest::addColumn<int>("executionMethod");
+    QTest::addColumn<bool>("useAsyncObject");
+    add_update_query_test_data("QTRACKER_DIRECT", "Tracker Direct");
+    add_update_query_test_data("QTRACKER", "Tracker DBus");
+    if (testEndpoint)
+        add_update_query_test_data("QSPARQL_ENDPOINT", "Endpoint");
+}
+
+void tst_QSparqlAPI::update_query_error_test()
+{
+    QFETCH(QString, connectionDriver);
+    QFETCH(QString, query);
+    QFETCH(int, executionMethod);
+    QFETCH(int, expectedErrorType);
+    QFETCH(bool, useAsyncObject);
+
+    QSparqlQuery::StatementType queryType = QSparqlQuery::InsertStatement;
+    for (int round = 1; round <= 2; ++round) {
+        QSparqlConnectionOptions options = getConnectionOptions(connectionDriver);
+        QSparqlConnection conn(connectionDriver, options);
+        QSparqlQueryOptions queryOptions;
+        queryOptions.setExecutionMethod(QSparqlQueryOptions::ExecutionMethod(executionMethod));
+        const QSparqlQuery q(query, queryType);
+
+        QSparqlResult* r = conn.exec(q, queryOptions);
+
+        checkExecutionMethod(r, executionMethod, useAsyncObject);
+        validateErrorResult(r, expectedErrorType);
+        QCOMPARE((*msgRecorder)[QtWarningMsg].count(), round);
+
+        delete r;
+        // also check delete statments
+        queryType = QSparqlQuery::DeleteStatement;
+    }
+}
+
+void tst_QSparqlAPI::add_update_query_error_test_data(const QString& connectionDriver, const QString& dataTagPrefix, bool supportsConstruct)
+{
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async Empty Query")))
+        << connectionDriver
+        << ""
+        << int(QSparqlQueryOptions::AsyncExec)
+        << int(QSparqlError::StatementError)
+        << false;
+
+   QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async Object Empty Query")))
+        << connectionDriver
+        << ""
+        << int(QSparqlQueryOptions::AsyncExec)
+        << int(QSparqlError::StatementError)
+        << true;
+
+   QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Sync Empty Query")))
+       << connectionDriver
+       << ""
+       << int(QSparqlQueryOptions::SyncExec)
+       << int(QSparqlError::StatementError)
+       << false;
+
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async Invalid Query")))
+        << connectionDriver
+        << invalidQuery
+        << int(QSparqlQueryOptions::AsyncExec)
+        << int(QSparqlError::StatementError)
+        << false;
+
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async Object Invalid Query")))
+        << connectionDriver
+        << invalidQuery
+        << int(QSparqlQueryOptions::AsyncExec)
+        << int(QSparqlError::StatementError)
+        << true;
+
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Sync Invalid Query")))
+        << connectionDriver
+        << invalidQuery
+        << int(QSparqlQueryOptions::SyncExec)
+        << int(QSparqlError::StatementError)
+        << false;
+
+    if (!supportsConstruct) {
+        QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async Unsupported Construct Query")))
+            << connectionDriver
+            << constructQuery
+            << int(QSparqlQueryOptions::AsyncExec)
+            << int(QSparqlError::StatementError)
+            << false;
+
+        QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async Object Unsupported Construct Query")))
+            << connectionDriver
+            << constructQuery
+            << int(QSparqlQueryOptions::AsyncExec)
+            << int(QSparqlError::StatementError)
+            << true;
+
+        QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Sync Unsupported Construct Query")))
+            << connectionDriver
+            << constructQuery
+            << int(QSparqlQueryOptions::SyncExec)
+            << int(QSparqlError::StatementError)
+            << false;
+    }
+}
+
+void tst_QSparqlAPI::update_query_error_test_data()
+{
+    QTest::addColumn<QString>("connectionDriver");
+    QTest::addColumn<QString>("query");
+    QTest::addColumn<int>("executionMethod");
+    QTest::addColumn<int>("expectedErrorType");
+    QTest::addColumn<bool>("useAsyncObject");
+    add_update_query_error_test_data("QTRACKER_DIRECT", "Tracker Direct", false);
+    add_update_query_error_test_data("QTRACKER", "Tracker DBus", false);
+    if (testEndpoint)
+        add_update_query_error_test_data("QSPARQL_ENDPOINT", "Endpoint", true);
+}
+
+void tst_QSparqlAPI::update_query_destroy_connection_test()
+{
+    QFETCH(QString, connectionDriver);
+    QFETCH(QString, query);
+    QFETCH(int, executionMethod);
+    QFETCH(bool, useAsyncObject);
+    QFETCH(QString, deleteQuery);
+
+    QSparqlConnectionOptions cleanupOptions = getConnectionOptions(connectionDriver);
+    QSparqlConnection cleanupConn(connectionDriver, cleanupOptions);
+
+    QSparqlQuery::StatementType queryType = QSparqlQuery::InsertStatement;
+    for (int round = 1; round <= 2; ++round) {
+        QSparqlConnectionOptions options = getConnectionOptions(connectionDriver);
+        QSparqlConnection* conn = new QSparqlConnection(connectionDriver, options);
+        QSparqlQueryOptions queryOptions;
+        queryOptions.setExecutionMethod(QSparqlQueryOptions::ExecutionMethod(executionMethod));
+        const QSparqlQuery q(query, queryType);
+
+        QSparqlResult* r = conn->exec(q, queryOptions);
+        const bool immediatelyFinished = r->isFinished();
+        QVERIFY(!r->hasError());
+        // Re-parent the result to release it from the connection's ownership
+        r->setParent(this);
+        delete conn; conn = 0;
+
+        checkExecutionMethod(r, executionMethod, useAsyncObject);
+
+        if (!immediatelyFinished) {
+            // If the result was not immediately finished after exec it should have an error
+            QVERIFY(r->hasError());
+            QVERIFY(r->lastError().type() == QSparqlError::ConnectionError);
+        }
+        validateResults(r, 0);
+        // Check we got a warning
+        QCOMPARE((*msgRecorder)[QtWarningMsg].count(), round);
+        delete r;
+
+        QSparqlResult* cleanupResult = cleanupConn.syncExec(
+                QSparqlQuery(deleteQuery, QSparqlQuery::DeleteStatement));
+        CHECK_QSPARQL_RESULT(cleanupResult);
+        delete cleanupResult;
+
+        // also check delete statments
+        queryType = QSparqlQuery::DeleteStatement;
+    }
+}
+
+void tst_QSparqlAPI::add_update_query_destroy_connection_test_data(const QString& connectionDriver, const QString& dataTagPrefix)
+{
+    QString insertQuery = contactInsertHeader.arg( getTemplateArguments(connectionDriver, "INSERT") );
+    insertQuery.append(contactInsertQueryTemplate.arg(NUM_INSERTS+1));
+    insertQuery.append(" }");
+
+    QString deleteQuery = contactDeleteHeader.arg( getTemplateArguments(connectionDriver, "DELETE") );
+    deleteQuery.append(contactDeleteQueryTemplate.arg(NUM_INSERTS+1));
+    deleteQuery.append(" }");
+
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async Query")))
+        << connectionDriver
+        << insertQuery
+        << int(QSparqlQueryOptions::AsyncExec)
+        << false
+        << deleteQuery;
+
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async Object Query")))
+        << connectionDriver
+        << insertQuery
+        << int(QSparqlQueryOptions::AsyncExec)
+        << true
+        << deleteQuery;
+
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Sync Query")))
+        << connectionDriver
+        << insertQuery
+        << int(QSparqlQueryOptions::SyncExec)
+        << false
+        << deleteQuery;
+}
+
+void tst_QSparqlAPI::update_query_destroy_connection_test_data()
+{
+    QTest::addColumn<QString>("connectionDriver");
+    QTest::addColumn<QString>("query");
+    QTest::addColumn<int>("executionMethod");
+    QTest::addColumn<bool>("useAsyncObject");
+    QTest::addColumn<QString>("deleteQuery");
+    add_update_query_destroy_connection_test_data("QTRACKER_DIRECT", "Tracker Direct");
+    add_update_query_destroy_connection_test_data("QTRACKER", "Tracker DBus");
+    if (testEndpoint)
+        add_update_query_destroy_connection_test_data("QSPARQL_ENDPOINT", "Endpoint");
+}
+
+void tst_QSparqlAPI::ask_query_test()
+{
+    QFETCH(QString, connectionDriver);
+    QFETCH(QString, query);
+    QFETCH(int, executionMethod);
+    QFETCH(bool, expectedResult);
+    QFETCH(bool, useAsyncObject);
+    QFETCH(bool, forwardOnly);
+
+    QSparqlConnectionOptions options = getConnectionOptions(connectionDriver);
+    QSparqlConnection conn(connectionDriver, options);
+    QVERIFY(conn.hasFeature(QSparqlConnection::AskQueries));
+
+    const QSparqlQuery q(query, QSparqlQuery::AskStatement);
+
+    QSparqlQueryOptions queryOptions;
+    queryOptions.setForwardOnly(forwardOnly);
+    queryOptions.setExecutionMethod(QSparqlQueryOptions::ExecutionMethod(executionMethod));
+
+    QSparqlResult *r = conn.exec(q, queryOptions);
+
+    checkExecutionMethod(r, executionMethod, useAsyncObject);
+    const bool immediatelyFinished = r->isFinished();
+
+    if (immediatelyFinished) {
+        QVERIFY(!r->hasError());
+        // Boolean results are retrieved immediately without the need to call next() for conveniency
+        QVERIFY(r->isBool());
+        QCOMPARE(r->boolValue(), expectedResult);
+        QCOMPARE(r->size(), 1);
+    }
+
+    int resultSize = 0;
+    while (r->next()) {
+        if (++resultSize <= 1) {
+            QVERIFY(validateCurrentBoolResult(r, expectedResult));
+        }
+        else {
+            qDebug() << "Unexpected result row for an ask query:" << r->current();
+        }
+    }
+    QVERIFY(r->isFinished());
+    QCOMPARE(resultSize, 1);
+
+    delete r;
+}
+
+void tst_QSparqlAPI::add_ask_query_test_data(const QString& connectionDriver, const QString& dataTagPrefix)
+{
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async True Query")))
+        << connectionDriver
+        << int(QSparqlQueryOptions::AsyncExec)
+        << askQueryTrue
+        << true
+        << false
+        << false;
+
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async Forward Only True Query")))
+        << connectionDriver
+        << int(QSparqlQueryOptions::AsyncExec)
+        << askQueryTrue
+        << true
+        << false
+        << true;
+
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async Object True Query")))
+        << connectionDriver
+        << int(QSparqlQueryOptions::AsyncExec)
+        << askQueryTrue
+        << true
+        << true
+        << false;
+
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async Object Forward Only True Query")))
+        << connectionDriver
+        << int(QSparqlQueryOptions::AsyncExec)
+        << askQueryTrue
+        << true
+        << true
+        << true;
+
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Sync True Query")))
+        << connectionDriver
+        << int(QSparqlQueryOptions::SyncExec)
+        << askQueryTrue
+        << true
+        << false
+        << false;
+
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async False Query")))
+        << connectionDriver
+        << int(QSparqlQueryOptions::AsyncExec)
+        << askQueryFalse
+        << false
+        << false
+        << false;
+
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async Forward Only False Query")))
+        << connectionDriver
+        << int(QSparqlQueryOptions::AsyncExec)
+        << askQueryFalse
+        << false
+        << false
+        << true;
+
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async Object False Query")))
+        << connectionDriver
+        << int(QSparqlQueryOptions::AsyncExec)
+        << askQueryFalse
+        << false
+        << true
+        << false;
+
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Async Object Forward Only False Query")))
+        << connectionDriver
+        << int(QSparqlQueryOptions::AsyncExec)
+        << askQueryFalse
+        << false
+        << true
+        << true;
+
+    QTest::newRow(qPrintable(QString(dataTagPrefix).append(" Sync False Query")))
+        << connectionDriver
+        << int(QSparqlQueryOptions::SyncExec)
+        << askQueryFalse
+        << false
+        << false
+        << false;
+}
+
+void tst_QSparqlAPI::ask_query_test_data()
+{
+    QTest::addColumn<QString>("connectionDriver");
+    QTest::addColumn<int>("executionMethod");
+    QTest::addColumn<QString>("query");
+    QTest::addColumn<bool>("expectedResult");
+    QTest::addColumn<bool>("useAsyncObject");
+    QTest::addColumn<bool>("forwardOnly");
+    add_ask_query_test_data("QTRACKER_DIRECT", "Tracker Direct");
+    add_ask_query_test_data("QTRACKER", "Tracker DBus");
+    if (testEndpoint)
+        add_ask_query_test_data("QSPARQL_ENDPOINT", "Endpoint");
+}
+
+void tst_QSparqlAPI::isFinished_test()
+{
+    QFETCH(QString, connectionDriver);
+    QFETCH(QString, queryTemplate);
+    QFETCH(int, expectedResultsSize);
+    QFETCH(int, executionMethod);
+    QFETCH(bool, useAsyncObject);
+    QFETCH(bool, forwardOnly);
+
+    QSparqlConnectionOptions options = getConnectionOptions(connectionDriver);
+    QSparqlConnection conn(connectionDriver, options);
+
+    QSparqlQueryOptions queryOptions;
+    queryOptions.setForwardOnly(forwardOnly);
+    queryOptions.setExecutionMethod(QSparqlQueryOptions::ExecutionMethod(executionMethod));
+
+    const QString queryString = queryTemplate.arg( getTemplateArguments(connectionDriver, "SELECT") );
+    const QSparqlQuery q(queryString);
+
+    QSparqlResult* r = conn.exec(q, queryOptions);
+
+    checkExecutionMethod(r, executionMethod, useAsyncObject);
+
+    // According to the documentation, isFinished() will be false for sync queries
+    // until the results have been iterated
+    // If the result has been set as ForwardOnly, it should behave in the same
+    // way as a Sync result, so also check that here by also testing
+    // if the result reports as ForwardOnly
+    bool forwardOnlyResult = r->hasFeature(QSparqlResult::ForwardOnly);
+    if ((executionMethod == QSparqlQueryOptions::SyncExec &&
+        conn.hasFeature(QSparqlConnection::SyncExec)) || forwardOnlyResult) {
+        QVERIFY(!r->isFinished());
+        validateResults(r, expectedResultsSize);
+        QVERIFY(r->isFinished());
+    } else {
+        QVERIFY(r->isFinished());
+        validateResults(r, expectedResultsSize);
+        QVERIFY(r->isFinished());
+    }
+
+    delete r;
+}
+
+void tst_QSparqlAPI::isFinished_test_data()
+{
+    query_test_data();
+}
+
+void tst_QSparqlAPI::queryModel_test()
+{
+    QFETCH(QString, connectionDriver);
+    QFETCH(QString, query);
+    QFETCH(int, expectedResultsSize);
+
+    QSparqlConnectionOptions options = getConnectionOptions(connectionDriver);
+    QSparqlConnection conn(connectionDriver, options);
+    QSparqlQueryModel model;
+
+    model.setQuery(QSparqlQuery(query), conn);
+
+    FinishedSignalReceiver signalReceiver;
+    signalReceiver.connectFinished(&model);
+    signalReceiver.waitForFinished(2000);
+    signalReceiver.ensureOneFinishedReceived(100);
+
+    QCOMPARE(model.rowCount(), expectedResultsSize);
+    QCOMPARE(model.columnCount(), contactSelectColumnCount);
+
+    // Test the results against a query to get the insertion order
+    QList<QString> insertOrder;
+    QSparqlResult *r = conn.syncExec(QSparqlQuery(query));
+    while (r->next())
+    {
+        insertOrder.append(r->value(0).toString());
+        insertOrder.append(r->value(1).toString());
+    }
+
+    // Verify the data in the model
+    for (int i=0;i<model.rowCount();i++) {
+        QSparqlResultRow row = model.resultRow(i);
+        QCOMPARE(insertOrder.at(0), row.value(0).toString());
+        // inserted as uri, then name, so just pop the front
+        insertOrder.pop_front();
+        QCOMPARE(insertOrder.at(0), row.value(1).toString());
+        insertOrder.pop_front();
+    }
+
+    delete r;
+}
+
+void tst_QSparqlAPI::queryModel_test_data()
+{
+    QTest::addColumn<QString>("connectionDriver");
+    QTest::addColumn<QString>("query");
+    QTest::addColumn<int>("expectedResultsSize");
+
+    QTest::newRow("DBus Query Model")
+        << "QTRACKER"
+        << contactSelectQueryTemplate.arg("")
+        << NUM_INSERTS;
+
+    QTest::newRow("Tracker Direct Query Model")
+        << "QTRACKER_DIRECT"
+        << contactSelectQueryTemplate.arg("")
+        << NUM_INSERTS;
+
+    if (testEndpoint) {
+        QTest::newRow("Endpoint Query Model")
+            << "QSPARQL_ENDPOINT"
+            << contactSelectQueryTemplate.arg( getTemplateArguments("QSPARQL_ENDPOINT", "SELECT") )
+            << NUM_INSERTS;
+    }
+}
+
+void tst_QSparqlAPI::syncExec_waitForFinished_query_test()
+{
+    QFETCH(QString, connectionDriver);
+    QFETCH(QString, query);
+    QFETCH(int, expectedResultsSize);
+
+    QSparqlConnectionOptions options = getConnectionOptions(connectionDriver);
+    QSparqlConnection conn(connectionDriver, options);
+    const QSparqlQuery q(query);
+    QSparqlResult* r = conn.syncExec(q);
+    QVERIFY(!r->hasError());
+    r->waitForFinished();
+    QVERIFY(!r->hasError());
+
+    validateResults(r, expectedResultsSize);
+    delete r;
+}
+
+void tst_QSparqlAPI::syncExec_waitForFinished_query_test_data()
+{
+    QTest::addColumn<QString>("connectionDriver");
+    QTest::addColumn<QString>("query");
+    QTest::addColumn<int>("expectedResultsSize");
+
+    QTest::newRow("Tracker Direct Sync Select")
+        << "QTRACKER_DIRECT"
+        << contactSelectQueryTemplate.arg("")
+        << NUM_INSERTS;
+
+    QTest::newRow("DBus Sync Select")
+        << "QTRACKER"
+        << contactSelectQueryTemplate.arg("")
+        << NUM_INSERTS;
+
+    if (testEndpoint) {
+        QTest::newRow("Endpoint Sync Select")
+            << "QSPARQL_ENDPOINT"
+            << contactSelectQueryTemplate.arg( getTemplateArguments("QSPARQL_ENDPOINT", "SELECT") )
+            << NUM_INSERTS;
+    }
+}
+
+void tst_QSparqlAPI::syncExec_waitForFinished_update_query_test()
+{
+    QFETCH(QString, connectionDriver);
+    QFETCH(QString, insertTemplate);
+    QFETCH(QString, deleteTemplate);
+    QFETCH(QString, validateQuery);
+    QFETCH(int, initialSize);
+    QFETCH(int, contactInserts);
+    QFETCH(int, contactDeletes);
+
+    QSparqlConnectionOptions options = getConnectionOptions(connectionDriver);
+    QSparqlConnection conn(connectionDriver, options);
+    const int expectedResultsSize = initialSize + contactInserts;
+
+    QString insertQuery = contactInsertHeader.arg( getTemplateArguments(connectionDriver, "INSERT") );
+    for (int item = initialSize+1; item <= expectedResultsSize; item++) {
+        insertQuery.append( insertTemplate.arg(item) );
+    }
+    insertQuery.append(" }");
+
+    const QSparqlQuery q(insertQuery, QSparqlQuery::InsertStatement);
+    QSparqlResult* r = conn.syncExec(q);
+    QVERIFY(!r->hasError());
+    r->waitForFinished();
+    QVERIFY(!r->hasError());
+    delete r;
+
+    // Verify the insertion
+    r = conn.syncExec(QSparqlQuery(validateQuery));
+    r->waitForFinished();
+    validateResults(r, expectedResultsSize);
+    delete r;
+
+    // Delete the insertion
+    QString deleteQuery = contactDeleteHeader.arg( getTemplateArguments(connectionDriver, "DELETE") );
+    for (int item = initialSize+1; item <= expectedResultsSize; item++) {
+        deleteQuery.append( deleteTemplate.arg(item) );
+    }
+    deleteQuery.append(" }");
+
+    QSparqlQuery delQuery(deleteQuery, QSparqlQuery::DeleteStatement);
+    r = conn.syncExec(delQuery);
+    QVERIFY(!r->hasError());
+    r->waitForFinished();
+    QVERIFY(!r->hasError());
+    delete r;
+
+    // Now verify deletion
+    r = conn.syncExec(QSparqlQuery(validateQuery));
+    r->waitForFinished();
+    validateResults(r, expectedResultsSize - contactDeletes);
+    delete r;
+}
+
+void tst_QSparqlAPI::syncExec_waitForFinished_update_query_test_data()
+{
+    QTest::addColumn<QString>("connectionDriver");
+    QTest::addColumn<QString>("insertTemplate");
+    QTest::addColumn<QString>("deleteTemplate");
+    QTest::addColumn<QString>("validateQuery");
+    QTest::addColumn<int>("initialSize");
+    QTest::addColumn<int>("contactInserts");
+    QTest::addColumn<int>("contactDeletes");
+
+    QTest::newRow("Tracker Direct Sync Update Query")
+        << "QTRACKER_DIRECT"
+        << contactInsertQueryTemplate
+        << contactDeleteQueryTemplate
+        << contactSelectQueryTemplate.arg("")
+        << NUM_INSERTS
+        << contactInsertAmount
+        << contactDeleteAmount;
+
+    QTest::newRow("DBus Sync Update Query")
+        << "QTRACKER"
+        << contactInsertQueryTemplate
+        << contactDeleteQueryTemplate
+        << contactSelectQueryTemplate.arg("")
+        << NUM_INSERTS
+        << contactInsertAmount
+        << contactDeleteAmount;
+
+    if (testEndpoint) {
+        QTest::newRow("Endpoint Sync Update Query")
+            << "QSPARQL_ENDPOINT"
+            << contactInsertQueryTemplate
+            << contactDeleteQueryTemplate
+            << contactSelectQueryTemplate.arg( getTemplateArguments("QSPARQL_ENDPOINT", "SELECT") )
+            << NUM_INSERTS
+            << contactInsertAmount
+            << contactDeleteAmount;
+    }
+}
+
+void tst_QSparqlAPI::query_with_prefix()
+{
+    QFETCH(QString, connectionDriver);
+    QFETCH(QString, queryTemplate);
+    QFETCH(int, expectedResultsSize);
+    QFETCH(int, executionMethod);
+    QFETCH(bool, useAsyncObject);
+    
+    QSparqlConnectionOptions options = getConnectionOptions(connectionDriver);
+    QSparqlConnection conn(connectionDriver, options);
+    conn.addPrefix("alias", QUrl("http://www.semanticdesktop.org/ontologies/2007/03/22/nco#"));
+    
+    QSparqlQueryOptions queryOptions;
+    queryOptions.setExecutionMethod(QSparqlQueryOptions::ExecutionMethod(executionMethod));
+    
+    const QString queryString = queryTemplate.arg( getTemplateArguments(connectionDriver, "SELECT") ).
+                                replace(QString("nco"), QString("alias"));
+    const QSparqlQuery q(queryString);
+    
+    QSparqlResult* r = conn.exec(q, queryOptions);
+    checkExecutionMethod(r, executionMethod, useAsyncObject);
+    validateResults(r, expectedResultsSize);
+    
+    conn.clearPrefixes();
+    
+    r = conn.exec(q, queryOptions);
+    checkExecutionMethod(r, executionMethod, useAsyncObject);
+    QVERIFY(r->hasError());
+    
+    delete r;
+}
+
+void tst_QSparqlAPI::query_with_prefix_data()
+{
+    query_test_data();
+}
+
+void tst_QSparqlAPI::go_beyond_columns_number()
+{
+    QFETCH(QString, connectionDriver);
+    QFETCH(QString, queryTemplate);
+    QFETCH(int, expectedResultsSize);
+    QFETCH(int, executionMethod);
+    QFETCH(bool, useAsyncObject);
+
+    QSparqlConnectionOptions options = getConnectionOptions(connectionDriver);
+    QSparqlConnection conn(connectionDriver, options);
+
+    QSparqlQueryOptions queryOptions;
+    queryOptions.setExecutionMethod(QSparqlQueryOptions::ExecutionMethod(executionMethod));
+
+    const QString queryString = queryTemplate.arg( getTemplateArguments(connectionDriver, "SELECT") );
+    const QSparqlQuery q(queryString);
+
+    QSparqlResult* r = conn.exec(q, queryOptions);
+    checkExecutionMethod(r, executionMethod, useAsyncObject);
+
+    while (r->next()) {
+        QCOMPARE(r->current().count(), 2);
+        QCOMPARE(r->value(expectedResultsSize+1).toString(), QString());
+        QCOMPARE(r->binding(expectedResultsSize+1).toString(), QString());
+        QCOMPARE(r->binding(-2).toString(), QString());
+    }
+    delete r;
+}
+
+void tst_QSparqlAPI::go_beyond_columns_number_data()
+{
+    query_test_data();
+}
+
+QTEST_MAIN( tst_QSparqlAPI )
+#include "tst_qsparql_api.moc"
--- tests/auto/qsparql_benchmark/qsparql_benchmark.pro
+++ tests/auto/qsparql_benchmark/qsparql_benchmark.pro
@@ -1,7 +1,7 @@
 include(../sparqltest.pri)
 CONFIG += qt warn_on console depend_includepath testcase link_pkgconfig
 PKGCONFIG = tracker-sparql-0.10
-QT += testlib
+QT += testlib xml
 SOURCES  += tst_qsparql_benchmark.cpp
 
 #QT = sparql # enable this later
--- tests/auto/qsparql_benchmark/tst_qsparql_benchmark.cpp
+++ tests/auto/qsparql_benchmark/tst_qsparql_benchmark.cpp
@@ -43,9 +43,9 @@
 
 #include <QtTest/QtTest>
 #include <QtSparql/QtSparql>
-
 #include <sys/time.h>
 #include <stdio.h>
+#include <QDomDocument>
 
 #define START_BENCHMARK \
     int benchmarkTotal=0; { \
@@ -70,10 +70,17 @@
     int average = 0; \
     for(int i=0;i<LIST.size();i++) \
         average += LIST[i]; \
-    fprintf(stderr, "%s total time %i\n", qPrintable(BENCHMARKNAME), average); \
-    fprintf(stderr, "%s median value = %i\n", qPrintable(BENCHMARKNAME), LIST[median]); \
-    fprintf(stderr, "%s mean value = %i\n", qPrintable(BENCHMARKNAME), average/LIST.size()); }
-
+    QString underline; \
+    for(int i=0;i<BENCHMARKNAME.size();i++) \
+    { \
+        underline.append("-"); \
+    } \
+    fprintf(stderr, "\n%s\n%s\n\n", qPrintable(BENCHMARKNAME), qPrintable(underline)); \
+    fprintf(stderr, "median\t\t\t\t\t\t\t%i\n", LIST[median]); \
+    fprintf(stderr, "mean\t\t\t\t\t\t\t%i\n", average/LIST.size());\
+    fprintf(stderr, "total time\t\t\t\t\t\t%i\n\n", average); \
+    appendResult(BENCHMARKNAME, LIST[median], average/LIST.size(), average); \
+    }
 #define NO_QUERIES 100
 
 class tst_QSparqlBenchmark : public QObject
@@ -91,6 +98,9 @@
     void cleanup();
 
 private slots:
+    // Data injection
+    void trackerDataInjection();
+
     // Actual benchmarks
     void queryBenchmark();
     void queryBenchmark_data();
@@ -98,9 +108,6 @@
     void dataReadingBenchmark();
     void dataReadingBenchmark_data();
 
-    void dataReadingBenchmarkSync();
-    void dataReadingBenchmarkSync_data();
-
     // Reference benchmarks
     void queryWithLibtrackerSparql();
     void queryWithLibtrackerSparql_data();
@@ -109,6 +116,10 @@
     void queryWithLibtrackerSparqlInThread_data();
 
     void threadCreatingOverhead();
+    void generateResultsReport();
+private:
+    void appendResult(QString name, int median, int mean, int total);
+    QDomDocument result;
 };
 
 namespace {
@@ -119,7 +130,8 @@
     "SELECT nmm:artistName(?artist) GROUP_CONCAT(nie:title(?album),'|') "
     "WHERE "
     "{ "
-    "?song a nmm:MusicPiece . "
+    "?song a nmm:MusicPiece ; "
+    "nie:isLogicalPartOf <qsparql-benchmark-tests> . "
     "?song nmm:performer ?artist . "
     "?song nmm:musicAlbum ?album . "
         "} GROUP BY ?artist";
@@ -136,7 +148,8 @@
     "tracker:id(?song) tracker:id(nmm:performer(?song)) "
     "tracker:id(nmm:musicAlbum(?song)) "
     "where { ?song a nmm:MusicPiece . "
-    "?song nie:title ?title . } "
+    "?song nie:title ?title ;"
+    "nie:isLogicalPartOf <qsparql-benchmark-tests> }"
     "order by ?title "
     "<http://www.tracker-project.org/ontologies/tracker#id>(?song)";
 
@@ -171,8 +184,24 @@
 
 }
 
-tst_QSparqlBenchmark::tst_QSparqlBenchmark()
+tst_QSparqlBenchmark::tst_QSparqlBenchmark() : result("Benchmark_results")
 {
+    QString description("Some description of what was improved "
+                        "comparing to previous verion");
+    QDomElement benchmarks = result.createElement("benchmark");
+    QDomElement asset = result.createElement("asset");
+    QDomElement tests = result.createElement("tests");
+    QDomElement created = result.createElement("created");
+    QDomElement descriptionNode = result.createElement("description");
+    QDomText date = result.createTextNode(QDate::currentDate().toString());
+    QDomText text = result.createTextNode(description);
+    created.appendChild(date);
+    descriptionNode.appendChild(text);
+    asset.appendChild(created);
+    asset.appendChild(descriptionNode);
+    result.appendChild(benchmarks);
+    benchmarks.appendChild(asset);
+    benchmarks.appendChild(tests);
 }
 
 tst_QSparqlBenchmark::~tst_QSparqlBenchmark()
@@ -188,6 +217,16 @@
 
 void tst_QSparqlBenchmark::cleanupTestCase()
 {
+    QSparqlConnection conn("QTRACKER_DIRECT");
+    const QSparqlQuery q("DELETE { ?u a rdfs:Resource . } "
+                         "WHERE { ?u nie:isLogicalPartOf <qsparql-benchmark-tests> . } "
+                         "DELETE { <qsparql-benchmark-tests> a rdfs:Resource . }",
+                        QSparqlQuery::DeleteStatement);
+    QSparqlResult* r = conn.exec(q);
+    QVERIFY(!r->hasError());
+    r->waitForFinished();
+    QVERIFY(!r->hasError());
+    delete r;
 }
 
 void tst_QSparqlBenchmark::init()
@@ -228,18 +267,160 @@
 
 }
 
+void tst_QSparqlBenchmark::trackerDataInjection()
+{
+    QSparqlConnection conn("QTRACKER_DIRECT");
+    const QString insertHeader = "INSERT {<qsparql-benchmark-tests> a nie:InformationElement. ";
+
+    const QString albumDiscInsertItem = " <urn:qsparql-benchmark:album-disk:%1> a nmm:MusicAlbumDisc ;"
+                                        "nie:isLogicalPartOf <qsparql-benchmark-tests> .";
+    const QString artistInsertItem = " <urn:qsparql-benchmark:artist:%1> a nmm:Artist ;"
+                                        " nmm:artistName \"Artist %1\" ; "
+                                        "nie:isLogicalPartOf <qsparql-benchmark-tests> .";
+    const QString albumInsertItem = " <urn:qsparql-benchmark:album:%1> a nmm:MusicAlbum ;"
+                                        "nie:title        \"Album %1\" ;"
+                                        "nmm:albumTitle   \"Album %1\" ;"
+                                        "nie:isLogicalPartOf <qsparql-benchmark-tests> .";
+
+    // create exact copy of tracker's ttls data
+    QString insertQuery(insertHeader);
+    for (int major = 50; major <= 1000; major+=50){
+        for (int minor = 2; minor <= 6; minor++) {
+            insertQuery.append( albumDiscInsertItem.arg(major+minor) );
+            insertQuery.append( albumInsertItem.arg((major+minor-1)%1000) );
+        }
+        insertQuery.append( artistInsertItem.arg(major % 1000) );
+    }
+    insertQuery.append(" }");
+
+    QSparqlQuery query(insertQuery, QSparqlQuery::InsertStatement);
+    QSparqlResult* r = 0;
+    r = conn.exec(query);
+    r->waitForFinished();
+
+    QString musicPieceItem = "<urn:qsparql-benchmark:music:%1> a nmm:MusicPiece, "
+                                "nfo:FileDataObject, nfo:Audio; "
+                                "tracker:available          true ;"
+                                "nie:byteSize               \"%1\" ;"
+                                "nie:url                    \"file://music/Song_%1.mp3\" ;"
+                                "nfo:belongsToContainer     <file://music/> ;"
+                                "nie:title                  \"Song %1\" ;"
+                                "nie:mimeType               \"audio/mpeg\" ;"
+                                "nie:contentCreated         \"%2\" ;"
+                                "nie:isLogicalPartOf        <urn:album:51> ;"
+                                "nco:contributor            <urn:artist:%6> ;"
+                                "nfo:fileLastAccessed       \"%2\" ;"
+                                "nfo:fileSize               \"%1\" ;"
+                                "nfo:fileName               \"Song_%1.mp3\" ;"
+                                "nfo:fileLastModified       \"%2\" ;"
+                                "nfo:codec                  \"MPEG\" ;"
+                                "nfo:averageBitrate         \"%3\" ;"
+                                "nfo:genre                  \"Genre %1\" ;"
+                                "nfo:channels               \"2\" ;"
+                                "nfo:sampleRate             \"44100.0\" ;"
+                                "nmm:musicAlbum             <urn:album:%7> ;"
+                                "nmm:musicAlbumDisc         <urn:album-disk:%8> ;"
+                                "nmm:performer              <urn:artist:%6> ;"
+                                "nfo:duration               \"%5\" ;"
+                                "nmm:trackNumber            \"%4\" ;"
+                                "nie:isLogicalPartOf <qsparql-benchmark-tests> .";
+    QString dateTemplate("%1-%2-%3T01:01:01Z");
+    insertQuery = insertHeader;
+    int artistId = 50;
+    int albumId = 50;
+    QString benchmarkName("data-injection");
+    QList<int> totalTimes;
+    for (int i = 0; i < 1000; i++) {
+        QString date = dateTemplate.arg(2000 + (i % 10)).arg((i % 12) + 1, 2, 10, QLatin1Char('0'))
+                                    .arg((i%25) + 1, 2, 10, QLatin1Char('0'));
+        int bitrate = 16 + (i % 300);
+        int track = 1 + (i % 100);
+        int duration = i + 1;
+        if(i%50 == 0)
+            artistId = i % 1000 + 50;
+        if(i%10 == 0) {
+            albumId++;
+            if(albumId%10 ==6)
+                albumId+=45;
+        }
+        insertQuery.append(musicPieceItem.arg(i).arg(date).arg(bitrate).arg(track).arg(duration).
+                                                arg(artistId).arg(albumId).arg(albumId+1));
+        if((i+1)%100 == 0) {
+            insertQuery.append(" }");
+            START_BENCHMARK {
+                QSparqlQuery queryData(insertQuery, QSparqlQuery::InsertStatement);
+                r = conn.exec(queryData);
+                r->waitForFinished();
+                CHECK_QSPARQL_RESULT(r);
+            }
+            END_BENCHMARK(benchmarkName);
+            totalTimes.append(benchmarkTotal);
+            insertQuery = insertHeader;
+        }
+    }
+    PRINT_STATS(benchmarkName, totalTimes);
+    qDebug() << "Insertion finished. 2 minutes wait until tracker harvests the data and settles down";
+    QTest::qWait(120000);
+    qDebug() << "2 minutes passed. Now tracker should be ready for fast cooperation";
+
+    // do some validation if data is ready for tests
+    QString validateData("SELECT ?url ?title ?album WHERE {?url a nmm:MusicAlbum ;"
+                         " nie:isLogicalPartOf <qsparql-benchmark-tests>; "
+                         " nie:title ?title; nmm:albumTitle ?album. }");
+    QSparqlQuery validateQuery(validateData);
+    r = conn.exec(validateQuery);
+    r->waitForFinished();
+    CHECK_QSPARQL_RESULT(r);
+    QVERIFY(!r->hasError());
+    QCOMPARE(r->size(), 100);
+
+    validateData="SELECT ?url WHERE {?url a nmm:MusicAlbumDisc; "
+                 "nie:isLogicalPartOf <qsparql-benchmark-tests> . }";
+    validateQuery.setQuery(validateData);
+    r = conn.exec(validateQuery);
+    r->waitForFinished();
+    CHECK_QSPARQL_RESULT(r);
+    QVERIFY(!r->hasError());
+    QCOMPARE(r->size(), 100);
+
+    validateData="SELECT ?url ?name WHERE {?url a nmm:Artist; "
+                 "nie:isLogicalPartOf <qsparql-benchmark-tests> ;  nmm:artistName ?name.}";
+    validateQuery.setQuery(validateData);
+    r = conn.exec(validateQuery);
+    r->waitForFinished();
+    CHECK_QSPARQL_RESULT(r);
+    QVERIFY(!r->hasError());
+    QCOMPARE(r->size(), 20);
+
+    validateQuery.setQuery(musicQuery);
+    r = conn.exec(validateQuery);
+    r->waitForFinished();
+    CHECK_QSPARQL_RESULT(r);
+    QVERIFY(!r->hasError());
+    QCOMPARE(r->size(), 1000);
+    delete r;
+}
+
 void tst_QSparqlBenchmark::queryBenchmark()
 {
     QFETCH(QString, benchmarkName);
     QFETCH(QString, connectionName);
     QFETCH(QString, queryString);
+    QFETCH(int, executionMethod);
+    QFETCH(bool, forwardOnly);
 
     QSparqlQuery query(queryString);
     QSparqlConnection conn(connectionName);
-    // Note: connection opening cost is left out of the benchmark. Connection
-    // opening is async, so we need to wait here long enough to know that it has
+
+    // Note: connection opening cost is left out of the benchmark. If connection
+    // opening is async, we need to wait here long enough to know that it has
     // opened (there is no signal sent or such to know it has opened).
-    QTest::qWait(2000);
+    if (executionMethod == QSparqlQueryOptions::AsyncExec)
+        QTest::qWait(2000);
+
+    QSparqlQueryOptions queryOptions;
+    queryOptions.setForwardOnly(forwardOnly);
+    queryOptions.setExecutionMethod((QSparqlQueryOptions::ExecutionMethod)executionMethod);
 
     QSparqlResult* r = 0;
     QList<int> totalTimes;
@@ -248,10 +429,10 @@
     // does adding a QThreadPool help".
     for (int i = 0; i < NO_QUERIES; ++i) {
         START_BENCHMARK {
-            r = conn.exec(query);
-            r->waitForFinished();
+            r = conn.exec(query, queryOptions);
+            if (executionMethod == QSparqlQueryOptions::AsyncExec)
+                r->waitForFinished();
             CHECK_QSPARQL_RESULT(r);
-            QVERIFY(r->size() > 0);
             delete r;
         }
         END_BENCHMARK(benchmarkName);
@@ -264,17 +445,38 @@
 {
     QTest::addColumn<QString>("benchmarkName");
     QTest::addColumn<QString>("connectionName");
+    QTest::addColumn<int>("executionMethod");
+    QTest::addColumn<bool>("forwardOnly");
     QTest::addColumn<QString>("queryString");
 
     QTest::newRow("TrackerDBusArtistsAndAlbums")
         << "dbus-artistsandalbums"
         << "QTRACKER"
+        << (int)QSparqlQueryOptions::AsyncExec
+        << false
+        << artistsAndAlbumsQuery;
+
+    QTest::newRow("TrackerDirectArtistsAndAlbums-Async")
+        << "direct-artistsandalbums-Async"
+        << "QTRACKER_DIRECT"
+        << (int)QSparqlQueryOptions::AsyncExec
+        << false
+        << artistsAndAlbumsQuery;
+
+    QTest::newRow("TrackerDirectArtistsAndAlbums-Async-ForwardOnly")
+        << "direct-artistsandalbums-Async-ForwardOnly"
+        << "QTRACKER_DIRECT"
+        << (int)QSparqlQueryOptions::AsyncExec
+        << true
         << artistsAndAlbumsQuery;
 
-    QTest::newRow("TrackerDirectArtistsAndAlbums")
-        << "direct-artistsandalbums"
+    QTest::newRow("TrackerDirectArtistsAndAlbums-Sync")
+        << "direct-artistandalbums-Sync"
         << "QTRACKER_DIRECT"
+        << (int)QSparqlQueryOptions::SyncExec
+        << false
         << artistsAndAlbumsQuery;
+
 }
 
 void tst_QSparqlBenchmark::dataReadingBenchmark()
@@ -282,12 +484,17 @@
     QFETCH(QString, benchmarkName);
     QFETCH(QString, queryString);
     QFETCH(int, columnCount);
+    QFETCH(int, executionMethod);
+    QFETCH(bool, forwardOnly);
 
     // Set the dataReadyInterval to be large enough so that it won't affect this
     // test case.
     QSparqlConnectionOptions opts;
     opts.setDataReadyInterval(1000000);
 
+    QSparqlQueryOptions queryOptions;
+    queryOptions.setForwardOnly(forwardOnly);
+    queryOptions.setExecutionMethod((QSparqlQueryOptions::ExecutionMethod)executionMethod);
     QSparqlConnection conn("QTRACKER_DIRECT", opts);
     // Note: connection opening cost is left out of the benchmark. Connection
     // opening is async, so we need to wait here long enough to know that it has
@@ -306,16 +513,17 @@
     for (int i = 0; i < NO_QUERIES; ++i) {
         {
             START_BENCHMARK {
-                r = conn.exec(query);
-                QEventLoop loop;
-                connect(r, SIGNAL(finished()), &loop, SLOT(quit()));
-                loop.exec();
+                r = conn.exec(query,queryOptions);
+                if(executionMethod == QSparqlQueryOptions::AsyncExec) {
+                    QEventLoop loop;
+                    connect(r, SIGNAL(finished()), &loop, SLOT(quit()));
+                    loop.exec();
+                }
             }
             END_BENCHMARK(finished);
             totalTimesFinished.append(benchmarkTotal);
         }
         CHECK_QSPARQL_RESULT(r);
-        QVERIFY(r->size() > 0);
         {
             int size = 0;
             START_BENCHMARK {
@@ -346,94 +554,50 @@
     QTest::addColumn<QString>("benchmarkName");
     QTest::addColumn<QString>("queryString");
     QTest::addColumn<int>("columnCount");
+    QTest::addColumn<int>("executionMethod");
+    QTest::addColumn<bool>("forwardOnly");
 
-    QTest::newRow("ReadingArtistsAndAlbums")
-        << "read-artistsandalbums"
+    QTest::newRow("ReadingArtistsAndAlbums-Async")
+        << "read-artistsandalbums-Async"
         << artistsAndAlbumsQuery
-        << artistsAndAlbumsColumnCount;
-
-    QTest::newRow("ReadingMusic")
-        << "read-music"
-        << musicQuery
-        << musicQueryColumnCount;
-}
-
-void tst_QSparqlBenchmark::dataReadingBenchmarkSync()
-{
-    QFETCH(QString, benchmarkName);
-    QFETCH(QString, queryString);
-    QFETCH(int, columnCount);
+        << artistsAndAlbumsColumnCount
+        << (int)QSparqlQueryOptions::AsyncExec
+        << false;
 
-    // Set the dataReadyInterval to be large enough so that it won't affect this
-    // test case.
-    QSparqlConnectionOptions opts;
-    opts.setDataReadyInterval(1000000);
-
-    QSparqlConnection conn("QTRACKER_DIRECT", opts);
-    // Note: connection opening cost is left out of the benchmark. Connection
-    // opening is async, so we need to wait here long enough to know that it has
-    // opened (there is no signal sent or such to know it has opened).
-    QTest::qWait(2000);
-
-    QSparqlQuery query(queryString);
-
-    QString finished = benchmarkName + "-fin";
-    QString read = benchmarkName + "-read";
-
-    QSparqlResult* r = 0;
-    QList<int> totalTimesFinished;
-    QList<int> totalTimesRead;
+    QTest::newRow("ReadingArtistsAndAlbums-Async-ForwardOnly")
+        << "read-artistsandalbums-Async-ForwardOnly"
+        << artistsAndAlbumsQuery
+        << artistsAndAlbumsColumnCount
+        << (int)QSparqlQueryOptions::AsyncExec
+        << true;
 
-    for (int i = 0; i < NO_QUERIES; ++i) {
-        {
-            START_BENCHMARK {
-                r = conn.syncExec(query);               
-            }
-            END_BENCHMARK(finished);
-            totalTimesFinished.append(benchmarkTotal);
-        }
-        CHECK_QSPARQL_RESULT(r);
-        
-        {
-            int size = 0;
-            START_BENCHMARK {
-                while (r->next()) {
-                    for (int c = 0; c < columnCount; ++c) {
-                        QVariant var = r->value(c);
-                        // Probably it's enough not to do anything with the
-                        // value; the statement of getting the value won't be
-                        // optimized out since calling r->value() might have
-                        // side effects.
-                    }
-                    ++size;
-                }
-            }
-            END_BENCHMARK(read);
-            totalTimesRead.append(benchmarkTotal);
-            // For verifying that enough data was really read
-            // qDebug() << "No of results" << size;
-        }
-        delete r;
-    }
-    PRINT_STATS(finished, totalTimesFinished);
-    PRINT_STATS(read, totalTimesRead);
-}
+    QTest::newRow("ReadingArtistsAndAlbums-Sync")
+        << "read-artistsandalbums-Sync"
+        << artistsAndAlbumsQuery
+        << artistsAndAlbumsColumnCount
+        << (int)QSparqlQueryOptions::SyncExec
+        << false;
 
-void tst_QSparqlBenchmark::dataReadingBenchmarkSync_data()
-{
-    QTest::addColumn<QString>("benchmarkName");
-    QTest::addColumn<QString>("queryString");
-    QTest::addColumn<int>("columnCount");
+    QTest::newRow("ReadingMusic-Async")
+        << "read-music-Async"
+        << musicQuery
+        << musicQueryColumnCount
+        << (int)QSparqlQueryOptions::AsyncExec
+        << false;
 
-    QTest::newRow("ReadingArtistsAndAlbums")
-        << "sync-read-artistsandalbums"
-        << artistsAndAlbumsQuery
-        << artistsAndAlbumsColumnCount;
+    QTest::newRow("ReadingMusic-Async-ForwardOnly")
+        << "read-music-Async-ForwardOnly"
+        << musicQuery
+        << musicQueryColumnCount
+        << (int)QSparqlQueryOptions::AsyncExec
+        << true;
 
-    QTest::newRow("ReadingMusic")
-        << "sync-read-music"
+    QTest::newRow("ReadingMusic-Sync")
+        << "read-music-Sync"
         << musicQuery
-        << musicQueryColumnCount;
+        << musicQueryColumnCount
+        << (int)QSparqlQueryOptions::SyncExec
+        << false;
 }
 
 void tst_QSparqlBenchmark::queryWithLibtrackerSparql()
@@ -569,5 +733,51 @@
     }
 }
 
+void tst_QSparqlBenchmark::generateResultsReport()
+{
+    QDomElement tests = result.firstChild().namedItem("tests").toElement();
+    tests.setAttribute("count", tests.elementsByTagName("test").count());
+    //include date in filename so it can be sorted by filename and still have chronological order
+    QString coreFilenameTemplate("benchmark-%1-%2-%3");
+    QString filenameTemplate("%1.run-%2.xml");
+    QString dirPath = QDir::homePath() + QDir::separator();
+    int y, m, d;
+    QDate::currentDate().getDate(&y, &m, &d);
+    QString coreFilename = coreFilenameTemplate.arg(y).arg(m, 2, 10, QLatin1Char('0'))
+                                                        .arg(d, 2, 10, QLatin1Char('0'));
+    int run =1;
+    QString filePath= dirPath + filenameTemplate.arg(coreFilename).arg(run);
+    QFileInfo fi(filePath);
+    while(fi.exists())
+    {
+        run++;
+        filePath= dirPath + filenameTemplate.arg(coreFilename).arg(run);
+        fi.setFile(filePath);
+    }
+    QFile data(filePath);
+    if (data.open(QFile::WriteOnly | QFile::Truncate)) {
+        QTextStream out(&data);
+        result.save(out, 4);
+    }
+    else
+        qDebug() << "Could not open "<< filePath <<" for writing. Check permissions";
+}
+
+void tst_QSparqlBenchmark::appendResult(QString name, int median, int mean, int total)
+{
+    QDomNode test = result.createElement("test");
+    test.toElement().setAttribute("name", name);
+    result.firstChild().namedItem("tests").appendChild(test);
+    QDomNode medianNode = result.createElement("median");
+    medianNode.toElement().setAttribute("value", median);
+    test.appendChild(medianNode);
+    QDomNode meanNode = result.createElement("mean");
+    meanNode.toElement().setAttribute("value", mean);
+    test.appendChild(meanNode);
+    QDomNode totalNode = result.createElement("total");
+    totalNode.toElement().setAttribute("value", total);
+    test.appendChild(totalNode);
+}
+
 QTEST_MAIN(tst_QSparqlBenchmark)
 #include "tst_qsparql_benchmark.moc"
--- tests/auto/qsparql_endpoint/qsparql_endpoint.pro
+++ tests/auto/qsparql_endpoint/qsparql_endpoint.pro
@@ -1,6 +1,6 @@
 include(../sparqltest.pri)
 CONFIG += qt warn_on console depend_includepath testcase
-QT += testlib xml
+QT += testlib xml network
 SOURCES  += tst_qsparql_endpoint.cpp
 
 #QT = sparql # enable this later
--- tests/auto/qsparql_endpoint/tst_qsparql_endpoint.cpp
+++ tests/auto/qsparql_endpoint/tst_qsparql_endpoint.cpp
@@ -40,10 +40,6 @@
 #include <QtTest/QtTest>
 #include <QtSparql/QtSparql>
 
-//const QString qtest(qTableName( "qtest", __FILE__ )); // FIXME: what's this
-
-//TESTED_FILES=
-
 class tst_QSparqlEndpoint : public QObject
 {
     Q_OBJECT
@@ -79,6 +75,20 @@
     // For running the test without installing the plugins. Should work in
     // normal and vpath builds.
     QCoreApplication::addLibraryPath("../../../plugins");
+
+    // Check for a proxy
+    QString url = getenv("http_proxy");
+    if (!url.isEmpty()) {
+        qDebug() << "Proxy found:"<<url;
+        QUrl proxyUrl(url);
+
+        QNetworkProxy proxy;
+        proxy.setType(QNetworkProxy::HttpProxy);
+        proxy.setHostName(proxyUrl.host());
+        proxy.setPort(proxyUrl.port());
+        QNetworkProxy::setApplicationProxy(proxy);
+        qDebug() << "Proxy Setup";
+    }
 }
 
 void tst_QSparqlEndpoint::cleanupTestCase()
@@ -108,16 +118,23 @@
     QCOMPARE(r->hasError(), false);
     r->waitForFinished(); // this test is synchronous only
     QCOMPARE(r->hasError(), false);
-    QCOMPARE(r->size(), 4);
+    // dbpedia gives 5 results for the query, rather than 4
+    // so comment this out for now
+    //QCOMPARE(r->size(), 4);
     QHash<QString, QString> placesOfBirth;
     while (r->next()) {
         QCOMPARE(r->current().count(), 2);
         placesOfBirth[r->current().binding(0).toString()] = r->current().binding(1).toString();
     }
-    QCOMPARE(placesOfBirth.size(), 4);
-    QCOMPARE(placesOfBirth["<http://dbpedia.org/resource/George_Harrison>"], QString("<http://dbpedia.org/resource/Wavertree>"));
+    // ringo isn't getting his place of birth returned
+    // so comment this out for now
+    // QCOMPARE(placesOfBirth.size(), 4);
+
+    // George Harrison is having several locations for places of birth returned, so comment this out for now
+    // QCOMPARE(placesOfBirth["<http://dbpedia.org/resource/George_Harrison>"], QString("<http://dbpedia.org/resource/Wavertree>"));
     QCOMPARE(placesOfBirth["<http://dbpedia.org/resource/John_Lennon>"], QString("<http://dbpedia.org/resource/Liverpool>"));
-    QCOMPARE(placesOfBirth["<http://dbpedia.org/resource/Ringo_Starr>"], QString("<http://dbpedia.org/resource/Dingle%252C_Liverpool>"));
+    // Commented out due to fault with dbpedia
+    //QCOMPARE(placesOfBirth["<http://dbpedia.org/resource/Ringo_Starr>"], QString("<http://dbpedia.org/resource/Dingle%252C_Liverpool>"));
     QCOMPARE(placesOfBirth["<http://dbpedia.org/resource/Paul_McCartney>"], QString("<http://dbpedia.org/resource/Liverpool>"));
     delete r;
 }
@@ -153,7 +170,8 @@
         QCOMPARE(r->current().binding(1).toString(), QString("<http://dbpedia.org/property/currentMembers>"));
         
         QCOMPARE(r->current().binding(2).name(), QString("o"));
-        QCOMPARE((bool) currentMembers.contains(r->current().binding(2).toString()), true);
+        // Commented out due to fault with dbpedia
+        //QCOMPARE((bool) currentMembers.contains(r->current().binding(2).toString()), true);
     }
 
     delete r;
@@ -165,7 +183,7 @@
     options.setHostName("dbpedia.org");
     QSparqlConnection conn("QSPARQL_ENDPOINT", options);
 
-    QSparqlQuery add1("ASK { <http://dbpedia.org/resource/The_Beatles> <http://dbpedia.org/property/currentMembers> <http://dbpedia.org/resource/Ringo_Starr> . }",
+    QSparqlQuery add1("ASK { <http://dbpedia.org/resource/The_Beatles> <http://dbpedia.org/property/currentMembers> <http://dbpedia.org/resource/George_Harrison> . }",
                      QSparqlQuery::AskStatement);
 
     QSparqlResult* r = conn.exec(add1);
--- tests/auto/qsparql_ntriples/qsparql_ntriples.pro
+++ tests/auto/qsparql_ntriples/qsparql_ntriples.pro
@@ -8,7 +8,10 @@
 check.depends = $$TARGET
 check.commands = ./tst_qsparql_ntriples
 
-QMAKE_EXTRA_TARGETS += check
+memcheck.depends = $$TARGET
+memcheck.commands = $$VALGRIND $$VALGRIND_OPT ./tst_qsparql_ntriples
+
+QMAKE_EXTRA_TARGETS += check memcheck
 
 #QT = sparql # enable this later
 
--- tests/auto/qsparql_ntriples/tst_qsparql_ntriples.cpp
+++ tests/auto/qsparql_ntriples/tst_qsparql_ntriples.cpp
@@ -41,10 +41,6 @@
 #include <QtSparql/QtSparql>
 #include <QtSparql/private/qsparqlntriples_p.h>
 
-//const QString qtest(qTableName( "qtest", __FILE__ )); // FIXME: what's this
-
-//TESTED_FILES=
-
 class tst_QSparqlNTriples : public QObject
 {
     Q_OBJECT
--- tests/auto/qsparql_qmlbindings
+++ tests/auto/qsparql_qmlbindings
+(directory)
--- tests/auto/qsparql_qmlbindings/qsparql_qmlbindings.pro
+++ tests/auto/qsparql_qmlbindings/qsparql_qmlbindings.pro
+include(../sparqltest.pri)
+CONFIG += qt warn_on console depend_includepath
+QT += testlib declarative
+
+SOURCES  += tst_qsparql_qmlbindings.cpp
+
+check.depends = $$TARGET
+check.commands = ./tst_qsparql_qmlbindings
+
+memcheck.depends = $$TARGET
+memcheck.commands = $$VALGRIND $$VALGRIND_OPT ./tst_qsparql_qmlbindings
+
+QMAKE_EXTRA_TARGETS += check memcheck
+
+#QT = sparql # enable this later
+
+install_qml.files = qsparqlconnection.qml qsparqlresultlist.qml qsparqllegacy.qml
+install_qml.path = $$PREFIX/lib/$$PACKAGENAME-tests/
+INSTALLS += install_qml
--- tests/auto/qsparql_qmlbindings/qsparqlconnection.qml
+++ tests/auto/qsparql_qmlbindings/qsparqlconnection.qml
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (ivan.frade at nokia.com)
+**
+** This file is part of the test suite of the QtSparql module (not yet part of the Qt Toolkit).
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at ivan.frade at nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import Qt 4.7
+import QtSparql 1.0
+
+Rectangle {
+    id: rootComp
+    property string setDriver: "QTRACKER_DIRECT"
+    property string queryString: sparqlQueryString
+    property int portNumber: setPortNumber
+    property string host: setHost
+    property int connectionStatus: 0
+    property int resultReadyCalled: 0
+    property variant resultFromSlot: 0
+
+    signal resultReadySignal();
+
+    SparqlConnection {
+        objectName: "connectionWithOptions"
+        id: sparqlConnection
+        driver: setDriver
+        options: SparqlConnectionOptions { id:connectionOptions; hostName: host; port: portNumber }
+        onStatusChanged: connectionStatus = sparqlConnection.status
+        onResultReady: resultReadySignal()
+    }
+
+    function runSelectQuery()
+    {
+       return sparqlConnection.select(queryString);
+    }
+
+    function runAskQuery(query)
+    {
+        return sparqlConnection.ask(query);
+    }
+
+    function runAskQueryAsync(query)
+    {
+        sparqlConnection.ask(query, true);
+    }
+
+    function runConstructQuery()
+    {
+        // will result in error, since construct queries are not
+        // supported by tracker
+        return sparqlConnection.construct(queryString);
+    }
+
+    function runSelectQueryAsync()
+    {
+        sparqlConnection.resultReady.connect(asyncResultReady);
+        sparqlConnection.select(queryString, true);
+    }
+
+    function asyncResultReady(result)
+    {
+        resultFromSlot = result;
+        resultReadySignal();
+    }
+
+    // returns from the result property
+    function returnResults()
+    {
+        return sparqlConnection.result;
+    }
+
+    function returnResultsFromSlot()
+    {
+        return resultFromSlot;
+    }
+
+    function returnConnectionOptions() {
+        var hash = {};
+        for (var prop in connectionOptions) {
+            hash[prop] = connectionOptions[prop];
+        }
+        return hash;
+    }
+
+    function insertContact() {
+        var insertQuery = "insert { <qmlInsert> a nco:PersonContact; "+
+                          "nie:isLogicalPartOf <qsparql-qml-tests>; "+
+                          "nco:nameGiven 'QML INSERT' }";
+        sparqlConnection.update(insertQuery);
+    }
+
+    function insertBoundContact() {
+        var insertQuery = "insert { <qmlInsert-bound> a nco:PersonContact; "+
+                          "nie:isLogicalPartOf <qsparql-qml-tests>; "+
+                          "nco:nameGiven ?:nameGiven; "+
+                          "nco:nameFamily ?:nameFamily }";
+        var boundValues = { "nameFamily":"QML Family", "nameGiven":"QML Insert" };
+        sparqlConnection.update(insertQuery, boundValues);
+    }
+
+    function deleteBoundContact() {
+        var deleteQuery = "delete { ?u a nco:PersonContact } "+
+                          "where { ?u a nco:PersonContact; nco:nameGiven ?:ng; nco:nameFamily ?:nf } ";
+        var boundValues = { "ng":"QML Insert", "nf":"QML Family" };
+        sparqlConnection.update(deleteQuery, boundValues);
+    }
+
+    function selectBoundContact() {
+        var selectQuery = "select ?u { ?u a nco:PersonContact; "+
+                          "nie:isLogicalPartOf <qsparql-qml-tests>; "+
+                          "nco:nameGiven ?:nameGiven; nco:nameFamily ?:nameFamily}";
+        var boundValues = { "nameFamily":"QML Family", "nameGiven":"QML Insert" };
+        return sparqlConnection.select(selectQuery, boundValues);
+    }
+
+    function askBoundContact() {
+        var askQuery = "ask { ?u a nco:PersonContact; "+
+                       "nco:nameGiven ?:ng;"+
+                       "nco:nameFamily ?:nf .}";
+        var boundValues = { "ng":"QML Insert", "nf":"QML Family" };
+        return sparqlConnection.ask(askQuery, boundValues);
+    }
+
+    function insertContactAsync() {
+        var insertQuery = "insert { <qmlInsert> a nco:PersonContact; "+
+                          "nie:isLogicalPartOf <qsparql-qml-tests>; "+
+                          "nco:nameGiven 'QML INSERT' }";
+        sparqlConnection.update(insertQuery, true);
+    }
+
+    function deleteContact() {
+        var deleteQuery = "delete { <qmlInsert> a nco:PersonContact } "+
+                          "where { <qmlInsert> a nco:PersonContact } ";
+
+        sparqlConnection.update(deleteQuery);
+    }
+
+    function deleteContactAsync() {
+        var deleteQuery = "delete { <qmlInsert> a nco:PersonContact } "+
+                          "where { <qmlInsert> a nco:PersonContact } ";
+
+        sparqlConnection.update(deleteQuery, true);
+    }
+
+    function getStatus()
+    {
+        // return the property value here
+        // that way we can also check to make sure
+        // the notify for Status is working
+        return connectionStatus
+    }
+
+    function getLastError()
+    {
+        return sparqlConnection.errorString();
+    }
+}
+
--- tests/auto/qsparql_qmlbindings/qsparqllegacy.qml
+++ tests/auto/qsparql_qmlbindings/qsparqllegacy.qml
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (ivan.frade at nokia.com)
+**
+** This file is part of the test suite of the QtSparql module (not yet part of the Qt Toolkit).
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at ivan.frade at nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import Qt 4.7
+import QtSparql 0.1
+
+ListView {
+    width: 1000; height: 600
+
+    model: SparqlResultsList {
+        options: SparqlConnectionOptions {
+            driverName: "QTRACKER_DIRECT"
+            hostName: "dbpedia.org"
+        }
+
+        query: "SELECT $predicate $thing WHERE { <http://dbpedia.org/resource/The_Beatles> $predicate $thing . }"
+    }
+
+    delegate: Text { text: "Data: " + $predicate + ", " + $thing }
+}
--- tests/auto/qsparql_qmlbindings/qsparqlresultlist.qml
+++ tests/auto/qsparql_qmlbindings/qsparqlresultlist.qml
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (ivan.frade at nokia.com)
+**
+** This file is part of the test suite of the QtSparql module (not yet part of the Qt Toolkit).
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at ivan.frade at nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import Qt 4.7
+import QtSparql 1.0
+
+Rectangle {
+    id: rootComp
+    property string setDriver: "QTRACKER_DIRECT"
+    property string queryString: sparqlQueryString
+    property int modelStatus: 0
+
+    signal modelCountChanged()
+    signal modelStatusReady()
+
+    ListView {
+        id: contactsView
+        width: parent.width
+        height: parent.height
+
+        model: SparqlListModel {
+            id: sparqlResultList
+            onCountChanged: { modelCountChanged() }
+            objectName: "queryModel"
+            // load existing query model
+            connection: sparqlConnection
+            query: sparqlQueryString
+            onStatusChanged: { modelStatusChanged() }
+
+        }
+       delegate: Item {  height: 50;  }
+    }
+
+    SparqlConnection {
+        objectName: "sparqlConnection"
+        id: sparqlConnection
+        driver: setDriver
+    }
+
+    function modelStatusChanged()
+    {
+        modelStatus = sparqlResultList.status;
+        if (modelStatus == SparqlListModel.Ready) {
+            modelStatusReady();
+        }
+    }
+
+    function getCount()
+    {
+        var resultListCount = sparqlResultList.count;
+        return resultListCount
+    }
+
+    function getStatus()
+    {
+        // return the property value here
+        // that way we can also check to make sure
+        // the notify for Status is working
+        return modelStatus
+    }
+
+    function reloadModel()
+    {
+        sparqlResultList.reload();
+    }
+
+    function setQuery(query)
+    {
+        sparqlResultList.query = query;
+    }
+
+    function getRow(row)
+    {
+        return sparqlResultList.get(row);
+    }
+
+}
+
--- tests/auto/qsparql_qmlbindings/tst_qsparql_qmlbindings.cpp
+++ tests/auto/qsparql_qmlbindings/tst_qsparql_qmlbindings.cpp
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (ivan.frade at nokia.com)
+**
+** This file is part of the test suite of the QtSparql module (not yet part of the Qt Toolkit).
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at ivan.frade at nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QtSparql/QtSparql>
+#include <QtDeclarative/qdeclarative.h>
+#include <QtDeclarative>
+#include <QtSparql/private/qsparqlsparqlconnection_p.h>
+#include <QtSparql>
+
+#define NUM_INSERTS 10
+
+class tst_QSparqlQMLBindings : public QObject
+{
+    Q_OBJECT
+
+public:
+    tst_QSparqlQMLBindings();
+    virtual ~tst_QSparqlQMLBindings();
+public slots:
+    void initTestCase();
+    void cleanupTestCase();
+    void init();
+    void cleanup();
+
+private slots:
+    void sparql_connection_test();
+    void sparql_connection_test_data();
+    void sparql_connection_select_query_test();
+    void sparql_connection_select_query_async_test();
+    void sparql_connection_ask_query_test();
+    void sparql_connection_ask_query_async_test();
+    void sparql_connection_update_query_test(); //insert and delete
+    void sparql_connection_update_query_async_test();
+    void sparql_connection_construct_query_test();
+    void sparql_connection_bound_values_test();
+    void sparql_connection_options_test();
+    void sparql_connection_options_test_data();
+    void sparql_query_model_test();
+    void sparql_query_model_test_data();
+    void sparql_query_model_reload_test();
+    void sparql_query_model_get_test();
+    void sparql_query_model_test_role_names();
+    void sparql_legacy_test();
+
+};
+
+namespace {
+
+// QML stuff
+enum Status { Null, Ready, Loading, Error };
+
+QDeclarativeEngine *engine;
+QDeclarativeComponent *component;
+QDeclarativeContext *context;
+QObject* qmlObject;
+
+const QString contactSelectQuery =
+    "select ?u ?ng {"
+    "    ?u a nco:PersonContact; "
+    "    nie:isLogicalPartOf <qsparql-qml-tests> ;"
+    "    nco:nameGiven ?ng .}";
+
+template <class T>
+T getObject(QString objectName)
+{
+    T object;
+    object = qobject_cast<T>(qmlObject->findChild<QObject*>(objectName));
+    return object;
+}
+
+QVariant callMethod(QString methodName, QVariant parameter = QVariant())
+{
+    QVariant returnValue;
+    if (parameter.isNull()) {
+        QMetaObject::invokeMethod(qmlObject,
+                                methodName.toAscii(),
+                                Qt::DirectConnection,
+                                Q_RETURN_ARG(QVariant, returnValue));
+    } else {
+        QMetaObject::invokeMethod(qmlObject,
+                                methodName.toAscii(),
+                                Qt::DirectConnection,
+                                Q_RETURN_ARG(QVariant, returnValue),
+                                Q_ARG(QVariant, parameter));
+    }
+
+
+    return returnValue;
+}
+
+void qmlCleanup()
+{
+    // may want to do this as part of a test
+    // so set pointers to null as well
+    delete qmlObject;
+    qmlObject = 0;
+    delete component;
+    component = 0;
+    delete engine;
+    engine = 0;
+}
+
+bool loadQmlFile(QString fileName, QList<QPair<QString, QVariant> > contextProperties)
+{
+    QFileInfo fileInfo(QApplication::argv()[0]);
+
+    engine = new QDeclarativeEngine();
+    engine->addImportPath("../../../imports");
+    component = new QDeclarativeComponent(engine, QUrl::fromLocalFile(fileInfo.absolutePath()+"/"+fileName));
+    context = engine->rootContext();
+
+    for(int i=0;i<contextProperties.size();i++) {
+        QPair<QString, QVariant> contextPair = contextProperties.at(i);
+        context->setContextProperty(contextPair.first, contextPair.second);
+    }
+    qmlObject = component->create();
+    if (component->isError()) {
+        qWarning() << component->errors();
+        return false;
+    }
+    return true;
+}
+
+void compareResults(QVariant qmlResults, int resultSize, QString query)
+{
+    QSparqlConnection *connection = new QSparqlConnection("QTRACKER_DIRECT");
+    QSparqlResult *result = connection->exec(QSparqlQuery(query));
+    result->waitForFinished(); // for size();
+
+    QList<QVariant> list = qmlResults.toList();
+    QCOMPARE(list.length(), resultSize);
+    QHash<QString, QString> contactNamesValue;
+
+    for (int i=0; i<list.length();i++) {
+        QMap<QString, QVariant> resultMap = list[i].toMap();
+        // the result map is binding->value, store the binding
+        contactNamesValue[resultMap["u"].toString()] = resultMap["ng"].toString();
+    }
+
+    QCOMPARE(result->size(), resultSize);
+
+    while (result->next()) {
+        QCOMPARE(contactNamesValue[result->value(0).toString()], result->value(1).toString());
+    }
+    delete result;
+    delete connection;
+}
+
+bool waitForSignals(QSignalSpy *signalSpy, int numSignals)
+{
+    QTime timer;
+    int timeoutMs = 2000;
+    bool timeout = false;
+    timer.start();
+
+    while (signalSpy->count() !=numSignals && !(timeout = (timer.elapsed() > timeoutMs)))
+        QTest::qWait(100);
+
+    if (signalSpy->count() != numSignals) {
+        qWarning() << "Got" << signalSpy->count() << "signals, expected" << numSignals;
+        return false;
+    }
+    return !timeout;
+}
+
+} // end namespace
+
+tst_QSparqlQMLBindings::tst_QSparqlQMLBindings()
+{
+}
+
+tst_QSparqlQMLBindings::~tst_QSparqlQMLBindings()
+{
+}
+
+void tst_QSparqlQMLBindings::initTestCase()
+{
+    QCoreApplication::addLibraryPath("../../../plugins");
+    QCoreApplication::addLibraryPath("../../../imports");
+
+    const QString insertQueryTemplate =
+        "<qml-uri00%1> a nco:PersonContact, nie:InformationElement ;"
+        "nie:isLogicalPartOf <qsparql-qml-tests> ;"
+        "nco:nameGiven \"name00%1\" .";
+    QString insertQuery = "insert { <qsparql-qml-tests> a nie:InformationElement .";
+    for (int item = 1; item <= NUM_INSERTS; item++) {
+        insertQuery.append( insertQueryTemplate.arg(item) );
+    }
+    insertQuery.append(" }");
+
+    QSparqlConnection conn("QTRACKER_DIRECT");
+    const QSparqlQuery q(insertQuery,QSparqlQuery::InsertStatement);
+    QSparqlResult* r = conn.exec(q);
+    QVERIFY(!r->hasError());
+    r->waitForFinished();
+    QVERIFY(!r->hasError());
+    delete r;
+}
+
+void tst_QSparqlQMLBindings::cleanupTestCase()
+{
+    QSparqlConnection conn("QTRACKER");
+    const QSparqlQuery q("DELETE { ?u a rdfs:Resource . } "
+                         "  WHERE { ?u nie:isLogicalPartOf <qsparql-qml-tests> . }"
+                         "DELETE { <qsparql-qml=tests> a rdfs:Resource . }",
+                    QSparqlQuery::DeleteStatement);
+    QSparqlResult* r = conn.exec(q);
+    QVERIFY(!r->hasError());
+    r->waitForFinished();
+    QVERIFY(!r->hasError());
+    delete r;
+}
+
+void tst_QSparqlQMLBindings::init()
+{
+}
+
+void tst_QSparqlQMLBindings::cleanup()
+{
+    qmlCleanup();
+}
+
+void tst_QSparqlQMLBindings::sparql_connection_test()
+{
+    QPointer<QSparqlConnection> connPointer =
+        getObject<QSparqlConnection*>("connectionWithOptions");
+
+    QVERIFY(connPointer->isValid());
+    // now make sure the connection is "Ready"
+    Status status = (Status)callMethod("getStatus").toInt();
+    QCOMPARE(status, Ready);
+    QCOMPARE(connPointer->driverName(), QString("QTRACKER_DIRECT"));
+    // now make sure deleting the root object (i.e closing the qml viewer) deletes the connection object
+    qmlCleanup();
+    QVERIFY(connPointer.isNull());
+}
+
+void tst_QSparqlQMLBindings::sparql_connection_test_data()
+{
+    QList<QPair<QString, QVariant> > contextProperties;
+    contextProperties.append(qMakePair(QString("sparqlQueryString"),QVariant(contactSelectQuery)));
+    contextProperties.append(qMakePair(QString("setPortNumber"),QVariant(1234)));
+    contextProperties.append(qMakePair(QString("setHost"), QVariant("null")));
+
+    QVERIFY(loadQmlFile("qsparqlconnection.qml", contextProperties));
+}
+
+void tst_QSparqlQMLBindings::sparql_connection_select_query_test()
+{
+    // shares data with connection test
+    sparql_connection_test_data();
+
+    QSparqlConnection *connection =
+        getObject<QSparqlConnection*>("connectionWithOptions");
+
+    QVERIFY(connection->isValid());
+    Status status = (Status)callMethod("getStatus").toInt();
+    QCOMPARE(status, Ready);
+    // get the return value from qml
+    QVariant returnValue = callMethod("runSelectQuery");
+    compareResults(returnValue, NUM_INSERTS, contactSelectQuery);
+}
+
+void tst_QSparqlQMLBindings::sparql_connection_select_query_async_test()
+{
+    sparql_connection_test_data();
+    QSignalSpy resultSpy(qmlObject, SIGNAL(resultReadySignal()));
+
+    callMethod("runSelectQueryAsync");
+    // we should get two result ready signals, one from the property change
+    // notification (that a new SparqlConnection.result is ready), and one
+    // emitted from the javascript function that handels the resultReady() signal
+    // from within javascript
+    QVERIFY(waitForSignals(&resultSpy, 2));
+
+    // the SparqlConnection.result property should be the same as the
+    // result passed to the resultReady() signal slot
+    QVariant returnValue = callMethod("returnResults");
+    QVariant returnValueFromSlot = callMethod("returnResultsFromSlot");
+    QCOMPARE(returnValue, returnValueFromSlot);
+    compareResults(returnValue, NUM_INSERTS, contactSelectQuery);
+    compareResults(returnValueFromSlot, NUM_INSERTS, contactSelectQuery);
+}
+
+void tst_QSparqlQMLBindings::sparql_connection_ask_query_test()
+{
+    sparql_connection_test_data();
+    QString askQuery = "ASK { <qml-uri001> a nco:PersonContact }";
+    QVariant result = callMethod("runAskQuery", askQuery);
+    QVERIFY(result.canConvert(QVariant::Bool));
+    QVERIFY(result.toBool());
+    askQuery = "ASK { <falseask> a nco:PersonContact }";
+    result = callMethod("runAskQuery", askQuery);
+    QVERIFY(result.canConvert(QVariant::Bool));
+    QVERIFY(!result.toBool());
+}
+
+void tst_QSparqlQMLBindings::sparql_connection_ask_query_async_test()
+{
+    sparql_connection_test_data();
+    QSignalSpy resultSpy(qmlObject, SIGNAL(resultReadySignal()));
+    QString askQuery = "ASK { <qml-uri001> a nco:PersonContact }";
+    callMethod("runAskQueryAsync", askQuery);
+    QVERIFY(waitForSignals(&resultSpy, 1));
+
+    QVariant returnValue = callMethod("returnResults");
+    QVERIFY(returnValue.canConvert(QVariant::Bool));
+    QVERIFY(returnValue.toBool());
+
+    askQuery = "ASK { <falseask> a nco:PersonContact }";
+    resultSpy.clear();
+    callMethod("runAskQueryAsync", askQuery);
+    QVERIFY(waitForSignals(&resultSpy, 1));
+
+    returnValue = callMethod("returnResults");
+    QVERIFY(returnValue.canConvert(QVariant::Bool));
+    QVERIFY(!returnValue.toBool());
+}
+
+void tst_QSparqlQMLBindings::sparql_connection_update_query_test()
+{
+    sparql_connection_test_data();
+
+    callMethod("insertContact"); // inserts one new contact
+    QVariant returnValue = callMethod("runSelectQuery");
+    compareResults(returnValue, NUM_INSERTS+1, contactSelectQuery);
+
+    // now delete the result
+    callMethod("deleteContact");
+    returnValue = callMethod("runSelectQuery");
+    compareResults(returnValue, NUM_INSERTS, contactSelectQuery);
+}
+
+void tst_QSparqlQMLBindings::sparql_connection_update_query_async_test()
+{
+    sparql_connection_test_data();
+
+    QSignalSpy resultSpy(qmlObject, SIGNAL(resultReadySignal()));
+    callMethod("insertContactAsync");
+
+    QVERIFY(waitForSignals(&resultSpy, 1));
+
+    QVariant returnValue = callMethod("runSelectQuery");
+    compareResults(returnValue, NUM_INSERTS+1, contactSelectQuery);
+
+    callMethod("deleteContactAsync");
+    // we got a signal from "runSelectQuery" once the results are done, so need to
+    // wait for the signal from the delete query, hence 3
+    QVERIFY(waitForSignals(&resultSpy, 3));
+
+    returnValue = callMethod("runSelectQuery");
+    compareResults(returnValue, NUM_INSERTS, contactSelectQuery);
+}
+
+void tst_QSparqlQMLBindings::sparql_connection_construct_query_test()
+{
+    // tracker doesn't support construct queries, so this should
+    // be in error. TODO: Test with endpoint driver
+    sparql_connection_test_data();
+    QVariant returnValue = callMethod("runConstructQuery");
+    QCOMPARE(returnValue.toInt(), -1);
+    Status status = (Status)callMethod("getStatus").toInt();
+    QCOMPARE(status, Error);
+    returnValue = callMethod("getLastError");
+    QCOMPARE(returnValue.toString(), QString("Unsupported statement type"));
+}
+
+void tst_QSparqlQMLBindings::sparql_connection_options_test()
+{
+    QFETCH(int, portNumber);
+    QFETCH(QString, hostName);
+
+    QVariant returnValue = callMethod("returnConnectionOptions");
+
+    // compare the values we set from what was returned
+    QMap<QString, QVariant> map = returnValue.toMap();
+    QMap<QString, QVariant>::const_iterator i = map.constBegin();
+    while (i != map.constEnd()) {
+        if (i.key() == "port")
+            QCOMPARE(i.value().toInt(), portNumber);
+        else if (i.key() == "hostName")
+            QCOMPARE(i.value().toString(), hostName);
+        else
+            QCOMPARE(i.value().toString(), QString(""));
+        ++i;
+    }
+}
+
+void tst_QSparqlQMLBindings::sparql_connection_options_test_data()
+{
+    int portNumber = 1234;
+    QString hostName = "localhost";
+
+    QTest::addColumn<int>("portNumber");
+    QTest::addColumn<QString>("hostName");
+    QTest::newRow("connection_options_test")
+        << portNumber
+        << hostName;
+
+    QList<QPair<QString, QVariant> > contextProperties;
+    contextProperties.append(qMakePair(QString("sparqlQueryString"),QVariant(contactSelectQuery)));
+    contextProperties.append(qMakePair(QString("setPortNumber"),QVariant(portNumber)));
+    contextProperties.append(qMakePair(QString("setHost"), QVariant(hostName)));
+    QVERIFY(loadQmlFile("qsparqlconnection.qml", contextProperties));
+}
+
+void tst_QSparqlQMLBindings::sparql_connection_bound_values_test()
+{
+    sparql_connection_test_data();
+    // insert a new contact using bound values
+    callMethod("insertBoundContact");
+    // ask to see if contact was inserted, using bound values
+    QVariant returnValue = callMethod("askBoundContact");
+    QVERIFY(returnValue.canConvert(QVariant::Bool));
+    QVERIFY(returnValue.toBool());
+    // check the select value
+    QList<QVariant> selectValue = callMethod("selectBoundContact").toList();
+    // should only be one contact
+    QCOMPARE(selectValue.size(), 1);
+
+    // Now delete the contact
+    callMethod("deleteBoundContact");
+    // ask the contact again, should be false
+    returnValue = callMethod("askBoundContact");
+    QVERIFY(!returnValue.toBool());
+    selectValue = callMethod("selectBoundContact").toList();
+    QCOMPARE(selectValue.size(), 0);
+}
+
+void tst_QSparqlQMLBindings::sparql_query_model_test()
+{
+    QSignalSpy countSpy(qmlObject, SIGNAL(modelCountChanged()));
+    QSignalSpy readySpy(qmlObject, SIGNAL(modelStatusReady()));
+
+    QSparqlConnection *connection =
+        getObject<QSparqlConnection*>("sparqlConnection");
+    QPointer<QSparqlQueryModel> model =
+        getObject<QSparqlQueryModel *>("queryModel");
+    QVERIFY(connection->isValid());
+
+    // status of the model should be "loading" before the model finished();
+    QVERIFY(model->rowCount() != NUM_INSERTS);
+    Status status = (Status)callMethod("getStatus").toInt();
+    QCOMPARE(status, Loading);
+    QVERIFY(waitForSignals(&countSpy, NUM_INSERTS));
+    QVERIFY(waitForSignals(&readySpy, 1));
+
+    // status of the model should now be ready
+    status = (Status)callMethod("getStatus").toInt();
+    QCOMPARE(status, Ready);
+
+    // get the number of rows from the list model in qml
+    QVariant returnValue = callMethod("getCount");
+
+    QCOMPARE(NUM_INSERTS, returnValue.toInt());
+    QCOMPARE(returnValue.toInt(), model->rowCount());
+
+    // verify the model is deleted when the QML object is destroyed
+    qmlCleanup();
+    QVERIFY(model.isNull());
+}
+
+void tst_QSparqlQMLBindings::sparql_query_model_test_data()
+{
+    QList<QPair<QString, QVariant> > contextProperties;
+    contextProperties.append(qMakePair(QString("sparqlQueryString"),QVariant(contactSelectQuery)));
+    QVERIFY(loadQmlFile("qsparqlresultlist.qml", contextProperties));
+}
+
+void tst_QSparqlQMLBindings::sparql_query_model_reload_test()
+{
+    sparql_query_model_test_data();
+    QSignalSpy countSpy(qmlObject, SIGNAL(modelCountChanged()));
+    QSignalSpy readySpy(qmlObject, SIGNAL(modelStatusReady()));
+
+    // wait for the model to finish
+    QVERIFY(waitForSignals(&readySpy, 1));
+    // we used a query with one contact, check to see the count was correct
+    QVERIFY(waitForSignals(&countSpy, NUM_INSERTS));
+    QVariant returnValue = callMethod("getCount");
+    QCOMPARE(returnValue.toInt(), NUM_INSERTS);
+
+    readySpy.clear();
+    countSpy.clear();
+    // check the status is ready
+    Status status = (Status)callMethod("getStatus").toInt();
+    QCOMPARE(status, Ready);
+    // now reload the model, we should get one signal after clearing the model
+    // model, and 10 inserts
+    callMethod("reloadModel");
+    // reloading the model should set the status to loading again
+    status = (Status)callMethod("getStatus").toInt();
+    QCOMPARE(status, Loading);
+    QVERIFY(waitForSignals(&readySpy, 1));
+    QVERIFY(waitForSignals(&countSpy, NUM_INSERTS+1));
+    // should be ready when finished
+    status = (Status)callMethod("getStatus").toInt();
+    QCOMPARE(status, Ready);
+}
+
+void tst_QSparqlQMLBindings::sparql_query_model_get_test()
+{
+    sparql_query_model_test_data();
+    QSignalSpy countSpy(qmlObject, SIGNAL(modelCountChanged()));
+
+    QSparqlQueryModel *model =
+        getObject<QSparqlQueryModel *>("queryModel");
+
+    // wait for the model to finish
+    QVERIFY(waitForSignals(&countSpy, NUM_INSERTS));
+
+    // now check that the result from get(i) is the same
+    // as the result from model.getRow()
+    for (int i=0;i<model->rowCount();i++) {
+        QSparqlResultRow modelRow = model->resultRow(i);
+        QVariantMap row = callMethod("getRow", i).toMap();
+
+        QString binding0 = modelRow.binding(0).name();
+        QString binding1 = modelRow.binding(1).name();
+        QVariant value0 = modelRow.value(0);
+        QVariant value1 = modelRow.value(1);
+
+        QCOMPARE(row[binding0], value0);
+        QCOMPARE(row[binding1], value1);
+    }
+}
+
+void tst_QSparqlQMLBindings::sparql_query_model_test_role_names()
+{
+    QString select1 = "select ?u ?ng ?nf"
+                      "{ ?u a nco:PersonContact; nco:nameGiven ?ng; nco:nameFamily ?nf }";
+    QString select2 = "select ?u fn:string-join( (?ng, ?nf), ' ') AS ?joinName "
+                      "{ ?u a nco:PersonContact; nco:nameGiven ?ng; nco:nameFamily ?nf }";
+    QList<QPair<QString, QVariant> > contextProperties;
+    contextProperties.append(qMakePair(QString("sparqlQueryString"), QVariant(select1)));
+    QVERIFY(loadQmlFile("qsparqlresultlist.qml", contextProperties));
+
+    QSparqlQueryModel *model =
+        getObject<QSparqlQueryModel *>("queryModel");
+
+    QHash<int, QByteArray> roleNames = model->roleNames();
+    // wait for result
+    QTest::qWait(500);
+    // role names start from Qt::UserRole + 1,
+    QCOMPARE(roleNames[Qt::UserRole+1], QByteArray("u"));
+    QCOMPARE(roleNames[Qt::UserRole+2], QByteArray("ng"));
+    QCOMPARE(roleNames[Qt::UserRole+3], QByteArray("nf"));
+
+}
+
+void tst_QSparqlQMLBindings::sparql_legacy_test()
+{
+    // This test simple checks to see if the old SparqlResultList binding still
+    // works, along with its options
+    QList<QPair<QString, QVariant> > contextProperties;
+    // If theres a problem with finding the binding, or in setting a property (driverName())
+    // this will return false
+    QVERIFY(loadQmlFile("qsparqllegacy.qml", contextProperties));
+}
+
+QTEST_MAIN(tst_QSparqlQMLBindings)
+#include "tst_qsparql_qmlbindings.moc"
--- tests/auto/qsparql_threading/clean_data_threading.rq
+++ tests/auto/qsparql_threading/clean_data_threading.rq
-DELETE
-{
-    ?u a rdfs:Resource .
-}
-WHERE
-{
-    ?u nie:isLogicalPartOf <qsparql-threading-tests> .
-}
-DELETE
-{
-    <qsparql-threading-tests> a rdfs:Resource .
-}
--- tests/auto/qsparql_threading/qsparql_threading.pro
+++ tests/auto/qsparql_threading/qsparql_threading.pro
@@ -1,6 +1,18 @@
 include(../sparqltest.pri)
-CONFIG += qt warn_on console depend_includepath testcase
+CONFIG += qt warn_on console depend_includepath
 QT += testlib xml
 SOURCES  += tst_qsparql_threading.cpp
 
 #QT = sparql # enable this later
+
+TEST_EXE = ./tst_qsparql_threading
+TEST_CASES = concurrentTrackerQueries
+
+check.depends = $$TARGET
+check.commands = $$TEST_EXE $$TEST_CASES
+
+memcheck.depends = $$TARGET
+memcheck.commands = $$VALGRIND $$VALGRIND_OPT \
+                      $$TEST_EXE $$TEST_CASES
+
+QMAKE_EXTRA_TARGETS += check memcheck
--- tests/auto/qsparql_threading/tst_qsparql_threading.cpp
+++ tests/auto/qsparql_threading/tst_qsparql_threading.cpp
@@ -52,6 +52,8 @@
 
 #include <QtSparql/QtSparql>
 
+#include "../messagerecorder.h"
+
 #define TEST_PORT 1111
 
 class Thread : public QThread
@@ -101,21 +103,16 @@
     void concurrentEndpointQueries_thread();
     void concurrentVirtuosoQueries_thread();
     void concurrentTrackerQueries_thread();
-    void concurrentTrackerDirectQueries_thread();
-    void concurrentTrackerDirectInserts_thread();
-    void subThreadTrackerDirectQuery_thread();
 
     void queryFinished();
     void resultsReturned(int count);
 
 private Q_SLOTS:
     void initTestCase();
+    void cleanupTestCase();
     void concurrentEndpointQueries();
     void concurrentVirtuosoQueries();
     void concurrentTrackerQueries();
-    void concurrentTrackerDirectQueries();
-    void concurrentTrackerDirectInserts();
-    void subThreadTrackerDirectQuery();
 };
 tst_QSparqlThreading *tst_QSparqlThreading::_self;
 
@@ -220,6 +217,20 @@
     delete r;
 }
 
+void tst_QSparqlThreading::cleanupTestCase()
+{
+    QSparqlConnection conn("QTRACKER");
+    QSparqlQuery q("DELETE { ?u a rdfs:Resource . }"
+                   "WHERE  { ?u nie:isLogicalPartOf <qsparql-threading-tests> . }"
+                   "DELETE { <qsparql-threading-tests> a rdfs:Resource . }",
+                    QSparqlQuery::DeleteStatement);
+    QSparqlResult* r = conn.exec(q);
+    CHECK_QSPARQL_RESULT(r);
+    r->waitForFinished();
+    CHECK_QSPARQL_RESULT(r);
+    delete r;
+}
+
 void tst_QSparqlThreading::concurrentEndpointQueries_thread()
 {
     sem1.acquire();
@@ -344,200 +355,5 @@
     QCOMPARE(r1->size(), r2->size());
 }
 
-void tst_QSparqlThreading::concurrentTrackerDirectQueries_thread()
-{
-    sem1.acquire();
-
-    conn2 = new QSparqlConnection("QTRACKER_DIRECT");
-
-    QSparqlQuery q("select ?u {?u a rdfs:Resource .}");
-
-    r2 = conn2->exec(q);
-
-    connect(r2, SIGNAL(finished()), QThread::currentThread(), SLOT(queryFinished()));
-    connect(r2, SIGNAL(dataReady(int)), QThread::currentThread(), SLOT(resultsReturned(int)));
-    sem2.release();
-
-    r2->waitForFinished();
-
-    // set the parent to 0 so we don't delete the result with the connection
-    r2->setParent(0);
-    // Delete the connection now, so we don't delete it AFTER the thread has been deleted
-    delete conn2;
-    conn2=0;
-}
-
-void tst_QSparqlThreading::concurrentTrackerDirectQueries()
-{
-    QPointer<Thread> th = new Thread;
-
-    sem1.release();
-    conn1 = new QSparqlConnection("QTRACKER_DIRECT");
-
-    QSparqlQuery q("select ?u {?u a rdfs:Resource .}");
-    r1 = conn1->exec(q);
-    connect(r1, SIGNAL(finished()), SLOT(queryFinished()));
-    connect(r1, SIGNAL(dataReady(int)), SLOT(resultsReturned(int)));
-    sem2.acquire();
-
-    r1->waitForFinished();
-
-    if (!th.isNull())
-        waitForSignal(th, SIGNAL(finished()));
-    CHECK_QSPARQL_RESULT(r1);
-    CHECK_QSPARQL_RESULT(r2);
-    QCOMPARE(r1->size(), r2->size());
-
-    // Delete r2 now since we reparented it to avoid it being deleted
-    // when we deleted the connection
-    delete r2;
-    r2 = 0;
-}
-
-void tst_QSparqlThreading::concurrentTrackerDirectInserts_thread()
-{
-    sem1.acquire();
-    conn2 = new QSparqlConnection("QTRACKER_DIRECT");
-
-    QSparqlQuery q("insert { ?:addeduri a nco:PersonContact; "
-                     "nie:isLogicalPartOf <qsparql-threading-tests> ;"
-                     "nco:nameGiven \"addedname007\" .}",
-                     QSparqlQuery::InsertStatement);
-    q.bindValue(conn2->createUrn("addeduri"));
-
-    r2 = conn2->exec(q);
-    connect(r2, SIGNAL(finished()), QThread::currentThread(), SLOT(queryFinished()));
-    connect(r2, SIGNAL(dataReady(int)), QThread::currentThread(), SLOT(resultsReturned(int)));
-    sem2.release();
-    r2->waitForFinished();
-
-    CHECK_QSPARQL_RESULT(r2);
-
-    delete r2;
-
-    // Verify that the insertion succeeded
-    QSparqlQuery q2("select ?addeduri {?addeduri a nco:PersonContact; "
-                   "nie:isLogicalPartOf <qsparql-threading-tests> ;"
-                   "nco:nameGiven \"addedname007\" .}");
-    r2 = conn2->exec(q2);
-    QVERIFY(r2 != 0);
-    r2->waitForFinished();
-    QCOMPARE(r2->size(), 1);
-    if (r2->next()) {
-        // We can only compare the first 9 chars because the rest is a new uuid string
-        QCOMPARE(r2->value(0).toString().mid(0, 9), QString("urn:uuid:"));
-    }
-
-    // Delete the uri
-    QSparqlQuery del("delete { ?:addeduri a rdfs:Resource. }",
-                     QSparqlQuery::DeleteStatement);
-
-    del.bindValue(r2->binding(0));
-    delete r2;
-    r2 = conn2->exec(del);
-    qDebug() << "r2 delete query:" << r2->query();
-    QVERIFY(r2 != 0);
-    r2->waitForFinished(); // this test is synchronous only
-    CHECK_QSPARQL_RESULT(r2);
-    delete r2;
-
-    // Verify that it got deleted
-    r2 = conn2->exec(q2);
-    QVERIFY(r2 != 0);
-    r2->waitForFinished();
-    QCOMPARE(r2->size(), 0);
-    delete r2;
-
-}
-
-void tst_QSparqlThreading::concurrentTrackerDirectInserts()
-{
-    QPointer<Thread> th = new Thread;
-
-    sem1.release();
-    conn1 = new QSparqlConnection("QTRACKER_DIRECT");
-
-    QSparqlQuery q1("insert { ?:addeduri a nco:PersonContact; "
-                     "nie:isLogicalPartOf <qsparql-threading-tests> ;"
-                     "nco:nameGiven \"addedname008\" .}",
-                     QSparqlQuery::InsertStatement);
-    q1.bindValue(conn1->createUrn("addeduri"));
-
-    r1 = conn1->exec(q1);
-    connect(r1, SIGNAL(finished()), SLOT(queryFinished()));
-    connect(r1, SIGNAL(dataReady(int)), SLOT(resultsReturned(int)));
-    sem2.acquire();
-
-    r1->waitForFinished();
-
-    CHECK_QSPARQL_RESULT(r1);
-
-    delete r1;
-
-    // Verify that the insertion succeeded
-    QSparqlQuery q2("select ?addeduri {?addeduri a nco:PersonContact; "
-                   "nie:isLogicalPartOf <qsparql-threading-tests> ;"
-                   "nco:nameGiven \"addedname008\" .}");
-    r1 = conn1->exec(q2);
-    QVERIFY(r1 != 0);
-    r1->waitForFinished();
-    QCOMPARE(r1->size(), 1);
-    if (r1->next()) {
-        // We can only compare the first 9 chars because the rest is a new uuid string
-        QCOMPARE(r1->value(0).toString().mid(0, 9), QString("urn:uuid:"));
-    }
-
-    // Delete the uri
-    QSparqlQuery del("delete { ?:addeduri a rdfs:Resource. }",
-                     QSparqlQuery::DeleteStatement);
-
-    del.bindValue(r1->binding(0));
-    delete r1;
-    r1 = conn1->exec(del);
-    qDebug() << "r1 delete query:" << r1->query();
-    CHECK_QSPARQL_RESULT(r1);
-    r1->waitForFinished(); // this test is synchronous only
-    CHECK_QSPARQL_RESULT(r1);
-    delete r1;
-
-    // Verify that it got deleted
-    r1 = conn1->exec(q2);
-    QVERIFY(r1 != 0);
-    r1->waitForFinished();
-    QCOMPARE(r1->size(), 0);
-    delete r1;
-
-    if (!th.isNull()) {
-        waitForSignal(th, SIGNAL(finished()));
-    }
-}
-
-void tst_QSparqlThreading::subThreadTrackerDirectQuery_thread()
-{
-    sem1.acquire();
-    conn2 = new QSparqlConnection("QTRACKER_DIRECT");
-
-    QSparqlQuery q("select ?u {?u a rdfs:Resource .}");
-    r2 = conn2->exec(q);
-    connect(r2, SIGNAL(finished()), QThread::currentThread(), SLOT(queryFinished()));
-    connect(r2, SIGNAL(dataReady(int)), QThread::currentThread(), SLOT(resultsReturned(int)));
-    sem2.release();
-    r2->waitForFinished();
-}
-
-void tst_QSparqlThreading::subThreadTrackerDirectQuery()
-{
-    QPointer<Thread> th = new Thread;
-
-    sem1.release();
-    sem2.acquire();
-
-    if (!th.isNull()) {
-        waitForSignal(th, SIGNAL(finished()));
-    }
-
-    CHECK_QSPARQL_RESULT(r2);
-}
-
 QTEST_MAIN(tst_QSparqlThreading)
 #include "tst_qsparql_threading.moc"
--- tests/auto/qsparql_tracker/tst_qsparql_tracker.cpp
+++ tests/auto/qsparql_tracker/tst_qsparql_tracker.cpp
@@ -42,10 +42,6 @@
 #include <QtTest/QtTest>
 #include <QtSparql/QtSparql>
 
-//const QString qtest(qTableName( "qtest", __FILE__ )); // FIXME: what's this
-
-//TESTED_FILES=
-
 class tst_QSparqlTracker : public QObject
 {
     Q_OBJECT
@@ -60,22 +56,13 @@
     void init();
     void cleanup();
 
-    void query_contacts();
-    void query_contacts_syncExec();
-    void insert_and_delete_contact();
     void insert_new_urn();
 
-    void query_with_error();
-
     void batch_update();
 
     void iterate_result();
 
     void delete_unfinished_result();
-
-    void go_beyond_columns_number();
-
-    void destroy_connection_before_result();
 };
 
 namespace {
@@ -164,106 +151,6 @@
 {
 }
 
-void tst_QSparqlTracker::query_contacts()
-{
-    QSparqlConnection conn("QTRACKER");
-    QSparqlQuery q("select ?u ?ng {?u a nco:PersonContact; "
-                   "nie:isLogicalPartOf <qsparql-tracker-tests> ;"
-                   "nco:nameGiven ?ng .}");
-    QSparqlResult* r = conn.exec(q);
-    CHECK_QSPARQL_RESULT(r);
-    r->waitForFinished(); // this test is syncronous only
-    CHECK_QSPARQL_RESULT(r);
-    QCOMPARE(r->size(), 3);
-    QHash<QString, QString> contactNames;
-    while (r->next()) {
-        QCOMPARE(r->current().count(), 2);
-        contactNames[r->value(0).toString()] = r->value(1).toString();
-    }
-    QCOMPARE(contactNames.size(), 3);
-    QCOMPARE(contactNames["uri001"], QString("name001"));
-    QCOMPARE(contactNames["uri002"], QString("name002"));
-    QCOMPARE(contactNames["uri003"], QString("name003"));
-    delete r;
-}
-
-void tst_QSparqlTracker::query_contacts_syncExec()
-{
-    QSparqlConnection conn("QTRACKER");
-    QSparqlQuery q("select ?u ?ng {?u a nco:PersonContact; "
-                   "nie:isLogicalPartOf <qsparql-tracker-tests> ;"
-                   "nco:nameGiven ?ng .}");
-    QSparqlResult* r = conn.syncExec(q);
-    CHECK_QSPARQL_RESULT(r);
-    QCOMPARE(r->size(), 3);
-    QHash<QString, QString> contactNames;
-    while (r->next()) {
-        QCOMPARE(r->current().count(), 2);
-        contactNames[r->value(0).toString()] = r->value(1).toString();
-    }
-    QCOMPARE(contactNames.size(), 3);
-    QCOMPARE(contactNames["uri001"], QString("name001"));
-    QCOMPARE(contactNames["uri002"], QString("name002"));
-    QCOMPARE(contactNames["uri003"], QString("name003"));
-    delete r;
-}
-
-void tst_QSparqlTracker::insert_and_delete_contact()
-{
-    // This test will leave unclean test data into tracker if it crashes.
-    QSparqlConnection conn("QTRACKER");
-    QSparqlQuery add("insert { <addeduri001> a nco:PersonContact; "
-                     "nie:isLogicalPartOf <qsparql-tracker-tests> ;"
-                     "nco:nameGiven \"addedname001\" .}",
-                     QSparqlQuery::InsertStatement);
-
-    QSparqlResult* r = conn.exec(add);
-    CHECK_QSPARQL_RESULT(r);
-    r->waitForFinished(); // this test is syncronous only
-    CHECK_QSPARQL_RESULT(r);
-    delete r;
-
-    // Verify that the insertion succeeded
-    QSparqlQuery q("select ?u ?ng {?u a nco:PersonContact; "
-                   "nie:isLogicalPartOf <qsparql-tracker-tests> ;"
-                   "nco:nameGiven ?ng .}");
-    QHash<QString, QString> contactNames;
-    r = conn.exec(q);
-    CHECK_QSPARQL_RESULT(r);
-    r->waitForFinished();
-    CHECK_QSPARQL_RESULT(r);
-    QCOMPARE(r->size(), 4);
-    while (r->next()) {
-        contactNames[r->binding(0).value().toString()] = r->binding(1).value().toString();
-    }
-    QCOMPARE(contactNames.size(), 4);
-    QCOMPARE(contactNames["addeduri001"], QString("addedname001"));
-    delete r;
-
-    // Delete the uri
-    QSparqlQuery del("delete { <addeduri001> a rdfs:Resource. }",
-                     QSparqlQuery::DeleteStatement);
-
-    r = conn.exec(del);
-    CHECK_QSPARQL_RESULT(r);
-    r->waitForFinished(); // this test is syncronous only
-    CHECK_QSPARQL_RESULT(r);
-    delete r;
-
-    // Verify that it got deleted
-    contactNames.clear();
-    r = conn.exec(q);
-    CHECK_QSPARQL_RESULT(r);
-    r->waitForFinished();
-    CHECK_QSPARQL_RESULT(r);
-    QCOMPARE(r->size(), 3);
-    while (r->next()) {
-        contactNames[r->binding(0).value().toString()] = r->binding(1).value().toString();
-    }
-    QCOMPARE(contactNames.size(), 3);
-    delete r;
-}
-
 void tst_QSparqlTracker::insert_new_urn()
 {
     // This test will leave unclean test data in tracker if it crashes.
@@ -324,20 +211,6 @@
     delete r;
 }
 
-void tst_QSparqlTracker::query_with_error()
-{
-    // This test will print out warnings
-    testLogLevel = QtCriticalMsg;
-    QSparqlConnection conn("QTRACKER");
-    QSparqlQuery q("this is not a valid query");
-    QSparqlResult* r = conn.exec(q);
-    QVERIFY(r != 0);
-    r->waitForFinished(); // this test is syncronous only
-    QVERIFY(r->hasError());
-    QCOMPARE(r->lastError().type(), QSparqlError::StatementError);
-    delete r;
-}
-
 void tst_QSparqlTracker::batch_update()
 {
     // The "batch" option has been removed from API documentation as it is replaced by
@@ -459,53 +332,5 @@
     QTest::qWait(1000);
 }
 
-void tst_QSparqlTracker::go_beyond_columns_number()
-{
-    // This test will print out warnings
-    testLogLevel = QtCriticalMsg;
-    QSparqlConnection conn("QTRACKER");
-    QSparqlQuery q("select ?u ?ng {?u a nco:PersonContact; "
-                   "nie:isLogicalPartOf <qsparql-tracker-tests> ;"
-                   "nco:nameGiven ?ng .}");
-    QSparqlResult* r = conn.exec(q);
-    CHECK_QSPARQL_RESULT(r);
-    r->waitForFinished(); // this test is syncronous only
-    CHECK_QSPARQL_RESULT(r);
-    QCOMPARE(r->size(), 3);
-    while (r->next()) {
-        QCOMPARE(r->current().count(), 2);
-        QCOMPARE(r->value(5).toString(), QString());
-        QCOMPARE(r->binding(5).toString(), QString());
-    }
-    delete r;
-}
-
-void tst_QSparqlTracker::destroy_connection_before_result()
-{
-    const QString connectionType("QTRACKER");
-    QSparqlConnection* conn = new QSparqlConnection(connectionType);
-    QSparqlResult* r = 0;
-    const QSparqlQuery q("select ?u ?ng {?u a nco:PersonContact; "
-                   "nie:isLogicalPartOf <qsparql-tracker-tests> ;"
-                   "nco:nameGiven ?ng .}");
-
-    r = conn->exec(q);
-    QVERIFY( r );
-    QVERIFY( !r->hasError() );
-
-    // Take ownership of the result to prevent connection from deleting it
-    r->setParent(this);
-    // Delete the connection before the result
-    delete conn; conn = 0;
-
-    // Wait in event loop to let any asynchronous activity complete
-    QTest::qWait(500);
-
-    // Delete the result
-    delete r; r = 0;
-    // Wait in event loop to let any asynchronous activity complete
-    QTest::qWait(500);
-}
-
 QTEST_MAIN( tst_QSparqlTracker )
 #include "tst_qsparql_tracker.moc"
--- tests/auto/qsparql_tracker_direct/qsparql_tracker_direct.pro
+++ tests/auto/qsparql_tracker_direct/qsparql_tracker_direct.pro
@@ -1,8 +1,9 @@
 include(../sparqltest.pri)
 CONFIG += qt warn_on console depend_includepath
 QT += testlib
-HEADERS += ../tracker_direct_common.h
-SOURCES  += tst_qsparql_tracker_direct.cpp ../tracker_direct_common.cpp
+HEADERS += ../tracker_direct_common.h ../utils/testdata.h
+SOURCES  += tst_qsparql_tracker_direct.cpp ../tracker_direct_common.cpp \
+            ../utils/testdata.cpp
 
 check.depends = $$TARGET
 check.commands = ./tst_qsparql_tracker_direct
--- tests/auto/qsparql_tracker_direct/tst_qsparql_tracker_direct.cpp
+++ tests/auto/qsparql_tracker_direct/tst_qsparql_tracker_direct.cpp
@@ -39,14 +39,11 @@
 
 #include "../testhelpers.h"
 #include "../tracker_direct_common.h"
+#include "../utils/testdata.h"
 
 #include <QtTest/QtTest>
 #include <QtSparql/QtSparql>
 
-//const QString qtest(qTableName( "qtest", __FILE__ )); // FIXME: what's this
-
-//TESTED_FILES=
-
 class tst_QSparqlTrackerDirect : public TrackerDirectCommon
 {
     Q_OBJECT
@@ -68,9 +65,6 @@
     void cleanup();
 
     void qsparqlresultrow();
-    void query_contacts_async();
-    void ask_contacts();
-    void insert_and_delete_contact_async();
     void insert_new_urn();
 
     void delete_unfinished_result();
@@ -92,8 +86,6 @@
     void delete_connection_immediately();
     void delete_connection_before_a_wait();
 
-    void go_beyond_columns_number();
-
     void create_2_connections();
 
     void unsupported_statement_type();
@@ -112,20 +104,92 @@
     void query_with_data_ready_set();
     void query_with_data_ready_set_data();
 
-    void destroy_connection_before_result();
-    void destroy_connection_before_result_data();
-    void destroy_connection_waitForFinished();
-    void destroy_connection_verify_result();
-    void destroy_connection_verify_result_async();
     void destroy_connection_partially_iterated_results();
 
-    void validate_threadpool_results();
     void waitForFinished_after_dataReady();
 
+    void test_threadpool_priority_select_results();
+    void test_threadpool_priority_update_results();
+
 private:
     QSharedPointer<QSignalSpy> dataReadySpy;
 };
 
+namespace {
+class FinishedSignalReceiver : public QObject
+{
+    Q_OBJECT
+    QList<QSparqlResult*> allResults;
+    QSet<QObject*> pendingResults;
+    QSignalMapper signalMapper;
+
+public:
+
+    QList<QSparqlResult*> resultOrder;
+
+    FinishedSignalReceiver()
+    {
+        connect(&signalMapper, SIGNAL(mapped(QObject*)), this, SLOT(onFinished(QObject*)));
+    }
+
+    ~FinishedSignalReceiver()
+    {
+        qDeleteAll(allResults);
+    }
+
+    const QList<QSparqlResult*>& results() const
+    {
+        return allResults;
+    }
+
+    void append(QSparqlResult* r)
+    {
+        allResults.append(r);
+        if (!r->isFinished()) {
+            pendingResults.insert(r);
+            connectFinishedSignal(r);
+        }
+    }
+
+    bool waitForAllFinished(int silenceTimeoutMs)
+    {
+        QTime timeoutTimer;
+        timeoutTimer.start();
+        bool timeout = false;
+        while (!pendingResults.empty() && !timeout) {
+            const int pendingResultsCountBefore = pendingResults.count();
+            QTest::qWait(silenceTimeoutMs / 10);
+            if (pendingResults.count() < pendingResultsCountBefore) {
+                timeoutTimer.restart();
+            }
+            else if (timeoutTimer.elapsed() > silenceTimeoutMs) {
+                timeout = true;
+            }
+        }
+        return !timeout;
+    }
+
+private:
+    void connectFinishedSignal(QSparqlResult* r)
+    {
+        // Use QSignalMapper to be able to figure out which result was
+        // finished in onFinished().
+        // Note that using sender() would not work as it returns null when
+        // signal is emitted from another thread.
+        signalMapper.setMapping(r, r);
+        connect(r, SIGNAL(finished()), &signalMapper, SLOT(map()));
+    }
+
+private slots:
+    void onFinished(QObject* r)
+    {
+        pendingResults.remove(r);
+        resultOrder.append((QSparqlResult*)r);
+    }
+};
+
+}  // namespace
+
 tst_QSparqlTrackerDirect::tst_QSparqlTrackerDirect()
 {
 }
@@ -225,134 +289,6 @@
     delete r;
 }
 
-void tst_QSparqlTrackerDirect::query_contacts_async()
-{
-    QSparqlConnection conn("QTRACKER_DIRECT");
-    QSparqlQuery q("select ?u ?ng {?u a nco:PersonContact; "
-                   "nie:isLogicalPartOf <qsparql-tracker-direct-tests> ;"
-                   "nco:nameGiven ?ng .}");
-    QSparqlResult* r = conn.exec(q);
-    CHECK_QSPARQL_RESULT(r);
-
-    QTime timer;
-    timer.start();
-    QSignalSpy spy(r, SIGNAL(finished()));
-    while (spy.count() == 0 && timer.elapsed() < 5000) {
-        QTest::qWait(100);
-    }
-
-    QCOMPARE(spy.count(), 1);
-
-    CHECK_QSPARQL_RESULT(r);
-    QCOMPARE(r->size(), 3);
-    QHash<QString, QString> contactNames;
-    while (r->next()) {
-        QCOMPARE(r->current().count(), 2);
-        contactNames[r->value(0).toString()] = r->value(1).toString();
-    }
-    QCOMPARE(contactNames.size(), 3);
-    QCOMPARE(contactNames["uri001"], QString("name001"));
-    QCOMPARE(contactNames["uri002"], QString("name002"));
-    QCOMPARE(contactNames["uri003"], QString("name003"));
-    delete r;
-}
-
-void tst_QSparqlTrackerDirect::ask_contacts()
-{
-    QSparqlConnection conn("QTRACKER_DIRECT");
-    QSparqlQuery q1("ask {<uri003> a nco:PersonContact; "
-                   "nie:isLogicalPartOf <qsparql-tracker-direct-tests> ;"
-                   "nco:nameGiven \"name003\" .}", QSparqlQuery::AskStatement);
-    QSparqlResult* r = conn.exec(q1);
-    CHECK_QSPARQL_RESULT(r);
-    r->waitForFinished(); // this test is synchronous only
-    CHECK_QSPARQL_RESULT(r);
-    QCOMPARE(r->boolValue(), true);
-    delete r;
-
-    QSparqlQuery q2("ask {<uri005> a nco:PersonContact; "
-                   "nie:isLogicalPartOf <qsparql-tracker-direct-tests> ;"
-                   "nco:nameGiven \"name005\" .}", QSparqlQuery::AskStatement);
-    r = conn.exec(q2);
-    CHECK_QSPARQL_RESULT(r);
-    r->waitForFinished(); // this test is synchronous only
-    CHECK_QSPARQL_RESULT(r);
-    QCOMPARE(r->boolValue(), false);
-    delete r;
-}
-
-void tst_QSparqlTrackerDirect::insert_and_delete_contact_async()
-{
-    // This test will leave unclean test data in tracker if it crashes.
-    QSparqlConnection conn("QTRACKER_DIRECT");
-    QSparqlQuery add("insert { <addeduri001> a nco:PersonContact; "
-                     "nie:isLogicalPartOf <qsparql-tracker-direct-tests> ;"
-                     "nco:nameGiven \"addedname001\" .}",
-                     QSparqlQuery::InsertStatement);
-
-    QSparqlResult* r = conn.exec(add);
-    CHECK_QSPARQL_RESULT(r);
-
-    QTime timer;
-    timer.start();
-    QSignalSpy insertSpy(r, SIGNAL(finished()));
-    while (insertSpy.count() == 0 && timer.elapsed() < 5000) {
-        QTest::qWait(100);
-    }
-    QCOMPARE(insertSpy.count(), 1);
-
-    CHECK_QSPARQL_RESULT(r);
-    delete r;
-
-    // Verify that the insertion succeeded
-    QSparqlQuery q("select ?u ?ng {?u a nco:PersonContact; "
-                   "nie:isLogicalPartOf <qsparql-tracker-direct-tests> ;"
-                   "nco:nameGiven ?ng .}");
-    QHash<QString, QString> contactNames;
-    r = conn.exec(q);
-    QVERIFY(r != 0);
-    r->waitForFinished();
-    QCOMPARE(r->size(), 4);
-    while (r->next()) {
-        contactNames[r->binding(0).value().toString()] =
-            r->binding(1).value().toString();
-    }
-    QCOMPARE(contactNames.size(), 4);
-    QCOMPARE(contactNames["addeduri001"], QString("addedname001"));
-    delete r;
-
-    // Delete the uri
-    QSparqlQuery del("delete { <addeduri001> a rdfs:Resource. }",
-                     QSparqlQuery::DeleteStatement);
-
-    r = conn.exec(del);
-    CHECK_QSPARQL_RESULT(r);
-
-    timer.restart();
-    QSignalSpy deleteSpy(r, SIGNAL(finished()));
-    while (deleteSpy.count() == 0 && timer.elapsed() < 5000) {
-        QTest::qWait(100);
-    }
-    QCOMPARE(deleteSpy.count(), 1);
-
-    CHECK_QSPARQL_RESULT(r);
-    delete r;
-
-    // Verify that it got deleted
-    contactNames.clear();
-    r = conn.exec(q);
-    CHECK_QSPARQL_RESULT(r);
-    r->waitForFinished();
-    CHECK_QSPARQL_RESULT(r);
-    QCOMPARE(r->size(), 3);
-    while (r->next()) {
-        contactNames[r->binding(0).value().toString()] =
-            r->binding(1).value().toString();
-    }
-    QCOMPARE(contactNames.size(), 3);
-    delete r;
-}
-
 void tst_QSparqlTrackerDirect::insert_new_urn()
 {
     // This test will leave unclean test data in tracker if it crashes.
@@ -429,7 +365,7 @@
     const int testDataAmount = 3000;
     const QString testCaseTag("<qsparql-tracker-direct-tests-delete_partially_iterated_result>");
     QScopedPointer<TestData> testData(
-            createTestData(testDataAmount, "<qsparql-tracker-direct-tests>", testCaseTag));
+            TestData::createTrackerTestData(testDataAmount, "<qsparql-tracker-direct-tests>", testCaseTag));
     QTest::qWait(1000);
     QVERIFY( testData->isOK() );
     QSparqlConnectionOptions opts;
@@ -753,7 +689,7 @@
 
 void tst_QSparqlTrackerDirect::delete_connection_immediately()
 {
-    // QSparqlConnection conn("QTRACKER_DIRECT");
+    QSparqlConnection conn("QTRACKER_DIRECT");
 }
 
 void tst_QSparqlTrackerDirect::delete_connection_before_a_wait()
@@ -764,27 +700,6 @@
     QTest::qWait(1000);
 }
 
-void tst_QSparqlTrackerDirect::go_beyond_columns_number()
-{
-    // This test will print out warnings
-    setMsgLogLevel(QtCriticalMsg);
-    QSparqlConnection conn("QTRACKER_DIRECT");
-    QSparqlQuery q("select ?u ?ng {?u a nco:PersonContact; "
-                   "nie:isLogicalPartOf <qsparql-tracker-direct-tests> ;"
-                   "nco:nameGiven ?ng .}");
-    QSparqlResult* r = conn.exec(q);
-    CHECK_QSPARQL_RESULT(r);
-    r->waitForFinished(); // this test is synchronous only
-    CHECK_QSPARQL_RESULT(r);
-    QCOMPARE(r->size(), 3);
-    while (r->next()) {
-        QCOMPARE(r->current().count(), 2);
-        QCOMPARE(r->value(5).toString(), QString());
-        QCOMPARE(r->binding(5).toString(), QString());
-    }
-    delete r;
-}
-
 void tst_QSparqlTrackerDirect::create_2_connections()
 {
     QSparqlConnection conn("QTRACKER_DIRECT");
@@ -1047,11 +962,14 @@
 class DeleteResultOnFinished : public QObject
 {
     Q_OBJECT
+    public:
+        DeleteResultOnFinished(QSparqlResult *result) : r(result) {}
+        QSparqlResult *r;
     public Q_SLOTS:
-    void onFinished()
-    {
-        sender()->deleteLater();
-    }
+        void onFinished()
+        {
+            r->deleteLater();
+        }
 };
 
 }
@@ -1067,11 +985,10 @@
     QSignalSpy destroyedSpy(r, SIGNAL(destroyed()));
 
     // When we get the finished() signal of the result, do deleteLater.
-    DeleteResultOnFinished resultDeleter;
+    DeleteResultOnFinished resultDeleter(r);
     connect(r, SIGNAL(finished()), &resultDeleter, SLOT(onFinished()));
 
     QSignalSpy finishedSpy(r, SIGNAL(finished()));
-
     // Spin the event loop so that the finished() signal arrives
     QTime timer;
     timer.start();
@@ -1101,7 +1018,7 @@
     QSignalSpy destroyedSpy(r, SIGNAL(destroyed()));
 
     // When we get the finished() signal of the result, do deleteLater.
-    DeleteResultOnFinished resultDeleter;
+    DeleteResultOnFinished resultDeleter(r);
     connect(r, SIGNAL(finished()), &resultDeleter, SLOT(onFinished()));
 
     QSignalSpy finishedSpy(r, SIGNAL(finished()));
@@ -1249,152 +1166,13 @@
             << 17 << 5 << 4;
 }
 
-void tst_QSparqlTrackerDirect::destroy_connection_before_result()
-{
-    // This test will print out warnings
-    setMsgLogLevel(QtCriticalMsg);
-
-    const QString connectionType("QTRACKER_DIRECT");
-    QFETCH(int, waitForConnectionOpen);
-    QSparqlConnection* conn = new QSparqlConnection(connectionType);
-    if (waitForConnectionOpen > 0)
-        QTest::qWait(waitForConnectionOpen);
-    QSparqlResult* r = 0;
-    const QSparqlQuery q("select ?u ?ng {?u a nco:PersonContact; "
-                         "nie:isLogicalPartOf <qsparql-tracker-direct-tests>; "
-                         "nco:nameGiven ?ng. }");
-
-    r = conn->exec(q);
-    QVERIFY( r );
-    QVERIFY( !r->hasError() );
-
-    // Take ownership of the result to prevent connection from deleting it
-    r->setParent(this);
-    // Delete the connection before the result
-    delete conn; conn = 0;
-
-    // Wait in event loop to let any asynchronous activity complete
-    QTest::qWait(500);
-
-    // Delete the result
-    delete r; r = 0;
-    // Wait in event loop to let any asynchronous activity complete
-    QTest::qWait(500);
-}
-
-void tst_QSparqlTrackerDirect::destroy_connection_before_result_data()
-{
-    QTest::addColumn<int>("waitForConnectionOpen");
-
-    QTest::newRow("Dbus connection") << 0;
-    QTest::newRow("Direct connection") << 0;
-    QTest::newRow("Direct connection") << 1000;
-}
-
-void tst_QSparqlTrackerDirect::destroy_connection_waitForFinished()
-{
-    setMsgLogLevel(QtCriticalMsg);
-    const QString connectionType("QTRACKER_DIRECT");
-    const QSparqlQuery q("select ?u ?ng {?u a nco:PersonContact; "
-                         "nie:isLogicalPartOf <qsparql-tracker-direct-tests> ;"
-                         "nco:nameGiven ?ng .}");
-    QSparqlConnection* conn = new QSparqlConnection(connectionType);
-    //wait for the connection to open
-    QTest::qWait(1000);
-
-    QSparqlResult* r = conn->exec(q);
-    r->setParent(this);
-    delete conn; conn = 0;
-    QTest::qWait(500);
-
-    r->waitForFinished();
-
-    CHECK_QSPARQL_RESULT(r);
-    delete r;
-}
-
-void tst_QSparqlTrackerDirect::destroy_connection_verify_result()
-{
-    setMsgLogLevel(QtCriticalMsg);
-    const QString connectionType("QTRACKER_DIRECT");
-    const QSparqlQuery q("select ?u ?ng {?u a nco:PersonContact; "
-                         "nie:isLogicalPartOf <qsparql-tracker-direct-tests> ;"
-                         "nco:nameGiven ?ng .}");
-    QSparqlConnection* conn = new QSparqlConnection(connectionType);
-    //wait for the connection to open
-    QTest::qWait(1000);
-
-    QSparqlResult* r = conn->exec(q);
-    r->setParent(this);
-    r->waitForFinished();
-    QVERIFY(r != 0);
-
-    delete conn; conn = 0;
-    QTest::qWait(500);
-
-    QVERIFY(checkResultSize(r, 3));
-    QHash<QString, QString> contactNames;
-    while (r->next()) {
-        QCOMPARE(r->current().count(), 2);
-        QCOMPARE(r->stringValue(0), r->value(0).toString());
-        QCOMPARE(r->stringValue(1), r->value(1).toString());
-
-        contactNames[r->value(0).toString()] = r->value(1).toString();
-    }
-    QVERIFY(r->isFinished());
-    QCOMPARE(contactNames.size(), 3);
-    QCOMPARE(contactNames["uri001"], QString("name001"));
-    QCOMPARE(contactNames["uri002"], QString("name002"));
-    QCOMPARE(contactNames["uri003"], QString("name003"));
-
-    CHECK_QSPARQL_RESULT(r);
-    delete r;
-}
-
-void tst_QSparqlTrackerDirect::destroy_connection_verify_result_async()
-{
-    setMsgLogLevel(QtCriticalMsg);
-    const QString connectionType("QTRACKER_DIRECT");
-    const QSparqlQuery q("select ?u ?ng {?u a nco:PersonContact; "
-                         "nie:isLogicalPartOf <qsparql-tracker-direct-tests> ;"
-                         "nco:nameGiven ?ng .}");
-    QSparqlConnection* conn = new QSparqlConnection(connectionType);
-    //wait for the connection to open
-    QTest::qWait(1000);
-
-    QSparqlResult* r = conn->exec(q);
-    CHECK_QSPARQL_RESULT(r);
-    r->setParent(this);
-
-    QTime timer;
-    timer.start();
-    QSignalSpy spy(r, SIGNAL(finished()));
-    while (spy.count() == 0 && timer.elapsed() < 5000) {
-        QTest::qWait(100);
-    }
-    QCOMPARE(spy.count(), 1);
-    CHECK_QSPARQL_RESULT(r);
-    delete conn; conn = 0;
-    QCOMPARE(r->size(), 3);
-    QHash<QString, QString> contactNames;
-    while (r->next()) {
-        QCOMPARE(r->current().count(), 2);
-        contactNames[r->value(0).toString()] = r->value(1).toString();
-    }
-    QCOMPARE(contactNames.size(), 3);
-    QCOMPARE(contactNames["uri001"], QString("name001"));
-    QCOMPARE(contactNames["uri002"], QString("name002"));
-    QCOMPARE(contactNames["uri003"], QString("name003"));
-    delete r;
-}
-
 void tst_QSparqlTrackerDirect::destroy_connection_partially_iterated_results()
 {
     setMsgLogLevel(QtCriticalMsg);
     const int testDataAmount = 3000;
     const QString testCaseTag("<qsparql-tracker-direct-tests-destroy_connection_partially_iterated_result>");
     QScopedPointer<TestData> testData(
-            createTestData(testDataAmount, "<qsparql-tracker-direct-tests>", testCaseTag));
+            TestData::createTrackerTestData(testDataAmount, "<qsparql-tracker-direct-tests>", testCaseTag));
     QTest::qWait(1000);
     QVERIFY( testData->isOK() );
     QSparqlConnectionOptions opts;
@@ -1424,84 +1202,12 @@
     }
 }
 
-void tst_QSparqlTrackerDirect::validate_threadpool_results()
-{
-    setMsgLogLevel(QtCriticalMsg);
-    const int testDataAmount = 3000;
-    const QString testTag("<qsparql-tracker-direct-tests-validate_threadpool_results>");
-    QScopedPointer<TestData> testData(createTestData(testDataAmount, "<qsparql-tracker-direct-tests>", testTag));
-    QTest::qWait(1000);
-    QVERIFY( testData->isOK() );
-
-    for (int maxThreadCount = 1; maxThreadCount <= 100; maxThreadCount *= 10) {
-        QSparqlConnectionOptions opts;
-        opts.setDataReadyInterval(1);
-        opts.setMaxThreadCount(maxThreadCount);
-        QSparqlConnection conn("QTRACKER_DIRECT", opts);
-
-        //now read this back, each result will then be validated to ensure its the correct one
-        QList<QSparqlResult*> resultList;
-        QList<QSignalSpy*> resultSpys;
-
-        const int numberOfResults = 50;
-        const int resultRange = testDataAmount/numberOfResults;
-        for(int i=1;i<=numberOfResults;i++)
-        {
-            int lower = i*resultRange-(resultRange-1);
-            int upper = i*resultRange;
-            QSparqlQuery select(QString("select ?u ?t {?u a nmm:MusicPiece;"
-                                    "nmm:trackNumber ?t;"
-                                    "nie:isLogicalPartOf <qsparql-tracker-direct-tests-validate_threadpool_results>"
-                                    "FILTER ( ?t >=%1 && ?t <=%2 ) }").arg(lower).arg(upper));
-
-            QSparqlResult *r = conn.exec(select);
-            CHECK_QSPARQL_RESULT(r);
-            QSignalSpy *resultSpy = new QSignalSpy(r, SIGNAL(finished()));
-            resultList.append(r);
-            resultSpys.append(resultSpy);
-        }
-
-        //check the signals
-        QTime timer;
-
-        foreach(QSignalSpy *resultSpy, resultSpys) {
-            bool timeout = false;
-            timer.restart();
-            while(resultSpy->count() == 0 && !timeout)
-            {
-                QTest::qWait(1);
-                if (timer.elapsed() > 8000)
-                    timeout = true;
-            }
-            QVERIFY(!timeout);
-            QCOMPARE(resultSpy->count(), 1);
-        }
-        qDeleteAll(resultSpys);
-
-        int i=1;
-        foreach(QSparqlResult *result, resultList) {
-            QCOMPARE(result->size(), resultRange);
-            const int start = i*resultRange-(resultRange-1);
-            while(result->next())
-            {
-                //the id we are matching will be sequential and unique
-                //in all results, so we can calculate what it will be
-                //using the result position plus the start offset
-                int expectedValue = result->pos()+start;
-                QCOMPARE(result->value(1).toInt(),expectedValue);
-            }
-            i++;
-        }
-        qDeleteAll(resultList);
-    }
-}
-
 void tst_QSparqlTrackerDirect::waitForFinished_after_dataReady()
 {
     setMsgLogLevel(QtCriticalMsg);
     const int testDataAmount = 3000;
     const QString testTag("<qsparql-tracker-direct-tests-waitForFinished_after_dataReady>");
-    QScopedPointer<TestData> testData(createTestData(testDataAmount, "<qsparql-tracker-direct-tests>", testTag));
+    QScopedPointer<TestData> testData(TestData::createTrackerTestData(testDataAmount, "<qsparql-tracker-direct-tests>", testTag));
     QTest::qWait(1000);
     QVERIFY( testData->isOK() );
     QSparqlConnectionOptions opts;
@@ -1533,6 +1239,164 @@
     QVERIFY(succesfulRounds >= 5);
 }
 
+void tst_QSparqlTrackerDirect::test_threadpool_priority_select_results()
+{
+    const int testDataAmount = 3000;
+    const QString testTag("<qsparql-tracker-direct-tests-test_threadpool_priority_select_results>");
+    QScopedPointer<TestData> testData(TestData::createTrackerTestData(testDataAmount, "<qsparql-tracker-direct-tests>", testTag));
+    QTest::qWait(2000);
+    QVERIFY( testData->isOK() );
+
+    // Use only one thread
+    QSparqlConnectionOptions options;
+    options.setMaxThreadCount(1);
+    QSparqlConnection conn("QTRACKER_DIRECT", options);
+    bool forwardOnly = false;
+    QSparqlQuery select(QString("select ?u {?u a nmm:MusicPiece;"
+                                "nie:isLogicalPartOf <qsparql-tracker-direct-tests-test_threadpool_priority_select_results> }"));
+
+    // Do this twice, one with normal results, once with forwardOnly results
+    for (int i=0;i<2;i++) {
+        if (i==1) {
+            forwardOnly = true;
+        }
+        FinishedSignalReceiver signalReceiver;
+
+        QSparqlQueryOptions result1_options;
+        QSparqlQueryOptions result2_options;
+        QSparqlQueryOptions result3_options;
+        // execute result 4 with normal priority by not setting anything
+        QSparqlQueryOptions result5_options;
+
+        result1_options.setPriority(QSparqlQueryOptions::NormalPriority);
+        result2_options.setPriority(QSparqlQueryOptions::LowPriority);
+        result2_options.setForwardOnly(forwardOnly);
+        result3_options.setPriority(QSparqlQueryOptions::NormalPriority);
+        result3_options.setForwardOnly(forwardOnly);
+        result5_options.setPriority(QSparqlQueryOptions::HighPriority);
+        result5_options.setForwardOnly(forwardOnly);
+
+        // first result, default priority
+        QSparqlResult *result1 =
+            conn.exec(select, result1_options);
+        signalReceiver.append(result1);
+        // this result should be processed last
+        QSparqlResult *result2 =
+            conn.exec(select,result2_options);
+        signalReceiver.append(result2);
+        // this result should be processed after the first one
+        // unless some high priority result comes along
+        QSparqlResult *result3 =
+            conn.exec(select, result3_options);
+        signalReceiver.append(result3);
+        // default is normal priority, so this should be processed after
+        // result 3
+        QSparqlResult *result4 =
+            conn.exec(select);
+        signalReceiver.append(result4);
+        // insert a high priority result, should be bumped to the front
+        // of the queue to be processed before 3, 4 and 2
+        QSparqlResult *result5 =
+            conn.exec(select, result5_options);
+        signalReceiver.append(result5);
+
+        // wait for them all to finish
+        QVERIFY(signalReceiver.waitForAllFinished(8000));
+
+        // order should be result1, result5, result3, result4, result2
+        // however if result1 hasn't started before result5 it will
+        // be result5, result1, result3, result4, result2 so check this
+        // as a special case
+        bool firstOrder = false;
+        QList<QSparqlResult*> resultOrder = signalReceiver.resultOrder;
+        if (resultOrder.at(0) == result1 || resultOrder.at(0) == result5) {
+            firstOrder = true;
+        }
+        QVERIFY(firstOrder);
+        QVERIFY(resultOrder.at(2) == result3);
+        QVERIFY(resultOrder.at(3) == result4);
+        QVERIFY(resultOrder.at(4) == result2);
+
+        // finally just validate they all got the correct number of results
+        foreach(QSparqlResult *result, resultOrder) {
+            int resultSize = 0;
+            if (forwardOnly) {
+                while (result->next())
+                    resultSize++;
+            } else {
+                resultSize = result->size();
+            }
+            QCOMPARE(resultSize, 3000);
+        }
+    }
+}
+
+void tst_QSparqlTrackerDirect::test_threadpool_priority_update_results()
+{
+    QSparqlConnectionOptions options;
+    options.setMaxThreadCount(1);
+    QSparqlConnection conn("QTRACKER_DIRECT", options);
+    FinishedSignalReceiver signalReceiver;
+
+    QString insertString = "insert { <newInsert-%1> a nco:PersonContact; nco:nameGiven 'name-%1' .}";
+    QString selectString = "select <newInsert-%1> ?ng { <newInsert-%1> a nco:PersonContact; nco:nameGiven ?ng }";
+    QString deleteString = "delete { <newInsert-%1> a nco:PersonContact }";
+    QSparqlQueryOptions result1_options;
+    QSparqlQueryOptions result2_options;
+    QSparqlQueryOptions result3_options;
+    QSparqlQueryOptions result4_options;
+    QSparqlQueryOptions result5_options;
+    QSparqlQueryOptions result6_options;
+
+    result1_options.setPriority(QSparqlQueryOptions::NormalPriority);
+    result2_options.setPriority(QSparqlQueryOptions::LowPriority);
+    result3_options.setPriority(QSparqlQueryOptions::LowPriority);
+    result4_options.setPriority(QSparqlQueryOptions::NormalPriority);
+    result5_options.setPriority(QSparqlQueryOptions::NormalPriority);
+    result6_options.setPriority(QSparqlQueryOptions::HighPriority);
+
+    //result1, insert contact 1 - normal priority
+    //result2, delete contact 2 - low priority
+    //result3, delete contact 1 - low priority
+    //result4, select contact 1 - normal priority
+    //result5, select contact 2 - normal priority
+    //result6, insert contact 2 - high priority
+    QSparqlResult *result1 =
+        conn.exec(QSparqlQuery(insertString.arg(1),QSparqlQuery::InsertStatement),result1_options);
+    signalReceiver.append(result1);
+    QSparqlResult *result2 =
+        conn.exec(QSparqlQuery(deleteString.arg(1),QSparqlQuery::DeleteStatement),result2_options);
+    signalReceiver.append(result2);
+    QSparqlResult *result3 =
+        conn.exec(QSparqlQuery(deleteString.arg(2),QSparqlQuery::DeleteStatement),result3_options);
+    signalReceiver.append(result3);
+    QSparqlResult *result4 =
+        conn.exec(QSparqlQuery(selectString.arg(1)),result4_options);
+    signalReceiver.append(result4);
+    QSparqlResult *result5 =
+        conn.exec(QSparqlQuery(selectString.arg(2)),result5_options);
+    signalReceiver.append(result5);
+    QSparqlResult *result6 =
+        conn.exec(QSparqlQuery(insertString.arg(2),QSparqlQuery::InsertStatement),result6_options);
+    signalReceiver.append(result6);
+
+    signalReceiver.waitForAllFinished(8000);
+    // contact 1 was selected with result 4, contact 2 with result 5, check these are correct
+    result4->next();
+    QCOMPARE(result4->value(0).toString(), QString("newInsert-1"));
+    QCOMPARE(result4->value(1).toString(), QString("name-1"));
+    result5->next();
+    QCOMPARE(result5->value(0).toString(), QString("newInsert-2"));
+    QCOMPARE(result5->value(1).toString(), QString("name-2"));
+
+    // Check the inserts got deleted
+    QSparqlResult *validateResult1 = conn.exec(QSparqlQuery(selectString.arg(1)));
+    validateResult1->waitForFinished();
+    QSparqlResult *validateResult2 = conn.exec(QSparqlQuery(selectString.arg(2)));
+    validateResult2->waitForFinished();
+    QCOMPARE(validateResult1->size(), 0);
+    QCOMPARE(validateResult2->size(), 0);
+}
 
 QTEST_MAIN( tst_QSparqlTrackerDirect )
 #include "tst_qsparql_tracker_direct.moc"
--- tests/auto/qsparql_tracker_direct_concurrency
+++ tests/auto/qsparql_tracker_direct_concurrency
+(directory)
--- tests/auto/qsparql_tracker_direct_concurrency/qsparql_tracker_direct_concurrency.pro
+++ tests/auto/qsparql_tracker_direct_concurrency/qsparql_tracker_direct_concurrency.pro
+include(../sparqltest.pri)
+CONFIG += qt warn_on console depend_includepath
+QT += testlib
+HEADERS += ../utils/testdata.h querytester.h updatetester.h resultchecker.h
+SOURCES  += tst_qsparql_tracker_direct_concurrency.cpp \
+            querytester.cpp updatetester.cpp resultchecker.cpp \
+        ../utils/testdata.cpp
+
+check.depends = $$TARGET
+check.commands = ./tst_qsparql_tracker_direct_concurrency
+
+memcheck.depends = $$TARGET
+memcheck.commands = $$VALGRIND $$VALGRIND_OPT ./tst_qsparql_tracker_direct_concurrency
+
+QMAKE_EXTRA_TARGETS += check memcheck
+
+#QT = sparql # enable this later
--- tests/auto/qsparql_tracker_direct_concurrency/querytester.cpp
+++ tests/auto/qsparql_tracker_direct_concurrency/querytester.cpp
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (ivan.frade at nokia.com)
+**
+** This file is part of the test suite of the QtSparql module (not yet part of the Qt Toolkit).
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at ivan.frade at nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "querytester.h"
+#include <QtTest/QtTest>
+#include <QtSparql/QtSparql>
+#include "resultchecker.h"
+
+namespace {
+
+QPair<int,int> randomRangeIn(int max)
+{
+    const int low = qrand() % (max-1) + 1;
+    const int high = qrand() % ((max+1) - low) + low;
+    return qMakePair(low, high);
+}
+
+void seedRandomRangeGenerator()
+{
+    static bool seeded = false;
+    if (!seeded) {
+        QTime time = QTime::currentTime();
+        qsrand((uint)time.msec());
+        seeded = true;
+    }
+}
+
+}  // namespace
+
+QueryTester::QueryTester()
+    : connection(0), ownConnection(0), resultChecker(0)
+{
+    seedRandomRangeGenerator();
+}
+
+QueryTester::~QueryTester()
+{
+    cleanup();
+}
+
+void QueryTester::cleanup()
+{
+    delete resultChecker;
+    resultChecker = 0;
+    delete ownConnection;
+    ownConnection = 0;
+}
+
+void QueryTester::setParameters(int numQueries, int testDataSize, bool forwardOnly)
+{
+    this->numQueries = numQueries;
+    this->testDataSize = testDataSize;
+    this->forwardOnly = forwardOnly;
+}
+
+void QueryTester::setConnection(QSparqlConnection* connection)
+{
+    this->connection = connection;
+    delete ownConnection;
+    ownConnection = 0;
+}
+
+bool QueryTester::waitForAllFinished(int silenceTimeoutMs)
+{
+    return resultChecker->waitForAllFinished(silenceTimeoutMs);
+}
+
+void QueryTester::startQueries()
+{
+    initResources();
+    for (int i=0;i<numQueries;i++) {
+        QPair<int, int> resultRange;
+        QString filter;
+        if (i % 10 == 0) {
+            // Override every 10th result to read all
+            resultRange = qMakePair(1, testDataSize);
+            filter = ". }";
+        }
+        else {
+            resultRange  = randomRangeIn(testDataSize);
+            filter = QString("FILTER ( ?t >=%1 && ?t <=%2 ) }").arg(resultRange.first).arg(resultRange.second);
+        }
+        QSparqlQuery select(QString("select ?u ?t {?u a nmm:MusicPiece; "
+                                    "nmm:trackNumber ?t; "
+                                    "nie:isLogicalPartOf <qsparql-tracker-direct-tests-concurrency-stress> "
+                                    + filter));
+        QSparqlQueryOptions queryOptions;
+        queryOptions.setForwardOnly(forwardOnly);
+        QSparqlResult *result = connection->exec(select, queryOptions);
+        resultChecker->append(result, resultRange);
+    }
+}
+
+void QueryTester::startInThread(QThread* thread)
+{
+    this->moveToThread(thread);
+    connect(thread, SIGNAL(started()), this, SLOT(runInThread()));
+}
+
+void QueryTester::runInThread()
+{
+    initResources();
+    connect(resultChecker, SIGNAL(allFinished()), this, SLOT(quit()));
+    startQueries();
+}
+
+void QueryTester::quit()
+{
+    cleanup();
+    this->thread()->quit();
+}
+
+void QueryTester::initResources()
+{
+    if (!connection) {
+        const int dataReadyInterval = qMax(testDataSize/100, 10);
+        QSparqlConnectionOptions options;
+        options.setDataReadyInterval(dataReadyInterval);
+        ownConnection = new QSparqlConnection("QTRACKER_DIRECT", options);
+        connection = ownConnection;
+    }
+    if (!resultChecker) {
+        resultChecker = new ResultChecker;
+    }
+}
--- tests/auto/qsparql_tracker_direct_concurrency/querytester.h
+++ tests/auto/qsparql_tracker_direct_concurrency/querytester.h
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (ivan.frade at nokia.com)
+**
+** This file is part of the test suite of the QtSparql module (not yet part of the Qt Toolkit).
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at ivan.frade at nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QUERYTESTER_H
+#define QUERYTESTER_H
+
+#include <QtCore/qobject.h>
+
+class QSparqlConnection;
+class ResultChecker;
+
+class QueryTester : public QObject
+{
+    Q_OBJECT
+
+    QSparqlConnection *connection;
+    QSparqlConnection *ownConnection;
+    ResultChecker *resultChecker;
+
+    int numQueries;
+    int testDataSize;
+    bool forwardOnly;
+
+public:
+    QueryTester();
+    ~QueryTester();
+
+    void cleanup();
+    void setParameters(int numQueries, int testDataSize, bool forwardOnly);
+    void setConnection(QSparqlConnection* connection);
+    bool waitForAllFinished(int silenceTimeoutMs);
+
+public Q_SLOTS:
+    void startQueries();
+    void startInThread(QThread* thread);
+    void runInThread();
+
+private Q_SLOTS:
+    void quit();
+
+private:
+    void initResources();
+};
+
+#endif // QUERYTESTER_H
--- tests/auto/qsparql_tracker_direct_concurrency/resultchecker.cpp
+++ tests/auto/qsparql_tracker_direct_concurrency/resultchecker.cpp
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (ivan.frade at nokia.com)
+**
+** This file is part of the test suite of the QtSparql module (not yet part of the Qt Toolkit).
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at ivan.frade at nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "resultchecker.h"
+#include <QtTest/QtTest>
+#include <QtSparql/QtSparql>
+
+ResultChecker::ResultChecker()
+    : dataReadyMapper(0), finishedMapper(0)
+{
+}
+
+ResultChecker::~ResultChecker()
+{
+    pendingResults.clear();
+    qDeleteAll(allResults);
+}
+
+void ResultChecker::append(QSparqlResult *r, const QPair<int, int>& range)
+{
+    QVERIFY( r );
+    QVERIFY( !r->hasError() );
+    initResources();
+    dataReadyMapper->setMapping(r, r);
+    connect(r, SIGNAL(dataReady(int)), dataReadyMapper, SLOT(map()));
+    finishedMapper->setMapping(r, r);
+    connect(r, SIGNAL(finished()), finishedMapper, SLOT(map()));
+    allResults.append(r);
+    pendingResults.insert(r, range);
+}
+
+bool ResultChecker::waitForAllFinished(int silenceTimeoutMs)
+{
+    QTime timeoutTimer;
+    timeoutTimer.start();
+    bool timeout = false;
+    while (!pendingResults.empty() && !timeout) {
+        const int pendingResultsCountBefore = pendingResults.count();
+        QTest::qWait(silenceTimeoutMs / 10);
+        if (pendingResults.count() < pendingResultsCountBefore) {
+            timeoutTimer.restart();
+        }
+        else if (timeoutTimer.elapsed() > silenceTimeoutMs) {
+            timeout = true;
+        }
+    }
+    return !timeout;
+}
+
+void ResultChecker::onDataReady(QObject* mappedResult)
+{
+    QSparqlResult *result = qobject_cast<QSparqlResult*>(mappedResult);
+    while (result->next()) {
+        // just do something pointless with the result
+        result->value(1).toInt();
+        result->value(0).toString();
+    }
+}
+
+void ResultChecker::onFinished(QObject* mappedResult)
+{
+    QSparqlResult *result = qobject_cast<QSparqlResult*>(mappedResult);
+    QVERIFY( result );
+    QVERIFY( !result->hasError() );
+    QVERIFY( pendingResults.contains(result) );
+
+    const QPair<int, int> resultRange = pendingResults.value(result);
+    const int expectedResultSize = (resultRange.second - resultRange.first) + 1;
+    int resultSize = result->size();
+    if (result->hasFeature(QSparqlResult::ForwardOnly)) {
+        resultSize = 0;
+        while (result->next()) {
+            resultSize++;
+            // Also verify the results here
+            QVERIFY(result->value(1).toInt() >= resultRange.first);
+            QVERIFY(result->value(1).toInt() <= resultRange.second);
+        }
+    }
+    QCOMPARE(resultSize, expectedResultSize);
+
+    // the results should have been fully nexted in the data ready function
+    QCOMPARE(result->pos(), int(QSparql::AfterLastRow));
+
+    if (!result->hasFeature(QSparqlResult::ForwardOnly)) {
+        // go back through the results and validate that they are in range
+        int resultCount = 0;
+        while (result->previous()) {
+            //we don't know the order, so just ensure the result is within range
+            QVERIFY(result->value(1).toInt() >= resultRange.first);
+            QVERIFY(result->value(1).toInt() <= resultRange.second);
+            resultCount++;
+        }
+        // now make sure the results counted match the size
+        QCOMPARE(resultCount, expectedResultSize);
+    }
+
+    pendingResults.remove(result);
+    if (pendingResults.empty())
+        Q_EMIT allFinished();
+}
+
+void ResultChecker::initResources()
+{
+    if (!dataReadyMapper) {
+        dataReadyMapper = new QSignalMapper(this);
+        connect(dataReadyMapper, SIGNAL(mapped(QObject*)), this, SLOT(onDataReady(QObject*)));
+    }
+    if (!finishedMapper) {
+        finishedMapper = new QSignalMapper(this);
+        connect(finishedMapper, SIGNAL(mapped(QObject*)), this, SLOT(onFinished(QObject*)));
+    }
+}
--- tests/auto/qsparql_tracker_direct_concurrency/resultchecker.h
+++ tests/auto/qsparql_tracker_direct_concurrency/resultchecker.h
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (ivan.frade at nokia.com)
+**
+** This file is part of the test suite of the QtSparql module (not yet part of the Qt Toolkit).
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at ivan.frade at nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef RESULTCHECKER_H
+#define RESULTCHECKER_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qpair.h>
+
+class QSignalMapper;
+class QSparqlResult;
+
+class ResultChecker : public QObject
+{
+    Q_OBJECT
+    QSignalMapper* dataReadyMapper;
+    QSignalMapper* finishedMapper;
+    QList<QSparqlResult*> allResults;
+    QHash<QSparqlResult*, QPair<int,int> > pendingResults;
+
+public:
+    ResultChecker();
+    ~ResultChecker();
+    void append(QSparqlResult *r, const QPair<int, int>& range);
+    bool waitForAllFinished(int silenceTimeoutMs);
+
+Q_SIGNALS:
+    void allFinished();
+
+private Q_SLOTS:
+    void onDataReady(QObject* mappedResult);
+    void onFinished(QObject* mappedResult);
+
+private:
+    void initResources();
+};
+
+
+#endif // RESULTCHECKER_H
--- tests/auto/qsparql_tracker_direct_concurrency/tst_qsparql_tracker_direct_concurrency.cpp
+++ tests/auto/qsparql_tracker_direct_concurrency/tst_qsparql_tracker_direct_concurrency.cpp
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (ivan.frade at nokia.com)
+**
+** This file is part of the test suite of the QtSparql module (not yet part of the Qt Toolkit).
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at ivan.frade at nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "../testhelpers.h"
+#include "querytester.h"
+#include "updatetester.h"
+#include "resultchecker.h"
+#include "../utils/testdata.h"
+
+#include <QtTest/QtTest>
+#include <QtSparql/QtSparql>
+
+#define TEST_DATA_AMOUNT 3000
+
+class tst_QSparqlTrackerDirectConcurrency : public QObject
+{
+    Q_OBJECT
+public:
+    tst_QSparqlTrackerDirectConcurrency();
+    virtual ~tst_QSparqlTrackerDirectConcurrency();
+
+private:
+    TestData *testData;
+    void createTrackerTestData();
+
+private Q_SLOTS:
+    void initTestCase();
+    void cleanupTestCase();
+    void init();
+    void cleanup();
+
+    void sameConnection_selectQueries();
+    void sameConnection_selectQueries_data();
+    void sameConnection_updateQueries();
+    void sameConnection_updateQueries_data();
+
+    void multipleConnections_selectQueries();
+    void multipleConnections_selectQueries_data();
+    void multipleConnections_updateQueries();
+    void multipleConnections_updateQueries_data();
+
+    void multipleConnections_multipleThreads_selectQueries();
+    void multipleConnections_multipleThreads_selectQueries_data();
+    void multipleConnections_multipleThreads_updateQueries();
+    void multipleConnections_multipleThreads_updateQueries_data();
+};
+
+namespace {
+
+void waitForAllFinished(const QList<QThread*>& threads, int timeoutMs)
+{
+    Q_FOREACH(QThread* thread, threads) {
+        QVERIFY( thread->wait(timeoutMs) );
+    }
+}
+
+} //end namespace
+
+tst_QSparqlTrackerDirectConcurrency::tst_QSparqlTrackerDirectConcurrency()
+{
+}
+
+tst_QSparqlTrackerDirectConcurrency::~tst_QSparqlTrackerDirectConcurrency()
+{
+}
+
+void tst_QSparqlTrackerDirectConcurrency::initTestCase()
+{
+    // For running the test without installing the plugins. Should work in
+    // normal and vpath builds.
+    QCoreApplication::addLibraryPath("../../../plugins");
+    testData = 0;
+
+    // delete any previous pieces of test data that may have been left
+    // over if the test was killed prematurely
+    QSparqlConnection conn("QTRACKER_DIRECT");
+    QString deleteString = "delete { ?u a rdfs:Resource } WHERE { ?u nie:isLogicalPartOf <qsparql-tracker-direct-tests-concurrency-stress> }";
+    QSparqlResult *result = conn.syncExec(QSparqlQuery(deleteString, QSparqlQuery::DeleteStatement));
+    QVERIFY(!result->hasError());
+    delete result;
+}
+
+void tst_QSparqlTrackerDirectConcurrency::cleanupTestCase()
+{
+    if (testData) {
+        delete testData;
+        testData = 0;
+    }
+}
+
+void tst_QSparqlTrackerDirectConcurrency::createTrackerTestData()
+{
+    if (!testData) {
+        const QString testTag("<qsparql-tracker-direct-tests-concurrency-stress>");
+        testData = TestData::createTrackerTestData(TEST_DATA_AMOUNT, "<qsparql-tracker-direct-tests>", testTag);
+        QTest::qWait(2000);
+        QVERIFY( testData->isOK() );
+    }
+}
+
+void tst_QSparqlTrackerDirectConcurrency::init()
+{
+}
+
+void tst_QSparqlTrackerDirectConcurrency::cleanup()
+{
+}
+
+void tst_QSparqlTrackerDirectConcurrency::sameConnection_selectQueries()
+{
+    QFETCH(int, testDataAmount);
+    QFETCH(int, numQueries);
+    QFETCH(int, maxThreadCount);
+    QFETCH(bool, forwardOnly);
+    const int dataReadyInterval = qMax(testDataAmount/100, 10);
+
+    QSparqlConnectionOptions options;
+    options.setDataReadyInterval(dataReadyInterval);
+    if (maxThreadCount > 0)
+        options.setMaxThreadCount(maxThreadCount);
+    QSparqlConnection conn("QTRACKER_DIRECT", options);
+
+    QueryTester queryTester;
+    queryTester.setConnection(&conn);
+    queryTester.setParameters(numQueries, testDataAmount, forwardOnly);
+
+    queryTester.startQueries();
+    QVERIFY(queryTester.waitForAllFinished(8000));
+}
+
+void tst_QSparqlTrackerDirectConcurrency::sameConnection_selectQueries_data()
+{
+    createTrackerTestData();
+    QTest::addColumn<int>("testDataAmount");
+    QTest::addColumn<int>("numQueries");
+    QTest::addColumn<int>("maxThreadCount");
+    QTest::addColumn<bool>("forwardOnly");
+
+    QTest::newRow("10 queries, 1 Thread") <<
+        TEST_DATA_AMOUNT << 10 << 1 << false;
+    QTest::newRow("10 queries, 1 Thread, forward only") <<
+        TEST_DATA_AMOUNT << 10 << 1 << true;
+    QTest::newRow("100 queries, 1 Thread") <<
+        TEST_DATA_AMOUNT << 100 << 1 << false;
+    QTest::newRow("100 queries, 1 Thread, forward only") <<
+        TEST_DATA_AMOUNT << 100 << 1 << true;
+    QTest::newRow("10 queries, default number of threads") <<
+        TEST_DATA_AMOUNT << 10 << 0 << false;
+    QTest::newRow("10 queries, default number of threads, forward only") <<
+        TEST_DATA_AMOUNT << 10 << 0 << true;
+    QTest::newRow("100 queries, default number of threads") <<
+        TEST_DATA_AMOUNT << 100 << 0 << false;
+    QTest::newRow("100 queries, default number of threads, forward only") <<
+        TEST_DATA_AMOUNT << 100 << 0 << true;
+    QTest::newRow("10 queries, 4 Threads") <<
+        TEST_DATA_AMOUNT << 10 << 4 << false;
+    QTest::newRow("10 queries, 4 Threads, forward only") <<
+        TEST_DATA_AMOUNT << 10 << 4 << true;
+    QTest::newRow("100 queries, 4 Threads") <<
+        TEST_DATA_AMOUNT << 100 << 4 << false;
+    QTest::newRow("100 queries, 4 Threads, forward only") <<
+        TEST_DATA_AMOUNT << 100 << 4 << true;
+}
+
+void tst_QSparqlTrackerDirectConcurrency::sameConnection_updateQueries()
+{
+    QFETCH(int, numInserts);
+    QFETCH(int, numDeletes);
+    QSparqlConnection connection("QTRACKER_DIRECT");
+
+    UpdateTester updateTester(1);
+    updateTester.setParameters(numInserts, numDeletes);
+    updateTester.setConnection(&connection);
+    updateTester.run();
+}
+
+void tst_QSparqlTrackerDirectConcurrency::sameConnection_updateQueries_data()
+{
+    QTest::addColumn<int>("numInserts");
+    QTest::addColumn<int>("numDeletes");
+
+    QTest::newRow("10 inserts, 10 deletes") <<
+        10 << 10;
+    QTest::newRow("100 inserts, 100 deletes") <<
+        100 << 100;
+    QTest::newRow("250 inserts, 250 deletes") <<
+        250 << 250;
+}
+
+void tst_QSparqlTrackerDirectConcurrency::multipleConnections_selectQueries()
+{
+    QFETCH(int, testDataAmount);
+    QFETCH(int, numQueries);
+    QFETCH(int, numConnections);
+    QFETCH(bool, forwardOnly);
+    QList<QueryTester*> queryTesters;
+
+    // Create the connections and start the queries
+    for (int i = 0; i < numConnections; ++i) {
+        QueryTester* queryTester = new QueryTester;
+        queryTester->setParameters(numQueries, testDataAmount, forwardOnly);
+        queryTesters << queryTester;
+        queryTester->startQueries();
+    }
+
+    // Wait for all the queries to finish
+    Q_FOREACH(QueryTester* queryTester, queryTesters) {
+        QVERIFY(queryTester->waitForAllFinished(60000));
+    }
+
+    qDeleteAll(queryTesters);
+}
+
+void tst_QSparqlTrackerDirectConcurrency::multipleConnections_selectQueries_data()
+{
+    createTrackerTestData();
+    QTest::addColumn<int>("testDataAmount");
+    QTest::addColumn<int>("numQueries");
+    QTest::addColumn<int>("numConnections");
+    QTest::addColumn<bool>("forwardOnly");
+
+    QTest::newRow("10 queries, 2 connections") <<
+        TEST_DATA_AMOUNT << 10 << 2 << false;
+    QTest::newRow("10 queries, 2 connections, forward only") <<
+        TEST_DATA_AMOUNT << 10 << 2 << true;
+    QTest::newRow("100 queries, 2 connections") <<
+        TEST_DATA_AMOUNT << 100 << 2 << false;
+    QTest::newRow("100 queries, 2 connections, forward only") <<
+        TEST_DATA_AMOUNT << 100 << 2 << true;
+    QTest::newRow("10 queries, 4 connections") <<
+        TEST_DATA_AMOUNT << 10 << 4 << false;
+    QTest::newRow("10 queries, 4 connections, forward only") <<
+        TEST_DATA_AMOUNT << 10 << 4 << true;
+    QTest::newRow("100 queries, 4 connections") <<
+        TEST_DATA_AMOUNT << 100 << 4 << false;
+    QTest::newRow("100 queries, 4 connections, forward only") <<
+        TEST_DATA_AMOUNT << 100 << 4 << true;
+}
+
+void tst_QSparqlTrackerDirectConcurrency::multipleConnections_updateQueries()
+{
+    QFETCH(int, numInserts);
+    QFETCH(int, numDeletes);
+    QFETCH(int, numConnections);
+
+    QList<QSparqlConnection*> connections;
+    QList<UpdateTester*> updateTesters;
+
+    for (int i = 0; i < numConnections; ++i) {
+        QSparqlConnection* conn = new QSparqlConnection("QTRACKER_DIRECT");
+        connections << conn;
+
+        UpdateTester* updateTester = new UpdateTester(i);
+        updateTester->setConnection(conn);
+        updateTester->setParameters(numInserts, numDeletes);
+        updateTesters << updateTester;
+        updateTester->start();
+    }
+    Q_FOREACH(UpdateTester* updateTester, updateTesters) {
+        updateTester->waitForFinished();
+        updateTester->cleanup();
+    }
+
+    qDeleteAll(updateTesters);
+    qDeleteAll(connections);
+}
+
+void tst_QSparqlTrackerDirectConcurrency::multipleConnections_updateQueries_data()
+{
+    QTest::addColumn<int>("numInserts");
+    QTest::addColumn<int>("numDeletes");
+    QTest::addColumn<int>("numConnections");
+
+    QTest::newRow("10 inserts, 10 deletes, 2 connections") <<
+        10 << 10 << 2;
+    QTest::newRow("100 inserts, 100 deletes, 2 connections") <<
+        100 << 100 << 2;
+    QTest::newRow("250 inserts, 250 deletes, 2 connections") <<
+        250 << 250 << 2;
+    QTest::newRow("10 inserts, 10 deletes, 4 connections") <<
+        10 << 10 << 4;
+    QTest::newRow("100 inserts, 100 deletes, 4 connections") <<
+        100 << 100 << 4;
+    QTest::newRow("250 inserts, 250 deletes, 4 connections") <<
+        250 << 250 << 4;
+
+}
+
+void tst_QSparqlTrackerDirectConcurrency::multipleConnections_multipleThreads_selectQueries()
+{
+    QFETCH(int, testDataAmount);
+    QFETCH(int, numQueries);
+    QFETCH(int, numThreads);
+    QFETCH(bool, forwardOnly);
+
+    QList<QThread*> createdThreads;
+    QList<QueryTester*> queryTesters;
+    for (int i=0;i<numThreads;i++) {
+        QThread *newThread = new QThread;
+        createdThreads.append(newThread);
+
+        QueryTester *queryTester = new QueryTester;
+        queryTester->setParameters(numQueries, testDataAmount, forwardOnly);
+        queryTesters.append(queryTester);
+        queryTester->startInThread(newThread);
+    }
+    // start all the threads
+    Q_FOREACH(QThread* thread, createdThreads) {
+        thread->start();
+    }
+
+    waitForAllFinished(createdThreads, 60000*numThreads);
+    qDeleteAll(queryTesters);
+    qDeleteAll(createdThreads);
+}
+
+void tst_QSparqlTrackerDirectConcurrency::multipleConnections_multipleThreads_selectQueries_data()
+{
+    createTrackerTestData();
+    QTest::addColumn<int>("testDataAmount");
+    QTest::addColumn<int>("numQueries");
+    QTest::addColumn<int>("numThreads");
+    QTest::addColumn<bool>("forwardOnly");
+
+    QTest::newRow("10 queries, 2 Threads") <<
+        TEST_DATA_AMOUNT << 10 << 2 << false;
+    QTest::newRow("10 queries, 2 Threads, forward only") <<
+        TEST_DATA_AMOUNT << 10 << 2 << true;
+    QTest::newRow("100 queries, 2 Threads") <<
+        TEST_DATA_AMOUNT << 100 << 2 << false;
+    QTest::newRow("100 queries, 2 Threads, forward only") <<
+        TEST_DATA_AMOUNT << 100 << 2 << true;
+    QTest::newRow("10 queries, 4 Threads") <<
+        TEST_DATA_AMOUNT << 10 << 4 << false;
+    QTest::newRow("10 queries, 4 Threads, forward only") <<
+        TEST_DATA_AMOUNT << 10 << 4 << true;
+    QTest::newRow("100 queries, 4 Threads") <<
+        TEST_DATA_AMOUNT << 100 << 4 << false;
+    QTest::newRow("100 queries, 4 Threads, forward only") <<
+        TEST_DATA_AMOUNT << 100 << 4 << true;
+}
+
+void tst_QSparqlTrackerDirectConcurrency::multipleConnections_multipleThreads_updateQueries()
+{
+    QFETCH(int, numThreads);
+    QFETCH(int, numInserts);
+    QFETCH(int, numDeletes);
+
+    QList<QThread*> createdThreads;
+    QList<UpdateTester*> updateTesters;
+    for (int i=0;i<numThreads;i++) {
+        QThread* newThread = new QThread;
+        createdThreads.append(newThread);
+
+        UpdateTester* updateTester = new UpdateTester(i);
+        updateTester->setParameters(numInserts, numDeletes);
+        updateTesters.append(updateTester);
+        updateTester->startInThread(newThread);
+    }
+    // start all the threads
+    Q_FOREACH(QThread* thread, createdThreads) {
+        thread->start();
+    }
+
+    waitForAllFinished(createdThreads, 60000*numThreads);
+    qDeleteAll(updateTesters);
+    qDeleteAll(createdThreads);
+}
+
+void tst_QSparqlTrackerDirectConcurrency::multipleConnections_multipleThreads_updateQueries_data()
+{
+    QTest::addColumn<int>("numThreads");
+    QTest::addColumn<int>("numInserts");
+    QTest::addColumn<int>("numDeletes");
+
+    QTest::newRow("1 Thread, 10 inserts, 10 deletes") <<
+        1 << 10 << 10;
+    QTest::newRow("2 Threads, 100 inserts, 100 deletes") <<
+        2 << 100 << 100;
+    QTest::newRow("2 Threads, 250 inserts, 250 deletes") <<
+        2 << 250 << 250;
+    QTest::newRow("4 Threads, 100 inserts, 100 deletes") <<
+        4 << 100 << 100;
+    QTest::newRow("4 Threads, 250 inserts, 250 deletes") <<
+        4 << 250 << 250;
+}
+
+QTEST_MAIN( tst_QSparqlTrackerDirectConcurrency )
+#include "tst_qsparql_tracker_direct_concurrency.moc"
--- tests/auto/qsparql_tracker_direct_concurrency/updatetester.cpp
+++ tests/auto/qsparql_tracker_direct_concurrency/updatetester.cpp
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (ivan.frade at nokia.com)
+**
+** This file is part of the test suite of the QtSparql module (not yet part of the Qt Toolkit).
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at ivan.frade at nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "updatetester.h"
+#include <QtTest/QtTest>
+#include <QtSparql/QtSparql>
+
+UpdateTester::UpdateTester(int id)
+    : connection(0), ownConnection(0)
+    , updateFinishedMapper(0)
+    , deleteFinishedMapper(0)
+    , id(id), isFinished(false)
+    , validateUpdateResultAttempts(0)
+    , validateDeleteResultAttempts(0)
+{
+}
+
+void UpdateTester::setParameters(int numInserts, int numDeletes)
+{
+    QVERIFY(numDeletes <= numInserts);
+    this->numInserts = numInserts;
+    this->numDeletes = numDeletes;
+}
+
+void UpdateTester::setConnection(QSparqlConnection *connection)
+{
+    this->connection = connection;
+    delete ownConnection;
+    ownConnection = 0;
+}
+
+void UpdateTester::waitForFinished()
+{
+    while (!isFinished)
+    {
+        QTest::qWait(100);
+    }
+}
+
+void UpdateTester::startInThread(QThread* thread)
+{
+    this->moveToThread(thread);
+    connect(thread, SIGNAL(started()), this, SLOT(runInThread()));
+}
+
+void UpdateTester::start()
+{
+    connect(this, SIGNAL(updatesComplete()), this, SLOT(startValidateUpdate()));
+    connect(this, SIGNAL(validateUpdateComplete()), this, SLOT(startDeletions()));
+    connect(this, SIGNAL(deletionsComplete()), this, SLOT(startValidateDeletion()));
+    connect(this, SIGNAL(validateDeletionComplete()), this, SLOT(finish()));
+    initResources();
+    startUpdates();
+}
+
+void UpdateTester::run()
+{
+    start();
+    waitForFinished();
+    cleanup();
+}
+
+void UpdateTester::runInThread()
+{
+    run();
+    this->thread()->quit();
+}
+
+void UpdateTester::cleanup()
+{
+    if (connection && numInserts-numDeletes > 0) {
+        QString deleteTemplate = "DELETE { ?u a nco:PersonContact }"
+                              " WHERE { ?u a nco:PersonContact; nie:isLogicalPartOf <qsparql-tracker-direct-concurrency-thread%1> . }";
+        QSparqlQuery deleteQuery(deleteTemplate.arg(id), QSparqlQuery::DeleteStatement);
+        QSparqlResult* result = connection->syncExec(deleteQuery);
+        delete result;
+    }
+
+    qDeleteAll(resultList);
+    resultList.clear();
+
+    if (ownConnection) {
+        delete ownConnection;
+        ownConnection = connection = 0;
+    }
+}
+
+void UpdateTester::initResources()
+{
+    if (!connection) {
+        ownConnection = new QSparqlConnection("QTRACKER_DIRECT");
+        connection = ownConnection;
+    }
+    if (!updateFinishedMapper) {
+        updateFinishedMapper = new QSignalMapper(this);
+        connect(updateFinishedMapper, SIGNAL(mapped(QObject*)), this, SLOT(onUpdateFinished(QObject*)));
+    }
+    if (!deleteFinishedMapper) {
+        deleteFinishedMapper = new QSignalMapper(this);
+        connect(deleteFinishedMapper, SIGNAL(mapped(QObject*)), this, SLOT(onDeleteFinished(QObject*)));
+    }
+}
+
+void UpdateTester::startUpdates()
+{
+    validateUpdateResultAttempts = 0;
+    const QString insertTemplate = "insert { <addeduri00%1-%2> a nco:PersonContact; nie:isLogicalPartOf <qsparql-tracker-direct-concurrency-thread%2>;"
+                                    "nie:isLogicalPartOf <qsparql-tracker-direct-tests-concurrency-stress>;"
+                                    "nco:nameGiven \"addedname00%1\"; nco:nameFamily \"addedFamily00%1\" . }";
+    for (int i=0;i<numInserts;i++) {
+        QSparqlQuery insertQuery(insertTemplate.arg(i).arg(id), QSparqlQuery::InsertStatement);
+        QSparqlResult *result = connection->exec(insertQuery);
+        QVERIFY( result );
+        QVERIFY( !result->hasError() );
+        appendPendingResult(result, updateFinishedMapper);
+    }
+}
+
+void UpdateTester::startValidateUpdate()
+{
+    QSparqlResult* result = connection->exec(QSparqlQuery(selectTemplate().arg(id)));
+    connect(result, SIGNAL(finished()), this, SLOT(validateUpdateResult()));
+    QVERIFY( result );
+    QVERIFY( !result->hasError() );
+    resultList.append(result);
+}
+
+void UpdateTester::validateUpdateResult()
+{
+    bool retry = false;
+    doValidateUpdateResult(&retry);
+    if (retry) {
+        QMetaObject::invokeMethod(this, "startValidateUpdate", Qt::QueuedConnection);
+    }
+    else {
+        Q_EMIT validateUpdateComplete();
+    }
+}
+
+void UpdateTester::startDeletions()
+{
+    validateDeleteResultAttempts = 0;
+    const QString deleteTemplate = "delete { <addeduri00%1-%2> a nco:PersonContact }"
+                                   " WHERE { <addeduri00%1-%2> a nco:PersonContact; nie:isLogicalPartOf <qsparql-tracker-direct-concurrency-thread%2> . }";
+    for (int i=0;i<numDeletes;i++) {
+        QSparqlQuery deleteQuery(deleteTemplate.arg(i).arg(id), QSparqlQuery::DeleteStatement);
+        QSparqlResult* result = connection->exec(deleteQuery);
+        QVERIFY( result );
+        QVERIFY( !result->hasError() );
+        appendPendingResult(result, deleteFinishedMapper);
+    }
+}
+
+void UpdateTester::startValidateDeletion()
+{
+    QSparqlResult* result = connection->exec(QSparqlQuery(selectTemplate().arg(id)));
+    QVERIFY( result );
+    QVERIFY( !result->hasError() );
+    connect(result, SIGNAL(finished()), this, SLOT(validateDeleteResult()));
+    resultList.append(result);
+}
+
+void UpdateTester::validateDeleteResult()
+{
+    bool retry = false;
+    doValidateDeleteResult(&retry);
+    if (retry) {
+        QMetaObject::invokeMethod(this, "startValidateDeletion", Qt::QueuedConnection);
+    }
+    else {
+        Q_EMIT validateDeletionComplete();
+    }
+}
+
+void UpdateTester::onUpdateFinished(QObject* mappedResult)
+{
+    checkIsPendingResult(mappedResult);
+    if (removePendingResultWasLast(mappedResult))
+        Q_EMIT updatesComplete();
+}
+
+void UpdateTester::onDeleteFinished(QObject* mappedResult)
+{
+    checkIsPendingResult(mappedResult);
+    if (removePendingResultWasLast(mappedResult))
+        Q_EMIT deletionsComplete();
+}
+
+void UpdateTester::finish()
+{
+    isFinished = true;
+    if (validateUpdateResultAttempts > 1) {
+        qDebug() << "Update result validation attempts" << validateUpdateResultAttempts;
+    }
+    if (validateDeleteResultAttempts > 1) {
+        qDebug() << "Delete result validation attempts" << validateDeleteResultAttempts;
+    }
+
+    Q_EMIT finished();
+}
+
+QString UpdateTester::selectTemplate()
+{
+    return QString("select ?u ?ng ?nf { ?u a nco:PersonContact; nie:isLogicalPartOf <qsparql-tracker-direct-concurrency-thread%1>;"
+                        "nco:nameGiven ?ng; nco:nameFamily ?nf . }");
+}
+
+void UpdateTester::appendPendingResult(QSparqlResult* result, QSignalMapper* signalMapper)
+{
+    QVERIFY( !pendingResults.contains(result) );
+    resultList.append(result);
+    pendingResults.insert(result);
+    signalMapper->setMapping(result,result);
+    connect(result, SIGNAL(finished()), signalMapper, SLOT(map()));
+}
+
+void UpdateTester::checkIsPendingResult(QObject* mappedResult) const
+{
+    QSparqlResult* result = qobject_cast<QSparqlResult*>(mappedResult);
+    QVERIFY( result );
+    QVERIFY( pendingResults.contains(result) );
+}
+
+bool UpdateTester::removePendingResultWasLast(QObject* mappedResult)
+{
+    QSparqlResult* result = qobject_cast<QSparqlResult*>(mappedResult);
+    pendingResults.remove(result);
+    return pendingResults.isEmpty();
+}
+
+void UpdateTester::doValidateUpdateResult(bool* retry)
+{
+    QVERIFY( ++validateUpdateResultAttempts < 10 );
+
+    QSparqlResult* result = resultList.back();
+    QVERIFY( !result->hasError() );
+
+    // Verify that we get most numInserts results
+    // The result size may temporarily be smaller with tracker direct access
+    // due to its transaction management
+    QVERIFY( result->size() <= numInserts );
+
+    QHash<QString, QString> contactNameValues;
+    while (result->next()) {
+        contactNameValues[result->value(0).toString()] = result->value(1).toString();
+    }
+    // Verify that all resource uris were unique
+    QVERIFY( contactNameValues.count() == result->size() );
+
+    // Verify that all succesfully inserted data was present in the result
+    int missingInsertsCount = 0;
+    for(int i=0; i<numInserts; i++) {
+        const QString resourceUri = QString("addeduri00%1-%2").arg(i).arg(id);
+        if (contactNameValues.contains(resourceUri)) {
+            QCOMPARE(contactNameValues[resourceUri], QString("addedname00%1").arg(i));
+        }
+        else {
+            ++missingInsertsCount;
+        }
+    }
+    QCOMPARE( numInserts - result->size(), missingInsertsCount );
+
+    *retry = (missingInsertsCount > 0);
+}
+
+void UpdateTester::doValidateDeleteResult(bool* retry)
+{
+    QVERIFY( ++validateDeleteResultAttempts < 10 );
+
+    QSparqlResult* result = resultList.back();
+    QVERIFY( !result->hasError() );
+    if (result->size() == numInserts-numDeletes) {
+        QHash<QString, QString> contactNameValues;
+        while (result->next()) {
+            contactNameValues[result->value(0).toString()] = result->value(1).toString();
+        }
+        QCOMPARE(contactNameValues.size(), numInserts-numDeletes);
+        // number of deletes might be less than the number of inserts, we delete from 0 -> numDeletes-1, so
+        int startFrom = numInserts - numDeletes;
+        if (startFrom != 0) {
+            for (int i=startFrom;i<numInserts;i++) {
+                QCOMPARE(contactNameValues[QString("addeduri00%1-%2").arg(i).arg(id)], QString("addedname00%1").arg(i));
+            }
+        }
+    }
+    else {
+        *retry = true;
+    }
+}
--- tests/auto/qsparql_tracker_direct_concurrency/updatetester.h
+++ tests/auto/qsparql_tracker_direct_concurrency/updatetester.h
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (ivan.frade at nokia.com)
+**
+** This file is part of the test suite of the QtSparql module (not yet part of the Qt Toolkit).
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at ivan.frade at nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef UPDATETESTER_H
+#define UPDATETESTER_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qset.h>
+
+class QSignalMapper;
+class QSparqlConnection;
+class QSparqlResult;
+
+class UpdateTester : public QObject
+{
+    Q_OBJECT
+    QSparqlConnection *connection;
+    QSparqlConnection *ownConnection;
+    QList<QSparqlResult*> resultList;
+    QSet<QSparqlResult*> pendingResults;
+    QSignalMapper* updateFinishedMapper;
+    QSignalMapper* deleteFinishedMapper;
+    int numInserts;
+    int numDeletes;
+    int id;
+    bool isFinished;
+    int validateUpdateResultAttempts;
+    int validateDeleteResultAttempts;
+
+public:
+    UpdateTester(int id);
+    void setParameters(int numInserts, int numDeletes);
+    void setConnection(QSparqlConnection *connection);
+    void waitForFinished();
+    void startInThread(QThread* thread);
+
+Q_SIGNALS:
+    void updatesComplete();
+    void validateUpdateComplete();
+    void deletionsComplete();
+    void validateDeletionComplete();
+    void finished();
+
+public Q_SLOTS:
+    void start();
+    void run();
+    void runInThread();
+    void cleanup();
+
+private Q_SLOTS:
+    void initResources();
+    void startUpdates();
+    void startValidateUpdate();
+    void validateUpdateResult();
+    void startDeletions();
+    void startValidateDeletion();
+    void validateDeleteResult();
+    void onUpdateFinished(QObject* mappedResult);
+    void onDeleteFinished(QObject* mappedResult);
+    void finish();
+
+private:
+    static QString selectTemplate();
+    void appendPendingResult(QSparqlResult* result, QSignalMapper* signalMapper);
+    void checkIsPendingResult(QObject* mappedResult) const;
+    bool removePendingResultWasLast(QObject* mappedResult);
+    void doValidateUpdateResult(bool* retry);
+    void doValidateDeleteResult(bool* retry);
+};
+
+#endif // UPDATETESTER_H
--- tests/auto/qsparql_tracker_direct_crashes/qsparql_tracker_direct_crashes.pro
+++ tests/auto/qsparql_tracker_direct_crashes/qsparql_tracker_direct_crashes.pro
@@ -1,13 +1,18 @@
 include(../sparqltest.pri)
-CONFIG += qt warn_on console depend_includepath testcase
+CONFIG += qt warn_on console depend_includepath
 QT += testlib
 SOURCES  += tst_qsparql_tracker_direct_crashes.cpp
 
-memcheck.depends = $$TARGET
-memcheck.commands = $$VALGRIND $$VALGRIND_OPT ./tst_qsparql_tracker_crashes
+TEST_ENV = XDG_CACHE_HOME=bogus TRACKER_SPARQL_BACKEND=direct
+TEST_EXE = ./tst_qsparql_tracker_direct_crashes
+
+check.depends = $$TARGET
+check.commands = $$TEST_ENV $$TEST_EXE
 
-QMAKE_EXTRA_TARGETS += memcheck
+memcheck.depends = $$TARGET
+#memcheck.commands = $$TEST_ENV $$VALGRIND $$VALGRIND_OPT $$TEST_EXE
+memcheck.commands = @echo $$TARGET: memcheck is disabled for until leak in tracker is fixed
 
-# this test is not ran when doing "make check", but it's inluded in the test package
+QMAKE_EXTRA_TARGETS += check memcheck
 
 #QT = sparql # enable this later
--- tests/auto/qsparql_tracker_direct_crashes/tst_qsparql_tracker_direct_crashes.cpp
+++ tests/auto/qsparql_tracker_direct_crashes/tst_qsparql_tracker_direct_crashes.cpp
@@ -40,10 +40,6 @@
 #include <QtTest/QtTest>
 #include <QtSparql/QtSparql>
 
-//const QString qtest(qTableName( "qtest", __FILE__ )); // FIXME: what's this
-
-//TESTED_FILES=
-
 class tst_QSparqlTrackerDirectCrashes : public QObject
 {
     Q_OBJECT
@@ -145,7 +141,6 @@
 
 void tst_QSparqlTrackerDirectCrashes::two_failing_connections()
 {
-    QSKIP("Waiting for a tracker bugfix", SkipAll);
     // This is a regression test. Run this in a setup where the
     // libtracker-sparql connection opening fails to reproduce the problem.
     {
--- tests/auto/qsparql_tracker_direct_sync/qsparql_tracker_direct_sync.pro
+++ tests/auto/qsparql_tracker_direct_sync/qsparql_tracker_direct_sync.pro
@@ -8,7 +8,7 @@
 check.commands = ./tst_qsparql_tracker_direct_sync
 
 memcheck.depends = $$TARGET
-memcheck.commands = $$VALGRIND $$VALGRIND_OPT ./tst_qsparql_tracker_sync
+memcheck.commands = $$VALGRIND $$VALGRIND_OPT ./tst_qsparql_tracker_direct_sync
 
 QMAKE_EXTRA_TARGETS += check memcheck
 
--- tests/auto/qsparql_tracker_direct_sync/tst_qsparql_tracker_direct_sync.cpp
+++ tests/auto/qsparql_tracker_direct_sync/tst_qsparql_tracker_direct_sync.cpp
@@ -43,10 +43,6 @@
 #include <QtTest/QtTest>
 #include <QtSparql/QtSparql>
 
-//const QString qtest(qTableName( "qtest", __FILE__ )); // FIXME: what's this
-
-//TESTED_FILES=
-
 class tst_QSparqlTrackerDirectSync : public TrackerDirectCommon
 {
     Q_OBJECT
--- tests/auto/qsparql_virtuoso/tst_qsparql_virtuoso.cpp
+++ tests/auto/qsparql_virtuoso/tst_qsparql_virtuoso.cpp
@@ -40,10 +40,6 @@
 #include <QtTest/QtTest>
 #include <QtSparql/QtSparql>
 
-//const QString qtest(qTableName( "qtest", __FILE__ )); // FIXME: what's this
-
-//TESTED_FILES=
-
 #define TEST_PORT 1234
 // #define TEST_PORT 1111
 
--- tests/auto/qsparql_virtuoso_endpoint/tst_qsparql_virtuoso_endpoint.cpp
+++ tests/auto/qsparql_virtuoso_endpoint/tst_qsparql_virtuoso_endpoint.cpp
@@ -40,10 +40,6 @@
 #include <QtTest/QtTest>
 #include <QtSparql/QtSparql>
 
-//const QString qtest(qTableName( "qtest", __FILE__ )); // FIXME: what's this
-
-//TESTED_FILES=
-
 class tst_QSparqlVirtuosoEndpoint : public QObject
 {
     Q_OBJECT
--- tests/auto/qsparqlbinding/qsparqlbinding.pro
+++ tests/auto/qsparqlbinding/qsparqlbinding.pro
@@ -7,7 +7,10 @@
 check.depends = $$TARGET
 check.commands = ./tst_qsparqlbinding
 
-QMAKE_EXTRA_TARGETS += check
+memcheck.depends = $$TARGET
+memcheck.commands = $$VALGRIND $$VALGRIND_OPT ./tst_qsparqlbinding
+
+QMAKE_EXTRA_TARGETS += check memcheck
 
 #QT = sparql # enable this later
 
--- tests/auto/qsparqlbinding/tst_qsparqlbinding.cpp
+++ tests/auto/qsparqlbinding/tst_qsparqlbinding.cpp
@@ -46,10 +46,6 @@
 
 #include <QUrl>
 
-//const QString qtest(qTableName( "qtest", __FILE__ )); // FIXME: what's this
-
-//TESTED_FILES=
-
 class tst_QSparqlBinding : public QObject
 {
     Q_OBJECT
--- tests/auto/qsparqlquery/qsparqlquery.pro
+++ tests/auto/qsparqlquery/qsparqlquery.pro
@@ -7,7 +7,10 @@
 check.depends = $$TARGET
 check.commands = ./tst_qsparqlquery
 
-QMAKE_EXTRA_TARGETS += check
+memcheck.depends = $$TARGET
+memcheck.commands = $$VALGRIND $$VALGRIND_OPT ./tst_qsparqlquery
+
+QMAKE_EXTRA_TARGETS += check memcheck
 
 #QT = sparql # enable this later
 
--- tests/auto/qsparqlquery/tst_qsparqlquery.cpp
+++ tests/auto/qsparqlquery/tst_qsparqlquery.cpp
@@ -42,10 +42,6 @@
 
 #include <QUrl>
 
-//const QString qtest(qTableName( "qtest", __FILE__ )); // FIXME: what's this
-
-//TESTED_FILES=
-
 class tst_QSparqlQuery : public QObject
 {
     Q_OBJECT
@@ -67,6 +63,7 @@
     void unbind_and_replace();
     void different_datatypes_data();
     void different_datatypes();
+    void copy();
 };
 
 tst_QSparqlQuery::tst_QSparqlQuery()
@@ -250,5 +247,46 @@
     QCOMPARE(q.preparedQueryText(), replacedString);
 }
 
+void tst_QSparqlQuery::copy()
+{
+    const QString query1("insert { _:c a nco:Contact ; "
+                   "nco:fullname \"NAME\" ; "
+                   "nco:hasPhoneNumber _:pn . "
+                   "_:pn a nco:PhoneNumber ; "
+                   "nco:phoneNumber \"PHONE\" . }");
+    const QString query2("select ?r { ?r a nie:InformationElement ; "
+                   "nie:isLogicalPartOf <qsparql-query-tests> .}");
+    
+    const QSparqlQuery::StatementType type1(QSparqlQuery::InsertStatement);
+    const QSparqlQuery::StatementType type2(QSparqlQuery::SelectStatement);
+    const QSparqlQuery q1(query1, type1);
+
+    // Copy construct q2 from q1
+    QSparqlQuery q2(q1);
+    QCOMPARE(q2.query(), query1);
+    QCOMPARE(q2.type(), type1);
+
+    q2.setType(type2);
+    QCOMPARE(q2.type(), type2);
+    QCOMPARE(q1.type(), type1);
+
+    q2.setQuery(query2);
+    QCOMPARE(q2.query(), query2);
+    QCOMPARE(q1.query(), query1);
+
+    // Assign q1 to q2
+    q2 = q1;
+    QCOMPARE(q2.query(), query1);
+    QCOMPARE(q2.type(), type1);
+
+    q2.setType(type2);
+    QCOMPARE(q2.type(), type2);
+    QCOMPARE(q1.type(), type1);
+
+    q2.setQuery(query2);
+    QCOMPARE(q2.query(), query2);
+    QCOMPARE(q1.query(), query1);
+}
+
 QTEST_MAIN( tst_QSparqlQuery )
 #include "tst_qsparqlquery.moc"
--- tests/auto/qsparqlresultrow/qsparqlresultrow.pro
+++ tests/auto/qsparqlresultrow/qsparqlresultrow.pro
@@ -7,6 +7,9 @@
 check.depends = $$TARGET
 check.commands = ./tst_qsparqlresultrow
 
-QMAKE_EXTRA_TARGETS += check
+memcheck.depends = $$TARGET
+memcheck.commands = $$VALGRIND $$VALGRIND_OPT ./tst_qsparqlresultrow
+
+QMAKE_EXTRA_TARGETS += check memcheck
 
 #QT = sparql # enable this later
--- tests/auto/qsparqlresultrow/tst_qsparqlresultrow.cpp
+++ tests/auto/qsparqlresultrow/tst_qsparqlresultrow.cpp
@@ -47,10 +47,6 @@
 
 #include <QUrl>
 
-//const QString qtest(qTableName( "qtest", __FILE__ )); // FIXME: what's this
-
-//TESTED_FILES=
-
 class tst_QSparqlResultRow : public QObject
 {
     Q_OBJECT
--- tests/auto/tests.xml
+++ tests/auto/tests.xml
@@ -3,22 +3,22 @@
   <suite name="libqtsparql-tests">
     <set name="qsparlq-unit" description="Unit tests of libqtsparql">
       <case name="qsparqlquery" description="qsparqlquery unit tests">
-        <step expected_result="0">
+        <step>
 	  /usr/lib/libqtsparql-tests/tst_qsparqlquery
         </step>
       </case>
       <case name="qsparqlbinding" description="qsparqlbinding unit tests">
-        <step expected_result="0">
+        <step>
       /usr/lib/libqtsparql-tests/tst_qsparqlbinding
         </step>
       </case>
       <case name="qsparqlresultrow" description="qsparqlresultrow unit tests">
-        <step expected_result="0">
+        <step>
       /usr/lib/libqtsparql-tests/tst_qsparqlresultrow
         </step>
       </case>
       <case name="qsparql" description="qsparql unit tests">
-        <step expected_result="0">
+        <step>
 	  /usr/lib/libqtsparql-tests/tst_qsparql
         </step>
       </case>
@@ -27,9 +27,20 @@
         <hardware>true</hardware>
       </environments>
     </set>
+    <set name="qsparql-api" description="Tests for qsparql API">
+      <case name="tst_qsparql_api" description="Executing tst_qsparql_api">
+        <step>
+            su - user -c "/usr/lib/libqtsparql-tests/tst_qsparql_api"
+        </step>
+      </case>
+      <environments>
+        <scratchbox>true</scratchbox>
+        <hardware>true</hardware>
+      </environments>
+    </set>
     <set name="qsparql-tracker" description="Tests for tracker plugin of qsparql">
       <case name="tst_qsparql_tracker" description="Executing tst_qsparql_tracker">
-        <step expected_result="0">
+        <step>
             su - user -c "/usr/lib/libqtsparql-tests/tst_qsparql_tracker"
         </step>
       </case>
@@ -43,7 +54,7 @@
     </set>
     <set name="qsparql-tracker-direct" description="Tests for tracker direct access plugin of qsparql">
       <case name="tst_qsparql_tracker_direct" description="Executing tst_qsparql_tracker_direct" timeout="900">
-        <step expected_result="0">
+        <step>
             su - user -c "/usr/lib/libqtsparql-tests/tst_qsparql_tracker_direct"
         </step>
       </case>
@@ -57,27 +68,10 @@
     </set>
     <set name="qsparql-threading" description="Multithreading tests">
         <case name="test-tracker-queries" description="Tracker queries">
-            <step expected_result="0">
+            <step>
                 su - user -c "/usr/lib/libqtsparql-tests/tst_qsparql_threading concurrentTrackerQueries"
             </step>
         </case>
-        <case name="test-tracker-direct-queries" description="Tracker direct queries">
-            <step expected_result="0">
-                su - user -c "/usr/lib/libqtsparql-tests/tst_qsparql_threading concurrentTrackerDirectQueries"
-            </step>
-        </case>
-        <case name="test-tracker-direct-inserts" description="Tracker direct inserts" insignificant="true">
-            <!-- this is marked as insigficant since it fails sporadically; this needs debugging! -->
-            <step expected_result="0">
-                su - user -c "/usr/lib/libqtsparql-tests/tst_qsparql_threading concurrentTrackerDirectInserts ||
-                ( i=$? && tracker-sparql -u -f /usr/share/libqtsparql-tests/clean_data_threading.rq && exit $i )"
-            </step>
-        </case>
-        <post_steps>
-            <step expected_result="0">
-                su - user -c "tracker-sparql -u -f /usr/share/libqtsparql-tests/clean_data_threading.rq"
-            </step>
-        </post_steps>
         <environments>
             <scratchbox>true</scratchbox>
             <hardware>true</hardware>
@@ -88,7 +82,7 @@
     </set>
     <set name="qsparql-tracker-direct-sync" description="Tests for tracker direct access plugin of qsparql, sync mode">
         <case name="tst_qsparql_tracker_direct_sync" description="Executing tst_qsparql_tracker_direct_sync">
-            <step expected_result="0">
+            <step>
                 su - user -c "/usr/lib/libqtsparql-tests/tst_qsparql_tracker_direct_sync"
             </step>
         </case>
@@ -101,24 +95,23 @@
         </get>
     </set>
     <set name="qsparql-tracker-direct-crashes" description="Regression tests">
-      <case name="test-waitforfinished-crashes" description="Regression test">
-        <step expected_result="0">
-            <!-- Note: the env vars (and running this as root) should ensure that the direct connection opening fails -->
-            XDG_CACHE_HOME=bogus TRACKER_SPARQL_BACKEND=direct /usr/lib/libqtsparql-tests/tst_qsparql_tracker_direct_crashes waitForFinished_crashes_when_connection_opening_fails
-        </step>
-      </case>
-      <case name="test-syncexec-crashes" description="Regression test">
-        <step expected_result="0">
-            <!-- Note: the env vars (and running this as root) should ensure that the direct connection opening fails -->
-            XDG_CACHE_HOME=bogus TRACKER_SPARQL_BACKEND=direct /usr/lib/libqtsparql-tests/tst_qsparql_tracker_direct_crashes syncExec_crashes_when_connection_opening_fails
-        </step>
-      </case>
-      <case name="test-syncexec-update-crashes" description="Regression test">
-        <step expected_result="0">
-            <!-- Note: the env vars (and running this as root) should ensure that the direct connection opening fails -->
-            XDG_CACHE_HOME=bogus TRACKER_SPARQL_BACKEND=direct /usr/lib/libqtsparql-tests/tst_qsparql_tracker_direct_crashes syncExec_update_crashes_when_connection_opening_fails
+      <case name="tst_qsparql_tracker_direct_crashes" description="Regression test">
+        <step>
+            <!-- Note: the env vars should ensure that the direct connection opening fails -->
+            su - user -c "XDG_CACHE_HOME=bogus TRACKER_SPARQL_BACKEND=direct /usr/lib/libqtsparql-tests/tst_qsparql_tracker_direct_crashes"
+        </step>
+      </case>
+    </set>
+    <set name="qsparql-qmlbindings" description="Tests for qsparql QML bindings">
+      <case name="tst_qsparql_qmlbindings" description="Executing tst_qsparql_qmlbindings">
+        <step>
+            su - user -c "/usr/lib/libqtsparql-tests/tst_qsparql_qmlbindings"
         </step>
       </case>
+      <environments>
+        <scratchbox>true</scratchbox>
+        <hardware>true</hardware>
+      </environments>
     </set>
   </suite>
 </testdefinition>
--- tests/auto/tracker_direct_common.cpp
+++ tests/auto/tracker_direct_common.cpp
@@ -809,135 +809,3 @@
     delete r;
 }
 
-class TestDataImpl : public TestData {
-
-public:
-    TestDataImpl(const QSparqlQuery& cleanupQuery, const QSparqlQuery& selectQuery);
-    ~TestDataImpl();
-    void setOK();
-    bool isOK() const;
-    QSparqlQuery selectQuery() const;
-private:
-    QSparqlQuery cleanupQuery;
-    QSparqlQuery selectQuery_;
-    bool ok;
-};
-
-TestData* createTestData(int testDataAmount, const QString& testSuiteTag, const QString& testCaseTag)
-{
-    const int insertBatchSize = 200;
-    QSparqlConnection conn("QTRACKER_DIRECT");
-    const QString insertQueryTemplate =
-            "<urn:music:%1> a nmm:MusicPiece, nfo:FileDataObject, nfo:Audio;"
-                "nie:isLogicalPartOf %3 ;"
-                "nie:isLogicalPartOf %4 ;"
-                "tracker:available          true ;"
-                "nie:byteSize               \"0\" ;"
-                "nie:url                    \"file://music/Song_%1.mp3\" ;"
-                "nfo:belongsToContainer     <file://music/> ;"
-                "nie:title                  \"Song %1\" ;"
-                "nie:mimeType               \"audio/mpeg\" ;"
-                "nie:contentCreated         \"2000-01-01T01:01:01Z\" ;"
-                "nie:isLogicalPartOf        <urn:album:%2> ;"
-                "nco:contributor            <urn:artist:%2> ;"
-                "nfo:fileLastAccessed       \"2000-01-01T01:01:01Z\" ;"
-                "nfo:fileSize               \"0\" ;"
-                "nfo:fileName               \"Song_%1.mp3\" ;"
-                "nfo:fileLastModified       \"2000-01-01T01:01:01Z\" ;"
-                "nfo:codec                  \"MPEG\" ;"
-                "nfo:averageBitrate         \"16\" ;"
-                "nfo:genre                  \"Genre %2\" ;"
-                "nfo:channels               \"2\" ;"
-                "nfo:sampleRate             \"44100.0\" ;"
-                "nmm:musicAlbum             <urn:album:%2> ;"
-                "nmm:musicAlbumDisc         <urn:album-disk:%2> ;"
-                "nmm:performer              <urn:artist:%2> ;"
-                "nfo:duration               \"1\" ;"
-                "nmm:trackNumber            \"%1\" .";
-
-    const QSparqlQuery cleanupQuery(
-        QString("delete { "
-            "?u a rdfs:Resource . } "
-            "where { "
-            "?u nie:isLogicalPartOf %1 . "
-            "?u nie:isLogicalPartOf %2 . "
-            "} "
-            "delete {"
-            "%2 a rdfs:Resource . "
-            "}").arg(testSuiteTag).arg(testCaseTag),
-        QSparqlQuery::DeleteStatement);
-
-    const QSparqlQuery selectQuery(
-        QString("select tracker:id(?musicPiece) ?title ?performer ?album ?duration ?created "
-            "{ "
-            "?musicPiece a nmm:MusicPiece; "
-            "nie:isLogicalPartOf %1; "
-            "nie:isLogicalPartOf %2; "
-            "nie:title ?title; "
-            "nmm:performer ?performer; "
-            "nmm:musicAlbum ?album; "
-            "nfo:duration ?duration; "
-            "nie:contentCreated ?created. "
-            "} order by ?title ?created")
-                .arg(testSuiteTag)
-                .arg(testCaseTag));
-
-    TestDataImpl* testData = new TestDataImpl(cleanupQuery, selectQuery);
-
-    QString insertTagsQuery = QString("insert { %1 a nie:InformationElement. "
-                                               "%2 a nie:InformationElement. "
-                                               "%2 nie:isLogicalPartOf %1. }")
-                                        .arg(testSuiteTag).arg(testCaseTag);
-    QScopedPointer<QSparqlResult> r(conn.syncExec(QSparqlQuery(insertTagsQuery, QSparqlQuery::InsertStatement)));
-    if (r.isNull() || r->hasError())
-        return testData;
-    r.reset();
-
-    for (int item = 1; item <= testDataAmount; ) {
-        QString insertQuery = "insert { ";
-        int itemDozen = 10;
-        const int batchEnd = item + insertBatchSize;
-        for (; item < batchEnd && item <= testDataAmount; ++item) {
-            insertQuery.append( insertQueryTemplate
-                                    .arg(item)
-                                    .arg(itemDozen)
-                                    .arg(testSuiteTag)
-                                    .arg(testCaseTag) );
-            if (item % 10 == 0) itemDozen += 10;
-        }
-        insertQuery.append(" }");
-        QScopedPointer<QSparqlResult> r(conn.syncExec(QSparqlQuery(insertQuery, QSparqlQuery::InsertStatement)));
-        if (r.isNull() || r->hasError())
-            return testData;
-    }
-
-    testData->setOK();
-    return testData;
-}
-
-TestDataImpl::TestDataImpl(const QSparqlQuery& cleanupQuery, const QSparqlQuery& selectQuery)
-    : cleanupQuery(cleanupQuery), selectQuery_(selectQuery), ok(false)
-{
-}
-
-TestDataImpl::~TestDataImpl()
-{
-    QSparqlConnection conn("QTRACKER_DIRECT");
-    conn.syncExec(cleanupQuery);
-}
-
-void TestDataImpl::setOK()
-{
-    ok = true;
-}
-
-bool TestDataImpl::isOK() const
-{
-    return ok;
-}
-
-QSparqlQuery TestDataImpl::selectQuery() const
-{
-    return selectQuery_;
-}
-
--- tests/auto/tracker_direct_common.h
+++ tests/auto/tracker_direct_common.h
@@ -87,14 +87,4 @@
         QtMsgHandler origMsgHandler;
 };
 
-class TestData : public QObject {
-    Q_OBJECT
-public:
-    virtual ~TestData() { }
-    virtual bool isOK() const =0;
-    virtual QSparqlQuery selectQuery() const = 0;
-};
-
-TestData* createTestData(int testDataAmount, const QString& testSuiteTag, const QString& testCaseTag);
-
 #endif // QSPARQL_TRACKER_COMMON_H
--- tests/auto/utils
+++ tests/auto/utils
+(directory)
--- tests/auto/utils/testdata.cpp
+++ tests/auto/utils/testdata.cpp
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (ivan.frade at nokia.com)
+**
+** This file is part of the test suite of the QtSparql module (not yet part of the Qt Toolkit).
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at ivan.frade at nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testdata.h"
+#include <QtSparql/QtSparql>
+
+namespace {
+
+class TestDataImpl : public TestData {
+
+public:
+    TestDataImpl(const QSparqlQuery& cleanupQuery, const QSparqlQuery& selectQuery);
+    ~TestDataImpl();
+    void setOK();
+    bool isOK() const;
+    QSparqlQuery selectQuery() const;
+private:
+    QSparqlQuery cleanupQuery;
+    QSparqlQuery selectQuery_;
+    bool ok;
+};
+
+}  // namespace
+
+TestData* TestData::createTrackerTestData(int testDataAmount, const QString& testSuiteTag, const QString& testCaseTag)
+{
+    const int insertBatchSize = 200;
+    QSparqlConnection conn("QTRACKER_DIRECT");
+    const QString insertQueryTemplate =
+            "<urn:music:%1> a nmm:MusicPiece, nfo:FileDataObject, nfo:Audio;"
+                "nie:isLogicalPartOf %3 ;"
+                "nie:isLogicalPartOf %4 ;"
+                "tracker:available          true ;"
+                "nie:byteSize               \"0\" ;"
+                "nie:url                    \"file://music/Song_%1.mp3\" ;"
+                "nfo:belongsToContainer     <file://music/> ;"
+                "nie:title                  \"Song %1\" ;"
+                "nie:mimeType               \"audio/mpeg\" ;"
+                "nie:contentCreated         \"2000-01-01T01:01:01Z\" ;"
+                "nie:isLogicalPartOf        <urn:album:%2> ;"
+                "nco:contributor            <urn:artist:%2> ;"
+                "nfo:fileLastAccessed       \"2000-01-01T01:01:01Z\" ;"
+                "nfo:fileSize               \"0\" ;"
+                "nfo:fileName               \"Song_%1.mp3\" ;"
+                "nfo:fileLastModified       \"2000-01-01T01:01:01Z\" ;"
+                "nfo:codec                  \"MPEG\" ;"
+                "nfo:averageBitrate         \"16\" ;"
+                "nfo:genre                  \"Genre %2\" ;"
+                "nfo:channels               \"2\" ;"
+                "nfo:sampleRate             \"44100.0\" ;"
+                "nmm:musicAlbum             <urn:album:%2> ;"
+                "nmm:musicAlbumDisc         <urn:album-disk:%2> ;"
+                "nmm:performer              <urn:artist:%2> ;"
+                "nfo:duration               \"1\" ;"
+                "nmm:trackNumber            \"%1\" .";
+
+    const QSparqlQuery cleanupQuery(
+        QString("delete { "
+            "?u a rdfs:Resource . } "
+            "where { "
+            "?u nie:isLogicalPartOf %1 . "
+            "?u nie:isLogicalPartOf %2 . "
+            "} "
+            "delete {"
+            "%2 a rdfs:Resource . "
+            "}").arg(testSuiteTag).arg(testCaseTag),
+        QSparqlQuery::DeleteStatement);
+
+    const QSparqlQuery selectQuery(
+        QString("select tracker:id(?musicPiece) ?title ?performer ?album ?duration ?created "
+            "{ "
+            "?musicPiece a nmm:MusicPiece; "
+            "nie:isLogicalPartOf %1; "
+            "nie:isLogicalPartOf %2; "
+            "nie:title ?title; "
+            "nmm:performer ?performer; "
+            "nmm:musicAlbum ?album; "
+            "nfo:duration ?duration; "
+            "nie:contentCreated ?created. "
+            "} order by ?title ?created")
+                .arg(testSuiteTag)
+                .arg(testCaseTag));
+
+    TestDataImpl* testData = new TestDataImpl(cleanupQuery, selectQuery);
+
+    QString insertTagsQuery = QString("insert { %1 a nie:InformationElement. "
+                                               "%2 a nie:InformationElement. "
+                                               "%2 nie:isLogicalPartOf %1. }")
+                                        .arg(testSuiteTag).arg(testCaseTag);
+    QScopedPointer<QSparqlResult> r(conn.syncExec(QSparqlQuery(insertTagsQuery, QSparqlQuery::InsertStatement)));
+    if (r.isNull() || r->hasError())
+        return testData;
+    r.reset();
+
+    for (int item = 1; item <= testDataAmount; ) {
+        QString insertQuery = "insert { ";
+        int itemDozen = 10;
+        const int batchEnd = item + insertBatchSize;
+        for (; item < batchEnd && item <= testDataAmount; ++item) {
+            insertQuery.append( insertQueryTemplate
+                                    .arg(item)
+                                    .arg(itemDozen)
+                                    .arg(testSuiteTag)
+                                    .arg(testCaseTag) );
+            if (item % 10 == 0) itemDozen += 10;
+        }
+        insertQuery.append(" }");
+        QScopedPointer<QSparqlResult> r(conn.syncExec(QSparqlQuery(insertQuery, QSparqlQuery::InsertStatement)));
+        if (r.isNull() || r->hasError())
+            return testData;
+    }
+
+    testData->setOK();
+    return testData;
+}
+
+TestDataImpl::TestDataImpl(const QSparqlQuery& cleanupQuery, const QSparqlQuery& selectQuery)
+    : cleanupQuery(cleanupQuery), selectQuery_(selectQuery), ok(false)
+{
+}
+
+TestDataImpl::~TestDataImpl()
+{
+    QSparqlConnection conn("QTRACKER_DIRECT");
+    conn.syncExec(cleanupQuery);
+}
+
+void TestDataImpl::setOK()
+{
+    ok = true;
+}
+
+bool TestDataImpl::isOK() const
+{
+    return ok;
+}
+
+QSparqlQuery TestDataImpl::selectQuery() const
+{
+    return selectQuery_;
+}
+
--- tests/auto/utils/testdata.h
+++ tests/auto/utils/testdata.h
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (ivan.frade at nokia.com)
+**
+** This file is part of the test suite of the QtSparql module (not yet part of the Qt Toolkit).
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at ivan.frade at nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTDATA_H
+#define TESTDATA_H
+
+#include <QtCore/qobject.h>
+
+class QSparqlQuery;
+
+class TestData : public QObject {
+    Q_OBJECT
+public:
+    static TestData* createTrackerTestData(int testDataAmount, const QString& testSuiteTag, const QString& testCaseTag);
+    virtual ~TestData() { }
+    virtual bool isOK() const =0;
+    virtual QSparqlQuery selectQuery() const = 0;
+};
+
+#endif // TESTDATA_H
+



More information about the MeeGo-commits mailing list