zeoslib  UNKNOWN
 All Files
ZGenericSqlToken.pas
Go to the documentation of this file.
1 {*********************************************************}
2 { }
3 { Zeos Database Objects }
4 { String tokenizing classes for Generic SQL }
5 { }
6 { Originally written by Sergey Seroukhov }
7 { }
8 {*********************************************************}
9 
10 {@********************************************************}
11 { Copyright (c) 1999-2012 Zeos Development Group }
12 { }
13 { License Agreement: }
14 { }
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. }
20 { }
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. }
39 { }
40 { }
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) }
45 { }
46 { http://www.sourceforge.net/projects/zeoslib. }
47 { }
48 { }
49 { Zeos Development Group. }
50 {********************************************************@}
51 
52 unit ZGenericSqlToken;
53 
54 interface
55 
56 {$I ZParseSql.inc}
57 
58 uses
59  Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils,
60  ZTokenizer, ZCompatibility;
61 
62 type
63 
64  {** Implements a symbol state object. }
65  TZGenericSQLSymbolState = class (TZSymbolState)
66  public
67  constructor Create;
68  end;
69 
70  {** Implements a word state object. }
71  TZGenericSQLWordState = class (TZWordState)
72  public
73  constructor Create;
74 
75  function NextToken(Stream: TStream; FirstChar: Char;
76  Tokenizer: TZTokenizer): TZToken; override;
77  end;
78 
79  {** Implements a quote string state object. }
80  TZGenericSQLQuoteState = class (TZQuoteState)
81  public
82  function NextToken(Stream: TStream; FirstChar: Char;
83  Tokenizer: TZTokenizer): TZToken; override;
84 
85  function EncodeString(const Value: string; QuoteChar: Char): string; override;
86  function DecodeString(const Value: string; QuoteChar: Char): string; override;
87  end;
88 
89  {** Implements a default tokenizer object. }
90  TZGenericSQLTokenizer = class (TZTokenizer)
91  public
92  constructor Create;
93  end;
94 
95 implementation
96 
97 { TZGenericSQLSymbolState }
98 
99 {**
100  Creates this SQL-specific symbol state object.
101 }
102 constructor TZGenericSQLSymbolState.Create;
103 begin
104  inherited Create;
105  Add('<=');
106  Add('>=');
107  Add('<>');
108  Add('<<');
109  Add('>>');
110 end;
111 
112 { TZGenericSQLWordState }
113 
114 {**
115  Constructs this SQL-specific word state object.
116 }
117 constructor TZGenericSQLWordState.Create;
118 begin
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);
126 end;
127 
128 const
129  {** List of keywords. }
130  Keywords: array [0..8] of string = (
131  'AND','OR','NOT','XOR','LIKE','IS','NULL','TRUE','FALSE'
132  );
133 
134 {**
135  Gets a word tokens or special operators.
136  @return a processed token.
137 }
138 function TZGenericSQLWordState.NextToken(Stream: TStream; FirstChar: Char;
139  Tokenizer: TZTokenizer): TZToken;
140 var
141  I: Integer;
142  Temp: string;
143 begin
144  Result := inherited NextToken(Stream, FirstChar, Tokenizer);
145  Temp := UpperCase(Result.Value);
146 
147  for I := Low(Keywords) to High(Keywords) do
148  begin
149  if Temp = Keywords[I] then
150  begin
151  Result.TokenType := ttKeyword;
152  Break;
153  end;
154  end;
155 end;
156 
157 
158 { TZGenericSQLQuoteState }
159 
160 {**
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.
164 
165  @return a quoted string token from a reader
166 }
167 {$IFDEF FPC}
168  {$HINTS OFF}
169 {$ENDIF}
170 function TZGenericSQLQuoteState.NextToken(Stream: TStream;
171  FirstChar: Char; Tokenizer: TZTokenizer): TZToken;
172 var
173  ReadChar: Char;
174  LastChar: Char;
175  ReadCounter, NumericCounter, CountDoublePoint, CountSlash, CountSpace : integer;
176 begin
177  Result.Value := FirstChar;
178  LastChar := #0;
179  CountDoublePoint := 0;
180  CountSlash := 0;
181  CountSpace := 0;
182  ReadCounter := 0;
183  NumericCounter := 0;
184 
185  while Stream.Read(ReadChar, SizeOf(Char)) > 0 do
186  begin
187  if (LastChar = FirstChar) and (ReadChar <> FirstChar) then
188  begin
189  Stream.Seek(-SizeOf(Char), soFromCurrent);
190  Break;
191  end;
192  if ReadChar = {$IFDEF WITH_FORMATSETTINGS}FormatSettings.{$ENDIF}TimeSeparator then
193  inc(CountDoublePoint)
194  else if ReadChar = {$IFDEF WITH_FORMATSETTINGS}FormatSettings.{$ENDIF}DateSeparator then
195  inc(CountSlash)
196  else if ReadChar = ' ' then
197  inc(CountSpace)
198  else if CharInSet(ReadChar, ['0'..'9']) then
199  inc(NumericCounter);
200  Inc(ReadCounter);
201 
202  Result.Value := Result.Value + ReadChar;
203  if (LastChar = FirstChar) and (ReadChar = FirstChar) then
204  LastChar := #0
205  else LastChar := ReadChar;
206  end;
207 
208  if FirstChar = '"' then
209  Result.TokenType := ttWord
210  else Result.TokenType := ttQuoted;
211 
212  // Time constant
213  if (CountDoublePoint = 2) and (CountSlash = 0) and
214  ((NumericCounter + CountDoublePoint) = ReadCounter-1) then
215  begin
216  try
217  if StrToTimeDef(DecodeString(Result.Value, FirstChar), 0) = 0 then
218  Exit;
219  Result.Value := DecodeString(Result.Value,'"');
220  Result.TokenType := ttTime;
221  except
222  end;
223  end;
224  // Date constant
225  if (CountDoublePoint = 0) and (CountSlash = 2) and
226  ((NumericCounter + CountSlash) = ReadCounter-1) then
227  begin
228  try
229  if StrToDateDef(DecodeString(Result.Value, FirstChar), 0) = 0 then
230  Exit;
231  Result.Value := DecodeString(Result.Value,'"');
232  Result.TokenType := ttDate;
233  except
234  end;
235  end;
236 
237  // DateTime constant
238  if (CountDoublePoint = 2) and (CountSlash = 2) and
239  ((NumericCounter + CountDoublePoint + CountSlash + CountSpace) = ReadCounter-1) then
240  begin
241  try
242  if StrToDateTimeDef(DecodeString(Result.Value, FirstChar), 0) = 0 then
243  Exit;
244  Result.Value := DecodeString(Result.Value,'"');
245  Result.TokenType := ttDateTime;
246  except
247  end;
248  end;
249 
250  if not ( Result.TokenType in [ttQuoted, ttWord] ) then
251  Exit;
252 
253  //No System-defaults found, Check for SQL format;
254  {AStamp := TimestampStrToDateTime(DecodeString(Result.Value, FirstChar)); //minimize the handling
255  if AStamp = 0 then
256  Exit
257  else
258  if ( TDate(AStamp) <> EmptyDate ) then
259  if ( TTime(AStamp) <> EmptyTime ) then
260  begin
261  Result.Value := DateTimeToStr(AStamp);
262  Result.TokenType := ttDateTime;
263  end
264  else
265  begin
266  Result.Value := DateToStr(AStamp);
267  Result.TokenType := ttDate;
268  end
269  else
270  if ( TTime(AStamp) <> EmptyTime ) then
271  begin
272  Result.Value := TimeToStr(AStamp);
273  Result.TokenType := ttTime;
274  end;}
275 end;
276 {$IFDEF FPC}
277  {$HINTS ON}
278 {$ENDIF}
279 
280 {**
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.
285 }
286 function TZGenericSQLQuoteState.EncodeString(const Value: string;
287  QuoteChar: Char): string;
288 begin
289  if CharInSet(QuoteChar, [#39, '"', '`']) then
290  Result := AnsiQuotedStr(Value, QuoteChar)
291  else Result := Value;
292 end;
293 
294 {**
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.
299 }
300 function TZGenericSQLQuoteState.DecodeString(const Value: string;
301  QuoteChar: Char): string;
302 var
303  Len: Integer;
304 begin
305  Len := Length(Value);
306  if (Len >= 2) and CharInSet(QuoteChar, [#39, '"', '`'])
307  and (Value[1] = QuoteChar) and (Value[Len] = QuoteChar) then
308  begin
309  if Len > 2 then
310  Result := AnsiDequotedStr(Value, QuoteChar)
311  else Result := '';
312  end
313  else Result := Value;
314 end;
315 
316 { TZGenericSQLTokenizer }
317 
318 {**
319  Constructs a tokenizer with a default state table (as
320  described in the class comment).
321 }
322 constructor TZGenericSQLTokenizer.Create;
323 begin
324  NumberState := TZNumberState.Create;
325  QuoteState := TZGenericSQLQuoteState.Create;
326  WhitespaceState := TZWhitespaceState.Create;
327  CommentState := TZCppCommentState.Create;
328 
329  SymbolState := TZGenericSQLSymbolState.Create;
330  WordState := TZGenericSQLWordState.Create;
331 
332  SetCharacterState(#0, #32, WhitespaceState);
333  SetCharacterState(#33, #191, SymbolState);
334  SetCharacterState(#192, High(Char), WordState);
335 
336  SetCharacterState('a', 'z', WordState);
337  SetCharacterState('A', 'Z', WordState);
338  SetCharacterState('_', '_', WordState);
339  SetCharacterState('$', '$', WordState);
340 
341  SetCharacterState('0', '9', NumberState);
342  SetCharacterState('.', '.', NumberState);
343 
344  SetCharacterState('"', '"', QuoteState);
345  SetCharacterState(#39, #39, QuoteState);
346  SetCharacterState('`', '`', QuoteState);
347 
348  SetCharacterState('/', '/', CommentState);
349 end;
350 
351 end.
352