--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/persistentstorage/dbms/tdbms/t_dbscript.cpp Fri Jan 22 11:06:30 2010 +0200
@@ -0,0 +1,1493 @@
+// 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:
+//
+
+#include <d32dbms.h>
+#include <f32file.h>
+#include <e32test.h>
+#include <e32math.h>
+#include <d32dbmsconstants.h>
+
+LOCAL_D RTest TheTest(_L("t_dbscript"));
+LOCAL_D CTrapCleanup* TheTrapCleanup;
+LOCAL_D RDbNamedDatabase TheDatabase;
+LOCAL_D RFs TheFs;
+LOCAL_D RDbView TheView;
+//
+const TPtrC KTestDatabase=_L("c:\\dbms-tst\\t_script.db");
+
+const TPtrC KRomScriptFile=_L("z:\\test\\t_script.txt");
+
+const TPtrC KOutputFile=_L("c:\\dbms-tst\\t_script.log");
+
+const TInt KTestCleanupStack=0x20;
+const TPtrC KDDLKeywords[]={_L("CREATE"),_L("DROP"),_L("ALTER")};
+const TPtrC KDMLKeywords[]={_L("INSERT"),_L("DELETE"),_L("UPDATE")};
+const TPtrC KQueryKeywords[]={_L("SELECT")};
+const TPtrC KScriptKeywords[]={_L("PRINT"),_L("ROWS"),_L("COMPARE"),_L("ERROR"),_L("!"),
+ _L("POPULATE"),_L("RESULTS"),_L("BUILD"),_L("QUERY"),
+ _L("NORMAL"),_L("FOLDED"),_L("COLLATED"),_L("START"),_L("STOP"),
+ _L("LOAD"),_L("ECHO"),_L("WINDOW"),_L("ACCESS")};
+const TPtrC KRowIdColName=_L("Rw");
+enum TKeyword {EPrint,ERows,ECompare,EError,EComment,EPopulate,EResults,EBuild,EQuery,ENormal,
+ EFolded,ECollated,EStart,EStop,ELoad,EEcho,EWindow,EAccess,ENumKeywords,EUnknown};
+//
+typedef TBuf<256> TScriptLine;
+typedef TBuf<256> TScriptToken;
+//
+#define ARRAY_SIZE(array) (sizeof(array)/sizeof(array[0]))
+
+class TScript;
+class TTimer
+ {
+public:
+ inline TTimer(TScript& aScript);
+ void Start(const TDesC& aDes);
+ void Stop(const TDesC& aDes);
+private:
+ TUint iTicks;
+ TScript& iScript;
+ };
+
+class TResults
+ {
+public:
+ inline TResults();
+public:
+ RDbView& iView;
+ TInt iError;
+ TInt iRows;
+ TInt iLineNo;
+ TScriptLine iLine;
+ };
+
+class TSqlStatement
+ {
+private:
+ enum TSqlType {EDML,EDDL,EQuery,EUnknown};
+public:
+ inline TSqlStatement(const TDesC& aSql,TResults& aResults);
+ TInt Execute(TDbTextComparison aTextComparison=EDbCompareNormal,
+ RDbRowSet::TAccess aAccess=RDbRowSet::EReadOnly,TBool aWindow=EFalse) const;
+private:
+ void ExecuteSql(TDbTextComparison aTextComparison) const;
+ void ExecuteQuery(RDbRowSet::TAccess aAccess,TBool aWindow) const;
+ TSqlType SqlType() const;
+private:
+ const TDesC& iSql;
+ TResults& iResults;
+ };
+
+class TScript
+ {
+public:
+ TScript();
+ ~TScript()
+ {
+ iFile.Close();
+ }
+ TInt ReadNextStatement();
+ void GetNextTokenFromStatement(TDes& aToken);
+ void GetNextTokenFromLine(TDes& aToken);
+ TPtrC Statement();
+ TInt IntValue();
+ void WriteLine(const TDesC& aLine);
+ void WriteError(const TDesC& aLine);
+ void WriteSqlError(const TResults& aResults,const TDesC& aLine);
+ void WriteComment(const TDesC& aLine);
+ TKeyword Keyword(const TDesC& aKeyword) const;
+ void ConsumeLine();
+ void ConsumeStatement();
+ inline TInt LineNo() const;
+private:
+ TInt ReadNextLine();
+ TInt AppendNextLine();
+ TBool IsStatement();
+private:
+ TFileText iInput;
+ TFileText iOutput;
+ TScriptLine iBuf;
+ TLex iStatement;
+ TLex iLine;
+ TInt iLineNo;
+ RFile iFile;
+ };
+
+class TScriptEngine
+ {
+public:
+ inline TScriptEngine();
+ void RunL();
+private:
+ void ExecuteL();
+ TInt ExecuteScriptL();
+ TInt ExecuteSql(const TDesC& aSql);
+ TInt ExecuteSql();
+ // keyword operations
+ void DoPrintL();
+ void DoComment();
+ void DoError();
+ void DoEcho();
+ void DoWindow();
+ void DoAccess();
+ void DoRows();
+ void DoCompareL();
+ void DoPopulate();
+ void DoResultsL();
+ void DoBuildTable();
+ void DoQuery();
+ void DoTextComparison(TKeyword aKeyword);
+ void DoStartTimer();
+ void DoStopTimer();
+ void DoLoadDb();
+ //
+ void PrintL(RDbRowSet& aRowSet);
+ void CompareL(RDbRowSet& aRowSet);
+ void CompareValues(RDbRowSet& aRowSet,TDbColNo ColNo,TDbColType aType,const TDesC& aToken);
+ void FatalError(const TDesC& aLine);
+ void FatalError();
+ void FatalSqlError(const TDesC& aLine);
+ void TestForNoError();
+private:
+ TScript iScript;
+ TResults iResults;
+ TDbTextComparison iTextComparison;
+ TTimer iTimer;
+ TBool iEcho;
+ TBool iWindow;
+ RDbRowSet::TAccess iAccess;
+
+ };
+
+//
+// class TTimer
+//
+
+inline TTimer::TTimer(TScript& aScript)
+ : iScript(aScript)
+ {}
+
+void TTimer::Start(const TDesC& aDes)
+ {
+ TScriptLine line;
+ line.Format(_L("%S: "),&aDes);
+ iScript.WriteLine(line);
+ iTicks=User::TickCount();
+ }
+
+void TTimer::Stop(const TDesC& aDes)
+ {
+ TScriptLine line;
+ line.Format(_L("%S: "),&aDes);
+#ifdef __EPOC32__
+#define TICK_TIME 15625
+#else
+#define TICK_TIME 100000
+#endif
+ TInt microSec=(User::TickCount()-iTicks)*TICK_TIME;
+ TUint sec=microSec/1000000;
+ TUint centi=(microSec/10000)-sec*100;
+ line.AppendFormat(_L("%u.%02us\n"),sec,centi);
+ iScript.WriteLine(line);
+ }
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+LOCAL_C void DeleteDataFile(const TDesC& aFullName)
+ {
+ RFs fsSession;
+ TInt err = fsSession.Connect();
+ if(err == KErrNone)
+ {
+ TEntry entry;
+ if(fsSession.Entry(aFullName, entry) == KErrNone)
+ {
+ RDebug::Print(_L("Deleting \"%S\" file.\n"), &aFullName);
+ err = fsSession.SetAtt(aFullName, 0, KEntryAttReadOnly);
+ if(err != KErrNone)
+ {
+ RDebug::Print(_L("Error %d changing \"%S\" file attributes.\n"), err, &aFullName);
+ }
+ err = fsSession.Delete(aFullName);
+ if(err != KErrNone)
+ {
+ RDebug::Print(_L("Error %d deleting \"%S\" file.\n"), err, &aFullName);
+ }
+ }
+ fsSession.Close();
+ }
+ else
+ {
+ RDebug::Print(_L("Error %d connecting file session. File: %S.\n"), err, &aFullName);
+ }
+ }
+
+///////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////
+//Tests macros and functions.
+//If (!aValue) then the test will be panicked, the test data files will be deleted.
+static void Check(TInt aValue, TInt aLine)
+ {
+ if(!aValue)
+ {
+ RDebug::Print(_L("*** Expression evaluated to false\r\n"));
+ DeleteDataFile(KTestDatabase);
+ DeleteDataFile(KOutputFile);
+ TheTest(EFalse, aLine);
+ }
+ }
+//If (aValue != aExpected) then the test will be panicked, the test data files will be deleted.
+static void Check(TInt aValue, TInt aExpected, TInt aLine)
+ {
+ if(aValue != aExpected)
+ {
+ RDebug::Print(_L("*** Expected error: %d, got: %d\r\n"), aExpected, aValue);
+ DeleteDataFile(KTestDatabase);
+ DeleteDataFile(KOutputFile);
+ TheTest(EFalse, aLine);
+ }
+ }
+//Use these to test conditions.
+#define TEST(arg) Check((arg), __LINE__)
+#define TEST2(aValue, aExpected) Check(aValue, aExpected, __LINE__)
+
+///////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////
+
+//
+// class TResults
+//
+
+inline TResults::TResults()
+ : iView(TheView),iError(KErrNone)
+ {}
+
+
+//
+// class TSqlStatement
+//
+
+inline TSqlStatement::TSqlStatement(const TDesC& aSql,TResults& aResults)
+ : iSql(aSql),iResults(aResults)
+ {}
+
+//
+// executes DML or DDL
+//
+void TSqlStatement::ExecuteSql(TDbTextComparison aTextComparison) const
+ {
+ TInt r=TheDatabase.Execute(iSql,aTextComparison);
+ if (r<0)
+ iResults.iError=r;
+ else
+ {
+ iResults.iError=KErrNone;
+ iResults.iRows=r;
+ }
+ }
+
+void TSqlStatement::ExecuteQuery(RDbRowSet::TAccess aAccess,TBool aWindow) const
+ {
+ iResults.iView.Close(); // discard any previous queries
+ TInt& err=iResults.iError;
+ if (aWindow)
+ err=iResults.iView.Prepare(TheDatabase,iSql,KDbUnlimitedWindow,aAccess);
+ else
+ err=iResults.iView.Prepare(TheDatabase,iSql,aAccess);
+ if (err==KErrNone)
+ err=iResults.iView.EvaluateAll();
+ }
+
+//
+// determines the type of sql statement by matching keywords
+//
+TSqlStatement::TSqlType TSqlStatement::SqlType() const
+ {
+ for (TUint i=0;i<ARRAY_SIZE(KDDLKeywords);++i)
+ {
+ if (iSql.FindF(KDDLKeywords[i])==0)
+ return EDDL;
+ }
+ for (TUint ii=0;ii<ARRAY_SIZE(KDMLKeywords);++ii)
+ {
+ if (iSql.FindF(KDMLKeywords[ii])==0)
+ return EDML;
+ }
+ for (TUint j=0;j<ARRAY_SIZE(KQueryKeywords);++j)
+ {
+ if (iSql.FindF(KQueryKeywords[j])==0)
+ return EQuery;
+ }
+ return EUnknown;
+ }
+
+//
+// executes the sql statement
+//
+TInt TSqlStatement::Execute(TDbTextComparison aTextComparison,RDbRowSet::TAccess aAccess,TBool aWindow) const
+ {
+ TInt r=KErrNone;
+ switch (SqlType())
+ {
+ case EDDL:
+ case EDML:
+ ExecuteSql(aTextComparison);
+ break;
+ case EQuery:
+ ExecuteQuery(aAccess,aWindow);
+ break;
+ case EUnknown:
+ default:
+ r=KErrNotFound;
+ break;
+ }
+ return r;
+ }
+
+
+//
+// class TScript
+//
+
+TScript::TScript()
+ : iLineNo(0)
+ {
+ TheTest.Printf(_L("---TScript::TScript(), Open the script file \"%S\"\r\n"), &KRomScriptFile);
+ RFile file;
+ TInt r=file.Open(TheFs, KRomScriptFile, EFileRead);
+ TEST2(r, KErrNone);
+ iInput.Set(file);
+ TheTest.Printf(_L("---TScript::TScript(), Create the file \"%S\"\r\n"), &KOutputFile);
+ TEST2(file.Replace(TheFs, KOutputFile, EFileWrite), KErrNone);
+ iOutput.Set(file);
+ iFile = file;
+ }
+
+inline TInt TScript::LineNo() const
+ {return iLineNo;}
+
+//
+// checks for keywords which possibly conform to the usual statement format (ie end in ';')
+//
+TBool TScript::IsStatement()
+ {
+ if (iLine.Remainder().Length()==0) // null statement
+ return ETrue;
+ TPtrC line=iLine.Remainder();
+ TKeyword keyword=Keyword(line);
+ switch (keyword)
+ {
+ case EPrint:
+ case ERows:
+ case EBuild:
+ case EError:
+ case EQuery:
+ case ENormal:
+ case EFolded:
+ case ECollated:
+ case EStart:
+ case EStop:
+ case ELoad:
+ case EEcho:
+ case EWindow:
+ case EAccess:
+ case EUnknown: // could be sql
+ return ETrue;
+ case EComment:
+ case EPopulate:
+ case ECompare:
+ case EResults:
+ iStatement=line; // not a statement, so make it the whole line
+ return EFalse;
+ default:
+ TEST(0);
+ return EFalse;
+ }
+ }
+
+//
+// reads the next non-blank statement or line
+//
+TInt TScript::ReadNextStatement()
+ {
+ TInt r=ReadNextLine();
+ if (r!=KErrNone || !IsStatement())
+ return r;
+ TChar c=0;
+ while (c!=';')
+ {
+ c=iLine.Get();
+ if (!c) // nothing left to read
+ {
+ r=AppendNextLine();
+ if (r!=KErrNone)
+ return r;
+ }
+ }
+ iLine.UnGet(); // the semi-colon
+ iStatement=iLine.MarkedToken();
+ iLine.Get(); // the semi-colon
+ iLine.SkipSpaceAndMark();
+ return KErrNone;
+ }
+
+TPtrC TScript::Statement()
+ {
+ return iStatement.Remainder();
+ }
+
+void TScript::ConsumeLine()
+ {
+ iLine=TPtrC();
+ iStatement=TPtrC();
+ }
+
+void TScript::ConsumeStatement()
+ {
+ iLine=iLine.Remainder();
+ iStatement=TPtrC();
+ }
+
+//
+// reads the next non-blank line into iLine
+//
+TInt TScript::ReadNextLine()
+ {
+ while (iLine.Remainder().Length()==0)
+ {
+ TInt r=iInput.Read(iBuf);
+ if (r!=KErrNone)
+ return r;
+ if (iBuf.Length()>0 && iBuf[0]==0xfeff) // unicode stream marker
+ iBuf.Delete(0,1);
+ iLineNo++;
+ iLine=iBuf;
+ iLine.SkipSpaceAndMark();
+ }
+ return KErrNone;
+ }
+
+//
+// adds next line from file to iLine
+//
+TInt TScript::AppendNextLine()
+ {
+ TScriptLine line;
+ do {
+ TInt r=iInput.Read(line);
+ if (r!=KErrNone)
+ return r;
+ iLineNo++;
+ } while (line.Length()==0);
+ iBuf=iLine.MarkedToken();
+ iBuf.Append(line);
+ iLine=iBuf;
+ return KErrNone;
+ }
+
+void TScript::WriteError(const TDesC& aLine)
+ {
+ TScriptLine line;
+ line.Format(_L("Error at line %d: %S\n"),iLineNo,&aLine);
+ WriteLine(line);
+ TheTest.Printf(line);
+ }
+
+void TScript::WriteSqlError(const TResults& aResults,const TDesC& aLine)
+ {
+ TScriptLine line;
+ line.Format(_L("Error at line %d: %S :-\n"),aResults.iLineNo,&aLine);
+ WriteLine(line);
+ TheTest.Printf(line);
+ line.Format(_L("\t%S\n"),&aResults.iLine);
+ WriteLine(line);
+ TheTest.Printf(line);
+ }
+
+void TScript::WriteLine(const TDesC& aLine)
+ {
+ TScriptLine l=aLine;
+ l.Append('\r');
+ iOutput.Write(l);
+ }
+
+void TScript::WriteComment(const TDesC& aLine)
+ {
+ TScriptLine line;
+ line.Format(_L("\n%S"),&aLine);
+ WriteLine(line);
+ }
+
+//
+// returns the integer n from the ' = n ' which must follow in the statement
+//
+TInt TScript::IntValue()
+ {
+ TScriptToken keyword;
+ GetNextTokenFromStatement(keyword);
+ if (keyword.Compare(_L("="))!=0)
+ WriteError(_L("expected '=' missing"));
+ iStatement.SkipSpaceAndMark();
+ TInt num=0;
+ TInt err=iStatement.Val(num);
+ if (err!=KErrNone)
+ WriteError(_L("expected number missing"));
+ return num;
+ }
+
+TKeyword TScript::Keyword(const TDesC& aKeyword) const
+ {
+ for (TInt ii=0; ii<ENumKeywords; ++ii)
+ {
+ if (aKeyword.FindF(KScriptKeywords[ii])==0)
+ return TKeyword(ii);
+ }
+ return EUnknown;
+ }
+
+//
+// gets the next token from iStatement
+//
+void TScript::GetNextTokenFromStatement(TDes& aToken)
+ {
+ iStatement.SkipSpaceAndMark();
+ TUint c;
+ do
+ {
+ c=iStatement.Get();
+ if (c=='=' || c=='!')
+ break;
+ } while (iStatement.Peek().IsAlphaDigit());
+ aToken=iStatement.MarkedToken();
+ iStatement.SkipSpaceAndMark();
+ }
+
+//
+// gets the next token from iLine
+//
+void TScript::GetNextTokenFromLine(TDes& aToken)
+ {
+ iLine.SkipSpaceAndMark();
+ TUint c=0;
+ TChar cc=c;
+ TBool literal=EFalse;
+ do
+ {
+ c=iLine.Get();
+ if (!c)
+ {
+ AppendNextLine();
+ iLine.SkipSpaceAndMark();
+ c=iLine.Get();
+ }
+ if (c=='\'' || c=='#')
+ literal=!literal;
+ if ((c==',' || c=='(' || c==')' || c=='{' || c=='}' || c=='!' ) && !literal)
+ break;
+ cc=iLine.Peek();
+ } while (cc.IsAlphaDigit() || literal || TUint(cc)=='.' || TUint(cc)=='+' || TUint(cc)=='-');
+ aToken=iLine.MarkedToken();
+ if (TUint(cc)==';') // ignore semi-colons - they're optional
+ iLine.Get();
+ iLine.SkipSpaceAndMark();
+ if (c=='!')
+ {
+ iStatement=iLine.Remainder();
+ TPtrC comment=iStatement.Remainder();
+ WriteComment(comment);
+ iLine=TPtrC();
+ GetNextTokenFromLine(aToken);
+ }
+ }
+
+
+//
+// class TScriptEngine
+//
+
+TScriptEngine::TScriptEngine()
+ : iTextComparison(EDbCompareNormal),iTimer(iScript),iEcho(EFalse),iWindow(EFalse),iAccess(RDbRowSet::EReadOnly)
+ {}
+
+
+//
+// runs the script file
+//
+void TScriptEngine::RunL()
+ {
+ while (iScript.ReadNextStatement()!=KErrEof)
+ ExecuteL();
+ TestForNoError();
+ }
+
+void TScriptEngine::TestForNoError()
+ {
+ if (iResults.iError!=KErrNone)
+ {
+ TScriptLine line;
+ line.Format(_L("unexpected error %d"),iResults.iError);
+ FatalSqlError(line);
+ }
+ }
+
+void TScriptEngine::ExecuteL()
+ {
+ if (ExecuteScriptL()!=KErrNone && ExecuteSql()!=KErrNone)
+ FatalSqlError(_L("syntax error"));
+ }
+
+TInt TScriptEngine::ExecuteScriptL()
+ {
+ TKeyword keyword=iScript.Keyword(iScript.Statement());
+ if (keyword!=EError)
+ TestForNoError();
+ switch (keyword)
+ {
+ case EPrint:
+ DoPrintL();
+ break;
+ case ERows:
+ DoRows();
+ break;
+ case ELoad:
+ DoLoadDb();
+ break;
+ case EEcho:
+ DoEcho();
+ break;
+ case EWindow:
+ DoWindow();
+ break;
+ case EAccess:
+ DoAccess();
+ break;
+ case ECompare:
+ DoCompareL();
+ break;
+ case EError:
+ DoError();
+ break;
+ case EPopulate:
+ DoPopulate();
+ break;
+ case EComment:
+ DoComment();
+ break;
+ case EResults:
+ DoResultsL();
+ break;
+ case EBuild:
+ DoBuildTable();
+ break;
+ case EQuery:
+ DoQuery();
+ break;
+ case ENormal:
+ case EFolded:
+ case ECollated:
+ DoTextComparison(keyword);
+ break;
+ case EStart:
+ DoStartTimer();
+ break;
+ case EStop:
+ DoStopTimer();
+ break;
+ case EUnknown:
+ default:
+ return KErrNotFound;
+ }
+ return KErrNone;
+ }
+
+TInt TScriptEngine::ExecuteSql()
+ {
+ return ExecuteSql(iScript.Statement());
+ }
+
+TInt TScriptEngine::ExecuteSql(const TDesC& aSql)
+ {
+ if (iEcho)
+ {
+ TScriptLine line(_L("\nSQL:\t"));
+ line.Append(aSql);
+ iScript.WriteLine(line);
+ }
+ iResults.iLineNo=iScript.LineNo();
+ iResults.iLine=aSql;
+ TSqlStatement statement(aSql,iResults);
+ return statement.Execute(iTextComparison,iAccess,iWindow);
+ }
+
+void TScriptEngine::DoStartTimer()
+ {
+ // test its right function
+ TScriptToken keyword;
+ iScript.GetNextTokenFromStatement(keyword);
+ TEST2(keyword.CompareF(_L("START")), 0);
+ iScript.GetNextTokenFromStatement(keyword);
+ TEST2(keyword.CompareF(_L("TIMER")), 0);
+ //
+ iTimer.Start(_L("Timer started"));
+ }
+
+void TScriptEngine::DoStopTimer()
+ {
+ // test its right function
+ TScriptToken keyword;
+ iScript.GetNextTokenFromStatement(keyword);
+ TEST2(keyword.CompareF(_L("STOP")), 0);
+ iScript.GetNextTokenFromStatement(keyword);
+ TEST2(keyword.CompareF(_L("TIMER")), 0);
+ //
+ iTimer.Stop(_L("Timer stopped"));
+ }
+
+void TScriptEngine::DoTextComparison(TKeyword aKeyword)
+ {
+ TPtrC line;
+ switch (aKeyword)
+ {
+ case ENormal:
+ iTextComparison=EDbCompareNormal;
+ line.Set(_L("[Normal text comparison]"));
+ break;
+ case EFolded:
+ iTextComparison=EDbCompareFolded;
+ line.Set(_L("[Folded text comparison]"));
+ break;
+ case ECollated:
+ iTextComparison=EDbCompareCollated;
+ line.Set(_L("[Collated text comparison]"));
+ break;
+ default:
+ TEST(0);
+ }
+ iScript.WriteLine(line);
+ }
+
+void TScriptEngine::DoComment()
+ {
+ // test its right function
+ TScriptToken keyword;
+ iScript.GetNextTokenFromStatement(keyword);
+ TEST2(keyword.CompareF(_L("!")), 0);
+ //
+ TPtrC comment=iScript.Statement();
+ iScript.WriteComment(comment);
+ iScript.ConsumeLine();
+ }
+
+void TScriptEngine::DoError()
+ {
+ // test its right function
+ TScriptToken keyword;
+ iScript.GetNextTokenFromStatement(keyword);
+ TEST2(keyword.CompareF(_L("ERROR")), 0);
+ //
+ TScriptLine line;
+ if (iScript.Statement().Length()==0)
+ {
+ if (iResults.iError>=0)
+ FatalSqlError(_L("no error when one was expected"));
+ line=_L("\t\tERROR OK");
+ }
+ else
+ {
+ TInt err=iScript.IntValue();
+ if (iResults.iError!=err)
+ {
+ line.Format(_L("expected error %d, actual error %d"),err,iResults.iError);
+ FatalSqlError(line);
+ }
+ line.Format(_L("\t\tERROR=%D OK"),err);
+ }
+ iResults.iError=0;
+ iScript.WriteLine(line);
+ }
+
+void TScriptEngine::DoRows()
+ {
+ // test its right function
+ TScriptToken keyword;
+ iScript.GetNextTokenFromStatement(keyword);
+ TEST2(keyword.CompareF(_L("ROWS")), 0);
+ //
+ TScriptLine line;
+ TInt rows=iScript.IntValue();
+ if (iResults.iRows!=rows)
+ {
+ line.Format(_L("expected rows %d, actual rows %d"),rows,iResults.iRows);
+ FatalSqlError(line);
+ }
+ line.Format(_L("\t\tROWS=%D OK"),rows);
+ iScript.WriteLine(line);
+ }
+
+void TScriptEngine::DoLoadDb()
+ {
+ // test its right function
+ TScriptToken token;
+ iScript.GetNextTokenFromStatement(token);
+ TEST2(token.CompareF(_L("LOAD")), 0);
+ //
+ TFileName database(iScript.Statement());
+ TheDatabase.Close();
+ TScriptLine line;
+ line.Format(_L("Opening database: %S"),&database);
+ iScript.WriteLine(line);
+ TEST2(TheDatabase.Open(TheFs,database), KErrNone);
+ }
+
+void TScriptEngine::DoEcho()
+ {
+ // test its right function
+ TScriptToken keyword;
+ iScript.GetNextTokenFromStatement(keyword);
+ TEST2(keyword.CompareF(_L("ECHO")), 0);
+ //
+ iScript.GetNextTokenFromStatement(keyword);
+ if (keyword.CompareF(_L("OFF"))==0)
+ {
+ iEcho=EFalse;
+ iScript.WriteLine(_L("Echo is off"));
+ }
+ else if (keyword.CompareF(_L("ON"))==0)
+ {
+ iEcho=ETrue;
+ iScript.WriteLine(_L("Echo is on"));
+ }
+ else
+ FatalError(_L("Expected ON|OFF to follow ECHO statement"));
+ }
+
+void TScriptEngine::DoWindow()
+ {
+ // test its right function
+ TScriptToken keyword;
+ iScript.GetNextTokenFromStatement(keyword);
+ TEST2(keyword.CompareF(_L("WINDOW")), 0);
+ //
+ iScript.GetNextTokenFromStatement(keyword);
+ if (keyword.CompareF(_L("OFF"))==0)
+ {
+ iWindow=EFalse;
+ iScript.WriteLine(_L("Window is off"));
+ }
+ else if (keyword.CompareF(_L("ON"))==0)
+ {
+ iWindow=ETrue;
+ iScript.WriteLine(_L("Window is on"));
+ }
+ else
+ FatalError(_L("Expected ON|OFF to follow WINDOW statement"));
+ }
+
+void TScriptEngine::DoAccess()
+ {
+ // test its right function
+ TScriptToken keyword;
+ iScript.GetNextTokenFromStatement(keyword);
+ TEST2(keyword.CompareF(_L("ACCESS")), 0);
+ //
+ iScript.GetNextTokenFromStatement(keyword);
+ if (keyword.CompareF(_L("UPDATE"))==0)
+ {
+ iAccess=RDbRowSet::EUpdatable;
+ iScript.WriteLine(_L("Access is updateable"));
+ }
+ else if (keyword.CompareF(_L("READ"))==0)
+ {
+ iAccess=RDbRowSet::EReadOnly;
+ iScript.WriteLine(_L("Access is read only"));
+ }
+ else if (keyword.CompareF(_L("INSERT"))==0)
+ {
+ iAccess=RDbRowSet::EInsertOnly;
+ iScript.WriteLine(_L("Access is insert only"));
+ }
+ else
+ FatalError(_L("Expected UPDATE|INSERT|READ to follow ACCESS statement"));
+ }
+
+void TScriptEngine::DoResultsL()
+ {
+ // test its right function
+ TScriptToken token;
+ iScript.GetNextTokenFromLine(token);
+ TEST2(token.CompareF(_L("RESULTS")), 0);
+ //
+ iScript.GetNextTokenFromLine(token);
+ if (token.Compare(_L("{"))!=0)
+ FatalError(_L("missing '{'"));
+ iScript.GetNextTokenFromLine(token); // first value
+ TLex value;
+ RDbRowSet& rowset=iResults.iView;
+ CDbColSet* colset=rowset.ColSetL();
+ CleanupStack::PushL(colset);
+ TDbColNo colno=colset->ColNo(KRowIdColName);
+ CArrayFixFlat<TInt>* rowIdScript=new CArrayFixFlat<TInt>(4);
+ CleanupStack::PushL(rowIdScript);
+ CArrayFixFlat<TInt>* rowIdView=new CArrayFixFlat<TInt>(4);
+ CleanupStack::PushL(rowIdView);
+ rowset.BeginningL();
+ while (rowset.NextL())
+ {
+ rowset.GetL();
+ TUint rIdScript;
+ value=token;
+ if (value.Val(rIdScript)!=KErrNone)
+ {
+ TScriptLine line;
+ line.Format(_L("Unable to extract row id from \"%S\""),&token);
+ FatalError(line);
+ }
+ TUint rIdView=rowset.ColUint(colno);
+ rowIdScript->AppendL(rIdScript);
+ rowIdView->AppendL(rIdView);
+ iScript.GetNextTokenFromLine(token);
+ if (token.Compare(_L(","))==0 || token.Compare(_L("}"))==0)
+ {
+ if (rowIdScript->Count())
+ {
+ TKeyArrayFix key(0,ECmpTInt);
+ rowIdScript->Sort(key);
+ rowIdView->Sort(key);
+ for (TInt ii=0;ii<rowIdScript->Count();++ii)
+ {
+ TInt expectedId=(*rowIdScript)[ii];
+ TInt actualId=(*rowIdView)[ii];
+ if (actualId!=expectedId)
+ {
+ TScriptLine line;
+ line.Format(_L("expected row id %d, actual row id %d"),actualId,expectedId);
+ FatalError(line);
+ }
+ }
+ rowIdScript->Reset();
+ rowIdView->Reset();
+ }
+ if (token.Compare(_L(","))==0)
+ iScript.GetNextTokenFromLine(token);
+ }
+ }
+ if (token.Compare(_L("}"))!=0)
+ FatalError(_L("too many results expected"));
+ CleanupStack::PopAndDestroy(3); // arrays + colset
+ iScript.ConsumeStatement();
+ }
+
+//
+// same as Sql create statement, but adds a counter
+//
+void TScriptEngine::DoBuildTable()
+ {
+ // test its right function
+ TScriptToken keyword;
+ iScript.GetNextTokenFromStatement(keyword);
+ TEST2(keyword.CompareF(_L("BUILD")), 0);
+ //
+ TScriptLine sql(_L("CREATE "));
+ sql.Append(iScript.Statement());
+ TInt pos=sql.Find(_L("("));
+ sql.Insert(++pos,_L("Rw COUNTER,"));
+ iScript.ConsumeStatement();
+ ExecuteSql(sql);
+ }
+
+//
+// same as Sql select statement, but makes sure counter is included
+//
+void TScriptEngine::DoQuery()
+ {
+ // test its right function
+ TScriptToken keyword;
+ iScript.GetNextTokenFromStatement(keyword);
+ TEST2(keyword.CompareF(_L("QUERY")), 0);
+ //
+ TScriptLine sql(iScript.Statement());
+ if (sql.Find(_L("*"))!=0)
+ {
+ sql.Insert(0,_L(","));
+ sql.Insert(0,KRowIdColName);
+ }
+ sql.Insert(0,_L("SELECT "));
+ iScript.ConsumeStatement();
+ ExecuteSql(sql);
+ }
+
+void TScriptEngine::FatalError(const TDesC& aLine)
+ {
+ iScript.WriteError(aLine);
+ TEST(0);
+ }
+
+void TScriptEngine::FatalError()
+ {
+ FatalError(_L("wrong expected value"));
+ }
+
+void TScriptEngine::FatalSqlError(const TDesC& aLine)
+ {
+ iScript.WriteSqlError(iResults,aLine);
+ TEST(0);
+ }
+
+void TScriptEngine::DoPopulate()
+ {
+ // check its right function
+ TScriptToken token;
+ iScript.GetNextTokenFromLine(token);
+ TEST2(token.CompareF(_L("POPULATE")), 0);
+ //
+ TScriptLine sqlbase=_L("INSERT INTO ");
+ iScript.GetNextTokenFromLine(token); // table name
+ sqlbase.AppendFormat(_L("%S "),&token);
+ iScript.GetNextTokenFromLine(token);
+ if (token.Compare(_L("("))==0) // optional column names present?
+ {
+ for (;;)
+ {
+ sqlbase.AppendFormat(token);
+ if (token.Compare(_L(")"))==0)
+ break;
+ iScript.GetNextTokenFromLine(token);
+ }
+ iScript.GetNextTokenFromLine(token);
+ }
+ if (token.Compare(_L("{"))!=0)
+ FatalError(_L("missing '{'"));
+ sqlbase.AppendFormat(_L(" VALUES ("));
+ iScript.GetNextTokenFromLine(token); // first value
+ TheDatabase.Begin(); // all in same transaction
+ for (;;)
+ {
+ if (token.Compare(_L("}"))==0)
+ break;
+ TScriptLine sql=sqlbase;
+ for (;;)
+ {
+ sql.Append(token);
+ iScript.GetNextTokenFromLine(token);
+ if (token.Compare(_L(","))==0)
+ {
+ sql.Append(token); // comma
+ iScript.GetNextTokenFromLine(token);
+ }
+ else
+ break;
+ }
+ sql.AppendFormat(_L(")"));
+ ExecuteSql(sql);
+ TestForNoError();
+ }
+ TheDatabase.Commit();
+ iScript.ConsumeStatement();
+ }
+
+void TScriptEngine::DoPrintL()
+ {
+ // check its right function
+ TScriptToken keyword;
+ iScript.GetNextTokenFromStatement(keyword);
+ TEST2(keyword.CompareF(_L("PRINT")), 0);
+ //
+ iScript.GetNextTokenFromStatement(keyword);
+ if (keyword.CompareF(_L("VIEW"))==0)
+ PrintL(iResults.iView);
+ else if (keyword.CompareF(_L("TABLE"))==0)
+ {
+ iScript.GetNextTokenFromStatement(keyword); // name of table
+ RDbTable table;
+ TInt err=table.Open(TheDatabase,keyword,table.EReadOnly);
+ if (err!=KErrNone)
+ FatalError(_L("unable to open table"));
+ PrintL(table);
+ table.Close();
+ }
+ else
+ FatalError(_L("expected VIEW or TABLE keyword not present"));
+ }
+
+void TScriptEngine::DoCompareL()
+ {
+ // check its right function
+ TScriptToken keyword;
+ iScript.GetNextTokenFromLine(keyword);
+ TEST2(keyword.CompareF(_L("COMPARE")), 0);
+ //
+ iScript.GetNextTokenFromLine(keyword);
+ if (keyword.CompareF(_L("VIEW"))==0)
+ CompareL(iResults.iView);
+ else if (keyword.CompareF(_L("TABLE"))==0)
+ {
+ iScript.GetNextTokenFromLine(keyword); // name of table
+ RDbTable table;
+ TInt err=table.Open(TheDatabase,keyword,table.EReadOnly);
+ if (err!=KErrNone)
+ FatalError(_L("unable to open table"));
+ CompareL(table);
+ table.Close();
+ }
+ else
+ FatalError(_L("expected VIEW or TABLE keyword not present"));
+ }
+
+void TScriptEngine::CompareL(RDbRowSet& aRowSet)
+ {
+ TScriptToken token;
+ iScript.GetNextTokenFromLine(token);
+ TBool rowIdMode=EFalse;
+ CArrayFixFlat<TInt>* rowIdToTest=new CArrayFixFlat<TInt>(4);
+ CleanupStack::PushL(rowIdToTest);
+ if (token.Compare(_L("("))==0) // optional row ids present?
+ {
+ rowIdMode=ETrue;
+ iScript.GetNextTokenFromLine(token); // first value
+ TLex value;
+ TInt rowId;
+ for (;;)
+ {
+ value=token;
+ TEST2(value.Val(rowId), KErrNone);
+ rowIdToTest->AppendL(rowId); // add row id to array
+ iScript.GetNextTokenFromLine(token);
+ if (token.Compare(_L(")"))==0)
+ break;
+ if (token.Compare(_L(","))==0)
+ iScript.GetNextTokenFromLine(token);
+ }
+ iScript.GetNextTokenFromLine(token);
+ }
+ if (token.Compare(_L("{"))!=0)
+ FatalError(_L("missing '{'"));
+ TInt columns=aRowSet.ColCount();
+ CDbColSet* colset=aRowSet.ColSetL();
+ aRowSet.BeginningL();
+ while (aRowSet.NextL())
+ {
+ aRowSet.GetL();
+ if (rowIdMode)
+ {
+ TInt currentId=aRowSet.ColUint(colset->ColNo(KRowIdColName));
+ TBool toTest=EFalse;
+ for (TInt jj=0; jj<rowIdToTest->Count(); ++jj)
+ {
+ if (currentId==(*rowIdToTest)[jj])
+ toTest=ETrue;
+ }
+ if (!toTest)
+ continue;
+ }
+ for (TInt ii=1;ii<=columns;++ii)
+ {
+ if (rowIdMode && ii==colset->ColNo(KRowIdColName)) // ignore row id column
+ continue;
+ const TDbCol& col=(*colset)[ii];
+ iScript.GetNextTokenFromLine(token); // value
+ if (token.Compare(_L(","))==0)
+ iScript.GetNextTokenFromLine(token); // ignore comma
+ if (aRowSet.IsColNull(ii))
+ {
+ if (token.CompareF(_L("NULL"))!=0)
+ FatalError(_L("NULL expected"));
+ continue;
+ }
+ CompareValues(aRowSet,ii,col.iType,token);
+ }
+ }
+ delete colset;
+ CleanupStack::PopAndDestroy(); // rowIdToTest
+ iScript.GetNextTokenFromLine(token); // look for closing '}'
+ if (token.Compare(_L("}"))!=0)
+ FatalError(_L("missing '}'"));
+ iScript.ConsumeStatement();
+ }
+
+//
+// compares the value from a rowset aRowset, colimn number aColNo and of type aType, with the value
+// contained in the descriptor aToken
+//
+void TScriptEngine::CompareValues(RDbRowSet& aRowSet,TDbColNo ColNo,TDbColType aType,const TDesC& aToken)
+ {
+ TLex value=aToken;
+ switch (aType)
+ {
+ case EDbColInt32:
+ {
+ TInt num;
+ TEST2(value.Val(num), KErrNone);
+ if (num!=aRowSet.ColInt(ColNo))
+ FatalError();
+ break;
+ }
+ case EDbColInt8:
+ {
+ TInt8 num8;
+ TEST2(value.Val(num8), KErrNone);
+ if (num8!=aRowSet.ColInt8(ColNo))
+ FatalError();
+ break;
+ }
+ case EDbColInt16:
+ {
+ TInt16 num16;
+ TEST2(value.Val(num16), KErrNone);
+ if (num16!=aRowSet.ColInt16(ColNo))
+ FatalError();
+ break;
+ }
+ case EDbColInt64:
+ {
+ TInt64 num64;
+ TEST2(value.Val(num64), KErrNone);
+ if (num64!=aRowSet.ColInt64(ColNo))
+ FatalError();
+ break;
+ }
+ case EDbColUint8:
+ {
+ TUint8 numu8;
+ TEST2(value.Val(numu8,EDecimal), KErrNone);
+ if (numu8!=aRowSet.ColUint8(ColNo))
+ FatalError();
+ break;
+ }
+ case EDbColUint16:
+ {
+ TUint16 numu16;
+ TEST2(value.Val(numu16,EDecimal), KErrNone);
+ if (numu16!=aRowSet.ColUint16(ColNo))
+ FatalError();
+ break;
+ }
+ case EDbColUint32:
+ {
+ TUint32 numu32;
+ TEST2(value.Val(numu32,EDecimal), KErrNone);
+ if (numu32!=aRowSet.ColUint32(ColNo))
+ FatalError();
+ break;
+ }
+ case EDbColReal32:
+ {
+ TReal32 numr32;
+ TEST2(value.Val(numr32), KErrNone);
+ if (numr32!=aRowSet.ColReal32(ColNo))
+ FatalError();
+ break;
+ }
+ case EDbColReal64:
+ {
+ TReal64 numr64;
+ TEST2(value.Val(numr64), KErrNone);
+ if (numr64!=aRowSet.ColReal64(ColNo))
+ FatalError();
+ break;
+ }
+ case EDbColText8:
+ case EDbColText16:
+ {
+ TPtrC text=aToken.Mid(1,aToken.Length()-2); // skip quotes
+ if (text.CompareF(aRowSet.ColDes(ColNo))!=0)
+ FatalError();
+ break;
+ }
+ case EDbColDateTime:
+ {
+ TScriptLine time=aToken.Mid(1,aToken.Length()-2); // skip hashes
+ TTime t1;
+ t1.Parse(time);
+ TTime t2(aRowSet.ColTime(ColNo).DateTime());
+ if (t1!=t2)
+ FatalError();
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+void TScriptEngine::PrintL(RDbRowSet& aRowSet)
+ {
+ iScript.WriteLine(TPtrC());
+ TInt columns=aRowSet.ColCount();
+ CDbColSet* colset=aRowSet.ColSetL();
+ TScriptLine line;
+ for (TInt i=1;i<=columns;++i)
+ {
+ const TDbCol& col=(*colset)[i];
+ line.AppendFormat(_L("%S\t"),&col.iName);
+ }
+ iScript.WriteLine(line);
+ aRowSet.BeginningL();
+ while (aRowSet.NextL())
+ {
+ line=TPtrC();
+ for (TInt ii=1;ii<=columns;++ii)
+ {
+ const TDbCol& col=(*colset)[ii];
+ aRowSet.GetL();
+ if (aRowSet.IsColNull(ii))
+ {
+ line.AppendFormat(_L("NULL\t"));
+ continue;
+ }
+ switch (col.iType)
+ {
+ case EDbColInt32:
+ line.AppendFormat(_L("%d\t"),aRowSet.ColInt(ii));
+ break;
+ case EDbColInt8:
+ line.AppendFormat(_L("%d\t"),aRowSet.ColInt8(ii));
+ break;
+ case EDbColInt16:
+ line.AppendFormat(_L("%d\t"),aRowSet.ColInt16(ii));
+ break;
+ case EDbColInt64:
+ line.AppendFormat(_L("%ld\t"),aRowSet.ColInt64(ii));
+ break;
+ case EDbColUint8:
+ line.AppendFormat(_L("%u\t"),aRowSet.ColUint8(ii));
+ break;
+ case EDbColUint16:
+ line.AppendFormat(_L("%u\t"),aRowSet.ColUint16(ii));
+ break;
+ case EDbColUint32:
+ line.AppendFormat(_L("%u\t"),aRowSet.ColUint(ii));
+ break;
+ case EDbColReal32:
+ line.AppendFormat(_L("%f\t"),aRowSet.ColReal32(ii));
+ break;
+ case EDbColReal64:
+ line.AppendFormat(_L("%f\t"),aRowSet.ColReal64(ii));
+ break;
+ case EDbColText:
+ line.Append(aRowSet.ColDes(ii));
+ line.Append('\t');
+ break;
+ case EDbColDateTime:
+ {
+ TDateTime time(aRowSet.ColTime(ii).DateTime());
+ line.AppendFormat(_L("%d:%d:%d %d/%d/%d"),time.Hour(),time.Minute(),time.Second(),time.Day(),time.Month(),time.Year());
+ }
+ break;
+ case EDbColLongText:
+ {
+ RDbColReadStream blob;
+ blob.OpenLC(aRowSet,ii);
+ TScriptLine text;
+ blob.ReadL(text,aRowSet.ColLength(ii));
+ CleanupStack::PopAndDestroy();
+ line.AppendFormat(_L("%S\t"),&text);
+ }
+ default:
+ break;
+ }
+ }
+ iScript.WriteLine(line);
+ }
+ iScript.WriteLine(TPtrC());
+ delete colset;
+ }
+
+
+//
+// Create the database
+//
+LOCAL_C void CreateDatabase()
+ {
+ TEST2(TheDatabase.Replace(TheFs,KTestDatabase), KErrNone);
+ }
+
+//
+// Close the database
+//
+LOCAL_C void CloseDatabase()
+ {
+ TheDatabase.Close();
+ }
+
+//
+// Prepare the test directory.
+//
+LOCAL_C void SetupTestDirectory()
+ {
+ TInt err=TheFs.Connect();
+ TEST2(err, KErrNone);
+//
+ err=TheFs.MkDir(KTestDatabase);
+ TEST(err==KErrNone || err==KErrAlreadyExists);
+ }
+
+//
+// Initialise the cleanup stack.
+//
+LOCAL_C void SetupCleanup()
+ {
+ TheTrapCleanup=CTrapCleanup::New();
+ TEST(TheTrapCleanup!=NULL);
+ TRAPD(err,\
+ {\
+ for (TInt i=KTestCleanupStack;i>0;i--)\
+ CleanupStack::PushL((TAny*)0);\
+ CleanupStack::Pop(KTestCleanupStack);\
+ });
+ TEST2(err, KErrNone);
+ }
+
+/**
+@SYMTestCaseID SYSLIB-DBMS-CT-0632
+@SYMTestCaseDesc Executes the script files
+@SYMTestPriority Medium
+@SYMTestActions Start the script engine
+@SYMTestExpectedResults Test must not fail
+@SYMREQ REQ0000
+*/
+LOCAL_C void RunScriptL()
+ {
+ TheTest.Start(_L(" @SYMTestCaseID:SYSLIB-DBMS-CT-0632 Running script "));
+ CreateDatabase();
+ TScriptEngine script;
+ script.RunL();
+ CloseDatabase();
+ TheView.Close();
+ }
+
+//
+// entry point
+//
+GLDEF_C TInt E32Main()
+ {
+ TheTest.Title();
+ SetupTestDirectory();
+ SetupCleanup();
+ __UHEAP_MARK;
+//
+ TRAPD(err,RunScriptL());
+ TEST2(err, KErrNone);
+
+ //deletion of data files must be done before call to end - DEF047652
+ ::DeleteDataFile(KTestDatabase);
+ ::DeleteDataFile(KOutputFile);//Comment this line if you want to keep "t_script.log" file.
+ TheTest.End();
+//
+ __UHEAP_MARKEND;
+ delete TheTrapCleanup;
+
+ TheFs.Close();
+ TheTest.Close();
+
+ return 0;
+ }