First public contribution.
1 // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
19 #include "D32Assert.h"
23 const TInt KSqlError = -1;
25 TSqlParser::TSqlParser(const TDesC& aSql)
28 NextToken(); // parse the first token
31 TSqlTokenType TSqlParser::NextToken()
33 return iSql.NextToken(iToken);
36 CSqlSearchCondition* TSqlParser::SqlError()
39 iToken.SetError(KErrArgument);
43 TSqlTokenType TSqlParser::SqlErrorL()
45 // Report a SQL syntax error
48 return TSqlTokenType(__LEAVE_IF_ERROR(KErrArgument));
51 TSqlTokenType TSqlParser::Parse(TSqlKeyword aKeyword)
53 // look for requested keyword, skip to the next token if found
54 // return the next token if found, else ESqlNoToken (==0)
57 return TSqlLexer::IsKeyword(aKeyword,iToken) ? NextToken() : ESqlNoToken;
60 TSqlTokenType TSqlParser::ParseL(TSqlTokenType aToken)
62 // parse the desired token
65 return iToken!=aToken ? SqlErrorL() : NextToken();
68 TSqlTokenType TSqlParser::ParseL(TSqlKeyword aKeyword)
70 // parse the desired keyword
73 TSqlTokenType t=Parse(aKeyword);
74 return t==ESqlNoToken ? SqlErrorL() : t;
77 TSqlKeyword TSqlParser::Keyword()
82 TSqlKeyword k=TSqlLexer::Keyword(iToken);
83 if (k!=ESqlNotKeyword)
88 TSqlTokenType TSqlParser::RightBracketL()
90 // parse a right bracket, and fail if not found
93 return ParseL(ESqlRightBracket);
96 void TSqlParser::EndL()
98 // Check that the SQL has been fully parsed
105 TSqlTokenType TSqlParser::IdentifierL(TPtrC& aIdentifier)
107 // parse an identifer, fail if not found
110 if (iToken!=ESqlIdentifier)
112 const TText* p=iToken.Literal().Ptr();
113 TInt len=iToken.Literal().End()-p;
114 aIdentifier.Set(p,len);
118 TPtrC TSqlParser::IdentifierL()
120 // parse an identifer, fail if not found
123 if (iToken!=ESqlIdentifier)
125 return iToken.Literal().DesC();
128 TSqlTokenType TSqlParser::ColumnNameL(RSqlColumnList& aList)
130 // Parse a column-identifier
133 __LEAVE_IF_ERROR(aList.Append(IdentifierL()));
137 TSqlTokenType TSqlParser::ColumnListL(RSqlColumnList& aList)
139 // Parse a column-identifier-comma-list
144 TSqlTokenType t=ColumnNameL(aList);
151 TSqlTokenType TSqlParser::AddColumnSpecL(TDbCol& aDef)
153 // Parse an add-column-spec
157 aDef.iName=IdentifierL();
163 case ESqlKeyword_bit:
166 case ESqlKeyword_tinyint:
169 case ESqlKeyword_smallint:
172 case ESqlKeyword_integer:
175 case ESqlKeyword_counter:
176 aDef.iAttributes=aDef.EAutoIncrement;
179 case ESqlKeyword_bigint:
182 case ESqlKeyword_real:
185 case ESqlKeyword_double:
186 Parse(ESqlKeyword_precision);
188 case ESqlKeyword_float:
191 case ESqlKeyword_date:
192 case ESqlKeyword_time:
193 case ESqlKeyword_timestamp:
196 case ESqlKeyword_char:
197 case ESqlKeyword_varchar:
200 case ESqlKeyword_char8:
201 case ESqlKeyword_varchar8:
204 case ESqlKeyword_binary:
205 case ESqlKeyword_varbinary:
208 case ESqlKeyword_unsigned: // unsigned tinyint, smallint or integer
211 case ESqlKeyword_tinyint:
214 case ESqlKeyword_smallint:
217 case ESqlKeyword_integer:
224 case ESqlKeyword_long: // varchar or varbinary
227 case ESqlKeyword_varchar8:
228 type=EDbColLongText8;
230 case ESqlKeyword_varchar:
233 case ESqlKeyword_varbinary:
234 type=EDbColLongBinary;
245 // get any optional length
246 aDef.iMaxLength=KDbUndefinedLength;
247 TSqlTokenType t=iToken.Type();
252 if (t==ESqlLeftBracket)
254 if (NextToken()==ESqlLiteralInt)
256 iToken.Literal().ToInt32L();
257 aDef.iMaxLength=iToken.Literal().Int32();
271 CSqlSearchCondition* TSqlParser::SearchCondition(TInt aNot)
273 // Parse a search-condition
276 CSqlSearchCondition* left=BooleanTerm(aNot);
277 if (left==0 || Parse(ESqlKeyword_or)==ESqlNoToken)
279 return CSqlMultiNode::New(aNot ? CSqlMultiNode::EAnd : CSqlMultiNode::EOr,left,SearchCondition(aNot));
282 CSqlSearchCondition* TSqlParser::BooleanTerm(TInt aNot)
284 // Parse a boolean-term
287 CSqlSearchCondition* left=BooleanFactor(aNot);
288 if (left==0 || Parse(ESqlKeyword_and)==ESqlNoToken)
290 return CSqlMultiNode::New(aNot ? CSqlMultiNode::EOr : CSqlMultiNode::EAnd,left,BooleanTerm(aNot));
293 CSqlSearchCondition* TSqlParser::BooleanFactor(TInt aNot)
295 // Parse a boolean-factor
298 while (Parse(ESqlKeyword_not))
300 return BooleanPrimary(aNot);
303 CSqlSearchCondition* TSqlParser::BooleanPrimary(TInt aNot)
305 // Parse a boolean-factor
308 // brackets only allowed in this element, so this ordering is valid
309 if (iToken!=ESqlLeftBracket)
310 return Predicate(aNot);
311 // bracketed search condition
313 CSqlSearchCondition* node=SearchCondition(aNot);
316 if (iToken==ESqlRightBracket)
325 CSqlSearchCondition* TSqlParser::Predicate(TInt aNot)
328 // On null return, error will already be set
331 if (iToken!=ESqlIdentifier) // column name
333 TPtrC column(iToken.Literal().DesC());
334 TSqlTokenType t=NextToken();
335 if (t==ESqlIdentifier)
336 { // like-predicate or null-predicate
339 case ESqlKeyword_is: // IS [NOT] NULL
340 if (Parse(ESqlKeyword_not))
342 if (Parse(ESqlKeyword_null)==ESqlNoToken)
344 return new CSqlNullPredicate(aNot ? CSqlNullPredicate::EIsNotNull : CSqlNullPredicate::EIsNull,column);
345 case ESqlKeyword_not: // NOT LIKE
346 if (Parse(ESqlKeyword_like)==ESqlNoToken)
349 // drop through to Like
350 case ESqlKeyword_like: // LIKE
352 if (iToken!=ESqlLiteralText)
355 //Following code is for the implementation of limited-ESCAPE-clause
356 const TText *next = iSql.Next();
357 TPtrC pattern(iToken.Literal().DesC());
358 RSqlLiteral tmp = iToken.Literal();
360 NextToken(); // Searching for ESCAPE Key word
362 if (Keyword() == ESqlKeyword_escape)
364 TInt length = pattern.Length();
365 if (length <= 0 || length > (KMaxSegmentLength + 2 ))
367 TPtrC escapeChar(iToken.Literal().DesC());
368 if (escapeChar.Length() <= 0)
370 TChar escchar = escapeChar[0];
371 TText newPattern[KMaxSegmentLength + 2]; // '*' can come as first and last char
372 TInt count = PatternFilter(pattern,escchar, newPattern);
375 iToken.Literal().SetText(newPattern,(newPattern + count));
376 // copy the text to RSqlLiteral as newpattern could go out of scope
377 if (iToken.Literal().CopyText() != KErrNone)
381 CSqlSearchCondition* node = new CSqlLikePredicate(aNot ? CSqlLikePredicate::ENotLike : CSqlLikePredicate::ELike,column,iToken.Literal());
385 node->iIsEscape = ETrue;
391 //Setto the previous node
393 CSqlSearchCondition* node = new CSqlLikePredicate(aNot ? CSqlLikePredicate::ENotLike : CSqlLikePredicate::ELike,column,tmp);
404 // Comparison predicate...
405 CSqlSearchCondition::TType op;
408 case ESqlGreaterEqual:
410 // drop through to less
412 op=aNot ? CSqlSearchCondition::EGreaterEqual : CSqlSearchCondition::ELess;
416 // drop through to less equal
418 op=aNot ? CSqlSearchCondition::EGreater: CSqlSearchCondition::ELessEqual;
422 // drop through to equal
424 op=aNot ? CSqlSearchCondition::ENotEqual : CSqlSearchCondition::EEqual;
430 if (t!=ESqlLiteralInt && t!=ESqlLiteralReal &&
431 t!=ESqlLiteralTime && t!=ESqlLiteralText &&
434 CSqlSearchCondition* node=new CSqlCompPredicate(op,column,iToken.Literal());
440 CSqlSearchCondition* TSqlParser::SearchConditionL()
442 // Parse a search-condition
445 CSqlSearchCondition* sc=SearchCondition(0);
448 __LEAVE_IF_ERROR(Error()); // syntax error
449 User::LeaveNoMemory(); // otherwise a OOM error
454 void TSqlParser::SortSpecificationL(CDbKey& aKey)
456 // Parse a sort-specification
461 TDbKeyCol col(IdentifierL());
463 if (Parse(ESqlKeyword_desc))
464 col.iOrder=col.EDesc;
467 Parse(ESqlKeyword_asc);
471 if (iToken!=ESqlComma)
477 CSqlQuery* TSqlParser::QueryLC()
479 // Generate a CSqlQuery
482 CSqlQuery* query=new(ELeave) CSqlQuery;
483 CleanupStack::PushL(query);
484 if (ParseL(ESqlKeyword_select)==ESqlAsterisk)
487 ColumnListL(query->iColumns);
488 ParseL(ESqlKeyword_from);
489 IdentifierL(query->iTable);
490 if (Parse(ESqlKeyword_where))
491 query->iSearchCondition=SearchConditionL();
492 if (Parse(ESqlKeyword_order))
494 ParseL(ESqlKeyword_by);
495 SortSpecificationL(query->SortSpecificationL());
501 CSqlSearchCondition* TSqlParser::SearchConditionLC()
503 // Parse a standalone search-condition
506 CSqlSearchCondition* sc=SearchConditionL();
507 CleanupStack::PushL(sc);
512 CSqlDDLStatement* TSqlParser::CreateTableLC()
514 // Parse a CREATE TABLE statement
517 CSqlCreateTableStatement* statement=new(ELeave) CSqlCreateTableStatement;
518 CleanupStack::PushL(statement);
519 IdentifierL(statement->iName);
520 ParseL(ESqlLeftBracket);
525 if (Parse(ESqlKeyword_not))
527 ParseL(ESqlKeyword_null);
528 def.iAttributes|=TDbCol::ENotNull;
530 if (Parse(ESqlKeyword_autoincrement))
532 def.iAttributes|=TDbCol::EAutoIncrement;
534 statement->iColumns.AddL(def);
535 if (iToken!=ESqlComma)
543 CSqlDDLStatement* TSqlParser::DropTableLC()
545 // Parse a DROP TABLE statement
548 CSqlDropTableStatement* statement=new(ELeave) CSqlDropTableStatement;
549 CleanupStack::PushL(statement);
550 IdentifierL(statement->iName);
554 CSqlDDLStatement* TSqlParser::AlterTableLC()
556 // Parse a CREATE TABLE statement
559 CSqlAlterTableStatement* statement=new(ELeave) CSqlAlterTableStatement;
560 CleanupStack::PushL(statement);
561 IdentifierL(statement->iName);
562 TSqlTokenType t=Parse(ESqlKeyword_add);
566 if (t==ESqlLeftBracket)
571 t=AddColumnSpecL(def);
572 statement->iAdd.AddL(def);
582 statement->iAdd.AddL(def);
585 t=Parse(ESqlKeyword_drop);
588 if (t!=ESqlLeftBracket)
589 ColumnNameL(statement->iDrop);
593 ColumnListL(statement->iDrop);
600 CSqlDDLStatement* TSqlParser::CreateIndexLC(TBool aUnique)
602 // Parse a CREATE INDEX statement
605 CSqlCreateIndexStatement* statement=new(ELeave) CSqlCreateIndexStatement;
606 CleanupStack::PushL(statement);
608 statement->iKey.MakeUnique();
609 IdentifierL(statement->iName);
610 ParseL(ESqlKeyword_on);
611 IdentifierL(statement->iTable);
612 ParseL(ESqlLeftBracket);
613 SortSpecificationL(statement->iKey);
615 statement->iKey.SetComparison(EDbCompareNormal);
616 TSqlTokenType collate=Parse(ESqlKeyword_collate);
617 if ( collate != ESqlNoToken )
619 TSqlTokenType normal=Parse(ESqlKeyword_normal);
620 if ( normal == ESqlNoToken )
622 TSqlTokenType collated=Parse(ESqlKeyword_collated);
623 if ( collated == ESqlNoToken )
625 TSqlTokenType folded=Parse(ESqlKeyword_folded);
626 if ( folded != ESqlNoToken)
628 statement->iKey.SetComparison(EDbCompareFolded);
633 statement->iKey.SetComparison(EDbCompareCollated);
640 CSqlDDLStatement* TSqlParser::DropIndexLC()
642 // Parse a DROP INDEX statement
645 CSqlDropIndexStatement* statement=new(ELeave) CSqlDropIndexStatement;
646 CleanupStack::PushL(statement);
647 IdentifierL(statement->iName);
648 ParseL(ESqlKeyword_from);
649 IdentifierL(statement->iTable);
653 CSqlDDLStatement* TSqlParser::DDLStatementLC()
655 CSqlDDLStatement* statement;
656 if (Parse(ESqlKeyword_create))
658 if (Parse(ESqlKeyword_table))
659 statement=CreateTableLC();
662 TSqlTokenType unique=Parse(ESqlKeyword_unique);
663 ParseL(ESqlKeyword_index);
664 statement=CreateIndexLC(unique);
667 else if (Parse(ESqlKeyword_drop))
669 if (Parse(ESqlKeyword_table))
670 statement=DropTableLC();
673 ParseL(ESqlKeyword_index);
674 statement=DropIndexLC();
679 ParseL(ESqlKeyword_alter);
680 ParseL(ESqlKeyword_table);
681 statement=AlterTableLC();
687 TSqlTokenType TSqlParser::ColumnValueL(CSqlValues& aValues)
689 // parse a column-value and add to aValues
692 switch (iToken.Type())
695 case ESqlLiteralReal:
696 case ESqlLiteralTime:
697 case ESqlLiteralText:
698 case ESqlLiteralBlob:
699 aValues.AddL(iToken.Literal());
701 case ESqlIdentifier: // NULL
703 TSqlTokenType t=ParseL(ESqlKeyword_null);
704 aValues.AddL(RSqlLiteral()); // default c'ted RSqlLiteral is null
707 default: // SQL error
712 CSqlDMLStatement* TSqlParser::InsertStatementLC()
714 // parse an insert-statement
717 ParseL(ESqlKeyword_into);
718 CSqlInsertStatement* statement=CSqlInsertStatement::NewLC();
719 if (IdentifierL(statement->iQuery.iTable)==ESqlLeftBracket)
722 ColumnListL(statement->iQuery.iColumns);
725 ParseL(ESqlKeyword_values);
726 ParseL(ESqlLeftBracket);
727 CSqlValues& values=statement->ValuesL();
728 while (ColumnValueL(values)==ESqlComma)
734 CSqlDMLStatement* TSqlParser::UpdateStatementLC()
736 // parse an update-statement
739 CSqlModifyStatement* statement=CSqlModifyStatement::NewLC();
740 IdentifierL(statement->iQuery.iTable);
741 ParseL(ESqlKeyword_set);
742 CSqlValues& values=statement->ValuesL();
745 ColumnNameL(statement->iQuery.iColumns);
747 if (ColumnValueL(values)!=ESqlComma)
751 if (Parse(ESqlKeyword_where))
752 statement->iQuery.iSearchCondition=SearchConditionL();
756 CSqlDMLStatement* TSqlParser::DeleteStatementLC()
758 // parse a delete-statement
761 ParseL(ESqlKeyword_from);
762 CSqlModifyStatement* statement=CSqlModifyStatement::NewLC();
763 IdentifierL(statement->iQuery.iTable);
764 if (Parse(ESqlKeyword_where))
765 statement->iQuery.iSearchCondition=SearchConditionL();
769 CSqlDMLStatement* TSqlParser::DMLStatementLC()
771 CSqlDMLStatement* statement;
772 if (Parse(ESqlKeyword_insert))
773 statement=InsertStatementLC();
774 else if (Parse(ESqlKeyword_update))
775 statement=UpdateStatementLC();
778 ParseL(ESqlKeyword_delete);
779 statement=DeleteStatementLC();
785 Sql::TStatementType TSqlParser::Type()
787 TSqlKeyword k=TSqlLexer::Keyword(iToken);
788 if (k==ESqlKeyword_create || k==ESqlKeyword_alter || k==ESqlKeyword_drop)
790 if (k==ESqlKeyword_insert || k==ESqlKeyword_update || k==ESqlKeyword_delete)
795 TInt TSqlParser::PatternFilter(const TDesC& aPattern,const TChar aEscape,TText *aNewPatternBuffer )
797 TInt length = aPattern.Length();
800 // Ensure that the pattern begins and ends with an '*'
801 if ((length < 2) || (aPattern[0] != KMatchAny || aPattern[length-1] != KMatchAny))
806 for (TInt i = 1 ; i< length -1 ;++i)
808 if (aPattern[i]== (TUint)aEscape)
810 if ((aPattern[i + 1] == KMatchAny) || (aPattern[i + 1] == KMatchOne) || (aPattern[i + 1] == (TUint)aEscape))
813 aNewPatternBuffer[count++] = aPattern[i];
822 if ((aPattern[i] == KMatchAny || aPattern[i] == KMatchOne) )
828 aNewPatternBuffer[count++] = aPattern[i];