1 {*********************************************************}
3 { Zeos Database Objects }
4 { String tokenizing classes for Generic SQL }
6 { Originally written by Sergey Seroukhov }
8 {*********************************************************}
10 {@********************************************************}
11 { Copyright (c) 1999-2012 Zeos Development Group }
13 { License Agreement: }
15 { This library is distributed in the hope that it will be }
16 { useful, but WITHOUT ANY WARRANTY; without even the }
17 { implied warranty of MERCHANTABILITY or FITNESS FOR }
18 { A PARTICULAR PURPOSE. See the GNU Lesser General }
19 { Public License for more details. }
21 { The source code of the ZEOS Libraries and packages are }
22 { distributed under the Library GNU General Public }
23 { License (see the file COPYING / COPYING.ZEOS) }
24 { with the following modification: }
25 { As a special exception, the copyright holders of this }
26 { library give you permission to link this library with }
27 { independent modules to produce an executable, }
28 { regardless of the license terms of these independent }
29 { modules, and to copy and distribute the resulting }
30 { executable under terms of your choice, provided that }
31 { you also meet, for each linked independent module, }
32 { the terms and conditions of the license of that module. }
33 { An independent module is a module which is not derived }
34 { from or based on this library. If you modify this }
35 { library, you may extend this exception to your version }
36 { of the library, but you are not obligated to do so. }
37 { If you do not wish to do so, delete this exception }
38 { statement from your version. }
41 { The project web site is located on: }
42 { http://zeos.firmos.at (FORUM) }
43 { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)}
44 { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) }
46 { http://www.sourceforge.net/projects/zeoslib. }
49 { Zeos Development Group. }
50 {********************************************************@}
52 unit ZGenericSqlToken;
59 Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils,
60 ZTokenizer, ZCompatibility;
64 {** Implements a symbol state object. }
65 TZGenericSQLSymbolState = class (TZSymbolState)
70 {** Implements a word state object. }
71 TZGenericSQLWordState = class (TZWordState)
75 function NextToken(Stream: TStream; FirstChar: Char;
76 Tokenizer: TZTokenizer): TZToken; override;
79 {** Implements a quote string state object. }
80 TZGenericSQLQuoteState = class (TZQuoteState)
82 function NextToken(Stream: TStream; FirstChar: Char;
83 Tokenizer: TZTokenizer): TZToken; override;
85 function EncodeString(const Value: string; QuoteChar: Char): string; override;
86 function DecodeString(const Value: string; QuoteChar: Char): string; override;
89 {** Implements a default tokenizer object. }
90 TZGenericSQLTokenizer = class (TZTokenizer)
97 { TZGenericSQLSymbolState }
100 Creates this SQL-specific symbol state object.
102 constructor TZGenericSQLSymbolState.Create;
112 { TZGenericSQLWordState }
115 Constructs this SQL-specific word state object.
117 constructor TZGenericSQLWordState.Create;
119 SetWordChars(#0, #191, False);
120 SetWordChars(#192, high(char), True);
121 SetWordChars('a', 'z', True);
122 SetWordChars('A', 'Z', True);
123 SetWordChars('0', '9', True);
124 SetWordChars('$', '$', True);
125 SetWordChars('_', '_', True);
129 {** List of keywords. }
130 Keywords: array [0..8] of string = (
131 'AND','OR','NOT','XOR','LIKE','IS','NULL','TRUE','FALSE'
135 Gets a word tokens or special operators.
136 @return a processed token.
138 function TZGenericSQLWordState.NextToken(Stream: TStream; FirstChar: Char;
139 Tokenizer: TZTokenizer): TZToken;
144 Result := inherited NextToken(Stream, FirstChar, Tokenizer);
145 Temp := UpperCase(Result.Value);
147 for I := Low(Keywords) to High(Keywords) do
149 if Temp = Keywords[I] then
151 Result.TokenType := ttKeyword;
158 { TZGenericSQLQuoteState }
161 Return a quoted string token from a reader. This method
162 will collect characters until it sees a match to the
163 character that the tokenizer used to switch to this state.
165 @return a quoted string token from a reader
170 function TZGenericSQLQuoteState.NextToken(Stream: TStream;
171 FirstChar: Char; Tokenizer: TZTokenizer): TZToken;
175 ReadCounter, NumericCounter, CountDoublePoint, CountSlash, CountSpace : integer;
177 Result.Value := FirstChar;
179 CountDoublePoint := 0;
185 while Stream.Read(ReadChar, SizeOf(Char)) > 0 do
187 if (LastChar = FirstChar) and (ReadChar <> FirstChar) then
189 Stream.Seek(-SizeOf(Char), soFromCurrent);
192 if ReadChar = {$IFDEF WITH_FORMATSETTINGS}FormatSettings.{$ENDIF}TimeSeparator then
193 inc(CountDoublePoint)
194 else if ReadChar = {$IFDEF WITH_FORMATSETTINGS}FormatSettings.{$ENDIF}DateSeparator then
196 else if ReadChar = ' ' then
198 else if CharInSet(ReadChar, ['0'..'9']) then
202 Result.Value := Result.Value + ReadChar;
203 if (LastChar = FirstChar) and (ReadChar = FirstChar) then
205 else LastChar := ReadChar;
208 if FirstChar = '"' then
209 Result.TokenType := ttWord
210 else Result.TokenType := ttQuoted;
213 if (CountDoublePoint = 2) and (CountSlash = 0) and
214 ((NumericCounter + CountDoublePoint) = ReadCounter-1) then
217 if StrToTimeDef(DecodeString(Result.Value, FirstChar), 0) = 0 then
219 Result.Value := DecodeString(Result.Value,'"');
220 Result.TokenType := ttTime;
225 if (CountDoublePoint = 0) and (CountSlash = 2) and
226 ((NumericCounter + CountSlash) = ReadCounter-1) then
229 if StrToDateDef(DecodeString(Result.Value, FirstChar), 0) = 0 then
231 Result.Value := DecodeString(Result.Value,'"');
232 Result.TokenType := ttDate;
238 if (CountDoublePoint = 2) and (CountSlash = 2) and
239 ((NumericCounter + CountDoublePoint + CountSlash + CountSpace) = ReadCounter-1) then
242 if StrToDateTimeDef(DecodeString(Result.Value, FirstChar), 0) = 0 then
244 Result.Value := DecodeString(Result.Value,'"');
245 Result.TokenType := ttDateTime;
250 if not ( Result.TokenType in [ttQuoted, ttWord] ) then
253 //No System-defaults found, Check for SQL format;
254 {AStamp := TimestampStrToDateTime(DecodeString(Result.Value, FirstChar)); //minimize the handling
258 if ( TDate(AStamp) <> EmptyDate ) then
259 if ( TTime(AStamp) <> EmptyTime ) then
261 Result.Value := DateTimeToStr(AStamp);
262 Result.TokenType := ttDateTime;
266 Result.Value := DateToStr(AStamp);
267 Result.TokenType := ttDate;
270 if ( TTime(AStamp) <> EmptyTime ) then
272 Result.Value := TimeToStr(AStamp);
273 Result.TokenType := ttTime;
281 Encodes a string value.
282 @param Value a string value to be encoded.
283 @param QuoteChar a string quote character.
284 @returns an encoded string.
286 function TZGenericSQLQuoteState.EncodeString(const Value: string;
287 QuoteChar: Char): string;
289 if CharInSet(QuoteChar, [#39, '"', '`']) then
290 Result := AnsiQuotedStr(Value, QuoteChar)
291 else Result := Value;
295 Decodes a string value.
296 @param Value a string value to be decoded.
297 @param QuoteChar a string quote character.
298 @returns an decoded string.
300 function TZGenericSQLQuoteState.DecodeString(const Value: string;
301 QuoteChar: Char): string;
305 Len := Length(Value);
306 if (Len >= 2) and CharInSet(QuoteChar, [#39, '"', '`'])
307 and (Value[1] = QuoteChar) and (Value[Len] = QuoteChar) then
310 Result := AnsiDequotedStr(Value, QuoteChar)
313 else Result := Value;
316 { TZGenericSQLTokenizer }
319 Constructs a tokenizer with a default state table (as
320 described in the class comment).
322 constructor TZGenericSQLTokenizer.Create;
324 NumberState := TZNumberState.Create;
325 QuoteState := TZGenericSQLQuoteState.Create;
326 WhitespaceState := TZWhitespaceState.Create;
327 CommentState := TZCppCommentState.Create;
329 SymbolState := TZGenericSQLSymbolState.Create;
330 WordState := TZGenericSQLWordState.Create;
332 SetCharacterState(#0, #32, WhitespaceState);
333 SetCharacterState(#33, #191, SymbolState);
334 SetCharacterState(#192, High(Char), WordState);
336 SetCharacterState('a', 'z', WordState);
337 SetCharacterState('A', 'Z', WordState);
338 SetCharacterState('_', '_', WordState);
339 SetCharacterState('$', '$', WordState);
341 SetCharacterState('0', '9', NumberState);
342 SetCharacterState('.', '.', NumberState);
344 SetCharacterState('"', '"', QuoteState);
345 SetCharacterState(#39, #39, QuoteState);
346 SetCharacterState('`', '`', QuoteState);
348 SetCharacterState('/', '/', CommentState);