1 {*********************************************************}
3 { Zeos Database Objects }
4 { SQL Select Objects and Assembler classes }
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 {********************************************************@}
58 uses ZClasses, Contnrs, ZCompatibility
59 {$IFDEF WITH_SYSTEMCLASSES},System.Classes{$ENDIF}
60 {$IFDEF WITH_TOBJECTLIST_INLINE}, System.Types{$ENDIF};
64 {** Case Sensitive/Unsensitive identificator processor. }
65 IZIdentifierConvertor = interface (IZInterface)
66 ['{2EB07B9B-1E96-4A42-8084-6F98D9140B27}']
68 function IsCaseSensitive(const Value: string): Boolean;
69 function IsQuoted(const Value: string): Boolean;
70 function Quote(const Value: string): string;
71 function ExtractQuote(const Value: string): string;
74 {** Implements a table reference assembly. }
75 TZTableRef = class (TObject)
82 constructor Create(const Catalog, Schema, Table, Alias: string);
83 function FullName: string;
85 property Catalog: string read FCatalog write FCatalog;
86 property Schema: string read FSchema write FSchema;
87 property Table: string read FTable write FTable;
88 property Alias: string read FAlias write FAlias;
91 {** Implements a field reference assembly. }
92 TZFieldRef = class (TObject)
100 FTableRef: TZTableRef;
103 constructor Create(IsField: Boolean; const Catalog, Schema, Table,
104 Field, Alias: string; TableRef: TZTableRef);
106 property IsField: Boolean read FIsField write FIsField;
107 property Catalog: string read FCatalog write FCatalog;
108 property Schema: string read FSchema write FSchema;
109 property Table: string read FTable write FTable;
110 property Field: string read FField write FField;
111 property Alias: string read FAlias write FAlias;
112 property TableRef: TZTableRef read FTableRef write FTableRef;
113 property Linked: Boolean read FLinked write FLinked;
116 {** Defines an interface to select assembly. }
117 IZSelectSchema = interface (IZInterface)
118 ['{3B892975-57E9-4EB7-8DB1-BDDED91E7FBC}']
120 procedure AddField(FieldRef: TZFieldRef);
121 procedure InsertField(Index: Integer; FieldRef: TZFieldRef);
122 procedure DeleteField(FieldRef: TZFieldRef);
124 procedure AddTable(TableRef: TZTableRef);
126 procedure LinkReferences(Convertor: IZIdentifierConvertor);
128 function FindTableByFullName(const Catalog, Schema, Table: string): TZTableRef;
129 function FindTableByShortName(const Table: string): TZTableRef;
130 function FindFieldByShortName(const Field: string): TZFieldRef;
132 function LinkFieldByIndexAndShortName(const ColumnIndex: Integer; const Field: string;
133 const Convertor: IZIdentifierConvertor): TZFieldRef;
135 function GetFieldCount: Integer;
136 function GetTableCount: Integer;
137 function GetField(Index: Integer): TZFieldRef;
138 function GetTable(Index: Integer): TZTableRef;
140 property FieldCount: Integer read GetFieldCount;
141 property Fields[Index: Integer]: TZFieldRef read GetField;
142 property TableCount: Integer read GetTableCount;
143 property Tables[Index: Integer]: TZTableRef read GetTable;
146 {** Implements a select assembly. }
147 TZSelectSchema = class (TZAbstractObject, IZSelectSchema)
149 FFields: TObjectList;
150 FTables: TObjectList;
152 procedure ConvertIdentifiers(Convertor: IZIdentifierConvertor);
155 destructor Destroy; override;
157 procedure AddField(FieldRef: TZFieldRef);
158 procedure InsertField(Index: Integer; FieldRef: TZFieldRef);
159 procedure DeleteField(FieldRef: TZFieldRef);
161 procedure AddTable(TableRef: TZTableRef);
163 procedure LinkReferences(Convertor: IZIdentifierConvertor);
165 function FindTableByFullName(const Catalog, Schema, Table: string): TZTableRef;
166 function FindTableByShortName(const Table: string): TZTableRef;
167 function FindFieldByShortName(const Field: string): TZFieldRef;
169 function LinkFieldByIndexAndShortName(const ColumnIndex: Integer; const Field: string;
170 const Convertor: IZIdentifierConvertor): TZFieldRef;
172 function GetFieldCount: Integer;
173 function GetTableCount: Integer;
174 function GetField(Index: Integer): TZFieldRef;
175 function GetTable(Index: Integer): TZTableRef;
177 property FieldCount: Integer read GetFieldCount;
178 property Fields[Index: Integer]: TZFieldRef read GetField;
179 property TableCount: Integer read GetTableCount;
180 property Tables[Index: Integer]: TZTableRef read GetTable;
188 Creates a table reference object.
189 @param Catalog a catalog name.
190 @param Schema a schema name.
191 @param Table a table name.
192 @param Alias a table alias.
194 constructor TZTableRef.Create(const Catalog, Schema, Table, Alias: string);
203 Gets a full database table name.
204 @return a full database table name.
206 function TZTableRef.FullName: string;
208 Result := FCatalog + '.' + FSchema + '.' + FTable;
210 while (Result <> '') and (Result[1] = '.') do
211 Delete(Result, 1, 1);
217 Creates a field reference object.
218 @param IsField flag which separates table columns from expressions.
219 @param Catalog a catalog name.
220 @param Schema a schema name.
221 @param Table a table name.
222 @param Field a field name.
223 @param Alias a field alias.
225 constructor TZFieldRef.Create(IsField: Boolean; const Catalog, Schema, Table,
226 Field, Alias: string; TableRef: TZTableRef);
234 FTableRef := TableRef;
241 Constructs this assembly object and assignes the main properties.
243 constructor TZSelectSchema.Create;
245 FFields := TObjectList.Create;
246 FTables := TObjectList.Create;
250 Destroys this object and cleanups the memory.
252 destructor TZSelectSchema.Destroy;
259 Finds a table reference by catalog and table name.
260 @param Catalog a database catalog name.
261 @param Schema a database schema name.
262 @param Table a database table name.
263 @return a found table reference object or <code>null</code> otherwise.
265 function TZSelectSchema.FindTableByFullName(
266 const Catalog, Schema, Table: string): TZTableRef;
273 { Looks a table by it's full name. }
274 for I := 0 to FTables.Count - 1 do
276 Current := TZTableRef(FTables[I]);
277 if (Current.Schema = Schema) and (Current.Table = Table) then
284 { Looks a table by it's short name. }
285 for I := 0 to FTables.Count - 1 do
287 Current := TZTableRef(FTables[I]);
288 if (Current.Schema = '') and (Current.Table = Table) then
297 Finds a table reference by table name or table alias.
298 @param Table a database table name or alias.
299 @return a found table reference object or <code>null</code> otherwise.
301 function TZSelectSchema.FindTableByShortName(const Table: string): TZTableRef;
308 { Looks a table by it's alias. }
309 for I := 0 to FTables.Count - 1 do
311 Current := TZTableRef(FTables[I]);
312 if Current.Alias = Table then
319 { Looks a table by it's name. }
320 for I := 0 to FTables.Count - 1 do
322 Current := TZTableRef(FTables[I]);
323 if Current.Table = Table then
332 Finds a field reference by field name or field alias.
333 @param Field a table field name or alias.
334 @return a found field reference object or <code>null</code> otherwise.
336 function TZSelectSchema.FindFieldByShortName(const Field: string): TZFieldRef;
345 { Looks a field by it's alias. }
346 for I := 0 to FFields.Count - 1 do
348 Current := TZFieldRef(FFields[I]);
349 if Current.Alias = Field then
356 { Looks a field by it's name. }
357 for I := 0 to FFields.Count - 1 do
359 Current := TZFieldRef(FFields[I]);
360 if Current.Field = Field then
369 Links a field reference by index and/or field name or field alias.
370 @param ColumnIndex an index of the column.
371 @param Field a table field name or alias.
372 @return a found field reference object or <code>null</code> otherwise.
374 function TZSelectSchema.LinkFieldByIndexAndShortName(const ColumnIndex: Integer;
375 const Field: string; const Convertor: IZIdentifierConvertor): TZFieldRef;
384 { Looks by field index. }
385 if (ColumnIndex > 0) and (ColumnIndex <= FFields.Count) then
387 Current := TZFieldRef(FFields[ColumnIndex - 1]);
388 if not Current.Linked
389 //note http://sourceforge.net/p/zeoslib/tickets/101/
390 and ((Current.Alias = Field) or (Current.Field = Field) or (Current.Field = Convertor.Quote(Field))) then
393 Result.Linked := True;
398 { Looks a field by it's alias. }
399 for I := 0 to FFields.Count - 1 do
401 Current := TZFieldRef(FFields[I]);
402 if not Current.Linked and ((Current.Alias = Field) or (Current.Alias = Convertor.Quote(Field))) then
405 Result.Linked := True;
410 { Looks a field by field and table aliases. }
411 for I := 0 to FFields.Count - 1 do
413 Current := TZFieldRef(FFields[I]);
414 if not Current.Linked and Assigned(Current.TableRef)
415 and (((Current.TableRef.Alias + '.' + Current.Field) = Field)
416 or (((Current.TableRef.Table + '.' + Current.Field) = Field))) then
419 Result.Linked := True;
424 { Looks a field by it's name. }
425 for I := 0 to FFields.Count - 1 do
427 Current := TZFieldRef(FFields[I]);
428 if not Current.Linked and (Current.Field = Field) then
431 Result.Linked := True;
438 Convert all table and field identifiers..
439 @param Convertor an identifier convertor.
441 procedure TZSelectSchema.ConvertIdentifiers(Convertor: IZIdentifierConvertor);
444 function ExtractNeedlessQuote(Value : String) : String;
448 tempstring := Convertor.ExtractQuote(Value);
449 if Convertor.IsCaseSensitive(tempstring) then
452 result := tempstring;
456 if Convertor = nil then Exit;
458 for I := 0 to FFields.Count - 1 do
460 with TZFieldRef(FFields[I]) do
462 Catalog := ExtractNeedlessQuote(Catalog);
463 Schema := ExtractNeedlessQuote(Schema);
464 Table := ExtractNeedlessQuote(Table);
465 Field := ExtractNeedlessQuote(Field);
466 Alias := ExtractNeedlessQuote(Alias);
470 for I := 0 to FTables.Count - 1 do
472 with TZTableRef(FTables[I]) do
474 Catalog := ExtractNeedlessQuote(Catalog);
475 Schema := ExtractNeedlessQuote(Schema);
476 Table := ExtractNeedlessQuote(Table);
477 Alias := ExtractNeedlessQuote(Alias);
483 Links references between fields and tables.
484 @param Convertor an identifier convertor.
486 procedure TZSelectSchema.LinkReferences(Convertor: IZIdentifierConvertor);
489 FieldRef: TZFieldRef;
490 TableRef: TZTableRef;
491 TempFields: TObjectList;
493 ConvertIdentifiers(Convertor);
494 TempFields := FFields;
495 FFields := TObjectList.Create;
498 for I := 0 to TempFields.Count - 1 do
500 FieldRef := TZFieldRef(TempFields[I]);
503 if not FieldRef.IsField then
505 FFields.Add(TZFieldRef.Create(FieldRef.IsField, FieldRef.Catalog,
506 FieldRef.Schema, FieldRef.Table, FieldRef.Field, FieldRef.Alias,
510 else if (FieldRef.Schema <> '') and (FieldRef.Table <> '') then
512 TableRef := FindTableByFullName(FieldRef.Catalog, FieldRef.Schema,
515 else if FieldRef.Table <> '' then
516 TableRef := FindTableByShortName(FieldRef.Table)
517 else if FieldRef.Field = '*' then
519 { Add all fields from all tables. }
520 for J := 0 to FTables.Count - 1 do
522 with TZTableRef(FTables[J]) do
524 FFields.Add(TZFieldRef.Create(True, Catalog, Schema,
525 Table, '*', '', TZTableRef(FTables[J])));
531 if TableRef <> nil then
533 FFields.Add(TZFieldRef.Create(True, TableRef.Catalog, TableRef.Schema,
534 TableRef.Table, FieldRef.Field, FieldRef.Alias, TableRef));
538 FFields.Add(TZFieldRef.Create(True, FieldRef.Catalog, FieldRef.Schema,
539 FieldRef.Table, FieldRef.Field, FieldRef.Alias, TableRef));
548 Adds a new field to this select schema.
549 @param FieldRef a field reference object.
551 procedure TZSelectSchema.AddField(FieldRef: TZFieldRef);
553 FFields.Add(FieldRef);
557 Inserts a new field to this select schema.
558 @param Index an index where to insert a new field reference.
559 @param FieldRef a field reference object.
561 procedure TZSelectSchema.InsertField(Index: Integer; FieldRef: TZFieldRef);
563 FFields.Insert(Index, FieldRef);
567 Deletes a field from this select schema.
568 @param FieldRef a field reference object.
570 procedure TZSelectSchema.DeleteField(FieldRef: TZFieldRef);
572 FFields.Remove(FieldRef);
576 Adds a new table to this select schema.
577 @param TableRef a table reference object.
579 procedure TZSelectSchema.AddTable(TableRef: TZTableRef);
581 FTables.Add(TableRef);
585 Gets a field reference by index.
586 @param Index an index of the reference.
587 @returns a pointer to the field reference.
589 function TZSelectSchema.GetField(Index: Integer): TZFieldRef;
591 Result := TZFieldRef(FFields[Index]);
595 Gets a count of field references.
596 @returns a count of field references.
598 function TZSelectSchema.GetFieldCount: Integer;
600 Result := FFields.Count;
604 Gets a table reference by index.
605 @param Index an index of the reference.
606 @returns a pointer to the table reference.
608 function TZSelectSchema.GetTable(Index: Integer): TZTableRef;
610 Result := TZTableRef(FTables[Index]);
614 Gets a count of table references.
615 @returns a count of table references.
617 function TZSelectSchema.GetTableCount: Integer;
619 Result := FTables.Count;