/*
* Copyright (c) 2009 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:
*
*/
#include "pltables.h"
#include "dbsqlconstants.h"
#include "cntitem.h"
#include "cpcskeymap.h"
#include <QStringList>
// How many characters from the beginning of the first name and last name are
// stored. This only affects how precisely the results are put in alphabetic order.
const TInt KCharactersFromName = 16;
// Max amount of tokens stored from contact
const TInt KMaxTokens = 4;
// How many digits are stored at most in the numeric field
// Since BIGINT is a signed 64-bit integer, store only 15 hexadecimal characters
// to prevent overflow when comparing upper and lower limits.
const TInt KMaxDigits = 15;
const quint64 KConversionError = 0xeeeeeeeeeeeeeee;
#define MAPPED_CHAR_FOR_STAR 'a'
#define MAPPED_CHAR_FOR_HASH 'b'
const QChar KMappedQCharForStar = MAPPED_CHAR_FOR_STAR;
const QChar KMappedQCharForHash = MAPPED_CHAR_FOR_HASH;
// These must be same as in cpcskeymap.cpp
const TChar KMappedCharForStar = MAPPED_CHAR_FOR_STAR;
const TChar KMappedCharForHash = MAPPED_CHAR_FOR_HASH;
const QChar KPadChar = 'f'; // Pad with hex-digit 0xF
/**
@param aDatabase A handle to the database.
@param aProperties A contact properties object.
@return A pointer to a new CPplPredictiveSearchTable object.
*/
CPplPredictiveSearchTable*
CPplPredictiveSearchTable::NewL(RSqlDatabase& aDatabase)
{
RDebug::Print(_L("CPplPredictiveSearchTable::NewL"));
CPplPredictiveSearchTable* self = CPplPredictiveSearchTable::NewLC(aDatabase);
CleanupStack::Pop(self);
RDebug::Print(_L("CPplPredictiveSearchTable::NewL ends"));
return self;
}
/**
@param aDatabase A handle to the database.
@param aProperties A contact properties object.
@return A pointer to a new CPplPredictiveSearchTable object.
*/
CPplPredictiveSearchTable*
CPplPredictiveSearchTable::NewLC(RSqlDatabase& aDatabase)
{
RDebug::Print(_L("CPplPredictiveSearchTable::NewLC"));
CPplPredictiveSearchTable* self =
new (ELeave) CPplPredictiveSearchTable(aDatabase);
CleanupStack::PushL(self);
self->ConstructL();
RDebug::Print(_L("CPplPredictiveSearchTable::NewLC ends"));
return self;
}
/**
Destructor
*/
CPplPredictiveSearchTable::~CPplPredictiveSearchTable()
{
RDebug::Print(_L("CPplPredictiveSearchTable dtor"));
delete iInsertStmnt;
delete iDeleteStmnt;
delete iKeyMap;
RDebug::Print(_L("CPplPredictiveSearchTable dtor ends"));
}
/**
@param aItem A contact item whose data are added to the table.
*/
void CPplPredictiveSearchTable::CreateInDbL(CContactItem& aItem)
{
RDebug::Print(_L("CPplPredictiveSearchTable::CreateInDbL"));
WriteToDbL(aItem);
RDebug::Print(_L("CPplPredictiveSearchTable::CreateInDbL ends"));
}
/**
Update is done in two steps: delete contact from all predictive search tables,
then insert it into relevant tables.
@param aItem A contact item whose data is updated in the database.
*/
void CPplPredictiveSearchTable::UpdateL(const CContactItem& aItem)
{
RDebug::Print(_L("CPplPredictiveSearchTable::UpdateL"));
TBool lowDiskErrorOccurred(EFalse);
DeleteFromAllTablesL(aItem.Id(), lowDiskErrorOccurred);
if (lowDiskErrorOccurred)
{
User::Leave(KErrGeneral);
}
WriteToDbL(aItem);
RDebug::Print(_L("CPplPredictiveSearchTable::UpdateL ends"));
}
/**
Deletes a contact item from predictive search tables.
@param aItem The contact item to be deleted. It contains contact id, but not
first name or last name fields.
*/
void CPplPredictiveSearchTable::DeleteL(const CContactItem& aItem,
TBool& aLowDiskErrorOccurred)
{
RDebug::Print(_L("CPplPredictiveSearchTable::DeleteL"));
DeleteFromAllTablesL(aItem.Id(), aLowDiskErrorOccurred);
RDebug::Print(_L("CPplPredictiveSearchTable::DeleteL ends"));
}
/**
Creates the comm_addr table and its indexes in the database.
*/
void CPplPredictiveSearchTable::CreateTableL()
{
RDebug::Print(_L("CPplPredictiveSearchTable::CreateTableL"));
RDebug::Print(_L("Create 12 tables"));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateTable0Stmnt));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateTable1Stmnt));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateTable2Stmnt));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateTable3Stmnt));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateTable4Stmnt));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateTable5Stmnt));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateTable6Stmnt));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateTable7Stmnt));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateTable8Stmnt));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateTable9Stmnt));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateTable10Stmnt));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateTable11Stmnt));
RDebug::Print(_L("Create indexes"));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbrIndexTable0));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbr2IndexTable0));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbr3IndexTable0));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbr4IndexTable0));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbrIndexTable1));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbr2IndexTable1));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbr3IndexTable1));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbr4IndexTable1));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbrIndexTable2));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbr2IndexTable2));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbr3IndexTable2));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbr4IndexTable2));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbrIndexTable3));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbr2IndexTable3));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbr3IndexTable3));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbr4IndexTable3));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbrIndexTable4));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbr2IndexTable4));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbr3IndexTable4));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbr4IndexTable4));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbrIndexTable5));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbr2IndexTable5));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbr3IndexTable5));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbr4IndexTable5));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbrIndexTable6));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbr2IndexTable6));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbr3IndexTable6));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbr4IndexTable6));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbrIndexTable7));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbr2IndexTable7));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbr3IndexTable7));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbr4IndexTable7));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbrIndexTable8));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbr2IndexTable8));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbr3IndexTable8));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbr4IndexTable8));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbrIndexTable9));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbr2IndexTable9));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbr3IndexTable9));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbr4IndexTable9));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbrIndexTable10));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbr2IndexTable10));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbr3IndexTable10));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbr4IndexTable10));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbrIndexTable11));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbr2IndexTable11));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbr3IndexTable11));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateNbr4IndexTable11));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateFNIndexInTable0));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateLNIndexInTable0));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateFNIndexInTable1));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateLNIndexInTable1));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateFNIndexInTable2));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateLNIndexInTable2));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateFNIndexInTable3));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateLNIndexInTable3));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateFNIndexInTable4));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateLNIndexInTable4));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateFNIndexInTable5));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateLNIndexInTable5));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateFNIndexInTable6));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateLNIndexInTable6));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateFNIndexInTable7));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateLNIndexInTable7));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateFNIndexInTable8));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateLNIndexInTable8));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateFNIndexInTable9));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateLNIndexInTable9));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateFNIndexInTable10));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateLNIndexInTable10));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateFNIndexInTable11));
User::LeaveIfError(iDatabase.Exec(KPredSearchCreateLNIndexInTable11));
RDebug::Print(_L("CPplPredictiveSearchTable::CreateTableL ends"));
}
/**
Set up the CCntSqlStatement objects held by the class.
*/
void CPplPredictiveSearchTable::ConstructL()
{
RDebug::Print(_L("CPplPredictiveSearchTable::ConstructL"));
// Using dummy table names here
TCntSqlStatementType insertType(EInsert, KSqlContactPredSearchTable0);
TCntSqlStatementType deleteType(EDelete, KSqlContactPredSearchTable0);
// Insert new record
// INSERT INTO predictivesearchX (X=0..11)
// (contact_id, nbr, nbr2, nbr3, nbr4, first_name, last_name)
// VALUES (contact_id value, nbr value, nbr2 value, nbr3 value, nbr4 value,
// first_name value, last_name value);
iInsertStmnt = TSqlProvider::GetSqlStatementL(insertType);
iInsertStmnt->SetParamL(KPredSearchContactId,
KPredSearchContactIdParam);
iInsertStmnt->SetParamL(KPredSearchNameAsNumber,
KPredSearchNameAsNumberParam);
iInsertStmnt->SetParamL(KPredSearchNameAsNumber2,
KPredSearchNameAsNumber2Param);
iInsertStmnt->SetParamL(KPredSearchNameAsNumber3,
KPredSearchNameAsNumber3Param);
iInsertStmnt->SetParamL(KPredSearchNameAsNumber4,
KPredSearchNameAsNumber4Param);
iInsertStmnt->SetParamL(KPredSearchFirstName,
KPredSearchFirstNameParam);
iInsertStmnt->SetParamL(KPredSearchLastName,
KPredSearchLastNameParam);
const TInt KWhereContactIdBufSize(
KWhereStringEqualsStringFormatText().Size() +
KPredSearchContactId().Size() +
KPredSearchContactIdParam().Size() );
HBufC* whereContactIdClause = HBufC::NewLC(KWhereContactIdBufSize);
// for WHERE contact_id = [contact id value]
whereContactIdClause->Des().AppendFormat(KWhereStringEqualsStringFormatText,
&KPredSearchContactId, &KPredSearchContactIdParam);
// Delete information of a particular contact item
// DELETE FROM predictivesearchX (X=0..11)
// WHERE contact_id = [contact id value];
iDeleteStmnt = TSqlProvider::GetSqlStatementL(deleteType);
iDeleteStmnt->SetConditionL(*whereContactIdClause);
CleanupStack::PopAndDestroy(whereContactIdClause);
RDebug::Print(_L("CPplPredictiveSearchTable::ConstructL create key map"));
iKeyMap = CPcsKeyMap::NewL();
RDebug::Print(_L("CPplPredictiveSearchTable::ConstructL ends"));
}
/**
Constructor
*/
CPplPredictiveSearchTable::CPplPredictiveSearchTable(RSqlDatabase& aDatabase) :
iDatabase(aDatabase)
{
}
// Insert a contact to predictive search tables.
// Write contact's all tokens to each associate pred.search table.
// E.g. if FN="11 22" LN="2 333", write "11","22","2" and "333" to tables 1, 2 and 3.
void CPplPredictiveSearchTable::WriteToDbL(const CContactItem& aItem)
{
RDebug::Print(_L("CPplPredictiveSearchTable::WriteToDbL"));
HBufC* firstNameAsNbr(NULL); // owned
HBufC* lastNameAsNbr(NULL); // owned
HBufC* firstName(NULL); // owned
HBufC* lastName(NULL); // owned
GetFieldsLC(aItem, &firstNameAsNbr, &lastNameAsNbr, &firstName, &lastName);
QStringList numericTokens;
QList<TChar> tables;
QT_TRYCATCH_LEAVING({
numericTokens = GetNumericTokens(firstNameAsNbr, lastNameAsNbr);
tables = DetermineTables(numericTokens);
});
HBufC* tableName(NULL);
while ((tableName = GetNextTableNameL(tables)) != NULL)
{
// Takes ownership. Clears also earlier SQL statement.
iInsertStmnt->SetTableName(tableName);
RSqlStatement stmnt;
CleanupClosePushL( stmnt );
RDebug::Print(_L("CPplPredictiveSearchTable::WriteToDbL SQL='%S'"),
&iInsertStmnt->SqlStringL());
stmnt.PrepareL(iDatabase, iInsertStmnt->SqlStringL());
const TDesC* paramNames[] = {
&KPredSearchNameAsNumberParam,
&KPredSearchNameAsNumber2Param,
&KPredSearchNameAsNumber3Param,
&KPredSearchNameAsNumber4Param};
for (TInt i = 0; i < numericTokens.count(); ++i)
{
quint64 hex(0);
QT_TRYCATCH_LEAVING(hex = ConvertToHex(numericTokens[i]));
if (hex == KConversionError)
{
User::Leave(KErrArgument);
}
User::LeaveIfError(stmnt.BindInt64(
User::LeaveIfError(stmnt.ParameterIndex(*paramNames[i])), hex));
}
User::LeaveIfError(stmnt.BindInt(
User::LeaveIfError(stmnt.ParameterIndex(KPredSearchContactIdParam)),
aItem.Id()));
if (firstName)
{
User::LeaveIfError(stmnt.BindText(
User::LeaveIfError(stmnt.ParameterIndex(KPredSearchFirstNameParam)),
*firstName));
}
if (lastName)
{
User::LeaveIfError(stmnt.BindText(
User::LeaveIfError(stmnt.ParameterIndex(KPredSearchLastNameParam)),
*lastName));
}
RDebug::Print(_L("CPplPredictiveSearchTable::WriteToDbL execute SQL statement"));
// Execute the SQL statement
User::LeaveIfError(stmnt.Exec());
CleanupStack::PopAndDestroy(&stmnt);
}
CleanupStack::PopAndDestroy(lastNameAsNbr);
CleanupStack::PopAndDestroy(lastName);
CleanupStack::PopAndDestroy(firstNameAsNbr);
CleanupStack::PopAndDestroy(firstName);
RDebug::Print(_L("CPplPredictiveSearchTable::WriteToDbL ends"));
}
void CPplPredictiveSearchTable::GetFieldsLC(const CContactItem& aItem,
HBufC** aFirstNameAsNbr,
HBufC** aLastNameAsNbr,
HBufC** aFirstName,
HBufC** aLastName) const
{
RDebug::Print(_L("CPplPredictiveSearchTable::GetFieldsLC"));
__ASSERT_ALWAYS(aFirstNameAsNbr != NULL && *aFirstNameAsNbr == NULL,
User::Leave(KErrArgument));
__ASSERT_ALWAYS(aLastNameAsNbr != NULL && *aLastNameAsNbr == NULL,
User::Leave(KErrArgument));
__ASSERT_ALWAYS(aFirstName != NULL && *aFirstName == NULL,
User::Leave(KErrArgument));
__ASSERT_ALWAYS(aLastName != NULL && *aLastName == NULL,
User::Leave(KErrArgument));
CContactItemFieldSet& fieldset = aItem.CardFields();
TInt pos = fieldset.Find(KUidContactFieldGivenName);
if (pos != KErrNotFound)
{
CContactTextField* textfield = fieldset[pos].TextStorage();
if (textfield)
{
TPtrC firstName = textfield->Text();
*aFirstName = firstName.Left(KCharactersFromName).AllocLC();
*aFirstNameAsNbr = iKeyMap->GetNumericKeyStringL(firstName, EFalse);
}
}
// If aFirstName was not pushed to cleanupstack above, do it now
if (*aFirstName == NULL)
{
CleanupStack::PushL(*aFirstName);
}
CleanupStack::PushL(*aFirstNameAsNbr);
pos = fieldset.Find(KUidContactFieldFamilyName);
if (pos != KErrNotFound)
{
CContactTextField* textfield = fieldset[pos].TextStorage();
if (textfield)
{
TPtrC lastName = textfield->Text();
*aLastName = lastName.Left(KCharactersFromName).AllocLC();
*aLastNameAsNbr = iKeyMap->GetNumericKeyStringL(lastName, EFalse);
}
}
// If aLastName was not pushed to cleanupstack above, do it now
if (*aLastName == NULL)
{
CleanupStack::PushL(*aLastName);
}
CleanupStack::PushL(*aLastNameAsNbr);
RDebug::Print(_L("CPplPredictiveSearchTable::GetFieldsLC id=%d FNnbr='%S' LNnbr='%S' FN='%S' LN='%S'"),
aItem.Id(),
*aFirstNameAsNbr ? *aFirstNameAsNbr : &KNullDesC,
*aLastNameAsNbr ? *aLastNameAsNbr : &KNullDesC,
*aFirstName ? *aFirstName : &KNullDesC,
*aLastName ? *aLastName: &KNullDesC);
}
QList<TChar> CPplPredictiveSearchTable::DetermineTables(QStringList aTokens) const
{
QList<TChar> tables;
for (TInt i = aTokens.count() - 1; i >= 0; --i)
{
__ASSERT_ALWAYS(IsValidChar(aTokens[i][0]),
User::Panic(_L("DetermineTables"), KErrArgument));
TChar ch(aTokens[i][0].unicode());
if (!tables.contains(ch))
{
tables.append(ch);
}
}
return tables;
}
// 1. get first token of LN
// 2. get first token of FN
// 3. get second token of LN
// 4. get second token of FN
// :
// :
// If LN or FN runs out of tokens before KMaxTokens have been found,
// keep getting tokens from the other field.
QStringList CPplPredictiveSearchTable::GetNumericTokens(HBufC* aFirstName,
HBufC* aLastName) const
{
RDebug::Print(_L("CPplPredictiveSearchTable::GetNumericTokens FN='%S',LN='%S'"),
aFirstName ? aFirstName : &KNullDesC,
aLastName ? aLastName : &KNullDesC);
QStringList firstNameTokens;
QStringList lastNameTokens;
AddTokens(aFirstName, firstNameTokens);
AddTokens(aLastName, lastNameTokens);
QStringList tokens;
while (tokens.count() < KMaxTokens &&
(!firstNameTokens.isEmpty() || !lastNameTokens.isEmpty()))
{
GetNextToken(lastNameTokens, tokens);
GetNextToken(firstNameTokens, tokens);
}
RDebug::Print(_L("CPplPredictiveSearchTable::GetNumericTokens found %d tokens"),
tokens.count());
return tokens;
}
// Ignore tokens beginning with invalid (unknown) character.
// Keep duplicate tokens to support e.g. search "202" when both FN and LN are "23".
void
CPplPredictiveSearchTable::AddTokens(HBufC* aString, QStringList& aTokens) const
{
if (aString)
{
QString s((QChar*)aString->Ptr(), aString->Length());
#if defined(USE_ORBIT_KEYMAP)
QStringList tokens = s.split(iKeyMap->Separator(), QString::SkipEmptyParts);
#else
QStringList tokens = s.split(' ', QString::SkipEmptyParts);
#endif
// Select tokens in the same order they are in original aString
for (TInt i = 0; i < tokens.count(); ++i)
{
if (IsValidChar(tokens[i][0]))
{
aTokens.append(tokens[i]);
}
}
}
}
TBool CPplPredictiveSearchTable::IsValidChar(QChar aChar) const
{
return (aChar >= '0' && aChar <= '9') ||
aChar == MAPPED_CHAR_FOR_STAR ||
aChar == MAPPED_CHAR_FOR_HASH;
}
void CPplPredictiveSearchTable::GetNextToken(QStringList& aSource,
QStringList& aDestination) const
{
if (!aSource.isEmpty() && aDestination.count() < KMaxTokens)
{
QString padded = aSource[0].left(KMaxDigits);
aDestination.append(padded);
aSource.removeFirst();
}
}
void
CPplPredictiveSearchTable::DeleteFromAllTablesL(TContactItemId aContactId,
TBool& aLowDiskErrorOccurred) const
{
QList<TChar> tables;
QT_TRYCATCH_LEAVING(tables = FillAllTables());
HBufC* tableName(NULL);
while ((tableName = GetNextTableNameL(tables)) != NULL)
{
iDeleteStmnt->SetTableName(tableName); // Clears also earlier SQL statement
RSqlStatement stmnt;
CleanupClosePushL(stmnt);
RDebug::Print(_L("CPplPredictiveSearchTable::DeleteFromAllTablesL SQL='%S'"),
&iDeleteStmnt->SqlStringL());
stmnt.PrepareL(iDatabase, iDeleteStmnt->SqlStringL());
// Contact id was not added with iDeleteStmnt->SetParamL() so it can not be
// accessed with iDeleteStmnt->ParameterIndex().
// It is the first and only parameter in query
const TInt KContactIdParamIndex(KFirstIndex);
User::LeaveIfError(stmnt.BindInt(KContactIdParamIndex, aContactId));
RDebug::Print(_L("CPplPredictiveSearchTable::DeleteFromAllTablesL execute statement"));
// Returns the amount of affected rows. As contact is not present each
// table, some operations return 0, it is not an error.
TInt status = stmnt.Exec();
RDebug::Print(_L("CPplPredictiveSearchTable::DeleteFromAllTablesL rows deleted=%d"), status);
CleanupStack::PopAndDestroy(&stmnt);
if (status == KErrDiskFull)
{
RDebug::Print(_L("CPplPredictiveSearchTable::DeleteFromAllTablesL disk full"));
aLowDiskErrorOccurred = ETrue;
}
else
{
RDebug::Print(_L("CPplPredictiveSearchTable::DeleteFromAllTablesL status=%d"), status);
User::LeaveIfError(status);
}
}
}
QList<TChar> CPplPredictiveSearchTable::FillAllTables() const
{
QList<TChar> tables;
const TInt KLargestDigitKey = '9';
for (TInt i = '0'; i <= KLargestDigitKey; ++i)
{
TChar ch = i;
tables << ch;
}
tables << KMappedCharForStar;
tables << KMappedCharForHash;
return tables;
}
HBufC* CPplPredictiveSearchTable::GetNextTableNameL(QList<TChar>& aTables) const
{
HBufC* tableName(NULL);
if (aTables.count() > 0)
{
// Enough space for the longest table name
tableName = HBufC::NewL(KSqlContactPredSearchTable11().Length());
TPtr ptr = tableName->Des();
ptr.Append(TableNameL(aTables[0]));
aTables.removeFirst();
RDebug::Print(_L("CPplPredictiveSearchTable::GetNextTableNameL '%S'"), tableName);
}
return tableName;
}
// when qwerty will be supported, keymap prob maps original chars to
// 0..9, a..z + few capital letters
const TDesC& CPplPredictiveSearchTable::TableNameL(TChar aCh) const
{
switch (aCh)
{
case '0': return KSqlContactPredSearchTable0;
case '1': return KSqlContactPredSearchTable1;
case '2': return KSqlContactPredSearchTable2;
case '3': return KSqlContactPredSearchTable3;
case '4': return KSqlContactPredSearchTable4;
case '5': return KSqlContactPredSearchTable5;
case '6': return KSqlContactPredSearchTable6;
case '7': return KSqlContactPredSearchTable7;
case '8': return KSqlContactPredSearchTable8;
case '9': return KSqlContactPredSearchTable9;
case MAPPED_CHAR_FOR_STAR: return KSqlContactPredSearchTable10;
case MAPPED_CHAR_FOR_HASH: return KSqlContactPredSearchTable11;
default:
TUint ch = aCh;
RDebug::Print(_L("CPplPredictiveSearchTable::TableName unknown char '%c'"), ch);
User::Leave(KErrArgument);
return KNullDesC;
}
}
// E.g. aToken = "01230" -> append KPadChar until has KMaxDigits characters
// -> "01230ffffffffff" -> convert to hexadecimal number -> 0x01230ffffffffff.
// If this function would leave, causes panic, perhaps because of QString parameter?
quint64 CPplPredictiveSearchTable::ConvertToHex(QString aToken) const
{
if (aToken.length() > KMaxDigits)
{
return KConversionError;
}
QString padded = aToken.leftJustified(KMaxDigits, KPadChar);
TBuf<KMaxDigits> log(padded.utf16());
RDebug::Print(_L("CPplPredictiveSearchTable::ConvertToHex padded '%S'"), &log);
// Replace unmapped char and the following characters with KPadChar.
QString replaced = padded;
bool done(false);
for (TInt i = 0; i < KMaxDigits && !done; ++i)
{
if (!IsValidChar(padded[i]))
{
// replace() does not work, it puts just one 'a' at end
// replaced = padded.replace(i, KMaxDigits - i, KPadChar);
padded.remove(i, KMaxDigits - i);
replaced = padded.leftJustified(KMaxDigits, KPadChar);
done = true;
TBuf<KMaxDigits> log2(replaced.utf16());
RDebug::Print(_L("After replacing '%S'"), &log2);
}
}
const TInt KHexadecimalBase = 16;
bool ok(true);
quint64 hex = replaced.toULongLong(&ok, KHexadecimalBase);
if (!ok)
{
RDebug::Print(_L("conv to hex failed"));
return KConversionError;
}
RDebug::Print(_L("CPplPredictiveSearchTable::ConvertToHex result 0x%lx"), hex);
return hex;
}