zeoslib  UNKNOWN
 All Files
ZDbcInterbase6Metadata.pas
Go to the documentation of this file.
1 {*********************************************************}
2 { }
3 { Zeos Database Objects }
4 { Interbase Database Connectivity Classes }
5 { }
6 { Originally written by Sergey Merkuriev }
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 ZDbcInterbase6Metadata;
53 
54 interface
55 
56 {$I ZDbc.inc}
57 
58 uses
59  Types, Classes, SysUtils, ZSysUtils, ZDbcIntfs, ZDbcMetadata, ZCompatibility,
60  ZDbcConnection, ZDbcInterbase6, ZURL;
61 
62 type
63 
64  // technobot 2008-06-25 - methods moved as is from TZInterbase6DatabaseMetadata:
65  {** Implements Interbase6 Database Information. }
66  IZInterbaseDatabaseInfo = Interface(IZDatabaseInfo)
67  ['{F2895A2A-C427-4984-9356-79349EAAD44F}']
68  function HostIsFireBird: Boolean;
69  procedure CollectServerInformations;
70  End;
71 
72  TZInterbase6DatabaseInfo = class(TZAbstractDatabaseInfo, IZInterbaseDatabaseInfo)
73  private
74  FIsFireBird: Boolean;
75  FServerVersion: string;
76  FProductVersion: String;
77 // function UncachedGetUDTs(const Catalog: string; const SchemaPattern: string;
78 // const TypeNamePattern: string; const Types: TIntegerDynArray): IZResultSet; override;
79  public
80  procedure CollectServerInformations;
81  function HostIsFireBird: Boolean;
82  // database/driver/server info:
83  function GetDatabaseProductName: string; override;
84  function GetDatabaseProductVersion: string; override;
85  function GetDriverName: string; override;
86 // function GetDriverVersion: string; override; -> Same as parent
87  function GetDriverMajorVersion: Integer; override;
88  function GetDriverMinorVersion: Integer; override;
89  function GetServerVersion: string; override;
90 
91  // capabilities (what it can/cannot do):
92 // function AllProceduresAreCallable: Boolean; override; -> Not implemented
93 // function AllTablesAreSelectable: Boolean; override; -> Not implemented
94  function SupportsMixedCaseIdentifiers: Boolean; override;
95  function SupportsMixedCaseQuotedIdentifiers: Boolean; override;
96 // function SupportsAlterTableWithAddColumn: Boolean; override; -> Not implemented
97 // function SupportsAlterTableWithDropColumn: Boolean; override; -> Not implemented
98 // function SupportsColumnAliasing: Boolean; override; -> Not implemented
99 // function SupportsConvert: Boolean; override; -> Not implemented
100 // function SupportsConvertForTypes(FromType: TZSQLType; ToType: TZSQLType):
101 // Boolean; override; -> Not implemented
102 // function SupportsTableCorrelationNames: Boolean; override; -> Not implemented
103 // function SupportsDifferentTableCorrelationNames: Boolean; override; -> Not implemented
104  function SupportsExpressionsInOrderBy: Boolean; override;
105  function SupportsOrderByUnrelated: Boolean; override;
106  function SupportsGroupBy: Boolean; override;
107  function SupportsGroupByUnrelated: Boolean; override;
108  function SupportsGroupByBeyondSelect: Boolean; override;
109 // function SupportsLikeEscapeClause: Boolean; override; -> Not implemented
110 // function SupportsMultipleResultSets: Boolean; override; -> Not implemented
111 // function SupportsMultipleTransactions: Boolean; override; -> Not implemented
112 // function SupportsNonNullableColumns: Boolean; override; -> Not implemented
113 // function SupportsMinimumSQLGrammar: Boolean; override; -> Not implemented
114 // function SupportsCoreSQLGrammar: Boolean; override; -> Not implemented
115 // function SupportsExtendedSQLGrammar: Boolean; override; -> Not implemented
116 // function SupportsANSI92EntryLevelSQL: Boolean; override; -> Not implemented
117 // function SupportsANSI92IntermediateSQL: Boolean; override; -> Not implemented
118 // function SupportsANSI92FullSQL: Boolean; override; -> Not implemented
119  function SupportsIntegrityEnhancementFacility: Boolean; override;
120 // function SupportsOuterJoins: Boolean; override; -> Not implemented
121 // function SupportsFullOuterJoins: Boolean; override; -> Not implemented
122 // function SupportsLimitedOuterJoins: Boolean; override; -> Not implemented
123  function SupportsSchemasInDataManipulation: Boolean; override;
124  function SupportsSchemasInProcedureCalls: Boolean; override;
125  function SupportsSchemasInTableDefinitions: Boolean; override;
126  function SupportsSchemasInIndexDefinitions: Boolean; override;
127  function SupportsSchemasInPrivilegeDefinitions: Boolean; override;
128  function SupportsCatalogsInDataManipulation: Boolean; override;
129  function SupportsCatalogsInProcedureCalls: Boolean; override;
130  function SupportsCatalogsInTableDefinitions: Boolean; override;
131  function SupportsCatalogsInIndexDefinitions: Boolean; override;
132  function SupportsCatalogsInPrivilegeDefinitions: Boolean; override;
133  function SupportsPositionedDelete: Boolean; override;
134  function SupportsPositionedUpdate: Boolean; override;
135  function SupportsSelectForUpdate: Boolean; override;
136  function SupportsStoredProcedures: Boolean; override;
137  function SupportsSubqueriesInComparisons: Boolean; override;
138  function SupportsSubqueriesInExists: Boolean; override;
139  function SupportsSubqueriesInIns: Boolean; override;
140  function SupportsSubqueriesInQuantifieds: Boolean; override;
141  function SupportsCorrelatedSubqueries: Boolean; override;
142  function SupportsUnion: Boolean; override;
143  function SupportsUnionAll: Boolean; override;
144  function SupportsOpenCursorsAcrossCommit: Boolean; override;
145  function SupportsOpenCursorsAcrossRollback: Boolean; override;
146  function SupportsOpenStatementsAcrossCommit: Boolean; override;
147  function SupportsOpenStatementsAcrossRollback: Boolean; override;
148  function SupportsTransactions: Boolean; override;
149  function SupportsTransactionIsolationLevel(Level: TZTransactIsolationLevel):
150  Boolean; override;
151  function SupportsDataDefinitionAndDataManipulationTransactions: Boolean; override;
152  function SupportsDataManipulationTransactionsOnly: Boolean; override;
153  function SupportsResultSetType(_Type: TZResultSetType): Boolean; override;
154  function SupportsResultSetConcurrency(_Type: TZResultSetType;
155  Concurrency: TZResultSetConcurrency): Boolean; override;
156 // function SupportsBatchUpdates: Boolean; override; -> Not implemented
157 
158  // maxima:
159  function GetMaxBinaryLiteralLength: Integer; override;
160  function GetMaxCharLiteralLength: Integer; override;
161  function GetMaxColumnNameLength: Integer; override;
162  function GetMaxColumnsInGroupBy: Integer; override;
163  function GetMaxColumnsInIndex: Integer; override;
164  function GetMaxColumnsInOrderBy: Integer; override;
165  function GetMaxColumnsInSelect: Integer; override;
166  function GetMaxColumnsInTable: Integer; override;
167  function GetMaxConnections: Integer; override;
168  function GetMaxCursorNameLength: Integer; override;
169  function GetMaxIndexLength: Integer; override;
170  function GetMaxSchemaNameLength: Integer; override;
171  function GetMaxProcedureNameLength: Integer; override;
172  function GetMaxCatalogNameLength: Integer; override;
173  function GetMaxRowSize: Integer; override;
174  function GetMaxStatementLength: Integer; override;
175  function GetMaxStatements: Integer; override;
176  function GetMaxTableNameLength: Integer; override;
177  function GetMaxTablesInSelect: Integer; override;
178  function GetMaxUserNameLength: Integer; override;
179 
180  // policies (how are various data and operations handled):
181 // function IsReadOnly: Boolean; override; -> Not implemented
182 // function IsCatalogAtStart: Boolean; override; -> Not implemented
183  function DoesMaxRowSizeIncludeBlobs: Boolean; override;
184 // function NullsAreSortedHigh: Boolean; override; -> Not implemented
185 // function NullsAreSortedLow: Boolean; override; -> Not implemented
186 // function NullsAreSortedAtStart: Boolean; override; -> Not implemented
187 // function NullsAreSortedAtEnd: Boolean; override; -> Not implemented
188 // function NullPlusNonNullIsNull: Boolean; override; -> Not implemented
189 // function UsesLocalFiles: Boolean; override; -> Not implemented
190  function UsesLocalFilePerTable: Boolean; override;
191  function StoresUpperCaseIdentifiers: Boolean; override;
192  function StoresLowerCaseIdentifiers: Boolean; override;
193  function StoresMixedCaseIdentifiers: Boolean; override;
194  function StoresUpperCaseQuotedIdentifiers: Boolean; override;
195  function StoresLowerCaseQuotedIdentifiers: Boolean; override;
196  function StoresMixedCaseQuotedIdentifiers: Boolean; override;
197  function GetDefaultTransactionIsolation: TZTransactIsolationLevel; override;
198  function DataDefinitionCausesTransactionCommit: Boolean; override;
199  function DataDefinitionIgnoredInTransactions: Boolean; override;
200 
201  // interface details (terms, keywords, etc):
202  function GetSchemaTerm: string; override;
203  function GetProcedureTerm: string; override;
204  function GetCatalogTerm: string; override;
205  function GetCatalogSeparator: string; override;
206  function GetSQLKeywords: string; override;
207  function GetNumericFunctions: string; override;
208  function GetStringFunctions: string; override;
209  function GetSystemFunctions: string; override;
210  function GetTimeDateFunctions: string; override;
211  function GetSearchStringEscape: string; override;
212  function GetExtraNameCharacters: string; override;
213  end;
214 
215  {** Implements Interbase6 Database Metadata. }
216  TZInterbase6DatabaseMetadata = class(TZAbstractDatabaseMetadata)
217  private
218  function GetPrivilege(Privilege: string): string;
219  protected
220  function CreateDatabaseInfo: IZDatabaseInfo; override; // technobot 2008-06-25
221  function ConstructNameCondition(Pattern: string; Column: string): string; override;
222 
223  function UncachedGetTables(const Catalog: string; const SchemaPattern: string;
224  const TableNamePattern: string; const Types: TStringDynArray): IZResultSet; override;
225 // function UncachedGetSchemas: IZResultSet; override; -> Not implemented
226 // function UncachedGetCatalogs: IZResultSet; override; -> Not Implemented
227  function UncachedGetTableTypes: IZResultSet; override;
228  function UncachedGetColumns(const Catalog: string; const SchemaPattern: string;
229  const TableNamePattern: string; const ColumnNamePattern: string): IZResultSet; override;
230  function UncachedGetTablePrivileges(const Catalog: string; const SchemaPattern: string;
231  const TableNamePattern: string): IZResultSet; override;
232  function UncachedGetColumnPrivileges(const Catalog: string; const Schema: string;
233  const Table: string; const ColumnNamePattern: string): IZResultSet; override;
234  function UncachedGetPrimaryKeys(const Catalog: string; const Schema: string;
235  const Table: string): IZResultSet; override;
236  function UncachedGetImportedKeys(const Catalog: string; const Schema: string;
237  const Table: string): IZResultSet; override;
238  function UncachedGetExportedKeys(const Catalog: string; const Schema: string;
239  const Table: string): IZResultSet; override;
240  function UncachedGetCrossReference(const PrimaryCatalog: string; const PrimarySchema: string;
241  const PrimaryTable: string; const ForeignCatalog: string; const ForeignSchema: string;
242  const ForeignTable: string): IZResultSet; override;
243  function UncachedGetIndexInfo(const Catalog: string; const Schema: string; const Table: string;
244  Unique: Boolean; Approximate: Boolean): IZResultSet; override;
245  function UncachedGetSequences(const Catalog: string; const SchemaPattern: string;
246  const SequenceNamePattern: string): IZResultSet; override;
247  function UncachedGetProcedures(const Catalog: string; const SchemaPattern: string;
248  const ProcedureNamePattern: string): IZResultSet; override;
249  function UncachedGetProcedureColumns(const Catalog: string; const SchemaPattern: string;
250  const ProcedureNamePattern: string; const ColumnNamePattern: string):
251  IZResultSet; override;
252  function UncachedGetVersionColumns(const Catalog: string; const Schema: string;
253  const Table: string): IZResultSet; override;
254  function UncachedGetTypeInfo: IZResultSet; override;
255  function UncachedGetTriggers(const Catalog: string;
256  const SchemaPattern: string; const TableNamePattern: string;
257  const TriggerNamePattern: string): IZResultSet; override; //EgonHugesit
258  function UncachedGetCollationAndCharSet(const Catalog, SchemaPattern,
259  TableNamePattern, ColumnNamePattern: string): IZResultSet; override; //EgonHugeist
260  function UncachedGetCharacterSets: IZResultSet; override; //EgonHugeist
261  public
262  property ConSettings;
263  end;
264 
265 implementation
266 
267 uses ZMessages, ZDbcInterbase6Utils, ZPlainFirebirdInterbaseConstants;
268 
269 const
270  DBProvider: array[Boolean] of String = ('Interbase', 'Firebird');
271 
272 { TZInterbase6DatabaseInfo }
273 
274 //----------------------------------------------------------------------
275 // First, a variety of minor information about the target database.
276 
277 procedure TZInterbase6DatabaseInfo.CollectServerInformations;
278 var
279  FIBConnection: IZInterbase6Connection;
280 begin
281  if FServerVersion = '' then
282  begin
283  FIBConnection := Metadata.GetConnection as IZInterbase6Connection;
284  FServerVersion := String(GetVersion(FIBConnection.GetPlainDriver,
285  FIBConnection.GetDBHandle));
286  FIsFireBird := Pos('Firebird', FServerVersion) > 0;
287  FProductVersion := Copy(FServerVersion, Pos(DBProvider[FIsFireBird],
288  FServerVersion)+8+Ord(not FIsFireBird)+1, Length(FServerVersion));
289  end;
290 end;
291 
292 function TZInterbase6DatabaseInfo.HostIsFireBird: Boolean;
293 begin
294  Result := FIsFireBird;
295 end;
296 
297 {**
298  What's the name of this database product?
299  @return database product name
300 }
301 function TZInterbase6DatabaseInfo.GetDatabaseProductName: string;
302 begin
303  Result := DBProvider[FIsFireBird];
304 end;
305 
306 {**
307  What's the version of this database product?
308  @return database version
309 }
310 function TZInterbase6DatabaseInfo.GetDatabaseProductVersion: string;
311 begin
312  Result := FProductVersion;
313 end;
314 
315 {**
316  What's the name of this JDBC driver?
317  @return JDBC driver name
318 }
319 function TZInterbase6DatabaseInfo.GetDriverName: string;
320 begin
321  Result := 'Zeos Database Connectivity Driver for Interbase and Firebird';
322 end;
323 
324 {**
325  What's this JDBC driver's major version number?
326  @return JDBC driver major version
327 }
328 function TZInterbase6DatabaseInfo.GetDriverMajorVersion: Integer;
329 begin
330  Result := 1;
331 end;
332 
333 {**
334  What's this JDBC driver's minor version number?
335  @return JDBC driver minor version number
336 }
337 function TZInterbase6DatabaseInfo.GetDriverMinorVersion: Integer;
338 begin
339  Result := 0;
340 end;
341 
342 {**
343  Gets the version of the server.
344  @returns the version of the server.
345 }
346 function TZInterbase6DatabaseInfo.GetServerVersion: string;
347 begin
348  if FServerVersion = '' then
349  begin
350  FServerVersion := String(GetVersion((Metadata.GetConnection as IZInterbase6Connection).GetPlainDriver,
351  (Metadata.GetConnection as IZInterbase6Connection).GetDBHandle));
352  end;
353  Result := FServerVersion;
354 end;
355 
356 {**
357  Does the database use a file for each table?
358  @return true if the database uses a local file for each table
359 }
360 function TZInterbase6DatabaseInfo.UsesLocalFilePerTable: Boolean;
361 begin
362  Result := False;
363 end;
364 
365 {**
366  Does the database treat mixed case unquoted SQL identifiers as
367  case sensitive and as a result store them in mixed case?
368  A JDBC Compliant<sup><font size=-2>TM</font></sup> driver will always return false.
369  @return <code>true</code> if so; <code>false</code> otherwise
370 }
371 function TZInterbase6DatabaseInfo.SupportsMixedCaseIdentifiers: Boolean;
372 begin
373  Result := True;
374 end;
375 
376 {**
377  Does the database treat mixed case unquoted SQL identifiers as
378  case insensitive and store them in upper case?
379  @return <code>true</code> if so; <code>false</code> otherwise
380 }
381 function TZInterbase6DatabaseInfo.StoresUpperCaseIdentifiers: Boolean;
382 begin
383  Result := True;
384 end;
385 
386 {**
387  Does the database treat mixed case unquoted SQL identifiers as
388  case insensitive and store them in lower case?
389  @return <code>true</code> if so; <code>false</code> otherwise
390 }
391 function TZInterbase6DatabaseInfo.StoresLowerCaseIdentifiers: Boolean;
392 begin
393  Result := False;
394 end;
395 
396 {**
397  Does the database treat mixed case unquoted SQL identifiers as
398  case insensitive and store them in mixed case?
399  @return <code>true</code> if so; <code>false</code> otherwise
400 }
401 function TZInterbase6DatabaseInfo.StoresMixedCaseIdentifiers: Boolean;
402 begin
403  Result := False;
404 end;
405 
406 {**
407  Does the database treat mixed case quoted SQL identifiers as
408  case sensitive and as a result store them in mixed case?
409  A JDBC Compliant<sup><font size=-2>TM</font></sup> driver will always return true.
410  @return <code>true</code> if so; <code>false</code> otherwise
411 }
412 function TZInterbase6DatabaseInfo.SupportsMixedCaseQuotedIdentifiers: Boolean;
413 begin
414  Result := True;
415 end;
416 
417 {**
418  Does the database treat mixed case quoted SQL identifiers as
419  case insensitive and store them in upper case?
420  @return <code>true</code> if so; <code>false</code> otherwise
421 }
422 function TZInterbase6DatabaseInfo.StoresUpperCaseQuotedIdentifiers: Boolean;
423 begin
424  Result := False;
425 end;
426 
427 {**
428  Does the database treat mixed case quoted SQL identifiers as
429  case insensitive and store them in lower case?
430  @return <code>true</code> if so; <code>false</code> otherwise
431 }
432 function TZInterbase6DatabaseInfo.StoresLowerCaseQuotedIdentifiers: Boolean;
433 begin
434  Result := False;
435 end;
436 
437 {**
438  Does the database treat mixed case quoted SQL identifiers as
439  case insensitive and store them in mixed case?
440  @return <code>true</code> if so; <code>false</code> otherwise
441 }
442 function TZInterbase6DatabaseInfo.StoresMixedCaseQuotedIdentifiers: Boolean;
443 begin
444  Result := True;
445 end;
446 
447 {**
448  Gets a comma-separated list of all a database's SQL keywords
449  that are NOT also SQL92 keywords.
450  @return the list
451 }
452 function TZInterbase6DatabaseInfo.GetSQLKeywords: string;
453 begin
454  Result := 'ACTIVE,AFTER,ASCENDING,BASE_NAME,BEFORE,BLOB,' +
455  'CACHE,CHECK_POINT_LENGTH,COMPUTED,CONDITIONAL,CONTAINING,' +
456  'CSTRING,DATABASE,RDB$DB_KEY,DEBUG,DESCENDING,DO,ENTRY_POINT,' +
457  'EXIT,FILE,FILTER,FUNCTION,GDSCODE,GENERATOR,GEN_ID,' +
458  'GROUP_COMMIT_WAIT_TIME,IF,INACTIVE,INPUT_TYPE,INDEX,' +
459  'LOGFILE,LOG_BUFFER_SIZE,MANUAL,MAXIMUM_SEGMENT,MERGE, MESSAGE,' +
460  'MODULE_NAME,NCHAR,NUM_LOG_BUFFERS,OUTPUT_TYPE,OVERFLOW,PAGE,' +
461  'PAGES,PAGE_SIZE,PARAMETER,PASSWORD,PLAN,POST_EVENT,PROTECTED,' +
462  'RAW_PARTITIONS,RESERV,RESERVING,RETAIN,RETURNING_VALUES,RETURNS,' +
463  'SEGMENT,SHADOW,SHARED,SINGULAR,SNAPSHOT,SORT,STABILITY,STARTS,' +
464  'STARTING,STATISTICS,SUB_TYPE,SUSPEND,TRIGGER,VARIABLE,RECORD_VERSION,' +
465  'WAIT,WHILE,WORK,VALUE,POSITION,USER,CURRENCY,OPTION,DATE,START,END,USER,' +
466  'READ,PARENT,TYPE'+
467  {Ticket #63: http://sourceforge.net/p/zeoslib/tickets/62/}
468  ',DEC,TIME,MIN,MAX'+
469  {FireBird 3.0}
470  ',DETERMINISTIC,OVER,RETURN,SCROLL,SQLSTATE';
471 end;
472 
473 {**
474  Gets a comma-separated list of math functions. These are the
475  X/Open CLI math function names used in the JDBC function escape
476  clause.
477  @return the list
478 }
479 function TZInterbase6DatabaseInfo.GetNumericFunctions: string;
480 begin
481  Result := '';
482 end;
483 
484 {**
485  Gets a comma-separated list of string functions. These are the
486  X/Open CLI string function names used in the JDBC function escape
487  clause.
488  @return the list
489 }
490 function TZInterbase6DatabaseInfo.GetStringFunctions: string;
491 begin
492  Result := '';
493 end;
494 
495 {**
496  Gets a comma-separated list of system functions. These are the
497  X/Open CLI system function names used in the JDBC function escape
498  clause.
499  @return the list
500 }
501 function TZInterbase6DatabaseInfo.GetSystemFunctions: string;
502 begin
503  Result := '';
504 end;
505 
506 {**
507  Gets a comma-separated list of time and date functions.
508  @return the list
509 }
510 function TZInterbase6DatabaseInfo.GetTimeDateFunctions: string;
511 begin
512  Result := '';
513 end;
514 
515 {**
516  Gets the string that can be used to escape wildcard characters.
517  This is the string that can be used to escape '_' or '%' in
518  the string pattern style catalog search parameters.
519 
520  <P>The '_' character represents any single character.
521  <P>The '%' character represents any sequence of zero or
522  more characters.
523 
524  @return the string used to escape wildcard characters
525 }
526 function TZInterbase6DatabaseInfo.GetSearchStringEscape: string;
527 begin
528  Result := '\';
529 end;
530 
531 {**
532  Gets all the "extra" characters that can be used in unquoted
533  identifier names (those beyond a-z, A-Z, 0-9 and _).
534  @return the string containing the extra characters
535 }
536 function TZInterbase6DatabaseInfo.GetExtraNameCharacters: string;
537 begin
538  Result := '$';
539 end;
540 
541 //--------------------------------------------------------------------
542 // Functions describing which features are supported.
543 
544 {**
545  Are expressions in "ORDER BY" lists supported?
546  @return <code>true</code> if so; <code>false</code> otherwise
547 }
548 function TZInterbase6DatabaseInfo.SupportsExpressionsInOrderBy: Boolean;
549 begin
550  Result := False;
551 end;
552 
553 {**
554  Can an "ORDER BY" clause use columns not in the SELECT statement?
555  @return <code>true</code> if so; <code>false</code> otherwise
556 }
557 function TZInterbase6DatabaseInfo.SupportsOrderByUnrelated: Boolean;
558 begin
559  Result := True;
560 end;
561 
562 {**
563  Is some form of "GROUP BY" clause supported?
564  @return <code>true</code> if so; <code>false</code> otherwise
565 }
566 function TZInterbase6DatabaseInfo.SupportsGroupBy: Boolean;
567 begin
568  Result := True;
569 end;
570 
571 {**
572  Can a "GROUP BY" clause use columns not in the SELECT?
573  @return <code>true</code> if so; <code>false</code> otherwise
574 }
575 function TZInterbase6DatabaseInfo.SupportsGroupByUnrelated: Boolean;
576 begin
577  Result := True;
578 end;
579 
580 {**
581  Can a "GROUP BY" clause add columns not in the SELECT
582  provided it specifies all the columns in the SELECT?
583  @return <code>true</code> if so; <code>false</code> otherwise
584 }
585 function TZInterbase6DatabaseInfo.SupportsGroupByBeyondSelect: Boolean;
586 begin
587  Result := True;
588 end;
589 
590 {**
591  Is the SQL Integrity Enhancement Facility supported?
592  @return <code>true</code> if so; <code>false</code> otherwise
593 }
594 function TZInterbase6DatabaseInfo.SupportsIntegrityEnhancementFacility: Boolean;
595 begin
596  Result := False;
597 end;
598 
599 {**
600  What's the database vendor's preferred term for "schema"?
601  @return the vendor term
602 }
603 function TZInterbase6DatabaseInfo.GetSchemaTerm: string;
604 begin
605  Result := '';
606 end;
607 
608 {**
609  What's the database vendor's preferred term for "procedure"?
610  @return the vendor term
611 }
612 function TZInterbase6DatabaseInfo.GetProcedureTerm: string;
613 begin
614  Result := 'PROCEDURE';
615 end;
616 
617 {**
618  What's the database vendor's preferred term for "catalog"?
619  @return the vendor term
620 }
621 function TZInterbase6DatabaseInfo.GetCatalogTerm: string;
622 begin
623  Result := '';
624 end;
625 
626 {**
627  What's the separator between catalog and table name?
628  @return the separator string
629 }
630 function TZInterbase6DatabaseInfo.GetCatalogSeparator: string;
631 begin
632  Result := '';
633 end;
634 
635 {**
636  Can a schema name be used in a data manipulation statement?
637  @return <code>true</code> if so; <code>false</code> otherwise
638 }
639 function TZInterbase6DatabaseInfo.SupportsSchemasInDataManipulation: Boolean;
640 begin
641  Result := False;
642 end;
643 
644 {**
645  Can a schema name be used in a procedure call statement?
646  @return <code>true</code> if so; <code>false</code> otherwise
647 }
648 function TZInterbase6DatabaseInfo.SupportsSchemasInProcedureCalls: Boolean;
649 begin
650  Result := False;
651 end;
652 
653 {**
654  Can a schema name be used in a table definition statement?
655  @return <code>true</code> if so; <code>false</code> otherwise
656 }
657 function TZInterbase6DatabaseInfo.SupportsSchemasInTableDefinitions: Boolean;
658 begin
659  Result := False;
660 end;
661 
662 {**
663  Can a schema name be used in an index definition statement?
664  @return <code>true</code> if so; <code>false</code> otherwise
665 }
666 function TZInterbase6DatabaseInfo.SupportsSchemasInIndexDefinitions: Boolean;
667 begin
668  Result := False;
669 end;
670 
671 {**
672  Can a schema name be used in a privilege definition statement?
673  @return <code>true</code> if so; <code>false</code> otherwise
674 }
675 function TZInterbase6DatabaseInfo.SupportsSchemasInPrivilegeDefinitions: Boolean;
676 begin
677  Result := False;
678 end;
679 
680 {**
681  Can a catalog name be used in a data manipulation statement?
682  @return <code>true</code> if so; <code>false</code> otherwise
683 }
684 function TZInterbase6DatabaseInfo.SupportsCatalogsInDataManipulation: Boolean;
685 begin
686  Result := False;
687 end;
688 
689 {**
690  Can a catalog name be used in a procedure call statement?
691  @return <code>true</code> if so; <code>false</code> otherwise
692 }
693 function TZInterbase6DatabaseInfo.SupportsCatalogsInProcedureCalls: Boolean;
694 begin
695  Result := False;
696 end;
697 
698 {**
699  Can a catalog name be used in a table definition statement?
700  @return <code>true</code> if so; <code>false</code> otherwise
701 }
702 function TZInterbase6DatabaseInfo.SupportsCatalogsInTableDefinitions: Boolean;
703 begin
704  Result := False;
705 end;
706 
707 {**
708  Can a catalog name be used in an index definition statement?
709  @return <code>true</code> if so; <code>false</code> otherwise
710 }
711 function TZInterbase6DatabaseInfo.SupportsCatalogsInIndexDefinitions: Boolean;
712 begin
713  Result := False;
714 end;
715 
716 {**
717  Can a catalog name be used in a privilege definition statement?
718  @return <code>true</code> if so; <code>false</code> otherwise
719 }
720 function TZInterbase6DatabaseInfo.SupportsCatalogsInPrivilegeDefinitions: Boolean;
721 begin
722  Result := False;
723 end;
724 
725 {**
726  Is positioned DELETE supported?
727  @return <code>true</code> if so; <code>false</code> otherwise
728 }
729 function TZInterbase6DatabaseInfo.SupportsPositionedDelete: Boolean;
730 begin
731  Result := True;
732 end;
733 
734 {**
735  Is positioned UPDATE supported?
736  @return <code>true</code> if so; <code>false</code> otherwise
737 }
738 function TZInterbase6DatabaseInfo.SupportsPositionedUpdate: Boolean;
739 begin
740  Result := True;
741 end;
742 
743 {**
744  Is SELECT for UPDATE supported?
745  @return <code>true</code> if so; <code>false</code> otherwise
746 }
747 function TZInterbase6DatabaseInfo.SupportsSelectForUpdate: Boolean;
748 begin
749  Result := True;
750 end;
751 
752 {**
753  Are stored procedure calls using the stored procedure escape
754  syntax supported?
755  @return <code>true</code> if so; <code>false</code> otherwise
756 }
757 function TZInterbase6DatabaseInfo.SupportsStoredProcedures: Boolean;
758 begin
759  Result := True;
760 end;
761 
762 {**
763  Are subqueries in comparison expressions supported?
764  A JDBC Compliant<sup><font size=-2>TM</font></sup> driver always returns true.
765  @return <code>true</code> if so; <code>false</code> otherwise
766 }
767 function TZInterbase6DatabaseInfo.SupportsSubqueriesInComparisons: Boolean;
768 begin
769  Result := True;
770 end;
771 
772 {**
773  Are subqueries in 'exists' expressions supported?
774  A JDBC Compliant<sup><font size=-2>TM</font></sup> driver always returns true.
775  @return <code>true</code> if so; <code>false</code> otherwise
776 }
777 function TZInterbase6DatabaseInfo.SupportsSubqueriesInExists: Boolean;
778 begin
779  Result := True;
780 end;
781 
782 {**
783  Are subqueries in 'in' statements supported?
784  A JDBC Compliant<sup><font size=-2>TM</font></sup> driver always returns true.
785  @return <code>true</code> if so; <code>false</code> otherwise
786 }
787 function TZInterbase6DatabaseInfo.SupportsSubqueriesInIns: Boolean;
788 begin
789  Result := False;
790 end;
791 
792 {**
793  Are subqueries in quantified expressions supported?
794  A JDBC Compliant<sup><font size=-2>TM</font></sup> driver always returns true.
795  @return <code>true</code> if so; <code>false</code> otherwise
796 }
797 function TZInterbase6DatabaseInfo.SupportsSubqueriesInQuantifieds: Boolean;
798 begin
799  Result := True;
800 end;
801 
802 {**
803  Are correlated subqueries supported?
804  A JDBC Compliant<sup><font size=-2>TM</font></sup> driver always returns true.
805  @return <code>true</code> if so; <code>false</code> otherwise
806 }
807 function TZInterbase6DatabaseInfo.SupportsCorrelatedSubqueries: Boolean;
808 begin
809  Result := True;
810 end;
811 
812 {**
813  Is SQL UNION supported?
814  @return <code>true</code> if so; <code>false</code> otherwise
815 }
816 function TZInterbase6DatabaseInfo.SupportsUnion: Boolean;
817 begin
818  Result := True;
819 end;
820 
821 {**
822  Is SQL UNION ALL supported?
823  @return <code>true</code> if so; <code>false</code> otherwise
824 }
825 function TZInterbase6DatabaseInfo.SupportsUnionAll: Boolean;
826 begin
827  Result := True;
828 end;
829 
830 {**
831  Can cursors remain open across commits?
832  @return <code>true</code> if cursors always remain open;
833  <code>false</code> if they might not remain open
834 }
835 function TZInterbase6DatabaseInfo.SupportsOpenCursorsAcrossCommit: Boolean;
836 begin
837  Result := False;
838 end;
839 
840 {**
841  Can cursors remain open across rollbacks?
842  @return <code>true</code> if cursors always remain open;
843  <code>false</code> if they might not remain open
844 }
845 function TZInterbase6DatabaseInfo.SupportsOpenCursorsAcrossRollback: Boolean;
846 begin
847  Result := False;
848 end;
849 
850 {**
851  Can statements remain open across commits?
852  @return <code>true</code> if statements always remain open;
853  <code>false</code> if they might not remain open
854 }
855 function TZInterbase6DatabaseInfo.SupportsOpenStatementsAcrossCommit: Boolean;
856 begin
857  Result := True;
858 end;
859 
860 {**
861  Can statements remain open across rollbacks?
862  @return <code>true</code> if statements always remain open;
863  <code>false</code> if they might not remain open
864 }
865 function TZInterbase6DatabaseInfo.SupportsOpenStatementsAcrossRollback: Boolean;
866 begin
867  Result := True;
868 end;
869 
870 //----------------------------------------------------------------------
871 // The following group of methods exposes various limitations
872 // based on the target database with the current driver.
873 // Unless otherwise specified, a result of zero means there is no
874 // limit, or the limit is not known.
875 
876 {**
877  How many hex characters can you have in an inline binary literal?
878  @return max binary literal length in hex characters;
879  a result of zero means that there is no limit or the limit is not known
880 }
881 function TZInterbase6DatabaseInfo.GetMaxBinaryLiteralLength: Integer;
882 begin
883  Result := 0;
884 end;
885 
886 {**
887  What's the max length for a character literal?
888  @return max literal length;
889  a result of zero means that there is no limit or the limit is not known
890 }
891 function TZInterbase6DatabaseInfo.GetMaxCharLiteralLength: Integer;
892 begin
893  Result := 1024;
894 end;
895 
896 {**
897  What's the limit on column name length?
898  @return max column name length;
899  a result of zero means that there is no limit or the limit is not known
900 }
901 function TZInterbase6DatabaseInfo.GetMaxColumnNameLength: Integer;
902 begin
903  Result := 31;
904 end;
905 
906 {**
907  What's the maximum number of columns in a "GROUP BY" clause?
908  @return max number of columns;
909  a result of zero means that there is no limit or the limit is not known
910 }
911 function TZInterbase6DatabaseInfo.GetMaxColumnsInGroupBy: Integer;
912 begin
913  Result := 16;
914 end;
915 
916 {**
917  What's the maximum number of columns allowed in an index?
918  @return max number of columns;
919  a result of zero means that there is no limit or the limit is not known
920 }
921 function TZInterbase6DatabaseInfo.GetMaxColumnsInIndex: Integer;
922 begin
923  Result := 16;
924 end;
925 
926 {**
927  What's the maximum number of columns in an "ORDER BY" clause?
928  @return max number of columns;
929  a result of zero means that there is no limit or the limit is not known
930 }
931 function TZInterbase6DatabaseInfo.GetMaxColumnsInOrderBy: Integer;
932 begin
933  Result := 16;
934 end;
935 
936 {**
937  What's the maximum number of columns in a "SELECT" list?
938  @return max number of columns;
939  a result of zero means that there is no limit or the limit is not known
940 }
941 function TZInterbase6DatabaseInfo.GetMaxColumnsInSelect: Integer;
942 begin
943  Result := 32767;
944 end;
945 
946 {**
947  What's the maximum number of columns in a table?
948  @return max number of columns;
949  a result of zero means that there is no limit or the limit is not known
950 }
951 function TZInterbase6DatabaseInfo.GetMaxColumnsInTable: Integer;
952 begin
953  Result := 32767;
954 end;
955 
956 {**
957  How many active connections can we have at a time to this database?
958  @return max number of active connections;
959  a result of zero means that there is no limit or the limit is not known
960 }
961 function TZInterbase6DatabaseInfo.GetMaxConnections: Integer;
962 begin
963  Result := 0;
964 end;
965 
966 {**
967  What's the maximum cursor name length?
968  @return max cursor name length in bytes;
969  a result of zero means that there is no limit or the limit is not known
970 }
971 function TZInterbase6DatabaseInfo.GetMaxCursorNameLength: Integer;
972 begin
973  Result := 31;
974 end;
975 
976 {**
977  Retrieves the maximum number of bytes for an index, including all
978  of the parts of the index.
979  @return max index length in bytes, which includes the composite of all
980  the constituent parts of the index;
981  a result of zero means that there is no limit or the limit is not known
982 }
983 function TZInterbase6DatabaseInfo.GetMaxIndexLength: Integer;
984 begin
985  Result := 198;
986 end;
987 
988 {**
989  What's the maximum length allowed for a schema name?
990  @return max name length in bytes;
991  a result of zero means that there is no limit or the limit is not known
992 }
993 function TZInterbase6DatabaseInfo.GetMaxSchemaNameLength: Integer;
994 begin
995  Result := 0;
996 end;
997 
998 {**
999  What's the maximum length of a procedure name?
1000  @return max name length in bytes;
1001  a result of zero means that there is no limit or the limit is not known
1002 }
1003 function TZInterbase6DatabaseInfo.GetMaxProcedureNameLength: Integer;
1004 begin
1005  Result := 0;
1006 end;
1007 
1008 {**
1009  What's the maximum length of a catalog name?
1010  @return max name length in bytes;
1011  a result of zero means that there is no limit or the limit is not known
1012 }
1013 function TZInterbase6DatabaseInfo.GetMaxCatalogNameLength: Integer;
1014 begin
1015  Result := 27;
1016 end;
1017 
1018 {**
1019  What's the maximum length of a single row?
1020  @return max row size in bytes;
1021  a result of zero means that there is no limit or the limit is not known
1022 }
1023 function TZInterbase6DatabaseInfo.GetMaxRowSize: Integer;
1024 begin
1025  Result := 32664;
1026 end;
1027 
1028 {**
1029  Did getMaxRowSize() include LONGVARCHAR and LONGVARBINARY
1030  blobs?
1031  @return <code>true</code> if so; <code>false</code> otherwise
1032 }
1033 function TZInterbase6DatabaseInfo.DoesMaxRowSizeIncludeBlobs: Boolean;
1034 begin
1035  Result := False;
1036 end;
1037 
1038 {**
1039  What's the maximum length of an SQL statement?
1040  @return max length in bytes;
1041  a result of zero means that there is no limit or the limit is not known
1042 }
1043 function TZInterbase6DatabaseInfo.GetMaxStatementLength: Integer;
1044 begin
1045  Result := 640;
1046 end;
1047 
1048 {**
1049  How many active statements can we have open at one time to this
1050  database?
1051  @return the maximum number of statements that can be open at one time;
1052  a result of zero means that there is no limit or the limit is not known
1053 }
1054 function TZInterbase6DatabaseInfo.GetMaxStatements: Integer;
1055 begin
1056  Result := 0;
1057 end;
1058 
1059 {**
1060  What's the maximum length of a table name?
1061  @return max name length in bytes;
1062  a result of zero means that there is no limit or the limit is not known
1063 }
1064 function TZInterbase6DatabaseInfo.GetMaxTableNameLength: Integer;
1065 begin
1066  Result := 31;
1067 end;
1068 
1069 {**
1070  What's the maximum number of tables in a SELECT statement?
1071  @return the maximum number of tables allowed in a SELECT statement;
1072  a result of zero means that there is no limit or the limit is not known
1073 }
1074 function TZInterbase6DatabaseInfo.GetMaxTablesInSelect: Integer;
1075 begin
1076  Result := 16;
1077 end;
1078 
1079 {**
1080  What's the maximum length of a user name?
1081  @return max user name length in bytes;
1082  a result of zero means that there is no limit or the limit is not known
1083 }
1084 function TZInterbase6DatabaseInfo.GetMaxUserNameLength: Integer;
1085 begin
1086  Result := 31;
1087 end;
1088 
1089 //----------------------------------------------------------------------
1090 
1091 {**
1092  What's the database's default transaction isolation level? The
1093  values are defined in <code>java.sql.Connection</code>.
1094  @return the default isolation level
1095  @see Connection
1096 }
1097 function TZInterbase6DatabaseInfo.GetDefaultTransactionIsolation:
1098  TZTransactIsolationLevel;
1099 begin
1100  Result := tiSerializable;
1101 end;
1102 
1103 {**
1104  Are transactions supported? If not, invoking the method
1105  <code>commit</code> is a noop and the isolation level is TRANSACTION_NONE.
1106  @return <code>true</code> if transactions are supported; <code>false</code> otherwise
1107 }
1108 function TZInterbase6DatabaseInfo.SupportsTransactions: Boolean;
1109 begin
1110  Result := True;
1111 end;
1112 
1113 {**
1114  Does this database support the given transaction isolation level?
1115  @param level the values are defined in <code>java.sql.Connection</code>
1116  @return <code>true</code> if so; <code>false</code> otherwise
1117  @see Connection
1118 }
1119 function TZInterbase6DatabaseInfo.SupportsTransactionIsolationLevel(
1120  Level: TZTransactIsolationLevel): Boolean;
1121 begin
1122  case Level of
1123  tiRepeatableRead, tiReadCommitted, tiSerializable: Result := True;
1124  tiReadUncommitted: Result := False;
1125  tiNone: Result := False; //MAY BE FIX IT
1126  else
1127  Result := False;
1128  end;
1129 end;
1130 
1131 {**
1132  Are both data definition and data manipulation statements
1133  within a transaction supported?
1134  @return <code>true</code> if so; <code>false</code> otherwise
1135 }
1136 function TZInterbase6DatabaseInfo.
1137  SupportsDataDefinitionAndDataManipulationTransactions: Boolean;
1138 begin
1139  Result := True;
1140 end;
1141 
1142 {**
1143  Are only data manipulation statements within a transaction
1144  supported?
1145  @return <code>true</code> if so; <code>false</code> otherwise
1146 }
1147 function TZInterbase6DatabaseInfo.
1148  SupportsDataManipulationTransactionsOnly: Boolean;
1149 begin
1150  Result := False;
1151 end;
1152 
1153 {**
1154  Does a data definition statement within a transaction force the
1155  transaction to commit?
1156  @return <code>true</code> if so; <code>false</code> otherwise
1157 }
1158 function TZInterbase6DatabaseInfo.DataDefinitionCausesTransactionCommit: Boolean;
1159 begin
1160  Result := True;
1161 end;
1162 
1163 {**
1164  Is a data definition statement within a transaction ignored?
1165  @return <code>true</code> if so; <code>false</code> otherwise
1166 }
1167 function TZInterbase6DatabaseInfo.DataDefinitionIgnoredInTransactions: Boolean;
1168 begin
1169  Result := False;
1170 end;
1171 
1172 {**
1173  Does the database support the given result set type?
1174  @param type defined in <code>java.sql.ResultSet</code>
1175  @return <code>true</code> if so; <code>false</code> otherwise
1176 }
1177 function TZInterbase6DatabaseInfo.SupportsResultSetType(
1178  _Type: TZResultSetType): Boolean;
1179 begin
1180  Result := _Type = rtScrollInsensitive;
1181 end;
1182 
1183 {**
1184  Does the database support the concurrency type in combination
1185  with the given result set type?
1186 
1187  @param type defined in <code>java.sql.ResultSet</code>
1188  @param concurrency type defined in <code>java.sql.ResultSet</code>
1189  @return <code>true</code> if so; <code>false</code> otherwise
1190 }
1191 function TZInterbase6DatabaseInfo.SupportsResultSetConcurrency(
1192  _Type: TZResultSetType; Concurrency: TZResultSetConcurrency): Boolean;
1193 begin
1194  Result := (_Type = rtScrollInsensitive) and (Concurrency = rcReadOnly);
1195 end;
1196 
1197 
1198 { TZInterbase6DatabaseMetadata }
1199 
1200 {**
1201  Constructs a database information object and returns the interface to it. Used
1202  internally by the constructor.
1203  @return the database information object interface
1204 }
1205 function TZInterbase6DatabaseMetadata.CreateDatabaseInfo: IZDatabaseInfo;
1206 begin
1207  Result := TZInterbase6DatabaseInfo.Create(Self);
1208 end;
1209 
1210 function TZInterbase6DatabaseMetadata.ConstructNameCondition(Pattern: string;
1211  Column: string): string;
1212 begin
1213  if (GetDatabaseInfo as IZInterbaseDatabaseInfo).HostIsFireBird and
1214  (GetConnection.GetHostVersion < 2000000) then
1215  //Old FireBird do NOT support 'trim'
1216  Result := Inherited ConstructnameCondition(Pattern,Column)
1217  else
1218  Result := Inherited ConstructnameCondition(Pattern,'trim('+Column+')')
1219 end;
1220 
1221 function TZInterbase6DatabaseMetadata.UncachedGetTriggers(const Catalog: string;
1222  const SchemaPattern: string; const TableNamePattern: string;
1223  const TriggerNamePattern: string): IZResultSet;
1224 var
1225  SQL: string;
1226  LTriggerNamePattern: string;
1227  LTableNamePattern: string;
1228 begin
1229  Result:=inherited UncachedGetTriggers(Catalog, SchemaPattern, TableNamePattern, TriggerNamePattern);
1230 
1231  LTriggerNamePattern := ConstructNameCondition(TriggerNamePattern,
1232  'RDB$TRIGGER_NAME');
1233  LTableNamePattern := ConstructNameCondition(TableNamePattern,
1234  'RDB$RELATION_NAME');
1235  If LTriggerNamePattern <> '' then
1236  LTriggerNamePattern := ' and ' + LTriggerNamePattern;
1237  If LTableNamePattern <> '' then
1238  LTableNamePattern := ' and ' + LTableNamePattern;
1239 
1240  SQL := 'SELECT RDB$TRIGGER_NAME, RDB$RELATION_NAME,'
1241  + ' RDB$TRIGGER_TYPE, RDB$TRIGGER_INACTIVE,'
1242  + ' RDB$TRIGGER_SOURCE, RDB$DESCRIPTION FROM RDB$TRIGGERS'
1243  + ' WHERE 1=1' + LTriggerNamePattern + LTableNamePattern;
1244 
1245  with GetConnection.CreateStatement.ExecuteQuery(SQL) do
1246  begin
1247  while Next do
1248  begin
1249  Result.MoveToInsertRow;
1250  Result.UpdateNull(1);
1251  Result.UpdateNull(2);
1252  Result.UpdateString(3, GetString(1)); //RDB$TRIGGER_NAME
1253  Result.UpdateString(4, GetString(2)); //RDB$RELATION_NAME
1254  Result.UpdateShort(5, GetShort(3)); //RDB$TRIGGER_TYPE
1255  Result.UpdateShort(6, GetShort(4)); //RDB$TRIGGER_INACTIVE
1256  Result.UpdateString(7, GetString(5)); //RDB$TRIGGER_SOURCE
1257  Result.UpdateString(8, GetString(6)); //RDB$DESCRIPTION
1258  Result.InsertRow;
1259  end;
1260  Close;
1261  end;
1262 end;
1263 
1264 
1265 {**
1266  Gets a description of the stored procedures available in a
1267  catalog.
1268 
1269  <P>Only procedure descriptions matching the schema and
1270  procedure name criteria are returned. They are ordered by
1271  PROCEDURE_SCHEM, and PROCEDURE_NAME.
1272 
1273  <P>Each procedure description has the the following columns:
1274  <OL>
1275  <LI><B>PROCEDURE_CAT</B> String => procedure catalog (may be null)
1276  <LI><B>PROCEDURE_SCHEM</B> String => procedure schema (may be null)
1277  <LI><B>PROCEDURE_NAME</B> String => procedure name
1278  <LI> reserved for future use
1279  <LI> reserved for future use
1280  <LI> reserved for future use
1281  <LI><B>REMARKS</B> String => explanatory comment on the procedure
1282  <LI><B>PROCEDURE_TYPE</B> short => kind of procedure:
1283  <UL>
1284  <LI> procedureResultUnknown - May return a result
1285  <LI> procedureNoResult - Does not return a result
1286  <LI> procedureReturnsResult - Returns a result
1287  </UL>
1288  </OL>
1289 
1290  @param catalog a catalog name; "" retrieves those without a
1291  catalog; null means drop catalog name from the selection criteria
1292  @param schemaPattern a schema name pattern; "" retrieves those
1293  without a schema
1294  @param procedureNamePattern a procedure name pattern
1295  @return <code>ResultSet</code> - each row is a procedure description
1296  @see #getSearchStringEscape
1297 }
1298 function TZInterbase6DatabaseMetadata.UncachedGetProcedures(const Catalog: string;
1299  const SchemaPattern: string; const ProcedureNamePattern: string): IZResultSet;
1300 var
1301  SQL: string;
1302  LProcedureNamePattern: string;
1303 begin
1304  Result:=inherited UncachedGetProcedures(Catalog, SchemaPattern, ProcedureNamePattern);
1305 
1306  LProcedureNamePattern := ConstructNameCondition(ProcedureNamePattern,
1307  'RDB$PROCEDURE_NAME');
1308  If LProcedureNamePattern <> '' then
1309  LProcedureNamePattern := ' and ' + LProcedureNamePattern;
1310 
1311  SQL := 'SELECT RDB$PROCEDURE_NAME, RDB$PROCEDURE_OUTPUTS,'
1312  + ' RDB$DESCRIPTION FROM RDB$PROCEDURES'
1313  + ' WHERE 1=1' + LProcedureNamePattern;
1314 
1315  with GetConnection.CreateStatement.ExecuteQuery(SQL) do
1316  begin
1317  while Next do
1318  begin
1319  Result.MoveToInsertRow;
1320  Result.UpdateNull(1);
1321  Result.UpdateNull(2);
1322  Result.UpdateString(3, GetString(1)); //RDB$PROCEDURE_NAME
1323  Result.UpdateNull(4);
1324  Result.UpdateNull(5);
1325  Result.UpdateNull(6);
1326  Result.UpdateString(7, GetString(3)); //RDB$DESCRIPTION
1327  if IsNull(2) then //RDB$PROCEDURE_OUTPUTS
1328  Result.UpdateInt(8, Ord(prtNoResult))
1329  else Result.UpdateInt(8, Ord(prtReturnsResult));
1330  Result.InsertRow;
1331  end;
1332  Close;
1333  end;
1334 end;
1335 
1336 {**
1337  Gets a description of a catalog's stored procedure parameters
1338  and result columns.
1339 
1340  <P>Only descriptions matching the schema, procedure and
1341  parameter name criteria are returned. They are ordered by
1342  PROCEDURE_SCHEM and PROCEDURE_NAME. Within this, the return value,
1343  if any, is first. Next are the parameter descriptions in call
1344  order. The column descriptions follow in column number order.
1345 
1346  <P>Each row in the <code>ResultSet</code> is a parameter description or
1347  column description with the following fields:
1348  <OL>
1349  <LI><B>PROCEDURE_CAT</B> String => procedure catalog (may be null)
1350  <LI><B>PROCEDURE_SCHEM</B> String => procedure schema (may be null)
1351  <LI><B>PROCEDURE_NAME</B> String => procedure name
1352  <LI><B>COLUMN_NAME</B> String => column/parameter name
1353  <LI><B>COLUMN_TYPE</B> Short => kind of column/parameter:
1354  <UL>
1355  <LI> procedureColumnUnknown - nobody knows
1356  <LI> procedureColumnIn - IN parameter
1357  <LI> procedureColumnInOut - INOUT parameter
1358  <LI> procedureColumnOut - OUT parameter
1359  <LI> procedureColumnReturn - procedure return value
1360  <LI> procedureColumnResult - result column in <code>ResultSet</code>
1361  </UL>
1362  <LI><B>DATA_TYPE</B> short => SQL type from java.sql.Types
1363  <LI><B>TYPE_NAME</B> String => SQL type name, for a UDT type the
1364  type name is fully qualified
1365  <LI><B>PRECISION</B> int => precision
1366  <LI><B>LENGTH</B> int => length in bytes of data
1367  <LI><B>SCALE</B> short => scale
1368  <LI><B>RADIX</B> short => radix
1369  <LI><B>NULLABLE</B> short => can it contain NULL?
1370  <UL>
1371  <LI> procedureNoNulls - does not allow NULL values
1372  <LI> procedureNullable - allows NULL values
1373  <LI> procedureNullableUnknown - nullability unknown
1374  </UL>
1375  <LI><B>REMARKS</B> String => comment describing parameter/column
1376  </OL>
1377 
1378  <P><B>Note:</B> Some databases may not return the column
1379  descriptions for a procedure. Additional columns beyond
1380  REMARKS can be defined by the database.
1381 
1382  @param catalog a catalog name; "" retrieves those without a
1383  catalog; null means drop catalog name from the selection criteria
1384  @param schemaPattern a schema name pattern; "" retrieves those
1385  without a schema
1386  @param procedureNamePattern a procedure name pattern
1387  @param columnNamePattern a column name pattern
1388  @return <code>ResultSet</code> - each row describes a stored procedure parameter or
1389  column
1390  @see #getSearchStringEscape
1391 }
1392 function TZInterbase6DatabaseMetadata.UncachedGetProcedureColumns(const Catalog: string;
1393  const SchemaPattern: string; const ProcedureNamePattern: string;
1394  const ColumnNamePattern: string): IZResultSet;
1395 var
1396  SQL: string;
1397  LProcedureNamePattern, LColumnNamePattern: string;
1398  TypeName, SubTypeName: Integer;
1399  ColumnIndexes : Array[1..8] of integer;
1400 begin
1401  Result:=inherited UncachedGetProcedureColumns(Catalog, SchemaPattern, ProcedureNamePattern, ColumnNamePattern);
1402 
1403  LProcedureNamePattern := ConstructNameCondition(ProcedureNamePattern,
1404  'P.RDB$PROCEDURE_NAME');
1405  LColumnNamePattern := ConstructNameCondition(ColumnNamePattern,
1406  'PP.RDB$PARAMETER_NAME');
1407  If LProcedureNamePattern <> '' then
1408  LProcedureNamePattern := ' and ' + LProcedureNamePattern;
1409  If LColumnNamePattern <> '' then
1410  LColumnNamePattern := ' and ' + LColumnNamePattern;
1411 
1412  if (StrPos(PChar(GetDatabaseInfo.GetServerVersion), 'Interbase 5') <> nil)
1413  or (StrPos(PChar(GetDatabaseInfo.GetServerVersion), 'V5.') <> nil) then
1414  begin
1415  SQL := ' SELECT P.RDB$PROCEDURE_NAME, PP.RDB$PARAMETER_NAME,'
1416  + ' PP.RDB$PARAMETER_TYPE, F.RDB$FIELD_TYPE, F.RDB$FIELD_SUB_TYPE,'
1417  + ' F.RDB$FIELD_SCALE, F.RDB$FIELD_LENGTH, F.RDB$NULL_FLAG,'
1418  + ' PP.RDB$DESCRIPTION, F.RDB$FIELD_SCALE as RDB$FIELD_PRECISION,'
1419  + ' F.RDB$NULL_FLAG FROM RDB$PROCEDURES P'
1420  + ' JOIN RDB$PROCEDURE_PARAMETERS PP ON P.RDB$PROCEDURE_NAME'
1421  + '=PP.RDB$PROCEDURE_NAME JOIN RDB$FIELDS F ON PP.RDB$FIELD_SOURCE'
1422  + '=F.RDB$FIELD_NAME '
1423  + ' WHERE 1=1' + LProcedureNamePattern + LColumnNamePattern
1424  + ' ORDER BY P.RDB$PROCEDURE_NAME,'
1425  + ' PP.RDB$PARAMETER_TYPE, PP.RDB$PARAMETER_NUMBER';
1426  end
1427  else
1428  begin
1429  SQL := ' SELECT P.RDB$PROCEDURE_NAME, PP.RDB$PARAMETER_NAME,'
1430  + ' PP.RDB$PARAMETER_TYPE, F.RDB$FIELD_TYPE, F.RDB$FIELD_SUB_TYPE,'
1431  + ' F.RDB$FIELD_SCALE, F.RDB$FIELD_LENGTH, F.RDB$NULL_FLAG,'
1432  + ' PP.RDB$DESCRIPTION, F.RDB$FIELD_PRECISION, F.RDB$NULL_FLAG '
1433  + ' FROM RDB$PROCEDURES P JOIN RDB$PROCEDURE_PARAMETERS PP ON'
1434  + ' P.RDB$PROCEDURE_NAME = PP.RDB$PROCEDURE_NAME '
1435  + ' JOIN RDB$FIELDS F ON PP.RDB$FIELD_SOURCE = F.RDB$FIELD_NAME '
1436  + ' WHERE 1=1' + LProcedureNamePattern + LColumnNamePattern
1437  + ' ORDER BY P.RDB$PROCEDURE_NAME,'
1438  + ' PP.RDB$PARAMETER_TYPE, PP.RDB$PARAMETER_NUMBER';
1439  end;
1440 
1441  with GetConnection.CreateStatement.ExecuteQuery(SQL) do
1442  begin
1443  ColumnIndexes[1] := FindColumn('RDB$PROCEDURE_NAME');
1444  ColumnIndexes[2] := FindColumn('RDB$PARAMETER_NAME');
1445  ColumnIndexes[3] := FindColumn('RDB$PARAMETER_TYPE');
1446  ColumnIndexes[4] := FindColumn('RDB$FIELD_TYPE');
1447  ColumnIndexes[5] := FindColumn('RDB$FIELD_SUB_TYPE');
1448  ColumnIndexes[6] := FindColumn('RDB$FIELD_PRECISION');
1449  ColumnIndexes[7] := FindColumn('RDB$FIELD_SCALE');
1450  ColumnIndexes[8] := FindColumn('RDB$NULL_FLAG');
1451  while Next do
1452  begin
1453  TypeName := GetInt(ColumnIndexes[4]);
1454  SubTypeName := GetInt(ColumnIndexes[5]);
1455 
1456  Result.MoveToInsertRow;
1457  Result.UpdateNull(1); //PROCEDURE_CAT
1458  Result.UpdateNull(2); //PROCEDURE_SCHEM
1459  Result.UpdateString(3, GetString(ColumnIndexes[1])); //TABLE_NAME
1460  Result.UpdateString(4, GetString(ColumnIndexes[2])); //COLUMN_NAME
1461  case GetInt(ColumnIndexes[3]) of
1462  0: Result.UpdateInt(5, Ord(pctIn));
1463  1: Result.UpdateInt(5, Ord(pctOut));
1464  else
1465  Result.UpdateInt(5, Ord(pctUnknown));
1466  end;
1467 
1468  Result.UpdateInt(6,
1469  Ord(ConvertInterbase6ToSqlType(TypeName, SubTypeName,
1470  ConSettings.CPType))); //DATA_TYPE
1471  Result.UpdateString(7,GetString(ColumnIndexes[4])); //TYPE_NAME
1472  Result.UpdateInt(10, GetInt(ColumnIndexes[6]));
1473  Result.UpdateNull(9); //BUFFER_LENGTH
1474  Result.UpdateInt(10, GetInt(ColumnIndexes[7]));
1475  Result.UpdateInt(11, 10);
1476  Result.UpdateInt(12, GetInt(ColumnIndexes[8]));
1477  Result.UpdateString(12, GetString(ColumnIndexes[6]));
1478  Result.InsertRow;
1479  end;
1480  Close;
1481  end;
1482 end;
1483 
1484 {**
1485  Gets a description of tables available in a catalog.
1486 
1487  <P>Only table descriptions matching the catalog, schema, table
1488  name and type criteria are returned. They are ordered by
1489  TABLE_TYPE, TABLE_SCHEM and TABLE_NAME.
1490 
1491  <P>Each table description has the following columns:
1492  <OL>
1493  <LI><B>TABLE_CAT</B> String => table catalog (may be null)
1494  <LI><B>TABLE_SCHEM</B> String => table schema (may be null)
1495  <LI><B>TABLE_NAME</B> String => table name
1496  <LI><B>TABLE_TYPE</B> String => table type. Typical types are "TABLE",
1497  "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY",
1498  "LOCAL TEMPORARY", "ALIAS", "SYNONYM".
1499  <LI><B>REMARKS</B> String => explanatory comment on the table
1500  </OL>
1501 
1502  <P><B>Note:</B> Some databases may not return information for
1503  all tables.
1504 
1505  @param catalog a catalog name; "" retrieves those without a
1506  catalog; null means drop catalog name from the selection criteria
1507  @param schemaPattern a schema name pattern; "" retrieves those
1508  without a schema
1509  @param tableNamePattern a table name pattern
1510  @param types a list of table types to include; null returns all types
1511  @return <code>ResultSet</code> - each row is a table description
1512  @see #getSearchStringEscape
1513 }
1514 
1515 function TZInterbase6DatabaseMetadata.UncachedGetTables(const Catalog: string;
1516  const SchemaPattern: string; const TableNamePattern: string;
1517  const Types: TStringDynArray): IZResultSet;
1518 var
1519  SQL, TableType: string;
1520  I, SystemFlag: Integer;
1521  TableNameCondition: string;
1522 
1523 begin
1524  Result:=inherited UncachedGetTables(Catalog, SchemaPattern, TableNamePattern, Types);
1525 
1526  TableNameCondition := ConstructNameCondition(TableNamePattern,
1527  'a.RDB$RELATION_NAME');
1528  If TableNameCondition <> '' then
1529  TableNameCondition := ' and ' + TableNameCondition;
1530 
1531  SQL := 'SELECT DISTINCT a.RDB$RELATION_NAME, a.RDB$SYSTEM_FLAG, '
1532  + ' a.RDB$VIEW_SOURCE, a.RDB$DESCRIPTION FROM RDB$RELATIONS a'
1533  + ' WHERE 1=1' + TableNameCondition;
1534 
1535  with GetConnection.CreateStatement.ExecuteQuery(SQL) do
1536  begin
1537  while Next do
1538  begin
1539  SystemFlag := GetInt(2); //RDB$SYSTEM_FLAG
1540 
1541  if SystemFlag = 0 then
1542  begin
1543  if IsNull(3) then //RDB$VIEW_SOURCE
1544  TableType := 'TABLE'
1545  else
1546  TableType := 'VIEW';
1547  end
1548  else
1549  TableType := 'SYSTEM TABLE';
1550 
1551  if Length(Types) = 0 then
1552  begin
1553  Result.MoveToInsertRow;
1554  Result.UpdateNull(1);
1555  Result.UpdateNull(2);
1556  Result.UpdateString(3, GetString(1)); //RDB$RELATION_NAME
1557  Result.UpdateString(4, TableType);
1558  Result.UpdateString(5, Copy(GetString(4),1,255)); //RDB$DESCRIPTION
1559  Result.InsertRow;
1560  end
1561  else
1562  begin
1563  for I := 0 to High(Types) do
1564  begin
1565  if Types[I] = TableType then
1566  begin
1567  Result.MoveToInsertRow;
1568  Result.UpdateNull(1);
1569  Result.UpdateNull(2);
1570  Result.UpdateString(3, GetString(1)); //RDB$RELATION_NAME
1571  Result.UpdateString(4, TableType);
1572  Result.UpdateString(5, Copy(GetString(4),1,255)); //RDB$DESCRIPTION
1573  Result.InsertRow;
1574  end;
1575  end;
1576  end;
1577 
1578  end;
1579  Close;
1580  end;
1581 end;
1582 
1583 {**
1584  Gets the table types available in this database. The results
1585  are ordered by table type.
1586 
1587  <P>The table type is:
1588  <OL>
1589  <LI><B>TABLE_TYPE</B> String => table type. Typical types are "TABLE",
1590  "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY",
1591  "LOCAL TEMPORARY", "ALIAS", "SYNONYM".
1592  </OL>
1593 
1594  @return <code>ResultSet</code> - each row has a single String column that is a
1595  table type
1596 }
1597 function TZInterbase6DatabaseMetadata.UncachedGetTableTypes: IZResultSet;
1598 const
1599  TablesTypes: array [0..2] of String = ('TABLE', 'VIEW', 'SYSTEM TABLE');
1600 var
1601  I: Integer;
1602 begin
1603  Result:=inherited UncachedGetTableTypes;
1604 
1605  for I := 0 to 2 do
1606  begin
1607  Result.MoveToInsertRow;
1608  Result.UpdateString(1, TablesTypes[I]);
1609  Result.InsertRow;
1610  end;
1611 end;
1612 
1613 {**
1614  Gets a description of table columns available in
1615  the specified catalog.
1616 
1617  <P>Only column descriptions matching the catalog, schema, table
1618  and column name criteria are returned. They are ordered by
1619  TABLE_SCHEM, TABLE_NAME and ORDINAL_POSITION.
1620 
1621  <P>Each column description has the following columns:
1622  <OL>
1623  <LI><B>TABLE_CAT</B> String => table catalog (may be null)
1624  <LI><B>TABLE_SCHEM</B> String => table schema (may be null)
1625  <LI><B>TABLE_NAME</B> String => table name
1626  <LI><B>COLUMN_NAME</B> String => column name
1627  <LI><B>DATA_TYPE</B> short => SQL type from java.sql.Types
1628  <LI><B>TYPE_NAME</B> String => Data source dependent type name,
1629  for a UDT the type name is fully qualified
1630  <LI><B>COLUMN_SIZE</B> int => column size. For char or date
1631  types this is the maximum number of characters, for numeric or
1632  decimal types this is precision.
1633  <LI><B>BUFFER_LENGTH</B> is not used.
1634  <LI><B>DECIMAL_DIGITS</B> int => the number of fractional digits
1635  <LI><B>NUM_PREC_RADIX</B> int => Radix (typically either 10 or 2)
1636  <LI><B>NULLABLE</B> int => is NULL allowed?
1637  <UL>
1638  <LI> columnNoNulls - might not allow NULL values
1639  <LI> columnNullable - definitely allows NULL values
1640  <LI> columnNullableUnknown - nullability unknown
1641  </UL>
1642  <LI><B>REMARKS</B> String => comment describing column (may be null)
1643  <LI><B>COLUMN_DEF</B> String => default value (may be null)
1644  <LI><B>SQL_DATA_TYPE</B> int => unused
1645  <LI><B>SQL_DATETIME_SUB</B> int => unused
1646  <LI><B>CHAR_OCTET_LENGTH</B> int => for char types the
1647  maximum number of bytes in the column
1648  <LI><B>ORDINAL_POSITION</B> int => index of column in table
1649  (starting at 1)
1650  <LI><B>IS_NULLABLE</B> String => "NO" means column definitely
1651  does not allow NULL values; "YES" means the column might
1652  allow NULL values. An empty string means nobody knows.
1653  </OL>
1654 
1655  @param catalog a catalog name; "" retrieves those without a
1656  catalog; null means drop catalog name from the selection criteria
1657  @param schemaPattern a schema name pattern; "" retrieves those
1658  without a schema
1659  @param tableNamePattern a table name pattern
1660  @param columnNamePattern a column name pattern
1661  @return <code>ResultSet</code> - each row is a column description
1662  @see #getSearchStringEscape
1663 }
1664 
1665 function TZInterbase6DatabaseMetadata.UncachedGetColumns(const Catalog: string;
1666  const SchemaPattern: string; const TableNamePattern: string;
1667  const ColumnNamePattern: string): IZResultSet;
1668 var
1669  SQL, ColumnName, DefaultValue: String;
1670  TypeName, SubTypeName, FieldScale: integer;
1671  LTableNamePattern, LColumnNamePattern: string;
1672  ColumnIndexes : Array[1..15] of integer;
1673  SQLType: TZSQLType;
1674 begin
1675  Result:=inherited UncachedGetColumns(Catalog, SchemaPattern, TableNamePattern, ColumnNamePattern);
1676 
1677  LTableNamePattern := ConstructNameCondition(TableNamePattern,
1678  'a.RDB$RELATION_NAME');
1679  LColumnNamePattern := ConstructNameCondition(ColumnNamePattern,
1680  'a.RDB$FIELD_NAME');
1681  If LTableNamePattern <> '' then
1682  LTableNamePattern := ' and ' + LTableNamePattern;
1683  If LColumnNamePattern <> '' then
1684  LColumnNamePattern := ' and ' + LColumnNamePattern;
1685 
1686  if (StrPos(PChar(GetDatabaseInfo.GetServerVersion), 'Interbase 5') <> nil)
1687  or (StrPos(PChar(GetDatabaseInfo.GetServerVersion), 'V5.') <> nil) then
1688  begin
1689  SQL := 'SELECT a.RDB$RELATION_NAME, a.RDB$FIELD_NAME, a.RDB$FIELD_POSITION,'
1690  + ' a.RDB$NULL_FLAG, b. RDB$FIELD_LENGTH, b.RDB$FIELD_SCALE,'
1691  + ' c.RDB$TYPE_NAME, b.RDB$FIELD_TYPE, b.RDB$FIELD_SUB_TYPE,'
1692  + ' b.RDB$DESCRIPTION, b.RDB$CHARACTER_LENGTH, b.RDB$FIELD_SCALE'
1693  + ' as RDB$FIELD_PRECISION, a.RDB$DEFAULT_SOURCE, b.RDB$DEFAULT_SOURCE'
1694  + ' as RDB$DEFAULT_SOURCE_DOMAIN, b.RDB$COMPUTED_SOURCE as RDB$COMPUTED_SOURCE'
1695  + ' , b.RDB$CHARACTER_SET_ID FROM RDB$RELATION_FIELDS a'
1696  + ' JOIN RDB$FIELDS b ON (b.RDB$FIELD_NAME = a.RDB$FIELD_SOURCE)'
1697  + ' LEFT JOIN RDB$TYPES c ON b.RDB$FIELD_TYPE = c.RDB$TYPE'
1698  + ' and c.RDB$FIELD_NAME = ''RDB$FIELD_TYPE'''
1699  + ' WHERE 1=1' + LTableNamePattern + LColumnNamePattern
1700  + ' ORDER BY a.RDB$RELATION_NAME, a.RDB$FIELD_POSITION';
1701  end
1702  else
1703  begin
1704  SQL := ' SELECT a.RDB$RELATION_NAME, a.RDB$FIELD_NAME, a.RDB$FIELD_POSITION,'
1705  + ' a.RDB$NULL_FLAG, a.RDB$DEFAULT_VALUE, b. RDB$FIELD_LENGTH,'
1706  + ' b.RDB$FIELD_SCALE, c.RDB$TYPE_NAME, b.RDB$FIELD_TYPE,'
1707  + ' b.RDB$FIELD_SUB_TYPE, b.RDB$DESCRIPTION, b.RDB$CHARACTER_LENGTH,'
1708  + ' b.RDB$FIELD_PRECISION, a.RDB$DEFAULT_SOURCE, b.RDB$DEFAULT_SOURCE'
1709  + ' as RDB$DEFAULT_SOURCE_DOMAIN,b.RDB$COMPUTED_SOURCE as RDB$COMPUTED_SOURCE'
1710  + ' , b.RDB$CHARACTER_SET_ID FROM RDB$RELATION_FIELDS a'
1711  + ' JOIN RDB$FIELDS b ON (b.RDB$FIELD_NAME = a.RDB$FIELD_SOURCE)'
1712  + ' LEFT JOIN RDB$TYPES c ON (b.RDB$FIELD_TYPE = c.RDB$TYPE'
1713  + ' and c.RDB$FIELD_NAME = ''RDB$FIELD_TYPE'')'
1714  + ' WHERE 1=1' + LTableNamePattern + LColumnNamePattern
1715  + ' ORDER BY a.RDB$RELATION_NAME, a.RDB$FIELD_POSITION';
1716  end;
1717 
1718  with GetConnection.CreateStatement.ExecuteQuery(SQL) do
1719  begin
1720  ColumnIndexes[1] := FindColumn('RDB$FIELD_TYPE');
1721  ColumnIndexes[2] := FindColumn('RDB$FIELD_SUB_TYPE');
1722  ColumnIndexes[3] := FindColumn('RDB$FIELD_SCALE');
1723  ColumnIndexes[4] := FindColumn('RDB$FIELD_NAME');
1724  ColumnIndexes[5] := FindColumn('RDB$DEFAULT_SOURCE');
1725  ColumnIndexes[6] := FindColumn('RDB$DEFAULT_SOURCE_DOMAIN');
1726  ColumnIndexes[7] := FindColumn('RDB$RELATION_NAME');
1727  ColumnIndexes[8] := FindColumn('RDB$TYPE_NAME');
1728  ColumnIndexes[9] := FindColumn('RDB$FIELD_PRECISION');
1729  ColumnIndexes[10] := FindColumn('RDB$FIELD_LENGTH');
1730  ColumnIndexes[11] := FindColumn('RDB$NULL_FLAG');
1731  ColumnIndexes[12] := FindColumn('RDB$DESCRIPTION');
1732  ColumnIndexes[13] := FindColumn('RDB$FIELD_POSITION');
1733  ColumnIndexes[14] := FindColumn('RDB$COMPUTED_SOURCE');
1734  ColumnIndexes[15] := FindColumn('RDB$CHARACTER_SET_ID');
1735  while Next do
1736  begin
1737  TypeName := GetInt(ColumnIndexes[1]);
1738  if TypeName = 14 then //'TEXT'
1739  SubTypeName := GetInt(ColumnIndexes[15]) //need a way to determine CS_Binary (octets) for stBytes on the other hand the subtype is useless here
1740  else
1741  SubTypeName := GetInt(ColumnIndexes[2]);
1742  FieldScale := GetInt(ColumnIndexes[3]);
1743  ColumnName := GetString(ColumnIndexes[4]);
1744 
1745  if (GetString(ColumnIndexes[14]) <> '') then //AVZ -- not isNull(14) was not working correcly here could be ' ' - subselect
1746  begin //Computed by Source & Sub Selects //AVZ
1747  if ((TypeName = 16) and (FieldScale < 0)) then SubTypeName := 1; // Fix for 0 subtype which removes decimals
1748  end;
1749 
1750  DefaultValue := GetString(ColumnIndexes[5]);
1751  if DefaultValue = '' then
1752  DefaultValue := GetString(ColumnIndexes[6]);
1753  if StartsWith(Trim(UpperCase(DefaultValue)), 'DEFAULT') then
1754  begin
1755  DefaultValue := Trim(StringReplace(DefaultValue, 'DEFAULT ', '',
1756  [rfIgnoreCase]));
1757  end;
1758 
1759  IF (UpperCase(DefaultValue)= '''NOW''') or (UpperCase(DefaultValue)= '"NOW"')then
1760  case TypeName of
1761  12: DefaultValue := 'CURRENT_DATE';
1762  13: DefaultValue := 'CURRENT_TIME';
1763  35: DefaultValue := 'CURRENT_TIMESTAMP';
1764  else begin end;
1765  end;
1766 
1767  Result.MoveToInsertRow;
1768  Result.UpdateNull(1); //TABLE_CAT
1769  Result.UpdateNull(2); //TABLE_SCHEM
1770  Result.UpdateString(3, GetString(ColumnIndexes[7])); //TABLE_NAME
1771  Result.UpdateString(4, ColumnName); //COLUMN_NAME
1772  SQLType := ConvertInterbase6ToSqlType(TypeName, SubTypeName
1773  , ConSettings.CPType);
1774  Result.UpdateInt(5, Ord(SQLType));
1775  // TYPE_NAME
1776  case TypeName of
1777  7 : Result.UpdateString(6, 'SMALLINT');
1778  8 : Result.UpdateString(6, 'INTEGER' );
1779  16 :
1780  begin
1781  if (SubTypeName = 0) then
1782  Result.UpdateString(6, GetString(ColumnIndexes[8]));
1783  if (SubTypeName = 1) then
1784  Result.UpdateString(6, 'NUMERIC');
1785  if (SubTypeName = 2) then
1786  Result.UpdateString(6, 'DECIMAL');
1787  end;
1788  37 : Result.UpdateString(6, 'VARCHAR'); // Instead of VARYING
1789  else
1790  Result.UpdateString(6, GetString(ColumnIndexes[8]));
1791  end;
1792  // COLUMN_SIZE.
1793  case TypeName of
1794  7, 8 : Result.UpdateInt(7, 0);
1795  16 : Result.UpdateInt(7, GetInt(ColumnIndexes[9]));
1796  37, 38: Result.UpdateNull(7); //the defaults of the resultsets will be used if null
1797  {if ( ConSettings.ClientCodePage.ID = 0 ) then //CharcterSet 'NONE'
1798  Result.UpdateInt(7, GetFieldSize(SQLType, ConSettings,
1799  GetInt(ColumnIndexes[10]), GetConnection.GetIZPlainDriver.ValidateCharEncoding(SubTypeName).CharWidth, nil, True)) //FireBird return Char*Bytes for Varchar
1800  else
1801  Result.UpdateInt(7, GetFieldSize(SQLType, ConSettings,
1802  GetInt(ColumnIndexes[10]), ConSettings.ClientCodePage.CharWidth, nil, True)); //FireBird return Char*Bytes for Varchar}
1803  else
1804  Result.UpdateInt(7, GetInt(ColumnIndexes[10]));
1805  end;
1806 
1807  Result.UpdateNull(8); //BUFFER_LENGTH
1808 
1809  if FieldScale < 0 then
1810  Result.UpdateInt(9, -1 * FieldScale) //DECIMAL_DIGITS
1811  else
1812  Result.UpdateInt(9, 0); //DECIMAL_DIGITS
1813 
1814  Result.UpdateInt(10, 10); //NUM_PREC_RADIX
1815 
1816  if GetInt(ColumnIndexes[11]) <> 0 then
1817  Result.UpdateInt(11, Ord(ntNoNulls)) //NULLABLE
1818  else
1819  Result.UpdateInt(11, Ord(ntNullable));
1820 
1821  Result.UpdateString(12, Copy(GetString(ColumnIndexes[12]),1,255)); //REMARKS
1822  Result.UpdateString(13, DefaultValue); //COLUMN_DEF
1823  Result.UpdateNull(14); //SQL_DATA_TYPE
1824  Result.UpdateNull(15); //SQL_DATETIME_SUB
1825  Result.UpdateInt(16,
1826  GetInt(7)); //CHAR_OCTET_LENGTH
1827  Result.UpdateInt(17, GetInt(ColumnIndexes[13]) + 1); //ORDINAL_POSITION
1828 
1829  if IsNull(ColumnIndexes[11]) then
1830  Result.UpdateString(18, 'YES') //IS_NULLABLE
1831  else
1832  Result.UpdateString(18, 'NO'); //IS_NULLABLE
1833 
1834  Result.UpdateNull(19); //AUTO_INCREMENT
1835 
1836  if CompareStr(ColumnName, UpperCase(ColumnName)) = 0 then
1837  Result.UpdateBoolean(20, False) //CASE_SENSITIVE
1838  else
1839  Result.UpdateBoolean(20, True); //CASE_SENSITIVE
1840 
1841  Result.UpdateBoolean(21, True); //SEARCHABLE
1842  if isNull(ColumnIndexes[14]) then
1843  begin
1844  Result.UpdateBoolean(22, True); //WRITABLE
1845  Result.UpdateBoolean(23, True); //DEFINITELYWRITABLE
1846  Result.UpdateBoolean(24, False); //READONLY
1847  end
1848  else
1849  begin
1850  Result.UpdateBoolean(22, False); //WRITABLE
1851  Result.UpdateBoolean(23, False); //DEFINITELYWRITABLE
1852  Result.UpdateBoolean(24, True); //READONLY
1853  end;
1854  Result.InsertRow;
1855  end;
1856  Close;
1857  end;
1858 end;
1859 
1860 {**
1861  Gets a description of the access rights for a table's columns.
1862 
1863  <P>Only privileges matching the column name criteria are
1864  returned. They are ordered by COLUMN_NAME and PRIVILEGE.
1865 
1866  <P>Each privilige description has the following columns:
1867  <OL>
1868  <LI><B>TABLE_CAT</B> String => table catalog (may be null)
1869  <LI><B>TABLE_SCHEM</B> String => table schema (may be null)
1870  <LI><B>TABLE_NAME</B> String => table name
1871  <LI><B>COLUMN_NAME</B> String => column name
1872  <LI><B>GRANTOR</B> => grantor of access (may be null)
1873  <LI><B>GRANTEE</B> String => grantee of access
1874  <LI><B>PRIVILEGE</B> String => name of access (SELECT,
1875  INSERT, UPDATE, REFRENCES, ...)
1876  <LI><B>IS_GRANTABLE</B> String => "YES" if grantee is permitted
1877  to grant to others; "NO" if not; null if unknown
1878  </OL>
1879 
1880  @param catalog a catalog name; "" retrieves those without a
1881  catalog; null means drop catalog name from the selection criteria
1882  @param schema a schema name; "" retrieves those without a schema
1883  @param table a table name
1884  @param columnNamePattern a column name pattern
1885  @return <code>ResultSet</code> - each row is a column privilege description
1886  @see #getSearchStringEscape
1887 }
1888 function TZInterbase6DatabaseMetadata.UncachedGetColumnPrivileges(const Catalog: string;
1889  const Schema: string; const Table: string; const ColumnNamePattern: string): IZResultSet;
1890 var
1891  SQL: string;
1892  TableName, FieldName, Privilege: String;
1893  Grantor, Grantee, Grantable: String;
1894  LColumnNamePattern, LTable: String;
1895 begin
1896  Result:=inherited UncachedGetColumnPrivileges(Catalog, Schema, Table, ColumnNamePattern);
1897 
1898  LTable := ConstructNameCondition(AddEscapeCharToWildcards(Table), 'a.RDB$RELATION_NAME');
1899  LColumnNamePattern := ConstructNameCondition(ColumnNamePattern, 'a.RDB$FIELD_NAME');
1900  if LTable <> '' then
1901  LTable := ' and ' + LTable;
1902  if LColumnNamePattern <> '' then
1903  LColumnNamePattern := ' and ' + LColumnNamePattern;
1904 
1905  SQL := 'SELECT a.RDB$USER, a.RDB$GRANTOR, a.RDB$PRIVILEGE,'
1906  + ' a.RDB$GRANT_OPTION, a.RDB$RELATION_NAME, a.RDB$FIELD_NAME '
1907  + ' FROM RDB$USER_PRIVILEGES a, RDB$TYPES b '
1908  + ' WHERE a.RDB$OBJECT_TYPE = b.RDB$TYPE '
1909  + LTable + LColumnNamePattern
1910  + ' and b.RDB$TYPE_NAME IN (''RELATION'', ''VIEW'','
1911  + ' ''COMPUTED_FIELD'', ''FIELD'' ) AND b.RDB$FIELD_NAME'
1912  + '=''RDB$OBJECT_TYPE'' ORDER BY a.RDB$FIELD_NAME, a.RDB$PRIVILEGE ' ;
1913 
1914  with GetConnection.CreateStatement.ExecuteQuery(SQL) do
1915  begin
1916  while Next do
1917  begin
1918 
1919  TableName := GetString(5); //RDB$RELATION_NAME
1920  FieldName := GetString(6); //RDB$FIELD_NAME
1921  Privilege := GetPrivilege(GetString(3)); //RDB$PRIVILEGE
1922  Grantor := GetString(2); //RDB$GRANTOR
1923  Grantee := GetString(1); //RDB$USER
1924  if Grantor = Grantee then
1925  Grantable := 'YES'
1926  else
1927  Grantable := 'NO';
1928  if FieldName = '' then
1929  begin
1930  LTable := ConstructNameCondition(TableName, 'a.RDB$RELATION_NAME');
1931  SQL := 'SELECT RDB$FIELD_NAME FROM RDB$RELATION_FIELDS A'
1932  + ' WHERE ' + LTable + LColumnNamePattern;
1933  with GetConnection.CreateStatement.ExecuteQuery(SQL) do
1934  begin
1935  while Next do
1936  begin
1937  Result.MoveToInsertRow;
1938  Result.UpdateNull(1);
1939  Result.UpdateNull(2);
1940  Result.UpdateString(3, TableName);
1941  Result.UpdateString(4, GetString(1));
1942  Result.UpdateString(5, Grantor);
1943  Result.UpdateString(6, Grantee);
1944  Result.UpdateString(7, Privilege);
1945  Result.UpdateString(8, Grantable);
1946  Result.InsertRow;
1947  end;
1948  Close;
1949  end;
1950  end
1951  else
1952  begin
1953  Result.MoveToInsertRow;
1954  Result.UpdateNull(1);
1955  Result.UpdateNull(2);
1956  Result.UpdateString(3, TableName);
1957  Result.UpdateString(4, FieldName);
1958  Result.UpdateString(5, Grantor);
1959  Result.UpdateString(6, Grantee);
1960  Result.UpdateString(7, Privilege);
1961  Result.UpdateString(8, Grantable);
1962  Result.InsertRow;
1963  end;
1964  end;
1965  Close;
1966  end;
1967 end;
1968 
1969 {**
1970  Gets a description of the access rights for each table available
1971  in a catalog. Note that a table privilege applies to one or
1972  more columns in the table. It would be wrong to assume that
1973  this priviledge applies to all columns (this may be true for
1974  some systems but is not true for all.)
1975 
1976  <P>Only privileges matching the schema and table name
1977  criteria are returned. They are ordered by TABLE_SCHEM,
1978  TABLE_NAME, and PRIVILEGE.
1979 
1980  <P>Each privilige description has the following columns:
1981  <OL>
1982  <LI><B>TABLE_CAT</B> String => table catalog (may be null)
1983  <LI><B>TABLE_SCHEM</B> String => table schema (may be null)
1984  <LI><B>TABLE_NAME</B> String => table name
1985  <LI><B>GRANTOR</B> => grantor of access (may be null)
1986  <LI><B>GRANTEE</B> String => grantee of access
1987  <LI><B>PRIVILEGE</B> String => name of access (SELECT,
1988  INSERT, UPDATE, REFRENCES, ...)
1989  <LI><B>IS_GRANTABLE</B> String => "YES" if grantee is permitted
1990  to grant to others; "NO" if not; null if unknown
1991  </OL>
1992 
1993  @param catalog a catalog name; "" retrieves those without a
1994  catalog; null means drop catalog name from the selection criteria
1995  @param schemaPattern a schema name pattern; "" retrieves those
1996  without a schema
1997  @param tableNamePattern a table name pattern
1998  @return <code>ResultSet</code> - each row is a table privilege description
1999  @see #getSearchStringEscape
2000 }
2001 function TZInterbase6DatabaseMetadata.UncachedGetTablePrivileges(const Catalog: string;
2002  const SchemaPattern: string; const TableNamePattern: string): IZResultSet;
2003 var
2004  SQL: string;
2005  TableName, Privilege, Grantor: String;
2006  Grantee, Grantable: String;
2007  LTableNamePattern: String;
2008 begin
2009  Result:=inherited UncachedGetTablePrivileges(Catalog, SchemaPattern, TableNamePattern);
2010 
2011  LTableNamePattern := ConstructNameCondition(TableNamePattern, 'a.RDB$RELATION_NAME');
2012  if LTableNamePattern <> '' then
2013  LTableNamePattern := ' and ' + LTableNamePattern;
2014 
2015  SQL := 'SELECT a.RDB$USER, a.RDB$GRANTOR, a.RDB$PRIVILEGE,'
2016  + ' a.RDB$GRANT_OPTION, a.RDB$RELATION_NAME FROM RDB$USER_PRIVILEGES a,'
2017  + ' RDB$TYPES b WHERE a.RDB$OBJECT_TYPE = b.RDB$TYPE AND '
2018  + ' b.RDB$TYPE_NAME IN (''RELATION'', ''VIEW'', ''COMPUTED_FIELD'','
2019  + ' ''FIELD'' ) AND a.RDB$FIELD_NAME IS NULL '+ LTableNamePattern
2020  + ' ORDER BY a.RDB$RELATION_NAME, a.RDB$PRIVILEGE';
2021 
2022  with GetConnection.CreateStatement.ExecuteQuery(SQL) do
2023  begin
2024  while Next do
2025  begin
2026  TableName := GetString(5); //RDB$RELATION_NAME
2027  Privilege := GetPrivilege(GetString(3)); //RDB$PRIVILEGE
2028  Grantor := GetString(2); //RDB$GRANTOR
2029  Grantee := GetString(1); //RDB$USER
2030 
2031  if Grantor = Grantee then
2032  Grantable := 'YES'
2033  else
2034  Grantable := 'NO';
2035 
2036  Result.MoveToInsertRow;
2037  Result.UpdateNull(1);
2038  Result.UpdateNull(2);
2039  Result.UpdateString(3, TableName);
2040  Result.UpdateString(4, Grantor);
2041  Result.UpdateString(5, Grantee);
2042  Result.UpdateString(6, Privilege);
2043  Result.UpdateString(7, Grantable);
2044  Result.InsertRow;
2045  end;
2046  Close;
2047  end;
2048 end;
2049 
2050 {**
2051  Gets a description of a table's columns that are automatically
2052  updated when any value in a row is updated. They are
2053  unordered.
2054 
2055  <P>Each column description has the following columns:
2056  <OL>
2057  <LI><B>SCOPE</B> short => is not used
2058  <LI><B>COLUMN_NAME</B> String => column name
2059  <LI><B>DATA_TYPE</B> short => SQL data type from java.sql.Types
2060  <LI><B>TYPE_NAME</B> String => Data source dependent type name
2061  <LI><B>COLUMN_SIZE</B> int => precision
2062  <LI><B>BUFFER_LENGTH</B> int => length of column value in bytes
2063  <LI><B>DECIMAL_DIGITS</B> short => scale
2064  <LI><B>PSEUDO_COLUMN</B> short => is this a pseudo column
2065  like an Oracle ROWID
2066  <UL>
2067  <LI> versionColumnUnknown - may or may not be pseudo column
2068  <LI> versionColumnNotPseudo - is NOT a pseudo column
2069  <LI> versionColumnPseudo - is a pseudo column
2070  </UL>
2071  </OL>
2072 
2073  @param catalog a catalog name; "" retrieves those without a
2074  catalog; null means drop catalog name from the selection criteria
2075  @param schema a schema name; "" retrieves those without a schema
2076  @param table a table name
2077  @return <code>ResultSet</code> - each row is a column description
2078  @exception SQLException if a database access error occurs
2079 }
2080 function TZInterbase6DatabaseMetadata.UncachedGetVersionColumns(const Catalog: string;
2081  const Schema: string; const Table: string): IZResultSet;
2082 begin
2083  Result:=inherited UncachedGetVersionColumns(Catalog, Schema, Table);
2084 
2085  Result.MoveToInsertRow;
2086  Result.UpdateNull(1);
2087  Result.UpdateString(2, 'ctid');
2088  // Result.UpdateInt(3, GetSQLType('tid')); //FIX IT
2089  Result.UpdateString(4, 'tid');
2090  Result.UpdateNull(5);
2091  Result.UpdateNull(6);
2092  Result.UpdateNull(7);
2093  Result.UpdateInt(4, Ord(vcPseudo));
2094  Result.InsertRow;
2095 end;
2096 
2097 {**
2098  Gets a description of a table's primary key columns. They
2099  are ordered by COLUMN_NAME.
2100 
2101  <P>Each primary key column description has the following columns:
2102  <OL>
2103  <LI><B>TABLE_CAT</B> String => table catalog (may be null)
2104  <LI><B>TABLE_SCHEM</B> String => table schema (may be null)
2105  <LI><B>TABLE_NAME</B> String => table name
2106  <LI><B>COLUMN_NAME</B> String => column name
2107  <LI><B>KEY_SEQ</B> short => sequence number within primary key
2108  <LI><B>PK_NAME</B> String => primary key name (may be null)
2109  </OL>
2110 
2111  @param catalog a catalog name; "" retrieves those without a
2112  catalog; null means drop catalog name from the selection criteria
2113  @param schema a schema name; "" retrieves those
2114  without a schema
2115  @param table a table name
2116  @return <code>ResultSet</code> - each row is a primary key column description
2117  @exception SQLException if a database access error occurs
2118 }
2119 function TZInterbase6DatabaseMetadata.UncachedGetPrimaryKeys(const Catalog: string;
2120  const Schema: string; const Table: string): IZResultSet;
2121 var
2122  SQL: string;
2123  LTable: string;
2124 begin
2125  LTable := ConstructNameCondition(AddEscapeCharToWildcards(Table), 'a.RDB$RELATION_NAME');
2126  if LTable <> '' then
2127  LTable := ' AND ' + LTable;
2128 
2129  SQL := ' SELECT null as TABLE_CAT, null as TABLE_SCHEM,'
2130  + ' a.RDB$RELATION_NAME as TABLE_NAME, b.RDB$FIELD_NAME as COLUMN_NAME,'
2131  + ' b.RDB$FIELD_POSITION+1 as KEY_SEQ, a.RDB$INDEX_NAME as PK_NAME'
2132  + ' FROM RDB$RELATION_CONSTRAINTS a JOIN RDB$INDEX_SEGMENTS b ON'
2133  + ' (a.RDB$INDEX_NAME = b.RDB$INDEX_NAME)'
2134  + ' WHERE RDB$CONSTRAINT_TYPE = ''PRIMARY KEY''' + LTable
2135  + ' ORDER BY a.RDB$RELATION_NAME, b.RDB$FIELD_NAME';
2136 
2137  Result := CopyToVirtualResultSet(
2138  GetConnection.CreateStatement.ExecuteQuery(SQL),
2139  ConstructVirtualResultSet(PrimaryKeyColumnsDynArray));
2140 end;
2141 
2142 {**
2143  Gets a description of the primary key columns that are
2144  referenced by a table's foreign key columns (the primary keys
2145  imported by a table). They are ordered by PKTABLE_CAT,
2146  PKTABLE_SCHEM, PKTABLE_NAME, and KEY_SEQ.
2147 
2148  <P>Each primary key column description has the following columns:
2149  <OL>
2150  <LI><B>PKTABLE_CAT</B> String => primary key table catalog
2151  being imported (may be null)
2152  <LI><B>PKTABLE_SCHEM</B> String => primary key table schema
2153  being imported (may be null)
2154  <LI><B>PKTABLE_NAME</B> String => primary key table name
2155  being imported
2156  <LI><B>PKCOLUMN_NAME</B> String => primary key column name
2157  being imported
2158  <LI><B>FKTABLE_CAT</B> String => foreign key table catalog (may be null)
2159  <LI><B>FKTABLE_SCHEM</B> String => foreign key table schema (may be null)
2160  <LI><B>FKTABLE_NAME</B> String => foreign key table name
2161  <LI><B>FKCOLUMN_NAME</B> String => foreign key column name
2162  <LI><B>KEY_SEQ</B> short => sequence number within foreign key
2163  <LI><B>UPDATE_RULE</B> short => What happens to
2164  foreign key when primary is updated:
2165  <UL>
2166  <LI> importedNoAction - do not allow update of primary
2167  key if it has been imported
2168  <LI> importedKeyCascade - change imported key to agree
2169  with primary key update
2170  <LI> importedKeySetNull - change imported key to NULL if
2171  its primary key has been updated
2172  <LI> importedKeySetDefault - change imported key to default values
2173  if its primary key has been updated
2174  <LI> importedKeyRestrict - same as importedKeyNoAction
2175  (for ODBC 2.x compatibility)
2176  </UL>
2177  <LI><B>DELETE_RULE</B> short => What happens to
2178  the foreign key when primary is deleted.
2179  <UL>
2180  <LI> importedKeyNoAction - do not allow delete of primary
2181  key if it has been imported
2182  <LI> importedKeyCascade - delete rows that import a deleted key
2183  <LI> importedKeySetNull - change imported key to NULL if
2184  its primary key has been deleted
2185  <LI> importedKeyRestrict - same as importedKeyNoAction
2186  (for ODBC 2.x compatibility)
2187  <LI> importedKeySetDefault - change imported key to default if
2188  its primary key has been deleted
2189  </UL>
2190  <LI><B>FK_NAME</B> String => foreign key name (may be null)
2191  <LI><B>PK_NAME</B> String => primary key name (may be null)
2192  <LI><B>DEFERRABILITY</B> short => can the evaluation of foreign key
2193  constraints be deferred until commit
2194  <UL>
2195  <LI> importedKeyInitiallyDeferred - see SQL92 for definition
2196  <LI> importedKeyInitiallyImmediate - see SQL92 for definition
2197  <LI> importedKeyNotDeferrable - see SQL92 for definition
2198  </UL>
2199  </OL>
2200 
2201  @param catalog a catalog name; "" retrieves those without a
2202  catalog; null means drop catalog name from the selection criteria
2203  @param schema a schema name; "" retrieves those
2204  without a schema
2205  @param table a table name
2206  @return <code>ResultSet</code> - each row is a primary key column description
2207  @see #getExportedKeys
2208 }
2209 function TZInterbase6DatabaseMetadata.UncachedGetImportedKeys(const Catalog: string;
2210  const Schema: string; const Table: string): IZResultSet;
2211 var
2212  SQL: string;
2213  LTable: string;
2214 begin
2215  Result:=inherited UncachedGetImportedKeys(Catalog, Schema, Table);
2216 
2217  LTable := ConstructNameCondition(AddEscapeCharToWildcards(Table), 'RELC_FOR.RDB$RELATION_NAME'); // Modified by cipto 6/11/2007 4:53:02 PM
2218  if LTable <> '' then
2219  LTable := ' AND ' + LTable;
2220 
2221  SQL := 'SELECT RELC_PRIM.RDB$RELATION_NAME, ' // 1 prim.RDB$ key table name
2222  + ' IS_PRIM.RDB$FIELD_NAME, ' // 2 prim.RDB$ key column name
2223  + ' RELC_FOR.RDB$RELATION_NAME, ' // 3 foreign key table name
2224  + ' IS_FOR.RDB$FIELD_NAME, ' // 4 foreign key column name
2225  + ' IS_FOR.RDB$FIELD_POSITION, ' // 5 key sequence
2226  + ' REFC_PRIM.RDB$UPDATE_RULE, ' // 6
2227  + ' REFC_PRIM.RDB$DELETE_RULE, ' // 7
2228  + ' RELC_FOR.RDB$CONSTRAINT_NAME, ' // 8 foreign key constraint name
2229  + ' RELC_PRIM.RDB$CONSTRAINT_NAME ' // 9 primary key constraint name
2230  + ' FROM RDB$RELATION_CONSTRAINTS RELC_FOR, RDB$REF_CONSTRAINTS REFC_FOR, '
2231  + ' RDB$RELATION_CONSTRAINTS RELC_PRIM, RDB$REF_CONSTRAINTS REFC_PRIM, '
2232  + ' RDB$INDEX_SEGMENTS IS_PRIM, RDB$INDEX_SEGMENTS IS_FOR '
2233  + ' WHERE RELC_FOR.RDB$CONSTRAINT_TYPE = ''FOREIGN KEY'' ' + LTable
2234  + ' AND RELC_FOR.RDB$CONSTRAINT_NAME=REFC_FOR.RDB$CONSTRAINT_NAME'
2235  + ' and REFC_FOR.RDB$CONST_NAME_UQ = RELC_PRIM.RDB$CONSTRAINT_NAME and '
2236  + ' RELC_PRIM.RDB$CONSTRAINT_TYPE = ''PRIMARY KEY'' and ' // useful check, anyay
2237  + ' RELC_PRIM.RDB$INDEX_NAME = IS_PRIM.RDB$INDEX_NAME and '
2238  + ' IS_FOR.RDB$INDEX_NAME = RELC_FOR.RDB$INDEX_NAME and '
2239  + ' IS_PRIM.RDB$FIELD_POSITION = IS_FOR.RDB$FIELD_POSITION and '
2240  + ' REFC_PRIM.RDB$CONSTRAINT_NAME = RELC_FOR.RDB$CONSTRAINT_NAME '
2241  + ' ORDER BY RELC_PRIM.RDB$RELATION_NAME, IS_FOR.RDB$FIELD_POSITION ';
2242 
2243  with GetConnection.CreateStatement.ExecuteQuery(SQL) do
2244  begin
2245  while Next do
2246  begin
2247  Result.MoveToInsertRow;
2248  Result.UpdateNull(1); //PKTABLE_CAT
2249  Result.UpdateNull(2); //PKTABLE_SCHEM
2250  Result.UpdateString(3, GetString(1)); //PKTABLE_NAME
2251  Result.UpdateString(4, GetString(2)); //PKCOLUMN_NAME
2252  Result.UpdateNull(5); //FKTABLE_CAT
2253  Result.UpdateNull(6); //FKTABLE_SCHEM
2254  Result.UpdateString(7, GetString(3)); //FKTABLE_NAME
2255  Result.UpdateString(8, GetString(4)); //FKCOLUMN_NAME
2256  Result.UpdateInt(9, GetInt(5) + 1); //KEY_SEQ
2257 
2258  if GetString(6) = 'RESTRICT' then //UPDATE_RULE
2259  Result.UpdateInt(10, Ord(ikRestrict))
2260  else if GetString(6) = 'NO ACTION' then
2261  Result.UpdateInt(10, Ord(ikNoAction))
2262  else if GetString(6) = 'SET DEFAULT' then
2263  Result.UpdateInt(10, Ord(ikSetDefault))
2264  else if GetString(6) = 'CASCADE' then
2265  Result.UpdateInt(10, Ord(ikCascade))
2266  else if GetString(6) = 'SET NULL' then
2267  Result.UpdateInt(10, Ord(ikSetNull));
2268 
2269  if GetString(7) = 'RESTRICT' then //DELETE_RULE
2270  Result.UpdateInt(11, Ord(ikRestrict))
2271  else if GetString(7) = 'NO ACTION' then
2272  Result.UpdateInt(11, Ord(ikNoAction))
2273  else if GetString(7) = 'SET DEFAULT' then
2274  Result.UpdateInt(11, Ord(ikSetDefault))
2275  else if GetString(7) = 'CASCADE' then
2276  Result.UpdateInt(11, Ord(ikCascade))
2277  else if GetString(7) = 'SET NULL' then
2278  Result.UpdateInt(11, Ord(ikSetNull));
2279 
2280  Result.UpdateString(12, GetString(8)); //FK_NAME
2281  Result.UpdateString(13, GetString(9)); //PK_NAME
2282  Result.UpdateNull(14); //DEFERABILITY
2283  Result.InsertRow;
2284  end;
2285  Close;
2286  end;
2287 end;
2288 
2289 {**
2290  Gets a description of the foreign key columns that reference a
2291  table's primary key columns (the foreign keys exported by a
2292  table). They are ordered by FKTABLE_CAT, FKTABLE_SCHEM,
2293  FKTABLE_NAME, and KEY_SEQ.
2294 
2295  <P>Each foreign key column description has the following columns:
2296  <OL>
2297  <LI><B>PKTABLE_CAT</B> String => primary key table catalog (may be null)
2298  <LI><B>PKTABLE_SCHEM</B> String => primary key table schema (may be null)
2299  <LI><B>PKTABLE_NAME</B> String => primary key table name
2300  <LI><B>PKCOLUMN_NAME</B> String => primary key column name
2301  <LI><B>FKTABLE_CAT</B> String => foreign key table catalog (may be null)
2302  being exported (may be null)
2303  <LI><B>FKTABLE_SCHEM</B> String => foreign key table schema (may be null)
2304  being exported (may be null)
2305  <LI><B>FKTABLE_NAME</B> String => foreign key table name
2306  being exported
2307  <LI><B>FKCOLUMN_NAME</B> String => foreign key column name
2308  being exported
2309  <LI><B>KEY_SEQ</B> short => sequence number within foreign key
2310  <LI><B>UPDATE_RULE</B> short => What happens to
2311  foreign key when primary is updated:
2312  <UL>
2313  <LI> importedNoAction - do not allow update of primary
2314  key if it has been imported
2315  <LI> importedKeyCascade - change imported key to agree
2316  with primary key update
2317  <LI> importedKeySetNull - change imported key to NULL if
2318  its primary key has been updated
2319  <LI> importedKeySetDefault - change imported key to default values
2320  if its primary key has been updated
2321  <LI> importedKeyRestrict - same as importedKeyNoAction
2322  (for ODBC 2.x compatibility)
2323  </UL>
2324  <LI><B>DELETE_RULE</B> short => What happens to
2325  the foreign key when primary is deleted.
2326  <UL>
2327  <LI> importedKeyNoAction - do not allow delete of primary
2328  key if it has been imported
2329  <LI> importedKeyCascade - delete rows that import a deleted key
2330  <LI> importedKeySetNull - change imported key to NULL if
2331  its primary key has been deleted
2332  <LI> importedKeyRestrict - same as importedKeyNoAction
2333  (for ODBC 2.x compatibility)
2334  <LI> importedKeySetDefault - change imported key to default if
2335  its primary key has been deleted
2336  </UL>
2337  <LI><B>FK_NAME</B> String => foreign key name (may be null)
2338  <LI><B>PK_NAME</B> String => primary key name (may be null)
2339  <LI><B>DEFERRABILITY</B> short => can the evaluation of foreign key
2340  constraints be deferred until commit
2341  <UL>
2342  <LI> importedKeyInitiallyDeferred - see SQL92 for definition
2343  <LI> importedKeyInitiallyImmediate - see SQL92 for definition
2344  <LI> importedKeyNotDeferrable - see SQL92 for definition
2345  </UL>
2346  </OL>
2347 
2348  @param catalog a catalog name; "" retrieves those without a
2349  catalog; null means drop catalog name from the selection criteria
2350  @param schema a schema name; "" retrieves those
2351  without a schema
2352  @param table a table name
2353  @return <code>ResultSet</code> - each row is a foreign key column description
2354  @see #getImportedKeys
2355 }
2356 function TZInterbase6DatabaseMetadata.UncachedGetExportedKeys(const Catalog: string;
2357  const Schema: string; const Table: string): IZResultSet;
2358 var
2359  SQL: string;
2360  LTable: string;
2361 begin
2362  Result:=inherited UncachedGetExportedKeys(Catalog, Schema, Table);
2363 
2364  LTable := ConstructNameCondition(AddEscapeCharToWildcards(Table), 'RC_PRIM.RDB$RELATION_NAME'); // Modified by cipto 6/11/2007 4:54:02 PM
2365  if LTable <> '' then
2366  LTable := ' AND ' + LTable;
2367 
2368  SQL := ' SELECT RC_PRIM.RDB$RELATION_NAME, ' // prim.RDB$ key Table name
2369  + ' IS_PRIM.RDB$FIELD_NAME, ' // prim.RDB$ key column name
2370  + ' RC_FOR.RDB$RELATION_NAME, ' // foreign key Table name
2371  + ' IS_FOR.RDB$FIELD_NAME, ' // foreign key column name
2372  + ' IS_FOR.RDB$FIELD_POSITION, ' // key sequence
2373  + ' REFC_PRIM.RDB$UPDATE_RULE, ' // if update or delete rule is null, interpret as RESTRICT
2374  + ' REFC_PRIM.RDB$DELETE_RULE, '
2375  + ' RC_FOR.RDB$CONSTRAINT_NAME, ' // foreign key constraint name
2376  + ' RC_PRIM.RDB$CONSTRAINT_NAME ' // primary key constraint name
2377  + ' FROM RDB$RELATION_CONSTRAINTS RC_FOR, RDB$REF_CONSTRAINTS REFC_FOR, '
2378  + ' RDB$RELATION_CONSTRAINTS RC_PRIM, RDB$REF_CONSTRAINTS REFC_PRIM, '
2379  + ' RDB$INDEX_SEGMENTS IS_PRIM, RDB$INDEX_SEGMENTS IS_FOR '
2380  + ' WHERE RC_PRIM.RDB$CONSTRAINT_TYPE = ''PRIMARY KEY'' '+ LTable
2381  + ' and REFC_FOR.RDB$CONST_NAME_UQ = RC_PRIM.RDB$CONSTRAINT_NAME'
2382  + ' and RC_FOR.RDB$CONSTRAINT_NAME = REFC_FOR.RDB$CONSTRAINT_NAME and '
2383  + ' RC_FOR.RDB$CONSTRAINT_TYPE = ''FOREIGN KEY'' and '// useful check, anyay
2384  + ' RC_PRIM.RDB$INDEX_NAME = IS_PRIM.RDB$INDEX_NAME and '
2385  + ' IS_FOR.RDB$INDEX_NAME = RC_FOR.RDB$INDEX_NAME and '
2386  + ' IS_PRIM.RDB$FIELD_POSITION = IS_FOR.RDB$FIELD_POSITION and '
2387  + ' REFC_PRIM.RDB$CONSTRAINT_NAME = RC_FOR.RDB$CONSTRAINT_NAME '
2388  + ' ORDER BY RC_FOR.RDB$RELATION_NAME, IS_FOR.RDB$FIELD_POSITION ';
2389 
2390  with GetConnection.CreateStatement.ExecuteQuery(SQL) do
2391  begin
2392  while Next do
2393  begin
2394  Result.MoveToInsertRow;
2395  Result.UpdateNull(1); //PKTABLE_CAT
2396  Result.UpdateNull(2); //PKTABLE_SCHEM
2397  Result.UpdateString(3, GetString(1)); //PKTABLE_NAME
2398  Result.UpdateString(4, GetString(2)); //PKCOLUMN_NAME
2399  Result.UpdateNull(5); //FKTABLE_CAT
2400  Result.UpdateNull(6); //FKTABLE_SCHEM'
2401  Result.UpdateString(7, GetString(3)); //FKTABLE_NAME
2402  Result.UpdateString(8, GetString(4)); //FKCOLUMN_NAME
2403  Result.UpdateInt(9, GetInt(5) + 1); //KEY_SEQ
2404 
2405  if GetString(6) = 'RESTRICT' then //UPDATE_RULE
2406  Result.UpdateInt(10, Ord(ikRestrict))
2407  else if GetString(6) = 'NO ACTION' then
2408  Result.UpdateInt(10, Ord(ikNoAction))
2409  else if GetString(6) = 'SET DEFAULT' then
2410  Result.UpdateInt(10, Ord(ikSetDefault))
2411  else if GetString(6) = 'CASCADE' then
2412  Result.UpdateInt(10, Ord(ikCascade))
2413  else if GetString(6) = 'SET NULL' then
2414  Result.UpdateInt(10, Ord(ikSetNull));
2415 
2416  if GetString(7) = 'RESTRICT' then //DELETE_RULE
2417  Result.UpdateInt(11, Ord(ikRestrict))
2418  else if GetString(7) = 'NO ACTION' then
2419  Result.UpdateInt(11, Ord(ikNoAction))
2420  else if GetString(7) = 'SET DEFAULT' then
2421  Result.UpdateInt(11, Ord(ikSetDefault))
2422  else if GetString(7) = 'CASCADE' then
2423  Result.UpdateInt(11, Ord(ikCascade))
2424  else if GetString(7) = 'SET NULL' then
2425  Result.UpdateInt(11, Ord(ikSetNull));
2426 
2427  Result.UpdateString(12, GetString(8)); //FK_NAME
2428  Result.UpdateString(13, GetString(9)); //PK_NAME
2429  Result.UpdateNull(14); //DEFERABILITY
2430  Result.InsertRow;
2431  end;
2432  Close;
2433  end;
2434 end;
2435 
2436 {**
2437  EgonHugeist:
2438  Gets a description of the foreign key columns in the foreign key
2439  table that reference the primary key columns of the primary key
2440  table (describe how one table imports another's key.) This
2441  should normally return a single foreign key/primary key pair
2442  (most tables only import a foreign key from a table once.) They
2443  are ordered by FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, and
2444  KEY_SEQ.
2445 
2446  <P>Each foreign key column description has the following columns:
2447  <OL>
2448  <LI><B>PKTABLE_CAT</B> String => primary key table catalog (may be null)
2449  <LI><B>PKTABLE_SCHEM</B> String => primary key table schema (may be null)
2450  <LI><B>PKTABLE_NAME</B> String => primary key table name
2451  <LI><B>PKCOLUMN_NAME</B> String => primary key column name
2452  <LI><B>FKTABLE_CAT</B> String => foreign key table catalog (may be null)
2453  being exported (may be null)
2454  <LI><B>FKTABLE_SCHEM</B> String => foreign key table schema (may be null)
2455  being exported (may be null)
2456  <LI><B>FKTABLE_NAME</B> String => foreign key table name
2457  being exported
2458  <LI><B>FKCOLUMN_NAME</B> String => foreign key column name
2459  being exported
2460  <LI><B>KEY_SEQ</B> short => sequence number within foreign key
2461  <LI><B>UPDATE_RULE</B> short => What happens to
2462  foreign key when primary is updated:
2463  <UL>
2464  <LI> importedNoAction - do not allow update of primary
2465  key if it has been imported
2466  <LI> importedKeyCascade - change imported key to agree
2467  with primary key update
2468  <LI> importedKeySetNull - change imported key to NULL if
2469  its primary key has been updated
2470  <LI> importedKeySetDefault - change imported key to default values
2471  if its primary key has been updated
2472  <LI> importedKeyRestrict - same as importedKeyNoAction
2473  (for ODBC 2.x compatibility)
2474  </UL>
2475  <LI><B>DELETE_RULE</B> short => What happens to
2476  the foreign key when primary is deleted.
2477  <UL>
2478  <LI> importedKeyNoAction - do not allow delete of primary
2479  key if it has been imported
2480  <LI> importedKeyCascade - delete rows that import a deleted key
2481  <LI> importedKeySetNull - change imported key to NULL if
2482  its primary key has been deleted
2483  <LI> importedKeyRestrict - same as importedKeyNoAction
2484  (for ODBC 2.x compatibility)
2485  <LI> importedKeySetDefault - change imported key to default if
2486  its primary key has been deleted
2487  </UL>
2488  <LI><B>FK_NAME</B> String => foreign key name (may be null)
2489  <LI><B>PK_NAME</B> String => primary key name (may be null)
2490  <LI><B>DEFERRABILITY</B> short => can the evaluation of foreign key
2491  constraints be deferred until commit
2492  <UL>
2493  <LI> importedKeyInitiallyDeferred - see SQL92 for definition
2494  <LI> importedKeyInitiallyImmediate - see SQL92 for definition
2495  <LI> importedKeyNotDeferrable - see SQL92 for definition
2496  </UL>
2497  </OL>
2498 
2499  @param primaryCatalog a catalog name; "" retrieves those without a
2500  catalog; null means drop catalog name from the selection criteria
2501  @param primarySchema a schema name; "" retrieves those
2502  without a schema
2503  @param primaryTable the table name that exports the key
2504  @param foreignCatalog a catalog name; "" retrieves those without a
2505  catalog; null means drop catalog name from the selection criteria
2506  @param foreignSchema a schema name; "" retrieves those
2507  without a schema
2508  @param foreignTable the table name that imports the key
2509  @return <code>ResultSet</code> - each row is a foreign key column description
2510  @see #getImportedKeys
2511 }
2512 function TZInterbase6DatabaseMetadata.UncachedGetCrossReference(
2513  const PrimaryCatalog: string; const PrimarySchema: string;
2514  const PrimaryTable: string; const ForeignCatalog: string; const ForeignSchema: string;
2515  const ForeignTable: string): IZResultSet;
2516 var
2517  KeySeq: Integer;
2518  LCatalog, SQLString, LPTable, LFTable: String;
2519 
2520  function GetRuleType(const Rule: String): TZImportedKey;
2521  begin
2522  if Rule = 'RESTRICT' then
2523  Result := ikRestrict
2524  else if Rule = 'NO ACTION' then
2525  Result := ikNoAction
2526  else if Rule = 'CASCADE' then
2527  Result := ikCascade
2528  else if Rule = 'SET DEFAULT' then
2529  Result := ikSetDefault
2530  else if Rule = 'SET NULL' then
2531  Result := ikSetNull
2532  else
2533  Result := ikNotDeferrable; //impossible!
2534  end;
2535 begin
2536  if PrimaryCatalog = '' then
2537  LCatalog := GetConnection.GetCatalog
2538  else
2539  LCatalog := PrimaryCatalog;
2540 
2541  LPTable := ConstructNameCondition(AddEscapeCharToWildcards(PrimaryTable), 'i2.RDB$RELATION_NAME');
2542  LFTable := ConstructNameCondition(AddEscapeCharToWildcards(ForeignTable), 'rc.RDB$RELATION_NAME');
2543  if LPTable <> '' then
2544  LPTable := ' AND ' + LPTable;
2545  if LFTable <> '' then
2546  LFTable := ' AND ' + LFTable;
2547 
2548  Result:=inherited UncachedGetCrossReference(PrimaryCatalog, PrimarySchema, PrimaryTable,
2549  ForeignCatalog, ForeignSchema, ForeignTable);
2550 
2551  SQLString :=
2552  'SELECT '+
2553  'i2.RDB$RELATION_NAME AS PKTABLE_NAME, '+
2554  's2.RDB$FIELD_NAME AS PKCOLUMN_NAME, '+
2555  'rc.RDB$RELATION_NAME as FKTABLE_NAME, '+
2556  's.RDB$FIELD_NAME AS FKCOLUMN_NAME, '+
2557  'refc.RDB$UPDATE_RULE AS UPDATE_RULE, '+
2558  'refc.RDB$DELETE_RULE AS DELETE_RULE, '+
2559  'i.RDB$INDEX_NAME AS FK_NAME, '+
2560  's2.RDB$INDEX_NAME as PK_NAME, '+
2561  'rc.RDB$DEFERRABLE AS DEFERRABILITY '+
2562  'FROM RDB$INDEX_SEGMENTS s '+
2563  'LEFT JOIN RDB$INDICES i ON i.RDB$INDEX_NAME = s.RDB$INDEX_NAME '+
2564  'LEFT JOIN RDB$RELATION_CONSTRAINTS rc ON rc.RDB$INDEX_NAME = s.RDB$INDEX_NAME '+
2565  'LEFT JOIN RDB$REF_CONSTRAINTS refc ON rc.RDB$CONSTRAINT_NAME = refc.RDB$CONSTRAINT_NAME '+
2566  'LEFT JOIN RDB$RELATION_CONSTRAINTS rc2 ON rc2.RDB$CONSTRAINT_NAME = refc.RDB$CONST_NAME_UQ '+
2567  'LEFT JOIN RDB$INDICES i2 ON i2.RDB$INDEX_NAME = rc2.RDB$INDEX_NAME '+
2568  'LEFT JOIN RDB$INDEX_SEGMENTS s2 ON i2.RDB$INDEX_NAME = s2.RDB$INDEX_NAME '+
2569  'WHERE rc.RDB$CONSTRAINT_TYPE = ''FOREIGN KEY'' '+
2570  'AND rc.RDB$CONSTRAINT_TYPE IS NOT NULL '+LPTable+LFTable;
2571 
2572  KeySeq := 0;
2573  with GetConnection.CreateStatement.ExecuteQuery(SQLString) do
2574  begin
2575  while Next do
2576  begin
2577  Inc(KeySeq);
2578  Result.MoveToInsertRow;
2579  Result.UpdateString(1, LCatalog); //PKTABLE_CAT
2580  Result.UpdateNull(2); //PKTABLE_SCHEM
2581  Result.UpdateString(3, GetString(1)); //PKTABLE_NAME
2582  Result.UpdateString(4, GetString(2)); //PKCOLUMN_NAME
2583  Result.UpdateString(5, LCatalog); //PKTABLE_CAT
2584  Result.UpdateNull(6); //FKTABLE_SCHEM
2585  Result.UpdateString(7, GetString(3)); //FKTABLE_NAME
2586  Result.UpdateString(8, GetString(4)); //FKCOLUMN_NAME
2587  Result.UpdateShort(9, KeySeq); //KEY_SEQ
2588  Result.UpdateShort(10, Ord(GetRuleType(GetString(5)))); //UPDATE_RULE
2589  Result.UpdateShort(11, Ord(GetRuleType(GetString(6)))); //DELETE_RULE
2590  Result.UpdateString(12, GetString(7)); //FK_NAME
2591  Result.UpdateString(13, GetString(8)); //PK_NAME
2592  if GetString(9) = 'NO' then
2593  Result.UpdateShort(14, Ord(ikNotDeferrable)) //DEFERRABILITY
2594  else
2595  Result.UpdateShort(14, Ord(ikInitiallyDeferred)); //DEFERRABILITY
2596  Result.InsertRow;
2597  end;
2598  Close;
2599  end;
2600 end;
2601 
2602 {**
2603  Gets a description of all the standard SQL types supported by
2604  this database. They are ordered by DATA_TYPE and then by how
2605  closely the data type maps to the corresponding JDBC SQL type.
2606 
2607  <P>Each type description has the following columns:
2608  <OL>
2609  <LI><B>TYPE_NAME</B> String => Type name
2610  <LI><B>DATA_TYPE</B> short => SQL data type from java.sql.Types
2611  <LI><B>PRECISION</B> int => maximum precision
2612  <LI><B>LITERAL_PREFIX</B> String => prefix used to quote a literal
2613  (may be null)
2614  <LI><B>LITERAL_SUFFIX</B> String => suffix used to quote a literal
2615  (may be null)
2616  <LI><B>CREATE_PARAMS</B> String => parameters used in creating
2617  the type (may be null)
2618  <LI><B>NULLABLE</B> short => can you use NULL for this type?
2619  <UL>
2620  <LI> typeNoNulls - does not allow NULL values
2621  <LI> typeNullable - allows NULL values
2622  <LI> typeNullableUnknown - nullability unknown
2623  </UL>
2624  <LI><B>CASE_SENSITIVE</B> boolean=> is it case sensitive?
2625  <LI><B>SEARCHABLE</B> short => can you use "WHERE" based on this type:
2626  <UL>
2627  <LI> typePredNone - No support
2628  <LI> typePredChar - Only supported with WHERE .. LIKE
2629  <LI> typePredBasic - Supported except for WHERE .. LIKE
2630  <LI> typeSearchable - Supported for all WHERE ..
2631  </UL>
2632  <LI><B>UNSIGNED_ATTRIBUTE</B> boolean => is it unsigned?
2633  <LI><B>FIXED_PREC_SCALE</B> boolean => can it be a money value?
2634  <LI><B>AUTO_INCREMENT</B> boolean => can it be used for an
2635  auto-increment value?
2636  <LI><B>LOCAL_TYPE_NAME</B> String => localized version of type name
2637  (may be null)
2638  <LI><B>MINIMUM_SCALE</B> short => minimum scale supported
2639  <LI><B>MAXIMUM_SCALE</B> short => maximum scale supported
2640  <LI><B>SQL_DATA_TYPE</B> int => unused
2641  <LI><B>SQL_DATETIME_SUB</B> int => unused
2642  <LI><B>NUM_PREC_RADIX</B> int => usually 2 or 10
2643  </OL>
2644 
2645  @return <code>ResultSet</code> - each row is an SQL type description
2646 }
2647 function TZInterbase6DatabaseMetadata.UncachedGetTypeInfo: IZResultSet;
2648 var
2649  SQL: string;
2650 begin
2651  Result:=inherited UncachedGetTypeInfo;
2652 
2653  SQL := ' SELECT RDB$TYPE, RDB$TYPE_NAME FROM RDB$TYPES ' +
2654  ' WHERE RDB$FIELD_NAME = ''RDB$FIELD_TYPE'' ';
2655  with GetConnection.CreateStatement.ExecuteQuery(SQL) do
2656  begin
2657  while Next do
2658  begin
2659  Result.MoveToInsertRow;
2660  Result.UpdateString(1, GetString(2));
2661  Result.UpdateInt(2, Ord(ConvertInterbase6ToSqlType(GetInt(1), 0,
2662  ConSettings.CPType)));
2663  Result.UpdateInt(3, 9);
2664  Result.UpdateInt(7, Ord(ntNoNulls));
2665  Result.UpdateBoolean(8, false);
2666  Result.UpdateBoolean(9, false);
2667  Result.UpdateBoolean(11, false);
2668  Result.UpdateBoolean(12, false);
2669  Result.UpdateInt(18, 10);
2670  Result.InsertRow;
2671  end;
2672  Close;
2673  end;
2674 end;
2675 
2676 {**
2677  Gets a description of a table's indices and statistics. They are
2678  ordered by NON_UNIQUE, TYPE, INDEX_NAME, and ORDINAL_POSITION.
2679 
2680  <P>Each index column description has the following columns:
2681  <OL>
2682  <LI><B>TABLE_CAT</B> String => table catalog (may be null)
2683  <LI><B>TABLE_SCHEM</B> String => table schema (may be null)
2684  <LI><B>TABLE_NAME</B> String => table name
2685  <LI><B>NON_UNIQUE</B> boolean => Can index values be non-unique?
2686  false when TYPE is tableIndexStatistic
2687  <LI><B>INDEX_QUALIFIER</B> String => index catalog (may be null);
2688  null when TYPE is tableIndexStatistic
2689  <LI><B>INDEX_NAME</B> String => index name; null when TYPE is
2690  tableIndexStatistic
2691  <LI><B>TYPE</B> short => index type:
2692  <UL>
2693  <LI> tableIndexStatistic - this identifies table statistics that are
2694  returned in conjuction with a table's index descriptions
2695  <LI> tableIndexClustered - this is a clustered index
2696  <LI> tableIndexHashed - this is a hashed index
2697  <LI> tableIndexOther - this is some other style of index
2698  </UL>
2699  <LI><B>ORDINAL_POSITION</B> short => column sequence number
2700  within index; zero when TYPE is tableIndexStatistic
2701  <LI><B>COLUMN_NAME</B> String => column name; null when TYPE is
2702  tableIndexStatistic
2703  <LI><B>ASC_OR_DESC</B> String => column sort sequence, "A" => ascending,
2704  "D" => descending, may be null if sort sequence is not supported;
2705  null when TYPE is tableIndexStatistic
2706  <LI><B>CARDINALITY</B> int => When TYPE is tableIndexStatistic, then
2707  this is the number of rows in the table; otherwise, it is the
2708  number of unique values in the index.
2709  <LI><B>PAGES</B> int => When TYPE is tableIndexStatisic then
2710  this is the number of pages used for the table, otherwise it
2711  is the number of pages used for the current index.
2712  <LI><B>FILTER_CONDITION</B> String => Filter condition, if any.
2713  (may be null)
2714  </OL>
2715 
2716  @param catalog a catalog name; "" retrieves those without a
2717  catalog; null means drop catalog name from the selection criteria
2718  @param schema a schema name; "" retrieves those without a schema
2719  @param table a table name
2720  @param unique when true, return only indices for unique values;
2721  when false, return indices regardless of whether unique or not
2722  @param approximate when true, result is allowed to reflect approximate
2723  or out of data values; when false, results are requested to be
2724  accurate
2725  @return <code>ResultSet</code> - each row is an index column description
2726 }
2727 function TZInterbase6DatabaseMetadata.UncachedGetIndexInfo(const Catalog: string;
2728  const Schema: string; const Table: string; Unique: Boolean;
2729  Approximate: Boolean): IZResultSet;
2730 var
2731  SQL : string;
2732  LTable: String;
2733 begin
2734  LTable := ConstructNameCondition(Table, 'I.RDB$RELATION_NAME');
2735  if LTable <> '' then
2736  LTable := ' AND ' + LTable;
2737 
2738  Result:=inherited UncachedGetIndexInfo(Catalog, Schema, Table, Unique, Approximate);
2739 
2740  SQL := ' SELECT I.RDB$RELATION_NAME, I.RDB$UNIQUE_FLAG, I.RDB$INDEX_NAME,'
2741  + ' ISGMT.RDB$FIELD_POSITION, ISGMT.RDB$FIELD_NAME, I.RDB$INDEX_TYPE,'
2742  + ' I.RDB$SEGMENT_COUNT, COUNT (DISTINCT P.RDB$PAGE_NUMBER) '
2743  + ' FROM RDB$INDICES I JOIN RDB$INDEX_SEGMENTS ISGMT ON'
2744  + ' I.RDB$INDEX_NAME = ISGMT.RDB$INDEX_NAME JOIN RDB$RELATIONS R ON'
2745  + ' (R.RDB$RELATION_NAME = I.RDB$RELATION_NAME) JOIN RDB$PAGES P ON'
2746  + ' (P.RDB$RELATION_ID = R.RDB$RELATION_ID AND P.RDB$PAGE_TYPE = 7'
2747  + ' OR P.RDB$PAGE_TYPE = 6) WHERE ';
2748  if Unique then
2749  SQL := SQL + ' I.RDB$UNIQUE_FLAG = 1 AND ';
2750 
2751  SQL := SQL + 'I.RDB$RELATION_NAME != '''' ' + LTable
2752  + ' GROUP BY '
2753  + ' I.RDB$INDEX_NAME, I.RDB$RELATION_NAME, I.RDB$UNIQUE_FLAG, '
2754  + ' ISGMT.RDB$FIELD_POSITION, ISGMT.RDB$FIELD_NAME, I.RDB$INDEX_TYPE, '
2755  + ' I.RDB$SEGMENT_COUNT ORDER BY 1,2,3,4';
2756 
2757 
2758  with GetConnection.CreateStatement.ExecuteQuery(SQL) do
2759  begin
2760  while Next do
2761  begin
2762  Result.MoveToInsertRow;
2763  Result.UpdateNull(1); //TABLE_CAT
2764  Result.UpdateNull(2); //TABLE_SCHEM
2765  Result.UpdateString(3, GetString(1)); //TABLE_NAME, RDB$RELATION_NAME
2766  Result.UpdateBoolean(4, not GetBoolean(2)); //NON_UNIQUE, RDB$UNIQUE_FLAG
2767  Result.UpdateNull(5); //INDEX_QUALIFIER
2768  Result.UpdateString(6, GetString(3)); //INDEX_NAME, RDB$INDEX_NAME
2769  Result.UpdateInt(7, Ord(ntNoNulls)); //TYPE
2770  Result.UpdateInt(8, GetInt(4) + 1); //ORDINAL_POSITION, RDB$FIELD_POSITION
2771  Result.UpdateString(9, GetString(5)); //COLUMN_NAME, RDB$FIELD_NAME
2772  Result.UpdateNull(10); //ASC_OR_DESC
2773  Result.UpdateNull(11); //CARDINALITY
2774  Result.UpdateInt(12, GetInt(7)); //PAGES, RDB$SEGMENT_COUNT
2775  Result.UpdateNull(13); //FILTER_CONDITION
2776  Result.InsertRow;
2777  end;
2778  Close;
2779  end;
2780 end;
2781 
2782 function TZInterbase6DatabaseMetadata.UncachedGetSequences(const Catalog, SchemaPattern,
2783  SequenceNamePattern: string): IZResultSet;
2784 var
2785  SQL: string;
2786  LSequenceNamePattern: string;
2787 begin
2788  Result:=inherited UncachedGetSequences(Catalog, SchemaPattern, SequenceNamePattern);
2789 
2790  LSequenceNamePattern := ConstructNameCondition(SequenceNamePattern,
2791  'RDB$GENERATOR_NAME');
2792  if LSequenceNamePattern <> '' then
2793  LSequenceNamePattern := ' and '+LSequenceNamePattern;
2794 
2795  SQL := ' SELECT RDB$GENERATOR_NAME FROM RDB$GENERATORS ' +
2796  'WHERE (RDB$SYSTEM_FLAG IS NULL OR RDB$SYSTEM_FLAG = 0)'+ LSequenceNamePattern;
2797 
2798  with GetConnection.CreateStatement.ExecuteQuery(SQL) do
2799  begin
2800  while Next do
2801  begin
2802  Result.MoveToInsertRow;
2803  Result.UpdateNull(1);
2804  Result.UpdateNull(2);
2805  Result.UpdateString(3, GetString(1)); //RDB$GENERATOR_NAME
2806  Result.InsertRow;
2807  end;
2808  Close;
2809  end;
2810 end;
2811 
2812 {**
2813  Gets a privilege name.
2814  @param Interbase privilege name
2815  @returns a JDBC privilege name.
2816 }
2817 function TZInterbase6DatabaseMetadata.GetPrivilege(Privilege: string): string;
2818 begin
2819  if Privilege = 'S' then
2820  Result := 'SELECT'
2821  else if Privilege = 'I' then
2822  Result := 'INSERT'
2823  else if Privilege = 'U' then
2824  Result := 'UPDATE'
2825  else if Privilege = 'D' then
2826  Result := 'DELETE'
2827  else if Privilege = 'R' then
2828  Result := 'REFERENCE'
2829  else
2830  Result := '';
2831 end;
2832 
2833 {**
2834  Gets the used Collation and CharacterSet of spezified Object.
2835 
2836  @param catalog a catalog name; "" retrieves those without a
2837  catalog; null means drop catalog name from the selection criteria
2838  @param schema a schema name; "" and Catolog "" retrieves nothing
2839  @param table a table name; "" retrieves the Schema Colloation and CharacterSet
2840  @param ColumnNamePattern ColumnPattern;"" retrieves the
2841  Table(if @param TablePattern is set) or
2842  Schema(if @param TablePattern is NULL)
2843  Colloation and CharacterSet
2844  @return <code>ResultSet</code> - each row is a Collation, CharacterSet, ID,
2845  and ByteLength per Char of speziefied Object
2846 }
2847 function TZInterbase6DatabaseMetadata.UncachedGetCollationAndCharSet(const Catalog, SchemaPattern,
2848  TableNamePattern, ColumnNamePattern: string): IZResultSet; //EgonHugeist
2849 var
2850  SQL, LCatalog: string;
2851  ColumnNameCondition, TableNameCondition: string;
2852 begin
2853  if Catalog = '' then
2854  begin
2855  if SchemaPattern <> '' then
2856  LCatalog := SchemaPattern
2857  else
2858  LCatalog := FDatabase;
2859  end
2860  else
2861  LCatalog := Catalog;
2862  TableNameCondition := ConstructNameCondition(TableNamePattern,'R.RDB$RELATION_NAME');
2863  ColumnNameCondition := ConstructNameCondition(ColumnNamePattern,'R.RDB$FIELD_NAME');
2864  If TableNameCondition <> '' then
2865  TableNameCondition := ' and ' + TableNameCondition;
2866  If ColumnNameCondition <> '' then
2867  ColumnNameCondition := ' and ' + ColumnNameCondition;
2868 
2869  Result:=inherited UncachedGetCollationAndCharSet(Catalog, SchemaPattern, TableNamePattern, ColumnNamePattern);
2870 
2871  if LCatalog <> '' then
2872  begin
2873  if TableNamePattern <> '' then
2874  begin
2875  if ColumnNamePattern <> '' then
2876  begin
2877  SQL := 'SELECT C.RDB$CHARACTER_SET_NAME, C.RDB$DEFAULT_COLLATE_NAME, '+
2878  'C.RDB$CHARACTER_SET_ID, C.RDB$BYTES_PER_CHARACTER '+
2879  'FROM RDB$RELATION_FIELDS R '+
2880  'right join RDB$FIELDS F on R.RDB$FIELD_SOURCE = F.RDB$FIELD_NAME '+
2881  'left join RDB$CHARACTER_SETS C on C.RDB$CHARACTER_SET_ID = F.RDB$CHARACTER_SET_ID '+
2882  'left join RDB$TYPES T on F.RDB$FIELD_TYPE = T.RDB$TYPE'+
2883  'where T.RDB$FIELD_NAME=''RDB$FIELD_TYPE'' '+
2884  ColumnNameCondition+TableNameCondition+
2885  'order by R.RDB$FIELD_POSITION;';
2886  with GetConnection.CreateStatement.ExecuteQuery(SQL) do
2887  begin
2888  if Next then
2889  begin
2890  if not ( GetString(FindColumn('RDB$CHARACTER_SET_NAME')) = 'NONE' ) then
2891  begin
2892  Result.MoveToInsertRow;
2893  Result.UpdateString(1, LCatalog); //COLLATION_CATALOG
2894  Result.UpdateString(2, LCatalog); //COLLATION_SCHEMA
2895  Result.UpdateString(3, TableNamePattern); //COLLATION_TABLE
2896  Result.UpdateString(4, ColumnNamePattern);//COLLATION_COLUMN
2897  Result.UpdateString(5, GetString(FindColumn('RDB$DEFAULT_COLLATE_NAME'))); //COLLATION_NAME
2898  Result.UpdateString(6, GetString(FindColumn('RDB$CHARACTER_SET_NAME'))); //CHARACTER_SET_NAME
2899  Result.UpdateShort(7, GetShort(FindColumn('RDB$CHARACTER_SET_ID'))); //CHARACTER_SET_ID
2900  Result.UpdateShort(8, GetShort(FindColumn('RDB$BYTES_PER_CHARACTER'))); //CHARACTER_SET_SIZE
2901  Result.InsertRow;
2902  Close;
2903  Exit;
2904  end;
2905  end;
2906  Close;
2907  end;
2908  end;
2909  end;
2910  end;
2911  {Brings Defaults for Table or Database up}
2912  SQL := 'SELECT D.RDB$CHARACTER_SET_NAME, CS.RDB$DEFAULT_COLLATE_NAME, '+
2913  'CS.RDB$CHARACTER_SET_ID, CS.RDB$BYTES_PER_CHARACTER '+
2914  'FROM RDB$DATABASE D '+
2915  'LEFT JOIN RDB$CHARACTER_SETS CS on '+
2916  'D.RDB$CHARACTER_SET_NAME = CS.RDB$CHARACTER_SET_NAME; ';
2917  with GetConnection.CreateStatement.ExecuteQuery(SQL) do
2918  begin
2919  if Next then
2920  begin
2921  Result.MoveToInsertRow;
2922  Result.UpdateString(1, LCatalog); //COLLATION_CATALOG
2923  Result.UpdateString(2, LCatalog); //COLLATION_SCHEMA
2924  Result.UpdateString(3, TableNamePattern); //COLLATION_TABLE
2925  Result.UpdateNull(4);//COLLATION_COLUMN
2926  Result.UpdateString(5, GetString(FindColumn('RDB$DEFAULT_COLLATE_NAME'))); //COLLATION_NAME
2927  Result.UpdateString(6, GetString(FindColumn('RDB$CHARACTER_SET_NAME'))); //CHARACTER_SET_NAME
2928  Result.UpdateShort(7, GetShort(FindColumn('RDB$CHARACTER_SET_ID'))); //CHARACTER_SET_ID
2929  Result.UpdateShort(8, GetShort(FindColumn('RDB$BYTES_PER_CHARACTER'))); //CHARACTER_SET_SIZE
2930  Result.InsertRow;
2931  end;
2932  Close;
2933  end;
2934 end;
2935 
2936 {**
2937  Gets the supported CharacterSets:
2938  @return <code>ResultSet</code> - each row is a CharacterSetName and it's ID
2939 }
2940 function TZInterbase6DatabaseMetadata.UncachedGetCharacterSets: IZResultSet; //EgonHugeist
2941 begin
2942  Result:=inherited UncachedGetCharacterSets;
2943 
2944  with GetConnection.CreateStatement.ExecuteQuery(
2945  'SELECT RDB$CHARACTER_SET_NAME, RDB$CHARACTER_SET_ID '+
2946  'FROM RDB$CHARACTER_SETS') do
2947  begin
2948  while Next do
2949  begin
2950  Result.MoveToInsertRow;
2951  Result.UpdateString(1, GetString(FindColumn('RDB$CHARACTER_SET_NAME'))); //CHARACTER_SET_NAME
2952  Result.UpdateString(2, GetString(FindColumn('RDB$CHARACTER_SET_ID'))); //CHARACTER_SET_ID
2953  Result.InsertRow;
2954  end;
2955  Close;
2956  end;
2957 end;
2958 
2959 end.