persistentstorage/dbms/usql/UQ_PARSE.CPP
changeset 0 08ec8eefde2f
--- /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;
+	}