zeoslib  UNKNOWN
 All Files
ZDbcResultSetMetadata.pas
Go to the documentation of this file.
1 {*********************************************************}
2 { }
3 { Zeos Database Objects }
4 { Abstract Database Connectivity Classes }
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 ZDbcResultSetMetadata;
53 
54 interface
55 
56 {$I ZDbc.inc}
57 
58 uses
59  Classes, SysUtils, Contnrs, ZDbcIntfs, ZClasses, ZCollections,
60  ZGenericSqlAnalyser,
61 {$IFDEF FPC}
62  {$IFDEF WIN32}
63  Comobj,
64  {$ENDIF}
65 {$ENDIF}
66  ZTokenizer, ZSelectSchema, ZCompatibility, ZDbcResultSet;
67 
68 type
69 
70  {** Implements a column information structure. }
71  TZColumnInfo = class(TObject)
72  protected
73  FAutoIncrement: Boolean;
74  FCaseSensitive: Boolean;
75  FSearchable: Boolean;
76  FCurrency: Boolean;
77  FNullable: TZColumnNullableType;
78  FSigned: Boolean;
79  FColumnDisplaySize: Integer;
80  FMaxLenghtBytes: Integer;
81  FColumnLabel: string;
82  FColumnName: string;
83  FSchemaName: string;
84  FPrecision: Integer;
85  FScale: Integer;
86  FTableName: string;
87  FCatalogName: string;
88  FColumnType: TZSQLType;
89  FInternalColumnType: TZSQLType;
90  FReadOnly: Boolean;
91  FWritable: Boolean;
92  FDefinitelyWritable: Boolean;
93  FDefaultValue: string;
94  FDefaultExpression : string;
95  public
96  constructor Create;
97  function GetColumnTypeName: string;
98 
99  property AutoIncrement: Boolean read FAutoIncrement write FAutoIncrement;
100  property CaseSensitive: Boolean read FCaseSensitive write FCaseSensitive;
101  property Searchable: Boolean read FSearchable write FSearchable;
102  property Currency: Boolean read FCurrency write FCurrency;
103  property Nullable: TZColumnNullableType read FNullable write FNullable;
104 
105  property Signed: Boolean read FSigned write FSigned;
106  property ColumnDisplaySize: Integer read FColumnDisplaySize
107  write FColumnDisplaySize;
108  property MaxLenghtBytes: Integer read FMaxLenghtBytes
109  write FMaxLenghtBytes;
110  property ColumnLabel: string read FColumnLabel write FColumnLabel;
111  property ColumnName: string read FColumnName write FColumnName;
112  property SchemaName: string read FSchemaName write FSchemaName;
113  property Precision: Integer read FPrecision write FPrecision;
114  property Scale: Integer read FScale write FScale;
115  property TableName: string read FTableName write FTableName;
116  property CatalogName: string read FCatalogName write FCatalogName;
117  property ColumnType: TZSQLType read FColumnType write FColumnType;
118  property InternalColumnType: TZSQLType read FInternalColumnType write FInternalColumnType;
119  property ReadOnly: Boolean read FReadOnly write FReadOnly;
120  property Writable: Boolean read FWritable write FWritable;
121  property DefinitelyWritable: Boolean read FDefinitelyWritable
122  write FDefinitelyWritable;
123  property DefaultValue: string read FDefaultValue write FDefaultValue;
124  property DefaultExpression: string read FDefaultExpression write FDefaultExpression;
125  end;
126 
127  {** Implements Abstract ResultSet Metadata. }
128  TZAbstractResultSetMetadata = class(TContainedObject, IZResultSetMetaData)
129  private
130  FLoaded: Boolean;
131  FMetadata: IZDatabaseMetadata;
132  FColumnsLabels: TStrings;
133  FSQL: string;
134  FTableColumns: TZHashMap;
135  FIdentifierConvertor: IZIdentifierConvertor;
136  FResultSet: TZAbstractResultSet;
137  procedure SetMetadata(const Value: IZDatabaseMetadata);
138  protected
139  procedure LoadColumn(ColumnIndex: Integer; ColumnInfo: TZColumnInfo;
140  SelectSchema: IZSelectSchema); virtual;
141 
142  function GetTableColumns(TableRef: TZTableRef): IZResultSet;
143  function ReadColumnByRef(FieldRef: TZFieldRef;
144  ColumnInfo: TZColumnInfo): Boolean;
145  function ReadColumnByName(FieldName: string; TableRef: TZTableRef;
146  ColumnInfo: TZColumnInfo): Boolean;
147  procedure ClearColumn(ColumnInfo: TZColumnInfo);
148  procedure LoadColumns;
149  procedure ReplaceStarColumns(SelectSchema: IZSelectSchema);
150 
151  property MetaData: IZDatabaseMetadata read FMetadata write SetMetadata;
152  property ColumnsLabels: TStrings read FColumnsLabels write FColumnsLabels;
153  property SQL: string read FSQL write FSQL;
154  property IdentifierConvertor: IZIdentifierConvertor
155  read FIdentifierConvertor write FIdentifierConvertor;
156  property Loaded: Boolean read FLoaded write FLoaded;
157  property ResultSet: TZAbstractResultSet read FResultSet write FResultSet;
158  public
159  constructor Create(Metadata: IZDatabaseMetadata; SQL: string;
160  ParentResultSet: TZAbstractResultSet);
161  destructor Destroy; override;
162 
163  function GetColumnCount: Integer; virtual;
164  function IsAutoIncrement(Column: Integer): Boolean; virtual;
165  function IsCaseSensitive(Column: Integer): Boolean; virtual;
166  function IsSearchable(Column: Integer): Boolean; virtual;
167  function IsCurrency(Column: Integer): Boolean; virtual;
168  function IsNullable(Column: Integer): TZColumnNullableType; virtual;
169 
170  function IsSigned(Column: Integer): Boolean; virtual;
171  function GetColumnDisplaySize(Column: Integer): Integer; virtual;
172  function GetColumnLabel(Column: Integer): string; virtual;
173  function GetColumnName(Column: Integer): string; virtual;
174  function GetSchemaName(Column: Integer): string; virtual;
175  function GetPrecision(Column: Integer): Integer; virtual;
176  function GetScale(Column: Integer): Integer; virtual;
177  function GetTableName(Column: Integer): string; virtual;
178  function GetCatalogName(Column: Integer): string; virtual;
179  function GetColumnType(Column: Integer): TZSQLType; virtual;
180  function GetColumnTypeName(Column: Integer): string; virtual;
181  function IsReadOnly(Column: Integer): Boolean; virtual;
182  function IsWritable(Column: Integer): Boolean; virtual;
183  function IsDefinitelyWritable(Column: Integer): Boolean; virtual;
184  function GetDefaultValue(Column: Integer): string; virtual;
185  function HasDefaultValue(Column: Integer): Boolean; virtual;
186  end;
187 
188 implementation
189 
190 uses ZVariant, ZDbcUtils, ZDbcMetadata;
191 
192 { TZColumnInfo }
193 
194 {**
195  Constructs this object and assigns main properties.
196 }
197 constructor TZColumnInfo.Create;
198 begin
199  FAutoIncrement := False;
200  FCaseSensitive := False;
201  FSearchable := False;
202  FCurrency := False;
203  FNullable := ntNullableUnknown;
204  FSigned := False;
205  FColumnDisplaySize := 0;
206  FColumnLabel := '';
207  FColumnName := '';
208  FSchemaName := '';
209  FPrecision := 0;
210  FScale := 0;
211  FTableName := '';
212  FCatalogName := '';
213  FDefaultValue := '';
214  FColumnType := stUnknown;
215  FInternalColumnType := stUnknown;
216  FReadOnly := True;
217  FWritable := False;
218  FDefinitelyWritable := False;
219 end;
220 
221 {**
222  Retrieves the designated column's database-specific type name.
223  @return type name used by the database. If the column type is
224  a user-defined type, then a fully-qualified type name is returned.
225 }
226 function TZColumnInfo.GetColumnTypeName: string;
227 begin
228  Result := DefineColumnTypeName(FColumnType);
229 end;
230 
231 { TZAbstractResultSetMetadata }
232 
233 {**
234  Constructs this object and assignes the main properties.
235  @param Metadata a database metadata object.
236  @param SQL an SQL query statement.
237  @param ColumnsInfo a collection of columns info.
238 }
239 constructor TZAbstractResultSetMetadata.Create(Metadata: IZDatabaseMetadata;
240  SQL: string; ParentResultSet: TZAbstractResultSet);
241 begin
242  inherited Create(ParentResultSet);
243 
244  SetMetadata(Metadata);
245  FSQL := SQL;
246  FLoaded := not (FMetadata <> nil);
247  FTableColumns := TZHashMap.Create;
248  FResultSet := ParentResultSet;
249 end;
250 
251 {**
252  Destroys this object and cleanups the memory.
253 }
254 destructor TZAbstractResultSetMetadata.Destroy;
255 begin
256  FIdentifierConvertor := nil;
257  FMetadata := nil;
258  if Assigned(FTableColumns) then
259  begin
260  FTableColumns.Clear;
261  FTableColumns.Free;
262  end;
263  FTableColumns := nil;
264  if FColumnsLabels <> nil then
265  FColumnsLabels.Free;
266  inherited Destroy;
267 end;
268 
269 {**
270  Returns the number of columns in this <code>ResultSet</code> object.
271  @return the number of columns
272 }
273 function TZAbstractResultSetMetadata.GetColumnCount: Integer;
274 begin
275  Result := FResultSet.ColumnsInfo.Count;
276 end;
277 
278 {**
279  Indicates whether the designated column is automatically numbered, thus read-only.
280  @param column the first column is 1, the second is 2, ...
281  @return <code>true</code> if so; <code>false</code> otherwise
282 }
283 function TZAbstractResultSetMetadata.IsAutoIncrement(Column: Integer): Boolean;
284 begin
285  if not Loaded then
286  LoadColumns;
287  Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).AutoIncrement;
288 end;
289 
290 {**
291  Indicates whether a column's case matters.
292  @param column the first column is 1, the second is 2, ...
293  @return <code>true</code> if so; <code>false</code> otherwise
294 }
295 function TZAbstractResultSetMetadata.IsCaseSensitive(Column: Integer): Boolean;
296 begin
297  if not Loaded then
298  LoadColumns;
299  Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).CaseSensitive;
300 end;
301 
302 {**
303  Indicates whether the designated column can be used in a where clause.
304  @param column the first column is 1, the second is 2, ...
305  @return <code>true</code> if so; <code>false</code> otherwise
306 }
307 function TZAbstractResultSetMetadata.IsSearchable(Column: Integer): Boolean;
308 begin
309  if not Loaded then
310  LoadColumns;
311  Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).Searchable;
312 end;
313 
314 {**
315  Indicates whether the designated column is a cash value.
316  @param column the first column is 1, the second is 2, ...
317  @return <code>true</code> if so; <code>false</code> otherwise
318 }
319 function TZAbstractResultSetMetadata.IsCurrency(Column: Integer): Boolean;
320 begin
321  Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).Currency;
322 end;
323 
324 {**
325  Indicates the nullability of values in the designated column.
326  @param column the first column is 1, the second is 2, ...
327  @return the nullability status of the given column; one of <code>columnNoNulls</code>,
328  <code>columnNullable</code> or <code>columnNullableUnknown</code>
329 }
330 function TZAbstractResultSetMetadata.IsNullable(
331  Column: Integer): TZColumnNullableType;
332 begin
333  if not Loaded then
334  LoadColumns;
335  Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).Nullable;
336 end;
337 
338 {**
339  Indicates whether values in the designated column are signed numbers.
340  @param column the first column is 1, the second is 2, ...
341  @return <code>true</code> if so; <code>false</code> otherwise
342 }
343 function TZAbstractResultSetMetadata.IsSigned(Column: Integer): Boolean;
344 begin
345  Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).Signed;
346 end;
347 
348 {**
349  Indicates the designated column's normal maximum width in characters.
350  @param column the first column is 1, the second is 2, ...
351  @return the normal maximum number of characters allowed as the width
352  of the designated column
353 }
354 function TZAbstractResultSetMetadata.GetColumnDisplaySize(
355  Column: Integer): Integer;
356 begin
357  Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).ColumnDisplaySize;
358 end;
359 
360 {**
361  Gets the designated column's suggested title for use in printouts and
362  displays.
363  @param column the first column is 1, the second is 2, ...
364  @return the suggested column title
365 }
366 function TZAbstractResultSetMetadata.GetColumnLabel(Column: Integer): string;
367 var
368  I, J, N: Integer;
369  ColumnName: string;
370  ColumnsInfo: TObjectList;
371 begin
372  { Prepare unique column labels. }
373  if FColumnsLabels = nil then
374  begin
375  ColumnsInfo := FResultSet.ColumnsInfo;
376  FColumnsLabels := TStringList.Create;
377  for I := 0 to ColumnsInfo.Count - 1 do
378  begin
379  N := 0;
380  ColumnName := TZColumnInfo(ColumnsInfo[I]).ColumnLabel;
381  for J := 0 to I - 1 do
382  begin
383  if TZColumnInfo(ColumnsInfo[J]).ColumnLabel = ColumnName then
384  Inc(N);
385  end;
386  if ColumnName = '' then
387  ColumnName := 'Column';
388  if N > 0 then
389  ColumnName := ColumnName + '_' + IntToStr(N);
390  FColumnsLabels.Add(ColumnName);
391  end;
392  end;
393 
394  Result := ColumnsLabels[Column - 1];
395 end;
396 
397 {**
398  Get the designated column's name.
399  @param column the first column is 1, the second is 2, ...
400  @return column name
401 }
402 function TZAbstractResultSetMetadata.GetColumnName(
403  Column: Integer): string;
404 begin
405  if not Loaded then
406  LoadColumns;
407  Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).ColumnName;
408 end;
409 
410 {**
411  Get the designated column's table's schema.
412  @param column the first column is 1, the second is 2, ...
413  @return schema name or "" if not applicable
414 }
415 function TZAbstractResultSetMetadata.GetSchemaName(
416  Column: Integer): string;
417 begin
418  if not Loaded then
419  LoadColumns;
420  Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).SchemaName;
421 end;
422 
423 {**
424  Get the designated column's number of decimal digits.
425  @param column the first column is 1, the second is 2, ...
426  @return precision
427 }
428 function TZAbstractResultSetMetadata.GetPrecision(Column: Integer): Integer;
429 begin
430  Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).Precision;
431 end;
432 
433 {**
434  Gets the designated column's number of digits to right of the decimal point.
435  @param column the first column is 1, the second is 2, ...
436  @return scale
437 }
438 function TZAbstractResultSetMetadata.GetScale(Column: Integer): Integer;
439 begin
440  Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).Scale;
441 end;
442 
443 {**
444  Gets the designated column's table name.
445  @param column the first column is 1, the second is 2, ...
446  @return table name or "" if not applicable
447 }
448 function TZAbstractResultSetMetadata.GetTableName(Column: Integer): string;
449 begin
450  if not Loaded then
451  LoadColumns;
452  Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).TableName;
453 end;
454 
455 {**
456  Gets the designated column's table's catalog name.
457  @param column the first column is 1, the second is 2, ...
458  @return column name or "" if not applicable
459 }
460 function TZAbstractResultSetMetadata.GetCatalogName(Column: Integer): string;
461 begin
462  if not Loaded then
463  LoadColumns;
464  Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).CatalogName;
465 end;
466 
467 {**
468  Retrieves the designated column's SQL type.
469  @param column the first column is 1, the second is 2, ...
470  @return SQL type from java.sql.Types
471 }
472 function TZAbstractResultSetMetadata.GetColumnType(Column: Integer): TZSQLType;
473 begin
474  Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).ColumnType;
475 end;
476 
477 {**
478  Retrieves the designated column's database-specific type name.
479 
480  @param column the first column is 1, the second is 2, ...
481  @return type name used by the database. If the column type is
482  a user-defined type, then a fully-qualified type name is returned.
483 }
484 function TZAbstractResultSetMetadata.GetColumnTypeName(Column: Integer): string;
485 begin
486  Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).GetColumnTypeName;
487 end;
488 
489 {**
490  Indicates whether the designated column is definitely not writable.
491  @param column the first column is 1, the second is 2, ...
492  @return <code>true</code> if so; <code>false</code> otherwise
493 }
494 function TZAbstractResultSetMetadata.IsReadOnly(Column: Integer): Boolean;
495 begin
496  if not Loaded then
497  LoadColumns;
498  Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).ReadOnly;
499 end;
500 
501 {**
502  Indicates whether it is possible for a write on the designated column to succeed.
503  @param column the first column is 1, the second is 2, ...
504  @return <code>true</code> if so; <code>false</code> otherwise
505 }
506 function TZAbstractResultSetMetadata.IsWritable(Column: Integer): Boolean;
507 begin
508  if not Loaded then
509  LoadColumns;
510  Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).Writable;
511 end;
512 
513 {**
514  Indicates whether a write on the designated column will definitely succeed.
515  @param column the first column is 1, the second is 2, ...
516  @return <code>true</code> if so; <code>false</code> otherwise
517 }
518 function TZAbstractResultSetMetadata.IsDefinitelyWritable(
519  Column: Integer): Boolean;
520 begin
521  if not Loaded then
522  LoadColumns;
523  Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).DefinitelyWritable;
524 end;
525 
526 {**
527  Gets a default value for this field.
528  @param column the first column is 1, the second is 2, ...
529  @return a default value for this field.
530 }
531 function TZAbstractResultSetMetadata.GetDefaultValue(
532  Column: Integer): string;
533 begin
534  if not Loaded then
535  LoadColumns;
536  Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).DefaultValue;
537 end;
538 
539 {**
540  Finds whether this field has a default value.
541  @param column the first column is 1, the second is 2, ...
542  @return true if this field has a default value.
543 }
544 function TZAbstractResultSetMetadata.HasDefaultValue(
545  Column: Integer): Boolean;
546 begin
547  if not Loaded then
548  LoadColumns;
549  // '' = NULL / no default value, '''''' = empty string (''), etc.
550  Result := not(TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).DefaultValue = '');
551 end;
552 
553 {**
554  Gets a table description result set.
555  @param TableRef a table reference object.
556  @return a result set with table columns from database metadata.
557 }
558 function TZAbstractResultSetMetadata.GetTableColumns(
559  TableRef: TZTableRef): IZResultSet;
560 var
561  TableKey: IZAnyValue;
562 begin
563  TableKey := TZAnyValue.CreateWithString(TableRef.FullName);
564  if FTableColumns.Get(TableKey) = nil then
565  begin
566  Result := Metadata.GetColumns(TableRef.Catalog,
567  TableRef.Schema, TableRef.Table, '');
568  FTableColumns.Put(TableKey, Result);
569  end
570  else
571  Result := FTableColumns.Get(TableKey) as IZResultSet;
572 end;
573 
574 {**
575  Clears specified column information.
576  @param ColumnInfo a column information object.
577 }
578 procedure TZAbstractResultSetMetadata.ClearColumn(ColumnInfo: TZColumnInfo);
579 begin
580  ColumnInfo.ReadOnly := True;
581  ColumnInfo.Writable := False;
582  ColumnInfo.DefinitelyWritable := False;
583  ColumnInfo.CatalogName := '';
584  ColumnInfo.SchemaName := '';
585  ColumnInfo.TableName := '';
586  ColumnInfo.ColumnName := '';
587 end;
588 
589 {**
590  Reads a column information from table metadata.
591  @param FieldName a name of the field.
592  @param TableRef a table reference object.
593  @param ColumnInfo a column information object.
594  @return <code>True</code> is column was found and read.
595 }
596 function TZAbstractResultSetMetadata.ReadColumnByName(FieldName: string;
597  TableRef: TZTableRef; ColumnInfo: TZColumnInfo): Boolean;
598 var
599  TableColumns: IZResultSet;
600  tempColType: TZSQLType;
601 begin
602  Result := False;
603  TableColumns := GetTableColumns(TableRef);
604  { Checks for unexisted table. }
605  if not Assigned(TableColumns) then
606  Exit;
607 
608  { Locates a column row. }
609  TableColumns.BeforeFirst;
610  while TableColumns.Next do
611  if TableColumns.GetString(4) = FieldName then
612  Break;
613  if TableColumns.IsAfterLast then
614  begin
615  { Locates a column row with case insensitivity. }
616  TableColumns.BeforeFirst;
617  while TableColumns.Next do
618  if AnsiUpperCase(TableColumns.GetString(4)) = AnsiUpperCase(FieldName) then
619  Break;
620  if TableColumns.IsAfterLast then
621  Exit;
622  end;
623 
624  { Reads a column information. }
625  Result := True;
626  ColumnInfo.CatalogName := TableColumns.GetString(1);
627  ColumnInfo.SchemaName := TableColumns.GetString(2);
628  ColumnInfo.TableName := TableColumns.GetString(3);
629  ColumnInfo.ColumnName := FieldName;
630 
631 //If the returned column information is null then the value assigned during
632 //the resultset.open will be kept
633  if not TableColumns.IsNull(5) then
634  begin
635  //since Pointer referencing by RowAccessor we've a pointer and GetBlob
636  //raises an exception if the pointer is a reference to PPAnsiChar or
637  //ZPPWideChar. if we execute a cast of a lob field the database meta-informtions
638  //assume a IZLob-Pointer. So let's prevent this case and check for
639  //stByte, stString, stUnicoeString first. If this type is returned from the
640  //ResultSet-Metadata we do NOT overwrite the column-type
641  //f.e. select cast( name as varchar(100)), cast(setting as varchar(100)) from pg_settings
642 
643  //or the same vice versa:
644  //(CASE WHEN (Ticket51_B."Name" IS NOT NULL) THEN Ticket51_B."Name" ELSE 'Empty' END) As "Name"
645  //we've NO fixed length for a case(postgres and FB2.5up f.e.) select
646  tempColType := TZSQLType(TableColumns.GetShort(5));
647  if not (TZSQLType(TableColumns.GetShort(5)) in [stBinaryStream, stAsciiStream,
648  stUnicodeStream, stBytes, stString, stUnicodeString]) then
649  ColumnInfo.ColumnType := tempColType;
650  end;
651  if not TableColumns.IsNull(11) then
652  ColumnInfo.Nullable := TZColumnNullableType(TableColumns.GetInt(11));
653  if not TableColumns.IsNull(19) then
654  ColumnInfo.AutoIncrement := TableColumns.GetBoolean(19);
655  if not TableColumns.IsNull(20) then
656  ColumnInfo.CaseSensitive := TableColumns.GetBoolean(20);
657  if not TableColumns.IsNull(21) then
658  ColumnInfo.Searchable := TableColumns.GetBoolean(21);
659  if not TableColumns.IsNull(22) then
660  if ColumnInfo.AutoIncrement and Assigned(FMetadata) then {improve ADO where the metainformations do not bring autoincremental fields through}
661  if FMetadata.GetDatabaseInfo.SupportsUpdateAutoIncrementFields then
662  ColumnInfo.Writable := TableColumns.GetBoolean(22)
663  else
664  ColumnInfo.Writable := False
665  else
666  ColumnInfo.Writable := TableColumns.GetBoolean(22);
667  if not TableColumns.IsNull(23) then
668  if ColumnInfo.AutoIncrement and Assigned(FMetadata) then {improve ADO where the metainformations do not bring autoincremental fields through}
669  if FMetadata.GetDatabaseInfo.SupportsUpdateAutoIncrementFields then
670  ColumnInfo.DefinitelyWritable := TableColumns.GetBoolean(23)
671  else
672  ColumnInfo.DefinitelyWritable := False
673  else
674  ColumnInfo.DefinitelyWritable := TableColumns.GetBoolean(23);
675  if not TableColumns.IsNull(24) then
676  if ColumnInfo.AutoIncrement and Assigned(FMetadata) then {improve ADO where the metainformations do not bring autoincremental fields through}
677  if FMetadata.GetDatabaseInfo.SupportsUpdateAutoIncrementFields then
678  ColumnInfo.ReadOnly := TableColumns.GetBoolean(24)
679  else
680  ColumnInfo.ReadOnly := True
681  else
682  ColumnInfo.ReadOnly := TableColumns.GetBoolean(24);
683  if not TableColumns.IsNull(13) then
684  ColumnInfo.DefaultValue := TableColumns.GetString(13);
685 end;
686 
687 {**
688  Reads a column information from table metadata.
689  @param FieldRef a field reference object.
690  @param ColumnInfo a column information object.
691  @return <code>True</code> if column was found and read.
692 }
693 function TZAbstractResultSetMetadata.ReadColumnByRef(
694  FieldRef: TZFieldRef; ColumnInfo: TZColumnInfo): Boolean;
695 begin
696  Result := False;
697  ClearColumn(ColumnInfo);
698  { Checks for uncompleted field reference. }
699  if not Assigned(FieldRef) or not Assigned(FieldRef.TableRef) then
700  Exit;
701  if not FieldRef.IsField then
702  Exit;
703 
704  Result := ReadColumnByName(FieldRef.Field, FieldRef.TableRef, ColumnInfo);
705 end;
706 
707 {**
708  Initializes on single column of the result set.
709  @param ColumnIndex a column index in the query.
710  @param ColumnInfo a column information object to be initialized.
711  @param SelectSchema a schema of the select statement.
712 }
713 procedure TZAbstractResultSetMetadata.LoadColumn(ColumnIndex: Integer;
714  ColumnInfo: TZColumnInfo; SelectSchema: IZSelectSchema);
715 var
716  I: Integer;
717  FieldRef: TZFieldRef;
718  TableRef: TZTableRef;
719  Found: Boolean;
720 begin
721  { Initializes single columns with specified table. }
722  FieldRef := SelectSchema.LinkFieldByIndexAndShortName(ColumnIndex,
723  ColumnInfo.ColumnLabel, IdentifierConvertor);
724  ReadColumnByRef(FieldRef, ColumnInfo);
725  if ColumnInfo.ColumnName <> '' then
726  Exit;
727 
728  { Initializes single columns without specified table. }
729  I := 0;
730  Found := False;
731  while (ColumnInfo.ColumnName = '') and (I < SelectSchema.TableCount)
732  and not Found do
733  begin
734  TableRef := SelectSchema.Tables[I];
735  if Assigned(FieldRef) then
736  Found := ReadColumnByName(IdentifierConvertor.ExtractQuote(FieldRef.Field), TableRef, ColumnInfo)
737  else
738  Found := ReadColumnByName(IdentifierConvertor.ExtractQuote(ColumnInfo.ColumnLabel), TableRef, ColumnInfo);
739  Inc(I);
740  end;
741 end;
742 
743 {**
744  Replaces '*' columns in the select schema.
745  @param SelectSchema a query select schema.
746 }
747 procedure TZAbstractResultSetMetadata.ReplaceStarColumns(
748  SelectSchema: IZSelectSchema);
749 var
750  I: Integer;
751  Current: TZFieldRef;
752  FieldRef: TZFieldRef;
753  TableRef: TZTableRef;
754  ResultSet: IZResultSet;
755 begin
756  I := 0;
757  while I < SelectSchema.FieldCount do
758  begin
759  Current := SelectSchema.Fields[I];
760  if (Current.Field = '*') and (Current.TableRef <> nil) then
761  begin
762  TableRef := Current.TableRef;
763  ResultSet := Self.GetTableColumns(TableRef);
764  if ResultSet <> nil then
765  begin
766  ResultSet.BeforeFirst;
767  while ResultSet.Next do
768  begin
769  FieldRef := TZFieldRef.Create(True, TableRef.Catalog, TableRef.Schema,
770  TableRef.Table, ResultSet.GetString(4), '', TableRef);
771  SelectSchema.InsertField(I, FieldRef);
772  Inc(I);
773  end;
774  end;
775  SelectSchema.DeleteField(Current);
776  Dec(I);
777  end;
778  Inc(I);
779  end;
780 end;
781 
782 procedure TZAbstractResultSetMetadata.SetMetadata(
783  const Value: IZDatabaseMetadata);
784 begin
785  FMetadata := Value;
786  if Value<>nil then
787  FIdentifierConvertor := Value.GetIdentifierConvertor
788  else
789  FIdentifierConvertor := TZDefaultIdentifierConvertor.Create(FMetadata);
790 end;
791 
792 {**
793  Initializes columns with additional data.
794 }
795 procedure TZAbstractResultSetMetadata.LoadColumns;
796 var
797  I: Integer;
798  Driver: IZDriver;
799  Tokenizer: IZTokenizer;
800  StatementAnalyser: IZStatementAnalyser;
801  SelectSchema: IZSelectSchema;
802  FillByIndices: Boolean;
803 begin
804  { Parses the Select statement and retrieves a schema object. }
805  Driver := Metadata.GetConnection.GetDriver;
806  Tokenizer := Driver.GetTokenizer;
807  StatementAnalyser := Driver.GetStatementAnalyser;
808  SelectSchema := StatementAnalyser.DefineSelectSchemaFromQuery(Tokenizer, SQL);
809  if Assigned(SelectSchema) then
810  begin
811  SelectSchema.LinkReferences(IdentifierConvertor);
812  ReplaceStarColumns(SelectSchema);
813  FillByIndices := SelectSchema.FieldCount = FResultSet.ColumnsInfo.Count;
814  for I := 0 to FResultSet.ColumnsInfo.Count - 1 do
815  begin
816  if FillByIndices then
817  LoadColumn(I + 1, TZColumnInfo(FResultSet.ColumnsInfo[I]), SelectSchema)
818  else
819  LoadColumn(-1, TZColumnInfo(FResultSet.ColumnsInfo[I]), SelectSchema);
820  end;
821  end;
822  Loaded := True;
823 end;
824 
825 end.
826