--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/persistentstorage/dbms/usql/UQ_PARSE.CPP Fri Jan 22 11:06:30 2010 +0200
@@ -0,0 +1,807 @@
+// Copyright (c) 1998-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:
+// SQL parser
+//
+//
+
+#include "UQ_STD.H"
+
+// class TSqlParser
+
+const TInt KSqlError = -1;
+
+TSqlParser::TSqlParser(const TDesC& aSql)
+ : iSql(aSql)
+ {
+ NextToken(); // parse the first token
+ }
+
+TSqlTokenType TSqlParser::NextToken()
+ {
+ return iSql.NextToken(iToken);
+ }
+
+CSqlSearchCondition* TSqlParser::SqlError()
+ {
+ if (!Error())
+ iToken.SetError(KErrArgument);
+ return 0;
+ }
+
+TSqlTokenType TSqlParser::SqlErrorL()
+//
+// Report a SQL syntax error
+//
+ {
+ return TSqlTokenType(__LEAVE_IF_ERROR(KErrArgument));
+ }
+
+TSqlTokenType TSqlParser::Parse(TSqlKeyword aKeyword)
+//
+// look for requested keyword, skip to the next token if found
+// return the next token if found, else ESqlNoToken (==0)
+//
+ {
+ return TSqlLexer::IsKeyword(aKeyword,iToken) ? NextToken() : ESqlNoToken;
+ }
+
+TSqlTokenType TSqlParser::ParseL(TSqlTokenType aToken)
+//
+// parse the desired token
+//
+ {
+ return iToken!=aToken ? SqlErrorL() : NextToken();
+ }
+
+TSqlTokenType TSqlParser::ParseL(TSqlKeyword aKeyword)
+//
+// parse the desired keyword
+//
+ {
+ TSqlTokenType t=Parse(aKeyword);
+ return t==ESqlNoToken ? SqlErrorL() : t;
+ }
+
+TSqlKeyword TSqlParser::Keyword()
+//
+// parse a keyword
+//
+ {
+ TSqlKeyword k=TSqlLexer::Keyword(iToken);
+ if (k!=ESqlNotKeyword)
+ NextToken();
+ return k;
+ }
+
+TSqlTokenType TSqlParser::RightBracketL()
+//
+// parse a right bracket, and fail if not found
+//
+ {
+ return ParseL(ESqlRightBracket);
+ }
+
+void TSqlParser::EndL()
+//
+// Check that the SQL has been fully parsed
+//
+ {
+ if (iToken!=ESqlEos)
+ SqlErrorL();
+ }
+
+TSqlTokenType TSqlParser::IdentifierL(TPtrC& aIdentifier)
+//
+// parse an identifer, fail if not found
+//
+ {
+ if (iToken!=ESqlIdentifier)
+ return SqlErrorL();
+ const TText* p=iToken.Literal().Ptr();
+ TInt len=iToken.Literal().End()-p;
+ aIdentifier.Set(p,len);
+ return NextToken();
+ }
+
+TPtrC TSqlParser::IdentifierL()
+//
+// parse an identifer, fail if not found
+//
+ {
+ if (iToken!=ESqlIdentifier)
+ SqlErrorL();
+ return iToken.Literal().DesC();
+ }
+
+TSqlTokenType TSqlParser::ColumnNameL(RSqlColumnList& aList)
+//
+// Parse a column-identifier
+//
+ {
+ __LEAVE_IF_ERROR(aList.Append(IdentifierL()));
+ return NextToken();
+ }
+
+TSqlTokenType TSqlParser::ColumnListL(RSqlColumnList& aList)
+//
+// Parse a column-identifier-comma-list
+//
+ {
+ for (;;)
+ {
+ TSqlTokenType t=ColumnNameL(aList);
+ if (t!=ESqlComma)
+ return t;
+ NextToken();
+ }
+ }
+
+TSqlTokenType TSqlParser::AddColumnSpecL(TDbCol& aDef)
+//
+// Parse an add-column-spec
+//
+ {
+ aDef.iAttributes=0;
+ aDef.iName=IdentifierL();
+ NextToken();
+//
+ TDbColType type;
+ switch (Keyword())
+ {
+ case ESqlKeyword_bit:
+ type=EDbColBit;
+ break;
+ case ESqlKeyword_tinyint:
+ type=EDbColInt8;
+ break;
+ case ESqlKeyword_smallint:
+ type=EDbColInt16;
+ break;
+ case ESqlKeyword_integer:
+ type=EDbColInt32;
+ break;
+ case ESqlKeyword_counter:
+ aDef.iAttributes=aDef.EAutoIncrement;
+ type=EDbColUint32;
+ break;
+ case ESqlKeyword_bigint:
+ type=EDbColInt64;
+ break;
+ case ESqlKeyword_real:
+ type=EDbColReal32;
+ break;
+ case ESqlKeyword_double:
+ //Return value is intentionaly not checked. Parse() checks for
+ //an optional SQL keyword and calls internal checks.
+ //coverity[check_return]
+ //coverity[unchecked_value]
+ Parse(ESqlKeyword_precision);
+ // fall through
+ case ESqlKeyword_float:
+ type=EDbColReal64;
+ break;
+ case ESqlKeyword_date:
+ case ESqlKeyword_time:
+ case ESqlKeyword_timestamp:
+ type=EDbColDateTime;
+ break;
+ case ESqlKeyword_char:
+ case ESqlKeyword_varchar:
+ type=EDbColText;
+ break;
+ case ESqlKeyword_binary:
+ case ESqlKeyword_varbinary:
+ type=EDbColBinary;
+ break;
+ case ESqlKeyword_unsigned: // unsigned tinyint, smallint or integer
+ switch (Keyword())
+ {
+ case ESqlKeyword_tinyint:
+ type=EDbColUint8;
+ break;
+ case ESqlKeyword_smallint:
+ type=EDbColUint16;
+ break;
+ case ESqlKeyword_integer:
+ type=EDbColUint32;
+ break;
+ default:
+ return SqlErrorL();
+ };
+ break;
+ case ESqlKeyword_long: // varchar or varbinary
+ switch (Keyword())
+ {
+ case ESqlKeyword_varchar:
+ type=EDbColLongText;
+ break;
+ case ESqlKeyword_varbinary:
+ type=EDbColLongBinary;
+ break;
+ default:
+ return SqlErrorL();
+ };
+ break;
+ default:
+ return SqlErrorL();
+ }
+ aDef.iType=type;
+//
+// get any optional length
+ aDef.iMaxLength=KDbUndefinedLength;
+ TSqlTokenType t=iToken.Type();
+ switch (type)
+ {
+ case EDbColText:
+ case EDbColBinary:
+ if (t==ESqlLeftBracket)
+ {
+ if (NextToken()==ESqlLiteralInt)
+ {
+ iToken.Literal().ToInt32L();
+ aDef.iMaxLength=iToken.Literal().Int32();
+ NextToken();
+ t=RightBracketL();
+ }
+ else
+ return SqlErrorL();
+ }
+ break;
+ default:
+ break;
+ }
+ return t;
+ }
+
+CSqlSearchCondition* TSqlParser::SearchCondition(TInt aNot)
+//
+// Parse a search-condition
+//
+ {
+ CSqlSearchCondition* left=BooleanTerm(aNot);
+ if (left==0 || Parse(ESqlKeyword_or)==ESqlNoToken)
+ return left;
+ return CSqlMultiNode::New(aNot ? CSqlMultiNode::EAnd : CSqlMultiNode::EOr,left,SearchCondition(aNot));
+ }
+
+CSqlSearchCondition* TSqlParser::BooleanTerm(TInt aNot)
+//
+// Parse a boolean-term
+//
+ {
+ CSqlSearchCondition* left=BooleanFactor(aNot);
+ if (left==0 || Parse(ESqlKeyword_and)==ESqlNoToken)
+ return left;
+ return CSqlMultiNode::New(aNot ? CSqlMultiNode::EOr : CSqlMultiNode::EAnd,left,BooleanTerm(aNot));
+ }
+
+CSqlSearchCondition* TSqlParser::BooleanFactor(TInt aNot)
+//
+// Parse a boolean-factor
+//
+ {
+ while (Parse(ESqlKeyword_not))
+ aNot=~aNot;
+ return BooleanPrimary(aNot);
+ }
+
+CSqlSearchCondition* TSqlParser::BooleanPrimary(TInt aNot)
+//
+// Parse a boolean-factor
+//
+ {
+ // brackets only allowed in this element, so this ordering is valid
+ if (iToken!=ESqlLeftBracket)
+ return Predicate(aNot);
+ // bracketed search condition
+ NextToken();
+ CSqlSearchCondition* node=SearchCondition(aNot);
+ if (!node)
+ return node;
+ if (iToken==ESqlRightBracket)
+ {
+ NextToken();
+ return node;
+ }
+ delete node;
+ return SqlError();
+ }
+
+CSqlSearchCondition* TSqlParser::Predicate(TInt aNot)
+//
+// Parse predicate
+// On null return, error will already be set
+//
+ {
+ if (iToken!=ESqlIdentifier) // column name
+ return SqlError();
+ TPtrC column(iToken.Literal().DesC());
+ TSqlTokenType t=NextToken();
+ if (t==ESqlIdentifier)
+ { // like-predicate or null-predicate
+ switch (Keyword())
+ {
+ case ESqlKeyword_is: // IS [NOT] NULL
+ if (Parse(ESqlKeyword_not))
+ aNot=~aNot;
+ if (Parse(ESqlKeyword_null)==ESqlNoToken)
+ return SqlError();
+ return new CSqlNullPredicate(aNot ? CSqlNullPredicate::EIsNotNull : CSqlNullPredicate::EIsNull,column);
+ case ESqlKeyword_not: // NOT LIKE
+ if (Parse(ESqlKeyword_like)==ESqlNoToken)
+ return SqlError();
+ aNot=~aNot;
+ // drop through to Like
+ case ESqlKeyword_like: // LIKE
+ {
+ if (iToken!=ESqlLiteralText)
+ return SqlError();
+
+ //Following code is for the implementation of limited-ESCAPE-clause
+ const TText *next = iSql.Next(); //remember thecurrent position in the SQL statement
+ RSqlLiteral pattern = iToken.Literal(); //this is the LIKE pattern, remember it, because the next keyword might be ESCAPE
+
+ NextToken(); // Searching for ESCAPE keyword
+
+ if (Keyword() == ESqlKeyword_escape)
+ {
+ if (pattern.DesC().Length() <= 0 || pattern.DesC().Length() > (KMaxSegmentLength + 2 ))
+ return SqlError();
+ TPtrC escapeChar(iToken.Literal().DesC());
+ if (escapeChar.Length() <= 0)
+ return SqlError();
+ TChar escchar = escapeChar[0];
+ TText newPattern[KMaxSegmentLength + 2]; // '*' can come as first and last char
+ TInt count = PatternFilter(pattern.DesC(),escchar, newPattern);//remove the escape characters from the pattern and store it in "newPattern" variable
+ if (count <=0 )
+ return SqlError();
+ iToken.Literal().SetText(newPattern,(newPattern + count));
+ // copy the text to RSqlLiteral as "newPattern" is stack based variable and will go out of scope
+ if (iToken.Literal().CopyText() != KErrNone)
+ {
+ return SqlError();
+ }
+ CSqlSearchCondition* node = new CSqlLikePredicate(aNot ? CSqlLikePredicate::ENotLike : CSqlLikePredicate::ELike,column,iToken.Literal());
+ //cleanup iToken.Literal(), because if there is another LIKE predicate, the allocated by CopyText() buffer will
+ //be shared between two RSqlLiteral instances and RSqlLiteral::Close() call will crash.
+ //RSqlLiteral::RSqlLiteral() will set the "iBuffer" data member to NULL.
+ iToken.Literal() = RSqlLiteral();
+ if (node)
+ {
+ NextToken();
+ node->iIsEscape = ETrue;
+ }
+ return node;
+ }
+ else
+ {
+ //Set to the previous node
+ iSql.Set(next);
+ CSqlSearchCondition* node = new CSqlLikePredicate(aNot ? CSqlLikePredicate::ENotLike : CSqlLikePredicate::ELike,column,pattern);
+ if(node)
+ NextToken();
+ return node;
+
+ }
+ }
+ default:
+ return SqlError();
+ }
+ }
+ // Comparison predicate...
+ CSqlSearchCondition::TType op;
+ switch (t)
+ {
+ case ESqlGreaterEqual:
+ aNot=~aNot;
+ // drop through to less
+ case ESqlLess:
+ op=aNot ? CSqlSearchCondition::EGreaterEqual : CSqlSearchCondition::ELess;
+ break;
+ case ESqlGreater:
+ aNot=~aNot;
+ // drop through to less equal
+ case ESqlLessEqual:
+ op=aNot ? CSqlSearchCondition::EGreater: CSqlSearchCondition::ELessEqual;
+ break;
+ case ESqlNotEqual:
+ aNot=~aNot;
+ // drop through to equal
+ case ESqlEqual:
+ op=aNot ? CSqlSearchCondition::ENotEqual : CSqlSearchCondition::EEqual;
+ break;
+ default:
+ return SqlError();
+ }
+ t=NextToken();
+ if (t!=ESqlLiteralInt && t!=ESqlLiteralReal && t!=ESqlLiteralTime && t!=ESqlLiteralText)
+ return SqlError();
+ CSqlSearchCondition* node=new CSqlCompPredicate(op,column,iToken.Literal());
+ if (node)
+ NextToken();
+ return node;
+ }
+
+CSqlSearchCondition* TSqlParser::SearchConditionL()
+//
+// Parse a search-condition
+//
+ {
+ CSqlSearchCondition* sc=SearchCondition(0);
+ if (!sc)
+ {
+ __LEAVE_IF_ERROR(Error()); // syntax error
+ User::LeaveNoMemory(); // otherwise a OOM error
+ }
+ return sc;
+ }
+
+void TSqlParser::SortSpecificationL(CDbKey& aKey)
+//
+// Parse a sort-specification
+//
+ {
+ for (;;)
+ {
+ TDbKeyCol col(IdentifierL());
+ NextToken();
+ if (Parse(ESqlKeyword_desc))
+ col.iOrder=col.EDesc;
+ else
+ {
+ //Return value is intentionaly not checked. Parse() checks for
+ //an optional SQL keyword and calls internal checks.
+ //coverity[check_return]
+ //coverity[unchecked_value]
+ Parse(ESqlKeyword_asc);
+ col.iOrder=col.EAsc;
+ }
+ aKey.AddL(col);
+ if (iToken!=ESqlComma)
+ break;
+ NextToken();
+ }
+ }
+
+CSqlQuery* TSqlParser::QueryLC()
+//
+// Generate a CSqlQuery
+//
+ {
+ CSqlQuery* query=new(ELeave) CSqlQuery;
+ CleanupStack::PushL(query);
+ if (ParseL(ESqlKeyword_select)==ESqlAsterisk)
+ NextToken();
+ else
+ ColumnListL(query->iColumns);
+ ParseL(ESqlKeyword_from);
+ IdentifierL(query->iTable);
+ if (Parse(ESqlKeyword_where))
+ query->iSearchCondition=SearchConditionL();
+ if (Parse(ESqlKeyword_order))
+ {
+ ParseL(ESqlKeyword_by);
+ SortSpecificationL(query->SortSpecificationL());
+ }
+ EndL();
+ return query;
+ }
+
+CSqlSearchCondition* TSqlParser::SearchConditionLC()
+//
+// Parse a standalone search-condition
+//
+ {
+ CSqlSearchCondition* sc=SearchConditionL();
+ CleanupStack::PushL(sc);
+ EndL();
+ return sc;
+ }
+
+CSqlDDLStatement* TSqlParser::CreateTableLC()
+//
+// Parse a CREATE TABLE statement
+//
+ {
+ CSqlCreateTableStatement* statement=new(ELeave) CSqlCreateTableStatement;
+ CleanupStack::PushL(statement);
+ IdentifierL(statement->iName);
+ ParseL(ESqlLeftBracket);
+ TDbCol def;
+ for (;;)
+ {
+ AddColumnSpecL(def);
+ if (Parse(ESqlKeyword_not))
+ {
+ ParseL(ESqlKeyword_null);
+ def.iAttributes|=TDbCol::ENotNull;
+ }
+ statement->iColumns.AddL(def);
+ if (iToken!=ESqlComma)
+ break;
+ NextToken();
+ }
+ RightBracketL();
+ return statement;
+ }
+
+CSqlDDLStatement* TSqlParser::DropTableLC()
+//
+// Parse a DROP TABLE statement
+//
+ {
+ CSqlDropTableStatement* statement=new(ELeave) CSqlDropTableStatement;
+ CleanupStack::PushL(statement);
+ IdentifierL(statement->iName);
+ return statement;
+ }
+
+CSqlDDLStatement* TSqlParser::AlterTableLC()
+//
+// Parse a CREATE TABLE statement
+//
+ {
+ CSqlAlterTableStatement* statement=new(ELeave) CSqlAlterTableStatement;
+ CleanupStack::PushL(statement);
+ IdentifierL(statement->iName);
+ TSqlTokenType t=Parse(ESqlKeyword_add);
+ if (t!=ESqlNoToken)
+ {
+ TDbCol def;
+ if (t==ESqlLeftBracket)
+ {
+ NextToken();
+ for (;;)
+ {
+ t=AddColumnSpecL(def);
+ statement->iAdd.AddL(def);
+ if (t!=ESqlComma)
+ break;
+ NextToken();
+ }
+ RightBracketL();
+ }
+ else
+ {
+ AddColumnSpecL(def);
+ statement->iAdd.AddL(def);
+ }
+ }
+ t=Parse(ESqlKeyword_drop);
+ if (t!=ESqlNoToken)
+ {
+ if (t!=ESqlLeftBracket)
+ ColumnNameL(statement->iDrop);
+ else
+ {
+ NextToken();
+ ColumnListL(statement->iDrop);
+ RightBracketL();
+ }
+ }
+ return statement;
+ }
+
+CSqlDDLStatement* TSqlParser::CreateIndexLC(TBool aUnique)
+//
+// Parse a CREATE INDEX statement
+//
+ {
+ CSqlCreateIndexStatement* statement=new(ELeave) CSqlCreateIndexStatement;
+ CleanupStack::PushL(statement);
+ if (aUnique)
+ statement->iKey.MakeUnique();
+ IdentifierL(statement->iName);
+ ParseL(ESqlKeyword_on);
+ IdentifierL(statement->iTable);
+ ParseL(ESqlLeftBracket);
+ SortSpecificationL(statement->iKey);
+ RightBracketL();
+ return statement;
+ }
+
+CSqlDDLStatement* TSqlParser::DropIndexLC()
+//
+// Parse a DROP INDEX statement
+//
+ {
+ CSqlDropIndexStatement* statement=new(ELeave) CSqlDropIndexStatement;
+ CleanupStack::PushL(statement);
+ IdentifierL(statement->iName);
+ ParseL(ESqlKeyword_from);
+ IdentifierL(statement->iTable);
+ return statement;
+ }
+
+CSqlDDLStatement* TSqlParser::DDLStatementLC()
+ {
+ CSqlDDLStatement* statement;
+ if (Parse(ESqlKeyword_create))
+ {
+ if (Parse(ESqlKeyword_table))
+ statement=CreateTableLC();
+ else
+ {
+ TSqlTokenType unique=Parse(ESqlKeyword_unique);
+ ParseL(ESqlKeyword_index);
+ statement=CreateIndexLC(unique);
+ }
+ }
+ else if (Parse(ESqlKeyword_drop))
+ {
+ if (Parse(ESqlKeyword_table))
+ statement=DropTableLC();
+ else
+ {
+ ParseL(ESqlKeyword_index);
+ statement=DropIndexLC();
+ }
+ }
+ else
+ {
+ ParseL(ESqlKeyword_alter);
+ ParseL(ESqlKeyword_table);
+ statement=AlterTableLC();
+ }
+ EndL();
+ return statement;
+ }
+
+TSqlTokenType TSqlParser::ColumnValueL(CSqlValues& aValues)
+//
+// parse a column-value and add to aValues
+//
+ {
+ switch (iToken.Type())
+ {
+ case ESqlLiteralInt:
+ case ESqlLiteralReal:
+ case ESqlLiteralTime:
+ case ESqlLiteralText:
+ aValues.AddL(iToken.Literal());
+ return NextToken();
+ case ESqlIdentifier: // NULL
+ {
+ TSqlTokenType t=ParseL(ESqlKeyword_null);
+ aValues.AddL(RSqlLiteral()); // default c'ted RSqlLiteral is null
+ return t;
+ }
+ default: // SQL error
+ return SqlErrorL();
+ }
+ }
+
+CSqlDMLStatement* TSqlParser::InsertStatementLC()
+//
+// parse an insert-statement
+//
+ {
+ ParseL(ESqlKeyword_into);
+ CSqlInsertStatement* statement=CSqlInsertStatement::NewLC();
+ if (IdentifierL(statement->iQuery.iTable)==ESqlLeftBracket)
+ {
+ NextToken();
+ ColumnListL(statement->iQuery.iColumns);
+ RightBracketL();
+ }
+ ParseL(ESqlKeyword_values);
+ ParseL(ESqlLeftBracket);
+ CSqlValues& values=statement->ValuesL();
+ while (ColumnValueL(values)==ESqlComma)
+ NextToken();
+ RightBracketL();
+ return statement;
+ }
+
+CSqlDMLStatement* TSqlParser::UpdateStatementLC()
+//
+// parse an update-statement
+//
+ {
+ CSqlModifyStatement* statement=CSqlModifyStatement::NewLC();
+ IdentifierL(statement->iQuery.iTable);
+ ParseL(ESqlKeyword_set);
+ CSqlValues& values=statement->ValuesL();
+ for (;;)
+ {
+ ColumnNameL(statement->iQuery.iColumns);
+ ParseL(ESqlEqual);
+ if (ColumnValueL(values)!=ESqlComma)
+ break;
+ NextToken();
+ }
+ if (Parse(ESqlKeyword_where))
+ statement->iQuery.iSearchCondition=SearchConditionL();
+ return statement;
+ }
+
+CSqlDMLStatement* TSqlParser::DeleteStatementLC()
+//
+// parse a delete-statement
+//
+ {
+ ParseL(ESqlKeyword_from);
+ CSqlModifyStatement* statement=CSqlModifyStatement::NewLC();
+ IdentifierL(statement->iQuery.iTable);
+ if (Parse(ESqlKeyword_where))
+ statement->iQuery.iSearchCondition=SearchConditionL();
+ return statement;
+ }
+
+CSqlDMLStatement* TSqlParser::DMLStatementLC()
+ {
+ CSqlDMLStatement* statement;
+ if (Parse(ESqlKeyword_insert))
+ statement=InsertStatementLC();
+ else if (Parse(ESqlKeyword_update))
+ statement=UpdateStatementLC();
+ else
+ {
+ ParseL(ESqlKeyword_delete);
+ statement=DeleteStatementLC();
+ }
+ EndL();
+ return statement;
+ }
+
+Sql::TStatementType TSqlParser::Type()
+ {
+ TSqlKeyword k=TSqlLexer::Keyword(iToken);
+ if (k==ESqlKeyword_create || k==ESqlKeyword_alter || k==ESqlKeyword_drop)
+ return Sql::EDDL;
+ if (k==ESqlKeyword_insert || k==ESqlKeyword_update || k==ESqlKeyword_delete)
+ return Sql::EDML;
+ return Sql::ENone;
+ }
+
+TInt TSqlParser::PatternFilter(const TDesC& aPattern,const TChar aEscape,TText *aNewPatternBuffer )
+ {
+ TInt length = aPattern.Length();
+ TInt count =0;
+
+ // Ensure that the pattern begins and ends with an '*'
+ if ((length < 2) || (aPattern[0] != KMatchAny || aPattern[length-1] != KMatchAny))
+ {
+ return KSqlError;
+ }
+
+ for (TInt i = 1 ; i< length -1 ;++i)
+ {
+ if (aPattern[i]== (TUint)aEscape)
+ {
+ if ((aPattern[i + 1] == KMatchAny) || (aPattern[i + 1] == KMatchOne) || (aPattern[i + 1] == (TUint)aEscape))
+ {
+ i++;
+ aNewPatternBuffer[count++] = aPattern[i];
+ }
+ else
+ {
+ return KSqlError;
+ }
+ }
+ else
+ {
+ if ((aPattern[i] == KMatchAny || aPattern[i] == KMatchOne) )
+ {
+ return KSqlError;
+ }
+ else
+ {
+ aNewPatternBuffer[count++] = aPattern[i];
+ }
+ }
+ }
+
+ return count;
+ }