landmarks/locationlandmarks/dbreg/src/EPos_CPosLmDbRegistry.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Fri, 16 Apr 2010 15:23:31 +0300
changeset 18 3825cf2dc8c2
parent 0 667063e416a2
permissions -rw-r--r--
Revision: 201011 Kit: 201015

/*
* Copyright (c) 2005 Nokia Corporation and/or its subsidiary(-ies). 
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: Registry for storing landmark database information.
*
*
*/


// INCLUDE FILES
#include <d32dbms.h>
#include <EPos_Landmarks.h>
#include <epos_poslmdatabaseutility.h>
#include <EPos_TPosLmDatabaseSettings.h>
#include "EPos_CPosLmDbRegistry.h"
#include "EPos_PosDbRegistryConstants.h"
#include "EPos_CPosLmDatabaseIterator.h"

//CONSTANTS
const TInt KPosLmSqlStatementMaxLen = 256;

//If a URI including the sql statement exceed KPosLmSqlStatementMaxLen
//a panic will be raised. The sql statement used in the function
//FindLongEntryL excluding the URI is approx. 55 characters. Creating a
//sql statement with a URI of max 180 characters will therefor not exceed
//KPosLmSqlStatementMaxLen.
const TInt KPosLmSqlStatementUriMaxLen = 180;

struct TDeleteFile
    {
    RFs* iFs;
    TPtrC iFilename;
    };

// ==================== LOCAL FUNCTIONS ====================

// ---------------------------------------------------------
// Deletes the database if anything goes
// wrong during database construction.
// ---------------------------------------------------------
//
void DeleteFileCleanupItem(TAny* aParam)
    {
    TDeleteFile* obj = reinterpret_cast<TDeleteFile*>(aParam);
    obj->iFs->Delete(obj->iFilename);
    }

// ============================ MEMBER FUNCTIONS ===============================

// -----------------------------------------------------------------------------
// CPosLmDbRegistry::CPosLmDbRegistry
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CPosLmDbRegistry::CPosLmDbRegistry()
    {
    }

// -----------------------------------------------------------------------------
// CPosLmDbRegistry::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CPosLmDbRegistry::ConstructL()
    {
    }

// -----------------------------------------------------------------------------
// CPosLmDbRegistry::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
EXPORT_C CPosLmDbRegistry* CPosLmDbRegistry::NewL()
    {
    CPosLmDbRegistry* self = new (ELeave) CPosLmDbRegistry;
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop(self);
    return self;
    }

// Destructor
EXPORT_C CPosLmDbRegistry::~CPosLmDbRegistry()
    {
    iDb.Close();
    }

// -----------------------------------------------------------------------------
// CPosLmDbRegistry::CreateL
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
EXPORT_C void CPosLmDbRegistry::CreateL(
    RFs& aFileSession,
    const TDesC& aFileName)
    {
    User::LeaveIfError(iDb.Create(aFileSession, aFileName));

    TDeleteFile* del = new (ELeave) TDeleteFile;
    del->iFs = &aFileSession;
    del->iFilename.Set(aFileName);

    CleanupStack::PushL(TCleanupItem(DeleteFileCleanupItem, del));

    //Create the database table
    CDbColSet* columns = CDbColSet::NewLC();

    columns->AddL(TDbCol(KPosLmProtocolCol, EDbColText, KProtocolMaxLength));
    columns->AddL(TDbCol(KPosLmFileNameCol, EDbColLongText));
    columns->AddL(TDbCol(KPosLmSettingsCol, EDbColLongText));
    User::LeaveIfError(iDb.CreateTable(KPosLmDbRegistryTable, *columns));

    CleanupStack::PopAndDestroy(columns);

    //Create index on the protocol field
    _LIT(KPosSqlCreateIndex, "CREATE INDEX %S ON %S (%S)");

    HBufC* sql = HBufC::NewLC(KPosLmSqlStatementMaxLen);
    sql->Des().Format(KPosSqlCreateIndex, &KPosLmDbRegIndex,
                  &KPosLmDbRegistryTable, &KPosLmProtocolCol);
    User::LeaveIfError(iDb.Execute(*sql));
    CleanupStack::PopAndDestroy(sql);

    CleanupStack::PopAndDestroy(&del); //DeleteFileCleanupItem
    }

// -----------------------------------------------------------------------------
// CPosLmDbRegistry::Open
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CPosLmDbRegistry::Open(
    RFs& aFileSession,
    const TDesC& aFileName)
    {
    return iDb.Open(aFileSession, aFileName);
    }

// -----------------------------------------------------------------------------
// CPosLmDbRegistry::RegisterDatabaseL
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
EXPORT_C void CPosLmDbRegistry::RegisterDatabaseL(
    const TDesC& aDatabaseUri,
    const TPosLmDatabaseSettings& aSettings)
    {
    RecoverIfNeededL();

    HBufC* embeddedUri =
        PosLmDatabaseUtility::EmbedSingleQuoteCharactersLC(aDatabaseUri);

    RDbView view;
    CleanupClosePushL(view);

    if (FindEntryL(view, *embeddedUri))
        {
        User::Leave(KErrAlreadyExists);
        }

    CleanupStack::PopAndDestroy(2, embeddedUri); //&view

    _LIT(KPosLmSqlRegisterDb, "SELECT %S, %S, %S FROM %S");
    HBufC* sql = HBufC::NewLC(KPosLmSqlStatementMaxLen);
    sql->Des().Format(KPosLmSqlRegisterDb, &KPosLmProtocolCol,
        &KPosLmFileNameCol, &KPosLmSettingsCol, &KPosLmDbRegistryTable);

    CleanupClosePushL(view);
    User::LeaveIfError(view.Prepare(iDb, TDbQuery(*sql),
        TDbWindow::EUnlimited, RDbView::EInsertOnly));

    CDbColSet* colset = view.ColSetL();
    CleanupStack::PushL(colset);

    view.InsertL();
    view.SetColL(
        colset->ColNo(KPosLmProtocolCol), ExtractProtocol(aDatabaseUri));

    RDbColWriteStream out;
    out.OpenLC(view, colset->ColNo(KPosLmFileNameCol));
    out.WriteL(ExtractFileName(aDatabaseUri));
    CleanupStack::Pop(&out);
    out.Close(); // This line must exist in order for
                 // the item to be written to db.

    TPckgC<TPosLmDatabaseSettings> settingsPckg(aSettings);
    out.OpenLC(view, colset->ColNo(KPosLmSettingsCol));
    out.WriteL(settingsPckg);
    CleanupStack::Pop(&out);
    out.Close(); // This line must exist in order for
                 // the item to be written to db.

    view.PutL();
    // CleanupStack::PopAndDestroy(3, sql); //view, colset

    // CleanupStack::PopAndDestroy(colset);
    CleanupStack::Pop(colset);
    delete colset;
    CleanupStack::PopAndDestroy(&view);
    CleanupStack::PopAndDestroy(sql);
    }

// -----------------------------------------------------------------------------
// CPosLmDbRegistry::UnregisterDatabaseL
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
EXPORT_C void CPosLmDbRegistry::UnregisterDatabaseL(
    const TDesC& aDatabaseUri)
    {
    RecoverIfNeededL();

    HBufC* embeddedUri =
        PosLmDatabaseUtility::EmbedSingleQuoteCharactersLC(aDatabaseUri);

    _LIT(KPosLmSqlUnregisterDb,
        "Delete FROM %S WHERE %S = '%S' AND %S = '%S'");

    //If the URI length is less than KPosLmSqlStatementUriMaxLen
    //proceed as usual, i.e. create a sql delete statement to unregister
    //the URI. However, URIs that exceed KPosLmSqlStatementUriMaxLen has
    //to be handled differently, see the else block.
    if (embeddedUri->Length() < KPosLmSqlStatementUriMaxLen)
        {
        TPtrC protPtr = ExtractProtocol(*embeddedUri);
        TPtrC namePtr = ExtractFileName(*embeddedUri);
        HBufC* sql = HBufC::NewLC(KPosLmSqlStatementMaxLen);

        sql->Des().Format(KPosLmSqlUnregisterDb, &KPosLmDbRegistryTable,
            &KPosLmProtocolCol, &protPtr, &KPosLmFileNameCol, &namePtr);

        User::LeaveIfError(iDb.Execute(*sql));
        CleanupStack::PopAndDestroy(sql);
        }
    else
        {
        //Handle long URIs.
        RDbView view;
        CleanupClosePushL(view);

        if (FindLongEntryL(view, *embeddedUri))
            {
            view.DeleteL();
            }

        CleanupStack::PopAndDestroy(&view);
        }
    CleanupStack::PopAndDestroy(embeddedUri);
    }

// -----------------------------------------------------------------------------
// CPosLmDbRegistry::UnregisterAllL
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
EXPORT_C void CPosLmDbRegistry::UnregisterAllL(
    const TDesC& aProtocol)
    {
    RecoverIfNeededL();

    _LIT(KPosLmSqlUnregisterAll, "Delete FROM %S WHERE %S = '%S'");

    HBufC* sql = HBufC::NewLC(KPosLmSqlStatementMaxLen);
    sql->Des().Format(KPosLmSqlUnregisterAll, &KPosLmDbRegistryTable,
        &KPosLmProtocolCol, &aProtocol);

    User::LeaveIfError(iDb.Execute(*sql));
    CleanupStack::PopAndDestroy(sql);
    }

// -----------------------------------------------------------------------------
// CPosLmDbRegistry::ReadDatabaseSettingsL
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
EXPORT_C void CPosLmDbRegistry::ReadDatabaseSettingsL(
    const TDesC& aDatabaseUri,
    TPosLmDatabaseSettings& aSettings)
    {
    RecoverIfNeededL();

    HBufC* embeddedUri =
        PosLmDatabaseUtility::EmbedSingleQuoteCharactersLC(aDatabaseUri);

    RDbView view;
    CleanupClosePushL(view);
    if (!FindEntryL(view, *embeddedUri))
        {
        User::Leave(KErrNotFound);
        }

    CDbColSet* colset = view.ColSetL();
    CleanupStack::PushL(colset);

    view.GetL();
    TPckg<TPosLmDatabaseSettings> dbPckg(aSettings);

    RDbColReadStream in;
    in.OpenLC(view, colset->ColNo(KPosLmSettingsCol));
    in.ReadL(dbPckg);
    in.Close();

    CleanupStack::PopAndDestroy(4, embeddedUri); //&view, colset, &in
    }

// -----------------------------------------------------------------------------
// CPosLmDbRegistry::ModifyDatabaseSettingsL
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
EXPORT_C void CPosLmDbRegistry::ModifyDatabaseSettingsL(
    const TDesC& aDatabaseUri,
    const TPosLmDatabaseSettings& aSettings)
    {
    RecoverIfNeededL();

    HBufC* embeddedUri =
        PosLmDatabaseUtility::EmbedSingleQuoteCharactersLC(aDatabaseUri);

    RDbView view;
    CleanupClosePushL(view);
    if (!FindEntryL(view, *embeddedUri))
        {
        User::Leave(KErrNotFound);
        }

    view.UpdateL();

    CDbColSet* colset = view.ColSetL();
    CleanupStack::PushL(colset);

    TPckg<TPosLmDatabaseSettings> settingsPckg(aSettings);
    RDbColWriteStream out;
    out.OpenLC(view, colset->ColNo(KPosLmSettingsCol));
    out.WriteL(settingsPckg);
    CleanupStack::Pop(&out);
    out.Close();

    view.PutL();

    CleanupStack::PopAndDestroy(3, embeddedUri); //&view, colset
    }

// -----------------------------------------------------------------------------
// CPosLmDbRegistry::ListDatabasesL
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
EXPORT_C CPosLmDatabaseIterator* CPosLmDbRegistry::ListDatabasesL(
    const TDesC& aProtocol)
    {
    RecoverIfNeededL();

    _LIT(KPosLmSqlListDb, "SELECT * FROM %S WHERE %S = '%S'");

    HBufC* sql = HBufC::NewLC(KPosLmSqlStatementMaxLen);
    sql->Des().Format(KPosLmSqlListDb,
        &KPosLmDbRegistryTable, &KPosLmProtocolCol, &aProtocol);

    RDbView view;
    CleanupClosePushL(view);
    User::LeaveIfError(view.Prepare(
        iDb, TDbQuery(*sql), TDbWindow::EUnlimited));
    User::LeaveIfError(view.EvaluateAll());

    CPosLmDatabaseIterator* iter = CPosLmDatabaseIterator::NewL(view);
    CleanupStack::Pop(&view);
    CleanupStack::PopAndDestroy(sql);

    return iter;
    }

// -----------------------------------------------------------------------------
// CPosLmDbRegistry::Compact
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CPosLmDbRegistry::Compact()
    {
    return iDb.Compact();
    }

// -----------------------------------------------------------------------------
// CPosLmDbRegistry::ExtractProtocol
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TPtrC CPosLmDbRegistry::ExtractProtocol(
    const TDesC& aDatabaseUri)
    {
    TInt pos = aDatabaseUri.Find(KProtocol);
    if (pos == KErrNotFound)
        {
        return TPtrC();
        }
    return aDatabaseUri.Left(pos);
    }

// -----------------------------------------------------------------------------
// CPosLmDbRegistry::ExtractFileName
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TPtrC CPosLmDbRegistry::ExtractFileName(
    const TDesC& aDatabaseUri)
    {
    TInt pos = aDatabaseUri.Find(KProtocol);
    if (pos == KErrNotFound)
        {
        return TPtrC();
        }
    return aDatabaseUri.Right(aDatabaseUri.Length() -
        pos - KProtocol().Length());
    }

// -----------------------------------------------------------------------------
// CPosLmDbRegistry::FindEntryL
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CPosLmDbRegistry::FindEntryL(
    RDbView& aView,
    const TDesC& aDatabaseUri)
    {
    if (aDatabaseUri.Length() < KPosLmSqlStatementUriMaxLen)
        {
        _LIT(KPosLmSqlSelectSettings,
            "SELECT %S FROM %S WHERE %S = '%S' AND %S = '%S'");

        TPtrC protPtr = ExtractProtocol(aDatabaseUri);
        TPtrC namePtr = ExtractFileName(aDatabaseUri);
        HBufC* sql = HBufC::NewLC(KPosLmSqlStatementMaxLen);

        sql->Des().Format(KPosLmSqlSelectSettings, &KPosLmSettingsCol,
            &KPosLmDbRegistryTable, &KPosLmProtocolCol, &protPtr,
            &KPosLmFileNameCol, &namePtr);

        User::LeaveIfError(aView.Prepare(iDb, TDbQuery(*sql),
            TDbWindow::EUnlimited));
        User::LeaveIfError(aView.EvaluateAll());

        CleanupStack::PopAndDestroy(sql);
        return aView.NextL();
        }

    return FindLongEntryL(aView, aDatabaseUri);
    }

// -----------------------------------------------------------------------------
// CPosLmDbRegistry::FindLongEntryL
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CPosLmDbRegistry::FindLongEntryL(
    RDbView& aView,
    const TDesC& aDatabaseUri)
    {
    _LIT(KPosLmSqlSelectSettingsLike,
        "SELECT %S, %S FROM %S WHERE %S = '%S' AND %S LIKE '%S*'");

    HBufC* sql = HBufC::NewLC(KPosLmSqlStatementMaxLen);

    TPtrC protPtr = ExtractProtocol(aDatabaseUri);
    TPtrC namePtr = ExtractFileName(aDatabaseUri);
    TPtrC leftPart(namePtr.Left(KPosLmSqlStatementUriMaxLen));

    sql->Des().Format(KPosLmSqlSelectSettingsLike,
        &KPosLmSettingsCol, &KPosLmFileNameCol,
        &KPosLmDbRegistryTable, &KPosLmProtocolCol, &protPtr,
        &KPosLmFileNameCol, &leftPart);

    //Find all entries that match the supplied URI,
    User::LeaveIfError(
        aView.Prepare(iDb, TDbQuery(*sql), TDbWindow::EUnlimited));
    User::LeaveIfError(aView.EvaluateAll());

    //Check for exact matches.
    TBool found(EFalse);
    while (!found && aView.NextL())
        {
        aView.GetL();

        CDbColSet* colset = aView.ColSetL();
        CleanupStack::PushL(colset);

        TDbColNo colNo = colset->ColNo(KPosLmFileNameCol);
        TInt nameLength = aView.ColLength(colNo);

        CleanupStack::PopAndDestroy(colset);

        HBufC* name = HBufC::NewLC(nameLength);
        TPtr ptr = name->Des();

        RDbColReadStream in;
        in.OpenLC(aView, colNo);
        in.ReadL(ptr, nameLength);
        CleanupStack::Pop(&in);
        in.Close();

        if (ptr == namePtr)
            {
            found = ETrue;
            }
        CleanupStack::PopAndDestroy(name);
        }

    CleanupStack::PopAndDestroy(sql);
    return found;
    }

// -----------------------------------------------------------------------------
// CPosLmDbRegistry::RecoverIfNeededL
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CPosLmDbRegistry::RecoverIfNeededL()
    {
    if (iDb.IsDamaged())
        {
        User::LeaveIfError(iDb.Recover());
        }
    }

//  End of File