sl@0
|
1 |
// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
|
sl@0
|
2 |
// All rights reserved.
|
sl@0
|
3 |
// This component and the accompanying materials are made available
|
sl@0
|
4 |
// under the terms of "Eclipse Public License v1.0"
|
sl@0
|
5 |
// which accompanies this distribution, and is available
|
sl@0
|
6 |
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
|
sl@0
|
7 |
//
|
sl@0
|
8 |
// Initial Contributors:
|
sl@0
|
9 |
// Nokia Corporation - initial contribution.
|
sl@0
|
10 |
//
|
sl@0
|
11 |
// Contributors:
|
sl@0
|
12 |
//
|
sl@0
|
13 |
// Description:
|
sl@0
|
14 |
// SQL parser tokeniser
|
sl@0
|
15 |
//
|
sl@0
|
16 |
//
|
sl@0
|
17 |
|
sl@0
|
18 |
#include "UQ_STD.H"
|
sl@0
|
19 |
|
sl@0
|
20 |
// optimised tables for ASCII character set
|
sl@0
|
21 |
|
sl@0
|
22 |
const TUint8 KAlpha=0x1;
|
sl@0
|
23 |
const TUint8 KDigitOr_=0x2;
|
sl@0
|
24 |
|
sl@0
|
25 |
const TUint8 KCharAttrib[]=
|
sl@0
|
26 |
{
|
sl@0
|
27 |
KDigitOr_,KDigitOr_,KDigitOr_,KDigitOr_,KDigitOr_,KDigitOr_,KDigitOr_,KDigitOr_,
|
sl@0
|
28 |
KDigitOr_,KDigitOr_,0,0,0,0,0,0,
|
sl@0
|
29 |
0,KAlpha,KAlpha,KAlpha,KAlpha,KAlpha,KAlpha,KAlpha,
|
sl@0
|
30 |
KAlpha,KAlpha,KAlpha,KAlpha,KAlpha,KAlpha,KAlpha,KAlpha,
|
sl@0
|
31 |
KAlpha,KAlpha,KAlpha,KAlpha,KAlpha,KAlpha,KAlpha,KAlpha,
|
sl@0
|
32 |
KAlpha,KAlpha,KAlpha,0,0,0,0,KDigitOr_,
|
sl@0
|
33 |
0,KAlpha,KAlpha,KAlpha,KAlpha,KAlpha,KAlpha,KAlpha,
|
sl@0
|
34 |
KAlpha,KAlpha,KAlpha,KAlpha,KAlpha,KAlpha,KAlpha,KAlpha,
|
sl@0
|
35 |
KAlpha,KAlpha,KAlpha,KAlpha,KAlpha,KAlpha,KAlpha,KAlpha,
|
sl@0
|
36 |
KAlpha,KAlpha,KAlpha
|
sl@0
|
37 |
};
|
sl@0
|
38 |
|
sl@0
|
39 |
#define ISALPHA(aChar) (TUint(aChar-'0')<=TUint('z'-'0') && KCharAttrib[aChar-'0']&KAlpha)
|
sl@0
|
40 |
#define ISALPHA_DIGIT_OR_(aChar) (TUint(aChar-'0')<=TUint('z'-'0') && KCharAttrib[aChar-'0']&(KAlpha|KDigitOr_))
|
sl@0
|
41 |
#define LCASE(aChar) (aChar|0x20)
|
sl@0
|
42 |
|
sl@0
|
43 |
// The keywords
|
sl@0
|
44 |
// These are always stored as ASCII because DBMS has its own
|
sl@0
|
45 |
|
sl@0
|
46 |
const TInt KMaxKeywordLength=9;
|
sl@0
|
47 |
|
sl@0
|
48 |
static const TText8 KSqlKeywords[][KMaxKeywordLength+1]=
|
sl@0
|
49 |
{
|
sl@0
|
50 |
#define KEYWORD(s) #s
|
sl@0
|
51 |
#include "UQ_KEYWD.H"
|
sl@0
|
52 |
#undef KEYWORD
|
sl@0
|
53 |
};
|
sl@0
|
54 |
const TInt KSqlKeywordCount=sizeof(KSqlKeywords)/sizeof(*KSqlKeywords);
|
sl@0
|
55 |
|
sl@0
|
56 |
#if defined(_ASSERTIONS)
|
sl@0
|
57 |
TInt CheckKeywords()
|
sl@0
|
58 |
//
|
sl@0
|
59 |
// ensure that the keyword table is in alphabetical order
|
sl@0
|
60 |
//
|
sl@0
|
61 |
{
|
sl@0
|
62 |
for (TInt ii=1;ii<KSqlKeywordCount;++ii)
|
sl@0
|
63 |
__ASSERT(TPtrC8(KSqlKeywords[ii-1])<TPtrC8(KSqlKeywords[ii]));
|
sl@0
|
64 |
return 1;
|
sl@0
|
65 |
}
|
sl@0
|
66 |
#endif
|
sl@0
|
67 |
|
sl@0
|
68 |
// class TSqlLexer
|
sl@0
|
69 |
|
sl@0
|
70 |
TInt TSqlLexer::CompareKeyword(TInt aKeyword,const RSqlLiteral& aIdentifier)
|
sl@0
|
71 |
//
|
sl@0
|
72 |
// Check if the identifer in aIdentifier is a keyword
|
sl@0
|
73 |
// uses a case-insensitive match, not folding
|
sl@0
|
74 |
//
|
sl@0
|
75 |
{
|
sl@0
|
76 |
__ASSERT(TUint(aKeyword)<TUint(KSqlKeywordCount));
|
sl@0
|
77 |
//
|
sl@0
|
78 |
const TText* ptr=aIdentifier.Ptr();
|
sl@0
|
79 |
const TText* end=aIdentifier.End();
|
sl@0
|
80 |
const TText8* pk=&KSqlKeywords[aKeyword][0];
|
sl@0
|
81 |
for (;;)
|
sl@0
|
82 |
{
|
sl@0
|
83 |
TUint ck=*pk++;
|
sl@0
|
84 |
if (ptr==end)
|
sl@0
|
85 |
return ck;
|
sl@0
|
86 |
if (!ck)
|
sl@0
|
87 |
return -1;
|
sl@0
|
88 |
TInt d=ck-LCASE(TUint(*ptr++));
|
sl@0
|
89 |
if (d)
|
sl@0
|
90 |
return d;
|
sl@0
|
91 |
}
|
sl@0
|
92 |
}
|
sl@0
|
93 |
|
sl@0
|
94 |
TSqlKeyword TSqlLexer::Keyword(const TSqlToken& aToken)
|
sl@0
|
95 |
//
|
sl@0
|
96 |
// non-member function: Return the keyword value
|
sl@0
|
97 |
//
|
sl@0
|
98 |
{
|
sl@0
|
99 |
if (aToken==ESqlIdentifier)
|
sl@0
|
100 |
{
|
sl@0
|
101 |
TInt r=KSqlKeywordCount;
|
sl@0
|
102 |
TInt l=0;
|
sl@0
|
103 |
while (r>l)
|
sl@0
|
104 |
{
|
sl@0
|
105 |
TInt m=(l+r)>>1;
|
sl@0
|
106 |
TInt k=CompareKeyword(m,aToken.Literal());
|
sl@0
|
107 |
if (k>0)
|
sl@0
|
108 |
r=m;
|
sl@0
|
109 |
else if (k<0)
|
sl@0
|
110 |
l=m+1;
|
sl@0
|
111 |
else
|
sl@0
|
112 |
return TSqlKeyword(m); // keyword
|
sl@0
|
113 |
}
|
sl@0
|
114 |
}
|
sl@0
|
115 |
// identifier
|
sl@0
|
116 |
return ESqlNotKeyword;
|
sl@0
|
117 |
}
|
sl@0
|
118 |
|
sl@0
|
119 |
TSqlLexer::TSqlLexer(const TDesC& aSql)
|
sl@0
|
120 |
: iNext(aSql.Ptr()),iEnd(iNext+aSql.Length())
|
sl@0
|
121 |
{
|
sl@0
|
122 |
__ASSERT(CheckKeywords());
|
sl@0
|
123 |
}
|
sl@0
|
124 |
|
sl@0
|
125 |
TSqlTokenType TSqlLexer::GetIdentifier(TSqlToken& aToken)
|
sl@0
|
126 |
//
|
sl@0
|
127 |
// Get a keyword or identifier. Do not resolve a keyword at this stage
|
sl@0
|
128 |
//
|
sl@0
|
129 |
{
|
sl@0
|
130 |
const TText* end=iEnd;
|
sl@0
|
131 |
const TText* next=iNext-1;
|
sl@0
|
132 |
while (++next<end)
|
sl@0
|
133 |
{
|
sl@0
|
134 |
TUint ch=*next;
|
sl@0
|
135 |
if (ISALPHA_DIGIT_OR_(ch))
|
sl@0
|
136 |
continue;
|
sl@0
|
137 |
if (!TChar(ch).IsAlphaDigit())
|
sl@0
|
138 |
break;
|
sl@0
|
139 |
}
|
sl@0
|
140 |
aToken.iLiteral.SetText(iNext-1,next);
|
sl@0
|
141 |
iNext=next;
|
sl@0
|
142 |
return ESqlIdentifier;
|
sl@0
|
143 |
}
|
sl@0
|
144 |
|
sl@0
|
145 |
TInt TSqlLexer::GetInteger(TInt64 &aVal)
|
sl@0
|
146 |
//
|
sl@0
|
147 |
// A rather more optimised version of TLex::Val(TInt64&)
|
sl@0
|
148 |
// initially accumulate the value in a TUint32, and only switch to 64-bit arithmetic
|
sl@0
|
149 |
// if the value overflows. Always return a 64-bit value
|
sl@0
|
150 |
//
|
sl@0
|
151 |
{
|
sl@0
|
152 |
const TUint KPreMultiplyLimit32=429496728; //(KMaxTUint-9)/10
|
sl@0
|
153 |
const TUint KPreMultiplyLimit64=214748364; //(KMaxTInt+1)/10
|
sl@0
|
154 |
//
|
sl@0
|
155 |
const TText* ptr=iNext;
|
sl@0
|
156 |
const TText* const end=iEnd;
|
sl@0
|
157 |
__ASSERT(ptr<end);
|
sl@0
|
158 |
TUint sign=0;
|
sl@0
|
159 |
TUint c=*ptr;
|
sl@0
|
160 |
if (c=='-')
|
sl@0
|
161 |
{
|
sl@0
|
162 |
sign=1;
|
sl@0
|
163 |
if (++ptr==end)
|
sl@0
|
164 |
return KErrGeneral;
|
sl@0
|
165 |
c=*ptr;
|
sl@0
|
166 |
}
|
sl@0
|
167 |
else if (c=='+')
|
sl@0
|
168 |
{
|
sl@0
|
169 |
if (++ptr==end)
|
sl@0
|
170 |
return KErrGeneral;
|
sl@0
|
171 |
c=*ptr;
|
sl@0
|
172 |
}
|
sl@0
|
173 |
c-='0';
|
sl@0
|
174 |
if (c>=10u)
|
sl@0
|
175 |
return KErrGeneral; // no digits at all
|
sl@0
|
176 |
TUint val32=c;
|
sl@0
|
177 |
while (++ptr<end)
|
sl@0
|
178 |
{
|
sl@0
|
179 |
c=*ptr-'0';
|
sl@0
|
180 |
if (c>=10u)
|
sl@0
|
181 |
break;
|
sl@0
|
182 |
if (val32>KPreMultiplyLimit32)
|
sl@0
|
183 |
goto overflow64; // will not fit into 32 bit arithmetic
|
sl@0
|
184 |
val32*=10;
|
sl@0
|
185 |
val32+=c;
|
sl@0
|
186 |
}
|
sl@0
|
187 |
// we have result, just set the sign and finish
|
sl@0
|
188 |
aVal=val32;
|
sl@0
|
189 |
goto checksign;
|
sl@0
|
190 |
//
|
sl@0
|
191 |
// continue the accumulation with a 64-bit integer
|
sl@0
|
192 |
overflow64:
|
sl@0
|
193 |
aVal=val32;
|
sl@0
|
194 |
for (;;)
|
sl@0
|
195 |
{
|
sl@0
|
196 |
I64MUL10(aVal);
|
sl@0
|
197 |
aVal+=c;
|
sl@0
|
198 |
if (++ptr==end)
|
sl@0
|
199 |
break;
|
sl@0
|
200 |
c=*ptr-'0';
|
sl@0
|
201 |
if (c>=10u)
|
sl@0
|
202 |
break;
|
sl@0
|
203 |
if (I64HIGH(aVal)>KPreMultiplyLimit64)
|
sl@0
|
204 |
return KErrOverflow; // the value is certain to overflow
|
sl@0
|
205 |
}
|
sl@0
|
206 |
if (I64HIGH(aVal)&0x80000000u)
|
sl@0
|
207 |
{ // greater than the "half way mark"
|
sl@0
|
208 |
if (!sign)
|
sl@0
|
209 |
return KErrOverflow;
|
sl@0
|
210 |
if (I64LOW(aVal)!=0)
|
sl@0
|
211 |
return KErrOverflow;
|
sl@0
|
212 |
}
|
sl@0
|
213 |
checksign:
|
sl@0
|
214 |
iNext=ptr;
|
sl@0
|
215 |
if (sign)
|
sl@0
|
216 |
aVal=-aVal;
|
sl@0
|
217 |
return KErrNone;
|
sl@0
|
218 |
}
|
sl@0
|
219 |
|
sl@0
|
220 |
TSqlTokenType TSqlLexer::GetNumber(TSqlToken& aToken)
|
sl@0
|
221 |
{
|
sl@0
|
222 |
const TText* mark=--iNext; // rewind past initial character
|
sl@0
|
223 |
// attempt to parse a integer
|
sl@0
|
224 |
TInt r=GetInteger(aToken.iLiteral.SetInt());
|
sl@0
|
225 |
if (r==KErrNone)
|
sl@0
|
226 |
{
|
sl@0
|
227 |
if (iNext<iEnd)
|
sl@0
|
228 |
{
|
sl@0
|
229 |
TUint c=*iNext;
|
sl@0
|
230 |
if (c!='.' && c!='e' && c!='E')
|
sl@0
|
231 |
return ESqlLiteralInt; // it is an integer
|
sl@0
|
232 |
}
|
sl@0
|
233 |
else
|
sl@0
|
234 |
return ESqlLiteralInt; // it is an integer
|
sl@0
|
235 |
}
|
sl@0
|
236 |
TLex lex(TPtrC(mark,iEnd-mark));
|
sl@0
|
237 |
r=lex.Val(aToken.iLiteral.SetReal(),TChar('.'));
|
sl@0
|
238 |
if (r!=KErrNone)
|
sl@0
|
239 |
return SqlError(r);
|
sl@0
|
240 |
iNext=mark+lex.Offset();
|
sl@0
|
241 |
return ESqlLiteralReal;
|
sl@0
|
242 |
}
|
sl@0
|
243 |
|
sl@0
|
244 |
TSqlTokenType TSqlLexer::GetString(TSqlToken& aToken)
|
sl@0
|
245 |
{
|
sl@0
|
246 |
const TText* next=iNext;
|
sl@0
|
247 |
const TText* end=iEnd;
|
sl@0
|
248 |
for (;;)
|
sl@0
|
249 |
{
|
sl@0
|
250 |
if (next==end)
|
sl@0
|
251 |
return SqlError();
|
sl@0
|
252 |
TUint c=*next++;
|
sl@0
|
253 |
if (c=='\'')
|
sl@0
|
254 |
{
|
sl@0
|
255 |
if (next==end)
|
sl@0
|
256 |
break;
|
sl@0
|
257 |
if (*next!='\'')
|
sl@0
|
258 |
break;
|
sl@0
|
259 |
next++;
|
sl@0
|
260 |
}
|
sl@0
|
261 |
}
|
sl@0
|
262 |
aToken.iLiteral.SetText(iNext,next-1);
|
sl@0
|
263 |
iNext=next;
|
sl@0
|
264 |
return ESqlLiteralText;
|
sl@0
|
265 |
}
|
sl@0
|
266 |
|
sl@0
|
267 |
TSqlTokenType TSqlLexer::GetDate(TSqlToken& aToken)
|
sl@0
|
268 |
{
|
sl@0
|
269 |
const TText* end=iEnd;
|
sl@0
|
270 |
const TText* next=iNext;
|
sl@0
|
271 |
do
|
sl@0
|
272 |
{
|
sl@0
|
273 |
if (next==end)
|
sl@0
|
274 |
return SqlError();
|
sl@0
|
275 |
} while (*next++!='#');
|
sl@0
|
276 |
TInt r=aToken.iLiteral.SetTime().Parse(TPtrC(iNext,(next-1)-iNext));
|
sl@0
|
277 |
if (r<0)
|
sl@0
|
278 |
return SqlError(r);
|
sl@0
|
279 |
iNext=next;
|
sl@0
|
280 |
return ESqlLiteralTime;
|
sl@0
|
281 |
}
|
sl@0
|
282 |
|
sl@0
|
283 |
TSqlTokenType TSqlLexer::GetNextToken(TSqlToken& aToken)
|
sl@0
|
284 |
{
|
sl@0
|
285 |
const TText* ptr=iNext;
|
sl@0
|
286 |
const TText* const end=iEnd;
|
sl@0
|
287 |
for (;;)
|
sl@0
|
288 |
{
|
sl@0
|
289 |
if (ptr==end)
|
sl@0
|
290 |
return ESqlEos;
|
sl@0
|
291 |
TUint ch=*ptr++;
|
sl@0
|
292 |
iNext=ptr;
|
sl@0
|
293 |
switch (ch)
|
sl@0
|
294 |
{
|
sl@0
|
295 |
case ' ': // a "normal" space
|
sl@0
|
296 |
continue;
|
sl@0
|
297 |
case '0': case '1': case '2': case '3': case '4': // literal number
|
sl@0
|
298 |
case '5': case '6': case '7': case '8': case '9':
|
sl@0
|
299 |
case '+': case '-': case '.':
|
sl@0
|
300 |
return GetNumber(aToken);
|
sl@0
|
301 |
case '\'':
|
sl@0
|
302 |
return GetString(aToken);
|
sl@0
|
303 |
case '#':
|
sl@0
|
304 |
return GetDate(aToken);
|
sl@0
|
305 |
case '*':
|
sl@0
|
306 |
return ESqlAsterisk;
|
sl@0
|
307 |
case ',':
|
sl@0
|
308 |
return ESqlComma;
|
sl@0
|
309 |
case '(':
|
sl@0
|
310 |
return ESqlLeftBracket;
|
sl@0
|
311 |
case ')':
|
sl@0
|
312 |
return ESqlRightBracket;
|
sl@0
|
313 |
case '=':
|
sl@0
|
314 |
return ESqlEqual;
|
sl@0
|
315 |
case '<':
|
sl@0
|
316 |
{
|
sl@0
|
317 |
ch=*ptr++;
|
sl@0
|
318 |
if (ch=='=')
|
sl@0
|
319 |
{
|
sl@0
|
320 |
iNext=ptr;
|
sl@0
|
321 |
return ESqlLessEqual;
|
sl@0
|
322 |
}
|
sl@0
|
323 |
if (ch=='>')
|
sl@0
|
324 |
{
|
sl@0
|
325 |
iNext=ptr;
|
sl@0
|
326 |
return ESqlNotEqual;
|
sl@0
|
327 |
}
|
sl@0
|
328 |
return ESqlLess;
|
sl@0
|
329 |
}
|
sl@0
|
330 |
case '>':
|
sl@0
|
331 |
{
|
sl@0
|
332 |
ch=*ptr++;
|
sl@0
|
333 |
if (ch=='=')
|
sl@0
|
334 |
{
|
sl@0
|
335 |
iNext=ptr;
|
sl@0
|
336 |
return ESqlGreaterEqual;
|
sl@0
|
337 |
}
|
sl@0
|
338 |
return ESqlGreater;
|
sl@0
|
339 |
}
|
sl@0
|
340 |
default:
|
sl@0
|
341 |
break;
|
sl@0
|
342 |
}
|
sl@0
|
343 |
if (ISALPHA(ch))
|
sl@0
|
344 |
return GetIdentifier(aToken); // keyword or identifier
|
sl@0
|
345 |
TChar cc(ch);
|
sl@0
|
346 |
if (cc.IsAlpha())
|
sl@0
|
347 |
return GetIdentifier(aToken); // keyword or identifier
|
sl@0
|
348 |
if (!cc.IsSpace())
|
sl@0
|
349 |
return SqlError();
|
sl@0
|
350 |
}
|
sl@0
|
351 |
}
|
sl@0
|
352 |
|
sl@0
|
353 |
const TText* TSqlLexer::Next() const
|
sl@0
|
354 |
{
|
sl@0
|
355 |
return iNext;
|
sl@0
|
356 |
}
|
sl@0
|
357 |
void TSqlLexer::Set(const TText* aNext)
|
sl@0
|
358 |
{
|
sl@0
|
359 |
iNext = aNext ;
|
sl@0
|
360 |
}
|