zeoslib  UNKNOWN
 All Files
ZDbcAdoMetadata.pas
Go to the documentation of this file.
1 {*********************************************************}
2 { }
3 { Zeos Database Objects }
4 { Ado metadata information }
5 { }
6 { Originally written by Janos Fegyverneki }
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 ZDbcAdoMetadata;
53 
54 interface
55 
56 {$I ZDbc.inc}
57 
58 uses
59  Types, Classes, SysUtils, ZSysUtils, ZClasses, ZDbcIntfs, ZDbcMetadata,
60  ZDbcResultSet, ZDbcCachedResultSet, ZDbcResultsetMetadata, ZURL,
61  ZCompatibility, ZGenericSqlAnalyser, ZPlainAdo, ZDbcConnection;
62 
63 type
64  // technobot 2008-06-27 - methods moved as is from TZAdoDatabaseMetadata:
65  {** Implements Ado Database Information. }
66  TZAdoDatabaseInfo = class(TZAbstractDatabaseInfo)
67  public
68  constructor Create(const Metadata: TZAbstractDatabaseMetadata);
69 
70  // database/driver/server info:
71  function GetDatabaseProductName: string; override;
72  function GetDatabaseProductVersion: string; override;
73  function GetDriverName: string; override;
74 // function GetDriverVersion: string; override; -> Same as parent
75  function GetDriverMajorVersion: Integer; override;
76  function GetDriverMinorVersion: Integer; override;
77 // function GetServerVersion: string; -> Not implemented
78 
79  // capabilities (what it can/cannot do):
80 // function AllProceduresAreCallable: Boolean; override; -> Not implemented
81 // function AllTablesAreSelectable: Boolean; override; -> Not implemented
82  function SupportsMixedCaseIdentifiers: Boolean; override;
83  function SupportsMixedCaseQuotedIdentifiers: Boolean; override;
84 // function SupportsAlterTableWithAddColumn: Boolean; override; -> Not implemented
85 // function SupportsAlterTableWithDropColumn: Boolean; override; -> Not implemented
86 // function SupportsColumnAliasing: Boolean; override; -> Not implemented
87 // function SupportsConvert: Boolean; override; -> Not implemented
88 // function SupportsConvertForTypes(FromType: TZSQLType; ToType: TZSQLType):
89 // Boolean; override; -> Not implemented
90 // function SupportsTableCorrelationNames: Boolean; override; -> Not implemented
91 // function SupportsDifferentTableCorrelationNames: Boolean; override; -> Not implemented
92  function SupportsExpressionsInOrderBy: Boolean; override;
93  function SupportsOrderByUnrelated: Boolean; override;
94  function SupportsGroupBy: Boolean; override;
95  function SupportsGroupByUnrelated: Boolean; override;
96  function SupportsGroupByBeyondSelect: Boolean; override;
97 // function SupportsLikeEscapeClause: Boolean; override; -> Not implemented
98 // function SupportsMultipleResultSets: Boolean; override; -> Not implemented
99 // function SupportsMultipleTransactions: Boolean; override; -> Not implemented
100 // function SupportsNonNullableColumns: Boolean; override; -> Not implemented
101 // function SupportsMinimumSQLGrammar: Boolean; override; -> Not implemented
102 // function SupportsCoreSQLGrammar: Boolean; override; -> Not implemented
103 // function SupportsExtendedSQLGrammar: Boolean; override; -> Not implemented
104 // function SupportsANSI92EntryLevelSQL: Boolean; override; -> Not implemented
105 // function SupportsANSI92IntermediateSQL: Boolean; override; -> Not implemented
106 // function SupportsANSI92FullSQL: Boolean; override; -> Not implemented
107  function SupportsIntegrityEnhancementFacility: Boolean; override;
108 // function SupportsOuterJoins: Boolean; override; -> Not implemented
109 // function SupportsFullOuterJoins: Boolean; override; -> Not implemented
110 // function SupportsLimitedOuterJoins: Boolean; override; -> Not implemented
111  function SupportsSchemasInDataManipulation: Boolean; override;
112  function SupportsSchemasInProcedureCalls: Boolean; override;
113  function SupportsSchemasInTableDefinitions: Boolean; override;
114  function SupportsSchemasInIndexDefinitions: Boolean; override;
115  function SupportsSchemasInPrivilegeDefinitions: Boolean; override;
116  function SupportsCatalogsInDataManipulation: Boolean; override;
117  function SupportsCatalogsInProcedureCalls: Boolean; override;
118  function SupportsCatalogsInTableDefinitions: Boolean; override;
119  function SupportsCatalogsInIndexDefinitions: Boolean; override;
120  function SupportsCatalogsInPrivilegeDefinitions: Boolean; override;
121  function SupportsOverloadPrefixInStoredProcedureName: Boolean; override;
122  function SupportsPositionedDelete: Boolean; override;
123  function SupportsPositionedUpdate: Boolean; override;
124  function SupportsSelectForUpdate: Boolean; override;
125  function SupportsStoredProcedures: Boolean; override;
126  function SupportsSubqueriesInComparisons: Boolean; override;
127  function SupportsSubqueriesInExists: Boolean; override;
128  function SupportsSubqueriesInIns: Boolean; override;
129  function SupportsSubqueriesInQuantifieds: Boolean; override;
130  function SupportsCorrelatedSubqueries: Boolean; override;
131  function SupportsUnion: Boolean; override;
132  function SupportsUnionAll: Boolean; override;
133  function SupportsOpenCursorsAcrossCommit: Boolean; override;
134  function SupportsOpenCursorsAcrossRollback: Boolean; override;
135  function SupportsOpenStatementsAcrossCommit: Boolean; override;
136  function SupportsOpenStatementsAcrossRollback: Boolean; override;
137  function SupportsTransactions: Boolean; override;
138  function SupportsTransactionIsolationLevel(Level: TZTransactIsolationLevel):
139  Boolean; override;
140  function SupportsDataDefinitionAndDataManipulationTransactions: Boolean; override;
141  function SupportsDataManipulationTransactionsOnly: Boolean; override;
142  function SupportsResultSetType(_Type: TZResultSetType): Boolean; override;
143  function SupportsResultSetConcurrency(_Type: TZResultSetType;
144  Concurrency: TZResultSetConcurrency): Boolean; override;
145 // function SupportsBatchUpdates: Boolean; override; -> Not implemented
146  function SupportsNonEscapedSearchStrings: Boolean; override;
147  function SupportsUpdateAutoIncrementFields: Boolean; override;
148 
149  // maxima:
150  function GetMaxBinaryLiteralLength: Integer; override;
151  function GetMaxCharLiteralLength: Integer; override;
152  function GetMaxColumnNameLength: Integer; override;
153  function GetMaxColumnsInGroupBy: Integer; override;
154  function GetMaxColumnsInIndex: Integer; override;
155  function GetMaxColumnsInOrderBy: Integer; override;
156  function GetMaxColumnsInSelect: Integer; override;
157  function GetMaxColumnsInTable: Integer; override;
158  function GetMaxConnections: Integer; override;
159  function GetMaxCursorNameLength: Integer; override;
160  function GetMaxIndexLength: Integer; override;
161  function GetMaxSchemaNameLength: Integer; override;
162  function GetMaxProcedureNameLength: Integer; override;
163  function GetMaxCatalogNameLength: Integer; override;
164  function GetMaxRowSize: Integer; override;
165  function GetMaxStatementLength: Integer; override;
166  function GetMaxStatements: Integer; override;
167  function GetMaxTableNameLength: Integer; override;
168  function GetMaxTablesInSelect: Integer; override;
169  function GetMaxUserNameLength: Integer; override;
170 
171  // policies (how are various data and operations handled):
172 // function IsReadOnly: Boolean; override; -> Not implemented
173 // function IsCatalogAtStart: Boolean; override; -> Not implemented
174  function DoesMaxRowSizeIncludeBlobs: Boolean; override;
175 // function NullsAreSortedHigh: Boolean; override; -> Not implemented
176 // function NullsAreSortedLow: Boolean; override; -> Not implemented
177 // function NullsAreSortedAtStart: Boolean; override; -> Not implemented
178 // function NullsAreSortedAtEnd: Boolean; override; -> Not implemented
179 // function NullPlusNonNullIsNull: Boolean; override; -> Not implemented
180 // function UsesLocalFiles: Boolean; override; -> Not implemented
181  function UsesLocalFilePerTable: Boolean; override;
182  function StoresUpperCaseIdentifiers: Boolean; override;
183  function StoresLowerCaseIdentifiers: Boolean; override;
184  function StoresMixedCaseIdentifiers: Boolean; override;
185  function StoresUpperCaseQuotedIdentifiers: Boolean; override;
186  function StoresLowerCaseQuotedIdentifiers: Boolean; override;
187  function StoresMixedCaseQuotedIdentifiers: Boolean; override;
188  function GetDefaultTransactionIsolation: TZTransactIsolationLevel; override;
189  function DataDefinitionCausesTransactionCommit: Boolean; override;
190  function DataDefinitionIgnoredInTransactions: Boolean; override;
191 
192  // interface details (terms, keywords, etc):
193  function GetSchemaTerm: string; override;
194  function GetProcedureTerm: string; override;
195  function GetCatalogTerm: string; override;
196  function GetCatalogSeparator: string; override;
197  function GetSQLKeywords: string; override;
198  function GetNumericFunctions: string; override;
199  function GetStringFunctions: string; override;
200  function GetSystemFunctions: string; override;
201  function GetTimeDateFunctions: string; override;
202  function GetSearchStringEscape: string; override;
203  function GetExtraNameCharacters: string; override;
204  end;
205 
206  {** Implements Ado Metadata. }
207  TZAdoDatabaseMetadata = class(TZAbstractDatabaseMetadata)
208  private
209  FAdoConnection: ZPlainAdo.Connection;
210  FSupportedSchemasInitialized: Boolean;
211  function AdoOpenSchema(Schema: Integer; const Args: array of const): ZPlainAdo.RecordSet;
212  procedure InitializeSchemas;
213  function SchemaSupported(SchemaId: Integer): Boolean; // (technobot) should be moved to TZAdoDatabaseInfo?
214  function FindSchema(SchemaId: Integer): Integer;
215  function BuildRestrictions(SchemaId: Integer; const Args: array of const): Variant;
216  protected
217  function CreateDatabaseInfo: IZDatabaseInfo; override; // technobot 2008-06-27
218  function DecomposeObjectString(const S: String): String; override;
219 
220  function UncachedGetTables(const Catalog: string; const SchemaPattern: string;
221  const TableNamePattern: string; const Types: TStringDynArray): IZResultSet; override;
222  function UncachedGetSchemas: IZResultSet; override;
223  function UncachedGetCatalogs: IZResultSet; override;
224  function UncachedGetTableTypes: IZResultSet; override;
225  function UncachedGetColumns(const Catalog: string; const SchemaPattern: string;
226  const TableNamePattern: string; const ColumnNamePattern: string): IZResultSet; override;
227  function UncachedGetTablePrivileges(const Catalog: string; const SchemaPattern: string;
228  const TableNamePattern: string): IZResultSet; override;
229  function UncachedGetColumnPrivileges(const Catalog: string; const Schema: string;
230  const Table: string; const ColumnNamePattern: string): IZResultSet; override;
231  function UncachedGetPrimaryKeys(const Catalog: string; const Schema: string;
232  const Table: string): IZResultSet; override;
233  function UncachedGetImportedKeys(const Catalog: string; const Schema: string;
234  const Table: string): IZResultSet; override;
235  function UncachedGetExportedKeys(const Catalog: string; const Schema: string;
236  const Table: string): IZResultSet; override;
237  function UncachedGetCrossReference(const PrimaryCatalog: string; const PrimarySchema: string;
238  const PrimaryTable: string; const ForeignCatalog: string; const ForeignSchema: string;
239  const ForeignTable: string): IZResultSet; override;
240  function UncachedGetIndexInfo(const Catalog: string; const Schema: string; const Table: string;
241  Unique: Boolean; Approximate: Boolean): IZResultSet; override;
242 // function UncachedGetSequences(const Catalog: string; const SchemaPattern: string;
243 // const SequenceNamePattern: string): IZResultSet; virtual; -> Not implemented
244  function UncachedGetProcedures(const Catalog: string; const SchemaPattern: string;
245  const ProcedureNamePattern: string): IZResultSet; override;
246  function UncachedGetProcedureColumns(const Catalog: string; const SchemaPattern: string;
247  const ProcedureNamePattern: string; const ColumnNamePattern: string):
248  IZResultSet; override;
249  function UncachedGetVersionColumns(const Catalog: string; const Schema: string;
250  const Table: string): IZResultSet; override;
251  function UncachedGetTypeInfo: IZResultSet; override;
252  function UncachedGetUDTs(const Catalog: string; const SchemaPattern: string;
253  const TypeNamePattern: string; const Types: TIntegerDynArray): IZResultSet; override;
254  public
255  constructor Create(Connection: TZAbstractConnection; const Url: TZURL); override;
256  destructor Destroy; override;
257 
258 // function GetTokenizer: IZTokenizer; override;
259  end;
260 
261 implementation
262 
263 uses
264 {$IFNDEF FPC}
265  Variants,
266 {$ENDIF}
267  Math, ZDbcUtils, ZCollections, ZGenericSqlToken, ZDbcAdoUtils, ZDbcAdo,
268  OleDB, ZDbcAdoResultSet;
269 
270 type
271  TSuppSchemaRec = record
272  SchemaGuid: TGuid;
273  SupportedRestrictions: Integer;
274  AdoSchemaId: Integer;
275  end;
276 
277  IDBSchemaRowset = interface(IUnknown)
278  ['{0c733a7b-2a1c-11ce-ade5-00aa0044773d}']
279  function GetRowset(
280  pUnkOuter : IUnknown;
281  const rguidSchema : TGUID;
282  cRestrictions : Integer;
283  var rgRestrictions : PVariant;{!!was: const VARIANT __RPC_FAR rgRestrictions[ ],}
284  const riid : IUnknown;
285  cPropertySets : Integer;
286  var rgPropertySets : TDBPROPSET;
287  var ppRowset : IUnknown) : HResult; stdcall;
288  function GetSchemas(
289  var pcSchemas : Integer;
290  var prgSchemas : PGUID;
291  var prgRestrictionSupport : PInteger) : HResult; stdcall;
292  end;
293 
294 var
295  SupportedSchemas: array of TSuppSchemaRec;
296 
297 { TZAdoDatabaseInfo }
298 
299 {**
300  Constructs this object.
301  @param Metadata the interface of the correpsonding database metadata object
302  @param IdentifierQuotes the default Quotes for Identifiers used by the driver
303 }
304 constructor TZAdoDatabaseInfo.Create(const Metadata: TZAbstractDatabaseMetadata);
305 begin
306  inherited Create(MetaData, '[]');
307 end;
308 
309 //----------------------------------------------------------------------
310 // First, a variety of minor information about the target database.
311 
312 {**
313  What's the name of this database product?
314  @return database product name
315 }
316 function TZAdoDatabaseInfo.GetDatabaseProductName: string;
317 begin
318  Result := 'ado';
319 end;
320 
321 {**
322  What's the version of this database product?
323  @return database version
324 }
325 function TZAdoDatabaseInfo.GetDatabaseProductVersion: string;
326 begin
327  Result := (Metadata.GetConnection as IZAdoConnection).GetAdoConnection.Version;
328 end;
329 
330 {**
331  What's the name of this JDBC driver?
332  @return JDBC driver name
333 }
334 function TZAdoDatabaseInfo.GetDriverName: string;
335 begin
336  Result := 'Zeos Database Connectivity Driver for Microsoft ADO';
337 end;
338 
339 {**
340  What's this JDBC driver's major version number?
341  @return JDBC driver major version
342 }
343 function TZAdoDatabaseInfo.GetDriverMajorVersion: Integer;
344 begin
345  Result := 1;
346 end;
347 
348 {**
349  What's this JDBC driver's minor version number?
350  @return JDBC driver minor version number
351 }
352 function TZAdoDatabaseInfo.GetDriverMinorVersion: Integer;
353 begin
354  Result := 0;
355 end;
356 
357 {**
358  Does the database use a file for each table?
359  @return true if the database uses a local file for each table
360 }
361 function TZAdoDatabaseInfo.UsesLocalFilePerTable: Boolean;
362 begin
363  Result := False;
364 end;
365 
366 {**
367  Does the database treat mixed case unquoted SQL identifiers as
368  case sensitive and as a result store them in mixed case?
369  A JDBC Compliant<sup><font size=-2>TM</font></sup> driver will
370  always return false.
371  @return <code>true</code> if so; <code>false</code> otherwise
372 }
373 function TZAdoDatabaseInfo.SupportsMixedCaseIdentifiers: Boolean;
374 begin
375  Result := False;
376 end;
377 
378 {**
379  Does the database treat mixed case unquoted SQL identifiers as
380  case insensitive and store them in upper case?
381  @return <code>true</code> if so; <code>false</code> otherwise
382 }
383 function TZAdoDatabaseInfo.StoresUpperCaseIdentifiers: Boolean;
384 begin
385  Result := True;
386 end;
387 
388 {**
389  Does the database treat mixed case unquoted SQL identifiers as
390  case insensitive and store them in lower case?
391  @return <code>true</code> if so; <code>false</code> otherwise
392 }
393 function TZAdoDatabaseInfo.StoresLowerCaseIdentifiers: Boolean;
394 begin
395  Result := True;
396 end;
397 
398 {**
399  Does the database treat mixed case unquoted SQL identifiers as
400  case insensitive and store them in mixed case?
401  @return <code>true</code> if so; <code>false</code> otherwise
402 }
403 function TZAdoDatabaseInfo.StoresMixedCaseIdentifiers: Boolean;
404 begin
405  Result := True;
406 end;
407 
408 {**
409  Does the database treat mixed case quoted SQL identifiers as
410  case sensitive and as a result store them in mixed case?
411  A JDBC Compliant<sup><font size=-2>TM</font></sup> driver will always return true.
412  @return <code>true</code> if so; <code>false</code> otherwise
413 }
414 function TZAdoDatabaseInfo.SupportsMixedCaseQuotedIdentifiers: Boolean;
415 begin
416  Result := True;
417 end;
418 
419 {**
420  Does the database treat mixed case quoted SQL identifiers as
421  case insensitive and store them in upper case?
422  @return <code>true</code> if so; <code>false</code> otherwise
423 }
424 function TZAdoDatabaseInfo.StoresUpperCaseQuotedIdentifiers: Boolean;
425 begin
426  Result := True;
427 end;
428 
429 {**
430  Does the database treat mixed case quoted SQL identifiers as
431  case insensitive and store them in lower case?
432  @return <code>true</code> if so; <code>false</code> otherwise
433 }
434 function TZAdoDatabaseInfo.StoresLowerCaseQuotedIdentifiers: Boolean;
435 begin
436  Result := True;
437 end;
438 
439 {**
440  Does the database treat mixed case quoted SQL identifiers as
441  case insensitive and store them in mixed case?
442  @return <code>true</code> if so; <code>false</code> otherwise
443 }
444 function TZAdoDatabaseInfo.StoresMixedCaseQuotedIdentifiers: Boolean;
445 begin
446  Result := True;
447 end;
448 
449 {**
450  Gets a comma-separated list of all a database's SQL keywords
451  that are NOT also SQL92 keywords.
452  @return the list
453 }
454 function TZAdoDatabaseInfo.GetSQLKeywords: string;
455 begin
456  { TODO -ofjanos -cAPI : SQL Keywords that are not SQL92 compliant }
457  Result := '';
458 end;
459 
460 {**
461  Gets a comma-separated list of math functions. These are the
462  X/Open CLI math function names used in the JDBC function escape
463  clause.
464  @return the list
465 }
466 function TZAdoDatabaseInfo.GetNumericFunctions: string;
467 begin
468  Result := 'ABS,ACOS,ASIN,ATAN,ATN2,CEILING,COS,COT,DEGREES,EXP,FLOOR,LOG,LOG10,'+
469  'PI,POWER,RADIANS,RAND,ROUND,SIGN,SIN,SQUARE,SQRT,TAN';
470 end;
471 
472 {**
473  Gets a comma-separated list of string functions. These are the
474  X/Open CLI string function names used in the JDBC function escape
475  clause.
476  @return the list
477 }
478 function TZAdoDatabaseInfo.GetStringFunctions: string;
479 begin
480  Result := 'ASCII,CHAR,CHARINDEX,DIFFERENCE,LEFT,LEN,LOWER,LTRIM,NCHAR,PATINDEX,'+
481  'REPLACE,QUOTENAME,REPLICATE,REVERSE,RIGHT,RTRIM,SOUNDEX,SPACE,STR,'+
482  'STUFF,SUBSTRING,UNICODE,UPPER';
483 end;
484 
485 {**
486  Gets a comma-separated list of system functions. These are the
487  X/Open CLI system function names used in the JDBC function escape
488  clause.
489  @return the list
490 }
491 function TZAdoDatabaseInfo.GetSystemFunctions: string;
492 begin
493  Result := 'APP_NAME,CASE,CAST,CONVERT,COALESCE,CURRENT_TIMESTAMP,CURRENT_USER,'+
494  'DATALENGTH,@@ERROR,FORMATMESSAGE,GETANSINULL,HOST_ID,HOST_NAME,'+
495  'IDENT_INCR,IDENT_SEED,@@IDENTITY,IDENTITY,ISDATE,ISNULL,ISNUMERIC,'+
496  'NEWID,NULLIF,PARSENAME,PERMISSIONS,@@ROWCOUNT,SESSION_USER,STATS_DATE,'+
497  'SYSTEM_USER,@@TRANCOUNT,USER_NAME';
498 end;
499 
500 {**
501  Gets a comma-separated list of time and date functions.
502  @return the list
503 }
504 function TZAdoDatabaseInfo.GetTimeDateFunctions: string;
505 begin
506  Result := 'DATEADD,DATEDIFF,DATENAME,DATEPART,DAY,GETDATE,MONTH,YEAR';
507 end;
508 
509 {**
510  Gets the string that can be used to escape wildcard characters.
511  This is the string that can be used to escape '_' or '%' in
512  the string pattern style catalog search parameters.
513 
514  <P>The '_' character represents any single character.
515  <P>The '%' character represents any sequence of zero or
516  more characters.
517 
518  @return the string used to escape wildcard characters
519 }
520 function TZAdoDatabaseInfo.GetSearchStringEscape: string;
521 begin
522 { TODO -ofjanos -cgeneral :
523 In sql server this must be specified as the parameter of like.
524 example: WHERE ColumnA LIKE '%5/%%' ESCAPE '/' }
525  Result := '/';
526 end;
527 
528 {**
529  Gets all the "extra" characters that can be used in unquoted
530  identifier names (those beyond a-z, A-Z, 0-9 and _).
531  @return the string containing the extra characters
532 }
533 function TZAdoDatabaseInfo.GetExtraNameCharacters: string;
534 begin
535  Result := '@$#';
536 end;
537 
538 //--------------------------------------------------------------------
539 // Functions describing which features are supported.
540 
541 {**
542  Are expressions in "ORDER BY" lists supported?
543  @return <code>true</code> if so; <code>false</code> otherwise
544 }
545 function TZAdoDatabaseInfo.SupportsExpressionsInOrderBy: Boolean;
546 begin
547  Result := True;
548 end;
549 
550 {**
551  Can an "ORDER BY" clause use columns not in the SELECT statement?
552  @return <code>true</code> if so; <code>false</code> otherwise
553 }
554 function TZAdoDatabaseInfo.SupportsOrderByUnrelated: Boolean;
555 begin
556  Result := True;
557 end;
558 
559 {**
560  Is some form of "GROUP BY" clause supported?
561  @return <code>true</code> if so; <code>false</code> otherwise
562 }
563 function TZAdoDatabaseInfo.SupportsGroupBy: Boolean;
564 begin
565  Result := True;
566 end;
567 
568 {**
569  Can a "GROUP BY" clause use columns not in the SELECT?
570  @return <code>true</code> if so; <code>false</code> otherwise
571 }
572 function TZAdoDatabaseInfo.SupportsGroupByUnrelated: Boolean;
573 begin
574  Result := True;
575 end;
576 
577 {**
578  Can a "GROUP BY" clause add columns not in the SELECT
579  provided it specifies all the columns in the SELECT?
580  @return <code>true</code> if so; <code>false</code> otherwise
581 }
582 function TZAdoDatabaseInfo.SupportsGroupByBeyondSelect: Boolean;
583 begin
584  Result := True;
585 end;
586 
587 {**
588  Is the SQL Integrity Enhancement Facility supported?
589  @return <code>true</code> if so; <code>false</code> otherwise
590 }
591 function TZAdoDatabaseInfo.SupportsIntegrityEnhancementFacility: Boolean;
592 begin
593  Result := False;
594 end;
595 
596 {**
597  What's the database vendor's preferred term for "schema"?
598  @return the vendor term
599 }
600 function TZAdoDatabaseInfo.GetSchemaTerm: string;
601 begin
602  Result := 'owner';
603 end;
604 
605 {**
606  What's the database vendor's preferred term for "procedure"?
607  @return the vendor term
608 }
609 function TZAdoDatabaseInfo.GetProcedureTerm: string;
610 begin
611  Result := 'procedure';
612 end;
613 
614 {**
615  What's the database vendor's preferred term for "catalog"?
616  @return the vendor term
617 }
618 function TZAdoDatabaseInfo.GetCatalogTerm: string;
619 begin
620  Result := 'database';
621 end;
622 
623 {**
624  What's the separator between catalog and table name?
625  @return the separator string
626 }
627 function TZAdoDatabaseInfo.GetCatalogSeparator: string;
628 begin
629  Result := '.';
630 end;
631 
632 {**
633  Can a schema name be used in a data manipulation statement?
634  @return <code>true</code> if so; <code>false</code> otherwise
635 }
636 function TZAdoDatabaseInfo.SupportsSchemasInDataManipulation: Boolean;
637 begin
638  Result := True;
639 end;
640 
641 {**
642  Can a schema name be used in a procedure call statement?
643  @return <code>true</code> if so; <code>false</code> otherwise
644 }
645 function TZAdoDatabaseInfo.SupportsSchemasInProcedureCalls: Boolean;
646 begin
647  Result := True;
648 end;
649 
650 {**
651  Can a schema name be used in a table definition statement?
652  @return <code>true</code> if so; <code>false</code> otherwise
653 }
654 function TZAdoDatabaseInfo.SupportsSchemasInTableDefinitions: Boolean;
655 begin
656  Result := True;
657 end;
658 
659 {**
660  Can a schema name be used in an index definition statement?
661  @return <code>true</code> if so; <code>false</code> otherwise
662 }
663 function TZAdoDatabaseInfo.SupportsSchemasInIndexDefinitions: Boolean;
664 begin
665  Result := True;
666 end;
667 
668 {**
669  Can a schema name be used in a privilege definition statement?
670  @return <code>true</code> if so; <code>false</code> otherwise
671 }
672 function TZAdoDatabaseInfo.SupportsSchemasInPrivilegeDefinitions: Boolean;
673 begin
674  Result := True;
675 end;
676 
677 {**
678  Can a catalog name be used in a data manipulation statement?
679  @return <code>true</code> if so; <code>false</code> otherwise
680 }
681 function TZAdoDatabaseInfo.SupportsCatalogsInDataManipulation: Boolean;
682 begin
683  Result := True;
684 end;
685 
686 {**
687  Can a catalog name be used in a procedure call statement?
688  @return <code>true</code> if so; <code>false</code> otherwise
689 }
690 function TZAdoDatabaseInfo.SupportsCatalogsInProcedureCalls: Boolean;
691 begin
692  Result := True;
693 end;
694 
695 {**
696  Can a catalog name be used in a table definition statement?
697  @return <code>true</code> if so; <code>false</code> otherwise
698 }
699 function TZAdoDatabaseInfo.SupportsCatalogsInTableDefinitions: Boolean;
700 begin
701  Result := True;
702 end;
703 
704 {**
705  Can a catalog name be used in an index definition statement?
706  @return <code>true</code> if so; <code>false</code> otherwise
707 }
708 function TZAdoDatabaseInfo.SupportsCatalogsInIndexDefinitions: Boolean;
709 begin
710  Result := True;
711 end;
712 
713 {**
714  Can a catalog name be used in a privilege definition statement?
715  @return <code>true</code> if so; <code>false</code> otherwise
716 }
717 function TZAdoDatabaseInfo.SupportsCatalogsInPrivilegeDefinitions: Boolean;
718 begin
719  Result := True;
720 end;
721 
722 {**
723  Can a stored procedure have an additional overload suffix?
724  @return <code>true</code> if so; <code>false</code> otherwise
725 }
726 function TZAdoDatabaseInfo.SupportsOverloadPrefixInStoredProcedureName: Boolean;
727 begin
728  Result := True;
729 end;
730 
731 {**
732  Is positioned DELETE supported?
733  @return <code>true</code> if so; <code>false</code> otherwise
734 }
735 function TZAdoDatabaseInfo.SupportsPositionedDelete: Boolean;
736 begin
737 //CURRENT OF
738 //Specifies that the DELETE is done at the current position of the specified cursor.
739  Result := True;
740 end;
741 
742 {**
743  Is positioned UPDATE supported?
744  @return <code>true</code> if so; <code>false</code> otherwise
745 }
746 function TZAdoDatabaseInfo.SupportsPositionedUpdate: Boolean;
747 begin
748  Result := True;
749 end;
750 
751 {**
752  Is SELECT for UPDATE supported?
753  @return <code>true</code> if so; <code>false</code> otherwise
754 }
755 function TZAdoDatabaseInfo.SupportsSelectForUpdate: Boolean;
756 begin
757  Result := True;
758 end;
759 
760 {**
761  Are stored procedure calls using the stored procedure escape
762  syntax supported?
763  @return <code>true</code> if so; <code>false</code> otherwise
764 }
765 function TZAdoDatabaseInfo.SupportsStoredProcedures: Boolean;
766 begin
767  Result := True;
768 end;
769 
770 {**
771  Are subqueries in comparison expressions supported?
772  A JDBC Compliant<sup><font size=-2>TM</font></sup> driver always returns true.
773  @return <code>true</code> if so; <code>false</code> otherwise
774 }
775 function TZAdoDatabaseInfo.SupportsSubqueriesInComparisons: Boolean;
776 begin
777  Result := True;
778 end;
779 
780 {**
781  Are subqueries in 'exists' expressions supported?
782  A JDBC Compliant<sup><font size=-2>TM</font></sup> driver always returns true.
783  @return <code>true</code> if so; <code>false</code> otherwise
784 }
785 function TZAdoDatabaseInfo.SupportsSubqueriesInExists: Boolean;
786 begin
787  Result := True;
788 end;
789 
790 {**
791  Are subqueries in 'in' statements supported?
792  A JDBC Compliant<sup><font size=-2>TM</font></sup> driver always returns true.
793  @return <code>true</code> if so; <code>false</code> otherwise
794 }
795 function TZAdoDatabaseInfo.SupportsSubqueriesInIns: Boolean;
796 begin
797  Result := True;
798 end;
799 
800 {**
801  Are subqueries in quantified expressions supported?
802  A JDBC Compliant<sup><font size=-2>TM</font></sup> driver always returns true.
803  @return <code>true</code> if so; <code>false</code> otherwise
804 }
805 function TZAdoDatabaseInfo.SupportsSubqueriesInQuantifieds: Boolean;
806 begin
807  Result := True;
808 end;
809 
810 {**
811  Are correlated subqueries supported?
812  A JDBC Compliant<sup><font size=-2>TM</font></sup> driver always returns true.
813  @return <code>true</code> if so; <code>false</code> otherwise
814 }
815 function TZAdoDatabaseInfo.SupportsCorrelatedSubqueries: Boolean;
816 begin
817  Result := True;
818 end;
819 
820 {**
821  Is SQL UNION supported?
822  @return <code>true</code> if so; <code>false</code> otherwise
823 }
824 function TZAdoDatabaseInfo.SupportsUnion: Boolean;
825 begin
826  Result := True;
827 end;
828 
829 {**
830  Is SQL UNION ALL supported?
831  @return <code>true</code> if so; <code>false</code> otherwise
832 }
833 function TZAdoDatabaseInfo.SupportsUnionAll: Boolean;
834 begin
835  Result := True;
836 end;
837 
838 {**
839  Can cursors remain open across commits?
840  @return <code>true</code> if cursors always remain open;
841  <code>false</code> if they might not remain open
842 }
843 function TZAdoDatabaseInfo.SupportsOpenCursorsAcrossCommit: Boolean;
844 begin
845  Result := True;
846 end;
847 
848 {**
849  Can cursors remain open across rollbacks?
850  @return <code>true</code> if cursors always remain open;
851  <code>false</code> if they might not remain open
852 }
853 function TZAdoDatabaseInfo.SupportsOpenCursorsAcrossRollback: Boolean;
854 begin
855  Result := True;
856 end;
857 
858 {**
859  Can statements remain open across commits?
860  @return <code>true</code> if statements always remain open;
861  <code>false</code> if they might not remain open
862 }
863 function TZAdoDatabaseInfo.SupportsOpenStatementsAcrossCommit: Boolean;
864 begin
865  Result := False;
866 end;
867 
868 {**
869  Can statements remain open across rollbacks?
870  @return <code>true</code> if statements always remain open;
871  <code>false</code> if they might not remain open
872 }
873 function TZAdoDatabaseInfo.SupportsOpenStatementsAcrossRollback: Boolean;
874 begin
875  Result := False;
876 end;
877 
878 //----------------------------------------------------------------------
879 // The following group of methods exposes various limitations
880 // based on the target database with the current driver.
881 // Unless otherwise specified, a result of zero means there is no
882 // limit, or the limit is not known.
883 
884 {**
885  How many hex characters can you have in an inline binary literal?
886  @return max binary literal length in hex characters;
887  a result of zero means that there is no limit or the limit is not known
888 }
889 function TZAdoDatabaseInfo.GetMaxBinaryLiteralLength: Integer;
890 begin
891  Result := 16000;
892 end;
893 
894 {**
895  What's the max length for a character literal?
896  @return max literal length;
897  a result of zero means that there is no limit or the limit is not known
898 }
899 function TZAdoDatabaseInfo.GetMaxCharLiteralLength: Integer;
900 begin
901  Result := 8000;
902 end;
903 
904 {**
905  What's the limit on column name length?
906  @return max column name length;
907  a result of zero means that there is no limit or the limit is not known
908 }
909 function TZAdoDatabaseInfo.GetMaxColumnNameLength: Integer;
910 begin
911  Result := 128;
912 end;
913 
914 {**
915  What's the maximum number of columns in a "GROUP BY" clause?
916  @return max number of columns;
917  a result of zero means that there is no limit or the limit is not known
918 }
919 function TZAdoDatabaseInfo.GetMaxColumnsInGroupBy: Integer;
920 begin
921  Result := 0;
922 end;
923 
924 {**
925  What's the maximum number of columns allowed in an index?
926  @return max number of columns;
927  a result of zero means that there is no limit or the limit is not known
928 }
929 function TZAdoDatabaseInfo.GetMaxColumnsInIndex: Integer;
930 begin
931  Result := 16;
932 end;
933 
934 {**
935  What's the maximum number of columns in an "ORDER BY" clause?
936  @return max number of columns;
937  a result of zero means that there is no limit or the limit is not known
938 }
939 function TZAdoDatabaseInfo.GetMaxColumnsInOrderBy: Integer;
940 begin
941  Result := 0;
942 end;
943 
944 {**
945  What's the maximum number of columns in a "SELECT" list?
946  @return max number of columns;
947  a result of zero means that there is no limit or the limit is not known
948 }
949 function TZAdoDatabaseInfo.GetMaxColumnsInSelect: Integer;
950 begin
951  Result := 4096;
952 end;
953 
954 {**
955  What's the maximum number of columns in a table?
956  @return max number of columns;
957  a result of zero means that there is no limit or the limit is not known
958 }
959 function TZAdoDatabaseInfo.GetMaxColumnsInTable: Integer;
960 begin
961  Result := 1024;
962 end;
963 
964 {**
965  How many active connections can we have at a time to this database?
966  @return max number of active connections;
967  a result of zero means that there is no limit or the limit is not known
968 }
969 function TZAdoDatabaseInfo.GetMaxConnections: Integer;
970 begin
971  Result := 0;
972 end;
973 
974 {**
975  What's the maximum cursor name length?
976  @return max cursor name length in bytes;
977  a result of zero means that there is no limit or the limit is not known
978 }
979 function TZAdoDatabaseInfo.GetMaxCursorNameLength: Integer;
980 begin
981  Result := 128;
982 end;
983 
984 {**
985  Retrieves the maximum number of bytes for an index, including all
986  of the parts of the index.
987  @return max index length in bytes, which includes the composite of all
988  the constituent parts of the index;
989  a result of zero means that there is no limit or the limit is not known
990 }
991 function TZAdoDatabaseInfo.GetMaxIndexLength: Integer;
992 begin
993  Result := 900;
994 end;
995 
996 {**
997  What's the maximum length allowed for a schema name?
998  @return max name length in bytes;
999  a result of zero means that there is no limit or the limit is not known
1000 }
1001 function TZAdoDatabaseInfo.GetMaxSchemaNameLength: Integer;
1002 begin
1003  Result := 128;
1004 end;
1005 
1006 {**
1007  What's the maximum length of a procedure name?
1008  @return max name length in bytes;
1009  a result of zero means that there is no limit or the limit is not known
1010 }
1011 function TZAdoDatabaseInfo.GetMaxProcedureNameLength: Integer;
1012 begin
1013  Result := 128;
1014 end;
1015 
1016 {**
1017  What's the maximum length of a catalog name?
1018  @return max name length in bytes;
1019  a result of zero means that there is no limit or the limit is not known
1020 }
1021 function TZAdoDatabaseInfo.GetMaxCatalogNameLength: Integer;
1022 begin
1023  Result := 128;
1024 end;
1025 
1026 {**
1027  What's the maximum length of a single row?
1028  @return max row size in bytes;
1029  a result of zero means that there is no limit or the limit is not known
1030 }
1031 function TZAdoDatabaseInfo.GetMaxRowSize: Integer;
1032 begin
1033  Result := 8060;
1034 end;
1035 
1036 {**
1037  Did getMaxRowSize() include LONGVARCHAR and LONGVARBINARY
1038  blobs?
1039  @return <code>true</code> if so; <code>false</code> otherwise
1040 }
1041 function TZAdoDatabaseInfo.DoesMaxRowSizeIncludeBlobs: Boolean;
1042 begin
1043  Result := False;
1044 end;
1045 
1046 {**
1047  What's the maximum length of an SQL statement?
1048  @return max length in bytes;
1049  a result of zero means that there is no limit or the limit is not known
1050 }
1051 function TZAdoDatabaseInfo.GetMaxStatementLength: Integer;
1052 begin
1053  Result := 0;
1054 end;
1055 
1056 {**
1057  How many active statements can we have open at one time to this
1058  database?
1059  @return the maximum number of statements that can be open at one time;
1060  a result of zero means that there is no limit or the limit is not known
1061 }
1062 function TZAdoDatabaseInfo.GetMaxStatements: Integer;
1063 begin
1064  Result := 0;
1065 end;
1066 
1067 {**
1068  What's the maximum length of a table name?
1069  @return max name length in bytes;
1070  a result of zero means that there is no limit or the limit is not known
1071 }
1072 function TZAdoDatabaseInfo.GetMaxTableNameLength: Integer;
1073 begin
1074  Result := 128;
1075 end;
1076 
1077 {**
1078  What's the maximum number of tables in a SELECT statement?
1079  @return the maximum number of tables allowed in a SELECT statement;
1080  a result of zero means that there is no limit or the limit is not known
1081 }
1082 function TZAdoDatabaseInfo.GetMaxTablesInSelect: Integer;
1083 begin
1084  Result := 256;
1085 end;
1086 
1087 {**
1088  What's the maximum length of a user name?
1089  @return max user name length in bytes;
1090  a result of zero means that there is no limit or the limit is not known
1091 }
1092 function TZAdoDatabaseInfo.GetMaxUserNameLength: Integer;
1093 begin
1094  Result := 128;
1095 end;
1096 
1097 //----------------------------------------------------------------------
1098 
1099 {**
1100  What's the database's default transaction isolation level? The
1101  values are defined in <code>java.sql.Connection</code>.
1102  @return the default isolation level
1103  @see Connection
1104 }
1105 function TZAdoDatabaseInfo.GetDefaultTransactionIsolation:
1106  TZTransactIsolationLevel;
1107 begin
1108  Result := tiReadCommitted;
1109 end;
1110 
1111 {**
1112  Are transactions supported? If not, invoking the method
1113  <code>commit</code> is a noop and the isolation level is TRANSACTION_NONE.
1114  @return <code>true</code> if transactions are supported; <code>false</code> otherwise
1115 }
1116 function TZAdoDatabaseInfo.SupportsTransactions: Boolean;
1117 begin
1118  Result := True;
1119 end;
1120 
1121 {**
1122  Does this database support the given transaction isolation level?
1123  @param level the values are defined in <code>java.sql.Connection</code>
1124  @return <code>true</code> if so; <code>false</code> otherwise
1125  @see Connection
1126 }
1127 function TZAdoDatabaseInfo.SupportsTransactionIsolationLevel(
1128  Level: TZTransactIsolationLevel): Boolean;
1129 begin
1130  Result := True;
1131 end;
1132 
1133 {**
1134  Are both data definition and data manipulation statements
1135  within a transaction supported?
1136  @return <code>true</code> if so; <code>false</code> otherwise
1137 }
1138 function TZAdoDatabaseInfo.
1139  SupportsDataDefinitionAndDataManipulationTransactions: Boolean;
1140 begin
1141  Result := True;
1142 end;
1143 
1144 {**
1145  Are only data manipulation statements within a transaction
1146  supported?
1147  @return <code>true</code> if so; <code>false</code> otherwise
1148 }
1149 function TZAdoDatabaseInfo.
1150  SupportsDataManipulationTransactionsOnly: Boolean;
1151 begin
1152  Result := False;
1153 end;
1154 
1155 {**
1156  Does a data definition statement within a transaction force the
1157  transaction to commit?
1158  @return <code>true</code> if so; <code>false</code> otherwise
1159 }
1160 function TZAdoDatabaseInfo.DataDefinitionCausesTransactionCommit: Boolean;
1161 begin
1162  Result := False;
1163 end;
1164 
1165 {**
1166  Is a data definition statement within a transaction ignored?
1167  @return <code>true</code> if so; <code>false</code> otherwise
1168 }
1169 function TZAdoDatabaseInfo.DataDefinitionIgnoredInTransactions: Boolean;
1170 begin
1171  Result := False;
1172 end;
1173 
1174 {**
1175  Does the database support the given result set type?
1176  @param type defined in <code>java.sql.ResultSet</code>
1177  @return <code>true</code> if so; <code>false</code> otherwise
1178 }
1179 function TZAdoDatabaseInfo.SupportsResultSetType(
1180  _Type: TZResultSetType): Boolean;
1181 begin
1182  Result := True;
1183 end;
1184 
1185 {**
1186  Does the database support the concurrency type in combination
1187  with the given result set type?
1188 
1189  @param type defined in <code>java.sql.ResultSet</code>
1190  @param concurrency type defined in <code>java.sql.ResultSet</code>
1191  @return <code>true</code> if so; <code>false</code> otherwise
1192 }
1193 function TZAdoDatabaseInfo.SupportsResultSetConcurrency(
1194  _Type: TZResultSetType; Concurrency: TZResultSetConcurrency): Boolean;
1195 begin
1196  Result := True;
1197 end;
1198 
1199 {**
1200  Does the Database or Actual Version understand non escaped search strings?
1201  @return <code>true</code> if the DataBase does understand non escaped
1202  search strings
1203 }
1204 function TZAdoDatabaseInfo.SupportsNonEscapedSearchStrings: Boolean;
1205 begin
1206  Result := True;
1207 end;
1208 
1209 {**
1210  Does the Database support updating auto incremental fields?
1211  @return <code>true</code> if the DataBase allows it.
1212 }
1213 function TZAdoDatabaseInfo.SupportsUpdateAutoIncrementFields: Boolean;
1214 begin
1215  Result := False;
1216 end;
1217 
1218 { TZAdoDatabaseMetadata }
1219 
1220 
1221 {**
1222  Constructs this object and assignes the main properties.
1223  @param Connection a database connection object.
1224  @param Url a database connection url string.
1225  @param Info an extra connection properties.
1226 }
1227 constructor TZAdoDatabaseMetadata.Create(Connection: TZAbstractConnection;
1228  const Url: TZURL);
1229 begin
1230  inherited Create(Connection, Url);
1231  FAdoConnection := nil;
1232 end;
1233 
1234 {**
1235  Destroys this object and cleanups the memory.
1236 }
1237 destructor TZAdoDatabaseMetadata.Destroy;
1238 begin
1239  inherited Destroy;
1240 end;
1241 
1242 {**
1243  Constructs a database information object and returns the interface to it. Used
1244  internally by the constructor.
1245  @return the database information object interface
1246 }
1247 function TZAdoDatabaseMetadata.CreateDatabaseInfo: IZDatabaseInfo;
1248 begin
1249  Result := TZAdoDatabaseInfo.Create(Self);
1250 end;
1251 
1252 function TZAdoDatabaseMetadata.DecomposeObjectString(const S: String): String;
1253 begin
1254  if S = '' then
1255  Result := S
1256  else
1257  if IC.IsQuoted(S) then
1258  Result := IC.ExtractQuote(S)
1259  else
1260  Result := s;
1261 end;
1262 {**
1263  Gets a description of the stored procedures available in a
1264  catalog.
1265 
1266  <P>Only procedure descriptions matching the schema and
1267  procedure name criteria are returned. They are ordered by
1268  PROCEDURE_SCHEM, and PROCEDURE_NAME.
1269 
1270  <P>Each procedure description has the the following columns:
1271  <OL>
1272  <LI><B>PROCEDURE_CAT</B> String => procedure catalog (may be null)
1273  <LI><B>PROCEDURE_SCHEM</B> String => procedure schema (may be null)
1274  <LI><B>PROCEDURE_NAME</B> String => procedure name
1275  <LI> reserved for future use
1276  <LI> reserved for future use
1277  <LI> reserved for future use
1278  <LI><B>REMARKS</B> String => explanatory comment on the procedure
1279  <LI><B>PROCEDURE_TYPE</B> short => kind of procedure:
1280  <UL>
1281  <LI> procedureResultUnknown - May return a result
1282  <LI> procedureNoResult - Does not return a result
1283  <LI> procedureReturnsResult - Returns a result
1284  </UL>
1285  </OL>
1286 
1287  @param catalog a catalog name; "" retrieves those without a
1288  catalog; null means drop catalog name from the selection criteria
1289  @param schemaPattern a schema name pattern; "" retrieves those
1290  without a schema
1291  @param procedureNamePattern a procedure name pattern
1292  @return <code>ResultSet</code> - each row is a procedure description
1293  @see #getSearchStringEscape
1294 }
1295 function TZAdoDatabaseMetadata.UncachedGetProcedures(const Catalog: string;
1296  const SchemaPattern: string; const ProcedureNamePattern: string): IZResultSet;
1297 var
1298  AdoRecordSet: ZPlainAdo.RecordSet;
1299 begin
1300  Result:=inherited UncachedGetProcedures(Catalog, SchemaPattern, ProcedureNamePattern);
1301 
1302  AdoRecordSet := AdoOpenSchema(adSchemaProcedures,
1303  [Catalog, SchemaPattern, ProcedureNamePattern, '']);
1304  if Assigned(AdoRecordSet) then
1305  begin
1306  with TZAdoResultSet.Create(GetStatement, '', AdoRecordSet) do
1307  begin
1308  while Next do
1309  begin
1310  Result.MoveToInsertRow;
1311  Result.UpdateStringByName('PROCEDURE_CAT',
1312  GetStringByName('PROCEDURE_CATALOG'));
1313  Result.UpdateStringByName('PROCEDURE_SCHEM',
1314  GetStringByName('PROCEDURE_SCHEMA'));
1315  Result.UpdateStringByName('PROCEDURE_NAME',
1316  GetStringByName('PROCEDURE_NAME'));
1317  Result.UpdateStringByName('REMARKS',
1318  GetStringByName('DESCRIPTION'));
1319  Result.UpdateShortByName('PROCEDURE_TYPE',
1320  GetShortByName('PROCEDURE_TYPE') - 1);
1321  Result.InsertRow;
1322  end;
1323  Close;
1324  Free;
1325  end;
1326  end;
1327 end;
1328 
1329 {**
1330  Gets a description of a catalog's stored procedure parameters
1331  and result columns.
1332 
1333  <P>Only descriptions matching the schema, procedure and
1334  parameter name criteria are returned. They are ordered by
1335  PROCEDURE_SCHEM and PROCEDURE_NAME. Within this, the return value,
1336  if any, is first. Next are the parameter descriptions in call
1337  order. The column descriptions follow in column number order.
1338 
1339  <P>Each row in the <code>ResultSet</code> is a parameter description or
1340  column description with the following fields:
1341  <OL>
1342  <LI><B>PROCEDURE_CAT</B> String => procedure catalog (may be null)
1343  <LI><B>PROCEDURE_SCHEM</B> String => procedure schema (may be null)
1344  <LI><B>PROCEDURE_NAME</B> String => procedure name
1345  <LI><B>COLUMN_NAME</B> String => column/parameter name
1346  <LI><B>COLUMN_TYPE</B> Short => kind of column/parameter:
1347  <UL>
1348  <LI> procedureColumnUnknown - nobody knows
1349  <LI> procedureColumnIn - IN parameter
1350  <LI> procedureColumnInOut - INOUT parameter
1351  <LI> procedureColumnOut - OUT parameter
1352  <LI> procedureColumnReturn - procedure return value
1353  <LI> procedureColumnResult - result column in <code>ResultSet</code>
1354  </UL>
1355  <LI><B>DATA_TYPE</B> short => SQL type from java.sql.Types
1356  <LI><B>TYPE_NAME</B> String => SQL type name, for a UDT type the
1357  type name is fully qualified
1358  <LI><B>PRECISION</B> int => precision
1359  <LI><B>LENGTH</B> int => length in bytes of data
1360  <LI><B>SCALE</B> short => scale
1361  <LI><B>RADIX</B> short => radix
1362  <LI><B>NULLABLE</B> short => can it contain NULL?
1363  <UL>
1364  <LI> procedureNoNulls - does not allow NULL values
1365  <LI> procedureNullable - allows NULL values
1366  <LI> procedureNullableUnknown - nullability unknown
1367  </UL>
1368  <LI><B>REMARKS</B> String => comment describing parameter/column
1369  </OL>
1370 
1371  <P><B>Note:</B> Some databases may not return the column
1372  descriptions for a procedure. Additional columns beyond
1373  REMARKS can be defined by the database.
1374 
1375  @param catalog a catalog name; "" retrieves those without a
1376  catalog; null means drop catalog name from the selection criteria
1377  @param schemaPattern a schema name pattern; "" retrieves those
1378  without a schema
1379  @param procedureNamePattern a procedure name pattern
1380  @param columnNamePattern a column name pattern
1381  @return <code>ResultSet</code> - each row describes a stored procedure parameter or
1382  column
1383  @see #getSearchStringEscape
1384 }
1385 function TZAdoDatabaseMetadata.UncachedGetProcedureColumns(const Catalog: string;
1386  const SchemaPattern: string; const ProcedureNamePattern: string;
1387  const ColumnNamePattern: string): IZResultSet;
1388 var
1389  AdoRecordSet: ZPlainAdo.RecordSet;
1390 begin
1391  Result:=inherited UncachedGetProcedureColumns(Catalog, SchemaPattern, ProcedureNamePattern, ColumnNamePattern);
1392 
1393  AdoRecordSet := AdoOpenSchema(adSchemaProcedureParameters,
1394  [Catalog, SchemaPattern, ProcedureNamePattern]);
1395  if Assigned(AdoRecordSet) then
1396  begin
1397  with TZAdoResultSet.Create(GetStatement, '', AdoRecordSet) do
1398  begin
1399  while Next do
1400  begin
1401  Result.MoveToInsertRow;
1402  Result.UpdateStringByName('PROCEDURE_CAT',
1403  GetStringByName('PROCEDURE_CATALOG'));
1404  Result.UpdateStringByName('PROCEDURE_SCHEM',
1405  GetStringByName('PROCEDURE_SCHEMA'));
1406  Result.UpdateStringByName('PROCEDURE_NAME',
1407  GetStringByName('PROCEDURE_NAME'));
1408  Result.UpdateStringByName('COLUMN_NAME',
1409  GetStringByName('PARAMETER_NAME'));
1410  case GetShortByName('PARAMETER_TYPE') of
1411  1: Result.UpdateShortByName('COLUMN_TYPE', Ord(pctIn));
1412  2: Result.UpdateShortByName('COLUMN_TYPE', Ord(pctInOut));
1413  3: Result.UpdateShortByName('COLUMN_TYPE', Ord(pctOut));
1414  4: Result.UpdateShortByName('COLUMN_TYPE', Ord(pctReturn));
1415  else
1416  Result.UpdateShortByName('COLUMN_TYPE', Ord(pctUnknown));
1417  end;
1418  Result.UpdateShortByName('DATA_TYPE',
1419  Ord(ConvertAdoToSqlType(GetShortByName('DATA_TYPE'),
1420  ConSettings.CPType)));
1421  Result.UpdateStringByName('TYPE_NAME',
1422  GetStringByName('TYPE_NAME'));
1423  Result.UpdateIntByName('PRECISION',
1424  GetIntByName('NUMERIC_PRECISION'));
1425  Result.UpdateIntByName('LENGTH',
1426  GetIntByName('CHARACTER_OCTET_LENGTH'));
1427  Result.UpdateShortByName('SCALE',
1428  GetShortByName('NUMERIC_SCALE'));
1429  // Result.UpdateShortByName('RADIX', GetShortByName('RADIX'));
1430  Result.UpdateShortByName('NULLABLE', 2);
1431  if GetStringByName('IS_NULLABLE') = 'NO' then
1432  Result.UpdateShortByName('NULLABLE', 0);
1433  if GetStringByName('IS_NULLABLE') = 'YES' then
1434  Result.UpdateShortByName('NULLABLE', 1);
1435  Result.UpdateStringByName('REMARKS',
1436  GetStringByName('DESCRIPTION'));
1437  Result.InsertRow;
1438  end;
1439  Close;
1440  Free;
1441  end;
1442  end;
1443 end;
1444 
1445 {**
1446  Gets a description of tables available in a catalog.
1447 
1448  <P>Only table descriptions matching the catalog, schema, table
1449  name and type criteria are returned. They are ordered by
1450  TABLE_TYPE, TABLE_SCHEM and TABLE_NAME.
1451 
1452  <P>Each table description has the following columns:
1453  <OL>
1454  <LI><B>TABLE_CAT</B> String => table catalog (may be null)
1455  <LI><B>TABLE_SCHEM</B> String => table schema (may be null)
1456  <LI><B>TABLE_NAME</B> String => table name
1457  <LI><B>TABLE_TYPE</B> String => table type. Typical types are "TABLE",
1458  "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY",
1459  "LOCAL TEMPORARY", "ALIAS", "SYNONYM".
1460  <LI><B>REMARKS</B> String => explanatory comment on the table
1461  </OL>
1462 
1463  <P><B>Note:</B> Some databases may not return information for
1464  all tables.
1465 
1466  @param catalog a catalog name; "" retrieves those without a
1467  catalog; null means drop catalog name from the selection criteria
1468  @param schemaPattern a schema name pattern; "" retrieves those
1469  without a schema
1470  @param tableNamePattern a table name pattern
1471  @param types a list of table types to include; null returns all types
1472  @return <code>ResultSet</code> - each row is a table description
1473  @see #getSearchStringEscape
1474 }
1475 function TZAdoDatabaseMetadata.UncachedGetTables(const Catalog: string;
1476  const SchemaPattern: string; const TableNamePattern: string;
1477  const Types: TStringDynArray): IZResultSet;
1478 var
1479  I: Integer;
1480  TableTypes: string;
1481  AdoRecordSet: ZPlainAdo.RecordSet;
1482 begin
1483  Result:=inherited UncachedGetTables(Catalog, SchemaPattern, TableNamePattern, Types);
1484 
1485  for I := Low(Types) to High(Types) do
1486  begin
1487  if Length(TableTypes) > 0 then
1488  TableTypes := TableTypes + ',';
1489  TableTypes := TableTypes + Types[I];
1490  end;
1491 
1492  AdoRecordSet := AdoOpenSchema(adSchemaTables,
1493  [Catalog, SchemaPattern, TableNamePattern, TableTypes]);
1494  if Assigned(AdoRecordSet) then
1495  begin
1496  with TZAdoResultSet.Create(GetStatement, '', AdoRecordset) do
1497  begin
1498  while Next do
1499  begin
1500  Result.MoveToInsertRow;
1501  Result.UpdateStringByName('TABLE_CAT',
1502  GetStringByName('TABLE_CATALOG'));
1503  Result.UpdateStringByName('TABLE_SCHEM',
1504  GetStringByName('TABLE_SCHEMA'));
1505  Result.UpdateStringByName('TABLE_NAME',
1506  GetStringByName('TABLE_NAME'));
1507  Result.UpdateStringByName('TABLE_TYPE',
1508  GetStringByName('TABLE_TYPE'));
1509  Result.UpdateStringByName('REMARKS',
1510  GetStringByName('DESCRIPTION'));
1511  Result.InsertRow;
1512  end;
1513  Close;
1514  Free;
1515  end;
1516  end;
1517 end;
1518 
1519 {**
1520  Gets the schema names available in this database. The results
1521  are ordered by schema name.
1522 
1523  <P>The schema column is:
1524  <OL>
1525  <LI><B>TABLE_SCHEM</B> String => schema name
1526  </OL>
1527 
1528  @return <code>ResultSet</code> - each row has a single String column that is a
1529  schema name
1530 }
1531 function TZAdoDatabaseMetadata.UncachedGetSchemas: IZResultSet;
1532 var
1533  AdoRecordSet: ZPlainAdo.RecordSet;
1534 begin
1535  Result:=inherited UncachedGetSchemas;
1536 
1537  AdoRecordSet := AdoOpenSchema(adSchemaSchemata, []);
1538  if Assigned(AdoRecordSet) then
1539  begin
1540  with TZAdoResultSet.Create(GetStatement, '', AdoRecordSet) do
1541  begin
1542  while Next do
1543  begin
1544  Result.MoveToInsertRow;
1545  Result.UpdateStringByName('TABLE_SCHEM',
1546  GetStringByName('SCHEMA_NAME'));
1547  Result.InsertRow;
1548  end;
1549  Close;
1550  Free;
1551  end;
1552  end;
1553 end;
1554 
1555 {**
1556  Gets the catalog names available in this database. The results
1557  are ordered by catalog name.
1558 
1559  <P>The catalog column is:
1560  <OL>
1561  <LI><B>TABLE_CAT</B> String => catalog name
1562  </OL>
1563 
1564  @return <code>ResultSet</code> - each row has a single String column that is a
1565  catalog name
1566 }
1567 function TZAdoDatabaseMetadata.UncachedGetCatalogs: IZResultSet;
1568 var
1569  AdoRecordSet: ZPlainAdo.RecordSet;
1570 begin
1571  Result:=inherited UncachedGetCatalogs;
1572 
1573  AdoRecordSet := AdoOpenSchema(adSchemaCatalogs, []);
1574  if Assigned(AdoRecordSet) then
1575  begin
1576  with TZAdoResultSet.Create(GetStatement, '', AdoRecordSet) do
1577  begin
1578  while Next do
1579  begin
1580  Result.MoveToInsertRow;
1581  Result.UpdateStringByName('TABLE_CAT',
1582  GetStringByName('CATALOG_NAME'));
1583  Result.InsertRow;
1584  end;
1585  Close;
1586  Free;
1587  end;
1588  end;
1589 end;
1590 
1591 {**
1592  Gets the table types available in this database. The results
1593  are ordered by table type.
1594 
1595  <P>The table type is:
1596  <OL>
1597  <LI><B>TABLE_TYPE</B> String => table type. Typical types are "TABLE",
1598  "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY",
1599  "LOCAL TEMPORARY", "ALIAS", "SYNONYM".
1600  </OL>
1601 
1602  @return <code>ResultSet</code> - each row has a single String column that is a
1603  table type
1604 }
1605 function TZAdoDatabaseMetadata.UncachedGetTableTypes: IZResultSet;
1606 const
1607  TableTypes: array[0..7] of string = (
1608  'ALIAS', 'TABLE', 'SYNONYM', 'SYSTEM TABLE', 'VIEW',
1609  'GLOBAL TEMPORARY', 'LOCAL TEMPORARY', 'SYSTEM VIEW'
1610  );
1611 var
1612  I: Integer;
1613 begin
1614  Result:=inherited UncachedGetTableTypes;
1615 
1616  for I := 0 to 7 do
1617  begin
1618  Result.MoveToInsertRow;
1619  Result.UpdateStringByName('TABLE_TYPE', TableTypes[I]);
1620  Result.InsertRow;
1621  end;
1622 end;
1623 
1624 {**
1625  Gets a description of table columns available in
1626  the specified catalog.
1627 
1628  <P>Only column descriptions matching the catalog, schema, table
1629  and column name criteria are returned. They are ordered by
1630  TABLE_SCHEM, TABLE_NAME and ORDINAL_POSITION.
1631 
1632  <P>Each column description has the following columns:
1633  <OL>
1634  <LI><B>TABLE_CAT</B> String => table catalog (may be null)
1635  <LI><B>TABLE_SCHEM</B> String => table schema (may be null)
1636  <LI><B>TABLE_NAME</B> String => table name
1637  <LI><B>COLUMN_NAME</B> String => column name
1638  <LI><B>DATA_TYPE</B> short => SQL type from java.sql.Types
1639  <LI><B>TYPE_NAME</B> String => Data source dependent type name,
1640  for a UDT the type name is fully qualified
1641  <LI><B>COLUMN_SIZE</B> int => column size. For char or date
1642  types this is the maximum number of characters, for numeric or
1643  decimal types this is precision.
1644  <LI><B>BUFFER_LENGTH</B> is not used.
1645  <LI><B>DECIMAL_DIGITS</B> int => the number of fractional digits
1646  <LI><B>NUM_PREC_RADIX</B> int => Radix (typically either 10 or 2)
1647  <LI><B>NULLABLE</B> int => is NULL allowed?
1648  <UL>
1649  <LI> columnNoNulls - might not allow NULL values
1650  <LI> columnNullable - definitely allows NULL values
1651  <LI> columnNullableUnknown - nullability unknown
1652  </UL>
1653  <LI><B>REMARKS</B> String => comment describing column (may be null)
1654  <LI><B>COLUMN_DEF</B> String => default value (may be null)
1655  <LI><B>SQL_DATA_TYPE</B> int => unused
1656  <LI><B>SQL_DATETIME_SUB</B> int => unused
1657  <LI><B>CHAR_OCTET_LENGTH</B> int => for char types the
1658  maximum number of bytes in the column
1659  <LI><B>ORDINAL_POSITION</B> int => index of column in table
1660  (starting at 1)
1661  <LI><B>IS_NULLABLE</B> String => "NO" means column definitely
1662  does not allow NULL values; "YES" means the column might
1663  allow NULL values. An empty string means nobody knows.
1664  </OL>
1665 
1666  @param catalog a catalog name; "" retrieves those without a
1667  catalog; null means drop catalog name from the selection criteria
1668  @param schemaPattern a schema name pattern; "" retrieves those
1669  without a schema
1670  @param tableNamePattern a table name pattern
1671  @param columnNamePattern a column name pattern
1672  @return <code>ResultSet</code> - each row is a column description
1673  @see #getSearchStringEscape
1674 }
1675 function TZAdoDatabaseMetadata.UncachedGetColumns(const Catalog: string;
1676  const SchemaPattern: string; const TableNamePattern: string;
1677  const ColumnNamePattern: string): IZResultSet;
1678 var
1679  AdoRecordSet: ZPlainAdo.RecordSet;
1680  Flags: Integer;
1681  SQLType: TZSQLType;
1682 begin
1683  Result:=inherited UncachedGetColumns(Catalog, SchemaPattern,
1684  TableNamePattern, ColumnNamePattern);
1685 
1686  AdoRecordSet := AdoOpenSchema(adSchemaColumns,
1687  [DecomposeObjectString(Catalog), DecomposeObjectString(SchemaPattern),
1688  DecomposeObjectString(TableNamePattern), DecomposeObjectString(ColumnNamePattern)]);
1689  if Assigned(AdoRecordSet) then
1690  begin
1691  AdoRecordSet.Sort := 'ORDINAL_POSITION';
1692  with TZAdoResultSet.Create(GetStatement, '', AdoRecordSet) do
1693  begin
1694  while Next do
1695  begin
1696  Result.MoveToInsertRow;
1697  Result.UpdateStringByName('TABLE_CAT',
1698  GetStringByName('TABLE_CATALOG'));
1699  Result.UpdateStringByName('TABLE_SCHEM',
1700  GetStringByName('TABLE_SCHEMA'));
1701  Result.UpdateStringByName('TABLE_NAME',
1702  GetStringByName('TABLE_NAME'));
1703  Result.UpdateStringByName('COLUMN_NAME',
1704  GetStringByName('COLUMN_NAME'));
1705 
1706  SQLType := ConvertAdoToSqlType(GetShortByName('DATA_TYPE'),
1707  ConSettings.CPType);
1708  Flags := GetIntByName('COLUMN_FLAGS');
1709  //!!!If the field type is long then this is the only way to know it because it just returns string type
1710  if ((Flags and DBCOLUMNFLAGS_ISLONG) <> 0 ) and (SQLType in [stBytes, stString, stUnicodeString]) then
1711  case SQLType of
1712  stBytes: SQLType := stBinaryStream;
1713  stString: SQLType := stAsciiStream;
1714  stUnicodeString: SQLType := stUnicodeStream;
1715  end;
1716  Result.UpdateShortByName('DATA_TYPE', Ord(SQLType));
1717  Result.UpdateIntByName('COLUMN_SIZE',
1718  GetIntByName('CHARACTER_MAXIMUM_LENGTH'));
1719  Result.UpdateIntByName('BUFFER_LENGTH',
1720  GetIntByName('CHARACTER_MAXIMUM_LENGTH'));
1721  Result.UpdateIntByName('DECIMAL_DIGITS',
1722  GetIntByName('NUMERIC_SCALE'));
1723  Result.UpdateIntByName('NUM_PREC_RADIX',
1724  GetShortByName('NUMERIC_PRECISION'));
1725  if GetBooleanByName('IS_NULLABLE') then
1726  Result.UpdateShortByName('NULLABLE', 1)
1727  else
1728  Result.UpdateShortByName('NULLABLE', 0);
1729  Result.UpdateStringByName('REMARKS',
1730  GetStringByName('DESCRIPTION'));
1731  Result.UpdateStringByName('COLUMN_DEF',
1732  GetStringByName('COLUMN_DEFAULT'));
1733  Result.UpdateShortByName('SQL_DATETIME_SUB',
1734  GetShortByName('DATETIME_PRECISION'));
1735  Result.UpdateIntByName('CHAR_OCTET_LENGTH',
1736  GetIntByName('CHARACTER_OCTET_LENGTH'));
1737  Result.UpdateIntByName('ORDINAL_POSITION',
1738  GetIntByName('ORDINAL_POSITION'));
1739  if UpperCase(GetStringByName('IS_NULLABLE')) = 'FALSE' then
1740  Result.UpdateStringByName('IS_NULLABLE', 'NO')
1741  else
1742  Result.UpdateStringByName('IS_NULLABLE', 'YES');
1743 
1744  Result.UpdateBooleanByName('WRITABLE',
1745  (Flags and (DBCOLUMNFLAGS_WRITE or DBCOLUMNFLAGS_WRITEUNKNOWN) <> 0));
1746 
1747  Result.UpdateBooleanByName('DEFINITELYWRITABLE',
1748  (Flags and (DBCOLUMNFLAGS_WRITE) <> 0));
1749  Result.UpdateBooleanByName('READONLY',
1750  (Flags and (DBCOLUMNFLAGS_WRITE or DBCOLUMNFLAGS_WRITEUNKNOWN) = 0));
1751  Result.UpdateBooleanByName('SEARCHABLE',
1752  (Flags and (DBCOLUMNFLAGS_ISLONG) = 0));
1753  Result.UpdateNullByName('AUTO_INCREMENT');
1754  Result.InsertRow;
1755  end;
1756  Close;
1757  Free;
1758  end;
1759  end;
1760 end;
1761 
1762 {**
1763  Gets a description of the access rights for a table's columns.
1764 
1765  <P>Only privileges matching the column name criteria are
1766  returned. They are ordered by COLUMN_NAME and PRIVILEGE.
1767 
1768  <P>Each privilige description has the following columns:
1769  <OL>
1770  <LI><B>TABLE_CAT</B> String => table catalog (may be null)
1771  <LI><B>TABLE_SCHEM</B> String => table schema (may be null)
1772  <LI><B>TABLE_NAME</B> String => table name
1773  <LI><B>COLUMN_NAME</B> String => column name
1774  <LI><B>GRANTOR</B> => grantor of access (may be null)
1775  <LI><B>GRANTEE</B> String => grantee of access
1776  <LI><B>PRIVILEGE</B> String => name of access (SELECT,
1777  INSERT, UPDATE, REFRENCES, ...)
1778  <LI><B>IS_GRANTABLE</B> String => "YES" if grantee is permitted
1779  to grant to others; "NO" if not; null if unknown
1780  </OL>
1781 
1782  @param catalog a catalog name; "" retrieves those without a
1783  catalog; null means drop catalog name from the selection criteria
1784  @param schema a schema name; "" retrieves those without a schema
1785  @param table a table name
1786  @param columnNamePattern a column name pattern
1787  @return <code>ResultSet</code> - each row is a column privilege description
1788  @see #getSearchStringEscape
1789 }
1790 function TZAdoDatabaseMetadata.UncachedGetColumnPrivileges(const Catalog: string;
1791  const Schema: string; const Table: string; const ColumnNamePattern: string): IZResultSet;
1792 var
1793  AdoRecordSet: ZPlainAdo.RecordSet;
1794 begin
1795  Result:=inherited UncachedGetColumnPrivileges(Catalog, Schema, Table, ColumnNamePattern);
1796 
1797  AdoRecordSet := AdoOpenSchema(adSchemaColumnPrivileges,
1798  [Catalog, Schema, Table, ColumnNamePattern]);
1799  if Assigned(AdoRecordSet) then
1800  begin
1801  with TZAdoResultSet.Create(GetStatement, '', AdoRecordSet) do
1802  begin
1803  while Next do
1804  begin
1805  Result.MoveToInsertRow;
1806  Result.UpdateStringByName('TABLE_CAT',
1807  GetStringByName('TABLE_CATALOG'));
1808  Result.UpdateStringByName('TABLE_SCHEM',
1809  GetStringByName('TABLE_SCHEMA'));
1810  Result.UpdateStringByName('TABLE_NAME',
1811  GetStringByName('TABLE_NAME'));
1812  Result.UpdateStringByName('COLUMN_NAME',
1813  GetStringByName('COLUMN_NAME'));
1814  Result.UpdateStringByName('GRANTOR',
1815  GetStringByName('GRANTOR'));
1816  Result.UpdateStringByName('GRANTEE',
1817  GetStringByName('GRANTEE'));
1818  Result.UpdateStringByName('PRIVILEGE',
1819  GetStringByName('PRIVILEGE_TYPE'));
1820  if GetBooleanByName('IS_GRANTABLE') then
1821  Result.UpdateStringByName('IS_GRANTABLE', 'YES')
1822  else
1823  Result.UpdateStringByName('IS_GRANTABLE', 'NO');
1824  Result.InsertRow;
1825  end;
1826  Close;
1827  Free;
1828  end;
1829  end;
1830 end;
1831 
1832 {**
1833  Gets a description of the access rights for each table available
1834  in a catalog. Note that a table privilege applies to one or
1835  more columns in the table. It would be wrong to assume that
1836  this priviledge applies to all columns (this may be true for
1837  some systems but is not true for all.)
1838 
1839  <P>Only privileges matching the schema and table name
1840  criteria are returned. They are ordered by TABLE_SCHEM,
1841  TABLE_NAME, and PRIVILEGE.
1842 
1843  <P>Each privilige description has the following columns:
1844  <OL>
1845  <LI><B>TABLE_CAT</B> String => table catalog (may be null)
1846  <LI><B>TABLE_SCHEM</B> String => table schema (may be null)
1847  <LI><B>TABLE_NAME</B> String => table name
1848  <LI><B>GRANTOR</B> => grantor of access (may be null)
1849  <LI><B>GRANTEE</B> String => grantee of access
1850  <LI><B>PRIVILEGE</B> String => name of access (SELECT,
1851  INSERT, UPDATE, REFRENCES, ...)
1852  <LI><B>IS_GRANTABLE</B> String => "YES" if grantee is permitted
1853  to grant to others; "NO" if not; null if unknown
1854  </OL>
1855 
1856  @param catalog a catalog name; "" retrieves those without a
1857  catalog; null means drop catalog name from the selection criteria
1858  @param schemaPattern a schema name pattern; "" retrieves those
1859  without a schema
1860  @param tableNamePattern a table name pattern
1861  @return <code>ResultSet</code> - each row is a table privilege description
1862  @see #getSearchStringEscape
1863 }
1864 function TZAdoDatabaseMetadata.UncachedGetTablePrivileges(const Catalog: string;
1865  const SchemaPattern: string; const TableNamePattern: string): IZResultSet;
1866 var
1867  AdoRecordSet: ZPlainAdo.RecordSet;
1868 begin
1869  Result:=inherited UncachedGetTablePrivileges(Catalog, SchemaPattern, TableNamePattern);
1870 
1871  AdoRecordSet := AdoOpenSchema(adSchemaTablePrivileges,
1872  [Catalog, SchemaPattern, TableNamePattern]);
1873  if Assigned(AdoRecordSet) then
1874  begin
1875  with TZAdoResultSet.Create(GetStatement, '', AdoRecordSet) do
1876  begin
1877  while Next do
1878  begin
1879  Result.MoveToInsertRow;
1880  Result.UpdateStringByName('TABLE_CAT',
1881  GetStringByName('TABLE_CATALOG'));
1882  Result.UpdateStringByName('TABLE_SCHEM',
1883  GetStringByName('TABLE_SCHEMA'));
1884  Result.UpdateStringByName('TABLE_NAME',
1885  GetStringByName('TABLE_NAME'));
1886  Result.UpdateStringByName('GRANTOR',
1887  GetStringByName('GRANTOR'));
1888  Result.UpdateStringByName('GRANTEE',
1889  GetStringByName('GRANTEE'));
1890  Result.UpdateStringByName('PRIVILEGE',
1891  GetStringByName('PRIVILEGE_TYPE'));
1892  if GetBooleanByName('IS_GRANTABLE') then
1893  Result.UpdateStringByName('IS_GRANTABLE', 'YES')
1894  else Result.UpdateStringByName('IS_GRANTABLE', 'NO');
1895  Result.InsertRow;
1896  end;
1897  Close;
1898  Free;
1899  end;
1900  end;
1901 end;
1902 
1903 {**
1904  Gets a description of a table's columns that are automatically
1905  updated when any value in a row is updated. They are
1906  unordered.
1907 
1908  <P>Each column description has the following columns:
1909  <OL>
1910  <LI><B>SCOPE</B> short => is not used
1911  <LI><B>COLUMN_NAME</B> String => column name
1912  <LI><B>DATA_TYPE</B> short => SQL data type from java.sql.Types
1913  <LI><B>TYPE_NAME</B> String => Data source dependent type name
1914  <LI><B>COLUMN_SIZE</B> int => precision
1915  <LI><B>BUFFER_LENGTH</B> int => length of column value in bytes
1916  <LI><B>DECIMAL_DIGITS</B> short => scale
1917  <LI><B>PSEUDO_COLUMN</B> short => is this a pseudo column
1918  like an Oracle ROWID
1919  <UL>
1920  <LI> versionColumnUnknown - may or may not be pseudo column
1921  <LI> versionColumnNotPseudo - is NOT a pseudo column
1922  <LI> versionColumnPseudo - is a pseudo column
1923  </UL>
1924  </OL>
1925 
1926  @param catalog a catalog name; "" retrieves those without a
1927  catalog; null means drop catalog name from the selection criteria
1928  @param schema a schema name; "" retrieves those without a schema
1929  @param table a table name
1930  @return <code>ResultSet</code> - each row is a column description
1931  @exception SQLException if a database access error occurs
1932 }
1933 function TZAdoDatabaseMetadata.UncachedGetVersionColumns(const Catalog: string;
1934  const Schema: string; const Table: string): IZResultSet;
1935 const
1936  DBCOLUMNFLAGS_ISROWVER = $00000200;
1937 var
1938  AdoRecordSet: ZPlainAdo.RecordSet;
1939 begin
1940  Result:=inherited UncachedGetVersionColumns(Catalog, Schema, Table);
1941 
1942  AdoRecordSet := AdoOpenSchema(adSchemaColumns, [Catalog, Schema, Table]);
1943  if Assigned(AdoRecordSet) then
1944  begin
1945  with TZAdoResultSet.Create(GetStatement, '', AdoRecordSet) do
1946  begin
1947  while Next do
1948  begin
1949  if (GetIntByName('COLUMN_FLAGS')
1950  and DBCOLUMNFLAGS_ISROWVER) = 0 then
1951  Continue;
1952  Result.MoveToInsertRow;
1953  Result.UpdateShortByName('SCOPE', 0);
1954  Result.UpdateStringByName('COLUMN_NAME',
1955  GetStringByName('COLUMN_NAME'));
1956  Result.UpdateShortByName('DATA_TYPE',
1957  Ord(ConvertAdoToSqlType(GetShortByName('DATA_TYPE'),
1958  ConSettings.CPType)));
1959  Result.UpdateStringByName('TYPE_NAME',
1960  GetStringByName('TYPE_NAME'));
1961  Result.UpdateIntByName('COLUMN_SIZE',
1962  GetIntByName('CHARACTER_OCTET_LENGTH'));
1963  Result.UpdateIntByName('BUFFER_LENGTH',
1964  GetIntByName('CHARACTER_OCTET_LENGTH'));
1965  Result.UpdateIntByName('DECIMAL_DIGITS',
1966  GetIntByName('NUMERIC_SCALE'));
1967  Result.UpdateShortByName('PSEUDO_COLUMN', 0);
1968  Result.InsertRow;
1969  end;
1970  Close;
1971  Free;
1972  end;
1973  end;
1974 end;
1975 
1976 {**
1977  Gets a description of a table's primary key columns. They
1978  are ordered by COLUMN_NAME.
1979 
1980  <P>Each primary key column 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>COLUMN_NAME</B> String => column name
1986  <LI><B>KEY_SEQ</B> short => sequence number within primary key
1987  <LI><B>PK_NAME</B> String => primary key name (may be null)
1988  </OL>
1989 
1990  @param catalog a catalog name; "" retrieves those without a
1991  catalog; null means drop catalog name from the selection criteria
1992  @param schema a schema name; "" retrieves those
1993  without a schema
1994  @param table a table name
1995  @return <code>ResultSet</code> - each row is a primary key column description
1996  @exception SQLException if a database access error occurs
1997 }
1998 function TZAdoDatabaseMetadata.UncachedGetPrimaryKeys(const Catalog: string;
1999  const Schema: string; const Table: string): IZResultSet;
2000 var
2001  AdoRecordSet: ZPlainAdo.RecordSet;
2002 begin
2003  Result:=inherited UncachedGetPrimaryKeys(Catalog, Schema, Table);
2004 
2005  AdoRecordSet := AdoOpenSchema(adSchemaPrimaryKeys,
2006  [Catalog, Schema, Table]);
2007  if Assigned(AdoRecordSet) then
2008  begin
2009  with TZAdoResultSet.Create(GetStatement, '', AdoRecordSet) do
2010  begin
2011  while Next do
2012  begin
2013  Result.MoveToInsertRow;
2014  Result.UpdateStringByName('TABLE_CAT',
2015  GetStringByName('TABLE_CATALOG'));
2016  Result.UpdateStringByName('TABLE_SCHEM',
2017  GetStringByName('TABLE_SCHEMA'));
2018  Result.UpdateStringByName('TABLE_NAME',
2019  GetStringByName('TABLE_NAME'));
2020  Result.UpdateStringByName('COLUMN_NAME',
2021  GetStringByName('COLUMN_NAME'));
2022  Result.UpdateShortByName('KEY_SEQ',
2023  GetShortByName('ORDINAL'));
2024  if FindColumn('PK_NAME') >= 1 then
2025  begin
2026  Result.UpdateStringByName('PK_NAME',
2027  GetStringByName('PK_NAME'));
2028  end;
2029  Result.InsertRow;
2030  end;
2031  Close;
2032  Free;
2033  end;
2034  end;
2035 end;
2036 
2037 {**
2038  Gets a description of the primary key columns that are
2039  referenced by a table's foreign key columns (the primary keys
2040  imported by a table). They are ordered by PKTABLE_CAT,
2041  PKTABLE_SCHEM, PKTABLE_NAME, and KEY_SEQ.
2042 
2043  <P>Each primary key column description has the following columns:
2044  <OL>
2045  <LI><B>PKTABLE_CAT</B> String => primary key table catalog
2046  being imported (may be null)
2047  <LI><B>PKTABLE_SCHEM</B> String => primary key table schema
2048  being imported (may be null)
2049  <LI><B>PKTABLE_NAME</B> String => primary key table name
2050  being imported
2051  <LI><B>PKCOLUMN_NAME</B> String => primary key column name
2052  being imported
2053  <LI><B>FKTABLE_CAT</B> String => foreign key table catalog (may be null)
2054  <LI><B>FKTABLE_SCHEM</B> String => foreign key table schema (may be null)
2055  <LI><B>FKTABLE_NAME</B> String => foreign key table name
2056  <LI><B>FKCOLUMN_NAME</B> String => foreign key column name
2057  <LI><B>KEY_SEQ</B> short => sequence number within foreign key
2058  <LI><B>UPDATE_RULE</B> short => What happens to
2059  foreign key when primary is updated:
2060  <UL>
2061  <LI> importedNoAction - do not allow update of primary
2062  key if it has been imported
2063  <LI> importedKeyCascade - change imported key to agree
2064  with primary key update
2065  <LI> importedKeySetNull - change imported key to NULL if
2066  its primary key has been updated
2067  <LI> importedKeySetDefault - change imported key to default values
2068  if its primary key has been updated
2069  <LI> importedKeyRestrict - same as importedKeyNoAction
2070  (for ODBC 2.x compatibility)
2071  </UL>
2072  <LI><B>DELETE_RULE</B> short => What happens to
2073  the foreign key when primary is deleted.
2074  <UL>
2075  <LI> importedKeyNoAction - do not allow delete of primary
2076  key if it has been imported
2077  <LI> importedKeyCascade - delete rows that import a deleted key
2078  <LI> importedKeySetNull - change imported key to NULL if
2079  its primary key has been deleted
2080  <LI> importedKeyRestrict - same as importedKeyNoAction
2081  (for ODBC 2.x compatibility)
2082  <LI> importedKeySetDefault - change imported key to default if
2083  its primary key has been deleted
2084  </UL>
2085  <LI><B>FK_NAME</B> String => foreign key name (may be null)
2086  <LI><B>PK_NAME</B> String => primary key name (may be null)
2087  <LI><B>DEFERRABILITY</B> short => can the evaluation of foreign key
2088  constraints be deferred until commit
2089  <UL>
2090  <LI> importedKeyInitiallyDeferred - see SQL92 for definition
2091  <LI> importedKeyInitiallyImmediate - see SQL92 for definition
2092  <LI> importedKeyNotDeferrable - see SQL92 for definition
2093  </UL>
2094  </OL>
2095 
2096  @param catalog a catalog name; "" retrieves those without a
2097  catalog; null means drop catalog name from the selection criteria
2098  @param schema a schema name; "" retrieves those
2099  without a schema
2100  @param table a table name
2101  @return <code>ResultSet</code> - each row is a primary key column description
2102  @see #getExportedKeys
2103 }
2104 function TZAdoDatabaseMetadata.UncachedGetImportedKeys(const Catalog: string;
2105  const Schema: string; const Table: string): IZResultSet;
2106 begin
2107  Result := UncachedGetCrossReference('', '', '', Catalog, Schema, Table);
2108 end;
2109 
2110 {**
2111  Gets a description of the foreign key columns that reference a
2112  table's primary key columns (the foreign keys exported by a
2113  table). They are ordered by FKTABLE_CAT, FKTABLE_SCHEM,
2114  FKTABLE_NAME, and KEY_SEQ.
2115 
2116  <P>Each foreign key column description has the following columns:
2117  <OL>
2118  <LI><B>PKTABLE_CAT</B> String => primary key table catalog (may be null)
2119  <LI><B>PKTABLE_SCHEM</B> String => primary key table schema (may be null)
2120  <LI><B>PKTABLE_NAME</B> String => primary key table name
2121  <LI><B>PKCOLUMN_NAME</B> String => primary key column name
2122  <LI><B>FKTABLE_CAT</B> String => foreign key table catalog (may be null)
2123  being exported (may be null)
2124  <LI><B>FKTABLE_SCHEM</B> String => foreign key table schema (may be null)
2125  being exported (may be null)
2126  <LI><B>FKTABLE_NAME</B> String => foreign key table name
2127  being exported
2128  <LI><B>FKCOLUMN_NAME</B> String => foreign key column name
2129  being exported
2130  <LI><B>KEY_SEQ</B> short => sequence number within foreign key
2131  <LI><B>UPDATE_RULE</B> short => What happens to
2132  foreign key when primary is updated:
2133  <UL>
2134  <LI> importedNoAction - do not allow update of primary
2135  key if it has been imported
2136  <LI> importedKeyCascade - change imported key to agree
2137  with primary key update
2138  <LI> importedKeySetNull - change imported key to NULL if
2139  its primary key has been updated
2140  <LI> importedKeySetDefault - change imported key to default values
2141  if its primary key has been updated
2142  <LI> importedKeyRestrict - same as importedKeyNoAction
2143  (for ODBC 2.x compatibility)
2144  </UL>
2145  <LI><B>DELETE_RULE</B> short => What happens to
2146  the foreign key when primary is deleted.
2147  <UL>
2148  <LI> importedKeyNoAction - do not allow delete of primary
2149  key if it has been imported
2150  <LI> importedKeyCascade - delete rows that import a deleted key
2151  <LI> importedKeySetNull - change imported key to NULL if
2152  its primary key has been deleted
2153  <LI> importedKeyRestrict - same as importedKeyNoAction
2154  (for ODBC 2.x compatibility)
2155  <LI> importedKeySetDefault - change imported key to default if
2156  its primary key has been deleted
2157  </UL>
2158  <LI><B>FK_NAME</B> String => foreign key name (may be null)
2159  <LI><B>PK_NAME</B> String => primary key name (may be null)
2160  <LI><B>DEFERRABILITY</B> short => can the evaluation of foreign key
2161  constraints be deferred until commit
2162  <UL>
2163  <LI> importedKeyInitiallyDeferred - see SQL92 for definition
2164  <LI> importedKeyInitiallyImmediate - see SQL92 for definition
2165  <LI> importedKeyNotDeferrable - see SQL92 for definition
2166  </UL>
2167  </OL>
2168 
2169  @param catalog a catalog name; "" retrieves those without a
2170  catalog; null means drop catalog name from the selection criteria
2171  @param schema a schema name; "" retrieves those
2172  without a schema
2173  @param table a table name
2174  @return <code>ResultSet</code> - each row is a foreign key column description
2175  @see #getImportedKeys
2176 }
2177 function TZAdoDatabaseMetadata.UncachedGetExportedKeys(const Catalog: string;
2178  const Schema: string; const Table: string): IZResultSet;
2179 begin
2180  Result := UncachedGetCrossReference(Catalog, Schema, Table, '', '', '');
2181 end;
2182 
2183 {**
2184  Gets a description of the foreign key columns in the foreign key
2185  table that reference the primary key columns of the primary key
2186  table (describe how one table imports another's key.) This
2187  should normally return a single foreign key/primary key pair
2188  (most tables only import a foreign key from a table once.) They
2189  are ordered by FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, and
2190  KEY_SEQ.
2191 
2192  <P>Each foreign key column description has the following columns:
2193  <OL>
2194  <LI><B>PKTABLE_CAT</B> String => primary key table catalog (may be null)
2195  <LI><B>PKTABLE_SCHEM</B> String => primary key table schema (may be null)
2196  <LI><B>PKTABLE_NAME</B> String => primary key table name
2197  <LI><B>PKCOLUMN_NAME</B> String => primary key column name
2198  <LI><B>FKTABLE_CAT</B> String => foreign key table catalog (may be null)
2199  being exported (may be null)
2200  <LI><B>FKTABLE_SCHEM</B> String => foreign key table schema (may be null)
2201  being exported (may be null)
2202  <LI><B>FKTABLE_NAME</B> String => foreign key table name
2203  being exported
2204  <LI><B>FKCOLUMN_NAME</B> String => foreign key column name
2205  being exported
2206  <LI><B>KEY_SEQ</B> short => sequence number within foreign key
2207  <LI><B>UPDATE_RULE</B> short => What happens to
2208  foreign key when primary is updated:
2209  <UL>
2210  <LI> importedNoAction - do not allow update of primary
2211  key if it has been imported
2212  <LI> importedKeyCascade - change imported key to agree
2213  with primary key update
2214  <LI> importedKeySetNull - change imported key to NULL if
2215  its primary key has been updated
2216  <LI> importedKeySetDefault - change imported key to default values
2217  if its primary key has been updated
2218  <LI> importedKeyRestrict - same as importedKeyNoAction
2219  (for ODBC 2.x compatibility)
2220  </UL>
2221  <LI><B>DELETE_RULE</B> short => What happens to
2222  the foreign key when primary is deleted.
2223  <UL>
2224  <LI> importedKeyNoAction - do not allow delete of primary
2225  key if it has been imported
2226  <LI> importedKeyCascade - delete rows that import a deleted key
2227  <LI> importedKeySetNull - change imported key to NULL if
2228  its primary key has been deleted
2229  <LI> importedKeyRestrict - same as importedKeyNoAction
2230  (for ODBC 2.x compatibility)
2231  <LI> importedKeySetDefault - change imported key to default if
2232  its primary key has been deleted
2233  </UL>
2234  <LI><B>FK_NAME</B> String => foreign key name (may be null)
2235  <LI><B>PK_NAME</B> String => primary key name (may be null)
2236  <LI><B>DEFERRABILITY</B> short => can the evaluation of foreign key
2237  constraints be deferred until commit
2238  <UL>
2239  <LI> importedKeyInitiallyDeferred - see SQL92 for definition
2240  <LI> importedKeyInitiallyImmediate - see SQL92 for definition
2241  <LI> importedKeyNotDeferrable - see SQL92 for definition
2242  </UL>
2243  </OL>
2244 
2245  @param primaryCatalog a catalog name; "" retrieves those without a
2246  catalog; null means drop catalog name from the selection criteria
2247  @param primarySchema a schema name; "" retrieves those
2248  without a schema
2249  @param primaryTable the table name that exports the key
2250  @param foreignCatalog a catalog name; "" retrieves those without a
2251  catalog; null means drop catalog name from the selection criteria
2252  @param foreignSchema a schema name; "" retrieves those
2253  without a schema
2254  @param foreignTable the table name that imports the key
2255  @return <code>ResultSet</code> - each row is a foreign key column description
2256  @see #getImportedKeys
2257 }
2258 function TZAdoDatabaseMetadata.UncachedGetCrossReference(const PrimaryCatalog: string;
2259  const PrimarySchema: string; const PrimaryTable: string; const ForeignCatalog: string;
2260  const ForeignSchema: string; const ForeignTable: string): IZResultSet;
2261 var
2262  AdoRecordSet: ZPlainAdo.RecordSet;
2263 
2264  function GetRuleType(const Rule: String): TZImportedKey;
2265  begin
2266  if Rule = 'RESTRICT' then
2267  Result := ikRestrict
2268  else if Rule = 'NO ACTION' then
2269  Result := ikNoAction
2270  else if Rule = 'CASCADE' then
2271  Result := ikCascade
2272  else if Rule = 'SET DEFAULT' then
2273  Result := ikSetDefault
2274  else if Rule = 'SET NULL' then
2275  Result := ikSetNull
2276  else
2277  Result := ikNotDeferrable; //impossible!
2278  end;
2279 begin
2280  Result:=inherited UncachedGetCrossReference(PrimaryCatalog, PrimarySchema, PrimaryTable,
2281  ForeignCatalog, ForeignSchema, ForeignTable);
2282 
2283  AdoRecordSet := AdoOpenSchema(adSchemaForeignKeys,
2284  [PrimaryCatalog, PrimarySchema, PrimaryTable,
2285  ForeignCatalog, ForeignSchema, ForeignTable]);
2286  if Assigned(AdoRecordSet) then
2287  begin
2288  with TZAdoResultSet.Create(GetStatement, '', AdoRecordSet) do
2289  begin
2290  while Next do
2291  begin
2292  Result.MoveToInsertRow;
2293  Result.UpdateStringByName('PKTABLE_CAT',
2294  GetStringByName('PK_TABLE_CATALOG'));
2295  Result.UpdateStringByName('PKTABLE_SCHEM',
2296  GetStringByName('PK_TABLE_SCHEMA'));
2297  Result.UpdateStringByName('PKTABLE_NAME',
2298  GetStringByName('PK_TABLE_NAME'));
2299  Result.UpdateStringByName('PKCOLUMN_NAME',
2300  GetStringByName('PK_COLUMN_NAME'));
2301  Result.UpdateStringByName('FKTABLE_CAT',
2302  GetStringByName('FK_TABLE_CATALOG'));
2303  Result.UpdateStringByName('FKTABLE_SCHEM',
2304  GetStringByName('FK_TABLE_SCHEMA'));
2305  Result.UpdateStringByName('FKTABLE_NAME',
2306  GetStringByName('FK_TABLE_NAME'));
2307  Result.UpdateStringByName('FKCOLUMN_NAME',
2308  GetStringByName('FK_COLUMN_NAME'));
2309  Result.UpdateShortByName('KEY_SEQ',
2310  GetShortByName('ORDINAL'));
2311  Result.UpdateShortByName('UPDATE_RULE',
2312  Ord(GetRuleType(GetStringByName('UPDATE_RULE'))));
2313  Result.UpdateShortByName('DELETE_RULE',
2314  Ord(GetRuleType(GetStringByName('DELETE_RULE'))));
2315  Result.UpdateStringByName('FK_NAME',
2316  GetStringByName('FK_NAME'));
2317  Result.UpdateStringByName('PK_NAME',
2318  GetStringByName('PK_NAME'));
2319  Result.UpdateIntByName('DEFERRABILITY',
2320  GetShortByName('DEFERRABILITY'));
2321  Result.InsertRow;
2322  end;
2323  Close;
2324  Free;
2325  end;
2326  end;
2327 end;
2328 
2329 {**
2330  Gets a description of all the standard SQL types supported by
2331  this database. They are ordered by DATA_TYPE and then by how
2332  closely the data type maps to the corresponding JDBC SQL type.
2333 
2334  <P>Each type description has the following columns:
2335  <OL>
2336  <LI><B>TYPE_NAME</B> String => Type name
2337  <LI><B>DATA_TYPE</B> short => SQL data type from java.sql.Types
2338  <LI><B>PRECISION</B> int => maximum precision
2339  <LI><B>LITERAL_PREFIX</B> String => prefix used to quote a literal
2340  (may be null)
2341  <LI><B>LITERAL_SUFFIX</B> String => suffix used to quote a literal
2342  (may be null)
2343  <LI><B>CREATE_PARAMS</B> String => parameters used in creating
2344  the type (may be null)
2345  <LI><B>NULLABLE</B> short => can you use NULL for this type?
2346  <UL>
2347  <LI> typeNoNulls - does not allow NULL values
2348  <LI> typeNullable - allows NULL values
2349  <LI> typeNullableUnknown - nullability unknown
2350  </UL>
2351  <LI><B>CASE_SENSITIVE</B> boolean=> is it case sensitive?
2352  <LI><B>SEARCHABLE</B> short => can you use "WHERE" based on this type:
2353  <UL>
2354  <LI> typePredNone - No support
2355  <LI> typePredChar - Only supported with WHERE .. LIKE
2356  <LI> typePredBasic - Supported except for WHERE .. LIKE
2357  <LI> typeSearchable - Supported for all WHERE ..
2358  </UL>
2359  <LI><B>UNSIGNED_ATTRIBUTE</B> boolean => is it unsigned?
2360  <LI><B>FIXED_PREC_SCALE</B> boolean => can it be a money value?
2361  <LI><B>AUTO_INCREMENT</B> boolean => can it be used for an
2362  auto-increment value?
2363  <LI><B>LOCAL_TYPE_NAME</B> String => localized version of type name
2364  (may be null)
2365  <LI><B>MINIMUM_SCALE</B> short => minimum scale supported
2366  <LI><B>MAXIMUM_SCALE</B> short => maximum scale supported
2367  <LI><B>SQL_DATA_TYPE</B> int => unused
2368  <LI><B>SQL_DATETIME_SUB</B> int => unused
2369  <LI><B>NUM_PREC_RADIX</B> int => usually 2 or 10
2370  </OL>
2371 
2372  @return <code>ResultSet</code> - each row is an SQL type description
2373 }
2374 function TZAdoDatabaseMetadata.UncachedGetTypeInfo: IZResultSet;
2375 var
2376  AdoRecordSet: ZPlainAdo.RecordSet;
2377 begin
2378  Result:=inherited UncachedGetTypeInfo;
2379 
2380  AdoRecordSet := AdoOpenSchema(adSchemaProviderTypes, []);
2381  if Assigned(AdoRecordSet) then
2382  begin
2383  with TZAdoResultSet.Create(GetStatement, '', AdoRecordSet) do
2384  begin
2385  while Next do
2386  begin
2387  Result.MoveToInsertRow;
2388  Result.UpdateStringByName('TYPE_NAME',
2389  GetStringByName('TYPE_NAME'));
2390  Result.UpdateShortByName('DATA_TYPE',
2391  Ord(ConvertAdoToSqlType(GetShortByName('DATA_TYPE'),
2392  ConSettings.CPType)));
2393  Result.UpdateIntByName('PRECISION',
2394  0);//GetIntByName('PRECISION'));
2395  Result.UpdateStringByName('LITERAL_PREFIX',
2396  GetStringByName('LITERAL_PREFIX'));
2397  Result.UpdateStringByName('LITERAL_SUFFIX',
2398  GetStringByName('LITERAL_SUFFIX'));
2399  Result.UpdateStringByName('CREATE_PARAMS',
2400  GetStringByName('CREATE_PARAMS'));
2401  if GetBooleanByName('IS_NULLABLE') then
2402  Result.UpdateShortByName('NULLABLE', 1)
2403  else
2404  Result.UpdateShortByName('NULLABLE', 0);
2405  Result.UpdateBooleanByName('CASE_SENSITIVE',
2406  GetBooleanByName('CASE_SENSITIVE'));
2407  Result.UpdateShortByName('SEARCHABLE',
2408  GetShortByName('SEARCHABLE'));
2409  Result.UpdateBooleanByName('UNSIGNED_ATTRIBUTE',
2410  GetBooleanByName('UNSIGNED_ATTRIBUTE'));
2411  Result.UpdateBooleanByName('FIXED_PREC_SCALE',
2412  GetBooleanByName('FIXED_PREC_SCALE'));
2413  Result.UpdateBooleanByName('AUTO_INCREMENT', False);
2414  Result.UpdateStringByName('LOCAL_TYPE_NAME',
2415  GetStringByName('LOCAL_TYPE_NAME'));
2416  Result.UpdateShortByName('MINIMUM_SCALE',
2417  GetShortByName('MINIMUM_SCALE'));
2418  Result.UpdateShortByName('MAXIMUM_SCALE',
2419  GetShortByName('MAXIMUM_SCALE'));
2420  // Result.UpdateShortByName('SQL_DATA_TYPE',
2421  // GetShortByName('SQL_DATA_TYPE'));
2422  // Result.UpdateShortByName('SQL_DATETIME_SUB',
2423  // GetShortByName('SQL_DATETIME_SUB'));
2424  // Result.UpdateShortByName('NUM_PREC_RADIX',
2425  // GetShortByName('NUM_PREC_RADIX'));
2426  Result.InsertRow;
2427  end;
2428  Close;
2429  Free;
2430  end;
2431  end;
2432 end;
2433 
2434 {**
2435  Gets a description of a table's indices and statistics. They are
2436  ordered by NON_UNIQUE, TYPE, INDEX_NAME, and ORDINAL_POSITION.
2437 
2438  <P>Each index column description has the following columns:
2439  <OL>
2440  <LI><B>TABLE_CAT</B> String => table catalog (may be null)
2441  <LI><B>TABLE_SCHEM</B> String => table schema (may be null)
2442  <LI><B>TABLE_NAME</B> String => table name
2443  <LI><B>NON_UNIQUE</B> boolean => Can index values be non-unique?
2444  false when TYPE is tableIndexStatistic
2445  <LI><B>INDEX_QUALIFIER</B> String => index catalog (may be null);
2446  null when TYPE is tableIndexStatistic
2447  <LI><B>INDEX_NAME</B> String => index name; null when TYPE is
2448  tableIndexStatistic
2449  <LI><B>TYPE</B> short => index type:
2450  <UL>
2451  <LI> tableIndexStatistic - this identifies table statistics that are
2452  returned in conjuction with a table's index descriptions
2453  <LI> tableIndexClustered - this is a clustered index
2454  <LI> tableIndexHashed - this is a hashed index
2455  <LI> tableIndexOther - this is some other style of index
2456  </UL>
2457  <LI><B>ORDINAL_POSITION</B> short => column sequence number
2458  within index; zero when TYPE is tableIndexStatistic
2459  <LI><B>COLUMN_NAME</B> String => column name; null when TYPE is
2460  tableIndexStatistic
2461  <LI><B>ASC_OR_DESC</B> String => column sort sequence, "A" => ascending,
2462  "D" => descending, may be null if sort sequence is not supported;
2463  null when TYPE is tableIndexStatistic
2464  <LI><B>CARDINALITY</B> int => When TYPE is tableIndexStatistic, then
2465  this is the number of rows in the table; otherwise, it is the
2466  number of unique values in the index.
2467  <LI><B>PAGES</B> int => When TYPE is tableIndexStatisic then
2468  this is the number of pages used for the table, otherwise it
2469  is the number of pages used for the current index.
2470  <LI><B>FILTER_CONDITION</B> String => Filter condition, if any.
2471  (may be null)
2472  </OL>
2473 
2474  @param catalog a catalog name; "" retrieves those without a
2475  catalog; null means drop catalog name from the selection criteria
2476  @param schema a schema name; "" retrieves those without a schema
2477  @param table a table name
2478  @param unique when true, return only indices for unique values;
2479  when false, return indices regardless of whether unique or not
2480  @param approximate when true, result is allowed to reflect approximate
2481  or out of data values; when false, results are requested to be
2482  accurate
2483  @return <code>ResultSet</code> - each row is an index column description
2484 }
2485 function TZAdoDatabaseMetadata.UncachedGetIndexInfo(const Catalog: string;
2486  const Schema: string; const Table: string; Unique: Boolean;
2487  Approximate: Boolean): IZResultSet;
2488 var
2489  AdoRecordSet: ZPlainAdo.RecordSet;
2490 begin
2491  Result:=inherited UncachedGetIndexInfo(Catalog, Schema, Table, Unique, Approximate);
2492 
2493  AdoRecordSet := AdoOpenSchema(adSchemaIndexes,
2494  [Catalog, Schema, '', '', Table]);
2495  if Assigned(AdoRecordSet) then
2496  begin
2497  with TZAdoResultSet.Create(GetStatement, '', AdoRecordSet) do
2498  begin
2499  while Next do
2500  begin
2501  Result.MoveToInsertRow;
2502  Result.UpdateStringByName('TABLE_CAT',
2503  GetStringByName('TABLE_CATALOG'));
2504  Result.UpdateStringByName('TABLE_SCHEM',
2505  GetStringByName('TABLE_SCHEMA'));
2506  Result.UpdateStringByName('TABLE_NAME',
2507  GetStringByName('TABLE_NAME'));
2508  Result.UpdateBooleanByName('NON_UNIQUE',
2509  not GetBooleanByName('UNIQUE'));
2510  Result.UpdateStringByName('INDEX_QUALIFIER',
2511  GetStringByName('INDEX_CATALOG'));
2512  Result.UpdateStringByName('INDEX_NAME',
2513  GetStringByName('INDEX_NAME'));
2514  Result.UpdateShortByName('TYPE',
2515  GetShortByName('TYPE'));
2516  Result.UpdateShortByName('ORDINAL_POSITION',
2517  GetShortByName('ORDINAL_POSITION'));
2518  Result.UpdateStringByName('COLUMN_NAME',
2519  GetStringByName('COLUMN_NAME'));
2520  //!!! Result.UpdateStringByName('ASC_OR_DESC',
2521  // GetStringByName('COLLATION'));
2522  Result.UpdateIntByName('CARDINALITY',
2523  GetIntByName('CARDINALITY'));
2524  Result.UpdateIntByName('PAGES',
2525  GetIntByName('PAGES'));
2526  Result.UpdateStringByName('FILTER_CONDITION',
2527  GetStringByName('FILTER_CONDITION'));
2528  Result.InsertRow;
2529  end;
2530  Close;
2531  Free;
2532  end;
2533  end;
2534 end;
2535 
2536 {**
2537 
2538  Gets a description of the user-defined types defined in a particular
2539  schema. Schema-specific UDTs may have type JAVA_OBJECT, STRUCT,
2540  or DISTINCT.
2541 
2542  <P>Only types matching the catalog, schema, type name and type
2543  criteria are returned. They are ordered by DATA_TYPE, TYPE_SCHEM
2544  and TYPE_NAME. The type name parameter may be a fully-qualified
2545  name. In this case, the catalog and schemaPattern parameters are
2546  ignored.
2547 
2548  <P>Each type description has the following columns:
2549  <OL>
2550  <LI><B>TYPE_CAT</B> String => the type's catalog (may be null)
2551  <LI><B>TYPE_SCHEM</B> String => type's schema (may be null)
2552  <LI><B>TYPE_NAME</B> String => type name
2553  <LI><B>CLASS_NAME</B> String => Java class name
2554  <LI><B>DATA_TYPE</B> String => type value defined in java.sql.Types.
2555  One of JAVA_OBJECT, STRUCT, or DISTINCT
2556  <LI><B>REMARKS</B> String => explanatory comment on the type
2557  </OL>
2558 
2559  <P><B>Note:</B> If the driver does not support UDTs, an empty
2560  result set is returned.
2561 
2562  @param catalog a catalog name; "" retrieves those without a
2563  catalog; null means drop catalog name from the selection criteria
2564  @param schemaPattern a schema name pattern; "" retrieves those
2565  without a schema
2566  @param typeNamePattern a type name pattern; may be a fully-qualified name
2567  @param types a list of user-named types to include (JAVA_OBJECT,
2568  STRUCT, or DISTINCT); null returns all types
2569  @return <code>ResultSet</code> - each row is a type description
2570 }
2571 function TZAdoDatabaseMetadata.UncachedGetUDTs(const Catalog: string; const SchemaPattern: string;
2572  const TypeNamePattern: string; const Types: TIntegerDynArray): IZResultSet;
2573 begin
2574 
2575  Result:=inherited UncachedGetUDTs(Catalog, SchemaPattern, TypeNamePattern, Types);
2576 
2577 // AdoRecordSet := AdoOpenSchema(adSchemaIndexes, Restrictions);
2578 // if Assigned(AdoRecordSet) then
2579 // with GetStatement.ExecuteQuery(
2580 // Format('select TYPE_CAT = db_name(), TYPE_SCHEM = user_name(uid),'
2581 // + ' TYPE_NAME = st.name, DATA_TYPE from master.dbo.spt_datatype_info'
2582 // + ' sti left outer join systypes st on (sti.ss_dtype = st.xtype)'
2583 // + ' where st.xusertype > 255 and user_name(uid) like %s and st.name'
2584 // + ' like %s', [SchemaPattern, TypeNamePattern])) do
2585 // while Next do
2586 // begin
2587 // Result.MoveToInsertRow;
2588 // Result.UpdateString('TYPE_CAT', GetString('TYPE_CAT'));
2589 // Result.UpdateString('TYPE_SCHEM', GetString('TYPE_SCHEM'));
2590 // Result.UpdateString('TYPE_NAME', GetString('TYPE_NAME'));
2591 // Result.UpdateNull('JAVA_CLASS');
2592 // Result.UpdateShort('DATA_TYPE', GetShort('DATA_TYPE'));
2593 // Result.UpdateNull('REMARKS');
2594 // Result.InsertRow;
2595 // end;
2596 
2597 end;
2598 
2599 {**
2600  Open a schema rowset from ado
2601 
2602  @Schema Ado identifier
2603  @Args Variant array with restrictions
2604  @return ADO recordset with the schemas; nil if the schema is not supported
2605 }
2606 function TZAdoDatabaseMetadata.AdoOpenSchema(Schema: Integer; const Args: array of const): ZPlainAdo.RecordSet;
2607 var
2608  Restrictions: Variant;
2609 begin
2610  Result := nil;
2611  if not FSupportedSchemasInitialized then
2612  InitializeSchemas;
2613  if not SchemaSupported(Schema) then
2614  Exit;
2615  try
2616  Restrictions := BuildRestrictions(Schema, Args);
2617  Result := (GetConnection as IZAdoConnection).GetAdoConnection.
2618  OpenSchema(Schema, Restrictions, EmptyParam);
2619  except
2620  Result := nil;
2621  end;
2622 end;
2623 
2624 {**
2625  Initialize supported schemas and restrictions from the OleDB provider
2626 }
2627 procedure TZAdoDatabaseMetadata.InitializeSchemas;
2628 var
2629  AdoConnection: IZAdoConnection;
2630  OleDBSession: IUnknown;
2631  SchemaRS: IDBSchemaRowset;
2632  PG, OriginalPG: PGUID;
2633  IA: PIntegerArray;
2634  Nr: Integer;
2635  I: Integer;
2636 begin
2637  if not FSupportedSchemasInitialized then
2638  begin
2639  if not Assigned(FAdoConnection) then
2640  begin
2641  GetConnection.QueryInterface(IZAdoConnection, AdoConnection);
2642  FAdoConnection := AdoConnection.GetAdoConnection;
2643  end;
2644  (FAdoConnection as ADOConnectionConstruction).Get_Session(OleDBSession);
2645  if Assigned(OleDBSession) then
2646  begin
2647  OleDBSession.QueryInterface(IDBSchemaRowset, SchemaRS);
2648  if Assigned(SchemaRS) then
2649  begin
2650  SchemaRS.GetSchemas(Nr, PG, PInteger(IA));
2651  OriginalPG := PG;
2652  SetLength(SupportedSchemas, Nr);
2653  for I := 0 to Nr - 1 do
2654  begin
2655  SupportedSchemas[I].SchemaGuid := PG^;
2656  SupportedSchemas[I].SupportedRestrictions := IA^[I];
2657  SupportedSchemas[I].AdoSchemaId := ConvertOleDBToAdoSchema(PG^);
2658  Inc({$IFDEF DELPHI16_UP}NativeInt{$ELSE}Integer{$ENDIF}(PG), SizeOf(TGuid)); //M.A. Inc(Integer(PG), SizeOf(TGuid));
2659  end;
2660  FSupportedSchemasInitialized := True;
2661  if Assigned(OriginalPG) then ZAdoMalloc.Free(OriginalPG);
2662  if Assigned(IA) then ZAdoMalloc.Free(IA);
2663  end;
2664  end;
2665  end;
2666 end;
2667 
2668 {**
2669  Find the Schema Id in the supported schemas
2670 
2671  @SchemaId Ado identifier
2672  @return Index of the schema in the supported schemas array
2673 }
2674 function TZAdoDatabaseMetadata.FindSchema(SchemaId: Integer): Integer;
2675 var
2676  I: Integer;
2677 begin
2678  Result := -1;
2679  for I := 0 to Length(SupportedSchemas) - 1 do
2680  if SupportedSchemas[I].AdoSchemaId = SchemaId then
2681  begin
2682  Result := I;
2683  Break;
2684  end;
2685 end;
2686 
2687 {**
2688  Is the schema supported by the OleDB provider?
2689 
2690  @SchemaId Ado identifier
2691  @return True if the schema is supported
2692 }
2693 function TZAdoDatabaseMetadata.SchemaSupported(SchemaId: Integer): Boolean;
2694 begin
2695  Result := FindSchema(SchemaId) > -1;
2696 end;
2697 
2698 {**
2699  Build a variant array from the provided parameters based on the supported restrictions
2700 
2701  @SchemaId Ado identifier
2702  @Args Restrictions
2703  @return Variant array of restrictions
2704 }
2705 function TZAdoDatabaseMetadata.BuildRestrictions(SchemaId: Integer;
2706  const Args: array of const): Variant;
2707 var
2708  SchemaIndex: Integer;
2709  I: Integer;
2710 begin
2711  Result := Null;
2712  if High(Args) = -1 then
2713  Exit;
2714  SchemaIndex := FindSchema(SchemaId);
2715  if SchemaIndex = -1 then
2716  Exit;
2717 
2718  Result := VarArrayCreate([0, High(Args)], varVariant);
2719  for I := 0 to High(Args) do
2720  begin
2721  if (SupportedSchemas[SchemaIndex].SupportedRestrictions
2722  and (1 shl I)) <> 0 then
2723  begin
2724  {$IFDEF UNICODE}
2725  Result[I] := string(Args[I].VPWideChar);
2726  if (Args[I].VType = VtUnicodeString) then
2727  if string(Args[I].VPWideChar) = '' then
2728  {$ELSE}
2729  Result[I] := string(Args[I].VAnsiString);
2730  if (Args[I].VType = vtAnsiString) then
2731  if string(Args[I].VAnsiString) = '' then
2732  {$ENDIF}
2733  Result[I] := UnAssigned;
2734  end else
2735  Result[I] := UnAssigned;
2736  end;
2737 end;
2738 
2739 end.
2740 
2741