00001 {*********************************************************}
00002 { }
00003 { Zeos Database Objects }
00004 { Abstract Database Connectivity Classes }
00005 { }
00006 { Originally written by Sergey Seroukhov }
00007 { }
00008 {*********************************************************}
00009
00010 {@********************************************************}
00011 { Copyright (c) 1999-2006 Zeos Development Group }
00012 { }
00013 { License Agreement: }
00014 { }
00015 { This library is distributed in the hope that it will be }
00016 { useful, but WITHOUT ANY WARRANTY; without even the }
00017 { implied warranty of MERCHANTABILITY or FITNESS FOR }
00018 { A PARTICULAR PURPOSE. See the GNU Lesser General }
00019 { Public License for more details. }
00020 { }
00021 { The source code of the ZEOS Libraries and packages are }
00022 { distributed under the Library GNU General Public }
00023 { License (see the file COPYING / COPYING.ZEOS) }
00024 { with the following modification: }
00025 { As a special exception, the copyright holders of this }
00026 { library give you permission to link this library with }
00027 { independent modules to produce an executable, }
00028 { regardless of the license terms of these independent }
00029 { modules, and to copy and distribute the resulting }
00030 { executable under terms of your choice, provided that }
00031 { you also meet, for each linked independent module, }
00032 { the terms and conditions of the license of that module. }
00033 { An independent module is a module which is not derived }
00034 { from or based on this library. If you modify this }
00035 { library, you may extend this exception to your version }
00036 { of the library, but you are not obligated to do so. }
00037 { If you do not wish to do so, delete this exception }
00038 { statement from your version. }
00039 { }
00040 { }
00041 { The project web site is located on: }
00042 { http:
00043 { http:
00044 { svn:
00045 { }
00046 { http:
00047 { http:
00048 { }
00049 { }
00050 { }
00051 { Zeos Development Group. }
00052 {********************************************************@}
00053
00054 unit ZDbcResultSetMetadata;
00055
00056 interface
00057
00058 {$I ZDbc.inc}
00059
00060 uses
00061 Classes, SysUtils, Contnrs, ZDbcIntfs, ZClasses, ZCollections,
00062 ZGenericSqlAnalyser,
00063 {$IFDEF VER130BELOW}
00064 {$IFDEF WIN32}
00065 Comobj,
00066 {$ENDIF}
00067 {$ENDIF}
00068 ZTokenizer, ZSelectSchema, ZCompatibility, ZDbcResultSet;
00069
00070 type
00071
00072 {** Implements a column information structure. }
00073 TZColumnInfo = class(TObject)
00074 protected
00075 FAutoIncrement: Boolean;
00076 FCaseSensitive: Boolean;
00077 FSearchable: Boolean;
00078 FCurrency: Boolean;
00079 FNullable: TZColumnNullableType;
00080 FSigned: Boolean;
00081 FColumnDisplaySize: Integer;
00082 FColumnLabel: string;
00083 FColumnName: string;
00084 FSchemaName: string;
00085 FPrecision: Integer;
00086 FScale: Integer;
00087 FTableName: string;
00088 FCatalogName: string;
00089 FColumnType: TZSQLType;
00090 FReadOnly: Boolean;
00091 FWritable: Boolean;
00092 FDefinitelyWritable: Boolean;
00093 FDefaultValue: string;
00094 public
00095 constructor Create;
00096 function GetColumnTypeName: string;
00097
00098 property AutoIncrement: Boolean read FAutoIncrement write FAutoIncrement;
00099 property CaseSensitive: Boolean read FCaseSensitive write FCaseSensitive;
00100 property Searchable: Boolean read FSearchable write FSearchable;
00101 property Currency: Boolean read FCurrency write FCurrency;
00102 property Nullable: TZColumnNullableType read FNullable write FNullable;
00103
00104 property Signed: Boolean read FSigned write FSigned;
00105 property ColumnDisplaySize: Integer read FColumnDisplaySize
00106 write FColumnDisplaySize;
00107 property ColumnLabel: string read FColumnLabel write FColumnLabel;
00108 property ColumnName: string read FColumnName write FColumnName;
00109 property SchemaName: string read FSchemaName write FSchemaName;
00110 property Precision: Integer read FPrecision write FPrecision;
00111 property Scale: Integer read FScale write FScale;
00112 property TableName: string read FTableName write FTableName;
00113 property CatalogName: string read FCatalogName write FCatalogName;
00114 property ColumnType: TZSQLType read FColumnType write FColumnType;
00115 property ReadOnly: Boolean read FReadOnly write FReadOnly;
00116 property Writable: Boolean read FWritable write FWritable;
00117 property DefinitelyWritable: Boolean read FDefinitelyWritable
00118 write FDefinitelyWritable;
00119 property DefaultValue: string read FDefaultValue write FDefaultValue;
00120 end;
00121
00122 {** Implements Abstract ResultSet Metadata. }
00123 TZAbstractResultSetMetadata = class(TContainedObject, IZResultSetMetaData)
00124 private
00125 FLoaded: Boolean;
00126 FMetadata: IZDatabaseMetadata;
00127 FColumnsLabels: TStrings;
00128 FSQL: string;
00129 FTableColumns: TZHashMap;
00130 FIdentifierConvertor: IZIdentifierConvertor;
00131 FResultSet: TZAbstractResultSet;
00132 protected
00133 procedure LoadColumn(ColumnIndex: Integer; ColumnInfo: TZColumnInfo;
00134 SelectSchema: IZSelectSchema); virtual;
00135
00136 function GetTableColumns(TableRef: TZTableRef): IZResultSet;
00137 function ReadColumnByRef(FieldRef: TZFieldRef;
00138 ColumnInfo: TZColumnInfo): Boolean;
00139 function ReadColumnByName(FieldName: string; TableRef: TZTableRef;
00140 ColumnInfo: TZColumnInfo): Boolean;
00141 procedure ClearColumn(ColumnInfo: TZColumnInfo);
00142 procedure LoadColumns;
00143 procedure ReplaceStarColumns(SelectSchema: IZSelectSchema);
00144
00145 property MetaData: IZDatabaseMetadata read FMetadata write FMetadata;
00146 property ColumnsLabels: TStrings read FColumnsLabels write FColumnsLabels;
00147 property SQL: string read FSQL write FSQL;
00148 property IdentifierConvertor: IZIdentifierConvertor
00149 read FIdentifierConvertor write FIdentifierConvertor;
00150 property Loaded: Boolean read FLoaded write FLoaded;
00151 property ResultSet: TZAbstractResultSet read FResultSet write FResultSet;
00152 public
00153 constructor Create(Metadata: IZDatabaseMetadata; SQL: string;
00154 ParentResultSet: TZAbstractResultSet);
00155 destructor Destroy; override;
00156
00157 function GetColumnCount: Integer; virtual;
00158 function IsAutoIncrement(Column: Integer): Boolean; virtual;
00159 function IsCaseSensitive(Column: Integer): Boolean; virtual;
00160 function IsSearchable(Column: Integer): Boolean; virtual;
00161 function IsCurrency(Column: Integer): Boolean; virtual;
00162 function IsNullable(Column: Integer): TZColumnNullableType; virtual;
00163
00164 function IsSigned(Column: Integer): Boolean; virtual;
00165 function GetColumnDisplaySize(Column: Integer): Integer; virtual;
00166 function GetColumnLabel(Column: Integer): string; virtual;
00167 function GetColumnName(Column: Integer): string; virtual;
00168 function GetSchemaName(Column: Integer): string; virtual;
00169 function GetPrecision(Column: Integer): Integer; virtual;
00170 function GetScale(Column: Integer): Integer; virtual;
00171 function GetTableName(Column: Integer): string; virtual;
00172 function GetCatalogName(Column: Integer): string; virtual;
00173 function GetColumnType(Column: Integer): TZSQLType; virtual;
00174 function GetColumnTypeName(Column: Integer): string; virtual;
00175 function IsReadOnly(Column: Integer): Boolean; virtual;
00176 function IsWritable(Column: Integer): Boolean; virtual;
00177 function IsDefinitelyWritable(Column: Integer): Boolean; virtual;
00178 function GetDefaultValue(Column: Integer): string; virtual;
00179 function HasDefaultValue(Column: Integer): Boolean; virtual;
00180 end;
00181
00182 implementation
00183
00184 uses ZVariant, ZDbcUtils, ZDbcMetadata, ZSysUtils;
00185
00186 { TZColumnInfo }
00187
00188 {**
00189 Constructs this object and assigns main properties.
00190 }
00191 constructor TZColumnInfo.Create;
00192 begin
00193 FAutoIncrement := False;
00194 FCaseSensitive := False;
00195 FSearchable := False;
00196 FCurrency := False;
00197 FNullable := ntNullableUnknown;
00198 FSigned := False;
00199 FColumnDisplaySize := 0;
00200 FColumnLabel := '';
00201 FColumnName := '';
00202 FSchemaName := '';
00203 FPrecision := 0;
00204 FScale := 0;
00205 FTableName := '';
00206 FCatalogName := '';
00207 FDefaultValue := '';
00208 FColumnType := stUnknown;
00209 FReadOnly := True;
00210 FWritable := False;
00211 FDefinitelyWritable := False;
00212 end;
00213
00214 {**
00215 Retrieves the designated column's database-specific type name.
00216 @return type name used by the database. If the column type is
00217 a user-defined type, then a fully-qualified type name is returned.
00218 }
00219 function TZColumnInfo.GetColumnTypeName: string;
00220 begin
00221 Result := DefineColumnTypeName(FColumnType);
00222 end;
00223
00224 { TZAbstractResultSetMetadata }
00225
00226 {**
00227 Constructs this object and assignes the main properties.
00228 @param Metadata a database metadata object.
00229 @param SQL an SQL query statement.
00230 @param ColumnsInfo a collection of columns info.
00231 }
00232 constructor TZAbstractResultSetMetadata.Create(Metadata: IZDatabaseMetadata;
00233 SQL: string; ParentResultSet: TZAbstractResultSet);
00234 begin
00235 inherited Create(ParentResultSet);
00236
00237 FMetadata := Metadata;
00238 FSQL := SQL;
00239 FLoaded := not (FMetadata <> nil);
00240 FTableColumns := TZHashMap.Create;
00241 FIdentifierConvertor := TZDefaultIdentifierConvertor.Create(FMetadata);
00242 FResultSet := ParentResultSet;
00243 end;
00244
00245 {**
00246 Destroys this object and cleanups the memory.
00247 }
00248 destructor TZAbstractResultSetMetadata.Destroy;
00249 begin
00250 FIdentifierConvertor := nil;
00251 FMetadata := nil;
00252 if Assigned(FTableColumns) then
00253 begin
00254 FTableColumns.Clear;
00255 FTableColumns.Free;
00256 end;
00257 FTableColumns := nil;
00258 if FColumnsLabels <> nil then
00259 FColumnsLabels.Free;
00260 inherited Destroy;
00261 end;
00262
00263 {**
00264 Returns the number of columns in this <code>ResultSet</code> object.
00265 @return the number of columns
00266 }
00267 function TZAbstractResultSetMetadata.GetColumnCount: Integer;
00268 begin
00269 Result := FResultSet.ColumnsInfo.Count;
00270 end;
00271
00272 {**
00273 Indicates whether the designated column is automatically numbered, thus read-only.
00274 @param column the first column is 1, the second is 2, ...
00275 @return <code>true</code> if so; <code>false</code> otherwise
00276 }
00277 function TZAbstractResultSetMetadata.IsAutoIncrement(Column: Integer): Boolean;
00278 begin
00279 if not Loaded then LoadColumns;
00280 Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).AutoIncrement;
00281 end;
00282
00283 {**
00284 Indicates whether a column's case matters.
00285 @param column the first column is 1, the second is 2, ...
00286 @return <code>true</code> if so; <code>false</code> otherwise
00287 }
00288 function TZAbstractResultSetMetadata.IsCaseSensitive(Column: Integer): Boolean;
00289 begin
00290 if not Loaded then LoadColumns;
00291 Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).CaseSensitive;
00292 end;
00293
00294 {**
00295 Indicates whether the designated column can be used in a where clause.
00296 @param column the first column is 1, the second is 2, ...
00297 @return <code>true</code> if so; <code>false</code> otherwise
00298 }
00299 function TZAbstractResultSetMetadata.IsSearchable(Column: Integer): Boolean;
00300 begin
00301 if not Loaded then LoadColumns;
00302 Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).Searchable;
00303 end;
00304
00305 {**
00306 Indicates whether the designated column is a cash value.
00307 @param column the first column is 1, the second is 2, ...
00308 @return <code>true</code> if so; <code>false</code> otherwise
00309 }
00310 function TZAbstractResultSetMetadata.IsCurrency(Column: Integer): Boolean;
00311 begin
00312 Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).Currency;
00313 end;
00314
00315 {**
00316 Indicates the nullability of values in the designated column.
00317 @param column the first column is 1, the second is 2, ...
00318 @return the nullability status of the given column; one of <code>columnNoNulls</code>,
00319 <code>columnNullable</code> or <code>columnNullableUnknown</code>
00320 }
00321 function TZAbstractResultSetMetadata.IsNullable(
00322 Column: Integer): TZColumnNullableType;
00323 begin
00324 if not Loaded then LoadColumns;
00325 Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).Nullable;
00326 end;
00327
00328 {**
00329 Indicates whether values in the designated column are signed numbers.
00330 @param column the first column is 1, the second is 2, ...
00331 @return <code>true</code> if so; <code>false</code> otherwise
00332 }
00333 function TZAbstractResultSetMetadata.IsSigned(Column: Integer): Boolean;
00334 begin
00335 Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).Signed;
00336 end;
00337
00338 {**
00339 Indicates the designated column's normal maximum width in characters.
00340 @param column the first column is 1, the second is 2, ...
00341 @return the normal maximum number of characters allowed as the width
00342 of the designated column
00343 }
00344 function TZAbstractResultSetMetadata.GetColumnDisplaySize(
00345 Column: Integer): Integer;
00346 begin
00347 Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).ColumnDisplaySize;
00348 end;
00349
00350 {**
00351 Gets the designated column's suggested title for use in printouts and
00352 displays.
00353 @param column the first column is 1, the second is 2, ...
00354 @return the suggested column title
00355 }
00356 function TZAbstractResultSetMetadata.GetColumnLabel(Column: Integer): string;
00357 var
00358 I, J, N: Integer;
00359 ColumnName: string;
00360 ColumnsInfo: TObjectList;
00361 begin
00362 { Prepare unique column labels. }
00363 if FColumnsLabels = nil then
00364 begin
00365 ColumnsInfo := FResultSet.ColumnsInfo;
00366 FColumnsLabels := TStringList.Create;
00367 for I := 0 to ColumnsInfo.Count - 1 do
00368 begin
00369 N := 0;
00370 ColumnName := TZColumnInfo(ColumnsInfo[I]).ColumnLabel;
00371 for J := 0 to I - 1 do
00372 begin
00373 if TZColumnInfo(ColumnsInfo[J]).ColumnLabel = ColumnName then
00374 Inc(N);
00375 end;
00376 if ColumnName = '' then
00377 ColumnName := 'Column';
00378 if N > 0 then
00379 ColumnName := ColumnName + '_' + IntToStr(N);
00380 FColumnsLabels.Add(ColumnName);
00381 end;
00382 end;
00383
00384 Result := ColumnsLabels[Column - 1];
00385 end;
00386
00387 {**
00388 Get the designated column's name.
00389 @param column the first column is 1, the second is 2, ...
00390 @return column name
00391 }
00392 function TZAbstractResultSetMetadata.GetColumnName(
00393 Column: Integer): string;
00394 begin
00395 if not Loaded then LoadColumns;
00396 Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).ColumnName;
00397 end;
00398
00399 {**
00400 Get the designated column's table's schema.
00401 @param column the first column is 1, the second is 2, ...
00402 @return schema name or "" if not applicable
00403 }
00404 function TZAbstractResultSetMetadata.GetSchemaName(
00405 Column: Integer): string;
00406 begin
00407 if not Loaded then LoadColumns;
00408 Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).SchemaName;
00409 end;
00410
00411 {**
00412 Get the designated column's number of decimal digits.
00413 @param column the first column is 1, the second is 2, ...
00414 @return precision
00415 }
00416 function TZAbstractResultSetMetadata.GetPrecision(Column: Integer): Integer;
00417 begin
00418 Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).Precision;
00419 end;
00420
00421 {**
00422 Gets the designated column's number of digits to right of the decimal point.
00423 @param column the first column is 1, the second is 2, ...
00424 @return scale
00425 }
00426 function TZAbstractResultSetMetadata.GetScale(Column: Integer): Integer;
00427 begin
00428 Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).Scale;
00429 end;
00430
00431 {**
00432 Gets the designated column's table name.
00433 @param column the first column is 1, the second is 2, ...
00434 @return table name or "" if not applicable
00435 }
00436 function TZAbstractResultSetMetadata.GetTableName(Column: Integer): string;
00437 begin
00438 if not Loaded then LoadColumns;
00439 Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).TableName;
00440 end;
00441
00442 {**
00443 Gets the designated column's table's catalog name.
00444 @param column the first column is 1, the second is 2, ...
00445 @return column name or "" if not applicable
00446 }
00447 function TZAbstractResultSetMetadata.GetCatalogName(Column: Integer): string;
00448 begin
00449 if not Loaded then LoadColumns;
00450 Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).CatalogName;
00451 end;
00452
00453 {**
00454 Retrieves the designated column's SQL type.
00455 @param column the first column is 1, the second is 2, ...
00456 @return SQL type from java.sql.Types
00457 }
00458 function TZAbstractResultSetMetadata.GetColumnType(Column: Integer): TZSQLType;
00459 begin
00460 Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).ColumnType;
00461 end;
00462
00463 {**
00464 Retrieves the designated column's database-specific type name.
00465
00466 @param column the first column is 1, the second is 2, ...
00467 @return type name used by the database. If the column type is
00468 a user-defined type, then a fully-qualified type name is returned.
00469 }
00470 function TZAbstractResultSetMetadata.GetColumnTypeName(Column: Integer): string;
00471 begin
00472 Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).GetColumnTypeName;
00473 end;
00474
00475 {**
00476 Indicates whether the designated column is definitely not writable.
00477 @param column the first column is 1, the second is 2, ...
00478 @return <code>true</code> if so; <code>false</code> otherwise
00479 }
00480 function TZAbstractResultSetMetadata.IsReadOnly(Column: Integer): Boolean;
00481 begin
00482 if not Loaded then LoadColumns;
00483 Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).ReadOnly;
00484 end;
00485
00486 {**
00487 Indicates whether it is possible for a write on the designated column to succeed.
00488 @param column the first column is 1, the second is 2, ...
00489 @return <code>true</code> if so; <code>false</code> otherwise
00490 }
00491 function TZAbstractResultSetMetadata.IsWritable(Column: Integer): Boolean;
00492 begin
00493 if not Loaded then LoadColumns;
00494 Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).Writable;
00495 end;
00496
00497 {**
00498 Indicates whether a write on the designated column will definitely succeed.
00499 @param column the first column is 1, the second is 2, ...
00500 @return <code>true</code> if so; <code>false</code> otherwise
00501 }
00502 function TZAbstractResultSetMetadata.IsDefinitelyWritable(
00503 Column: Integer): Boolean;
00504 begin
00505 if not Loaded then LoadColumns;
00506 Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).DefinitelyWritable;
00507 end;
00508
00509 {**
00510 Gets a default value for this field.
00511 @param column the first column is 1, the second is 2, ...
00512 @return a default value for this field.
00513 }
00514 function TZAbstractResultSetMetadata.GetDefaultValue(
00515 Column: Integer): string;
00516 begin
00517 if not Loaded then LoadColumns;
00518 Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).DefaultValue;
00519 end;
00520
00521 {**
00522 Finds whether this field has a default value.
00523 @param column the first column is 1, the second is 2, ...
00524 @return true if this field has a default value.
00525 }
00526 function TZAbstractResultSetMetadata.HasDefaultValue(
00527 Column: Integer): Boolean;
00528 begin
00529 if not Loaded then LoadColumns;
00530
00531 Result := not(TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).DefaultValue = '');
00532 end;
00533
00534 {**
00535 Gets a table description result set.
00536 @param TableRef a table reference object.
00537 @return a result set with table columns from database metadata.
00538 }
00539 function TZAbstractResultSetMetadata.GetTableColumns(
00540 TableRef: TZTableRef): IZResultSet;
00541 var
00542 TableKey: IZAnyValue;
00543 begin
00544 TableKey := TZAnyValue.CreateWithString(TableRef.FullName);
00545 if FTableColumns.Get(TableKey) = nil then
00546 begin
00547 Result := Metadata.GetColumns(TableRef.Catalog,
00548 TableRef.Schema, TableRef.Table, '');
00549 FTableColumns.Put(TableKey, Result);
00550 end else
00551 Result := FTableColumns.Get(TableKey) as IZResultSet;
00552 end;
00553
00554 {**
00555 Clears specified column information.
00556 @param ColumnInfo a column information object.
00557 }
00558 procedure TZAbstractResultSetMetadata.ClearColumn(ColumnInfo: TZColumnInfo);
00559 begin
00560 ColumnInfo.ReadOnly := True;
00561 ColumnInfo.Writable := False;
00562 ColumnInfo.DefinitelyWritable := False;
00563 ColumnInfo.CatalogName := '';
00564 ColumnInfo.SchemaName := '';
00565 ColumnInfo.TableName := '';
00566 ColumnInfo.ColumnName := '';
00567 end;
00568
00569 {**
00570 Reads a column information from table metadata.
00571 @param FieldName a name of the field.
00572 @param TableRef a table reference object.
00573 @param ColumnInfo a column information object.
00574 @return <code>True</code> is column was found and read.
00575 }
00576 function TZAbstractResultSetMetadata.ReadColumnByName(FieldName: string;
00577 TableRef: TZTableRef; ColumnInfo: TZColumnInfo): Boolean;
00578 var
00579 TableColumns: IZResultSet;
00580 begin
00581 Result := False;
00582 TableColumns := GetTableColumns(TableRef);
00583 { Checks for unexisted table. }
00584 if not Assigned(TableColumns) then
00585 Exit;
00586
00587 { Locates a column row. }
00588 TableColumns.BeforeFirst;
00589 while TableColumns.Next do
00590 if TableColumns.GetString(4) = FieldName then
00591 Break;
00592 if TableColumns.IsAfterLast then
00593 begin
00594 { Locates a column row with case insensitivity. }
00595 TableColumns.BeforeFirst;
00596 while TableColumns.Next do
00597 if AnsiUpperCase(TableColumns.GetString(4)) = AnsiUpperCase(FieldName) then
00598 Break;
00599 if TableColumns.IsAfterLast then
00600 Exit;
00601 end;
00602
00603 { Reads a column information. }
00604 Result := True;
00605 ColumnInfo.CatalogName := TableColumns.GetString(1);
00606 ColumnInfo.SchemaName := TableColumns.GetString(2);
00607 ColumnInfo.TableName := TableColumns.GetString(3);
00608 ColumnInfo.ColumnName := FieldName;
00609
00610
00611
00612 if not TableColumns.IsNull(5) then
00613 ColumnInfo.ColumnType := TZSQLType(TableColumns.GetInt(5));
00614 if not TableColumns.IsNull(11) then
00615 ColumnInfo.Nullable := TZColumnNullableType(TableColumns.GetInt(11));
00616 if not TableColumns.IsNull(19) then
00617 ColumnInfo.AutoIncrement := TableColumns.GetBoolean(19);
00618 if not TableColumns.IsNull(20) then
00619 ColumnInfo.CaseSensitive := TableColumns.GetBoolean(20);
00620 if not TableColumns.IsNull(21) then
00621 ColumnInfo.Searchable := TableColumns.GetBoolean(21);
00622 if not TableColumns.IsNull(22) then
00623 ColumnInfo.Writable := TableColumns.GetBoolean(22);
00624 if not TableColumns.IsNull(23) then
00625 ColumnInfo.DefinitelyWritable := TableColumns.GetBoolean(23);
00626 if not TableColumns.IsNull(24) then
00627 ColumnInfo.ReadOnly := TableColumns.GetBoolean(24);
00628 if not TableColumns.IsNull(13) then
00629 ColumnInfo.DefaultValue := TableColumns.GetString(13);
00630 end;
00631
00632 {**
00633 Reads a column information from table metadata.
00634 @param FieldRef a field reference object.
00635 @param ColumnInfo a column information object.
00636 @return <code>True</code> if column was found and read.
00637 }
00638 function TZAbstractResultSetMetadata.ReadColumnByRef(
00639 FieldRef: TZFieldRef; ColumnInfo: TZColumnInfo): Boolean;
00640 begin
00641 Result := False;
00642 ClearColumn(ColumnInfo);
00643 { Checks for uncompleted field reference. }
00644 if not Assigned(FieldRef) or not Assigned(FieldRef.TableRef) then
00645 Exit;
00646 if not FieldRef.IsField then
00647 Exit;
00648
00649 Result := ReadColumnByName(FieldRef.Field, FieldRef.TableRef, ColumnInfo);
00650 end;
00651
00652 {**
00653 Initializes on single column of the result set.
00654 @param ColumnIndex a column index in the query.
00655 @param ColumnInfo a column information object to be initialized.
00656 @param SelectSchema a schema of the select statement.
00657 }
00658 procedure TZAbstractResultSetMetadata.LoadColumn(ColumnIndex: Integer;
00659 ColumnInfo: TZColumnInfo; SelectSchema: IZSelectSchema);
00660 var
00661 I: Integer;
00662 FieldRef: TZFieldRef;
00663 TableRef: TZTableRef;
00664 Found: Boolean;
00665 begin
00666 { Initializes single columns with specified table. }
00667 FieldRef := SelectSchema.LinkFieldByIndexAndShortName(
00668 ColumnIndex, ColumnInfo.ColumnLabel);
00669 ReadColumnByRef(FieldRef, ColumnInfo);
00670 if ColumnInfo.ColumnName <> '' then
00671 Exit;
00672
00673 { Initializes single columns without specified table. }
00674 I := 0;
00675 Found := False;
00676 while (ColumnInfo.ColumnName = '') and (I < SelectSchema.TableCount)
00677 and not Found do
00678 begin
00679 TableRef := SelectSchema.Tables[I];
00680 if Assigned(FieldRef) then
00681 Found := ReadColumnByName(FieldRef.Field, TableRef, ColumnInfo)
00682 else
00683 Found := ReadColumnByName(ColumnInfo.ColumnLabel, TableRef, ColumnInfo);
00684 Inc(I);
00685 end;
00686 end;
00687
00688 {**
00689 Replaces '*' columns in the select schema.
00690 @param SelectSchema a query select schema.
00691 }
00692 procedure TZAbstractResultSetMetadata.ReplaceStarColumns(
00693 SelectSchema: IZSelectSchema);
00694 var
00695 I: Integer;
00696 Current: TZFieldRef;
00697 FieldRef: TZFieldRef;
00698 TableRef: TZTableRef;
00699 ResultSet: IZResultSet;
00700 begin
00701 I := 0;
00702 while I < SelectSchema.FieldCount do
00703 begin
00704 Current := SelectSchema.Fields[I];
00705 if (Current.Field = '*') and (Current.TableRef <> nil) then
00706 begin
00707 TableRef := Current.TableRef;
00708 ResultSet := Self.GetTableColumns(TableRef);
00709 if ResultSet <> nil then
00710 begin
00711 ResultSet.BeforeFirst;
00712 while ResultSet.Next do
00713 begin
00714 FieldRef := TZFieldRef.Create(True, TableRef.Catalog, TableRef.Schema,
00715 TableRef.Table, ResultSet.GetString(4), '', TableRef);
00716 SelectSchema.InsertField(I, FieldRef);
00717 Inc(I);
00718 end;
00719 end;
00720 SelectSchema.DeleteField(Current);
00721 Dec(I);
00722 end;
00723 Inc(I);
00724 end;
00725 end;
00726
00727 {**
00728 Initializes columns with additional data.
00729 }
00730 procedure TZAbstractResultSetMetadata.LoadColumns;
00731 var
00732 I: Integer;
00733 Driver: IZDriver;
00734 Tokenizer: IZTokenizer;
00735 StatementAnalyser: IZStatementAnalyser;
00736 SelectSchema: IZSelectSchema;
00737 FillByIndices: Boolean;
00738 begin
00739 { Parses the Select statement and retrieves a schema object. }
00740 Driver := Metadata.GetConnection.GetDriver;
00741 Tokenizer := Driver.GetTokenizer;
00742 StatementAnalyser := Driver.GetStatementAnalyser;
00743 SelectSchema := StatementAnalyser.DefineSelectSchemaFromQuery(Tokenizer, SQL);
00744 if Assigned(SelectSchema) then
00745 begin
00746 SelectSchema.LinkReferences(IdentifierConvertor);
00747 ReplaceStarColumns(SelectSchema);
00748 FillByIndices := SelectSchema.FieldCount = FResultSet.ColumnsInfo.Count;
00749 for I := 0 to FResultSet.ColumnsInfo.Count - 1 do
00750 begin
00751 if FillByIndices then
00752 LoadColumn(I + 1, TZColumnInfo(FResultSet.ColumnsInfo[I]), SelectSchema)
00753 else
00754 LoadColumn(-1, TZColumnInfo(FResultSet.ColumnsInfo[I]), SelectSchema);
00755 end;
00756 end;
00757 Loaded := True;
00758 end;
00759
00760 end.
00761