qtmobility/src/serviceframework/servicedatabase.cpp
changeset 1 2b40d63a9c3d
child 4 90517678cc4f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/qtmobility/src/serviceframework/servicedatabase.cpp	Fri Apr 16 15:51:22 2010 +0300
@@ -0,0 +1,2132 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Mobility Components.
+**
+** $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.
+**
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//#define QT_SFW_SERVICEDATABASE_DEBUG
+
+#include "servicedatabase_p.h"
+#include <QDir>
+#include <QSet>
+#include "qserviceinterfacedescriptor.h"
+#include "qserviceinterfacedescriptor_p.h"
+#include <QUuid>
+#include "dberror_p.h"
+
+//database name
+#define RESOLVERDATABASE "services.db"
+
+//database table names
+#define SERVICE_TABLE "Service"
+#define INTERFACE_TABLE "Interface"
+#define DEFAULTS_TABLE "Defaults"
+#define SERVICE_PROPERTY_TABLE "ServiceProperty"
+#define INTERFACE_PROPERTY_TABLE "InterfaceProperty"
+
+//separator
+#define RESOLVERDATABASE_PATH_SEPARATOR "//"
+
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+#include <QDebug>
+#endif
+
+#define SERVICE_DESCRIPTION_KEY "DESCRIPTION"
+#ifdef QT_SFW_SERVICEDATABASE_USE_SECURITY_TOKEN
+#define SECURITY_TOKEN_KEY "SECURITYTOKEN"
+#endif
+#define INTERFACE_DESCRIPTION_KEY "DESCRIPTION"
+#define INTERFACE_CAPABILITY_KEY "CAPABILITIES"
+
+QTM_BEGIN_NAMESPACE
+
+enum TBindIndexes
+    {
+        EBindIndex=0,
+        EBindIndex1,
+        EBindIndex2,
+        EBindIndex3,
+        EBindIndex4,
+        EBindIndex5,
+        EBindIndex6,
+        EBindIndex7
+    };
+
+
+/*
+   \class ServiceDatabase
+   The ServiceDatabase is responsible for the management of a single
+   service database.  It provides operations for:
+   - opening and closing a connection with the database,
+   - registering and unregistering services
+   - querying for services and interfaces
+   - setting and getting default interface implementations.
+*/
+
+/*
+    Constructor
+*/
+ServiceDatabase::ServiceDatabase(void)
+:m_isDatabaseOpen(false),m_inTransaction(false)
+{
+}
+
+/*
+    Destructor
+*/
+ServiceDatabase::~ServiceDatabase()
+{
+    close();
+}
+
+/*
+    Opens the service database
+    The method creates or opens database and creates tables if they are not present
+    Returns true if the operation was successful, false if not.
+*/
+bool ServiceDatabase::open()
+{
+    if (m_isDatabaseOpen)
+        return true;
+
+    QString path;
+
+    //Create full path to database
+    if(m_databasePath.isEmpty ())
+        m_databasePath = databasePath();
+
+    path = m_databasePath;
+    QFileInfo dbFileInfo(path);
+    if (!dbFileInfo.dir().exists()) {
+       if(!QDir::root().mkpath(dbFileInfo.path())) {
+           QString errorText("Could not create database directory: %1");
+           m_lastError.setError(DBError::CannotCreateDbDir, errorText.arg(dbFileInfo.path()));
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+           qWarning() << "ServiceDatabase::open():-"
+                        << "Problem:" << qPrintable(m_lastError.text());
+#endif
+           close();
+           return false;
+        }
+    }
+
+    m_connectionName = dbFileInfo.completeBaseName();
+    QSqlDatabase  database;
+    if(QSqlDatabase::contains(m_connectionName)) {
+        database = QSqlDatabase::database(m_connectionName);
+    } else {
+        database = QSqlDatabase::addDatabase("QSQLITE", m_connectionName);
+        database.setDatabaseName(path);
+    }
+
+    if (!database.isValid()){
+        m_lastError.setError(DBError::InvalidDatabaseConnection);
+        close();
+        return false;
+    }
+
+    //Create or open database
+    if (!database.isOpen()) {
+        if(!database.open()) {
+            m_lastError.setError(DBError::SqlError, database.lastError().text());
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+            qWarning() << "ServiceDatabase::open():-"
+                        << "Problem:" << "Could not open database"
+                        << "\nReason:" << m_lastError.text();
+#endif
+            close();
+            return false;
+        }
+    }
+    m_isDatabaseOpen = true;
+
+    //Check database structure (tables) and recreate tables if neccessary
+    //If one of tables is missing remove all tables and recreate them
+    //This operation is required in order to avoid data coruption
+    if (!checkTables()) {
+        if(dropTables()) {
+            if (createTables()) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+                qDebug() << "ServiceDatabase::open():-"
+                    << "Database tables recreated";
+#endif
+            } else {
+                //createTable() should've handled error message
+                //and warning
+                close();
+                return false;
+            }
+        }
+        else {
+            //dropTables() should've handled error message
+            //and warning
+            close();
+            return false;
+        }
+    }
+    return true;
+}
+
+/*
+   Adds a \a service into the database.
+
+   May set the following error codes
+   DBError::NoError
+   DBError::LocationAlreadyRegistered
+   DBError::IfaceImplAlreadyRegistered
+   DBError::SqlError
+   DBError::DatabaseNotOpen
+   DBError::InvalidDatabaseConnection
+   DBError::NoWritePermissions
+   DBError::InvalidDatabaseFile
+*/
+//bool ServiceDatabase::registerService(ServiceMetaData &service)
+bool ServiceDatabase::registerService(const ServiceMetaDataResults &service, const QString &securityToken)
+{
+#ifndef QT_SFW_SERVICEDATABASE_USE_SECURITY_TOKEN
+    Q_UNUSED(securityToken);
+#endif
+
+    if(!checkConnection()) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::registerService():-"
+                    << "Problem:" << qPrintable(m_lastError.text());
+#endif
+        return false;
+    }
+
+    QSqlDatabase database = QSqlDatabase::database(m_connectionName);
+    QSqlQuery query(database);
+
+    if (!beginTransaction(&query, Write)) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::registerService():-"
+                    << "Unable to begin transaction"
+                    << "\nReason:" << qPrintable(m_lastError.text());
+#endif
+        return false;
+    }
+    //See if the service's location has already been previously registered
+    QString statement("SELECT Name from Service WHERE Location=? COLLATE NOCASE");
+    QList<QVariant> bindValues;
+    bindValues.append(service.location);
+    if (!executeQuery(&query, statement, bindValues)) {
+        rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::registerService():-"
+                    << qPrintable(m_lastError.text());
+#endif
+        return false;
+    }
+
+    if (query.next()) {
+        QString alreadyRegisteredService = query.value(EBindIndex).toString();
+        const QString errorText = "Cannot register service \"%1\". Service location \"%2\" is already "
+                    "registered to service \"%3\".  \"%3\" must first be deregistered "
+                    "for new registration to take place.";
+
+        m_lastError.setError(DBError::LocationAlreadyRegistered,
+                errorText.arg(service.name)
+                        .arg(service.location)
+                        .arg(alreadyRegisteredService));
+
+        rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::registerService():-"
+                    << "Problem:" << qPrintable(m_lastError.text());
+#endif
+        return false;
+    }
+
+#ifdef QT_SFW_SERVICEDATABASE_USE_SECURITY_TOKEN
+    statement = "SELECT Value FROM ServiceProperty WHERE ServiceID = ? AND Key = ?";
+    bindValues.clear();
+    bindValues.append(service.name);
+    bindValues.append(SECURITY_TOKEN_KEY);
+    
+    if(!executeQuery(&query, statement, bindValues)) {
+        rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::registerService():-"
+                    << qPrintable(m_lastError.text());
+#endif
+        return false;
+    }
+
+    QStringList securityTokens;
+    while(query.next()) {
+        securityTokens << query.value(EBindIndex).toString();
+    }
+    
+    if (!securityTokens.isEmpty() && securityTokens.first() != securityToken) {
+        QString errorText("Access denied: \"%1\"");
+             m_lastError.setError(DBError::NoWritePermissions, errorText.arg(service.name));
+             rollbackTransaction(&query);
+     #ifdef QT_SFW_SERVICEDATABASE_DEBUG
+             qWarning() << "ServiceDatabase::registerService():-"
+                         << "Problem: Unable to register service"
+                         << "\nReason:" << qPrintable(m_lastError.text());
+     #endif    
+             return false;
+    }
+#endif
+
+    statement = "INSERT INTO Service(ID,Name,Location) VALUES(?,?,?)";
+    QString serviceID = QUuid::createUuid().toString();
+
+    bindValues.clear();
+    bindValues.append(serviceID);
+    bindValues.append(service.name);
+    bindValues.append(service.location);
+
+    if (!executeQuery(&query, statement, bindValues)) {
+        rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::registerService():-"
+                    << qPrintable(m_lastError.text());
+#endif
+        return false;
+    }
+
+    statement = "INSERT INTO ServiceProperty(ServiceID,Key,Value) VALUES(?,?,?)";
+    bindValues.clear();
+    bindValues.append(serviceID);
+    bindValues.append(SERVICE_DESCRIPTION_KEY);
+    if (service.description.isNull())
+        bindValues.append("");
+    else
+        bindValues.append(service.description);
+
+    if (!executeQuery(&query, statement, bindValues)) {
+        rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::registerService():-"
+                    << qPrintable(m_lastError.text());
+#endif
+        return false;
+    }
+    
+#ifdef QT_SFW_SERVICEDATABASE_USE_SECURITY_TOKEN
+    if (securityTokens.isEmpty()) {
+        statement = "INSERT INTO ServiceProperty(ServiceID,Key,Value) VALUES(?,?,?)";
+        bindValues.clear();
+        bindValues.append(service.name);
+        bindValues.append(SECURITY_TOKEN_KEY);
+        bindValues.append(securityToken);
+    
+        if (!executeQuery(&query, statement, bindValues)) {
+            rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+            qWarning() << "ServiceDatabase::registerService():-"
+                        << qPrintable(m_lastError.text());
+#endif
+            return false;
+        }
+    }
+#endif
+    
+    QList <QServiceInterfaceDescriptor> interfaces = service.interfaces;
+    QString interfaceID;;
+    foreach (const QServiceInterfaceDescriptor &interface, interfaces) {
+        interfaceID = getInterfaceID(&query, interface);
+        if (m_lastError.code() == DBError::NoError) {
+            QString errorText;
+            errorText = "Cannot register service \"%1\". \"%1\" is already registered "
+                        "and implements interface \"%2\", Version \"%3.%4.\"  \"%1\" must "
+                        "first be deregistered for new registration to take place.";
+            m_lastError.setError(DBError::IfaceImplAlreadyRegistered,
+                                errorText.arg(interface.serviceName())
+                                            .arg(interface.interfaceName())
+                                            .arg(interface.majorVersion())
+                                            .arg(interface.minorVersion()));
+
+            rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+            qWarning() << "ServiceDatabase::registerService():-"
+                        << "Problem:" << qPrintable(m_lastError.text());
+#endif
+            return false;
+        } else if (m_lastError.code() == DBError::NotFound){
+            //No interface implementation already exists for the service
+            //so add it
+            if(!insertInterfaceData(&query, interface, serviceID)) {
+                rollbackTransaction(&query);
+                return false;
+            } else {
+                continue;
+            }
+        } else {
+            rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+            qWarning() << "ServiceDatabase::registerService():-"
+                        << "Unable to confirm if implementation version"
+                        << (QString::number(interface.majorVersion()) + "."
+                           + QString::number(interface.minorVersion())).toAscii()
+                        << "for interface" << interface.interfaceName()
+                        << "is already registered for service "
+                        << interface.serviceName()
+                        << qPrintable(QString("\n") + m_lastError.text());
+#endif
+            return false;
+        }
+    }
+
+    interfaces = service.latestInterfaces;
+    QServiceInterfaceDescriptor defaultInterface;
+    foreach(const QServiceInterfaceDescriptor &interface, interfaces) {
+        defaultInterface = interfaceDefault(interface.interfaceName(), NULL, true);
+        if (m_lastError.code() == DBError::NoError
+                || m_lastError.code() == DBError::ExternalIfaceIDFound) {
+            continue; //default already exists so don't do anything
+        } else if (m_lastError.code() == DBError::NotFound) {
+            //default does not already exist so create one
+            interfaceID = getInterfaceID(&query, interface);
+            if (m_lastError.code() != DBError::NoError) {
+                rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+                qWarning() << "ServiceDatabase::registerService():-"
+                    << "Unable to retrieve interfaceID for "
+                        "interface" << interface.interfaceName()
+                        <<  qPrintable(QString("\n") + m_lastError.text());
+#endif
+                return false;
+            }
+
+            statement = "INSERT INTO Defaults(InterfaceName, InterfaceID) VALUES(?,?)";
+            bindValues.clear();
+            bindValues.append(interface.interfaceName());
+            bindValues.append(interfaceID);
+            if (!executeQuery(&query, statement, bindValues)) {
+                rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+                qWarning() << "ServiceDatabase::registerService():-"
+                    << qPrintable(m_lastError.text());
+#endif
+                return false;
+            }
+        } else {
+            rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+            qWarning() << "ServiceDatabase::registerService()"
+                        << "Problem: Unable to confirm if interface"
+                        << interface.interfaceName()
+                        << "already has a default implementation";
+#endif
+            return false;
+        }
+    }
+
+    if(!commitTransaction(&query)) {
+        rollbackTransaction(&query);
+        return false;
+    }
+    m_lastError.setError(DBError::NoError);
+    return true;
+}
+
+/*
+    Obtains an interface ID corresponding to a given interface \a descriptor
+
+    May set the following error codes:
+    DBError::NoError
+    DBError::NotFound
+    DBError::SqlError
+    DBError::DatabaseNotOpen
+    DBError::InvalidDatabaseConnection
+*/
+QString ServiceDatabase::getInterfaceID(const QServiceInterfaceDescriptor &descriptor) {
+    QString interfaceID;
+    if (!checkConnection()) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::getInterfaceID():-"
+                    << "Problem:" << qPrintable(m_lastError.text());
+#endif
+        return interfaceID;
+    }
+
+    QSqlDatabase database = QSqlDatabase::database(m_connectionName);
+    QSqlQuery query(database);
+
+    return getInterfaceID(&query, descriptor);
+}
+
+/*
+    This function should only ever be called on a user scope database.
+    It returns a list of Interface Name and Interface ID pairs, where
+    the Interface ID refers to an external interface implementation
+    in the system scope database.
+
+    May set the last error to:
+    DBError::NoError
+    DBError::SqlError
+    DBError::DatabaseNotOpen
+    DBError::InvalidDatabaseConnection
+
+    Aside:  There is only one query which implicitly gets
+    wrapped in it's own transaction.
+*/
+QList<QPair<QString,QString> > ServiceDatabase::externalDefaultsInfo()
+{
+    QList<QPair<QString,QString> > ret;
+    if (!checkConnection()) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::externalDefaultsInfo():-"
+                    << "Problem:" << qPrintable(m_lastError.text());
+#endif
+        return ret;
+    }
+
+    QSqlDatabase database = QSqlDatabase::database(m_connectionName);
+    QSqlQuery query(database);
+
+    //Prepare search query, bind criteria values and execute search
+    QString selectComponent = "SELECT InterfaceName, InterfaceID ";
+    QString fromComponent = "FROM Defaults ";
+    QString whereComponent = "WHERE InterfaceID NOT IN (SELECT Interface.ID FROM Interface) ";
+
+    //Aside: this individual query is implicitly wrapped in a transaction
+    if (!executeQuery(&query, selectComponent + fromComponent + whereComponent)) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::externalDefaultsInfo():-"
+                    << "Problem:" << qPrintable(m_lastError.text());
+#endif
+        return ret;
+    }
+
+    while (query.next()) {
+        ret.append(qMakePair(query.value(EBindIndex).toString(),
+                    query.value(EBindIndex1).toString()));
+    }
+
+    m_lastError.setError(DBError::NoError);
+    return ret;
+}
+
+/*
+    Helper function that obtains an interfaceID for a given \a descriptor.
+
+    May set last error to one of the following error codes:
+    DBError::NoError
+    DBError::NotFound
+    DBError::SqlError
+
+    Aside: This function may be safely called standalone or within an explicit
+    transaction.  If called standalone, it's single query is implicitly
+    wrapped in it's own transaction.
+*/
+QString ServiceDatabase::getInterfaceID(QSqlQuery *query, const QServiceInterfaceDescriptor &interface)
+{
+    QString statement = "SELECT Interface.ID "
+                        "FROM Interface, Service "
+                        "WHERE Service.ID = Interface.ServiceID "
+                        "AND Service.Name = ? COLLATE NOCASE "
+                        "AND Interface.Name = ? COLLATE NOCASE "
+                        "AND Interface.VerMaj = ? AND Interface.VerMin = ?";
+    QList<QVariant> bindValues;
+    bindValues.append(interface.serviceName());
+    bindValues.append(interface.interfaceName());
+    bindValues.append(interface.majorVersion());
+    bindValues.append(interface.minorVersion());
+
+    if (!executeQuery(query, statement, bindValues)) {
+        return QString();
+    }
+
+    if (!query->next()) {
+         QString errorText("No Interface Descriptor found with "
+                            "\nService name: %1 "
+                            "\nInterface name: %2 "
+                            "\nVersion: %3.%4");
+        m_lastError.setError(DBError::NotFound, errorText.arg(interface.serviceName())
+                                                        .arg(interface.interfaceName())
+                                                        .arg(interface.majorVersion())
+                                                        .arg(interface.minorVersion()));
+        return QString();
+    }
+
+    m_lastError.setError(DBError::NoError);
+    return query->value(EBindIndex).toString();
+}
+
+/*
+    Helper functions that saves \a interface related data in the Interface table
+    The \a interface data is recorded as belonging to the service assocciated
+    with \a serviceID.
+
+    May set the last error to one of the following error codes:
+    DBError::NoError
+    DBError::SqlError
+
+    Aside: It is already assumed that a write transaction has been started by the
+    time this function is called; and this function will not rollback/commit
+    the transaction.
+*/
+bool ServiceDatabase::insertInterfaceData(QSqlQuery *query,const QServiceInterfaceDescriptor &interface, const QString &serviceID)
+{
+    QString statement = "INSERT INTO Interface(ID, ServiceID,Name,VerMaj, VerMin) "
+                        "VALUES(?,?,?,?,?)";
+    QString interfaceID = QUuid::createUuid();
+
+    QList<QVariant> bindValues;
+    bindValues.append(interfaceID);
+    bindValues.append(serviceID);
+    bindValues.append(interface.interfaceName());
+    bindValues.append(interface.majorVersion());
+    bindValues.append(interface.minorVersion());
+
+    if (!executeQuery(query, statement, bindValues)) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::insertInterfaceData():-"
+                    << qPrintable(m_lastError.text());
+#endif
+        return false;
+    }
+
+    statement = "INSERT INTO InterfaceProperty(InterfaceID, Key, Value) VALUES(?,?,?)";
+    QHash<QServiceInterfaceDescriptor::Attribute, QVariant>::const_iterator iter = interface.d->attributes.constBegin();
+    bool isValidInterfaceProperty;
+    QString capabilities;
+    QString interfaceDescription;
+    while (iter != interface.d->attributes.constEnd()) {
+        isValidInterfaceProperty = true;
+
+        bindValues.clear();
+        bindValues.append(interfaceID);
+        switch (iter.key()) {
+            case (QServiceInterfaceDescriptor::Capabilities):
+                bindValues.append(INTERFACE_CAPABILITY_KEY);
+                capabilities = interface.attribute(QServiceInterfaceDescriptor::Capabilities).toStringList().join(",");
+                if (capabilities.isNull())
+                    capabilities = "";
+                bindValues.append(capabilities);
+                break;
+            case(QServiceInterfaceDescriptor::Location):
+                isValidInterfaceProperty = false;
+                break;
+            case(QServiceInterfaceDescriptor::ServiceDescription):
+                isValidInterfaceProperty = false;
+                break;
+            case(QServiceInterfaceDescriptor::InterfaceDescription):
+                bindValues.append(INTERFACE_DESCRIPTION_KEY);
+                interfaceDescription = interface.attribute(QServiceInterfaceDescriptor::InterfaceDescription).toString();
+                if (interfaceDescription.isNull())
+                    interfaceDescription = "";
+                bindValues.append(interfaceDescription);
+                break;
+            default:
+                isValidInterfaceProperty = false;
+                break;
+        }
+
+        if (isValidInterfaceProperty) {
+              if (!executeQuery(query, statement, bindValues)) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+                  qWarning() << "ServiceDatabase::insertInterfaceData():-"
+                                << qPrintable(m_lastError.text());
+#endif
+                  return false;
+              }
+        }
+        ++iter;
+    }
+
+    //add custom attributes
+    QHash<QString, QString>::const_iterator customIter = interface.d->customAttributes.constBegin();
+    while(customIter!=interface.d->customAttributes.constEnd()) {
+        bindValues.clear();
+        bindValues.append(interfaceID);
+        //to avoid key clashes use separate c_ namespace ->is this sufficient?
+        bindValues.append("c_"+customIter.key());
+        bindValues.append(customIter.value());
+        if (!executeQuery(query, statement, bindValues)) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+            qWarning() << "ServiceDatabase::insertInterfaceData(customProps):-"
+                            << qPrintable(m_lastError.text());
+#endif
+            return false;
+        }
+        ++customIter;
+    }
+    m_lastError.setError(DBError::NoError);
+    return true;
+}
+
+/*
+    Helper function that executes the sql query specified in \a statement.
+    It is assumed that the \a statement uses positional placeholders and
+    corresponding parameters are placed in the list of \a bindValues.
+
+    Aside: This function may be safely called standalone or within an explicit
+    transaction.  If called standalone, it's single query is implicitly
+    wrapped in it's own transaction.
+
+    May set the last error to one of the following error codes:
+    DBError::NoError
+    DBError::SqlError
+    DBError::NoWritePermissions
+    DBError::InvalidDatabaseFile
+*/
+bool ServiceDatabase::executeQuery(QSqlQuery *query, const QString &statement, const QList<QVariant> &bindValues)
+{
+    Q_ASSERT(query != NULL);
+
+    bool success = false;
+    enum {Prepare =0 , Execute=1};
+    for(int stage=Prepare; stage <= Execute; ++stage) {
+        if ( stage == Prepare)
+            success = query->prepare(statement);
+        else // stage == Execute
+            success = query->exec();
+
+        if (!success) {
+            QString errorText;
+            errorText = "Problem: Could not %1 statement: %2"
+                "\nReason: %3"
+                "\nParameters: %4\n";
+            QString parameters;
+            if (bindValues.count() > 0) {
+                for(int i = 0; i < bindValues.count(); ++i) {
+                    parameters.append(QString("\n\t[") + QString::number(i) + "]: " + bindValues.at(i).toString());
+                }
+            } else {
+                parameters = "None";
+            }
+
+            DBError::ErrorCode errorType;
+            int result = query->lastError().number();
+            if (result == 26 || result == 11) {//SQLILTE_NOTADB || SQLITE_CORRUPT
+                qWarning() << "Service Framework:- Database file is corrupt or invalid:" << databasePath();
+                errorType = DBError::InvalidDatabaseFile;
+            }
+            else if ( result == 8) //SQLITE_READONLY
+                errorType = DBError::NoWritePermissions;
+            else
+                errorType = DBError::SqlError;
+
+            m_lastError.setError(errorType,
+                    errorText
+                    .arg(stage == Prepare ?"prepare":"execute")
+                    .arg(statement)
+                    .arg(query->lastError().text())
+                    .arg(parameters));
+
+            query->finish();
+            query->clear();
+            return false;
+        }
+
+        if (stage == Prepare) {
+            foreach(const QVariant &bindValue, bindValues)
+            query->addBindValue(bindValue);
+        }
+    }
+
+    m_lastError.setError(DBError::NoError);
+    return true;
+}
+
+/*
+   Obtains a list of QServiceInterfaceDescriptors that match the constraints supplied
+   by \a filter.
+
+   May set last error to one of the following error codes:
+   DBError::NoError
+   DBError::SqlError
+   DBError::DatabaseNotOpen
+   DBError::InvalidDatabaseConnection
+   DBError::NoWritePermissions
+   DBError::InvalidDatabaseFile
+*/
+QList<QServiceInterfaceDescriptor> ServiceDatabase::getInterfaces(const QServiceFilter &filter)
+{
+    QList<QServiceInterfaceDescriptor> interfaces;
+    if (!checkConnection()) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::getInterfaces():-"
+                    << "Problem:" << qPrintable(m_lastError.text());
+#endif
+        return interfaces;
+    }
+
+    QSqlDatabase database = QSqlDatabase::database(m_connectionName);
+    QSqlQuery query(database);
+
+    //multiple read queries are performed so wrap them
+    //in a read only transaction
+    if (!beginTransaction(&query, Read)) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::getInterfaces():-"
+                    << "Unable to begin transaction:"
+                    << "\nReason:" << qPrintable(m_lastError.text());
+#endif
+        return interfaces;
+    }
+
+    //Prepare search query, bind criteria values
+    QString selectComponent = "SELECT Interface.Name, "
+                                "Service.Name, Interface.VerMaj, "
+                                "Interface.VerMin, "
+                                "Service.Location, "
+                                "Service.ID, "
+                                "Interface.ID ";
+    QString fromComponent = "FROM Interface, Service ";
+    QString whereComponent = "WHERE Service.ID = Interface.ServiceID ";
+    QList<QVariant> bindValues;
+
+    if (filter.serviceName().isEmpty() && filter.interfaceName().isEmpty()) {
+        //do nothing, (don't add any extra constraints to the query
+    } else {
+
+        if (!filter.serviceName().isEmpty()) {
+            whereComponent.append("AND Service.Name = ?").append(" COLLATE NOCASE ");
+            bindValues.append(filter.serviceName());
+        }
+        if (!filter.interfaceName().isEmpty()) {
+            whereComponent.append("AND Interface.Name = ?").append(" COLLATE NOCASE ");
+            bindValues.append(filter.interfaceName());
+            if (filter.majorVersion() >=0 && filter.minorVersion() >=0) {
+                if (filter.versionMatchRule() == QServiceFilter::ExactVersionMatch) {
+                    whereComponent.append("AND Interface.VerMaj = ?").append(" AND Interface.VerMin = ? ");
+                    bindValues.append(QString::number(filter.majorVersion()));
+                    bindValues.append(QString::number(filter.minorVersion()));
+                }
+                else if (filter.versionMatchRule() == QServiceFilter::MinimumVersionMatch) {
+                    whereComponent.append("AND ((Interface.VerMaj > ?")
+                        .append(") OR Interface.VerMaj = ?").append(" AND Interface.VerMin >= ?").append(") ");
+                    bindValues.append(QString::number(filter.majorVersion()));
+                    bindValues.append(QString::number(filter.majorVersion()));
+                    bindValues.append(QString::number(filter.minorVersion()));
+                }
+            }
+        }
+    }
+
+    if (!executeQuery(&query, selectComponent + fromComponent + whereComponent, bindValues)) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::getInterfaces():-"
+                    << "Problem:" << qPrintable(m_lastError.text());
+#endif
+        rollbackTransaction(&query);
+        return interfaces;
+    }
+
+    QServiceInterfaceDescriptor interface;
+    interface.d = new QServiceInterfaceDescriptorPrivate;
+    QStringList capabilities;
+    QString serviceID;
+    QString interfaceID;
+    const QSet<QString> filterCaps = filter.capabilities().toSet();
+    QSet<QString> difference;
+
+    while(query.next()){
+        difference.clear();
+        interface.d->customAttributes.clear();
+        interface.d->attributes.clear();
+        interface.d->interfaceName =query.value(EBindIndex).toString();
+        interface.d->serviceName = query.value(EBindIndex1).toString();
+        interface.d->major = query.value(EBindIndex2).toInt();
+        interface.d->minor = query.value(EBindIndex3).toInt();
+
+        interface.d->attributes[QServiceInterfaceDescriptor::Location]
+            = query.value(EBindIndex4).toString();
+
+        serviceID = query.value(EBindIndex5).toString();
+        if (!populateServiceProperties(&interface, serviceID)) {
+            //populateServiceProperties should already give a warning message
+            //and set the last error
+            interfaces.clear();
+            rollbackTransaction(&query);
+            return interfaces;
+        }
+
+        interfaceID = query.value(EBindIndex6).toString();
+        if (!populateInterfaceProperties(&interface, interfaceID)) {
+            //populateInterfaceProperties should already give a warning message
+            //and set the last error
+            interfaces.clear();
+            rollbackTransaction(&query);
+            return interfaces;
+        }
+
+        const QSet<QString> ifaceCaps = interface.d->attributes.value(QServiceInterfaceDescriptor::Capabilities).toStringList().toSet();
+        difference = ((filter.capabilityMatchRule() == QServiceFilter::MatchMinimum) ? (filterCaps-ifaceCaps) : (ifaceCaps-filterCaps));
+        if (!difference.isEmpty())
+            continue;
+
+        //only return those interfaces that comply with set custom filters
+        if (filter.customAttributes().size() > 0) {
+            QSet<QString> keyDiff = filter.customAttributes().toSet();
+            keyDiff.subtract(interface.d->customAttributes.uniqueKeys().toSet());
+            if (keyDiff.isEmpty()) { //target descriptor has same custom keys as filter
+                bool isMatch = true;
+                const QStringList keys = filter.customAttributes();
+                for(int i = 0; i<keys.count(); i++) {
+                    if (interface.d->customAttributes.value(keys[i]) !=
+                            filter.customAttribute(keys[i])) {
+                        isMatch = false;
+                        break;
+                    }
+                }
+                if (isMatch)
+                    interfaces.append(interface);
+            }
+        } else { //no custom keys -> SQL statement ensures proper selection already
+            interfaces.append(interface);
+        }
+    }
+
+    rollbackTransaction(&query);//read-only operation so just rollback
+    m_lastError.setError(DBError::NoError);
+    return interfaces;
+}
+
+/*
+   Obtains a QServiceInterfaceDescriptor that
+   corresponds to a given \a interfaceID
+
+   May set last error to one of the following error codes:
+   DBError::NoError
+   DBError::NotFound
+   DBError::SqlError
+   DBError::DatabaseNotOpen
+   DBError::InvalidDatabaseConnection
+   DBError::NoWritePermissions
+   DBError::InvalidDatabaseFile
+*/
+QServiceInterfaceDescriptor ServiceDatabase::getInterface(const QString &interfaceID)
+{
+    QServiceInterfaceDescriptor interface;
+    if (!checkConnection()) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::getInterface():-"
+                    << "Problem:" << qPrintable(m_lastError.text());
+#endif
+        return interface;
+    }
+
+    QSqlDatabase database = QSqlDatabase::database(m_connectionName);
+    QSqlQuery query(database);
+
+    if (!beginTransaction(&query, Read)) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::getInterface():-"
+                    << "Unable to begin transaction"
+                    << "\nReason:" << qPrintable(m_lastError.text());
+#endif
+        return interface;
+    }
+
+    QString selectComponent = "SELECT Interface.Name, "
+                                "Service.Name, Interface.VerMaj, "
+                                "Interface.VerMin, "
+                                "Service.Location, "
+                                "Service.ID ";
+    QString fromComponent = "FROM Interface, Service ";
+    QString whereComponent = "WHERE Service.ID = Interface.ServiceID "
+                                    "AND Interface.ID = ? ";
+    QList<QVariant> bindValues;
+    bindValues.append(interfaceID);
+
+    if (!executeQuery(&query, selectComponent + fromComponent + whereComponent, bindValues)) {
+        rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::getInterfaces():-"
+                    << "Problem:" << qPrintable(m_lastError.text());
+#endif
+        return interface;
+    }
+
+    if (!query.next()) {
+        rollbackTransaction(&query);
+        QString errorText("Interface implementation not found for Interface ID: %1");
+        m_lastError.setError(DBError::NotFound, errorText.arg(interfaceID));
+        return interface;
+    }
+
+    interface.d = new QServiceInterfaceDescriptorPrivate;
+    interface.d->interfaceName = query.value(EBindIndex).toString();
+    interface.d->serviceName = query.value(EBindIndex1).toString();
+    interface.d->major = query.value(EBindIndex2).toInt();
+    interface.d->minor = query.value(EBindIndex3).toInt();
+    interface.d->attributes[QServiceInterfaceDescriptor::Location]
+        = query.value(EBindIndex4).toString();
+
+    QString serviceID = query.value(EBindIndex5).toString();
+    if (!populateServiceProperties(&interface, serviceID)) {
+        //populateServiceProperties should already give a warning message
+        //and set the last error
+        rollbackTransaction(&query);
+        return QServiceInterfaceDescriptor();
+    }
+
+    if (!populateInterfaceProperties(&interface, interfaceID)) {
+        //populateInterfaceProperties should already give a warning message
+        //and set the last error
+        rollbackTransaction(&query);
+        return QServiceInterfaceDescriptor();
+    }
+
+    rollbackTransaction(&query);//read only operation so just rollback
+    m_lastError.setError(DBError::NoError);
+    return interface;
+}
+
+/*
+    Obtains a list of services names.  If \a interfaceName is empty,
+    then all service names are returned.  If \a interfaceName specifies
+    an interface then the names of all services implementing that interface
+    are returned
+
+    May set last error to one of the following error codes:
+    DBError::NoError
+    DBError::SqlError
+    DBError::DatabaseNotOpen
+    DBError::InvalidDatabaseConnection
+    DBError::NoWritePermissions
+    DBError::InvalidDatabaseFile
+
+    Aside:  There is only one query which implicitly gets
+    wrapped in it's own transaction.
+*/
+QStringList ServiceDatabase::getServiceNames(const QString &interfaceName)
+{
+    QStringList services;
+    if (!checkConnection()) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::getServiceNames():-"
+                    << "Problem:" << qPrintable(m_lastError.text());
+#endif
+        return services;
+    }
+    QSqlDatabase database = QSqlDatabase::database(m_connectionName);
+    QSqlQuery query(database);
+    QString selectComponent("SELECT DISTINCT Service.Name COLLATE NOCASE ");
+    QString fromComponent;
+    QString whereComponent;
+    QList<QVariant> bindValues;
+    if (interfaceName.isEmpty()) {
+        fromComponent = "FROM Service ";
+    } else {
+        fromComponent = "FROM Interface,Service ";
+        whereComponent = "WHERE Service.ID = Interface.ServiceID AND Interface.Name = ? COLLATE NOCASE ";
+        bindValues.append(interfaceName);
+    }
+
+    if (!executeQuery(&query, selectComponent + fromComponent + whereComponent, bindValues)) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::getServiceNames():-"
+                    << qPrintable(m_lastError.text());
+#endif
+        return services;
+    }
+
+    while( query.next()) {
+        services.append(query.value(EBindIndex).toString());
+    }
+    query.finish();
+    query.clear();
+    m_lastError.setError(DBError::NoError);
+    return services;
+}
+
+/*
+    Returns a descriptor for the default interface implementation of
+    \a interfaceName.
+
+    For user scope databases only, \a defaultInterfaceID is set if the default
+    in the user scope database refers to a interface implementation in the
+    system scope database.  In this case the descriptor will be invalid and
+    the \a defaultInterfaceID must be used to query the system scope database,
+    The last error set to DBError::ExternalIfaceIDFound
+
+    If this function is called within a transaction, \a inTransaction
+    must be set to true.  If \a inTransaction is false, this fuction
+    will begin and end its own transaction.
+
+    The last error may be set to one of the following error codes:
+    DBError::NoError
+    DBError::ExternalIfaceIDFound
+    DBError::SqlError
+    DBError::DatabaseNotOpen
+    DBError::InvalidDatabaseConnection
+    DBError::NoWritePermissions
+    DBError::InvalidDatabaseFile
+*/
+QServiceInterfaceDescriptor ServiceDatabase::interfaceDefault(const QString &interfaceName, QString *defaultInterfaceID,
+                                                                    bool inTransaction)
+{
+    QServiceInterfaceDescriptor interface;
+    if (!checkConnection())
+    {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::interfaceDefault():-"
+                    << "Problem:" << qPrintable(m_lastError.text());
+#endif
+        return interface;
+    }
+
+    QSqlDatabase database = QSqlDatabase::database(m_connectionName);
+    QSqlQuery query(database);
+
+    if (!inTransaction && !beginTransaction(&query, Read)) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::interfaceDefault(QString, QString):-"
+                    << "Unable to begin transaction"
+                    << "\nReason:" << qPrintable(m_lastError.text());
+#endif
+        return interface;
+    }
+
+    QString statement("SELECT InterfaceID FROM Defaults WHERE InterfaceName = ? COLLATE NOCASE");
+    QList<QVariant> bindValues;
+    bindValues.append(interfaceName);
+    if(!executeQuery(&query, statement, bindValues)) {
+        if (!inTransaction)
+            rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::interfaceDefault():-"
+                    << qPrintable(m_lastError.text());
+#endif
+        return interface;
+    }
+
+    QString interfaceID;
+    if (!query.next())
+    {
+        if (!inTransaction)
+            rollbackTransaction(&query);
+        QString errorText("No default service found for interface: \"%1\"");
+        m_lastError.setError(DBError::NotFound, errorText.arg(interfaceName));
+        return interface;
+    }
+    else
+        interfaceID = query.value(EBindIndex).toString();
+    Q_ASSERT(!interfaceID.isEmpty());
+
+    statement = "SELECT Interface.Name, "
+                        "Service.Name, Interface.VerMaj, "
+                        "Interface.VerMin, "
+                        "Service.Location, "
+                        "Service.ID "
+                    "FROM Service, Interface "
+                    "WHERE Service.ID = Interface.ServiceID AND Interface.ID = ?";
+    bindValues.clear();
+    bindValues.append(interfaceID);
+    if(!executeQuery(&query, statement, bindValues))
+    {
+        if (!inTransaction)
+            rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::interfaceDefault():-"
+                    << qPrintable(m_lastError.text());
+#endif
+        return interface;
+    }
+
+    if(!query.next()) {
+        if (!inTransaction)
+            rollbackTransaction(&query);
+        if (defaultInterfaceID != NULL )
+            *defaultInterfaceID = interfaceID;
+        m_lastError.setError(DBError::ExternalIfaceIDFound);
+        return interface;
+    }
+
+    interface.d = new QServiceInterfaceDescriptorPrivate;
+    interface.d->interfaceName =query.value(EBindIndex).toString();
+    interface.d->serviceName = query.value(EBindIndex1).toString();
+    interface.d->major = query.value(EBindIndex2).toInt();
+    interface.d->minor = query.value(EBindIndex3).toInt();
+
+    interface.d->attributes[QServiceInterfaceDescriptor::Location]
+        = query.value(EBindIndex4).toString();
+
+    QString serviceID = query.value(EBindIndex5).toString();
+    if (!populateServiceProperties(&interface, serviceID)) {
+        //populateServiceProperties should already give a warning
+        //and set the last error
+        if (!inTransaction)
+            rollbackTransaction(&query);
+        return QServiceInterfaceDescriptor();
+    }
+
+    if (!populateInterfaceProperties(&interface, interfaceID)) {
+        //populateInterfaceProperties should already give a warning
+        //and set the last error
+        if (!inTransaction)
+            rollbackTransaction(&query);
+        return QServiceInterfaceDescriptor();
+    }
+
+    if (!inTransaction)
+        rollbackTransaction(&query); //Read only operation so just rollback
+    m_lastError.setError(DBError::NoError);
+    return interface;
+}
+
+/*
+   Sets a particular service's \a interface implementation as a the default
+   implementation to look up when using the interface's name in
+   interfaceDefault().
+
+   For a user scope database an \a externalInterfaceID can be provided
+   so that the Defaults table will contain a "link" to an interface
+   implmentation provided in the system scope database.
+
+   May set the last error to one of the following error codes:
+   DBError::NoError
+   DBerror::NotFound
+   DBError::SqlError
+   DBError::DatabaseNotOpen
+   DBError::InvalidDatabaseConnection
+   DBError::NoWritePermissions
+   DBError::InvalidDatabaseFile
+*/
+bool ServiceDatabase::setInterfaceDefault(const QServiceInterfaceDescriptor &interface, const QString &externalInterfaceID)
+{
+    if(!checkConnection()) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::setInterfaceDefault(QServiceInterfaceDescriptor):-"
+            << "Problem:" << qPrintable(m_lastError.text());
+#endif
+        return false;
+    }
+
+    QSqlDatabase database = QSqlDatabase::database(m_connectionName);
+    QSqlQuery query(database);
+
+    //Begin Transaction
+    if(!beginTransaction(&query, Write)) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::setInterfaceDefault(QServiceInterfaceDescriptor):-"
+            << "Problem: Unable to begin transaction"
+            << "\nReason:" << qPrintable(m_lastError.text());
+#endif
+        return false;
+    }
+
+    QString statement;
+    QList<QVariant> bindValues;
+    QString interfaceID = externalInterfaceID;
+    if (interfaceID.isEmpty()) {
+        statement = "SELECT Interface.ID from Interface, Service "
+                "WHERE Service.ID = Interface.ServiceID "
+                "AND Service.Name = ? COLLATE NOCASE "
+                "AND Interface.Name = ? COLLATE NOCASE "
+                "AND Interface.VerMaj = ? "
+                "AND Interface.VerMin = ? ";
+        bindValues.append(interface.serviceName());
+        bindValues.append(interface.interfaceName());
+        bindValues.append(interface.majorVersion());
+        bindValues.append(interface.minorVersion());
+
+        if (!executeQuery(&query, statement, bindValues)) {
+            rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+            qWarning() << "ServiceDatabase::setInterfaceDefault(QServiceInterfaceDescriptor):-"
+                << qPrintable(m_lastError.text());
+#endif
+            return false;
+        }
+
+        if(!query.next()) {
+            QString errorText;
+            errorText = "No implementation for interface: %1, Version: %2.%3 found "
+                "for service: %4";
+            m_lastError.setNotFoundError(errorText.arg(interface.interfaceName())
+                    .arg(interface.majorVersion())
+                    .arg(interface.minorVersion())
+                    .arg(interface.serviceName()));
+
+            rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+            qWarning() << "ServiceDatbase::setInterfaceDefault(QServiceInterfaceDescriptor):-"
+                << "Problem: Unable to set default service"
+                    << "\nReason:" << qPrintable(m_lastError.text());
+#endif
+            return false;
+        }
+
+        interfaceID = query.value(EBindIndex).toString();
+        Q_ASSERT(!interfaceID.isEmpty());
+    }
+
+    statement = "SELECT InterfaceName FROM Defaults WHERE InterfaceName = ? COLLATE NOCASE";
+    bindValues.clear();
+    bindValues.append(interface.interfaceName());
+    if (!executeQuery(&query, statement, bindValues)) {
+        rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::setInterfaceDefault(QServiceInterfaceDescriptor):-"
+                    << qPrintable(m_lastError.text());
+#endif
+        return false;
+    }
+
+    if (query.next()) {
+        statement = "UPDATE Defaults "
+            "SET InterfaceID = ? "
+            "WHERE InterfaceName = ? COLLATE NOCASE";
+        bindValues.clear();
+        bindValues.append(interfaceID);
+        bindValues.append(interface.interfaceName());
+
+        if (!executeQuery(&query, statement, bindValues)) {
+            rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+            qWarning() << "ServiceDatabase::setInterfaceDefault(QServiceInterfaceDescriptor):-"
+                << qPrintable(m_lastError.text());
+#endif
+            return false;
+        }
+    } else {
+        statement = "INSERT INTO Defaults(InterfaceName,InterfaceID) VALUES(?,?)";
+        bindValues.clear();
+        bindValues.append(interface.interfaceName());
+        bindValues.append(interfaceID);
+
+        if (!executeQuery(&query, statement, bindValues)) {
+            rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+            qWarning() << "ServiceDatabase::setInterfaceDefault(QServiceInterfaceDescriptor):-"
+                << qPrintable(m_lastError.text());
+#endif
+            return false;
+        }
+    }
+
+    //End Transaction
+    if (!commitTransaction(&query)) {
+        rollbackTransaction(&query);
+        return false;
+    }
+    m_lastError.setError(DBError::NoError);
+    return true;
+}
+
+/*
+   Removes the service with name \a serviceName.
+   If the service provides a default interface implementation, then
+   another service implementing the highest interface implementation
+   version becomes the new default(if any).  If more than one service
+   provides same the highest version number, an arbitrary choice is made
+   between them.
+
+   May set the last error to the folowing error codes:
+   DBError::NoError
+   DBError::NotFound
+   DBError::SqlError
+   DBError::DatabaseNotOpen
+   DBError::InvalidDatabaseConnection
+   DBError::NoWritePermissions
+   DBError::InvalidDatabaseFile
+*/
+bool ServiceDatabase::unregisterService(const QString &serviceName, const QString &securityToken)
+{
+#ifndef QT_SFW_SERVICEDATABASE_USE_SECURITY_TOKEN
+    Q_UNUSED(securityToken);
+#endif
+
+    if (!checkConnection()) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::unregisterService():-"
+                    << "Problem:" << qPrintable(m_lastError.text());
+#endif
+        return false;
+    }
+
+    QSqlDatabase database = QSqlDatabase::database(m_connectionName);
+    QSqlQuery query(database);
+
+    if(!beginTransaction(&query, Write)) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::unregisterService():-"
+                    << "Problem: Unable to begin transaction"
+                    << "\nReason:" << qPrintable(m_lastError.text());
+#endif
+        return false;
+    }
+        
+    QString statement("SELECT Service.ID from Service WHERE Service.Name = ? COLLATE NOCASE");
+    QList<QVariant> bindValues;
+    bindValues.append(serviceName);
+    if(!executeQuery(&query, statement, bindValues)) {
+        rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::unregisterService():-"
+                    << qPrintable(m_lastError.text());
+#endif
+        return false;
+    }
+
+    QStringList serviceIDs;
+    while(query.next()) {
+        serviceIDs << query.value(EBindIndex).toString();
+    }
+
+
+#ifdef QT_SFW_SERVICEDATABASE_USE_SECURITY_TOKEN
+    statement = "SELECT Value FROM ServiceProperty WHERE ServiceID = ? AND Key = ?";
+    bindValues.clear();
+    bindValues.append(serviceName);
+    bindValues.append(SECURITY_TOKEN_KEY);
+    if(!executeQuery(&query, statement, bindValues)) {
+        rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::unregisterService():-"
+                    << qPrintable(m_lastError.text());
+#endif
+        return false;
+    }
+
+    QStringList securityTokens;
+    while(query.next()) {
+        securityTokens << query.value(EBindIndex).toString();
+    }
+    
+    if (!securityTokens.isEmpty() && (securityTokens.first() != securityToken)) {
+        QString errorText("Access denied: \"%1\"");
+             m_lastError.setError(DBError::NoWritePermissions, errorText.arg(serviceName));
+             rollbackTransaction(&query);
+     #ifdef QT_SFW_SERVICEDATABASE_DEBUG
+             qWarning() << "ServiceDatabase::unregisterService():-"
+                         << "Problem: Unable to unregister service"
+                         << "\nReason:" << qPrintable(m_lastError.text());
+     #endif    
+    }
+    
+#endif
+    
+    statement = "SELECT Interface.ID from Interface, Service "
+                "WHERE Interface.ServiceID = Service.ID "
+                    "AND Service.Name =? COLLATE NOCASE";
+    bindValues.clear();
+    bindValues.append(serviceName);
+    if (!executeQuery(&query, statement, bindValues)) {
+        rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::unregisterService():-"
+                    << qPrintable(m_lastError.text());
+#endif
+        return false;
+    }
+    
+    QStringList interfaceIDs;
+    while (query.next()) {
+        interfaceIDs << query.value(EBindIndex).toString();
+    }
+
+    if (serviceIDs.count() == 0) {
+        QString errorText("Service not found: \"%1\"");
+        m_lastError.setError(DBError::NotFound, errorText.arg(serviceName));
+        rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::unregisterService():-"
+                    << "Problem: Unable to unregister service"
+                    << "\nReason:" << qPrintable(m_lastError.text());
+#endif
+        return false;
+    }
+
+    statement = "SELECT Defaults.InterfaceName "
+                "FROM Defaults, Interface, Service "
+                "WHERE Defaults.InterfaceID = Interface.ID "
+                    "AND Interface.ServiceID = Service.ID "
+                    "AND Service.Name = ? COLLATE NOCASE";
+    bindValues.clear();
+    bindValues.append(serviceName);
+    if (!executeQuery(&query, statement, bindValues)) {
+        rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase:unregisterService():-"
+                    << qPrintable(m_lastError.text());
+#endif
+        return false;
+    }
+
+    QStringList serviceDefaultInterfaces;
+    while(query.next()) {
+        serviceDefaultInterfaces << query.value(EBindIndex).toString();
+    }
+
+    
+    statement = "DELETE FROM Service WHERE Service.Name = ? COLLATE NOCASE";
+    bindValues.clear();
+    bindValues.append(serviceName);
+    if (!executeQuery(&query, statement, bindValues)) {
+        rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::unregisterService():-"
+                    << qPrintable(m_lastError.text());
+#endif
+        return false;
+    }
+
+    statement = "DELETE FROM Interface WHERE Interface.ServiceID = ?";
+    foreach(const QString &serviceID, serviceIDs) {
+        bindValues.clear();
+        bindValues.append(serviceID);
+        if (!executeQuery(&query, statement, bindValues)) {
+            rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+            qWarning() << "ServiceDatabase::unregisterService():-"
+                        << qPrintable(m_lastError.text());
+#endif
+            return false;
+        }
+    }
+
+#ifndef QT_SFW_SERVICEDATABASE_USE_SECURITY_TOKEN
+    statement = "DELETE FROM ServiceProperty WHERE ServiceID = ?";
+#else
+    statement = "DELETE FROM ServiceProperty WHERE ServiceID = ? AND Key <> ?";
+#endif
+
+    
+    foreach(const QString &serviceID, serviceIDs) {
+        bindValues.clear();
+        bindValues.append(serviceID);
+#ifdef QT_SFW_SERVICEDATABASE_USE_SECURITY_TOKEN
+        bindValues.append(SECURITY_TOKEN_KEY);
+#endif
+        if (!executeQuery(&query, statement, bindValues)) {
+            rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+            qWarning() << "ServiceDatabase::unregisterService():-"
+                        << qPrintable(m_lastError.text());
+#endif
+            return false;
+        }
+    }
+
+    statement = "DELETE FROM InterfaceProperty WHERE InterfaceID = ?";
+    foreach(const QString &interfaceID,  interfaceIDs) {
+        bindValues.clear();
+        bindValues.append(interfaceID);
+        if (!executeQuery(&query, statement, bindValues)) {
+            rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+            qWarning() << "ServiceDatabase::unregisterService():-"
+                        << qPrintable(m_lastError.text());
+#endif
+            return false;
+        }
+    }
+
+    foreach(const QString &interfaceName, serviceDefaultInterfaces) {
+        statement = "SELECT ID FROM Interface WHERE Interface.Name = ? COLLATE NOCASE "
+                    "ORDER BY Interface.VerMaj DESC, Interface.VerMin DESC";
+        bindValues.clear();
+        bindValues.append(interfaceName);
+        if (!executeQuery(&query, statement, bindValues)) {
+            rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+            qWarning() << "ServiceDatabase::unregisterService():-"
+                        << qPrintable(m_lastError.text());
+#endif
+            return false;
+        }
+
+        if(query.next()) {
+            QString newDefaultID = query.value(EBindIndex).toString();
+            statement = "UPDATE Defaults SET InterfaceID = ? WHERE InterfaceName = ? COLLATE NOCASE ";
+            bindValues.clear();
+            bindValues.append(newDefaultID);
+            bindValues.append(interfaceName);
+            if (!executeQuery(&query, statement, bindValues)) {
+                rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+                qWarning() << "ServiceDatabase::unregisterService():-"
+                            << qPrintable(m_lastError.text());
+#endif
+                return false;
+            }
+        } else {
+            statement = "DELETE FROM Defaults WHERE InterfaceName = ? COLLATE NOCASE ";
+            bindValues.clear();
+            bindValues.append(interfaceName);
+            if (!executeQuery(&query, statement, bindValues)) {
+                rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+                qWarning() << "ServiceDatabase::unregisterService():-"
+                            << qPrintable(m_lastError.text());
+#endif
+                return false;
+            }
+        }
+    }
+
+    //databaseCommit
+    if (!commitTransaction(&query)) {
+        rollbackTransaction(&query);
+        return false;
+    }
+    m_lastError.setError(DBError::NoError);
+    return true;
+}
+
+/*
+    Closes the database
+
+    May set the following error codes:
+    DBError::NoError
+    DBError::InvalidDatabaseConnection
+*/
+bool ServiceDatabase::close()
+{
+    if(m_isDatabaseOpen) {
+        QSqlDatabase database = QSqlDatabase::database(m_connectionName, false);
+        if (database.isValid()){
+            if(database.isOpen()) {
+                database.close();
+                m_isDatabaseOpen = false;
+                return true;
+            }
+        } else {
+            m_lastError.setError(DBError::InvalidDatabaseConnection);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+            qWarning() << "ServiceDatabase::close():-"
+                        << "Problem: " << qPrintable(m_lastError.text());
+#endif
+            return false;
+        }
+    }
+    m_lastError.setError(DBError::NoError);
+    return true;
+}
+
+/*
+    Sets the path of the service database to \a databasePath
+*/
+void ServiceDatabase::setDatabasePath(const QString &databasePath)
+{
+    m_databasePath = QDir::toNativeSeparators(databasePath);
+}
+
+/*
+    Returns the path of the service database
+*/
+QString ServiceDatabase::databasePath() const
+{
+    QString path;
+    if(m_databasePath.isEmpty()) {
+        QSettings settings(QSettings::SystemScope, "Nokia", "Services");
+        path = settings.value("ServicesDB/Path").toString();
+        if (path.isEmpty()) {
+            path = QDir::currentPath();
+            if (path.lastIndexOf(RESOLVERDATABASE_PATH_SEPARATOR) != path.length() -1) {
+                path.append(RESOLVERDATABASE_PATH_SEPARATOR);
+            }
+            path.append(RESOLVERDATABASE);
+        }
+        path = QDir::toNativeSeparators(path);
+    } else {
+        path = m_databasePath;
+    }
+
+    return path;
+}
+
+/*
+    Helper method that creates the database tables: Service, Interface,
+    Defaults, ServiceProperty and InterfaceProperty
+
+    May set the last error to one of the following error codes:
+    DBError::NoError
+    DBError::SqlError
+    DBError::NoWritePermissions
+    DBError::InvalidDatabaseFile
+*/
+bool ServiceDatabase::createTables()
+{
+    QSqlDatabase database = QSqlDatabase::database(m_connectionName);
+    QSqlQuery query(database);
+
+    //Begin Transaction
+    if (!beginTransaction(&query, Write)) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::createTables():-"
+                    << "Unable to begin transaction"
+                    << "\nReason:" << qPrintable(m_lastError.text());
+#endif
+        return false;
+    }
+
+    QString statement("CREATE TABLE Service("
+                        "ID TEXT NOT NULL PRIMARY KEY UNIQUE,"
+                        "Name TEXT NOT NULL, "
+                        "Location TEXT NOT NULL)");
+    if (!executeQuery(&query, statement)) {
+        rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::createTables():-"
+                    << qPrintable(m_lastError.text());
+#endif
+        return false;
+    }
+
+    statement = "CREATE TABLE Interface("
+                "ID TEXT NOT NULL PRIMARY KEY UNIQUE,"
+                "ServiceID TEXT NOT NULL, "
+                "Name TEXT NOT NULL, "
+                "VerMaj INTEGER NOT NULL, "
+                "VerMin INTEGER NOT NULL)";
+    if (!executeQuery(&query, statement)) {
+        rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::createTables():-"
+                    << qPrintable(m_lastError.text());
+#endif
+        return false;
+    }
+
+    statement = "CREATE TABLE Defaults("
+                "InterfaceName TEXT PRIMARY KEY UNIQUE NOT NULL,"
+                "InterfaceID TEXT NOT NULL)";
+    if (!executeQuery(&query, statement)) {
+        rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::createTables():-"
+                    << qPrintable(m_lastError.text());
+#endif
+        return false;
+    }
+
+    statement = "CREATE TABLE ServiceProperty("
+                "ServiceID TEXT NOT NULL,"
+                "Key TEXT NOT NULL,"
+                "Value TEXT NOT NULL)";
+    if (!executeQuery(&query, statement)) {
+        rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::createTables():-"
+                    << qPrintable(m_lastError.text());
+#endif
+        return false;
+    }
+
+    statement = "CREATE TABLE InterfaceProperty("
+                "InterfaceID TEXT NOT NULL,"
+                "Key TEXT NOT NULL,"
+                "Value TEXT NOT NULL)";
+
+    if (!executeQuery(&query, statement)) {
+        rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::createTables():-"
+                    << qPrintable(m_lastError.text());
+#endif
+        return false;
+    }
+
+    if(!commitTransaction(&query)) {
+        rollbackTransaction(&query);
+        return false;
+    }
+    m_lastError.setError(DBError::NoError);
+    return true;
+}
+
+/*!
+    Helper method that checks if the all expected tables exist in the database
+    Returns true if they all exist and false if any of them don't
+*/
+bool ServiceDatabase::checkTables()
+{
+    bool bTables(false);
+    QStringList tables = QSqlDatabase::database(m_connectionName).tables();
+    if (tables.contains(SERVICE_TABLE)
+        && tables.contains(INTERFACE_TABLE)
+        && tables.contains(DEFAULTS_TABLE)
+        && tables.contains(SERVICE_PROPERTY_TABLE)
+        && tables.contains(INTERFACE_PROPERTY_TABLE)){
+            bTables = true;
+    }
+    return bTables;
+}
+
+/*
+   This function should only ever be used on a user scope database
+   It removes an entry from the Defaults table where the default
+   refers to an interface implementation in the system scope database.
+   The particular default that is removed is specified by
+   \a interfaceID.
+
+   May set the last error to one of the following error codes:
+   DBError::NoError
+   DBError::IfaceIDNotExternal
+   DBError::SqlError
+   DBError::NoWritePermissions
+   DBError::InvalidDatabaseFile
+*/
+bool ServiceDatabase::removeExternalDefaultServiceInterface(const QString &interfaceID)
+{
+    QSqlDatabase database = QSqlDatabase::database(m_connectionName);
+    QSqlQuery query(database);
+
+    //begin transaction
+    if (!beginTransaction(&query, Write)) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::removeExternalDefaultServiceInterface():-"
+                    << "Problem: Unable to begin transaction"
+                    << "\nReason:" << qPrintable(m_lastError.text());
+#endif
+        return false;
+    }
+
+    QString statement("SELECT Name FROM Interface WHERE Interface.ID = ?");
+    QList<QVariant> bindValues;
+    bindValues.append(interfaceID);
+    if (!executeQuery(&query, statement, bindValues)) {
+        rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::removeDefaultServiceInterface():-"
+                    << qPrintable(m_lastError.text());
+#endif
+        return false;
+    }
+    if (query.next()) {
+        QString interfaceName = query.value(EBindIndex).toString();
+        QString errorText("Local interface implementation exists for interface \"%1\" "
+                           "with interfaceID: \"%2\"");
+        m_lastError.setError(DBError::IfaceIDNotExternal,
+                errorText.arg(interfaceName).arg(interfaceID));
+        rollbackTransaction(&query);
+        return false;
+    }
+
+    statement = "DELETE FROM Defaults WHERE InterfaceID = ? COLLATE NOCASE";
+    bindValues.clear();
+    bindValues.append(interfaceID);
+    if (!executeQuery(&query, statement, bindValues)) {
+        rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::removeDefaultServiceInterface():-"
+                    << qPrintable(m_lastError.text());
+#endif
+        return false;
+    }
+
+    //end transaction
+    if (!commitTransaction(&query)){
+        rollbackTransaction(&query);
+        return false;
+    }
+    m_lastError.setError(DBError::NoError);
+    return true;
+}
+
+/*
+    Removes all tables from the database
+
+    In future this function may be deprecated or removed.
+
+    May set the last error to one of the following error codes:
+    DBError::NoError
+    DBError::SqlError
+    DBError::NoWritePermissions
+    DBError::InvalidDatabaseFile
+*/
+bool ServiceDatabase::dropTables()
+{
+    //Execute transaction for deleting the database tables
+    QSqlDatabase database = QSqlDatabase::database(m_connectionName);
+    QSqlQuery query(database);
+    QStringList expectedTables;
+    expectedTables << SERVICE_TABLE
+                << INTERFACE_TABLE
+                << DEFAULTS_TABLE
+                << SERVICE_PROPERTY_TABLE
+                << INTERFACE_PROPERTY_TABLE;
+
+    if (database.tables().count() > 0) {
+        if (!beginTransaction(&query, Write)) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+            qWarning() << "ServiceDatabase::dropTables():-"
+                        << "Unable to begin transaction"
+                        << "\nReason:" << qPrintable(m_lastError.text());
+#endif
+            return false;
+        }
+        QStringList actualTables = database.tables();
+
+        foreach(QString expectedTable, expectedTables) {
+            if ((actualTables.contains(expectedTable))
+                && (!executeQuery(&query, QString("DROP TABLE ") + expectedTable))) {
+                rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+                qWarning() << "ServiceDatabase::dropTables():-"
+                           << qPrintable(m_lastError.text());
+#endif
+                return false;
+            }
+        }
+        if (!commitTransaction(&query)) {
+            rollbackTransaction(&query);
+            return false;
+        }
+    }
+    m_lastError.setError(DBError::NoError);
+    return true;
+}
+
+/*
+    Checks if the database is open
+*/
+bool ServiceDatabase::isOpen() const
+{
+  return m_isDatabaseOpen;
+}
+
+/*
+   Checks the database connection.
+
+   May set the last error to one of the following error codes:
+   DBError::DatabaseNotOpen
+   DBError::InvalidDatabaseConnection
+*/
+bool ServiceDatabase::checkConnection()
+{
+    if(!m_isDatabaseOpen)
+    {
+        m_lastError.setError(DBError::DatabaseNotOpen);
+        return false;
+    }
+
+    if (!QSqlDatabase::database(m_connectionName).isValid())
+    {
+        m_lastError.setError(DBError::InvalidDatabaseConnection);
+        return false;
+    }
+
+    return true;
+}
+
+/*
+   Begins a transcaction based on the \a type which can be Read or Write.
+
+   May set the last error to one of the following error codes:
+   DBError::NoError
+   DBError::SqlError
+   DBError::NoWritePermissions
+   DBError::InvalidDatabaseFile
+*/
+bool ServiceDatabase::beginTransaction(QSqlQuery *query, TransactionType type)
+{
+    bool success;
+    if (type == Read)
+        success = query->exec(QLatin1String("BEGIN"));
+    else
+        success = query->exec(QLatin1String("BEGIN IMMEDIATE"));
+
+    if (!success) {
+        int result = query->lastError().number();
+        if (result == 26 || result == 11) {//SQLITE_NOTADB || SQLITE_CORRUPT
+            qWarning() << "Service Framework:- Database file is corrupt or invalid:" << databasePath();
+            m_lastError.setError(DBError::InvalidDatabaseFile, query->lastError().text());
+        }
+        else if (result == 8) { //SQLITE_READONLY
+            qWarning() << "Service Framework:-  Insufficient permissions to write to database:" << databasePath();
+            m_lastError.setError(DBError::NoWritePermissions, query->lastError().text());
+        }
+        else
+            m_lastError.setError(DBError::SqlError, query->lastError().text());
+        return false;
+    }
+
+    m_lastError.setError(DBError::NoError);
+    return true;
+}
+
+/*
+    Commits a transaction
+
+    May set the last error to one of the following error codes:
+    DBError::NoError
+    DBError::SqlError
+*/
+bool ServiceDatabase::commitTransaction(QSqlQuery *query)
+{
+    Q_ASSERT(query != NULL);
+    query->finish();
+    query->clear();
+    if (!query->exec(QLatin1String("COMMIT"))) {
+        m_lastError.setError(DBError::SqlError, query->lastError().text());
+        return false;
+    }
+    m_lastError.setError(DBError::NoError);
+    return true;
+}
+
+/*
+    Rolls back a transaction
+
+    May set the last error to one of the following error codes:
+    DBError::NoError
+    DBError::SqlError
+*/
+bool ServiceDatabase::rollbackTransaction(QSqlQuery *query)
+{
+    Q_ASSERT(query !=NULL);
+    query->finish();
+    query->clear();
+
+    if (!query->exec(QLatin1String("ROLLBACK"))) {
+        m_lastError.setError(DBError::SqlError, query->lastError().text());
+        return false;
+    }
+    return true;
+}
+
+/*
+    Helper function that populates a service \a interface descriptor
+    with interface related attributes corresponding to the interface
+    represented by \a interfaceID
+
+    It is already assumed that a transaction has been started by the time
+    this function is called.  This function will not rollback/commit the
+    transaction.
+
+    May set the last error to one of the following error codes:
+    DBError::NoError
+    DBError::SqlError
+*/
+bool ServiceDatabase::populateInterfaceProperties(QServiceInterfaceDescriptor *interface, const QString &interfaceID)
+{
+    QSqlQuery query(QSqlDatabase::database(m_connectionName));
+    QString statement("SELECT Key, Value FROM InterfaceProperty WHERE InterfaceID = ?");
+    QList<QVariant> bindValues;
+    bindValues.append(interfaceID);
+    if (!executeQuery(&query, statement, bindValues)) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::populateInterfaceProperties():-"
+                    << qPrintable(m_lastError.text());
+#endif
+        return false;
+    }
+
+    bool isFound = false;
+    QString attribute;
+    while (query.next()) {
+        isFound = true;
+        attribute = query.value(EBindIndex).toString();
+        if (attribute == INTERFACE_CAPABILITY_KEY) {
+            const QStringList capabilities = query.value(EBindIndex1).toString().split(",");
+            if (capabilities.count() == 1 && capabilities[0].isEmpty()) {
+                interface->d->attributes[QServiceInterfaceDescriptor::Capabilities]
+                    = QStringList();
+            } else {
+                interface->d->attributes[QServiceInterfaceDescriptor::Capabilities]
+                = capabilities;
+            }
+        } else if (attribute == INTERFACE_DESCRIPTION_KEY) {
+            interface->d->attributes[QServiceInterfaceDescriptor::InterfaceDescription]
+               = query.value(EBindIndex1).toString();
+        } else if (attribute.startsWith("c_")) {
+            interface->d->customAttributes[attribute.mid(2)]
+               = query.value(EBindIndex1).toString();
+        }
+    }
+
+    if (!isFound) {
+        QString errorText("Database integrity corrupted, Properties for InterfaceID: %1 does not exist in the InterfaceProperty table for interface \"%2\"");
+        m_lastError.setError(DBError::SqlError, errorText.arg(interfaceID).arg(interface->interfaceName()));
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::populateInterfaceProperties():-"
+                    << "Problem:" << qPrintable(m_lastError.text());
+#endif
+        return false;
+    }
+    m_lastError.setError(DBError::NoError);
+    return true;
+}
+
+/*
+    Helper function that populates a service \a interface descriptor
+    with service related attributes corresponding to the service
+    represented by \a serviceID
+
+    It is already assumed that a transaction has been started by the time
+    this function is called.  This function will not rollback/commit the
+    transaction.
+
+    May set the last error to one of the following error codes:
+    DBError::NoError
+    DBError::SqlError
+*/
+bool ServiceDatabase::populateServiceProperties(QServiceInterfaceDescriptor *interface, const QString &serviceID)
+{
+    QSqlQuery query(QSqlDatabase::database(m_connectionName));
+    QString statement("SELECT Key, Value FROM ServiceProperty WHERE ServiceID = ?");
+    QList<QVariant> bindValues;
+    bindValues.append(serviceID);
+    if (!executeQuery(&query, statement, bindValues)) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::populateServiceProperties():-"
+                    << qPrintable(m_lastError.text());
+#endif
+        return false;
+    }
+
+    bool isFound = false;
+    QString attribute;
+    while (query.next()) {
+        isFound = true;
+        attribute = query.value(EBindIndex).toString();
+        if (attribute == SERVICE_DESCRIPTION_KEY) {
+                interface->d->attributes[QServiceInterfaceDescriptor::ServiceDescription]
+                    = query.value(EBindIndex1).toString();
+        }
+    }
+
+    if (!isFound) {
+        QString errorText("Database integrity corrupted, Service Properties for ServiceID: \"%1\" does not exist in the ServiceProperty table for service \"%2\"");
+        m_lastError.setError(DBError::SqlError, errorText.arg(serviceID).arg(interface->serviceName()));
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+        qWarning() << "ServiceDatabase::populateServiceProperties():-"
+                    << "Problem:" << qPrintable(m_lastError.text());
+#endif
+        return false;
+    }
+    m_lastError.setError(DBError::NoError);
+    return true;
+}
+
+#include "moc_servicedatabase_p.cpp"
+
+QTM_END_NAMESPACE