[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